fix: [PRO-470] add --path option and auto-stop to deploy commands#115
Conversation
Fixed two deployment issues: 1. Added --path option to both 'xpander deploy' and 'xpander agent deploy' to allow specifying agent directory (defaults to current directory) 2. Added automatic stop of existing deployment before deploying new version to prevent conflicts with running agents Changes: - Updated deploy.ts to add --path option - Updated agent/index.ts to add --path option for agent deploy - Modified deployAgent() to accept workingDirectory parameter - Added automatic stopDeployment() call before building/deploying - Gracefully handles cases where no deployment is running Both 'xpander deploy' and 'xpander agent deploy' now work consistently with same options and behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
| deploymentSpinner.info( | ||
| `No existing deployment to stop, proceeding with deployment...`, | ||
| ); | ||
| } |
There was a problem hiding this comment.
Bug: Spinner not restarted after stop failure in catch block
When stopDeployment fails and the code enters the catch block, deploymentSpinner.info() is called which stops the spinner animation. However, unlike the success path (which calls deploymentSpinner.start() on line 83), the error path doesn't restart the spinner. This means subsequent operations like buildAndSaveDockerImage will update spinner.text on a stopped spinner, resulting in no visual progress indication during the Docker build and deployment process.
| deploymentSpinner.info( | ||
| `No existing deployment to stop, proceeding with deployment...`, | ||
| ); | ||
| } |
There was a problem hiding this comment.
Bug: Spinner not restarted after stop failure in catch block
When stopDeployment fails and the code enters the catch block, deploymentSpinner.info() is called which stops the spinner animation. However, unlike the success path (which calls deploymentSpinner.start() on line 83), the error path doesn't restart the spinner. This means subsequent operations like buildAndSaveDockerImage will update spinner.text on a stopped spinner, resulting in no visual progress indication during the Docker build and deployment process.
There was a problem hiding this comment.
Bug: Path option not used when resolving agent ID
When --path is provided without an explicit agent ID, getAgentIdFromEnvOrSelection looks for the .env file in process.cwd() instead of the specified options.path directory. This means running xpander deploy --path /path/to/agent will fail to find the agent ID from the target directory's .env file. The options.path value needs to be passed to getAgentIdFromEnvOrSelection so it can read the .env from the correct directory.
src/commands/deploy.ts#L24-L28
xpander-cli/src/commands/deploy.ts
Lines 24 to 28 in ac26e43
src/commands/agent/index.ts#L79-L83
xpander-cli/src/commands/agent/index.ts
Lines 79 to 83 in ac26e43
When deploying an agent, the CLI now prioritizes credentials from the agent's .env file over the configured profile credentials. This allows deploying agents that belong to different organizations without switching profiles. Changes: - Modified deployAgent() to read credentials from .env file - Creates new XpanderClient with .env credentials if available - Falls back to profile credentials if .env doesn't have them - Shows info message when using .env credentials Behavior: - If .env contains XPANDER_API_KEY and XPANDER_ORGANIZATION_ID, uses them - Otherwise, uses credentials from --profile or default profile - Applies to both 'xpander deploy' and 'xpander agent deploy' commands 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Fixed deployment flow to properly use .env file configuration: - Agent ID now always comes from .env file (not command line) - Removed agent selection prompt when deploying from agent directory - Moved deployment confirmation after .env is read - Simplified command handlers to pass agent ID directly This ensures that when deploying with --path, the CLI uses the complete configuration from the agent's .env file including credentials and agent ID. Test results: - CLI correctly shows "Using credentials from .env file" - Agent ID from .env is used (not from command line or selection) - Deployment flow is streamlined without redundant prompts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
When deploying and no XPANDER_AGENT_ID is found in .env file, the CLI now prompts the user to select an existing agent or create a new one. Changes: - Modified deployAgent() to gracefully handle missing XPANDER_AGENT_ID - Still reads credentials from .env if available - Falls back to agent selection prompt if no agent ID found - Uses getAgentIdFromEnvOrSelection() with correct client credentials Behavior: - If .env has agent ID: uses it directly - If .env missing agent ID: prompts user to select/create agent - Credentials from .env are still respected during selection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
…eployment When deploying with credentials from .env file, if the agent doesn't exist in that organization, the CLI now offers to create it automatically. Changes: - Modified deployAgent() to check if agent exists - Prompts user to create agent if not found (unless --confirm flag) - Creates agent with container deployment type - Uses agent ID from .env as the agent name - Continues with deployment after agent creation Behavior: - If agent exists: deploys normally - If agent doesn't exist: prompts to create, then deploys - In non-interactive mode: skips confirmation prompts This completes the deployment workflow for new agents using .env credentials. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
The --confirm flag now properly skips the agent creation confirmation prompt, allowing fully automated deployment when agent doesn't exist. Changes: - Agent creation prompt respects skipDeploymentConfirmation flag - Shows message: "Agent does not exist, creating automatically..." - Works in both --confirm and non-interactive modes Test results: - Agent successfully auto-created with --confirm flag - Used credentials from .env file - No user interaction required for full deployment flow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
When --profile is explicitly specified, the CLI now uses profile credentials instead of .env credentials. This gives users control over which credentials to use for deployment. Changes: - Added useProfileCredentials parameter to deployAgent() - Profile credentials take precedence when --profile flag is set - Shows message: "Using credentials from profile (--profile flag set)" - Otherwise uses .env credentials if available Credential Priority (updated): 1. --profile flag credentials (if --profile specified) 2. .env file credentials (if no --profile flag) 3. Default profile credentials (fallback) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
…esolution Fixed three bugs identified by Cursor Bugbot code review: 1. Spinner not restarted after stop failure - Added deploymentSpinner.start() in catch block after info message - Ensures visual progress indication continues after stop failures 2. Command-line agent ID precedence - Changed from config.agent_id || _agentId to _agentId || config.agent_id - Command-line arguments now properly override .env configuration 3. Agent name resolution - Added resolveAgentId() call for command-line agent arguments - Users can now deploy by agent name: xpander deploy my-agent-name - Maintains backward compatibility with agent name lookups All three bugs fixed and tested. Build passes with all tests green. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
| // Command-line argument provided - resolve name to ID | ||
| const { resolveAgentId } = await import('../../../utils/agent-resolver'); | ||
| const resolved = await resolveAgentId(deployClient, _agentId, true); | ||
| agentId = resolved || undefined; |
There was a problem hiding this comment.
Bug: Missing early return when agent resolution fails
When _agentId is provided but resolveAgentId cannot find a matching agent, it returns null. The code sets agentId = resolved || undefined but doesn't return early. This causes the deployment to continue with agentId being undefined, resulting in getAgent(undefined) returning null, and then createAgent(undefined, 'container') being called, which creates an agent with the name "undefined". The original code always returned early if resolution failed (if (!resolvedAgentId) return), but this check was removed.
## Summary - Fixed profile credential precedence with --profile flag - Fixed agent naming to use directory name instead of UUID - Fixed .env file auto-creation and updates during deployment - Fixed race condition in agent creation workflow - Added --path option to stop, restart, and dev commands - Fixed non-interactive mode for agent delete command ## Changes ### Profile Credential Handling - Modified deploy command to detect explicit --profile flag using rawArgs - When --profile is explicitly set, CLI credentials take precedence over .env - Fixes issue where Commander.js returns undefined for default values ### Agent Creation and Naming - Agents now created with directory name instead of agent ID - Fixed agentId variable update after agent creation to prevent race condition - Ensures subsequent operations (stop, build, deploy) use correct new agent ID ### .env File Management - Auto-creates .env file with CLI credentials if it doesn't exist - Updates .env file with new agent ID after agent creation - Supports deployment workflow without pre-existing .env file ### Non-Interactive Mode Support - Agent delete now respects XPANDER_NON_INTERACTIVE environment variable - Allows automated deletion without confirmation prompts - Maintains security with --confirm flag requirement ### --path Option Support - Added --path option to stop, restart, and dev commands - Allows operating on agents from any directory - Implements proper working directory switching with restoration ### Race Condition Fix - Fixed critical bug where old agentId was used after creating new agent - Added `agentId = agent.id` after agent creation - Prevents conflicts and "agent is currently running" errors ## Files Modified - src/commands/deploy.ts - src/commands/agent/interactive/deploy.ts - src/commands/agent/commands/delete.ts - src/commands/agent/index.ts - src/commands/stop.ts - src/commands/restart.ts - src/commands/dev.ts - src/commands/agent/interactive/dev.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
| // Restore original working directory | ||
| if (workingDirectory) { | ||
| process.chdir(originalCwd); | ||
| } |
There was a problem hiding this comment.
Bug: Working directory not restored on exception
If getAgentIdFromEnvOrSelection throws an error after process.chdir(workingDirectory) is called, the original working directory is never restored because the restoration code on lines 31-33 won't execute. The outer try-catch handles the error but doesn't restore the directory, leaving the process in the wrong working directory for any subsequent operations. A try-finally pattern around the chdir/restore logic would ensure cleanup.
Additional Locations (1)
… support - Added optional workingDirectory parameter to getAgentIdFromEnvOrSelection - Now uses workingDirectory when reading .env file instead of process.cwd() - Fixed deploy command to pass currentDirectory when resolving agent ID - Resolves Cursor bug where --path option wasn't being used for agent resolution
Summary
This PR includes comprehensive improvements to the deployment workflow and command handling, fixing multiple critical issues with profile credentials, agent creation, non-interactive mode, and command options.
Key Fixes
1. Profile Credential Precedence
Problem: Even with
--profileflag, CLI was using .env credentials instead of profile credentialsRoot Cause: Commander.js returns
undefinedwhen an option's value matches its defaultSolution: Detect explicit
--profileflag usingcommand.parent?.rawArgs.includes('--profile')2. Agent Naming
Problem: Agents were created with UUID as name instead of directory name
Solution: Use
path.basename(currentDirectory)for agent name during creation3. .env File Management
Problem: Deployment failed when .env didn't exist; .env not updated after agent creation
Solution:
4. Race Condition in Agent Creation (Critical Fix)
Problem: After creating new agent, old
agentIdvariable was used for stop/build/deploy operationsSymptom: "This agent is currently running in production" error
Solution: Added
agentId = agent.idafter agent creation5. --path Option Support
Problem: Only deploy command had
--pathoption; stop/restart/dev commands required being in agent directorySolution: Added
--pathoption to all agent management commands with proper working directory handling6. Non-Interactive Mode for Delete
Problem: Agent delete asked for confirmation even with
XPANDER_NON_INTERACTIVE=trueSolution: Check both
--confirmflag andXPANDER_NON_INTERACTIVEenvironment variableFiles Modified
Test plan
Breaking Changes
None - all changes are backwards compatible
🤖 Generated with Claude Code
Note
Enhances agent deploy/dev/stop/restart commands with --path support, proper credential precedence, non-interactive handling, .env management, and pre-deploy auto-stop with robust agent ID resolution.
agent deploy, rootdeploy,agent dev,agent stop,agent restartnow accept--pathto target a specific directory; plumbed through to handlers.--profilevia raw args to ensure profile credentials are honored over.envwhen specified.src/commands/agent/interactive/deploy.ts):.envwith CLI credentials if missing; updateXPANDER_AGENT_IDafter agent creation..envcredentials unless--profileexplicitly set; resolve agent from arg/.env/selection or directory name (non-interactive).agentIdto the newly created agent's ID.stopDeployment.src/commands/agent/interactive/dev.ts):--pathby temporarilychdirto resolve agent from.env, then restore CWD.--confirmandXPANDER_NON_INTERACTIVEto skip confirmation; show notice when skipping.getAgentIdFromEnvOrSelectionacceptsworkingDirectoryfor.envlookup; improved resolution flow.Written by Cursor Bugbot for commit ccfded4. This will update automatically on new commits. Configure here.