diff --git a/.claude/commands/setup-statusline.md b/.claude/commands/setup-statusline.md index 7791e8ca..c8dc2e25 100644 --- a/.claude/commands/setup-statusline.md +++ b/.claude/commands/setup-statusline.md @@ -80,7 +80,7 @@ Output: Raw JSON status data ## Status File -Auto-build writes status to `.auto-claude-status` in your project root: +Auto-build writes status to `.aperant-status` in your project root: ```json { @@ -121,7 +121,7 @@ When active, you'll see these indicators: ## Troubleshooting ### Status not showing? -1. Check if `.auto-claude-status` exists in your project root +1. Check if `.aperant-status` exists in your project root 2. Verify the path to `statusline.py` is correct 3. Try running the command manually: `python auto-claude/statusline.py --format compact` diff --git a/.gitignore b/.gitignore index e41c5b3d..46ee37d0 100644 --- a/.gitignore +++ b/.gitignore @@ -54,13 +54,16 @@ lerna-debug.log* .worktrees/ # =========================== -# Auto Claude Generated +# Aperant Generated # =========================== +.aperant/ .auto-claude/ .planning/ .planning-archive/ .auto-build-security.json +.aperant-security.json .auto-claude-security.json +.aperant-status .auto-claude-status .claude_settings.json .update-metadata.json diff --git a/CLAUDE.md b/CLAUDE.md index f8808f8a..9bc94d6a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -82,10 +82,10 @@ Your context window will be automatically compacted as it approaches its limit, ### Resetting PR Review State -To fully clear all PR review data so reviews run fresh, delete/reset these three things in `.auto-claude/github/`: +To fully clear all PR review data so reviews run fresh, delete/reset these three things in `.aperant/github/`: -1. `rm .auto-claude/github/pr/logs_*.json` — review log files -2. `rm .auto-claude/github/pr/review_*.json` — review result files +1. `rm .aperant/github/pr/logs_*.json` — review log files +2. `rm .aperant/github/pr/review_*.json` — review result files 3. Reset `pr/index.json` to `{"reviews": [], "last_updated": null}` 4. Reset `bot_detection_state.json` to `{"reviewed_commits": {}}` — this is the gatekeeper; without clearing it, the bot detector skips already-seen commits @@ -217,7 +217,7 @@ const readTool = tool({ ### Spec Directory Structure -Each spec in `.auto-claude/specs/XXX-name/` contains: `spec.md`, `requirements.json`, `context.json`, `implementation_plan.json`, `qa_report.md`, `QA_FIX_REQUEST.md` +Each spec in `.aperant/specs/XXX-name/` contains: `spec.md`, `requirements.json`, `context.json`, `implementation_plan.json`, `qa_report.md`, `QA_FIX_REQUEST.md` ### Memory System (Graphiti) @@ -355,5 +355,5 @@ npm run dev # Development mode with HMR npm run dev:debug # Debug mode with verbose output npm run dev:mcp # Electron MCP server for AI debugging -# Project data: .auto-claude/specs/ (gitignored) +# Project data: .aperant/specs/ (gitignored) ``` diff --git a/apps/desktop/prompts/coder.md b/apps/desktop/prompts/coder.md index 1c7db8e6..f34232ea 100644 --- a/apps/desktop/prompts/coder.md +++ b/apps/desktop/prompts/coder.md @@ -12,7 +12,7 @@ You are continuing work on an autonomous development task. This is a **FRESH con environment at the start of each prompt in the "YOUR ENVIRONMENT" section. Pay close attention to: - **Working Directory**: This is your root - all paths are relative to here -- **Spec Location**: Where your spec files live (usually `./auto-claude/specs/{spec-name}/`) +- **Spec Location**: Where your spec files live (usually `./.aperant/specs/{spec-name}/`) - **Isolation Mode**: If present, you are in an isolated worktree (see below) **RULES:** @@ -57,9 +57,9 @@ You may see absolute paths like `/e/projects/myapp/prod/src/file.ts` in: ```bash # Verify you're still in the worktree pwd -# Should show: .../.auto-claude/worktrees/tasks/{spec-name}/ +# Should show: .../.aperant/worktrees/tasks/{spec-name}/ # Or (legacy): .../.worktrees/{spec-name}/ -# Or (PR review): .../.auto-claude/github/pr/worktrees/{pr-number}/ +# Or (PR review): .../.aperant/github/pr/worktrees/{pr-number}/ # NOT: /path/to/main/project ``` @@ -140,7 +140,7 @@ pwd && ls -la find . -name "implementation_plan.json" -type f 2>/dev/null | head -5 # 3. Set SPEC_DIR based on what you find (example - adjust path as needed) -SPEC_DIR="./auto-claude/specs/YOUR-SPEC-NAME" # Replace with actual path from step 2 +SPEC_DIR="./.aperant/specs/YOUR-SPEC-NAME" # Replace with actual path from step 2 # 4. Read the implementation plan (your main source of truth) cat "$SPEC_DIR/implementation_plan.json" @@ -791,7 +791,7 @@ The system **automatically scans for secrets** before every commit. If secrets a api_key = os.environ.get("API_KEY") ``` 3. **Update .env.example** - Add placeholder for the new variable -4. **Re-stage and retry** - `git add . ':!.auto-claude' && git commit ...` +4. **Re-stage and retry** - `git add . ':!.aperant' && git commit ...` **If it's a false positive:** - Add the file pattern to `.secretsignore` in the project root @@ -803,22 +803,22 @@ The system **automatically scans for secrets** before every commit. If secrets a # FIRST: Make sure you're in the working directory root (check YOUR ENVIRONMENT section at top) pwd # Should match your working directory -# Add all files EXCEPT .auto-claude directory (spec files should never be committed) -git add . ':!.auto-claude' +# Add all files EXCEPT .aperant directory (spec files should never be committed) +git add . ':!.aperant' # If git add fails with "pathspec did not match", you have a path problem: # 1. Run pwd to see where you are # 2. Run git status to see what git sees # 3. Adjust your paths accordingly -git commit -m "auto-claude: Complete [subtask-id] - [subtask description] +git commit -m "aperant: Complete [subtask-id] - [subtask description] - Files modified: [list] - Verification: [type] - passed - Phase progress: [X]/[Y] subtasks complete" ``` -**CRITICAL**: The `:!.auto-claude` pathspec exclusion ensures spec files are NEVER committed. +**CRITICAL**: The `:!.aperant` pathspec exclusion ensures spec files are NEVER committed. These are internal tracking files that must stay local. ### DO NOT Push to Remote @@ -851,7 +851,7 @@ Next phase (if applicable): [phase-name] === END SESSION N === ``` -**Note:** The `build-progress.txt` file is in `.auto-claude/specs/` which is gitignored. +**Note:** The `build-progress.txt` file is in `.aperant/specs/` which is gitignored. Do NOT try to commit it - the framework tracks progress automatically. --- @@ -881,7 +881,7 @@ All subtasks completed! Workflow type: [type] Total phases: [N] Total subtasks: [N] -Branch: auto-claude/[feature-name] +Branch: aperant/[feature-name] Ready for human review and merge. ``` diff --git a/apps/desktop/prompts/planner.md b/apps/desktop/prompts/planner.md index e5914ff8..26c4c73f 100644 --- a/apps/desktop/prompts/planner.md +++ b/apps/desktop/prompts/planner.md @@ -741,7 +741,7 @@ The following files are gitignored and should NOT be committed: - `init.sh` - tracked locally only - `build-progress.txt` - tracked locally only -These files live in `.auto-claude/specs/` which is gitignored. The orchestrator handles syncing them between worktrees and the main project. +These files live in `.aperant/specs/` which is gitignored. The orchestrator handles syncing them between worktrees and the main project. **Only code changes should be committed** - spec metadata stays local. diff --git a/apps/desktop/prompts/qa_fixer.md b/apps/desktop/prompts/qa_fixer.md index 8c94ccaa..121c8eab 100644 --- a/apps/desktop/prompts/qa_fixer.md +++ b/apps/desktop/prompts/qa_fixer.md @@ -11,10 +11,10 @@ You are the **QA Fix Agent** in an autonomous development process. The QA Review ### NEVER edit qa_report.md The `qa_report.md` file belongs to the QA Reviewer. You must NEVER modify it. The reviewer writes the verdict; you implement fixes. If you change the report status (e.g., to "FIXES_APPLIED"), the orchestrator won't recognize it as a valid verdict and your fixes will be wasted. -### Fix in the PROJECT SOURCE, not in .auto-claude/specs/ -All your code changes, documentation additions, and new files must go into the **project source tree** (the actual codebase). Never create deliverable files inside `.auto-claude/specs/` — that directory contains gitignored metadata (spec, plan, QA report). The QA reviewer evaluates the project source, not spec artifacts. +### Fix in the PROJECT SOURCE, not in .aperant/specs/ +All your code changes, documentation additions, and new files must go into the **project source tree** (the actual codebase). Never create deliverable files inside `.aperant/specs/` — that directory contains gitignored metadata (spec, plan, QA report). The QA reviewer evaluates the project source, not spec artifacts. -**Example:** If QA says "missing route inventory document", create it in the project root (e.g., `docs/route-policy.md` or `ROUTE_POLICY.md`), NOT in `.auto-claude/specs/route_access_policy.md`. +**Example:** If QA says "missing route inventory document", create it in the project root (e.g., `docs/route-policy.md` or `ROUTE_POLICY.md`), NOT in `.aperant/specs/route_access_policy.md`. ### Fix CODE issues with CODE, not documentation If QA reports a missing test, write the test. If QA reports a code bug, fix the code. Don't write a markdown document explaining why the code is fine — write the code that makes it fine. @@ -204,7 +204,7 @@ Escaping the worktree causes: pwd # 2. Verify the target is within your worktree -# If pwd shows: /path/to/.auto-claude/worktrees/tasks/spec-name/ +# If pwd shows: /path/to/.aperant/worktrees/tasks/spec-name/ # Then: cd ./apps/desktop ✅ SAFE # But: cd /path/to/parent/project ❌ FORBIDDEN - ESCAPES ISOLATION @@ -338,8 +338,8 @@ ls -la [path-to-files] # Make sure the path is correct from your current locati # FIRST: Make sure you're in the working directory root pwd # Should match your working directory -# Add all files EXCEPT .auto-claude directory (spec files should never be committed) -git add . ':!.auto-claude' +# Add all files EXCEPT .aperant directory (spec files should never be committed) +git add . ':!.aperant' # If git add fails with "pathspec did not match", you have a path problem: # 1. Run pwd to see where you are @@ -360,7 +360,7 @@ Verified: QA Fix Session: [N]" ``` -**CRITICAL**: The `:!.auto-claude` pathspec exclusion ensures spec files are NEVER committed. +**CRITICAL**: The `:!.aperant` pathspec exclusion ensures spec files are NEVER committed. **NOTE**: Do NOT push to remote. All work stays local until user reviews and approves. @@ -490,7 +490,7 @@ npx prisma migrate dev --name [name] ### Write Deliverables to the Project, Not Spec Artifacts - All new files (docs, tests, code) go in the project source tree -- NEVER create deliverable files in `.auto-claude/specs/` — that directory is gitignored metadata +- NEVER create deliverable files in `.aperant/specs/` — that directory is gitignored metadata ### Git Configuration - NEVER MODIFY **CRITICAL**: You MUST NOT modify git user configuration. Never run: diff --git a/apps/desktop/prompts/qa_reviewer.md b/apps/desktop/prompts/qa_reviewer.md index 501b0dc0..947d554a 100644 --- a/apps/desktop/prompts/qa_reviewer.md +++ b/apps/desktop/prompts/qa_reviewer.md @@ -480,7 +480,7 @@ cat > qa_report.md << 'EOF' [QA Report content] EOF -# Note: qa_report.md and implementation_plan.json are in .auto-claude/specs/ (gitignored) +# Note: qa_report.md and implementation_plan.json are in .aperant/specs/ (gitignored) # Do NOT commit them - the framework tracks QA status automatically # Only commit actual code changes to the project ``` @@ -517,7 +517,7 @@ Once fixes are complete: EOF -# Note: QA_FIX_REQUEST.md and implementation_plan.json are in .auto-claude/specs/ (gitignored) +# Note: QA_FIX_REQUEST.md and implementation_plan.json are in .aperant/specs/ (gitignored) # Do NOT commit them - the framework tracks QA status automatically # Only commit actual code fixes to the project ``` diff --git a/apps/desktop/src/__tests__/e2e/smoke.test.ts b/apps/desktop/src/__tests__/e2e/smoke.test.ts index bdee6480..4a12f015 100644 --- a/apps/desktop/src/__tests__/e2e/smoke.test.ts +++ b/apps/desktop/src/__tests__/e2e/smoke.test.ts @@ -127,7 +127,7 @@ function setupTestDirs(): void { TEST_PROJECT_PATH = path.join(TEST_DIR, 'test-project'); mkdirSync(TEST_PROJECT_PATH, { recursive: true }); // Create a minimal project structure - mkdirSync(path.join(TEST_PROJECT_PATH, '.auto-claude'), { recursive: true }); + mkdirSync(path.join(TEST_PROJECT_PATH, '.aperant'), { recursive: true }); } // Cleanup test directories diff --git a/apps/desktop/src/__tests__/integration/rate-limit-subtask-recovery.test.ts b/apps/desktop/src/__tests__/integration/rate-limit-subtask-recovery.test.ts index a672a7ce..5893773a 100644 --- a/apps/desktop/src/__tests__/integration/rate-limit-subtask-recovery.test.ts +++ b/apps/desktop/src/__tests__/integration/rate-limit-subtask-recovery.test.ts @@ -23,7 +23,7 @@ let PLAN_PATH: string; // Setup test directories function setupTestDirs(): void { TEST_DIR = mkdtempSync(path.join(tmpdir(), 'rate-limit-recovery-test-')); - TEST_SPEC_DIR = path.join(TEST_DIR, '.auto-claude/specs/001-test-feature'); + TEST_SPEC_DIR = path.join(TEST_DIR, '.aperant/specs/001-test-feature'); PLAN_PATH = path.join(TEST_SPEC_DIR, 'implementation_plan.json'); mkdirSync(TEST_SPEC_DIR, { recursive: true }); } diff --git a/apps/desktop/src/__tests__/integration/task-lifecycle.test.ts b/apps/desktop/src/__tests__/integration/task-lifecycle.test.ts index be9b16cd..aa15c443 100644 --- a/apps/desktop/src/__tests__/integration/task-lifecycle.test.ts +++ b/apps/desktop/src/__tests__/integration/task-lifecycle.test.ts @@ -94,7 +94,7 @@ function setupTestDirs(): void { // Create secure temp directory with random suffix TEST_DIR = mkdtempSync(path.join(tmpdir(), 'task-lifecycle-test-')); TEST_PROJECT_PATH = path.join(TEST_DIR, 'test-project'); - TEST_SPEC_DIR = path.join(TEST_PROJECT_PATH, '.auto-claude/specs/001-test-feature'); + TEST_SPEC_DIR = path.join(TEST_PROJECT_PATH, '.aperant/specs/001-test-feature'); mkdirSync(TEST_SPEC_DIR, { recursive: true }); } diff --git a/apps/desktop/src/main/__tests__/file-watcher.test.ts b/apps/desktop/src/main/__tests__/file-watcher.test.ts index 685e7e89..677851ae 100644 --- a/apps/desktop/src/main/__tests__/file-watcher.test.ts +++ b/apps/desktop/src/main/__tests__/file-watcher.test.ts @@ -74,7 +74,7 @@ describe('FileWatcher concurrency', () => { // ------------------------------------------------------------------------- describe('deduplication: second watch() with same specDir is a no-op', () => { it('should only create one FSWatcher when watch() is called twice with the same specDir while the first is still in-flight', async () => { - const specDir = '/project/.auto-claude/specs/001-task'; + const specDir = '/project/.aperant/specs/001-task'; const taskId = 'task-1'; // To create a real async gap we need an existing watcher whose close() is slow. @@ -111,8 +111,8 @@ describe('FileWatcher concurrency', () => { describe('supersession: watch() with different specDir replaces the in-flight call', () => { it('should let the second call win when the first is awaiting close()', async () => { const taskId = 'task-2'; - const specDir1 = path.join('/project', '.auto-claude', 'specs', '001-first'); - const specDir2 = path.join('/project', '.auto-claude', 'specs', '002-second'); + const specDir1 = path.join('/project', '.aperant', 'specs', '001-first'); + const specDir2 = path.join('/project', '.aperant', 'specs', '002-second'); // First call installs an existing watcher (simulate: the watcher for // specDir1 is already set up so the second watch() needs to close it). @@ -148,8 +148,8 @@ describe('FileWatcher concurrency', () => { it('first watch() bails when pendingWatches changes to a different specDir', async () => { const taskId = 'task-super'; - const specDir1 = path.join('/project', '.auto-claude', 'specs', 'super-first'); - const specDir2 = path.join('/project', '.auto-claude', 'specs', 'super-second'); + const specDir1 = path.join('/project', '.aperant', 'specs', 'super-first'); + const specDir2 = path.join('/project', '.aperant', 'specs', 'super-second'); // Make the first watcher's close() slow so we can interleave. let resolveFirstClose!: () => void; @@ -187,7 +187,7 @@ describe('FileWatcher concurrency', () => { describe('cancellation: unwatch() during in-flight watch() prevents watcher creation', () => { it('should not create a watcher when unwatch() is called before the async gap resolves', async () => { const taskId = 'task-3'; - const specDir = '/project/.auto-claude/specs/003-cancel'; + const specDir = '/project/.aperant/specs/003-cancel'; // There's no pre-existing watcher, so watch() won't call close(). But it // does go async (chokidar.watch is sync but we can test the cancellation @@ -207,7 +207,7 @@ describe('FileWatcher concurrency', () => { ); // Start a second watch() — it will await the slow close(). - const specDir2 = '/project/.auto-claude/specs/003-cancel-v2'; + const specDir2 = '/project/.aperant/specs/003-cancel-v2'; const watchPromise = fw.watch(taskId, specDir2); // While watch() is in-flight, call unwatch(). @@ -231,8 +231,8 @@ describe('FileWatcher concurrency', () => { it('should cancel pending watch() calls and clear pendingWatches', async () => { const taskId1 = 'task-4a'; const taskId2 = 'task-4b'; - const specDir1 = '/project/.auto-claude/specs/004a'; - const specDir2 = '/project/.auto-claude/specs/004b'; + const specDir1 = '/project/.aperant/specs/004a'; + const specDir2 = '/project/.aperant/specs/004b'; // Set up slow-close scenario for taskId1 (so watch() is in-flight). await fw.watch(taskId1, specDir1); @@ -243,7 +243,7 @@ describe('FileWatcher concurrency', () => { ); // Start a new watch for taskId1 with a different specDir — this is now in-flight. - const newSpecDir1 = '/project/.auto-claude/specs/004a-v2'; + const newSpecDir1 = '/project/.aperant/specs/004a-v2'; const watchPromise1 = fw.watch(taskId1, newSpecDir1); // Start a fresh watch for taskId2. @@ -262,7 +262,7 @@ describe('FileWatcher concurrency', () => { // pendingWatches should be cleared (we verify indirectly: a fresh // watch() call for taskId1 must succeed without treating it as a duplicate). - const specDirFresh = path.join('/project', '.auto-claude', 'specs', '004a-fresh'); + const specDirFresh = path.join('/project', '.aperant', 'specs', '004a-fresh'); await fw.watch(taskId1, specDirFresh); expect(fw.isWatching(taskId1)).toBe(true); expect(fw.getWatchedSpecDir(taskId1)).toBe(specDirFresh); @@ -275,7 +275,7 @@ describe('FileWatcher concurrency', () => { describe('getWatchedSpecDir()', () => { it('returns the specDir that was passed to watch()', async () => { const taskId = 'task-5'; - const specDir = path.join('/project', '.auto-claude', 'specs', '005-specdir'); + const specDir = path.join('/project', '.aperant', 'specs', '005-specdir'); await fw.watch(taskId, specDir); @@ -288,8 +288,8 @@ describe('FileWatcher concurrency', () => { it('returns updated specDir after re-watch with different specDir', async () => { const taskId = 'task-5b'; - const specDir1 = path.join('/project', '.auto-claude', 'specs', '005b-first'); - const specDir2 = path.join('/project', '.auto-claude', 'specs', '005b-second'); + const specDir1 = path.join('/project', '.aperant', 'specs', '005b-first'); + const specDir2 = path.join('/project', '.aperant', 'specs', '005b-second'); await fw.watch(taskId, specDir1); expect(fw.getWatchedSpecDir(taskId)).toBe(specDir1); diff --git a/apps/desktop/src/main/__tests__/ipc-handlers.test.ts b/apps/desktop/src/main/__tests__/ipc-handlers.test.ts index 88ede24e..2b9ee417 100644 --- a/apps/desktop/src/main/__tests__/ipc-handlers.test.ts +++ b/apps/desktop/src/main/__tests__/ipc-handlers.test.ts @@ -143,7 +143,7 @@ vi.mock("electron", () => { // Setup test project structure function setupTestProject(): void { mkdirSync(TEST_PROJECT_PATH, { recursive: true }); - mkdirSync(path.join(TEST_PROJECT_PATH, "auto-claude", "specs"), { recursive: true }); + mkdirSync(path.join(TEST_PROJECT_PATH, "aperant", "specs"), { recursive: true }); } // Cleanup test directories @@ -419,15 +419,15 @@ describe("IPC Handlers", { timeout: 30000 }, () => { () => mockMainWindow as never ); - // Create .auto-claude directory first (before adding project so it gets detected) - mkdirSync(path.join(TEST_PROJECT_PATH, ".auto-claude", "specs"), { recursive: true }); + // Create .aperant directory first (before adding project so it gets detected) + mkdirSync(path.join(TEST_PROJECT_PATH, ".aperant", "specs"), { recursive: true }); - // Add a project - it will detect .auto-claude + // Add a project - it will detect .aperant const addResult = await ipcMain.invokeHandler("project:add", {}, TEST_PROJECT_PATH); const projectId = (addResult as { data: { id: string } }).data.id; - // Create a spec directory with implementation plan in .auto-claude/specs - const specDir = path.join(TEST_PROJECT_PATH, ".auto-claude", "specs", "001-test-feature"); + // Create a spec directory with implementation plan in .aperant/specs + const specDir = path.join(TEST_PROJECT_PATH, ".aperant", "specs", "001-test-feature"); mkdirSync(specDir, { recursive: true }); writeFileSync( path.join(specDir, "implementation_plan.json"), @@ -489,8 +489,8 @@ describe("IPC Handlers", { timeout: 30000 }, () => { () => mockMainWindow as never ); - // Create .auto-claude directory first (before adding project so it gets detected) - mkdirSync(path.join(TEST_PROJECT_PATH, ".auto-claude", "specs"), { recursive: true }); + // Create .aperant directory first (before adding project so it gets detected) + mkdirSync(path.join(TEST_PROJECT_PATH, ".aperant", "specs"), { recursive: true }); // Add a project first const addResult = await ipcMain.invokeHandler("project:add", {}, TEST_PROJECT_PATH); @@ -630,7 +630,7 @@ describe("IPC Handlers", { timeout: 30000 }, () => { await ipcMain.invokeHandler("project:add", {}, TEST_PROJECT_PATH); // Create a spec/task directory with implementation_plan.json - const specDir = path.join(TEST_PROJECT_PATH, ".auto-claude", "specs", "task-1"); + const specDir = path.join(TEST_PROJECT_PATH, ".aperant", "specs", "task-1"); mkdirSync(specDir, { recursive: true }); writeFileSync( path.join(specDir, "implementation_plan.json"), diff --git a/apps/desktop/src/main/__tests__/project-store.test.ts b/apps/desktop/src/main/__tests__/project-store.test.ts index 9273f618..6dac3bce 100644 --- a/apps/desktop/src/main/__tests__/project-store.test.ts +++ b/apps/desktop/src/main/__tests__/project-store.test.ts @@ -88,16 +88,16 @@ describe('ProjectStore', () => { expect(project1.id).toBe(project2.id); }); - it('should detect auto-claude directory if present', async () => { - // Create .auto-claude directory (the data directory, not source code) - mkdirSync(path.join(TEST_PROJECT_PATH, '.auto-claude'), { recursive: true }); + it('should detect aperant directory if present', async () => { + // Create .aperant directory (the data directory, not source code) + mkdirSync(path.join(TEST_PROJECT_PATH, '.aperant'), { recursive: true }); const { ProjectStore } = await import('../project-store'); const store = new ProjectStore(); const project = store.addProject(TEST_PROJECT_PATH); - expect(project.autoBuildPath).toBe('.auto-claude'); + expect(project.autoBuildPath).toBe('.aperant'); }); it('should set empty autoBuildPath if not present', async () => { @@ -284,8 +284,8 @@ describe('ProjectStore', () => { }); it('should read tasks from filesystem correctly', async () => { - // Create spec directory structure in .auto-claude (the data directory) - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '001-test-feature'); + // Create spec directory structure in .aperant (the data directory) + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '001-test-feature'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -332,7 +332,7 @@ describe('ProjectStore', () => { }); it('should determine status as backlog when no subtasks completed', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '002-pending'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '002-pending'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -372,7 +372,7 @@ describe('ProjectStore', () => { }); it('should determine status as ai_review when all subtasks completed', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '003-complete'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '003-complete'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -412,7 +412,7 @@ describe('ProjectStore', () => { }); it('should determine status as human_review when plan status is human_review', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '004-rejected'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '004-rejected'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -452,7 +452,7 @@ describe('ProjectStore', () => { }); it('should determine reviewReason from plan when status is human_review', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '005-approved'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '005-approved'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -494,7 +494,7 @@ describe('ProjectStore', () => { it('should determine status as done when plan status is explicitly done', async () => { // User explicitly marking task as done via drag-and-drop sets status to done - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '006-done'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '006-done'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -533,7 +533,7 @@ describe('ProjectStore', () => { }); it('should prefer original task description from requirements.json over plan description', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '007-description-priority'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '007-description-priority'); mkdirSync(specsDir, { recursive: true }); const aiDescription = 'AI-generated implementation plan description'; @@ -633,7 +633,7 @@ describe('ProjectStore', () => { describe('archiveTasks - multi-location handling', () => { it('should archive task from main specs directory only', async () => { // Create spec directory in main location only - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '001-test-task'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '001-test-task'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -666,18 +666,18 @@ describe('ProjectStore', () => { it('should archive task from BOTH main and worktree locations', async () => { // Create spec directory in main location - const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '002-multi-location'); + const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '002-multi-location'); mkdirSync(mainSpecsDir, { recursive: true }); // Create spec directory in worktree location - // Worktree path: .auto-claude/worktrees/tasks//.auto-claude/specs/ + // Worktree path: .aperant/worktrees/tasks//.aperant/specs/ const worktreeDir = path.join( TEST_PROJECT_PATH, - '.auto-claude', + '.aperant', 'worktrees', 'tasks', 'my-worktree', - '.auto-claude', + '.aperant', 'specs', '002-multi-location' ); @@ -724,11 +724,11 @@ describe('ProjectStore', () => { // Create spec directory ONLY in worktree location (not in main) const worktreeDir = path.join( TEST_PROJECT_PATH, - '.auto-claude', + '.aperant', 'worktrees', 'tasks', 'only-worktree', - '.auto-claude', + '.aperant', 'specs', '003-worktree-only' ); @@ -765,8 +765,8 @@ describe('ProjectStore', () => { const { ProjectStore } = await import('../project-store'); const store = new ProjectStore(); - // Create .auto-claude directory so project is recognized - mkdirSync(path.join(TEST_PROJECT_PATH, '.auto-claude'), { recursive: true }); + // Create .aperant directory so project is recognized + mkdirSync(path.join(TEST_PROJECT_PATH, '.aperant'), { recursive: true }); const project = store.addProject(TEST_PROJECT_PATH); // Task doesn't exist anywhere @@ -778,7 +778,7 @@ describe('ProjectStore', () => { it('should reject path traversal attempts in taskId', async () => { // Create a valid spec dir - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', 'valid-task'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', 'valid-task'); mkdirSync(specsDir, { recursive: true }); const plan = { feature: 'Test', phases: [] }; @@ -820,16 +820,16 @@ describe('ProjectStore', () => { describe('unarchiveTasks - multi-location handling', () => { it('should unarchive task from BOTH main and worktree locations', async () => { // Create archived task in both locations - const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '004-unarchive-test'); + const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '004-unarchive-test'); mkdirSync(mainSpecsDir, { recursive: true }); const worktreeDir = path.join( TEST_PROJECT_PATH, - '.auto-claude', + '.aperant', 'worktrees', 'tasks', 'unarchive-worktree', - '.auto-claude', + '.aperant', 'specs', '004-unarchive-test' ); @@ -874,7 +874,7 @@ describe('ProjectStore', () => { describe('cache invalidation', () => { it('should invalidate cache after archiveTasks', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '005-cache-test'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '005-cache-test'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -915,7 +915,7 @@ describe('ProjectStore', () => { }); it('should return fresh data after invalidateTasksCache is called', async () => { - const specsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '006-invalidate-test'); + const specsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '006-invalidate-test'); mkdirSync(specsDir, { recursive: true }); const plan = { @@ -959,16 +959,16 @@ describe('ProjectStore', () => { describe('getTasks - worktree deduplication', () => { it('should not duplicate tasks that exist in both main and worktree', async () => { // Create same task in both main and worktree - const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.auto-claude', 'specs', '007-dedupe-test'); + const mainSpecsDir = path.join(TEST_PROJECT_PATH, '.aperant', 'specs', '007-dedupe-test'); mkdirSync(mainSpecsDir, { recursive: true }); const worktreeDir = path.join( TEST_PROJECT_PATH, - '.auto-claude', + '.aperant', 'worktrees', 'tasks', 'dedupe-worktree', - '.auto-claude', + '.aperant', 'specs', '007-dedupe-test' ); diff --git a/apps/desktop/src/main/agent/agent-manager.ts b/apps/desktop/src/main/agent/agent-manager.ts index 21a53849..2104acba 100644 --- a/apps/desktop/src/main/agent/agent-manager.ts +++ b/apps/desktop/src/main/agent/agent-manager.ts @@ -375,7 +375,7 @@ export class AgentManager extends EventEmitter { const resolved = await this.resolveAuthFromProviderQueue(specModelId, preferredProvider); // Build the serializable session config for the worker - const resolvedSpecDir = specDir ?? path.join(projectPath, '.auto-claude', 'specs', taskId); + const resolvedSpecDir = specDir ?? path.join(projectPath, '.aperant', 'specs', taskId); const sessionConfig: SerializableSessionConfig = { agentType: 'spec_orchestrator' as const, systemPrompt, diff --git a/apps/desktop/src/main/agent/agent-process.ts b/apps/desktop/src/main/agent/agent-process.ts index d3f11421..1d068424 100644 --- a/apps/desktop/src/main/agent/agent-process.ts +++ b/apps/desktop/src/main/agent/agent-process.ts @@ -493,7 +493,7 @@ export class AgentProcessManager { } /** - * Load environment variables from project's .auto-claude/.env file + * Load environment variables from project's .aperant/.env file * This contains frontend-configured settings like memory configuration */ private loadProjectEnv(projectPath: string): Record { @@ -1036,7 +1036,7 @@ export class AgentProcessManager { * Priority (later sources override earlier): * 1. App-wide memory settings from settings.json (NEW - enables memory from onboarding) * 2. Auto-build source .env (prompts directory) - default values - * 3. Project's .auto-claude/.env - Frontend-configured settings (memory, integrations) + * 3. Project's .aperant/.env - Frontend-configured settings (memory, integrations) * 4. Project settings (useClaudeMd) - Runtime overrides */ getCombinedEnv(projectPath: string): Record { diff --git a/apps/desktop/src/main/agent/agent-queue.ts b/apps/desktop/src/main/agent/agent-queue.ts index aada34a5..e5fb48df 100644 --- a/apps/desktop/src/main/agent/agent-queue.ts +++ b/apps/desktop/src/main/agent/agent-queue.ts @@ -225,7 +225,7 @@ export class AgentQueueManager { // which handles both dev (apps/desktop/prompts/) and production (resourcesPath/prompts/) const promptsDir = resolvePromptsDir(); - const outputDir = path.join(projectPath, '.auto-claude', 'ideation'); + const outputDir = path.join(projectPath, '.aperant', 'ideation'); // Emit initial progress this.emitter.emit('ideation-progress', projectId, { @@ -469,7 +469,7 @@ export class AgentQueueManager { this.clearRoadmapProgress(projectPath); // Load and emit the complete roadmap - const roadmapFilePath = path.join(projectPath, '.auto-claude', 'roadmap', 'roadmap.json'); + const roadmapFilePath = path.join(projectPath, '.aperant', 'roadmap', 'roadmap.json'); if (existsSync(roadmapFilePath)) { try { const content = await fsPromises.readFile(roadmapFilePath, 'utf-8'); diff --git a/apps/desktop/src/main/ai/client/__tests__/factory.test.ts b/apps/desktop/src/main/ai/client/__tests__/factory.test.ts index 608dd4a9..cc9fe01f 100644 --- a/apps/desktop/src/main/ai/client/__tests__/factory.test.ts +++ b/apps/desktop/src/main/ai/client/__tests__/factory.test.ts @@ -82,7 +82,7 @@ const FAKE_MODEL = { type: 'language-model', modelId: 'mock-model-id' }; const baseToolContext = { cwd: '/project', projectDir: '/project', - specDir: '/project/.auto-claude/specs/001', + specDir: '/project/.aperant/specs/001', securityProfile: 'standard' as const, } as unknown as ToolContext; diff --git a/apps/desktop/src/main/ai/config/__tests__/agent-configs.test.ts b/apps/desktop/src/main/ai/config/__tests__/agent-configs.test.ts index 7a189a81..2c4a183a 100644 --- a/apps/desktop/src/main/ai/config/__tests__/agent-configs.test.ts +++ b/apps/desktop/src/main/ai/config/__tests__/agent-configs.test.ts @@ -87,11 +87,11 @@ describe('AGENT_CONFIGS', () => { expect(config.thinkingDefault).toBe('low'); }); - it('should configure planner with memory and auto-claude MCP', () => { + it('should configure planner with memory and aperant MCP', () => { const config = AGENT_CONFIGS.planner; expect(config.mcpServers).toContain('context7'); expect(config.mcpServers).toContain('memory'); - expect(config.mcpServers).toContain('auto-claude'); + expect(config.mcpServers).toContain('aperant'); expect(config.mcpServersOptional).toContain('linear'); expect(config.thinkingDefault).toBe('high'); }); @@ -197,7 +197,7 @@ describe('mapMcpServerName', () => { expect(mapMcpServerName('graphiti')).toBe('memory'); expect(mapMcpServerName('graphiti-memory')).toBe('memory'); expect(mapMcpServerName('linear')).toBe('linear'); - expect(mapMcpServerName('auto-claude')).toBe('auto-claude'); + expect(mapMcpServerName('aperant')).toBe('aperant'); }); it('should return null for unknown names', () => { @@ -291,12 +291,12 @@ describe('getRequiredMcpServers', () => { expect(servers).toContain('context7'); }); - it('should support per-agent MCP removals but never remove auto-claude', () => { + it('should support per-agent MCP removals but never remove aperant', () => { const servers = getRequiredMcpServers('coder', { memoryEnabled: true, - agentMcpRemove: 'auto-claude,memory', + agentMcpRemove: 'aperant,memory', }); - expect(servers).toContain('auto-claude'); + expect(servers).toContain('aperant'); expect(servers).not.toContain('memory'); }); }); diff --git a/apps/desktop/src/main/ai/config/agent-configs.ts b/apps/desktop/src/main/ai/config/agent-configs.ts index 0fe5aae9..1449c9ff 100644 --- a/apps/desktop/src/main/ai/config/agent-configs.ts +++ b/apps/desktop/src/main/ai/config/agent-configs.ts @@ -36,15 +36,15 @@ const ALL_BUILTIN_TOOLS = [...BASE_READ_TOOLS, ...BASE_WRITE_TOOLS, ...WEB_TOOLS const SPEC_TOOLS = [...BASE_READ_TOOLS, 'Write', ...WEB_TOOLS] as const; // ============================================================================= -// Auto-Claude MCP Tools (Custom build management) +// Aperant MCP Tools (Custom build management) // ============================================================================= -const TOOL_UPDATE_SUBTASK_STATUS = 'mcp__auto-claude__update_subtask_status'; -const TOOL_GET_BUILD_PROGRESS = 'mcp__auto-claude__get_build_progress'; -const TOOL_RECORD_DISCOVERY = 'mcp__auto-claude__record_discovery'; -const TOOL_RECORD_GOTCHA = 'mcp__auto-claude__record_gotcha'; -const TOOL_GET_SESSION_CONTEXT = 'mcp__auto-claude__get_session_context'; -const TOOL_UPDATE_QA_STATUS = 'mcp__auto-claude__update_qa_status'; +const TOOL_UPDATE_SUBTASK_STATUS = 'mcp__aperant__update_subtask_status'; +const TOOL_GET_BUILD_PROGRESS = 'mcp__aperant__get_build_progress'; +const TOOL_RECORD_DISCOVERY = 'mcp__aperant__record_discovery'; +const TOOL_RECORD_GOTCHA = 'mcp__aperant__record_gotcha'; +const TOOL_GET_SESSION_CONTEXT = 'mcp__aperant__get_session_context'; +const TOOL_UPDATE_QA_STATUS = 'mcp__aperant__update_qa_status'; // ============================================================================= // External MCP Tools @@ -246,7 +246,7 @@ export const AGENT_CONFIGS: Record = { */ build_orchestrator: { tools: [...ALL_BUILTIN_TOOLS, 'SpawnSubagent'], - mcpServers: ['context7', 'memory', 'auto-claude'], + mcpServers: ['context7', 'memory', 'aperant'], mcpServersOptional: ['linear'], autoClaudeTools: [ TOOL_GET_BUILD_PROGRESS, @@ -263,7 +263,7 @@ export const AGENT_CONFIGS: Record = { // ═══════════════════════════════════════════════════════════════════════ planner: { tools: [...ALL_BUILTIN_TOOLS], - mcpServers: ['context7', 'memory', 'auto-claude'], + mcpServers: ['context7', 'memory', 'aperant'], mcpServersOptional: ['linear'], autoClaudeTools: [ TOOL_GET_BUILD_PROGRESS, @@ -274,7 +274,7 @@ export const AGENT_CONFIGS: Record = { }, coder: { tools: [...ALL_BUILTIN_TOOLS], - mcpServers: ['context7', 'memory', 'auto-claude'], + mcpServers: ['context7', 'memory', 'aperant'], mcpServersOptional: ['linear'], autoClaudeTools: [ TOOL_UPDATE_SUBTASK_STATUS, @@ -291,7 +291,7 @@ export const AGENT_CONFIGS: Record = { // ═══════════════════════════════════════════════════════════════════════ qa_reviewer: { tools: [...ALL_BUILTIN_TOOLS], - mcpServers: ['context7', 'memory', 'auto-claude', 'browser'], + mcpServers: ['context7', 'memory', 'aperant', 'browser'], mcpServersOptional: ['linear'], autoClaudeTools: [ TOOL_GET_BUILD_PROGRESS, @@ -302,7 +302,7 @@ export const AGENT_CONFIGS: Record = { }, qa_fixer: { tools: [...ALL_BUILTIN_TOOLS], - mcpServers: ['context7', 'memory', 'auto-claude', 'browser'], + mcpServers: ['context7', 'memory', 'aperant', 'browser'], mcpServersOptional: ['linear'], autoClaudeTools: [ TOOL_UPDATE_SUBTASK_STATUS, @@ -482,7 +482,7 @@ const MCP_SERVER_NAME_MAP: Record = { linear: 'linear', electron: 'electron', puppeteer: 'puppeteer', - 'auto-claude': 'auto-claude', + 'aperant': 'aperant', }; /** @@ -593,11 +593,11 @@ export function getRequiredMcpServers( } } - // Apply per-agent MCP removals (never remove auto-claude) + // Apply per-agent MCP removals (never remove aperant) if (options.agentMcpRemove) { for (const name of options.agentMcpRemove.split(',')) { const mapped = mapMcpServerName(name.trim(), options.customServerIds); - if (mapped && mapped !== 'auto-claude') { + if (mapped && mapped !== 'aperant') { const idx = servers.indexOf(mapped); if (idx !== -1) servers.splice(idx, 1); } diff --git a/apps/desktop/src/main/ai/context/builder.ts b/apps/desktop/src/main/ai/context/builder.ts index 41b97c32..61ea03d3 100644 --- a/apps/desktop/src/main/ai/context/builder.ts +++ b/apps/desktop/src/main/ai/context/builder.ts @@ -33,7 +33,7 @@ import type { // --------------------------------------------------------------------------- function loadProjectIndex(projectDir: string): ProjectIndex { - const indexFile = path.join(projectDir, '.auto-claude', 'project_index.json'); + const indexFile = path.join(projectDir, '.aperant', 'project_index.json'); if (fs.existsSync(indexFile)) { try { return JSON.parse(fs.readFileSync(indexFile, 'utf8')) as ProjectIndex; diff --git a/apps/desktop/src/main/ai/context/search.ts b/apps/desktop/src/main/ai/context/search.ts index b5ca3981..18103a4f 100644 --- a/apps/desktop/src/main/ai/context/search.ts +++ b/apps/desktop/src/main/ai/context/search.ts @@ -14,8 +14,8 @@ import type { FileMatch } from './types.js'; /** Directories that should never be searched. */ const SKIP_DIRS = new Set([ 'node_modules', '.git', '__pycache__', '.venv', 'venv', 'dist', 'build', - '.next', '.nuxt', 'target', 'vendor', '.idea', '.vscode', 'auto-claude', - '.auto-claude', '.pytest_cache', '.mypy_cache', 'coverage', '.turbo', '.cache', + '.next', '.nuxt', 'target', 'vendor', '.idea', '.vscode', + '.aperant', '.pytest_cache', '.mypy_cache', 'coverage', '.turbo', '.cache', 'out', ]); diff --git a/apps/desktop/src/main/ai/context/types.ts b/apps/desktop/src/main/ai/context/types.ts index d47dca30..a18b7ae6 100644 --- a/apps/desktop/src/main/ai/context/types.ts +++ b/apps/desktop/src/main/ai/context/types.ts @@ -55,7 +55,7 @@ export interface ServiceInfo { key_directories?: Record; } -/** Shape of .auto-claude/project_index.json */ +/** Shape of .aperant/project_index.json */ export interface ProjectIndex { services?: Record; [key: string]: unknown; diff --git a/apps/desktop/src/main/ai/mcp/__tests__/client.test.ts b/apps/desktop/src/main/ai/mcp/__tests__/client.test.ts index 151350fe..9d1931ea 100644 --- a/apps/desktop/src/main/ai/mcp/__tests__/client.test.ts +++ b/apps/desktop/src/main/ai/mcp/__tests__/client.test.ts @@ -195,10 +195,10 @@ describe('createMcpClientsForAgent', () => { }); it('creates clients for each resolved server config', async () => { - mockGetRequiredMcpServers.mockReturnValueOnce(['context7', 'auto-claude']); + mockGetRequiredMcpServers.mockReturnValueOnce(['context7', 'aperant']); mockResolveMcpServers.mockReturnValueOnce([ { ...stdioConfig, id: 'context7' }, - { ...stdioConfig, id: 'auto-claude' }, + { ...stdioConfig, id: 'aperant' }, ]); // Two separate mock instances for the two servers mockCreateMCPClient @@ -209,7 +209,7 @@ describe('createMcpClientsForAgent', () => { expect(clients).toHaveLength(2); expect(clients[0].serverId).toBe('context7'); - expect(clients[1].serverId).toBe('auto-claude'); + expect(clients[1].serverId).toBe('aperant'); }); it('skips failed connections without throwing', async () => { diff --git a/apps/desktop/src/main/ai/mcp/__tests__/registry.test.ts b/apps/desktop/src/main/ai/mcp/__tests__/registry.test.ts index 2d8c5f8d..a9797345 100644 --- a/apps/desktop/src/main/ai/mcp/__tests__/registry.test.ts +++ b/apps/desktop/src/main/ai/mcp/__tests__/registry.test.ts @@ -104,23 +104,23 @@ describe('getMcpServerConfig', () => { }); }); - describe('auto-claude', () => { - it('returns auto-claude config with empty specDir as default', () => { - const config = getMcpServerConfig('auto-claude', {}); + describe('aperant', () => { + it('returns aperant config with empty specDir as default', () => { + const config = getMcpServerConfig('aperant', {}); expect(config).not.toBeNull(); - expect(config?.id).toBe('auto-claude'); + expect(config?.id).toBe('aperant'); }); it('injects SPEC_DIR into transport env', () => { - const config = getMcpServerConfig('auto-claude', { specDir: '/project/.auto-claude/specs/001-feature' }); + const config = getMcpServerConfig('aperant', { specDir: '/project/.aperant/specs/001-feature' }); expect(config?.transport.type).toBe('stdio'); if (config?.transport.type === 'stdio') { - expect(config.transport.env?.SPEC_DIR).toBe('/project/.auto-claude/specs/001-feature'); + expect(config.transport.env?.SPEC_DIR).toBe('/project/.aperant/specs/001-feature'); } }); it('uses node command', () => { - const config = getMcpServerConfig('auto-claude', {}); + const config = getMcpServerConfig('aperant', {}); if (config?.transport.type === 'stdio') { expect(config.transport.command).toBe('node'); } @@ -174,9 +174,9 @@ describe('resolveMcpServers', () => { expect(configs[0].id).toBe('memory'); }); - it('passes specDir through to auto-claude config', () => { - const specDir = '/my-project/.auto-claude/specs/042-auth'; - const configs = resolveMcpServers(['auto-claude'], { specDir }); + it('passes specDir through to aperant config', () => { + const specDir = '/my-project/.aperant/specs/042-auth'; + const configs = resolveMcpServers(['aperant'], { specDir }); expect(configs).toHaveLength(1); if (configs[0].transport.type === 'stdio') { expect(configs[0].transport.env?.SPEC_DIR).toBe(specDir); diff --git a/apps/desktop/src/main/ai/mcp/registry.ts b/apps/desktop/src/main/ai/mcp/registry.ts index 54892f8d..5c62a256 100644 --- a/apps/desktop/src/main/ai/mcp/registry.ts +++ b/apps/desktop/src/main/ai/mcp/registry.ts @@ -100,12 +100,12 @@ const PUPPETEER_SERVER: McpServerConfig = { }; /** - * Auto-Claude MCP server - custom build management tools. + * Aperant MCP server - custom build management tools. * Used by planner, coder, and QA agents for build progress tracking. */ function createAutoClaudeServer(specDir: string): McpServerConfig { return { - id: 'auto-claude', + id: 'aperant', name: 'Aperant', description: 'Build management tools (progress tracking, session context)', enabledByDefault: true, @@ -124,7 +124,7 @@ function createAutoClaudeServer(specDir: string): McpServerConfig { /** Options for resolving MCP server configurations */ export interface McpRegistryOptions { - /** Spec directory for auto-claude MCP server */ + /** Spec directory for aperant MCP server */ specDir?: string; /** Memory MCP server URL (if enabled) */ memoryMcpUrl?: string; @@ -175,7 +175,7 @@ export function getMcpServerConfig( case 'puppeteer': return PUPPETEER_SERVER; - case 'auto-claude': { + case 'aperant': { const specDir = options.specDir ?? ''; return createAutoClaudeServer(specDir); } diff --git a/apps/desktop/src/main/ai/mcp/types.ts b/apps/desktop/src/main/ai/mcp/types.ts index c0cefbd4..858e3066 100644 --- a/apps/desktop/src/main/ai/mcp/types.ts +++ b/apps/desktop/src/main/ai/mcp/types.ts @@ -49,7 +49,7 @@ export type McpServerId = | 'memory' | 'electron' | 'puppeteer' - | 'auto-claude'; + | 'aperant'; /** Configuration for a single MCP server */ export interface McpServerConfig { diff --git a/apps/desktop/src/main/ai/memory/graph/incremental-indexer.ts b/apps/desktop/src/main/ai/memory/graph/incremental-indexer.ts index fa4f0696..4de2896c 100644 --- a/apps/desktop/src/main/ai/memory/graph/incremental-indexer.ts +++ b/apps/desktop/src/main/ai/memory/graph/incremental-indexer.ts @@ -46,7 +46,7 @@ export class IncrementalIndexer { ignored: [ '**/node_modules/**', '**/.git/**', - '**/.auto-claude/**', + '**/.aperant/**', '**/dist/**', '**/build/**', '**/.next/**', @@ -313,7 +313,7 @@ export class IncrementalIndexer { private collectSupportedFiles(dir: string, extensions: string[]): string[] { const files: string[] = []; const IGNORED_DIRS = new Set([ - 'node_modules', '.git', '.auto-claude', 'dist', 'build', + 'node_modules', '.git', '.aperant', 'dist', 'build', '.next', '__pycache__', 'target', '.venv', ]); diff --git a/apps/desktop/src/main/ai/merge/file-evolution.ts b/apps/desktop/src/main/ai/merge/file-evolution.ts index 2d868f81..2f2e07f8 100644 --- a/apps/desktop/src/main/ai/merge/file-evolution.ts +++ b/apps/desktop/src/main/ai/merge/file-evolution.ts @@ -7,7 +7,7 @@ * * Manages: * - Baseline capture when worktrees are created - * - File content snapshots in .auto-claude/baselines/ + * - File content snapshots in .aperant/baselines/ * - Task modification tracking with semantic analysis * - Persistence of evolution data */ @@ -198,7 +198,7 @@ export class FileEvolutionTracker { storageDir?: string, semanticAnalyzer?: SemanticAnalyzer, ) { - const resolvedStorageDir = storageDir ?? path.join(projectDir, '.auto-claude'); + const resolvedStorageDir = storageDir ?? path.join(projectDir, '.aperant'); this.storage = new EvolutionStorage(projectDir, resolvedStorageDir); this.analyzer = semanticAnalyzer ?? new SemanticAnalyzer(); this.evolutions = this.storage.loadEvolutions(); diff --git a/apps/desktop/src/main/ai/merge/orchestrator.ts b/apps/desktop/src/main/ai/merge/orchestrator.ts index 02ac252f..10c52e60 100644 --- a/apps/desktop/src/main/ai/merge/orchestrator.ts +++ b/apps/desktop/src/main/ai/merge/orchestrator.ts @@ -110,8 +110,8 @@ function getFileFromBranch( function findWorktree(projectDir: string, taskId: string): string | undefined { // Common worktree locations const candidates = [ - path.join(projectDir, '.auto-claude', 'worktrees', taskId), - path.join(projectDir, '.auto-claude', 'worktrees', 'tasks', taskId), + path.join(projectDir, '.aperant', 'worktrees', taskId), + path.join(projectDir, '.aperant', 'worktrees', 'tasks', taskId), ]; for (const c of candidates) { if (fs.existsSync(c)) return c; @@ -254,7 +254,7 @@ export class MergeOrchestrator { dryRun?: boolean; }) { this.projectDir = path.resolve(options.projectDir); - this.storageDir = options.storageDir ?? path.join(this.projectDir, '.auto-claude'); + this.storageDir = options.storageDir ?? path.join(this.projectDir, '.aperant'); this.enableAi = options.enableAi ?? true; this.dryRun = options.dryRun ?? false; this.aiResolver = options.aiResolver; diff --git a/apps/desktop/src/main/ai/merge/timeline-tracker.ts b/apps/desktop/src/main/ai/merge/timeline-tracker.ts index 8e06abeb..32a1849e 100644 --- a/apps/desktop/src/main/ai/merge/timeline-tracker.ts +++ b/apps/desktop/src/main/ai/merge/timeline-tracker.ts @@ -313,7 +313,7 @@ function getCommitInfo(commitHash: string, cwd: string): Record function getWorktreeFileContent(taskId: string, filePath: string, projectDir: string): string { // Try common worktree locations - const worktreePath = path.join(projectDir, '.auto-claude', 'worktrees', taskId, filePath); + const worktreePath = path.join(projectDir, '.aperant', 'worktrees', taskId, filePath); if (fs.existsSync(worktreePath)) { try { return fs.readFileSync(worktreePath, 'utf8'); @@ -369,7 +369,7 @@ export class FileTimelineTracker { constructor(projectPath: string, storagePath?: string) { this.projectPath = path.resolve(projectPath); - const resolvedStoragePath = storagePath ?? path.join(this.projectPath, '.auto-claude'); + const resolvedStoragePath = storagePath ?? path.join(this.projectPath, '.aperant'); this.persistence = new TimelinePersistence(resolvedStoragePath); this.timelines = this.persistence.loadAllTimelines(); } diff --git a/apps/desktop/src/main/ai/orchestration/__tests__/qa-loop.test.ts b/apps/desktop/src/main/ai/orchestration/__tests__/qa-loop.test.ts index c30ff044..1cb0b39f 100644 --- a/apps/desktop/src/main/ai/orchestration/__tests__/qa-loop.test.ts +++ b/apps/desktop/src/main/ai/orchestration/__tests__/qa-loop.test.ts @@ -49,7 +49,7 @@ import type { SessionResult } from '../../session/types'; // Helpers // --------------------------------------------------------------------------- -const SPEC_DIR = '/project/.auto-claude/specs/001-feature'; +const SPEC_DIR = '/project/.aperant/specs/001-feature'; const PROJECT_DIR = '/project'; function completedPlan(qaStatus?: 'approved' | 'rejected' | 'unknown') { diff --git a/apps/desktop/src/main/ai/orchestration/__tests__/qa-reports.test.ts b/apps/desktop/src/main/ai/orchestration/__tests__/qa-reports.test.ts index 078b8f21..bbb279c5 100644 --- a/apps/desktop/src/main/ai/orchestration/__tests__/qa-reports.test.ts +++ b/apps/desktop/src/main/ai/orchestration/__tests__/qa-reports.test.ts @@ -207,7 +207,7 @@ describe('generateEscalationReport', () => { // --------------------------------------------------------------------------- describe('generateManualTestPlan', () => { - const SPEC_DIR = '/project/.auto-claude/specs/001-feature'; + const SPEC_DIR = '/project/.aperant/specs/001-feature'; const PROJECT_DIR = '/project'; beforeEach(() => { diff --git a/apps/desktop/src/main/ai/orchestration/__tests__/recovery-manager.test.ts b/apps/desktop/src/main/ai/orchestration/__tests__/recovery-manager.test.ts index ba123685..f1e7390b 100644 --- a/apps/desktop/src/main/ai/orchestration/__tests__/recovery-manager.test.ts +++ b/apps/desktop/src/main/ai/orchestration/__tests__/recovery-manager.test.ts @@ -33,7 +33,7 @@ import type { BuildCheckpoint, FailureType } from '../recovery-manager'; // --------------------------------------------------------------------------- const PROJECT_DIR = path.join(path.sep, 'project'); -const SPEC_DIR = path.join(PROJECT_DIR, '.auto-claude', 'specs', '001-feature'); +const SPEC_DIR = path.join(PROJECT_DIR, '.aperant', 'specs', '001-feature'); const MEMORY_DIR = path.join(SPEC_DIR, 'memory'); const ATTEMPT_HISTORY_PATH = path.join(MEMORY_DIR, 'attempt_history.json'); diff --git a/apps/desktop/src/main/ai/orchestration/build-orchestrator.ts b/apps/desktop/src/main/ai/orchestration/build-orchestrator.ts index d04dea93..a6d70abd 100644 --- a/apps/desktop/src/main/ai/orchestration/build-orchestrator.ts +++ b/apps/desktop/src/main/ai/orchestration/build-orchestrator.ts @@ -77,7 +77,7 @@ const PHASE_CONFIG_MAP: Record = { /** Configuration for the build orchestrator */ export interface BuildOrchestratorConfig { - /** Spec directory path (e.g., .auto-claude/specs/001-feature/) */ + /** Spec directory path (e.g., .aperant/specs/001-feature/) */ specDir: string; /** Project root directory */ projectDir: string; diff --git a/apps/desktop/src/main/ai/project/analyzer.ts b/apps/desktop/src/main/ai/project/analyzer.ts index dcbab705..9abaf03f 100644 --- a/apps/desktop/src/main/ai/project/analyzer.ts +++ b/apps/desktop/src/main/ai/project/analyzer.ts @@ -40,8 +40,8 @@ import type { // Constants // --------------------------------------------------------------------------- -const PROFILE_FILENAME = '.auto-claude-security.json'; -const CUSTOM_ALLOWLIST_FILENAME = '.auto-claude-allowlist'; +const PROFILE_FILENAME = '.aperant-security.json'; +const CUSTOM_ALLOWLIST_FILENAME = '.aperant-allowlist'; const HASH_FILES = [ 'package.json', diff --git a/apps/desktop/src/main/ai/project/project-indexer.ts b/apps/desktop/src/main/ai/project/project-indexer.ts index 2ed5dd9c..fce0a9e2 100644 --- a/apps/desktop/src/main/ai/project/project-indexer.ts +++ b/apps/desktop/src/main/ai/project/project-indexer.ts @@ -35,7 +35,7 @@ const SKIP_DIRS = new Set([ '.nuxt', 'target', 'vendor', - '.auto-claude', + '.aperant', 'coverage', '.nyc_output', ]); diff --git a/apps/desktop/src/main/ai/prompts/prompt-loader.ts b/apps/desktop/src/main/ai/prompts/prompt-loader.ts index 6ad1ff34..a2beb56a 100644 --- a/apps/desktop/src/main/ai/prompts/prompt-loader.ts +++ b/apps/desktop/src/main/ai/prompts/prompt-loader.ts @@ -402,10 +402,10 @@ function validateBranchName(branch: string | null | undefined): string | null { // ============================================================================= /** - * Load project_index.json from the project's .auto-claude directory. + * Load project_index.json from the project's .aperant directory. */ export function loadProjectIndex(projectDir: string): Record { - const indexPath = join(projectDir, '.auto-claude', 'project_index.json'); + const indexPath = join(projectDir, '.aperant', 'project_index.json'); if (!existsSync(indexPath)) return {}; try { return JSON.parse(readFileSync(indexPath, 'utf-8')) as Record; diff --git a/apps/desktop/src/main/ai/prompts/subtask-prompt-generator.ts b/apps/desktop/src/main/ai/prompts/subtask-prompt-generator.ts index 0e7663c0..74a43812 100644 --- a/apps/desktop/src/main/ai/prompts/subtask-prompt-generator.ts +++ b/apps/desktop/src/main/ai/prompts/subtask-prompt-generator.ts @@ -28,8 +28,8 @@ import type { /** Patterns to detect worktree isolation */ const WORKTREE_PATH_PATTERNS = [ - /[/\\]\.auto-claude[/\\]worktrees[/\\]tasks[/\\]/, - /[/\\]\.auto-claude[/\\]github[/\\]pr[/\\]worktrees[/\\]/, + /[/\\]\.aperant[/\\]worktrees[/\\]tasks[/\\]/, + /[/\\]\.aperant[/\\]github[/\\]pr[/\\]worktrees[/\\]/, /[/\\]\.worktrees[/\\]/, ]; @@ -106,7 +106,7 @@ function getRelativeSpecPath(specDir: string, projectDir: string): string { // Fallback: just use the spec dir name const parts = resolvedSpec.split(/[/\\]/); - return `./auto-claude/specs/${parts[parts.length - 1]}`; + return `./aperant/specs/${parts[parts.length - 1]}`; } /** diff --git a/apps/desktop/src/main/ai/runners/__tests__/commit-message.test.ts b/apps/desktop/src/main/ai/runners/__tests__/commit-message.test.ts index 82107644..02d989da 100644 --- a/apps/desktop/src/main/ai/runners/__tests__/commit-message.test.ts +++ b/apps/desktop/src/main/ai/runners/__tests__/commit-message.test.ts @@ -161,7 +161,7 @@ describe('generateCommitMessage', () => { // --------------------------------------------------------------------------- it('reads spec.md for title when spec directory exists', async () => { - // Spec directory at .auto-claude/specs/001-add-feature + // Spec directory at .aperant/specs/001-add-feature mockExistsSync.mockImplementation((p: string) => { const normalized = p.replace(/\\/g, '/'); if (normalized.includes('specs/001-add-feature')) return true; diff --git a/apps/desktop/src/main/ai/runners/__tests__/ideation.test.ts b/apps/desktop/src/main/ai/runners/__tests__/ideation.test.ts index 85dedd27..e0b2bc97 100644 --- a/apps/desktop/src/main/ai/runners/__tests__/ideation.test.ts +++ b/apps/desktop/src/main/ai/runners/__tests__/ideation.test.ts @@ -71,7 +71,7 @@ function makeStream(parts: Array>) { function baseConfig(overrides: Partial = {}): IdeationConfig { return { projectDir: '/project', - outputDir: '/project/.auto-claude/ideation', + outputDir: '/project/.aperant/ideation', promptsDir: '/app/prompts', ideationType: 'code_improvements', ...overrides, @@ -285,7 +285,7 @@ describe('runIdeation', () => { mockStreamText.mockReturnValue(makeStream([])); await runIdeation( - baseConfig({ projectDir: '/my/project', outputDir: '/my/project/.auto-claude/ideation' }), + baseConfig({ projectDir: '/my/project', outputDir: '/my/project/.aperant/ideation' }), ); // The system prompt passed to streamText should contain the project dir diff --git a/apps/desktop/src/main/ai/runners/__tests__/roadmap.test.ts b/apps/desktop/src/main/ai/runners/__tests__/roadmap.test.ts index 16721617..2009b135 100644 --- a/apps/desktop/src/main/ai/runners/__tests__/roadmap.test.ts +++ b/apps/desktop/src/main/ai/runners/__tests__/roadmap.test.ts @@ -124,7 +124,7 @@ const VALID_ROADMAP_JSON = JSON.stringify({ function baseConfig(overrides: Partial = {}): RoadmapConfig { return { projectDir: '/project', - outputDir: '/project/.auto-claude/roadmap', + outputDir: '/project/.aperant/roadmap', ...overrides, }; } @@ -277,7 +277,7 @@ describe('runRoadmapGeneration', () => { }); mockStreamText.mockReturnValue(makeStream([])); - await runRoadmapGeneration(baseConfig({ outputDir: '/project/.auto-claude/roadmap' })); + await runRoadmapGeneration(baseConfig({ outputDir: '/project/.aperant/roadmap' })); expect(mockMkdirSync).toHaveBeenCalledWith( expect.stringContaining('roadmap'), @@ -388,7 +388,7 @@ describe('runRoadmapGeneration', () => { // mkdirSync should have been called with the default path expect(mockMkdirSync).toHaveBeenCalledWith( - expect.stringContaining('.auto-claude'), + expect.stringContaining('.aperant'), expect.anything(), ); }); diff --git a/apps/desktop/src/main/ai/runners/commit-message.ts b/apps/desktop/src/main/ai/runners/commit-message.ts index 1d20dd22..c25241b0 100644 --- a/apps/desktop/src/main/ai/runners/commit-message.ts +++ b/apps/desktop/src/main/ai/runners/commit-message.ts @@ -236,10 +236,7 @@ export async function generateCommitMessage( } = config; // Find spec directory - let specDir = join(projectDir, '.auto-claude', 'specs', specName); - if (!existsSync(specDir)) { - specDir = join(projectDir, 'auto-claude', 'specs', specName); - } + const specDir = join(projectDir, '.aperant', 'specs', specName); // Get context from spec files const specContext = existsSync(specDir) ? getSpecContext(specDir) : { diff --git a/apps/desktop/src/main/ai/runners/github/pr-creator.ts b/apps/desktop/src/main/ai/runners/github/pr-creator.ts index e42dbb28..ee411f49 100644 --- a/apps/desktop/src/main/ai/runners/github/pr-creator.ts +++ b/apps/desktop/src/main/ai/runners/github/pr-creator.ts @@ -141,7 +141,7 @@ function gatherPRContext( * Extract a brief summary from the spec file for fallback PR body. */ function extractSpecSummary(projectDir: string, specId: string): string { - const specFile = join(projectDir, '.auto-claude', 'specs', specId, 'spec.md'); + const specFile = join(projectDir, '.aperant', 'specs', specId, 'spec.md'); if (!existsSync(specFile)) { return `Implements ${specId}`; } diff --git a/apps/desktop/src/main/ai/runners/ideation.ts b/apps/desktop/src/main/ai/runners/ideation.ts index 4b75fe46..cfc3180c 100644 --- a/apps/desktop/src/main/ai/runners/ideation.ts +++ b/apps/desktop/src/main/ai/runners/ideation.ts @@ -160,7 +160,7 @@ export async function runIdeation( const toolContext: ToolContext = { cwd: projectDir, projectDir, - specDir: join(projectDir, '.auto-claude', 'specs'), + specDir: join(projectDir, '.aperant', 'specs'), securityProfile: null as unknown as SecurityProfile, abortSignal, }; diff --git a/apps/desktop/src/main/ai/runners/insights.ts b/apps/desktop/src/main/ai/runners/insights.ts index d4da7daa..d5ef9679 100644 --- a/apps/desktop/src/main/ai/runners/insights.ts +++ b/apps/desktop/src/main/ai/runners/insights.ts @@ -99,7 +99,7 @@ function loadProjectContext(projectDir: string): string { const contextParts: string[] = []; // Load project index if available - const indexPath = join(projectDir, '.auto-claude', 'project_index.json'); + const indexPath = join(projectDir, '.aperant', 'project_index.json'); if (existsSync(indexPath)) { const index = safeParseJson>(readFileSync(indexPath, 'utf-8')); if (index) { @@ -116,7 +116,7 @@ function loadProjectContext(projectDir: string): string { } // Load roadmap if available - const roadmapPath = join(projectDir, '.auto-claude', 'roadmap', 'roadmap.json'); + const roadmapPath = join(projectDir, '.aperant', 'roadmap', 'roadmap.json'); if (existsSync(roadmapPath)) { const roadmap = safeParseJson>(readFileSync(roadmapPath, 'utf-8')); if (roadmap) { @@ -132,7 +132,7 @@ function loadProjectContext(projectDir: string): string { } // Load existing tasks - const tasksPath = join(projectDir, '.auto-claude', 'specs'); + const tasksPath = join(projectDir, '.aperant', 'specs'); if (existsSync(tasksPath)) { try { const taskDirs = readdirSync(tasksPath, { withFileTypes: true }) @@ -246,7 +246,7 @@ export async function runInsightsQuery( const toolContext: ToolContext = { cwd: projectDir, projectDir, - specDir: join(projectDir, '.auto-claude', 'specs'), + specDir: join(projectDir, '.aperant', 'specs'), securityProfile: null as unknown as SecurityProfile, abortSignal, }; diff --git a/apps/desktop/src/main/ai/runners/roadmap.ts b/apps/desktop/src/main/ai/runners/roadmap.ts index b589af4c..3b475ac3 100644 --- a/apps/desktop/src/main/ai/runners/roadmap.ts +++ b/apps/desktop/src/main/ai/runners/roadmap.ts @@ -39,7 +39,7 @@ const MAX_STEPS_PER_PHASE = 30; export interface RoadmapConfig { /** Project directory path */ projectDir: string; - /** Output directory for roadmap files (defaults to .auto-claude/roadmap/) */ + /** Output directory for roadmap files (defaults to .aperant/roadmap/) */ outputDir?: string; /** Model shorthand (defaults to 'sonnet') */ modelShorthand?: ModelShorthand; @@ -443,7 +443,7 @@ export async function runRoadmapGeneration( abortSignal, } = config; - const outputDir = config.outputDir ?? join(projectDir, '.auto-claude', 'roadmap'); + const outputDir = config.outputDir ?? join(projectDir, '.aperant', 'roadmap'); // Ensure output directory exists if (!existsSync(outputDir)) { @@ -454,7 +454,7 @@ export async function runRoadmapGeneration( const toolContext: ToolContext = { cwd: projectDir, projectDir, - specDir: join(projectDir, '.auto-claude', 'specs'), + specDir: join(projectDir, '.aperant', 'specs'), securityProfile: null as unknown as SecurityProfile, abortSignal, }; diff --git a/apps/desktop/src/main/ai/security/security-profile.ts b/apps/desktop/src/main/ai/security/security-profile.ts index 041a35d5..49704b73 100644 --- a/apps/desktop/src/main/ai/security/security-profile.ts +++ b/apps/desktop/src/main/ai/security/security-profile.ts @@ -2,7 +2,7 @@ * Security Profile Management * ============================ * - * Loads and caches project security profiles from .auto-claude/ config. + * Loads and caches project security profiles from .aperant/ config. * Provides SecurityProfile instances consumed by bash-validator.ts. * * NOTE: With the denylist security model, SecurityProfile command sets are no @@ -23,8 +23,8 @@ import type { SecurityProfile } from './bash-validator'; // Constants // --------------------------------------------------------------------------- -const PROFILE_FILENAME = '.auto-claude-security.json'; -const ALLOWLIST_FILENAME = '.auto-claude-allowlist'; +const PROFILE_FILENAME = '.aperant-security.json'; +const ALLOWLIST_FILENAME = '.aperant-allowlist'; // --------------------------------------------------------------------------- // Cache state diff --git a/apps/desktop/src/main/ai/security/validators/process-validators.ts b/apps/desktop/src/main/ai/security/validators/process-validators.ts index 5c3a91e5..53fcb0d4 100644 --- a/apps/desktop/src/main/ai/security/validators/process-validators.ts +++ b/apps/desktop/src/main/ai/security/validators/process-validators.ts @@ -86,7 +86,7 @@ const BLOCKED_PROCESS_NAMES = new Set([ // -- Self-protection (don't let the agent kill its own host) -- 'electron', 'Electron', - 'auto-claude', + 'aperant', 'Aperant', ]); diff --git a/apps/desktop/src/main/ai/session/__tests__/progress-tracker.test.ts b/apps/desktop/src/main/ai/session/__tests__/progress-tracker.test.ts index 84ea0e51..c5ad7e5a 100644 --- a/apps/desktop/src/main/ai/session/__tests__/progress-tracker.test.ts +++ b/apps/desktop/src/main/ai/session/__tests__/progress-tracker.test.ts @@ -33,7 +33,7 @@ describe('ProgressTracker', () => { type: 'tool-call', toolName: 'Write', toolCallId: 'c1', - args: { file_path: '/project/.auto-claude/specs/001/implementation_plan.json' }, + args: { file_path: '/project/.aperant/specs/001/implementation_plan.json' }, }); expect(result).not.toBeNull(); diff --git a/apps/desktop/src/main/ai/tools/__tests__/registry.test.ts b/apps/desktop/src/main/ai/tools/__tests__/registry.test.ts index ba20621c..eb3d8adb 100644 --- a/apps/desktop/src/main/ai/tools/__tests__/registry.test.ts +++ b/apps/desktop/src/main/ai/tools/__tests__/registry.test.ts @@ -251,12 +251,12 @@ describe('getRequiredMcpServers (registry)', () => { expect(servers).toContain('context7'); }); - it('should support per-agent MCP REMOVE overrides but protect auto-claude', () => { + it('should support per-agent MCP REMOVE overrides but protect aperant', () => { const servers = getRequiredMcpServers('coder', { memoryEnabled: true, - mcpConfig: { AGENT_MCP_coder_REMOVE: 'auto-claude,memory' }, + mcpConfig: { AGENT_MCP_coder_REMOVE: 'aperant,memory' }, }); - expect(servers).toContain('auto-claude'); + expect(servers).toContain('aperant'); expect(servers).not.toContain('memory'); }); }); diff --git a/apps/desktop/src/main/ai/tools/registry.ts b/apps/desktop/src/main/ai/tools/registry.ts index d38372f5..4d426cf4 100644 --- a/apps/desktop/src/main/ai/tools/registry.ts +++ b/apps/desktop/src/main/ai/tools/registry.ts @@ -221,7 +221,7 @@ export function getRequiredMcpServers( const removals = removeValue.split(',').map((s) => s.trim()).filter(Boolean); for (const server of removals) { const mapped = mapMcpServerName(server, customServerIds); - if (mapped && mapped !== 'auto-claude') { + if (mapped && mapped !== 'aperant') { servers = servers.filter((s) => s !== mapped); } } diff --git a/apps/desktop/src/main/ai/tools/truncation.ts b/apps/desktop/src/main/ai/tools/truncation.ts index 447908f1..1155c1ea 100644 --- a/apps/desktop/src/main/ai/tools/truncation.ts +++ b/apps/desktop/src/main/ai/tools/truncation.ts @@ -44,7 +44,7 @@ export interface TruncationResult { * * @param output - The raw tool output string * @param toolName - Name of the tool (for spillover filename) - * @param projectDir - Project directory (spillover written to .auto-claude/tool-output/) + * @param projectDir - Project directory (spillover written to .aperant/tool-output/) * @param maxBytes - Override max bytes limit (default: MAX_BYTES) * @returns TruncationResult with potentially truncated content */ @@ -67,7 +67,7 @@ export function truncateToolOutput( } // Exceeds limits — spill to disk - const spilloverDir = path.join(projectDir, '.auto-claude', 'tool-output'); + const spilloverDir = path.join(projectDir, '.aperant', 'tool-output'); try { fs.mkdirSync(spilloverDir, { recursive: true }); } catch { diff --git a/apps/desktop/src/main/ai/tools/types.ts b/apps/desktop/src/main/ai/tools/types.ts index 9ee673cc..683eb1d5 100644 --- a/apps/desktop/src/main/ai/tools/types.ts +++ b/apps/desktop/src/main/ai/tools/types.ts @@ -23,7 +23,7 @@ export interface ToolContext { cwd: string; /** Root directory of the project being worked on */ projectDir: string; - /** Spec directory for the current task (e.g., .auto-claude/specs/001-feature/) */ + /** Spec directory for the current task (e.g., .aperant/specs/001-feature/) */ specDir: string; /** Security profile governing command allowlists */ securityProfile: SecurityProfile; diff --git a/apps/desktop/src/main/ai/worktree/worktree-manager.ts b/apps/desktop/src/main/ai/worktree/worktree-manager.ts index d5deac4a..308d20e5 100644 --- a/apps/desktop/src/main/ai/worktree/worktree-manager.ts +++ b/apps/desktop/src/main/ai/worktree/worktree-manager.ts @@ -7,9 +7,9 @@ * * Creates and manages git worktrees for autonomous task execution. * Each task runs in an isolated worktree at: - * {projectPath}/.auto-claude/worktrees/tasks/{specId}/ + * {projectPath}/.aperant/worktrees/tasks/{specId}/ * on branch: - * auto-claude/{specId} + * aperant/{specId} * * The function is idempotent — calling it repeatedly with the same specId * returns the existing worktree without error. @@ -78,7 +78,7 @@ export interface WorktreeResult { * the remote ref (preserves gitignored files) * @param pushNewBranches If true, push the branch to origin and set upstream * tracking after worktree creation. Defaults to true. - * @param autoBuildPath Optional custom data directory (e.g. ".auto-claude"). + * @param autoBuildPath Optional custom data directory (e.g. ".aperant"). * Passed to getSpecsDir() for spec-copy logic. */ export async function createOrGetWorktree( @@ -89,8 +89,8 @@ export async function createOrGetWorktree( pushNewBranches = true, autoBuildPath?: string, ): Promise { - const worktreePath = join(projectPath, '.auto-claude/worktrees/tasks', specId); - const branchName = `auto-claude/${specId}`; + const worktreePath = join(projectPath, '.aperant/worktrees/tasks', specId); + const branchName = `aperant/${specId}`; // ------------------------------------------------------------------ // Step 1: Prune stale worktree references from git's internal records @@ -239,11 +239,11 @@ export async function createOrGetWorktree( // ------------------------------------------------------------------ // Step 7: Copy spec directory into the worktree // - // .auto-claude/specs/ is gitignored, so it is NOT present in the + // .aperant/specs/ is gitignored, so it is NOT present in the // newly-created worktree checkout. Copy it from the main project so // that agents can read spec.md, implementation_plan.json, etc. // ------------------------------------------------------------------ - const specsRelDir = getSpecsDir(autoBuildPath); // e.g. ".auto-claude/specs" + const specsRelDir = getSpecsDir(autoBuildPath); // e.g. ".aperant/specs" const sourceSpecDir = join(projectPath, specsRelDir, specId); const destSpecDir = join(worktreePath, specsRelDir, specId); diff --git a/apps/desktop/src/main/changelog/__tests__/changelog-service.integration.test.ts b/apps/desktop/src/main/changelog/__tests__/changelog-service.integration.test.ts index 1a675763..17bdcb3b 100644 --- a/apps/desktop/src/main/changelog/__tests__/changelog-service.integration.test.ts +++ b/apps/desktop/src/main/changelog/__tests__/changelog-service.integration.test.ts @@ -35,7 +35,7 @@ describe('ChangelogService - Task Filtering Integration', () => { // Create temporary test directory testDir = mkdtempSync(path.join(tmpdir(), 'changelog-test-')); projectPath = path.join(testDir, 'test-project'); - specsDir = path.join(projectPath, '.auto-claude', 'specs'); + specsDir = path.join(projectPath, '.aperant', 'specs'); // Create project structure mkdirSync(projectPath, { recursive: true }); diff --git a/apps/desktop/src/main/changelog/changelog-service.ts b/apps/desktop/src/main/changelog/changelog-service.ts index 0ba31698..fefb0a12 100644 --- a/apps/desktop/src/main/changelog/changelog-service.ts +++ b/apps/desktop/src/main/changelog/changelog-service.ts @@ -54,7 +54,7 @@ export class ChangelogService extends EventEmitter { /** * Check if debug mode is enabled - * Checks DEBUG from auto-claude/.env and DEBUG from process.env + * Checks DEBUG from aperant/.env and DEBUG from process.env */ private isDebugEnabled(): boolean { // Cache the result after first check @@ -78,7 +78,7 @@ export class ChangelogService extends EventEmitter { } /** - * Debug logging - only logs when DEBUG=true in auto-claude/.env or DEBUG is set + * Debug logging - only logs when DEBUG=true in aperant/.env or DEBUG is set */ private debug(...args: unknown[]): void { if (this.isDebugEnabled()) { diff --git a/apps/desktop/src/main/config-paths.ts b/apps/desktop/src/main/config-paths.ts index 839da5b8..09724d51 100644 --- a/apps/desktop/src/main/config-paths.ts +++ b/apps/desktop/src/main/config-paths.ts @@ -18,7 +18,7 @@ import * as path from 'path'; import * as os from 'os'; import { isLinux } from './platform'; -const APP_NAME = 'auto-claude'; +const APP_NAME = 'aperant'; /** * Get the XDG config home directory @@ -70,11 +70,11 @@ export function getAppCacheDir(): string { /** * Get the memories storage directory - * This is where graph databases are stored (previously ~/.auto-claude/memories) + * This is where graph databases are stored (previously ~/.aperant/memories) */ export function getMemoriesDir(): string { // For compatibility, we still support the legacy path - const legacyPath = path.join(os.homedir(), '.auto-claude', 'memories'); + const legacyPath = path.join(os.homedir(), '.aperant', 'memories'); // On Linux with XDG variables set (AppImage, Flatpak, Snap), use XDG path if (isLinux() && (process.env.XDG_DATA_HOME || process.env.APPIMAGE || process.env.SNAP || process.env.FLATPAK_ID)) { diff --git a/apps/desktop/src/main/insights/paths.ts b/apps/desktop/src/main/insights/paths.ts index 4433990a..fcea3a50 100644 --- a/apps/desktop/src/main/insights/paths.ts +++ b/apps/desktop/src/main/insights/paths.ts @@ -1,6 +1,6 @@ import path from 'path'; -const INSIGHTS_DIR = '.auto-claude/insights'; +const INSIGHTS_DIR = '.aperant/insights'; const SESSIONS_DIR = 'sessions'; const CURRENT_SESSION_FILE = 'current_session.json'; diff --git a/apps/desktop/src/main/ipc-handlers/README.md b/apps/desktop/src/main/ipc-handlers/README.md index 6ae86748..98cc4379 100644 --- a/apps/desktop/src/main/ipc-handlers/README.md +++ b/apps/desktop/src/main/ipc-handlers/README.md @@ -16,7 +16,7 @@ Handles project lifecycle and Python environment management: - `PROJECT_REMOVE` - Remove project - `PROJECT_LIST` - List all projects - `PROJECT_UPDATE_SETTINGS` - Update project settings -- `PROJECT_INITIALIZE` - Initialize .auto-claude directory +- `PROJECT_INITIALIZE` - Initialize .aperant directory - `PROJECT_CHECK_VERSION` - Check initialization status - `project:has-local-source` - Check if project has local auto-claude source - Python environment initialization and status events diff --git a/apps/desktop/src/main/ipc-handlers/context/utils.ts b/apps/desktop/src/main/ipc-handlers/context/utils.ts index 41e94ecd..1dccf8f3 100644 --- a/apps/desktop/src/main/ipc-handlers/context/utils.ts +++ b/apps/desktop/src/main/ipc-handlers/context/utils.ts @@ -218,7 +218,7 @@ export interface MemoryDatabaseDetails { export function getMemoryDatabaseDetails(projectEnvVars: EnvironmentVars): MemoryDatabaseDetails { const dbPath = projectEnvVars['GRAPHITI_DB_PATH'] || process.env.GRAPHITI_DB_PATH || - require('path').join(require('os').homedir(), '.auto-claude', 'memories'); + require('path').join(require('os').homedir(), '.aperant', 'memories'); const database = projectEnvVars['GRAPHITI_DATABASE'] || process.env.GRAPHITI_DATABASE || diff --git a/apps/desktop/src/main/ipc-handlers/env-handlers.ts b/apps/desktop/src/main/ipc-handlers/env-handlers.ts index 7f7e5c3a..0d5a9c72 100644 --- a/apps/desktop/src/main/ipc-handlers/env-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/env-handlers.ts @@ -288,7 +288,7 @@ ${existingVars['OLLAMA_EMBEDDING_DIM'] ? `OLLAMA_EMBEDDING_DIM=${existingVars['O # LadybugDB Database (embedded - no Docker required) ${existingVars['GRAPHITI_DATABASE'] ? `GRAPHITI_DATABASE=${existingVars['GRAPHITI_DATABASE']}` : '# GRAPHITI_DATABASE=auto_claude_memory'} -${existingVars['GRAPHITI_DB_PATH'] ? `GRAPHITI_DB_PATH=${existingVars['GRAPHITI_DB_PATH']}` : '# GRAPHITI_DB_PATH=~/.auto-claude/memories'} +${existingVars['GRAPHITI_DB_PATH'] ? `GRAPHITI_DB_PATH=${existingVars['GRAPHITI_DB_PATH']}` : '# GRAPHITI_DB_PATH=~/.aperant/memories'} `; return content; diff --git a/apps/desktop/src/main/ipc-handlers/github/__tests__/runner-env-handlers.test.ts b/apps/desktop/src/main/ipc-handlers/github/__tests__/runner-env-handlers.test.ts index c100a227..37405f86 100644 --- a/apps/desktop/src/main/ipc-handlers/github/__tests__/runner-env-handlers.test.ts +++ b/apps/desktop/src/main/ipc-handlers/github/__tests__/runner-env-handlers.test.ts @@ -242,7 +242,7 @@ function createProject(): Project { id: 'project-1', name: 'Test Project', path: projectPath, - autoBuildPath: '.auto-claude', + autoBuildPath: '.aperant', settings: { model: 'default', memoryBackend: 'file', diff --git a/apps/desktop/src/main/ipc-handlers/github/autofix-handlers.ts b/apps/desktop/src/main/ipc-handlers/github/autofix-handlers.ts index f4476b7e..b370f1c5 100644 --- a/apps/desktop/src/main/ipc-handlers/github/autofix-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/github/autofix-handlers.ts @@ -28,7 +28,7 @@ import type { ModelShorthand, ThinkingLevel } from '../../ai/config/types'; const { debug: debugLog } = createContextLogger('GitHub AutoFix'); /** - * Auto-fix configuration stored in .auto-claude/github/config.json + * Auto-fix configuration stored in .aperant/github/config.json */ export interface AutoFixConfig { enabled: boolean; @@ -99,7 +99,7 @@ export interface BatchProgress { * Get the GitHub directory for a project */ function getGitHubDir(project: Project): string { - return path.join(project.path, '.auto-claude', 'github'); + return path.join(project.path, '.aperant', 'github'); } /** diff --git a/apps/desktop/src/main/ipc-handlers/github/pr-handlers.ts b/apps/desktop/src/main/ipc-handlers/github/pr-handlers.ts index 1ff9f8e0..9cec98da 100644 --- a/apps/desktop/src/main/ipc-handlers/github/pr-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/github/pr-handlers.ts @@ -822,7 +822,7 @@ async function performCIWaitCheck( * Get the GitHub directory for a project */ function getGitHubDir(project: Project): string { - return path.join(project.path, ".auto-claude", "github"); + return path.join(project.path, ".aperant", "github"); } /** @@ -1081,7 +1081,7 @@ function createEmptyPRLogs(prNumber: number, repo: string, isFollowup: boolean): /** * Get PR logs file path * - * Logs are stored at `.auto-claude/github/pr/logs_${prNumber}.json` within the project directory. + * Logs are stored at `.aperant/github/pr/logs_${prNumber}.json` within the project directory. * This provides persistent storage for streaming log data during PR reviews. */ function getPRLogsPath(project: Project, prNumber: number): string { @@ -1163,7 +1163,7 @@ function addLogEntry(logs: PRLogs, entry: PRLogEntry): boolean { * This class implements a hybrid push/pull approach for real-time log streaming: * * 1. **File-Based Storage**: Logs are saved to disk every 3 entries (saveInterval) - * - Location: .auto-claude/github/pr/logs_${prNumber}.json + * - Location: .aperant/github/pr/logs_${prNumber}.json * - Format: JSON with phase status and log entries * * 2. **Push-Based Updates**: Emits IPC events (GITHUB_PR_LOGS_UPDATED) after each save @@ -1281,7 +1281,7 @@ class PRLogCollector { * Two-step update mechanism: * -------------------------- * 1. **File Write**: Persists logs to disk via savePRLogs() - * - Creates/updates .auto-claude/github/pr/logs_${prNumber}.json + * - Creates/updates .aperant/github/pr/logs_${prNumber}.json * - Updates the `updated_at` timestamp * * 2. **IPC Push Event**: Sends GITHUB_PR_LOGS_UPDATED to renderer @@ -2508,7 +2508,7 @@ export function registerPRHandlers(getMainWindow: () => BrowserWindow | null): v } // Use temp file to avoid shell escaping issues - const tmpFile = join(project.path, ".auto-claude", "tmp_comment_body.txt"); + const tmpFile = join(project.path, ".aperant", "tmp_comment_body.txt"); try { writeFileSync(tmpFile, body, "utf-8"); // Use execFileSync with arguments array to prevent command injection @@ -2733,7 +2733,7 @@ export function registerPRHandlers(getMainWindow: () => BrowserWindow | null): v const result = await withProjectOrNull(projectId, async (project) => { // Check if review exists and has reviewed_commit_sha - const githubDir = path.join(project.path, ".auto-claude", "github"); + const githubDir = path.join(project.path, ".aperant", "github"); const reviewPath = path.join(githubDir, "pr", `review_${prNumber}.json`); let review: PRReviewResult; diff --git a/apps/desktop/src/main/ipc-handlers/github/triage-handlers.ts b/apps/desktop/src/main/ipc-handlers/github/triage-handlers.ts index 93f4209a..93e1ebf3 100644 --- a/apps/desktop/src/main/ipc-handlers/github/triage-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/github/triage-handlers.ts @@ -92,7 +92,7 @@ export interface TriageProgress { * Get the GitHub directory for a project */ function getGitHubDir(project: Project): string { - return path.join(project.path, '.auto-claude', 'github'); + return path.join(project.path, '.aperant', 'github'); } /** diff --git a/apps/desktop/src/main/ipc-handlers/gitlab/autofix-handlers.ts b/apps/desktop/src/main/ipc-handlers/gitlab/autofix-handlers.ts index 87b8edf0..abef008c 100644 --- a/apps/desktop/src/main/ipc-handlers/gitlab/autofix-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/gitlab/autofix-handlers.ts @@ -68,7 +68,7 @@ function validatePathWithinProject(projectPath: string, resolvedPath: string): v * Get the GitLab directory for a project */ function getGitLabDir(project: Project): string { - const gitlabDir = path.join(project.path, '.auto-claude', 'gitlab'); + const gitlabDir = path.join(project.path, '.aperant', 'gitlab'); validatePathWithinProject(project.path, gitlabDir); return gitlabDir; } diff --git a/apps/desktop/src/main/ipc-handlers/gitlab/mr-review-handlers.ts b/apps/desktop/src/main/ipc-handlers/gitlab/mr-review-handlers.ts index 8ade48cd..0e361db6 100644 --- a/apps/desktop/src/main/ipc-handlers/gitlab/mr-review-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/gitlab/mr-review-handlers.ts @@ -58,7 +58,7 @@ function getReviewKey(projectId: string, mrIid: number): string { * Get the GitLab directory for a project */ function getGitLabDir(project: Project): string { - return path.join(project.path, '.auto-claude', 'gitlab'); + return path.join(project.path, '.aperant', 'gitlab'); } async function waitForRebaseCompletion( @@ -774,7 +774,7 @@ export function registerMRReviewHandlers( debugLog('checkNewCommits handler called', { projectId, mrIid }); const result = await withProjectOrNull(projectId, async (project) => { - const gitlabDir = path.join(project.path, '.auto-claude', 'gitlab'); + const gitlabDir = path.join(project.path, '.aperant', 'gitlab'); const reviewPath = path.join(gitlabDir, 'mr', `review_${mrIid}.json`); if (!fs.existsSync(reviewPath)) { diff --git a/apps/desktop/src/main/ipc-handlers/gitlab/triage-handlers.ts b/apps/desktop/src/main/ipc-handlers/gitlab/triage-handlers.ts index c99593e8..d40ed4be 100644 --- a/apps/desktop/src/main/ipc-handlers/gitlab/triage-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/gitlab/triage-handlers.ts @@ -95,7 +95,7 @@ function sanitizeTriageResult(result: GitLabTriageResult): { * Get the GitLab directory for a project */ function getGitLabDir(project: Project): string { - return path.join(project.path, '.auto-claude', 'gitlab'); + return path.join(project.path, '.aperant', 'gitlab'); } /** diff --git a/apps/desktop/src/main/ipc-handlers/project-handlers.ts b/apps/desktop/src/main/ipc-handlers/project-handlers.ts index e5567c17..089a0970 100644 --- a/apps/desktop/src/main/ipc-handlers/project-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/project-handlers.ts @@ -17,7 +17,9 @@ import { isInitialized, hasLocalSource, checkGitStatus, - initializeGit + initializeGit, + needsMigration, + migrateProject } from '../project-initializer'; import { getToolPath } from '../cli-tool-manager'; import type { BrowserWindow } from 'electron'; @@ -274,11 +276,11 @@ export function registerProjectHandlers( ipcMain.handle( IPC_CHANNELS.PROJECT_LIST, async (): Promise> => { - // Validate that .auto-claude folders still exist for all projects + // Validate that .aperant folders still exist for all projects // If a folder was deleted, reset autoBuildPath so UI prompts for reinitialization const resetIds = projectStore.validateProjects(); if (resetIds.length > 0) { - console.warn('[IPC] PROJECT_LIST: Detected missing .auto-claude folders for', resetIds.length, 'project(s)'); + console.warn('[IPC] PROJECT_LIST: Detected missing .aperant folders for', resetIds.length, 'project(s)'); } const projects = projectStore.getProjects(); @@ -382,7 +384,7 @@ export function registerProjectHandlers( if (result.success) { // Update project's autoBuildPath - projectStore.updateAutoBuildPath(projectId, '.auto-claude'); + projectStore.updateAutoBuildPath(projectId, '.aperant'); } return { success: result.success, data: result, error: result.error }; @@ -396,7 +398,7 @@ export function registerProjectHandlers( ); // PROJECT_CHECK_VERSION now just checks if project is initialized - // Version tracking for .auto-claude is removed since it only contains data + // Version tracking for .aperant is removed since it only contains data ipcMain.handle( IPC_CHANNELS.PROJECT_CHECK_VERSION, async (_, projectId: string): Promise> => { @@ -410,7 +412,7 @@ export function registerProjectHandlers( success: true, data: { isInitialized: isInitialized(project.path), - updateAvailable: false // No updates for .auto-claude - it's just data + updateAvailable: false // No updates for .aperant - it's just data } }; } catch (error) { @@ -441,6 +443,20 @@ export function registerProjectHandlers( } ); + // ============================================ + // Migration Operations + // ============================================ + + // Check if project needs migration from .auto-claude to .aperant + ipcMain.handle('project:needs-migration', async (_event, projectPath: string) => { + return needsMigration(projectPath); + }); + + // Migrate project from .auto-claude to .aperant + ipcMain.handle('project:migrate', async (_event, projectPath: string) => { + return migrateProject(projectPath); + }); + // ============================================ // Git Operations // ============================================ diff --git a/apps/desktop/src/main/ipc-handlers/sections/task-section.txt b/apps/desktop/src/main/ipc-handlers/sections/task-section.txt index d077902d..14c81bd2 100644 --- a/apps/desktop/src/main/ipc-handlers/sections/task-section.txt +++ b/apps/desktop/src/main/ipc-handlers/sections/task-section.txt @@ -258,7 +258,7 @@ return { success: false, error: 'Task not found' }; } - const autoBuildDir = project.autoBuildPath || '.auto-claude'; + const autoBuildDir = project.autoBuildPath || '.aperant'; const specDir = path.join(project.path, autoBuildDir, 'specs', task.specId); if (!existsSync(specDir)) { @@ -775,7 +775,7 @@ } // Get the spec directory - const autoBuildDir = project.autoBuildPath || '.auto-claude'; + const autoBuildDir = project.autoBuildPath || '.aperant'; const specDir = path.join( project.path, autoBuildDir, @@ -1207,7 +1207,7 @@ } const runScript = path.join(sourcePath, 'run.py'); - const specDir = path.join(project.path, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const specDir = path.join(project.path, project.autoBuildPath || '.aperant', 'specs', task.specId); if (!existsSync(specDir)) { return { success: false, error: 'Spec directory not found' }; diff --git a/apps/desktop/src/main/ipc-handlers/sections/task_extracted.txt b/apps/desktop/src/main/ipc-handlers/sections/task_extracted.txt index d077902d..14c81bd2 100644 --- a/apps/desktop/src/main/ipc-handlers/sections/task_extracted.txt +++ b/apps/desktop/src/main/ipc-handlers/sections/task_extracted.txt @@ -258,7 +258,7 @@ return { success: false, error: 'Task not found' }; } - const autoBuildDir = project.autoBuildPath || '.auto-claude'; + const autoBuildDir = project.autoBuildPath || '.aperant'; const specDir = path.join(project.path, autoBuildDir, 'specs', task.specId); if (!existsSync(specDir)) { @@ -775,7 +775,7 @@ } // Get the spec directory - const autoBuildDir = project.autoBuildPath || '.auto-claude'; + const autoBuildDir = project.autoBuildPath || '.aperant'; const specDir = path.join( project.path, autoBuildDir, @@ -1207,7 +1207,7 @@ } const runScript = path.join(sourcePath, 'run.py'); - const specDir = path.join(project.path, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const specDir = path.join(project.path, project.autoBuildPath || '.aperant', 'specs', task.specId); if (!existsSync(specDir)) { return { success: false, error: 'Spec directory not found' }; diff --git a/apps/desktop/src/main/ipc-handlers/task/__tests__/logs-integration.test.ts b/apps/desktop/src/main/ipc-handlers/task/__tests__/logs-integration.test.ts index b2298de5..0a291b97 100644 --- a/apps/desktop/src/main/ipc-handlers/task/__tests__/logs-integration.test.ts +++ b/apps/desktop/src/main/ipc-handlers/task/__tests__/logs-integration.test.ts @@ -101,7 +101,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; const mockLogs: TaskLogs = { @@ -158,9 +158,9 @@ describe('Task Logs Integration (IPC → Service → State)', () => { expect(result.data).toEqual(mockLogs); expect(projectStore.getProject).toHaveBeenCalledWith('project-123'); expect(taskLogService.loadLogs).toHaveBeenCalledWith( - path.join('/absolute/path/to/project', '.auto-claude/specs', '001-test-task'), + path.join('/absolute/path/to/project', '.aperant/specs', '001-test-task'), '/absolute/path/to/project', - '.auto-claude/specs', + '.aperant/specs', '001-test-task' ); }); @@ -173,7 +173,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: './relative/path', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; const mockLogs: TaskLogs = { @@ -228,7 +228,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -250,7 +250,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -274,7 +274,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -298,7 +298,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -310,9 +310,9 @@ describe('Task Logs Integration (IPC → Service → State)', () => { expect(result.success).toBe(true); expect(taskLogService.startWatching).toHaveBeenCalledWith( '001-test-task', - path.join('/absolute/path/to/project', '.auto-claude/specs', '001-test-task'), + path.join('/absolute/path/to/project', '.aperant/specs', '001-test-task'), '/absolute/path/to/project', - '.auto-claude/specs' + '.aperant/specs' ); }); @@ -343,7 +343,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -355,9 +355,9 @@ describe('Task Logs Integration (IPC → Service → State)', () => { expect(result.success).toBe(true); expect(taskLogService.startWatching).toHaveBeenCalledWith( 'nonexistent-spec', - path.join('/absolute/path/to/project', '.auto-claude/specs', 'nonexistent-spec'), + path.join('/absolute/path/to/project', '.aperant/specs', 'nonexistent-spec'), '/absolute/path/to/project', - '.auto-claude/specs' + '.aperant/specs' ); }); @@ -369,7 +369,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); @@ -422,7 +422,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProjectRelative = { id: 'project-123', path: './my-project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProjectRelative); @@ -463,7 +463,7 @@ describe('Task Logs Integration (IPC → Service → State)', () => { const mockProject = { id: 'project-123', path: '/absolute/path/to/project', - autoBuildPath: '.auto-claude' + autoBuildPath: '.aperant' }; (projectStore.getProject as Mock).mockReturnValue(mockProject); diff --git a/apps/desktop/src/main/ipc-handlers/task/__tests__/worktree-branch-validation.test.ts b/apps/desktop/src/main/ipc-handlers/task/__tests__/worktree-branch-validation.test.ts index a7d318bd..bcf4330a 100644 --- a/apps/desktop/src/main/ipc-handlers/task/__tests__/worktree-branch-validation.test.ts +++ b/apps/desktop/src/main/ipc-handlers/task/__tests__/worktree-branch-validation.test.ts @@ -12,10 +12,10 @@ import { describe, expect, it } from 'vitest'; import { GIT_BRANCH_REGEX, validateWorktreeBranch } from '../worktree-handlers'; describe('GIT_BRANCH_REGEX', () => { - it('should accept valid auto-claude branch names', () => { - expect(GIT_BRANCH_REGEX.test('auto-claude/my-feature')).toBe(true); - expect(GIT_BRANCH_REGEX.test('auto-claude/123-fix-bug')).toBe(true); - expect(GIT_BRANCH_REGEX.test('auto-claude/feature_with_underscore')).toBe(true); + it('should accept valid aperant branch names', () => { + expect(GIT_BRANCH_REGEX.test('aperant/my-feature')).toBe(true); + expect(GIT_BRANCH_REGEX.test('aperant/123-fix-bug')).toBe(true); + expect(GIT_BRANCH_REGEX.test('aperant/feature_with_underscore')).toBe(true); }); it('should accept valid feature branch names', () => { @@ -46,28 +46,28 @@ describe('GIT_BRANCH_REGEX', () => { }); describe('validateWorktreeBranch', () => { - const expectedBranch = 'auto-claude/my-feature-123'; + const expectedBranch = 'aperant/my-feature-123'; describe('exact match scenarios', () => { it('should use detected branch when it matches expected exactly', () => { - const result = validateWorktreeBranch('auto-claude/my-feature-123', expectedBranch); - expect(result.branchToDelete).toBe('auto-claude/my-feature-123'); + const result = validateWorktreeBranch('aperant/my-feature-123', expectedBranch); + expect(result.branchToDelete).toBe('aperant/my-feature-123'); expect(result.usedFallback).toBe(false); expect(result.reason).toBe('exact_match'); }); }); describe('pattern match scenarios', () => { - it('should allow other auto-claude branches (specId renamed)', () => { - const result = validateWorktreeBranch('auto-claude/renamed-feature', expectedBranch); - expect(result.branchToDelete).toBe('auto-claude/renamed-feature'); + it('should allow other aperant branches (specId renamed)', () => { + const result = validateWorktreeBranch('aperant/renamed-feature', expectedBranch); + expect(result.branchToDelete).toBe('aperant/renamed-feature'); expect(result.usedFallback).toBe(false); expect(result.reason).toBe('pattern_match'); }); - it('should allow auto-claude branches with different formats', () => { - const result = validateWorktreeBranch('auto-claude/001-task', expectedBranch); - expect(result.branchToDelete).toBe('auto-claude/001-task'); + it('should allow aperant branches with different formats', () => { + const result = validateWorktreeBranch('aperant/001-task', expectedBranch); + expect(result.branchToDelete).toBe('aperant/001-task'); expect(result.usedFallback).toBe(false); expect(result.reason).toBe('pattern_match'); }); @@ -142,17 +142,17 @@ describe('validateWorktreeBranch', () => { expect(result.reason).toBe('invalid_pattern'); }); - it('should handle branch that starts with auto-claude but is malformed', () => { - // "auto-claude" without a slash should still be rejected - const result = validateWorktreeBranch('auto-claude', expectedBranch); + it('should handle branch that starts with aperant but is malformed', () => { + // "aperant" without a slash should still be rejected + const result = validateWorktreeBranch('aperant', expectedBranch); expect(result.branchToDelete).toBe(expectedBranch); expect(result.usedFallback).toBe(true); expect(result.reason).toBe('invalid_pattern'); }); - it('should reject auto-claude/ with no suffix (invalid branch name)', () => { - // "auto-claude/" alone is not a valid branch name - needs actual specId - const result = validateWorktreeBranch('auto-claude/', expectedBranch); + it('should reject aperant/ with no suffix (invalid branch name)', () => { + // "aperant/" alone is not a valid branch name - needs actual specId + const result = validateWorktreeBranch('aperant/', expectedBranch); expect(result.branchToDelete).toBe(expectedBranch); expect(result.usedFallback).toBe(true); expect(result.reason).toBe('invalid_pattern'); diff --git a/apps/desktop/src/main/ipc-handlers/task/crud-handlers.ts b/apps/desktop/src/main/ipc-handlers/task/crud-handlers.ts index 76561d2b..2a0c4151 100644 --- a/apps/desktop/src/main/ipc-handlers/task/crud-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/task/crud-handlers.ts @@ -462,7 +462,7 @@ export function registerTaskCRUDHandlers(agentManager: AgentManager): void { return { success: false, error: 'Task not found' }; } - const autoBuildDir = project.autoBuildPath || '.auto-claude'; + const autoBuildDir = project.autoBuildPath || '.aperant'; const specDir = path.join(project.path, autoBuildDir, 'specs', task.specId); if (!existsSync(specDir)) { @@ -674,7 +674,7 @@ export function registerTaskCRUDHandlers(agentManager: AgentManager): void { console.error(`[IPC] TASK_LOAD_IMAGE_THUMBNAIL: Unknown project: "${projectPath}"`); return { success: false, error: 'Unknown project' }; } - const autoBuildPath = project.autoBuildPath || '.auto-claude'; + const autoBuildPath = project.autoBuildPath || '.aperant'; // Build full path to the image const specsDir = getSpecsDir(autoBuildPath); diff --git a/apps/desktop/src/main/ipc-handlers/task/execution-handlers.ts b/apps/desktop/src/main/ipc-handlers/task/execution-handlers.ts index d3d62eb2..336f261e 100644 --- a/apps/desktop/src/main/ipc-handlers/task/execution-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/task/execution-handlers.ts @@ -468,15 +468,15 @@ export function registerTaskExecutionHandlers( } // Step 3: Clean untracked files that came from the merge - // IMPORTANT: Exclude .auto-claude directory to preserve specs and worktree data - const cleanResult = spawnSync(getToolPath('git'), ['clean', '-fd', '-e', '.auto-claude'], { + // IMPORTANT: Exclude .aperant directory to preserve specs and worktree data + const cleanResult = spawnSync(getToolPath('git'), ['clean', '-fd', '-e', '.aperant'], { cwd: project.path, encoding: 'utf-8', stdio: 'pipe', env: getIsolatedGitEnv() }); if (cleanResult.status === 0) { - console.log('[TASK_REVIEW] Cleaned untracked files in main (excluding .auto-claude)'); + console.log('[TASK_REVIEW] Cleaned untracked files in main (excluding .aperant)'); } console.log('[TASK_REVIEW] Main branch restored to pre-merge state'); diff --git a/apps/desktop/src/main/ipc-handlers/task/worktree-handlers.ts b/apps/desktop/src/main/ipc-handlers/task/worktree-handlers.ts index 3ff3ac25..27eca657 100644 --- a/apps/desktop/src/main/ipc-handlers/task/worktree-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/task/worktree-handlers.ts @@ -33,9 +33,9 @@ export const GIT_BRANCH_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9._/-]*[a-zA-Z0-9]$|^[a-zA /** * Validates a detected branch name and returns the safe branch to delete. * - * Why `auto-claude/` prefix is considered safe: - * - All task worktrees use branches named `auto-claude/{specId}` - * - This pattern is controlled by Auto-Claude, not user input + * Why `aperant/` prefix is considered safe: + * - All task worktrees use branches named `aperant/{specId}` + * - This pattern is controlled by Aperant, not user input * - If detected branch matches this pattern, it's a valid task branch * - If it doesn't match (e.g., `main`, `develop`, `feature/xxx`), it's likely * the main project's branch being incorrectly detected from a corrupted worktree @@ -66,9 +66,9 @@ export function validateWorktreeBranch( }; } - // Matches auto-claude pattern with valid specId (not just "auto-claude/") + // Matches aperant pattern with valid specId (not just "aperant/") // The specId must be non-empty for this to be a valid task branch - if (detectedBranch.startsWith('auto-claude/') && detectedBranch.length > 'auto-claude/'.length) { + if (detectedBranch.startsWith('aperant/') && detectedBranch.length > 'aperant/'.length) { return { branchToDelete: detectedBranch, usedFallback: false, @@ -1480,7 +1480,7 @@ function getEffectiveBaseBranch(projectPath: string, specId: string, projectMain } // 1. Try task metadata baseBranch - const specDir = path.join(projectPath, '.auto-claude', 'specs', specId); + const specDir = path.join(projectPath, '.aperant', 'specs', specId); const taskBaseBranch = getTaskBaseBranch(specDir); if (taskBaseBranch) { return taskBaseBranch; @@ -1755,7 +1755,7 @@ export function registerWorktreeHandlers( ): void { /** * Get the worktree status for a task - * Per-spec architecture: Each spec has its own worktree at .auto-claude/worktrees/tasks/{spec-name}/ + * Per-spec architecture: Each spec has its own worktree at .aperant/worktrees/tasks/{spec-name}/ */ ipcMain.handle( IPC_CHANNELS.TASK_WORKTREE_STATUS, @@ -1766,7 +1766,7 @@ export function registerWorktreeHandlers( return { success: false, error: 'Task not found' }; } - // Find worktree at .auto-claude/worktrees/tasks/{spec-name}/ + // Find worktree at .aperant/worktrees/tasks/{spec-name}/ const worktreePath = findTaskWorktree(project.path, task.specId); if (!worktreePath) { @@ -1871,7 +1871,7 @@ export function registerWorktreeHandlers( /** * Get the diff for a task's worktree - * Per-spec architecture: Each spec has its own worktree at .auto-claude/worktrees/tasks/{spec-name}/ + * Per-spec architecture: Each spec has its own worktree at .aperant/worktrees/tasks/{spec-name}/ */ ipcMain.handle( IPC_CHANNELS.TASK_WORKTREE_DIFF, @@ -1882,7 +1882,7 @@ export function registerWorktreeHandlers( return { success: false, error: 'Task not found' }; } - // Find worktree at .auto-claude/worktrees/tasks/{spec-name}/ + // Find worktree at .aperant/worktrees/tasks/{spec-name}/ const worktreePath = findTaskWorktree(project.path, task.specId); if (!worktreePath) { @@ -1987,7 +1987,7 @@ export function registerWorktreeHandlers( debug('Found task:', task.specId, 'project:', project.path); - const specDir = path.join(project.path, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const specDir = path.join(project.path, project.autoBuildPath || '.aperant', 'specs', task.specId); const worktreePath = findTaskWorktree(project.path, task.specId); // Auto-fix any misconfigured bare repo before merge operation @@ -2031,7 +2031,7 @@ export function registerWorktreeHandlers( const aiResolverFn = createMergeResolverFn(modelShorthand, 'low'); // Create the merge orchestrator - const storageDir = path.join(project.path, project.autoBuildPath || '.auto-claude'); + const storageDir = path.join(project.path, project.autoBuildPath || '.aperant'); const orchestrator = new MergeOrchestrator({ projectDir: project.path, storageDir, @@ -2126,7 +2126,7 @@ export function registerWorktreeHandlers( if (!hasActualStagedChanges) { // Check if worktree branch was already merged (merge commit exists) - const specBranch = `auto-claude/${task.specId}`; + const specBranch = `aperant/${task.specId}`; try { // Check if current branch contains all commits from spec branch // git merge-base --is-ancestor returns exit code 0 if true, 1 if false @@ -2269,7 +2269,7 @@ export function registerWorktreeHandlers( ]; // Add worktree plan path if worktree exists if (worktreePath) { - const worktreeSpecDir = path.join(worktreePath, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const worktreeSpecDir = path.join(worktreePath, project.autoBuildPath || '.aperant', 'specs', task.specId); planPaths.push({ path: path.join(worktreeSpecDir, AUTO_BUILD_PATHS.IMPLEMENTATION_PLAN), isMain: false }); } @@ -2433,7 +2433,7 @@ export function registerWorktreeHandlers( // 1. Task metadata baseBranch (explicit task-level override) // 2. Project settings mainBranch (project-level default) // 3. Default to 'main' - const specDir = path.join(project.path, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const specDir = path.join(project.path, project.autoBuildPath || '.aperant', 'specs', task.specId); const taskBaseBranch = getTaskBaseBranch(specDir); const projectMainBranch = project.settings?.mainBranch; const effectiveBaseBranch = taskBaseBranch || projectMainBranch || 'main'; @@ -2442,7 +2442,7 @@ export function registerWorktreeHandlers( // Run preview using the TypeScript MergeOrchestrator in dry-run mode // (no AI resolver needed for preview — only conflict detection and analysis) - const storageDir = path.join(project.path, project.autoBuildPath || '.auto-claude'); + const storageDir = path.join(project.path, project.autoBuildPath || '.aperant'); const orchestrator = new MergeOrchestrator({ projectDir: project.path, storageDir, @@ -2515,7 +2515,7 @@ export function registerWorktreeHandlers( /** * Discard the worktree changes - * Per-spec architecture: Each spec has its own worktree at .auto-claude/worktrees/tasks/{spec-name}/ + * Per-spec architecture: Each spec has its own worktree at .aperant/worktrees/tasks/{spec-name}/ * * Note: Uses the shared cleanupWorktree utility which handles Windows-specific issues * where `git worktree remove --force` fails when the directory contains untracked files. @@ -2530,7 +2530,7 @@ export function registerWorktreeHandlers( return { success: false, error: 'Task not found' }; } - // Find worktree at .auto-claude/worktrees/tasks/{spec-name}/ + // Find worktree at .aperant/worktrees/tasks/{spec-name}/ const worktreePath = findTaskWorktree(project.path, task.specId); if (!worktreePath) { @@ -2622,7 +2622,7 @@ export function registerWorktreeHandlers( return { success: false, error: 'Project path is invalid' }; } - // Find worktree at .auto-claude/worktrees/tasks/{spec-name}/ + // Find worktree at .aperant/worktrees/tasks/{spec-name}/ const worktreePath = findTaskWorktree(project.path, specName); if (!worktreePath) { @@ -2670,7 +2670,7 @@ export function registerWorktreeHandlers( /** * List all spec worktrees for a project - * Per-spec architecture: Each spec has its own worktree at .auto-claude/worktrees/tasks/{spec-name}/ + * Per-spec architecture: Each spec has its own worktree at .aperant/worktrees/tasks/{spec-name}/ */ ipcMain.handle( IPC_CHANNELS.TASK_LIST_WORKTREES, @@ -2699,7 +2699,7 @@ export function registerWorktreeHandlers( // Used for orphan detection - worktrees without a matching task are orphaned const tasks = projectStore.getTasks(projectId); // Track if task lookup was successful (empty array with existing specs dir = lookup failed) - const mainSpecsDir = path.join(project.path, '.auto-claude', 'specs'); + const mainSpecsDir = path.join(project.path, '.aperant', 'specs'); const taskLookupSuccessful = tasks.length > 0 || !existsSync(mainSpecsDir); // Helper to process a single worktree entry (async) @@ -2997,7 +2997,7 @@ export function registerWorktreeHandlers( debug('Found task:', task.specId, 'project:', project.path); - const specDir = path.join(project.path, project.autoBuildPath || '.auto-claude', 'specs', task.specId); + const specDir = path.join(project.path, project.autoBuildPath || '.aperant', 'specs', task.specId); // Use EAFP pattern - try to read specDir and catch ENOENT try { @@ -3034,7 +3034,7 @@ export function registerWorktreeHandlers( // Determine base branch and branch name const taskBaseBranch = getTaskBaseBranch(specDir); const baseBranch = options?.targetBranch || taskBaseBranch || 'main'; - const branchName = `auto-claude/${task.specId}`; + const branchName = `aperant/${task.specId}`; const prTitle = options?.title || `auto-claude: ${task.specId}`; if (taskBaseBranch) { diff --git a/apps/desktop/src/main/ipc-handlers/terminal/worktree-handlers.ts b/apps/desktop/src/main/ipc-handlers/terminal/worktree-handlers.ts index 5f6be075..41dc75e1 100644 --- a/apps/desktop/src/main/ipc-handlers/terminal/worktree-handlers.ts +++ b/apps/desktop/src/main/ipc-handlers/terminal/worktree-handlers.ts @@ -195,7 +195,7 @@ function getDefaultBranch(projectPath: string): string { return project.settings.mainBranch; } - const envPath = path.join(projectPath, '.auto-claude', '.env'); + const envPath = path.join(projectPath, '.aperant', '.env'); if (existsSync(envPath)) { try { const content = readFileSync(envPath, 'utf-8'); @@ -291,7 +291,7 @@ const DEFAULT_STRATEGY_MAP: Record { // Validate projectPath against registered projects @@ -1061,9 +1061,9 @@ async function listOtherWorktrees(projectPath: string): Promise p.path === absolutePath); if (existing) { - // Validate that .auto-claude folder still exists for existing project + // Validate that .aperant folder still exists for existing project // If manually deleted, reset autoBuildPath so UI prompts for reinitialization if (existing.autoBuildPath && !isInitialized(existing.path)) { - console.warn(`[ProjectStore] .auto-claude folder was deleted for project "${existing.name}" - resetting autoBuildPath`); + console.warn(`[ProjectStore] .aperant folder was deleted for project "${existing.name}" - resetting autoBuildPath`); existing.autoBuildPath = ''; existing.updatedAt = new Date(); this.save(); @@ -111,7 +111,7 @@ export class ProjectStore { // Derive name from path if not provided const projectName = name || path.basename(absolutePath); - // Determine auto-claude path (supports both 'auto-claude' and '.auto-claude') + // Determine aperant path const autoBuildPath = getAutoBuildPath(absolutePath) || ''; const project: Project = { @@ -213,11 +213,11 @@ export class ProjectStore { } /** - * Validate all projects to ensure their .auto-claude folders still exist. + * Validate all projects to ensure their .aperant folders still exist. * If a project has autoBuildPath set but the folder was deleted, * reset autoBuildPath to empty string so the UI prompts for reinitialization. * - * @returns Array of project IDs that were reset due to missing .auto-claude folder + * @returns Array of project IDs that were reset due to missing .aperant folder */ validateProjects(): string[] { const resetProjectIds: string[] = []; @@ -235,9 +235,9 @@ export class ProjectStore { continue; // Don't reset - let user handle this case } - // Check if .auto-claude folder still exists + // Check if .aperant folder still exists if (!isInitialized(project.path)) { - console.warn(`[ProjectStore] .auto-claude folder missing for project "${project.name}" at ${project.path}`); + console.warn(`[ProjectStore] .aperant folder missing for project "${project.name}" at ${project.path}`); project.autoBuildPath = ''; project.updatedAt = new Date(); resetProjectIds.push(project.id); @@ -247,7 +247,7 @@ export class ProjectStore { if (hasChanges) { this.save(); - console.warn(`[ProjectStore] Reset ${resetProjectIds.length} project(s) due to missing .auto-claude folder`); + console.warn(`[ProjectStore] Reset ${resetProjectIds.length} project(s) due to missing .aperant folder`); } return resetProjectIds; diff --git a/apps/desktop/src/main/release-service.ts b/apps/desktop/src/main/release-service.ts index e7203cb8..fccf184f 100644 --- a/apps/desktop/src/main/release-service.ts +++ b/apps/desktop/src/main/release-service.ts @@ -344,7 +344,7 @@ export class ReleaseService extends EventEmitter { tasks: Task[] ): Promise { const unmerged: UnmergedWorktreeInfo[] = []; - const worktreesDir = path.join(projectPath, '.auto-claude', 'worktrees', 'tasks'); + const worktreesDir = path.join(projectPath, '.aperant', 'worktrees', 'tasks'); if (!existsSync(worktreesDir)) { return []; diff --git a/apps/desktop/src/main/services/profile/profile-manager.test.ts b/apps/desktop/src/main/services/profile/profile-manager.test.ts index e2e33658..d7d881d1 100644 --- a/apps/desktop/src/main/services/profile/profile-manager.test.ts +++ b/apps/desktop/src/main/services/profile/profile-manager.test.ts @@ -119,15 +119,15 @@ describe('profile-manager', () => { expect(result).toEqual(mockData); }); - it('should use auto-claude directory for profiles.json path', async () => { + it('should use aperant directory for profiles.json path', async () => { fsMocks.readFile.mockRejectedValue(new Error('ENOENT')); await loadProfilesFile(); - // Verify the file path includes auto-claude + // Verify the file path includes aperant const readFileCalls = fsMocks.readFile.mock.calls; const filePath = readFileCalls[0]?.[0]; - expect(filePath).toContain('auto-claude'); + expect(filePath).toContain('aperant'); expect(filePath).toContain('profiles.json'); }); }); @@ -147,7 +147,7 @@ describe('profile-manager', () => { const filePath = writeFileCall?.[0]; const content = writeFileCall?.[1]; - expect(filePath).toContain('auto-claude'); + expect(filePath).toContain('aperant'); expect(filePath).toContain('profiles.json'); expect(content).toBe(JSON.stringify(mockData, null, 2)); }); diff --git a/apps/desktop/src/main/services/profile/profile-manager.ts b/apps/desktop/src/main/services/profile/profile-manager.ts index dcb75d28..205a1d94 100644 --- a/apps/desktop/src/main/services/profile/profile-manager.ts +++ b/apps/desktop/src/main/services/profile/profile-manager.ts @@ -14,11 +14,11 @@ import * as lockfile from 'proper-lockfile'; import type { APIProfile, ProfilesFile } from '@shared/types/profile'; /** - * Get the path to profiles.json in the auto-claude directory + * Get the path to profiles.json in the aperant directory */ export function getProfilesFilePath(): string { const userDataPath = app.getPath('userData'); - return path.join(userDataPath, 'auto-claude', 'profiles.json'); + return path.join(userDataPath, 'aperant', 'profiles.json'); } /** diff --git a/apps/desktop/src/main/task-log-service.ts b/apps/desktop/src/main/task-log-service.ts index ec7af2c3..c1fceb9c 100644 --- a/apps/desktop/src/main/task-log-service.ts +++ b/apps/desktop/src/main/task-log-service.ts @@ -164,7 +164,7 @@ export class TaskLogService extends EventEmitter { * * @param specDir - Main project spec directory * @param projectPath - Optional: Project root path (needed to find worktree if not registered) - * @param specsRelPath - Optional: Relative path to specs (e.g., "auto-claude/specs") + * @param specsRelPath - Optional: Relative path to specs (e.g., "aperant/specs") * @param specId - Optional: Spec ID (needed to find worktree if not registered) */ loadLogs(specDir: string, projectPath?: string, specsRelPath?: string, specId?: string): TaskLogs | null { @@ -247,7 +247,7 @@ export class TaskLogService extends EventEmitter { * @param specId - The spec ID (e.g., "013-screenshots-on-tasks") * @param specDir - Main project spec directory * @param projectPath - Optional: Project root path (needed to find worktree) - * @param specsRelPath - Optional: Relative path to specs (e.g., "auto-claude/specs") + * @param specsRelPath - Optional: Relative path to specs (e.g., "aperant/specs") */ startWatching(specId: string, specDir: string, projectPath?: string, specsRelPath?: string): void { debugLog('[TaskLogService.startWatching] Starting watch:', { diff --git a/apps/desktop/src/main/utils/git-isolation.ts b/apps/desktop/src/main/utils/git-isolation.ts index 3c7328b0..890ffa95 100644 --- a/apps/desktop/src/main/utils/git-isolation.ts +++ b/apps/desktop/src/main/utils/git-isolation.ts @@ -151,7 +151,7 @@ export function detectWorktreeBranch( options: { timeout?: number; logPrefix?: string } = {} ): WorktreeBranchDetectionResult { const { timeout = 30000, logPrefix = '[WORKTREE_BRANCH_DETECTION]' } = options; - const expectedBranch = `auto-claude/${specId}`; + const expectedBranch = `aperant/${specId}`; let branch = expectedBranch; let usingFallback = false; diff --git a/apps/desktop/src/main/utils/profile-manager.test.ts b/apps/desktop/src/main/utils/profile-manager.test.ts index a47804d2..e502df2d 100644 --- a/apps/desktop/src/main/utils/profile-manager.test.ts +++ b/apps/desktop/src/main/utils/profile-manager.test.ts @@ -106,15 +106,15 @@ describe('profile-manager', () => { expect(result).toEqual(mockData); }); - it('should use auto-claude directory for profiles.json path', async () => { + it('should use aperant directory for profiles.json path', async () => { vi.mocked(fsPromises.readFile).mockRejectedValue(new Error('ENOENT')); await loadProfilesFile(); - // Verify the file path includes auto-claude + // Verify the file path includes aperant const readFileCalls = vi.mocked(fsPromises.readFile).mock.calls; const filePath = readFileCalls[0]?.[0]; - expect(filePath).toContain('auto-claude'); + expect(filePath).toContain('aperant'); expect(filePath).toContain('profiles.json'); }); }); @@ -136,7 +136,7 @@ describe('profile-manager', () => { const filePath = writeFileCall?.[0]; const content = writeFileCall?.[1]; - expect(filePath).toContain('auto-claude'); + expect(filePath).toContain('aperant'); expect(filePath).toContain('profiles.json'); expect(content).toBe(JSON.stringify(mockData, null, 2)); }); diff --git a/apps/desktop/src/main/utils/profile-manager.ts b/apps/desktop/src/main/utils/profile-manager.ts index 2b7177ae..791ae581 100644 --- a/apps/desktop/src/main/utils/profile-manager.ts +++ b/apps/desktop/src/main/utils/profile-manager.ts @@ -11,11 +11,11 @@ import { app } from 'electron'; import type { ProfilesFile } from '../../shared/types/profile'; /** - * Get the path to profiles.json in the auto-claude directory + * Get the path to profiles.json in the aperant directory */ export function getProfilesFilePath(): string { const userDataPath = app.getPath('userData'); - return path.join(userDataPath, 'auto-claude', 'profiles.json'); + return path.join(userDataPath, 'aperant', 'profiles.json'); } /** diff --git a/apps/desktop/src/main/utils/spec-number-lock.ts b/apps/desktop/src/main/utils/spec-number-lock.ts index a6e168bd..6803e125 100644 --- a/apps/desktop/src/main/utils/spec-number-lock.ts +++ b/apps/desktop/src/main/utils/spec-number-lock.ts @@ -34,7 +34,7 @@ export class SpecNumberLock { constructor(projectDir: string) { this.projectDir = projectDir; - this.lockDir = path.join(projectDir, '.auto-claude', '.locks'); + this.lockDir = path.join(projectDir, '.aperant', '.locks'); this.lockFile = path.join(this.lockDir, 'spec-numbering.lock'); } @@ -147,14 +147,14 @@ export class SpecNumberLock { let maxNumber = 0; // Determine specs directory base path - const specsBase = autoBuildPath || '.auto-claude'; + const specsBase = autoBuildPath || '.aperant'; // 1. Scan main project specs const mainSpecsDir = path.join(this.projectDir, specsBase, 'specs'); maxNumber = Math.max(maxNumber, this.scanSpecsDir(mainSpecsDir)); // 2. Scan all worktree specs - const worktreesDir = path.join(this.projectDir, '.auto-claude', 'worktrees', 'tasks'); + const worktreesDir = path.join(this.projectDir, '.aperant', 'worktrees', 'tasks'); if (existsSync(worktreesDir)) { try { const worktrees = readdirSync(worktreesDir, { withFileTypes: true }); diff --git a/apps/desktop/src/main/utils/spec-path-helpers.ts b/apps/desktop/src/main/utils/spec-path-helpers.ts index e84174d1..f1120150 100644 --- a/apps/desktop/src/main/utils/spec-path-helpers.ts +++ b/apps/desktop/src/main/utils/spec-path-helpers.ts @@ -29,7 +29,7 @@ export function isValidTaskId(taskId: string): boolean { * A task can exist in multiple locations (main + worktree), so return all paths * * @param projectPath - The root path of the project - * @param specsBaseDir - The relative path to specs directory (e.g., '.auto-claude/specs') + * @param specsBaseDir - The relative path to specs directory (e.g., '.aperant/specs') * @param taskId - The task/spec ID to find * @param logPrefix - Optional prefix for log messages (defaults to '[SpecPathHelpers]') * @returns Array of absolute paths where the spec exists diff --git a/apps/desktop/src/main/utils/worktree-cleanup.ts b/apps/desktop/src/main/utils/worktree-cleanup.ts index 6c5be7b1..7371ee60 100644 --- a/apps/desktop/src/main/utils/worktree-cleanup.ts +++ b/apps/desktop/src/main/utils/worktree-cleanup.ts @@ -85,8 +85,8 @@ function getWorktreeBranch(worktreePath: string, specId: string, timeout: number return explicitBranchName; } - // Fall back to the naming convention: auto-claude/{spec-id} - return `auto-claude/${specId}`; + // Fall back to the naming convention: aperant/{spec-id} + return `aperant/${specId}`; } /** @@ -163,7 +163,7 @@ async function deleteDirectoryWithRetry( * @example * ```typescript * const result = await cleanupWorktree({ - * worktreePath: 'C:/projects/my-app/.auto-claude/worktrees/tasks/001-feature', + * worktreePath: 'C:/projects/my-app/.aperant/worktrees/tasks/001-feature', * projectPath: 'C:/projects/my-app', * specId: '001-feature', * logPrefix: '[TASK_DELETE]' @@ -191,7 +191,7 @@ export async function cleanupWorktree(options: WorktreeCleanupOptions): Promise< // Security: Validate that worktreePath is within the expected worktree directories // This prevents path traversal attacks and accidental deletion of wrong directories - // Supports both task worktrees (.auto-claude/worktrees/tasks) and terminal worktrees (.auto-claude/worktrees/terminal) + // Supports both task worktrees (.aperant/worktrees/tasks) and terminal worktrees (.aperant/worktrees/terminal) const taskBase = getTaskWorktreeDir(projectPath); const terminalBase = getTerminalWorktreeDir(projectPath); const isValidPath = isPathWithinBase(worktreePath, taskBase) || isPathWithinBase(worktreePath, terminalBase); diff --git a/apps/desktop/src/main/worktree-paths.ts b/apps/desktop/src/main/worktree-paths.ts index 5d4d8746..31159ce3 100644 --- a/apps/desktop/src/main/worktree-paths.ts +++ b/apps/desktop/src/main/worktree-paths.ts @@ -9,11 +9,11 @@ import path from 'path'; import { existsSync } from 'fs'; // Path constants for worktree directories -export const TASK_WORKTREE_DIR = '.auto-claude/worktrees/tasks'; -export const TERMINAL_WORKTREE_DIR = '.auto-claude/worktrees/terminal'; +export const TASK_WORKTREE_DIR = '.aperant/worktrees/tasks'; +export const TERMINAL_WORKTREE_DIR = '.aperant/worktrees/terminal'; // Metadata directories (separate from git worktrees to avoid uncommitted files) -export const TERMINAL_WORKTREE_METADATA_DIR = '.auto-claude/terminal/metadata'; +export const TERMINAL_WORKTREE_METADATA_DIR = '.aperant/terminal/metadata'; // Legacy path for backwards compatibility export const LEGACY_WORKTREE_DIR = '.worktrees'; diff --git a/apps/desktop/src/preload/api/project-api.ts b/apps/desktop/src/preload/api/project-api.ts index 818c257d..340f8d70 100644 --- a/apps/desktop/src/preload/api/project-api.ts +++ b/apps/desktop/src/preload/api/project-api.ts @@ -30,6 +30,8 @@ export interface ProjectAPI { ) => Promise; initializeProject: (projectId: string) => Promise>; checkProjectVersion: (projectId: string) => Promise>; + needsMigration: (projectPath: string) => Promise; + migrateProject: (projectPath: string) => Promise<{ success: boolean; error?: string }>; // Tab State (persisted in main process for reliability) getTabState: () => Promise>; @@ -158,6 +160,12 @@ export const createProjectAPI = (): ProjectAPI => ({ checkProjectVersion: (projectId: string): Promise> => ipcRenderer.invoke(IPC_CHANNELS.PROJECT_CHECK_VERSION, projectId), + needsMigration: (projectPath: string): Promise => + ipcRenderer.invoke('project:needs-migration', projectPath), + + migrateProject: (projectPath: string): Promise<{ success: boolean; error?: string }> => + ipcRenderer.invoke('project:migrate', projectPath), + // Tab State (persisted in main process for reliability) getTabState: (): Promise> => ipcRenderer.invoke(IPC_CHANNELS.TAB_STATE_GET), diff --git a/apps/desktop/src/renderer/App.tsx b/apps/desktop/src/renderer/App.tsx index 021d9b14..84691b93 100644 --- a/apps/desktop/src/renderer/App.tsx +++ b/apps/desktop/src/renderer/App.tsx @@ -155,6 +155,12 @@ export function App() { const [skippedInitProjectId, setSkippedInitProjectId] = useState(null); const [showAddProjectModal, setShowAddProjectModal] = useState(false); + // Migration dialog state + const [showMigrateDialog, setShowMigrateDialog] = useState(false); + const [migrationProject, setMigrationProject] = useState(null); + const [isMigrating, setIsMigrating] = useState(false); + const [migrateError, setMigrateError] = useState(null); + // GitHub setup state (shown after Auto Claude init) const [showGitHubSetup, setShowGitHubSetup] = useState(false); const [gitHubSetupProject, setGitHubSetupProject] = useState(null); @@ -372,7 +378,7 @@ export function App() { setInitError(null); }, []); - // Check if selected project needs initialization (e.g., .auto-claude folder was deleted) + // Check if selected project needs initialization (e.g., .aperant folder was deleted) useEffect(() => { // Don't show dialog while initialization is in progress if (isInitializing) return; @@ -411,6 +417,18 @@ export function App() { const project = await addProject(path); if (project) { openProjectTab(project.id); + // Check migration before init + try { + const requiresMigration = await window.electronAPI.needsMigration(project.path); + if (requiresMigration) { + setMigrationProject(project); + setMigrateError(null); + setShowMigrateDialog(true); + return; + } + } catch { + // Non-critical - fall through to init check + } if (!project.autoBuildPath) { setPendingProject(project); setInitError(null); @@ -639,8 +657,22 @@ export function App() { setShowAddProjectModal(true); }; - const handleProjectAdded = (project: Project, needsInit: boolean) => { + const handleProjectAdded = async (project: Project, needsInit: boolean) => { openProjectTab(project.id); + + // Check for migration before showing init dialog + try { + const requiresMigration = await window.electronAPI.needsMigration(project.path); + if (requiresMigration) { + setMigrationProject(project); + setMigrateError(null); + setShowMigrateDialog(true); + return; + } + } catch (error) { + console.error('[App] Failed to check migration status:', error); + } + if (needsInit) { setPendingProject(project); setInitError(null); @@ -713,6 +745,34 @@ export function App() { } }; + const handleMigrate = async () => { + if (!migrationProject) return; + + setIsMigrating(true); + setMigrateError(null); + try { + const result = await window.electronAPI.migrateProject(migrationProject.path); + if (result.success) { + setShowMigrateDialog(false); + // Refresh projects so the updated autoBuildPath is reflected + await loadProjects(); + setMigrationProject(null); + } else { + setMigrateError(result.error || t('initialize.migrateError')); + } + } catch (error) { + setMigrateError(error instanceof Error ? error.message : t('initialize.migrateError')); + } finally { + setIsMigrating(false); + } + }; + + const handleSkipMigrate = () => { + setShowMigrateDialog(false); + setMigrationProject(null); + setMigrateError(null); + }; + const handleInitialize = async () => { if (!pendingProject) return; @@ -1014,6 +1074,51 @@ export function App() { onProjectAdded={handleProjectAdded} /> + {/* Migrate Project Data Dialog - shown when .auto-claude exists but .aperant does not */} + { + if (!open && !isMigrating) { + handleSkipMigrate(); + } + }}> + + + + + {t('initialize.migrateTitle')} + + + {t('initialize.migrateDescription')} + + + {migrateError && ( +
+
+ +
+

{t('initialize.migrateError')}

+

{migrateError}

+
+
+
+ )} + + + + +
+
+ {/* Initialize Auto Claude Dialog */} { console.warn('[InitDialog] onOpenChange called', { open, pendingProject: !!pendingProject, isInitializing, initSuccess }); diff --git a/apps/desktop/src/renderer/__tests__/project-store-tabs.test.ts b/apps/desktop/src/renderer/__tests__/project-store-tabs.test.ts index b066db35..ca46a5ca 100644 --- a/apps/desktop/src/renderer/__tests__/project-store-tabs.test.ts +++ b/apps/desktop/src/renderer/__tests__/project-store-tabs.test.ts @@ -29,7 +29,7 @@ function createTestProject(overrides: Partial = {}): Project { id: `project-${Date.now()}-${Math.random().toString(36).substring(7)}`, name: 'Test Project', path: '/path/to/test-project', - autoBuildPath: '.auto-claude', + autoBuildPath: '.aperant', settings: defaultSettings, createdAt: new Date(), updatedAt: new Date(), diff --git a/apps/desktop/src/renderer/components/AgentTools.tsx b/apps/desktop/src/renderer/components/AgentTools.tsx index 4142a4ca..42188f0e 100644 --- a/apps/desktop/src/renderer/components/AgentTools.tsx +++ b/apps/desktop/src/renderer/components/AgentTools.tsx @@ -152,7 +152,7 @@ const AGENT_CONFIGS: Record = { description: 'Creates implementation plan with subtasks', category: 'build', tools: ['Read', 'Glob', 'Grep', 'Write', 'Edit', 'Bash', 'WebFetch', 'WebSearch'], - mcp_servers: ['context7', 'memory', 'auto-claude'], + mcp_servers: ['context7', 'memory', 'aperant'], mcp_optional: ['linear'], settingsSource: { type: 'phase', phase: 'planning' }, }, @@ -161,7 +161,7 @@ const AGENT_CONFIGS: Record = { description: 'Implements individual subtasks', category: 'build', tools: ['Read', 'Glob', 'Grep', 'Write', 'Edit', 'Bash', 'WebFetch', 'WebSearch'], - mcp_servers: ['context7', 'memory', 'auto-claude'], + mcp_servers: ['context7', 'memory', 'aperant'], mcp_optional: ['linear'], settingsSource: { type: 'phase', phase: 'coding' }, }, @@ -172,7 +172,7 @@ const AGENT_CONFIGS: Record = { description: 'Validates acceptance criteria. Uses Electron or Puppeteer based on project type.', category: 'qa', tools: ['Read', 'Glob', 'Grep', 'Bash', 'WebFetch', 'WebSearch'], - mcp_servers: ['context7', 'memory', 'auto-claude'], + mcp_servers: ['context7', 'memory', 'aperant'], mcp_optional: ['linear', 'electron', 'puppeteer'], settingsSource: { type: 'phase', phase: 'qa' }, }, @@ -181,7 +181,7 @@ const AGENT_CONFIGS: Record = { description: 'Fixes QA-reported issues. Uses Electron or Puppeteer based on project type.', category: 'qa', tools: ['Read', 'Glob', 'Grep', 'Write', 'Edit', 'Bash', 'WebFetch', 'WebSearch'], - mcp_servers: ['context7', 'memory', 'auto-claude'], + mcp_servers: ['context7', 'memory', 'aperant'], mcp_optional: ['linear', 'electron', 'puppeteer'], settingsSource: { type: 'phase', phase: 'qa' }, }, @@ -286,17 +286,17 @@ const MCP_SERVERS: Record s.id); const allAvailableMcpIds = [...ALL_MCP_SERVERS, ...customServerIds]; const availableMcps = allAvailableMcpIds.filter( - mcp => !effectiveMcps.includes(mcp) && !removedMcps.includes(mcp) && mcp !== 'auto-claude' + mcp => !effectiveMcps.includes(mcp) && !removedMcps.includes(mcp) && mcp !== 'aperant' ); return ( @@ -495,7 +495,7 @@ function AgentCard({ id, config, modelLabel, thinkingLabel, overrides, mcpServer const serverInfo = allMcpServers[server]; const ServerIcon = serverInfo?.icon || Server; const isAdded = isCustomAdd(server); - const canRemove = server !== 'auto-claude'; + const canRemove = server !== 'aperant'; return (
diff --git a/apps/desktop/src/renderer/components/__tests__/ProjectTabBar.test.tsx b/apps/desktop/src/renderer/components/__tests__/ProjectTabBar.test.tsx index b9b21858..da2654c1 100644 --- a/apps/desktop/src/renderer/components/__tests__/ProjectTabBar.test.tsx +++ b/apps/desktop/src/renderer/components/__tests__/ProjectTabBar.test.tsx @@ -14,7 +14,7 @@ function createTestProject(overrides: Partial = {}): Project { id: `project-${Date.now()}-${Math.random().toString(36).substring(7)}`, name: 'Test Project', path: '/path/to/test-project', - autoBuildPath: '/path/to/test-project/.auto-claude', + autoBuildPath: '/path/to/test-project/.aperant', settings: { model: 'claude-3-haiku-20240307', memoryBackend: 'file', diff --git a/apps/desktop/src/renderer/components/__tests__/SortableProjectTab.test.tsx b/apps/desktop/src/renderer/components/__tests__/SortableProjectTab.test.tsx index 05c46319..a8cea5cc 100644 --- a/apps/desktop/src/renderer/components/__tests__/SortableProjectTab.test.tsx +++ b/apps/desktop/src/renderer/components/__tests__/SortableProjectTab.test.tsx @@ -14,7 +14,7 @@ function createTestProject(overrides: Partial = {}): Project { id: `project-${Date.now()}-${Math.random().toString(36).substring(7)}`, name: 'Test Project', path: '/path/to/test-project', - autoBuildPath: '/path/to/test-project/.auto-claude', + autoBuildPath: '/path/to/test-project/.aperant', settings: { model: 'claude-3-haiku-20240307', memoryBackend: 'file', diff --git a/apps/desktop/src/renderer/components/context/MemoriesTab.tsx b/apps/desktop/src/renderer/components/context/MemoriesTab.tsx index 7f35f3f0..38196e16 100644 --- a/apps/desktop/src/renderer/components/context/MemoriesTab.tsx +++ b/apps/desktop/src/renderer/components/context/MemoriesTab.tsx @@ -166,7 +166,7 @@ export function MemoriesTab({ <>
- + {memoryStatus.embeddingProvider && ( )} diff --git a/apps/desktop/src/renderer/components/github-prs/components/PRDetail.tsx b/apps/desktop/src/renderer/components/github-prs/components/PRDetail.tsx index b0e1e432..0e921b35 100644 --- a/apps/desktop/src/renderer/components/github-prs/components/PRDetail.tsx +++ b/apps/desktop/src/renderer/components/github-prs/components/PRDetail.tsx @@ -126,7 +126,7 @@ export function PRDetail({ // a hybrid push/pull architecture: // // Backend (PRLogCollector in pr-handlers.ts): - // - Writes logs to disk every 3 entries: .auto-claude/github/pr/logs_${prNumber}.json + // - Writes logs to disk every 3 entries: .aperant/github/pr/logs_${prNumber}.json // - Emits GITHUB_PR_LOGS_UPDATED IPC events after each save // - Tracks phase status: pending → active → completed/failed // diff --git a/apps/desktop/src/renderer/components/onboarding/GraphitiStep.tsx b/apps/desktop/src/renderer/components/onboarding/GraphitiStep.tsx index e4be1ff1..acc5998d 100644 --- a/apps/desktop/src/renderer/components/onboarding/GraphitiStep.tsx +++ b/apps/desktop/src/renderer/components/onboarding/GraphitiStep.tsx @@ -907,7 +907,7 @@ export function GraphitiStep({ onNext, onBack, onSkip }: GraphitiStepProps) { disabled={isSaving || isValidating} />

- Stored in ~/.auto-claude/graphs/ + Stored in ~/.aperant/graphs/

diff --git a/apps/desktop/src/renderer/components/project-settings/MemoryBackendSection.tsx b/apps/desktop/src/renderer/components/project-settings/MemoryBackendSection.tsx index 8504e6bf..dba027d3 100644 --- a/apps/desktop/src/renderer/components/project-settings/MemoryBackendSection.tsx +++ b/apps/desktop/src/renderer/components/project-settings/MemoryBackendSection.tsx @@ -127,7 +127,7 @@ export function MemoryBackendSection({

- Name for the memory database (stored in ~/.auto-claude/memories/) + Name for the memory database (stored in ~/.aperant/memories/)

- Custom storage location. Default: ~/.auto-claude/memories/ + Custom storage location. Default: ~/.aperant/memories/

onUpdateConfig({ memoryDbPath: e.target.value || undefined })} /> diff --git a/apps/desktop/src/renderer/components/project-settings/SecuritySettings.tsx b/apps/desktop/src/renderer/components/project-settings/SecuritySettings.tsx index bd66a4fd..a1c4da58 100644 --- a/apps/desktop/src/renderer/components/project-settings/SecuritySettings.tsx +++ b/apps/desktop/src/renderer/components/project-settings/SecuritySettings.tsx @@ -423,7 +423,7 @@ export function SecuritySettings({

- Stored in ~/.auto-claude/memories/ + Stored in ~/.aperant/memories/

- Custom storage location. Default: ~/.auto-claude/memories/ + Custom storage location. Default: ~/.aperant/memories/

updateEnvConfig({ memoryDbPath: e.target.value || undefined })} /> diff --git a/apps/desktop/src/renderer/components/task-detail/task-review/CreatePRDialog.test.tsx b/apps/desktop/src/renderer/components/task-detail/task-review/CreatePRDialog.test.tsx index 17add18f..57064940 100644 --- a/apps/desktop/src/renderer/components/task-detail/task-review/CreatePRDialog.test.tsx +++ b/apps/desktop/src/renderer/components/task-detail/task-review/CreatePRDialog.test.tsx @@ -45,7 +45,7 @@ describe('CreatePRDialog', () => { const mockWorktreeStatus: WorktreeStatus = { exists: true, worktreePath: '/path/to/worktree', - branch: 'auto-claude/implement-user-authentication', + branch: 'aperant/implement-user-authentication', baseBranch: 'develop', commitCount: 5, filesChanged: 10, @@ -121,7 +121,7 @@ describe('CreatePRDialog', () => { ); await waitFor(() => { - expect(screen.getByText('auto-claude/implement-user-authentication')).toBeInTheDocument(); + expect(screen.getByText('aperant/implement-user-authentication')).toBeInTheDocument(); }); }); diff --git a/apps/desktop/src/renderer/lib/mocks/infrastructure-mock.ts b/apps/desktop/src/renderer/lib/mocks/infrastructure-mock.ts index f70404a2..4835b116 100644 --- a/apps/desktop/src/renderer/lib/mocks/infrastructure-mock.ts +++ b/apps/desktop/src/renderer/lib/mocks/infrastructure-mock.ts @@ -10,7 +10,7 @@ export const infrastructureMock = { data: { memory: { kuzuInstalled: true, - databasePath: '~/.auto-claude/graphs', + databasePath: '~/.aperant/graphs', databaseExists: true, databases: ['auto_claude_memory'] }, diff --git a/apps/desktop/src/renderer/lib/mocks/project-mock.ts b/apps/desktop/src/renderer/lib/mocks/project-mock.ts index 153600e0..3703524d 100644 --- a/apps/desktop/src/renderer/lib/mocks/project-mock.ts +++ b/apps/desktop/src/renderer/lib/mocks/project-mock.ts @@ -125,5 +125,9 @@ export const projectMock = { initializeGit: async () => ({ success: true, data: { success: true } - }) + }), + + needsMigration: async () => false, + + migrateProject: async () => ({ success: true }) }; diff --git a/apps/desktop/src/renderer/stores/project-store.ts b/apps/desktop/src/renderer/stores/project-store.ts index 5442fdd8..26399446 100644 --- a/apps/desktop/src/renderer/stores/project-store.ts +++ b/apps/desktop/src/renderer/stores/project-store.ts @@ -439,8 +439,8 @@ export async function initializeProject( console.log('[ProjectStore] IPC succeeded, result.data:', result.data); // Update the project's autoBuildPath in local state if (result.data.success) { - console.log('[ProjectStore] Updating project autoBuildPath to .auto-claude'); - store.updateProject(projectId, { autoBuildPath: '.auto-claude' }); + console.log('[ProjectStore] Updating project autoBuildPath to .aperant'); + store.updateProject(projectId, { autoBuildPath: '.aperant' }); } else { console.log('[ProjectStore] result.data.success is false, not updating project'); } diff --git a/apps/desktop/src/shared/constants/config.ts b/apps/desktop/src/shared/constants/config.ts index a3f66a41..2d4b5cb8 100644 --- a/apps/desktop/src/shared/constants/config.ts +++ b/apps/desktop/src/shared/constants/config.ts @@ -96,11 +96,11 @@ export const DEFAULT_PROJECT_SETTINGS = { // ============================================ // File paths relative to project -// IMPORTANT: All paths use .auto-claude/ (the installed instance), NOT auto-claude/ (source code) +// IMPORTANT: All paths use .aperant/ (the installed instance), NOT aperant/ (source code) export const AUTO_BUILD_PATHS = { - SPECS_DIR: '.auto-claude/specs', - ROADMAP_DIR: '.auto-claude/roadmap', - IDEATION_DIR: '.auto-claude/ideation', + SPECS_DIR: '.aperant/specs', + ROADMAP_DIR: '.aperant/roadmap', + IDEATION_DIR: '.aperant/ideation', IMPLEMENTATION_PLAN: 'implementation_plan.json', SPEC_FILE: 'spec.md', QA_REPORT: 'qa_report.md', @@ -114,15 +114,15 @@ export const AUTO_BUILD_PATHS = { MANUAL_COMPETITORS: 'manual_competitors.json', IDEATION_FILE: 'ideation.json', IDEATION_CONTEXT: 'ideation_context.json', - PROJECT_INDEX: '.auto-claude/project_index.json', + PROJECT_INDEX: '.aperant/project_index.json', MEMORY_STATE: '.memory_state.json' } as const; /** * Get the specs directory path. - * All specs go to .auto-claude/specs/ (the project's data directory). + * All specs go to .aperant/specs/ (the project's data directory). */ export function getSpecsDir(autoBuildPath: string | undefined): string { - const basePath = autoBuildPath || '.auto-claude'; + const basePath = autoBuildPath || '.aperant'; return `${basePath}/specs`; } diff --git a/apps/desktop/src/shared/i18n/locales/en/dialogs.json b/apps/desktop/src/shared/i18n/locales/en/dialogs.json index 35feafb8..7e9b42f0 100644 --- a/apps/desktop/src/shared/i18n/locales/en/dialogs.json +++ b/apps/desktop/src/shared/i18n/locales/en/dialogs.json @@ -3,13 +3,18 @@ "title": "Initialize Aperant", "description": "This project doesn't have Aperant initialized. Would you like to set it up now?", "willDo": "This will:", - "createFolder": "Create a .auto-claude folder in your project", + "createFolder": "Create a .aperant folder in your project", "copyFramework": "Copy the Aperant framework files", "setupSpecs": "Set up the specs directory for your tasks", "sourcePathNotConfigured": "Source path not configured", "sourcePathNotConfiguredDescription": "Please set the Aperant source path in App Settings before initializing.", "initFailed": "Initialization Failed", - "initFailedDescription": "Failed to initialize Aperant. Please try again." + "initFailedDescription": "Failed to initialize Aperant. Please try again.", + "migrateTitle": "Migrate Project Data", + "migrateDescription": "This project uses the old .auto-claude folder. Aperant now uses .aperant for project data.", + "migrateAction": "Migrate", + "migrateSuccess": "Project data migrated successfully", + "migrateError": "Migration failed" }, "gitSetup": { "title": "Git Repository Required", diff --git a/apps/desktop/src/shared/i18n/locales/en/settings.json b/apps/desktop/src/shared/i18n/locales/en/settings.json index 68cfa87c..448389e6 100644 --- a/apps/desktop/src/shared/i18n/locales/en/settings.json +++ b/apps/desktop/src/shared/i18n/locales/en/settings.json @@ -245,8 +245,8 @@ "sourceFallback": "Fallback", "notDetected": "Not detected", "autoClaudePath": "Aperant Path", - "autoClaudePathDescription": "Relative path to auto-claude directory in projects", - "autoClaudePathPlaceholder": "auto-claude (default)", + "autoClaudePathDescription": "Relative path to aperant directory in projects", + "autoClaudePathPlaceholder": ".aperant (default)", "autoNameTerminals": "Automatically name terminals", "autoNameTerminalsDescription": "Use AI to generate descriptive names for terminal tabs based on their activity" }, diff --git a/apps/desktop/src/shared/i18n/locales/fr/dialogs.json b/apps/desktop/src/shared/i18n/locales/fr/dialogs.json index 93cd2634..913a20aa 100644 --- a/apps/desktop/src/shared/i18n/locales/fr/dialogs.json +++ b/apps/desktop/src/shared/i18n/locales/fr/dialogs.json @@ -3,13 +3,18 @@ "title": "Initialiser Aperant", "description": "Ce projet n'a pas Aperant initialisé. Voulez-vous le configurer maintenant ?", "willDo": "Ceci va :", - "createFolder": "Créer un dossier .auto-claude dans votre projet", + "createFolder": "Créer un dossier .aperant dans votre projet", "copyFramework": "Copier les fichiers du framework Aperant", "setupSpecs": "Configurer le répertoire des spécifications pour vos tâches", "sourcePathNotConfigured": "Chemin source non configuré", "sourcePathNotConfiguredDescription": "Veuillez définir le chemin source Aperant dans les paramètres de l'application avant d'initialiser.", "initFailed": "Échec de l'initialisation", - "initFailedDescription": "Échec de l'initialisation de Aperant. Veuillez réessayer." + "initFailedDescription": "Échec de l'initialisation de Aperant. Veuillez réessayer.", + "migrateTitle": "Migrer les données du projet", + "migrateDescription": "Ce projet utilise l'ancien dossier .auto-claude. Aperant utilise maintenant .aperant pour les données du projet.", + "migrateAction": "Migrer", + "migrateSuccess": "Données du projet migrées avec succès", + "migrateError": "La migration a échoué" }, "gitSetup": { "title": "Dépôt Git requis", diff --git a/apps/desktop/src/shared/i18n/locales/fr/settings.json b/apps/desktop/src/shared/i18n/locales/fr/settings.json index 5970f01a..5d543f7e 100644 --- a/apps/desktop/src/shared/i18n/locales/fr/settings.json +++ b/apps/desktop/src/shared/i18n/locales/fr/settings.json @@ -245,8 +245,8 @@ "sourceFallback": "Valeur par défaut", "notDetected": "Non détecté", "autoClaudePath": "Chemin Aperant", - "autoClaudePathDescription": "Chemin relatif vers le répertoire auto-claude dans les projets", - "autoClaudePathPlaceholder": "auto-claude (par défaut)", + "autoClaudePathDescription": "Chemin relatif vers le répertoire aperant dans les projets", + "autoClaudePathPlaceholder": ".aperant (par défaut)", "autoNameTerminals": "Nommer automatiquement les terminaux", "autoNameTerminalsDescription": "Utiliser l'IA pour générer des noms descriptifs pour les onglets de terminal en fonction de leur activité" }, diff --git a/apps/desktop/src/shared/types/ipc.ts b/apps/desktop/src/shared/types/ipc.ts index eb99c715..a58da4dc 100644 --- a/apps/desktop/src/shared/types/ipc.ts +++ b/apps/desktop/src/shared/types/ipc.ts @@ -185,6 +185,8 @@ export interface ElectronAPI { updateProjectSettings: (projectId: string, settings: Partial) => Promise; initializeProject: (projectId: string) => Promise>; checkProjectVersion: (projectId: string) => Promise>; + needsMigration: (projectPath: string) => Promise; + migrateProject: (projectPath: string) => Promise<{ success: boolean; error?: string }>; // Tab State (persisted in main process for reliability) getTabState: () => Promise>; diff --git a/apps/desktop/src/shared/types/project.ts b/apps/desktop/src/shared/types/project.ts index f8afb633..2d289ade 100644 --- a/apps/desktop/src/shared/types/project.ts +++ b/apps/desktop/src/shared/types/project.ts @@ -221,7 +221,7 @@ export interface MemoryProviderConfig { // LadybugDB settings (embedded database - no Docker required) database?: string; // Database name (default: auto_claude_memory) - dbPath?: string; // Database storage path (default: ~/.auto-claude/memories) + dbPath?: string; // Database storage path (default: ~/.aperant/memories) } export interface MemoryProviderInfo { @@ -368,7 +368,7 @@ export interface ProjectEnvConfig { /** * Per-agent MCP override configuration. - * Stored in .auto-claude/.env as AGENT_MCP__ADD and AGENT_MCP__REMOVE + * Stored in .aperant/.env as AGENT_MCP__ADD and AGENT_MCP__REMOVE */ export interface AgentMcpOverride { /** MCP servers to add beyond the agent's defaults */ @@ -452,7 +452,7 @@ export interface McpTestConnectionResult { // Auto Claude Initialization Types export interface AutoBuildVersionInfo { isInitialized: boolean; - updateAvailable: boolean; // Always false - .auto-claude only contains data, no code to update + updateAvailable: boolean; // Always false - .aperant only contains data, no code to update } export interface InitializationResult { diff --git a/apps/desktop/src/shared/types/terminal.ts b/apps/desktop/src/shared/types/terminal.ts index 1b97feaf..0ddcbb92 100644 --- a/apps/desktop/src/shared/types/terminal.ts +++ b/apps/desktop/src/shared/types/terminal.ts @@ -205,7 +205,7 @@ export interface RetryWithProfileRequest { export interface TerminalWorktreeConfig { /** Unique worktree name (used as directory name) */ name: string; - /** Path to the worktree directory (.auto-claude/worktrees/terminal/{name}/) */ + /** Path to the worktree directory (.aperant/worktrees/terminal/{name}/) */ worktreePath: string; /** Git branch name (terminal/{name}) - empty if no branch created */ branchName: string;