@cat-factory/app 0.153.3 → 0.153.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/stores/auth/mothership.ts +108 -0
- package/app/stores/auth/session.ts +118 -0
- package/app/stores/auth.ts +17 -167
- package/app/stores/board/mutations.ts +6 -191
- package/app/stores/board/placement.ts +203 -0
- package/app/stores/board.ts +5 -1
- package/app/stores/execution/commands.ts +197 -0
- package/app/stores/execution.ts +12 -171
- package/app/stores/github/connection.ts +60 -0
- package/app/stores/github/context.ts +46 -0
- package/app/stores/github/repoActions.ts +151 -0
- package/app/stores/github.ts +30 -183
- package/app/stores/initiative/curation.ts +89 -0
- package/app/stores/initiative/planning.ts +121 -0
- package/app/stores/initiative.ts +14 -175
- package/app/stores/workspace/hydrate.ts +105 -0
- package/app/stores/workspace.ts +6 -94
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import type { Initiative } from '~/types/domain'
|
|
4
|
+
import { useWorkspaceStore } from '~/stores/workspace'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared reactive state + injected dependencies the initiatives-store action factories close
|
|
8
|
+
* over. Created once in the `initiatives` store setup and threaded into
|
|
9
|
+
* {@link createInitiativePlanningActions} / {@link createInitiativeCurationActions} so the split
|
|
10
|
+
* operations stay behaviourally identical to the original single-closure store — a size-only
|
|
11
|
+
* extraction mirroring `stores/board/` and `stores/pipelines/`, not a new seam.
|
|
12
|
+
*/
|
|
13
|
+
export interface InitiativeActionContext {
|
|
14
|
+
api: ReturnType<typeof useApi>
|
|
15
|
+
workspace: ReturnType<typeof useWorkspaceStore>
|
|
16
|
+
/** Patch an entity a call returned into the by-block cache (newest rev wins). */
|
|
17
|
+
upsert: (initiative: Initiative) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The planning-window actions: answering / dismissing the interviewer's questions, asking it to
|
|
22
|
+
* recommend an answer, and the two loop-resuming controls (continue / proceed). Owns the
|
|
23
|
+
* in-flight flags the window renders its spinners from.
|
|
24
|
+
*/
|
|
25
|
+
export function createInitiativePlanningActions(ctx: InitiativeActionContext) {
|
|
26
|
+
const { api, workspace, upsert } = ctx
|
|
27
|
+
|
|
28
|
+
/** True while a planning-window action (continue/proceed) is resuming the run. */
|
|
29
|
+
const resuming = ref(false)
|
|
30
|
+
/** Question ids the interviewer is currently drafting a recommendation for (window spinner). */
|
|
31
|
+
const recommending: Ref<Set<string>> = ref(new Set())
|
|
32
|
+
|
|
33
|
+
/** Record the human's answer to one pending interview question (no run resume). */
|
|
34
|
+
async function answerQuestion(blockId: string, questionId: string, answer: string) {
|
|
35
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
36
|
+
const updated = await api.answerInitiativeQuestion(
|
|
37
|
+
workspace.workspaceId,
|
|
38
|
+
blockId,
|
|
39
|
+
questionId,
|
|
40
|
+
answer,
|
|
41
|
+
)
|
|
42
|
+
upsert(updated)
|
|
43
|
+
return updated
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Mark a planning question not-relevant (`dismissed`) or reopen it (no run resume). */
|
|
47
|
+
async function setQuestionStatus(
|
|
48
|
+
blockId: string,
|
|
49
|
+
questionId: string,
|
|
50
|
+
status: 'open' | 'dismissed',
|
|
51
|
+
) {
|
|
52
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
53
|
+
const updated = await api.setInitiativeQuestionStatus(
|
|
54
|
+
workspace.workspaceId,
|
|
55
|
+
blockId,
|
|
56
|
+
questionId,
|
|
57
|
+
status,
|
|
58
|
+
)
|
|
59
|
+
upsert(updated)
|
|
60
|
+
return updated
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Ask the interviewer to recommend a suggested answer for one pending question. Runs the
|
|
65
|
+
* interviewer LLM inline server-side; the returned entity carries the suggestion on the question.
|
|
66
|
+
* Tracks the in-flight id so the window can show a per-question spinner.
|
|
67
|
+
*/
|
|
68
|
+
async function recommendAnswer(blockId: string, questionId: string) {
|
|
69
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
70
|
+
recommending.value = new Set(recommending.value).add(questionId)
|
|
71
|
+
try {
|
|
72
|
+
const updated = await api.recommendInitiativeAnswer(
|
|
73
|
+
workspace.workspaceId,
|
|
74
|
+
blockId,
|
|
75
|
+
questionId,
|
|
76
|
+
)
|
|
77
|
+
upsert(updated)
|
|
78
|
+
return updated
|
|
79
|
+
} finally {
|
|
80
|
+
const next = new Set(recommending.value)
|
|
81
|
+
next.delete(questionId)
|
|
82
|
+
recommending.value = next
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Submit the answers and resume the interview (the interviewer re-runs, may ask more). */
|
|
87
|
+
async function continuePlanning(blockId: string) {
|
|
88
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
89
|
+
resuming.value = true
|
|
90
|
+
try {
|
|
91
|
+
const updated = await api.continueInitiativePlanning(workspace.workspaceId, blockId)
|
|
92
|
+
upsert(updated)
|
|
93
|
+
return updated
|
|
94
|
+
} finally {
|
|
95
|
+
resuming.value = false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Skip remaining questions: the interviewer converges and the run advances. */
|
|
100
|
+
async function proceedPlanning(blockId: string) {
|
|
101
|
+
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
102
|
+
resuming.value = true
|
|
103
|
+
try {
|
|
104
|
+
const updated = await api.proceedInitiativePlanning(workspace.workspaceId, blockId)
|
|
105
|
+
upsert(updated)
|
|
106
|
+
return updated
|
|
107
|
+
} finally {
|
|
108
|
+
resuming.value = false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
resuming,
|
|
114
|
+
recommending,
|
|
115
|
+
answerQuestion,
|
|
116
|
+
setQuestionStatus,
|
|
117
|
+
recommendAnswer,
|
|
118
|
+
continuePlanning,
|
|
119
|
+
proceedPlanning,
|
|
120
|
+
}
|
|
121
|
+
}
|
package/app/stores/initiative.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
|
-
import type {
|
|
4
|
-
Initiative,
|
|
5
|
-
InitiativeExecutionPolicy,
|
|
6
|
-
InitiativePresetDescriptor,
|
|
7
|
-
InitiativePresetInputs,
|
|
8
|
-
PromoteInitiativeFollowUpInput,
|
|
9
|
-
UpdateInitiativeItemInput,
|
|
10
|
-
} from '~/types/domain'
|
|
3
|
+
import type { Initiative, InitiativePresetDescriptor, InitiativePresetInputs } from '~/types/domain'
|
|
11
4
|
|
|
12
5
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
13
6
|
import { useBoardStore } from '~/stores/board'
|
|
7
|
+
import {
|
|
8
|
+
createInitiativePlanningActions,
|
|
9
|
+
type InitiativeActionContext,
|
|
10
|
+
} from '~/stores/initiative/planning'
|
|
11
|
+
import { createInitiativeCurationActions } from '~/stores/initiative/curation'
|
|
14
12
|
|
|
15
13
|
/** The built-in generic preset id (mirrors kernel's `GENERIC_INITIATIVE_PRESET_ID`). */
|
|
16
14
|
export const GENERIC_PRESET_ID = 'preset_generic'
|
|
@@ -165,91 +163,6 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
165
163
|
}
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
/** True while a planning-window action (continue/proceed) is resuming the run. */
|
|
169
|
-
const resuming = ref(false)
|
|
170
|
-
|
|
171
|
-
/** Record the human's answer to one pending interview question (no run resume). */
|
|
172
|
-
async function answerQuestion(blockId: string, questionId: string, answer: string) {
|
|
173
|
-
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
174
|
-
const updated = await api.answerInitiativeQuestion(
|
|
175
|
-
workspace.workspaceId,
|
|
176
|
-
blockId,
|
|
177
|
-
questionId,
|
|
178
|
-
answer,
|
|
179
|
-
)
|
|
180
|
-
upsert(updated)
|
|
181
|
-
return updated
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/** Question ids the interviewer is currently drafting a recommendation for (window spinner). */
|
|
185
|
-
const recommending = ref<Set<string>>(new Set())
|
|
186
|
-
|
|
187
|
-
/** Mark a planning question not-relevant (`dismissed`) or reopen it (no run resume). */
|
|
188
|
-
async function setQuestionStatus(
|
|
189
|
-
blockId: string,
|
|
190
|
-
questionId: string,
|
|
191
|
-
status: 'open' | 'dismissed',
|
|
192
|
-
) {
|
|
193
|
-
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
194
|
-
const updated = await api.setInitiativeQuestionStatus(
|
|
195
|
-
workspace.workspaceId,
|
|
196
|
-
blockId,
|
|
197
|
-
questionId,
|
|
198
|
-
status,
|
|
199
|
-
)
|
|
200
|
-
upsert(updated)
|
|
201
|
-
return updated
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Ask the interviewer to recommend a suggested answer for one pending question. Runs the
|
|
206
|
-
* interviewer LLM inline server-side; the returned entity carries the suggestion on the question.
|
|
207
|
-
* Tracks the in-flight id so the window can show a per-question spinner.
|
|
208
|
-
*/
|
|
209
|
-
async function recommendAnswer(blockId: string, questionId: string) {
|
|
210
|
-
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
211
|
-
recommending.value = new Set(recommending.value).add(questionId)
|
|
212
|
-
try {
|
|
213
|
-
const updated = await api.recommendInitiativeAnswer(
|
|
214
|
-
workspace.workspaceId,
|
|
215
|
-
blockId,
|
|
216
|
-
questionId,
|
|
217
|
-
)
|
|
218
|
-
upsert(updated)
|
|
219
|
-
return updated
|
|
220
|
-
} finally {
|
|
221
|
-
const next = new Set(recommending.value)
|
|
222
|
-
next.delete(questionId)
|
|
223
|
-
recommending.value = next
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/** Submit the answers and resume the interview (the interviewer re-runs, may ask more). */
|
|
228
|
-
async function continuePlanning(blockId: string) {
|
|
229
|
-
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
230
|
-
resuming.value = true
|
|
231
|
-
try {
|
|
232
|
-
const updated = await api.continueInitiativePlanning(workspace.workspaceId, blockId)
|
|
233
|
-
upsert(updated)
|
|
234
|
-
return updated
|
|
235
|
-
} finally {
|
|
236
|
-
resuming.value = false
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/** Skip remaining questions: the interviewer converges and the run advances. */
|
|
241
|
-
async function proceedPlanning(blockId: string) {
|
|
242
|
-
if (!workspace.workspaceId) throw new Error('No active workspace')
|
|
243
|
-
resuming.value = true
|
|
244
|
-
try {
|
|
245
|
-
const updated = await api.proceedInitiativePlanning(workspace.workspaceId, blockId)
|
|
246
|
-
upsert(updated)
|
|
247
|
-
return updated
|
|
248
|
-
} finally {
|
|
249
|
-
resuming.value = false
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
166
|
/** True while a loop control (pause/resume/cancel) is in flight. */
|
|
254
167
|
const controlling = ref(false)
|
|
255
168
|
|
|
@@ -272,76 +185,12 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
272
185
|
}
|
|
273
186
|
}
|
|
274
187
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
try {
|
|
282
|
-
return await fn()
|
|
283
|
-
} finally {
|
|
284
|
-
curating.value = false
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/** Promote an `open` harvested follow-up into a new pending tracker item. */
|
|
289
|
-
async function promoteFollowUp(
|
|
290
|
-
initiativeId: string,
|
|
291
|
-
followUpId: string,
|
|
292
|
-
input: PromoteInitiativeFollowUpInput,
|
|
293
|
-
) {
|
|
294
|
-
return curate(async () => {
|
|
295
|
-
const updated = await api.promoteInitiativeFollowUp(
|
|
296
|
-
workspace.workspaceId!,
|
|
297
|
-
initiativeId,
|
|
298
|
-
followUpId,
|
|
299
|
-
input,
|
|
300
|
-
)
|
|
301
|
-
upsert(updated)
|
|
302
|
-
return updated
|
|
303
|
-
})
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/** Dismiss a harvested follow-up. */
|
|
307
|
-
async function dismissFollowUp(initiativeId: string, followUpId: string) {
|
|
308
|
-
return curate(async () => {
|
|
309
|
-
const updated = await api.dismissInitiativeFollowUp(
|
|
310
|
-
workspace.workspaceId!,
|
|
311
|
-
initiativeId,
|
|
312
|
-
followUpId,
|
|
313
|
-
)
|
|
314
|
-
upsert(updated)
|
|
315
|
-
return updated
|
|
316
|
-
})
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/** Edit one tracker item and/or drive its status (retry a blocked item / skip it). */
|
|
320
|
-
async function updateItem(
|
|
321
|
-
initiativeId: string,
|
|
322
|
-
itemId: string,
|
|
323
|
-
input: UpdateInitiativeItemInput,
|
|
324
|
-
) {
|
|
325
|
-
return curate(async () => {
|
|
326
|
-
const updated = await api.updateInitiativeItem(
|
|
327
|
-
workspace.workspaceId!,
|
|
328
|
-
initiativeId,
|
|
329
|
-
itemId,
|
|
330
|
-
input,
|
|
331
|
-
)
|
|
332
|
-
upsert(updated)
|
|
333
|
-
return updated
|
|
334
|
-
})
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/** Replace the execution policy (concurrency + pipeline rules). */
|
|
338
|
-
async function updatePolicy(initiativeId: string, policy: InitiativeExecutionPolicy) {
|
|
339
|
-
return curate(async () => {
|
|
340
|
-
const updated = await api.updateInitiativePolicy(workspace.workspaceId!, initiativeId, policy)
|
|
341
|
-
upsert(updated)
|
|
342
|
-
return updated
|
|
343
|
-
})
|
|
344
|
-
}
|
|
188
|
+
// The planning-window + tracker-curation actions, split into cohesive factories sharing the
|
|
189
|
+
// state above (a size-only extraction mirroring `stores/board/` — behaviour is identical to the
|
|
190
|
+
// former in-closure functions). Each owns the in-flight flags its window renders.
|
|
191
|
+
const context: InitiativeActionContext = { api, workspace, upsert }
|
|
192
|
+
const planning = createInitiativePlanningActions(context)
|
|
193
|
+
const curation = createInitiativeCurationActions(context)
|
|
345
194
|
|
|
346
195
|
function reset() {
|
|
347
196
|
byBlock.value = {}
|
|
@@ -353,10 +202,7 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
353
202
|
presets,
|
|
354
203
|
all,
|
|
355
204
|
creating,
|
|
356
|
-
resuming,
|
|
357
205
|
controlling,
|
|
358
|
-
curating,
|
|
359
|
-
recommending,
|
|
360
206
|
forBlock,
|
|
361
207
|
presetById,
|
|
362
208
|
planningPipelineIdFor,
|
|
@@ -366,16 +212,9 @@ export const useInitiativesStore = defineStore('initiatives', () => {
|
|
|
366
212
|
create,
|
|
367
213
|
probePreset,
|
|
368
214
|
load,
|
|
369
|
-
answerQuestion,
|
|
370
|
-
setQuestionStatus,
|
|
371
|
-
recommendAnswer,
|
|
372
|
-
continuePlanning,
|
|
373
|
-
proceedPlanning,
|
|
374
215
|
control,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
updateItem,
|
|
378
|
-
updatePolicy,
|
|
216
|
+
...planning,
|
|
217
|
+
...curation,
|
|
379
218
|
reset,
|
|
380
219
|
}
|
|
381
220
|
})
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { WorkspaceSnapshot } from '~/types/domain'
|
|
2
|
+
import { useAgentConfigStore } from '~/stores/agentConfig'
|
|
3
|
+
import { useAgentRunsStore } from '~/stores/agentRuns'
|
|
4
|
+
import { useAgentsStore } from '~/stores/agents'
|
|
5
|
+
import { useBoardStore } from '~/stores/board'
|
|
6
|
+
import { useBrainstormStore } from '~/stores/brainstorm'
|
|
7
|
+
import { useClarityStore } from '~/stores/clarity'
|
|
8
|
+
import { useConsensusStore } from '~/stores/consensus'
|
|
9
|
+
import { useEnvironmentTestStore } from '~/stores/environmentTest'
|
|
10
|
+
import { useExecutionStore } from '~/stores/execution'
|
|
11
|
+
import { useFragmentsStore } from '~/stores/fragments'
|
|
12
|
+
import { useGitHubStore } from '~/stores/github'
|
|
13
|
+
import { useInitiativesStore } from '~/stores/initiative'
|
|
14
|
+
import { useModelPresetsStore } from '~/stores/modelPresets'
|
|
15
|
+
import { useNotificationsStore } from '~/stores/notifications'
|
|
16
|
+
import { usePipelinesStore } from '~/stores/pipelines'
|
|
17
|
+
import { useProviderConnectionsStore } from '~/stores/providerConnections'
|
|
18
|
+
import { useRecurringPipelinesStore } from '~/stores/recurringPipelines'
|
|
19
|
+
import { useRequirementsStore } from '~/stores/requirements'
|
|
20
|
+
import { useRiskPoliciesStore } from '~/stores/riskPolicies'
|
|
21
|
+
import { useServiceFragmentDefaultsStore } from '~/stores/serviceFragmentDefaults'
|
|
22
|
+
import { useServicesStore } from '~/stores/services'
|
|
23
|
+
import { useSharedStacksStore } from '~/stores/sharedStacks'
|
|
24
|
+
import { useSkillsStore } from '~/stores/skills'
|
|
25
|
+
import { useTaskTypesStore } from '~/stores/taskTypes'
|
|
26
|
+
import { useTrackerStore } from '~/stores/tracker'
|
|
27
|
+
import { useWorkspaceSettingsStore } from '~/stores/workspaceSettings'
|
|
28
|
+
import { buildWorkspaceCapabilitiesManifest } from '~/modular/capabilities'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Drop the per-block caches that are NOT part of the snapshot (reviews, brainstorm/consensus
|
|
32
|
+
* sessions, the GitHub projection) so a switched-to board never shows the previous one's stale
|
|
33
|
+
* state. These are lazily reloaded/re-probed per board, so clearing on a same-board refresh
|
|
34
|
+
* would needlessly wipe an open review window — hence only on an actual id change.
|
|
35
|
+
*/
|
|
36
|
+
export function resetPerBoardCaches() {
|
|
37
|
+
useRequirementsStore().reset()
|
|
38
|
+
useClarityStore().reset()
|
|
39
|
+
useBrainstormStore().reset()
|
|
40
|
+
useConsensusStore().reset()
|
|
41
|
+
useGitHubStore().reset()
|
|
42
|
+
useInitiativesStore().reset()
|
|
43
|
+
useDocInterviewStore().reset()
|
|
44
|
+
// The fragment picker catalog is per-board (the merged tenant catalog), so drop
|
|
45
|
+
// it too — the next inspector open re-fetches it for the switched-to board rather
|
|
46
|
+
// than showing the previous board's (or a raw-id placeholder for) fragments.
|
|
47
|
+
useFragmentsStore().invalidate()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Fan a workspace snapshot out into the per-feature data stores. Extracted verbatim from the
|
|
52
|
+
* `workspace` store's `hydrate` (which keeps the workspace-scoped state it owns + the
|
|
53
|
+
* board-switch cache reset) so the ordering of the hydrate calls is preserved exactly — a
|
|
54
|
+
* size-only split, not a new seam.
|
|
55
|
+
*
|
|
56
|
+
* `boardSince` (captured BEFORE this snapshot's fetch) lets the board store preserve any block
|
|
57
|
+
* live-`upsert`ed while the fetch was in flight, so a slower refresh can't clobber a newer live
|
|
58
|
+
* status (see `useBoardStore().hydrate`).
|
|
59
|
+
*/
|
|
60
|
+
export function applySnapshotToStores(snapshot: WorkspaceSnapshot, boardSince?: number) {
|
|
61
|
+
useUserSettingsStore().hydrate(snapshot.userSettings ?? null)
|
|
62
|
+
useBoardStore().hydrate(snapshot.blocks, boardSince)
|
|
63
|
+
useBoardStore().hydrateArchived(snapshot.archivedServices ?? [])
|
|
64
|
+
usePipelinesStore().hydrate(snapshot.pipelines, snapshot.pipelineCatalogVersions)
|
|
65
|
+
useExecutionStore().hydrate(snapshot.executions, snapshot.workspace.id)
|
|
66
|
+
useAgentRunsStore().hydrate(snapshot.bootstrapJobs ?? [], snapshot.workspace.id)
|
|
67
|
+
useAgentRunsStore().hydrateEnvConfigRepair(snapshot.envConfigRepairJobs ?? [])
|
|
68
|
+
useEnvironmentTestStore().hydrate(snapshot.environmentTestRuns ?? [], snapshot.workspace.id)
|
|
69
|
+
useNotificationsStore().hydrate(snapshot.notifications ?? [])
|
|
70
|
+
useRiskPoliciesStore().hydrate(snapshot.riskPolicies ?? [], snapshot.riskPolicyCatalogVersions)
|
|
71
|
+
useSharedStacksStore().hydrate(snapshot.sharedStacks ?? [])
|
|
72
|
+
useWorkspaceSettingsStore().hydrate(snapshot.settings)
|
|
73
|
+
useAgentConfigStore().hydrate(snapshot.agentConfigCatalog ?? [])
|
|
74
|
+
useModelPresetsStore().hydrate(snapshot.modelPresets ?? [], snapshot.modelPresetCatalogVersions)
|
|
75
|
+
useServiceFragmentDefaultsStore().hydrate(snapshot.serviceFragmentDefaults?.fragmentIds)
|
|
76
|
+
useRecurringPipelinesStore().hydrate(snapshot.recurringPipelines ?? [])
|
|
77
|
+
useInitiativesStore().hydrate(snapshot.initiatives)
|
|
78
|
+
// Registered initiative presets (built-in generic + any a deployment mixed in): drive the
|
|
79
|
+
// create picker and which planning pipeline "Run planning" starts. Workspace-independent.
|
|
80
|
+
useInitiativesStore().hydratePresets(snapshot.initiativePresets)
|
|
81
|
+
useTrackerStore().hydrate(snapshot.trackerSettings)
|
|
82
|
+
useServicesStore().hydrate(snapshot.mounts ?? [], snapshot.serviceCatalog ?? [])
|
|
83
|
+
// Hydrate the deployment's backend-registered capabilities from ONE shared per-workspace
|
|
84
|
+
// remote capability manifest carrying BOTH custom agent kinds AND custom task types (its
|
|
85
|
+
// version covers both, so an unchanged snapshot no-ops both stores). Each store reads its
|
|
86
|
+
// own slot off it, so a proprietary agent kind renders as a first-class palette block +
|
|
87
|
+
// result view and a proprietary task type as a first-class create-task choice + card badge.
|
|
88
|
+
// Swapped wholesale per workspace (no global-catalog mutation).
|
|
89
|
+
const capabilities = buildWorkspaceCapabilitiesManifest(
|
|
90
|
+
snapshot.customAgentKinds ?? [],
|
|
91
|
+
snapshot.customTaskTypes ?? [],
|
|
92
|
+
)
|
|
93
|
+
useAgentsStore().hydrateCapabilities(capabilities)
|
|
94
|
+
useTaskTypesStore().hydrateCapabilities(capabilities)
|
|
95
|
+
// The account's repo-sourced Claude Skills catalog (shared across its workspaces), so the
|
|
96
|
+
// pipeline builder's per-step skill picker has its options. A straight replace.
|
|
97
|
+
useSkillsStore().hydrate(snapshot.skills ?? [])
|
|
98
|
+
// Seed the connect form's backend-kind selectors (built-in + any custom backend a
|
|
99
|
+
// deployment registered), so a programmatically-registered env/runner backend is a
|
|
100
|
+
// first-class connect option instead of a hardcoded manifest/kubernetes list.
|
|
101
|
+
useProviderConnectionsStore().registerBackendKinds({
|
|
102
|
+
environment: snapshot.environmentBackendKinds,
|
|
103
|
+
'runner-pool': snapshot.runnerBackendKinds,
|
|
104
|
+
})
|
|
105
|
+
}
|
package/app/stores/workspace.ts
CHANGED
|
@@ -10,32 +10,7 @@ import type {
|
|
|
10
10
|
} from '~/types/domain'
|
|
11
11
|
import { useAccountsStore } from '~/stores/accounts'
|
|
12
12
|
import { useBoardStore } from '~/stores/board'
|
|
13
|
-
import {
|
|
14
|
-
import { useExecutionStore } from '~/stores/execution'
|
|
15
|
-
import { useAgentRunsStore } from '~/stores/agentRuns'
|
|
16
|
-
import { useEnvironmentTestStore } from '~/stores/environmentTest'
|
|
17
|
-
import { useNotificationsStore } from '~/stores/notifications'
|
|
18
|
-
import { useRiskPoliciesStore } from '~/stores/riskPolicies'
|
|
19
|
-
import { useSharedStacksStore } from '~/stores/sharedStacks'
|
|
20
|
-
import { useWorkspaceSettingsStore } from '~/stores/workspaceSettings'
|
|
21
|
-
import { useAgentConfigStore } from '~/stores/agentConfig'
|
|
22
|
-
import { useModelPresetsStore } from '~/stores/modelPresets'
|
|
23
|
-
import { useServiceFragmentDefaultsStore } from '~/stores/serviceFragmentDefaults'
|
|
24
|
-
import { useRecurringPipelinesStore } from '~/stores/recurringPipelines'
|
|
25
|
-
import { useInitiativesStore } from '~/stores/initiative'
|
|
26
|
-
import { useServicesStore } from '~/stores/services'
|
|
27
|
-
import { useAgentsStore } from '~/stores/agents'
|
|
28
|
-
import { useTaskTypesStore } from '~/stores/taskTypes'
|
|
29
|
-
import { buildWorkspaceCapabilitiesManifest } from '~/modular/capabilities'
|
|
30
|
-
import { useSkillsStore } from '~/stores/skills'
|
|
31
|
-
import { useTrackerStore } from '~/stores/tracker'
|
|
32
|
-
import { useRequirementsStore } from '~/stores/requirements'
|
|
33
|
-
import { useClarityStore } from '~/stores/clarity'
|
|
34
|
-
import { useBrainstormStore } from '~/stores/brainstorm'
|
|
35
|
-
import { useConsensusStore } from '~/stores/consensus'
|
|
36
|
-
import { useGitHubStore } from '~/stores/github'
|
|
37
|
-
import { useFragmentsStore } from '~/stores/fragments'
|
|
38
|
-
import { useProviderConnectionsStore } from '~/stores/providerConnections'
|
|
13
|
+
import { applySnapshotToStores, resetPerBoardCaches } from '~/stores/workspace/hydrate'
|
|
39
14
|
import { markBoot } from '~/utils/bootMarks'
|
|
40
15
|
import { retryWhileBackendUnreachable } from '~/utils/backendReady'
|
|
41
16
|
|
|
@@ -109,30 +84,14 @@ export const useWorkspaceStore = defineStore(
|
|
|
109
84
|
* fresh loads (init/switch/create), where there is no in-flight-upsert race to guard.
|
|
110
85
|
*/
|
|
111
86
|
function hydrate(snapshot: WorkspaceSnapshot, boardSince?: number) {
|
|
112
|
-
// A change of active board (or the first load)
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
// These are lazily reloaded/re-probed per board, so clearing on a same-board refresh
|
|
116
|
-
// would needlessly wipe an open review window — hence only on an actual id change.
|
|
117
|
-
if (workspaceId.value !== snapshot.workspace.id) {
|
|
118
|
-
useRequirementsStore().reset()
|
|
119
|
-
useClarityStore().reset()
|
|
120
|
-
useBrainstormStore().reset()
|
|
121
|
-
useConsensusStore().reset()
|
|
122
|
-
useGitHubStore().reset()
|
|
123
|
-
useInitiativesStore().reset()
|
|
124
|
-
useDocInterviewStore().reset()
|
|
125
|
-
// The fragment picker catalog is per-board (the merged tenant catalog), so drop
|
|
126
|
-
// it too — the next inspector open re-fetches it for the switched-to board rather
|
|
127
|
-
// than showing the previous board's (or a raw-id placeholder for) fragments.
|
|
128
|
-
useFragmentsStore().invalidate()
|
|
129
|
-
}
|
|
87
|
+
// A change of active board (or the first load) drops the per-block caches that are NOT
|
|
88
|
+
// part of the snapshot; a same-board refresh keeps them (see `resetPerBoardCaches`).
|
|
89
|
+
if (workspaceId.value !== snapshot.workspace.id) resetPerBoardCaches()
|
|
130
90
|
workspaceId.value = snapshot.workspace.id
|
|
131
91
|
spend.value = snapshot.spend ?? null
|
|
132
92
|
accountSpend.value = snapshot.accountSpend ?? null
|
|
133
93
|
userSpend.value = snapshot.userSpend ?? null
|
|
134
94
|
budgetCaps.value = snapshot.budgetCaps ?? null
|
|
135
|
-
useUserSettingsStore().hydrate(snapshot.userSettings ?? null)
|
|
136
95
|
infraSetup.value = snapshot.infraSetup ?? null
|
|
137
96
|
access.value = snapshot.access ?? null
|
|
138
97
|
// Keep the board list in step (e.g. a freshly created board, or a rename). The
|
|
@@ -144,55 +103,8 @@ export const useWorkspaceStore = defineStore(
|
|
|
144
103
|
} else {
|
|
145
104
|
workspaces.value.unshift(snapshot.workspace)
|
|
146
105
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
usePipelinesStore().hydrate(snapshot.pipelines, snapshot.pipelineCatalogVersions)
|
|
150
|
-
useExecutionStore().hydrate(snapshot.executions, snapshot.workspace.id)
|
|
151
|
-
useAgentRunsStore().hydrate(snapshot.bootstrapJobs ?? [], snapshot.workspace.id)
|
|
152
|
-
useAgentRunsStore().hydrateEnvConfigRepair(snapshot.envConfigRepairJobs ?? [])
|
|
153
|
-
useEnvironmentTestStore().hydrate(snapshot.environmentTestRuns ?? [], snapshot.workspace.id)
|
|
154
|
-
useNotificationsStore().hydrate(snapshot.notifications ?? [])
|
|
155
|
-
useRiskPoliciesStore().hydrate(
|
|
156
|
-
snapshot.riskPolicies ?? [],
|
|
157
|
-
snapshot.riskPolicyCatalogVersions,
|
|
158
|
-
)
|
|
159
|
-
useSharedStacksStore().hydrate(snapshot.sharedStacks ?? [])
|
|
160
|
-
useWorkspaceSettingsStore().hydrate(snapshot.settings)
|
|
161
|
-
useAgentConfigStore().hydrate(snapshot.agentConfigCatalog ?? [])
|
|
162
|
-
useModelPresetsStore().hydrate(
|
|
163
|
-
snapshot.modelPresets ?? [],
|
|
164
|
-
snapshot.modelPresetCatalogVersions,
|
|
165
|
-
)
|
|
166
|
-
useServiceFragmentDefaultsStore().hydrate(snapshot.serviceFragmentDefaults?.fragmentIds)
|
|
167
|
-
useRecurringPipelinesStore().hydrate(snapshot.recurringPipelines ?? [])
|
|
168
|
-
useInitiativesStore().hydrate(snapshot.initiatives)
|
|
169
|
-
// Registered initiative presets (built-in generic + any a deployment mixed in): drive the
|
|
170
|
-
// create picker and which planning pipeline "Run planning" starts. Workspace-independent.
|
|
171
|
-
useInitiativesStore().hydratePresets(snapshot.initiativePresets)
|
|
172
|
-
useTrackerStore().hydrate(snapshot.trackerSettings)
|
|
173
|
-
useServicesStore().hydrate(snapshot.mounts ?? [], snapshot.serviceCatalog ?? [])
|
|
174
|
-
// Hydrate the deployment's backend-registered capabilities from ONE shared per-workspace
|
|
175
|
-
// remote capability manifest carrying BOTH custom agent kinds AND custom task types (its
|
|
176
|
-
// version covers both, so an unchanged snapshot no-ops both stores). Each store reads its
|
|
177
|
-
// own slot off it, so a proprietary agent kind renders as a first-class palette block +
|
|
178
|
-
// result view and a proprietary task type as a first-class create-task choice + card badge.
|
|
179
|
-
// Swapped wholesale per workspace (no global-catalog mutation).
|
|
180
|
-
const capabilities = buildWorkspaceCapabilitiesManifest(
|
|
181
|
-
snapshot.customAgentKinds ?? [],
|
|
182
|
-
snapshot.customTaskTypes ?? [],
|
|
183
|
-
)
|
|
184
|
-
useAgentsStore().hydrateCapabilities(capabilities)
|
|
185
|
-
useTaskTypesStore().hydrateCapabilities(capabilities)
|
|
186
|
-
// The account's repo-sourced Claude Skills catalog (shared across its workspaces), so the
|
|
187
|
-
// pipeline builder's per-step skill picker has its options. A straight replace.
|
|
188
|
-
useSkillsStore().hydrate(snapshot.skills ?? [])
|
|
189
|
-
// Seed the connect form's backend-kind selectors (built-in + any custom backend a
|
|
190
|
-
// deployment registered), so a programmatically-registered env/runner backend is a
|
|
191
|
-
// first-class connect option instead of a hardcoded manifest/kubernetes list.
|
|
192
|
-
useProviderConnectionsStore().registerBackendKinds({
|
|
193
|
-
environment: snapshot.environmentBackendKinds,
|
|
194
|
-
'runner-pool': snapshot.runnerBackendKinds,
|
|
195
|
-
})
|
|
106
|
+
// Fan the rest of the snapshot out into the per-feature data stores.
|
|
107
|
+
applySnapshotToStores(snapshot, boardSince)
|
|
196
108
|
}
|
|
197
109
|
|
|
198
110
|
/** Resolve accounts + boards, then open the right board for the active account. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.153.
|
|
3
|
+
"version": "0.153.4",
|
|
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",
|