@cat-factory/app 0.133.0 → 0.135.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/app/components/environments/EnvironmentSetupWizard.vue +70 -632
- package/app/components/environments/steps/EnvPickStep.vue +40 -0
- package/app/components/environments/steps/EnvPreflightStep.vue +115 -0
- package/app/components/environments/steps/EnvReviewStep.vue +381 -0
- package/app/components/environments/steps/EnvSaveStep.vue +109 -0
- package/app/components/environments/steps/JourneyStepNav.vue +30 -0
- package/app/components/panels/StepResultViewHost.vue +48 -86
- package/app/modular/agent-kinds.spec.ts +80 -0
- package/app/modular/agent-kinds.ts +83 -0
- package/app/modular/journeys/environmentSetup.frame.ts +31 -0
- package/app/modular/journeys/environmentSetup.logic.spec.ts +34 -0
- package/app/modular/journeys/environmentSetup.logic.ts +86 -0
- package/app/modular/journeys/environmentSetup.ts +143 -0
- package/app/modular/journeys/persistence.spec.ts +68 -0
- package/app/modular/journeys/persistence.ts +58 -0
- package/app/modular/nav-contributions.spec.ts +1 -1
- package/app/modular/nav-contributions.ts +7 -11
- package/app/modular/registry.spec.ts +38 -0
- package/app/modular/registry.ts +30 -13
- package/app/modular/result-views.ts +104 -0
- package/app/modular/slots.ts +40 -0
- package/app/plugins/modular.client.ts +59 -3
- package/app/stores/agents.spec.ts +100 -0
- package/app/stores/agents.ts +115 -34
- package/app/stores/environmentWizard.ts +23 -27
- package/app/stores/workspace.ts +4 -3
- package/app/types/domain.ts +4 -3
- package/app/utils/catalog.ts +57 -16
- package/package.json +13 -12
package/app/stores/agents.ts
CHANGED
|
@@ -1,21 +1,96 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import {
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
|
+
import type { RemoteModuleManifest } from '@modular-vue/core'
|
|
4
|
+
import { buildAgentCapabilitiesManifest, customKindToArchetype } from '~/modular/agent-kinds'
|
|
5
|
+
import type { AppSlots } from '~/modular/slots'
|
|
6
|
+
import {
|
|
7
|
+
AGENT_ARCHETYPES,
|
|
8
|
+
AGENT_BY_KIND,
|
|
9
|
+
setCustomAgentKindMeta,
|
|
10
|
+
SYSTEM_AGENT_META,
|
|
11
|
+
uid,
|
|
12
|
+
} from '~/utils/catalog'
|
|
4
13
|
import type { AgentArchetype, AgentKind, CustomAgentKind } from '~/types/domain'
|
|
5
14
|
|
|
6
15
|
/**
|
|
7
|
-
* The agent palette
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
16
|
+
* The agent palette catalog (slice 2 of the modular-vue adoption —
|
|
17
|
+
* docs/initiatives/modular-vue-adoption.md).
|
|
18
|
+
*
|
|
19
|
+
* Reactive union of three sources, none of which mutates the frozen built-in
|
|
20
|
+
* {@link AGENT_BY_KIND} const any more:
|
|
21
|
+
* - the built-in archetypes (static);
|
|
22
|
+
* - CONSUMER-shipped kinds contributed as CODE via the modular `agentKinds`
|
|
23
|
+
* slot (`registerConsumerKinds`, fed once at boot from the resolved manifest);
|
|
24
|
+
* - the deployment's BACKEND-registered kinds, modeled as a single
|
|
25
|
+
* {@link RemoteModuleManifest} swapped per workspace snapshot
|
|
26
|
+
* (`hydrateCustomKinds`) and read directly (single-active-manifest shape).
|
|
27
|
+
*
|
|
28
|
+
* The merged custom catalog is projected back into `catalog.ts`'s
|
|
29
|
+
* {@link setCustomAgentKindMeta} read-model so the pure `agentKindMeta` /
|
|
30
|
+
* `isKnownAgentKind` lookups (used across ~17 renderers) resolve a custom kind
|
|
31
|
+
* reactively without importing this store.
|
|
11
32
|
*/
|
|
12
33
|
export const useAgentsStore = defineStore('agents', () => {
|
|
13
|
-
|
|
34
|
+
// CODE-shipped consumer kinds from the static `agentKinds` slot (fed once at
|
|
35
|
+
// boot by the modular install plugin — module slots are resolved once).
|
|
36
|
+
const consumerKinds = ref<CustomAgentKind[]>([])
|
|
37
|
+
// The active per-workspace capability manifest built from the snapshot's
|
|
38
|
+
// `customAgentKinds`, or null before the first hydrate.
|
|
39
|
+
const capabilitiesManifest = ref<RemoteModuleManifest<AppSlots> | null>(null)
|
|
40
|
+
// In-UI, client-only prototype agents created via the "add agent" modal.
|
|
41
|
+
const runtimeAgents = ref<AgentArchetype[]>([])
|
|
14
42
|
|
|
15
|
-
|
|
16
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The merged CUSTOM catalog (consumer-slot → backend-manifest → runtime), each
|
|
45
|
+
* mapped to display metadata, de-duplicated, and never shadowing a built-in or
|
|
46
|
+
* system kind. The old `registerCustomKinds` only guarded `AGENT_BY_KIND`; this
|
|
47
|
+
* intentionally ALSO drops any custom kind colliding with a `SYSTEM_AGENT_META`
|
|
48
|
+
* kind (`ci` / `merger` / `blueprints` / gates …), so a snapshot can't override an
|
|
49
|
+
* engine kind's palette entry either — matching `agentKindMeta`'s precedence
|
|
50
|
+
* (built-in → system → custom), where a colliding custom kind would never win anyway.
|
|
51
|
+
*/
|
|
52
|
+
const customArchetypes = computed<AgentArchetype[]>(() => {
|
|
53
|
+
const seen = new Set<string>()
|
|
54
|
+
const out: AgentArchetype[] = []
|
|
55
|
+
const add = (a: AgentArchetype) => {
|
|
56
|
+
if (a.kind in AGENT_BY_KIND || a.kind in SYSTEM_AGENT_META || seen.has(a.kind)) return
|
|
57
|
+
seen.add(a.kind)
|
|
58
|
+
out.push(a)
|
|
59
|
+
}
|
|
60
|
+
for (const k of consumerKinds.value) add(customKindToArchetype(k))
|
|
61
|
+
for (const k of capabilitiesManifest.value?.slots?.agentKinds ?? [])
|
|
62
|
+
add(customKindToArchetype(k))
|
|
63
|
+
for (const a of runtimeAgents.value) add(a)
|
|
64
|
+
return out
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
/** The full palette: built-in archetypes + the merged custom ones. */
|
|
68
|
+
const archetypes = computed<AgentArchetype[]>(() => [
|
|
69
|
+
...AGENT_ARCHETYPES,
|
|
70
|
+
...customArchetypes.value,
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
// Known-kind lookup (built-in ∪ system ∪ custom) for `get`.
|
|
74
|
+
const customByKind = computed<Record<string, AgentArchetype>>(() =>
|
|
75
|
+
Object.fromEntries(customArchetypes.value.map((a) => [a.kind, a])),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
// Keep `catalog.ts`'s pure-util projection in sync with the merged custom
|
|
79
|
+
// catalog so `agentKindMeta` / `isKnownAgentKind` resolve custom kinds. Sync
|
|
80
|
+
// flush so an imperative read right after `hydrateCustomKinds` (e.g. the run
|
|
81
|
+
// dispatch resolving a custom kind's `resultView`) sees the fresh catalog with
|
|
82
|
+
// no tick gap. The watch lives in the store's effect scope (disposed with it).
|
|
83
|
+
watch(customByKind, (map) => setCustomAgentKindMeta(map), { immediate: true, flush: 'sync' })
|
|
84
|
+
|
|
85
|
+
/** Display metadata for a KNOWN kind (built-in / system / custom), else undefined. */
|
|
86
|
+
function get(kind: AgentKind): AgentArchetype | undefined {
|
|
87
|
+
return AGENT_BY_KIND[kind] ?? SYSTEM_AGENT_META[kind] ?? customByKind.value[kind]
|
|
17
88
|
}
|
|
18
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Add an in-UI prototype agent (the pipeline builder's "add agent" modal).
|
|
92
|
+
* Client-only, so it lives in store state — no backend, no global mutation.
|
|
93
|
+
*/
|
|
19
94
|
function addAgent(input: {
|
|
20
95
|
label: string
|
|
21
96
|
description?: string
|
|
@@ -30,36 +105,42 @@ export const useAgentsStore = defineStore('agents', () => {
|
|
|
30
105
|
icon: input.icon || 'i-lucide-sparkles',
|
|
31
106
|
color: input.color || '#22d3ee',
|
|
32
107
|
}
|
|
33
|
-
|
|
34
|
-
AGENT_BY_KIND[archetype.kind] = archetype
|
|
35
|
-
archetypes.value.push(archetype)
|
|
108
|
+
runtimeAgents.value = [...runtimeAgents.value, archetype]
|
|
36
109
|
return archetype
|
|
37
110
|
}
|
|
38
111
|
|
|
39
112
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* declared `resultView` opens through the same registry the built-ins use. Idempotent
|
|
44
|
-
* and built-in-safe — a kind already known (a built-in, or a prior load) is left
|
|
45
|
-
* untouched, so a snapshot can't shadow a built-in or duplicate on reload.
|
|
113
|
+
* Register the deployment's CODE-shipped consumer agent kinds — the resolved
|
|
114
|
+
* modular `agentKinds` slot, fed once by the install plugin. Idempotent
|
|
115
|
+
* replace (module slots resolve once, so this is called a single time).
|
|
46
116
|
*/
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
if (AGENT_BY_KIND[kind]) continue
|
|
50
|
-
const archetype: AgentArchetype = {
|
|
51
|
-
kind,
|
|
52
|
-
label: presentation.label,
|
|
53
|
-
icon: presentation.icon,
|
|
54
|
-
color: presentation.color,
|
|
55
|
-
description: presentation.description,
|
|
56
|
-
...(presentation.category ? { category: presentation.category } : {}),
|
|
57
|
-
...(presentation.resultView ? { resultView: presentation.resultView } : {}),
|
|
58
|
-
}
|
|
59
|
-
AGENT_BY_KIND[kind] = archetype
|
|
60
|
-
archetypes.value.push(archetype)
|
|
61
|
-
}
|
|
117
|
+
function registerConsumerKinds(kinds: readonly CustomAgentKind[]) {
|
|
118
|
+
consumerKinds.value = [...kinds]
|
|
62
119
|
}
|
|
63
120
|
|
|
64
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Hydrate the deployment's BACKEND-registered custom kinds from a workspace
|
|
123
|
+
* snapshot, modeled as a single remote capability manifest (swapped wholesale
|
|
124
|
+
* per workspace). Replaces the old `registerCustomKinds` that mutated
|
|
125
|
+
* {@link AGENT_BY_KIND} directly.
|
|
126
|
+
*
|
|
127
|
+
* The snapshot re-delivers the same deployment kinds on every board refresh, so
|
|
128
|
+
* skip the swap — and the downstream projection invalidation of every
|
|
129
|
+
* `agentKindMeta` consumer — when the content-derived manifest version is
|
|
130
|
+
* unchanged. A genuinely different workspace's kinds change the version and swap.
|
|
131
|
+
*/
|
|
132
|
+
function hydrateCustomKinds(kinds: CustomAgentKind[]) {
|
|
133
|
+
const next = buildAgentCapabilitiesManifest(kinds)
|
|
134
|
+
if (capabilitiesManifest.value?.version === next.version) return
|
|
135
|
+
capabilitiesManifest.value = next
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
archetypes,
|
|
140
|
+
customArchetypes,
|
|
141
|
+
get,
|
|
142
|
+
addAgent,
|
|
143
|
+
registerConsumerKinds,
|
|
144
|
+
hydrateCustomKinds,
|
|
145
|
+
}
|
|
65
146
|
})
|
|
@@ -23,7 +23,7 @@ import { usePreflightsStore } from '~/stores/preflights'
|
|
|
23
23
|
import { useServicesStore } from '~/stores/services'
|
|
24
24
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
25
25
|
|
|
26
|
-
// The environment setup wizard's cross-step
|
|
26
|
+
// The environment setup wizard's cross-step DATA + actions (shared-stacks slice 7). It backs the
|
|
27
27
|
// guided flow — pick a service frame → review the recommended `docker-compose` recipe (detector
|
|
28
28
|
// facts + the opt-in analyst draft, merged with provenance) → run the machine preflights → save
|
|
29
29
|
// (persist the recipe on the frame AND register the workspace's docker-compose handler so the
|
|
@@ -31,17 +31,19 @@ import { useWorkspaceStore } from '~/stores/workspace'
|
|
|
31
31
|
//
|
|
32
32
|
// The detector + analyst only RECOMMEND; the human confirms/edits the working `recipe` here and the
|
|
33
33
|
// compose provider keys purely on the saved recipe (the build-flag rule). Mirrors the other infra
|
|
34
|
-
// stores' idiom; the flow state is a singleton so the wizard
|
|
34
|
+
// stores' idiom; the flow state is a singleton so the wizard's step children share it.
|
|
35
|
+
//
|
|
36
|
+
// Since slice 3 of the modular-vue adoption (docs/initiatives/modular-vue-adoption.md) the wizard's
|
|
37
|
+
// step NAVIGATION lives in a modular-vue journey (`app/modular/journeys/environmentSetup.ts`), NOT
|
|
38
|
+
// here — this store no longer holds a `step` / `STEP_ORDER` / `goToStep`. It is purely the per-frame
|
|
39
|
+
// data+action layer the journey's step components drive; `beginForFrame` seeds it when a step first
|
|
40
|
+
// targets a frame.
|
|
35
41
|
|
|
36
42
|
/** The seeded analyst-only pipeline the "run deep analysis" trigger starts against the frame. */
|
|
37
43
|
const ANALYSIS_PIPELINE_ID = 'pl_environment_analysis'
|
|
38
44
|
/** The analyst agent kind whose `result.custom` carries the drafted recipe. */
|
|
39
45
|
const ANALYST_AGENT_KIND = 'environment-analyst'
|
|
40
46
|
|
|
41
|
-
/** The wizard's ordered steps. `trial` is an optional post-save action, not a gate. */
|
|
42
|
-
export type EnvWizardStep = 'pick' | 'review' | 'preflight' | 'save'
|
|
43
|
-
export const ENV_WIZARD_STEPS: EnvWizardStep[] = ['pick', 'review', 'preflight', 'save']
|
|
44
|
-
|
|
45
47
|
/** The analyst run's lifecycle as the wizard surfaces it. */
|
|
46
48
|
export type AnalysisStatus = 'idle' | 'running' | 'ready' | 'failed'
|
|
47
49
|
|
|
@@ -70,9 +72,11 @@ export const useEnvironmentWizardStore = defineStore('environmentWizard', () =>
|
|
|
70
72
|
const pipelines = usePipelinesStore()
|
|
71
73
|
const preflights = usePreflightsStore()
|
|
72
74
|
|
|
73
|
-
// ----
|
|
75
|
+
// ---- Target frame -------------------------------------------------------
|
|
76
|
+
// The frame the flow currently targets. Set by `beginForFrame` when a journey
|
|
77
|
+
// step first mounts against a frame; the journey (not this store) owns which
|
|
78
|
+
// step is showing.
|
|
74
79
|
const frameId = ref<string | null>(null)
|
|
75
|
-
const step = ref<EnvWizardStep>('pick')
|
|
76
80
|
|
|
77
81
|
// ---- Detection ----------------------------------------------------------
|
|
78
82
|
const detecting = ref(false)
|
|
@@ -212,19 +216,18 @@ export const useEnvironmentWizardStore = defineStore('environmentWizard', () =>
|
|
|
212
216
|
trialStarted.value = false
|
|
213
217
|
}
|
|
214
218
|
|
|
215
|
-
/**
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Seed the data layer for a frame the journey's review step is entering. The
|
|
221
|
+
* journey owns navigation, so this is idempotent by frame: it (re)seeds +
|
|
222
|
+
* detects only when the target frame actually changes, so back-navigating to
|
|
223
|
+
* the review step (or a resume) does NOT clobber the operator's in-progress
|
|
224
|
+
* recipe edits. Selecting a different frame resets the flow for it.
|
|
225
|
+
*/
|
|
226
|
+
function beginForFrame(id: string | null) {
|
|
227
|
+
if (frameId.value === id) return
|
|
224
228
|
frameId.value = id
|
|
225
229
|
resetFlowState()
|
|
226
|
-
|
|
227
|
-
void detect()
|
|
230
|
+
if (id) void detect()
|
|
228
231
|
}
|
|
229
232
|
|
|
230
233
|
/** Re-seed the working recipe from the current merge (detector-only, or +analyst after apply). */
|
|
@@ -435,14 +438,9 @@ export const useEnvironmentWizardStore = defineStore('environmentWizard', () =>
|
|
|
435
438
|
}
|
|
436
439
|
}
|
|
437
440
|
|
|
438
|
-
function goToStep(next: EnvWizardStep) {
|
|
439
|
-
step.value = next
|
|
440
|
-
}
|
|
441
|
-
|
|
442
441
|
return {
|
|
443
442
|
// state
|
|
444
443
|
frameId,
|
|
445
|
-
step,
|
|
446
444
|
detecting,
|
|
447
445
|
detectError,
|
|
448
446
|
recommendation,
|
|
@@ -472,8 +470,7 @@ export const useEnvironmentWizardStore = defineStore('environmentWizard', () =>
|
|
|
472
470
|
analysisStatus,
|
|
473
471
|
merged,
|
|
474
472
|
// actions
|
|
475
|
-
|
|
476
|
-
selectFrame,
|
|
473
|
+
beginForFrame,
|
|
477
474
|
detect,
|
|
478
475
|
startAnalysis,
|
|
479
476
|
applyAnalystDraft,
|
|
@@ -484,6 +481,5 @@ export const useEnvironmentWizardStore = defineStore('environmentWizard', () =>
|
|
|
484
481
|
runPreflight,
|
|
485
482
|
save,
|
|
486
483
|
trialProvision,
|
|
487
|
-
goToStep,
|
|
488
484
|
}
|
|
489
485
|
})
|
package/app/stores/workspace.ts
CHANGED
|
@@ -168,9 +168,10 @@ export const useWorkspaceStore = defineStore(
|
|
|
168
168
|
useInitiativesStore().hydratePresets(snapshot.initiativePresets)
|
|
169
169
|
useTrackerStore().hydrate(snapshot.trackerSettings)
|
|
170
170
|
useServicesStore().hydrate(snapshot.mounts ?? [], snapshot.serviceCatalog ?? [])
|
|
171
|
-
//
|
|
172
|
-
// proprietary kind renders as a first-class
|
|
173
|
-
|
|
171
|
+
// Hydrate the deployment's backend-registered custom agent kinds as the workspace's
|
|
172
|
+
// remote capability manifest, so a proprietary kind renders as a first-class palette
|
|
173
|
+
// block + result view. Swapped wholesale per workspace (no global-catalog mutation).
|
|
174
|
+
useAgentsStore().hydrateCustomKinds(snapshot.customAgentKinds ?? [])
|
|
174
175
|
// The account's repo-sourced Claude Skills catalog (shared across its workspaces), so the
|
|
175
176
|
// pipeline builder's per-step skill picker has its options. A straight replace.
|
|
176
177
|
useSkillsStore().hydrate(snapshot.skills ?? [])
|
package/app/types/domain.ts
CHANGED
|
@@ -108,9 +108,10 @@ export interface AgentArchetype {
|
|
|
108
108
|
category?: AgentCategory
|
|
109
109
|
/**
|
|
110
110
|
* Optional id of a DEDICATED result window this agent's step opens instead of the
|
|
111
|
-
* generic prose step-detail panel. Resolved through the
|
|
112
|
-
* (`
|
|
113
|
-
*
|
|
111
|
+
* generic prose step-detail panel. Resolved through the modular `resultViews` slot
|
|
112
|
+
* registry (`~/modular/result-views`, read by `StepResultViewHost`) so any agent —
|
|
113
|
+
* built-in or a consumer's — can declare a bespoke visualization without the renderer
|
|
114
|
+
* hardcoding a kind. Absent → the generic `AgentStepDetail` panel.
|
|
114
115
|
*/
|
|
115
116
|
resultView?: string
|
|
116
117
|
}
|
package/app/utils/catalog.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { shallowRef } from 'vue'
|
|
1
2
|
import type {
|
|
2
3
|
AgentArchetype,
|
|
3
4
|
AgentCategory,
|
|
@@ -304,10 +305,44 @@ export function isProducerCompanion(kind: string): boolean {
|
|
|
304
305
|
return COMPANION_KINDS.has(kind)
|
|
305
306
|
}
|
|
306
307
|
|
|
307
|
-
|
|
308
|
-
|
|
308
|
+
/**
|
|
309
|
+
* The BUILT-IN palette + companion catalog, keyed by kind. Frozen and never
|
|
310
|
+
* mutated: custom (deployment/consumer) kinds no longer reach into this const —
|
|
311
|
+
* they flow through the modular `agentKinds` slot / the workspace-capability
|
|
312
|
+
* remote manifest and land in {@link customAgentKindMeta} instead (slice 2 of
|
|
313
|
+
* the modular-vue adoption). Freezing turns any stray write into a loud runtime
|
|
314
|
+
* error rather than silently conflating built-ins with custom kinds.
|
|
315
|
+
*/
|
|
316
|
+
export const AGENT_BY_KIND: Record<AgentKind, AgentArchetype> = Object.freeze(
|
|
317
|
+
Object.fromEntries([...AGENT_ARCHETYPES, ...COMPANION_ARCHETYPES].map((a) => [a.kind, a])),
|
|
309
318
|
) as Record<AgentKind, AgentArchetype>
|
|
310
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Reactive read-model of the deployment's CUSTOM agent kinds (consumer-slot +
|
|
322
|
+
* backend remote-manifest), kept in sync by the agents store from the resolved
|
|
323
|
+
* modular `agentKinds` slot. The slot/manifest is the source of truth; this
|
|
324
|
+
* `shallowRef` is its synchronous projection so the pure kind-meta lookups below
|
|
325
|
+
* ({@link agentKindMeta} / {@link isKnownAgentKind}) resolve a custom kind — and
|
|
326
|
+
* re-render when the catalog changes — WITHOUT importing the store (which would
|
|
327
|
+
* be circular) or mutating {@link AGENT_BY_KIND}. Empty until the store first
|
|
328
|
+
* populates it, so an unknown custom kind degrades to the generic fallback,
|
|
329
|
+
* exactly as before registration.
|
|
330
|
+
*/
|
|
331
|
+
const customAgentKindMeta = shallowRef<Record<string, AgentArchetype>>({})
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Replace the custom-kind projection (called only by the agents store, whenever
|
|
335
|
+
* its merged custom catalog changes). Whole-map replace, not per-key mutation.
|
|
336
|
+
*/
|
|
337
|
+
export function setCustomAgentKindMeta(map: Record<string, AgentArchetype>): void {
|
|
338
|
+
customAgentKindMeta.value = map
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Test-only: clear the custom-kind projection so a spec starts from built-ins only. */
|
|
342
|
+
export function __resetCustomAgentKindMetaForTest(): void {
|
|
343
|
+
customAgentKindMeta.value = {}
|
|
344
|
+
}
|
|
345
|
+
|
|
311
346
|
/**
|
|
312
347
|
* Agent kinds eligible for the optional consensus mechanism (the pipeline builder shows an
|
|
313
348
|
* "Enable Consensus" toggle for these). Mirrors the backend default-eligible set assigned by
|
|
@@ -596,30 +631,36 @@ const FALLBACK_AGENT_META: Omit<AgentArchetype, 'kind'> = {
|
|
|
596
631
|
}
|
|
597
632
|
|
|
598
633
|
/**
|
|
599
|
-
* Resolve display metadata for ANY agent kind — a palette archetype
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
634
|
+
* Resolve display metadata for ANY agent kind — a built-in palette archetype
|
|
635
|
+
* ({@link AGENT_BY_KIND}), an engine system kind ({@link SYSTEM_AGENT_META}), a
|
|
636
|
+
* deployment CUSTOM kind (projected from the modular `agentKinds` slot into
|
|
637
|
+
* {@link customAgentKindMeta} by the agents store), or an unknown one — ALWAYS
|
|
638
|
+
* returning a usable icon/label/color. This is the single lookup every pipeline
|
|
639
|
+
* / run renderer should use so a kind missing from the archetype map (e.g.
|
|
640
|
+
* `ci`/`merger`/`blueprints` in a seeded pipeline) can never blow up a component
|
|
641
|
+
* with an undefined access. Reading `customAgentKindMeta` reactively means a
|
|
642
|
+
* component computed re-runs when the custom catalog changes.
|
|
605
643
|
*/
|
|
606
644
|
export function agentKindMeta(kind: string): AgentArchetype {
|
|
607
645
|
return (
|
|
608
646
|
AGENT_BY_KIND[kind as AgentKind] ??
|
|
609
|
-
SYSTEM_AGENT_META[kind] ??
|
|
647
|
+
SYSTEM_AGENT_META[kind] ??
|
|
648
|
+
customAgentKindMeta.value[kind] ?? { kind: kind as AgentKind, ...FALLBACK_AGENT_META }
|
|
610
649
|
)
|
|
611
650
|
}
|
|
612
651
|
|
|
613
652
|
/**
|
|
614
|
-
* Whether an agent kind is actually known to this build — a palette
|
|
615
|
-
* ({@link AGENT_BY_KIND},
|
|
616
|
-
*
|
|
617
|
-
* ({@link
|
|
618
|
-
*
|
|
619
|
-
*
|
|
653
|
+
* Whether an agent kind is actually known to this build — a built-in palette
|
|
654
|
+
* archetype or companion ({@link AGENT_BY_KIND}), an engine system/gate kind
|
|
655
|
+
* ({@link SYSTEM_AGENT_META}), or a deployment CUSTOM kind projected from the
|
|
656
|
+
* modular `agentKinds` slot ({@link customAgentKindMeta}). Unlike
|
|
657
|
+
* {@link agentKindMeta} (which always returns a usable fallback so renderers
|
|
658
|
+
* never crash), this returns `false` for an unknown kind — used to flag a
|
|
659
|
+
* pipeline that references a nonexistent agent. Call AFTER the workspace
|
|
660
|
+
* snapshot has hydrated the custom kinds.
|
|
620
661
|
*/
|
|
621
662
|
export function isKnownAgentKind(kind: string): boolean {
|
|
622
|
-
return kind in AGENT_BY_KIND || kind in SYSTEM_AGENT_META
|
|
663
|
+
return kind in AGENT_BY_KIND || kind in SYSTEM_AGENT_META || kind in customAgentKindMeta.value
|
|
623
664
|
}
|
|
624
665
|
|
|
625
666
|
type BlockTypeMeta = { label: string; icon: string; accent: string }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.135.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,15 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@modular-frontend/core": "^0.
|
|
22
|
-
"@modular-vue/core": "^1.0
|
|
23
|
-
"@modular-vue/
|
|
24
|
-
"@modular-vue/
|
|
25
|
-
"@modular-vue/
|
|
26
|
-
"@
|
|
21
|
+
"@modular-frontend/core": "^0.2.0",
|
|
22
|
+
"@modular-vue/core": "^1.2.0",
|
|
23
|
+
"@modular-vue/journeys": "^1.1.0",
|
|
24
|
+
"@modular-vue/nuxt": "^0.3.0",
|
|
25
|
+
"@modular-vue/runtime": "^1.3.0",
|
|
26
|
+
"@modular-vue/vue": "^1.2.0",
|
|
27
|
+
"@nuxt/ui": "^4.10.0",
|
|
27
28
|
"@nuxtjs/i18n": "^10.4.1",
|
|
28
|
-
"@pinia/nuxt": "^0.
|
|
29
|
+
"@pinia/nuxt": "^1.0.1",
|
|
29
30
|
"@toad-contracts/core": "0.4.0",
|
|
30
31
|
"@toad-contracts/frontend-http-client": "0.3.2",
|
|
31
32
|
"@toad-contracts/valibot": "0.5.0",
|
|
@@ -34,26 +35,26 @@
|
|
|
34
35
|
"@vue-flow/node-resizer": "^1.5.1",
|
|
35
36
|
"@vueuse/core": "^14.3.0",
|
|
36
37
|
"markdown-it": "^14.3.0",
|
|
37
|
-
"pinia": "^
|
|
38
|
+
"pinia": "^4.0.2",
|
|
38
39
|
"pinia-plugin-persistedstate": "^4.7.1",
|
|
39
40
|
"valibot": "^1.4.2",
|
|
40
41
|
"vue": "3.5.40",
|
|
41
42
|
"wretch": "^3.0.9",
|
|
42
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.148.0"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@toad-contracts/testing": "0.3.2",
|
|
46
47
|
"@types/markdown-it": "^14.1.2",
|
|
47
48
|
"happy-dom": "^20.10.6",
|
|
48
49
|
"msw": "^2.15.0",
|
|
49
|
-
"nuxt": "^4.
|
|
50
|
+
"nuxt": "^4.5.0",
|
|
50
51
|
"typescript": "^6.0.3",
|
|
51
52
|
"vitest": "^4.1.10",
|
|
52
53
|
"vue-i18n-extract": "^2.0.7",
|
|
53
54
|
"vue-tsc": "^3.3.7"
|
|
54
55
|
},
|
|
55
56
|
"peerDependencies": {
|
|
56
|
-
"nuxt": "^4.
|
|
57
|
+
"nuxt": "^4.5.0"
|
|
57
58
|
},
|
|
58
59
|
"scripts": {
|
|
59
60
|
"postinstall": "nuxt prepare",
|