@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,91 @@
|
|
|
1
|
+
import { marked } from 'marked';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configure marked with safe defaults
|
|
5
|
+
*/
|
|
6
|
+
marked.setOptions({
|
|
7
|
+
gfm: true, // GitHub Flavored Markdown
|
|
8
|
+
breaks: true, // Line breaks as <br>
|
|
9
|
+
headerIds: true, // Add IDs to headers
|
|
10
|
+
mangle: false, // Don't mangle email addresses
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Render markdown to HTML
|
|
15
|
+
* @param {string} markdown - Markdown content
|
|
16
|
+
* @returns {string} HTML content
|
|
17
|
+
*/
|
|
18
|
+
export function renderMarkdown(markdown) {
|
|
19
|
+
if (!markdown || typeof markdown !== 'string') {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return marked.parse(markdown);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('Error rendering markdown:', error);
|
|
27
|
+
return `<p>Error rendering markdown: ${error.message}</p>`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Sanitize markdown content (remove potentially dangerous content)
|
|
33
|
+
* Note: For MVP, we're assuming trusted content from .avc/project/
|
|
34
|
+
* In production, consider using DOMPurify or similar
|
|
35
|
+
* @param {string} html - HTML content
|
|
36
|
+
* @returns {string} Sanitized HTML
|
|
37
|
+
*/
|
|
38
|
+
export function sanitizeHtml(html) {
|
|
39
|
+
// For now, just return as-is since content is from trusted source
|
|
40
|
+
// TODO: Add proper sanitization if exposing to untrusted users
|
|
41
|
+
return html;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extract the description (first paragraph after H1) from a doc.md string.
|
|
46
|
+
* @param {string} markdown
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
export function extractDescriptionFromDoc(markdown) {
|
|
50
|
+
if (!markdown) return '';
|
|
51
|
+
const lines = markdown.split('\n');
|
|
52
|
+
let pastH1 = false;
|
|
53
|
+
const descLines = [];
|
|
54
|
+
for (const line of lines) {
|
|
55
|
+
if (!pastH1) {
|
|
56
|
+
if (line.startsWith('# ')) pastH1 = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (line.startsWith('#') || line.startsWith('---')) break;
|
|
60
|
+
if (line.trim() === '' && descLines.length > 0) break;
|
|
61
|
+
if (line.trim()) descLines.push(line.trim());
|
|
62
|
+
}
|
|
63
|
+
return descLines.join(' ');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Replace the first paragraph after H1 with newDescription.
|
|
68
|
+
* Preserves all content below the first paragraph unchanged.
|
|
69
|
+
* @param {string} markdown
|
|
70
|
+
* @param {string} newDescription
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
export function updateDescriptionInDoc(markdown, newDescription) {
|
|
74
|
+
if (!markdown) return `\n\n${newDescription}\n`;
|
|
75
|
+
const lines = markdown.split('\n');
|
|
76
|
+
let h1Idx = -1, paraStart = -1, paraEnd = -1;
|
|
77
|
+
for (let i = 0; i < lines.length; i++) {
|
|
78
|
+
if (h1Idx === -1 && lines[i].startsWith('# ')) { h1Idx = i; continue; }
|
|
79
|
+
if (h1Idx !== -1 && paraStart === -1 && lines[i].trim()) { paraStart = i; continue; }
|
|
80
|
+
if (paraStart !== -1 && (!lines[i].trim() || lines[i].startsWith('#') || lines[i] === '---')) {
|
|
81
|
+
paraEnd = i; break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (paraStart === -1) {
|
|
85
|
+
lines.splice(h1Idx + 1, 0, '', newDescription);
|
|
86
|
+
return lines.join('\n');
|
|
87
|
+
}
|
|
88
|
+
if (paraEnd === -1) paraEnd = lines.length;
|
|
89
|
+
lines.splice(paraStart, paraEnd - paraStart, newDescription);
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status Column Grouping Logic
|
|
3
|
+
* Maps AVC work item statuses to logical kanban columns
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps status values to their display column
|
|
8
|
+
* Key: Column name
|
|
9
|
+
* Value: Array of status values that belong in that column
|
|
10
|
+
*/
|
|
11
|
+
export const STATUS_COLUMN_MAPPING = {
|
|
12
|
+
Backlog: ['planned', 'pending'],
|
|
13
|
+
Ready: ['ready'],
|
|
14
|
+
'In Progress': ['implementing', 'feedback'],
|
|
15
|
+
Review: ['implemented', 'testing'],
|
|
16
|
+
Done: ['completed'],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Metadata for each status value
|
|
21
|
+
* Used for badges, colors, icons within grouped columns
|
|
22
|
+
*/
|
|
23
|
+
export const STATUS_METADATA = {
|
|
24
|
+
planned: { color: 'gray', icon: '📋', label: 'Planned' },
|
|
25
|
+
pending: { color: 'slate', icon: '⏸️', label: 'Pending' },
|
|
26
|
+
ready: { color: 'blue', icon: '🚀', label: 'Ready' },
|
|
27
|
+
implementing: { color: 'yellow', icon: '⚙️', label: 'Implementing' },
|
|
28
|
+
feedback: { color: 'amber', icon: '💬', label: 'Feedback' },
|
|
29
|
+
implemented: { color: 'purple', icon: '✅', label: 'Implemented' },
|
|
30
|
+
testing: { color: 'violet', icon: '🧪', label: 'Testing' },
|
|
31
|
+
completed: { color: 'green', icon: '🎉', label: 'Completed' },
|
|
32
|
+
blocked: { color: 'red', icon: '🚫', label: 'Blocked' },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Canonical order for columns on the board
|
|
37
|
+
*/
|
|
38
|
+
export const COLUMN_ORDER = ['Backlog', 'Ready', 'In Progress', 'Review', 'Done'];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the column name for a given status
|
|
42
|
+
* @param {string} status - Work item status
|
|
43
|
+
* @returns {string|null} Column name or null if not found
|
|
44
|
+
*/
|
|
45
|
+
export function getColumnForStatus(status) {
|
|
46
|
+
for (const [column, statuses] of Object.entries(STATUS_COLUMN_MAPPING)) {
|
|
47
|
+
if (statuses.includes(status)) {
|
|
48
|
+
return column;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get metadata for a status
|
|
56
|
+
* @param {string} status - Work item status
|
|
57
|
+
* @returns {object|null} Status metadata or null if not found
|
|
58
|
+
*/
|
|
59
|
+
export function getStatusMetadata(status) {
|
|
60
|
+
return STATUS_METADATA[status] || null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Group work items by column
|
|
65
|
+
* @param {Array} workItems - Array of work items
|
|
66
|
+
* @returns {object} Object with column names as keys, arrays of work items as values
|
|
67
|
+
*/
|
|
68
|
+
export function groupItemsByColumn(workItems) {
|
|
69
|
+
const grouped = {};
|
|
70
|
+
|
|
71
|
+
// Initialize all columns as empty arrays
|
|
72
|
+
COLUMN_ORDER.forEach((column) => {
|
|
73
|
+
grouped[column] = [];
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Group items by their column
|
|
77
|
+
workItems.forEach((item) => {
|
|
78
|
+
const column = getColumnForStatus(item.status);
|
|
79
|
+
if (column && grouped[column]) {
|
|
80
|
+
grouped[column].push(item);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return grouped;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get statistics for a column
|
|
89
|
+
* @param {Array} workItems - Work items in the column
|
|
90
|
+
* @returns {object} Statistics object with total count and breakdown by status
|
|
91
|
+
*/
|
|
92
|
+
export function getColumnStats(workItems) {
|
|
93
|
+
const stats = {
|
|
94
|
+
total: workItems.length,
|
|
95
|
+
byStatus: {},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
workItems.forEach((item) => {
|
|
99
|
+
const status = item.status;
|
|
100
|
+
if (!stats.byStatus[status]) {
|
|
101
|
+
stats.byStatus[status] = 0;
|
|
102
|
+
}
|
|
103
|
+
stats.byStatus[status]++;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return stats;
|
|
107
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sponsor Call Worker
|
|
3
|
+
* Forked by CeremonyService.runSponsorCallInProcess().
|
|
4
|
+
* Same IPC protocol as sprint-planning-worker.js.
|
|
5
|
+
* Receives `requirements` in the init message.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ProjectInitiator } from '../../../cli/init.js';
|
|
9
|
+
import { CommandLogger } from '../../../cli/command-logger.js';
|
|
10
|
+
|
|
11
|
+
let _paused = false;
|
|
12
|
+
let _cancelled = false;
|
|
13
|
+
let _requirements = null;
|
|
14
|
+
let _costThreshold = null;
|
|
15
|
+
let _waitingCostLimit = false;
|
|
16
|
+
|
|
17
|
+
// Parent server stopped — exit rather than running as an orphan.
|
|
18
|
+
process.on('disconnect', () => {
|
|
19
|
+
_cancelled = true;
|
|
20
|
+
// Give the current LLM call up to 5s to finish, then hard-exit.
|
|
21
|
+
setTimeout(() => process.exit(1), 5000).unref();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
process.on('message', async (msg) => {
|
|
25
|
+
if (msg.type === 'init') {
|
|
26
|
+
_requirements = msg.requirements;
|
|
27
|
+
_costThreshold = msg.costThreshold ?? null;
|
|
28
|
+
run();
|
|
29
|
+
} else if (msg.type === 'pause') {
|
|
30
|
+
_paused = true;
|
|
31
|
+
process.send({ type: 'paused' });
|
|
32
|
+
} else if (msg.type === 'resume') {
|
|
33
|
+
_paused = false;
|
|
34
|
+
process.send({ type: 'resumed' });
|
|
35
|
+
} else if (msg.type === 'cancel') {
|
|
36
|
+
_cancelled = true;
|
|
37
|
+
} else if (msg.type === 'cost-limit-continue') {
|
|
38
|
+
_waitingCostLimit = false;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
async function run() {
|
|
43
|
+
const logger = new CommandLogger('sponsor-call', process.cwd());
|
|
44
|
+
logger.start();
|
|
45
|
+
try {
|
|
46
|
+
const initiator = new ProjectInitiator();
|
|
47
|
+
|
|
48
|
+
const progressCallback = async (msg, substep, meta) => {
|
|
49
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
50
|
+
while (_paused) {
|
|
51
|
+
await new Promise(r => setTimeout(r, 200));
|
|
52
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
53
|
+
}
|
|
54
|
+
if (msg) process.send({ type: 'progress', message: msg });
|
|
55
|
+
if (substep) process.send({ type: 'substep', substep, meta: meta || {} });
|
|
56
|
+
if (meta?.detail) process.send({ type: 'detail', detail: meta.detail });
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const costLimitReachedCallback = async (cost) => {
|
|
60
|
+
_waitingCostLimit = true;
|
|
61
|
+
process.send({ type: 'cost-limit', cost, threshold: _costThreshold });
|
|
62
|
+
while (_waitingCostLimit) {
|
|
63
|
+
await new Promise(r => setTimeout(r, 200));
|
|
64
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = await initiator.sponsorCallWithAnswers(_requirements, progressCallback, {
|
|
69
|
+
costThreshold: _costThreshold,
|
|
70
|
+
costLimitReachedCallback,
|
|
71
|
+
});
|
|
72
|
+
logger.stop();
|
|
73
|
+
process.send({ type: 'complete', result });
|
|
74
|
+
process.exit(0);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
logger.stop();
|
|
77
|
+
if (err.message === 'CEREMONY_CANCELLED') {
|
|
78
|
+
process.send({ type: 'cancelled' });
|
|
79
|
+
} else {
|
|
80
|
+
process.send({ type: 'error', error: err.message });
|
|
81
|
+
}
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprint Planning Worker
|
|
3
|
+
* Forked by CeremonyService.runSprintPlanningInProcess().
|
|
4
|
+
* Communicates with the parent via IPC (process.send / process.on('message')).
|
|
5
|
+
*
|
|
6
|
+
* Parent → Worker:
|
|
7
|
+
* { type: 'init' }
|
|
8
|
+
* { type: 'pause' }
|
|
9
|
+
* { type: 'resume' }
|
|
10
|
+
* { type: 'cancel' }
|
|
11
|
+
* { type: 'selection-confirmed', selectedEpicIds, selectedStoryIds }
|
|
12
|
+
*
|
|
13
|
+
* Worker → Parent:
|
|
14
|
+
* { type: 'progress', message }
|
|
15
|
+
* { type: 'substep', substep, meta }
|
|
16
|
+
* { type: 'detail', detail }
|
|
17
|
+
* { type: 'paused' }
|
|
18
|
+
* { type: 'resumed' }
|
|
19
|
+
* { type: 'decomposition-complete', hierarchy }
|
|
20
|
+
* { type: 'complete', result }
|
|
21
|
+
* { type: 'cancelled' }
|
|
22
|
+
* { type: 'error', error }
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { ProjectInitiator } from '../../../cli/init.js';
|
|
26
|
+
import { CommandLogger } from '../../../cli/command-logger.js';
|
|
27
|
+
|
|
28
|
+
let _paused = false;
|
|
29
|
+
let _cancelled = false;
|
|
30
|
+
let _costThreshold = null;
|
|
31
|
+
let _waitingCostLimit = false;
|
|
32
|
+
let _waitingSelection = false;
|
|
33
|
+
let _selectionResult = null;
|
|
34
|
+
|
|
35
|
+
// Parent server stopped — exit rather than running as an orphan.
|
|
36
|
+
process.on('disconnect', () => {
|
|
37
|
+
_cancelled = true;
|
|
38
|
+
// Give the current LLM call up to 5s to finish, then hard-exit.
|
|
39
|
+
setTimeout(() => process.exit(1), 5000).unref();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
process.on('message', async (msg) => {
|
|
43
|
+
if (msg.type === 'init') {
|
|
44
|
+
_costThreshold = msg.costThreshold ?? null;
|
|
45
|
+
run();
|
|
46
|
+
} else if (msg.type === 'pause') {
|
|
47
|
+
_paused = true;
|
|
48
|
+
process.send({ type: 'paused' });
|
|
49
|
+
} else if (msg.type === 'resume') {
|
|
50
|
+
_paused = false;
|
|
51
|
+
process.send({ type: 'resumed' });
|
|
52
|
+
} else if (msg.type === 'cancel') {
|
|
53
|
+
_cancelled = true;
|
|
54
|
+
} else if (msg.type === 'cost-limit-continue') {
|
|
55
|
+
_waitingCostLimit = false;
|
|
56
|
+
} else if (msg.type === 'selection-confirmed') {
|
|
57
|
+
_selectionResult = { selectedEpicIds: msg.selectedEpicIds, selectedStoryIds: msg.selectedStoryIds };
|
|
58
|
+
_waitingSelection = false;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
async function run() {
|
|
63
|
+
const logger = new CommandLogger('sprint-planning', process.cwd());
|
|
64
|
+
logger.start();
|
|
65
|
+
try {
|
|
66
|
+
const initiator = new ProjectInitiator();
|
|
67
|
+
|
|
68
|
+
const progressCallback = async (msg, substep, meta) => {
|
|
69
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
70
|
+
while (_paused) {
|
|
71
|
+
await new Promise(r => setTimeout(r, 200));
|
|
72
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
73
|
+
}
|
|
74
|
+
if (msg) process.send({ type: 'progress', message: msg });
|
|
75
|
+
if (substep) process.send({ type: 'substep', substep, meta: meta || {} });
|
|
76
|
+
if (meta?.detail) process.send({ type: 'detail', detail: meta.detail });
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const costLimitReachedCallback = async (cost) => {
|
|
80
|
+
_waitingCostLimit = true;
|
|
81
|
+
process.send({ type: 'cost-limit', cost, threshold: _costThreshold });
|
|
82
|
+
while (_waitingCostLimit) {
|
|
83
|
+
await new Promise(r => setTimeout(r, 200));
|
|
84
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const selectionCallback = async (hierarchy) => {
|
|
89
|
+
_waitingSelection = true;
|
|
90
|
+
_selectionResult = null;
|
|
91
|
+
process.send({ type: 'decomposition-complete', hierarchy });
|
|
92
|
+
while (_waitingSelection) {
|
|
93
|
+
await new Promise(r => setTimeout(r, 200));
|
|
94
|
+
if (_cancelled) throw new Error('CEREMONY_CANCELLED');
|
|
95
|
+
}
|
|
96
|
+
return _selectionResult;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const result = await initiator.sprintPlanningWithCallback(progressCallback, {
|
|
100
|
+
costThreshold: _costThreshold,
|
|
101
|
+
costLimitReachedCallback,
|
|
102
|
+
selectionCallback,
|
|
103
|
+
});
|
|
104
|
+
logger.stop();
|
|
105
|
+
process.send({ type: 'complete', result });
|
|
106
|
+
|
|
107
|
+
// Non-fatal docs sync after ceremony completes
|
|
108
|
+
try {
|
|
109
|
+
const { DocsSyncProcessor } = await import('../../../cli/docs-sync.js');
|
|
110
|
+
const syncer = new DocsSyncProcessor(process.cwd());
|
|
111
|
+
const { existsSync } = await import('fs');
|
|
112
|
+
if (existsSync(syncer.docsDir)) {
|
|
113
|
+
await syncer.sync();
|
|
114
|
+
process.send({ type: 'docs-synced' });
|
|
115
|
+
}
|
|
116
|
+
} catch (e) {
|
|
117
|
+
process.send({ type: 'docs-sync-failed', error: e.message });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
process.exit(0);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
logger.stop();
|
|
123
|
+
if (err.message === 'CEREMONY_CANCELLED') {
|
|
124
|
+
process.send({ type: 'cancelled' });
|
|
125
|
+
} else {
|
|
126
|
+
process.send({ type: 'error', error: err.message });
|
|
127
|
+
}
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agile-vibe-coding/avc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Agile Vibe Coding (AVC) - Framework for managing AI agent-based software development projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"cli/",
|
|
12
|
+
"kanban/",
|
|
12
13
|
"README.md",
|
|
13
14
|
"LICENSE"
|
|
14
15
|
],
|
|
@@ -22,6 +23,9 @@
|
|
|
22
23
|
"test:watch": "vitest watch",
|
|
23
24
|
"test:coverage": "vitest run --coverage",
|
|
24
25
|
"test:ui": "vitest --ui",
|
|
26
|
+
"models:evaluate": "node cli/model-selector.js",
|
|
27
|
+
"models:tables": "node cli/generate-summary-table.js",
|
|
28
|
+
"test:e2e": "node tests/e2e/cli-e2e.js",
|
|
25
29
|
"prepublishOnly": "echo \"Running pre-publish checks...\" && npm test"
|
|
26
30
|
},
|
|
27
31
|
"keywords": [
|
|
@@ -39,7 +43,7 @@
|
|
|
39
43
|
"workflow"
|
|
40
44
|
],
|
|
41
45
|
"author": "Nacho Coll",
|
|
42
|
-
"license": "
|
|
46
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
43
47
|
"homepage": "https://agilevibecoding.org",
|
|
44
48
|
"repository": {
|
|
45
49
|
"type": "git",
|
|
@@ -50,22 +54,31 @@
|
|
|
50
54
|
"url": "https://github.com/NachoColl/agilevibecoding/issues"
|
|
51
55
|
},
|
|
52
56
|
"engines": {
|
|
53
|
-
"node": ">=
|
|
57
|
+
"node": ">=20.0.0"
|
|
54
58
|
},
|
|
55
59
|
"dependencies": {
|
|
56
60
|
"@anthropic-ai/sdk": "^0.20.0",
|
|
57
61
|
"@google/genai": "^1.37.0",
|
|
62
|
+
"chokidar": "^4.0.3",
|
|
63
|
+
"cors": "^2.8.5",
|
|
58
64
|
"dotenv": "^16.4.0",
|
|
59
|
-
"
|
|
65
|
+
"express": "^4.21.2",
|
|
66
|
+
"ink": "^6.7.0",
|
|
60
67
|
"ink-select-input": "^6.0.0",
|
|
61
68
|
"ink-spinner": "^5.0.0",
|
|
62
|
-
"
|
|
69
|
+
"jsonrepair": "^3.13.2",
|
|
70
|
+
"marked": "^15.0.6",
|
|
71
|
+
"openai": "^6.19.0",
|
|
72
|
+
"react": "^19.0.0",
|
|
73
|
+
"vitepress": "^1.6.4",
|
|
74
|
+
"ws": "^8.18.0"
|
|
63
75
|
},
|
|
64
76
|
"devDependencies": {
|
|
65
77
|
"@sinonjs/fake-timers": "^12.0.0",
|
|
66
78
|
"@vitest/coverage-v8": "^2.1.9",
|
|
67
79
|
"@vitest/ui": "^2.1.9",
|
|
68
80
|
"memfs": "^4.56.10",
|
|
81
|
+
"node-pty": "^1.1.0",
|
|
69
82
|
"sinon": "^19.0.5",
|
|
70
83
|
"vitest": "^2.1.9"
|
|
71
84
|
}
|