@cat-factory/app 0.309.0 → 0.310.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/README.md +11 -2
- package/app/components/assistant/AssistantModal.vue +5 -4
- package/app/components/auth/BackendMisconfiguredScreen.vue +4 -3
- package/app/components/auth/LoginScreen.vue +40 -26
- package/app/components/auth/ResetPasswordScreen.vue +9 -4
- package/app/components/auth/UserMenu.vue +4 -3
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +34 -23
- package/app/components/binaryOutput/StoredAssetView.vue +8 -6
- package/app/components/board/AddTaskModal.vue +16 -15
- package/app/components/board/AgentFailureCard.vue +12 -9
- package/app/components/board/AgentFailureHistory.vue +18 -9
- package/app/components/board/CreateInitiativeModal.vue +5 -4
- package/app/components/board/FailureDetail.vue +22 -12
- package/app/components/board/ReviewFrictionDialog.vue +4 -3
- package/app/components/board/nodes/BlockNode.vue +17 -15
- package/app/components/board/nodes/DecisionBadge.vue +4 -3
- package/app/components/board/nodes/FrameSwimlanes.vue +4 -3
- package/app/components/board/nodes/TaskCard.vue +12 -7
- package/app/components/board/nodes/TaskPipelineMini.vue +9 -7
- package/app/components/bootstrap/AdoptionReviewModal.vue +30 -21
- package/app/components/bootstrap/BootstrapModal.vue +3 -3
- package/app/components/brainstorm/BrainstormWindow.vue +5 -3
- package/app/components/bugFishing/BugFishingWindow.vue +49 -27
- package/app/components/clarity/ClarityReviewWindow.vue +5 -3
- package/app/components/common/CopyButton.vue +12 -11
- package/app/components/common/IconButton.vue +34 -9
- package/app/components/context/ContextAttachmentFields.vue +23 -12
- package/app/components/documents/ContextDocumentPicker.vue +12 -9
- package/app/components/documents/DocumentImportModal.vue +4 -3
- package/app/components/documents/DocumentOriginLink.vue +12 -9
- package/app/components/documents/DocumentSyncState.vue +3 -3
- package/app/components/documents/RepoContextDocPicker.vue +4 -3
- package/app/components/environments/EnvironmentStatusPanel.vue +4 -3
- package/app/components/followUp/FollowUpWindow.vue +9 -6
- package/app/components/forkDecision/ForkDecisionWindow.vue +71 -80
- package/app/components/foundational/FoundationalServiceCatalogList.vue +3 -2
- package/app/components/foundational/FoundationalServiceRegistry.vue +7 -6
- package/app/components/foundational/FoundationalServiceSources.vue +7 -6
- package/app/components/fragments/FragmentLibraryManager.vue +5 -4
- package/app/components/fragments/FragmentSelector.vue +12 -9
- package/app/components/gates/GateFailingCheckList.vue +4 -3
- package/app/components/gates/GateResultView.vue +17 -12
- package/app/components/github/AddServiceFromRepoModal.vue +11 -7
- package/app/components/github/GitHubOnboarding.vue +7 -2
- package/app/components/github/GitHubPanel.vue +9 -6
- package/app/components/github/RepoTreeBrowser.vue +15 -12
- package/app/components/humanTest/HumanTestWindow.vue +13 -9
- package/app/components/initiative/InitiativePlanReview.vue +28 -18
- package/app/components/initiative/InitiativeTrackerWindow.vue +171 -124
- package/app/components/judge/JudgeResultView.vue +5 -3
- package/app/components/kaizen/KaizenPanel.vue +67 -53
- package/app/components/layout/AccountTeamSettings.vue +9 -9
- package/app/components/layout/AppearanceSwitcher.vue +4 -3
- package/app/components/layout/BoardSwitcher.vue +10 -8
- package/app/components/layout/BoardToolbar.vue +5 -4
- package/app/components/layout/CommandBar.vue +4 -3
- package/app/components/layout/DefaultTestEnvBanner.vue +4 -3
- package/app/components/layout/IntegrationsHub.vue +8 -6
- package/app/components/layout/LanguageSwitcher.vue +4 -3
- package/app/components/layout/ModelProvidersHub.vue +4 -3
- package/app/components/layout/NotificationsInbox.vue +40 -30
- package/app/components/layout/PersonalSetupModal.vue +4 -3
- package/app/components/layout/RolePrompt.vue +4 -3
- package/app/components/layout/SideBar.vue +4 -3
- package/app/components/layout/TranslationWarningBanner.vue +4 -3
- package/app/components/layout/UiModeSwitcher.vue +8 -6
- package/app/components/layout/UiRoleSwitcher.vue +8 -6
- package/app/components/layout/WorkspaceMembersSettings.vue +2 -2
- package/app/components/media/ArtifactLightbox.vue +69 -39
- package/app/components/media/ImageCompare.vue +69 -74
- package/app/components/observability/OutcomeFilterChips.vue +5 -4
- package/app/components/observability/RunFailureSummary.vue +8 -6
- package/app/components/observability/StepModelActivity.vue +5 -3
- package/app/components/observability/ToolCallList.vue +4 -2
- package/app/components/outcome/OutcomeSummaryWindow.vue +5 -4
- package/app/components/palettes/AgentPalette.vue +18 -14
- package/app/components/panels/AgentStepDetail.vue +30 -19
- package/app/components/panels/ObservabilityPanel.vue +149 -114
- package/app/components/panels/OperatorDashboardPanel.vue +99 -91
- package/app/components/panels/ReportsPanel.vue +64 -61
- package/app/components/panels/ResultWindowShell.vue +148 -134
- package/app/components/panels/StepContainerStatus.vue +9 -9
- package/app/components/panels/StepDelegatedStatus.vue +11 -9
- package/app/components/panels/StepRestartControl.vue +3 -2
- package/app/components/panels/inspector/EpicChildren.vue +4 -3
- package/app/components/panels/inspector/FrontendConfig.vue +3 -2
- package/app/components/panels/inspector/InspectorSection.vue +22 -17
- package/app/components/panels/inspector/ServiceConnections.vue +3 -2
- package/app/components/panels/inspector/ServiceTestConfig.vue +5 -4
- package/app/components/panels/inspector/TaskExecution.vue +5 -4
- package/app/components/panels/inspector/TaskRunSettings.vue +10 -6
- package/app/components/pipeline/EstimateThresholdFields.vue +13 -10
- package/app/components/pipeline/GateConfigFields.vue +14 -18
- package/app/components/pipeline/PipelineBuilder.vue +90 -77
- package/app/components/pipeline/PipelinePicker.vue +8 -6
- package/app/components/pipeline/PipelineProgress.vue +26 -21
- package/app/components/prReview/PrReviewWindow.vue +46 -25
- package/app/components/providers/ApiKeysSection.vue +4 -3
- package/app/components/ralph/RalphLoopResultView.vue +4 -3
- package/app/components/requirements/RequirementsReviewWindow.vue +10 -6
- package/app/components/riskPolicy/RiskPolicyPicker.vue +8 -6
- package/app/components/sandbox/SandboxPanel.vue +73 -54
- package/app/components/settings/CloudflareHandlerSection.vue +33 -30
- package/app/components/settings/ConsensusGroupsSection.vue +40 -30
- package/app/components/settings/InfraHandlersConfigurator.vue +16 -13
- package/app/components/settings/InfrastructureBackendPicker.vue +17 -17
- package/app/components/settings/IssueTrackerPanel.vue +21 -6
- package/app/components/settings/LocalModelEndpointsPanel.vue +3 -2
- package/app/components/settings/ModelConfigurationPanel.vue +9 -8
- package/app/components/settings/OpenRouterCatalogPanel.vue +4 -3
- package/app/components/settings/ProviderPreferenceEditor.vue +5 -6
- package/app/components/settings/RiskPolicyEditorRow.vue +3 -2
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +10 -8
- package/app/components/skills/ReviewSkillQueue.vue +4 -3
- package/app/components/skills/SkillLibraryManager.vue +7 -6
- package/app/components/slack/SlackPanel.vue +9 -5
- package/app/components/spec/ServiceSpecWindow.vue +4 -3
- package/app/components/tasks/ContextIssuePicker.vue +12 -9
- package/app/components/tasks/TaskContextIssues.vue +4 -3
- package/app/components/testing/TestReportWindow.vue +14 -8
- package/app/components/theme/ThemeImportModal.vue +2 -2
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +62 -35
- package/i18n/locales/de.json +7 -3
- package/i18n/locales/en.json +7 -3
- package/i18n/locales/es.json +7 -3
- package/i18n/locales/fr.json +7 -3
- package/i18n/locales/he.json +7 -3
- package/i18n/locales/it.json +7 -3
- package/i18n/locales/ja.json +7 -3
- package/i18n/locales/pl.json +7 -3
- package/i18n/locales/tr.json +7 -3
- package/i18n/locales/uk.json +7 -3
- package/package.json +2 -2
|
@@ -94,8 +94,9 @@ function choose(id: string) {
|
|
|
94
94
|
<!-- left: selectable options -->
|
|
95
95
|
<ul class="w-1/2 shrink-0 overflow-y-auto border-e border-default p-1">
|
|
96
96
|
<li v-if="noneLabel !== undefined">
|
|
97
|
-
<
|
|
98
|
-
|
|
97
|
+
<UButton
|
|
98
|
+
color="neutral"
|
|
99
|
+
variant="ghost"
|
|
99
100
|
class="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-start text-sm hover:bg-elevated/60"
|
|
100
101
|
:class="modelValue ? 'text-toned' : 'text-app-100'"
|
|
101
102
|
data-testid="pipeline-option-none"
|
|
@@ -109,11 +110,12 @@ function choose(id: string) {
|
|
|
109
110
|
name="i-lucide-check"
|
|
110
111
|
class="h-4 w-4 shrink-0 text-primary"
|
|
111
112
|
/>
|
|
112
|
-
</
|
|
113
|
+
</UButton>
|
|
113
114
|
</li>
|
|
114
115
|
<li v-for="p in options" :key="p.id">
|
|
115
|
-
<
|
|
116
|
-
|
|
116
|
+
<UButton
|
|
117
|
+
color="neutral"
|
|
118
|
+
variant="ghost"
|
|
117
119
|
class="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-start text-sm hover:bg-elevated/60"
|
|
118
120
|
:class="modelValue === p.id ? 'text-app-100' : 'text-toned'"
|
|
119
121
|
:data-testid="`pipeline-option-${p.id}`"
|
|
@@ -127,7 +129,7 @@ function choose(id: string) {
|
|
|
127
129
|
name="i-lucide-check"
|
|
128
130
|
class="h-4 w-4 shrink-0 text-primary"
|
|
129
131
|
/>
|
|
130
|
-
</
|
|
132
|
+
</UButton>
|
|
131
133
|
</li>
|
|
132
134
|
</ul>
|
|
133
135
|
|
|
@@ -21,6 +21,7 @@ import PrReviewPhaseBadge from '~/components/prReview/PrReviewPhaseBadge.vue'
|
|
|
21
21
|
import { useNowTick, stepDurationLabel } from '~/composables/useStepTimer'
|
|
22
22
|
import type { BadgeColor } from '~/utils/badge'
|
|
23
23
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
24
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
24
25
|
|
|
25
26
|
const props = defineProps<{ instance: ExecutionInstance }>()
|
|
26
27
|
const emit = defineEmits<{
|
|
@@ -397,14 +398,14 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
397
398
|
(resetting later steps is destructive). Stops propagation so it
|
|
398
399
|
doesn't also open the step-detail overlay. -->
|
|
399
400
|
<template v-if="canRestart(s)">
|
|
400
|
-
<
|
|
401
|
+
<IconButton
|
|
401
402
|
v-if="restartArmed !== i"
|
|
402
403
|
icon="i-lucide-rotate-ccw"
|
|
403
404
|
color="neutral"
|
|
404
405
|
variant="ghost"
|
|
405
406
|
size="xs"
|
|
406
|
-
class="shrink-0 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-
|
|
407
|
-
:
|
|
407
|
+
class="shrink-0 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-within:opacity-100"
|
|
408
|
+
:label="t('pipeline.progress.restartTooltip')"
|
|
408
409
|
@click.stop="
|
|
409
410
|
() => {
|
|
410
411
|
restartArmed = i
|
|
@@ -607,14 +608,15 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
607
608
|
<!-- Follow-up companion (future-looking Coder): a blinking chip that lights up the
|
|
608
609
|
moment the Coder streams an item; click to triage. Blinks while any item is
|
|
609
610
|
undecided (the gate holds the pipeline until they're all decided). -->
|
|
610
|
-
<
|
|
611
|
+
<UButton
|
|
612
|
+
color="neutral"
|
|
613
|
+
variant="ghost"
|
|
611
614
|
v-if="s.followUps?.enabled"
|
|
612
|
-
type="button"
|
|
613
615
|
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed px-2.5 py-1.5 text-start transition hover:border-app-hue-pink/60"
|
|
614
616
|
:class="
|
|
615
617
|
followUpPending(s) > 0
|
|
616
|
-
? 'border-app-hue-pink/50 bg-app-hue-pink/10 followup-blink'
|
|
617
|
-
: 'border-muted/70 bg-default/40'
|
|
618
|
+
? 'border-app-hue-pink/50 bg-app-hue-pink/10 hover:bg-app-hue-pink/10 focus-visible:bg-app-hue-pink/10 disabled:bg-app-hue-pink/10 followup-blink'
|
|
619
|
+
: 'border-muted/70 bg-default/40 hover:bg-default/40 focus-visible:bg-default/40 disabled:bg-default/40'
|
|
618
620
|
"
|
|
619
621
|
@click="ui.openFollowUps(instance.id, i)"
|
|
620
622
|
>
|
|
@@ -633,20 +635,21 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
633
635
|
>
|
|
634
636
|
{{ followUpLabel(s) }}
|
|
635
637
|
</span>
|
|
636
|
-
</
|
|
638
|
+
</UButton>
|
|
637
639
|
|
|
638
640
|
<!-- Implementation-fork decision phase (Coder step): a spinner while the proposer
|
|
639
641
|
surfaces approaches, then a clickable chip to choose one. -->
|
|
640
|
-
<
|
|
642
|
+
<UButton
|
|
643
|
+
color="neutral"
|
|
644
|
+
variant="ghost"
|
|
641
645
|
v-if="forkPhase(s)"
|
|
642
|
-
type="button"
|
|
643
646
|
data-testid="fork-decision-open"
|
|
644
647
|
:data-fork-phase="forkPhase(s)"
|
|
645
648
|
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed px-2.5 py-1.5 text-start transition hover:border-app-secondary-400/60"
|
|
646
649
|
:class="
|
|
647
650
|
forkPhase(s) === 'awaiting_choice'
|
|
648
|
-
? 'border-app-secondary-500/50 bg-app-secondary-500/10 followup-blink'
|
|
649
|
-
: 'border-muted/70 bg-default/40'
|
|
651
|
+
? 'border-app-secondary-500/50 bg-app-secondary-500/10 hover:bg-app-secondary-500/10 focus-visible:bg-app-secondary-500/10 disabled:bg-app-secondary-500/10 followup-blink'
|
|
652
|
+
: 'border-muted/70 bg-default/40 hover:bg-default/40 focus-visible:bg-default/40 disabled:bg-default/40'
|
|
650
653
|
"
|
|
651
654
|
:disabled="forkPhase(s) === 'proposing'"
|
|
652
655
|
@click="ui.openForkDecision(instance.id, i)"
|
|
@@ -669,16 +672,17 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
669
672
|
: t('pipeline.progress.forkDecision.choose')
|
|
670
673
|
}}
|
|
671
674
|
</span>
|
|
672
|
-
</
|
|
675
|
+
</UButton>
|
|
673
676
|
|
|
674
677
|
<!-- PR deep-review parked for a human to select which findings matter: a
|
|
675
678
|
purpose-built chip opening the findings-selection window, ahead of the
|
|
676
679
|
generic approval gate (mirrors the fork-decision chip above). -->
|
|
677
|
-
<
|
|
680
|
+
<UButton
|
|
681
|
+
color="neutral"
|
|
682
|
+
variant="ghost"
|
|
678
683
|
v-if="prReviewAwaiting(s)"
|
|
679
|
-
type="button"
|
|
680
684
|
data-testid="pr-review-open"
|
|
681
|
-
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed border-primary/50 bg-primary/10 px-2.5 py-1.5 text-start transition followup-blink hover:border-primary/60"
|
|
685
|
+
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed border-primary/50 bg-primary/10 hover:bg-primary/10 focus-visible:bg-primary/10 disabled:bg-primary/10 px-2.5 py-1.5 text-start transition followup-blink hover:border-primary/60"
|
|
682
686
|
@click="ui.openPrReview(instance.id, i)"
|
|
683
687
|
>
|
|
684
688
|
<span
|
|
@@ -689,18 +693,19 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
689
693
|
<span class="min-w-0 flex-1 truncate text-xs text-toned">
|
|
690
694
|
{{ t('pipeline.progress.prReview.review') }}
|
|
691
695
|
</span>
|
|
692
|
-
</
|
|
696
|
+
</UButton>
|
|
693
697
|
|
|
694
698
|
<!-- A generating step parked between its candidate pass and its delivering pass: a
|
|
695
699
|
purpose-built chip opening the comparison window, ahead of the generic approval
|
|
696
700
|
gate (mirrors the fork-decision and pr-review chips above). Without it the step
|
|
697
701
|
shows no action at all, because the generic gate below is suppressed for every
|
|
698
702
|
park a dedicated window owns. -->
|
|
699
|
-
<
|
|
703
|
+
<UButton
|
|
704
|
+
color="neutral"
|
|
705
|
+
variant="ghost"
|
|
700
706
|
v-if="candidatesAwaiting(s)"
|
|
701
|
-
type="button"
|
|
702
707
|
data-testid="binary-candidates-open"
|
|
703
|
-
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed border-app-hue-cyan/50 bg-app-hue-cyan/10 px-2.5 py-1.5 text-start transition followup-blink hover:border-app-hue-cyan/60"
|
|
708
|
+
class="mt-3 flex w-full items-center gap-2 rounded-lg border border-dashed border-app-hue-cyan/50 bg-app-hue-cyan/10 hover:bg-app-hue-cyan/10 focus-visible:bg-app-hue-cyan/10 disabled:bg-app-hue-cyan/10 px-2.5 py-1.5 text-start transition followup-blink hover:border-app-hue-cyan/60"
|
|
704
709
|
@click="ui.openBinaryCandidates(instance.id, i)"
|
|
705
710
|
>
|
|
706
711
|
<span
|
|
@@ -714,7 +719,7 @@ const ITEM_ICON: Record<string, string> = {
|
|
|
714
719
|
<span class="min-w-0 flex-1 truncate text-xs text-toned">
|
|
715
720
|
{{ t('pipeline.progress.binaryCandidates.choose') }}
|
|
716
721
|
</span>
|
|
717
|
-
</
|
|
722
|
+
</UButton>
|
|
718
723
|
|
|
719
724
|
<!-- reviewer gate folding/re-reviewing in the background: a working indicator,
|
|
720
725
|
NOT a "Review & approve" gate (the human is summoned only if needed) -->
|
|
@@ -292,14 +292,15 @@ const { requestClose } = useUnsavedGuard({
|
|
|
292
292
|
@close="requestClose"
|
|
293
293
|
>
|
|
294
294
|
<template v-if="state?.prUrl" #header-extras>
|
|
295
|
-
<
|
|
296
|
-
|
|
295
|
+
<ULink
|
|
296
|
+
raw
|
|
297
|
+
:to="state.prUrl"
|
|
297
298
|
target="_blank"
|
|
298
299
|
rel="noopener"
|
|
299
300
|
class="rounded-md px-2 py-1 text-2xs text-primary hover:bg-elevated"
|
|
300
301
|
>
|
|
301
302
|
{{ t('prReview.openPr') }}
|
|
302
|
-
</
|
|
303
|
+
</ULink>
|
|
303
304
|
</template>
|
|
304
305
|
|
|
305
306
|
<div class="flex min-h-0 flex-1">
|
|
@@ -586,12 +587,22 @@ const { requestClose } = useUnsavedGuard({
|
|
|
586
587
|
<span data-testid="pr-review-selected-count">
|
|
587
588
|
{{ t('prReview.selectedCount', { count: activeSelectedIds.length }) }}
|
|
588
589
|
</span>
|
|
589
|
-
<
|
|
590
|
+
<UButton
|
|
591
|
+
color="primary"
|
|
592
|
+
variant="link"
|
|
593
|
+
class="p-0 text-2xs text-primary hover:underline"
|
|
594
|
+
@click="selectAll"
|
|
595
|
+
>
|
|
590
596
|
{{ t('prReview.selectAll') }}
|
|
591
|
-
</
|
|
592
|
-
<
|
|
597
|
+
</UButton>
|
|
598
|
+
<UButton
|
|
599
|
+
color="primary"
|
|
600
|
+
variant="link"
|
|
601
|
+
class="p-0 text-2xs text-primary hover:underline"
|
|
602
|
+
@click="clearAll"
|
|
603
|
+
>
|
|
593
604
|
{{ t('prReview.clear') }}
|
|
594
|
-
</
|
|
605
|
+
</UButton>
|
|
595
606
|
</div>
|
|
596
607
|
|
|
597
608
|
<!-- Findings grouped by slice -->
|
|
@@ -615,14 +626,14 @@ const { requestClose } = useUnsavedGuard({
|
|
|
615
626
|
]"
|
|
616
627
|
>
|
|
617
628
|
<div class="flex items-start gap-2">
|
|
618
|
-
<
|
|
629
|
+
<UCheckbox
|
|
619
630
|
v-if="awaiting || challenging"
|
|
620
|
-
|
|
621
|
-
class="mt-1
|
|
631
|
+
size="xs"
|
|
632
|
+
class="mt-1"
|
|
622
633
|
data-testid="pr-review-finding-toggle"
|
|
623
|
-
:
|
|
634
|
+
:model-value="selected.has(f.id) && !isRetracted(f)"
|
|
624
635
|
:disabled="!awaiting || isRetracted(f)"
|
|
625
|
-
@
|
|
636
|
+
@update:model-value="toggle(f.id)"
|
|
626
637
|
/>
|
|
627
638
|
<div class="min-w-0 flex-1">
|
|
628
639
|
<div class="flex flex-wrap items-center gap-1.5">
|
|
@@ -748,10 +759,12 @@ const { requestClose } = useUnsavedGuard({
|
|
|
748
759
|
v-if="awaiting && !isInvestigating(f)"
|
|
749
760
|
class="mt-1.5 flex items-center gap-3 text-2xs"
|
|
750
761
|
>
|
|
751
|
-
<
|
|
762
|
+
<UButton
|
|
763
|
+
color="primary"
|
|
764
|
+
variant="link"
|
|
752
765
|
v-if="!isRetracted(f)"
|
|
753
766
|
data-testid="pr-review-finding-challenge"
|
|
754
|
-
class="flex items-center gap-1 text-primary hover:underline disabled:opacity-50"
|
|
767
|
+
class="p-0 text-2xs flex items-center gap-1 text-primary hover:underline disabled:opacity-50"
|
|
755
768
|
:disabled="!canResolve || !access.canExecuteRuns.value"
|
|
756
769
|
@click="openChallenge(f.id)"
|
|
757
770
|
>
|
|
@@ -761,16 +774,18 @@ const { requestClose } = useUnsavedGuard({
|
|
|
761
774
|
? t('prReview.challenge.reChallenge')
|
|
762
775
|
: t('prReview.challenge.action')
|
|
763
776
|
}}
|
|
764
|
-
</
|
|
765
|
-
<
|
|
777
|
+
</UButton>
|
|
778
|
+
<UButton
|
|
779
|
+
color="neutral"
|
|
780
|
+
variant="link"
|
|
766
781
|
data-testid="pr-review-finding-dismiss"
|
|
767
|
-
class="flex items-center gap-1 text-muted hover:text-app-error-300 hover:underline disabled:opacity-50"
|
|
782
|
+
class="p-0 text-xs flex items-center gap-1 text-muted hover:text-app-error-300 hover:underline disabled:opacity-50"
|
|
768
783
|
:disabled="!canResolve || !access.canExecuteRuns.value"
|
|
769
784
|
@click="onDismiss(f.id)"
|
|
770
785
|
>
|
|
771
786
|
<UIcon name="i-lucide-trash-2" class="h-3.5 w-3.5" />
|
|
772
787
|
{{ t('prReview.challenge.dismiss') }}
|
|
773
|
-
</
|
|
788
|
+
</UButton>
|
|
774
789
|
</div>
|
|
775
790
|
|
|
776
791
|
<!-- The inline challenge box: an OPTIONAL specific concern for the investigator. -->
|
|
@@ -779,31 +794,37 @@ const { requestClose } = useUnsavedGuard({
|
|
|
779
794
|
data-testid="pr-review-challenge-box"
|
|
780
795
|
class="mt-2 rounded-md border border-primary/40 bg-default/80 p-2"
|
|
781
796
|
>
|
|
782
|
-
<
|
|
797
|
+
<UTextarea
|
|
783
798
|
v-model="challengeText"
|
|
784
799
|
data-testid="pr-review-challenge-input"
|
|
785
|
-
rows="2"
|
|
800
|
+
:rows="2"
|
|
786
801
|
:placeholder="t('prReview.challenge.placeholder')"
|
|
787
|
-
|
|
802
|
+
size="xs"
|
|
803
|
+
class="w-full"
|
|
804
|
+
:ui="{ base: 'resize-y' }"
|
|
788
805
|
/>
|
|
789
806
|
<p class="mt-1 text-3xs text-dimmed">
|
|
790
807
|
{{ t('prReview.challenge.hint') }}
|
|
791
808
|
</p>
|
|
792
809
|
<div class="mt-1.5 flex justify-end gap-2">
|
|
793
|
-
<
|
|
810
|
+
<UButton
|
|
811
|
+
color="neutral"
|
|
812
|
+
variant="ghost"
|
|
794
813
|
class="rounded-sm px-2 py-1 text-2xs text-muted hover:text-default"
|
|
795
814
|
@click="cancelChallenge"
|
|
796
815
|
>
|
|
797
816
|
{{ t('common.cancel') }}
|
|
798
|
-
</
|
|
799
|
-
<
|
|
817
|
+
</UButton>
|
|
818
|
+
<UButton
|
|
819
|
+
color="neutral"
|
|
820
|
+
variant="ghost"
|
|
800
821
|
data-testid="pr-review-challenge-submit"
|
|
801
822
|
class="rounded-sm bg-primary/80 px-2 py-1 text-2xs font-medium text-inverted hover:bg-primary/90 disabled:opacity-50"
|
|
802
823
|
:disabled="!canResolve"
|
|
803
824
|
@click="submitChallenge(f.id)"
|
|
804
825
|
>
|
|
805
826
|
{{ t('prReview.challenge.submit') }}
|
|
806
|
-
</
|
|
827
|
+
</UButton>
|
|
807
828
|
</div>
|
|
808
829
|
</div>
|
|
809
830
|
</div>
|
|
@@ -329,14 +329,15 @@ async function remove(k: ApiKey) {
|
|
|
329
329
|
>
|
|
330
330
|
<li v-for="(step, i) in selected.steps" :key="i">{{ step }}</li>
|
|
331
331
|
<li>
|
|
332
|
-
<
|
|
333
|
-
|
|
332
|
+
<ULink
|
|
333
|
+
raw
|
|
334
|
+
:to="selected.url"
|
|
334
335
|
target="_blank"
|
|
335
336
|
rel="noopener noreferrer"
|
|
336
337
|
class="text-primary underline"
|
|
337
338
|
>
|
|
338
339
|
{{ t('providers.apiKeys.openKeys', { provider: selected.label }) }}
|
|
339
|
-
</
|
|
340
|
+
</ULink>
|
|
340
341
|
</li>
|
|
341
342
|
</ol>
|
|
342
343
|
|
|
@@ -169,16 +169,17 @@ const STATUS_META = computed<
|
|
|
169
169
|
</div>
|
|
170
170
|
</template>
|
|
171
171
|
|
|
172
|
-
<
|
|
172
|
+
<ULink
|
|
173
|
+
raw
|
|
173
174
|
v-if="prUrl"
|
|
174
|
-
:
|
|
175
|
+
:to="prUrl"
|
|
175
176
|
target="_blank"
|
|
176
177
|
rel="noopener"
|
|
177
178
|
class="mt-3 inline-flex items-center gap-1 text-xs text-app-info-300 hover:text-app-info-200 hover:underline"
|
|
178
179
|
>
|
|
179
180
|
{{ t('ralph.viewPr') }}
|
|
180
181
|
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
181
|
-
</
|
|
182
|
+
</ULink>
|
|
182
183
|
|
|
183
184
|
<!-- Why a loop that stopped short of its budget stopped: without this the count in
|
|
184
185
|
the sidebar (e.g. "3 of 20") reads as an unexplained abandonment. -->
|
|
@@ -1116,8 +1116,10 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
1116
1116
|
collapses as a unit (a long doc otherwise pushes the findings/recommendations
|
|
1117
1117
|
off-screen); the per-heading toggles below still work when it's expanded. -->
|
|
1118
1118
|
<section v-if="outline" class="mt-6 border-t border-default pt-5">
|
|
1119
|
-
<
|
|
1120
|
-
|
|
1119
|
+
<UButton
|
|
1120
|
+
color="neutral"
|
|
1121
|
+
variant="ghost"
|
|
1122
|
+
class="mb-3 flex w-full items-center gap-1.5 p-0 text-2xs text-app-success-400 hover:bg-transparent"
|
|
1121
1123
|
@click="toggleDoc"
|
|
1122
1124
|
>
|
|
1123
1125
|
<UIcon
|
|
@@ -1133,16 +1135,18 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
1133
1135
|
: t('requirements.incorporatedDraft')
|
|
1134
1136
|
}}
|
|
1135
1137
|
</span>
|
|
1136
|
-
</
|
|
1138
|
+
</UButton>
|
|
1137
1139
|
<!-- The same reading measure the findings' own prose takes above (see the shell's
|
|
1138
1140
|
`width` prop): the window is `full`-width now, and this is continuous prose that
|
|
1139
1141
|
would otherwise run to 200-character lines. Left-aligned rather than centred, so
|
|
1140
1142
|
it starts where every finding above it starts. -->
|
|
1141
1143
|
<div v-show="!docCollapsed" class="max-w-3xl">
|
|
1142
1144
|
<div v-for="s in outline.sections" :key="s.id" class="mb-2">
|
|
1143
|
-
<
|
|
1145
|
+
<UButton
|
|
1146
|
+
color="neutral"
|
|
1147
|
+
variant="ghost"
|
|
1144
1148
|
v-if="s.title"
|
|
1145
|
-
class="group flex w-full items-center gap-2 text-start"
|
|
1149
|
+
class="group flex w-full items-center gap-2 p-0 text-start hover:bg-transparent"
|
|
1146
1150
|
@click="toggle(s.id)"
|
|
1147
1151
|
>
|
|
1148
1152
|
<UIcon
|
|
@@ -1155,7 +1159,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
1155
1159
|
:class="s.depth <= 1 ? 'text-base' : s.depth === 2 ? 'text-sm' : 'text-xs'"
|
|
1156
1160
|
v-html="s.titleHtml"
|
|
1157
1161
|
/>
|
|
1158
|
-
</
|
|
1162
|
+
</UButton>
|
|
1159
1163
|
<div
|
|
1160
1164
|
v-show="!s.title || !collapsed[s.id]"
|
|
1161
1165
|
class="reader-prose mt-1 ps-5.5 text-sm leading-relaxed text-toned"
|
|
@@ -140,8 +140,9 @@ function choose(id: string) {
|
|
|
140
140
|
<!-- left: selectable options, NAME ONLY -->
|
|
141
141
|
<ul class="w-1/2 shrink-0 overflow-y-auto border-e border-default p-1">
|
|
142
142
|
<li>
|
|
143
|
-
<
|
|
144
|
-
|
|
143
|
+
<UButton
|
|
144
|
+
color="neutral"
|
|
145
|
+
variant="ghost"
|
|
145
146
|
class="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-start text-sm"
|
|
146
147
|
:class="[
|
|
147
148
|
refused.has('') ? 'cursor-not-allowed opacity-50' : 'hover:bg-elevated/60',
|
|
@@ -164,11 +165,12 @@ function choose(id: string) {
|
|
|
164
165
|
name="i-lucide-check"
|
|
165
166
|
class="h-4 w-4 shrink-0 text-primary"
|
|
166
167
|
/>
|
|
167
|
-
</
|
|
168
|
+
</UButton>
|
|
168
169
|
</li>
|
|
169
170
|
<li v-for="p in options" :key="p.id">
|
|
170
|
-
<
|
|
171
|
-
|
|
171
|
+
<UButton
|
|
172
|
+
color="neutral"
|
|
173
|
+
variant="ghost"
|
|
172
174
|
class="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-start text-sm"
|
|
173
175
|
:class="[
|
|
174
176
|
refused.has(p.id) ? 'cursor-not-allowed opacity-50' : 'hover:bg-elevated/60',
|
|
@@ -191,7 +193,7 @@ function choose(id: string) {
|
|
|
191
193
|
name="i-lucide-check"
|
|
192
194
|
class="h-4 w-4 shrink-0 text-primary"
|
|
193
195
|
/>
|
|
194
|
-
</
|
|
196
|
+
</UButton>
|
|
195
197
|
</li>
|
|
196
198
|
</ul>
|
|
197
199
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// and Fixtures (the graded inputs each run is scored against). Loaded on demand when the
|
|
7
7
|
// window opens; 503 (the deployment hasn't provisioned the Sandbox DB) shows a notice.
|
|
8
8
|
import { computed, ref, watch } from 'vue'
|
|
9
|
+
import type { TableColumn } from '@nuxt/ui'
|
|
9
10
|
import type {
|
|
10
11
|
SandboxExperimentStatus,
|
|
11
12
|
SandboxFixtureKind,
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
SandboxUnsupportedReason,
|
|
17
18
|
} from '~/types/sandbox'
|
|
18
19
|
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
20
|
+
import IconButton from '~/components/common/IconButton.vue'
|
|
19
21
|
|
|
20
22
|
const ui = useUiStore()
|
|
21
23
|
const store = useSandboxStore()
|
|
@@ -222,6 +224,16 @@ const detailRows = computed(() =>
|
|
|
222
224
|
)
|
|
223
225
|
const selectedRun = ref<SandboxRun | null>(null)
|
|
224
226
|
|
|
227
|
+
// Column definitions rather than hand-written `<th>`s: the header typography then comes from the
|
|
228
|
+
// table theme instead of a per-file recipe.
|
|
229
|
+
const detailColumns = computed<TableColumn<(typeof detailRows.value)[number]>[]>(() => [
|
|
230
|
+
{ id: 'prompt', header: t('sandbox.results.col.prompt') },
|
|
231
|
+
{ id: 'model', header: t('sandbox.results.col.model') },
|
|
232
|
+
{ id: 'fixture', header: t('sandbox.results.col.fixture') },
|
|
233
|
+
{ id: 'score', header: t('sandbox.results.col.score') },
|
|
234
|
+
{ id: 'objective', header: t('sandbox.results.col.objective') },
|
|
235
|
+
])
|
|
236
|
+
|
|
225
237
|
function scoreColor(score: number): string {
|
|
226
238
|
if (score >= 4) return 'text-app-success-400'
|
|
227
239
|
if (score >= 3) return 'text-app-warning-400'
|
|
@@ -469,55 +481,60 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
469
481
|
}}</UBadge>
|
|
470
482
|
</div>
|
|
471
483
|
<div class="overflow-auto">
|
|
472
|
-
<
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
484
|
+
<UTable
|
|
485
|
+
:data="detailRows"
|
|
486
|
+
:columns="detailColumns"
|
|
487
|
+
:ui="{
|
|
488
|
+
base: 'text-xs',
|
|
489
|
+
th: 'ps-0 pe-2 py-1',
|
|
490
|
+
td: 'ps-0 pe-2 py-1 text-xs whitespace-normal',
|
|
491
|
+
tbody: '[&>tr]:cursor-pointer',
|
|
492
|
+
empty: 'py-0',
|
|
493
|
+
}"
|
|
494
|
+
@select="(_event, row) => (selectedRun = row.original.run)"
|
|
495
|
+
>
|
|
496
|
+
<template #prompt-cell="{ row }">
|
|
497
|
+
<span class="text-toned">{{ row.original.run.promptLabel }}</span>
|
|
498
|
+
</template>
|
|
499
|
+
<template #model-cell="{ row }">
|
|
500
|
+
<span class="font-mono text-2xs text-muted">{{ row.original.run.model }}</span>
|
|
501
|
+
</template>
|
|
502
|
+
<template #fixture-cell="{ row }">
|
|
503
|
+
<span class="text-muted">{{ row.original.fixtureName }}</span>
|
|
504
|
+
</template>
|
|
505
|
+
<template #score-cell="{ row }">
|
|
506
|
+
<span
|
|
507
|
+
v-if="row.original.grade"
|
|
508
|
+
:class="scoreColor(row.original.grade.weightedTotal)"
|
|
509
|
+
class="font-semibold"
|
|
488
510
|
>
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
<span v-else class="text-app-600">—</span>
|
|
517
|
-
</td>
|
|
518
|
-
</tr>
|
|
519
|
-
</tbody>
|
|
520
|
-
</table>
|
|
511
|
+
{{ row.original.grade.weightedTotal.toFixed(2) }}
|
|
512
|
+
</span>
|
|
513
|
+
<span
|
|
514
|
+
v-else-if="row.original.run.status === 'failed'"
|
|
515
|
+
class="text-app-error-400"
|
|
516
|
+
>{{ t('sandbox.results.failed') }}</span
|
|
517
|
+
>
|
|
518
|
+
<span v-else class="text-app-600">—</span>
|
|
519
|
+
</template>
|
|
520
|
+
<template #objective-cell="{ row }">
|
|
521
|
+
<span
|
|
522
|
+
v-if="row.original.grade?.objective"
|
|
523
|
+
:class="
|
|
524
|
+
row.original.grade.objective.pass
|
|
525
|
+
? 'text-app-success-400'
|
|
526
|
+
: 'text-app-warning-400'
|
|
527
|
+
"
|
|
528
|
+
>
|
|
529
|
+
{{ row.original.grade.objective.caught }}/{{
|
|
530
|
+
row.original.grade.objective.total
|
|
531
|
+
}}
|
|
532
|
+
</span>
|
|
533
|
+
<span v-else class="text-app-600">—</span>
|
|
534
|
+
</template>
|
|
535
|
+
<!-- See InitiativeTrackerWindow: the fallback copy is untranslated. -->
|
|
536
|
+
<template #empty />
|
|
537
|
+
</UTable>
|
|
521
538
|
</div>
|
|
522
539
|
|
|
523
540
|
<!-- selected cell output -->
|
|
@@ -550,7 +567,9 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
550
567
|
{{ t('sandbox.results.past') }}
|
|
551
568
|
</SectionLabel>
|
|
552
569
|
<div class="max-h-56 space-y-1 overflow-auto">
|
|
553
|
-
<
|
|
570
|
+
<UButton
|
|
571
|
+
color="neutral"
|
|
572
|
+
variant="ghost"
|
|
554
573
|
v-for="x in store.experiments"
|
|
555
574
|
:key="x.id"
|
|
556
575
|
class="flex w-full items-center justify-between rounded-md border border-default bg-default/40 px-2 py-1.5 text-start text-sm hover:bg-elevated/50"
|
|
@@ -558,7 +577,7 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
558
577
|
>
|
|
559
578
|
<span class="truncate text-toned">{{ x.name }}</span>
|
|
560
579
|
<UBadge variant="soft" size="xs">{{ EXPERIMENT_STATUS_LABEL[x.status] }}</UBadge>
|
|
561
|
-
</
|
|
580
|
+
</UButton>
|
|
562
581
|
<p v-if="!store.experiments.length" class="text-xs text-dimmed">
|
|
563
582
|
{{ t('sandbox.results.empty') }}
|
|
564
583
|
</p>
|
|
@@ -595,12 +614,12 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
595
614
|
<span class="text-2xs text-dimmed">{{ p.agentKind }}</span>
|
|
596
615
|
</div>
|
|
597
616
|
<div class="flex items-center gap-1">
|
|
598
|
-
<
|
|
617
|
+
<IconButton
|
|
599
618
|
icon="i-lucide-pencil"
|
|
600
619
|
color="neutral"
|
|
601
620
|
variant="ghost"
|
|
602
621
|
size="xs"
|
|
603
|
-
:
|
|
622
|
+
:label="
|
|
604
623
|
p.origin === 'baseline'
|
|
605
624
|
? t('sandbox.prompts.forkTitle')
|
|
606
625
|
: t('sandbox.prompts.editTitle')
|
|
@@ -610,14 +629,14 @@ async function archive(prompt: SandboxPromptVersion) {
|
|
|
610
629
|
<!-- Deploy: make this version the workspace's live prompt for its agent kind.
|
|
611
630
|
Offered on a graded candidate and on an older workspace revision (rolling
|
|
612
631
|
back), but not on the one already live, where it would be a no-op. -->
|
|
613
|
-
<
|
|
632
|
+
<IconButton
|
|
614
633
|
v-if="canPromote(p)"
|
|
615
634
|
icon="i-lucide-rocket"
|
|
616
635
|
color="primary"
|
|
617
636
|
variant="ghost"
|
|
618
637
|
size="xs"
|
|
619
638
|
:loading="promoting === p.id"
|
|
620
|
-
:
|
|
639
|
+
:label="t('sandbox.prompts.promoteTitle')"
|
|
621
640
|
@click="promote(p)"
|
|
622
641
|
/>
|
|
623
642
|
<UButton
|