update 0.0.6

This commit is contained in:
xiongxiao
2026-03-13 20:17:33 +08:00
committed by cnb
parent 6e31e24887
commit 711aa221a5
5 changed files with 55 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "@kevisual/project-search", "name": "@kevisual/project-search",
"version": "0.0.5", "version": "0.0.6",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -4,6 +4,7 @@ import { ProjectStore, ProjectDoc } from "./project-store";
import { ProjectListener } from "./project-listener/listener"; import { ProjectListener } from "./project-listener/listener";
import { EventEmitter } from "eventemitter3"; import { EventEmitter } from "eventemitter3";
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path';
import { CustomError } from "@kevisual/router"; import { CustomError } from "@kevisual/router";
type Project = { type Project = {
@@ -171,6 +172,21 @@ export class ProjectManager implements ProjectManagerInterface {
} }
} }
async writeFile(filepath: string, content: string): Promise<boolean> {
try {
const buffer = Buffer.from(content, 'base64');
const dir = path.dirname(filepath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(filepath, buffer);
return true;
} catch (error) {
console.error('写入文件失败:', error);
return false;
}
}
async deleteFile(filepath: string): Promise<boolean> { async deleteFile(filepath: string): Promise<boolean> {
if (!fileIsExist(filepath)) { if (!fileIsExist(filepath)) {
return false; return false;

View File

@@ -78,6 +78,7 @@ export class ProjectSearch {
async searchFiles(query: string = '', options?: { async searchFiles(query: string = '', options?: {
projectPath?: string; projectPath?: string;
repo?: string; repo?: string;
filepath?: string;
title?: string; title?: string;
tags?: string | string[]; tags?: string | string[];
summary?: string; summary?: string;
@@ -93,6 +94,7 @@ export class ProjectSearch {
const filter: string[] = []; const filter: string[] = [];
if (options?.projectPath) filter.push(`projectPath = "${options.projectPath}"`); if (options?.projectPath) filter.push(`projectPath = "${options.projectPath}"`);
if (options?.repo) filter.push(`repo = "${options.repo}"`); if (options?.repo) filter.push(`repo = "${options.repo}"`);
if (options?.filepath) filter.push(`filepath = "${options.filepath}"`);
if (options?.title) filter.push(`title = "${options.title}"`); if (options?.title) filter.push(`title = "${options.title}"`);
if (options?.tags) { if (options?.tags) {
const tags = Array.isArray(options.tags) ? options.tags : [options.tags]; const tags = Array.isArray(options.tags) ? options.tags : [options.tags];

View File

@@ -23,6 +23,39 @@ app.route({
} }
}).addTo(app); }).addTo(app);
/**
* 更新文件内容base64 编码)
*/
app.route({
path: 'project-file',
key: 'update-content',
middleware: ['auth-admin'],
description: '将 base64 编码的内容写入指定文件路径,用于更新或创建文件',
metadata: {
args: {
filepath: z.string().nonempty().describe('要写入的文件绝对路径,必填'),
content: z.string().nonempty().describe('文件内容的 base64 编码,必填'),
}
}
}).define(async (ctx) => {
const { filepath, content } = ctx.query as {
filepath: string;
content: string;
};
if (!filepath) ctx.throw(400, 'filepath 不能为空');
if (!content) ctx.throw(400, 'content 不能为空');
try {
const success = await manager.writeFile(filepath, content);
if (!success) {
ctx.throw(500, '写入文件失败');
}
ctx.body = { success: true };
} catch (error) {
ctx.throw(500, '写入文件失败');
}
}).addTo(app);
/** /**
* 更新文件自定义信息title/tags/summary/description/link * 更新文件自定义信息title/tags/summary/description/link
*/ */

View File

@@ -14,6 +14,7 @@ app
args: { args: {
q: z.string().optional().describe('搜索关键词,选填;留空或不传则返回全部文件'), q: z.string().optional().describe('搜索关键词,选填;留空或不传则返回全部文件'),
projectPath: z.string().optional().describe('按项目根目录路径过滤,仅返回该项目下的文件,选填'), projectPath: z.string().optional().describe('按项目根目录路径过滤,仅返回该项目下的文件,选填'),
filepath: z.string().optional().describe('按文件绝对路径过滤,选填'),
repo: z.string().optional().describe('按代码仓库标识过滤(如 owner/repo选填'), repo: z.string().optional().describe('按代码仓库标识过滤(如 owner/repo选填'),
title: z.string().optional().describe('按人工标注的标题字段过滤,选填'), title: z.string().optional().describe('按人工标注的标题字段过滤,选填'),
tags: z.array(z.string()).optional().describe('按人工标注的标签列表过滤,选填'), tags: z.array(z.string()).optional().describe('按人工标注的标签列表过滤,选填'),
@@ -27,13 +28,13 @@ app
} }
}) })
.define(async (ctx) => { .define(async (ctx) => {
let { q, projectPath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query as { q?: string; projectPath?: string; repo?: string; title?: string; tags?: string[]; summary?: string; description?: string; link?: string; sort?: string[]; limit?: number; getContent?: boolean }; let { q, projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent = false } = ctx.query as { q?: string; projectPath?: string; filepath?: string; repo?: string; title?: string; tags?: string[]; summary?: string; description?: string; link?: string; sort?: string[]; limit?: number; getContent?: boolean };
if (!q) { if (!q) {
sort = sort ?? ['projectPath:asc']; sort = sort ?? ['projectPath:asc'];
limit = limit ?? 1000; limit = limit ?? 1000;
} }
const projectSearch = manager.projectSearch; const projectSearch = manager.projectSearch;
const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent }); const hits = await projectSearch.searchFiles(q, { projectPath, filepath, repo, title, tags, summary, description, link, sort, limit, getContent });
ctx.body = { list: hits }; ctx.body = { list: hits };
}) })
.addTo(app); .addTo(app);