@cat-factory/app 0.66.0 → 0.67.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.
@@ -37,6 +37,7 @@ const accounts = useAccountsStore()
37
37
  const github = useGitHubStore()
38
38
  const services = useServicesStore()
39
39
  const infra = useInfraConfigStore()
40
+ const agentRuns = useAgentRunsStore()
40
41
  const { t } = useI18n()
41
42
 
42
43
  // The custom-manifest-type catalog feeds the `custom` picker. Cheap + shared (coalesced).
@@ -83,6 +84,12 @@ watch(
83
84
  )
84
85
  const customManifestId = computed(() => props.block.provisioning?.manifestId ?? '')
85
86
  const customManifestPath = computed(() => props.block.provisioning?.manifestPath ?? '')
87
+ // The catalog entry for the pinned custom type — supplies its default manifest path (prefill +
88
+ // detection seed) and whether it can generate/fix (a `fixerPrompt` is declared).
89
+ const selectedCustomType = computed(() =>
90
+ infra.customTypes.find((c) => c.manifestId === customManifestId.value),
91
+ )
92
+ const manifestFixerAvailable = computed(() => !!selectedCustomType.value?.fixerPrompt)
86
93
 
87
94
  const PROVISION_TYPES = computed<{ value: ProvisionType; label: string }[]>(() => [
88
95
  { value: 'infraless', label: t('inspector.testConfig.provisionTypes.infraless') },
@@ -158,14 +165,82 @@ function setKubeRenderer(value: KubernetesRenderer) {
158
165
  commitManifestSource()
159
166
  }
160
167
 
168
+ // Root a service-relative default under the service subtree, normalizing `.`/`..`/empty segments
169
+ // (mirrors the backend `joinPath`). A stored `manifestPath` is always REPO-root-relative — the
170
+ // same form auto-detection produces — so prefill and generate agree with detect.
171
+ function rootUnderDirectory(directory: string | null | undefined, path: string): string {
172
+ const segs: string[] = []
173
+ for (const part of [directory ?? '', path]) {
174
+ for (const seg of part.split('/')) {
175
+ if (!seg || seg === '.') continue
176
+ if (seg === '..') segs.pop()
177
+ else segs.push(seg)
178
+ }
179
+ }
180
+ return segs.join('/')
181
+ }
182
+
161
183
  function setCustomManifestId(value: string) {
162
- patchProvisioning({ type: 'custom', manifestId: value || undefined })
184
+ // Prefill the manifest path with the selected type's default, rooted under the service subtree
185
+ // (repo-root-relative, editable afterwards) so a monorepo service targets the right location
186
+ // even without running Detect. Leave the existing path untouched when the type declares no default.
187
+ const type = infra.customTypes.find((c) => c.manifestId === value)
188
+ const rooted = type?.defaultManifestPath
189
+ ? rootUnderDirectory(repoContext.value?.directory, type.defaultManifestPath)
190
+ : ''
191
+ patchProvisioning({
192
+ type: 'custom',
193
+ manifestId: value || undefined,
194
+ ...(rooted ? { manifestPath: rooted } : {}),
195
+ })
163
196
  }
164
197
 
165
198
  function setCustomManifestPath(value: string) {
166
199
  patchProvisioning({ type: 'custom', manifestPath: value.trim() || undefined })
167
200
  }
168
201
 
202
+ // Generate (or fix) the custom manifest via the fixer coding agent (async repair run). Shown only
203
+ // when the selected type declares a `fixerPrompt`. The dispatched run is tracked live below by id.
204
+ const generating = ref(false)
205
+ const manifestRepairError = ref(false)
206
+ const manifestRepairJobId = ref<string | null>(null)
207
+ const manifestRepairJob = computed(() =>
208
+ manifestRepairJobId.value ? agentRuns.envConfigRepairById(manifestRepairJobId.value) : undefined,
209
+ )
210
+
211
+ async function generateOrFixManifest() {
212
+ const ctx = repoContext.value
213
+ const type = selectedCustomType.value
214
+ if (!ctx || !type?.fixerPrompt) return
215
+ const repo = github.repoFor(ctx.githubId)
216
+ // `manifestPath` is already repo-root-relative (prefill/detect root it); the fallback default
217
+ // still needs rooting for the rare case where nothing was prefilled yet.
218
+ const path =
219
+ customManifestPath.value.trim() ||
220
+ (type.defaultManifestPath ? rootUnderDirectory(ctx.directory, type.defaultManifestPath) : '')
221
+ if (!repo || !path) {
222
+ manifestRepairError.value = true
223
+ return
224
+ }
225
+ generating.value = true
226
+ manifestRepairError.value = false
227
+ manifestRepairJobId.value = null
228
+ try {
229
+ const res = await infra.repairCustomManifest({
230
+ manifestId: type.manifestId,
231
+ owner: repo.owner,
232
+ repo: repo.name,
233
+ manifestPath: path,
234
+ })
235
+ manifestRepairJobId.value = res.repairJobId ?? null
236
+ if (!res.usedAgent) manifestRepairError.value = true
237
+ } catch {
238
+ manifestRepairError.value = true
239
+ } finally {
240
+ generating.value = false
241
+ }
242
+ }
243
+
169
244
  // The provisioning hints (cloud provider + instance size) are advisory inputs to the
170
245
  // ephemeral-environment provisioner, not commonly tuned — keep them collapsed by default.
171
246
  const showProvisioning = ref(false)
@@ -239,19 +314,27 @@ async function detectFromRepo() {
239
314
  owner: repo.owner,
240
315
  repo: repo.name,
241
316
  ...(ctx.directory ? { directory: ctx.directory } : {}),
242
- // Prioritize the option matching the currently-selected tab (kubernetes vs
243
- // docker-compose); the detector falls back to the other when the preferred isn't found.
317
+ // Prioritize the option matching the currently-selected tab (kubernetes / docker-compose /
318
+ // custom); the detector falls back to the other when the preferred isn't found.
244
319
  prefer: provisionType.value,
320
+ // `custom`: the selected type seeds the path search from its default; the current path is
321
+ // kept when it already resolves.
322
+ ...(provisionType.value === 'custom' && customManifestId.value
323
+ ? {
324
+ manifestId: customManifestId.value,
325
+ ...(customManifestPath.value ? { currentManifestPath: customManifestPath.value } : {}),
326
+ }
327
+ : {}),
245
328
  })
246
329
  detectResult.value = rec
247
330
  // Pre-select the recommended compose service so the picker opens on a real choice.
248
331
  pickedComposeService.value =
249
332
  rec.composeServiceCandidates?.find((c) => c.recommended)?.service ?? null
250
- // Only prefill when the detector actually inferred something. A `detected: false`
251
- // recommendation is `infraless`; applying it would WIPE the service's existing
252
- // provisioning (board.updateBlock persists immediately). Leave the current config
253
- // untouched and just surface the "nothing found" note.
254
- if (rec.detected) {
333
+ // Prefill when the detector inferred something. A non-custom `detected: false` recommendation
334
+ // is `infraless`; applying it would WIPE the service's existing provisioning (updateBlock
335
+ // persists immediately) — so we skip it. A `custom` recommendation is non-destructive (it just
336
+ // carries the resolved/default manifest path), so we apply it even when the file wasn't found.
337
+ if (rec.detected || rec.provisioning.type === 'custom') {
255
338
  board.updateBlock(props.block.id, { provisioning: rec.provisioning })
256
339
  if (rec.provisioning.type === 'kubernetes') seedKubeSource(rec.provisioning.manifestSource)
257
340
  }
@@ -369,7 +452,10 @@ function setSize(value: InstanceSize) {
369
452
  </p>
370
453
 
371
454
  <template v-if="detectResult && !detecting">
372
- <p v-if="!detectResult.detected" class="text-[11px] text-amber-300/80">
455
+ <p
456
+ v-if="!detectResult.detected && detectResult.provisioning.type !== 'custom'"
457
+ class="text-[11px] text-amber-300/80"
458
+ >
373
459
  {{ t('inspector.testConfig.detect.none') }}
374
460
  </p>
375
461
  <template v-else>
@@ -659,6 +745,53 @@ function setSize(value: InstanceSize) {
659
745
  (e: KeyboardEvent) => setCustomManifestPath((e.target as HTMLInputElement).value)
660
746
  "
661
747
  />
748
+ <p class="text-[11px] leading-snug text-slate-500">
749
+ {{ t('inspector.testConfig.customManifestPathHint') }}
750
+ </p>
751
+ </div>
752
+
753
+ <!-- Generate (when missing) or fix (when invalid) the manifest via the fixer agent. Only
754
+ shown when the selected type declares a fixer prompt. -->
755
+ <div
756
+ v-if="manifestFixerAvailable && repoContext"
757
+ class="space-y-1.5 rounded border border-slate-800 bg-slate-900/40 p-2"
758
+ >
759
+ <div class="flex items-center justify-between gap-2">
760
+ <span class="text-[11px] text-slate-400">{{
761
+ t('inspector.testConfig.generateManifest.title')
762
+ }}</span>
763
+ <UButton
764
+ size="xs"
765
+ variant="soft"
766
+ color="primary"
767
+ icon="i-lucide-file-cog"
768
+ :loading="generating"
769
+ :disabled="!customManifestPath && !selectedCustomType?.defaultManifestPath"
770
+ @click="generateOrFixManifest"
771
+ >
772
+ {{ t('inspector.testConfig.generateManifest.button') }}
773
+ </UButton>
774
+ </div>
775
+ <p class="text-[11px] leading-snug text-slate-500">
776
+ {{ t('inspector.testConfig.generateManifest.hint') }}
777
+ </p>
778
+ <p v-if="manifestRepairError" class="text-[11px] text-rose-300/80">
779
+ {{ t('inspector.testConfig.generateManifest.error') }}
780
+ </p>
781
+ <p
782
+ v-else-if="manifestRepairJob"
783
+ class="text-[11px]"
784
+ :class="{
785
+ 'text-sky-300/80': manifestRepairJob.status === 'running',
786
+ 'text-emerald-300/80': manifestRepairJob.status === 'succeeded',
787
+ 'text-rose-300/80': manifestRepairJob.status === 'failed',
788
+ }"
789
+ >
790
+ {{ t(`inspector.testConfig.generateManifest.status.${manifestRepairJob.status}`) }}
791
+ </p>
792
+ <p v-else-if="manifestRepairJobId" class="text-[11px] text-sky-300/80">
793
+ {{ t('inspector.testConfig.generateManifest.dispatched') }}
794
+ </p>
662
795
  </div>
663
796
  </div>
664
797
 
@@ -12,7 +12,14 @@ const infra = useInfraConfigStore()
12
12
  const toast = useToast()
13
13
 
14
14
  // A draft for the add/edit form. `manifestId` is locked on edit (it's the PK).
15
- const draft = reactive({ manifestId: '', label: '', acceptsInputHint: '', description: '' })
15
+ const draft = reactive({
16
+ manifestId: '',
17
+ label: '',
18
+ acceptsInputHint: '',
19
+ description: '',
20
+ defaultManifestPath: '',
21
+ fixerPrompt: '',
22
+ })
16
23
  const editing = ref(false)
17
24
  const busy = ref(false)
18
25
 
@@ -22,7 +29,14 @@ const canSave = computed(
22
29
  )
23
30
 
24
31
  function startAdd() {
25
- Object.assign(draft, { manifestId: '', label: '', acceptsInputHint: '', description: '' })
32
+ Object.assign(draft, {
33
+ manifestId: '',
34
+ label: '',
35
+ acceptsInputHint: '',
36
+ description: '',
37
+ defaultManifestPath: '',
38
+ fixerPrompt: '',
39
+ })
26
40
  editing.value = false
27
41
  }
28
42
 
@@ -32,6 +46,8 @@ function startEdit(type: CustomManifestType) {
32
46
  label: type.label,
33
47
  acceptsInputHint: type.acceptsInputHint ?? '',
34
48
  description: type.description ?? '',
49
+ defaultManifestPath: type.defaultManifestPath ?? '',
50
+ fixerPrompt: type.fixerPrompt ?? '',
35
51
  })
36
52
  editing.value = true
37
53
  }
@@ -44,6 +60,10 @@ async function save() {
44
60
  label: draft.label.trim(),
45
61
  ...(draft.acceptsInputHint.trim() ? { acceptsInputHint: draft.acceptsInputHint.trim() } : {}),
46
62
  ...(draft.description.trim() ? { description: draft.description.trim() } : {}),
63
+ ...(draft.defaultManifestPath.trim()
64
+ ? { defaultManifestPath: draft.defaultManifestPath.trim() }
65
+ : {}),
66
+ ...(draft.fixerPrompt.trim() ? { fixerPrompt: draft.fixerPrompt.trim() } : {}),
47
67
  })
48
68
  startAdd()
49
69
  } catch (e) {
@@ -158,6 +178,22 @@ async function remove(type: CustomManifestType) {
158
178
  <UFormField :label="t('settings.infrastructure.customType.description')">
159
179
  <UTextarea v-model="draft.description" :rows="2" />
160
180
  </UFormField>
181
+ <UFormField
182
+ :label="t('settings.infrastructure.customType.defaultManifestPath')"
183
+ :help="t('settings.infrastructure.customType.defaultManifestPathHelp')"
184
+ >
185
+ <UInput
186
+ v-model="draft.defaultManifestPath"
187
+ class="font-mono"
188
+ placeholder="deploy/preview.yaml"
189
+ />
190
+ </UFormField>
191
+ <UFormField
192
+ :label="t('settings.infrastructure.customType.fixerPrompt')"
193
+ :help="t('settings.infrastructure.customType.fixerPromptHelp')"
194
+ >
195
+ <UTextarea v-model="draft.fixerPrompt" :rows="3" />
196
+ </UFormField>
161
197
  <div class="flex justify-end gap-2">
162
198
  <UButton v-if="editing" color="neutral" variant="ghost" size="sm" @click="startAdd">
163
199
  {{ t('common.cancel') }}
@@ -5,6 +5,7 @@ import {
5
5
  registerEnvironmentHandlerContract,
6
6
  removeCustomManifestTypeContract,
7
7
  removeEnvironmentUserHandlerContract,
8
+ repairCustomManifestContract,
8
9
  testEnvironmentHandlerContract,
9
10
  unregisterEnvironmentHandlerContract,
10
11
  upsertCustomManifestTypeContract,
@@ -14,6 +15,7 @@ import type {
14
15
  DetectServiceProvisioningInput,
15
16
  ProvisionType,
16
17
  RegisterEnvironmentHandlerInput,
18
+ RepairCustomManifestInput,
17
19
  TestEnvironmentHandlerInput,
18
20
  UpsertCustomManifestTypeInput,
19
21
  UpsertEnvironmentUserHandlerBody,
@@ -45,6 +47,10 @@ export function infraHandlersApi({ send, ws }: ApiContext) {
45
47
  detectServiceProvisioning: (workspaceId: string, body: DetectServiceProvisioningInput) =>
46
48
  send(detectServiceProvisioningContract, { pathPrefix: ws(workspaceId), body }),
47
49
 
50
+ // Generate/fix a service's custom manifest via the fixer coding agent (async repair run).
51
+ repairCustomManifest: (workspaceId: string, body: RepairCustomManifestInput) =>
52
+ send(repairCustomManifestContract, { pathPrefix: ws(workspaceId), body }),
53
+
48
54
  // `manifestId` (for a `custom` handler) rides as a query param; absent ⇒ the bare handler.
49
55
  unregisterEnvironmentHandler: (
50
56
  workspaceId: string,
@@ -6,6 +6,7 @@ import type {
6
6
  EnvironmentHandlerView,
7
7
  ProvisionType,
8
8
  RegisterEnvironmentHandlerInput,
9
+ RepairCustomManifestInput,
9
10
  TestEnvironmentHandlerInput,
10
11
  UpsertCustomManifestTypeInput,
11
12
  UpsertEnvironmentUserHandlerBody,
@@ -112,6 +113,16 @@ export const useInfraConfigStore = defineStore('infraConfig', () => {
112
113
  return api.detectServiceProvisioning(ws.requireId(), input)
113
114
  }
114
115
 
116
+ /**
117
+ * Generate (or fix) a service's custom manifest via the fixer coding agent. Dispatches a
118
+ * durable async repair run and returns immediately with `usedAgent`/`repairJobId`; the run is
119
+ * tracked via the workspace stream like the provider-config repair. Nothing persisted here.
120
+ */
121
+ async function repairCustomManifest(input: RepairCustomManifestInput) {
122
+ const ws = useWorkspaceStore()
123
+ return api.repairCustomManifest(ws.requireId(), input)
124
+ }
125
+
115
126
  async function unregisterHandler(type: ProvisionType, manifestId?: string | null) {
116
127
  const ws = useWorkspaceStore()
117
128
  await api.unregisterEnvironmentHandler(ws.requireId(), type, manifestId ?? undefined)
@@ -181,6 +192,7 @@ export const useInfraConfigStore = defineStore('infraConfig', () => {
181
192
  registerHandler,
182
193
  testHandler,
183
194
  detectProvisioning,
195
+ repairCustomManifest,
184
196
  unregisterHandler,
185
197
  upsertCustomType,
186
198
  removeCustomType,
@@ -476,6 +476,19 @@
476
476
  "customNoTypes": "No custom manifest types are defined yet. Add one in the Infrastructure window.",
477
477
  "customManifestIdHint": "The custom type this service produces, matched to a remote-custom handler the workspace configures.",
478
478
  "customManifestPath": "Manifest path (optional)",
479
+ "customManifestPathHint": "Prefilled from the type's default when you select it. Use Detect to locate an existing manifest in the repo.",
480
+ "generateManifest": {
481
+ "title": "Manifest file",
482
+ "button": "Generate / fix",
483
+ "hint": "Runs a coding agent to create the manifest at this path (or fix it if it exists but is invalid) and push it to the branch.",
484
+ "error": "Could not start the manifest generation run.",
485
+ "dispatched": "A manifest generation run was started.",
486
+ "status": {
487
+ "running": "Generating the manifest…",
488
+ "succeeded": "Manifest generated and pushed.",
489
+ "failed": "The manifest generation run failed. Retry it from the Infrastructure window."
490
+ }
491
+ },
479
492
  "detect": {
480
493
  "title": "Auto-detect",
481
494
  "button": "Detect from repo",
@@ -1404,6 +1417,10 @@
1404
1417
  "acceptsInputHint": "Input hint (optional)",
1405
1418
  "acceptsInputHintHelp": "Describes the input shape the provider expects.",
1406
1419
  "description": "Description (optional)",
1420
+ "defaultManifestPath": "Default manifest path (optional)",
1421
+ "defaultManifestPathHelp": "Prefilled on a service that pins this type, and the seed for path auto-detection. A complete path (deploy/preview.yaml) or a bare filename.",
1422
+ "fixerPrompt": "Fixer prompt (optional)",
1423
+ "fixerPromptHelp": "Coding-agent instructions to generate or fix the manifest. When set, a service shows a Generate / fix button.",
1407
1424
  "add": "Add type",
1408
1425
  "saveFailed": "Could not save the custom type",
1409
1426
  "removeFailed": "Could not remove the custom type"
@@ -454,6 +454,19 @@
454
454
  "namespace": "Los manifiestos fijan el espacio de nombres \"{namespace}\"; se recomienda respetarlo en el gestor del espacio de trabajo.",
455
455
  "confidenceHigh": "Detectado",
456
456
  "confidenceLow": "Sugerencia"
457
+ },
458
+ "customManifestPathHint": "Se rellena con el valor predeterminado del tipo al seleccionarlo. Usa Detectar para localizar un manifiesto existente en el repositorio.",
459
+ "generateManifest": {
460
+ "title": "Archivo de manifiesto",
461
+ "button": "Generar / corregir",
462
+ "hint": "Ejecuta un agente de código para crear el manifiesto en esta ruta (o corregirlo si existe pero no es válido) y subirlo a la rama.",
463
+ "error": "No se pudo iniciar la generación del manifiesto.",
464
+ "dispatched": "Se inició una ejecución de generación del manifiesto.",
465
+ "status": {
466
+ "running": "Generando el manifiesto…",
467
+ "succeeded": "Manifiesto generado y subido.",
468
+ "failed": "La generación del manifiesto falló. Vuelve a intentarlo desde la ventana de Infraestructura."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1815,7 +1828,11 @@
1815
1828
  "description": "Descripción (opcional)",
1816
1829
  "add": "Añadir tipo",
1817
1830
  "saveFailed": "No se pudo guardar el tipo personalizado",
1818
- "removeFailed": "No se pudo eliminar el tipo personalizado"
1831
+ "removeFailed": "No se pudo eliminar el tipo personalizado",
1832
+ "defaultManifestPath": "Ruta de manifiesto predeterminada (opcional)",
1833
+ "defaultManifestPathHelp": "Se rellena en un servicio que fije este tipo, y es la base para la detección automática de la ruta. Una ruta completa (deploy/preview.yaml) o solo un nombre de archivo.",
1834
+ "fixerPrompt": "Prompt de corrección (opcional)",
1835
+ "fixerPromptHelp": "Instrucciones para el agente de código para generar o corregir el manifiesto. Cuando se define, el servicio muestra un botón Generar / corregir."
1819
1836
  },
1820
1837
  "handler": {
1821
1838
  "intro": "Configura cómo se gestiona cada tipo de aprovisionamiento que declara un servicio: el motor y la conexión. Los manifiestos o la ruta de compose de un servicio (el qué/dónde) se definen en el servicio.",
@@ -454,6 +454,19 @@
454
454
  "namespace": "Les manifestes fixent l'espace de noms « {namespace} » ; il est recommandé de le respecter sur le gestionnaire de l'espace de travail.",
455
455
  "confidenceHigh": "Détecté",
456
456
  "confidenceLow": "Suggestion"
457
+ },
458
+ "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.",
459
+ "generateManifest": {
460
+ "title": "Fichier de manifeste",
461
+ "button": "Générer / corriger",
462
+ "hint": "Lance un agent de code pour créer le manifeste à ce chemin (ou le corriger s'il existe mais n'est pas valide) et le pousser sur la branche.",
463
+ "error": "Impossible de démarrer la génération du manifeste.",
464
+ "dispatched": "Une exécution de génération du manifeste a démarré.",
465
+ "status": {
466
+ "running": "Génération du manifeste…",
467
+ "succeeded": "Manifeste généré et poussé.",
468
+ "failed": "La génération du manifeste a échoué. Réessayez depuis la fenêtre Infrastructure."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1815,7 +1828,11 @@
1815
1828
  "description": "Description (facultatif)",
1816
1829
  "add": "Ajouter le type",
1817
1830
  "saveFailed": "Impossible d'enregistrer le type personnalisé",
1818
- "removeFailed": "Impossible de supprimer le type personnalisé"
1831
+ "removeFailed": "Impossible de supprimer le type personnalisé",
1832
+ "defaultManifestPath": "Chemin de manifeste par défaut (facultatif)",
1833
+ "defaultManifestPathHelp": "Prérempli sur un service qui épingle ce type, et base de la détection automatique du chemin. Un chemin complet (deploy/preview.yaml) ou un simple nom de fichier.",
1834
+ "fixerPrompt": "Prompt de correction (facultatif)",
1835
+ "fixerPromptHelp": "Instructions pour l'agent de code afin de générer ou corriger le manifeste. Lorsqu'il est défini, le service affiche un bouton Générer / corriger."
1819
1836
  },
1820
1837
  "handler": {
1821
1838
  "intro": "Configurez la manière dont chaque type de provisionnement déclaré par un service est géré: le moteur et la connexion. Les manifestes ou le chemin compose d'un service (le quoi/où) se définissent sur le service.",
@@ -454,6 +454,19 @@
454
454
  "namespace": "המניפסטים מקבעים את מרחב השמות \"{namespace}\"; מומלץ לכבד אותו במטפל של המרחב.",
455
455
  "confidenceHigh": "זוהה",
456
456
  "confidenceLow": "הצעה"
457
+ },
458
+ "customManifestPathHint": "מתמלא מברירת המחדל של הסוג בעת הבחירה. השתמש ב'זיהוי' כדי לאתר מניפסט קיים במאגר.",
459
+ "generateManifest": {
460
+ "title": "קובץ מניפסט",
461
+ "button": "צור / תקן",
462
+ "hint": "מריץ סוכן קוד ליצירת המניפסט בנתיב זה (או לתיקונו אם קיים אך אינו תקין) ולדחיפתו לענף.",
463
+ "error": "לא ניתן להתחיל את הפקת המניפסט.",
464
+ "dispatched": "הפקת מניפסט הופעלה.",
465
+ "status": {
466
+ "running": "מפיק את המניפסט…",
467
+ "succeeded": "המניפסט נוצר ונדחף.",
468
+ "failed": "הפקת המניפסט נכשלה. נסה שוב מחלון התשתית."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1364,7 +1377,11 @@
1364
1377
  "description": "תיאור (אופציונלי)",
1365
1378
  "add": "הוסף סוג",
1366
1379
  "saveFailed": "לא ניתן לשמור את הסוג המותאם",
1367
- "removeFailed": "לא ניתן להסיר את הסוג המותאם"
1380
+ "removeFailed": "לא ניתן להסיר את הסוג המותאם",
1381
+ "defaultManifestPath": "נתיב מניפסט ברירת מחדל (אופציונלי)",
1382
+ "defaultManifestPathHelp": "מתמלא בשירות שמצמיד סוג זה, ומשמש בסיס לזיהוי אוטומטי של הנתיב. נתיב מלא (deploy/preview.yaml) או שם קובץ בלבד.",
1383
+ "fixerPrompt": "הנחיית תיקון (אופציונלי)",
1384
+ "fixerPromptHelp": "הוראות לסוכן הקוד ליצירה או תיקון של המניפסט. כאשר מוגדר, השירות מציג כפתור צור / תקן."
1368
1385
  },
1369
1386
  "handler": {
1370
1387
  "intro": "הגדר כיצד מטופל כל סוג אספקה שהשירות מצהיר עליו: המנוע והחיבור. המניפסטים או נתיב ה-compose של שירות (מה/היכן) מוגדרים על השירות.",
@@ -454,6 +454,19 @@
454
454
  "namespace": "マニフェストは名前空間「{namespace}」を固定しています。ワークスペースのハンドラーでそれを尊重することを推奨します。",
455
455
  "confidenceHigh": "検出",
456
456
  "confidenceLow": "提案"
457
+ },
458
+ "customManifestPathHint": "タイプを選択すると既定値が自動入力されます。リポジトリ内の既存のマニフェストを探すには「検出」を使用してください。",
459
+ "generateManifest": {
460
+ "title": "マニフェストファイル",
461
+ "button": "生成 / 修正",
462
+ "hint": "コーディングエージェントを実行して、このパスにマニフェストを作成(存在するが無効な場合は修正)し、ブランチにプッシュします。",
463
+ "error": "マニフェスト生成の実行を開始できませんでした。",
464
+ "dispatched": "マニフェスト生成の実行を開始しました。",
465
+ "status": {
466
+ "running": "マニフェストを生成しています…",
467
+ "succeeded": "マニフェストを生成してプッシュしました。",
468
+ "failed": "マニフェスト生成の実行に失敗しました。インフラウィンドウから再試行してください。"
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1366,7 +1379,11 @@
1366
1379
  "description": "説明(任意)",
1367
1380
  "add": "タイプを追加",
1368
1381
  "saveFailed": "カスタムタイプを保存できませんでした",
1369
- "removeFailed": "カスタムタイプを削除できませんでした"
1382
+ "removeFailed": "カスタムタイプを削除できませんでした",
1383
+ "defaultManifestPath": "既定のマニフェストパス(任意)",
1384
+ "defaultManifestPathHelp": "このタイプを固定するサービスに自動入力され、パス自動検出の起点になります。完全なパス(deploy/preview.yaml)またはファイル名のみ。",
1385
+ "fixerPrompt": "修正プロンプト(任意)",
1386
+ "fixerPromptHelp": "マニフェストを生成または修正するためのコーディングエージェントへの指示。設定すると、サービスに「生成 / 修正」ボタンが表示されます。"
1370
1387
  },
1371
1388
  "handler": {
1372
1389
  "intro": "サービスが宣言する各プロビジョニングタイプの処理方法(エンジンと接続)を構成します。サービスのマニフェストや compose パス(何を/どこで)はサービス側で設定します。",
@@ -454,6 +454,19 @@
454
454
  "namespace": "Manifesty ustalają przestrzeń nazw \"{namespace}\"; zaleca się jej przestrzeganie w handlerze przestrzeni roboczej.",
455
455
  "confidenceHigh": "Wykryto",
456
456
  "confidenceLow": "Sugestia"
457
+ },
458
+ "customManifestPathHint": "Wypełniane wartością domyślną typu po jego wybraniu. Użyj Wykryj, aby znaleźć istniejący manifest w repozytorium.",
459
+ "generateManifest": {
460
+ "title": "Plik manifestu",
461
+ "button": "Generuj / napraw",
462
+ "hint": "Uruchamia agenta kodu, aby utworzyć manifest w tej ścieżce (lub naprawić go, jeśli istnieje, ale jest nieprawidłowy) i wypchnąć go do gałęzi.",
463
+ "error": "Nie udało się rozpocząć generowania manifestu.",
464
+ "dispatched": "Rozpoczęto generowanie manifestu.",
465
+ "status": {
466
+ "running": "Generowanie manifestu…",
467
+ "succeeded": "Manifest wygenerowany i wypchnięty.",
468
+ "failed": "Generowanie manifestu nie powiodło się. Spróbuj ponownie w oknie Infrastruktura."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1815,7 +1828,11 @@
1815
1828
  "description": "Opis (opcjonalnie)",
1816
1829
  "add": "Dodaj typ",
1817
1830
  "saveFailed": "Nie udało się zapisać niestandardowego typu",
1818
- "removeFailed": "Nie udało się usunąć niestandardowego typu"
1831
+ "removeFailed": "Nie udało się usunąć niestandardowego typu",
1832
+ "defaultManifestPath": "Domyślna ścieżka manifestu (opcjonalnie)",
1833
+ "defaultManifestPathHelp": "Wypełniane dla usługi, która przypina ten typ, oraz podstawa automatycznego wykrywania ścieżki. Pełna ścieżka (deploy/preview.yaml) lub sama nazwa pliku.",
1834
+ "fixerPrompt": "Prompt naprawczy (opcjonalnie)",
1835
+ "fixerPromptHelp": "Instrukcje dla agenta kodu do wygenerowania lub naprawy manifestu. Gdy ustawione, usługa pokazuje przycisk Generuj / napraw."
1819
1836
  },
1820
1837
  "handler": {
1821
1838
  "intro": "Skonfiguruj, jak obsługiwany jest każdy typ provisioningu zadeklarowany przez usługę: silnik i połączenie. Manifesty lub ścieżka compose usługi (co/gdzie) są ustawiane na usłudze.",
@@ -454,6 +454,19 @@
454
454
  "namespace": "Manifestler \"{namespace}\" ad alanını sabitliyor; çalışma alanı işleyicisinde buna uymanız önerilir.",
455
455
  "confidenceHigh": "Algılandı",
456
456
  "confidenceLow": "Öneri"
457
+ },
458
+ "customManifestPathHint": "Türü seçtiğinizde varsayılan değeriyle doldurulur. Depodaki mevcut bir manifesti bulmak için Algıla'yı kullanın.",
459
+ "generateManifest": {
460
+ "title": "Manifest dosyası",
461
+ "button": "Oluştur / düzelt",
462
+ "hint": "Bu yolda manifesti oluşturmak (veya varsa ancak geçersizse düzeltmek) ve dala göndermek için bir kod aracısı çalıştırır.",
463
+ "error": "Manifest oluşturma çalışması başlatılamadı.",
464
+ "dispatched": "Bir manifest oluşturma çalışması başlatıldı.",
465
+ "status": {
466
+ "running": "Manifest oluşturuluyor…",
467
+ "succeeded": "Manifest oluşturuldu ve gönderildi.",
468
+ "failed": "Manifest oluşturma çalışması başarısız oldu. Altyapı penceresinden yeniden deneyin."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1366,7 +1379,11 @@
1366
1379
  "description": "Açıklama (isteğe bağlı)",
1367
1380
  "add": "Tür ekle",
1368
1381
  "saveFailed": "Özel tür kaydedilemedi",
1369
- "removeFailed": "Özel tür kaldırılamadı"
1382
+ "removeFailed": "Özel tür kaldırılamadı",
1383
+ "defaultManifestPath": "Varsayılan manifest yolu (isteğe bağlı)",
1384
+ "defaultManifestPathHelp": "Bu türü sabitleyen bir hizmette önceden doldurulur ve yol otomatik algılamanın temelidir. Tam bir yol (deploy/preview.yaml) veya yalnızca bir dosya adı.",
1385
+ "fixerPrompt": "Düzeltme istemi (isteğe bağlı)",
1386
+ "fixerPromptHelp": "Manifesti oluşturmak veya düzeltmek için kod aracısı talimatları. Ayarlandığında hizmette bir Oluştur / düzelt düğmesi gösterilir."
1370
1387
  },
1371
1388
  "handler": {
1372
1389
  "intro": "Bir servisin bildirdiği her sağlama türünün nasıl ele alınacağını yapılandırın: motor ve bağlantı. Bir servisin manifestleri veya compose yolu (ne/nerede) serviste ayarlanır.",
@@ -454,6 +454,19 @@
454
454
  "namespace": "Маніфести фіксують простір імен \"{namespace}\"; рекомендуємо дотримуватися його в обробнику робочого простору.",
455
455
  "confidenceHigh": "Виявлено",
456
456
  "confidenceLow": "Пропозиція"
457
+ },
458
+ "customManifestPathHint": "Заповнюється значенням типу за замовчуванням під час вибору. Скористайтеся «Виявити», щоб знайти наявний маніфест у репозиторії.",
459
+ "generateManifest": {
460
+ "title": "Файл маніфесту",
461
+ "button": "Згенерувати / виправити",
462
+ "hint": "Запускає агента коду, щоб створити маніфест за цим шляхом (або виправити його, якщо він існує, але недійсний) і надіслати до гілки.",
463
+ "error": "Не вдалося розпочати генерування маніфесту.",
464
+ "dispatched": "Розпочато генерування маніфесту.",
465
+ "status": {
466
+ "running": "Генерування маніфесту…",
467
+ "succeeded": "Маніфест згенеровано та надіслано.",
468
+ "failed": "Генерування маніфесту не вдалося. Повторіть спробу у вікні «Інфраструктура»."
469
+ }
457
470
  }
458
471
  },
459
472
  "agentConfig": {
@@ -1815,7 +1828,11 @@
1815
1828
  "description": "Опис (необов'язково)",
1816
1829
  "add": "Додати тип",
1817
1830
  "saveFailed": "Не вдалося зберегти власний тип",
1818
- "removeFailed": "Не вдалося видалити власний тип"
1831
+ "removeFailed": "Не вдалося видалити власний тип",
1832
+ "defaultManifestPath": "Типовий шлях маніфесту (необов’язково)",
1833
+ "defaultManifestPathHelp": "Заповнюється для сервісу, який закріплює цей тип, і є основою для автоматичного визначення шляху. Повний шлях (deploy/preview.yaml) або лише ім’я файлу.",
1834
+ "fixerPrompt": "Промпт для виправлення (необов’язково)",
1835
+ "fixerPromptHelp": "Інструкції для агента коду щодо генерування або виправлення маніфесту. Якщо задано, сервіс показує кнопку «Згенерувати / виправити»."
1819
1836
  },
1820
1837
  "handler": {
1821
1838
  "intro": "Налаштуйте, як обробляється кожен тип провіженінгу, оголошений службою: рушій і з'єднання. Маніфести або шлях compose служби (що/де) задаються на службі.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.66.0",
3
+ "version": "0.67.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.72.0"
37
+ "@cat-factory/contracts": "0.73.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",