feat(ipuaro): implement v0.1.0 foundation

- Project setup with tsup, vitest, ESM support
- Domain entities: Session, Project
- Value objects: FileData, FileAST, FileMeta, ChatMessage, ToolCall, ToolResult, UndoEntry
- Service interfaces: IStorage, ILLMClient, ITool, IIndexer, IToolRegistry
- Shared: Config (zod), IpuaroError, utils (hash, tokens), Result type
- CLI with placeholder commands (start, init, index)
- 91 unit tests with 100% coverage
- Fix package scope @puaros -> @samiyev in CLAUDE.md
This commit is contained in:
imfozilbek
2025-11-29 23:08:38 +05:00
parent 7f6180df37
commit 130a8c4f24
62 changed files with 4629 additions and 6 deletions

View File

@@ -0,0 +1,61 @@
import { basename, dirname } from "node:path"
/**
* Project entity representing an indexed codebase.
*/
export class Project {
readonly name: string
readonly rootPath: string
readonly createdAt: number
lastIndexedAt: number | null
fileCount: number
indexingInProgress: boolean
constructor(rootPath: string, createdAt?: number) {
this.rootPath = rootPath
this.name = Project.generateProjectName(rootPath)
this.createdAt = createdAt ?? Date.now()
this.lastIndexedAt = null
this.fileCount = 0
this.indexingInProgress = false
}
/**
* Generate project name from path.
* Format: {parent-folder}-{project-folder}
*/
static generateProjectName(rootPath: string): string {
const projectFolder = basename(rootPath)
const parentFolder = basename(dirname(rootPath))
if (parentFolder && parentFolder !== ".") {
return `${parentFolder}-${projectFolder}`
}
return projectFolder
}
markIndexingStarted(): void {
this.indexingInProgress = true
}
markIndexingCompleted(fileCount: number): void {
this.indexingInProgress = false
this.lastIndexedAt = Date.now()
this.fileCount = fileCount
}
markIndexingFailed(): void {
this.indexingInProgress = false
}
isIndexed(): boolean {
return this.lastIndexedAt !== null
}
getTimeSinceIndexed(): number | null {
if (this.lastIndexedAt === null) {
return null
}
return Date.now() - this.lastIndexedAt
}
}