diff --git a/.claude/skills/setup-trigger-service/refactor.sh b/.claude/skills/setup-trigger-service/refactor.sh index 25c42966..7909de4a 100755 --- a/.claude/skills/setup-trigger-service/refactor.sh +++ b/.claude/skills/setup-trigger-service/refactor.sh @@ -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 diff --git a/cli/src/commands.ts b/cli/src/commands.ts index 83903fc8..b22a7f14 100644 --- a/cli/src/commands.ts +++ b/cli/src/commands.ts @@ -63,8 +63,8 @@ async function loadManifestWithSpinner(): Promise { 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); } } diff --git a/hetzner/lib/common.sh b/hetzner/lib/common.sh index 472d3425..c9f5db61 100755 --- a/hetzner/lib/common.sh +++ b/hetzner/lib/common.sh @@ -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 diff --git a/shared/common.sh b/shared/common.sh index 39a255ff..eb3e6420 100644 --- a/shared/common.sh +++ b/shared/common.sh @@ -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