@cat-factory/app 0.307.1 → 0.309.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 (255) hide show
  1. package/README.md +21 -0
  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 +3 -2
  6. package/app/components/auth/UserMenu.vue +1 -1
  7. package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +15 -15
  8. package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
  9. package/app/components/binaryOutput/StoredAssetView.vue +5 -5
  10. package/app/components/board/AddTaskModal.vue +16 -14
  11. package/app/components/board/AgentFailureCard.vue +9 -9
  12. package/app/components/board/AgentFailureHistory.vue +1 -1
  13. package/app/components/board/CreateInitiativeModal.vue +2 -2
  14. package/app/components/board/FailureDetail.vue +1 -1
  15. package/app/components/board/FailureHistoryList.vue +5 -5
  16. package/app/components/board/RecurringPipelineModal.vue +12 -11
  17. package/app/components/board/ReviewFrictionDialog.vue +4 -3
  18. package/app/components/board/StepExecutionHistory.vue +8 -8
  19. package/app/components/board/nodes/AgentChip.vue +1 -1
  20. package/app/components/board/nodes/BlockNode.vue +8 -9
  21. package/app/components/board/nodes/EpicNode.vue +4 -4
  22. package/app/components/board/nodes/FrameSwimlanes.vue +4 -7
  23. package/app/components/board/nodes/InitiativeCard.vue +4 -4
  24. package/app/components/board/nodes/LaneGroup.vue +3 -5
  25. package/app/components/board/nodes/TaskCard.vue +8 -8
  26. package/app/components/board/nodes/TaskLane.vue +3 -3
  27. package/app/components/board/nodes/TaskPipelineMini.vue +13 -12
  28. package/app/components/bootstrap/AdoptionReviewModal.vue +7 -6
  29. package/app/components/bootstrap/BootstrapModal.vue +11 -10
  30. package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
  31. package/app/components/brainstorm/BrainstormWindow.vue +8 -7
  32. package/app/components/bugFishing/BugFishingWindow.vue +37 -36
  33. package/app/components/clarity/ClarityReviewWindow.vue +8 -7
  34. package/app/components/common/AsyncViewError.vue +1 -1
  35. package/app/components/common/ClarificationItem.vue +6 -6
  36. package/app/components/common/DescriptorFields.vue +1 -1
  37. package/app/components/common/EmptyState.vue +1 -1
  38. package/app/components/common/InterviewGateNotice.vue +4 -4
  39. package/app/components/common/MarkdownProse.vue +8 -2
  40. package/app/components/common/SectionLabel.vue +38 -0
  41. package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
  42. package/app/components/context/ContextAttachmentFields.vue +9 -8
  43. package/app/components/docs/DocInterviewWindow.vue +10 -9
  44. package/app/components/documents/ContextDocumentPicker.vue +10 -12
  45. package/app/components/documents/DocumentImportModal.vue +3 -2
  46. package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
  47. package/app/components/documents/DocumentSyncState.vue +1 -1
  48. package/app/components/documents/DocumentTemplatesModal.vue +5 -4
  49. package/app/components/documents/RepoContextDocPicker.vue +3 -6
  50. package/app/components/documents/StartFromDesignModal.vue +4 -4
  51. package/app/components/documents/TaskContextDocs.vue +1 -1
  52. package/app/components/environments/EnvSetupStepper.vue +3 -3
  53. package/app/components/environments/EnvironmentStatusPanel.vue +11 -10
  54. package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
  55. package/app/components/environments/steps/EnvReviewStep.vue +23 -22
  56. package/app/components/environments/steps/EnvSaveStep.vue +5 -5
  57. package/app/components/focus/BlockFocusView.vue +11 -10
  58. package/app/components/followUp/FollowUpWindow.vue +10 -10
  59. package/app/components/forkDecision/ForkDecisionWindow.vue +23 -26
  60. package/app/components/foundational/FoundationalContractSummary.vue +2 -2
  61. package/app/components/foundational/FoundationalServiceCatalogList.vue +3 -3
  62. package/app/components/foundational/FoundationalServiceRegistry.vue +3 -3
  63. package/app/components/foundational/FoundationalSuppressions.vue +2 -2
  64. package/app/components/fragments/FragmentLibraryManager.vue +3 -3
  65. package/app/components/fragments/FragmentSelector.vue +10 -11
  66. package/app/components/gates/GateFailingCheckList.vue +3 -3
  67. package/app/components/gates/GateResultView.vue +39 -38
  68. package/app/components/github/AddServiceFromRepoModal.vue +5 -4
  69. package/app/components/github/BranchProtectionPreflight.vue +5 -5
  70. package/app/components/github/GitHubConnect.vue +5 -3
  71. package/app/components/github/GitHubPanel.vue +14 -13
  72. package/app/components/github/RepoTreeBrowser.vue +1 -1
  73. package/app/components/humanTest/HumanTestWindow.vue +18 -17
  74. package/app/components/initiative/InitiativePlanNotice.vue +3 -3
  75. package/app/components/initiative/InitiativePlanReview.vue +19 -21
  76. package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
  77. package/app/components/initiative/InitiativeTrackerWindow.vue +54 -53
  78. package/app/components/judge/JudgeResultView.vue +24 -25
  79. package/app/components/kaizen/KaizenPanel.vue +4 -4
  80. package/app/components/kaizen/KaizenStepStatus.vue +7 -6
  81. package/app/components/layout/AccountAuditLog.vue +1 -1
  82. package/app/components/layout/AccountDeploymentSettings.vue +10 -10
  83. package/app/components/layout/AccountFailureKindRules.vue +13 -13
  84. package/app/components/layout/AccountFoundationalSettings.vue +1 -1
  85. package/app/components/layout/AccountFragmentSettings.vue +1 -1
  86. package/app/components/layout/AccountModelPolicySettings.vue +7 -7
  87. package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
  88. package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
  89. package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
  90. package/app/components/layout/AccountSkillSettings.vue +1 -1
  91. package/app/components/layout/AccountTeamSettings.vue +4 -0
  92. package/app/components/layout/AiProvidersBanner.vue +1 -1
  93. package/app/components/layout/AppearanceSwitcher.vue +1 -1
  94. package/app/components/layout/BoardSwitcher.vue +3 -2
  95. package/app/components/layout/BoardToolbar.vue +6 -2
  96. package/app/components/layout/CommandBar.vue +4 -2
  97. package/app/components/layout/DefaultTestEnvBanner.vue +2 -2
  98. package/app/components/layout/IntegrationsHub.vue +4 -3
  99. package/app/components/layout/LanguageSwitcher.vue +1 -1
  100. package/app/components/layout/ModelProvidersHub.vue +6 -4
  101. package/app/components/layout/NotificationsInbox.vue +8 -7
  102. package/app/components/layout/PersonalSetupModal.vue +5 -3
  103. package/app/components/layout/RolePrompt.vue +1 -1
  104. package/app/components/layout/SideBar.vue +3 -5
  105. package/app/components/layout/SpendWarningBanner.vue +3 -3
  106. package/app/components/layout/TranslationWarningBanner.vue +1 -1
  107. package/app/components/layout/UiModeSwitcher.vue +7 -6
  108. package/app/components/layout/UiRoleSwitcher.vue +2 -2
  109. package/app/components/media/ArtifactLightbox.vue +6 -6
  110. package/app/components/media/ImageCompare.vue +16 -16
  111. package/app/components/merge/MergeEffortChips.vue +4 -6
  112. package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
  113. package/app/components/observability/OutcomeFilterChips.vue +1 -1
  114. package/app/components/observability/RunFailureSummary.vue +14 -17
  115. package/app/components/observability/StepMetricsBar.vue +9 -8
  116. package/app/components/observability/StepModelActivity.vue +4 -3
  117. package/app/components/observability/ToolCallList.vue +15 -18
  118. package/app/components/outcome/OutcomeSummaryWindow.vue +43 -42
  119. package/app/components/palettes/AgentPalette.vue +7 -5
  120. package/app/components/palettes/AgentTierSelect.vue +1 -1
  121. package/app/components/palettes/PipelinePurposeSelect.vue +2 -1
  122. package/app/components/panels/AgentStepDetail.vue +27 -30
  123. package/app/components/panels/AttemptEntryHeader.vue +2 -2
  124. package/app/components/panels/DecisionModal.vue +1 -1
  125. package/app/components/panels/GenericStructuredResultView.vue +6 -5
  126. package/app/components/panels/InspectorPanel.vue +15 -13
  127. package/app/components/panels/MergerResultView.vue +10 -9
  128. package/app/components/panels/ObservabilityPanel.vue +66 -76
  129. package/app/components/panels/OperatorDashboardPanel.vue +27 -26
  130. package/app/components/panels/ReportsPanel.vue +26 -25
  131. package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
  132. package/app/components/panels/ResultWindowShell.vue +19 -18
  133. package/app/components/panels/RunDetailLoadState.vue +1 -1
  134. package/app/components/panels/StepContainerStatus.vue +8 -7
  135. package/app/components/panels/StepDelegatedStatus.vue +13 -12
  136. package/app/components/panels/StepEffortReport.vue +12 -17
  137. package/app/components/panels/StepFragmentAdherence.vue +9 -10
  138. package/app/components/panels/StepMetadataCard.vue +41 -43
  139. package/app/components/panels/StepReproductionReport.vue +18 -20
  140. package/app/components/panels/StepRunMeta.vue +27 -26
  141. package/app/components/panels/StepTestReport.vue +16 -15
  142. package/app/components/panels/StepToolServers.vue +7 -8
  143. package/app/components/panels/StepValidationReport.vue +5 -5
  144. package/app/components/panels/inspector/ContainerSummary.vue +4 -4
  145. package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
  146. package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
  147. package/app/components/panels/inspector/EpicChildren.vue +8 -7
  148. package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
  149. package/app/components/panels/inspector/FrontendConfig.vue +26 -34
  150. package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
  151. package/app/components/panels/inspector/InspectorSection.vue +7 -4
  152. package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
  153. package/app/components/panels/inspector/ServiceConnections.vue +2 -2
  154. package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
  155. package/app/components/panels/inspector/ServiceSelfTests.vue +9 -13
  156. package/app/components/panels/inspector/ServiceTestConfig.vue +41 -45
  157. package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
  158. package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
  159. package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
  160. package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
  161. package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
  162. package/app/components/panels/inspector/TaskDependencies.vue +1 -1
  163. package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
  164. package/app/components/panels/inspector/TaskExecution.vue +13 -12
  165. package/app/components/panels/inspector/TaskRunSettings.vue +35 -38
  166. package/app/components/panels/inspector/TaskStructure.vue +5 -4
  167. package/app/components/pipeline/AgentPromptEditor.vue +15 -14
  168. package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
  169. package/app/components/pipeline/EstimateThresholdFields.vue +2 -2
  170. package/app/components/pipeline/GateConfigFields.vue +6 -6
  171. package/app/components/pipeline/IterationCapPrompt.vue +1 -1
  172. package/app/components/pipeline/PipelineBuilder.vue +28 -27
  173. package/app/components/pipeline/PipelineHealthModal.vue +7 -7
  174. package/app/components/pipeline/PipelinePicker.vue +3 -3
  175. package/app/components/pipeline/PipelinePreview.vue +6 -7
  176. package/app/components/pipeline/PipelineProgress.vue +23 -24
  177. package/app/components/prReview/PrReviewWindow.vue +42 -41
  178. package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
  179. package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
  180. package/app/components/providers/ApiKeysSection.vue +7 -6
  181. package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
  182. package/app/components/providers/VendorCredentialsModal.vue +5 -4
  183. package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
  184. package/app/components/ralph/RalphLoopResultView.vue +25 -26
  185. package/app/components/requirements/RequirementsReviewWindow.vue +13 -12
  186. package/app/components/riskPolicy/RiskPolicyPicker.vue +5 -5
  187. package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
  188. package/app/components/sandbox/SandboxPanel.vue +21 -20
  189. package/app/components/settings/ApiTokensPanel.vue +1 -1
  190. package/app/components/settings/BudgetSettings.vue +18 -17
  191. package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
  192. package/app/components/settings/CloudflareHandlerSection.vue +16 -16
  193. package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
  194. package/app/components/settings/ConnectionTestVerdict.vue +1 -1
  195. package/app/components/settings/ConsensusGroupsSection.vue +21 -20
  196. package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
  197. package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
  198. package/app/components/settings/InfraHandlersConfigurator.vue +14 -15
  199. package/app/components/settings/InfrastructureBackendPicker.vue +2 -2
  200. package/app/components/settings/IssueTrackerPanel.vue +9 -15
  201. package/app/components/settings/KubernetesEngineForm.vue +9 -8
  202. package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
  203. package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
  204. package/app/components/settings/LocalModelEndpointsPanel.vue +10 -9
  205. package/app/components/settings/MergeClassRulesEditor.vue +6 -5
  206. package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
  207. package/app/components/settings/ModelConfigurationPanel.vue +8 -11
  208. package/app/components/settings/ModelPresetHealthModal.vue +3 -3
  209. package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
  210. package/app/components/settings/OpenRouterCatalogPanel.vue +6 -5
  211. package/app/components/settings/PackageRegistriesPanel.vue +4 -4
  212. package/app/components/settings/ProviderConnectionTab.vue +5 -4
  213. package/app/components/settings/ProviderManifestEditor.vue +9 -8
  214. package/app/components/settings/ProviderPreferenceEditor.vue +8 -7
  215. package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
  216. package/app/components/settings/RiskPolicyEditorRow.vue +18 -17
  217. package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
  218. package/app/components/settings/RiskPolicyPanel.vue +11 -13
  219. package/app/components/settings/ServiceFragmentDefaultsPanel.vue +5 -4
  220. package/app/components/settings/SharedStacksPanel.vue +5 -5
  221. package/app/components/settings/TaskSourceCard.vue +2 -2
  222. package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
  223. package/app/components/settings/ToolServerChecklist.vue +22 -22
  224. package/app/components/settings/UsageSettings.vue +13 -13
  225. package/app/components/settings/UserSecretsSection.vue +4 -3
  226. package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
  227. package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
  228. package/app/components/skills/ReviewSkillQueue.vue +8 -7
  229. package/app/components/skills/SkillLibraryManager.vue +2 -2
  230. package/app/components/slack/SlackPanel.vue +8 -7
  231. package/app/components/spec/ServiceSpecWindow.vue +15 -16
  232. package/app/components/tasks/BugHuntModal.vue +1 -1
  233. package/app/components/tasks/ContextIssuePicker.vue +4 -6
  234. package/app/components/tasks/TaskContextIssues.vue +1 -1
  235. package/app/components/tasks/TaskImportModal.vue +3 -2
  236. package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
  237. package/app/components/testing/TestReportWindow.vue +54 -53
  238. package/app/components/tutorial/TutorialNudge.vue +3 -2
  239. package/app/components/tutorial/TutorialOverlay.vue +3 -2
  240. package/app/components/vcs/GitLabConnect.vue +1 -1
  241. package/app/components/visualConfirm/VisualConfirmationWindow.vue +23 -25
  242. package/app/composables/usePipelineErrorToast.ts +2 -0
  243. package/app/utils/catalog.ts +8 -0
  244. package/app/utils/theme/builtins.ts +7 -1
  245. package/i18n/locales/de.json +6 -3
  246. package/i18n/locales/en.json +6 -3
  247. package/i18n/locales/es.json +6 -3
  248. package/i18n/locales/fr.json +6 -3
  249. package/i18n/locales/he.json +6 -3
  250. package/i18n/locales/it.json +6 -3
  251. package/i18n/locales/ja.json +6 -3
  252. package/i18n/locales/pl.json +6 -3
  253. package/i18n/locales/tr.json +6 -3
  254. package/i18n/locales/uk.json +6 -3
  255. package/package.json +2 -2
@@ -29,6 +29,7 @@ import {
29
29
  import OutcomeFilterChips from '~/components/observability/OutcomeFilterChips.vue'
30
30
  import RunFailureSummary from '~/components/observability/RunFailureSummary.vue'
31
31
  import ToolCallList from '~/components/observability/ToolCallList.vue'
32
+ import SectionLabel from '~/components/common/SectionLabel.vue'
32
33
 
33
34
  /** No run selected: the same empty, NOT-truncated trajectory the store answers with. */
34
35
  const EMPTY_TRAJECTORY: RunToolCallTrajectory = Object.freeze({
@@ -520,7 +521,7 @@ function exportJson() {
520
521
  </p>
521
522
  </div>
522
523
  <div class="ms-auto flex items-center gap-1.5">
523
- <div class="me-1 flex rounded-lg border border-default p-0.5 text-[12px]">
524
+ <div class="me-1 flex rounded-lg border border-default p-0.5 text-xs">
524
525
  <button
525
526
  class="rounded-md px-2.5 py-1 transition"
526
527
  :class="
@@ -597,28 +598,28 @@ function exportJson() {
597
598
 
598
599
  <!-- run-level summary -->
599
600
  <section class="rounded-xl border border-default bg-default/50 p-4">
600
- <dl class="grid grid-cols-2 gap-x-6 gap-y-3 text-[13px] sm:grid-cols-4">
601
+ <dl class="grid grid-cols-2 gap-x-6 gap-y-3 text-sm sm:grid-cols-4">
601
602
  <div>
602
- <dt class="text-[11px] uppercase tracking-wide text-dimmed">
603
+ <SectionLabel as="dt">
603
604
  {{ t('observability.summary.calls') }}
604
- </dt>
605
+ </SectionLabel>
605
606
  <dd class="mt-0.5 tabular-nums text-default">{{ totals.calls }}</dd>
606
607
  </div>
607
608
  <div v-if="showCost || !phaseRollup.available">
608
- <dt class="text-[11px] uppercase tracking-wide text-dimmed">
609
+ <SectionLabel as="dt">
609
610
  {{ t('observability.summary.cost') }}
610
- </dt>
611
+ </SectionLabel>
611
612
  <dd class="mt-0.5 tabular-nums text-default">
612
613
  {{ runCost ?? '—' }}
613
- <span class="mt-0.5 block text-[11px] text-dimmed">
614
+ <span class="mt-0.5 block text-2xs text-dimmed">
614
615
  {{ t(costNoteKey) }}
615
616
  </span>
616
617
  </dd>
617
618
  </div>
618
619
  <div>
619
- <dt class="text-[11px] uppercase tracking-wide text-dimmed">
620
+ <SectionLabel as="dt">
620
621
  {{ t('observability.summary.tokensInOut') }}
621
- </dt>
622
+ </SectionLabel>
622
623
  <dd class="mt-0.5 tabular-nums text-default">
623
624
  <span :title="t('observability.summary.inputTokensHint')">
624
625
  {{ formatTokens(totals.inputTokens) }} /
@@ -626,7 +627,7 @@ function exportJson() {
626
627
  </span>
627
628
  <span
628
629
  v-if="totals.cacheReadTokens > 0 || totals.cacheWriteTokens > 0"
629
- class="mt-0.5 block text-[11px]"
630
+ class="mt-0.5 block text-2xs"
630
631
  >
631
632
  <span class="text-muted" :title="t('observability.summary.freshHint')">
632
633
  {{
@@ -665,9 +666,9 @@ function exportJson() {
665
666
  </dd>
666
667
  </div>
667
668
  <div>
668
- <dt class="text-[11px] uppercase tracking-wide text-dimmed">
669
+ <SectionLabel as="dt">
669
670
  {{ t('observability.summary.transportOverhead') }}
670
- </dt>
671
+ </SectionLabel>
671
672
  <dd class="mt-0.5 tabular-nums text-default">
672
673
  <span v-if="totals.transportPct !== null">
673
674
  {{ totals.transportPct }}% · {{ formatMs(totals.overheadMs) }}
@@ -676,9 +677,9 @@ function exportJson() {
676
677
  </dd>
677
678
  </div>
678
679
  <div>
679
- <dt class="text-[11px] uppercase tracking-wide text-dimmed">
680
+ <SectionLabel as="dt">
680
681
  {{ t('observability.summary.modelExecution') }}
681
- </dt>
682
+ </SectionLabel>
682
683
  <dd class="mt-0.5 tabular-nums text-default">
683
684
  {{ formatMs(totals.upstreamMs) }}
684
685
  </dd>
@@ -718,22 +719,22 @@ function exportJson() {
718
719
  class="rounded-xl border border-default bg-default/50 p-4"
719
720
  >
720
721
  <div class="flex items-baseline gap-2">
721
- <h2 class="text-[11px] uppercase tracking-wide text-dimmed">
722
+ <SectionLabel as="h2">
722
723
  {{ t('observability.phase.title') }}
723
- </h2>
724
- <span v-if="phaseRollup.available" class="text-[11px] text-app-600">
724
+ </SectionLabel>
725
+ <span v-if="phaseRollup.available" class="text-2xs text-app-600">
725
726
  {{ t('observability.phase.subtitle') }}
726
727
  </span>
727
728
  </div>
728
729
  <!-- No rollup to fold: said in words, because an absent table and a run that spent
729
730
  nothing look identical, and the calls listed above prove it spent something. -->
730
- <p v-if="!phaseRollup.available" class="mt-2 text-[12px] text-muted">
731
+ <p v-if="!phaseRollup.available" class="mt-2 text-xs text-muted">
731
732
  {{ t('observability.phase.noRollup') }}
732
733
  </p>
733
734
  <div v-else class="mt-3 overflow-x-auto">
734
- <table class="w-full min-w-[32rem] text-[12px]">
735
+ <table class="w-full min-w-[32rem] text-xs">
735
736
  <thead>
736
- <tr class="text-[11px] uppercase tracking-wide text-dimmed">
737
+ <tr class="text-2xs uppercase tracking-wide text-dimmed">
737
738
  <th class="py-1 pe-3 text-start font-normal">
738
739
  {{ t('observability.phase.columns.phase') }}
739
740
  </th>
@@ -767,7 +768,7 @@ function exportJson() {
767
768
  <span :class="p.phase ? '' : 'text-muted italic'">
768
769
  {{ phaseLabel(p.phase) }}
769
770
  </span>
770
- <span v-if="!p.phase" class="ms-1.5 text-[11px] text-app-600">
771
+ <span v-if="!p.phase" class="ms-1.5 text-2xs text-app-600">
771
772
  {{ t('observability.phase.unattributedHint') }}
772
773
  </span>
773
774
  <UBadge
@@ -838,9 +839,9 @@ function exportJson() {
838
839
  <!-- per-call list, narrowable by outcome -->
839
840
  <template v-else>
840
841
  <div class="flex flex-wrap items-center justify-between gap-2">
841
- <h2 class="text-[11px] uppercase tracking-wide text-dimmed">
842
+ <SectionLabel as="h2">
842
843
  {{ t('observability.callsTitle') }}
843
- </h2>
844
+ </SectionLabel>
844
845
  <OutcomeFilterChips v-model="callFilter" :options="callFilterOptions" />
845
846
  </div>
846
847
 
@@ -876,11 +877,8 @@ function exportJson() {
876
877
  class="h-4 w-4 shrink-0"
877
878
  :style="{ color: agentMeta(c.agentKind).color }"
878
879
  />
879
- <span class="text-[13px] text-default">{{ agentMeta(c.agentKind).label }}</span>
880
- <span
881
- class="hidden truncate text-[11px] text-dimmed sm:inline"
882
- :title="c.model"
883
- >
880
+ <span class="text-sm text-default">{{ agentMeta(c.agentKind).label }}</span>
881
+ <span class="hidden truncate text-2xs text-dimmed sm:inline" :title="c.model">
884
882
  {{ c.provider }}:{{ c.model }}
885
883
  <!-- Which upstream a GATEWAY routed to. Without it every `openrouter` row
886
884
  reads alike, and an upstream having a bad day cannot be told from the
@@ -890,9 +888,7 @@ function exportJson() {
890
888
  {{ t('observability.call.viaUpstream', { upstream: c.upstreamProvider }) }}
891
889
  </span>
892
890
  </span>
893
- <div
894
- class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-muted"
895
- >
891
+ <div class="ms-auto flex items-center gap-2.5 text-2xs tabular-nums text-muted">
896
892
  <span
897
893
  :title="
898
894
  t('observability.call.tokensTitle', {
@@ -942,10 +938,10 @@ function exportJson() {
942
938
  </button>
943
939
 
944
940
  <div v-if="expanded[c.id]" class="border-t border-default px-4 py-3 space-y-3">
945
- <p v-if="c.errorMessage" class="text-[12px] text-app-error-400">
941
+ <p v-if="c.errorMessage" class="text-xs text-app-error-400">
946
942
  {{ c.errorMessage }}
947
943
  </p>
948
- <div class="flex flex-wrap gap-x-5 gap-y-1 text-[11px] text-dimmed">
944
+ <div class="flex flex-wrap gap-x-5 gap-y-1 text-2xs text-dimmed">
949
945
  <span>{{ t('observability.call.messages', { count: c.messageCount }) }}</span>
950
946
  <span>{{ t('observability.call.tools', { count: c.toolCount }) }}</span>
951
947
  <span>{{
@@ -982,9 +978,7 @@ function exportJson() {
982
978
  </span>
983
979
  </div>
984
980
  <div>
985
- <div
986
- class="mb-1 flex items-center gap-2 text-[11px] uppercase tracking-wide text-dimmed"
987
- >
981
+ <SectionLabel class="mb-1 flex items-center gap-2">
988
982
  <span>{{ t('observability.call.prompt') }}</span>
989
983
  <span
990
984
  v-if="c.promptPrefixCount > 0"
@@ -996,25 +990,25 @@ function exportJson() {
996
990
  })
997
991
  }}
998
992
  </span>
999
- </div>
993
+ </SectionLabel>
1000
994
  <pre
1001
- class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
995
+ class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
1002
996
  >{{ prettyPrompt(c.promptText) }}</pre>
1003
997
  </div>
1004
998
  <div>
1005
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
999
+ <SectionLabel class="mb-1">
1006
1000
  {{ t('observability.call.response') }}
1007
- </div>
1001
+ </SectionLabel>
1008
1002
  <pre
1009
- class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
1003
+ class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
1010
1004
  >{{ c.responseText || '—' }}</pre>
1011
1005
  </div>
1012
1006
  <div v-if="c.reasoningText">
1013
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1007
+ <SectionLabel class="mb-1">
1014
1008
  {{ t('observability.call.reasoning') }}
1015
- </div>
1009
+ </SectionLabel>
1016
1010
  <pre
1017
- class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-muted"
1011
+ class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-muted"
1018
1012
  >{{ c.reasoningText }}</pre>
1019
1013
  </div>
1020
1014
  </div>
@@ -1039,7 +1033,7 @@ function exportJson() {
1039
1033
  so the survey's absence would otherwise read as a phase that used no tools. -->
1040
1034
  <p
1041
1035
  v-if="bootstrap?.monorepo"
1042
- class="rounded-lg border border-dashed border-default px-3 py-2 text-[12px] text-muted"
1036
+ class="rounded-lg border border-dashed border-default px-3 py-2 text-xs text-muted"
1043
1037
  >
1044
1038
  {{ t('observability.toolCalls.surveyReadsElsewhere') }}
1045
1039
  </p>
@@ -1108,13 +1102,11 @@ function exportJson() {
1108
1102
  class="h-4 w-4 shrink-0"
1109
1103
  :style="{ color: agentMeta(s.agentKind).color }"
1110
1104
  />
1111
- <span class="text-[13px] text-default">{{ agentMeta(s.agentKind).label }}</span>
1112
- <span v-if="s.model" class="hidden truncate text-[11px] text-dimmed sm:inline">
1105
+ <span class="text-sm text-default">{{ agentMeta(s.agentKind).label }}</span>
1106
+ <span v-if="s.model" class="hidden truncate text-2xs text-dimmed sm:inline">
1113
1107
  {{ s.model }}
1114
1108
  </span>
1115
- <div
1116
- class="ms-auto flex items-center gap-2.5 text-[11px] tabular-nums text-muted"
1117
- >
1109
+ <div class="ms-auto flex items-center gap-2.5 text-2xs tabular-nums text-muted">
1118
1110
  <span :title="t('observability.context.injectedFiles')">{{
1119
1111
  t('observability.context.filesCount', { count: s.contextFiles.length })
1120
1112
  }}</span>
@@ -1127,60 +1119,60 @@ function exportJson() {
1127
1119
 
1128
1120
  <div v-if="expandedCtx[s.id]" class="border-t border-default px-4 py-3 space-y-3">
1129
1121
  <div>
1130
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1122
+ <SectionLabel class="mb-1">
1131
1123
  {{ t('observability.context.systemPrompt') }}
1132
- </div>
1124
+ </SectionLabel>
1133
1125
  <pre
1134
- class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
1126
+ class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
1135
1127
  >{{ s.systemPrompt || '—' }}</pre>
1136
1128
  </div>
1137
1129
  <div>
1138
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1130
+ <SectionLabel class="mb-1">
1139
1131
  {{ t('observability.context.userPrompt') }}
1140
- </div>
1132
+ </SectionLabel>
1141
1133
  <pre
1142
- class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-toned"
1134
+ class="max-h-72 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-toned"
1143
1135
  >{{ s.userPrompt || '—' }}</pre>
1144
1136
  </div>
1145
1137
  <div v-if="s.fragments.length">
1146
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1138
+ <SectionLabel class="mb-1">
1147
1139
  {{ t('observability.context.bestPracticeFragments') }}
1148
- </div>
1140
+ </SectionLabel>
1149
1141
  <div
1150
1142
  v-for="f in s.fragments"
1151
1143
  :key="f.id"
1152
1144
  class="mb-2 rounded-lg bg-app-950/70 p-3"
1153
1145
  >
1154
- <div class="mb-1 text-[11px] text-muted">{{ f.id }}</div>
1155
- <pre class="max-h-48 overflow-auto text-[11px] leading-relaxed text-toned">{{
1146
+ <div class="mb-1 text-2xs text-muted">{{ f.id }}</div>
1147
+ <pre class="max-h-48 overflow-auto text-2xs leading-relaxed text-toned">{{
1156
1148
  f.body
1157
1149
  }}</pre>
1158
1150
  </div>
1159
1151
  </div>
1160
1152
  <div v-if="s.contextFiles.length">
1161
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1153
+ <SectionLabel class="mb-1">
1162
1154
  {{ t('observability.context.injectedFiles') }}
1163
- </div>
1155
+ </SectionLabel>
1164
1156
  <div
1165
1157
  v-for="file in s.contextFiles"
1166
1158
  :key="file.path"
1167
1159
  class="mb-2 rounded-lg bg-app-950/70 p-3"
1168
1160
  >
1169
- <div class="mb-1 text-[11px] text-muted">
1161
+ <div class="mb-1 text-2xs text-muted">
1170
1162
  {{ file.title }}
1171
1163
  <span class="text-app-600">· {{ file.path }}</span>
1172
1164
  </div>
1173
- <pre class="max-h-72 overflow-auto text-[11px] leading-relaxed text-toned">{{
1165
+ <pre class="max-h-72 overflow-auto text-2xs leading-relaxed text-toned">{{
1174
1166
  file.content
1175
1167
  }}</pre>
1176
1168
  </div>
1177
1169
  </div>
1178
1170
  <div>
1179
- <div class="mb-1 text-[11px] uppercase tracking-wide text-dimmed">
1171
+ <SectionLabel class="mb-1">
1180
1172
  {{ t('observability.context.details') }}
1181
- </div>
1173
+ </SectionLabel>
1182
1174
  <pre
1183
- class="max-h-48 overflow-auto rounded-lg bg-app-950/70 p-3 text-[11px] leading-relaxed text-muted"
1175
+ class="max-h-48 overflow-auto rounded-lg bg-app-950/70 p-3 text-2xs leading-relaxed text-muted"
1184
1176
  >{{ prettyExtras(s.extras) }}</pre>
1185
1177
  </div>
1186
1178
  </div>
@@ -1192,11 +1184,11 @@ function exportJson() {
1192
1184
  <!-- Availability header: a static per-run fact (not telemetry-gated). -->
1193
1185
  <section
1194
1186
  v-if="searchAvailability"
1195
- class="flex flex-wrap items-center gap-x-3 gap-y-1 rounded-xl border border-default bg-default/50 px-4 py-3 text-[13px]"
1187
+ class="flex flex-wrap items-center gap-x-3 gap-y-1 rounded-xl border border-default bg-default/50 px-4 py-3 text-sm"
1196
1188
  >
1197
- <span class="text-[11px] uppercase tracking-wide text-dimmed">
1189
+ <SectionLabel as="span">
1198
1190
  {{ t('observability.webSearch') }}
1199
- </span>
1191
+ </SectionLabel>
1200
1192
  <span
1201
1193
  class="inline-flex items-center gap-1.5"
1202
1194
  :class="searchAvailability.available ? 'text-app-success-300' : 'text-muted'"
@@ -1232,9 +1224,9 @@ function exportJson() {
1232
1224
  </p>
1233
1225
 
1234
1226
  <div v-else>
1235
- <div class="mb-2 text-[11px] uppercase tracking-wide text-dimmed">
1227
+ <SectionLabel class="mb-2">
1236
1228
  {{ t('observability.search.queriesTitle') }}
1237
- </div>
1229
+ </SectionLabel>
1238
1230
  <ul class="space-y-2">
1239
1231
  <li
1240
1232
  v-for="q in searchQueries"
@@ -1247,12 +1239,10 @@ function exportJson() {
1247
1239
  :style="{ color: agentMeta(q.agentKind).color }"
1248
1240
  :title="agentMeta(q.agentKind).label"
1249
1241
  />
1250
- <span class="min-w-0 flex-1 truncate text-[13px] text-default" :title="q.query">
1242
+ <span class="min-w-0 flex-1 truncate text-sm text-default" :title="q.query">
1251
1243
  {{ q.query }}
1252
1244
  </span>
1253
- <div
1254
- class="flex shrink-0 items-center gap-2.5 text-[11px] tabular-nums text-muted"
1255
- >
1245
+ <div class="flex shrink-0 items-center gap-2.5 text-2xs tabular-nums text-muted">
1256
1246
  <span v-if="q.provider" class="hidden sm:inline">{{
1257
1247
  providerLabel(q.provider)
1258
1248
  }}</span>
@@ -4,6 +4,7 @@ import { onKeyStroke } from '@vueuse/core'
4
4
  import type { PlatformObservabilityWindow } from '~/types/execution'
5
5
  import { formatMs } from '~/utils/observability'
6
6
  import { FAILURE_KIND_KEYS, isAgentFailureKind } from '~/utils/failureKinds'
7
+ import SectionLabel from '~/components/common/SectionLabel.vue'
7
8
 
8
9
  // Deployment-level (platform-operator) observability dashboard: the aggregate health of the
9
10
  // active account's runs — outcome totals + success rate, a time-bucketed outcome trend, the
@@ -124,7 +125,7 @@ watch(
124
125
  <p v-if="accountName" class="truncate text-xs text-dimmed">{{ accountName }}</p>
125
126
  </div>
126
127
  <div class="ms-auto flex items-center gap-1.5">
127
- <div class="me-1 flex rounded-lg border border-default p-0.5 text-[12px]">
128
+ <div class="me-1 flex rounded-lg border border-default p-0.5 text-xs">
128
129
  <button
129
130
  v-for="opt in WINDOWS"
130
131
  :key="opt.value"
@@ -221,9 +222,9 @@ watch(
221
222
 
222
223
  <!-- Outcome summary tiles -->
223
224
  <section>
224
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
225
+ <SectionLabel as="h2" class="mb-2">
225
226
  {{ t('platformObservability.outcomes.title') }}
226
- </h2>
227
+ </SectionLabel>
227
228
  <div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
228
229
  <div class="rounded-lg border border-default bg-default/40 p-3">
229
230
  <p class="text-2xl font-semibold text-highlighted">
@@ -269,9 +270,9 @@ watch(
269
270
 
270
271
  <!-- Outcome trend sparkline -->
271
272
  <section>
272
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
273
+ <SectionLabel as="h2" class="mb-2">
273
274
  {{ t('platformObservability.trend.title') }}
274
- </h2>
275
+ </SectionLabel>
275
276
  <div class="rounded-lg border border-default bg-default/40 p-4">
276
277
  <div v-if="view.outcomes.total === 0" class="py-6 text-center text-xs text-dimmed">
277
278
  {{ t('platformObservability.trend.empty') }}
@@ -297,7 +298,7 @@ watch(
297
298
  />
298
299
  </div>
299
300
  </div>
300
- <div class="mt-2 flex items-center gap-4 text-[11px] text-dimmed">
301
+ <div class="mt-2 flex items-center gap-4 text-2xs text-dimmed">
301
302
  <span class="flex items-center gap-1"
302
303
  ><span class="h-2 w-2 rounded-sm bg-app-success-500/80" />{{
303
304
  t('platformObservability.trend.done')
@@ -319,15 +320,15 @@ watch(
319
320
 
320
321
  <!-- Gate / CI-fixer attempt statistics -->
321
322
  <section>
322
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
323
+ <SectionLabel as="h2" class="mb-2">
323
324
  {{ t('platformObservability.gates.title') }}
324
- </h2>
325
+ </SectionLabel>
325
326
  <div class="overflow-x-auto rounded-lg border border-default bg-default/40 p-4">
326
327
  <p v-if="!view.gates.length" class="py-4 text-center text-xs text-dimmed">
327
328
  {{ t('platformObservability.gates.empty') }}
328
329
  </p>
329
330
  <table v-else class="w-full text-left text-xs" data-testid="operator-gates">
330
- <thead class="text-[11px] uppercase tracking-wide text-dimmed">
331
+ <thead class="text-2xs uppercase tracking-wide text-dimmed">
331
332
  <tr>
332
333
  <th class="pb-2 pe-3 font-medium">
333
334
  {{ t('platformObservability.gates.gate') }}
@@ -382,7 +383,7 @@ watch(
382
383
  </tr>
383
384
  </tbody>
384
385
  </table>
385
- <p class="mt-3 text-[11px] leading-relaxed text-dimmed">
386
+ <p class="mt-3 text-2xs leading-relaxed text-dimmed">
386
387
  {{ t('platformObservability.gates.hint') }}
387
388
  </p>
388
389
  </div>
@@ -391,9 +392,9 @@ watch(
391
392
  <div class="grid gap-6 md:grid-cols-2">
392
393
  <!-- Failure taxonomy -->
393
394
  <section>
394
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
395
+ <SectionLabel as="h2" class="mb-2">
395
396
  {{ t('platformObservability.failures.title') }}
396
- </h2>
397
+ </SectionLabel>
397
398
  <div class="rounded-lg border border-default bg-default/40 p-4">
398
399
  <div v-if="!view.failures.length" class="py-4 text-center text-xs text-dimmed">
399
400
  {{ t('platformObservability.failures.empty') }}
@@ -418,16 +419,16 @@ watch(
418
419
  <!-- Live depth + durations -->
419
420
  <section class="flex flex-col gap-4">
420
421
  <div>
421
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
422
+ <SectionLabel as="h2" class="mb-2">
422
423
  {{ t('platformObservability.live.title') }}
423
- </h2>
424
+ </SectionLabel>
424
425
  <div
425
426
  class="grid grid-cols-4 gap-2 rounded-lg border border-default bg-default/40 p-3 text-center"
426
427
  data-testid="operator-live"
427
428
  >
428
429
  <div>
429
430
  <p class="text-lg font-semibold text-app-info-400">{{ view.live.running }}</p>
430
- <p class="text-[11px] text-dimmed">
431
+ <p class="text-2xs text-dimmed">
431
432
  {{ t('platformObservability.outcomes.running') }}
432
433
  </p>
433
434
  </div>
@@ -435,28 +436,28 @@ watch(
435
436
  <p class="text-lg font-semibold text-app-warning-400">
436
437
  {{ view.live.blocked }}
437
438
  </p>
438
- <p class="text-[11px] text-dimmed">
439
+ <p class="text-2xs text-dimmed">
439
440
  {{ t('platformObservability.outcomes.blocked') }}
440
441
  </p>
441
442
  </div>
442
443
  <div>
443
444
  <p class="text-lg font-semibold text-toned">{{ view.live.paused }}</p>
444
- <p class="text-[11px] text-dimmed">
445
+ <p class="text-2xs text-dimmed">
445
446
  {{ t('platformObservability.outcomes.paused') }}
446
447
  </p>
447
448
  </div>
448
449
  <div>
449
450
  <p class="text-lg font-semibold text-toned">{{ view.live.pending }}</p>
450
- <p class="text-[11px] text-dimmed">
451
+ <p class="text-2xs text-dimmed">
451
452
  {{ t('platformObservability.outcomes.pending') }}
452
453
  </p>
453
454
  </div>
454
455
  </div>
455
456
  </div>
456
457
  <div>
457
- <h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-dimmed">
458
+ <SectionLabel as="h2" class="mb-2">
458
459
  {{ t('platformObservability.durations.title') }}
459
- </h2>
460
+ </SectionLabel>
460
461
  <div class="rounded-lg border border-default bg-default/40 p-3 text-sm">
461
462
  <div
462
463
  v-if="view.durations.count === 0"
@@ -470,7 +471,7 @@ watch(
470
471
  data-testid="operator-durations"
471
472
  >
472
473
  <div>
473
- <dt class="text-[11px] text-dimmed">
474
+ <dt class="text-2xs text-dimmed">
474
475
  {{ t('platformObservability.durations.avg') }}
475
476
  </dt>
476
477
  <dd class="font-semibold text-highlighted">
@@ -478,7 +479,7 @@ watch(
478
479
  </dd>
479
480
  </div>
480
481
  <div>
481
- <dt class="text-[11px] text-dimmed">
482
+ <dt class="text-2xs text-dimmed">
482
483
  {{ t('platformObservability.durations.min') }}
483
484
  </dt>
484
485
  <dd class="font-semibold text-toned">
@@ -486,7 +487,7 @@ watch(
486
487
  </dd>
487
488
  </div>
488
489
  <div>
489
- <dt class="text-[11px] text-dimmed">
490
+ <dt class="text-2xs text-dimmed">
490
491
  {{ t('platformObservability.durations.max') }}
491
492
  </dt>
492
493
  <dd class="font-semibold text-toned">
@@ -494,7 +495,7 @@ watch(
494
495
  </dd>
495
496
  </div>
496
497
  <div>
497
- <dt class="text-[11px] text-dimmed">
498
+ <dt class="text-2xs text-dimmed">
498
499
  {{ t('platformObservability.durations.p50') }}
499
500
  </dt>
500
501
  <dd class="font-semibold text-toned" data-testid="operator-duration-p50">
@@ -502,7 +503,7 @@ watch(
502
503
  </dd>
503
504
  </div>
504
505
  <div>
505
- <dt class="text-[11px] text-dimmed">
506
+ <dt class="text-2xs text-dimmed">
506
507
  {{ t('platformObservability.durations.p90') }}
507
508
  </dt>
508
509
  <dd class="font-semibold text-toned" data-testid="operator-duration-p90">
@@ -510,7 +511,7 @@ watch(
510
511
  </dd>
511
512
  </div>
512
513
  <div>
513
- <dt class="text-[11px] text-dimmed">
514
+ <dt class="text-2xs text-dimmed">
514
515
  {{ t('platformObservability.durations.p99') }}
515
516
  </dt>
516
517
  <dd class="font-semibold text-toned" data-testid="operator-duration-p99">