Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions internal/cmd/agents.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func clearCurrentAgentIfMatches(expectedID string) error {
func RequireAgentID() error {
resolvedID := GetCurrentAgentID()
if resolvedID == "" {
return errors.New("agent ID required: use --id flag, set NOTTE_AGENT_ID env var, or start an agent first")
return errors.New("agent ID required: use --agent-id flag, set NOTTE_AGENT_ID env var, or start an agent first")
}
agentID = resolvedID
return nil
Expand Down Expand Up @@ -142,16 +142,16 @@ func init() {
_ = agentsStartCmd.MarkFlagRequired("task")

// Status command flags
agentsStatusCmd.Flags().StringVar(&agentID, "id", "", "Agent ID (uses current agent if not specified)")
agentsStatusCmd.Flags().StringVar(&agentID, "agent-id", "", "Agent ID (uses current agent if not specified)")

// Stop command flags
agentsStopCmd.Flags().StringVar(&agentID, "id", "", "Agent ID (uses current agent if not specified)")
agentsStopCmd.Flags().StringVar(&agentID, "agent-id", "", "Agent ID (uses current agent if not specified)")

// Workflow-code command flags
agentsWorkflowCodeCmd.Flags().StringVar(&agentID, "id", "", "Agent ID (uses current agent if not specified)")
agentsWorkflowCodeCmd.Flags().StringVar(&agentID, "agent-id", "", "Agent ID (uses current agent if not specified)")

// Replay command flags
agentsReplayCmd.Flags().StringVar(&agentID, "id", "", "Agent ID (uses current agent if not specified)")
agentsReplayCmd.Flags().StringVar(&agentID, "agent-id", "", "Agent ID (uses current agent if not specified)")
}

func runAgentsList(cmd *cobra.Command, args []string) error {
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ func init() {
// List command flags
filesListCmd.Flags().BoolVar(&filesListUploadsFlag, "uploads", true, "List uploaded files")
filesListCmd.Flags().BoolVar(&filesListDownloadsFlag, "downloads", false, "List downloaded files from a session")
filesListCmd.Flags().StringVar(&sessionID, "id", "", "Session ID (uses current session if not specified)")
filesListCmd.Flags().StringVar(&sessionID, "session-id", "", "Session ID (uses current session if not specified)")

// Download command flags
filesDownloadCmd.Flags().StringVar(&sessionID, "id", "", "Session ID (uses current session if not specified)")
filesDownloadCmd.Flags().StringVar(&sessionID, "session-id", "", "Session ID (uses current session if not specified)")
filesDownloadCmd.Flags().StringVarP(&filesDownloadOutput, "output", "o", "", "Output file path (defaults to current directory)")
}

Expand Down
108 changes: 108 additions & 0 deletions internal/cmd/flags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cmd

import (
"testing"

"github.com/spf13/pflag"
)

// TestNoGenericIDFlags ensures no command uses a generic "--id" flag.
// All ID flags should be resource-specific (e.g., --session-id, --function-id).
func TestNoGenericIDFlags(t *testing.T) {
var violations []string

// Recursive function to check all commands
checkCommand := func(path string, flags *pflag.FlagSet, flagType string) {
flags.VisitAll(func(f *pflag.Flag) {
if f.Name == "id" {
violations = append(violations, path+" has "+flagType+" --id flag (should be resource-specific)")
}
})
}

// Check pageCmd and subcommands
checkCommand("notte page", pageCmd.PersistentFlags(), "persistent")
checkCommand("notte page", pageCmd.Flags(), "local")
for _, sub := range pageCmd.Commands() {
cmdPath := "notte page " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check filesCmd and subcommands
checkCommand("notte files", filesCmd.PersistentFlags(), "persistent")
checkCommand("notte files", filesCmd.Flags(), "local")
for _, sub := range filesCmd.Commands() {
cmdPath := "notte files " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check functionsCmd and subcommands
checkCommand("notte functions", functionsCmd.PersistentFlags(), "persistent")
checkCommand("notte functions", functionsCmd.Flags(), "local")
for _, sub := range functionsCmd.Commands() {
cmdPath := "notte functions " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check vaultsCmd and subcommands
checkCommand("notte vaults", vaultsCmd.PersistentFlags(), "persistent")
checkCommand("notte vaults", vaultsCmd.Flags(), "local")
for _, sub := range vaultsCmd.Commands() {
cmdPath := "notte vaults " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
// Check nested subcommands (e.g., vaults credentials)
for _, nested := range sub.Commands() {
nestedPath := cmdPath + " " + nested.Name()
checkCommand(nestedPath, nested.Flags(), "local")
checkCommand(nestedPath, nested.PersistentFlags(), "persistent")
}
}

// Check profilesCmd and subcommands
checkCommand("notte profiles", profilesCmd.PersistentFlags(), "persistent")
checkCommand("notte profiles", profilesCmd.Flags(), "local")
for _, sub := range profilesCmd.Commands() {
cmdPath := "notte profiles " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check personasCmd and subcommands
checkCommand("notte personas", personasCmd.PersistentFlags(), "persistent")
checkCommand("notte personas", personasCmd.Flags(), "local")
for _, sub := range personasCmd.Commands() {
cmdPath := "notte personas " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check agentsCmd and subcommands
checkCommand("notte agents", agentsCmd.PersistentFlags(), "persistent")
checkCommand("notte agents", agentsCmd.Flags(), "local")
for _, sub := range agentsCmd.Commands() {
cmdPath := "notte agents " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

// Check sessionsCmd and subcommands
checkCommand("notte sessions", sessionsCmd.PersistentFlags(), "persistent")
checkCommand("notte sessions", sessionsCmd.Flags(), "local")
for _, sub := range sessionsCmd.Commands() {
cmdPath := "notte sessions " + sub.Name()
checkCommand(cmdPath, sub.Flags(), "local")
checkCommand(cmdPath, sub.PersistentFlags(), "persistent")
}

if len(violations) > 0 {
t.Errorf("Found %d command(s) with generic --id flag:\n", len(violations))
for _, v := range violations {
t.Errorf(" - %s", v)
}
t.Error("All ID flags should be resource-specific (e.g., --session-id, --function-id, --vault-id)")
}
}
32 changes: 16 additions & 16 deletions internal/cmd/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var (

// GetCurrentFunctionID returns the function ID from flag, env var, or file (in priority order)
func GetCurrentFunctionID() string {
// 1. Check --id flag (already in functionID variable if set)
// 1. Check --function-id flag (already in functionID variable if set)
if functionID != "" {
return functionID
}
Expand Down Expand Up @@ -89,7 +89,7 @@ func clearCurrentFunction() error {
func RequireFunctionID() error {
functionID = GetCurrentFunctionID()
if functionID == "" {
return errors.New("function ID required: use --id flag, set NOTTE_FUNCTION_ID env var, or create a function first")
return errors.New("function ID required: use --function-id flag, set NOTTE_FUNCTION_ID env var, or create a function first")
}
return nil
}
Expand Down Expand Up @@ -173,13 +173,13 @@ var functionsRunMetadataUpdateCmd = &cobra.Command{
Short: "Update function run metadata",
Args: cobra.NoArgs,
Example: ` # Direct JSON
notte functions run-metadata-update --id <function-id> --run-id <run-id> --data '{"key": "value"}'
notte functions run-metadata-update --function-id <function-id> --run-id <run-id> --data '{"key": "value"}'

# From file
notte functions run-metadata-update --id <function-id> --run-id <run-id> --data @metadata.json
notte functions run-metadata-update --function-id <function-id> --run-id <run-id> --data @metadata.json

# From stdin
echo '{"key": "value"}' | notte functions run-metadata-update --id <function-id> --run-id <run-id>`,
echo '{"key": "value"}' | notte functions run-metadata-update --function-id <function-id> --run-id <run-id>`,
RunE: runFunctionRunMetadataUpdate,
Hidden: true,
}
Expand Down Expand Up @@ -222,50 +222,50 @@ func init() {
functionsCreateCmd.Flags().BoolVar(&functionsCreateShared, "shared", false, "Make function public")

// Show command flags
functionsShowCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsShowCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")

// Update command flags
functionsUpdateCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsUpdateCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsUpdateCmd.Flags().StringVar(&functionUpdateFile, "file", "", "Path to updated function file (required)")
_ = functionsUpdateCmd.MarkFlagRequired("file")

// Delete command flags
functionsDeleteCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsDeleteCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")

// Run command flags
functionsRunCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsRunCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsRunCmd.Flags().StringArrayVar(&functionRunVariables, "var", []string{}, "Variable as key=value pair (can be used multiple times)")
functionsRunCmd.Flags().StringVar(&functionRunVariablesJSON, "vars", "", "Variables as JSON object string")

// Runs command flags
functionsRunsCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsRunsCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")

// Fork command flags
functionsForkCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsForkCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")

// Run-stop command flags
functionsRunStopCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsRunStopCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsRunStopCmd.Flags().StringVar(&functionRunID, "run-id", "", "Run ID (required)")
_ = functionsRunStopCmd.MarkFlagRequired("run-id")

// Run-metadata command flags
functionsRunMetadataCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsRunMetadataCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsRunMetadataCmd.Flags().StringVar(&functionRunID, "run-id", "", "Run ID (required)")
_ = functionsRunMetadataCmd.MarkFlagRequired("run-id")

// Run-metadata-update command flags
functionsRunMetadataUpdateCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsRunMetadataUpdateCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsRunMetadataUpdateCmd.Flags().StringVar(&functionRunID, "run-id", "", "Run ID (required)")
_ = functionsRunMetadataUpdateCmd.MarkFlagRequired("run-id")
functionsRunMetadataUpdateCmd.Flags().StringVar(&functionMetadataJSON, "data", "", "JSON metadata, @file, or '-' for stdin")

// Schedule command flags
functionsScheduleCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsScheduleCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
functionsScheduleCmd.Flags().StringVar(&functionCronExpression, "cron", "", "Cron expression (required)")
_ = functionsScheduleCmd.MarkFlagRequired("cron")

// Unschedule command flags
functionsUnscheduleCmd.Flags().StringVar(&functionID, "id", "", "Function ID (uses current function if not specified)")
functionsUnscheduleCmd.Flags().StringVar(&functionID, "function-id", "", "Function ID (uses current function if not specified)")
}

func runFunctionsList(cmd *cobra.Command, args []string) error {
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -768,8 +768,8 @@ func init() {
pageCmd.AddCommand(pageScreenshotCmd)
pageCmd.AddCommand(pageEvalJsCmd)

// Add --id flag to parent command (inherited by all subcommands)
pageCmd.PersistentFlags().StringVar(&sessionID, "id", "", "Session ID (uses current session if not specified)")
// Add --session-id flag to parent command (inherited by all subcommands)
pageCmd.PersistentFlags().StringVar(&sessionID, "session-id", "", "Session ID (uses current session if not specified)")

// click flags
pageClickCmd.Flags().IntVar(&pageClickTimeout, "timeout", 0, "Timeout in milliseconds")
Expand Down
16 changes: 8 additions & 8 deletions internal/cmd/personas.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,20 @@ func init() {
RegisterPersonaCreateFlags(personasCreateCmd)

// Show command flags
personasShowCmd.Flags().StringVar(&personaID, "id", "", "Persona ID (required)")
_ = personasShowCmd.MarkFlagRequired("id")
personasShowCmd.Flags().StringVar(&personaID, "persona-id", "", "Persona ID (required)")
_ = personasShowCmd.MarkFlagRequired("persona-id")

// Delete command flags
personasDeleteCmd.Flags().StringVar(&personaID, "id", "", "Persona ID (required)")
_ = personasDeleteCmd.MarkFlagRequired("id")
personasDeleteCmd.Flags().StringVar(&personaID, "persona-id", "", "Persona ID (required)")
_ = personasDeleteCmd.MarkFlagRequired("persona-id")

// Emails command flags
personasEmailsCmd.Flags().StringVar(&personaID, "id", "", "Persona ID (required)")
_ = personasEmailsCmd.MarkFlagRequired("id")
personasEmailsCmd.Flags().StringVar(&personaID, "persona-id", "", "Persona ID (required)")
_ = personasEmailsCmd.MarkFlagRequired("persona-id")

// SMS command flags
personasSmsCmd.Flags().StringVar(&personaID, "id", "", "Persona ID (required)")
_ = personasSmsCmd.MarkFlagRequired("id")
personasSmsCmd.Flags().StringVar(&personaID, "persona-id", "", "Persona ID (required)")
_ = personasSmsCmd.MarkFlagRequired("persona-id")
}

func runPersonasList(cmd *cobra.Command, args []string) error {
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ func init() {
RegisterProfileCreateFlags(profilesCreateCmd)

// Show command flags
profilesShowCmd.Flags().StringVar(&profileID, "id", "", "Profile ID (required)")
_ = profilesShowCmd.MarkFlagRequired("id")
profilesShowCmd.Flags().StringVar(&profileID, "profile-id", "", "Profile ID (required)")
_ = profilesShowCmd.MarkFlagRequired("profile-id")

// Delete command flags
profilesDeleteCmd.Flags().StringVar(&profileID, "id", "", "Profile ID (required)")
_ = profilesDeleteCmd.MarkFlagRequired("id")
profilesDeleteCmd.Flags().StringVar(&profileID, "profile-id", "", "Profile ID (required)")
_ = profilesDeleteCmd.MarkFlagRequired("profile-id")
}

func runProfilesList(cmd *cobra.Command, args []string) error {
Expand Down
14 changes: 7 additions & 7 deletions internal/cmd/vaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,19 @@ func init() {
// Create command flags (auto-generated)
RegisterVaultCreateFlags(vaultsCreateCmd)

// Credentials subcommand group - use PersistentFlags for --id
vaultsCredentialsCmd.PersistentFlags().StringVar(&vaultID, "id", "", "Vault ID (required)")
_ = vaultsCredentialsCmd.MarkPersistentFlagRequired("id")
// Credentials subcommand group - use PersistentFlags for --vault-id
vaultsCredentialsCmd.PersistentFlags().StringVar(&vaultID, "vault-id", "", "Vault ID (required)")
_ = vaultsCredentialsCmd.MarkPersistentFlagRequired("vault-id")

// Update command flags
vaultsUpdateCmd.Flags().StringVar(&vaultID, "id", "", "Vault ID (required)")
_ = vaultsUpdateCmd.MarkFlagRequired("id")
vaultsUpdateCmd.Flags().StringVar(&vaultID, "vault-id", "", "Vault ID (required)")
_ = vaultsUpdateCmd.MarkFlagRequired("vault-id")
vaultsUpdateCmd.Flags().StringVar(&vaultUpdateName, "name", "", "New name for the vault (required)")
_ = vaultsUpdateCmd.MarkFlagRequired("name")

// Delete command flags
vaultsDeleteCmd.Flags().StringVar(&vaultID, "id", "", "Vault ID (required)")
_ = vaultsDeleteCmd.MarkFlagRequired("id")
vaultsDeleteCmd.Flags().StringVar(&vaultID, "vault-id", "", "Vault ID (required)")
_ = vaultsDeleteCmd.MarkFlagRequired("vault-id")

// Credentials add command flags (auto-generated)
RegisterVaultCredentialsAddFlags(vaultsCredentialsAddCmd)
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/agents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@ func TestAgentsStartWithSession(t *testing.T) {
// cleanupSession will stop the session which implicitly stops the agent

// Get agent status
result = runCLI(t, "agents", "status", "--id", agentID)
result = runCLI(t, "agents", "status", "--agent-id", agentID)
requireSuccess(t, result)
t.Log("Agent on session test completed")
}

func TestAgentsStatusNonexistent(t *testing.T) {
// Try to get status of a non-existent agent
result := runCLI(t, "agents", "status", "--id", "nonexistent-agent-id-12345")
result := runCLI(t, "agents", "status", "--agent-id", "nonexistent-agent-id-12345")
requireFailure(t, result)
t.Log("Correctly failed to get status of non-existent agent")
}

func TestAgentsStopNonexistent(t *testing.T) {
// Try to stop a non-existent agent
result := runCLI(t, "agents", "stop", "--id", "nonexistent-agent-id-12345")
result := runCLI(t, "agents", "stop", "--agent-id", "nonexistent-agent-id-12345")
requireFailure(t, result)
t.Log("Correctly failed to stop non-existent agent")
}
8 changes: 4 additions & 4 deletions tests/integration/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestErrorParsing_NonexistentSession(t *testing.T) {
// TestErrorParsing_NonexistentVault tests that vault not found errors show proper messages
func TestErrorParsing_NonexistentVault(t *testing.T) {
// Try to get credentials from a non-existent vault
result := runCLI(t, "vaults", "credentials", "list", "--id", "nonexistent-vault-id-abc123")
result := runCLI(t, "vaults", "credentials", "list", "--vault-id", "nonexistent-vault-id-abc123")
requireFailure(t, result)

// Verify we get a proper error (not "failed to read response body")
Expand All @@ -63,7 +63,7 @@ func TestErrorParsing_NonexistentVault(t *testing.T) {
// TestErrorParsing_NonexistentPersona tests that persona not found errors show proper messages
func TestErrorParsing_NonexistentPersona(t *testing.T) {
// Try to get a non-existent persona
result := runCLI(t, "personas", "show", "--id", "nonexistent-persona-id-def456")
result := runCLI(t, "personas", "show", "--persona-id", "nonexistent-persona-id-def456")
requireFailure(t, result)

// Verify we get a proper error (not "failed to read response body")
Expand All @@ -77,7 +77,7 @@ func TestErrorParsing_NonexistentPersona(t *testing.T) {
// TestErrorParsing_NonexistentProfile tests that profile not found errors show proper messages
func TestErrorParsing_NonexistentProfile(t *testing.T) {
// Try to get a non-existent profile
result := runCLI(t, "profiles", "show", "--id", "nonexistent-profile-id-ghi789")
result := runCLI(t, "profiles", "show", "--profile-id", "nonexistent-profile-id-ghi789")
requireFailure(t, result)

// Verify we get a proper error (not "failed to read response body")
Expand All @@ -91,7 +91,7 @@ func TestErrorParsing_NonexistentProfile(t *testing.T) {
// TestErrorParsing_NonexistentAgent tests that agent not found errors show proper messages
func TestErrorParsing_NonexistentAgent(t *testing.T) {
// Try to get status of a non-existent agent
result := runCLI(t, "agents", "status", "--id", "nonexistent-agent-id-jkl012")
result := runCLI(t, "agents", "status", "--agent-id", "nonexistent-agent-id-jkl012")
requireFailure(t, result)

// Verify we get a proper error (not "failed to read response body")
Expand Down
Loading