@agile-vibe-coding/avc 0.1.0 → 0.2.3

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 (290) hide show
  1. package/README.md +2 -0
  2. package/cli/agent-loader.js +21 -0
  3. package/cli/agents/agent-selector.md +129 -0
  4. package/cli/agents/architecture-recommender.md +418 -0
  5. package/cli/agents/database-deep-dive.md +470 -0
  6. package/cli/agents/database-recommender.md +634 -0
  7. package/cli/agents/doc-distributor.md +176 -0
  8. package/cli/agents/documentation-updater.md +203 -0
  9. package/cli/agents/epic-story-decomposer.md +280 -0
  10. package/cli/agents/feature-context-generator.md +91 -0
  11. package/cli/agents/gap-checker-epic.md +52 -0
  12. package/cli/agents/impact-checker-story.md +51 -0
  13. package/cli/agents/migration-guide-generator.md +305 -0
  14. package/cli/agents/mission-scope-generator.md +79 -0
  15. package/cli/agents/mission-scope-validator.md +112 -0
  16. package/cli/agents/project-context-extractor.md +107 -0
  17. package/cli/agents/project-documentation-creator.json +226 -0
  18. package/cli/agents/project-documentation-creator.md +595 -0
  19. package/cli/agents/question-prefiller.md +269 -0
  20. package/cli/agents/refiner-epic.md +39 -0
  21. package/cli/agents/refiner-story.md +42 -0
  22. package/cli/agents/solver-epic-api.json +15 -0
  23. package/cli/agents/solver-epic-api.md +39 -0
  24. package/cli/agents/solver-epic-backend.json +15 -0
  25. package/cli/agents/solver-epic-backend.md +39 -0
  26. package/cli/agents/solver-epic-cloud.json +15 -0
  27. package/cli/agents/solver-epic-cloud.md +39 -0
  28. package/cli/agents/solver-epic-data.json +15 -0
  29. package/cli/agents/solver-epic-data.md +39 -0
  30. package/cli/agents/solver-epic-database.json +15 -0
  31. package/cli/agents/solver-epic-database.md +39 -0
  32. package/cli/agents/solver-epic-developer.json +15 -0
  33. package/cli/agents/solver-epic-developer.md +39 -0
  34. package/cli/agents/solver-epic-devops.json +15 -0
  35. package/cli/agents/solver-epic-devops.md +39 -0
  36. package/cli/agents/solver-epic-frontend.json +15 -0
  37. package/cli/agents/solver-epic-frontend.md +39 -0
  38. package/cli/agents/solver-epic-mobile.json +15 -0
  39. package/cli/agents/solver-epic-mobile.md +39 -0
  40. package/cli/agents/solver-epic-qa.json +15 -0
  41. package/cli/agents/solver-epic-qa.md +39 -0
  42. package/cli/agents/solver-epic-security.json +15 -0
  43. package/cli/agents/solver-epic-security.md +39 -0
  44. package/cli/agents/solver-epic-solution-architect.json +15 -0
  45. package/cli/agents/solver-epic-solution-architect.md +39 -0
  46. package/cli/agents/solver-epic-test-architect.json +15 -0
  47. package/cli/agents/solver-epic-test-architect.md +39 -0
  48. package/cli/agents/solver-epic-ui.json +15 -0
  49. package/cli/agents/solver-epic-ui.md +39 -0
  50. package/cli/agents/solver-epic-ux.json +15 -0
  51. package/cli/agents/solver-epic-ux.md +39 -0
  52. package/cli/agents/solver-story-api.json +15 -0
  53. package/cli/agents/solver-story-api.md +39 -0
  54. package/cli/agents/solver-story-backend.json +15 -0
  55. package/cli/agents/solver-story-backend.md +39 -0
  56. package/cli/agents/solver-story-cloud.json +15 -0
  57. package/cli/agents/solver-story-cloud.md +39 -0
  58. package/cli/agents/solver-story-data.json +15 -0
  59. package/cli/agents/solver-story-data.md +39 -0
  60. package/cli/agents/solver-story-database.json +15 -0
  61. package/cli/agents/solver-story-database.md +39 -0
  62. package/cli/agents/solver-story-developer.json +15 -0
  63. package/cli/agents/solver-story-developer.md +39 -0
  64. package/cli/agents/solver-story-devops.json +15 -0
  65. package/cli/agents/solver-story-devops.md +39 -0
  66. package/cli/agents/solver-story-frontend.json +15 -0
  67. package/cli/agents/solver-story-frontend.md +39 -0
  68. package/cli/agents/solver-story-mobile.json +15 -0
  69. package/cli/agents/solver-story-mobile.md +39 -0
  70. package/cli/agents/solver-story-qa.json +15 -0
  71. package/cli/agents/solver-story-qa.md +39 -0
  72. package/cli/agents/solver-story-security.json +15 -0
  73. package/cli/agents/solver-story-security.md +39 -0
  74. package/cli/agents/solver-story-solution-architect.json +15 -0
  75. package/cli/agents/solver-story-solution-architect.md +39 -0
  76. package/cli/agents/solver-story-test-architect.json +15 -0
  77. package/cli/agents/solver-story-test-architect.md +39 -0
  78. package/cli/agents/solver-story-ui.json +15 -0
  79. package/cli/agents/solver-story-ui.md +39 -0
  80. package/cli/agents/solver-story-ux.json +15 -0
  81. package/cli/agents/solver-story-ux.md +39 -0
  82. package/cli/agents/story-doc-enricher.md +133 -0
  83. package/cli/agents/suggestion-business-analyst.md +88 -0
  84. package/cli/agents/suggestion-deployment-architect.md +263 -0
  85. package/cli/agents/suggestion-product-manager.md +129 -0
  86. package/cli/agents/suggestion-security-specialist.md +156 -0
  87. package/cli/agents/suggestion-technical-architect.md +269 -0
  88. package/cli/agents/suggestion-ux-researcher.md +93 -0
  89. package/cli/agents/task-subtask-decomposer.md +188 -0
  90. package/cli/agents/validator-documentation.json +152 -0
  91. package/cli/agents/validator-documentation.md +453 -0
  92. package/cli/agents/validator-epic-api.json +93 -0
  93. package/cli/agents/validator-epic-api.md +137 -0
  94. package/cli/agents/validator-epic-backend.json +93 -0
  95. package/cli/agents/validator-epic-backend.md +130 -0
  96. package/cli/agents/validator-epic-cloud.json +93 -0
  97. package/cli/agents/validator-epic-cloud.md +137 -0
  98. package/cli/agents/validator-epic-data.json +93 -0
  99. package/cli/agents/validator-epic-data.md +130 -0
  100. package/cli/agents/validator-epic-database.json +93 -0
  101. package/cli/agents/validator-epic-database.md +137 -0
  102. package/cli/agents/validator-epic-developer.json +74 -0
  103. package/cli/agents/validator-epic-developer.md +153 -0
  104. package/cli/agents/validator-epic-devops.json +74 -0
  105. package/cli/agents/validator-epic-devops.md +153 -0
  106. package/cli/agents/validator-epic-frontend.json +74 -0
  107. package/cli/agents/validator-epic-frontend.md +153 -0
  108. package/cli/agents/validator-epic-mobile.json +93 -0
  109. package/cli/agents/validator-epic-mobile.md +130 -0
  110. package/cli/agents/validator-epic-qa.json +93 -0
  111. package/cli/agents/validator-epic-qa.md +130 -0
  112. package/cli/agents/validator-epic-security.json +74 -0
  113. package/cli/agents/validator-epic-security.md +154 -0
  114. package/cli/agents/validator-epic-solution-architect.json +74 -0
  115. package/cli/agents/validator-epic-solution-architect.md +156 -0
  116. package/cli/agents/validator-epic-test-architect.json +93 -0
  117. package/cli/agents/validator-epic-test-architect.md +130 -0
  118. package/cli/agents/validator-epic-ui.json +93 -0
  119. package/cli/agents/validator-epic-ui.md +130 -0
  120. package/cli/agents/validator-epic-ux.json +93 -0
  121. package/cli/agents/validator-epic-ux.md +130 -0
  122. package/cli/agents/validator-selector.md +211 -0
  123. package/cli/agents/validator-story-api.json +104 -0
  124. package/cli/agents/validator-story-api.md +152 -0
  125. package/cli/agents/validator-story-backend.json +104 -0
  126. package/cli/agents/validator-story-backend.md +152 -0
  127. package/cli/agents/validator-story-cloud.json +104 -0
  128. package/cli/agents/validator-story-cloud.md +152 -0
  129. package/cli/agents/validator-story-data.json +104 -0
  130. package/cli/agents/validator-story-data.md +152 -0
  131. package/cli/agents/validator-story-database.json +104 -0
  132. package/cli/agents/validator-story-database.md +152 -0
  133. package/cli/agents/validator-story-developer.json +104 -0
  134. package/cli/agents/validator-story-developer.md +152 -0
  135. package/cli/agents/validator-story-devops.json +104 -0
  136. package/cli/agents/validator-story-devops.md +152 -0
  137. package/cli/agents/validator-story-frontend.json +104 -0
  138. package/cli/agents/validator-story-frontend.md +152 -0
  139. package/cli/agents/validator-story-mobile.json +104 -0
  140. package/cli/agents/validator-story-mobile.md +152 -0
  141. package/cli/agents/validator-story-qa.json +104 -0
  142. package/cli/agents/validator-story-qa.md +152 -0
  143. package/cli/agents/validator-story-security.json +104 -0
  144. package/cli/agents/validator-story-security.md +152 -0
  145. package/cli/agents/validator-story-solution-architect.json +104 -0
  146. package/cli/agents/validator-story-solution-architect.md +152 -0
  147. package/cli/agents/validator-story-test-architect.json +104 -0
  148. package/cli/agents/validator-story-test-architect.md +152 -0
  149. package/cli/agents/validator-story-ui.json +104 -0
  150. package/cli/agents/validator-story-ui.md +152 -0
  151. package/cli/agents/validator-story-ux.json +104 -0
  152. package/cli/agents/validator-story-ux.md +152 -0
  153. package/cli/ansi-colors.js +21 -0
  154. package/cli/build-docs.js +298 -0
  155. package/cli/ceremony-history.js +369 -0
  156. package/cli/command-logger.js +245 -0
  157. package/cli/components/static-output.js +63 -0
  158. package/cli/console-output-manager.js +94 -0
  159. package/cli/docs-sync.js +306 -0
  160. package/cli/epic-story-validator.js +1174 -0
  161. package/cli/evaluation-prompts.js +1008 -0
  162. package/cli/execution-context.js +195 -0
  163. package/cli/generate-summary-table.js +340 -0
  164. package/cli/index.js +3 -25
  165. package/cli/init-model-config.js +697 -0
  166. package/cli/init.js +1765 -100
  167. package/cli/kanban-server-manager.js +228 -0
  168. package/cli/llm-claude.js +109 -0
  169. package/cli/llm-gemini.js +115 -0
  170. package/cli/llm-mock.js +233 -0
  171. package/cli/llm-openai.js +233 -0
  172. package/cli/llm-provider.js +300 -0
  173. package/cli/llm-token-limits.js +102 -0
  174. package/cli/llm-verifier.js +454 -0
  175. package/cli/logger.js +32 -5
  176. package/cli/message-constants.js +58 -0
  177. package/cli/message-manager.js +334 -0
  178. package/cli/message-types.js +96 -0
  179. package/cli/messaging-api.js +297 -0
  180. package/cli/model-pricing.js +169 -0
  181. package/cli/model-query-engine.js +468 -0
  182. package/cli/model-recommendation-analyzer.js +495 -0
  183. package/cli/model-selector.js +269 -0
  184. package/cli/output-buffer.js +107 -0
  185. package/cli/process-manager.js +332 -0
  186. package/cli/repl-ink.js +5840 -504
  187. package/cli/repl-old.js +4 -4
  188. package/cli/seed-processor.js +792 -0
  189. package/cli/sprint-planning-processor.js +1813 -0
  190. package/cli/template-processor.js +2306 -108
  191. package/cli/templates/project.md +25 -8
  192. package/cli/templates/vitepress-config.mts.template +34 -0
  193. package/cli/token-tracker.js +520 -0
  194. package/cli/tools/generate-story-validators.js +317 -0
  195. package/cli/tools/generate-validators.js +669 -0
  196. package/cli/update-checker.js +19 -17
  197. package/cli/update-notifier.js +4 -4
  198. package/cli/validation-router.js +605 -0
  199. package/cli/verification-tracker.js +563 -0
  200. package/kanban/README.md +386 -0
  201. package/kanban/client/README.md +205 -0
  202. package/kanban/client/components.json +20 -0
  203. package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
  204. package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
  205. package/kanban/client/dist/index.html +16 -0
  206. package/kanban/client/dist/vite.svg +1 -0
  207. package/kanban/client/index.html +15 -0
  208. package/kanban/client/package-lock.json +9442 -0
  209. package/kanban/client/package.json +44 -0
  210. package/kanban/client/postcss.config.js +6 -0
  211. package/kanban/client/public/vite.svg +1 -0
  212. package/kanban/client/src/App.jsx +622 -0
  213. package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
  214. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
  215. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
  216. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
  217. package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
  218. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
  219. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
  220. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
  221. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
  222. package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
  223. package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
  224. package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
  225. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
  226. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
  227. package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
  228. package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
  229. package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
  230. package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
  231. package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
  232. package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
  233. package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
  234. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
  235. package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
  236. package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
  237. package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
  238. package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
  239. package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
  240. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
  241. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
  242. package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
  243. package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
  244. package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
  245. package/kanban/client/src/components/stats/CostModal.jsx +353 -0
  246. package/kanban/client/src/components/ui/badge.jsx +27 -0
  247. package/kanban/client/src/components/ui/dialog.jsx +121 -0
  248. package/kanban/client/src/components/ui/tabs.jsx +85 -0
  249. package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
  250. package/kanban/client/src/hooks/useGrouping.js +118 -0
  251. package/kanban/client/src/hooks/useWebSocket.js +120 -0
  252. package/kanban/client/src/lib/__tests__/api.test.js +196 -0
  253. package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
  254. package/kanban/client/src/lib/api.js +401 -0
  255. package/kanban/client/src/lib/status-grouping.js +144 -0
  256. package/kanban/client/src/lib/utils.js +11 -0
  257. package/kanban/client/src/main.jsx +10 -0
  258. package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
  259. package/kanban/client/src/store/ceremonyStore.js +172 -0
  260. package/kanban/client/src/store/filterStore.js +201 -0
  261. package/kanban/client/src/store/kanbanStore.js +115 -0
  262. package/kanban/client/src/store/processStore.js +65 -0
  263. package/kanban/client/src/store/sprintPlanningStore.js +33 -0
  264. package/kanban/client/src/styles/globals.css +59 -0
  265. package/kanban/client/tailwind.config.js +77 -0
  266. package/kanban/client/vite.config.js +28 -0
  267. package/kanban/client/vitest.config.js +28 -0
  268. package/kanban/dev-start.sh +47 -0
  269. package/kanban/package.json +12 -0
  270. package/kanban/server/index.js +516 -0
  271. package/kanban/server/routes/ceremony.js +305 -0
  272. package/kanban/server/routes/costs.js +157 -0
  273. package/kanban/server/routes/processes.js +50 -0
  274. package/kanban/server/routes/settings.js +303 -0
  275. package/kanban/server/routes/websocket.js +276 -0
  276. package/kanban/server/routes/work-items.js +347 -0
  277. package/kanban/server/services/CeremonyService.js +1190 -0
  278. package/kanban/server/services/FileSystemScanner.js +95 -0
  279. package/kanban/server/services/FileWatcher.js +144 -0
  280. package/kanban/server/services/HierarchyBuilder.js +196 -0
  281. package/kanban/server/services/ProcessRegistry.js +122 -0
  282. package/kanban/server/services/WorkItemReader.js +123 -0
  283. package/kanban/server/services/WorkItemRefineService.js +510 -0
  284. package/kanban/server/start.js +49 -0
  285. package/kanban/server/utils/kanban-logger.js +132 -0
  286. package/kanban/server/utils/markdown.js +91 -0
  287. package/kanban/server/utils/status-grouping.js +107 -0
  288. package/kanban/server/workers/sponsor-call-worker.js +84 -0
  289. package/kanban/server/workers/sprint-planning-worker.js +130 -0
  290. package/package.json +34 -7
@@ -0,0 +1,164 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { useKanbanStore } from '../kanbanStore';
3
+ import * as api from '../../lib/api';
4
+
5
+ // Mock the API module
6
+ vi.mock('../../lib/api', () => ({
7
+ getWorkItems: vi.fn(),
8
+ }));
9
+
10
+ describe('kanbanStore', () => {
11
+ beforeEach(() => {
12
+ // Reset store state before each test
13
+ useKanbanStore.setState({
14
+ workItems: [],
15
+ loading: false,
16
+ error: null,
17
+ });
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ describe('initial state', () => {
22
+ it('should have empty work items array', () => {
23
+ const state = useKanbanStore.getState();
24
+ expect(state.workItems).toEqual([]);
25
+ });
26
+
27
+ it('should not be loading initially', () => {
28
+ const state = useKanbanStore.getState();
29
+ expect(state.loading).toBe(false);
30
+ });
31
+
32
+ it('should have no error initially', () => {
33
+ const state = useKanbanStore.getState();
34
+ expect(state.error).toBeNull();
35
+ });
36
+ });
37
+
38
+ describe('loadWorkItems', () => {
39
+ it('should load work items successfully', async () => {
40
+ const mockItems = [
41
+ { id: 'EPIC-001', type: 'epic', status: 'implementing' },
42
+ { id: 'STORY-001', type: 'story', status: 'ready' },
43
+ ];
44
+
45
+ api.getWorkItems.mockResolvedValueOnce({ items: mockItems });
46
+
47
+ const { loadWorkItems } = useKanbanStore.getState();
48
+ await loadWorkItems();
49
+
50
+ const state = useKanbanStore.getState();
51
+ expect(state.workItems).toEqual(mockItems);
52
+ expect(state.loading).toBe(false);
53
+ expect(state.error).toBeNull();
54
+ });
55
+
56
+ it('should set loading state during fetch', async () => {
57
+ api.getWorkItems.mockImplementation(() => {
58
+ // Check loading state while promise is pending
59
+ const state = useKanbanStore.getState();
60
+ expect(state.loading).toBe(true);
61
+ return Promise.resolve({ items: [] });
62
+ });
63
+
64
+ const { loadWorkItems } = useKanbanStore.getState();
65
+ await loadWorkItems();
66
+ });
67
+
68
+ it('should handle errors gracefully', async () => {
69
+ const error = new Error('Failed to fetch');
70
+ api.getWorkItems.mockRejectedValueOnce(error);
71
+
72
+ const { loadWorkItems } = useKanbanStore.getState();
73
+ await loadWorkItems();
74
+
75
+ const state = useKanbanStore.getState();
76
+ expect(state.workItems).toEqual([]);
77
+ expect(state.loading).toBe(false);
78
+ expect(state.error).toBe('Failed to fetch');
79
+ });
80
+
81
+ it('should pass filters to API', async () => {
82
+ api.getWorkItems.mockResolvedValueOnce({ items: [] });
83
+
84
+ const { loadWorkItems } = useKanbanStore.getState();
85
+ await loadWorkItems({ type: 'epic', status: 'ready' });
86
+
87
+ expect(api.getWorkItems).toHaveBeenCalledWith({ type: 'epic', status: 'ready' });
88
+ });
89
+ });
90
+
91
+ describe('updateWorkItem', () => {
92
+ it('should update existing work item', () => {
93
+ const initialItems = [
94
+ { id: 'EPIC-001', name: 'Old Name', status: 'planned' },
95
+ { id: 'STORY-001', name: 'Story', status: 'ready' },
96
+ ];
97
+
98
+ useKanbanStore.setState({ workItems: initialItems });
99
+
100
+ const { updateWorkItem } = useKanbanStore.getState();
101
+ updateWorkItem('EPIC-001', { name: 'New Name', status: 'implementing' });
102
+
103
+ const state = useKanbanStore.getState();
104
+ expect(state.workItems[0]).toEqual({
105
+ id: 'EPIC-001',
106
+ name: 'New Name',
107
+ status: 'implementing',
108
+ });
109
+ expect(state.workItems[1]).toEqual(initialItems[1]); // Unchanged
110
+ });
111
+
112
+ it('should not modify state if item not found', () => {
113
+ const initialItems = [{ id: 'EPIC-001', name: 'Epic', status: 'planned' }];
114
+
115
+ useKanbanStore.setState({ workItems: initialItems });
116
+
117
+ const { updateWorkItem } = useKanbanStore.getState();
118
+ updateWorkItem('NONEXISTENT', { name: 'New Name' });
119
+
120
+ const state = useKanbanStore.getState();
121
+ expect(state.workItems).toEqual(initialItems);
122
+ });
123
+
124
+ it('should merge updates with existing properties', () => {
125
+ const initialItems = [
126
+ {
127
+ id: 'EPIC-001',
128
+ name: 'Epic',
129
+ status: 'planned',
130
+ description: 'Description',
131
+ type: 'epic',
132
+ },
133
+ ];
134
+
135
+ useKanbanStore.setState({ workItems: initialItems });
136
+
137
+ const { updateWorkItem } = useKanbanStore.getState();
138
+ updateWorkItem('EPIC-001', { status: 'implementing' });
139
+
140
+ const state = useKanbanStore.getState();
141
+ expect(state.workItems[0]).toEqual({
142
+ id: 'EPIC-001',
143
+ name: 'Epic',
144
+ status: 'implementing', // Updated
145
+ description: 'Description', // Preserved
146
+ type: 'epic', // Preserved
147
+ });
148
+ });
149
+ });
150
+
151
+ describe('refresh', () => {
152
+ it('should reload work items', async () => {
153
+ const mockItems = [{ id: 'EPIC-001', type: 'epic' }];
154
+ api.getWorkItems.mockResolvedValueOnce({ items: mockItems });
155
+
156
+ const { refresh } = useKanbanStore.getState();
157
+ await refresh();
158
+
159
+ const state = useKanbanStore.getState();
160
+ expect(state.workItems).toEqual(mockItems);
161
+ expect(api.getWorkItems).toHaveBeenCalled();
162
+ });
163
+ });
164
+ });
@@ -0,0 +1,172 @@
1
+ import { create } from 'zustand';
2
+
3
+ /**
4
+ * Ceremony Store
5
+ * Manages the sponsor-call wizard state (not persisted).
6
+ */
7
+ export const useCeremonyStore = create((set, get) => ({
8
+ // ── Modal open/close ───────────────────────────────────────────────────────
9
+ isOpen: false,
10
+
11
+ // ── Wizard navigation ──────────────────────────────────────────────────────
12
+ wizardStep: 1,
13
+ analyzing: false, // true while an analyze API call is in-flight
14
+
15
+ // ── Step 1: Deployment strategy ───────────────────────────────────────────
16
+ strategy: null, // 'local-mvp' | 'cloud'
17
+
18
+ // ── Step 2: Mission & Scope ───────────────────────────────────────────────
19
+ mission: '',
20
+ initialScope: '',
21
+
22
+ // ── Step 3: Database ──────────────────────────────────────────────────────
23
+ dbResult: null, // API response from analyze/database
24
+ dbChoice: null, // 'sql' | 'nosql' (user selection)
25
+
26
+ // ── Step 4: Architecture ──────────────────────────────────────────────────
27
+ archOptions: [], // array of architecture objects from analyze/architecture
28
+ selectedArch: null, // chosen architecture object
29
+
30
+ // ── Step 5: Review & Edit ─────────────────────────────────────────────────
31
+ prefillResult: null, // API response from analyze/prefill
32
+
33
+ // ── Requirements (all 7 template variables) ───────────────────────────────
34
+ requirements: {
35
+ MISSION_STATEMENT: '',
36
+ INITIAL_SCOPE: '',
37
+ TARGET_USERS: '',
38
+ DEPLOYMENT_TARGET: '',
39
+ TECHNICAL_CONSIDERATIONS: '',
40
+ TECHNICAL_EXCLUSIONS: '',
41
+ SECURITY_AND_COMPLIANCE_REQUIREMENTS: '',
42
+ },
43
+
44
+ // ── Mission generator progress ─────────────────────────────────────────────
45
+ missionProgressLog: [], // { step, message }
46
+
47
+ // ── Steps 6-7: Running / Complete ─────────────────────────────────────────
48
+ progressLog: [], // { type:'progress'|'substep', message?, substep?, meta? }
49
+ ceremonyStatus: 'idle', // 'idle' | 'running' | 'complete' | 'error'
50
+ ceremonyResult: null,
51
+ ceremonyError: null,
52
+ isPaused: false,
53
+ processId: null, // active fork processId (set after run starts)
54
+
55
+ // ── Actions ────────────────────────────────────────────────────────────────
56
+
57
+ openWizard: () => set({ isOpen: true }),
58
+
59
+ closeWizard: () => set({ isOpen: false }),
60
+
61
+ // Reopen without resetting state — used by ProcessMonitorBar chip click
62
+ reopenWizard: () => set((s) => ({
63
+ isOpen: true,
64
+ wizardStep: s.ceremonyStatus === 'complete' ? 7 : 6,
65
+ })),
66
+
67
+ resetWizard: () =>
68
+ set({
69
+ wizardStep: 1,
70
+ analyzing: false,
71
+ strategy: null,
72
+ mission: '',
73
+ initialScope: '',
74
+ dbResult: null,
75
+ dbChoice: null,
76
+ archOptions: [],
77
+ selectedArch: null,
78
+ prefillResult: null,
79
+ requirements: {
80
+ MISSION_STATEMENT: '',
81
+ INITIAL_SCOPE: '',
82
+ TARGET_USERS: '',
83
+ DEPLOYMENT_TARGET: '',
84
+ TECHNICAL_CONSIDERATIONS: '',
85
+ TECHNICAL_EXCLUSIONS: '',
86
+ SECURITY_AND_COMPLIANCE_REQUIREMENTS: '',
87
+ },
88
+ progressLog: [],
89
+ ceremonyStatus: 'idle',
90
+ ceremonyResult: null,
91
+ ceremonyError: null,
92
+ }),
93
+
94
+ setStrategy: (strategy) => set({ strategy }),
95
+
96
+ setMission: (mission) => set({ mission }),
97
+
98
+ setInitialScope: (initialScope) => set({ initialScope }),
99
+
100
+ setDbResult: (dbResult) => set({ dbResult }),
101
+
102
+ setDbChoice: (dbChoice) => set({ dbChoice }),
103
+
104
+ setArchOptions: (archOptions) => set({ archOptions }),
105
+
106
+ setSelectedArch: (selectedArch) => set({ selectedArch }),
107
+
108
+ setPrefillResult: (prefillResult) => set({ prefillResult }),
109
+
110
+ setAnalyzing: (analyzing) => set({ analyzing }),
111
+
112
+ setWizardStep: (wizardStep) => set({ wizardStep }),
113
+
114
+ updateRequirement: (key, value) =>
115
+ set((state) => ({
116
+ requirements: { ...state.requirements, [key]: value },
117
+ })),
118
+
119
+ setRequirements: (requirements) => set({ requirements }),
120
+
121
+ // Called from App.jsx WebSocket message handler
122
+ appendProgress: (entry) =>
123
+ set((state) => ({
124
+ progressLog: [...state.progressLog, entry],
125
+ })),
126
+
127
+ setProgressLog: (entries) => set({ progressLog: Array.isArray(entries) ? entries : [] }),
128
+
129
+ appendMissionProgress: (entry) =>
130
+ set((state) => ({
131
+ missionProgressLog: [...state.missionProgressLog, entry],
132
+ })),
133
+
134
+ clearMissionProgress: () => set({ missionProgressLog: [] }),
135
+
136
+ setCeremonyStatus: (ceremonyStatus) => set({ ceremonyStatus }),
137
+
138
+ setCeremonyResult: (ceremonyResult) => set({ ceremonyResult }),
139
+
140
+ setCeremonyError: (ceremonyError) => set({ ceremonyError }),
141
+
142
+ setPaused: (isPaused) => set({ isPaused }),
143
+
144
+ setProcessId: (processId) => set({ processId }),
145
+
146
+ // Sync requirements from prefill result + step 1-2 data
147
+ applyPrefill: (prefillResult, strategy, mission, initialScope) => {
148
+ set((state) => ({
149
+ prefillResult,
150
+ requirements: {
151
+ ...state.requirements,
152
+ MISSION_STATEMENT: mission,
153
+ INITIAL_SCOPE: initialScope,
154
+ TARGET_USERS: prefillResult.TARGET_USERS || '',
155
+ DEPLOYMENT_TARGET: prefillResult.DEPLOYMENT_TARGET || '',
156
+ TECHNICAL_CONSIDERATIONS: prefillResult.TECHNICAL_CONSIDERATIONS || '',
157
+ SECURITY_AND_COMPLIANCE_REQUIREMENTS:
158
+ prefillResult.SECURITY_AND_COMPLIANCE_REQUIREMENTS || '',
159
+ // TECHNICAL_EXCLUSIONS stays as user entered (empty by default)
160
+ },
161
+ }));
162
+ },
163
+
164
+ // Initialize ceremony run
165
+ startRun: () =>
166
+ set({
167
+ ceremonyStatus: 'running',
168
+ progressLog: [],
169
+ ceremonyResult: null,
170
+ ceremonyError: null,
171
+ }),
172
+ }));
@@ -0,0 +1,201 @@
1
+ import { create } from 'zustand';
2
+ import { persist } from 'zustand/middleware';
3
+
4
+ /**
5
+ * Filter Store
6
+ * Manages filters, grouping, and search state
7
+ * Persisted to localStorage
8
+ */
9
+ export const useFilterStore = create(
10
+ persist(
11
+ (set, get) => ({
12
+ // State
13
+ typeFilters: {
14
+ epic: true,
15
+ story: true,
16
+ task: true,
17
+ subtask: true,
18
+ },
19
+ columnVisibility: {
20
+ Backlog: true,
21
+ Ready: true,
22
+ 'In Progress': true,
23
+ Review: true,
24
+ Done: true,
25
+ },
26
+ searchQuery: '',
27
+ groupBy: 'epic', // 'status' | 'epic' | 'type' | 'category'
28
+
29
+ // Actions
30
+
31
+ /**
32
+ * Toggle type filter
33
+ * @param {string} type - Work item type
34
+ */
35
+ toggleTypeFilter: (type) => {
36
+ set((state) => ({
37
+ typeFilters: {
38
+ ...state.typeFilters,
39
+ [type]: !state.typeFilters[type],
40
+ },
41
+ }));
42
+ },
43
+
44
+ /**
45
+ * Set all type filters
46
+ * @param {boolean} value - Enable or disable all
47
+ */
48
+ setAllTypeFilters: (value) => {
49
+ set({
50
+ typeFilters: {
51
+ epic: value,
52
+ story: value,
53
+ task: value,
54
+ subtask: value,
55
+ },
56
+ });
57
+ },
58
+
59
+ /**
60
+ * Toggle column visibility
61
+ * @param {string} column - Column name
62
+ */
63
+ toggleColumnVisibility: (column) => {
64
+ set((state) => ({
65
+ columnVisibility: {
66
+ ...state.columnVisibility,
67
+ [column]: !state.columnVisibility[column],
68
+ },
69
+ }));
70
+ },
71
+
72
+ /**
73
+ * Set all column visibility
74
+ * @param {boolean} value - Show or hide all
75
+ */
76
+ setAllColumnsVisibility: (value) => {
77
+ set((state) => {
78
+ const updated = {};
79
+ Object.keys(state.columnVisibility).forEach((col) => {
80
+ updated[col] = value;
81
+ });
82
+ return { columnVisibility: updated };
83
+ });
84
+ },
85
+
86
+ /**
87
+ * Apply preset filter
88
+ * @param {string} preset - Preset name
89
+ */
90
+ applyPreset: (preset) => {
91
+ switch (preset) {
92
+ case 'all':
93
+ get().setAllColumnsVisibility(true);
94
+ get().setAllTypeFilters(true);
95
+ break;
96
+ case 'active':
97
+ set({
98
+ columnVisibility: {
99
+ Backlog: false,
100
+ Ready: true,
101
+ 'In Progress': true,
102
+ Review: true,
103
+ Done: false,
104
+ },
105
+ });
106
+ break;
107
+ case 'hide-completed':
108
+ set({
109
+ columnVisibility: {
110
+ Backlog: true,
111
+ Ready: true,
112
+ 'In Progress': true,
113
+ Review: true,
114
+ Done: false,
115
+ },
116
+ });
117
+ break;
118
+ default:
119
+ break;
120
+ }
121
+ },
122
+
123
+ /**
124
+ * Set search query
125
+ * @param {string} query - Search query
126
+ */
127
+ setSearchQuery: (query) => {
128
+ set({ searchQuery: query });
129
+ },
130
+
131
+ /**
132
+ * Clear search query
133
+ */
134
+ clearSearch: () => {
135
+ set({ searchQuery: '' });
136
+ },
137
+
138
+ /**
139
+ * Set grouping mode
140
+ * @param {string} mode - Grouping mode
141
+ */
142
+ setGroupBy: (mode) => {
143
+ set({ groupBy: mode });
144
+ },
145
+
146
+ /**
147
+ * Get active type filters
148
+ * @returns {string[]} Array of active types
149
+ */
150
+ getActiveTypes: () => {
151
+ const { typeFilters } = get();
152
+ return Object.entries(typeFilters)
153
+ .filter(([_, enabled]) => enabled)
154
+ .map(([type]) => type);
155
+ },
156
+
157
+ /**
158
+ * Get visible columns
159
+ * @returns {string[]} Array of visible column names
160
+ */
161
+ getVisibleColumns: () => {
162
+ const { columnVisibility } = get();
163
+ return Object.entries(columnVisibility)
164
+ .filter(([_, visible]) => visible)
165
+ .map(([column]) => column);
166
+ },
167
+
168
+ /**
169
+ * Reset all filters to defaults
170
+ */
171
+ resetFilters: () => {
172
+ set({
173
+ typeFilters: {
174
+ epic: true,
175
+ story: true,
176
+ task: true,
177
+ subtask: true,
178
+ },
179
+ columnVisibility: {
180
+ Backlog: true,
181
+ Ready: true,
182
+ 'In Progress': true,
183
+ Review: true,
184
+ Done: true,
185
+ },
186
+ searchQuery: '',
187
+ groupBy: 'epic',
188
+ });
189
+ },
190
+ }),
191
+ {
192
+ name: 'avc-kanban-filters', // localStorage key
193
+ partialize: (state) => ({
194
+ // Only persist these fields
195
+ typeFilters: state.typeFilters,
196
+ columnVisibility: state.columnVisibility,
197
+ groupBy: state.groupBy,
198
+ }),
199
+ }
200
+ )
201
+ );
@@ -0,0 +1,115 @@
1
+ import { create } from 'zustand';
2
+ import { getWorkItems, getWorkItemsGrouped } from '../lib/api';
3
+
4
+ /**
5
+ * Kanban Store
6
+ * Manages work items, loading states, and data fetching
7
+ */
8
+ export const useKanbanStore = create((set, get) => ({
9
+ // State
10
+ workItems: [],
11
+ groupedItems: {},
12
+ loading: false,
13
+ error: null,
14
+ lastUpdated: null,
15
+
16
+ // Actions
17
+
18
+ /**
19
+ * Load all work items
20
+ * @param {object} filters - Optional filters
21
+ */
22
+ loadWorkItems: async (filters = {}) => {
23
+ set({ loading: true, error: null });
24
+
25
+ try {
26
+ const data = await getWorkItems(filters);
27
+ set({
28
+ workItems: data.items || [],
29
+ loading: false,
30
+ lastUpdated: Date.now(),
31
+ error: null,
32
+ });
33
+ } catch (error) {
34
+ set({
35
+ loading: false,
36
+ error: error.message,
37
+ });
38
+ console.error('Failed to load work items:', error);
39
+ }
40
+ },
41
+
42
+ /**
43
+ * Load work items grouped by column
44
+ */
45
+ loadGroupedItems: async () => {
46
+ set({ loading: true, error: null });
47
+
48
+ try {
49
+ const data = await getWorkItemsGrouped();
50
+ set({
51
+ groupedItems: data,
52
+ loading: false,
53
+ lastUpdated: Date.now(),
54
+ error: null,
55
+ });
56
+ } catch (error) {
57
+ set({
58
+ loading: false,
59
+ error: error.message,
60
+ });
61
+ console.error('Failed to load grouped items:', error);
62
+ }
63
+ },
64
+
65
+ /**
66
+ * Refresh work items (re-fetch from server)
67
+ */
68
+ refresh: async () => {
69
+ const { loadWorkItems } = get();
70
+ await loadWorkItems();
71
+ },
72
+
73
+ /**
74
+ * Update a single work item in the store
75
+ * Used for WebSocket updates
76
+ * @param {string} id - Work item ID
77
+ * @param {object} updatedItem - Updated work item data
78
+ */
79
+ updateWorkItem: (id, updatedItem) => {
80
+ set((state) => ({
81
+ workItems: state.workItems.map((item) =>
82
+ item.id === id ? { ...item, ...updatedItem } : item
83
+ ),
84
+ }));
85
+ },
86
+
87
+ /**
88
+ * Add a new work item to the store
89
+ * Used for WebSocket updates
90
+ * @param {object} newItem - New work item
91
+ */
92
+ addWorkItem: (newItem) => {
93
+ set((state) => ({
94
+ workItems: [...state.workItems, newItem],
95
+ }));
96
+ },
97
+
98
+ /**
99
+ * Remove a work item from the store
100
+ * Used for WebSocket updates
101
+ * @param {string} id - Work item ID to remove
102
+ */
103
+ removeWorkItem: (id) => {
104
+ set((state) => ({
105
+ workItems: state.workItems.filter((item) => item.id !== id),
106
+ }));
107
+ },
108
+
109
+ /**
110
+ * Clear error state
111
+ */
112
+ clearError: () => {
113
+ set({ error: null });
114
+ },
115
+ }));