@agile-vibe-coding/avc 0.1.1 → 0.3.1

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 (239) hide show
  1. package/cli/agent-loader.js +21 -0
  2. package/cli/agents/agent-selector.md +152 -0
  3. package/cli/agents/architecture-recommender.md +418 -0
  4. package/cli/agents/code-implementer.md +117 -0
  5. package/cli/agents/code-validator.md +80 -0
  6. package/cli/agents/context-reviewer-epic.md +101 -0
  7. package/cli/agents/context-reviewer-story.md +92 -0
  8. package/cli/agents/context-writer-epic.md +145 -0
  9. package/cli/agents/context-writer-story.md +111 -0
  10. package/cli/agents/database-deep-dive.md +470 -0
  11. package/cli/agents/database-recommender.md +634 -0
  12. package/cli/agents/doc-distributor.md +176 -0
  13. package/cli/agents/doc-writer-epic.md +42 -0
  14. package/cli/agents/doc-writer-story.md +43 -0
  15. package/cli/agents/documentation-updater.md +203 -0
  16. package/cli/agents/duplicate-detector.md +110 -0
  17. package/cli/agents/epic-story-decomposer.md +559 -0
  18. package/cli/agents/feature-context-generator.md +91 -0
  19. package/cli/agents/gap-checker-epic.md +52 -0
  20. package/cli/agents/impact-checker-story.md +51 -0
  21. package/cli/agents/migration-guide-generator.md +305 -0
  22. package/cli/agents/mission-scope-generator.md +143 -0
  23. package/cli/agents/mission-scope-validator.md +146 -0
  24. package/cli/agents/project-context-extractor.md +122 -0
  25. package/cli/agents/project-documentation-creator.json +226 -0
  26. package/cli/agents/project-documentation-creator.md +595 -0
  27. package/cli/agents/question-prefiller.md +269 -0
  28. package/cli/agents/refiner-epic.md +39 -0
  29. package/cli/agents/refiner-story.md +42 -0
  30. package/cli/agents/scaffolding-generator.md +99 -0
  31. package/cli/agents/seed-validator.md +71 -0
  32. package/cli/agents/story-doc-enricher.md +133 -0
  33. package/cli/agents/story-scope-reviewer.md +147 -0
  34. package/cli/agents/story-splitter.md +83 -0
  35. package/cli/agents/suggestion-business-analyst.md +88 -0
  36. package/cli/agents/suggestion-deployment-architect.md +263 -0
  37. package/cli/agents/suggestion-product-manager.md +129 -0
  38. package/cli/agents/suggestion-security-specialist.md +156 -0
  39. package/cli/agents/suggestion-technical-architect.md +269 -0
  40. package/cli/agents/suggestion-ux-researcher.md +93 -0
  41. package/cli/agents/task-subtask-decomposer.md +188 -0
  42. package/cli/agents/validator-documentation.json +183 -0
  43. package/cli/agents/validator-documentation.md +455 -0
  44. package/cli/agents/validator-selector.md +211 -0
  45. package/cli/ansi-colors.js +21 -0
  46. package/cli/api-reference-tool.js +368 -0
  47. package/cli/build-docs.js +29 -8
  48. package/cli/ceremony-history.js +369 -0
  49. package/cli/checks/catalog.json +76 -0
  50. package/cli/checks/code/quality.json +26 -0
  51. package/cli/checks/code/testing.json +14 -0
  52. package/cli/checks/code/traceability.json +26 -0
  53. package/cli/checks/cross-refs/epic.json +171 -0
  54. package/cli/checks/cross-refs/story.json +149 -0
  55. package/cli/checks/epic/api.json +114 -0
  56. package/cli/checks/epic/backend.json +126 -0
  57. package/cli/checks/epic/cloud.json +126 -0
  58. package/cli/checks/epic/data.json +102 -0
  59. package/cli/checks/epic/database.json +114 -0
  60. package/cli/checks/epic/developer.json +182 -0
  61. package/cli/checks/epic/devops.json +174 -0
  62. package/cli/checks/epic/frontend.json +162 -0
  63. package/cli/checks/epic/mobile.json +102 -0
  64. package/cli/checks/epic/qa.json +90 -0
  65. package/cli/checks/epic/security.json +184 -0
  66. package/cli/checks/epic/solution-architect.json +192 -0
  67. package/cli/checks/epic/test-architect.json +90 -0
  68. package/cli/checks/epic/ui.json +102 -0
  69. package/cli/checks/epic/ux.json +90 -0
  70. package/cli/checks/fixes/epic-fix-template.md +10 -0
  71. package/cli/checks/fixes/story-fix-template.md +10 -0
  72. package/cli/checks/story/api.json +186 -0
  73. package/cli/checks/story/backend.json +102 -0
  74. package/cli/checks/story/cloud.json +102 -0
  75. package/cli/checks/story/data.json +210 -0
  76. package/cli/checks/story/database.json +102 -0
  77. package/cli/checks/story/developer.json +168 -0
  78. package/cli/checks/story/devops.json +102 -0
  79. package/cli/checks/story/frontend.json +174 -0
  80. package/cli/checks/story/mobile.json +102 -0
  81. package/cli/checks/story/qa.json +210 -0
  82. package/cli/checks/story/security.json +198 -0
  83. package/cli/checks/story/solution-architect.json +230 -0
  84. package/cli/checks/story/test-architect.json +210 -0
  85. package/cli/checks/story/ui.json +102 -0
  86. package/cli/checks/story/ux.json +102 -0
  87. package/cli/coding-order.js +401 -0
  88. package/cli/command-logger.js +49 -12
  89. package/cli/components/static-output.js +63 -0
  90. package/cli/console-output-manager.js +94 -0
  91. package/cli/dependency-checker.js +72 -0
  92. package/cli/docs-sync.js +306 -0
  93. package/cli/epic-story-validator.js +659 -0
  94. package/cli/evaluation-prompts.js +1008 -0
  95. package/cli/execution-context.js +195 -0
  96. package/cli/generate-summary-table.js +340 -0
  97. package/cli/init-model-config.js +704 -0
  98. package/cli/init.js +1737 -278
  99. package/cli/kanban-server-manager.js +227 -0
  100. package/cli/llm-claude.js +150 -1
  101. package/cli/llm-gemini.js +109 -0
  102. package/cli/llm-local.js +493 -0
  103. package/cli/llm-mock.js +233 -0
  104. package/cli/llm-openai.js +454 -0
  105. package/cli/llm-provider.js +379 -3
  106. package/cli/llm-token-limits.js +211 -0
  107. package/cli/llm-verifier.js +662 -0
  108. package/cli/llm-xiaomi.js +143 -0
  109. package/cli/message-constants.js +49 -0
  110. package/cli/message-manager.js +334 -0
  111. package/cli/message-types.js +96 -0
  112. package/cli/messaging-api.js +291 -0
  113. package/cli/micro-check-fixer.js +335 -0
  114. package/cli/micro-check-runner.js +449 -0
  115. package/cli/micro-check-scorer.js +148 -0
  116. package/cli/micro-check-validator.js +538 -0
  117. package/cli/model-pricing.js +192 -0
  118. package/cli/model-query-engine.js +468 -0
  119. package/cli/model-recommendation-analyzer.js +495 -0
  120. package/cli/model-selector.js +270 -0
  121. package/cli/output-buffer.js +107 -0
  122. package/cli/process-manager.js +73 -2
  123. package/cli/prompt-logger.js +57 -0
  124. package/cli/repl-ink.js +4625 -1094
  125. package/cli/repl-old.js +3 -4
  126. package/cli/seed-processor.js +962 -0
  127. package/cli/sprint-planning-processor.js +4162 -0
  128. package/cli/template-processor.js +2149 -105
  129. package/cli/templates/project.md +25 -8
  130. package/cli/templates/vitepress-config.mts.template +5 -4
  131. package/cli/token-tracker.js +547 -0
  132. package/cli/tools/generate-story-validators.js +317 -0
  133. package/cli/tools/generate-validators.js +669 -0
  134. package/cli/update-checker.js +19 -17
  135. package/cli/update-notifier.js +4 -4
  136. package/cli/validation-router.js +667 -0
  137. package/cli/verification-tracker.js +563 -0
  138. package/cli/worktree-runner.js +654 -0
  139. package/kanban/README.md +386 -0
  140. package/kanban/client/README.md +205 -0
  141. package/kanban/client/components.json +20 -0
  142. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  143. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  144. package/kanban/client/dist/index.html +16 -0
  145. package/kanban/client/dist/vite.svg +1 -0
  146. package/kanban/client/index.html +15 -0
  147. package/kanban/client/package-lock.json +9442 -0
  148. package/kanban/client/package.json +44 -0
  149. package/kanban/client/postcss.config.js +6 -0
  150. package/kanban/client/public/vite.svg +1 -0
  151. package/kanban/client/src/App.jsx +651 -0
  152. package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
  153. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +420 -0
  154. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +629 -0
  155. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +1133 -0
  156. package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
  157. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  158. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +686 -0
  159. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +838 -0
  160. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
  161. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +136 -0
  162. package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
  163. package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
  164. package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
  165. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +329 -0
  166. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +249 -0
  167. package/kanban/client/src/components/kanban/CardDetailModal.jsx +646 -0
  168. package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
  169. package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
  170. package/kanban/client/src/components/kanban/GroupingSelector.jsx +63 -0
  171. package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
  172. package/kanban/client/src/components/kanban/KanbanCard.jsx +147 -0
  173. package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
  174. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +784 -0
  175. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  176. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  177. package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
  178. package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
  179. package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
  180. package/kanban/client/src/components/settings/AgentsTab.jsx +381 -0
  181. package/kanban/client/src/components/settings/ApiKeysTab.jsx +142 -0
  182. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +105 -0
  183. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  184. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +95 -0
  185. package/kanban/client/src/components/settings/ModelPricingTab.jsx +269 -0
  186. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  187. package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
  188. package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
  189. package/kanban/client/src/components/stats/CostModal.jsx +384 -0
  190. package/kanban/client/src/components/ui/badge.jsx +27 -0
  191. package/kanban/client/src/components/ui/dialog.jsx +121 -0
  192. package/kanban/client/src/components/ui/tabs.jsx +85 -0
  193. package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
  194. package/kanban/client/src/hooks/useGrouping.js +177 -0
  195. package/kanban/client/src/hooks/useWebSocket.js +120 -0
  196. package/kanban/client/src/lib/__tests__/api.test.js +196 -0
  197. package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
  198. package/kanban/client/src/lib/api.js +515 -0
  199. package/kanban/client/src/lib/status-grouping.js +154 -0
  200. package/kanban/client/src/lib/utils.js +11 -0
  201. package/kanban/client/src/main.jsx +10 -0
  202. package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
  203. package/kanban/client/src/store/ceremonyStore.js +172 -0
  204. package/kanban/client/src/store/filterStore.js +201 -0
  205. package/kanban/client/src/store/kanbanStore.js +123 -0
  206. package/kanban/client/src/store/processStore.js +65 -0
  207. package/kanban/client/src/store/sprintPlanningStore.js +33 -0
  208. package/kanban/client/src/styles/globals.css +59 -0
  209. package/kanban/client/tailwind.config.js +77 -0
  210. package/kanban/client/vite.config.js +28 -0
  211. package/kanban/client/vitest.config.js +28 -0
  212. package/kanban/dev-start.sh +47 -0
  213. package/kanban/package.json +12 -0
  214. package/kanban/server/index.js +537 -0
  215. package/kanban/server/routes/ceremony.js +454 -0
  216. package/kanban/server/routes/costs.js +163 -0
  217. package/kanban/server/routes/openai-oauth.js +366 -0
  218. package/kanban/server/routes/processes.js +50 -0
  219. package/kanban/server/routes/settings.js +736 -0
  220. package/kanban/server/routes/websocket.js +281 -0
  221. package/kanban/server/routes/work-items.js +487 -0
  222. package/kanban/server/services/CeremonyService.js +1441 -0
  223. package/kanban/server/services/FileSystemScanner.js +95 -0
  224. package/kanban/server/services/FileWatcher.js +144 -0
  225. package/kanban/server/services/HierarchyBuilder.js +196 -0
  226. package/kanban/server/services/ProcessRegistry.js +122 -0
  227. package/kanban/server/services/TaskRunnerService.js +261 -0
  228. package/kanban/server/services/WorkItemReader.js +123 -0
  229. package/kanban/server/services/WorkItemRefineService.js +510 -0
  230. package/kanban/server/start.js +49 -0
  231. package/kanban/server/utils/kanban-logger.js +132 -0
  232. package/kanban/server/utils/markdown.js +91 -0
  233. package/kanban/server/utils/status-grouping.js +107 -0
  234. package/kanban/server/workers/run-task-worker.js +121 -0
  235. package/kanban/server/workers/seed-worker.js +94 -0
  236. package/kanban/server/workers/sponsor-call-worker.js +92 -0
  237. package/kanban/server/workers/sprint-planning-worker.js +212 -0
  238. package/package.json +19 -7
  239. package/cli/agents/documentation.md +0 -302
@@ -0,0 +1,102 @@
1
+ {
2
+ "perspective": "ui",
3
+ "scope": "story",
4
+ "checks": [
5
+ {
6
+ "id": "ui-story-01",
7
+ "tier": 1,
8
+ "perspective": "ui",
9
+ "severity": "critical",
10
+ "category": "acceptance-criteria",
11
+ "universal": false,
12
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements? (Does it include component specs, styling, or visual layout?)",
13
+ "question": "Is each acceptance criterion testable and measurable?",
14
+ "failDescription": "One or more acceptance criteria are not testable or measurable",
15
+ "failSuggestion": "Make each AC testable: specify exact visual outcomes, component states, or measurable UI properties"
16
+ },
17
+ {
18
+ "id": "ui-story-02",
19
+ "tier": 1,
20
+ "perspective": "ui",
21
+ "severity": "major",
22
+ "category": "acceptance-criteria",
23
+ "universal": false,
24
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
25
+ "question": "Do criteria cover happy path, edge cases, and error scenarios?",
26
+ "failDescription": "Criteria do not cover UI edge cases or error states",
27
+ "failSuggestion": "Add UI edge cases: overflow text, empty states, loading skeletons, error displays, responsive breakpoints"
28
+ },
29
+ {
30
+ "id": "ui-story-03",
31
+ "tier": 1,
32
+ "perspective": "ui",
33
+ "severity": "major",
34
+ "category": "acceptance-criteria",
35
+ "universal": false,
36
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
37
+ "question": "Are UI requirements explicitly stated?",
38
+ "failDescription": "UI requirements are not explicitly stated",
39
+ "failSuggestion": "State UI requirements: component variants, colors, spacing, typography, responsive behavior"
40
+ },
41
+ {
42
+ "id": "ui-story-04",
43
+ "tier": 1,
44
+ "perspective": "ui",
45
+ "severity": "major",
46
+ "category": "implementation-clarity",
47
+ "universal": false,
48
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
49
+ "question": "Does the story provide enough UI detail for implementation?",
50
+ "failDescription": "Insufficient UI detail for implementation",
51
+ "failSuggestion": "Add UI details: component dimensions, color values, spacing units, font sizes, animation timing"
52
+ },
53
+ {
54
+ "id": "ui-story-05",
55
+ "tier": 1,
56
+ "perspective": "ui",
57
+ "severity": "minor",
58
+ "category": "implementation-clarity",
59
+ "universal": false,
60
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
61
+ "question": "Are UI patterns and approaches specified?",
62
+ "failDescription": "UI patterns and approaches are not specified",
63
+ "failSuggestion": "Specify UI patterns: component composition, design token usage, responsive strategy, theme support"
64
+ },
65
+ {
66
+ "id": "ui-story-06",
67
+ "tier": 1,
68
+ "perspective": "ui",
69
+ "severity": "major",
70
+ "category": "testability",
71
+ "universal": false,
72
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
73
+ "question": "Does the story have a test-boundary AC naming specific scenarios a developer must test?",
74
+ "failDescription": "Story lacks a test-boundary AC",
75
+ "failSuggestion": "Add test-boundary AC: 'Tests must cover: (1) default state, (2) hover/focus, (3) error state, (4) responsive, (5) accessibility'"
76
+ },
77
+ {
78
+ "id": "ui-story-07",
79
+ "tier": 1,
80
+ "perspective": "ui",
81
+ "severity": "minor",
82
+ "category": "scope-dependencies",
83
+ "universal": false,
84
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
85
+ "question": "Are dependencies on other stories explicit?",
86
+ "failDescription": "Dependencies on other stories are not explicit",
87
+ "failSuggestion": "Make dependencies explicit: reference design system stories, component library dependencies"
88
+ },
89
+ {
90
+ "id": "ui-story-08",
91
+ "tier": 1,
92
+ "perspective": "ui",
93
+ "severity": "minor",
94
+ "category": "best-practices",
95
+ "universal": false,
96
+ "applicabilityQuestion": "Does this story involve UI components, visual design, or design system elements?",
97
+ "question": "Does the story follow UI best practices?",
98
+ "failDescription": "UI best practices are not followed",
99
+ "failSuggestion": "Follow UI best practices: consistent design tokens, accessibility contrast ratios, responsive design, visual hierarchy"
100
+ }
101
+ ]
102
+ }
@@ -0,0 +1,102 @@
1
+ {
2
+ "perspective": "ux",
3
+ "scope": "story",
4
+ "checks": [
5
+ {
6
+ "id": "ux-story-01",
7
+ "tier": 1,
8
+ "perspective": "ux",
9
+ "severity": "critical",
10
+ "category": "acceptance-criteria",
11
+ "universal": false,
12
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design? (Does it define user journeys, navigation, or usability requirements?)",
13
+ "question": "Is each acceptance criterion testable and measurable?",
14
+ "failDescription": "One or more acceptance criteria are not testable or measurable",
15
+ "failSuggestion": "Make each AC testable: specify user actions, expected outcomes, and measurable UX metrics"
16
+ },
17
+ {
18
+ "id": "ux-story-02",
19
+ "tier": 1,
20
+ "perspective": "ux",
21
+ "severity": "major",
22
+ "category": "acceptance-criteria",
23
+ "universal": false,
24
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
25
+ "question": "Do criteria cover happy path, edge cases, and error scenarios?",
26
+ "failDescription": "Criteria do not cover UX edge cases or error scenarios",
27
+ "failSuggestion": "Add UX edge cases: empty states, error recovery flows, timeout handling, progressive disclosure"
28
+ },
29
+ {
30
+ "id": "ux-story-03",
31
+ "tier": 1,
32
+ "perspective": "ux",
33
+ "severity": "major",
34
+ "category": "acceptance-criteria",
35
+ "universal": false,
36
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
37
+ "question": "Are UX requirements explicitly stated?",
38
+ "failDescription": "UX requirements are not explicitly stated",
39
+ "failSuggestion": "State UX requirements: user flow steps, interaction patterns, feedback mechanisms, accessibility needs"
40
+ },
41
+ {
42
+ "id": "ux-story-04",
43
+ "tier": 1,
44
+ "perspective": "ux",
45
+ "severity": "major",
46
+ "category": "implementation-clarity",
47
+ "universal": false,
48
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
49
+ "question": "Does the story provide enough UX detail for implementation?",
50
+ "failDescription": "Insufficient UX detail for implementation",
51
+ "failSuggestion": "Add UX details: user flow diagrams, interaction states, feedback timing, animation expectations"
52
+ },
53
+ {
54
+ "id": "ux-story-05",
55
+ "tier": 1,
56
+ "perspective": "ux",
57
+ "severity": "minor",
58
+ "category": "implementation-clarity",
59
+ "universal": false,
60
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
61
+ "question": "Are UX patterns and approaches specified?",
62
+ "failDescription": "UX patterns and approaches are not specified",
63
+ "failSuggestion": "Specify UX patterns: progressive disclosure, inline validation, optimistic feedback, error recovery"
64
+ },
65
+ {
66
+ "id": "ux-story-06",
67
+ "tier": 1,
68
+ "perspective": "ux",
69
+ "severity": "major",
70
+ "category": "testability",
71
+ "universal": false,
72
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
73
+ "question": "Does the story have a test-boundary AC naming specific scenarios a developer must test?",
74
+ "failDescription": "Story lacks a test-boundary AC",
75
+ "failSuggestion": "Add test-boundary AC: 'Tests must cover: (1) happy flow, (2) error recovery, (3) empty state, (4) loading state, (5) accessibility'"
76
+ },
77
+ {
78
+ "id": "ux-story-07",
79
+ "tier": 1,
80
+ "perspective": "ux",
81
+ "severity": "minor",
82
+ "category": "scope-dependencies",
83
+ "universal": false,
84
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
85
+ "question": "Are dependencies on other stories explicit?",
86
+ "failDescription": "Dependencies on other stories are not explicit",
87
+ "failSuggestion": "Make dependencies explicit: reference related user flow stories and shared UX patterns"
88
+ },
89
+ {
90
+ "id": "ux-story-08",
91
+ "tier": 1,
92
+ "perspective": "ux",
93
+ "severity": "minor",
94
+ "category": "best-practices",
95
+ "universal": false,
96
+ "applicabilityQuestion": "Does this story involve user experience, user flows, or interaction design?",
97
+ "question": "Does the story follow UX best practices?",
98
+ "failDescription": "UX best practices are not followed",
99
+ "failSuggestion": "Follow UX best practices: minimize cognitive load, provide clear feedback, support undo, maintain consistency"
100
+ }
101
+ ]
102
+ }
@@ -0,0 +1,401 @@
1
+ /**
2
+ * coding-order.js — Computes implementation ordering from epic/story dependency graphs.
3
+ *
4
+ * Pure functions: no side effects, no file I/O. All I/O is done by the caller
5
+ * (SprintPlanningProcessor.generateCodingOrder).
6
+ */
7
+
8
+ /**
9
+ * Build adjacency maps from hierarchy dependencies.
10
+ * @param {{ epics: Array }} hierarchy
11
+ * @returns {{ epicGraph: Map<string,Set<string>>, storyGraphs: Map<string,Map<string,Set<string>>>, allNodes: Map<string,{id,name,type,parentId?}> }}
12
+ */
13
+ export function buildDependencyGraph(hierarchy) {
14
+ const epicGraph = new Map(); // epicId → Set<epicId it depends on>
15
+ const storyGraphs = new Map(); // epicId → Map<storyId, Set<storyId>>
16
+ const allNodes = new Map(); // id → { id, name, type, parentId? }
17
+
18
+ for (const epic of hierarchy.epics || []) {
19
+ const epicId = epic.id;
20
+ allNodes.set(epicId, { id: epicId, name: epic.name, type: 'epic' });
21
+
22
+ // Epic-level deps: only keep references that look like epic IDs (context-XXXX)
23
+ const epicDeps = new Set();
24
+ for (const dep of epic.dependencies || []) {
25
+ if (/^context-\d{4}$/.test(dep) && dep !== epicId) {
26
+ epicDeps.add(dep);
27
+ }
28
+ }
29
+ epicGraph.set(epicId, epicDeps);
30
+
31
+ // Story-level: intra-epic deps only
32
+ const storyMap = new Map();
33
+ const epicStoryIds = new Set((epic.stories || []).map(s => s.id));
34
+
35
+ for (const story of epic.stories || []) {
36
+ allNodes.set(story.id, { id: story.id, name: story.name, type: 'story', parentId: epicId });
37
+ const storyDeps = new Set();
38
+ for (const dep of story.dependencies || []) {
39
+ if (epicStoryIds.has(dep) && dep !== story.id) {
40
+ storyDeps.add(dep); // intra-epic story dependency
41
+ }
42
+ // Cross-epic story deps → promote to epic dependency
43
+ if (/^context-\d{4}$/.test(dep) && dep !== epicId) {
44
+ epicDeps.add(dep);
45
+ }
46
+ }
47
+ storyMap.set(story.id, storyDeps);
48
+ }
49
+
50
+ storyGraphs.set(epicId, storyMap);
51
+ }
52
+
53
+ return { epicGraph, storyGraphs, allNodes };
54
+ }
55
+
56
+ /**
57
+ * Kahn's algorithm — topological sort with cycle detection.
58
+ * @param {Map<string,Set<string>>} graph — nodeId → Set<dependency nodeIds>
59
+ * @returns {{ sorted: string[], hasCycle: boolean, cycleNodes: string[] }}
60
+ */
61
+ export function topologicalSort(graph) {
62
+ const inDegree = new Map();
63
+ const adjList = new Map(); // forward edges: dep → [dependents]
64
+
65
+ for (const [node] of graph) {
66
+ if (!inDegree.has(node)) inDegree.set(node, 0);
67
+ if (!adjList.has(node)) adjList.set(node, []);
68
+ }
69
+
70
+ for (const [node, deps] of graph) {
71
+ for (const dep of deps) {
72
+ if (!graph.has(dep)) continue; // skip refs to non-existent nodes
73
+ if (!adjList.has(dep)) adjList.set(dep, []);
74
+ adjList.get(dep).push(node);
75
+ inDegree.set(node, (inDegree.get(node) || 0) + 1);
76
+ }
77
+ }
78
+
79
+ const queue = [];
80
+ for (const [node, deg] of inDegree) {
81
+ if (deg === 0) queue.push(node);
82
+ }
83
+ queue.sort(); // deterministic ordering for ties
84
+
85
+ const sorted = [];
86
+ while (queue.length > 0) {
87
+ const node = queue.shift();
88
+ sorted.push(node);
89
+ for (const dependent of adjList.get(node) || []) {
90
+ const newDeg = inDegree.get(dependent) - 1;
91
+ inDegree.set(dependent, newDeg);
92
+ if (newDeg === 0) {
93
+ queue.push(dependent);
94
+ queue.sort();
95
+ }
96
+ }
97
+ }
98
+
99
+ const hasCycle = sorted.length < graph.size;
100
+ const cycleNodes = hasCycle
101
+ ? [...graph.keys()].filter(n => !sorted.includes(n))
102
+ : [];
103
+
104
+ // If cycle, append remaining nodes in ID order to still produce output
105
+ if (hasCycle) {
106
+ for (const node of cycleNodes.sort()) {
107
+ sorted.push(node);
108
+ }
109
+ }
110
+
111
+ return { sorted, hasCycle, cycleNodes };
112
+ }
113
+
114
+ /**
115
+ * Group epics into implementation phases by longest-path distance from root nodes.
116
+ * Phase 0 = no dependencies, Phase N = longest dep chain is N.
117
+ * @param {Map<string,Set<string>>} epicGraph
118
+ * @returns {Array<{ phase: number, epicIds: string[] }>}
119
+ */
120
+ export function computePhases(epicGraph) {
121
+ const depth = new Map();
122
+
123
+ function getDepth(node, visited = new Set()) {
124
+ if (depth.has(node)) return depth.get(node);
125
+ if (visited.has(node)) return 0; // cycle guard
126
+ visited.add(node);
127
+
128
+ const deps = epicGraph.get(node) || new Set();
129
+ let maxDepth = 0;
130
+ for (const dep of deps) {
131
+ if (epicGraph.has(dep)) {
132
+ maxDepth = Math.max(maxDepth, getDepth(dep, visited) + 1);
133
+ }
134
+ }
135
+ depth.set(node, maxDepth);
136
+ return maxDepth;
137
+ }
138
+
139
+ for (const [node] of epicGraph) getDepth(node);
140
+
141
+ // Group by phase
142
+ const phaseMap = new Map();
143
+ for (const [node, d] of depth) {
144
+ if (!phaseMap.has(d)) phaseMap.set(d, []);
145
+ phaseMap.get(d).push(node);
146
+ }
147
+
148
+ return [...phaseMap.entries()]
149
+ .sort((a, b) => a[0] - b[0])
150
+ .map(([phase, epicIds]) => ({ phase, epicIds: epicIds.sort() }));
151
+ }
152
+
153
+ /**
154
+ * Find the longest path through the epic dependency graph (critical path).
155
+ * @param {Map<string,Set<string>>} epicGraph
156
+ * @returns {{ path: string[], length: number }}
157
+ */
158
+ export function computeCriticalPath(epicGraph) {
159
+ const memo = new Map();
160
+
161
+ function longestFrom(node, visited = new Set()) {
162
+ if (memo.has(node)) return memo.get(node);
163
+ if (visited.has(node)) return [node]; // cycle guard
164
+ visited.add(node);
165
+
166
+ // Find all nodes that depend on this one
167
+ const dependents = [];
168
+ for (const [n, deps] of epicGraph) {
169
+ if (deps.has(node)) dependents.push(n);
170
+ }
171
+
172
+ let best = [node];
173
+ for (const dep of dependents) {
174
+ const sub = longestFrom(dep, new Set(visited));
175
+ if (sub.length + 1 > best.length) {
176
+ best = [node, ...sub];
177
+ }
178
+ }
179
+ memo.set(node, best);
180
+ return best;
181
+ }
182
+
183
+ // Find roots (nodes with no dependencies)
184
+ const roots = [];
185
+ for (const [node, deps] of epicGraph) {
186
+ if (deps.size === 0) roots.push(node);
187
+ }
188
+
189
+ let criticalPath = [];
190
+ for (const root of roots) {
191
+ const path = longestFrom(root);
192
+ if (path.length > criticalPath.length) criticalPath = path;
193
+ }
194
+
195
+ return { path: criticalPath, length: criticalPath.length };
196
+ }
197
+
198
+ /**
199
+ * Topologically sort stories within a single epic.
200
+ * @param {Map<string,Set<string>>} storyGraph — storyId → Set<intra-epic dep storyIds>
201
+ * @returns {string[]}
202
+ */
203
+ export function orderStoriesWithinEpic(storyGraph) {
204
+ return topologicalSort(storyGraph).sorted;
205
+ }
206
+
207
+ /**
208
+ * Render the coding order as a Markdown document.
209
+ */
210
+ export function generateCodingOrderMd(phases, storyOrders, allNodes, criticalPath) {
211
+ const lines = [
212
+ '# Coding Order',
213
+ '',
214
+ `Generated: ${new Date().toISOString()}`,
215
+ '',
216
+ ];
217
+
218
+ // Mermaid dependency graph
219
+ lines.push('## Dependency Graph', '', '```mermaid', 'graph LR');
220
+ for (const [id, node] of allNodes) {
221
+ if (node.type === 'epic') {
222
+ const label = node.name.replace(/"/g, "'");
223
+ lines.push(` ${id}["${label}"]`);
224
+ }
225
+ }
226
+ // Edges: for each epic, draw edges FROM its dependencies TO it
227
+ for (const phase of phases) {
228
+ for (const epicId of phase.epicIds) {
229
+ // Find this epic's node in allNodes and look up its deps
230
+ // We need the original graph — reconstruct from phases
231
+ }
232
+ }
233
+ // Use phases to reconstruct edges from allNodes
234
+ // Actually we need epicGraph — let's take it as parameter
235
+ lines.push('```', '');
236
+
237
+ // Critical path
238
+ lines.push('## Critical Path', '');
239
+ if (criticalPath.path.length > 0) {
240
+ const pathStr = criticalPath.path
241
+ .map(id => { const n = allNodes.get(id); return n ? `${id} (${n.name})` : id; })
242
+ .join(' → ');
243
+ lines.push(pathStr);
244
+ lines.push(``, `Length: ${criticalPath.length} epics`, '');
245
+ } else {
246
+ lines.push('No dependencies — all epics are independent.', '');
247
+ }
248
+
249
+ // Implementation phases
250
+ lines.push('## Implementation Phases', '');
251
+ for (const phase of phases) {
252
+ const parallel = phase.epicIds.length > 1 ? ' (parallel)' : '';
253
+ const depNote = phase.phase === 0 ? ' — no dependencies' : ` — depends on Phase ${phase.phase}`;
254
+ lines.push(`### Phase ${phase.phase + 1}${parallel}${depNote}`, '');
255
+
256
+ for (const epicId of phase.epicIds) {
257
+ const epic = allNodes.get(epicId);
258
+ const epicName = epic ? epic.name : epicId;
259
+ lines.push(`#### ${epicId}: ${epicName}`, '');
260
+
261
+ const stories = storyOrders.get(epicId) || [];
262
+ if (stories.length > 0) {
263
+ lines.push('| # | Story | ID |', '|---|-------|-----|');
264
+ stories.forEach((storyId, idx) => {
265
+ const story = allNodes.get(storyId);
266
+ const storyName = story ? story.name : storyId;
267
+ lines.push(`| ${idx + 1} | ${storyName} | ${storyId} |`);
268
+ });
269
+ lines.push('');
270
+ }
271
+ }
272
+ }
273
+
274
+ return lines.join('\n');
275
+ }
276
+
277
+ /**
278
+ * Render the coding order as structured JSON for the kanban API.
279
+ */
280
+ export function generateCodingOrderJson(phases, storyOrders, allNodes, criticalPath) {
281
+ return {
282
+ generatedAt: new Date().toISOString(),
283
+ criticalPath: {
284
+ epicIds: criticalPath.path,
285
+ length: criticalPath.length,
286
+ epics: criticalPath.path.map(id => {
287
+ const n = allNodes.get(id);
288
+ return { id, name: n?.name || id };
289
+ }),
290
+ },
291
+ phases: phases.map(phase => ({
292
+ phase: phase.phase + 1,
293
+ parallel: phase.epicIds.length > 1,
294
+ epics: phase.epicIds.map(epicId => {
295
+ const epic = allNodes.get(epicId);
296
+ const stories = (storyOrders.get(epicId) || []).map((storyId, idx) => {
297
+ const story = allNodes.get(storyId);
298
+ return { order: idx + 1, id: storyId, name: story?.name || storyId };
299
+ });
300
+ return { id: epicId, name: epic?.name || epicId, stories };
301
+ }),
302
+ })),
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Main entry point — compute everything from a hierarchy.
308
+ * @param {{ epics: Array }} hierarchy
309
+ * @returns {{ md: string, json: object, phases: Array, criticalPath: object }}
310
+ */
311
+ export function computeCodingOrder(hierarchy) {
312
+ const { epicGraph, storyGraphs, allNodes } = buildDependencyGraph(hierarchy);
313
+ const phases = computePhases(epicGraph);
314
+ const criticalPath = computeCriticalPath(epicGraph);
315
+
316
+ // Order stories within each epic
317
+ const storyOrders = new Map();
318
+ for (const [epicId, storyGraph] of storyGraphs) {
319
+ storyOrders.set(epicId, orderStoriesWithinEpic(storyGraph));
320
+ }
321
+
322
+ // Render mermaid edges using epicGraph
323
+ const md = generateCodingOrderMdWithGraph(phases, storyOrders, allNodes, criticalPath, epicGraph);
324
+ const json = generateCodingOrderJson(phases, storyOrders, allNodes, criticalPath);
325
+
326
+ return { md, json, phases, criticalPath };
327
+ }
328
+
329
+ /**
330
+ * Full Markdown rendering with mermaid graph edges.
331
+ */
332
+ function generateCodingOrderMdWithGraph(phases, storyOrders, allNodes, criticalPath, epicGraph) {
333
+ const lines = [
334
+ '# Coding Order',
335
+ '',
336
+ `Generated: ${new Date().toISOString()}`,
337
+ '',
338
+ '## Dependency Graph',
339
+ '',
340
+ '```mermaid',
341
+ 'graph LR',
342
+ ];
343
+
344
+ // Nodes
345
+ for (const [id, node] of allNodes) {
346
+ if (node.type === 'epic') {
347
+ const label = node.name.replace(/"/g, "'");
348
+ lines.push(` ${id}["${label}"]`);
349
+ }
350
+ }
351
+
352
+ // Edges
353
+ for (const [epicId, deps] of epicGraph) {
354
+ for (const dep of deps) {
355
+ lines.push(` ${dep} --> ${epicId}`);
356
+ }
357
+ }
358
+
359
+ // Highlight critical path
360
+ if (criticalPath.path.length > 1) {
361
+ lines.push(` style ${criticalPath.path.join(' stroke:#f44,stroke-width:3px; style ')} stroke:#f44,stroke-width:3px`);
362
+ }
363
+
364
+ lines.push('```', '');
365
+
366
+ // Critical path
367
+ lines.push('## Critical Path', '');
368
+ if (criticalPath.path.length > 0) {
369
+ const pathStr = criticalPath.path
370
+ .map(id => { const n = allNodes.get(id); return n ? `**${n.name}**` : id; })
371
+ .join(' → ');
372
+ lines.push(pathStr, '', `Length: ${criticalPath.length} epics`, '');
373
+ } else {
374
+ lines.push('No dependencies — all epics are independent.', '');
375
+ }
376
+
377
+ // Phases
378
+ lines.push('## Implementation Phases', '');
379
+ for (const phase of phases) {
380
+ const parallel = phase.epicIds.length > 1 ? ' (parallel)' : '';
381
+ const depNote = phase.phase === 0 ? '' : ` — requires Phase ${phase.phase} complete`;
382
+ lines.push(`### Phase ${phase.phase + 1}${parallel}${depNote}`, '');
383
+
384
+ for (const epicId of phase.epicIds) {
385
+ const epic = allNodes.get(epicId);
386
+ lines.push(`#### ${epicId}: ${epic?.name || epicId}`, '');
387
+
388
+ const stories = storyOrders.get(epicId) || [];
389
+ if (stories.length > 0) {
390
+ lines.push('| # | Story | ID |', '|---|-------|-----|');
391
+ stories.forEach((storyId, idx) => {
392
+ const story = allNodes.get(storyId);
393
+ lines.push(`| ${idx + 1} | ${story?.name || storyId} | \`${storyId}\` |`);
394
+ });
395
+ lines.push('');
396
+ }
397
+ }
398
+ }
399
+
400
+ return lines.join('\n');
401
+ }