mirror of
https://github.com/chaitin/MonkeyCode.git
synced 2026-02-07 09:14:06 +08:00
feat: Implement CodeSnippet functionality with repository and use case layers, update CLI command references
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
105
backend/domain/codesnippet.go
Normal file
105
backend/domain/codesnippet.go
Normal file
@@ -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
|
||||
}
|
||||
81
backend/internal/codesnippet/repo/codesnippet.go
Normal file
81
backend/internal/codesnippet/repo/codesnippet.go
Normal file
@@ -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
|
||||
}
|
||||
82
backend/internal/codesnippet/usecase/codesnippet.go
Normal file
82
backend/internal/codesnippet/usecase/codesnippet.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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 ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
40
backend/migration/000012_create_codesnippets_table.up.sql
Normal file
40
backend/migration/000012_create_codesnippets_table.up.sql
Normal file
@@ -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;
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user