Files
puaros/packages/ipuaro/ROADMAP.md
imfozilbek 33d52bc7ca feat(ipuaro): add slash commands for TUI (v0.14.0)
- Add useCommands hook with command parser
- Implement 8 commands: /help, /clear, /undo, /sessions, /status, /reindex, /eval, /auto-apply
- Integrate commands into App.tsx with visual feedback
- Add 38 unit tests for commands
- Update ROADMAP.md to reflect current status
2025-12-01 14:33:30 +05:00

33 KiB

ipuaro Roadmap

Local AI agent for codebase operations with "infinite" context feeling through lazy loading.

Project Structure (Clean Architecture)

packages/ipuaro/
├── bin/
│   └── ipuaro.js               # CLI entry point
├── src/
│   ├── domain/                 # Business logic (no dependencies)
│   │   ├── entities/
│   │   │   ├── Session.ts
│   │   │   └── Project.ts
│   │   ├── value-objects/
│   │   │   ├── FileData.ts
│   │   │   ├── FileAST.ts
│   │   │   ├── FileMeta.ts
│   │   │   ├── ChatMessage.ts
│   │   │   ├── ToolCall.ts
│   │   │   ├── ToolResult.ts
│   │   │   └── UndoEntry.ts
│   │   ├── services/           # Interfaces (ports)
│   │   │   ├── IStorage.ts
│   │   │   ├── ILLMClient.ts
│   │   │   ├── ITool.ts
│   │   │   └── IIndexer.ts
│   │   └── constants/
│   │       └── index.ts
│   ├── application/            # Use cases & orchestration
│   │   ├── use-cases/
│   │   │   ├── StartSession.ts
│   │   │   ├── HandleMessage.ts
│   │   │   ├── IndexProject.ts
│   │   │   ├── ExecuteTool.ts
│   │   │   └── UndoChange.ts
│   │   ├── dtos/
│   │   │   ├── SessionDto.ts
│   │   │   ├── MessageDto.ts
│   │   │   └── ToolCallDto.ts
│   │   ├── mappers/
│   │   │   └── SessionMapper.ts
│   │   └── interfaces/
│   │       └── IToolRegistry.ts
│   ├── infrastructure/         # External implementations
│   │   ├── storage/
│   │   │   ├── RedisClient.ts
│   │   │   ├── RedisStorage.ts
│   │   │   └── schema.ts
│   │   ├── llm/
│   │   │   ├── OllamaClient.ts
│   │   │   ├── prompts.ts
│   │   │   └── ResponseParser.ts
│   │   ├── indexer/
│   │   │   ├── FileScanner.ts
│   │   │   ├── ASTParser.ts
│   │   │   ├── MetaAnalyzer.ts
│   │   │   ├── IndexBuilder.ts
│   │   │   └── Watchdog.ts
│   │   ├── tools/
│   │   │   ├── registry.ts
│   │   │   ├── read/
│   │   │   │   ├── GetLinesTool.ts
│   │   │   │   ├── GetFunctionTool.ts
│   │   │   │   ├── GetClassTool.ts
│   │   │   │   └── GetStructureTool.ts
│   │   │   ├── edit/
│   │   │   │   ├── EditLinesTool.ts
│   │   │   │   ├── CreateFileTool.ts
│   │   │   │   └── DeleteFileTool.ts
│   │   │   ├── search/
│   │   │   │   ├── FindReferencesTool.ts
│   │   │   │   └── FindDefinitionTool.ts
│   │   │   ├── analysis/
│   │   │   │   ├── GetDependenciesTool.ts
│   │   │   │   ├── GetDependentsTool.ts
│   │   │   │   ├── GetComplexityTool.ts
│   │   │   │   └── GetTodosTool.ts
│   │   │   ├── git/
│   │   │   │   ├── GitStatusTool.ts
│   │   │   │   ├── GitDiffTool.ts
│   │   │   │   └── GitCommitTool.ts
│   │   │   └── run/
│   │   │       ├── RunCommandTool.ts
│   │   │       └── RunTestsTool.ts
│   │   ├── security/
│   │   │   ├── Blacklist.ts
│   │   │   ├── Whitelist.ts
│   │   │   └── PathValidator.ts
│   │   └── constants/
│   │       ├── blacklist.ts
│   │       └── whitelist.ts
│   ├── shared/                 # Cross-cutting concerns
│   │   ├── types/
│   │   │   └── index.ts
│   │   ├── constants/
│   │   │   ├── config.ts
│   │   │   └── messages.ts
│   │   ├── utils/
│   │   │   ├── hash.ts
│   │   │   └── tokens.ts
│   │   └── errors/
│   │       └── IpuaroError.ts
│   ├── tui/                    # Terminal UI (Ink/React)
│   │   ├── App.tsx
│   │   ├── components/
│   │   │   ├── StatusBar.tsx
│   │   │   ├── Chat.tsx
│   │   │   ├── Input.tsx
│   │   │   ├── DiffView.tsx
│   │   │   ├── ConfirmDialog.tsx
│   │   │   ├── ErrorDialog.tsx
│   │   │   └── Progress.tsx
│   │   └── hooks/
│   │       ├── useSession.ts
│   │       ├── useHotkeys.ts
│   │       └── useAutocomplete.ts
│   └── cli/                    # CLI commands
│       ├── index.ts
│       └── commands/
│           ├── start.ts
│           ├── init.ts
│           └── index-cmd.ts
├── tests/
│   ├── unit/
│   │   ├── domain/
│   │   ├── application/
│   │   └── infrastructure/
│   ├── e2e/
│   │   ├── cli.test.ts
│   │   └── full-flow.test.ts
│   └── fixtures/
│       └── sample-project/
├── examples/
│   └── demo-project/
├── config/
│   ├── default.json
│   ├── blacklist.json
│   └── whitelist.json
├── CHANGELOG.md
├── TODO.md
├── README.md
├── package.json
├── tsconfig.json
└── vitest.config.ts

Version 0.1.0 - Foundation ⚙️

Priority: CRITICAL Status: Complete (v0.1.0 released)

0.1.1 - Project Setup

Dependencies:

{
  "dependencies": {
    "ink": "^4.0.0",
    "ink-text-input": "^5.0.0",
    "react": "^18.0.0",
    "ioredis": "^5.0.0",
    "tree-sitter": "^0.20.0",
    "tree-sitter-typescript": "^0.20.0",
    "tree-sitter-javascript": "^0.20.0",
    "ollama": "^0.5.0",
    "simple-git": "^3.0.0",
    "chokidar": "^3.0.0",
    "commander": "^11.0.0",
    "zod": "^3.0.0",
    "ignore": "^5.0.0"
  },
  "devDependencies": {
    "vitest": "^1.0.0",
    "@vitest/coverage-v8": "^1.0.0",
    "tsup": "^8.0.0",
    "typescript": "^5.0.0"
  }
}

Deliverables:

  • package.json with all dependencies
  • tsconfig.json (strict, jsx react, nodenext)
  • tsup.config.ts (bundle ESM + CJS)
  • vitest.config.ts (coverage 80%)
  • bin/ipuaro.js entry point

0.1.2 - Domain Value Objects

// src/domain/value-objects/FileData.ts
interface FileData {
    lines: string[]
    hash: string           // MD5
    size: number
    lastModified: number
}

// src/domain/value-objects/FileAST.ts
interface FileAST {
    imports: ImportInfo[]
    exports: ExportInfo[]
    functions: FunctionInfo[]
    classes: ClassInfo[]
    parseError: boolean
}

interface ImportInfo {
    name: string
    from: string
    line: number
    type: "internal" | "external" | "builtin"
    isDefault: boolean
}

interface FunctionInfo {
    name: string
    lineStart: number
    lineEnd: number
    params: string[]
    isAsync: boolean
    isExported: boolean
}

interface ClassInfo {
    name: string
    lineStart: number
    lineEnd: number
    methods: MethodInfo[]
    extends?: string
    isExported: boolean
}

// src/domain/value-objects/ChatMessage.ts
interface ChatMessage {
    role: "user" | "assistant" | "tool"
    content: string
    timestamp: number
    toolCalls?: ToolCall[]
    toolResults?: ToolResult[]
    stats?: { tokens: number; timeMs: number; toolCalls: number }
}

// src/domain/value-objects/UndoEntry.ts
interface UndoEntry {
    id: string
    timestamp: number
    filePath: string
    previousContent: string[]
    newContent: string[]
    description: string
}

0.1.3 - Domain Services (Interfaces)

// src/domain/services/IStorage.ts
interface IStorage {
    getFile(path: string): Promise<FileData | null>
    setFile(path: string, data: FileData): Promise<void>
    deleteFile(path: string): Promise<void>
    getAllFiles(): Promise<Map<string, FileData>>
    getAST(path: string): Promise<FileAST | null>
    setAST(path: string, ast: FileAST): Promise<void>
    getSymbolIndex(): Promise<SymbolIndex>
    setSymbolIndex(index: SymbolIndex): Promise<void>
}

// src/domain/services/ILLMClient.ts
interface ILLMClient {
    chat(messages: ChatMessage[], tools?: ToolDef[]): Promise<LLMResponse>
    countTokens(text: string): Promise<number>
    isAvailable(): Promise<boolean>
}

// src/domain/services/ITool.ts
interface ITool {
    name: string
    description: string
    parameters: ToolParameter[]
    requiresConfirmation: boolean
    execute(params: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>
}

0.1.4 - Shared Config

// src/shared/constants/config.ts
interface Config {
    redis: { host: string; port: number; db: number }
    llm: { model: string; contextWindow: number; temperature: number }
    project: { ignorePatterns: string[]; binaryExtensions: string[] }
    watchdog: { debounceMs: number }
    undo: { stackSize: number }
    edit: { autoApply: boolean }
}

// loadConfig(): reads config/default.json + .ipuaro.json
// validates with zod schema

Tests:

  • Unit tests for value objects
  • Unit tests for config loader

Version 0.2.0 - Redis Storage 🗄️

Priority: CRITICAL Status: Complete (v0.2.0 released)

0.2.1 - Redis Client

// src/infrastructure/storage/RedisClient.ts
class RedisClient {
    connect(): Promise<void>      // AOF config on connect
    disconnect(): Promise<void>
    isConnected(): boolean
    getClient(): Redis
}

// Redis config for AOF persistence
// appendonly yes
// appendfsync everysec

0.2.2 - Redis Schema

project:{name}:files      # Hash<path, FileData>
project:{name}:ast        # Hash<path, FileAST>
project:{name}:meta       # Hash<path, FileMeta>
project:{name}:indexes    # Hash<symbols|deps_graph, JSON>
project:{name}:config     # Hash<settings|last_indexed, JSON>

session:{id}:data         # Hash<history|context|stats>
session:{id}:undo         # List<UndoEntry> (max 10)
sessions:list             # List<session_id>

Project name format: {parent-folder}-{project-folder}

0.2.3 - Redis Storage Implementation

// src/infrastructure/storage/RedisStorage.ts
class RedisStorage implements IStorage {
    constructor(private client: RedisClient, private projectName: string)

    async getFile(path: string): Promise<FileData | null>
    async setFile(path: string, data: FileData): Promise<void>
    async deleteFile(path: string): Promise<void>
    async getAllFiles(): Promise<Map<string, FileData>>
    // ... all IStorage methods
}

Tests:

  • Unit tests for RedisStorage (mock Redis)
  • Integration tests with real Redis

Version 0.3.0 - Indexer 📂

Priority: CRITICAL Status: Complete (v0.3.0, v0.3.1 released)

0.3.1 - File Scanner

// src/infrastructure/indexer/FileScanner.ts
class FileScanner {
    scan(root: string): AsyncGenerator<ScanResult>
}

interface ScanResult {
    path: string
    type: "file" | "dir" | "symlink"
    stats: Stats
}

// Filters: .gitignore (via ignore lib), node_modules, dist
// Supports: .ts, .tsx, .js, .jsx, .json, .yaml
// Only UTF-8 files (skip binary)
// Progress callback: onProgress(current, total, file)

0.3.2 - AST Parser

// src/infrastructure/indexer/ASTParser.ts
class ASTParser {
    parse(content: string, lang: "ts" | "tsx" | "js" | "jsx"): FileAST
}

// Uses tree-sitter
// Extracts: imports, exports, functions, classes
// On error: parseError: true, continue with partial data

0.3.3 - Meta Analyzer

// src/infrastructure/indexer/MetaAnalyzer.ts
class MetaAnalyzer {
    analyze(path: string, ast: FileAST, allASTs: Map<string, FileAST>): FileMeta
}

interface FileMeta {
    complexity: { loc: number; nesting: number; score: number }
    dependencies: string[]    // files this imports
    dependents: string[]      // files importing this
    isHub: boolean            // >5 dependents
    isEntryPoint: boolean     // index.ts or 0 dependents
}

0.3.4 - Index Builder

// src/infrastructure/indexer/IndexBuilder.ts
class IndexBuilder {
    buildSymbolIndex(asts: Map<string, FileAST>): SymbolIndex
    buildDepsGraph(asts: Map<string, FileAST>): DepsGraph
}

// SymbolIndex: { [name]: { path, line, type } }
// DepsGraph: { [path]: { imports: [], importedBy: [] } }

0.3.5 - Watchdog

// src/infrastructure/indexer/Watchdog.ts
class Watchdog {
    start(root: string, storage: IStorage): void
    stop(): void
    onFileChange(callback: (path: string) => void): void
}

// chokidar with 500ms debounce
// On change: recalc hash → update lines/AST/meta if changed
// Silent updates (no UI notification)

Tests:

  • Unit tests for ASTParser (fixtures)
  • Unit tests for MetaAnalyzer
  • Integration tests for full indexing

Version 0.4.0 - LLM Integration 🤖

Priority: CRITICAL Status: Complete (v0.4.0 released)

0.4.1 - Ollama Client

// src/infrastructure/llm/OllamaClient.ts
class OllamaClient implements ILLMClient {
    constructor(config: { model: string; contextWindow: number; temperature: number })

    async chat(messages: ChatMessage[], tools?: ToolDef[]): Promise<LLMResponse>
    async countTokens(text: string): Promise<number>
    async isAvailable(): Promise<boolean>
    async pullModel(model: string): Promise<void>
}

interface LLMResponse {
    content: string
    toolCalls?: ToolCall[]
    tokens: number
    timeMs: number
}

0.4.2 - System Prompt

// src/infrastructure/llm/prompts.ts
const SYSTEM_PROMPT: string  // EN, role + rules + tools

function buildInitialContext(
    structure: ProjectStructure,
    asts: Map<string, FileAST>
): string

// Returns: project structure + AST metadata (NO code)
// Code loaded lazily via tools

0.4.3 - Tool Definitions

// src/infrastructure/llm/toolDefs.ts
const TOOL_DEFINITIONS: ToolDef[]  // 18 tools

interface ToolDef {
    name: string
    description: string
    parameters: {
        type: "object"
        properties: Record<string, { type: string; description: string }>
        required: string[]
    }
}

// XML format in prompt: <tool_call name="..."><param>...</param></tool_call>

0.4.4 - Response Parser

// src/infrastructure/llm/ResponseParser.ts
function parseToolCalls(response: string): ToolCall[]

// Parses XML tool calls from model response
// Handles multiple tool calls in one response

Tests:

  • Unit tests for ResponseParser
  • Mock tests for OllamaClient

Version 0.5.0 - Read Tools 📖

Priority: HIGH Status: Complete (v0.5.0 released)

4 tools for reading code without modification.

0.5.1 - Tool Registry

// src/infrastructure/tools/registry.ts
class ToolRegistry implements IToolRegistry {
    register(tool: ITool): void
    get(name: string): ITool | undefined
    getAll(): ITool[]
    execute(name: string, params: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>
}

0.5.2 - get_lines

// src/infrastructure/tools/read/GetLinesTool.ts
class GetLinesTool implements ITool {
    name = "get_lines"
    requiresConfirmation = false

    // get_lines(path, start?, end?)
    // Returns lines from Redis (or file if not indexed)
    // Default: entire file
}

0.5.3 - get_function

// src/infrastructure/tools/read/GetFunctionTool.ts
class GetFunctionTool implements ITool {
    name = "get_function"
    requiresConfirmation = false

    // get_function(path, name)
    // Uses AST lineStart/lineEnd to return function code
}

0.5.4 - get_class

// src/infrastructure/tools/read/GetClassTool.ts
class GetClassTool implements ITool {
    name = "get_class"
    requiresConfirmation = false

    // get_class(path, name)
    // Uses AST lineStart/lineEnd to return class code
}

0.5.5 - get_structure

// src/infrastructure/tools/read/GetStructureTool.ts
class GetStructureTool implements ITool {
    name = "get_structure"
    requiresConfirmation = false

    // get_structure(path?)
    // Returns folder/file tree
    // Default: entire project
}

Tests:

  • Unit tests for each read tool
  • Integration tests with real storage

Version 0.6.0 - Edit Tools ✏️

Priority: HIGH Status: Complete (v0.6.0 released)

3 tools for file modifications. All require confirmation (unless autoApply).

0.6.1 - edit_lines

// src/infrastructure/tools/edit/EditLinesTool.ts
class EditLinesTool implements ITool {
    name = "edit_lines"
    requiresConfirmation = true

    // edit_lines(path, start, end, content)
    // Replaces lines start-end with content
    // Checks hash conflict before apply
}

0.6.2 - create_file

// src/infrastructure/tools/edit/CreateFileTool.ts
class CreateFileTool implements ITool {
    name = "create_file"
    requiresConfirmation = true

    // create_file(path, content)
    // Creates new file
    // Validates path inside project
}

0.6.3 - delete_file

// src/infrastructure/tools/edit/DeleteFileTool.ts
class DeleteFileTool implements ITool {
    name = "delete_file"
    requiresConfirmation = true

    // delete_file(path)
    // Deletes file from filesystem and Redis
}

Tests:

  • Unit tests for each edit tool
  • Integration tests with filesystem

Version 0.7.0 - Search Tools 🔍

Priority: HIGH Status: Complete (v0.7.0 released)

0.7.1 - find_references

// src/infrastructure/tools/search/FindReferencesTool.ts
class FindReferencesTool implements ITool {
    name = "find_references"
    requiresConfirmation = false

    // find_references(symbol)
    // Searches SymbolIndex for all usages
    // Returns: [{ path, line, context }]
}

0.7.2 - find_definition

// src/infrastructure/tools/search/FindDefinitionTool.ts
class FindDefinitionTool implements ITool {
    name = "find_definition"
    requiresConfirmation = false

    // find_definition(symbol)
    // Finds where symbol is defined
    // Returns: { path, line, type }
}

Tests:

  • Unit tests for search tools

Version 0.8.0 - Analysis Tools 📊

Priority: MEDIUM Status: Complete (v0.8.0 released)

0.8.1 - get_dependencies

// src/infrastructure/tools/analysis/GetDependenciesTool.ts
// get_dependencies(path)
// Returns files this file imports (from FileMeta)

0.8.2 - get_dependents

// src/infrastructure/tools/analysis/GetDependentsTool.ts
// get_dependents(path)
// Returns files that import this file

0.8.3 - get_complexity

// src/infrastructure/tools/analysis/GetComplexityTool.ts
// get_complexity(path?)
// Returns complexity metrics
// Default: all files sorted by score

0.8.4 - get_todos

// src/infrastructure/tools/analysis/GetTodosTool.ts
// get_todos(path?)
// Finds TODO/FIXME comments in code
// Returns: [{ path, line, text }]

Tests:

  • Unit tests for analysis tools

Version 0.9.0 - Git & Run Tools 🚀

Priority: MEDIUM Status: Complete (v0.9.0 released) — includes CommandSecurity (Blacklist/Whitelist)

0.9.1 - git_status

// src/infrastructure/tools/git/GitStatusTool.ts
// git_status()
// Returns: { branch, staged, modified, untracked }

0.9.2 - git_diff

// src/infrastructure/tools/git/GitDiffTool.ts
// git_diff(path?)
// Returns uncommitted changes
// Default: all changes

0.9.3 - git_commit

// src/infrastructure/tools/git/GitCommitTool.ts
// git_commit(message, files?)
// Creates commit
// requiresConfirmation: true

0.9.4 - run_command

// src/infrastructure/tools/run/RunCommandTool.ts
// run_command(command)
// Executes shell command with security checks:
// 1. Check blacklist → reject
// 2. Check whitelist → allow
// 3. Unknown → ask user confirmation

0.9.5 - run_tests

// src/infrastructure/tools/run/RunTestsTool.ts
// run_tests(path?, filter?)
// Detects test runner (vitest/jest/npm test)
// Runs tests and returns results

Tests:

  • Unit tests for git tools
  • Unit tests for run tools

Version 0.10.0 - Session Management 💾

Priority: HIGH Status: Complete (v0.10.0 released) — includes HandleMessage orchestrator (originally planned for 0.14.0)

0.10.1 - Session Entity

// src/domain/entities/Session.ts
class Session {
    id: string
    projectName: string
    createdAt: number
    lastActivityAt: number
    history: ChatMessage[]
    context: ContextState
    undoStack: UndoEntry[]
    stats: SessionStats
    inputHistory: string[]
}

interface SessionStats {
    totalTokens: number
    totalTime: number
    toolCalls: number
    editsApplied: number
    editsRejected: number
}

0.10.2 - Session Use Cases

// src/application/use-cases/StartSession.ts
class StartSession {
    execute(projectName: string): Promise<Session>
    // Creates new or loads latest session
}

// src/application/use-cases/HandleMessage.ts
class HandleMessage {
    execute(session: Session, message: string): Promise<void>
    // Main message flow
}

0.10.3 - Undo Use Case

// src/application/use-cases/UndoChange.ts
class UndoChange {
    execute(session: Session): Promise<UndoResult>
    // Reverts last file change from undo stack
}

0.10.4 - Context Manager

// src/application/use-cases/pipeline/ContextManager.ts
class ContextManager {
    addToContext(file: string, tokens: number): void
    getUsage(): number  // 0-1
    needsCompression(): boolean  // >80%
    compress(llm: ILLMClient): Promise<void>
}

// Compression: LLM summarizes old messages + removes tool results

Tests:

  • Unit tests for session use cases
  • Integration tests for full session flow

Version 0.11.0 - TUI Basic 🖥️

Priority: CRITICAL Status: Complete (v0.11.0 released) — includes useHotkeys (originally planned for 0.16.0)

0.11.1 - App Shell

// src/tui/App.tsx
function App({ projectPath }: { projectPath: string }) {
    const [session, setSession] = useState<Session | null>(null)
    const [status, setStatus] = useState<"ready" | "thinking" | "error">("ready")
    const [messages, setMessages] = useState<ChatMessage[]>([])

    return (
        <Box flexDirection="column" height="100%">
            <StatusBar ... />
            <Chat messages={messages} isThinking={status === "thinking"} />
            <Input onSubmit={handleSubmit} disabled={status === "thinking"} />
        </Box>
    )
}

0.11.2 - StatusBar

// src/tui/components/StatusBar.tsx
// [ipuaro] [ctx: 12%] [project: myapp] [main] [47m] ✓

interface Props {
    contextUsage: number
    projectName: string
    branch: string
    sessionTime: number
    status: "ready" | "thinking" | "error"
}

0.11.3 - Chat

// src/tui/components/Chat.tsx
// Displays message history
// Tool calls as: [tool_name params...]
// Stats after response: ⏱ 3.2s │ 1,247 tokens │ 1 tool call

interface Props {
    messages: ChatMessage[]
    isThinking: boolean
}

0.11.4 - Input

// src/tui/components/Input.tsx
// Prompt: > _
// ↑/↓ for history
// Tab for path autocomplete

interface Props {
    onSubmit: (text: string) => void
    history: string[]
    disabled: boolean
}

Tests:

  • Component tests for TUI

Version 0.12.0 - TUI Advanced 🎨

Priority: HIGH Status: Complete (v0.12.0 released)

0.12.1 - DiffView

// src/tui/components/DiffView.tsx
// Inline highlights: green added, red removed
// Header: ┌─── path (lines X-Y) ───┐

interface Props {
    filePath: string
    oldLines: string[]
    newLines: string[]
    startLine: number
}

0.12.2 - ConfirmDialog

// src/tui/components/ConfirmDialog.tsx
// [Y] Apply  [N] Cancel  [E] Edit

interface Props {
    message: string
    diff?: DiffProps
    onSelect: (choice: "apply" | "cancel" | "edit") => void
}

0.12.3 - ErrorDialog

// src/tui/components/ErrorDialog.tsx
// ❌ type: message
// [R] Retry  [S] Skip  [A] Abort

interface Props {
    error: { type: string; message: string; recoverable: boolean }
    onChoice: (choice: "retry" | "skip" | "abort") => void
}

0.12.4 - Progress

// src/tui/components/Progress.tsx
// [=====>    ] 45% (120/267 files)
// Used during indexing

interface Props {
    current: number
    total: number
    label: string
}

Tests:

  • Component tests for dialogs

Version 0.13.0 - Security 🔒

Priority: HIGH Status: Complete (v0.13.0 released) — Blacklist/Whitelist done in v0.9.0, PathValidator in v0.13.0

0.13.1 - Blacklist

// src/infrastructure/security/Blacklist.ts
const BLACKLIST = [
    "rm -rf", "rm -r",
    "git push --force", "git reset --hard", "git clean -fd",
    "npm publish", "sudo", "chmod", "chown"
]

function isBlacklisted(command: string): boolean
// Substring match - always reject

0.13.2 - Whitelist

// src/infrastructure/security/Whitelist.ts
const DEFAULT_WHITELIST = [
    "npm", "pnpm", "yarn", "git",
    "node", "npx", "tsx",
    "vitest", "jest", "tsc", "eslint", "prettier"
]

function isWhitelisted(command: string): boolean
// First word match
// User can extend via config.whitelist.user

0.13.3 - Path Validator

// src/infrastructure/security/PathValidator.ts
function validatePath(path: string, projectRoot: string): boolean
// Rejects: .., absolute paths outside project

Tests:

  • Unit tests for security validators

[DONE] Original 0.14.0 - Orchestrator 🎭

Note: This was implemented in v0.10.0 as part of Session Management

Originally planned (click to expand)

HandleMessage Use Case (Done in v0.10.5)

// src/application/use-cases/HandleMessage.ts
class HandleMessage {
    constructor(
        private storage: IStorage,
        private llm: ILLMClient,
        private tools: IToolRegistry
    )

    async execute(session: Session, message: string): Promise<void> {
        // 1. Add user message to history
        // 2. Build context: system prompt + structure + AST + history
        // 3. Send to LLM
        // 4. Parse tool calls
        // 5. For each tool:
        //    - if requiresConfirmation → emit onEdit
        //    - else → execute
        // 6. If tool results → repeat from step 3
        // 7. Show final response with stats
    }

    // Events
    onMessage: (msg: ChatMessage) => void
    onToolCall: (call: ToolCall) => void
    onEdit: (edit: EditRequest) => Promise<EditChoice>
    onError: (error: IpuaroError) => Promise<ErrorChoice>
    onStatusChange: (status: Status) => void
}

Edit Flow (Done in v0.10.5)

// Edit handling inside HandleMessage:
// 1. Check hash conflict (file changed during generation?)
// 2. If conflict → onEdit with choices: apply/skip/regenerate
// 3. If not autoApply → onEdit with diff
// 4. On "apply":
//    - Save to undo stack
//    - Apply changes to file
//    - Update storage (lines, AST, meta)

[DONE] Original 0.16.0 - Hotkeys & Polish ⌨️

Note: useHotkeys done in v0.11.0, ContextManager auto-compression in v0.10.3

Originally planned (click to expand)

Hotkeys (Done in v0.11.0)

// src/tui/hooks/useHotkeys.ts

Ctrl+C  // Interrupt generation (1st), exit (2nd)
Ctrl+D  // Exit with session save
Ctrl+Z  // Undo (= /undo)
/     // Input history
Tab     // Path autocomplete

Auto-compression (Done in v0.10.3)

// Triggered at >80% context:
// 1. LLM summarizes old messages
// 2. Remove tool results older than 5 messages
// 3. Update status bar (ctx% changes)
// No modal notification - silent

Version 0.14.0 - Commands 📝

Priority: HIGH Status: Complete (v0.14.0 released)

8 slash commands for TUI.

// src/tui/hooks/useCommands.ts

/help       // Shows all commands and hotkeys
/clear      // Clears chat history (keeps session)
/undo       // Reverts last file change from undo stack
/sessions   // list | load <id> | delete <id>
/status     // Shows: Redis, context, model, session stats
/reindex    // Forces full project reindexation
/eval       // LLM self-check for hallucinations
/auto-apply // on | off - toggle auto-apply mode

Tests:

  • Unit tests for command handlers (38 tests)

Version 0.15.0 - CLI Entry Point 🚪

Priority: HIGH Status: NEXT MILESTONE

0.15.1 - CLI Commands

// src/cli/index.ts

ipuaro [path]           // Start TUI in directory (default: cwd)
ipuaro init             // Create .ipuaro.json config
ipuaro index            // Index only (no TUI)

0.15.2 - CLI Options

--auto-apply            # Enable auto-apply mode
--model <name>          # Override model (default: qwen2.5-coder:7b-instruct)
--help                  # Show help
--version               # Show version

0.15.3 - Onboarding

// src/cli/commands/start.ts

// On first run:
// 1. Check Redis → error with install instructions if missing
// 2. Check Ollama → error if unavailable
// 3. Check model → offer to pull if missing
// 4. Check project size → warn if >10K files, offer subdirectory

Tests:

  • E2E tests for CLI

Version 0.16.0 - Error Handling ⚠️

Priority: HIGH Status: Partial — IpuaroError exists (v0.1.0), need full error matrix implementation

0.16.1 - Error Types

// src/shared/errors/IpuaroError.ts
type ErrorType = "redis" | "parse" | "llm" | "file" | "command" | "conflict"

class IpuaroError extends Error {
    type: ErrorType
    recoverable: boolean
    suggestion?: string
}

0.16.2 - Error Handling Matrix

Error Recoverable Options
Redis unavailable No Retry / Abort
AST parse failed Yes Skip file / Abort
LLM timeout Yes Retry / Skip / Abort
File not found Yes Skip / Abort
Command not in whitelist Yes Confirm / Skip / Abort
Edit conflict Yes Apply / Skip / Regenerate

Tests:

  • Unit tests for error handling

Version 1.0.0 - Production Ready 🚀

Target: Stable release

Checklist:

  • All 18 tools implemented and tested (v0.9.0)
  • TUI fully functional (v0.11.0, v0.12.0)
  • Session persistence working (v0.10.0)
  • Error handling complete (partial)
  • Performance optimized
  • Documentation complete
  • 80%+ test coverage (~98%)
  • 0 ESLint errors
  • Examples working
  • CHANGELOG.md up to date

Post 1.0 - Future 💡

1.1.0 - Performance

  • Parallel AST parsing
  • Incremental indexing
  • Response caching

1.2.0 - Features

  • Multiple file edits in one operation
  • Batch operations
  • Custom prompt templates

1.3.0 - Extensibility

  • Plugin system for tools
  • Custom LLM providers (OpenAI, Anthropic)
  • IDE integration (LSP?)

Summary Tables

Tool Summary (18 total)

Category Tool Confirm Description
Read get_lines No Get file lines
get_function No Get function by name
get_class No Get class by name
get_structure No Get project tree
Edit edit_lines Yes Replace lines
create_file Yes Create new file
delete_file Yes Delete file
Search find_references No Find symbol usages
find_definition No Find symbol definition
Analysis get_dependencies No File imports
get_dependents No Files importing this
get_complexity No Complexity metrics
get_todos No Find TODO/FIXME
Git git_status No Repository status
git_diff No Uncommitted changes
git_commit Yes Create commit
Run run_command Conditional Execute shell command
run_tests No Run test suite

Redis Schema

# Project (5 keys per project)
project:{name}:files      # Hash<path, FileData>
project:{name}:ast        # Hash<path, FileAST>
project:{name}:meta       # Hash<path, FileMeta>
project:{name}:indexes    # Hash<name, JSON>
project:{name}:config     # Hash<key, JSON>

# Sessions (3 keys per session)
session:{id}:data         # Hash<field, JSON>
session:{id}:undo         # List<UndoEntry> max 10
sessions:list             # List<session_id>

Context Budget (128K window)

Component Tokens %
System prompt ~2,000 1.5%
Structure + AST ~10,000 8%
Available ~116,000 90%

Last Updated: 2025-12-01 Target Version: 1.0.0 Current Version: 0.14.0