cckb 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/install.ts","../src/core/file-collector.ts","../src/core/chunk-manager.ts","../src/core/auto-discover.ts","../src/cli/discover.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as fsSync from \"node:fs\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ensureDir,\n fileExists,\n readJSON,\n writeJSON,\n readTextFile,\n writeTextFile,\n} from \"../utils/file-utils.js\";\nimport { DEFAULT_CONFIG } from \"../utils/config.js\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Find package root by looking for package.json\nfunction findPackageRoot(): string {\n let dir = __dirname;\n for (let i = 0; i < 5; i++) {\n const packageJson = path.join(dir, \"package.json\");\n if (fsSync.existsSync(packageJson)) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n // Fallback to relative from __dirname\n return path.resolve(__dirname, \"../..\");\n}\n\nconst PACKAGE_ROOT = findPackageRoot();\nconst TEMPLATES_DIR = path.join(PACKAGE_ROOT, \"templates\");\n\nexport interface InstallOptions {\n force?: boolean;\n}\n\nexport async function install(\n targetPath: string,\n options: InstallOptions = {}\n): Promise<void> {\n const resolvedPath = path.resolve(targetPath);\n\n console.log(`Installing CCKB to: ${resolvedPath}`);\n\n // Pre-flight checks\n await validateTargetPath(resolvedPath);\n await checkExistingInstallation(resolvedPath, options.force);\n\n // Create directory structure\n await createDirectoryStructure(resolvedPath);\n\n // Copy template files\n await copyTemplateFiles(resolvedPath);\n\n // Create config file\n await createConfigFile(resolvedPath);\n\n // Install hooks configuration\n await installHooks(resolvedPath);\n\n // Update CLAUDE.md\n await updateClaudeMd(resolvedPath);\n\n // Update .gitignore\n await updateGitignore(resolvedPath);\n\n console.log(\"\\nCCKB installed successfully!\");\n console.log(\"\\nNext steps:\");\n console.log(\" 1. Review cc-knowledge-base/vault/ structure\");\n console.log(\" 2. Check .claude/settings.json for hook configuration\");\n console.log(\" 3. Start a new Claude Code session to begin capturing knowledge\");\n}\n\nasync function validateTargetPath(targetPath: string): Promise<void> {\n const exists = await fileExists(targetPath);\n if (!exists) {\n throw new Error(`Target path does not exist: ${targetPath}`);\n }\n\n const stats = await fs.stat(targetPath);\n if (!stats.isDirectory()) {\n throw new Error(`Target path is not a directory: ${targetPath}`);\n }\n}\n\nasync function checkExistingInstallation(\n targetPath: string,\n force?: boolean\n): Promise<void> {\n const kbPath = path.join(targetPath, \"cc-knowledge-base\");\n const exists = await fileExists(kbPath);\n\n if (exists && !force) {\n throw new Error(\n \"CCKB is already installed in this project. Use --force to reinstall.\"\n );\n }\n}\n\nasync function createDirectoryStructure(targetPath: string): Promise<void> {\n const directories = [\n \"cc-knowledge-base\",\n \"cc-knowledge-base/conversations\",\n \"cc-knowledge-base/vault\",\n \"cc-knowledge-base/vault/entities\",\n \"cc-knowledge-base/vault/apps\",\n \"cc-knowledge-base/vault/modules\",\n \"cc-knowledge-base/.cckb-state\",\n ];\n\n for (const dir of directories) {\n await ensureDir(path.join(targetPath, dir));\n }\n\n console.log(\" Created directory structure\");\n}\n\nasync function copyTemplateFiles(targetPath: string): Promise<void> {\n const vaultFiles = [\n { src: \"vault/INDEX.md\", dest: \"cc-knowledge-base/vault/INDEX.md\" },\n {\n src: \"vault/architecture.md\",\n dest: \"cc-knowledge-base/vault/architecture.md\",\n },\n {\n src: \"vault/general-knowledge.md\",\n dest: \"cc-knowledge-base/vault/general-knowledge.md\",\n },\n {\n src: \"vault/entities/INDEX.md\",\n dest: \"cc-knowledge-base/vault/entities/INDEX.md\",\n },\n {\n src: \"vault/apps/INDEX.md\",\n dest: \"cc-knowledge-base/vault/apps/INDEX.md\",\n },\n {\n src: \"vault/modules/INDEX.md\",\n dest: \"cc-knowledge-base/vault/modules/INDEX.md\",\n },\n ];\n\n for (const file of vaultFiles) {\n const srcPath = path.join(TEMPLATES_DIR, file.src);\n const destPath = path.join(targetPath, file.dest);\n\n const content = await readTextFile(srcPath);\n if (content) {\n await writeTextFile(destPath, content);\n }\n }\n\n // Create .gitkeep for conversations\n await writeTextFile(\n path.join(targetPath, \"cc-knowledge-base/conversations/.gitkeep\"),\n \"\"\n );\n\n console.log(\" Copied vault template files\");\n}\n\nasync function createConfigFile(targetPath: string): Promise<void> {\n const configPath = path.join(\n targetPath,\n \"cc-knowledge-base\",\n \".cckb-config.json\"\n );\n\n await writeJSON(configPath, DEFAULT_CONFIG);\n\n console.log(\" Created configuration file\");\n}\n\nasync function installHooks(targetPath: string): Promise<void> {\n const claudeDir = path.join(targetPath, \".claude\");\n const settingsPath = path.join(claudeDir, \"settings.json\");\n\n await ensureDir(claudeDir);\n\n // Load existing settings or create new\n let settings: Record<string, unknown> =\n (await readJSON<Record<string, unknown>>(settingsPath)) || {};\n\n // Load hook template\n const templatePath = path.join(TEMPLATES_DIR, \"settings.json.tmpl\");\n const hookSettings = await readJSON<{ hooks: Record<string, unknown> }>(\n templatePath\n );\n\n if (!hookSettings) {\n throw new Error(\"Failed to load hook template\");\n }\n\n // Merge hooks (CCKB hooks take precedence for its own hook types)\n const existingHooks = (settings.hooks as Record<string, unknown[]>) || {};\n const newHooks = hookSettings.hooks as Record<string, unknown[]>;\n\n settings.hooks = mergeHooks(existingHooks, newHooks);\n\n await writeJSON(settingsPath, settings);\n\n console.log(\" Installed hook configuration\");\n}\n\nfunction mergeHooks(\n existing: Record<string, unknown[]>,\n incoming: Record<string, unknown[]>\n): Record<string, unknown[]> {\n const merged = { ...existing };\n\n for (const [hookType, hooks] of Object.entries(incoming)) {\n if (!merged[hookType]) {\n merged[hookType] = [];\n }\n\n // Add incoming hooks, avoiding duplicates based on command\n for (const hook of hooks) {\n const hookObj = hook as Record<string, unknown>;\n const command = hookObj.command as string | undefined;\n\n if (command?.includes(\"cckb\")) {\n // Remove any existing CCKB hooks for this type\n merged[hookType] = merged[hookType].filter((h) => {\n const existingCmd = (h as Record<string, unknown>).command as\n | string\n | undefined;\n return !existingCmd?.includes(\"cckb\");\n });\n }\n\n merged[hookType].push(hook);\n }\n }\n\n return merged;\n}\n\nasync function updateClaudeMd(targetPath: string): Promise<void> {\n const claudeMdPath = path.join(targetPath, \"CLAUDE.md\");\n const templatePath = path.join(TEMPLATES_DIR, \"CLAUDE.md.tmpl\");\n\n const template = await readTextFile(templatePath);\n if (!template) {\n throw new Error(\"Failed to load CLAUDE.md template\");\n }\n\n const marker = \"## Project Knowledge Base (CCKB)\";\n\n let existing = await readTextFile(claudeMdPath);\n\n if (existing) {\n // Check if CCKB section already exists\n if (existing.includes(marker)) {\n // Replace existing CCKB section\n const regex = /## Project Knowledge Base \\(CCKB\\)[\\s\\S]*?(?=\\n## |$)/;\n existing = existing.replace(regex, template.trim());\n } else {\n // Append CCKB section\n existing = existing.trimEnd() + \"\\n\\n\" + template;\n }\n await writeTextFile(claudeMdPath, existing);\n } else {\n // Create new CLAUDE.md with CCKB section\n await writeTextFile(claudeMdPath, template);\n }\n\n console.log(\" Updated CLAUDE.md with vault directives\");\n}\n\nasync function updateGitignore(targetPath: string): Promise<void> {\n const gitignorePath = path.join(targetPath, \".gitignore\");\n\n const entries = [\n \"\",\n \"# CCKB state files\",\n \"cc-knowledge-base/.cckb-state/\",\n ];\n\n let existing = (await readTextFile(gitignorePath)) || \"\";\n\n // Check if already added\n if (existing.includes(\"cc-knowledge-base/.cckb-state/\")) {\n return;\n }\n\n existing = existing.trimEnd() + \"\\n\" + entries.join(\"\\n\") + \"\\n\";\n await writeTextFile(gitignorePath, existing);\n\n console.log(\" Updated .gitignore\");\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { readTextFile, fileExists } from \"../utils/file-utils.js\";\nimport { loadConfig } from \"../utils/config.js\";\n\n// Language detection from manifest files\nconst MANIFEST_LANGUAGE_MAP: Record<string, { language: string; projectType: string }> = {\n \"package.json\": { language: \"typescript\", projectType: \"node\" },\n \"tsconfig.json\": { language: \"typescript\", projectType: \"node\" },\n \"Cargo.toml\": { language: \"rust\", projectType: \"rust\" },\n \"go.mod\": { language: \"go\", projectType: \"go\" },\n \"requirements.txt\": { language: \"python\", projectType: \"python\" },\n \"pyproject.toml\": { language: \"python\", projectType: \"python\" },\n \"setup.py\": { language: \"python\", projectType: \"python\" },\n \"pom.xml\": { language: \"java\", projectType: \"java\" },\n \"build.gradle\": { language: \"java\", projectType: \"java\" },\n \"*.csproj\": { language: \"csharp\", projectType: \"dotnet\" },\n \"Gemfile\": { language: \"ruby\", projectType: \"ruby\" },\n \"composer.json\": { language: \"php\", projectType: \"php\" },\n};\n\n// Extension to language mapping\nconst EXTENSION_LANGUAGE_MAP: Record<string, string> = {\n \".ts\": \"typescript\",\n \".tsx\": \"typescript\",\n \".js\": \"javascript\",\n \".jsx\": \"javascript\",\n \".mjs\": \"javascript\",\n \".cjs\": \"javascript\",\n \".py\": \"python\",\n \".go\": \"go\",\n \".rs\": \"rust\",\n \".java\": \"java\",\n \".cs\": \"csharp\",\n \".rb\": \"ruby\",\n \".php\": \"php\",\n};\n\n// File categories for prioritization\ntype FileCategory = \"entry\" | \"model\" | \"service\" | \"util\" | \"config\" | \"test\" | \"other\";\n\nexport interface CollectedFile {\n path: string; // Relative to project root\n absolutePath: string;\n language: string;\n category: FileCategory;\n size: number;\n priority: number;\n}\n\nexport interface CollectionResult {\n files: CollectedFile[];\n languages: string[];\n projectType: string;\n totalFilesScanned: number;\n}\n\nexport interface CollectOptions {\n maxFiles?: number;\n excludePatterns?: string[];\n priorityPatterns?: string[];\n supportedLanguages?: string[];\n}\n\nexport class FileCollector {\n private projectPath: string;\n\n constructor(projectPath: string) {\n this.projectPath = projectPath;\n }\n\n async collect(options?: CollectOptions): Promise<CollectionResult> {\n const config = await loadConfig(this.projectPath);\n const mergedOptions = {\n maxFiles: options?.maxFiles ?? config.discover.maxFiles,\n excludePatterns: options?.excludePatterns ?? config.discover.excludePatterns,\n supportedLanguages: options?.supportedLanguages ?? config.discover.supportedLanguages,\n };\n\n // Detect project languages\n const { languages, projectType } = await this.detectLanguages();\n\n // Load ignore patterns\n const ignorePatterns = await this.loadIgnorePatterns(mergedOptions.excludePatterns);\n\n // Collect all source files\n const allFiles: CollectedFile[] = [];\n let totalScanned = 0;\n\n await this.walkDirectory(\n this.projectPath,\n async (filePath, stats) => {\n totalScanned++;\n const relativePath = path.relative(this.projectPath, filePath);\n\n // Skip if matches ignore pattern\n if (this.shouldIgnore(relativePath, ignorePatterns)) {\n return;\n }\n\n const ext = path.extname(filePath);\n const language = EXTENSION_LANGUAGE_MAP[ext];\n\n // Skip unsupported languages\n if (!language || !mergedOptions.supportedLanguages.includes(language)) {\n return;\n }\n\n const category = this.categorizeFile(relativePath);\n const priority = this.calculatePriority(relativePath, category, stats.size);\n\n allFiles.push({\n path: relativePath,\n absolutePath: filePath,\n language,\n category,\n size: stats.size,\n priority,\n });\n }\n );\n\n // Sort by priority (descending) and limit\n allFiles.sort((a, b) => b.priority - a.priority);\n const limitedFiles = allFiles.slice(0, mergedOptions.maxFiles);\n\n return {\n files: limitedFiles,\n languages,\n projectType,\n totalFilesScanned: totalScanned,\n };\n }\n\n async detectLanguages(): Promise<{ languages: string[]; projectType: string }> {\n const detected = new Set<string>();\n let projectType = \"unknown\";\n\n // Check for manifest files\n for (const [manifest, info] of Object.entries(MANIFEST_LANGUAGE_MAP)) {\n if (manifest.startsWith(\"*\")) {\n // Glob pattern - skip for now\n continue;\n }\n const manifestPath = path.join(this.projectPath, manifest);\n if (await fileExists(manifestPath)) {\n detected.add(info.language);\n if (projectType === \"unknown\") {\n projectType = info.projectType;\n }\n }\n }\n\n // If package.json exists, check for TypeScript\n const packageJsonPath = path.join(this.projectPath, \"package.json\");\n if (await fileExists(packageJsonPath)) {\n const content = await readTextFile(packageJsonPath);\n if (content) {\n try {\n const pkg = JSON.parse(content);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps.typescript || await fileExists(path.join(this.projectPath, \"tsconfig.json\"))) {\n detected.add(\"typescript\");\n } else {\n detected.add(\"javascript\");\n }\n } catch {\n detected.add(\"javascript\");\n }\n }\n }\n\n return {\n languages: Array.from(detected),\n projectType,\n };\n }\n\n private async loadIgnorePatterns(additionalPatterns: string[]): Promise<string[]> {\n const patterns: string[] = [\n // Default ignores\n \"node_modules/**\",\n \".git/**\",\n \"dist/**\",\n \"build/**\",\n \"coverage/**\",\n \"*.log\",\n \".env*\",\n \"__pycache__/**\",\n \"*.pyc\",\n \"target/**\", // Rust\n \"vendor/**\", // Go\n \".venv/**\",\n \"venv/**\",\n ];\n\n // Load .gitignore\n const gitignorePath = path.join(this.projectPath, \".gitignore\");\n const gitignore = await readTextFile(gitignorePath);\n if (gitignore) {\n const lines = gitignore\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith(\"#\"));\n patterns.push(...lines);\n }\n\n // Add user-configured excludes\n patterns.push(...additionalPatterns);\n\n return patterns;\n }\n\n private shouldIgnore(relativePath: string, patterns: string[]): boolean {\n const normalizedPath = relativePath.replace(/\\\\/g, \"/\");\n\n for (const pattern of patterns) {\n if (this.matchPattern(normalizedPath, pattern)) {\n return true;\n }\n }\n return false;\n }\n\n private matchPattern(filePath: string, pattern: string): boolean {\n // Simple glob matching - supports *, **, and basic patterns\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\");\n\n // Handle negation patterns\n if (normalizedPattern.startsWith(\"!\")) {\n return false; // Negation patterns don't cause ignore\n }\n\n // Convert glob to regex\n let regex = normalizedPattern\n .replace(/\\./g, \"\\\\.\")\n .replace(/\\*\\*/g, \"{{GLOBSTAR}}\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/{{GLOBSTAR}}/g, \".*\")\n .replace(/\\?/g, \".\");\n\n // Handle patterns that should match from start or anywhere\n if (!regex.startsWith(\"/\") && !regex.startsWith(\".*\")) {\n regex = \"(^|/)\" + regex;\n }\n\n // Handle trailing slash (directory match)\n if (regex.endsWith(\"/\")) {\n regex = regex + \".*\";\n }\n\n try {\n const re = new RegExp(regex);\n return re.test(filePath);\n } catch {\n // Invalid regex, do simple includes check\n return filePath.includes(pattern.replace(/\\*/g, \"\"));\n }\n }\n\n private categorizeFile(relativePath: string): FileCategory {\n const lowerPath = relativePath.toLowerCase();\n const fileName = path.basename(lowerPath);\n\n // Test files\n if (\n /\\.(test|spec)\\.[^/]+$/.test(lowerPath) ||\n /\\/__tests__\\//.test(lowerPath) ||\n /\\/test\\//.test(lowerPath) ||\n /\\/tests\\//.test(lowerPath)\n ) {\n return \"test\";\n }\n\n // Entry points\n if (\n /^(index|main|app|server)\\.[^/]+$/.test(fileName) ||\n /\\/src\\/(index|main|app)\\.[^/]+$/.test(lowerPath)\n ) {\n return \"entry\";\n }\n\n // Models/Entities\n if (\n /\\/(models?|entities|domain|types|schemas?)\\//i.test(lowerPath) ||\n /\\.(model|entity|type)\\.[^/]+$/.test(lowerPath)\n ) {\n return \"model\";\n }\n\n // Services\n if (\n /\\/(services?|controllers?|handlers?|api|routes?)\\//i.test(lowerPath) ||\n /\\.(service|controller|handler)\\.[^/]+$/.test(lowerPath)\n ) {\n return \"service\";\n }\n\n // Config files\n if (\n /\\.(config|conf)\\.[^/]+$/.test(lowerPath) ||\n /\\/config\\//i.test(lowerPath) ||\n fileName.startsWith(\".\")\n ) {\n return \"config\";\n }\n\n // Utilities\n if (\n /\\/(utils?|helpers?|lib|common|shared)\\//i.test(lowerPath) ||\n /\\.(util|helper)\\.[^/]+$/.test(lowerPath)\n ) {\n return \"util\";\n }\n\n return \"other\";\n }\n\n private calculatePriority(\n relativePath: string,\n category: FileCategory,\n size: number\n ): number {\n let score = 0;\n\n // Category-based scoring\n const categoryScores: Record<FileCategory, number> = {\n entry: 100,\n model: 80,\n service: 70,\n util: 30,\n config: 20,\n other: 10,\n test: -50,\n };\n score += categoryScores[category];\n\n // Depth penalty (shallower files are usually more important)\n const depth = relativePath.split(\"/\").length;\n score -= depth * 2;\n\n // Size preferences\n if (size < 5000) score += 10; // Small, focused files\n if (size > 50000) score -= 20; // Very large files\n if (size > 100000) score -= 30; // Huge files\n\n // Bonus for src directory\n if (/^src\\//.test(relativePath)) score += 15;\n\n return score;\n }\n\n private async walkDirectory(\n dir: string,\n callback: (filePath: string, stats: { size: number }) => Promise<void>\n ): Promise<void> {\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip common non-source directories early\n if (\n entry.name === \"node_modules\" ||\n entry.name === \".git\" ||\n entry.name === \"dist\" ||\n entry.name === \"build\" ||\n entry.name === \"__pycache__\" ||\n entry.name === \"target\" ||\n entry.name === \"vendor\" ||\n entry.name === \".venv\" ||\n entry.name === \"venv\"\n ) {\n continue;\n }\n await this.walkDirectory(fullPath, callback);\n } else if (entry.isFile()) {\n try {\n const stats = await fs.stat(fullPath);\n await callback(fullPath, { size: stats.size });\n } catch {\n // Skip files we can't stat\n }\n }\n }\n } catch {\n // Skip directories we can't read\n }\n }\n}\n","import { readTextFile } from \"../utils/file-utils.js\";\nimport type { CollectedFile } from \"./file-collector.js\";\n\nexport interface FileChunk {\n files: CollectedFile[];\n content: string;\n estimatedTokens: number;\n index: number;\n totalChunks: number;\n}\n\nexport interface ChunkOptions {\n maxChunkSize?: number; // Max characters per chunk (default: 50000)\n}\n\nconst DEFAULT_MAX_CHUNK_SIZE = 50000;\n\n// Rough token estimation (avg ~4 chars per token for code)\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport class ChunkManager {\n private files: CollectedFile[];\n private maxChunkSize: number;\n private chunks: FileChunk[] | null = null;\n\n constructor(files: CollectedFile[], options?: ChunkOptions) {\n this.files = files;\n this.maxChunkSize = options?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n }\n\n async prepareChunks(): Promise<FileChunk[]> {\n if (this.chunks) {\n return this.chunks;\n }\n\n const chunks: FileChunk[] = [];\n let currentChunk: CollectedFile[] = [];\n let currentContent = \"\";\n let currentSize = 0;\n\n for (const file of this.files) {\n const content = await readTextFile(file.absolutePath);\n if (!content) continue;\n\n // Format file content with path header\n const formattedContent = this.formatFileContent(file.path, content);\n const contentSize = formattedContent.length;\n\n // If single file exceeds max size, truncate it\n if (contentSize > this.maxChunkSize) {\n // If we have pending content, save current chunk first\n if (currentChunk.length > 0) {\n chunks.push(this.createChunk(currentChunk, currentContent, chunks.length));\n currentChunk = [];\n currentContent = \"\";\n currentSize = 0;\n }\n\n // Add truncated file as its own chunk\n const truncatedContent = this.truncateContent(formattedContent, this.maxChunkSize);\n chunks.push(this.createChunk([file], truncatedContent, chunks.length));\n continue;\n }\n\n // If adding this file would exceed max size, start new chunk\n if (currentSize + contentSize > this.maxChunkSize && currentChunk.length > 0) {\n chunks.push(this.createChunk(currentChunk, currentContent, chunks.length));\n currentChunk = [];\n currentContent = \"\";\n currentSize = 0;\n }\n\n // Add file to current chunk\n currentChunk.push(file);\n currentContent += formattedContent + \"\\n\\n\";\n currentSize += contentSize;\n }\n\n // Don't forget the last chunk\n if (currentChunk.length > 0) {\n chunks.push(this.createChunk(currentChunk, currentContent, chunks.length));\n }\n\n // Update totalChunks in all chunks\n for (const chunk of chunks) {\n chunk.totalChunks = chunks.length;\n }\n\n this.chunks = chunks;\n return chunks;\n }\n\n private createChunk(\n files: CollectedFile[],\n content: string,\n index: number\n ): FileChunk {\n return {\n files,\n content: content.trim(),\n estimatedTokens: estimateTokens(content),\n index,\n totalChunks: 0, // Will be updated after all chunks are created\n };\n }\n\n private formatFileContent(filePath: string, content: string): string {\n // Add clear file boundaries for Claude to parse\n return `===== FILE: ${filePath} =====\n${content}\n===== END: ${filePath} =====`;\n }\n\n private truncateContent(content: string, maxSize: number): string {\n if (content.length <= maxSize) {\n return content;\n }\n\n // Try to truncate at a reasonable point\n const truncateAt = maxSize - 100; // Leave room for truncation message\n const lastNewline = content.lastIndexOf(\"\\n\", truncateAt);\n const cutPoint = lastNewline > truncateAt * 0.5 ? lastNewline : truncateAt;\n\n return content.slice(0, cutPoint) + \"\\n\\n[... TRUNCATED - file too large ...]\";\n }\n\n getTotalChunks(): number {\n if (!this.chunks) {\n throw new Error(\"Chunks not prepared. Call prepareChunks() first.\");\n }\n return this.chunks.length;\n }\n\n getChunkSummary(): string {\n if (!this.chunks) {\n return \"Chunks not yet prepared\";\n }\n\n const totalFiles = this.chunks.reduce((sum, c) => sum + c.files.length, 0);\n const totalTokens = this.chunks.reduce((sum, c) => sum + c.estimatedTokens, 0);\n\n return `${totalFiles} files in ${this.chunks.length} chunks (~${totalTokens} tokens)`;\n }\n\n // Async generator for processing chunks one at a time\n async *iterateChunks(): AsyncGenerator<FileChunk> {\n const chunks = await this.prepareChunks();\n for (const chunk of chunks) {\n yield chunk;\n }\n }\n}\n","import { FileCollector, type CollectionResult } from \"./file-collector.js\";\nimport { ChunkManager, type FileChunk } from \"./chunk-manager.js\";\nimport { VaultIntegrator } from \"./vault-integrator.js\";\nimport { spawnClaudeAgent, isClaudeAvailable } from \"../utils/claude-sdk.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport type {\n Summary,\n ExtractedEntity,\n ArchitectureItem,\n ServiceItem,\n KnowledgeItem,\n} from \"./compaction-engine.js\";\n\nconst DISCOVERY_PROMPT = `You are a technical knowledge extractor analyzing a codebase. Extract information for a project knowledge base.\n\nPROJECT CONTEXT:\n- Language(s): {languages}\n- Project Type: {projectType}\n\nANALYZE THESE SOURCE FILES:\n\n{fileContents}\n\nExtract and format the following:\n\n## Entities\nFor each domain entity (data model, type, class, interface):\n- **Name**: Entity name\n- **Location**: File path\n- **Attributes**: Key fields/properties\n- **Relations**: Related entities\n\n## Architecture\nFor each architectural pattern or design decision:\n- **Pattern**: Name of pattern (e.g., MVC, Repository, Factory, Singleton, etc.)\n- **Description**: Brief explanation of how it's used\n- **Affected Files**: Relevant file paths\n\n## Services\nFor each service or component:\n- **Name**: Service name\n- **Location**: File path\n- **Purpose**: Brief description\n- **Methods**: Key methods/functions\n\n## Knowledge\nFor each convention, rule, or important context discovered:\n- **Topic**: What it's about\n- **Details**: The actual information\n\nGuidelines:\n- Only include sections that have content\n- Be concise but complete\n- Use exact file paths as shown\n- Focus on domain logic, not framework boilerplate\n- Identify patterns from code structure, not just naming\n`;\n\nexport interface DiscoverOptions {\n maxFiles?: number;\n maxChunkSize?: number;\n verbose?: boolean;\n}\n\nexport interface DiscoveryResult {\n summary: Summary;\n filesAnalyzed: number;\n chunksProcessed: number;\n duration: number;\n integrated: boolean;\n}\n\nexport class AutoDiscover {\n private projectPath: string;\n private verbose: boolean;\n\n constructor(projectPath: string, verbose = false) {\n this.projectPath = projectPath;\n this.verbose = verbose;\n }\n\n async discover(options?: DiscoverOptions): Promise<DiscoveryResult> {\n const startTime = Date.now();\n const config = await loadConfig(this.projectPath);\n\n const maxFiles = options?.maxFiles ?? config.discover.maxFiles;\n const maxChunkSize = options?.maxChunkSize ?? config.discover.maxChunkSize;\n\n this.log(\"Discovering codebase...\\n\");\n\n // Step 1: Collect files\n const collector = new FileCollector(this.projectPath);\n const collection = await collector.collect({ maxFiles });\n\n this.log(`Detected: ${collection.languages.join(\", \")} (${collection.projectType} project)`);\n this.log(`Collected: ${collection.totalFilesScanned} files → ${collection.files.length} prioritized`);\n\n if (collection.files.length === 0) {\n this.log(\"No source files found to analyze.\");\n return this.createEmptyResult(startTime);\n }\n\n // Step 2: Check Claude availability\n const claudeAvailable = await isClaudeAvailable();\n if (!claudeAvailable) {\n this.log(\"Claude CLI not available. Using fallback analysis...\");\n return this.fallbackDiscovery(collection, startTime);\n }\n\n // Step 3: Prepare chunks\n const chunkManager = new ChunkManager(collection.files, { maxChunkSize });\n const chunks = await chunkManager.prepareChunks();\n\n this.log(`Grouped into ${chunks.length} chunks\\n`);\n this.log(\"Analyzing with Claude...\");\n\n // Step 4: Analyze each chunk with Claude\n const partialSummaries: Summary[] = [];\n let chunksProcessed = 0;\n\n for (const chunk of chunks) {\n this.log(` [${chunk.index + 1}/${chunk.totalChunks}] Analyzing ${chunk.files.length} files...`);\n\n try {\n const summary = await this.analyzeChunk(chunk, collection);\n partialSummaries.push(summary);\n chunksProcessed++;\n\n // Rate limiting between chunks\n if (chunk.index < chunks.length - 1) {\n await this.delay(1500);\n }\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.log(` Warning: Chunk ${chunk.index + 1} analysis failed: ${errorMsg}`);\n // Continue with other chunks\n }\n }\n\n if (partialSummaries.length === 0) {\n this.log(\"\\nNo successful analyses. Using fallback...\");\n return this.fallbackDiscovery(collection, startTime);\n }\n\n // Step 5: Merge summaries\n const mergedSummary = this.mergeSummaries(partialSummaries);\n\n // Step 6: Integrate into vault\n this.log(\"\\nIntegrating into vault...\");\n let integrated = false;\n\n try {\n const integrator = new VaultIntegrator(this.projectPath);\n await integrator.integrate(mergedSummary);\n integrated = true;\n\n this.log(` ${mergedSummary.entities.length} entities`);\n this.log(` ${mergedSummary.architecture.length} patterns`);\n this.log(` ${mergedSummary.services.length} services`);\n this.log(` ${mergedSummary.knowledge.length} knowledge items`);\n } catch (error) {\n this.log(` Warning: Vault integration failed: ${error}`);\n }\n\n const duration = Date.now() - startTime;\n this.log(`\\nDiscovery complete (${(duration / 1000).toFixed(1)}s)`);\n\n return {\n summary: mergedSummary,\n filesAnalyzed: collection.files.length,\n chunksProcessed,\n duration,\n integrated,\n };\n }\n\n private async analyzeChunk(\n chunk: FileChunk,\n collection: CollectionResult\n ): Promise<Summary> {\n const prompt = DISCOVERY_PROMPT\n .replace(\"{languages}\", collection.languages.join(\", \"))\n .replace(\"{projectType}\", collection.projectType)\n .replace(\"{fileContents}\", chunk.content);\n\n const response = await this.runWithProgressIndicators(\n () => spawnClaudeAgent(prompt, { timeout: 300000 }), // 5 minutes\n [\n { at: 60000, message: \" Still analyzing... (1 min)\" },\n { at: 180000, message: \" Still working... (3 min)\" },\n ]\n );\n\n return this.parseResponse(response, chunk);\n }\n\n private async runWithProgressIndicators<T>(\n task: () => Promise<T>,\n indicators: { at: number; message: string }[]\n ): Promise<T> {\n const timers: NodeJS.Timeout[] = [];\n\n // Set up progress indicators\n for (const indicator of indicators) {\n const timer = setTimeout(() => {\n this.log(indicator.message);\n }, indicator.at);\n timers.push(timer);\n }\n\n try {\n const result = await task();\n return result;\n } finally {\n // Clean up timers\n for (const timer of timers) {\n clearTimeout(timer);\n }\n }\n }\n\n private parseResponse(response: string, _chunk: FileChunk): Summary {\n const summary: Summary = {\n sessionId: `discover-${Date.now()}`,\n content: response,\n entities: [],\n architecture: [],\n services: [],\n knowledge: [],\n };\n\n // Parse entities\n const entitiesMatch = response.match(/## Entities\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (entitiesMatch) {\n summary.entities = this.parseEntities(entitiesMatch[1]);\n }\n\n // Parse architecture\n const archMatch = response.match(/## Architecture\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (archMatch) {\n summary.architecture = this.parseArchitecture(archMatch[1]);\n }\n\n // Parse services\n const servicesMatch = response.match(/## Services\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (servicesMatch) {\n summary.services = this.parseServices(servicesMatch[1]);\n }\n\n // Parse knowledge\n const knowledgeMatch = response.match(/## Knowledge\\n([\\s\\S]*?)(?=\\n## |$)/);\n if (knowledgeMatch) {\n summary.knowledge = this.parseKnowledge(knowledgeMatch[1]);\n }\n\n return summary;\n }\n\n private parseEntities(section: string): ExtractedEntity[] {\n const entities: ExtractedEntity[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const attributesMatch = block.match(/\\*\\*Attributes\\*\\*:\\s*(.+)/);\n const relationsMatch = block.match(/\\*\\*Relations\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n entities.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n attributes: attributesMatch?.[1].split(\",\").map((a) => a.trim()) || [],\n relations: relationsMatch?.[1].split(\",\").map((r) => r.trim()) || [],\n });\n }\n }\n\n return entities;\n }\n\n private parseArchitecture(section: string): ArchitectureItem[] {\n const items: ArchitectureItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Pattern\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const patternMatch = block.match(/\\*\\*Pattern\\*\\*:\\s*(.+)/);\n const descMatch = block.match(/\\*\\*Description\\*\\*:\\s*(.+)/);\n const filesMatch = block.match(/\\*\\*Affected Files\\*\\*:\\s*(.+)/);\n\n if (patternMatch) {\n items.push({\n pattern: patternMatch[1].trim(),\n description: descMatch?.[1].trim() || \"\",\n affectedFiles: filesMatch?.[1].split(\",\").map((f) => f.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseServices(section: string): ServiceItem[] {\n const items: ServiceItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Name\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const nameMatch = block.match(/\\*\\*Name\\*\\*:\\s*(.+)/);\n const locationMatch = block.match(/\\*\\*Location\\*\\*:\\s*(.+)/);\n const purposeMatch = block.match(/\\*\\*Purpose\\*\\*:\\s*(.+)/);\n const methodsMatch = block.match(/\\*\\*Methods\\*\\*:\\s*(.+)/);\n\n if (nameMatch) {\n items.push({\n name: nameMatch[1].trim(),\n location: locationMatch?.[1].trim(),\n purpose: purposeMatch?.[1].trim() || \"\",\n methods: methodsMatch?.[1].split(\",\").map((m) => m.trim()) || [],\n });\n }\n }\n\n return items;\n }\n\n private parseKnowledge(section: string): KnowledgeItem[] {\n const items: KnowledgeItem[] = [];\n const blocks = section.split(/\\n(?=- \\*\\*Topic\\*\\*:)/);\n\n for (const block of blocks) {\n if (!block.trim()) continue;\n\n const topicMatch = block.match(/\\*\\*Topic\\*\\*:\\s*(.+)/);\n const detailsMatch = block.match(/\\*\\*Details\\*\\*:\\s*(.+)/);\n\n if (topicMatch) {\n items.push({\n topic: topicMatch[1].trim(),\n details: detailsMatch?.[1].trim() || \"\",\n });\n }\n }\n\n return items;\n }\n\n private mergeSummaries(summaries: Summary[]): Summary {\n const merged: Summary = {\n sessionId: `discover-${Date.now()}`,\n content: summaries.map((s) => s.content).join(\"\\n\\n---\\n\\n\"),\n entities: [],\n architecture: [],\n services: [],\n knowledge: [],\n };\n\n // Merge and deduplicate by name\n const entityMap = new Map<string, ExtractedEntity>();\n const archMap = new Map<string, ArchitectureItem>();\n const serviceMap = new Map<string, ServiceItem>();\n const knowledgeMap = new Map<string, KnowledgeItem>();\n\n for (const summary of summaries) {\n for (const entity of summary.entities) {\n const key = entity.name.toLowerCase();\n if (!entityMap.has(key)) {\n entityMap.set(key, entity);\n }\n }\n\n for (const arch of summary.architecture) {\n const key = arch.pattern.toLowerCase();\n if (!archMap.has(key)) {\n archMap.set(key, arch);\n }\n }\n\n for (const service of summary.services) {\n const key = service.name.toLowerCase();\n if (!serviceMap.has(key)) {\n serviceMap.set(key, service);\n }\n }\n\n for (const knowledge of summary.knowledge) {\n const key = knowledge.topic.toLowerCase();\n if (!knowledgeMap.has(key)) {\n knowledgeMap.set(key, knowledge);\n }\n }\n }\n\n merged.entities = Array.from(entityMap.values());\n merged.architecture = Array.from(archMap.values());\n merged.services = Array.from(serviceMap.values());\n merged.knowledge = Array.from(knowledgeMap.values());\n\n return merged;\n }\n\n private async fallbackDiscovery(\n collection: CollectionResult,\n startTime: number\n ): Promise<DiscoveryResult> {\n // Basic discovery without Claude - just catalog files\n const summary: Summary = {\n sessionId: `discover-fallback-${Date.now()}`,\n content: \"Fallback discovery - Claude unavailable\",\n entities: [],\n architecture: [],\n services: [],\n knowledge: [\n {\n topic: \"Project Languages\",\n details: collection.languages.join(\", \"),\n },\n {\n topic: \"Project Type\",\n details: collection.projectType,\n },\n {\n topic: \"Source Files Discovered\",\n details: `${collection.files.length} files categorized by type`,\n },\n ],\n };\n\n // Group files by category\n const categories = new Map<string, string[]>();\n for (const file of collection.files) {\n if (!categories.has(file.category)) {\n categories.set(file.category, []);\n }\n categories.get(file.category)!.push(file.path);\n }\n\n for (const [category, files] of categories) {\n if (category !== \"other\" && category !== \"test\") {\n summary.knowledge.push({\n topic: `${category.charAt(0).toUpperCase() + category.slice(1)} Files`,\n details: files.slice(0, 10).join(\", \") + (files.length > 10 ? ` (+${files.length - 10} more)` : \"\"),\n });\n }\n }\n\n // Try to integrate\n let integrated = false;\n try {\n const integrator = new VaultIntegrator(this.projectPath);\n await integrator.integrate(summary);\n integrated = true;\n this.log(\"\\nFallback discovery integrated into vault\");\n } catch {\n this.log(\"\\nFallback discovery completed (vault integration failed)\");\n }\n\n return {\n summary,\n filesAnalyzed: collection.files.length,\n chunksProcessed: 0,\n duration: Date.now() - startTime,\n integrated,\n };\n }\n\n private createEmptyResult(startTime: number): DiscoveryResult {\n return {\n summary: {\n sessionId: `discover-empty-${Date.now()}`,\n content: \"\",\n entities: [],\n architecture: [],\n services: [],\n knowledge: [],\n },\n filesAnalyzed: 0,\n chunksProcessed: 0,\n duration: Date.now() - startTime,\n integrated: false,\n };\n }\n\n private log(message: string): void {\n if (this.verbose) {\n console.log(message);\n }\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import * as path from \"node:path\";\nimport { fileExists } from \"../utils/file-utils.js\";\nimport { AutoDiscover } from \"../core/auto-discover.js\";\n\nexport interface DiscoverCommandOptions {\n targetPath?: string;\n verbose?: boolean;\n}\n\nexport async function discover(options: DiscoverCommandOptions = {}): Promise<void> {\n const targetPath = path.resolve(options.targetPath || process.cwd());\n const verbose = options.verbose ?? true; // Default to verbose for CLI\n\n // Validate target path\n const exists = await fileExists(targetPath);\n if (!exists) {\n console.error(`Error: Target path does not exist: ${targetPath}`);\n process.exit(1);\n }\n\n // Check if CCKB is installed\n const kbPath = path.join(targetPath, \"cc-knowledge-base\");\n const kbExists = await fileExists(kbPath);\n if (!kbExists) {\n console.error(\"Error: CCKB is not installed in this project.\");\n console.error(\"Run 'cckb init' first to install CCKB.\");\n process.exit(1);\n }\n\n try {\n const autoDiscover = new AutoDiscover(targetPath, verbose);\n const result = await autoDiscover.discover();\n\n if (!result.integrated) {\n console.error(\"\\nWarning: Vault integration failed. Check the logs above.\");\n process.exit(1);\n }\n\n console.log(`\\nVault populated at: ${kbPath}/vault/`);\n } catch (error) {\n console.error(\"Discovery failed:\", error);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["fs","path","resolve","path"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IndexManager
3
- } from "../chunk-NOCXYKIE.js";
3
+ } from "../chunk-4IQV2TQE.js";
4
4
  import {
5
5
  fileExists,
6
6
  getStatePath,
@@ -8,7 +8,7 @@ import {
8
8
  loadConfig,
9
9
  readJSON,
10
10
  writeJSON
11
- } from "../chunk-E2IJSPVB.js";
11
+ } from "../chunk-FRETJBP5.js";
12
12
 
13
13
  // src/hooks/notification.ts
14
14
  import * as path from "path";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ConversationManager
3
- } from "../chunk-XQXIDTUW.js";
3
+ } from "../chunk-HP5YVMZ6.js";
4
4
  import {
5
5
  loadConfig
6
- } from "../chunk-E2IJSPVB.js";
6
+ } from "../chunk-FRETJBP5.js";
7
7
 
8
8
  // src/hooks/post-tool-use.ts
9
9
  async function handlePostToolUse() {
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ConversationManager
3
- } from "../chunk-XQXIDTUW.js";
3
+ } from "../chunk-HP5YVMZ6.js";
4
4
  import {
5
5
  IndexManager
6
- } from "../chunk-NOCXYKIE.js";
6
+ } from "../chunk-4IQV2TQE.js";
7
7
  import {
8
8
  getVaultPath
9
- } from "../chunk-E2IJSPVB.js";
9
+ } from "../chunk-FRETJBP5.js";
10
10
 
11
11
  // src/hooks/session-start.ts
12
12
  async function handleSessionStart() {
@@ -1,15 +1,17 @@
1
1
  import {
2
- CompactionEngine,
2
+ CompactionEngine
3
+ } from "../chunk-C6NR36YP.js";
4
+ import {
3
5
  VaultIntegrator
4
- } from "../chunk-GLYS4OA4.js";
6
+ } from "../chunk-TB2GPCQP.js";
5
7
  import {
6
8
  ConversationManager
7
- } from "../chunk-XQXIDTUW.js";
8
- import "../chunk-NOCXYKIE.js";
9
+ } from "../chunk-HP5YVMZ6.js";
10
+ import "../chunk-4IQV2TQE.js";
9
11
  import {
10
12
  getVaultPath,
11
13
  loadConfig
12
- } from "../chunk-E2IJSPVB.js";
14
+ } from "../chunk-FRETJBP5.js";
13
15
 
14
16
  // src/hooks/stop.ts
15
17
  async function handleStop() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/stop.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\nimport { CompactionEngine } from \"../core/compaction-engine.js\";\nimport { VaultIntegrator } from \"../core/vault-integrator.js\";\nimport { loadConfig, getVaultPath } from \"../utils/config.js\";\n\ninterface StopInput {\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n}\n\nexport async function handleStop(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: StopInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n\n // Get active session\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getActiveSessionId();\n\n if (!sessionId) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n return;\n }\n\n // Run compaction asynchronously (don't block session exit)\n runCompactionAsync(projectPath, sessionId).catch(() => {\n // Silent failure\n });\n\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n console.log(JSON.stringify(output));\n } catch (error) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function runCompactionAsync(\n projectPath: string,\n sessionId: string\n): Promise<void> {\n const config = await loadConfig(projectPath);\n\n if (config.compaction.trigger !== \"session_end\") {\n return;\n }\n\n // Get conversation content\n const manager = new ConversationManager(projectPath);\n const conversation = await manager.getFullConversation(sessionId);\n\n if (!conversation || conversation.length < 100) {\n // Skip empty or very short conversations\n return;\n }\n\n // Run compaction\n const compactionEngine = new CompactionEngine(projectPath);\n const summary = await compactionEngine.compact(sessionId, conversation);\n\n if (!summary) {\n return;\n }\n\n // Integrate into vault if enabled\n if (config.vault.autoIntegrate) {\n const vaultPath = getVaultPath(projectPath);\n const integrator = new VaultIntegrator(vaultPath);\n await integrator.integrate(summary);\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,eAAsB,aAA4B;AAChD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAAkB,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAErD,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAG5C,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB;AAEnD,QAAI,CAAC,WAAW;AACd,cAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AACpE;AAAA,IACF;AAGA,uBAAmB,aAAa,SAAS,EAAE,MAAM,MAAM;AAAA,IAEvD,CAAC;AAED,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAe,mBACb,aACA,WACe;AACf,QAAM,SAAS,MAAM,WAAW,WAAW;AAE3C,MAAI,OAAO,WAAW,YAAY,eAAe;AAC/C;AAAA,EACF;AAGA,QAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,QAAM,eAAe,MAAM,QAAQ,oBAAoB,SAAS;AAEhE,MAAI,CAAC,gBAAgB,aAAa,SAAS,KAAK;AAE9C;AAAA,EACF;AAGA,QAAM,mBAAmB,IAAI,iBAAiB,WAAW;AACzD,QAAM,UAAU,MAAM,iBAAiB,QAAQ,WAAW,YAAY;AAEtE,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,eAAe;AAC9B,UAAM,YAAY,aAAa,WAAW;AAC1C,UAAM,aAAa,IAAI,gBAAgB,SAAS;AAChD,UAAM,WAAW,UAAU,OAAO;AAAA,EACpC;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../src/hooks/stop.ts"],"sourcesContent":["import { ConversationManager } from \"../core/conversation-manager.js\";\nimport { CompactionEngine } from \"../core/compaction-engine.js\";\nimport { VaultIntegrator } from \"../core/vault-integrator.js\";\nimport { loadConfig, getVaultPath } from \"../utils/config.js\";\n\ninterface StopInput {\n cwd?: string;\n}\n\ninterface HookOutput {\n continue: boolean;\n suppressOutput?: boolean;\n}\n\nexport async function handleStop(): Promise<void> {\n try {\n // Read input from stdin\n const input = await readStdin();\n const data: StopInput = input ? JSON.parse(input) : {};\n\n const projectPath = data.cwd || process.cwd();\n\n // Get active session\n const manager = new ConversationManager(projectPath);\n const sessionId = await manager.getActiveSessionId();\n\n if (!sessionId) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n return;\n }\n\n // Run compaction asynchronously (don't block session exit)\n runCompactionAsync(projectPath, sessionId).catch(() => {\n // Silent failure\n });\n\n const output: HookOutput = {\n continue: true,\n suppressOutput: true,\n };\n\n console.log(JSON.stringify(output));\n } catch (error) {\n console.log(JSON.stringify({ continue: true, suppressOutput: true }));\n }\n}\n\nasync function runCompactionAsync(\n projectPath: string,\n sessionId: string\n): Promise<void> {\n const config = await loadConfig(projectPath);\n\n if (config.compaction.trigger !== \"session_end\") {\n return;\n }\n\n // Get conversation content\n const manager = new ConversationManager(projectPath);\n const conversation = await manager.getFullConversation(sessionId);\n\n if (!conversation || conversation.length < 100) {\n // Skip empty or very short conversations\n return;\n }\n\n // Run compaction\n const compactionEngine = new CompactionEngine(projectPath);\n const summary = await compactionEngine.compact(sessionId, conversation);\n\n if (!summary) {\n return;\n }\n\n // Integrate into vault if enabled\n if (config.vault.autoIntegrate) {\n const vaultPath = getVaultPath(projectPath);\n const integrator = new VaultIntegrator(vaultPath);\n await integrator.integrate(summary);\n }\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let data = \"\";\n\n if (process.stdin.isTTY) {\n resolve(\"\");\n return;\n }\n\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim());\n });\n\n setTimeout(() => {\n resolve(data.trim());\n }, 1000);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,eAAsB,aAA4B;AAChD,MAAI;AAEF,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,OAAkB,QAAQ,KAAK,MAAM,KAAK,IAAI,CAAC;AAErD,UAAM,cAAc,KAAK,OAAO,QAAQ,IAAI;AAG5C,UAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,UAAM,YAAY,MAAM,QAAQ,mBAAmB;AAEnD,QAAI,CAAC,WAAW;AACd,cAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AACpE;AAAA,IACF;AAGA,uBAAmB,aAAa,SAAS,EAAE,MAAM,MAAM;AAAA,IAEvD,CAAC;AAED,UAAM,SAAqB;AAAA,MACzB,UAAU;AAAA,MACV,gBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,YAAQ,IAAI,KAAK,UAAU,EAAE,UAAU,MAAM,gBAAgB,KAAK,CAAC,CAAC;AAAA,EACtE;AACF;AAEA,eAAe,mBACb,aACA,WACe;AACf,QAAM,SAAS,MAAM,WAAW,WAAW;AAE3C,MAAI,OAAO,WAAW,YAAY,eAAe;AAC/C;AAAA,EACF;AAGA,QAAM,UAAU,IAAI,oBAAoB,WAAW;AACnD,QAAM,eAAe,MAAM,QAAQ,oBAAoB,SAAS;AAEhE,MAAI,CAAC,gBAAgB,aAAa,SAAS,KAAK;AAE9C;AAAA,EACF;AAGA,QAAM,mBAAmB,IAAI,iBAAiB,WAAW;AACzD,QAAM,UAAU,MAAM,iBAAiB,QAAQ,WAAW,YAAY;AAEtE,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AAGA,MAAI,OAAO,MAAM,eAAe;AAC9B,UAAM,YAAY,aAAa,WAAW;AAC1C,UAAM,aAAa,IAAI,gBAAgB,SAAS;AAChD,UAAM,WAAW,UAAU,OAAO;AAAA,EACpC;AACF;AAEA,eAAe,YAA6B;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,OAAO;AAEX,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,EAAE;AACV;AAAA,IACF;AAEA,YAAQ,MAAM,YAAY,MAAM;AAChC,YAAQ,MAAM,GAAG,QAAQ,CAAC,UAAU;AAClC,cAAQ;AAAA,IACV,CAAC;AACD,YAAQ,MAAM,GAAG,OAAO,MAAM;AAC5B,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,CAAC;AAED,eAAW,MAAM;AACf,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,GAAG,GAAI;AAAA,EACT,CAAC;AACH;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ConversationManager
3
- } from "../chunk-XQXIDTUW.js";
4
- import "../chunk-E2IJSPVB.js";
3
+ } from "../chunk-HP5YVMZ6.js";
4
+ import "../chunk-FRETJBP5.js";
5
5
 
6
6
  // src/hooks/user-prompt.ts
7
7
  async function handleUserPrompt() {
package/dist/index.d.ts CHANGED
@@ -3,6 +3,12 @@ interface InstallOptions {
3
3
  }
4
4
  declare function install(targetPath: string, options?: InstallOptions): Promise<void>;
5
5
 
6
+ interface DiscoverCommandOptions {
7
+ targetPath?: string;
8
+ verbose?: boolean;
9
+ }
10
+ declare function discover(options?: DiscoverCommandOptions): Promise<void>;
11
+
6
12
  declare class ConversationManager {
7
13
  private projectPath;
8
14
  constructor(projectPath: string);
@@ -125,6 +131,98 @@ declare class IndexManager {
125
131
  private parseTableToOverview;
126
132
  }
127
133
 
134
+ interface DiscoverOptions {
135
+ maxFiles?: number;
136
+ maxChunkSize?: number;
137
+ verbose?: boolean;
138
+ }
139
+ interface DiscoveryResult {
140
+ summary: Summary;
141
+ filesAnalyzed: number;
142
+ chunksProcessed: number;
143
+ duration: number;
144
+ integrated: boolean;
145
+ }
146
+ declare class AutoDiscover {
147
+ private projectPath;
148
+ private verbose;
149
+ constructor(projectPath: string, verbose?: boolean);
150
+ discover(options?: DiscoverOptions): Promise<DiscoveryResult>;
151
+ private analyzeChunk;
152
+ private runWithProgressIndicators;
153
+ private parseResponse;
154
+ private parseEntities;
155
+ private parseArchitecture;
156
+ private parseServices;
157
+ private parseKnowledge;
158
+ private mergeSummaries;
159
+ private fallbackDiscovery;
160
+ private createEmptyResult;
161
+ private log;
162
+ private delay;
163
+ }
164
+
165
+ type FileCategory = "entry" | "model" | "service" | "util" | "config" | "test" | "other";
166
+ interface CollectedFile {
167
+ path: string;
168
+ absolutePath: string;
169
+ language: string;
170
+ category: FileCategory;
171
+ size: number;
172
+ priority: number;
173
+ }
174
+ interface CollectionResult {
175
+ files: CollectedFile[];
176
+ languages: string[];
177
+ projectType: string;
178
+ totalFilesScanned: number;
179
+ }
180
+ interface CollectOptions {
181
+ maxFiles?: number;
182
+ excludePatterns?: string[];
183
+ priorityPatterns?: string[];
184
+ supportedLanguages?: string[];
185
+ }
186
+ declare class FileCollector {
187
+ private projectPath;
188
+ constructor(projectPath: string);
189
+ collect(options?: CollectOptions): Promise<CollectionResult>;
190
+ detectLanguages(): Promise<{
191
+ languages: string[];
192
+ projectType: string;
193
+ }>;
194
+ private loadIgnorePatterns;
195
+ private shouldIgnore;
196
+ private matchPattern;
197
+ private categorizeFile;
198
+ private calculatePriority;
199
+ private walkDirectory;
200
+ }
201
+
202
+ interface FileChunk {
203
+ files: CollectedFile[];
204
+ content: string;
205
+ estimatedTokens: number;
206
+ index: number;
207
+ totalChunks: number;
208
+ }
209
+ interface ChunkOptions {
210
+ maxChunkSize?: number;
211
+ }
212
+ declare class ChunkManager {
213
+ private files;
214
+ private maxChunkSize;
215
+ private chunks;
216
+ constructor(files: CollectedFile[], options?: ChunkOptions);
217
+ prepareChunks(): Promise<FileChunk[]>;
218
+ private createChunk;
219
+ private formatFileContent;
220
+ private truncateContent;
221
+ getTotalChunks(): number;
222
+ getChunkSummary(): string;
223
+ iterateChunks(): AsyncGenerator<FileChunk>;
224
+ }
225
+
128
226
  interface CCKBConfig {
129
227
  compaction: {
130
228
  trigger: "session_end" | "size" | "messages" | "manual";
@@ -144,6 +242,13 @@ interface CCKBConfig {
144
242
  enabled: boolean;
145
243
  contextDepth: number;
146
244
  };
245
+ discover: {
246
+ maxFiles: number;
247
+ maxChunkSize: number;
248
+ excludePatterns: string[];
249
+ priorityPatterns: string[];
250
+ supportedLanguages: string[];
251
+ };
147
252
  }
148
253
 
149
- export { type CCKBConfig, CompactionEngine, ConversationManager, EntityDetector, IndexManager, VaultIntegrator, install };
254
+ export { AutoDiscover, type CCKBConfig, ChunkManager, CompactionEngine, ConversationManager, EntityDetector, FileCollector, IndexManager, VaultIntegrator, discover, install };
package/dist/index.js CHANGED
@@ -1,24 +1,34 @@
1
1
  import {
2
+ AutoDiscover,
3
+ ChunkManager,
4
+ FileCollector,
5
+ discover,
2
6
  install
3
- } from "./chunk-3KGJEBKK.js";
7
+ } from "./chunk-XOV27B2L.js";
8
+ import {
9
+ CompactionEngine
10
+ } from "./chunk-C6NR36YP.js";
4
11
  import {
5
- CompactionEngine,
6
12
  EntityDetector,
7
13
  VaultIntegrator
8
- } from "./chunk-GLYS4OA4.js";
14
+ } from "./chunk-TB2GPCQP.js";
9
15
  import {
10
16
  ConversationManager
11
- } from "./chunk-XQXIDTUW.js";
17
+ } from "./chunk-HP5YVMZ6.js";
12
18
  import {
13
19
  IndexManager
14
- } from "./chunk-NOCXYKIE.js";
15
- import "./chunk-E2IJSPVB.js";
20
+ } from "./chunk-4IQV2TQE.js";
21
+ import "./chunk-FRETJBP5.js";
16
22
  export {
23
+ AutoDiscover,
24
+ ChunkManager,
17
25
  CompactionEngine,
18
26
  ConversationManager,
19
27
  EntityDetector,
28
+ FileCollector,
20
29
  IndexManager,
21
30
  VaultIntegrator,
31
+ discover,
22
32
  install
23
33
  };
24
34
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cckb",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Claude Code Knowledge Base - Automatic project knowledge capture for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,207 +0,0 @@
1
- import {
2
- DEFAULT_CONFIG,
3
- ensureDir,
4
- fileExists,
5
- readJSON,
6
- readTextFile,
7
- writeJSON,
8
- writeTextFile
9
- } from "./chunk-E2IJSPVB.js";
10
-
11
- // src/cli/install.ts
12
- import * as fs from "fs/promises";
13
- import * as fsSync from "fs";
14
- import * as path from "path";
15
- import { fileURLToPath } from "url";
16
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
17
- function findPackageRoot() {
18
- let dir = __dirname;
19
- for (let i = 0; i < 5; i++) {
20
- const packageJson = path.join(dir, "package.json");
21
- if (fsSync.existsSync(packageJson)) {
22
- return dir;
23
- }
24
- dir = path.dirname(dir);
25
- }
26
- return path.resolve(__dirname, "../..");
27
- }
28
- var PACKAGE_ROOT = findPackageRoot();
29
- var TEMPLATES_DIR = path.join(PACKAGE_ROOT, "templates");
30
- async function install(targetPath, options = {}) {
31
- const resolvedPath = path.resolve(targetPath);
32
- console.log(`Installing CCKB to: ${resolvedPath}`);
33
- await validateTargetPath(resolvedPath);
34
- await checkExistingInstallation(resolvedPath, options.force);
35
- await createDirectoryStructure(resolvedPath);
36
- await copyTemplateFiles(resolvedPath);
37
- await createConfigFile(resolvedPath);
38
- await installHooks(resolvedPath);
39
- await updateClaudeMd(resolvedPath);
40
- await updateGitignore(resolvedPath);
41
- console.log("\nCCKB installed successfully!");
42
- console.log("\nNext steps:");
43
- console.log(" 1. Review cc-knowledge-base/vault/ structure");
44
- console.log(" 2. Check .claude/settings.json for hook configuration");
45
- console.log(" 3. Start a new Claude Code session to begin capturing knowledge");
46
- }
47
- async function validateTargetPath(targetPath) {
48
- const exists = await fileExists(targetPath);
49
- if (!exists) {
50
- throw new Error(`Target path does not exist: ${targetPath}`);
51
- }
52
- const stats = await fs.stat(targetPath);
53
- if (!stats.isDirectory()) {
54
- throw new Error(`Target path is not a directory: ${targetPath}`);
55
- }
56
- }
57
- async function checkExistingInstallation(targetPath, force) {
58
- const kbPath = path.join(targetPath, "cc-knowledge-base");
59
- const exists = await fileExists(kbPath);
60
- if (exists && !force) {
61
- throw new Error(
62
- "CCKB is already installed in this project. Use --force to reinstall."
63
- );
64
- }
65
- }
66
- async function createDirectoryStructure(targetPath) {
67
- const directories = [
68
- "cc-knowledge-base",
69
- "cc-knowledge-base/conversations",
70
- "cc-knowledge-base/vault",
71
- "cc-knowledge-base/vault/entities",
72
- "cc-knowledge-base/vault/apps",
73
- "cc-knowledge-base/vault/modules",
74
- "cc-knowledge-base/.cckb-state"
75
- ];
76
- for (const dir of directories) {
77
- await ensureDir(path.join(targetPath, dir));
78
- }
79
- console.log(" Created directory structure");
80
- }
81
- async function copyTemplateFiles(targetPath) {
82
- const vaultFiles = [
83
- { src: "vault/INDEX.md", dest: "cc-knowledge-base/vault/INDEX.md" },
84
- {
85
- src: "vault/architecture.md",
86
- dest: "cc-knowledge-base/vault/architecture.md"
87
- },
88
- {
89
- src: "vault/general-knowledge.md",
90
- dest: "cc-knowledge-base/vault/general-knowledge.md"
91
- },
92
- {
93
- src: "vault/entities/INDEX.md",
94
- dest: "cc-knowledge-base/vault/entities/INDEX.md"
95
- },
96
- {
97
- src: "vault/apps/INDEX.md",
98
- dest: "cc-knowledge-base/vault/apps/INDEX.md"
99
- },
100
- {
101
- src: "vault/modules/INDEX.md",
102
- dest: "cc-knowledge-base/vault/modules/INDEX.md"
103
- }
104
- ];
105
- for (const file of vaultFiles) {
106
- const srcPath = path.join(TEMPLATES_DIR, file.src);
107
- const destPath = path.join(targetPath, file.dest);
108
- const content = await readTextFile(srcPath);
109
- if (content) {
110
- await writeTextFile(destPath, content);
111
- }
112
- }
113
- await writeTextFile(
114
- path.join(targetPath, "cc-knowledge-base/conversations/.gitkeep"),
115
- ""
116
- );
117
- console.log(" Copied vault template files");
118
- }
119
- async function createConfigFile(targetPath) {
120
- const configPath = path.join(
121
- targetPath,
122
- "cc-knowledge-base",
123
- ".cckb-config.json"
124
- );
125
- await writeJSON(configPath, DEFAULT_CONFIG);
126
- console.log(" Created configuration file");
127
- }
128
- async function installHooks(targetPath) {
129
- const claudeDir = path.join(targetPath, ".claude");
130
- const settingsPath = path.join(claudeDir, "settings.json");
131
- await ensureDir(claudeDir);
132
- let settings = await readJSON(settingsPath) || {};
133
- const templatePath = path.join(TEMPLATES_DIR, "settings.json.tmpl");
134
- const hookSettings = await readJSON(
135
- templatePath
136
- );
137
- if (!hookSettings) {
138
- throw new Error("Failed to load hook template");
139
- }
140
- const existingHooks = settings.hooks || {};
141
- const newHooks = hookSettings.hooks;
142
- settings.hooks = mergeHooks(existingHooks, newHooks);
143
- await writeJSON(settingsPath, settings);
144
- console.log(" Installed hook configuration");
145
- }
146
- function mergeHooks(existing, incoming) {
147
- const merged = { ...existing };
148
- for (const [hookType, hooks] of Object.entries(incoming)) {
149
- if (!merged[hookType]) {
150
- merged[hookType] = [];
151
- }
152
- for (const hook of hooks) {
153
- const hookObj = hook;
154
- const command = hookObj.command;
155
- if (command?.includes("cckb")) {
156
- merged[hookType] = merged[hookType].filter((h) => {
157
- const existingCmd = h.command;
158
- return !existingCmd?.includes("cckb");
159
- });
160
- }
161
- merged[hookType].push(hook);
162
- }
163
- }
164
- return merged;
165
- }
166
- async function updateClaudeMd(targetPath) {
167
- const claudeMdPath = path.join(targetPath, "CLAUDE.md");
168
- const templatePath = path.join(TEMPLATES_DIR, "CLAUDE.md.tmpl");
169
- const template = await readTextFile(templatePath);
170
- if (!template) {
171
- throw new Error("Failed to load CLAUDE.md template");
172
- }
173
- const marker = "## Project Knowledge Base (CCKB)";
174
- let existing = await readTextFile(claudeMdPath);
175
- if (existing) {
176
- if (existing.includes(marker)) {
177
- const regex = /## Project Knowledge Base \(CCKB\)[\s\S]*?(?=\n## |$)/;
178
- existing = existing.replace(regex, template.trim());
179
- } else {
180
- existing = existing.trimEnd() + "\n\n" + template;
181
- }
182
- await writeTextFile(claudeMdPath, existing);
183
- } else {
184
- await writeTextFile(claudeMdPath, template);
185
- }
186
- console.log(" Updated CLAUDE.md with vault directives");
187
- }
188
- async function updateGitignore(targetPath) {
189
- const gitignorePath = path.join(targetPath, ".gitignore");
190
- const entries = [
191
- "",
192
- "# CCKB state files",
193
- "cc-knowledge-base/.cckb-state/"
194
- ];
195
- let existing = await readTextFile(gitignorePath) || "";
196
- if (existing.includes("cc-knowledge-base/.cckb-state/")) {
197
- return;
198
- }
199
- existing = existing.trimEnd() + "\n" + entries.join("\n") + "\n";
200
- await writeTextFile(gitignorePath, existing);
201
- console.log(" Updated .gitignore");
202
- }
203
-
204
- export {
205
- install
206
- };
207
- //# sourceMappingURL=chunk-3KGJEBKK.js.map