Files
gh-ce-dot-net-ce-claude-mar…/commands/ace-configure.md
2025-11-29 18:08:19 +08:00

15 KiB
Raw Blame History

description: Configure ACE server connection settings interactively argument-hint: [--global] [--project]

Configure ACE Connection

Interactive configuration wizard using ce-ace CLI v1.0.2+ features with Claude Code native UI.

What This Does

Two-step configuration:

  1. Global Config: Uses ce-ace config validate + ce-ace config with flags
  2. Project Config: Creates .claude/settings.json with orgId and projectId

Instructions for Claude

When the user runs /ace:configure, follow these steps:

Step 1: Check ce-ace CLI Version and Dependencies

#!/usr/bin/env bash
set -euo pipefail

# Check for jq (required for JSON parsing)
if ! command -v jq >/dev/null 2>&1; then
  echo "❌ jq not found (required for JSON parsing)"
  echo ""
  echo "Installation instructions:"
  echo "  macOS:   brew install jq"
  echo "  Linux:   apt-get install jq  or  yum install jq"
  echo "  Windows: Download from https://stedolan.github.io/jq/download/"
  echo ""
  exit 1
fi

# Check for ce-ace CLI
if ! command -v ce-ace >/dev/null 2>&1; then
  echo "❌ ce-ace CLI not found"
  echo ""
  echo "Installation required:"
  echo "  npm install -g @ace-sdk/cli"
  echo ""
  exit 1
fi

VERSION=$(ce-ace --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
echo "✅ ce-ace CLI found (version: $VERSION)"

# Check version >= 1.0.2
REQUIRED_VERSION="1.0.2"
if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$VERSION" | sort -V | head -n1)" != "$REQUIRED_VERSION" ]; then
  echo "⚠️  ce-ace v$VERSION found, but v1.0.2+ required for non-interactive config"
  echo ""
  echo "Please upgrade:"
  echo "  npm install -g @ace-sdk/cli@latest"
  echo ""
  exit 1
fi

echo ""

Step 2: Detect Scope

# Parse arguments
SCOPE="both"
if [ "${1:-}" == "--global" ]; then
  SCOPE="global"
elif [ "${1:-}" == "--project" ]; then
  SCOPE="project"
else
  # Auto-detect: If in a git repo, do both; otherwise just global
  if git rev-parse --show-toplevel 2>/dev/null; then
    SCOPE="both"
  else
    SCOPE="global"
  fi
fi

echo "📋 Configuration scope: $SCOPE"
echo ""

Step 3: Global Configuration (if needed)

If SCOPE is "global" or "both", use AskUserQuestion to gather inputs, then configure:

  1. Ask for Server URL: Use AskUserQuestion tool:

    {
      questions: [
        {
          question: "ACE Server URL?",
          header: "Server URL",
          multiSelect: false,
          options: [
            {
              label: "Production (ace-api.code-engine.app)",
              description: "Official ACE production server (recommended)"
            },
            {
              label: "Localhost (localhost:9000)",
              description: "Local development server"
            }
          ]
        }
      ]
    }
    

    Map user selection to URL:

    • "Production" → https://ace-api.code-engine.app
    • "Localhost" → http://localhost:9000
    • "Other" → Prompt for custom URL
  2. Ask for API Token: Use AskUserQuestion tool:

    {
      questions: [
        {
          question: "Enter your ACE API token (starts with 'ace_')?",
          header: "API Token",
          multiSelect: false,
          options: [
            {
              label: "I have a token",
              description: "Enter token in the next step"
            },
            {
              label: "I need to get a token",
              description: "Visit https://ace.code-engine.app/settings/tokens"
            }
          ]
        }
      ]
    }
    

    If user selects "I have a token", they'll provide it in the "Other" field. If "I need to get a token", show them the URL and exit.

  3. Validate Token and Get Org/Project Info:

    echo "🔍 Validating token with ACE server..."
    echo "   Server: $SERVER_URL"
    echo ""
    
    # Use subshell to avoid polluting parent environment
    # Workaround: ce-ace config validate doesn't accept --server-url flag properly
    # Use environment variables instead
    VALIDATION_OUTPUT=$(
      ACE_SERVER_URL="$SERVER_URL" \
      ACE_API_TOKEN="$API_TOKEN" \
      ce-ace config validate --json 2>&1
    )
    VALIDATION_EXIT_CODE=$?
    
    if [ $VALIDATION_EXIT_CODE -ne 0 ]; then
      echo "❌ Token validation failed"
      echo ""
      echo "Error details:"
      echo "$VALIDATION_OUTPUT"
      echo ""
      echo "Common issues:"
      echo "  - Invalid or expired token"
      echo "  - Network connectivity problems"
      echo "  - Server URL incorrect"
      echo ""
      echo "Please verify your token at: https://ace.code-engine.app/settings"
      exit 1
    fi
    
    # Verify we got valid JSON back
    if ! echo "$VALIDATION_OUTPUT" | jq empty 2>/dev/null; then
      echo "❌ Invalid response from ACE server (not valid JSON)"
      echo ""
      echo "Response:"
      echo "$VALIDATION_OUTPUT"
      exit 1
    fi
    
    # Parse validation response
    ORG_ID=$(echo "$VALIDATION_OUTPUT" | jq -r '.org_id // empty')
    ORG_NAME=$(echo "$VALIDATION_OUTPUT" | jq -r '.org_name // empty')
    PROJECTS_JSON=$(echo "$VALIDATION_OUTPUT" | jq -c '.projects // []')
    
    # Verify required fields
    if [ -z "$ORG_ID" ] || [ -z "$ORG_NAME" ]; then
      echo "❌ Validation response missing required fields (org_id, org_name)"
      echo ""
      echo "Response:"
      echo "$VALIDATION_OUTPUT"
      exit 1
    fi
    
    # Check if user has any projects
    PROJECT_COUNT=$(echo "$PROJECTS_JSON" | jq 'length')
    if [ "$PROJECT_COUNT" -eq 0 ]; then
      echo "⚠️  No projects found for organization: $ORG_NAME"
      echo ""
      echo "Please create a project first at: https://ace.code-engine.app/projects"
      exit 1
    fi
    
    echo "✅ Validated! Organization: $ORG_NAME ($ORG_ID)"
    echo "   Projects available: $PROJECT_COUNT"
    echo ""
    
  4. Ask User to Select Project (use AskUserQuestion):

    // Parse projects from PROJECTS_JSON
    // Build options dynamically from project list
    {
      questions: [
        {
          question: "Which project should be configured?",
          header: "Project",
          multiSelect: false,
          options: [
            // For each project in PROJECTS_JSON:
            {
              label: "project.project_name",
              description: "project.project_id"
            }
            // ... more projects
          ]
        }
      ]
    }
    

    Extract project_id from user selection.

  5. Configure with ce-ace CLI:

    echo "💾 Saving global configuration..."
    
    # Determine config location (respect XDG_CONFIG_HOME)
    GLOBAL_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/ace/config.json"
    GLOBAL_CONFIG_DIR=$(dirname "$GLOBAL_CONFIG")
    
    # Ensure config directory exists
    if [ ! -d "$GLOBAL_CONFIG_DIR" ]; then
      echo "📁 Creating config directory: $GLOBAL_CONFIG_DIR"
      mkdir -p "$GLOBAL_CONFIG_DIR"
      if [ $? -ne 0 ]; then
        echo "❌ Failed to create config directory: $GLOBAL_CONFIG_DIR"
        exit 1
      fi
    fi
    
    # Save configuration
    ce-ace config \
      --server-url "$SERVER_URL" \
      --api-token "$API_TOKEN" \
      --project-id "$PROJECT_ID" \
      --json
    
    if [ $? -ne 0 ]; then
      echo "❌ Failed to save global configuration (ce-ace config command failed)"
      exit 1
    fi
    
    # Verify config file was created
    if [ ! -f "$GLOBAL_CONFIG" ]; then
      echo "❌ Global config was not created at expected location"
      echo "   Expected: $GLOBAL_CONFIG"
      echo "   Please check ce-ace CLI logs for details"
      exit 1
    fi
    
    # Verify config is valid JSON
    if ! jq empty "$GLOBAL_CONFIG" 2>/dev/null; then
      echo "❌ Global config is not valid JSON"
      echo "   Location: $GLOBAL_CONFIG"
      echo "   Please check file contents"
      exit 1
    fi
    
    # Verify required fields are present
    if ! jq -e '.serverUrl and .apiToken' "$GLOBAL_CONFIG" >/dev/null 2>&1; then
      echo "❌ Global config is missing required fields (serverUrl, apiToken)"
      echo "   Location: $GLOBAL_CONFIG"
      exit 1
    fi
    
    echo "✅ Global configuration saved and verified:"
    echo "   Location: $GLOBAL_CONFIG"
    echo "   Server: $SERVER_URL"
    echo "   Project: $PROJECT_ID"
    echo ""
    

Step 4: Project Configuration (if needed)

If SCOPE is "project" or "both":

  1. Get Project Root:

    PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
    PROJECT_CONFIG="$PROJECT_ROOT/.claude/settings.json"
    
    echo "📂 Project root: $PROJECT_ROOT"
    echo ""
    
  2. Check Existing Config:

    if [ -f "$PROJECT_CONFIG" ]; then
      EXISTING_ORG=$(jq -r '.env.ACE_ORG_ID // empty' "$PROJECT_CONFIG" 2>/dev/null || echo "")
      EXISTING_PROJECT=$(jq -r '.env.ACE_PROJECT_ID // empty' "$PROJECT_CONFIG" 2>/dev/null || echo "")
    
      if [ -n "$EXISTING_ORG" ] && [ -n "$EXISTING_PROJECT" ]; then
        echo "  Found existing project configuration:"
        echo "  Organization ID: $EXISTING_ORG"
        echo "  Project ID: $EXISTING_PROJECT"
        echo ""
        # Ask user what they want to do - STOP HERE AND PROMPT
        EXISTING_CONFIG="true"
      fi
    fi
    
  3. Prompt for Action (if existing config found):

    If existing configuration was detected, use AskUserQuestion:

    {
      questions: [
        {
          question: "Found existing ACE configuration. What would you like to do?",
          header: "Config Action",
          multiSelect: false,
          options: [
            {
              label: "Keep existing configuration",
              description: "No changes - use current org and project settings"
            },
            {
              label: "Update project only",
              description: "Keep organization, select a different project"
            },
            {
              label: "Reconfigure everything",
              description: "Fresh setup - change both organization and project"
            }
          ]
        }
      ]
    }
    

    Based on user's choice:

    • "Keep existing configuration" → Exit early:
      echo "✅ Keeping existing configuration"
      echo "   Organization: $EXISTING_ORG"
      echo "   Project: $EXISTING_PROJECT"
      exit 0
      
    • "Update project only" → Skip to Step 5 (project selection), reuse $EXISTING_ORG
    • "Reconfigure everything" → Continue with Step 4 (full flow)
  4. Read Global Config:

    GLOBAL_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/ace/config.json"
    
    if [ ! -f "$GLOBAL_CONFIG" ]; then
      echo "⚠️  No global config found at $GLOBAL_CONFIG"
      echo "   Run /ace:configure --global first"
      exit 1
    fi
    
    # Check if multi-org mode
    HAS_ORGS=$(jq 'has("orgs")' "$GLOBAL_CONFIG" 2>/dev/null || echo "false")
    
  5. Multi-Org Mode (if HAS_ORGS is true):

    Use AskUserQuestion to select organization:

    // Parse orgs from global config
    // For each org in config.orgs:
    {
      questions: [
        {
          question: "Which organization should this project use?",
          header: "Organization",
          multiSelect: false,
          options: [
            {
              label: "org.orgName",
              description: "org_id"
            }
            // ... more orgs
          ]
        }
      ]
    }
    

    Then ask for project from that org's project list.

  6. Single-Org Mode (if HAS_ORGS is false):

    Just ask for project ID directly using AskUserQuestion.

  7. Write .claude/settings.json:

    mkdir -p "$PROJECT_ROOT/.claude"
    
    if [ -n "$ORG_ID" ]; then
      # Multi-org: include ACE_ORG_ID in env
      cat > "$PROJECT_CONFIG" <<EOF
    

{ "env": { "ACE_ORG_ID": "$ORG_ID", "ACE_PROJECT_ID": "$PROJECT_ID" } } EOF echo " Project configuration saved:" echo " Organization ID: $ORG_ID" echo " Project ID: $PROJECT_ID" else # Single-org: just ACE_PROJECT_ID in env cat > "$PROJECT_CONFIG" <<EOF { "env": { "ACE_PROJECT_ID": "$PROJECT_ID" } } EOF echo " Project configuration saved:" echo " Project ID: $PROJECT_ID" fi

echo " Location: $PROJECT_CONFIG" echo ""


### Step 5: Show Summary

```bash
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ ACE Configuration Complete!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

if [ "$SCOPE" = "global" ] || [ "$SCOPE" = "both" ]; then
GLOBAL_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/ace/config.json"
echo "Global Config: $GLOBAL_CONFIG ✓"
fi

if [ "$SCOPE" = "project" ] || [ "$SCOPE" = "both" ]; then
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
echo "Project Config: $PROJECT_ROOT/.claude/settings.json ✓"
fi

echo ""
echo "Next steps:"
echo "1. Run: /ace:status to verify connection"
echo "2. Optional: /ace:bootstrap to populate playbook from codebase"
echo "3. Start coding - hooks will auto-search patterns!"
echo ""

Implementation Notes for Claude

Key Points:

  1. Always use AskUserQuestion for user input (not bash read or prompts)
  2. Parse JSON responses from ce-ace config validate --json
  3. Build dynamic options from validation response (orgs/projects)
  4. Map user selections to actual values (e.g., "Production" → URL)
  5. Handle both single-org and multi-org modes based on global config

Error Handling:

  • Check jq availability (required for JSON parsing)
  • Check ce-ace version >= 1.0.2
  • Validate token before saving (with detailed error messages)
  • Verify global config file was created and is valid JSON
  • Verify global config has required fields (serverUrl, apiToken)
  • Check user has at least one project in organization
  • Handle missing global config for project-only mode
  • Use subshell for environment variables (avoid pollution)

User Experience:

  • Show progress messages at each step
  • Display org/project names (not just IDs) in selections
  • Provide helpful error messages with next steps
  • Summarize what was configured

What Gets Configured

Global Config (~/.config/ace/config.json)

Single-Org Mode:

{
  "serverUrl": "https://ace-api.code-engine.app",
  "apiToken": "ace_xxxxx",
  "projectId": "prj_xxxxx",
  "cacheTtlMinutes": 120
}

Multi-Org Mode:

{
  "serverUrl": "https://ace-api.code-engine.app",
  "orgs": {
    "org_xxxxx": {
      "orgName": "My Organization",
      "apiToken": "ace_xxxxx",
      "projects": ["prj_123", "prj_456"]
    }
  },
  "cacheTtlMinutes": 120
}

Project Config (.claude/settings.json)

Multi-Org:

{
  "env": {
    "ACE_ORG_ID": "org_xxxxx",
    "ACE_PROJECT_ID": "prj_xxxxx"
  }
}

Single-Org:

{
  "env": {
    "ACE_PROJECT_ID": "prj_xxxxx"
  }
}

Usage Examples

First-Time Setup (Both Global + Project)

/ace:configure

Flow:

  1. Asks for server URL (production/localhost/custom)
  2. Asks for API token
  3. Validates token, fetches org/projects
  4. Asks which project to configure
  5. Saves global config (~/.config/ace/config.json)
  6. Saves project config (.claude/settings.json)

Update Global Config Only

/ace:configure --global

Flow:

  1. Reconfigures global settings
  2. Validates token
  3. Updates ~/.config/ace/config.json

Update Project Config Only

/ace:configure --project

Flow:

  1. Reads existing global config
  2. Asks which org/project for THIS project
  3. Updates .claude/settings.json

See Also

  • /ace:status - Verify configuration
  • /ace:bootstrap - Initialize playbook
  • ce-ace config --help - CLI config help
  • ce-ace config show - View current config