@cat-factory/app 0.96.5 → 0.97.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.
- package/app/components/panels/inspector/FrontendConfig.vue +17 -7
- package/app/components/panels/inspector/ServiceTestConfig.vue +19 -7
- package/app/composables/usePipelineErrorToast.ts +1 -0
- package/app/utils/catalog.ts +12 -0
- package/i18n/locales/en.json +3 -1
- package/i18n/locales/es.json +3 -1
- package/i18n/locales/fr.json +3 -1
- package/i18n/locales/he.json +3 -1
- package/i18n/locales/ja.json +3 -1
- package/i18n/locales/pl.json +3 -1
- package/i18n/locales/tr.json +3 -1
- package/i18n/locales/uk.json +3 -1
- package/package.json +2 -2
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from '~/types/domain'
|
|
13
13
|
import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBindingsResolved.vue'
|
|
14
14
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
15
|
+
import { apiErrorEnvelope } from '~/composables/api/errors'
|
|
15
16
|
|
|
16
17
|
// Frontend-frame (`type: 'frontend'`) configuration: how to build, serve, and mock this
|
|
17
18
|
// frontend for a self-contained UI test (+ an optional browsable preview on local/node),
|
|
@@ -119,7 +120,9 @@ const showPreview = ref(false)
|
|
|
119
120
|
// frame links to its repo the same way a service does (`github_repos.block_id`).
|
|
120
121
|
const repoLink = computed(() => github.repoForBlock(props.block.id))
|
|
121
122
|
const detecting = ref(false)
|
|
122
|
-
|
|
123
|
+
// The detect failure message to show, or null when there's no error. Holds the SERVER's real
|
|
124
|
+
// message (the backend raises an actionable one for an unreadable repo) instead of a fixed line.
|
|
125
|
+
const detectError = ref<string | null>(null)
|
|
123
126
|
const detectResult = ref<FrontendConfigRecommendation | null>(null)
|
|
124
127
|
|
|
125
128
|
// A detection result is scoped to the inspected block — clear it (and any error) when the
|
|
@@ -128,18 +131,20 @@ watch(
|
|
|
128
131
|
() => props.block.id,
|
|
129
132
|
() => {
|
|
130
133
|
detectResult.value = null
|
|
131
|
-
detectError.value =
|
|
134
|
+
detectError.value = null
|
|
132
135
|
},
|
|
133
136
|
)
|
|
134
137
|
|
|
135
138
|
async function detectFromRepo() {
|
|
136
139
|
const repo = repoLink.value
|
|
137
140
|
if (!repo) {
|
|
138
|
-
|
|
141
|
+
// The frame points at a repo that isn't in the connected-repo projection, so we can't resolve
|
|
142
|
+
// its owner/name to ask the backend. A "sync/connect GitHub" problem, not a read failure.
|
|
143
|
+
detectError.value = t('inspector.detectRepoUnresolved')
|
|
139
144
|
return
|
|
140
145
|
}
|
|
141
146
|
detecting.value = true
|
|
142
|
-
detectError.value =
|
|
147
|
+
detectError.value = null
|
|
143
148
|
detectResult.value = null
|
|
144
149
|
try {
|
|
145
150
|
const result = await infra.detectFrontendConfig({
|
|
@@ -151,8 +156,13 @@ async function detectFromRepo() {
|
|
|
151
156
|
// When nothing was detected the "none" hint tells the user to set the frontend directory —
|
|
152
157
|
// that field lives in the (collapsed) Build group, so open it so the advice is actionable.
|
|
153
158
|
if (!result.detected) showBuild.value = true
|
|
154
|
-
} catch {
|
|
155
|
-
|
|
159
|
+
} catch (e) {
|
|
160
|
+
// Surface the server's real message (an actionable "couldn't read the repo — check App access"
|
|
161
|
+
// for a read fault), falling back to the generic line only when none is available.
|
|
162
|
+
detectError.value =
|
|
163
|
+
apiErrorEnvelope(e)?.message ??
|
|
164
|
+
(e instanceof Error ? e.message : null) ??
|
|
165
|
+
t('inspector.frontendConfig.detect.error')
|
|
156
166
|
} finally {
|
|
157
167
|
detecting.value = false
|
|
158
168
|
}
|
|
@@ -243,7 +253,7 @@ onUnmounted(() => preview.stopPolling(props.block.id))
|
|
|
243
253
|
</p>
|
|
244
254
|
|
|
245
255
|
<p v-if="detectError" class="text-[11px] text-rose-300/80">
|
|
246
|
-
{{
|
|
256
|
+
{{ detectError }}
|
|
247
257
|
</p>
|
|
248
258
|
|
|
249
259
|
<template v-if="detectResult && !detecting">
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
} from '@cat-factory/contracts'
|
|
19
19
|
import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
|
|
20
20
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
21
|
+
import { apiErrorEnvelope } from '~/composables/api/errors'
|
|
21
22
|
|
|
22
23
|
// Service-level (frame) configuration: the service-owned PROVISIONING — the provision
|
|
23
24
|
// TYPE this service produces (`infraless` / `docker-compose` / `kubernetes` / `custom`)
|
|
@@ -284,7 +285,10 @@ function applyPicked() {
|
|
|
284
285
|
// every field stays editable, and the engine-level URL/namespace suggestions are surfaced
|
|
285
286
|
// read-only (the workspace handler owns them). Nothing is persisted server-side by detection.
|
|
286
287
|
const detecting = ref(false)
|
|
287
|
-
|
|
288
|
+
// The detect failure message to show, or null when there's no error. Holds the SERVER's real
|
|
289
|
+
// message (the backend now raises an actionable one for an unreadable repo) so the user sees why
|
|
290
|
+
// detection failed instead of a fixed, vague line.
|
|
291
|
+
const detectError = ref<string | null>(null)
|
|
288
292
|
const detectResult = ref<ProvisioningRecommendation | null>(null)
|
|
289
293
|
// Advisory, LOCAL-ONLY selection: which compose `services:` key the user picked. It is NOT persisted
|
|
290
294
|
// (the compose backend targets the file, not a single service), so it lives only in component state
|
|
@@ -298,7 +302,7 @@ watch(
|
|
|
298
302
|
() => props.block.id,
|
|
299
303
|
() => {
|
|
300
304
|
detectResult.value = null
|
|
301
|
-
detectError.value =
|
|
305
|
+
detectError.value = null
|
|
302
306
|
pickedComposeService.value = null
|
|
303
307
|
},
|
|
304
308
|
)
|
|
@@ -308,11 +312,14 @@ async function detectFromRepo() {
|
|
|
308
312
|
if (!ctx) return
|
|
309
313
|
const repo = github.repoFor(ctx.githubId)
|
|
310
314
|
if (!repo) {
|
|
311
|
-
|
|
315
|
+
// The frame points at a repo that isn't in the connected-repo projection, so we can't resolve
|
|
316
|
+
// its owner/name to ask the backend. That's a "sync/connect GitHub" problem, NOT "couldn't read
|
|
317
|
+
// the repo" — say so specifically.
|
|
318
|
+
detectError.value = t('inspector.detectRepoUnresolved')
|
|
312
319
|
return
|
|
313
320
|
}
|
|
314
321
|
detecting.value = true
|
|
315
|
-
detectError.value =
|
|
322
|
+
detectError.value = null
|
|
316
323
|
try {
|
|
317
324
|
const rec = await infra.detectProvisioning({
|
|
318
325
|
owner: repo.owner,
|
|
@@ -342,8 +349,13 @@ async function detectFromRepo() {
|
|
|
342
349
|
board.updateBlock(props.block.id, { provisioning: rec.provisioning })
|
|
343
350
|
if (rec.provisioning.type === 'kubernetes') seedKubeSource(rec.provisioning.manifestSource)
|
|
344
351
|
}
|
|
345
|
-
} catch {
|
|
346
|
-
|
|
352
|
+
} catch (e) {
|
|
353
|
+
// Surface the server's real message (an actionable "couldn't read the repo — check App access"
|
|
354
|
+
// for a read fault), falling back to the generic line only when none is available.
|
|
355
|
+
detectError.value =
|
|
356
|
+
apiErrorEnvelope(e)?.message ??
|
|
357
|
+
(e instanceof Error ? e.message : null) ??
|
|
358
|
+
t('inspector.testConfig.detect.error')
|
|
347
359
|
} finally {
|
|
348
360
|
detecting.value = false
|
|
349
361
|
}
|
|
@@ -452,7 +464,7 @@ function setSize(value: InstanceSize) {
|
|
|
452
464
|
</p>
|
|
453
465
|
|
|
454
466
|
<p v-if="detectError" class="text-[11px] text-rose-300/80">
|
|
455
|
-
{{
|
|
467
|
+
{{ detectError }}
|
|
456
468
|
</p>
|
|
457
469
|
|
|
458
470
|
<template v-if="detectResult && !detecting">
|
|
@@ -48,6 +48,7 @@ const CONFLICT_TITLE_KEYS: Record<
|
|
|
48
48
|
provision_type_unhandled: 'errors.conflict.title.provision_type_unhandled',
|
|
49
49
|
preset_unsatisfiable: 'errors.conflict.title.preset_unsatisfiable',
|
|
50
50
|
visual_pipeline_no_frontend: 'errors.conflict.title.visual_pipeline_no_frontend',
|
|
51
|
+
deployer_required_before_tester: 'errors.conflict.title.deployer_required_before_tester',
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
/**
|
package/app/utils/catalog.ts
CHANGED
|
@@ -346,6 +346,18 @@ export const SYSTEM_AGENT_META: Record<string, AgentArchetype> = {
|
|
|
346
346
|
color: '#22d3ee',
|
|
347
347
|
description: 'Maps the repository into the service → modules blueprint.',
|
|
348
348
|
},
|
|
349
|
+
// The single environment provisioner: an operational (non-LLM) step that stands up the ephemeral
|
|
350
|
+
// environment the tester / human-test gate run against for a kubernetes/custom service, and is a
|
|
351
|
+
// fast no-op for docker-compose / infraless. Seeded before the first tester/human-test step in the
|
|
352
|
+
// built-in pipelines, so it needs display metadata (else it renders as a generic gray "Agent").
|
|
353
|
+
deployer: {
|
|
354
|
+
kind: 'deployer',
|
|
355
|
+
label: 'Deployer',
|
|
356
|
+
icon: 'i-lucide-cloud-upload',
|
|
357
|
+
color: '#34d399',
|
|
358
|
+
description:
|
|
359
|
+
'Provisions the ephemeral environment the tester and human-test gate run against (kubernetes / custom services); a no-op for docker-compose / infraless.',
|
|
360
|
+
},
|
|
349
361
|
// The Initiative Planning pipeline's two steps. Only runnable on an initiative
|
|
350
362
|
// block (pl_initiative — enforced by the engine), so they are display-metadata
|
|
351
363
|
// system kinds, never palette archetypes.
|
package/i18n/locales/en.json
CHANGED
|
@@ -428,7 +428,8 @@
|
|
|
428
428
|
"bootstrap_reference_missing": "Reference architecture is gone",
|
|
429
429
|
"provision_type_unhandled": "No handler for this provision type",
|
|
430
430
|
"preset_unsatisfiable": "Model preset can't run this pipeline",
|
|
431
|
-
"visual_pipeline_no_frontend": "No frontend to test"
|
|
431
|
+
"visual_pipeline_no_frontend": "No frontend to test",
|
|
432
|
+
"deployer_required_before_tester": "Add a Deployer before the Tester"
|
|
432
433
|
},
|
|
433
434
|
"fallbackMessage": "This action conflicts with the current state.",
|
|
434
435
|
"providersUnconfigured": {
|
|
@@ -503,6 +504,7 @@
|
|
|
503
504
|
}
|
|
504
505
|
},
|
|
505
506
|
"inspector": {
|
|
507
|
+
"detectRepoUnresolved": "This block's repository isn't among the connected GitHub repos, so it can't be read. Connect or sync GitHub for it, then retry.",
|
|
506
508
|
"container": {
|
|
507
509
|
"title": "Contents",
|
|
508
510
|
"hint": "The modules and tasks inside this block. Click an entry to select it on the board.",
|
package/i18n/locales/es.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "La inicialización no se puede reintentar",
|
|
392
392
|
"bootstrap_reference_missing": "La arquitectura de referencia ha desaparecido",
|
|
393
393
|
"preset_unsatisfiable": "El preajuste de modelo no puede ejecutar esta canalización",
|
|
394
|
-
"visual_pipeline_no_frontend": "No hay frontend que probar"
|
|
394
|
+
"visual_pipeline_no_frontend": "No hay frontend que probar",
|
|
395
|
+
"deployer_required_before_tester": "Añade un Deployer antes del Tester"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "Esta acción entra en conflicto con el estado actual.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "El repositorio de este bloque no está entre los repositorios de GitHub conectados, por lo que no se puede leer. Conecta o sincroniza GitHub para él y vuelve a intentarlo.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "Contenido",
|
|
465
467
|
"hint": "Los módulos y tareas dentro de este bloque. Haz clic en una entrada para seleccionarla en el tablero.",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "L’initialisation ne peut pas être relancée",
|
|
392
392
|
"bootstrap_reference_missing": "L’architecture de référence a disparu",
|
|
393
393
|
"preset_unsatisfiable": "Le préréglage de modèle ne peut pas exécuter ce pipeline",
|
|
394
|
-
"visual_pipeline_no_frontend": "Aucun frontend à tester"
|
|
394
|
+
"visual_pipeline_no_frontend": "Aucun frontend à tester",
|
|
395
|
+
"deployer_required_before_tester": "Ajoutez un Deployer avant le Testeur"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "Cette action est en conflit avec l’état actuel.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "Le dépôt de ce bloc ne figure pas parmi les dépôts GitHub connectés et ne peut donc pas être lu. Connectez ou synchronisez GitHub pour ce dépôt, puis réessayez.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "Contenu",
|
|
465
467
|
"hint": "Les modules et les tâches contenus dans ce bloc. Cliquez sur une entrée pour la sélectionner sur le tableau.",
|
package/i18n/locales/he.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "לא ניתן להריץ מחדש את האתחול",
|
|
392
392
|
"bootstrap_reference_missing": "ארכיטקטורת ההפניה נעלמה",
|
|
393
393
|
"preset_unsatisfiable": "קדם‑הגדרת המודל אינה יכולה להריץ צנרת זו",
|
|
394
|
-
"visual_pipeline_no_frontend": "אין frontend לבדיקה"
|
|
394
|
+
"visual_pipeline_no_frontend": "אין frontend לבדיקה",
|
|
395
|
+
"deployer_required_before_tester": "הוסף Deployer לפני ה-Tester"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "פעולה זו מתנגשת עם המצב הנוכחי.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "מאגר הקוד של בלוק זה אינו נמצא בין מאגרי GitHub המחוברים, ולכן לא ניתן לקרוא אותו. חבר או סנכרן את GitHub עבורו ונסה שוב.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "תוכן",
|
|
465
467
|
"hint": "המודולים והמשימות בתוך בלוק זה. לחץ על פריט כדי לבחור אותו בלוח.",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "ブートストラップは再試行できません",
|
|
392
392
|
"bootstrap_reference_missing": "リファレンスアーキテクチャが見つかりません",
|
|
393
393
|
"preset_unsatisfiable": "モデルプリセットではこのパイプラインを実行できません",
|
|
394
|
-
"visual_pipeline_no_frontend": "テスト対象のフロントエンドがありません"
|
|
394
|
+
"visual_pipeline_no_frontend": "テスト対象のフロントエンドがありません",
|
|
395
|
+
"deployer_required_before_tester": "テスターの前にDeployerを追加してください"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "この操作は現在の状態と競合します。",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "このブロックのリポジトリは接続済みの GitHub リポジトリに含まれていないため、読み取れません。GitHub を接続または同期してから、もう一度お試しください。",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "内容",
|
|
465
467
|
"hint": "このブロック内のモジュールとタスク。エントリをクリックするとボード上で選択されます。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "Inicjalizacji nie można ponowić",
|
|
392
392
|
"bootstrap_reference_missing": "Architektura referencyjna zniknęła",
|
|
393
393
|
"preset_unsatisfiable": "Ten zestaw modeli nie może uruchomić tego potoku",
|
|
394
|
-
"visual_pipeline_no_frontend": "Brak frontendu do przetestowania"
|
|
394
|
+
"visual_pipeline_no_frontend": "Brak frontendu do przetestowania",
|
|
395
|
+
"deployer_required_before_tester": "Dodaj Deployer przed Testerem"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "Ta akcja jest sprzeczna z bieżącym stanem.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "Repozytorium tego bloku nie znajduje się wśród połączonych repozytoriów GitHub, więc nie można go odczytać. Połącz lub zsynchronizuj GitHub dla tego repozytorium, a następnie spróbuj ponownie.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "Zawartość",
|
|
465
467
|
"hint": "Moduły i zadania wewnątrz tego bloku. Kliknij pozycję, aby zaznaczyć ją na tablicy.",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "Bootstrap yeniden denenemiyor",
|
|
392
392
|
"bootstrap_reference_missing": "Referans mimari kayıp",
|
|
393
393
|
"preset_unsatisfiable": "Model ön ayarı bu ardışık düzeni çalıştıramıyor",
|
|
394
|
-
"visual_pipeline_no_frontend": "Test edilecek bir frontend yok"
|
|
394
|
+
"visual_pipeline_no_frontend": "Test edilecek bir frontend yok",
|
|
395
|
+
"deployer_required_before_tester": "Tester’dan önce bir Deployer ekleyin"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "Bu eylem mevcut durumla çelişiyor.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "Bu bloğun deposu bağlı GitHub depoları arasında değil, bu yüzden okunamıyor. Bunun için GitHub'ı bağlayın veya eşitleyin, ardından yeniden deneyin.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "İçerik",
|
|
465
467
|
"hint": "Bu bloğun içindeki modüller ve görevler. Bir öğeye tıklayarak panoda seçin.",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -391,7 +391,8 @@
|
|
|
391
391
|
"bootstrap_not_retryable": "Ініціалізацію неможливо повторити",
|
|
392
392
|
"bootstrap_reference_missing": "Еталонна архітектура зникла",
|
|
393
393
|
"preset_unsatisfiable": "Пресет моделі не може запустити цей конвеєр",
|
|
394
|
-
"visual_pipeline_no_frontend": "Немає фронтенду для тестування"
|
|
394
|
+
"visual_pipeline_no_frontend": "Немає фронтенду для тестування",
|
|
395
|
+
"deployer_required_before_tester": "Додайте Deployer перед Tester"
|
|
395
396
|
},
|
|
396
397
|
"fallbackMessage": "Ця дія суперечить поточному стану.",
|
|
397
398
|
"providersUnconfigured": {
|
|
@@ -460,6 +461,7 @@
|
|
|
460
461
|
}
|
|
461
462
|
},
|
|
462
463
|
"inspector": {
|
|
464
|
+
"detectRepoUnresolved": "Репозиторій цього блоку відсутній серед підключених репозиторіїв GitHub, тому його не вдається прочитати. Підключіть або синхронізуйте GitHub для нього та повторіть спробу.",
|
|
463
465
|
"container": {
|
|
464
466
|
"title": "Вміст",
|
|
465
467
|
"hint": "Модулі та завдання всередині цього блока. Клацніть запис, щоб вибрати його на дошці.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.97.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -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.
|
|
37
|
+
"@cat-factory/contracts": "0.108.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|