mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
fix(wizard): Use configured Auto Run folder path instead of default
The /wizard command now respects the user's configured Auto Run folder path instead of always creating "Auto Run Docs" at the repository root. Fixes #169
This commit is contained in:
@@ -108,7 +108,12 @@ describe('useInlineWizard', () => {
|
||||
describe('startWizard - intent parsing flow', () => {
|
||||
describe('when no input is provided', () => {
|
||||
it('should set mode to "ask" when existing docs exist', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1', 'phase-2'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
@@ -118,11 +123,16 @@ describe('useInlineWizard', () => {
|
||||
|
||||
expect(result.current.isWizardActive).toBe(true);
|
||||
expect(result.current.wizardMode).toBe('ask');
|
||||
expect(mockHasExistingAutoRunDocs).toHaveBeenCalledWith('/test/project');
|
||||
expect(mockListDocs).toHaveBeenCalledWith('/test/project/Auto Run Docs');
|
||||
});
|
||||
|
||||
it('should set mode to "new" when no existing docs', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(false);
|
||||
// Mock listDocs to return empty files (no docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: [],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
@@ -140,15 +150,19 @@ describe('useInlineWizard', () => {
|
||||
await result.current.startWizard();
|
||||
});
|
||||
|
||||
// Without a project path, hasExistingDocs defaults to false → new mode
|
||||
// Without a project path, effectiveAutoRunFolderPath is null → no docs check → new mode
|
||||
expect(result.current.wizardMode).toBe('new');
|
||||
expect(mockHasExistingAutoRunDocs).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when input is provided', () => {
|
||||
it('should call parseWizardIntent with input and hasExistingDocs', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1', 'phase-2'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'iterate', goal: 'add auth' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -163,7 +177,12 @@ describe('useInlineWizard', () => {
|
||||
});
|
||||
|
||||
it('should handle new mode from intent parser', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'new' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -177,7 +196,12 @@ describe('useInlineWizard', () => {
|
||||
});
|
||||
|
||||
it('should handle ask mode from intent parser', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'ask' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -204,12 +228,12 @@ describe('useInlineWizard', () => {
|
||||
|
||||
describe('loading existing docs for iterate mode', () => {
|
||||
it('should load existing docs when mode is iterate', async () => {
|
||||
const mockDocs = [
|
||||
{ name: 'phase-1', filename: 'phase-1.md', path: '/test/Auto Run Docs/phase-1.md' },
|
||||
{ name: 'phase-2', filename: 'phase-2.md', path: '/test/Auto Run Docs/phase-2.md' },
|
||||
];
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
mockGetExistingAutoRunDocs.mockResolvedValue(mockDocs);
|
||||
// Mock listDocs to return files
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1', 'phase-2'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'iterate', goal: 'add feature' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -218,12 +242,19 @@ describe('useInlineWizard', () => {
|
||||
await result.current.startWizard('add new feature', undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(mockGetExistingAutoRunDocs).toHaveBeenCalledWith('/test/project');
|
||||
expect(result.current.existingDocuments).toEqual(mockDocs);
|
||||
// The new implementation constructs existingDocs from listDocs result
|
||||
expect(result.current.existingDocuments).toHaveLength(2);
|
||||
expect(result.current.existingDocuments[0].name).toBe('phase-1');
|
||||
expect(result.current.existingDocuments[1].name).toBe('phase-2');
|
||||
});
|
||||
|
||||
it('should not load existing docs when mode is new', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'new' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -232,12 +263,17 @@ describe('useInlineWizard', () => {
|
||||
await result.current.startWizard('start fresh', undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(mockGetExistingAutoRunDocs).not.toHaveBeenCalled();
|
||||
// existingDocuments should be empty for new mode (docs only loaded for iterate)
|
||||
expect(result.current.existingDocuments).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not load existing docs when mode is ask', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
// Mock listDocs to return files (existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'ask' });
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
@@ -246,13 +282,19 @@ describe('useInlineWizard', () => {
|
||||
await result.current.startWizard('do something', undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(mockGetExistingAutoRunDocs).not.toHaveBeenCalled();
|
||||
// existingDocuments should be empty for ask mode
|
||||
expect(result.current.existingDocuments).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInitializing state', () => {
|
||||
it('should set isInitializing to false after async operations complete', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(false);
|
||||
// Mock listDocs to return empty (no existing docs)
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: [],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
@@ -267,27 +309,34 @@ describe('useInlineWizard', () => {
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should handle errors from hasExistingAutoRunDocs', async () => {
|
||||
mockHasExistingAutoRunDocs.mockRejectedValue(new Error('Failed to check docs'));
|
||||
it('should silently handle listDocs errors and default to new mode', async () => {
|
||||
// When listDocs fails, we treat it as no existing docs (folder doesn't exist)
|
||||
const mockListDocs = vi.fn().mockRejectedValue(new Error('Folder not found'));
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startWizard('test', undefined, '/test/project');
|
||||
await result.current.startWizard(undefined, undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Failed to check docs');
|
||||
expect(result.current.wizardMode).toBe('new'); // Fallback to new mode
|
||||
// Error should NOT be set - we silently catch listDocs errors
|
||||
expect(result.current.error).toBe(null);
|
||||
expect(result.current.wizardMode).toBe('new'); // Default to new when can't check docs
|
||||
expect(result.current.isInitializing).toBe(false);
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should handle errors from getExistingAutoRunDocs', async () => {
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(true);
|
||||
it('should handle errors from loadDocumentContents in iterate mode', async () => {
|
||||
// Setup: listDocs returns files, but loading content fails
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1', 'phase-2'],
|
||||
});
|
||||
const mockReadDoc = vi.fn().mockRejectedValue(new Error('Failed to read file'));
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
window.maestro.autorun.readDoc = mockReadDoc;
|
||||
|
||||
mockParseWizardIntent.mockReturnValue({ mode: 'iterate', goal: 'add feature' });
|
||||
mockGetExistingAutoRunDocs.mockRejectedValue(new Error('Failed to load docs'));
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
@@ -296,26 +345,29 @@ describe('useInlineWizard', () => {
|
||||
await result.current.startWizard('add feature', undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Failed to load docs');
|
||||
expect(result.current.wizardMode).toBe('new'); // Fallback to new mode
|
||||
// readDoc failure causes loadDocumentContents to fail
|
||||
// This should set an error since it's a real loading failure
|
||||
expect(result.current.isInitializing).toBe(false);
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should handle non-Error exceptions', async () => {
|
||||
mockHasExistingAutoRunDocs.mockRejectedValue('String error');
|
||||
it('should treat empty listDocs response as no docs', async () => {
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: [],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startWizard('test', undefined, '/test/project');
|
||||
await result.current.startWizard(undefined, undefined, '/test/project');
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Failed to initialize wizard');
|
||||
|
||||
consoleSpy.mockRestore();
|
||||
// Empty files means no existing docs → new mode
|
||||
expect(result.current.error).toBe(null);
|
||||
expect(result.current.wizardMode).toBe('new');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -361,6 +413,76 @@ describe('useInlineWizard', () => {
|
||||
expect(result.current.state.projectPath).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('autoRunFolderPath parameter', () => {
|
||||
it('should use configured autoRunFolderPath when provided', async () => {
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startWizard(
|
||||
'test',
|
||||
undefined,
|
||||
'/my/project',
|
||||
'claude-code',
|
||||
'Test Project',
|
||||
'tab-1',
|
||||
'session-1',
|
||||
'/custom/auto-run/folder' // User-configured Auto Run folder
|
||||
);
|
||||
});
|
||||
|
||||
expect(result.current.state.autoRunFolderPath).toBe('/custom/auto-run/folder');
|
||||
});
|
||||
|
||||
it('should fall back to default path when autoRunFolderPath not provided', async () => {
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startWizard(
|
||||
'test',
|
||||
undefined,
|
||||
'/my/project',
|
||||
'claude-code',
|
||||
'Test Project',
|
||||
'tab-1',
|
||||
'session-1'
|
||||
// No autoRunFolderPath provided
|
||||
);
|
||||
});
|
||||
|
||||
// Should fall back to projectPath/Auto Run Docs
|
||||
expect(result.current.state.autoRunFolderPath).toBe('/my/project/Auto Run Docs');
|
||||
});
|
||||
|
||||
it('should check for existing docs in configured folder', async () => {
|
||||
// Mock the direct listDocs call
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: ['phase-1', 'phase-2'],
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
await act(async () => {
|
||||
await result.current.startWizard(
|
||||
undefined, // No input, so it checks for existing docs
|
||||
undefined,
|
||||
'/my/project',
|
||||
'claude-code',
|
||||
'Test Project',
|
||||
'tab-1',
|
||||
'session-1',
|
||||
'/custom/auto-run/folder'
|
||||
);
|
||||
});
|
||||
|
||||
// Should check the configured folder, not the default
|
||||
expect(mockListDocs).toHaveBeenCalledWith('/custom/auto-run/folder');
|
||||
// Should be 'ask' mode since docs exist
|
||||
expect(result.current.wizardMode).toBe('ask');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('endWizard', () => {
|
||||
@@ -563,8 +685,12 @@ describe('useInlineWizard', () => {
|
||||
const mockStartConversation = vi.mocked(startInlineWizardConversation);
|
||||
mockStartConversation.mockClear();
|
||||
|
||||
// Setup: no existing docs, so we get 'new' mode directly
|
||||
mockHasExistingAutoRunDocs.mockResolvedValue(false);
|
||||
// Setup: no existing docs via listDocs, so we get 'new' mode directly
|
||||
const mockListDocs = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
files: [], // Empty = no existing docs
|
||||
});
|
||||
window.maestro.autorun.listDocs = mockListDocs;
|
||||
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
@@ -712,15 +838,15 @@ describe('useInlineWizard', () => {
|
||||
});
|
||||
|
||||
describe('generateDocuments', () => {
|
||||
it('should return error when agent type is missing', async () => {
|
||||
it('should return error when agent type or Auto Run folder path is missing', async () => {
|
||||
const { result } = renderHook(() => useInlineWizard());
|
||||
|
||||
// Don't start wizard (no agentType or projectPath)
|
||||
// Don't start wizard (no agentType or autoRunFolderPath)
|
||||
await act(async () => {
|
||||
await result.current.generateDocuments();
|
||||
});
|
||||
|
||||
expect(result.current.error).toBe('Cannot generate documents: missing agent type or project path');
|
||||
expect(result.current.error).toBe('Cannot generate documents: missing agent type or Auto Run folder path');
|
||||
expect(result.current.isGeneratingDocs).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -3648,7 +3648,7 @@ You are taking over this conversation. Based on the context above, provide a bri
|
||||
addToast({
|
||||
type: 'warning',
|
||||
title: 'Cannot Compact',
|
||||
message: `Context too small. Need at least ${minContextUsagePercent}% usage or ~10k tokens to compact.`,
|
||||
message: `Context too small. Need at least ${minContextUsagePercent}% usage, ~2k tokens, or 8+ messages to compact.`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -4960,7 +4960,8 @@ You are taking over this conversation. Based on the context above, provide a bri
|
||||
activeSession.toolType, // Agent type for AI conversation
|
||||
activeSession.name, // Session/project name
|
||||
activeTab.id, // Tab ID for per-tab isolation
|
||||
activeSession.id // Session ID for playbook creation
|
||||
activeSession.id, // Session ID for playbook creation
|
||||
activeSession.autoRunFolderPath // User-configured Auto Run folder path (if set)
|
||||
);
|
||||
|
||||
// Rename the tab to "Wizard" immediately when wizard starts
|
||||
@@ -5037,7 +5038,8 @@ You are taking over this conversation. Based on the context above, provide a bri
|
||||
activeSession.toolType,
|
||||
activeSession.name,
|
||||
newTab.id,
|
||||
activeSession.id
|
||||
activeSession.id,
|
||||
activeSession.autoRunFolderPath // User-configured Auto Run folder path (if set)
|
||||
);
|
||||
|
||||
// Show a system log entry
|
||||
|
||||
@@ -141,6 +141,8 @@ export interface InlineWizardState {
|
||||
subfolderName: string | null;
|
||||
/** Full path to the subfolder where documents are saved (e.g., "/path/Auto Run Docs/Maestro-Marketing") */
|
||||
subfolderPath: string | null;
|
||||
/** User-configured Auto Run folder path (overrides default projectPath/Auto Run Docs) */
|
||||
autoRunFolderPath: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,6 +198,7 @@ export interface UseInlineWizardReturn {
|
||||
* @param sessionName - The session name (used as project name)
|
||||
* @param tabId - The tab ID to associate the wizard with
|
||||
* @param sessionId - The session ID for playbook creation
|
||||
* @param autoRunFolderPath - User-configured Auto Run folder path (if set, overrides default projectPath/Auto Run Docs)
|
||||
*/
|
||||
startWizard: (
|
||||
naturalLanguageInput?: string,
|
||||
@@ -204,7 +207,8 @@ export interface UseInlineWizardReturn {
|
||||
agentType?: ToolType,
|
||||
sessionName?: string,
|
||||
tabId?: string,
|
||||
sessionId?: string
|
||||
sessionId?: string,
|
||||
autoRunFolderPath?: string
|
||||
) => Promise<void>;
|
||||
/** End the wizard and restore previous UI state */
|
||||
endWizard: () => Promise<PreviousUIState | null>;
|
||||
@@ -291,6 +295,7 @@ const initialState: InlineWizardState = {
|
||||
agentSessionId: null,
|
||||
subfolderName: null,
|
||||
subfolderPath: null,
|
||||
autoRunFolderPath: null,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -444,15 +449,28 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
agentType?: ToolType,
|
||||
sessionName?: string,
|
||||
tabId?: string,
|
||||
sessionId?: string
|
||||
sessionId?: string,
|
||||
configuredAutoRunFolderPath?: string
|
||||
): Promise<void> => {
|
||||
// Tab ID is required for per-tab wizard management
|
||||
const effectiveTabId = tabId || 'default';
|
||||
|
||||
// Determine the Auto Run folder path to use:
|
||||
// 1. If user has configured a specific path (configuredAutoRunFolderPath), use it
|
||||
// 2. Otherwise, fall back to the default: projectPath/Auto Run Docs
|
||||
const effectiveAutoRunFolderPath = configuredAutoRunFolderPath ||
|
||||
(projectPath ? getAutoRunFolderPath(projectPath) : null);
|
||||
|
||||
logger.info(
|
||||
`Starting inline wizard on tab ${effectiveTabId}`,
|
||||
'[InlineWizard]',
|
||||
{ projectPath, agentType, sessionName, hasInput: !!naturalLanguageInput }
|
||||
{
|
||||
projectPath,
|
||||
agentType,
|
||||
sessionName,
|
||||
hasInput: !!naturalLanguageInput,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
}
|
||||
);
|
||||
|
||||
// Store current UI state for later restoration (per-tab)
|
||||
@@ -491,13 +509,22 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
agentSessionId: null,
|
||||
subfolderName: null,
|
||||
subfolderPath: null,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
}));
|
||||
|
||||
try {
|
||||
// Step 1: Check for existing Auto Run documents
|
||||
const hasExistingDocs = projectPath
|
||||
? await hasExistingAutoRunDocs(projectPath)
|
||||
: false;
|
||||
// Step 1: Check for existing Auto Run documents in the configured folder
|
||||
// Use the effective Auto Run folder path (user-configured or default)
|
||||
let hasExistingDocs = false;
|
||||
if (effectiveAutoRunFolderPath) {
|
||||
try {
|
||||
const result = await window.maestro.autorun.listDocs(effectiveAutoRunFolderPath);
|
||||
hasExistingDocs = result.success && result.files && result.files.length > 0;
|
||||
} catch {
|
||||
// Folder doesn't exist or can't be read - no existing docs
|
||||
hasExistingDocs = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Determine mode based on input and existing docs
|
||||
let mode: InlineWizardMode;
|
||||
@@ -524,23 +551,33 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
|
||||
// Step 3: If iterate mode, load existing docs with content for context
|
||||
let docsWithContent: ExistingDocumentWithContent[] = [];
|
||||
if (mode === 'iterate' && projectPath) {
|
||||
existingDocs = await getExistingAutoRunDocs(projectPath);
|
||||
const autoRunFolderPath = getAutoRunFolderPath(projectPath);
|
||||
docsWithContent = await loadDocumentContents(existingDocs, autoRunFolderPath);
|
||||
if (mode === 'iterate' && effectiveAutoRunFolderPath) {
|
||||
// List docs from the configured Auto Run folder
|
||||
try {
|
||||
const result = await window.maestro.autorun.listDocs(effectiveAutoRunFolderPath);
|
||||
if (result.success && result.files) {
|
||||
existingDocs = result.files.map((name: string) => ({
|
||||
name,
|
||||
filename: `${name}.md`,
|
||||
path: `${effectiveAutoRunFolderPath}/${name}.md`,
|
||||
}));
|
||||
}
|
||||
} catch {
|
||||
existingDocs = [];
|
||||
}
|
||||
docsWithContent = await loadDocumentContents(existingDocs, effectiveAutoRunFolderPath);
|
||||
}
|
||||
|
||||
// Step 4: Initialize conversation session (only for 'new' or 'iterate' modes)
|
||||
if ((mode === 'new' || mode === 'iterate') && agentType && projectPath) {
|
||||
const autoRunFolderPath = getAutoRunFolderPath(projectPath);
|
||||
if ((mode === 'new' || mode === 'iterate') && agentType && effectiveAutoRunFolderPath) {
|
||||
const session = startInlineWizardConversation({
|
||||
mode,
|
||||
agentType,
|
||||
directoryPath: projectPath,
|
||||
directoryPath: projectPath || effectiveAutoRunFolderPath,
|
||||
projectName: sessionName || 'Project',
|
||||
goal: goal || undefined,
|
||||
existingDocs: docsWithContent.length > 0 ? docsWithContent : undefined,
|
||||
autoRunFolderPath,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
});
|
||||
|
||||
// Store conversation session per-tab
|
||||
@@ -555,6 +592,7 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
mode,
|
||||
goal: goal || null,
|
||||
existingDocsCount: docsWithContent.length,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -661,17 +699,20 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
// If we're in 'ask' mode and don't have a session, auto-create one with 'new' mode
|
||||
// This happens when user types directly instead of using the mode selection modal
|
||||
const currentState = tabStatesRef.current.get(tabId);
|
||||
if (currentState?.mode === 'ask' && currentState.agentType && currentState.projectPath) {
|
||||
// Use stored autoRunFolderPath from state (configured by user or default)
|
||||
const effectiveAutoRunFolderPath = currentState?.autoRunFolderPath ||
|
||||
(currentState?.projectPath ? getAutoRunFolderPath(currentState.projectPath) : null);
|
||||
|
||||
if (currentState?.mode === 'ask' && currentState.agentType && effectiveAutoRunFolderPath) {
|
||||
console.log('[useInlineWizard] Auto-creating session for direct message in ask mode');
|
||||
const autoRunFolderPath = getAutoRunFolderPath(currentState.projectPath);
|
||||
session = startInlineWizardConversation({
|
||||
mode: 'new',
|
||||
agentType: currentState.agentType,
|
||||
directoryPath: currentState.projectPath,
|
||||
directoryPath: currentState.projectPath || effectiveAutoRunFolderPath,
|
||||
projectName: currentState.sessionName || 'Project',
|
||||
goal: currentState.goal || undefined,
|
||||
existingDocs: undefined,
|
||||
autoRunFolderPath,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
});
|
||||
conversationSessionsMap.current.set(tabId, session);
|
||||
// Update mode to 'new' since we're proceeding with a new plan
|
||||
@@ -682,6 +723,7 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
mode: currentState?.mode,
|
||||
agentType: currentState?.agentType,
|
||||
projectPath: currentState?.projectPath,
|
||||
autoRunFolderPath: currentState?.autoRunFolderPath,
|
||||
});
|
||||
setTabState(tabId, (prev) => ({
|
||||
...prev,
|
||||
@@ -835,16 +877,19 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
// If transitioning from 'ask' to 'new' or 'iterate', we need to create the conversation session
|
||||
if (currentState?.mode === 'ask' && (newMode === 'new' || newMode === 'iterate') && !conversationSessionsMap.current.has(tabId)) {
|
||||
// Create conversation session if we have the required info
|
||||
if (currentState.agentType && currentState.projectPath) {
|
||||
const autoRunFolderPath = getAutoRunFolderPath(currentState.projectPath);
|
||||
// Use the stored autoRunFolderPath from state (configured by user or default)
|
||||
const effectiveAutoRunFolderPath = currentState.autoRunFolderPath ||
|
||||
(currentState.projectPath ? getAutoRunFolderPath(currentState.projectPath) : null);
|
||||
|
||||
if (currentState.agentType && effectiveAutoRunFolderPath) {
|
||||
const session = startInlineWizardConversation({
|
||||
mode: newMode,
|
||||
agentType: currentState.agentType,
|
||||
directoryPath: currentState.projectPath,
|
||||
directoryPath: currentState.projectPath || effectiveAutoRunFolderPath,
|
||||
projectName: currentState.sessionName || 'Project',
|
||||
goal: currentState.goal || undefined,
|
||||
existingDocs: undefined, // Will be loaded separately if needed
|
||||
autoRunFolderPath,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
});
|
||||
|
||||
conversationSessionsMap.current.set(tabId, session);
|
||||
@@ -1045,9 +1090,13 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
setCurrentTabId(tabId);
|
||||
}
|
||||
|
||||
// Get the effective Auto Run folder path (stored in state from startWizard)
|
||||
const effectiveAutoRunFolderPath = currentState?.autoRunFolderPath ||
|
||||
(currentState?.projectPath ? getAutoRunFolderPath(currentState.projectPath) : null);
|
||||
|
||||
// Validate we have the required state
|
||||
if (!currentState?.agentType || !currentState?.projectPath) {
|
||||
const errorMsg = 'Cannot generate documents: missing agent type or project path';
|
||||
if (!currentState?.agentType || !effectiveAutoRunFolderPath) {
|
||||
const errorMsg = 'Cannot generate documents: missing agent type or Auto Run folder path';
|
||||
console.error('[useInlineWizard]', errorMsg);
|
||||
setTabState(tabId, (prev) => ({ ...prev, error: errorMsg }));
|
||||
callbacks?.onError?.(errorMsg);
|
||||
@@ -1066,19 +1115,16 @@ export function useInlineWizard(): UseInlineWizardReturn {
|
||||
}));
|
||||
|
||||
try {
|
||||
// Get the Auto Run folder path
|
||||
const autoRunFolderPath = getAutoRunFolderPath(currentState.projectPath);
|
||||
|
||||
// Call the document generation service
|
||||
// Call the document generation service with the effective Auto Run folder path
|
||||
const result = await generateInlineDocuments({
|
||||
agentType: currentState.agentType,
|
||||
directoryPath: currentState.projectPath,
|
||||
directoryPath: currentState.projectPath || effectiveAutoRunFolderPath,
|
||||
projectName: currentState.sessionName || 'Project',
|
||||
conversationHistory: currentState.conversationHistory,
|
||||
existingDocuments: currentState.existingDocuments,
|
||||
mode: currentState.mode === 'iterate' ? 'iterate' : 'new',
|
||||
goal: currentState.goal || undefined,
|
||||
autoRunFolderPath,
|
||||
autoRunFolderPath: effectiveAutoRunFolderPath,
|
||||
sessionId: currentState.sessionId || undefined,
|
||||
callbacks: {
|
||||
onStart: () => {
|
||||
|
||||
Reference in New Issue
Block a user