@cat-factory/app 0.147.0 → 0.147.1

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.
@@ -17,9 +17,11 @@ import type {
17
17
  PrReviewResolution,
18
18
  PrReviewSeverity,
19
19
  PrReviewStepState,
20
+ StepSubtaskItem,
20
21
  StepSubtasks,
21
22
  } from '~/types/execution'
22
23
  import { subtaskIconClass } from '~/utils/pipelineRender'
24
+ import { activeChunkLabels, chunkReviewPercent, isSlicingChunks } from '~/utils/prReviewProgress'
23
25
  import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
24
26
 
25
27
  const execution = useExecutionStore()
@@ -51,17 +53,46 @@ const awaiting = computed(() => status.value === 'awaiting_selection')
51
53
  // selection controls + per-finding actions are disabled until the verdict lands and it re-parks.
52
54
  const challenging = computed(() => status.value === 'challenging')
53
55
  // The reviewer's live todo list while it works, streamed onto the step. Its entries are the
54
- // cohesive slices/chunks the agent grouped the diff into (plus a final "aggregate" step), so it
55
- // surfaces slices-reviewed-so-far progress during the `reviewing` phase richer than a spinner.
56
+ // cohesive slices/chunks the agent grouped the diff into (plus a final "aggregate" step). The
57
+ // derivation of the two `reviewing`-phase sub-states from it lives in `~/utils/prReviewProgress`
58
+ // (pure + unit-tested); see that module for the slicing-vs-reviewing signal.
56
59
  const subtasks = computed<StepSubtasks | null>(() => step.value?.subtasks ?? null)
57
- const hasProgress = computed(() => (subtasks.value?.total ?? 0) > 0)
60
+
61
+ /**
62
+ * Slicing sub-phase: the reviewer is still grouping the diff into chunks (no todo list yet).
63
+ * Once the list exists, slicing is done and we render the per-chunk status list instead.
64
+ */
65
+ const slicing = computed(() => status.value === 'reviewing' && isSlicingChunks(subtasks.value))
66
+
67
+ /** Chunk-review completion, clamped 0..100 for the progress bar. */
68
+ const chunkPercent = computed(() => chunkReviewPercent(subtasks.value))
69
+
70
+ /** The chunks the reviewer is actively working through right now (their labels), for the callout. */
71
+ const activeChunks = computed<string[]>(() => activeChunkLabels(subtasks.value))
58
72
 
59
73
  /** Icon per todo-item status (matches the pipeline timeline's live subtask breakdown). */
60
- const ITEM_ICON: Record<string, string> = {
74
+ const ITEM_ICON: Record<StepSubtaskItem['status'], string> = {
61
75
  completed: 'i-lucide-check-circle-2',
62
76
  in_progress: 'i-lucide-loader-circle',
63
77
  pending: 'i-lucide-circle',
64
78
  }
79
+
80
+ // Per-chunk status label + chip styling. The key map is an exhaustive Record over the subtask
81
+ // status union, so adding a status without a label fails the typecheck (the sanctioned dynamic
82
+ // enum→key pattern — tier 1 can't see a runtime-built key).
83
+ const CHUNK_STATUS_KEY: Record<StepSubtaskItem['status'], string> = {
84
+ completed: 'prReview.reviewing.chunkStatus.completed',
85
+ in_progress: 'prReview.reviewing.chunkStatus.in_progress',
86
+ pending: 'prReview.reviewing.chunkStatus.pending',
87
+ }
88
+ const CHUNK_STATUS_CLASS: Record<StepSubtaskItem['status'], string> = {
89
+ completed: 'bg-emerald-500/15 text-emerald-300',
90
+ in_progress: 'bg-indigo-500/15 text-indigo-300',
91
+ pending: 'bg-slate-700/60 text-slate-400',
92
+ }
93
+ function chunkStatusLabel(status: StepSubtaskItem['status']): string {
94
+ return t(CHUNK_STATUS_KEY[status])
95
+ }
65
96
  // A resolution is executing (the Fixer is committing, or comments are being posted) — show a
66
97
  // working state between the human's choice and the run advancing/the stream echoing `done`.
67
98
  const working = computed(() => status.value === 'fixing' || status.value === 'posting')
@@ -223,24 +254,39 @@ async function onDismiss(id: string): Promise<void> {
223
254
  </template>
224
255
 
225
256
  <div class="min-h-0 flex-1 overflow-y-auto px-5 py-4">
226
- <!-- Reviewing: the read-only reviewer is still working. Once it starts maintaining its
227
- per-slice todo list, surface the live chunk progress (slices reviewed / total + the
228
- breakdown) instead of a bare spinner. -->
257
+ <!-- Reviewing: the read-only reviewer is still working. The phase is told apart precisely —
258
+ SLICING (still grouping the diff into chunks, no plan yet) vs REVIEWING (slicing done,
259
+ working through the chunks) so the copy never claims "reviewing" while it's slicing. -->
229
260
  <div
230
261
  v-if="status === 'reviewing'"
231
262
  data-testid="pr-review-reviewing"
232
263
  class="flex h-full flex-col"
233
264
  >
234
- <!-- Live chunk progress once the reviewer has planned its slices. -->
235
- <div v-if="hasProgress" class="py-2">
265
+ <!-- SLICING: no todo list yet — the reviewer is still grouping the diff into chunks. -->
266
+ <div
267
+ v-if="slicing"
268
+ data-testid="pr-review-slicing"
269
+ class="flex h-full flex-col items-center justify-center gap-2 py-10 text-center text-slate-400"
270
+ >
271
+ <UIcon name="i-lucide-loader-circle" class="h-8 w-8 animate-spin opacity-60" />
272
+ <p class="text-sm text-slate-200">{{ t('prReview.reviewing.slicing.title') }}</p>
273
+ <p class="max-w-sm text-[11px] text-slate-500">
274
+ {{ t('prReview.reviewing.slicing.hint') }}
275
+ </p>
276
+ </div>
277
+
278
+ <!-- REVIEWING: slicing is done — show every chunk with its status + which are active now. -->
279
+ <div v-else data-testid="pr-review-reviewing-chunks" class="py-2">
236
280
  <div class="mb-1 flex items-center gap-2 text-sm text-slate-200">
237
281
  <UIcon
238
282
  name="i-lucide-loader-circle"
239
283
  class="h-4 w-4 shrink-0 animate-spin text-indigo-300"
240
284
  />
241
- <span>{{ t('prReview.reviewing.title') }}</span>
285
+ <span>{{ t('prReview.reviewing.reviewingChunks.title') }}</span>
242
286
  </div>
243
- <p class="mb-3 text-[11px] text-slate-500">{{ t('prReview.reviewing.hint') }}</p>
287
+ <p class="mb-3 text-[11px] text-slate-500">
288
+ {{ t('prReview.reviewing.reviewingChunks.hint') }}
289
+ </p>
244
290
 
245
291
  <div class="flex items-center justify-between text-[11px] text-slate-400">
246
292
  <span data-testid="pr-review-chunk-count">
@@ -258,46 +304,74 @@ async function onDismiss(id: string): Promise<void> {
258
304
  <div class="mt-1 h-1.5 overflow-hidden rounded-full bg-slate-700/60">
259
305
  <div
260
306
  class="h-full rounded-full bg-indigo-400 transition-all duration-500"
261
- :style="{ width: `${(subtasks!.completed / subtasks!.total) * 100}%` }"
307
+ :style="{ width: `${chunkPercent}%` }"
262
308
  />
263
309
  </div>
264
310
 
265
- <!-- The slice/todo breakdown the agent is working through. -->
266
- <ul
267
- v-if="subtasks!.items?.length"
268
- class="mt-3 space-y-1.5"
269
- data-testid="pr-review-chunks"
311
+ <!-- The chunk(s) being actively reviewed right now, called out on their own. -->
312
+ <div
313
+ v-if="activeChunks.length"
314
+ data-testid="pr-review-active-chunks"
315
+ class="mt-3 rounded-lg border border-indigo-500/30 bg-indigo-500/5 px-2.5 py-2"
270
316
  >
271
- <li
272
- v-for="(item, i) in subtasks!.items"
273
- :key="i"
274
- class="flex items-start gap-1.5 text-[12px]"
275
- :class="
276
- item.status === 'completed'
277
- ? 'text-slate-500 line-through'
278
- : item.status === 'in_progress'
279
- ? 'text-slate-100'
280
- : 'text-slate-400'
281
- "
282
- >
283
- <UIcon
284
- :name="ITEM_ICON[item.status]"
285
- class="mt-0.5 h-3.5 w-3.5 shrink-0"
286
- :class="subtaskIconClass(item.status, false)"
287
- />
288
- <span>{{ item.label }}</span>
289
- </li>
290
- </ul>
291
- </div>
317
+ <p class="mb-1 text-[10px] font-semibold uppercase tracking-wide text-indigo-300">
318
+ {{ t('prReview.reviewing.activeHeading') }}
319
+ </p>
320
+ <ul class="space-y-1">
321
+ <li
322
+ v-for="(label, i) in activeChunks"
323
+ :key="i"
324
+ class="flex items-start gap-1.5 text-[12px] text-slate-100"
325
+ >
326
+ <UIcon
327
+ name="i-lucide-loader-circle"
328
+ class="mt-0.5 h-3.5 w-3.5 shrink-0 animate-spin text-indigo-300"
329
+ />
330
+ <span class="min-w-0">{{ label }}</span>
331
+ </li>
332
+ </ul>
333
+ </div>
292
334
 
293
- <!-- Before the reviewer has planned its slices: the cold-start spinner. -->
294
- <div
295
- v-else
296
- class="flex h-full flex-col items-center justify-center gap-2 py-10 text-center text-slate-400"
297
- >
298
- <UIcon name="i-lucide-loader-circle" class="h-8 w-8 animate-spin opacity-60" />
299
- <p class="text-sm">{{ t('prReview.reviewing.title') }}</p>
300
- <p class="max-w-sm text-[11px] text-slate-500">{{ t('prReview.reviewing.hint') }}</p>
335
+ <!-- Every chunk with its explicit status (Reviewed / Reviewing… / Queued). -->
336
+ <template v-if="subtasks!.items?.length">
337
+ <p class="mb-1.5 mt-3 text-[10px] font-semibold uppercase tracking-wide text-slate-400">
338
+ {{ t('prReview.reviewing.chunksHeading') }}
339
+ </p>
340
+ <ul class="space-y-1.5" data-testid="pr-review-chunks">
341
+ <li
342
+ v-for="(item, i) in subtasks!.items"
343
+ :key="i"
344
+ data-testid="pr-review-chunk"
345
+ class="flex items-center gap-1.5 text-[12px]"
346
+ :class="
347
+ item.status === 'completed'
348
+ ? 'text-slate-500'
349
+ : item.status === 'in_progress'
350
+ ? 'text-slate-100'
351
+ : 'text-slate-400'
352
+ "
353
+ >
354
+ <UIcon
355
+ :name="ITEM_ICON[item.status]"
356
+ class="h-3.5 w-3.5 shrink-0"
357
+ :class="subtaskIconClass(item.status, false)"
358
+ />
359
+ <span
360
+ class="min-w-0 flex-1 truncate"
361
+ :class="item.status === 'completed' ? 'line-through' : ''"
362
+ >
363
+ {{ item.label }}
364
+ </span>
365
+ <span
366
+ data-testid="pr-review-chunk-status"
367
+ class="shrink-0 rounded px-1.5 py-0.5 text-[10px] font-medium uppercase"
368
+ :class="CHUNK_STATUS_CLASS[item.status]"
369
+ >
370
+ {{ chunkStatusLabel(item.status) }}
371
+ </span>
372
+ </li>
373
+ </ul>
374
+ </template>
301
375
  </div>
302
376
  </div>
303
377
 
@@ -0,0 +1,73 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import type { StepSubtasks } from '~/types/execution'
3
+ import { activeChunkLabels, chunkReviewPercent, isSlicingChunks } from './prReviewProgress'
4
+
5
+ const subtasks = (over: Partial<StepSubtasks>): StepSubtasks => ({
6
+ completed: 0,
7
+ inProgress: 0,
8
+ total: 0,
9
+ ...over,
10
+ })
11
+
12
+ describe('isSlicingChunks', () => {
13
+ it('is slicing when there is no todo list yet (null/undefined or empty)', () => {
14
+ // No plan committed → the reviewer is still grouping the diff into chunks.
15
+ expect(isSlicingChunks(null)).toBe(true)
16
+ expect(isSlicingChunks(undefined)).toBe(true)
17
+ expect(isSlicingChunks(subtasks({ total: 0 }))).toBe(true)
18
+ })
19
+
20
+ it('is not slicing once the todo list exists (slicing is done)', () => {
21
+ expect(isSlicingChunks(subtasks({ total: 3, completed: 1 }))).toBe(false)
22
+ // A single-chunk plan still counts as sliced — a plan of size 1 is a committed plan.
23
+ expect(isSlicingChunks(subtasks({ total: 1 }))).toBe(false)
24
+ })
25
+ })
26
+
27
+ describe('chunkReviewPercent', () => {
28
+ it('is 0 with no plan (avoids 0/0 → NaN)', () => {
29
+ expect(chunkReviewPercent(null)).toBe(0)
30
+ expect(chunkReviewPercent(subtasks({ total: 0, completed: 0 }))).toBe(0)
31
+ })
32
+
33
+ it('rounds completion to an integer percent', () => {
34
+ expect(chunkReviewPercent(subtasks({ total: 4, completed: 1 }))).toBe(25)
35
+ // 1/3 → 33.33… rounds to 33 (the old inline math emitted a fractional width).
36
+ expect(chunkReviewPercent(subtasks({ total: 3, completed: 1 }))).toBe(33)
37
+ })
38
+
39
+ it('clamps to 0..100 even if counts are inconsistent', () => {
40
+ expect(chunkReviewPercent(subtasks({ total: 2, completed: 5 }))).toBe(100)
41
+ expect(chunkReviewPercent(subtasks({ total: 2, completed: -1 }))).toBe(0)
42
+ })
43
+ })
44
+
45
+ describe('activeChunkLabels', () => {
46
+ it('returns only the in-progress chunk labels, in order', () => {
47
+ const s = subtasks({
48
+ total: 3,
49
+ completed: 1,
50
+ inProgress: 1,
51
+ items: [
52
+ { label: 'auth', status: 'completed' },
53
+ { label: 'db layer', status: 'in_progress' },
54
+ { label: 'ui', status: 'pending' },
55
+ ],
56
+ })
57
+ expect(activeChunkLabels(s)).toEqual(['db layer'])
58
+ })
59
+
60
+ it('is empty with no items or no in-progress chunk', () => {
61
+ expect(activeChunkLabels(null)).toEqual([])
62
+ expect(activeChunkLabels(subtasks({ total: 2 }))).toEqual([])
63
+ expect(
64
+ activeChunkLabels(
65
+ subtasks({
66
+ total: 1,
67
+ completed: 1,
68
+ items: [{ label: 'only', status: 'completed' }],
69
+ }),
70
+ ),
71
+ ).toEqual([])
72
+ })
73
+ })
@@ -0,0 +1,28 @@
1
+ import type { StepSubtasks } from '~/types/execution'
2
+
3
+ // Pure derivation of the PR deep-reviewer's `reviewing`-phase progress, factored out of
4
+ // `PrReviewWindow.vue` so it is unit-testable independently of the Vue component.
5
+ //
6
+ // The reviewer maintains a per-slice todo list (`step.subtasks`) once it has grouped the diff
7
+ // into cohesive chunks. The PRESENCE of that list is the signal that slicing is done, so the two
8
+ // `reviewing` sub-phases are told apart by it:
9
+ // - no todo list yet (`total === 0`) → still SLICING the diff into chunks (no plan committed).
10
+ // - todo list present (`total > 0`) → slicing DONE, working through the chunks.
11
+
12
+ /** True while the reviewer is still grouping the diff into chunks (it has not committed a plan). */
13
+ export function isSlicingChunks(subtasks: StepSubtasks | null | undefined): boolean {
14
+ return (subtasks?.total ?? 0) <= 0
15
+ }
16
+
17
+ /** Chunk-review completion as an integer percent, clamped 0..100, for the progress bar. */
18
+ export function chunkReviewPercent(subtasks: StepSubtasks | null | undefined): number {
19
+ const total = subtasks?.total ?? 0
20
+ if (total <= 0) return 0
21
+ const completed = subtasks?.completed ?? 0
22
+ return Math.min(100, Math.max(0, Math.round((completed / total) * 100)))
23
+ }
24
+
25
+ /** Labels of the chunk(s) the reviewer is actively working through right now (for the callout). */
26
+ export function activeChunkLabels(subtasks: StepSubtasks | null | undefined): string[] {
27
+ return subtasks?.items?.filter((i) => i.status === 'in_progress').map((i) => i.label) ?? []
28
+ }
@@ -4943,10 +4943,23 @@
4943
4943
  "suggestedFix": "Lösungsvorschlag:",
4944
4944
  "line": "Zeile {line}",
4945
4945
  "reviewing": {
4946
- "title": "Pull Request wird geprüft…",
4947
- "hint": "Der Diff wird in zusammenhängende Teile zerlegt und einzeln geprüft.",
4946
+ "slicing": {
4947
+ "title": "Diff wird in Abschnitte zerlegt",
4948
+ "hint": "Die geänderten Dateien werden in zusammenhängende Abschnitte gruppiert, damit jeder einzeln geprüft werden kann. Die Abschnittsliste erscheint hier, sobald die Zerlegung abgeschlossen ist."
4949
+ },
4950
+ "reviewingChunks": {
4951
+ "title": "Abschnitte werden geprüft…",
4952
+ "hint": "Die Zerlegung ist abgeschlossen. Jeder Abschnitt wird nacheinander geprüft und die Ergebnisse werden gesammelt."
4953
+ },
4948
4954
  "chunks": "{completed} von {total} Abschnitten geprüft",
4949
- "inProgress": "{count} in Bearbeitung"
4955
+ "inProgress": "{count} in Bearbeitung",
4956
+ "activeHeading": "Wird jetzt geprüft",
4957
+ "chunksHeading": "Abschnitte",
4958
+ "chunkStatus": {
4959
+ "completed": "Geprüft",
4960
+ "in_progress": "Wird geprüft…",
4961
+ "pending": "In Warteschlange"
4962
+ }
4950
4963
  },
4951
4964
  "challenge": {
4952
4965
  "action": "Anfechten",
@@ -5072,10 +5072,23 @@
5072
5072
  "suggestedFix": "Suggested fix:",
5073
5073
  "line": "line {line}",
5074
5074
  "reviewing": {
5075
- "title": "Reviewing the pull request…",
5076
- "hint": "Slicing the diff into cohesive chunks and reviewing each one.",
5075
+ "slicing": {
5076
+ "title": "Slicing the diff into chunks",
5077
+ "hint": "Grouping the changed files into cohesive chunks so each can be reviewed on its own. The chunk list appears here once slicing is done."
5078
+ },
5079
+ "reviewingChunks": {
5080
+ "title": "Reviewing the chunks…",
5081
+ "hint": "Slicing is done. Working through each chunk one at a time and collecting findings."
5082
+ },
5077
5083
  "chunks": "{completed} of {total} chunks reviewed",
5078
- "inProgress": "{count} in progress"
5084
+ "inProgress": "{count} in progress",
5085
+ "activeHeading": "Reviewing now",
5086
+ "chunksHeading": "Chunks",
5087
+ "chunkStatus": {
5088
+ "completed": "Reviewed",
5089
+ "in_progress": "Reviewing…",
5090
+ "pending": "Queued"
5091
+ }
5079
5092
  },
5080
5093
  "challenge": {
5081
5094
  "action": "Challenge",
@@ -4931,10 +4931,23 @@
4931
4931
  "suggestedFix": "Corrección sugerida:",
4932
4932
  "line": "línea {line}",
4933
4933
  "reviewing": {
4934
- "title": "Revisando el pull request…",
4935
- "hint": "Dividiendo el diff en bloques coherentes y revisando cada uno.",
4934
+ "slicing": {
4935
+ "title": "Dividiendo el diff en fragmentos…",
4936
+ "hint": "Agrupando los archivos modificados en fragmentos coherentes para revisar cada uno por separado. La lista de fragmentos aparecerá aquí cuando termine la división."
4937
+ },
4938
+ "reviewingChunks": {
4939
+ "title": "Revisando los fragmentos…",
4940
+ "hint": "La división ha terminado. Revisando cada fragmento de uno en uno y recopilando los hallazgos."
4941
+ },
4936
4942
  "chunks": "{completed} de {total} fragmentos revisados",
4937
- "inProgress": "{count} en curso"
4943
+ "inProgress": "{count} en curso",
4944
+ "activeHeading": "Revisando ahora",
4945
+ "chunksHeading": "Fragmentos",
4946
+ "chunkStatus": {
4947
+ "completed": "Revisado",
4948
+ "in_progress": "Revisando…",
4949
+ "pending": "En cola"
4950
+ }
4938
4951
  },
4939
4952
  "challenge": {
4940
4953
  "action": "Cuestionar",
@@ -4931,10 +4931,23 @@
4931
4931
  "suggestedFix": "Correction suggérée :",
4932
4932
  "line": "ligne {line}",
4933
4933
  "reviewing": {
4934
- "title": "Revue de la pull request…",
4935
- "hint": "Découpage du diff en blocs cohérents et revue de chacun.",
4934
+ "slicing": {
4935
+ "title": "Découpage du diff en sections…",
4936
+ "hint": "Regroupement des fichiers modifiés en sections cohérentes afin de pouvoir examiner chacune séparément. La liste des sections apparaîtra ici une fois le découpage terminé."
4937
+ },
4938
+ "reviewingChunks": {
4939
+ "title": "Revue des sections…",
4940
+ "hint": "Le découpage est terminé. Chaque section est examinée l'une après l'autre et les remarques sont rassemblées."
4941
+ },
4936
4942
  "chunks": "{completed} sur {total} sections examinées",
4937
- "inProgress": "{count} en cours"
4943
+ "inProgress": "{count} en cours",
4944
+ "activeHeading": "Revue en cours",
4945
+ "chunksHeading": "Sections",
4946
+ "chunkStatus": {
4947
+ "completed": "Examinée",
4948
+ "in_progress": "En cours d'examen…",
4949
+ "pending": "En attente"
4950
+ }
4938
4951
  },
4939
4952
  "challenge": {
4940
4953
  "action": "Contester",
@@ -4942,10 +4942,23 @@
4942
4942
  "suggestedFix": "תיקון מוצע:",
4943
4943
  "line": "שורה {line}",
4944
4944
  "reviewing": {
4945
- "title": "בודק את בקשת המשיכה…",
4946
- "hint": "מחלק את ההבדלים לקטעים לכידים ובודק כל אחד.",
4945
+ "slicing": {
4946
+ "title": "מחלק את ההבדלים למקטעים…",
4947
+ "hint": "מקבץ את הקבצים שהשתנו למקטעים לכידים כדי לבדוק כל אחד בנפרד. רשימת המקטעים תופיע כאן לאחר סיום החלוקה."
4948
+ },
4949
+ "reviewingChunks": {
4950
+ "title": "בודק את המקטעים…",
4951
+ "hint": "החלוקה הסתיימה. בודק כל מקטע בנפרד ואוסף את הממצאים."
4952
+ },
4947
4953
  "chunks": "{completed} מתוך {total} מקטעים נבדקו",
4948
- "inProgress": "{count} בתהליך"
4954
+ "inProgress": "{count} בתהליך",
4955
+ "activeHeading": "נבדק כעת",
4956
+ "chunksHeading": "מקטעים",
4957
+ "chunkStatus": {
4958
+ "completed": "נבדק",
4959
+ "in_progress": "בבדיקה…",
4960
+ "pending": "בתור"
4961
+ }
4949
4962
  },
4950
4963
  "challenge": {
4951
4964
  "action": "ערער",
@@ -4943,10 +4943,23 @@
4943
4943
  "suggestedFix": "Correzione suggerita:",
4944
4944
  "line": "riga {line}",
4945
4945
  "reviewing": {
4946
- "title": "Revisione della pull request…",
4947
- "hint": "Suddivisione del diff in blocchi coerenti e revisione di ciascuno.",
4946
+ "slicing": {
4947
+ "title": "Suddivisione del diff in blocchi",
4948
+ "hint": "Raggruppamento dei file modificati in blocchi coerenti per esaminare ciascuno separatamente. L'elenco dei blocchi comparirà qui al termine della suddivisione."
4949
+ },
4950
+ "reviewingChunks": {
4951
+ "title": "Revisione dei blocchi…",
4952
+ "hint": "La suddivisione è terminata. Ogni blocco viene esaminato uno alla volta e le osservazioni vengono raccolte."
4953
+ },
4948
4954
  "chunks": "{completed} di {total} sezioni esaminate",
4949
- "inProgress": "{count} in corso"
4955
+ "inProgress": "{count} in corso",
4956
+ "activeHeading": "In revisione ora",
4957
+ "chunksHeading": "Blocchi",
4958
+ "chunkStatus": {
4959
+ "completed": "Esaminato",
4960
+ "in_progress": "In revisione…",
4961
+ "pending": "In coda"
4962
+ }
4950
4963
  },
4951
4964
  "challenge": {
4952
4965
  "action": "Contesta",
@@ -4943,10 +4943,23 @@
4943
4943
  "suggestedFix": "修正案:",
4944
4944
  "line": "{line}行目",
4945
4945
  "reviewing": {
4946
- "title": "プルリクエストをレビュー中…",
4947
- "hint": "差分をまとまりのある単位に分割し、各単位をレビューしています。",
4946
+ "slicing": {
4947
+ "title": "差分をチャンクに分割中…",
4948
+ "hint": "変更されたファイルをまとまりのあるチャンクにグループ化し、各チャンクを個別にレビューできるようにしています。分割が完了すると、ここにチャンク一覧が表示されます。"
4949
+ },
4950
+ "reviewingChunks": {
4951
+ "title": "チャンクをレビュー中…",
4952
+ "hint": "分割は完了しました。各チャンクを一つずつレビューし、指摘事項を収集しています。"
4953
+ },
4948
4954
  "chunks": "{total} 個中 {completed} 個のチャンクをレビュー済み",
4949
- "inProgress": "{count} 件処理中"
4955
+ "inProgress": "{count} 件処理中",
4956
+ "activeHeading": "レビュー中",
4957
+ "chunksHeading": "チャンク",
4958
+ "chunkStatus": {
4959
+ "completed": "レビュー済み",
4960
+ "in_progress": "レビュー中…",
4961
+ "pending": "待機中"
4962
+ }
4950
4963
  },
4951
4964
  "challenge": {
4952
4965
  "action": "異議を唱える",
@@ -4931,10 +4931,23 @@
4931
4931
  "suggestedFix": "Sugerowana poprawka:",
4932
4932
  "line": "wiersz {line}",
4933
4933
  "reviewing": {
4934
- "title": "Przeglądanie pull requesta…",
4935
- "hint": "Dzielenie zmian na spójne części i przeglądanie każdej z nich.",
4934
+ "slicing": {
4935
+ "title": "Dzielenie zmian na fragmenty…",
4936
+ "hint": "Grupowanie zmienionych plików w spójne fragmenty, aby każdy można było przejrzeć osobno. Lista fragmentów pojawi się tutaj po zakończeniu podziału."
4937
+ },
4938
+ "reviewingChunks": {
4939
+ "title": "Przeglądanie fragmentów…",
4940
+ "hint": "Podział zakończony. Przeglądanie każdego fragmentu po kolei i zbieranie uwag."
4941
+ },
4936
4942
  "chunks": "Sprawdzono {completed} z {total} fragmentów",
4937
- "inProgress": "{count} w toku"
4943
+ "inProgress": "{count} w toku",
4944
+ "activeHeading": "Przeglądane teraz",
4945
+ "chunksHeading": "Fragmenty",
4946
+ "chunkStatus": {
4947
+ "completed": "Sprawdzony",
4948
+ "in_progress": "Przeglądanie…",
4949
+ "pending": "W kolejce"
4950
+ }
4938
4951
  },
4939
4952
  "challenge": {
4940
4953
  "action": "Zakwestionuj",
@@ -4943,10 +4943,23 @@
4943
4943
  "suggestedFix": "Önerilen düzeltme:",
4944
4944
  "line": "satır {line}",
4945
4945
  "reviewing": {
4946
- "title": "Pull request inceleniyor…",
4947
- "hint": "Fark tutarlı parçalara bölünüp her biri inceleniyor.",
4946
+ "slicing": {
4947
+ "title": "Fark parçalara bölünüyor…",
4948
+ "hint": "Değiştirilen dosyalar, her biri ayrı ayrı incelenebilsin diye tutarlı parçalara gruplanıyor. Bölme tamamlandığında parça listesi burada görünecek."
4949
+ },
4950
+ "reviewingChunks": {
4951
+ "title": "Parçalar inceleniyor…",
4952
+ "hint": "Bölme tamamlandı. Her parça tek tek inceleniyor ve bulgular toplanıyor."
4953
+ },
4948
4954
  "chunks": "{total} bölümden {completed} tanesi incelendi",
4949
- "inProgress": "{count} devam ediyor"
4955
+ "inProgress": "{count} devam ediyor",
4956
+ "activeHeading": "Şimdi inceleniyor",
4957
+ "chunksHeading": "Parçalar",
4958
+ "chunkStatus": {
4959
+ "completed": "İncelendi",
4960
+ "in_progress": "İnceleniyor…",
4961
+ "pending": "Sırada"
4962
+ }
4950
4963
  },
4951
4964
  "challenge": {
4952
4965
  "action": "İtiraz et",
@@ -4931,10 +4931,23 @@
4931
4931
  "suggestedFix": "Пропоноване виправлення:",
4932
4932
  "line": "рядок {line}",
4933
4933
  "reviewing": {
4934
- "title": "Перевірка pull request…",
4935
- "hint": "Поділ змін на цілісні частини та огляд кожної з них.",
4934
+ "slicing": {
4935
+ "title": "Поділ змін на фрагменти…",
4936
+ "hint": "Групування змінених файлів у цілісні фрагменти, щоб кожен можна було переглянути окремо. Список фрагментів з'явиться тут після завершення поділу."
4937
+ },
4938
+ "reviewingChunks": {
4939
+ "title": "Огляд фрагментів…",
4940
+ "hint": "Поділ завершено. Кожен фрагмент переглядається по черзі, а зауваження збираються."
4941
+ },
4936
4942
  "chunks": "Перевірено {completed} з {total} фрагментів",
4937
- "inProgress": "{count} у процесі"
4943
+ "inProgress": "{count} у процесі",
4944
+ "activeHeading": "Переглядається зараз",
4945
+ "chunksHeading": "Фрагменти",
4946
+ "chunkStatus": {
4947
+ "completed": "Переглянуто",
4948
+ "in_progress": "Огляд…",
4949
+ "pending": "У черзі"
4950
+ }
4938
4951
  },
4939
4952
  "challenge": {
4940
4953
  "action": "Оскаржити",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.147.0",
3
+ "version": "0.147.1",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",