mcp-adr-analysis-server 2.0.9 → 2.0.11
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/README.md +1 -1
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +573 -348
- package/dist/src/index.js.map +1 -1
- package/dist/src/prompts/adr-suggestion-prompts.d.ts.map +1 -1
- package/dist/src/prompts/adr-suggestion-prompts.js +2 -0
- package/dist/src/prompts/adr-suggestion-prompts.js.map +1 -1
- package/dist/src/resources/index.d.ts.map +1 -1
- package/dist/src/resources/index.js +71 -1
- package/dist/src/resources/index.js.map +1 -1
- package/dist/src/tools/adr-suggestion-tool.d.ts +16 -0
- package/dist/src/tools/adr-suggestion-tool.d.ts.map +1 -1
- package/dist/src/tools/adr-suggestion-tool.js +55 -2
- package/dist/src/tools/adr-suggestion-tool.js.map +1 -1
- package/dist/src/tools/smart-git-push-tool.d.ts +21 -1
- package/dist/src/tools/smart-git-push-tool.d.ts.map +1 -1
- package/dist/src/tools/smart-git-push-tool.js +181 -28
- package/dist/src/tools/smart-git-push-tool.js.map +1 -1
- package/dist/src/tools/smart-score-tool.d.ts +173 -0
- package/dist/src/tools/smart-score-tool.d.ts.map +1 -0
- package/dist/src/tools/smart-score-tool.js +681 -0
- package/dist/src/tools/smart-score-tool.js.map +1 -0
- package/dist/src/tools/todo-management-tool-v2.d.ts +329 -0
- package/dist/src/tools/todo-management-tool-v2.d.ts.map +1 -0
- package/dist/src/tools/todo-management-tool-v2.js +644 -0
- package/dist/src/tools/todo-management-tool-v2.js.map +1 -0
- package/dist/src/tools/tool-chain-orchestrator.d.ts +126 -0
- package/dist/src/tools/tool-chain-orchestrator.d.ts.map +1 -0
- package/dist/src/tools/tool-chain-orchestrator.js +550 -0
- package/dist/src/tools/tool-chain-orchestrator.js.map +1 -0
- package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts +150 -0
- package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts.map +1 -0
- package/dist/src/tools/troubleshoot-guided-workflow-tool.js +520 -0
- package/dist/src/tools/troubleshoot-guided-workflow-tool.js.map +1 -0
- package/dist/src/types/conversation-context.d.ts +6 -0
- package/dist/src/types/conversation-context.d.ts.map +1 -1
- package/dist/src/types/conversation-context.js +9 -1
- package/dist/src/types/conversation-context.js.map +1 -1
- package/dist/src/types/knowledge-graph-schemas.d.ts +773 -0
- package/dist/src/types/knowledge-graph-schemas.d.ts.map +1 -0
- package/dist/src/types/knowledge-graph-schemas.js +87 -0
- package/dist/src/types/knowledge-graph-schemas.js.map +1 -0
- package/dist/src/types/todo-json-schemas.d.ts +663 -0
- package/dist/src/types/todo-json-schemas.d.ts.map +1 -0
- package/dist/src/types/todo-json-schemas.js +113 -0
- package/dist/src/types/todo-json-schemas.js.map +1 -0
- package/dist/src/utils/chain-of-thought-template.d.ts.map +1 -1
- package/dist/src/utils/chain-of-thought-template.js.map +1 -1
- package/dist/src/utils/json-safe.d.ts +38 -0
- package/dist/src/utils/json-safe.d.ts.map +1 -0
- package/dist/src/utils/json-safe.js +86 -0
- package/dist/src/utils/json-safe.js.map +1 -0
- package/dist/src/utils/knowledge-graph-manager.d.ts +65 -0
- package/dist/src/utils/knowledge-graph-manager.d.ts.map +1 -0
- package/dist/src/utils/knowledge-graph-manager.js +358 -0
- package/dist/src/utils/knowledge-graph-manager.js.map +1 -0
- package/dist/src/utils/mcp-response-validator.d.ts +30 -0
- package/dist/src/utils/mcp-response-validator.d.ts.map +1 -0
- package/dist/src/utils/mcp-response-validator.js +197 -0
- package/dist/src/utils/mcp-response-validator.js.map +1 -0
- package/dist/src/utils/project-health-scoring.d.ts +177 -0
- package/dist/src/utils/project-health-scoring.d.ts.map +1 -0
- package/dist/src/utils/project-health-scoring.js +370 -0
- package/dist/src/utils/project-health-scoring.js.map +1 -0
- package/dist/src/utils/release-readiness-detector.d.ts +2 -0
- package/dist/src/utils/release-readiness-detector.d.ts.map +1 -1
- package/dist/src/utils/release-readiness-detector.js +2 -0
- package/dist/src/utils/release-readiness-detector.js.map +1 -1
- package/dist/src/utils/todo-file-watcher.d.ts +26 -0
- package/dist/src/utils/todo-file-watcher.d.ts.map +1 -0
- package/dist/src/utils/todo-file-watcher.js +163 -0
- package/dist/src/utils/todo-file-watcher.js.map +1 -0
- package/dist/src/utils/todo-json-manager.d.ts +71 -0
- package/dist/src/utils/todo-json-manager.d.ts.map +1 -0
- package/dist/src/utils/todo-json-manager.js +394 -0
- package/dist/src/utils/todo-json-manager.js.map +1 -0
- package/dist/src/utils/todo-markdown-converter.d.ts +16 -0
- package/dist/src/utils/todo-markdown-converter.d.ts.map +1 -0
- package/dist/src/utils/todo-markdown-converter.js +362 -0
- package/dist/src/utils/todo-markdown-converter.js.map +1 -0
- package/dist/src/utils/todo-migration.d.ts +47 -0
- package/dist/src/utils/todo-migration.d.ts.map +1 -0
- package/dist/src/utils/todo-migration.js +261 -0
- package/dist/src/utils/todo-migration.js.map +1 -0
- package/package.json +1 -1
- package/dist/src/tools/todo-management-tool.d.ts +0 -166
- package/dist/src/tools/todo-management-tool.d.ts.map +0 -1
- package/dist/src/tools/todo-management-tool.js +0 -472
- package/dist/src/tools/todo-management-tool.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare class TodoFileWatcher {
|
|
2
|
+
private kgManager;
|
|
3
|
+
private todoPath;
|
|
4
|
+
private watcherActive;
|
|
5
|
+
private lastKnownHash;
|
|
6
|
+
private pollInterval;
|
|
7
|
+
constructor(todoPath?: string);
|
|
8
|
+
startWatching(intervalMs?: number): Promise<void>;
|
|
9
|
+
stopWatching(): Promise<void>;
|
|
10
|
+
private checkForChanges;
|
|
11
|
+
private parseChanges;
|
|
12
|
+
private notifyActiveIntents;
|
|
13
|
+
manualSync(): Promise<{
|
|
14
|
+
changesDetected: boolean;
|
|
15
|
+
syncStatus: string;
|
|
16
|
+
activeIntentsNotified: number;
|
|
17
|
+
}>;
|
|
18
|
+
getWatcherStatus(): Promise<{
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
todoPath: string;
|
|
21
|
+
lastKnownHash: string;
|
|
22
|
+
lastSyncTime: string;
|
|
23
|
+
syncStatus: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=todo-file-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-file-watcher.d.ts","sourceRoot":"","sources":["../../../src/utils/todo-file-watcher.ts"],"names":[],"mappings":"AAKA,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,YAAY,CAA+B;gBAEvC,QAAQ,CAAC,EAAE,MAAM;IAMvB,aAAa,CAAC,UAAU,GAAE,MAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBvD,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAerB,eAAe;YAsCf,YAAY;YA2CZ,mBAAmB;IAoC3B,UAAU,IAAI,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;QACnB,qBAAqB,EAAE,MAAM,CAAC;KAC/B,CAAC;IA4CI,gBAAgB,IAAI,OAAO,CAAC;QAChC,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CAaH"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { KnowledgeGraphManager } from './knowledge-graph-manager.js';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
export class TodoFileWatcher {
|
|
6
|
+
kgManager;
|
|
7
|
+
todoPath;
|
|
8
|
+
watcherActive = false;
|
|
9
|
+
lastKnownHash = '';
|
|
10
|
+
pollInterval = null;
|
|
11
|
+
constructor(todoPath) {
|
|
12
|
+
this.kgManager = new KnowledgeGraphManager();
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
this.todoPath = todoPath || path.join(config.projectPath, 'TODO.md');
|
|
15
|
+
}
|
|
16
|
+
async startWatching(intervalMs = 2000) {
|
|
17
|
+
if (this.watcherActive) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.watcherActive = true;
|
|
21
|
+
// Initialize with current hash
|
|
22
|
+
this.lastKnownHash = await this.kgManager.calculateTodoMdHash(this.todoPath);
|
|
23
|
+
// Start polling for changes
|
|
24
|
+
this.pollInterval = setInterval(async () => {
|
|
25
|
+
try {
|
|
26
|
+
await this.checkForChanges();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Error checking TODO.md changes:', error);
|
|
30
|
+
}
|
|
31
|
+
}, intervalMs);
|
|
32
|
+
console.error(`[TodoFileWatcher] Started watching ${this.todoPath}`);
|
|
33
|
+
}
|
|
34
|
+
async stopWatching() {
|
|
35
|
+
if (!this.watcherActive) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.watcherActive = false;
|
|
39
|
+
if (this.pollInterval) {
|
|
40
|
+
clearInterval(this.pollInterval);
|
|
41
|
+
this.pollInterval = null;
|
|
42
|
+
}
|
|
43
|
+
console.error(`[TodoFileWatcher] Stopped watching ${this.todoPath}`);
|
|
44
|
+
}
|
|
45
|
+
async checkForChanges() {
|
|
46
|
+
if (!this.watcherActive) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const detection = await this.kgManager.detectTodoChanges(this.todoPath);
|
|
50
|
+
if (detection.hasChanges) {
|
|
51
|
+
console.error(`[TodoFileWatcher] TODO.md changes detected`);
|
|
52
|
+
// Read the new content
|
|
53
|
+
let todoContent = '';
|
|
54
|
+
try {
|
|
55
|
+
todoContent = await fs.readFile(this.todoPath, 'utf-8');
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error(`[TodoFileWatcher] Error reading TODO.md:`, error);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Parse changes and extract task modifications
|
|
62
|
+
const changes = await this.parseChanges(this.lastKnownHash, detection.currentHash, todoContent);
|
|
63
|
+
// Update sync state
|
|
64
|
+
await this.kgManager.updateSyncState({
|
|
65
|
+
lastSyncTimestamp: new Date().toISOString(),
|
|
66
|
+
todoMdHash: detection.currentHash,
|
|
67
|
+
syncStatus: changes.length > 0 ? 'pending' : 'synced',
|
|
68
|
+
lastModifiedBy: 'human',
|
|
69
|
+
version: (await this.kgManager.getSyncState()).version + 1
|
|
70
|
+
});
|
|
71
|
+
// Notify active intents about TODO changes
|
|
72
|
+
await this.notifyActiveIntents(todoContent, changes);
|
|
73
|
+
this.lastKnownHash = detection.currentHash;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async parseChanges(oldHash, newHash, todoContent) {
|
|
77
|
+
const changes = [];
|
|
78
|
+
// Simple change detection by analyzing the TODO content
|
|
79
|
+
// In a more sophisticated implementation, this would diff the actual content
|
|
80
|
+
const lines = todoContent.split('\n');
|
|
81
|
+
const taskLines = lines.filter(line => line.trim().match(/^-\s*\[[\sx]\]/) ||
|
|
82
|
+
line.trim().match(/^\d+\.\s*\[[\sx]\]/) ||
|
|
83
|
+
line.trim().match(/^##\s+/) // Section headers
|
|
84
|
+
);
|
|
85
|
+
// For now, we'll create a generic change record
|
|
86
|
+
if (oldHash !== newHash && taskLines.length > 0) {
|
|
87
|
+
changes.push({
|
|
88
|
+
type: 'modified',
|
|
89
|
+
taskId: `todo-change-${Date.now()}`,
|
|
90
|
+
description: 'TODO.md content modified externally',
|
|
91
|
+
details: {
|
|
92
|
+
taskCount: taskLines.length,
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
contentLength: todoContent.length
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return changes;
|
|
99
|
+
}
|
|
100
|
+
async notifyActiveIntents(todoContent, changes) {
|
|
101
|
+
const activeIntents = await this.kgManager.getActiveIntents();
|
|
102
|
+
for (const intent of activeIntents) {
|
|
103
|
+
// Update TODO snapshot for each active intent
|
|
104
|
+
await this.kgManager.updateTodoSnapshot(intent.intentId, todoContent);
|
|
105
|
+
// Add a tool execution record for the TODO change
|
|
106
|
+
const changeDetails = changes.map(c => `${c.type}: ${c.description}`).join('; ');
|
|
107
|
+
await this.kgManager.addToolExecution(intent.intentId, 'todo_file_watcher_change_detected', { todoPath: this.todoPath }, {
|
|
108
|
+
changes: changes.length,
|
|
109
|
+
changeDetails,
|
|
110
|
+
todoContentLength: todoContent.length,
|
|
111
|
+
detectedAt: new Date().toISOString()
|
|
112
|
+
}, true, [], changes.map(c => c.taskId), undefined);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async manualSync() {
|
|
116
|
+
const detection = await this.kgManager.detectTodoChanges(this.todoPath);
|
|
117
|
+
if (!detection.hasChanges) {
|
|
118
|
+
return {
|
|
119
|
+
changesDetected: false,
|
|
120
|
+
syncStatus: 'no_changes',
|
|
121
|
+
activeIntentsNotified: 0
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
let todoContent = '';
|
|
125
|
+
try {
|
|
126
|
+
todoContent = await fs.readFile(this.todoPath, 'utf-8');
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return {
|
|
130
|
+
changesDetected: true,
|
|
131
|
+
syncStatus: 'error_reading_file',
|
|
132
|
+
activeIntentsNotified: 0
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const changes = await this.parseChanges(this.lastKnownHash, detection.currentHash, todoContent);
|
|
136
|
+
await this.notifyActiveIntents(todoContent, changes);
|
|
137
|
+
await this.kgManager.updateSyncState({
|
|
138
|
+
lastSyncTimestamp: new Date().toISOString(),
|
|
139
|
+
todoMdHash: detection.currentHash,
|
|
140
|
+
syncStatus: 'synced',
|
|
141
|
+
lastModifiedBy: 'sync',
|
|
142
|
+
version: (await this.kgManager.getSyncState()).version + 1
|
|
143
|
+
});
|
|
144
|
+
this.lastKnownHash = detection.currentHash;
|
|
145
|
+
const activeIntents = await this.kgManager.getActiveIntents();
|
|
146
|
+
return {
|
|
147
|
+
changesDetected: true,
|
|
148
|
+
syncStatus: 'synced',
|
|
149
|
+
activeIntentsNotified: activeIntents.length
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
async getWatcherStatus() {
|
|
153
|
+
const syncState = await this.kgManager.getSyncState();
|
|
154
|
+
return {
|
|
155
|
+
isActive: this.watcherActive,
|
|
156
|
+
todoPath: this.todoPath,
|
|
157
|
+
lastKnownHash: this.lastKnownHash,
|
|
158
|
+
lastSyncTime: syncState.lastSyncTimestamp,
|
|
159
|
+
syncStatus: syncState.syncStatus
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=todo-file-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-file-watcher.js","sourceRoot":"","sources":["../../../src/utils/todo-file-watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-First TODO Management System
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent, structured TODO management with automatic scoring sync,
|
|
5
|
+
* knowledge graph integration, and intelligent task automation.
|
|
6
|
+
*/
|
|
7
|
+
import { TodoJsonData, TodoTask, TaskUpdateOperation, TodoScoreMetrics } from '../types/todo-json-schemas.js';
|
|
8
|
+
export declare class TodoJsonManager {
|
|
9
|
+
private todoJsonPath;
|
|
10
|
+
private todoMdPath;
|
|
11
|
+
private cacheDir;
|
|
12
|
+
private kgManager;
|
|
13
|
+
private healthScoring;
|
|
14
|
+
constructor(projectPath?: string);
|
|
15
|
+
/**
|
|
16
|
+
* Load TODO data from JSON, creating default structure if needed
|
|
17
|
+
*/
|
|
18
|
+
loadTodoData(): Promise<TodoJsonData>;
|
|
19
|
+
/**
|
|
20
|
+
* Save TODO data to JSON and optionally sync to markdown
|
|
21
|
+
*/
|
|
22
|
+
saveTodoData(data: TodoJsonData, syncToMarkdown?: boolean): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Create a new task with automatic ID generation and scoring integration
|
|
25
|
+
*/
|
|
26
|
+
createTask(taskData: Partial<TodoTask> & {
|
|
27
|
+
title: string;
|
|
28
|
+
}): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Update task with automatic changelog and scoring sync
|
|
31
|
+
*/
|
|
32
|
+
updateTask(operation: TaskUpdateOperation): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Move task between sections automatically
|
|
35
|
+
*/
|
|
36
|
+
private moveTaskBetweenSections;
|
|
37
|
+
/**
|
|
38
|
+
* Process auto-completion rules
|
|
39
|
+
*/
|
|
40
|
+
private processAutoCompletionRules;
|
|
41
|
+
/**
|
|
42
|
+
* Update scoring system with current task data
|
|
43
|
+
*/
|
|
44
|
+
private updateScoring;
|
|
45
|
+
/**
|
|
46
|
+
* Calculate comprehensive score metrics
|
|
47
|
+
*/
|
|
48
|
+
private calculateScoreMetrics;
|
|
49
|
+
/**
|
|
50
|
+
* Link task to knowledge graph
|
|
51
|
+
*/
|
|
52
|
+
private linkToKnowledgeGraph;
|
|
53
|
+
/**
|
|
54
|
+
* Convert JSON data to markdown format
|
|
55
|
+
*/
|
|
56
|
+
convertToMarkdown(data?: TodoJsonData): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Import existing TODO.md into JSON format
|
|
59
|
+
*/
|
|
60
|
+
importFromMarkdown(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Get analytics and metrics
|
|
63
|
+
*/
|
|
64
|
+
getAnalytics(): Promise<{
|
|
65
|
+
metrics: TodoScoreMetrics;
|
|
66
|
+
trends: any[];
|
|
67
|
+
recommendations: string[];
|
|
68
|
+
}>;
|
|
69
|
+
private ensureCacheDirectory;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=todo-json-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo-json-manager.d.ts","sourceRoot":"","sources":["../../../src/utils/todo-json-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EACL,YAAY,EACZ,QAAQ,EAER,mBAAmB,EACnB,gBAAgB,EAEjB,MAAM,+BAA+B,CAAC;AAKvC,qBAAa,eAAe;IAC1B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,aAAa,CAAuB;gBAEhC,WAAW,CAAC,EAAE,MAAM;IAYhC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IA6D3C;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,cAAc,GAAE,OAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBrF;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAiElF;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+C/D;;OAEG;YACW,uBAAuB;IAkBrC;;OAEG;YACW,0BAA0B;IAsBxC;;OAEG;YACW,aAAa;IA4B3B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA6D7B;;OAEG;YACW,oBAAoB;IAkBlC;;OAEG;IACG,iBAAiB,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3D;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAazC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC;QAC5B,OAAO,EAAE,gBAAgB,CAAC;QAC1B,MAAM,EAAE,GAAG,EAAE,CAAC;QACd,eAAe,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC;YAsBY,oBAAoB;CAOnC"}
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-First TODO Management System
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent, structured TODO management with automatic scoring sync,
|
|
5
|
+
* knowledge graph integration, and intelligent task automation.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import crypto from 'crypto';
|
|
10
|
+
import { TodoJsonDataSchema } from '../types/todo-json-schemas.js';
|
|
11
|
+
import { loadConfig } from './config.js';
|
|
12
|
+
import { KnowledgeGraphManager } from './knowledge-graph-manager.js';
|
|
13
|
+
import { ProjectHealthScoring } from './project-health-scoring.js';
|
|
14
|
+
export class TodoJsonManager {
|
|
15
|
+
todoJsonPath;
|
|
16
|
+
todoMdPath;
|
|
17
|
+
cacheDir;
|
|
18
|
+
kgManager;
|
|
19
|
+
healthScoring;
|
|
20
|
+
constructor(projectPath) {
|
|
21
|
+
const config = loadConfig();
|
|
22
|
+
const basePath = projectPath || config.projectPath;
|
|
23
|
+
this.cacheDir = path.join(basePath, '.mcp-adr-cache');
|
|
24
|
+
this.todoJsonPath = path.join(this.cacheDir, 'todo-data.json');
|
|
25
|
+
this.todoMdPath = path.join(basePath, 'TODO.md');
|
|
26
|
+
this.kgManager = new KnowledgeGraphManager();
|
|
27
|
+
this.healthScoring = new ProjectHealthScoring(basePath);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Load TODO data from JSON, creating default structure if needed
|
|
31
|
+
*/
|
|
32
|
+
async loadTodoData() {
|
|
33
|
+
await this.ensureCacheDirectory();
|
|
34
|
+
try {
|
|
35
|
+
const data = await fs.readFile(this.todoJsonPath, 'utf-8');
|
|
36
|
+
const parsed = JSON.parse(data);
|
|
37
|
+
return TodoJsonDataSchema.parse(parsed);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// Create default structure
|
|
41
|
+
const defaultData = {
|
|
42
|
+
version: '1.0.0',
|
|
43
|
+
metadata: {
|
|
44
|
+
lastUpdated: new Date().toISOString(),
|
|
45
|
+
totalTasks: 0,
|
|
46
|
+
completedTasks: 0,
|
|
47
|
+
autoSyncEnabled: true
|
|
48
|
+
},
|
|
49
|
+
tasks: {},
|
|
50
|
+
sections: [
|
|
51
|
+
{
|
|
52
|
+
id: 'pending',
|
|
53
|
+
title: 'Pending Tasks',
|
|
54
|
+
order: 1,
|
|
55
|
+
collapsed: false,
|
|
56
|
+
tasks: []
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'in_progress',
|
|
60
|
+
title: 'In Progress',
|
|
61
|
+
order: 2,
|
|
62
|
+
collapsed: false,
|
|
63
|
+
tasks: []
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'completed',
|
|
67
|
+
title: 'Completed',
|
|
68
|
+
order: 3,
|
|
69
|
+
collapsed: false,
|
|
70
|
+
tasks: []
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
scoringSync: {
|
|
74
|
+
lastScoreUpdate: new Date().toISOString(),
|
|
75
|
+
taskCompletionScore: 0,
|
|
76
|
+
priorityWeightedScore: 0,
|
|
77
|
+
criticalTasksRemaining: 0,
|
|
78
|
+
scoreHistory: []
|
|
79
|
+
},
|
|
80
|
+
knowledgeGraphSync: {
|
|
81
|
+
lastSync: new Date().toISOString(),
|
|
82
|
+
linkedIntents: [],
|
|
83
|
+
pendingUpdates: []
|
|
84
|
+
},
|
|
85
|
+
automationRules: []
|
|
86
|
+
};
|
|
87
|
+
await this.saveTodoData(defaultData);
|
|
88
|
+
return defaultData;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Save TODO data to JSON and optionally sync to markdown
|
|
93
|
+
*/
|
|
94
|
+
async saveTodoData(data, syncToMarkdown = true) {
|
|
95
|
+
await this.ensureCacheDirectory();
|
|
96
|
+
// Update metadata
|
|
97
|
+
data.metadata.lastUpdated = new Date().toISOString();
|
|
98
|
+
data.metadata.totalTasks = Object.keys(data.tasks).length;
|
|
99
|
+
data.metadata.completedTasks = Object.values(data.tasks).filter(t => t.status === 'completed').length;
|
|
100
|
+
// Save JSON
|
|
101
|
+
await fs.writeFile(this.todoJsonPath, JSON.stringify(data, null, 2));
|
|
102
|
+
// Auto-sync to markdown if enabled
|
|
103
|
+
if (syncToMarkdown && data.metadata.autoSyncEnabled) {
|
|
104
|
+
await this.convertToMarkdown(data);
|
|
105
|
+
data.metadata.lastSyncToMarkdown = new Date().toISOString();
|
|
106
|
+
await fs.writeFile(this.todoJsonPath, JSON.stringify(data, null, 2));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a new task with automatic ID generation and scoring integration
|
|
111
|
+
*/
|
|
112
|
+
async createTask(taskData) {
|
|
113
|
+
const data = await this.loadTodoData();
|
|
114
|
+
const taskId = crypto.randomUUID();
|
|
115
|
+
const now = new Date().toISOString();
|
|
116
|
+
const task = {
|
|
117
|
+
id: taskId,
|
|
118
|
+
title: taskData.title,
|
|
119
|
+
description: taskData.description || '',
|
|
120
|
+
status: taskData.status || 'pending',
|
|
121
|
+
priority: taskData.priority || 'medium',
|
|
122
|
+
category: taskData.category,
|
|
123
|
+
assignee: taskData.assignee,
|
|
124
|
+
createdAt: now,
|
|
125
|
+
updatedAt: now,
|
|
126
|
+
completedAt: undefined,
|
|
127
|
+
dueDate: taskData.dueDate,
|
|
128
|
+
parentTaskId: taskData.parentTaskId,
|
|
129
|
+
subtasks: taskData.subtasks || [],
|
|
130
|
+
dependencies: taskData.dependencies || [],
|
|
131
|
+
blockedBy: taskData.blockedBy || [],
|
|
132
|
+
linkedAdrs: taskData.linkedAdrs || [],
|
|
133
|
+
adrGeneratedTask: taskData.adrGeneratedTask || false,
|
|
134
|
+
intentId: taskData.intentId,
|
|
135
|
+
toolExecutions: taskData.toolExecutions || [],
|
|
136
|
+
scoreWeight: taskData.scoreWeight || 1,
|
|
137
|
+
scoreCategory: taskData.scoreCategory || 'task_completion',
|
|
138
|
+
estimatedHours: taskData.estimatedHours,
|
|
139
|
+
actualHours: taskData.actualHours,
|
|
140
|
+
progressPercentage: taskData.progressPercentage || 0,
|
|
141
|
+
tags: taskData.tags || [],
|
|
142
|
+
notes: taskData.notes,
|
|
143
|
+
lastModifiedBy: taskData.lastModifiedBy || 'tool',
|
|
144
|
+
autoComplete: taskData.autoComplete || false,
|
|
145
|
+
completionCriteria: taskData.completionCriteria,
|
|
146
|
+
version: 1,
|
|
147
|
+
changeLog: [{
|
|
148
|
+
timestamp: now,
|
|
149
|
+
action: 'created',
|
|
150
|
+
details: `Task created: ${taskData.title}`,
|
|
151
|
+
modifiedBy: taskData.lastModifiedBy || 'tool'
|
|
152
|
+
}]
|
|
153
|
+
};
|
|
154
|
+
// Add to tasks
|
|
155
|
+
data.tasks[taskId] = task;
|
|
156
|
+
// Add to appropriate section
|
|
157
|
+
const targetSection = data.sections.find(s => s.id === task.status) || data.sections[0];
|
|
158
|
+
if (targetSection) {
|
|
159
|
+
targetSection.tasks.push(taskId);
|
|
160
|
+
}
|
|
161
|
+
// Update knowledge graph if intentId provided
|
|
162
|
+
if (task.intentId) {
|
|
163
|
+
await this.linkToKnowledgeGraph(taskId, task.intentId, 'generated_from');
|
|
164
|
+
}
|
|
165
|
+
await this.saveTodoData(data);
|
|
166
|
+
await this.updateScoring(data);
|
|
167
|
+
return taskId;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Update task with automatic changelog and scoring sync
|
|
171
|
+
*/
|
|
172
|
+
async updateTask(operation) {
|
|
173
|
+
const data = await this.loadTodoData();
|
|
174
|
+
const task = data.tasks[operation.taskId];
|
|
175
|
+
if (!task) {
|
|
176
|
+
throw new Error(`Task ${operation.taskId} not found`);
|
|
177
|
+
}
|
|
178
|
+
const now = new Date().toISOString();
|
|
179
|
+
const oldStatus = task.status;
|
|
180
|
+
// Apply updates
|
|
181
|
+
Object.assign(task, operation.updates);
|
|
182
|
+
task.updatedAt = now;
|
|
183
|
+
task.version += 1;
|
|
184
|
+
// Add changelog entry
|
|
185
|
+
task.changeLog.push({
|
|
186
|
+
timestamp: now,
|
|
187
|
+
action: 'updated',
|
|
188
|
+
details: operation.reason,
|
|
189
|
+
modifiedBy: operation.triggeredBy
|
|
190
|
+
});
|
|
191
|
+
// Handle status changes
|
|
192
|
+
if (operation.updates.status && operation.updates.status !== oldStatus) {
|
|
193
|
+
await this.moveTaskBetweenSections(data, operation.taskId, oldStatus, operation.updates.status);
|
|
194
|
+
// Handle completion
|
|
195
|
+
if (operation.updates.status === 'completed') {
|
|
196
|
+
task.completedAt = now;
|
|
197
|
+
task.progressPercentage = 100;
|
|
198
|
+
// Update knowledge graph
|
|
199
|
+
if (task.intentId) {
|
|
200
|
+
await this.kgManager.updateTodoSnapshot(task.intentId, `Task completed: ${task.title}`);
|
|
201
|
+
}
|
|
202
|
+
// Check for auto-completion rules
|
|
203
|
+
await this.processAutoCompletionRules(data, operation.taskId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
await this.saveTodoData(data);
|
|
207
|
+
await this.updateScoring(data);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Move task between sections automatically
|
|
211
|
+
*/
|
|
212
|
+
async moveTaskBetweenSections(data, taskId, fromStatus, toStatus) {
|
|
213
|
+
const fromSection = data.sections.find(s => s.id === fromStatus);
|
|
214
|
+
const toSection = data.sections.find(s => s.id === toStatus);
|
|
215
|
+
if (fromSection) {
|
|
216
|
+
fromSection.tasks = fromSection.tasks.filter(id => id !== taskId);
|
|
217
|
+
}
|
|
218
|
+
if (toSection) {
|
|
219
|
+
toSection.tasks.push(taskId);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Process auto-completion rules
|
|
224
|
+
*/
|
|
225
|
+
async processAutoCompletionRules(data, completedTaskId) {
|
|
226
|
+
// Check for dependent tasks that can now be auto-completed
|
|
227
|
+
for (const [taskId, task] of Object.entries(data.tasks)) {
|
|
228
|
+
if (task.autoComplete && task.dependencies.includes(completedTaskId)) {
|
|
229
|
+
const allDependenciesCompleted = task.dependencies.every(depId => {
|
|
230
|
+
const depTask = data.tasks[depId];
|
|
231
|
+
return depTask && depTask.status === 'completed';
|
|
232
|
+
});
|
|
233
|
+
if (allDependenciesCompleted) {
|
|
234
|
+
await this.updateTask({
|
|
235
|
+
taskId,
|
|
236
|
+
updates: { status: 'completed' },
|
|
237
|
+
reason: `Auto-completed: all dependencies satisfied`,
|
|
238
|
+
triggeredBy: 'automation'
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Update scoring system with current task data
|
|
246
|
+
*/
|
|
247
|
+
async updateScoring(data) {
|
|
248
|
+
const metrics = this.calculateScoreMetrics(data);
|
|
249
|
+
// Update scoring sync
|
|
250
|
+
data.scoringSync = {
|
|
251
|
+
lastScoreUpdate: new Date().toISOString(),
|
|
252
|
+
taskCompletionScore: metrics.completionPercentage,
|
|
253
|
+
priorityWeightedScore: metrics.priorityWeightedScore,
|
|
254
|
+
criticalTasksRemaining: metrics.criticalTasksRemaining,
|
|
255
|
+
scoreHistory: [
|
|
256
|
+
...data.scoringSync.scoreHistory,
|
|
257
|
+
{
|
|
258
|
+
timestamp: new Date().toISOString(),
|
|
259
|
+
score: metrics.completionPercentage,
|
|
260
|
+
trigger: 'task_update'
|
|
261
|
+
}
|
|
262
|
+
].slice(-50) // Keep last 50 entries
|
|
263
|
+
};
|
|
264
|
+
// Update project health scoring
|
|
265
|
+
await this.healthScoring.updateTaskCompletionScore({
|
|
266
|
+
completed: metrics.completedTasks,
|
|
267
|
+
total: metrics.totalTasks,
|
|
268
|
+
criticalTasksRemaining: metrics.criticalTasksRemaining,
|
|
269
|
+
priorityWeightedScore: metrics.priorityWeightedScore
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Calculate comprehensive score metrics
|
|
274
|
+
*/
|
|
275
|
+
calculateScoreMetrics(data) {
|
|
276
|
+
const tasks = Object.values(data.tasks);
|
|
277
|
+
const totalTasks = tasks.length;
|
|
278
|
+
const completedTasks = tasks.filter(t => t.status === 'completed').length;
|
|
279
|
+
const completionPercentage = totalTasks > 0 ? (completedTasks / totalTasks) * 100 : 100;
|
|
280
|
+
// Priority-weighted scoring
|
|
281
|
+
const priorityWeights = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
282
|
+
const totalWeight = tasks.reduce((sum, t) => sum + priorityWeights[t.priority], 0);
|
|
283
|
+
const completedWeight = tasks
|
|
284
|
+
.filter(t => t.status === 'completed')
|
|
285
|
+
.reduce((sum, t) => sum + priorityWeights[t.priority], 0);
|
|
286
|
+
const priorityWeightedScore = totalWeight > 0 ? (completedWeight / totalWeight) * 100 : 100;
|
|
287
|
+
// Critical tasks remaining
|
|
288
|
+
const criticalTasksRemaining = tasks.filter(t => t.priority === 'critical' && t.status !== 'completed').length;
|
|
289
|
+
// Other metrics
|
|
290
|
+
const blockedTasksCount = tasks.filter(t => t.status === 'blocked').length;
|
|
291
|
+
const now = new Date();
|
|
292
|
+
const averageTaskAge = tasks.reduce((sum, t) => {
|
|
293
|
+
const age = (now.getTime() - new Date(t.createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
294
|
+
return sum + age;
|
|
295
|
+
}, 0) / totalTasks;
|
|
296
|
+
// Velocity metrics (last 7 days)
|
|
297
|
+
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
298
|
+
const tasksCompletedLastWeek = tasks.filter(t => t.status === 'completed' &&
|
|
299
|
+
t.completedAt &&
|
|
300
|
+
new Date(t.completedAt) > weekAgo).length;
|
|
301
|
+
const completedTasksWithDuration = tasks.filter(t => t.status === 'completed' &&
|
|
302
|
+
t.completedAt);
|
|
303
|
+
const averageCompletionTime = completedTasksWithDuration.length > 0
|
|
304
|
+
? completedTasksWithDuration.reduce((sum, t) => {
|
|
305
|
+
const duration = (new Date(t.completedAt).getTime() - new Date(t.createdAt).getTime()) / (1000 * 60 * 60);
|
|
306
|
+
return sum + duration;
|
|
307
|
+
}, 0) / completedTasksWithDuration.length
|
|
308
|
+
: 0;
|
|
309
|
+
return {
|
|
310
|
+
totalTasks,
|
|
311
|
+
completedTasks,
|
|
312
|
+
completionPercentage,
|
|
313
|
+
priorityWeightedScore,
|
|
314
|
+
criticalTasksRemaining,
|
|
315
|
+
blockedTasksCount,
|
|
316
|
+
averageTaskAge,
|
|
317
|
+
velocityMetrics: {
|
|
318
|
+
tasksCompletedLastWeek,
|
|
319
|
+
averageCompletionTime
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Link task to knowledge graph
|
|
325
|
+
*/
|
|
326
|
+
async linkToKnowledgeGraph(taskId, intentId, _linkType) {
|
|
327
|
+
const data = await this.loadTodoData();
|
|
328
|
+
// Update knowledge graph sync
|
|
329
|
+
data.knowledgeGraphSync.linkedIntents.push(intentId);
|
|
330
|
+
data.knowledgeGraphSync.pendingUpdates.push({
|
|
331
|
+
taskId,
|
|
332
|
+
updateType: 'status',
|
|
333
|
+
timestamp: new Date().toISOString()
|
|
334
|
+
});
|
|
335
|
+
await this.saveTodoData(data, false); // Don't sync to markdown yet
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Convert JSON data to markdown format
|
|
339
|
+
*/
|
|
340
|
+
async convertToMarkdown(data) {
|
|
341
|
+
if (!data) {
|
|
342
|
+
data = await this.loadTodoData();
|
|
343
|
+
}
|
|
344
|
+
const { generateTodoMarkdown } = await import('./todo-markdown-converter.js');
|
|
345
|
+
const markdown = await generateTodoMarkdown(data);
|
|
346
|
+
await fs.writeFile(this.todoMdPath, markdown);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Import existing TODO.md into JSON format
|
|
350
|
+
*/
|
|
351
|
+
async importFromMarkdown() {
|
|
352
|
+
try {
|
|
353
|
+
const markdownContent = await fs.readFile(this.todoMdPath, 'utf-8');
|
|
354
|
+
const { parseMarkdownToJson } = await import('./todo-markdown-converter.js');
|
|
355
|
+
const jsonData = await parseMarkdownToJson(markdownContent);
|
|
356
|
+
await this.saveTodoData(jsonData, false);
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
359
|
+
// If TODO.md doesn't exist, create fresh JSON
|
|
360
|
+
await this.loadTodoData();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get analytics and metrics
|
|
365
|
+
*/
|
|
366
|
+
async getAnalytics() {
|
|
367
|
+
const data = await this.loadTodoData();
|
|
368
|
+
const metrics = this.calculateScoreMetrics(data);
|
|
369
|
+
const recommendations = [];
|
|
370
|
+
if (metrics.criticalTasksRemaining > 0) {
|
|
371
|
+
recommendations.push(`Address ${metrics.criticalTasksRemaining} critical tasks`);
|
|
372
|
+
}
|
|
373
|
+
if (metrics.blockedTasksCount > 0) {
|
|
374
|
+
recommendations.push(`Resolve ${metrics.blockedTasksCount} blocked tasks`);
|
|
375
|
+
}
|
|
376
|
+
if (metrics.averageTaskAge > 30) {
|
|
377
|
+
recommendations.push('Consider breaking down old tasks or removing stale ones');
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
metrics,
|
|
381
|
+
trends: data.scoringSync.scoreHistory,
|
|
382
|
+
recommendations
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
async ensureCacheDirectory() {
|
|
386
|
+
try {
|
|
387
|
+
await fs.access(this.cacheDir);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
await fs.mkdir(this.cacheDir, { recursive: true });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=todo-json-manager.js.map
|