@cat-factory/app 0.99.0 → 0.100.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.
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  // The newest-first list of failed-attempt entries (timestamp + message + hint + collapsible
3
- // detail), shared by the task-inspector's "previous errors" disclosure (AgentFailureHistory)
4
- // and the step-detail overlay's per-step "execution history". Presentational only the caller
5
- // decides which trail to pass (the whole run's, or one step's) and how to reveal it.
3
+ // detail) behind the task-inspector's "previous errors" disclosure (AgentFailureHistory).
4
+ // Presentational only — the caller decides which trail to pass and how to reveal it. (The
5
+ // step-detail overlay's per-step "execution history" uses StepExecutionHistory instead, which
6
+ // merges these failures with the successful outputs a restart superseded.)
6
7
  import type { AgentFailure } from '~/types/domain'
7
8
  import FailureDetail from '~/components/board/FailureDetail.vue'
8
9
 
@@ -0,0 +1,100 @@
1
+ <script setup lang="ts">
2
+ // The step-detail overlay's per-step "execution history": a newest-first, MERGED timeline of
3
+ // this step's SUCCESSFUL prior outputs (discarded by a restart) and its FAILED attempts — so
4
+ // the history surfaces what superseded attempts PRODUCED, not only the errors. Presentational
5
+ // only: the caller passes both trails already narrowed to the step (by `stepIndex`).
6
+ import type { AgentFailure, PriorStepOutput } from '~/types/domain'
7
+ import FailureDetail from '~/components/board/FailureDetail.vue'
8
+ import CopyButton from '~/components/common/CopyButton.vue'
9
+
10
+ const props = defineProps<{ failures: AgentFailure[]; outputs: PriorStepOutput[] }>()
11
+
12
+ const { t, d } = useI18n()
13
+
14
+ type Entry =
15
+ | { kind: 'failure'; key: string; occurredAt: number; failure: AgentFailure }
16
+ | { kind: 'success'; key: string; occurredAt: number; output: PriorStepOutput }
17
+
18
+ // Merge both trails and show newest first — the most recent attempt is the most relevant.
19
+ // Each entry's `key` is its position within its OWN trail (both are append-only, so that
20
+ // position is a stable identity), not the volatile merged-sort index — and it stays unique
21
+ // even when several entries share a timestamp (a restart can discard many steps with the same
22
+ // clock-fallback `occurredAt`).
23
+ const entries = computed<Entry[]>(() =>
24
+ [
25
+ ...props.failures.map(
26
+ (failure, i): Entry => ({
27
+ kind: 'failure',
28
+ key: `failure-${i}`,
29
+ occurredAt: failure.occurredAt,
30
+ failure,
31
+ }),
32
+ ),
33
+ ...props.outputs.map(
34
+ (output, i): Entry => ({
35
+ kind: 'success',
36
+ key: `success-${i}`,
37
+ occurredAt: output.occurredAt,
38
+ output,
39
+ }),
40
+ ),
41
+ ].sort((a, b) => b.occurredAt - a.occurredAt),
42
+ )
43
+ </script>
44
+
45
+ <template>
46
+ <ol class="space-y-2">
47
+ <li
48
+ v-for="entry in entries"
49
+ :key="entry.key"
50
+ class="rounded-md border px-2.5 py-2"
51
+ :class="
52
+ entry.kind === 'success'
53
+ ? 'border-emerald-900/60 bg-emerald-950/20'
54
+ : 'border-slate-800/80 bg-slate-950/50'
55
+ "
56
+ :data-testid="
57
+ entry.kind === 'success' ? 'step-history-success-entry' : 'step-history-failure-entry'
58
+ "
59
+ >
60
+ <!-- a superseded SUCCESSFUL attempt: its output, collapsible + copyable -->
61
+ <template v-if="entry.kind === 'success'">
62
+ <div class="flex items-center gap-1.5 text-[10px] text-slate-500">
63
+ <UIcon name="i-lucide-check-circle-2" class="h-3 w-3 shrink-0 text-emerald-400/70" />
64
+ <time>{{ d(new Date(entry.occurredAt), 'long') }}</time>
65
+ <span class="text-emerald-400/80">{{ t('panels.stepDetail.attemptSucceeded') }}</span>
66
+ </div>
67
+ <div class="relative mt-1">
68
+ <CopyButton :text="entry.output.output" class="absolute end-1 top-1 z-10" />
69
+ <pre
70
+ class="max-h-40 overflow-auto whitespace-pre-wrap rounded bg-slate-950/80 p-1.5 pe-9 text-[10px] leading-snug text-slate-300"
71
+ >{{ entry.output.output }}</pre
72
+ >
73
+ </div>
74
+ <p v-if="entry.output.truncated" class="mt-1 text-[10px] text-slate-500">
75
+ {{ t('panels.stepDetail.outputTruncated') }}
76
+ </p>
77
+ </template>
78
+
79
+ <!-- a FAILED attempt: mirrors FailureHistoryList's entry markup -->
80
+ <template v-else>
81
+ <div class="flex items-center gap-1.5 text-[10px] text-slate-500">
82
+ <UIcon name="i-lucide-alert-triangle" class="h-3 w-3 shrink-0 text-rose-400/70" />
83
+ <time>{{ d(new Date(entry.occurredAt), 'long') }}</time>
84
+ </div>
85
+ <p class="mt-1 text-[11px] leading-snug text-slate-300" :title="entry.failure.message">
86
+ {{ entry.failure.message }}
87
+ </p>
88
+ <p v-if="entry.failure.hint" class="mt-1 text-[10px] leading-snug text-slate-500">
89
+ {{ entry.failure.hint }}
90
+ </p>
91
+ <FailureDetail
92
+ :detail="entry.failure.detail"
93
+ :message="entry.failure.message"
94
+ summary-class="text-[10px] text-slate-500 hover:text-slate-300"
95
+ pre-class="bg-slate-950/80 text-[10px] text-slate-400"
96
+ />
97
+ </template>
98
+ </li>
99
+ </ol>
100
+ </template>
@@ -11,7 +11,7 @@ import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBind
11
11
  import { UI_TESTER_AGENT_KIND } from '@cat-factory/contracts'
12
12
  import ProvisioningLogsDrawer from '~/components/provisioning/ProvisioningLogsDrawer.vue'
13
13
  import IterationCapPrompt from '~/components/pipeline/IterationCapPrompt.vue'
14
- import FailureHistoryList from '~/components/board/FailureHistoryList.vue'
14
+ import StepExecutionHistory from '~/components/board/StepExecutionHistory.vue'
15
15
  import { useStepTimer } from '~/composables/useStepTimer'
16
16
  import { useStepProse } from '~/composables/useStepProse'
17
17
  import { useStepApproval } from '~/composables/useStepApproval'
@@ -96,6 +96,16 @@ const stepFailures = computed(() => {
96
96
  if (instance.value?.failure) trail.push(instance.value.failure)
97
97
  return trail.filter((f) => f.stepIndex === idx)
98
98
  })
99
+ // The positive complement of the failure trail: the SUCCESSFUL outputs a restart discarded
100
+ // for THIS step (each carries the `stepIndex` that produced it), so the history surfaces what
101
+ // superseded attempts produced — not only errors. Merged with `stepFailures` in the timeline.
102
+ const stepOutputs = computed(() => {
103
+ const idx = ctx.value?.stepIndex
104
+ if (idx == null) return []
105
+ return (instance.value?.outputHistory ?? []).filter((o) => o.stepIndex === idx)
106
+ })
107
+ // Whether this step has ANY prior-attempt history (successful outputs and/or failures).
108
+ const hasStepHistory = computed(() => stepFailures.value.length > 0 || stepOutputs.value.length > 0)
99
109
  const showHistory = ref(false)
100
110
 
101
111
  // A failed run is no longer executing: a step left mid-flight (state still
@@ -439,10 +449,10 @@ async function copyOutput() {
439
449
  />
440
450
  </div>
441
451
 
442
- <!-- this step's failure trail (the run-level history narrowed to this step),
443
- behind a toggle — mirrors the "previous errors" history on the task inspector
444
- but scoped to the step the user is looking at -->
445
- <div v-if="stepFailures.length">
452
+ <!-- this step's execution history (the run-level trail narrowed to this step),
453
+ behind a toggle — a merged timeline of the SUCCESSFUL outputs a restart
454
+ superseded and the FAILED attempts, scoped to the step being looked at -->
455
+ <div v-if="hasStepHistory">
446
456
  <UButton
447
457
  :icon="showHistory ? 'i-lucide-chevron-up' : 'i-lucide-history'"
448
458
  variant="ghost"
@@ -460,10 +470,11 @@ async function copyOutput() {
460
470
  : t('panels.stepDetail.executionHistory')
461
471
  }}
462
472
  </UButton>
463
- <FailureHistoryList
473
+ <StepExecutionHistory
464
474
  v-if="showHistory"
465
475
  class="mt-2"
466
476
  :failures="stepFailures"
477
+ :outputs="stepOutputs"
467
478
  data-testid="step-execution-history"
468
479
  />
469
480
  </div>
@@ -290,7 +290,16 @@ const detecting = ref(false)
290
290
  // message (the backend now raises an actionable one for an unreadable repo) so the user sees why
291
291
  // detection failed instead of a fixed, vague line.
292
292
  const detectError = ref<string | null>(null)
293
+ // Set instead of `detectError` when detection fails because the ephemeral-environment
294
+ // integration is turned off for this deployment (the backend 503s with code `unavailable`).
295
+ // That's a deployment-level toggle, NOT a repo/GitHub problem, so it gets its own actionable
296
+ // panel (what's off + how to enable it + a docs link) rather than the generic red line.
297
+ const detectUnavailable = ref(false)
293
298
  const detectResult = ref<ProvisioningRecommendation | null>(null)
299
+ // Where enabling the ephemeral-environment integration is documented (a deployment-level
300
+ // toggle set by whoever runs the server, so there is no in-app config page to link to).
301
+ const ENVIRONMENTS_DOCS_URL =
302
+ 'https://github.com/kibertoad/cat-factory/blob/main/backend/docs/environments-integration.md'
294
303
  // Advisory, LOCAL-ONLY selection: which compose `services:` key the user picked. It is NOT persisted
295
304
  // (the compose backend targets the file, not a single service), so it lives only in component state
296
305
  // and merely drives the chip highlight. Without it the highlight would compare `composePath` — which
@@ -304,6 +313,7 @@ watch(
304
313
  () => {
305
314
  detectResult.value = null
306
315
  detectError.value = null
316
+ detectUnavailable.value = false
307
317
  pickedComposeService.value = null
308
318
  },
309
319
  )
@@ -321,6 +331,7 @@ async function detectFromRepo() {
321
331
  }
322
332
  detecting.value = true
323
333
  detectError.value = null
334
+ detectUnavailable.value = false
324
335
  try {
325
336
  const rec = await infra.detectProvisioning({
326
337
  owner: repo.owner,
@@ -351,12 +362,18 @@ async function detectFromRepo() {
351
362
  if (rec.provisioning.type === 'kubernetes') seedKubeSource(rec.provisioning.manifestSource)
352
363
  }
353
364
  } catch (e) {
354
- // Surface the server's real message (an actionable "couldn't read the repo — check App access"
355
- // for a read fault), falling back to the generic line only when none is available.
356
- detectError.value =
357
- apiErrorEnvelope(e)?.message ??
358
- (e instanceof Error ? e.message : null) ??
359
- t('inspector.testConfig.detect.error')
365
+ // A 503 `unavailable` means the ephemeral-environment integration is off for this deployment
366
+ // (not a repo read fault) show the dedicated "how to enable it" panel instead of a red line.
367
+ if (apiErrorEnvelope(e)?.code === 'unavailable') {
368
+ detectUnavailable.value = true
369
+ } else {
370
+ // Surface the server's real message (an actionable "couldn't read the repo — check App access"
371
+ // for a read fault), falling back to the generic line only when none is available.
372
+ detectError.value =
373
+ apiErrorEnvelope(e)?.message ??
374
+ (e instanceof Error ? e.message : null) ??
375
+ t('inspector.testConfig.detect.error')
376
+ }
360
377
  } finally {
361
378
  detecting.value = false
362
379
  }
@@ -496,6 +513,28 @@ function setSize(value: InstanceSize) {
496
513
  {{ detectError }}
497
514
  </p>
498
515
 
516
+ <!-- The ephemeral-environment integration is off for this deployment. Say exactly what's
517
+ missing (it's separate from the GitHub connection), what enables it, and link the docs. -->
518
+ <div
519
+ v-if="detectUnavailable"
520
+ class="space-y-1 rounded border border-amber-500/30 bg-amber-500/5 p-2"
521
+ >
522
+ <p class="text-[11px] font-medium text-amber-300/90">
523
+ {{ t('inspector.testConfig.detect.unavailable.title') }}
524
+ </p>
525
+ <p class="text-[11px] leading-snug text-slate-400">
526
+ {{ t('inspector.testConfig.detect.unavailable.body') }}
527
+ </p>
528
+ <a
529
+ :href="ENVIRONMENTS_DOCS_URL"
530
+ target="_blank"
531
+ rel="noopener noreferrer"
532
+ class="inline-block text-[11px] text-primary-400 underline hover:text-primary-300"
533
+ >
534
+ {{ t('inspector.testConfig.detect.unavailable.docs') }}
535
+ </a>
536
+ </div>
537
+
499
538
  <template v-if="detectResult && !detecting">
500
539
  <p
501
540
  v-if="!detectResult.detected && detectResult.provisioning.type !== 'custom'"
@@ -18,6 +18,7 @@ export type {
18
18
  AgentRunKind,
19
19
  AgentFailureKind,
20
20
  AgentFailure,
21
+ PriorStepOutput,
21
22
  StepApproval,
22
23
  StepMetrics,
23
24
  LlmCallMetric,
@@ -744,7 +744,12 @@
744
744
  "urlSource": "Suggested environment URL source: {source}. The workspace handler owns this; set it there.",
745
745
  "namespace": "Manifests pin namespace \"{namespace}\"; recommend honoring it on the workspace handler.",
746
746
  "confidenceHigh": "Detected",
747
- "confidenceLow": "Suggestion"
747
+ "confidenceLow": "Suggestion",
748
+ "unavailable": {
749
+ "title": "Ephemeral environments aren't enabled",
750
+ "body": "Autodetect reads this repo to suggest a test-environment (Kubernetes or Docker Compose) config, but the ephemeral-environment integration is turned off for this deployment. This is separate from your GitHub connection. Whoever runs the server enables it (set ENVIRONMENTS_ENABLED and an encryption key); then autodetect and provisioning become available.",
751
+ "docs": "How to enable ephemeral environments"
752
+ }
748
753
  },
749
754
  "envWizard": {
750
755
  "title": "Compose environment setup",
@@ -1027,6 +1032,8 @@
1027
1032
  "hideInfraAttempts": "Hide infrastructure attempts",
1028
1033
  "executionHistory": "Execution history",
1029
1034
  "hideExecutionHistory": "Hide execution history",
1035
+ "attemptSucceeded": "Succeeded",
1036
+ "outputTruncated": "Output clipped to keep the run history compact.",
1030
1037
  "editingConclusions": "Editing the conclusions",
1031
1038
  "editConclusionsPlaceholder": "Edit the agent's conclusions; your edits are saved when you approve…",
1032
1039
  "noProseOutput": "This agent produced no prose output.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "Fuente de URL del entorno sugerida: {source}. El gestor del espacio de trabajo la controla; configúrala allí.",
689
689
  "namespace": "Los manifiestos fijan el espacio de nombres \"{namespace}\"; se recomienda respetarlo en el gestor del espacio de trabajo.",
690
690
  "confidenceHigh": "Detectado",
691
- "confidenceLow": "Sugerencia"
691
+ "confidenceLow": "Sugerencia",
692
+ "unavailable": {
693
+ "title": "Los entornos efímeros no están habilitados",
694
+ "body": "La detección automática lee este repositorio para sugerir una configuración de entorno de prueba (Kubernetes o Docker Compose), pero la integración de entornos efímeros está desactivada en este despliegue. Esto es independiente de tu conexión con GitHub. Quien administre el servidor debe habilitarla (definir ENVIRONMENTS_ENABLED y una clave de cifrado); después, la detección automática y el aprovisionamiento estarán disponibles.",
695
+ "docs": "Cómo habilitar los entornos efímeros"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "Se rellena con el valor predeterminado del tipo al seleccionarlo. Usa Detectar para localizar un manifiesto existente en el repositorio.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "Ocultar intentos de infraestructura",
985
990
  "executionHistory": "Historial de ejecución",
986
991
  "hideExecutionHistory": "Ocultar historial de ejecución",
992
+ "attemptSucceeded": "Correcto",
993
+ "outputTruncated": "Salida recortada para mantener compacto el historial de ejecución.",
987
994
  "editingConclusions": "Editando las conclusiones",
988
995
  "editConclusionsPlaceholder": "Edita las conclusiones del agente; tus cambios se guardan cuando apruebas…",
989
996
  "noProseOutput": "Este agente no produjo salida en prosa.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "Source d'URL d'environnement suggérée : {source}. Le gestionnaire de l'espace de travail la contrôle ; définissez-la là.",
689
689
  "namespace": "Les manifestes fixent l'espace de noms « {namespace} » ; il est recommandé de le respecter sur le gestionnaire de l'espace de travail.",
690
690
  "confidenceHigh": "Détecté",
691
- "confidenceLow": "Suggestion"
691
+ "confidenceLow": "Suggestion",
692
+ "unavailable": {
693
+ "title": "Les environnements éphémères ne sont pas activés",
694
+ "body": "La détection automatique lit ce dépôt pour proposer une configuration d'environnement de test (Kubernetes ou Docker Compose), mais l'intégration des environnements éphémères est désactivée pour ce déploiement. C'est distinct de votre connexion GitHub. La personne qui gère le serveur doit l'activer (définir ENVIRONMENTS_ENABLED et une clé de chiffrement) ; la détection automatique et le provisionnement deviennent alors disponibles.",
695
+ "docs": "Comment activer les environnements éphémères"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "Prérempli avec la valeur par défaut du type lors de sa sélection. Utilisez Détecter pour localiser un manifeste existant dans le dépôt.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "Masquer les tentatives d'infrastructure",
985
990
  "executionHistory": "Historique d'exécution",
986
991
  "hideExecutionHistory": "Masquer l'historique d'exécution",
992
+ "attemptSucceeded": "Réussi",
993
+ "outputTruncated": "Sortie tronquée pour garder l'historique d'exécution compact.",
987
994
  "editingConclusions": "Modification des conclusions",
988
995
  "editConclusionsPlaceholder": "Modifiez les conclusions de l'agent ; vos modifications sont enregistrées lorsque vous approuvez…",
989
996
  "noProseOutput": "Cet agent n'a produit aucune sortie en texte libre.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "מקור כתובת הסביבה המוצע: {source}. המטפל של המרחב שולט בכך; הגדר זאת שם.",
689
689
  "namespace": "המניפסטים מקבעים את מרחב השמות \"{namespace}\"; מומלץ לכבד אותו במטפל של המרחב.",
690
690
  "confidenceHigh": "זוהה",
691
- "confidenceLow": "הצעה"
691
+ "confidenceLow": "הצעה",
692
+ "unavailable": {
693
+ "title": "סביבות זמניות אינן מופעלות",
694
+ "body": "הזיהוי האוטומטי קורא מאגר זה כדי להציע תצורת סביבת בדיקה (Kubernetes או Docker Compose), אך שילוב הסביבות הזמניות מכובה בפריסה זו. זה נפרד מחיבור ה-GitHub שלך. מי שמפעיל את השרת צריך להפעיל אותו (להגדיר את ENVIRONMENTS_ENABLED ומפתח הצפנה); לאחר מכן הזיהוי האוטומטי וההקצאה יהיו זמינים.",
695
+ "docs": "כיצד להפעיל סביבות זמניות"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "מתמלא מברירת המחדל של הסוג בעת הבחירה. השתמש ב'זיהוי' כדי לאתר מניפסט קיים במאגר.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "הסתר ניסיונות תשתית",
985
990
  "executionHistory": "היסטוריית הרצה",
986
991
  "hideExecutionHistory": "הסתר היסטוריית הרצה",
992
+ "attemptSucceeded": "הצליח",
993
+ "outputTruncated": "הפלט נקטע כדי לשמור על היסטוריית ההרצה קומפקטית.",
987
994
  "editingConclusions": "עריכת המסקנות",
988
995
  "editConclusionsPlaceholder": "ערוך את מסקנות הסוכן; העריכות שלך נשמרות כשתאשר…",
989
996
  "noProseOutput": "סוכן זה לא הפיק פלט טקסטואלי.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "推奨される環境 URL ソース: {source}。これはワークスペースのハンドラーが管理します。そちらで設定してください。",
689
689
  "namespace": "マニフェストは名前空間「{namespace}」を固定しています。ワークスペースのハンドラーでそれを尊重することを推奨します。",
690
690
  "confidenceHigh": "検出",
691
- "confidenceLow": "提案"
691
+ "confidenceLow": "提案",
692
+ "unavailable": {
693
+ "title": "エフェメラル環境が有効になっていません",
694
+ "body": "自動検出はこのリポジトリを読み取ってテスト環境(Kubernetes または Docker Compose)の設定を提案しますが、このデプロイではエフェメラル環境統合が無効になっています。これは GitHub 接続とは別のものです。サーバーを運用している担当者が有効化(ENVIRONMENTS_ENABLED と暗号化キーを設定)すると、自動検出とプロビジョニングが利用できるようになります。",
695
+ "docs": "エフェメラル環境を有効にする方法"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "タイプを選択すると既定値が自動入力されます。リポジトリ内の既存のマニフェストを探すには「検出」を使用してください。",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "インフラの試行を非表示",
985
990
  "executionHistory": "実行履歴",
986
991
  "hideExecutionHistory": "実行履歴を非表示",
992
+ "attemptSucceeded": "成功",
993
+ "outputTruncated": "実行履歴を簡潔に保つため出力を切り詰めました。",
987
994
  "editingConclusions": "結論を編集中",
988
995
  "editConclusionsPlaceholder": "エージェントの結論を編集してください。編集内容は承認時に保存されます…",
989
996
  "noProseOutput": "このエージェントは文章出力を生成しませんでした。",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "Sugerowane źródło adresu URL środowiska: {source}. Zarządza tym handler przestrzeni roboczej; ustaw to tam.",
689
689
  "namespace": "Manifesty ustalają przestrzeń nazw \"{namespace}\"; zaleca się jej przestrzeganie w handlerze przestrzeni roboczej.",
690
690
  "confidenceHigh": "Wykryto",
691
- "confidenceLow": "Sugestia"
691
+ "confidenceLow": "Sugestia",
692
+ "unavailable": {
693
+ "title": "Środowiska efemeryczne nie są włączone",
694
+ "body": "Automatyczne wykrywanie odczytuje to repozytorium, aby zaproponować konfigurację środowiska testowego (Kubernetes lub Docker Compose), ale integracja środowisk efemerycznych jest wyłączona dla tego wdrożenia. Jest to niezależne od połączenia z GitHub. Osoba zarządzająca serwerem musi ją włączyć (ustawić ENVIRONMENTS_ENABLED oraz klucz szyfrowania); wtedy automatyczne wykrywanie i udostępnianie staną się dostępne.",
695
+ "docs": "Jak włączyć środowiska efemeryczne"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "Wypełniane wartością domyślną typu po jego wybraniu. Użyj Wykryj, aby znaleźć istniejący manifest w repozytorium.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "Ukryj próby infrastrukturalne",
985
990
  "executionHistory": "Historia wykonania",
986
991
  "hideExecutionHistory": "Ukryj historię wykonania",
992
+ "attemptSucceeded": "Powodzenie",
993
+ "outputTruncated": "Wynik przycięty, aby zachować zwięzłość historii wykonania.",
987
994
  "editingConclusions": "Edytowanie wniosków",
988
995
  "editConclusionsPlaceholder": "Edytuj wnioski agenta; Twoje zmiany zostaną zapisane po zatwierdzeniu…",
989
996
  "noProseOutput": "Ten agent nie wytworzył wyniku tekstowego.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "Önerilen ortam URL kaynağı: {source}. Bunu çalışma alanı işleyicisi yönetir; oradan ayarlayın.",
689
689
  "namespace": "Manifestler \"{namespace}\" ad alanını sabitliyor; çalışma alanı işleyicisinde buna uymanız önerilir.",
690
690
  "confidenceHigh": "Algılandı",
691
- "confidenceLow": "Öneri"
691
+ "confidenceLow": "Öneri",
692
+ "unavailable": {
693
+ "title": "Geçici ortamlar etkin değil",
694
+ "body": "Otomatik algılama, bir test ortamı (Kubernetes veya Docker Compose) yapılandırması önermek için bu depoyu okur, ancak geçici ortam entegrasyonu bu dağıtımda kapalıdır. Bu, GitHub bağlantınızdan ayrıdır. Sunucuyu çalıştıran kişi bunu etkinleştirmelidir (ENVIRONMENTS_ENABLED ve bir şifreleme anahtarı ayarlayın); ardından otomatik algılama ve sağlama kullanılabilir hale gelir.",
695
+ "docs": "Geçici ortamlar nasıl etkinleştirilir"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "Türü seçtiğinizde varsayılan değeriyle doldurulur. Depodaki mevcut bir manifesti bulmak için Algıla'yı kullanın.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "Altyapı denemelerini gizle",
985
990
  "executionHistory": "Yürütme geçmişi",
986
991
  "hideExecutionHistory": "Yürütme geçmişini gizle",
992
+ "attemptSucceeded": "Başarılı",
993
+ "outputTruncated": "Yürütme geçmişini derli toplu tutmak için çıktı kırpıldı.",
987
994
  "editingConclusions": "Sonuçlar düzenleniyor",
988
995
  "editConclusionsPlaceholder": "Aracının sonuçlarını düzenleyin; düzenlemeleriniz onayladığınızda kaydedilir…",
989
996
  "noProseOutput": "Bu aracı herhangi bir metin çıktısı üretmedi.",
@@ -688,7 +688,12 @@
688
688
  "urlSource": "Запропоноване джерело URL середовища: {source}. Цим керує обробник робочого простору; налаштуйте його там.",
689
689
  "namespace": "Маніфести фіксують простір імен \"{namespace}\"; рекомендуємо дотримуватися його в обробнику робочого простору.",
690
690
  "confidenceHigh": "Виявлено",
691
- "confidenceLow": "Пропозиція"
691
+ "confidenceLow": "Пропозиція",
692
+ "unavailable": {
693
+ "title": "Ефемерні середовища не ввімкнено",
694
+ "body": "Автоматичне визначення читає цей репозиторій, щоб запропонувати конфігурацію тестового середовища (Kubernetes або Docker Compose), але інтеграцію ефемерних середовищ вимкнено для цього розгортання. Це окремо від вашого підключення до GitHub. Той, хто керує сервером, має ввімкнути її (задати ENVIRONMENTS_ENABLED і ключ шифрування); після цього автоматичне визначення та провізіонування стануть доступними.",
695
+ "docs": "Як увімкнути ефемерні середовища"
696
+ }
692
697
  },
693
698
  "customManifestPathHint": "Заповнюється значенням типу за замовчуванням під час вибору. Скористайтеся «Виявити», щоб знайти наявний маніфест у репозиторії.",
694
699
  "generateManifest": {
@@ -984,6 +989,8 @@
984
989
  "hideInfraAttempts": "Приховати спроби інфраструктури",
985
990
  "executionHistory": "Історія виконання",
986
991
  "hideExecutionHistory": "Приховати історію виконання",
992
+ "attemptSucceeded": "Успішно",
993
+ "outputTruncated": "Вивід обрізано, щоб історія виконання залишалася компактною.",
987
994
  "editingConclusions": "Редагування висновків",
988
995
  "editConclusionsPlaceholder": "Відредагуйте висновки агента; ваші зміни зберігаються після затвердження…",
989
996
  "noProseOutput": "Цей агент не створив текстового виводу.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.99.0",
3
+ "version": "0.100.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",
@@ -34,7 +34,7 @@
34
34
  "valibot": "^1.4.2",
35
35
  "vue": "3.5.39",
36
36
  "wretch": "^3.0.9",
37
- "@cat-factory/contracts": "0.109.0"
37
+ "@cat-factory/contracts": "0.110.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",