@cat-factory/app 0.145.0 → 0.146.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.
Files changed (30) hide show
  1. package/app/components/board/TaskDependencyEdges.vue +37 -73
  2. package/app/components/brainstorm/BrainstormWindow.vue +2 -7
  3. package/app/components/clarity/ClarityReviewWindow.vue +2 -2
  4. package/app/components/consensus/ConsensusSessionWindow.vue +2 -2
  5. package/app/components/docs/DocInterviewWindow.vue +1 -1
  6. package/app/components/environments/EnvSetupStepper.vue +70 -0
  7. package/app/components/environments/EnvironmentSetupWizard.vue +9 -59
  8. package/app/components/forkDecision/ForkDecisionWindow.vue +1 -1
  9. package/app/components/initiative/InitiativePlanningWindow.vue +1 -1
  10. package/app/components/initiative/InitiativeTrackerWindow.vue +1 -1
  11. package/app/components/prReview/PrReviewWindow.vue +2 -2
  12. package/app/components/requirements/RequirementsReviewWindow.vue +2 -2
  13. package/app/components/spec/ServiceSpecWindow.vue +2 -2
  14. package/app/composables/useResultView.ts +26 -3
  15. package/app/modular/journeys/environmentSetup.logic.spec.ts +46 -15
  16. package/app/modular/journeys/environmentSetup.logic.ts +102 -35
  17. package/app/modular/journeys/environmentSetup.ts +17 -68
  18. package/app/stores/pipelines.ts +50 -19
  19. package/app/stores/ui/modals.ts +599 -532
  20. package/i18n/locales/de.json +1 -0
  21. package/i18n/locales/en.json +1 -0
  22. package/i18n/locales/es.json +1 -0
  23. package/i18n/locales/fr.json +1 -0
  24. package/i18n/locales/he.json +1 -0
  25. package/i18n/locales/it.json +1 -0
  26. package/i18n/locales/ja.json +1 -0
  27. package/i18n/locales/pl.json +1 -0
  28. package/i18n/locales/tr.json +1 -0
  29. package/i18n/locales/uk.json +1 -0
  30. package/package.json +4 -4
@@ -10,15 +10,26 @@
10
10
  * trial) stay in that Pinia store, which the step components still drive; the
11
11
  * journey just decides WHICH step shows and threads the target frame id.
12
12
  *
13
- * This file is deliberately free of Vue/`.vue`/`defineModule` imports so the
14
- * transition graph is unit-tested directly (`environmentSetup.spec.ts`); the
15
- * component wiring lives in `environmentSetup.ts`, which feeds these helpers into
16
- * `defineJourney`'s `transitions` map.
13
+ * The step ORDER is no longer spelled out a second time as an ordered array: it
14
+ * is DERIVED from the annotated transition graph below (production-feedback item
15
+ * 4 in modular-react#83). Each transition wraps its handler with
16
+ * `defineTransition({ targets, handle })` so the static `targets` declare where
17
+ * the flow can go; `resolveStepSequence` / `useJourneyProgress` walk that graph
18
+ * to produce the ordered step list and the wizard's "Step X of N" progress from
19
+ * the one place the flow is encoded. `steps` carries each step's progress-label
20
+ * key beside the transitions.
21
+ *
22
+ * This definition lives in the logic file (not the SFC-importing
23
+ * `environmentSetup.ts`) so the graph stays free of `.vue` imports and is
24
+ * unit-tested directly (`environmentSetup.logic.spec.ts`). It references the step
25
+ * module only as a TYPE (`import type`), which is erased at runtime, so importing
26
+ * this file pulls no components. `environmentSetup.ts` supplies the module (with
27
+ * its step components) and re-exports the journey + the launch handle + the
28
+ * persistence adapter.
17
29
  */
18
-
19
- /** The journey's ordered step entries (also the module's `entryPoints` keys). */
20
- export const ENV_STEP_ORDER = ['pick', 'review', 'preflight', 'save'] as const
21
- export type EnvStep = (typeof ENV_STEP_ORDER)[number]
30
+ import type { ExitCtx } from '@modular-vue/journeys'
31
+ import { defineJourney, defineTransition } from '@modular-vue/journeys'
32
+ import type { environmentSetupModule } from '~/modular/journeys/environmentSetup'
22
33
 
23
34
  /** The single module id every step entry lives under. */
24
35
  export const ENV_MODULE_ID = 'cat-factory:environment-setup' as const
@@ -52,35 +63,91 @@ export function envInitialState(input: EnvSetupInput): EnvSetupState {
52
63
  }
53
64
 
54
65
  /** First step: skip the picker when the launcher already chose a frame. */
55
- export function envStartStep(_state: EnvSetupState, input: EnvSetupInput): EnvStep {
66
+ export function envStartStep(_state: EnvSetupState, input: EnvSetupInput): 'pick' | 'review' {
56
67
  return input.frameId ? 'review' : 'pick'
57
68
  }
58
69
 
59
70
  /**
60
- * The step reached by advancing from `from` via its forward exit, or `'done'`
61
- * when the flow completes. The pick step advances via `select` (a distinct
62
- * exit); the rest via `advance`. Pure and total over `EnvStep`.
63
- *
64
- * This is the SINGLE SOURCE OF TRUTH for the linear forward chain: the journey
65
- * definition (`environmentSetup.ts`) derives its `advance` transitions' target
66
- * entries from it, so pinning this function in `environmentSetup.logic.spec.ts`
67
- * genuinely guards the wired graph against a silent reorder/drop. The overloads
68
- * narrow the return to a concrete entry (or `'done'`) so a transition handler can
69
- * feed the result straight into a `StepSpec` without a widened `EnvStep | 'done'`.
71
+ * The journey's module type map one module, referenced by its `typeof` so the
72
+ * transition + step maps resolve its literal entry/exit vocabulary with no casts.
73
+ * This is the case production-feedback item 3 (modular-react#83) fixed: before it,
74
+ * `defineModule` widened the descriptor, so `typeof environmentSetupModule` could
75
+ * not stand in as a `TModules` member without re-declaring the entry names by hand.
70
76
  */
71
- export function envNextAfter(from: 'pick'): 'review'
72
- export function envNextAfter(from: 'review'): 'preflight'
73
- export function envNextAfter(from: 'preflight'): 'save'
74
- export function envNextAfter(from: 'save'): 'done'
75
- export function envNextAfter(from: EnvStep): EnvStep | 'done' {
76
- switch (from) {
77
- case 'pick':
78
- return 'review'
79
- case 'review':
80
- return 'preflight'
81
- case 'preflight':
82
- return 'save'
83
- case 'save':
84
- return 'done'
85
- }
86
- }
77
+ export type EnvModules = { [ENV_MODULE_ID]: typeof environmentSetupModule }
78
+
79
+ /** Binder threading the journey generics into each annotated transition handler. */
80
+ const transition = defineTransition<EnvModules, EnvSetupState>()
81
+
82
+ /**
83
+ * The journey definition. `start` skips the picker when a frame was preselected.
84
+ * The forward chain is the annotated transitions' `targets`: pick →(select)→
85
+ * review →(advance)→ preflight →(advance)→ save →(advance)→ complete. Back
86
+ * navigation is handled by the entries' `allowBack` (declared on the module in
87
+ * `environmentSetup.ts`), not explicit transitions.
88
+ */
89
+ export const environmentSetupJourney = defineJourney<EnvModules, EnvSetupState>()({
90
+ id: 'environment-setup',
91
+ version: '1.0.0',
92
+ initialState: (input: EnvSetupInput) => envInitialState(input),
93
+ start: (state, input: EnvSetupInput) =>
94
+ envStartStep(state, input) === 'review'
95
+ ? { module: ENV_MODULE_ID, entry: 'review', input: { frameId: state.frameId } }
96
+ : { module: ENV_MODULE_ID, entry: 'pick', input: { frameId: state.frameId } },
97
+ steps: {
98
+ [ENV_MODULE_ID]: {
99
+ pick: { progressLabel: 'environmentWizard.steps.pick' },
100
+ review: { progressLabel: 'environmentWizard.steps.review' },
101
+ preflight: { progressLabel: 'environmentWizard.steps.preflight' },
102
+ save: { progressLabel: 'environmentWizard.steps.save' },
103
+ },
104
+ },
105
+ transitions: {
106
+ [ENV_MODULE_ID]: {
107
+ pick: {
108
+ [ENV_SELECT_EXIT]: transition({
109
+ targets: [{ module: ENV_MODULE_ID, entry: 'review' }],
110
+ handle: (ctx: ExitCtx<EnvSetupState, EnvSelectOutput, unknown>) => ({
111
+ next: {
112
+ module: ENV_MODULE_ID,
113
+ entry: 'review',
114
+ input: { frameId: ctx.output.frameId },
115
+ },
116
+ state: { frameId: ctx.output.frameId },
117
+ }),
118
+ }),
119
+ },
120
+ review: {
121
+ [ENV_ADVANCE_EXIT]: transition({
122
+ targets: [{ module: ENV_MODULE_ID, entry: 'preflight' }],
123
+ handle: (ctx) => ({
124
+ next: {
125
+ module: ENV_MODULE_ID,
126
+ entry: 'preflight',
127
+ input: { frameId: ctx.state.frameId },
128
+ },
129
+ }),
130
+ }),
131
+ },
132
+ preflight: {
133
+ [ENV_ADVANCE_EXIT]: transition({
134
+ targets: [{ module: ENV_MODULE_ID, entry: 'save' }],
135
+ handle: (ctx) => ({
136
+ next: {
137
+ module: ENV_MODULE_ID,
138
+ entry: 'save',
139
+ input: { frameId: ctx.state.frameId },
140
+ },
141
+ }),
142
+ }),
143
+ },
144
+ // `save` advances to journey completion.
145
+ save: {
146
+ [ENV_ADVANCE_EXIT]: transition({
147
+ targets: ['complete'],
148
+ handle: () => ({ complete: undefined }),
149
+ }),
150
+ },
151
+ },
152
+ },
153
+ })
@@ -1,6 +1,6 @@
1
1
  import { defineModule } from '@modular-vue/core'
2
2
  import { defineExit } from '@modular-frontend/core'
3
- import { defineJourney, defineJourneyHandle } from '@modular-vue/journeys'
3
+ import { defineJourneyHandle } from '@modular-vue/journeys'
4
4
  import EnvPickStep from '~/components/environments/steps/EnvPickStep.vue'
5
5
  import EnvReviewStep from '~/components/environments/steps/EnvReviewStep.vue'
6
6
  import EnvPreflightStep from '~/components/environments/steps/EnvPreflightStep.vue'
@@ -13,9 +13,7 @@ import {
13
13
  type EnvSelectOutput,
14
14
  type EnvSetupInput,
15
15
  type EnvSetupState,
16
- envInitialState,
17
- envNextAfter,
18
- envStartStep,
16
+ environmentSetupJourney,
19
17
  } from '~/modular/journeys/environmentSetup.logic'
20
18
 
21
19
  /**
@@ -25,6 +23,13 @@ import {
25
23
  * with a typed, back/rewind-capable, resumable journey; the per-step data + async
26
24
  * actions stay in that Pinia store, driven by the step components below.
27
25
  *
26
+ * This file supplies the step MODULE (it imports the step `.vue` components, so —
27
+ * like `result-views.ts` — it's registered from the client plugin, keeping the
28
+ * unit-tested `registry.ts` / `*.logic.ts` import graph free of SFCs) and re-exports
29
+ * the JOURNEY, whose transition graph + step metadata live in the SFC-free
30
+ * `environmentSetup.logic.ts` (so `resolveStepSequence` / `useJourneyProgress` and
31
+ * the ordering test have no `.vue` dependency).
32
+ *
28
33
  * Authoring notes (co-evolution): `defineModule` comes from the `@modular-vue/core`
29
34
  * binding, but the exit helper `defineExit` is only exported from the neutral
30
35
  * `@modular-frontend/core` engine (a direct dep) — the Vue binding doesn't re-export
@@ -36,10 +41,6 @@ import {
36
41
  * pick step and never changes mid-flow, so the snapshot input a transition places is
37
42
  * always current — even on `preserve-state` back-navigation — which keeps the module
38
43
  * type simple (no `buildInput`-optionality quirk) and the flow fully explicit.
39
- *
40
- * This file imports the step `.vue` components, so — like `result-views.ts` — it's
41
- * registered from the client plugin, keeping the unit-tested `registry.ts` /
42
- * `*.logic.ts` import graph free of SFCs.
43
44
  */
44
45
 
45
46
  /**
@@ -52,20 +53,20 @@ export const environmentSetupModule = defineModule({
52
53
  id: ENV_MODULE_ID,
53
54
  version: '1.0.0',
54
55
  entryPoints: {
55
- pick: { mountKinds: ['journey'] as const, component: EnvPickStep },
56
+ pick: { mountKinds: ['journey'], component: EnvPickStep },
56
57
  review: {
57
- mountKinds: ['journey'] as const,
58
- allowBack: 'preserve-state' as const,
58
+ mountKinds: ['journey'],
59
+ allowBack: 'preserve-state',
59
60
  component: EnvReviewStep,
60
61
  },
61
62
  preflight: {
62
- mountKinds: ['journey'] as const,
63
- allowBack: 'preserve-state' as const,
63
+ mountKinds: ['journey'],
64
+ allowBack: 'preserve-state',
64
65
  component: EnvPreflightStep,
65
66
  },
66
67
  save: {
67
- mountKinds: ['journey'] as const,
68
- allowBack: 'preserve-state' as const,
68
+ mountKinds: ['journey'],
69
+ allowBack: 'preserve-state',
69
70
  component: EnvSaveStep,
70
71
  },
71
72
  },
@@ -75,59 +76,7 @@ export const environmentSetupModule = defineModule({
75
76
  },
76
77
  })
77
78
 
78
- type EnvModules = { [ENV_MODULE_ID]: typeof environmentSetupModule }
79
-
80
- /**
81
- * The journey definition. `start` skips the picker when a frame was preselected;
82
- * transitions are the linear pick → review → preflight → save chain, terminating
83
- * with `complete` off the save step's `advance`. Back-navigation is handled by the
84
- * entries' `allowBack`, not explicit transitions.
85
- */
86
- export const environmentSetupJourney = defineJourney<EnvModules, EnvSetupState>()({
87
- id: 'environment-setup',
88
- version: '1.0.0',
89
- initialState: (input: EnvSetupInput) => envInitialState(input),
90
- start: (state, input: EnvSetupInput) =>
91
- envStartStep(state, input) === 'review'
92
- ? ({ module: ENV_MODULE_ID, entry: 'review', input: { frameId: state.frameId } } as const)
93
- : ({ module: ENV_MODULE_ID, entry: 'pick', input: { frameId: state.frameId } } as const),
94
- transitions: {
95
- [ENV_MODULE_ID]: {
96
- pick: {
97
- [ENV_SELECT_EXIT]: (ctx) => ({
98
- next: {
99
- module: ENV_MODULE_ID,
100
- entry: 'review',
101
- input: { frameId: ctx.output.frameId },
102
- } as const,
103
- state: { frameId: ctx.output.frameId },
104
- }),
105
- },
106
- review: {
107
- [ENV_ADVANCE_EXIT]: (ctx) => ({
108
- next: {
109
- module: ENV_MODULE_ID,
110
- entry: envNextAfter('review'),
111
- input: { frameId: ctx.state.frameId },
112
- } as const,
113
- }),
114
- },
115
- preflight: {
116
- [ENV_ADVANCE_EXIT]: (ctx) => ({
117
- next: {
118
- module: ENV_MODULE_ID,
119
- entry: envNextAfter('preflight'),
120
- input: { frameId: ctx.state.frameId },
121
- } as const,
122
- }),
123
- },
124
- // `save` advances to `envNextAfter('save') === 'done'`, i.e. journey completion.
125
- save: {
126
- [ENV_ADVANCE_EXIT]: () => ({ complete: undefined }),
127
- },
128
- },
129
- },
130
- })
79
+ export { environmentSetupJourney }
131
80
 
132
81
  /** Typed launch handle — callers `runtime.start(handle, { frameId })`. */
133
82
  export const environmentSetupHandle = defineJourneyHandle(environmentSetupJourney)
@@ -24,26 +24,11 @@ function defaultConsensusConfig(): ConsensusStepConfig {
24
24
  }
25
25
 
26
26
  /**
27
- * Saved, reusable pipelines (the pipeline palette) plus the in-progress draft
28
- * being assembled in the pipeline builder. Saved pipelines live on the backend;
29
- * the draft is transient client state. The draft doubles as the EDIT surface: a
30
- * custom pipeline can be loaded into it (`loadForEdit`) and saved back in place,
31
- * while a built-in is cloned first (`clonePipeline`) into an editable copy.
27
+ * The per-step, index-aligned draft arrays. Every one is kept the same length as `draft` and
28
+ * spliced/reordered in lockstep (see `insertAt` / `removeFromDraft` / `moveUnit`), so grouping
29
+ * their construction keeps that alignment contract and its documentation in one place.
32
30
  */
33
- export const usePipelinesStore = defineStore('pipelines', () => {
34
- const api = useApi()
35
- const {
36
- items: pipelines,
37
- upsert: upsertPipeline,
38
- remove: dropPipeline,
39
- } = useUpsertList<Pipeline>({ key: (p) => p.id })
40
- /**
41
- * Current built-in catalog versions (`seedPipelines()`), keyed by pipeline id, from the
42
- * workspace snapshot. A built-in whose stored `version` is below its catalog value here has
43
- * a newer definition available (see `usePipelineHealth`).
44
- */
45
- const catalogVersions = ref<Record<string, number>>({})
46
-
31
+ function createDraftStepState() {
47
32
  /** The chain currently being assembled in the builder. */
48
33
  const draft = ref<AgentKind[]>([])
49
34
  /** Per-step approval gates, kept index-aligned with `draft`. */
@@ -79,6 +64,52 @@ export const usePipelinesStore = defineStore('pipelines', () => {
79
64
  * default, so an entry exists only when a step opts out of something.
80
65
  */
81
66
  const draftStepOptions = ref<(StepOptions | null)[]>([])
67
+ return {
68
+ draft,
69
+ draftGates,
70
+ draftEnabled,
71
+ draftThresholds,
72
+ draftConsensus,
73
+ draftGating,
74
+ draftFollowUps,
75
+ draftTesterQuality,
76
+ draftStepOptions,
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Saved, reusable pipelines (the pipeline palette) plus the in-progress draft
82
+ * being assembled in the pipeline builder. Saved pipelines live on the backend;
83
+ * the draft is transient client state. The draft doubles as the EDIT surface: a
84
+ * custom pipeline can be loaded into it (`loadForEdit`) and saved back in place,
85
+ * while a built-in is cloned first (`clonePipeline`) into an editable copy.
86
+ */
87
+ export const usePipelinesStore = defineStore('pipelines', () => {
88
+ const api = useApi()
89
+ const {
90
+ items: pipelines,
91
+ upsert: upsertPipeline,
92
+ remove: dropPipeline,
93
+ } = useUpsertList<Pipeline>({ key: (p) => p.id })
94
+ /**
95
+ * Current built-in catalog versions (`seedPipelines()`), keyed by pipeline id, from the
96
+ * workspace snapshot. A built-in whose stored `version` is below its catalog value here has
97
+ * a newer definition available (see `usePipelineHealth`).
98
+ */
99
+ const catalogVersions = ref<Record<string, number>>({})
100
+
101
+ // The per-step, index-aligned draft arrays (kept in lockstep — see `createDraftStepState`).
102
+ const {
103
+ draft,
104
+ draftGates,
105
+ draftEnabled,
106
+ draftThresholds,
107
+ draftConsensus,
108
+ draftGating,
109
+ draftFollowUps,
110
+ draftTesterQuality,
111
+ draftStepOptions,
112
+ } = createDraftStepState()
82
113
  /** Organizational labels for the pipeline being assembled/edited. */
83
114
  const draftLabels = ref<string[]>([])
84
115
  /**