@cat-factory/app 0.137.2 → 0.138.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.
- package/app/components/documents/TaskContextDocs.vue +1 -0
- package/app/components/followUp/FollowUpWindow.vue +174 -200
- package/app/components/forkDecision/ForkDecisionWindow.vue +250 -275
- package/app/components/gates/GateResultView.vue +309 -333
- package/app/components/humanTest/HumanTestWindow.vue +212 -236
- package/app/components/media/ArtifactLightbox.vue +20 -19
- package/app/components/panels/GenericStructuredResultView.vue +60 -88
- package/app/components/ralph/RalphLoopResultView.vue +150 -171
- package/app/components/testing/TestReportWindow.vue +505 -559
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +224 -262
- package/i18n/locales/de.json +0 -1
- package/i18n/locales/en.json +0 -1
- package/i18n/locales/es.json +0 -1
- package/i18n/locales/fr.json +0 -1
- package/i18n/locales/he.json +0 -1
- package/i18n/locales/it.json +0 -1
- package/i18n/locales/ja.json +0 -1
- package/i18n/locales/pl.json +0 -1
- package/i18n/locales/tr.json +0 -1
- package/i18n/locales/uk.json +0 -1
- package/package.json +1 -1
- package/app/composables/useFocusTrap.ts +0 -72
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { computed, ref } from 'vue'
|
|
9
9
|
import { agentKindMeta } from '~/utils/catalog'
|
|
10
10
|
import type { GateAttempt, GateStepState } from '~/types/execution'
|
|
11
|
-
import
|
|
11
|
+
import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
|
|
12
12
|
import StepRunMeta from '~/components/panels/StepRunMeta.vue'
|
|
13
13
|
import AttemptEntryHeader from '~/components/panels/AttemptEntryHeader.vue'
|
|
14
14
|
import GateFailingCheckList from '~/components/gates/GateFailingCheckList.vue'
|
|
@@ -20,10 +20,16 @@ const { t } = useI18n()
|
|
|
20
20
|
const access = useWorkspaceAccess()
|
|
21
21
|
|
|
22
22
|
// Synchronous window: it reads its state straight off the execution step, so there's
|
|
23
|
-
// nothing to fetch on open (no `onOpen` loader).
|
|
24
|
-
|
|
23
|
+
// nothing to fetch on open (no `onOpen` loader). `manageEscape: false` — `ResultWindowShell`
|
|
24
|
+
// owns Escape (and focus trap + scroll lock + stacking).
|
|
25
|
+
const { open, blockId, instanceId, stepIndex, close } = useResultView('gate', {
|
|
26
|
+
manageEscape: false,
|
|
27
|
+
})
|
|
25
28
|
const block = computed(() => (blockId.value ? board.getBlock(blockId.value) : undefined))
|
|
26
29
|
const prUrl = computed(() => block.value?.pullRequest?.url ?? null)
|
|
30
|
+
const headerTitle = computed(
|
|
31
|
+
() => `${meta.value.label}${block.value ? ` — ${block.value.title}` : ''}`,
|
|
32
|
+
)
|
|
27
33
|
|
|
28
34
|
const instance = computed(() =>
|
|
29
35
|
instanceId.value === null ? null : (execution.getInstance(instanceId.value) ?? null),
|
|
@@ -171,363 +177,333 @@ const conflictVerdict = computed(() => {
|
|
|
171
177
|
</script>
|
|
172
178
|
|
|
173
179
|
<template>
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
<ResultWindowShell
|
|
181
|
+
:open="open"
|
|
182
|
+
:icon="meta.icon"
|
|
183
|
+
icon-class="bg-sky-500/15 text-sky-300"
|
|
184
|
+
:title="headerTitle"
|
|
185
|
+
:subtitle="subtitle"
|
|
186
|
+
:step-ref="{ instanceId, stepIndex }"
|
|
187
|
+
width="3xl"
|
|
188
|
+
@close="close"
|
|
189
|
+
>
|
|
190
|
+
<template #header-extras>
|
|
191
|
+
<UBadge
|
|
192
|
+
:color="STATUS_META[status].badge"
|
|
193
|
+
variant="subtle"
|
|
194
|
+
size="sm"
|
|
195
|
+
data-testid="gate-status"
|
|
184
196
|
>
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
{{ STATUS_META[status].label }}
|
|
198
|
+
</UBadge>
|
|
199
|
+
</template>
|
|
200
|
+
|
|
201
|
+
<div class="flex min-h-0 flex-1">
|
|
202
|
+
<!-- Main: the conclusion -->
|
|
203
|
+
<div class="min-w-0 flex-1 overflow-y-auto px-5 py-4">
|
|
204
|
+
<div
|
|
205
|
+
v-if="!gate"
|
|
206
|
+
class="flex h-full flex-col items-center justify-center gap-2 text-center text-slate-400"
|
|
207
|
+
>
|
|
208
|
+
<UIcon :name="meta.icon" class="h-8 w-8 opacity-40" />
|
|
209
|
+
<p class="text-sm">{{ t('gates.noActivity') }}</p>
|
|
210
|
+
<p class="max-w-sm text-[11px] text-slate-500">
|
|
211
|
+
{{ t('gates.noActivityHint') }}
|
|
212
|
+
</p>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
<template v-else>
|
|
216
|
+
<!-- Passed -->
|
|
217
|
+
<div
|
|
218
|
+
v-if="status === 'passed'"
|
|
219
|
+
class="flex items-start gap-2 rounded-lg border border-emerald-500/30 bg-emerald-500/10 px-3 py-2.5"
|
|
189
220
|
>
|
|
190
|
-
<UIcon
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
{{ meta.label }}{{ block ? ` — ${block.title}` : '' }}
|
|
195
|
-
</h2>
|
|
196
|
-
<p class="truncate text-[11px] text-slate-400">{{ subtitle }}</p>
|
|
221
|
+
<UIcon name="i-lucide-circle-check" class="mt-0.5 h-4 w-4 shrink-0 text-emerald-400" />
|
|
222
|
+
<p class="text-[13px] leading-relaxed text-emerald-200">
|
|
223
|
+
{{ step?.output || (isCi ? t('gates.passedCi') : t('gates.passedConflicts')) }}
|
|
224
|
+
</p>
|
|
197
225
|
</div>
|
|
198
|
-
<UBadge :color="STATUS_META[status].badge" variant="subtle" size="sm">
|
|
199
|
-
{{ STATUS_META[status].label }}
|
|
200
|
-
</UBadge>
|
|
201
|
-
<StepRestartControl
|
|
202
|
-
:instance-id="instanceId"
|
|
203
|
-
:step-index="stepIndex"
|
|
204
|
-
@restarted="close"
|
|
205
|
-
/>
|
|
206
|
-
<button
|
|
207
|
-
class="rounded-md p-1.5 text-slate-400 hover:bg-slate-800 hover:text-slate-200"
|
|
208
|
-
@click="close"
|
|
209
|
-
>
|
|
210
|
-
<UIcon name="i-lucide-x" class="h-4 w-4" />
|
|
211
|
-
</button>
|
|
212
|
-
</header>
|
|
213
226
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
227
|
+
<!-- Human review: approval progress, the feedback being fixed, freeform fix box -->
|
|
228
|
+
<template v-else-if="isHumanReview">
|
|
229
|
+
<div
|
|
230
|
+
class="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
231
|
+
>
|
|
232
|
+
<UIcon name="i-lucide-users" class="h-4 w-4 shrink-0 text-violet-300" />
|
|
233
|
+
<span class="text-[13px] text-slate-200">
|
|
234
|
+
{{
|
|
235
|
+
t(
|
|
236
|
+
'gates.humanReview.approvals',
|
|
237
|
+
{ approved: gate.lastApprovals ?? 0, required: requiredApprovals },
|
|
238
|
+
requiredApprovals,
|
|
239
|
+
)
|
|
240
|
+
}}
|
|
241
|
+
<template v-if="status === 'fixing'">
|
|
242
|
+
{{ t('gates.humanReview.suffixFixing') }}</template
|
|
243
|
+
>
|
|
244
|
+
<template v-else-if="status === 'failing'">
|
|
245
|
+
{{ t('gates.humanReview.suffixFailing') }}</template
|
|
246
|
+
>
|
|
247
|
+
<template v-else> {{ t('gates.humanReview.suffixAwaiting') }}</template>
|
|
248
|
+
</span>
|
|
249
|
+
</div>
|
|
217
250
|
<div
|
|
218
|
-
v-if="
|
|
219
|
-
class="
|
|
251
|
+
v-if="gate.lastFailureSummary"
|
|
252
|
+
class="relative mt-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
220
253
|
>
|
|
221
|
-
<
|
|
222
|
-
<p class="text-
|
|
223
|
-
|
|
224
|
-
{{ t('gates.noActivityHint') }}
|
|
254
|
+
<CopyButton :text="gate.lastFailureSummary" class="absolute end-1 top-1" />
|
|
255
|
+
<p class="whitespace-pre-wrap pe-8 text-[12px] leading-relaxed text-slate-300">
|
|
256
|
+
{{ gate.lastFailureSummary }}
|
|
225
257
|
</p>
|
|
226
258
|
</div>
|
|
259
|
+
<a
|
|
260
|
+
v-if="prUrl"
|
|
261
|
+
:href="prUrl"
|
|
262
|
+
target="_blank"
|
|
263
|
+
rel="noopener"
|
|
264
|
+
class="mt-2 inline-flex items-center gap-1 text-[12px] text-sky-300 hover:text-sky-200 hover:underline"
|
|
265
|
+
>
|
|
266
|
+
{{ t('gates.humanReview.reviewPr') }}
|
|
267
|
+
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
268
|
+
</a>
|
|
227
269
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
270
|
+
<!-- Freeform fix request: dispatch the fixer now with these instructions. -->
|
|
271
|
+
<section v-if="status !== 'gave-up'" class="mt-4">
|
|
272
|
+
<h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
273
|
+
{{ t('gates.humanReview.requestFixHeading') }}
|
|
274
|
+
</h3>
|
|
275
|
+
<p class="mb-2 text-[11px] leading-relaxed text-slate-500">
|
|
276
|
+
{{ t('gates.humanReview.requestFixDescription') }}
|
|
277
|
+
</p>
|
|
278
|
+
<textarea
|
|
279
|
+
v-model="fixInstructions"
|
|
280
|
+
rows="3"
|
|
281
|
+
:disabled="fixBusy"
|
|
282
|
+
:placeholder="t('gates.humanReview.requestFixPlaceholder')"
|
|
283
|
+
class="w-full resize-y rounded-md border border-slate-800 bg-slate-950/60 px-3 py-2 text-[13px] text-slate-200 placeholder:text-slate-600 focus:border-violet-500/60 focus:outline-none focus-visible:ring-2 focus-visible:ring-violet-500/60"
|
|
284
|
+
/>
|
|
285
|
+
<div class="mt-2 flex justify-end">
|
|
286
|
+
<UButton
|
|
287
|
+
size="sm"
|
|
288
|
+
color="primary"
|
|
289
|
+
icon="i-lucide-wrench"
|
|
290
|
+
:loading="fixBusy"
|
|
291
|
+
:disabled="
|
|
292
|
+
fixBusy || fixInstructions.trim().length === 0 || !access.canExecuteRuns.value
|
|
293
|
+
"
|
|
294
|
+
:title="access.canExecuteRuns.value ? undefined : t('access.noRunExecute')"
|
|
295
|
+
@click="submitFix"
|
|
296
|
+
>
|
|
297
|
+
{{ t('gates.humanReview.requestFix') }}
|
|
298
|
+
</UButton>
|
|
241
299
|
</div>
|
|
300
|
+
</section>
|
|
301
|
+
</template>
|
|
242
302
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
{ approved: gate.lastApprovals ?? 0, required: requiredApprovals },
|
|
254
|
-
requiredApprovals,
|
|
255
|
-
)
|
|
256
|
-
}}
|
|
257
|
-
<template v-if="status === 'fixing'">
|
|
258
|
-
{{ t('gates.humanReview.suffixFixing') }}</template
|
|
259
|
-
>
|
|
260
|
-
<template v-else-if="status === 'failing'">
|
|
261
|
-
{{ t('gates.humanReview.suffixFailing') }}</template
|
|
262
|
-
>
|
|
263
|
-
<template v-else> {{ t('gates.humanReview.suffixAwaiting') }}</template>
|
|
264
|
-
</span>
|
|
265
|
-
</div>
|
|
266
|
-
<div
|
|
267
|
-
v-if="gate.lastFailureSummary"
|
|
268
|
-
class="relative mt-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
269
|
-
>
|
|
270
|
-
<CopyButton :text="gate.lastFailureSummary" class="absolute end-1 top-1" />
|
|
271
|
-
<p class="whitespace-pre-wrap pe-8 text-[12px] leading-relaxed text-slate-300">
|
|
272
|
-
{{ gate.lastFailureSummary }}
|
|
273
|
-
</p>
|
|
274
|
-
</div>
|
|
275
|
-
<a
|
|
276
|
-
v-if="prUrl"
|
|
277
|
-
:href="prUrl"
|
|
278
|
-
target="_blank"
|
|
279
|
-
rel="noopener"
|
|
280
|
-
class="mt-2 inline-flex items-center gap-1 text-[12px] text-sky-300 hover:text-sky-200 hover:underline"
|
|
281
|
-
>
|
|
282
|
-
{{ t('gates.humanReview.reviewPr') }}
|
|
283
|
-
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
284
|
-
</a>
|
|
303
|
+
<!-- CI: failing checks -->
|
|
304
|
+
<template v-else-if="isCi">
|
|
305
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
306
|
+
{{ t('gates.ci.failingChecks') }}
|
|
307
|
+
</h3>
|
|
308
|
+
<GateFailingCheckList v-if="failingChecks.length" :checks="failingChecks" />
|
|
309
|
+
<p v-else class="text-[13px] leading-relaxed text-slate-300">
|
|
310
|
+
{{ gate.lastFailureSummary || t('gates.ci.failureFallback') }}
|
|
311
|
+
</p>
|
|
312
|
+
</template>
|
|
285
313
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
:title="access.canExecuteRuns.value ? undefined : t('access.noRunExecute')"
|
|
315
|
-
@click="submitFix"
|
|
316
|
-
>
|
|
317
|
-
{{ t('gates.humanReview.requestFix') }}
|
|
318
|
-
</UButton>
|
|
319
|
-
</div>
|
|
320
|
-
</section>
|
|
321
|
-
</template>
|
|
314
|
+
<!-- Doc quality: the deterministic structural findings the gate raised -->
|
|
315
|
+
<template v-else-if="isDocQuality">
|
|
316
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
317
|
+
{{ t('gates.docQuality.findings') }}
|
|
318
|
+
</h3>
|
|
319
|
+
<div
|
|
320
|
+
v-if="gate.lastFailureSummary"
|
|
321
|
+
class="relative rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
322
|
+
>
|
|
323
|
+
<CopyButton :text="gate.lastFailureSummary" class="absolute end-1 top-1" />
|
|
324
|
+
<p class="whitespace-pre-wrap pe-8 text-[12px] leading-relaxed text-slate-300">
|
|
325
|
+
{{ gate.lastFailureSummary }}
|
|
326
|
+
</p>
|
|
327
|
+
</div>
|
|
328
|
+
<p v-else class="text-[13px] leading-relaxed text-slate-300">
|
|
329
|
+
{{ t('gates.docQuality.findingsFallback') }}
|
|
330
|
+
</p>
|
|
331
|
+
<a
|
|
332
|
+
v-if="prUrl"
|
|
333
|
+
:href="prUrl"
|
|
334
|
+
target="_blank"
|
|
335
|
+
rel="noopener"
|
|
336
|
+
class="mt-2 inline-flex items-center gap-1 text-[12px] text-sky-300 hover:text-sky-200 hover:underline"
|
|
337
|
+
>
|
|
338
|
+
{{ t('gates.docQuality.viewPr') }}
|
|
339
|
+
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
340
|
+
</a>
|
|
341
|
+
</template>
|
|
322
342
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
343
|
+
<!-- Conflicts: verdict + the resolver's account of what it left -->
|
|
344
|
+
<template v-else>
|
|
345
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
346
|
+
{{ t('gates.conflicts.mergeability') }}
|
|
347
|
+
</h3>
|
|
348
|
+
<div
|
|
349
|
+
class="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
350
|
+
>
|
|
351
|
+
<UIcon
|
|
352
|
+
:name="STATUS_META[status].icon"
|
|
353
|
+
class="h-4 w-4 shrink-0"
|
|
354
|
+
:class="STATUS_META[status].text"
|
|
355
|
+
/>
|
|
356
|
+
<span class="text-[13px] text-slate-200">{{ conflictVerdict }}</span>
|
|
357
|
+
</div>
|
|
358
|
+
<!-- GitHub's API reports mergeability as a single bit (no file list), but the
|
|
359
|
+
conflict resolver discovers the conflicting files in the container and
|
|
360
|
+
reports them back — surface that account here. -->
|
|
361
|
+
<div
|
|
362
|
+
v-if="gate.lastFailureSummary"
|
|
363
|
+
class="relative mt-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
364
|
+
>
|
|
365
|
+
<CopyButton :text="gate.lastFailureSummary" class="absolute end-1 top-1" />
|
|
366
|
+
<p class="whitespace-pre-wrap pe-8 text-[12px] leading-relaxed text-slate-300">
|
|
367
|
+
{{ gate.lastFailureSummary }}
|
|
368
|
+
</p>
|
|
369
|
+
</div>
|
|
370
|
+
<a
|
|
371
|
+
v-if="prUrl"
|
|
372
|
+
:href="prUrl"
|
|
373
|
+
target="_blank"
|
|
374
|
+
rel="noopener"
|
|
375
|
+
class="mt-2 inline-flex items-center gap-1 text-[12px] text-sky-300 hover:text-sky-200 hover:underline"
|
|
376
|
+
>
|
|
377
|
+
{{ t('gates.conflicts.viewPr') }}
|
|
378
|
+
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
379
|
+
</a>
|
|
380
|
+
</template>
|
|
333
381
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
382
|
+
<!-- Attempt history (both gates): what each helper run did and how it ended. -->
|
|
383
|
+
<section v-if="attempts.length" class="mt-5">
|
|
384
|
+
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
385
|
+
{{ t('gates.attemptsHeading', { helper: helperMeta.label }) }}
|
|
386
|
+
</h3>
|
|
387
|
+
<ol class="space-y-2">
|
|
388
|
+
<li
|
|
389
|
+
v-for="a in attempts"
|
|
390
|
+
:key="a.attempt"
|
|
391
|
+
class="rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
392
|
+
>
|
|
393
|
+
<AttemptEntryHeader
|
|
394
|
+
:label="t('gates.attempt', { number: a.attempt })"
|
|
395
|
+
:outcome="a.outcome"
|
|
396
|
+
:outcome-label="OUTCOME_LABELS[a.outcome]"
|
|
397
|
+
:at="a.at"
|
|
398
|
+
date-format="long"
|
|
399
|
+
/>
|
|
400
|
+
<!-- What this round was asked to fix: the instructions the gate handed the
|
|
401
|
+
helper (the failing-check summary / conflict reason / review comments),
|
|
402
|
+
plus the structured red checks for the CI gate. -->
|
|
339
403
|
<div
|
|
340
|
-
v-if="
|
|
341
|
-
class="
|
|
404
|
+
v-if="a.instructions || (a.failingChecks && a.failingChecks.length)"
|
|
405
|
+
class="mt-1.5"
|
|
342
406
|
>
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
{{ gate.lastFailureSummary }}
|
|
407
|
+
<p class="text-[11px] text-slate-500">
|
|
408
|
+
{{ t('gates.attemptInstructions', { helper: helperMeta.label }) }}
|
|
346
409
|
</p>
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
v-if="prUrl"
|
|
353
|
-
:href="prUrl"
|
|
354
|
-
target="_blank"
|
|
355
|
-
rel="noopener"
|
|
356
|
-
class="mt-2 inline-flex items-center gap-1 text-[12px] text-sky-300 hover:text-sky-200 hover:underline"
|
|
357
|
-
>
|
|
358
|
-
{{ t('gates.docQuality.viewPr') }}
|
|
359
|
-
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
360
|
-
</a>
|
|
361
|
-
</template>
|
|
362
|
-
|
|
363
|
-
<!-- Conflicts: verdict + the resolver's account of what it left -->
|
|
364
|
-
<template v-else>
|
|
365
|
-
<h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
366
|
-
{{ t('gates.conflicts.mergeability') }}
|
|
367
|
-
</h3>
|
|
368
|
-
<div
|
|
369
|
-
class="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
370
|
-
>
|
|
371
|
-
<UIcon
|
|
372
|
-
:name="STATUS_META[status].icon"
|
|
373
|
-
class="h-4 w-4 shrink-0"
|
|
374
|
-
:class="STATUS_META[status].text"
|
|
410
|
+
<GateFailingCheckList
|
|
411
|
+
v-if="a.failingChecks && a.failingChecks.length"
|
|
412
|
+
class="mt-1"
|
|
413
|
+
:checks="a.failingChecks"
|
|
414
|
+
dense
|
|
375
415
|
/>
|
|
376
|
-
<
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
<div
|
|
382
|
-
v-if="gate.lastFailureSummary"
|
|
383
|
-
class="relative mt-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-2"
|
|
384
|
-
>
|
|
385
|
-
<CopyButton :text="gate.lastFailureSummary" class="absolute end-1 top-1" />
|
|
386
|
-
<p class="whitespace-pre-wrap pe-8 text-[12px] leading-relaxed text-slate-300">
|
|
387
|
-
{{ gate.lastFailureSummary }}
|
|
416
|
+
<p
|
|
417
|
+
v-else-if="a.instructions"
|
|
418
|
+
class="mt-1 whitespace-pre-wrap text-[12px] leading-relaxed text-slate-300"
|
|
419
|
+
>
|
|
420
|
+
{{ a.instructions }}
|
|
388
421
|
</p>
|
|
389
422
|
</div>
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
class="mt-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
423
|
+
<!-- The helper's own report of what it did / what remains. -->
|
|
424
|
+
<template v-if="a.summary">
|
|
425
|
+
<p class="mt-1.5 text-[11px] text-slate-500">
|
|
426
|
+
{{ t('gates.attemptReport', { helper: helperMeta.label }) }}
|
|
427
|
+
</p>
|
|
428
|
+
<p class="mt-1 whitespace-pre-wrap text-[12px] leading-relaxed text-slate-400">
|
|
429
|
+
{{ a.summary }}
|
|
430
|
+
</p>
|
|
431
|
+
</template>
|
|
432
|
+
</li>
|
|
433
|
+
</ol>
|
|
434
|
+
</section>
|
|
435
|
+
</template>
|
|
436
|
+
</div>
|
|
401
437
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
:at="a.at"
|
|
418
|
-
date-format="long"
|
|
419
|
-
/>
|
|
420
|
-
<!-- What this round was asked to fix: the instructions the gate handed the
|
|
421
|
-
helper (the failing-check summary / conflict reason / review comments),
|
|
422
|
-
plus the structured red checks for the CI gate. -->
|
|
423
|
-
<div
|
|
424
|
-
v-if="a.instructions || (a.failingChecks && a.failingChecks.length)"
|
|
425
|
-
class="mt-1.5"
|
|
426
|
-
>
|
|
427
|
-
<p class="text-[11px] text-slate-500">
|
|
428
|
-
{{ t('gates.attemptInstructions', { helper: helperMeta.label }) }}
|
|
429
|
-
</p>
|
|
430
|
-
<GateFailingCheckList
|
|
431
|
-
v-if="a.failingChecks && a.failingChecks.length"
|
|
432
|
-
class="mt-1"
|
|
433
|
-
:checks="a.failingChecks"
|
|
434
|
-
dense
|
|
435
|
-
/>
|
|
436
|
-
<p
|
|
437
|
-
v-else-if="a.instructions"
|
|
438
|
-
class="mt-1 whitespace-pre-wrap text-[12px] leading-relaxed text-slate-300"
|
|
439
|
-
>
|
|
440
|
-
{{ a.instructions }}
|
|
441
|
-
</p>
|
|
442
|
-
</div>
|
|
443
|
-
<!-- The helper's own report of what it did / what remains. -->
|
|
444
|
-
<template v-if="a.summary">
|
|
445
|
-
<p class="mt-1.5 text-[11px] text-slate-500">
|
|
446
|
-
{{ t('gates.attemptReport', { helper: helperMeta.label }) }}
|
|
447
|
-
</p>
|
|
448
|
-
<p
|
|
449
|
-
class="mt-1 whitespace-pre-wrap text-[12px] leading-relaxed text-slate-400"
|
|
450
|
-
>
|
|
451
|
-
{{ a.summary }}
|
|
452
|
-
</p>
|
|
453
|
-
</template>
|
|
454
|
-
</li>
|
|
455
|
-
</ol>
|
|
456
|
-
</section>
|
|
457
|
-
</template>
|
|
438
|
+
<!-- Sidebar: gate state -->
|
|
439
|
+
<aside
|
|
440
|
+
class="hidden w-60 shrink-0 flex-col gap-4 border-s border-slate-800 bg-slate-900/50 px-4 py-4 lg:flex"
|
|
441
|
+
>
|
|
442
|
+
<div v-if="gate">
|
|
443
|
+
<h4 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
444
|
+
{{ t('gates.sidebar.state') }}
|
|
445
|
+
</h4>
|
|
446
|
+
<div class="flex items-center gap-2 text-[13px]">
|
|
447
|
+
<UIcon
|
|
448
|
+
:name="STATUS_META[status].icon"
|
|
449
|
+
class="h-4 w-4"
|
|
450
|
+
:class="STATUS_META[status].text"
|
|
451
|
+
/>
|
|
452
|
+
<span :class="STATUS_META[status].text">{{ STATUS_META[status].label }}</span>
|
|
458
453
|
</div>
|
|
454
|
+
</div>
|
|
459
455
|
|
|
460
|
-
|
|
461
|
-
<
|
|
462
|
-
|
|
463
|
-
>
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
{{ t('gates.sidebar.state') }}
|
|
467
|
-
</h4>
|
|
468
|
-
<div class="flex items-center gap-2 text-[13px]">
|
|
469
|
-
<UIcon
|
|
470
|
-
:name="STATUS_META[status].icon"
|
|
471
|
-
class="h-4 w-4"
|
|
472
|
-
:class="STATUS_META[status].text"
|
|
473
|
-
/>
|
|
474
|
-
<span :class="STATUS_META[status].text">{{ STATUS_META[status].label }}</span>
|
|
475
|
-
</div>
|
|
476
|
-
</div>
|
|
477
|
-
|
|
478
|
-
<div v-if="gate">
|
|
479
|
-
<h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
480
|
-
{{ helperMeta.label }}
|
|
481
|
-
</h4>
|
|
482
|
-
<p class="text-[12px] text-slate-300">
|
|
483
|
-
<!-- The human-review gate's budget is effectively unbounded (it waits for a human
|
|
456
|
+
<div v-if="gate">
|
|
457
|
+
<h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
458
|
+
{{ helperMeta.label }}
|
|
459
|
+
</h4>
|
|
460
|
+
<p class="text-[12px] text-slate-300">
|
|
461
|
+
<!-- The human-review gate's budget is effectively unbounded (it waits for a human
|
|
484
462
|
indefinitely), so render a plain round count rather than "0/9007199254740991". -->
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
463
|
+
<template v-if="isHumanReview">
|
|
464
|
+
{{ t('gates.sidebar.fixRounds', { count: gate.attempts }, gate.attempts) }}
|
|
465
|
+
</template>
|
|
466
|
+
<template v-else>
|
|
467
|
+
{{
|
|
468
|
+
t(
|
|
469
|
+
'gates.sidebar.attempts',
|
|
470
|
+
{ attempts: gate.attempts, max: gate.maxAttempts },
|
|
471
|
+
gate.maxAttempts,
|
|
472
|
+
)
|
|
473
|
+
}}
|
|
474
|
+
</template>
|
|
475
|
+
<template v-if="gate.phase === 'working'">
|
|
476
|
+
{{ t('gates.sidebar.suffixRunning') }}</template
|
|
477
|
+
>
|
|
478
|
+
<template v-else-if="gate.attempts === 0">
|
|
479
|
+
{{ t('gates.sidebar.suffixNotNeeded') }}</template
|
|
480
|
+
>
|
|
481
|
+
</p>
|
|
482
|
+
</div>
|
|
505
483
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
484
|
+
<div v-if="shortSha">
|
|
485
|
+
<h4 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
486
|
+
{{ t('gates.sidebar.gatedCommit') }}
|
|
487
|
+
</h4>
|
|
488
|
+
<p class="font-mono text-[12px] text-slate-300">{{ shortSha }}</p>
|
|
489
|
+
</div>
|
|
512
490
|
|
|
513
|
-
|
|
491
|
+
<!-- Shared run metadata + embedded observability (model, run id, timing,
|
|
514
492
|
model-activity rollup) — identical to the agent step detail. -->
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
493
|
+
<StepRunMeta
|
|
494
|
+
v-if="step"
|
|
495
|
+
:step="step"
|
|
496
|
+
:instance-id="instanceId ?? undefined"
|
|
497
|
+
:step-number="stepIndex === null ? undefined : stepIndex + 1"
|
|
498
|
+
:total-steps="instance?.steps.length"
|
|
499
|
+
:run-failed="instance?.status === 'failed'"
|
|
500
|
+
:failure-at="instance?.failure?.occurredAt"
|
|
501
|
+
/>
|
|
524
502
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
</div>
|
|
530
|
-
</div>
|
|
503
|
+
<p class="mt-auto text-[10px] leading-relaxed text-slate-600">
|
|
504
|
+
{{ t('gates.sidebar.footer', { helper: helperMeta.label }) }}
|
|
505
|
+
</p>
|
|
506
|
+
</aside>
|
|
531
507
|
</div>
|
|
532
|
-
</
|
|
508
|
+
</ResultWindowShell>
|
|
533
509
|
</template>
|