@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,347 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import fsSync from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { renderMarkdown, extractDescriptionFromDoc } from '../utils/markdown.js';
|
|
6
|
+
import { groupItemsByColumn, getColumnStats } from '../utils/status-grouping.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create work items router
|
|
10
|
+
* @param {object} dataStore - Data store with work items
|
|
11
|
+
* @returns {express.Router}
|
|
12
|
+
*/
|
|
13
|
+
export function createWorkItemsRouter(dataStore, refineService) {
|
|
14
|
+
const router = express.Router();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* GET /api/work-items
|
|
18
|
+
* Get all work items as hierarchical JSON
|
|
19
|
+
*/
|
|
20
|
+
router.get('/', (req, res) => {
|
|
21
|
+
try {
|
|
22
|
+
const { items, roots } = dataStore.getHierarchy();
|
|
23
|
+
|
|
24
|
+
// Convert Map to array
|
|
25
|
+
const allItems = Array.from(items.values());
|
|
26
|
+
|
|
27
|
+
// Apply filters if provided
|
|
28
|
+
let filtered = allItems;
|
|
29
|
+
|
|
30
|
+
// Filter by type
|
|
31
|
+
if (req.query.type) {
|
|
32
|
+
const types = req.query.type.split(',');
|
|
33
|
+
filtered = filtered.filter((item) => types.includes(item._type));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Filter by status
|
|
37
|
+
if (req.query.status) {
|
|
38
|
+
const statuses = req.query.status.split(',');
|
|
39
|
+
filtered = filtered.filter((item) => statuses.includes(item.status));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Search query
|
|
43
|
+
if (req.query.search) {
|
|
44
|
+
const search = req.query.search.toLowerCase();
|
|
45
|
+
filtered = filtered.filter(
|
|
46
|
+
(item) =>
|
|
47
|
+
item.name.toLowerCase().includes(search) ||
|
|
48
|
+
item.id.toLowerCase().includes(search) ||
|
|
49
|
+
(item.description && item.description.toLowerCase().includes(search))
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Clean items (remove circular references for JSON serialization)
|
|
54
|
+
const cleanItems = filtered.map((item) => cleanWorkItem(item));
|
|
55
|
+
|
|
56
|
+
res.json({
|
|
57
|
+
items: cleanItems,
|
|
58
|
+
total: cleanItems.length,
|
|
59
|
+
roots: roots.map((r) => r.id),
|
|
60
|
+
});
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('Error getting work items:', error);
|
|
63
|
+
res.status(500).json({ error: 'Failed to get work items' });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* GET /api/work-items/grouped
|
|
69
|
+
* Get work items grouped by column
|
|
70
|
+
*/
|
|
71
|
+
router.get('/grouped', (req, res) => {
|
|
72
|
+
try {
|
|
73
|
+
const { items } = dataStore.getHierarchy();
|
|
74
|
+
const allItems = Array.from(items.values());
|
|
75
|
+
|
|
76
|
+
// Group by column
|
|
77
|
+
const grouped = groupItemsByColumn(allItems);
|
|
78
|
+
|
|
79
|
+
// Add statistics for each column
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const [column, columnItems] of Object.entries(grouped)) {
|
|
82
|
+
result[column] = {
|
|
83
|
+
items: columnItems.map((item) => cleanWorkItem(item)),
|
|
84
|
+
stats: getColumnStats(columnItems),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
res.json(result);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('Error getting grouped work items:', error);
|
|
91
|
+
res.status(500).json({ error: 'Failed to get grouped work items' });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* GET /api/work-items/:id
|
|
97
|
+
* Get single work item with full details
|
|
98
|
+
*/
|
|
99
|
+
router.get('/:id', async (req, res) => {
|
|
100
|
+
try {
|
|
101
|
+
const { items } = dataStore.getHierarchy();
|
|
102
|
+
const item = items.get(req.params.id);
|
|
103
|
+
|
|
104
|
+
if (!item) {
|
|
105
|
+
return res.status(404).json({ error: 'Work item not found' });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Get full details (including doc.md and context.md)
|
|
109
|
+
const fullItem = await dataStore.getFullDetails(item);
|
|
110
|
+
|
|
111
|
+
res.json(cleanWorkItem(fullItem, true));
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(`Error getting work item ${req.params.id}:`, error);
|
|
114
|
+
res.status(500).json({ error: 'Failed to get work item' });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* GET /api/work-items/:id/doc
|
|
120
|
+
* Get rendered documentation (doc.md) as HTML
|
|
121
|
+
*/
|
|
122
|
+
router.get('/:id/doc', async (req, res) => {
|
|
123
|
+
try {
|
|
124
|
+
const { items } = dataStore.getHierarchy();
|
|
125
|
+
const item = items.get(req.params.id);
|
|
126
|
+
|
|
127
|
+
if (!item) {
|
|
128
|
+
return res.status(404).json({ error: 'Work item not found' });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const fullItem = await dataStore.getFullDetails(item);
|
|
132
|
+
|
|
133
|
+
if (!fullItem.documentation) {
|
|
134
|
+
return res.status(404).json({ error: 'Documentation not found' });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const html = renderMarkdown(fullItem.documentation);
|
|
138
|
+
res.send(html);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(`Error getting documentation for ${req.params.id}:`, error);
|
|
141
|
+
res.status(500).json({ error: 'Failed to get documentation' });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* GET /api/work-items/:id/doc/raw
|
|
147
|
+
* Get raw markdown source of doc.md
|
|
148
|
+
*/
|
|
149
|
+
router.get('/:id/doc/raw', async (req, res) => {
|
|
150
|
+
try {
|
|
151
|
+
const { items } = dataStore.getHierarchy();
|
|
152
|
+
const item = items.get(req.params.id);
|
|
153
|
+
if (!item) return res.status(404).json({ error: 'Work item not found' });
|
|
154
|
+
|
|
155
|
+
const fullItem = await dataStore.getFullDetails(item);
|
|
156
|
+
if (!fullItem.documentation) return res.status(404).json({ error: 'Documentation not found' });
|
|
157
|
+
|
|
158
|
+
res.type('text/plain').send(fullItem.documentation);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(`Error getting raw doc for ${req.params.id}:`, error);
|
|
161
|
+
res.status(500).json({ error: 'Failed to get documentation' });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* POST /api/work-items/:id/refine
|
|
167
|
+
* Start an async refinement job for an epic or story.
|
|
168
|
+
* Body: { refinementRequest?, selectedIssues?, modelId, provider, validatorModelId, validatorProvider }
|
|
169
|
+
* Returns: { jobId }
|
|
170
|
+
*/
|
|
171
|
+
router.post('/:id/refine', async (req, res) => {
|
|
172
|
+
try {
|
|
173
|
+
if (!refineService) {
|
|
174
|
+
return res.status(503).json({ error: 'Refine service not available' });
|
|
175
|
+
}
|
|
176
|
+
const { items } = dataStore.getHierarchy();
|
|
177
|
+
const item = items.get(req.params.id);
|
|
178
|
+
if (!item) return res.status(404).json({ error: 'Work item not found' });
|
|
179
|
+
|
|
180
|
+
const { refinementRequest, selectedIssues, modelId, provider, validatorModelId, validatorProvider } =
|
|
181
|
+
req.body;
|
|
182
|
+
|
|
183
|
+
if (!modelId || !provider || !validatorModelId || !validatorProvider) {
|
|
184
|
+
return res.status(400).json({
|
|
185
|
+
error: 'modelId, provider, validatorModelId and validatorProvider are required',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const fullItem = await dataStore.getFullDetails(item);
|
|
190
|
+
const cleanItem = cleanWorkItem(fullItem, true);
|
|
191
|
+
|
|
192
|
+
const jobId = await refineService.startRefine(req.params.id, cleanItem, {
|
|
193
|
+
refinementRequest: refinementRequest || '',
|
|
194
|
+
selectedIssues: selectedIssues || [],
|
|
195
|
+
modelId,
|
|
196
|
+
provider,
|
|
197
|
+
validatorModelId,
|
|
198
|
+
validatorProvider,
|
|
199
|
+
itemDirPath: item._dirPath,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
res.json({ jobId });
|
|
203
|
+
} catch (err) {
|
|
204
|
+
console.error(`Error starting refine for ${req.params.id}:`, err);
|
|
205
|
+
res.status(500).json({ error: err.message });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* PUT /api/work-items/:id
|
|
211
|
+
* Apply accepted refinement changes to work.json on disk.
|
|
212
|
+
* Body: { proposedItem, storyChanges? }
|
|
213
|
+
*/
|
|
214
|
+
router.put('/:id', async (req, res) => {
|
|
215
|
+
try {
|
|
216
|
+
if (!refineService) {
|
|
217
|
+
return res.status(503).json({ error: 'Refine service not available' });
|
|
218
|
+
}
|
|
219
|
+
const { proposedItem, storyChanges } = req.body;
|
|
220
|
+
if (!proposedItem) return res.status(400).json({ error: 'proposedItem is required' });
|
|
221
|
+
|
|
222
|
+
// Build a dirPath map from the in-memory data store so applyChanges doesn't
|
|
223
|
+
// need to walk the filesystem (which can silently fail).
|
|
224
|
+
const { items } = dataStore.getHierarchy();
|
|
225
|
+
const item = items.get(req.params.id);
|
|
226
|
+
if (!item) return res.status(404).json({ error: 'Work item not found' });
|
|
227
|
+
|
|
228
|
+
const dirPathMap = new Map([[item.id, item._dirPath]]);
|
|
229
|
+
for (const change of (storyChanges || [])) {
|
|
230
|
+
if (change.storyId) {
|
|
231
|
+
const storyItem = items.get(change.storyId);
|
|
232
|
+
if (storyItem) dirPathMap.set(change.storyId, storyItem._dirPath);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
await refineService.applyChanges(req.params.id, proposedItem, storyChanges || [], dirPathMap);
|
|
237
|
+
res.json({ status: 'ok' });
|
|
238
|
+
} catch (err) {
|
|
239
|
+
console.error(`Error applying changes for ${req.params.id}:`, err);
|
|
240
|
+
res.status(500).json({ error: err.message });
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* PUT /api/work-items/:id/doc
|
|
246
|
+
* Save updated markdown content to doc.md
|
|
247
|
+
*/
|
|
248
|
+
router.put('/:id/doc', async (req, res) => {
|
|
249
|
+
try {
|
|
250
|
+
const { items } = dataStore.getHierarchy();
|
|
251
|
+
const item = items.get(req.params.id);
|
|
252
|
+
if (!item) return res.status(404).json({ error: 'Work item not found' });
|
|
253
|
+
|
|
254
|
+
const markdown = req.body.content;
|
|
255
|
+
if (typeof markdown !== 'string') {
|
|
256
|
+
return res.status(400).json({ error: 'content must be a string' });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const docPath = path.join(item._dirPath, 'doc.md');
|
|
260
|
+
await fs.writeFile(docPath, markdown, 'utf8');
|
|
261
|
+
|
|
262
|
+
// Sync work.json description cache so kanban cards stay in sync
|
|
263
|
+
const newDescription = extractDescriptionFromDoc(markdown);
|
|
264
|
+
if (newDescription) {
|
|
265
|
+
const workJsonPath = path.join(item._dirPath, 'work.json');
|
|
266
|
+
if (fsSync.existsSync(workJsonPath)) {
|
|
267
|
+
const workJson = JSON.parse(fsSync.readFileSync(workJsonPath, 'utf8'));
|
|
268
|
+
workJson.description = newDescription;
|
|
269
|
+
fsSync.writeFileSync(workJsonPath, JSON.stringify(workJson, null, 2), 'utf8');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
res.json({ status: 'ok' });
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(`Error saving doc for ${req.params.id}:`, error);
|
|
276
|
+
res.status(500).json({ error: 'Failed to save documentation' });
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return router;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Clean work item for JSON serialization
|
|
285
|
+
* Removes circular references and internal fields
|
|
286
|
+
* @param {object} item - Work item
|
|
287
|
+
* @param {boolean} includeFullDetails - Include documentation and context
|
|
288
|
+
* @returns {object} Cleaned work item
|
|
289
|
+
*/
|
|
290
|
+
function cleanWorkItem(item, includeFullDetails = false) {
|
|
291
|
+
const cleaned = {
|
|
292
|
+
id: item.id,
|
|
293
|
+
name: item.name,
|
|
294
|
+
type: item._type,
|
|
295
|
+
status: item.status,
|
|
296
|
+
description: item.description,
|
|
297
|
+
dependencies: item.dependencies || [],
|
|
298
|
+
metadata: item.metadata,
|
|
299
|
+
created: item.created,
|
|
300
|
+
updated: item.updated,
|
|
301
|
+
// Type-specific fields used for diff display in RefineWorkItemPopup
|
|
302
|
+
features: item.features, // epics
|
|
303
|
+
acceptance: item.acceptance, // stories
|
|
304
|
+
userType: item.userType, // stories
|
|
305
|
+
domain: item.domain, // epics
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Add parent reference (ID only, not full object)
|
|
309
|
+
if (item._parentId) {
|
|
310
|
+
cleaned.parentId = item._parentId;
|
|
311
|
+
cleaned.parentName = item._parent?.name;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Add children references (IDs only)
|
|
315
|
+
if (item._children && item._children.length > 0) {
|
|
316
|
+
cleaned.children = item._children.map((child) => ({
|
|
317
|
+
id: child.id,
|
|
318
|
+
name: child.name,
|
|
319
|
+
type: child._type,
|
|
320
|
+
status: child.status,
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Add epic reference for nested items
|
|
325
|
+
if (item._type !== 'epic' && item._parent) {
|
|
326
|
+
let epic = item._parent;
|
|
327
|
+
while (epic._parent) {
|
|
328
|
+
epic = epic._parent;
|
|
329
|
+
}
|
|
330
|
+
if (epic._type === 'epic') {
|
|
331
|
+
cleaned.epicId = epic.id;
|
|
332
|
+
cleaned.epicName = epic.name;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Include full details if requested
|
|
337
|
+
if (includeFullDetails) {
|
|
338
|
+
if (item.documentation) {
|
|
339
|
+
cleaned.documentation = item.documentation;
|
|
340
|
+
}
|
|
341
|
+
if (item.context) {
|
|
342
|
+
cleaned.context = item.context;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return cleaned;
|
|
347
|
+
}
|