@cat-factory/app 0.63.1 → 0.65.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.
- package/app/components/auth/LoginScreen.vue +26 -0
- package/app/components/panels/inspector/ServiceTestConfig.vue +85 -0
- package/app/composables/api/auth.ts +6 -0
- package/app/stores/auth.ts +59 -1
- package/i18n/locales/en.json +8 -0
- package/i18n/locales/es.json +8 -0
- package/i18n/locales/fr.json +8 -0
- package/i18n/locales/he.json +8 -0
- package/i18n/locales/ja.json +8 -0
- package/i18n/locales/pl.json +8 -0
- package/i18n/locales/tr.json +8 -0
- package/i18n/locales/uk.json +8 -0
- package/package.json +2 -2
|
@@ -32,6 +32,9 @@ const configuredProviders = computed<PatProvider[]>(
|
|
|
32
32
|
)
|
|
33
33
|
const isLocalMode = computed(() => auth.localMode?.enabled === true)
|
|
34
34
|
const hasConfiguredPat = computed(() => configuredProviders.value.length > 0)
|
|
35
|
+
// Mothership mode: identity + org data live on a hosted mothership, so the primary sign-in is a
|
|
36
|
+
// round-trip to the mothership's OAuth (the node then exchanges the session for a machine token).
|
|
37
|
+
const isMothership = computed(() => auth.localMode?.mothership === true)
|
|
35
38
|
|
|
36
39
|
const patBusy = ref(false)
|
|
37
40
|
const patError = ref<string | null>(null)
|
|
@@ -186,6 +189,29 @@ const noSignInMethod = computed(
|
|
|
186
189
|
</p>
|
|
187
190
|
</div>
|
|
188
191
|
|
|
192
|
+
<!-- Mothership mode: sign in through the hosted mothership (it owns identity + the
|
|
193
|
+
allowlist). The node exchanges the returned session for a machine token. -->
|
|
194
|
+
<div v-if="isMothership && mode !== 'forgot'" class="mb-4 space-y-2">
|
|
195
|
+
<UButton
|
|
196
|
+
block
|
|
197
|
+
size="lg"
|
|
198
|
+
color="primary"
|
|
199
|
+
icon="i-lucide-cloud"
|
|
200
|
+
data-testid="mothership-signin"
|
|
201
|
+
@click="auth.signInViaMothership()"
|
|
202
|
+
>
|
|
203
|
+
{{ t('auth.mothership.signIn') }}
|
|
204
|
+
</UButton>
|
|
205
|
+
<p class="px-1 text-xs text-slate-400">{{ t('auth.mothership.hint') }}</p>
|
|
206
|
+
<p
|
|
207
|
+
v-if="auth.mothershipError"
|
|
208
|
+
class="px-1 text-xs text-rose-400"
|
|
209
|
+
data-testid="mothership-error"
|
|
210
|
+
>
|
|
211
|
+
{{ t('auth.mothership.error') }}
|
|
212
|
+
</p>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
189
215
|
<!-- Local mode: sign in with the env-configured source-control PAT. The token lives
|
|
190
216
|
server-side (GITHUB_PAT / GITLAB_PAT); we only pick a provider here. -->
|
|
191
217
|
<div v-if="isLocalMode && mode !== 'forgot'" class="space-y-3">
|
|
@@ -10,8 +10,11 @@ import type {
|
|
|
10
10
|
import type {
|
|
11
11
|
KubernetesManifestSource,
|
|
12
12
|
KubernetesRenderer,
|
|
13
|
+
ProvisioningComposeServiceCandidate,
|
|
14
|
+
ProvisioningManifestRootCandidate,
|
|
13
15
|
ProvisioningOverlayCandidate,
|
|
14
16
|
ProvisioningRecommendation,
|
|
17
|
+
ProvisioningServiceDirCandidate,
|
|
15
18
|
} from '@cat-factory/contracts'
|
|
16
19
|
import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
|
|
17
20
|
|
|
@@ -204,6 +207,11 @@ function applyPicked() {
|
|
|
204
207
|
const detecting = ref(false)
|
|
205
208
|
const detectError = ref(false)
|
|
206
209
|
const detectResult = ref<ProvisioningRecommendation | null>(null)
|
|
210
|
+
// Advisory, LOCAL-ONLY selection: which compose `services:` key the user picked. It is NOT persisted
|
|
211
|
+
// (the compose backend targets the file, not a single service), so it lives only in component state
|
|
212
|
+
// and merely drives the chip highlight. Without it the highlight would compare `composePath` — which
|
|
213
|
+
// every candidate shares — and light up ALL chips at once, making the picker look non-functional.
|
|
214
|
+
const pickedComposeService = ref<string | null>(null)
|
|
207
215
|
|
|
208
216
|
// A detection result is scoped to the inspected block — clear it (and any error) when the
|
|
209
217
|
// selection changes, so block B never shows block A's stale recommendation / overlay chips.
|
|
@@ -212,6 +220,7 @@ watch(
|
|
|
212
220
|
() => {
|
|
213
221
|
detectResult.value = null
|
|
214
222
|
detectError.value = false
|
|
223
|
+
pickedComposeService.value = null
|
|
215
224
|
},
|
|
216
225
|
)
|
|
217
226
|
|
|
@@ -235,6 +244,9 @@ async function detectFromRepo() {
|
|
|
235
244
|
prefer: provisionType.value,
|
|
236
245
|
})
|
|
237
246
|
detectResult.value = rec
|
|
247
|
+
// Pre-select the recommended compose service so the picker opens on a real choice.
|
|
248
|
+
pickedComposeService.value =
|
|
249
|
+
rec.composeServiceCandidates?.find((c) => c.recommended)?.service ?? null
|
|
238
250
|
// Only prefill when the detector actually inferred something. A `detected: false`
|
|
239
251
|
// recommendation is `infraless`; applying it would WIPE the service's existing
|
|
240
252
|
// provisioning (board.updateBlock persists immediately). Leave the current config
|
|
@@ -255,6 +267,25 @@ function applyOverlay(candidate: ProvisioningOverlayCandidate) {
|
|
|
255
267
|
setKubePath(candidate.path)
|
|
256
268
|
}
|
|
257
269
|
|
|
270
|
+
// Point the manifest path at a different k8s root (and match its renderer) the user picks.
|
|
271
|
+
function applyManifestRoot(candidate: ProvisioningManifestRootCandidate) {
|
|
272
|
+
setKubePath(candidate.path)
|
|
273
|
+
setKubeRenderer(candidate.renderer)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Point the manifest path at a different root-shared monorepo deploy slice the user picks.
|
|
277
|
+
function applyServiceDir(candidate: ProvisioningServiceDirCandidate) {
|
|
278
|
+
setKubePath(candidate.path)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Point the compose file at the picked candidate's file and record the advisory service selection.
|
|
282
|
+
// The service KEY is not persisted (the compose backend targets the file, not a single service); the
|
|
283
|
+
// picked key is tracked locally only to drive the chip highlight and the note.
|
|
284
|
+
function applyComposeService(candidate: ProvisioningComposeServiceCandidate) {
|
|
285
|
+
setComposePath(candidate.composePath)
|
|
286
|
+
pickedComposeService.value = candidate.service
|
|
287
|
+
}
|
|
288
|
+
|
|
258
289
|
function provisionTypeLabel(type: ProvisionType): string {
|
|
259
290
|
return t(`inspector.testConfig.provisionTypes.${type}`)
|
|
260
291
|
}
|
|
@@ -350,6 +381,42 @@ function setSize(value: InstanceSize) {
|
|
|
350
381
|
}}
|
|
351
382
|
</p>
|
|
352
383
|
|
|
384
|
+
<div v-if="detectResult.serviceDirCandidates?.length" class="space-y-1">
|
|
385
|
+
<span class="text-[11px] text-slate-400">{{
|
|
386
|
+
t('inspector.testConfig.detect.serviceDirTitle')
|
|
387
|
+
}}</span>
|
|
388
|
+
<div class="flex flex-wrap gap-1">
|
|
389
|
+
<UButton
|
|
390
|
+
v-for="s in detectResult.serviceDirCandidates"
|
|
391
|
+
:key="s.path"
|
|
392
|
+
:color="kubePath === s.path ? 'primary' : 'neutral'"
|
|
393
|
+
:variant="kubePath === s.path ? 'soft' : 'ghost'"
|
|
394
|
+
size="xs"
|
|
395
|
+
@click="applyServiceDir(s)"
|
|
396
|
+
>
|
|
397
|
+
{{ s.name }}
|
|
398
|
+
</UButton>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
|
|
402
|
+
<div v-if="detectResult.manifestRootCandidates?.length" class="space-y-1">
|
|
403
|
+
<span class="text-[11px] text-slate-400">{{
|
|
404
|
+
t('inspector.testConfig.detect.manifestRootTitle')
|
|
405
|
+
}}</span>
|
|
406
|
+
<div class="flex flex-wrap gap-1">
|
|
407
|
+
<UButton
|
|
408
|
+
v-for="r in detectResult.manifestRootCandidates"
|
|
409
|
+
:key="r.path"
|
|
410
|
+
:color="kubePath === r.path ? 'primary' : 'neutral'"
|
|
411
|
+
:variant="kubePath === r.path ? 'soft' : 'ghost'"
|
|
412
|
+
size="xs"
|
|
413
|
+
@click="applyManifestRoot(r)"
|
|
414
|
+
>
|
|
415
|
+
{{ r.name }}
|
|
416
|
+
</UButton>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
|
|
353
420
|
<div v-if="detectResult.overlayCandidates?.length" class="space-y-1">
|
|
354
421
|
<span class="text-[11px] text-slate-400">{{
|
|
355
422
|
t('inspector.testConfig.detect.overlayTitle')
|
|
@@ -368,6 +435,24 @@ function setSize(value: InstanceSize) {
|
|
|
368
435
|
</div>
|
|
369
436
|
</div>
|
|
370
437
|
|
|
438
|
+
<div v-if="detectResult.composeServiceCandidates?.length" class="space-y-1">
|
|
439
|
+
<span class="text-[11px] text-slate-400">{{
|
|
440
|
+
t('inspector.testConfig.detect.composeServiceTitle')
|
|
441
|
+
}}</span>
|
|
442
|
+
<div class="flex flex-wrap gap-1">
|
|
443
|
+
<UButton
|
|
444
|
+
v-for="c in detectResult.composeServiceCandidates"
|
|
445
|
+
:key="c.service"
|
|
446
|
+
:color="pickedComposeService === c.service ? 'primary' : 'neutral'"
|
|
447
|
+
:variant="pickedComposeService === c.service ? 'soft' : 'ghost'"
|
|
448
|
+
size="xs"
|
|
449
|
+
@click="applyComposeService(c)"
|
|
450
|
+
>
|
|
451
|
+
{{ c.service }}
|
|
452
|
+
</UButton>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
371
456
|
<p v-if="detectResult.urlSource" class="text-[11px] text-slate-500">
|
|
372
457
|
{{
|
|
373
458
|
t('inspector.testConfig.detect.urlSource', { source: detectResult.urlSource.source })
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
acceptInvitationContract,
|
|
3
3
|
authConfigContract,
|
|
4
|
+
connectMothershipContract,
|
|
4
5
|
forgotPasswordContract,
|
|
5
6
|
logoutContract,
|
|
6
7
|
meContract,
|
|
@@ -51,6 +52,11 @@ export function authApi({ http, send, ws }: ApiContext) {
|
|
|
51
52
|
|
|
52
53
|
logout: () => send(logoutContract, { pathPrefix: '/auth' }),
|
|
53
54
|
|
|
55
|
+
// Mothership mode (local facade): hand the local node a mothership SESSION token (captured
|
|
56
|
+
// from the mothership OAuth redirect fragment). The node exchanges it for a cached machine
|
|
57
|
+
// token and returns a LOCAL session for the same user. Mounted at the app root (no prefix).
|
|
58
|
+
connectMothership: (session: string) => send(connectMothershipContract, { body: { session } }),
|
|
59
|
+
|
|
54
60
|
// Mint a short-lived, workspace-scoped ticket for the events WebSocket. A
|
|
55
61
|
// browser can't set Authorization on a WS handshake, so the socket auths from
|
|
56
62
|
// this `?ticket=` instead of the long-lived session token. Empty string when
|
package/app/stores/auth.ts
CHANGED
|
@@ -60,6 +60,12 @@ export const useAuthStore = defineStore(
|
|
|
60
60
|
const autoLoginProvider = ref<'github' | 'gitlab' | null>(null)
|
|
61
61
|
/** True once the initial auth handshake has settled. */
|
|
62
62
|
const ready = ref(false)
|
|
63
|
+
/**
|
|
64
|
+
* Mothership mode: the last mothership sign-in failure (node unreachable / rejected session),
|
|
65
|
+
* or null. Set when the post-OAuth connect exchange fails, so the login screen can tell the
|
|
66
|
+
* user the click didn't take instead of silently returning them to the sign-in button.
|
|
67
|
+
*/
|
|
68
|
+
const mothershipError = ref<string | null>(null)
|
|
63
69
|
/**
|
|
64
70
|
* True only once `getAuthConfig()` has resolved successfully. Distinguishes "the backend
|
|
65
71
|
* told us auth is off" from "we never reached the backend" (the bootstrap catch path),
|
|
@@ -109,9 +115,59 @@ export const useAuthStore = defineStore(
|
|
|
109
115
|
history.replaceState(null, '', window.location.pathname + window.location.search)
|
|
110
116
|
}
|
|
111
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Mothership mode: when the mothership OAuth redirect returns here (flagged
|
|
120
|
+
* `?mothership_connect=1`), the URL fragment carries a MOTHERSHIP session — not a local one.
|
|
121
|
+
* Hand it to our OWN node, which exchanges it for a cached machine token and returns a LOCAL
|
|
122
|
+
* session for the same user. Returns true when it handled the redirect (so the caller skips
|
|
123
|
+
* the normal `consumeRedirectToken`, which would wrongly store the mothership session locally).
|
|
124
|
+
*/
|
|
125
|
+
async function maybeConnectMothership(): Promise<boolean> {
|
|
126
|
+
if (typeof window === 'undefined') return false
|
|
127
|
+
const params = new URLSearchParams(window.location.search)
|
|
128
|
+
if (params.get('mothership_connect') !== '1') return false
|
|
129
|
+
const match = /(?:^#|[#&])token=([^&]+)/.exec(window.location.hash)
|
|
130
|
+
const session = match ? decodeURIComponent(match[1]!) : null
|
|
131
|
+
// Clean the flag + fragment from the URL regardless of outcome, so it isn't left in history.
|
|
132
|
+
params.delete('mothership_connect')
|
|
133
|
+
const qs = params.toString()
|
|
134
|
+
history.replaceState(null, '', window.location.pathname + (qs ? `?${qs}` : ''))
|
|
135
|
+
if (!session) return true
|
|
136
|
+
try {
|
|
137
|
+
const result = await api.connectMothership(session)
|
|
138
|
+
applySession({ token: result.session, user: result.user })
|
|
139
|
+
mothershipError.value = null
|
|
140
|
+
} catch (err) {
|
|
141
|
+
// Surface the failure so the login screen shows it, rather than silently dropping the
|
|
142
|
+
// user back on the sign-in button as if the click did nothing. The captured session is
|
|
143
|
+
// already stripped from the URL, so recovery is a fresh "Sign in via mothership".
|
|
144
|
+
mothershipError.value =
|
|
145
|
+
err instanceof Error ? err.message : 'Could not connect to the mothership'
|
|
146
|
+
}
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Mothership mode: sign in through the hosted mothership. The mothership owns identity + the
|
|
152
|
+
* allowlist, so we send the browser to ITS OAuth and return here flagged for the connect
|
|
153
|
+
* exchange (`maybeConnectMothership`). No-op if the mothership URL isn't known.
|
|
154
|
+
*/
|
|
155
|
+
function signInViaMothership() {
|
|
156
|
+
if (typeof window === 'undefined') return
|
|
157
|
+
const base = localMode.value?.mothershipUrl
|
|
158
|
+
if (!base) return
|
|
159
|
+
mothershipError.value = null
|
|
160
|
+
const here = new URL(window.location.origin + window.location.pathname)
|
|
161
|
+
here.searchParams.set('mothership_connect', '1')
|
|
162
|
+
const redirect = new URLSearchParams({ redirect: here.toString() })
|
|
163
|
+
window.location.href = `${base.replace(/\/$/, '')}/auth/login?${redirect}`
|
|
164
|
+
}
|
|
165
|
+
|
|
112
166
|
/** Resolve auth state: capture any redirect token, then check the backend. */
|
|
113
167
|
async function bootstrap() {
|
|
114
|
-
|
|
168
|
+
// A returning mothership-connect redirect is handled first (it carries a mothership session,
|
|
169
|
+
// which must be exchanged — not stored as a local token by `consumeRedirectToken`).
|
|
170
|
+
if (!(await maybeConnectMothership())) consumeRedirectToken()
|
|
115
171
|
try {
|
|
116
172
|
const config = await api.getAuthConfig()
|
|
117
173
|
required.value = config.enabled
|
|
@@ -277,6 +333,7 @@ export const useAuthStore = defineStore(
|
|
|
277
333
|
infrastructure,
|
|
278
334
|
autoLoginProvider,
|
|
279
335
|
ready,
|
|
336
|
+
mothershipError,
|
|
280
337
|
configLoaded,
|
|
281
338
|
isLocalFacade,
|
|
282
339
|
isAuthenticated,
|
|
@@ -284,6 +341,7 @@ export const useAuthStore = defineStore(
|
|
|
284
341
|
bootstrap,
|
|
285
342
|
login,
|
|
286
343
|
loginWithGoogle,
|
|
344
|
+
signInViaMothership,
|
|
287
345
|
signup,
|
|
288
346
|
passwordLogin,
|
|
289
347
|
patLogin,
|
package/i18n/locales/en.json
CHANGED
|
@@ -483,6 +483,9 @@
|
|
|
483
483
|
"none": "No Kubernetes manifests or Compose file were detected.",
|
|
484
484
|
"applied": "Suggested a {type} config. Review and adjust the fields below.",
|
|
485
485
|
"overlayTitle": "Ephemeral overlay",
|
|
486
|
+
"serviceDirTitle": "Service deploy folder",
|
|
487
|
+
"manifestRootTitle": "Manifest location",
|
|
488
|
+
"composeServiceTitle": "Compose service",
|
|
486
489
|
"urlSource": "Suggested environment URL source: {source}. The workspace handler owns this; set it there.",
|
|
487
490
|
"namespace": "Manifests pin namespace \"{namespace}\"; recommend honoring it on the workspace handler.",
|
|
488
491
|
"confidenceHigh": "Detected",
|
|
@@ -869,6 +872,11 @@
|
|
|
869
872
|
"userMenu": {
|
|
870
873
|
"mySetup": "My setup",
|
|
871
874
|
"signOut": "Sign out"
|
|
875
|
+
},
|
|
876
|
+
"mothership": {
|
|
877
|
+
"signIn": "Sign in via mothership",
|
|
878
|
+
"hint": "Your projects and identity live on the hosted mothership. Sign in there to connect this node.",
|
|
879
|
+
"error": "Could not sign in via the mothership. Try again."
|
|
872
880
|
}
|
|
873
881
|
},
|
|
874
882
|
"layout": {
|
package/i18n/locales/es.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "No se detectaron manifiestos de Kubernetes ni archivo Compose.",
|
|
447
447
|
"applied": "Se sugirió una configuración {type}. Revisa y ajusta los campos de abajo.",
|
|
448
448
|
"overlayTitle": "Overlay efímero",
|
|
449
|
+
"serviceDirTitle": "Carpeta de despliegue del servicio",
|
|
450
|
+
"manifestRootTitle": "Ubicación del manifiesto",
|
|
451
|
+
"composeServiceTitle": "Servicio de Compose",
|
|
449
452
|
"urlSource": "Fuente de URL del entorno sugerida: {source}. El gestor del espacio de trabajo la controla; configúrala allí.",
|
|
450
453
|
"namespace": "Los manifiestos fijan el espacio de nombres \"{namespace}\"; se recomienda respetarlo en el gestor del espacio de trabajo.",
|
|
451
454
|
"confidenceHigh": "Detectado",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "Mi configuración",
|
|
831
834
|
"signOut": "Cerrar sesión"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "Iniciar sesión con la central",
|
|
838
|
+
"hint": "Tus proyectos e identidad están en la central alojada: inicia sesión allí para conectar este nodo.",
|
|
839
|
+
"error": "No se pudo iniciar sesión con la central. Inténtalo de nuevo."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/fr.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "Aucun manifeste Kubernetes ni fichier Compose détecté.",
|
|
447
447
|
"applied": "Configuration {type} suggérée. Vérifiez et ajustez les champs ci-dessous.",
|
|
448
448
|
"overlayTitle": "Overlay éphémère",
|
|
449
|
+
"serviceDirTitle": "Dossier de déploiement du service",
|
|
450
|
+
"manifestRootTitle": "Emplacement du manifeste",
|
|
451
|
+
"composeServiceTitle": "Service Compose",
|
|
449
452
|
"urlSource": "Source d'URL d'environnement suggérée : {source}. Le gestionnaire de l'espace de travail la contrôle ; définissez-la là.",
|
|
450
453
|
"namespace": "Les manifestes fixent l'espace de noms « {namespace} » ; il est recommandé de le respecter sur le gestionnaire de l'espace de travail.",
|
|
451
454
|
"confidenceHigh": "Détecté",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "Ma configuration",
|
|
831
834
|
"signOut": "Se déconnecter"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "Se connecter via le serveur central",
|
|
838
|
+
"hint": "Vos projets et votre identité sont sur le serveur central hébergé. Connectez-vous là-bas pour relier ce nœud.",
|
|
839
|
+
"error": "Impossible de se connecter via le serveur central. Réessayez."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/he.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "לא זוהו מניפסטים של Kubernetes או קובץ Compose.",
|
|
447
447
|
"applied": "הוצעה תצורת {type}. בדוק והתאם את השדות למטה.",
|
|
448
448
|
"overlayTitle": "שכבת סביבה זמנית",
|
|
449
|
+
"serviceDirTitle": "תיקיית פריסת השירות",
|
|
450
|
+
"manifestRootTitle": "מיקום המניפסט",
|
|
451
|
+
"composeServiceTitle": "שירות Compose",
|
|
449
452
|
"urlSource": "מקור כתובת הסביבה המוצע: {source}. המטפל של המרחב שולט בכך; הגדר זאת שם.",
|
|
450
453
|
"namespace": "המניפסטים מקבעים את מרחב השמות \"{namespace}\"; מומלץ לכבד אותו במטפל של המרחב.",
|
|
451
454
|
"confidenceHigh": "זוהה",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "ההגדרות שלי",
|
|
831
834
|
"signOut": "התנתק"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "התחברות דרך שרת המרכז",
|
|
838
|
+
"hint": "הפרויקטים והזהות שלך נמצאים בשרת המרכז המתארח. התחבר שם כדי לחבר את הצומת הזה.",
|
|
839
|
+
"error": "לא ניתן להתחבר דרך שרת המרכז. נסה שוב."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/ja.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "Kubernetes マニフェストや Compose ファイルは検出されませんでした。",
|
|
447
447
|
"applied": "{type} の設定を提案しました。以下のフィールドを確認して調整してください。",
|
|
448
448
|
"overlayTitle": "一時環境のオーバーレイ",
|
|
449
|
+
"serviceDirTitle": "サービスのデプロイフォルダ",
|
|
450
|
+
"manifestRootTitle": "マニフェストの場所",
|
|
451
|
+
"composeServiceTitle": "Compose サービス",
|
|
449
452
|
"urlSource": "推奨される環境 URL ソース: {source}。これはワークスペースのハンドラーが管理します。そちらで設定してください。",
|
|
450
453
|
"namespace": "マニフェストは名前空間「{namespace}」を固定しています。ワークスペースのハンドラーでそれを尊重することを推奨します。",
|
|
451
454
|
"confidenceHigh": "検出",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "マイセットアップ",
|
|
831
834
|
"signOut": "サインアウト"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "マザーシップ経由でサインイン",
|
|
838
|
+
"hint": "プロジェクトと認証情報はホスト型のマザーシップにあります。そこでサインインしてこのノードを接続してください。",
|
|
839
|
+
"error": "マザーシップ経由でサインインできませんでした。もう一度お試しください。"
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/pl.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "Nie wykryto manifestów Kubernetes ani pliku Compose.",
|
|
447
447
|
"applied": "Zaproponowano konfigurację {type}. Przejrzyj i dostosuj pola poniżej.",
|
|
448
448
|
"overlayTitle": "Tymczasowy overlay",
|
|
449
|
+
"serviceDirTitle": "Folder wdrożenia usługi",
|
|
450
|
+
"manifestRootTitle": "Lokalizacja manifestu",
|
|
451
|
+
"composeServiceTitle": "Usługa Compose",
|
|
449
452
|
"urlSource": "Sugerowane źródło adresu URL środowiska: {source}. Zarządza tym handler przestrzeni roboczej; ustaw to tam.",
|
|
450
453
|
"namespace": "Manifesty ustalają przestrzeń nazw \"{namespace}\"; zaleca się jej przestrzeganie w handlerze przestrzeni roboczej.",
|
|
451
454
|
"confidenceHigh": "Wykryto",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "Moja konfiguracja",
|
|
831
834
|
"signOut": "Wyloguj się"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "Zaloguj się przez serwer centralny",
|
|
838
|
+
"hint": "Twoje projekty i tożsamość znajdują się na hostowanym serwerze centralnym. Zaloguj się tam, aby połączyć ten węzeł.",
|
|
839
|
+
"error": "Nie udało się zalogować przez serwer centralny. Spróbuj ponownie."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/tr.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "Kubernetes manifesti veya Compose dosyası algılanmadı.",
|
|
447
447
|
"applied": "{type} yapılandırması önerildi. Aşağıdaki alanları gözden geçirip ayarlayın.",
|
|
448
448
|
"overlayTitle": "Geçici overlay",
|
|
449
|
+
"serviceDirTitle": "Servis dağıtım klasörü",
|
|
450
|
+
"manifestRootTitle": "Manifest konumu",
|
|
451
|
+
"composeServiceTitle": "Compose servisi",
|
|
449
452
|
"urlSource": "Önerilen ortam URL kaynağı: {source}. Bunu çalışma alanı işleyicisi yönetir; oradan ayarlayın.",
|
|
450
453
|
"namespace": "Manifestler \"{namespace}\" ad alanını sabitliyor; çalışma alanı işleyicisinde buna uymanız önerilir.",
|
|
451
454
|
"confidenceHigh": "Algılandı",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "Kurulumum",
|
|
831
834
|
"signOut": "Oturumu kapat"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "Ana sunucu üzerinden oturum aç",
|
|
838
|
+
"hint": "Projeleriniz ve kimliğiniz barındırılan ana sunucuda tutulur. Bu düğümü bağlamak için orada oturum açın.",
|
|
839
|
+
"error": "Ana sunucu üzerinden oturum açılamadı. Tekrar deneyin."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/i18n/locales/uk.json
CHANGED
|
@@ -446,6 +446,9 @@
|
|
|
446
446
|
"none": "Маніфести Kubernetes або файл Compose не виявлено.",
|
|
447
447
|
"applied": "Запропоновано конфігурацію {type}. Перегляньте та скоригуйте поля нижче.",
|
|
448
448
|
"overlayTitle": "Тимчасовий overlay",
|
|
449
|
+
"serviceDirTitle": "Тека розгортання сервісу",
|
|
450
|
+
"manifestRootTitle": "Розташування маніфесту",
|
|
451
|
+
"composeServiceTitle": "Сервіс Compose",
|
|
449
452
|
"urlSource": "Запропоноване джерело URL середовища: {source}. Цим керує обробник робочого простору; налаштуйте його там.",
|
|
450
453
|
"namespace": "Маніфести фіксують простір імен \"{namespace}\"; рекомендуємо дотримуватися його в обробнику робочого простору.",
|
|
451
454
|
"confidenceHigh": "Виявлено",
|
|
@@ -829,6 +832,11 @@
|
|
|
829
832
|
"userMenu": {
|
|
830
833
|
"mySetup": "Моє налаштування",
|
|
831
834
|
"signOut": "Вийти"
|
|
835
|
+
},
|
|
836
|
+
"mothership": {
|
|
837
|
+
"signIn": "Увійти через центральний сервер",
|
|
838
|
+
"hint": "Ваші проєкти та обліковий запис зберігаються на центральному сервері. Увійдіть там, щоб приєднати цей вузол.",
|
|
839
|
+
"error": "Не вдалося увійти через центральний сервер. Спробуйте ще раз."
|
|
832
840
|
}
|
|
833
841
|
},
|
|
834
842
|
"layout": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.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.
|
|
37
|
+
"@cat-factory/contracts": "0.72.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|