@hsingjui/contextweaver 0.0.4 → 0.0.5
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/dist/{SearchService-DYGJT2DZ.js → SearchService-SRT2KP6A.js} +1 -1
- package/dist/{chunk-WWYSLCNZ.js → chunk-5MZUQNOD.js} +18 -8
- package/dist/{chunk-QWQ64TBE.js → chunk-T337P433.js} +14 -8
- package/dist/{chunk-O3HDM3CF.js → chunk-XHJNV3MK.js} +10 -9
- package/dist/{codebaseRetrieval-AV4GK6FT.js → codebaseRetrieval-7SCFUVKL.js} +1 -1
- package/dist/index.js +13 -7
- package/dist/{scanner-HYP3L57R.js → scanner-7AZ4CHAR.js} +2 -2
- package/dist/{server-7PYHHTOM.js → server-GSXFZX6I.js} +21 -4
- package/package.json +1 -1
|
@@ -259,15 +259,21 @@ var ProgressTracker = class {
|
|
|
259
259
|
startTime;
|
|
260
260
|
lastLogTime = 0;
|
|
261
261
|
logIntervalMs = 2e3;
|
|
262
|
-
// 每
|
|
263
|
-
|
|
262
|
+
// 每 2 秒输出一次
|
|
263
|
+
onProgress;
|
|
264
|
+
/** 是否跳过日志(单批次时跳过,避免与索引日志混淆) */
|
|
265
|
+
skipLogs;
|
|
266
|
+
constructor(total, onProgress) {
|
|
264
267
|
this.total = total;
|
|
265
268
|
this.startTime = Date.now();
|
|
269
|
+
this.onProgress = onProgress;
|
|
270
|
+
this.skipLogs = total <= 1;
|
|
266
271
|
}
|
|
267
272
|
/** 记录一个批次完成 */
|
|
268
273
|
recordBatch(tokens) {
|
|
269
274
|
this.completed++;
|
|
270
275
|
this.totalTokens += tokens;
|
|
276
|
+
this.onProgress?.(this.completed, this.total);
|
|
271
277
|
const now = Date.now();
|
|
272
278
|
if (now - this.lastLogTime >= this.logIntervalMs) {
|
|
273
279
|
this.logProgress();
|
|
@@ -276,6 +282,7 @@ var ProgressTracker = class {
|
|
|
276
282
|
}
|
|
277
283
|
/** 输出进度 */
|
|
278
284
|
logProgress() {
|
|
285
|
+
if (this.skipLogs) return;
|
|
279
286
|
const elapsed = (Date.now() - this.startTime) / 1e3;
|
|
280
287
|
const percent = Math.round(this.completed / this.total * 100);
|
|
281
288
|
const rate = this.completed / elapsed;
|
|
@@ -293,6 +300,7 @@ var ProgressTracker = class {
|
|
|
293
300
|
}
|
|
294
301
|
/** 完成时输出最终统计 */
|
|
295
302
|
complete() {
|
|
303
|
+
if (this.skipLogs) return;
|
|
296
304
|
const elapsed = (Date.now() - this.startTime) / 1e3;
|
|
297
305
|
logger.info(
|
|
298
306
|
{
|
|
@@ -447,8 +455,9 @@ var EmbeddingClient = class {
|
|
|
447
455
|
* 批量获取 Embedding
|
|
448
456
|
* @param texts 待处理的文本数组
|
|
449
457
|
* @param batchSize 每批次发送的文本数量(默认 20)
|
|
458
|
+
* @param onProgress 可选的进度回调 (completed, total) => void
|
|
450
459
|
*/
|
|
451
|
-
async embedBatch(texts, batchSize = 20) {
|
|
460
|
+
async embedBatch(texts, batchSize = 20, onProgress) {
|
|
452
461
|
if (texts.length === 0) {
|
|
453
462
|
return [];
|
|
454
463
|
}
|
|
@@ -456,7 +465,7 @@ var EmbeddingClient = class {
|
|
|
456
465
|
for (let i = 0; i < texts.length; i += batchSize) {
|
|
457
466
|
batches.push(texts.slice(i, i + batchSize));
|
|
458
467
|
}
|
|
459
|
-
const progress = new ProgressTracker(batches.length);
|
|
468
|
+
const progress = new ProgressTracker(batches.length, onProgress);
|
|
460
469
|
const batchResults = await Promise.all(
|
|
461
470
|
batches.map(
|
|
462
471
|
(batch, batchIndex) => this.processWithRateLimit(batch, batchIndex * batchSize, progress)
|
|
@@ -625,8 +634,9 @@ var Indexer = class {
|
|
|
625
634
|
*
|
|
626
635
|
* @param db SQLite 数据库实例
|
|
627
636
|
* @param results 文件处理结果
|
|
637
|
+
* @param onProgress 可选的进度回调 (indexed, total) => void
|
|
628
638
|
*/
|
|
629
|
-
async indexFiles(db, results) {
|
|
639
|
+
async indexFiles(db, results, onProgress) {
|
|
630
640
|
if (!this.vectorStore) {
|
|
631
641
|
await this.init();
|
|
632
642
|
}
|
|
@@ -670,7 +680,7 @@ var Indexer = class {
|
|
|
670
680
|
stats.deleted = toDelete.length;
|
|
671
681
|
}
|
|
672
682
|
if (toIndex.length > 0) {
|
|
673
|
-
const indexResult = await this.batchIndex(db, toIndex);
|
|
683
|
+
const indexResult = await this.batchIndex(db, toIndex, onProgress);
|
|
674
684
|
stats.indexed = indexResult.success;
|
|
675
685
|
stats.errors = indexResult.errors;
|
|
676
686
|
}
|
|
@@ -694,7 +704,7 @@ var Indexer = class {
|
|
|
694
704
|
* 3. FTS 写入批量化:N 次删除+插入 → 1 次批量删除 + 1 次批量插入
|
|
695
705
|
* 4. 日志汇总化:逐文件日志 → 汇总日志
|
|
696
706
|
*/
|
|
697
|
-
async batchIndex(db, files) {
|
|
707
|
+
async batchIndex(db, files, onProgress) {
|
|
698
708
|
if (files.length === 0) {
|
|
699
709
|
return { success: 0, errors: 0 };
|
|
700
710
|
}
|
|
@@ -715,7 +725,7 @@ var Indexer = class {
|
|
|
715
725
|
logger.info({ count: allTexts.length, files: files.length }, "\u5F00\u59CB\u6279\u91CF Embedding");
|
|
716
726
|
let embeddings;
|
|
717
727
|
try {
|
|
718
|
-
const results = await this.embeddingClient.embedBatch(allTexts);
|
|
728
|
+
const results = await this.embeddingClient.embedBatch(allTexts, 20, onProgress);
|
|
719
729
|
embeddings = results.map((r) => r.embedding);
|
|
720
730
|
} catch (err) {
|
|
721
731
|
const error = err;
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
closeAllIndexers,
|
|
3
3
|
closeAllVectorStores,
|
|
4
4
|
getIndexer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5MZUQNOD.js";
|
|
6
6
|
import {
|
|
7
7
|
batchDelete,
|
|
8
8
|
batchUpdateMtime,
|
|
@@ -1065,15 +1065,12 @@ async function scan(rootPath, options = {}) {
|
|
|
1065
1065
|
const scannedPaths = new Set(
|
|
1066
1066
|
filePaths.map((p) => path3.relative(rootPath, p).replace(/\\/g, "/"))
|
|
1067
1067
|
);
|
|
1068
|
-
let processedCount = 0;
|
|
1069
1068
|
const results = [];
|
|
1070
1069
|
const batchSize = 100;
|
|
1071
1070
|
for (let i = 0; i < filePaths.length; i += batchSize) {
|
|
1072
1071
|
const batch = filePaths.slice(i, i + batchSize);
|
|
1073
1072
|
const batchResults = await processFiles(rootPath, batch, knownFiles);
|
|
1074
1073
|
results.push(...batchResults);
|
|
1075
|
-
processedCount += batch.length;
|
|
1076
|
-
options.onProgress?.(processedCount, filePaths.length);
|
|
1077
1074
|
}
|
|
1078
1075
|
const toAdd = [];
|
|
1079
1076
|
const toUpdateMtime = [];
|
|
@@ -1124,15 +1121,19 @@ async function scan(rootPath, options = {}) {
|
|
|
1124
1121
|
errors: results.filter((r) => r.status === "error").length
|
|
1125
1122
|
};
|
|
1126
1123
|
if (options.vectorIndex !== false) {
|
|
1124
|
+
options.onProgress?.(45, 100, "\u6B63\u5728\u51C6\u5907\u5411\u91CF\u7D22\u5F15...");
|
|
1127
1125
|
const embeddingConfig = getEmbeddingConfig();
|
|
1128
1126
|
const indexer = await getIndexer(projectId, embeddingConfig.dimensions);
|
|
1129
1127
|
const needsVectorIndex = results.filter(
|
|
1130
1128
|
(r) => r.status === "added" || r.status === "modified"
|
|
1131
1129
|
);
|
|
1132
1130
|
const healingPathSet = new Set(getFilesNeedingVectorIndex(db));
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1131
|
+
const healingFilePaths = results.filter((r) => r.status === "unchanged" && healingPathSet.has(r.relPath)).map((r) => r.absPath);
|
|
1132
|
+
let healingFiles = [];
|
|
1133
|
+
if (healingFilePaths.length > 0) {
|
|
1134
|
+
logger.info({ count: healingFilePaths.length }, "\u81EA\u6108\uFF1A\u53D1\u73B0\u9700\u8981\u8865\u7D22\u5F15\u7684\u6587\u4EF6");
|
|
1135
|
+
const processedHealingFiles = await processFiles(rootPath, healingFilePaths, /* @__PURE__ */ new Map());
|
|
1136
|
+
healingFiles = processedHealingFiles.filter((r) => r.status === "added" || r.status === "modified").map((r) => ({ ...r, status: "modified" }));
|
|
1136
1137
|
}
|
|
1137
1138
|
const deletedResults = deletedPaths.map((path4) => ({
|
|
1138
1139
|
absPath: "",
|
|
@@ -1147,7 +1148,11 @@ async function scan(rootPath, options = {}) {
|
|
|
1147
1148
|
}));
|
|
1148
1149
|
const allToIndex = [...needsVectorIndex, ...healingFiles, ...deletedResults];
|
|
1149
1150
|
if (allToIndex.length > 0) {
|
|
1150
|
-
|
|
1151
|
+
options.onProgress?.(45, 100, `\u6B63\u5728\u751F\u6210\u5411\u91CF\u5D4C\u5165... (${allToIndex.length} \u4E2A\u6587\u4EF6)`);
|
|
1152
|
+
const indexStats = await indexer.indexFiles(db, allToIndex, (completed, total) => {
|
|
1153
|
+
const progress = 45 + Math.floor(completed / total * 54);
|
|
1154
|
+
options.onProgress?.(progress, 100, `\u6B63\u5728\u751F\u6210\u5411\u91CF\u5D4C\u5165... (${completed}/${total} \u6279\u6B21)`);
|
|
1155
|
+
});
|
|
1151
1156
|
stats.vectorIndex = {
|
|
1152
1157
|
indexed: indexStats.indexed,
|
|
1153
1158
|
deleted: indexStats.deleted,
|
|
@@ -1155,6 +1160,7 @@ async function scan(rootPath, options = {}) {
|
|
|
1155
1160
|
};
|
|
1156
1161
|
}
|
|
1157
1162
|
}
|
|
1163
|
+
options.onProgress?.(100, 100, "\u7D22\u5F15\u5B8C\u6210");
|
|
1158
1164
|
return stats;
|
|
1159
1165
|
} finally {
|
|
1160
1166
|
closeDb(db);
|
|
@@ -67,9 +67,9 @@ function isProjectIndexed(projectId) {
|
|
|
67
67
|
const dbPath = path.join(BASE_DIR, projectId, "index.db");
|
|
68
68
|
return fs.existsSync(dbPath);
|
|
69
69
|
}
|
|
70
|
-
async function ensureIndexed(repoPath, projectId) {
|
|
70
|
+
async function ensureIndexed(repoPath, projectId, onProgress) {
|
|
71
71
|
const { withLock } = await import("./lock-PX2BX2YN.js");
|
|
72
|
-
const { scan } = await import("./scanner-
|
|
72
|
+
const { scan } = await import("./scanner-7AZ4CHAR.js");
|
|
73
73
|
await withLock(projectId, "index", async () => {
|
|
74
74
|
const wasIndexed = isProjectIndexed(projectId);
|
|
75
75
|
if (!wasIndexed) {
|
|
@@ -77,11 +77,12 @@ async function ensureIndexed(repoPath, projectId) {
|
|
|
77
77
|
{ repoPath, projectId: projectId.slice(0, 10) },
|
|
78
78
|
"\u4EE3\u7801\u5E93\u672A\u521D\u59CB\u5316\uFF0C\u5F00\u59CB\u9996\u6B21\u7D22\u5F15..."
|
|
79
79
|
);
|
|
80
|
+
onProgress?.(0, 100, "\u4EE3\u7801\u5E93\u672A\u7D22\u5F15\uFF0C\u5F00\u59CB\u9996\u6B21\u7D22\u5F15...");
|
|
80
81
|
} else {
|
|
81
82
|
logger.debug({ projectId: projectId.slice(0, 10) }, "\u6267\u884C\u589E\u91CF\u7D22\u5F15...");
|
|
82
83
|
}
|
|
83
84
|
const startTime = Date.now();
|
|
84
|
-
const stats = await scan(repoPath, { vectorIndex: true });
|
|
85
|
+
const stats = await scan(repoPath, { vectorIndex: true, onProgress });
|
|
85
86
|
const elapsed = Date.now() - startTime;
|
|
86
87
|
logger.info(
|
|
87
88
|
{
|
|
@@ -98,7 +99,7 @@ async function ensureIndexed(repoPath, projectId) {
|
|
|
98
99
|
);
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
|
-
async function handleCodebaseRetrieval(args, configOverride = ZEN_CONFIG_OVERRIDE) {
|
|
102
|
+
async function handleCodebaseRetrieval(args, configOverride = ZEN_CONFIG_OVERRIDE, onProgress) {
|
|
102
103
|
const { repo_path, information_request, technical_terms } = args;
|
|
103
104
|
logger.info(
|
|
104
105
|
{
|
|
@@ -118,7 +119,7 @@ async function handleCodebaseRetrieval(args, configOverride = ZEN_CONFIG_OVERRID
|
|
|
118
119
|
return formatEnvMissingResponse(allMissingVars);
|
|
119
120
|
}
|
|
120
121
|
const projectId = generateProjectId(repo_path);
|
|
121
|
-
await ensureIndexed(repo_path, projectId);
|
|
122
|
+
await ensureIndexed(repo_path, projectId, onProgress);
|
|
122
123
|
const query = [information_request, ...technical_terms || []].filter(Boolean).join(" ");
|
|
123
124
|
logger.info(
|
|
124
125
|
{
|
|
@@ -128,7 +129,7 @@ async function handleCodebaseRetrieval(args, configOverride = ZEN_CONFIG_OVERRID
|
|
|
128
129
|
},
|
|
129
130
|
"MCP \u67E5\u8BE2\u6784\u5EFA"
|
|
130
131
|
);
|
|
131
|
-
const { SearchService } = await import("./SearchService-
|
|
132
|
+
const { SearchService } = await import("./SearchService-SRT2KP6A.js");
|
|
132
133
|
const service = new SearchService(projectId, repo_path, configOverride);
|
|
133
134
|
await service.init();
|
|
134
135
|
logger.debug("SearchService \u521D\u59CB\u5316\u5B8C\u6210");
|
|
@@ -176,16 +177,16 @@ async function handleCodebaseRetrieval(args, configOverride = ZEN_CONFIG_OVERRID
|
|
|
176
177
|
},
|
|
177
178
|
"MCP codebase-retrieval \u5B8C\u6210"
|
|
178
179
|
);
|
|
179
|
-
return formatMcpResponse(contextPack
|
|
180
|
+
return formatMcpResponse(contextPack);
|
|
180
181
|
}
|
|
181
|
-
function formatMcpResponse(pack
|
|
182
|
+
function formatMcpResponse(pack) {
|
|
182
183
|
const { files, seeds } = pack;
|
|
183
184
|
const fileBlocks = files.map((file) => {
|
|
184
185
|
const segments = file.segments.map((seg) => formatSegment(seg)).join("\n\n");
|
|
185
186
|
return segments;
|
|
186
187
|
}).join("\n\n---\n\n");
|
|
187
188
|
const summary = [
|
|
188
|
-
`Found ${seeds.length} relevant code blocks
|
|
189
|
+
`Found ${seeds.length} relevant code blocks`,
|
|
189
190
|
`Files: ${files.length}`,
|
|
190
191
|
`Total segments: ${files.reduce((acc, f) => acc + f.segments.length, 0)}`
|
|
191
192
|
].join(" | ");
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
scan
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-T337P433.js";
|
|
5
|
+
import "./chunk-5MZUQNOD.js";
|
|
6
6
|
import {
|
|
7
7
|
generateProjectId
|
|
8
8
|
} from "./chunk-VW5RACJC.js";
|
|
@@ -82,9 +82,15 @@ cli.command("index [path]", "\u626B\u63CF\u4EE3\u7801\u5E93\u5E76\u5EFA\u7ACB\u7
|
|
|
82
82
|
try {
|
|
83
83
|
const stats = await scan(rootPath, {
|
|
84
84
|
force: options.force,
|
|
85
|
-
onProgress: (current, total) => {
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
onProgress: (current, total, message) => {
|
|
86
|
+
if (total !== void 0) {
|
|
87
|
+
const percent = (current / total * 100).toFixed(1);
|
|
88
|
+
logger.info({ current, total, percent: `${percent}%`, message }, "\u626B\u63CF\u8FDB\u5EA6");
|
|
89
|
+
} else if (message) {
|
|
90
|
+
logger.info({ current, message }, "\u626B\u63CF\u8FDB\u5EA6");
|
|
91
|
+
} else {
|
|
92
|
+
logger.info({ current }, "\u626B\u63CF\u8FDB\u5EA6");
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
});
|
|
90
96
|
process.stdout.write("\n");
|
|
@@ -105,7 +111,7 @@ cli.command("index [path]", "\u626B\u63CF\u4EE3\u7801\u5E93\u5E76\u5EFA\u7ACB\u7
|
|
|
105
111
|
}
|
|
106
112
|
});
|
|
107
113
|
cli.command("mcp", "\u542F\u52A8 MCP \u670D\u52A1\u5668").action(async () => {
|
|
108
|
-
const { startMcpServer } = await import("./server-
|
|
114
|
+
const { startMcpServer } = await import("./server-GSXFZX6I.js");
|
|
109
115
|
try {
|
|
110
116
|
await startMcpServer();
|
|
111
117
|
} catch (err) {
|
|
@@ -127,7 +133,7 @@ cli.command("search", "\u672C\u5730\u68C0\u7D22\uFF08\u53C2\u6570\u5BF9\u9F50 MC
|
|
|
127
133
|
}
|
|
128
134
|
const technicalTerms = (options.technicalTerms || "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
129
135
|
const useZen = options.zen !== false;
|
|
130
|
-
const { handleCodebaseRetrieval } = await import("./codebaseRetrieval-
|
|
136
|
+
const { handleCodebaseRetrieval } = await import("./codebaseRetrieval-7SCFUVKL.js");
|
|
131
137
|
const response = await handleCodebaseRetrieval(
|
|
132
138
|
{
|
|
133
139
|
repo_path: repoPath,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
codebaseRetrievalSchema,
|
|
3
3
|
handleCodebaseRetrieval
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XHJNV3MK.js";
|
|
5
5
|
import "./chunk-VW5RACJC.js";
|
|
6
6
|
import {
|
|
7
7
|
logger
|
|
@@ -94,14 +94,31 @@ async function startMcpServer() {
|
|
|
94
94
|
logger.debug("\u6536\u5230 list_tools \u8BF7\u6C42");
|
|
95
95
|
return { tools: TOOLS };
|
|
96
96
|
});
|
|
97
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
97
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
98
98
|
const { name, arguments: args } = request.params;
|
|
99
99
|
logger.info({ tool: name }, "\u6536\u5230 call_tool \u8BF7\u6C42");
|
|
100
|
+
const rawToken = extra._meta?.progressToken;
|
|
101
|
+
const progressToken = typeof rawToken === "string" || typeof rawToken === "number" ? rawToken : void 0;
|
|
102
|
+
const onProgress = progressToken ? async (current, total, message) => {
|
|
103
|
+
try {
|
|
104
|
+
await extra.sendNotification({
|
|
105
|
+
method: "notifications/progress",
|
|
106
|
+
params: {
|
|
107
|
+
progressToken,
|
|
108
|
+
progress: current,
|
|
109
|
+
total,
|
|
110
|
+
message
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} catch (err) {
|
|
114
|
+
logger.debug({ error: err.message }, "\u53D1\u9001\u8FDB\u5EA6\u901A\u77E5\u5931\u8D25");
|
|
115
|
+
}
|
|
116
|
+
} : void 0;
|
|
100
117
|
try {
|
|
101
118
|
switch (name) {
|
|
102
119
|
case "codebase-retrieval": {
|
|
103
120
|
const parsed = codebaseRetrievalSchema.parse(args);
|
|
104
|
-
return await handleCodebaseRetrieval(parsed);
|
|
121
|
+
return await handleCodebaseRetrieval(parsed, void 0, onProgress);
|
|
105
122
|
}
|
|
106
123
|
default:
|
|
107
124
|
throw new Error(`Unknown tool: ${name}`);
|
|
@@ -121,8 +138,8 @@ async function startMcpServer() {
|
|
|
121
138
|
}
|
|
122
139
|
});
|
|
123
140
|
const transport = new StdioServerTransport();
|
|
124
|
-
await server.connect(transport);
|
|
125
141
|
logger.info("MCP \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u7B49\u5F85\u8FDE\u63A5...");
|
|
142
|
+
await server.connect(transport);
|
|
126
143
|
}
|
|
127
144
|
export {
|
|
128
145
|
startMcpServer
|