Skip to content

Commit 81ce5a6

Browse files
authored
Merge pull request #298 from vypdev/feature/296-bugbot-autofix
[#296] ✨ - Bugbot autofix
2 parents 391d4a8 + eb13c62 commit 81ce5a6

File tree

337 files changed

+17553
-1127
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+17553
-1127
lines changed

.cursor/rules/architecture.mdc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ alwaysApply: true
2424
| Shared flow | `src/actions/common_action.ts` | mainRun, waitForPreviousRuns, dispatch to use cases |
2525
| Use cases | `src/usecase/` | issue_use_case, pull_request_use_case, commit_use_case, single_action_use_case |
2626
| Single actions | `src/usecase/actions/` | check_progress, detect_errors, recommend_steps, think, initial_setup, create_release, create_tag, publish_github_action, deployed_action |
27-
| Steps (issue) | `src/usecase/steps/issue/` | check_permissions, close_not_allowed_issue, assign_members, update_title, update_issue_type, link_issue_project, check_priority_issue_size, prepare_branches, remove_issue_branches, remove_not_needed_branches, label_deploy_added, label_deployed_added, move_issue_to_in_progress |
27+
| Steps (issue) | `src/usecase/steps/issue/` | check_permissions, close_not_allowed_issue, assign_members, update_title, update_issue_type, link_issue_project, check_priority_issue_size, prepare_branches, remove_issue_branches, remove_not_needed_branches, label_deploy_added, label_deployed_added, move_issue_to_in_progress, answer_issue_help_use_case (question/help on open). On issue opened: RecommendStepsUseCase (non release/question/help) or AnswerIssueHelpUseCase (question/help). |
2828
| Steps (PR) | `src/usecase/steps/pull_request/` | update_title, assign_members (issue), assign_reviewers_to_issue, link_pr_project, link_pr_issue, sync_size_and_progress_from_issue, check_priority_pull_request_size, update_description (AI), close_issue_after_merging |
2929
| Steps (commit) | `src/usecase/steps/commit/` | notify commit, check size |
3030
| Steps (issue comment) | `src/usecase/steps/issue_comment/` | check_issue_comment_language (translation) |
3131
| Steps (PR review comment) | `src/usecase/steps/pull_request_review_comment/` | check_pull_request_comment_language (translation) |
32+
| Bugbot autofix & user request | `src/usecase/steps/commit/bugbot/` + `user_request_use_case.ts` | detect_bugbot_fix_intent_use_case (plan agent: is_fix_request, is_do_request, target_finding_ids), BugbotAutofixUseCase + runBugbotAutofixCommitAndPush (fix findings), DoUserRequestUseCase + runUserRequestCommitAndPush (generic “do this”). Permission: ProjectRepository.isActorAllowedToModifyFiles (org member or repo owner). |
3233
| Manager (content) | `src/manager/` | description handlers, configuration_handler, markdown_content_hotfix_handler (PR description, hotfix changelog content) |
3334
| Models | `src/data/model/` | Execution, Issue, PullRequest, SingleAction, etc. |
3435
| Repos | `src/data/repository/` | branch_repository, issue_repository, workflow_repository, ai_repository (OpenCode), file_repository, project_repository |
@@ -48,3 +49,22 @@ alwaysApply: true
4849
## Concurrency (sequential runs)
4950

5051
`common_action.ts` calls `waitForPreviousRuns(execution)` (from `src/utils/queue_utils.ts`): lists workflow runs, waits until no previous run of the **same workflow name** is in progress/queued, then continues. Implemented in `WorkflowRepository.getActivePreviousRuns`.
52+
53+
## Flow: issue comment & PR review comment (intent + permissions + actions)
54+
55+
When the event is **issue_comment** or **pull_request_review_comment**, `common_action.ts` invokes `IssueCommentUseCase` or `PullRequestReviewCommentUseCase` respectively. Both follow the same flow:
56+
57+
1. **Check language** (e.g. translation): `CheckIssueCommentLanguageUseCase` / `CheckPullRequestCommentLanguageUseCase`.
58+
2. **Detect intent** (OpenCode plan agent): `DetectBugbotFixIntentUseCase` runs and returns a payload with:
59+
- `isFixRequest`: user asked to fix one or more bugbot findings.
60+
- `isDoRequest`: user asked to perform some other change/task in the repo (generic “do this”).
61+
- `targetFindingIds`: when fix request, which finding ids to fix.
62+
- `context`, `branchOverride`: for autofix (e.g. branch from open PR when on issue comment).
63+
3. **Permission check**: `ProjectRepository.isActorAllowedToModifyFiles(owner, actor, token)`:
64+
- If repo **owner is an organization**: actor must be a **member** of that org.
65+
- If repo **owner is a user**: actor must be the **same** as the owner.
66+
- If not allowed and the intent was fix or do-request, we skip the file-modifying use cases and log; Think still runs so the user gets a response.
67+
4. **Run at most one file-modifying action** (only if allowed):
68+
- If **fix request** with targets and context: `BugbotAutofixUseCase` → `runBugbotAutofixCommitAndPush` → optionally `markFindingsResolved`.
69+
- Else if **do request** (and not fix): `DoUserRequestUseCase` → `runUserRequestCommitAndPush`.
70+
5. **Think**: If **no** file-modifying action ran (no intent, no permission, or no targets/context), we run `ThinkUseCase` so the user gets an AI reply (e.g. answer to a question).

.cursor/rules/bugbot.mdc

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
description: Detailed technical reference for Bugbot (detection, markers, context, intent, autofix, do user request, permissions)
3+
alwaysApply: false
4+
---
5+
6+
# Bugbot – technical reference
7+
8+
Bugbot has two main modes: **detection** (on push or single action) and **fix/do** (on issue comment or PR review comment). All Bugbot code lives under `src/usecase/steps/commit/bugbot/` and `src/usecase/steps/commit/` (DetectPotentialProblemsUseCase, user_request_use_case).
9+
10+
---
11+
12+
## 1. Detection flow (push or single action)
13+
14+
**Entry:** `CommitUseCase` (on push) calls `DetectPotentialProblemsUseCase`; or `SingleActionUseCase` when action is `detect_potential_problems_action`.
15+
16+
**Steps:**
17+
18+
1. **Guard:** OpenCode must be configured; `issueNumber !== -1`.
19+
2. **Load context:** `loadBugbotContext(param)` → issue comments + PR review comments parsed for markers; builds `existingByFindingId`, `issueComments`, `openPrNumbers`, `previousFindingsBlock`, `prContext`, `unresolvedFindingsWithBody`. Branch is `param.commit.branch` (or `options.branchOverride` when provided). PR context includes `prHeadSha`, `prFiles`, `pathToFirstDiffLine` for the first open PR.
20+
3. **Build prompt:** `buildBugbotPrompt(param, context)` – repo context, head/base branch, issue number, optional `ai-ignore-files`, and `previousFindingsBlock` (task 2: which previous findings are now resolved). OpenCode is asked to compute the diff itself and return `findings` + `resolved_finding_ids`.
21+
4. **Call OpenCode:** `askAgent(OPENCODE_AGENT_PLAN, prompt, BUGBOT_RESPONSE_SCHEMA)`.
22+
5. **Process response:** Filter findings: safe path (`isSafeFindingFilePath`), not in `ai-ignore-files` (`fileMatchesIgnorePatterns`), `meetsMinSeverity` (min from `bugbot-severity`), `deduplicateFindings`. Apply `applyCommentLimit(findings, bugbot-comment-limit)` → `toPublish`, `overflowCount`, `overflowTitles`.
23+
6. **Mark resolved:** `markFindingsResolved(execution, context, resolvedFindingIds, normalizedResolvedIds)` – for each existing finding in context whose id is in resolved set, update issue comment (and PR review comment if any) via `replaceMarkerInBody` to set `resolved:true`; if PR comment, call `resolveReviewThread` when applicable.
24+
7. **Publish:** `publishFindings(execution, context, toPublish, overflowCount?, overflowTitles?)` – for each finding: add or update **issue comment** (always); add or update **PR review comment** only when `finding.file` is in `prContext.prFiles` (using `pathToFirstDiffLine` when finding has no line). Each comment body is built with `buildCommentBody(finding, resolved)` and includes the **marker** `<!-- copilot-bugbot finding_id:"id" resolved:false -->`. Overflow: one extra issue comment summarizing excess findings.
25+
26+
**Key paths (detection):**
27+
28+
- `detect_potential_problems_use_case.ts` – orchestration
29+
- `load_bugbot_context_use_case.ts` – issue/PR comments, markers, previousFindingsBlock, prContext
30+
- `build_bugbot_prompt.ts` – prompt for plan agent (task 1: new findings, task 2: resolved ids)
31+
- `schema.ts` – BUGBOT_RESPONSE_SCHEMA (findings, resolved_finding_ids)
32+
- `marker.ts` – BUGBOT_MARKER_PREFIX, buildMarker, parseMarker, replaceMarkerInBody, extractTitleFromBody, buildCommentBody
33+
- `publish_findings_use_case.ts` – add/update issue comment, create/update PR review comment
34+
- `mark_findings_resolved_use_case.ts` – update comment body with resolved marker, resolve PR thread
35+
- `severity.ts`, `file_ignore.ts`, `path_validation.ts`, `limit_comments.ts`, `deduplicate_findings.ts`
36+
37+
---
38+
39+
## 2. Marker format and context
40+
41+
**Marker:** Hidden HTML comment in every finding comment (issue and PR):
42+
43+
`<!-- copilot-bugbot finding_id:"<id>" resolved:true|false -->`
44+
45+
- **Parse:** `parseMarker(body)` returns `{ findingId, resolved }[]`. Used when loading context from issue comments and PR review comments.
46+
- **Build:** `buildMarker(findingId, resolved)`. IDs are sanitized (`sanitizeFindingIdForMarker`) so they cannot break HTML (no `-->`, `<`, `>`, newlines, etc.).
47+
- **Update:** `replaceMarkerInBody(body, findingId, newResolved)` – used when marking a finding as resolved (same comment, body updated with `resolved:true`).
48+
49+
**Context (`BugbotContext`):**
50+
51+
- `existingByFindingId[id]`: `{ issueCommentId?, prCommentId?, prNumber?, resolved }` – from parsing all issue + PR comments for markers.
52+
- `issueComments`: raw list from API (for body when building previousFindingsBlock / unresolvedFindingsWithBody).
53+
- `openPrNumbers`, `previousFindingsBlock`, `prContext` (prHeadSha, prFiles, pathToFirstDiffLine), `unresolvedFindingsWithBody`: `{ id, fullBody }[]` for findings that are not resolved (body truncated to MAX_FINDING_BODY_LENGTH when loading).
54+
55+
---
56+
57+
## 3. Fix intent and file-modifying actions (issue comment / PR review comment)
58+
59+
**Entry:** `IssueCommentUseCase` or `PullRequestReviewCommentUseCase` (after language check).
60+
61+
**Steps:**
62+
63+
1. **Intent:** `DetectBugbotFixIntentUseCase.invoke(param)`
64+
- Guards: OpenCode configured, issue number set, comment body non-empty, branch (or branchOverride from `getHeadBranchForIssue` when commit.branch empty).
65+
- `loadBugbotContext(param, { branchOverride })` → unresolved findings.
66+
- Build `UnresolvedFindingSummary[]` (id, title from `extractTitleFromBody`, description = fullBody.slice(0, 4000)).
67+
- If PR review comment and `commentInReplyToId`: fetch parent comment body (`getPullRequestReviewCommentBody`), slice(0,1500).trim for prompt.
68+
- `buildBugbotFixIntentPrompt(commentBody, unresolvedFindings, parentCommentBody?)` → prompt asks: is_fix_request?, target_finding_ids?, is_do_request?
69+
- `askAgent(OPENCODE_AGENT_PLAN, prompt, BUGBOT_FIX_INTENT_RESPONSE_SCHEMA)` → `{ is_fix_request, target_finding_ids, is_do_request }`.
70+
- Payload: `isFixRequest`, `isDoRequest`, `targetFindingIds` (filtered to valid unresolved ids), `context`, `branchOverride`.
71+
72+
2. **Permission:** `ProjectRepository.isActorAllowedToModifyFiles(owner, actor, token)`.
73+
- If owner is Organization: `orgs.checkMembershipForUser` (204 = allowed).
74+
- If owner is User: allowed only if `actor === owner`.
75+
76+
3. **Branch A – Bugbot autofix** (when `canRunBugbotAutofix(payload)` and `allowedToModifyFiles`):
77+
- `BugbotAutofixUseCase.invoke({ execution, targetFindingIds, userComment, context, branchOverride })`
78+
- Load context if not provided; filter targets to valid unresolved ids; `buildBugbotFixPrompt(...)` with repo, findings block (truncated fullBody per finding), user comment, verify commands; `copilotMessage(ai, prompt)` (build agent).
79+
- If success: `runBugbotAutofixCommitAndPush(execution, { branchOverride, targetFindingIds })` – optional checkout if branchOverride, run verify commands (from `getBugbotFixVerifyCommands`, max 20), git add/commit/push (message `fix(#N): bugbot autofix - resolve ...`).
80+
- If committed and context: `markFindingsResolved({ execution, context, resolvedFindingIds, normalizedResolvedIds })`.
81+
82+
4. **Branch B – Do user request** (when `!runAutofix && canRunDoUserRequest(payload)` and `allowedToModifyFiles`):
83+
- `DoUserRequestUseCase.invoke({ execution, userComment, branchOverride })`
84+
- `buildUserRequestPrompt(execution, userComment)` – repo context + sanitized user request; `copilotMessage(ai, prompt)`.
85+
- If success: `runUserRequestCommitAndPush(execution, { branchOverride })` – same verify/checkout/add/commit/push with message `chore(#N): apply user request` or `chore: apply user request`.
86+
87+
5. **Think** (when no file-modifying action ran): `ThinkUseCase.invoke(param)` – answers the user (e.g. question).
88+
89+
**Key paths (fix/do):**
90+
91+
- `detect_bugbot_fix_intent_use_case.ts` – intent detection, branch resolution for issue_comment
92+
- `build_bugbot_fix_intent_prompt.ts` – prompt for is_fix_request / is_do_request / target_finding_ids
93+
- `bugbot_fix_intent_payload.ts` – getBugbotFixIntentPayload, canRunBugbotAutofix, canRunDoUserRequest
94+
- `schema.ts` – BUGBOT_FIX_INTENT_RESPONSE_SCHEMA (is_fix_request, target_finding_ids, is_do_request)
95+
- `bugbot_autofix_use_case.ts` – build prompt, copilotMessage (build agent)
96+
- `build_bugbot_fix_prompt.ts` – fix prompt (findings block, verify commands, truncate finding body to MAX_FINDING_BODY_LENGTH)
97+
- `bugbot_autofix_commit.ts` – runBugbotAutofixCommitAndPush, runUserRequestCommitAndPush (checkout, verify commands max 20, git config, add, commit, push)
98+
- `user_request_use_case.ts` – DoUserRequestUseCase, buildUserRequestPrompt
99+
- `mark_findings_resolved_use_case.ts` – update issue/PR comment with resolved marker
100+
- `project_repository.ts` – isActorAllowedToModifyFiles
101+
102+
---
103+
104+
## 4. Configuration (inputs / Ai model)
105+
106+
- **bugbot-severity:** Minimum severity to publish (info, low, medium, high). Default low. `getBugbotMinSeverity()`, `normalizeMinSeverity`, `meetsMinSeverity`.
107+
- **bugbot-comment-limit:** Max individual finding comments per issue/PR (overflow gets one summary). Default 20. `getBugbotCommentLimit()`, `applyCommentLimit`.
108+
- **bugbot-fix-verify-commands:** Comma-separated commands run after autofix (and do user request) before commit. `getBugbotFixVerifyCommands()`, parsed with shell-quote; max 20 executed. Stored in `Ai` model; read in `github_action.ts` / `local_action.ts`.
109+
- **ai-ignore-files:** Exclude paths from detection (and from reporting). Used in buildBugbotPrompt and in filtering findings.
110+
111+
---
112+
113+
## 5. Constants and types
114+
115+
- `BUGBOT_MARKER_PREFIX`: `'copilot-bugbot'`
116+
- `BUGBOT_MAX_COMMENTS`: 20 (default limit)
117+
- `MAX_FINDING_BODY_LENGTH`: 12000 (truncation when loading context and in build_bugbot_fix_prompt)
118+
- `MAX_VERIFY_COMMANDS`: 20 (in bugbot_autofix_commit)
119+
- Types: `BugbotContext`, `BugbotFinding` (id, title, description, file?, line?, severity?, suggestion?), `UnresolvedFindingSummary`, `BugbotFixIntentPayload`.
120+
121+
---
122+
123+
## 6. Sanitization and safety
124+
125+
- **User comment in prompts:** `sanitizeUserCommentForPrompt(raw)` – trim, escape backslashes, replace `"""`, truncate 4000 with no lone trailing backslash.
126+
- **Finding body in prompts:** `truncateFindingBody(body, MAX_FINDING_BODY_LENGTH)` with suffix `[... truncated for length ...]` (used in load_bugbot_context and build_bugbot_fix_prompt).
127+
- **Verify commands:** Parsed with shell-quote; no shell operators (;, |, etc.); max 20 run.
128+
- **Path:** `isSafeFindingFilePath` (no null byte, no `..`, no absolute); PR review comment only if file in `prFiles`.

0 commit comments

Comments
 (0)