mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-08-31 01:54:53 +00:00
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:
parent
aeec170dfa
commit
1bd7b1bd07
4 changed files with 93 additions and 55 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue