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.
@@ -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: f.title,
763
- body: f.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,6 +1,6 @@
1
1
  {
2
2
  "name": "limn-review",
3
- "version": "0.1.182",
3
+ "version": "0.1.183",
4
4
  "description": "Dashboard for tracking your team's GitHub PR activity across repos. Runs on your machine with your gh login.",
5
5
  "type": "module",
6
6
  "author": "Alex Wakeman",
@@ -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};