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.
Files changed (90) hide show
  1. package/README.md +1 -1
  2. package/dist/src/index.d.ts +8 -1
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +573 -348
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/prompts/adr-suggestion-prompts.d.ts.map +1 -1
  7. package/dist/src/prompts/adr-suggestion-prompts.js +2 -0
  8. package/dist/src/prompts/adr-suggestion-prompts.js.map +1 -1
  9. package/dist/src/resources/index.d.ts.map +1 -1
  10. package/dist/src/resources/index.js +71 -1
  11. package/dist/src/resources/index.js.map +1 -1
  12. package/dist/src/tools/adr-suggestion-tool.d.ts +16 -0
  13. package/dist/src/tools/adr-suggestion-tool.d.ts.map +1 -1
  14. package/dist/src/tools/adr-suggestion-tool.js +55 -2
  15. package/dist/src/tools/adr-suggestion-tool.js.map +1 -1
  16. package/dist/src/tools/smart-git-push-tool.d.ts +21 -1
  17. package/dist/src/tools/smart-git-push-tool.d.ts.map +1 -1
  18. package/dist/src/tools/smart-git-push-tool.js +181 -28
  19. package/dist/src/tools/smart-git-push-tool.js.map +1 -1
  20. package/dist/src/tools/smart-score-tool.d.ts +173 -0
  21. package/dist/src/tools/smart-score-tool.d.ts.map +1 -0
  22. package/dist/src/tools/smart-score-tool.js +681 -0
  23. package/dist/src/tools/smart-score-tool.js.map +1 -0
  24. package/dist/src/tools/todo-management-tool-v2.d.ts +329 -0
  25. package/dist/src/tools/todo-management-tool-v2.d.ts.map +1 -0
  26. package/dist/src/tools/todo-management-tool-v2.js +644 -0
  27. package/dist/src/tools/todo-management-tool-v2.js.map +1 -0
  28. package/dist/src/tools/tool-chain-orchestrator.d.ts +126 -0
  29. package/dist/src/tools/tool-chain-orchestrator.d.ts.map +1 -0
  30. package/dist/src/tools/tool-chain-orchestrator.js +550 -0
  31. package/dist/src/tools/tool-chain-orchestrator.js.map +1 -0
  32. package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts +150 -0
  33. package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts.map +1 -0
  34. package/dist/src/tools/troubleshoot-guided-workflow-tool.js +520 -0
  35. package/dist/src/tools/troubleshoot-guided-workflow-tool.js.map +1 -0
  36. package/dist/src/types/conversation-context.d.ts +6 -0
  37. package/dist/src/types/conversation-context.d.ts.map +1 -1
  38. package/dist/src/types/conversation-context.js +9 -1
  39. package/dist/src/types/conversation-context.js.map +1 -1
  40. package/dist/src/types/knowledge-graph-schemas.d.ts +773 -0
  41. package/dist/src/types/knowledge-graph-schemas.d.ts.map +1 -0
  42. package/dist/src/types/knowledge-graph-schemas.js +87 -0
  43. package/dist/src/types/knowledge-graph-schemas.js.map +1 -0
  44. package/dist/src/types/todo-json-schemas.d.ts +663 -0
  45. package/dist/src/types/todo-json-schemas.d.ts.map +1 -0
  46. package/dist/src/types/todo-json-schemas.js +113 -0
  47. package/dist/src/types/todo-json-schemas.js.map +1 -0
  48. package/dist/src/utils/chain-of-thought-template.d.ts.map +1 -1
  49. package/dist/src/utils/chain-of-thought-template.js.map +1 -1
  50. package/dist/src/utils/json-safe.d.ts +38 -0
  51. package/dist/src/utils/json-safe.d.ts.map +1 -0
  52. package/dist/src/utils/json-safe.js +86 -0
  53. package/dist/src/utils/json-safe.js.map +1 -0
  54. package/dist/src/utils/knowledge-graph-manager.d.ts +65 -0
  55. package/dist/src/utils/knowledge-graph-manager.d.ts.map +1 -0
  56. package/dist/src/utils/knowledge-graph-manager.js +358 -0
  57. package/dist/src/utils/knowledge-graph-manager.js.map +1 -0
  58. package/dist/src/utils/mcp-response-validator.d.ts +30 -0
  59. package/dist/src/utils/mcp-response-validator.d.ts.map +1 -0
  60. package/dist/src/utils/mcp-response-validator.js +197 -0
  61. package/dist/src/utils/mcp-response-validator.js.map +1 -0
  62. package/dist/src/utils/project-health-scoring.d.ts +177 -0
  63. package/dist/src/utils/project-health-scoring.d.ts.map +1 -0
  64. package/dist/src/utils/project-health-scoring.js +370 -0
  65. package/dist/src/utils/project-health-scoring.js.map +1 -0
  66. package/dist/src/utils/release-readiness-detector.d.ts +2 -0
  67. package/dist/src/utils/release-readiness-detector.d.ts.map +1 -1
  68. package/dist/src/utils/release-readiness-detector.js +2 -0
  69. package/dist/src/utils/release-readiness-detector.js.map +1 -1
  70. package/dist/src/utils/todo-file-watcher.d.ts +26 -0
  71. package/dist/src/utils/todo-file-watcher.d.ts.map +1 -0
  72. package/dist/src/utils/todo-file-watcher.js +163 -0
  73. package/dist/src/utils/todo-file-watcher.js.map +1 -0
  74. package/dist/src/utils/todo-json-manager.d.ts +71 -0
  75. package/dist/src/utils/todo-json-manager.d.ts.map +1 -0
  76. package/dist/src/utils/todo-json-manager.js +394 -0
  77. package/dist/src/utils/todo-json-manager.js.map +1 -0
  78. package/dist/src/utils/todo-markdown-converter.d.ts +16 -0
  79. package/dist/src/utils/todo-markdown-converter.d.ts.map +1 -0
  80. package/dist/src/utils/todo-markdown-converter.js +362 -0
  81. package/dist/src/utils/todo-markdown-converter.js.map +1 -0
  82. package/dist/src/utils/todo-migration.d.ts +47 -0
  83. package/dist/src/utils/todo-migration.d.ts.map +1 -0
  84. package/dist/src/utils/todo-migration.js +261 -0
  85. package/dist/src/utils/todo-migration.js.map +1 -0
  86. package/package.json +1 -1
  87. package/dist/src/tools/todo-management-tool.d.ts +0 -166
  88. package/dist/src/tools/todo-management-tool.d.ts.map +0 -1
  89. package/dist/src/tools/todo-management-tool.js +0 -472
  90. 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