Edit

export type GitWSMessage =
  | GitStatusWSMessage
  | GitErrorWSMessage
  | GitPongWSMessage

export type GitWSMessage =
  | GitStatusWSMessage
  | GitErrorWSMessage
  | GitPongWSMessage

// ============================================================================
// Reference Folder Types
// ============================================================================

export interface ReferenceFolder {
  id: number
  path: string
  alias: string | null
  description: string | null
  created_at: string | null
  exists: boolean
}

export interface ReferenceFolderCreate {
  path: string
  alias?: string
  description?: string
}

export interface ReferenceFolderUpdate {
  alias?: string
  description?: string
}


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\ui\src\lib\types.ts has been updated successfully.

export type GitWSMessage =
  | GitStatusWSMessage
  | GitErrorWSMessage
  | GitPongWSMessage

// ============================================================================
// Reference Folder Types
// ============================================================================

export interface ReferenceFolder {
  id: number
  path: string
  alias: string | null
  description: string | null
  created_at: string | null
  exists: boolean
}

export interface ReferenceFolderCreate {
  path: string
  alias?: string
  description?: string
}

export interface ReferenceFolderUpdate {
  alias?: string
  description?: string
}

/**
 * TypeScript types for the Autonomous Coding UI
 */

// Project types
export interface ProjectStats {
  passing: number
  in_progress: number
  total: number
  percentage: number
}

export interface ProjectSummary {
  name: string
  path: string
  has_spec: boolean
  stats: ProjectStats
}

export interface ProjectDetail extends ProjectSummary {
  prompts_dir: string
}

// Filesystem types
export interface DriveInfo {
  letter: string
  label: string
  available?: boolean
}

export interface DirectoryEntry {
  name: string
  path: string
  is_directory: boolean
  has_children: boolean
}

export interface DirectoryListResponse {
  current_path: string
  parent_path: string | null
  entries: DirectoryEntry[]
  drives: DriveInfo[] | null
}

export interface PathValidationResponse {
  valid: boolean
  exists: boolean
  is_directory: boolean
  can_write: boolean
  message: string
}

export interface ProjectPrompts {
  app_spec: string
  initializer_prompt: string
  coding_prompt: string
}

// Feature types
export interface Feature {
  id: number
  priority: number
  category: string
  name: string
  description: string
  steps: string[]
  passes: boolean
  in_progress: boolean
}

export interface FeatureListResponse {
  pending: Feature[]
  in_progress: Feature[]
  done: Feature[]
}

export interface FeatureCreate {
  category: string
  name: string
  description: string
  steps: string[]
  priority?: number
}

// Agent types
export type AgentStatus = 'stopped' | 'running' | 'paused' | 'crashed'

export interface AgentStatusResponse {
  status: AgentStatus
  pid: number | null
  started_at: string | null
  yolo_mode: boolean
}

export interface AgentActionResponse {
  success: boolean
  status: AgentStatus
  message: string
}

// Setup types
export interface SetupStatus {
  claude_cli: boolean
  credentials: boolean
  node: boolean
  npm: boolean
}

// WebSocket message types
export type WSMessageType = 'progress' | 'feature_update' | 'log' | 'agent_status' | 'pong'

export interface WSProgressMessage {
  type: 'progress'
  passing: number
  in_progress: number
  total: number
  percentage: number
}

export interface WSFeatureUpdateMessage {
  type: 'feature_update'
  feature_id: number
  passes: boolean
}

export interface WSLogMessage {
  type: 'log'
  line: string
  timestamp: string
}

export interface WSAgentStatusMessage {
  type: 'agent_status'
  status: AgentStatus
}

export interface WSPongMessage {
  type: 'pong'
}

export type WSMessage =
  | WSProgressMessage
  | WSFeatureUpdateMessage
  | WSLogMessage
  | WSAgentStatusMessage
  | WSPongMessage

// ============================================================================
// Spec Chat Types
// ============================================================================

export interface SpecQuestionOption {
  label: string
  description: string
}

export interface SpecQuestion {
  question: string
  header: string
  options: SpecQuestionOption[]
  multiSelect: boolean
}

export interface SpecChatTextMessage {
  type: 'text'
  content: string
}

export interface SpecChatQuestionMessage {
  type: 'question'
  questions: SpecQuestion[]
  tool_id?: string
}

export interface SpecChatCompleteMessage {
  type: 'spec_complete'
  path: string
}

export interface SpecChatFileWrittenMessage {
  type: 'file_written'
  path: string
}

export interface SpecChatSessionCompleteMessage {
  type: 'complete'
}

export interface SpecChatErrorMessage {
  type: 'error'
  content: string
}

export interface SpecChatPongMessage {
  type: 'pong'
}

export interface SpecChatResponseDoneMessage {
  type: 'response_done'
}

export type SpecChatServerMessage =
  | SpecChatTextMessage
  | SpecChatQuestionMessage
  | SpecChatCompleteMessage
  | SpecChatFileWrittenMessage
  | SpecChatSessionCompleteMessage
  | SpecChatErrorMessage
  | SpecChatPongMessage
  | SpecChatResponseDoneMessage

// Image attachment for chat messages
export interface ImageAttachment {
  id: string
  filename: string
  mimeType: 'image/jpeg' | 'image/png'
  base64Data: string    // Raw base64 (without data: prefix)
  previewUrl: string    // data: URL for display
  size: number          // File size in bytes
}

// UI chat message for display
export interface ChatMessage {
  id: string
  role: 'user' | 'assistant' | 'system'
  content: string
  attachments?: ImageAttachment[]
  timestamp: Date
  questions?: SpecQuestion[]
  isStreaming?: boolean
}

// ============================================================================
// Assistant Chat Types
// ============================================================================

export interface AssistantConversation {
  id: number
  project_name: string
  title: string | null
  created_at: string | null
  updated_at: string | null
  message_count: number
}

export interface AssistantMessage {
  id: number
  role: 'user' | 'assistant' | 'system'
  content: string
  timestamp: string | null
}

export interface AssistantConversationDetail {
  id: number
  project_name: string
  title: string | null
  created_at: string | null
  updated_at: string | null
  messages: AssistantMessage[]
}

export interface AssistantChatTextMessage {
  type: 'text'
  content: string
}

export interface AssistantChatToolCallMessage {
  type: 'tool_call'
  tool: string
  input: Record<string, unknown>
}

export interface AssistantChatResponseDoneMessage {
  type: 'response_done'
}

export interface AssistantChatErrorMessage {
  type: 'error'
  content: string
}

export interface AssistantChatConversationCreatedMessage {
  type: 'conversation_created'
  conversation_id: number
}

export interface AssistantChatPongMessage {
  type: 'pong'
}

export type AssistantChatServerMessage =
  | AssistantChatTextMessage
  | AssistantChatToolCallMessage
  | AssistantChatResponseDoneMessage
  | AssistantChatErrorMessage
  | AssistantChatConversationCreatedMessage
  | AssistantChatPongMessage

// ============================================================================
// Git Types
// ============================================================================

export interface GitStatus {
  branch: string
  ahead: number
  behind: number
  staged: string[]
  unstaged: string[]
  untracked: string[]
  has_conflicts: boolean
  is_clean: boolean
  remote?: string
  last_commit_hash?: string
  last_commit_message?: string
  last_commit_time?: string
}

export interface GitCommit {
  hash: string
  short_hash: string
  message: string
  author: string
  date: string
}

export interface GitResult {
  success: boolean
  output: string
  error?: string
  commit_hash?: string
}

export interface GitStatusWSMessage {
  type: 'status'
  data: GitStatus
}

export interface GitErrorWSMessage {
  type: 'error'
  content: string
}

export interface GitPongWSMessage {
  type: 'pong'
}

export type GitWSMessage =
  | GitStatusWSMessage
  | GitErrorWSMessage
  | GitPongWSMessage

+export interface ReferenceFolderCreate {

+export interface ReferenceFolderUpdate {


Now let me add the API functions for reference folders.


import type {
  ProjectSummary,
  ProjectDetail,
  ProjectPrompts,
  FeatureListResponse,
  Feature,
  FeatureCreate,
  AgentStatusResponse,
  AgentActionResponse,
  SetupStatus,
  DirectoryListResponse,
  PathValidationResponse,
  AssistantConversation,
  AssistantConversationDetail,
} from './types'

import type {
  ProjectSummary,
  ProjectDetail,
  ProjectPrompts,
  FeatureListResponse,
  Feature,
  FeatureCreate,
  AgentStatusResponse,
  AgentActionResponse,
  SetupStatus,
  DirectoryListResponse,
  PathValidationResponse,
  AssistantConversation,
  AssistantConversationDetail,
  ReferenceFolder,
  ReferenceFolderCreate,
  ReferenceFolderUpdate,
} from './types'


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\ui\src\lib\api.ts has been updated successfully.

import type {
  ProjectSummary,
  ProjectDetail,
  ProjectPrompts,
  FeatureListResponse,
  Feature,
  FeatureCreate,
  AgentStatusResponse,
  AgentActionResponse,
  SetupStatus,
  DirectoryListResponse,
  PathValidationResponse,
  AssistantConversation,
  AssistantConversationDetail,
  ReferenceFolder,
  ReferenceFolderCreate,
  ReferenceFolderUpdate,
} from './types'

/**
 * API Client for the Autonomous Coding UI
 */

import type {
  ProjectSummary,
  ProjectDetail,
  ProjectPrompts,
  FeatureListResponse,
  Feature,
  FeatureCreate,
  AgentStatusResponse,
  AgentActionResponse,
  SetupStatus,
  DirectoryListResponse,
  PathValidationResponse,
  AssistantConversation,
  AssistantConversationDetail,
} from './types'

const API_BASE = '/api'

async function fetchJSON<T>(url: string, options?: RequestInit): Promise<T> {
  const response = await fetch(`${API_BASE}${url}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...options?.headers,
    },
  })

  if (!response.ok) {
    const error = await response.json().catch(() => ({ detail: 'Unknown error' }))
    throw new Error(error.detail || `HTTP ${response.status}`)
  }

  return response.json()
}

// ============================================================================
// Projects API
// ============================================================================

export async function listProjects(): Promise<ProjectSummary[]> {
  return fetchJSON('/projects')
}

export async function createProject(
  name: string,
  path: string,
  specMethod: 'claude' | 'manual' = 'manual'
): Promise<ProjectSummary> {
  return fetchJSON('/projects', {
    method: 'POST',
    body: JSON.stringify({ name, path, spec_method: specMethod }),
  })
}

export async function getProject(name: string): Promise<ProjectDetail> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}`)
}

export interface DeleteProjectResponse {
  success: boolean
  message: string
}

export async function deleteProject(
  name: string,
  deleteFiles: boolean = false
): Promise<DeleteProjectResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}?delete_files=${deleteFiles}`, {
    method: 'DELETE',
  })
}

// Import an existing project (analyzes codebase)
export interface CodebaseAnalysis {
  total_files: number
  file_types: Record<string, number>
  detected_stack: Record<string, string>
  has_claude_md: boolean
  claude_md_content: string | null
  has_readme: boolean
  readme_content: string | null
  directories: string[]
  entry_points: string[]
  project_name: string | null
}

export interface ProjectImportResponse {
  project: ProjectSummary
  analysis: CodebaseAnalysis
  is_import: boolean
}

export async function importProject(
  name: string,
  path: string
): Promise<ProjectImportResponse> {
  return fetchJSON('/projects/import', {
    method: 'POST',
    body: JSON.stringify({ name, path }),
  })
}

export async function getProjectPrompts(name: string): Promise<ProjectPrompts> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}/prompts`)
}

export async function updateProjectPrompts(
  name: string,
  prompts: Partial<ProjectPrompts>
): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(name)}/prompts`, {
    method: 'PUT',
    body: JSON.stringify(prompts),
  })
}

// ============================================================================
// Features API
// ============================================================================

export async function listFeatures(projectName: string): Promise<FeatureListResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features`)
}

export async function createFeature(projectName: string, feature: FeatureCreate): Promise<Feature> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features`, {
    method: 'POST',
    body: JSON.stringify(feature),
  })
}

export async function getFeature(projectName: string, featureId: number): Promise<Feature> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}`)
}

export async function deleteFeature(projectName: string, featureId: number): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}`, {
    method: 'DELETE',
  })
}

export async function skipFeature(projectName: string, featureId: number): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}/skip`, {
    method: 'PATCH',
  })
}

// ============================================================================
// Agent API
// ============================================================================

export async function getAgentStatus(projectName: string): Promise<AgentStatusResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/status`)
}

export async function startAgent(
  projectName: string,
  yoloMode: boolean = false
): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/start`, {
    method: 'POST',
    body: JSON.stringify({ yolo_mode: yoloMode }),
  })
}

export async function stopAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/stop`, {
    method: 'POST',
  })
}

export async function pauseAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/pause`, {
    method: 'POST',
  })
}

export async function resumeAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/resume`, {
    method: 'POST',
  })
}

// ============================================================================
// Spec Creation API
// ============================================================================

export interface SpecFileStatus {
  exists: boolean
  status: 'complete' | 'in_progress' | 'not_started' | 'error' | 'unknown'
  feature_count: number | null
  timestamp: string | null
  files_written: string[]
}

export async function getSpecStatus(projectName: string): Promise<SpecFileStatus> {
  return fetchJSON(`/spec/status/${encodeURIComponent(projectName)}`)
}

// ============================================================================
// Setup API
// ============================================================================

export async function getSetupStatus(): Promise<SetupStatus> {
  return fetchJSON('/setup/status')
}

export async function healthCheck(): Promise<{ status: string }> {
  return fetchJSON('/health')
}

// ============================================================================
// Filesystem API
// ============================================================================

export async function listDirectory(path?: string): Promise<DirectoryListResponse> {
  const params = path ? `?path=${encodeURIComponent(path)}` : ''
  return fetchJSON(`/filesystem/list${params}`)
}

export async function createDirectory(fullPath: string): Promise<{ success: boolean; path: string }> {
  // Backend expects { parent_path, name }, not { path }
  // Split the full path into parent directory and folder name

  // Remove trailing slash if present
  const normalizedPath = fullPath.endsWith('/') ? fullPath.slice(0, -1) : fullPath

  // Find the last path separator
  const lastSlash = normalizedPath.lastIndexOf('/')

  let parentPath: string
  let name: string

  // Handle Windows drive root (e.g., "C:/newfolder")
  if (lastSlash === 2 && /^[A-Za-z]:/.test(normalizedPath)) {
    // Path like "C:/newfolder" - parent is "C:/"
    parentPath = normalizedPath.substring(0, 3) // "C:/"
    name = normalizedPath.substring(3)
  } else if (lastSlash > 0) {
    parentPath = normalizedPath.substring(0, lastSlash)
    name = normalizedPath.substring(lastSlash + 1)
  } else if (lastSlash === 0) {
    // Unix root path like "/newfolder"
    parentPath = '/'
    name = normalizedPath.substring(1)
  } else {
    // No slash - invalid path
    throw new Error('Invalid path: must be an absolute path')
  }

  if (!name) {
    throw new Error('Invalid path: directory name is empty')
  }

  return fetchJSON('/filesystem/create-directory', {
    method: 'POST',
    body: JSON.stringify({ parent_path: parentPath, name }),
  })
}

export async function validatePath(path: string): Promise<PathValidationResponse> {
  return fetchJSON('/filesystem/validate', {
    method: 'POST',
    body: JSON.stringify({ path }),
  })
}

// ============================================================================
// Assistant Chat API
// ============================================================================

export async function listAssistantConversations(
  projectName: string
): Promise<AssistantConversation[]> {
  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`)
}

export async function getAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<AssistantConversationDetail> {
  return fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`
  )
}

export async function createAssistantConversation(
  projectName: string
): Promise<AssistantConversation> {
  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`, {
    method: 'POST',
  })
}

export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}

PathValidationResponse,
AssistantConversation,
AssistantConversationDetail,
+  ReferenceFolder,
+  ReferenceFolderCreate,
+  ReferenceFolderUpdate,
} from './types'
const API_BASE = '/api'


Now add the reference folder API functions at the end of api.ts.


   285→export async function getAssistantConversation(
   286→  projectName: string,
   287→  conversationId: number
   288→): Promise<AssistantConversationDetail> {
   289→  return fetchJSON(
   290→    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`
   291→  )
   292→}
   293→
   294→export async function createAssistantConversation(
   295→  projectName: string
   296→): Promise<AssistantConversation> {
   297→  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`, {
   298→    method: 'POST',
   299→  })
   300→}
   301→
   302→export async function deleteAssistantConversation(
   303→  projectName: string,
   304→  conversationId: number

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

export async function getAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<AssistantConversationDetail> {
  return fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`
  )
}

export async function createAssistantConversation(
  projectName: string
): Promise<AssistantConversation> {
  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`, {
    method: 'POST',
  })
}

export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number


Let me get to the end of the file to add the reference folder functions.


   300→}
   301→
   302→export async function deleteAssistantConversation(
   303→  projectName: string,
   304→  conversationId: number
   305→): Promise<void> {
   306→  await fetchJSON(
   307→    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
   308→    { method: 'DELETE' }
   309→  )
   310→}
   311→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

}

export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}


Good, let me add the reference folder API functions at the end.


export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}

export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}

// ============================================================================
// Reference Folder API
// ============================================================================

export async function listReferences(projectName: string): Promise<ReferenceFolder[]> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`)
}

export async function addReference(
  projectName: string,
  data: ReferenceFolderCreate
): Promise<ReferenceFolder> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`, {
    method: 'POST',
    body: JSON.stringify(data),
  })
}

export async function removeReference(
  projectName: string,
  referenceId: number
): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {
    method: 'DELETE',
  })
}

export async function updateReference(
  projectName: string,
  referenceId: number,
  data: ReferenceFolderUpdate
): Promise<ReferenceFolder> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {
    method: 'PATCH',
    body: JSON.stringify(data),
  })
}


export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}

// ============================================================================
// Reference Folder API
// ============================================================================

export async function listReferences(projectName: string): Promise<ReferenceFolder[]> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`)
}

export async function addReference(
  projectName: string,
  data: ReferenceFolderCreate
): Promise<ReferenceFolder> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`, {
    method: 'POST',
    body: JSON.stringify(data),
  })
}

export async function removeReference(
  projectName: string,
  referenceId: number
): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {
    method: 'DELETE',
  })
}

export async function updateReference(
  projectName: string,
  referenceId: number,
  data: ReferenceFolderUpdate
): Promise<ReferenceFolder> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {
    method: 'PATCH',
    body: JSON.stringify(data),
  })
}

/**
 * API Client for the Autonomous Coding UI
 */

import type {
  ProjectSummary,
  ProjectDetail,
  ProjectPrompts,
  FeatureListResponse,
  Feature,
  FeatureCreate,
  AgentStatusResponse,
  AgentActionResponse,
  SetupStatus,
  DirectoryListResponse,
  PathValidationResponse,
  AssistantConversation,
  AssistantConversationDetail,
  ReferenceFolder,
  ReferenceFolderCreate,
  ReferenceFolderUpdate,
} from './types'

const API_BASE = '/api'

async function fetchJSON<T>(url: string, options?: RequestInit): Promise<T> {
  const response = await fetch(`${API_BASE}${url}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...options?.headers,
    },
  })

  if (!response.ok) {
    const error = await response.json().catch(() => ({ detail: 'Unknown error' }))
    throw new Error(error.detail || `HTTP ${response.status}`)
  }

  return response.json()
}

// ============================================================================
// Projects API
// ============================================================================

export async function listProjects(): Promise<ProjectSummary[]> {
  return fetchJSON('/projects')
}

export async function createProject(
  name: string,
  path: string,
  specMethod: 'claude' | 'manual' = 'manual'
): Promise<ProjectSummary> {
  return fetchJSON('/projects', {
    method: 'POST',
    body: JSON.stringify({ name, path, spec_method: specMethod }),
  })
}

export async function getProject(name: string): Promise<ProjectDetail> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}`)
}

export interface DeleteProjectResponse {
  success: boolean
  message: string
}

export async function deleteProject(
  name: string,
  deleteFiles: boolean = false
): Promise<DeleteProjectResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}?delete_files=${deleteFiles}`, {
    method: 'DELETE',
  })
}

// Import an existing project (analyzes codebase)
export interface CodebaseAnalysis {
  total_files: number
  file_types: Record<string, number>
  detected_stack: Record<string, string>
  has_claude_md: boolean
  claude_md_content: string | null
  has_readme: boolean
  readme_content: string | null
  directories: string[]
  entry_points: string[]
  project_name: string | null
}

export interface ProjectImportResponse {
  project: ProjectSummary
  analysis: CodebaseAnalysis
  is_import: boolean
}

export async function importProject(
  name: string,
  path: string
): Promise<ProjectImportResponse> {
  return fetchJSON('/projects/import', {
    method: 'POST',
    body: JSON.stringify({ name, path }),
  })
}

export async function getProjectPrompts(name: string): Promise<ProjectPrompts> {
  return fetchJSON(`/projects/${encodeURIComponent(name)}/prompts`)
}

export async function updateProjectPrompts(
  name: string,
  prompts: Partial<ProjectPrompts>
): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(name)}/prompts`, {
    method: 'PUT',
    body: JSON.stringify(prompts),
  })
}

// ============================================================================
// Features API
// ============================================================================

export async function listFeatures(projectName: string): Promise<FeatureListResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features`)
}

export async function createFeature(projectName: string, feature: FeatureCreate): Promise<Feature> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features`, {
    method: 'POST',
    body: JSON.stringify(feature),
  })
}

export async function getFeature(projectName: string, featureId: number): Promise<Feature> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}`)
}

export async function deleteFeature(projectName: string, featureId: number): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}`, {
    method: 'DELETE',
  })
}

export async function skipFeature(projectName: string, featureId: number): Promise<void> {
  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/features/${featureId}/skip`, {
    method: 'PATCH',
  })
}

// ============================================================================
// Agent API
// ============================================================================

export async function getAgentStatus(projectName: string): Promise<AgentStatusResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/status`)
}

export async function startAgent(
  projectName: string,
  yoloMode: boolean = false
): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/start`, {
    method: 'POST',
    body: JSON.stringify({ yolo_mode: yoloMode }),
  })
}

export async function stopAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/stop`, {
    method: 'POST',
  })
}

export async function pauseAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/pause`, {
    method: 'POST',
  })
}

export async function resumeAgent(projectName: string): Promise<AgentActionResponse> {
  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/agent/resume`, {
    method: 'POST',
  })
}

// ============================================================================
// Spec Creation API
// ============================================================================

export interface SpecFileStatus {
  exists: boolean
  status: 'complete' | 'in_progress' | 'not_started' | 'error' | 'unknown'
  feature_count: number | null
  timestamp: string | null
  files_written: string[]
}

export async function getSpecStatus(projectName: string): Promise<SpecFileStatus> {
  return fetchJSON(`/spec/status/${encodeURIComponent(projectName)}`)
}

// ============================================================================
// Setup API
// ============================================================================

export async function getSetupStatus(): Promise<SetupStatus> {
  return fetchJSON('/setup/status')
}

export async function healthCheck(): Promise<{ status: string }> {
  return fetchJSON('/health')
}

// ============================================================================
// Filesystem API
// ============================================================================

export async function listDirectory(path?: string): Promise<DirectoryListResponse> {
  const params = path ? `?path=${encodeURIComponent(path)}` : ''
  return fetchJSON(`/filesystem/list${params}`)
}

export async function createDirectory(fullPath: string): Promise<{ success: boolean; path: string }> {
  // Backend expects { parent_path, name }, not { path }
  // Split the full path into parent directory and folder name

  // Remove trailing slash if present
  const normalizedPath = fullPath.endsWith('/') ? fullPath.slice(0, -1) : fullPath

  // Find the last path separator
  const lastSlash = normalizedPath.lastIndexOf('/')

  let parentPath: string
  let name: string

  // Handle Windows drive root (e.g., "C:/newfolder")
  if (lastSlash === 2 && /^[A-Za-z]:/.test(normalizedPath)) {
    // Path like "C:/newfolder" - parent is "C:/"
    parentPath = normalizedPath.substring(0, 3) // "C:/"
    name = normalizedPath.substring(3)
  } else if (lastSlash > 0) {
    parentPath = normalizedPath.substring(0, lastSlash)
    name = normalizedPath.substring(lastSlash + 1)
  } else if (lastSlash === 0) {
    // Unix root path like "/newfolder"
    parentPath = '/'
    name = normalizedPath.substring(1)
  } else {
    // No slash - invalid path
    throw new Error('Invalid path: must be an absolute path')
  }

  if (!name) {
    throw new Error('Invalid path: directory name is empty')
  }

  return fetchJSON('/filesystem/create-directory', {
    method: 'POST',
    body: JSON.stringify({ parent_path: parentPath, name }),
  })
}

export async function validatePath(path: string): Promise<PathValidationResponse> {
  return fetchJSON('/filesystem/validate', {
    method: 'POST',
    body: JSON.stringify({ path }),
  })
}

// ============================================================================
// Assistant Chat API
// ============================================================================

export async function listAssistantConversations(
  projectName: string
): Promise<AssistantConversation[]> {
  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`)
}

export async function getAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<AssistantConversationDetail> {
  return fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`
  )
}

export async function createAssistantConversation(
  projectName: string
): Promise<AssistantConversation> {
  return fetchJSON(`/assistant/conversations/${encodeURIComponent(projectName)}`, {
    method: 'POST',
  })
}

export async function deleteAssistantConversation(
  projectName: string,
  conversationId: number
): Promise<void> {
  await fetchJSON(
    `/assistant/conversations/${encodeURIComponent(projectName)}/${conversationId}`,
    { method: 'DELETE' }
  )
}

+export async function listReferences(projectName: string): Promise<ReferenceFolder[]> {

+  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`)

+  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references`, {

+  await fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {

+  return fetchJSON(`/projects/${encodeURIComponent(projectName)}/references/${referenceId}`, {


Now let me add the React hooks for reference folders.


import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate } from '../lib/types'

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate, ReferenceFolderCreate, ReferenceFolderUpdate } from '../lib/types'


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\ui\src\hooks\useProjects.ts has been updated successfully.

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate, ReferenceFolderCreate, ReferenceFolderUpdate } from '../lib/types'

/**
 * React Query hooks for project data
 */

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate } from '../lib/types'

// ============================================================================
// Projects
// ============================================================================

export function useProjects() {
  return useQuery({
    queryKey: ['projects'],
    queryFn: api.listProjects,
  })
}

export function useProject(name: string | null) {
  return useQuery({
    queryKey: ['project', name],
    queryFn: () => api.getProject(name!),
    enabled: !!name,
  })
}

export function useCreateProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, path, specMethod }: { name: string; path: string; specMethod?: 'claude' | 'manual' }) =>
      api.createProject(name, path, specMethod),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

export function useDeleteProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, deleteFiles = false }: { name: string; deleteFiles?: boolean }) =>
      api.deleteProject(name, deleteFiles),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

export function useImportProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, path }: { name: string; path: string }) =>
      api.importProject(name, path),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

// ============================================================================
// Features
// ============================================================================

export function useFeatures(projectName: string | null) {
  return useQuery({
    queryKey: ['features', projectName],
    queryFn: () => api.listFeatures(projectName!),
    enabled: !!projectName,
    refetchInterval: 5000, // Refetch every 5 seconds for real-time updates
  })
}

export function useCreateFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (feature: FeatureCreate) => api.createFeature(projectName, feature),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

export function useDeleteFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (featureId: number) => api.deleteFeature(projectName, featureId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

export function useSkipFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (featureId: number) => api.skipFeature(projectName, featureId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

// ============================================================================
// Agent
// ============================================================================

export function useAgentStatus(projectName: string | null) {
  return useQuery({
    queryKey: ['agent-status', projectName],
    queryFn: () => api.getAgentStatus(projectName!),
    enabled: !!projectName,
    refetchInterval: 3000, // Poll every 3 seconds
  })
}

export function useStartAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (yoloMode: boolean = false) => api.startAgent(projectName, yoloMode),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function useStopAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.stopAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function usePauseAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.pauseAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function useResumeAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.resumeAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

// ============================================================================
// Setup
// ============================================================================

export function useSetupStatus() {
  return useQuery({
    queryKey: ['setup-status'],
    queryFn: api.getSetupStatus,
    staleTime: 60000, // Cache for 1 minute
  })
}

export function useHealthCheck() {
  return useQuery({
    queryKey: ['health'],
    queryFn: api.healthCheck,
    retry: false,
  })
}

// ============================================================================
// Filesystem
// ============================================================================

export function useListDirectory(path?: string) {
  return useQuery({
    queryKey: ['filesystem', 'list', path],
    queryFn: () => api.listDirectory(path),
  })
}

export function useCreateDirectory() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (path: string) => api.createDirectory(path),
    onSuccess: (_, path) => {
      // Invalidate parent directory listing
      const parentPath = path.split('/').slice(0, -1).join('/') || undefined
      queryClient.invalidateQueries({ queryKey: ['filesystem', 'list', parentPath] })
    },
  })
}

export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}

-import type { FeatureCreate } from '../lib/types'

+import type { FeatureCreate, ReferenceFolderCreate, ReferenceFolderUpdate } from '../lib/types'


Now let me add the reference folder hooks at the end of useProjects.ts.


   200→
   201→  return useMutation({
   202→    mutationFn: (path: string) => api.createDirectory(path),
   203→    onSuccess: (_, path) => {
   204→      // Invalidate parent directory listing
   205→      const parentPath = path.split('/').slice(0, -1).join('/') || undefined
   206→      queryClient.invalidateQueries({ queryKey: ['filesystem', 'list', parentPath] })
   207→    },
   208→  })
   209→}
   210→
   211→export function useValidatePath() {
   212→  return useMutation({
   213→    mutationFn: (path: string) => api.validatePath(path),
   214→  })
   215→}
   216→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

  return useMutation({
    mutationFn: (path: string) => api.createDirectory(path),
    onSuccess: (_, path) => {
      // Invalidate parent directory listing
      const parentPath = path.split('/').slice(0, -1).join('/') || undefined
      queryClient.invalidateQueries({ queryKey: ['filesystem', 'list', parentPath] })
    },
  })
}

export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}


Good, now let me add the reference folder hooks at the end of the file.


export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}

export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}

// ============================================================================
// Reference Folders
// ============================================================================

export function useReferences(projectName: string | null) {
  return useQuery({
    queryKey: ['references', projectName],
    queryFn: () => api.listReferences(projectName!),
    enabled: !!projectName,
  })
}

export function useAddReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (data: ReferenceFolderCreate) => api.addReference(projectName, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}

export function useRemoveReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (referenceId: number) => api.removeReference(projectName, referenceId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}

export function useUpdateReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: ReferenceFolderUpdate }) =>
      api.updateReference(projectName, id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}


export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}

// ============================================================================
// Reference Folders
// ============================================================================

export function useReferences(projectName: string | null) {
  return useQuery({
    queryKey: ['references', projectName],
    queryFn: () => api.listReferences(projectName!),
    enabled: !!projectName,
  })
}

export function useAddReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (data: ReferenceFolderCreate) => api.addReference(projectName, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}

export function useRemoveReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (referenceId: number) => api.removeReference(projectName, referenceId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}

export function useUpdateReference(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ id, data }: { id: number; data: ReferenceFolderUpdate }) =>
      api.updateReference(projectName, id, data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['references', projectName] })
    },
  })
}

/**
 * React Query hooks for project data
 */

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import * as api from '../lib/api'
import type { FeatureCreate, ReferenceFolderCreate, ReferenceFolderUpdate } from '../lib/types'

// ============================================================================
// Projects
// ============================================================================

export function useProjects() {
  return useQuery({
    queryKey: ['projects'],
    queryFn: api.listProjects,
  })
}

export function useProject(name: string | null) {
  return useQuery({
    queryKey: ['project', name],
    queryFn: () => api.getProject(name!),
    enabled: !!name,
  })
}

export function useCreateProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, path, specMethod }: { name: string; path: string; specMethod?: 'claude' | 'manual' }) =>
      api.createProject(name, path, specMethod),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

export function useDeleteProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, deleteFiles = false }: { name: string; deleteFiles?: boolean }) =>
      api.deleteProject(name, deleteFiles),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

export function useImportProject() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ name, path }: { name: string; path: string }) =>
      api.importProject(name, path),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['projects'] })
    },
  })
}

// ============================================================================
// Features
// ============================================================================

export function useFeatures(projectName: string | null) {
  return useQuery({
    queryKey: ['features', projectName],
    queryFn: () => api.listFeatures(projectName!),
    enabled: !!projectName,
    refetchInterval: 5000, // Refetch every 5 seconds for real-time updates
  })
}

export function useCreateFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (feature: FeatureCreate) => api.createFeature(projectName, feature),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

export function useDeleteFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (featureId: number) => api.deleteFeature(projectName, featureId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

export function useSkipFeature(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (featureId: number) => api.skipFeature(projectName, featureId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['features', projectName] })
    },
  })
}

// ============================================================================
// Agent
// ============================================================================

export function useAgentStatus(projectName: string | null) {
  return useQuery({
    queryKey: ['agent-status', projectName],
    queryFn: () => api.getAgentStatus(projectName!),
    enabled: !!projectName,
    refetchInterval: 3000, // Poll every 3 seconds
  })
}

export function useStartAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (yoloMode: boolean = false) => api.startAgent(projectName, yoloMode),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function useStopAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.stopAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function usePauseAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.pauseAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

export function useResumeAgent(projectName: string) {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: () => api.resumeAgent(projectName),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['agent-status', projectName] })
    },
  })
}

// ============================================================================
// Setup
// ============================================================================

export function useSetupStatus() {
  return useQuery({
    queryKey: ['setup-status'],
    queryFn: api.getSetupStatus,
    staleTime: 60000, // Cache for 1 minute
  })
}

export function useHealthCheck() {
  return useQuery({
    queryKey: ['health'],
    queryFn: api.healthCheck,
    retry: false,
  })
}

// ============================================================================
// Filesystem
// ============================================================================

export function useListDirectory(path?: string) {
  return useQuery({
    queryKey: ['filesystem', 'list', path],
    queryFn: () => api.listDirectory(path),
  })
}

export function useCreateDirectory() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (path: string) => api.createDirectory(path),
    onSuccess: (_, path) => {
      // Invalidate parent directory listing
      const parentPath = path.split('/').slice(0, -1).join('/') || undefined
      queryClient.invalidateQueries({ queryKey: ['filesystem', 'list', parentPath] })
    },
  })
}

export function useValidatePath() {
  return useMutation({
    mutationFn: (path: string) => api.validatePath(path),
  })
}

+export function useReferences(projectName: string | null) {

+    queryKey: ['references', projectName],

+    queryFn: () => api.listReferences(projectName!),

+export function useAddReference(projectName: string) {

+    mutationFn: (data: ReferenceFolderCreate) => api.addReference(projectName, data),

+      queryClient.invalidateQueries({ queryKey: ['references', projectName] })

+export function useRemoveReference(projectName: string) {

+    mutationFn: (referenceId: number) => api.removeReference(projectName, referenceId),

+export function useUpdateReference(projectName: string) {

+    mutationFn: ({ id, data }: { id: number; data: ReferenceFolderUpdate }) =>

+      api.updateReference(projectName, id, data),


Now let me create the ReferenceFoldersPanel component. This will be a panel where users can add, view, edit, and remove reference folders.


Write

/**
 * Reference Folders Panel
 *
 * Manages reference folders for a project - codebases the agent can
 * learn from when implementing features.
 */

import { useState } from 'react'
import {
  FolderSearch,
  Plus,
  Trash2,
  X,
  Loader2,
  AlertTriangle,
  ExternalLink,
  Edit2,
  Check,
  FolderOpen,
} from 'lucide-react'
import { useReferences, useAddReference, useRemoveReference, useUpdateReference } from '../hooks/useProjects'
import { FolderBrowser } from './FolderBrowser'
import type { ReferenceFolder } from '../lib/types'

interface ReferenceFoldersPanelProps {
  projectName: string
  isOpen: boolean
  onClose: () => void
}

export function ReferenceFoldersPanel({
  projectName,
  isOpen,
  onClose,
}: ReferenceFoldersPanelProps) {
  const [showBrowser, setShowBrowser] = useState(false)
  const [newAlias, setNewAlias] = useState('')
  const [newDescription, setNewDescription] = useState('')
  const [editingId, setEditingId] = useState<number | null>(null)
  const [editAlias, setEditAlias] = useState('')
  const [editDescription, setEditDescription] = useState('')

  const { data: references, isLoading } = useReferences(projectName)
  const addReference = useAddReference(projectName)
  const removeReference = useRemoveReference(projectName)
  const updateReference = useUpdateReference(projectName)

  if (!isOpen) return null

  const handleFolderSelect = async (path: string) => {
    try {
      await addReference.mutateAsync({
        path,
        alias: newAlias || undefined,
        description: newDescription || undefined,
      })
      setShowBrowser(false)
      setNewAlias('')
      setNewDescription('')
    } catch (error) {
      console.error('Failed to add reference:', error)
    }
  }

  const handleRemove = async (id: number) => {
    try {
      await removeReference.mutateAsync(id)
    } catch (error) {
      console.error('Failed to remove reference:', error)
    }
  }

  const handleStartEdit = (ref: ReferenceFolder) => {
    setEditingId(ref.id)
    setEditAlias(ref.alias || '')
    setEditDescription(ref.description || '')
  }

  const handleSaveEdit = async (id: number) => {
    try {
      await updateReference.mutateAsync({
        id,
        data: {
          alias: editAlias || undefined,
          description: editDescription || undefined,
        },
      })
      setEditingId(null)
    } catch (error) {
      console.error('Failed to update reference:', error)
    }
  }

  const handleCancelEdit = () => {
    setEditingId(null)
    setEditAlias('')
    setEditDescription('')
  }

  return (
    <>
      {/* Backdrop */}

      {/* Panel */}

        {/* Header */}

            <FolderSearch size={20} />

Reference Folders

          <button
            onClick={onClose}
            className="p-1 hover:bg-gray-100 rounded"
          >
            <X size={20} />
          </button>

        {/* Description */}

            Reference folders are existing codebases the agent can learn from when
            implementing features. Add previous projects or examples here.

        {/* Content */}

          {isLoading ? (

              <Loader2 className="animate-spin" size={24} />

          ) : (

              {references && references.length > 0 ? (
                references.map((ref) => (

                    {editingId === ref.id ? (
                      // Edit mode

                        <input
                          type="text"
                          value={editAlias}
                          onChange={(e) => setEditAlias(e.target.value)}
                          placeholder="Alias (optional)"
                          className="w-full neo-input text-sm"
                        />
                        <textarea
                          value={editDescription}
                          onChange={(e) => setEditDescription(e.target.value)}
                          placeholder="Description (optional)"
                          className="w-full neo-input text-sm resize-none"
                          rows={2}
                        />

                          <button
                            onClick={handleCancelEdit}
                            className="neo-btn bg-white text-sm py-1"
                          >
                            Cancel
                          </button>
                          <button
                            onClick={() => handleSaveEdit(ref.id)}
                            disabled={updateReference.isPending}
                            className="neo-btn bg-[var(--color-neo-done)] text-sm py-1"
                          >
                            {updateReference.isPending ? (
                              <Loader2 size={14} className="animate-spin" />
                            ) : (
                              <Check size={14} />
                            )}
                            Save
                          </button>

                    ) : (
                      // View mode
                      <>

                              <FolderOpen size={16} className="flex-shrink-0 text-gray-500" />

                                {ref.alias || ref.path.split('/').pop()}

                              {ref.path}

                            {ref.description && (

                                {ref.description}

                            )}

                            <button
                              onClick={() => handleStartEdit(ref)}
                              className="p-1 hover:bg-gray-100 rounded"
                              title="Edit"
                            >
                              <Edit2 size={14} />
                            </button>
                            <button
                              onClick={() => handleRemove(ref.id)}
                              disabled={removeReference.isPending}
                              className="p-1 hover:bg-red-100 rounded text-red-500"
                              title="Remove"
                            >
                              {removeReference.isPending ? (
                                <Loader2 size={14} className="animate-spin" />
                              ) : (
                                <Trash2 size={14} />
                              )}
                            </button>

                        {!ref.exists && (

                            <AlertTriangle size={12} />
                            Path no longer exists

                        )}
                      </>
                    )}

                ))
              ) : (

                  <FolderSearch size={48} className="mx-auto mb-2 opacity-50" />

No reference folders yet

Add a codebase for the agent to learn from

              )}

          )}

        {/* Add Reference Section */}

          {showBrowser ? (

                <input
                  type="text"
                  value={newAlias}
                  onChange={(e) => setNewAlias(e.target.value)}
                  placeholder="Alias (optional)"
                  className="flex-1 neo-input text-sm"
                />

              <input
                type="text"
                value={newDescription}
                onChange={(e) => setNewDescription(e.target.value)}
                placeholder="Description - what is this reference for?"
                className="w-full neo-input text-sm"
              />

                <FolderBrowser
                  mode="select"
                  onSelect={handleFolderSelect}
                  allowCreateFolder={false}
                />

                <button
                  onClick={() => {
                    setShowBrowser(false)
                    setNewAlias('')
                    setNewDescription('')
                  }}
                  className="neo-btn bg-white"
                >
                  Cancel
                </button>

              {addReference.isError && (

                  {addReference.error instanceof Error
                    ? addReference.error.message
                    : 'Failed to add reference'}

              )}

          ) : (
            <button
              onClick={() => setShowBrowser(true)}
              className="w-full neo-btn bg-[var(--color-neo-pending)] flex items-center justify-center gap-2"
            >
              <Plus size={18} />
              Add Reference Folder
            </button>
          )}

    </>
  )
}


File created successfully at: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\ui\src\components\ReferenceFoldersPanel.tsx

/**
 * Reference Folders Panel
 *
 * Manages reference folders for a project - codebases the agent can
 * learn from when implementing features.
 */

import { useState } from 'react'
import {
  FolderSearch,
  Plus,
  Trash2,
  X,
  Loader2,
  AlertTriangle,
  ExternalLink,
  Edit2,
  Check,
  FolderOpen,
} from 'lucide-react'
import { useReferences, useAddReference, useRemoveReference, useUpdateReference } from '../hooks/useProjects'
import { FolderBrowser } from './FolderBrowser'
import type { ReferenceFolder } from '../lib/types'

interface ReferenceFoldersPanelProps {
  projectName: string
  isOpen: boolean
  onClose: () => void
}

export function ReferenceFoldersPanel({
  projectName,
  isOpen,
  onClose,
}: ReferenceFoldersPanelProps) {
  const [showBrowser, setShowBrowser] = useState(false)
  const [newAlias, setNewAlias] = useState('')
  const [newDescription, setNewDescription] = useState('')
  const [editingId, setEditingId] = useState<number | null>(null)
  const [editAlias, setEditAlias] = useState('')
  const [editDescription, setEditDescription] = useState('')

  const { data: references, isLoading } = useReferences(projectName)
  const addReference = useAddReference(projectName)
  const removeReference = useRemoveReference(projectName)
  const updateReference = useUpdateReference(projectName)

  if (!isOpen) return null

  const handleFolderSelect = async (path: string) => {
    try {
      await addReference.mutateAsync({
        path,
        alias: newAlias || undefined,
        description: newDescription || undefined,
      })
      setShowBrowser(false)
      setNewAlias('')
      setNewDescription('')
    } catch (error) {
      console.error('Failed to add reference:', error)
    }
  }

  const handleRemove = async (id: number) => {
    try {
      await removeReference.mutateAsync(id)
    } catch (error) {
      console.error('Failed to remove reference:', error)
    }
  }

  const handleStartEdit = (ref: ReferenceFolder) => {
    setEditingId(ref.id)
    setEditAlias(ref.alias || '')
    setEditDescription(ref.description || '')
  }

  const handleSaveEdit = async (id: number) => {
    try {
      await updateReference.mutateAsync({
        id,
        data: {
          alias: editAlias || undefined,
          description: editDescription || undefined,
        },
      })
      setEditingId(null)
    } catch (error) {
      console.error('Failed to update reference:', error)
    }
  }

  const handleCancelEdit = () => {
    setEditingId(null)
    setEditAlias('')
    setEditDescription('')
  }

  return (
    <>
      {/* Backdrop */}

      {/* Panel */}

        {/* Header */}

            <FolderSearch size={20} />

Reference Folders

          <button
            onClick={onClose}
            className="p-1 hover:bg-gray-100 rounded"
          >
            <X size={20} />
          </button>

        {/* Description */}

            Reference folders are existing codebases the agent can learn from when
            implementing features. Add previous projects or examples here.

        {/* Content */}

          {isLoading ? (

              <Loader2 className="animate-spin" size={24} />

          ) : (

              {references && references.length > 0 ? (
                references.map((ref) => (

                    {editingId === ref.id ? (
                      // Edit mode

                        <input
                          type="text"
                          value={editAlias}
                          onChange={(e) => setEditAlias(e.target.value)}
                          placeholder="Alias (optional)"
                          className="w-full neo-input text-sm"
                        />
                        <textarea
                          value={editDescription}
                          onChange={(e) => setEditDescription(e.target.value)}
                          placeholder="Description (optional)"
                          className="w-full neo-input text-sm resize-none"
                          rows={2}
                        />

                          <button
                            onClick={handleCancelEdit}
                            className="neo-btn bg-white text-sm py-1"
                          >
                            Cancel
                          </button>
                          <button
                            onClick={() => handleSaveEdit(ref.id)}
                            disabled={updateReference.isPending}
                            className="neo-btn bg-[var(--color-neo-done)] text-sm py-1"
                          >
                            {updateReference.isPending ? (
                              <Loader2 size={14} className="animate-spin" />
                            ) : (
                              <Check size={14} />
                            )}
                            Save
                          </button>

                    ) : (
                      // View mode
                      <>

                              <FolderOpen size={16} className="flex-shrink-0 text-gray-500" />

                                {ref.alias || ref.path.split('/').pop()}

                              {ref.path}

                            {ref.description && (

                                {ref.description}

                            )}

                            <button
                              onClick={() => handleStartEdit(ref)}
                              className="p-1 hover:bg-gray-100 rounded"
                              title="Edit"
                            >
                              <Edit2 size={14} />
                            </button>
                            <button
                              onClick={() => handleRemove(ref.id)}
                              disabled={removeReference.isPending}
                              className="p-1 hover:bg-red-100 rounded text-red-500"
                              title="Remove"
                            >
                              {removeReference.isPending ? (
                                <Loader2 size={14} className="animate-spin" />
                              ) : (
                                <Trash2 size={14} />
                              )}
                            </button>

                        {!ref.exists && (

                            <AlertTriangle size={12} />
                            Path no longer exists

                        )}
                      </>
                    )}

                ))
              ) : (

                  <FolderSearch size={48} className="mx-auto mb-2 opacity-50" />

No reference folders yet

Add a codebase for the agent to learn from

              )}

          )}

        {/* Add Reference Section */}

          {showBrowser ? (

                <input
                  type="text"
                  value={newAlias}
                  onChange={(e) => setNewAlias(e.target.value)}
                  placeholder="Alias (optional)"
                  className="flex-1 neo-input text-sm"
                />

              <input
                type="text"
                value={newDescription}
                onChange={(e) => setNewDescription(e.target.value)}
                placeholder="Description - what is this reference for?"
                className="w-full neo-input text-sm"
              />

                <FolderBrowser
                  mode="select"
                  onSelect={handleFolderSelect}
                  allowCreateFolder={false}
                />

                <button
                  onClick={() => {
                    setShowBrowser(false)
                    setNewAlias('')
                    setNewDescription('')
                  }}
                  className="neo-btn bg-white"
                >
                  Cancel
                </button>

              {addReference.isError && (

                  {addReference.error instanceof Error
                    ? addReference.error.message
                    : 'Failed to add reference'}

              )}

          ) : (
            <button
              onClick={() => setShowBrowser(true)}
              className="w-full neo-btn bg-[var(--color-neo-pending)] flex items-center justify-center gap-2"
            >
              <Plus size={18} />
              Add Reference Folder
            </button>
          )}

    </>
  )
}


Now I need to add a button to the App.tsx to open the ReferenceFoldersPanel. Let me check what the current App.tsx looks like and add the button.


Now let me add a button in the UI to access the reference folders panel:


     1→import { useState, useEffect, useCallback } from 'react'
     2→import { useProjects, useFeatures, useAgentStatus } from './hooks/useProjects'
     3→import { useProjectWebSocket } from './hooks/useWebSocket'
     4→import { useFeatureSound } from './hooks/useFeatureSound'
     5→import { useCelebration } from './hooks/useCelebration'
     6→
     7→const STORAGE_KEY = 'autocoder-selected-project'
     8→import { ProjectSelector } from './components/ProjectSelector'
     9→import { KanbanBoard } from './components/KanbanBoard'
    10→import { AgentControl } from './components/AgentControl'
    11→import { ProgressDashboard } from './components/ProgressDashboard'
    12→import { SetupWizard } from './components/SetupWizard'
    13→import { AddFeatureForm } from './components/AddFeatureForm'
    14→import { FeatureModal } from './components/FeatureModal'
    15→import { DebugLogViewer } from './components/DebugLogViewer'
    16→import { AgentThought } from './components/AgentThought'
    17→import { AssistantFAB } from './components/AssistantFAB'
    18→import { AssistantPanel } from './components/AssistantPanel'
    19→import { GitPanel } from './components/GitPanel'
    20→import { TerminalChat } from './components/TerminalChat'
    21→import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'
    22→import type { Feature } from './lib/types'
    23→
    24→function App() {
    25→  // Initialize selected project from localStorage
    26→  const [selectedProject, setSelectedProject] = useState<string | null>(() => {
    27→    try {
    28→      return localStorage.getItem(STORAGE_KEY)
    29→    } catch {
    30→      return null
    31→    }
    32→  })
    33→  const [showAddFeature, setShowAddFeature] = useState(false)
    34→  const [selectedFeature, setSelectedFeature] = useState<Feature | null>(null)
    35→  const [setupComplete, setSetupComplete] = useState(true) // Start optimistic
    36→  const [debugOpen, setDebugOpen] = useState(false)
    37→  const [debugPanelHeight, setDebugPanelHeight] = useState(288) // Default height
    38→  const [assistantOpen, setAssistantOpen] = useState(false)
    39→  const [gitPanelOpen, setGitPanelOpen] = useState(false)
    40→  const [terminalOpen, setTerminalOpen] = useState(false)
    41→
    42→  const { data: projects, isLoading: projectsLoading } = useProjects()
    43→  const { data: features } = useFeatures(selectedProject)
    44→  const { data: agentStatusData } = useAgentStatus(selectedProject)
    45→  const wsState = useProjectWebSocket(selectedProject)
    46→
    47→  // Play sounds when features move between columns
    48→  useFeatureSound(features)
    49→
    50→  // Celebrate when all features are complete

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import { useState, useEffect, useCallback } from 'react'
import { useProjects, useFeatures, useAgentStatus } from './hooks/useProjects'
import { useProjectWebSocket } from './hooks/useWebSocket'
import { useFeatureSound } from './hooks/useFeatureSound'
import { useCelebration } from './hooks/useCelebration'

const STORAGE_KEY = 'autocoder-selected-project'
import { ProjectSelector } from './components/ProjectSelector'
import { KanbanBoard } from './components/KanbanBoard'
import { AgentControl } from './components/AgentControl'
import { ProgressDashboard } from './components/ProgressDashboard'
import { SetupWizard } from './components/SetupWizard'
import { AddFeatureForm } from './components/AddFeatureForm'
import { FeatureModal } from './components/FeatureModal'
import { DebugLogViewer } from './components/DebugLogViewer'
import { AgentThought } from './components/AgentThought'
import { AssistantFAB } from './components/AssistantFAB'
import { AssistantPanel } from './components/AssistantPanel'
import { GitPanel } from './components/GitPanel'
import { TerminalChat } from './components/TerminalChat'
import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'
import type { Feature } from './lib/types'

function App() {
  // Initialize selected project from localStorage
  const [selectedProject, setSelectedProject] = useState<string | null>(() => {
    try {
      return localStorage.getItem(STORAGE_KEY)
    } catch {
      return null
    }
  })
  const [showAddFeature, setShowAddFeature] = useState(false)
  const [selectedFeature, setSelectedFeature] = useState<Feature | null>(null)
  const [setupComplete, setSetupComplete] = useState(true) // Start optimistic
  const [debugOpen, setDebugOpen] = useState(false)
  const [debugPanelHeight, setDebugPanelHeight] = useState(288) // Default height
  const [assistantOpen, setAssistantOpen] = useState(false)
  const [gitPanelOpen, setGitPanelOpen] = useState(false)
  const [terminalOpen, setTerminalOpen] = useState(false)

  const { data: projects, isLoading: projectsLoading } = useProjects()
  const { data: features } = useFeatures(selectedProject)
  const { data: agentStatusData } = useAgentStatus(selectedProject)
  const wsState = useProjectWebSocket(selectedProject)

  // Play sounds when features move between columns
  useFeatureSound(features)

  // Celebrate when all features are complete


Let me find where the header buttons are so I can add a Reference Folders button.


6-
7-const STORAGE_KEY = 'autocoder-selected-project'
8-import { ProjectSelector } from './components/ProjectSelector'
9-import { KanbanBoard } from './components/KanbanBoard'
10-import { AgentControl } from './components/AgentControl'
11-import { ProgressDashboard } from './components/ProgressDashboard'
12-import { SetupWizard } from './components/SetupWizard'
13-import { AddFeatureForm } from './components/AddFeatureForm'
14-import { FeatureModal } from './components/FeatureModal'
15-import { DebugLogViewer } from './components/DebugLogViewer'
16-import { AgentThought } from './components/AgentThought'
17-import { AssistantFAB } from './components/AssistantFAB'
18-import { AssistantPanel } from './components/AssistantPanel'
19-import { GitPanel } from './components/GitPanel'
20-import { TerminalChat } from './components/TerminalChat'
21:import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'
22-import type { Feature } from './lib/types'
23-
24-function App() {
25-  // Initialize selected project from localStorage
26-  const [selectedProject, setSelectedProject] = useState<string | null>(() => {
27-    try {
28-      return localStorage.getItem(STORAGE_KEY)
29-    } catch {
30-      return null
31-    }
32-  })
33-  const [showAddFeature, setShowAddFeature] = useState(false)
34-  const [selectedFeature, setSelectedFeature] = useState<Feature | null>(null)
35-  const [setupComplete, setSetupComplete] = useState(true) // Start optimistic
36-  const [debugOpen, setDebugOpen] = useState(false)
--
185-                    className="neo-btn text-sm"
186-                    title="Press T"
187-                  >
188-                    <Terminal size={18} />
189-                    Terminal
190-                    <kbd className="ml-1.5 px-1.5 py-0.5 text-xs bg-black/20 rounded font-mono">
191-                      T
192-                    </kbd>
193-                  </button>
194-
195-                  <button
196-                    onClick={() => setGitPanelOpen(true)}
197-                    className="neo-btn text-sm"
198-                    title="Press G"
199-                  >
200:                    <GitBranch size={18} />
201-                    Git
202-                    <kbd className="ml-1.5 px-1.5 py-0.5 text-xs bg-black/20 rounded font-mono">
203-                      G
204-                    </kbd>
205-                  </button>
206-
207-                  <AgentControl
208-                    projectName={selectedProject}
209-                    status={wsState.agentStatus}
210-                    yoloMode={agentStatusData?.yolo_mode ?? false}
211-                  />
212-                </>
213-              )}
214-            </div>
215-          </div>


Good, I can see where the buttons are. Let me add the ReferenceFoldersPanel import and add a button for it. I'll also need to add the state for it.


Edit

import { GitPanel } from './components/GitPanel'
import { TerminalChat } from './components/TerminalChat'
import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'

import { GitPanel } from './components/GitPanel'
import { TerminalChat } from './components/TerminalChat'
import { ReferenceFoldersPanel } from './components/ReferenceFoldersPanel'
import { Plus, Loader2, GitBranch, Terminal, X, FolderSearch } from 'lucide-react'


The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\ui\src\App.tsx has been updated successfully.

import { GitPanel } from './components/GitPanel'
import { TerminalChat } from './components/TerminalChat'
import { ReferenceFoldersPanel } from './components/ReferenceFoldersPanel'
import { Plus, Loader2, GitBranch, Terminal, X, FolderSearch } from 'lucide-react'

import { useState, useEffect, useCallback } from 'react'
import { useProjects, useFeatures, useAgentStatus } from './hooks/useProjects'
import { useProjectWebSocket } from './hooks/useWebSocket'
import { useFeatureSound } from './hooks/useFeatureSound'
import { useCelebration } from './hooks/useCelebration'

const STORAGE_KEY = 'autocoder-selected-project'
import { ProjectSelector } from './components/ProjectSelector'
import { KanbanBoard } from './components/KanbanBoard'
import { AgentControl } from './components/AgentControl'
import { ProgressDashboard } from './components/ProgressDashboard'
import { SetupWizard } from './components/SetupWizard'
import { AddFeatureForm } from './components/AddFeatureForm'
import { FeatureModal } from './components/FeatureModal'
import { DebugLogViewer } from './components/DebugLogViewer'
import { AgentThought } from './components/AgentThought'
import { AssistantFAB } from './components/AssistantFAB'
import { AssistantPanel } from './components/AssistantPanel'
import { GitPanel } from './components/GitPanel'
import { TerminalChat } from './components/TerminalChat'
import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'
import type { Feature } from './lib/types'

function App() {
  // Initialize selected project from localStorage
  const [selectedProject, setSelectedProject] = useState<string | null>(() => {
    try {
      return localStorage.getItem(STORAGE_KEY)
    } catch {
      return null
    }
  })
  const [showAddFeature, setShowAddFeature] = useState(false)
  const [selectedFeature, setSelectedFeature] = useState<Feature | null>(null)
  const [setupComplete, setSetupComplete] = useState(true) // Start optimistic
  const [debugOpen, setDebugOpen] = useState(false)
  const [debugPanelHeight, setDebugPanelHeight] = useState(288) // Default height
  const [assistantOpen, setAssistantOpen] = useState(false)
  const [gitPanelOpen, setGitPanelOpen] = useState(false)
  const [terminalOpen, setTerminalOpen] = useState(false)

  const { data: projects, isLoading: projectsLoading } = useProjects()
  const { data: features } = useFeatures(selectedProject)
  const { data: agentStatusData } = useAgentStatus(selectedProject)
  const wsState = useProjectWebSocket(selectedProject)

  // Play sounds when features move between columns
  useFeatureSound(features)

  // Celebrate when all features are complete
  useCelebration(features, selectedProject)

  // Persist selected project to localStorage
  const handleSelectProject = useCallback((project: string | null) => {
    setSelectedProject(project)
    try {
      if (project) {
        localStorage.setItem(STORAGE_KEY, project)
      } else {
        localStorage.removeItem(STORAGE_KEY)
      }
    } catch {
      // localStorage not available
    }
  }, [])

  // Validate stored project exists (clear if project was deleted)
  useEffect(() => {
    if (selectedProject && projects && !projects.some(p => p.name === selectedProject)) {
      handleSelectProject(null)
    }
  }, [selectedProject, projects, handleSelectProject])

  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Ignore if user is typing in an input
      if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
        return
      }

      // D : Toggle debug window
      if (e.key === 'd' || e.key === 'D') {
        e.preventDefault()
        setDebugOpen(prev => !prev)
      }

      // N : Add new feature (when project selected)
      if ((e.key === 'n' || e.key === 'N') && selectedProject) {
        e.preventDefault()
        setShowAddFeature(true)
      }

      // A : Toggle assistant panel (when project selected)
      if ((e.key === 'a' || e.key === 'A') && selectedProject) {
        e.preventDefault()
        setAssistantOpen(prev => !prev)
      }

      // G : Toggle git panel (when project selected)
      if ((e.key === 'g' || e.key === 'G') && selectedProject) {
        e.preventDefault()
        setGitPanelOpen(prev => !prev)
      }

      // T : Toggle terminal panel (when project selected)
      if ((e.key === 't' || e.key === 'T') && selectedProject) {
        e.preventDefault()
        setTerminalOpen(prev => !prev)
      }

      // Escape : Close modals
      if (e.key === 'Escape') {
        if (terminalOpen) {
          setTerminalOpen(false)
        } else if (gitPanelOpen) {
          setGitPanelOpen(false)
        } else if (assistantOpen) {
          setAssistantOpen(false)
        } else if (showAddFeature) {
          setShowAddFeature(false)
        } else if (selectedFeature) {
          setSelectedFeature(null)
        } else if (debugOpen) {
          setDebugOpen(false)
        }
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [selectedProject, showAddFeature, selectedFeature, debugOpen, assistantOpen, gitPanelOpen, terminalOpen])

  // Combine WebSocket progress with feature data
  const progress = wsState.progress.total > 0 ? wsState.progress : {
    passing: features?.done.length ?? 0,
    total: (features?.pending.length ?? 0) + (features?.in_progress.length ?? 0) + (features?.done.length ?? 0),
    percentage: 0,
  }

  if (progress.total > 0 && progress.percentage === 0) {
    progress.percentage = Math.round((progress.passing / progress.total) * 100 * 10) / 10
  }

  if (!setupComplete) {
    return <SetupWizard onComplete={() => setSetupComplete(true)} />
  }

  return (

      {/* Header */}

            {/* Logo and Title */}

              AutoCoder

            {/* Controls */}

              <ProjectSelector
                projects={projects ?? []}
                selectedProject={selectedProject}
                onSelectProject={handleSelectProject}
                isLoading={projectsLoading}
              />

              {selectedProject && (
                <>
                  <button
                    onClick={() => setShowAddFeature(true)}
                    className="neo-btn neo-btn-primary text-sm"
                    title="Press N"
                  >
                    <Plus size={18} />
                    Add Feature

                      N

                  </button>

                  <button
                    onClick={() => setTerminalOpen(true)}
                    className="neo-btn text-sm"
                    title="Press T"
                  >
                    <Terminal size={18} />
                    Terminal

                      T

                  </button>

                  <button
                    onClick={() => setGitPanelOpen(true)}
                    className="neo-btn text-sm"
                    title="Press G"
                  >
                    <GitBranch size={18} />
                    Git

                      G

                  </button>

                  <AgentControl
                    projectName={selectedProject}
                    status={wsState.agentStatus}
                    yoloMode={agentStatusData?.yolo_mode ?? false}
                  />
                </>
              )}

      {/* Main Content */}

        {!selectedProject ? (

              Welcome to AutoCoder

              Select a project from the dropdown above or create a new one to get started.

        ) : (

            {/* Progress Dashboard */}
            <ProgressDashboard
              passing={progress.passing}
              total={progress.total}
              percentage={progress.percentage}
              isConnected={wsState.isConnected}
            />

            {/* Agent Thought - shows latest agent narrative */}
            <AgentThought
              logs={wsState.logs}
              agentStatus={wsState.agentStatus}
            />

            {/* Initializing Features State - show when agent is running but no features yet */}
            {features &&
             features.pending.length === 0 &&
             features.in_progress.length === 0 &&
             features.done.length === 0 &&
             wsState.agentStatus === 'running' && (

                <Loader2 size={32} className="animate-spin mx-auto mb-4 text-[var(--color-neo-progress)]" />

                  Initializing Features...

                  The agent is reading your spec and creating features. This may take a moment.

            )}

            {/* Kanban Board */}
            <KanbanBoard
              features={features}
              onFeatureClick={setSelectedFeature}
            />

        )}

      {/* Add Feature Modal */}
      {showAddFeature && selectedProject && (
        <AddFeatureForm
          projectName={selectedProject}
          onClose={() => setShowAddFeature(false)}
        />
      )}

      {/* Feature Detail Modal */}
      {selectedFeature && selectedProject && (
        <FeatureModal
          feature={selectedFeature}
          projectName={selectedProject}
          onClose={() => setSelectedFeature(null)}
        />
      )}

      {/* Debug Log Viewer - fixed to bottom */}
      {selectedProject && (
        <DebugLogViewer
          logs={wsState.logs}
          isOpen={debugOpen}
          onToggle={() => setDebugOpen(!debugOpen)}
          onClear={wsState.clearLogs}
          onHeightChange={setDebugPanelHeight}
        />
      )}

      {/* Assistant FAB and Panel */}
      {selectedProject && (
        <>
          <AssistantFAB
            onClick={() => setAssistantOpen(!assistantOpen)}
            isOpen={assistantOpen}
          />
          <AssistantPanel
            projectName={selectedProject}
            isOpen={assistantOpen}
            onClose={() => setAssistantOpen(false)}
          />
        </>
      )}

      {/* Git Panel */}
      {selectedProject && (
        <GitPanel
          projectName={selectedProject}
          isOpen={gitPanelOpen}
          onClose={() => setGitPanelOpen(false)}
        />
      )}

      {/* Terminal Panel */}
      {selectedProject && (
        <>
          {/* Backdrop */}
          {terminalOpen && (

 setTerminalOpen(false)}
              aria-hidden="true"
            />
          )}
          {/* Panel */}
          <div
            className={`
              fixed right-0 top-0 bottom-0 z-50
              w-[600px] max-w-[90vw]
              bg-white
              border-l-4 border-[var(--color-neo-border)]
              shadow-[-8px_0_0px_rgba(0,0,0,1)]
              transform transition-transform duration-300 ease-out
              flex flex-col
              ${terminalOpen ? 'translate-x-0' : 'translate-x-full'}
            `}
            role="dialog"
            aria-label="Claude Terminal"
            aria-hidden={!terminalOpen}
          >
            {/* Header */}

                  <Terminal size={18} />

Claude Terminal

{selectedProject}

              <button
                onClick={() => setTerminalOpen(false)}
                className="neo-btn neo-btn-ghost p-2 bg-white/20 border-white/40 hover:bg-white/30 text-white"
                title="Close Terminal (Press T)"
              >
                <X size={18} />
              </button>

            {/* Terminal Chat area */}

              {terminalOpen && <TerminalChat projectName={selectedProject} onClose={() => setTerminalOpen(false)} />}

        </>
      )}

  )
}

export default App

-import { Plus, Loader2, GitBranch, Terminal, X } from 'lucide-react'

+import { ReferenceFoldersPanel } from './components/ReferenceFoldersPanel'

+import { Plus, Loader2, GitBranch, Terminal, X, FolderSearch } from 'lucide-react'


Now let me add the state for the references panel.


const [gitPanelOpen, setGitPanelOpen] = useState(false)
  const [terminalOpen, setTerminalOpen] = useState(false)

const [gitPanelOpen, setGitPanelOpen] = useState(false)
  const [terminalOpen, setTerminalOpen] = useState(false)
  const [referencesOpen, setReferencesOpen] = useState(false)