@agile-vibe-coding/avc 0.1.1 → 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.
- package/cli/agent-loader.js +21 -0
- package/cli/agents/agent-selector.md +129 -0
- package/cli/agents/architecture-recommender.md +418 -0
- package/cli/agents/database-deep-dive.md +470 -0
- package/cli/agents/database-recommender.md +634 -0
- package/cli/agents/doc-distributor.md +176 -0
- package/cli/agents/documentation-updater.md +203 -0
- package/cli/agents/epic-story-decomposer.md +280 -0
- package/cli/agents/feature-context-generator.md +91 -0
- package/cli/agents/gap-checker-epic.md +52 -0
- package/cli/agents/impact-checker-story.md +51 -0
- package/cli/agents/migration-guide-generator.md +305 -0
- package/cli/agents/mission-scope-generator.md +79 -0
- package/cli/agents/mission-scope-validator.md +112 -0
- package/cli/agents/project-context-extractor.md +107 -0
- package/cli/agents/project-documentation-creator.json +226 -0
- package/cli/agents/project-documentation-creator.md +595 -0
- package/cli/agents/question-prefiller.md +269 -0
- package/cli/agents/refiner-epic.md +39 -0
- package/cli/agents/refiner-story.md +42 -0
- package/cli/agents/solver-epic-api.json +15 -0
- package/cli/agents/solver-epic-api.md +39 -0
- package/cli/agents/solver-epic-backend.json +15 -0
- package/cli/agents/solver-epic-backend.md +39 -0
- package/cli/agents/solver-epic-cloud.json +15 -0
- package/cli/agents/solver-epic-cloud.md +39 -0
- package/cli/agents/solver-epic-data.json +15 -0
- package/cli/agents/solver-epic-data.md +39 -0
- package/cli/agents/solver-epic-database.json +15 -0
- package/cli/agents/solver-epic-database.md +39 -0
- package/cli/agents/solver-epic-developer.json +15 -0
- package/cli/agents/solver-epic-developer.md +39 -0
- package/cli/agents/solver-epic-devops.json +15 -0
- package/cli/agents/solver-epic-devops.md +39 -0
- package/cli/agents/solver-epic-frontend.json +15 -0
- package/cli/agents/solver-epic-frontend.md +39 -0
- package/cli/agents/solver-epic-mobile.json +15 -0
- package/cli/agents/solver-epic-mobile.md +39 -0
- package/cli/agents/solver-epic-qa.json +15 -0
- package/cli/agents/solver-epic-qa.md +39 -0
- package/cli/agents/solver-epic-security.json +15 -0
- package/cli/agents/solver-epic-security.md +39 -0
- package/cli/agents/solver-epic-solution-architect.json +15 -0
- package/cli/agents/solver-epic-solution-architect.md +39 -0
- package/cli/agents/solver-epic-test-architect.json +15 -0
- package/cli/agents/solver-epic-test-architect.md +39 -0
- package/cli/agents/solver-epic-ui.json +15 -0
- package/cli/agents/solver-epic-ui.md +39 -0
- package/cli/agents/solver-epic-ux.json +15 -0
- package/cli/agents/solver-epic-ux.md +39 -0
- package/cli/agents/solver-story-api.json +15 -0
- package/cli/agents/solver-story-api.md +39 -0
- package/cli/agents/solver-story-backend.json +15 -0
- package/cli/agents/solver-story-backend.md +39 -0
- package/cli/agents/solver-story-cloud.json +15 -0
- package/cli/agents/solver-story-cloud.md +39 -0
- package/cli/agents/solver-story-data.json +15 -0
- package/cli/agents/solver-story-data.md +39 -0
- package/cli/agents/solver-story-database.json +15 -0
- package/cli/agents/solver-story-database.md +39 -0
- package/cli/agents/solver-story-developer.json +15 -0
- package/cli/agents/solver-story-developer.md +39 -0
- package/cli/agents/solver-story-devops.json +15 -0
- package/cli/agents/solver-story-devops.md +39 -0
- package/cli/agents/solver-story-frontend.json +15 -0
- package/cli/agents/solver-story-frontend.md +39 -0
- package/cli/agents/solver-story-mobile.json +15 -0
- package/cli/agents/solver-story-mobile.md +39 -0
- package/cli/agents/solver-story-qa.json +15 -0
- package/cli/agents/solver-story-qa.md +39 -0
- package/cli/agents/solver-story-security.json +15 -0
- package/cli/agents/solver-story-security.md +39 -0
- package/cli/agents/solver-story-solution-architect.json +15 -0
- package/cli/agents/solver-story-solution-architect.md +39 -0
- package/cli/agents/solver-story-test-architect.json +15 -0
- package/cli/agents/solver-story-test-architect.md +39 -0
- package/cli/agents/solver-story-ui.json +15 -0
- package/cli/agents/solver-story-ui.md +39 -0
- package/cli/agents/solver-story-ux.json +15 -0
- package/cli/agents/solver-story-ux.md +39 -0
- package/cli/agents/story-doc-enricher.md +133 -0
- package/cli/agents/suggestion-business-analyst.md +88 -0
- package/cli/agents/suggestion-deployment-architect.md +263 -0
- package/cli/agents/suggestion-product-manager.md +129 -0
- package/cli/agents/suggestion-security-specialist.md +156 -0
- package/cli/agents/suggestion-technical-architect.md +269 -0
- package/cli/agents/suggestion-ux-researcher.md +93 -0
- package/cli/agents/task-subtask-decomposer.md +188 -0
- package/cli/agents/validator-documentation.json +152 -0
- package/cli/agents/validator-documentation.md +453 -0
- package/cli/agents/validator-epic-api.json +93 -0
- package/cli/agents/validator-epic-api.md +137 -0
- package/cli/agents/validator-epic-backend.json +93 -0
- package/cli/agents/validator-epic-backend.md +130 -0
- package/cli/agents/validator-epic-cloud.json +93 -0
- package/cli/agents/validator-epic-cloud.md +137 -0
- package/cli/agents/validator-epic-data.json +93 -0
- package/cli/agents/validator-epic-data.md +130 -0
- package/cli/agents/validator-epic-database.json +93 -0
- package/cli/agents/validator-epic-database.md +137 -0
- package/cli/agents/validator-epic-developer.json +74 -0
- package/cli/agents/validator-epic-developer.md +153 -0
- package/cli/agents/validator-epic-devops.json +74 -0
- package/cli/agents/validator-epic-devops.md +153 -0
- package/cli/agents/validator-epic-frontend.json +74 -0
- package/cli/agents/validator-epic-frontend.md +153 -0
- package/cli/agents/validator-epic-mobile.json +93 -0
- package/cli/agents/validator-epic-mobile.md +130 -0
- package/cli/agents/validator-epic-qa.json +93 -0
- package/cli/agents/validator-epic-qa.md +130 -0
- package/cli/agents/validator-epic-security.json +74 -0
- package/cli/agents/validator-epic-security.md +154 -0
- package/cli/agents/validator-epic-solution-architect.json +74 -0
- package/cli/agents/validator-epic-solution-architect.md +156 -0
- package/cli/agents/validator-epic-test-architect.json +93 -0
- package/cli/agents/validator-epic-test-architect.md +130 -0
- package/cli/agents/validator-epic-ui.json +93 -0
- package/cli/agents/validator-epic-ui.md +130 -0
- package/cli/agents/validator-epic-ux.json +93 -0
- package/cli/agents/validator-epic-ux.md +130 -0
- package/cli/agents/validator-selector.md +211 -0
- package/cli/agents/validator-story-api.json +104 -0
- package/cli/agents/validator-story-api.md +152 -0
- package/cli/agents/validator-story-backend.json +104 -0
- package/cli/agents/validator-story-backend.md +152 -0
- package/cli/agents/validator-story-cloud.json +104 -0
- package/cli/agents/validator-story-cloud.md +152 -0
- package/cli/agents/validator-story-data.json +104 -0
- package/cli/agents/validator-story-data.md +152 -0
- package/cli/agents/validator-story-database.json +104 -0
- package/cli/agents/validator-story-database.md +152 -0
- package/cli/agents/validator-story-developer.json +104 -0
- package/cli/agents/validator-story-developer.md +152 -0
- package/cli/agents/validator-story-devops.json +104 -0
- package/cli/agents/validator-story-devops.md +152 -0
- package/cli/agents/validator-story-frontend.json +104 -0
- package/cli/agents/validator-story-frontend.md +152 -0
- package/cli/agents/validator-story-mobile.json +104 -0
- package/cli/agents/validator-story-mobile.md +152 -0
- package/cli/agents/validator-story-qa.json +104 -0
- package/cli/agents/validator-story-qa.md +152 -0
- package/cli/agents/validator-story-security.json +104 -0
- package/cli/agents/validator-story-security.md +152 -0
- package/cli/agents/validator-story-solution-architect.json +104 -0
- package/cli/agents/validator-story-solution-architect.md +152 -0
- package/cli/agents/validator-story-test-architect.json +104 -0
- package/cli/agents/validator-story-test-architect.md +152 -0
- package/cli/agents/validator-story-ui.json +104 -0
- package/cli/agents/validator-story-ui.md +152 -0
- package/cli/agents/validator-story-ux.json +104 -0
- package/cli/agents/validator-story-ux.md +152 -0
- package/cli/ansi-colors.js +21 -0
- package/cli/build-docs.js +29 -8
- package/cli/ceremony-history.js +369 -0
- package/cli/command-logger.js +49 -12
- package/cli/components/static-output.js +63 -0
- package/cli/console-output-manager.js +94 -0
- package/cli/docs-sync.js +306 -0
- package/cli/epic-story-validator.js +1174 -0
- package/cli/evaluation-prompts.js +1008 -0
- package/cli/execution-context.js +195 -0
- package/cli/generate-summary-table.js +340 -0
- package/cli/index.js +0 -0
- package/cli/init-model-config.js +697 -0
- package/cli/init.js +1311 -274
- package/cli/kanban-server-manager.js +228 -0
- package/cli/llm-claude.js +83 -1
- package/cli/llm-gemini.js +85 -0
- package/cli/llm-mock.js +233 -0
- package/cli/llm-openai.js +233 -0
- package/cli/llm-provider.js +240 -3
- package/cli/llm-token-limits.js +102 -0
- package/cli/llm-verifier.js +454 -0
- package/cli/message-constants.js +58 -0
- package/cli/message-manager.js +334 -0
- package/cli/message-types.js +96 -0
- package/cli/messaging-api.js +297 -0
- package/cli/model-pricing.js +169 -0
- package/cli/model-query-engine.js +468 -0
- package/cli/model-recommendation-analyzer.js +495 -0
- package/cli/model-selector.js +269 -0
- package/cli/output-buffer.js +107 -0
- package/cli/process-manager.js +73 -2
- package/cli/repl-ink.js +4988 -1217
- package/cli/repl-old.js +4 -4
- package/cli/seed-processor.js +792 -0
- package/cli/sprint-planning-processor.js +1813 -0
- package/cli/template-processor.js +2102 -105
- package/cli/templates/project.md +25 -8
- package/cli/templates/vitepress-config.mts.template +5 -4
- package/cli/token-tracker.js +520 -0
- package/cli/tools/generate-story-validators.js +317 -0
- package/cli/tools/generate-validators.js +669 -0
- package/cli/update-checker.js +19 -17
- package/cli/update-notifier.js +4 -4
- package/cli/validation-router.js +605 -0
- package/cli/verification-tracker.js +563 -0
- package/kanban/README.md +386 -0
- package/kanban/client/README.md +205 -0
- package/kanban/client/components.json +20 -0
- package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
- package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
- package/kanban/client/dist/index.html +16 -0
- package/kanban/client/dist/vite.svg +1 -0
- package/kanban/client/index.html +15 -0
- package/kanban/client/package-lock.json +9442 -0
- package/kanban/client/package.json +44 -0
- package/kanban/client/postcss.config.js +6 -0
- package/kanban/client/public/vite.svg +1 -0
- package/kanban/client/src/App.jsx +622 -0
- package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
- package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
- package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
- package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
- package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
- package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
- package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
- package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
- package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
- package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
- package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
- package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
- package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
- package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
- package/kanban/client/src/components/stats/CostModal.jsx +353 -0
- package/kanban/client/src/components/ui/badge.jsx +27 -0
- package/kanban/client/src/components/ui/dialog.jsx +121 -0
- package/kanban/client/src/components/ui/tabs.jsx +85 -0
- package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
- package/kanban/client/src/hooks/useGrouping.js +118 -0
- package/kanban/client/src/hooks/useWebSocket.js +120 -0
- package/kanban/client/src/lib/__tests__/api.test.js +196 -0
- package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
- package/kanban/client/src/lib/api.js +401 -0
- package/kanban/client/src/lib/status-grouping.js +144 -0
- package/kanban/client/src/lib/utils.js +11 -0
- package/kanban/client/src/main.jsx +10 -0
- package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
- package/kanban/client/src/store/ceremonyStore.js +172 -0
- package/kanban/client/src/store/filterStore.js +201 -0
- package/kanban/client/src/store/kanbanStore.js +115 -0
- package/kanban/client/src/store/processStore.js +65 -0
- package/kanban/client/src/store/sprintPlanningStore.js +33 -0
- package/kanban/client/src/styles/globals.css +59 -0
- package/kanban/client/tailwind.config.js +77 -0
- package/kanban/client/vite.config.js +28 -0
- package/kanban/client/vitest.config.js +28 -0
- package/kanban/dev-start.sh +47 -0
- package/kanban/package.json +12 -0
- package/kanban/server/index.js +516 -0
- package/kanban/server/routes/ceremony.js +305 -0
- package/kanban/server/routes/costs.js +157 -0
- package/kanban/server/routes/processes.js +50 -0
- package/kanban/server/routes/settings.js +303 -0
- package/kanban/server/routes/websocket.js +276 -0
- package/kanban/server/routes/work-items.js +347 -0
- package/kanban/server/services/CeremonyService.js +1190 -0
- package/kanban/server/services/FileSystemScanner.js +95 -0
- package/kanban/server/services/FileWatcher.js +144 -0
- package/kanban/server/services/HierarchyBuilder.js +196 -0
- package/kanban/server/services/ProcessRegistry.js +122 -0
- package/kanban/server/services/WorkItemReader.js +123 -0
- package/kanban/server/services/WorkItemRefineService.js +510 -0
- package/kanban/server/start.js +49 -0
- package/kanban/server/utils/kanban-logger.js +132 -0
- package/kanban/server/utils/markdown.js +91 -0
- package/kanban/server/utils/status-grouping.js +107 -0
- package/kanban/server/workers/sponsor-call-worker.js +84 -0
- package/kanban/server/workers/sprint-planning-worker.js +130 -0
- package/package.json +18 -5
- package/cli/agents/documentation.md +0 -302
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useSprintPlanningStore } from '../../store/sprintPlanningStore';
|
|
3
|
+
import { confirmSprintPlanningSelection, cancelCeremony } from '../../lib/api';
|
|
4
|
+
|
|
5
|
+
// ── Inner component: only mounted when hierarchy is non-null ──────────────────
|
|
6
|
+
// Using a wrapper+inner pattern so useState can be lazily initialised from
|
|
7
|
+
// a non-null hierarchy prop, avoiding "hooks before conditional return" issues.
|
|
8
|
+
|
|
9
|
+
function SelectionContent({ hierarchy, onConfirm, onCancel }) {
|
|
10
|
+
const [epicSel, setEpicSel] = useState(() => {
|
|
11
|
+
const m = {};
|
|
12
|
+
for (const e of hierarchy.epics) m[e.id] = true;
|
|
13
|
+
return m;
|
|
14
|
+
});
|
|
15
|
+
const [storySel, setStorySel] = useState(() => {
|
|
16
|
+
const m = {};
|
|
17
|
+
for (const e of hierarchy.epics)
|
|
18
|
+
for (const s of (e.stories || []))
|
|
19
|
+
m[s.id] = true;
|
|
20
|
+
return m;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const selectedEpicCount = Object.values(epicSel).filter(Boolean).length;
|
|
24
|
+
const totalEpicCount = hierarchy.epics.length;
|
|
25
|
+
const selectedStoryCount = Object.values(storySel).filter(Boolean).length;
|
|
26
|
+
const totalStoryCount = hierarchy.epics.reduce((n, e) => n + (e.stories?.length || 0), 0);
|
|
27
|
+
const canConfirm = selectedEpicCount > 0;
|
|
28
|
+
|
|
29
|
+
const toggleEpic = (epicId, checked) => {
|
|
30
|
+
setEpicSel(prev => ({ ...prev, [epicId]: checked }));
|
|
31
|
+
const epic = hierarchy.epics.find(e => e.id === epicId);
|
|
32
|
+
if (epic) {
|
|
33
|
+
const update = {};
|
|
34
|
+
for (const s of (epic.stories || [])) update[s.id] = checked;
|
|
35
|
+
setStorySel(prev => ({ ...prev, ...update }));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const toggleStory = (epicId, storyId, checked) => {
|
|
40
|
+
const next = { ...storySel, [storyId]: checked };
|
|
41
|
+
setStorySel(next);
|
|
42
|
+
const epic = hierarchy.epics.find(e => e.id === epicId);
|
|
43
|
+
if (epic) {
|
|
44
|
+
const anyChecked = (epic.stories || []).some(s => next[s.id]);
|
|
45
|
+
setEpicSel(prev => ({ ...prev, [epicId]: anyChecked }));
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const selectAll = () => {
|
|
50
|
+
const em = {}, sm = {};
|
|
51
|
+
for (const e of hierarchy.epics) {
|
|
52
|
+
em[e.id] = true;
|
|
53
|
+
for (const s of (e.stories || [])) sm[s.id] = true;
|
|
54
|
+
}
|
|
55
|
+
setEpicSel(em); setStorySel(sm);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const deselectAll = () => {
|
|
59
|
+
const em = {}, sm = {};
|
|
60
|
+
for (const e of hierarchy.epics) {
|
|
61
|
+
em[e.id] = false;
|
|
62
|
+
for (const s of (e.stories || [])) sm[s.id] = false;
|
|
63
|
+
}
|
|
64
|
+
setEpicSel(em); setStorySel(sm);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const handleConfirm = () => {
|
|
68
|
+
const selectedEpicIds = Object.entries(epicSel).filter(([, v]) => v).map(([k]) => k);
|
|
69
|
+
const selectedStoryIds = Object.entries(storySel).filter(([, v]) => v).map(([k]) => k);
|
|
70
|
+
onConfirm(selectedEpicIds, selectedStoryIds);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
{/* Header */}
|
|
76
|
+
<div className="px-6 pt-5 pb-4 border-b border-slate-200 flex-shrink-0">
|
|
77
|
+
<h2 className="text-base font-semibold text-slate-900">Review Decomposed Work</h2>
|
|
78
|
+
<p className="text-sm text-slate-500 mt-1">
|
|
79
|
+
The AI has decomposed your scope into epics and stories. Select which items to carry
|
|
80
|
+
forward into validation — deselected items will be skipped entirely.
|
|
81
|
+
</p>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* Scrollable checklist */}
|
|
85
|
+
<div className="flex-1 overflow-y-auto px-6 py-4 space-y-4 min-h-0">
|
|
86
|
+
{/* Counts + select-all controls */}
|
|
87
|
+
<div className="flex items-center justify-between">
|
|
88
|
+
<p className="text-xs text-slate-500">
|
|
89
|
+
<span className="font-medium text-slate-700">{selectedEpicCount}/{totalEpicCount}</span> epics ·{' '}
|
|
90
|
+
<span className="font-medium text-slate-700">{selectedStoryCount}/{totalStoryCount}</span> stories selected
|
|
91
|
+
</p>
|
|
92
|
+
<div className="flex items-center gap-1.5">
|
|
93
|
+
<button onClick={selectAll} className="text-xs px-2 py-0.5 rounded border border-slate-200 text-slate-600 hover:bg-slate-50 transition-colors">
|
|
94
|
+
Select all
|
|
95
|
+
</button>
|
|
96
|
+
<button onClick={deselectAll} className="text-xs px-2 py-0.5 rounded border border-slate-200 text-slate-600 hover:bg-slate-50 transition-colors">
|
|
97
|
+
Deselect all
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
{/* Two-level checklist */}
|
|
103
|
+
<div className="space-y-2">
|
|
104
|
+
{hierarchy.epics.map(epic => {
|
|
105
|
+
const epicChecked = epicSel[epic.id] ?? false;
|
|
106
|
+
const stories = epic.stories || [];
|
|
107
|
+
return (
|
|
108
|
+
<div key={epic.id} className="rounded-lg border border-slate-200 overflow-hidden">
|
|
109
|
+
{/* Epic row */}
|
|
110
|
+
<label className="flex items-start gap-3 px-4 py-3 bg-slate-50 cursor-pointer hover:bg-slate-100 select-none">
|
|
111
|
+
<input
|
|
112
|
+
type="checkbox"
|
|
113
|
+
checked={epicChecked}
|
|
114
|
+
onChange={e => toggleEpic(epic.id, e.target.checked)}
|
|
115
|
+
className="mt-0.5 flex-shrink-0 accent-slate-900"
|
|
116
|
+
/>
|
|
117
|
+
<div className="min-w-0 flex-1">
|
|
118
|
+
<p className="text-sm font-semibold text-slate-900 leading-snug">{epic.name}</p>
|
|
119
|
+
{epic.description && (
|
|
120
|
+
<p className="text-xs text-slate-500 mt-0.5 line-clamp-2">{epic.description}</p>
|
|
121
|
+
)}
|
|
122
|
+
<p className="text-xs text-slate-400 mt-0.5">
|
|
123
|
+
{stories.length} {stories.length === 1 ? 'story' : 'stories'}
|
|
124
|
+
{epic.domain ? <span className="ml-1 text-slate-300">· {epic.domain}</span> : null}
|
|
125
|
+
</p>
|
|
126
|
+
</div>
|
|
127
|
+
</label>
|
|
128
|
+
|
|
129
|
+
{/* Story rows */}
|
|
130
|
+
{stories.length > 0 && (
|
|
131
|
+
<div className="divide-y divide-slate-100">
|
|
132
|
+
{stories.map(story => (
|
|
133
|
+
<label
|
|
134
|
+
key={story.id}
|
|
135
|
+
className="flex items-start gap-3 px-4 py-2 pl-10 cursor-pointer hover:bg-slate-50 select-none"
|
|
136
|
+
>
|
|
137
|
+
<input
|
|
138
|
+
type="checkbox"
|
|
139
|
+
checked={storySel[story.id] ?? false}
|
|
140
|
+
onChange={e => toggleStory(epic.id, story.id, e.target.checked)}
|
|
141
|
+
className="mt-0.5 flex-shrink-0 accent-slate-600"
|
|
142
|
+
/>
|
|
143
|
+
<div className="min-w-0">
|
|
144
|
+
<p className="text-xs font-medium text-slate-800">{story.name}</p>
|
|
145
|
+
{story.userType && (
|
|
146
|
+
<p className="text-xs text-slate-400 mt-0.5">{story.userType}</p>
|
|
147
|
+
)}
|
|
148
|
+
</div>
|
|
149
|
+
</label>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
})}
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
{/* Footer */}
|
|
160
|
+
<div className="flex items-center justify-between px-6 py-4 border-t border-slate-200 flex-shrink-0">
|
|
161
|
+
<button
|
|
162
|
+
onClick={onCancel}
|
|
163
|
+
className="px-4 py-2 text-sm rounded-lg border border-red-200 text-red-600 hover:bg-red-50 transition-colors"
|
|
164
|
+
>
|
|
165
|
+
✕ Cancel Run
|
|
166
|
+
</button>
|
|
167
|
+
<button
|
|
168
|
+
onClick={handleConfirm}
|
|
169
|
+
disabled={!canConfirm}
|
|
170
|
+
className="px-6 py-2 text-sm font-medium bg-slate-900 text-white rounded-lg hover:bg-slate-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
|
171
|
+
>
|
|
172
|
+
Confirm Selection →
|
|
173
|
+
</button>
|
|
174
|
+
</div>
|
|
175
|
+
</>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ── Outer wrapper: guards on status + hierarchy ───────────────────────────────
|
|
180
|
+
|
|
181
|
+
export function EpicStorySelectionModal() {
|
|
182
|
+
const {
|
|
183
|
+
status,
|
|
184
|
+
decomposedHierarchy,
|
|
185
|
+
setStatus,
|
|
186
|
+
setStep,
|
|
187
|
+
setDecomposedHierarchy,
|
|
188
|
+
setError,
|
|
189
|
+
} = useSprintPlanningStore();
|
|
190
|
+
|
|
191
|
+
const [showCancelConfirm, setShowCancelConfirm] = useState(false);
|
|
192
|
+
|
|
193
|
+
// Only render when the worker is waiting for selection
|
|
194
|
+
if (status !== 'awaiting-selection' || !decomposedHierarchy) return null;
|
|
195
|
+
|
|
196
|
+
const handleConfirm = async (selectedEpicIds, selectedStoryIds) => {
|
|
197
|
+
setDecomposedHierarchy(null);
|
|
198
|
+
setStatus('running');
|
|
199
|
+
setStep(2);
|
|
200
|
+
try {
|
|
201
|
+
await confirmSprintPlanningSelection(selectedEpicIds, selectedStoryIds);
|
|
202
|
+
} catch (err) {
|
|
203
|
+
setStatus('error');
|
|
204
|
+
setError(err.message);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const handleConfirmCancel = async () => {
|
|
209
|
+
setShowCancelConfirm(false);
|
|
210
|
+
try { await cancelCeremony(); } catch (_) {}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<div className="fixed inset-0 z-[80] flex items-center justify-center">
|
|
215
|
+
{/* Non-dismissible backdrop — user must make a selection or cancel */}
|
|
216
|
+
<div className="absolute inset-0 bg-black/60" />
|
|
217
|
+
|
|
218
|
+
{/* Modal */}
|
|
219
|
+
<div className="relative bg-white rounded-2xl shadow-2xl w-full max-w-2xl mx-4 max-h-[90vh] flex flex-col">
|
|
220
|
+
{/* Cancel confirmation overlay */}
|
|
221
|
+
{showCancelConfirm && (
|
|
222
|
+
<div className="absolute inset-0 z-10 flex items-center justify-center bg-white/90 rounded-2xl">
|
|
223
|
+
<div className="bg-white border border-slate-200 rounded-xl shadow-lg p-6 max-w-sm mx-4 text-center space-y-4">
|
|
224
|
+
<p className="text-base font-semibold text-slate-900">Cancel sprint planning?</p>
|
|
225
|
+
<p className="text-sm text-slate-500">
|
|
226
|
+
Any epics and stories created in this run will be permanently deleted.
|
|
227
|
+
</p>
|
|
228
|
+
<div className="flex gap-3 justify-center pt-1">
|
|
229
|
+
<button
|
|
230
|
+
onClick={() => setShowCancelConfirm(false)}
|
|
231
|
+
className="px-4 py-2 text-sm rounded-lg border border-slate-200 text-slate-700 hover:bg-slate-50"
|
|
232
|
+
>
|
|
233
|
+
Go Back
|
|
234
|
+
</button>
|
|
235
|
+
<button
|
|
236
|
+
onClick={handleConfirmCancel}
|
|
237
|
+
className="px-4 py-2 text-sm rounded-lg bg-red-600 text-white hover:bg-red-700"
|
|
238
|
+
>
|
|
239
|
+
Cancel Run
|
|
240
|
+
</button>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
)}
|
|
245
|
+
|
|
246
|
+
<SelectionContent
|
|
247
|
+
hierarchy={decomposedHierarchy}
|
|
248
|
+
onConfirm={handleConfirm}
|
|
249
|
+
onCancel={() => setShowCancelConfirm(true)}
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
);
|
|
254
|
+
}
|