UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

362 lines (361 loc) 20.8 kB
/** * Drizzle ORM Schema — Single Source of Truth * * 所有表定义从 migration 001-003 忠实翻译。 * DB 列名与 migration 保持一致;实体映射由 repository 层处理。 * * 表清单 (15): * 001: knowledge_entries, knowledge_edges, guard_violations, audit_logs, * sessions, token_usage, semantic_memories, bootstrap_snapshots, * bootstrap_dim_files, code_entities * 003: remote_commands * 004: evolution_proposals (+ knowledge_entries.staging_deadline) * 005: recipe_source_refs * 内联: remote_state * 内部: schema_migrations * * 注: Task 系统为纯内存 + JSONL 信号架构,不使用数据库表。 */ import { index, integer, real, sqliteTable, text, uniqueIndex, } from 'drizzle-orm/sqlite-core'; // ═══════════════════════════════════════════════════════════════ // 内部 — schema_migrations // ═══════════════════════════════════════════════════════════════ export const schemaMigrations = sqliteTable('schema_migrations', { version: text('version').primaryKey(), appliedAt: text('applied_at').notNull(), }); // ═══════════════════════════════════════════════════════════════ // 1. knowledge_entries — 核心知识条目 // ═══════════════════════════════════════════════════════════════ export const knowledgeEntries = sqliteTable('knowledge_entries', { id: text('id').primaryKey(), title: text('title').notNull().default(''), description: text('description').default(''), lifecycle: text('lifecycle').notNull().default('pending'), lifecycleHistory: text('lifecycleHistory').default('[]'), autoApprovable: integer('autoApprovable').default(0), language: text('language').notNull().default(''), category: text('category').notNull().default('general'), kind: text('kind').default('pattern'), knowledgeType: text('knowledgeType').default('code-pattern'), complexity: text('complexity').default('intermediate'), scope: text('scope').default('universal'), difficulty: text('difficulty'), tags: text('tags').default('[]'), // Cursor 交付字段 trigger: text('trigger').default(''), topicHint: text('topicHint').default(''), whenClause: text('whenClause').default(''), doClause: text('doClause').default(''), dontClause: text('dontClause').default(''), coreCode: text('coreCode').default(''), // 值对象 (JSON) content: text('content').default('{}'), relations: text('relations').default('{}'), constraints: text('constraints').default('{}'), reasoning: text('reasoning').default('{}'), quality: text('quality').default('{}'), stats: text('stats').default('{}'), // ObjC/Swift headers headers: text('headers').default('[]'), headerPaths: text('headerPaths').default('[]'), moduleName: text('moduleName').default(''), includeHeaders: integer('includeHeaders').default(0), // AI notes agentNotes: text('agentNotes'), aiInsight: text('aiInsight'), // Review reviewedBy: text('reviewedBy'), reviewedAt: integer('reviewedAt'), rejectionReason: text('rejectionReason'), // Source source: text('source').default('agent'), sourceFile: text('sourceFile'), sourceCandidateId: text('sourceCandidateId'), // Timestamps createdBy: text('createdBy').default('agent'), createdAt: integer('createdAt').notNull(), updatedAt: integer('updatedAt').notNull(), publishedAt: integer('publishedAt'), publishedBy: text('publishedBy'), // Content hash contentHash: text('contentHash'), // M2: Staging support (migration 004) stagingDeadline: integer('staging_deadline'), }, (table) => [ index('idx_ke3_lifecycle').on(table.lifecycle), index('idx_ke3_language').on(table.language), index('idx_ke3_category').on(table.category), index('idx_ke3_kind').on(table.kind), index('idx_ke3_createdAt').on(table.createdAt), index('idx_ke3_trigger').on(table.trigger), index('idx_ke3_title').on(table.title), index('idx_ke3_source').on(table.source), index('idx_ke3_guard_active').on(table.kind, table.lifecycle), index('idx_ke3_topicHint').on(table.topicHint), ]); // ═══════════════════════════════════════════════════════════════ // 2. knowledge_edges — 知识关系图谱边 // ═══════════════════════════════════════════════════════════════ export const knowledgeEdges = sqliteTable('knowledge_edges', { id: integer('id').primaryKey({ autoIncrement: true }), fromId: text('from_id').notNull(), fromType: text('from_type').notNull().default('recipe'), toId: text('to_id').notNull(), toType: text('to_type').notNull().default('recipe'), relation: text('relation').notNull(), weight: real('weight').default(1.0), metadataJson: text('metadata_json').default('{}'), createdAt: integer('created_at').notNull(), updatedAt: integer('updated_at').notNull(), }, (table) => [ uniqueIndex('knowledge_edges_unique').on(table.fromId, table.fromType, table.toId, table.toType, table.relation), index('idx_ke_from').on(table.fromId, table.fromType), index('idx_ke_to').on(table.toId, table.toType), index('idx_ke_relation').on(table.relation), ]); // ═══════════════════════════════════════════════════════════════ // 3. guard_violations — Guard 违反记录 // ═══════════════════════════════════════════════════════════════ export const guardViolations = sqliteTable('guard_violations', { id: text('id').primaryKey(), filePath: text('file_path').notNull(), triggeredAt: text('triggered_at').notNull(), violationCount: integer('violation_count').default(0), summary: text('summary'), violationsJson: text('violations_json').default('[]'), createdAt: integer('created_at').notNull(), }, (table) => [ index('idx_guard_violations_file').on(table.filePath), index('idx_guard_violations_time').on(table.triggeredAt), ]); // ═══════════════════════════════════════════════════════════════ // 4. audit_logs — 审计日志 // ═══════════════════════════════════════════════════════════════ export const auditLogs = sqliteTable('audit_logs', { id: text('id').primaryKey(), timestamp: integer('timestamp').notNull(), actor: text('actor').notNull(), actorContext: text('actor_context').default('{}'), action: text('action').notNull(), resource: text('resource'), operationData: text('operation_data').default('{}'), result: text('result').notNull(), errorMessage: text('error_message'), duration: integer('duration'), }, (table) => [ index('idx_audit_actor').on(table.actor), index('idx_audit_action').on(table.action), index('idx_audit_result').on(table.result), index('idx_audit_timestamp').on(table.timestamp), ]); // ═══════════════════════════════════════════════════════════════ // 5. sessions — 会话管理 // ═══════════════════════════════════════════════════════════════ export const sessions = sqliteTable('sessions', { id: text('id').primaryKey(), scope: text('scope').notNull(), scopeId: text('scope_id'), context: text('context').default('{}'), metadata: text('metadata').default('{}'), actor: text('actor'), createdAt: integer('created_at').notNull(), lastActiveAt: integer('last_active_at'), expiredAt: integer('expired_at'), }, (table) => [ index('idx_sessions_scope').on(table.scope), index('idx_sessions_actor').on(table.actor), index('idx_sessions_expired').on(table.expiredAt), ]); // ═══════════════════════════════════════════════════════════════ // 6. token_usage — AI Token 消耗记录 // ═══════════════════════════════════════════════════════════════ export const tokenUsage = sqliteTable('token_usage', { id: integer('id').primaryKey({ autoIncrement: true }), timestamp: integer('timestamp').notNull(), source: text('source').notNull().default('unknown'), dimension: text('dimension'), provider: text('provider'), model: text('model'), inputTokens: integer('input_tokens').notNull().default(0), outputTokens: integer('output_tokens').notNull().default(0), totalTokens: integer('total_tokens').notNull().default(0), durationMs: integer('duration_ms'), toolCalls: integer('tool_calls').default(0), sessionId: text('session_id'), }, (table) => [ index('idx_token_usage_timestamp').on(table.timestamp), index('idx_token_usage_source').on(table.source), ]); // ═══════════════════════════════════════════════════════════════ // 7. semantic_memories — 项目级语义记忆 // ═══════════════════════════════════════════════════════════════ export const semanticMemories = sqliteTable('semantic_memories', { id: text('id').primaryKey(), type: text('type').notNull().default('fact'), content: text('content').notNull().default(''), source: text('source').notNull().default('bootstrap'), importance: real('importance').notNull().default(5.0), accessCount: integer('access_count').notNull().default(0), lastAccessedAt: text('last_accessed_at'), createdAt: text('created_at').notNull(), updatedAt: text('updated_at').notNull(), expiresAt: text('expires_at'), relatedEntities: text('related_entities').default('[]'), relatedMemories: text('related_memories').default('[]'), sourceDimension: text('source_dimension'), sourceEvidence: text('source_evidence'), bootstrapSession: text('bootstrap_session'), tags: text('tags').default('[]'), }, (table) => [ index('idx_semantic_memories_type').on(table.type), index('idx_semantic_memories_source').on(table.source), index('idx_semantic_memories_importance').on(table.importance), index('idx_semantic_memories_updated_at').on(table.updatedAt), index('idx_semantic_memories_source_dimension').on(table.sourceDimension), ]); // ═══════════════════════════════════════════════════════════════ // 8. bootstrap_snapshots — Bootstrap 快照主表 // ═══════════════════════════════════════════════════════════════ export const bootstrapSnapshots = sqliteTable('bootstrap_snapshots', { id: text('id').primaryKey(), sessionId: text('session_id'), projectRoot: text('project_root').notNull(), createdAt: text('created_at').notNull(), durationMs: integer('duration_ms').default(0), fileCount: integer('file_count').default(0), dimensionCount: integer('dimension_count').default(0), candidateCount: integer('candidate_count').default(0), primaryLang: text('primary_lang'), fileHashes: text('file_hashes').notNull().default('{}'), dimensionMeta: text('dimension_meta').notNull().default('{}'), episodicData: text('episodic_data'), isIncremental: integer('is_incremental').default(0), parentId: text('parent_id'), changedFiles: text('changed_files').default('[]'), affectedDims: text('affected_dims').default('[]'), status: text('status').default('complete'), }, (table) => [ index('idx_snapshots_project').on(table.projectRoot, table.createdAt), index('idx_snapshots_status').on(table.status), ]); // ═══════════════════════════════════════════════════════════════ // 9. bootstrap_dim_files — 维度-文件关联表 // ═══════════════════════════════════════════════════════════════ export const bootstrapDimFiles = sqliteTable('bootstrap_dim_files', { snapshotId: text('snapshot_id') .notNull() .references(() => bootstrapSnapshots.id, { onDelete: 'cascade' }), dimId: text('dim_id').notNull(), filePath: text('file_path').notNull(), role: text('role').default('referenced'), }, (table) => [ // composite primary key emulated via unique index uniqueIndex('bootstrap_dim_files_pk').on(table.snapshotId, table.dimId, table.filePath), index('idx_dim_files_file').on(table.filePath), index('idx_dim_files_dim').on(table.dimId), ]); // ═══════════════════════════════════════════════════════════════ // 10. code_entities — 代码实体节点 (AST) // ═══════════════════════════════════════════════════════════════ export const codeEntities = sqliteTable('code_entities', { id: integer('id').primaryKey({ autoIncrement: true }), entityId: text('entity_id').notNull(), entityType: text('entity_type').notNull(), projectRoot: text('project_root').notNull(), name: text('name').notNull(), filePath: text('file_path'), lineNumber: integer('line_number'), superclass: text('superclass'), protocols: text('protocols').default('[]'), metadataJson: text('metadata_json').default('{}'), createdAt: integer('created_at').notNull(), updatedAt: integer('updated_at').notNull(), }, (table) => [ uniqueIndex('code_entities_unique').on(table.entityId, table.entityType, table.projectRoot), index('idx_ce_project').on(table.projectRoot), index('idx_ce_type').on(table.entityType), index('idx_ce_name').on(table.name), index('idx_ce_file').on(table.filePath), index('idx_ce_superclass').on(table.superclass), ]); // ═══════════════════════════════════════════════════════════════ // 11. remote_commands — 远程指令队列 (migration 003) // ═══════════════════════════════════════════════════════════════ export const remoteCommands = sqliteTable('remote_commands', { id: text('id').primaryKey(), source: text('source').notNull().default('lark'), chatId: text('chat_id'), messageId: text('message_id'), userId: text('user_id'), userName: text('user_name'), command: text('command').notNull(), status: text('status').notNull().default('pending'), result: text('result'), createdAt: integer('created_at').notNull(), claimedAt: integer('claimed_at'), completedAt: integer('completed_at'), }, (table) => [ index('idx_remote_commands_status').on(table.status), index('idx_remote_commands_created').on(table.createdAt), ]); // ═══════════════════════════════════════════════════════════════ // 15. remote_state — 远程状态 (路由内联创建) // ═══════════════════════════════════════════════════════════════ export const remoteState = sqliteTable('remote_state', { key: text('key').primaryKey(), value: text('value'), updatedAt: integer('updated_at'), }); // ═══════════════════════════════════════════════════════════════ // 16. evolution_proposals — 知识进化提案 (M2 Recipe 治理) // ═══════════════════════════════════════════════════════════════ export const evolutionProposals = sqliteTable('evolution_proposals', { id: text('id').primaryKey(), type: text('type').notNull(), targetRecipeId: text('target_recipe_id').notNull(), relatedRecipeIds: text('related_recipe_ids').default('[]'), confidence: real('confidence').notNull().default(0), source: text('source').notNull(), description: text('description').default(''), evidence: text('evidence').default('[]'), status: text('status').notNull().default('pending'), proposedAt: integer('proposed_at').notNull(), expiresAt: integer('expires_at').notNull(), resolvedAt: integer('resolved_at'), resolvedBy: text('resolved_by'), resolution: text('resolution'), }, (table) => [ index('idx_ep_status').on(table.status), index('idx_ep_target').on(table.targetRecipeId), index('idx_ep_expires').on(table.expiresAt), index('idx_ep_source').on(table.source), ]); // ═══════════════════════════════════════════════════════════════ // 17. recipe_source_refs — Recipe 来源引用桥接表 (可信度证据链) // ═══════════════════════════════════════════════════════════════ export const recipeSourceRefs = sqliteTable('recipe_source_refs', { recipeId: text('recipe_id').notNull(), sourcePath: text('source_path').notNull(), status: text('status').notNull().default('active'), newPath: text('new_path'), verifiedAt: integer('verified_at').notNull(), }, (table) => [index('idx_rsr_path').on(table.sourcePath), index('idx_rsr_status').on(table.status)]); // ═══════════════════════════════════════════════════════════════ // 18. lifecycle_transition_events — Recipe 生命周期转移事件 (migration 006) // ═══════════════════════════════════════════════════════════════ export const lifecycleTransitionEvents = sqliteTable('lifecycle_transition_events', { id: text('id').primaryKey(), recipeId: text('recipe_id').notNull(), fromState: text('from_state').notNull(), toState: text('to_state').notNull(), trigger: text('trigger').notNull(), operatorId: text('operator_id').notNull().default('system'), evidenceJson: text('evidence_json'), proposalId: text('proposal_id'), createdAt: integer('created_at').notNull(), }, (table) => [ index('idx_lte_recipe_id').on(table.recipeId), index('idx_lte_created_at').on(table.createdAt), index('idx_lte_trigger').on(table.trigger), ]);