- go.mod module name
- All 714 import references across 289 Go files
- VERSION: 0.1.0
- CI DB names: switchboard_core_{ci,dev,test}
- Docker image: gobha/switchboard-core
- Test fixtures: JWT issuer, repo names
- .env.example, docker-compose container name
- Compiles clean (go build exit 0)
226 lines
6.0 KiB
Go
226 lines
6.0 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"switchboard-core/workspace"
|
|
)
|
|
|
|
// RegisterGitTools registers the 5 git-related workspace tools.
|
|
// Each declares RequireWorkspace + DenyVisitor availability via workspaceToolBase.
|
|
func RegisterGitTools(gitOps *workspace.GitOps) {
|
|
Register(&gitStatusTool{gitOps: gitOps})
|
|
Register(&gitDiffTool{gitOps: gitOps})
|
|
Register(&gitCommitTool{gitOps: gitOps})
|
|
Register(&gitLogTool{gitOps: gitOps})
|
|
Register(&gitBranchTool{gitOps: gitOps})
|
|
}
|
|
|
|
// ── git_status ───────────────────────────────
|
|
|
|
type gitStatusTool struct {
|
|
workspaceToolBase
|
|
gitOps *workspace.GitOps
|
|
}
|
|
|
|
func (t *gitStatusTool) Definition() ToolDef {
|
|
return ToolDef{
|
|
Name: "git_status",
|
|
DisplayName: "Git Status",
|
|
Description: "Show git working tree status: branch name, staged/modified/untracked files, ahead/behind remote counts.",
|
|
Category: "workspace",
|
|
Parameters: JSONSchema(map[string]interface{}{}, nil),
|
|
}
|
|
}
|
|
|
|
func (t *gitStatusTool) Execute(ctx context.Context, execCtx ExecutionContext, argsJSON string) (string, error) {
|
|
w, err := t.gitOps.LoadWorkspace(ctx, execCtx.WorkspaceID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
status, err := t.gitOps.Status(ctx, w)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
data, _ := json.MarshalIndent(status, "", " ")
|
|
return string(data), nil
|
|
}
|
|
|
|
// ── git_diff ─────────────────────────────────
|
|
|
|
type gitDiffTool struct {
|
|
workspaceToolBase
|
|
gitOps *workspace.GitOps
|
|
}
|
|
|
|
func (t *gitDiffTool) Definition() ToolDef {
|
|
return ToolDef{
|
|
Name: "git_diff",
|
|
DisplayName: "Git Diff",
|
|
Description: "Show git diff for a specific file or all uncommitted changes.",
|
|
Category: "workspace",
|
|
Parameters: JSONSchema(map[string]interface{}{
|
|
"path": Prop("string", "File path to diff (empty for all changes)"),
|
|
}, nil),
|
|
}
|
|
}
|
|
|
|
func (t *gitDiffTool) Execute(ctx context.Context, execCtx ExecutionContext, argsJSON string) (string, error) {
|
|
var args struct {
|
|
Path string `json:"path"`
|
|
}
|
|
json.Unmarshal([]byte(argsJSON), &args)
|
|
|
|
w, err := t.gitOps.LoadWorkspace(ctx, execCtx.WorkspaceID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
diff, err := t.gitOps.Diff(ctx, w, args.Path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if diff == "" {
|
|
return "No changes.", nil
|
|
}
|
|
if len(diff) > 50000 {
|
|
diff = diff[:50000] + "\n... (truncated)"
|
|
}
|
|
return diff, nil
|
|
}
|
|
|
|
// ── git_commit ───────────────────────────────
|
|
|
|
type gitCommitTool struct {
|
|
workspaceToolBase
|
|
gitOps *workspace.GitOps
|
|
}
|
|
|
|
func (t *gitCommitTool) Definition() ToolDef {
|
|
return ToolDef{
|
|
Name: "git_commit",
|
|
DisplayName: "Git Commit",
|
|
Description: "Stage and commit files. Stages all changes if no paths specified.",
|
|
Category: "workspace",
|
|
Parameters: JSONSchema(map[string]interface{}{
|
|
"message": Prop("string", "Commit message"),
|
|
"paths": PropArray("Specific file paths to stage (empty = stage all)"),
|
|
}, []string{"message"}),
|
|
}
|
|
}
|
|
|
|
func (t *gitCommitTool) Execute(ctx context.Context, execCtx ExecutionContext, argsJSON string) (string, error) {
|
|
var args struct {
|
|
Message string `json:"message"`
|
|
Paths []string `json:"paths"`
|
|
}
|
|
if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
|
|
return "", fmt.Errorf("invalid arguments: %w", err)
|
|
}
|
|
if args.Message == "" {
|
|
return "", fmt.Errorf("commit message is required")
|
|
}
|
|
|
|
w, err := t.gitOps.LoadWorkspace(ctx, execCtx.WorkspaceID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if err := t.gitOps.Commit(ctx, w, args.Message, args.Paths); err != nil {
|
|
return "", err
|
|
}
|
|
return fmt.Sprintf("Committed: %s", args.Message), nil
|
|
}
|
|
|
|
// ── git_log ──────────────────────────────────
|
|
|
|
type gitLogTool struct {
|
|
workspaceToolBase
|
|
gitOps *workspace.GitOps
|
|
}
|
|
|
|
func (t *gitLogTool) Definition() ToolDef {
|
|
return ToolDef{
|
|
Name: "git_log",
|
|
DisplayName: "Git Log",
|
|
Description: "Show recent commit history.",
|
|
Category: "workspace",
|
|
Parameters: JSONSchema(map[string]interface{}{
|
|
"count": Prop("integer", "Number of commits to show (default 20, max 100)"),
|
|
}, nil),
|
|
}
|
|
}
|
|
|
|
func (t *gitLogTool) Execute(ctx context.Context, execCtx ExecutionContext, argsJSON string) (string, error) {
|
|
var args struct {
|
|
Count int `json:"count"`
|
|
}
|
|
json.Unmarshal([]byte(argsJSON), &args)
|
|
if args.Count <= 0 {
|
|
args.Count = 20
|
|
}
|
|
if args.Count > 100 {
|
|
args.Count = 100
|
|
}
|
|
|
|
w, err := t.gitOps.LoadWorkspace(ctx, execCtx.WorkspaceID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
entries, err := t.gitOps.Log(ctx, w, args.Count)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
data, _ := json.MarshalIndent(entries, "", " ")
|
|
return string(data), nil
|
|
}
|
|
|
|
// ── git_branch ───────────────────────────────
|
|
|
|
type gitBranchTool struct {
|
|
workspaceToolBase
|
|
gitOps *workspace.GitOps
|
|
}
|
|
|
|
func (t *gitBranchTool) Definition() ToolDef {
|
|
return ToolDef{
|
|
Name: "git_branch",
|
|
DisplayName: "Git Branch",
|
|
Description: "List branches or switch to a different branch.",
|
|
Category: "workspace",
|
|
Parameters: JSONSchema(map[string]interface{}{
|
|
"checkout": Prop("string", "Branch name to switch to (empty = list only)"),
|
|
}, nil),
|
|
}
|
|
}
|
|
|
|
func (t *gitBranchTool) Execute(ctx context.Context, execCtx ExecutionContext, argsJSON string) (string, error) {
|
|
var args struct {
|
|
Checkout string `json:"checkout"`
|
|
}
|
|
json.Unmarshal([]byte(argsJSON), &args)
|
|
|
|
w, err := t.gitOps.LoadWorkspace(ctx, execCtx.WorkspaceID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if args.Checkout != "" {
|
|
if err := t.gitOps.Checkout(ctx, w, args.Checkout); err != nil {
|
|
return "", err
|
|
}
|
|
return fmt.Sprintf("Switched to branch: %s", args.Checkout), nil
|
|
}
|
|
|
|
branches, current, err := t.gitOps.BranchList(ctx, w)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
result := map[string]interface{}{
|
|
"current": current,
|
|
"branches": branches,
|
|
}
|
|
data, _ := json.MarshalIndent(result, "", " ")
|
|
return string(data), nil
|
|
}
|