@cat-factory/app 0.93.0 → 0.94.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.
@@ -14,6 +14,10 @@ import type { ProviderConnectionKind } from '~/types/providerConnections'
14
14
  import InfrastructureBackendPicker from '~/components/settings/InfrastructureBackendPicker.vue'
15
15
  import InfraHandlersConfigurator from '~/components/settings/InfraHandlersConfigurator.vue'
16
16
  import LocalContainerPoolSettings from '~/components/settings/LocalContainerPoolSettings.vue'
17
+ import SharedStacksPanel from '~/components/settings/SharedStacksPanel.vue'
18
+
19
+ // The shared-stacks tab uses its own slot key beyond the provider-connection kinds.
20
+ type InfraTabValue = ProviderConnectionKind | 'shared-stacks'
17
21
 
18
22
  const { t } = useI18n()
19
23
  const ui = useUiStore()
@@ -37,7 +41,7 @@ const agentsAvailable = computed(() => (auth.infrastructure?.execution.available
37
41
  const envsAvailable = computed(() => (auth.infrastructure?.testEnv.available.length ?? 0) > 0)
38
42
 
39
43
  const tabs = computed(() => {
40
- const out: { value: ProviderConnectionKind; label: string; icon: string; slot: string }[] = []
44
+ const out: { value: InfraTabValue; label: string; icon: string; slot: string }[] = []
41
45
  if (agentsAvailable.value)
42
46
  out.push({
43
47
  value: 'runner-pool',
@@ -52,10 +56,19 @@ const tabs = computed(() => {
52
56
  icon: 'i-lucide-cloud',
53
57
  slot: 'environment',
54
58
  })
59
+ // Shared stacks are long-lived compose infra a Tester environment attaches to, so they live
60
+ // alongside the test-environment config (shown wherever an environment backend is available).
61
+ if (envsAvailable.value)
62
+ out.push({
63
+ value: 'shared-stacks',
64
+ label: t('settings.sharedStacks.tab'),
65
+ icon: 'i-lucide-layers',
66
+ slot: 'shared-stacks',
67
+ })
55
68
  return out
56
69
  })
57
70
 
58
- const activeTab = ref<ProviderConnectionKind>(ui.infrastructureTab)
71
+ const activeTab = ref<InfraTabValue>(ui.infrastructureTab)
59
72
 
60
73
  // Honour the deep-linked tab each time the window opens, falling back to the first available
61
74
  // tab if the requested one is off.
@@ -124,6 +137,9 @@ watch([tabs, () => store.loaded], () => {
124
137
  <InfraHandlersConfigurator />
125
138
  </div>
126
139
  </template>
140
+ <template #shared-stacks>
141
+ <SharedStacksPanel />
142
+ </template>
127
143
  </UTabs>
128
144
 
129
145
  <p v-else class="px-1 py-6 text-center text-sm text-slate-500">
@@ -0,0 +1,363 @@
1
+ <script setup lang="ts">
2
+ // Shared stacks — long-lived compose infra (e.g. acme-shared-services: MySQL / Postgres /
3
+ // Valkey / RabbitMQ / Kafka / ES / Mailpit / Envoy) brought up ONCE per workspace and reused
4
+ // across runs + PRs. A per-PR consumer environment attaches to a stack's managed network. CRUD
5
+ // works on every backend; the bring-up (Start) / teardown (Stop) drive a host Docker daemon, so
6
+ // they succeed only on the local facade (elsewhere the backend returns a clear error surfaced as
7
+ // a toast). Renders inline inside the Infrastructure window's "Shared stacks" tab.
8
+ import { computed, reactive, ref } from 'vue'
9
+ import type { SharedStack, SharedStackStatus } from '~/types/sharedStacks'
10
+
11
+ const { t } = useI18n()
12
+ const store = useSharedStacksStore()
13
+ const toast = useToast()
14
+ const { confirmAction, toastDone } = useConfirmAction()
15
+
16
+ const stacks = computed(() => store.stacks)
17
+ const busyId = ref<string | null>(null)
18
+ const saving = ref(false)
19
+ // null ⇒ the form is in "add" mode; a stack id ⇒ editing that stack's definition in place.
20
+ const editingId = ref<string | null>(null)
21
+
22
+ const form = reactive({
23
+ name: '',
24
+ cloneUrl: '',
25
+ gitRef: '',
26
+ composeFiles: '',
27
+ composeProfiles: '',
28
+ managedNetworks: '',
29
+ allowHostCommands: false,
30
+ })
31
+
32
+ /** Status → badge colour. */
33
+ const STATUS_COLOR: Record<SharedStackStatus, 'neutral' | 'warning' | 'success' | 'error'> = {
34
+ stopped: 'neutral',
35
+ starting: 'warning',
36
+ running: 'success',
37
+ failed: 'error',
38
+ }
39
+
40
+ // Status → catalog key as an EXHAUSTIVE Record over the enum (not a runtime-assembled key), so a
41
+ // new SharedStackStatus fails the typecheck on this map instead of leaking a raw key into the badge.
42
+ const STATUS_LABEL_KEYS: Record<SharedStackStatus, string> = {
43
+ stopped: 'settings.sharedStacks.status.stopped',
44
+ starting: 'settings.sharedStacks.status.starting',
45
+ running: 'settings.sharedStacks.status.running',
46
+ failed: 'settings.sharedStacks.status.failed',
47
+ }
48
+
49
+ function statusLabel(status: SharedStackStatus): string {
50
+ return t(STATUS_LABEL_KEYS[status])
51
+ }
52
+
53
+ /** A running/starting stack cannot be reconfigured (the backend refuses) — edit is stopped/failed only. */
54
+ function canEdit(stack: SharedStack): boolean {
55
+ return stack.status !== 'running' && stack.status !== 'starting'
56
+ }
57
+
58
+ /** Split a comma/whitespace-separated field into trimmed non-empty tokens. */
59
+ function tokens(value: string): string[] {
60
+ return value
61
+ .split(/[\s,]+/)
62
+ .map((s) => s.trim())
63
+ .filter(Boolean)
64
+ }
65
+
66
+ const canSave = computed(
67
+ () => form.name.trim() && form.cloneUrl.trim() && tokens(form.composeFiles).length > 0,
68
+ )
69
+
70
+ function resetForm() {
71
+ editingId.value = null
72
+ form.name = ''
73
+ form.cloneUrl = ''
74
+ form.gitRef = ''
75
+ form.composeFiles = ''
76
+ form.composeProfiles = ''
77
+ form.managedNetworks = ''
78
+ form.allowHostCommands = false
79
+ }
80
+
81
+ /** Load a stack's definition into the form for in-place editing. */
82
+ function startEdit(stack: SharedStack) {
83
+ editingId.value = stack.id
84
+ form.name = stack.name
85
+ form.cloneUrl = stack.cloneUrl
86
+ form.gitRef = stack.gitRef ?? ''
87
+ form.composeFiles = stack.composeFiles.join(', ')
88
+ form.composeProfiles = stack.composeProfiles.join(', ')
89
+ form.managedNetworks = stack.managedNetworks.join(', ')
90
+ form.allowHostCommands = stack.allowHostCommands
91
+ }
92
+
93
+ function notifyError(title: string, e: unknown) {
94
+ toast.add({
95
+ title,
96
+ description: e instanceof Error ? e.message : String(e),
97
+ icon: 'i-lucide-triangle-alert',
98
+ color: 'error',
99
+ })
100
+ }
101
+
102
+ /** Create a new stack, or save edits to the one being edited (same form, mode toggled by `editingId`). */
103
+ async function saveStack() {
104
+ saving.value = true
105
+ const editing = editingId.value
106
+ const payload = {
107
+ name: form.name.trim(),
108
+ cloneUrl: form.cloneUrl.trim(),
109
+ ...(form.gitRef.trim() ? { gitRef: form.gitRef.trim() } : {}),
110
+ composeFiles: tokens(form.composeFiles),
111
+ composeProfiles: tokens(form.composeProfiles),
112
+ managedNetworks: tokens(form.managedNetworks),
113
+ allowHostCommands: form.allowHostCommands,
114
+ }
115
+ try {
116
+ if (editing) {
117
+ await store.update(editing, { ...payload, gitRef: form.gitRef.trim() || null })
118
+ } else {
119
+ await store.create(payload)
120
+ }
121
+ resetForm()
122
+ toast.add({
123
+ title: t(
124
+ editing ? 'settings.sharedStacks.toast.updated' : 'settings.sharedStacks.toast.created',
125
+ ),
126
+ icon: 'i-lucide-check',
127
+ color: 'success',
128
+ })
129
+ } catch (e) {
130
+ notifyError(
131
+ t(
132
+ editing
133
+ ? 'settings.sharedStacks.toast.updateFailed'
134
+ : 'settings.sharedStacks.toast.createFailed',
135
+ ),
136
+ e,
137
+ )
138
+ } finally {
139
+ saving.value = false
140
+ }
141
+ }
142
+
143
+ async function start(stack: SharedStack) {
144
+ busyId.value = stack.id
145
+ try {
146
+ // ensureUp resolves 200 even on a FAILED bring-up (the record carries status/lastError), so
147
+ // surface that as an error toast too — not only a thrown transport/unavailable error.
148
+ const updated = await store.ensureUp(stack.id)
149
+ if (updated.status === 'failed') {
150
+ notifyError(t('settings.sharedStacks.toast.startFailed'), updated.lastError ?? '')
151
+ }
152
+ } catch (e) {
153
+ notifyError(t('settings.sharedStacks.toast.startFailed'), e)
154
+ } finally {
155
+ busyId.value = null
156
+ }
157
+ }
158
+
159
+ async function stop(stack: SharedStack) {
160
+ busyId.value = stack.id
161
+ try {
162
+ await store.teardown(stack.id)
163
+ } catch (e) {
164
+ notifyError(t('settings.sharedStacks.toast.stopFailed'), e)
165
+ } finally {
166
+ busyId.value = null
167
+ }
168
+ }
169
+
170
+ async function remove(stack: SharedStack) {
171
+ const noun = t('settings.sharedStacks.stackNoun')
172
+ if (!(await confirmAction('remove', noun))) return
173
+ busyId.value = stack.id
174
+ try {
175
+ await store.remove(stack.id)
176
+ toastDone('remove', noun)
177
+ } catch (e) {
178
+ notifyError(t('settings.sharedStacks.toast.removeFailed'), e)
179
+ } finally {
180
+ busyId.value = null
181
+ }
182
+ }
183
+ </script>
184
+
185
+ <template>
186
+ <div class="space-y-4" data-testid="shared-stacks-panel">
187
+ <p class="text-sm text-slate-400">{{ t('settings.sharedStacks.intro') }}</p>
188
+
189
+ <section v-if="stacks.length" class="space-y-2 rounded-lg border border-slate-700 p-3">
190
+ <h3 class="text-sm font-semibold">{{ t('settings.sharedStacks.list.heading') }}</h3>
191
+ <div
192
+ v-for="stack in stacks"
193
+ :key="stack.id"
194
+ class="space-y-2 rounded-md border border-slate-800 px-3 py-2"
195
+ :data-testid="`shared-stack-${stack.id}`"
196
+ >
197
+ <div class="flex items-center justify-between gap-2">
198
+ <div class="min-w-0 space-y-1">
199
+ <div class="flex items-center gap-2">
200
+ <span class="text-sm font-medium">{{ stack.name }}</span>
201
+ <UBadge :color="STATUS_COLOR[stack.status]" variant="soft" size="sm">
202
+ {{ statusLabel(stack.status) }}
203
+ </UBadge>
204
+ </div>
205
+ <p class="truncate text-[11px] text-slate-500">{{ stack.cloneUrl }}</p>
206
+ <div v-if="stack.managedNetworks.length" class="flex flex-wrap gap-1">
207
+ <UBadge
208
+ v-for="net in stack.managedNetworks"
209
+ :key="net"
210
+ color="neutral"
211
+ variant="soft"
212
+ size="sm"
213
+ >
214
+ {{ net }}
215
+ </UBadge>
216
+ </div>
217
+ </div>
218
+ <div class="flex shrink-0 items-center gap-1">
219
+ <UButton
220
+ v-if="stack.status !== 'running'"
221
+ icon="i-lucide-play"
222
+ size="sm"
223
+ variant="soft"
224
+ :loading="busyId === stack.id"
225
+ :data-testid="`shared-stack-start-${stack.id}`"
226
+ @click="start(stack)"
227
+ >
228
+ {{ t('settings.sharedStacks.list.start') }}
229
+ </UButton>
230
+ <UButton
231
+ v-else
232
+ icon="i-lucide-square"
233
+ size="sm"
234
+ variant="soft"
235
+ color="warning"
236
+ :loading="busyId === stack.id"
237
+ :data-testid="`shared-stack-stop-${stack.id}`"
238
+ @click="stop(stack)"
239
+ >
240
+ {{ t('settings.sharedStacks.list.stop') }}
241
+ </UButton>
242
+ <UButton
243
+ v-if="canEdit(stack)"
244
+ color="neutral"
245
+ variant="ghost"
246
+ icon="i-lucide-pencil"
247
+ size="sm"
248
+ :data-testid="`shared-stack-edit-${stack.id}`"
249
+ :aria-label="t('settings.sharedStacks.list.edit')"
250
+ @click="startEdit(stack)"
251
+ />
252
+ <UButton
253
+ color="error"
254
+ variant="ghost"
255
+ icon="i-lucide-trash-2"
256
+ size="sm"
257
+ :loading="busyId === stack.id"
258
+ :data-testid="`shared-stack-delete-${stack.id}`"
259
+ :aria-label="t('settings.sharedStacks.list.remove')"
260
+ @click="remove(stack)"
261
+ />
262
+ </div>
263
+ </div>
264
+ <p v-if="stack.lastError" class="text-[11px] text-rose-400">{{ stack.lastError }}</p>
265
+ </div>
266
+ </section>
267
+
268
+ <section
269
+ class="space-y-3 rounded-lg border border-slate-700 p-3"
270
+ data-testid="shared-stack-form"
271
+ >
272
+ <h3 class="text-sm font-semibold">
273
+ {{
274
+ t(editingId ? 'settings.sharedStacks.edit.heading' : 'settings.sharedStacks.add.heading')
275
+ }}
276
+ </h3>
277
+
278
+ <UFormField :label="t('settings.sharedStacks.add.name')">
279
+ <UInput v-model="form.name" class="w-full" data-testid="shared-stack-name" />
280
+ </UFormField>
281
+
282
+ <UFormField
283
+ :label="t('settings.sharedStacks.add.cloneUrl')"
284
+ :help="t('settings.sharedStacks.add.cloneUrlHelp')"
285
+ >
286
+ <UInput
287
+ v-model="form.cloneUrl"
288
+ placeholder="https://github.com/acme/acme-shared-services.git"
289
+ class="w-full"
290
+ data-testid="shared-stack-clone-url"
291
+ />
292
+ </UFormField>
293
+
294
+ <UFormField :label="t('settings.sharedStacks.add.gitRef')">
295
+ <UInput
296
+ v-model="form.gitRef"
297
+ placeholder="main"
298
+ class="w-full"
299
+ data-testid="shared-stack-git-ref"
300
+ />
301
+ </UFormField>
302
+
303
+ <UFormField
304
+ :label="t('settings.sharedStacks.add.composeFiles')"
305
+ :help="t('settings.sharedStacks.add.composeFilesHelp')"
306
+ >
307
+ <UInput
308
+ v-model="form.composeFiles"
309
+ placeholder="docker-compose.yml, docker-compose.override.yml"
310
+ class="w-full"
311
+ data-testid="shared-stack-compose-files"
312
+ />
313
+ </UFormField>
314
+
315
+ <UFormField :label="t('settings.sharedStacks.add.composeProfiles')">
316
+ <UInput
317
+ v-model="form.composeProfiles"
318
+ placeholder="backends, peer"
319
+ class="w-full"
320
+ data-testid="shared-stack-profiles"
321
+ />
322
+ </UFormField>
323
+
324
+ <UFormField
325
+ :label="t('settings.sharedStacks.add.managedNetworks')"
326
+ :help="t('settings.sharedStacks.add.managedNetworksHelp')"
327
+ >
328
+ <UInput
329
+ v-model="form.managedNetworks"
330
+ placeholder="acme-net"
331
+ class="w-full"
332
+ data-testid="shared-stack-networks"
333
+ />
334
+ </UFormField>
335
+
336
+ <UCheckbox
337
+ v-model="form.allowHostCommands"
338
+ :label="t('settings.sharedStacks.add.allowHostCommands')"
339
+ data-testid="shared-stack-allow-host-commands"
340
+ />
341
+
342
+ <div class="flex items-center gap-2">
343
+ <UButton
344
+ :loading="saving"
345
+ :disabled="!canSave"
346
+ data-testid="shared-stack-save"
347
+ @click="saveStack"
348
+ >
349
+ {{ t(editingId ? 'settings.sharedStacks.edit.save' : 'settings.sharedStacks.add.save') }}
350
+ </UButton>
351
+ <UButton
352
+ v-if="editingId"
353
+ color="neutral"
354
+ variant="ghost"
355
+ data-testid="shared-stack-cancel-edit"
356
+ @click="resetForm"
357
+ >
358
+ {{ t('settings.sharedStacks.edit.cancel') }}
359
+ </UButton>
360
+ </div>
361
+ </section>
362
+ </div>
363
+ </template>
@@ -0,0 +1,42 @@
1
+ import {
2
+ createSharedStackContract,
3
+ deleteSharedStackContract,
4
+ ensureSharedStackUpContract,
5
+ listSharedStacksContract,
6
+ teardownSharedStackContract,
7
+ updateSharedStackContract,
8
+ } from '@cat-factory/contracts'
9
+ import type { UpdateSharedStackInput } from '~/types/sharedStacks'
10
+ import type { SendParams } from './client'
11
+ import type { ApiContext } from './context'
12
+
13
+ // The create body is typed from the contract's INPUT shape so the valibot-defaulted array fields
14
+ // (profiles, envFiles, managedNetworks, setupSteps, allowHostCommands) stay optional for callers.
15
+ type CreateSharedStackBody = NonNullable<SendParams<typeof createSharedStackContract>['body']>
16
+
17
+ /** A workspace's shared stacks: CRUD plus the ensure-up / teardown lifecycle actions. */
18
+ export function sharedStacksApi({ send, ws }: ApiContext) {
19
+ return {
20
+ listSharedStacks: (workspaceId: string) =>
21
+ send(listSharedStacksContract, { pathPrefix: ws(workspaceId) }),
22
+
23
+ createSharedStack: (workspaceId: string, body: CreateSharedStackBody) =>
24
+ send(createSharedStackContract, { pathPrefix: ws(workspaceId), body }),
25
+
26
+ updateSharedStack: (workspaceId: string, stackId: string, body: UpdateSharedStackInput) =>
27
+ send(updateSharedStackContract, {
28
+ pathPrefix: ws(workspaceId),
29
+ pathParams: { stackId },
30
+ body,
31
+ }),
32
+
33
+ deleteSharedStack: (workspaceId: string, stackId: string) =>
34
+ send(deleteSharedStackContract, { pathPrefix: ws(workspaceId), pathParams: { stackId } }),
35
+
36
+ ensureSharedStackUp: (workspaceId: string, stackId: string) =>
37
+ send(ensureSharedStackUpContract, { pathPrefix: ws(workspaceId), pathParams: { stackId } }),
38
+
39
+ teardownSharedStack: (workspaceId: string, stackId: string) =>
40
+ send(teardownSharedStackContract, { pathPrefix: ws(workspaceId), pathParams: { stackId } }),
41
+ }
42
+ }
@@ -22,6 +22,7 @@ import { modelsApi } from './api/models'
22
22
  import { notificationsApi } from './api/notifications'
23
23
  import { packageRegistriesApi } from './api/packageRegistries'
24
24
  import { presetsApi } from './api/presets'
25
+ import { sharedStacksApi } from './api/sharedStacks'
25
26
  import { providerConnectionsApi } from './api/providerConnections'
26
27
  import { provisioningLogsApi } from './api/provisioningLogs'
27
28
  import { recurringApi } from './api/recurring'
@@ -112,6 +113,7 @@ export function useApi() {
112
113
  ...specApi(ctx),
113
114
  ...notificationsApi(ctx),
114
115
  ...presetsApi(ctx),
116
+ ...sharedStacksApi(ctx),
115
117
  ...providerConnectionsApi(ctx),
116
118
  ...infraHandlersApi(ctx),
117
119
  ...initiativeApi(ctx),
@@ -0,0 +1,65 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+ import type { SharedStack, UpdateSharedStackInput } from '~/types/sharedStacks'
4
+ import { useWorkspaceStore } from '~/stores/workspace'
5
+
6
+ /**
7
+ * The workspace's shared stacks — long-lived compose infra (e.g. acme-shared-services) that
8
+ * per-PR consumer environments attach to over an external network. Hydrated from the workspace
9
+ * snapshot; managed via the Infrastructure window's "Shared stacks" panel. CRUD works on every
10
+ * backend, but the bring-up (`ensureUp`) / teardown drive a host Docker daemon, so they succeed
11
+ * only on the local facade (elsewhere the backend returns a clear error the panel surfaces).
12
+ *
13
+ * Mutations refresh the workspace snapshot (the stack list rides it), while the async lifecycle
14
+ * actions patch the returned record in place so the panel shows the new status immediately.
15
+ */
16
+ export const useSharedStacksStore = defineStore('sharedStacks', () => {
17
+ const api = useApi()
18
+ const stacks = ref<SharedStack[]>([])
19
+
20
+ function hydrate(list: SharedStack[]) {
21
+ stacks.value = [...list].sort((a, b) => a.createdAt - b.createdAt)
22
+ }
23
+
24
+ function patch(stack: SharedStack) {
25
+ const idx = stacks.value.findIndex((s) => s.id === stack.id)
26
+ if (idx >= 0) stacks.value[idx] = stack
27
+ else stacks.value.push(stack)
28
+ }
29
+
30
+ async function create(input: Parameters<typeof api.createSharedStack>[1]) {
31
+ const ws = useWorkspaceStore()
32
+ const created = await api.createSharedStack(ws.requireId(), input)
33
+ await ws.refresh()
34
+ return created
35
+ }
36
+
37
+ async function update(stackId: string, patchInput: UpdateSharedStackInput) {
38
+ const ws = useWorkspaceStore()
39
+ const updated = await api.updateSharedStack(ws.requireId(), stackId, patchInput)
40
+ await ws.refresh()
41
+ return updated
42
+ }
43
+
44
+ async function remove(stackId: string) {
45
+ const ws = useWorkspaceStore()
46
+ await api.deleteSharedStack(ws.requireId(), stackId)
47
+ await ws.refresh()
48
+ }
49
+
50
+ async function ensureUp(stackId: string) {
51
+ const ws = useWorkspaceStore()
52
+ const updated = await api.ensureSharedStackUp(ws.requireId(), stackId)
53
+ patch(updated)
54
+ return updated
55
+ }
56
+
57
+ async function teardown(stackId: string) {
58
+ const ws = useWorkspaceStore()
59
+ const updated = await api.teardownSharedStack(ws.requireId(), stackId)
60
+ patch(updated)
61
+ return updated
62
+ }
63
+
64
+ return { stacks, hydrate, create, update, remove, ensureUp, teardown }
65
+ })
@@ -8,6 +8,7 @@ import { useExecutionStore } from '~/stores/execution'
8
8
  import { useAgentRunsStore } from '~/stores/agentRuns'
9
9
  import { useNotificationsStore } from '~/stores/notifications'
10
10
  import { useMergePresetsStore } from '~/stores/mergePresets'
11
+ import { useSharedStacksStore } from '~/stores/sharedStacks'
11
12
  import { useWorkspaceSettingsStore } from '~/stores/workspaceSettings'
12
13
  import { useAgentConfigStore } from '~/stores/agentConfig'
13
14
  import { useModelPresetsStore } from '~/stores/modelPresets'
@@ -107,6 +108,7 @@ export const useWorkspaceStore = defineStore(
107
108
  snapshot.mergePresets ?? [],
108
109
  snapshot.mergePresetCatalogVersions,
109
110
  )
111
+ useSharedStacksStore().hydrate(snapshot.sharedStacks ?? [])
110
112
  useWorkspaceSettingsStore().hydrate(snapshot.settings)
111
113
  useAgentConfigStore().hydrate(snapshot.agentConfigCatalog ?? [])
112
114
  useModelPresetsStore().hydrate(snapshot.modelPresets ?? [])
@@ -0,0 +1,8 @@
1
+ // Wire types for shared stacks — long-lived compose infra a consumer environment attaches to
2
+ // over an external network. Re-exported from the single source of truth (`@cat-factory/contracts`).
3
+ export type {
4
+ SharedStack,
5
+ SharedStackStatus,
6
+ CreateSharedStackInput,
7
+ UpdateSharedStackInput,
8
+ } from '@cat-factory/contracts'
@@ -2155,6 +2155,52 @@
2155
2155
  "removeFailed": "Could not remove the registry entry"
2156
2156
  }
2157
2157
  },
2158
+ "sharedStacks": {
2159
+ "tab": "Shared stacks",
2160
+ "intro": "Long-lived compose infrastructure (databases, brokers, search, mail) brought up once per workspace and reused across runs and pull requests. A test environment attaches to a stack's managed network. Bringing a stack up runs on a local Docker deployment; on other backends you can still manage the definition.",
2161
+ "stackNoun": "shared stack",
2162
+ "status": {
2163
+ "stopped": "Stopped",
2164
+ "starting": "Starting",
2165
+ "running": "Running",
2166
+ "failed": "Failed"
2167
+ },
2168
+ "list": {
2169
+ "heading": "Configured stacks",
2170
+ "start": "Start",
2171
+ "stop": "Stop",
2172
+ "edit": "Edit",
2173
+ "remove": "Delete stack"
2174
+ },
2175
+ "add": {
2176
+ "heading": "Add a shared stack",
2177
+ "name": "Name",
2178
+ "cloneUrl": "Repository clone URL",
2179
+ "cloneUrlHelp": "The git repository the stack's compose files live in.",
2180
+ "gitRef": "Branch or tag (optional)",
2181
+ "composeFiles": "Compose files",
2182
+ "composeFilesHelp": "Comma-separated, repo-relative, in override order.",
2183
+ "composeProfiles": "Compose profiles (optional)",
2184
+ "managedNetworks": "Managed networks (optional)",
2185
+ "managedNetworksHelp": "Networks this stack creates and owns for consumers to attach to.",
2186
+ "allowHostCommands": "Allow host-command setup steps",
2187
+ "save": "Add stack"
2188
+ },
2189
+ "edit": {
2190
+ "heading": "Edit shared stack",
2191
+ "save": "Save changes",
2192
+ "cancel": "Cancel"
2193
+ },
2194
+ "toast": {
2195
+ "created": "Shared stack added",
2196
+ "createFailed": "Could not add the shared stack",
2197
+ "updated": "Shared stack updated",
2198
+ "updateFailed": "Could not update the shared stack",
2199
+ "startFailed": "Could not start the shared stack",
2200
+ "stopFailed": "Could not stop the shared stack",
2201
+ "removeFailed": "Could not delete the shared stack"
2202
+ }
2203
+ },
2158
2204
  "localMode": {
2159
2205
  "title": "Local mode",
2160
2206
  "intro": "Tuning for the local container runner, stored on this machine's deployment (it replaced the {poolVars} / {harnessVars} env vars). Saving resizes the warm pool live, no restart needed; in-flight runs keep the container they already hold.",
@@ -1984,6 +1984,52 @@
1984
1984
  "removeFailed": "No se pudo eliminar la entrada del registro"
1985
1985
  }
1986
1986
  },
1987
+ "sharedStacks": {
1988
+ "tab": "Stacks compartidos",
1989
+ "intro": "Infraestructura de Compose de larga duración (bases de datos, brokers, búsqueda, correo) que se levanta una vez por espacio de trabajo y se reutiliza en todas las ejecuciones y pull requests. Un entorno de pruebas se conecta a la red gestionada de un stack. Levantar un stack requiere un despliegue local de Docker; en otros backends puedes gestionar igualmente la definición.",
1990
+ "stackNoun": "stack compartido",
1991
+ "status": {
1992
+ "stopped": "Detenido",
1993
+ "starting": "Iniciando",
1994
+ "running": "En ejecución",
1995
+ "failed": "Con errores"
1996
+ },
1997
+ "list": {
1998
+ "heading": "Stacks configurados",
1999
+ "start": "Iniciar",
2000
+ "stop": "Detener",
2001
+ "edit": "Editar",
2002
+ "remove": "Eliminar stack"
2003
+ },
2004
+ "add": {
2005
+ "heading": "Añadir un stack compartido",
2006
+ "name": "Nombre",
2007
+ "cloneUrl": "URL de clonación del repositorio",
2008
+ "cloneUrlHelp": "El repositorio git donde viven los archivos de Compose del stack.",
2009
+ "gitRef": "Rama o etiqueta (opcional)",
2010
+ "composeFiles": "Archivos de Compose",
2011
+ "composeFilesHelp": "Separados por comas, relativos al repositorio, en orden de anulación.",
2012
+ "composeProfiles": "Perfiles de Compose (opcional)",
2013
+ "managedNetworks": "Redes gestionadas (opcional)",
2014
+ "managedNetworksHelp": "Redes que este stack crea y posee para que los consumidores se conecten.",
2015
+ "allowHostCommands": "Permitir pasos de configuración con comandos del host",
2016
+ "save": "Añadir stack"
2017
+ },
2018
+ "edit": {
2019
+ "heading": "Editar stack compartido",
2020
+ "save": "Guardar cambios",
2021
+ "cancel": "Cancelar"
2022
+ },
2023
+ "toast": {
2024
+ "created": "Stack compartido añadido",
2025
+ "createFailed": "No se pudo añadir el stack compartido",
2026
+ "updated": "Stack compartido actualizado",
2027
+ "updateFailed": "No se pudo actualizar el stack compartido",
2028
+ "startFailed": "No se pudo iniciar el stack compartido",
2029
+ "stopFailed": "No se pudo detener el stack compartido",
2030
+ "removeFailed": "No se pudo eliminar el stack compartido"
2031
+ }
2032
+ },
1987
2033
  "localMode": {
1988
2034
  "title": "Modo local",
1989
2035
  "intro": "Ajustes del ejecutor de contenedores local, almacenados en el despliegue de esta máquina (reemplazó las variables de entorno {poolVars} / {harnessVars}). Guardar redimensiona el grupo en caliente en vivo, sin necesidad de reiniciar; las ejecuciones en curso conservan el contenedor que ya tienen.",
@@ -1984,6 +1984,52 @@
1984
1984
  "removeFailed": "Impossible de supprimer l'entrée du registre"
1985
1985
  }
1986
1986
  },
1987
+ "sharedStacks": {
1988
+ "tab": "Stacks partagés",
1989
+ "intro": "Infrastructure Compose de longue durée (bases de données, brokers, recherche, e-mail) démarrée une fois par espace de travail et réutilisée pour toutes les exécutions et pull requests. Un environnement de test se connecte au réseau géré d'un stack. Démarrer un stack nécessite un déploiement Docker local ; sur les autres backends, vous pouvez tout de même gérer la définition.",
1990
+ "stackNoun": "stack partagé",
1991
+ "status": {
1992
+ "stopped": "Arrêté",
1993
+ "starting": "Démarrage",
1994
+ "running": "En cours d'exécution",
1995
+ "failed": "Échec"
1996
+ },
1997
+ "list": {
1998
+ "heading": "Stacks configurés",
1999
+ "start": "Démarrer",
2000
+ "stop": "Arrêter",
2001
+ "edit": "Modifier",
2002
+ "remove": "Supprimer le stack"
2003
+ },
2004
+ "add": {
2005
+ "heading": "Ajouter un stack partagé",
2006
+ "name": "Nom",
2007
+ "cloneUrl": "URL de clonage du dépôt",
2008
+ "cloneUrlHelp": "Le dépôt git où se trouvent les fichiers Compose du stack.",
2009
+ "gitRef": "Branche ou tag (facultatif)",
2010
+ "composeFiles": "Fichiers Compose",
2011
+ "composeFilesHelp": "Séparés par des virgules, relatifs au dépôt, dans l'ordre de surcharge.",
2012
+ "composeProfiles": "Profils Compose (facultatif)",
2013
+ "managedNetworks": "Réseaux gérés (facultatif)",
2014
+ "managedNetworksHelp": "Réseaux que ce stack crée et possède pour que les consommateurs s'y connectent.",
2015
+ "allowHostCommands": "Autoriser les étapes de configuration par commande hôte",
2016
+ "save": "Ajouter le stack"
2017
+ },
2018
+ "edit": {
2019
+ "heading": "Modifier le stack partagé",
2020
+ "save": "Enregistrer les modifications",
2021
+ "cancel": "Annuler"
2022
+ },
2023
+ "toast": {
2024
+ "created": "Stack partagé ajouté",
2025
+ "createFailed": "Impossible d'ajouter le stack partagé",
2026
+ "updated": "Stack partagé mis à jour",
2027
+ "updateFailed": "Impossible de mettre à jour le stack partagé",
2028
+ "startFailed": "Impossible de démarrer le stack partagé",
2029
+ "stopFailed": "Impossible d'arrêter le stack partagé",
2030
+ "removeFailed": "Impossible de supprimer le stack partagé"
2031
+ }
2032
+ },
1987
2033
  "localMode": {
1988
2034
  "title": "Mode local",
1989
2035
  "intro": "Réglage de l'exécuteur de conteneurs local, stocké sur le déploiement de cette machine (il a remplacé les variables d'environnement {poolVars} / {harnessVars}). L'enregistrement redimensionne le pool à chaud en direct, sans redémarrage nécessaire; les exécutions en cours conservent le conteneur qu'elles détiennent déjà.",
@@ -2105,6 +2105,52 @@
2105
2105
  "removeFailed": "הסרת רשומת המאגר נכשלה"
2106
2106
  }
2107
2107
  },
2108
+ "sharedStacks": {
2109
+ "tab": "מקבצים משותפים",
2110
+ "intro": "תשתית Compose ארוכת-טווח (מסדי נתונים, ברוקרים, חיפוש, דואר) שמופעלת פעם אחת לכל סביבת עבודה ומשמשת מחדש בכל ההרצות ובקשות המשיכה. סביבת בדיקה מתחברת לרשת המנוהלת של מקבץ. הפעלת מקבץ מחייבת פריסת Docker מקומית; ב-backends אחרים עדיין ניתן לנהל את ההגדרה.",
2111
+ "stackNoun": "מקבץ משותף",
2112
+ "status": {
2113
+ "stopped": "הופסק",
2114
+ "starting": "מופעל",
2115
+ "running": "פועל",
2116
+ "failed": "נכשל"
2117
+ },
2118
+ "list": {
2119
+ "heading": "מקבצים מוגדרים",
2120
+ "start": "הפעלה",
2121
+ "stop": "עצירה",
2122
+ "edit": "עריכה",
2123
+ "remove": "מחיקת מקבץ"
2124
+ },
2125
+ "add": {
2126
+ "heading": "הוספת מקבץ משותף",
2127
+ "name": "שם",
2128
+ "cloneUrl": "כתובת שכפול של המאגר",
2129
+ "cloneUrlHelp": "מאגר ה-git שבו נמצאים קובצי ה-Compose של המקבץ.",
2130
+ "gitRef": "ענף או תג (אופציונלי)",
2131
+ "composeFiles": "קובצי Compose",
2132
+ "composeFilesHelp": "מופרדים בפסיקים, יחסית למאגר, לפי סדר הדריסה.",
2133
+ "composeProfiles": "פרופילי Compose (אופציונלי)",
2134
+ "managedNetworks": "רשתות מנוהלות (אופציונלי)",
2135
+ "managedNetworksHelp": "רשתות שהמקבץ יוצר ומחזיק כדי שצרכנים יתחברו אליהן.",
2136
+ "allowHostCommands": "אפשר שלבי הגדרה עם פקודות מארח",
2137
+ "save": "הוספת מקבץ"
2138
+ },
2139
+ "edit": {
2140
+ "heading": "עריכת מקבץ משותף",
2141
+ "save": "שמירת שינויים",
2142
+ "cancel": "ביטול"
2143
+ },
2144
+ "toast": {
2145
+ "created": "המקבץ המשותף נוסף",
2146
+ "createFailed": "לא ניתן להוסיף את המקבץ המשותף",
2147
+ "updated": "המקבץ המשותף עודכן",
2148
+ "updateFailed": "לא ניתן לעדכן את המקבץ המשותף",
2149
+ "startFailed": "לא ניתן להפעיל את המקבץ המשותף",
2150
+ "stopFailed": "לא ניתן לעצור את המקבץ המשותף",
2151
+ "removeFailed": "לא ניתן למחוק את המקבץ המשותף"
2152
+ }
2153
+ },
2108
2154
  "localMode": {
2109
2155
  "title": "מצב מקומי",
2110
2156
  "intro": "כוונון עבור מריץ הקונטיינרים המקומי, נשמר בפריסה של מכונה זו (הוא החליף את משתני הסביבה {poolVars} / {harnessVars}). שמירה משנה את גודל המאגר החם בזמן אמת, ללא צורך באתחול מחדש; הרצות פעילות שומרות את הקונטיינר שהן כבר מחזיקות.",
@@ -2106,6 +2106,52 @@
2106
2106
  "removeFailed": "レジストリエントリを削除できませんでした"
2107
2107
  }
2108
2108
  },
2109
+ "sharedStacks": {
2110
+ "tab": "共有スタック",
2111
+ "intro": "ワークスペースごとに一度だけ起動され、すべての実行とプルリクエストで再利用される長期稼働の Compose インフラ(データベース、ブローカー、検索、メール)です。テスト環境はスタックのマネージドネットワークに接続します。スタックの起動にはローカルの Docker デプロイが必要です。他のバックエンドでも定義の管理は可能です。",
2112
+ "stackNoun": "共有スタック",
2113
+ "status": {
2114
+ "stopped": "停止",
2115
+ "starting": "起動中",
2116
+ "running": "実行中",
2117
+ "failed": "失敗"
2118
+ },
2119
+ "list": {
2120
+ "heading": "構成済みのスタック",
2121
+ "start": "開始",
2122
+ "stop": "停止",
2123
+ "edit": "編集",
2124
+ "remove": "スタックを削除"
2125
+ },
2126
+ "add": {
2127
+ "heading": "共有スタックを追加",
2128
+ "name": "名前",
2129
+ "cloneUrl": "リポジトリのクローン URL",
2130
+ "cloneUrlHelp": "スタックの Compose ファイルが置かれている git リポジトリ。",
2131
+ "gitRef": "ブランチまたはタグ(任意)",
2132
+ "composeFiles": "Compose ファイル",
2133
+ "composeFilesHelp": "カンマ区切り、リポジトリ相対、オーバーライド順。",
2134
+ "composeProfiles": "Compose プロファイル(任意)",
2135
+ "managedNetworks": "マネージドネットワーク(任意)",
2136
+ "managedNetworksHelp": "コンシューマーが接続するために、このスタックが作成・所有するネットワーク。",
2137
+ "allowHostCommands": "ホストコマンドのセットアップ手順を許可する",
2138
+ "save": "スタックを追加"
2139
+ },
2140
+ "edit": {
2141
+ "heading": "共有スタックを編集",
2142
+ "save": "変更を保存",
2143
+ "cancel": "キャンセル"
2144
+ },
2145
+ "toast": {
2146
+ "created": "共有スタックを追加しました",
2147
+ "createFailed": "共有スタックを追加できませんでした",
2148
+ "updated": "共有スタックを更新しました",
2149
+ "updateFailed": "共有スタックを更新できませんでした",
2150
+ "startFailed": "共有スタックを開始できませんでした",
2151
+ "stopFailed": "共有スタックを停止できませんでした",
2152
+ "removeFailed": "共有スタックを削除できませんでした"
2153
+ }
2154
+ },
2109
2155
  "localMode": {
2110
2156
  "title": "ローカルモード",
2111
2157
  "intro": "ローカルコンテナランナーの調整設定で、このマシンのデプロイに保存されます ({poolVars} / {harnessVars} 環境変数を置き換えました)。保存するとウォームプールがライブでサイズ変更され、再起動は不要です。実行中のランは、すでに保持しているコンテナをそのまま使います。",
@@ -1984,6 +1984,52 @@
1984
1984
  "removeFailed": "Nie udało się usunąć wpisu rejestru"
1985
1985
  }
1986
1986
  },
1987
+ "sharedStacks": {
1988
+ "tab": "Współdzielone stosy",
1989
+ "intro": "Długo działająca infrastruktura Compose (bazy danych, brokery, wyszukiwanie, poczta) uruchamiana raz na przestrzeń roboczą i wykorzystywana ponownie we wszystkich uruchomieniach i pull requestach. Środowisko testowe łączy się z zarządzaną siecią stosu. Uruchomienie stosu wymaga lokalnego wdrożenia Dockera; w innych backendach nadal możesz zarządzać definicją.",
1990
+ "stackNoun": "współdzielony stos",
1991
+ "status": {
1992
+ "stopped": "Zatrzymany",
1993
+ "starting": "Uruchamianie",
1994
+ "running": "Działa",
1995
+ "failed": "Niepowodzenie"
1996
+ },
1997
+ "list": {
1998
+ "heading": "Skonfigurowane stosy",
1999
+ "start": "Uruchom",
2000
+ "stop": "Zatrzymaj",
2001
+ "edit": "Edytuj",
2002
+ "remove": "Usuń stos"
2003
+ },
2004
+ "add": {
2005
+ "heading": "Dodaj współdzielony stos",
2006
+ "name": "Nazwa",
2007
+ "cloneUrl": "URL klonowania repozytorium",
2008
+ "cloneUrlHelp": "Repozytorium git, w którym znajdują się pliki Compose stosu.",
2009
+ "gitRef": "Gałąź lub tag (opcjonalnie)",
2010
+ "composeFiles": "Pliki Compose",
2011
+ "composeFilesHelp": "Rozdzielone przecinkami, względem repozytorium, w kolejności nadpisywania.",
2012
+ "composeProfiles": "Profile Compose (opcjonalnie)",
2013
+ "managedNetworks": "Zarządzane sieci (opcjonalnie)",
2014
+ "managedNetworksHelp": "Sieci, które ten stos tworzy i posiada, aby konsumenci mogli się z nimi łączyć.",
2015
+ "allowHostCommands": "Zezwól na kroki konfiguracji z poleceniami hosta",
2016
+ "save": "Dodaj stos"
2017
+ },
2018
+ "edit": {
2019
+ "heading": "Edytuj współdzielony stos",
2020
+ "save": "Zapisz zmiany",
2021
+ "cancel": "Anuluj"
2022
+ },
2023
+ "toast": {
2024
+ "created": "Dodano współdzielony stos",
2025
+ "createFailed": "Nie udało się dodać współdzielonego stosu",
2026
+ "updated": "Zaktualizowano współdzielony stos",
2027
+ "updateFailed": "Nie udało się zaktualizować współdzielonego stosu",
2028
+ "startFailed": "Nie udało się uruchomić współdzielonego stosu",
2029
+ "stopFailed": "Nie udało się zatrzymać współdzielonego stosu",
2030
+ "removeFailed": "Nie udało się usunąć współdzielonego stosu"
2031
+ }
2032
+ },
1987
2033
  "localMode": {
1988
2034
  "title": "Tryb lokalny",
1989
2035
  "intro": "Strojenie lokalnego uruchamiacza kontenerów, przechowywane we wdrożeniu tej maszyny (zastąpiło zmienne środowiskowe {poolVars} / {harnessVars}). Zapisanie zmienia rozmiar ciepłej puli na żywo, bez potrzeby restartu; trwające uruchomienia zachowują kontener, który już mają.",
@@ -2106,6 +2106,52 @@
2106
2106
  "removeFailed": "Kayıt defteri girdisi kaldırılamadı"
2107
2107
  }
2108
2108
  },
2109
+ "sharedStacks": {
2110
+ "tab": "Paylaşılan yığınlar",
2111
+ "intro": "Çalışma alanı başına bir kez başlatılan ve tüm çalıştırmalar ile pull request'lerde yeniden kullanılan uzun ömürlü Compose altyapısı (veritabanları, aracılar, arama, posta). Bir test ortamı, yığının yönetilen ağına bağlanır. Bir yığını başlatmak yerel bir Docker dağıtımı gerektirir; diğer arka uçlarda tanımı yine de yönetebilirsiniz.",
2112
+ "stackNoun": "paylaşılan yığın",
2113
+ "status": {
2114
+ "stopped": "Durduruldu",
2115
+ "starting": "Başlatılıyor",
2116
+ "running": "Çalışıyor",
2117
+ "failed": "Başarısız"
2118
+ },
2119
+ "list": {
2120
+ "heading": "Yapılandırılmış yığınlar",
2121
+ "start": "Başlat",
2122
+ "stop": "Durdur",
2123
+ "edit": "Düzenle",
2124
+ "remove": "Yığını sil"
2125
+ },
2126
+ "add": {
2127
+ "heading": "Paylaşılan yığın ekle",
2128
+ "name": "Ad",
2129
+ "cloneUrl": "Depo klonlama URL'si",
2130
+ "cloneUrlHelp": "Yığının Compose dosyalarının bulunduğu git deposu.",
2131
+ "gitRef": "Dal veya etiket (isteğe bağlı)",
2132
+ "composeFiles": "Compose dosyaları",
2133
+ "composeFilesHelp": "Virgülle ayrılmış, depoya göreli, geçersiz kılma sırasında.",
2134
+ "composeProfiles": "Compose profilleri (isteğe bağlı)",
2135
+ "managedNetworks": "Yönetilen ağlar (isteğe bağlı)",
2136
+ "managedNetworksHelp": "Tüketicilerin bağlanması için bu yığının oluşturup sahip olduğu ağlar.",
2137
+ "allowHostCommands": "Ana makine komutu kurulum adımlarına izin ver",
2138
+ "save": "Yığın ekle"
2139
+ },
2140
+ "edit": {
2141
+ "heading": "Paylaşılan yığını düzenle",
2142
+ "save": "Değişiklikleri kaydet",
2143
+ "cancel": "İptal"
2144
+ },
2145
+ "toast": {
2146
+ "created": "Paylaşılan yığın eklendi",
2147
+ "createFailed": "Paylaşılan yığın eklenemedi",
2148
+ "updated": "Paylaşılan yığın güncellendi",
2149
+ "updateFailed": "Paylaşılan yığın güncellenemedi",
2150
+ "startFailed": "Paylaşılan yığın başlatılamadı",
2151
+ "stopFailed": "Paylaşılan yığın durdurulamadı",
2152
+ "removeFailed": "Paylaşılan yığın silinemedi"
2153
+ }
2154
+ },
2109
2155
  "localMode": {
2110
2156
  "title": "Yerel mod",
2111
2157
  "intro": "Yerel konteyner çalıştırıcısı için ayarlar, bu makinenin dağıtımında saklanır ({poolVars} / {harnessVars} ortam değişkenlerinin yerini aldı). Kaydetmek sıcak havuzu anında yeniden boyutlandırır, yeniden başlatma gerekmez; devam eden çalıştırmalar zaten tuttukları konteyneri korur.",
@@ -1984,6 +1984,52 @@
1984
1984
  "removeFailed": "Не вдалося видалити запис реєстру"
1985
1985
  }
1986
1986
  },
1987
+ "sharedStacks": {
1988
+ "tab": "Спільні стеки",
1989
+ "intro": "Довготривала інфраструктура Compose (бази даних, брокери, пошук, пошта), яку запускають один раз на робочий простір і повторно використовують у всіх запусках та pull request'ах. Тестове середовище під'єднується до керованої мережі стека. Запуск стека потребує локального розгортання Docker; на інших бекендах ви все одно можете керувати визначенням.",
1990
+ "stackNoun": "спільний стек",
1991
+ "status": {
1992
+ "stopped": "Зупинено",
1993
+ "starting": "Запуск",
1994
+ "running": "Працює",
1995
+ "failed": "Помилка"
1996
+ },
1997
+ "list": {
1998
+ "heading": "Налаштовані стеки",
1999
+ "start": "Запустити",
2000
+ "stop": "Зупинити",
2001
+ "edit": "Редагувати",
2002
+ "remove": "Видалити стек"
2003
+ },
2004
+ "add": {
2005
+ "heading": "Додати спільний стек",
2006
+ "name": "Назва",
2007
+ "cloneUrl": "URL клонування репозиторію",
2008
+ "cloneUrlHelp": "Git-репозиторій, у якому містяться файли Compose стека.",
2009
+ "gitRef": "Гілка або тег (необов'язково)",
2010
+ "composeFiles": "Файли Compose",
2011
+ "composeFilesHelp": "Через кому, відносно репозиторію, у порядку перевизначення.",
2012
+ "composeProfiles": "Профілі Compose (необов'язково)",
2013
+ "managedNetworks": "Керовані мережі (необов'язково)",
2014
+ "managedNetworksHelp": "Мережі, які цей стек створює й якими володіє, щоб споживачі під'єднувалися до них.",
2015
+ "allowHostCommands": "Дозволити кроки налаштування з командами хоста",
2016
+ "save": "Додати стек"
2017
+ },
2018
+ "edit": {
2019
+ "heading": "Редагувати спільний стек",
2020
+ "save": "Зберегти зміни",
2021
+ "cancel": "Скасувати"
2022
+ },
2023
+ "toast": {
2024
+ "created": "Спільний стек додано",
2025
+ "createFailed": "Не вдалося додати спільний стек",
2026
+ "updated": "Спільний стек оновлено",
2027
+ "updateFailed": "Не вдалося оновити спільний стек",
2028
+ "startFailed": "Не вдалося запустити спільний стек",
2029
+ "stopFailed": "Не вдалося зупинити спільний стек",
2030
+ "removeFailed": "Не вдалося видалити спільний стек"
2031
+ }
2032
+ },
1987
2033
  "localMode": {
1988
2034
  "title": "Локальний режим",
1989
2035
  "intro": "Налаштування локального запускача контейнерів, збережене на розгортанні цієї машини (воно замінило змінні середовища {poolVars} / {harnessVars}). Збереження змінює розмір теплого пулу наживо, без потреби в перезапуску; поточні запуски зберігають контейнер, який вони вже утримують.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.93.0",
3
+ "version": "0.94.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.102.0"
37
+ "@cat-factory/contracts": "0.103.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@toad-contracts/testing": "0.3.2",