@cat-factory/app 0.296.0 → 0.296.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.
@@ -1,11 +1,13 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import {
3
3
  defaultBootstrapDelivery,
4
+ referenceRefusalOf,
5
+ referenceRefusalSurvivesSave,
4
6
  serviceDirectoryLeaf,
5
7
  serviceDirectoryParent,
6
8
  } from '~/components/bootstrap/BootstrapModal.logic'
7
9
 
8
- // The rule these two pin is what makes the field browsable AND typable at once: the tree hands
10
+ // The rule the first two pin is what makes the field browsable AND typable at once: the tree hands
9
11
  // back the folder it was standing in plus the leaf, so a name someone typed has to survive a
10
12
  // trip through the tree. Reading the leaf off the service name instead would silently discard it.
11
13
 
@@ -43,6 +45,79 @@ describe('serviceDirectoryParent', () => {
43
45
  })
44
46
  })
45
47
 
48
+ // The refusal a launch can come back with. Both halves are read off ONE wire envelope and the
49
+ // stakes are the same in either direction: a banner that is dropped while it is still true takes
50
+ // away the only pointer to the broken entry, and one kept after it is fixed reads as a live error.
51
+ describe('referenceRefusalOf', () => {
52
+ /** The envelope shape the contract client throws, as `apiErrorEnvelope` reads it. */
53
+ const failure = (details: Record<string, unknown>) => ({ body: { error: { details } } })
54
+
55
+ it('reads the reason and the two fields that name the offending entry', () => {
56
+ expect(
57
+ referenceRefusalOf(
58
+ failure({
59
+ reason: 'reference_repo_not_found',
60
+ referenceArchitectureId: 'ref_1',
61
+ repo: 'acme/service-template',
62
+ }),
63
+ ),
64
+ ).toEqual({
65
+ reason: 'reference_repo_not_found',
66
+ architectureId: 'ref_1',
67
+ repo: 'acme/service-template',
68
+ })
69
+ })
70
+
71
+ it('keeps the two reasons apart, since only one of them means the entry is wrong', () => {
72
+ expect(referenceRefusalOf(failure({ reason: 'reference_repo_unreadable' }))?.reason).toBe(
73
+ 'reference_repo_unreadable',
74
+ )
75
+ })
76
+
77
+ it('is null for every other failure, so an unrelated error never shows this banner', () => {
78
+ expect(referenceRefusalOf(failure({ reason: 'github_not_connected' }))).toBeNull()
79
+ expect(referenceRefusalOf(failure({}))).toBeNull()
80
+ expect(referenceRefusalOf(new Error('network down'))).toBeNull()
81
+ expect(referenceRefusalOf(undefined)).toBeNull()
82
+ })
83
+
84
+ it('answers null for the ids rather than trusting whatever the field held', () => {
85
+ // The refusal drives a jump to one entry, so a non-string id must not reach the lookup as one.
86
+ expect(
87
+ referenceRefusalOf(
88
+ failure({ reason: 'reference_repo_not_found', referenceArchitectureId: 7, repo: null }),
89
+ ),
90
+ ).toEqual({ reason: 'reference_repo_not_found', architectureId: null, repo: null })
91
+ })
92
+ })
93
+
94
+ describe('referenceRefusalSurvivesSave', () => {
95
+ const refusal = {
96
+ reason: 'reference_repo_not_found',
97
+ architectureId: 'ref_1',
98
+ repo: 'acme/service-template',
99
+ } as const
100
+
101
+ it('is cleared by saving the entry it named: that entry no longer reads the way it did', () => {
102
+ expect(referenceRefusalSurvivesSave('ref_1', refusal)).toBe(false)
103
+ })
104
+
105
+ it('survives an edit to a DIFFERENT entry, which changed nothing about this claim', () => {
106
+ expect(referenceRefusalSurvivesSave('ref_2', refusal)).toBe(true)
107
+ })
108
+
109
+ it('survives CREATING an entry beside the refused one', () => {
110
+ // The case that lost the banner: adding an architecture while the refused one is still
111
+ // selected and still unreachable, so the next launch fails again with nothing pointing at it.
112
+ expect(referenceRefusalSurvivesSave(null, refusal)).toBe(true)
113
+ expect(referenceRefusalSurvivesSave(undefined, refusal)).toBe(true)
114
+ })
115
+
116
+ it('has nothing to survive when no refusal stands', () => {
117
+ expect(referenceRefusalSurvivesSave('ref_1', null)).toBe(false)
118
+ })
119
+ })
120
+
46
121
  describe('defaultBootstrapDelivery', () => {
47
122
  it('reviews a monorepo and pushes a repository being created', () => {
48
123
  // The form has to SHOW the default it is about to send, and the two targets want opposite
@@ -1,12 +1,14 @@
1
+ import type { BootstrapReferenceReason } from '@cat-factory/contracts'
2
+ import { apiErrorEnvelope, apiErrorReason } from '~/composables/api/errors'
1
3
  import type { BootstrapDelivery } from '~/types/domain'
2
4
  import { repoPathSegments } from '~/utils/repoPath'
3
5
 
4
- // The pure half of the bootstrap launch form's monorepo service-directory field. That field
5
- // holds one string but carries two decisions: what the new directory is CALLED and WHERE in the
6
- // repo it sits. Browsing the repo tree answers only the second, so it rewrites the parent and
7
- // keeps the leaf, which means both halves have to be readable off the typed value on their own.
8
- // Extracted for the reason every `*.logic.ts` here is: a decision worth a test should not need a
9
- // mounted component to reach.
6
+ // The pure half of the bootstrap launch form: the monorepo service-directory field, the delivery
7
+ // default, and the refusal a launch can come back with. The directory field holds one string but
8
+ // carries two decisions: what the new directory is CALLED and WHERE in the repo it sits. Browsing
9
+ // the repo tree answers only the second, so it rewrites the parent and keeps the leaf, which means
10
+ // both halves have to be readable off the typed value on their own. Extracted for the reason every
11
+ // `*.logic.ts` here is: a decision worth a test should not need a mounted component to reach.
10
12
 
11
13
  /**
12
14
  * What the new directory is called: the last segment of the typed path.
@@ -42,3 +44,50 @@ export function serviceDirectoryParent(directory: string): string {
42
44
  export function defaultBootstrapDelivery(intoMonorepo: boolean): BootstrapDelivery {
43
45
  return intoMonorepo ? 'pull_request' : 'direct_push'
44
46
  }
47
+
48
+ /** A launch the backend refused because of the reference architecture it named. */
49
+ export interface ReferenceRefusal {
50
+ reason: BootstrapReferenceReason
51
+ /** The entry that named the repository, so the fix opens the right one of several. */
52
+ architectureId: string | null
53
+ /** `owner/name` as the entry spells it. */
54
+ repo: string | null
55
+ }
56
+
57
+ /**
58
+ * The refusal a failed launch carries, or null when it failed for anything else.
59
+ *
60
+ * The reason comes from the shared `apiErrorReason`, never a second hand-rolled read of the same
61
+ * wire field: that helper is what keeps a renamed code a typecheck failure here instead of a
62
+ * silent fall-through to the generic toast. The envelope is read directly only for the two extra
63
+ * fields this refusal carries, which no shared accessor knows about.
64
+ */
65
+ export function referenceRefusalOf(error: unknown): ReferenceRefusal | null {
66
+ const reason = apiErrorReason(error)
67
+ if (reason !== 'reference_repo_not_found' && reason !== 'reference_repo_unreadable') return null
68
+ const details = (apiErrorEnvelope(error)?.details ?? {}) as Record<string, unknown>
69
+ return {
70
+ reason,
71
+ architectureId:
72
+ typeof details.referenceArchitectureId === 'string' ? details.referenceArchitectureId : null,
73
+ repo: typeof details.repo === 'string' ? details.repo : null,
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Whether saving a reference architecture makes a standing refusal stale.
79
+ *
80
+ * Only the entry the refusal NAMED: that one has been rewritten, so the refusal no longer
81
+ * describes it, and whether the new value is reachable is the next launch's question. Every other
82
+ * save leaves it alone. Clearing on any save is the bug this answers: adding a second
83
+ * architecture, or editing an unrelated one, dropped the banner while the refused entry was still
84
+ * selected and still unreachable, taking away the one affordance pointing at the problem.
85
+ */
86
+ export function referenceRefusalSurvivesSave(
87
+ /** The entry that was saved, or null/undefined when the save CREATED a new one. */
88
+ savedArchitectureId: string | null | undefined,
89
+ refusal: ReferenceRefusal | null,
90
+ ): boolean {
91
+ if (!refusal) return false
92
+ return !savedArchitectureId || savedArchitectureId !== refusal.architectureId
93
+ }
@@ -12,6 +12,9 @@ import type {
12
12
  } from '~/types/domain'
13
13
  import {
14
14
  defaultBootstrapDelivery,
15
+ type ReferenceRefusal,
16
+ referenceRefusalOf,
17
+ referenceRefusalSurvivesSave,
15
18
  serviceDirectoryLeaf,
16
19
  serviceDirectoryParent,
17
20
  } from '~/components/bootstrap/BootstrapModal.logic'
@@ -243,6 +246,49 @@ const selectedArch = computed(() =>
243
246
  bootstrap.architectures.find((a) => a.id === selectedArchId.value),
244
247
  )
245
248
 
249
+ // ---- a launch refused for its reference architecture -----------------------
250
+ // The backend pre-flights the template against the workspace's source-control connection BEFORE
251
+ // it records anything, so this refusal costs the user nothing except a correction: the run does
252
+ // not exist, the board has no card, and every other field of this form is still filled in. That
253
+ // is what the alert is for. A toast would say the same words and then disappear, leaving the
254
+ // person to work out which of the two repositories in this dialog was the problem. Reading it off
255
+ // the wire, and deciding when a save makes it stale, are in `BootstrapModal.logic.ts`.
256
+ const referenceRefusal = ref<ReferenceRefusal | null>(null)
257
+
258
+ const referenceRefusalMessage = computed(() => {
259
+ const refusal = referenceRefusal.value
260
+ if (!refusal) return ''
261
+ const repo = refusal.repo ?? t('bootstrap.reference.refusal.unnamedRepo')
262
+ return refusal.reason === 'reference_repo_not_found'
263
+ ? t('bootstrap.reference.refusal.notFound', { repo })
264
+ : t('bootstrap.reference.refusal.unreadable', { repo })
265
+ })
266
+
267
+ /**
268
+ * Whether correcting the ENTRY is the fix. Only for `not_found`: an unreadable probe says nothing
269
+ * about the entry, so offering to edit it there would send someone to change a value that is
270
+ * very likely already right.
271
+ */
272
+ const referenceRefusalIsFixable = computed(
273
+ () => referenceRefusal.value?.reason === 'reference_repo_not_found',
274
+ )
275
+
276
+ /** Open the refused entry's edit form, prefilled, leaving the launch form untouched. */
277
+ function editRefusedArchitecture() {
278
+ const id = referenceRefusal.value?.architectureId
279
+ const arch = bootstrap.architectures.find((a) => a.id === id)
280
+ if (arch) startEdit(arch)
281
+ }
282
+
283
+ // A refusal is about ONE entry as it was, so picking a different reference architecture makes it
284
+ // stale, and a stale error banner reads as a live one. Reopening the dialog clears it for the same
285
+ // reason: the form deliberately keeps its fields across opens, but a refusal is not a field, it is
286
+ // a claim about a check that has not been made again. Saving the refused entry clears it too
287
+ // (`saveArch`), and saving any other one deliberately does not.
288
+ watch([open, selectedArchId], () => {
289
+ referenceRefusal.value = null
290
+ })
291
+
246
292
  const archOptions = computed(() =>
247
293
  bootstrap.architectures.map((a) => ({
248
294
  label: `${a.name} · ${a.repoOwner}/${a.repoName}`,
@@ -433,6 +479,10 @@ async function launch() {
433
479
  ui.closeBootstrap()
434
480
  }
435
481
  } catch (e) {
482
+ // A reference-architecture refusal is kept on the form as well as toasted: the run was never
483
+ // recorded, so what the user needs is the one field to change and everything else left alone,
484
+ // which a toast cannot hold still long enough to give them.
485
+ referenceRefusal.value = referenceRefusalOf(e)
436
486
  present(e, 'bootstrap.toast.bootstrapFailed')
437
487
  } finally {
438
488
  launching.value = false
@@ -513,8 +563,12 @@ async function saveArch() {
513
563
  description: archForm.value.description.trim(),
514
564
  defaultInstructions: archForm.value.defaultInstructions.trim(),
515
565
  }
516
- if (archForm.value.id) await bootstrap.updateArchitecture(archForm.value.id, body)
566
+ const editedId = archForm.value.id
567
+ if (editedId) await bootstrap.updateArchitecture(editedId, body)
517
568
  else await bootstrap.createArchitecture(body)
569
+ if (!referenceRefusalSurvivesSave(editedId, referenceRefusal.value)) {
570
+ referenceRefusal.value = null
571
+ }
518
572
  showArchForm.value = false
519
573
  archForm.value = blankForm()
520
574
  archRepoSlug.value = undefined
@@ -706,6 +760,31 @@ const statusLabel = computed<Record<BootstrapStatus, string>>(() => ({
706
760
  class="w-full"
707
761
  />
708
762
  </UFormField>
763
+
764
+ <!-- The launch was refused for the template, before anything was recorded. The
765
+ remedy lives in this same dialog, so the alert carries the jump to it rather
766
+ than describing where to go. -->
767
+ <UAlert
768
+ v-if="referenceRefusal"
769
+ color="error"
770
+ variant="subtle"
771
+ icon="i-lucide-triangle-alert"
772
+ :title="t('bootstrap.reference.refusal.title')"
773
+ :description="referenceRefusalMessage"
774
+ data-testid="bootstrap-reference-refusal"
775
+ >
776
+ <template v-if="referenceRefusalIsFixable" #actions>
777
+ <UButton
778
+ color="error"
779
+ variant="soft"
780
+ size="xs"
781
+ icon="i-lucide-pencil"
782
+ @click="editRefusedArchitecture"
783
+ >
784
+ {{ t('bootstrap.reference.refusal.edit') }}
785
+ </UButton>
786
+ </template>
787
+ </UAlert>
709
788
  </template>
710
789
 
711
790
  <UFormField
@@ -30,13 +30,17 @@ const back = useIntegrationBack(open)
30
30
  // Popular slugs offered by "Enable recommended" — these mirror the curated `openrouter`
31
31
  // refs in the backend MODEL_CATALOG. Only the ones present in the live browse list are
32
32
  // ticked, so a recommendation never enables a slug OpenRouter doesn't actually serve.
33
+ // The contributor tier of Muse Spark is deliberately absent: it is cheaper because Meta
34
+ // trains on the traffic, and a one-click "enable recommended" is the wrong place to make
35
+ // that trade on somebody's behalf.
33
36
  const RECOMMENDED_SLUGS = [
34
- 'anthropic/claude-fable-5',
37
+ 'anthropic/claude-fable-5.1',
35
38
  'anthropic/claude-opus-5',
36
39
  'openai/gpt-5.6-sol',
37
40
  'openai/gpt-5.6-terra',
38
41
  'google/gemini-3.1-pro-preview',
39
- 'google/gemini-3.6-flash',
42
+ 'google/gemini-3.8-flash',
43
+ 'meta/muse-spark-1.3',
40
44
  'deepseek/deepseek-v4-flash',
41
45
  'moonshotai/kimi-k2.7-code',
42
46
  'z-ai/glm-5.2',
@@ -5,6 +5,7 @@ import {
5
5
  describeGenericFailure,
6
6
  } from '~/composables/usePipelineErrorToast'
7
7
  import { ApiError } from '~/composables/api/errors'
8
+ import { BOOTSTRAP_REFERENCE_REASONS, UNAVAILABLE_REASONS } from '@cat-factory/contracts'
8
9
  import en from '../../i18n/locales/en.json'
9
10
 
10
11
  /**
@@ -304,6 +305,23 @@ describe('describeGenericFailure', () => {
304
305
  ).toBe('errors.generic.description.unexpected')
305
306
  })
306
307
 
308
+ it('gives every reason with its own copy a key that ships, and lets it beat the status class', () => {
309
+ // Derived from the vocabularies the code reads rather than pinned to a count: a new reason is
310
+ // supposed to be an ordinary addition, and an expectation that fails on every one of them
311
+ // trains the next person to re-pin it unread. What is worth asserting is the property the
312
+ // exhaustive `Record` alone cannot make, that the key it maps to actually EXISTS in the
313
+ // catalog, and that a reason wins over the status class it is attached to. Both refusals here
314
+ // reach a person who can act on them, and the generic 503 wording ("this deployment has not
315
+ // configured the capability") would send them to configure something that is already wired.
316
+ for (const reason of [...UNAVAILABLE_REASONS, ...BOOTSTRAP_REFERENCE_REASONS]) {
317
+ const failure = describeGenericFailure(
318
+ new ApiError(503, { error: { code: 'unavailable', details: { reason } } }),
319
+ )
320
+ expect(failure.descriptionKey).not.toBe('errors.generic.description.unavailable')
321
+ expect(hasKey(failure.descriptionKey), `${reason} has no copy`).toBe(true)
322
+ }
323
+ })
324
+
307
325
  it('never presents a conflict (parseConflict owns those) but still classifies safely', () => {
308
326
  // `conflict` is deliberately absent from the map, so it reads as an unrecognised code rather
309
327
  // than throwing — the conflict path intercepts it long before this function is reached.
@@ -28,7 +28,12 @@ import { createBespokeConflictToasts } from '~/composables/pipelineErrorToast/be
28
28
  // Imported by path rather than left to Nuxt's auto-import: this module is also loaded directly by
29
29
  // unit tests (and from store setup), where the auto-import globals are not installed.
30
30
  import { useCopyToClipboard } from '~/composables/useCopyToClipboard'
31
- import type { ApiErrorCode, ConflictReason, UnavailableReason } from '@cat-factory/contracts'
31
+ import type {
32
+ ApiErrorCode,
33
+ BootstrapReferenceReason,
34
+ ConflictReason,
35
+ UnavailableReason,
36
+ } from '@cat-factory/contracts'
32
37
  import { apiErrorEnvelope, apiErrorReason, apiErrorStatus } from './api/errors'
33
38
 
34
39
  /** The parsed shape of a backend conflict (`{ error: { code: 'conflict', details } }`). */
@@ -386,8 +391,16 @@ const GENERIC_DESCRIPTION_KEYS: Record<Exclude<ApiErrorCode, 'conflict'>, string
386
391
  * the reasons in {@link UNAVAILABLE_REASONS} carry their own copy, and the exhaustive `Record`
387
392
  * over that union is the drift guard: a new user-reachable 503 reason fails this typecheck until
388
393
  * it has wording.
394
+ *
395
+ * `BootstrapReferenceReason` joins it because the same argument reaches one 422: a bootstrap
396
+ * refused for its reference architecture is not "the request was malformed", it names a specific
397
+ * entry a specific person can go and fix. The launch dialog handles that one itself, since it can
398
+ * open the entry. This is what every OTHER caller of the funnel is told instead of the status
399
+ * class's generic wording, above all a retry driven from the run card.
389
400
  */
390
- const UNAVAILABLE_DESCRIPTION_KEYS: Record<UnavailableReason, string> = {
401
+ const REASON_DESCRIPTION_KEYS: Record<UnavailableReason | BootstrapReferenceReason, string> = {
402
+ reference_repo_not_found: 'errors.reason.description.reference_repo_not_found',
403
+ reference_repo_unreadable: 'errors.reason.description.reference_repo_unreadable',
391
404
  binary_generators_unreachable: 'errors.unavailable.description.binary_generators_unreachable',
392
405
  foundational_builtins_unreachable:
393
406
  'errors.unavailable.description.foundational_builtins_unreachable',
@@ -445,7 +458,7 @@ export function describeGenericFailure(error: unknown): GenericFailure {
445
458
  // A REASON that has its own copy wins over the status class's, through the same widened-alias
446
459
  // read and for the same reason: a `reason` this build doesn't know must resolve to `undefined`
447
460
  // and fall through, never narrow the wire string to the union by casting.
448
- const byReason: Readonly<Record<string, string | undefined>> = UNAVAILABLE_DESCRIPTION_KEYS
461
+ const byReason: Readonly<Record<string, string | undefined>> = REASON_DESCRIPTION_KEYS
449
462
  const reason = apiErrorReason(error)
450
463
  const mapped =
451
464
  (reason ? byReason[reason] : undefined) ?? (envelope?.code ? byCode[envelope.code] : undefined)
@@ -5050,7 +5050,14 @@
5050
5050
  "label": "Referenzarchitektur",
5051
5051
  "description": "Das verwaltete Basis-Repo zum Klonen und Anpassen.",
5052
5052
  "empty": "Noch keine Referenzarchitekturen. Fügen Sie unten eine hinzu oder wechseln Sie zu 'Von Grund auf'.",
5053
- "placeholder": "Referenzarchitektur wählen"
5053
+ "placeholder": "Referenzarchitektur wählen",
5054
+ "refusal": {
5055
+ "title": "Diese Referenzarchitektur konnte nicht verwendet werden",
5056
+ "notFound": "{repo} ist über die Quellcodeverwaltungs-Verbindung dieses Workspace nicht sichtbar. Entweder nennt dieser Eintrag das falsche Repository, oder die Verbindung hat keinen Zugriff darauf. Es wurde nichts angelegt: Korrigieren Sie den Eintrag und starten Sie erneut, alles andere in diesem Formular bleibt erhalten.",
5057
+ "unreadable": "{repo} konnte gerade nicht gelesen werden, deshalb wurde nichts angelegt. Es ist nichts falsch konfiguriert: Starten Sie erneut, sobald die Verbindung wieder steht, alles andere in diesem Formular bleibt erhalten.",
5058
+ "unnamedRepo": "Das Repository der Referenzarchitektur",
5059
+ "edit": "Diese Referenzarchitektur bearbeiten"
5060
+ }
5054
5061
  },
5055
5062
  "targetRepo": {
5056
5063
  "label": "Name des Ziel-Repositorys",
@@ -6105,6 +6112,12 @@
6105
6112
  "service_catalog_response_too_large": "Das Entwicklerportal hat mit mehr Daten geantwortet, als diese Plattform in einer Antwort aufnimmt. Öffne die Servicekatalog-Einstellungen und senke das Service-Limit oder deaktiviere den Import von Schnittstellendefinitionen, und importiere dann erneut."
6106
6113
  }
6107
6114
  },
6115
+ "reason": {
6116
+ "description": {
6117
+ "reference_repo_not_found": "Das Repository hinter der Referenzarchitektur dieses Laufs ist über die Quellcodeverwaltungs-Verbindung dieses Workspace nicht sichtbar. Entweder nennt der Eintrag das falsche Repository, oder die Verbindung hat keinen Zugriff darauf: Korrigieren Sie die Referenzarchitektur oder erteilen Sie den Zugriff, und versuchen Sie es erneut.",
6118
+ "reference_repo_unreadable": "Das Repository hinter der Referenzarchitektur dieses Laufs konnte gerade nicht gelesen werden, deshalb wurde der Lauf nicht gegen eine Vorlage gestartet, die er möglicherweise nicht klonen kann. Es ist nichts falsch konfiguriert und keine Änderung nötig: versuchen Sie es erneut, sobald die Verbindung wieder steht."
6119
+ }
6120
+ },
6108
6121
  "action": {
6109
6122
  "retryFailed": "Wiederholung fehlgeschlagen",
6110
6123
  "startFailed": "Start fehlgeschlagen",
@@ -709,6 +709,12 @@
709
709
  "service_catalog_response_too_large": "The developer portal answered with more data than this platform will hold in one response. Open the service-catalog settings and lower the service cap, or turn off importing interface definitions, then import again."
710
710
  }
711
711
  },
712
+ "reason": {
713
+ "description": {
714
+ "reference_repo_not_found": "The repository behind this run's reference architecture cannot be seen through this workspace's source-control connection. Either the entry names the wrong repository, or the connection has not been granted access to it: correct the reference architecture, or grant it access, then try again.",
715
+ "reference_repo_unreadable": "The repository behind this run's reference architecture could not be read just now, so the run was not started against a template it might be unable to clone. Nothing here is misconfigured and no change is needed: try again once the source-control connection recovers."
716
+ }
717
+ },
712
718
  "action": {
713
719
  "retryFailed": "Retry failed",
714
720
  "startFailed": "Failed to start",
@@ -7243,7 +7249,14 @@
7243
7249
  "label": "Reference architecture",
7244
7250
  "description": "The managed base repo to clone and adapt.",
7245
7251
  "empty": "No reference architectures yet. Add one below, or switch to 'From scratch'.",
7246
- "placeholder": "Choose a reference architecture"
7252
+ "placeholder": "Choose a reference architecture",
7253
+ "refusal": {
7254
+ "title": "This reference architecture could not be used",
7255
+ "notFound": "{repo} cannot be seen through this workspace's source-control connection. Either this entry names the wrong repository, or the connection has not been granted access to it. Nothing was created, so correct the entry and launch again: everything else on this form is kept.",
7256
+ "unreadable": "{repo} could not be read just now, so nothing was created. Nothing here is misconfigured: launch again once the source-control connection recovers, and everything else on this form is kept.",
7257
+ "unnamedRepo": "The reference architecture's repository",
7258
+ "edit": "Edit this reference architecture"
7259
+ }
7247
7260
  },
7248
7261
  "targetRepo": {
7249
7262
  "label": "Target repository name",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "El portal de desarrollo respondió con más datos de los que esta plataforma admite en una sola respuesta. Abre la configuración del catálogo de servicios y reduce el límite de servicios, o desactiva la importación de definiciones de interfaz, y vuelve a importar."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "El repositorio de la arquitectura de referencia de esta ejecución no es visible a través de la conexión de control de código de este espacio de trabajo. O la entrada indica el repositorio equivocado, o la conexión no tiene acceso a él: corrige la arquitectura de referencia, o concédele acceso, e inténtalo de nuevo.",
643
+ "reference_repo_unreadable": "No se ha podido leer en este momento el repositorio de la arquitectura de referencia de esta ejecución, así que no se ha iniciado contra una plantilla que quizá no pueda clonar. No hay nada mal configurado ni hace falta ningún cambio: inténtalo de nuevo cuando se restablezca la conexión."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "El reintento falló",
642
648
  "startFailed": "No se pudo iniciar",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "Arquitectura de referencia",
6921
6927
  "description": "El repositorio base gestionado que se clona y adapta.",
6922
6928
  "empty": "Aún no hay arquitecturas de referencia. Añade una abajo o cambia a 'Desde cero'.",
6923
- "placeholder": "Elige una arquitectura de referencia"
6929
+ "placeholder": "Elige una arquitectura de referencia",
6930
+ "refusal": {
6931
+ "title": "No se ha podido usar esta arquitectura de referencia",
6932
+ "notFound": "{repo} no es visible a través de la conexión de control de código de este espacio de trabajo. O esta entrada indica el repositorio equivocado, o la conexión no tiene acceso a él. No se ha creado nada: corrige la entrada y vuelve a lanzar, todo lo demás de este formulario se conserva.",
6933
+ "unreadable": "{repo} no se ha podido leer en este momento, así que no se ha creado nada. No hay nada mal configurado: vuelve a lanzar cuando se restablezca la conexión, todo lo demás de este formulario se conserva.",
6934
+ "unnamedRepo": "El repositorio de la arquitectura de referencia",
6935
+ "edit": "Editar esta arquitectura de referencia"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "Nombre del repositorio de destino",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "Le portail développeur a renvoyé plus de données que cette plateforme n'en accepte dans une seule réponse. Ouvrez les paramètres du catalogue de services et abaissez la limite de services, ou désactivez l'import des définitions d'interface, puis relancez l'import."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "Le dépôt de l'architecture de référence de cette exécution n'est pas visible via la connexion de gestion de code de cet espace de travail. Soit l'entrée désigne le mauvais dépôt, soit la connexion n'y a pas accès : corrigez l'architecture de référence, ou accordez-lui l'accès, puis réessayez.",
643
+ "reference_repo_unreadable": "Le dépôt de l'architecture de référence de cette exécution n'a pas pu être lu pour l'instant, l'exécution n'a donc pas été lancée sur un modèle qu'elle pourrait ne pas savoir cloner. Rien n'est mal configuré et aucune modification n'est nécessaire : réessayez une fois la connexion rétablie."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "Échec de la nouvelle tentative",
642
648
  "startFailed": "Échec du démarrage",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "Architecture de référence",
6921
6927
  "description": "Le dépôt de base géré à cloner et à adapter.",
6922
6928
  "empty": "Aucune architecture de référence pour l'instant. Ajoutez-en une ci-dessous, ou passez à « À partir de zéro ».",
6923
- "placeholder": "Choisissez une architecture de référence"
6929
+ "placeholder": "Choisissez une architecture de référence",
6930
+ "refusal": {
6931
+ "title": "Cette architecture de référence n'a pas pu être utilisée",
6932
+ "notFound": "{repo} n'est pas visible via la connexion de gestion de code de cet espace de travail. Soit cette entrée désigne le mauvais dépôt, soit la connexion n'y a pas accès. Rien n'a été créé : corrigez l'entrée et relancez, tout le reste de ce formulaire est conservé.",
6933
+ "unreadable": "{repo} n'a pas pu être lu pour l'instant, rien n'a donc été créé. Rien n'est mal configuré : relancez une fois la connexion rétablie, tout le reste de ce formulaire est conservé.",
6934
+ "unnamedRepo": "Le dépôt de l'architecture de référence",
6935
+ "edit": "Modifier cette architecture de référence"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "Nom du dépôt cible",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "פורטל המפתחים החזיר יותר נתונים ממה שהפלטפורמה הזו מחזיקה בתשובה אחת. פתחו את הגדרות קטלוג השירותים והנמיכו את מגבלת השירותים, או כבו את ייבוא הגדרות הממשק, ואז ייבאו שוב."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "המאגר שמאחורי ארכיטקטורת הייחוס של ההרצה הזו אינו נראה דרך חיבור ניהול הקוד של סביבת העבודה. או שהרשומה מציינת מאגר שגוי, או שלחיבור לא ניתנה גישה אליו: תקנו את ארכיטקטורת הייחוס, או העניקו לה גישה, ונסו שוב.",
643
+ "reference_repo_unreadable": "לא ניתן היה לקרוא כרגע את המאגר שמאחורי ארכיטקטורת הייחוס של ההרצה הזו, ולכן ההרצה לא הופעלה מול תבנית שאולי לא תוכל לשכפל. אין כאן תצורה שגויה ולא נדרש שום שינוי: נסו שוב כשהחיבור יחזור."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "הניסיון החוזר נכשל",
642
648
  "startFailed": "ההפעלה נכשלה",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "ארכיטקטורת ייחוס",
6921
6927
  "description": "מאגר הבסיס המנוהל לשכפול והתאמה.",
6922
6928
  "empty": "אין עדיין ארכיטקטורות ייחוס. הוסף אחת למטה, או עבור ל'מאפס'.",
6923
- "placeholder": "בחר ארכיטקטורת ייחוס"
6929
+ "placeholder": "בחר ארכיטקטורת ייחוס",
6930
+ "refusal": {
6931
+ "title": "לא ניתן היה להשתמש בארכיטקטורת הייחוס הזו",
6932
+ "notFound": "המאגר {repo} אינו נראה דרך חיבור ניהול הקוד של סביבת העבודה. או שהרשומה הזו מציינת מאגר שגוי, או שלחיבור לא ניתנה גישה אליו. לא נוצר דבר: תקנו את הרשומה והפעילו שוב, כל שאר השדות בטופס נשמרים.",
6933
+ "unreadable": "לא ניתן היה לקרוא כרגע את {repo}, ולכן לא נוצר דבר. אין כאן תצורה שגויה: הפעילו שוב כשהחיבור יחזור, כל שאר השדות בטופס נשמרים.",
6934
+ "unnamedRepo": "המאגר של ארכיטקטורת הייחוס",
6935
+ "edit": "ערכו את ארכיטקטורת הייחוס הזו"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "שם מאגר היעד",
@@ -5050,7 +5050,14 @@
5050
5050
  "label": "Architettura di riferimento",
5051
5051
  "description": "Il repository base gestito da clonare e adattare.",
5052
5052
  "empty": "Nessuna architettura di riferimento ancora. Aggiungine una qui sotto, oppure passa a 'Da zero'.",
5053
- "placeholder": "Scegli un'architettura di riferimento"
5053
+ "placeholder": "Scegli un'architettura di riferimento",
5054
+ "refusal": {
5055
+ "title": "Non è stato possibile usare questa architettura di riferimento",
5056
+ "notFound": "{repo} non è visibile attraverso la connessione di controllo del codice di questo workspace. O questa voce indica il repository sbagliato, o la connessione non vi ha accesso. Non è stato creato nulla: correggi la voce e riavvia, tutto il resto di questo modulo viene mantenuto.",
5057
+ "unreadable": "{repo} non è risultato leggibile in questo momento, quindi non è stato creato nulla. Non c'è nulla di configurato male: riavvia quando la connessione sarà ripristinata, tutto il resto di questo modulo viene mantenuto.",
5058
+ "unnamedRepo": "Il repository dell'architettura di riferimento",
5059
+ "edit": "Modifica questa architettura di riferimento"
5060
+ }
5054
5061
  },
5055
5062
  "targetRepo": {
5056
5063
  "label": "Nome del repository di destinazione",
@@ -6105,6 +6112,12 @@
6105
6112
  "service_catalog_response_too_large": "Il portale per sviluppatori ha risposto con più dati di quanti questa piattaforma ne accolga in una sola risposta. Apri le impostazioni del catalogo dei servizi e abbassa il limite dei servizi, oppure disattiva l'importazione delle definizioni di interfaccia, poi importa di nuovo."
6106
6113
  }
6107
6114
  },
6115
+ "reason": {
6116
+ "description": {
6117
+ "reference_repo_not_found": "Il repository dietro l'architettura di riferimento di questa esecuzione non è visibile attraverso la connessione di controllo del codice di questo workspace. O la voce indica il repository sbagliato, o la connessione non vi ha accesso: correggi l'architettura di riferimento, oppure concedile l'accesso, e riprova.",
6118
+ "reference_repo_unreadable": "Non è stato possibile leggere in questo momento il repository dietro l'architettura di riferimento di questa esecuzione, quindi l'esecuzione non è stata avviata su un modello che potrebbe non riuscire a clonare. Non c'è nulla di configurato male e non serve alcuna modifica: riprova quando la connessione sarà ripristinata."
6119
+ }
6120
+ },
6108
6121
  "action": {
6109
6122
  "retryFailed": "Nuovo tentativo non riuscito",
6110
6123
  "startFailed": "Avvio non riuscito",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "開発者ポータルが、このプラットフォームが 1 回の応答で保持できる量を超えるデータを返しました。サービスカタログの設定を開いてサービス上限を下げるか、インターフェース定義の取り込みをオフにしてから、もう一度取り込んでください。"
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "この実行のリファレンスアーキテクチャが指すリポジトリは、このワークスペースのソース管理接続からは参照できません。エントリが誤ったリポジトリを指しているか、接続にアクセス権が付与されていません。リファレンスアーキテクチャを修正するか、アクセス権を付与してから、もう一度お試しください。",
643
+ "reference_repo_unreadable": "この実行のリファレンスアーキテクチャが指すリポジトリを現在読み取れなかったため、クローンできない可能性のあるテンプレートに対して実行は開始されませんでした。設定に誤りはなく、変更も不要です。接続が回復してからもう一度お試しください。"
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "再試行に失敗しました",
642
648
  "startFailed": "開始に失敗しました",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "リファレンスアーキテクチャ",
6921
6927
  "description": "クローンして適用する管理対象のベースリポジトリ。",
6922
6928
  "empty": "リファレンスアーキテクチャがまだありません。下で追加するか、'ゼロから' に切り替えてください。",
6923
- "placeholder": "リファレンスアーキテクチャを選択"
6929
+ "placeholder": "リファレンスアーキテクチャを選択",
6930
+ "refusal": {
6931
+ "title": "このリファレンスアーキテクチャは使用できませんでした",
6932
+ "notFound": "{repo} は、このワークスペースのソース管理接続からは参照できません。このエントリが誤ったリポジトリを指しているか、接続にアクセス権が付与されていません。何も作成されていません。エントリを修正して再度開始してください。このフォームの他の入力内容はそのまま保持されます。",
6933
+ "unreadable": "{repo} を現在読み取れなかったため、何も作成されていません。設定に誤りはありません。接続が回復してから再度開始してください。このフォームの他の入力内容はそのまま保持されます。",
6934
+ "unnamedRepo": "リファレンスアーキテクチャのリポジトリ",
6935
+ "edit": "このリファレンスアーキテクチャを編集"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "ターゲットリポジトリ名",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "Portal deweloperski zwrócił więcej danych, niż ta platforma przyjmuje w jednej odpowiedzi. Otwórz ustawienia katalogu usług i obniż limit usług albo wyłącz importowanie definicji interfejsów, a następnie zaimportuj ponownie."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "Repozytorium stojące za architekturą referencyjną tego uruchomienia nie jest widoczne przez połączenie kontroli źródeł tej przestrzeni roboczej. Albo wpis wskazuje niewłaściwe repozytorium, albo połączenie nie ma do niego dostępu: popraw architekturę referencyjną lub nadaj jej dostęp i spróbuj ponownie.",
643
+ "reference_repo_unreadable": "Nie udało się teraz odczytać repozytorium stojącego za architekturą referencyjną tego uruchomienia, więc nie zostało ono uruchomione na szablonie, którego może nie umieć sklonować. Nic nie jest źle skonfigurowane i nie trzeba nic zmieniać: spróbuj ponownie, gdy połączenie wróci."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "Ponowienie nie powiodło się",
642
648
  "startFailed": "Nie udało się uruchomić",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "Architektura referencyjna",
6921
6927
  "description": "Zarządzane repozytorium bazowe do sklonowania i dostosowania.",
6922
6928
  "empty": "Brak architektur referencyjnych. Dodaj jedną poniżej lub przełącz na „Od zera”.",
6923
- "placeholder": "Wybierz architekturę referencyjną"
6929
+ "placeholder": "Wybierz architekturę referencyjną",
6930
+ "refusal": {
6931
+ "title": "Nie udało się użyć tej architektury referencyjnej",
6932
+ "notFound": "Nie widać {repo} przez połączenie kontroli źródeł tej przestrzeni roboczej. Albo ten wpis wskazuje niewłaściwe repozytorium, albo połączenie nie ma do niego dostępu. Nic nie zostało utworzone: popraw wpis i uruchom ponownie, reszta tego formularza zostaje zachowana.",
6933
+ "unreadable": "Nie udało się teraz odczytać {repo}, więc nic nie zostało utworzone. Nic nie jest źle skonfigurowane: uruchom ponownie, gdy połączenie wróci, reszta tego formularza zostaje zachowana.",
6934
+ "unnamedRepo": "repozytorium architektury referencyjnej",
6935
+ "edit": "Edytuj tę architekturę referencyjną"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "Nazwa repozytorium docelowego",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "Geliştirici portalı, bu platformun tek bir yanıtta tutacağından daha fazla veri döndürdü. Servis kataloğu ayarlarını açıp servis sınırını düşürün ya da arayüz tanımlarının aktarımını kapatın, sonra yeniden aktarın."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "Bu çalıştırmanın referans mimarisinin arkasındaki depo, bu çalışma alanının kaynak denetimi bağlantısı üzerinden görülemiyor. Ya kayıt yanlış depoyu gösteriyor ya da bağlantıya erişim verilmemiş: referans mimarisini düzeltin veya erişim verin, sonra yeniden deneyin.",
643
+ "reference_repo_unreadable": "Bu çalıştırmanın referans mimarisinin arkasındaki depo şu anda okunamadı, bu yüzden klonlayamayabileceği bir şablon üzerinde başlatılmadı. Yanlış yapılandırılmış bir şey yok ve bir değişiklik gerekmiyor: bağlantı düzeldiğinde yeniden deneyin."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "Yeniden deneme başarısız oldu",
642
648
  "startFailed": "Başlatılamadı",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "Referans mimari",
6921
6927
  "description": "Klonlanacak ve uyarlanacak yönetilen temel depo.",
6922
6928
  "empty": "Henüz referans mimari yok. Aşağıdan bir tane ekleyin veya 'Sıfırdan' seçeneğine geçin.",
6923
- "placeholder": "Bir referans mimari seçin"
6929
+ "placeholder": "Bir referans mimari seçin",
6930
+ "refusal": {
6931
+ "title": "Bu referans mimari kullanılamadı",
6932
+ "notFound": "{repo}, bu çalışma alanının kaynak denetimi bağlantısı üzerinden görülemiyor. Ya bu kayıt yanlış depoyu gösteriyor ya da bağlantıya erişim verilmemiş. Hiçbir şey oluşturulmadı: kaydı düzeltip yeniden başlatın, bu formdaki diğer her şey korunur.",
6933
+ "unreadable": "{repo} şu anda okunamadı, bu yüzden hiçbir şey oluşturulmadı. Yanlış yapılandırılmış bir şey yok: bağlantı düzeldiğinde yeniden başlatın, bu formdaki diğer her şey korunur.",
6934
+ "unnamedRepo": "Referans mimarinin deposu",
6935
+ "edit": "Bu referans mimariyi düzenle"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "Hedef depo adı",
@@ -637,6 +637,12 @@
637
637
  "service_catalog_response_too_large": "Портал розробника повернув більше даних, ніж ця платформа приймає в одній відповіді. Відкрийте налаштування каталогу сервісів і знизьте ліміт сервісів або вимкніть імпорт визначень інтерфейсів, а тоді імпортуйте ще раз."
638
638
  }
639
639
  },
640
+ "reason": {
641
+ "description": {
642
+ "reference_repo_not_found": "Репозиторій, на який вказує еталонна архітектура цього запуску, не видно через з'єднання з системою контролю версій цього робочого простору. Або запис вказує на не той репозиторій, або з'єднанню не надано до нього доступ: виправте еталонну архітектуру або надайте доступ і спробуйте ще раз.",
643
+ "reference_repo_unreadable": "Наразі не вдалося прочитати репозиторій, на який вказує еталонна архітектура цього запуску, тож запуск не було розпочато на шаблоні, який він, можливо, не зможе клонувати. Нічого не налаштовано неправильно і жодних змін не потрібно: спробуйте ще раз, коли з'єднання відновиться."
644
+ }
645
+ },
640
646
  "action": {
641
647
  "retryFailed": "Не вдалося повторити",
642
648
  "startFailed": "Не вдалося запустити",
@@ -6920,7 +6926,14 @@
6920
6926
  "label": "Еталонна архітектура",
6921
6927
  "description": "Кероване базове репо для клонування й адаптації.",
6922
6928
  "empty": "Еталонних архітектур ще немає. Додайте одну нижче або перемкніться на «З нуля».",
6923
- "placeholder": "Виберіть еталонну архітектуру"
6929
+ "placeholder": "Виберіть еталонну архітектуру",
6930
+ "refusal": {
6931
+ "title": "Не вдалося скористатися цією еталонною архітектурою",
6932
+ "notFound": "Не видно {repo} через з'єднання з системою контролю версій цього робочого простору. Або цей запис вказує на не той репозиторій, або з'єднанню не надано до нього доступ. Нічого не створено: виправте запис і запустіть знову, решта цієї форми зберігається.",
6933
+ "unreadable": "Наразі не вдалося прочитати {repo}, тож нічого не створено. Нічого не налаштовано неправильно: запустіть знову, коли з'єднання відновиться, решта цієї форми зберігається.",
6934
+ "unnamedRepo": "репозиторій еталонної архітектури",
6935
+ "edit": "Редагувати цю еталонну архітектуру"
6936
+ }
6924
6937
  },
6925
6938
  "targetRepo": {
6926
6939
  "label": "Назва цільового репозиторію",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.296.0",
3
+ "version": "0.296.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",
@@ -18,7 +18,7 @@
18
18
  "access": "public"
19
19
  },
20
20
  "dependencies": {
21
- "@cat-factory/contracts": "0.346.0",
21
+ "@cat-factory/contracts": "0.346.1",
22
22
  "@modular-frontend/core": "0.6.0",
23
23
  "@modular-vue/core": "^1.5.0",
24
24
  "@modular-vue/journeys": "^1.4.0",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",
47
- "happy-dom": "^20.12.0",
47
+ "happy-dom": "^20.13.2",
48
48
  "msw": "^2.15.0",
49
49
  "nuxt": "^4.5.2",
50
50
  "typescript": "^6.0.3",