@cat-factory/app 0.147.1 → 0.147.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/board/nodes/TaskPipelineMini.vue +23 -2
- package/app/components/pipeline/PipelineProgress.vue +25 -1
- package/app/components/prReview/PrReviewPhaseBadge.vue +74 -0
- package/app/components/prReview/PrReviewWindow.vue +430 -403
- package/app/stores/personalSubscriptions.spec.ts +57 -6
- package/app/stores/personalSubscriptions.ts +72 -11
- package/app/utils/prReviewProgress.spec.ts +63 -12
- package/app/utils/prReviewProgress.ts +70 -8
- package/i18n/locales/de.json +11 -3
- package/i18n/locales/en.json +11 -3
- package/i18n/locales/es.json +11 -3
- package/i18n/locales/fr.json +11 -3
- package/i18n/locales/he.json +11 -3
- package/i18n/locales/it.json +11 -3
- package/i18n/locales/ja.json +11 -3
- package/i18n/locales/pl.json +11 -3
- package/i18n/locales/tr.json +11 -3
- package/i18n/locales/uk.json +11 -3
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
COMPANION_STATE_META,
|
|
10
10
|
} from '~/utils/pipelineRender'
|
|
11
11
|
import { lodAtLeast } from '~/composables/useSemanticZoom'
|
|
12
|
+
import { prReviewPhase } from '~/utils/prReviewProgress'
|
|
13
|
+
import PrReviewPhaseBadge from '~/components/prReview/PrReviewPhaseBadge.vue'
|
|
12
14
|
|
|
13
15
|
// Spatial drill-down inside a task card: at the `steps` zoom band the task's
|
|
14
16
|
// build-pipeline steps appear, and one band deeper (`subtasks`) each step's live
|
|
@@ -83,6 +85,13 @@ function stepSpinning(s: PipelineStep) {
|
|
|
83
85
|
return !runFailed.value && (s.state === 'working' || backgroundReview(s))
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// Whether a step is a `pr-reviewer` with a LIVE phase to surface (slicing / reviewing / … ).
|
|
89
|
+
// Drives replacing the generic N/M count + state icon with the phase badge, while a terminal
|
|
90
|
+
// (done/skipped) review keeps its normal check/count visuals.
|
|
91
|
+
function prPhaseActive(s: PipelineStep): boolean {
|
|
92
|
+
return prReviewPhase(s.prReview, s.subtasks) !== null
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
// Same todo-status icons the bootstrap card uses, so a zoomed-in task reads the
|
|
87
96
|
// same way as a zoomed-in bootstrap.
|
|
88
97
|
const ITEM_ICON: Record<string, string> = {
|
|
@@ -118,14 +127,16 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
118
127
|
name="i-lucide-file-text"
|
|
119
128
|
class="h-2.5 w-2.5 shrink-0 text-slate-500"
|
|
120
129
|
/>
|
|
130
|
+
<!-- The plain N/M count, replaced by the phase line below while a `pr-reviewer` step is
|
|
131
|
+
live — its slice progress reads better as Slicing… / Reviewing X/Y slices. -->
|
|
121
132
|
<span
|
|
122
|
-
v-if="s.subtasks && s.subtasks.total > 0"
|
|
133
|
+
v-if="s.subtasks && s.subtasks.total > 0 && !prPhaseActive(s)"
|
|
123
134
|
class="ms-auto shrink-0 font-mono text-[9px] tabular-nums text-slate-400"
|
|
124
135
|
>
|
|
125
136
|
{{ s.subtasks.completed }}/{{ s.subtasks.total }}
|
|
126
137
|
</span>
|
|
127
138
|
<UIcon
|
|
128
|
-
v-else
|
|
139
|
+
v-else-if="!prPhaseActive(s)"
|
|
129
140
|
:name="stepVisual(s).icon"
|
|
130
141
|
class="ms-auto h-2.5 w-2.5 shrink-0"
|
|
131
142
|
:class="stepSpinning(s) ? 'animate-spin' : ''"
|
|
@@ -133,6 +144,16 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
133
144
|
/>
|
|
134
145
|
</button>
|
|
135
146
|
|
|
147
|
+
<!-- PR reviewer: the precise sub-phase (slicing vs reviewing N/M slices), so the board
|
|
148
|
+
card tells the reviewer's progress apart from a bare subtask count. Self-hides once
|
|
149
|
+
the review is terminal / for any non-pr-reviewer step. -->
|
|
150
|
+
<PrReviewPhaseBadge
|
|
151
|
+
v-if="prPhaseActive(s)"
|
|
152
|
+
:step="s"
|
|
153
|
+
:run-failed="runFailed"
|
|
154
|
+
class="ms-4 mt-1 text-[9px]"
|
|
155
|
+
/>
|
|
156
|
+
|
|
136
157
|
<!-- pending approval gate: jump straight to the conclusions reader. Suppressed
|
|
137
158
|
while a reviewer gate is folding/re-reviewing in the background (no human needed). -->
|
|
138
159
|
<button
|
|
@@ -11,7 +11,9 @@ import {
|
|
|
11
11
|
FAILED_STEP_META,
|
|
12
12
|
containerPhaseLabel,
|
|
13
13
|
} from '~/utils/pipelineRender'
|
|
14
|
+
import { prReviewPhase } from '~/utils/prReviewProgress'
|
|
14
15
|
import StepMetricsBar from '~/components/observability/StepMetricsBar.vue'
|
|
16
|
+
import PrReviewPhaseBadge from '~/components/prReview/PrReviewPhaseBadge.vue'
|
|
15
17
|
import { useNowTick, stepDurationLabel } from '~/composables/useStepTimer'
|
|
16
18
|
|
|
17
19
|
const props = defineProps<{ instance: ExecutionInstance }>()
|
|
@@ -84,6 +86,15 @@ function prReviewAwaiting(step: PipelineStep): boolean {
|
|
|
84
86
|
return step.prReview?.status === 'awaiting_selection'
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Whether a `pr-reviewer` step has a LIVE phase to surface (slicing / reviewing / … ). Drives
|
|
91
|
+
* showing the phase badge in place of the generic subtask count header; a terminal (done/skipped)
|
|
92
|
+
* review keeps the plain count.
|
|
93
|
+
*/
|
|
94
|
+
function prPhaseActive(step: PipelineStep): boolean {
|
|
95
|
+
return prReviewPhase(step.prReview, step.subtasks) !== null
|
|
96
|
+
}
|
|
97
|
+
|
|
87
98
|
// --- restart from a step -----------------------------------------------------
|
|
88
99
|
// Re-run the pipeline from a chosen step onward: the server resets that step +
|
|
89
100
|
// every later step's iteration counters and re-drives a fresh run, keeping the
|
|
@@ -444,9 +455,22 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
444
455
|
<span>{{ stepPhaseLabel(s) }}</span>
|
|
445
456
|
</div>
|
|
446
457
|
|
|
458
|
+
<!-- PR reviewer: the precise sub-phase (Slicing… / Reviewing N/M slices), which reads
|
|
459
|
+
better than a bare subtask count. Shows during slicing (no todo list yet) too, so
|
|
460
|
+
it fills the gap before the chunk list exists. -->
|
|
461
|
+
<PrReviewPhaseBadge
|
|
462
|
+
v-if="prPhaseActive(s)"
|
|
463
|
+
:step="s"
|
|
464
|
+
:run-failed="runFailed"
|
|
465
|
+
class="mt-2 text-[11px]"
|
|
466
|
+
/>
|
|
467
|
+
|
|
447
468
|
<!-- live subtask counts from the agent's todo list -->
|
|
448
469
|
<div v-if="s.subtasks && s.subtasks.total > 0" class="mt-2">
|
|
449
|
-
<div
|
|
470
|
+
<div
|
|
471
|
+
v-if="!prPhaseActive(s)"
|
|
472
|
+
class="flex items-center justify-between text-[10px] text-slate-400"
|
|
473
|
+
>
|
|
450
474
|
<span>
|
|
451
475
|
{{
|
|
452
476
|
t('pipeline.progress.subtasks', {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { PipelineStep } from '~/types/execution'
|
|
4
|
+
import { prReviewPhase, type PrReviewPhaseKind } from '~/utils/prReviewProgress'
|
|
5
|
+
|
|
6
|
+
// Compact, at-a-glance phase label for a live `pr-reviewer` step, so the BOARD surfaces (the
|
|
7
|
+
// task-card mini pipeline + the focus-view timeline) tell the reviewer's sub-phase apart —
|
|
8
|
+
// "Slicing…" while it groups the diff, "Reviewing X/Y slices" while it works through the chunks
|
|
9
|
+
// — instead of a bare N/M count that reads the same as any other agent. Self-hides when the step
|
|
10
|
+
// has no live review (terminal / not-a-pr-reviewer), so a host can drop it in unconditionally.
|
|
11
|
+
// The precise phase derivation is the pure `prReviewPhase` helper (unit-tested).
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
step: PipelineStep
|
|
14
|
+
/** The run has failed — freeze the phase (no spinner), matching the surrounding step visuals. */
|
|
15
|
+
runFailed?: boolean
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const { t } = useI18n()
|
|
19
|
+
|
|
20
|
+
const phase = computed(() => prReviewPhase(props.step.prReview, props.step.subtasks))
|
|
21
|
+
|
|
22
|
+
// Per-phase icon + accent. `spin` drives the loader animation while the phase is actively
|
|
23
|
+
// working (suppressed on a failed run). `awaiting` is the parked "findings ready" state — a
|
|
24
|
+
// steady amber prompt, not a spinner.
|
|
25
|
+
const PHASE_META: Record<PrReviewPhaseKind, { icon: string; spin: boolean; class: string }> = {
|
|
26
|
+
planning: { icon: 'i-lucide-loader-circle', spin: true, class: 'text-indigo-300' },
|
|
27
|
+
reviewing: { icon: 'i-lucide-loader-circle', spin: true, class: 'text-indigo-300' },
|
|
28
|
+
awaiting: { icon: 'i-lucide-clipboard-check', spin: false, class: 'text-amber-300' },
|
|
29
|
+
challenging: { icon: 'i-lucide-gavel', spin: true, class: 'text-indigo-300' },
|
|
30
|
+
fixing: { icon: 'i-lucide-wrench', spin: true, class: 'text-indigo-300' },
|
|
31
|
+
posting: { icon: 'i-lucide-send', spin: true, class: 'text-indigo-300' },
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Phase → i18n key. Exhaustive Record over the phase-kind union, so adding a kind without a
|
|
35
|
+
// label fails the typecheck (the sanctioned dynamic enum→key guard — tier 1 can't see a
|
|
36
|
+
// runtime-built key), matching the `CHUNK_STATUS_KEY` pattern in PrReviewWindow.vue.
|
|
37
|
+
const PHASE_LABEL_KEY: Record<PrReviewPhaseKind, string> = {
|
|
38
|
+
planning: 'prReview.phase.planning',
|
|
39
|
+
reviewing: 'prReview.phase.reviewing',
|
|
40
|
+
awaiting: 'prReview.phase.awaiting',
|
|
41
|
+
challenging: 'prReview.phase.challenging',
|
|
42
|
+
fixing: 'prReview.phase.fixing',
|
|
43
|
+
posting: 'prReview.phase.posting',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const label = computed(() => {
|
|
47
|
+
const p = phase.value
|
|
48
|
+
if (!p) return null
|
|
49
|
+
// `reviewing` carries the live slice counts; the rest are static status copy.
|
|
50
|
+
if (p.kind === 'reviewing')
|
|
51
|
+
return t(PHASE_LABEL_KEY.reviewing, { completed: p.completed, total: p.total })
|
|
52
|
+
return t(PHASE_LABEL_KEY[p.kind])
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const spinning = computed(
|
|
56
|
+
() => !!phase.value && PHASE_META[phase.value.kind].spin && !props.runFailed,
|
|
57
|
+
)
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<span
|
|
62
|
+
v-if="phase && label"
|
|
63
|
+
data-testid="pr-review-phase"
|
|
64
|
+
class="inline-flex items-center gap-1"
|
|
65
|
+
:class="runFailed ? 'text-rose-400' : PHASE_META[phase.kind].class"
|
|
66
|
+
>
|
|
67
|
+
<UIcon
|
|
68
|
+
:name="runFailed ? 'i-lucide-circle-x' : PHASE_META[phase.kind].icon"
|
|
69
|
+
class="h-3 w-3 shrink-0"
|
|
70
|
+
:class="spinning ? 'animate-spin' : ''"
|
|
71
|
+
/>
|
|
72
|
+
<span class="truncate">{{ label }}</span>
|
|
73
|
+
</span>
|
|
74
|
+
</template>
|