@cat-factory/app 0.169.0 → 0.171.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.
package/README.md CHANGED
@@ -56,9 +56,10 @@ over the WebSocket. How that sync works is written up in
56
56
  ## Interface modes (basic / advanced)
57
57
 
58
58
  The SPA renders at one of two **interface tiers**. `basic` (the default) is the everyday
59
- surface: the power-user nav destinations are hidden and the run/pipeline options that only
60
- exist to override a workspace-level default are left at that default. `advanced` shows
61
- everything. The tier resolves in a fixed order, first match wins:
59
+ surface: the run/pipeline options that only exist to override a workspace-level default are
60
+ left at that default, and the nav is trimmed to the destinations that are the **only route**
61
+ to their capability. `advanced` shows everything. The tier resolves in a fixed order, first
62
+ match wins:
62
63
 
63
64
  1. **`NUXT_PUBLIC_UI_MODE`** (`basic` | `advanced`) — the deployment pin. Like
64
65
  `NUXT_PUBLIC_API_BASE` it is baked in at **build** time (`ssr: false`), and while it is
@@ -81,7 +82,15 @@ hoc where it can be avoided:
81
82
  - **A nav destination** declares `advanced: true` in `app/modular/nav-contributions.ts`. The
82
83
  shared `navSlotFilter` drops it in basic mode across all three shells (sidebar, command
83
84
  palette, toolbar), independently of its RBAC `gate` — both must pass. A consumer module's
84
- own contributions take the same flag.
85
+ own contributions take the same flag. The bar for setting it is **route count, not how
86
+ advanced the surface feels**: hiding the only way to reach a capability removes the
87
+ capability from the tier, while hiding a shortcut into a surface a basic destination also
88
+ opens removes nothing. So the flag belongs on a surface that sits beside the delivery path
89
+ (Sandbox, Kaizen), on a palette shortcut into a Workspace-settings tab, or on a knob the
90
+ Integrations hub already offers — and never on a sole route (the pipeline builder, the
91
+ fragment library, the infrastructure/PREnv windows, the operator + reports views).
92
+ `nav-contributions.spec.ts` pins the advanced set against a table of each item's
93
+ alternative route, so promoting one forces that claim to be written down.
85
94
  - **A less-used option inside a surface** reads `useUiModeStore().isAdvanced`. Hide, never
86
95
  disable, and only ever hide an OVERRIDE: what remains must be exactly the default the hidden
87
96
  field would have shown, so a basic-mode user never gets different behaviour from an advanced
@@ -36,20 +36,33 @@ const meta = computed(() => agentKindMeta('ralph'))
36
36
 
37
37
  // Iterations, newest-first for the timeline.
38
38
  const attempts = computed(() => [...(ralph.value?.attemptLog ?? [])].reverse())
39
+ // How many earlier iterations the backend's log cap dropped (0 when the history is complete).
40
+ const droppedAttempts = computed(() => ralph.value?.droppedAttempts ?? 0)
39
41
 
40
42
  /**
41
43
  * The display status, rolled up from the persisted loop state + the run status:
42
44
  * - `passed` — the step finished (the validation command exited 0);
43
- * - `gave-up` — the run failed here (the iteration budget was spent);
45
+ * - `stalled` — the run failed here BEFORE the budget ran out, because consecutive iterations
46
+ * stopped changing the branch;
47
+ * - `gave-up` — the run failed here with the iteration budget spent;
44
48
  * - `running` — an iteration is in flight;
45
49
  * - `failing` — the last validation failed and another iteration is about to run.
50
+ *
51
+ * The stall is derived from "ended short of the budget" rather than from the streak count, so
52
+ * the view never has to keep a copy of the engine's no-progress limit in step with it. Telling
53
+ * the two apart matters: a loop that stopped at 3 of 20 reads as an unexplained give-up
54
+ * otherwise, and the fix for a stall (change the task or the command) is not the fix for a
55
+ * spent budget (give it more room).
46
56
  */
47
- type RalphDisplayStatus = 'passed' | 'gave-up' | 'running' | 'failing'
57
+ type RalphDisplayStatus = 'passed' | 'stalled' | 'gave-up' | 'running' | 'failing'
48
58
  const status = computed<RalphDisplayStatus>(() => {
49
59
  const s = step.value
50
60
  if (!s) return 'running'
51
61
  if (s.state === 'done') return 'passed'
52
- if (instance.value?.status === 'failed') return 'gave-up'
62
+ if (instance.value?.status === 'failed') {
63
+ const r = ralph.value
64
+ return r && r.attempts > 0 && r.attempts < r.maxIterations ? 'stalled' : 'gave-up'
65
+ }
53
66
  if (s.container?.status === 'starting' || s.container?.status === 'up') return 'running'
54
67
  return 'failing'
55
68
  })
@@ -71,6 +84,12 @@ const STATUS_META = computed<
71
84
  icon: 'i-lucide-circle-check',
72
85
  text: 'text-emerald-300',
73
86
  },
87
+ stalled: {
88
+ label: t('ralph.status.stalled'),
89
+ badge: 'error',
90
+ icon: 'i-lucide-circle-slash',
91
+ text: 'text-rose-300',
92
+ },
74
93
  'gave-up': {
75
94
  label: t('ralph.status.gaveUp'),
76
95
  badge: 'error',
@@ -162,11 +181,30 @@ const STATUS_META = computed<
162
181
  <UIcon name="i-lucide-external-link" class="h-3 w-3" />
163
182
  </a>
164
183
 
184
+ <!-- Why a loop that stopped short of its budget stopped: without this the count in
185
+ the sidebar (e.g. "3 of 20") reads as an unexplained abandonment. -->
186
+ <p
187
+ v-if="status === 'stalled'"
188
+ class="mt-3 rounded-md border border-rose-900/60 bg-rose-950/30 px-3 py-2 text-[12px] leading-relaxed text-rose-200"
189
+ data-testid="ralph-stalled-note"
190
+ >
191
+ {{ t('ralph.stalledNote') }}
192
+ </p>
193
+
165
194
  <!-- Iteration history: what each pass produced and whether its validation passed. -->
166
195
  <section v-if="attempts.length" class="mt-5">
167
196
  <h3 class="mb-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
168
197
  {{ t('ralph.iterationsHeading') }}
169
198
  </h3>
199
+ <!-- The log is capped (it rides the run's detail blob); say so rather than letting a
200
+ long loop's partial history read as if those iterations never ran. -->
201
+ <p
202
+ v-if="droppedAttempts"
203
+ class="mb-2 text-[11px] text-slate-500"
204
+ data-testid="ralph-iterations-truncated"
205
+ >
206
+ {{ t('ralph.iterationsTruncated', { count: droppedAttempts }, droppedAttempts) }}
207
+ </p>
170
208
  <ol class="space-y-2">
171
209
  <li
172
210
  v-for="a in attempts"
@@ -99,11 +99,36 @@ describe('navSlotFilter', () => {
99
99
  expect(kept).toContain('integrations-hub')
100
100
  expect(kept).toContain('workspace-settings')
101
101
  expect(kept).toContain('model-config')
102
- // ...and the authoring / operator surfaces don't.
103
- expect(kept).not.toContain('build-pipeline')
104
- expect(kept).not.toContain('fragments')
102
+ // ...and so does every destination that is the SOLE route to its capability, however deep
103
+ // it feels: authoring a flow, the standards library, the PREnv/runner plumbing, and the
104
+ // aggregate run-health / spend views.
105
+ expect(kept).toContain('build-pipeline')
106
+ expect(kept).toContain('fragments')
107
+ expect(kept).toContain('infrastructure')
108
+ expect(kept).toContain('environment-setup')
109
+ expect(kept).toContain('operator-dashboard')
110
+ expect(kept).toContain('reports')
111
+ // What drops is beside the delivery path (experimentation) or a shortcut into a surface
112
+ // basic mode already reaches another way.
105
113
  expect(kept).not.toContain('sandbox')
106
- expect(kept).not.toContain('operator-dashboard')
114
+ expect(kept).not.toContain('kaizen')
115
+ expect(kept).not.toContain('merge-thresholds')
116
+ })
117
+
118
+ it('never makes an advanced item the only route to its capability', () => {
119
+ // The tier's governing rule (see the catalog comment): every advanced destination either
120
+ // sits beside the delivery path, or is a shortcut into a surface a basic destination also
121
+ // opens. Spelled out here as a table so promoting an item to `advanced` forces an explicit
122
+ // claim about how basic mode still reaches it, rather than a silent capability loss.
123
+ const ALTERNATIVE_ROUTE: Record<string, string> = {
124
+ sandbox: 'none needed - experimentation surface, not on the delivery path',
125
+ kaizen: 'none needed - self-grading history, not on the delivery path',
126
+ 'merge-thresholds': 'workspace-settings -> Merge tab',
127
+ 'service-fragment-defaults': 'workspace-settings -> Service best practices tab',
128
+ 'local-models': 'integrations-hub -> Local runners',
129
+ }
130
+ const advanced = NAV_CONTRIBUTIONS.filter((i) => i.advanced).map((i) => i.id)
131
+ expect(advanced.sort()).toEqual(Object.keys(ALTERNATIVE_ROUTE).sort())
107
132
  })
108
133
 
109
134
  it('keeps the tier switch itself reachable in basic mode', () => {
@@ -119,15 +144,19 @@ describe('navSlotFilter', () => {
119
144
  })
120
145
 
121
146
  it('keeps the tier and the permission axes independent — both must pass', () => {
122
- // `build-pipeline` is advanced AND needs board.write: neither axis alone reveals it.
147
+ // `sandbox` is advanced AND needs integrations.manage: neither axis alone reveals it.
123
148
  const advancedOnly: NavGates = { ...NO_GATES, advancedMode: true }
124
- expect(ids(navSlotFilter(slots(), { gates: advancedOnly }))).not.toContain('build-pipeline')
149
+ expect(ids(navSlotFilter(slots(), { gates: advancedOnly }))).not.toContain('sandbox')
125
150
 
126
- const permissionOnly: NavGates = { ...NO_GATES, canWriteBoard: true, advancedMode: false }
127
- expect(ids(navSlotFilter(slots(), { gates: permissionOnly }))).not.toContain('build-pipeline')
151
+ const permissionOnly: NavGates = {
152
+ ...NO_GATES,
153
+ canManageIntegrations: true,
154
+ advancedMode: false,
155
+ }
156
+ expect(ids(navSlotFilter(slots(), { gates: permissionOnly }))).not.toContain('sandbox')
128
157
 
129
- const both: NavGates = { ...NO_GATES, canWriteBoard: true, advancedMode: true }
130
- expect(ids(navSlotFilter(slots(), { gates: both }))).toContain('build-pipeline')
158
+ const both: NavGates = { ...NO_GATES, canManageIntegrations: true, advancedMode: true }
159
+ expect(ids(navSlotFilter(slots(), { gates: both }))).toContain('sandbox')
131
160
  })
132
161
 
133
162
  it('leaves at least one sidebar destination in every basic-mode section it keeps', () => {
@@ -153,13 +153,24 @@ const S = (...s: NavSurface[]) => s as readonly NavSurface[]
153
153
  * with accounts enabled).
154
154
  * - one icon per destination across shells.
155
155
  *
156
- * `advanced: true` marks the power-user half, hidden in basic interface mode. The line
157
- * drawn here is "would a team shipping their first task open this?": connecting a repo or
158
- * an integration, picking models, and the workspace/account settings stay; AUTHORING the
159
- * machinery those defaults come from (the pipeline builder, the fragment library, merge
160
- * thresholds, service fragment defaults), the experimentation surfaces (sandbox, Kaizen),
161
- * the infrastructure/environment plumbing, per-user local models, and the operator-tier
162
- * dashboards do not.
156
+ * `advanced: true` marks the power-user half, hidden in basic interface mode. The line is
157
+ * drawn by ROUTE COUNT, not by how advanced a surface feels: hiding the only way to reach a
158
+ * capability removes the capability from the tier, while hiding a shortcut to a surface basic
159
+ * mode already reaches removes nothing. So an item is advanced only when both of these hold —
160
+ * it is not the sole route to its capability, and nothing on the delivery path needs it:
161
+ *
162
+ * - `sandbox` / `kaizen` — experimentation and self-grading surfaces, beside the delivery
163
+ * path rather than on it.
164
+ * - `merge-thresholds` / `service-fragment-defaults` — palette shortcuts into Workspace
165
+ * settings tabs (Merge, Service best practices), which basic mode reaches via
166
+ * `workspace-settings`.
167
+ * - `local-models` — a per-user endpoint knob the Integrations hub already offers.
168
+ *
169
+ * Everything else stays in basic BECAUSE it is a sole route: authoring a flow
170
+ * (`build-pipeline`), the standards/skills library (`fragments`, whose only other route is a
171
+ * button two levels into Workspace settings), the PREnv + runner plumbing (`infrastructure`,
172
+ * `environment-setup`), and the operator/cost views that are the only aggregate read of run
173
+ * health and spend (`operator-dashboard`, `reports`).
163
174
  */
164
175
  export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
165
176
  {
@@ -167,7 +178,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
167
178
  labelKey: 'nav.buildPipeline',
168
179
  icon: 'i-lucide-workflow',
169
180
  surfaces: S('sidebar', 'command'),
170
- advanced: true,
171
181
  gate: (g) => g.canWriteBoard,
172
182
  action: 'buildPipeline',
173
183
  testId: 'nav-build-pipeline',
@@ -253,7 +263,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
253
263
  labelKey: 'nav.infrastructure',
254
264
  icon: 'i-lucide-server-cog',
255
265
  surfaces: S('sidebar'),
256
- advanced: true,
257
266
  gate: (g) => g.infrastructureAvailable,
258
267
  action: 'infrastructure',
259
268
  testId: 'nav-infrastructure',
@@ -264,7 +273,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
264
273
  labelKey: 'nav.environmentSetup',
265
274
  icon: 'i-lucide-flask-conical',
266
275
  surfaces: S('sidebar'),
267
- advanced: true,
268
276
  gate: (g) => g.infrastructureAvailable,
269
277
  action: 'environmentSetup',
270
278
  testId: 'nav-environment-setup',
@@ -275,7 +283,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
275
283
  labelKey: 'nav.contextFragments',
276
284
  icon: 'i-lucide-book-marked',
277
285
  surfaces: S('sidebar', 'command'),
278
- advanced: true,
279
286
  gate: (g) => g.libraryAvailable && g.canManageSettings,
280
287
  action: 'fragmentLibrary',
281
288
  testId: 'nav-fragments',
@@ -381,7 +388,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
381
388
  labelKey: 'nav.operatorDashboard',
382
389
  icon: 'i-lucide-gauge',
383
390
  surfaces: S('sidebar'),
384
- advanced: true,
385
391
  gate: (g) => g.accountsEnabled && g.isAccountAdmin,
386
392
  action: 'operatorDashboard',
387
393
  testId: 'nav-operator-dashboard',
@@ -392,7 +398,6 @@ export const NAV_CONTRIBUTIONS: readonly NavContribution[] = [
392
398
  labelKey: 'nav.reports',
393
399
  icon: 'i-lucide-chart-column',
394
400
  surfaces: S('sidebar'),
395
- advanced: true,
396
401
  gate: (g) => g.accountsEnabled && g.isAccountAdmin,
397
402
  action: 'reports',
398
403
  testId: 'nav-reports',
@@ -5423,6 +5423,7 @@
5423
5423
  "subtitle": "Eine dauerhafte Schleife: Aufgabe bearbeiten, Validierungsbefehl ausführen und wiederholen, bis er erfolgreich ist.",
5424
5424
  "status": {
5425
5425
  "passed": "Bestanden",
5426
+ "stalled": "Blockiert",
5426
5427
  "gaveUp": "Aufgegeben",
5427
5428
  "running": "Läuft",
5428
5429
  "failing": "Fehlgeschlagen"
@@ -5431,7 +5432,9 @@
5431
5432
  "validationCommand": "Validierungsbefehl",
5432
5433
  "lastOutput": "Letzte Validierung (Exit {exit})",
5433
5434
  "viewPr": "Pull Request ansehen",
5435
+ "stalledNote": "Die Schleife wurde vorzeitig beendet: Aufeinanderfolgende Iterationen haben den Branch nicht verändert und der Validierungsbefehl schlägt weiterhin fehl, daher wurde das restliche Budget nicht verbraucht. Wahrscheinlich muss die Aufgabe oder der Validierungsbefehl geändert werden, bevor ein erneuter Versuch hilft.",
5434
5436
  "iterationsHeading": "Iterationen",
5437
+ "iterationsTruncated": "{count} frühere Iteration wird nicht angezeigt (der Verlauf ist begrenzt). | {count} frühere Iterationen werden nicht angezeigt (der Verlauf ist begrenzt).",
5435
5438
  "iteration": "Iteration {number}",
5436
5439
  "iterationPassed": "Validierung bestanden",
5437
5440
  "iterationFailed": "Exit {exit}",
@@ -5573,6 +5573,7 @@
5573
5573
  "subtitle": "A persistent loop: work the task, run the validation command, and repeat until it passes.",
5574
5574
  "status": {
5575
5575
  "passed": "Passed",
5576
+ "stalled": "Stalled",
5576
5577
  "gaveUp": "Gave up",
5577
5578
  "running": "Running",
5578
5579
  "failing": "Failing"
@@ -5581,7 +5582,9 @@
5581
5582
  "validationCommand": "Validation command",
5582
5583
  "lastOutput": "Latest validation (exit {exit})",
5583
5584
  "viewPr": "View pull request",
5585
+ "stalledNote": "The loop stopped early: consecutive iterations left the branch unchanged and the validation command still fails, so it did not spend the rest of its budget. The task or the validation command likely needs a change before a retry can help.",
5584
5586
  "iterationsHeading": "Iterations",
5587
+ "iterationsTruncated": "{count} earlier iteration is not shown (the history is capped). | {count} earlier iterations are not shown (the history is capped).",
5585
5588
  "iteration": "Iteration {number}",
5586
5589
  "iterationPassed": "validation passed",
5587
5590
  "iterationFailed": "exit {exit}",
@@ -5411,6 +5411,7 @@
5411
5411
  "subtitle": "Un bucle persistente: trabaja la tarea, ejecuta el comando de validación y repite hasta que pase.",
5412
5412
  "status": {
5413
5413
  "passed": "Superado",
5414
+ "stalled": "Estancado",
5414
5415
  "gaveUp": "Abandonado",
5415
5416
  "running": "En ejecución",
5416
5417
  "failing": "Fallando"
@@ -5419,7 +5420,9 @@
5419
5420
  "validationCommand": "Comando de validación",
5420
5421
  "lastOutput": "Última validación (salida {exit})",
5421
5422
  "viewPr": "Ver pull request",
5423
+ "stalledNote": "El bucle se detuvo antes de tiempo: iteraciones consecutivas dejaron la rama sin cambios y el comando de validación sigue fallando, por lo que no gastó el resto de su presupuesto. Probablemente haya que cambiar la tarea o el comando de validación para que un reintento sirva de algo.",
5422
5424
  "iterationsHeading": "Iteraciones",
5425
+ "iterationsTruncated": "No se muestra {count} iteración anterior (el historial está limitado). | No se muestran {count} iteraciones anteriores (el historial está limitado).",
5423
5426
  "iteration": "Iteración {number}",
5424
5427
  "iterationPassed": "validación superada",
5425
5428
  "iterationFailed": "salida {exit}",
@@ -5411,6 +5411,7 @@
5411
5411
  "subtitle": "Une boucle persistante : traiter la tâche, exécuter la commande de validation, et recommencer jusqu'à ce qu'elle réussisse.",
5412
5412
  "status": {
5413
5413
  "passed": "Réussi",
5414
+ "stalled": "Bloquée",
5414
5415
  "gaveUp": "Abandonné",
5415
5416
  "running": "En cours",
5416
5417
  "failing": "En échec"
@@ -5419,7 +5420,9 @@
5419
5420
  "validationCommand": "Commande de validation",
5420
5421
  "lastOutput": "Dernière validation (code {exit})",
5421
5422
  "viewPr": "Voir la pull request",
5423
+ "stalledNote": "La boucle s'est arrêtée prématurément : des itérations consécutives ont laissé la branche inchangée et la commande de validation échoue toujours, elle n'a donc pas consommé le reste de son budget. La tâche ou la commande de validation doit probablement être modifiée pour qu'une relance serve à quelque chose.",
5422
5424
  "iterationsHeading": "Itérations",
5425
+ "iterationsTruncated": "{count} itération antérieure n'est pas affichée (l'historique est plafonné). | {count} itérations antérieures ne sont pas affichées (l'historique est plafonné).",
5423
5426
  "iteration": "Itération {number}",
5424
5427
  "iterationPassed": "validation réussie",
5425
5428
  "iterationFailed": "code {exit}",
@@ -5422,6 +5422,7 @@
5422
5422
  "subtitle": "לולאה מתמשכת: לעבוד על המשימה, להריץ את פקודת האימות, ולחזור עד שהיא עוברת.",
5423
5423
  "status": {
5424
5424
  "passed": "עבר",
5425
+ "stalled": "נתקע",
5425
5426
  "gaveUp": "ויתר",
5426
5427
  "running": "פועל",
5427
5428
  "failing": "נכשל"
@@ -5430,7 +5431,9 @@
5430
5431
  "validationCommand": "פקודת אימות",
5431
5432
  "lastOutput": "אימות אחרון (יציאה {exit})",
5432
5433
  "viewPr": "הצג בקשת משיכה",
5434
+ "stalledNote": "הלולאה נעצרה מוקדם: איטרציות רצופות לא שינו את הענף ופקודת האימות עדיין נכשלת, ולכן היא לא ניצלה את שארית התקציב. כנראה שצריך לשנות את המשימה או את פקודת האימות לפני שניסיון חוזר יועיל.",
5433
5435
  "iterationsHeading": "איטרציות",
5436
+ "iterationsTruncated": "איטרציה קודמת אחת אינה מוצגת (ההיסטוריה מוגבלת). | {count} איטרציות קודמות אינן מוצגות (ההיסטוריה מוגבלת).",
5434
5437
  "iteration": "איטרציה {number}",
5435
5438
  "iterationPassed": "האימות עבר",
5436
5439
  "iterationFailed": "יציאה {exit}",
@@ -5423,6 +5423,7 @@
5423
5423
  "subtitle": "Un ciclo persistente: lavora sull'attività, esegui il comando di validazione e ripeti finché non passa.",
5424
5424
  "status": {
5425
5425
  "passed": "Superato",
5426
+ "stalled": "In stallo",
5426
5427
  "gaveUp": "Interrotto",
5427
5428
  "running": "In esecuzione",
5428
5429
  "failing": "In errore"
@@ -5431,7 +5432,9 @@
5431
5432
  "validationCommand": "Comando di validazione",
5432
5433
  "lastOutput": "Ultima validazione (uscita {exit})",
5433
5434
  "viewPr": "Visualizza pull request",
5435
+ "stalledNote": "Il ciclo si è fermato in anticipo: iterazioni consecutive hanno lasciato il branch invariato e il comando di validazione continua a fallire, quindi non ha consumato il resto del budget. Probabilmente occorre modificare il task o il comando di validazione prima che un nuovo tentativo possa servire.",
5434
5436
  "iterationsHeading": "Iterazioni",
5437
+ "iterationsTruncated": "{count} iterazione precedente non è mostrata (la cronologia è limitata). | {count} iterazioni precedenti non sono mostrate (la cronologia è limitata).",
5435
5438
  "iteration": "Iterazione {number}",
5436
5439
  "iterationPassed": "validazione superata",
5437
5440
  "iterationFailed": "uscita {exit}",
@@ -5423,6 +5423,7 @@
5423
5423
  "subtitle": "永続的なループ:タスクを進め、検証コマンドを実行し、成功するまで繰り返します。",
5424
5424
  "status": {
5425
5425
  "passed": "合格",
5426
+ "stalled": "停滞",
5426
5427
  "gaveUp": "中止",
5427
5428
  "running": "実行中",
5428
5429
  "failing": "失敗中"
@@ -5431,7 +5432,9 @@
5431
5432
  "validationCommand": "検証コマンド",
5432
5433
  "lastOutput": "最新の検証(終了コード {exit})",
5433
5434
  "viewPr": "プルリクエストを表示",
5435
+ "stalledNote": "ループは早期に停止しました。連続する反復でブランチが変化せず、検証コマンドも失敗し続けたため、残りの上限を使い切らずに終了しています。再実行が有効になるには、タスクか検証コマンドの変更が必要と思われます。",
5434
5436
  "iterationsHeading": "反復",
5437
+ "iterationsTruncated": "以前の反復 {count} 件は表示されていません (履歴は上限付きです)。",
5435
5438
  "iteration": "反復 {number}",
5436
5439
  "iterationPassed": "検証に合格",
5437
5440
  "iterationFailed": "終了コード {exit}",
@@ -5411,6 +5411,7 @@
5411
5411
  "subtitle": "Trwała pętla: pracuj nad zadaniem, uruchom polecenie walidacji i powtarzaj, aż się powiedzie.",
5412
5412
  "status": {
5413
5413
  "passed": "Zaliczono",
5414
+ "stalled": "Utknęła",
5414
5415
  "gaveUp": "Poddano się",
5415
5416
  "running": "Działa",
5416
5417
  "failing": "Niepowodzenie"
@@ -5419,7 +5420,9 @@
5419
5420
  "validationCommand": "Polecenie walidacji",
5420
5421
  "lastOutput": "Ostatnia walidacja (kod {exit})",
5421
5422
  "viewPr": "Zobacz pull request",
5423
+ "stalledNote": "Pętla zatrzymała się przedwcześnie: kolejne iteracje nie zmieniły gałęzi, a polecenie walidacji nadal kończy się niepowodzeniem, więc nie zużyła reszty budżetu. Zanim ponowna próba cokolwiek da, prawdopodobnie trzeba zmienić zadanie lub polecenie walidacji.",
5422
5424
  "iterationsHeading": "Iteracje",
5425
+ "iterationsTruncated": "Nie pokazano {count} wcześniejszej iteracji (historia jest ograniczona). | Nie pokazano {count} wcześniejszych iteracji (historia jest ograniczona).",
5423
5426
  "iteration": "Iteracja {number}",
5424
5427
  "iterationPassed": "walidacja zaliczona",
5425
5428
  "iterationFailed": "kod {exit}",
@@ -5423,6 +5423,7 @@
5423
5423
  "subtitle": "Kalıcı bir döngü: görev üzerinde çalış, doğrulama komutunu çalıştır ve geçene kadar tekrarla.",
5424
5424
  "status": {
5425
5425
  "passed": "Geçti",
5426
+ "stalled": "Takıldı",
5426
5427
  "gaveUp": "Vazgeçildi",
5427
5428
  "running": "Çalışıyor",
5428
5429
  "failing": "Başarısız"
@@ -5431,7 +5432,9 @@
5431
5432
  "validationCommand": "Doğrulama komutu",
5432
5433
  "lastOutput": "Son doğrulama (çıkış {exit})",
5433
5434
  "viewPr": "Pull request'i görüntüle",
5435
+ "stalledNote": "Döngü erken durdu: ardışık yinelemeler dalı değiştirmedi ve doğrulama komutu hâlâ başarısız oluyor, bu yüzden bütçesinin kalanını harcamadı. Yeniden denemenin işe yaraması için muhtemelen görevin ya da doğrulama komutunun değişmesi gerekiyor.",
5434
5436
  "iterationsHeading": "Yinelemeler",
5437
+ "iterationsTruncated": "Önceki {count} yineleme gösterilmiyor (geçmiş sınırlıdır).",
5435
5438
  "iteration": "Yineleme {number}",
5436
5439
  "iterationPassed": "doğrulama geçti",
5437
5440
  "iterationFailed": "çıkış {exit}",
@@ -5411,6 +5411,7 @@
5411
5411
  "subtitle": "Постійний цикл: працюйте над завданням, запускайте команду перевірки та повторюйте, доки вона не пройде.",
5412
5412
  "status": {
5413
5413
  "passed": "Пройдено",
5414
+ "stalled": "Застрягло",
5414
5415
  "gaveUp": "Припинено",
5415
5416
  "running": "Виконується",
5416
5417
  "failing": "Помилка"
@@ -5419,7 +5420,9 @@
5419
5420
  "validationCommand": "Команда перевірки",
5420
5421
  "lastOutput": "Остання перевірка (код {exit})",
5421
5422
  "viewPr": "Переглянути pull request",
5423
+ "stalledNote": "Цикл зупинився достроково: послідовні ітерації не змінили гілку, а команда перевірки досі не проходить, тож решту бюджету не витрачено. Імовірно, перш ніж повторний запуск допоможе, потрібно змінити завдання або команду перевірки.",
5422
5424
  "iterationsHeading": "Ітерації",
5425
+ "iterationsTruncated": "Не показано {count} попередню ітерацію (історія обмежена). | Не показано {count} попередніх ітерацій (історія обмежена).",
5423
5426
  "iteration": "Ітерація {number}",
5424
5427
  "iterationPassed": "перевірку пройдено",
5425
5428
  "iterationFailed": "код {exit}",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.169.0",
3
+ "version": "0.171.0",
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.182.0"
43
+ "@cat-factory/contracts": "0.183.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",