Skip to content

Commit ae94fb2

Browse files
Improve error handling and logging
This commit enhances error handling and logging across various components, including service initialization, package management, and API responses. It ensures that critical errors are logged with sufficient context and that failures during operations like file operations, service initialization, and transaction commits are handled more gracefully. Key improvements include: - More robust error checking and logging for service initialization in `container.go`. - Improved error handling for file operations in CLI commands (`list.go`, `logs.go`, `package_service.go`, `git.go`, `github.go`, `runner.go`). - Enhanced transaction management by using a helper function `rollbackTx` to consistently handle rollback scenarios and log potential errors. - Added `fmt.Errorf` with `%w` for better error wrapping in `core/services` and `packages` directories. - Refined process management with more explicit error handling during `Stop` and `Wait` operations. - Improved error reporting for MCP server operations, including graceful shutdown procedures and configuration saving. - Added specific error handling for SSE write operations in UI handlers to prevent panics and log issues. - Added a fallback for crypto/rand in `id_generator.go` to ensure ID generation in all environments. - General cleanup and minor refactors for better code readability and maintainability.
1 parent a57ad81 commit ae94fb2

44 files changed

Lines changed: 355 additions & 245 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

control-plane/internal/application/container.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ package application
33
import (
44
"crypto/sha256"
55
"encoding/hex"
6+
"path/filepath"
7+
68
"github.com/your-org/agentfield/control-plane/internal/cli/framework"
79
"github.com/your-org/agentfield/control-plane/internal/config"
810
"github.com/your-org/agentfield/control-plane/internal/core/services"
911
"github.com/your-org/agentfield/control-plane/internal/infrastructure/process"
1012
"github.com/your-org/agentfield/control-plane/internal/infrastructure/storage"
13+
"github.com/your-org/agentfield/control-plane/internal/logger"
1114
didServices "github.com/your-org/agentfield/control-plane/internal/services"
1215
storageInterface "github.com/your-org/agentfield/control-plane/internal/storage"
13-
"path/filepath"
1416
)
1517

1618
// CreateServiceContainer creates and wires up all services for the CLI commands
@@ -72,15 +74,21 @@ func CreateServiceContainer(cfg *config.Config, agentfieldHome string) *framewor
7274
// Generate af server ID based on agentfield home directory
7375
// This ensures each agentfield instance has a unique ID while being deterministic
7476
agentfieldServerID := generateAgentFieldServerID(agentfieldHome)
75-
didService.Initialize(agentfieldServerID)
76-
77-
// Create VC service with database storage (required)
78-
if storageProvider != nil {
79-
vcService = didServices.NewVCService(&cfg.Features.DID, didService, storageProvider)
80-
}
81-
82-
if vcService != nil {
83-
vcService.Initialize()
77+
if err := didService.Initialize(agentfieldServerID); err != nil {
78+
logger.Logger.Warn().Err(err).Msg("failed to initialize DID service")
79+
didService = nil
80+
} else {
81+
// Create VC service with database storage (required)
82+
if storageProvider != nil {
83+
vcService = didServices.NewVCService(&cfg.Features.DID, didService, storageProvider)
84+
}
85+
86+
if vcService != nil {
87+
if err := vcService.Initialize(); err != nil {
88+
logger.Logger.Warn().Err(err).Msg("failed to initialize VC service")
89+
vcService = nil
90+
}
91+
}
8492
}
8593
}
8694
}

control-plane/internal/cli/add.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Template Variables:
8888
RunE: func(cmd *cobra.Command, args []string) error {
8989
opts.Source = args[0]
9090
// If --alias flag is not used, and a second positional arg is present, use it as alias.
91-
if cmd.Flags().Changed("alias") == false && len(args) > 1 {
91+
if !cmd.Flags().Changed("alias") && len(args) > 1 {
9292
opts.Alias = args[1]
9393
}
9494
// verbose flag is typically a persistent flag from the root command.
@@ -169,9 +169,8 @@ func NewMCPAddCommand(projectDir string, opts *MCPAddOptions, verboseFlag bool)
169169
}
170170

171171
// Determine final alias
172-
finalAlias := opts.Alias
173-
if finalAlias == "" {
174-
finalAlias = deriveAliasLocally(opts.Source) // Using local helper for now
172+
if opts.Alias == "" {
173+
opts.Alias = deriveAliasLocally(opts.Source) // Using local helper for now
175174
}
176175

177176
// Construct MCPServerConfig (this will be part of the MCPAddCommand or its options)

control-plane/internal/cli/init.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var (
3939
Foreground(lipgloss.Color("196")).
4040
Bold(true)
4141

42-
successStyle = lipgloss.NewStyle().
42+
successStyle = lipgloss.NewStyle(). //nolint:unused // Reserved for future use
4343
Foreground(lipgloss.Color("42")).
4444
Bold(true)
4545
)
@@ -56,7 +56,7 @@ type initModel struct {
5656
textInput string
5757
err error
5858
done bool
59-
nonInteractive bool
59+
nonInteractive bool //nolint:unused // Reserved for future use
6060
}
6161

6262
func (m initModel) Init() tea.Cmd {
@@ -413,9 +413,15 @@ Example:
413413
cmd.Flags().StringVarP(&authorEmail, "email", "e", "", "Author email for the project")
414414
cmd.Flags().BoolVar(&nonInteractive, "non-interactive", false, "Run in non-interactive mode (use defaults)")
415415

416-
viper.BindPFlag("language", cmd.Flags().Lookup("language"))
417-
viper.BindPFlag("author.name", cmd.Flags().Lookup("author"))
418-
viper.BindPFlag("author.email", cmd.Flags().Lookup("email"))
416+
if err := viper.BindPFlag("language", cmd.Flags().Lookup("language")); err != nil {
417+
printError("failed to bind language flag: %v", err)
418+
}
419+
if err := viper.BindPFlag("author.name", cmd.Flags().Lookup("author")); err != nil {
420+
printError("failed to bind author flag: %v", err)
421+
}
422+
if err := viper.BindPFlag("author.email", cmd.Flags().Lookup("email")); err != nil {
423+
printError("failed to bind email flag: %v", err)
424+
}
419425

420426
return cmd
421427
}

control-plane/internal/cli/list.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -37,7 +38,13 @@ func runListCommand(cmd *cobra.Command, args []string) {
3738
}
3839

3940
if data, err := os.ReadFile(registryPath); err == nil {
40-
yaml.Unmarshal(data, registry)
41+
if err := yaml.Unmarshal(data, registry); err != nil {
42+
cmd.PrintErrf("failed to parse registry: %v\n", err)
43+
return
44+
}
45+
} else if !errors.Is(err, os.ErrNotExist) {
46+
cmd.PrintErrf("failed to read registry: %v\n", err)
47+
return
4148
}
4249

4350
if len(registry.Installed) == 0 {

control-plane/internal/cli/logs.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67
"os/exec" // Added missing import
@@ -70,7 +71,11 @@ func (lv *LogViewer) ViewLogs(agentNodeName string) error {
7071
}
7172

7273
if data, err := os.ReadFile(registryPath); err == nil {
73-
yaml.Unmarshal(data, registry)
74+
if err := yaml.Unmarshal(data, registry); err != nil {
75+
return fmt.Errorf("failed to parse registry: %w", err)
76+
}
77+
} else if !errors.Is(err, os.ErrNotExist) {
78+
return fmt.Errorf("failed to read registry: %w", err)
7479
}
7580

7681
agentNode, exists := registry.Installed[agentNodeName]

control-plane/internal/cli/mcp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ func runMCPRemoveCommand(cmd *cobra.Command, args []string, force bool) error {
538538

539539
if err := manager.Remove(alias); err != nil {
540540
if !force && strings.Contains(err.Error(), "is running") {
541-
PrintError(fmt.Sprintf("MCP server is running. Stop it first or use --force"))
541+
PrintError("MCP server is running. Stop it first or use --force")
542542
return err
543543
}
544544
PrintError(fmt.Sprintf("Failed to remove MCP server: %v", err))

control-plane/internal/cli/vc.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/base64"
66
"encoding/json"
77
"fmt"
8-
"io/ioutil"
98
"net/http"
109
"os"
1110
"strings"
@@ -167,7 +166,7 @@ func verifyVC(vcFilePath string, options VerifyOptions) error {
167166

168167
// Step 1: Read and parse VC file
169168
step1 := VerificationStep{Step: 1, Description: "Reading VC file"}
170-
vcData, err := ioutil.ReadFile(vcFilePath)
169+
vcData, err := os.ReadFile(vcFilePath)
171170
if err != nil {
172171
step1.Success = false
173172
step1.Error = fmt.Sprintf("Failed to read VC file: %v", err)
@@ -500,6 +499,7 @@ func extractPublicKeyFromDIDDoc(didDoc map[string]interface{}) (map[string]inter
500499
return publicKeyJwk, nil
501500
}
502501

502+
//nolint:unused // Reserved for future signature verification
503503
func verifyVCSignature(vcDoc types.VCDocument, resolution DIDResolutionInfo) (bool, error) {
504504
// Create canonical representation for verification
505505
vcCopy := vcDoc
@@ -533,6 +533,7 @@ func verifyVCSignature(vcDoc types.VCDocument, resolution DIDResolutionInfo) (bo
533533
return ed25519.Verify(publicKey, canonicalBytes, signatureBytes), nil
534534
}
535535

536+
//nolint:unused // Reserved for future signature verification
536537
func verifyWorkflowVCSignature(vcDoc types.WorkflowVCDocument, resolution DIDResolutionInfo) (bool, error) {
537538
// Create canonical representation for verification
538539
vcCopy := vcDoc

control-plane/internal/core/services/agent_service.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package services
44
import (
55
"context"
66
"encoding/json"
7+
"errors"
78
"fmt"
89
"net/http"
910
"os"
@@ -103,7 +104,9 @@ func (as *DefaultAgentService) RunAgent(name string, options domain.RunOptions)
103104
// 5. Wait for agent node to be ready
104105
if err := as.waitForAgentNode(port, 10*time.Second); err != nil {
105106
// Kill the process if it failed to start properly
106-
as.processManager.Stop(pid)
107+
if stopErr := as.processManager.Stop(pid); stopErr != nil {
108+
return nil, fmt.Errorf("agent node failed to start: %w (additionally failed to stop process: %v)", err, stopErr)
109+
}
107110
return nil, fmt.Errorf("agent node failed to start: %w", err)
108111
}
109112

@@ -549,7 +552,11 @@ func (as *DefaultAgentService) updateRuntimeInfo(agentNodeName string, port, pid
549552
// Load registry
550553
registry := &packages.InstallationRegistry{}
551554
if data, err := os.ReadFile(registryPath); err == nil {
552-
yaml.Unmarshal(data, registry)
555+
if err := yaml.Unmarshal(data, registry); err != nil {
556+
return fmt.Errorf("failed to parse registry: %w", err)
557+
}
558+
} else if !errors.Is(err, os.ErrNotExist) {
559+
return fmt.Errorf("failed to read registry: %w", err)
553560
}
554561

555562
// Update runtime info

control-plane/internal/core/services/dev_service.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ func (ds *DefaultDevService) runDev(packagePath string, options domain.DevOption
152152
return nil
153153
}
154154

155-
// getFreePort finds an available port in the range 8001-8999
155+
// getFreePort finds an available port in the range 8001-8999.
156+
//
157+
//nolint:unused // retained for future dev-service enhancements
156158
func (ds *DefaultDevService) getFreePort() (int, error) {
157159
for port := 8001; port <= 8999; port++ {
158160
if ds.isPortAvailable(port) {
@@ -162,7 +164,9 @@ func (ds *DefaultDevService) getFreePort() (int, error) {
162164
return 0, fmt.Errorf("no free port available in range 8001-8999")
163165
}
164166

165-
// isPortAvailable checks if a port is available
167+
// isPortAvailable checks if a port is available.
168+
//
169+
//nolint:unused // retained for future dev-service enhancements
166170
func (ds *DefaultDevService) isPortAvailable(port int) bool {
167171
conn, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
168172
if err != nil {
@@ -270,7 +274,9 @@ func (ds *DefaultDevService) discoverAgentPort(timeout time.Duration) (int, erro
270274
return 0, fmt.Errorf("could not discover agent port within %v after %d attempts", timeout, checkCount)
271275
}
272276

273-
// waitForAgent waits for the agent to become ready in dev mode
277+
// waitForAgent waits for the agent to become ready in dev mode.
278+
//
279+
//nolint:unused // retained for future dev-service enhancements
274280
func (ds *DefaultDevService) waitForAgent(port int, timeout time.Duration) error {
275281
client := &http.Client{Timeout: 2 * time.Second}
276282
deadline := time.Now().Add(timeout)

control-plane/internal/core/services/package_service.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,19 @@ type Spinner struct {
307307
}
308308

309309
// Color helper methods
310-
func (ps *DefaultPackageService) green(text string) string { return green(text) }
310+
func (ps *DefaultPackageService) green(text string) string { return green(text) }
311+
312+
//nolint:unused // retained for console color helpers
311313
func (ps *DefaultPackageService) red(text string) string { return red(text) }
312314
func (ps *DefaultPackageService) yellow(text string) string { return yellow(text) }
313315
func (ps *DefaultPackageService) blue(text string) string { return blue(text) }
314316
func (ps *DefaultPackageService) cyan(text string) string { return cyan(text) }
315317
func (ps *DefaultPackageService) gray(text string) string { return gray(text) }
316318
func (ps *DefaultPackageService) bold(text string) string { return bold(text) }
317319
func (ps *DefaultPackageService) statusSuccess() string { return statusSuccess }
318-
func (ps *DefaultPackageService) statusError() string { return statusError }
320+
321+
//nolint:unused // retained for console status helpers
322+
func (ps *DefaultPackageService) statusError() string { return statusError }
319323

320324
// newSpinner creates a new spinner with the given message
321325
func (ps *DefaultPackageService) newSpinner(message string) *Spinner {
@@ -424,7 +428,9 @@ func (ps *DefaultPackageService) isPackageInstalled(packageName string) bool {
424428
}
425429

426430
if data, err := os.ReadFile(registryPath); err == nil {
427-
yaml.Unmarshal(data, registry)
431+
if err := yaml.Unmarshal(data, registry); err != nil {
432+
return false
433+
}
428434
}
429435

430436
_, exists := registry.Installed[packageName]
@@ -508,11 +514,9 @@ func (ps *DefaultPackageService) installDependencies(packagePath string, metadat
508514
pipPath = filepath.Join(venvPath, "Scripts", "pip.exe") // Windows
509515
}
510516

511-
// Upgrade pip first
517+
// Upgrade pip first (ignore failures)
512518
cmd = exec.Command(pipPath, "install", "--upgrade", "pip")
513-
if _, err := cmd.CombinedOutput(); err != nil {
514-
// Ignore pip upgrade failures
515-
}
519+
_, _ = cmd.CombinedOutput()
516520

517521
// Install from requirements.txt if it exists
518522
requirementsPath := filepath.Join(packagePath, "requirements.txt")
@@ -561,7 +565,9 @@ func (ps *DefaultPackageService) updateRegistry(metadata *packages.PackageMetada
561565
}
562566

563567
if data, err := os.ReadFile(registryPath); err == nil {
564-
yaml.Unmarshal(data, registry)
568+
if err := yaml.Unmarshal(data, registry); err != nil {
569+
return fmt.Errorf("failed to parse registry: %w", err)
570+
}
565571
}
566572

567573
// Add/update package entry

0 commit comments

Comments
 (0)