@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
@@ -5,6 +5,7 @@ import type { ToolOutcomeFilter } from '~/utils/observability'
5
5
  import { filterToolCallsByOutcome, formatMs } from '~/utils/observability'
6
6
  import { agentKindMeta } from '~/utils/catalog'
7
7
  import OutcomeFilterChips from '~/components/observability/OutcomeFilterChips.vue'
8
+ import SectionLabel from '~/components/common/SectionLabel.vue'
8
9
 
9
10
  // The tool-call TRAJECTORY drill-down: what the run's agents DID, oldest first, in the order
10
11
  // they did it. The sibling of the model-call list, and the one that holds the failures no LLM
@@ -142,10 +143,10 @@ function prettyArgs(raw: string): string {
142
143
  <div class="space-y-4">
143
144
  <div class="flex flex-wrap items-center justify-between gap-2">
144
145
  <div>
145
- <h2 class="text-[11px] uppercase tracking-wide text-dimmed">
146
+ <SectionLabel as="h2">
146
147
  {{ t('observability.toolCalls.title') }}
147
- </h2>
148
- <p class="text-[11px] text-app-600">{{ t('observability.toolCalls.subtitle') }}</p>
148
+ </SectionLabel>
149
+ <p class="text-2xs text-app-600">{{ t('observability.toolCalls.subtitle') }}</p>
149
150
  </div>
150
151
  <OutcomeFilterChips v-model="filter" :options="filterOptions" />
151
152
  </div>
@@ -198,7 +199,7 @@ function prettyArgs(raw: string): string {
198
199
  implies has to explain itself here. -->
199
200
  <p
200
201
  v-if="boundedNotice"
201
- class="rounded-lg border border-dashed border-app-warning-900/50 px-3 py-2 text-[11px] text-app-warning-300/90"
202
+ class="rounded-lg border border-dashed border-app-warning-900/50 px-3 py-2 text-2xs text-app-warning-300/90"
202
203
  >
203
204
  {{ boundedNotice }}
204
205
  </p>
@@ -210,7 +211,9 @@ function prettyArgs(raw: string): string {
210
211
  class="overflow-hidden rounded-xl border border-default bg-default/40"
211
212
  :class="!call.ok ? 'border-app-error-900/60' : ''"
212
213
  >
213
- <button
214
+ <UButton
215
+ color="neutral"
216
+ variant="ghost"
214
217
  class="flex w-full items-center gap-3 px-4 py-2.5 text-start transition hover:bg-default/70"
215
218
  @click="toggle(call)"
216
219
  >
@@ -225,8 +228,8 @@ function prettyArgs(raw: string): string {
225
228
  :style="{ color: agentMeta(call.agentKind).color }"
226
229
  :title="agentMeta(call.agentKind).label"
227
230
  />
228
- <span class="font-mono text-[13px] text-default">{{ call.tool }}</span>
229
- <div class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-muted">
231
+ <span class="font-mono text-sm text-default">{{ call.tool }}</span>
232
+ <div class="ms-auto flex items-center gap-2.5 text-2xs tabular-nums text-muted">
230
233
  <span :title="t('observability.toolCalls.durationHint')">
231
234
  {{ formatMs(Math.max(0, call.endedAt - call.startedAt)) }}
232
235
  </span>
@@ -235,23 +238,21 @@ function prettyArgs(raw: string): string {
235
238
  </UBadge>
236
239
  <span class="hidden text-app-600 md:inline">{{ clock(call.startedAt) }}</span>
237
240
  </div>
238
- </button>
241
+ </UButton>
239
242
 
240
243
  <div v-if="expanded[call.id]" class="border-t border-default px-4 py-3 space-y-3">
241
- <div class="flex flex-wrap gap-x-5 gap-y-1 text-[11px] text-dimmed">
244
+ <div class="flex flex-wrap gap-x-5 gap-y-1 text-2xs text-dimmed">
242
245
  <span>{{ t('observability.toolCalls.dispatch', { jobId: call.jobId }) }}</span>
243
246
  <span>{{ t('observability.toolCalls.seq', { seq: call.seq }) }}</span>
244
247
  </div>
245
248
  <!-- `withheld` is not an empty body: nothing was captured, so an empty `args` here
246
249
  must not read as a tool that took none. -->
247
- <p v-if="call.bodies !== 'stored'" class="text-[12px] italic text-dimmed">
250
+ <p v-if="call.bodies !== 'stored'" class="text-xs italic text-dimmed">
248
251
  {{ t('observability.toolCalls.bodiesWithheld') }}
249
252
  </p>
250
253
  <template v-else>
251
254
  <div>
252
- <div
253
- class="mb-1 flex items-center gap-2 text-[11px] uppercase tracking-wide text-dimmed"
254
- >
255
+ <SectionLabel class="mb-1 flex items-center gap-2">
255
256
  <span>{{ t('observability.toolCalls.arguments') }}</span>
256
257
  <span
257
258
  v-if="call.argsDropped > 0"
@@ -259,15 +260,13 @@ function prettyArgs(raw: string): string {
259
260
  >
260
261
  {{ t('observability.toolCalls.dropped', { chars: call.argsDropped }) }}
261
262
  </span>
262
- </div>
263
+ </SectionLabel>
263
264
  <pre
264
- class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
265
+ class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
265
266
  >{{ call.args ? prettyArgs(call.args) : '—' }}</pre>
266
267
  </div>
267
268
  <div>
268
- <div
269
- class="mb-1 flex items-center gap-2 text-[11px] uppercase tracking-wide text-dimmed"
270
- >
269
+ <SectionLabel class="mb-1 flex items-center gap-2">
271
270
  <span>{{ t('observability.toolCalls.result') }}</span>
272
271
  <span
273
272
  v-if="call.resultDropped > 0"
@@ -275,9 +274,9 @@ function prettyArgs(raw: string): string {
275
274
  >
276
275
  {{ t('observability.toolCalls.dropped', { chars: call.resultDropped }) }}
277
276
  </span>
278
- </div>
277
+ </SectionLabel>
279
278
  <pre
280
- class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed"
279
+ class="max-h-60 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed"
281
280
  :class="call.ok ? 'text-toned' : 'text-app-error-300'"
282
281
  >{{ call.result || '—' }}</pre>
283
282
  </div>
@@ -45,6 +45,7 @@ import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
45
45
  import MarkdownProse from '~/components/common/MarkdownProse.vue'
46
46
  import EmptyState from '~/components/common/EmptyState.vue'
47
47
  import type { BadgeColor } from '~/utils/badge'
48
+ import SectionLabel from '~/components/common/SectionLabel.vue'
48
49
 
49
50
  const board = useBoardStore()
50
51
  const documents = useDocumentsStore()
@@ -458,16 +459,16 @@ function openTestReport() {
458
459
 
459
460
  <!-- What was asked, in the requester's own words. -->
460
461
  <section class="mb-5">
461
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
462
+ <SectionLabel as="h3" class="mb-1.5">
462
463
  {{ t('outcome.ask.title') }}
463
- </h3>
464
+ </SectionLabel>
464
465
  <MarkdownProse
465
466
  v-if="outcome.ask"
466
467
  :text="outcome.ask"
467
- class="text-[13px] leading-relaxed text-toned"
468
+ class="text-sm leading-relaxed text-toned"
468
469
  data-testid="outcome-ask"
469
470
  />
470
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
471
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
471
472
  {{ t('outcome.ask.none') }}
472
473
  </p>
473
474
  </section>
@@ -477,9 +478,9 @@ function openTestReport() {
477
478
  agents actually read, and every section below is a statement about work done against
478
479
  it. A design that moved mid-run is the reading that changes all of them. -->
479
480
  <section class="mb-5" data-testid="outcome-sources">
480
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
481
+ <SectionLabel as="h3" class="mb-1.5">
481
482
  {{ t('outcome.sources.title') }}
482
- </h3>
483
+ </SectionLabel>
483
484
  <div v-if="outcome.sources.status === 'reported'" class="space-y-1">
484
485
  <div
485
486
  v-for="source in sourceRows"
@@ -495,7 +496,7 @@ function openTestReport() {
495
496
  <UIcon :name="source.icon" class="h-3.5 w-3.5 shrink-0 text-primary" />
496
497
  <span class="truncate">{{ source.title }}</span>
497
498
  </DocumentOriginLink>
498
- <p class="mt-0.5 text-[11px] text-dimmed" data-testid="outcome-source-revision">
499
+ <p class="mt-0.5 text-2xs text-dimmed" data-testid="outcome-source-revision">
499
500
  {{ source.revision }}
500
501
  </p>
501
502
  <!-- Stated separately from the revision above: the last revision alone says the run
@@ -503,23 +504,23 @@ function openTestReport() {
503
504
  changed under it. -->
504
505
  <p
505
506
  v-if="source.movedDuringRun"
506
- class="mt-0.5 text-[11px] text-app-warning-300"
507
+ class="mt-0.5 text-2xs text-app-warning-300"
507
508
  data-testid="outcome-source-moved"
508
509
  >
509
510
  {{ t('outcome.sources.moved') }}
510
511
  </p>
511
512
  </div>
512
513
  </div>
513
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
514
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
514
515
  {{ t(SOURCES_GAP_KEYS[outcome.sources.gap]) }}
515
516
  </p>
516
517
  </section>
517
518
 
518
519
  <!-- Requirement coverage: which required behaviours were checked, and what was seen. -->
519
520
  <section class="mb-5" data-testid="outcome-requirements">
520
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
521
+ <SectionLabel as="h3" class="mb-1.5">
521
522
  {{ t('outcome.requirements.title') }}
522
- </h3>
523
+ </SectionLabel>
523
524
  <template v-if="outcome.requirements.status === 'reported'">
524
525
  <div class="mb-2 flex flex-wrap items-center gap-1.5">
525
526
  <UBadge color="success" variant="subtle" size="sm">
@@ -550,7 +551,7 @@ function openTestReport() {
550
551
  and do not cover rather than letting them read as the whole picture. -->
551
552
  <p
552
553
  v-if="specNote"
553
- class="mb-2 text-[11px] leading-relaxed text-app-warning-300/90"
554
+ class="mb-2 text-2xs leading-relaxed text-app-warning-300/90"
554
555
  data-testid="outcome-spec-note"
555
556
  >
556
557
  {{ specNote }}
@@ -560,7 +561,7 @@ function openTestReport() {
560
561
  deciding which of the two numbers to distrust. -->
561
562
  <p
562
563
  v-if="unmatchedVerdicts > 0"
563
- class="mb-2 text-[11px] leading-relaxed text-app-warning-300/90"
564
+ class="mb-2 text-2xs leading-relaxed text-app-warning-300/90"
564
565
  data-testid="outcome-unmatched-verdicts"
565
566
  >
566
567
  {{ t('outcome.requirements.unmatchedVerdicts', { count: unmatchedVerdicts }) }}
@@ -578,7 +579,7 @@ function openTestReport() {
578
579
  />
579
580
  <div class="min-w-0">
580
581
  <div class="flex flex-wrap items-center gap-1.5">
581
- <span class="text-[13px] text-default">{{ req.title ?? req.id }}</span>
582
+ <span class="text-sm text-default">{{ req.title ?? req.id }}</span>
582
583
  <UBadge
583
584
  v-if="req.regression"
584
585
  color="error"
@@ -588,18 +589,18 @@ function openTestReport() {
588
589
  >
589
590
  {{ t('outcome.requirements.regressionTag') }}
590
591
  </UBadge>
591
- <span class="text-[10px] uppercase tracking-wide text-dimmed">
592
+ <SectionLabel as="span">
592
593
  {{ t(VERDICT_META[req.verdict].key) }}
593
- </span>
594
+ </SectionLabel>
594
595
  </div>
595
- <p v-if="req.detail" class="mt-0.5 text-[12px] leading-relaxed text-muted">
596
+ <p v-if="req.detail" class="mt-0.5 text-xs leading-relaxed text-muted">
596
597
  {{ req.detail }}
597
598
  </p>
598
599
  </div>
599
600
  </li>
600
601
  </ul>
601
602
  </template>
602
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
603
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
603
604
  {{ t(REQUIREMENTS_GAP_KEYS[outcome.requirements.gap]) }}
604
605
  </p>
605
606
  </section>
@@ -607,9 +608,9 @@ function openTestReport() {
607
608
  <!-- How it was tested: the tester's own verdict and prose, attributed as its account. -->
608
609
  <section class="mb-5" data-testid="outcome-tests">
609
610
  <div class="mb-1.5 flex flex-wrap items-center gap-2">
610
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
611
+ <SectionLabel as="h3">
611
612
  {{ t('outcome.tests.title') }}
612
- </h3>
613
+ </SectionLabel>
613
614
  <UBadge
614
615
  v-if="outcome.tests.status === 'reported'"
615
616
  :color="TESTS_VERDICT_COLOR[outcome.tests.verdict]"
@@ -642,15 +643,15 @@ function openTestReport() {
642
643
  <template v-if="outcome.tests.status === 'reported'">
643
644
  <p
644
645
  v-if="outcome.tests.abortReason"
645
- class="mb-2 rounded-md border border-app-error-900/70 bg-app-error-500/10 p-2 text-[13px] leading-relaxed text-app-error-200"
646
+ class="mb-2 rounded-md border border-app-error-900/70 bg-app-error-500/10 p-2 text-sm leading-relaxed text-app-error-200"
646
647
  data-testid="outcome-tests-abort"
647
648
  >
648
649
  {{ t('outcome.tests.abort', { reason: outcome.tests.abortReason }) }}
649
650
  </p>
650
- <p v-if="outcome.tests.summary" class="text-[13px] leading-relaxed text-toned">
651
+ <p v-if="outcome.tests.summary" class="text-sm leading-relaxed text-toned">
651
652
  {{ t('outcome.tests.summary', { summary: outcome.tests.summary }) }}
652
653
  </p>
653
- <p class="mt-1.5 text-[12px] text-muted">
654
+ <p class="mt-1.5 text-xs text-muted">
654
655
  {{
655
656
  t('outcome.tests.counts', {
656
657
  passed: outcome.tests.passed,
@@ -663,7 +664,7 @@ function openTestReport() {
663
664
  <li
664
665
  v-for="(concern, i) in outcome.tests.concerns"
665
666
  :key="i"
666
- class="flex items-start gap-2 text-[12px] text-toned"
667
+ class="flex items-start gap-2 text-xs text-toned"
667
668
  data-testid="outcome-concern"
668
669
  >
669
670
  <UBadge :color="SEVERITY_COLOR[concern.severity]" variant="subtle" size="sm">
@@ -673,18 +674,18 @@ function openTestReport() {
673
674
  </li>
674
675
  </ul>
675
676
  </template>
676
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
677
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
677
678
  {{ t(TESTS_GAP_KEYS[outcome.tests.gap]) }}
678
679
  </p>
679
680
  </section>
680
681
 
681
682
  <!-- What it looks like: the captured views, and whether a human was asked about them. -->
682
683
  <section class="mb-5" data-testid="outcome-visuals">
683
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
684
+ <SectionLabel as="h3" class="mb-1.5">
684
685
  {{ t('outcome.visuals.title') }}
685
- </h3>
686
+ </SectionLabel>
686
687
  <template v-if="outcome.visuals.status === 'reported'">
687
- <p class="mb-2 text-[12px] leading-relaxed text-muted">
688
+ <p class="mb-2 text-xs leading-relaxed text-muted">
688
689
  {{
689
690
  outcome.visuals.source === 'visual_confirm'
690
691
  ? t('outcome.visuals.source.visual_confirm')
@@ -692,11 +693,12 @@ function openTestReport() {
692
693
  }}
693
694
  </p>
694
695
  <div class="grid grid-cols-2 gap-2 sm:grid-cols-3">
695
- <button
696
+ <UButton
697
+ color="neutral"
698
+ variant="ghost"
696
699
  v-for="(view, position) in outcome.visuals.views"
697
700
  :key="`${position}:${view.view}`"
698
- type="button"
699
- class="group overflow-hidden rounded-md border border-default bg-app-950/60 text-start transition hover:border-app-600"
701
+ class="group block overflow-hidden rounded-md border border-default bg-app-950/60 hover:bg-app-950/60 focus-visible:bg-app-950/60 disabled:bg-app-950/60 p-0 text-start transition hover:border-app-600"
700
702
  :disabled="!view.artifactId"
701
703
  data-testid="outcome-shot"
702
704
  @click="openShot(view, position)"
@@ -718,7 +720,7 @@ function openTestReport() {
718
720
  />
719
721
  </div>
720
722
  <span
721
- class="flex items-center gap-1 truncate px-1.5 py-1 text-[11px] text-toned"
723
+ class="flex items-center gap-1 truncate px-1.5 py-1 text-2xs text-toned"
722
724
  :title="view.view"
723
725
  >
724
726
  <UIcon
@@ -729,16 +731,16 @@ function openTestReport() {
729
731
  />
730
732
  {{ view.view }}
731
733
  </span>
732
- </button>
734
+ </UButton>
733
735
  </div>
734
736
  </template>
735
737
  <template v-else>
736
- <p class="text-[13px] italic leading-relaxed text-dimmed">
738
+ <p class="text-sm italic leading-relaxed text-dimmed">
737
739
  {{ t(VISUALS_GAP_KEYS[outcome.visuals.gap]) }}
738
740
  </p>
739
741
  <p
740
742
  v-if="outcome.visuals.detail"
741
- class="mt-1 text-[12px] leading-relaxed text-dimmed"
743
+ class="mt-1 text-xs leading-relaxed text-dimmed"
742
744
  data-testid="outcome-visuals-detail"
743
745
  >
744
746
  {{ outcome.visuals.detail }}
@@ -750,9 +752,9 @@ function openTestReport() {
750
752
  not read diffs starts from. Beside the captured views on purpose: the shots are what
751
753
  this run saw, this is the thing itself. -->
752
754
  <section class="mb-5" data-testid="outcome-environments">
753
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
755
+ <SectionLabel as="h3" class="mb-1.5">
754
756
  {{ t('outcome.environments.title') }}
755
- </h3>
757
+ </SectionLabel>
756
758
  <template v-if="outcome.environments.status === 'reported'">
757
759
  <div
758
760
  v-for="row in environmentRows"
@@ -765,10 +767,10 @@ function openTestReport() {
765
767
  <UBadge :color="ENVIRONMENT_STATE_COLOR[row.state]" variant="subtle" size="sm">
766
768
  {{ t(ENVIRONMENT_STATE_KEYS[row.state]) }}
767
769
  </UBadge>
768
- <span v-if="row.service" class="truncate text-[12px] text-toned">
770
+ <span v-if="row.service" class="truncate text-xs text-toned">
769
771
  {{ row.service }}
770
772
  </span>
771
- <span class="text-[11px] text-dimmed">
773
+ <span class="text-2xs text-dimmed">
772
774
  {{ t(ENVIRONMENT_ORIGIN_KEYS[row.origin]) }}
773
775
  </span>
774
776
  </div>
@@ -789,15 +791,15 @@ function openTestReport() {
789
791
  </UButton>
790
792
  <p
791
793
  v-else-if="row.url"
792
- class="mt-1.5 break-all text-[12px] text-dimmed"
794
+ class="mt-1.5 break-all text-xs text-dimmed"
793
795
  data-testid="outcome-environment-url"
794
796
  >
795
797
  {{ row.url }}
796
798
  </p>
797
- <p v-if="row.retained" class="mt-1 text-[11px] text-muted">
799
+ <p v-if="row.retained" class="mt-1 text-2xs text-muted">
798
800
  {{ t('outcome.environments.retained') }}
799
801
  </p>
800
- <p v-if="row.expiresAt" class="mt-1 text-[11px] text-dimmed">
802
+ <p v-if="row.expiresAt" class="mt-1 text-2xs text-dimmed">
801
803
  {{
802
804
  row.lapsed
803
805
  ? t('outcome.environments.expired', { date: d(new Date(row.expiresAt), 'long') })
@@ -810,7 +812,7 @@ function openTestReport() {
810
812
  otherwise holds "quota exceeded" reports a fault the environment does not have. -->
811
813
  <p
812
814
  v-if="row.detail"
813
- class="mt-1 break-words text-[12px] leading-relaxed text-dimmed"
815
+ class="mt-1 break-words text-xs leading-relaxed text-dimmed"
814
816
  data-testid="outcome-environment-detail"
815
817
  :data-detail-kind="row.detailKind"
816
818
  >
@@ -822,16 +824,16 @@ function openTestReport() {
822
824
  </p>
823
825
  </div>
824
826
  </template>
825
- <p v-else class="text-[13px] italic leading-relaxed text-dimmed">
827
+ <p v-else class="text-sm italic leading-relaxed text-dimmed">
826
828
  {{ t(ENVIRONMENTS_GAP_KEYS[outcome.environments.gap]) }}
827
829
  </p>
828
830
  </section>
829
831
 
830
832
  <!-- The machine checks, listed only where one actually recorded a verdict. -->
831
833
  <section v-if="checkRows.length" data-testid="outcome-checks">
832
- <h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
834
+ <SectionLabel as="h3" class="mb-1.5">
833
835
  {{ t('outcome.checks.title') }}
834
- </h3>
836
+ </SectionLabel>
835
837
  <div class="flex flex-wrap items-center gap-1.5">
836
838
  <UBadge
837
839
  v-for="check in checkRows"
@@ -6,6 +6,7 @@ import AgentTierSelect from '~/components/palettes/AgentTierSelect.vue'
6
6
  import PipelinePurposeSelect from '~/components/palettes/PipelinePurposeSelect.vue'
7
7
  import { groupAgentPalette, narrowAgentPalette } from '~/utils/agentPalette'
8
8
  import { AGENT_CATEGORIES, OBSERVABILITY_GATE_ARCHETYPE } from '~/utils/catalog'
9
+ import SectionLabel from '~/components/common/SectionLabel.vue'
9
10
 
10
11
  const { t } = useI18n()
11
12
  const agents = useAgentsStore()
@@ -57,7 +58,7 @@ function toggle(id: string) {
57
58
 
58
59
  <template>
59
60
  <div class="space-y-2">
60
- <p class="px-1 text-[11px] text-dimmed">{{ t('palette.hint') }}</p>
61
+ <p class="px-1 text-2xs text-dimmed">{{ t('palette.hint') }}</p>
61
62
  <!-- The two catalog dials, one above the other: what this pipeline is for, and how deep into
62
63
  the agent catalog to look. Both narrow the sections below, and each states its own count.
63
64
  Stacked rather than side by side because the palette column is a third of the slideover:
@@ -73,23 +74,28 @@ function toggle(id: string) {
73
74
  </div>
74
75
  <div class="space-y-2">
75
76
  <section v-for="g in groups" :key="g.id">
76
- <button
77
- type="button"
78
- class="flex w-full items-center gap-1.5 rounded px-1 py-1 text-start text-[11px] font-semibold uppercase tracking-wide text-muted transition hover:text-default"
77
+ <UButton
78
+ color="neutral"
79
+ variant="link"
80
+ class="group w-full rounded-sm px-1 py-1"
81
+ :aria-expanded="!isCollapsed(g.id)"
79
82
  @click="toggle(g.id)"
80
83
  >
81
- <UIcon
82
- :name="isCollapsed(g.id) ? 'i-lucide-chevron-right' : 'i-lucide-chevron-down'"
83
- class="h-3.5 w-3.5 shrink-0"
84
- />
85
- <span>{{ g.label }}</span>
86
- <span class="ms-auto text-app-600">{{ g.agents.length }}</span>
87
- </button>
84
+ <SectionLabel as="span" class="flex w-full items-center gap-1.5 group-hover:text-default">
85
+ <UIcon
86
+ :name="isCollapsed(g.id) ? 'i-lucide-chevron-right' : 'i-lucide-chevron-down'"
87
+ class="h-3.5 w-3.5 shrink-0"
88
+ />
89
+ <span>{{ g.label }}</span>
90
+ <span class="ms-auto text-app-600">{{ g.agents.length }}</span>
91
+ </SectionLabel>
92
+ </UButton>
88
93
  <div v-if="!isCollapsed(g.id)" class="mt-1 space-y-1.5">
89
- <button
94
+ <UButton
95
+ color="neutral"
96
+ variant="ghost"
90
97
  v-for="a in g.agents"
91
98
  :key="a.kind"
92
- type="button"
93
99
  class="flex w-full items-center gap-2.5 rounded-lg border border-muted bg-elevated/60 p-2 text-start transition hover:border-app-500 hover:bg-elevated"
94
100
  :title="a.description"
95
101
  :data-testid="`palette-agent-${a.kind}`"
@@ -103,10 +109,10 @@ function toggle(id: string) {
103
109
  </div>
104
110
  <div class="min-w-0">
105
111
  <div class="text-xs font-semibold text-app-100">{{ a.label }}</div>
106
- <div class="truncate text-[10px] text-muted">{{ a.description }}</div>
112
+ <div class="truncate text-3xs text-muted">{{ a.description }}</div>
107
113
  </div>
108
114
  <UIcon name="i-lucide-plus" class="ms-auto h-4 w-4 shrink-0 text-dimmed" />
109
- </button>
115
+ </UButton>
110
116
  </div>
111
117
  </section>
112
118
  </div>
@@ -60,7 +60,7 @@ const items = computed(() => [
60
60
  </span>
61
61
  </UButton>
62
62
  </UDropdownMenu>
63
- <p v-if="props.hiddenCount" class="px-1 text-[10px] text-dimmed">
63
+ <p v-if="props.hiddenCount" class="px-1 text-3xs text-dimmed">
64
64
  {{ t('agentTier.hidden', { count: props.hiddenCount }, props.hiddenCount) }}
65
65
  </p>
66
66
  </div>
@@ -72,7 +72,7 @@ const items = computed(() => [
72
72
  <span class="truncate"> {{ t('pipeline.builder.purposeLabel') }}: {{ current }} </span>
73
73
  </UButton>
74
74
  </UDropdownMenu>
75
- <p v-if="props.hiddenCount" class="px-1 text-[10px] text-dimmed">
75
+ <p v-if="props.hiddenCount" class="px-1 text-3xs text-dimmed">
76
76
  {{ t('palette.purposeHidden', { count: props.hiddenCount }, props.hiddenCount) }}
77
77
  </p>
78
78
  </div>