@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
@@ -13,6 +13,7 @@
13
13
  // request-changes rail has to live here or the gate has no resolving surface at all —
14
14
  // which is exactly how an approved-only-over-REST plan gate shipped.
15
15
  import { computed, reactive, ref } from 'vue'
16
+ import type { TableColumn } from '@nuxt/ui'
16
17
  import type { InitiativeFollowUp, InitiativeItem } from '~/types/domain'
17
18
  import { useInitiativePlanning } from '~/composables/useInitiativePlanning'
18
19
  import {
@@ -29,6 +30,7 @@ import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
29
30
  import StepRunMeta from '~/components/panels/StepRunMeta.vue'
30
31
  import InitiativePlanReview from '~/components/initiative/InitiativePlanReview.vue'
31
32
  import InitiativePlanNotice from '~/components/initiative/InitiativePlanNotice.vue'
33
+ import SectionLabel from '~/components/common/SectionLabel.vue'
32
34
 
33
35
  const board = useBoardStore()
34
36
  const initiatives = useInitiativesStore()
@@ -86,6 +88,16 @@ function itemsOf(phaseId: string): InitiativeItem[] {
86
88
  return (initiative.value?.items ?? []).filter((i) => i.phaseId === phaseId)
87
89
  }
88
90
 
91
+ // One column set for every phase's table, so the header typography is the table theme's rather
92
+ // than a per-file recipe.
93
+ const phaseItems = computed(() => phases.value.map((p) => ({ label: p.title, value: p.id })))
94
+
95
+ const itemColumns = computed<TableColumn<InitiativeItem>[]>(() => [
96
+ { id: 'item', header: t('initiative.tracker.colItem') },
97
+ { id: 'status', header: t('initiative.tracker.colStatus') },
98
+ { id: 'pr', header: t('initiative.tracker.colPr') },
99
+ ])
100
+
89
101
  const progress = computed(() => initiativeProgress(initiative.value?.items))
90
102
  const progressPct = computed(() =>
91
103
  progress.value && progress.value.total > 0
@@ -313,7 +325,7 @@ const { requestClose } = useUnsavedGuard({
313
325
  :style="{ width: `${progressPct}%` }"
314
326
  />
315
327
  </div>
316
- <span class="text-[11px] tabular-nums text-muted">
328
+ <span class="text-2xs tabular-nums text-muted">
317
329
  {{ t('initiative.card.progress', { done: progress.settled, total: progress.total }) }}
318
330
  </span>
319
331
  </div>
@@ -385,29 +397,33 @@ const { requestClose } = useUnsavedGuard({
385
397
  class="mt-0.5 h-4 w-4 shrink-0 text-app-warning-300"
386
398
  />
387
399
  <div class="min-w-0 flex-1">
388
- <h3 class="text-[13px] font-semibold text-app-warning-200">
400
+ <h3 class="text-sm font-semibold text-app-warning-200">
389
401
  {{ t('initiative.checkpoint.pausedTitle') }}
390
402
  </h3>
391
- <p class="mt-0.5 text-[12px] leading-relaxed text-app-warning-100/80">
403
+ <p class="mt-0.5 text-xs leading-relaxed text-app-warning-100/80">
392
404
  {{ t('initiative.checkpoint.pausedBody', { phase: checkpointPhase!.title }) }}
393
405
  </p>
394
406
  <div class="mt-2.5 flex flex-wrap gap-2">
395
- <button
396
- class="rounded bg-primary/90 px-2.5 py-1 text-[11px] font-medium text-inverted hover:bg-primary disabled:opacity-50"
407
+ <UButton
408
+ color="neutral"
409
+ variant="ghost"
410
+ class="rounded-sm bg-primary/90 px-2.5 py-1 text-2xs font-medium text-inverted hover:bg-primary disabled:opacity-50"
397
411
  :disabled="initiatives.controlling"
398
412
  data-testid="initiative-checkpoint-resume"
399
413
  @click="checkpointControl('resume')"
400
414
  >
401
415
  {{ t('initiative.inspector.resume') }}
402
- </button>
403
- <button
404
- class="rounded border border-app-error-500/50 px-2.5 py-1 text-[11px] font-medium text-app-error-300 hover:bg-app-error-500/10 disabled:opacity-50"
416
+ </UButton>
417
+ <UButton
418
+ color="neutral"
419
+ variant="ghost"
420
+ class="rounded-sm border border-app-error-500/50 px-2.5 py-1 text-2xs font-medium text-app-error-300 hover:bg-app-error-500/10 disabled:opacity-50"
405
421
  :disabled="initiatives.controlling"
406
422
  data-testid="initiative-checkpoint-cancel"
407
423
  @click="checkpointControl('cancel')"
408
424
  >
409
425
  {{ t('initiative.inspector.cancel') }}
410
- </button>
426
+ </UButton>
411
427
  </div>
412
428
  </div>
413
429
  </div>
@@ -418,34 +434,34 @@ const { requestClose } = useUnsavedGuard({
418
434
  structure that reads better at the full span, but these are paragraphs and bullets
419
435
  of agent-written text that would otherwise run the width of the display. -->
420
436
  <section v-if="initiative.goal" class="mb-4">
421
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
437
+ <SectionLabel as="h3" class="mb-1">
422
438
  {{ t('initiative.tracker.goal') }}
423
- </h3>
424
- <p class="max-w-3xl whitespace-pre-wrap text-[13px] leading-relaxed text-toned">
439
+ </SectionLabel>
440
+ <p class="max-w-3xl whitespace-pre-wrap text-sm leading-relaxed text-toned">
425
441
  {{ initiative.goal }}
426
442
  </p>
427
443
  </section>
428
444
  <section v-if="initiative.constraints?.length" class="mb-4">
429
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
445
+ <SectionLabel as="h3" class="mb-1">
430
446
  {{ t('initiative.tracker.constraints') }}
431
- </h3>
432
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
447
+ </SectionLabel>
448
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
433
449
  <li v-for="(c, i) in initiative.constraints" :key="i">{{ c }}</li>
434
450
  </ul>
435
451
  </section>
436
452
  <section v-if="initiative.nonGoals?.length" class="mb-4">
437
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
453
+ <SectionLabel as="h3" class="mb-1">
438
454
  {{ t('initiative.tracker.nonGoals') }}
439
- </h3>
440
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
455
+ </SectionLabel>
456
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
441
457
  <li v-for="(g, i) in initiative.nonGoals" :key="i">{{ g }}</li>
442
458
  </ul>
443
459
  </section>
444
460
  <section v-if="initiative.analysisSummary" class="mb-4">
445
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
461
+ <SectionLabel as="h3" class="mb-1">
446
462
  {{ t('initiative.tracker.analysis') }}
447
- </h3>
448
- <p class="max-w-3xl whitespace-pre-wrap text-[13px] leading-relaxed text-toned">
463
+ </SectionLabel>
464
+ <p class="max-w-3xl whitespace-pre-wrap text-sm leading-relaxed text-toned">
449
465
  {{ initiative.analysisSummary }}
450
466
  </p>
451
467
  </section>
@@ -453,7 +469,7 @@ const { requestClose } = useUnsavedGuard({
453
469
  <!-- Awaiting planning -->
454
470
  <div
455
471
  v-if="phases.length === 0"
456
- class="mb-4 rounded-lg border border-dashed border-muted p-4 text-center text-[12px] text-muted"
472
+ class="mb-4 rounded-lg border border-dashed border-muted p-4 text-center text-xs text-muted"
457
473
  >
458
474
  {{ t('initiative.tracker.noPlan') }}
459
475
  </div>
@@ -488,103 +504,112 @@ const { requestClose } = useUnsavedGuard({
488
504
  }}
489
505
  </UBadge>
490
506
  </h3>
491
- <p v-if="phase.goal" class="mb-2 text-[12px] text-muted">{{ phase.goal }}</p>
492
- <div class="overflow-x-auto rounded-lg border border-default">
493
- <table class="w-full text-[12px]">
494
- <thead>
495
- <tr class="border-b border-default text-left text-dimmed">
496
- <th class="px-3 py-2 font-medium">{{ t('initiative.tracker.colItem') }}</th>
497
- <th class="px-3 py-2 font-medium">{{ t('initiative.tracker.colStatus') }}</th>
498
- <th class="px-3 py-2 font-medium">{{ t('initiative.tracker.colPr') }}</th>
499
- </tr>
500
- </thead>
501
- <tbody>
502
- <tr
503
- v-for="item in itemsOf(phase.id)"
504
- :key="item.id"
505
- class="border-b border-default/60 last:border-0"
506
- >
507
- <td class="px-3 py-2 align-top">
508
- <div class="font-medium text-default">{{ item.title }}</div>
509
- <div v-if="item.dependsOn?.length" class="mt-0.5 text-[10px] text-dimmed">
510
- {{
511
- t('initiative.tracker.dependsOn', {
512
- items: item.dependsOn.join(', '),
513
- })
514
- }}
515
- </div>
516
- <div
517
- v-if="item.note"
518
- class="mt-0.5 max-w-3xl text-[10px] text-app-warning-300/80"
519
- >
520
- {{ item.note }}
521
- </div>
522
- <div
523
- v-if="editable && (item.status === 'blocked' || item.status === 'pending')"
524
- class="mt-1 flex gap-1.5"
525
- >
526
- <button
527
- v-if="item.status === 'blocked'"
528
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
529
- :disabled="initiatives.curating"
530
- :data-testid="`initiative-item-retry-${item.id}`"
531
- @click="itemAction(item, 'retry')"
532
- >
533
- {{ t('initiative.curation.retry') }}
534
- </button>
535
- <button
536
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
537
- :disabled="initiatives.curating"
538
- :data-testid="`initiative-item-skip-${item.id}`"
539
- @click="itemAction(item, 'skip')"
540
- >
541
- {{ t('initiative.curation.skip') }}
542
- </button>
543
- </div>
544
- </td>
545
- <td class="px-3 py-2 align-top">
546
- <UBadge
547
- :color="INITIATIVE_ITEM_STATUS_CHIPS[item.status]"
548
- variant="subtle"
549
- size="sm"
550
- >
551
- {{ t(INITIATIVE_ITEM_STATUS_LABEL_KEYS[item.status]) }}
552
- </UBadge>
553
- </td>
554
- <td class="px-3 py-2 align-top">
555
- <a
556
- v-if="item.pr"
557
- :href="item.pr.url"
558
- target="_blank"
559
- rel="noopener"
560
- class="text-app-info-400 hover:underline"
561
- >
562
- {{ item.pr.number ? `#${item.pr.number}` : t('initiative.tracker.prLink') }}
563
- </a>
564
- <span v-else class="text-app-600">—</span>
565
- </td>
566
- </tr>
567
- </tbody>
568
- </table>
569
- </div>
507
+ <p v-if="phase.goal" class="mb-2 text-xs text-muted">{{ phase.goal }}</p>
508
+ <UTable
509
+ :data="itemsOf(phase.id)"
510
+ :columns="itemColumns"
511
+ :ui="{
512
+ root: 'overflow-x-auto rounded-lg border border-default',
513
+ base: 'text-xs',
514
+ th: 'px-3 py-2',
515
+ td: 'px-3 py-2 text-xs whitespace-normal',
516
+ empty: 'py-0',
517
+ tr: 'align-top',
518
+ }"
519
+ >
520
+ <template #item-cell="{ row }">
521
+ <div class="font-medium text-default">{{ row.original.title }}</div>
522
+ <div v-if="row.original.dependsOn?.length" class="mt-0.5 text-3xs text-dimmed">
523
+ {{
524
+ t('initiative.tracker.dependsOn', {
525
+ items: row.original.dependsOn.join(', '),
526
+ })
527
+ }}
528
+ </div>
529
+ <div
530
+ v-if="row.original.note"
531
+ class="mt-0.5 max-w-3xl text-3xs text-app-warning-300/80"
532
+ >
533
+ {{ row.original.note }}
534
+ </div>
535
+ <div
536
+ v-if="
537
+ editable &&
538
+ (row.original.status === 'blocked' || row.original.status === 'pending')
539
+ "
540
+ class="mt-1 flex gap-1.5"
541
+ >
542
+ <UButton
543
+ v-if="row.original.status === 'blocked'"
544
+ color="neutral"
545
+ variant="outline"
546
+ size="xs"
547
+ :label="t('initiative.curation.retry')"
548
+ :disabled="initiatives.curating"
549
+ :data-testid="`initiative-item-retry-${row.original.id}`"
550
+ @click="itemAction(row.original, 'retry')"
551
+ />
552
+ <UButton
553
+ color="neutral"
554
+ variant="outline"
555
+ size="xs"
556
+ :label="t('initiative.curation.skip')"
557
+ :disabled="initiatives.curating"
558
+ :data-testid="`initiative-item-skip-${row.original.id}`"
559
+ @click="itemAction(row.original, 'skip')"
560
+ />
561
+ </div>
562
+ </template>
563
+ <template #status-cell="{ row }">
564
+ <UBadge
565
+ :color="INITIATIVE_ITEM_STATUS_CHIPS[row.original.status]"
566
+ variant="subtle"
567
+ size="sm"
568
+ >
569
+ {{ t(INITIATIVE_ITEM_STATUS_LABEL_KEYS[row.original.status]) }}
570
+ </UBadge>
571
+ </template>
572
+ <template #pr-cell="{ row }">
573
+ <ULink
574
+ raw
575
+ v-if="row.original.pr"
576
+ :to="row.original.pr.url"
577
+ target="_blank"
578
+ rel="noopener"
579
+ class="text-app-info-400 hover:underline"
580
+ >
581
+ {{
582
+ row.original.pr.number
583
+ ? `#${row.original.pr.number}`
584
+ : t('initiative.tracker.prLink')
585
+ }}
586
+ </ULink>
587
+ <span v-else class="text-app-600">&mdash;</span>
588
+ </template>
589
+ <!-- The hand-built table rendered its header and no row; Nuxt UI's fallback is
590
+ an untranslated "No data.", so the slot states the same nothing. -->
591
+ <template #empty />
592
+ </UTable>
570
593
  </section>
571
594
 
572
595
  <!-- Execution policy -->
573
596
  <section v-if="initiative.policy" class="mb-4">
574
597
  <div class="mb-1 flex items-center gap-2">
575
- <h3 class="text-[11px] font-semibold uppercase tracking-wide text-dimmed">
598
+ <SectionLabel as="h3">
576
599
  {{ t('initiative.tracker.policy') }}
577
- </h3>
578
- <button
600
+ </SectionLabel>
601
+ <UButton
602
+ color="neutral"
603
+ variant="ghost"
579
604
  v-if="editable && !editingPolicy"
580
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated"
605
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated"
581
606
  data-testid="initiative-policy-edit"
582
607
  @click="startEditPolicy"
583
608
  >
584
609
  {{ t('initiative.curation.edit') }}
585
- </button>
610
+ </UButton>
586
611
  </div>
587
- <ul v-if="!editingPolicy" class="text-[12px] text-toned">
612
+ <ul v-if="!editingPolicy" class="text-xs text-toned">
588
613
  <li>
589
614
  {{
590
615
  t('initiative.tracker.maxConcurrent', {
@@ -603,51 +628,66 @@ const { requestClose } = useUnsavedGuard({
603
628
  </ul>
604
629
  <!-- Edit form: the two scalar knobs; planner-authored rules are preserved. -->
605
630
  <div v-else class="flex flex-col gap-2 rounded-lg border border-default p-3">
606
- <label class="flex items-center gap-2 text-[12px] text-toned">
607
- <span class="w-40">{{ t('initiative.curation.maxConcurrentField') }}</span>
608
- <input
609
- v-model.number="policyForm.maxConcurrent"
610
- type="number"
611
- min="1"
612
- max="20"
613
- class="w-20 rounded border border-muted bg-app-950 px-2 py-1 text-default"
631
+ <UFormField
632
+ size="xs"
633
+ :label="t('initiative.curation.maxConcurrentField')"
634
+ :ui="{ root: 'flex items-center gap-2', label: 'w-40', container: 'mt-0' }"
635
+ >
636
+ <UInputNumber
637
+ v-model.optional="policyForm.maxConcurrent"
638
+ :min="1"
639
+ :max="20"
640
+ size="xs"
641
+ class="w-28"
614
642
  data-testid="initiative-policy-max-concurrent"
615
643
  />
616
- </label>
617
- <label class="flex items-center gap-2 text-[12px] text-toned">
618
- <span class="w-40">{{ t('initiative.curation.defaultPipelineField') }}</span>
619
- <input
644
+ </UFormField>
645
+ <UFormField
646
+ size="xs"
647
+ :label="t('initiative.curation.defaultPipelineField')"
648
+ :ui="{
649
+ root: 'flex items-center gap-2',
650
+ label: 'w-40',
651
+ container: 'flex-1 mt-0',
652
+ }"
653
+ >
654
+ <UInput
620
655
  v-model="policyForm.defaultPipelineId"
621
- type="text"
622
- class="flex-1 rounded border border-muted bg-app-950 px-2 py-1 font-mono text-[11px] text-default"
656
+ size="xs"
657
+ class="w-full"
658
+ :ui="{ base: 'font-mono' }"
623
659
  data-testid="initiative-policy-default-pipeline"
624
660
  />
625
- </label>
661
+ </UFormField>
626
662
  <div class="flex gap-2">
627
- <button
628
- class="rounded bg-primary/90 px-2 py-1 text-[11px] text-inverted hover:bg-primary disabled:opacity-50"
663
+ <UButton
664
+ color="neutral"
665
+ variant="ghost"
666
+ class="rounded-sm bg-primary/90 px-2 py-1 text-2xs text-inverted hover:bg-primary disabled:opacity-50"
629
667
  :disabled="initiatives.curating"
630
668
  data-testid="initiative-policy-save"
631
669
  @click="savePolicy"
632
670
  >
633
671
  {{ t('initiative.curation.save') }}
634
- </button>
635
- <button
636
- class="rounded border border-muted px-2 py-1 text-[11px] text-toned hover:bg-elevated"
672
+ </UButton>
673
+ <UButton
674
+ color="neutral"
675
+ variant="ghost"
676
+ class="rounded-sm border border-muted px-2 py-1 text-2xs text-toned hover:bg-elevated"
637
677
  @click="editingPolicy = false"
638
678
  >
639
679
  {{ t('initiative.curation.cancel') }}
640
- </button>
680
+ </UButton>
641
681
  </div>
642
682
  </div>
643
683
  </section>
644
684
 
645
685
  <!-- Logs -->
646
686
  <section v-if="initiative.decisions?.length" class="mb-4">
647
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
687
+ <SectionLabel as="h3" class="mb-1">
648
688
  {{ t('initiative.tracker.decisions') }}
649
- </h3>
650
- <ul class="list-inside list-disc text-[13px] text-toned">
689
+ </SectionLabel>
690
+ <ul class="list-inside list-disc text-sm text-toned">
651
691
  <li v-for="d in initiative.decisions" :key="d.id">
652
692
  <span class="font-medium">{{ d.title }}</span>
653
693
  <span v-if="d.detail" class="text-muted"> — {{ d.detail }}</span>
@@ -655,10 +695,10 @@ const { requestClose } = useUnsavedGuard({
655
695
  </ul>
656
696
  </section>
657
697
  <section v-if="initiative.deviations?.length" class="mb-4">
658
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
698
+ <SectionLabel as="h3" class="mb-1">
659
699
  {{ t('initiative.tracker.deviations') }}
660
- </h3>
661
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
700
+ </SectionLabel>
701
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
662
702
  <li v-for="d in initiative.deviations" :key="d.id">
663
703
  <code v-if="d.itemId" class="text-muted">{{ d.itemId }}</code>
664
704
  {{ d.description }}
@@ -667,10 +707,10 @@ const { requestClose } = useUnsavedGuard({
667
707
  </ul>
668
708
  </section>
669
709
  <section v-if="initiative.followUps?.length" class="mb-4">
670
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
710
+ <SectionLabel as="h3" class="mb-1">
671
711
  {{ t('initiative.tracker.followUps') }}
672
- </h3>
673
- <ul class="flex flex-col gap-2 text-[13px] text-toned">
712
+ </SectionLabel>
713
+ <ul class="flex flex-col gap-2 text-sm text-toned">
674
714
  <li
675
715
  v-for="f in initiative.followUps"
676
716
  :key="f.id"
@@ -693,68 +733,76 @@ const { requestClose } = useUnsavedGuard({
693
733
  <!-- Triage actions for an open follow-up (only while executing) -->
694
734
  <div v-if="editable && f.status === 'open'" class="mt-2">
695
735
  <div v-if="promotingId === f.id" class="flex flex-col gap-2">
696
- <label class="flex items-center gap-2 text-[12px]">
697
- <span class="text-muted">{{ t('initiative.curation.phaseField') }}</span>
698
- <select
736
+ <UFormField
737
+ size="xs"
738
+ :label="t('initiative.curation.phaseField')"
739
+ :ui="{ root: 'flex items-center gap-2', container: 'flex-1 mt-0' }"
740
+ >
741
+ <USelect
699
742
  v-model="promoteForm.phaseId"
700
- class="flex-1 rounded border border-muted bg-app-950 px-2 py-1 text-default"
743
+ :items="phaseItems"
744
+ size="xs"
745
+ class="w-full"
701
746
  data-testid="initiative-promote-phase"
702
- >
703
- <option v-for="p in phases" :key="p.id" :value="p.id">
704
- {{ p.title }}
705
- </option>
706
- </select>
707
- </label>
708
- <input
747
+ />
748
+ </UFormField>
749
+ <UInput
709
750
  v-model="promoteForm.title"
710
- type="text"
711
- class="rounded border border-muted bg-app-950 px-2 py-1 text-[12px] text-default"
751
+ size="xs"
712
752
  :placeholder="t('initiative.curation.itemTitlePlaceholder')"
713
753
  data-testid="initiative-promote-title"
714
754
  />
715
755
  <div class="flex gap-2">
716
- <button
717
- class="rounded bg-primary/90 px-2 py-1 text-[11px] text-inverted hover:bg-primary disabled:opacity-50"
756
+ <UButton
757
+ color="neutral"
758
+ variant="ghost"
759
+ class="rounded-sm bg-primary/90 px-2 py-1 text-2xs text-inverted hover:bg-primary disabled:opacity-50"
718
760
  :disabled="initiatives.curating || !promoteForm.phaseId"
719
761
  data-testid="initiative-promote-submit"
720
762
  @click="submitPromote(f)"
721
763
  >
722
764
  {{ t('initiative.curation.promoteConfirm') }}
723
- </button>
724
- <button
725
- class="rounded border border-muted px-2 py-1 text-[11px] text-toned hover:bg-elevated"
765
+ </UButton>
766
+ <UButton
767
+ color="neutral"
768
+ variant="ghost"
769
+ class="rounded-sm border border-muted px-2 py-1 text-2xs text-toned hover:bg-elevated"
726
770
  @click="promotingId = null"
727
771
  >
728
772
  {{ t('initiative.curation.cancel') }}
729
- </button>
773
+ </UButton>
730
774
  </div>
731
775
  </div>
732
776
  <div v-else class="flex gap-1.5">
733
- <button
734
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated"
777
+ <UButton
778
+ color="neutral"
779
+ variant="ghost"
780
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated"
735
781
  data-testid="initiative-followup-promote"
736
782
  @click="startPromote(f)"
737
783
  >
738
784
  {{ t('initiative.curation.promote') }}
739
- </button>
740
- <button
741
- class="rounded border border-muted px-1.5 py-0.5 text-[10px] text-toned hover:bg-elevated disabled:opacity-50"
785
+ </UButton>
786
+ <UButton
787
+ color="neutral"
788
+ variant="ghost"
789
+ class="rounded-sm border border-muted px-1.5 py-0.5 text-3xs text-toned hover:bg-elevated disabled:opacity-50"
742
790
  :disabled="initiatives.curating"
743
791
  data-testid="initiative-followup-dismiss"
744
792
  @click="dismissFollowUp(f)"
745
793
  >
746
794
  {{ t('initiative.curation.dismiss') }}
747
- </button>
795
+ </UButton>
748
796
  </div>
749
797
  </div>
750
798
  </li>
751
799
  </ul>
752
800
  </section>
753
801
  <section v-if="initiative.caveats?.length" class="mb-4">
754
- <h3 class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-dimmed">
802
+ <SectionLabel as="h3" class="mb-1">
755
803
  {{ t('initiative.tracker.caveats') }}
756
- </h3>
757
- <ul class="max-w-3xl list-inside list-disc text-[13px] text-toned">
804
+ </SectionLabel>
805
+ <ul class="max-w-3xl list-inside list-disc text-sm text-toned">
758
806
  <li v-for="(c, i) in initiative.caveats" :key="i">{{ c }}</li>
759
807
  </ul>
760
808
  </section>