autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
391 lines (390 loc) • 12.9 kB
TypeScript
/**
* bootstrap-phases.js — 共享的 Phase 1-4 数据收集管线
*
* 内部 Agent (bootstrap-internal.js) 和外部 Agent (bootstrap-external.js)
* 共享完全相同的项目分析逻辑。本模块将这些逻辑提取为可复用函数,
* 消除约 300 行重复代码。
*
* Phase 概览:
* Phase 1 → 文件收集(DiscovererRegistry → 多语言项目类型检测)
* Phase 1.5 → AST 代码结构分析(tree-sitter + SFC 预处理)
* Phase 1.6 → Code Entity Graph(代码实体关系图谱)
* Phase 2.2 → Panorama 全景汇总(RoleRefiner + CouplingAnalyzer + LayerInferrer)
* Phase 2 → 依赖关系 → knowledge_edges
* Phase 2.1 → Module 实体写入 Entity Graph
* Phase 3 → Guard 规则审计
* Phase 4 → 维度条件化过滤 + Enhancement Pack + 语言画像
*
* @module bootstrap/shared/bootstrap-phases
*/
import type { ProjectAnalysisResult } from '#core/AstAnalyzer.js';
import type { GuardAudit } from '#types/project-snapshot.js';
import { type BaseDimension } from '../base-dimensions.js';
/** Logger with required info/warn (compatible with Logger singleton) */
interface PhaseLogger {
info(...args: unknown[]): void;
warn(...args: unknown[]): void;
error?(...args: unknown[]): void;
debug?(...args: unknown[]): void;
}
/** Minimal DI container shape (extends McpServiceContainer pattern) */
interface PhaseContainer {
get(name: string): any;
[key: string]: any;
}
/** Single file entry collected during Phase 1 */
interface BootstrapFileEntry {
name: string;
path: string;
relativePath: string;
content: string;
targetName: string;
/** Whether this file belongs to a test target or matches test file naming patterns */
isTest: boolean;
}
/** Target item — either a plain string or an object with metadata */
type TargetItem = string | {
name: string;
framework?: string;
type?: string;
packageName?: string;
[key: string]: unknown;
};
/** Dependency graph data shape */
interface DepGraphData {
nodes?: Array<Record<string, unknown>>;
edges?: Array<{
from: string;
to: string;
[key: string]: unknown;
}>;
[key: string]: unknown;
}
type AstProjectSummaryLike = ProjectAnalysisResult;
type GuardAuditLike = GuardAudit;
/** Minimal guard engine shape */
interface GuardEngineLike {
auditFiles(files: Array<{
path: string;
content: string;
}>, opts?: Record<string, unknown>): GuardAuditLike;
injectExternalRules(rules: unknown[]): void;
getExternalRuleCount(): number;
[key: string]: unknown;
}
/** Minimal discoverer shape */
interface DiscovererLike {
id: string;
displayName: string;
load(root: string): Promise<void>;
listTargets(): Promise<TargetItem[]>;
getTargetFiles(target: unknown): Promise<Array<string | {
path: string;
name?: string;
relativePath?: string;
}>>;
getDependencyGraph(): Promise<DepGraphData>;
[key: string]: unknown;
}
/** Phase 4 dimension resolve params */
interface Phase4Params {
primaryLang: string;
langStats: Record<string, number>;
allTargets: TargetItem[];
astProjectSummary: AstProjectSummaryLike | null;
guardEngine: GuardEngineLike | null;
allFiles: BootstrapFileEntry[];
logger: PhaseLogger;
}
/** Phase 1 options */
interface Phase1Options {
maxFiles?: number;
[key: string]: unknown;
}
/** Phase 1.5 AST analysis options */
interface AstAnalysisOptions {
generateAstContext?: boolean;
[key: string]: unknown;
}
/** Phase 1.7 incremental call graph options */
interface IncrementalCallGraphOpts {
changedFiles?: string[];
[key: string]: unknown;
}
/** Phase 3 Guard audit options */
interface GuardAuditOptions {
skipGuard?: boolean;
summaryPrefix?: string;
[key: string]: unknown;
}
/** runAllPhases context — callers pass McpContext variants with different shapes */
interface AllPhasesContext {
container: PhaseContainer;
[key: string]: any;
}
/** runAllPhases options */
interface AllPhasesOptions {
incremental?: boolean;
generateReport?: boolean;
clearOldData?: boolean;
generateAstContext?: boolean;
maxFiles?: number;
skipGuard?: boolean;
sourceTag?: string;
summaryPrefix?: string;
[key: string]: unknown;
}
/** Phase report structure */
export interface PhaseReport {
phases: Record<string, Record<string, unknown>>;
startTime: number;
totalMs?: number;
[key: string]: unknown;
}
/** 判断文件是否为 AutoSnippet 生成物(用于排除自引用循环知识) */
export declare function isAutoSnippetGenerated(filePath: string): boolean;
/**
* Phase 1: 通过 DiscovererRegistry 检测项目类型并收集源文件
*
* @param projectRoot 项目根目录
* @returns >}
*/
export declare function runPhase1_FileCollection(projectRoot: string, logger: PhaseLogger, options?: Phase1Options): Promise<{
allFiles: BootstrapFileEntry[];
allTargets: TargetItem[];
discoverer: DiscovererLike;
langStats: Record<string, number>;
truncated: boolean;
}>;
/**
* Phase 1.5: tree-sitter AST 分析
* - 1.5a: 按需安装缺失的语法包
* - 1.5b: 执行 AST 分析 + SFC 预处理
*
* @param allFiles Phase 1 收集的文件
* @param langStats 语言统计
* @param [options.generateAstContext=false] 是否生成 astContext 文本
* @returns >}
*/
export declare function runPhase1_5_AstAnalysis(allFiles: BootstrapFileEntry[], langStats: Record<string, number>, logger: PhaseLogger, options?: AstAnalysisOptions): Promise<{
astProjectSummary: ProjectAnalysisResult | null;
astContext: string;
warnings: string[];
}>;
/**
* Phase 1.6: 从 AST 结果构建代码实体关系图谱
*
* @param astProjectSummary AST 分析结果
* @param container ServiceContainer
* @returns >}
*/
export declare function runPhase1_6_EntityGraph(astProjectSummary: AstProjectSummaryLike | null, projectRoot: string, container: PhaseContainer, logger: PhaseLogger): Promise<{
codeEntityResult: {
entitiesUpserted: number;
edgesCreated: number;
durationMs: number;
} | null;
warnings: string[];
}>;
/**
* Phase 1.7: 跨文件调用图分析 (Phase 5)
*
* 从 AST 的 callSites 构建全局调用图并写入 CodeEntityGraph。
*
* @param astProjectSummary AST 分析结果 (含 fileSummaries[].callSites)
* @param container ServiceContainer
* @param [incrementalOpts] 增量分析选项
* @param [incrementalOpts.changedFiles] 变更文件的相对路径
* @returns >}
*/
export declare function runPhase1_7_CallGraph(astProjectSummary: AstProjectSummaryLike | null, projectRoot: string, container: PhaseContainer, logger: PhaseLogger, incrementalOpts?: IncrementalCallGraphOpts | null): Promise<{
callGraphResult: {
entitiesUpserted: number;
edgesCreated: number;
durationMs: number;
} | null;
warnings: string[];
}>;
/**
* Phase 2: 获取依赖图并写入 knowledge_edges
*
* @param discoverer DiscovererRegistry 检测到的 discoverer
* @param container ServiceContainer
* @param [sourceTag='bootstrap'] edge 的 source 标签后缀
* @returns >}
*/
export declare function runPhase2_DependencyGraph(discoverer: DiscovererLike, container: PhaseContainer, logger: PhaseLogger, sourceTag?: string): Promise<{
depGraphData: DepGraphData | null;
depEdgesWritten: number;
warnings: string[];
}>;
/**
* Phase 2.1: 将依赖图的 module 节点写入 Code Entity Graph
*
* @param depGraphData 依赖图数据
*/
export declare function runPhase2_1_ModuleEntities(depGraphData: DepGraphData | null, projectRoot: string, container: PhaseContainer, logger: PhaseLogger): Promise<void>;
/**
* Phase 3: Guard 规则审计
*
* @param allFiles Phase 1 收集的文件
* @param [options.summaryPrefix='Bootstrap scan'] - ViolationsStore 摘要前缀
* @returns >}
*/
export declare function runPhase3_GuardAudit(allFiles: BootstrapFileEntry[], container: PhaseContainer, logger: PhaseLogger, options?: GuardAuditOptions): Promise<{
guardAudit: GuardAudit | null;
guardEngine: GuardEngineLike | null;
warnings: string[];
}>;
/**
* Phase 4: 维度条件化过滤 + Enhancement Pack 动态追加 + 语言画像 + Skill 增强
*
* @param params.astProjectSummary AST 结果(供 Enhancement Pack 模式检测)
* @param params.guardEngine Guard 引擎(供 Enhancement Pack 规则注入)
* @param params.allFiles 文件列表(供 Guard 二次审计)
* @returns {Promise<{
* activeDimensions: Array,
* enhancementPackInfo: Array,
* enhancementPatterns: Array,
* enhancementGuardRules: Array,
* langProfile: object,
* detectedFrameworks: string[],
* guardAudit: object|null
* }>}
*/
export declare function runPhase4_DimensionResolve(params: Phase4Params): Promise<{
activeDimensions: BaseDimension[];
enhancementPackInfo: {
id: string;
displayName: string;
}[];
enhancementPatterns: Record<string, unknown>[];
enhancementGuardRules: unknown[];
langProfile: {
primary: string;
secondary: string[];
all: {
ratio: number;
lang: string;
count: number;
}[];
totalFiles: number;
isMultiLang: boolean;
};
detectedFrameworks: string[];
guardAudit: GuardAudit | null;
}>;
/**
* runAllPhases — 一站式执行 Phase 1~4 全部数据收集
*
* 内部 Agent 和外部 Agent 均可调用此函数获取统一的分析结果。
*
* @param projectRoot 项目根目录
* @param ctx { container, logger }
* @param [options.incremental=false] 启用增量评估 (Phase 1 后执行)
* @param [options.generateReport=false] 生成 Phase 级详细报告
* @param [options.clearOldData=false] 先清除旧 checkpoints/snapshots
* @param [options.generateAstContext=false] 生成 astContext 文本
* @param [options.summaryPrefix='Bootstrap scan']
*/
export declare function runAllPhases(projectRoot: string, ctx: AllPhasesContext, options?: AllPhasesOptions): Promise<{
allFiles: BootstrapFileEntry[];
langStats: Record<string, number>;
primaryLang: null;
discoverer: DiscovererLike;
allTargets: TargetItem[];
truncated: boolean;
astProjectSummary: null;
astContext: string;
codeEntityResult: null;
callGraphResult: null;
depGraphData: null;
depEdgesWritten: number;
guardAudit: null;
guardEngine: null;
activeDimensions: never[];
enhancementPackInfo: never[];
enhancementPatterns: never[];
enhancementGuardRules: never[];
langProfile: {};
targetsSummary: never[];
localPackageModules: never[];
warnings: string[];
report: {};
incrementalPlan: null;
panoramaResult: null;
detectedFrameworks: never[];
isEmpty: boolean;
} | {
allFiles: BootstrapFileEntry[];
langStats: Record<string, number>;
primaryLang: string;
discoverer: DiscovererLike;
allTargets: TargetItem[];
truncated: boolean;
astProjectSummary: ProjectAnalysisResult | null;
astContext: string;
codeEntityResult: {
entitiesUpserted: number;
edgesCreated: number;
durationMs: number;
} | null;
callGraphResult: {
entitiesUpserted: number;
edgesCreated: number;
durationMs: number;
} | null;
depGraphData: DepGraphData | null;
depEdgesWritten: number;
guardAudit: GuardAudit | null;
guardEngine: GuardEngineLike | null;
activeDimensions: BaseDimension[];
enhancementPackInfo: {
id: string;
displayName: string;
}[];
enhancementPatterns: Record<string, unknown>[];
enhancementGuardRules: unknown[];
langProfile: {
primary: string;
secondary: string[];
all: {
ratio: number;
lang: string;
count: number;
}[];
totalFiles: number;
isMultiLang: boolean;
};
detectedFrameworks: string[];
targetsSummary: {
name: string;
type: string;
packageName: string | undefined;
inferredRole: string;
fileCount: number;
isLocalPackage: boolean | undefined;
}[];
localPackageModules: {
name: string;
packageName: string;
fileCount: number;
inferredRole: string;
keyFiles: string[];
}[];
warnings: string[];
report: PhaseReport | null;
incrementalPlan: {
mode: string;
canIncremental: boolean;
affectedDimensions: string[];
skippedDimensions: string[];
reason: string;
diff?: unknown;
previousSnapshot?: unknown;
restoredEpisodic?: unknown;
} | null;
panoramaResult: Record<string, unknown> | null;
isEmpty: boolean;
}>;
export {};