diff --git a/.automaker/feature_list.json b/.automaker/feature_list.json
index b6c2deb4..2095e4dd 100644
--- a/.automaker/feature_list.json
+++ b/.automaker/feature_list.json
@@ -16,28 +16,28 @@
"3. archive it",
"4. expect empty state placeholder in right panel"
],
- "status": "backlog"
+ "status": "verified"
},
{
"id": "feature-1765260557163-86b3tby5d",
"category": "Core",
"description": "Remove analysis link and related code, it's not useful",
"steps": [],
- "status": "backlog"
+ "status": "verified"
},
{
"id": "feature-1765260608543-frhplaxss",
"category": "Kanban",
"description": "when clicking a value in the typeahead, there is a bug where it does not close automatically, fix this",
"steps": [],
- "status": "backlog"
+ "status": "verified"
},
{
"id": "feature-1765260671085-7dgotl21h",
"category": "Kanban",
"description": "show a error toast when concurrency limit is hit and someone tries to drag a card into in progress to give them feedback why it won't work.",
"steps": [],
- "status": "backlog"
+ "status": "verified"
},
{
"id": "feature-1765260791341-iaxxt172n",
@@ -58,13 +58,48 @@
"category": "Kanban",
"description": "add a count up timer for showing how long the card has been in progress",
"steps": [],
- "status": "backlog"
+ "status": "verified"
},
{
"id": "feature-1765261027396-b78maajg7",
"category": "Kanban",
"description": "When the agent is marked as verified, remove their context file",
"steps": [],
+ "status": "verified"
+ },
+ {
+ "id": "feature-1765261574969-kaqzq39fh",
+ "category": "Core",
+ "description": "change the recent change for adding the ability to edit the context .automaker/context directory to instead be in .automaker/support and auto add it to prompts",
+ "steps": [],
+ "status": "verified"
+ },
+ {
+ "id": "feature-1765262225700-q2rkue6l8",
+ "category": "Context",
+ "description": "Add Context File should show a file name and a textarea for the context info, that text area should allow drag n drop for txt files and .md files which the system will parse and put into the text area",
+ "steps": [],
+ "status": "backlog"
+ },
+ {
+ "id": "feature-1765262261787-o84j26dty",
+ "category": "Kanban",
+ "description": "Ability to delete in progress cards which will auto stop their agents on delete",
+ "steps": [],
+ "status": "verified"
+ },
+ {
+ "id": "feature-1765262348401-hivjg6vuq",
+ "category": "Kanban",
+ "description": "Make in progress column double width so that the cards display 2 columns masonry layout",
+ "steps": [],
+ "status": "backlog"
+ },
+ {
+ "id": "feature-1765262430461-vennhg2b5",
+ "category": "Core",
+ "description": "When the electron ui refreshes, it often redirects me back to the overview, remeber my last route and restore on app load",
+ "steps": [],
"status": "backlog"
}
]
\ No newline at end of file
diff --git a/app/src/lib/electron.ts b/app/src/lib/electron.ts
index 76be1c0e..e0358029 100644
--- a/app/src/lib/electron.ts
+++ b/app/src/lib/electron.ts
@@ -157,8 +157,8 @@ export const getElectronAPI = (): ElectronAPI => {
content: "\n Demo Project\n",
};
}
- // For any file in mock context directory, return empty string (file exists but is empty)
- if (filePath.includes(".automaker/context/")) {
+ // For any file in mock agents-context directory, return empty string (file exists but is empty)
+ if (filePath.includes(".automaker/agents-context/")) {
return { success: true, content: "" };
}
return { success: false, error: "File not found (mock)" };
@@ -176,8 +176,8 @@ export const getElectronAPI = (): ElectronAPI => {
readdir: async (dirPath: string) => {
// Return mock directory structure based on path
if (dirPath) {
- // Check if this is the context directory - return files from mock file system
- if (dirPath.includes(".automaker/context")) {
+ // Check if this is the context or agents-context directory - return files from mock file system
+ if (dirPath.includes(".automaker/context") || dirPath.includes(".automaker/agents-context")) {
const contextFiles = Object.keys(mockFileSystem)
.filter(path => path.startsWith(dirPath) && path !== dirPath)
.map(path => {
@@ -417,7 +417,7 @@ function createMockAutoModeAPI(): AutoModeAPI {
contextExists: async (projectPath: string, featureId: string) => {
// Mock implementation - simulate that context exists for some features
- const exists = mockFileSystem[`${projectPath}/.automaker/context/${featureId}.md`] !== undefined;
+ const exists = mockFileSystem[`${projectPath}/.automaker/agents-context/${featureId}.md`] !== undefined;
return { success: true, exists };
},
@@ -539,6 +539,10 @@ async function simulateAutoModeLoop(projectPath: string, featureId: string) {
message: "Feature implemented successfully",
});
+ // Delete context file when feature is verified (matches real auto-mode-service behavior)
+ const contextFilePath = `${projectPath}/.automaker/agents-context/${featureId}.md`;
+ delete mockFileSystem[contextFilePath];
+
// Clean up this feature from running set
mockRunningFeatures.delete(featureId);
mockAutoModeTimeouts.delete(featureId);
diff --git a/app/tests/utils.ts b/app/tests/utils.ts
index dc0f7ccf..65e3920f 100644
--- a/app/tests/utils.ts
+++ b/app/tests/utils.ts
@@ -516,3 +516,293 @@ export async function waitForSuccessToast(
});
return toast;
}
+
+/**
+ * Get the delete button for an in_progress feature
+ */
+export async function getDeleteInProgressButton(
+ page: Page,
+ featureId: string
+): Promise {
+ return page.locator(`[data-testid="delete-inprogress-feature-${featureId}"]`);
+}
+
+/**
+ * Click the delete button for an in_progress feature
+ */
+export async function clickDeleteInProgressFeature(
+ page: Page,
+ featureId: string
+): Promise {
+ const button = page.locator(
+ `[data-testid="delete-inprogress-feature-${featureId}"]`
+ );
+ await button.click();
+}
+
+/**
+ * Check if the delete button is visible for an in_progress feature
+ */
+export async function isDeleteInProgressButtonVisible(
+ page: Page,
+ featureId: string
+): Promise {
+ const button = page.locator(
+ `[data-testid="delete-inprogress-feature-${featureId}"]`
+ );
+ return await button.isVisible();
+}
+
+/**
+ * Set up a mock project with features in different states
+ */
+export async function setupMockProjectWithFeatures(
+ page: Page,
+ options?: {
+ maxConcurrency?: number;
+ runningTasks?: string[];
+ features?: Array<{
+ id: string;
+ category: string;
+ description: string;
+ status: "backlog" | "in_progress" | "verified";
+ steps?: string[];
+ }>;
+ }
+): Promise {
+ await page.addInitScript(
+ (opts: typeof options) => {
+ const mockProject = {
+ id: "test-project-1",
+ name: "Test Project",
+ path: "/mock/test-project",
+ lastOpened: new Date().toISOString(),
+ };
+
+ const mockFeatures = opts?.features || [];
+
+ const mockState = {
+ state: {
+ projects: [mockProject],
+ currentProject: mockProject,
+ theme: "dark",
+ sidebarOpen: true,
+ apiKeys: { anthropic: "", google: "" },
+ chatSessions: [],
+ chatHistoryOpen: false,
+ maxConcurrency: opts?.maxConcurrency ?? 3,
+ isAutoModeRunning: false,
+ runningAutoTasks: opts?.runningTasks ?? [],
+ autoModeActivityLog: [],
+ features: mockFeatures,
+ },
+ version: 0,
+ };
+
+ localStorage.setItem("automaker-storage", JSON.stringify(mockState));
+ },
+ options
+ );
+}
+
+/**
+ * Set up a mock project with a feature context file
+ * This simulates an agent having created context for a feature
+ */
+export async function setupMockProjectWithContextFile(
+ page: Page,
+ featureId: string,
+ contextContent: string = "# Agent Context\n\nPrevious implementation work..."
+): Promise {
+ await page.addInitScript(
+ ({ featureId, contextContent }: { featureId: string; contextContent: string }) => {
+ const mockProject = {
+ id: "test-project-1",
+ name: "Test Project",
+ path: "/mock/test-project",
+ lastOpened: new Date().toISOString(),
+ };
+
+ const mockState = {
+ state: {
+ projects: [mockProject],
+ currentProject: mockProject,
+ theme: "dark",
+ sidebarOpen: true,
+ apiKeys: { anthropic: "", google: "" },
+ chatSessions: [],
+ chatHistoryOpen: false,
+ maxConcurrency: 3,
+ },
+ version: 0,
+ };
+
+ localStorage.setItem("automaker-storage", JSON.stringify(mockState));
+
+ // Set up mock file system with a context file for the feature
+ // This will be used by the mock electron API
+ (window as any).__mockContextFile = {
+ featureId,
+ path: `/mock/test-project/.automaker/agents-context/${featureId}.md`,
+ content: contextContent,
+ };
+ },
+ { featureId, contextContent }
+ );
+}
+
+/**
+ * Get the category autocomplete input element
+ */
+export async function getCategoryAutocompleteInput(
+ page: Page,
+ testId: string = "feature-category-input"
+): Promise {
+ return page.locator(`[data-testid="${testId}"]`);
+}
+
+/**
+ * Get the category autocomplete dropdown list
+ */
+export async function getCategoryAutocompleteList(page: Page): Promise {
+ return page.locator('[data-testid="category-autocomplete-list"]');
+}
+
+/**
+ * Check if the category autocomplete dropdown is visible
+ */
+export async function isCategoryAutocompleteListVisible(page: Page): Promise {
+ const list = page.locator('[data-testid="category-autocomplete-list"]');
+ return await list.isVisible();
+}
+
+/**
+ * Wait for the category autocomplete dropdown to be visible
+ */
+export async function waitForCategoryAutocompleteList(
+ page: Page,
+ options?: { timeout?: number }
+): Promise {
+ return await waitForElement(page, "category-autocomplete-list", options);
+}
+
+/**
+ * Wait for the category autocomplete dropdown to be hidden
+ */
+export async function waitForCategoryAutocompleteListHidden(
+ page: Page,
+ options?: { timeout?: number }
+): Promise {
+ await waitForElementHidden(page, "category-autocomplete-list", options);
+}
+
+/**
+ * Click a category option in the autocomplete dropdown
+ */
+export async function clickCategoryOption(
+ page: Page,
+ categoryName: string
+): Promise {
+ const optionTestId = `category-option-${categoryName.toLowerCase().replace(/\s+/g, "-")}`;
+ const option = page.locator(`[data-testid="${optionTestId}"]`);
+ await option.click();
+}
+
+/**
+ * Get a category option element by name
+ */
+export async function getCategoryOption(
+ page: Page,
+ categoryName: string
+): Promise {
+ const optionTestId = `category-option-${categoryName.toLowerCase().replace(/\s+/g, "-")}`;
+ return page.locator(`[data-testid="${optionTestId}"]`);
+}
+
+/**
+ * Navigate to the agent view
+ */
+export async function navigateToAgent(page: Page): Promise {
+ await page.goto("/");
+
+ // Wait for the page to load
+ await page.waitForLoadState("networkidle");
+
+ // Click on the Agent nav button
+ const agentNav = page.locator('[data-testid="nav-agent"]');
+ if (await agentNav.isVisible().catch(() => false)) {
+ await agentNav.click();
+ }
+
+ // Wait for the agent view to be visible
+ await waitForElement(page, "agent-view", { timeout: 10000 });
+}
+
+/**
+ * Get the session list element
+ */
+export async function getSessionList(page: Page): Promise {
+ return page.locator('[data-testid="session-list"]');
+}
+
+/**
+ * Get the new session button
+ */
+export async function getNewSessionButton(page: Page): Promise {
+ return page.locator('[data-testid="new-session-button"]');
+}
+
+/**
+ * Click the new session button
+ */
+export async function clickNewSessionButton(page: Page): Promise {
+ const button = await getNewSessionButton(page);
+ await button.click();
+}
+
+/**
+ * Get a session item by its ID
+ */
+export async function getSessionItem(
+ page: Page,
+ sessionId: string
+): Promise {
+ return page.locator(`[data-testid="session-item-${sessionId}"]`);
+}
+
+/**
+ * Click the archive button for a session
+ */
+export async function clickArchiveSession(
+ page: Page,
+ sessionId: string
+): Promise {
+ const button = page.locator(`[data-testid="archive-session-${sessionId}"]`);
+ await button.click();
+}
+
+/**
+ * Check if the no session placeholder is visible
+ */
+export async function isNoSessionPlaceholderVisible(page: Page): Promise {
+ const placeholder = page.locator('[data-testid="no-session-placeholder"]');
+ return await placeholder.isVisible();
+}
+
+/**
+ * Wait for the no session placeholder to be visible
+ */
+export async function waitForNoSessionPlaceholder(
+ page: Page,
+ options?: { timeout?: number }
+): Promise {
+ return await waitForElement(page, "no-session-placeholder", options);
+}
+
+/**
+ * Check if the message list is visible (indicates a session is selected)
+ */
+export async function isMessageListVisible(page: Page): Promise {
+ const messageList = page.locator('[data-testid="message-list"]');
+ return await messageList.isVisible();
+}