Skip to content

Commit e211aeb

Browse files
committed
feature-296-bugbot-autofix: Add Bugbot documentation and enhance integration with user request handling. Introduce new Bugbot section in the documentation, update existing references, and improve clarity on Bugbot functionalities. Update tests to ensure comprehensive coverage of new features and permission checks for user requests.
1 parent c6b4308 commit e211aeb

18 files changed

Lines changed: 725 additions & 25 deletions

File tree

.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`.

.cursor/rules/usecase-flows.mdc

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
description: Schematic overview of all use case flows (common_action → use case → steps)
3+
alwaysApply: false
4+
---
5+
6+
# Use case flows (schematic)
7+
8+
Entry point: `mainRun(execution)` in `src/actions/common_action.ts`. After `execution.setup()` and optionally `waitForPreviousRuns`, the dispatch is:
9+
10+
```
11+
mainRun
12+
├── runnedByToken && singleAction → SingleActionUseCase (only if validSingleAction)
13+
├── issueNumber === -1 → SingleActionUseCase (only if isSingleActionWithoutIssue) or skip
14+
├── welcome → log boxen and continue
15+
└── try:
16+
├── isSingleAction → SingleActionUseCase
17+
├── isIssue → issue.isIssueComment ? IssueCommentUseCase : IssueUseCase
18+
├── isPullRequest → pullRequest.isPullRequestReviewComment ? PullRequestReviewCommentUseCase : PullRequestUseCase
19+
├── isPush → CommitUseCase
20+
└── else → core.setFailed
21+
```
22+
23+
---
24+
25+
## 1. IssueUseCase (`on: issues`, not a comment)
26+
27+
**Step order:**
28+
29+
1. **CheckPermissionsUseCase** → if it fails (not allowed): CloseNotAllowedIssueUseCase and return.
30+
2. **RemoveIssueBranchesUseCase** (only if `cleanIssueBranches`).
31+
3. **AssignMemberToIssueUseCase**
32+
4. **UpdateTitleUseCase**
33+
5. **UpdateIssueTypeUseCase**
34+
6. **LinkIssueProjectUseCase**
35+
7. **CheckPriorityIssueSizeUseCase**
36+
8. **PrepareBranchesUseCase** (if `isBranched`) **or** **RemoveIssueBranchesUseCase** (if not).
37+
9. **RemoveNotNeededBranchesUseCase**
38+
10. **DeployAddedUseCase** (deploy label)
39+
11. **DeployedAddedUseCase** (deployed label)
40+
12. If **issue.opened**:
41+
- If not release and not question/help → **RecommendStepsUseCase**
42+
- If question or help → **AnswerIssueHelpUseCase**
43+
44+
---
45+
46+
## 2. IssueCommentUseCase (`on: issue_comment`)
47+
48+
**Step order:**
49+
50+
1. **CheckIssueCommentLanguageUseCase** (translation)
51+
2. **DetectBugbotFixIntentUseCase** → payload: `isFixRequest`, `isDoRequest`, `targetFindingIds`, `context`, `branchOverride`
52+
3. **ProjectRepository.isActorAllowedToModifyFiles(owner, actor, token)** (permission to modify files)
53+
4. Branch A – **if runAutofix && allowed**:
54+
- **BugbotAutofixUseCase** → **runBugbotAutofixCommitAndPush** → if committed: **markFindingsResolved**
55+
5. Branch B – **if !runAutofix && canRunDoUserRequest && allowed**:
56+
- **DoUserRequestUseCase** → **runUserRequestCommitAndPush**
57+
6. **If no file-modifying action ran** → **ThinkUseCase**
58+
59+
---
60+
61+
## 3. PullRequestReviewCommentUseCase (`on: pull_request_review_comment`)
62+
63+
Same flow as **IssueCommentUseCase**, with:
64+
65+
- CheckIssueCommentLanguageUseCase → **CheckPullRequestCommentLanguageUseCase**
66+
- User comment: `param.pullRequest.commentBody`
67+
- DetectBugbotFixIntentUseCase may use **parent comment** (commentInReplyToId) in the prompt.
68+
69+
---
70+
71+
## 4. PullRequestUseCase (`on: pull_request`, not a review comment)
72+
73+
**Branches by PR state:**
74+
75+
- **pullRequest.isOpened**:
76+
1. UpdateTitleUseCase
77+
2. AssignMemberToIssueUseCase
78+
3. AssignReviewersToIssueUseCase
79+
4. LinkPullRequestProjectUseCase
80+
5. LinkPullRequestIssueUseCase
81+
6. SyncSizeAndProgressLabelsFromIssueToPrUseCase
82+
7. CheckPriorityPullRequestSizeUseCase
83+
8. If AI PR description: **UpdatePullRequestDescriptionUseCase**
84+
85+
- **pullRequest.isSynchronize** (new pushes):
86+
- If AI PR description: **UpdatePullRequestDescriptionUseCase**
87+
88+
- **pullRequest.isClosed && isMerged**:
89+
- **CloseIssueAfterMergingUseCase**
90+
91+
---
92+
93+
## 5. CommitUseCase (`on: push`)
94+
95+
**Precondition:** `param.commit.commits.length > 0` (if 0, return with no steps).
96+
97+
**Order:**
98+
99+
1. **NotifyNewCommitOnIssueUseCase**
100+
2. **CheckChangesIssueSizeUseCase**
101+
3. **CheckProgressUseCase** (OpenCode: progress + size labels on issue and PRs)
102+
4. **DetectPotentialProblemsUseCase** (Bugbot: detection, publish to issue/PR, resolved markers)
103+
104+
---
105+
106+
## 6. SingleActionUseCase
107+
108+
Invoked when:
109+
- `runnedByToken && isSingleAction && validSingleAction`, or
110+
- `issueNumber === -1 && isSingleAction && isSingleActionWithoutIssue`, or
111+
- `isSingleAction` in the main try block.
112+
113+
**Dispatch by action (one per run):**
114+
115+
| Action | Use case |
116+
|--------|----------|
117+
| `deployed_action` | DeployedActionUseCase |
118+
| `publish_github_action` | PublishGithubActionUseCase |
119+
| `create_release` | CreateReleaseUseCase |
120+
| `create_tag` | CreateTagUseCase |
121+
| `think_action` | ThinkUseCase |
122+
| `initial_setup` | InitialSetupUseCase |
123+
| `check_progress_action` | CheckProgressUseCase |
124+
| `detect_potential_problems_action` | DetectPotentialProblemsUseCase |
125+
| `recommend_steps_action` | RecommendStepsUseCase |
126+
127+
(Action names in constants: check_progress_action, detect_potential_problems_action, recommend_steps_action.)
128+
129+
---
130+
131+
## 7. Summary by event
132+
133+
| Event | Use case | Schematic content |
134+
|--------|----------|------------------------|
135+
| **issues** (opened/edited/labeled…) | IssueUseCase | Permissions → close if not ok; branches; assign; title; issue type; project; priority/size; prepare/remove branches; deploy labels; if opened: recommend steps or answer help. |
136+
| **issue_comment** | IssueCommentUseCase | Language → intent (fix/do) → permission → [BugbotAutofix + commit + mark] or [DoUserRequest + commit] or Think. |
137+
| **pull_request** (opened/sync/closed) | PullRequestUseCase | Title, assign, reviewers, project, link issue, sync labels, size, [AI description]; if merged: close issue. |
138+
| **pull_request_review_comment** | PullRequestReviewCommentUseCase | Same as IssueCommentUseCase (language → intent → permission → autofix/do/Think). |
139+
| **push** | CommitUseCase | Notify commit → size → progress (OpenCode) → bugbot detect (OpenCode). |
140+
| **single-action** | SingleActionUseCase | One of: deployed, publish_github_action, create_release, create_tag, think, initial_setup, check_progress, detect_potential_problems, recommend_steps. |
141+
142+
---
143+
144+
## 8. Flow dependencies
145+
146+
- **Bugbot autofix / Do user request**: require OpenCode, `isActorAllowedToModifyFiles` (org member or repo owner), and on issue_comment optionally branch from PR (`getHeadBranchForIssue`).
147+
- **Think**: used in IssueComment and PullRequestReviewComment when neither autofix nor do user request runs (by intent or by permission).
148+
- **CommitUseCase**: NotifyNewCommitOnIssue, CheckChangesIssueSize, CheckProgress, DetectPotentialProblems (bugbot) always run in that order on every push with commits.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* Unit tests for ProjectRepository.isActorAllowedToModifyFiles: org member, user owner, 404/errors.
3+
*/
4+
export {};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* Unit tests for DoUserRequestUseCase: skip when no OpenCode/empty comment, copilotMessage call, success/failure.
3+
*/
4+
export {};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* Unit tests for ProjectRepository.isActorAllowedToModifyFiles: org member, user owner, 404/errors.
3+
*/
4+
export {};

build/github_action/src/data/repository/branch_repository.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export declare class BranchRepository {
3333
totalCommits: number;
3434
files: {
3535
filename: string;
36-
status: "added" | "removed" | "modified" | "renamed" | "copied" | "changed" | "unchanged";
36+
status: "modified" | "added" | "removed" | "renamed" | "copied" | "changed" | "unchanged";
3737
additions: number;
3838
deletions: number;
3939
changes: number;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* Unit tests for DoUserRequestUseCase: skip when no OpenCode/empty comment, copilotMessage call, success/failure.
3+
*/
4+
export {};

docs.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
"id": "single-action",
2222
"title": "Single Actions",
2323
"href": "/single-actions"
24+
},
25+
{
26+
"id": "bugbot",
27+
"title": "Bugbot",
28+
"href": "/bugbot"
2429
}
2530
],
2631
"sidebar": [
@@ -164,6 +169,17 @@
164169
}
165170
]
166171
},
172+
{
173+
"group": "Bugbot",
174+
"tab": "bugbot",
175+
"pages": [
176+
{
177+
"title": "Overview",
178+
"href": "/bugbot",
179+
"icon": "bug"
180+
}
181+
]
182+
},
167183
{
168184
"group": "Support",
169185
"pages": [

0 commit comments

Comments
 (0)