@cat-factory/app 0.308.0 → 0.310.0

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.
Files changed (265) hide show
  1. package/README.md +32 -2
  2. package/app/assets/css/main.css +22 -0
  3. package/app/assets/css/prose.css +4 -4
  4. package/app/assets/css/type.css +24 -0
  5. package/app/components/assistant/AssistantModal.vue +8 -6
  6. package/app/components/auth/BackendMisconfiguredScreen.vue +4 -3
  7. package/app/components/auth/LoginScreen.vue +40 -26
  8. package/app/components/auth/ResetPasswordScreen.vue +9 -4
  9. package/app/components/auth/UserMenu.vue +5 -4
  10. package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +48 -37
  11. package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
  12. package/app/components/binaryOutput/StoredAssetView.vue +13 -11
  13. package/app/components/board/AddTaskModal.vue +30 -27
  14. package/app/components/board/AgentFailureCard.vue +21 -18
  15. package/app/components/board/AgentFailureHistory.vue +18 -9
  16. package/app/components/board/CreateInitiativeModal.vue +7 -6
  17. package/app/components/board/FailureDetail.vue +22 -12
  18. package/app/components/board/FailureHistoryList.vue +5 -5
  19. package/app/components/board/RecurringPipelineModal.vue +12 -11
  20. package/app/components/board/ReviewFrictionDialog.vue +8 -6
  21. package/app/components/board/StepExecutionHistory.vue +8 -8
  22. package/app/components/board/nodes/AgentChip.vue +1 -1
  23. package/app/components/board/nodes/BlockNode.vue +25 -24
  24. package/app/components/board/nodes/DecisionBadge.vue +4 -3
  25. package/app/components/board/nodes/EpicNode.vue +4 -4
  26. package/app/components/board/nodes/FrameSwimlanes.vue +8 -10
  27. package/app/components/board/nodes/InitiativeCard.vue +4 -4
  28. package/app/components/board/nodes/LaneGroup.vue +3 -5
  29. package/app/components/board/nodes/TaskCard.vue +20 -15
  30. package/app/components/board/nodes/TaskLane.vue +3 -3
  31. package/app/components/board/nodes/TaskPipelineMini.vue +21 -18
  32. package/app/components/bootstrap/AdoptionReviewModal.vue +36 -26
  33. package/app/components/bootstrap/BootstrapModal.vue +14 -13
  34. package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
  35. package/app/components/brainstorm/BrainstormWindow.vue +13 -10
  36. package/app/components/bugFishing/BugFishingWindow.vue +81 -58
  37. package/app/components/clarity/ClarityReviewWindow.vue +13 -10
  38. package/app/components/common/AsyncViewError.vue +1 -1
  39. package/app/components/common/ClarificationItem.vue +6 -6
  40. package/app/components/common/CopyButton.vue +12 -11
  41. package/app/components/common/DescriptorFields.vue +1 -1
  42. package/app/components/common/EmptyState.vue +1 -1
  43. package/app/components/common/IconButton.vue +34 -9
  44. package/app/components/common/InterviewGateNotice.vue +4 -4
  45. package/app/components/common/MarkdownProse.vue +8 -2
  46. package/app/components/common/SectionLabel.vue +38 -0
  47. package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
  48. package/app/components/context/ContextAttachmentFields.vue +32 -20
  49. package/app/components/docs/DocInterviewWindow.vue +10 -9
  50. package/app/components/documents/ContextDocumentPicker.vue +22 -21
  51. package/app/components/documents/DocumentImportModal.vue +7 -5
  52. package/app/components/documents/DocumentOriginLink.vue +12 -9
  53. package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
  54. package/app/components/documents/DocumentSyncState.vue +4 -4
  55. package/app/components/documents/DocumentTemplatesModal.vue +5 -4
  56. package/app/components/documents/RepoContextDocPicker.vue +7 -9
  57. package/app/components/documents/StartFromDesignModal.vue +4 -4
  58. package/app/components/documents/TaskContextDocs.vue +1 -1
  59. package/app/components/environments/EnvSetupStepper.vue +3 -3
  60. package/app/components/environments/EnvironmentStatusPanel.vue +15 -13
  61. package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
  62. package/app/components/environments/steps/EnvReviewStep.vue +23 -22
  63. package/app/components/environments/steps/EnvSaveStep.vue +5 -5
  64. package/app/components/focus/BlockFocusView.vue +11 -10
  65. package/app/components/followUp/FollowUpWindow.vue +18 -15
  66. package/app/components/forkDecision/ForkDecisionWindow.vue +85 -97
  67. package/app/components/foundational/FoundationalContractSummary.vue +2 -2
  68. package/app/components/foundational/FoundationalServiceCatalogList.vue +6 -5
  69. package/app/components/foundational/FoundationalServiceRegistry.vue +10 -9
  70. package/app/components/foundational/FoundationalServiceSources.vue +7 -6
  71. package/app/components/foundational/FoundationalSuppressions.vue +2 -2
  72. package/app/components/fragments/FragmentLibraryManager.vue +8 -7
  73. package/app/components/fragments/FragmentSelector.vue +22 -20
  74. package/app/components/gates/GateFailingCheckList.vue +7 -6
  75. package/app/components/gates/GateResultView.vue +55 -49
  76. package/app/components/github/AddServiceFromRepoModal.vue +16 -11
  77. package/app/components/github/BranchProtectionPreflight.vue +5 -5
  78. package/app/components/github/GitHubConnect.vue +5 -3
  79. package/app/components/github/GitHubOnboarding.vue +7 -2
  80. package/app/components/github/GitHubPanel.vue +23 -19
  81. package/app/components/github/RepoTreeBrowser.vue +16 -13
  82. package/app/components/humanTest/HumanTestWindow.vue +29 -24
  83. package/app/components/initiative/InitiativePlanNotice.vue +3 -3
  84. package/app/components/initiative/InitiativePlanReview.vue +46 -38
  85. package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
  86. package/app/components/initiative/InitiativeTrackerWindow.vue +213 -165
  87. package/app/components/judge/JudgeResultView.vue +28 -27
  88. package/app/components/kaizen/KaizenPanel.vue +70 -56
  89. package/app/components/kaizen/KaizenStepStatus.vue +7 -6
  90. package/app/components/layout/AccountAuditLog.vue +1 -1
  91. package/app/components/layout/AccountDeploymentSettings.vue +10 -10
  92. package/app/components/layout/AccountFailureKindRules.vue +13 -13
  93. package/app/components/layout/AccountFoundationalSettings.vue +1 -1
  94. package/app/components/layout/AccountFragmentSettings.vue +1 -1
  95. package/app/components/layout/AccountModelPolicySettings.vue +7 -7
  96. package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
  97. package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
  98. package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
  99. package/app/components/layout/AccountSkillSettings.vue +1 -1
  100. package/app/components/layout/AccountTeamSettings.vue +13 -9
  101. package/app/components/layout/AiProvidersBanner.vue +1 -1
  102. package/app/components/layout/AppearanceSwitcher.vue +5 -4
  103. package/app/components/layout/BoardSwitcher.vue +13 -10
  104. package/app/components/layout/BoardToolbar.vue +10 -5
  105. package/app/components/layout/CommandBar.vue +8 -5
  106. package/app/components/layout/DefaultTestEnvBanner.vue +6 -5
  107. package/app/components/layout/IntegrationsHub.vue +12 -9
  108. package/app/components/layout/LanguageSwitcher.vue +5 -4
  109. package/app/components/layout/ModelProvidersHub.vue +10 -7
  110. package/app/components/layout/NotificationsInbox.vue +47 -36
  111. package/app/components/layout/PersonalSetupModal.vue +9 -6
  112. package/app/components/layout/RolePrompt.vue +5 -4
  113. package/app/components/layout/SideBar.vue +7 -8
  114. package/app/components/layout/SpendWarningBanner.vue +3 -3
  115. package/app/components/layout/TranslationWarningBanner.vue +5 -4
  116. package/app/components/layout/UiModeSwitcher.vue +15 -12
  117. package/app/components/layout/UiRoleSwitcher.vue +10 -8
  118. package/app/components/layout/WorkspaceMembersSettings.vue +2 -2
  119. package/app/components/media/ArtifactLightbox.vue +74 -44
  120. package/app/components/media/ImageCompare.vue +80 -85
  121. package/app/components/merge/MergeEffortChips.vue +4 -6
  122. package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
  123. package/app/components/observability/OutcomeFilterChips.vue +6 -5
  124. package/app/components/observability/RunFailureSummary.vue +22 -23
  125. package/app/components/observability/StepMetricsBar.vue +9 -8
  126. package/app/components/observability/StepModelActivity.vue +8 -5
  127. package/app/components/observability/ToolCallList.vue +19 -20
  128. package/app/components/outcome/OutcomeSummaryWindow.vue +48 -46
  129. package/app/components/palettes/AgentPalette.vue +21 -15
  130. package/app/components/palettes/AgentTierSelect.vue +1 -1
  131. package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
  132. package/app/components/panels/AgentStepDetail.vue +57 -49
  133. package/app/components/panels/AttemptEntryHeader.vue +2 -2
  134. package/app/components/panels/DecisionModal.vue +1 -1
  135. package/app/components/panels/GenericStructuredResultView.vue +6 -5
  136. package/app/components/panels/InspectorPanel.vue +15 -13
  137. package/app/components/panels/MergerResultView.vue +10 -9
  138. package/app/components/panels/ObservabilityPanel.vue +211 -186
  139. package/app/components/panels/OperatorDashboardPanel.vue +124 -115
  140. package/app/components/panels/ReportsPanel.vue +87 -83
  141. package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
  142. package/app/components/panels/ResultWindowShell.vue +152 -137
  143. package/app/components/panels/RunDetailLoadState.vue +1 -1
  144. package/app/components/panels/StepContainerStatus.vue +17 -16
  145. package/app/components/panels/StepDelegatedStatus.vue +24 -21
  146. package/app/components/panels/StepEffortReport.vue +12 -17
  147. package/app/components/panels/StepFragmentAdherence.vue +9 -10
  148. package/app/components/panels/StepMetadataCard.vue +41 -43
  149. package/app/components/panels/StepReproductionReport.vue +18 -20
  150. package/app/components/panels/StepRestartControl.vue +3 -2
  151. package/app/components/panels/StepRunMeta.vue +27 -26
  152. package/app/components/panels/StepTestReport.vue +16 -15
  153. package/app/components/panels/StepToolServers.vue +7 -8
  154. package/app/components/panels/StepValidationReport.vue +5 -5
  155. package/app/components/panels/inspector/ContainerSummary.vue +4 -4
  156. package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
  157. package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
  158. package/app/components/panels/inspector/EpicChildren.vue +12 -10
  159. package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
  160. package/app/components/panels/inspector/FrontendConfig.vue +29 -36
  161. package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
  162. package/app/components/panels/inspector/InspectorSection.vue +25 -17
  163. package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
  164. package/app/components/panels/inspector/ServiceConnections.vue +5 -4
  165. package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
  166. package/app/components/panels/inspector/ServiceSelfTests.vue +9 -13
  167. package/app/components/panels/inspector/ServiceTestConfig.vue +46 -49
  168. package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
  169. package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
  170. package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
  171. package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
  172. package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
  173. package/app/components/panels/inspector/TaskDependencies.vue +1 -1
  174. package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
  175. package/app/components/panels/inspector/TaskExecution.vue +18 -16
  176. package/app/components/panels/inspector/TaskRunSettings.vue +45 -44
  177. package/app/components/panels/inspector/TaskStructure.vue +5 -4
  178. package/app/components/pipeline/AgentPromptEditor.vue +15 -14
  179. package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
  180. package/app/components/pipeline/EstimateThresholdFields.vue +14 -11
  181. package/app/components/pipeline/GateConfigFields.vue +19 -23
  182. package/app/components/pipeline/IterationCapPrompt.vue +1 -1
  183. package/app/components/pipeline/PipelineBuilder.vue +113 -99
  184. package/app/components/pipeline/PipelineHealthModal.vue +7 -7
  185. package/app/components/pipeline/PipelinePicker.vue +11 -9
  186. package/app/components/pipeline/PipelinePreview.vue +6 -7
  187. package/app/components/pipeline/PipelineProgress.vue +49 -45
  188. package/app/components/prReview/PrReviewWindow.vue +87 -65
  189. package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
  190. package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
  191. package/app/components/providers/ApiKeysSection.vue +11 -9
  192. package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
  193. package/app/components/providers/VendorCredentialsModal.vue +5 -4
  194. package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
  195. package/app/components/ralph/RalphLoopResultView.vue +29 -29
  196. package/app/components/requirements/RequirementsReviewWindow.vue +22 -17
  197. package/app/components/riskPolicy/RiskPolicyPicker.vue +13 -11
  198. package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
  199. package/app/components/sandbox/SandboxPanel.vue +93 -73
  200. package/app/components/settings/ApiTokensPanel.vue +1 -1
  201. package/app/components/settings/BudgetSettings.vue +18 -17
  202. package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
  203. package/app/components/settings/CloudflareHandlerSection.vue +44 -41
  204. package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
  205. package/app/components/settings/ConnectionTestVerdict.vue +1 -1
  206. package/app/components/settings/ConsensusGroupsSection.vue +58 -47
  207. package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
  208. package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
  209. package/app/components/settings/InfraHandlersConfigurator.vue +26 -24
  210. package/app/components/settings/InfrastructureBackendPicker.vue +18 -18
  211. package/app/components/settings/IssueTrackerPanel.vue +30 -21
  212. package/app/components/settings/KubernetesEngineForm.vue +9 -8
  213. package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
  214. package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
  215. package/app/components/settings/LocalModelEndpointsPanel.vue +13 -11
  216. package/app/components/settings/MergeClassRulesEditor.vue +6 -5
  217. package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
  218. package/app/components/settings/ModelConfigurationPanel.vue +17 -19
  219. package/app/components/settings/ModelPresetHealthModal.vue +3 -3
  220. package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
  221. package/app/components/settings/OpenRouterCatalogPanel.vue +10 -8
  222. package/app/components/settings/PackageRegistriesPanel.vue +4 -4
  223. package/app/components/settings/ProviderConnectionTab.vue +5 -4
  224. package/app/components/settings/ProviderManifestEditor.vue +9 -8
  225. package/app/components/settings/ProviderPreferenceEditor.vue +13 -13
  226. package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
  227. package/app/components/settings/RiskPolicyEditorRow.vue +21 -19
  228. package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
  229. package/app/components/settings/RiskPolicyPanel.vue +11 -13
  230. package/app/components/settings/ServiceFragmentDefaultsPanel.vue +15 -12
  231. package/app/components/settings/SharedStacksPanel.vue +5 -5
  232. package/app/components/settings/TaskSourceCard.vue +2 -2
  233. package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
  234. package/app/components/settings/ToolServerChecklist.vue +22 -22
  235. package/app/components/settings/UsageSettings.vue +13 -13
  236. package/app/components/settings/UserSecretsSection.vue +4 -3
  237. package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
  238. package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
  239. package/app/components/skills/ReviewSkillQueue.vue +12 -10
  240. package/app/components/skills/SkillLibraryManager.vue +9 -8
  241. package/app/components/slack/SlackPanel.vue +17 -12
  242. package/app/components/spec/ServiceSpecWindow.vue +19 -19
  243. package/app/components/tasks/BugHuntModal.vue +1 -1
  244. package/app/components/tasks/ContextIssuePicker.vue +16 -15
  245. package/app/components/tasks/TaskContextIssues.vue +5 -4
  246. package/app/components/tasks/TaskImportModal.vue +3 -2
  247. package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
  248. package/app/components/testing/TestReportWindow.vue +67 -60
  249. package/app/components/theme/ThemeImportModal.vue +2 -2
  250. package/app/components/tutorial/TutorialNudge.vue +3 -2
  251. package/app/components/tutorial/TutorialOverlay.vue +3 -2
  252. package/app/components/vcs/GitLabConnect.vue +1 -1
  253. package/app/components/visualConfirm/VisualConfirmationWindow.vue +79 -54
  254. package/app/utils/theme/builtins.ts +7 -1
  255. package/i18n/locales/de.json +7 -3
  256. package/i18n/locales/en.json +7 -3
  257. package/i18n/locales/es.json +7 -3
  258. package/i18n/locales/fr.json +7 -3
  259. package/i18n/locales/he.json +7 -3
  260. package/i18n/locales/it.json +7 -3
  261. package/i18n/locales/ja.json +7 -3
  262. package/i18n/locales/pl.json +7 -3
  263. package/i18n/locales/tr.json +7 -3
  264. package/i18n/locales/uk.json +7 -3
  265. package/package.json +1 -1
@@ -137,7 +137,7 @@ const reseedableCount = computed(
137
137
  {{ t('pipeline.health.newHeading') }}
138
138
  </h3>
139
139
  </div>
140
- <p class="text-[11px] text-dimmed">{{ t('pipeline.health.newDescription') }}</p>
140
+ <p class="text-2xs text-dimmed">{{ t('pipeline.health.newDescription') }}</p>
141
141
  <ul class="space-y-2">
142
142
  <li
143
143
  v-for="p in newPipelines"
@@ -172,7 +172,7 @@ const reseedableCount = computed(
172
172
  {{ t('pipeline.health.invalidHeading') }}
173
173
  </h3>
174
174
  </div>
175
- <p class="text-[11px] text-dimmed">
175
+ <p class="text-2xs text-dimmed">
176
176
  {{ t('pipeline.health.invalidDescription') }}
177
177
  </p>
178
178
  <ul class="space-y-2">
@@ -195,7 +195,7 @@ const reseedableCount = computed(
195
195
  <li
196
196
  v-for="(p, i) in h.problems"
197
197
  :key="i"
198
- class="text-[11px]"
198
+ class="text-2xs"
199
199
  :class="
200
200
  p.type === 'outdated' ? 'text-app-warning-400/80' : 'text-app-error-400/90'
201
201
  "
@@ -241,7 +241,7 @@ const reseedableCount = computed(
241
241
  {{ t('pipeline.health.retiredHeading') }}
242
242
  </h3>
243
243
  </div>
244
- <p class="text-[11px] text-dimmed">{{ t('pipeline.health.retiredDescription') }}</p>
244
+ <p class="text-2xs text-dimmed">{{ t('pipeline.health.retiredDescription') }}</p>
245
245
  <ul class="space-y-2">
246
246
  <li
247
247
  v-for="r in retired"
@@ -250,7 +250,7 @@ const reseedableCount = computed(
250
250
  >
251
251
  <div class="min-w-0">
252
252
  <span class="truncate text-sm font-medium text-app-100">{{ r.pipeline.name }}</span>
253
- <p class="text-[11px] text-muted/80">
253
+ <p class="text-2xs text-muted/80">
254
254
  {{
255
255
  r.replacement
256
256
  ? t('pipeline.health.retiredReplacedBy', { name: r.replacement.name })
@@ -281,7 +281,7 @@ const reseedableCount = computed(
281
281
  {{ t('pipeline.health.updatesHeading') }}
282
282
  </h3>
283
283
  </div>
284
- <p class="text-[11px] text-dimmed">
284
+ <p class="text-2xs text-dimmed">
285
285
  {{ t('pipeline.health.updatesDescription') }}
286
286
  </p>
287
287
  <ul class="space-y-2">
@@ -292,7 +292,7 @@ const reseedableCount = computed(
292
292
  >
293
293
  <div class="min-w-0">
294
294
  <span class="truncate text-sm font-medium text-app-100">{{ h.pipeline.name }}</span>
295
- <p class="text-[11px] text-app-warning-400/80">{{ h.problems[0]?.message }}</p>
295
+ <p class="text-2xs text-app-warning-400/80">{{ h.problems[0]?.message }}</p>
296
296
  </div>
297
297
  <UButton
298
298
  size="xs"
@@ -94,9 +94,10 @@ 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
- <button
98
- type="button"
99
- class="flex w-full items-center gap-2 rounded px-2 py-1.5 text-start text-sm hover:bg-elevated/60"
97
+ <UButton
98
+ color="neutral"
99
+ variant="ghost"
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"
102
103
  @mouseenter="hoverId = ''"
@@ -109,12 +110,13 @@ function choose(id: string) {
109
110
  name="i-lucide-check"
110
111
  class="h-4 w-4 shrink-0 text-primary"
111
112
  />
112
- </button>
113
+ </UButton>
113
114
  </li>
114
115
  <li v-for="p in options" :key="p.id">
115
- <button
116
- type="button"
117
- class="flex w-full items-center gap-2 rounded px-2 py-1.5 text-start text-sm hover:bg-elevated/60"
116
+ <UButton
117
+ color="neutral"
118
+ variant="ghost"
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}`"
120
122
  @mouseenter="hoverId = p.id"
@@ -127,14 +129,14 @@ function choose(id: string) {
127
129
  name="i-lucide-check"
128
130
  class="h-4 w-4 shrink-0 text-primary"
129
131
  />
130
- </button>
132
+ </UButton>
131
133
  </li>
132
134
  </ul>
133
135
 
134
136
  <!-- right: preview of the hovered (or selected) pipeline -->
135
137
  <div class="w-1/2 overflow-y-auto p-3">
136
138
  <PipelinePreview v-if="previewPipeline" :pipeline="previewPipeline" />
137
- <div v-else class="text-[12px] leading-snug text-dimmed">{{ emptyHint }}</div>
139
+ <div v-else class="text-xs leading-snug text-dimmed">{{ emptyHint }}</div>
138
140
  </div>
139
141
  </div>
140
142
  </template>
@@ -18,6 +18,7 @@ import {
18
18
  pipelineGateCount,
19
19
  } from '~/utils/pipeline'
20
20
  import AgentKindIcon from '~/components/pipeline/AgentKindIcon.vue'
21
+ import SectionLabel from '~/components/common/SectionLabel.vue'
21
22
 
22
23
  const props = defineProps<{ pipeline: Pipeline }>()
23
24
  const { t } = useI18n()
@@ -37,15 +38,13 @@ function stepDescription(kind: string): string {
37
38
  <div class="text-sm font-semibold text-app-100">{{ pipeline.name }}</div>
38
39
  <p
39
40
  v-if="pipeline.description"
40
- class="text-[12px] leading-snug text-muted"
41
+ class="text-xs leading-snug text-muted"
41
42
  data-testid="pipeline-preview-description"
42
43
  >
43
44
  {{ pipeline.description }}
44
45
  </p>
45
46
 
46
- <div
47
- class="flex flex-wrap items-center gap-x-3 gap-y-1 text-[10px] uppercase tracking-wide text-dimmed"
48
- >
47
+ <SectionLabel class="flex flex-wrap items-center gap-x-3 gap-y-1">
49
48
  <span class="inline-flex items-center gap-1">
50
49
  <UIcon name="i-lucide-workflow" class="h-3 w-3" />
51
50
  {{ t('pipeline.preview.stepCount', { count: steps.length }, steps.length) }}
@@ -62,7 +61,7 @@ function stepDescription(kind: string): string {
62
61
  <UIcon name="i-lucide-git-branch" class="h-3 w-3" />
63
62
  {{ t('pipeline.preview.conditionalCount', { count: conditionalCount }, conditionalCount) }}
64
63
  </span>
65
- </div>
64
+ </SectionLabel>
66
65
 
67
66
  <!-- The ordered steps. The number column doubles as the flow connector (a rule drawn between
68
67
  consecutive numbers), so the list reads as a sequence rather than an unordered set. -->
@@ -76,7 +75,7 @@ function stepDescription(kind: string): string {
76
75
  >
77
76
  <div class="flex flex-col items-center">
78
77
  <span
79
- class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-elevated font-mono text-[9px] tabular-nums text-muted"
78
+ class="flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-elevated font-mono text-3xs tabular-nums text-muted"
80
79
  >
81
80
  {{ i + 1 }}
82
81
  </span>
@@ -101,7 +100,7 @@ function stepDescription(kind: string): string {
101
100
  </div>
102
101
  <!-- Clamped: the catalog prose runs long for some kinds, and <AgentKindIcon> already
103
102
  carries the full text in its hover tooltip. -->
104
- <p class="line-clamp-2 text-[11px] leading-snug text-dimmed">
103
+ <p class="line-clamp-2 text-2xs leading-snug text-dimmed">
105
104
  {{ stepDescription(s.kind) }}
106
105
  </p>
107
106
  </div>
@@ -20,6 +20,8 @@ import StepMetricsBar from '~/components/observability/StepMetricsBar.vue'
20
20
  import PrReviewPhaseBadge from '~/components/prReview/PrReviewPhaseBadge.vue'
21
21
  import { useNowTick, stepDurationLabel } from '~/composables/useStepTimer'
22
22
  import type { BadgeColor } from '~/utils/badge'
23
+ import SectionLabel from '~/components/common/SectionLabel.vue'
24
+ import IconButton from '~/components/common/IconButton.vue'
23
25
 
24
26
  const props = defineProps<{ instance: ExecutionInstance }>()
25
27
  const emit = defineEmits<{
@@ -292,7 +294,7 @@ const ITEM_ICON: Record<string, string> = {
292
294
  <span
293
295
  v-for="l in legend"
294
296
  :key="l.state"
295
- class="inline-flex items-center gap-1.5 text-[11px] text-muted"
297
+ class="inline-flex items-center gap-1.5 text-2xs text-muted"
296
298
  >
297
299
  <span
298
300
  class="h-2 w-2 rounded-full"
@@ -365,15 +367,13 @@ const ITEM_ICON: Record<string, string> = {
365
367
  </span>
366
368
  <span
367
369
  v-if="isCompanionKind(s.agentKind)"
368
- class="shrink-0 rounded bg-accented/60 px-1 text-[9px] font-medium uppercase tracking-wide text-toned"
370
+ class="shrink-0 rounded-sm bg-accented/60 px-1 text-3xs font-medium uppercase tracking-wide text-toned"
369
371
  :title="t('pipeline.progress.companionTooltip')"
370
372
  >
371
373
  {{ t('pipeline.progress.companion') }}
372
374
  </span>
373
375
  </div>
374
- <div
375
- class="flex items-center gap-1.5 text-[10px] uppercase tracking-wide text-dimmed"
376
- >
376
+ <SectionLabel class="flex items-center gap-1.5">
377
377
  <span>{{ t('pipeline.progress.stepOf', { current: i + 1, total }) }}</span>
378
378
  <!-- live elapsed clock: a running step counts up (so no-subtask steps
379
379
  don't read as hung), a finished step shows its total duration -->
@@ -385,10 +385,10 @@ const ITEM_ICON: Record<string, string> = {
385
385
  <UIcon name="i-lucide-clock" class="h-2.5 w-2.5 shrink-0" />
386
386
  {{ stepElapsed(s) }}
387
387
  </span>
388
- </div>
388
+ </SectionLabel>
389
389
  </div>
390
390
  <span
391
- class="ms-auto shrink-0 text-[11px] font-medium"
391
+ class="ms-auto shrink-0 text-2xs font-medium"
392
392
  :style="{ color: stepVisual(s).color }"
393
393
  >
394
394
  {{ stepVisual(s).label }}
@@ -398,14 +398,14 @@ const ITEM_ICON: Record<string, string> = {
398
398
  (resetting later steps is destructive). Stops propagation so it
399
399
  doesn't also open the step-detail overlay. -->
400
400
  <template v-if="canRestart(s)">
401
- <UButton
401
+ <IconButton
402
402
  v-if="restartArmed !== i"
403
403
  icon="i-lucide-rotate-ccw"
404
404
  color="neutral"
405
405
  variant="ghost"
406
406
  size="xs"
407
- class="shrink-0 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100"
408
- :title="t('pipeline.progress.restartTooltip')"
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')"
409
409
  @click.stop="
410
410
  () => {
411
411
  restartArmed = i
@@ -458,7 +458,7 @@ const ITEM_ICON: Record<string, string> = {
458
458
  <!-- container cold-boot phase: shown while the container is spinning up. -->
459
459
  <div
460
460
  v-if="s.container?.status === 'starting' && !runFailed"
461
- class="mt-2 flex items-center gap-1.5 text-[11px] text-app-info-300"
461
+ class="mt-2 flex items-center gap-1.5 text-2xs text-app-info-300"
462
462
  >
463
463
  <UIcon name="i-lucide-loader-circle" class="h-3.5 w-3.5 shrink-0 animate-spin" />
464
464
  <span>{{ t('pipeline.progress.spinningUpContainer') }}</span>
@@ -468,7 +468,7 @@ const ITEM_ICON: Record<string, string> = {
468
468
  making calls) so the step isn't a blank "working" before subtasks appear. -->
469
469
  <div
470
470
  v-else-if="stepPhaseLabel(s) && !runFailed"
471
- class="mt-2 flex items-center gap-1.5 text-[11px] text-app-success-300"
471
+ class="mt-2 flex items-center gap-1.5 text-2xs text-app-success-300"
472
472
  >
473
473
  <UIcon name="i-lucide-box" class="h-3.5 w-3.5 shrink-0" />
474
474
  <span>{{ stepPhaseLabel(s) }}</span>
@@ -481,14 +481,14 @@ const ITEM_ICON: Record<string, string> = {
481
481
  v-if="prPhaseActive(s)"
482
482
  :step="s"
483
483
  :run-failed="runFailed"
484
- class="mt-2 text-[11px]"
484
+ class="mt-2 text-2xs"
485
485
  />
486
486
 
487
487
  <!-- live subtask counts from the agent's todo list -->
488
488
  <div v-if="s.subtasks && s.subtasks.total > 0" class="mt-2">
489
489
  <div
490
490
  v-if="!prPhaseActive(s)"
491
- class="flex items-center justify-between text-[10px] text-muted"
491
+ class="flex items-center justify-between text-3xs text-muted"
492
492
  >
493
493
  <span>
494
494
  {{
@@ -515,7 +515,7 @@ const ITEM_ICON: Record<string, string> = {
515
515
  <li
516
516
  v-for="(item, i) in s.subtasks.items"
517
517
  :key="i"
518
- class="flex items-start gap-1.5 text-[11px]"
518
+ class="flex items-start gap-1.5 text-2xs"
519
519
  :class="
520
520
  item.status === 'completed'
521
521
  ? 'text-dimmed line-through'
@@ -537,7 +537,7 @@ const ITEM_ICON: Record<string, string> = {
537
537
  <!-- model used for this step -->
538
538
  <p
539
539
  v-if="s.model"
540
- class="mt-2 flex items-center gap-1 truncate text-[10px] text-dimmed"
540
+ class="mt-2 flex items-center gap-1 truncate text-3xs text-dimmed"
541
541
  :title="s.model"
542
542
  >
543
543
  <UIcon name="i-lucide-cpu" class="h-3 w-3 shrink-0" />
@@ -557,7 +557,7 @@ const ITEM_ICON: Record<string, string> = {
557
557
 
558
558
  <!-- A one-line hint that the agent produced prose; the full output (and
559
559
  all step metadata) lives in the step-detail overlay opened by click. -->
560
- <p v-if="stepHasOutput(s)" class="mt-2 flex items-center gap-1 text-[11px] text-dimmed">
560
+ <p v-if="stepHasOutput(s)" class="mt-2 flex items-center gap-1 text-2xs text-dimmed">
561
561
  <UIcon name="i-lucide-book-open-text" class="h-3 w-3 shrink-0" />
562
562
  {{ t('pipeline.progress.clickToRead') }}
563
563
  </p>
@@ -567,7 +567,7 @@ const ITEM_ICON: Record<string, string> = {
567
567
  which reads as a tester that silently did its job. -->
568
568
  <p
569
569
  v-if="stepSkipReasonKey(s)"
570
- class="mt-2 flex items-center gap-1 text-[11px] text-dimmed"
570
+ class="mt-2 flex items-center gap-1 text-2xs text-dimmed"
571
571
  data-testid="step-skip-reason"
572
572
  >
573
573
  <UIcon name="i-lucide-skip-forward" class="h-3 w-3 shrink-0" />
@@ -593,12 +593,12 @@ const ITEM_ICON: Record<string, string> = {
593
593
  ]"
594
594
  />
595
595
  </span>
596
- <span class="min-w-0 flex-1 truncate text-[12px] text-toned">
596
+ <span class="min-w-0 flex-1 truncate text-xs text-toned">
597
597
  {{ agentKindMeta(companionByStep[i]!.kind).label }}
598
598
  <span class="text-dimmed">{{ t('pipeline.progress.companionSuffix') }}</span>
599
599
  </span>
600
600
  <span
601
- class="shrink-0 text-[11px] font-medium"
601
+ class="shrink-0 text-2xs font-medium"
602
602
  :class="COMPANION_STATE_META[companionByStep[i]!.state].text"
603
603
  >
604
604
  {{ COMPANION_STATE_META[companionByStep[i]!.state].label }}
@@ -608,14 +608,15 @@ const ITEM_ICON: Record<string, string> = {
608
608
  <!-- Follow-up companion (future-looking Coder): a blinking chip that lights up the
609
609
  moment the Coder streams an item; click to triage. Blinks while any item is
610
610
  undecided (the gate holds the pipeline until they're all decided). -->
611
- <button
611
+ <UButton
612
+ color="neutral"
613
+ variant="ghost"
612
614
  v-if="s.followUps?.enabled"
613
- type="button"
614
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"
615
616
  :class="
616
617
  followUpPending(s) > 0
617
- ? 'border-app-hue-pink/50 bg-app-hue-pink/10 followup-blink'
618
- : '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'
619
620
  "
620
621
  @click="ui.openFollowUps(instance.id, i)"
621
622
  >
@@ -624,30 +625,31 @@ const ITEM_ICON: Record<string, string> = {
624
625
  >
625
626
  <UIcon :name="FOLLOW_UP_COMPANION_META.icon" class="h-3 w-3 text-app-hue-pink" />
626
627
  </span>
627
- <span class="min-w-0 flex-1 truncate text-[12px] text-toned">
628
+ <span class="min-w-0 flex-1 truncate text-xs text-toned">
628
629
  {{ FOLLOW_UP_COMPANION_META.label }}
629
630
  <span class="text-dimmed">{{ t('pipeline.progress.companionSuffix') }}</span>
630
631
  </span>
631
632
  <span
632
- class="shrink-0 text-[11px] font-medium"
633
+ class="shrink-0 text-2xs font-medium"
633
634
  :class="followUpPending(s) > 0 ? 'text-app-hue-pink' : 'text-muted'"
634
635
  >
635
636
  {{ followUpLabel(s) }}
636
637
  </span>
637
- </button>
638
+ </UButton>
638
639
 
639
640
  <!-- Implementation-fork decision phase (Coder step): a spinner while the proposer
640
641
  surfaces approaches, then a clickable chip to choose one. -->
641
- <button
642
+ <UButton
643
+ color="neutral"
644
+ variant="ghost"
642
645
  v-if="forkPhase(s)"
643
- type="button"
644
646
  data-testid="fork-decision-open"
645
647
  :data-fork-phase="forkPhase(s)"
646
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"
647
649
  :class="
648
650
  forkPhase(s) === 'awaiting_choice'
649
- ? 'border-app-secondary-500/50 bg-app-secondary-500/10 followup-blink'
650
- : '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'
651
653
  "
652
654
  :disabled="forkPhase(s) === 'proposing'"
653
655
  @click="ui.openForkDecision(instance.id, i)"
@@ -663,23 +665,24 @@ const ITEM_ICON: Record<string, string> = {
663
665
  :class="forkPhase(s) === 'proposing' ? 'animate-spin' : ''"
664
666
  />
665
667
  </span>
666
- <span class="min-w-0 flex-1 truncate text-[12px] text-toned">
668
+ <span class="min-w-0 flex-1 truncate text-xs text-toned">
667
669
  {{
668
670
  forkPhase(s) === 'proposing'
669
671
  ? t('pipeline.progress.forkDecision.proposing')
670
672
  : t('pipeline.progress.forkDecision.choose')
671
673
  }}
672
674
  </span>
673
- </button>
675
+ </UButton>
674
676
 
675
677
  <!-- PR deep-review parked for a human to select which findings matter: a
676
678
  purpose-built chip opening the findings-selection window, ahead of the
677
679
  generic approval gate (mirrors the fork-decision chip above). -->
678
- <button
680
+ <UButton
681
+ color="neutral"
682
+ variant="ghost"
679
683
  v-if="prReviewAwaiting(s)"
680
- type="button"
681
684
  data-testid="pr-review-open"
682
- 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"
683
686
  @click="ui.openPrReview(instance.id, i)"
684
687
  >
685
688
  <span
@@ -687,21 +690,22 @@ const ITEM_ICON: Record<string, string> = {
687
690
  >
688
691
  <UIcon name="i-lucide-clipboard-check" class="h-3 w-3 text-primary" />
689
692
  </span>
690
- <span class="min-w-0 flex-1 truncate text-[12px] text-toned">
693
+ <span class="min-w-0 flex-1 truncate text-xs text-toned">
691
694
  {{ t('pipeline.progress.prReview.review') }}
692
695
  </span>
693
- </button>
696
+ </UButton>
694
697
 
695
698
  <!-- A generating step parked between its candidate pass and its delivering pass: a
696
699
  purpose-built chip opening the comparison window, ahead of the generic approval
697
700
  gate (mirrors the fork-decision and pr-review chips above). Without it the step
698
701
  shows no action at all, because the generic gate below is suppressed for every
699
702
  park a dedicated window owns. -->
700
- <button
703
+ <UButton
704
+ color="neutral"
705
+ variant="ghost"
701
706
  v-if="candidatesAwaiting(s)"
702
- type="button"
703
707
  data-testid="binary-candidates-open"
704
- 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"
705
709
  @click="ui.openBinaryCandidates(instance.id, i)"
706
710
  >
707
711
  <span
@@ -712,16 +716,16 @@ const ITEM_ICON: Record<string, string> = {
712
716
  class="h-3 w-3 text-app-hue-cyan"
713
717
  />
714
718
  </span>
715
- <span class="min-w-0 flex-1 truncate text-[12px] text-toned">
719
+ <span class="min-w-0 flex-1 truncate text-xs text-toned">
716
720
  {{ t('pipeline.progress.binaryCandidates.choose') }}
717
721
  </span>
718
- </button>
722
+ </UButton>
719
723
 
720
724
  <!-- reviewer gate folding/re-reviewing in the background: a working indicator,
721
725
  NOT a "Review & approve" gate (the human is summoned only if needed) -->
722
726
  <div
723
727
  v-if="reviewStageLabel(s.agentKind)"
724
- class="mt-3 inline-flex items-center gap-1 text-[11px] text-primary"
728
+ class="mt-3 inline-flex items-center gap-1 text-2xs text-primary"
725
729
  >
726
730
  <UIcon name="i-lucide-loader-circle" class="h-3 w-3 animate-spin" />
727
731
  {{ reviewStageLabel(s.agentKind) }}
@@ -766,7 +770,7 @@ const ITEM_ICON: Record<string, string> = {
766
770
  </div>
767
771
  <p
768
772
  v-else-if="s.decision?.chosen"
769
- class="mt-2 flex items-center gap-1 truncate text-[11px] text-app-success-400"
773
+ class="mt-2 flex items-center gap-1 truncate text-2xs text-app-success-400"
770
774
  :title="s.decision.chosen"
771
775
  >
772
776
  <UIcon name="i-lucide-check" class="h-3 w-3 shrink-0" />