limn-review 0.1.182 → 0.1.183
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db/teammate-reviews.js +11 -0
- package/dist/review/claude-review/routes.js +16 -0
- package/dist/review/claude-review/team-view.js +50 -4
- package/dist/review/claude-review/teammate-reminder.js +135 -0
- package/dist/shared/limn-review-meta.js +52 -0
- package/package.json +1 -1
- package/public/assets/{AiFixTab-Bhq_0mmG.js → AiFixTab-DwjVZ3Od.js} +1 -1
- package/public/assets/ClaudeReviewTab-CMCKluXj.js +22 -0
- package/public/assets/{PrBotBehaviourTab-oOBsdGPH.js → PrBotBehaviourTab-3mieFdQL.js} +1 -1
- package/public/assets/{index-BTsR634o.js → index-DnvzZnsD.js} +28 -28
- package/public/index.html +1 -1
- package/public/assets/ClaudeReviewTab-BVlkGiBL.js +0 -20
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// TEAMMATES' POSTED REVIEWS — THE READ SIDE (docs/CLAUDE-REVIEW.md § Teammates' reviews). The import
|
|
2
2
|
// is db/teammate-reviews-import.ts. ⚠ This module opens NO database at import (every reader takes an
|
|
3
3
|
// executor): review modules and their fake-context tests import it.
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
4
5
|
import { and, asc, desc, eq, inArray, isNull, ne, or, sql } from 'drizzle-orm';
|
|
5
6
|
import * as schema from './schema.sqlite.js';
|
|
6
7
|
const { users, reviewComments, commits, pullRequests, repos } = schema;
|
|
@@ -67,6 +68,9 @@ export async function listTeammateReviews(exec, accountId, prId) {
|
|
|
67
68
|
kind: crf.postedCommentKind,
|
|
68
69
|
githubCommentId: crf.githubCommentId,
|
|
69
70
|
nodeId: crf.sourceCommentNodeId,
|
|
71
|
+
postedAt: crf.postedAt,
|
|
72
|
+
side: crf.side,
|
|
73
|
+
reminder: crf.reminder,
|
|
70
74
|
})
|
|
71
75
|
.from(crf)
|
|
72
76
|
.where(inArray(crf.reviewId, rows.map((r) => r.id)))
|
|
@@ -114,6 +118,13 @@ export async function listTeammateReviews(exec, accountId, prId) {
|
|
|
114
118
|
threadId: kind === 'inline' && f.nodeId != null ? (threadOf.get(f.nodeId) ?? null) : null,
|
|
115
119
|
...providersOf(f.nodeId),
|
|
116
120
|
githubCommentId: f.githubCommentId ?? null,
|
|
121
|
+
postedAt: f.postedAt != null ? f.postedAt.toISOString() : null,
|
|
122
|
+
side: f.side === 'LEFT' ? 'LEFT' : 'RIGHT',
|
|
123
|
+
diffAnchorId: createHash('sha256').update(f.path, 'utf8').digest('hex'),
|
|
124
|
+
// The reader's reminder (stored beside the finding, never its own post); wire shape only.
|
|
125
|
+
reminder: f.reminder == null
|
|
126
|
+
? null
|
|
127
|
+
: { githubCommentId: f.reminder.githubCommentId, postedCommentKind: f.reminder.postedCommentKind, postedAt: f.reminder.postedAt },
|
|
117
128
|
};
|
|
118
129
|
});
|
|
119
130
|
const at = r.postedAt ?? r.createdAt;
|
|
@@ -586,6 +586,22 @@ export function registerClaudeReviewRoutes(app, ctx) {
|
|
|
586
586
|
const accountId = ctx.accountIdOf(req);
|
|
587
587
|
const fctx = await getFindingPostContext(ctx, findingId, accountId);
|
|
588
588
|
if (!fctx) {
|
|
589
|
+
// A TEAMMATE'S finding takes ONE action here, "Post reminder" (teammate-reminder.ts): posted as
|
|
590
|
+
// the reader, linking the teammate's comment. A plain Post of it stays 404 (it is theirs).
|
|
591
|
+
if (req.body?.reminder === true) {
|
|
592
|
+
const { postTeammateReminder } = await import('./teammate-reminder.js');
|
|
593
|
+
const out = await postTeammateReminder(ctx, accountId, findingId);
|
|
594
|
+
if (out.kind === 'posted')
|
|
595
|
+
return out.result;
|
|
596
|
+
if (out.kind === 'conflict') {
|
|
597
|
+
reply.status(409);
|
|
598
|
+
return { error: out.code, message: out.message };
|
|
599
|
+
}
|
|
600
|
+
if (out.kind === 'github_error') {
|
|
601
|
+
reply.status(502);
|
|
602
|
+
return { error: 'GitHubError', message: out.message };
|
|
603
|
+
}
|
|
604
|
+
}
|
|
589
605
|
reply.status(404);
|
|
590
606
|
return { error: 'NotFound', message: `Finding ${findingId} not found` };
|
|
591
607
|
}
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
// tab, the PR overview and the review count read the result (`ClaudeReviewResponse.teamView`).
|
|
14
14
|
// ⚠ Own-only readers (caps, budget, posting, follow-up) never read this: it is a view.
|
|
15
15
|
// This module opens NO database at import (the loader takes an executor).
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
16
17
|
import { and, eq, inArray, isNull, sql } from 'drizzle-orm';
|
|
17
|
-
import { aiRunProvider } from '../../shared/index.js';
|
|
18
|
+
import { aiRunProvider, postedFindingDisplay } from '../../shared/index.js';
|
|
18
19
|
import * as schema from '../../db/schema.sqlite.js';
|
|
19
20
|
import { ownRunsOnly } from '../../db/teammate-reviews.js';
|
|
20
21
|
import { similarTitles } from './settled-by-reply.js';
|
|
@@ -263,6 +264,10 @@ export async function loadTeamReviewView(exec, accountId, prId, own, teammateRev
|
|
|
263
264
|
kind: crf.postedCommentKind,
|
|
264
265
|
mergedInto: crf.mergedInto,
|
|
265
266
|
storyIndex: crf.storyIndex,
|
|
267
|
+
side: crf.side,
|
|
268
|
+
suggestion: crf.suggestion,
|
|
269
|
+
postedAuto: crf.postedAuto,
|
|
270
|
+
reminder: crf.reminder,
|
|
266
271
|
})
|
|
267
272
|
.from(crf)
|
|
268
273
|
.where(inArray(crf.reviewId, [...runOf.keys()]))
|
|
@@ -308,6 +313,12 @@ export async function loadTeamReviewView(exec, accountId, prId, own, teammateRev
|
|
|
308
313
|
? `${prUrl}#discussion_r${f.githubCommentId}`
|
|
309
314
|
: `${prUrl}#issuecomment-${f.githubCommentId}`,
|
|
310
315
|
threadId: inline && f.githubCommentId != null ? (threadOfComment.get(f.githubCommentId) ?? null) : null,
|
|
316
|
+
side: f.side === 'LEFT' ? 'LEFT' : 'RIGHT',
|
|
317
|
+
suggestion: f.suggestion ?? null,
|
|
318
|
+
postedAt: f.postedAt != null ? f.postedAt.getTime() : null,
|
|
319
|
+
postedCommentKind: f.kind ?? null,
|
|
320
|
+
postedAuto: f.postedAuto === true,
|
|
321
|
+
reminder: f.reminder ?? null,
|
|
311
322
|
};
|
|
312
323
|
});
|
|
313
324
|
const judgements = reviewed
|
|
@@ -726,6 +737,14 @@ export function foldAllTeamFindings(input) {
|
|
|
726
737
|
ignored: postedOne == null && list.every((m) => m.ignored),
|
|
727
738
|
state: stateOf(members, shown.at),
|
|
728
739
|
alsoRaisedBy: [],
|
|
740
|
+
side: shown.side ?? 'RIGHT',
|
|
741
|
+
diffAnchorId: diffAnchorIdOf(shown.path),
|
|
742
|
+
suggestion: shown.suggestion ?? null,
|
|
743
|
+
postedAt: postedOne?.postedAt != null ? new Date(postedOne.postedAt).toISOString() : null,
|
|
744
|
+
githubCommentId: postedOne?.githubCommentId ?? null,
|
|
745
|
+
postedCommentKind: postedOne?.postedCommentKind ?? null,
|
|
746
|
+
postedAuto: postedOne?.postedAuto === true,
|
|
747
|
+
reminder: wireReminder(shown.reminder ?? postedOne?.reminder ?? null),
|
|
729
748
|
},
|
|
730
749
|
spot: shown,
|
|
731
750
|
mateRoot: mateRootOf(shown.id),
|
|
@@ -749,6 +768,8 @@ export function foldAllTeamFindings(input) {
|
|
|
749
768
|
twin.point.alsoRaisedBy.push({ ...author, findingId: f.id, reviewId: r.reviewId, providers });
|
|
750
769
|
continue;
|
|
751
770
|
}
|
|
771
|
+
// Limn posts a finding's text, never its title: split it the way the reader's own card shows one.
|
|
772
|
+
const shown = postedFindingDisplay(f.body, f.title);
|
|
752
773
|
entries.push({
|
|
753
774
|
point: {
|
|
754
775
|
findingId: f.id,
|
|
@@ -759,8 +780,8 @@ export function foldAllTeamFindings(input) {
|
|
|
759
780
|
path: f.path,
|
|
760
781
|
line: f.line,
|
|
761
782
|
severity: f.severity,
|
|
762
|
-
title:
|
|
763
|
-
body:
|
|
783
|
+
title: shown.title,
|
|
784
|
+
body: shown.body,
|
|
764
785
|
raisedAt: r.postedAt,
|
|
765
786
|
headSha: r.headSha,
|
|
766
787
|
githubUrl: f.githubUrl,
|
|
@@ -773,6 +794,14 @@ export function foldAllTeamFindings(input) {
|
|
|
773
794
|
...input.own.filter((o) => mateRootOf(o.id) === f.id).map((o) => ({ id: o.id, commentId: null, threadId: null, at: o.at })),
|
|
774
795
|
], ms(r.postedAt)),
|
|
775
796
|
alsoRaisedBy: [],
|
|
797
|
+
side: f.side ?? 'RIGHT',
|
|
798
|
+
diffAnchorId: f.diffAnchorId ?? diffAnchorIdOf(f.path),
|
|
799
|
+
suggestion: shown.suggestion,
|
|
800
|
+
postedAt: f.postedAt ?? r.postedAt,
|
|
801
|
+
githubCommentId: f.githubCommentId ?? null,
|
|
802
|
+
postedCommentKind: f.kind,
|
|
803
|
+
postedAuto: false,
|
|
804
|
+
reminder: wireReminder(f.reminder ?? null),
|
|
776
805
|
},
|
|
777
806
|
spot: f,
|
|
778
807
|
mateRoot: f.id,
|
|
@@ -784,6 +813,23 @@ export function foldAllTeamFindings(input) {
|
|
|
784
813
|
const rank = (p) => (p.state.kind === 'open' ? 0 : 1);
|
|
785
814
|
return entries
|
|
786
815
|
.sort((a, b) => rank(a.point) - rank(b.point) || b.first - a.first || a.point.findingId - b.point.findingId)
|
|
787
|
-
.map((e) => e.point);
|
|
816
|
+
.map((e) => ({ ...e.point, remindable: teammatePointRemindable(e.point) }));
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* A TEAMMATE'S POINT THE READER MAY REMIND (docs/CLAUDE-REVIEW.md § Teammates' reviews → A reminder of a
|
|
820
|
+
* teammate's finding): the teammate raised it (the point is theirs, not folded under the reader's own
|
|
821
|
+
* card), it is still OPEN, and its comment is on GitHub (an id to link). The SPA's button and the
|
|
822
|
+
* route's check read this ONE rule.
|
|
823
|
+
*/
|
|
824
|
+
export function teammatePointRemindable(p) {
|
|
825
|
+
return p.origin === 'teammate' && p.state.kind === 'open' && p.githubCommentId != null;
|
|
826
|
+
}
|
|
827
|
+
/** GitHub's "Files changed" anchor of a path (SHA-256, hex) — the reader's own findings use the same. */
|
|
828
|
+
function diffAnchorIdOf(path) {
|
|
829
|
+
return createHash('sha256').update(path).digest('hex');
|
|
830
|
+
}
|
|
831
|
+
/** A stored reminder on the wire (its earlier comment ids stay server-side). */
|
|
832
|
+
function wireReminder(r) {
|
|
833
|
+
return r == null ? null : { githubCommentId: r.githubCommentId, postedCommentKind: r.postedCommentKind, postedAt: r.postedAt };
|
|
788
834
|
}
|
|
789
835
|
//# sourceMappingURL=team-view.js.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// A REMINDER OF A TEAMMATE'S FINDING (docs/CLAUDE-REVIEW.md § Teammates' reviews → A reminder of a
|
|
2
|
+
// teammate's finding). "Post reminder" on a teammate's open point posts the point again AS THE READER:
|
|
3
|
+
// a new comment of the reader's own Limn (the finding marker, so `isLimnPostedComment` holds), led by
|
|
4
|
+
// the same reminder line as the reader's own reminders (`reminderLead`), linking the teammate's
|
|
5
|
+
// original comment. It never edits, replies to or resolves the teammate's comment or thread.
|
|
6
|
+
//
|
|
7
|
+
// ⚠ ONE RULE decides what may be reminded: `teamPointRemindable` (team-view.ts) on the SAME fold the
|
|
8
|
+
// tab shows (`loadTeamReviewView`) — a teammate's point, still OPEN, with its comment on GitHub. A
|
|
9
|
+
// foreign, unknown, closed or own finding answers not_found / conflict and nothing is written.
|
|
10
|
+
// ⚠ Recorded like the reader's own reminder (`markFindingReminder` on the teammate's finding row:
|
|
11
|
+
// display + dedupe only — posted-state.ts counts its comment as claimed). The import never touches
|
|
12
|
+
// the column, so it survives every later walk.
|
|
13
|
+
import { and, eq } from 'drizzle-orm';
|
|
14
|
+
import { splitTrailingSuggestion } from '../../shared/index.js';
|
|
15
|
+
import { TEAMMATE_KIND, listTeammateReviews } from '../../db/teammate-reviews.js';
|
|
16
|
+
import { getLatestClaudeReview, markFindingReminder } from './persist.js';
|
|
17
|
+
import { findingCommentUrl, reminderLead } from './posted-state.js';
|
|
18
|
+
import { loadTeamReviewView, teammatePointRemindable } from './team-view.js';
|
|
19
|
+
import { tabThreadView } from './thread-judgements.js';
|
|
20
|
+
/** Is this finding id a TEAMMATE's imported finding of this account? (null = no: the caller 404s.) */
|
|
21
|
+
export async function teammateFindingPr(ctx, accountId, findingId) {
|
|
22
|
+
const { claudeReviews: cr, claudeReviewFindings: crf } = ctx.schema; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const row = (await ctx.db
|
|
24
|
+
.select({ prId: cr.prId })
|
|
25
|
+
.from(crf)
|
|
26
|
+
.innerJoin(cr, eq(cr.id, crf.reviewId))
|
|
27
|
+
.where(and(eq(crf.id, findingId), eq(cr.accountId, accountId), eq(cr.kind, TEAMMATE_KIND)))
|
|
28
|
+
.limit(1)
|
|
29
|
+
.execute())[0];
|
|
30
|
+
return row ?? null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Post a reminder of a teammate's finding as the reader. DB reads first (the fold), then ONE GitHub
|
|
34
|
+
* write through the same seam the reader's own reminders use (`ctx.review.postFinding`).
|
|
35
|
+
*/
|
|
36
|
+
export async function postTeammateReminder(ctx, accountId, findingId) {
|
|
37
|
+
const owner = await teammateFindingPr(ctx, accountId, findingId);
|
|
38
|
+
if (owner == null)
|
|
39
|
+
return { kind: 'not_found' };
|
|
40
|
+
const prId = owner.prId;
|
|
41
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
42
|
+
const { claudeReviewFindings: crf, reviewComments: rc, reviewThreads: rt, pullRequests: prs, repos } = ctx.schema;
|
|
43
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
44
|
+
// THE SAME FOLD THE TAB SHOWS: the point must be this teammate finding's, and still open.
|
|
45
|
+
const [latest, threads, mates] = await Promise.all([
|
|
46
|
+
getLatestClaudeReview(ctx, prId, accountId),
|
|
47
|
+
tabThreadView(ctx, accountId, prId),
|
|
48
|
+
listTeammateReviews(ctx.db, accountId, prId),
|
|
49
|
+
]);
|
|
50
|
+
const view = await loadTeamReviewView(ctx.db, accountId, prId, latest, mates, threads.team);
|
|
51
|
+
const point = (view.allFindings ?? []).find((p) => p.findingId === findingId);
|
|
52
|
+
if (point == null) {
|
|
53
|
+
// Folded under another entry (the reader's own re-raise, or another teammate's): that entry's
|
|
54
|
+
// card carries the action, never this one.
|
|
55
|
+
return { kind: 'conflict', code: 'NotOpen', message: 'This point is shown under another finding. Post the reminder from there.' };
|
|
56
|
+
}
|
|
57
|
+
if (point.githubCommentId == null) {
|
|
58
|
+
return { kind: 'conflict', code: 'NotOnGithub', message: 'The original comment is not synced yet. Try again in a moment.' };
|
|
59
|
+
}
|
|
60
|
+
if (!teammatePointRemindable(point)) {
|
|
61
|
+
return { kind: 'conflict', code: 'NotOpen', message: 'This point is resolved or addressed.' };
|
|
62
|
+
}
|
|
63
|
+
// What to post: the teammate's stored text (lead, notes and marker already stripped at import).
|
|
64
|
+
const f = (await ctx.db
|
|
65
|
+
.select({ path: crf.path, line: crf.line, side: crf.side, body: crf.body, nodeId: crf.sourceCommentNodeId, kind: crf.postedCommentKind, postedAt: crf.postedAt })
|
|
66
|
+
.from(crf)
|
|
67
|
+
.where(eq(crf.id, findingId))
|
|
68
|
+
.limit(1)
|
|
69
|
+
.execute())[0];
|
|
70
|
+
const pr = (await ctx.db
|
|
71
|
+
.select({ owner: repos.owner, name: repos.name, number: prs.number, headSha: prs.headSha })
|
|
72
|
+
.from(prs)
|
|
73
|
+
.innerJoin(repos, eq(repos.id, prs.repoId))
|
|
74
|
+
.where(and(eq(prs.id, prId), eq(repos.accountId, accountId)))
|
|
75
|
+
.limit(1)
|
|
76
|
+
.execute())[0];
|
|
77
|
+
if (f == null || pr == null)
|
|
78
|
+
return { kind: 'not_found' };
|
|
79
|
+
if (pr.headSha == null) {
|
|
80
|
+
return { kind: 'conflict', code: 'HeadMoved', message: 'The PR is not synced yet. Try again in a moment.' };
|
|
81
|
+
}
|
|
82
|
+
// WHERE: inline on the line the teammate's thread sits on NOW (GitHub's current line at the synced
|
|
83
|
+
// head), else a PR-level comment naming the file. The teammate's review head may be older than the
|
|
84
|
+
// PR's: their line is not reused unless GitHub still shows the thread on the current diff.
|
|
85
|
+
const thread = f.kind === 'inline' && f.nodeId != null
|
|
86
|
+
? (await ctx.db
|
|
87
|
+
.select({ line: rt.line, isOutdated: rt.isOutdated })
|
|
88
|
+
.from(rc)
|
|
89
|
+
.innerJoin(rt, eq(rt.id, rc.threadId))
|
|
90
|
+
.where(and(eq(rc.prId, prId), eq(rc.githubNodeId, f.nodeId)))
|
|
91
|
+
.limit(1)
|
|
92
|
+
.execute())[0] ?? null
|
|
93
|
+
: null;
|
|
94
|
+
const inlineLine = thread != null && !thread.isOutdated && thread.line != null ? thread.line : null;
|
|
95
|
+
const { text, suggestion } = splitTrailingSuggestion(f.body);
|
|
96
|
+
const lead = reminderLead({
|
|
97
|
+
url: findingCommentUrl({ owner: pr.owner, name: pr.name, prNumber: pr.number }, {
|
|
98
|
+
githubCommentId: point.githubCommentId,
|
|
99
|
+
postedCommentKind: point.postedCommentKind ?? (f.kind === 'pr_comment' ? 'pr_comment' : 'inline'),
|
|
100
|
+
}),
|
|
101
|
+
postedAt: point.postedAt ?? (f.postedAt != null ? f.postedAt.toISOString() : null),
|
|
102
|
+
});
|
|
103
|
+
const severity = point.severity;
|
|
104
|
+
try {
|
|
105
|
+
const outcome = await ctx.review.postFinding({
|
|
106
|
+
owner: pr.owner,
|
|
107
|
+
name: pr.name,
|
|
108
|
+
prNumber: pr.number,
|
|
109
|
+
// The synced head: the seam refuses when the live head moved past it (`headMoved`).
|
|
110
|
+
reviewHeadSha: pr.headSha,
|
|
111
|
+
finding: {
|
|
112
|
+
id: findingId,
|
|
113
|
+
path: f.path,
|
|
114
|
+
line: inlineLine ?? f.line,
|
|
115
|
+
side: f.side === 'LEFT' ? 'LEFT' : 'RIGHT',
|
|
116
|
+
anchored: inlineLine != null,
|
|
117
|
+
fileInDiff: inlineLine != null,
|
|
118
|
+
body: text,
|
|
119
|
+
suggestion,
|
|
120
|
+
severity,
|
|
121
|
+
storyLead: lead,
|
|
122
|
+
},
|
|
123
|
+
...(inlineLine == null ? { prLevel: true } : {}),
|
|
124
|
+
});
|
|
125
|
+
if (outcome.headMoved) {
|
|
126
|
+
return { kind: 'conflict', code: 'HeadMoved', message: 'The PR has new commits that are not synced yet. Try again in a moment.' };
|
|
127
|
+
}
|
|
128
|
+
const r = await markFindingReminder(ctx, findingId, outcome.commentId, outcome.postedCommentKind);
|
|
129
|
+
return { kind: 'posted', result: { githubCommentId: outcome.commentId, postedAt: r.postedAt, reminder: true } };
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return { kind: 'github_error', message: err instanceof Error ? err.message : String(err) };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=teammate-reminder.js.map
|
|
@@ -202,3 +202,55 @@ export function parsePostedLimnFinding(raw) {
|
|
|
202
202
|
const title = first.length > 120 ? `${first.slice(0, 119).trimEnd()}…` : first;
|
|
203
203
|
return { severity, tag, refPath, refLine, title, body: text };
|
|
204
204
|
}
|
|
205
|
+
const TRAILING_SUGGESTION_RE = /\n*```suggestion[^\n]*\n([\s\S]*?)\n?```\s*$/;
|
|
206
|
+
const TITLE_MAX = 160;
|
|
207
|
+
/**
|
|
208
|
+
* A posted finding's text without its trailing ```suggestion block, and that block's code (null when
|
|
209
|
+
* there is none). Limn posts a finding's suggestion LAST, so only a trailing block is one. Pure.
|
|
210
|
+
*/
|
|
211
|
+
export function splitTrailingSuggestion(text) {
|
|
212
|
+
const rest = text.replace(/\r\n?/g, '\n').trim();
|
|
213
|
+
const sug = TRAILING_SUGGESTION_RE.exec(rest);
|
|
214
|
+
if (!sug)
|
|
215
|
+
return { text: rest, suggestion: null };
|
|
216
|
+
return { text: rest.slice(0, sug.index).trim(), suggestion: sug[1] };
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* A POSTED Limn finding's text (a teammate's, as `parsePostedLimnFinding` returns its `body`) shown
|
|
220
|
+
* like the reader's own finding: a title, a body and a separate suggestion. Limn posts a finding's
|
|
221
|
+
* BODY only (never its title), so the title is the text's first sentence — a full stop, question
|
|
222
|
+
* mark or exclamation mark followed by a space or the line end, outside `code` — when it is short;
|
|
223
|
+
* else the stored title (`fallbackTitle`) and the whole text. Pure; never throws.
|
|
224
|
+
*/
|
|
225
|
+
export function postedFindingDisplay(text, fallbackTitle) {
|
|
226
|
+
const { text: rest, suggestion } = splitTrailingSuggestion(text);
|
|
227
|
+
const firstLineEnd = rest.indexOf('\n');
|
|
228
|
+
const firstLine = (firstLineEnd < 0 ? rest : rest.slice(0, firstLineEnd)).replace(/^#+\s*/, '');
|
|
229
|
+
let end = -1;
|
|
230
|
+
let inCode = false;
|
|
231
|
+
for (let i = 0; i < firstLine.length; i += 1) {
|
|
232
|
+
const ch = firstLine[i];
|
|
233
|
+
if (ch === '`')
|
|
234
|
+
inCode = !inCode;
|
|
235
|
+
else if (!inCode && (ch === '.' || ch === '?' || ch === '!') && (i + 1 === firstLine.length || firstLine[i + 1] === ' ')) {
|
|
236
|
+
// "e.g." / "i.e." are not the end of a sentence.
|
|
237
|
+
if (ch === '.' && /\b(?:e\.g|i\.e|etc|vs)$/i.test(firstLine.slice(0, i)))
|
|
238
|
+
continue;
|
|
239
|
+
end = i + 1;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (end < 0 && firstLineEnd >= 0)
|
|
244
|
+
end = firstLine.length;
|
|
245
|
+
if (end < 0 && firstLine.length <= TITLE_MAX)
|
|
246
|
+
end = firstLine.length;
|
|
247
|
+
if (end > 0 && end <= TITLE_MAX) {
|
|
248
|
+
const title = firstLine.slice(0, end).trim();
|
|
249
|
+
const afterTitle = firstLine.slice(end).trim();
|
|
250
|
+
// The rest keeps its own line breaks (a paragraph break stays one).
|
|
251
|
+
const body = (afterTitle + (firstLineEnd < 0 ? '' : rest.slice(firstLineEnd))).trim();
|
|
252
|
+
if (title !== '')
|
|
253
|
+
return { title, body, suggestion };
|
|
254
|
+
}
|
|
255
|
+
return { title: fallbackTitle, body: rest, suggestion };
|
|
256
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as Ie,r as x,j as e}from"./tanstack-BnbsafB1.js";import{aY as G,aX as Qe,cT as je,c_ as Ze,cA as es,cR as ss,cC as Te,aR as ts,cS as O,A as Ne,aW as Se,W as ne,y as ns,a7 as is,an as ie,bv as Ee,a3 as _e,e as Me,f as q,a6 as as,aU as Be,i as Le,s as rs,k as ls,a as cs,C as os,dx as us,c0 as ds,aZ as ms,dp as hs,dq as xs,$ as ps,J as fs,V as gs,v as z,bK as bs,cQ as js,cP as Ns,cz as vs,bn as ws,c1 as ks,az as ys,bm as Rs,bb as Ps,cb as $e,bN as Cs,cv as Ue,cw as As,cJ as Fs,cY as Is,cX as Ts,dh as Ss,di as Es,aV as _s,aS as Ms,cy as Bs,cx as Ls,cK as $s,de as Us,au as Os,a0 as Ds,aT as Hs,bR as Ws,b_ as ae,X as Ys,w as Ks,N as qs,U as zs,c6 as Oe,d6 as Vs,aj as ve,x as Gs,L as Xs}from"./index-BTsR634o.js";import{r as Js,t as Qs,S as Zs,C as et,T as st,F as tt,f as nt}from"./ClaudeReviewTab-BVlkGiBL.js";import"./markdown-CcoLFczy.js";import"./highlight-DIEV0qGG.js";import"./vis-C3BCkP5U.js";const it="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",we="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",ke="inline-flex items-center rounded-ui bg-ui-raise px-1.5 py-px font-mono text-meta text-ui-ink";function at(s){return s instanceof Le||s instanceof Error?s.message:"Something went wrong"}function De({plan:s}){return e.jsx("ul",{className:"list-disc space-y-0.5 pl-5 text-body text-ui-ink",children:s.summary.map((t,n)=>e.jsx("li",{children:t},n))})}function ye(s,t){var n;return((n=s==null?void 0:s.find(a=>a.ref===t))==null?void 0:n.title)??null}function rt({plan:s,items:t}){return e.jsxs("div",{className:"mt-2 space-y-3 text-meta text-ui-ink",children:[s.steps.length>0&&e.jsx("ol",{className:"list-decimal space-y-2 pl-5",children:s.steps.map((n,a)=>e.jsxs("li",{children:[e.jsx("div",{className:"font-medium text-ui-ink",children:n.title}),n.files.length>0&&e.jsx("div",{className:"mt-0.5 font-mono text-meta text-ui-mute",children:n.files.join(", ")}),e.jsx("p",{className:"mt-0.5 whitespace-pre-wrap",children:n.change}),n.refs.length>0&&e.jsx("div",{className:"mt-1 flex flex-wrap gap-1",children:n.refs.map(i=>e.jsx("span",{className:ke,children:i},i))})]},a))}),s.notAddressed.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"mb-1 font-semibold text-ui-mute",children:"Will not fix"}),e.jsx("ul",{className:"space-y-1",children:s.notAddressed.map(n=>e.jsxs("li",{children:[e.jsx("span",{className:ke,children:n.ref})," ",ye(t,n.ref)&&e.jsxs("span",{className:"font-medium",children:[ye(t,n.ref),": "]}),n.reason]},n.ref))})]}),s.notCovered.length>0&&e.jsxs("p",{children:[e.jsx("span",{className:"font-semibold text-ui-mute",children:"Not in the plan: "}),s.notCovered.join(", ")]})]})}function lt({pr:s,fix:t,liveStatus:n,passRunning:a,auth:i}){var w,p;const l=t.plan,o=G(t.plan??t),g=Qe((t.plan??t).provider,(t.plan??t).model),c=je(g,"plan"),m=je(g,"fix"),v=Be(c),F=Ze(s.id),u=es(s.id),k=ss(s.id),M=Te(s.id),C=Ie({mutationKey:ts(s.id)})>0,B=O(N=>N.noteAiFixRun),[E,I]=x.useState(""),[y,D]=x.useState(!1);if(!l)return null;const R=l.plan,_=l.status==="plan_ready"&&!a,L=E.trim(),P=L.length>Ne,r=()=>{!_||C||L===""||P||F.mutate({fixId:t.id,text:L},{onSuccess:()=>I("")})},d=()=>{B({prId:s.id,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title}),u.mutate(t.id)},f=F.error??u.error??k.error;return e.jsxs("div",{className:"mt-3 rounded-ui bg-ui-surface p-3",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-1 text-meta font-semibold text-ui-ink",children:["Plan",R&&l.revision>1&&e.jsxs("span",{className:"font-normal text-ui-mute",children:["· version ",l.revision]}),l.model&&e.jsxs("span",{className:"font-normal text-ui-mute",children:["· ",Se(l.provider,l.model,l.effort)]}),e.jsxs(ne,{title:"Plan first",children:[e.jsxs("p",{children:[v," reads the code and writes a plan. It changes nothing."]}),e.jsxs("p",{children:["Tell ",v," what to change and it rewrites the plan, taking the whole conversation into account. Each message runs ",v," again."]}),e.jsxs("p",{children:["When you approve, ",v," builds the fix from this plan. You still review the diff and press Push."]})]})]}),R?e.jsxs(e.Fragment,{children:[e.jsx(De,{plan:R}),e.jsxs("button",{type:"button",className:"hit mt-2 inline-flex items-center gap-1 text-meta text-ui-mute hover:text-ui-ink","aria-expanded":y,onClick:()=>D(N=>!N),children:[e.jsx(ns,{dir:y?"down":"right"}),"Details"]}),y&&e.jsx(rt,{plan:R,items:t.reviewItems})]}):!a&&e.jsx("p",{className:"text-meta text-ui-mute",children:"No plan yet."}),t.error&&e.jsx("p",{className:"mt-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-warn",children:t.error}),e.jsx(is,{transcript:l.transcript,plannedBy:o}),a&&e.jsxs("div",{className:"mt-3",children:[e.jsx(ie,{active:!0,label:R?"Updating the plan":"Making the plan",value:Ee(n),timeConstantSec:30}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[_e[((w=n==null?void 0:n.progress)==null?void 0:w.phase)??""]??"Working…",e.jsx("button",{type:"button",className:we,onClick:()=>M.mutate(),children:"Cancel"})]}),e.jsx(Me,{lines:(p=n==null?void 0:n.progress)==null?void 0:p.recentActivity,className:"mt-1"})]}),_&&R&&e.jsxs("div",{className:"mt-3",children:[e.jsx(q,{kind:"plan",auth:i,meter:!1,followUp:!0,provider:c,children:e.jsx(as,{name:v,draft:E,setDraft:I,busy:C,maxChars:Ne,onSend:r})}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx(q,{kind:"fix",auth:i,followUp:!0,provider:m,children:e.jsx("button",{type:"button","data-ai-run":!0,className:it,disabled:C,onClick:d,children:"Approve and build"})}),e.jsx("button",{type:"button",className:we,disabled:C,onClick:()=>k.mutate(t.id),children:"Discard plan"})]})]}),f!=null&&e.jsx("p",{className:"mt-1 text-meta text-ui-danger",children:at(f)})]})}function He({fix:s}){var n;const t=((n=s.plan)==null?void 0:n.status)==="approved"?s.plan.plan:null;return t?e.jsxs("div",{className:"mb-2 rounded-ui bg-ui-surface p-2",children:[e.jsx("div",{className:"mb-1 text-meta font-semibold text-ui-mute",children:"Built from your plan"}),e.jsx(De,{plan:t})]}):null}function ct(s,t,n){var a;return s??((t==null?void 0:t.status)==="succeeded"?t.id:((a=n.find(i=>i.status==="succeeded"))==null?void 0:a.id)??null)}function ot(s,t,n){return t==null||n==null||t===n.id?null:s!=null?"Uses the review you picked, not the latest.":n.status==="failed"?"Uses the last review that finished. The latest one failed.":n.status==="running"||n.status==="queued"?"Uses the last review that finished. A newer one is running.":"Uses the last review that finished."}const Re=os,ut=ls;function dt(s){return s.kind==="finding"&&s.findingId!=null?`claude-finding-${s.findingId}`:null}function mt(s){const t=O(n=>n.openClaudeReview);return n=>{t({id:s.id,number:s.number,title:s.title,repoFullName:s.repoFullName,authorLogin:null,authorDisplayName:null,authorAvatarUrl:null});const a=Date.now()+3e3,i=()=>{const l=document.getElementById(n);if(l){l.scrollIntoView({behavior:"smooth",block:"center"});return}Date.now()<a&&requestAnimationFrame(i)};requestAnimationFrame(i)}}function Pe({refId:s,item:t,onJump:n}){const a=t?`${cs[t.kind]} ${s}`:s,i=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"shrink-0",children:a}),t&&e.jsxs("span",{className:"min-w-0 truncate font-normal",children:["· ",t.title]})]}),l=t?dt(t):null;return l?e.jsx("button",{type:"button",onClick:()=>n(l),"aria-label":`${a}: ${(t==null?void 0:t.title)??""}. Show in AI Review`,className:`${Re} max-w-[22rem] hover:bg-ui-hover`,children:i}):e.jsx("span",{className:`${Re} max-w-[22rem]`,children:i})}function ht(s){var t;switch(s.seed){case"review":{const n=((t=s.reviewItems)==null?void 0:t.length)??0;return`Fix from ${s.sourceReviewId==null?"the CI check":"the AI review"}${n>0?` (${n} item${n===1?"":"s"})`:""}.`}case"plain":return"Fix from your instruction.";case"comments":return"Fix from picked comments (no longer offered).";case"ci_analysis":return"Fix from the CI analysis (no longer offered).";default:return""}}function xt({pr:s,fix:t}){const n=G(t),a=mt(s),i=t.changeReport,l=new Map((t.reviewItems??[]).map(c=>[c.ref,c])),o=(t.reviewItems??[]).filter(c=>!c.included);if(!i&&o.length===0)return null;const g=l.size>0;return e.jsxs("div",{className:"mt-2 text-meta",children:[e.jsx(rs,{report:i,filesChanged:t.filesChanged,by:n,refsInfo:g?e.jsx("p",{children:"Each tag is a review item the change answers. A finding tag opens it in the AI Review tab."}):null,renderRef:c=>e.jsx(Pe,{refId:c,item:l.get(c),onJump:a},c)}),o.length>0&&e.jsxs("section",{children:[e.jsxs("div",{className:ut,children:["Left out",e.jsx(ne,{title:"Left out",children:e.jsxs("p",{children:["These review items did not fit in what ",n," was sent, so it never saw them."]})})]}),e.jsx("div",{className:"flex flex-wrap gap-1",children:o.map(c=>e.jsx(Pe,{refId:c.ref,item:c,onJump:a},c.ref))})]})]})}const pt=["findings","earlier_findings","judged_threads","untouched_threads","ci_failures","sonar","style_bots","story"],ft={findings:"Claude’s findings",earlier_findings:"Earlier findings still open",judged_threads:"Threads Claude says need a fix",untouched_threads:"Unanswered threads",ci_failures:"CI failures",sonar:"SonarCloud issues",style_bots:"Style bot comments",story:"Ticket gaps"};function Ce(s,t="Claude"){return s==="findings"?`${t}’s findings`:s==="judged_threads"?`Threads ${t} says need a fix`:ft[s]}function V(s,t){return t[s.key]??s.defaultIncluded}function gt(s,t){return s.items.filter(n=>V(n,t)).map(n=>n.key)}function We(s,t){const n=new Set;let a=0;for(const i of s.items)if(V(i,t)){if(a>0&&a+i.chars>s.budgetChars){n.add(i.key);continue}a+=i.chars}return n}function bt(s,t){const n={};for(const a of s.items)n[a.key]=a.section===t;return n}const jt={blocker:"Blocker",warning:"Warning",nit:"Nit",question:"Question",praise:"Praise"},Ae={blocker:"bg-ui-danger/10 text-ui-danger",warning:"bg-ui-raise text-ui-warn",nit:"bg-ui-raise text-ui-mute"},Ye="whitespace-nowrap rounded-ui bg-ui-raise px-1 py-px text-meta text-ui-warn",Z=new Set;function Nt(s,t){return s?t!=null?`${s}:${t}`:s:null}function vt({item:s,picked:t,cut:n,disabled:a,onToggle:i}){return e.jsxs("span",{className:"inline-flex shrink-0 items-center gap-1.5 pt-0.5",children:[e.jsx("label",{className:"flex cursor-pointer items-center touch:-my-3 touch:min-h-10 touch:min-w-10 touch:justify-center",children:e.jsx(z,{checked:t,disabled:a,onChange:l=>i(l.target.checked),"aria-label":`Include in the fix: ${s.label}`})}),t&&n&&e.jsx("span",{className:Ye,children:"Won’t fit"})]})}function wt({item:s,picked:t,cut:n,disabled:a,onToggle:i}){const l=Nt(s.path,s.line);return e.jsx("li",{children:e.jsxs("label",{className:`flex cursor-pointer items-start gap-2 rounded-ui border px-2 py-1.5 text-meta ${t?"border-ui-line bg-ui-sel":"border-ui-line"}`,children:[e.jsx(z,{className:"mt-0.5",checked:t,disabled:a,onChange:o=>i(o.target.checked)}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsxs("span",{className:"flex flex-wrap items-center gap-1.5",children:[s.severity&&Ae[s.severity]&&e.jsx("span",{className:`rounded-ui px-1 py-px text-meta font-medium ${Ae[s.severity]}`,children:jt[s.severity]}),e.jsx("span",{className:"break-words text-ui-ink",children:s.label}),t&&n&&e.jsx("span",{className:Ye,children:"Won’t fit"})]}),(l||s.detail)&&e.jsxs("span",{className:"mt-0.5 block break-words text-meta text-ui-mute",children:[l&&e.jsx("span",{className:"font-mono",children:l}),l&&s.detail?" · ":"",s.detail]})]})]})})}function kt({preview:s,overrides:t,onChange:n,disabled:a,pr:i,review:l}){const o=We(s,t),g=new Map;for(const r of s.items){const d=g.get(r.section)??[];d.push(r),g.set(r.section,d)}const c=(r,d)=>{const f={...t};for(const w of r)f[w]=d;n(f)},m=l!=null&&l.id===s.sourceReviewId?l:null,v=Js(l),F=Qs(l),u=x.useMemo(()=>m!=null?us(m):null,[m]),k=x.useMemo(()=>new Map(((u==null?void 0:u.findings)??[]).map(r=>[r.id,r])),[u]),M=x.useMemo(()=>{var r;return new Map((((r=u==null?void 0:u.followUp)==null?void 0:r.items)??[]).map(d=>[d.priorFindingId,d]))},[u]),C=x.useMemo(()=>u!=null?ds(u):new Map,[u]),B=x.useMemo(()=>u!=null?ms(u):new Set,[u]),E=x.useMemo(()=>{var d;const r=new Set;for(const f of s.items)((d=f.card)==null?void 0:d.kind)==="story"&&r.add(f.card.ticketReviewId);return[...r].sort((f,w)=>f-w)},[s.items]),I=hs(i.id,E.length>0),y=x.useMemo(()=>{var d;const r=new Map;for(const f of((d=I.data)==null?void 0:d.tickets)??[])f.review!=null&&r.set(f.review.id,f.review);return r},[I.data]),D=x.useMemo(()=>I.data==null?[]:E.filter(r=>!y.has(r)),[I.data,E,y]),R=xs(D),_=x.useMemo(()=>{const r=new Map(y);for(const d of R)r.set(d.id,d);return r},[y,R]);if(s.items.length===0)return e.jsx("p",{className:"text-meta text-ui-mute",children:"The review found nothing to fix."});const L=(m==null?void 0:m.headSha)??i.headSha,P=r=>{var H,T;const d=V(r,t),f=o.has(r.key),w=j=>c([r.key],j),p=e.jsx(vt,{item:r,picked:d,cut:f,disabled:a,onToggle:w}),N=r.card;switch(N==null?void 0:N.kind){case"finding":{const j=k.get(N.findingId);if(j==null)break;return e.jsx(tt,{authorName:nt(l,j),prId:i.id,finding:j,editable:!1,prUrl:i.githubUrl,repoFullName:i.repoFullName,headSha:L,posting:!1,postError:null,inChangeset:j.fileInDiff,priorStatus:C.get(j.id),alreadyPosted:B.has(j.id),actions:!1,selection:p,docReferences:(m==null?void 0:m.docReferences)??null},r.key)}case"earlier_finding":{const j=M.get(N.priorFindingId);if(j==null)break;return e.jsx(gs,{item:j,muted:!1,findingsById:k,headMoved:((H=u==null?void 0:u.followUp)==null?void 0:H.headMoved)??!1,changedPaths:Z,actions:!1,selection:p,by:v},r.key)}case"thread":return e.jsx(st,{t:N.assessment,muted:!1,actions:!1,selection:p,notCheckedNote:N.inReview?void 0:`${F} didn’t check this one.`,by:F},r.key);case"ci":return e.jsx(et,{f:N.item,suggestion:N.item.suggestion,changedPaths:Z,selection:p},r.key);case"sonar":return e.jsx(Zs,{issue:N.issue,selection:p},r.key);case"story":{const j=_.get(N.ticketReviewId),S=j==null?void 0:j.items.find($=>$.id===N.itemId);if(j==null||S==null)break;const b={review:j,viewedPrId:i.id,changedPaths:Z,actions:!1,selection:p};if(S.status==="missing")return e.jsx(ps,{item:S,...b},r.key);const h=(T=j.assessment)==null?void 0:T.criteria.find($=>$.ref===S.ref);if(h==null||h.status==="met")break;return e.jsx(fs,{c:h,item:S,...b},r.key)}}return e.jsx(wt,{item:r,picked:d,cut:f,disabled:a,onToggle:w},r.key)};return e.jsxs("div",{className:"space-y-3",children:[pt.filter(r=>g.has(r)).map(r=>{const d=g.get(r),f=d.filter(p=>V(p,t)).length,w=f===d.length;return e.jsxs("section",{"aria-label":Ce(r,v),children:[e.jsxs("div",{className:"mb-1 flex items-center gap-2",children:[e.jsx("h4",{className:"text-meta font-semibold text-ui-ink",children:Ce(r,v)}),e.jsxs("span",{className:"text-meta text-ui-mute",children:[f," of ",d.length]}),e.jsx("button",{type:"button",className:"hit ml-auto text-meta text-ui-accent hover:underline disabled:opacity-50",disabled:a,onClick:()=>c(d.map(p=>p.key),!w),children:w?"Untick all":"Tick all"})]}),e.jsx("ul",{className:"space-y-1.5",children:d.map(P)})]},r)}),o.size>0&&e.jsxs("p",{className:"text-meta text-ui-warn",children:[o.size," ticked ",o.size===1?"item does":"items do"," not fit in one fix and will be left out. Untick something to make room."]})]})}const yt="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",Fe="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function Ke(s){return{prId:s.id,repoId:s.repoId,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title,githubUrl:s.githubUrl}}function Rt(s){const t=bs({mergeable:s.mergeable,mergeStateStatus:s.mergeStateStatus,isDraft:s.isDraft,inMergeQueue:s.inMergeQueue===!0}).verdict;return js({state:s.state,verdict:t,viewerCanPush:s.viewerCanPush})}function Pt({pr:s}){const t=Ns(s.id),n=vs(),a=ws(t),i=s.baseRefName??"the base branch";x.useEffect(()=>{ks(s.id)},[s.id]);const l=Ke(s),o=(t==null?void 0:t.phase)==="succeeded"?t.resolution:null;return e.jsxs("div",{className:"mb-3 rounded-ui bg-ui-surface p-3",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-body font-medium text-ui-ink",children:[e.jsx(ys,{size:13,className:"text-ai-signal"}),"This branch conflicts with ",i]}),e.jsxs("p",{className:"mt-1 text-meta text-ui-mute",children:[n," reads the code and picks a result for each conflict. You check its choices in the resolver before anything is pushed."]}),a&&t!=null?e.jsxs("div",{className:"mt-2",children:[e.jsx(ie,{active:!0,label:`Resolving conflicts with ${n}`,timeConstantSec:60}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[Rs(t.phase,n),e.jsx("button",{type:"button",className:Fe,onClick:()=>Ps(s.id),children:"Cancel"})]})]}):e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx(q,{kind:"resolve",children:e.jsx("button",{type:"button",className:yt,onClick:()=>$e(l,{providerName:n}),children:o!=null?"Run again":`Resolve merge conflicts with ${n}`})}),o!=null&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:Fe,onClick:()=>Cs(l),children:"Open the resolver"}),e.jsxs("span",{className:"text-meta text-ui-mute",children:[G(o)," decided ",o.choices.length," of ",o.decidableTotal," change",o.decidableTotal===1?"":"s","."]})]}),(t==null?void 0:t.phase)==="failed"&&t.error!=null&&e.jsx("span",{className:"text-meta text-ui-danger",children:t.error}),(t==null?void 0:t.phase)==="cancelled"&&e.jsx("span",{className:"text-meta text-ui-mute",children:"Cancelled."})]})]})}const se="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function te(s){return s instanceof Le||s instanceof Error?s.message:"Something went wrong"}const ee="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function Ct({children:s,info:t}){return e.jsxs("div",{className:"flex items-center gap-1.5 px-4 pb-2 pt-4 text-title text-ui-ink md:px-5",children:[e.jsx("h3",{children:s}),t]})}function Ot({pr:s}){const t=Ue().enabled,n=O(c=>c.aiFixTabFocus),a=O(c=>c.consumeAiFixTabFocus),[i,l]=x.useState(null),[o,g]=x.useState(null);return x.useEffect(()=>{n&&n.prId===s.id&&(n.reviewId!=null&&l(n.reviewId),n.only!=null&&g(n.only),a())},[n,s.id,a]),t?e.jsx("div",{className:"pb-6",children:e.jsx(At,{pr:s,handoffReviewId:i,onlySection:o,onOnlySectionApplied:()=>g(null)})}):e.jsx(e.Fragment,{})}function At({pr:s,handoffReviewId:t,onlySection:n,onOnlySectionApplied:a}){var oe,ue,de,me,he,xe,pe,fe,ge,be;const{data:i,isLoading:l}=As(s.id,!0),{data:o,isLoading:g}=Fs(s.id),c=(o==null?void 0:o.review)??null,m=ct(t,c,(o==null?void 0:o.history)??[]),v=ot(t,m,c),F=O(A=>A.setPrDetailTab),u=Is("fix",Xs),k=Be(u.chosen.provider),M=Ts().data,C=Ss(s.id),B=Es(s.id),E=Te(s.id),I=Ue(),y=_s(M,u.chosen.provider,"plan"),[D,R]=x.useState(!1),_=D&&y,L=O(A=>A.noteAiFixRun),P=Ie({mutationKey:Ms(s.id)})>0,r=((oe=i==null?void 0:i.fix)==null?void 0:oe.status)??null,d=r==="planned",f=d&&((de=(ue=i==null?void 0:i.fix)==null?void 0:ue.plan)==null?void 0:de.status)==="planning",w=r==="running"||r==="queued"||P||f,{status:p}=Bs(s.id,w),N=(p==null?void 0:p.status)??r??"idle",H=N==="running"||N==="queued",T=H&&!d,j=d&&(f||H),S=d&&(((he=(me=i==null?void 0:i.fix)==null?void 0:me.plan)==null?void 0:he.status)==="planning"||((pe=(xe=i==null?void 0:i.fix)==null?void 0:xe.plan)==null?void 0:pe.status)==="plan_ready"),b=(i==null?void 0:i.fix)??null,h=Ls(s.id,m,(i==null?void 0:i.enabled)!==!1&&(m!=null||!g)),$=m==null&&h.data!=null&&h.data.sourceReviewId==null&&h.data.items.length>0,K=m!=null||$,ze=$s(m!=null&&(c==null?void 0:c.id)!==m?m:null),Ve=m!=null&&(c==null?void 0:c.id)===m?c:ze.data??null,[X,J]=x.useState({});x.useEffect(()=>J({}),[m]);const[Ge,W]=x.useState(!1);x.useEffect(()=>{n==null||!h.data||(J(bt(h.data,n)),W(!0),a())},[n,h.data,a]);const re=!S&&(Ge||!b||b.status!=="succeeded"),Q=Rt(s),[le,Xe]=x.useState(!1),Y=Us(s.id,s.repoFullName),U=h.data?gt(h.data,X):[],ce=h.data?We(h.data,X).size:0,Je=()=>{if(!K||!h.data||U.length===0)return;const A={model:u.chosen.model,provider:u.chosen.provider,seed:"review",...m!=null?{sourceReviewId:m}:{},include:U,...Y.names.length>0?{checks:Y.names}:{}};_?B.mutate(A,{onSuccess:()=>W(!1)}):(L({prId:s.id,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title}),C.mutate(A,{onSuccess:()=>W(!1)})),le&&Q&&$e(Ke(s),{model:Hs(u.chosen.model),providerName:I.providerName})};return e.jsxs("div",{children:[e.jsx(Ct,{info:e.jsxs(ne,{title:"AI Fix",children:[e.jsxs("p",{children:[k," reads the PR's code and edits files in a private copy. It has no shell. Tick Run tests to let it run the project's own test, lint and type checks in a sandbox."]}),e.jsx("p",{children:"A fix starts from an AI review. Pick what it should work on: the review's findings, earlier findings still open, threads the review says need a fix, unanswered threads, CI failures and ticket gaps are ticked; style bot comments are not."}),e.jsx("p",{children:"With no AI review, a fix can start from a finished CI check: it works on the failures the check says this PR can fix."}),e.jsxs("p",{children:["Tick Plan first to read ",k,"'s plan, steer it and approve it before anything changes."]}),e.jsxs("p",{children:[k," reports what it changed in each file and what it left alone, and why."]}),e.jsx("p",{children:"Nothing is pushed until you press Push. An automatic fix on your own PR is pushed for you only when Push automatically is on in Settings."})]}),children:"AI Fix"}),e.jsxs("div",{className:"px-4",children:[Q&&e.jsx(Pt,{pr:s}),(i==null?void 0:i.enabled)===!1?e.jsx("p",{className:"text-body text-ui-mute",children:"The agentic fixer is turned off."}):e.jsxs(e.Fragment,{children:[!T&&!S&&!K&&!g&&!h.isLoading&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("p",{className:"text-meta text-ui-mute",children:(c==null?void 0:c.status)==="running"||(c==null?void 0:c.status)==="queued"?"A fix starts from an AI review. One is running.":"A fix starts from a finished AI review."}),e.jsx("button",{type:"button",className:se,onClick:()=>F(s.id,"claude_review"),children:"Open AI Review"})]}),!T&&!S&&K&&!re&&e.jsx("button",{type:"button",className:ee,onClick:()=>W(!0),children:"New fix"}),!T&&K&&re&&e.jsxs("div",{children:[v&&e.jsx("p",{className:"mb-2 text-meta text-ui-mute",children:v}),$&&e.jsx("p",{className:"mb-2 text-meta text-ui-mute",children:"No AI review yet. This fix works on the CI check’s failures."}),h.isLoading&&e.jsx("p",{className:"text-meta text-ui-mute",children:"Loading…"}),h.isError&&m!=null&&e.jsx("p",{className:"text-meta text-ui-danger",children:te(h.error)}),h.data&&e.jsx(kt,{preview:h.data,overrides:X,onChange:J,disabled:P,pr:s,review:Ve}),h.data&&h.data.items.length>0&&Q&&e.jsxs("label",{className:"mt-3 flex cursor-pointer items-start gap-2 text-meta text-ui-ink",children:[e.jsx(z,{className:"mt-0.5",checked:le,disabled:P,onChange:A=>Xe(A.target.checked)}),e.jsxs("span",{children:["Also resolve merge conflicts with ",s.baseRefName??"the base branch",e.jsx("span",{className:"block text-meta text-ui-mute",children:"You check the merge in the resolver. It lands as its own commit, apart from the fix."})]})]}),h.data&&h.data.items.length>0&&e.jsx(Os,{state:Y,disabled:P}),h.data&&h.data.items.length>0&&e.jsxs("div",{className:"mt-3 flex flex-wrap items-center gap-2 max-md:sticky max-md:bottom-0 max-md:z-20 max-md:-mx-4 max-md:bg-ui-surface max-md:px-4 max-md:py-3",children:[e.jsx(Ds,{state:u,onPick:u.pick,disabled:P}),y&&e.jsxs("label",{className:"flex cursor-pointer items-center gap-1.5 text-meta text-ui-ink",children:[e.jsx(z,{checked:_,disabled:P,onChange:A=>R(A.target.checked)}),"Plan first"]}),e.jsx(q,{kind:"fix",auth:i==null?void 0:i.auth,anyProvider:!0,provider:u.chosen.provider,children:e.jsx("button",{type:"button",className:se,disabled:P||U.length===0||Y.on&&Y.query.isLoading,onClick:Je,children:_?"Make a plan":"Start fix"})}),e.jsx("span",{className:"text-meta text-ui-mute",children:U.length===0?"Nothing ticked.":`${U.length-ce} item${U.length-ce===1?"":"s"}`}),(b==null?void 0:b.status)==="succeeded"&&e.jsx("button",{type:"button",className:ee,onClick:()=>W(!1),children:"Close"})]})]}),T&&e.jsx("button",{type:"button",className:ee,onClick:()=>E.mutate(),children:"Cancel"}),(C.isError||B.isError)&&e.jsx("p",{className:"mt-1 text-meta text-ui-danger",children:te(C.error??B.error)}),b&&d&&e.jsx(lt,{pr:s,fix:b,liveStatus:p,passRunning:j,auth:i==null?void 0:i.auth}),T&&e.jsxs("div",{className:"mt-3",children:[b&&e.jsx(He,{fix:b}),e.jsx(ie,{active:!0,label:"Running AI fix",value:Ee(p),timeConstantSec:40}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[(b==null?void 0:b.trigger)==="auto"&&e.jsx(qe,{}),_e[((fe=p==null?void 0:p.progress)==null?void 0:fe.phase)??""]??"Working…"]}),e.jsx(Me,{lines:(ge=p==null?void 0:p.progress)==null?void 0:ge.recentActivity,runKey:(b==null?void 0:b.id)??null,className:"mt-1"})]}),!T&&b&&!d&&e.jsx(It,{pr:s,fix:b,headInfo:(i==null?void 0:i.headInfo)??null,viewerCanPush:(i==null?void 0:i.viewerCanPush)??!1}),l&&!b&&e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"Loading…"})]}),e.jsx(St,{history:(i==null?void 0:i.history)??[],currentFixId:((be=i==null?void 0:i.fix)==null?void 0:be.id)??null})]})]})}function qe(){return e.jsx("span",{className:"inline-flex items-center rounded-ui bg-ui-raise px-1.5 py-px text-meta font-medium text-ui-mute",children:"Auto fix"})}function Ft(s){return Se(s.provider,s.model,s.effort)}function It({pr:s,fix:t,headInfo:n,viewerCanPush:a}){var o,g,c;const i=x.useMemo(()=>Ws(t.patch),[t.patch]);if(t.status==="failed"&&((o=t.plan)==null?void 0:o.status)==="failed")return e.jsxs("div",{className:"mt-3 rounded-ui border border-ui-danger/40 bg-ui-danger/10 p-2 text-meta text-ui-danger",children:[G(t.plan??t)," could not make a plan: ",t.error??"unknown error"]});if(t.status==="cancelled"&&((g=t.plan)==null?void 0:g.status)==="discarded")return e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"The plan was discarded."});if(t.status==="failed")return e.jsxs("div",{className:"mt-3 rounded-ui border border-ui-danger/40 bg-ui-danger/10 p-2 text-meta text-ui-danger",children:["The fix run failed: ",t.error??"unknown error"]});if(t.status==="cancelled")return e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"The fix run was cancelled."});if(t.status!=="succeeded")return e.jsx(e.Fragment,{});const l=!t.patch||t.filesChanged.length===0;return e.jsxs("div",{className:"mt-3 border-t border-ui-line pt-3",children:[e.jsxs("p",{className:"mb-1 text-meta text-ui-mute",children:[t.trigger==="auto"&&e.jsxs(e.Fragment,{children:[e.jsx(qe,{})," "]}),ht(t)," · ",Ft(t),t.finishedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(t.finishedAt)]})]}),t.pushedAt==null&&t.error&&e.jsx("p",{className:"mb-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-warn",children:t.error}),e.jsx(He,{fix:t}),t.summary&&e.jsx("div",{className:"prose prose-sm max-w-none dark:prose-invert",children:e.jsx(Ys,{children:t.summary})}),e.jsx(xt,{pr:s,fix:t}),e.jsx(Ks,{checks:t.checks}),l?e.jsx("p",{className:"mt-2 text-meta text-ui-mute",children:"No files changed."}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-1 mt-2 flex items-center justify-between gap-3 text-meta text-ui-mute",children:[e.jsxs("span",{children:[t.filesChanged.length," file",t.filesChanged.length===1?"":"s"," changed",!((c=t.checks)!=null&&c.ran)&&" · Not built or tested here."]}),e.jsx(qs,{})]}),e.jsx("div",{className:"overflow-hidden rounded-ui bg-ui-surface text-ui-ink",children:e.jsx(zs,{files:i})}),e.jsx(Et,{pr:s,fix:t,headInfo:n,viewerCanPush:a})]})]})}function Tt({fix:s}){return e.jsxs("div",{className:"mb-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-success",children:[e.jsxs("div",{children:["Pushed to ",e.jsx("span",{className:"font-mono",children:s.pushedBranch}),s.pushedPrUrl&&e.jsxs(e.Fragment,{children:[" · ",e.jsxs("a",{href:Oe(s.pushedPrUrl),target:"_blank",rel:"noreferrer",className:"hit underline",children:["PR #",s.pushedPrNumber]})]}),s.pushedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(s.pushedAt)]})]}),s.commitMessage&&e.jsx("div",{className:"mt-1 font-mono text-meta text-ui-success",children:s.commitMessage})]})}function St({history:s,currentFixId:t}){const n=s.filter(a=>a.pushedAt!=null&&a.id!==t);return n.length===0?null:e.jsxs("div",{className:"mt-6",children:[e.jsx("div",{className:"mb-2 text-title text-ui-ink",children:"Earlier fixes pushed"}),e.jsx("ul",{className:"space-y-2",children:n.map(a=>e.jsxs("li",{className:"text-meta",children:[e.jsx("div",{className:"font-mono text-ui-ink",children:a.commitMessage??"(no commit message)"}),e.jsxs("div",{className:"mt-0.5 text-meta text-ui-faint",children:[a.pushedBranch&&e.jsx("span",{className:"font-mono",children:a.pushedBranch}),a.pushedPrUrl&&e.jsxs(e.Fragment,{children:[" · ",e.jsxs("a",{href:Oe(a.pushedPrUrl),target:"_blank",rel:"noreferrer",className:"hit underline",children:["PR #",a.pushedPrNumber]})]}),a.pushedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(a.pushedAt)]})]})]},a.id))})]})}function Et({pr:s,fix:t,headInfo:n,viewerCanPush:a}){const i=Vs(s.id),l=(n==null?void 0:n.canPushSameBranch)??!1,[o,g]=x.useState(l?"existing":"new"),[c,m]=x.useState((n==null?void 0:n.suggestedBranch)??""),v=x.useRef(!1);if(x.useEffect(()=>{!v.current&&(n!=null&&n.suggestedBranch)&&(m(n.suggestedBranch),v.current=!0,n.canPushSameBranch||g("new"))},[n]),t.pushedAt!=null)return e.jsx(Tt,{fix:t});if(!a)return e.jsx("p",{className:"mt-2 text-meta text-ui-mute",children:"You need write access to push this fix."});const F=o==="new"&&c.trim().length===0,u=i.isPending,k=()=>{i.mutate({fixId:t.id,body:{target:o,branch:o==="new"?c.trim():void 0}})};return e.jsxs("div",{className:"mt-3 rounded-ui bg-ui-surface p-2",children:[t.commitMessage&&e.jsx("div",{className:"mb-2 rounded-ui bg-ui-surface px-2 py-1 font-mono text-meta text-ui-ink",title:"Commit message",children:t.commitMessage}),e.jsxs("label",{className:`flex items-center gap-2 text-meta ${l?"":"opacity-40"}`,title:l?void 0:"The PR head is a fork you cannot push to — use a new branch",children:[e.jsx(ve,{className:"mt-0",checked:o==="existing",disabled:!l||u,onChange:()=>g("existing")}),"Push to the PR branch",(n==null?void 0:n.headRef)&&e.jsxs("span",{className:"font-mono text-ui-faint",children:["(",n.headRef,")"]})]}),e.jsxs("label",{className:"mt-1 flex items-center gap-2 text-meta",children:[e.jsx(ve,{className:"mt-0",checked:o==="new",disabled:u,onChange:()=>g("new")}),"New branch + open a PR"]}),o==="new"&&e.jsx("input",{type:"text",className:"mt-1 w-full rounded-ui bg-ui-raise px-2 py-1 font-mono text-meta ring-1 ring-inset ring-ui-line focus:outline-none focus:ring-2 focus:ring-ui-accent touch:min-h-10",value:c,disabled:u,onChange:M=>m(M.target.value),placeholder:"branch-name"}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",className:se,disabled:u||F,onClick:k,children:u?"Pushing…":o==="new"?"Push + open PR":"Push"}),e.jsx(Gs,{checks:t.checks})]}),i.isError&&e.jsx("div",{className:"mt-2 text-meta text-ui-danger",children:te(i.error)})]})}export{Ot as AiFixTab};
|
|
1
|
+
import{d as Ie,r as x,j as e}from"./tanstack-BnbsafB1.js";import{aY as G,aX as Qe,cT as je,c_ as Ze,cA as es,cR as ss,cC as Te,aR as ts,cS as O,A as Ne,aW as Se,W as ne,y as ns,a7 as is,an as ie,bv as Ee,a3 as _e,e as Me,f as q,a6 as as,aU as Be,i as Le,s as rs,k as ls,a as cs,C as os,dx as us,c0 as ds,aZ as ms,dp as hs,dq as xs,$ as ps,J as fs,V as gs,v as z,bK as bs,cQ as js,cP as Ns,cz as vs,bn as ws,c1 as ks,az as ys,bm as Rs,bb as Ps,cb as $e,bN as Cs,cv as Ue,cw as As,cJ as Fs,cY as Is,cX as Ts,dh as Ss,di as Es,aV as _s,aS as Ms,cy as Bs,cx as Ls,cK as $s,de as Us,au as Os,a0 as Ds,aT as Hs,bR as Ws,b_ as ae,X as Ys,w as Ks,N as qs,U as zs,c6 as Oe,d6 as Vs,aj as ve,x as Gs,L as Xs}from"./index-DnvzZnsD.js";import{r as Js,t as Qs,S as Zs,C as et,T as st,F as tt,f as nt}from"./ClaudeReviewTab-CMCKluXj.js";import"./markdown-CcoLFczy.js";import"./highlight-DIEV0qGG.js";import"./vis-C3BCkP5U.js";const it="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",we="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",ke="inline-flex items-center rounded-ui bg-ui-raise px-1.5 py-px font-mono text-meta text-ui-ink";function at(s){return s instanceof Le||s instanceof Error?s.message:"Something went wrong"}function De({plan:s}){return e.jsx("ul",{className:"list-disc space-y-0.5 pl-5 text-body text-ui-ink",children:s.summary.map((t,n)=>e.jsx("li",{children:t},n))})}function ye(s,t){var n;return((n=s==null?void 0:s.find(a=>a.ref===t))==null?void 0:n.title)??null}function rt({plan:s,items:t}){return e.jsxs("div",{className:"mt-2 space-y-3 text-meta text-ui-ink",children:[s.steps.length>0&&e.jsx("ol",{className:"list-decimal space-y-2 pl-5",children:s.steps.map((n,a)=>e.jsxs("li",{children:[e.jsx("div",{className:"font-medium text-ui-ink",children:n.title}),n.files.length>0&&e.jsx("div",{className:"mt-0.5 font-mono text-meta text-ui-mute",children:n.files.join(", ")}),e.jsx("p",{className:"mt-0.5 whitespace-pre-wrap",children:n.change}),n.refs.length>0&&e.jsx("div",{className:"mt-1 flex flex-wrap gap-1",children:n.refs.map(i=>e.jsx("span",{className:ke,children:i},i))})]},a))}),s.notAddressed.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"mb-1 font-semibold text-ui-mute",children:"Will not fix"}),e.jsx("ul",{className:"space-y-1",children:s.notAddressed.map(n=>e.jsxs("li",{children:[e.jsx("span",{className:ke,children:n.ref})," ",ye(t,n.ref)&&e.jsxs("span",{className:"font-medium",children:[ye(t,n.ref),": "]}),n.reason]},n.ref))})]}),s.notCovered.length>0&&e.jsxs("p",{children:[e.jsx("span",{className:"font-semibold text-ui-mute",children:"Not in the plan: "}),s.notCovered.join(", ")]})]})}function lt({pr:s,fix:t,liveStatus:n,passRunning:a,auth:i}){var w,p;const l=t.plan,o=G(t.plan??t),g=Qe((t.plan??t).provider,(t.plan??t).model),c=je(g,"plan"),m=je(g,"fix"),v=Be(c),F=Ze(s.id),u=es(s.id),k=ss(s.id),M=Te(s.id),C=Ie({mutationKey:ts(s.id)})>0,B=O(N=>N.noteAiFixRun),[E,I]=x.useState(""),[y,D]=x.useState(!1);if(!l)return null;const R=l.plan,_=l.status==="plan_ready"&&!a,L=E.trim(),P=L.length>Ne,r=()=>{!_||C||L===""||P||F.mutate({fixId:t.id,text:L},{onSuccess:()=>I("")})},d=()=>{B({prId:s.id,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title}),u.mutate(t.id)},f=F.error??u.error??k.error;return e.jsxs("div",{className:"mt-3 rounded-ui bg-ui-surface p-3",children:[e.jsxs("div",{className:"mb-1 flex items-center gap-1 text-meta font-semibold text-ui-ink",children:["Plan",R&&l.revision>1&&e.jsxs("span",{className:"font-normal text-ui-mute",children:["· version ",l.revision]}),l.model&&e.jsxs("span",{className:"font-normal text-ui-mute",children:["· ",Se(l.provider,l.model,l.effort)]}),e.jsxs(ne,{title:"Plan first",children:[e.jsxs("p",{children:[v," reads the code and writes a plan. It changes nothing."]}),e.jsxs("p",{children:["Tell ",v," what to change and it rewrites the plan, taking the whole conversation into account. Each message runs ",v," again."]}),e.jsxs("p",{children:["When you approve, ",v," builds the fix from this plan. You still review the diff and press Push."]})]})]}),R?e.jsxs(e.Fragment,{children:[e.jsx(De,{plan:R}),e.jsxs("button",{type:"button",className:"hit mt-2 inline-flex items-center gap-1 text-meta text-ui-mute hover:text-ui-ink","aria-expanded":y,onClick:()=>D(N=>!N),children:[e.jsx(ns,{dir:y?"down":"right"}),"Details"]}),y&&e.jsx(rt,{plan:R,items:t.reviewItems})]}):!a&&e.jsx("p",{className:"text-meta text-ui-mute",children:"No plan yet."}),t.error&&e.jsx("p",{className:"mt-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-warn",children:t.error}),e.jsx(is,{transcript:l.transcript,plannedBy:o}),a&&e.jsxs("div",{className:"mt-3",children:[e.jsx(ie,{active:!0,label:R?"Updating the plan":"Making the plan",value:Ee(n),timeConstantSec:30}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[_e[((w=n==null?void 0:n.progress)==null?void 0:w.phase)??""]??"Working…",e.jsx("button",{type:"button",className:we,onClick:()=>M.mutate(),children:"Cancel"})]}),e.jsx(Me,{lines:(p=n==null?void 0:n.progress)==null?void 0:p.recentActivity,className:"mt-1"})]}),_&&R&&e.jsxs("div",{className:"mt-3",children:[e.jsx(q,{kind:"plan",auth:i,meter:!1,followUp:!0,provider:c,children:e.jsx(as,{name:v,draft:E,setDraft:I,busy:C,maxChars:Ne,onSend:r})}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx(q,{kind:"fix",auth:i,followUp:!0,provider:m,children:e.jsx("button",{type:"button","data-ai-run":!0,className:it,disabled:C,onClick:d,children:"Approve and build"})}),e.jsx("button",{type:"button",className:we,disabled:C,onClick:()=>k.mutate(t.id),children:"Discard plan"})]})]}),f!=null&&e.jsx("p",{className:"mt-1 text-meta text-ui-danger",children:at(f)})]})}function He({fix:s}){var n;const t=((n=s.plan)==null?void 0:n.status)==="approved"?s.plan.plan:null;return t?e.jsxs("div",{className:"mb-2 rounded-ui bg-ui-surface p-2",children:[e.jsx("div",{className:"mb-1 text-meta font-semibold text-ui-mute",children:"Built from your plan"}),e.jsx(De,{plan:t})]}):null}function ct(s,t,n){var a;return s??((t==null?void 0:t.status)==="succeeded"?t.id:((a=n.find(i=>i.status==="succeeded"))==null?void 0:a.id)??null)}function ot(s,t,n){return t==null||n==null||t===n.id?null:s!=null?"Uses the review you picked, not the latest.":n.status==="failed"?"Uses the last review that finished. The latest one failed.":n.status==="running"||n.status==="queued"?"Uses the last review that finished. A newer one is running.":"Uses the last review that finished."}const Re=os,ut=ls;function dt(s){return s.kind==="finding"&&s.findingId!=null?`claude-finding-${s.findingId}`:null}function mt(s){const t=O(n=>n.openClaudeReview);return n=>{t({id:s.id,number:s.number,title:s.title,repoFullName:s.repoFullName,authorLogin:null,authorDisplayName:null,authorAvatarUrl:null});const a=Date.now()+3e3,i=()=>{const l=document.getElementById(n);if(l){l.scrollIntoView({behavior:"smooth",block:"center"});return}Date.now()<a&&requestAnimationFrame(i)};requestAnimationFrame(i)}}function Pe({refId:s,item:t,onJump:n}){const a=t?`${cs[t.kind]} ${s}`:s,i=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"shrink-0",children:a}),t&&e.jsxs("span",{className:"min-w-0 truncate font-normal",children:["· ",t.title]})]}),l=t?dt(t):null;return l?e.jsx("button",{type:"button",onClick:()=>n(l),"aria-label":`${a}: ${(t==null?void 0:t.title)??""}. Show in AI Review`,className:`${Re} max-w-[22rem] hover:bg-ui-hover`,children:i}):e.jsx("span",{className:`${Re} max-w-[22rem]`,children:i})}function ht(s){var t;switch(s.seed){case"review":{const n=((t=s.reviewItems)==null?void 0:t.length)??0;return`Fix from ${s.sourceReviewId==null?"the CI check":"the AI review"}${n>0?` (${n} item${n===1?"":"s"})`:""}.`}case"plain":return"Fix from your instruction.";case"comments":return"Fix from picked comments (no longer offered).";case"ci_analysis":return"Fix from the CI analysis (no longer offered).";default:return""}}function xt({pr:s,fix:t}){const n=G(t),a=mt(s),i=t.changeReport,l=new Map((t.reviewItems??[]).map(c=>[c.ref,c])),o=(t.reviewItems??[]).filter(c=>!c.included);if(!i&&o.length===0)return null;const g=l.size>0;return e.jsxs("div",{className:"mt-2 text-meta",children:[e.jsx(rs,{report:i,filesChanged:t.filesChanged,by:n,refsInfo:g?e.jsx("p",{children:"Each tag is a review item the change answers. A finding tag opens it in the AI Review tab."}):null,renderRef:c=>e.jsx(Pe,{refId:c,item:l.get(c),onJump:a},c)}),o.length>0&&e.jsxs("section",{children:[e.jsxs("div",{className:ut,children:["Left out",e.jsx(ne,{title:"Left out",children:e.jsxs("p",{children:["These review items did not fit in what ",n," was sent, so it never saw them."]})})]}),e.jsx("div",{className:"flex flex-wrap gap-1",children:o.map(c=>e.jsx(Pe,{refId:c.ref,item:c,onJump:a},c.ref))})]})]})}const pt=["findings","earlier_findings","judged_threads","untouched_threads","ci_failures","sonar","style_bots","story"],ft={findings:"Claude’s findings",earlier_findings:"Earlier findings still open",judged_threads:"Threads Claude says need a fix",untouched_threads:"Unanswered threads",ci_failures:"CI failures",sonar:"SonarCloud issues",style_bots:"Style bot comments",story:"Ticket gaps"};function Ce(s,t="Claude"){return s==="findings"?`${t}’s findings`:s==="judged_threads"?`Threads ${t} says need a fix`:ft[s]}function V(s,t){return t[s.key]??s.defaultIncluded}function gt(s,t){return s.items.filter(n=>V(n,t)).map(n=>n.key)}function We(s,t){const n=new Set;let a=0;for(const i of s.items)if(V(i,t)){if(a>0&&a+i.chars>s.budgetChars){n.add(i.key);continue}a+=i.chars}return n}function bt(s,t){const n={};for(const a of s.items)n[a.key]=a.section===t;return n}const jt={blocker:"Blocker",warning:"Warning",nit:"Nit",question:"Question",praise:"Praise"},Ae={blocker:"bg-ui-danger/10 text-ui-danger",warning:"bg-ui-raise text-ui-warn",nit:"bg-ui-raise text-ui-mute"},Ye="whitespace-nowrap rounded-ui bg-ui-raise px-1 py-px text-meta text-ui-warn",Z=new Set;function Nt(s,t){return s?t!=null?`${s}:${t}`:s:null}function vt({item:s,picked:t,cut:n,disabled:a,onToggle:i}){return e.jsxs("span",{className:"inline-flex shrink-0 items-center gap-1.5 pt-0.5",children:[e.jsx("label",{className:"flex cursor-pointer items-center touch:-my-3 touch:min-h-10 touch:min-w-10 touch:justify-center",children:e.jsx(z,{checked:t,disabled:a,onChange:l=>i(l.target.checked),"aria-label":`Include in the fix: ${s.label}`})}),t&&n&&e.jsx("span",{className:Ye,children:"Won’t fit"})]})}function wt({item:s,picked:t,cut:n,disabled:a,onToggle:i}){const l=Nt(s.path,s.line);return e.jsx("li",{children:e.jsxs("label",{className:`flex cursor-pointer items-start gap-2 rounded-ui border px-2 py-1.5 text-meta ${t?"border-ui-line bg-ui-sel":"border-ui-line"}`,children:[e.jsx(z,{className:"mt-0.5",checked:t,disabled:a,onChange:o=>i(o.target.checked)}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsxs("span",{className:"flex flex-wrap items-center gap-1.5",children:[s.severity&&Ae[s.severity]&&e.jsx("span",{className:`rounded-ui px-1 py-px text-meta font-medium ${Ae[s.severity]}`,children:jt[s.severity]}),e.jsx("span",{className:"break-words text-ui-ink",children:s.label}),t&&n&&e.jsx("span",{className:Ye,children:"Won’t fit"})]}),(l||s.detail)&&e.jsxs("span",{className:"mt-0.5 block break-words text-meta text-ui-mute",children:[l&&e.jsx("span",{className:"font-mono",children:l}),l&&s.detail?" · ":"",s.detail]})]})]})})}function kt({preview:s,overrides:t,onChange:n,disabled:a,pr:i,review:l}){const o=We(s,t),g=new Map;for(const r of s.items){const d=g.get(r.section)??[];d.push(r),g.set(r.section,d)}const c=(r,d)=>{const f={...t};for(const w of r)f[w]=d;n(f)},m=l!=null&&l.id===s.sourceReviewId?l:null,v=Js(l),F=Qs(l),u=x.useMemo(()=>m!=null?us(m):null,[m]),k=x.useMemo(()=>new Map(((u==null?void 0:u.findings)??[]).map(r=>[r.id,r])),[u]),M=x.useMemo(()=>{var r;return new Map((((r=u==null?void 0:u.followUp)==null?void 0:r.items)??[]).map(d=>[d.priorFindingId,d]))},[u]),C=x.useMemo(()=>u!=null?ds(u):new Map,[u]),B=x.useMemo(()=>u!=null?ms(u):new Set,[u]),E=x.useMemo(()=>{var d;const r=new Set;for(const f of s.items)((d=f.card)==null?void 0:d.kind)==="story"&&r.add(f.card.ticketReviewId);return[...r].sort((f,w)=>f-w)},[s.items]),I=hs(i.id,E.length>0),y=x.useMemo(()=>{var d;const r=new Map;for(const f of((d=I.data)==null?void 0:d.tickets)??[])f.review!=null&&r.set(f.review.id,f.review);return r},[I.data]),D=x.useMemo(()=>I.data==null?[]:E.filter(r=>!y.has(r)),[I.data,E,y]),R=xs(D),_=x.useMemo(()=>{const r=new Map(y);for(const d of R)r.set(d.id,d);return r},[y,R]);if(s.items.length===0)return e.jsx("p",{className:"text-meta text-ui-mute",children:"The review found nothing to fix."});const L=(m==null?void 0:m.headSha)??i.headSha,P=r=>{var H,T;const d=V(r,t),f=o.has(r.key),w=j=>c([r.key],j),p=e.jsx(vt,{item:r,picked:d,cut:f,disabled:a,onToggle:w}),N=r.card;switch(N==null?void 0:N.kind){case"finding":{const j=k.get(N.findingId);if(j==null)break;return e.jsx(tt,{authorName:nt(l,j),prId:i.id,finding:j,editable:!1,prUrl:i.githubUrl,repoFullName:i.repoFullName,headSha:L,posting:!1,postError:null,inChangeset:j.fileInDiff,priorStatus:C.get(j.id),alreadyPosted:B.has(j.id),actions:!1,selection:p,docReferences:(m==null?void 0:m.docReferences)??null},r.key)}case"earlier_finding":{const j=M.get(N.priorFindingId);if(j==null)break;return e.jsx(gs,{item:j,muted:!1,findingsById:k,headMoved:((H=u==null?void 0:u.followUp)==null?void 0:H.headMoved)??!1,changedPaths:Z,actions:!1,selection:p,by:v},r.key)}case"thread":return e.jsx(st,{t:N.assessment,muted:!1,actions:!1,selection:p,notCheckedNote:N.inReview?void 0:`${F} didn’t check this one.`,by:F},r.key);case"ci":return e.jsx(et,{f:N.item,suggestion:N.item.suggestion,changedPaths:Z,selection:p},r.key);case"sonar":return e.jsx(Zs,{issue:N.issue,selection:p},r.key);case"story":{const j=_.get(N.ticketReviewId),S=j==null?void 0:j.items.find($=>$.id===N.itemId);if(j==null||S==null)break;const b={review:j,viewedPrId:i.id,changedPaths:Z,actions:!1,selection:p};if(S.status==="missing")return e.jsx(ps,{item:S,...b},r.key);const h=(T=j.assessment)==null?void 0:T.criteria.find($=>$.ref===S.ref);if(h==null||h.status==="met")break;return e.jsx(fs,{c:h,item:S,...b},r.key)}}return e.jsx(wt,{item:r,picked:d,cut:f,disabled:a,onToggle:w},r.key)};return e.jsxs("div",{className:"space-y-3",children:[pt.filter(r=>g.has(r)).map(r=>{const d=g.get(r),f=d.filter(p=>V(p,t)).length,w=f===d.length;return e.jsxs("section",{"aria-label":Ce(r,v),children:[e.jsxs("div",{className:"mb-1 flex items-center gap-2",children:[e.jsx("h4",{className:"text-meta font-semibold text-ui-ink",children:Ce(r,v)}),e.jsxs("span",{className:"text-meta text-ui-mute",children:[f," of ",d.length]}),e.jsx("button",{type:"button",className:"hit ml-auto text-meta text-ui-accent hover:underline disabled:opacity-50",disabled:a,onClick:()=>c(d.map(p=>p.key),!w),children:w?"Untick all":"Tick all"})]}),e.jsx("ul",{className:"space-y-1.5",children:d.map(P)})]},r)}),o.size>0&&e.jsxs("p",{className:"text-meta text-ui-warn",children:[o.size," ticked ",o.size===1?"item does":"items do"," not fit in one fix and will be left out. Untick something to make room."]})]})}const yt="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3",Fe="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function Ke(s){return{prId:s.id,repoId:s.repoId,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title,githubUrl:s.githubUrl}}function Rt(s){const t=bs({mergeable:s.mergeable,mergeStateStatus:s.mergeStateStatus,isDraft:s.isDraft,inMergeQueue:s.inMergeQueue===!0}).verdict;return js({state:s.state,verdict:t,viewerCanPush:s.viewerCanPush})}function Pt({pr:s}){const t=Ns(s.id),n=vs(),a=ws(t),i=s.baseRefName??"the base branch";x.useEffect(()=>{ks(s.id)},[s.id]);const l=Ke(s),o=(t==null?void 0:t.phase)==="succeeded"?t.resolution:null;return e.jsxs("div",{className:"mb-3 rounded-ui bg-ui-surface p-3",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-body font-medium text-ui-ink",children:[e.jsx(ys,{size:13,className:"text-ai-signal"}),"This branch conflicts with ",i]}),e.jsxs("p",{className:"mt-1 text-meta text-ui-mute",children:[n," reads the code and picks a result for each conflict. You check its choices in the resolver before anything is pushed."]}),a&&t!=null?e.jsxs("div",{className:"mt-2",children:[e.jsx(ie,{active:!0,label:`Resolving conflicts with ${n}`,timeConstantSec:60}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[Rs(t.phase,n),e.jsx("button",{type:"button",className:Fe,onClick:()=>Ps(s.id),children:"Cancel"})]})]}):e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx(q,{kind:"resolve",children:e.jsx("button",{type:"button",className:yt,onClick:()=>$e(l,{providerName:n}),children:o!=null?"Run again":`Resolve merge conflicts with ${n}`})}),o!=null&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:Fe,onClick:()=>Cs(l),children:"Open the resolver"}),e.jsxs("span",{className:"text-meta text-ui-mute",children:[G(o)," decided ",o.choices.length," of ",o.decidableTotal," change",o.decidableTotal===1?"":"s","."]})]}),(t==null?void 0:t.phase)==="failed"&&t.error!=null&&e.jsx("span",{className:"text-meta text-ui-danger",children:t.error}),(t==null?void 0:t.phase)==="cancelled"&&e.jsx("span",{className:"text-meta text-ui-mute",children:"Cancelled."})]})]})}const se="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function te(s){return s instanceof Le||s instanceof Error?s.message:"Something went wrong"}const ee="inline-flex h-7 items-center whitespace-nowrap rounded-ui bg-ui-raise px-2.5 text-meta font-medium text-ui-ink hover:bg-ui-hover disabled:cursor-not-allowed disabled:opacity-50 touch:h-10 touch:px-3";function Ct({children:s,info:t}){return e.jsxs("div",{className:"flex items-center gap-1.5 px-4 pb-2 pt-4 text-title text-ui-ink md:px-5",children:[e.jsx("h3",{children:s}),t]})}function Ot({pr:s}){const t=Ue().enabled,n=O(c=>c.aiFixTabFocus),a=O(c=>c.consumeAiFixTabFocus),[i,l]=x.useState(null),[o,g]=x.useState(null);return x.useEffect(()=>{n&&n.prId===s.id&&(n.reviewId!=null&&l(n.reviewId),n.only!=null&&g(n.only),a())},[n,s.id,a]),t?e.jsx("div",{className:"pb-6",children:e.jsx(At,{pr:s,handoffReviewId:i,onlySection:o,onOnlySectionApplied:()=>g(null)})}):e.jsx(e.Fragment,{})}function At({pr:s,handoffReviewId:t,onlySection:n,onOnlySectionApplied:a}){var oe,ue,de,me,he,xe,pe,fe,ge,be;const{data:i,isLoading:l}=As(s.id,!0),{data:o,isLoading:g}=Fs(s.id),c=(o==null?void 0:o.review)??null,m=ct(t,c,(o==null?void 0:o.history)??[]),v=ot(t,m,c),F=O(A=>A.setPrDetailTab),u=Is("fix",Xs),k=Be(u.chosen.provider),M=Ts().data,C=Ss(s.id),B=Es(s.id),E=Te(s.id),I=Ue(),y=_s(M,u.chosen.provider,"plan"),[D,R]=x.useState(!1),_=D&&y,L=O(A=>A.noteAiFixRun),P=Ie({mutationKey:Ms(s.id)})>0,r=((oe=i==null?void 0:i.fix)==null?void 0:oe.status)??null,d=r==="planned",f=d&&((de=(ue=i==null?void 0:i.fix)==null?void 0:ue.plan)==null?void 0:de.status)==="planning",w=r==="running"||r==="queued"||P||f,{status:p}=Bs(s.id,w),N=(p==null?void 0:p.status)??r??"idle",H=N==="running"||N==="queued",T=H&&!d,j=d&&(f||H),S=d&&(((he=(me=i==null?void 0:i.fix)==null?void 0:me.plan)==null?void 0:he.status)==="planning"||((pe=(xe=i==null?void 0:i.fix)==null?void 0:xe.plan)==null?void 0:pe.status)==="plan_ready"),b=(i==null?void 0:i.fix)??null,h=Ls(s.id,m,(i==null?void 0:i.enabled)!==!1&&(m!=null||!g)),$=m==null&&h.data!=null&&h.data.sourceReviewId==null&&h.data.items.length>0,K=m!=null||$,ze=$s(m!=null&&(c==null?void 0:c.id)!==m?m:null),Ve=m!=null&&(c==null?void 0:c.id)===m?c:ze.data??null,[X,J]=x.useState({});x.useEffect(()=>J({}),[m]);const[Ge,W]=x.useState(!1);x.useEffect(()=>{n==null||!h.data||(J(bt(h.data,n)),W(!0),a())},[n,h.data,a]);const re=!S&&(Ge||!b||b.status!=="succeeded"),Q=Rt(s),[le,Xe]=x.useState(!1),Y=Us(s.id,s.repoFullName),U=h.data?gt(h.data,X):[],ce=h.data?We(h.data,X).size:0,Je=()=>{if(!K||!h.data||U.length===0)return;const A={model:u.chosen.model,provider:u.chosen.provider,seed:"review",...m!=null?{sourceReviewId:m}:{},include:U,...Y.names.length>0?{checks:Y.names}:{}};_?B.mutate(A,{onSuccess:()=>W(!1)}):(L({prId:s.id,repoFullName:s.repoFullName,prNumber:s.number,prTitle:s.title}),C.mutate(A,{onSuccess:()=>W(!1)})),le&&Q&&$e(Ke(s),{model:Hs(u.chosen.model),providerName:I.providerName})};return e.jsxs("div",{children:[e.jsx(Ct,{info:e.jsxs(ne,{title:"AI Fix",children:[e.jsxs("p",{children:[k," reads the PR's code and edits files in a private copy. It has no shell. Tick Run tests to let it run the project's own test, lint and type checks in a sandbox."]}),e.jsx("p",{children:"A fix starts from an AI review. Pick what it should work on: the review's findings, earlier findings still open, threads the review says need a fix, unanswered threads, CI failures and ticket gaps are ticked; style bot comments are not."}),e.jsx("p",{children:"With no AI review, a fix can start from a finished CI check: it works on the failures the check says this PR can fix."}),e.jsxs("p",{children:["Tick Plan first to read ",k,"'s plan, steer it and approve it before anything changes."]}),e.jsxs("p",{children:[k," reports what it changed in each file and what it left alone, and why."]}),e.jsx("p",{children:"Nothing is pushed until you press Push. An automatic fix on your own PR is pushed for you only when Push automatically is on in Settings."})]}),children:"AI Fix"}),e.jsxs("div",{className:"px-4",children:[Q&&e.jsx(Pt,{pr:s}),(i==null?void 0:i.enabled)===!1?e.jsx("p",{className:"text-body text-ui-mute",children:"The agentic fixer is turned off."}):e.jsxs(e.Fragment,{children:[!T&&!S&&!K&&!g&&!h.isLoading&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("p",{className:"text-meta text-ui-mute",children:(c==null?void 0:c.status)==="running"||(c==null?void 0:c.status)==="queued"?"A fix starts from an AI review. One is running.":"A fix starts from a finished AI review."}),e.jsx("button",{type:"button",className:se,onClick:()=>F(s.id,"claude_review"),children:"Open AI Review"})]}),!T&&!S&&K&&!re&&e.jsx("button",{type:"button",className:ee,onClick:()=>W(!0),children:"New fix"}),!T&&K&&re&&e.jsxs("div",{children:[v&&e.jsx("p",{className:"mb-2 text-meta text-ui-mute",children:v}),$&&e.jsx("p",{className:"mb-2 text-meta text-ui-mute",children:"No AI review yet. This fix works on the CI check’s failures."}),h.isLoading&&e.jsx("p",{className:"text-meta text-ui-mute",children:"Loading…"}),h.isError&&m!=null&&e.jsx("p",{className:"text-meta text-ui-danger",children:te(h.error)}),h.data&&e.jsx(kt,{preview:h.data,overrides:X,onChange:J,disabled:P,pr:s,review:Ve}),h.data&&h.data.items.length>0&&Q&&e.jsxs("label",{className:"mt-3 flex cursor-pointer items-start gap-2 text-meta text-ui-ink",children:[e.jsx(z,{className:"mt-0.5",checked:le,disabled:P,onChange:A=>Xe(A.target.checked)}),e.jsxs("span",{children:["Also resolve merge conflicts with ",s.baseRefName??"the base branch",e.jsx("span",{className:"block text-meta text-ui-mute",children:"You check the merge in the resolver. It lands as its own commit, apart from the fix."})]})]}),h.data&&h.data.items.length>0&&e.jsx(Os,{state:Y,disabled:P}),h.data&&h.data.items.length>0&&e.jsxs("div",{className:"mt-3 flex flex-wrap items-center gap-2 max-md:sticky max-md:bottom-0 max-md:z-20 max-md:-mx-4 max-md:bg-ui-surface max-md:px-4 max-md:py-3",children:[e.jsx(Ds,{state:u,onPick:u.pick,disabled:P}),y&&e.jsxs("label",{className:"flex cursor-pointer items-center gap-1.5 text-meta text-ui-ink",children:[e.jsx(z,{checked:_,disabled:P,onChange:A=>R(A.target.checked)}),"Plan first"]}),e.jsx(q,{kind:"fix",auth:i==null?void 0:i.auth,anyProvider:!0,provider:u.chosen.provider,children:e.jsx("button",{type:"button",className:se,disabled:P||U.length===0||Y.on&&Y.query.isLoading,onClick:Je,children:_?"Make a plan":"Start fix"})}),e.jsx("span",{className:"text-meta text-ui-mute",children:U.length===0?"Nothing ticked.":`${U.length-ce} item${U.length-ce===1?"":"s"}`}),(b==null?void 0:b.status)==="succeeded"&&e.jsx("button",{type:"button",className:ee,onClick:()=>W(!1),children:"Close"})]})]}),T&&e.jsx("button",{type:"button",className:ee,onClick:()=>E.mutate(),children:"Cancel"}),(C.isError||B.isError)&&e.jsx("p",{className:"mt-1 text-meta text-ui-danger",children:te(C.error??B.error)}),b&&d&&e.jsx(lt,{pr:s,fix:b,liveStatus:p,passRunning:j,auth:i==null?void 0:i.auth}),T&&e.jsxs("div",{className:"mt-3",children:[b&&e.jsx(He,{fix:b}),e.jsx(ie,{active:!0,label:"Running AI fix",value:Ee(p),timeConstantSec:40}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-meta text-ui-mute",children:[(b==null?void 0:b.trigger)==="auto"&&e.jsx(qe,{}),_e[((fe=p==null?void 0:p.progress)==null?void 0:fe.phase)??""]??"Working…"]}),e.jsx(Me,{lines:(ge=p==null?void 0:p.progress)==null?void 0:ge.recentActivity,runKey:(b==null?void 0:b.id)??null,className:"mt-1"})]}),!T&&b&&!d&&e.jsx(It,{pr:s,fix:b,headInfo:(i==null?void 0:i.headInfo)??null,viewerCanPush:(i==null?void 0:i.viewerCanPush)??!1}),l&&!b&&e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"Loading…"})]}),e.jsx(St,{history:(i==null?void 0:i.history)??[],currentFixId:((be=i==null?void 0:i.fix)==null?void 0:be.id)??null})]})]})}function qe(){return e.jsx("span",{className:"inline-flex items-center rounded-ui bg-ui-raise px-1.5 py-px text-meta font-medium text-ui-mute",children:"Auto fix"})}function Ft(s){return Se(s.provider,s.model,s.effort)}function It({pr:s,fix:t,headInfo:n,viewerCanPush:a}){var o,g,c;const i=x.useMemo(()=>Ws(t.patch),[t.patch]);if(t.status==="failed"&&((o=t.plan)==null?void 0:o.status)==="failed")return e.jsxs("div",{className:"mt-3 rounded-ui border border-ui-danger/40 bg-ui-danger/10 p-2 text-meta text-ui-danger",children:[G(t.plan??t)," could not make a plan: ",t.error??"unknown error"]});if(t.status==="cancelled"&&((g=t.plan)==null?void 0:g.status)==="discarded")return e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"The plan was discarded."});if(t.status==="failed")return e.jsxs("div",{className:"mt-3 rounded-ui border border-ui-danger/40 bg-ui-danger/10 p-2 text-meta text-ui-danger",children:["The fix run failed: ",t.error??"unknown error"]});if(t.status==="cancelled")return e.jsx("p",{className:"mt-3 text-meta text-ui-mute",children:"The fix run was cancelled."});if(t.status!=="succeeded")return e.jsx(e.Fragment,{});const l=!t.patch||t.filesChanged.length===0;return e.jsxs("div",{className:"mt-3 border-t border-ui-line pt-3",children:[e.jsxs("p",{className:"mb-1 text-meta text-ui-mute",children:[t.trigger==="auto"&&e.jsxs(e.Fragment,{children:[e.jsx(qe,{})," "]}),ht(t)," · ",Ft(t),t.finishedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(t.finishedAt)]})]}),t.pushedAt==null&&t.error&&e.jsx("p",{className:"mb-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-warn",children:t.error}),e.jsx(He,{fix:t}),t.summary&&e.jsx("div",{className:"prose prose-sm max-w-none dark:prose-invert",children:e.jsx(Ys,{children:t.summary})}),e.jsx(xt,{pr:s,fix:t}),e.jsx(Ks,{checks:t.checks}),l?e.jsx("p",{className:"mt-2 text-meta text-ui-mute",children:"No files changed."}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-1 mt-2 flex items-center justify-between gap-3 text-meta text-ui-mute",children:[e.jsxs("span",{children:[t.filesChanged.length," file",t.filesChanged.length===1?"":"s"," changed",!((c=t.checks)!=null&&c.ran)&&" · Not built or tested here."]}),e.jsx(qs,{})]}),e.jsx("div",{className:"overflow-hidden rounded-ui bg-ui-surface text-ui-ink",children:e.jsx(zs,{files:i})}),e.jsx(Et,{pr:s,fix:t,headInfo:n,viewerCanPush:a})]})]})}function Tt({fix:s}){return e.jsxs("div",{className:"mb-2 rounded-ui bg-ui-raise p-2 text-meta text-ui-success",children:[e.jsxs("div",{children:["Pushed to ",e.jsx("span",{className:"font-mono",children:s.pushedBranch}),s.pushedPrUrl&&e.jsxs(e.Fragment,{children:[" · ",e.jsxs("a",{href:Oe(s.pushedPrUrl),target:"_blank",rel:"noreferrer",className:"hit underline",children:["PR #",s.pushedPrNumber]})]}),s.pushedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(s.pushedAt)]})]}),s.commitMessage&&e.jsx("div",{className:"mt-1 font-mono text-meta text-ui-success",children:s.commitMessage})]})}function St({history:s,currentFixId:t}){const n=s.filter(a=>a.pushedAt!=null&&a.id!==t);return n.length===0?null:e.jsxs("div",{className:"mt-6",children:[e.jsx("div",{className:"mb-2 text-title text-ui-ink",children:"Earlier fixes pushed"}),e.jsx("ul",{className:"space-y-2",children:n.map(a=>e.jsxs("li",{className:"text-meta",children:[e.jsx("div",{className:"font-mono text-ui-ink",children:a.commitMessage??"(no commit message)"}),e.jsxs("div",{className:"mt-0.5 text-meta text-ui-faint",children:[a.pushedBranch&&e.jsx("span",{className:"font-mono",children:a.pushedBranch}),a.pushedPrUrl&&e.jsxs(e.Fragment,{children:[" · ",e.jsxs("a",{href:Oe(a.pushedPrUrl),target:"_blank",rel:"noreferrer",className:"hit underline",children:["PR #",a.pushedPrNumber]})]}),a.pushedAt&&e.jsxs(e.Fragment,{children:[" · ",ae(a.pushedAt)]})]})]},a.id))})]})}function Et({pr:s,fix:t,headInfo:n,viewerCanPush:a}){const i=Vs(s.id),l=(n==null?void 0:n.canPushSameBranch)??!1,[o,g]=x.useState(l?"existing":"new"),[c,m]=x.useState((n==null?void 0:n.suggestedBranch)??""),v=x.useRef(!1);if(x.useEffect(()=>{!v.current&&(n!=null&&n.suggestedBranch)&&(m(n.suggestedBranch),v.current=!0,n.canPushSameBranch||g("new"))},[n]),t.pushedAt!=null)return e.jsx(Tt,{fix:t});if(!a)return e.jsx("p",{className:"mt-2 text-meta text-ui-mute",children:"You need write access to push this fix."});const F=o==="new"&&c.trim().length===0,u=i.isPending,k=()=>{i.mutate({fixId:t.id,body:{target:o,branch:o==="new"?c.trim():void 0}})};return e.jsxs("div",{className:"mt-3 rounded-ui bg-ui-surface p-2",children:[t.commitMessage&&e.jsx("div",{className:"mb-2 rounded-ui bg-ui-surface px-2 py-1 font-mono text-meta text-ui-ink",title:"Commit message",children:t.commitMessage}),e.jsxs("label",{className:`flex items-center gap-2 text-meta ${l?"":"opacity-40"}`,title:l?void 0:"The PR head is a fork you cannot push to — use a new branch",children:[e.jsx(ve,{className:"mt-0",checked:o==="existing",disabled:!l||u,onChange:()=>g("existing")}),"Push to the PR branch",(n==null?void 0:n.headRef)&&e.jsxs("span",{className:"font-mono text-ui-faint",children:["(",n.headRef,")"]})]}),e.jsxs("label",{className:"mt-1 flex items-center gap-2 text-meta",children:[e.jsx(ve,{className:"mt-0",checked:o==="new",disabled:u,onChange:()=>g("new")}),"New branch + open a PR"]}),o==="new"&&e.jsx("input",{type:"text",className:"mt-1 w-full rounded-ui bg-ui-raise px-2 py-1 font-mono text-meta ring-1 ring-inset ring-ui-line focus:outline-none focus:ring-2 focus:ring-ui-accent touch:min-h-10",value:c,disabled:u,onChange:M=>m(M.target.value),placeholder:"branch-name"}),e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",className:se,disabled:u||F,onClick:k,children:u?"Pushing…":o==="new"?"Push + open PR":"Push"}),e.jsx(Gs,{checks:t.checks})]}),i.isError&&e.jsx("div",{className:"mt-2 text-meta text-ui-danger",children:te(i.error)})]})}export{Ot as AiFixTab};
|