import { writable } from "svelte/store"; import { invoke } from "@tauri-apps/api/core"; export type ProjectFile = "PROJECT" | "REQUIREMENTS" | "ROADMAP" | "STATE" | "CODEBASE"; export const PROJECT_FILE_NAMES: Record = { PROJECT: "PROJECT.md", REQUIREMENTS: "REQUIREMENTS.md", ROADMAP: "ROADMAP.md", STATE: "STATE.md", CODEBASE: "CODEBASE.md", }; export const PROJECT_TEMPLATES: Record = { PROJECT: `# Project Overview ## What is this project? ## Goals ## Tech Stack ## Architecture `, REQUIREMENTS: `# Requirements ## Functional Requirements ## Non-Functional Requirements ## Out of Scope `, ROADMAP: `# Roadmap ## Current Sprint ## Next Sprint ## Backlog ## Completed `, STATE: `# Current State ## Last Updated ## What's Working ## In Progress ## Known Issues ## Next Steps `, CODEBASE: "", }; const PROJECT_FILES = Object.keys(PROJECT_FILE_NAMES) as ProjectFile[]; export interface ProjectScan { working_dir: string; file_tree: string; detected_type: string; key_files: string[]; } function createProjectContextStore() { const contents = writable>({ PROJECT: null, REQUIREMENTS: null, ROADMAP: null, STATE: null, CODEBASE: null, }); const isLoading = writable>({ PROJECT: false, REQUIREMENTS: false, ROADMAP: false, STATE: false, CODEBASE: false, }); const isSaving = writable>({ PROJECT: false, REQUIREMENTS: false, ROADMAP: false, STATE: false, CODEBASE: false, }); const activeFile = writable("PROJECT"); const isMappingCodebase = writable(false); async function loadFile(file: ProjectFile, workingDirectory: string): Promise { isLoading.update((state) => ({ ...state, [file]: true })); try { const path = `${workingDirectory}/${PROJECT_FILE_NAMES[file]}`; const content = await invoke("read_file_content", { path }); contents.update((state) => ({ ...state, [file]: content })); } catch { contents.update((state) => ({ ...state, [file]: null })); } finally { isLoading.update((state) => ({ ...state, [file]: false })); } } async function saveFile( file: ProjectFile, content: string, workingDirectory: string ): Promise { isSaving.update((state) => ({ ...state, [file]: true })); try { const path = `${workingDirectory}/${PROJECT_FILE_NAMES[file]}`; await invoke("write_file_content", { path, content }); contents.update((state) => ({ ...state, [file]: content })); return true; } catch (error) { console.error("Failed to save project context file:", error); return false; } finally { isSaving.update((state) => ({ ...state, [file]: false })); } } async function loadAll(workingDirectory: string): Promise { await Promise.all(PROJECT_FILES.map((file) => loadFile(file, workingDirectory))); } function setActiveFile(file: ProjectFile): void { activeFile.set(file); } function getTemplate(file: ProjectFile): string { return PROJECT_TEMPLATES[file]; } async function mapCodebase(workingDirectory: string, conversationId: string): Promise { isMappingCodebase.set(true); try { const scan = await invoke("scan_project", { workingDir: workingDirectory, }); const prompt = buildCodebaseMapPrompt(scan); await invoke("send_prompt", { conversationId, message: prompt }); } catch (error) { console.error("Failed to map codebase:", error); isMappingCodebase.set(false); } } function finishMapping(): void { isMappingCodebase.set(false); } return { contents: { subscribe: contents.subscribe }, isLoading: { subscribe: isLoading.subscribe }, isSaving: { subscribe: isSaving.subscribe }, activeFile: { subscribe: activeFile.subscribe }, isMappingCodebase: { subscribe: isMappingCodebase.subscribe }, loadFile, saveFile, loadAll, setActiveFile, getTemplate, mapCodebase, finishMapping, }; } function buildCodebaseMapPrompt(scan: ProjectScan): string { const keyFilesSection = scan.key_files.length > 0 ? `\n\nKey files detected:\n${scan.key_files.map((f) => `- ${f}`).join("\n")}` : ""; return `Please analyse this codebase and generate a comprehensive \`CODEBASE.md\` file in the working directory (${scan.working_dir}). Project type detected: **${scan.detected_type}**${keyFilesSection} Directory structure: \`\`\` ${scan.file_tree} \`\`\` The CODEBASE.md file should include: 1. **Overview** — what the project does and its purpose 2. **Architecture** — key directories, how the code is organised, and the overall structure 3. **Key Components** — the most important files and modules, what they do, and how they interact 4. **Data Flow** — how data moves through the system (if applicable) 5. **Dependencies** — notable external dependencies and why they are used 6. **Development Notes** — anything helpful for a developer new to the codebase Write the file concisely but thoroughly. Focus on information that helps a developer understand the codebase quickly. Use the actual file structure above to inform your analysis — read the key files as needed before writing.`; } export const projectContextStore = createProjectContextStore(); // Signal store for injecting context into the active InputBar. // StatusBar sets this; InputBar subscribes and applies it to inputValue directly, // then resets it to null so the signal only fires once. export const injectTextStore = writable(null); // Appended silently to custom_instructions at connection time (never saved to config). // Mirrors how CLAUDE.md works natively — Claude checks the files itself if they exist. export const PROJECT_CONTEXT_SYSTEM_ADDENDUM = ` --- The following project context files may exist in your working directory. If they exist, read and refer to them as needed: - PROJECT.md — project overview, goals, and architecture - REQUIREMENTS.md — functional and non-functional requirements - ROADMAP.md — current sprint, backlog, and completed work - STATE.md — current state, known issues, and next steps - CODEBASE.md — auto-generated codebase map and architecture overview`;