@cat-factory/app 0.209.0 → 0.210.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.
@@ -160,16 +160,26 @@ async function removeKey(key: string) {
160
160
  })
161
161
  }}
162
162
  </p>
163
- <!-- An EMPTY row is not the same fact in both deployments, so it must not read the same
164
- way. Behind the store the deployment's own environment may still answer for this key,
165
- and calling that "missing" would send an operator hunting for a value that is already
166
- resolving. -->
167
- <p v-else-if="view?.environmentFallback" class="text-[11px] text-slate-500">
163
+ <!-- An EMPTY row is not the same fact in every deployment, so it must not read the same way.
164
+ Three states, and the backend reports them off the chain it actually composed: with the
165
+ fallback the deployment's own environment may still answer, and calling that "missing"
166
+ would send an operator hunting for a value that is already resolving; without it, blank
167
+ really does mean the capability cannot authenticate.
168
+
169
+ The third is that the chain cannot be described, and this copy says exactly that and
170
+ stops. It must not name a cause: a deployment's own resolver replacing the chain is the
171
+ usual one, but a facade that wired the store and dropped the flag lands here too, and
172
+ blaming a custom resolver would make that wiring bug read as a deliberate configuration
173
+ and send the operator to the one place that cannot explain it. -->
174
+ <p v-else-if="view?.environmentFallback === true" class="text-[11px] text-slate-500">
168
175
  {{ t('settings.capabilityCredentials.notStoredWithFallback') }}
169
176
  </p>
170
- <p v-else class="text-[11px] text-amber-400">
177
+ <p v-else-if="view?.environmentFallback === false" class="text-[11px] text-amber-400">
171
178
  {{ t('settings.capabilityCredentials.notStored') }}
172
179
  </p>
180
+ <p v-else class="text-[11px] text-slate-500">
181
+ {{ t('settings.capabilityCredentials.notStoredUnknownFallback') }}
182
+ </p>
173
183
 
174
184
  <div class="flex items-end gap-2">
175
185
  <UFormField
@@ -30,6 +30,11 @@ describe('captureRunDeepLink', () => {
30
30
  })
31
31
  })
32
32
 
33
+ it('parses the captured-evidence link the lifecycle section emits', () => {
34
+ setUrl('?ws=ws_1&block=blk_1&run=exec_1&view=test-evidence')
35
+ expect(captureRunDeepLink()?.view).toBe('test-evidence')
36
+ })
37
+
33
38
  it('strips its own params so a reload does not re-open the panel', () => {
34
39
  setUrl('?ws=ws_1&run=exec_1&view=observability&keep=yes')
35
40
  captureRunDeepLink()
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Boot-time replay of a RUN deep link `?ws=<id>&block=<id>&run=<id>&view=observability`.
2
+ * Boot-time replay of a RUN deep link: `?ws=<id>&block=<id>&run=<id>&view=<panel>`.
3
3
  *
4
- * The engine's PR verification report links each PR back to the run's observability panel
5
- * (Model activity / Provided context), built from the deployment's public app URL. The SPA is a
6
- * single canvas with no URL identity for anything, so this is the narrow consumer that makes
7
- * that link resolve: pin the board before the snapshot loads, then once the board is ready
8
- * select the task and open the panel for the run.
4
+ * The engine's PR verification report links each PR back into the run: to the observability
5
+ * panel (Model activity / Provided context), and to the Tester's result window holding the
6
+ * evidence its environment-lifecycle section lists. Both are built from the deployment's public
7
+ * app URL. The SPA is a single canvas with no URL identity for anything, so this is the narrow
8
+ * consumer that makes those links resolve: pin the board before the snapshot loads, then, once
9
+ * the board is ready, select the task and open the panel for the run.
9
10
  *
10
11
  * Deliberately narrow. The GENERAL parser (every entity, every window, plus state→URL sync) is
11
12
  * slice 4 of `docs/initiatives/global-search-and-deep-links.md`; when it lands, this composable
@@ -81,9 +82,11 @@ export function useRunDeepLink(): void {
81
82
  if (!ready || applied) return
82
83
  applied = true
83
84
  if (link.blockId) ui.select(link.blockId)
84
- // `observability` is the only view this narrow parser serves an unknown view still
85
- // lands the user on the right board and task rather than failing the navigation.
85
+ // Two views are served: the observability panel and the Tester's result window (where the
86
+ // screenshots the report's environment-lifecycle section lists are rendered). An unknown
87
+ // view still lands the user on the right board and task rather than failing the navigation.
86
88
  if (link.view === 'observability') ui.openObservability(link.runId)
89
+ else if (link.view === 'test-evidence') ui.openTestEvidence(link.runId)
87
90
  stop?.()
88
91
  },
89
92
  { immediate: true },
@@ -2,6 +2,7 @@ import { ref } from 'vue'
2
2
  import { useExecutionStore } from '~/stores/execution'
3
3
  import { agentKindMeta } from '~/utils/catalog'
4
4
  import { dedicatedParkView } from '~/utils/pipelineRender'
5
+ import { createRunStepOpeners } from './runStepOpeners'
5
6
 
6
7
  /**
7
8
  * The step-inspection / result-view slice of the UI store: the dedicated result-view overlay
@@ -126,84 +127,16 @@ export function createUiResultViews() {
126
127
  function openInitiativePlanning(blockId: string) {
127
128
  resultView.value = { view: 'initiative-planning', blockId, instanceId: null, stepIndex: null }
128
129
  }
129
- // Open the Follow-up companion window for a run's Coder step (the blinking chip + the
130
- // `followup_pending` notification). Resolves the Coder step index from the run when not
131
- // given, so callers that only know the run can still open it.
132
- function openFollowUps(instanceId: string, stepIndex: number | null = null) {
133
- const execution = useExecutionStore()
134
- const instance = execution.getInstance(instanceId)
135
- if (!instance) return
136
- // A pipeline may carry more than one follow-up-enabled Coder step, so don't blindly pick
137
- // the first when no index is given: prefer the step that still has undecided items (the
138
- // one the run is parked on), else the current step, else the first enabled one.
139
- const resolveIdx = () => {
140
- const pending = instance.steps.findIndex(
141
- (s) => s.followUps?.enabled && s.followUps.items.some((i) => i.status === 'pending'),
142
- )
143
- if (pending >= 0) return pending
144
- const current = instance.steps[instance.currentStep]
145
- if (current?.followUps?.enabled) return instance.currentStep
146
- return instance.steps.findIndex((s) => s.followUps?.enabled)
147
- }
148
- const idx = stepIndex ?? resolveIdx()
149
- if (idx < 0) return
150
- resultView.value = {
151
- view: 'follow-ups',
152
- blockId: instance.blockId,
153
- instanceId,
154
- stepIndex: idx,
155
- }
156
- }
157
- // Open the implementation-fork decision window for a run's coder step (from the inspector /
158
- // pipeline chip / `fork_decision_pending` notification). Resolves the coder step index from
159
- // the run when not given, preferring the step parked awaiting a choice.
160
- function openForkDecision(instanceId: string, stepIndex: number | null = null) {
161
- const execution = useExecutionStore()
162
- const instance = execution.getInstance(instanceId)
163
- if (!instance) return
164
- const resolveIdx = () => {
165
- const awaiting = instance.steps.findIndex(
166
- (s) => s.agentKind === 'coder' && s.forkDecision?.status === 'awaiting_choice',
167
- )
168
- if (awaiting >= 0) return awaiting
169
- const current = instance.steps[instance.currentStep]
170
- if (current?.agentKind === 'coder' && current.forkDecision) return instance.currentStep
171
- return instance.steps.findIndex((s) => s.agentKind === 'coder' && s.forkDecision)
172
- }
173
- const idx = stepIndex ?? resolveIdx()
174
- if (idx < 0) return
175
- resultView.value = {
176
- view: 'fork-decision',
177
- blockId: instance.blockId,
178
- instanceId,
179
- stepIndex: idx,
180
- }
181
- }
182
- // Open the PR deep-review window for a run's `pr-reviewer` step (from the `pr_review_ready`
183
- // notification / the step). Resolves the step index from the run when not given, preferring
184
- // the step parked awaiting a finding selection.
185
- function openPrReview(instanceId: string, stepIndex: number | null = null) {
186
- const execution = useExecutionStore()
187
- const instance = execution.getInstance(instanceId)
188
- if (!instance) return
189
- const resolveIdx = () => {
190
- const awaiting = instance.steps.findIndex(
191
- (s) => s.agentKind === 'pr-reviewer' && s.prReview?.status === 'awaiting_selection',
192
- )
193
- if (awaiting >= 0) return awaiting
194
- const current = instance.steps[instance.currentStep]
195
- if (current?.agentKind === 'pr-reviewer' && current.prReview) return instance.currentStep
196
- return instance.steps.findIndex((s) => s.agentKind === 'pr-reviewer' && s.prReview)
197
- }
198
- const idx = stepIndex ?? resolveIdx()
199
- if (idx < 0) return
200
- resultView.value = {
201
- view: 'pr-review',
202
- blockId: instance.blockId,
203
- instanceId,
204
- stepIndex: idx,
205
- }
206
- }
130
+ // The run-scoped openers (a caller that knows only the RUN, so the step index has to be
131
+ // resolved) live in a sibling module: they share one shape and one hazard, and lifting them out
132
+ // keeps this factory inside its per-function line budget. Their two seams are bound here.
133
+ const { openFollowUps, openForkDecision, openPrReview, openTestEvidence } = createRunStepOpeners({
134
+ dispatchStepView: (instanceId, stepIndex) => dispatchStepView(instanceId, stepIndex),
135
+ setResultView: (view, instance, stepIndex) => {
136
+ resultView.value = { view, blockId: instance.blockId, instanceId: instance.id, stepIndex }
137
+ },
138
+ })
139
+
207
140
  function closeResultView() {
208
141
  resultView.value = null
209
142
  }
@@ -243,6 +176,7 @@ export function createUiResultViews() {
243
176
  openFollowUps,
244
177
  openForkDecision,
245
178
  openPrReview,
179
+ openTestEvidence,
246
180
  closeResultView,
247
181
  closeRequirementReview,
248
182
  openStepDetail,
@@ -0,0 +1,143 @@
1
+ import { useExecutionStore } from '~/stores/execution'
2
+ import { isTesterKind } from '~/utils/catalog'
3
+ import type { ExecutionInstance, PipelineStep } from '~/types/domain'
4
+
5
+ /**
6
+ * The RUN-SCOPED window openers: entry points that know only which run to open, and have to
7
+ * resolve WHICH step of it the caller means before dispatching.
8
+ *
9
+ * They share one shape (find the step, bail if the run has none, open its window) and one hazard:
10
+ * a pipeline may carry the same agent kind more than once, so "the first matching step" is the
11
+ * wrong answer for every one of them. Each resolver states which of its candidates is the one a
12
+ * human was pointed at (the step parked awaiting a decision, the one that actually reported), and
13
+ * the callers that DO know the index still pass it and skip the resolution entirely.
14
+ *
15
+ * Extracted from `resultViews.ts` when the `test-evidence` opener pushed that factory over its
16
+ * per-function line budget: the budget is a split trigger, and this is the cohesive seam it named.
17
+ * Purely a move plus the new opener; the store's public surface is unchanged.
18
+ */
19
+ export interface RunStepOpenerDeps {
20
+ /** Open a step's bespoke window through the universal routing seam. */
21
+ dispatchStepView: (instanceId: string, stepIndex: number) => void
22
+ /** Set the result-view overlay directly, for a window the routing seam does not select. */
23
+ setResultView: (view: string, instance: ExecutionInstance, stepIndex: number) => void
24
+ }
25
+
26
+ /** Index of the first step matching `predicate`, or -1. */
27
+ function indexOf(instance: ExecutionInstance, predicate: (step: PipelineStep) => boolean): number {
28
+ return instance.steps.findIndex(predicate)
29
+ }
30
+
31
+ export function createRunStepOpeners(deps: RunStepOpenerDeps) {
32
+ /**
33
+ * Resolve the run, then the step index (the caller's when given, else `resolve`'s), then hand
34
+ * both to `open`. A run the store has not hydrated, or a pipeline with no candidate step, is a
35
+ * silent no-op: these are notification and deep-link entry points, and failing loudly at one
36
+ * would strand a user on a blank overlay.
37
+ */
38
+ function withStep(
39
+ instanceId: string,
40
+ stepIndex: number | null,
41
+ resolve: (instance: ExecutionInstance) => number,
42
+ open: (instance: ExecutionInstance, idx: number) => void,
43
+ ): void {
44
+ const instance = useExecutionStore().getInstance(instanceId)
45
+ if (!instance) return
46
+ const idx = stepIndex ?? resolve(instance)
47
+ if (idx < 0) return
48
+ open(instance, idx)
49
+ }
50
+
51
+ // Open the Follow-up companion window for a run's Coder step (the blinking chip + the
52
+ // `followup_pending` notification). Resolves the Coder step index from the run when not
53
+ // given, so callers that only know the run can still open it.
54
+ function openFollowUps(instanceId: string, stepIndex: number | null = null) {
55
+ withStep(
56
+ instanceId,
57
+ stepIndex,
58
+ // A pipeline may carry more than one follow-up-enabled Coder step, so don't blindly pick
59
+ // the first when no index is given: prefer the step that still has undecided items (the
60
+ // one the run is parked on), else the current step, else the first enabled one.
61
+ (instance) => {
62
+ const pending = indexOf(
63
+ instance,
64
+ (s) => !!s.followUps?.enabled && s.followUps.items.some((i) => i.status === 'pending'),
65
+ )
66
+ if (pending >= 0) return pending
67
+ const current = instance.steps[instance.currentStep]
68
+ if (current?.followUps?.enabled) return instance.currentStep
69
+ return indexOf(instance, (s) => !!s.followUps?.enabled)
70
+ },
71
+ (instance, idx) => deps.setResultView('follow-ups', instance, idx),
72
+ )
73
+ }
74
+
75
+ // Open the implementation-fork decision window for a run's coder step (from the inspector /
76
+ // pipeline chip / `fork_decision_pending` notification). Resolves the coder step index from
77
+ // the run when not given, preferring the step parked awaiting a choice.
78
+ function openForkDecision(instanceId: string, stepIndex: number | null = null) {
79
+ withStep(
80
+ instanceId,
81
+ stepIndex,
82
+ (instance) => {
83
+ const awaiting = indexOf(
84
+ instance,
85
+ (s) => s.agentKind === 'coder' && s.forkDecision?.status === 'awaiting_choice',
86
+ )
87
+ if (awaiting >= 0) return awaiting
88
+ const current = instance.steps[instance.currentStep]
89
+ if (current?.agentKind === 'coder' && current.forkDecision) return instance.currentStep
90
+ return indexOf(instance, (s) => s.agentKind === 'coder' && !!s.forkDecision)
91
+ },
92
+ (instance, idx) => deps.setResultView('fork-decision', instance, idx),
93
+ )
94
+ }
95
+
96
+ // Open the PR deep-review window for a run's `pr-reviewer` step (from the `pr_review_ready`
97
+ // notification / the step). Resolves the step index from the run when not given, preferring
98
+ // the step parked awaiting a finding selection.
99
+ function openPrReview(instanceId: string, stepIndex: number | null = null) {
100
+ withStep(
101
+ instanceId,
102
+ stepIndex,
103
+ (instance) => {
104
+ const awaiting = indexOf(
105
+ instance,
106
+ (s) => s.agentKind === 'pr-reviewer' && s.prReview?.status === 'awaiting_selection',
107
+ )
108
+ if (awaiting >= 0) return awaiting
109
+ const current = instance.steps[instance.currentStep]
110
+ if (current?.agentKind === 'pr-reviewer' && current.prReview) return instance.currentStep
111
+ return indexOf(instance, (s) => s.agentKind === 'pr-reviewer' && !!s.prReview)
112
+ },
113
+ (instance, idx) => deps.setResultView('pr-review', instance, idx),
114
+ )
115
+ }
116
+
117
+ // Open the Tester's result window for a run, where the screenshots and per-area outcomes it
118
+ // captured are rendered. The entry point is the `test-evidence` deep link the engine puts in
119
+ // every PR verification report's environment-lifecycle section, so the caller only ever knows
120
+ // the run.
121
+ function openTestEvidence(instanceId: string) {
122
+ withStep(
123
+ instanceId,
124
+ null,
125
+ // Prefer the tester step that actually REPORTED: a pipeline may carry more than one, and
126
+ // the later one describes the PR as it stands. Falling back to the first tester step opens
127
+ // the window on its "not run yet" state, which beats the link going nowhere.
128
+ (instance) => {
129
+ const candidates = instance.steps
130
+ .map((s, i) => ({ s, i }))
131
+ .filter(({ s }) => isTesterKind(s.agentKind))
132
+ const reported = candidates.filter(({ s }) => s.test?.lastReport)
133
+ return (reported.at(-1) ?? candidates[0])?.i ?? -1
134
+ },
135
+ // Routed through the universal dispatch rather than a fixed view id: a tester step running
136
+ // as a consensus panel opens the Consensus Session window instead, and this entry point
137
+ // must not override that.
138
+ (_instance, idx) => deps.dispatchStepView(instanceId, idx),
139
+ )
140
+ }
141
+
142
+ return { openFollowUps, openForkDecision, openPrReview, openTestEvidence }
143
+ }
@@ -96,4 +96,42 @@ describe('dispatchStepView routing', () => {
96
96
  expect(ui.resultView).toBeNull()
97
97
  expect(ui.stepDetail).toEqual({ instanceId: 'e1', stepIndex: 0 })
98
98
  })
99
+
100
+ // The `test-evidence` deep link the engine puts in every PR verification report knows only the
101
+ // RUN, so the opener has to resolve which tester step the reviewer was pointed at.
102
+ describe('openTestEvidence', () => {
103
+ it('opens the tester step that actually reported, not the first one', () => {
104
+ execution.hydrate(
105
+ [
106
+ instance('e1', 'b1', [
107
+ { agentKind: 'coder' },
108
+ { agentKind: 'tester-api' },
109
+ { agentKind: 'tester-ui', test: { lastReport: { greenlight: true } } },
110
+ ]),
111
+ ],
112
+ 'ws1',
113
+ )
114
+
115
+ ui.openTestEvidence('e1')
116
+
117
+ expect(ui.resultView).toMatchObject({ view: 'tester', instanceId: 'e1', stepIndex: 2 })
118
+ })
119
+
120
+ it('still opens a tester step that has not reported, rather than going nowhere', () => {
121
+ execution.hydrate([instance('e1', 'b1', [{ agentKind: 'tester-api' }])], 'ws1')
122
+
123
+ ui.openTestEvidence('e1')
124
+
125
+ expect(ui.resultView).toMatchObject({ view: 'tester', stepIndex: 0 })
126
+ })
127
+
128
+ it('does nothing when the run carries no tester step at all', () => {
129
+ execution.hydrate([instance('e1', 'b1', [{ agentKind: 'coder' }])], 'ws1')
130
+
131
+ ui.openTestEvidence('e1')
132
+
133
+ expect(ui.resultView).toBeNull()
134
+ expect(ui.stepDetail).toBeNull()
135
+ })
136
+ })
99
137
  })
@@ -578,6 +578,7 @@
578
578
  "storedAt": "Zuletzt gesetzt am {date}",
579
579
  "notStoredWithFallback": "Für dieses Board ist nichts gespeichert. Diese Installation liest den Schlüssel auch aus ihrer eigenen Umgebung, die Fähigkeit funktioniert also möglicherweise trotzdem.",
580
580
  "notStored": "Für dieses Board ist nichts gespeichert, und diese Installation hat keinen Rückfallwert aus der Umgebung. Die Fähigkeit kann sich daher nicht authentifizieren.",
581
+ "notStoredUnknownFallback": "Für dieses Board ist nichts gespeichert. Die Kette der Anmeldedaten dieser Installation lässt sich hier nicht beschreiben, daher ist nicht bekannt, ob der Schlüssel anderswo beantwortet wird.",
581
582
  "setValue": "Wert",
582
583
  "replaceValue": "Gespeicherten Wert ersetzen",
583
584
  "save": "Speichern",
@@ -2951,6 +2951,7 @@
2951
2951
  "storedAt": "Last set {date}",
2952
2952
  "notStoredWithFallback": "Nothing stored for this board. This deployment also reads the key from its own environment, so the capability may still be working.",
2953
2953
  "notStored": "Nothing stored for this board, and this deployment has no environment fallback, so the capability cannot authenticate.",
2954
+ "notStoredUnknownFallback": "Nothing stored for this board. This deployment's credential chain cannot be described here, so whether this key is answered elsewhere is not known.",
2954
2955
  "setValue": "Value",
2955
2956
  "replaceValue": "Replace the stored value",
2956
2957
  "save": "Save",
@@ -2719,6 +2719,7 @@
2719
2719
  "storedAt": "Definida por última vez el {date}",
2720
2720
  "notStoredWithFallback": "No hay nada guardado para este tablero. Esta instalación también lee la clave de su propio entorno, así que la capacidad puede seguir funcionando.",
2721
2721
  "notStored": "No hay nada guardado para este tablero y esta instalación no tiene respaldo en el entorno, así que la capacidad no puede autenticarse.",
2722
+ "notStoredUnknownFallback": "No hay nada guardado para este tablero. La cadena de credenciales de esta instalación no se puede describir aquí, así que no se sabe si la clave se responde en otro sitio.",
2722
2723
  "setValue": "Valor",
2723
2724
  "replaceValue": "Sustituir el valor guardado",
2724
2725
  "save": "Guardar",
@@ -2719,6 +2719,7 @@
2719
2719
  "storedAt": "Défini le {date}",
2720
2720
  "notStoredWithFallback": "Rien n'est enregistré pour ce tableau. Ce déploiement lit aussi la clé dans son propre environnement, la capacité fonctionne donc peut-être encore.",
2721
2721
  "notStored": "Rien n'est enregistré pour ce tableau et ce déploiement n'a pas de valeur de repli dans l'environnement : la capacité ne peut pas s'authentifier.",
2722
+ "notStoredUnknownFallback": "Rien n'est enregistré pour ce tableau. La chaîne d'identifiants de ce déploiement ne peut pas être décrite ici : on ne sait donc pas si la clé est fournie ailleurs.",
2722
2723
  "setValue": "Valeur",
2723
2724
  "replaceValue": "Remplacer la valeur enregistrée",
2724
2725
  "save": "Enregistrer",
@@ -2859,6 +2859,7 @@
2859
2859
  "storedAt": "הוגדר לאחרונה ב-{date}",
2860
2860
  "notStoredWithFallback": "לא נשמר דבר עבור הלוח הזה. הפריסה הזו קוראת את המפתח גם מהסביבה שלה, ולכן ייתכן שהיכולת עדיין פועלת.",
2861
2861
  "notStored": "לא נשמר דבר עבור הלוח הזה, ולפריסה הזו אין נפילה לסביבה, ולכן היכולת אינה יכולה לבצע אימות.",
2862
+ "notStoredUnknownFallback": "לא נשמר דבר עבור הלוח הזה. לא ניתן לתאר כאן את שרשרת האישורים של הפריסה הזו, ולכן לא ידוע אם המפתח נענה במקום אחר.",
2862
2863
  "setValue": "ערך",
2863
2864
  "replaceValue": "החלפת הערך השמור",
2864
2865
  "save": "שמירה",
@@ -578,6 +578,7 @@
578
578
  "storedAt": "Impostata l'ultima volta il {date}",
579
579
  "notStoredWithFallback": "Per questa board non è salvato nulla. Questo deployment legge la chiave anche dal proprio ambiente, quindi la capacità potrebbe funzionare comunque.",
580
580
  "notStored": "Per questa board non è salvato nulla e questo deployment non ha un ripiego sull'ambiente, quindi la capacità non può autenticarsi.",
581
+ "notStoredUnknownFallback": "Per questa board non è salvato nulla. La catena di credenziali di questo deployment non può essere descritta qui, quindi non si sa se la chiave venga fornita altrove.",
581
582
  "setValue": "Valore",
582
583
  "replaceValue": "Sostituisci il valore salvato",
583
584
  "save": "Salva",
@@ -2860,6 +2860,7 @@
2860
2860
  "storedAt": "最終設定: {date}",
2861
2861
  "notStoredWithFallback": "このボードには何も保存されていません。このデプロイは自身の環境からもこのキーを読み取るため、機能は動作している可能性があります。",
2862
2862
  "notStored": "このボードには何も保存されておらず、このデプロイには環境からのフォールバックもないため、機能は認証できません。",
2863
+ "notStoredUnknownFallback": "このボードには何も保存されていません。このデプロイの資格情報チェーンはここでは説明できないため、このキーが別の場所で解決されるかどうかは分かりません。",
2863
2864
  "setValue": "値",
2864
2865
  "replaceValue": "保存済みの値を置き換える",
2865
2866
  "save": "保存",
@@ -2719,6 +2719,7 @@
2719
2719
  "storedAt": "Ostatnio ustawione {date}",
2720
2720
  "notStoredWithFallback": "Dla tej tablicy nic nie jest zapisane. To wdrożenie odczytuje klucz również z własnego środowiska, więc funkcja może nadal działać.",
2721
2721
  "notStored": "Dla tej tablicy nic nie jest zapisane, a to wdrożenie nie ma awaryjnego odczytu ze środowiska, więc funkcja nie może się uwierzytelnić.",
2722
+ "notStoredUnknownFallback": "Dla tej tablicy nic nie jest zapisane. Łańcucha poświadczeń tego wdrożenia nie można tutaj opisać, więc nie wiadomo, czy klucz jest obsługiwany gdzie indziej.",
2722
2723
  "setValue": "Wartość",
2723
2724
  "replaceValue": "Zastąp zapisaną wartość",
2724
2725
  "save": "Zapisz",
@@ -2860,6 +2860,7 @@
2860
2860
  "storedAt": "Son ayarlanma: {date}",
2861
2861
  "notStoredWithFallback": "Bu pano için hiçbir şey saklanmıyor. Bu kurulum anahtarı kendi ortamından da okuyor, dolayısıyla yetenek hâlâ çalışıyor olabilir.",
2862
2862
  "notStored": "Bu pano için hiçbir şey saklanmıyor ve bu kurulumun ortam yedeği yok, dolayısıyla yetenek kimlik doğrulaması yapamaz.",
2863
+ "notStoredUnknownFallback": "Bu pano için hiçbir şey saklanmıyor. Bu kurulumun kimlik bilgisi zinciri burada tanımlanamıyor, dolayısıyla anahtarın başka bir yerden karşılanıp karşılanmadığı bilinmiyor.",
2863
2864
  "setValue": "Değer",
2864
2865
  "replaceValue": "Saklanan değeri değiştir",
2865
2866
  "save": "Kaydet",
@@ -2719,6 +2719,7 @@
2719
2719
  "storedAt": "Востаннє задано {date}",
2720
2720
  "notStoredWithFallback": "Для цієї дошки нічого не збережено. Це розгортання також читає ключ із власного середовища, тож можливість може й далі працювати.",
2721
2721
  "notStored": "Для цієї дошки нічого не збережено, а запасного читання із середовища в цьому розгортанні немає, тож можливість не зможе пройти автентифікацію.",
2722
+ "notStoredUnknownFallback": "Для цієї дошки нічого не збережено. Ланцюг облікових даних цього розгортання неможливо описати тут, тож невідомо, чи ключ надається деінде.",
2722
2723
  "setValue": "Значення",
2723
2724
  "replaceValue": "Замінити збережене значення",
2724
2725
  "save": "Зберегти",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.209.0",
3
+ "version": "0.210.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.217.0"
43
+ "@cat-factory/contracts": "0.219.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@toad-contracts/testing": "0.3.2",