/** * Index Manager — 知识配置层模块。 * * 职责边界: * - 负责:normalizeType 等 知识配置层职责 * - 不负责:不属于本模块的职责由对应模块承担 * * 被谁调用:上层模块按需调用 * 调用谁:promises、node:fs、node:path、gray-matter、yaml、index * * 数据流:输入 → normalizeType 处理 → 输出 * 持久化:读写本地文件(详见代码内路径) */ import type { ProjectConfig, KnowledgeEntry } from "../../types/index.js"; /** * 校验知识类型。未知值不回退,否则拼写错误会被当成 pattern 并产生错误查询结果。 * * @param raw - 原始 type 或 asset_kind 字符串 * @returns 当前合法知识类型 */ export declare function normalizeType(raw: string): KnowledgeEntry["type"]; /** 索引 schema 版本号 — 增量变更时递增 */ export declare const INDEX_SCHEMA_VERSION = 1; /** * 知识索引构建选项。 */ export interface KnowledgeIndexOptions { /** 是否启用文件监听,默认 true */ watch?: boolean; } /** * 知识索引管理器。 * @description 负责扫描、严格解析、索引知识文件(Markdown 和 YAML), * 文件变化后按同一构建路径重建,并提供只读查询。 */ export declare class KnowledgeIndexManager { private config; private index; private watcher; private rebuildTimer; private watchingStarted; private watchEnabled; private closed; private rebuildInProgress; private rebuildRequested; private buildPromise; private ready; private parseDiagnostics; private watchDiagnostic; private invertedIndex; /** * 创建知识索引管理器实例。 * @param config - 项目配置对象 * @param options - 索引构建选项 */ constructor(config: ProjectConfig, options?: KnowledgeIndexOptions); /** * 构建知识索引。 * @description 扫描全局和项目知识目录,解析所有知识文件并建立索引。 * 首次构建时启动文件监听。 */ build(): Promise; /** 执行一次完整、原子可见的索引构建;并发请求由 build 串行合并。 */ private buildOnce; /** * 关闭索引管理器,停止文件监听并清理资源。 */ close(): Promise; /** * 合同门禁过滤 — 项目目录和全局目录下的条目。 * 内置知识资产不再复制到项目目录,所以项目/全局目录下的条目都是用户自建的,直接放行。 */ private filterByContractGate; /** * 内置资产门禁过滤 — 从 SoloForge templates/knowledge/ 直接读取的条目。 * 只检查合同可见性和技术栈适用性,不做 hash 比对(直接读源头,无需防篡改)。 */ private filterBuiltinEntries; /** 从绝对路径提取 templates/ 下的相对路径 */ private toBuiltinRelPath; private getProjectTechStack; /** * 启动文件监听(内部方法)。 * @description 使用 chokidar 监听全局和项目知识目录的文件变更, * 变更后 300ms 防抖执行增量更新。 */ private startWatching; /** * 重建倒排索引(每次 build / 增量更新后调用)。 * 索引键: scope/product/type/stage → 条目 id 集合;activeIds 仅含 status="active"。 */ private rebuildInvertedIndex; /** * 用固定优先级解决跨来源 ID 冲突:builtin > project > global。 * 同一来源内重复 ID 无法判断意图,全部排除;任何被排除条目都进入 audit 诊断。 */ private resolveDuplicateIds; /** * 向倒排索引添加映射关系(通用辅助方法)。 */ private addToIndex; /** * 为单个条目提取关键词并填充到 byKeyword 倒排索引。 * 关键词来源:name + triggers + keywords + body 的空格分词(纳入 body 捕获正文中的英文/技术术语, * 如 Idempotency/payment/JWT——原仅 name+triggers 致术语只在正文时无法召回,AI 误判"无约束")。 * 中文子串索引对 name 和 keywords 的每个词做(keywords 即任务侧中文检索词的机制化通道); * 不对 body 全文做中文子串索引(O(n²) 膨胀 + 散文噪声匹配,明确放弃)。 */ private indexKeywordsForEntry; /** * 解析单个知识文件(内部方法)。 * @description 根据文件扩展名选择解析器:Markdown 使用 gray-matter 解析 frontmatter, * YAML 使用 YAML.parse 解析。 * @param filePath - 文件路径 * @returns 解析后的知识条目数组 */ private parseFile; /** 只把 guidance/knowledge 或无 kind 的知识条目放入查询索引。 */ private shouldIndexKnowledgeData; /** * 按条件查询知识条目。 * @description 支持按 scope、products、type 过滤,以及按 keywords 关键词匹配和排序。 * 只返回 status 为 active 的条目,默认限制返回 5 条。 * @param filters - 查询过滤条件 * @param filters.scope - 作用域过滤列表 * @param filters.products - 产品过滤列表 * @param filters.type - 条目类型过滤 * @param filters.keywords - 关键词列表(用于模糊匹配 name 和 when 字段) * @param filters.limit - 最大返回条数,默认 5 * @returns 匹配的知识条目数组 */ query(filters: { scope?: string[]; products?: string[]; type?: string; keywords?: string[]; limit?: number; domain?: string[]; }): KnowledgeEntry[]; /** * 根据 ID 获取知识条目。 * @param id - 条目 ID * @returns 匹配的知识条目,未找到则返回 undefined */ getEntry(id: string): KnowledgeEntry | undefined; /** * 获取所有知识条目(按来源分组)。 * @returns 包含全局和项目知识条目的对象 */ getAllEntries(): { global: KnowledgeEntry[]; project: KnowledgeEntry[]; builtin: KnowledgeEntry[]; }; /** 返回构建时被拒绝的知识文件,供只读 audit 向用户解释。 */ getParseDiagnostics(): Array<{ file_path: string; message: string; }>; /** 首次完整构建成功后才允许产品层把查询结果视为权威。 */ isReady(): boolean; /** * 重新加载知识索引。 * @description 完全重建索引,重新扫描所有知识文件。 */ reload(): Promise; /** * 扫描目录中的知识文件(内部方法)。 * @description 递归遍历目录,解析所有 .md 和 .yaml/.yml 文件。 * @param dir - 要扫描的目录路径 * @returns 解析后的知识条目数组 */ private scanDirectory; /** * 将原始数据解析为知识条目(内部方法)。 * @description 从 frontmatter/解析数据中提取字段;错误枚举和错误形状拒绝进入索引。 * @param data - 解析后的 frontmatter 或 YAML 数据 * @param filePath - 文件路径 * @param body - Markdown 正文内容(可选) * @returns 解析后的知识条目 */ private parseEntry; /** * 根据文件路径推断知识条目类型(内部方法)。 * @description 根据路径中包含的目录名推断条目类型。 * inferType 与 normalizeType 的职责不同: * - normalizeType: 将 frontmatter 中的 type 字段值映射到标准枚举(字段级映射) * - inferType: 当 frontmatter 中 type/asset_kind 缺失时,根据文件路径目录名推断类型(路径级推断) * 两者是互补关系,parseEntry 中优先使用 normalizeType,仅当两者都无法命中时才 fallback 到 inferType。 * @param filePath - 文件路径 * @returns 推断出的知识条目类型 */ private inferType; /** * 递归遍历目录获取文件列表(内部方法)。 * @description 递归遍历目录,收集所有 .md 和 .yaml/.yml 文件路径。 * 自动跳过 SKIP_DIRS 中定义的系统目录。 * @param dir - 要遍历的目录 * @param maxDepth - 最大递归深度,默认 10 * @param currentDepth - 当前递归深度 * @returns 文件路径数组 */ private walkFiles; }