@kevisual/project-search 0.0.5 → 0.0.7
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/app.d.ts +4 -0
- package/dist/app.js +74 -27
- package/dist/remote.js +72 -25
- package/package.json +4 -4
package/dist/app.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ type FileProjectData = {
|
|
|
42
42
|
* 文件对应相关信息
|
|
43
43
|
*
|
|
44
44
|
* 具体文件路径
|
|
45
|
+
* /workspace/projects/project-search/src/index.ts
|
|
45
46
|
*/
|
|
46
47
|
filepath: string;
|
|
47
48
|
content?: string;
|
|
@@ -49,6 +50,7 @@ type FileProjectData = {
|
|
|
49
50
|
size: number;
|
|
50
51
|
/**
|
|
51
52
|
* 项目路径,文件所在的项目路径,方便搜索结果展示和过滤
|
|
53
|
+
* /workspace/projects/project-search
|
|
52
54
|
*/
|
|
53
55
|
projectPath: string;
|
|
54
56
|
repo: string;
|
|
@@ -73,6 +75,7 @@ declare class ProjectSearch {
|
|
|
73
75
|
searchFiles(query?: string, options?: {
|
|
74
76
|
projectPath?: string;
|
|
75
77
|
repo?: string;
|
|
78
|
+
filepath?: string;
|
|
76
79
|
title?: string;
|
|
77
80
|
tags?: string | string[];
|
|
78
81
|
summary?: string;
|
|
@@ -232,6 +235,7 @@ declare class ProjectManager implements ProjectManagerInterface {
|
|
|
232
235
|
content: string;
|
|
233
236
|
type: string;
|
|
234
237
|
} | null>;
|
|
238
|
+
writeFile(filepath: string, content: string): Promise<boolean>;
|
|
235
239
|
deleteFile(filepath: string): Promise<boolean>;
|
|
236
240
|
}
|
|
237
241
|
|
package/dist/app.js
CHANGED
|
@@ -25142,21 +25142,25 @@ class ProjectSearch {
|
|
|
25142
25142
|
async searchFiles(query = "", options) {
|
|
25143
25143
|
const filter = [];
|
|
25144
25144
|
if (options?.projectPath)
|
|
25145
|
-
filter.push(`projectPath
|
|
25145
|
+
filter.push(`projectPath starts_with "${options.projectPath}"`);
|
|
25146
25146
|
if (options?.repo)
|
|
25147
25147
|
filter.push(`repo = "${options.repo}"`);
|
|
25148
|
+
if (options?.filepath)
|
|
25149
|
+
filter.push(`filepath starts_with "${options.filepath}"`);
|
|
25150
|
+
if (options?.link)
|
|
25151
|
+
filter.push(`link = "${options.link}"`);
|
|
25152
|
+
const searchTerms = [];
|
|
25148
25153
|
if (options?.title)
|
|
25149
|
-
|
|
25154
|
+
searchTerms.push(options.title);
|
|
25155
|
+
if (options?.summary)
|
|
25156
|
+
searchTerms.push(options.summary);
|
|
25157
|
+
if (options?.description)
|
|
25158
|
+
searchTerms.push(options.description);
|
|
25150
25159
|
if (options?.tags) {
|
|
25151
25160
|
const tags = Array.isArray(options.tags) ? options.tags : [options.tags];
|
|
25152
|
-
tags.forEach((tag) =>
|
|
25161
|
+
tags.forEach((tag) => searchTerms.push(tag));
|
|
25153
25162
|
}
|
|
25154
|
-
|
|
25155
|
-
filter.push(`summary = "${options.summary}"`);
|
|
25156
|
-
if (options?.description)
|
|
25157
|
-
filter.push(`description = "${options.description}"`);
|
|
25158
|
-
if (options?.link)
|
|
25159
|
-
filter.push(`link = "${options.link}"`);
|
|
25163
|
+
const fullQuery = [query, ...searchTerms].filter(Boolean).join(" ");
|
|
25160
25164
|
const limit = options?.limit ?? 1000;
|
|
25161
25165
|
const search = {
|
|
25162
25166
|
filter: filter.length ? filter.join(" AND ") : undefined,
|
|
@@ -25167,7 +25171,7 @@ class ProjectSearch {
|
|
|
25167
25171
|
let allHits = [];
|
|
25168
25172
|
let offset = 0;
|
|
25169
25173
|
while (true) {
|
|
25170
|
-
const searchResults = await this.index.search(
|
|
25174
|
+
const searchResults = await this.index.search(fullQuery, {
|
|
25171
25175
|
...search,
|
|
25172
25176
|
limit: Math.min(limit - allHits.length, 1000),
|
|
25173
25177
|
offset
|
|
@@ -25496,6 +25500,7 @@ var import__2 = __toESM(require_eventemitter32(), 1);
|
|
|
25496
25500
|
|
|
25497
25501
|
// src/project/manager.ts
|
|
25498
25502
|
import fs3 from "node:fs";
|
|
25503
|
+
import path4 from "node:path";
|
|
25499
25504
|
class ProjectManager {
|
|
25500
25505
|
projects = new Map;
|
|
25501
25506
|
projectSearch;
|
|
@@ -25606,6 +25611,20 @@ class ProjectManager {
|
|
|
25606
25611
|
type: "base64"
|
|
25607
25612
|
};
|
|
25608
25613
|
}
|
|
25614
|
+
async writeFile(filepath, content) {
|
|
25615
|
+
try {
|
|
25616
|
+
const buffer = Buffer.from(content, "base64");
|
|
25617
|
+
const dir = path4.dirname(filepath);
|
|
25618
|
+
if (!fs3.existsSync(dir)) {
|
|
25619
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
25620
|
+
}
|
|
25621
|
+
fs3.writeFileSync(filepath, buffer);
|
|
25622
|
+
return true;
|
|
25623
|
+
} catch (error48) {
|
|
25624
|
+
console.error("写入文件失败:", error48);
|
|
25625
|
+
return false;
|
|
25626
|
+
}
|
|
25627
|
+
}
|
|
25609
25628
|
async deleteFile(filepath) {
|
|
25610
25629
|
if (!fileIsExist(filepath)) {
|
|
25611
25630
|
return false;
|
|
@@ -26215,7 +26234,7 @@ var manager = useContextKey("project-manager", new ProjectManager({
|
|
|
26215
26234
|
}));
|
|
26216
26235
|
// src/file-search/index.ts
|
|
26217
26236
|
var import_fast_glob2 = __toESM(require_out4(), 1);
|
|
26218
|
-
import
|
|
26237
|
+
import path5 from "node:path";
|
|
26219
26238
|
import fs4 from "node:fs";
|
|
26220
26239
|
var defaultIgnore = [
|
|
26221
26240
|
"node_modules",
|
|
@@ -26235,7 +26254,7 @@ var defaultIgnore = [
|
|
|
26235
26254
|
class FileSearch {
|
|
26236
26255
|
async searchFiles(options = {}) {
|
|
26237
26256
|
const { cwd = process.cwd(), ignore = [] } = options;
|
|
26238
|
-
const ignoreFile =
|
|
26257
|
+
const ignoreFile = path5.join(cwd, ".gitignore");
|
|
26239
26258
|
const gitIgnorePatterns = fs4.existsSync(ignoreFile) ? fs4.readFileSync(ignoreFile, "utf-8").split(`
|
|
26240
26259
|
`).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")) : [];
|
|
26241
26260
|
const allIgnore = [...defaultIgnore, ...ignore, ...gitIgnorePatterns];
|
|
@@ -27027,10 +27046,10 @@ function mergeDefs2(...defs) {
|
|
|
27027
27046
|
function cloneDef2(schema) {
|
|
27028
27047
|
return mergeDefs2(schema._zod.def);
|
|
27029
27048
|
}
|
|
27030
|
-
function getElementAtPath2(obj,
|
|
27031
|
-
if (!
|
|
27049
|
+
function getElementAtPath2(obj, path6) {
|
|
27050
|
+
if (!path6)
|
|
27032
27051
|
return obj;
|
|
27033
|
-
return
|
|
27052
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
27034
27053
|
}
|
|
27035
27054
|
function promiseAllObject2(promisesObj) {
|
|
27036
27055
|
const keys = Object.keys(promisesObj);
|
|
@@ -27411,11 +27430,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
27411
27430
|
}
|
|
27412
27431
|
return false;
|
|
27413
27432
|
}
|
|
27414
|
-
function prefixIssues2(
|
|
27433
|
+
function prefixIssues2(path6, issues) {
|
|
27415
27434
|
return issues.map((iss) => {
|
|
27416
27435
|
var _a2;
|
|
27417
27436
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
27418
|
-
iss.path.unshift(
|
|
27437
|
+
iss.path.unshift(path6);
|
|
27419
27438
|
return iss;
|
|
27420
27439
|
});
|
|
27421
27440
|
}
|
|
@@ -27598,7 +27617,7 @@ function formatError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27598
27617
|
}
|
|
27599
27618
|
function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
27600
27619
|
const result = { errors: [] };
|
|
27601
|
-
const processError = (error49,
|
|
27620
|
+
const processError = (error49, path6 = []) => {
|
|
27602
27621
|
var _a2, _b;
|
|
27603
27622
|
for (const issue3 of error49.issues) {
|
|
27604
27623
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -27608,7 +27627,7 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27608
27627
|
} else if (issue3.code === "invalid_element") {
|
|
27609
27628
|
processError({ issues: issue3.issues }, issue3.path);
|
|
27610
27629
|
} else {
|
|
27611
|
-
const fullpath = [...
|
|
27630
|
+
const fullpath = [...path6, ...issue3.path];
|
|
27612
27631
|
if (fullpath.length === 0) {
|
|
27613
27632
|
result.errors.push(mapper(issue3));
|
|
27614
27633
|
continue;
|
|
@@ -27640,8 +27659,8 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27640
27659
|
}
|
|
27641
27660
|
function toDotPath2(_path) {
|
|
27642
27661
|
const segs = [];
|
|
27643
|
-
const
|
|
27644
|
-
for (const seg of
|
|
27662
|
+
const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
27663
|
+
for (const seg of path6) {
|
|
27645
27664
|
if (typeof seg === "number")
|
|
27646
27665
|
segs.push(`[${seg}]`);
|
|
27647
27666
|
else if (typeof seg === "symbol")
|
|
@@ -39388,13 +39407,13 @@ function resolveRef2(ref, ctx) {
|
|
|
39388
39407
|
if (!ref.startsWith("#")) {
|
|
39389
39408
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
39390
39409
|
}
|
|
39391
|
-
const
|
|
39392
|
-
if (
|
|
39410
|
+
const path6 = ref.slice(1).split("/").filter(Boolean);
|
|
39411
|
+
if (path6.length === 0) {
|
|
39393
39412
|
return ctx.rootSchema;
|
|
39394
39413
|
}
|
|
39395
39414
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
39396
|
-
if (
|
|
39397
|
-
const key =
|
|
39415
|
+
if (path6[0] === defsKey) {
|
|
39416
|
+
const key = path6[1];
|
|
39398
39417
|
if (!key || !ctx.defs[key]) {
|
|
39399
39418
|
throw new Error(`Reference not found: ${ref}`);
|
|
39400
39419
|
}
|
|
@@ -39937,6 +39956,7 @@ app.route({
|
|
|
39937
39956
|
args: {
|
|
39938
39957
|
q: exports_external2.string().optional().describe("搜索关键词,选填;留空或不传则返回全部文件"),
|
|
39939
39958
|
projectPath: exports_external2.string().optional().describe("按项目根目录路径过滤,仅返回该项目下的文件,选填"),
|
|
39959
|
+
filepath: exports_external2.string().optional().describe("按文件绝对路径过滤,选填"),
|
|
39940
39960
|
repo: exports_external2.string().optional().describe("按代码仓库标识过滤(如 owner/repo),选填"),
|
|
39941
39961
|
title: exports_external2.string().optional().describe("按人工标注的标题字段过滤,选填"),
|
|
39942
39962
|
tags: exports_external2.array(exports_external2.string()).optional().describe("按人工标注的标签列表过滤,选填"),
|
|
@@ -39949,13 +39969,13 @@ app.route({
|
|
|
39949
39969
|
}
|
|
39950
39970
|
}
|
|
39951
39971
|
}).define(async (ctx) => {
|
|
39952
|
-
let { q, projectPath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
|
|
39972
|
+
let { q, projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
|
|
39953
39973
|
if (!q) {
|
|
39954
39974
|
sort = sort ?? ["projectPath:asc"];
|
|
39955
39975
|
limit = limit ?? 1000;
|
|
39956
39976
|
}
|
|
39957
39977
|
const projectSearch = manager.projectSearch;
|
|
39958
|
-
const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent });
|
|
39978
|
+
const hits = await projectSearch.searchFiles(q, { projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent });
|
|
39959
39979
|
ctx.body = { list: hits };
|
|
39960
39980
|
}).addTo(app);
|
|
39961
39981
|
|
|
@@ -39981,6 +40001,33 @@ app.route({
|
|
|
39981
40001
|
ctx.throw(500, "读取文件失败");
|
|
39982
40002
|
}
|
|
39983
40003
|
}).addTo(app);
|
|
40004
|
+
app.route({
|
|
40005
|
+
path: "project-file",
|
|
40006
|
+
key: "update-content",
|
|
40007
|
+
middleware: ["auth-admin"],
|
|
40008
|
+
description: "将 base64 编码的内容写入指定文件路径,用于更新或创建文件",
|
|
40009
|
+
metadata: {
|
|
40010
|
+
args: {
|
|
40011
|
+
filepath: exports_external2.string().nonempty().describe("要写入的文件绝对路径,必填"),
|
|
40012
|
+
content: exports_external2.string().nonempty().describe("文件内容的 base64 编码,必填")
|
|
40013
|
+
}
|
|
40014
|
+
}
|
|
40015
|
+
}).define(async (ctx) => {
|
|
40016
|
+
const { filepath, content } = ctx.query;
|
|
40017
|
+
if (!filepath)
|
|
40018
|
+
ctx.throw(400, "filepath 不能为空");
|
|
40019
|
+
if (!content)
|
|
40020
|
+
ctx.throw(400, "content 不能为空");
|
|
40021
|
+
try {
|
|
40022
|
+
const success3 = await manager.writeFile(filepath, content);
|
|
40023
|
+
if (!success3) {
|
|
40024
|
+
ctx.throw(500, "写入文件失败");
|
|
40025
|
+
}
|
|
40026
|
+
ctx.body = { success: true };
|
|
40027
|
+
} catch (error49) {
|
|
40028
|
+
ctx.throw(500, "写入文件失败");
|
|
40029
|
+
}
|
|
40030
|
+
}).addTo(app);
|
|
39984
40031
|
app.route({
|
|
39985
40032
|
path: "project-file",
|
|
39986
40033
|
key: "update",
|
package/dist/remote.js
CHANGED
|
@@ -25142,21 +25142,25 @@ class ProjectSearch {
|
|
|
25142
25142
|
async searchFiles(query = "", options) {
|
|
25143
25143
|
const filter = [];
|
|
25144
25144
|
if (options?.projectPath)
|
|
25145
|
-
filter.push(`projectPath
|
|
25145
|
+
filter.push(`projectPath starts_with "${options.projectPath}"`);
|
|
25146
25146
|
if (options?.repo)
|
|
25147
25147
|
filter.push(`repo = "${options.repo}"`);
|
|
25148
|
+
if (options?.filepath)
|
|
25149
|
+
filter.push(`filepath starts_with "${options.filepath}"`);
|
|
25150
|
+
if (options?.link)
|
|
25151
|
+
filter.push(`link = "${options.link}"`);
|
|
25152
|
+
const searchTerms = [];
|
|
25148
25153
|
if (options?.title)
|
|
25149
|
-
|
|
25154
|
+
searchTerms.push(options.title);
|
|
25155
|
+
if (options?.summary)
|
|
25156
|
+
searchTerms.push(options.summary);
|
|
25157
|
+
if (options?.description)
|
|
25158
|
+
searchTerms.push(options.description);
|
|
25150
25159
|
if (options?.tags) {
|
|
25151
25160
|
const tags = Array.isArray(options.tags) ? options.tags : [options.tags];
|
|
25152
|
-
tags.forEach((tag) =>
|
|
25161
|
+
tags.forEach((tag) => searchTerms.push(tag));
|
|
25153
25162
|
}
|
|
25154
|
-
|
|
25155
|
-
filter.push(`summary = "${options.summary}"`);
|
|
25156
|
-
if (options?.description)
|
|
25157
|
-
filter.push(`description = "${options.description}"`);
|
|
25158
|
-
if (options?.link)
|
|
25159
|
-
filter.push(`link = "${options.link}"`);
|
|
25163
|
+
const fullQuery = [query, ...searchTerms].filter(Boolean).join(" ");
|
|
25160
25164
|
const limit = options?.limit ?? 1000;
|
|
25161
25165
|
const search = {
|
|
25162
25166
|
filter: filter.length ? filter.join(" AND ") : undefined,
|
|
@@ -25167,7 +25171,7 @@ class ProjectSearch {
|
|
|
25167
25171
|
let allHits = [];
|
|
25168
25172
|
let offset = 0;
|
|
25169
25173
|
while (true) {
|
|
25170
|
-
const searchResults = await this.index.search(
|
|
25174
|
+
const searchResults = await this.index.search(fullQuery, {
|
|
25171
25175
|
...search,
|
|
25172
25176
|
limit: Math.min(limit - allHits.length, 1000),
|
|
25173
25177
|
offset
|
|
@@ -25496,6 +25500,7 @@ var import__2 = __toESM(require_eventemitter32(), 1);
|
|
|
25496
25500
|
|
|
25497
25501
|
// src/project/manager.ts
|
|
25498
25502
|
import fs3 from "node:fs";
|
|
25503
|
+
import path4 from "node:path";
|
|
25499
25504
|
class ProjectManager {
|
|
25500
25505
|
projects = new Map;
|
|
25501
25506
|
projectSearch;
|
|
@@ -25606,6 +25611,20 @@ class ProjectManager {
|
|
|
25606
25611
|
type: "base64"
|
|
25607
25612
|
};
|
|
25608
25613
|
}
|
|
25614
|
+
async writeFile(filepath, content) {
|
|
25615
|
+
try {
|
|
25616
|
+
const buffer = Buffer.from(content, "base64");
|
|
25617
|
+
const dir = path4.dirname(filepath);
|
|
25618
|
+
if (!fs3.existsSync(dir)) {
|
|
25619
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
25620
|
+
}
|
|
25621
|
+
fs3.writeFileSync(filepath, buffer);
|
|
25622
|
+
return true;
|
|
25623
|
+
} catch (error48) {
|
|
25624
|
+
console.error("写入文件失败:", error48);
|
|
25625
|
+
return false;
|
|
25626
|
+
}
|
|
25627
|
+
}
|
|
25609
25628
|
async deleteFile(filepath) {
|
|
25610
25629
|
if (!fileIsExist(filepath)) {
|
|
25611
25630
|
return false;
|
|
@@ -26994,10 +27013,10 @@ function mergeDefs2(...defs) {
|
|
|
26994
27013
|
function cloneDef2(schema) {
|
|
26995
27014
|
return mergeDefs2(schema._zod.def);
|
|
26996
27015
|
}
|
|
26997
|
-
function getElementAtPath2(obj,
|
|
26998
|
-
if (!
|
|
27016
|
+
function getElementAtPath2(obj, path5) {
|
|
27017
|
+
if (!path5)
|
|
26999
27018
|
return obj;
|
|
27000
|
-
return
|
|
27019
|
+
return path5.reduce((acc, key) => acc?.[key], obj);
|
|
27001
27020
|
}
|
|
27002
27021
|
function promiseAllObject2(promisesObj) {
|
|
27003
27022
|
const keys = Object.keys(promisesObj);
|
|
@@ -27378,11 +27397,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
27378
27397
|
}
|
|
27379
27398
|
return false;
|
|
27380
27399
|
}
|
|
27381
|
-
function prefixIssues2(
|
|
27400
|
+
function prefixIssues2(path5, issues) {
|
|
27382
27401
|
return issues.map((iss) => {
|
|
27383
27402
|
var _a2;
|
|
27384
27403
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
27385
|
-
iss.path.unshift(
|
|
27404
|
+
iss.path.unshift(path5);
|
|
27386
27405
|
return iss;
|
|
27387
27406
|
});
|
|
27388
27407
|
}
|
|
@@ -27565,7 +27584,7 @@ function formatError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27565
27584
|
}
|
|
27566
27585
|
function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
27567
27586
|
const result = { errors: [] };
|
|
27568
|
-
const processError = (error49,
|
|
27587
|
+
const processError = (error49, path5 = []) => {
|
|
27569
27588
|
var _a2, _b;
|
|
27570
27589
|
for (const issue3 of error49.issues) {
|
|
27571
27590
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -27575,7 +27594,7 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27575
27594
|
} else if (issue3.code === "invalid_element") {
|
|
27576
27595
|
processError({ issues: issue3.issues }, issue3.path);
|
|
27577
27596
|
} else {
|
|
27578
|
-
const fullpath = [...
|
|
27597
|
+
const fullpath = [...path5, ...issue3.path];
|
|
27579
27598
|
if (fullpath.length === 0) {
|
|
27580
27599
|
result.errors.push(mapper(issue3));
|
|
27581
27600
|
continue;
|
|
@@ -27607,8 +27626,8 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
|
|
|
27607
27626
|
}
|
|
27608
27627
|
function toDotPath2(_path) {
|
|
27609
27628
|
const segs = [];
|
|
27610
|
-
const
|
|
27611
|
-
for (const seg of
|
|
27629
|
+
const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
27630
|
+
for (const seg of path5) {
|
|
27612
27631
|
if (typeof seg === "number")
|
|
27613
27632
|
segs.push(`[${seg}]`);
|
|
27614
27633
|
else if (typeof seg === "symbol")
|
|
@@ -39355,13 +39374,13 @@ function resolveRef2(ref, ctx) {
|
|
|
39355
39374
|
if (!ref.startsWith("#")) {
|
|
39356
39375
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
39357
39376
|
}
|
|
39358
|
-
const
|
|
39359
|
-
if (
|
|
39377
|
+
const path5 = ref.slice(1).split("/").filter(Boolean);
|
|
39378
|
+
if (path5.length === 0) {
|
|
39360
39379
|
return ctx.rootSchema;
|
|
39361
39380
|
}
|
|
39362
39381
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
39363
|
-
if (
|
|
39364
|
-
const key =
|
|
39382
|
+
if (path5[0] === defsKey) {
|
|
39383
|
+
const key = path5[1];
|
|
39365
39384
|
if (!key || !ctx.defs[key]) {
|
|
39366
39385
|
throw new Error(`Reference not found: ${ref}`);
|
|
39367
39386
|
}
|
|
@@ -39904,6 +39923,7 @@ app.route({
|
|
|
39904
39923
|
args: {
|
|
39905
39924
|
q: exports_external2.string().optional().describe("搜索关键词,选填;留空或不传则返回全部文件"),
|
|
39906
39925
|
projectPath: exports_external2.string().optional().describe("按项目根目录路径过滤,仅返回该项目下的文件,选填"),
|
|
39926
|
+
filepath: exports_external2.string().optional().describe("按文件绝对路径过滤,选填"),
|
|
39907
39927
|
repo: exports_external2.string().optional().describe("按代码仓库标识过滤(如 owner/repo),选填"),
|
|
39908
39928
|
title: exports_external2.string().optional().describe("按人工标注的标题字段过滤,选填"),
|
|
39909
39929
|
tags: exports_external2.array(exports_external2.string()).optional().describe("按人工标注的标签列表过滤,选填"),
|
|
@@ -39916,13 +39936,13 @@ app.route({
|
|
|
39916
39936
|
}
|
|
39917
39937
|
}
|
|
39918
39938
|
}).define(async (ctx) => {
|
|
39919
|
-
let { q, projectPath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
|
|
39939
|
+
let { q, projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
|
|
39920
39940
|
if (!q) {
|
|
39921
39941
|
sort = sort ?? ["projectPath:asc"];
|
|
39922
39942
|
limit = limit ?? 1000;
|
|
39923
39943
|
}
|
|
39924
39944
|
const projectSearch = manager.projectSearch;
|
|
39925
|
-
const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent });
|
|
39945
|
+
const hits = await projectSearch.searchFiles(q, { projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent });
|
|
39926
39946
|
ctx.body = { list: hits };
|
|
39927
39947
|
}).addTo(app);
|
|
39928
39948
|
|
|
@@ -39948,6 +39968,33 @@ app.route({
|
|
|
39948
39968
|
ctx.throw(500, "读取文件失败");
|
|
39949
39969
|
}
|
|
39950
39970
|
}).addTo(app);
|
|
39971
|
+
app.route({
|
|
39972
|
+
path: "project-file",
|
|
39973
|
+
key: "update-content",
|
|
39974
|
+
middleware: ["auth-admin"],
|
|
39975
|
+
description: "将 base64 编码的内容写入指定文件路径,用于更新或创建文件",
|
|
39976
|
+
metadata: {
|
|
39977
|
+
args: {
|
|
39978
|
+
filepath: exports_external2.string().nonempty().describe("要写入的文件绝对路径,必填"),
|
|
39979
|
+
content: exports_external2.string().nonempty().describe("文件内容的 base64 编码,必填")
|
|
39980
|
+
}
|
|
39981
|
+
}
|
|
39982
|
+
}).define(async (ctx) => {
|
|
39983
|
+
const { filepath, content } = ctx.query;
|
|
39984
|
+
if (!filepath)
|
|
39985
|
+
ctx.throw(400, "filepath 不能为空");
|
|
39986
|
+
if (!content)
|
|
39987
|
+
ctx.throw(400, "content 不能为空");
|
|
39988
|
+
try {
|
|
39989
|
+
const success3 = await manager.writeFile(filepath, content);
|
|
39990
|
+
if (!success3) {
|
|
39991
|
+
ctx.throw(500, "写入文件失败");
|
|
39992
|
+
}
|
|
39993
|
+
ctx.body = { success: true };
|
|
39994
|
+
} catch (error49) {
|
|
39995
|
+
ctx.throw(500, "写入文件失败");
|
|
39996
|
+
}
|
|
39997
|
+
}).addTo(app);
|
|
39951
39998
|
app.route({
|
|
39952
39999
|
path: "project-file",
|
|
39953
40000
|
key: "update",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/project-search",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"@kevisual/dts": "^0.0.4",
|
|
22
22
|
"@kevisual/remote-app": "^0.0.7",
|
|
23
23
|
"@kevisual/router": "^0.1.1",
|
|
24
|
+
"es-toolkit": "^1.45.1",
|
|
25
|
+
"eventemitter3": "^5.0.4",
|
|
24
26
|
"fast-glob": "^3.3.3",
|
|
25
27
|
"meilisearch": "^0.55.0",
|
|
26
|
-
"zod": "^4.3.6"
|
|
27
|
-
"es-toolkit": "^1.45.1",
|
|
28
|
-
"eventemitter3": "^5.0.4"
|
|
28
|
+
"zod": "^4.3.6"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@parcel/watcher": "^2.5.6"
|