@cat-factory/app 0.100.1 → 0.100.2

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.
@@ -4,6 +4,7 @@
4
4
  // the unified retry through the agentRuns store, so every surface (board card,
5
5
  // inspector, task panel) gets identical behaviour from one place. Replaces the
6
6
  // three hand-rolled bootstrap banners that used to duplicate this logic.
7
+ import type { EnvironmentFailureReason } from '@cat-factory/contracts'
7
8
  import type { AgentRunSummary } from '~/stores/agentRuns'
8
9
  import FailureDetail from '~/components/board/FailureDetail.vue'
9
10
 
@@ -14,9 +15,59 @@ const props = withDefaults(
14
15
 
15
16
  const { t } = useI18n()
16
17
  const agentRuns = useAgentRunsStore()
18
+ const ui = useUiStore()
19
+ const auth = useAuthStore()
20
+ const board = useBoardStore()
17
21
 
18
22
  const compact = computed(() => props.variant === 'compact')
19
23
  const failure = computed(() => props.run.failure)
24
+ // An `environment` failure is a provisioning/config problem, so offer a one-click jump to the
25
+ // place it's configured alongside the retry — the same "Configure…" deep-link pattern the
26
+ // infra-setup banners use.
27
+ const isEnvironmentFailure = computed(() => failure.value?.kind === 'environment')
28
+ const DEPLOY_RUNNER_UNWIRED: EnvironmentFailureReason = 'deploy_runner_unwired'
29
+
30
+ // The provision type of the failed run's SERVICE frame (walk up to the frame, mirroring the
31
+ // backend's `resolveServiceProvisioning`). Drives the K8s-specific gate below.
32
+ const provisionType = computed(() => {
33
+ const block = board.getBlock(props.run.blockId)
34
+ return block ? board.serviceOf(block)?.provisioning?.type : undefined
35
+ })
36
+
37
+ // Where the deep-link should land. A `deploy_runner_unwired` cause is fixed by wiring the DEPLOY
38
+ // RUNNER, which is the same self-hosted runner pool that runs agent containers (Infrastructure →
39
+ // "Agent containers" / `runner-pool`) — NOT the environment-provider connection (Infrastructure →
40
+ // "Test environments" / `environment`), where the generic banner would otherwise dead-end. So route
41
+ // that cause to the runner-pool tab on a non-local deployment; local mode's fix is an env var (the
42
+ // hint below, not a UI tab), and every OTHER environment failure is a provider-config problem that
43
+ // belongs on the environment tab.
44
+ const routesToRunnerPool = computed(
45
+ () =>
46
+ isEnvironmentFailure.value &&
47
+ failure.value?.reason === DEPLOY_RUNNER_UNWIRED &&
48
+ auth.localMode?.enabled !== true,
49
+ )
50
+ function openFailureSetup() {
51
+ ui.openProviderConnection(routesToRunnerPool.value ? 'runner-pool' : 'environment')
52
+ }
53
+ const failureSetupLabel = computed(() =>
54
+ routesToRunnerPool.value
55
+ ? t('board.failure.deployRunnerSetup')
56
+ : t('board.failure.environmentSetup'),
57
+ )
58
+
59
+ // The env-var hint is Kubernetes+local specific, so gate it precisely rather than showing it for
60
+ // every environment failure: only for the machine-readable `deploy_runner_unwired` cause (NOT a
61
+ // helm/apply error or a transient blip), only in local mode (where the deploy runtime is an env
62
+ // var, not a UI connection the tab could fix), and only for a `kubernetes` provision (so a future
63
+ // Nomad/custom provider triggering the same cause never shows kubectl/kustomize/helm guidance).
64
+ const showEnvironmentLocalHint = computed(
65
+ () =>
66
+ isEnvironmentFailure.value &&
67
+ auth.localMode?.enabled === true &&
68
+ failure.value?.reason === DEPLOY_RUNNER_UNWIRED &&
69
+ provisionType.value === 'kubernetes',
70
+ )
20
71
  const title = computed(() => {
21
72
  // A `dispatch` failure means the container/runner never accepted the job — say so
22
73
  // explicitly rather than the generic "Run failed", and show the verbatim provider
@@ -83,6 +134,22 @@ async function retry() {
83
134
  {{ failure.hint }}
84
135
  </p>
85
136
 
137
+ <!-- Local mode only: the deploy runtime is configured via env vars, not a UI connection, so
138
+ name the concrete .env fix rather than only pointing at the (unhelpful-here) tab. -->
139
+ <p
140
+ v-if="showEnvironmentLocalHint && !compact"
141
+ class="mt-1 text-[11px] leading-snug text-rose-400/70"
142
+ data-testid="agent-failure-environment-local-hint"
143
+ >
144
+ {{
145
+ t('board.failure.environmentLocalHint', {
146
+ runtime: 'LOCAL_DEPLOY_RUNTIME',
147
+ native: 'LOCAL_DEPLOY_HARNESS_ENTRY',
148
+ container: 'LOCAL_DEPLOY_IMAGE',
149
+ })
150
+ }}
151
+ </p>
152
+
86
153
  <FailureDetail
87
154
  v-if="!compact && failure"
88
155
  :detail="failure.detail"
@@ -91,19 +158,38 @@ async function retry() {
91
158
  pre-class="bg-rose-950/60 text-[10px] text-rose-200/80"
92
159
  />
93
160
 
94
- <button
95
- type="button"
96
- class="nodrag mt-2 flex items-center gap-1 rounded-md bg-rose-900/40 text-rose-200 hover:bg-rose-900/70 disabled:opacity-60"
97
- :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
98
- :disabled="retrying"
99
- data-testid="agent-failure-retry"
100
- @click.stop="retry"
101
- >
102
- <UIcon
103
- :name="retrying ? 'i-lucide-loader-circle' : 'i-lucide-rotate-ccw'"
104
- :class="[compact ? 'h-3 w-3' : 'h-3.5 w-3.5', { 'animate-spin': retrying }]"
105
- />
106
- {{ retrying ? t('board.failure.retrying') : compact ? t('common.retry') : retryLabel }}
107
- </button>
161
+ <div class="mt-2 flex flex-wrap items-center gap-2">
162
+ <button
163
+ type="button"
164
+ class="nodrag flex items-center gap-1 rounded-md bg-rose-900/40 text-rose-200 hover:bg-rose-900/70 disabled:opacity-60"
165
+ :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
166
+ :disabled="retrying"
167
+ data-testid="agent-failure-retry"
168
+ @click.stop="retry"
169
+ >
170
+ <UIcon
171
+ :name="retrying ? 'i-lucide-loader-circle' : 'i-lucide-rotate-ccw'"
172
+ :class="[compact ? 'h-3 w-3' : 'h-3.5 w-3.5', { 'animate-spin': retrying }]"
173
+ />
174
+ {{ retrying ? t('board.failure.retrying') : compact ? t('common.retry') : retryLabel }}
175
+ </button>
176
+
177
+ <!-- Environment provisioning failures are almost always a deploy-backend / provider-config
178
+ issue, so link straight to where it's set up rather than leaving the user to hunt. The
179
+ destination + label follow the cause: a `deploy_runner_unwired` failure needs the runner
180
+ pool (Agent containers tab), every other cause needs the environment provider (Test
181
+ environments tab) — see `routesToRunnerPool`. -->
182
+ <button
183
+ v-if="isEnvironmentFailure"
184
+ type="button"
185
+ class="nodrag flex items-center gap-1 rounded-md bg-rose-900/20 text-rose-300 hover:bg-rose-900/50"
186
+ :class="compact ? 'px-2 py-0.5 text-[10px]' : 'px-2 py-1 text-[11px]'"
187
+ data-testid="agent-failure-configure-environment"
188
+ @click.stop="openFailureSetup"
189
+ >
190
+ <UIcon name="i-lucide-settings" :class="compact ? 'h-3 w-3' : 'h-3.5 w-3.5'" />
191
+ {{ failureSetupLabel }}
192
+ </button>
193
+ </div>
108
194
  </div>
109
195
  </template>
@@ -297,6 +297,12 @@
297
297
  "stalled": "Run stalled",
298
298
  "retryBootstrap": "Retry bootstrap",
299
299
  "retryRun": "Retry run",
300
+ "environmentSetup": "Set up environments",
301
+ "deployRunnerSetup": "Set up runner pool",
302
+ "environmentLocalHint": "Local ephemeral environments need a deploy runtime to run kubectl/kustomize/helm. Set {runtime} in your .env: native mode runs those tools on your host ({native}), container mode runs them in the deploy image ({container}).",
303
+ "@environmentLocalHint": {
304
+ "description": "Shown only in local mode. The {runtime}/{native}/{container} placeholders are injected literal environment-variable names (LOCAL_DEPLOY_RUNTIME etc.) — keep them as placeholders, do not translate. '.env' is a filename, keep it verbatim."
305
+ },
300
306
  "showDetail": "Show detail",
301
307
  "retrying": "Retrying…",
302
308
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "La ejecución se estancó",
277
277
  "retryBootstrap": "Reintentar arranque",
278
278
  "retryRun": "Reintentar ejecución",
279
+ "environmentSetup": "Configurar entornos",
280
+ "deployRunnerSetup": "Configurar pool de runners",
281
+ "environmentLocalHint": "Los entornos efímeros locales necesitan un runtime de despliegue para ejecutar kubectl/kustomize/helm. Define {runtime} en tu .env: el modo nativo ejecuta esas herramientas en tu host ({native}), el modo contenedor las ejecuta en la imagen de despliegue ({container}).",
279
282
  "showDetail": "Mostrar detalle",
280
283
  "retrying": "Reintentando…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "L’exécution est bloquée",
277
277
  "retryBootstrap": "Relancer l’initialisation",
278
278
  "retryRun": "Relancer l’exécution",
279
+ "environmentSetup": "Configurer les environnements",
280
+ "deployRunnerSetup": "Configurer le pool de runners",
281
+ "environmentLocalHint": "Les environnements éphémères locaux nécessitent un runtime de déploiement pour exécuter kubectl/kustomize/helm. Définissez {runtime} dans votre .env : le mode natif exécute ces outils sur votre hôte ({native}), le mode conteneur les exécute dans l'image de déploiement ({container}).",
279
282
  "showDetail": "Afficher le détail",
280
283
  "retrying": "Nouvelle tentative…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "הריצה נתקעה",
277
277
  "retryBootstrap": "נסה שוב לאתחל",
278
278
  "retryRun": "נסה שוב להריץ",
279
+ "environmentSetup": "הגדרת סביבות",
280
+ "deployRunnerSetup": "הגדרת מאגר ראנרים",
281
+ "environmentLocalHint": "סביבות זמניות מקומיות זקוקות לזמן ריצה לפריסה כדי להריץ את kubectl/kustomize/helm. הגדירו את {runtime} בקובץ ה-.env שלכם: מצב מקורי מריץ את הכלים האלה על המארח שלכם ({native}), מצב מכולה מריץ אותם בתוך תמונת הפריסה ({container}).",
279
282
  "showDetail": "הצג פרטים",
280
283
  "retrying": "מנסה שוב…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "実行が停止しました",
277
277
  "retryBootstrap": "ブートストラップを再試行",
278
278
  "retryRun": "実行を再試行",
279
+ "environmentSetup": "環境をセットアップ",
280
+ "deployRunnerSetup": "ランナープールをセットアップ",
281
+ "environmentLocalHint": "ローカルの一時環境では、kubectl/kustomize/helm を実行するためにデプロイランタイムが必要です。.env に {runtime} を設定してください。ネイティブモードはこれらのツールをホスト上で実行し({native})、コンテナモードはデプロイイメージ内で実行します({container})。",
279
282
  "showDetail": "詳細を表示",
280
283
  "retrying": "再試行中…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "Uruchomienie utknęło",
277
277
  "retryBootstrap": "Ponów inicjalizację",
278
278
  "retryRun": "Ponów uruchomienie",
279
+ "environmentSetup": "Skonfiguruj środowiska",
280
+ "deployRunnerSetup": "Skonfiguruj pulę runnerów",
281
+ "environmentLocalHint": "Lokalne środowiska tymczasowe wymagają środowiska uruchomieniowego wdrożenia do uruchomienia kubectl/kustomize/helm. Ustaw {runtime} w pliku .env: tryb natywny uruchamia te narzędzia na twoim hoście ({native}), tryb kontenerowy uruchamia je w obrazie wdrożeniowym ({container}).",
279
282
  "showDetail": "Pokaż szczegóły",
280
283
  "retrying": "Ponawianie…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "Çalıştırma askıda kaldı",
277
277
  "retryBootstrap": "Bootstrap'ı yeniden dene",
278
278
  "retryRun": "Çalıştırmayı yeniden dene",
279
+ "environmentSetup": "Ortamları yapılandır",
280
+ "deployRunnerSetup": "Runner havuzunu yapılandır",
281
+ "environmentLocalHint": "Yerel geçici ortamlar, kubectl/kustomize/helm çalıştırmak için bir dağıtım çalışma zamanı gerektirir. .env dosyanızda {runtime} değerini ayarlayın: yerel mod bu araçları ana makinenizde çalıştırır ({native}), konteyner modu bunları dağıtım imajında çalıştırır ({container}).",
279
282
  "showDetail": "Ayrıntıyı göster",
280
283
  "retrying": "Yeniden deneniyor…",
281
284
  "history": {
@@ -276,6 +276,9 @@
276
276
  "stalled": "Запуск завис",
277
277
  "retryBootstrap": "Повторити ініціалізацію",
278
278
  "retryRun": "Повторити запуск",
279
+ "environmentSetup": "Налаштувати середовища",
280
+ "deployRunnerSetup": "Налаштувати пул раннерів",
281
+ "environmentLocalHint": "Локальні тимчасові середовища потребують середовища виконання розгортання для запуску kubectl/kustomize/helm. Встановіть {runtime} у вашому .env: нативний режим запускає ці інструменти на вашому хості ({native}), режим контейнера запускає їх в образі розгортання ({container}).",
279
282
  "showDetail": "Показати деталі",
280
283
  "retrying": "Повторення…",
281
284
  "history": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.100.1",
3
+ "version": "0.100.2",
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.110.0"
37
+ "@cat-factory/contracts": "0.110.1"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",