418 lines
9.6 KiB
Markdown
418 lines
9.6 KiB
Markdown
---
|
|
description: Update an existing project configuration
|
|
allowed-tools: [Bash, Read, Edit, AskUserQuestion]
|
|
argument-hint: <project-id> [--field FIELD_PATH]
|
|
---
|
|
|
|
# Update Project Configuration
|
|
|
|
Update an existing project in `~/.claude/ccpm-config.yaml`.
|
|
|
|
## Arguments
|
|
|
|
- **$1** - Project ID (required)
|
|
- **--field** - Specific field to update (optional, e.g., "linear.team", "external_pm.jira.project_key")
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# Interactive update (all fields)
|
|
/ccpm:project:update my-app
|
|
|
|
# Update specific field
|
|
/ccpm:project:update my-app --field linear.team
|
|
/ccpm:project:update my-app --field external_pm.jira.project_key
|
|
```
|
|
|
|
## Workflow
|
|
|
|
### Step 1: Validate and Load Project
|
|
|
|
```bash
|
|
CONFIG_FILE="$HOME/.claude/ccpm-config.yaml"
|
|
PROJECT_ID=$1
|
|
|
|
# Check configuration exists
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
echo "❌ Error: No CCPM configuration found"
|
|
echo ""
|
|
echo "Create configuration:"
|
|
echo " /ccpm:project:add <project-id>"
|
|
exit(1)
|
|
fi
|
|
|
|
# Check project exists
|
|
if ! yq eval ".projects.$PROJECT_ID" "$CONFIG_FILE" > /dev/null 2>&1; then
|
|
echo "❌ Error: Project '$PROJECT_ID' not found"
|
|
echo ""
|
|
echo "Available projects:"
|
|
yq eval '.projects | keys | .[]' "$CONFIG_FILE"
|
|
exit(1)
|
|
fi
|
|
|
|
# Load current configuration
|
|
CURRENT_CONFIG=$(yq eval ".projects.$PROJECT_ID" "$CONFIG_FILE" -o=json)
|
|
```
|
|
|
|
### Step 2: Determine Update Mode
|
|
|
|
If `--field` is provided → **Targeted field update**
|
|
Otherwise → **Interactive full update**
|
|
|
|
### Mode A: Targeted Field Update
|
|
|
|
```javascript
|
|
const fieldPath = $2 // e.g., "linear.team"
|
|
const currentValue = await yq(`.projects.${projectId}.${fieldPath}`, CONFIG_FILE)
|
|
|
|
console.log(`
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
📝 Update Field: ${fieldPath}
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
Project: ${projectId}
|
|
Field: ${fieldPath}
|
|
Current: ${currentValue}
|
|
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
`)
|
|
|
|
// Ask for new value
|
|
{
|
|
questions: [{
|
|
question: `What should the new value be for ${fieldPath}?`,
|
|
header: "New Value",
|
|
multiSelect: false,
|
|
options: [
|
|
{
|
|
label: "Enter manually",
|
|
description: "Type the new value"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
|
|
// Validate new value (type-specific validation)
|
|
const newValue = userInput
|
|
|
|
// Update configuration
|
|
await yq(`-i '.projects.${projectId}.${fieldPath} = "${newValue}"'`, CONFIG_FILE)
|
|
|
|
console.log(`
|
|
✅ Updated successfully!
|
|
|
|
Field: ${fieldPath}
|
|
Old: ${currentValue}
|
|
New: ${newValue}
|
|
`)
|
|
```
|
|
|
|
### Mode B: Interactive Full Update
|
|
|
|
Ask user which category to update:
|
|
|
|
```javascript
|
|
{
|
|
questions: [{
|
|
question: "What would you like to update?",
|
|
header: "Update Category",
|
|
multiSelect: false,
|
|
options: [
|
|
{
|
|
label: "Project Info",
|
|
description: "Name, description, owner"
|
|
},
|
|
{
|
|
label: "Linear Settings",
|
|
description: "Team, project, labels, workflow states"
|
|
},
|
|
{
|
|
label: "External PM",
|
|
description: "Jira, Confluence, Slack configuration"
|
|
},
|
|
{
|
|
label: "Code Repository",
|
|
description: "Repository type and settings"
|
|
},
|
|
{
|
|
label: "Quality Gates",
|
|
description: "SonarQube, code review settings"
|
|
},
|
|
{
|
|
label: "Tech Stack",
|
|
description: "Languages, frameworks, databases"
|
|
},
|
|
{
|
|
label: "Custom Commands",
|
|
description: "Project-specific commands"
|
|
},
|
|
{
|
|
label: "All Settings",
|
|
description: "Review and update all categories"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
```
|
|
|
|
#### Update: Project Info
|
|
|
|
```javascript
|
|
const current = config
|
|
|
|
// Show current values
|
|
console.log(`
|
|
Current Project Info:
|
|
Name: ${current.name}
|
|
Description: ${current.description}
|
|
Owner: ${current.owner}
|
|
`)
|
|
|
|
// Ask for updates
|
|
{
|
|
questions: [
|
|
{
|
|
question: "New project name? (or keep current)",
|
|
header: "Name",
|
|
multiSelect: false,
|
|
options: [
|
|
{ label: "Keep current", description: current.name },
|
|
{ label: "Change", description: "Enter new name" }
|
|
]
|
|
},
|
|
{
|
|
question: "New description? (or keep current)",
|
|
header: "Description",
|
|
multiSelect: false,
|
|
options: [
|
|
{ label: "Keep current", description: current.description },
|
|
{ label: "Change", description: "Enter new description" }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
// Apply changes
|
|
if (nameChanged) {
|
|
await yq(`-i '.projects.${projectId}.name = "${newName}"'`, CONFIG_FILE)
|
|
}
|
|
if (descriptionChanged) {
|
|
await yq(`-i '.projects.${projectId}.description = "${newDescription}"'`, CONFIG_FILE)
|
|
}
|
|
```
|
|
|
|
#### Update: Linear Settings
|
|
|
|
```javascript
|
|
{
|
|
questions: [
|
|
{
|
|
question: "Which Linear setting to update?",
|
|
header: "Linear",
|
|
multiSelect: true, // Allow multiple selections
|
|
options: [
|
|
{ label: "Team", description: `Current: ${config.linear.team}` },
|
|
{ label: "Project", description: `Current: ${config.linear.project}` },
|
|
{ label: "Labels", description: `Current: ${config.linear.default_labels.join(", ")}` },
|
|
{ label: "Workflow States", description: "Backlog, Planning, etc." }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
// For each selected setting, prompt for new value
|
|
// Then update configuration
|
|
```
|
|
|
|
#### Update: External PM
|
|
|
|
```javascript
|
|
{
|
|
questions: [{
|
|
question: "Update external PM integration?",
|
|
header: "External PM",
|
|
multiSelect: false,
|
|
options: [
|
|
{
|
|
label: "Enable/Disable",
|
|
description: `Currently: ${config.external_pm.enabled ? "Enabled" : "Disabled"}`
|
|
},
|
|
{
|
|
label: "Jira Settings",
|
|
description: "Base URL, project key"
|
|
},
|
|
{
|
|
label: "Confluence Settings",
|
|
description: "Base URL, space key"
|
|
},
|
|
{
|
|
label: "Slack Settings",
|
|
description: "Workspace, channels"
|
|
},
|
|
{
|
|
label: "Disable All External PM",
|
|
description: "Switch to Linear-only mode"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
```
|
|
|
|
#### Update: Code Repository
|
|
|
|
```javascript
|
|
{
|
|
questions: [{
|
|
question: "Update repository settings?",
|
|
header: "Repository",
|
|
multiSelect: false,
|
|
options: [
|
|
{
|
|
label: "Change Type",
|
|
description: `Currently: ${config.code_repository.type}`
|
|
},
|
|
{
|
|
label: "Update GitHub Settings",
|
|
description: "Owner, repo name"
|
|
},
|
|
{
|
|
label: "Update BitBucket Settings",
|
|
description: "Workspace, repo slug"
|
|
},
|
|
{
|
|
label: "Update Repository URL",
|
|
description: "Change repository URL"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
```
|
|
|
|
### Step 3: Show Changes Summary
|
|
|
|
After collecting all updates:
|
|
|
|
```javascript
|
|
console.log(`
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
📝 Changes Summary
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
|
|
Project: ${projectId}
|
|
|
|
${changes.map(change => `
|
|
${change.field}
|
|
Old: ${change.oldValue}
|
|
New: ${change.newValue}
|
|
`).join("\n")}
|
|
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
`)
|
|
```
|
|
|
|
### Step 4: Confirm and Apply
|
|
|
|
```javascript
|
|
{
|
|
questions: [{
|
|
question: "Apply these changes?",
|
|
header: "Confirm",
|
|
multiSelect: false,
|
|
options: [
|
|
{
|
|
label: "Yes, apply",
|
|
description: "Save changes to configuration"
|
|
},
|
|
{
|
|
label: "Review again",
|
|
description: "Go back and modify"
|
|
},
|
|
{
|
|
label: "Cancel",
|
|
description: "Discard all changes"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
```
|
|
|
|
If confirmed:
|
|
|
|
```bash
|
|
# Apply all changes using yq
|
|
for change in "${CHANGES[@]}"; do
|
|
yq eval -i ".projects.$PROJECT_ID.${change.field} = ${change.value}" "$CONFIG_FILE"
|
|
done
|
|
|
|
echo ""
|
|
echo "✅ Project configuration updated!"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📝 Next Steps"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "View updated config: /ccpm:project:show $PROJECT_ID"
|
|
echo "List all projects: /ccpm:project:list"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
```
|
|
|
|
## Examples
|
|
|
|
### Example 1: Update Linear team
|
|
|
|
```bash
|
|
/ccpm:project:update my-app --field linear.team
|
|
|
|
# Prompts:
|
|
# Current: Work
|
|
# New value: Personal
|
|
|
|
# Result:
|
|
# ✅ Updated linear.team from "Work" to "Personal"
|
|
```
|
|
|
|
### Example 2: Interactive update
|
|
|
|
```bash
|
|
/ccpm:project:update my-app
|
|
|
|
# Shows menu:
|
|
# 1. Project Info
|
|
# 2. Linear Settings
|
|
# 3. External PM
|
|
# ...
|
|
|
|
# User selects "Linear Settings"
|
|
# Shows checkboxes for Team, Project, Labels, Workflow States
|
|
# Updates selected fields
|
|
```
|
|
|
|
### Example 3: Enable Jira integration
|
|
|
|
```bash
|
|
/ccpm:project:update my-side-project
|
|
|
|
# Select: External PM
|
|
# Choose: Enable Jira
|
|
# Enter: Base URL, project key
|
|
# Result: external_pm.enabled = true, jira configured
|
|
```
|
|
|
|
## Validation
|
|
|
|
The command validates:
|
|
- Project ID exists
|
|
- Field paths are valid
|
|
- Values match expected types
|
|
- Required fields are not left empty
|
|
- URLs are properly formatted
|
|
|
|
## Notes
|
|
|
|
- All changes are applied atomically
|
|
- Invalid changes are rejected before saving
|
|
- Can cancel at any point before confirmation
|
|
- Use `/ccpm:project:show` to verify changes
|
|
- Configuration file: `~/.claude/ccpm-config.yaml`
|