list_projects
Retrieve all logged conversation projects to track AI-developer interactions, with optional statistics for analysis and continuity management.
Instructions
List all projects with optional statistics
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| includeStats | No | Include statistics for each project |
Implementation Reference
- src/tools/conversationLogger.ts:240-296 (handler)Main tool handler: validates input with validateListProjects, lists projects via fileManager.listProjects(), optionally computes stats with getProjectStats, and returns formatted markdown response.async listProjects(params: unknown): Promise<{ content: Array<{ type: string; text: string }> }> { try { const validatedParams = validateListProjects(params); const { includeStats } = validatedParams; const projects = await this.fileManager.listProjects(); if (projects.length === 0) { return { content: [ { type: 'text', text: '📁 暂无项目记录。\n\n使用 log_conversation 工具开始记录对话到新项目。' } ] }; } let result = `📁 共找到 ${projects.length} 个项目:\n\n`; if (includeStats) { for (const project of projects) { const stats = await this.getProjectStats(project); result += `## ${stats.name}\n`; result += `- 总对话数: ${stats.totalConversations}\n`; result += `- 最后活动: ${stats.lastActivity}\n`; result += `- 支持平台: ${stats.platforms.join(', ') || '无'}\n`; result += `- 常用标签: ${stats.tags.slice(0, 5).join(', ') || '无'}\n\n`; } } else { projects.forEach(project => { result += `- ${project}\n`; }); } return { content: [ { type: 'text', text: result } ] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `参数验证失败: ${error.message}` : `获取项目列表时出错: ${String(error)}`; return { content: [ { type: 'text', text: `❌ ${errorMessage}` } ] }; } }
- src/validation/schemas.ts:63-65 (schema)Zod schema definition for list_projects input parameters.export const ListProjectsSchema = z.object({ includeStats: z.boolean().optional().default(false) });
- src/index.ts:170-171 (registration)Tool dispatch/registration in the CallToolRequest handler switch statement.case 'list_projects': return await this.conversationLogger.listProjects(args || {});
- src/index.ts:139-151 (registration)Tool metadata registration (name, description, inputSchema) in the ListToolsRequest handler.name: 'list_projects', description: 'List all projects with optional statistics', inputSchema: { type: 'object', properties: { includeStats: { type: 'boolean', description: 'Include statistics for each project', default: false } } } }
- src/storage/fileManager.ts:124-159 (helper)Core utility method that lists projects by checking registry, current project, or scanning projects directory.async listProjects(): Promise<string[]> { // For the new design, we primarily work with the current project // But we can also scan the global registry for known projects const registryPath = join(this.getIndexDir(), 'projects-registry.json'); try { const registryContent = await this.readFile(registryPath); if (registryContent) { const registry = JSON.parse(registryContent); return Object.keys(registry); } } catch { // Registry doesn't exist or is corrupted } // If no registry, return current project if detected const projectInfo = await this.getProjectInfo(); if (projectInfo.root) { return [projectInfo.name]; } // Fallback: scan home config directory try { const projectsDir = join(this.homeConfigDir, 'projects'); const entries = await fs.readdir(projectsDir, { withFileTypes: true }); return entries .filter(entry => entry.isDirectory()) .map(entry => entry.name); } catch (error) { if ((error as { code?: string }).code === 'ENOENT') { return []; } const projectsDir = join(this.homeConfigDir, 'projects'); throw new FileOperationError(`Failed to list projects`, projectsDir, 'readdir'); } }