@cat-factory/app 0.297.0 → 0.299.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/app/components/panels/inspector/ServiceSelfTests.vue +1 -0
- package/app/composables/api/environments.ts +13 -3
- package/app/composables/usePipelineErrorToast.ts +9 -0
- package/app/stores/brainstorm.ts +9 -2
- package/app/stores/clarity.ts +9 -2
- package/app/stores/consensus.ts +7 -2
- package/app/stores/docInterview.ts +3 -1
- package/app/stores/environmentTest.spec.ts +43 -1
- package/app/stores/environmentTest.ts +25 -5
- package/app/stores/initiative.ts +4 -1
- package/app/stores/notifications.ts +2 -13
- package/app/stores/perKeyWrites.spec.ts +168 -0
- package/app/stores/requirements/recommendations.ts +25 -0
- package/app/stores/requirements.spec.ts +89 -1
- package/app/stores/requirements.ts +24 -19
- package/i18n/locales/de.json +3 -1
- package/i18n/locales/en.json +3 -1
- package/i18n/locales/es.json +3 -1
- package/i18n/locales/fr.json +3 -1
- package/i18n/locales/he.json +3 -1
- package/i18n/locales/it.json +3 -1
- package/i18n/locales/ja.json +3 -1
- package/i18n/locales/pl.json +3 -1
- package/i18n/locales/tr.json +3 -1
- package/i18n/locales/uk.json +3 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1091,9 +1091,23 @@ event left to restore it.
|
|
|
1091
1091
|
swaps that in. A missing trigger and an in-place patch are both SILENT, so
|
|
1092
1092
|
`stores/execution.spec.ts` pins each write shape twice: once on the array, once through the
|
|
1093
1093
|
`getInstance` chain a window actually reads.
|
|
1094
|
+
- **A record keyed by block id is written PER KEY, never replaced.** The review-family caches
|
|
1095
|
+
(`requirements`, `clarity`, `brainstorm`, `consensus`, `docInterview`, `initiative`) are deep
|
|
1096
|
+
reactive refs holding a `Record<blockId, T>`, so `x.value = { ...x.value, [id]: v }` is a write
|
|
1097
|
+
to the REF: a dependency every reader shares, whatever key it reads. One review event therefore
|
|
1098
|
+
woke every card on the board. `x.value[id] = v` keeps the invalidation on the key that changed,
|
|
1099
|
+
and Vue still tracks a key read before it exists, so a first write reaches its waiting reader.
|
|
1100
|
+
The exception is a HYDRATE, which replaces the record wholesale on purpose: a snapshot is
|
|
1101
|
+
authoritative for EXISTENCE, so anything it omits has been deleted. This is the opposite rule
|
|
1102
|
+
from `execution.instances` above, and for the opposite reason: that one is a `shallowRef`.
|
|
1094
1103
|
- **Pin it with a store-level unit test** (`stores/workspace.spec.ts` for refreshes,
|
|
1095
1104
|
`stores/workspace/refreshFunnel.spec.ts` for the funnel's own rules, `stores/execution.spec.ts`
|
|
1096
|
-
for echoes): drive the two orderings and assert the fresher one wins.
|
|
1105
|
+
for echoes): drive the two orderings and assert the fresher one wins. The per-key rule above has
|
|
1106
|
+
one table for the whole family, `stores/perKeyWrites.spec.ts`: a store joining it is a row there,
|
|
1107
|
+
and each row counts a `computed`'s evaluations across an event for a DIFFERENT block, plus the
|
|
1108
|
+
first write to a key a reader read while it was absent. What the record is keyed BY is per store
|
|
1109
|
+
(`stores/requirements.spec.ts` also covers the stage read, whose pending-recommendation half has
|
|
1110
|
+
to answer off the block's own review object rather than a computed over the record).
|
|
1097
1111
|
|
|
1098
1112
|
## Internationalization (i18n) authoring
|
|
1099
1113
|
|
|
@@ -117,6 +117,7 @@ const CONFLICT_KEYS: Record<Extract<ConflictReason, `env_test_${string}`>, strin
|
|
|
117
117
|
env_test_no_vcs: 'errors.conflict.title.env_test_no_vcs',
|
|
118
118
|
env_test_connection_failed: 'errors.conflict.title.env_test_connection_failed',
|
|
119
119
|
env_test_probe_unavailable: 'errors.conflict.title.env_test_probe_unavailable',
|
|
120
|
+
env_test_probe_model_unavailable: 'errors.conflict.title.env_test_probe_model_unavailable',
|
|
120
121
|
env_test_already_running: 'errors.conflict.title.env_test_already_running',
|
|
121
122
|
env_test_over_budget: 'errors.conflict.title.env_test_over_budget',
|
|
122
123
|
}
|
|
@@ -9,7 +9,7 @@ import type { EnvironmentTestMode, ProvisionEnvironmentInput } from '@cat-factor
|
|
|
9
9
|
import type { ApiContext } from './context'
|
|
10
10
|
|
|
11
11
|
/** Ephemeral environments: the workspace's live env handles (used to resolve frontend bindings). */
|
|
12
|
-
export function environmentsApi({ send, ws }: ApiContext) {
|
|
12
|
+
export function environmentsApi({ send, sendWith, ws, pwHeaders }: ApiContext) {
|
|
13
13
|
return {
|
|
14
14
|
listEnvironments: (workspaceId: string) =>
|
|
15
15
|
send(listEnvironmentsContract, { pathPrefix: ws(workspaceId) }),
|
|
@@ -22,8 +22,18 @@ export function environmentsApi({ send, ws }: ApiContext) {
|
|
|
22
22
|
// Ephemeral-environment self-test: start a full create-branch → provision → tear-down →
|
|
23
23
|
// delete-branch cycle against a service frame, then read / stop its run. `mode` picks what it
|
|
24
24
|
// exercises: the provisioning alone, or that plus an agent dry run against the environment.
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
//
|
|
26
|
+
// Carries the personal unlock password, because an `agent-probe` run spends a model call and
|
|
27
|
+
// the model comes from the workspace's preset, which can name a personal subscription
|
|
28
|
+
// (Claude). The backend only consults it when the resolved model needs one, so a provisioning
|
|
29
|
+
// self-test is unaffected.
|
|
30
|
+
startEnvironmentTest: (
|
|
31
|
+
workspaceId: string,
|
|
32
|
+
blockId: string,
|
|
33
|
+
mode: EnvironmentTestMode,
|
|
34
|
+
password?: string,
|
|
35
|
+
) =>
|
|
36
|
+
sendWith(pwHeaders(password), startEnvironmentTestContract, {
|
|
27
37
|
pathPrefix: ws(workspaceId),
|
|
28
38
|
pathParams: { blockId },
|
|
29
39
|
body: { mode },
|
|
@@ -277,6 +277,15 @@ const CONFLICT_INFO: Record<Exclude<ConflictReason, BespokeConflictReason>, Conf
|
|
|
277
277
|
titleKey: 'errors.conflict.title.env_test_probe_unavailable',
|
|
278
278
|
descriptionKey: 'errors.conflict.description.env_test_probe_unavailable',
|
|
279
279
|
},
|
|
280
|
+
// The frame's RESOLVED model cannot be dispatched: a provider the LLM proxy cannot serve, or a
|
|
281
|
+
// subscription-only model with no connected credential. Distinct from the reason above, whose
|
|
282
|
+
// gap is a container prerequisite: this deployment is wired and the workspace's own model preset
|
|
283
|
+
// names something unrunnable, so the remedy is in the model settings and the jump is worth
|
|
284
|
+
// offering. The specific cause rides `details.modelIssue`, which the funnel surfaces as detail.
|
|
285
|
+
env_test_probe_model_unavailable: {
|
|
286
|
+
titleKey: 'errors.conflict.title.env_test_probe_model_unavailable',
|
|
287
|
+
descriptionKey: 'errors.conflict.description.env_test_probe_model_unavailable',
|
|
288
|
+
},
|
|
280
289
|
// A second self-test on a frame that already has one running. No ACTION: the remedy is to wait
|
|
281
290
|
// for the run showing in the same panel, or to stop it with the button beside it.
|
|
282
291
|
env_test_already_running: {
|
package/app/stores/brainstorm.ts
CHANGED
|
@@ -80,8 +80,13 @@ export const useBrainstormStore = defineStore('brainstorm', () => {
|
|
|
80
80
|
return allSettled(session) && answeredCount(session) === 0
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Write one block+stage session into the cache, IN PLACE: per-key, never a whole-record clone.
|
|
85
|
+
* `sessions` is a deep reactive ref, so replacing the record retriggered every consumer keyed on
|
|
86
|
+
* an UNCHANGED key; assigning the key retriggers only the session that actually changed.
|
|
87
|
+
*/
|
|
83
88
|
function store(session: BrainstormSession) {
|
|
84
|
-
sessions.value
|
|
89
|
+
sessions.value[key(session.blockId, session.stage)] = session
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/** Patch the cache from a live `brainstorm` stream event (newest wins per block+stage). */
|
|
@@ -122,7 +127,9 @@ export const useBrainstormStore = defineStore('brainstorm', () => {
|
|
|
122
127
|
try {
|
|
123
128
|
const session = await api.getBrainstorm(workspace.requireId(), blockId, stage)
|
|
124
129
|
available.value = true
|
|
125
|
-
|
|
130
|
+
// By key like `store()`, and directly because a load resolving to "none exists" caches a
|
|
131
|
+
// null the getter reads as "fetched, absent".
|
|
132
|
+
sessions.value[k] = session
|
|
126
133
|
} catch {
|
|
127
134
|
available.value = false
|
|
128
135
|
} finally {
|
package/app/stores/clarity.ts
CHANGED
|
@@ -83,8 +83,13 @@ export const useClarityStore = defineStore('clarity', () => {
|
|
|
83
83
|
return allSettled(review) && answeredCount(review) === 0
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Write one block's review into the cache, IN PLACE: per-key, never a whole-record clone.
|
|
88
|
+
* `reviews` is a deep reactive ref, so replacing the record retriggered every consumer keyed on
|
|
89
|
+
* an UNCHANGED block; assigning the key retriggers only the block that actually changed.
|
|
90
|
+
*/
|
|
86
91
|
function store(review: ClarityReview) {
|
|
87
|
-
reviews.value
|
|
92
|
+
reviews.value[review.blockId] = review
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
/** Patch the cache from a live `clarity` stream event (newest wins per block). */
|
|
@@ -125,7 +130,9 @@ export const useClarityStore = defineStore('clarity', () => {
|
|
|
125
130
|
try {
|
|
126
131
|
const review = await api.getClarityReview(workspace.requireId(), blockId)
|
|
127
132
|
available.value = true
|
|
128
|
-
|
|
133
|
+
// By key like `store()`, and directly because a load resolving to "none exists" caches a
|
|
134
|
+
// null the getter reads as "fetched, absent".
|
|
135
|
+
reviews.value[blockId] = review
|
|
129
136
|
} catch {
|
|
130
137
|
// 503 (feature off) or any error → hide the UI entry points.
|
|
131
138
|
available.value = false
|
package/app/stores/consensus.ts
CHANGED
|
@@ -30,8 +30,13 @@ export const useConsensusStore = defineStore('consensus', () => {
|
|
|
30
30
|
return loading.value.has(blockId)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Write one block's session into the cache, IN PLACE: per-key, never a whole-record clone.
|
|
35
|
+
* `sessions` is a deep reactive ref, so replacing the record retriggered every consumer keyed on
|
|
36
|
+
* an UNCHANGED block; assigning the key retriggers only the block that actually changed.
|
|
37
|
+
*/
|
|
33
38
|
function store(session: ConsensusSession) {
|
|
34
|
-
sessions.value
|
|
39
|
+
sessions.value[session.blockId] = session
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/** Patch the cache from a live `consensus` stream event (newest wins per block). */
|
|
@@ -62,7 +67,7 @@ export const useConsensusStore = defineStore('consensus', () => {
|
|
|
62
67
|
if (session) {
|
|
63
68
|
if (!existing || session.updatedAt >= existing.updatedAt) store(session)
|
|
64
69
|
} else if (existing === undefined) {
|
|
65
|
-
sessions.value
|
|
70
|
+
sessions.value[blockId] = null
|
|
66
71
|
}
|
|
67
72
|
} catch {
|
|
68
73
|
// Consensus off / no session — leave the cache as-is; the window shows its empty state.
|
|
@@ -30,7 +30,9 @@ export const useDocInterviewStore = defineStore('docInterview', () => {
|
|
|
30
30
|
function upsert(session: DocInterviewSession) {
|
|
31
31
|
const existing = byBlock.value[session.blockId]
|
|
32
32
|
if (existing && existing.updatedAt > session.updatedAt) return
|
|
33
|
-
byBlock
|
|
33
|
+
// Per-key, never a whole-record clone: `byBlock` is a deep reactive ref, so replacing the
|
|
34
|
+
// record retriggered every consumer keyed on an UNCHANGED block.
|
|
35
|
+
byBlock.value[session.blockId] = session
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/** Re-fetch one block's session (the interview window's load path). */
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
2
|
import type { EnvironmentTestRun } from '~/types/domain'
|
|
3
3
|
import { useEnvironmentTestStore } from '~/stores/environmentTest'
|
|
4
|
+
import { usePersonalSubscriptionsStore } from '~/stores/personalSubscriptions'
|
|
5
|
+
import { useWorkspaceStore } from '~/stores/workspace'
|
|
4
6
|
|
|
5
7
|
// The store resolves `useApi()` at setup; override the inert global stub from
|
|
6
8
|
// `test/setup.ts` with a per-suite mock so the hydrate reconcile point-read is observable.
|
|
7
|
-
const apiMock = { getEnvironmentTest: vi.fn() }
|
|
9
|
+
const apiMock = { getEnvironmentTest: vi.fn(), startEnvironmentTest: vi.fn() }
|
|
8
10
|
vi.stubGlobal('useApi', () => apiMock)
|
|
9
11
|
|
|
10
12
|
/** Minimal EnvironmentTestRun factory — only the fields the store's reconcile logic touches. */
|
|
@@ -28,6 +30,46 @@ function run(id: string, over: Partial<EnvironmentTestRun> = {}): EnvironmentTes
|
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
describe('environmentTest store: starting a run that may need a personal credential', () => {
|
|
34
|
+
let store: ReturnType<typeof useEnvironmentTestStore>
|
|
35
|
+
let withCredential: ReturnType<typeof vi.fn>
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
useWorkspaceStore().workspaceId = 'ws_test'
|
|
39
|
+
// The gate's contract, stubbed on the real store: run the action with the cached password, and
|
|
40
|
+
// resolve `false` when the person cancels the unlock prompt.
|
|
41
|
+
withCredential = vi.fn(async (action: (password?: string) => Promise<void>) => {
|
|
42
|
+
await action('cached-password')
|
|
43
|
+
return true
|
|
44
|
+
})
|
|
45
|
+
usePersonalSubscriptionsStore().withCredential = withCredential as unknown as ReturnType<
|
|
46
|
+
typeof usePersonalSubscriptionsStore
|
|
47
|
+
>['withCredential']
|
|
48
|
+
apiMock.startEnvironmentTest = vi.fn(async () => run('envtest_1', { mode: 'agent-probe' }))
|
|
49
|
+
store = useEnvironmentTestStore()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('rides the unlock password, so a preset-resolved Claude dry run can lease it', async () => {
|
|
53
|
+
// Ungated, an `agent-probe` start 428s and the person is never asked for anything: the
|
|
54
|
+
// failure they see is a dry run that provisioned an environment and then could not open a
|
|
55
|
+
// credential nobody unlocked.
|
|
56
|
+
const started = await store.start('blk_1', 'agent-probe')
|
|
57
|
+
expect(apiMock.startEnvironmentTest).toHaveBeenCalledWith(
|
|
58
|
+
'ws_test',
|
|
59
|
+
'blk_1',
|
|
60
|
+
'agent-probe',
|
|
61
|
+
'cached-password',
|
|
62
|
+
)
|
|
63
|
+
expect(started?.id).toBe('envtest_1')
|
|
64
|
+
expect(store.runById('envtest_1')).toBeTruthy()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('reports a cancelled unlock as no run, so the caller stops waiting for one', async () => {
|
|
68
|
+
withCredential.mockImplementation(async () => false)
|
|
69
|
+
expect(await store.start('blk_1', 'agent-probe')).toBeNull()
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
31
73
|
describe('environmentTest store — monotonic run reconcile', () => {
|
|
32
74
|
let store: ReturnType<typeof useEnvironmentTestStore>
|
|
33
75
|
beforeEach(() => {
|
|
@@ -3,6 +3,7 @@ import { ref } from 'vue'
|
|
|
3
3
|
import type { EnvironmentTestMode } from '@cat-factory/contracts'
|
|
4
4
|
import type { EnvironmentTestRun } from '~/types/domain'
|
|
5
5
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
6
|
+
import { usePersonalSubscriptionsStore } from '~/stores/personalSubscriptions'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Ephemeral-environment self-test runs, in both modes: the provisioning self-test and the AGENT
|
|
@@ -129,12 +130,31 @@ export const useEnvironmentTestStore = defineStore('environmentTest', () => {
|
|
|
129
130
|
return runs.value.find((r) => r.blockId === blockId && r.mode === mode)
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
/**
|
|
133
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Start a self-test against a service frame; the returned run is tracked immediately.
|
|
135
|
+
*
|
|
136
|
+
* Gated through `withCredential`, like every other surface that starts agent work: an AGENT DRY
|
|
137
|
+
* RUN resolves its model from the workspace's model preset, which can name an individual-usage
|
|
138
|
+
* subscription (Claude), and such a credential is only leasable with the owner's unlock
|
|
139
|
+
* password. The cached password rides the first attempt and a `428` opens the modal; the
|
|
140
|
+
* provisioning self-test spends no model call, so the backend never consults it there.
|
|
141
|
+
*
|
|
142
|
+
* `null` when the person cancels the prompt: the run never started, so the caller reverts its
|
|
143
|
+
* spinner rather than waiting for a run that is not coming.
|
|
144
|
+
*/
|
|
145
|
+
async function start(
|
|
146
|
+
blockId: string,
|
|
147
|
+
mode: EnvironmentTestMode,
|
|
148
|
+
): Promise<EnvironmentTestRun | null> {
|
|
134
149
|
const ws = useWorkspaceStore()
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
const personal = usePersonalSubscriptionsStore()
|
|
151
|
+
let started: EnvironmentTestRun | null = null
|
|
152
|
+
const ok = await personal.withCredential(async (password) => {
|
|
153
|
+
const run = await api.startEnvironmentTest(ws.requireId(), blockId, mode, password)
|
|
154
|
+
upsert(run)
|
|
155
|
+
started = run
|
|
156
|
+
})
|
|
157
|
+
return ok ? started : null
|
|
138
158
|
}
|
|
139
159
|
|
|
140
160
|
/** Stop a running self-test (best-effort cleanup, then failed). */
|
package/app/stores/initiative.ts
CHANGED
|
@@ -96,7 +96,10 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
96
96
|
function upsert(initiative: Initiative) {
|
|
97
97
|
const existing = byBlock.value[initiative.blockId]
|
|
98
98
|
if (existing && existing.rev > initiative.rev) return
|
|
99
|
-
byBlock
|
|
99
|
+
// Per-key, never a whole-record clone: `byBlock` is a deep reactive ref, so replacing the
|
|
100
|
+
// record retriggered every consumer keyed on an UNCHANGED block. {@link hydrate} still
|
|
101
|
+
// replaces it wholesale, because a snapshot is authoritative for EXISTENCE.
|
|
102
|
+
byBlock.value[initiative.blockId] = initiative
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
/**
|
|
@@ -16,8 +16,8 @@ import { useWorkspaceStore } from '~/stores/workspace'
|
|
|
16
16
|
* Open, human-actionable notifications surfaced on the board (a PR awaiting a
|
|
17
17
|
* merge decision, a completed pipeline awaiting confirmation, CI that gave up).
|
|
18
18
|
* Hydrated from the workspace snapshot and patched live by the `notification`
|
|
19
|
-
* WorkspaceEvent (see `useWorkspaceStream`). The board renders an inbox
|
|
20
|
-
* per-block
|
|
19
|
+
* WorkspaceEvent (see `useWorkspaceStream`). The board renders an inbox from `open`, and the
|
|
20
|
+
* per-block review-wait stamps the swimlanes need from {@link reviewDebtByBlock}.
|
|
21
21
|
*/
|
|
22
22
|
export const useNotificationsStore = defineStore('notifications', () => {
|
|
23
23
|
const api = useApi()
|
|
@@ -110,16 +110,6 @@ export const useNotificationsStore = defineStore('notifications', () => {
|
|
|
110
110
|
upsertOpen(notification)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/** Open notifications for a given block (for the board card badge). */
|
|
114
|
-
const byBlock = computed<Record<string, Notification[]>>(() => {
|
|
115
|
-
const map: Record<string, Notification[]> = {}
|
|
116
|
-
for (const n of open.value) {
|
|
117
|
-
if (!n.blockId) continue
|
|
118
|
-
;(map[n.blockId] ??= []).push(n)
|
|
119
|
-
}
|
|
120
|
-
return map
|
|
121
|
-
})
|
|
122
|
-
|
|
123
113
|
/**
|
|
124
114
|
* Per-block "waiting since", derived from the open review-wait cards by the same
|
|
125
115
|
* `collectReviewDebt` the backend's friction check uses. It is the fallback source for the park
|
|
@@ -213,7 +203,6 @@ export const useNotificationsStore = defineStore('notifications', () => {
|
|
|
213
203
|
hydrate,
|
|
214
204
|
hydrateBaseline,
|
|
215
205
|
upsert,
|
|
216
|
-
byBlock,
|
|
217
206
|
reviewDebtByBlock,
|
|
218
207
|
count,
|
|
219
208
|
act,
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { BrainstormSession } from '~/types/brainstorm'
|
|
4
|
+
import type { ClarityReview } from '~/types/clarity'
|
|
5
|
+
import type { ConsensusSession } from '~/types/consensus'
|
|
6
|
+
import type { DocInterviewSession, Initiative } from '~/types/domain'
|
|
7
|
+
import type { RequirementReview } from '~/types/requirements'
|
|
8
|
+
import { useBrainstormStore } from '~/stores/brainstorm'
|
|
9
|
+
import { useClarityStore } from '~/stores/clarity'
|
|
10
|
+
import { useConsensusStore } from '~/stores/consensus'
|
|
11
|
+
import { useDocInterviewStore } from '~/stores/docInterview'
|
|
12
|
+
import { useInitiativesStore } from '~/stores/initiative'
|
|
13
|
+
import { useRequirementsStore } from '~/stores/requirements'
|
|
14
|
+
|
|
15
|
+
// The review-family stores all hold a `Record<blockId, T>` in a DEEP reactive ref and all patch it
|
|
16
|
+
// from a live stream event. `x.value = { ...x.value, [id]: v }` is a write to the REF, a dependency
|
|
17
|
+
// every reader shares whatever key it reads, so one event woke every card on the board;
|
|
18
|
+
// `x.value[id] = v` keeps the invalidation on the key that changed. The rule is stated once in
|
|
19
|
+
// `frontend/app/README.md` ("A record keyed by block id is written PER KEY, never replaced").
|
|
20
|
+
//
|
|
21
|
+
// One table rather than six near-identical specs, because the property is one property and a store
|
|
22
|
+
// that JOINS this family should have exactly one obvious place to be added. Each row asserts the
|
|
23
|
+
// two halves that can regress independently: an event for another block does not invalidate this
|
|
24
|
+
// block's reader, and a FIRST write still reaches a reader that read the key while it was absent
|
|
25
|
+
// (Vue tracks a missing-key read, which is what makes the in-place write safe at all).
|
|
26
|
+
|
|
27
|
+
interface StoreCase {
|
|
28
|
+
name: string
|
|
29
|
+
/** Patch the store from a live event for `blockId`, tagged with `mark` so the read can see it. */
|
|
30
|
+
write: (blockId: string, mark: string) => void
|
|
31
|
+
/** What a card renders off that block: the tag, or null when the store holds nothing. */
|
|
32
|
+
read: (blockId: string) => string | null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const cases: StoreCase[] = [
|
|
36
|
+
{
|
|
37
|
+
name: 'requirements',
|
|
38
|
+
write: (blockId, mark) => {
|
|
39
|
+
useRequirementsStore().upsert({
|
|
40
|
+
id: mark,
|
|
41
|
+
blockId,
|
|
42
|
+
status: 'ready',
|
|
43
|
+
iteration: 1,
|
|
44
|
+
maxIterations: 3,
|
|
45
|
+
items: [],
|
|
46
|
+
updatedAt: 1,
|
|
47
|
+
} as unknown as RequirementReview)
|
|
48
|
+
},
|
|
49
|
+
read: (blockId) => useRequirementsStore().reviewFor(blockId)?.id ?? null,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'clarity',
|
|
53
|
+
write: (blockId, mark) => {
|
|
54
|
+
useClarityStore().upsert({
|
|
55
|
+
id: mark,
|
|
56
|
+
blockId,
|
|
57
|
+
status: 'ready',
|
|
58
|
+
items: [],
|
|
59
|
+
updatedAt: 1,
|
|
60
|
+
} as unknown as ClarityReview)
|
|
61
|
+
},
|
|
62
|
+
read: (blockId) => useClarityStore().reviewFor(blockId)?.id ?? null,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'brainstorm',
|
|
66
|
+
// Keyed by block+STAGE, so a block legitimately holds one live session per stage; the
|
|
67
|
+
// invalidation still has to land on the one composite key that changed.
|
|
68
|
+
write: (blockId, mark) => {
|
|
69
|
+
useBrainstormStore().upsert({
|
|
70
|
+
id: mark,
|
|
71
|
+
blockId,
|
|
72
|
+
stage: 'requirements',
|
|
73
|
+
status: 'ready',
|
|
74
|
+
options: [],
|
|
75
|
+
updatedAt: 1,
|
|
76
|
+
} as unknown as BrainstormSession)
|
|
77
|
+
},
|
|
78
|
+
read: (blockId) => useBrainstormStore().sessionFor(blockId, 'requirements')?.id ?? null,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'consensus',
|
|
82
|
+
write: (blockId, mark) => {
|
|
83
|
+
useConsensusStore().upsert({
|
|
84
|
+
id: mark,
|
|
85
|
+
blockId,
|
|
86
|
+
status: 'complete',
|
|
87
|
+
participants: [],
|
|
88
|
+
rounds: [],
|
|
89
|
+
synthesis: null,
|
|
90
|
+
createdAt: 1,
|
|
91
|
+
updatedAt: 1,
|
|
92
|
+
} as unknown as ConsensusSession)
|
|
93
|
+
},
|
|
94
|
+
read: (blockId) => useConsensusStore().sessionFor(blockId)?.id ?? null,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'docInterview',
|
|
98
|
+
write: (blockId, mark) => {
|
|
99
|
+
useDocInterviewStore().upsert({
|
|
100
|
+
id: mark,
|
|
101
|
+
blockId,
|
|
102
|
+
status: 'awaiting_answers',
|
|
103
|
+
round: 1,
|
|
104
|
+
maxRounds: 3,
|
|
105
|
+
qa: [],
|
|
106
|
+
createdAt: 1,
|
|
107
|
+
updatedAt: 1,
|
|
108
|
+
} as unknown as DocInterviewSession)
|
|
109
|
+
},
|
|
110
|
+
read: (blockId) => useDocInterviewStore().forBlock(blockId)?.id ?? null,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'initiative',
|
|
114
|
+
write: (blockId, mark) => {
|
|
115
|
+
useInitiativesStore().upsert({
|
|
116
|
+
id: mark,
|
|
117
|
+
blockId,
|
|
118
|
+
slug: 'i',
|
|
119
|
+
title: 'I',
|
|
120
|
+
rev: 1,
|
|
121
|
+
} as unknown as Initiative)
|
|
122
|
+
},
|
|
123
|
+
read: (blockId) => useInitiativesStore().forBlock(blockId)?.id ?? null,
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
describe.each(cases)('$name store per-key writes', ({ write, read }) => {
|
|
128
|
+
it('an event for one block does not invalidate a consumer reading another', () => {
|
|
129
|
+
write('blk-a', 'a1')
|
|
130
|
+
|
|
131
|
+
let evaluations = 0
|
|
132
|
+
const forA = computed(() => {
|
|
133
|
+
evaluations++
|
|
134
|
+
return read('blk-a')
|
|
135
|
+
})
|
|
136
|
+
expect(forA.value).toBe('a1')
|
|
137
|
+
expect(evaluations).toBe(1)
|
|
138
|
+
|
|
139
|
+
// A brand-new key, then a rewrite of that existing one: neither is about `blk-a`.
|
|
140
|
+
write('blk-b', 'b1')
|
|
141
|
+
expect(forA.value).toBe('a1')
|
|
142
|
+
write('blk-b', 'b2')
|
|
143
|
+
expect(forA.value).toBe('a1')
|
|
144
|
+
expect(evaluations).toBe(1)
|
|
145
|
+
|
|
146
|
+
// The block's OWN event still reaches it.
|
|
147
|
+
write('blk-a', 'a2')
|
|
148
|
+
expect(forA.value).toBe('a2')
|
|
149
|
+
expect(evaluations).toBe(2)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('a FIRST write reaches a reader that read the key while it was absent', () => {
|
|
153
|
+
// The half an in-place write could plausibly lose: the reader tracked a key that did not
|
|
154
|
+
// exist. Vue tracks a missing-key read, so ADDING the key notifies it. Without this the
|
|
155
|
+
// window a card opens before its first event would render its empty state forever.
|
|
156
|
+
let evaluations = 0
|
|
157
|
+
const forC = computed(() => {
|
|
158
|
+
evaluations++
|
|
159
|
+
return read('blk-c')
|
|
160
|
+
})
|
|
161
|
+
expect(forC.value).toBeNull()
|
|
162
|
+
expect(evaluations).toBe(1)
|
|
163
|
+
|
|
164
|
+
write('blk-c', 'c1')
|
|
165
|
+
expect(forC.value).toBe('c1')
|
|
166
|
+
expect(evaluations).toBe(2)
|
|
167
|
+
})
|
|
168
|
+
})
|
|
@@ -20,6 +20,31 @@ export interface RecommendationCommandContext {
|
|
|
20
20
|
hasPendingRecommendations: (blockId: string) => boolean
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Whether the Requirement Writer is still producing recommendations for THIS review: a `pending`
|
|
25
|
+
* placeholder exists. Server-derived, so the "Recommending…" state survives the window closing
|
|
26
|
+
* and a page reload; the client-local `recommending` set only covers the request round-trip.
|
|
27
|
+
*
|
|
28
|
+
* Memoised on the review OBJECT, like the settlement tallies next door, and for the same reason:
|
|
29
|
+
* the store REPLACES the review on every write, so identity self-invalidates and a superseded
|
|
30
|
+
* review is collected along with its answer.
|
|
31
|
+
*
|
|
32
|
+
* Per REVIEW rather than per record, which is the whole point. `backgroundStage` asks this on the
|
|
33
|
+
* per-CARD path, and a `computed` over the `reviews` record tracks the ref plus every key in it,
|
|
34
|
+
* so one review event would re-evaluate every card's stage, the fan-out the per-key write exists
|
|
35
|
+
* to remove. Reading one key depends on one key.
|
|
36
|
+
*/
|
|
37
|
+
const pendingByReview = new WeakMap<RequirementReview, boolean>()
|
|
38
|
+
|
|
39
|
+
export function awaitsRecommendations(review: RequirementReview): boolean {
|
|
40
|
+
let pending = pendingByReview.get(review)
|
|
41
|
+
if (pending === undefined) {
|
|
42
|
+
pending = (review.recommendations ?? []).some((r) => r.status === 'pending')
|
|
43
|
+
pendingByReview.set(review, pending)
|
|
44
|
+
}
|
|
45
|
+
return pending
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
/** Ask for, accept, reject and re-request the Requirement Writer's suggested answers. */
|
|
24
49
|
export function createRecommendationCommands(ctx: RecommendationCommandContext) {
|
|
25
50
|
const { api, workspace, recommending, withFlag, store, hasPendingRecommendations } = ctx
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
2
|
-
import
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { RequirementRecommendation, RequirementReview } from '~/types/requirements'
|
|
3
4
|
import { useRequirementsStore } from '~/stores/requirements'
|
|
4
5
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
5
6
|
|
|
@@ -18,6 +19,20 @@ function review(over: Partial<RequirementReview> = {}): RequirementReview {
|
|
|
18
19
|
} as RequirementReview
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** A `pending` Writer placeholder: the state `backgroundStage` reads as "recommending". */
|
|
23
|
+
function pendingRecommendation(id: string): RequirementRecommendation {
|
|
24
|
+
return {
|
|
25
|
+
id,
|
|
26
|
+
sourceFinding: { title: 'f', detail: 'd', itemId: 'i1' },
|
|
27
|
+
recommendedText: '',
|
|
28
|
+
status: 'pending',
|
|
29
|
+
note: null,
|
|
30
|
+
groundedInFragment: null,
|
|
31
|
+
createdAt: 1,
|
|
32
|
+
updatedAt: 1,
|
|
33
|
+
} as RequirementRecommendation
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
describe('requirements store load() loading flag', () => {
|
|
22
37
|
beforeEach(() => {
|
|
23
38
|
// The store resolves its workspace id from the workspace store at call time.
|
|
@@ -113,3 +128,76 @@ describe('requirements store live-event upsert guard', () => {
|
|
|
113
128
|
expect(store.reviewFor('b1')?.id).toBe('rr2')
|
|
114
129
|
})
|
|
115
130
|
})
|
|
131
|
+
|
|
132
|
+
describe('requirements store per-key writes', () => {
|
|
133
|
+
it('an event for one block does not invalidate a consumer reading another', () => {
|
|
134
|
+
// Every card on the board reads its OWN block's review (the "Recommending…"/gate badge), so
|
|
135
|
+
// one review event used to wake every card: the store replaced the whole record, which is a
|
|
136
|
+
// write to the ref itself and therefore a dependency every reader shares. Writing the key
|
|
137
|
+
// keeps the invalidation on the block that changed.
|
|
138
|
+
const store = useRequirementsStore()
|
|
139
|
+
store.upsert(review({ id: 'rr-a', blockId: 'blk-a', updatedAt: 1 }))
|
|
140
|
+
|
|
141
|
+
let evaluations = 0
|
|
142
|
+
const forA = computed(() => {
|
|
143
|
+
evaluations++
|
|
144
|
+
return store.reviewFor('blk-a')?.id ?? null
|
|
145
|
+
})
|
|
146
|
+
expect(forA.value).toBe('rr-a')
|
|
147
|
+
expect(evaluations).toBe(1)
|
|
148
|
+
|
|
149
|
+
// A brand-new key, then a rewrite of an existing one: neither is about `blk-a`.
|
|
150
|
+
store.upsert(review({ id: 'rr-b', blockId: 'blk-b', updatedAt: 1 }))
|
|
151
|
+
expect(forA.value).toBe('rr-a')
|
|
152
|
+
store.upsert(review({ id: 'rr-b', blockId: 'blk-b', updatedAt: 2 }))
|
|
153
|
+
expect(forA.value).toBe('rr-a')
|
|
154
|
+
expect(evaluations).toBe(1)
|
|
155
|
+
|
|
156
|
+
// The block's OWN event still reaches it.
|
|
157
|
+
store.upsert(review({ id: 'rr-a2', blockId: 'blk-a', updatedAt: 2 }))
|
|
158
|
+
expect(forA.value).toBe('rr-a2')
|
|
159
|
+
expect(evaluations).toBe(2)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('the per-card STAGE read depends on one block too, pending recommendations included', () => {
|
|
163
|
+
// `backgroundStage` is the read every card actually makes (TaskCard/BlockNode via
|
|
164
|
+
// `useReviewStage`), and it is the one the per-key write alone does not fix: while the pending
|
|
165
|
+
// -recommendation answer came from a `computed` over the whole `reviews` record, that computed
|
|
166
|
+
// tracked every key, so one event still re-evaluated the stage of every card on the board.
|
|
167
|
+
// Answering off the block's own review object is what closes it.
|
|
168
|
+
const store = useRequirementsStore()
|
|
169
|
+
store.upsert(review({ id: 'rr-a', blockId: 'blk-a', updatedAt: 1 }))
|
|
170
|
+
|
|
171
|
+
let evaluations = 0
|
|
172
|
+
const stageForA = computed(() => {
|
|
173
|
+
evaluations++
|
|
174
|
+
return store.backgroundStage('blk-a')
|
|
175
|
+
})
|
|
176
|
+
expect(stageForA.value).toBeNull()
|
|
177
|
+
expect(evaluations).toBe(1)
|
|
178
|
+
|
|
179
|
+
// Another block starts recommending: not this card's business.
|
|
180
|
+
store.upsert(
|
|
181
|
+
review({
|
|
182
|
+
id: 'rr-b',
|
|
183
|
+
blockId: 'blk-b',
|
|
184
|
+
updatedAt: 1,
|
|
185
|
+
recommendations: [pendingRecommendation('rec-1')],
|
|
186
|
+
}),
|
|
187
|
+
)
|
|
188
|
+
expect(stageForA.value).toBeNull()
|
|
189
|
+
expect(evaluations).toBe(1)
|
|
190
|
+
|
|
191
|
+
// This block's own placeholder still surfaces the working state.
|
|
192
|
+
store.upsert(
|
|
193
|
+
review({
|
|
194
|
+
id: 'rr-a2',
|
|
195
|
+
blockId: 'blk-a',
|
|
196
|
+
updatedAt: 2,
|
|
197
|
+
recommendations: [pendingRecommendation('rec-2')],
|
|
198
|
+
}),
|
|
199
|
+
)
|
|
200
|
+
expect(stageForA.value).toBe('recommending')
|
|
201
|
+
expect(evaluations).toBe(2)
|
|
202
|
+
})
|
|
203
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
|
-
import {
|
|
2
|
+
import { ref } from 'vue'
|
|
3
3
|
import type {
|
|
4
4
|
RequirementReview,
|
|
5
5
|
ResolveRequirementsExceededChoice,
|
|
@@ -16,7 +16,10 @@ import {
|
|
|
16
16
|
canProceed,
|
|
17
17
|
openCount,
|
|
18
18
|
} from '~/stores/requirements/settlement'
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
awaitsRecommendations,
|
|
21
|
+
createRecommendationCommands,
|
|
22
|
+
} from '~/stores/requirements/recommendations'
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Requirements-review state. On the pipeline path the reviewer runs as the first gate
|
|
@@ -55,24 +58,16 @@ export const useRequirementsStore = defineStore('requirements', () => {
|
|
|
55
58
|
function reviewFor(blockId: string): RequirementReview | null {
|
|
56
59
|
return reviews.value[blockId] ?? null
|
|
57
60
|
}
|
|
58
|
-
/** Whether the Requirement Writer is still producing recommendations for a block (a `pending`
|
|
59
|
-
* placeholder exists). Server-derived, so the "Recommending…" state survives the window closing
|
|
60
|
-
* and a page reload — the client-local `recommending` set only covers the request round-trip. */
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
62
|
+
* Whether the Requirement Writer is still producing recommendations for a block. Reads ONE key
|
|
63
|
+
* and answers off the review object itself ({@link awaitsRecommendations} memoises the scan on
|
|
64
|
+
* that object), so a card asking about its own block depends only on its own block. A `computed`
|
|
65
|
+
* over the whole record would be the fan-out again: it tracks every key, so one review event
|
|
66
|
+
* would re-evaluate the stage of every card on the board.
|
|
66
67
|
*/
|
|
67
|
-
const blocksAwaitingRecommendations = computed(() => {
|
|
68
|
-
const blocks = new Set<string>()
|
|
69
|
-
for (const [blockId, review] of Object.entries(reviews.value)) {
|
|
70
|
-
if ((review?.recommendations ?? []).some((r) => r.status === 'pending')) blocks.add(blockId)
|
|
71
|
-
}
|
|
72
|
-
return blocks
|
|
73
|
-
})
|
|
74
68
|
function hasPendingRecommendations(blockId: string): boolean {
|
|
75
|
-
|
|
69
|
+
const review = reviews.value[blockId]
|
|
70
|
+
return review ? awaitsRecommendations(review) : false
|
|
76
71
|
}
|
|
77
72
|
/**
|
|
78
73
|
* The async background stage a block's review is in, or null. While the driver folds the
|
|
@@ -96,8 +91,16 @@ export const useRequirementsStore = defineStore('requirements', () => {
|
|
|
96
91
|
return incorporating.value.has(reviewId)
|
|
97
92
|
}
|
|
98
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Write one block's review into the cache, IN PLACE.
|
|
96
|
+
*
|
|
97
|
+
* Per-key, never a whole-record clone: `reviews` is a deep reactive ref, so a consumer reading
|
|
98
|
+
* `reviews[someBlockId]` depends on THAT key. Replacing the record retriggered every one of
|
|
99
|
+
* them (a card, a badge, an inspector panel for an untouched block) on every event; assigning
|
|
100
|
+
* the key retriggers only the consumers of the block that actually changed.
|
|
101
|
+
*/
|
|
99
102
|
function store(review: RequirementReview) {
|
|
100
|
-
reviews.value
|
|
103
|
+
reviews.value[review.blockId] = review
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
/** Patch the cache from a live `requirements` stream event (newest wins per block). */
|
|
@@ -139,7 +142,9 @@ export const useRequirementsStore = defineStore('requirements', () => {
|
|
|
139
142
|
try {
|
|
140
143
|
const review = await api.getRequirementReview(workspace.requireId(), blockId)
|
|
141
144
|
available.value = true
|
|
142
|
-
|
|
145
|
+
// Written by key like `store()`, and directly because a load resolving to "none exists"
|
|
146
|
+
// caches a null the getter reads as "fetched, absent".
|
|
147
|
+
reviews.value[blockId] = review
|
|
143
148
|
} catch {
|
|
144
149
|
// 503 (feature off) or any error → hide the UI entry points.
|
|
145
150
|
available.value = false
|
package/i18n/locales/de.json
CHANGED
|
@@ -6200,6 +6200,7 @@
|
|
|
6200
6200
|
"env_test_no_vcs": "Git-Anbieter nicht verbunden",
|
|
6201
6201
|
"env_test_connection_failed": "Umgebungsverbindung fehlgeschlagen",
|
|
6202
6202
|
"env_test_probe_unavailable": "Agenten-Probeläufe hier nicht verfügbar",
|
|
6203
|
+
"env_test_probe_model_unavailable": "Modell für den Probelauf nicht ausführbar",
|
|
6203
6204
|
"env_test_already_running": "Selbsttest läuft bereits",
|
|
6204
6205
|
"env_test_over_budget": "Ausgabenbudget erreicht",
|
|
6205
6206
|
"prompt_revision_conflict": "Prompt von jemand anderem geändert",
|
|
@@ -6251,7 +6252,8 @@
|
|
|
6251
6252
|
"env_test_no_vcs": "Der Selbsttest benötigt einen Git-Anbieter, um seinen Wegwerf-Branch zu erstellen und zu löschen, aber dieser Workspace ist mit keinem verbunden.",
|
|
6252
6253
|
"env_test_connection_failed": "Der Umgebungs-Handler dieses Dienstes hat seinen Verbindungstest nicht bestanden. Prüfen Sie Endpunkt, Anmeldedaten und Projekteinstellungen und testen Sie die Verbindung erneut.",
|
|
6253
6254
|
"env_test_connection_failed_detail": "Der Umgebungs-Handler dieses Dienstes hat seinen Verbindungstest nicht bestanden: {detail}. Prüfen Sie Endpunkt, Anmeldedaten und Projekteinstellungen und testen Sie die Verbindung erneut.",
|
|
6254
|
-
"env_test_probe_unavailable": "Ein Agenten-Probelauf benötigt einen Container-Runner
|
|
6255
|
+
"env_test_probe_unavailable": "Ein Agenten-Probelauf benötigt einen Container-Runner und ein verbundenes Repository. Hier fehlt eines davon, daher lässt sich nur der Bereitstellungs-Selbsttest ausführen.",
|
|
6256
|
+
"env_test_probe_model_unavailable": "Der Probelauf dieses Dienstes verweist auf ein Modell, das diese Installation nicht ausführen kann: entweder kann der LLM-Proxy dessen Anbieter nicht bedienen, oder es braucht ein Abonnement, das niemand verbunden hat. Ändern Sie das Modell-Preset für den Prüfagenten (oder das am Rahmen fixierte Modell), oder verbinden Sie das Abonnement. Der Bereitstellungs-Selbsttest braucht kein Modell und läuft weiterhin.",
|
|
6255
6257
|
"env_test_already_running": "Für diesen Dienst läuft bereits ein Selbsttest. Jeder stellt seine eigene Wegwerf-Umgebung bereit, daher läuft immer nur einer. Warten Sie, bis er fertig ist, oder stoppen Sie ihn zuerst.",
|
|
6256
6258
|
"env_test_over_budget": "Ein Agenten-Probelauf ist ein kostenpflichtiger Modellaufruf, und dieser Workspace hat sein Ausgabenbudget erreicht. Erhöhen Sie das Budget oder warten Sie auf den nächsten Abrechnungszeitraum. Der Bereitstellungs-Selbsttest kostet nichts und läuft weiterhin.",
|
|
6257
6259
|
"prompt_revision_conflict": "Eine andere Änderung an diesem Prompt war zuerst da. Laden Sie ihn neu und wenden Sie Ihre Änderung darauf erneut an.",
|
package/i18n/locales/en.json
CHANGED
|
@@ -767,6 +767,7 @@
|
|
|
767
767
|
"env_test_no_vcs": "Git provider not connected",
|
|
768
768
|
"env_test_connection_failed": "Environment connection failed",
|
|
769
769
|
"env_test_probe_unavailable": "Agent dry runs not available here",
|
|
770
|
+
"env_test_probe_model_unavailable": "Dry run model cannot run",
|
|
770
771
|
"env_test_already_running": "Self-test already running",
|
|
771
772
|
"env_test_over_budget": "Spend budget reached",
|
|
772
773
|
"prompt_revision_conflict": "Prompt changed by someone else",
|
|
@@ -818,7 +819,8 @@
|
|
|
818
819
|
"env_test_no_vcs": "The self-test needs a git provider to create and delete its throwaway branch, but this workspace isn't connected to one.",
|
|
819
820
|
"env_test_connection_failed": "The environment handler for this service failed its connection test. Check its endpoint, credentials and project settings, then re-test the connection.",
|
|
820
821
|
"env_test_connection_failed_detail": "The environment handler for this service failed its connection test: {detail}. Check its endpoint, credentials and project settings, then re-test the connection.",
|
|
821
|
-
"env_test_probe_unavailable": "An agent dry run needs a container runner
|
|
822
|
+
"env_test_probe_unavailable": "An agent dry run needs a container runner and a connected repository. One of them is missing here, so only the provisioning self-test can run.",
|
|
823
|
+
"env_test_probe_model_unavailable": "This service's dry run resolves to a model this deployment cannot dispatch: either the LLM proxy cannot serve its provider, or it needs a subscription no one has connected. Change the model preset for the prober (or the frame's own pinned model), or connect the subscription. The provisioning self-test needs no model and still runs.",
|
|
822
824
|
"env_test_already_running": "A self-test is already running for this service. Each one provisions its own throwaway environment, so only one runs at a time. Wait for it to finish, or stop it first.",
|
|
823
825
|
"env_test_over_budget": "An agent dry run is a billable model call, and this workspace has reached a spend budget. Raise the budget or wait for the billing period to reset. The provisioning self-test costs nothing and still runs.",
|
|
824
826
|
"@env_test_connection_failed_detail": {
|
package/i18n/locales/es.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Proveedor de Git no conectado",
|
|
690
690
|
"env_test_connection_failed": "Fallo de conexión del entorno",
|
|
691
691
|
"env_test_probe_unavailable": "Las ejecuciones en seco del agente no están disponibles aquí",
|
|
692
|
+
"env_test_probe_model_unavailable": "El modelo del ensayo no puede ejecutarse",
|
|
692
693
|
"env_test_already_running": "Ya hay una autoprueba en curso",
|
|
693
694
|
"env_test_over_budget": "Presupuesto de gasto alcanzado",
|
|
694
695
|
"prompt_revision_conflict": "Otra persona cambió el prompt",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "La autoprueba necesita un proveedor de Git para crear y eliminar su rama desechable, pero este espacio de trabajo no está conectado a ninguno.",
|
|
741
742
|
"env_test_connection_failed": "El gestor de entornos de este servicio no superó su prueba de conexión. Revisa su endpoint, sus credenciales y la configuración del proyecto, y vuelve a probar la conexión.",
|
|
742
743
|
"env_test_connection_failed_detail": "El gestor de entornos de este servicio no superó su prueba de conexión: {detail}. Revisa su endpoint, sus credenciales y la configuración del proyecto, y vuelve a probar la conexión.",
|
|
743
|
-
"env_test_probe_unavailable": "Una ejecución en seco del agente necesita un ejecutor de contenedores
|
|
744
|
+
"env_test_probe_unavailable": "Una ejecución en seco del agente necesita un ejecutor de contenedores y un repositorio conectado. Aquí falta uno de ellos, así que solo puede ejecutarse la autoprueba de aprovisionamiento.",
|
|
745
|
+
"env_test_probe_model_unavailable": "El ensayo de este servicio resuelve a un modelo que este despliegue no puede lanzar: o el proxy de LLM no puede atender a su proveedor, o necesita una suscripción que nadie ha conectado. Cambie el preajuste de modelo del sondeador (o el modelo fijado en el marco), o conecte la suscripción. La autoprueba de aprovisionamiento no necesita modelo y sigue funcionando.",
|
|
744
746
|
"env_test_already_running": "Ya se está ejecutando una autoprueba para este servicio. Cada una aprovisiona su propio entorno desechable, así que solo se ejecuta una a la vez. Espera a que termine o deténla primero.",
|
|
745
747
|
"env_test_over_budget": "Una prueba de agente es una llamada de modelo facturable y este espacio de trabajo ha alcanzado su presupuesto de gasto. Aumenta el presupuesto o espera al siguiente periodo de facturación. La autoprueba de aprovisionamiento no cuesta nada y sigue funcionando.",
|
|
746
748
|
"prompt_revision_conflict": "Otra edición de este prompt llegó primero. Recárgalo y vuelve a aplicar tu cambio encima.",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Fournisseur Git non connecté",
|
|
690
690
|
"env_test_connection_failed": "Échec de la connexion à l'environnement",
|
|
691
691
|
"env_test_probe_unavailable": "Essais à blanc d'agent indisponibles ici",
|
|
692
|
+
"env_test_probe_model_unavailable": "Le modèle du test à blanc ne peut pas être exécuté",
|
|
692
693
|
"env_test_already_running": "Auto-test déjà en cours",
|
|
693
694
|
"env_test_over_budget": "Budget de dépenses atteint",
|
|
694
695
|
"prompt_revision_conflict": "Invite modifiée par quelqu'un d'autre",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "L'auto-test a besoin d'un fournisseur Git pour créer et supprimer sa branche jetable, mais cet espace de travail n'est connecté à aucun.",
|
|
741
742
|
"env_test_connection_failed": "Le gestionnaire d'environnement de ce service a échoué à son test de connexion. Vérifiez son point de terminaison, ses identifiants et les paramètres du projet, puis retestez la connexion.",
|
|
742
743
|
"env_test_connection_failed_detail": "Le gestionnaire d'environnement de ce service a échoué à son test de connexion : {detail}. Vérifiez son point de terminaison, ses identifiants et les paramètres du projet, puis retestez la connexion.",
|
|
743
|
-
"env_test_probe_unavailable": "Un essai à blanc d'agent nécessite un exécuteur de conteneurs
|
|
744
|
+
"env_test_probe_unavailable": "Un essai à blanc d'agent nécessite un exécuteur de conteneurs et un dépôt connecté. L'un d'eux manque ici, donc seul l'autotest de provisionnement peut s'exécuter.",
|
|
745
|
+
"env_test_probe_model_unavailable": "Le test à blanc de ce service pointe vers un modèle que ce déploiement ne peut pas lancer : soit le proxy LLM ne prend pas en charge son fournisseur, soit il faut un abonnement que personne n'a connecté. Changez le préréglage de modèle du sondeur (ou le modèle épinglé sur le cadre), ou connectez l'abonnement. L'autotest de provisionnement n'a besoin d'aucun modèle et continue de fonctionner.",
|
|
744
746
|
"env_test_already_running": "Un auto-test est déjà en cours pour ce service. Chacun provisionne son propre environnement jetable, donc un seul s'exécute à la fois. Attendez qu'il se termine ou arrêtez-le d'abord.",
|
|
745
747
|
"env_test_over_budget": "Un essai à blanc d'agent est un appel de modèle facturé, et cet espace de travail a atteint son budget de dépenses. Augmentez le budget ou attendez la prochaine période de facturation. L'auto-test de provisionnement ne coûte rien et reste disponible.",
|
|
746
748
|
"prompt_revision_conflict": "Une autre modification de cette invite est arrivée en premier. Rechargez-la et réappliquez la vôtre par-dessus.",
|
package/i18n/locales/he.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "ספק Git אינו מחובר",
|
|
690
690
|
"env_test_connection_failed": "החיבור לסביבה נכשל",
|
|
691
691
|
"env_test_probe_unavailable": "הרצות יבשות של סוכן אינן זמינות כאן",
|
|
692
|
+
"env_test_probe_model_unavailable": "לא ניתן להריץ את המודל של הרצת היובש",
|
|
692
693
|
"env_test_already_running": "בדיקה עצמית כבר פועלת",
|
|
693
694
|
"env_test_over_budget": "הגעתם לתקרת התקציב",
|
|
694
695
|
"prompt_revision_conflict": "ההנחיה שונתה על ידי מישהו אחר",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "הבדיקה העצמית זקוקה לספק Git כדי ליצור ולמחוק את הענף החד-פעמי שלה, אך סביבת עבודה זו אינה מחוברת לאף אחד.",
|
|
741
742
|
"env_test_connection_failed": "מנהל הסביבה של שירות זה נכשל בבדיקת החיבור. בדקו את נקודת הקצה, פרטי ההזדהות והגדרות הפרויקט, ולאחר מכן בדקו שוב את החיבור.",
|
|
742
743
|
"env_test_connection_failed_detail": "מנהל הסביבה של שירות זה נכשל בבדיקת החיבור: {detail}. בדקו את נקודת הקצה, פרטי ההזדהות והגדרות הפרויקט, ולאחר מכן בדקו שוב את החיבור.",
|
|
743
|
-
"env_test_probe_unavailable": "הרצה יבשה של סוכן דורשת מריץ
|
|
744
|
+
"env_test_probe_unavailable": "הרצה יבשה של סוכן דורשת מריץ קונטיינרים ומאגר מחובר. כאן חסר אחד מהם, ולכן אפשר להריץ רק את הבדיקה העצמית של הקמת הסביבה.",
|
|
745
|
+
"env_test_probe_model_unavailable": "הרצת היובש של השירות הזה מפנה למודל שהפריסה הזאת אינה יכולה להריץ: או שפרוקסי ה-LLM אינו מסוגל לשרת את הספק שלו, או שנדרש מנוי שאף אחד לא חיבר. שנו את פריסט המודל של הבודק (או את המודל המוצמד למסגרת), או חברו את המנוי. הבדיקה העצמית של ההקצאה אינה זקוקה למודל וממשיכה לרוץ.",
|
|
744
746
|
"env_test_already_running": "בדיקה עצמית כבר פועלת עבור שירות זה. כל בדיקה מקצה סביבה זמנית משלה, ולכן רק אחת פועלת בכל רגע. המתינו לסיומה או עצרו אותה תחילה.",
|
|
745
747
|
"env_test_over_budget": "הרצת ניסיון של סוכן היא קריאת מודל בתשלום, וסביבת העבודה הזו הגיעה לתקרת התקציב. הגדילו את התקציב או המתינו לתקופת החיוב הבאה. הבדיקה העצמית של ההקצאה אינה עולה דבר וממשיכה לפעול.",
|
|
746
748
|
"prompt_revision_conflict": "עריכה אחרת של ההנחיה הזו נקלטה קודם. טענו אותה מחדש והחילו את השינוי שלכם מעליה.",
|
package/i18n/locales/it.json
CHANGED
|
@@ -6200,6 +6200,7 @@
|
|
|
6200
6200
|
"env_test_no_vcs": "Provider Git non connesso",
|
|
6201
6201
|
"env_test_connection_failed": "Connessione all'ambiente non riuscita",
|
|
6202
6202
|
"env_test_probe_unavailable": "Prove a vuoto dell'agente non disponibili qui",
|
|
6203
|
+
"env_test_probe_model_unavailable": "Il modello della prova a vuoto non è eseguibile",
|
|
6203
6204
|
"env_test_already_running": "Autotest già in esecuzione",
|
|
6204
6205
|
"env_test_over_budget": "Budget di spesa raggiunto",
|
|
6205
6206
|
"prompt_revision_conflict": "Prompt modificato da qualcun altro",
|
|
@@ -6251,7 +6252,8 @@
|
|
|
6251
6252
|
"env_test_no_vcs": "L'autotest ha bisogno di un provider Git per creare ed eliminare il suo branch usa e getta, ma questo workspace non è collegato a nessuno.",
|
|
6252
6253
|
"env_test_connection_failed": "Il gestore dell'ambiente di questo servizio non ha superato il test di connessione. Controlla endpoint, credenziali e impostazioni del progetto, poi ripeti il test della connessione.",
|
|
6253
6254
|
"env_test_connection_failed_detail": "Il gestore dell'ambiente di questo servizio non ha superato il test di connessione: {detail}. Controlla endpoint, credenziali e impostazioni del progetto, poi ripeti il test della connessione.",
|
|
6254
|
-
"env_test_probe_unavailable": "Una prova a vuoto dell’agente richiede un runner di container
|
|
6255
|
+
"env_test_probe_unavailable": "Una prova a vuoto dell’agente richiede un runner di container e un repository collegato. Qui ne manca uno, quindi può essere eseguito solo l’autotest di provisioning.",
|
|
6256
|
+
"env_test_probe_model_unavailable": "La prova a vuoto di questo servizio punta a un modello che questa installazione non può avviare: il proxy LLM non supporta il suo provider, oppure serve un abbonamento che nessuno ha collegato. Cambia il preset del modello per il sondatore (o il modello fissato sul riquadro), oppure collega l’abbonamento. L’autotest di provisioning non richiede alcun modello e continua a funzionare.",
|
|
6255
6257
|
"env_test_already_running": "È già in esecuzione un autotest per questo servizio. Ognuno effettua il provisioning del proprio ambiente temporaneo, quindi ne viene eseguito uno alla volta. Attendi che finisca oppure interrompilo.",
|
|
6256
6258
|
"env_test_over_budget": "Una prova a vuoto dell'agente è una chiamata al modello a pagamento e questo workspace ha raggiunto il budget di spesa. Aumenta il budget o attendi il prossimo periodo di fatturazione. L'autotest di provisioning non ha costi e resta disponibile.",
|
|
6257
6259
|
"prompt_revision_conflict": "Un'altra modifica a questo prompt è arrivata prima. Ricaricalo e riapplica la tua sopra.",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Git プロバイダーが未接続です",
|
|
690
690
|
"env_test_connection_failed": "環境への接続に失敗しました",
|
|
691
691
|
"env_test_probe_unavailable": "ここではエージェントのドライランを利用できません",
|
|
692
|
+
"env_test_probe_model_unavailable": "ドライランのモデルを実行できません",
|
|
692
693
|
"env_test_already_running": "セルフテストは既に実行中です",
|
|
693
694
|
"env_test_over_budget": "利用予算の上限に達しました",
|
|
694
695
|
"prompt_revision_conflict": "別のユーザーがプロンプトを変更しました",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "セルフテストは使い捨てブランチの作成と削除のために Git プロバイダーを必要としますが、このワークスペースはいずれにも接続されていません。",
|
|
741
742
|
"env_test_connection_failed": "このサービスの環境ハンドラーが接続テストに失敗しました。エンドポイント、認証情報、プロジェクト設定を確認してから、接続を再テストしてください。",
|
|
742
743
|
"env_test_connection_failed_detail": "このサービスの環境ハンドラーが接続テストに失敗しました: {detail}。エンドポイント、認証情報、プロジェクト設定を確認してから、接続を再テストしてください。",
|
|
743
|
-
"env_test_probe_unavailable": "
|
|
744
|
+
"env_test_probe_unavailable": "エージェントのドライランには、コンテナーランナーと接続済みのリポジトリが必要です。いずれかが欠けているため、ここではプロビジョニングの自己テストのみ実行できます。",
|
|
745
|
+
"env_test_probe_model_unavailable": "このサービスのドライランは、このデプロイでは実行できないモデルに解決されます。LLM プロキシがそのプロバイダーに対応していないか、誰も接続していないサブスクリプションが必要です。プローブ用のモデルプリセット(またはフレームに固定されたモデル)を変更するか、サブスクリプションを接続してください。プロビジョニングのセルフテストはモデルを必要とせず、引き続き実行できます。",
|
|
744
746
|
"env_test_already_running": "このサービスではすでにセルフテストが実行中です。各テストは独自の使い捨て環境をプロビジョニングするため、同時に実行できるのは 1 つだけです。終了を待つか、先に停止してください。",
|
|
745
747
|
"env_test_over_budget": "エージェントのドライランは課金対象のモデル呼び出しであり、このワークスペースは利用予算の上限に達しています。予算を引き上げるか、次の請求期間までお待ちください。プロビジョニングのセルフテストは無料で、引き続き実行できます。",
|
|
746
748
|
"prompt_revision_conflict": "このプロンプトへの別の編集が先に反映されました。読み込み直して、その上に変更をやり直してください。",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Dostawca Git nie jest połączony",
|
|
690
690
|
"env_test_connection_failed": "Połączenie ze środowiskiem nie powiodło się",
|
|
691
691
|
"env_test_probe_unavailable": "Próbne przebiegi agenta są tu niedostępne",
|
|
692
|
+
"env_test_probe_model_unavailable": "Nie można uruchomić modelu próbnego przebiegu",
|
|
692
693
|
"env_test_already_running": "Autotest już trwa",
|
|
693
694
|
"env_test_over_budget": "Osiągnięto limit wydatków",
|
|
694
695
|
"prompt_revision_conflict": "Prompt zmieniony przez kogoś innego",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "Autotest potrzebuje dostawcy Git, aby utworzyć i usunąć swoją jednorazową gałąź, ale ta przestrzeń robocza nie jest połączona z żadnym.",
|
|
741
742
|
"env_test_connection_failed": "Obsługa środowiska dla tej usługi nie przeszła testu połączenia. Sprawdź jej punkt końcowy, poświadczenia i ustawienia projektu, a następnie ponownie przetestuj połączenie.",
|
|
742
743
|
"env_test_connection_failed_detail": "Obsługa środowiska dla tej usługi nie przeszła testu połączenia: {detail}. Sprawdź jej punkt końcowy, poświadczenia i ustawienia projektu, a następnie ponownie przetestuj połączenie.",
|
|
743
|
-
"env_test_probe_unavailable": "Próbny przebieg agenta wymaga runnera kontenerów
|
|
744
|
+
"env_test_probe_unavailable": "Próbny przebieg agenta wymaga runnera kontenerów i podłączonego repozytorium. Brakuje tu jednego z nich, więc można uruchomić tylko autotest przydzielania środowiska.",
|
|
745
|
+
"env_test_probe_model_unavailable": "Próbny przebieg tej usługi wskazuje model, którego to wdrożenie nie może uruchomić: albo proxy LLM nie obsługuje jego dostawcy, albo potrzebna jest subskrypcja, której nikt nie podłączył. Zmień preset modelu dla sondy (lub model przypięty do ramki) albo podłącz subskrypcję. Autotest udostępniania nie potrzebuje modelu i nadal działa.",
|
|
744
746
|
"env_test_already_running": "Dla tej usługi już trwa autotest. Każdy z nich udostępnia własne środowisko jednorazowe, więc naraz działa tylko jeden. Poczekaj na zakończenie albo najpierw go zatrzymaj.",
|
|
745
747
|
"env_test_over_budget": "Próbny przebieg agenta to płatne wywołanie modelu, a ten obszar roboczy osiągnął limit wydatków. Zwiększ limit albo poczekaj na nowy okres rozliczeniowy. Autotest aprowizacji nic nie kosztuje i nadal działa.",
|
|
746
748
|
"prompt_revision_conflict": "Inna zmiana tego promptu trafiła pierwsza. Wczytaj go ponownie i nanieś swoją zmianę na wierzch.",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Git sağlayıcısı bağlı değil",
|
|
690
690
|
"env_test_connection_failed": "Ortam bağlantısı başarısız",
|
|
691
691
|
"env_test_probe_unavailable": "Aracı prova çalışmaları burada kullanılamıyor",
|
|
692
|
+
"env_test_probe_model_unavailable": "Prova çalıştırmasının modeli çalıştırılamıyor",
|
|
692
693
|
"env_test_already_running": "Kendi kendine test zaten çalışıyor",
|
|
693
694
|
"env_test_over_budget": "Harcama bütçesine ulaşıldı",
|
|
694
695
|
"prompt_revision_conflict": "İstem başka biri tarafından değiştirildi",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "Öz test, tek kullanımlık dalını oluşturup silmek için bir Git sağlayıcısına ihtiyaç duyar ancak bu çalışma alanı hiçbirine bağlı değil.",
|
|
741
742
|
"env_test_connection_failed": "Bu hizmetin ortam işleyicisi bağlantı testini geçemedi. Uç noktasını, kimlik bilgilerini ve proje ayarlarını kontrol edin, ardından bağlantıyı yeniden test edin.",
|
|
742
743
|
"env_test_connection_failed_detail": "Bu hizmetin ortam işleyicisi bağlantı testini geçemedi: {detail}. Uç noktasını, kimlik bilgilerini ve proje ayarlarını kontrol edin, ardından bağlantıyı yeniden test edin.",
|
|
743
|
-
"env_test_probe_unavailable": "Aracı prova çalışması bir konteyner
|
|
744
|
+
"env_test_probe_unavailable": "Aracı prova çalışması bir konteyner çalıştırıcısı ve bağlı bir depo gerektirir. Burada bunlardan biri eksik, bu yüzden yalnızca ortam hazırlama öz testi çalıştırılabilir.",
|
|
745
|
+
"env_test_probe_model_unavailable": "Bu servisin prova çalıştırması, bu kurulumun başlatamayacağı bir modele çözümleniyor: ya LLM proxy’si sağlayıcısını sunamıyor ya da kimsenin bağlamadığı bir abonelik gerekiyor. Sonda için model ön ayarını (ya da çerçeveye sabitlenmiş modeli) değiştirin veya aboneliği bağlayın. Sağlama öz testi model gerektirmez ve çalışmaya devam eder.",
|
|
744
746
|
"env_test_already_running": "Bu hizmet için zaten bir kendi kendine test çalışıyor. Her biri kendi tek kullanımlık ortamını hazırladığı için aynı anda yalnızca biri çalışır. Bitmesini bekleyin veya önce durdurun.",
|
|
745
747
|
"env_test_over_budget": "Aracı deneme çalıştırması ücretli bir model çağrısıdır ve bu çalışma alanı harcama bütçesine ulaşmıştır. Bütçeyi artırın veya yeni faturalandırma dönemini bekleyin. Sağlama kendi kendine testi ücretsizdir ve çalışmaya devam eder.",
|
|
746
748
|
"prompt_revision_conflict": "Bu isteme yapılan başka bir düzenleme önce ulaştı. Yeniden yükleyip değişikliğinizi onun üzerine uygulayın.",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -689,6 +689,7 @@
|
|
|
689
689
|
"env_test_no_vcs": "Провайдер Git не підключено",
|
|
690
690
|
"env_test_connection_failed": "Не вдалося підключитися до середовища",
|
|
691
691
|
"env_test_probe_unavailable": "Пробні запуски агента тут недоступні",
|
|
692
|
+
"env_test_probe_model_unavailable": "Модель пробного запуску неможливо запустити",
|
|
692
693
|
"env_test_already_running": "Самоперевірка вже виконується",
|
|
693
694
|
"env_test_over_budget": "Досягнуто ліміт витрат",
|
|
694
695
|
"prompt_revision_conflict": "Промпт змінив хтось інший",
|
|
@@ -740,7 +741,8 @@
|
|
|
740
741
|
"env_test_no_vcs": "Самоперевірці потрібен постачальник Git, щоб створити та видалити свою тимчасову гілку, але цей робочий простір не під'єднано до жодного.",
|
|
741
742
|
"env_test_connection_failed": "Обробник середовища для цієї служби не пройшов перевірку підключення. Перевірте його кінцеву точку, облікові дані та налаштування проєкту, а потім повторіть перевірку підключення.",
|
|
742
743
|
"env_test_connection_failed_detail": "Обробник середовища для цієї служби не пройшов перевірку підключення: {detail}. Перевірте його кінцеву точку, облікові дані та налаштування проєкту, а потім повторіть перевірку підключення.",
|
|
743
|
-
"env_test_probe_unavailable": "Пробний запуск агента потребує виконавця
|
|
744
|
+
"env_test_probe_unavailable": "Пробний запуск агента потребує виконавця контейнерів і підключеного репозиторія. Тут чогось із цього бракує, тому можна виконати лише самоперевірку створення середовища.",
|
|
745
|
+
"env_test_probe_model_unavailable": "Пробний запуск цієї служби вказує на модель, яку це розгортання не може запустити: або LLM-проксі не обслуговує її постачальника, або потрібна підписка, яку ніхто не підключив. Змініть пресет моделі для зонда (або модель, закріплену за рамкою), або підключіть підписку. Самоперевірка розгортання не потребує моделі й продовжує працювати.",
|
|
744
746
|
"env_test_already_running": "Для цієї служби вже виконується самоперевірка. Кожна створює власне тимчасове середовище, тому одночасно виконується лише одна. Дочекайтеся завершення або спершу зупиніть її.",
|
|
745
747
|
"env_test_over_budget": "Пробний запуск агента є платним викликом моделі, а цей робочий простір досяг ліміту витрат. Збільште ліміт або дочекайтеся нового платіжного періоду. Самоперевірка створення середовища нічого не коштує і працює далі.",
|
|
746
748
|
"prompt_revision_conflict": "Інша правка цього промпту надійшла першою. Перезавантажте його й накладіть свою зміну зверху.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.299.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",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@cat-factory/contracts": "0.
|
|
21
|
+
"@cat-factory/contracts": "0.349.0",
|
|
22
22
|
"@modular-frontend/core": "0.6.0",
|
|
23
23
|
"@modular-vue/core": "^1.5.0",
|
|
24
24
|
"@modular-vue/journeys": "^1.4.0",
|
|
25
25
|
"@modular-vue/nuxt": "^0.4.1",
|
|
26
26
|
"@modular-vue/runtime": "^1.4.1",
|
|
27
27
|
"@modular-vue/vue": "^1.4.1",
|
|
28
|
-
"@nuxt/ui": "^4.11.
|
|
28
|
+
"@nuxt/ui": "^4.11.1",
|
|
29
29
|
"@nuxtjs/i18n": "^10.6.0",
|
|
30
30
|
"@pinia/nuxt": "^1.0.2",
|
|
31
31
|
"@toad-contracts/core": "0.4.0",
|