chore: add bug-triage skill for agent-driven issue triage (#1725)
* chore: add bug-triage skill for agent-driven issue triage Add .skills/bug-triage/ with SKILL.md and push_fix_to_github.py script. The skill provides a complete triage workflow: - Gather bug context from chat/issues/live observation - Search for duplicate GitHub issues - File well-structured issues with root cause analysis - Push fix PRs via GitHub API (no local checkout needed) - Git archaeology (git log -S) for regression tracking - NPM package regression diffing - Remote code inspection without local clone Reference the skill in AGENTS.md so any agent working on this repo can discover and follow the triage workflow automatically. Tested across 100+ real bug triages on ComposioHQ/agent-orchestrator. * chore: add clickable issue/PR links as real-world examples Add concrete examples with links to actual issues and PRs: - #1129: deep diagnosis vs surface-level triage - #1151: placeholder URL RCA - #1391: CSS regression via git log -S archaeology - PR #1523: optional TypeScript interface fields - PR #1608: npm package regression diffing * chore: add formatting rule — always linkify issue/PR references Any agent following this skill must include clickable URLs when mentioning issues or PRs. Bare '#123' without links is not allowed. * fix: address review feedback — use existing skills/ dir, fix bugs - Move .skills/ → skills/ (repo already has a skills/ directory) - Fix label name: 'priority:medium' → 'priority: medium' (with space) - Fix issue-assets branch naming: use slug instead of issue number (issue doesn't exist yet at upload time) - Fix base64 command: portable across Linux and macOS (tr -d '\n') - push_fix_to_github.py: allow empty NEW_STRING for deletion edits - push_fix_to_github.py: warn on multiple OLD_STRING matches - push_fix_to_github.py: create branch before fetching file (SHA race) - push_fix_to_github.py: configurable BASE_BRANCH (not hardcoded main) - Update all path references in AGENTS.md and SKILL.md * fix: correct stale .skills/ path in AGENTS.md How to load section * feat: add cross-platform triage awareness (Windows/macOS/Linux) Add Step 1b covering: - When to ask for OS/shell/runtime/reproducibility - Common Windows-specific bug patterns (paths, shell syntax, ConPTY, named pipes, NTFS case-insensitivity, localhost IPv6 stalls) - Key cross-platform files (platform.ts, CROSS_PLATFORM.md, etc.) - Tagging OS-specific issues with 'to-reproduce' Based on the actual Windows support implementation in #1025 (platform.ts, runtime-process, CROSS_PLATFORM.md). * feat: add 6 triage improvements from real failure patterns 1. Environment Info Collection (Step 1): - Standard template: OS, shell, runtime, AO version, Node version, install method - Prevents wasted time tracing wrong code versions 2. Duplicate Search Strategy (Step 2): - Search by symptom, component, AND error message - Always search --state all (open + closed — bugs regress) - Check PRs too (fixes sometimes land without issues) 3. Stop-and-Ask Triggers (Step 1c): - Explicit criteria: 3 failed hypotheses, can't reproduce, upstream bug, UI-only bug without screenshot, unknown environment - Includes template for asking the reporter 4. Pre-Submission Checklist (Step 4.1b): - Reporter attribution, commit hash, AO version, confidence score, cross-links, concrete reproduction steps, screenshots ready - Verify all before creating the issue 5. Confidence Scoring (Step 4.4): - High/Medium/Low with clear criteria - Maps to labels: bug only / to-explore / to-reproduce - Example from PR #1608 where high confidence was wrong 6. Cross-Linking Related Issues (Step 4.5): - Search by subsystem after filing - Include Related section with one-line descriptions - Helps maintainers see patterns across issues 7. Subsystem-Specific Triage Quick Reference: - Table mapping subsystems to required info and key files - Common misrouting patterns (terminal, stuck session, config) * feat: add report gate, local diagnostics with ao events, deduplicate New sections: - Step 0a: Platform-specific context gathering (Discord/Slack/GitHub/live) - Step 0b: Minimum Viable Report Gate — required fields (what/where/when) plus 2-of-4 supporting (OS, version, reproducibility, steps) - Step 0c: Local Diagnostics — auto-gather environment, process health, AO event log (ao events list/search/stats), session state files, reproducibility testing. Covers ao events commands with all flags. Deduplication: - Step 1b: removed repeated OS/shell/runtime questions (now in Step 1.2) - Step 1c: removed 'environment unknown' and 'can't reproduce' triggers (covered by report gate in Step 0b) * refactor: compress bug-triage skill from 575→311 lines Merge overlapping sections (Steps 0/0b/0c/1 → single Gather+Investigate flow), move reference material to Appendix, deduplicate pitfalls, compress code blocks. All factual content preserved: commands, file paths, labels, examples, links. * docs: add skills/ README with agent-specific install instructions Covers Claude Code, Codex CLI, Cursor, Windsurf, Copilot, Gemini CLI, and Agent Orchestrator. Includes available skills table and how to write new skills. * docs: add Skills section to CLAUDE.md referencing skills/ directory Links all 4 skills with when-to-load guidance, plus pointer to skills/README.md for installing into other agents. * fix: resolve PR review comments — remove Hermes-specific refs, portable base64 - Replace execute_code references with agent-agnostic 'Python script' wording - Replace base64 -d (Linux-only) with python3 -c (portable across macOS/Linux/Windows) --------- Co-authored-by: AO Bot <ao-bot@composio.dev>
This commit is contained in:
parent
334611b375
commit
0133bcdc88
20
AGENTS.md
20
AGENTS.md
|
|
@ -29,6 +29,26 @@ Monorepo (pnpm) with packages: `core`, `cli`, `web`, and `plugins/*`. The web da
|
|||
|
||||
Full guidelines with AO-specific context: see "Working Principles" in CLAUDE.md.
|
||||
|
||||
## Skills
|
||||
|
||||
Agents working on this repo should use these checked-in skills:
|
||||
|
||||
### Bug Triage (`skills/bug-triage/`)
|
||||
|
||||
**When to use:** Any time a bug is reported — in chat, issues, or live observation.
|
||||
|
||||
**What it covers:**
|
||||
- Full triage workflow: gather context → search duplicates → file/update GitHub issues → push fix PRs
|
||||
- Root cause analysis with `git log -S` archaeology and upstream dependency research
|
||||
- GitHub API-based file editing (no local checkout needed) via `scripts/push_fix_to_github.py`
|
||||
- NPM package regression diffing
|
||||
- Remote code inspection when the repo isn't cloned locally
|
||||
|
||||
**How to load:** Read `skills/bug-triage/SKILL.md` and follow its step-by-step workflow. The `scripts/` directory contains executable tools:
|
||||
- `push_fix_to_github.py` — Push a single-file fix and create a PR entirely via GitHub API
|
||||
|
||||
**Always pull latest main before triaging.** Stale code = bad triage. No exceptions.
|
||||
|
||||
## Key Files
|
||||
|
||||
- `packages/core/src/types.ts` — All plugin interfaces (Agent, Runtime, Workspace, etc.)
|
||||
|
|
|
|||
13
CLAUDE.md
13
CLAUDE.md
|
|
@ -363,6 +363,19 @@ All importable from `@aoagents/ao-core` unless noted:
|
|||
| `packages/cli/src/lib/running-state.ts` | RunningState + LastStopState management (register/unregister, last-stop read/write) |
|
||||
| `packages/web/src/components/ProjectSidebar.tsx` | Sidebar — always shows all projects' sessions |
|
||||
|
||||
## Skills
|
||||
|
||||
The `skills/` directory contains reusable workflow documents for common tasks. Load them before starting work:
|
||||
|
||||
| Skill | When to load |
|
||||
|-------|-------------|
|
||||
| [`skills/bug-triage/SKILL.md`](skills/bug-triage/SKILL.md) | Triage a bug report — investigate, search duplicates, file GitHub issues, push fix PRs |
|
||||
| [`skills/agent-orchestrator/SKILL.md`](skills/agent-orchestrator/SKILL.md) | Architecture and conventions for working on this codebase |
|
||||
| [`skills/release-notes/ao-weekly-release/SKILL.md`](skills/release-notes/ao-weekly-release/SKILL.md) | Generate weekly release notes from git history |
|
||||
| [`skills/social-media/SKILL.md`](skills/social-media/SKILL.md) | Social media post generation |
|
||||
|
||||
See [`skills/README.md`](skills/README.md) for how to install skills into other coding agents (Cursor, Copilot, Codex, etc.).
|
||||
|
||||
## Plugin Standards
|
||||
|
||||
### Package Layout
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
# Skills
|
||||
|
||||
Reusable skill documents for AI coding agents working on this repository. Each skill is a self-contained `SKILL.md` that teaches an agent how to perform a specific task.
|
||||
|
||||
## Available Skills
|
||||
|
||||
| Skill | Description |
|
||||
|-------|-------------|
|
||||
| [`bug-triage/`](bug-triage/SKILL.md) | Triage bugs reported in chat/issues — investigate, search duplicates, file GitHub issues, push fix PRs |
|
||||
| [`agent-orchestrator/`](agent-orchestrator/SKILL.md) | Architecture and conventions for working on the agent-orchestrator codebase |
|
||||
| [`release-notes/`](release-notes/ao-weekly-release/SKILL.md) | Generate weekly release notes from git history |
|
||||
| [`social-media/`](social-media/SKILL.md) | Social media post generation |
|
||||
|
||||
## How to Use
|
||||
|
||||
Copy the skill into your coding agent's skill directory. The destination depends on which agent you're using:
|
||||
|
||||
### Claude Code
|
||||
|
||||
```bash
|
||||
cp -r skills/bug-triage .claude/skills/bug-triage
|
||||
```
|
||||
|
||||
Or add the full path to your `CLAUDE.md`:
|
||||
|
||||
```markdown
|
||||
See skills/bug-triage/SKILL.md for bug triage workflow.
|
||||
```
|
||||
|
||||
### OpenAI Codex CLI
|
||||
|
||||
```bash
|
||||
cp -r skills/bug-triage .codex/skills/bug-triage
|
||||
```
|
||||
|
||||
Or reference in `AGENTS.md`:
|
||||
|
||||
```markdown
|
||||
See skills/bug-triage/SKILL.md for bug triage workflow.
|
||||
```
|
||||
|
||||
### Cursor
|
||||
|
||||
Add to `.cursor/rules/` as a rule file:
|
||||
|
||||
```bash
|
||||
cp skills/bug-triage/SKILL.md .cursor/rules/bug-triage.mdc
|
||||
```
|
||||
|
||||
### Windsurf / Other Codeium-based agents
|
||||
|
||||
Add to `.windsurf/rules/`:
|
||||
|
||||
```bash
|
||||
cp skills/bug-triage/SKILL.md .windsurf/rules/bug-triage.md
|
||||
```
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
Add to `.github/copilot-instructions.md` or reference in `.github/`:
|
||||
|
||||
```bash
|
||||
cp skills/bug-triage/SKILL.md .github/skills/bug-triage.md
|
||||
```
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
```bash
|
||||
cp -r skills/bug-triage .gemini/skills/bug-triage
|
||||
```
|
||||
|
||||
### Agent Orchestrator (this project)
|
||||
|
||||
Skills in this `skills/` directory are automatically available to agents spawned via `ao spawn`. Reference them in `AGENTS.md` or `CLAUDE.md` so agents load them at the start of a session.
|
||||
|
||||
## Writing a New Skill
|
||||
|
||||
1. Create a directory under `skills/<name>/`
|
||||
2. Add a `SKILL.md` with YAML frontmatter:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: my-skill
|
||||
description: One-line description of what the skill does.
|
||||
trigger: When to activate this skill.
|
||||
---
|
||||
```
|
||||
|
||||
3. Write the skill body in markdown — numbered steps, code blocks, tables
|
||||
4. Keep it agent-agnostic: use `gh` CLI, `git`, and standard Unix tools. Avoid tying to a specific agent framework
|
||||
5. Reference it in `AGENTS.md` so spawned agents discover it
|
||||
|
|
@ -0,0 +1,311 @@
|
|||
---
|
||||
name: bug-triage
|
||||
description: Triage bugs reported in chat/issues, search for duplicates, file or update GitHub issues with full context, and push fix PRs.
|
||||
trigger: User reports a bug, or asks to triage/file an issue for a reported problem.
|
||||
---
|
||||
|
||||
# Bug Triage Skill
|
||||
|
||||
Triage bugs into well-structured GitHub issues on the correct upstream repo.
|
||||
|
||||
## 1. Pre-flight
|
||||
|
||||
- **Pull latest code:** `git pull origin main`. Stale code = bad triage.
|
||||
- **Target repo:** Always file on the **upstream org** (`ComposioHQ/agent-orchestrator`), not forks.
|
||||
- **Record source:** chat URL, reporter name, attachments.
|
||||
|
||||
## 2. Gather Context
|
||||
|
||||
### 2a. Extract the report
|
||||
|
||||
| Source | How to gather |
|
||||
|--------|---------------|
|
||||
| **Discord/Slack thread** | Read full thread. Extract: reporter name, original description (the thread starter, not whoever tagged you), screenshots, follow-ups |
|
||||
| **GitHub issue** | `gh issue view <number> --repo <repo> --json body,comments` |
|
||||
| **Live observation** | Pull live state via observability tools |
|
||||
|
||||
### 2b. Minimum viable report gate
|
||||
|
||||
Before tracing code, verify the report has enough substance:
|
||||
|
||||
**Required (ALL):** what happened, where (page/command/feature), when (after upgrade? first time?)
|
||||
|
||||
**Required (2 of 4):** OS/shell/runtime, AO version (`ao --version`), reproducibility (consistent vs intermittent), reproduction steps
|
||||
|
||||
If insufficient, ask:
|
||||
> "I'd like to triage this but need more info: (1) **What happened?** (error/behavior), (2) **Where?** (page/command), (3) **When did it start?**, (4) **How to reproduce?**"
|
||||
|
||||
### 2c. Local diagnostics (if bug is on same machine)
|
||||
|
||||
Gather everything yourself before asking the reporter:
|
||||
|
||||
```bash
|
||||
# Environment
|
||||
ao --version && node --version && echo $SHELL && uname -a
|
||||
cat agent-orchestrator.yaml
|
||||
cat ~/.agent-orchestrator/running.json
|
||||
|
||||
# Process health
|
||||
pm2 status
|
||||
tmux list-sessions
|
||||
lsof -i :3000
|
||||
|
||||
# AO event log — structured timeline
|
||||
ao events list --limit 50 # recent events
|
||||
ao events list --session ao-5 --limit 100 # filter by session
|
||||
ao events list --log-level error --since 1h # errors only
|
||||
ao events search "spawn failed" # full-text search
|
||||
ao events stats # counts by kind/source
|
||||
|
||||
# Session state files
|
||||
cat ~/.agent-orchestrator/projects/*/sessions/*.json | python3 -m json.tool
|
||||
```
|
||||
|
||||
Event kinds: `session.spawned`, `session.spawn_failed`, `session.killed`, `lifecycle.transition`, `ci.failing`, `review.pending`, `runtime.probe_failed`, `agent.process_probe_failed`, `reaction.escalated`, `lifecycle.poll_failed`. Sources: `lifecycle`, `session-manager`, `api`, `runtime`, `agent`, `reaction`.
|
||||
|
||||
**Try the reproduction steps.** Running the actual command is worth 100 lines of code tracing.
|
||||
|
||||
## 3. Investigate
|
||||
|
||||
### 3a. Trace the code path
|
||||
|
||||
**Always trace the actual code** — don't surface-level diagnose. [#1129](https://github.com/ComposioHQ/agent-orchestrator/issues/1129) looked like a simple `ao stop` issue but was actually a session lineage/cascade problem.
|
||||
|
||||
```bash
|
||||
git fetch origin main && git log --oneline origin/main -5 # current HEAD
|
||||
# Record the commit hash you're analyzing against
|
||||
```
|
||||
|
||||
**Git archaeology** — find which commits introduced/removed specific code:
|
||||
```bash
|
||||
git log --oneline -S 'exact-string' -- <file>
|
||||
git show <sha> -- <file> | grep -B 5 -A 10 'pattern'
|
||||
```
|
||||
Example: [#1391](https://github.com/ComposioHQ/agent-orchestrator/issues/1391) traced a mobile layout break to a `display: flex` → `display: grid` change.
|
||||
|
||||
**Research upstream dependencies** (xterm, node-pty, React, etc.) — check installed vs latest version, search their GitHub issues, check changelogs. Root cause is often upstream.
|
||||
|
||||
### 3b. Cross-platform check
|
||||
|
||||
AO runs on **Windows, macOS, Linux** as first-class targets. If env info indicates Windows (or is unknown), check for these patterns:
|
||||
|
||||
- **Path separators** — hardcoded `/` or `\` breaks cross-platform
|
||||
- **Shell syntax** — PowerShell lacks `&&`, `$VAR`, `$(cat ...)`, `/dev/null`, here-docs
|
||||
- **`process.platform === "win32"` inline** — must use `isWindows()` from `@aoagents/ao-core`
|
||||
- **`process.kill(-pid)`** — POSIX-only; use `killProcessTree()`
|
||||
- **Named pipes vs Unix sockets** — Windows uses `\\.\pipe\ao-pty-<id>`
|
||||
- **`localhost`** — Windows resolves to `::1` first, causing ~21s stalls on IPv4-only servers
|
||||
- **NTFS case-insensitivity** — use `pathsEqual()`, not `===`
|
||||
- **ConPTY orphans** — can trigger WER dialogs if pty-host not shut down cooperatively
|
||||
- **`.cmd` shim resolution** — needs `shell: true` for `PATHEXT` lookup
|
||||
|
||||
Key files: `packages/core/src/platform.ts`, `docs/CROSS_PLATFORM.md`, `packages/plugins/runtime-process/`, `packages/cli/src/lib/path-equality.ts`
|
||||
|
||||
### 3c. Stop-and-ask triggers
|
||||
|
||||
Stop and ask for more info if:
|
||||
- **3 failed hypotheses** — traced 3 code paths, none explain it
|
||||
- **Root cause is upstream** — file with upstream reference, don't guess a local fix
|
||||
- **UI-only bug** and you can't screenshot — ask reporter to describe
|
||||
- **Can't reproduce** — ask for different config/sequence
|
||||
|
||||
## 4. Search for Duplicates
|
||||
|
||||
Search with multiple strategies, always using `--state all` (closed bugs regress):
|
||||
|
||||
```bash
|
||||
gh issue list --repo <repo> --state all --search "<symptom>"
|
||||
gh issue list --repo <repo> --state all --search "<component-name>"
|
||||
gh issue list --repo <repo> --state all --search "<error-message>"
|
||||
gh pr list --repo <repo> --state all --search "<keywords>"
|
||||
```
|
||||
|
||||
### Duplicate found → comment on existing issue
|
||||
|
||||
```bash
|
||||
gh issue comment <number> --repo <repo> --body "$(cat <<'EOF'
|
||||
## New Report
|
||||
**Reported by:** @<reporter> in [chat](<url>)
|
||||
**Date:** <YYYY-MM-DD> | **Checkout:** `<commit-hash>`
|
||||
<context, differences from original, screenshots>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
### No duplicate → file new issue (next section)
|
||||
|
||||
## 5. File New Issue
|
||||
|
||||
### 5a. Pre-submission checklist
|
||||
|
||||
- [ ] Reporter attribution correct (original reporter, not who tagged you)
|
||||
- [ ] Commit hash recorded
|
||||
- [ ] AO version recorded
|
||||
- [ ] Root cause confidence scored (see 5c)
|
||||
- [ ] Related issues cross-linked
|
||||
- [ ] Reproduction steps are concrete
|
||||
- [ ] Screenshots uploaded with real URLs (see 5b)
|
||||
|
||||
### 5b. Upload screenshots
|
||||
|
||||
**⛔ NEVER use placeholder URLs.** Upload BEFORE creating the issue. ([#1151](https://github.com/ComposioHQ/agent-orchestrator/issues/1151) RCA on this pattern.)
|
||||
|
||||
```bash
|
||||
SLUG="descriptive-slug"
|
||||
# Create asset branch
|
||||
gh api -X POST repos/<repo>/git/refs \
|
||||
-f ref="refs/heads/issue-assets-${SLUG}" \
|
||||
-f sha=$(git rev-parse origin/main)
|
||||
|
||||
# Upload (portable base64)
|
||||
IMG_B64=$(base64 < /path/to/screenshot.png | tr -d '\n')
|
||||
gh api -X PUT "repos/<repo>/contents/.issue-assets/${SLUG}/name.png" \
|
||||
-f message="chore: upload screenshot" \
|
||||
-f content="$IMG_B64" \
|
||||
-f branch="issue-assets-${SLUG}"
|
||||
# Use: 
|
||||
```
|
||||
|
||||
### 5c. Create the issue
|
||||
|
||||
```bash
|
||||
gh issue create --repo <repo> --title "<title>" --body "$(cat <<'EOF'
|
||||
## Bug
|
||||
<summary>
|
||||
|
||||
**Source:** <url> | **Reported by:** @<reporter> | **Analyzed against:** `<hash>`
|
||||
**Confidence:** High/Medium/Low
|
||||
|
||||
## Reproduction
|
||||
1. <step>
|
||||
|
||||
## Root Cause
|
||||
<file paths, line numbers, explanation>
|
||||
|
||||
## Fix
|
||||
<suggested approach>
|
||||
|
||||
## Impact
|
||||
- <effects>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
### 5d. Label and prioritize
|
||||
|
||||
```bash
|
||||
gh issue edit <number> --repo <repo> --add-label "bug"
|
||||
```
|
||||
|
||||
| Priority label | Criteria |
|
||||
|----------------|----------|
|
||||
| `priority: critical` | Data loss, security, system down |
|
||||
| `priority: high` | Core feature broken, no workaround |
|
||||
| `priority: medium` | Feature degraded, workaround exists |
|
||||
| `priority: low` | Cosmetic, edge case |
|
||||
|
||||
**Confidence scoring** (include in issue body):
|
||||
|
||||
| Level | Meaning | Extra labels |
|
||||
|-------|---------|-------------|
|
||||
| **High** | Traced exact code path, specific lines, mechanism explained | `bug` only |
|
||||
| **Medium** | Strong hypothesis but unconfirmed | `bug`, `to-explore` |
|
||||
| **Low** | Can't trace, multiple conflicting theories | `bug`, `to-reproduce` |
|
||||
|
||||
Example: [PR #1608](https://github.com/ComposioHQ/agent-orchestrator/pull/1608) was diagnosed High as xterm v6 issue — real cause was a `=` prefix on tmux `set-option`. Should have been Medium.
|
||||
|
||||
**All available labels:** `priority: critical/high/medium/low`, `bug`, `enhancement`, `good-first-issue`, `to-reproduce`, `to-explore`. No others (no `p0`, `p1`, etc.).
|
||||
|
||||
### 5e. Cross-link related issues
|
||||
|
||||
Search by subsystem and add a `## Related` section to the issue body:
|
||||
```
|
||||
## Related
|
||||
- [#1020](url) — stale session blocking ao start (same subsystem)
|
||||
- [#1035](url) — same race condition
|
||||
```
|
||||
|
||||
### 5f. Push a fix PR (always attempt)
|
||||
|
||||
- **Trivial fix:** Push immediately.
|
||||
- **Complex fix:** Note in issue, suggest spawning an agent.
|
||||
- **Unclear fix:** Don't push a guess. Document and flag.
|
||||
|
||||
```bash
|
||||
OLD_STRING='<old>' NEW_STRING='<new>' \
|
||||
python3 skills/bug-triage/scripts/push_fix_to_github.py \
|
||||
<owner/repo> fix/slug path/to/file.tsx \
|
||||
"fix(scope): commit msg" "fix(scope): PR title" \
|
||||
"Fixes #<n>
|
||||
|
||||
## Summary
|
||||
<what changed>
|
||||
|
||||
## Test
|
||||
<how to verify>"
|
||||
```
|
||||
|
||||
The script reads from GitHub API, applies one replacement, pushes, opens PR — no local checkout needed. **Verify `OLD_STRING` matches GitHub first:** `gh api repos/<repo>/contents/<path>?ref=main -q '.content' | python3 -c "import base64,sys; sys.stdout.buffer.write(base64.b64decode(sys.stdin.read()))"`
|
||||
|
||||
**Multiple edits to same file:** The push script does one replacement per run. For multiple changes, use a Python script to read from the branch (`gh api` + `base64.b64decode`), apply all replacements, then push via `gh api -X PUT` with the updated SHA.
|
||||
|
||||
### 5g. Report back
|
||||
|
||||
Issue URL, PR URL (if created), labels, root cause summary, whether fix agent was suggested.
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
|
||||
### A. Subsystem Quick Reference
|
||||
|
||||
| Subsystem | Collect | Key files |
|
||||
|-----------|---------|-----------|
|
||||
| **CLI** (`ao start/stop/spawn`) | Config YAML, install method, version, OS | `packages/cli/src/commands/` |
|
||||
| **Web UI** | Screenshot, browser, viewport | `packages/web/src/components/`, `globals.css` |
|
||||
| **Terminal** | Runtime type, tmux version, shell | `DirectTerminal.tsx`, `useXtermTerminal.ts` |
|
||||
| **Lifecycle** | State transitions, session IDs | `core/src/lifecycle-manager.ts`, `core/src/lifecycle-state.ts` |
|
||||
| **Sessions** | Session ID, spawn config, runtime | `core/src/session-manager.ts` |
|
||||
| **Plugins** | Plugin name, agent version | `packages/plugins/<agent>/` |
|
||||
| **Config** | YAML contents, project path | `packages/core/src/config.ts` |
|
||||
|
||||
**Misrouting patterns:**
|
||||
- Terminal bugs → tmux (runtime-tmux) vs xterm (web) vs PTY (runtime-process/Windows). Trace where bytes flow.
|
||||
- "Session stuck" → lifecycle state machine vs agent process vs runtime connection.
|
||||
- "Config not saving" → config loading (c12) vs project registration (running-state.ts) vs YAML write (permissions).
|
||||
|
||||
### B. Remote Code Inspection (no local clone)
|
||||
|
||||
```bash
|
||||
gh api repos/{owner}/{repo}/git/trees/main?recursive=1 --jq '.tree[].path' # list files
|
||||
gh api repos/{owner}/{repo}/contents/{path} --jq '.content' | python3 -c "import base64,sys; sys.stdout.buffer.write(base64.b64decode(sys.stdin.read()))" # read file
|
||||
gh search code "term" --repo {owner}/{repo} --json path --jq '.[].path' # search code
|
||||
gh api "repos/{owner}/{repo}/commits?path={path}&per_page=10" --jq '.[] | "\(.sha[0:8]) \(.commit.message | split("\n")[0])"' # file history
|
||||
```
|
||||
|
||||
### C. NPM Package Regression Diffing
|
||||
|
||||
Diff **published** packages (not local builds) when regression follows an upgrade:
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/ao-diff/{v1,v2}
|
||||
curl -sL https://registry.npmjs.org/@scope/pkg/-/pkg-OLD.tgz | tar xz -C /tmp/ao-diff/v1
|
||||
curl -sL https://registry.npmjs.org/@scope/pkg/-/pkg-NEW.tgz | tar xz -C /tmp/ao-diff/v2
|
||||
diff -rq /tmp/ao-diff/v1/package/ /tmp/ao-diff/v2/package/
|
||||
```
|
||||
|
||||
Example: [PR #1608](https://github.com/ComposioHQ/agent-orchestrator/pull/1608) — source analysis led to wrong theories, npm diff showed the only change was a `=` prefix on tmux `set-option`.
|
||||
|
||||
## Formatting Rules
|
||||
|
||||
- **Linkify all issue/PR refs:** `[#123](https://github.com/ComposioHQ/agent-orchestrator/issues/123)`, `[PR #456](url)`. Never bare `#123`.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- **Reporter ≠ person who tagged you.** Always attribute to the original reporter.
|
||||
- **Record the commit hash** you analyzed — code changes fast.
|
||||
- **GitHub issue is mandatory** — every triaged bug gets one, even if fix is trivial.
|
||||
- **`gh api --jq .content` truncates large files** (>~100KB). Use local git instead.
|
||||
- **Push script arg limits** — long commit messages hit `OSError: Argument list too long`. Use a Python script with JSON payloads instead.
|
||||
- **`OLD_STRING` must match GitHub byte-for-byte** — local code may differ from `origin/main`.
|
||||
- **New fields on shared TS interfaces MUST be optional** (`field?: Type`). Downstream `Partial<X>` spreads break on required fields. Example: [PR #1523](https://github.com/ComposioHQ/agent-orchestrator/pull/1523).
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Push a file fix to GitHub via API and create a PR.
|
||||
|
||||
Usage: python3 push_fix_to_github.py <repo> <branch-name> <file-path> <commit-message> <pr-title> <pr-body>
|
||||
|
||||
Reads the original file content from GitHub (default branch), applies a sed-like
|
||||
replacement using OLD_STRING / NEW_STRING env vars, and pushes via GitHub API.
|
||||
|
||||
Environment variables:
|
||||
OLD_STRING - The exact string to find in the file (required)
|
||||
NEW_STRING - The replacement string (set to empty string to delete) (required as env var)
|
||||
BASE_SHA - Override the base commit SHA (optional, defaults to default branch HEAD)
|
||||
BASE_BRANCH - Override the base branch name (optional, defaults to "main")
|
||||
|
||||
Example:
|
||||
OLD_STRING='<td className="foo">{bar}</td>' \
|
||||
NEW_STRING='<td className="foo"><a href="#">{bar}</a></td>' \
|
||||
python3 push_fix_to_github.py ComposioHQ/agent-orchestrator fix/branch packages/web/src/File.tsx \
|
||||
"fix: description" "fix: title" "Fixes #123"
|
||||
"""
|
||||
import sys, os, json, subprocess, base64
|
||||
|
||||
|
||||
def run_gh(args, check=True):
|
||||
"""Run a gh API command and return parsed JSON."""
|
||||
cmd = ["gh", "api"] + args
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
if check and result.returncode != 0:
|
||||
print(f"ERROR: gh api failed: {result.stderr}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
try:
|
||||
return json.loads(result.stdout) if result.stdout.strip() else {}
|
||||
except json.JSONDecodeError:
|
||||
if check:
|
||||
print(f"ERROR: Invalid JSON: {result.stdout[:300]}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return {}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 7:
|
||||
print("Usage: push_fix_to_github.py <repo> <branch> <file-path> <commit-msg> <pr-title> <pr-body>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
repo = sys.argv[1]
|
||||
branch = sys.argv[2]
|
||||
file_path = sys.argv[3]
|
||||
commit_msg = sys.argv[4]
|
||||
pr_title = sys.argv[5]
|
||||
pr_body = sys.argv[6]
|
||||
base_branch = os.environ.get("BASE_BRANCH", "main")
|
||||
|
||||
old_string = os.environ.get("OLD_STRING", "")
|
||||
new_string = os.environ.get("NEW_STRING")
|
||||
|
||||
if not old_string:
|
||||
print("ERROR: OLD_STRING env var is required", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if new_string is None:
|
||||
print("ERROR: NEW_STRING env var is required (set to empty string to delete)", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# 1. Get base HEAD SHA first
|
||||
base_sha = os.environ.get("BASE_SHA")
|
||||
if not base_sha:
|
||||
ref_data = run_gh([f"repos/{repo}/git/ref/heads/{base_branch}"])
|
||||
base_sha = ref_data["object"]["sha"]
|
||||
|
||||
# 2. Create branch from base SHA (before fetching file to avoid SHA race)
|
||||
print(f"Creating branch {branch} from {base_branch} ({base_sha[:8]})...")
|
||||
run_gh([
|
||||
"-X", "POST", f"repos/{repo}/git/refs",
|
||||
"-f", f"ref=refs/heads/{branch}",
|
||||
"-f", f"sha={base_sha}"
|
||||
], check=False)
|
||||
|
||||
# 3. Fetch file content from the new branch (avoids SHA mismatch)
|
||||
print(f"Fetching {file_path} from {repo} (branch: {branch})...")
|
||||
file_data = run_gh([f"repos/{repo}/contents/{file_path}?ref={branch}"])
|
||||
file_sha = file_data["sha"]
|
||||
decoded_content = base64.b64decode(file_data["content"]).decode("utf-8")
|
||||
|
||||
print(f"File SHA: {file_sha}")
|
||||
|
||||
# 4. Apply replacement
|
||||
if old_string not in decoded_content:
|
||||
print(f"ERROR: OLD_STRING not found in file!", file=sys.stderr)
|
||||
print(f"Looking for:\n{old_string}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
match_count = decoded_content.count(old_string)
|
||||
if match_count > 1:
|
||||
print(f"WARNING: OLD_STRING found {match_count} times — replacing only the first occurrence.", file=sys.stderr)
|
||||
|
||||
new_content = decoded_content.replace(old_string, new_string, 1)
|
||||
encoded = base64.b64encode(new_content.encode("utf-8")).decode("ascii")
|
||||
|
||||
# 5. Push file to branch
|
||||
print(f"Pushing updated file...")
|
||||
result = run_gh([
|
||||
"-X", "PUT", f"repos/{repo}/contents/{file_path}",
|
||||
"-f", f"message={commit_msg}",
|
||||
"-f", f"content={encoded}",
|
||||
"-f", f"sha={file_sha}",
|
||||
"-f", f"branch={branch}"
|
||||
])
|
||||
|
||||
# 6. Create PR
|
||||
print(f"Creating PR...")
|
||||
pr_result = run_gh([
|
||||
"-X", "POST", f"repos/{repo}/pulls",
|
||||
"-f", f"title={pr_title}",
|
||||
"-f", f"body={pr_body}",
|
||||
"-f", f"head={branch}",
|
||||
"-f", f"base={base_branch}"
|
||||
])
|
||||
|
||||
pr_url = pr_result.get("html_url", "unknown")
|
||||
pr_number = pr_result.get("number", "?")
|
||||
print(f"\n✅ PR #{pr_number}: {pr_url}")
|
||||
Loading…
Reference in New Issue