@cat-factory/app 0.71.2 → 0.73.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.
Files changed (50) hide show
  1. package/app/components/board/nodes/TaskCard.vue +12 -2
  2. package/app/components/bootstrap/BootstrapModal.vue +23 -7
  3. package/app/components/brainstorm/BrainstormWindow.vue +2 -0
  4. package/app/components/clarity/ClarityReviewWindow.vue +2 -0
  5. package/app/components/consensus/ConsensusSessionWindow.vue +2 -0
  6. package/app/components/focus/BlockFocusView.vue +2 -0
  7. package/app/components/followUp/FollowUpWindow.vue +2 -0
  8. package/app/components/gates/GateResultView.vue +2 -0
  9. package/app/components/humanTest/HumanTestWindow.vue +2 -0
  10. package/app/components/layout/ConnectionStatusBanner.vue +81 -0
  11. package/app/components/layout/NotificationsInbox.vue +15 -0
  12. package/app/components/panels/GenericStructuredResultView.vue +2 -0
  13. package/app/components/panels/InspectorPanel.vue +30 -1
  14. package/app/components/panels/MergerResultView.vue +267 -0
  15. package/app/components/panels/StepResultViewHost.vue +4 -0
  16. package/app/components/panels/inspector/FrontendConfig.vue +111 -1
  17. package/app/components/panels/inspector/TaskExecution.vue +31 -2
  18. package/app/components/pipeline/PipelineBuilder.vue +110 -7
  19. package/app/components/requirements/RequirementsReviewWindow.vue +2 -0
  20. package/app/components/spec/ServiceSpecWindow.vue +2 -0
  21. package/app/components/testing/TestReportWindow.vue +91 -0
  22. package/app/composables/api/preview.ts +20 -0
  23. package/app/composables/useApi.ts +2 -0
  24. package/app/composables/useKeyboardShortcuts.ts +10 -2
  25. package/app/pages/index.vue +6 -4
  26. package/app/stores/board.spec.ts +58 -1
  27. package/app/stores/board.ts +59 -15
  28. package/app/stores/brainstorm.spec.ts +35 -0
  29. package/app/stores/brainstorm.ts +11 -2
  30. package/app/stores/clarity.spec.ts +33 -0
  31. package/app/stores/clarity.ts +11 -2
  32. package/app/stores/execution.spec.ts +71 -13
  33. package/app/stores/execution.ts +44 -6
  34. package/app/stores/pipelines.ts +53 -0
  35. package/app/stores/preview.ts +94 -0
  36. package/app/stores/recurringPipelines.ts +5 -1
  37. package/app/stores/requirements.spec.ts +21 -0
  38. package/app/stores/requirements.ts +11 -2
  39. package/app/stores/workspace.ts +1 -1
  40. package/app/types/domain.ts +2 -0
  41. package/app/utils/catalog.ts +12 -0
  42. package/i18n/locales/en.json +94 -5
  43. package/i18n/locales/es.json +94 -5
  44. package/i18n/locales/fr.json +94 -5
  45. package/i18n/locales/he.json +94 -5
  46. package/i18n/locales/ja.json +94 -5
  47. package/i18n/locales/pl.json +94 -5
  48. package/i18n/locales/tr.json +94 -5
  49. package/i18n/locales/uk.json +94 -5
  50. package/package.json +2 -2
@@ -92,3 +92,24 @@ describe('requirements store load() loading flag', () => {
92
92
  expect(calls).toBe(2)
93
93
  })
94
94
  })
95
+
96
+ describe('requirements store live-event upsert guard', () => {
97
+ it('an out-of-order stream event cannot revert a newer cached review', () => {
98
+ const store = useRequirementsStore()
99
+ // The API response for a just-submitted answer landed first (newer updatedAt)…
100
+ store.upsert(review({ updatedAt: 2000, status: 'merged' }))
101
+ // …then the slightly-older stream event (emitted just before) arrives late.
102
+ store.upsert(review({ updatedAt: 1000, status: 'ready' }))
103
+ expect(store.reviewFor('b1')?.status).toBe('merged')
104
+ // A genuinely newer event still applies.
105
+ store.upsert(review({ updatedAt: 3000, status: 'incorporated' }))
106
+ expect(store.reviewFor('b1')?.status).toBe('incorporated')
107
+ })
108
+
109
+ it('a NEW review (different id) for the block replaces regardless of updatedAt', () => {
110
+ const store = useRequirementsStore()
111
+ store.upsert(review({ updatedAt: 2000 }))
112
+ store.upsert(review({ id: 'rr2', updatedAt: 1000 }))
113
+ expect(store.reviewFor('b1')?.id).toBe('rr2')
114
+ })
115
+ })
@@ -97,6 +97,16 @@ export const useRequirementsStore = defineStore('requirements', () => {
97
97
  reviews.value = { ...reviews.value, [review.blockId]: review }
98
98
  }
99
99
 
100
+ /** Patch the cache from a live `requirements` stream event (newest wins per block). */
101
+ function upsert(review: RequirementReview) {
102
+ const existing = reviews.value[review.blockId]
103
+ // Keep the freshest by updatedAt (the consensus-store guard): `store()` also runs on
104
+ // API responses, so a slightly-older event racing a just-submitted answer over the
105
+ // separate WS transport must not revert the review the response already delivered.
106
+ if (existing && existing.id === review.id && existing.updatedAt > review.updatedAt) return
107
+ store(review)
108
+ }
109
+
100
110
  /** Drop all cached reviews + in-flight state (called on workspace switch). */
101
111
  function reset() {
102
112
  available.value = null
@@ -277,7 +287,6 @@ export const useRequirementsStore = defineStore('requirements', () => {
277
287
  rejectRecommendation,
278
288
  reRequestRecommendation,
279
289
  reset,
280
- // Patch the cache from a live `requirements` stream event.
281
- upsert: store,
290
+ upsert,
282
291
  }
283
292
  })
@@ -91,7 +91,7 @@ export const useWorkspaceStore = defineStore(
91
91
  else workspaces.value.unshift(snapshot.workspace)
92
92
  useBoardStore().hydrate(snapshot.blocks)
93
93
  usePipelinesStore().hydrate(snapshot.pipelines, snapshot.pipelineCatalogVersions)
94
- useExecutionStore().hydrate(snapshot.executions)
94
+ useExecutionStore().hydrate(snapshot.executions, snapshot.workspace.id)
95
95
  useAgentRunsStore().hydrate(snapshot.bootstrapJobs ?? [], snapshot.workspace.id)
96
96
  useAgentRunsStore().hydrateEnvConfigRepair(snapshot.envConfigRepairJobs ?? [])
97
97
  useNotificationsStore().hydrate(snapshot.notifications ?? [])
@@ -63,6 +63,8 @@ export type {
63
63
  KaizenVerifiedCombo,
64
64
  KaizenOverview,
65
65
  WorkspaceEvent,
66
+ PreviewState,
67
+ PreviewStatus,
66
68
  } from '@cat-factory/contracts'
67
69
 
68
70
  import type { AgentCategory, AgentKind } from '@cat-factory/contracts'
@@ -312,6 +312,15 @@ export function isConsensusEligibleKind(kind: string): boolean {
312
312
  return CONSENSUS_ELIGIBLE_KINDS.has(kind)
313
313
  }
314
314
 
315
+ /**
316
+ * Whether an agent kind is one of the Tester gate kinds (API or UI). Mirrors the backend
317
+ * `isTesterKind`; used by the pipeline builder to surface the test quality-control companion
318
+ * toggle only on Tester steps.
319
+ */
320
+ export function isTesterKind(kind: string): boolean {
321
+ return kind === 'tester-api' || kind === 'tester-ui'
322
+ }
323
+
315
324
  /**
316
325
  * Display metadata for the engine-driven "system" kinds — the gate/automation
317
326
  * steps (blueprint mapper, conflicts gate + resolver, CI gate + fixer, merger)
@@ -405,6 +414,9 @@ export const SYSTEM_AGENT_META: Record<string, AgentArchetype> = {
405
414
  icon: 'i-lucide-git-pull-request',
406
415
  color: '#a3e635',
407
416
  description: 'Scores the PR and auto-merges within the task thresholds, or asks for review.',
417
+ // The merger's verdict is structured (scores + the engine's auto-merge / review
418
+ // decision), so it opens a dedicated result view instead of the raw-JSON prose panel.
419
+ resultView: 'merger',
408
420
  },
409
421
  'human-review': {
410
422
  kind: 'human-review',
@@ -1,4 +1,10 @@
1
1
  {
2
+ "app": {
3
+ "loading": "Loading…",
4
+ "loadingBoard": "Loading board…",
5
+ "backendUnreachable": "Can't reach the backend",
6
+ "reconnecting": "Reconnecting…"
7
+ },
2
8
  "language": {
3
9
  "switcher": "Language",
4
10
  "warning": {
@@ -83,6 +89,14 @@
83
89
  "accountSettings": "Account settings"
84
90
  },
85
91
  "board": {
92
+ "toast": {
93
+ "updateFailed": "Could not save changes",
94
+ "epicFailed": "Could not change epic",
95
+ "moveFailed": "Could not move",
96
+ "deleteFailed": "Could not delete",
97
+ "linkFailed": "Could not link tasks",
98
+ "recurringDeleteFailed": "Could not delete recurring pipeline"
99
+ },
86
100
  "repoTypes": {
87
101
  "service": "Service",
88
102
  "frontend": "Frontend",
@@ -291,6 +305,11 @@
291
305
  "openPrOnGithub": "Open {pr} on GitHub",
292
306
  "review": "Review",
293
307
  "merge": "Merge",
308
+ "mergeConfirm": {
309
+ "title": "Merge this pull request?",
310
+ "body": "This merges the PR into its base branch and completes the task. This can't be undone.",
311
+ "confirm": "Merge"
312
+ },
294
313
  "implemented": "implemented",
295
314
  "module": "Module: {name}",
296
315
  "buildSteps": "Build steps",
@@ -485,6 +504,17 @@
485
504
  "mock": "Mock (WireMock)",
486
505
  "remove": "Remove binding",
487
506
  "empty": "No backend bindings. Add one to point an env var at a service or a mock."
507
+ },
508
+ "preview": {
509
+ "open": "Open preview",
510
+ "start": "Start preview",
511
+ "stop": "Stop",
512
+ "status": {
513
+ "starting": "Starting…",
514
+ "ready": "Running",
515
+ "failed": "Failed",
516
+ "stopped": "Not running"
517
+ }
488
518
  }
489
519
  },
490
520
  "releaseHealth": {
@@ -634,6 +664,16 @@
634
664
  "stopTooltip": "Stop the run but keep it (readable and retryable)",
635
665
  "reset": "Reset",
636
666
  "resetTooltip": "Discard this run and reset the task to planned",
667
+ "resetConfirm": {
668
+ "title": "Discard this run?",
669
+ "body": "This deletes the run and returns the task to planned. This can't be undone.",
670
+ "confirm": "Discard run"
671
+ },
672
+ "mergeConfirm": {
673
+ "title": "Merge this pull request?",
674
+ "body": "This merges the PR into its base branch and completes the task. This can't be undone.",
675
+ "confirm": "Merge"
676
+ },
637
677
  "viewDetailsOutput": "View details and read output",
638
678
  "viewDetails": "View step details",
639
679
  "companion": "Companion",
@@ -721,6 +761,33 @@
721
761
  "noResult": "No result yet.",
722
762
  "noResultHint": "The structured output appears once this agent finishes. While it runs, the step shows live progress on the board."
723
763
  },
764
+ "mergerResult": {
765
+ "title": "Merge decision",
766
+ "titleWithBlock": "Merge decision: {title}",
767
+ "description": "How the PR scored and what the engine decided.",
768
+ "outcome": {
769
+ "auto_merged": "Auto-merged",
770
+ "awaiting_review": "Awaiting human review"
771
+ },
772
+ "reason": {
773
+ "within_thresholds": "Every score is within the {preset} thresholds, so the PR was merged automatically.",
774
+ "exceeded_thresholds": "{axes} exceeded the {preset} thresholds, so the PR is waiting for a human to merge.",
775
+ "auto_merge_disabled": "The {preset} preset sends every PR to a human, so this one is waiting for review.",
776
+ "no_rationale": "The merger scored the PR but gave no rationale, so the verdict could not be trusted to auto-merge; the PR is waiting for a human to merge.",
777
+ "no_assessment": "The merger did not return a parseable assessment, so the PR is waiting for a human to merge.",
778
+ "merge_failed": "The scores were within the {preset} thresholds, but the automatic merge could not complete (for example branch protection or a conflict), so the PR is waiting for a human to merge."
779
+ },
780
+ "scores": "Scores",
781
+ "axis": {
782
+ "complexity": "Complexity",
783
+ "risk": "Risk",
784
+ "impact": "Impact"
785
+ },
786
+ "ceiling": "ceiling {value}",
787
+ "rationale": "Rationale",
788
+ "noAssessment": "The merger did not return a scored assessment.",
789
+ "noResult": "No merge decision recorded yet."
790
+ },
724
791
  "testReport": {
725
792
  "title": "Test report",
726
793
  "greenlit": "Greenlit",
@@ -1190,7 +1257,9 @@
1190
1257
  "dismiss": "Dismiss",
1191
1258
  "toast": {
1192
1259
  "acted": "Marked as handled",
1193
- "dismissed": "Dismissed"
1260
+ "dismissed": "Dismissed",
1261
+ "actFailed": "Could not complete that action",
1262
+ "dismissFailed": "Could not dismiss"
1194
1263
  },
1195
1264
  "action": {
1196
1265
  "merge_review": "Merge",
@@ -2637,6 +2706,10 @@
2637
2706
  "consensusRevertTooltip": "Consensus enabled. Click to revert to a single agent.",
2638
2707
  "followUpEnableTooltip": "Follow-up companion disabled. Click to enable (Coder surfaces loose ends / questions).",
2639
2708
  "followUpDisableTooltip": "Follow-up companion enabled. Coder surfaces loose ends / side-tasks / questions; click to disable.",
2709
+ "testerQualityEnableTooltip": "Test quality companion disabled. Click to enable (audits the report for coverage and loops the Tester on gaps).",
2710
+ "testerQualityDisableTooltip": "Test quality companion enabled. Audits the report for coverage before greenlight and loops the Tester on gaps; click to disable.",
2711
+ "testerQualityLabel": "Test quality companion",
2712
+ "testerQualityGateTooltip": "Only run the quality audit when the task estimate clears a threshold (needs a Task Estimator earlier)",
2640
2713
  "moveUp": "Move step up",
2641
2714
  "moveDown": "Move step down",
2642
2715
  "removeStep": "Remove this step from the pipeline",
@@ -3327,6 +3400,15 @@
3327
3400
  "failed": "Failed",
3328
3401
  "addressed": "Addressing"
3329
3402
  },
3403
+ "quality": {
3404
+ "heading": "Coverage review",
3405
+ "reruns": "Quality-driven Tester re-runs",
3406
+ "rerunCount": "{attempts}/{max} re-runs",
3407
+ "exceeded": "Budget spent",
3408
+ "adequate": "Coverage adequate",
3409
+ "inadequate": "Coverage gaps found",
3410
+ "gaps": "Gaps to close"
3411
+ },
3330
3412
  "empty": {
3331
3413
  "title": "No test report yet.",
3332
3414
  "hint": "The report appears once the Tester finishes a pass. While it runs, the step shows live progress on the board."
@@ -3799,6 +3881,7 @@
3799
3881
  },
3800
3882
  "targetRepo": {
3801
3883
  "label": "Target repository name",
3884
+ "namePlaceholder": "payments-service",
3802
3885
  "descWithOwner": "Create a fresh repo with this name under {owner}, then bootstrap pushes into it. A prepopulated README, .gitignore or license is fine.",
3803
3886
  "descNoOwner": "Create a fresh repo with this name, then bootstrap pushes into it. A prepopulated README, .gitignore or license is fine."
3804
3887
  },
@@ -3818,7 +3901,8 @@
3818
3901
  },
3819
3902
  "description": {
3820
3903
  "label": "Description",
3821
- "help": "Optional one-line summary for the repo."
3904
+ "help": "Optional one-line summary for the repo.",
3905
+ "placeholder": "Handles payment intents and refunds"
3822
3906
  },
3823
3907
  "instructions": {
3824
3908
  "labelReference": "Extra instructions for the bootstrapper",
@@ -3848,18 +3932,23 @@
3848
3932
  "add": "Add",
3849
3933
  "pickRepo": {
3850
3934
  "label": "Pick an existing GitHub repo",
3851
- "description": "Choose a repo you can access to fill in its owner and name, or enter them manually below."
3935
+ "description": "Choose a repo you can access to fill in its owner and name, or enter them manually below.",
3936
+ "placeholder": "owner/name"
3852
3937
  },
3853
3938
  "name": {
3854
3939
  "label": "Name",
3855
- "description": "A friendly label for this base."
3940
+ "description": "A friendly label for this base.",
3941
+ "placeholder": "Service Template"
3856
3942
  },
3857
3943
  "repoOwner": "Repo owner",
3944
+ "repoOwnerPlaceholder": "acme",
3858
3945
  "repoName": "Repo name",
3946
+ "repoNamePlaceholder": "service-template",
3859
3947
  "descriptionPlaceholder": "Optional summary of this base",
3860
3948
  "defaultInstructions": {
3861
3949
  "label": "Default bootstrapper instructions",
3862
- "description": "Prepended to the per-run instructions whenever this base is used."
3950
+ "description": "Prepended to the per-run instructions whenever this base is used.",
3951
+ "placeholder": "e.g. keep the structure; rename packages to match the new service"
3863
3952
  }
3864
3953
  },
3865
3954
  "toast": {
@@ -1,4 +1,10 @@
1
1
  {
2
+ "app": {
3
+ "loading": "Cargando…",
4
+ "loadingBoard": "Cargando tablero…",
5
+ "backendUnreachable": "No se puede conectar con el backend",
6
+ "reconnecting": "Reconectando…"
7
+ },
2
8
  "language": {
3
9
  "switcher": "Idioma",
4
10
  "warning": {
@@ -68,6 +74,14 @@
68
74
  "infrastructure": "Infraestructura"
69
75
  },
70
76
  "board": {
77
+ "toast": {
78
+ "updateFailed": "No se pudieron guardar los cambios",
79
+ "epicFailed": "No se pudo cambiar la épica",
80
+ "moveFailed": "No se pudo mover",
81
+ "deleteFailed": "No se pudo eliminar",
82
+ "linkFailed": "No se pudieron vincular las tareas",
83
+ "recurringDeleteFailed": "No se pudo eliminar el pipeline recurrente"
84
+ },
71
85
  "repoTypes": {
72
86
  "service": "Servicio",
73
87
  "frontend": "Frontend",
@@ -260,6 +274,11 @@
260
274
  "openPrOnGithub": "Abrir {pr} en GitHub",
261
275
  "review": "Revisar",
262
276
  "merge": "Fusionar",
277
+ "mergeConfirm": {
278
+ "title": "¿Fusionar esta pull request?",
279
+ "body": "Esto fusiona la PR en su rama base y completa la tarea. Esto no se puede deshacer.",
280
+ "confirm": "Fusionar"
281
+ },
263
282
  "implemented": "implementada",
264
283
  "module": "Módulo: {name}",
265
284
  "buildSteps": "Pasos de build",
@@ -445,6 +464,17 @@
445
464
  "mock": "Simulación (WireMock)",
446
465
  "remove": "Eliminar vinculación",
447
466
  "empty": "No hay vinculaciones de backend. Añade una para apuntar una variable de entorno a un servicio o a una simulación."
467
+ },
468
+ "preview": {
469
+ "open": "Abrir vista previa",
470
+ "start": "Iniciar vista previa",
471
+ "stop": "Detener",
472
+ "status": {
473
+ "starting": "Iniciando…",
474
+ "ready": "En ejecución",
475
+ "failed": "Error",
476
+ "stopped": "No iniciada"
477
+ }
448
478
  }
449
479
  },
450
480
  "releaseHealth": {
@@ -590,6 +620,16 @@
590
620
  "stopTooltip": "Detener la ejecución pero conservarla (legible y reintentable)",
591
621
  "reset": "Restablecer",
592
622
  "resetTooltip": "Descartar esta ejecución y restablecer la tarea a planificada",
623
+ "resetConfirm": {
624
+ "title": "¿Descartar esta ejecución?",
625
+ "body": "Esto elimina la ejecución y devuelve la tarea a planificada. Esto no se puede deshacer.",
626
+ "confirm": "Descartar ejecución"
627
+ },
628
+ "mergeConfirm": {
629
+ "title": "¿Fusionar esta pull request?",
630
+ "body": "Esto fusiona la PR en su rama base y completa la tarea. Esto no se puede deshacer.",
631
+ "confirm": "Fusionar"
632
+ },
593
633
  "viewDetailsOutput": "Ver detalles y leer la salida",
594
634
  "viewDetails": "Ver detalles del paso",
595
635
  "companion": "Acompañante",
@@ -681,6 +721,33 @@
681
721
  "noResult": "Aún no hay resultado.",
682
722
  "noResultHint": "La salida estructurada aparece cuando este agente termina. Mientras se ejecuta, el paso muestra el progreso en vivo en el tablero."
683
723
  },
724
+ "mergerResult": {
725
+ "title": "Decisión de fusión",
726
+ "titleWithBlock": "Decisión de fusión: {title}",
727
+ "description": "Cómo se puntuó el PR y qué decidió el motor.",
728
+ "outcome": {
729
+ "auto_merged": "Fusionado automáticamente",
730
+ "awaiting_review": "Esperando revisión humana"
731
+ },
732
+ "reason": {
733
+ "within_thresholds": "Todas las puntuaciones están dentro de los umbrales de {preset}, por lo que el PR se fusionó automáticamente.",
734
+ "exceeded_thresholds": "{axes} superó los umbrales de {preset}, por lo que el PR espera a que una persona lo fusione.",
735
+ "auto_merge_disabled": "El preajuste {preset} envía todos los PR a una persona, así que este espera revisión.",
736
+ "no_rationale": "El fusionador puntuó el PR pero no dio ninguna justificación, así que no se pudo confiar en el veredicto para fusionar automáticamente; el PR espera a que una persona lo fusione.",
737
+ "no_assessment": "El fusionador no devolvió una evaluación analizable, por lo que el PR espera a que una persona lo fusione.",
738
+ "merge_failed": "Las puntuaciones estaban dentro de los umbrales de {preset}, pero la fusión automática no pudo completarse (por ejemplo, protección de rama o un conflicto), por lo que el PR espera a que una persona lo fusione."
739
+ },
740
+ "scores": "Puntuaciones",
741
+ "axis": {
742
+ "complexity": "Complejidad",
743
+ "risk": "Riesgo",
744
+ "impact": "Impacto"
745
+ },
746
+ "ceiling": "límite {value}",
747
+ "rationale": "Justificación",
748
+ "noAssessment": "El fusionador no devolvió una evaluación puntuada.",
749
+ "noResult": "Aún no se ha registrado ninguna decisión de fusión."
750
+ },
684
751
  "testReport": {
685
752
  "title": "Informe de pruebas",
686
753
  "greenlit": "Aprobado",
@@ -1162,7 +1229,9 @@
1162
1229
  },
1163
1230
  "toast": {
1164
1231
  "acted": "Marcado como resuelto",
1165
- "dismissed": "Descartado"
1232
+ "dismissed": "Descartado",
1233
+ "actFailed": "No se pudo completar esa acción",
1234
+ "dismissFailed": "No se pudo descartar"
1166
1235
  }
1167
1236
  },
1168
1237
  "aiProvidersBanner": {
@@ -2563,6 +2632,10 @@
2563
2632
  "consensusRevertTooltip": "Consenso activado. Haz clic para volver a un solo agente.",
2564
2633
  "followUpEnableTooltip": "Compañero de seguimiento desactivado. Haz clic para activarlo (Coder detecta cabos sueltos / preguntas).",
2565
2634
  "followUpDisableTooltip": "Compañero de seguimiento activado. Coder detecta cabos sueltos / subtareas / preguntas; haz clic para desactivarlo.",
2635
+ "testerQualityEnableTooltip": "Compañero de calidad de pruebas desactivado. Haz clic para activarlo (audita la cobertura del informe y reitera el Tester ante lagunas).",
2636
+ "testerQualityDisableTooltip": "Compañero de calidad de pruebas activado. Audita la cobertura del informe antes de la aprobación y reitera el Tester ante lagunas; haz clic para desactivarlo.",
2637
+ "testerQualityLabel": "Compañero de calidad de pruebas",
2638
+ "testerQualityGateTooltip": "Ejecutar la auditoría de calidad solo cuando la estimación de la tarea supere un umbral (requiere un Estimador de Tareas antes)",
2566
2639
  "moveUp": "Subir el paso",
2567
2640
  "moveDown": "Bajar el paso",
2568
2641
  "removeStep": "Quitar este paso del pipeline",
@@ -3204,6 +3277,15 @@
3204
3277
  "failed": "Falló",
3205
3278
  "addressed": "Abordando"
3206
3279
  },
3280
+ "quality": {
3281
+ "heading": "Revisión de cobertura",
3282
+ "reruns": "Reejecuciones del Tester impulsadas por calidad",
3283
+ "rerunCount": "{attempts}/{max} reejecuciones",
3284
+ "exceeded": "Presupuesto agotado",
3285
+ "adequate": "Cobertura adecuada",
3286
+ "inadequate": "Se encontraron lagunas de cobertura",
3287
+ "gaps": "Lagunas por cerrar"
3288
+ },
3207
3289
  "empty": {
3208
3290
  "title": "Aún no hay informe de pruebas.",
3209
3291
  "hint": "El informe aparece cuando el Tester termina una pasada. Mientras se ejecuta, el paso muestra el progreso en vivo en el tablero."
@@ -3664,6 +3746,7 @@
3664
3746
  },
3665
3747
  "targetRepo": {
3666
3748
  "label": "Nombre del repositorio de destino",
3749
+ "namePlaceholder": "payments-service",
3667
3750
  "descWithOwner": "Crea un repositorio nuevo con este nombre bajo {owner} y luego la inicialización hace push a él. Un README, .gitignore o licencia ya creados están bien.",
3668
3751
  "descNoOwner": "Crea un repositorio nuevo con este nombre y luego la inicialización hace push a él. Un README, .gitignore o licencia ya creados están bien."
3669
3752
  },
@@ -3679,7 +3762,8 @@
3679
3762
  },
3680
3763
  "description": {
3681
3764
  "label": "Descripción",
3682
- "help": "Resumen opcional de una línea para el repositorio."
3765
+ "help": "Resumen opcional de una línea para el repositorio.",
3766
+ "placeholder": "Gestiona intenciones de pago y reembolsos"
3683
3767
  },
3684
3768
  "instructions": {
3685
3769
  "labelReference": "Instrucciones adicionales para el inicializador",
@@ -3709,18 +3793,23 @@
3709
3793
  "add": "Añadir",
3710
3794
  "pickRepo": {
3711
3795
  "label": "Elige un repositorio de GitHub existente",
3712
- "description": "Elige un repositorio al que tengas acceso para rellenar su propietario y nombre, o introdúcelos manualmente abajo."
3796
+ "description": "Elige un repositorio al que tengas acceso para rellenar su propietario y nombre, o introdúcelos manualmente abajo.",
3797
+ "placeholder": "owner/name"
3713
3798
  },
3714
3799
  "name": {
3715
3800
  "label": "Nombre",
3716
- "description": "Una etiqueta descriptiva para esta base."
3801
+ "description": "Una etiqueta descriptiva para esta base.",
3802
+ "placeholder": "Plantilla de servicio"
3717
3803
  },
3718
3804
  "repoOwner": "Propietario del repositorio",
3805
+ "repoOwnerPlaceholder": "acme",
3719
3806
  "repoName": "Nombre del repositorio",
3807
+ "repoNamePlaceholder": "service-template",
3720
3808
  "descriptionPlaceholder": "Resumen opcional de esta base",
3721
3809
  "defaultInstructions": {
3722
3810
  "label": "Instrucciones por defecto del inicializador",
3723
- "description": "Se anteponen a las instrucciones de cada ejecución siempre que se use esta base."
3811
+ "description": "Se anteponen a las instrucciones de cada ejecución siempre que se use esta base.",
3812
+ "placeholder": "p. ej. mantén la estructura; renombra los paquetes para que coincidan con el nuevo servicio"
3724
3813
  }
3725
3814
  },
3726
3815
  "toast": {
@@ -1,4 +1,10 @@
1
1
  {
2
+ "app": {
3
+ "loading": "Chargement…",
4
+ "loadingBoard": "Chargement du tableau…",
5
+ "backendUnreachable": "Impossible de joindre le backend",
6
+ "reconnecting": "Reconnexion…"
7
+ },
2
8
  "language": {
3
9
  "switcher": "Langue",
4
10
  "warning": {
@@ -68,6 +74,14 @@
68
74
  "infrastructure": "Infrastructure"
69
75
  },
70
76
  "board": {
77
+ "toast": {
78
+ "updateFailed": "Impossible d'enregistrer les modifications",
79
+ "epicFailed": "Impossible de changer l'épopée",
80
+ "moveFailed": "Impossible de déplacer",
81
+ "deleteFailed": "Impossible de supprimer",
82
+ "linkFailed": "Impossible de lier les tâches",
83
+ "recurringDeleteFailed": "Impossible de supprimer le pipeline récurrent"
84
+ },
71
85
  "repoTypes": {
72
86
  "service": "Service",
73
87
  "frontend": "Frontend",
@@ -260,6 +274,11 @@
260
274
  "openPrOnGithub": "Ouvrir {pr} sur GitHub",
261
275
  "review": "Revoir",
262
276
  "merge": "Fusionner",
277
+ "mergeConfirm": {
278
+ "title": "Fusionner cette pull request ?",
279
+ "body": "Cela fusionne la PR dans sa branche de base et termine la tâche. Cette action est irréversible.",
280
+ "confirm": "Fusionner"
281
+ },
263
282
  "implemented": "implémentée",
264
283
  "module": "Module : {name}",
265
284
  "buildSteps": "Étapes de build",
@@ -445,6 +464,17 @@
445
464
  "mock": "Simulation (WireMock)",
446
465
  "remove": "Supprimer la liaison",
447
466
  "empty": "Aucune liaison de backend. Ajoutez-en une pour pointer une variable d'environnement vers un service ou une simulation."
467
+ },
468
+ "preview": {
469
+ "open": "Ouvrir l'aperçu",
470
+ "start": "Démarrer l'aperçu",
471
+ "stop": "Arrêter",
472
+ "status": {
473
+ "starting": "Démarrage…",
474
+ "ready": "En cours",
475
+ "failed": "Échec",
476
+ "stopped": "Non démarré"
477
+ }
448
478
  }
449
479
  },
450
480
  "releaseHealth": {
@@ -590,6 +620,16 @@
590
620
  "stopTooltip": "Arrêter l'exécution mais la conserver (lisible et relançable)",
591
621
  "reset": "Réinitialiser",
592
622
  "resetTooltip": "Abandonner cette exécution et réinitialiser la tâche à planifiée",
623
+ "resetConfirm": {
624
+ "title": "Abandonner cette exécution ?",
625
+ "body": "Cela supprime l'exécution et ramène la tâche à planifiée. Cette action est irréversible.",
626
+ "confirm": "Abandonner l'exécution"
627
+ },
628
+ "mergeConfirm": {
629
+ "title": "Fusionner cette pull request ?",
630
+ "body": "Cela fusionne la PR dans sa branche de base et termine la tâche. Cette action est irréversible.",
631
+ "confirm": "Fusionner"
632
+ },
593
633
  "viewDetailsOutput": "Voir les détails et lire la sortie",
594
634
  "viewDetails": "Voir les détails de l'étape",
595
635
  "companion": "Compagnon",
@@ -681,6 +721,33 @@
681
721
  "noResult": "Pas encore de résultat.",
682
722
  "noResultHint": "La sortie structurée apparaît une fois que cet agent a terminé. Pendant son exécution, l'étape affiche sa progression en direct sur le tableau."
683
723
  },
724
+ "mergerResult": {
725
+ "title": "Décision de fusion",
726
+ "titleWithBlock": "Décision de fusion : {title}",
727
+ "description": "Comment la PR a été évaluée et ce que le moteur a décidé.",
728
+ "outcome": {
729
+ "auto_merged": "Fusionnée automatiquement",
730
+ "awaiting_review": "En attente de revue humaine"
731
+ },
732
+ "reason": {
733
+ "within_thresholds": "Tous les scores sont dans les seuils de {preset}, la PR a donc été fusionnée automatiquement.",
734
+ "exceeded_thresholds": "{axes} a dépassé les seuils de {preset}, la PR attend donc une fusion par une personne.",
735
+ "auto_merge_disabled": "Le préréglage {preset} envoie chaque PR à une personne ; celle-ci attend donc une revue.",
736
+ "no_rationale": "Le fusionneur a évalué la PR mais n'a donné aucune justification, le verdict n'a donc pas pu être approuvé pour une fusion automatique ; la PR attend une fusion par une personne.",
737
+ "no_assessment": "Le fusionneur n'a pas renvoyé d'évaluation exploitable, la PR attend donc une fusion par une personne.",
738
+ "merge_failed": "Les scores étaient dans les seuils de {preset}, mais la fusion automatique n'a pas pu aboutir (par exemple protection de branche ou conflit), la PR attend donc une fusion par une personne."
739
+ },
740
+ "scores": "Scores",
741
+ "axis": {
742
+ "complexity": "Complexité",
743
+ "risk": "Risque",
744
+ "impact": "Impact"
745
+ },
746
+ "ceiling": "plafond {value}",
747
+ "rationale": "Justification",
748
+ "noAssessment": "Le fusionneur n'a pas renvoyé d'évaluation chiffrée.",
749
+ "noResult": "Aucune décision de fusion enregistrée pour le moment."
750
+ },
684
751
  "testReport": {
685
752
  "title": "Rapport de test",
686
753
  "greenlit": "Validé",
@@ -1162,7 +1229,9 @@
1162
1229
  },
1163
1230
  "toast": {
1164
1231
  "acted": "Marqué comme traité",
1165
- "dismissed": "Ignoré"
1232
+ "dismissed": "Ignoré",
1233
+ "actFailed": "Impossible de terminer cette action",
1234
+ "dismissFailed": "Impossible d'ignorer"
1166
1235
  }
1167
1236
  },
1168
1237
  "aiProvidersBanner": {
@@ -2563,6 +2632,10 @@
2563
2632
  "consensusRevertTooltip": "Consensus activé. Cliquez pour revenir à un seul agent.",
2564
2633
  "followUpEnableTooltip": "Compagnon de suivi désactivé. Cliquez pour l'activer (Coder repère les points en suspens / questions).",
2565
2634
  "followUpDisableTooltip": "Compagnon de suivi activé. Coder repère les points en suspens / sous-tâches / questions ; cliquez pour le désactiver.",
2635
+ "testerQualityEnableTooltip": "Compagnon de qualité des tests désactivé. Cliquez pour l'activer (audite la couverture du rapport et relance le Testeur en cas de lacunes).",
2636
+ "testerQualityDisableTooltip": "Compagnon de qualité des tests activé. Audite la couverture du rapport avant le feu vert et relance le Testeur en cas de lacunes ; cliquez pour le désactiver.",
2637
+ "testerQualityLabel": "Compagnon de qualité des tests",
2638
+ "testerQualityGateTooltip": "N'exécuter l'audit de qualité que lorsque l'estimation de la tâche dépasse un seuil (nécessite un Estimateur de tâches en amont)",
2566
2639
  "moveUp": "Monter l'étape",
2567
2640
  "moveDown": "Descendre l'étape",
2568
2641
  "removeStep": "Retirer cette étape du pipeline",
@@ -3204,6 +3277,15 @@
3204
3277
  "failed": "Échec",
3205
3278
  "addressed": "Corrige"
3206
3279
  },
3280
+ "quality": {
3281
+ "heading": "Revue de couverture",
3282
+ "reruns": "Relances du Testeur pilotées par la qualité",
3283
+ "rerunCount": "{attempts}/{max} relances",
3284
+ "exceeded": "Budget épuisé",
3285
+ "adequate": "Couverture adéquate",
3286
+ "inadequate": "Lacunes de couverture détectées",
3287
+ "gaps": "Lacunes à combler"
3288
+ },
3207
3289
  "empty": {
3208
3290
  "title": "Aucun rapport de tests pour l'instant.",
3209
3291
  "hint": "Le rapport apparaît une fois que le Testeur a terminé une passe. Pendant son exécution, l'étape affiche la progression en direct sur le tableau."
@@ -3664,6 +3746,7 @@
3664
3746
  },
3665
3747
  "targetRepo": {
3666
3748
  "label": "Nom du dépôt cible",
3749
+ "namePlaceholder": "payments-service",
3667
3750
  "descWithOwner": "Créez un nouveau dépôt portant ce nom sous {owner}, puis l'initialisation y pousse. Un README, un .gitignore ou une licence préremplis conviennent.",
3668
3751
  "descNoOwner": "Créez un nouveau dépôt portant ce nom, puis l'initialisation y pousse. Un README, un .gitignore ou une licence préremplis conviennent."
3669
3752
  },
@@ -3679,7 +3762,8 @@
3679
3762
  },
3680
3763
  "description": {
3681
3764
  "label": "Description",
3682
- "help": "Résumé facultatif en une ligne pour le dépôt."
3765
+ "help": "Résumé facultatif en une ligne pour le dépôt.",
3766
+ "placeholder": "Gère les intentions de paiement et les remboursements"
3683
3767
  },
3684
3768
  "instructions": {
3685
3769
  "labelReference": "Instructions supplémentaires pour l'initialiseur",
@@ -3709,18 +3793,23 @@
3709
3793
  "add": "Ajouter",
3710
3794
  "pickRepo": {
3711
3795
  "label": "Choisir un dépôt GitHub existant",
3712
- "description": "Choisissez un dépôt auquel vous avez accès pour renseigner son propriétaire et son nom, ou saisissez-les manuellement ci-dessous."
3796
+ "description": "Choisissez un dépôt auquel vous avez accès pour renseigner son propriétaire et son nom, ou saisissez-les manuellement ci-dessous.",
3797
+ "placeholder": "owner/name"
3713
3798
  },
3714
3799
  "name": {
3715
3800
  "label": "Nom",
3716
- "description": "Un libellé convivial pour cette base."
3801
+ "description": "Un libellé convivial pour cette base.",
3802
+ "placeholder": "Modèle de service"
3717
3803
  },
3718
3804
  "repoOwner": "Propriétaire du dépôt",
3805
+ "repoOwnerPlaceholder": "acme",
3719
3806
  "repoName": "Nom du dépôt",
3807
+ "repoNamePlaceholder": "service-template",
3720
3808
  "descriptionPlaceholder": "Résumé facultatif de cette base",
3721
3809
  "defaultInstructions": {
3722
3810
  "label": "Instructions d'initialisation par défaut",
3723
- "description": "Ajoutées avant les instructions de chaque exécution chaque fois que cette base est utilisée."
3811
+ "description": "Ajoutées avant les instructions de chaque exécution chaque fois que cette base est utilisée.",
3812
+ "placeholder": "p. ex. conserver la structure ; renommer les paquets pour correspondre au nouveau service"
3724
3813
  }
3725
3814
  },
3726
3815
  "toast": {