feat: Add community-coordinator agent to refactor team (#64)

* ux: Improve error messages and user guidance across CLI and shell scripts

Enhanced error messages to be more actionable and user-friendly:

CLI improvements (commands.ts):
- Made validateNonEmptyString clearer: "is required but was not provided"
- Reordered troubleshooting steps to check matrix first (most common issue)
- Simplified 404 error message: "doesn't exist yet" vs "may not be implemented"
- Changed "Troubleshooting steps" to just "Troubleshooting" (less formal)

Shared library improvements (shared/common.sh):
- OAuth cancellation now explains why API key is needed and where to get it
- safe_read non-TTY error explains what non-interactive mode is with example
- get_resource_name error shows exact env var syntax needed
- Agent verification failures now list specific possible causes
- All improvements add context and next steps rather than just stating the problem

Hetzner library improvements (hetzner/lib/common.sh):
- Replaced technical "Remediation" with friendly "How to fix"
- Changed log_warn to log_error for error conditions (consistent severity)
- Added spacing for better readability of multi-line errors
- Made server creation errors more specific about account issues

All changes focus on helping users understand WHAT went wrong and HOW to fix it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: Replace issue-triager with community-coordinator agent

Replace the issue-triager agent in the refactor team with a
community-coordinator that actively engages with GitHub issues:
acknowledges reports, posts interim updates, delegates to relevant
teammates, and posts final resolutions — so reporters feel heard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
A 2026-02-09 02:58:26 -08:00 committed by GitHub
parent aeec170dfa
commit 1bd7b1bd07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 93 additions and 55 deletions

View file

@ -66,48 +66,66 @@ Create these teammates:
- Run 'bun test' and fix failures
- Add integration tests for critical paths
5. **issue-triager** (Sonnet)
- Run: gh issue list --repo OpenRouterTeam/spawn --state open --json number,title,body,createdAt
- For each open issue:
* Read the error log provided
* Attempt to reproduce locally
* If reproducible: create a fix branch, fix the bug, then follow the Issue Fix Workflow below
* If not reproducible or user error: comment explaining why, then close with gh issue close
* If feature request: label as 'enhancement' and close (point to discussions)
- EVERY open issue must be resolved by end of cycle. No dangling issues.
5. **community-coordinator** (Sonnet)
- FIRST TASK: Run `gh issue list --repo OpenRouterTeam/spawn --state open --json number,title,body,labels,createdAt`
- For EVERY open issue, immediately post an acknowledgment comment:
gh issue comment NUMBER --body "Thanks for reporting this! Our automated maintenance team is looking into it. We'll post updates here as we investigate."
- Categorize each issue (bug, feature request, question, already-fixed)
- For bugs: message the relevant teammate to investigate
* Security-related → message security-auditor
* UX/error messages → message ux-engineer
* Test failures → message test-engineer
* Code quality → message complexity-hunter
- Post interim updates on issues as teammates report findings:
gh issue comment NUMBER --body "Update: We've identified the root cause — [summary]. Working on a fix now."
- When a fix PR is merged, post the final resolution:
gh issue comment NUMBER --body "This has been fixed in PR_URL. [Brief explanation of what was changed and why]. The fix is live on main — please try updating and let us know if you still see the issue."
- Then close: gh issue close NUMBER
- For feature requests: comment acknowledging the request, label as enhancement, and close with a note pointing to discussions
- For questions: answer directly in a comment, then close
- GOAL: Every issue reporter should feel heard and informed. No cold trails.
- EVERY open issue must be engaged by end of cycle. No dangling issues.
## Issue Fix Workflow (CRITICAL follow exactly)
When fixing a bug reported in a GitHub issue:
1. Create a fix branch: git checkout -b fix/issue-NUMBER
2. Implement the fix and commit
3. Push the branch: git push -u origin fix/issue-NUMBER
4. Create a PR that references the issue:
1. Community-coordinator posts acknowledgment comment on the issue
2. Community-coordinator messages the relevant teammate to investigate
3. Create a fix branch: git checkout -b fix/issue-NUMBER
4. Implement the fix and commit
5. Community-coordinator posts interim update on the issue with root cause summary
6. Push the branch: git push -u origin fix/issue-NUMBER
7. Create a PR that references the issue:
gh pr create --title "Fix: description" --body "Fixes #NUMBER"
5. Merge the PR immediately: gh pr merge --squash --delete-branch
6. Close the issue: gh issue close NUMBER --comment "Fixed in PR_URL. The fix is now on main."
7. Switch back to main: git checkout main && git pull origin main
8. Merge the PR immediately: gh pr merge --squash --delete-branch
9. Community-coordinator posts final resolution comment with PR link and explanation
10. Close the issue: gh issue close NUMBER
11. Switch back to main: git checkout main && git pull origin main
NEVER leave an issue open after the fix is merged. NEVER leave a PR unmerged.
If a PR cannot be merged (conflicts, superseded, etc.), close it WITH a comment explaining why.
NEVER close a PR silently — every closed PR MUST have a comment.
The full cycle is: branch -> fix -> PR (references issue) -> merge PR -> close issue.
The full cycle is: acknowledge → investigate → branch → fix → update → PR (references issue) → merge PR → resolve & close issue.
## Workflow
1. Create the team with TeamCreate
2. Create tasks using TaskCreate for each area:
- Community coordination: scan all open issues, post acknowledgments, categorize, and delegate
- Security scan of all scripts
- UX test of main user flows
- Complexity reduction in top 5 longest functions
- Test coverage for recent changes
- GitHub issue triage: check ALL open issues and resolve each one
3. Spawn teammates with Task tool using subagent_type='general-purpose'
4. Assign tasks to teammates using TaskUpdate
5. Monitor teammate progress via their messages
6. Create Sprite checkpoint after successful changes: sprite-env checkpoint create --comment 'Description'
7. When cycle completes, verify: zero open issues, all PRs merged, summarize what was fixed/improved
5. Community-coordinator engages issues FIRST — posts acknowledgments before other agents start investigating
6. Community-coordinator delegates issue investigations to relevant teammates
7. Monitor teammate progress via their messages
8. Community-coordinator posts interim updates on issues as teammates report findings
9. Create Sprite checkpoint after successful changes: sprite-env checkpoint create --comment 'Description'
10. Community-coordinator posts final resolutions on all issues, closes them
11. When cycle completes, verify: every issue engaged with comments, all PRs merged, summarize what was fixed/improved
## Safety Rules

View file

@ -63,8 +63,8 @@ async function loadManifestWithSpinner(): Promise<Manifest> {
function validateNonEmptyString(value: string, fieldName: string, helpCommand: string): void {
if (!value || value.trim() === "") {
p.log.error(`${fieldName} cannot be empty`);
p.log.info(`Run ${pc.cyan(helpCommand)} to see available ${fieldName.toLowerCase()}s.`);
p.log.error(`${fieldName} is required but was not provided`);
p.log.info(`Run ${pc.cyan(helpCommand)} to see all available ${fieldName.toLowerCase()}s.`);
process.exit(1);
}
}
@ -240,8 +240,8 @@ function reportDownloadFailure(primaryUrl: string, fallbackUrl: string, primaryS
console.error(`Fallback source (${fallbackUrl}): ${getStatusDescription(fallbackStatus)}`);
if (primaryStatus === 404 && fallbackStatus === 404) {
console.error("\nThis combination may not be implemented yet.");
console.error(`Run ${pc.cyan("spawn list")} to see all available combinations.`);
console.error("\nThis agent + cloud combination doesn't exist yet.");
console.error(`Check which combinations are available: ${pc.cyan("spawn list")}`);
}
}
@ -255,10 +255,10 @@ async function execScript(cloud: string, agent: string, prompt?: string): Promis
} catch (err) {
p.log.error("Failed to download or execute spawn script");
console.error("\nError:", getErrorMessage(err));
console.error("\nTroubleshooting steps:");
console.error(" 1. Check your internet connection");
console.error(" 2. Verify the combination is implemented: spawn list");
console.error(` 3. Try the direct link: ${ghUrl}`);
console.error("\nTroubleshooting:");
console.error(` 1. Verify this combination exists: ${pc.cyan("spawn list")}`);
console.error(" 2. Check your internet connection");
console.error(` 3. Try accessing the script directly: ${ghUrl}`);
process.exit(1);
}
}

View file

@ -40,10 +40,11 @@ test_hcloud_token() {
local error_msg
error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('message','No details available'))" 2>/dev/null || echo "Unable to parse error")
log_error "API Error: $error_msg"
log_warn "Remediation steps:"
log_warn " 1. Verify token at: https://console.hetzner.cloud/projects → API Tokens"
log_warn " 2. Ensure the token has read/write permissions"
log_warn " 3. Check token hasn't expired"
log_error ""
log_error "How to fix:"
log_error " 1. Verify your token at: https://console.hetzner.cloud/projects → API Tokens"
log_error " 2. Ensure the token has read/write permissions"
log_error " 3. Check the token hasn't expired"
return 1
fi
return 0
@ -84,11 +85,11 @@ hetzner_register_ssh_key() {
local error_msg
error_msg=$(echo "$register_response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('message','Unknown error'))" 2>/dev/null || echo "$register_response")
log_error "API Error: $error_msg"
log_warn "Common causes:"
log_warn " - SSH key already registered with this name"
log_warn " - Invalid SSH key format (must be valid ed25519 public key)"
log_warn " - API token lacks write permissions"
log_error ""
log_error "Common causes:"
log_error " - SSH key already registered with this name"
log_error " - Invalid SSH key format (must be valid ed25519 public key)"
log_error " - API token lacks write permissions"
return 1
fi
@ -161,13 +162,14 @@ print(json.dumps(body))
local error_msg
error_msg=$(echo "$response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read()).get('error',{}).get('message','Unknown error'))" 2>/dev/null || echo "$response")
log_error "API Error: $error_msg"
log_warn "Common issues:"
log_warn " - Insufficient account balance or payment method required"
log_warn " - Server type/location unavailable (try different HETZNER_SERVER_TYPE or HETZNER_LOCATION)"
log_warn " - Server limit reached"
log_warn " - Invalid cloud-init userdata"
log_warn "Remediation: Check https://console.hetzner.cloud/"
log_error ""
log_error "Common issues:"
log_error " - Insufficient account balance or payment method required"
log_error " - Server type/location unavailable (try different HETZNER_SERVER_TYPE or HETZNER_LOCATION)"
log_error " - Server limit reached for your account"
log_error " - Invalid cloud-init userdata"
log_error ""
log_error "Check your account status: https://console.hetzner.cloud/"
return 1
fi

View file

@ -77,8 +77,12 @@ safe_read() {
read -r -p "${prompt}" result < /dev/tty
else
# No interactive input available
log_error "Cannot read input: no TTY available"
log_error "Set required environment variables for non-interactive usage"
log_error "Cannot prompt for input: no interactive terminal available"
log_error ""
log_error "Running in non-interactive mode (pipe, background job, or automated script)."
log_error "Set required environment variables before running spawn."
log_error ""
log_error "Example: OPENROUTER_API_KEY=sk-or-v1-... spawn claude sprite"
return 1
fi
@ -275,9 +279,10 @@ get_resource_name() {
local name
name=$(safe_read "${prompt_text}")
if [[ -z "${name}" ]]; then
log_error "${prompt_text%:*} is required"
log_error "${prompt_text%:*} is required but not provided"
log_error ""
log_error "For non-interactive usage, set: ${env_var_name}=your-value"
log_error "For non-interactive usage, set the environment variable:"
log_error " ${env_var_name}=your-value spawn ..."
return 1
fi
echo "${name}"
@ -644,8 +649,12 @@ get_openrouter_api_key_oauth() {
echo "${api_key}"
return 0
else
log_error "Authentication cancelled"
log_error "Cannot proceed without an API key"
log_error "Authentication cancelled by user"
log_error ""
log_error "An OpenRouter API key is required to use spawn."
log_error "Get your free API key at: https://openrouter.ai/settings/keys"
log_error ""
log_error "For non-interactive usage, set: OPENROUTER_API_KEY=sk-or-v1-..."
return 1
fi
}
@ -1006,16 +1015,25 @@ verify_agent_installed() {
if ! command -v "${agent_cmd}" &> /dev/null; then
log_error "${agent_name} installation failed: command '${agent_cmd}' not found in PATH"
log_error ""
log_error "This usually means the installation process encountered an error."
log_error "Try running the script again, or check the installation logs above."
log_error "Possible causes:"
log_error " - The installation script encountered an error (check logs above)"
log_error " - Network connectivity issues during download"
log_error " - Insufficient disk space or permissions"
log_error ""
log_error "Try running the script again, or install ${agent_name} manually."
return 1
fi
if ! "${agent_cmd}" "${verify_arg}" &> /dev/null; then
log_error "${agent_name} installation failed: '${agent_cmd} ${verify_arg}' returned an error"
log_error ""
log_error "The command exists but does not execute properly."
log_error "Try running the script again, or check for dependency issues."
log_error "The command was installed but doesn't execute properly."
log_error "Possible causes:"
log_error " - Missing runtime dependencies (Python, Node.js, etc.)"
log_error " - Incompatible system architecture or OS version"
log_error " - Corrupted download or partial installation"
log_error ""
log_error "Try running the script again, or check ${agent_name}'s installation docs."
return 1
fi