UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

381 lines (380 loc) 12 kB
/** * WikiGenerator Repo Wiki 生成引擎 (V3 Content-First) * * 自动分析项目代码结构,生成结构化的项目文档 Wiki。 * 结合 AutoSnippet AST 深度分析能力(ProjectGraph、CodeEntityGraph、SPM 依赖图) * 做到深层代码洞察。 * * V3 核心设计: "内容驱动 + AI 优先" * 1. 数据收集 (Scan AST SPM KB) * 2. 主题发现 分析数据丰富度,动态决定生成哪些文章 * 3. AI 优先撰写 直接由 AI 写完整文章,非骨架+润色 * 4. 质量关卡 内容不足 MIN_ARTICLE_CHARS 则跳过该文章 * 5. 降级保底 AI 不可用时使用丰富模板内容 * * Wiki 文档结构 (动态生成,按项目特征而异): * AutoSnippet/wiki/ * ├── index.md 项目概述 (始终生成) * ├── architecture.md 架构总览 (多模块项目) * ├── getting-started.md 快速上手 (有构建系统时) * ├── modules/ * ├── {ModuleName}.md 模块深度文档 (仅内容丰富的模块) * └── ... * ├── patterns.md 代码模式 (有知识库 Recipe 时) * ├── patterns/ 按分类拆分 (Recipe 较多时) * └── {category}.md * ├── protocols.md 协议参考 (协议较多时) * ├── documents/ 同步的 Cursor 端文档 * └── meta.json Wiki 元数据 * * @module WikiGenerator */ import { type WikiData } from './WikiRenderers.js'; /** Resolved WikiGenerator options */ interface WikiOptions { wikiDir: string; language: string; maxFiles: number; includeRecipes: boolean; includeDepGraph: boolean; includeComponents: boolean; [key: string]: unknown; } /** WikiGenerator constructor dependencies */ export interface WikiDeps { projectRoot: string; moduleService?: WikiModuleService | null; knowledgeService?: WikiKnowledgeService | null; projectGraph?: WikiProjectGraph | null; codeEntityGraph?: Record<string, unknown> | null; aiProvider?: WikiAiProvider | null; onProgress?: (phase: string, progress: number, message: string) => void; options?: Partial<WikiOptions>; [key: string]: unknown; } /** Minimal ProjectGraph interface */ export interface WikiProjectGraph { getOverview(): Record<string, unknown>; getAllClassNames(): string[]; getAllProtocolNames(): string[]; getClassInfo(name: string): { filePath?: string; } | null; getProtocolInfo(name: string): { filePath?: string; } | null; } /** Minimal ModuleService interface */ export interface WikiModuleService { load(): Promise<void>; listTargets(): Promise<WikiModuleTarget[]>; getDependencyGraph?(opts: Record<string, unknown>): Promise<unknown>; getProjectInfo(): Record<string, unknown>; } /** Module target descriptor */ interface WikiModuleTarget { name: string; path?: string; type?: string; dependencies?: unknown[]; info?: { dependencies?: unknown[]; path?: string; [key: string]: unknown; }; [key: string]: unknown; } /** Minimal KnowledgeService interface */ export interface WikiKnowledgeService { list(filter: Record<string, unknown>): Promise<{ data?: Record<string, unknown>[]; items?: Record<string, unknown>[]; [key: string]: unknown; }>; getStats?(): Promise<Record<string, unknown> | null>; } /** Minimal AiProvider interface */ export interface WikiAiProvider { chat(prompt: string, options: Record<string, unknown>): Promise<string>; } /** Topic descriptor from _discoverTopics */ interface WikiTopic { id: string; path: string; title: string; type: string; priority: number; _moduleData?: Record<string, unknown>; _patternData?: Record<string, unknown>; _folderProfiles?: Record<string, unknown>[]; _folderProfile?: Record<string, unknown>; _allTopics?: WikiTopic[]; [key: string]: unknown; } /** File write result */ interface WikiFileResult { path: string; hash: string; size: number; source?: string; polished?: boolean; } /** Scan project result */ interface ProjectScanInfo { name: string; root: string; buildSystems: { eco: string; buildTool: string; }[]; sourceFiles: string[]; languages: Record<string, number>; langProfile: Record<string, unknown> | null; primaryLanguage: string; hasPackageSwift: boolean; hasPodfile: boolean; hasXcodeproj: boolean; sourceFilesByModule: Record<string, string[]>; [key: string]: unknown; } export declare const WikiPhase: Readonly<{ INIT: "init"; SCAN: "scan"; AST_ANALYZE: "ast-analyze"; SPM_PARSE: "spm-parse"; KNOWLEDGE: "knowledge"; GENERATE: "generate"; AI_COMPOSE: "ai-compose"; SYNC_DOCS: "sync-docs"; DEDUP: "dedup"; FINALIZE: "finalize"; }>; export declare class WikiGenerator { projectRoot: string; wikiDir: string; _aborted: boolean; aiProvider: WikiAiProvider | null; codeEntityGraph: Record<string, unknown> | null; knowledgeService: WikiKnowledgeService | null; metaPath: string; moduleService: WikiModuleService | null; onProgress: (phase: string, progress: number, message: string) => void; options: WikiOptions; projectGraph: WikiProjectGraph | null; /** * @param [deps.spmService] 向后兼容 * @param [deps.onProgress] (phase, progress, message) => void */ constructor(deps: WikiDeps); /** 全量生成 Wiki */ generate(): Promise<{ success: boolean; error: string; duration: number; } | { success: boolean; filesGenerated: number; aiComposed: number; syncedDocs: number; dedup: { removed: string[]; kept: number; }; duration: number; wikiDir: string; meta: { dedup?: { removed: string[]; kept: number; } | undefined; version: string; generator: string; generatedAt: string; duration: number; projectRoot: string; language: string; files: { polished?: boolean | undefined; source?: string | undefined; path: string; hash: string; size: number; }[]; sourceHash: string; }; }>; /** 增量更新 仅重新生成变更的部分 */ update(): Promise<{ success: boolean; error: string; duration: number; } | { success: boolean; filesGenerated: number; aiComposed: number; syncedDocs: number; dedup: { removed: string[]; kept: number; }; duration: number; wikiDir: string; meta: { dedup?: { removed: string[]; kept: number; } | undefined; version: string; generator: string; generatedAt: string; duration: number; projectRoot: string; language: string; files: { polished?: boolean | undefined; source?: string | undefined; path: string; hash: string; size: number; }[]; sourceHash: string; }; } | { success: boolean; filesGenerated: number; duration: number; upToDate: boolean; }>; /** 中止当前生成 */ abort(): void; /** 获取当前 Wiki 状态 */ getStatus(): { exists: boolean; generatedAt?: undefined; filesCount?: undefined; version?: undefined; hasChanges?: undefined; } | { exists: boolean; generatedAt: any; filesCount: any; version: any; hasChanges: boolean; }; /** 扫描项目基本信息 */ _scanProject(): Promise<ProjectScanInfo>; /** AST 分析 利用已有 ProjectGraph 或重新构建 */ _analyzeAST(): Promise<{ overview: Record<string, unknown>; classes: string[]; protocols: string[]; classNamesByModule: Record<string, string[]>; protocolNamesByModule: Record<string, string[]>; } | { overview: null; classes: never[]; protocols: never[]; classNamesByModule: {}; protocolNamesByModule: {}; }>; /** * 模块依赖解析 * 通过 moduleService 统一处理所有语言的模块扫描 */ _parseModules(): Promise<{ targets: never[]; depGraph: null; projectInfo?: undefined; } | { targets: WikiModuleTarget[]; depGraph: unknown; projectInfo: Record<string, unknown>; }>; /** 整合已有知识库 Recipes */ _integrateKnowledge(): Promise<{ recipes: Record<string, unknown>[]; stats: Record<string, unknown> | null; }>; /** * V3 内容驱动的主题发现 * * 核心原则: * - 没有固定的文件列表 所有文章都由数据丰富度驱动 * - 跳过数据不足的主题(避免空文档) * - 不同的项目产出不同数量/类型的文章 * * @returns >} */ _discoverTopics(projectInfo: ProjectScanInfo, astInfo: Record<string, unknown>, moduleInfo: { targets: WikiModuleTarget[]; depGraph?: unknown; projectInfo?: Record<string, unknown>; }, knowledgeInfo: { recipes: Record<string, unknown>[]; stats: Record<string, unknown> | null; }): WikiTopic[]; /** * V3 AI-first 文章撰写 * * 对每个发现的主题: * 1. 优先使用 AI 撰写完整文章 (非骨架增强!) * 2. AI 不可用时使用丰富的模板内容 * 3. 质量关卡: 最终内容不足 MIN_ARTICLE_CHARS 则跳过 * * @param topics _discoverTopics() 的输出 * @param structuredData { projectInfo, astInfo, moduleInfo, knowledgeInfo } * @returns >>} */ _composeArticles(topics: WikiTopic[], structuredData: WikiData): Promise<WikiFileResult[]>; /** * 同步 Cursor 端保存的 MD wiki 目录 * * 同步源: * 1. .cursor/skills/autosnippet-devdocs/references/ (*.md) wiki/documents/ * * @returns >} */ _syncCursorDocs(): WikiFileResult[]; /** 为同步目录生成索引页 */ _generateSyncIndex(synced: WikiFileResult[], isZh: boolean): void; _emit(phase: string, progress: number, message: string): void; _ensureDir(dir: string): void; _writeFile(relativePath: string, content: string): WikiFileResult; _writeMeta(files: WikiFileResult[], startTime: number, dedupResult: { removed: string[]; kept: number; } | null): { dedup?: { removed: string[]; kept: number; } | undefined; version: string; generator: string; generatedAt: string; duration: number; projectRoot: string; language: string; files: { polished?: boolean | undefined; source?: string | undefined; path: string; hash: string; size: number; }[]; sourceHash: string; }; _readMeta(): any; /** 检测源码是否有变更(简化:对比 sourceHash) */ _detectChanges(meta: { sourceHash?: string; [key: string]: unknown; }): boolean; /** 计算项目源文件的简易 hash(基于文件名列表 + 总大小) */ _computeSourceHash(): string; _abortedResult(): { success: boolean; error: string; duration: number; }; } export default WikiGenerator;