@agile-vibe-coding/avc 0.2.3 → 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.
- package/cli/agents/agent-selector.md +23 -0
- package/cli/agents/code-implementer.md +117 -0
- package/cli/agents/code-validator.md +80 -0
- package/cli/agents/context-reviewer-epic.md +101 -0
- package/cli/agents/context-reviewer-story.md +92 -0
- package/cli/agents/context-writer-epic.md +145 -0
- package/cli/agents/context-writer-story.md +111 -0
- package/cli/agents/doc-writer-epic.md +42 -0
- package/cli/agents/doc-writer-story.md +43 -0
- package/cli/agents/duplicate-detector.md +110 -0
- package/cli/agents/epic-story-decomposer.md +318 -39
- package/cli/agents/mission-scope-generator.md +68 -4
- package/cli/agents/mission-scope-validator.md +40 -6
- package/cli/agents/project-context-extractor.md +21 -6
- package/cli/agents/scaffolding-generator.md +99 -0
- package/cli/agents/seed-validator.md +71 -0
- package/cli/agents/story-scope-reviewer.md +147 -0
- package/cli/agents/story-splitter.md +83 -0
- package/cli/agents/validator-documentation.json +31 -0
- package/cli/agents/validator-documentation.md +3 -1
- package/cli/api-reference-tool.js +368 -0
- package/cli/checks/catalog.json +76 -0
- package/cli/checks/code/quality.json +26 -0
- package/cli/checks/code/testing.json +14 -0
- package/cli/checks/code/traceability.json +26 -0
- package/cli/checks/cross-refs/epic.json +171 -0
- package/cli/checks/cross-refs/story.json +149 -0
- package/cli/checks/epic/api.json +114 -0
- package/cli/checks/epic/backend.json +126 -0
- package/cli/checks/epic/cloud.json +126 -0
- package/cli/checks/epic/data.json +102 -0
- package/cli/checks/epic/database.json +114 -0
- package/cli/checks/epic/developer.json +182 -0
- package/cli/checks/epic/devops.json +174 -0
- package/cli/checks/epic/frontend.json +162 -0
- package/cli/checks/epic/mobile.json +102 -0
- package/cli/checks/epic/qa.json +90 -0
- package/cli/checks/epic/security.json +184 -0
- package/cli/checks/epic/solution-architect.json +192 -0
- package/cli/checks/epic/test-architect.json +90 -0
- package/cli/checks/epic/ui.json +102 -0
- package/cli/checks/epic/ux.json +90 -0
- package/cli/checks/fixes/epic-fix-template.md +10 -0
- package/cli/checks/fixes/story-fix-template.md +10 -0
- package/cli/checks/story/api.json +186 -0
- package/cli/checks/story/backend.json +102 -0
- package/cli/checks/story/cloud.json +102 -0
- package/cli/checks/story/data.json +210 -0
- package/cli/checks/story/database.json +102 -0
- package/cli/checks/story/developer.json +168 -0
- package/cli/checks/story/devops.json +102 -0
- package/cli/checks/story/frontend.json +174 -0
- package/cli/checks/story/mobile.json +102 -0
- package/cli/checks/story/qa.json +210 -0
- package/cli/checks/story/security.json +198 -0
- package/cli/checks/story/solution-architect.json +230 -0
- package/cli/checks/story/test-architect.json +210 -0
- package/cli/checks/story/ui.json +102 -0
- package/cli/checks/story/ux.json +102 -0
- package/cli/coding-order.js +401 -0
- package/cli/dependency-checker.js +72 -0
- package/cli/epic-story-validator.js +284 -799
- package/cli/index.js +0 -0
- package/cli/init-model-config.js +17 -10
- package/cli/init.js +514 -92
- package/cli/kanban-server-manager.js +1 -2
- package/cli/llm-claude.js +98 -31
- package/cli/llm-gemini.js +29 -5
- package/cli/llm-local.js +493 -0
- package/cli/llm-openai.js +262 -41
- package/cli/llm-provider.js +147 -8
- package/cli/llm-token-limits.js +113 -4
- package/cli/llm-verifier.js +209 -1
- package/cli/llm-xiaomi.js +143 -0
- package/cli/message-constants.js +3 -12
- package/cli/messaging-api.js +6 -12
- package/cli/micro-check-fixer.js +335 -0
- package/cli/micro-check-runner.js +449 -0
- package/cli/micro-check-scorer.js +148 -0
- package/cli/micro-check-validator.js +538 -0
- package/cli/model-pricing.js +23 -0
- package/cli/model-selector.js +3 -2
- package/cli/prompt-logger.js +57 -0
- package/cli/repl-ink.js +106 -346
- package/cli/repl-old.js +1 -2
- package/cli/seed-processor.js +194 -24
- package/cli/sprint-planning-processor.js +2638 -289
- package/cli/template-processor.js +50 -3
- package/cli/token-tracker.js +50 -23
- package/cli/tools/generate-story-validators.js +1 -1
- package/cli/validation-router.js +70 -8
- package/cli/worktree-runner.js +654 -0
- package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
- package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
- package/kanban/client/dist/index.html +2 -2
- package/kanban/client/src/App.jsx +43 -14
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
- package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
- package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
- package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
- package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
- package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
- package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
- package/kanban/client/src/components/stats/CostModal.jsx +34 -3
- package/kanban/client/src/hooks/useGrouping.js +59 -0
- package/kanban/client/src/lib/api.js +118 -4
- package/kanban/client/src/lib/status-grouping.js +10 -0
- package/kanban/client/src/store/kanbanStore.js +8 -0
- package/kanban/server/index.js +23 -2
- package/kanban/server/routes/ceremony.js +153 -4
- package/kanban/server/routes/costs.js +9 -3
- package/kanban/server/routes/openai-oauth.js +366 -0
- package/kanban/server/routes/settings.js +447 -14
- package/kanban/server/routes/websocket.js +7 -2
- package/kanban/server/routes/work-items.js +141 -1
- package/kanban/server/services/CeremonyService.js +275 -24
- package/kanban/server/services/TaskRunnerService.js +261 -0
- package/kanban/server/workers/run-task-worker.js +121 -0
- package/kanban/server/workers/seed-worker.js +94 -0
- package/kanban/server/workers/sponsor-call-worker.js +14 -6
- package/kanban/server/workers/sprint-planning-worker.js +94 -12
- package/package.json +2 -3
- package/cli/agents/solver-epic-api.json +0 -15
- package/cli/agents/solver-epic-api.md +0 -39
- package/cli/agents/solver-epic-backend.json +0 -15
- package/cli/agents/solver-epic-backend.md +0 -39
- package/cli/agents/solver-epic-cloud.json +0 -15
- package/cli/agents/solver-epic-cloud.md +0 -39
- package/cli/agents/solver-epic-data.json +0 -15
- package/cli/agents/solver-epic-data.md +0 -39
- package/cli/agents/solver-epic-database.json +0 -15
- package/cli/agents/solver-epic-database.md +0 -39
- package/cli/agents/solver-epic-developer.json +0 -15
- package/cli/agents/solver-epic-developer.md +0 -39
- package/cli/agents/solver-epic-devops.json +0 -15
- package/cli/agents/solver-epic-devops.md +0 -39
- package/cli/agents/solver-epic-frontend.json +0 -15
- package/cli/agents/solver-epic-frontend.md +0 -39
- package/cli/agents/solver-epic-mobile.json +0 -15
- package/cli/agents/solver-epic-mobile.md +0 -39
- package/cli/agents/solver-epic-qa.json +0 -15
- package/cli/agents/solver-epic-qa.md +0 -39
- package/cli/agents/solver-epic-security.json +0 -15
- package/cli/agents/solver-epic-security.md +0 -39
- package/cli/agents/solver-epic-solution-architect.json +0 -15
- package/cli/agents/solver-epic-solution-architect.md +0 -39
- package/cli/agents/solver-epic-test-architect.json +0 -15
- package/cli/agents/solver-epic-test-architect.md +0 -39
- package/cli/agents/solver-epic-ui.json +0 -15
- package/cli/agents/solver-epic-ui.md +0 -39
- package/cli/agents/solver-epic-ux.json +0 -15
- package/cli/agents/solver-epic-ux.md +0 -39
- package/cli/agents/solver-story-api.json +0 -15
- package/cli/agents/solver-story-api.md +0 -39
- package/cli/agents/solver-story-backend.json +0 -15
- package/cli/agents/solver-story-backend.md +0 -39
- package/cli/agents/solver-story-cloud.json +0 -15
- package/cli/agents/solver-story-cloud.md +0 -39
- package/cli/agents/solver-story-data.json +0 -15
- package/cli/agents/solver-story-data.md +0 -39
- package/cli/agents/solver-story-database.json +0 -15
- package/cli/agents/solver-story-database.md +0 -39
- package/cli/agents/solver-story-developer.json +0 -15
- package/cli/agents/solver-story-developer.md +0 -39
- package/cli/agents/solver-story-devops.json +0 -15
- package/cli/agents/solver-story-devops.md +0 -39
- package/cli/agents/solver-story-frontend.json +0 -15
- package/cli/agents/solver-story-frontend.md +0 -39
- package/cli/agents/solver-story-mobile.json +0 -15
- package/cli/agents/solver-story-mobile.md +0 -39
- package/cli/agents/solver-story-qa.json +0 -15
- package/cli/agents/solver-story-qa.md +0 -39
- package/cli/agents/solver-story-security.json +0 -15
- package/cli/agents/solver-story-security.md +0 -39
- package/cli/agents/solver-story-solution-architect.json +0 -15
- package/cli/agents/solver-story-solution-architect.md +0 -39
- package/cli/agents/solver-story-test-architect.json +0 -15
- package/cli/agents/solver-story-test-architect.md +0 -39
- package/cli/agents/solver-story-ui.json +0 -15
- package/cli/agents/solver-story-ui.md +0 -39
- package/cli/agents/solver-story-ux.json +0 -15
- package/cli/agents/solver-story-ux.md +0 -39
- package/cli/agents/validator-epic-api.json +0 -93
- package/cli/agents/validator-epic-api.md +0 -137
- package/cli/agents/validator-epic-backend.json +0 -93
- package/cli/agents/validator-epic-backend.md +0 -130
- package/cli/agents/validator-epic-cloud.json +0 -93
- package/cli/agents/validator-epic-cloud.md +0 -137
- package/cli/agents/validator-epic-data.json +0 -93
- package/cli/agents/validator-epic-data.md +0 -130
- package/cli/agents/validator-epic-database.json +0 -93
- package/cli/agents/validator-epic-database.md +0 -137
- package/cli/agents/validator-epic-developer.json +0 -74
- package/cli/agents/validator-epic-developer.md +0 -153
- package/cli/agents/validator-epic-devops.json +0 -74
- package/cli/agents/validator-epic-devops.md +0 -153
- package/cli/agents/validator-epic-frontend.json +0 -74
- package/cli/agents/validator-epic-frontend.md +0 -153
- package/cli/agents/validator-epic-mobile.json +0 -93
- package/cli/agents/validator-epic-mobile.md +0 -130
- package/cli/agents/validator-epic-qa.json +0 -93
- package/cli/agents/validator-epic-qa.md +0 -130
- package/cli/agents/validator-epic-security.json +0 -74
- package/cli/agents/validator-epic-security.md +0 -154
- package/cli/agents/validator-epic-solution-architect.json +0 -74
- package/cli/agents/validator-epic-solution-architect.md +0 -156
- package/cli/agents/validator-epic-test-architect.json +0 -93
- package/cli/agents/validator-epic-test-architect.md +0 -130
- package/cli/agents/validator-epic-ui.json +0 -93
- package/cli/agents/validator-epic-ui.md +0 -130
- package/cli/agents/validator-epic-ux.json +0 -93
- package/cli/agents/validator-epic-ux.md +0 -130
- package/cli/agents/validator-story-api.json +0 -104
- package/cli/agents/validator-story-api.md +0 -152
- package/cli/agents/validator-story-backend.json +0 -104
- package/cli/agents/validator-story-backend.md +0 -152
- package/cli/agents/validator-story-cloud.json +0 -104
- package/cli/agents/validator-story-cloud.md +0 -152
- package/cli/agents/validator-story-data.json +0 -104
- package/cli/agents/validator-story-data.md +0 -152
- package/cli/agents/validator-story-database.json +0 -104
- package/cli/agents/validator-story-database.md +0 -152
- package/cli/agents/validator-story-developer.json +0 -104
- package/cli/agents/validator-story-developer.md +0 -152
- package/cli/agents/validator-story-devops.json +0 -104
- package/cli/agents/validator-story-devops.md +0 -152
- package/cli/agents/validator-story-frontend.json +0 -104
- package/cli/agents/validator-story-frontend.md +0 -152
- package/cli/agents/validator-story-mobile.json +0 -104
- package/cli/agents/validator-story-mobile.md +0 -152
- package/cli/agents/validator-story-qa.json +0 -104
- package/cli/agents/validator-story-qa.md +0 -152
- package/cli/agents/validator-story-security.json +0 -104
- package/cli/agents/validator-story-security.md +0 -152
- package/cli/agents/validator-story-solution-architect.json +0 -104
- package/cli/agents/validator-story-solution-architect.md +0 -152
- package/cli/agents/validator-story-test-architect.json +0 -104
- package/cli/agents/validator-story-test-architect.md +0 -152
- package/cli/agents/validator-story-ui.json +0 -104
- package/cli/agents/validator-story-ui.md +0 -152
- package/cli/agents/validator-story-ux.json +0 -104
- package/cli/agents/validator-story-ux.md +0 -152
- package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
- package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<meta name="avc-kanban" content="true" />
|
|
8
8
|
<meta name="generator" content="Agile Vibe Coding" />
|
|
9
9
|
<title>AVC Kanban Board</title>
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-DjY5zqW7.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D_KC5EQT.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="root"></div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState, useMemo, useRef } from 'react';
|
|
2
2
|
import { Pencil, Check, X, BookOpen, Settings, DollarSign } from 'lucide-react';
|
|
3
|
-
import { getHealth, getBoardTitle, updateBoardTitle, getDocsUrl, getSettings, getModels, getCostSummary, getProjectStatus, getCeremonyStatus, continuePastCostLimit, cancelCeremony } from './lib/api';
|
|
3
|
+
import { getHealth, getBoardTitle, updateBoardTitle, getDocsUrl, getSettings, getModels, getCostSummary, getProjectStatus, getCeremonyStatus, continuePastCostLimit, continueAfterQuota, cancelCeremony } from './lib/api';
|
|
4
4
|
import { useWebSocket } from './hooks/useWebSocket';
|
|
5
5
|
import { useKanbanStore } from './store/kanbanStore';
|
|
6
6
|
import { useFilterStore } from './store/filterStore';
|
|
@@ -43,6 +43,9 @@ function App() {
|
|
|
43
43
|
// Cost-limit pause dialog — { cost, threshold, runningType } when ceremony hits limit
|
|
44
44
|
const [costLimitPending, setCostLimitPending] = useState(null);
|
|
45
45
|
|
|
46
|
+
// Quota-limit pause dialog — { provider, model, errMsg, validatorName, runningType } when quota exceeded
|
|
47
|
+
const [quotaLimitPending, setQuotaLimitPending] = useState(null);
|
|
48
|
+
|
|
46
49
|
// Refine work item state — { itemId, jobId, message } / { itemId, jobId, result } / { itemId, jobId, error }
|
|
47
50
|
const [refineProgress, setRefineProgress] = useState(null);
|
|
48
51
|
const [refineResult, setRefineResult] = useState(null);
|
|
@@ -54,7 +57,7 @@ function App() {
|
|
|
54
57
|
const [editingProjectFile, setEditingProjectFile] = useState(null); // 'doc' | null
|
|
55
58
|
|
|
56
59
|
// Zustand stores
|
|
57
|
-
const { workItems, loadWorkItems, loading, error } = useKanbanStore();
|
|
60
|
+
const { workItems, loadWorkItems, loading, error, setCeremonyActive } = useKanbanStore();
|
|
58
61
|
const { typeFilters, searchQuery } = useFilterStore();
|
|
59
62
|
const {
|
|
60
63
|
isOpen: ceremonyOpen,
|
|
@@ -122,6 +125,7 @@ function App() {
|
|
|
122
125
|
appendProgress({ type: 'detail', detail: message.detail });
|
|
123
126
|
} else if (message.type === 'ceremony:complete') {
|
|
124
127
|
setCostLimitPending(null);
|
|
128
|
+
setQuotaLimitPending(null);
|
|
125
129
|
setCeremonyStatus('complete');
|
|
126
130
|
setCeremonyResult(message.result);
|
|
127
131
|
setWizardStep(7);
|
|
@@ -134,6 +138,8 @@ function App() {
|
|
|
134
138
|
appendMissionProgress({ step: message.step, message: message.message });
|
|
135
139
|
} else if (message.type === 'ceremony:cost-limit') {
|
|
136
140
|
setCostLimitPending({ cost: message.cost, threshold: message.threshold, runningType: message.runningType });
|
|
141
|
+
} else if (message.type === 'ceremony:quota-limit') {
|
|
142
|
+
setQuotaLimitPending({ provider: message.provider, model: message.model, errMsg: message.errMsg, validatorName: message.validatorName, runningType: message.runningType });
|
|
137
143
|
} else if (message.type === 'cost:update') {
|
|
138
144
|
getCostSummary().then(setCostSummary).catch(() => { });
|
|
139
145
|
} else if (message.type === 'sprint-planning:progress') {
|
|
@@ -148,33 +154,48 @@ function App() {
|
|
|
148
154
|
setSprintPlanningStep(3);
|
|
149
155
|
} else if (message.type === 'sprint-planning:complete') {
|
|
150
156
|
setCostLimitPending(null);
|
|
157
|
+
setQuotaLimitPending(null);
|
|
151
158
|
setSprintPlanningStatus('complete');
|
|
152
159
|
setSprintPlanningResult(message.result);
|
|
153
160
|
setSprintPlanningDecomposedHierarchy(null);
|
|
154
161
|
setSprintPlanningStep(4);
|
|
162
|
+
setCeremonyActive(false);
|
|
155
163
|
loadWorkItems();
|
|
156
164
|
} else if (message.type === 'sprint-planning:error') {
|
|
157
165
|
setSprintPlanningStatus('error');
|
|
158
166
|
setSprintPlanningError(message.error);
|
|
167
|
+
setCeremonyActive(false);
|
|
159
168
|
} else if (message.type === 'sprint-planning:paused') {
|
|
160
169
|
setSprintPlanningPaused(true);
|
|
161
170
|
} else if (message.type === 'sprint-planning:resumed') {
|
|
162
171
|
setSprintPlanningPaused(false);
|
|
163
172
|
} else if (message.type === 'sprint-planning:cancelled') {
|
|
164
173
|
setCostLimitPending(null);
|
|
174
|
+
setQuotaLimitPending(null);
|
|
165
175
|
setSprintPlanningStatus('idle');
|
|
166
176
|
setSprintPlanningStep(1);
|
|
167
177
|
setSprintPlanningPaused(false);
|
|
168
178
|
setSprintPlanningDecomposedHierarchy(null);
|
|
179
|
+
setCeremonyActive(false);
|
|
169
180
|
} else if (message.type === 'ceremony:paused') {
|
|
170
181
|
setCeremonyPaused(true);
|
|
171
182
|
} else if (message.type === 'ceremony:resumed') {
|
|
172
183
|
setCeremonyPaused(false);
|
|
173
184
|
} else if (message.type === 'ceremony:cancelled') {
|
|
174
185
|
setCostLimitPending(null);
|
|
186
|
+
setQuotaLimitPending(null);
|
|
175
187
|
setCeremonyStatus('idle');
|
|
176
188
|
setWizardStep(1);
|
|
177
189
|
setCeremonyPaused(false);
|
|
190
|
+
} else if (message.type?.startsWith('seed:') || message.type?.startsWith('run-task:')) {
|
|
191
|
+
// Dispatch seed/run events to components via CustomEvent
|
|
192
|
+
window.dispatchEvent(new CustomEvent('avc-ws-message', { detail: message }));
|
|
193
|
+
// Refresh board on completion or error
|
|
194
|
+
if (message.type.endsWith(':complete') || message.type.endsWith(':error')) {
|
|
195
|
+
loadWorkItems();
|
|
196
|
+
}
|
|
197
|
+
} else if (message.type === 'refresh') {
|
|
198
|
+
loadWorkItems();
|
|
178
199
|
} else if (message.type === 'refine:progress') {
|
|
179
200
|
setRefineProgress({ itemId: message.itemId, jobId: message.jobId, message: message.message });
|
|
180
201
|
} else if (message.type === 'refine:complete') {
|
|
@@ -187,6 +208,7 @@ function App() {
|
|
|
187
208
|
handleProcessMessage(message);
|
|
188
209
|
if (message.processType === 'sprint-planning') {
|
|
189
210
|
setSprintPlanningProcessId(message.processId);
|
|
211
|
+
setCeremonyActive(true);
|
|
190
212
|
} else if (message.processType === 'sponsor-call') {
|
|
191
213
|
setCeremonyProcessId(message.processId);
|
|
192
214
|
}
|
|
@@ -196,8 +218,9 @@ function App() {
|
|
|
196
218
|
// Server sends this on WebSocket connect when a ceremony is already running.
|
|
197
219
|
// Restores client state without requiring an HTTP round-trip.
|
|
198
220
|
const cs = message.ceremonyStatus;
|
|
199
|
-
if (cs?.status === 'running' || cs?.status === 'cost-limit-pending' || cs?.status === 'awaiting-selection') {
|
|
221
|
+
if (cs?.status === 'running' || cs?.status === 'cost-limit-pending' || cs?.status === 'quota-limit-pending' || cs?.status === 'awaiting-selection') {
|
|
200
222
|
if (cs.runningType === 'sprint-planning') {
|
|
223
|
+
setCeremonyActive(true);
|
|
201
224
|
if (cs.status === 'awaiting-selection') {
|
|
202
225
|
setSprintPlanningStatus('awaiting-selection');
|
|
203
226
|
setSprintPlanningDecomposedHierarchy(cs.decomposedHierarchy || null);
|
|
@@ -215,6 +238,9 @@ function App() {
|
|
|
215
238
|
if (cs.status === 'cost-limit-pending' && cs.costLimitInfo) {
|
|
216
239
|
setCostLimitPending({ ...cs.costLimitInfo, runningType: cs.runningType });
|
|
217
240
|
}
|
|
241
|
+
if (cs.status === 'quota-limit-pending' && cs.quotaLimitInfo) {
|
|
242
|
+
setQuotaLimitPending({ ...cs.quotaLimitInfo, runningType: cs.runningType });
|
|
243
|
+
}
|
|
218
244
|
}
|
|
219
245
|
}
|
|
220
246
|
},
|
|
@@ -238,7 +264,7 @@ function App() {
|
|
|
238
264
|
|
|
239
265
|
// Restore running ceremony state BEFORE revealing projectFilesLoaded so the
|
|
240
266
|
// board never shows "Start" buttons for an already-running ceremony.
|
|
241
|
-
if (ceremonyState?.status === 'running' || ceremonyState?.status === 'cost-limit-pending' || ceremonyState?.status === 'awaiting-selection') {
|
|
267
|
+
if (ceremonyState?.status === 'running' || ceremonyState?.status === 'cost-limit-pending' || ceremonyState?.status === 'quota-limit-pending' || ceremonyState?.status === 'awaiting-selection') {
|
|
242
268
|
if (ceremonyState.runningType === 'sprint-planning') {
|
|
243
269
|
if (ceremonyState.status === 'awaiting-selection') {
|
|
244
270
|
setSprintPlanningStatus('awaiting-selection');
|
|
@@ -257,6 +283,9 @@ function App() {
|
|
|
257
283
|
if (ceremonyState.status === 'cost-limit-pending' && ceremonyState.costLimitInfo) {
|
|
258
284
|
setCostLimitPending({ ...ceremonyState.costLimitInfo, runningType: ceremonyState.runningType });
|
|
259
285
|
}
|
|
286
|
+
if (ceremonyState.status === 'quota-limit-pending' && ceremonyState.quotaLimitInfo) {
|
|
287
|
+
setQuotaLimitPending({ ...ceremonyState.quotaLimitInfo, runningType: ceremonyState.runningType });
|
|
288
|
+
}
|
|
260
289
|
}
|
|
261
290
|
|
|
262
291
|
setProjectFilesLoaded(true);
|
|
@@ -320,11 +349,13 @@ function App() {
|
|
|
320
349
|
|
|
321
350
|
// ── Settings modal ─────────────────────────────────────────────────────────
|
|
322
351
|
|
|
323
|
-
const
|
|
352
|
+
const [settingsInitialTab, setSettingsInitialTab] = useState('api-keys');
|
|
353
|
+
const openSettings = async (initialTab = 'api-keys') => {
|
|
324
354
|
try {
|
|
325
355
|
const [data, modelList] = await Promise.all([getSettings(), getModels()]);
|
|
326
356
|
setSettingsSnapshot(data);
|
|
327
357
|
setModelsSnapshot(modelList);
|
|
358
|
+
setSettingsInitialTab(initialTab);
|
|
328
359
|
setSettingsOpen(true);
|
|
329
360
|
} catch (err) {
|
|
330
361
|
console.error('Failed to load settings:', err);
|
|
@@ -337,6 +368,7 @@ function App() {
|
|
|
337
368
|
setSettingsSnapshot(data);
|
|
338
369
|
const title = await getBoardTitle();
|
|
339
370
|
setBoardTitle(title);
|
|
371
|
+
document.dispatchEvent(new CustomEvent('avc:settings-saved'));
|
|
340
372
|
} catch (err) {
|
|
341
373
|
console.error('Failed to refresh settings:', err);
|
|
342
374
|
}
|
|
@@ -486,7 +518,7 @@ function App() {
|
|
|
486
518
|
|
|
487
519
|
{/* Settings button */}
|
|
488
520
|
<button
|
|
489
|
-
onClick={openSettings}
|
|
521
|
+
onClick={() => openSettings()}
|
|
490
522
|
className="flex items-center gap-1.5 text-sm text-slate-500 hover:text-slate-800 transition-colors"
|
|
491
523
|
title="Project settings"
|
|
492
524
|
>
|
|
@@ -548,14 +580,7 @@ function App() {
|
|
|
548
580
|
|
|
549
581
|
{/* Footer */}
|
|
550
582
|
<footer className="bg-white border-t border-slate-200 py-4 text-center text-sm text-slate-500 flex-shrink-0">
|
|
551
|
-
|
|
552
|
-
href="https://agilevibecoding.org"
|
|
553
|
-
target="_blank"
|
|
554
|
-
rel="noopener noreferrer"
|
|
555
|
-
className="text-blue-600 hover:text-blue-700 hover:underline"
|
|
556
|
-
>
|
|
557
|
-
Agile Vibe Coding
|
|
558
|
-
</a>
|
|
583
|
+
Agile Vibe Coding
|
|
559
584
|
</footer>
|
|
560
585
|
|
|
561
586
|
{/* Detail Modal */}
|
|
@@ -589,6 +614,9 @@ function App() {
|
|
|
589
614
|
costLimitPending={costLimitPending?.runningType === 'sprint-planning' ? costLimitPending : null}
|
|
590
615
|
onContinuePastCostLimit={async () => { try { await continuePastCostLimit(); setCostLimitPending(null); } catch (_) {} }}
|
|
591
616
|
onCancelFromCostLimit={async () => { try { await cancelCeremony(); setCostLimitPending(null); } catch (_) {} }}
|
|
617
|
+
quotaLimitPending={quotaLimitPending?.runningType === 'sprint-planning' ? quotaLimitPending : null}
|
|
618
|
+
onContinueAfterQuota={async (newProvider, newModel) => { try { await continueAfterQuota(newProvider, newModel); setQuotaLimitPending(null); } catch (_) {} }}
|
|
619
|
+
onCancelFromQuota={async () => { try { await cancelCeremony(); setQuotaLimitPending(null); } catch (_) {} }}
|
|
592
620
|
/>
|
|
593
621
|
)}
|
|
594
622
|
|
|
@@ -602,6 +630,7 @@ function App() {
|
|
|
602
630
|
models={modelsSnapshot}
|
|
603
631
|
onClose={() => setSettingsOpen(false)}
|
|
604
632
|
onSaved={handleSettingsSaved}
|
|
633
|
+
initialTab={settingsInitialTab}
|
|
605
634
|
/>
|
|
606
635
|
)}
|
|
607
636
|
|
|
@@ -12,6 +12,7 @@ const KEY_LABELS = {
|
|
|
12
12
|
anthropic: 'Anthropic API Key (ANTHROPIC_API_KEY)',
|
|
13
13
|
gemini: 'Google Gemini API Key (GEMINI_API_KEY)',
|
|
14
14
|
openai: 'OpenAI API Key (OPENAI_API_KEY)',
|
|
15
|
+
xiaomi: 'Xiaomi MiMo API Key (XIAOMI_API_KEY)',
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const COST_TIER_COLOR = {
|
|
@@ -106,8 +107,11 @@ export function AskArchPopup({ onUse, onClose, onOpenSettings }) {
|
|
|
106
107
|
.then(([data, settings]) => {
|
|
107
108
|
setModels(data);
|
|
108
109
|
setApiKeyStatus(settings.apiKeys ?? {});
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
// Prefer "pro" tier model for architecture generation
|
|
111
|
+
const ready = data.filter((m) => settings.apiKeys?.[normalizeProvider(m.provider)]?.isSet);
|
|
112
|
+
const isPro = (id) => /pro|opus|sonnet/i.test(id);
|
|
113
|
+
const best = ready.find((m) => isPro(m.modelId)) || ready[0];
|
|
114
|
+
setSelectedModelId(best ? best.modelId : (data.length > 0 ? data[0].modelId : ''));
|
|
111
115
|
})
|
|
112
116
|
.catch(() => setError('Failed to load available models.'));
|
|
113
117
|
}, []);
|
|
@@ -264,7 +268,7 @@ export function AskArchPopup({ onUse, onClose, onOpenSettings }) {
|
|
|
264
268
|
{onOpenSettings && (
|
|
265
269
|
<button
|
|
266
270
|
type="button"
|
|
267
|
-
onClick={onOpenSettings}
|
|
271
|
+
onClick={() => onOpenSettings()}
|
|
268
272
|
className="flex items-center gap-1 text-xs font-medium bg-slate-900 text-white px-2.5 py-1 rounded-md hover:bg-slate-700 transition-colors"
|
|
269
273
|
>
|
|
270
274
|
<SettingsIcon className="w-3 h-3" />
|
|
@@ -14,6 +14,7 @@ const KEY_LABELS = {
|
|
|
14
14
|
anthropic: 'Anthropic API Key (ANTHROPIC_API_KEY)',
|
|
15
15
|
gemini: 'Google Gemini API Key (GEMINI_API_KEY)',
|
|
16
16
|
openai: 'OpenAI API Key (OPENAI_API_KEY)',
|
|
17
|
+
xiaomi: 'Xiaomi MiMo API Key (XIAOMI_API_KEY)',
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -224,24 +225,36 @@ export function AskModelPopup({ onUse, onClose, onOpenSettings }) {
|
|
|
224
225
|
.then(([data, settings]) => {
|
|
225
226
|
setModels(data);
|
|
226
227
|
setApiKeyStatus(settings.apiKeys ?? {});
|
|
227
|
-
// Auto-select
|
|
228
|
-
const
|
|
229
|
-
const
|
|
228
|
+
// Auto-select best models: prefer "pro" tier for generator, "flash/lite" for validator
|
|
229
|
+
const ready = data.filter((m) => settings.apiKeys?.[normalizeProvider(m.provider)]?.isSet);
|
|
230
|
+
const isPro = (id) => /pro|opus|sonnet/i.test(id);
|
|
231
|
+
const isLite = (id) => /flash|lite|haiku|mini/i.test(id);
|
|
232
|
+
const generator = ready.find((m) => isPro(m.modelId)) || ready[0];
|
|
233
|
+
const generatorId = generator ? generator.modelId : (data.length > 0 ? data[0].modelId : '');
|
|
230
234
|
setSelectedModelId(generatorId);
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
setSelectedValidatorModelId(
|
|
235
|
+
const validator = ready.find((m) => isLite(m.modelId) && m.modelId !== generatorId)
|
|
236
|
+
|| ready.find((m) => m.modelId !== generatorId)
|
|
237
|
+
|| generator;
|
|
238
|
+
setSelectedValidatorModelId(validator ? validator.modelId : generatorId);
|
|
235
239
|
})
|
|
236
240
|
.catch(() => setError('Failed to load available models.'));
|
|
237
241
|
}, []);
|
|
238
242
|
|
|
239
243
|
function recheckKeys() {
|
|
240
|
-
getSettings()
|
|
241
|
-
.then((s) =>
|
|
244
|
+
Promise.all([getSettings(), getModels()])
|
|
245
|
+
.then(([s, updatedModels]) => {
|
|
246
|
+
setApiKeyStatus(s.apiKeys ?? {});
|
|
247
|
+
setModels(updatedModels);
|
|
248
|
+
})
|
|
242
249
|
.catch(() => {});
|
|
243
250
|
}
|
|
244
251
|
|
|
252
|
+
// Auto-recheck when settings are saved from anywhere in the app
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
document.addEventListener('avc:settings-saved', recheckKeys);
|
|
255
|
+
return () => document.removeEventListener('avc:settings-saved', recheckKeys);
|
|
256
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
257
|
+
|
|
245
258
|
const selectedModel = models.find((m) => m.modelId === selectedModelId);
|
|
246
259
|
const selectedValidatorModel = models.find((m) => m.modelId === selectedValidatorModelId);
|
|
247
260
|
|
|
@@ -428,7 +441,7 @@ export function AskModelPopup({ onUse, onClose, onOpenSettings }) {
|
|
|
428
441
|
{onOpenSettings && (
|
|
429
442
|
<button
|
|
430
443
|
type="button"
|
|
431
|
-
onClick={onOpenSettings}
|
|
444
|
+
onClick={() => onOpenSettings()}
|
|
432
445
|
className="flex items-center gap-1 text-xs font-medium bg-slate-900 text-white px-2.5 py-1 rounded-md hover:bg-slate-700 transition-colors"
|
|
433
446
|
>
|
|
434
447
|
<SettingsIcon className="w-3 h-3" />
|