@agimon-ai/po-git 0.0.0-alpha.24 → 0.0.0-alpha.26

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,12 +1,12 @@
1
1
  import { createApiClient, defineActivityGroup, defineChannelFile, defineFill, defineGlobalStore, defineNativePlugin, defineSessionStore, defineWebLifecycle, nativeApiTransport, sessionApiAddress } from "@agimon-ai/po-core/native";
2
- import { ArrowRightIcon, BranchIcon, Button, Dot, Input, ListRow, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Textarea, fontOf } from "@agimon-ai/po-native-components";
2
+ import { AlertIcon, Badge, BranchIcon, Button, ChevronRightIcon, Dot, FileIcon, Input, MessageIcon, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Spinner, SyntaxLine, Textarea, fontOf } from "@agimon-ai/po-native-components";
3
3
  import { createElement, useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { View } from "react-native-unistyles/components/native/View";
5
5
  import { Text } from "react-native-unistyles/components/native/Text";
6
6
  import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
7
- import { StyleSheet } from "react-native-unistyles";
8
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
7
  import { Pressable } from "react-native-unistyles/components/native/Pressable";
8
+ import { StyleSheet, useUnistyles } from "react-native-unistyles";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/types/webWorktrees.ts
11
11
  /**
12
12
  * The cockpit's view of this session's worktrees.
@@ -44,6 +44,15 @@ const GIT_WORKTREES_TYPE = "git_worktrees";
44
44
  * - `sendSessionFrame` for a command. It envelopes the frame as a session
45
45
  * command bound for the agent, which never reaches a channel's `receive`.
46
46
  */
47
+ /** Presentation state follows hub operation labels, including session startup progress. */
48
+ function worktreesPresentation(state) {
49
+ return {
50
+ working: state.worktrees.filter((item) => !item.orphaned && !item.unowned),
51
+ attention: state.worktrees.filter((item) => item.orphaned || item.unowned),
52
+ starting: state.requestedBranch !== void 0 ? !state.error && !state.worktrees.some((item) => item.branch === state.requestedBranch) : !!state.pending && /^(creating|starting session)/i.test(state.pending),
53
+ closeErrorId: state.errorTarget?.action === "close" ? state.errorTarget.id : void 0
54
+ };
55
+ }
47
56
  const worktreeActivity = defineSessionStore({
48
57
  worktrees: [],
49
58
  pending: void 0,
@@ -118,8 +127,12 @@ const worktreesChannel = worktreeActivity.channel({
118
127
  errorTarget: optionalErrorTarget$1(input.errorTarget)
119
128
  };
120
129
  },
121
- reduce(_current, next) {
122
- return next;
130
+ reduce(current, next) {
131
+ const requestedBranch = current.requestedBranch;
132
+ return {
133
+ ...next,
134
+ ...requestedBranch && next.pending && !next.error ? { requestedBranch } : {}
135
+ };
123
136
  }
124
137
  });
125
138
  /** Sends one command to the session's worktrees channel. */
@@ -133,6 +146,13 @@ function command(sessionId, payload) {
133
146
  /** Asks the hub for a worktree. The hub answers on the same channel. */
134
147
  function requestWorktreeCreate(sessionId, branch, baseRef, reservationId) {
135
148
  const trimmedBase = baseRef.trim();
149
+ if (worktreeSender.store.state) worktreeActivity.update(sessionId, (current) => ({
150
+ ...current,
151
+ requestedBranch: branch.trim(),
152
+ pending: "creating",
153
+ error: void 0,
154
+ errorTarget: void 0
155
+ }));
136
156
  command(sessionId, {
137
157
  action: "create",
138
158
  branch: branch.trim(),
@@ -163,137 +183,507 @@ function worktreesTab() {
163
183
  panel: WorktreesPanel
164
184
  };
165
185
  }
166
- function WorktreesPanel({ sessionId, sessionReservationId, openSession }) {
167
- const state = useWorktrees(sessionId);
168
- const [creating, setCreating] = useState(false);
169
- const [branch, setBranch] = useState("");
170
- const [baseRef, setBaseRef] = useState("");
171
- const [closing, setClosing] = useState();
172
- const busy = state.pending !== void 0;
173
- return /* @__PURE__ */ jsxs(ScrollView, {
174
- contentContainerStyle: styles$2.body,
186
+ function WorktreesHeader({ activity = false, onNew, disabled = false }) {
187
+ return /* @__PURE__ */ jsxs(View, {
188
+ style: styles$2.header,
189
+ children: [/* @__PURE__ */ jsx(Text, {
190
+ style: styles$2.title,
191
+ children: activity ? "Activity" : "Worktrees"
192
+ }), !activity ? /* @__PURE__ */ jsx(Button, {
193
+ testID: "git-worktree-create",
194
+ variant: "ghost",
195
+ style: styles$2.newPill,
196
+ disabled,
197
+ onPress: onNew,
198
+ children: /* @__PURE__ */ jsx(Text, {
199
+ style: styles$2.jade,
200
+ children: "+ New"
201
+ })
202
+ }) : null]
203
+ });
204
+ }
205
+ function WorktreeRow({ item, error, compact = false, onClose, onOpen, disabled = false }) {
206
+ return /* @__PURE__ */ jsxs(View, {
207
+ style: styles$2.worktree,
175
208
  children: [
176
- /* @__PURE__ */ jsx(Button, {
177
- testID: "git-worktree-create",
178
- disabled: sessionId === null || busy,
179
- onPress: () => setCreating(true),
180
- children: "Create a worktree"
181
- }),
182
- state.pending ? /* @__PURE__ */ jsx(Text, {
183
- style: styles$2.meta,
184
- children: state.pending
185
- }) : null,
186
- state.error ? /* @__PURE__ */ jsx(Text, {
187
- style: styles$2.error,
188
- children: state.error
189
- }) : null,
190
- state.worktrees.map((worktree) => /* @__PURE__ */ jsxs(View, {
191
- style: styles$2.card,
209
+ /* @__PURE__ */ jsxs(View, {
210
+ style: styles$2.line,
192
211
  children: [
193
- /* @__PURE__ */ jsx(ListRow, {
194
- title: worktree.branch,
195
- description: `${worktree.path}${worktree.orphaned ? "\nOrphaned" : ""}${worktree.unowned ? "\nUnowned" : ""}`
212
+ /* @__PURE__ */ jsx(Dot, {
213
+ tone: item.orphaned ? "yellow" : item.unowned ? "blue" : "green",
214
+ size: "md"
196
215
  }),
197
- worktree.sessionId && openSession ? /* @__PURE__ */ jsx(Button, {
198
- variant: "outline",
199
- onPress: () => openSession(worktree.sessionId),
200
- children: "Open session"
216
+ /* @__PURE__ */ jsxs(Pressable, {
217
+ style: styles$2.grow,
218
+ accessibilityRole: onOpen ? "button" : void 0,
219
+ accessibilityLabel: onOpen ? `Open session for ${item.branch}` : void 0,
220
+ onPress: onOpen,
221
+ disabled: !onOpen,
222
+ children: [/* @__PURE__ */ jsx(Text, {
223
+ numberOfLines: 1,
224
+ ellipsizeMode: "middle",
225
+ style: styles$2.branch,
226
+ children: compact && item.branch.length > 36 ? `${item.branch.slice(0, 19)}…${item.branch.slice(-14)}` : item.branch
227
+ }), !compact ? /* @__PURE__ */ jsx(Text, {
228
+ style: styles$2.dim,
229
+ children: item.orphaned ? "Its folder is missing" : item.unowned ? "Its session has ended" : "Session running"
230
+ }) : null]
231
+ }),
232
+ item.orphaned ? /* @__PURE__ */ jsx(Badge, {
233
+ tone: "yellow",
234
+ style: styles$2.caution,
235
+ children: "Orphaned"
236
+ }) : null,
237
+ item.unowned ? /* @__PURE__ */ jsx(Badge, {
238
+ tone: "blue",
239
+ style: styles$2.info,
240
+ children: "Unowned"
201
241
  }) : null,
202
- /* @__PURE__ */ jsx(Button, {
203
- variant: "danger-outline",
204
- disabled: sessionId === null || busy,
205
- testID: `git-worktree-close-${worktree.id}`,
206
- onPress: () => setClosing(worktree.id),
207
- children: "Close worktree"
242
+ !compact ? /* @__PURE__ */ jsx(Button, {
243
+ variant: "ghost",
244
+ style: styles$2.more,
245
+ accessibilityLabel: `Close ${item.branch}`,
246
+ testID: `git-worktree-close-${item.id}`,
247
+ onPress: onClose,
248
+ disabled,
249
+ children: "⋮"
250
+ }) : /* @__PURE__ */ jsx(ChevronRightIcon, {
251
+ size: 16,
252
+ color: "dim"
208
253
  })
209
254
  ]
210
- }, worktree.id)),
211
- state.worktrees.length === 0 ? /* @__PURE__ */ jsx(Text, {
212
- style: styles$2.meta,
213
- children: "No worktrees yet. A worktree is its own checkout, branch and session."
255
+ }),
256
+ !compact ? /* @__PURE__ */ jsx(Text, {
257
+ numberOfLines: 1,
258
+ ellipsizeMode: "middle",
259
+ style: styles$2.path,
260
+ children: item.path
214
261
  }) : null,
215
- /* @__PURE__ */ jsx(Sheet, {
216
- open: creating,
217
- onOpenChange: setCreating,
218
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Create a worktree" }) }), /* @__PURE__ */ jsx(SheetBody, { children: /* @__PURE__ */ jsxs(View, {
262
+ error ? /* @__PURE__ */ jsx(Text, {
263
+ accessibilityRole: "alert",
264
+ style: styles$2.error,
265
+ children: error
266
+ }) : null
267
+ ]
268
+ });
269
+ }
270
+ function WorktreeStarting({ branch }) {
271
+ return /* @__PURE__ */ jsxs(View, {
272
+ style: styles$2.starting,
273
+ children: [/* @__PURE__ */ jsx(Spinner, { label: "Starting session..." }), /* @__PURE__ */ jsxs(View, {
274
+ style: styles$2.grow,
275
+ children: [branch ? /* @__PURE__ */ jsx(Text, {
276
+ numberOfLines: 1,
277
+ ellipsizeMode: "middle",
278
+ style: styles$2.branch,
279
+ children: branch
280
+ }) : null, /* @__PURE__ */ jsx(Text, {
281
+ style: styles$2.dim,
282
+ children: "Starting session..."
283
+ })]
284
+ })]
285
+ });
286
+ }
287
+ function WorktreeGroup({ title, count }) {
288
+ return /* @__PURE__ */ jsxs(View, {
289
+ style: styles$2.group,
290
+ children: [/* @__PURE__ */ jsx(Text, {
291
+ style: styles$2.heading,
292
+ children: title
293
+ }), /* @__PURE__ */ jsx(Text, {
294
+ style: styles$2.dim,
295
+ children: count
296
+ })]
297
+ });
298
+ }
299
+ function WorktreeForm({ close = false, branch = "", baseRef = "", onBranch, onBaseRef, onConfirm, onCancel, disabled = false, framed = true }) {
300
+ return /* @__PURE__ */ jsxs(View, {
301
+ style: [styles$2.sheet, !framed && styles$2.unframed],
302
+ children: [
303
+ framed ? /* @__PURE__ */ jsx(View, { style: styles$2.handle }) : null,
304
+ /* @__PURE__ */ jsx(Text, {
305
+ style: styles$2.sheetTitle,
306
+ children: close ? "Close this worktree?" : "New worktree"
307
+ }),
308
+ close ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
309
+ style: styles$2.branch,
310
+ children: branch
311
+ }), /* @__PURE__ */ jsx(Text, {
312
+ style: styles$2.body,
313
+ children: "Removes the checkout and stops its session."
314
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
315
+ /* @__PURE__ */ jsx(Text, {
219
316
  style: styles$2.body,
220
- children: [
221
- /* @__PURE__ */ jsx(Input, {
222
- accessibilityLabel: "Branch",
223
- placeholder: "wt/fix-auth",
224
- value: branch,
225
- onChangeText: setBranch
226
- }),
227
- /* @__PURE__ */ jsx(Input, {
228
- accessibilityLabel: "Base ref",
229
- placeholder: "Base (current)",
230
- value: baseRef,
231
- onChangeText: setBaseRef
317
+ children: "A separate checkout on its own branch, with its own session. This session stays where it is."
318
+ }),
319
+ /* @__PURE__ */ jsx(Text, {
320
+ style: styles$2.label,
321
+ children: "Branch"
322
+ }),
323
+ /* @__PURE__ */ jsx(Input, {
324
+ accessibilityLabel: "Branch",
325
+ value: branch,
326
+ onChangeText: onBranch,
327
+ style: styles$2.monoInput
328
+ }),
329
+ /* @__PURE__ */ jsx(Text, {
330
+ style: styles$2.label,
331
+ children: "Start from"
332
+ }),
333
+ /* @__PURE__ */ jsx(Input, {
334
+ accessibilityLabel: "Start from",
335
+ value: baseRef,
336
+ onChangeText: onBaseRef,
337
+ placeholder: "Current branch"
338
+ })
339
+ ] }),
340
+ /* @__PURE__ */ jsx(Button, {
341
+ onPress: onConfirm,
342
+ disabled: disabled || !close && branch.trim() === "",
343
+ variant: close ? "danger" : "primary",
344
+ style: [styles$2.fullButton, !close && styles$2.createButton],
345
+ children: close ? "Close worktree" : /* @__PURE__ */ jsx(Text, {
346
+ style: styles$2.createLabel,
347
+ children: "Create worktree"
348
+ })
349
+ }),
350
+ /* @__PURE__ */ jsx(Button, {
351
+ variant: "outline",
352
+ style: styles$2.fullButton,
353
+ onPress: onCancel,
354
+ children: "Cancel"
355
+ })
356
+ ]
357
+ });
358
+ }
359
+ function WorktreesView({ state, disabled = false, onNew, onClose, onOpen }) {
360
+ const { working, attention, starting, closeErrorId } = worktreesPresentation(state);
361
+ const row = (item) => /* @__PURE__ */ jsx(WorktreeRow, {
362
+ item,
363
+ disabled: disabled || !!state.pending,
364
+ onClose: () => onClose?.(item),
365
+ onOpen: item.sessionId && onOpen ? () => onOpen(item.sessionId) : void 0,
366
+ error: state.errorTarget?.action === "close" && state.errorTarget.id === item.id ? state.error : void 0
367
+ }, item.id);
368
+ return /* @__PURE__ */ jsxs(View, {
369
+ style: styles$2.screen,
370
+ children: [
371
+ /* @__PURE__ */ jsx(WorktreesHeader, {
372
+ disabled: disabled || !!state.pending,
373
+ onNew
374
+ }),
375
+ state.worktrees.length || starting ? /* @__PURE__ */ jsxs(View, {
376
+ style: styles$2.content,
377
+ children: [
378
+ /* @__PURE__ */ jsx(WorktreeGroup, {
379
+ title: "Working",
380
+ count: `${working.length} open${starting ? " · 1 starting" : ""}`
381
+ }),
382
+ working.map(row),
383
+ starting ? /* @__PURE__ */ jsx(WorktreeStarting, { branch: state.requestedBranch }) : null,
384
+ attention.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
385
+ /* @__PURE__ */ jsx(WorktreeGroup, {
386
+ title: "Needs a look",
387
+ count: `${attention.length} open`
232
388
  }),
233
- /* @__PURE__ */ jsx(Text, {
234
- style: styles$2.meta,
235
- children: "Creates the worktree outside the repository and starts a session nested under this one."
389
+ /* @__PURE__ */ jsxs(Text, {
390
+ style: styles$2.dim,
391
+ children: [
392
+ attention.length === 2 ? "Two worktrees" : attention.length === 1 ? "One worktree" : `${attention.length} worktrees`,
393
+ " ",
394
+ "would like your eye, whenever you are ready."
395
+ ]
236
396
  }),
237
- /* @__PURE__ */ jsx(Button, {
238
- disabled: sessionId === null || busy || branch.trim() === "",
239
- onPress: () => {
240
- if (sessionId === null) return;
241
- requestWorktreeCreate(sessionId, branch, baseRef, sessionReservationId);
242
- setCreating(false);
243
- if (sessionReservationId === void 0) {
244
- setBranch("");
245
- setBaseRef("");
246
- }
247
- },
248
- children: "Create"
249
- })
250
- ]
251
- }) })] })
397
+ attention.map(row)
398
+ ] }) : null
399
+ ]
400
+ }) : /* @__PURE__ */ jsxs(View, {
401
+ style: styles$2.empty,
402
+ children: [/* @__PURE__ */ jsx(Text, {
403
+ style: styles$2.heading,
404
+ children: "No worktrees yet"
405
+ }), /* @__PURE__ */ jsx(Text, {
406
+ style: styles$2.emptyCopy,
407
+ children: "Create a worktree to run a separate session on its own branch."
408
+ })]
252
409
  }),
253
- /* @__PURE__ */ jsx(Sheet, {
254
- open: closing !== void 0,
255
- onOpenChange: (open) => {
256
- if (!open) setClosing(void 0);
257
- },
258
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Close this worktree?" }) }), /* @__PURE__ */ jsxs(SheetBody, { children: [/* @__PURE__ */ jsx(Text, {
259
- style: styles$2.meta,
260
- children: "The checkout is removed. Git refuses a dirty worktree."
261
- }), /* @__PURE__ */ jsx(Button, {
262
- variant: "danger-outline",
263
- disabled: busy,
264
- onPress: () => {
265
- if (sessionId !== null && closing !== void 0) requestWorktreeClose(sessionId, closing);
266
- setClosing(void 0);
267
- },
268
- children: "Close worktree"
269
- })] })] })
270
- })
410
+ state.pending && !starting ? /* @__PURE__ */ jsx(Text, {
411
+ style: styles$2.dim,
412
+ children: state.pending
413
+ }) : null,
414
+ state.error && (!closeErrorId || !state.worktrees.some((item) => item.id === closeErrorId)) ? /* @__PURE__ */ jsx(Text, {
415
+ accessibilityRole: "alert",
416
+ style: styles$2.error,
417
+ children: state.error
418
+ }) : null
271
419
  ]
272
420
  });
273
421
  }
422
+ function WorktreesPanel({ sessionId, sessionReservationId, openSession }) {
423
+ const state = useWorktrees(sessionId);
424
+ const [creating, setCreating] = useState(false);
425
+ const [branch, setBranch] = useState("");
426
+ const [baseRef, setBaseRef] = useState("");
427
+ const [closing, setClosing] = useState();
428
+ const busy = sessionId === null || state.pending !== void 0;
429
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
430
+ /* @__PURE__ */ jsx(ScrollView, {
431
+ contentContainerStyle: styles$2.scroll,
432
+ children: /* @__PURE__ */ jsx(WorktreesView, {
433
+ state,
434
+ disabled: sessionId === null,
435
+ onNew: () => setCreating(true),
436
+ onClose: setClosing,
437
+ onOpen: openSession
438
+ })
439
+ }),
440
+ /* @__PURE__ */ jsx(Sheet, {
441
+ open: creating,
442
+ onOpenChange: setCreating,
443
+ children: /* @__PURE__ */ jsx(SheetContent, { children: /* @__PURE__ */ jsx(WorktreeForm, {
444
+ framed: false,
445
+ branch,
446
+ baseRef,
447
+ onBranch: setBranch,
448
+ onBaseRef: setBaseRef,
449
+ disabled: busy,
450
+ onCancel: () => setCreating(false),
451
+ onConfirm: () => {
452
+ if (sessionId === null) return;
453
+ requestWorktreeCreate(sessionId, branch, baseRef, sessionReservationId);
454
+ setCreating(false);
455
+ if (sessionReservationId === void 0) {
456
+ setBranch("");
457
+ setBaseRef("");
458
+ }
459
+ }
460
+ }) })
461
+ }),
462
+ /* @__PURE__ */ jsx(Sheet, {
463
+ open: !!closing,
464
+ onOpenChange: (open) => {
465
+ if (!open) setClosing(void 0);
466
+ },
467
+ children: /* @__PURE__ */ jsx(SheetContent, { children: /* @__PURE__ */ jsx(WorktreeForm, {
468
+ framed: false,
469
+ close: true,
470
+ branch: closing?.branch,
471
+ disabled: busy,
472
+ onCancel: () => setClosing(void 0),
473
+ onConfirm: () => {
474
+ if (sessionId !== null && closing) requestWorktreeClose(sessionId, closing.id);
475
+ setClosing(void 0);
476
+ }
477
+ }) })
478
+ })
479
+ ] });
480
+ }
274
481
  const styles$2 = StyleSheet.create((theme) => ({
275
- body: {
276
- padding: theme.spacing(3),
482
+ screen: {
483
+ flex: 1,
484
+ backgroundColor: theme.colors.rail,
485
+ uni__dependencies: [0]
486
+ },
487
+ scroll: { flexGrow: 1 },
488
+ header: {
489
+ flexDirection: "row",
490
+ alignItems: "center",
491
+ justifyContent: "space-between",
492
+ padding: theme.spacing(5),
493
+ minHeight: 88,
494
+ uni__dependencies: [0]
495
+ },
496
+ title: {
497
+ fontFamily: fontOf(theme.fontFamily.sans),
498
+ fontSize: theme.fontSize["2xl"],
499
+ fontWeight: "600",
500
+ color: theme.colors.hi,
501
+ uni__dependencies: [0]
502
+ },
503
+ newPill: {
504
+ backgroundColor: theme.colors["tint-green"],
505
+ borderRadius: theme.borderRadius.full,
506
+ minHeight: 44,
507
+ paddingHorizontal: theme.spacing(4),
508
+ uni__dependencies: [0]
509
+ },
510
+ content: {
511
+ paddingHorizontal: theme.spacing(5),
277
512
  gap: theme.spacing(2),
278
513
  uni__dependencies: [0]
279
514
  },
280
- card: {
281
- borderWidth: 1,
515
+ group: {
516
+ flexDirection: "row",
517
+ alignItems: "center",
518
+ gap: theme.spacing(3),
519
+ paddingTop: theme.spacing(4),
520
+ paddingBottom: theme.spacing(2),
521
+ borderBottomWidth: StyleSheet.hairlineWidth,
282
522
  borderColor: theme.colors["border-soft"],
283
- borderRadius: theme.borderRadius.md,
284
- backgroundColor: theme.colors.panel,
285
- padding: theme.spacing(2),
286
- gap: theme.spacing(1),
287
523
  uni__dependencies: [0]
288
524
  },
289
- meta: {
525
+ heading: {
526
+ fontFamily: fontOf(theme.fontFamily.sans),
527
+ fontSize: theme.fontSize.lg,
528
+ lineHeight: theme.lineHeight.lg,
529
+ fontWeight: "600",
530
+ color: theme.colors.hi,
531
+ uni__dependencies: [0]
532
+ },
533
+ dim: {
534
+ fontFamily: fontOf(theme.fontFamily.sans),
535
+ fontSize: theme.fontSize.sm,
536
+ lineHeight: theme.lineHeight.sm,
537
+ color: theme.colors.dim,
538
+ uni__dependencies: [0]
539
+ },
540
+ body: {
541
+ fontFamily: fontOf(theme.fontFamily.sans),
542
+ fontSize: theme.fontSize.base,
543
+ lineHeight: theme.lineHeight.lg,
290
544
  color: theme.colors.dim,
545
+ uni__dependencies: [0]
546
+ },
547
+ label: {
548
+ fontFamily: fontOf(theme.fontFamily.sans),
549
+ fontSize: theme.fontSize.base,
550
+ fontWeight: "500",
551
+ color: theme.colors.text,
552
+ marginTop: theme.spacing(2),
553
+ uni__dependencies: [0]
554
+ },
555
+ branch: {
556
+ fontFamily: fontOf(theme.fontFamily.mono),
557
+ fontSize: theme.fontSize.base,
558
+ lineHeight: theme.lineHeight.lg,
559
+ color: theme.colors.hi,
560
+ uni__dependencies: [0]
561
+ },
562
+ path: {
563
+ fontFamily: fontOf(theme.fontFamily.mono),
291
564
  fontSize: theme.fontSize.sm,
565
+ lineHeight: theme.lineHeight.sm,
566
+ color: theme.colors.dim,
567
+ marginLeft: theme.spacing(4.5),
568
+ uni__dependencies: [0]
569
+ },
570
+ worktree: {
571
+ gap: theme.spacing(1),
572
+ paddingVertical: theme.spacing(2),
573
+ borderBottomWidth: StyleSheet.hairlineWidth,
574
+ borderColor: theme.colors["border-soft"],
575
+ uni__dependencies: [0]
576
+ },
577
+ line: {
578
+ flexDirection: "row",
579
+ alignItems: "center",
580
+ gap: theme.spacing(2),
581
+ minHeight: 44,
582
+ uni__dependencies: [0]
583
+ },
584
+ grow: {
585
+ flex: 1,
586
+ minWidth: 0,
587
+ minHeight: 44,
588
+ justifyContent: "center",
589
+ gap: theme.spacing(1),
590
+ uni__dependencies: [0]
591
+ },
592
+ more: {
593
+ width: 44,
594
+ height: 44,
595
+ padding: 0
596
+ },
597
+ caution: {
598
+ backgroundColor: theme.colors["tint-yellow"],
599
+ uni__dependencies: [0]
600
+ },
601
+ info: {
602
+ backgroundColor: theme.colors["tint-blue"],
603
+ uni__dependencies: [0]
604
+ },
605
+ starting: {
606
+ flexDirection: "row",
607
+ alignItems: "center",
608
+ gap: theme.spacing(2),
609
+ minHeight: 52,
610
+ uni__dependencies: [0]
611
+ },
612
+ jade: {
613
+ fontFamily: fontOf(theme.fontFamily.sans),
614
+ fontSize: theme.fontSize.base,
615
+ lineHeight: theme.lineHeight.base,
616
+ color: theme.colors.green,
617
+ fontWeight: "500",
292
618
  uni__dependencies: [0]
293
619
  },
294
620
  error: {
295
- color: theme.colors.red,
621
+ fontFamily: fontOf(theme.fontFamily.sans),
296
622
  fontSize: theme.fontSize.sm,
623
+ lineHeight: theme.lineHeight.sm,
624
+ color: theme.colors.red,
625
+ uni__dependencies: [0]
626
+ },
627
+ unframed: { borderTopWidth: 0 },
628
+ sheet: {
629
+ backgroundColor: theme.colors.bg,
630
+ borderTopWidth: 1,
631
+ borderColor: theme.colors.border,
632
+ borderTopLeftRadius: theme.borderRadius.lg,
633
+ borderTopRightRadius: theme.borderRadius.lg,
634
+ padding: theme.spacing(5),
635
+ gap: theme.spacing(3),
636
+ uni__dependencies: [0]
637
+ },
638
+ handle: {
639
+ alignSelf: "center",
640
+ width: 40,
641
+ height: 4,
642
+ borderRadius: theme.borderRadius.full,
643
+ backgroundColor: theme.colors.border,
644
+ marginBottom: theme.spacing(2),
645
+ uni__dependencies: [0]
646
+ },
647
+ sheetTitle: {
648
+ fontFamily: fontOf(theme.fontFamily.sans),
649
+ fontSize: theme.fontSize.xl,
650
+ fontWeight: "600",
651
+ color: theme.colors.hi,
652
+ uni__dependencies: [0]
653
+ },
654
+ monoInput: {
655
+ fontFamily: fontOf(theme.fontFamily.mono),
656
+ uni__dependencies: [0]
657
+ },
658
+ fullButton: {
659
+ height: 44,
660
+ alignSelf: "stretch"
661
+ },
662
+ createButton: {
663
+ backgroundColor: theme.colors.green,
664
+ uni__dependencies: [0]
665
+ },
666
+ createLabel: {
667
+ fontFamily: fontOf(theme.fontFamily.sans),
668
+ fontSize: theme.fontSize.base,
669
+ fontWeight: "600",
670
+ color: theme.colors.bg,
671
+ uni__dependencies: [0]
672
+ },
673
+ empty: {
674
+ flex: 1,
675
+ alignItems: "center",
676
+ justifyContent: "center",
677
+ padding: theme.spacing(8),
678
+ gap: theme.spacing(3),
679
+ uni__dependencies: [0]
680
+ },
681
+ emptyCopy: {
682
+ fontFamily: fontOf(theme.fontFamily.sans),
683
+ fontSize: theme.fontSize.base,
684
+ lineHeight: theme.lineHeight.lg,
685
+ color: theme.colors.dim,
686
+ textAlign: "center",
297
687
  uni__dependencies: [0]
298
688
  }
299
689
  }));
@@ -571,6 +961,31 @@ async function fetchReviewFile(sessionId, path, signal) {
571
961
  };
572
962
  }
573
963
  //#endregion
964
+ //#region src/extensions/workspaces/sessions/(frontend)/_lib/gitReviewSelection.ts
965
+ /** A different side starts a fresh selection. The second same-side tap completes it. */
966
+ function selectReviewLine(anchor, row) {
967
+ const side = row.marker === "-" ? "old" : "new";
968
+ if (!anchor || anchor.side !== side) return {
969
+ range: {
970
+ side,
971
+ startLine: row.line,
972
+ endLine: row.line
973
+ },
974
+ complete: false
975
+ };
976
+ return {
977
+ range: {
978
+ side,
979
+ startLine: Math.min(anchor.startLine, row.line),
980
+ endLine: Math.max(anchor.startLine, row.line)
981
+ },
982
+ complete: true
983
+ };
984
+ }
985
+ function reviewRangeRows(rows, range) {
986
+ return rows.filter((row) => (row.marker === "-" ? "old" : "new") === range.side && row.line >= range.startLine && row.line <= range.endLine);
987
+ }
988
+ //#endregion
574
989
  //#region src/extensions/workspaces/sessions/(frontend)/_lib/gitReviewStore.native.ts
575
990
  const gitReview = defineSessionStore({ comments: [] });
576
991
  function addReviewComment(sessionId, comment) {
@@ -616,6 +1031,23 @@ function conflictPrompt(branch, conflicts) {
616
1031
  ].join("\n");
617
1032
  }
618
1033
  /**
1034
+ * The one sync the bar fills in: pull while the branch is behind (a push would
1035
+ * be rejected), push while it is only ahead or has no upstream yet. Nothing
1036
+ * while a rebase is paused, detached, or already level.
1037
+ */
1038
+ function suggestedSyncAction(changes) {
1039
+ if (changes?.branch === void 0 || changes.rebase !== void 0) return void 0;
1040
+ if (changes.upstream === void 0) return "push";
1041
+ if (changes.upstream.behind > 0) return "pull";
1042
+ return changes.upstream.ahead > 0 ? "push" : void 0;
1043
+ }
1044
+ /** "2 to push, 1 new on origin/feat/git", or "Up to date with origin/feat/git". */
1045
+ function upstreamSummary(upstream) {
1046
+ if (upstream === void 0) return "No upstream yet";
1047
+ const parts = [...upstream.ahead > 0 ? [`${String(upstream.ahead)} to push`] : [], ...upstream.behind > 0 ? [`${String(upstream.behind)} new on ${upstream.ref}`] : []];
1048
+ return parts.length === 0 ? `Up to date with ${upstream.ref}` : parts.join(", ");
1049
+ }
1050
+ /**
619
1051
  * Hands one deferred follow-up to the session. Returns the reason it failed,
620
1052
  * or undefined once sent. The sender throws when the session is disconnected.
621
1053
  */
@@ -631,501 +1063,1163 @@ function deliverToAgent(send, sessionId, message) {
631
1063
  }
632
1064
  }
633
1065
  //#endregion
634
- //#region src/extensions/workspaces/sessions/(frontend)/_components/GitReviewPanel.native.tsx
635
- function useGitChanges(sessionId) {
636
- const subscribe = useCallback((listener) => {
637
- const sub = gitChanges.store.subscribe(listener);
638
- return () => sub.unsubscribe();
639
- }, []);
640
- return useSyncExternalStore(subscribe, () => gitChanges.select(gitChanges.store.state, sessionId));
1066
+ //#region src/extensions/workspaces/sessions/(frontend)/_components/GitReviewView.native.tsx
1067
+ function Action({ children, variant = "outline", disabled = false, onPress }) {
1068
+ const { theme } = useUnistyles();
1069
+ return /* @__PURE__ */ jsx(Button, {
1070
+ onPress,
1071
+ variant,
1072
+ disabled,
1073
+ style: [styles$1.action, variant === "primary" && styles$1.primary],
1074
+ children: variant === "primary" ? /* @__PURE__ */ jsx(Text, {
1075
+ style: [styles$1.primaryLabel, { color: theme.scheme === "dark" ? theme.colors.rail : theme.colors["on-selected"] }],
1076
+ children
1077
+ }) : children
1078
+ });
641
1079
  }
642
- function reviewTab() {
643
- return {
644
- id: "git-review",
645
- label: "review",
646
- panel: GitReviewPanel
647
- };
1080
+ function Footer({ count, discard = false, confirmation = false, onReview, onSend, onDiscard }) {
1081
+ return /* @__PURE__ */ jsxs(View, {
1082
+ style: styles$1.footer,
1083
+ children: [discard ? /* @__PURE__ */ jsx(Action, {
1084
+ variant: "ghost",
1085
+ onPress: onDiscard,
1086
+ children: "Discard"
1087
+ }) : /* @__PURE__ */ jsxs(Pressable, {
1088
+ accessibilityRole: "button",
1089
+ accessibilityLabel: "Review queued comments",
1090
+ onPress: onReview,
1091
+ style: [styles$1.inline, styles$1.action],
1092
+ children: [/* @__PURE__ */ jsx(MessageIcon, {
1093
+ size: 16,
1094
+ color: "blue"
1095
+ }), /* @__PURE__ */ jsxs(Text, {
1096
+ style: styles$1.dim,
1097
+ children: [
1098
+ count,
1099
+ " ",
1100
+ count === 1 ? "comment" : "comments",
1101
+ " queued"
1102
+ ]
1103
+ })]
1104
+ }), /* @__PURE__ */ jsx(Action, {
1105
+ variant: confirmation ? "outline" : "primary",
1106
+ disabled: count === 0,
1107
+ onPress: onSend,
1108
+ children: "Send review"
1109
+ })]
1110
+ });
648
1111
  }
649
- function GitReviewPanel({ sessionId, sendSessionFrame }) {
650
- const activity = useGitChanges(sessionId);
651
- const subscribe = useCallback((listener) => {
652
- const sub = gitReview.store.subscribe(listener);
653
- return () => sub.unsubscribe();
654
- }, []);
655
- const comments = useSyncExternalStore(subscribe, () => gitReview.select(gitReview.store.state, sessionId).comments);
656
- const [summary, setSummary] = useState();
657
- const [file, setFile] = useState();
658
- const [error, setError] = useState();
659
- const [dismissedError, setDismissedError] = useState();
660
- const [confirm, setConfirm] = useState();
661
- const [draft, setDraft] = useState();
662
- const [comment, setComment] = useState("");
663
- const [start, setStart] = useState("");
664
- const [end, setEnd] = useState("");
665
- const request = useRef(void 0);
666
- const fingerprint = JSON.stringify(activity.changes);
667
- useEffect(() => {
668
- if (sessionId === null) return void 0;
669
- const controller = new AbortController();
670
- fetchReviewSummary(sessionId, controller.signal).then((result) => {
671
- if (!controller.signal.aborted) {
672
- if (result.ok) setSummary(result.summary);
673
- else setError(result.error);
674
- }
675
- }).catch((cause) => {
676
- if (!controller.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
677
- });
678
- return () => {
679
- controller.abort();
680
- request.current?.abort();
681
- };
682
- }, [sessionId, fingerprint]);
683
- const loadFile = async (path) => {
684
- if (sessionId === null) return;
685
- request.current?.abort();
686
- const controller = new AbortController();
687
- request.current = controller;
688
- setFile(void 0);
689
- setError(void 0);
690
- try {
691
- const result = await fetchReviewFile(sessionId, path, controller.signal);
692
- if (!controller.signal.aborted) {
693
- if (result.ok) setFile(result.diff);
694
- else setError(result.error);
695
- }
696
- } catch (cause) {
697
- if (!controller.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
698
- }
699
- };
700
- if (sessionId === null) return null;
701
- const changes = activity.changes;
702
- const busy = activity.pending !== void 0;
703
- const paused = changes?.rebase !== void 0;
704
- const send = (message, onSent) => {
705
- const failure = deliverToAgent(sendSessionFrame, sessionId, message);
706
- setError(failure);
707
- if (failure === void 0) onSent?.();
708
- };
709
- const sync = (action) => requestGitSync(sessionId, action);
710
- const forceRequired = activity.error !== dismissedError && activity.errorTarget?.action === "push" && activity.errorTarget.forceRequired === true;
711
- return /* @__PURE__ */ jsxs(ScrollView, {
712
- contentContainerStyle: styles$1.body,
1112
+ function SyncCard({ changes, busy = false, onSync }) {
1113
+ const suggested = suggestedSyncAction(changes);
1114
+ return /* @__PURE__ */ jsxs(View, {
1115
+ style: styles$1.card,
713
1116
  children: [
714
- /* @__PURE__ */ jsx(Text, {
715
- style: styles$1.title,
716
- children: changes?.branch ?? "Detached HEAD"
717
- }),
718
- /* @__PURE__ */ jsxs(Text, {
719
- style: styles$1.meta,
720
- children: [
721
- changes?.base ? `vs ${changes.base}` : "Uncommitted changes",
722
- " · +",
723
- changes?.added ?? 0,
724
- " -",
725
- changes?.removed ?? 0,
726
- "\\n",
727
- changes?.upstream ? `↑${changes.upstream.ahead} ↓${changes.upstream.behind} ${changes.upstream.ref}` : "No upstream yet"
728
- ]
729
- }),
730
1117
  /* @__PURE__ */ jsxs(View, {
731
- style: styles$1.actions,
1118
+ style: styles$1.inline,
732
1119
  children: [
733
- /* @__PURE__ */ jsx(Button, {
734
- variant: "outline",
735
- disabled: busy || paused || changes?.upstream === void 0,
736
- onPress: () => sync("pull"),
737
- children: "Pull"
1120
+ /* @__PURE__ */ jsx(BranchIcon, {
1121
+ size: 18,
1122
+ color: "dim"
1123
+ }),
1124
+ /* @__PURE__ */ jsx(Text, {
1125
+ style: styles$1.branch,
1126
+ children: changes?.branch ?? "Detached HEAD"
738
1127
  }),
739
- /* @__PURE__ */ jsx(Button, {
740
- variant: "outline",
741
- disabled: busy || paused || changes?.branch === void 0,
742
- onPress: () => sync("push"),
743
- children: "Push"
1128
+ /* @__PURE__ */ jsx(View, { style: styles$1.grow }),
1129
+ /* @__PURE__ */ jsxs(Text, {
1130
+ style: styles$1.green,
1131
+ children: ["+", changes?.added ?? 0]
744
1132
  }),
745
- /* @__PURE__ */ jsx(Button, {
746
- variant: "outline",
747
- disabled: busy || paused || changes?.base === void 0,
748
- onPress: () => sync("rebase"),
749
- children: "Rebase"
1133
+ /* @__PURE__ */ jsxs(Text, {
1134
+ style: styles$1.red,
1135
+ children: ["-", changes?.removed ?? 0]
750
1136
  })
751
1137
  ]
752
1138
  }),
753
- activity.pending ? /* @__PURE__ */ jsx(Text, {
754
- style: styles$1.meta,
755
- children: activity.pending
756
- }) : null,
757
- activity.error && activity.error !== dismissedError ? /* @__PURE__ */ jsxs(View, { children: [/* @__PURE__ */ jsx(Text, {
758
- style: styles$1.error,
759
- children: activity.error
760
- }), /* @__PURE__ */ jsx(Button, {
761
- variant: "ghost",
762
- onPress: () => setDismissedError(activity.error),
763
- children: "Dismiss"
764
- })] }) : null,
765
- forceRequired ? /* @__PURE__ */ jsx(Button, {
766
- variant: "danger-outline",
767
- disabled: busy,
768
- onPress: () => setConfirm("force"),
769
- children: "Force push with lease…"
770
- }) : null,
771
- paused ? /* @__PURE__ */ jsxs(View, {
772
- style: styles$1.body,
1139
+ /* @__PURE__ */ jsx(Text, {
1140
+ style: [styles$1.dim, styles$1.mono],
1141
+ children: changes?.base ? `vs ${changes.base}` : "Uncommitted changes"
1142
+ }),
1143
+ /* @__PURE__ */ jsx(Text, {
1144
+ style: styles$1.dim,
1145
+ children: upstreamSummary(changes?.upstream)
1146
+ }),
1147
+ /* @__PURE__ */ jsx(View, {
1148
+ style: styles$1.inline,
773
1149
  children: [
1150
+ "pull",
1151
+ "push",
1152
+ "rebase"
1153
+ ].map((action) => /* @__PURE__ */ jsx(Button, {
1154
+ variant: suggested === action ? "outline" : "ghost",
1155
+ style: suggested === action ? [styles$1.action, styles$1.suggested] : styles$1.action,
1156
+ disabled: busy || changes?.rebase !== void 0 || (action === "pull" ? changes?.upstream === void 0 : action === "push" ? changes?.branch === void 0 : changes?.base === void 0),
1157
+ onPress: () => onSync?.(action),
1158
+ children: action === "pull" ? "Pull" : action === "push" ? "Push" : "Rebase"
1159
+ }, action))
1160
+ })
1161
+ ]
1162
+ });
1163
+ }
1164
+ function FileList({ files, comments = [], onFile }) {
1165
+ return /* @__PURE__ */ jsxs(View, {
1166
+ style: styles$1.list,
1167
+ children: [/* @__PURE__ */ jsxs(Text, {
1168
+ style: styles$1.section,
1169
+ children: [files.length, " files"]
1170
+ }), files.map((file) => /* @__PURE__ */ jsxs(Pressable, {
1171
+ accessibilityRole: "button",
1172
+ testID: `git-review-file-${file.path}`,
1173
+ onPress: () => onFile?.(file.path),
1174
+ style: styles$1.fileRow,
1175
+ children: [
1176
+ /* @__PURE__ */ jsx(Text, {
1177
+ style: file.status === "added" ? styles$1.green : file.status === "untracked" ? styles$1.blue : styles$1.yellow,
1178
+ children: file.status[0]?.toUpperCase()
1179
+ }),
1180
+ /* @__PURE__ */ jsxs(View, {
1181
+ style: styles$1.grow,
1182
+ children: [/* @__PURE__ */ jsx(Text, {
1183
+ style: styles$1.body,
1184
+ children: file.path.split("/").at(-1)
1185
+ }), /* @__PURE__ */ jsx(Text, {
1186
+ numberOfLines: 1,
1187
+ style: [styles$1.dim, styles$1.mono],
1188
+ children: file.path.split("/").slice(0, -1).join("/") || "."
1189
+ })]
1190
+ }),
1191
+ /* @__PURE__ */ jsxs(Text, { children: [
774
1192
  /* @__PURE__ */ jsxs(Text, {
775
- style: styles$1.error,
776
- children: ["Rebase paused\\n", changes.rebase?.conflicts.join("\n")]
1193
+ style: styles$1.green,
1194
+ children: ["+", file.added]
777
1195
  }),
778
- /* @__PURE__ */ jsx(Button, {
779
- disabled: busy,
780
- onPress: () => send(conflictPrompt(changes.branch, changes.rebase?.conflicts ?? [])),
781
- children: "Ask agent to resolve"
782
- }),
783
- /* @__PURE__ */ jsx(Button, {
784
- variant: "danger-outline",
785
- disabled: busy,
786
- onPress: () => setConfirm("abort"),
787
- children: "Abort rebase…"
1196
+ " ",
1197
+ /* @__PURE__ */ jsxs(Text, {
1198
+ style: styles$1.red,
1199
+ children: ["-", file.removed]
788
1200
  })
789
- ]
790
- }) : null,
791
- error ? /* @__PURE__ */ jsx(Text, {
792
- style: styles$1.error,
793
- children: error
794
- }) : null,
795
- summary ? summary.files.map((entry) => /* @__PURE__ */ jsxs(Button, {
796
- variant: "ghost",
797
- testID: `git-review-file-${entry.path}`,
798
- onPress: () => void loadFile(entry.path),
799
- children: [
800
- entry.path,
801
- " · ",
802
- entry.status,
803
- " · +",
804
- entry.added,
805
- " -",
806
- entry.removed
807
- ]
808
- }, entry.path)) : /* @__PURE__ */ jsx(Text, {
809
- style: styles$1.meta,
810
- children: "Loading changes…"
1201
+ ] }),
1202
+ comments.some((comment) => comment.path === file.path) ? /* @__PURE__ */ jsxs(View, {
1203
+ style: styles$1.inline,
1204
+ children: [/* @__PURE__ */ jsx(MessageIcon, {
1205
+ size: 12,
1206
+ color: "blue"
1207
+ }), /* @__PURE__ */ jsx(Text, {
1208
+ style: styles$1.blue,
1209
+ children: comments.filter((comment) => comment.path === file.path).length
1210
+ })]
1211
+ }) : null,
1212
+ /* @__PURE__ */ jsx(ChevronRightIcon, {
1213
+ size: 16,
1214
+ color: "dim"
1215
+ })
1216
+ ]
1217
+ }, file.path))]
1218
+ });
1219
+ }
1220
+ function RebaseCard({ confirmation = false, conflicts, busy = false, onResolve, onAbort }) {
1221
+ return /* @__PURE__ */ jsxs(View, {
1222
+ style: [styles$1.card, styles$1.caution],
1223
+ children: [
1224
+ /* @__PURE__ */ jsxs(View, {
1225
+ style: styles$1.inline,
1226
+ children: [/* @__PURE__ */ jsx(AlertIcon, {
1227
+ size: 20,
1228
+ color: "yellow"
1229
+ }), /* @__PURE__ */ jsx(Text, {
1230
+ style: styles$1.section,
1231
+ children: "Rebase paused"
1232
+ })]
811
1233
  }),
812
- summary?.files.length === 0 ? /* @__PURE__ */ jsx(Text, {
813
- style: styles$1.meta,
814
- children: summary.repository ? "No changed files" : "Not a Git checkout"
815
- }) : null,
816
- summary?.truncated ? /* @__PURE__ */ jsx(Text, {
817
- style: styles$1.meta,
818
- children: "The file list was truncated."
819
- }) : null,
820
- file ? /* @__PURE__ */ jsxs(View, {
1234
+ /* @__PURE__ */ jsx(Text, {
821
1235
  style: styles$1.body,
1236
+ children: "Resolve conflicts or ask Po to do it for you."
1237
+ }),
1238
+ /* @__PURE__ */ jsx(Text, {
1239
+ style: [styles$1.dim, styles$1.mono],
1240
+ children: conflicts.join("\n")
1241
+ }),
1242
+ /* @__PURE__ */ jsx(Action, {
1243
+ disabled: busy,
1244
+ onPress: onResolve,
1245
+ variant: confirmation ? "outline" : "primary",
1246
+ children: "Ask Po to resolve"
1247
+ }),
1248
+ /* @__PURE__ */ jsx(Action, {
1249
+ disabled: busy,
1250
+ onPress: onAbort,
1251
+ variant: "danger-outline",
1252
+ children: "Abort rebase"
1253
+ })
1254
+ ]
1255
+ });
1256
+ }
1257
+ function FileHeader({ entry, index, total, onPrevious, onNext, onChanges }) {
1258
+ return /* @__PURE__ */ jsxs(View, {
1259
+ style: styles$1.content,
1260
+ children: [
1261
+ /* @__PURE__ */ jsx(Text, {
1262
+ style: styles$1.heading,
1263
+ children: entry.path.split("/").at(-1)
1264
+ }),
1265
+ /* @__PURE__ */ jsx(Text, {
1266
+ style: [styles$1.dim, styles$1.mono],
1267
+ children: entry.path.split("/").slice(0, -1).join("/") || "."
1268
+ }),
1269
+ /* @__PURE__ */ jsxs(View, {
1270
+ style: styles$1.inline,
822
1271
  children: [
823
- /* @__PURE__ */ jsx(Text, {
824
- style: styles$1.title,
825
- children: file.path
1272
+ /* @__PURE__ */ jsxs(Text, {
1273
+ style: styles$1.dim,
1274
+ children: [entry.status[0]?.toUpperCase(), entry.status.slice(1)]
826
1275
  }),
827
- file.binary || file.tooLarge ? /* @__PURE__ */ jsx(Text, {
828
- style: styles$1.meta,
829
- children: file.binary ? "Binary file" : "Diff too large to display"
830
- }) : file.hunks.map((hunk, index) => /* @__PURE__ */ jsx(View, { children: hunk.rows.map((row, rowIndex) => /* @__PURE__ */ jsxs(Text, {
831
- selectable: true,
832
- style: styles$1.diff(row.marker),
833
- onPress: () => {
834
- setDraft({
835
- path: file.path,
836
- rows: hunk.rows
837
- });
838
- setStart(String(row.line));
839
- setEnd(String(row.line));
840
- },
841
- children: [
842
- row.marker,
843
- " ",
844
- row.line,
845
- " ",
846
- row.content
847
- ]
848
- }, rowIndex)) }, index)),
849
- /* @__PURE__ */ jsx(Button, {
850
- variant: "outline",
851
- onPress: () => {
852
- setDraft({
853
- path: file.path,
854
- rows: []
855
- });
856
- setStart("");
857
- setEnd("");
858
- },
859
- children: "Comment on file"
1276
+ /* @__PURE__ */ jsxs(Text, {
1277
+ style: styles$1.green,
1278
+ children: ["+", entry.added]
1279
+ }),
1280
+ /* @__PURE__ */ jsxs(Text, {
1281
+ style: styles$1.red,
1282
+ children: ["-", entry.removed]
860
1283
  })
861
1284
  ]
862
- }) : null,
863
- comments.map((item) => /* @__PURE__ */ jsxs(View, { children: [/* @__PURE__ */ jsxs(Text, {
864
- style: styles$1.meta,
1285
+ }),
1286
+ /* @__PURE__ */ jsxs(View, {
1287
+ style: styles$1.navigation,
865
1288
  children: [
866
- item.relPath,
867
- item.startLine === void 0 ? "" : `:${item.startLine}-${item.endLine ?? item.startLine}`,
868
- "\\n",
869
- item.body
1289
+ /* @__PURE__ */ jsx(Action, {
1290
+ variant: "ghost",
1291
+ disabled: index === 0,
1292
+ onPress: onPrevious,
1293
+ children: "Previous"
1294
+ }),
1295
+ /* @__PURE__ */ jsx(Pressable, {
1296
+ accessibilityRole: "button",
1297
+ accessibilityLabel: "Return to changes",
1298
+ onPress: onChanges,
1299
+ style: [styles$1.inline, styles$1.action],
1300
+ children: /* @__PURE__ */ jsxs(Text, {
1301
+ style: styles$1.dim,
1302
+ children: [
1303
+ onChanges ? "Changes · " : "",
1304
+ index + 1,
1305
+ " of ",
1306
+ total
1307
+ ]
1308
+ })
1309
+ }),
1310
+ /* @__PURE__ */ jsx(Action, {
1311
+ variant: "ghost",
1312
+ disabled: index === total - 1,
1313
+ onPress: onNext,
1314
+ children: "Next"
1315
+ })
870
1316
  ]
871
- }), /* @__PURE__ */ jsx(Button, {
872
- variant: "ghost",
873
- onPress: () => removeReviewComment(sessionId, item.id),
874
- children: "Remove comment"
875
- })] }, item.id)),
876
- comments.length > 0 ? /* @__PURE__ */ jsxs(View, {
877
- style: styles$1.actions,
878
- children: [/* @__PURE__ */ jsx(Button, {
879
- onPress: () => {
880
- const body = comments.map((item) => {
881
- return `### ${item.startLine === void 0 ? item.relPath : item.side === "old" ? `${item.relPath} (removed lines ${item.startLine}-${item.endLine ?? item.startLine})` : `${item.relPath}:${item.startLine}-${item.endLine ?? item.startLine}`}\n\n${item.snippet.split("\n").slice(0, 20).join("\n").slice(0, 2e3).split("\n").map((line) => `> ${line}`).join("\n")}\n\n${item.body.trim()}`;
882
- }).join("\n\n");
883
- send(`${reviewHeading(comments.length, summary?.branch, summary?.base)}\n\n${body}`, () => clearReviewComments(sessionId));
884
- },
885
- children: "Send review"
886
- }), /* @__PURE__ */ jsx(Button, {
887
- variant: "outline",
888
- onPress: () => setConfirm("discard"),
889
- children: "Discard review…"
890
- })]
1317
+ })
1318
+ ]
1319
+ });
1320
+ }
1321
+ function DiffRows({ rows, comments = [], selection, onLine, showInlineComments = true }) {
1322
+ return /* @__PURE__ */ jsx(View, { children: rows.map((row, i) => {
1323
+ const side = row.marker === "-" ? "old" : "new";
1324
+ const anchored = comments.filter((comment) => comment.side === side && (comment.endLine ?? comment.startLine) === row.line);
1325
+ return /* @__PURE__ */ jsxs(View, { children: [/* @__PURE__ */ jsxs(Pressable, {
1326
+ accessibilityRole: "button",
1327
+ accessibilityLabel: `Select ${side} line ${row.line}`,
1328
+ onPress: () => onLine?.(row),
1329
+ style: [
1330
+ styles$1.diffRow,
1331
+ row.marker === "+" && styles$1.added,
1332
+ row.marker === "-" && styles$1.removed,
1333
+ selection?.side === side && row.line >= selection.startLine && row.line <= selection.endLine && styles$1.selection
1334
+ ],
1335
+ children: [
1336
+ /* @__PURE__ */ jsx(Text, {
1337
+ style: [styles$1.mono, styles$1.gutter],
1338
+ children: row.line
1339
+ }),
1340
+ /* @__PURE__ */ jsx(Text, {
1341
+ style: [styles$1.dim, styles$1.mono],
1342
+ children: row.marker
1343
+ }),
1344
+ /* @__PURE__ */ jsx(SyntaxLine, {
1345
+ text: row.content || " ",
1346
+ style: [styles$1.mono, styles$1.code]
1347
+ }),
1348
+ anchored.length ? /* @__PURE__ */ jsx(MessageIcon, {
1349
+ size: 12,
1350
+ color: "blue"
1351
+ }) : null
1352
+ ]
1353
+ }), showInlineComments && anchored.map((comment) => /* @__PURE__ */ jsxs(View, {
1354
+ style: styles$1.inlineComment,
1355
+ children: [/* @__PURE__ */ jsxs(Text, {
1356
+ style: styles$1.blue,
1357
+ children: ["Queued comment · ", lineLabel(comment)]
1358
+ }), /* @__PURE__ */ jsx(Text, {
1359
+ style: styles$1.body,
1360
+ children: comment.body
1361
+ })]
1362
+ }, comment.id))] }, i);
1363
+ }) });
1364
+ }
1365
+ function lineLabel(comment) {
1366
+ return comment.startLine === void 0 ? "File comment" : comment.endLine === comment.startLine || comment.endLine === void 0 ? `Line ${comment.startLine}` : `Lines ${comment.startLine} to ${comment.endLine}`;
1367
+ }
1368
+ function CommentSheet({ range, snippet, value, onChange, onAdd, onCancel }) {
1369
+ return /* @__PURE__ */ jsxs(View, {
1370
+ style: styles$1.sheet,
1371
+ children: [
1372
+ /* @__PURE__ */ jsx(View, { style: styles$1.handle }),
1373
+ /* @__PURE__ */ jsx(Text, {
1374
+ style: styles$1.sheetTitle,
1375
+ children: range ? lineLabel(range) : "Comment on file"
1376
+ }),
1377
+ snippet ? /* @__PURE__ */ jsx(View, {
1378
+ style: styles$1.quote,
1379
+ children: /* @__PURE__ */ jsx(SyntaxLine, {
1380
+ text: snippet,
1381
+ style: [styles$1.body, styles$1.mono]
1382
+ })
891
1383
  }) : null,
892
- /* @__PURE__ */ jsx(Sheet, {
893
- open: draft !== void 0,
894
- onOpenChange: (open) => {
895
- if (!open) setDraft(void 0);
896
- },
897
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Review comment" }) }), /* @__PURE__ */ jsx(SheetBody, { children: /* @__PURE__ */ jsxs(View, {
898
- style: styles$1.body,
899
- children: [
900
- draft?.rows.length ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Input, {
901
- accessibilityLabel: "Start line",
902
- value: start,
903
- onChangeText: setStart,
904
- keyboardType: "number-pad"
905
- }), /* @__PURE__ */ jsx(Input, {
906
- accessibilityLabel: "End line",
907
- value: end,
908
- onChangeText: setEnd,
909
- keyboardType: "number-pad"
910
- })] }) : null,
911
- /* @__PURE__ */ jsx(Textarea, {
912
- accessibilityLabel: "Comment",
913
- value: comment,
914
- onChangeText: setComment
915
- }),
916
- /* @__PURE__ */ jsx(Button, {
917
- disabled: comment.trim() === "" || Boolean(draft?.rows.length) && (!Number.isInteger(Number(start)) || Number(start) < 1 || !Number.isInteger(Number(end)) || Number(end) < Number(start)),
918
- onPress: () => {
919
- if (!draft) return;
920
- const rows = draft.rows.filter((row) => row.line >= Number(start) && row.line <= Number(end));
921
- const kept = rows.filter((row) => row.marker !== "-");
922
- const numbered = kept.length > 0 ? kept : rows;
923
- addReviewComment(sessionId, {
924
- path: draft.path,
925
- relPath: draft.path,
926
- body: comment.trim(),
927
- snippet: numbered.map((row) => row.content).join("\n"),
928
- ...numbered.length === 0 ? {} : {
929
- side: kept.length > 0 ? "new" : "old",
930
- startLine: Math.min(...numbered.map((row) => row.line)),
931
- endLine: Math.max(...numbered.map((row) => row.line))
932
- }
933
- });
934
- setDraft(void 0);
935
- setComment("");
936
- },
937
- children: "Add comment"
938
- })
939
- ]
940
- }) })] })
1384
+ /* @__PURE__ */ jsx(Textarea, {
1385
+ accessibilityLabel: "What should change here?",
1386
+ placeholder: "What should change here?",
1387
+ rows: 4,
1388
+ value,
1389
+ onChangeText: onChange
941
1390
  }),
942
- /* @__PURE__ */ jsx(Sheet, {
943
- open: confirm !== void 0,
944
- onOpenChange: (open) => {
945
- if (!open) setConfirm(void 0);
946
- },
947
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: confirm === "force" ? "Force push with lease?" : confirm === "abort" ? "Abort rebase?" : "Discard review?" }) }), /* @__PURE__ */ jsxs(SheetBody, { children: [/* @__PURE__ */ jsx(Text, {
948
- style: styles$1.meta,
949
- children: confirm === "force" ? "Git refuses this if the remote holds commits you never fetched and integrated." : confirm === "abort" ? "Abort discards any conflict resolution in progress." : "Your queued comments will be removed."
950
- }), /* @__PURE__ */ jsx(Button, {
951
- variant: "danger-outline",
952
- onPress: () => {
953
- if (confirm === "force") requestGitSync(sessionId, "push", true);
954
- else if (confirm === "abort") sync("abort-rebase");
955
- else clearReviewComments(sessionId);
956
- setConfirm(void 0);
957
- },
958
- children: "Confirm"
959
- })] })] })
1391
+ /* @__PURE__ */ jsx(Action, {
1392
+ variant: "primary",
1393
+ disabled: value !== void 0 && value.trim() === "",
1394
+ onPress: onAdd,
1395
+ children: "Add comment"
1396
+ }),
1397
+ /* @__PURE__ */ jsx(Action, {
1398
+ variant: "ghost",
1399
+ onPress: onCancel,
1400
+ children: "Cancel"
960
1401
  })
961
1402
  ]
962
1403
  });
963
1404
  }
1405
+ function CommentCards({ comments, onRemove }) {
1406
+ return /* @__PURE__ */ jsxs(View, {
1407
+ style: styles$1.content,
1408
+ children: [/* @__PURE__ */ jsxs(Text, {
1409
+ style: styles$1.body,
1410
+ children: [
1411
+ comments.length === 2 ? "Two" : comments.length,
1412
+ " ",
1413
+ comments.length === 1 ? "comment" : "comments",
1414
+ " queued for Po, whenever you are ready."
1415
+ ]
1416
+ }), comments.map((comment) => /* @__PURE__ */ jsxs(View, {
1417
+ style: styles$1.card,
1418
+ children: [
1419
+ /* @__PURE__ */ jsx(Text, {
1420
+ style: [styles$1.body, styles$1.mono],
1421
+ children: comment.relPath
1422
+ }),
1423
+ /* @__PURE__ */ jsx(Text, {
1424
+ style: styles$1.dim,
1425
+ children: lineLabel(comment)
1426
+ }),
1427
+ comment.snippet ? /* @__PURE__ */ jsx(View, {
1428
+ style: styles$1.quote,
1429
+ children: /* @__PURE__ */ jsx(SyntaxLine, {
1430
+ text: comment.snippet,
1431
+ style: [styles$1.body, styles$1.mono]
1432
+ })
1433
+ }) : null,
1434
+ /* @__PURE__ */ jsx(Text, {
1435
+ style: styles$1.body,
1436
+ children: comment.body
1437
+ }),
1438
+ /* @__PURE__ */ jsx(View, {
1439
+ style: styles$1.remove,
1440
+ children: /* @__PURE__ */ jsx(Action, {
1441
+ variant: "ghost",
1442
+ onPress: () => onRemove?.(comment.id),
1443
+ children: "Remove"
1444
+ })
1445
+ })
1446
+ ]
1447
+ }, comment.id))]
1448
+ });
1449
+ }
964
1450
  const styles$1 = StyleSheet.create((theme) => ({
965
- body: {
966
- padding: theme.spacing(3),
967
- gap: theme.spacing(2),
1451
+ heading: {
1452
+ fontFamily: fontOf(theme.fontFamily.sans),
1453
+ fontSize: theme.fontSize["2xl"],
1454
+ fontWeight: "600",
1455
+ color: theme.colors.hi,
968
1456
  uni__dependencies: [0]
969
1457
  },
970
- actions: {
971
- flexDirection: "row",
972
- flexWrap: "wrap",
973
- gap: theme.spacing(1),
1458
+ sheetTitle: {
1459
+ fontFamily: fontOf(theme.fontFamily.sans),
1460
+ fontSize: theme.fontSize.xl,
1461
+ fontWeight: "600",
1462
+ color: theme.colors.hi,
974
1463
  uni__dependencies: [0]
975
1464
  },
976
- title: {
1465
+ section: {
1466
+ fontFamily: fontOf(theme.fontFamily.sans),
1467
+ fontSize: theme.fontSize.lg,
1468
+ fontWeight: "600",
977
1469
  color: theme.colors.hi,
1470
+ uni__dependencies: [0]
1471
+ },
1472
+ body: {
1473
+ fontFamily: fontOf(theme.fontFamily.sans),
978
1474
  fontSize: theme.fontSize.base,
979
- fontWeight: "600",
1475
+ lineHeight: theme.lineHeightRelaxed.base,
1476
+ color: theme.colors.text,
980
1477
  uni__dependencies: [0]
981
1478
  },
982
- meta: {
1479
+ dim: {
1480
+ fontFamily: fontOf(theme.fontFamily.sans),
1481
+ fontSize: theme.fontSize.sm,
1482
+ lineHeight: theme.lineHeightRelaxed.sm,
983
1483
  color: theme.colors.dim,
1484
+ uni__dependencies: [0]
1485
+ },
1486
+ mono: {
1487
+ fontFamily: fontOf(theme.fontFamily.mono),
984
1488
  fontSize: theme.fontSize.sm,
1489
+ lineHeight: theme.lineHeightRelaxed.sm,
985
1490
  uni__dependencies: [0]
986
1491
  },
987
- error: {
1492
+ branch: {
1493
+ fontFamily: fontOf(theme.fontFamily.mono),
1494
+ fontSize: theme.fontSize.lg,
1495
+ fontWeight: "600",
1496
+ color: theme.colors.hi,
1497
+ uni__dependencies: [0]
1498
+ },
1499
+ green: {
1500
+ fontSize: theme.fontSize.sm,
1501
+ color: theme.colors.green,
1502
+ uni__dependencies: [0]
1503
+ },
1504
+ red: {
1505
+ fontSize: theme.fontSize.sm,
988
1506
  color: theme.colors.red,
1507
+ uni__dependencies: [0]
1508
+ },
1509
+ blue: {
1510
+ fontFamily: fontOf(theme.fontFamily.sans),
989
1511
  fontSize: theme.fontSize.sm,
1512
+ color: theme.colors.blue,
990
1513
  uni__dependencies: [0]
991
1514
  },
992
- diff: (marker) => ({
993
- fontFamily: fontOf(theme.fontFamily.mono),
1515
+ yellow: {
994
1516
  fontSize: theme.fontSize.sm,
995
- color: marker === "+" ? theme.colors.green : marker === "-" ? theme.colors.red : theme.colors.text,
1517
+ color: theme.colors.yellow,
1518
+ uni__dependencies: [0]
1519
+ },
1520
+ content: {
1521
+ padding: theme.spacing(4),
1522
+ gap: theme.spacing(3),
1523
+ uni__dependencies: [0]
1524
+ },
1525
+ card: {
1526
+ borderWidth: 1,
1527
+ borderColor: theme.colors.border,
1528
+ borderRadius: theme.borderRadius.lg,
1529
+ padding: theme.spacing(3),
1530
+ gap: theme.spacing(2),
1531
+ uni__dependencies: [0]
1532
+ },
1533
+ inline: {
1534
+ flexDirection: "row",
1535
+ alignItems: "center",
1536
+ gap: theme.spacing(2),
1537
+ uni__dependencies: [0]
1538
+ },
1539
+ grow: {
1540
+ flex: 1,
1541
+ minWidth: 0
1542
+ },
1543
+ action: { minHeight: 44 },
1544
+ primary: {
1545
+ backgroundColor: theme.colors.green,
1546
+ uni__dependencies: [0]
1547
+ },
1548
+ primaryLabel: {
1549
+ fontFamily: fontOf(theme.fontFamily.sans),
1550
+ fontSize: theme.fontSize.base,
1551
+ fontWeight: "600",
1552
+ color: theme.scheme === "dark" ? theme.colors.rail : theme.colors["on-selected"],
1553
+ uni__dependencies: [0]
1554
+ },
1555
+ suggested: {
1556
+ backgroundColor: theme.colors["tint-green"],
1557
+ borderColor: theme.colors["edge-green"],
1558
+ flex: 1,
1559
+ uni__dependencies: [0]
1560
+ },
1561
+ list: {
1562
+ gap: theme.spacing(2),
1563
+ uni__dependencies: [0]
1564
+ },
1565
+ fileRow: {
1566
+ minHeight: 44,
1567
+ paddingVertical: theme.spacing(2),
1568
+ flexDirection: "row",
1569
+ alignItems: "center",
1570
+ gap: theme.spacing(2),
1571
+ borderBottomWidth: StyleSheet.hairlineWidth,
1572
+ borderColor: theme.colors.border,
1573
+ uni__dependencies: [0]
1574
+ },
1575
+ footer: {
1576
+ minHeight: 76,
1577
+ padding: theme.spacing(4),
1578
+ flexDirection: "row",
1579
+ alignItems: "center",
1580
+ justifyContent: "space-between",
1581
+ gap: theme.spacing(2),
1582
+ borderTopWidth: 1,
1583
+ borderColor: theme.colors.border,
1584
+ backgroundColor: theme.colors.rail,
1585
+ uni__dependencies: [0]
1586
+ },
1587
+ caution: {
1588
+ backgroundColor: theme.colors["tint-yellow"],
1589
+ borderColor: theme.colors["edge-yellow"],
1590
+ uni__dependencies: [0]
1591
+ },
1592
+ failure: {
1593
+ backgroundColor: theme.colors["tint-red"],
1594
+ borderColor: theme.colors["edge-red"],
1595
+ uni__dependencies: [0]
1596
+ },
1597
+ sheet: {
1598
+ padding: theme.spacing(4),
1599
+ gap: theme.spacing(3),
1600
+ borderTopWidth: 1,
1601
+ borderColor: theme.colors.border,
1602
+ borderTopLeftRadius: theme.borderRadius.lg,
1603
+ borderTopRightRadius: theme.borderRadius.lg,
1604
+ backgroundColor: theme.colors.rail,
1605
+ uni__dependencies: [0]
1606
+ },
1607
+ handle: {
1608
+ height: 4,
1609
+ width: 40,
1610
+ borderRadius: theme.borderRadius.md,
1611
+ backgroundColor: theme.colors.border,
1612
+ alignSelf: "center",
1613
+ uni__dependencies: [0]
1614
+ },
1615
+ empty: {
1616
+ flex: 1,
1617
+ alignItems: "center",
1618
+ justifyContent: "center",
1619
+ gap: theme.spacing(3),
1620
+ padding: theme.spacing(6),
1621
+ uni__dependencies: [0]
1622
+ },
1623
+ navigation: {
1624
+ flexDirection: "row",
1625
+ justifyContent: "space-between",
1626
+ alignItems: "center"
1627
+ },
1628
+ diffRow: {
1629
+ flexDirection: "row",
1630
+ alignItems: "flex-start",
1631
+ gap: theme.spacing(2),
1632
+ paddingHorizontal: theme.spacing(2),
996
1633
  paddingVertical: theme.spacing(1),
1634
+ borderLeftWidth: 3,
1635
+ borderLeftColor: theme.colors.bg,
1636
+ uni__dependencies: [0]
1637
+ },
1638
+ gutter: {
1639
+ color: theme.colors.dim,
1640
+ width: 24,
1641
+ textAlign: "right",
1642
+ uni__dependencies: [0]
1643
+ },
1644
+ code: {
1645
+ flex: 1,
1646
+ minWidth: 0,
1647
+ color: theme.colors.text,
1648
+ uni__dependencies: [0]
1649
+ },
1650
+ added: {
1651
+ backgroundColor: theme.colors["tint-green"],
1652
+ uni__dependencies: [0]
1653
+ },
1654
+ removed: {
1655
+ backgroundColor: theme.colors["tint-red"],
1656
+ uni__dependencies: [0]
1657
+ },
1658
+ selection: {
1659
+ borderLeftColor: theme.colors.green,
1660
+ uni__dependencies: [0]
1661
+ },
1662
+ inlineComment: {
1663
+ margin: theme.spacing(2),
1664
+ padding: theme.spacing(3),
1665
+ borderWidth: 1,
1666
+ borderColor: theme.colors["edge-blue"],
1667
+ borderRadius: theme.borderRadius.md,
1668
+ gap: theme.spacing(1),
1669
+ uni__dependencies: [0]
1670
+ },
1671
+ quote: {
1672
+ padding: theme.spacing(2),
1673
+ backgroundColor: theme.colors.panel,
1674
+ borderRadius: theme.borderRadius.md,
997
1675
  uni__dependencies: [0]
998
- })
1676
+ },
1677
+ remove: { alignSelf: "flex-end" }
999
1678
  }));
1000
- //#endregion
1001
- //#region src/extensions/workspaces/sessions/(frontend)/fill/_components/WorktreesActivitySection.native.tsx
1002
- function WorktreesActivitySection({ sessionId, openTransientTab }) {
1003
- const git = useGitChanges(sessionId);
1004
- const state = useWorktrees(sessionId);
1005
- const worktrees = state.worktrees.filter((item) => item.sessionId !== sessionId);
1679
+ function GitReviewView(props) {
1680
+ const { screen, activity, summary, file, path, comments } = props;
1681
+ const index = summary?.files.findIndex((entry) => entry.path === path) ?? -1;
1682
+ const entry = summary?.files[index];
1006
1683
  return /* @__PURE__ */ jsxs(View, {
1007
- style: styles.section,
1684
+ style: styles$1.grow,
1008
1685
  children: [
1009
- git.changes ? /* @__PURE__ */ jsxs(Pressable, {
1010
- accessibilityRole: "button",
1011
- accessibilityLabel: `${git.changes.branch ?? "Detached HEAD"}, ${git.changes.added} added, ${git.changes.removed} removed`,
1012
- testID: "activity-diff-changes",
1013
- onPress: () => openTransientTab(reviewTab()),
1014
- style: styles.changes,
1015
- children: [
1016
- /* @__PURE__ */ jsx(Text, {
1017
- numberOfLines: 1,
1018
- style: styles.branch,
1019
- children: git.changes.branch ?? "Detached HEAD"
1020
- }),
1021
- /* @__PURE__ */ jsxs(Text, {
1022
- style: styles.added,
1023
- children: ["+", git.changes.added]
1686
+ screen === "review" ? /* @__PURE__ */ jsxs(View, {
1687
+ style: styles$1.inline,
1688
+ children: [/* @__PURE__ */ jsx(Action, {
1689
+ variant: "ghost",
1690
+ onPress: () => props.onScreen("changes"),
1691
+ children: "Changes"
1692
+ }), screen === "review" && path ? /* @__PURE__ */ jsx(Action, {
1693
+ variant: "ghost",
1694
+ onPress: () => props.onScreen("file"),
1695
+ children: "File diff"
1696
+ }) : null]
1697
+ }) : null,
1698
+ /* @__PURE__ */ jsxs(ScrollView, {
1699
+ style: styles$1.grow,
1700
+ children: [screen === "changes" ? /* @__PURE__ */ jsxs(View, {
1701
+ style: styles$1.content,
1702
+ children: [
1703
+ summary?.repository !== false ? /* @__PURE__ */ jsx(SyncCard, {
1704
+ changes: activity.changes,
1705
+ busy: activity.pending !== void 0,
1706
+ onSync: props.onSync
1707
+ }) : null,
1708
+ activity.pending ? /* @__PURE__ */ jsx(Text, {
1709
+ style: styles$1.dim,
1710
+ children: activity.pending
1711
+ }) : null,
1712
+ activity.error ? /* @__PURE__ */ jsxs(View, {
1713
+ style: [styles$1.card, props.forceRequired ? styles$1.caution : styles$1.failure],
1714
+ children: [
1715
+ /* @__PURE__ */ jsx(Text, {
1716
+ style: styles$1.body,
1717
+ children: activity.error
1718
+ }),
1719
+ props.forceRequired ? /* @__PURE__ */ jsx(Action, {
1720
+ variant: "danger-outline",
1721
+ onPress: props.onForce,
1722
+ children: "Force push with lease"
1723
+ }) : null,
1724
+ /* @__PURE__ */ jsx(Action, {
1725
+ variant: "ghost",
1726
+ onPress: props.onDismiss,
1727
+ children: "Dismiss"
1728
+ })
1729
+ ]
1730
+ }) : null,
1731
+ activity.changes?.rebase ? /* @__PURE__ */ jsx(RebaseCard, {
1732
+ conflicts: activity.changes.rebase.conflicts,
1733
+ busy: activity.pending !== void 0,
1734
+ onResolve: props.onResolve,
1735
+ onAbort: props.onAbort
1736
+ }) : null,
1737
+ !summary ? /* @__PURE__ */ jsx(Text, {
1738
+ style: styles$1.dim,
1739
+ children: "Loading changes…"
1740
+ }) : summary.files.length ? /* @__PURE__ */ jsx(FileList, {
1741
+ files: summary.files,
1742
+ comments,
1743
+ onFile: props.onFile
1744
+ }) : /* @__PURE__ */ jsxs(View, {
1745
+ style: styles$1.empty,
1746
+ children: [/* @__PURE__ */ jsx(Text, {
1747
+ style: styles$1.sheetTitle,
1748
+ children: summary.repository ? "No changes yet" : "Not a Git checkout"
1749
+ }), /* @__PURE__ */ jsx(Text, {
1750
+ style: styles$1.dim,
1751
+ children: summary.repository ? `Nothing to review on ${summary.branch ?? "this checkout"}.` : "This folder is not a Git repository, so there is nothing to sync."
1752
+ })]
1753
+ }),
1754
+ summary?.truncated ? /* @__PURE__ */ jsx(Text, {
1755
+ style: styles$1.dim,
1756
+ children: "The file list was truncated."
1757
+ }) : null
1758
+ ]
1759
+ }) : screen === "file" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1760
+ entry ? /* @__PURE__ */ jsx(FileHeader, {
1761
+ entry,
1762
+ index,
1763
+ total: summary?.files.length ?? 0,
1764
+ onChanges: () => props.onScreen("changes"),
1765
+ onPrevious: () => {
1766
+ const previous = summary?.files[index - 1];
1767
+ if (previous) props.onFile(previous.path);
1768
+ },
1769
+ onNext: () => {
1770
+ const next = summary?.files[index + 1];
1771
+ if (next) props.onFile(next.path);
1772
+ }
1773
+ }) : /* @__PURE__ */ jsx(Text, {
1774
+ style: styles$1.heading,
1775
+ children: path
1024
1776
  }),
1025
- /* @__PURE__ */ jsxs(Text, {
1026
- style: styles.removed,
1027
- children: ["-", git.changes.removed]
1777
+ !file ? /* @__PURE__ */ jsxs(View, {
1778
+ style: styles$1.content,
1779
+ children: [/* @__PURE__ */ jsx(Text, {
1780
+ style: styles$1.dim,
1781
+ children: props.error ? "The diff could not be loaded. Please try again." : "Loading diff…"
1782
+ }), props.error && path ? /* @__PURE__ */ jsx(Action, {
1783
+ onPress: () => props.onFile(path),
1784
+ children: "Retry"
1785
+ }) : null]
1786
+ }) : file.binary || file.tooLarge ? /* @__PURE__ */ jsx(View, {
1787
+ style: styles$1.content,
1788
+ children: /* @__PURE__ */ jsx(Text, {
1789
+ style: styles$1.section,
1790
+ children: file.binary ? "Binary file" : "Diff too large to display"
1791
+ })
1792
+ }) : file.hunks.map((hunk, i) => /* @__PURE__ */ jsx(DiffRows, {
1793
+ rows: hunk.rows,
1794
+ comments: comments.filter((comment) => comment.path === file.path),
1795
+ selection: props.selection,
1796
+ onLine: props.onLine
1797
+ }, i)),
1798
+ comments.filter((comment) => comment.path === path && comment.startLine === void 0).map((comment) => /* @__PURE__ */ jsxs(View, {
1799
+ style: styles$1.inlineComment,
1800
+ children: [/* @__PURE__ */ jsx(Text, {
1801
+ style: styles$1.blue,
1802
+ children: "Queued file comment"
1803
+ }), /* @__PURE__ */ jsx(Text, {
1804
+ style: styles$1.body,
1805
+ children: comment.body
1806
+ })]
1807
+ }, comment.id)),
1808
+ /* @__PURE__ */ jsx(View, {
1809
+ style: styles$1.content,
1810
+ children: /* @__PURE__ */ jsx(Action, {
1811
+ onPress: props.onComment,
1812
+ children: "Comment on file"
1813
+ })
1028
1814
  })
1029
- ]
1030
- }) : null,
1031
- state.pending ? /* @__PURE__ */ jsx(ListRow, { title: state.pending }) : null,
1032
- worktrees.map((item) => /* @__PURE__ */ jsx(ListRow, {
1033
- leading: /* @__PURE__ */ jsx(Dot, { tone: item.orphaned ? "red" : item.sessionId === null ? "muted" : "blue" }),
1034
- title: /* @__PURE__ */ jsx(Button, {
1815
+ ] }) : /* @__PURE__ */ jsx(CommentCards, {
1816
+ comments,
1817
+ onRemove: props.onRemove
1818
+ }), props.error ? /* @__PURE__ */ jsx(Text, {
1819
+ style: [styles$1.red, styles$1.content],
1820
+ children: props.error
1821
+ }) : null]
1822
+ }),
1823
+ /* @__PURE__ */ jsx(Footer, {
1824
+ count: comments.length,
1825
+ confirmation: screen === "changes" && activity.changes?.rebase !== void 0,
1826
+ discard: screen === "review",
1827
+ onReview: () => props.onScreen("review"),
1828
+ onSend: props.onSend,
1829
+ onDiscard: props.onDiscard
1830
+ })
1831
+ ]
1832
+ });
1833
+ }
1834
+ //#endregion
1835
+ //#region src/extensions/workspaces/sessions/(frontend)/_components/GitReviewPanel.native.tsx
1836
+ function useGitChanges(sessionId) {
1837
+ const subscribe = useCallback((listener) => {
1838
+ const sub = gitChanges.store.subscribe(listener);
1839
+ return () => sub.unsubscribe();
1840
+ }, []);
1841
+ return useSyncExternalStore(subscribe, () => gitChanges.select(gitChanges.store.state, sessionId));
1842
+ }
1843
+ function reviewTab() {
1844
+ return {
1845
+ id: "git-review",
1846
+ label: "review",
1847
+ panel: GitReviewPanel
1848
+ };
1849
+ }
1850
+ function GitReviewPanel(props) {
1851
+ return /* @__PURE__ */ jsx(GitReviewPanelSession, { ...props }, props.sessionId);
1852
+ }
1853
+ function GitReviewPanelSession({ sessionId, sendSessionFrame }) {
1854
+ const activity = useGitChanges(sessionId);
1855
+ const subscribe = useCallback((listener) => {
1856
+ const sub = gitReview.store.subscribe(listener);
1857
+ return () => sub.unsubscribe();
1858
+ }, []);
1859
+ const comments = useSyncExternalStore(subscribe, () => gitReview.select(gitReview.store.state, sessionId).comments);
1860
+ const [summary, setSummary] = useState();
1861
+ const [file, setFile] = useState();
1862
+ const [error, setError] = useState();
1863
+ const [dismissedError, setDismissedError] = useState();
1864
+ const [confirm, setConfirm] = useState();
1865
+ const [screen, setScreen] = useState("changes");
1866
+ const [path, setPath] = useState();
1867
+ const [selection, setSelection] = useState();
1868
+ const [draft, setDraft] = useState();
1869
+ const [comment, setComment] = useState("");
1870
+ const request = useRef(void 0);
1871
+ const fingerprint = JSON.stringify(activity.changes);
1872
+ useEffect(() => {
1873
+ if (sessionId === null) return void 0;
1874
+ const controller = new AbortController();
1875
+ fetchReviewSummary(sessionId, controller.signal).then((result) => {
1876
+ if (!controller.signal.aborted) {
1877
+ if (result.ok) setSummary(result.summary);
1878
+ else setError(result.error);
1879
+ }
1880
+ }).catch((cause) => {
1881
+ if (!controller.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
1882
+ });
1883
+ return () => {
1884
+ controller.abort();
1885
+ request.current?.abort();
1886
+ };
1887
+ }, [sessionId, fingerprint]);
1888
+ const loadFile = async (path) => {
1889
+ if (sessionId === null) return;
1890
+ setScreen("file");
1891
+ setPath(path);
1892
+ setSelection(void 0);
1893
+ setDraft(void 0);
1894
+ request.current?.abort();
1895
+ const controller = new AbortController();
1896
+ request.current = controller;
1897
+ setFile(void 0);
1898
+ setError(void 0);
1899
+ try {
1900
+ const result = await fetchReviewFile(sessionId, path, controller.signal);
1901
+ if (!controller.signal.aborted) {
1902
+ if (result.ok) setFile(result.diff);
1903
+ else setError(result.error);
1904
+ }
1905
+ } catch (cause) {
1906
+ if (!controller.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
1907
+ }
1908
+ };
1909
+ if (sessionId === null) return null;
1910
+ const changes = activity.changes;
1911
+ const send = (message, onSent) => {
1912
+ const failure = deliverToAgent(sendSessionFrame, sessionId, message);
1913
+ setError(failure);
1914
+ if (failure === void 0) onSent?.();
1915
+ };
1916
+ const sync = (action) => requestGitSync(sessionId, action);
1917
+ const forceRequired = activity.error !== dismissedError && activity.errorTarget?.action === "push" && activity.errorTarget.forceRequired === true;
1918
+ const sendReview = () => {
1919
+ if (comments.length === 0) return;
1920
+ const body = comments.map((item) => {
1921
+ return `### ${item.startLine === void 0 ? item.relPath : item.side === "old" ? `${item.relPath} (removed lines ${item.startLine}-${item.endLine ?? item.startLine})` : `${item.relPath}:${item.startLine}-${item.endLine ?? item.startLine}`}\n\n${item.snippet.split("\n").slice(0, 20).join("\n").slice(0, 2e3).split("\n").map((line) => `> ${line}`).join("\n")}\n\n${item.body.trim()}`;
1922
+ }).join("\n\n");
1923
+ send(`${reviewHeading(comments.length, summary?.branch, summary?.base)}\n\n${body}`, () => clearReviewComments(sessionId));
1924
+ };
1925
+ const selectLine = (row) => {
1926
+ if (!file) return;
1927
+ const next = selectReviewLine(selection, row);
1928
+ setSelection(next.range);
1929
+ if (next.complete) {
1930
+ const rows = reviewRangeRows(file.hunks.flatMap((hunk) => hunk.rows), next.range);
1931
+ setDraft({
1932
+ path: file.path,
1933
+ range: next.range,
1934
+ snippet: rows.map((item) => item.content).join("\n")
1935
+ });
1936
+ }
1937
+ };
1938
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1939
+ /* @__PURE__ */ jsx(GitReviewView, {
1940
+ screen,
1941
+ activity: {
1942
+ ...activity,
1943
+ error: activity.error === dismissedError ? void 0 : activity.error
1944
+ },
1945
+ summary,
1946
+ file,
1947
+ path,
1948
+ comments,
1949
+ error,
1950
+ forceRequired,
1951
+ selection,
1952
+ onScreen: setScreen,
1953
+ onFile: (path) => void loadFile(path),
1954
+ onLine: selectLine,
1955
+ onSync: sync,
1956
+ onForce: () => setConfirm("force"),
1957
+ onAbort: () => setConfirm("abort"),
1958
+ onResolve: () => send(conflictPrompt(changes?.branch, changes?.rebase?.conflicts ?? [])),
1959
+ onDismiss: () => setDismissedError(activity.error),
1960
+ onComment: () => {
1961
+ if (path) {
1962
+ setSelection(void 0);
1963
+ setDraft({
1964
+ path,
1965
+ snippet: ""
1966
+ });
1967
+ }
1968
+ },
1969
+ onRemove: (id) => removeReviewComment(sessionId, id),
1970
+ onSend: sendReview,
1971
+ onDiscard: () => setConfirm("discard")
1972
+ }),
1973
+ /* @__PURE__ */ jsx(Sheet, {
1974
+ open: draft !== void 0,
1975
+ onOpenChange: (open) => {
1976
+ if (!open) {
1977
+ setDraft(void 0);
1978
+ setSelection(void 0);
1979
+ setComment("");
1980
+ }
1981
+ },
1982
+ children: /* @__PURE__ */ jsx(SheetContent, { children: /* @__PURE__ */ jsx(SheetBody, { children: /* @__PURE__ */ jsx(CommentSheet, {
1983
+ range: draft?.range,
1984
+ snippet: draft?.snippet ?? "",
1985
+ value: comment,
1986
+ onChange: setComment,
1987
+ onCancel: () => {
1988
+ setDraft(void 0);
1989
+ setSelection(void 0);
1990
+ setComment("");
1991
+ },
1992
+ onAdd: () => {
1993
+ if (!draft || !comment.trim()) return;
1994
+ addReviewComment(sessionId, {
1995
+ path: draft.path,
1996
+ relPath: draft.path,
1997
+ body: comment.trim(),
1998
+ snippet: draft.snippet,
1999
+ ...draft.range
2000
+ });
2001
+ setDraft(void 0);
2002
+ setSelection(void 0);
2003
+ setComment("");
2004
+ }
2005
+ }) }) })
2006
+ }),
2007
+ /* @__PURE__ */ jsx(Sheet, {
2008
+ open: confirm !== void 0,
2009
+ onOpenChange: (open) => {
2010
+ if (!open) setConfirm(void 0);
2011
+ },
2012
+ children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: confirm === "force" ? "Force push with lease?" : confirm === "abort" ? "Abort rebase?" : "Discard review?" }) }), /* @__PURE__ */ jsxs(SheetBody, { children: [
2013
+ /* @__PURE__ */ jsx(Text, {
2014
+ style: styles$1.dim,
2015
+ children: confirm === "force" ? "Git refuses this if the remote holds commits you never fetched and integrated." : confirm === "abort" ? "Abort discards any conflict resolution in progress." : "Your queued comments will be removed."
2016
+ }),
2017
+ /* @__PURE__ */ jsx(Button, {
2018
+ variant: "danger",
2019
+ disabled: confirm !== "discard" && activity.pending !== void 0,
2020
+ onPress: () => {
2021
+ if (confirm === "force") requestGitSync(sessionId, "push", true);
2022
+ else if (confirm === "abort") sync("abort-rebase");
2023
+ else clearReviewComments(sessionId);
2024
+ setConfirm(void 0);
2025
+ },
2026
+ children: confirm === "force" ? "Force push with lease" : confirm === "abort" ? "Abort rebase" : "Discard"
2027
+ }),
2028
+ /* @__PURE__ */ jsx(Button, {
1035
2029
  variant: "ghost",
1036
- onPress: () => openTransientTab(worktreesTab()),
1037
- children: item.branch
2030
+ onPress: () => setConfirm(void 0),
2031
+ children: "Cancel"
2032
+ })
2033
+ ] })] })
2034
+ })
2035
+ ] });
2036
+ }
2037
+ //#endregion
2038
+ //#region src/extensions/workspaces/sessions/(frontend)/fill/_components/WorktreesActivitySection.native.tsx
2039
+ function GitChangesRow({ state = "changes", branch = "Detached HEAD", added = 0, removed = 0, onReview }) {
2040
+ return /* @__PURE__ */ jsxs(Pressable, {
2041
+ testID: "activity-diff-changes",
2042
+ accessibilityRole: "button",
2043
+ accessibilityLabel: "Open changes review",
2044
+ onPress: onReview,
2045
+ style: styles.changeRow,
2046
+ children: [/* @__PURE__ */ jsxs(View, {
2047
+ style: styles.line,
2048
+ children: [
2049
+ /* @__PURE__ */ jsx(FileIcon, {
2050
+ size: 18,
2051
+ color: "dim"
2052
+ }),
2053
+ /* @__PURE__ */ jsx(Text, {
2054
+ style: [styles.heading, styles.grow],
2055
+ children: "Changes"
1038
2056
  }),
1039
- description: [item.orphaned ? "Orphaned" : "", item.unowned ? "Unowned" : ""].filter(Boolean).join(" · ")
2057
+ /* @__PURE__ */ jsx(ChevronRightIcon, {
2058
+ size: 16,
2059
+ color: "dim"
2060
+ })
2061
+ ]
2062
+ }), /* @__PURE__ */ jsxs(View, {
2063
+ style: styles.changeDetail,
2064
+ children: [/* @__PURE__ */ jsx(Text, {
2065
+ style: [styles.branch, styles.grow],
2066
+ children: branch
2067
+ }), state === "changes" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, {
2068
+ style: styles.jade,
2069
+ children: ["+", added]
2070
+ }), /* @__PURE__ */ jsxs(Text, {
2071
+ style: styles.error,
2072
+ children: ["-", removed]
2073
+ })] }) : state === "pushing" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, { label: "Pushing..." }), /* @__PURE__ */ jsx(Text, {
2074
+ style: styles.dim,
2075
+ children: "Pushing..."
2076
+ })] }) : /* @__PURE__ */ jsx(Text, {
2077
+ style: styles.dim,
2078
+ children: "No changes yet"
2079
+ })]
2080
+ })]
2081
+ });
2082
+ }
2083
+ function WorktreesActivityView({ git, state, disabled = false, onReview, onWorktrees }) {
2084
+ const { starting } = worktreesPresentation(state);
2085
+ return /* @__PURE__ */ jsxs(View, {
2086
+ style: styles.section,
2087
+ children: [
2088
+ git.changes ? /* @__PURE__ */ jsx(GitChangesRow, {
2089
+ branch: git.changes.branch ?? "Detached HEAD",
2090
+ added: git.changes.added,
2091
+ removed: git.changes.removed,
2092
+ state: git.pending?.startsWith("pushing") ? "pushing" : git.changes.added === 0 && git.changes.removed === 0 && git.changes.files === 0 ? "clean" : "changes",
2093
+ onReview
2094
+ }) : null,
2095
+ /* @__PURE__ */ jsx(WorktreeGroup, {
2096
+ title: "Worktrees",
2097
+ count: `${state.worktrees.length} open${starting ? " · 1 starting" : ""}`
2098
+ }),
2099
+ state.worktrees.map((item) => /* @__PURE__ */ jsx(WorktreeRow, {
2100
+ item,
2101
+ compact: true,
2102
+ onOpen: onWorktrees
1040
2103
  }, item.id)),
1041
- worktrees.length === 0 && state.pending === void 0 ? /* @__PURE__ */ jsxs(View, {
2104
+ starting ? /* @__PURE__ */ jsx(WorktreeStarting, { branch: state.requestedBranch }) : state.pending ? /* @__PURE__ */ jsx(Text, {
2105
+ style: styles.dim,
2106
+ children: state.pending
2107
+ }) : null,
2108
+ state.worktrees.length === 0 && !state.pending ? /* @__PURE__ */ jsxs(View, {
1042
2109
  style: styles.idle,
1043
2110
  children: [/* @__PURE__ */ jsx(Text, {
1044
- style: styles.status,
2111
+ style: styles.dim,
1045
2112
  children: "Idle"
1046
- }), /* @__PURE__ */ jsxs(Pressable, {
1047
- accessibilityRole: "button",
1048
- accessibilityState: { disabled: sessionId === null },
2113
+ }), /* @__PURE__ */ jsx(Button, {
1049
2114
  testID: "activity-git-create",
1050
- disabled: sessionId === null,
1051
- hitSlop: 10,
1052
- onPress: () => openTransientTab(worktreesTab()),
1053
- style: styles.action,
1054
- children: [/* @__PURE__ */ jsx(Text, {
1055
- style: styles.actionText(sessionId === null),
1056
- children: "Create a worktree"
1057
- }), /* @__PURE__ */ jsx(ArrowRightIcon, {
1058
- size: 14,
1059
- color: sessionId === null ? "dim" : "green"
1060
- })]
2115
+ variant: "ghost",
2116
+ style: styles.link,
2117
+ disabled,
2118
+ onPress: onWorktrees,
2119
+ children: /* @__PURE__ */ jsx(Text, {
2120
+ style: styles.jade,
2121
+ children: "Create a worktree →"
2122
+ })
1061
2123
  })]
1062
2124
  }) : null
1063
2125
  ]
1064
2126
  });
1065
2127
  }
1066
- const styles = StyleSheet.create((theme) => {
1067
- const sm = {
2128
+ function WorktreesActivitySection({ sessionId, openTransientTab }) {
2129
+ const git = useGitChanges(sessionId);
2130
+ const state = useWorktrees(sessionId);
2131
+ return /* @__PURE__ */ jsx(WorktreesActivityView, {
2132
+ git,
2133
+ state: {
2134
+ ...state,
2135
+ worktrees: state.worktrees.filter((item) => item.sessionId !== sessionId)
2136
+ },
2137
+ disabled: sessionId === null,
2138
+ onReview: () => openTransientTab(reviewTab()),
2139
+ onWorktrees: () => openTransientTab(worktreesTab())
2140
+ });
2141
+ }
2142
+ const styles = StyleSheet.create((theme) => ({
2143
+ section: {
2144
+ gap: theme.spacing(2),
2145
+ uni__dependencies: [0]
2146
+ },
2147
+ heading: {
2148
+ fontFamily: fontOf(theme.fontFamily.sans),
2149
+ fontSize: theme.fontSize.lg,
2150
+ lineHeight: theme.lineHeight.lg,
2151
+ fontWeight: "600",
2152
+ color: theme.colors.hi,
2153
+ uni__dependencies: [0]
2154
+ },
2155
+ dim: {
1068
2156
  fontFamily: fontOf(theme.fontFamily.sans),
1069
2157
  fontSize: theme.fontSize.sm,
1070
- lineHeight: theme.lineHeight.sm
1071
- };
1072
- return {
1073
- section: {
1074
- gap: theme.spacing(1.5),
1075
- uni__dependencies: [0]
1076
- },
1077
- changes: {
1078
- flexDirection: "row",
1079
- alignItems: "center",
1080
- gap: theme.spacing(2),
1081
- uni__dependencies: [0]
1082
- },
1083
- branch: {
1084
- ...sm,
1085
- flex: 1,
1086
- fontFamily: fontOf(theme.fontFamily.mono),
1087
- fontWeight: theme.fontWeight.semibold,
1088
- color: theme.colors.hi,
1089
- uni__dependencies: [0]
1090
- },
1091
- added: {
1092
- ...sm,
1093
- color: theme.colors.green,
1094
- uni__dependencies: [0]
1095
- },
1096
- removed: {
1097
- ...sm,
1098
- color: theme.colors.red,
1099
- uni__dependencies: [0]
1100
- },
1101
- idle: {
1102
- flexDirection: "row",
1103
- alignItems: "center",
1104
- flexWrap: "wrap",
1105
- gap: theme.spacing(4),
1106
- uni__dependencies: [0]
1107
- },
1108
- status: {
1109
- ...sm,
1110
- color: theme.colors.dim,
1111
- uni__dependencies: [0]
1112
- },
1113
- action: {
1114
- flexDirection: "row",
1115
- alignItems: "center",
1116
- gap: theme.spacing(1),
1117
- uni__dependencies: [0]
1118
- },
1119
- actionText: (disabled) => ({
1120
- fontFamily: fontOf(theme.fontFamily.sans),
1121
- fontSize: theme.fontSize.base,
1122
- lineHeight: theme.lineHeight.base,
1123
- fontWeight: theme.fontWeight.medium,
1124
- color: disabled ? theme.colors.dim : theme.colors.green,
1125
- uni__dependencies: [0]
1126
- })
1127
- };
1128
- });
2158
+ lineHeight: theme.lineHeight.sm,
2159
+ color: theme.colors.dim,
2160
+ uni__dependencies: [0]
2161
+ },
2162
+ branch: {
2163
+ fontFamily: fontOf(theme.fontFamily.mono),
2164
+ fontSize: theme.fontSize.base,
2165
+ lineHeight: theme.lineHeight.lg,
2166
+ color: theme.colors.hi,
2167
+ uni__dependencies: [0]
2168
+ },
2169
+ line: {
2170
+ flexDirection: "row",
2171
+ alignItems: "center",
2172
+ gap: theme.spacing(2),
2173
+ minHeight: 44,
2174
+ uni__dependencies: [0]
2175
+ },
2176
+ grow: {
2177
+ flex: 1,
2178
+ minWidth: 0,
2179
+ gap: theme.spacing(1),
2180
+ uni__dependencies: [0]
2181
+ },
2182
+ jade: {
2183
+ fontFamily: fontOf(theme.fontFamily.sans),
2184
+ fontSize: theme.fontSize.base,
2185
+ lineHeight: theme.lineHeight.base,
2186
+ color: theme.colors.green,
2187
+ fontWeight: "500",
2188
+ uni__dependencies: [0]
2189
+ },
2190
+ error: {
2191
+ fontFamily: fontOf(theme.fontFamily.sans),
2192
+ fontSize: theme.fontSize.sm,
2193
+ lineHeight: theme.lineHeight.sm,
2194
+ color: theme.colors.red,
2195
+ uni__dependencies: [0]
2196
+ },
2197
+ changeRow: {
2198
+ gap: theme.spacing(1),
2199
+ paddingVertical: theme.spacing(2),
2200
+ borderBottomWidth: StyleSheet.hairlineWidth,
2201
+ borderColor: theme.colors["border-soft"],
2202
+ uni__dependencies: [0]
2203
+ },
2204
+ changeDetail: {
2205
+ flexDirection: "row",
2206
+ alignItems: "center",
2207
+ gap: theme.spacing(3),
2208
+ paddingLeft: theme.spacing(6),
2209
+ minHeight: 28,
2210
+ uni__dependencies: [0]
2211
+ },
2212
+ idle: {
2213
+ flexDirection: "row",
2214
+ alignItems: "center",
2215
+ gap: theme.spacing(4),
2216
+ uni__dependencies: [0]
2217
+ },
2218
+ link: {
2219
+ minHeight: 44,
2220
+ paddingHorizontal: 0
2221
+ }
2222
+ }));
1129
2223
  //#endregion
1130
2224
  //#region src/extensions/workspaces/sessions/(frontend)/fill/Worktrees.activity.git.native.tsx
1131
2225
  var Worktrees_activity_git_native_default = defineFill({ component: WorktreesActivitySection });