feat: initialize project structure with essential files and configurations

- Add .gitignore to exclude unnecessary files and directories
- Create .npmrc for npm authentication
- Add AGENTS.md for project documentation
- Initialize package.json with project metadata and dependencies
- Implement app.ts to set up the application and project manager
- Create file-search module for searching files in a directory
- Set up project manager and listener for managing project files
- Implement project search functionality with MeiliSearch integration
- Add routes for authentication and project management
- Create scheduler for task management
- Add tests for file searching and project management functionalities
This commit is contained in:
xiongxiao
2026-03-13 17:22:14 +08:00
committed by cnb
commit 1b131b3961
27 changed files with 1336 additions and 0 deletions

39
src/routes/search.ts Normal file
View File

@@ -0,0 +1,39 @@
import { app, manager } from '../app.ts';
import { z } from 'zod'
/**
* 搜索文件
* query: { q, projectPath?, repo? }
*/
app
.route({
path: 'project-search',
key: 'files',
description: '在已索引的项目文件中执行全文搜索,支持按仓库、目录、标签等字段过滤,以及自定义排序和数量限制',
middleware: ['auth-admin'],
metadata: {
args: {
q: z.string().optional().describe('搜索关键词,选填;留空或不传则返回全部文件'),
projectPath: z.string().optional().describe('按项目根目录路径过滤,仅返回该项目下的文件,选填'),
repo: z.string().optional().describe('按代码仓库标识过滤(如 owner/repo选填'),
title: z.string().optional().describe('按人工标注的标题字段过滤,选填'),
tags: z.array(z.string()).optional().describe('按人工标注的标签列表过滤,选填'),
summary: z.string().optional().describe('按人工标注的摘要字段过滤,选填'),
description: z.string().optional().describe('按人工标注的描述字段过滤,选填'),
link: z.string().optional().describe('按人工标注的外部链接字段过滤,选填'),
sort: z.array(z.string()).optional().describe('排序规则数组,格式为 ["字段:asc"] 或 ["字段:desc"],选填,当 q 为空时默认为 ["projectPath:asc"]'),
limit: z.number().optional().describe('返回结果数量上限,选填,当 q 为空时默认为 1000'),
getContent: z.boolean().optional().describe('是否返回文件内容,默认为 false如果为 true则在结果中包含 content 字段,内容以 base64 编码返回,适用于前端预览或下载场景'),
}
}
})
.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 };
if (!q) {
sort = sort ?? ['projectPath:asc'];
limit = limit ?? 1000;
}
const projectSearch = manager.projectSearch;
const hits = await projectSearch.searchFiles(q, { projectPath, repo, title, tags, summary, description, link, sort, limit, getContent });
ctx.body = { list: hits };
})
.addTo(app);