@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
@@ -37,10 +37,10 @@ function stepLabel(key: string | undefined): string {
37
37
 
38
38
  <template>
39
39
  <div class="space-y-2" data-testid="env-setup-stepper">
40
- <p v-if="total" class="text-[11px] font-medium text-muted" data-testid="env-setup-progress">
40
+ <p v-if="total" class="text-2xs font-medium text-muted" data-testid="env-setup-progress">
41
41
  {{ t('environmentWizard.progress', { index: index + 1, total }) }}
42
42
  </p>
43
- <ol class="flex items-center gap-2 text-[11px]">
43
+ <ol class="flex items-center gap-2 text-2xs">
44
44
  <li
45
45
  v-for="(step, i) in steps"
46
46
  :key="step.entry"
@@ -48,7 +48,7 @@ function stepLabel(key: string | undefined): string {
48
48
  :data-testid="`env-setup-crumb-${step.entry}`"
49
49
  >
50
50
  <span
51
- class="flex h-5 w-5 items-center justify-center rounded-full text-[10px] font-semibold"
51
+ class="flex h-5 w-5 items-center justify-center rounded-full text-3xs font-semibold"
52
52
  :class="{
53
53
  'bg-primary text-inverted': i === index,
54
54
  'bg-app-success-600/70 text-highlighted': i < index,
@@ -9,6 +9,7 @@ import {
9
9
  readStatusNote,
10
10
  showsProviderFailure,
11
11
  } from '~/components/environments/EnvironmentStatusPanel.logic'
12
+ import SectionLabel from '~/components/common/SectionLabel.vue'
12
13
 
13
14
  const props = defineProps<{
14
15
  environment: RunEnvironment | null
@@ -106,11 +107,11 @@ const envInTransition = computed(
106
107
 
107
108
  <template>
108
109
  <section class="rounded-lg border border-default bg-default/60 p-3">
109
- <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
110
+ <SectionLabel as="h3" class="mb-2">
110
111
  {{ t('environments.title') }}
111
- </h3>
112
+ </SectionLabel>
112
113
  <div v-if="environment" class="space-y-2">
113
- <div class="flex items-center gap-2 text-[13px]">
114
+ <div class="flex items-center gap-2 text-sm">
114
115
  <UIcon
115
116
  :name="ENV_STATUS_META[environment.status].icon"
116
117
  class="h-3.5 w-3.5"
@@ -123,27 +124,28 @@ const envInTransition = computed(
123
124
  ENV_STATUS_META[environment.status].label
124
125
  }}</span>
125
126
  </div>
126
- <a
127
+ <ULink
128
+ raw
127
129
  v-if="environment.url"
128
- :href="environment.url"
130
+ :to="environment.url"
129
131
  target="_blank"
130
132
  rel="noopener"
131
- class="inline-flex items-center gap-1.5 break-all text-[13px] text-app-info-300 hover:underline"
133
+ class="inline-flex items-center gap-1.5 break-all text-sm text-app-info-300 hover:underline"
132
134
  >
133
135
  <UIcon name="i-lucide-external-link" class="h-3.5 w-3.5 shrink-0" />
134
136
  {{ environment.url }}
135
- </a>
136
- <p v-if="environment.expiresAt" class="text-[11px] text-dimmed">
137
+ </ULink>
138
+ <p v-if="environment.expiresAt" class="text-2xs text-dimmed">
137
139
  {{ t('environments.expires', { date: d(new Date(environment.expiresAt), 'long') }) }}
138
140
  </p>
139
141
  <!-- The resolved provision type + engine recorded at provision time, so a run states
140
142
  exactly what was provisioned and how (the what/where ÷ how split). -->
141
143
  <dl v-if="provisionTypeLabel || engineLabel" class="flex flex-wrap gap-x-4 gap-y-0.5">
142
- <div v-if="provisionTypeLabel" class="flex items-center gap-1 text-[11px]">
144
+ <div v-if="provisionTypeLabel" class="flex items-center gap-1 text-2xs">
143
145
  <dt class="text-dimmed">{{ t('environments.provisionTypeLabel') }}</dt>
144
146
  <dd class="text-toned">{{ provisionTypeLabel }}</dd>
145
147
  </div>
146
- <div v-if="engineLabel" class="flex items-center gap-1 text-[11px]">
148
+ <div v-if="engineLabel" class="flex items-center gap-1 text-2xs">
147
149
  <dt class="text-dimmed">{{ t('environments.engineLabel') }}</dt>
148
150
  <dd class="text-toned">{{ engineLabel }}</dd>
149
151
  </div>
@@ -151,7 +153,7 @@ const envInTransition = computed(
151
153
  <!-- The verbatim provider error when the environment failed/expired. -->
152
154
  <pre
153
155
  v-if="failureShown"
154
- class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap rounded border border-app-error-900/60 bg-app-error-950/40 p-1.5 text-[11px] text-app-error-200/90"
156
+ class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap rounded-sm border border-app-error-900/60 bg-app-error-950/40 p-1.5 text-2xs text-app-error-200/90"
155
157
  >{{ environment.lastError }}</pre>
156
158
  <!-- What the provider says it is still waiting on. Muted rather than alarming: an
157
159
  environment mid-rollout is healthy, and styling this like the error above would report
@@ -159,12 +161,12 @@ const envInTransition = computed(
159
161
  prose. -->
160
162
  <p
161
163
  v-if="statusNote"
162
- class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap break-words text-[11px] text-muted"
164
+ class="mt-1 max-h-32 overflow-auto whitespace-pre-wrap break-words text-2xs text-muted"
163
165
  >
164
166
  {{ t('environments.statusNote', { note: statusNote }) }}
165
167
  </p>
166
168
  </div>
167
- <p v-else class="text-[12px] text-dimmed">
169
+ <p v-else class="text-xs text-dimmed">
168
170
  {{ degradedReason ?? t('environments.empty') }}
169
171
  </p>
170
172
  </section>
@@ -51,21 +51,21 @@ const PREFLIGHT_COLOR: Record<'pass' | 'warn' | 'fail', 'success' | 'warning' |
51
51
 
52
52
  <p
53
53
  v-if="!store.recipe.prerequisites?.length"
54
- class="text-[12px] text-dimmed"
54
+ class="text-xs text-dimmed"
55
55
  data-testid="env-setup-preflight-none"
56
56
  >
57
57
  {{ t('environmentWizard.preflight.none') }}
58
58
  </p>
59
59
  <p
60
60
  v-else-if="preflightsUnavailable"
61
- class="text-[12px] text-app-warning-300/80"
61
+ class="text-xs text-app-warning-300/80"
62
62
  data-testid="env-setup-preflight-unavailable"
63
63
  >
64
64
  {{ t('environmentWizard.preflight.unavailable') }}
65
65
  </p>
66
66
  <p
67
67
  v-if="store.preflightError"
68
- class="text-[12px] text-app-error-300/80"
68
+ class="text-xs text-app-error-300/80"
69
69
  data-testid="env-setup-preflight-error"
70
70
  >
71
71
  {{ store.preflightError }}
@@ -79,21 +79,21 @@ const PREFLIGHT_COLOR: Record<'pass' | 'warn' | 'fail', 'success' | 'warning' |
79
79
  <li
80
80
  v-for="r in store.preflightResults"
81
81
  :key="r.title"
82
- class="rounded border border-default bg-default/40 p-2"
82
+ class="rounded-sm border border-default bg-default/40 p-2"
83
83
  >
84
84
  <div class="flex items-center gap-2">
85
85
  <UBadge :color="PREFLIGHT_COLOR[r.status]" variant="subtle" size="sm">
86
86
  {{ r.status }}
87
87
  </UBadge>
88
- <span class="text-[12px] text-default">{{ r.title }}</span>
89
- <span v-if="!r.required" class="ms-auto text-[10px] text-dimmed">
88
+ <span class="text-xs text-default">{{ r.title }}</span>
89
+ <span v-if="!r.required" class="ms-auto text-3xs text-dimmed">
90
90
  {{ t('environmentWizard.preflight.optional') }}
91
91
  </span>
92
92
  </div>
93
- <p v-if="r.detail" class="mt-1 text-[11px] text-muted">{{ r.detail }}</p>
93
+ <p v-if="r.detail" class="mt-1 text-2xs text-muted">{{ r.detail }}</p>
94
94
  <pre
95
95
  v-if="r.status !== 'pass' && r.remediation"
96
- class="mt-1 max-h-40 overflow-auto whitespace-pre-wrap rounded border border-app-warning-900/40 bg-app-warning-950/20 p-1.5 text-[11px] text-app-warning-200/90"
96
+ class="mt-1 max-h-40 overflow-auto whitespace-pre-wrap rounded-sm border border-app-warning-900/40 bg-app-warning-950/20 p-1.5 text-2xs text-app-warning-200/90"
97
97
  >{{ r.remediation }}</pre>
98
98
  </li>
99
99
  </ul>
@@ -14,6 +14,7 @@ import type {
14
14
  } from '@cat-factory/contracts'
15
15
  import JourneyStepNav from '~/components/environments/steps/JourneyStepNav.vue'
16
16
  import { useEnvironmentWizardTarget } from '~/modular/journeys/environmentSetup.frame'
17
+ import SectionLabel from '~/components/common/SectionLabel.vue'
17
18
 
18
19
  const props = defineProps<{
19
20
  input: { frameId: string | null }
@@ -114,7 +115,7 @@ const canLeaveReview = computed(
114
115
  <div class="flex items-center justify-between gap-2">
115
116
  <div class="min-w-0">
116
117
  <p class="text-sm font-medium text-default">{{ store.targetFrame?.title }}</p>
117
- <p class="text-[11px] text-dimmed">{{ t('environmentWizard.review.detectHint') }}</p>
118
+ <p class="text-2xs text-dimmed">{{ t('environmentWizard.review.detectHint') }}</p>
118
119
  </div>
119
120
  <UButton
120
121
  size="xs"
@@ -130,12 +131,12 @@ const canLeaveReview = computed(
130
131
  </UButton>
131
132
  </div>
132
133
 
133
- <p v-if="!store.hasRepo" class="text-[12px] text-app-warning-300/80">
134
+ <p v-if="!store.hasRepo" class="text-xs text-app-warning-300/80">
134
135
  {{ t('environmentWizard.review.noRepo') }}
135
136
  </p>
136
137
  <p
137
138
  v-else-if="store.detectError"
138
- class="text-[12px] text-app-error-300/80"
139
+ class="text-xs text-app-error-300/80"
139
140
  data-testid="env-setup-detect-error"
140
141
  >
141
142
  {{ t('environmentWizard.review.detectError') }}
@@ -149,7 +150,7 @@ const canLeaveReview = computed(
149
150
  >
150
151
  <p
151
152
  v-if="repoCliHint"
152
- class="mb-2 flex items-start gap-1.5 text-[11px] text-primary"
153
+ class="mb-2 flex items-start gap-1.5 text-2xs text-primary"
153
154
  data-testid="env-setup-cli-nudge"
154
155
  >
155
156
  <UIcon name="i-lucide-lightbulb" class="mt-0.5 h-3.5 w-3.5 shrink-0" />
@@ -157,10 +158,10 @@ const canLeaveReview = computed(
157
158
  </p>
158
159
  <div class="flex items-center justify-between gap-2">
159
160
  <div class="min-w-0">
160
- <p class="text-[12px] font-medium text-toned">
161
+ <p class="text-xs font-medium text-toned">
161
162
  {{ t('environmentWizard.analysis.title') }}
162
163
  </p>
163
- <p class="text-[11px] text-dimmed">{{ t('environmentWizard.analysis.hint') }}</p>
164
+ <p class="text-2xs text-dimmed">{{ t('environmentWizard.analysis.hint') }}</p>
164
165
  </div>
165
166
  <UButton
166
167
  size="xs"
@@ -177,14 +178,14 @@ const canLeaveReview = computed(
177
178
  </div>
178
179
  <p
179
180
  v-if="!store.canAnalyze"
180
- class="mt-2 text-[11px] text-dimmed"
181
+ class="mt-2 text-2xs text-dimmed"
181
182
  data-testid="env-setup-analysis-unavailable"
182
183
  >
183
184
  {{ t('environmentWizard.analysis.unavailable') }}
184
185
  </p>
185
186
  <p
186
187
  v-else-if="store.analysisStatus === 'failed'"
187
- class="mt-2 text-[11px] text-app-error-300/80"
188
+ class="mt-2 text-2xs text-app-error-300/80"
188
189
  >
189
190
  {{ t('environmentWizard.analysis.failed') }}
190
191
  </p>
@@ -193,7 +194,7 @@ const canLeaveReview = computed(
193
194
  class="mt-2 space-y-2"
194
195
  data-testid="env-setup-analysis-ready"
195
196
  >
196
- <p v-if="store.merged?.summary" class="text-[11px] leading-snug text-muted">
197
+ <p v-if="store.merged?.summary" class="text-2xs leading-snug text-muted">
197
198
  {{ store.merged.summary }}
198
199
  </p>
199
200
  <UButton
@@ -211,9 +212,9 @@ const canLeaveReview = computed(
211
212
 
212
213
  <!-- per-field provenance -->
213
214
  <div v-if="store.merged?.fields.length" class="space-y-1.5">
214
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
215
+ <SectionLabel as="p">
215
216
  {{ t('environmentWizard.review.provenanceTitle') }}
216
- </p>
217
+ </SectionLabel>
217
218
  <div class="flex flex-wrap gap-1.5">
218
219
  <UBadge
219
220
  v-for="f in store.merged.fields"
@@ -261,9 +262,9 @@ const canLeaveReview = computed(
261
262
 
262
263
  <!-- compose file layering -->
263
264
  <div v-if="composeFileCandidates.length" class="space-y-1.5">
264
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
265
+ <SectionLabel as="p">
265
266
  {{ t('environmentWizard.review.composeFiles') }}
266
- </p>
267
+ </SectionLabel>
267
268
  <div class="flex flex-wrap gap-1.5">
268
269
  <UButton
269
270
  v-for="c in composeFileCandidates"
@@ -275,16 +276,16 @@ const canLeaveReview = computed(
275
276
  :data-testid="`env-setup-file-${c.name}`"
276
277
  @click="store.toggleComposeFile(c.path)"
277
278
  >
278
- {{ c.name }}<span v-if="c.os" class="ms-1 text-[9px] opacity-70">{{ c.os }}</span>
279
+ {{ c.name }}<span v-if="c.os" class="ms-1 text-3xs opacity-70">{{ c.os }}</span>
279
280
  </UButton>
280
281
  </div>
281
282
  </div>
282
283
 
283
284
  <!-- compose profiles -->
284
285
  <div v-if="profileCandidates.length" class="space-y-1.5">
285
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
286
+ <SectionLabel as="p">
286
287
  {{ t('environmentWizard.review.profiles') }}
287
- </p>
288
+ </SectionLabel>
288
289
  <div class="flex flex-wrap gap-1.5">
289
290
  <UButton
290
291
  v-for="c in profileCandidates"
@@ -303,16 +304,16 @@ const canLeaveReview = computed(
303
304
 
304
305
  <!-- seed dumps -->
305
306
  <div v-if="seedDumpCandidates.length" class="space-y-1.5">
306
- <p class="text-[11px] font-semibold uppercase tracking-wide text-muted">
307
+ <SectionLabel as="p">
307
308
  {{ t('environmentWizard.review.seedDumps') }}
308
- </p>
309
+ </SectionLabel>
309
310
  <div class="space-y-1">
310
311
  <div
311
312
  v-for="c in seedDumpCandidates"
312
313
  :key="c.path"
313
- class="flex items-center justify-between gap-2 rounded border border-default bg-default/40 px-2 py-1"
314
+ class="flex items-center justify-between gap-2 rounded-sm border border-default bg-default/40 px-2 py-1"
314
315
  >
315
- <span class="truncate text-[11px] text-toned">{{ c.path }}</span>
316
+ <span class="truncate text-2xs text-toned">{{ c.path }}</span>
316
317
  <UButton
317
318
  size="xs"
318
319
  :color="seedAdded(c.path) ? 'success' : 'neutral'"
@@ -348,12 +349,12 @@ const canLeaveReview = computed(
348
349
  <UTextarea
349
350
  v-model="rawText"
350
351
  :rows="10"
351
- class="w-full font-mono text-[11px]"
352
+ class="w-full font-mono text-2xs"
352
353
  data-testid="env-setup-raw-text"
353
354
  />
354
355
  <p
355
356
  v-if="rawError"
356
- class="text-[11px] text-app-error-300/80"
357
+ class="text-2xs text-app-error-300/80"
357
358
  data-testid="env-setup-raw-error"
358
359
  >
359
360
  {{ rawError }}
@@ -31,7 +31,7 @@ useEnvironmentWizardTarget(() => props.input.frameId)
31
31
  <UInput v-model="store.handlerLabel" class="w-full" data-testid="env-setup-handler-label" />
32
32
  </UFormField>
33
33
 
34
- <div class="rounded-md border border-default bg-default/40 p-3 text-[12px] text-toned">
34
+ <div class="rounded-md border border-default bg-default/40 p-3 text-xs text-toned">
35
35
  <p>
36
36
  {{
37
37
  t('environmentWizard.save.summary', {
@@ -44,7 +44,7 @@ useEnvironmentWizardTarget(() => props.input.frameId)
44
44
 
45
45
  <p
46
46
  v-if="store.saveError"
47
- class="text-[12px] text-app-error-300/80"
47
+ class="text-xs text-app-error-300/80"
48
48
  data-testid="env-setup-save-error"
49
49
  >
50
50
  {{ store.saveError }}
@@ -66,7 +66,7 @@ useEnvironmentWizardTarget(() => props.input.frameId)
66
66
  <!-- saved: confirmation + optional trial provision -->
67
67
  <template v-else>
68
68
  <div
69
- class="flex items-center gap-2 rounded-md border border-app-success-800/50 bg-app-success-950/30 p-2 text-[12px] text-app-success-200"
69
+ class="flex items-center gap-2 rounded-md border border-app-success-800/50 bg-app-success-950/30 p-2 text-xs text-app-success-200"
70
70
  data-testid="env-setup-saved"
71
71
  >
72
72
  <UIcon name="i-lucide-check-circle" class="h-4 w-4" />
@@ -74,7 +74,7 @@ useEnvironmentWizardTarget(() => props.input.frameId)
74
74
  </div>
75
75
 
76
76
  <div class="flex items-center justify-between gap-2">
77
- <p class="text-[11px] text-dimmed">{{ t('environmentWizard.trial.hint') }}</p>
77
+ <p class="text-2xs text-dimmed">{{ t('environmentWizard.trial.hint') }}</p>
78
78
  <UButton
79
79
  size="xs"
80
80
  variant="soft"
@@ -88,7 +88,7 @@ useEnvironmentWizardTarget(() => props.input.frameId)
88
88
  {{ t('environmentWizard.trial.run') }}
89
89
  </UButton>
90
90
  </div>
91
- <p v-if="store.trialError" class="text-[11px] text-app-error-300/80">
91
+ <p v-if="store.trialError" class="text-2xs text-app-error-300/80">
92
92
  {{ store.trialError }}
93
93
  </p>
94
94
  <ProvisioningLogsDrawer v-if="store.trialStarted" subsystem="environment" />
@@ -6,6 +6,7 @@ import { pipelineAllowedForManualStart } from '~/utils/pipeline'
6
6
  import PipelineProgress from '~/components/pipeline/PipelineProgress.vue'
7
7
  import IconButton from '~/components/common/IconButton.vue'
8
8
  import { useInitiativePlanning } from '~/composables/useInitiativePlanning'
9
+ import SectionLabel from '~/components/common/SectionLabel.vue'
9
10
 
10
11
  const board = useBoardStore()
11
12
  const pipelines = usePipelinesStore()
@@ -203,9 +204,9 @@ function openApprovalFor(approvalId: string) {
203
204
  >
204
205
  <div class="mb-4 flex items-center gap-2">
205
206
  <UIcon name="i-lucide-workflow" class="h-4 w-4 text-dimmed" />
206
- <h2 class="text-sm font-semibold uppercase tracking-wide text-muted">
207
+ <SectionLabel as="h2">
207
208
  {{ instance ? instance.pipelineName : t('focus.noPipelineRunning') }}
208
- </h2>
209
+ </SectionLabel>
209
210
  </div>
210
211
 
211
212
  <PipelineProgress
@@ -226,30 +227,30 @@ function openApprovalFor(approvalId: string) {
226
227
  <!-- side: details -->
227
228
  <aside class="space-y-4 overflow-auto rounded-2xl border border-default bg-default/60 p-5">
228
229
  <div>
229
- <div class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted">
230
+ <SectionLabel class="mb-1">
230
231
  {{ t('focus.description') }}
231
- </div>
232
+ </SectionLabel>
232
233
  <p class="text-sm text-toned">{{ block.description }}</p>
233
234
  </div>
234
235
  <div v-if="instance">
235
- <div class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted">
236
+ <SectionLabel class="mb-1">
236
237
  {{ t('focus.overallProgress') }}
237
- </div>
238
+ </SectionLabel>
238
239
  <UProgress :model-value="Math.round(block.progress * 100)" />
239
- <div class="mt-1 text-[11px] text-muted">
240
+ <div class="mt-1 text-2xs text-muted">
240
241
  {{ n(block.progress, 'percent') }}
241
242
  </div>
242
243
  </div>
243
244
  <div>
244
- <div class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted">
245
+ <SectionLabel class="mb-1">
245
246
  {{ t('focus.dependencies') }}
246
- </div>
247
+ </SectionLabel>
247
248
  <div v-if="deps.length" class="flex flex-wrap gap-1">
248
249
  <UBadge v-for="d in deps" :key="d.id" color="neutral" variant="subtle" size="sm">
249
250
  {{ d.title }}
250
251
  </UBadge>
251
252
  </div>
252
- <div v-else class="text-[11px] text-dimmed">{{ t('focus.noDependencies') }}</div>
253
+ <div v-else class="text-2xs text-dimmed">{{ t('focus.noDependencies') }}</div>
253
254
  </div>
254
255
  </aside>
255
256
  </div>
@@ -162,7 +162,7 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
162
162
  >
163
163
  <UIcon :name="FOLLOW_UP_COMPANION_META.icon" class="h-8 w-8 opacity-40" />
164
164
  <p class="text-sm">{{ t('followUp.empty.title') }}</p>
165
- <p class="max-w-sm text-[11px] text-dimmed">
165
+ <p class="max-w-sm text-2xs text-dimmed">
166
166
  {{ t('followUp.empty.hint') }}
167
167
  </p>
168
168
  </div>
@@ -170,7 +170,7 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
170
170
  <div v-else class="space-y-3">
171
171
  <p
172
172
  v-if="followUps.error"
173
- class="rounded-md bg-app-error-500/10 px-3 py-2 text-[12px] text-app-error-300"
173
+ class="rounded-md bg-app-error-500/10 px-3 py-2 text-xs text-app-error-300"
174
174
  >
175
175
  {{ followUps.error }}
176
176
  </p>
@@ -189,31 +189,32 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
189
189
  />
190
190
  <div class="min-w-0 flex-1">
191
191
  <div class="flex items-center gap-2">
192
- <h3 class="min-w-0 flex-1 truncate text-[13px] font-medium text-app-100">
192
+ <h3 class="min-w-0 flex-1 truncate text-sm font-medium text-app-100">
193
193
  {{ item.title }}
194
194
  </h3>
195
195
  <UBadge :color="STATUS_META[item.status].badge" variant="subtle" size="sm">
196
196
  {{ t(STATUS_LABEL_KEYS[item.status]) }}
197
197
  </UBadge>
198
198
  </div>
199
- <p v-if="item.detail" class="mt-1 whitespace-pre-wrap text-[12px] text-toned">
199
+ <p v-if="item.detail" class="mt-1 whitespace-pre-wrap text-xs text-toned">
200
200
  {{ item.detail }}
201
201
  </p>
202
- <p v-if="item.suggestedAction" class="mt-1 text-[11px] text-muted">
202
+ <p v-if="item.suggestedAction" class="mt-1 text-2xs text-muted">
203
203
  <span class="text-dimmed">{{ t('followUp.suggested') }}</span>
204
204
  {{ item.suggestedAction }}
205
205
  </p>
206
- <p v-if="item.status === 'filed' && item.ticketUrl" class="mt-1 text-[11px]">
207
- <a
208
- :href="item.ticketUrl"
206
+ <p v-if="item.status === 'filed' && item.ticketUrl" class="mt-1 text-2xs">
207
+ <ULink
208
+ raw
209
+ :to="item.ticketUrl"
209
210
  target="_blank"
210
211
  rel="noopener"
211
212
  class="text-app-success-300 hover:underline"
212
213
  >
213
214
  {{ item.ticketExternalId ?? t('followUp.viewIssue') }}
214
- </a>
215
+ </ULink>
215
216
  </p>
216
- <p v-if="hasRecordedAnswer(item)" class="mt-1 text-[11px] text-toned">
217
+ <p v-if="hasRecordedAnswer(item)" class="mt-1 text-2xs text-toned">
217
218
  <span class="text-dimmed">
218
219
  {{
219
220
  item.status === 'closed' ? t('followUp.yourRuling') : t('followUp.yourAnswer')
@@ -223,7 +224,7 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
223
224
  </p>
224
225
  <!-- A decision that was made and then thrown away when the budget ran out. It must
225
226
  not read like one the Coder acted on. -->
226
- <p v-if="item.sendBackDropped" class="mt-1 text-[11px] text-app-warning-300">
227
+ <p v-if="item.sendBackDropped" class="mt-1 text-2xs text-app-warning-300">
227
228
  {{ t('followUp.sendBackDropped') }}
228
229
  </p>
229
230
 
@@ -231,11 +232,13 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
231
232
  <div v-if="item.status === 'pending'" class="mt-2.5">
232
233
  <!-- A question: answer it -->
233
234
  <div v-if="item.kind === 'question'" class="space-y-2">
234
- <textarea
235
+ <UTextarea
235
236
  v-model="drafts[item.id]"
236
- rows="2"
237
+ :rows="2"
237
238
  :placeholder="t('followUp.answerPlaceholder')"
238
- class="w-full resize-y rounded-md border border-muted bg-app-950/60 px-2.5 py-1.5 text-[12px] text-app-100 placeholder:text-app-600 focus:border-app-info-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-app-info-500/60"
239
+ size="xs"
240
+ class="w-full"
241
+ :ui="{ base: 'resize-y' }"
239
242
  />
240
243
  <!-- Wraps, like the follow-up row below: three buttons whose labels are two
241
244
  words each in English are one long line in most of the other locales, and
@@ -323,7 +326,7 @@ function hasRecordedAnswer(item: FollowUpItem): boolean {
323
326
  </div>
324
327
 
325
328
  <footer
326
- class="flex items-center justify-between border-t border-default px-5 py-2.5 text-[11px] text-muted"
329
+ class="flex items-center justify-between border-t border-default px-5 py-2.5 text-2xs text-muted"
327
330
  >
328
331
  <span>
329
332
  {{