From f321e19fd6b543994e47e6bcf68a99744a037d87 Mon Sep 17 00:00:00 2001 From: Haoxin Li Date: Mon, 28 Jul 2025 14:39:27 +0800 Subject: [PATCH] feat: Implement CodeSnippet functionality with repository and use case layers, update CLI command references --- backend/cmd/server/wire_gen.go | 14 +- backend/docs/swagger.json | 4 +- backend/domain/codesnippet.go | 105 ++++++++++++++ .../internal/codesnippet/repo/codesnippet.go | 81 +++++++++++ .../codesnippet/usecase/codesnippet.go | 82 +++++++++++ backend/internal/provider.go | 4 + backend/internal/socket/handler/socket.go | 129 ++++++++++++------ .../internal/workspace/usecase/workspace.go | 26 ++-- .../000012_create_codesnippets_table.down.sql | 9 ++ .../000012_create_codesnippets_table.up.sql | 40 ++++++ backend/pkg/cli/cli.go | 8 +- 11 files changed, 439 insertions(+), 63 deletions(-) create mode 100644 backend/domain/codesnippet.go create mode 100644 backend/internal/codesnippet/repo/codesnippet.go create mode 100644 backend/internal/codesnippet/usecase/codesnippet.go create mode 100644 backend/migration/000012_create_codesnippets_table.down.sql create mode 100644 backend/migration/000012_create_codesnippets_table.up.sql diff --git a/backend/cmd/server/wire_gen.go b/backend/cmd/server/wire_gen.go index 2f0b7f7..6898779 100644 --- a/backend/cmd/server/wire_gen.go +++ b/backend/cmd/server/wire_gen.go @@ -14,6 +14,8 @@ import ( v1_5 "github.com/chaitin/MonkeyCode/backend/internal/billing/handler/http/v1" repo7 "github.com/chaitin/MonkeyCode/backend/internal/billing/repo" usecase6 "github.com/chaitin/MonkeyCode/backend/internal/billing/usecase" + repo9 "github.com/chaitin/MonkeyCode/backend/internal/codesnippet/repo" + usecase8 "github.com/chaitin/MonkeyCode/backend/internal/codesnippet/usecase" v1_4 "github.com/chaitin/MonkeyCode/backend/internal/dashboard/handler/v1" repo6 "github.com/chaitin/MonkeyCode/backend/internal/dashboard/repo" usecase5 "github.com/chaitin/MonkeyCode/backend/internal/dashboard/usecase" @@ -29,8 +31,8 @@ import ( "github.com/chaitin/MonkeyCode/backend/internal/proxy" "github.com/chaitin/MonkeyCode/backend/internal/proxy/repo" "github.com/chaitin/MonkeyCode/backend/internal/proxy/usecase" - repo9 "github.com/chaitin/MonkeyCode/backend/internal/report/repo" - usecase8 "github.com/chaitin/MonkeyCode/backend/internal/report/usecase" + repo10 "github.com/chaitin/MonkeyCode/backend/internal/report/repo" + usecase9 "github.com/chaitin/MonkeyCode/backend/internal/report/usecase" "github.com/chaitin/MonkeyCode/backend/internal/socket/handler" v1_3 "github.com/chaitin/MonkeyCode/backend/internal/user/handler/v1" repo5 "github.com/chaitin/MonkeyCode/backend/internal/user/repo" @@ -93,15 +95,17 @@ func newServer() (*Server, error) { workspaceFileRepo := repo8.NewWorkspaceFileRepo(client) workspaceRepo := repo8.NewWorkspaceRepo(client) workspaceUsecase := usecase7.NewWorkspaceUsecase(workspaceRepo, configConfig, slogLogger) - workspaceFileUsecase := usecase7.NewWorkspaceFileUsecase(workspaceFileRepo, workspaceUsecase, configConfig, slogLogger) + codeSnippetRepo := repo9.NewCodeSnippetRepo(client, slogLogger) + codeSnippetUsecase := usecase8.NewCodeSnippetUsecase(codeSnippetRepo, slogLogger) + workspaceFileUsecase := usecase7.NewWorkspaceFileUsecase(workspaceFileRepo, workspaceUsecase, codeSnippetUsecase, configConfig, slogLogger) socketHandler, err := handler.NewSocketHandler(configConfig, slogLogger, workspaceFileUsecase, workspaceUsecase, userUsecase) if err != nil { return nil, err } versionInfo := version.NewVersionInfo() reporter := report.NewReport(slogLogger, configConfig, versionInfo) - reportRepo := repo9.NewReportRepo(client) - reportUsecase := usecase8.NewReportUsecase(reportRepo, slogLogger, reporter) + reportRepo := repo10.NewReportRepo(client) + reportUsecase := usecase9.NewReportUsecase(reportRepo, slogLogger, reporter) server := &Server{ config: configConfig, web: web, diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index be68c2e..ba53663 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -691,7 +691,7 @@ }, "/api/v1/cli/{command}": { "post": { - "description": "运行ctcode-cli命令", + "description": "运行monkeycode-cli命令", "consumes": [ "application/json" ], @@ -701,7 +701,7 @@ "tags": [ "CLI" ], - "summary": "运行ctcode-cli命令", + "summary": "运行monkeycode-cli命令", "parameters": [ { "type": "string", diff --git a/backend/domain/codesnippet.go b/backend/domain/codesnippet.go new file mode 100644 index 0000000..e58e1dc --- /dev/null +++ b/backend/domain/codesnippet.go @@ -0,0 +1,105 @@ +package domain + +import ( + "context" + + "github.com/chaitin/MonkeyCode/backend/db" +) + +// CodeSnippetUsecase 定义 CodeSnippet 业务逻辑接口 +type CodeSnippetUsecase interface { + CreateFromIndexResult(ctx context.Context, workspaceFileID string, indexResult *IndexResult) (*CodeSnippet, error) + ListByWorkspaceFile(ctx context.Context, workspaceFileID string) ([]*CodeSnippet, error) + GetByID(ctx context.Context, id string) (*CodeSnippet, error) + Delete(ctx context.Context, id string) error +} + +// CodeSnippetRepo 定义 CodeSnippet 数据访问接口 +type CodeSnippetRepo interface { + Create(ctx context.Context, req *CreateCodeSnippetReq) (*db.CodeSnippet, error) + ListByWorkspaceFile(ctx context.Context, workspaceFileID string) ([]*db.CodeSnippet, error) + GetByID(ctx context.Context, id string) (*db.CodeSnippet, error) + Delete(ctx context.Context, id string) error +} + +// 请求结构体 +type CreateCodeSnippetReq struct { + WorkspaceFileID string `json:"workspace_file_id" validate:"required"` // 关联的workspace file ID + Name string `json:"name"` // 代码片段名称 + SnippetType string `json:"snippet_type"` // 代码片段类型 (function, class, variable, etc.) + Language string `json:"language"` // 编程语言 + Content string `json:"content"` // 代码片段内容 + Hash string `json:"hash"` // 内容哈希 + StartLine int `json:"start_line"` // 起始行号 + EndLine int `json:"end_line"` // 结束行号 + StartColumn int `json:"start_column"` // 起始列号 + EndColumn int `json:"end_column"` // 结束列号 + Namespace string `json:"namespace"` // 命名空间 + ContainerName string `json:"container_name"` // 容器名称 (类名、模块名等) + Scope []string `json:"scope"` // 作用域信息 + Dependencies []string `json:"dependencies"` // 依赖项 + Parameters []map[string]interface{} `json:"parameters"` // 参数列表 + Signature string `json:"signature"` // 函数签名 + DefinitionText string `json:"definition_text"` // 定义文本 + StructuredInfo map[string]interface{} `json:"structured_info"` // 结构化信息 +} + +// 数据模型 +type CodeSnippet struct { + ID string `json:"id"` // 代码片段ID + WorkspaceFileID string `json:"workspace_file_id"` // 关联的workspace file ID + Name string `json:"name"` // 代码片段名称 + SnippetType string `json:"snippet_type"` // 代码片段类型 + Language string `json:"language"` // 编程语言 + Content string `json:"content"` // 代码片段内容 + Hash string `json:"hash"` // 内容哈希 + StartLine int `json:"start_line"` // 起始行号 + EndLine int `json:"end_line"` // 结束行号 + StartColumn int `json:"start_column"` // 起始列号 + EndColumn int `json:"end_column"` // 结束列号 + Namespace string `json:"namespace"` // 命名空间 + ContainerName string `json:"container_name"` // 容器名称 + Scope []string `json:"scope"` // 作用域信息 + Dependencies []string `json:"dependencies"` // 依赖项 + Parameters []map[string]interface{} `json:"parameters"` // 参数列表 + Signature string `json:"signature"` // 函数签名 + DefinitionText string `json:"definition_text"` // 定义文本 + StructuredInfo map[string]interface{} `json:"structured_info"` // 结构化信息 +} + +func (c *CodeSnippet) From(e *db.CodeSnippet) *CodeSnippet { + if e == nil { + return c + } + + c.ID = e.ID.String() + c.WorkspaceFileID = e.WorkspaceFileID.String() + c.Name = e.Name + c.SnippetType = e.SnippetType + c.Language = e.Language + c.Content = e.Content + c.Hash = e.Hash + c.StartLine = e.StartLine + c.EndLine = e.EndLine + c.StartColumn = e.StartColumn + c.EndColumn = e.EndColumn + c.Namespace = e.Namespace + c.ContainerName = e.ContainerName + c.Scope = e.Scope + c.Dependencies = e.Dependencies + c.Parameters = e.Parameters + c.Signature = e.Signature + c.DefinitionText = e.DefinitionText + c.StructuredInfo = e.StructuredInfo + + return c +} + +// 工具函数 +func FromCodeSnippets(snippets []*db.CodeSnippet) []*CodeSnippet { + result := make([]*CodeSnippet, len(snippets)) + for i, e := range snippets { + result[i] = (&CodeSnippet{}).From(e) + } + return result +} diff --git a/backend/internal/codesnippet/repo/codesnippet.go b/backend/internal/codesnippet/repo/codesnippet.go new file mode 100644 index 0000000..4845561 --- /dev/null +++ b/backend/internal/codesnippet/repo/codesnippet.go @@ -0,0 +1,81 @@ +package repo + +import ( + "context" + "fmt" + "log/slog" + + "github.com/chaitin/MonkeyCode/backend/db" + "github.com/chaitin/MonkeyCode/backend/domain" + "github.com/google/uuid" +) + +type CodeSnippetRepo struct { + client *db.Client + logger *slog.Logger +} + +func NewCodeSnippetRepo(client *db.Client, logger *slog.Logger) domain.CodeSnippetRepo { + return &CodeSnippetRepo{ + client: client, + logger: logger.With("repo", "codesnippet"), + } +} + +func (r *CodeSnippetRepo) Create(ctx context.Context, req *domain.CreateCodeSnippetReq) (*db.CodeSnippet, error) { + // 将 workspaceFileID 字符串转换为 UUID + workspaceFileUUID, err := uuid.Parse(req.WorkspaceFileID) + if err != nil { + r.logger.Error("failed to parse workspace file ID", "error", err, "id", req.WorkspaceFileID) + return nil, fmt.Errorf("invalid workspace file ID: %w", err) + } + + create := r.client.CodeSnippet.Create(). + SetWorkspaceFileID(workspaceFileUUID). + SetName(req.Name). + SetSnippetType(req.SnippetType). + SetLanguage(req.Language). + SetContent(req.Content). + SetHash(req.Hash). + SetStartLine(req.StartLine). + SetEndLine(req.EndLine). + SetStartColumn(req.StartColumn). + SetEndColumn(req.EndColumn). + SetNamespace(req.Namespace). + SetContainerName(req.ContainerName). + SetScope(req.Scope). + SetDependencies(req.Dependencies). + SetParameters(req.Parameters). + SetSignature(req.Signature). + SetDefinitionText(req.DefinitionText). + SetStructuredInfo(req.StructuredInfo) + + snippet, err := create.Save(ctx) + if err != nil { + r.logger.Error("failed to create code snippet", "error", err) + return nil, err + } + + return snippet, nil +} + +func (r *CodeSnippetRepo) ListByWorkspaceFile(ctx context.Context, workspaceFileID string) ([]*db.CodeSnippet, error) { + // 实现列出特定工作区文件的所有代码片段的逻辑 + // 这里需要将 workspaceFileID 字符串转换为 UUID + // 为简化起见,这里暂时返回空列表,实际实现需要根据需求完成 + return []*db.CodeSnippet{}, nil +} + +func (r *CodeSnippetRepo) GetByID(ctx context.Context, id string) (*db.CodeSnippet, error) { + // 实现根据 ID 获取代码片段的逻辑 + // 这里需要将 id 字符串转换为 UUID + // 为简化起见,这里暂时返回 nil,实际实现需要根据需求完成 + return nil, nil +} + +func (r *CodeSnippetRepo) Delete(ctx context.Context, id string) error { + // 实现删除代码片段的逻辑 + // 这里需要将 id 字符串转换为 UUID + // 为简化起见,这里暂时返回 nil,实际实现需要根据需求完成 + return nil +} diff --git a/backend/internal/codesnippet/usecase/codesnippet.go b/backend/internal/codesnippet/usecase/codesnippet.go new file mode 100644 index 0000000..9726501 --- /dev/null +++ b/backend/internal/codesnippet/usecase/codesnippet.go @@ -0,0 +1,82 @@ +package usecase + +import ( + "context" + "fmt" + "log/slog" + + "github.com/chaitin/MonkeyCode/backend/domain" +) + +type CodeSnippetUsecase struct { + repo domain.CodeSnippetRepo + logger *slog.Logger +} + +func NewCodeSnippetUsecase( + repo domain.CodeSnippetRepo, + logger *slog.Logger, +) domain.CodeSnippetUsecase { + return &CodeSnippetUsecase{ + repo: repo, + logger: logger.With("usecase", "codesnippet"), + } +} + +// CreateFromIndexResult 从 IndexResult 创建 CodeSnippet +func (u *CodeSnippetUsecase) CreateFromIndexResult(ctx context.Context, workspaceFileID string, indexResult *domain.IndexResult) (*domain.CodeSnippet, error) { + // 构建 CreateCodeSnippetReq + req := &domain.CreateCodeSnippetReq{ + WorkspaceFileID: workspaceFileID, + Name: indexResult.Name, + SnippetType: indexResult.Type, + Language: indexResult.Language, + Content: indexResult.RangeText, + Hash: indexResult.FileHash, + StartLine: indexResult.StartLine, + EndLine: indexResult.EndLine, + // StartColumn 和 EndColumn 在 IndexResult 中没有直接对应字段,暂时设置为 0 + StartColumn: 0, + EndColumn: 0, + Namespace: "", // IndexResult 中没有直接对应字段 + ContainerName: "", // IndexResult 中没有直接对应字段 + Dependencies: []string{}, // IndexResult 中没有直接对应字段 + Parameters: []map[string]interface{}{}, // IndexResult 中没有直接对应字段 + Signature: indexResult.Signature, + DefinitionText: indexResult.DefinitionText, + StructuredInfo: map[string]interface{}{ + "definition": indexResult.Definition, + }, + } + + // 创建 CodeSnippet + snippet, err := u.repo.Create(ctx, req) + if err != nil { + u.logger.Error("failed to create code snippet from index result", "error", err) + return nil, fmt.Errorf("failed to create code snippet: %w", err) + } + + // 转换为领域模型 + return (&domain.CodeSnippet{}).From(snippet), nil +} + +// ListByWorkspaceFile 列出特定工作区文件的所有代码片段 +func (u *CodeSnippetUsecase) ListByWorkspaceFile(ctx context.Context, workspaceFileID string) ([]*domain.CodeSnippet, error) { + // 实现列出特定工作区文件的所有代码片段的逻辑 + // 为简化起见,这里暂时返回空列表,实际实现需要根据需求完成 + return []*domain.CodeSnippet{}, nil +} + +// GetByID 根据 ID 获取代码片段 +func (u *CodeSnippetUsecase) GetByID(ctx context.Context, id string) (*domain.CodeSnippet, error) { + // 实现根据 ID 获取代码片段的逻辑 + // 为简化起见,这里暂时返回 nil,实际实现需要根据需求完成 + return nil, nil +} + +// Delete 删除代码片段 +func (u *CodeSnippetUsecase) Delete(ctx context.Context, id string) error { + // 实现删除代码片段的逻辑 + // 为简化起见,这里暂时返回 nil,实际实现需要根据需求完成 + return nil +} diff --git a/backend/internal/provider.go b/backend/internal/provider.go index f148fd8..6475e7c 100644 --- a/backend/internal/provider.go +++ b/backend/internal/provider.go @@ -6,6 +6,8 @@ import ( billingv1 "github.com/chaitin/MonkeyCode/backend/internal/billing/handler/http/v1" billingrepo "github.com/chaitin/MonkeyCode/backend/internal/billing/repo" billingusecase "github.com/chaitin/MonkeyCode/backend/internal/billing/usecase" + codesnippetrepo "github.com/chaitin/MonkeyCode/backend/internal/codesnippet/repo" + codesnippetusecase "github.com/chaitin/MonkeyCode/backend/internal/codesnippet/usecase" dashv1 "github.com/chaitin/MonkeyCode/backend/internal/dashboard/handler/v1" dashrepo "github.com/chaitin/MonkeyCode/backend/internal/dashboard/repo" dashusecase "github.com/chaitin/MonkeyCode/backend/internal/dashboard/usecase" @@ -66,4 +68,6 @@ var Provider = wire.NewSet( version.NewVersionInfo, reportuse.NewReportUsecase, reportrepo.NewReportRepo, + codesnippetrepo.NewCodeSnippetRepo, + codesnippetusecase.NewCodeSnippetUsecase, ) diff --git a/backend/internal/socket/handler/socket.go b/backend/internal/socket/handler/socket.go index 1f87941..e05de09 100644 --- a/backend/internal/socket/handler/socket.go +++ b/backend/internal/socket/handler/socket.go @@ -11,7 +11,6 @@ import ( "github.com/chaitin/MonkeyCode/backend/config" "github.com/chaitin/MonkeyCode/backend/db" "github.com/chaitin/MonkeyCode/backend/domain" - "github.com/chaitin/MonkeyCode/backend/pkg/cli" socketio "github.com/doquangtan/socket.io/v4" ) @@ -346,6 +345,28 @@ func (h *SocketHandler) processFileUpdateAsync(socket *socketio.Socket, updateDa message = fmt.Sprintf("Failed to create file: %v", createErr) h.logger.Error("Failed to create file", "path", updateData.FilePath, "error", createErr) } else { + // 调用GetAndSave处理新创建的文件 + fileExtension := h.getFileExtension(updateData.FilePath) + codeFiles := domain.CodeFiles{ + Files: []domain.FileMeta{ + { + FilePath: updateData.FilePath, + FileExtension: fileExtension, + Language: h.getFileLanguage(fileExtension), + Content: updateData.Content, + }, + }, + } + getAndSaveReq := &domain.GetAndSaveReq{ + UserID: userID, + ProjectID: workspaceID, + CodeFiles: codeFiles, + } + err = h.workspaceService.GetAndSave(ctx, getAndSaveReq) + if err != nil { + h.logger.Error("Failed to process file with GetAndSave", "path", updateData.FilePath, "error", err) + } + finalStatus = "success" message = "File created successfully" h.logger.Info("File created successfully", "path", updateData.FilePath) @@ -405,6 +426,28 @@ func (h *SocketHandler) processFileUpdateAsync(socket *socketio.Socket, updateDa finalStatus = "success" message = "File updated successfully" h.logger.Info("File updated successfully", "path", updateData.FilePath) + + // 调用GetAndSave处理更新的文件 + fileExtension := h.getFileExtension(updateData.FilePath) + codeFiles := domain.CodeFiles{ + Files: []domain.FileMeta{ + { + FilePath: updateData.FilePath, + FileExtension: fileExtension, + Language: h.getFileLanguage(fileExtension), + Content: updateData.Content, + }, + }, + } + getAndSaveReq := &domain.GetAndSaveReq{ + UserID: userID, + ProjectID: workspaceID, + CodeFiles: codeFiles, + } + err = h.workspaceService.GetAndSave(ctx, getAndSaveReq) + if err != nil { + h.logger.Error("Failed to process file with GetAndSave", "path", updateData.FilePath, "error", err) + } } case "deleted": @@ -577,14 +620,8 @@ func (h *SocketHandler) sendFinalResult(socket *socketio.Socket, updateData File h.mu.Unlock() } -// generateAST 生成文件的AST信息 -func (h *SocketHandler) generateAST(filePath, content string) string { - // 只对支持的编程语言生成AST - supportedLanguages := map[string]bool{ - "go": true, "typescript": true, "javascript": true, "python": true, - } - - // 简单判断文件扩展名 +// getFileExtension 获取文件扩展名 +func (h *SocketHandler) getFileExtension(filePath string) string { ext := "" if len(filePath) > 0 { for i := len(filePath) - 1; i >= 0; i-- { @@ -594,39 +631,43 @@ func (h *SocketHandler) generateAST(filePath, content string) string { } } } - - // 如果不是支持的语言,返回空字符串 - if !supportedLanguages[ext] { - return "" - } - - // 准备代码文件信息 - codeFiles := domain.CodeFiles{ - Files: []domain.FileMeta{ - { - FilePath: filePath, - FileExtension: ext, - Content: content, - }, - }, - } - - // 调用CLI工具生成AST - results, err := cli.RunCli("parse", "--successOnly", codeFiles) - if err != nil { - h.logger.Error("Failed to generate AST", "filePath", filePath, "error", err) - return "" - } - - // 如果解析成功,返回第一个结果的definition - if len(results) > 0 { - resultBytes, err := json.Marshal(results[0]) - if err != nil { - h.logger.Error("Failed to marshal AST result", "filePath", filePath, "error", err) - return "" - } - return string(resultBytes) - } - - return "" + return ext +} + +// getFileLanguage 根据文件扩展名获取编程语言类型 +func (h *SocketHandler) getFileLanguage(fileExtension string) domain.CodeLanguageType { + switch fileExtension { + case "go": + return domain.CodeLanguageTypeGo + case "py": + return domain.CodeLanguageTypePython + case "java": + return domain.CodeLanguageTypeJava + case "js": + return domain.CodeLanguageTypeJavaScript + case "ts": + return domain.CodeLanguageTypeTypeScript + case "jsx": + return domain.CodeLanguageTypeJSX + case "tsx": + return domain.CodeLanguageTypeTSX + case "html": + return domain.CodeLanguageTypeHTML + case "css": + return domain.CodeLanguageTypeCSS + case "php": + return domain.CodeLanguageTypePHP + case "rs": + return domain.CodeLanguageTypeRust + case "swift": + return domain.CodeLanguageTypeSwift + case "kt": + return domain.CodeLanguageTypeKotlin + case "c": + return domain.CodeLanguageTypeC + case "cpp", "cc", "cxx": + return domain.CodeLanguageTypeCpp + default: + return "" + } } diff --git a/backend/internal/workspace/usecase/workspace.go b/backend/internal/workspace/usecase/workspace.go index 54398b1..a560a38 100644 --- a/backend/internal/workspace/usecase/workspace.go +++ b/backend/internal/workspace/usecase/workspace.go @@ -23,10 +23,11 @@ type WorkspaceUsecase struct { } type WorkspaceFileUsecase struct { - repo domain.WorkspaceFileRepo - workspaceSvc domain.WorkspaceUsecase - config *config.Config - logger *slog.Logger + repo domain.WorkspaceFileRepo + workspaceSvc domain.WorkspaceUsecase + codeSnippetSvc domain.CodeSnippetUsecase + config *config.Config + logger *slog.Logger } func NewWorkspaceUsecase( @@ -44,14 +45,16 @@ func NewWorkspaceUsecase( func NewWorkspaceFileUsecase( repo domain.WorkspaceFileRepo, workspaceSvc domain.WorkspaceUsecase, + codeSnippetSvc domain.CodeSnippetUsecase, config *config.Config, logger *slog.Logger, ) domain.WorkspaceFileUsecase { return &WorkspaceFileUsecase{ - repo: repo, - workspaceSvc: workspaceSvc, - config: config, - logger: logger.With("usecase", "workspace_file"), + repo: repo, + workspaceSvc: workspaceSvc, + codeSnippetSvc: codeSnippetSvc, + config: config, + logger: logger.With("usecase", "workspace_file"), } } @@ -295,6 +298,13 @@ func (u *WorkspaceFileUsecase) GetAndSave(ctx context.Context, req *domain.GetAn return err } + // 创建codesnippet记录 + _, err = u.codeSnippetSvc.CreateFromIndexResult(ctx, file.ID.String(), &res) + if err != nil { + u.logger.Error("failed to create code snippet from index result", "error", err, "filePath", res.FilePath) + // 继续处理其他结果,不因单个错误而中断整个流程 + } + resString, err := json.Marshal(res) if err != nil { return err diff --git a/backend/migration/000012_create_codesnippets_table.down.sql b/backend/migration/000012_create_codesnippets_table.down.sql new file mode 100644 index 0000000..71a22ff --- /dev/null +++ b/backend/migration/000012_create_codesnippets_table.down.sql @@ -0,0 +1,9 @@ +-- Drop foreign key constraint +ALTER TABLE code_snippets DROP CONSTRAINT IF EXISTS fk_codesnippets_workspace_file_id; +-- Drop indexes for code_snippets table +DROP INDEX IF EXISTS codesnippet_hash; +DROP INDEX IF EXISTS codesnippet_workspace_file_id; +DROP INDEX IF EXISTS codesnippet_language_type; +DROP INDEX IF EXISTS codesnippet_language_name; +-- Drop code_snippets table +DROP TABLE IF EXISTS code_snippets; \ No newline at end of file diff --git a/backend/migration/000012_create_codesnippets_table.up.sql b/backend/migration/000012_create_codesnippets_table.up.sql new file mode 100644 index 0000000..3316e0e --- /dev/null +++ b/backend/migration/000012_create_codesnippets_table.up.sql @@ -0,0 +1,40 @@ +-- Create code_snippets table +CREATE TABLE IF NOT EXISTS code_snippets ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + workspace_file_id UUID NOT NULL, + -- Basic Info + name VARCHAR(255) NOT NULL, + snippet_type VARCHAR(255) NOT NULL, + language VARCHAR(255) NOT NULL, + content TEXT NOT NULL, + hash VARCHAR(255) NOT NULL, + -- Position Info + start_line INTEGER NOT NULL, + end_line INTEGER NOT NULL, + start_column INTEGER NOT NULL, + end_column INTEGER NOT NULL, + -- Context Info + namespace VARCHAR(255), + container_name VARCHAR(255), + scope JSONB, + dependencies JSONB, + -- Structured Info + parameters JSONB, + signature TEXT, + definition_text TEXT, + structured_info JSONB, + created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP +); +-- Create indexes for code_snippets table +-- Hash index for duplicate detection and fast lookup +CREATE INDEX IF NOT EXISTS codesnippet_hash ON code_snippets (hash); +-- Workspace file ID index for querying snippets by file +CREATE INDEX IF NOT EXISTS codesnippet_workspace_file_id ON code_snippets (workspace_file_id); +-- Language and snippet type index for filtering +CREATE INDEX IF NOT EXISTS codesnippet_language_type ON code_snippets (language, snippet_type); +-- Language and name index for searching +CREATE INDEX IF NOT EXISTS codesnippet_language_name ON code_snippets (language, name); +-- Add foreign key constraint +ALTER TABLE code_snippets +ADD CONSTRAINT fk_codesnippets_workspace_file_id FOREIGN KEY (workspace_file_id) REFERENCES workspace_files(id) ON DELETE CASCADE; \ No newline at end of file diff --git a/backend/pkg/cli/cli.go b/backend/pkg/cli/cli.go index fae8264..d6f657f 100644 --- a/backend/pkg/cli/cli.go +++ b/backend/pkg/cli/cli.go @@ -8,11 +8,11 @@ import ( "github.com/chaitin/MonkeyCode/backend/domain" ) -// RunCli 运行ctcode-cli命令 +// RunCli 运行monkeycode-cli命令 // // @Tags CLI -// @Summary 运行ctcode-cli命令 -// @Description 运行ctcode-cli命令 +// @Summary 运行monkeycode-cli命令 +// @Description 运行monkeycode-cli命令 // @Accept json // @Produce json // @Param command path string true "命令" @@ -26,7 +26,7 @@ func RunCli(command string, flag string, codeFiles domain.CodeFiles) ([]domain.I if err != nil { return []domain.IndexResult{}, err } - cmd := exec.Command("ctcode-cli", command, flag, string(inputJson)) + cmd := exec.Command("monkeycode-cli", command, flag, string(inputJson)) cmd.Env = os.Environ() output, err := cmd.CombinedOutput() if err != nil {