@kevisual/project-search 0.0.5 → 0.0.6

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 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
@@ -25145,6 +25145,8 @@ class ProjectSearch {
25145
25145
  filter.push(`projectPath = "${options.projectPath}"`);
25146
25146
  if (options?.repo)
25147
25147
  filter.push(`repo = "${options.repo}"`);
25148
+ if (options?.filepath)
25149
+ filter.push(`filepath = "${options.filepath}"`);
25148
25150
  if (options?.title)
25149
25151
  filter.push(`title = "${options.title}"`);
25150
25152
  if (options?.tags) {
@@ -25496,6 +25498,7 @@ var import__2 = __toESM(require_eventemitter32(), 1);
25496
25498
 
25497
25499
  // src/project/manager.ts
25498
25500
  import fs3 from "node:fs";
25501
+ import path4 from "node:path";
25499
25502
  class ProjectManager {
25500
25503
  projects = new Map;
25501
25504
  projectSearch;
@@ -25606,6 +25609,20 @@ class ProjectManager {
25606
25609
  type: "base64"
25607
25610
  };
25608
25611
  }
25612
+ async writeFile(filepath, content) {
25613
+ try {
25614
+ const buffer = Buffer.from(content, "base64");
25615
+ const dir = path4.dirname(filepath);
25616
+ if (!fs3.existsSync(dir)) {
25617
+ fs3.mkdirSync(dir, { recursive: true });
25618
+ }
25619
+ fs3.writeFileSync(filepath, buffer);
25620
+ return true;
25621
+ } catch (error48) {
25622
+ console.error("写入文件失败:", error48);
25623
+ return false;
25624
+ }
25625
+ }
25609
25626
  async deleteFile(filepath) {
25610
25627
  if (!fileIsExist(filepath)) {
25611
25628
  return false;
@@ -26215,7 +26232,7 @@ var manager = useContextKey("project-manager", new ProjectManager({
26215
26232
  }));
26216
26233
  // src/file-search/index.ts
26217
26234
  var import_fast_glob2 = __toESM(require_out4(), 1);
26218
- import path4 from "node:path";
26235
+ import path5 from "node:path";
26219
26236
  import fs4 from "node:fs";
26220
26237
  var defaultIgnore = [
26221
26238
  "node_modules",
@@ -26235,7 +26252,7 @@ var defaultIgnore = [
26235
26252
  class FileSearch {
26236
26253
  async searchFiles(options = {}) {
26237
26254
  const { cwd = process.cwd(), ignore = [] } = options;
26238
- const ignoreFile = path4.join(cwd, ".gitignore");
26255
+ const ignoreFile = path5.join(cwd, ".gitignore");
26239
26256
  const gitIgnorePatterns = fs4.existsSync(ignoreFile) ? fs4.readFileSync(ignoreFile, "utf-8").split(`
26240
26257
  `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")) : [];
26241
26258
  const allIgnore = [...defaultIgnore, ...ignore, ...gitIgnorePatterns];
@@ -27027,10 +27044,10 @@ function mergeDefs2(...defs) {
27027
27044
  function cloneDef2(schema) {
27028
27045
  return mergeDefs2(schema._zod.def);
27029
27046
  }
27030
- function getElementAtPath2(obj, path5) {
27031
- if (!path5)
27047
+ function getElementAtPath2(obj, path6) {
27048
+ if (!path6)
27032
27049
  return obj;
27033
- return path5.reduce((acc, key) => acc?.[key], obj);
27050
+ return path6.reduce((acc, key) => acc?.[key], obj);
27034
27051
  }
27035
27052
  function promiseAllObject2(promisesObj) {
27036
27053
  const keys = Object.keys(promisesObj);
@@ -27411,11 +27428,11 @@ function aborted2(x, startIndex = 0) {
27411
27428
  }
27412
27429
  return false;
27413
27430
  }
27414
- function prefixIssues2(path5, issues) {
27431
+ function prefixIssues2(path6, issues) {
27415
27432
  return issues.map((iss) => {
27416
27433
  var _a2;
27417
27434
  (_a2 = iss).path ?? (_a2.path = []);
27418
- iss.path.unshift(path5);
27435
+ iss.path.unshift(path6);
27419
27436
  return iss;
27420
27437
  });
27421
27438
  }
@@ -27598,7 +27615,7 @@ function formatError2(error48, mapper = (issue3) => issue3.message) {
27598
27615
  }
27599
27616
  function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27600
27617
  const result = { errors: [] };
27601
- const processError = (error49, path5 = []) => {
27618
+ const processError = (error49, path6 = []) => {
27602
27619
  var _a2, _b;
27603
27620
  for (const issue3 of error49.issues) {
27604
27621
  if (issue3.code === "invalid_union" && issue3.errors.length) {
@@ -27608,7 +27625,7 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27608
27625
  } else if (issue3.code === "invalid_element") {
27609
27626
  processError({ issues: issue3.issues }, issue3.path);
27610
27627
  } else {
27611
- const fullpath = [...path5, ...issue3.path];
27628
+ const fullpath = [...path6, ...issue3.path];
27612
27629
  if (fullpath.length === 0) {
27613
27630
  result.errors.push(mapper(issue3));
27614
27631
  continue;
@@ -27640,8 +27657,8 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27640
27657
  }
27641
27658
  function toDotPath2(_path) {
27642
27659
  const segs = [];
27643
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
27644
- for (const seg of path5) {
27660
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
27661
+ for (const seg of path6) {
27645
27662
  if (typeof seg === "number")
27646
27663
  segs.push(`[${seg}]`);
27647
27664
  else if (typeof seg === "symbol")
@@ -39388,13 +39405,13 @@ function resolveRef2(ref, ctx) {
39388
39405
  if (!ref.startsWith("#")) {
39389
39406
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
39390
39407
  }
39391
- const path5 = ref.slice(1).split("/").filter(Boolean);
39392
- if (path5.length === 0) {
39408
+ const path6 = ref.slice(1).split("/").filter(Boolean);
39409
+ if (path6.length === 0) {
39393
39410
  return ctx.rootSchema;
39394
39411
  }
39395
39412
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
39396
- if (path5[0] === defsKey) {
39397
- const key = path5[1];
39413
+ if (path6[0] === defsKey) {
39414
+ const key = path6[1];
39398
39415
  if (!key || !ctx.defs[key]) {
39399
39416
  throw new Error(`Reference not found: ${ref}`);
39400
39417
  }
@@ -39937,6 +39954,7 @@ app.route({
39937
39954
  args: {
39938
39955
  q: exports_external2.string().optional().describe("搜索关键词,选填;留空或不传则返回全部文件"),
39939
39956
  projectPath: exports_external2.string().optional().describe("按项目根目录路径过滤,仅返回该项目下的文件,选填"),
39957
+ filepath: exports_external2.string().optional().describe("按文件绝对路径过滤,选填"),
39940
39958
  repo: exports_external2.string().optional().describe("按代码仓库标识过滤(如 owner/repo),选填"),
39941
39959
  title: exports_external2.string().optional().describe("按人工标注的标题字段过滤,选填"),
39942
39960
  tags: exports_external2.array(exports_external2.string()).optional().describe("按人工标注的标签列表过滤,选填"),
@@ -39949,13 +39967,13 @@ app.route({
39949
39967
  }
39950
39968
  }
39951
39969
  }).define(async (ctx) => {
39952
- let { q, projectPath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
39970
+ let { q, projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
39953
39971
  if (!q) {
39954
39972
  sort = sort ?? ["projectPath:asc"];
39955
39973
  limit = limit ?? 1000;
39956
39974
  }
39957
39975
  const projectSearch = manager.projectSearch;
39958
- const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent });
39976
+ const hits = await projectSearch.searchFiles(q, { projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent });
39959
39977
  ctx.body = { list: hits };
39960
39978
  }).addTo(app);
39961
39979
 
@@ -39981,6 +39999,33 @@ app.route({
39981
39999
  ctx.throw(500, "读取文件失败");
39982
40000
  }
39983
40001
  }).addTo(app);
40002
+ app.route({
40003
+ path: "project-file",
40004
+ key: "update-content",
40005
+ middleware: ["auth-admin"],
40006
+ description: "将 base64 编码的内容写入指定文件路径,用于更新或创建文件",
40007
+ metadata: {
40008
+ args: {
40009
+ filepath: exports_external2.string().nonempty().describe("要写入的文件绝对路径,必填"),
40010
+ content: exports_external2.string().nonempty().describe("文件内容的 base64 编码,必填")
40011
+ }
40012
+ }
40013
+ }).define(async (ctx) => {
40014
+ const { filepath, content } = ctx.query;
40015
+ if (!filepath)
40016
+ ctx.throw(400, "filepath 不能为空");
40017
+ if (!content)
40018
+ ctx.throw(400, "content 不能为空");
40019
+ try {
40020
+ const success3 = await manager.writeFile(filepath, content);
40021
+ if (!success3) {
40022
+ ctx.throw(500, "写入文件失败");
40023
+ }
40024
+ ctx.body = { success: true };
40025
+ } catch (error49) {
40026
+ ctx.throw(500, "写入文件失败");
40027
+ }
40028
+ }).addTo(app);
39984
40029
  app.route({
39985
40030
  path: "project-file",
39986
40031
  key: "update",
package/dist/remote.js CHANGED
@@ -25145,6 +25145,8 @@ class ProjectSearch {
25145
25145
  filter.push(`projectPath = "${options.projectPath}"`);
25146
25146
  if (options?.repo)
25147
25147
  filter.push(`repo = "${options.repo}"`);
25148
+ if (options?.filepath)
25149
+ filter.push(`filepath = "${options.filepath}"`);
25148
25150
  if (options?.title)
25149
25151
  filter.push(`title = "${options.title}"`);
25150
25152
  if (options?.tags) {
@@ -25496,6 +25498,7 @@ var import__2 = __toESM(require_eventemitter32(), 1);
25496
25498
 
25497
25499
  // src/project/manager.ts
25498
25500
  import fs3 from "node:fs";
25501
+ import path4 from "node:path";
25499
25502
  class ProjectManager {
25500
25503
  projects = new Map;
25501
25504
  projectSearch;
@@ -25606,6 +25609,20 @@ class ProjectManager {
25606
25609
  type: "base64"
25607
25610
  };
25608
25611
  }
25612
+ async writeFile(filepath, content) {
25613
+ try {
25614
+ const buffer = Buffer.from(content, "base64");
25615
+ const dir = path4.dirname(filepath);
25616
+ if (!fs3.existsSync(dir)) {
25617
+ fs3.mkdirSync(dir, { recursive: true });
25618
+ }
25619
+ fs3.writeFileSync(filepath, buffer);
25620
+ return true;
25621
+ } catch (error48) {
25622
+ console.error("写入文件失败:", error48);
25623
+ return false;
25624
+ }
25625
+ }
25609
25626
  async deleteFile(filepath) {
25610
25627
  if (!fileIsExist(filepath)) {
25611
25628
  return false;
@@ -26994,10 +27011,10 @@ function mergeDefs2(...defs) {
26994
27011
  function cloneDef2(schema) {
26995
27012
  return mergeDefs2(schema._zod.def);
26996
27013
  }
26997
- function getElementAtPath2(obj, path4) {
26998
- if (!path4)
27014
+ function getElementAtPath2(obj, path5) {
27015
+ if (!path5)
26999
27016
  return obj;
27000
- return path4.reduce((acc, key) => acc?.[key], obj);
27017
+ return path5.reduce((acc, key) => acc?.[key], obj);
27001
27018
  }
27002
27019
  function promiseAllObject2(promisesObj) {
27003
27020
  const keys = Object.keys(promisesObj);
@@ -27378,11 +27395,11 @@ function aborted2(x, startIndex = 0) {
27378
27395
  }
27379
27396
  return false;
27380
27397
  }
27381
- function prefixIssues2(path4, issues) {
27398
+ function prefixIssues2(path5, issues) {
27382
27399
  return issues.map((iss) => {
27383
27400
  var _a2;
27384
27401
  (_a2 = iss).path ?? (_a2.path = []);
27385
- iss.path.unshift(path4);
27402
+ iss.path.unshift(path5);
27386
27403
  return iss;
27387
27404
  });
27388
27405
  }
@@ -27565,7 +27582,7 @@ function formatError2(error48, mapper = (issue3) => issue3.message) {
27565
27582
  }
27566
27583
  function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27567
27584
  const result = { errors: [] };
27568
- const processError = (error49, path4 = []) => {
27585
+ const processError = (error49, path5 = []) => {
27569
27586
  var _a2, _b;
27570
27587
  for (const issue3 of error49.issues) {
27571
27588
  if (issue3.code === "invalid_union" && issue3.errors.length) {
@@ -27575,7 +27592,7 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27575
27592
  } else if (issue3.code === "invalid_element") {
27576
27593
  processError({ issues: issue3.issues }, issue3.path);
27577
27594
  } else {
27578
- const fullpath = [...path4, ...issue3.path];
27595
+ const fullpath = [...path5, ...issue3.path];
27579
27596
  if (fullpath.length === 0) {
27580
27597
  result.errors.push(mapper(issue3));
27581
27598
  continue;
@@ -27607,8 +27624,8 @@ function treeifyError2(error48, mapper = (issue3) => issue3.message) {
27607
27624
  }
27608
27625
  function toDotPath2(_path) {
27609
27626
  const segs = [];
27610
- const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
27611
- for (const seg of path4) {
27627
+ const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
27628
+ for (const seg of path5) {
27612
27629
  if (typeof seg === "number")
27613
27630
  segs.push(`[${seg}]`);
27614
27631
  else if (typeof seg === "symbol")
@@ -39355,13 +39372,13 @@ function resolveRef2(ref, ctx) {
39355
39372
  if (!ref.startsWith("#")) {
39356
39373
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
39357
39374
  }
39358
- const path4 = ref.slice(1).split("/").filter(Boolean);
39359
- if (path4.length === 0) {
39375
+ const path5 = ref.slice(1).split("/").filter(Boolean);
39376
+ if (path5.length === 0) {
39360
39377
  return ctx.rootSchema;
39361
39378
  }
39362
39379
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
39363
- if (path4[0] === defsKey) {
39364
- const key = path4[1];
39380
+ if (path5[0] === defsKey) {
39381
+ const key = path5[1];
39365
39382
  if (!key || !ctx.defs[key]) {
39366
39383
  throw new Error(`Reference not found: ${ref}`);
39367
39384
  }
@@ -39904,6 +39921,7 @@ app.route({
39904
39921
  args: {
39905
39922
  q: exports_external2.string().optional().describe("搜索关键词,选填;留空或不传则返回全部文件"),
39906
39923
  projectPath: exports_external2.string().optional().describe("按项目根目录路径过滤,仅返回该项目下的文件,选填"),
39924
+ filepath: exports_external2.string().optional().describe("按文件绝对路径过滤,选填"),
39907
39925
  repo: exports_external2.string().optional().describe("按代码仓库标识过滤(如 owner/repo),选填"),
39908
39926
  title: exports_external2.string().optional().describe("按人工标注的标题字段过滤,选填"),
39909
39927
  tags: exports_external2.array(exports_external2.string()).optional().describe("按人工标注的标签列表过滤,选填"),
@@ -39916,13 +39934,13 @@ app.route({
39916
39934
  }
39917
39935
  }
39918
39936
  }).define(async (ctx) => {
39919
- let { q, projectPath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
39937
+ let { q, projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query;
39920
39938
  if (!q) {
39921
39939
  sort = sort ?? ["projectPath:asc"];
39922
39940
  limit = limit ?? 1000;
39923
39941
  }
39924
39942
  const projectSearch = manager.projectSearch;
39925
- const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent });
39943
+ const hits = await projectSearch.searchFiles(q, { projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent });
39926
39944
  ctx.body = { list: hits };
39927
39945
  }).addTo(app);
39928
39946
 
@@ -39948,6 +39966,33 @@ app.route({
39948
39966
  ctx.throw(500, "读取文件失败");
39949
39967
  }
39950
39968
  }).addTo(app);
39969
+ app.route({
39970
+ path: "project-file",
39971
+ key: "update-content",
39972
+ middleware: ["auth-admin"],
39973
+ description: "将 base64 编码的内容写入指定文件路径,用于更新或创建文件",
39974
+ metadata: {
39975
+ args: {
39976
+ filepath: exports_external2.string().nonempty().describe("要写入的文件绝对路径,必填"),
39977
+ content: exports_external2.string().nonempty().describe("文件内容的 base64 编码,必填")
39978
+ }
39979
+ }
39980
+ }).define(async (ctx) => {
39981
+ const { filepath, content } = ctx.query;
39982
+ if (!filepath)
39983
+ ctx.throw(400, "filepath 不能为空");
39984
+ if (!content)
39985
+ ctx.throw(400, "content 不能为空");
39986
+ try {
39987
+ const success3 = await manager.writeFile(filepath, content);
39988
+ if (!success3) {
39989
+ ctx.throw(500, "写入文件失败");
39990
+ }
39991
+ ctx.body = { success: true };
39992
+ } catch (error49) {
39993
+ ctx.throw(500, "写入文件失败");
39994
+ }
39995
+ }).addTo(app);
39951
39996
  app.route({
39952
39997
  path: "project-file",
39953
39998
  key: "update",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/project-search",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
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"