generated from nhcarrigan/template
e6e9f7ae59
## Summary A large productivity-focused feature branch delivering a suite of improvements across automation, project management, theming, performance, and documentation. ### Features - **Guided Project Workflow** (#189) — Four-phase workflow panel (Discuss → Plan → Execute → Verify) to keep projects structured from idea to completion - **Automated Task Loop** (#179) — Per-task conversation orchestration with wave-based parallel execution, blocked-task detection, and concurrency control - **Wave-Based Parallel Execution** (#191) — Tasks run in dependency-aware waves with configurable concurrency; independent tasks execute in parallel - **Auto-Commit After Task Completion** (#192) — Task Loop optionally commits after each completed task so progress is never lost - **PRD Creator** (#180) — AI-assisted PRD and task list panel that outputs `hikari-tasks.json` for the Task Loop to consume - **Project Context Panel** (#188) — Persistent `PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, and `STATE.md` files injected into Claude's context automatically - **Codebase Mapper** (#190) — Generates a `CODEBASE.md` architectural summary so Claude always understands the project structure - **Community Preset Themes** (#181) — Six built-in community themes: Dracula, Catppuccin Mocha, Nord, Solarized Dark, Gruvbox Dark, and Rosé Pine - **In-App Changelog Panel** (#193) — Fetches release notes from GitHub at runtime and displays them inside the app - **Full Embedded Documentation** (#196) — Replaced the single-page help modal with a 12-page paginated docs browser featuring a sidebar TOC, prev/next navigation, keyboard navigation (arrow keys, `?` shortcut), and comprehensive coverage of every feature ### Performance & Fixes - **Lazy Loading & Virtualisation** (#194) — Virtual windowing for conversation history, markdown memoisation, and debounced search for smooth rendering of large sessions - **Ctrl+C Copy Fix** (#195) — `Ctrl+C` now copies selected text as expected; interrupt-Claude behaviour only fires when no text is selected ### UX - Back-to-workflow button in PRD Creator and Task Loop panels for easy navigation - Navigation icon cluster replaced with a single clean dropdown menu ## Closes Closes #179 Closes #180 Closes #181 Closes #188 Closes #189 Closes #190 Closes #191 Closes #192 Closes #193 Closes #194 Closes #195 Closes #196 --- ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #197 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
218 lines
6.3 KiB
TypeScript
218 lines
6.3 KiB
TypeScript
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<ProjectFile, string> = {
|
|
PROJECT: "PROJECT.md",
|
|
REQUIREMENTS: "REQUIREMENTS.md",
|
|
ROADMAP: "ROADMAP.md",
|
|
STATE: "STATE.md",
|
|
CODEBASE: "CODEBASE.md",
|
|
};
|
|
|
|
export const PROJECT_TEMPLATES: Record<ProjectFile, string> = {
|
|
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<Record<ProjectFile, string | null>>({
|
|
PROJECT: null,
|
|
REQUIREMENTS: null,
|
|
ROADMAP: null,
|
|
STATE: null,
|
|
CODEBASE: null,
|
|
});
|
|
|
|
const isLoading = writable<Record<ProjectFile, boolean>>({
|
|
PROJECT: false,
|
|
REQUIREMENTS: false,
|
|
ROADMAP: false,
|
|
STATE: false,
|
|
CODEBASE: false,
|
|
});
|
|
|
|
const isSaving = writable<Record<ProjectFile, boolean>>({
|
|
PROJECT: false,
|
|
REQUIREMENTS: false,
|
|
ROADMAP: false,
|
|
STATE: false,
|
|
CODEBASE: false,
|
|
});
|
|
|
|
const activeFile = writable<ProjectFile>("PROJECT");
|
|
const isMappingCodebase = writable<boolean>(false);
|
|
|
|
async function loadFile(file: ProjectFile, workingDirectory: string): Promise<void> {
|
|
isLoading.update((state) => ({ ...state, [file]: true }));
|
|
try {
|
|
const path = `${workingDirectory}/${PROJECT_FILE_NAMES[file]}`;
|
|
const content = await invoke<string>("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<boolean> {
|
|
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<void> {
|
|
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<void> {
|
|
isMappingCodebase.set(true);
|
|
try {
|
|
const scan = await invoke<ProjectScan>("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<string | null>(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`;
|