@cat-factory/app 0.189.0 → 0.190.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/app/components/environments/EnvironmentSetupWizard.vue +1 -0
- package/app/components/panels/AgentStepDetail.vue +2 -0
- package/app/components/panels/ReportsPanel.vue +1 -0
- package/app/components/panels/inspector/TaskRunSettings.vue +1 -0
- package/app/components/pipeline/PipelinePreview.vue +1 -0
- package/app/components/prReview/PrReviewWindow.vue +1 -0
- package/app/components/settings/RiskPolicyPanel.vue +1 -0
- package/app/components/settings/SharedStacksPanel.vue +52 -4
- package/app/composables/api/client.spec.ts +50 -0
- package/app/composables/api/client.ts +26 -1
- package/app/stores/environmentWizard/save.ts +7 -1
- package/i18n/locales/de.json +1 -0
- package/i18n/locales/en.json +1 -0
- package/i18n/locales/es.json +1 -0
- package/i18n/locales/fr.json +1 -0
- package/i18n/locales/he.json +1 -0
- package/i18n/locales/it.json +1 -0
- package/i18n/locales/ja.json +1 -0
- package/i18n/locales/pl.json +1 -0
- package/i18n/locales/tr.json +1 -0
- package/i18n/locales/uk.json +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -54,6 +54,16 @@ over the WebSocket. How that sync works is written up in
|
|
|
54
54
|
| `types/` | TypeScript domain unions (`domain.ts`) and wire types mirroring the contracts. |
|
|
55
55
|
| `utils/` | Small pure helpers. |
|
|
56
56
|
|
|
57
|
+
### Always import a layer component explicitly
|
|
58
|
+
|
|
59
|
+
**Import a component under `components/` by path before using it in a template.** Do not lean on Nuxt's auto-registration. This layer sets no `components` config, so the default `pathPrefix: true` applies and a component is registered under its path-prefixed name: `components/panels/StepEffortReport.vue` becomes `PanelsStepEffortReport`, and a bare `<StepEffortReport>` matches nothing.
|
|
60
|
+
|
|
61
|
+
Some bare tags do work, which is exactly what makes this worth writing down. Nuxt drops a directory segment the filename already repeats, so `pipeline/PipelinePicker.vue` registers as `PipelinePicker` and resolves bare, while `pipeline/AgentKindIcon.vue` in the same folder registers as `PipelineAgentKindIcon` and does not. Whether a tag resolves therefore depends on a coincidence between a folder name and a filename, and renaming either end breaks the tag with no error. An explicit import does not care.
|
|
62
|
+
|
|
63
|
+
The failure is silent, which is why this is a rule rather than a preference. An unresolved tag warns in dev and then renders nothing, so a built SPA has a hole where the component should be. Nothing catches it: not typecheck, not the unit tests, not the e2e suite, and not the user, who reads it as a backend returning no data. Seven components had shipped this way.
|
|
64
|
+
|
|
65
|
+
`scripts/check-component-imports.mjs` enforces it (CI's `repo-guards` job). If a panel section is missing and the data looks right, check the import first.
|
|
66
|
+
|
|
57
67
|
## Interface modes (basic / advanced)
|
|
58
68
|
|
|
59
69
|
The SPA renders at one of two **interface tiers**. `basic` (the default) is the everyday
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { computed } from 'vue'
|
|
18
18
|
import { JourneyHost, JourneyOutlet } from '@modular-vue/journeys'
|
|
19
19
|
import { environmentSetupHandle } from '~/modular/journeys/environmentSetup'
|
|
20
|
+
import EnvSetupStepper from '~/components/environments/EnvSetupStepper.vue'
|
|
20
21
|
|
|
21
22
|
const ui = useUiStore()
|
|
22
23
|
const { t } = useI18n()
|
|
@@ -6,6 +6,8 @@ import { agentKindMeta } from '~/utils/catalog'
|
|
|
6
6
|
import StepRestartControl from '~/components/panels/StepRestartControl.vue'
|
|
7
7
|
import StepMetadataCard from '~/components/panels/StepMetadataCard.vue'
|
|
8
8
|
import StepTestReport from '~/components/panels/StepTestReport.vue'
|
|
9
|
+
import StepEffortReport from '~/components/panels/StepEffortReport.vue'
|
|
10
|
+
import StepFragmentAdherence from '~/components/panels/StepFragmentAdherence.vue'
|
|
9
11
|
import EnvironmentStatusPanel from '~/components/environments/EnvironmentStatusPanel.vue'
|
|
10
12
|
import FrontendBindingsResolved from '~/components/panels/inspector/FrontendBindingsResolved.vue'
|
|
11
13
|
import { UI_TESTER_AGENT_KIND } from '@cat-factory/contracts'
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
segmentPct,
|
|
17
17
|
trendMagnitude,
|
|
18
18
|
} from './ReportsPanel.logic'
|
|
19
|
+
import ReportsSpendBreakdown from '~/components/panels/ReportsSpendBreakdown.vue'
|
|
19
20
|
|
|
20
21
|
// Reports: cross-cutting usage analytics for the active account — where the spend and the
|
|
21
22
|
// work actually go. Spend per model and agent kind, spend + run activity per workspace /
|
|
@@ -8,6 +8,7 @@ import { showOverrideField } from '~/utils/uiMode'
|
|
|
8
8
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
9
9
|
import RiskPolicyPicker from '~/components/riskPolicy/RiskPolicyPicker.vue'
|
|
10
10
|
import TaskAprioriBranches from '~/components/panels/inspector/TaskAprioriBranches.vue'
|
|
11
|
+
import DocReferenceRepos from '~/components/panels/inspector/DocReferenceRepos.vue'
|
|
11
12
|
|
|
12
13
|
const props = defineProps<{ block: Block }>()
|
|
13
14
|
|
|
@@ -12,6 +12,7 @@ import { computed } from 'vue'
|
|
|
12
12
|
import type { Pipeline } from '~/types/domain'
|
|
13
13
|
import { agentKindMeta } from '~/utils/catalog'
|
|
14
14
|
import { pipelineDisplaySteps, pipelineGateCount } from '~/utils/pipeline'
|
|
15
|
+
import AgentKindIcon from '~/components/pipeline/AgentKindIcon.vue'
|
|
15
16
|
|
|
16
17
|
const props = defineProps<{ pipeline: Pipeline }>()
|
|
17
18
|
const { t } = useI18n()
|
|
@@ -24,6 +24,7 @@ import { subtaskIconClass } from '~/utils/pipelineRender'
|
|
|
24
24
|
import { activeChunkLabels, chunkReviewPercent, hasNoSlicePlan } from '~/utils/prReviewProgress'
|
|
25
25
|
import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
|
|
26
26
|
import StepRunMeta from '~/components/panels/StepRunMeta.vue'
|
|
27
|
+
import StepFragmentAdherence from '~/components/panels/StepFragmentAdherence.vue'
|
|
27
28
|
|
|
28
29
|
const execution = useExecutionStore()
|
|
29
30
|
const board = useBoardStore()
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// they succeed only on the local facade (elsewhere the backend returns a clear error surfaced as
|
|
7
7
|
// a toast). Renders inline inside the Infrastructure window's "Shared stacks" tab.
|
|
8
8
|
import { computed, reactive, ref } from 'vue'
|
|
9
|
+
import { describeComposeSource, normalizeComposeFileRefs } from '@cat-factory/contracts'
|
|
9
10
|
import type {
|
|
10
11
|
SharedStack,
|
|
11
12
|
SharedStackRecommendation,
|
|
@@ -76,8 +77,26 @@ function tokens(value: string): string[] {
|
|
|
76
77
|
.filter(Boolean)
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
// A stack's compose layers may be bare in-repo paths (what this form authors and what the
|
|
81
|
+
// autodetect scan returns) or explicit sources — an inline document, or a file in another repo —
|
|
82
|
+
// which arrive through the API / a deployment's programmatic seeds. The form edits only the
|
|
83
|
+
// former; a stack carrying any of the latter shows its layers read-only and its save omits
|
|
84
|
+
// `composeFiles` entirely, so editing the name or the profiles can never silently flatten a
|
|
85
|
+
// declaration this form has no editor for.
|
|
86
|
+
const editingStack = computed(() => stacks.value.find((s) => s.id === editingId.value) ?? null)
|
|
87
|
+
const advancedLayers = computed(() =>
|
|
88
|
+
(editingStack.value?.composeFiles ?? []).some((ref) => typeof ref !== 'string'),
|
|
89
|
+
)
|
|
90
|
+
const layerLabels = computed(() =>
|
|
91
|
+
normalizeComposeFileRefs(editingStack.value?.composeFiles ?? []).map(describeComposeSource),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
// A repo-LESS stack (every layer inline / from another repo) needs no clone URL, so the form
|
|
95
|
+
// requires one only while the layers it can author — in-repo paths — are what is being saved.
|
|
79
96
|
const canSave = computed(
|
|
80
|
-
() =>
|
|
97
|
+
() =>
|
|
98
|
+
form.name.trim() &&
|
|
99
|
+
(advancedLayers.value || (form.cloneUrl.trim() && tokens(form.composeFiles).length > 0)),
|
|
81
100
|
)
|
|
82
101
|
|
|
83
102
|
function resetForm() {
|
|
@@ -97,10 +116,12 @@ function resetForm() {
|
|
|
97
116
|
function startEdit(stack: SharedStack) {
|
|
98
117
|
editingId.value = stack.id
|
|
99
118
|
form.name = stack.name
|
|
100
|
-
form.cloneUrl = stack.cloneUrl
|
|
119
|
+
form.cloneUrl = stack.cloneUrl ?? ''
|
|
101
120
|
form.gitRef = stack.gitRef ?? ''
|
|
102
121
|
form.directory = ''
|
|
103
|
-
|
|
122
|
+
// Only bare in-repo paths are editable here; a stack with richer layers renders them read-only
|
|
123
|
+
// below and keeps them untouched through the save.
|
|
124
|
+
form.composeFiles = stack.composeFiles.filter((ref) => typeof ref === 'string').join(', ')
|
|
104
125
|
form.composeProfiles = stack.composeProfiles.join(', ')
|
|
105
126
|
form.managedNetworks = stack.managedNetworks.join(', ')
|
|
106
127
|
form.allowHostCommands = stack.allowHostCommands
|
|
@@ -179,7 +200,17 @@ async function saveStack() {
|
|
|
179
200
|
}
|
|
180
201
|
try {
|
|
181
202
|
if (editing) {
|
|
182
|
-
|
|
203
|
+
// `composeFiles` is omitted when the stack carries layers this form can't author — the
|
|
204
|
+
// partial update preserves them, exactly as it already does for setup steps and the health
|
|
205
|
+
// gate. `cloneUrl` goes through as an explicit null when cleared, so a stack can be moved to
|
|
206
|
+
// the repo-less shape from here too.
|
|
207
|
+
const { composeFiles, ...rest } = payload
|
|
208
|
+
await store.update(editing, {
|
|
209
|
+
...rest,
|
|
210
|
+
cloneUrl: form.cloneUrl.trim() || null,
|
|
211
|
+
gitRef: form.gitRef.trim() || null,
|
|
212
|
+
...(advancedLayers.value ? {} : { composeFiles }),
|
|
213
|
+
})
|
|
183
214
|
} else {
|
|
184
215
|
await store.create(payload)
|
|
185
216
|
}
|
|
@@ -402,6 +433,23 @@ async function remove(stack: SharedStack) {
|
|
|
402
433
|
</p>
|
|
403
434
|
|
|
404
435
|
<UFormField
|
|
436
|
+
v-if="advancedLayers"
|
|
437
|
+
:label="t('settings.sharedStacks.add.composeFiles')"
|
|
438
|
+
:help="t('settings.sharedStacks.add.composeLayersManagedHelp')"
|
|
439
|
+
>
|
|
440
|
+
<ul class="space-y-1" data-testid="shared-stack-compose-layers">
|
|
441
|
+
<li
|
|
442
|
+
v-for="(label, index) in layerLabels"
|
|
443
|
+
:key="index"
|
|
444
|
+
class="font-mono text-[11px] text-slate-500"
|
|
445
|
+
>
|
|
446
|
+
{{ label }}
|
|
447
|
+
</li>
|
|
448
|
+
</ul>
|
|
449
|
+
</UFormField>
|
|
450
|
+
|
|
451
|
+
<UFormField
|
|
452
|
+
v-else
|
|
405
453
|
:label="t('settings.sharedStacks.add.composeFiles')"
|
|
406
454
|
:help="t('settings.sharedStacks.add.composeFilesHelp')"
|
|
407
455
|
>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ApiContract } from '@toad-contracts/core'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import { type SendParams, withoutUndefinedQueryParams } from '~/composables/api/client'
|
|
4
|
+
|
|
5
|
+
// An omitted optional query param used to reach the server as `key=`: the contract client
|
|
6
|
+
// serialises with `fast-querystring`, whose `stringify({ blockId: undefined })` is `'blockId='`,
|
|
7
|
+
// and request validation waves the key through because `v.optional(...)` accepts `undefined`. On
|
|
8
|
+
// `listTasksContract`, whose `blockId` carries a `minLength(1)`, that made every unscoped
|
|
9
|
+
// `listTasks()` a guaranteed 400. These lock the strip in.
|
|
10
|
+
|
|
11
|
+
// The helper is contract-generic and only ever reads `queryParams`, so the cases below describe
|
|
12
|
+
// request params structurally rather than picking a real contract per shape.
|
|
13
|
+
type Params = Record<string, unknown>
|
|
14
|
+
const strip = (params: Params): Params =>
|
|
15
|
+
withoutUndefinedQueryParams(params as SendParams<ApiContract>) as Params
|
|
16
|
+
|
|
17
|
+
describe('withoutUndefinedQueryParams', () => {
|
|
18
|
+
it('drops undefined-valued query keys so they never reach the query string', () => {
|
|
19
|
+
const out = strip({ pathPrefix: '/workspaces/ws_1', queryParams: { blockId: undefined } })
|
|
20
|
+
expect(out.queryParams).toEqual({})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// The guard against "fix" it with a falsy check: 0, false and '' are all values a caller
|
|
24
|
+
// deliberately sent, and only `undefined` means absent.
|
|
25
|
+
it('keeps defined values, including falsy ones a caller meant to send', () => {
|
|
26
|
+
const out = strip({ queryParams: { blockId: 'blk_1', page: 0, all: false, q: '' } })
|
|
27
|
+
expect(out.queryParams).toEqual({ blockId: 'blk_1', page: 0, all: false, q: '' })
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('drops only the undefined keys from a mixed set', () => {
|
|
31
|
+
const out = strip({ queryParams: { window: '7d', workspaceId: undefined } })
|
|
32
|
+
expect(out.queryParams).toEqual({ window: '7d' })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('leaves other request params untouched', () => {
|
|
36
|
+
const params = {
|
|
37
|
+
pathPrefix: '/workspaces/ws_1',
|
|
38
|
+
pathParams: { source: 'jira' },
|
|
39
|
+
body: { a: 1 },
|
|
40
|
+
}
|
|
41
|
+
expect(strip(params)).toEqual(params)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('returns the same object when there is nothing to strip', () => {
|
|
45
|
+
const params = { queryParams: { blockId: 'blk_1' } }
|
|
46
|
+
expect(strip(params)).toBe(params)
|
|
47
|
+
const noQuery = { pathPrefix: '/workspaces/ws_1' }
|
|
48
|
+
expect(strip(noQuery)).toBe(noQuery)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -71,6 +71,31 @@ export function createApiClient(): WretchInstance {
|
|
|
71
71
|
])
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Drop query keys whose value is `undefined`, so an omitted optional param is absent from the
|
|
76
|
+
* query string instead of present-but-empty.
|
|
77
|
+
*
|
|
78
|
+
* `sendByApiContract` serialises with `fast-querystring`, and `stringify({ blockId: undefined })`
|
|
79
|
+
* is `'blockId='`. Request validation does not catch it, because `v.optional(...)` accepts
|
|
80
|
+
* `undefined` and the key only becomes empty on the way out. The server then validates the parsed
|
|
81
|
+
* `''`, so any optional param carrying a `minLength(1)` rejects the whole request with a 400. That
|
|
82
|
+
* is what made an unscoped `listTasks()` uncallable. Params with no length check are luckier but
|
|
83
|
+
* still wrong: the handler reads `''` where it asked for absence.
|
|
84
|
+
*
|
|
85
|
+
* Stripping at this one chokepoint fixes every contract at once, which is the point. Writing
|
|
86
|
+
* `queryParams: { foo }` for an optional `foo` is the obvious thing to write and it should work,
|
|
87
|
+
* rather than each call site remembering to spread the key in conditionally.
|
|
88
|
+
*/
|
|
89
|
+
export function withoutUndefinedQueryParams<T extends ApiContract>(
|
|
90
|
+
params: SendParams<T>,
|
|
91
|
+
): SendParams<T> {
|
|
92
|
+
const query = (params as { queryParams?: Record<string, unknown> }).queryParams
|
|
93
|
+
if (!query) return params
|
|
94
|
+
const present = Object.entries(query).filter(([, value]) => value !== undefined)
|
|
95
|
+
if (present.length === Object.keys(query).length) return params
|
|
96
|
+
return { ...params, queryParams: Object.fromEntries(present) }
|
|
97
|
+
}
|
|
98
|
+
|
|
74
99
|
/**
|
|
75
100
|
* Send a contract request and unwrap to the success body (or throw the typed error).
|
|
76
101
|
* The public signature preserves per-contract inference for callers; inside,
|
|
@@ -82,7 +107,7 @@ export async function sendContract<T extends ApiContract>(
|
|
|
82
107
|
contract: T,
|
|
83
108
|
params: SendParams<T>,
|
|
84
109
|
): Promise<SuccessBodyOf<T>> {
|
|
85
|
-
const outcome = await sendByApiContract(client, contract, params)
|
|
110
|
+
const outcome = await sendByApiContract(client, contract, withoutUndefinedQueryParams(params))
|
|
86
111
|
if (outcome.error) {
|
|
87
112
|
const error = outcome.error
|
|
88
113
|
// A contract-declared non-2xx is reported as a plain `{ statusCode, headers, body }`
|
|
@@ -95,7 +95,13 @@ export function createSaveActions(ctx: WizardContext) {
|
|
|
95
95
|
await board.updateBlock(id, {
|
|
96
96
|
provisioning: {
|
|
97
97
|
type: 'docker-compose',
|
|
98
|
-
|
|
98
|
+
// `composePath` is the single-file fallback the provider uses when a recipe declares no
|
|
99
|
+
// layers, so only a bare in-repo path can fill it. The wizard's layers always are ones
|
|
100
|
+
// (they come from the deterministic detector); an `inline` / other-repo layer, which the
|
|
101
|
+
// API can supply, simply leaves it unset — the recipe below already carries the layer.
|
|
102
|
+
...(typeof pruned.composeFiles?.[0] === 'string'
|
|
103
|
+
? { composePath: pruned.composeFiles[0] }
|
|
104
|
+
: {}),
|
|
99
105
|
...(build ? { composeBuild: true } : {}),
|
|
100
106
|
recipe: pruned,
|
|
101
107
|
},
|
package/i18n/locales/de.json
CHANGED
|
@@ -630,6 +630,7 @@
|
|
|
630
630
|
"directoryHelp": "Wird nur von der automatischen Erkennung verwendet: das Monorepo-Unterverzeichnis, in dem der Compose-Stack liegt.",
|
|
631
631
|
"composeFiles": "Compose-Dateien",
|
|
632
632
|
"composeFilesHelp": "Kommagetrennt, repo-relativ, in Override-Reihenfolge.",
|
|
633
|
+
"composeLayersManagedHelp": "Über die API verwaltet — dieser Stack hat Layer, die inline bereitgestellt oder aus einem anderen Repository gelesen werden; sie werden hier schreibgeschützt angezeigt und beim Speichern nicht verändert.",
|
|
633
634
|
"composeProfiles": "Compose-Profile (optional)",
|
|
634
635
|
"managedNetworks": "Verwaltete Netzwerke (optional)",
|
|
635
636
|
"managedNetworksHelp": "Netzwerke, die dieser Stack für Konsumenten erstellt und besitzt, um sich damit zu verbinden.",
|
package/i18n/locales/en.json
CHANGED
|
@@ -2923,6 +2923,7 @@
|
|
|
2923
2923
|
"directoryHelp": "Used only by Autodetect: the monorepo subdirectory the compose stack lives in.",
|
|
2924
2924
|
"composeFiles": "Compose files",
|
|
2925
2925
|
"composeFilesHelp": "Comma-separated, repo-relative, in override order.",
|
|
2926
|
+
"composeLayersManagedHelp": "Managed through the API — this stack has layers supplied inline or read from another repo, so they are shown read-only here and left untouched when you save.",
|
|
2926
2927
|
"composeProfiles": "Compose profiles (optional)",
|
|
2927
2928
|
"managedNetworks": "Managed networks (optional)",
|
|
2928
2929
|
"managedNetworksHelp": "Networks this stack creates and owns for consumers to attach to.",
|
package/i18n/locales/es.json
CHANGED
|
@@ -2703,6 +2703,7 @@
|
|
|
2703
2703
|
"directoryHelp": "Solo lo usa la detección automática: el subdirectorio del monorepo donde se encuentra el stack de compose.",
|
|
2704
2704
|
"composeFiles": "Archivos de Compose",
|
|
2705
2705
|
"composeFilesHelp": "Separados por comas, relativos al repositorio, en orden de anulación.",
|
|
2706
|
+
"composeLayersManagedHelp": "Gestionado mediante la API: esta pila tiene capas suministradas en línea o leídas desde otro repositorio, por lo que aquí se muestran como solo lectura y no se modifican al guardar.",
|
|
2706
2707
|
"composeProfiles": "Perfiles de Compose (opcional)",
|
|
2707
2708
|
"managedNetworks": "Redes gestionadas (opcional)",
|
|
2708
2709
|
"managedNetworksHelp": "Redes que este stack crea y posee para que los consumidores se conecten.",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -2703,6 +2703,7 @@
|
|
|
2703
2703
|
"directoryHelp": "Utilisé uniquement par la détection automatique : le sous-répertoire du monorepo où se trouve le stack compose.",
|
|
2704
2704
|
"composeFiles": "Fichiers Compose",
|
|
2705
2705
|
"composeFilesHelp": "Séparés par des virgules, relatifs au dépôt, dans l'ordre de surcharge.",
|
|
2706
|
+
"composeLayersManagedHelp": "Géré via l'API — cette pile comporte des couches fournies en ligne ou lues depuis un autre dépôt ; elles sont affichées en lecture seule ici et restent intactes à l'enregistrement.",
|
|
2706
2707
|
"composeProfiles": "Profils Compose (facultatif)",
|
|
2707
2708
|
"managedNetworks": "Réseaux gérés (facultatif)",
|
|
2708
2709
|
"managedNetworksHelp": "Réseaux que ce stack crée et possède pour que les consommateurs s'y connectent.",
|
package/i18n/locales/he.json
CHANGED
|
@@ -2843,6 +2843,7 @@
|
|
|
2843
2843
|
"directoryHelp": "בשימוש רק על ידי הזיהוי האוטומטי: תת-הספרייה במונורפו שבה נמצא מקבץ ה-compose.",
|
|
2844
2844
|
"composeFiles": "קובצי Compose",
|
|
2845
2845
|
"composeFilesHelp": "מופרדים בפסיקים, יחסית למאגר, לפי סדר הדריסה.",
|
|
2846
|
+
"composeLayersManagedHelp": "מנוהל דרך ה-API — למחסנית הזו יש שכבות שסופקו בתוך ההגדרה או נקראות ממאגר אחר, ולכן הן מוצגות כאן לקריאה בלבד ונשארות ללא שינוי בשמירה.",
|
|
2846
2847
|
"composeProfiles": "פרופילי Compose (אופציונלי)",
|
|
2847
2848
|
"managedNetworks": "רשתות מנוהלות (אופציונלי)",
|
|
2848
2849
|
"managedNetworksHelp": "רשתות שהמקבץ יוצר ומחזיק כדי שצרכנים יתחברו אליהן.",
|
package/i18n/locales/it.json
CHANGED
|
@@ -630,6 +630,7 @@
|
|
|
630
630
|
"directoryHelp": "Usato solo dal rilevamento automatico: la sottodirectory del monorepo in cui si trova lo stack compose.",
|
|
631
631
|
"composeFiles": "File compose",
|
|
632
632
|
"composeFilesHelp": "Separati da virgola, relativi al repository, in ordine di override.",
|
|
633
|
+
"composeLayersManagedHelp": "Gestito tramite API: questo stack ha livelli forniti inline o letti da un altro repository, quindi qui sono mostrati in sola lettura e restano invariati al salvataggio.",
|
|
633
634
|
"composeProfiles": "Profili compose (facoltativo)",
|
|
634
635
|
"managedNetworks": "Reti gestite (facoltativo)",
|
|
635
636
|
"managedNetworksHelp": "Reti che questo stack crea e possiede affinche i consumatori vi si colleghino.",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -2844,6 +2844,7 @@
|
|
|
2844
2844
|
"directoryHelp": "自動検出でのみ使用されます。compose スタックが存在するモノレポのサブディレクトリです。",
|
|
2845
2845
|
"composeFiles": "Compose ファイル",
|
|
2846
2846
|
"composeFilesHelp": "カンマ区切り、リポジトリ相対、オーバーライド順。",
|
|
2847
|
+
"composeLayersManagedHelp": "API で管理されています。このスタックにはインラインで指定された層、または別のリポジトリから読み込まれる層があるため、ここでは読み取り専用で表示され、保存時にも変更されません。",
|
|
2847
2848
|
"composeProfiles": "Compose プロファイル(任意)",
|
|
2848
2849
|
"managedNetworks": "マネージドネットワーク(任意)",
|
|
2849
2850
|
"managedNetworksHelp": "コンシューマーが接続するために、このスタックが作成・所有するネットワーク。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -2703,6 +2703,7 @@
|
|
|
2703
2703
|
"directoryHelp": "Używane tylko przez automatyczne wykrywanie: podkatalog monorepo, w którym znajduje się stos compose.",
|
|
2704
2704
|
"composeFiles": "Pliki Compose",
|
|
2705
2705
|
"composeFilesHelp": "Rozdzielone przecinkami, względem repozytorium, w kolejności nadpisywania.",
|
|
2706
|
+
"composeLayersManagedHelp": "Zarządzane przez API — ten stos ma warstwy podane bezpośrednio lub odczytywane z innego repozytorium, więc są tu tylko do odczytu i pozostają nietknięte przy zapisie.",
|
|
2706
2707
|
"composeProfiles": "Profile Compose (opcjonalnie)",
|
|
2707
2708
|
"managedNetworks": "Zarządzane sieci (opcjonalnie)",
|
|
2708
2709
|
"managedNetworksHelp": "Sieci, które ten stos tworzy i posiada, aby konsumenci mogli się z nimi łączyć.",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -2844,6 +2844,7 @@
|
|
|
2844
2844
|
"directoryHelp": "Yalnızca otomatik algılama tarafından kullanılır: compose yığınının bulunduğu monorepo alt dizini.",
|
|
2845
2845
|
"composeFiles": "Compose dosyaları",
|
|
2846
2846
|
"composeFilesHelp": "Virgülle ayrılmış, depoya göreli, geçersiz kılma sırasında.",
|
|
2847
|
+
"composeLayersManagedHelp": "API üzerinden yönetilir — bu yığında satır içi verilen veya başka bir depodan okunan katmanlar var; burada salt okunur gösterilir ve kaydettiğinizde değiştirilmez.",
|
|
2847
2848
|
"composeProfiles": "Compose profilleri (isteğe bağlı)",
|
|
2848
2849
|
"managedNetworks": "Yönetilen ağlar (isteğe bağlı)",
|
|
2849
2850
|
"managedNetworksHelp": "Tüketicilerin bağlanması için bu yığının oluşturup sahip olduğu ağlar.",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -2703,6 +2703,7 @@
|
|
|
2703
2703
|
"directoryHelp": "Використовується лише автовизначенням: підкаталог монорепозиторію, де розташований стек compose.",
|
|
2704
2704
|
"composeFiles": "Файли Compose",
|
|
2705
2705
|
"composeFilesHelp": "Через кому, відносно репозиторію, у порядку перевизначення.",
|
|
2706
|
+
"composeLayersManagedHelp": "Керується через API — цей стек має шари, задані безпосередньо або зчитані з іншого репозиторію, тож тут вони показані лише для читання й не змінюються під час збереження.",
|
|
2706
2707
|
"composeProfiles": "Профілі Compose (необов'язково)",
|
|
2707
2708
|
"managedNetworks": "Керовані мережі (необов'язково)",
|
|
2708
2709
|
"managedNetworksHelp": "Мережі, які цей стек створює й якими володіє, щоб споживачі під'єднувалися до них.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.190.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.40",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.197.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|