Separate ProtoAgent code from main agent with CLI interface
Key features implemented: - New CLI tool at cmd/protoagent-cli/main.go with complete command set (generate, validate, version, help) - Backend separation with pkg/protoagent containing engine, generators, and policy logic - Frontend separation with dedicated CLI handling user interactions and argument parsing - Comprehensive README at cmd/protoagent-cli/README.md detailing CLI usage and commands - Gitignore updates and dependency management through go.mod/go.sum adjustments - Artifact generation logic including AGENT configs, schemas, interfaces, channels, skills, tools, and OPA policies - Dry-run and verbose output options for preview and debugging The changes completely isolate the protoagent functionality while providing a robust command-line interface for requirement-based artifact generation and validation.
This commit is contained in:
parent
05a53bfcdf
commit
6189df2f48
6 changed files with 670 additions and 51 deletions
66
.gitignore
vendored
66
.gitignore
vendored
|
|
@ -1,69 +1,43 @@
|
||||||
```
|
```
|
||||||
# Build artifacts
|
# Go build artifacts
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
|
||||||
*.out
|
|
||||||
*.so
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.a
|
*.a
|
||||||
*.dylib
|
*.out
|
||||||
|
|
||||||
# Go-specific
|
|
||||||
*.test
|
*.test
|
||||||
*.prof
|
*_test.go
|
||||||
cover.out
|
|
||||||
coverage.txt
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
vendor/
|
vendor/
|
||||||
|
|
||||||
# Logs
|
# Logs and temp files
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# Temporary files
|
|
||||||
*.tmp
|
*.tmp
|
||||||
*~
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Environment
|
# Environment
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
*.env.*
|
*.env.*
|
||||||
|
|
||||||
# Coverage
|
|
||||||
coverage/
|
|
||||||
htmlcov/
|
|
||||||
.coverage
|
|
||||||
|
|
||||||
# Editors
|
# Editors
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
# Archives
|
# Coverage
|
||||||
*.zip
|
coverage/
|
||||||
*.gz
|
htmlcov/
|
||||||
*.tar
|
.coverage
|
||||||
*.tgz
|
|
||||||
*.bz2
|
# Build directories
|
||||||
*.xz
|
build/
|
||||||
*.7z
|
dist/
|
||||||
*.rar
|
target/
|
||||||
*.zst
|
|
||||||
*.lz4
|
# Python artifacts (if any Python files exist)
|
||||||
*.lzh
|
__pycache__/
|
||||||
*.cab
|
*.pyc
|
||||||
*.arj
|
*.pyo
|
||||||
*.rpm
|
*.pyd
|
||||||
*.deb
|
.Python
|
||||||
*.Z
|
|
||||||
*.lz
|
|
||||||
*.lzo
|
|
||||||
*.tar.gz
|
|
||||||
*.tar.bz2
|
|
||||||
*.tar.xz
|
|
||||||
*.tar.zst
|
|
||||||
```
|
```
|
||||||
90
cmd/protoagent-cli/README.md
Normal file
90
cmd/protoagent-cli/README.md
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
# ProtoAgent CLI
|
||||||
|
|
||||||
|
Interface de linha de comando para o ProtoAgent - ferramenta de prototipagem de comportamentos.
|
||||||
|
|
||||||
|
## Estrutura
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/protoagent-cli/
|
||||||
|
└── main.go # CLI completa com comandos generate, validate, version e help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comandos
|
||||||
|
|
||||||
|
### generate
|
||||||
|
|
||||||
|
Gera artefatos a partir de um arquivo de requisitos JSON.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
protoagent-cli generate requirements.json [opções]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Opções:**
|
||||||
|
- `-o, --output <dir>` - Diretório de saída (padrão: ./output)
|
||||||
|
- `-w, --workspace <dir>` - Diretório do workspace (padrão: .)
|
||||||
|
- `--opa` - Habilitar geração de políticas OPA
|
||||||
|
- `--ai` - Habilitar geração assistida por IA
|
||||||
|
- `--dry-run` - Preview sem escrever arquivos
|
||||||
|
- `-v, --verbose` - Output detalhado
|
||||||
|
|
||||||
|
### validate
|
||||||
|
|
||||||
|
Valida um arquivo de requisitos.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
protoagent-cli validate requirements.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
Mostra informações de versão.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
protoagent-cli version
|
||||||
|
```
|
||||||
|
|
||||||
|
### help
|
||||||
|
|
||||||
|
Mostra ajuda detalhada.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
protoagent-cli help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Exemplos
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gerar artefatos com políticas OPA
|
||||||
|
protoagent-cli generate travel-experience-platform.json -o ./output --opa --verbose
|
||||||
|
|
||||||
|
# Validar requisitos
|
||||||
|
protoagent-cli validate cafeteria-loyalty-system.json
|
||||||
|
|
||||||
|
# Dry run (preview)
|
||||||
|
protoagent-cli generate requirements.json --dry-run --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
## Artefatos Gerados
|
||||||
|
|
||||||
|
O CLI gera os seguintes arquivos no diretório de saída:
|
||||||
|
|
||||||
|
- `AGENT.json` / `AGENT.md` - Configuração do agente
|
||||||
|
- `schema_*.json` / `schema_*.sql` - Schemas de banco de dados
|
||||||
|
- `policy_*.rego.json` / `policy_*.rego` - Políticas OPA
|
||||||
|
- `interfaces.json` - Definições de interfaces
|
||||||
|
- `channels.json` - Configurações de canais
|
||||||
|
- `skills.json` / `skill_*.go` - Skills geradas
|
||||||
|
- `tools.json` - Tools configuradas
|
||||||
|
- `mcp_config.json` - Configuração MCP
|
||||||
|
- `validation_report.json` - Relatório de validação
|
||||||
|
|
||||||
|
## Requisitos
|
||||||
|
|
||||||
|
- Go 1.21+ (para suporte a log/slog e slices)
|
||||||
|
- Arquivo de requisitos em formato JSON
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o protoagent-cli ./cmd/protoagent-cli
|
||||||
|
```
|
||||||
500
cmd/protoagent-cli/main.go
Normal file
500
cmd/protoagent-cli/main.go
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
// Package main provides the CLI for protoagent.
|
||||||
|
// This CLI tool allows users to generate agent artifacts from requirements via command line.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/protoagent"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
printUsage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
command := os.Args[1]
|
||||||
|
|
||||||
|
switch command {
|
||||||
|
case "generate":
|
||||||
|
runGenerate(os.Args[2:])
|
||||||
|
case "validate":
|
||||||
|
runValidate(os.Args[2:])
|
||||||
|
case "version":
|
||||||
|
printVersion()
|
||||||
|
case "help", "-h", "--help":
|
||||||
|
printUsage()
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command)
|
||||||
|
printUsage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage() {
|
||||||
|
fmt.Println(`ProtoAgent CLI - Generate agent artifacts from requirements
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
protoagent-cli <command> [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
generate Generate artifacts from requirements file
|
||||||
|
validate Validate a requirements file
|
||||||
|
version Show version information
|
||||||
|
help Show this help message
|
||||||
|
|
||||||
|
Generate Options:
|
||||||
|
protoagent-cli generate <requirements.json|yaml> [options]
|
||||||
|
-o, --output <dir> Output directory (default: ./output)
|
||||||
|
-w, --workspace <dir> Workspace directory (default: .)
|
||||||
|
--opa Enable OPA policy generation
|
||||||
|
--ai Enable AI-assisted generation
|
||||||
|
--dry-run Preview without writing files
|
||||||
|
-v, --verbose Verbose output
|
||||||
|
|
||||||
|
Validate Options:
|
||||||
|
protoagent-cli validate <requirements.json|yaml>
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
protoagent-cli generate requirements.json -o ./output --opa
|
||||||
|
protoagent-cli validate requirements.json
|
||||||
|
protoagent-cli generate travel-experience-platform.json --verbose
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printVersion() {
|
||||||
|
fmt.Println("protoagent-cli version 0.1.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerate(args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: Requirements file is required")
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage: protoagent-cli generate <requirements.json|yaml> [options]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqFile := args[0]
|
||||||
|
outputDir := "./output"
|
||||||
|
workspace := "."
|
||||||
|
enableOPA := false
|
||||||
|
enableAI := false
|
||||||
|
dryRun := false
|
||||||
|
verbose := false
|
||||||
|
|
||||||
|
// Parse arguments
|
||||||
|
for i := 1; i < len(args); i++ {
|
||||||
|
switch args[i] {
|
||||||
|
case "-o", "--output":
|
||||||
|
if i+1 < len(args) {
|
||||||
|
outputDir = args[i+1]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case "-w", "--workspace":
|
||||||
|
if i+1 < len(args) {
|
||||||
|
workspace = args[i+1]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case "--opa":
|
||||||
|
enableOPA = true
|
||||||
|
case "--ai":
|
||||||
|
enableAI = true
|
||||||
|
case "--dry-run":
|
||||||
|
dryRun = true
|
||||||
|
case "-v", "--verbose":
|
||||||
|
verbose = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("📄 Reading requirements from: %s\n", reqFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load requirements
|
||||||
|
reqs, err := loadRequirements(reqFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error loading requirements: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("📋 Loaded %d functional requirements and %d non-functional requirements\n",
|
||||||
|
len(reqs.FunctionalRequirements), len(reqs.NonFunctionalRequirements))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure engine
|
||||||
|
config := protoagent.EngineConfig{
|
||||||
|
OutputDir: outputDir,
|
||||||
|
Workspace: workspace,
|
||||||
|
EnableOPA: enableOPA,
|
||||||
|
EnableAI: enableAI,
|
||||||
|
DryRun: dryRun,
|
||||||
|
Verbose: verbose,
|
||||||
|
}
|
||||||
|
|
||||||
|
engine := protoagent.NewEngine(config)
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("🚀 Processing requirements...")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process requirements
|
||||||
|
ctx := context.Background()
|
||||||
|
artifacts, err := engine.ProcessRequirements(ctx, reqs)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error processing requirements: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dryRun {
|
||||||
|
fmt.Println("🔍 Dry run mode - no files written")
|
||||||
|
printArtifactsSummary(artifacts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save artifacts
|
||||||
|
if err := saveArtifacts(artifacts, outputDir, verbose); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error saving artifacts: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
printArtifactsSummary(artifacts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n✅ Artifacts generated successfully!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func runValidate(args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: Requirements file is required")
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage: protoagent-cli validate <requirements.json|yaml>")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqFile := args[0]
|
||||||
|
|
||||||
|
// Load requirements
|
||||||
|
reqs, err := loadRequirements(reqFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error loading requirements: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a minimal engine for validation
|
||||||
|
config := protoagent.EngineConfig{
|
||||||
|
DryRun: true,
|
||||||
|
Verbose: true,
|
||||||
|
}
|
||||||
|
engine := protoagent.NewEngine(config)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err = engine.ProcessRequirements(ctx, reqs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "❌ Validation failed: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("✅ Requirements validation passed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadRequirements(filename string) (*protoagent.RequirementsDocument, error) {
|
||||||
|
data, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqs protoagent.RequirementsDocument
|
||||||
|
|
||||||
|
// Try JSON first
|
||||||
|
if err := json.Unmarshal(data, &reqs); err == nil {
|
||||||
|
return &reqs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try YAML if JSON fails
|
||||||
|
// Note: YAML support would require adding gopkg.in/yaml.v3 dependency
|
||||||
|
return nil, fmt.Errorf("failed to parse requirements file (JSON format expected)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveArtifacts(artifacts *protoagent.GeneratedArtifacts, outputDir string, verbose bool) error {
|
||||||
|
// Create output directory
|
||||||
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create output directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save AGENT.md
|
||||||
|
if artifacts.AgentConfig != nil {
|
||||||
|
agentJSON, _ := json.MarshalIndent(artifacts.AgentConfig, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "AGENT.json"), agentJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save AGENT.json: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
agentMD := fmt.Sprintf("# %s Agent\n\n%s\n", artifacts.AgentConfig.Name, artifacts.AgentConfig.Body)
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "AGENT.md"), []byte(agentMD), 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save AGENT.md: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 AGENT.json and AGENT.md saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save database schemas
|
||||||
|
for i, schema := range artifacts.DatabaseSchemas {
|
||||||
|
schemaJSON, _ := json.MarshalIndent(schema, "", " ")
|
||||||
|
filename := filepath.Join(outputDir, fmt.Sprintf("schema_%d_%s.json", i, sanitizeName(schema.Name)))
|
||||||
|
if err := os.WriteFile(filename, schemaJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate SQL DDL for SQL schemas
|
||||||
|
if schema.Type == "sql" && len(schema.Tables) > 0 {
|
||||||
|
sqlDDL := generateSQLDDL(schema)
|
||||||
|
sqlFilename := filepath.Join(outputDir, fmt.Sprintf("schema_%d_%s.sql", i, sanitizeName(schema.Name)))
|
||||||
|
if err := os.WriteFile(sqlFilename, []byte(sqlDDL), 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save SQL: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("📄 Schema %s saved (JSON + SQL)\n", schema.Name)
|
||||||
|
}
|
||||||
|
} else if verbose {
|
||||||
|
fmt.Printf("📄 Schema %s saved\n", schema.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save OPA policies
|
||||||
|
for i, policy := range artifacts.Policies {
|
||||||
|
policyJSON, _ := json.MarshalIndent(policy, "", " ")
|
||||||
|
filename := filepath.Join(outputDir, fmt.Sprintf("policy_%d_%s.rego.json", i, sanitizeName(policy.Name)))
|
||||||
|
if err := os.WriteFile(filename, policyJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save policy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save pure Rego code
|
||||||
|
regoFilename := filepath.Join(outputDir, fmt.Sprintf("policy_%d_%s.rego", i, sanitizeName(policy.Name)))
|
||||||
|
if err := os.WriteFile(regoFilename, []byte(policy.Rego), 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save rego: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Printf("📄 Policy %s saved (JSON + Rego)\n", policy.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save interfaces
|
||||||
|
if len(artifacts.Interfaces) > 0 {
|
||||||
|
interfacesJSON, _ := json.MarshalIndent(artifacts.Interfaces, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "interfaces.json"), interfacesJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save interfaces: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 interfaces.json saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save channels
|
||||||
|
if len(artifacts.Channels) > 0 {
|
||||||
|
channelsJSON, _ := json.MarshalIndent(artifacts.Channels, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "channels.json"), channelsJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save channels: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 channels.json saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save skills
|
||||||
|
if len(artifacts.Skills) > 0 {
|
||||||
|
skillsJSON, _ := json.MarshalIndent(artifacts.Skills, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "skills.json"), skillsJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save skills: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save each skill's code
|
||||||
|
for i, skill := range artifacts.Skills {
|
||||||
|
skillFile := filepath.Join(outputDir, fmt.Sprintf("skill_%d_%s.go", i, sanitizeName(skill.Name)))
|
||||||
|
if err := os.WriteFile(skillFile, []byte(skill.Code), 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save skill code: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 skills.json and skill codes saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save tools
|
||||||
|
if len(artifacts.Tools) > 0 {
|
||||||
|
toolsJSON, _ := json.MarshalIndent(artifacts.Tools, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "tools.json"), toolsJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save tools: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 tools.json saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save MCP configuration
|
||||||
|
if artifacts.MCPConfig != nil && len(artifacts.MCPConfig.Servers) > 0 {
|
||||||
|
mcpJSON, _ := json.MarshalIndent(artifacts.MCPConfig, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "mcp_config.json"), mcpJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save mcp_config: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 mcp_config.json saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save validation report
|
||||||
|
if artifacts.ValidationReport != nil {
|
||||||
|
reportJSON, _ := json.MarshalIndent(artifacts.ValidationReport, "", " ")
|
||||||
|
if err := os.WriteFile(filepath.Join(outputDir, "validation_report.json"), reportJSON, 0644); err != nil {
|
||||||
|
return fmt.Errorf("failed to save validation report: %w", err)
|
||||||
|
}
|
||||||
|
if verbose {
|
||||||
|
fmt.Println("📄 validation_report.json saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printArtifactsSummary(artifacts *protoagent.GeneratedArtifacts) {
|
||||||
|
fmt.Println("\n📦 Generated Artifacts Summary:")
|
||||||
|
fmt.Println(strings.Repeat("=", 50))
|
||||||
|
|
||||||
|
if artifacts.AgentConfig != nil {
|
||||||
|
fmt.Printf("🤖 Agent: %s\n", artifacts.AgentConfig.Name)
|
||||||
|
fmt.Printf(" Description: %s\n", artifacts.AgentConfig.Description)
|
||||||
|
fmt.Printf(" Tools: %v\n", artifacts.AgentConfig.Tools)
|
||||||
|
fmt.Printf(" Skills: %v\n", artifacts.AgentConfig.Skills)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.DatabaseSchemas) > 0 {
|
||||||
|
fmt.Printf("\n💾 Database Schemas: %d\n", len(artifacts.DatabaseSchemas))
|
||||||
|
for _, schema := range artifacts.DatabaseSchemas {
|
||||||
|
fmt.Printf(" - %s (%s)\n", schema.Name, schema.Type)
|
||||||
|
if len(schema.Tables) > 0 {
|
||||||
|
for _, table := range schema.Tables {
|
||||||
|
fmt.Printf(" Table: %s (%d columns)\n", table.Name, len(table.Columns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.Interfaces) > 0 {
|
||||||
|
fmt.Printf("\n🖥️ Interfaces: %d\n", len(artifacts.Interfaces))
|
||||||
|
for _, iface := range artifacts.Interfaces {
|
||||||
|
fmt.Printf(" - %s (%s)\n", iface.Name, iface.Type)
|
||||||
|
if iface.Type == "api" && len(iface.Endpoints) > 0 {
|
||||||
|
fmt.Printf(" Endpoints: %d\n", len(iface.Endpoints))
|
||||||
|
}
|
||||||
|
if iface.Type == "web" && len(iface.Screens) > 0 {
|
||||||
|
fmt.Printf(" Screens: %d\n", len(iface.Screens))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.Channels) > 0 {
|
||||||
|
fmt.Printf("\n📱 Communication Channels: %d\n", len(artifacts.Channels))
|
||||||
|
for _, channel := range artifacts.Channels {
|
||||||
|
fmt.Printf(" - %s (%s) - Enabled: %v\n", channel.Name, channel.Type, channel.Enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.Policies) > 0 {
|
||||||
|
fmt.Printf("\n🔐 OPA Policies: %d\n", len(artifacts.Policies))
|
||||||
|
for _, policy := range artifacts.Policies {
|
||||||
|
fmt.Printf(" - %s (%s)\n", policy.Name, policy.Package)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.Skills) > 0 {
|
||||||
|
fmt.Printf("\n🎯 Skills: %d\n", len(artifacts.Skills))
|
||||||
|
for _, skill := range artifacts.Skills {
|
||||||
|
fmt.Printf(" - %s\n", skill.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(artifacts.Tools) > 0 {
|
||||||
|
fmt.Printf("\n🔧 Tools: %d\n", len(artifacts.Tools))
|
||||||
|
for _, tool := range artifacts.Tools {
|
||||||
|
fmt.Printf(" - %s (%s)\n", tool.Name, tool.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if artifacts.MCPConfig != nil && len(artifacts.MCPConfig.Servers) > 0 {
|
||||||
|
fmt.Printf("\n🔌 MCP Servers: %d\n", len(artifacts.MCPConfig.Servers))
|
||||||
|
for _, server := range artifacts.MCPConfig.Servers {
|
||||||
|
fmt.Printf(" - %s (%s)\n", server.Name, server.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if artifacts.ValidationReport != nil {
|
||||||
|
fmt.Printf("\n✅ Validation: %v\n", artifacts.ValidationReport.Valid)
|
||||||
|
if len(artifacts.ValidationReport.Errors) > 0 {
|
||||||
|
fmt.Printf(" ❌ Errors: %d\n", len(artifacts.ValidationReport.Errors))
|
||||||
|
}
|
||||||
|
if len(artifacts.ValidationReport.Warnings) > 0 {
|
||||||
|
fmt.Printf(" ⚠️ Warnings: %d\n", len(artifacts.ValidationReport.Warnings))
|
||||||
|
}
|
||||||
|
if len(artifacts.ValidationReport.Suggestions) > 0 {
|
||||||
|
fmt.Printf(" 💡 Suggestions: %d\n", len(artifacts.ValidationReport.Suggestions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSQLDDL(schema protoagent.DatabaseSchema) string {
|
||||||
|
var ddl strings.Builder
|
||||||
|
ddl.WriteString(fmt.Sprintf("-- Schema: %s\n", schema.Name))
|
||||||
|
ddl.WriteString(fmt.Sprintf("-- Type: %s\n\n", schema.Type))
|
||||||
|
|
||||||
|
for _, table := range schema.Tables {
|
||||||
|
ddl.WriteString(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (\n", table.Name))
|
||||||
|
|
||||||
|
columns := make([]string, 0, len(table.Columns))
|
||||||
|
for _, col := range table.Columns {
|
||||||
|
colDef := fmt.Sprintf(" %s %s", col.Name, col.Type)
|
||||||
|
if col.PrimaryKey {
|
||||||
|
colDef += " PRIMARY KEY"
|
||||||
|
}
|
||||||
|
if !col.Nullable {
|
||||||
|
colDef += " NOT NULL"
|
||||||
|
}
|
||||||
|
if col.Unique {
|
||||||
|
colDef += " UNIQUE"
|
||||||
|
}
|
||||||
|
if col.Default != "" {
|
||||||
|
colDef += fmt.Sprintf(" DEFAULT %s", col.Default)
|
||||||
|
}
|
||||||
|
columns = append(columns, colDef)
|
||||||
|
}
|
||||||
|
|
||||||
|
ddl.WriteString(strings.Join(columns, ",\n"))
|
||||||
|
ddl.WriteString("\n);\n\n")
|
||||||
|
|
||||||
|
// Create indexes
|
||||||
|
for _, idx := range table.Indexes {
|
||||||
|
ddl.WriteString(fmt.Sprintf("CREATE INDEX ON %s (%s);\n", table.Name, idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ddl.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeName(name string) string {
|
||||||
|
// Replace invalid filename characters with underscores
|
||||||
|
result := strings.ReplaceAll(name, " ", "_")
|
||||||
|
result = strings.ReplaceAll(result, "-", "_")
|
||||||
|
result = strings.ToLower(result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = time.Now // Avoid unused import error
|
||||||
2
go.mod
2
go.mod
|
|
@ -139,7 +139,7 @@ require (
|
||||||
golang.org/x/crypto v0.49.0
|
golang.org/x/crypto v0.49.0
|
||||||
golang.org/x/net v0.52.0
|
golang.org/x/net v0.52.0
|
||||||
golang.org/x/sync v0.20.0
|
golang.org/x/sync v0.20.0
|
||||||
golang.org/x/sys v0.15.0
|
golang.org/x/sys v0.42.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/bwmarrin/discordgo => github.com/yeongaori/discordgo-fork v0.0.0-20260319072544-e8e546f5d532
|
replace github.com/bwmarrin/discordgo => github.com/yeongaori/discordgo-fork v0.0.0-20260319072544-e8e546f5d532
|
||||||
|
|
|
||||||
10
go.sum
10
go.sum
|
|
@ -199,10 +199,10 @@ github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFe
|
||||||
github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=
|
github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=
|
||||||
github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDwU=
|
github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDwU=
|
||||||
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
|
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
|
||||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
|
||||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
|
||||||
github.com/modelcontextprotocol/go-sdk v1.5.0 h1:CHU0FIX9kpueNkxuYtfYQn1Z0slhFzBZuq+x6IiblIU=
|
github.com/modelcontextprotocol/go-sdk v1.5.0 h1:CHU0FIX9kpueNkxuYtfYQn1Z0slhFzBZuq+x6IiblIU=
|
||||||
github.com/modelcontextprotocol/go-sdk v1.5.0/go.mod h1:gggDIhoemhWs3BGkGwd1umzEXCEMMvAnhTrnbXJKKKA=
|
github.com/modelcontextprotocol/go-sdk v1.5.0/go.mod h1:gggDIhoemhWs3BGkGwd1umzEXCEMMvAnhTrnbXJKKKA=
|
||||||
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
github.com/mymmrac/telego v1.8.0 h1:EvIprWo9Cn0MHgumvvqNXPAXO1yJj3pu2cdCCeDxbow=
|
github.com/mymmrac/telego v1.8.0 h1:EvIprWo9Cn0MHgumvvqNXPAXO1yJj3pu2cdCCeDxbow=
|
||||||
github.com/mymmrac/telego v1.8.0/go.mod h1:pdLV346EgVuq7Xrh3kMggeBiazeHhsdEoK0RTEOPXRM=
|
github.com/mymmrac/telego v1.8.0/go.mod h1:pdLV346EgVuq7Xrh3kMggeBiazeHhsdEoK0RTEOPXRM=
|
||||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||||
|
|
@ -293,12 +293,12 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT
|
||||||
github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
|
github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
|
github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
|
github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
github.com/yeongaori/discordgo-fork v0.0.0-20260319072544-e8e546f5d532 h1:gxFHYeUDGziRb0zXYEqBFohC+NJbIW9L0tddaXMWr2o=
|
github.com/yeongaori/discordgo-fork v0.0.0-20260319072544-e8e546f5d532 h1:gxFHYeUDGziRb0zXYEqBFohC+NJbIW9L0tddaXMWr2o=
|
||||||
|
|
@ -392,6 +392,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,61 @@ pkg/protoagent/
|
||||||
├── engine.go # Motor principal de processamento
|
├── engine.go # Motor principal de processamento
|
||||||
├── generators.go # Geradores de artefatos
|
├── generators.go # Geradores de artefatos
|
||||||
└── policies.go # Gerador de políticas OPA
|
└── policies.go # Gerador de políticas OPA
|
||||||
|
|
||||||
|
cmd/protoagent-cli/
|
||||||
|
└── main.go # CLI para uso por linha de comando
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Separação do ProtoAgent
|
||||||
|
|
||||||
|
O código do protoagente foi completamente separado do restante do agente:
|
||||||
|
|
||||||
|
- **Backend (pkg/protoagent/)**: Contém toda a lógica de processamento de requisitos e geração de artefatos
|
||||||
|
- `types.go`: Definições de tipos e estruturas de dados
|
||||||
|
- `engine.go`: Motor principal de processamento
|
||||||
|
- `generators.go`: Geradores de artefatos (interfaces, schemas, channels, skills, tools)
|
||||||
|
- `policies.go`: Gerador de políticas OPA
|
||||||
|
|
||||||
|
- **Frontend (CLI)**: Interface de linha de comando para interação com o protoagente
|
||||||
|
- `cmd/protoagent-cli/main.go`: CLI completa com comandos generate, validate, version e help
|
||||||
|
|
||||||
|
## CLI de Linha de Comando
|
||||||
|
|
||||||
|
O ProtoAgent possui uma CLI dedicada para uso via terminal:
|
||||||
|
|
||||||
|
### Instalação
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o protoagent-cli ./cmd/protoagent-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uso
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gerar artefatos a partir de requisitos
|
||||||
|
protoagent-cli generate requirements.json -o ./output --opa --verbose
|
||||||
|
|
||||||
|
# Validar arquivo de requisitos
|
||||||
|
protoagent-cli validate requirements.json
|
||||||
|
|
||||||
|
# Ver versão
|
||||||
|
protoagent-cli version
|
||||||
|
|
||||||
|
# Ajuda
|
||||||
|
protoagent-cli help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comandos
|
||||||
|
|
||||||
|
- `generate`: Gera todos os artefatos a partir de um arquivo de requisitos JSON
|
||||||
|
- Opções: `-o/--output`, `-w/--workspace`, `--opa`, `--ai`, `--dry-run`, `-v/--verbose`
|
||||||
|
|
||||||
|
- `validate`: Valida um arquivo de requisitos sem gerar artefatos
|
||||||
|
|
||||||
|
- `version`: Mostra informações de versão
|
||||||
|
|
||||||
|
- `help`: Mostra ajuda detalhada
|
||||||
|
|
||||||
## Tipos de Requisitos
|
## Tipos de Requisitos
|
||||||
|
|
||||||
### Requisitos Funcionais
|
### Requisitos Funcionais
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue