@cat-factory/app 0.142.0 → 0.143.1

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.
@@ -1,8 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  // Create a new task on the board. The user names the task and writes its
3
- // description themselves there are no auto-generated placeholder titles. The
4
- // task lands in `planned` state; it is never launched here. The user starts a
5
- // pipeline on it explicitly (and can keep editing it until they do).
3
+ // description themselves (a REVIEW task is the one exception — it shows neither Title
4
+ // nor Description: the target PR IS the subject, so the title is derived from the PR
5
+ // reference and any notes go in the dedicated "Review focus" field). The task lands in
6
+ // `planned` state; it is never launched here. The user starts a pipeline on it
7
+ // explicitly (and can keep editing it until they do).
6
8
  //
7
9
  // The form also shows ungated "Context documents" / "Context issues" sections
8
10
  // (mirroring the task inspector): an inline search picker (ContextDocumentPicker /
@@ -19,10 +21,12 @@ import type {
19
21
  TaskTypeFields,
20
22
  } from '~/types/domain'
21
23
  import { DOC_KINDS, DOC_KIND_FIELDS } from '~/types/domain'
24
+ import type { DropdownMenuItem } from '@nuxt/ui'
22
25
  import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.vue'
23
26
  import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
24
27
  import { riskPolicyOptionLabel, riskPolicySummary } from '~/utils/riskPolicy'
25
28
  import { pipelineAllowedForManualStart } from '~/utils/pipeline'
29
+ import { buildFragmentPickerGroups } from '~/utils/fragmentPicker'
26
30
 
27
31
  const ui = useUiStore()
28
32
  const board = useBoardStore()
@@ -32,6 +36,8 @@ const riskPolicies = useRiskPoliciesStore()
32
36
  const modelPresets = useModelPresetsStore()
33
37
  const pipelines = usePipelinesStore()
34
38
  const agentConfig = useAgentConfigStore()
39
+ const fragments = useFragmentsStore()
40
+ const accounts = useAccountsStore()
35
41
  const toast = useToast()
36
42
  const { t } = useI18n()
37
43
 
@@ -121,6 +127,12 @@ const docOutlineHints = ref('')
121
127
  const reviewPrRef = ref('')
122
128
  const reviewFocus = ref('')
123
129
 
130
+ // Best-practice prompt fragments the user pins on the task up front (folded into its agents
131
+ // on top of the service-level standards, exactly like the inspector's picker). Chosen from the
132
+ // resolved catalog, filtered to the enclosing frame's block type ("appropriate scope").
133
+ const fragmentIds = ref<string[]>([])
134
+ const isReview = computed(() => taskType.value === 'review')
135
+
124
136
  // Parse the PR-reference input into the contract fields: a bare positive integer (optionally
125
137
  // `#`-prefixed) becomes `prNumber` (a PR on the service's linked repo); anything else is taken
126
138
  // as a full URL (`prUrl`). Returns undefined when blank or unparseable — the caller uses that
@@ -135,6 +147,21 @@ function parseReviewPrRef(raw: string): Pick<TaskTypeFields, 'prUrl' | 'prNumber
135
147
  }
136
148
  return { prUrl: trimmed }
137
149
  }
150
+
151
+ // A review task doesn't require a title (the PR reference IS the subject), so when the user
152
+ // leaves it blank we derive a concise one from the parsed PR ref — `owner/repo#123` from a
153
+ // GitHub-style URL, else `#number`, else a bare label — so the board card still reads sensibly.
154
+ function deriveReviewTitle(raw: string): string {
155
+ const parsed = parseReviewPrRef(raw)
156
+ if (parsed?.prNumber)
157
+ return t('board.addTask.review.derivedTitle', { ref: `#${parsed.prNumber}` })
158
+ if (parsed?.prUrl) {
159
+ const m = /github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/.exec(parsed.prUrl)
160
+ const refLabel = m ? `${m[1]}/${m[2]}#${m[3]}` : parsed.prUrl
161
+ return t('board.addTask.review.derivedTitle', { ref: refLabel })
162
+ }
163
+ return t('board.addTask.review.derivedTitleFallback')
164
+ }
138
165
  // Per-kind specific fields (see DOC_KIND_FIELDS). Held in one keyed record; only the fields
139
166
  // for the selected kind are shown and submitted, so a value from a previously-selected kind is
140
167
  // never sent. The catalog keys below keep the labels/placeholders i18n and drift-guarded.
@@ -286,6 +313,52 @@ const selectedModelPresetLabel = computed(() => {
286
313
  )
287
314
  })
288
315
 
316
+ // ---- best-practice prompt fragments (pinned at creation) -------------------
317
+ // The fragments already chosen, resolved against the catalog. An id the catalog no longer
318
+ // resolves still renders (labelled by its raw id) so it stays visible and removable — mirrors
319
+ // the inspector's TaskStructure picker.
320
+ const selectedFragments = computed(() =>
321
+ fragmentIds.value.map((id) => fragments.getFragment(id) ?? { id, title: id, summary: '' }),
322
+ )
323
+ // A trailing group linking out to the fragment library (board tier always; account tier when
324
+ // enabled) — managing fragments is open to every member, exactly like the inspector picker.
325
+ const fragmentManageItems = computed<DropdownMenuItem[]>(() => {
326
+ const items: DropdownMenuItem[] = [
327
+ {
328
+ label: t('inspector.fragments.manageBoard'),
329
+ icon: 'i-lucide-book-marked',
330
+ onSelect: () => ui.openFragmentLibrary(),
331
+ },
332
+ ]
333
+ if (accounts.enabled) {
334
+ items.push({
335
+ label: t('inspector.fragments.manageAccount'),
336
+ icon: 'i-lucide-users',
337
+ onSelect: () => ui.openAccountSettings('fragments'),
338
+ })
339
+ }
340
+ return items
341
+ })
342
+ // Picker menu: fragments appropriate to the enclosing frame's block type (the "scope"), not
343
+ // already selected, grouped by category, with the management links appended as the final group.
344
+ // Falls back to `service` before a frame resolves so the catalog is still browsable.
345
+ const fragmentMenu = computed<DropdownMenuItem[][]>(() => {
346
+ const selected = new Set(fragmentIds.value)
347
+ return [
348
+ ...buildFragmentPickerGroups(
349
+ fragments.forBlockType(frame.value?.type ?? 'service'),
350
+ (id) => selected.has(id),
351
+ (id) => {
352
+ if (!fragmentIds.value.includes(id)) fragmentIds.value = [...fragmentIds.value, id]
353
+ },
354
+ ),
355
+ fragmentManageItems.value,
356
+ ]
357
+ })
358
+ function removeFragment(id: string) {
359
+ fragmentIds.value = fragmentIds.value.filter((x) => x !== id)
360
+ }
361
+
289
362
  // Hide UI-testing pipelines (`tester-ui` / `visual-confirmation`) when the target frame has no
290
363
  // UI to exercise — they'd be refused server-side (see utils/pipeline + the backend gate). Also
291
364
  // hide `'recurring'`-only pipelines (a one-off task start of one is refused at run start) and,
@@ -471,6 +544,7 @@ watch(open, (isOpen) => {
471
544
  docOutlineHints.value = ''
472
545
  reviewPrRef.value = ''
473
546
  reviewFocus.value = ''
547
+ fragmentIds.value = []
474
548
  for (const key of Object.keys(docKindFieldValues) as DocKindFieldKey[])
475
549
  delete docKindFieldValues[key]
476
550
  riskPolicyId.value = ''
@@ -494,6 +568,8 @@ watch(open, (isOpen) => {
494
568
  }
495
569
  documents.loadDocuments().catch(() => {})
496
570
  tasks.loadTasks().catch(() => {})
571
+ // Load the best-practice fragment catalog so the picker is populated (no-op while current).
572
+ fragments.ensureLoaded().catch(() => {})
497
573
  // Fetch any staged search-hit issue's body so its description shows read-only below.
498
574
  resolvePendingIssueBodies().catch(() => {})
499
575
  })
@@ -526,6 +602,7 @@ const { requestClose } = useUnsavedGuard({
526
602
  modelPresetId: modelPresetId.value,
527
603
  pipelineId: pipelineId.value,
528
604
  agentConfig: { ...agentConfigValues.value },
605
+ fragmentIds: [...fragmentIds.value],
529
606
  context: pendingContext.value.map(contextKey),
530
607
  }),
531
608
  })
@@ -539,8 +616,10 @@ const RALPH_VALIDATION_COMMAND_ID = 'ralph.validationCommand'
539
616
 
540
617
  const canAdd = computed(() => {
541
618
  if (isRecurring.value) return recurringFrameId.value !== null
619
+ // A review task doesn't require a title (the PR reference is the subject — we derive one),
620
+ // so it only needs a valid target PR. Every other type still requires a title.
621
+ if (isReview.value) return parseReviewPrRef(reviewPrRef.value) !== undefined
542
622
  if (title.value.trim().length === 0) return false
543
- if (taskType.value === 'review' && !parseReviewPrRef(reviewPrRef.value)) return false
544
623
  if (
545
624
  taskType.value === 'ralph' &&
546
625
  configValue(RALPH_VALIDATION_COMMAND_ID, '').trim().length === 0
@@ -571,15 +650,21 @@ async function add() {
571
650
  const fullDescription =
572
651
  [...linkedIssueBodies.value.map((b) => b.body), notes].filter(Boolean).join('\n\n') ||
573
652
  undefined
574
- const block = await board.addTask(containerId, title.value.trim(), fullDescription, {
653
+ // A review task's title is optional; when blank we derive one from the PR reference so the
654
+ // board card still reads sensibly (the backend also folds the PR ref into the description).
655
+ const effectiveTitle =
656
+ title.value.trim() || (isReview.value ? deriveReviewTitle(reviewPrRef.value) : '')
657
+ const block = await board.addTask(containerId, effectiveTitle, fullDescription, {
575
658
  taskType: taskType.value as CreateTaskType,
576
659
  ...(typeFields ? { taskTypeFields: typeFields } : {}),
577
- ...(riskPolicyId.value ? { riskPolicyId: riskPolicyId.value } : {}),
660
+ // A review task merges nothing, so its risk (merge) policy is meaningless never send it.
661
+ ...(riskPolicyId.value && !isReview.value ? { riskPolicyId: riskPolicyId.value } : {}),
578
662
  ...(modelPresetId.value ? { modelPresetId: modelPresetId.value } : {}),
579
663
  ...(pipelineId.value ? { pipelineId: pipelineId.value } : {}),
580
664
  ...(Object.keys(agentConfigValues.value).length
581
665
  ? { agentConfig: agentConfigValues.value }
582
666
  : {}),
667
+ ...(fragmentIds.value.length ? { fragmentIds: [...fragmentIds.value] } : {}),
583
668
  ...(technical.value ? { technical: true } : {}),
584
669
  })
585
670
  if (block) {
@@ -648,7 +733,10 @@ async function add() {
648
733
  </div>
649
734
 
650
735
  <template v-if="!isRecurring">
651
- <UFormField :label="t('board.addTask.titleField')" required>
736
+ <!-- A review task shows neither Title nor Description: the target PR is the
737
+ subject (the title is derived from the PR reference), and any notes go in
738
+ the dedicated "Review focus" field below. -->
739
+ <UFormField v-if="!isReview" :label="t('board.addTask.titleField')" required>
652
740
  <UInput
653
741
  v-model="title"
654
742
  data-testid="add-task-title"
@@ -659,46 +747,48 @@ async function add() {
659
747
  />
660
748
  </UFormField>
661
749
 
662
- <!-- Linked issue description(s), read-only: shown so the user sees the original
663
- issue description is included in the task. It's folded into the saved
664
- description (before their notes) on add. -->
665
- <UFormField
666
- v-for="issue in linkedIssueBodies"
667
- :key="issue.key"
668
- :label="t('board.addTask.issueIncluded', { title: issue.title })"
669
- >
670
- <UTextarea
671
- :model-value="issue.body"
672
- :rows="4"
673
- autoresize
674
- readonly
675
- class="w-full"
676
- :ui="{ base: 'cursor-default text-slate-300' }"
677
- />
678
- </UFormField>
679
- <p v-if="resolvingIssueBodies" class="text-[11px] text-slate-500">
680
- {{ t('board.addTask.loadingIssue') }}
681
- </p>
750
+ <template v-if="!isReview">
751
+ <!-- Linked issue description(s), read-only: shown so the user sees the original
752
+ issue description is included in the task. It's folded into the saved
753
+ description (before their notes) on add. -->
754
+ <UFormField
755
+ v-for="issue in linkedIssueBodies"
756
+ :key="issue.key"
757
+ :label="t('board.addTask.issueIncluded', { title: issue.title })"
758
+ >
759
+ <UTextarea
760
+ :model-value="issue.body"
761
+ :rows="4"
762
+ autoresize
763
+ readonly
764
+ class="w-full"
765
+ :ui="{ base: 'cursor-default text-slate-300' }"
766
+ />
767
+ </UFormField>
768
+ <p v-if="resolvingIssueBodies" class="text-[11px] text-slate-500">
769
+ {{ t('board.addTask.loadingIssue') }}
770
+ </p>
682
771
 
683
- <UFormField
684
- :label="
685
- hasLinkedIssueBody
686
- ? t('board.addTask.additionalNotes')
687
- : t('board.addTask.description')
688
- "
689
- >
690
- <UTextarea
691
- v-model="description"
692
- :rows="4"
693
- autoresize
694
- :placeholder="
772
+ <UFormField
773
+ :label="
695
774
  hasLinkedIssueBody
696
- ? t('board.addTask.notesPlaceholder')
697
- : t('board.addTask.descriptionPlaceholder')
775
+ ? t('board.addTask.additionalNotes')
776
+ : t('board.addTask.description')
698
777
  "
699
- class="w-full"
700
- />
701
- </UFormField>
778
+ >
779
+ <UTextarea
780
+ v-model="description"
781
+ :rows="4"
782
+ autoresize
783
+ :placeholder="
784
+ hasLinkedIssueBody
785
+ ? t('board.addTask.notesPlaceholder')
786
+ : t('board.addTask.descriptionPlaceholder')
787
+ "
788
+ class="w-full"
789
+ />
790
+ </UFormField>
791
+ </template>
702
792
 
703
793
  <UCheckbox v-model="technical" name="technical">
704
794
  <template #label>
@@ -905,7 +995,8 @@ async function add() {
905
995
  />
906
996
  </UFormField>
907
997
 
908
- <UFormField :label="t('board.addTask.mergePolicy')">
998
+ <!-- A review task merges nothing, so its risk (merge) policy is meaningless — omit it. -->
999
+ <UFormField v-if="!isReview" :label="t('board.addTask.mergePolicy')">
909
1000
  <UDropdownMenu :items="presetMenu" class="w-full">
910
1001
  <UButton
911
1002
  color="neutral"
@@ -967,6 +1058,43 @@ async function add() {
967
1058
  </div>
968
1059
  </div>
969
1060
 
1061
+ <!-- Best-practice fragments pinned on the task at creation, scoped to the frame's type. -->
1062
+ <div class="space-y-2">
1063
+ <div class="flex items-center justify-between">
1064
+ <span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
1065
+ {{ t('board.addTask.bestPractices') }}
1066
+ </span>
1067
+ <UDropdownMenu :items="fragmentMenu">
1068
+ <UButton
1069
+ color="neutral"
1070
+ variant="soft"
1071
+ size="xs"
1072
+ icon="i-lucide-plus"
1073
+ trailing-icon="i-lucide-chevron-down"
1074
+ >
1075
+ {{ t('board.addTask.attach') }}
1076
+ </UButton>
1077
+ </UDropdownMenu>
1078
+ </div>
1079
+ <div v-if="selectedFragments.length" class="flex flex-wrap gap-1">
1080
+ <UBadge
1081
+ v-for="f in selectedFragments"
1082
+ :key="f.id"
1083
+ color="primary"
1084
+ variant="subtle"
1085
+ size="sm"
1086
+ class="cursor-pointer"
1087
+ :title="f.summary"
1088
+ @click="removeFragment(f.id)"
1089
+ >
1090
+ {{ f.title }}<UIcon name="i-lucide-x" class="ms-0.5 h-3 w-3" />
1091
+ </UBadge>
1092
+ </div>
1093
+ <p v-else class="text-[11px] text-slate-500">
1094
+ {{ t('board.addTask.bestPracticesHint') }}
1095
+ </p>
1096
+ </div>
1097
+
970
1098
  <!-- Context documents (ungated; Attach disabled until a source is connected). -->
971
1099
  <div class="space-y-2">
972
1100
  <div class="flex items-center justify-between">
@@ -227,6 +227,7 @@ export const useBoardStore = defineStore('board', () => {
227
227
  modelPresetId?: string
228
228
  pipelineId?: string
229
229
  agentConfig?: Record<string, string>
230
+ fragmentIds?: string[]
230
231
  technical?: boolean
231
232
  },
232
233
  ): Promise<Block | undefined> {
@@ -240,6 +241,7 @@ export const useBoardStore = defineStore('board', () => {
240
241
  ...(options?.modelPresetId ? { modelPresetId: options.modelPresetId } : {}),
241
242
  ...(options?.pipelineId ? { pipelineId: options.pipelineId } : {}),
242
243
  ...(options?.agentConfig ? { agentConfig: options.agentConfig } : {}),
244
+ ...(options?.fragmentIds?.length ? { fragmentIds: options.fragmentIds } : {}),
243
245
  ...(options?.technical ? { technical: true } : {}),
244
246
  })
245
247
  upsert(block)
@@ -2172,6 +2172,8 @@
2172
2172
  "defaultPreset": "Standard ({name}) — {thresholds}",
2173
2173
  "defaultModelPreset": "Standard ({name})",
2174
2174
  "modelPreset": "Modell-Preset",
2175
+ "bestPractices": "Best Practices",
2176
+ "bestPracticesHint": "Best-Practice-Fragmente anheften, damit die Agenten dieser Aufgabe sie zusätzlich zu den Standards auf Service-Ebene befolgen.",
2175
2177
  "agentConfiguration": "Agent-Konfiguration",
2176
2178
  "contextDocuments": "Kontextdokumente",
2177
2179
  "contextIssues": "Kontext-Issues",
@@ -2195,7 +2197,9 @@
2195
2197
  "prUrl": "Pull Request",
2196
2198
  "prUrlHint": "URL oder Nummer des zu prüfenden Pull Requests",
2197
2199
  "focus": "Prüfungsschwerpunkt",
2198
- "focusPlaceholder": "z. B. Fokus auf die Auth-Änderungen und Fehlerbehandlung"
2200
+ "focusPlaceholder": "z. B. Fokus auf die Auth-Änderungen und Fehlerbehandlung",
2201
+ "derivedTitle": "{ref} prüfen",
2202
+ "derivedTitleFallback": "Pull Request prüfen"
2199
2203
  }
2200
2204
  },
2201
2205
  "recurring": {
@@ -291,6 +291,8 @@
291
291
  "defaultPreset": "Default ({name}) — {thresholds}",
292
292
  "defaultModelPreset": "Default ({name})",
293
293
  "modelPreset": "Model preset",
294
+ "bestPractices": "Best practices",
295
+ "bestPracticesHint": "Pin best-practice fragments so this task's agents follow them, on top of the service-level standards.",
294
296
  "agentConfiguration": "Agent configuration",
295
297
  "contextDocuments": "Context documents",
296
298
  "contextIssues": "Context issues",
@@ -317,7 +319,9 @@
317
319
  "prUrl": "Pull request",
318
320
  "prUrlHint": "URL or number of the pull request to review",
319
321
  "focus": "Review focus",
320
- "focusPlaceholder": "e.g. focus on the auth changes and error handling"
322
+ "focusPlaceholder": "e.g. focus on the auth changes and error handling",
323
+ "derivedTitle": "Review {ref}",
324
+ "derivedTitleFallback": "Review pull request"
321
325
  }
322
326
  },
323
327
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "Predeterminado ({name}): {thresholds}",
271
271
  "defaultModelPreset": "Predeterminado ({name})",
272
272
  "modelPreset": "Preset de modelo",
273
+ "bestPractices": "Buenas prácticas",
274
+ "bestPracticesHint": "Fija fragmentos de buenas prácticas para que los agentes de esta tarea los sigan, además de los estándares del servicio.",
273
275
  "agentConfiguration": "Configuración del agente",
274
276
  "contextDocuments": "Documentos de contexto",
275
277
  "contextIssues": "Incidencias de contexto",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "Pull request",
294
296
  "prUrlHint": "URL o número de la pull request a revisar",
295
297
  "focus": "Enfoque de la revisión",
296
- "focusPlaceholder": "p. ej., céntrate en los cambios de autenticación y el manejo de errores"
298
+ "focusPlaceholder": "p. ej., céntrate en los cambios de autenticación y el manejo de errores",
299
+ "derivedTitle": "Revisar {ref}",
300
+ "derivedTitleFallback": "Revisar la pull request"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "Par défaut ({name}) : {thresholds}",
271
271
  "defaultModelPreset": "Par défaut ({name})",
272
272
  "modelPreset": "Préréglage de modèle",
273
+ "bestPractices": "Bonnes pratiques",
274
+ "bestPracticesHint": "Épinglez des fragments de bonnes pratiques pour que les agents de cette tâche les suivent, en plus des standards au niveau du service.",
273
275
  "agentConfiguration": "Configuration de l’agent",
274
276
  "contextDocuments": "Documents de contexte",
275
277
  "contextIssues": "Tickets de contexte",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "Pull request",
294
296
  "prUrlHint": "URL ou numéro de la pull request à examiner",
295
297
  "focus": "Objet de la revue",
296
- "focusPlaceholder": "p. ex. concentrez-vous sur les changements d'authentification et la gestion des erreurs"
298
+ "focusPlaceholder": "p. ex. concentrez-vous sur les changements d'authentification et la gestion des erreurs",
299
+ "derivedTitle": "Examiner {ref}",
300
+ "derivedTitleFallback": "Examiner la pull request"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "ברירת מחדל ({name}) — {thresholds}",
271
271
  "defaultModelPreset": "ברירת מחדל ({name})",
272
272
  "modelPreset": "הגדרה קבועה של מודל",
273
+ "bestPractices": "מומלצות עבודה",
274
+ "bestPracticesHint": "הצמידו מקטעי מומלצות עבודה כדי שסוכני המשימה יפעלו לפיהם, בנוסף לסטנדרטים ברמת השירות.",
273
275
  "agentConfiguration": "תצורת סוכן",
274
276
  "contextDocuments": "מסמכי הקשר",
275
277
  "contextIssues": "אישיו הקשר",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "בקשת משיכה",
294
296
  "prUrlHint": "כתובת או מספר של בקשת המשיכה לסקירה",
295
297
  "focus": "מוקד הסקירה",
296
- "focusPlaceholder": "לדוגמה, להתמקד בשינויי האימות ובטיפול בשגיאות"
298
+ "focusPlaceholder": "לדוגמה, להתמקד בשינויי האימות ובטיפול בשגיאות",
299
+ "derivedTitle": "סקירת {ref}",
300
+ "derivedTitleFallback": "סקירת בקשת המשיכה"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -2172,6 +2172,8 @@
2172
2172
  "defaultPreset": "Predefinito ({name}) — {thresholds}",
2173
2173
  "defaultModelPreset": "Predefinito ({name})",
2174
2174
  "modelPreset": "Preset di modello",
2175
+ "bestPractices": "Best practice",
2176
+ "bestPracticesHint": "Fissa i frammenti di best practice affinché gli agenti di questa attività li seguano, oltre agli standard a livello di servizio.",
2175
2177
  "agentConfiguration": "Configurazione dell'agente",
2176
2178
  "contextDocuments": "Documenti di contesto",
2177
2179
  "contextIssues": "Issue di contesto",
@@ -2195,7 +2197,9 @@
2195
2197
  "prUrl": "Pull request",
2196
2198
  "prUrlHint": "URL o numero della pull request da revisionare",
2197
2199
  "focus": "Focus della revisione",
2198
- "focusPlaceholder": "es. concentrati sulle modifiche di autenticazione e sulla gestione degli errori"
2200
+ "focusPlaceholder": "es. concentrati sulle modifiche di autenticazione e sulla gestione degli errori",
2201
+ "derivedTitle": "Rivedi {ref}",
2202
+ "derivedTitleFallback": "Rivedi la pull request"
2199
2203
  }
2200
2204
  },
2201
2205
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "既定({name})— {thresholds}",
271
271
  "defaultModelPreset": "既定({name})",
272
272
  "modelPreset": "モデルプリセット",
273
+ "bestPractices": "ベストプラクティス",
274
+ "bestPracticesHint": "サービスレベルの標準に加えて、このタスクのエージェントが従うようにベストプラクティスのフラグメントを固定します。",
273
275
  "agentConfiguration": "エージェント設定",
274
276
  "contextDocuments": "コンテキストドキュメント",
275
277
  "contextIssues": "コンテキスト issue",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "プルリクエスト",
294
296
  "prUrlHint": "レビュー対象のプルリクエストのURLまたは番号",
295
297
  "focus": "レビューの重点",
296
- "focusPlaceholder": "例: 認証の変更とエラー処理に注目"
298
+ "focusPlaceholder": "例: 認証の変更とエラー処理に注目",
299
+ "derivedTitle": "{ref} をレビュー",
300
+ "derivedTitleFallback": "プルリクエストをレビュー"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "Domyślny ({name}): {thresholds}",
271
271
  "defaultModelPreset": "Domyślny ({name})",
272
272
  "modelPreset": "Preset modelu",
273
+ "bestPractices": "Dobre praktyki",
274
+ "bestPracticesHint": "Przypnij fragmenty dobrych praktyk, aby agenci tego zadania stosowali je oprócz standardów na poziomie usługi.",
273
275
  "agentConfiguration": "Konfiguracja agenta",
274
276
  "contextDocuments": "Dokumenty kontekstu",
275
277
  "contextIssues": "Zgłoszenia kontekstu",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "Pull request",
294
296
  "prUrlHint": "URL lub numer pull requesta do przeglądu",
295
297
  "focus": "Zakres przeglądu",
296
- "focusPlaceholder": "np. skup się na zmianach uwierzytelniania i obsłudze błędów"
298
+ "focusPlaceholder": "np. skup się na zmianach uwierzytelniania i obsłudze błędów",
299
+ "derivedTitle": "Przegląd {ref}",
300
+ "derivedTitleFallback": "Przegląd pull requesta"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "Varsayılan ({name}) — {thresholds}",
271
271
  "defaultModelPreset": "Varsayılan ({name})",
272
272
  "modelPreset": "Model ön ayarı",
273
+ "bestPractices": "En iyi uygulamalar",
274
+ "bestPracticesHint": "Bu görevin ajanlarının hizmet düzeyindeki standartlara ek olarak uygulaması için en iyi uygulama parçacıklarını sabitleyin.",
273
275
  "agentConfiguration": "Ajan yapılandırması",
274
276
  "contextDocuments": "Bağlam belgeleri",
275
277
  "contextIssues": "Bağlam sorunları",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "Pull request",
294
296
  "prUrlHint": "İncelenecek pull request'in URL'si veya numarası",
295
297
  "focus": "İnceleme odağı",
296
- "focusPlaceholder": "örn. kimlik doğrulama değişikliklerine ve hata yönetimine odaklan"
298
+ "focusPlaceholder": "örn. kimlik doğrulama değişikliklerine ve hata yönetimine odaklan",
299
+ "derivedTitle": "{ref} incele",
300
+ "derivedTitleFallback": "Pull request'i incele"
297
301
  }
298
302
  },
299
303
  "recurring": {
@@ -270,6 +270,8 @@
270
270
  "defaultPreset": "Типовий ({name}): {thresholds}",
271
271
  "defaultModelPreset": "Типовий ({name})",
272
272
  "modelPreset": "Пресет моделі",
273
+ "bestPractices": "Найкращі практики",
274
+ "bestPracticesHint": "Закріпіть фрагменти найкращих практик, щоб агенти цього завдання дотримувалися їх додатково до стандартів рівня сервісу.",
273
275
  "agentConfiguration": "Налаштування агента",
274
276
  "contextDocuments": "Документи контексту",
275
277
  "contextIssues": "Звернення контексту",
@@ -293,7 +295,9 @@
293
295
  "prUrl": "Pull request",
294
296
  "prUrlHint": "URL або номер pull request для огляду",
295
297
  "focus": "Фокус огляду",
296
- "focusPlaceholder": "напр. зосередься на змінах автентифікації та обробці помилок"
298
+ "focusPlaceholder": "напр. зосередься на змінах автентифікації та обробці помилок",
299
+ "derivedTitle": "Огляд {ref}",
300
+ "derivedTitleFallback": "Огляд pull request"
297
301
  }
298
302
  },
299
303
  "recurring": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.142.0",
3
+ "version": "0.143.1",
4
4
  "description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  "valibot": "^1.4.2",
41
41
  "vue": "3.5.40",
42
42
  "wretch": "^3.0.9",
43
- "@cat-factory/contracts": "0.151.0"
43
+ "@cat-factory/contracts": "0.152.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",