speccore 6.6.0 → 6.10.0
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.
- package/.agents/skills/spec-ask/SKILL.md +6 -0
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/about.d.ts.map +1 -1
- package/dist/commands/about.js +10 -3
- package/dist/commands/about.js.map +1 -1
- package/dist/commands/analyze.d.ts +2 -0
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +141 -0
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/change.d.ts.map +1 -1
- package/dist/commands/change.js +3 -0
- package/dist/commands/change.js.map +1 -1
- package/dist/commands/doc2spec.d.ts +1 -0
- package/dist/commands/doc2spec.d.ts.map +1 -1
- package/dist/commands/doc2spec.js +175 -0
- package/dist/commands/doc2spec.js.map +1 -1
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +20 -6
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/help.js +32 -5
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/iteration/create.d.ts.map +1 -1
- package/dist/commands/iteration/create.js +38 -10
- package/dist/commands/iteration/create.js.map +1 -1
- package/dist/commands/iteration/split.d.ts.map +1 -1
- package/dist/commands/iteration/split.js +125 -9
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/commands/rag-index.d.ts +19 -0
- package/dist/commands/rag-index.d.ts.map +1 -0
- package/dist/commands/rag-index.js +272 -0
- package/dist/commands/rag-index.js.map +1 -0
- package/dist/commands/refresh.d.ts +21 -0
- package/dist/commands/refresh.d.ts.map +1 -0
- package/dist/commands/refresh.js +185 -0
- package/dist/commands/refresh.js.map +1 -0
- package/dist/commands/sync-global.js +41 -0
- package/dist/commands/sync-global.js.map +1 -1
- package/dist/core/ai-context-generator.d.ts +2 -0
- package/dist/core/ai-context-generator.d.ts.map +1 -1
- package/dist/core/ai-context-generator.js +8 -6
- package/dist/core/ai-context-generator.js.map +1 -1
- package/dist/core/analyze-engine.d.ts +19 -0
- package/dist/core/analyze-engine.d.ts.map +1 -1
- package/dist/core/analyze-engine.js +326 -9
- package/dist/core/analyze-engine.js.map +1 -1
- package/dist/core/ask-engine.d.ts.map +1 -1
- package/dist/core/ask-engine.js +113 -4
- package/dist/core/ask-engine.js.map +1 -1
- package/dist/core/ask-host-ai.d.ts.map +1 -1
- package/dist/core/ask-host-ai.js +9 -6
- package/dist/core/ask-host-ai.js.map +1 -1
- package/dist/core/code-scanner.d.ts +24 -2
- package/dist/core/code-scanner.d.ts.map +1 -1
- package/dist/core/code-scanner.js +235 -5
- package/dist/core/code-scanner.js.map +1 -1
- package/dist/core/context-builder.d.ts.map +1 -1
- package/dist/core/context-builder.js +20 -1
- package/dist/core/context-builder.js.map +1 -1
- package/dist/core/decay-detector.d.ts +2 -2
- package/dist/core/decay-detector.d.ts.map +1 -1
- package/dist/core/decay-detector.js +135 -6
- package/dist/core/decay-detector.js.map +1 -1
- package/dist/core/git-integration.d.ts +50 -2
- package/dist/core/git-integration.d.ts.map +1 -1
- package/dist/core/git-integration.js +217 -27
- package/dist/core/git-integration.js.map +1 -1
- package/dist/core/global-knowledge.d.ts +25 -0
- package/dist/core/global-knowledge.d.ts.map +1 -0
- package/dist/core/global-knowledge.js +228 -0
- package/dist/core/global-knowledge.js.map +1 -0
- package/dist/core/index-guard.d.ts +57 -0
- package/dist/core/index-guard.d.ts.map +1 -0
- package/dist/core/index-guard.js +202 -0
- package/dist/core/index-guard.js.map +1 -0
- package/dist/core/intent-cache.d.ts +3 -1
- package/dist/core/intent-cache.d.ts.map +1 -1
- package/dist/core/intent-cache.js +33 -3
- package/dist/core/intent-cache.js.map +1 -1
- package/dist/core/knowledge-graph.d.ts +7 -1
- package/dist/core/knowledge-graph.d.ts.map +1 -1
- package/dist/core/knowledge-graph.js +208 -22
- package/dist/core/knowledge-graph.js.map +1 -1
- package/dist/core/platform-registry.d.ts +5 -0
- package/dist/core/platform-registry.d.ts.map +1 -1
- package/dist/core/platform-registry.js +52 -0
- package/dist/core/platform-registry.js.map +1 -1
- package/dist/core/prompt-builder.d.ts +3 -2
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +220 -71
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/rag-engine.d.ts +152 -0
- package/dist/core/rag-engine.d.ts.map +1 -0
- package/dist/core/rag-engine.js +816 -0
- package/dist/core/rag-engine.js.map +1 -0
- package/dist/core/unified-retrieval.d.ts +140 -0
- package/dist/core/unified-retrieval.d.ts.map +1 -0
- package/dist/core/unified-retrieval.js +466 -0
- package/dist/core/unified-retrieval.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* global-knowledge — 全局知识沉淀引擎
|
|
3
|
+
*
|
|
4
|
+
* 设计哲学:不追求完美文档,追求"能检索到"
|
|
5
|
+
*
|
|
6
|
+
* 工作流程:
|
|
7
|
+
* 1. sync-global 完成后,扫描迭代所有 specs 文档
|
|
8
|
+
* 2. 为全局层构建 RAG 索引(聚合所有迭代的技术内容)
|
|
9
|
+
* 3. 生成轻量级 GLOBAL/SUMMARY.md(AI 概览,可手动修改)
|
|
10
|
+
* 4. 刷新知识图谱
|
|
11
|
+
*
|
|
12
|
+
* 输出:
|
|
13
|
+
* .speccore/GLOBAL/SUMMARY.md ← 全局概览(轻量,可手动改)
|
|
14
|
+
* .speccore/cache/rag-index.json ← 全局 RAG 索引(聚合所有迭代)
|
|
15
|
+
*/
|
|
16
|
+
export interface GlobalKnowledgeOptions {
|
|
17
|
+
iteration?: string;
|
|
18
|
+
cwd?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 全局知识沉淀主入口
|
|
22
|
+
* sync-global 完成后调用
|
|
23
|
+
*/
|
|
24
|
+
export declare function syncGlobalKnowledge(options?: GlobalKnowledgeOptions): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=global-knowledge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-knowledge.d.ts","sourceRoot":"","sources":["../../src/core/global-knowledge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CA8E7F"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* global-knowledge — 全局知识沉淀引擎
|
|
4
|
+
*
|
|
5
|
+
* 设计哲学:不追求完美文档,追求"能检索到"
|
|
6
|
+
*
|
|
7
|
+
* 工作流程:
|
|
8
|
+
* 1. sync-global 完成后,扫描迭代所有 specs 文档
|
|
9
|
+
* 2. 为全局层构建 RAG 索引(聚合所有迭代的技术内容)
|
|
10
|
+
* 3. 生成轻量级 GLOBAL/SUMMARY.md(AI 概览,可手动修改)
|
|
11
|
+
* 4. 刷新知识图谱
|
|
12
|
+
*
|
|
13
|
+
* 输出:
|
|
14
|
+
* .speccore/GLOBAL/SUMMARY.md ← 全局概览(轻量,可手动改)
|
|
15
|
+
* .speccore/cache/rag-index.json ← 全局 RAG 索引(聚合所有迭代)
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.syncGlobalKnowledge = syncGlobalKnowledge;
|
|
19
|
+
const fs_extra_1 = require("fs-extra");
|
|
20
|
+
const path_1 = require("path");
|
|
21
|
+
const logger_1 = require("../utils/logger");
|
|
22
|
+
const rag_engine_1 = require("./rag-engine");
|
|
23
|
+
const knowledge_graph_1 = require("./knowledge-graph");
|
|
24
|
+
/**
|
|
25
|
+
* 全局知识沉淀主入口
|
|
26
|
+
* sync-global 完成后调用
|
|
27
|
+
*/
|
|
28
|
+
async function syncGlobalKnowledge(options = {}) {
|
|
29
|
+
const cwd = options.cwd || process.cwd();
|
|
30
|
+
const iteration = options.iteration;
|
|
31
|
+
logger_1.logger.info('');
|
|
32
|
+
logger_1.logger.info('🌐 全局知识沉淀...');
|
|
33
|
+
// ── 1. 收集所有迭代的 specs 文档 ──
|
|
34
|
+
const specsDirs = [];
|
|
35
|
+
// 1.1 如果指定了迭代,优先扫描该迭代
|
|
36
|
+
if (iteration) {
|
|
37
|
+
const iterSpecsDir = (0, path_1.join)(cwd, `Iteration-${iteration}`, '020-specs');
|
|
38
|
+
if (await (0, fs_extra_1.pathExists)(iterSpecsDir)) {
|
|
39
|
+
specsDirs.push(iterSpecsDir);
|
|
40
|
+
}
|
|
41
|
+
// 扫描该迭代的所有任务目录
|
|
42
|
+
const tasksDir = (0, path_1.join)(cwd, `Iteration-${iteration}`, '030-tasks');
|
|
43
|
+
if (await (0, fs_extra_1.pathExists)(tasksDir)) {
|
|
44
|
+
const tasks = await (0, fs_extra_1.readdir)(tasksDir, { withFileTypes: true });
|
|
45
|
+
for (const t of tasks) {
|
|
46
|
+
if (t.isDirectory() && t.name.startsWith('Task-')) {
|
|
47
|
+
const taskSpecsDir = (0, path_1.join)(tasksDir, t.name, '00-specs');
|
|
48
|
+
const taskSharedDir = (0, path_1.join)(tasksDir, t.name, '_shared');
|
|
49
|
+
if (await (0, fs_extra_1.pathExists)(taskSpecsDir))
|
|
50
|
+
specsDirs.push(taskSpecsDir);
|
|
51
|
+
if (await (0, fs_extra_1.pathExists)(taskSharedDir))
|
|
52
|
+
specsDirs.push(taskSharedDir);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 1.2 同时扫描全局层的现有 specs
|
|
58
|
+
const globalSpecsDir = (0, path_1.join)(cwd, '.speccore', 'GLOBAL', '020-specs');
|
|
59
|
+
if (await (0, fs_extra_1.pathExists)(globalSpecsDir)) {
|
|
60
|
+
specsDirs.push(globalSpecsDir);
|
|
61
|
+
}
|
|
62
|
+
if (specsDirs.length === 0) {
|
|
63
|
+
logger_1.logger.info(' ⚠️ 未找到 specs 文档,跳过全局知识沉淀');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// ── 2. 为每个 specs 目录构建/更新 RAG 索引 ──
|
|
67
|
+
// 全局 RAG 索引:聚合所有迭代的 specs(使用独立文件名,避免覆盖任务级索引)
|
|
68
|
+
const globalScope = iteration
|
|
69
|
+
? `GLOBAL_all_${iteration}_aggregated`
|
|
70
|
+
: 'GLOBAL_all_all_aggregated';
|
|
71
|
+
// 收集所有要索引的文件
|
|
72
|
+
const allFiles = [];
|
|
73
|
+
for (const dir of specsDirs) {
|
|
74
|
+
await collectMdFiles(dir, allFiles);
|
|
75
|
+
}
|
|
76
|
+
if (allFiles.length === 0) {
|
|
77
|
+
logger_1.logger.info(' ⚠️ 未收集到有效文档,跳过');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// 用通用函数建全局 RAG 索引(保存到独立文件)
|
|
81
|
+
const index = await (0, rag_engine_1.buildRagIndex)(allFiles, globalScope);
|
|
82
|
+
await (0, rag_engine_1.saveRagIndex)(cwd, index, 'rag-index-global.json');
|
|
83
|
+
logger_1.logger.info(` ✅ 全局 RAG 索引已更新: ${allFiles.length} 个文件, ${index.chunks.length} 个块 → rag-index-global.json`);
|
|
84
|
+
// ── 3. 生成/更新 GLOBAL/SUMMARY.md ──
|
|
85
|
+
await generateGlobalSummary(cwd, allFiles, iteration);
|
|
86
|
+
// ── 4. 刷新知识图谱 ──
|
|
87
|
+
try {
|
|
88
|
+
await (0, knowledge_graph_1.refreshKnowledgeGraph)(cwd, iteration || undefined);
|
|
89
|
+
logger_1.logger.info(' ✅ 知识图谱已刷新');
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
logger_1.logger.debug('知识图谱刷新失败(非关键)');
|
|
93
|
+
}
|
|
94
|
+
logger_1.logger.info(' 🌐 全局知识沉淀完成');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 递归收集目录下的 .md 文件
|
|
98
|
+
*/
|
|
99
|
+
async function collectMdFiles(dir, result) {
|
|
100
|
+
if (!(await (0, fs_extra_1.pathExists)(dir)))
|
|
101
|
+
return;
|
|
102
|
+
const items = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
|
|
103
|
+
for (const item of items) {
|
|
104
|
+
const fullPath = (0, path_1.join)(dir, item.name);
|
|
105
|
+
if (item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules') {
|
|
106
|
+
await collectMdFiles(fullPath, result);
|
|
107
|
+
}
|
|
108
|
+
else if (item.isFile() && item.name.endsWith('.md') && !item.name.startsWith('README')) {
|
|
109
|
+
const [content, st] = await Promise.all([
|
|
110
|
+
(0, fs_extra_1.readFile)(fullPath, 'utf-8'),
|
|
111
|
+
(0, fs_extra_1.stat)(fullPath),
|
|
112
|
+
]);
|
|
113
|
+
if (content.trim().length > 50) {
|
|
114
|
+
result.push({ filePath: fullPath, content, mtime: st.mtimeMs });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 生成轻量级 GLOBAL/SUMMARY.md
|
|
121
|
+
*
|
|
122
|
+
* 不追求完美,只是聚合信息 + 提供导航。
|
|
123
|
+
* 内容:已交付功能清单、技术方案概览、API 清单、已知问题。
|
|
124
|
+
*/
|
|
125
|
+
async function generateGlobalSummary(cwd, files, iteration) {
|
|
126
|
+
const summaryPath = (0, path_1.join)(cwd, '.speccore', 'GLOBAL', 'SUMMARY.md');
|
|
127
|
+
await (0, fs_extra_1.ensureDir)((0, path_1.join)(cwd, '.speccore', 'GLOBAL'));
|
|
128
|
+
// 从文件内容中提取结构化信息
|
|
129
|
+
const features = [];
|
|
130
|
+
const techDecisions = [];
|
|
131
|
+
const apis = [];
|
|
132
|
+
const issues = [];
|
|
133
|
+
for (const { filePath, content } of files) {
|
|
134
|
+
const fileName = filePath.split('/').pop() || '';
|
|
135
|
+
// 提取功能点(REQ.md / REQUIREMENT.md 中的 ### 标题)
|
|
136
|
+
if (fileName.includes('REQ') || fileName.includes('REQUIREMENT')) {
|
|
137
|
+
const matches = content.matchAll(/^#{2,3}\s+(.+)$/gm);
|
|
138
|
+
for (const m of matches) {
|
|
139
|
+
const title = m[1].trim();
|
|
140
|
+
if (title && !title.match(/^(需求|概述|目录|前言|背景)/)) {
|
|
141
|
+
features.push(title);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// 提取技术方案(TECH.md 中的 ### 标题)
|
|
146
|
+
if (fileName.includes('TECH')) {
|
|
147
|
+
const matches = content.matchAll(/^#{2,3}\s+(.+)$/gm);
|
|
148
|
+
for (const m of matches) {
|
|
149
|
+
const title = m[1].trim();
|
|
150
|
+
if (title && !title.match(/^(技术|概述|目录)/)) {
|
|
151
|
+
techDecisions.push(title);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// 提取 API(表格中的 GET/POST/PUT/DELETE)
|
|
156
|
+
const apiMatches = content.matchAll(/\|\s*(GET|POST|PUT|DELETE|PATCH)\s*\|\s*(\/[^\s|]+)/gi);
|
|
157
|
+
for (const m of apiMatches) {
|
|
158
|
+
apis.push(`${m[1].toUpperCase()} ${m[2]}`);
|
|
159
|
+
}
|
|
160
|
+
// 提取已知问题(.issues.md 或 RISK.md)
|
|
161
|
+
if (fileName.includes('issue') || fileName.includes('RISK')) {
|
|
162
|
+
const issueMatches = content.matchAll(/^[-*]\s+(.+)$/gm);
|
|
163
|
+
for (const m of issueMatches) {
|
|
164
|
+
issues.push(m[1].trim());
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 去重
|
|
169
|
+
const uniqueFeatures = [...new Set(features)].slice(0, 30);
|
|
170
|
+
const uniqueTech = [...new Set(techDecisions)].slice(0, 20);
|
|
171
|
+
const uniqueApis = [...new Set(apis)].slice(0, 30);
|
|
172
|
+
const uniqueIssues = [...new Set(issues)].slice(0, 10);
|
|
173
|
+
const now = new Date().toLocaleString('zh-CN');
|
|
174
|
+
const iterInfo = iteration ? `(基于 Iteration-${iteration})` : '';
|
|
175
|
+
const summary = `# 全局技术概览 ${iterInfo}
|
|
176
|
+
|
|
177
|
+
> 📌 本文件由 \_speccore sync-global\_ 自动生成,**可手动编辑**。不完美没关系,大方向对就行。
|
|
178
|
+
>
|
|
179
|
+
> 🔄 最后更新: ${now}
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 已交付功能
|
|
184
|
+
|
|
185
|
+
${uniqueFeatures.length > 0
|
|
186
|
+
? uniqueFeatures.map(f => `- ${f}`).join('\n')
|
|
187
|
+
: '_暂无功能记录_'}
|
|
188
|
+
|
|
189
|
+
## 技术方案要点
|
|
190
|
+
|
|
191
|
+
${uniqueTech.length > 0
|
|
192
|
+
? uniqueTech.map(t => `- ${t}`).join('\n')
|
|
193
|
+
: '_暂无技术方案_'}
|
|
194
|
+
|
|
195
|
+
## API 清单
|
|
196
|
+
|
|
197
|
+
${uniqueApis.length > 0
|
|
198
|
+
? '| 方法 | 路径 |\n| :--- | :--- |\n' + uniqueApis.map(a => {
|
|
199
|
+
const parts = a.split(' ');
|
|
200
|
+
return `| ${parts[0]} | ${parts[1] || ''} |`;
|
|
201
|
+
}).join('\n')
|
|
202
|
+
: '_暂无 API 记录_'}
|
|
203
|
+
|
|
204
|
+
## 已知问题 / 风险
|
|
205
|
+
|
|
206
|
+
${uniqueIssues.length > 0
|
|
207
|
+
? uniqueIssues.map(i => `- ${i}`).join('\n')
|
|
208
|
+
: '_暂无记录_'}
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 文档索引
|
|
213
|
+
|
|
214
|
+
${files.length > 0
|
|
215
|
+
? files.map(f => {
|
|
216
|
+
const relPath = f.filePath.replace(cwd + '/', '');
|
|
217
|
+
return `- [${relPath.split('/').pop()}](${relPath})`;
|
|
218
|
+
}).join('\n')
|
|
219
|
+
: '_暂无文档_'}
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
*💡 提示: 运行 \`speccore refresh\` 刷新检索层,运行 \`speccore rag-index\` 查看索引状态。*
|
|
224
|
+
`;
|
|
225
|
+
await (0, fs_extra_1.writeFile)(summaryPath, summary);
|
|
226
|
+
logger_1.logger.info(` ✅ 全局概览已生成: .speccore/GLOBAL/SUMMARY.md`);
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=global-knowledge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-knowledge.js","sourceRoot":"","sources":["../../src/core/global-knowledge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index-guard — 统一命令前索引新鲜度门禁
|
|
3
|
+
*
|
|
4
|
+
* 在 analyze / split / execute / change 等命令执行前,
|
|
5
|
+
* 检查所有索引层(RAG / 代码 / 知识图谱)是否过期,
|
|
6
|
+
* 返回标准化的变更摘要供 AI 展示给用户确认。
|
|
7
|
+
*
|
|
8
|
+
* 设计目标:
|
|
9
|
+
* - 一个入口函数 ensureIndexFresh() 覆盖所有命令
|
|
10
|
+
* - 输出标准化格式,AI 可直接展示
|
|
11
|
+
* - 非阻塞:只 warn 不阻止执行,但明确提示需要刷新
|
|
12
|
+
*/
|
|
13
|
+
export interface IndexFreshnessResult {
|
|
14
|
+
/** 是否全部新鲜 */
|
|
15
|
+
allFresh: boolean;
|
|
16
|
+
/** 各层状态 */
|
|
17
|
+
layers: {
|
|
18
|
+
rag: LayerStatus;
|
|
19
|
+
code: LayerStatus;
|
|
20
|
+
graph: LayerStatus;
|
|
21
|
+
};
|
|
22
|
+
/** 标准化变更摘要(可直接展示给用户) */
|
|
23
|
+
summary: string;
|
|
24
|
+
/** 建议的刷新命令 */
|
|
25
|
+
suggestedCommand: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LayerStatus {
|
|
28
|
+
/** 层名称 */
|
|
29
|
+
name: string;
|
|
30
|
+
/** 是否新鲜 */
|
|
31
|
+
fresh: boolean;
|
|
32
|
+
/** 变更文件数 */
|
|
33
|
+
changedCount: number;
|
|
34
|
+
/** 变更文件列表(最多显示 5 个) */
|
|
35
|
+
changedFiles: string[];
|
|
36
|
+
/** 人可读的描述 */
|
|
37
|
+
message: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 统一检查所有索引层的新鲜度
|
|
41
|
+
*
|
|
42
|
+
* 在 analyze / split / execute / change 命令入口调用。
|
|
43
|
+
* 返回标准化结果,调用方决定如何展示。
|
|
44
|
+
*
|
|
45
|
+
* @param cwd 工作目录
|
|
46
|
+
* @param command 当前执行的命令名(用于生成建议)
|
|
47
|
+
* @param iteration 迭代名(可选,自动推断)
|
|
48
|
+
*/
|
|
49
|
+
export declare function ensureIndexFresh(cwd: string, command: string, iteration?: string): Promise<IndexFreshnessResult>;
|
|
50
|
+
/**
|
|
51
|
+
* 在命令入口输出新鲜度检查(非阻塞,只 warn)
|
|
52
|
+
*
|
|
53
|
+
* 用法:
|
|
54
|
+
* await warnIfIndexStale(cwd, 'analyze');
|
|
55
|
+
*/
|
|
56
|
+
export declare function warnIfIndexStale(cwd: string, command: string, iteration?: string): Promise<IndexFreshnessResult>;
|
|
57
|
+
//# sourceMappingURL=index-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-guard.d.ts","sourceRoot":"","sources":["../../src/core/index-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,WAAW,oBAAoB;IACnC,aAAa;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW;IACX,MAAM,EAAE;QACN,GAAG,EAAE,WAAW,CAAC;QACjB,IAAI,EAAE,WAAW,CAAC;QAClB,KAAK,EAAE,WAAW,CAAC;KACpB,CAAC;IACF,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU;IACV,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,KAAK,EAAE,OAAO,CAAC;IACf,YAAY;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAoB/B;AAwJD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAM/B"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* index-guard — 统一命令前索引新鲜度门禁
|
|
4
|
+
*
|
|
5
|
+
* 在 analyze / split / execute / change 等命令执行前,
|
|
6
|
+
* 检查所有索引层(RAG / 代码 / 知识图谱)是否过期,
|
|
7
|
+
* 返回标准化的变更摘要供 AI 展示给用户确认。
|
|
8
|
+
*
|
|
9
|
+
* 设计目标:
|
|
10
|
+
* - 一个入口函数 ensureIndexFresh() 覆盖所有命令
|
|
11
|
+
* - 输出标准化格式,AI 可直接展示
|
|
12
|
+
* - 非阻塞:只 warn 不阻止执行,但明确提示需要刷新
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.ensureIndexFresh = ensureIndexFresh;
|
|
16
|
+
exports.warnIfIndexStale = warnIfIndexStale;
|
|
17
|
+
const logger_1 = require("../utils/logger");
|
|
18
|
+
const rag_engine_1 = require("./rag-engine");
|
|
19
|
+
const code_scanner_1 = require("./code-scanner");
|
|
20
|
+
const knowledge_graph_1 = require("./knowledge-graph");
|
|
21
|
+
const context_1 = require("./context");
|
|
22
|
+
// ═══════════════════════════════════════════════════════════
|
|
23
|
+
// 核心函数
|
|
24
|
+
// ═══════════════════════════════════════════════════════════
|
|
25
|
+
/**
|
|
26
|
+
* 统一检查所有索引层的新鲜度
|
|
27
|
+
*
|
|
28
|
+
* 在 analyze / split / execute / change 命令入口调用。
|
|
29
|
+
* 返回标准化结果,调用方决定如何展示。
|
|
30
|
+
*
|
|
31
|
+
* @param cwd 工作目录
|
|
32
|
+
* @param command 当前执行的命令名(用于生成建议)
|
|
33
|
+
* @param iteration 迭代名(可选,自动推断)
|
|
34
|
+
*/
|
|
35
|
+
async function ensureIndexFresh(cwd, command, iteration) {
|
|
36
|
+
const iterName = iteration || await (0, context_1.getDefaultIteration)(cwd);
|
|
37
|
+
// ── 并行检查三层 ──
|
|
38
|
+
const [ragStatus, codeStatus, graphStatus] = await Promise.all([
|
|
39
|
+
checkRagLayer(cwd, iterName),
|
|
40
|
+
checkCodeLayer(),
|
|
41
|
+
checkGraphLayer(cwd, iterName),
|
|
42
|
+
]);
|
|
43
|
+
const allFresh = ragStatus.fresh && codeStatus.fresh && graphStatus.fresh;
|
|
44
|
+
const summary = formatChangeSummary(ragStatus, codeStatus, graphStatus, command);
|
|
45
|
+
const suggestedCommand = `speccore refresh`;
|
|
46
|
+
return {
|
|
47
|
+
allFresh,
|
|
48
|
+
layers: { rag: ragStatus, code: codeStatus, graph: graphStatus },
|
|
49
|
+
summary,
|
|
50
|
+
suggestedCommand,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// ═══════════════════════════════════════════════════════════
|
|
54
|
+
// 各层检查
|
|
55
|
+
// ═══════════════════════════════════════════════════════════
|
|
56
|
+
async function checkRagLayer(cwd, iteration) {
|
|
57
|
+
try {
|
|
58
|
+
// 尝试加载 iteration 级索引
|
|
59
|
+
const ragFileName = iteration ? `rag-index-${iteration}.json` : undefined;
|
|
60
|
+
const index = await (0, rag_engine_1.loadRagIndex)(cwd, ragFileName);
|
|
61
|
+
if (!index) {
|
|
62
|
+
return {
|
|
63
|
+
name: '文档 RAG',
|
|
64
|
+
fresh: true, // 不存在不算过期,只是未建立
|
|
65
|
+
changedCount: 0,
|
|
66
|
+
changedFiles: [],
|
|
67
|
+
message: '未建立索引',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const { fresh, staleFiles, newFiles } = await (0, rag_engine_1.checkRagIndexFreshness)(cwd, ragFileName);
|
|
71
|
+
const changed = [...staleFiles, ...newFiles];
|
|
72
|
+
return {
|
|
73
|
+
name: '文档 RAG',
|
|
74
|
+
fresh,
|
|
75
|
+
changedCount: changed.length,
|
|
76
|
+
changedFiles: changed.slice(0, 5).map(f => f.replace(cwd + '/', '')),
|
|
77
|
+
message: fresh
|
|
78
|
+
? '文档索引已同步'
|
|
79
|
+
: `${staleFiles.length} 个文件已变更,${newFiles.length} 个新文件待索引`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return {
|
|
84
|
+
name: '文档 RAG',
|
|
85
|
+
fresh: true,
|
|
86
|
+
changedCount: 0,
|
|
87
|
+
changedFiles: [],
|
|
88
|
+
message: '检查失败(跳过)',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function checkCodeLayer() {
|
|
93
|
+
try {
|
|
94
|
+
const freshness = await (0, code_scanner_1.checkCodeIndexFreshness)();
|
|
95
|
+
const staleFiles = freshness.staleFiles || [];
|
|
96
|
+
return {
|
|
97
|
+
name: '代码索引',
|
|
98
|
+
fresh: freshness.fresh,
|
|
99
|
+
changedCount: staleFiles.length,
|
|
100
|
+
changedFiles: staleFiles.slice(0, 5),
|
|
101
|
+
message: freshness.fresh
|
|
102
|
+
? '代码索引已同步'
|
|
103
|
+
: freshness.message || `${staleFiles.length} 个文件已变更`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return {
|
|
108
|
+
name: '代码索引',
|
|
109
|
+
fresh: true,
|
|
110
|
+
changedCount: 0,
|
|
111
|
+
changedFiles: [],
|
|
112
|
+
message: '检查失败(跳过)',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function checkGraphLayer(cwd, iteration) {
|
|
117
|
+
try {
|
|
118
|
+
const stale = await (0, knowledge_graph_1.isGraphStale)(cwd, iteration);
|
|
119
|
+
const graph = await (0, knowledge_graph_1.loadKnowledgeGraph)(cwd);
|
|
120
|
+
const entityCount = graph ? graph.entities.length : 0;
|
|
121
|
+
return {
|
|
122
|
+
name: '知识图谱',
|
|
123
|
+
fresh: !stale,
|
|
124
|
+
changedCount: stale ? 1 : 0,
|
|
125
|
+
changedFiles: stale ? ['需求/规格/任务目录有变更'] : [],
|
|
126
|
+
message: stale
|
|
127
|
+
? `知识图谱已过期(${entityCount} 个实体待更新)`
|
|
128
|
+
: `知识图谱已同步(${entityCount} 个实体)`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return {
|
|
133
|
+
name: '知识图谱',
|
|
134
|
+
fresh: true,
|
|
135
|
+
changedCount: 0,
|
|
136
|
+
changedFiles: [],
|
|
137
|
+
message: '检查失败(跳过)',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ═══════════════════════════════════════════════════════════
|
|
142
|
+
// 变更摘要格式化
|
|
143
|
+
// ═══════════════════════════════════════════════════════════
|
|
144
|
+
/**
|
|
145
|
+
* 格式化标准化变更摘要
|
|
146
|
+
*
|
|
147
|
+
* 输出格式:
|
|
148
|
+
* ```
|
|
149
|
+
* 📋 索引状态检查(执行 {command} 前)
|
|
150
|
+
* ├── ✅ 文档 RAG:已同步
|
|
151
|
+
* ├── ⚠️ 代码索引:3 个文件已变更
|
|
152
|
+
* │ ├── src/commands/analyze.ts
|
|
153
|
+
* │ ├── src/core/rag-engine.ts
|
|
154
|
+
* │ └── src/core/prompt-builder.ts
|
|
155
|
+
* └── ⚠️ 知识图谱:已过期(12 个实体待更新)
|
|
156
|
+
*
|
|
157
|
+
* 💡 建议执行 `speccore refresh` 更新索引
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
function formatChangeSummary(rag, code, graph, command) {
|
|
161
|
+
const layers = [rag, code, graph];
|
|
162
|
+
const hasChanges = layers.some(l => !l.fresh);
|
|
163
|
+
if (!hasChanges) {
|
|
164
|
+
return `📋 索引状态检查(${command}):全部已同步 ✅`;
|
|
165
|
+
}
|
|
166
|
+
const lines = [];
|
|
167
|
+
lines.push(`📋 索引状态检查(${command} 前)`);
|
|
168
|
+
for (let i = 0; i < layers.length; i++) {
|
|
169
|
+
const layer = layers[i];
|
|
170
|
+
const connector = i === layers.length - 1 ? '└──' : '├──';
|
|
171
|
+
const icon = layer.fresh ? '✅' : '⚠️ ';
|
|
172
|
+
lines.push(`${connector} ${icon} ${layer.name}:${layer.message}`);
|
|
173
|
+
// 显示变更文件列表(最多 3 个)
|
|
174
|
+
if (!layer.fresh && layer.changedFiles.length > 0) {
|
|
175
|
+
const subConnector = i === layers.length - 1 ? ' ' : '│ ';
|
|
176
|
+
const files = layer.changedFiles.slice(0, 3);
|
|
177
|
+
for (const file of files) {
|
|
178
|
+
lines.push(`${subConnector} • ${file}`);
|
|
179
|
+
}
|
|
180
|
+
if (layer.changedFiles.length > 3) {
|
|
181
|
+
lines.push(`${subConnector} ... 还有 ${layer.changedFiles.length - 3} 个文件`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
lines.push('');
|
|
186
|
+
lines.push('💡 建议执行 `speccore refresh` 更新索引');
|
|
187
|
+
return lines.join('\n');
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 在命令入口输出新鲜度检查(非阻塞,只 warn)
|
|
191
|
+
*
|
|
192
|
+
* 用法:
|
|
193
|
+
* await warnIfIndexStale(cwd, 'analyze');
|
|
194
|
+
*/
|
|
195
|
+
async function warnIfIndexStale(cwd, command, iteration) {
|
|
196
|
+
const result = await ensureIndexFresh(cwd, command, iteration);
|
|
197
|
+
if (!result.allFresh) {
|
|
198
|
+
logger_1.logger.warn(result.summary);
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=index-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-guard.js","sourceRoot":"","sources":["../../src/core/index-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,8 @@ import type { AskResult } from './ask-engine';
|
|
|
11
11
|
export interface CachedIntent {
|
|
12
12
|
/** 缓存的输入文本 */
|
|
13
13
|
input: string;
|
|
14
|
+
/** 归一化后的输入(用于语义级缓存命中) */
|
|
15
|
+
normalizedInput: string;
|
|
14
16
|
/** 匹配的 AskResult */
|
|
15
17
|
result: AskResult;
|
|
16
18
|
/** 来源:local / host-ai / llm */
|
|
@@ -29,7 +31,7 @@ export interface IntentCache {
|
|
|
29
31
|
solidified: string[];
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
|
-
*
|
|
34
|
+
* 查询缓存:精确 → 归一化语义 → 编辑距离模糊
|
|
33
35
|
*/
|
|
34
36
|
export declare function getCachedIntent(input: string): Promise<AskResult | null>;
|
|
35
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent-cache.d.ts","sourceRoot":"","sources":["../../src/core/intent-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,MAAM,WAAW,YAAY;IAC3B,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,SAAS,CAAC;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACtC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"intent-cache.d.ts","sourceRoot":"","sources":["../../src/core/intent-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,MAAM,WAAW,YAAY;IAC3B,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,MAAM,EAAE,SAAS,CAAC;IAClB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACtC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAgED;;GAEG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA6C9E;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAE,MAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB7G;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGrF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjE;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CASrG"}
|
|
@@ -20,9 +20,25 @@ const logger_1 = require("../utils/logger");
|
|
|
20
20
|
// 常量
|
|
21
21
|
// ═══════════════════════════════════════════════════════════
|
|
22
22
|
const CACHE_PATH = '.speccore/local/intent-cache.json';
|
|
23
|
-
const CACHE_VERSION = '1.
|
|
23
|
+
const CACHE_VERSION = '1.1'; // 升级到 1.1 支持 normalizedInput
|
|
24
24
|
const MAX_ENTRIES = 200;
|
|
25
25
|
const FUZZY_THRESHOLD = 2; // 编辑距离阈值
|
|
26
|
+
/** 停用词表 */
|
|
27
|
+
const NORMALIZE_STOP_WORDS = new Set([
|
|
28
|
+
'的', '与', '和', '及', '在', '中', '对', '为', '是', '有', '从', '到',
|
|
29
|
+
'the', 'a', 'an', 'and', 'or', 'to', 'of', 'in', 'for', 'on', 'with', 'by',
|
|
30
|
+
'请', '帮我', '给我', '一下', '一个', '这个', '那个',
|
|
31
|
+
]);
|
|
32
|
+
/** 将输入归一化为语义键(去停用词 + 排序) */
|
|
33
|
+
function normalizeInput(input) {
|
|
34
|
+
const tokens = input
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^\u4e00-\u9fa5a-z0-9\s]/g, ' ')
|
|
37
|
+
.split(/\s+/)
|
|
38
|
+
.filter(t => t.length >= 2 && !NORMALIZE_STOP_WORDS.has(t))
|
|
39
|
+
.sort();
|
|
40
|
+
return tokens.slice(0, 6).join('|'); // 取前6个关键词,用 | 分隔
|
|
41
|
+
}
|
|
26
42
|
// ═══════════════════════════════════════════════════════════
|
|
27
43
|
// 缓存读写
|
|
28
44
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -54,7 +70,7 @@ async function saveCache(cache) {
|
|
|
54
70
|
// 公共 API
|
|
55
71
|
// ═══════════════════════════════════════════════════════════
|
|
56
72
|
/**
|
|
57
|
-
*
|
|
73
|
+
* 查询缓存:精确 → 归一化语义 → 编辑距离模糊
|
|
58
74
|
*/
|
|
59
75
|
async function getCachedIntent(input) {
|
|
60
76
|
const cache = await loadCache();
|
|
@@ -67,7 +83,20 @@ async function getCachedIntent(input) {
|
|
|
67
83
|
logger_1.logger.info(`💾 意图缓存命中(精确): "${input.slice(0, 30)}..." → ${exact.result.summary.slice(0, 30)}`);
|
|
68
84
|
return exact.result;
|
|
69
85
|
}
|
|
70
|
-
// 2.
|
|
86
|
+
// 2. 归一化语义匹配("分析一下登录" ≈ "分析登录功能")
|
|
87
|
+
const normalized = normalizeInput(input);
|
|
88
|
+
if (normalized) {
|
|
89
|
+
for (const entry of Object.values(cache.entries)) {
|
|
90
|
+
if (entry.normalizedInput === normalized) {
|
|
91
|
+
entry.hitCount++;
|
|
92
|
+
entry.lastUsed = new Date().toISOString();
|
|
93
|
+
await saveCache(cache);
|
|
94
|
+
logger_1.logger.info(`💾 意图缓存命中(语义): "${input.slice(0, 30)}..." ≈ "${entry.input.slice(0, 30)}..."`);
|
|
95
|
+
return entry.result;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// 3. 模糊匹配(编辑距离 ≤ 2,且长度比例合理)
|
|
71
100
|
// 防止短字符串误匹配:如"补充测试"匹配"补充分析"(编辑距离 2 但语义完全不同)
|
|
72
101
|
for (const [cachedInput, entry] of Object.entries(cache.entries)) {
|
|
73
102
|
const dist = levenshtein(input, cachedInput);
|
|
@@ -92,6 +121,7 @@ async function cacheIntent(input, result, source = 'host-ai') {
|
|
|
92
121
|
const cache = await loadCache();
|
|
93
122
|
cache.entries[input] = {
|
|
94
123
|
input,
|
|
124
|
+
normalizedInput: normalizeInput(input),
|
|
95
125
|
result,
|
|
96
126
|
source,
|
|
97
127
|
hitCount: 1,
|