From c502fbc57ac2fe0b009a09023d095f3782833f4d Mon Sep 17 00:00:00 2001
From: Cody Seibert
Date: Wed, 10 Dec 2025 14:29:05 -0500
Subject: [PATCH] feat(backup): add backup.json for feature tracking and status
updates
- Introduced a new `backup.json` file to track feature statuses, descriptions, and summaries for better project management.
- Updated `.automaker/feature_list.json` to reflect verified statuses for several features, ensuring accurate representation of progress.
- Enhanced `memory.md` with details on drag-and-drop functionality for features in `waiting_approval` status.
- Improved auto mode service to allow running tasks to complete when auto mode is stopped, enhancing user experience.
---
.automaker/feature_list.json | 223 +++++++-
.automaker/memory.md | 40 ++
app/electron/auto-mode-service.js | 23 +-
app/electron/preload.js | 4 +-
app/electron/services/context-manager.js | 195 +++++++
app/electron/services/feature-executor.js | 59 +-
app/src/app/globals.css | 525 ++++++++++++++++++
app/src/components/layout/sidebar.tsx | 178 ++++--
app/src/components/session-manager.tsx | 10 +-
.../components/ui/category-autocomplete.tsx | 106 ++--
.../ui/description-image-dropzone.tsx | 3 +
app/src/components/ui/hotkey-button.tsx | 296 ++++++++++
app/src/components/ui/image-drop-zone.tsx | 30 +-
app/src/components/ui/input.tsx | 4 +-
app/src/components/ui/xml-syntax-editor.tsx | 290 ++++++++++
app/src/components/views/agent-view.tsx | 18 +-
app/src/components/views/board-view.tsx | 250 +++++++--
app/src/components/views/context-view.tsx | 19 +-
.../views/feature-suggestions-dialog.tsx | 7 +-
app/src/components/views/kanban-card.tsx | 26 +-
app/src/components/views/profiles-view.tsx | 26 +-
app/src/components/views/settings-view.tsx | 156 ++++--
app/src/components/views/spec-view.tsx | 20 +-
app/src/components/views/welcome-view.tsx | 7 +-
app/src/hooks/use-auto-mode.ts | 11 +-
backup.json | 269 +++++++++
26 files changed, 2497 insertions(+), 298 deletions(-)
create mode 100644 app/src/components/ui/hotkey-button.tsx
create mode 100644 app/src/components/ui/xml-syntax-editor.tsx
create mode 100644 backup.json
diff --git a/.automaker/feature_list.json b/.automaker/feature_list.json
index a797057a..772a0f93 100644
--- a/.automaker/feature_list.json
+++ b/.automaker/feature_list.json
@@ -4,7 +4,7 @@
"category": "Kanban",
"description": "In the output logs of the proc agent output in the file diffs Can you add a scroll bar so it actually scroll to see all these new styles right now it seems like I can't scroll",
"steps": [],
- "status": "waiting_approval",
+ "status": "verified",
"startedAt": "2025-12-10T17:42:09.158Z",
"imagePaths": [],
"skipTests": true,
@@ -68,7 +68,7 @@
"category": "Uncategorized",
"description": "Can you please add some spacing and fix the styling of the hotkey with the command enter and make it so they're both vertically aligned for those icons?",
"steps": [],
- "status": "waiting_approval",
+ "status": "verified",
"startedAt": "2025-12-10T17:44:08.667Z",
"imagePaths": [
{
@@ -87,7 +87,7 @@
"category": "Uncategorized",
"description": "Fix the styling on all the buttons when I hover over them with my mouse they never change to a click mouse cursor. In order they seem to show any type of like hover state changes, if they do, at least for the certain game I'm using, it's not very obvious that you're hovering over the button.",
"steps": [],
- "status": "waiting_approval",
+ "status": "verified",
"startedAt": "2025-12-10T17:45:59.666Z",
"imagePaths": [],
"skipTests": true,
@@ -100,7 +100,7 @@
"category": "Kanban",
"description": "The tabs in the add new feature modal for the prompt model and testing tabs. They don't seem to look like tabs when I'm on a certain theme. Can you verify that those are hooked into the theme? And make sure that the active one is colored differently than the unactive ones. Keep the primary colors when doing this.",
"steps": [],
- "status": "waiting_approval",
+ "status": "verified",
"startedAt": "2025-12-10T17:46:00.019Z",
"imagePaths": [],
"skipTests": true,
@@ -113,7 +113,7 @@
"category": "Uncategorized",
"description": "There's a strange issue when I when when these agents are like doing things it seems like it completely refreshes the whole Kanban board and there's like a black flash. Can you verify that the data loading does not cause the entire component to refresh? Maybe there's an issue with the react effect or how the component is rendered maybe we need some used memos or something but it shouldn't refresh the whole page it should just like update the individual cards when they change.",
"steps": [],
- "status": "waiting_approval",
+ "status": "verified",
"startedAt": "2025-12-10T17:47:20.170Z",
"imagePaths": [],
"skipTests": true,
@@ -126,11 +126,11 @@
"category": "Uncategorized",
"description": "Add in the ability so that every project can have its own selected theme. This will allow me to have different projects have different themes so I can easily differentiate when I have one project selected or not.",
"steps": [],
- "status": "waiting_approval",
- "startedAt": "2025-12-10T17:54:11.363Z",
+ "status": "verified",
+ "startedAt": "2025-12-10T18:00:33.814Z",
"imagePaths": [],
"skipTests": true,
- "summary": "Added per-project theme support. Modified: electron.ts (added theme property to Project interface), app-store.ts (added setProjectTheme and getEffectiveTheme actions), page.tsx (uses effectiveTheme for theme switching), sidebar.tsx (added project theme selector dropdown with all 13 themes + \"Use Global\" option). Users can now set unique themes for each project via the project options menu in the sidebar.",
+ "summary": "Fixed per-project theme support. Modified: settings-view.tsx (now saves theme to project when project is selected, shows label indicating scope), page.tsx (computes effectiveTheme from currentProject?.theme || theme), app-store.ts (added setProjectTheme action, theme property on Project interface). When a project is selected, changing theme in Settings saves to that project only.",
"model": "opus",
"thinkingLevel": "none"
},
@@ -139,7 +139,8 @@
"category": "Agent Runner",
"description": "On the Agent Runner, I took a screenshot and dropped it into the text area and after a certain amount of time, it's like the image preview just completely went away. Can you debug and fix this on the Agent Runner?",
"steps": [],
- "status": "backlog",
+ "status": "verified",
+ "startedAt": "2025-12-10T18:11:17.561Z",
"imagePaths": [],
"skipTests": true,
"model": "opus",
@@ -150,9 +151,211 @@
"category": "Kanban",
"description": "It seems like the category typehead is no longer working. Can you double check that code didn't break? It should have kept track of categories inside of the categories.json file inside the .automaker folder when adding new features modal",
"steps": [],
- "status": "backlog",
+ "status": "verified",
+ "startedAt": "2025-12-10T18:17:22.274Z",
"imagePaths": [],
"skipTests": true,
+ "summary": "Fixed category typeahead dropdown being clipped by overflow containers. Modified: category-autocomplete.tsx. Changed dropdown to use React Portal (createPortal) to render to document.body with fixed positioning and z-index 9999. Added scroll/resize position tracking to keep dropdown aligned with input.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389420151-jzdsjzn9u",
+ "category": "Kanban",
+ "description": "Add in the ability to just click and drag a card from the waiting approval directly into the verify column as I can usually just commit it manually if I want to.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T18:05:08.252Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed drag-and-drop from waiting_approval to verified column. The issue was condition ordering in handleDragEnd - the skipTests check was intercepting waiting_approval features before they could be handled. Moved waiting_approval status check before skipTests check in board-view.tsx:731-752. Also updated agent memory with this lesson.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389468077-9x3vt1yjq",
+ "category": "Uncategorized",
+ "description": "The commit functionality on the waiting approval cards doesn't seem to work. It just committed everything in my working copy for git. I think I should be a little bit more intelligent and figure out what files it changed for that AI session and then only try to git add those individual files and commit those. Right now it just basically did a git add all and committed those. Re-factor the prompting or figure out a way to make it so it's more specific on what it's going to commit with the future change.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T18:17:22.580Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed commit functionality to only commit files changed during the AI session, not all working directory changes. Added git state tracking in context-manager.js (saveInitialGitState, getFilesChangedDuringSession methods) and updated commit prompt in feature-executor.js to use specific file lists instead of 'git add .'",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389502705-6deep7mvi",
+ "category": "Uncategorized",
+ "description": "I'm noticing that a lot of buttons in the UI, especially the ones that are submitting, are either missing the submit hotkey or they're not styled properly. Look at the add feature submit button that's on the add feature modal and abstract away a submit button so that on every single page that needs to submit something I can reuse this type of hotkey functionality. In fact, every single button should be abstracted enough where I can provide a hotkey and it will automatically listen if I press that hotkey when it's in view.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T19:03:41.338Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed duplicate hotkey listener issue. When HotkeyButton was used with simple keys (N, F, G) that were already handled by useKeyboardShortcuts, it created duplicate listeners. Added hotkeyActive={false} to HotkeyButton instances in board-view.tsx (Add Feature, Start Next), context-view.tsx (Add File), profiles-view.tsx (New Profile), and session-manager.tsx (New) where useKeyboardShortcuts already handles the hotkey. Also updated memory.md with this lesson learned.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389772166-an3yk3kpo",
+ "category": "Uncategorized",
+ "description": "Can you add some more padding to the bottom of the settings panel? Notice that I can't scroll down all the way. And that doesn't highlight the left sub navigation to highlight it pink when I'm on that section. I should be able to scroll a bit further and just have like blank space at the bottom. So I can eventually get to that actual section.",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [
+ {
+ "id": "img-1765389750685-jhq6rcidc",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765389750683-mqb0j7a3z_Screenshot_2025-12-10_at_1.02.26_PM.png",
+ "filename": "Screenshot 2025-12-10 at 1.02.26 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "summary": "Added bottom padding (pb-96) to settings panel content area to allow scrolling past last section. Improved scroll detection to highlight the last navigation item when scrolled to bottom. Modified: settings-view.tsx",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389829239-bbk596u6z",
+ "category": "Uncategorized",
+ "description": "Add some type of XML highlighting to the spec editor view. Right now it's just all grayscale and it's kind of ugly to look at. And try to make the syntax highlighting match the current selected theme.",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Added XML syntax highlighting to spec editor view. Created: xml-syntax-editor.tsx component with custom XML tokenizer and theme-aware syntax highlighting. Modified: spec-view.tsx to use new editor, globals.css with 500+ lines of theme-specific syntax highlighting colors for all 12 themes (light, dark, retro, dracula, nord, monokai, tokyonight, solarized, gruvbox, catppuccin, onedark, synthwave). Features: highlights tag brackets, tag names, attribute names, attribute values, comments, CDATA, DOCTYPE. Tab key indentation supported.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389859334-si9ivtehw",
+ "category": "Uncategorized",
+ "description": "Add a search bar to the top of the Kanban column that allows me to search the filter down just to show the cards I'm interested in by keyword.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T18:09:26.193Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Added forward slash (/) keyboard shortcut to focus search input. Modified: board-view.tsx - added searchInputRef, registered '/' shortcut in boardShortcuts, updated placeholder to show hint '(Press / to focus)'",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390022638-nalulsdxv",
+ "category": "Uncategorized",
+ "description": "In the project select can you actually remove the whole like 1 2 3 4 5 hotkeys instead? Just make it be a type ahead so when I open the panel I just should be able to type in the first letter or two of the project that I want and press enter and that should Just select it for me",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Replaced hotkey-based project selection (1-9) with type-ahead search. Modified: sidebar.tsx. Added search input with filtering, arrow key navigation (↑↓), Enter to select, and visual highlighting. Auto-focuses search when dropdown opens.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390055621-ewc4w7k5h",
+ "category": "Uncategorized",
+ "description": "In the add new feature prompt, instead of disabling the add feature button until we type into the description, keep it enabled. But if you click it, make sure you just show the client side validation and turn the description box in any other required field as red so that the user knows they have to fill it in.",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Added client-side validation for the Add Feature dialog. The Add Feature button is now always enabled. When clicked without a description, it shows a red border around the description field using aria-invalid styling. Modified: board-view.tsx (added descriptionError state, validation in handleAddFeature, error prop passing), description-image-dropzone.tsx (added error prop that sets aria-invalid on textarea).",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390131625-ymqxr5gln",
+ "category": "Uncategorized",
+ "description": "Can you please in the top right of the Kanban board use the show three icons for the Kanban card display formatting. You can look at the settings page to see that there's three different settings that we use for displaying the Kanban card information. But I also just want this to be really quickly accessible at the top right of the Kanban that they can switch between those three toggles. Keep them simple only just icons you don't need to put words in them. Make sure they do have harbor states though, or tooltips I mean.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T18:58:21.431Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Moved Kanban card detail toggle icons to search bar row. Modified: board-view.tsx. Three icons (Minimize2, Square, Maximize2) now appear on the right side of the search bar with tooltips and hover states.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390359456-n0vvdurjb",
+ "category": "Kanban",
+ "description": "When the item is in the backlog, do not show the logs. There's no reason for a user to look at the logs if it's in the backlog. So remove the logs button from the card, the Kanban card, if it's in the backlog.",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Removed logs button from Kanban cards when feature is in backlog. Modified: kanban-card.tsx - removed the dedicated logs button section for backlog items (lines 743-761) and added condition to hide logs option in dropdown menu for backlog items.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390428237-4ekiscpsf",
+ "category": "Uncategorized",
+ "description": "On the Kanban search bar, instead of press slash to focus, just use the normal shortcut display button that we've been using everywhere else in the application. Can you keep it consistent, please?",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [
+ {
+ "id": "img-1765390414226-66vm6cly4",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765390414225-7o9wizw90_Screenshot_2025-12-10_at_1.13.32_PM.png",
+ "filename": "Screenshot 2025-12-10 at 1.13.32 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390699789-uaxtse6hn",
+ "category": "Uncategorized",
+ "description": "Please fix the styling of this on the Agent Runner, make it match the theme of the project.",
+ "steps": [],
+ "status": "verified",
+ "imagePaths": [
+ {
+ "id": "img-1765390692809-0hahbe30j",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765390692808-u8dgwxx9n_Screenshot_2025-12-10_at_1.18.07_PM.png",
+ "filename": "Screenshot 2025-12-10 at 1.18.07 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765393057026-cjgr70d97",
+ "category": "Kanban",
+ "description": "there is a major bug: stopping auto mode should not cancel all running tasks, it should just turn off the auto toggle.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T18:57:56.137Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed auto mode stop to only turn off the toggle, not cancel running tasks. Modified: auto-mode-service.js (removed abort/clear logic from stop()), use-auto-mode.ts (removed clearRunningTasks from stop callback). Running features now complete naturally.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765393405243-xe047s4h5",
+ "category": "Uncategorized",
+ "description": "fix the style of the input on the kanban route to add a border around the entire input",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T19:08:38.024Z",
+ "imagePaths": [
+ {
+ "id": "img-1765393386453-nd1qucdne",
+ "path": "/Users/webdevcody/Workspace/automaker/.automaker/images/1765393386452-bz4q5pbkw_Screenshot_2025-12-10_at_2.03.04_PM.png",
+ "filename": "Screenshot 2025-12-10 at 2.03.04 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
"model": "opus",
"thinkingLevel": "none"
}
diff --git a/.automaker/memory.md b/.automaker/memory.md
index e86144e4..f9a80351 100644
--- a/.automaker/memory.md
+++ b/.automaker/memory.md
@@ -84,6 +84,22 @@ Note: `currentView` is NOT persisted - it's managed through actions.
4. `auto_mode_feature_complete` event fires → feature removed from `runningAutoTasks`
5. If `passes: true` → status becomes "verified", if `passes: false` → stays "in_progress"
+### Issue: waiting_approval features not draggable when skipTests=true
+**Problem:** Features in `waiting_approval` status couldn't be dragged to `verified` column, even though the code appeared to handle it.
+**Fix:** The order of condition checks in `handleDragEnd` matters. The `skipTests` check was catching `waiting_approval` features before the `waiting_approval` status check could handle them. Move the `waiting_approval` status check **before** the `skipTests` check in `board-view.tsx`:
+
+```typescript
+// Correct order in handleDragEnd:
+if (draggedFeature.status === "backlog") {
+ // ...
+} else if (draggedFeature.status === "waiting_approval") {
+ // Handle waiting_approval BEFORE skipTests check
+ // because waiting_approval features often have skipTests=true
+} else if (draggedFeature.skipTests) {
+ // Handle other skipTests features
+}
+```
+
## Best Practices Discovered
### Testing utilities are critical
@@ -107,3 +123,27 @@ The mock auto mode in `electron.ts` has predictable timing:
- Total duration: ~2.4 seconds (300+500+300+300+500+500ms)
- Plus 1.5s delay before auto-closing modals
- Total: ~4 seconds from start to completion
+
+### Issue: HotkeyButton conflicting with useKeyboardShortcuts
+**Problem:** Adding `HotkeyButton` with a simple key (like "N") to buttons that already had keyboard shortcuts registered via `useKeyboardShortcuts` caused the hotkey to stop working. Both registered duplicate listeners, and the HotkeyButton's `stopPropagation()` call could interfere.
+**Fix:** When a simple single-key hotkey is already handled by `useKeyboardShortcuts`, set `hotkeyActive={false}` on the `HotkeyButton` so it only displays the indicator badge without registering a duplicate listener:
+
+```tsx
+// In views that already use useKeyboardShortcuts for the "N" key:
+ setShowAddDialog(true)}
+ hotkey={ACTION_SHORTCUTS.addFeature}
+ hotkeyActive={false} // <-- Important! Prevents duplicate listener
+>
+ Add Feature
+
+
+// HotkeyButton should only actively listen when it's the sole handler (e.g., Cmd+Enter in dialogs)
+
+ Submit
+
+```
diff --git a/app/electron/auto-mode-service.js b/app/electron/auto-mode-service.js
index 054c3b03..2407dedb 100644
--- a/app/electron/auto-mode-service.js
+++ b/app/electron/auto-mode-service.js
@@ -128,10 +128,12 @@ class AutoModeService {
}
/**
- * Stop auto mode - stops the auto loop and all running features
+ * Stop auto mode - stops the auto loop but lets running features complete
+ * This only turns off the auto toggle to prevent picking up new features.
+ * Running tasks will continue until they complete naturally.
*/
async stop() {
- console.log("[AutoMode] Stopping auto mode");
+ console.log("[AutoMode] Stopping auto mode (letting running features complete)");
this.autoLoopRunning = false;
@@ -147,18 +149,15 @@ class AutoModeService {
this.autoLoopAbortController = null;
}
- // Abort all running features
- for (const [featureId, execution] of this.runningFeatures.entries()) {
- console.log(`[AutoMode] Aborting feature: ${featureId}`);
- if (execution.abortController) {
- execution.abortController.abort();
- }
- }
+ // NOTE: We intentionally do NOT abort running features here.
+ // Stopping auto mode should only turn off the toggle to prevent new features
+ // from being picked up. Running features will complete naturally.
+ // Use stopFeature() to cancel a specific running feature if needed.
- // Clear all running features
- this.runningFeatures.clear();
+ const runningCount = this.runningFeatures.size;
+ console.log(`[AutoMode] Auto loop stopped. ${runningCount} feature(s) still running and will complete.`);
- return { success: true };
+ return { success: true, runningFeatures: runningCount };
}
/**
diff --git a/app/electron/preload.js b/app/electron/preload.js
index 65d2b03a..c0fe2c7b 100644
--- a/app/electron/preload.js
+++ b/app/electron/preload.js
@@ -23,8 +23,8 @@ contextBridge.exposeInMainWorld("electronAPI", {
// App APIs
getPath: (name) => ipcRenderer.invoke("app:getPath", name),
- saveImageToTemp: (data, filename, mimeType) =>
- ipcRenderer.invoke("app:saveImageToTemp", { data, filename, mimeType }),
+ saveImageToTemp: (data, filename, mimeType, projectPath) =>
+ ipcRenderer.invoke("app:saveImageToTemp", { data, filename, mimeType, projectPath }),
// Agent APIs
agent: {
diff --git a/app/electron/services/context-manager.js b/app/electron/services/context-manager.js
index 22e4a609..607c806b 100644
--- a/app/electron/services/context-manager.js
+++ b/app/electron/services/context-manager.js
@@ -200,6 +200,201 @@ This helps future agent runs avoid the same pitfalls.
return "";
}
}
+
+ /**
+ * Save the initial git state before a feature starts executing
+ * This captures all files that were already modified before the AI agent started
+ * @param {string} projectPath - Path to the project
+ * @param {string} featureId - Feature ID
+ * @returns {Promise<{modifiedFiles: string[], untrackedFiles: string[]}>}
+ */
+ async saveInitialGitState(projectPath, featureId) {
+ if (!projectPath) return { modifiedFiles: [], untrackedFiles: [] };
+
+ try {
+ const { execSync } = require("child_process");
+ const contextDir = path.join(projectPath, ".automaker", "agents-context");
+
+ // Ensure directory exists
+ try {
+ await fs.access(contextDir);
+ } catch {
+ await fs.mkdir(contextDir, { recursive: true });
+ }
+
+ // Get list of modified files (both staged and unstaged)
+ let modifiedFiles = [];
+ try {
+ const modifiedOutput = execSync("git diff --name-only HEAD", {
+ cwd: projectPath,
+ encoding: "utf-8",
+ }).trim();
+ if (modifiedOutput) {
+ modifiedFiles = modifiedOutput.split("\n").filter(Boolean);
+ }
+ } catch (error) {
+ console.log("[ContextManager] No modified files or git error:", error.message);
+ }
+
+ // Get list of untracked files
+ let untrackedFiles = [];
+ try {
+ const untrackedOutput = execSync("git ls-files --others --exclude-standard", {
+ cwd: projectPath,
+ encoding: "utf-8",
+ }).trim();
+ if (untrackedOutput) {
+ untrackedFiles = untrackedOutput.split("\n").filter(Boolean);
+ }
+ } catch (error) {
+ console.log("[ContextManager] Error getting untracked files:", error.message);
+ }
+
+ // Save the initial state to a JSON file
+ const stateFile = path.join(contextDir, `${featureId}-git-state.json`);
+ const state = {
+ timestamp: new Date().toISOString(),
+ modifiedFiles,
+ untrackedFiles,
+ };
+
+ await fs.writeFile(stateFile, JSON.stringify(state, null, 2), "utf-8");
+ console.log(`[ContextManager] Saved initial git state for ${featureId}:`, {
+ modifiedCount: modifiedFiles.length,
+ untrackedCount: untrackedFiles.length,
+ });
+
+ return state;
+ } catch (error) {
+ console.error("[ContextManager] Failed to save initial git state:", error);
+ return { modifiedFiles: [], untrackedFiles: [] };
+ }
+ }
+
+ /**
+ * Get the initial git state saved before a feature started executing
+ * @param {string} projectPath - Path to the project
+ * @param {string} featureId - Feature ID
+ * @returns {Promise<{modifiedFiles: string[], untrackedFiles: string[], timestamp: string} | null>}
+ */
+ async getInitialGitState(projectPath, featureId) {
+ if (!projectPath) return null;
+
+ try {
+ const stateFile = path.join(
+ projectPath,
+ ".automaker",
+ "agents-context",
+ `${featureId}-git-state.json`
+ );
+ const content = await fs.readFile(stateFile, "utf-8");
+ return JSON.parse(content);
+ } catch (error) {
+ console.log(`[ContextManager] No initial git state found for ${featureId}`);
+ return null;
+ }
+ }
+
+ /**
+ * Delete the git state file for a feature
+ * @param {string} projectPath - Path to the project
+ * @param {string} featureId - Feature ID
+ */
+ async deleteGitStateFile(projectPath, featureId) {
+ if (!projectPath) return;
+
+ try {
+ const stateFile = path.join(
+ projectPath,
+ ".automaker",
+ "agents-context",
+ `${featureId}-git-state.json`
+ );
+ await fs.unlink(stateFile);
+ console.log(`[ContextManager] Deleted git state file for ${featureId}`);
+ } catch (error) {
+ // File might not exist, which is fine
+ if (error.code !== "ENOENT") {
+ console.error("[ContextManager] Failed to delete git state file:", error);
+ }
+ }
+ }
+
+ /**
+ * Calculate which files were changed during the AI session
+ * by comparing current git state with the saved initial state
+ * @param {string} projectPath - Path to the project
+ * @param {string} featureId - Feature ID
+ * @returns {Promise<{newFiles: string[], modifiedFiles: string[]}>}
+ */
+ async getFilesChangedDuringSession(projectPath, featureId) {
+ if (!projectPath) return { newFiles: [], modifiedFiles: [] };
+
+ try {
+ const { execSync } = require("child_process");
+
+ // Get initial state
+ const initialState = await this.getInitialGitState(projectPath, featureId);
+
+ // Get current state
+ let currentModified = [];
+ try {
+ const modifiedOutput = execSync("git diff --name-only HEAD", {
+ cwd: projectPath,
+ encoding: "utf-8",
+ }).trim();
+ if (modifiedOutput) {
+ currentModified = modifiedOutput.split("\n").filter(Boolean);
+ }
+ } catch (error) {
+ console.log("[ContextManager] No modified files or git error");
+ }
+
+ let currentUntracked = [];
+ try {
+ const untrackedOutput = execSync("git ls-files --others --exclude-standard", {
+ cwd: projectPath,
+ encoding: "utf-8",
+ }).trim();
+ if (untrackedOutput) {
+ currentUntracked = untrackedOutput.split("\n").filter(Boolean);
+ }
+ } catch (error) {
+ console.log("[ContextManager] Error getting untracked files");
+ }
+
+ if (!initialState) {
+ // No initial state - all current changes are considered from this session
+ console.log("[ContextManager] No initial state found, returning all current changes");
+ return {
+ newFiles: currentUntracked,
+ modifiedFiles: currentModified,
+ };
+ }
+
+ // Calculate files that are new since the session started
+ const initialModifiedSet = new Set(initialState.modifiedFiles || []);
+ const initialUntrackedSet = new Set(initialState.untrackedFiles || []);
+
+ // New files = current untracked - initial untracked
+ const newFiles = currentUntracked.filter(f => !initialUntrackedSet.has(f));
+
+ // Modified files = current modified - initial modified
+ const modifiedFiles = currentModified.filter(f => !initialModifiedSet.has(f));
+
+ console.log(`[ContextManager] Files changed during session for ${featureId}:`, {
+ newFilesCount: newFiles.length,
+ modifiedFilesCount: modifiedFiles.length,
+ newFiles,
+ modifiedFiles,
+ });
+
+ return { newFiles, modifiedFiles };
+ } catch (error) {
+ console.error("[ContextManager] Failed to calculate changed files:", error);
+ return { newFiles: [], modifiedFiles: [] };
+ }
+ }
}
module.exports = new ContextManager();
diff --git a/app/electron/services/feature-executor.js b/app/electron/services/feature-executor.js
index 8ab6e14e..c25ae1c5 100644
--- a/app/electron/services/feature-executor.js
+++ b/app/electron/services/feature-executor.js
@@ -193,6 +193,10 @@ class FeatureExecutor {
let isCodex;
try {
+ // Save the initial git state before starting implementation
+ // This allows us to track only files changed during this session when committing
+ await contextManager.saveInitialGitState(projectPath, feature.id);
+
// ========================================
// PHASE 1: PLANNING
// ========================================
@@ -1062,6 +1066,23 @@ class FeatureExecutor {
content: "Analyzing changes and creating commit...",
});
+ // Get the files that were changed during this AI session
+ const changedFiles = await contextManager.getFilesChangedDuringSession(
+ projectPath,
+ feature.id
+ );
+
+ // Combine new files and modified files into a single list of files to commit
+ const sessionFiles = [
+ ...changedFiles.newFiles,
+ ...changedFiles.modifiedFiles,
+ ];
+
+ console.log(
+ `[FeatureExecutor] Files changed during session: ${sessionFiles.length}`,
+ sessionFiles
+ );
+
const abortController = new AbortController();
execution.abortController = abortController;
@@ -1080,7 +1101,9 @@ IMPORTANT RULES:
- DO NOT write tests
- DO NOT do anything except analyzing changes and committing them
- Use the git command line tools via Bash
-- Create proper conventional commit messages based on what was actually changed`,
+- Create proper conventional commit messages based on what was actually changed
+- ONLY commit the specific files that were changed during the AI session (provided in the prompt)
+- DO NOT use 'git add .' - only add the specific files listed`,
maxTurns: 15, // Allow some turns to analyze and commit
cwd: projectPath,
mcpServers: {
@@ -1094,25 +1117,44 @@ IMPORTANT RULES:
abortController: abortController,
};
+ // Build the file list section for the prompt
+ let fileListSection = "";
+ if (sessionFiles.length > 0) {
+ fileListSection = `
+**Files Changed During This AI Session:**
+The following files were modified or created during this feature implementation:
+${sessionFiles.map((f) => `- ${f}`).join("\n")}
+
+**CRITICAL:** Only commit these specific files listed above. Do NOT use \`git add .\` or \`git add -A\`.
+Instead, add each file individually or use: \`git add ${sessionFiles.map((f) => `"${f}"`).join(" ")}\`
+`;
+ } else {
+ fileListSection = `
+**Note:** No specific files were tracked for this session. Please run \`git status\` to see what files have been modified, and only stage files that appear to be related to this feature implementation. Be conservative - if a file doesn't seem related to this feature, don't include it.
+`;
+ }
+
// Prompt that guides the agent to create a proper conventional commit
- const prompt = `Please commit the current changes with a proper conventional commit message.
+ const prompt = `Please commit the changes for this feature with a proper conventional commit message.
**Feature Context:**
Category: ${feature.category}
Description: ${feature.description}
-
+${fileListSection}
**Your Task:**
-1. First, run \`git status\` to see all untracked and modified files
-2. Run \`git diff\` to see the actual changes (both staged and unstaged)
+1. First, run \`git status\` to see the current state of the repository
+2. Run \`git diff\` on the specific files listed above to see the actual changes
3. Run \`git log --oneline -5\` to see recent commit message styles in this repo
-4. Analyze all the changes and draft a proper conventional commit message:
+4. Analyze the changes in the files and draft a proper conventional commit message:
- Use conventional commit format: \`type(scope): description\`
- Types: feat, fix, refactor, style, docs, test, chore
- The description should be concise (under 72 chars) and focus on "what" was done
- Summarize the nature of the changes (new feature, enhancement, bug fix, etc.)
- Make sure the commit message accurately reflects the actual code changes
-5. Run \`git add .\` to stage all changes
+5. Stage ONLY the specific files that were changed during this session (listed above)
+ - DO NOT use \`git add .\` or \`git add -A\`
+ - Add files individually: \`git add "path/to/file1" "path/to/file2"\`
6. Create the commit with a message ending with:
🤖 Generated with [Claude Code](https://claude.com/claude-code)
@@ -1136,7 +1178,8 @@ EOF
- DO NOT use the feature description verbatim as the commit message
- Analyze the actual code changes to determine the appropriate commit message
- The commit message should be professional and follow conventional commit standards
-- DO NOT modify any code or run tests - ONLY commit the existing changes`;
+- DO NOT modify any code or run tests - ONLY commit the existing changes
+- ONLY stage the specific files listed above - do not commit unrelated changes`;
const currentQuery = query({ prompt, options });
execution.query = currentQuery;
diff --git a/app/src/app/globals.css b/app/src/app/globals.css
index 50379b13..36444bdb 100644
--- a/app/src/app/globals.css
+++ b/app/src/app/globals.css
@@ -1727,3 +1727,528 @@
.titlebar-no-drag {
-webkit-app-region: no-drag;
}
+
+/* ========================================
+ XML SYNTAX HIGHLIGHTING
+ Theme-aware colors for XML editor
+ ======================================== */
+
+/* Light theme - professional and readable */
+.light .xml-highlight {
+ color: oklch(0.3 0 0); /* Default text */
+}
+
+.light .xml-tag-bracket {
+ color: oklch(0.45 0.15 250); /* Blue-gray for < > */
+}
+
+.light .xml-tag-name {
+ color: oklch(0.45 0.22 25); /* Red/maroon for tag names */
+}
+
+.light .xml-attribute-name {
+ color: oklch(0.45 0.18 280); /* Purple for attributes */
+}
+
+.light .xml-attribute-equals {
+ color: oklch(0.4 0 0); /* Dark gray for = */
+}
+
+.light .xml-attribute-value {
+ color: oklch(0.45 0.18 145); /* Green for string values */
+}
+
+.light .xml-comment {
+ color: oklch(0.55 0.05 100); /* Muted olive for comments */
+ font-style: italic;
+}
+
+.light .xml-cdata {
+ color: oklch(0.5 0.1 200); /* Teal for CDATA */
+}
+
+.light .xml-doctype {
+ color: oklch(0.5 0.15 280); /* Purple for DOCTYPE */
+}
+
+.light .xml-text {
+ color: oklch(0.25 0 0); /* Near-black for text content */
+}
+
+/* Dark theme - high contrast */
+.dark .xml-highlight {
+ color: oklch(0.9 0 0); /* Default light text */
+}
+
+.dark .xml-tag-bracket {
+ color: oklch(0.7 0.12 220); /* Soft blue for < > */
+}
+
+.dark .xml-tag-name {
+ color: oklch(0.75 0.2 25); /* Coral/salmon for tag names */
+}
+
+.dark .xml-attribute-name {
+ color: oklch(0.8 0.15 280); /* Light purple for attributes */
+}
+
+.dark .xml-attribute-equals {
+ color: oklch(0.6 0 0); /* Gray for = */
+}
+
+.dark .xml-attribute-value {
+ color: oklch(0.8 0.18 145); /* Bright green for strings */
+}
+
+.dark .xml-comment {
+ color: oklch(0.55 0.05 100); /* Muted for comments */
+ font-style: italic;
+}
+
+.dark .xml-cdata {
+ color: oklch(0.7 0.12 200); /* Teal for CDATA */
+}
+
+.dark .xml-doctype {
+ color: oklch(0.7 0.15 280); /* Purple for DOCTYPE */
+}
+
+.dark .xml-text {
+ color: oklch(0.85 0 0); /* Off-white for text */
+}
+
+/* Retro theme - neon green on black */
+.retro .xml-highlight {
+ color: oklch(0.85 0.25 145); /* Neon green default */
+}
+
+.retro .xml-tag-bracket {
+ color: oklch(0.8 0.25 200); /* Cyan for brackets */
+}
+
+.retro .xml-tag-name {
+ color: oklch(0.85 0.25 145); /* Bright green for tags */
+ text-shadow: 0 0 5px oklch(0.85 0.25 145 / 0.5);
+}
+
+.retro .xml-attribute-name {
+ color: oklch(0.8 0.25 300); /* Purple neon for attrs */
+}
+
+.retro .xml-attribute-equals {
+ color: oklch(0.6 0.15 145); /* Dim green for = */
+}
+
+.retro .xml-attribute-value {
+ color: oklch(0.8 0.25 60); /* Yellow neon for strings */
+}
+
+.retro .xml-comment {
+ color: oklch(0.5 0.15 145); /* Dim green for comments */
+ font-style: italic;
+}
+
+.retro .xml-cdata {
+ color: oklch(0.75 0.2 200); /* Cyan for CDATA */
+}
+
+.retro .xml-doctype {
+ color: oklch(0.75 0.2 300); /* Purple for DOCTYPE */
+}
+
+.retro .xml-text {
+ color: oklch(0.7 0.2 145); /* Green text */
+}
+
+/* Dracula theme */
+.dracula .xml-highlight {
+ color: oklch(0.95 0.01 280); /* #f8f8f2 */
+}
+
+.dracula .xml-tag-bracket {
+ color: oklch(0.7 0.25 350); /* Pink #ff79c6 */
+}
+
+.dracula .xml-tag-name {
+ color: oklch(0.7 0.25 350); /* Pink for tags */
+}
+
+.dracula .xml-attribute-name {
+ color: oklch(0.8 0.2 130); /* Green #50fa7b */
+}
+
+.dracula .xml-attribute-equals {
+ color: oklch(0.95 0.01 280); /* White */
+}
+
+.dracula .xml-attribute-value {
+ color: oklch(0.85 0.2 90); /* Yellow #f1fa8c */
+}
+
+.dracula .xml-comment {
+ color: oklch(0.55 0.08 280); /* #6272a4 */
+ font-style: italic;
+}
+
+.dracula .xml-cdata {
+ color: oklch(0.75 0.2 180); /* Cyan */
+}
+
+.dracula .xml-doctype {
+ color: oklch(0.7 0.2 320); /* Purple #bd93f9 */
+}
+
+.dracula .xml-text {
+ color: oklch(0.95 0.01 280); /* White */
+}
+
+/* Nord theme */
+.nord .xml-highlight {
+ color: oklch(0.9 0.01 230); /* #eceff4 */
+}
+
+.nord .xml-tag-bracket {
+ color: oklch(0.65 0.14 220); /* #81a1c1 */
+}
+
+.nord .xml-tag-name {
+ color: oklch(0.65 0.14 220); /* Frost blue for tags */
+}
+
+.nord .xml-attribute-name {
+ color: oklch(0.7 0.12 220); /* #88c0d0 */
+}
+
+.nord .xml-attribute-equals {
+ color: oklch(0.75 0.02 230); /* Dim white */
+}
+
+.nord .xml-attribute-value {
+ color: oklch(0.7 0.15 140); /* #a3be8c green */
+}
+
+.nord .xml-comment {
+ color: oklch(0.5 0.04 230); /* Dim text */
+ font-style: italic;
+}
+
+.nord .xml-cdata {
+ color: oklch(0.7 0.12 220); /* Frost blue */
+}
+
+.nord .xml-doctype {
+ color: oklch(0.7 0.2 320); /* #b48ead purple */
+}
+
+.nord .xml-text {
+ color: oklch(0.9 0.01 230); /* Snow white */
+}
+
+/* Monokai theme */
+.monokai .xml-highlight {
+ color: oklch(0.95 0.02 100); /* #f8f8f2 */
+}
+
+.monokai .xml-tag-bracket {
+ color: oklch(0.95 0.02 100); /* White */
+}
+
+.monokai .xml-tag-name {
+ color: oklch(0.8 0.2 350); /* #f92672 pink */
+}
+
+.monokai .xml-attribute-name {
+ color: oklch(0.8 0.2 140); /* #a6e22e green */
+}
+
+.monokai .xml-attribute-equals {
+ color: oklch(0.95 0.02 100); /* White */
+}
+
+.monokai .xml-attribute-value {
+ color: oklch(0.85 0.2 90); /* #e6db74 yellow */
+}
+
+.monokai .xml-comment {
+ color: oklch(0.55 0.04 100); /* #75715e */
+ font-style: italic;
+}
+
+.monokai .xml-cdata {
+ color: oklch(0.75 0.2 200); /* Cyan #66d9ef */
+}
+
+.monokai .xml-doctype {
+ color: oklch(0.75 0.2 200); /* Cyan */
+}
+
+.monokai .xml-text {
+ color: oklch(0.95 0.02 100); /* White */
+}
+
+/* Tokyo Night theme */
+.tokyonight .xml-highlight {
+ color: oklch(0.85 0.02 250); /* #a9b1d6 */
+}
+
+.tokyonight .xml-tag-bracket {
+ color: oklch(0.65 0.2 15); /* #f7768e red */
+}
+
+.tokyonight .xml-tag-name {
+ color: oklch(0.65 0.2 15); /* Red for tags */
+}
+
+.tokyonight .xml-attribute-name {
+ color: oklch(0.7 0.2 320); /* #bb9af7 purple */
+}
+
+.tokyonight .xml-attribute-equals {
+ color: oklch(0.75 0.02 250); /* Dim text */
+}
+
+.tokyonight .xml-attribute-value {
+ color: oklch(0.75 0.18 140); /* #9ece6a green */
+}
+
+.tokyonight .xml-comment {
+ color: oklch(0.5 0.04 250); /* #565f89 */
+ font-style: italic;
+}
+
+.tokyonight .xml-cdata {
+ color: oklch(0.75 0.18 200); /* #7dcfff cyan */
+}
+
+.tokyonight .xml-doctype {
+ color: oklch(0.7 0.18 280); /* #7aa2f7 blue */
+}
+
+.tokyonight .xml-text {
+ color: oklch(0.85 0.02 250); /* Text color */
+}
+
+/* Solarized theme */
+.solarized .xml-highlight {
+ color: oklch(0.75 0.02 90); /* #839496 */
+}
+
+.solarized .xml-tag-bracket {
+ color: oklch(0.65 0.15 220); /* #268bd2 blue */
+}
+
+.solarized .xml-tag-name {
+ color: oklch(0.65 0.15 220); /* Blue for tags */
+}
+
+.solarized .xml-attribute-name {
+ color: oklch(0.6 0.18 180); /* #2aa198 cyan */
+}
+
+.solarized .xml-attribute-equals {
+ color: oklch(0.75 0.02 90); /* Base text */
+}
+
+.solarized .xml-attribute-value {
+ color: oklch(0.65 0.2 140); /* #859900 green */
+}
+
+.solarized .xml-comment {
+ color: oklch(0.5 0.04 200); /* #586e75 */
+ font-style: italic;
+}
+
+.solarized .xml-cdata {
+ color: oklch(0.6 0.18 180); /* Cyan */
+}
+
+.solarized .xml-doctype {
+ color: oklch(0.6 0.2 290); /* #6c71c4 violet */
+}
+
+.solarized .xml-text {
+ color: oklch(0.75 0.02 90); /* Base text */
+}
+
+/* Gruvbox theme */
+.gruvbox .xml-highlight {
+ color: oklch(0.85 0.05 85); /* #ebdbb2 */
+}
+
+.gruvbox .xml-tag-bracket {
+ color: oklch(0.55 0.22 25); /* #fb4934 red */
+}
+
+.gruvbox .xml-tag-name {
+ color: oklch(0.55 0.22 25); /* Red for tags */
+}
+
+.gruvbox .xml-attribute-name {
+ color: oklch(0.7 0.15 200); /* #8ec07c aqua */
+}
+
+.gruvbox .xml-attribute-equals {
+ color: oklch(0.7 0.04 85); /* Dim text */
+}
+
+.gruvbox .xml-attribute-value {
+ color: oklch(0.65 0.2 140); /* #b8bb26 green */
+}
+
+.gruvbox .xml-comment {
+ color: oklch(0.55 0.04 85); /* #928374 gray */
+ font-style: italic;
+}
+
+.gruvbox .xml-cdata {
+ color: oklch(0.7 0.15 200); /* Aqua */
+}
+
+.gruvbox .xml-doctype {
+ color: oklch(0.6 0.2 320); /* #d3869b purple */
+}
+
+.gruvbox .xml-text {
+ color: oklch(0.85 0.05 85); /* Foreground */
+}
+
+/* Catppuccin theme */
+.catppuccin .xml-highlight {
+ color: oklch(0.9 0.01 280); /* #cdd6f4 */
+}
+
+.catppuccin .xml-tag-bracket {
+ color: oklch(0.65 0.2 15); /* #f38ba8 red */
+}
+
+.catppuccin .xml-tag-name {
+ color: oklch(0.65 0.2 15); /* Red for tags */
+}
+
+.catppuccin .xml-attribute-name {
+ color: oklch(0.75 0.15 280); /* #cba6f7 mauve */
+}
+
+.catppuccin .xml-attribute-equals {
+ color: oklch(0.75 0.02 280); /* Subtext */
+}
+
+.catppuccin .xml-attribute-value {
+ color: oklch(0.8 0.15 160); /* #a6e3a1 green */
+}
+
+.catppuccin .xml-comment {
+ color: oklch(0.5 0.04 280); /* Overlay */
+ font-style: italic;
+}
+
+.catppuccin .xml-cdata {
+ color: oklch(0.75 0.15 220); /* #89b4fa blue */
+}
+
+.catppuccin .xml-doctype {
+ color: oklch(0.8 0.15 350); /* #f5c2e7 pink */
+}
+
+.catppuccin .xml-text {
+ color: oklch(0.9 0.01 280); /* Text */
+}
+
+/* One Dark theme */
+.onedark .xml-highlight {
+ color: oklch(0.85 0.02 240); /* #abb2bf */
+}
+
+.onedark .xml-tag-bracket {
+ color: oklch(0.6 0.2 20); /* #e06c75 red */
+}
+
+.onedark .xml-tag-name {
+ color: oklch(0.6 0.2 20); /* Red for tags */
+}
+
+.onedark .xml-attribute-name {
+ color: oklch(0.8 0.15 80); /* #e5c07b yellow */
+}
+
+.onedark .xml-attribute-equals {
+ color: oklch(0.7 0.02 240); /* Dim text */
+}
+
+.onedark .xml-attribute-value {
+ color: oklch(0.75 0.18 150); /* #98c379 green */
+}
+
+.onedark .xml-comment {
+ color: oklch(0.5 0.03 240); /* #5c6370 */
+ font-style: italic;
+}
+
+.onedark .xml-cdata {
+ color: oklch(0.7 0.15 180); /* #56b6c2 cyan */
+}
+
+.onedark .xml-doctype {
+ color: oklch(0.75 0.15 320); /* #c678dd magenta */
+}
+
+.onedark .xml-text {
+ color: oklch(0.85 0.02 240); /* Text */
+}
+
+/* Synthwave theme */
+.synthwave .xml-highlight {
+ color: oklch(0.95 0.02 320); /* Warm white */
+}
+
+.synthwave .xml-tag-bracket {
+ color: oklch(0.7 0.28 350); /* #f97e72 hot pink */
+}
+
+.synthwave .xml-tag-name {
+ color: oklch(0.7 0.28 350); /* Hot pink */
+ text-shadow: 0 0 8px oklch(0.7 0.28 350 / 0.5);
+}
+
+.synthwave .xml-attribute-name {
+ color: oklch(0.7 0.25 280); /* #ff7edb purple */
+}
+
+.synthwave .xml-attribute-equals {
+ color: oklch(0.8 0.02 320); /* White-ish */
+}
+
+.synthwave .xml-attribute-value {
+ color: oklch(0.85 0.2 60); /* #fede5d yellow */
+ text-shadow: 0 0 5px oklch(0.85 0.2 60 / 0.3);
+}
+
+.synthwave .xml-comment {
+ color: oklch(0.55 0.08 290); /* Dim purple */
+ font-style: italic;
+}
+
+.synthwave .xml-cdata {
+ color: oklch(0.8 0.25 200); /* #72f1b8 cyan */
+}
+
+.synthwave .xml-doctype {
+ color: oklch(0.8 0.25 200); /* Cyan */
+}
+
+.synthwave .xml-text {
+ color: oklch(0.95 0.02 320); /* White */
+}
+
+/* XML Editor container styles */
+.xml-editor {
+ position: relative;
+}
+
+.xml-editor textarea {
+ z-index: 1;
+}
+
+.xml-editor .xml-highlight {
+ z-index: 0;
+}
diff --git a/app/src/components/layout/sidebar.tsx b/app/src/components/layout/sidebar.tsx
index 77e92c28..09abd4eb 100644
--- a/app/src/components/layout/sidebar.tsx
+++ b/app/src/components/layout/sidebar.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState, useMemo, useEffect, useCallback } from "react";
+import { useState, useMemo, useEffect, useCallback, useRef } from "react";
import { cn } from "@/lib/utils";
import { useAppStore } from "@/store/app-store";
import {
@@ -39,6 +39,7 @@ import {
Atom,
Radio,
Monitor,
+ Search,
} from "lucide-react";
import {
DropdownMenu,
@@ -109,15 +110,15 @@ interface NavItem {
// Sortable Project Item Component
interface SortableProjectItemProps {
project: Project;
- index: number;
currentProjectId: string | undefined;
+ isHighlighted: boolean;
onSelect: (project: Project) => void;
}
function SortableProjectItem({
project,
- index,
currentProjectId,
+ isHighlighted,
onSelect,
}: SortableProjectItemProps) {
const {
@@ -141,7 +142,8 @@ function SortableProjectItem({
style={style}
className={cn(
"flex items-center gap-2 px-2 py-1.5 rounded-md cursor-pointer text-muted-foreground hover:text-foreground hover:bg-accent",
- isDragging && "bg-accent shadow-lg"
+ isDragging && "bg-accent shadow-lg",
+ isHighlighted && "bg-brand-500/10 text-foreground"
)}
data-testid={`project-option-${project.id}`}
>
@@ -156,16 +158,6 @@ function SortableProjectItem({
- {/* Hotkey indicator */}
- {index < 9 && (
-
- {index + 1}
-
- )}
-
{/* Project content - clickable area */}
(null);
const [isEmptyingTrash, setIsEmptyingTrash] = useState(false);
@@ -238,6 +232,43 @@ export function Sidebar() {
const [generateFeatures, setGenerateFeatures] = useState(true);
const [showSpecIndicator, setShowSpecIndicator] = useState(true);
+ // Ref for project search input
+ const projectSearchInputRef = useRef(null);
+
+ // Filtered projects based on search query
+ const filteredProjects = useMemo(() => {
+ if (!projectSearchQuery.trim()) {
+ return projects;
+ }
+ const query = projectSearchQuery.toLowerCase();
+ return projects.filter((project) =>
+ project.name.toLowerCase().includes(query)
+ );
+ }, [projects, projectSearchQuery]);
+
+ // Reset selection when filtered results change
+ useEffect(() => {
+ setSelectedProjectIndex(0);
+ }, [filteredProjects.length, projectSearchQuery]);
+
+ // Reset search query when dropdown closes
+ useEffect(() => {
+ if (!isProjectPickerOpen) {
+ setProjectSearchQuery("");
+ setSelectedProjectIndex(0);
+ }
+ }, [isProjectPickerOpen]);
+
+ // Focus the search input when dropdown opens
+ useEffect(() => {
+ if (isProjectPickerOpen) {
+ // Small delay to ensure the dropdown is rendered
+ setTimeout(() => {
+ projectSearchInputRef.current?.focus();
+ }, 0);
+ }
+ }, [isProjectPickerOpen]);
+
// Sensors for drag-and-drop
const sensors = useSensors(
useSensor(PointerSensor, {
@@ -537,39 +568,45 @@ export function Sidebar() {
},
];
- // Handler for selecting a project by number key
- const selectProjectByNumber = useCallback(
- (num: number) => {
- const projectIndex = num - 1;
- if (projectIndex >= 0 && projectIndex < projects.length) {
- setCurrentProject(projects[projectIndex]);
- setIsProjectPickerOpen(false);
- }
- },
- [projects, setCurrentProject]
- );
+ // Handle selecting the currently highlighted project
+ const selectHighlightedProject = useCallback(() => {
+ if (filteredProjects.length > 0 && selectedProjectIndex < filteredProjects.length) {
+ setCurrentProject(filteredProjects[selectedProjectIndex]);
+ setIsProjectPickerOpen(false);
+ }
+ }, [filteredProjects, selectedProjectIndex, setCurrentProject]);
// Handle keyboard events when project picker is open
useEffect(() => {
if (!isProjectPickerOpen) return;
const handleKeyDown = (event: KeyboardEvent) => {
- const num = parseInt(event.key, 10);
- if (num >= 1 && num <= 9) {
- event.preventDefault();
- selectProjectByNumber(num);
- } else if (event.key === "Escape") {
+ if (event.key === "Escape") {
setIsProjectPickerOpen(false);
- } else if (event.key.toLowerCase() === "p") {
- // Toggle off when P is pressed while dropdown is open
+ } else if (event.key === "Enter") {
event.preventDefault();
- setIsProjectPickerOpen(false);
+ selectHighlightedProject();
+ } else if (event.key === "ArrowDown") {
+ event.preventDefault();
+ setSelectedProjectIndex((prev) =>
+ prev < filteredProjects.length - 1 ? prev + 1 : prev
+ );
+ } else if (event.key === "ArrowUp") {
+ event.preventDefault();
+ setSelectedProjectIndex((prev) => (prev > 0 ? prev - 1 : prev));
+ } else if (event.key.toLowerCase() === "p" && !event.metaKey && !event.ctrlKey) {
+ // Toggle off when P is pressed (not with modifiers) while dropdown is open
+ // Only if not typing in the search input
+ if (document.activeElement !== projectSearchInputRef.current) {
+ event.preventDefault();
+ setIsProjectPickerOpen(false);
+ }
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
- }, [isProjectPickerOpen, selectProjectByNumber]);
+ }, [isProjectPickerOpen, selectHighlightedProject, filteredProjects.length]);
// Build keyboard shortcuts for navigation
const navigationShortcuts: KeyboardShortcut[] = useMemo(() => {
@@ -793,29 +830,58 @@ export function Sidebar() {
align="start"
data-testid="project-picker-dropdown"
>
-
- p.id)}
- strategy={verticalListSortingStrategy}
+ {/* Search input for type-ahead filtering */}
+
-
+
@@ -662,6 +672,7 @@ export function ProfilesView() {
onSave={handleAddProfile}
onCancel={() => setShowAddDialog(false)}
isEditing={false}
+ hotkeyActive={showAddDialog}
/>
@@ -682,6 +693,7 @@ export function ProfilesView() {
onSave={handleUpdateProfile}
onCancel={() => setEditingProfile(null)}
isEditing={true}
+ hotkeyActive={!!editingProfile}
/>
)}
diff --git a/app/src/components/views/settings-view.tsx b/app/src/components/views/settings-view.tsx
index f3fe7581..e030800a 100644
--- a/app/src/components/views/settings-view.tsx
+++ b/app/src/components/views/settings-view.tsx
@@ -68,6 +68,7 @@ export function SettingsView() {
setCurrentView,
theme,
setTheme,
+ setProjectTheme,
kanbanCardDetailLevel,
setKanbanCardDetailLevel,
defaultSkipTests,
@@ -79,6 +80,18 @@ export function SettingsView() {
currentProject,
moveProjectToTrash,
} = useAppStore();
+
+ // Compute the effective theme for the current project
+ const effectiveTheme = currentProject?.theme || theme;
+
+ // Handler to set theme - saves to project if one is selected, otherwise to global
+ const handleSetTheme = (newTheme: typeof theme) => {
+ if (currentProject) {
+ setProjectTheme(currentProject.id, newTheme);
+ } else {
+ setTheme(newTheme);
+ }
+ };
const [anthropicKey, setAnthropicKey] = useState(apiKeys.anthropic);
const [googleKey, setGoogleKey] = useState(apiKeys.google);
const [openaiKey, setOpenaiKey] = useState(apiKeys.openai);
@@ -171,13 +184,28 @@ export function SettingsView() {
if (!container) return;
const handleScroll = () => {
- const sections = NAV_ITEMS.map((item) => ({
- id: item.id,
- element: document.getElementById(item.id),
- })).filter((s) => s.element);
+ const sections = NAV_ITEMS.filter(
+ (item) => item.id !== "danger" || currentProject
+ )
+ .map((item) => ({
+ id: item.id,
+ element: document.getElementById(item.id),
+ }))
+ .filter((s) => s.element);
const containerRect = container.getBoundingClientRect();
const scrollTop = container.scrollTop;
+ const scrollHeight = container.scrollHeight;
+ const clientHeight = container.clientHeight;
+
+ // Check if scrolled to bottom (within a small threshold)
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight - 50;
+
+ if (isAtBottom && sections.length > 0) {
+ // If at bottom, highlight the last visible section
+ setActiveSection(sections[sections.length - 1].id);
+ return;
+ }
for (let i = sections.length - 1; i >= 0; i--) {
const section = sections[i];
@@ -194,7 +222,7 @@ export function SettingsView() {
container.addEventListener("scroll", handleScroll);
return () => container.removeEventListener("scroll", handleScroll);
- }, []);
+ }, [currentProject]);
const scrollToSection = useCallback((sectionId: string) => {
const element = document.getElementById(sectionId);
@@ -407,7 +435,7 @@ export function SettingsView() {
{/* Scrollable Content */}
-
+
{/* API Keys Section */}
-
+
diff --git a/app/src/components/views/spec-view.tsx b/app/src/components/views/spec-view.tsx
index b54ceef1..0e292650 100644
--- a/app/src/components/views/spec-view.tsx
+++ b/app/src/components/views/spec-view.tsx
@@ -4,6 +4,7 @@ import { useEffect, useState, useCallback } from "react";
import { useAppStore } from "@/store/app-store";
import { getElectronAPI } from "@/lib/electron";
import { Button } from "@/components/ui/button";
+import { HotkeyButton } from "@/components/ui/hotkey-button";
import { Card } from "@/components/ui/card";
import {
Dialog,
@@ -15,6 +16,7 @@ import {
} from "@/components/ui/dialog";
import { Save, RefreshCw, FileText, Sparkles, Loader2, FilePlus2 } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
+import { XmlSyntaxEditor } from "@/components/ui/xml-syntax-editor";
import type { SpecRegenerationEvent } from "@/types/electron";
export function SpecView() {
@@ -299,13 +301,15 @@ export function SpecView() {
>
Cancel
-
+
@@ -359,12 +363,10 @@ export function SpecView() {
{/* Editor */}
-
@@ -409,9 +411,11 @@ export function SpecView() {
>
Cancel
-
+
diff --git a/app/src/components/views/welcome-view.tsx b/app/src/components/views/welcome-view.tsx
index 901e0fa7..d17236ca 100644
--- a/app/src/components/views/welcome-view.tsx
+++ b/app/src/components/views/welcome-view.tsx
@@ -2,6 +2,7 @@
import { useState, useCallback } from "react";
import { Button } from "@/components/ui/button";
+import { HotkeyButton } from "@/components/ui/hotkey-button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
@@ -512,14 +513,16 @@ export function WelcomeView() {
>
Cancel
-
+
diff --git a/app/src/hooks/use-auto-mode.ts b/app/src/hooks/use-auto-mode.ts
index 4301d406..9420a087 100644
--- a/app/src/hooks/use-auto-mode.ts
+++ b/app/src/hooks/use-auto-mode.ts
@@ -186,7 +186,7 @@ export function useAutoMode() {
}
}, [currentProject, setAutoModeRunning, maxConcurrency]);
- // Stop auto mode
+ // Stop auto mode - only turns off the toggle, running tasks continue
const stop = useCallback(async () => {
if (!currentProject) {
console.error("No project selected");
@@ -203,8 +203,11 @@ export function useAutoMode() {
if (result.success) {
setAutoModeRunning(currentProject.id, false);
- clearRunningTasks(currentProject.id);
- console.log("[AutoMode] Stopped successfully");
+ // NOTE: We intentionally do NOT clear running tasks here.
+ // Stopping auto mode only turns off the toggle to prevent new features
+ // from being picked up. Running tasks will complete naturally and be
+ // removed via the auto_mode_feature_complete event.
+ console.log("[AutoMode] Stopped successfully - running tasks will continue");
} else {
console.error("[AutoMode] Failed to stop:", result.error);
throw new Error(result.error || "Failed to stop auto mode");
@@ -213,7 +216,7 @@ export function useAutoMode() {
console.error("[AutoMode] Error stopping:", error);
throw error;
}
- }, [currentProject, setAutoModeRunning, clearRunningTasks]);
+ }, [currentProject, setAutoModeRunning]);
// Stop a specific feature
const stopFeature = useCallback(
diff --git a/backup.json b/backup.json
new file mode 100644
index 00000000..dd5b993c
--- /dev/null
+++ b/backup.json
@@ -0,0 +1,269 @@
+[
+ {
+ "id": "feature-1765387670653-bl83444lj",
+ "category": "Kanban",
+ "description": "In the output logs of the proc agent output in the file diffs Can you add a scroll bar so it actually scroll to see all these new styles right now it seems like I can't scroll",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T17:42:09.158Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed scrolling for file diffs in agent output modal. Changed approach: parent container (agent-output-modal.tsx) now handles scrolling with overflow-y-auto, while GitDiffPanel uses natural height without flex-based scrolling. Modified: agent-output-modal.tsx (line 304), git-diff-panel.tsx (lines 461, 500, 525, 614).",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765387746902-na752mp1y",
+ "category": "Kanban",
+ "description": "When the add feature modal pops up, make sure that the description is always the main focus. When it first loads up. Do not focus the prompt tab, which is currently doing this.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T17:29:13.854Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Added autoFocus prop to DescriptionImageDropZone component. Modified: description-image-dropzone.tsx (added autoFocus prop support), board-view.tsx (enabled autoFocus on add feature modal). Now the description textarea receives focus when the modal opens instead of the prompt tab.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388139100-ln31jgp5n",
+ "category": "Uncategorized",
+ "description": "Can you add a disclaimer .md file to this project saying that this uses a bunch of AI related tooling which could have access to your operating system and change and delete files and so use at your own risk. We tried to check it for security of vulnerability to make sure it's good. But you assume the risk and you should be reviewing the code yourself before you try to run it. And also sandboxing this so it doesn't have access to your whole operating system like using Docker to sandbox before you run it or use a virtual machine to sandbox it. and that we do not recommend running locally on your computer due to the risk of it having access to everything on your computer.\n\nUpdate or read me with a short paragraph overview/description at the top followed by a disclaimer section in red that points to the disclaimer file with the same disclaimer information.\n\nThen a section that lists out all the features of cool emojis.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T17:35:40.700Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Created DISCLAIMER.md with comprehensive security warnings about AI tooling risks and sandboxing recommendations. Updated README.md with project overview, red caution disclaimer section linking to DISCLAIMER.md, and features list with emojis covering all major functionality (Kanban, AI agents, multi-model support, etc.).",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388388144-oa1dewze9",
+ "category": "Uncategorized",
+ "description": "Please fix the styling of the hotkeys to be more using the theme colors. Notice that they're kind of gray. I would rather than have some type of like light green if they're not active and then the brighter green if they are active and also the add feature but in the top right it's not very legible. So fix the accessibility of the hotkey but also keep it within the theme. You might just have to change the text inside of it to be bright green.",
+ "steps": [],
+ "status": "verified",
+ "startedAt": "2025-12-10T17:40:02.745Z",
+ "imagePaths": [
+ {
+ "id": "img-1765388352835-dgx4ishp0",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765388352832-6jnbgw8kg_Screenshot_2025-12-10_at_12.39.10_PM.png",
+ "filename": "Screenshot 2025-12-10 at 12.39.10 PM.png",
+ "mimeType": "image/png"
+ },
+ {
+ "id": "img-1765388356955-a0gdovp5b",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765388356954-d59a65nf9_Screenshot_2025-12-10_at_12.39.15_PM.png",
+ "filename": "Screenshot 2025-12-10 at 12.39.15 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388402095-x66aduwg3",
+ "category": "Uncategorized",
+ "description": "Can you please add some spacing and fix the styling of the hotkey with the command enter and make it so they're both vertically aligned for those icons?",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T17:44:08.667Z",
+ "imagePaths": [
+ {
+ "id": "img-1765388390408-eefybe95t",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765388390408-nn320yoyc_Screenshot_2025-12-10_at_12.39.47_PM.png",
+ "filename": "Screenshot 2025-12-10 at 12.39.47 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388662444-as3hqn7be",
+ "category": "Uncategorized",
+ "description": "Fix the styling on all the buttons when I hover over them with my mouse they never change to a click mouse cursor. In order they seem to show any type of like hover state changes, if they do, at least for the certain game I'm using, it's not very obvious that you're hovering over the button.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T17:45:59.666Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed hover cursor styling on all interactive elements. Modified: button.tsx (added cursor-pointer to base styles), dropdown-menu.tsx (added cursor-pointer to all menu items), checkbox.tsx (added cursor-pointer), tabs.tsx (added cursor-pointer to triggers), dialog.tsx (added cursor-pointer to close button), slider.tsx (added cursor-grab to thumb, cursor-pointer to track), globals.css (added global CSS rules for clickable elements to ensure consistent cursor behavior).",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388693856-yx1dk1acj",
+ "category": "Kanban",
+ "description": "The tabs in the add new feature modal for the prompt model and testing tabs. They don't seem to look like tabs when I'm on a certain theme. Can you verify that those are hooked into the theme? And make sure that the active one is colored differently than the unactive ones. Keep the primary colors when doing this.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T17:46:00.019Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed tabs component theme integration. Modified: tabs.tsx. Changes: (1) Added visible border to TabsList container using theme's border color, (2) Changed inactive tab text to foreground/70 for better contrast, (3) Enhanced active tab with shadow-md and semi-transparent primary border, (4) Improved hover state with full accent background. Active tabs now properly use bg-primary/text-primary-foreground which adapts to each theme.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388754462-bek0flvkj",
+ "category": "Uncategorized",
+ "description": "There's a strange issue when I when when these agents are like doing things it seems like it completely refreshes the whole Kanban board and there's like a black flash. Can you verify that the data loading does not cause the entire component to refresh? Maybe there's an issue with the react effect or how the component is rendered maybe we need some used memos or something but it shouldn't refresh the whole page it should just like update the individual cards when they change.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T17:47:20.170Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed Kanban board flash/refresh issue. Changes: (1) board-view.tsx - Added isInitialLoadRef to only show loading spinner on initial load, not on feature reloads; memoized column features with useMemo to prevent recalculation on every render. (2) kanban-card.tsx - Wrapped with React.memo to prevent unnecessary re-renders. (3) kanban-column.tsx - Wrapped with React.memo for performance. The flash was caused by loadFeatures setting isLoading=true on every reload, which caused the entire board to unmount and show a loading spinner.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765388793845-yhluf0sry",
+ "category": "Uncategorized",
+ "description": "Add in the ability so that every project can have its own selected theme. This will allow me to have different projects have different themes so I can easily differentiate when I have one project selected or not.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T18:00:33.814Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed per-project theme support. Modified: settings-view.tsx (now saves theme to project when project is selected, shows label indicating scope), page.tsx (computes effectiveTheme from currentProject?.theme || theme), app-store.ts (added setProjectTheme action, theme property on Project interface). When a project is selected, changing theme in Settings saves to that project only.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389333728-y74hmz2yp",
+ "category": "Agent Runner",
+ "description": "On the Agent Runner, I took a screenshot and dropped it into the text area and after a certain amount of time, it's like the image preview just completely went away. Can you debug and fix this on the Agent Runner?",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389352488-j9bez5ztx",
+ "category": "Kanban",
+ "description": "It seems like the category typehead is no longer working. Can you double check that code didn't break? It should have kept track of categories inside of the categories.json file inside the .automaker folder when adding new features modal",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389420151-jzdsjzn9u",
+ "category": "Kanban",
+ "description": "Add in the ability to just click and drag a card from the waiting approval directly into the verify column as I can usually just commit it manually if I want to.",
+ "steps": [],
+ "status": "waiting_approval",
+ "startedAt": "2025-12-10T18:05:08.252Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Fixed drag-and-drop from waiting_approval to verified column. The issue was condition ordering in handleDragEnd - the skipTests check was intercepting waiting_approval features before they could be handled. Moved waiting_approval status check before skipTests check in board-view.tsx:731-752. Also updated agent memory with this lesson.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389468077-9x3vt1yjq",
+ "category": "Uncategorized",
+ "description": "The commit functionality on the waiting approval cards doesn't seem to work. It just committed everything in my working copy for git. I think I should be a little bit more intelligent and figure out what files it changed for that AI session and then only try to git add those individual files and commit those. Right now it just basically did a git add all and committed those. Re-factor the prompting or figure out a way to make it so it's more specific on what it's going to commit with the future change.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389502705-6deep7mvi",
+ "category": "Uncategorized",
+ "description": "I'm noticing that a lot of buttons in the UI, especially the ones that are submitting, are either missing the submit hotkey or they're not styled properly. Look at the add feature submit button that's on the add feature modal and abstract away a submit button so that on every single page that needs to submit something I can reuse this type of hotkey functionality. In fact, every single button should be abstracted enough where I can provide a hotkey and it will automatically listen if I press that hotkey when it's in view.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389772166-an3yk3kpo",
+ "category": "Uncategorized",
+ "description": "Can you add some more padding to the bottom of the settings panel? Notice that I can't scroll down all the way. And that doesn't highlight the left sub navigation to highlight it pink when I'm on that section. I should be able to scroll a bit further and just have like blank space at the bottom. So I can eventually get to that actual section.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [
+ {
+ "id": "img-1765389750685-jhq6rcidc",
+ "path": "/Users/webdevcody/Library/Application Support/automaker/images/1765389750683-mqb0j7a3z_Screenshot_2025-12-10_at_1.02.26_PM.png",
+ "filename": "Screenshot 2025-12-10 at 1.02.26 PM.png",
+ "mimeType": "image/png"
+ }
+ ],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389829239-bbk596u6z",
+ "category": "Uncategorized",
+ "description": "Add some type of XML highlighting to the spec editor view. Right now it's just all grayscale and it's kind of ugly to look at. And try to make the syntax highlighting match the current selected theme.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765389859334-si9ivtehw",
+ "category": "Uncategorized",
+ "description": "Add a search bar to the top of the Kanban column that allows me to search the filter down just to show the cards I'm interested in by keyword.",
+ "steps": [],
+ "status": "in_progress",
+ "startedAt": "2025-12-10T18:09:26.193Z",
+ "imagePaths": [],
+ "skipTests": true,
+ "summary": "Added search bar to Kanban board. Modified: board-view.tsx. Features: 1) Search input with icon at top of columns, 2) Case-insensitive filtering by description or category, 3) Clear button to reset search, 4) Real-time filtering as you type.",
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390022638-nalulsdxv",
+ "category": "Uncategorized",
+ "description": "In the project select can you actually remove the whole like 1 2 3 4 5 hotkeys instead? Just make it be a type ahead so when I open the panel I just should be able to type in the first letter or two of the project that I want and press enter and that should Just select it for me",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390055621-ewc4w7k5h",
+ "category": "Uncategorized",
+ "description": "In the add new feature prompt, instead of disabling the add feature button until we type into the description, keep it enabled. But if you click it, make sure you just show the client side validation and turn the description box in any other required field as red so that the user knows they have to fill it in.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ },
+ {
+ "id": "feature-1765390131625-ymqxr5gln",
+ "category": "Uncategorized",
+ "description": "Can you please in the top right of the Kanban board use the show three icons for the Kanban card display formatting. You can look at the settings page to see that there's three different settings that we use for displaying the Kanban card information. But I also just want this to be really quickly accessible at the top right of the Kanban that they can switch between those three toggles. Keep them simple only just icons you don't need to put words in them. Make sure they do have harbor states though, or tooltips I mean.",
+ "steps": [],
+ "status": "backlog",
+ "imagePaths": [],
+ "skipTests": true,
+ "model": "opus",
+ "thinkingLevel": "none"
+ }
+]
\ No newline at end of file