mcp-adr-analysis-server 2.0.21 → 2.1.0
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 +94 -839
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/config/ai-config.d.ts.map +1 -1
- package/dist/src/config/ai-config.js +9 -9
- package/dist/src/config/ai-config.js.map +1 -1
- package/dist/src/index.d.ts +15 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1594 -837
- package/dist/src/index.js.map +1 -1
- package/dist/src/prompts/analysis-prompts.d.ts +4 -1
- package/dist/src/prompts/analysis-prompts.d.ts.map +1 -1
- package/dist/src/prompts/analysis-prompts.js +61 -30
- package/dist/src/prompts/analysis-prompts.js.map +1 -1
- package/dist/src/prompts/index.d.ts +17 -1
- package/dist/src/prompts/index.d.ts.map +1 -1
- package/dist/src/prompts/index.js +325 -1
- package/dist/src/prompts/index.js.map +1 -1
- package/dist/src/prompts/rule-generation-prompts.d.ts +5 -1
- package/dist/src/prompts/rule-generation-prompts.d.ts.map +1 -1
- package/dist/src/prompts/rule-generation-prompts.js +5 -1
- package/dist/src/prompts/rule-generation-prompts.js.map +1 -1
- package/dist/src/prompts/security-prompts.d.ts +6 -1
- package/dist/src/prompts/security-prompts.d.ts.map +1 -1
- package/dist/src/prompts/security-prompts.js +6 -1
- package/dist/src/prompts/security-prompts.js.map +1 -1
- package/dist/src/prompts/todo-prompts.d.ts +49 -0
- package/dist/src/prompts/todo-prompts.d.ts.map +1 -0
- package/dist/src/prompts/todo-prompts.js +824 -0
- package/dist/src/prompts/todo-prompts.js.map +1 -0
- package/dist/src/resources/index.d.ts.map +1 -1
- package/dist/src/resources/index.js +9 -7
- package/dist/src/resources/index.js.map +1 -1
- package/dist/src/tools/adr-bootstrap-validation-tool.d.ts +47 -0
- package/dist/src/tools/adr-bootstrap-validation-tool.d.ts.map +1 -0
- package/dist/src/tools/adr-bootstrap-validation-tool.js +979 -0
- package/dist/src/tools/adr-bootstrap-validation-tool.js.map +1 -0
- package/dist/src/tools/adr-suggestion-tool.d.ts +1 -0
- package/dist/src/tools/adr-suggestion-tool.d.ts.map +1 -1
- package/dist/src/tools/adr-suggestion-tool.js +330 -32
- package/dist/src/tools/adr-suggestion-tool.js.map +1 -1
- package/dist/src/tools/content-masking-tool.d.ts +5 -0
- package/dist/src/tools/content-masking-tool.d.ts.map +1 -1
- package/dist/src/tools/content-masking-tool.js +631 -28
- package/dist/src/tools/content-masking-tool.js.map +1 -1
- package/dist/src/tools/deployment-readiness-tool.d.ts +8 -5
- package/dist/src/tools/deployment-readiness-tool.d.ts.map +1 -1
- package/dist/src/tools/deployment-readiness-tool.js +1017 -93
- package/dist/src/tools/deployment-readiness-tool.js.map +1 -1
- package/dist/src/tools/environment-analysis-tool.d.ts +4 -0
- package/dist/src/tools/environment-analysis-tool.d.ts.map +1 -1
- package/dist/src/tools/environment-analysis-tool.js +568 -24
- package/dist/src/tools/environment-analysis-tool.js.map +1 -1
- package/dist/src/tools/interactive-adr-planning-tool.d.ts.map +1 -1
- package/dist/src/tools/interactive-adr-planning-tool.js +270 -108
- package/dist/src/tools/interactive-adr-planning-tool.js.map +1 -1
- package/dist/src/tools/mcp-planning-tool.d.ts.map +1 -1
- package/dist/src/tools/mcp-planning-tool.js +316 -183
- package/dist/src/tools/mcp-planning-tool.js.map +1 -1
- package/dist/src/tools/memory-loading-tool.d.ts +60 -0
- package/dist/src/tools/memory-loading-tool.d.ts.map +1 -0
- package/dist/src/tools/memory-loading-tool.js +457 -0
- package/dist/src/tools/memory-loading-tool.js.map +1 -0
- package/dist/src/tools/research-integration-tool.d.ts +4 -1
- package/dist/src/tools/research-integration-tool.d.ts.map +1 -1
- package/dist/src/tools/research-integration-tool.js +5 -1
- package/dist/src/tools/research-integration-tool.js.map +1 -1
- package/dist/src/tools/review-existing-adrs-tool.d.ts +19 -0
- package/dist/src/tools/review-existing-adrs-tool.d.ts.map +1 -0
- package/dist/src/tools/review-existing-adrs-tool.js +1204 -0
- package/dist/src/tools/review-existing-adrs-tool.js.map +1 -0
- package/dist/src/tools/rule-generation-tool.d.ts +2 -0
- package/dist/src/tools/rule-generation-tool.d.ts.map +1 -1
- package/dist/src/tools/rule-generation-tool.js +274 -33
- package/dist/src/tools/rule-generation-tool.js.map +1 -1
- package/dist/src/tools/smart-git-push-tool-v2.d.ts +4 -0
- package/dist/src/tools/smart-git-push-tool-v2.d.ts.map +1 -1
- package/dist/src/tools/smart-git-push-tool-v2.js +423 -229
- package/dist/src/tools/smart-git-push-tool-v2.js.map +1 -1
- package/dist/src/tools/smart-git-push-tool.d.ts +3 -0
- package/dist/src/tools/smart-git-push-tool.d.ts.map +1 -1
- package/dist/src/tools/smart-git-push-tool.js +241 -235
- package/dist/src/tools/smart-git-push-tool.js.map +1 -1
- package/dist/src/tools/tool-chain-orchestrator.d.ts +2 -2
- package/dist/src/tools/tool-chain-orchestrator.d.ts.map +1 -1
- package/dist/src/tools/tool-chain-orchestrator.js +152 -93
- package/dist/src/tools/tool-chain-orchestrator.js.map +1 -1
- package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts +22 -13
- package/dist/src/tools/troubleshoot-guided-workflow-tool.d.ts.map +1 -1
- package/dist/src/tools/troubleshoot-guided-workflow-tool.js +660 -28
- package/dist/src/tools/troubleshoot-guided-workflow-tool.js.map +1 -1
- package/dist/src/types/ape-framework.d.ts +93 -0
- package/dist/src/types/ape-framework.d.ts.map +1 -1
- package/dist/src/types/ape-framework.js +10 -10
- package/dist/src/types/ape-framework.js.map +1 -1
- package/dist/src/types/enhanced-errors.d.ts +173 -0
- package/dist/src/types/enhanced-errors.d.ts.map +1 -0
- package/dist/src/types/enhanced-errors.js +668 -0
- package/dist/src/types/enhanced-errors.js.map +1 -0
- package/dist/src/types/index.d.ts +129 -3
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +15 -0
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/knowledge-generation.d.ts +78 -0
- package/dist/src/types/knowledge-generation.d.ts.map +1 -1
- package/dist/src/types/knowledge-generation.js +10 -6
- package/dist/src/types/knowledge-generation.js.map +1 -1
- package/dist/src/types/knowledge-graph-schemas.d.ts +92 -0
- package/dist/src/types/knowledge-graph-schemas.d.ts.map +1 -1
- package/dist/src/types/knowledge-graph-schemas.js +45 -17
- package/dist/src/types/knowledge-graph-schemas.js.map +1 -1
- package/dist/src/types/memory-entities.d.ts +7209 -0
- package/dist/src/types/memory-entities.d.ts.map +1 -0
- package/dist/src/types/memory-entities.js +395 -0
- package/dist/src/types/memory-entities.js.map +1 -0
- package/dist/src/types/reflexion-framework.d.ts +44 -0
- package/dist/src/types/reflexion-framework.d.ts.map +1 -1
- package/dist/src/types/reflexion-framework.js +7 -7
- package/dist/src/types/reflexion-framework.js.map +1 -1
- package/dist/src/types/todo-json-schemas.d.ts +7 -653
- package/dist/src/types/todo-json-schemas.d.ts.map +1 -1
- package/dist/src/types/todo-json-schemas.js +6 -110
- package/dist/src/types/todo-json-schemas.js.map +1 -1
- package/dist/src/types/tool-arguments.d.ts +224 -0
- package/dist/src/types/tool-arguments.d.ts.map +1 -0
- package/dist/src/types/tool-arguments.js +6 -0
- package/dist/src/types/tool-arguments.js.map +1 -0
- package/dist/src/utils/actual-file-operations.d.ts.map +1 -1
- package/dist/src/utils/actual-file-operations.js +25 -9
- package/dist/src/utils/actual-file-operations.js.map +1 -1
- package/dist/src/utils/adr-discovery.d.ts +33 -1
- package/dist/src/utils/adr-discovery.d.ts.map +1 -1
- package/dist/src/utils/adr-discovery.js +14 -9
- package/dist/src/utils/adr-discovery.js.map +1 -1
- package/dist/src/utils/adr-suggestions.d.ts +72 -0
- package/dist/src/utils/adr-suggestions.d.ts.map +1 -1
- package/dist/src/utils/adr-suggestions.js +6 -0
- package/dist/src/utils/adr-suggestions.js.map +1 -1
- package/dist/src/utils/cache.d.ts.map +1 -1
- package/dist/src/utils/cache.js +22 -19
- package/dist/src/utils/cache.js.map +1 -1
- package/dist/src/utils/chain-of-thought-template.d.ts +13 -1
- package/dist/src/utils/chain-of-thought-template.d.ts.map +1 -1
- package/dist/src/utils/chain-of-thought-template.js +31 -22
- package/dist/src/utils/chain-of-thought-template.js.map +1 -1
- package/dist/src/utils/config.d.ts.map +1 -1
- package/dist/src/utils/config.js +1 -0
- package/dist/src/utils/config.js.map +1 -1
- package/dist/src/utils/directory-compat.js +1 -1
- package/dist/src/utils/directory-compat.js.map +1 -1
- package/dist/src/utils/enhanced-logging.d.ts +195 -0
- package/dist/src/utils/enhanced-logging.d.ts.map +1 -0
- package/dist/src/utils/enhanced-logging.js +449 -0
- package/dist/src/utils/enhanced-logging.js.map +1 -0
- package/dist/src/utils/file-system.d.ts +182 -34
- package/dist/src/utils/file-system.d.ts.map +1 -1
- package/dist/src/utils/file-system.js +648 -774
- package/dist/src/utils/file-system.js.map +1 -1
- package/dist/src/utils/gitleaks-detector.d.ts +50 -0
- package/dist/src/utils/gitleaks-detector.d.ts.map +1 -0
- package/dist/src/utils/gitleaks-detector.js +334 -0
- package/dist/src/utils/gitleaks-detector.js.map +1 -0
- package/dist/src/utils/interactive-approval.d.ts +1 -1
- package/dist/src/utils/interactive-approval.d.ts.map +1 -1
- package/dist/src/utils/interactive-approval.js +22 -17
- package/dist/src/utils/interactive-approval.js.map +1 -1
- package/dist/src/utils/json-safe.d.ts.map +1 -1
- package/dist/src/utils/json-safe.js +9 -6
- package/dist/src/utils/json-safe.js.map +1 -1
- package/dist/src/utils/knowledge-graph-manager.d.ts +37 -1
- package/dist/src/utils/knowledge-graph-manager.d.ts.map +1 -1
- package/dist/src/utils/knowledge-graph-manager.js +315 -70
- package/dist/src/utils/knowledge-graph-manager.js.map +1 -1
- package/dist/src/utils/location-filter.d.ts +35 -10
- package/dist/src/utils/location-filter.d.ts.map +1 -1
- package/dist/src/utils/location-filter.js +360 -94
- package/dist/src/utils/location-filter.js.map +1 -1
- package/dist/src/utils/mcp-response-validator.d.ts.map +1 -1
- package/dist/src/utils/mcp-response-validator.js +34 -19
- package/dist/src/utils/mcp-response-validator.js.map +1 -1
- package/dist/src/utils/memory-entity-manager.d.ts +134 -0
- package/dist/src/utils/memory-entity-manager.d.ts.map +1 -0
- package/dist/src/utils/memory-entity-manager.js +851 -0
- package/dist/src/utils/memory-entity-manager.js.map +1 -0
- package/dist/src/utils/memory-health-scoring.d.ts +125 -0
- package/dist/src/utils/memory-health-scoring.d.ts.map +1 -0
- package/dist/src/utils/memory-health-scoring.js +277 -0
- package/dist/src/utils/memory-health-scoring.js.map +1 -0
- package/dist/src/utils/memory-migration-manager.d.ts +93 -0
- package/dist/src/utils/memory-migration-manager.d.ts.map +1 -0
- package/dist/src/utils/memory-migration-manager.js +842 -0
- package/dist/src/utils/memory-migration-manager.js.map +1 -0
- package/dist/src/utils/memory-relationship-mapper.d.ts +87 -0
- package/dist/src/utils/memory-relationship-mapper.d.ts.map +1 -0
- package/dist/src/utils/memory-relationship-mapper.js +482 -0
- package/dist/src/utils/memory-relationship-mapper.js.map +1 -0
- package/dist/src/utils/memory-rollback-manager.d.ts +105 -0
- package/dist/src/utils/memory-rollback-manager.d.ts.map +1 -0
- package/dist/src/utils/memory-rollback-manager.js +575 -0
- package/dist/src/utils/memory-rollback-manager.js.map +1 -0
- package/dist/src/utils/memory-transformation.d.ts +59 -0
- package/dist/src/utils/memory-transformation.d.ts.map +1 -0
- package/dist/src/utils/memory-transformation.js +742 -0
- package/dist/src/utils/memory-transformation.js.map +1 -0
- package/dist/src/utils/output-masking.d.ts +12 -0
- package/dist/src/utils/output-masking.d.ts.map +1 -1
- package/dist/src/utils/output-masking.js +5 -0
- package/dist/src/utils/output-masking.js.map +1 -1
- package/dist/src/utils/prompt-execution.d.ts.map +1 -1
- package/dist/src/utils/prompt-execution.js +72 -51
- package/dist/src/utils/prompt-execution.js.map +1 -1
- package/dist/src/utils/release-readiness-detector.d.ts.map +1 -1
- package/dist/src/utils/release-readiness-detector.js +43 -42
- package/dist/src/utils/release-readiness-detector.js.map +1 -1
- package/dist/src/utils/research-integration.d.ts.map +1 -1
- package/dist/src/utils/research-integration.js +73 -44
- package/dist/src/utils/research-integration.js.map +1 -1
- package/dist/src/utils/research-questions.d.ts.map +1 -1
- package/dist/src/utils/research-questions.js +40 -14
- package/dist/src/utils/research-questions.js.map +1 -1
- package/dist/src/utils/ripgrep-wrapper.d.ts +84 -0
- package/dist/src/utils/ripgrep-wrapper.d.ts.map +1 -0
- package/dist/src/utils/ripgrep-wrapper.js +255 -0
- package/dist/src/utils/ripgrep-wrapper.js.map +1 -0
- package/dist/src/utils/rule-generation.d.ts.map +1 -1
- package/dist/src/utils/rule-generation.js +26 -15
- package/dist/src/utils/rule-generation.js.map +1 -1
- package/dist/src/utils/todo-file-watcher.d.ts +11 -23
- package/dist/src/utils/todo-file-watcher.d.ts.map +1 -1
- package/dist/src/utils/todo-file-watcher.js +18 -156
- package/dist/src/utils/todo-file-watcher.js.map +1 -1
- package/dist/src/utils/tree-sitter-analyzer.d.ts +185 -0
- package/dist/src/utils/tree-sitter-analyzer.d.ts.map +1 -0
- package/dist/src/utils/tree-sitter-analyzer.js +885 -0
- package/dist/src/utils/tree-sitter-analyzer.js.map +1 -0
- package/package.json +51 -10
- package/dist/src/tools/smart-score-tool.d.ts +0 -173
- package/dist/src/tools/smart-score-tool.d.ts.map +0 -1
- package/dist/src/tools/smart-score-tool.js +0 -681
- package/dist/src/tools/smart-score-tool.js.map +0 -1
- package/dist/src/tools/todo-management-tool-v2.d.ts +0 -368
- package/dist/src/tools/todo-management-tool-v2.d.ts.map +0 -1
- package/dist/src/tools/todo-management-tool-v2.js +0 -922
- package/dist/src/tools/todo-management-tool-v2.js.map +0 -1
- package/dist/src/utils/enhanced-sensitive-detector.d.ts +0 -61
- package/dist/src/utils/enhanced-sensitive-detector.d.ts.map +0 -1
- package/dist/src/utils/enhanced-sensitive-detector.js +0 -437
- package/dist/src/utils/enhanced-sensitive-detector.js.map +0 -1
- package/dist/src/utils/project-health-scoring.d.ts +0 -177
- package/dist/src/utils/project-health-scoring.d.ts.map +0 -1
- package/dist/src/utils/project-health-scoring.js +0 -370
- package/dist/src/utils/project-health-scoring.js.map +0 -1
- package/dist/src/utils/todo-json-manager.d.ts +0 -71
- package/dist/src/utils/todo-json-manager.d.ts.map +0 -1
- package/dist/src/utils/todo-json-manager.js +0 -396
- package/dist/src/utils/todo-json-manager.js.map +0 -1
- package/dist/src/utils/todo-markdown-converter.d.ts +0 -16
- package/dist/src/utils/todo-markdown-converter.d.ts.map +0 -1
- package/dist/src/utils/todo-markdown-converter.js +0 -362
- package/dist/src/utils/todo-markdown-converter.js.map +0 -1
- package/dist/src/utils/todo-migration.d.ts +0 -47
- package/dist/src/utils/todo-migration.d.ts.map +0 -1
- package/dist/src/utils/todo-migration.js +0 -261
- package/dist/src/utils/todo-migration.js.map +0 -1
|
@@ -1,922 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON-First TODO Management Tool
|
|
3
|
-
*
|
|
4
|
-
* Replaces markdown-based TODO management with structured JSON backend
|
|
5
|
-
* for consistent LLM interactions and automatic scoring integration.
|
|
6
|
-
*
|
|
7
|
-
* IMPORTANT FOR AI ASSISTANTS: This tool requires the .mcp-adr-cache infrastructure
|
|
8
|
-
* to be initialized first. Run `discover_existing_adrs` before using this tool.
|
|
9
|
-
*
|
|
10
|
-
* Cache Dependencies:
|
|
11
|
-
* - Requires: .mcp-adr-cache/todo-data.json (main TODO storage)
|
|
12
|
-
* - Requires: .mcp-adr-cache/knowledge-graph-snapshots.json (for intent tracking)
|
|
13
|
-
* - Updates: .mcp-adr-cache/project-health-scores.json (task completion metrics)
|
|
14
|
-
*
|
|
15
|
-
* Key Features:
|
|
16
|
-
* - JSON-first storage with automatic Markdown synchronization
|
|
17
|
-
* - Automatic project health scoring integration
|
|
18
|
-
* - Knowledge graph intent tracking
|
|
19
|
-
* - Bidirectional TODO.md compatibility
|
|
20
|
-
*/
|
|
21
|
-
import { z } from 'zod';
|
|
22
|
-
import { McpAdrError } from '../types/index.js';
|
|
23
|
-
import { TodoJsonManager } from '../utils/todo-json-manager.js';
|
|
24
|
-
import { KnowledgeGraphManager } from '../utils/knowledge-graph-manager.js';
|
|
25
|
-
// Remove unused import
|
|
26
|
-
// Task operations schema
|
|
27
|
-
const CreateTaskSchema = z.object({
|
|
28
|
-
operation: z.literal('create_task'),
|
|
29
|
-
projectPath: z.string().describe('Project root path'),
|
|
30
|
-
title: z.string().describe('Task title'),
|
|
31
|
-
description: z.string().optional().describe('Task description'),
|
|
32
|
-
priority: z.enum(['low', 'medium', 'high', 'critical']).default('medium'),
|
|
33
|
-
assignee: z.string().optional().describe('Task assignee'),
|
|
34
|
-
dueDate: z.string().optional().describe('Due date (ISO string)'),
|
|
35
|
-
category: z.string().optional().describe('Task category'),
|
|
36
|
-
tags: z.array(z.string()).default([]).describe('Task tags'),
|
|
37
|
-
dependencies: z.array(z.string()).default([]).describe('Task dependencies (IDs)'),
|
|
38
|
-
intentId: z.string().optional().describe('Link to knowledge graph intent'),
|
|
39
|
-
linkedAdrs: z.array(z.string()).default([]).describe('Related ADR files'),
|
|
40
|
-
autoComplete: z.boolean().default(false).describe('Auto-complete when criteria met'),
|
|
41
|
-
completionCriteria: z.string().optional().describe('Auto-completion rules')
|
|
42
|
-
});
|
|
43
|
-
const UpdateTaskSchema = z.object({
|
|
44
|
-
operation: z.literal('update_task'),
|
|
45
|
-
projectPath: z.string().describe('Project root path'),
|
|
46
|
-
taskId: z.string().describe('Task ID to update'),
|
|
47
|
-
updates: z.object({
|
|
48
|
-
title: z.string().optional(),
|
|
49
|
-
description: z.string().optional(),
|
|
50
|
-
status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled']).optional(),
|
|
51
|
-
priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
|
|
52
|
-
assignee: z.string().optional(),
|
|
53
|
-
dueDate: z.string().optional(),
|
|
54
|
-
progressPercentage: z.number().min(0).max(100).optional(),
|
|
55
|
-
notes: z.string().optional(),
|
|
56
|
-
tags: z.array(z.string()).optional()
|
|
57
|
-
}).describe('Fields to update'),
|
|
58
|
-
reason: z.string().describe('Reason for update (for changelog)')
|
|
59
|
-
});
|
|
60
|
-
const BulkUpdateSchema = z.object({
|
|
61
|
-
operation: z.literal('bulk_update'),
|
|
62
|
-
projectPath: z.string().describe('Project root path'),
|
|
63
|
-
updates: z.array(z.object({
|
|
64
|
-
taskId: z.string(),
|
|
65
|
-
status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled']).optional(),
|
|
66
|
-
priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
|
|
67
|
-
assignee: z.string().optional(),
|
|
68
|
-
notes: z.string().optional()
|
|
69
|
-
})).describe('Bulk status updates'),
|
|
70
|
-
reason: z.string().describe('Reason for bulk update')
|
|
71
|
-
});
|
|
72
|
-
const GetTasksSchema = z.object({
|
|
73
|
-
operation: z.literal('get_tasks'),
|
|
74
|
-
projectPath: z.string().describe('Project root path'),
|
|
75
|
-
filters: z.object({
|
|
76
|
-
status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled']).optional(),
|
|
77
|
-
priority: z.enum(['low', 'medium', 'high', 'critical']).optional(),
|
|
78
|
-
assignee: z.string().optional(),
|
|
79
|
-
category: z.string().optional(),
|
|
80
|
-
hasDeadline: z.boolean().optional(),
|
|
81
|
-
overdue: z.boolean().optional(),
|
|
82
|
-
tags: z.array(z.string()).optional()
|
|
83
|
-
}).optional().describe('Filter criteria'),
|
|
84
|
-
sortBy: z.enum(['priority', 'dueDate', 'createdAt', 'updatedAt']).default('priority'),
|
|
85
|
-
sortOrder: z.enum(['asc', 'desc']).default('desc'),
|
|
86
|
-
limit: z.number().optional().describe('Maximum number of tasks to return'),
|
|
87
|
-
showFullIds: z.boolean().optional().default(false).describe('Show full UUIDs instead of short IDs')
|
|
88
|
-
});
|
|
89
|
-
const GetAnalyticsSchema = z.object({
|
|
90
|
-
operation: z.literal('get_analytics'),
|
|
91
|
-
projectPath: z.string().describe('Project root path'),
|
|
92
|
-
timeframe: z.enum(['day', 'week', 'month', 'all']).default('week').describe('Analysis timeframe'),
|
|
93
|
-
includeVelocity: z.boolean().default(true).describe('Include velocity metrics'),
|
|
94
|
-
includeScoring: z.boolean().default(true).describe('Include scoring metrics')
|
|
95
|
-
});
|
|
96
|
-
const ImportAdrTasksSchema = z.object({
|
|
97
|
-
operation: z.literal('import_adr_tasks'),
|
|
98
|
-
projectPath: z.string().describe('Project root path'),
|
|
99
|
-
adrDirectory: z.string().default('docs/adrs').describe('ADR directory path'),
|
|
100
|
-
intentId: z.string().optional().describe('Link imported tasks to intent'),
|
|
101
|
-
preserveExisting: z.boolean().default(true).describe('Keep existing tasks'),
|
|
102
|
-
autoLinkDependencies: z.boolean().default(true).describe('Auto-detect task dependencies')
|
|
103
|
-
});
|
|
104
|
-
const SyncWithKnowledgeGraphSchema = z.object({
|
|
105
|
-
operation: z.literal('sync_knowledge_graph'),
|
|
106
|
-
projectPath: z.string().describe('Project root path'),
|
|
107
|
-
direction: z.enum(['to_kg', 'from_kg', 'bidirectional']).default('bidirectional'),
|
|
108
|
-
intentId: z.string().optional().describe('Specific intent to sync with')
|
|
109
|
-
});
|
|
110
|
-
const SyncToMarkdownSchema = z.object({
|
|
111
|
-
operation: z.literal('sync_to_markdown'),
|
|
112
|
-
projectPath: z.string().describe('Project root path'),
|
|
113
|
-
force: z.boolean().default(false).describe('Force sync even if markdown is newer')
|
|
114
|
-
});
|
|
115
|
-
const ImportFromMarkdownSchema = z.object({
|
|
116
|
-
operation: z.literal('import_from_markdown'),
|
|
117
|
-
projectPath: z.string().describe('Project root path'),
|
|
118
|
-
mergeStrategy: z.enum(['overwrite', 'merge', 'preserve_json']).default('merge'),
|
|
119
|
-
backupExisting: z.boolean().default(true).describe('Create backup before import')
|
|
120
|
-
});
|
|
121
|
-
const FindTaskSchema = z.object({
|
|
122
|
-
operation: z.literal('find_task'),
|
|
123
|
-
projectPath: z.string().describe('Project root path'),
|
|
124
|
-
query: z.string().describe('Search query: partial ID, title, or description'),
|
|
125
|
-
searchType: z.enum(['id', 'title', 'description', 'all']).default('all').describe('What to search in')
|
|
126
|
-
});
|
|
127
|
-
const ResumeTodoListSchema = z.object({
|
|
128
|
-
operation: z.literal('resume_todo_list'),
|
|
129
|
-
projectPath: z.string().describe('Project root path'),
|
|
130
|
-
analyzeRecent: z.boolean().default(true).describe('Analyze recent changes and git commits'),
|
|
131
|
-
includeContext: z.boolean().default(true).describe('Include project context and ADR status'),
|
|
132
|
-
showNextActions: z.boolean().default(true).describe('Suggest next actionable steps'),
|
|
133
|
-
checkDeploymentReadiness: z.boolean().default(true).describe('Check if any tasks are deployment-ready')
|
|
134
|
-
});
|
|
135
|
-
// Main operation schema
|
|
136
|
-
const TodoManagementV2Schema = z.union([
|
|
137
|
-
CreateTaskSchema,
|
|
138
|
-
UpdateTaskSchema,
|
|
139
|
-
BulkUpdateSchema,
|
|
140
|
-
GetTasksSchema,
|
|
141
|
-
GetAnalyticsSchema,
|
|
142
|
-
ImportAdrTasksSchema,
|
|
143
|
-
SyncWithKnowledgeGraphSchema,
|
|
144
|
-
SyncToMarkdownSchema,
|
|
145
|
-
ImportFromMarkdownSchema,
|
|
146
|
-
FindTaskSchema,
|
|
147
|
-
ResumeTodoListSchema
|
|
148
|
-
]);
|
|
149
|
-
/**
|
|
150
|
-
* Main TODO management function with JSON backend
|
|
151
|
-
*/
|
|
152
|
-
export async function manageTodoV2(args) {
|
|
153
|
-
try {
|
|
154
|
-
const validatedArgs = TodoManagementV2Schema.parse(args);
|
|
155
|
-
const todoManager = new TodoJsonManager(validatedArgs.projectPath);
|
|
156
|
-
const kgManager = new KnowledgeGraphManager();
|
|
157
|
-
switch (validatedArgs.operation) {
|
|
158
|
-
case 'create_task': {
|
|
159
|
-
const taskId = await todoManager.createTask({
|
|
160
|
-
title: validatedArgs.title,
|
|
161
|
-
description: validatedArgs.description,
|
|
162
|
-
priority: validatedArgs.priority,
|
|
163
|
-
assignee: validatedArgs.assignee,
|
|
164
|
-
dueDate: validatedArgs.dueDate,
|
|
165
|
-
category: validatedArgs.category,
|
|
166
|
-
tags: validatedArgs.tags,
|
|
167
|
-
dependencies: validatedArgs.dependencies,
|
|
168
|
-
intentId: validatedArgs.intentId,
|
|
169
|
-
linkedAdrs: validatedArgs.linkedAdrs,
|
|
170
|
-
autoComplete: validatedArgs.autoComplete,
|
|
171
|
-
completionCriteria: validatedArgs.completionCriteria
|
|
172
|
-
});
|
|
173
|
-
return {
|
|
174
|
-
content: [{
|
|
175
|
-
type: 'text',
|
|
176
|
-
text: `✅ Task created successfully!\n\n**Task ID**: ${taskId}\n**Title**: ${validatedArgs.title}\n**Priority**: ${validatedArgs.priority}\n**Status**: pending\n\n*Task has been added to JSON backend and will sync to TODO.md automatically.*`
|
|
177
|
-
}]
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
case 'update_task': {
|
|
181
|
-
// Resolve partial ID to full ID if needed
|
|
182
|
-
let taskId = validatedArgs.taskId;
|
|
183
|
-
// If taskId looks like a partial ID (less than full UUID length), try to find the full ID
|
|
184
|
-
if (taskId.length < 36) {
|
|
185
|
-
const data = await todoManager.loadTodoData();
|
|
186
|
-
const tasks = Object.values(data.tasks);
|
|
187
|
-
const matchingTasks = tasks.filter(task => task.id.startsWith(taskId.toLowerCase()));
|
|
188
|
-
if (matchingTasks.length === 0) {
|
|
189
|
-
return {
|
|
190
|
-
content: [{
|
|
191
|
-
type: 'text',
|
|
192
|
-
text: `❌ No task found with ID starting with "${taskId}"\n\n**Suggestions:**\n1. Use the \`find_task\` operation to search for tasks\n2. Use \`get_tasks\` with \`showFullIds: true\` to see all full IDs\n3. Check that the task ID is correct`
|
|
193
|
-
}]
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
else if (matchingTasks.length > 1) {
|
|
197
|
-
const taskList = matchingTasks.map(task => `- **${task.title}** (ID: \`${task.id}\`)`).join('\n');
|
|
198
|
-
return {
|
|
199
|
-
content: [{
|
|
200
|
-
type: 'text',
|
|
201
|
-
text: `❌ Multiple tasks found with ID starting with "${taskId}"\n\n**Matching tasks:**\n${taskList}\n\n**Please use a more specific ID or the full UUID.**`
|
|
202
|
-
}]
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
taskId = matchingTasks[0].id;
|
|
206
|
-
}
|
|
207
|
-
// Filter out undefined values
|
|
208
|
-
const cleanUpdates = {};
|
|
209
|
-
if (validatedArgs.updates.title !== undefined)
|
|
210
|
-
cleanUpdates.title = validatedArgs.updates.title;
|
|
211
|
-
if (validatedArgs.updates.description !== undefined)
|
|
212
|
-
cleanUpdates.description = validatedArgs.updates.description;
|
|
213
|
-
if (validatedArgs.updates.status !== undefined)
|
|
214
|
-
cleanUpdates.status = validatedArgs.updates.status;
|
|
215
|
-
if (validatedArgs.updates.priority !== undefined)
|
|
216
|
-
cleanUpdates.priority = validatedArgs.updates.priority;
|
|
217
|
-
if (validatedArgs.updates.assignee !== undefined)
|
|
218
|
-
cleanUpdates.assignee = validatedArgs.updates.assignee;
|
|
219
|
-
if (validatedArgs.updates.dueDate !== undefined)
|
|
220
|
-
cleanUpdates.dueDate = validatedArgs.updates.dueDate;
|
|
221
|
-
if (validatedArgs.updates.progressPercentage !== undefined)
|
|
222
|
-
cleanUpdates.progressPercentage = validatedArgs.updates.progressPercentage;
|
|
223
|
-
if (validatedArgs.updates.notes !== undefined)
|
|
224
|
-
cleanUpdates.notes = validatedArgs.updates.notes;
|
|
225
|
-
if (validatedArgs.updates.tags !== undefined)
|
|
226
|
-
cleanUpdates.tags = validatedArgs.updates.tags;
|
|
227
|
-
await todoManager.updateTask({
|
|
228
|
-
taskId: taskId,
|
|
229
|
-
updates: cleanUpdates,
|
|
230
|
-
reason: validatedArgs.reason,
|
|
231
|
-
triggeredBy: 'tool'
|
|
232
|
-
});
|
|
233
|
-
return {
|
|
234
|
-
content: [{
|
|
235
|
-
type: 'text',
|
|
236
|
-
text: `✅ Task updated successfully!\n\n**Task ID**: ${taskId}\n**Original Input**: ${validatedArgs.taskId}\n**Updates**: ${Object.keys(validatedArgs.updates).filter(k => validatedArgs.updates[k] !== undefined).join(', ')}\n**Reason**: ${validatedArgs.reason}\n\n*Changes synced to JSON backend and TODO.md.*`
|
|
237
|
-
}]
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
case 'bulk_update': {
|
|
241
|
-
let updateCount = 0;
|
|
242
|
-
for (const update of validatedArgs.updates) {
|
|
243
|
-
// Filter out undefined values
|
|
244
|
-
const cleanUpdates = {};
|
|
245
|
-
if (update.status !== undefined)
|
|
246
|
-
cleanUpdates.status = update.status;
|
|
247
|
-
if (update.priority !== undefined)
|
|
248
|
-
cleanUpdates.priority = update.priority;
|
|
249
|
-
if (update.assignee !== undefined)
|
|
250
|
-
cleanUpdates.assignee = update.assignee;
|
|
251
|
-
if (update.notes !== undefined)
|
|
252
|
-
cleanUpdates.notes = update.notes;
|
|
253
|
-
await todoManager.updateTask({
|
|
254
|
-
taskId: update.taskId,
|
|
255
|
-
updates: cleanUpdates,
|
|
256
|
-
reason: validatedArgs.reason,
|
|
257
|
-
triggeredBy: 'tool'
|
|
258
|
-
});
|
|
259
|
-
updateCount++;
|
|
260
|
-
}
|
|
261
|
-
return {
|
|
262
|
-
content: [{
|
|
263
|
-
type: 'text',
|
|
264
|
-
text: `✅ Bulk update completed!\n\n**Tasks Updated**: ${updateCount}\n**Reason**: ${validatedArgs.reason}\n\n*All changes synced to JSON backend and TODO.md.*`
|
|
265
|
-
}]
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
case 'get_tasks': {
|
|
269
|
-
const data = await todoManager.loadTodoData();
|
|
270
|
-
let tasks = Object.values(data.tasks);
|
|
271
|
-
// Apply filters
|
|
272
|
-
if (validatedArgs.filters) {
|
|
273
|
-
const filters = validatedArgs.filters;
|
|
274
|
-
if (filters.status) {
|
|
275
|
-
tasks = tasks.filter(t => t.status === filters.status);
|
|
276
|
-
}
|
|
277
|
-
if (filters.priority) {
|
|
278
|
-
tasks = tasks.filter(t => t.priority === filters.priority);
|
|
279
|
-
}
|
|
280
|
-
if (filters.assignee) {
|
|
281
|
-
tasks = tasks.filter(t => t.assignee === filters.assignee);
|
|
282
|
-
}
|
|
283
|
-
if (filters.category) {
|
|
284
|
-
tasks = tasks.filter(t => t.category === filters.category);
|
|
285
|
-
}
|
|
286
|
-
if (filters.hasDeadline) {
|
|
287
|
-
tasks = tasks.filter(t => Boolean(t.dueDate));
|
|
288
|
-
}
|
|
289
|
-
if (filters.overdue) {
|
|
290
|
-
const now = new Date();
|
|
291
|
-
tasks = tasks.filter(t => t.dueDate && new Date(t.dueDate) < now && t.status !== 'completed');
|
|
292
|
-
}
|
|
293
|
-
if (filters.tags && filters.tags.length > 0) {
|
|
294
|
-
tasks = tasks.filter(t => filters.tags.some(tag => t.tags.includes(tag)));
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
// Sort tasks
|
|
298
|
-
tasks.sort((a, b) => {
|
|
299
|
-
const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
|
|
300
|
-
switch (validatedArgs.sortBy) {
|
|
301
|
-
case 'priority':
|
|
302
|
-
return validatedArgs.sortOrder === 'desc'
|
|
303
|
-
? priorityOrder[b.priority] - priorityOrder[a.priority]
|
|
304
|
-
: priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
305
|
-
case 'dueDate':
|
|
306
|
-
if (!a.dueDate && !b.dueDate)
|
|
307
|
-
return 0;
|
|
308
|
-
if (!a.dueDate)
|
|
309
|
-
return 1;
|
|
310
|
-
if (!b.dueDate)
|
|
311
|
-
return -1;
|
|
312
|
-
return validatedArgs.sortOrder === 'desc'
|
|
313
|
-
? new Date(b.dueDate).getTime() - new Date(a.dueDate).getTime()
|
|
314
|
-
: new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
|
|
315
|
-
case 'createdAt':
|
|
316
|
-
return validatedArgs.sortOrder === 'desc'
|
|
317
|
-
? new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
|
318
|
-
: new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
|
|
319
|
-
case 'updatedAt':
|
|
320
|
-
return validatedArgs.sortOrder === 'desc'
|
|
321
|
-
? new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
|
322
|
-
: new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime();
|
|
323
|
-
default:
|
|
324
|
-
return 0;
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
// Apply limit
|
|
328
|
-
if (validatedArgs.limit) {
|
|
329
|
-
tasks = tasks.slice(0, validatedArgs.limit);
|
|
330
|
-
}
|
|
331
|
-
const taskList = tasks.map(task => {
|
|
332
|
-
const dueDateStr = task.dueDate ? new Date(task.dueDate).toLocaleDateString() : 'No due date';
|
|
333
|
-
const isOverdue = task.dueDate && new Date(task.dueDate) < new Date() && task.status !== 'completed';
|
|
334
|
-
const taskId = (validatedArgs.showFullIds ?? false) ? task.id : task.id.substring(0, 8);
|
|
335
|
-
return `**${task.title}** (ID: ${taskId})\n` +
|
|
336
|
-
` Status: ${task.status} | Priority: ${task.priority}\n` +
|
|
337
|
-
` ${task.assignee ? `Assignee: ${task.assignee} | ` : ''}Due: ${dueDateStr} ${isOverdue ? '🔴 OVERDUE' : ''}\n` +
|
|
338
|
-
` ${task.tags.length > 0 ? `Tags: ${task.tags.join(', ')} | ` : ''}Progress: ${task.progressPercentage}%\n` +
|
|
339
|
-
` ${task.description || 'No description'}\n`;
|
|
340
|
-
}).join('\n');
|
|
341
|
-
return {
|
|
342
|
-
content: [{
|
|
343
|
-
type: 'text',
|
|
344
|
-
text: `# 📋 Task List (${tasks.length} tasks)\n\n${taskList || 'No tasks match the criteria.'}`
|
|
345
|
-
}]
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
case 'get_analytics': {
|
|
349
|
-
const analytics = await todoManager.getAnalytics();
|
|
350
|
-
const { metrics, trends, recommendations } = analytics;
|
|
351
|
-
let analyticsText = `# 📊 TODO Analytics\n\n`;
|
|
352
|
-
analyticsText += `## Task Metrics\n`;
|
|
353
|
-
analyticsText += `- **Total Tasks**: ${metrics.totalTasks}\n`;
|
|
354
|
-
analyticsText += `- **Completed**: ${metrics.completedTasks} (${metrics.completionPercentage.toFixed(1)}%)\n`;
|
|
355
|
-
analyticsText += `- **Priority Score**: ${metrics.priorityWeightedScore.toFixed(1)}%\n`;
|
|
356
|
-
analyticsText += `- **Critical Remaining**: ${metrics.criticalTasksRemaining}\n`;
|
|
357
|
-
analyticsText += `- **Blocked Tasks**: ${metrics.blockedTasksCount}\n`;
|
|
358
|
-
analyticsText += `- **Average Task Age**: ${metrics.averageTaskAge.toFixed(1)} days\n\n`;
|
|
359
|
-
if (validatedArgs.includeVelocity) {
|
|
360
|
-
analyticsText += `## Velocity Metrics\n`;
|
|
361
|
-
analyticsText += `- **Tasks/Week**: ${metrics.velocityMetrics.tasksCompletedLastWeek}\n`;
|
|
362
|
-
analyticsText += `- **Avg Completion Time**: ${metrics.velocityMetrics.averageCompletionTime.toFixed(1)} hours\n\n`;
|
|
363
|
-
}
|
|
364
|
-
if (recommendations.length > 0) {
|
|
365
|
-
analyticsText += `## Recommendations\n`;
|
|
366
|
-
analyticsText += recommendations.map(rec => `- ${rec}`).join('\n');
|
|
367
|
-
analyticsText += '\n\n';
|
|
368
|
-
}
|
|
369
|
-
if (trends.length > 0) {
|
|
370
|
-
analyticsText += `## Recent Score History\n`;
|
|
371
|
-
analyticsText += trends.slice(-5).map(trend => `- ${new Date(trend.timestamp).toLocaleDateString()}: ${trend.score.toFixed(1)}% (${trend.trigger})`).join('\n');
|
|
372
|
-
}
|
|
373
|
-
return {
|
|
374
|
-
content: [{
|
|
375
|
-
type: 'text',
|
|
376
|
-
text: analyticsText
|
|
377
|
-
}]
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
case 'import_adr_tasks': {
|
|
381
|
-
const adrDirectory = validatedArgs.adrDirectory;
|
|
382
|
-
const intentId = validatedArgs.intentId;
|
|
383
|
-
const preserveExisting = validatedArgs.preserveExisting;
|
|
384
|
-
const autoLinkDependencies = validatedArgs.autoLinkDependencies;
|
|
385
|
-
// Discover ADRs in the directory
|
|
386
|
-
const { discoverAdrsInDirectory } = await import('../utils/adr-discovery.js');
|
|
387
|
-
const discoveryResult = await discoverAdrsInDirectory(adrDirectory, true, // include content for task extraction
|
|
388
|
-
validatedArgs.projectPath);
|
|
389
|
-
if (discoveryResult.totalAdrs === 0) {
|
|
390
|
-
return {
|
|
391
|
-
content: [{
|
|
392
|
-
type: 'text',
|
|
393
|
-
text: `⚠️ No ADRs found in directory: ${adrDirectory}\n\n**Recommendations:**\n${discoveryResult.recommendations.join('\n')}`
|
|
394
|
-
}]
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
// Smart completion preservation: Load existing data before any operations
|
|
398
|
-
// This must happen BEFORE any data wiping for preserveExisting: false
|
|
399
|
-
const existingData = await todoManager.loadTodoData();
|
|
400
|
-
const existingTasksByTitle = new Map();
|
|
401
|
-
// Create a lookup map of existing tasks by title for smart matching
|
|
402
|
-
Object.values(existingData.tasks).forEach(task => {
|
|
403
|
-
const normalizedTitle = task.title.toLowerCase().trim();
|
|
404
|
-
existingTasksByTitle.set(normalizedTitle, task);
|
|
405
|
-
});
|
|
406
|
-
// If preserveExisting is false, we need to clear existing data first
|
|
407
|
-
// but we've already captured the completion states above
|
|
408
|
-
if (!preserveExisting) {
|
|
409
|
-
// Clear existing tasks but preserve the sections structure
|
|
410
|
-
const freshData = await todoManager.loadTodoData();
|
|
411
|
-
freshData.tasks = {};
|
|
412
|
-
freshData.sections.forEach(section => {
|
|
413
|
-
section.tasks = [];
|
|
414
|
-
});
|
|
415
|
-
await todoManager.saveTodoData(freshData, false); // Don't sync to markdown yet
|
|
416
|
-
}
|
|
417
|
-
// Extract tasks from each ADR
|
|
418
|
-
const extractedTasks = await extractTasksFromAdrs(discoveryResult.adrs, adrDirectory, intentId, autoLinkDependencies);
|
|
419
|
-
// Import tasks into JSON backend with smart completion preservation
|
|
420
|
-
let importedCount = 0;
|
|
421
|
-
let skippedCount = 0;
|
|
422
|
-
let preservedCompletions = 0;
|
|
423
|
-
const importResults = [];
|
|
424
|
-
for (const task of extractedTasks) {
|
|
425
|
-
try {
|
|
426
|
-
// Check if task already exists (by title and ADR reference) - only relevant when preserveExisting is true
|
|
427
|
-
let existingTask = null;
|
|
428
|
-
if (preserveExisting) {
|
|
429
|
-
const currentData = await todoManager.loadTodoData();
|
|
430
|
-
existingTask = Object.values(currentData.tasks).find(t => t.title === task.title &&
|
|
431
|
-
t.linkedAdrs.some(adr => task.linkedAdrs.includes(adr)));
|
|
432
|
-
}
|
|
433
|
-
if (existingTask && preserveExisting) {
|
|
434
|
-
skippedCount++;
|
|
435
|
-
importResults.push(`⏭️ Skipped: "${task.title}" (already exists)`);
|
|
436
|
-
continue;
|
|
437
|
-
}
|
|
438
|
-
// Smart completion preservation: match by title even if preserveExisting is false
|
|
439
|
-
const normalizedTitle = task.title.toLowerCase().trim();
|
|
440
|
-
const previousTask = existingTasksByTitle.get(normalizedTitle);
|
|
441
|
-
let taskToCreate = { ...task };
|
|
442
|
-
if (previousTask && (previousTask.status === 'completed' || previousTask.progressPercentage > 0)) {
|
|
443
|
-
// Preserve completion status and progress from previous task
|
|
444
|
-
taskToCreate = {
|
|
445
|
-
...task,
|
|
446
|
-
status: previousTask.status,
|
|
447
|
-
progressPercentage: previousTask.progressPercentage,
|
|
448
|
-
completedAt: previousTask.completedAt,
|
|
449
|
-
notes: previousTask.notes,
|
|
450
|
-
assignee: previousTask.assignee || task.assignee,
|
|
451
|
-
};
|
|
452
|
-
preservedCompletions++;
|
|
453
|
-
importResults.push(`🔄 Imported with preserved completion: "${task.title}" (${previousTask.status}, ${previousTask.progressPercentage}%)`);
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
importResults.push(`✅ Imported: "${task.title}" (${task.priority} priority)`);
|
|
457
|
-
}
|
|
458
|
-
// Create the task with preserved completion if applicable
|
|
459
|
-
await todoManager.createTask({
|
|
460
|
-
title: taskToCreate.title,
|
|
461
|
-
description: taskToCreate.description,
|
|
462
|
-
status: taskToCreate.status,
|
|
463
|
-
priority: taskToCreate.priority,
|
|
464
|
-
category: taskToCreate.category,
|
|
465
|
-
tags: taskToCreate.tags,
|
|
466
|
-
dependencies: taskToCreate.dependencies,
|
|
467
|
-
linkedAdrs: taskToCreate.linkedAdrs,
|
|
468
|
-
assignee: taskToCreate.assignee,
|
|
469
|
-
progressPercentage: taskToCreate.progressPercentage,
|
|
470
|
-
notes: taskToCreate.notes,
|
|
471
|
-
completedAt: taskToCreate.completedAt,
|
|
472
|
-
...(intentId && { intentId })
|
|
473
|
-
});
|
|
474
|
-
importedCount++;
|
|
475
|
-
}
|
|
476
|
-
catch (error) {
|
|
477
|
-
importResults.push(`❌ Failed: "${task.title}" - ${error instanceof Error ? error.message : String(error)}`);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
return {
|
|
481
|
-
content: [{
|
|
482
|
-
type: 'text',
|
|
483
|
-
text: `# ✅ ADR Task Import Completed
|
|
484
|
-
|
|
485
|
-
## Import Summary
|
|
486
|
-
- **ADRs Scanned**: ${discoveryResult.totalAdrs}
|
|
487
|
-
- **Tasks Extracted**: ${extractedTasks.length}
|
|
488
|
-
- **Tasks Imported**: ${importedCount}
|
|
489
|
-
- **Tasks Skipped**: ${skippedCount}
|
|
490
|
-
- **Completions Preserved**: ${preservedCompletions}
|
|
491
|
-
- **Preserve Existing**: ${preserveExisting}
|
|
492
|
-
- **Auto-Link Dependencies**: ${autoLinkDependencies}
|
|
493
|
-
|
|
494
|
-
## ADR Status Overview
|
|
495
|
-
${Object.entries(discoveryResult.summary.byStatus)
|
|
496
|
-
.map(([status, count]) => `- **${status}**: ${count} ADRs`)
|
|
497
|
-
.join('\n')}
|
|
498
|
-
|
|
499
|
-
## Import Results
|
|
500
|
-
${importResults.join('\n')}
|
|
501
|
-
|
|
502
|
-
${preservedCompletions > 0 ? `
|
|
503
|
-
## 🎯 Smart Completion Preservation
|
|
504
|
-
✅ **${preservedCompletions} task completions preserved** during import!
|
|
505
|
-
Tasks with the same title retained their completion status and progress.
|
|
506
|
-
` : ''}
|
|
507
|
-
|
|
508
|
-
## Next Steps
|
|
509
|
-
1. **View Tasks**: Use \`get_tasks\` operation to see imported tasks
|
|
510
|
-
2. **Sync to Markdown**: Tasks will be automatically synced to TODO.md
|
|
511
|
-
3. **Update Status**: Use \`update_task\` operation to track progress
|
|
512
|
-
4. **Link Knowledge Graph**: Tasks are ${intentId ? `linked to intent ${intentId}` : 'ready for intent linking'}
|
|
513
|
-
|
|
514
|
-
*All tasks have been imported into the JSON backend and are ready for the complete TODO management workflow.*`
|
|
515
|
-
}]
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
case 'sync_knowledge_graph': {
|
|
519
|
-
const data = await todoManager.loadTodoData();
|
|
520
|
-
// Sync task completion status to knowledge graph
|
|
521
|
-
for (const task of Object.values(data.tasks)) {
|
|
522
|
-
if (task.intentId) {
|
|
523
|
-
await kgManager.updateTodoSnapshot(task.intentId, `Task ${task.status}: ${task.title} (${task.progressPercentage}%)`);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
return {
|
|
527
|
-
content: [{
|
|
528
|
-
type: 'text',
|
|
529
|
-
text: `✅ Knowledge graph sync completed!\n\n**Direction**: ${validatedArgs.direction}\n**Tasks with Intent Links**: ${Object.values(data.tasks).filter(t => t.intentId).length}\n\n*Task progress has been synced to the knowledge graph.*`
|
|
530
|
-
}]
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
case 'sync_to_markdown': {
|
|
534
|
-
await todoManager.convertToMarkdown();
|
|
535
|
-
return {
|
|
536
|
-
content: [{
|
|
537
|
-
type: 'text',
|
|
538
|
-
text: `✅ Markdown sync completed!\n\n*TODO.md has been updated with the latest JSON data including health dashboard and formatted task lists.*`
|
|
539
|
-
}]
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
case 'import_from_markdown': {
|
|
543
|
-
if (validatedArgs.backupExisting) {
|
|
544
|
-
// Create backup of existing JSON
|
|
545
|
-
const data = await todoManager.loadTodoData();
|
|
546
|
-
const backupPath = `${validatedArgs.projectPath}/.mcp-adr-cache/todo-data-backup-${Date.now()}.json`;
|
|
547
|
-
const fs = await import('fs/promises');
|
|
548
|
-
await fs.writeFile(backupPath, JSON.stringify(data, null, 2));
|
|
549
|
-
}
|
|
550
|
-
await todoManager.importFromMarkdown();
|
|
551
|
-
return {
|
|
552
|
-
content: [{
|
|
553
|
-
type: 'text',
|
|
554
|
-
text: `✅ Markdown import completed!\n\n**Strategy**: ${validatedArgs.mergeStrategy}\n**Backup Created**: ${validatedArgs.backupExisting}\n\n*TODO.md has been parsed and imported into the JSON backend.*`
|
|
555
|
-
}]
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
case 'find_task': {
|
|
559
|
-
const data = await todoManager.loadTodoData();
|
|
560
|
-
const tasks = Object.values(data.tasks);
|
|
561
|
-
const query = validatedArgs.query.toLowerCase();
|
|
562
|
-
let matchingTasks = tasks.filter(task => {
|
|
563
|
-
switch (validatedArgs.searchType) {
|
|
564
|
-
case 'id':
|
|
565
|
-
return task.id.toLowerCase().includes(query);
|
|
566
|
-
case 'title':
|
|
567
|
-
return task.title.toLowerCase().includes(query);
|
|
568
|
-
case 'description':
|
|
569
|
-
return task.description?.toLowerCase().includes(query);
|
|
570
|
-
case 'all':
|
|
571
|
-
default:
|
|
572
|
-
return task.id.toLowerCase().includes(query) ||
|
|
573
|
-
task.title.toLowerCase().includes(query) ||
|
|
574
|
-
task.description?.toLowerCase().includes(query) ||
|
|
575
|
-
task.tags.some(tag => tag.toLowerCase().includes(query));
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
if (matchingTasks.length === 0) {
|
|
579
|
-
return {
|
|
580
|
-
content: [{
|
|
581
|
-
type: 'text',
|
|
582
|
-
text: `❌ No tasks found matching "${validatedArgs.query}"\n\n**Search Type**: ${validatedArgs.searchType}\n**Total Tasks**: ${tasks.length}\n\n*Try using a different query or search type.*`
|
|
583
|
-
}]
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
const taskList = matchingTasks.map(task => {
|
|
587
|
-
const dueDateStr = task.dueDate ? new Date(task.dueDate).toLocaleDateString() : 'No due date';
|
|
588
|
-
const isOverdue = task.dueDate && new Date(task.dueDate) < new Date() && task.status !== 'completed';
|
|
589
|
-
return `**${task.title}**\n` +
|
|
590
|
-
` 🆔 **Full ID**: \`${task.id}\`\n` +
|
|
591
|
-
` 📋 **Short ID**: \`${task.id.substring(0, 8)}\`\n` +
|
|
592
|
-
` 📊 Status: ${task.status} | Priority: ${task.priority}\n` +
|
|
593
|
-
` ${task.assignee ? `👤 Assignee: ${task.assignee} | ` : ''}📅 Due: ${dueDateStr} ${isOverdue ? '🔴 OVERDUE' : ''}\n` +
|
|
594
|
-
` ${task.tags.length > 0 ? `🏷️ Tags: ${task.tags.join(', ')} | ` : ''}📈 Progress: ${task.progressPercentage}%\n` +
|
|
595
|
-
` 📝 ${task.description || 'No description'}\n`;
|
|
596
|
-
}).join('\n');
|
|
597
|
-
return {
|
|
598
|
-
content: [{
|
|
599
|
-
type: 'text',
|
|
600
|
-
text: `# 🔍 Search Results (${matchingTasks.length} found)\n\n**Query**: "${validatedArgs.query}"\n**Search Type**: ${validatedArgs.searchType}\n\n${taskList}\n\n💡 **Tip**: Copy the Full ID to use with update_task operation.`
|
|
601
|
-
}]
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
case 'resume_todo_list': {
|
|
605
|
-
const data = await todoManager.loadTodoData();
|
|
606
|
-
const tasks = Object.values(data.tasks);
|
|
607
|
-
const analytics = await todoManager.getAnalytics();
|
|
608
|
-
// Get recent activity from task change logs
|
|
609
|
-
const recentActivity = Object.values(data.tasks)
|
|
610
|
-
.flatMap(task => task.changeLog || [])
|
|
611
|
-
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
612
|
-
.slice(0, 10)
|
|
613
|
-
.map((entry) => `- ${new Date(entry.timestamp).toLocaleDateString()}: ${entry.action} - ${entry.details}`)
|
|
614
|
-
.join('\n');
|
|
615
|
-
// Analyze current state
|
|
616
|
-
const inProgressTasks = tasks.filter(t => t.status === 'in_progress');
|
|
617
|
-
const pendingHighPriority = tasks.filter(t => t.status === 'pending' && ['high', 'critical'].includes(t.priority));
|
|
618
|
-
const overdueTasks = tasks.filter(t => t.dueDate && new Date(t.dueDate) < new Date() && t.status !== 'completed');
|
|
619
|
-
const blockedTasks = tasks.filter(t => t.status === 'blocked');
|
|
620
|
-
// Check deployment readiness
|
|
621
|
-
let deploymentReadyTasks = [];
|
|
622
|
-
let deploymentGuidance = '';
|
|
623
|
-
if (validatedArgs.checkDeploymentReadiness) {
|
|
624
|
-
deploymentReadyTasks = tasks.filter(t => t.status === 'completed' &&
|
|
625
|
-
(t.tags.includes('deployment') || t.category === 'Deployment' ||
|
|
626
|
-
t.title.toLowerCase().includes('deploy') || t.description?.toLowerCase().includes('deploy')));
|
|
627
|
-
if (deploymentReadyTasks.length > 0) {
|
|
628
|
-
deploymentGuidance = `\n## 🚀 Deployment Status\n**${deploymentReadyTasks.length} deployment-ready tasks found!**\n` +
|
|
629
|
-
deploymentReadyTasks.map(t => `- ✅ ${t.title}`).join('\n') +
|
|
630
|
-
`\n\n💡 **Tip**: Consider running deployment validation and using smart git push for these completed tasks.`;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
// Generate context summary
|
|
634
|
-
let contextSummary = '';
|
|
635
|
-
if (validatedArgs.includeContext) {
|
|
636
|
-
const fs = await import('fs/promises');
|
|
637
|
-
const path = await import('path');
|
|
638
|
-
// Check for recent git commits
|
|
639
|
-
try {
|
|
640
|
-
const { execSync } = await import('child_process');
|
|
641
|
-
const recentCommits = execSync('git log --oneline -5', {
|
|
642
|
-
cwd: validatedArgs.projectPath,
|
|
643
|
-
encoding: 'utf8'
|
|
644
|
-
}).trim().split('\n').slice(0, 3);
|
|
645
|
-
contextSummary += `\n## 📝 Recent Git Activity\n${recentCommits.map(commit => `- ${commit}`).join('\n')}\n`;
|
|
646
|
-
}
|
|
647
|
-
catch (error) {
|
|
648
|
-
// Git not available or no commits
|
|
649
|
-
}
|
|
650
|
-
// Check ADR status
|
|
651
|
-
try {
|
|
652
|
-
const adrPath = path.join(validatedArgs.projectPath, 'docs/adrs');
|
|
653
|
-
const adrFiles = await fs.readdir(adrPath).catch(() => []);
|
|
654
|
-
if (adrFiles.length > 0) {
|
|
655
|
-
contextSummary += `\n## 📋 ADR Context\n- **${adrFiles.length} ADRs** found in docs/adrs\n- Last TODO/ADR sync: ${data.metadata.lastAdrSync || 'Never'}\n`;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
catch (error) {
|
|
659
|
-
// ADR directory not found
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
// Generate next actions
|
|
663
|
-
let nextActions = '';
|
|
664
|
-
if (validatedArgs.showNextActions) {
|
|
665
|
-
const suggestions = [];
|
|
666
|
-
if (inProgressTasks.length > 0) {
|
|
667
|
-
suggestions.push(`Continue working on ${inProgressTasks.length} in-progress task(s)`);
|
|
668
|
-
}
|
|
669
|
-
if (overdueTasks.length > 0) {
|
|
670
|
-
suggestions.push(`Address ${overdueTasks.length} overdue task(s) - these need immediate attention`);
|
|
671
|
-
}
|
|
672
|
-
if (blockedTasks.length > 0) {
|
|
673
|
-
suggestions.push(`Unblock ${blockedTasks.length} blocked task(s) - resolve dependencies`);
|
|
674
|
-
}
|
|
675
|
-
if (pendingHighPriority.length > 0) {
|
|
676
|
-
suggestions.push(`Start ${pendingHighPriority.length} high-priority pending task(s)`);
|
|
677
|
-
}
|
|
678
|
-
if (analytics.metrics.completionPercentage > 80) {
|
|
679
|
-
suggestions.push('Project is nearing completion - consider deployment preparation');
|
|
680
|
-
}
|
|
681
|
-
if (deploymentReadyTasks.length > 0) {
|
|
682
|
-
suggestions.push('Review and deploy completed tasks using smart git push');
|
|
683
|
-
}
|
|
684
|
-
if (suggestions.length > 0) {
|
|
685
|
-
nextActions = `\n## 🎯 Recommended Next Actions\n${suggestions.map((s, i) => `${i + 1}. ${s}`).join('\n')}\n`;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
const resumeReport = `# 🔄 Resume TODO List - Session Context
|
|
689
|
-
|
|
690
|
-
## 📊 Current Status Summary
|
|
691
|
-
- **Total Tasks**: ${tasks.length}
|
|
692
|
-
- **Completion Rate**: ${analytics.metrics.completionPercentage.toFixed(1)}%
|
|
693
|
-
- **In Progress**: ${inProgressTasks.length} tasks
|
|
694
|
-
- **Pending High Priority**: ${pendingHighPriority.length} tasks
|
|
695
|
-
- **Overdue**: ${overdueTasks.length} tasks ${overdueTasks.length > 0 ? '🔴' : '✅'}
|
|
696
|
-
- **Blocked**: ${blockedTasks.length} tasks ${blockedTasks.length > 0 ? '⚠️' : '✅'}
|
|
697
|
-
|
|
698
|
-
## 🔥 Immediate Attention Required
|
|
699
|
-
${overdueTasks.length > 0 ?
|
|
700
|
-
overdueTasks.map(t => `- **${t.title}** (Due: ${new Date(t.dueDate).toLocaleDateString()}) - ${t.priority} priority`).join('\n') :
|
|
701
|
-
'✅ No overdue tasks'}
|
|
702
|
-
|
|
703
|
-
## 🚧 Currently In Progress
|
|
704
|
-
${inProgressTasks.length > 0 ?
|
|
705
|
-
inProgressTasks.map(t => `- **${t.title}** (${t.progressPercentage}% complete) - ${t.assignee || 'Unassigned'}`).join('\n') :
|
|
706
|
-
'📝 No tasks currently in progress'}
|
|
707
|
-
|
|
708
|
-
## ⚠️ Blocked Tasks
|
|
709
|
-
${blockedTasks.length > 0 ?
|
|
710
|
-
blockedTasks.map(t => `- **${t.title}** - ${t.notes || 'No blocking reason specified'}`).join('\n') :
|
|
711
|
-
'✅ No blocked tasks'}
|
|
712
|
-
|
|
713
|
-
${contextSummary}
|
|
714
|
-
|
|
715
|
-
## 📈 Recent Activity
|
|
716
|
-
${recentActivity || 'No recent TODO activity'}
|
|
717
|
-
|
|
718
|
-
${nextActions}
|
|
719
|
-
|
|
720
|
-
${deploymentGuidance}
|
|
721
|
-
|
|
722
|
-
## 💡 Session Resume Tips
|
|
723
|
-
1. Use \`get_tasks\` with filters to see specific task categories
|
|
724
|
-
2. Use \`find_task\` to quickly locate tasks by title or partial ID
|
|
725
|
-
3. Update task status as you work: \`update_task\` with progress notes
|
|
726
|
-
4. Check \`get_analytics\` for detailed progress metrics
|
|
727
|
-
5. Run smart git push when tasks are deployment-ready
|
|
728
|
-
|
|
729
|
-
---
|
|
730
|
-
*Ready to continue where you left off! Use the recommended actions above to prioritize your work.*`;
|
|
731
|
-
return {
|
|
732
|
-
content: [{
|
|
733
|
-
type: 'text',
|
|
734
|
-
text: resumeReport
|
|
735
|
-
}]
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
default:
|
|
739
|
-
throw new McpAdrError(`Unknown operation: ${validatedArgs.operation}`, 'INVALID_INPUT');
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
catch (error) {
|
|
743
|
-
if (error instanceof z.ZodError) {
|
|
744
|
-
throw new McpAdrError(`Invalid input: ${error.errors.map(e => e.message).join(', ')}`, 'INVALID_INPUT');
|
|
745
|
-
}
|
|
746
|
-
throw new McpAdrError(`TODO management failed: ${error instanceof Error ? error.message : String(error)}`, 'TODO_MANAGEMENT_ERROR');
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Extract implementation tasks from ADR content
|
|
751
|
-
*/
|
|
752
|
-
async function extractTasksFromAdrs(adrs, _adrDirectory, _intentId, autoLinkDependencies = true) {
|
|
753
|
-
const extractedTasks = [];
|
|
754
|
-
for (const adr of adrs) {
|
|
755
|
-
if (!adr.content)
|
|
756
|
-
continue;
|
|
757
|
-
// Extract tasks from Decision and Consequences sections
|
|
758
|
-
const tasks = extractTasksFromAdrContent(adr);
|
|
759
|
-
// Add ADR metadata to each task
|
|
760
|
-
for (const task of tasks) {
|
|
761
|
-
task.linkedAdrs = [adr.path];
|
|
762
|
-
task.category = task.category || 'ADR Implementation';
|
|
763
|
-
task.tags = task.tags || [];
|
|
764
|
-
// Add ADR-specific tags
|
|
765
|
-
if (adr.metadata?.number) {
|
|
766
|
-
task.tags.push(`adr-${adr.metadata.number}`);
|
|
767
|
-
}
|
|
768
|
-
if (adr.status) {
|
|
769
|
-
task.tags.push(`status-${adr.status}`);
|
|
770
|
-
}
|
|
771
|
-
// Set priority based on ADR status and content
|
|
772
|
-
if (!task.priority) {
|
|
773
|
-
task.priority = determinePriorityFromAdr(adr);
|
|
774
|
-
}
|
|
775
|
-
extractedTasks.push(task);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
// Link dependencies between ADRs if requested
|
|
779
|
-
if (autoLinkDependencies) {
|
|
780
|
-
linkAdrDependencies(extractedTasks, adrs);
|
|
781
|
-
}
|
|
782
|
-
return extractedTasks;
|
|
783
|
-
}
|
|
784
|
-
/**
|
|
785
|
-
* Extract tasks from ADR content sections
|
|
786
|
-
*/
|
|
787
|
-
function extractTasksFromAdrContent(adr) {
|
|
788
|
-
const tasks = [];
|
|
789
|
-
const content = adr.content || '';
|
|
790
|
-
// Look for implementation tasks in Decision section
|
|
791
|
-
if (adr.decision && typeof adr.decision === 'string') {
|
|
792
|
-
const decisionTasks = extractTasksFromText(adr.decision, 'Implementation', 'high');
|
|
793
|
-
tasks.push(...decisionTasks);
|
|
794
|
-
}
|
|
795
|
-
// Look for tasks in Consequences section
|
|
796
|
-
if (adr.consequences && typeof adr.consequences === 'string') {
|
|
797
|
-
const consequenceTasks = extractTasksFromText(adr.consequences, 'Validation', 'medium');
|
|
798
|
-
tasks.push(...consequenceTasks);
|
|
799
|
-
}
|
|
800
|
-
// Look for explicit task lists in content
|
|
801
|
-
const taskListRegex = /(?:##?\s*(?:tasks?|todo|implementation|action items?)\s*\n)([\s\S]*?)(?=\n##|\n#|$)/gi;
|
|
802
|
-
let match;
|
|
803
|
-
while ((match = taskListRegex.exec(content)) !== null) {
|
|
804
|
-
const taskSection = match[1];
|
|
805
|
-
if (taskSection) {
|
|
806
|
-
const sectionTasks = extractTasksFromText(taskSection, 'Task', 'medium');
|
|
807
|
-
tasks.push(...sectionTasks);
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
// If no explicit tasks found, create a general implementation task
|
|
811
|
-
if (tasks.length === 0) {
|
|
812
|
-
tasks.push({
|
|
813
|
-
title: `Implement ${adr.title}`,
|
|
814
|
-
description: `Implement the architectural decision: ${adr.title}`,
|
|
815
|
-
priority: 'medium',
|
|
816
|
-
category: 'ADR Implementation',
|
|
817
|
-
tags: ['implementation'],
|
|
818
|
-
dependencies: [],
|
|
819
|
-
linkedAdrs: []
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
return tasks;
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Extract tasks from text content using patterns
|
|
826
|
-
*/
|
|
827
|
-
function extractTasksFromText(text, defaultCategory, defaultPriority) {
|
|
828
|
-
const tasks = [];
|
|
829
|
-
// Look for bullet points that look like tasks
|
|
830
|
-
const taskPatterns = [
|
|
831
|
-
/[-*+]\s+(.+?)(?:\n|$)/g,
|
|
832
|
-
/\d+\.\s+(.+?)(?:\n|$)/g,
|
|
833
|
-
/(?:must|should|will|need to|implement|create|build|develop|configure|setup|establish)\s+(.+?)(?:\.|$)/gi
|
|
834
|
-
];
|
|
835
|
-
for (const pattern of taskPatterns) {
|
|
836
|
-
let match;
|
|
837
|
-
while ((match = pattern.exec(text)) !== null) {
|
|
838
|
-
const taskText = match[1]?.trim();
|
|
839
|
-
if (!taskText || taskText.length < 10 || taskText.length > 200)
|
|
840
|
-
continue; // Filter out very short/long matches
|
|
841
|
-
// Determine priority from keywords
|
|
842
|
-
let priority = defaultPriority;
|
|
843
|
-
if (/critical|urgent|must|security|breaking/.test(taskText.toLowerCase())) {
|
|
844
|
-
priority = 'critical';
|
|
845
|
-
}
|
|
846
|
-
else if (/important|should|key|major/.test(taskText.toLowerCase())) {
|
|
847
|
-
priority = 'high';
|
|
848
|
-
}
|
|
849
|
-
else if (/nice|could|minor|optional/.test(taskText.toLowerCase())) {
|
|
850
|
-
priority = 'low';
|
|
851
|
-
}
|
|
852
|
-
// Extract assignee if mentioned
|
|
853
|
-
let assignee;
|
|
854
|
-
const assigneeMatch = taskText.match(/@(\w+)|assigned to (\w+)|by (\w+)/i);
|
|
855
|
-
if (assigneeMatch) {
|
|
856
|
-
assignee = assigneeMatch[1] || assigneeMatch[2] || assigneeMatch[3];
|
|
857
|
-
}
|
|
858
|
-
tasks.push({
|
|
859
|
-
title: taskText.charAt(0).toUpperCase() + taskText.slice(1), // Capitalize first letter
|
|
860
|
-
description: `Task extracted from ADR: ${taskText}`,
|
|
861
|
-
priority,
|
|
862
|
-
category: defaultCategory,
|
|
863
|
-
tags: [],
|
|
864
|
-
dependencies: [],
|
|
865
|
-
linkedAdrs: [],
|
|
866
|
-
...(assignee && { assignee })
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return tasks;
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* Determine priority based on ADR status and content
|
|
874
|
-
*/
|
|
875
|
-
function determinePriorityFromAdr(adr) {
|
|
876
|
-
const status = adr.status?.toLowerCase() || '';
|
|
877
|
-
const content = (adr.content || '').toLowerCase();
|
|
878
|
-
// High priority for accepted/active ADRs
|
|
879
|
-
if (['accepted', 'active', 'approved'].includes(status)) {
|
|
880
|
-
return 'high';
|
|
881
|
-
}
|
|
882
|
-
// Critical for security/breaking changes
|
|
883
|
-
if (/security|breaking|critical|urgent/.test(content)) {
|
|
884
|
-
return 'critical';
|
|
885
|
-
}
|
|
886
|
-
// Low priority for deprecated/superseded
|
|
887
|
-
if (['deprecated', 'superseded', 'rejected'].includes(status)) {
|
|
888
|
-
return 'low';
|
|
889
|
-
}
|
|
890
|
-
// Default to medium
|
|
891
|
-
return 'medium';
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Link dependencies between ADR tasks
|
|
895
|
-
*/
|
|
896
|
-
function linkAdrDependencies(tasks, adrs) {
|
|
897
|
-
// Simple dependency linking based on ADR numbers and references
|
|
898
|
-
for (const task of tasks) {
|
|
899
|
-
const taskAdr = adrs.find(adr => task.linkedAdrs.includes(adr.path));
|
|
900
|
-
if (!taskAdr)
|
|
901
|
-
continue;
|
|
902
|
-
// Look for references to other ADRs in the content
|
|
903
|
-
const content = taskAdr.content || '';
|
|
904
|
-
const adrReferences = content.match(/adr[-_]?(\d+)/gi) || [];
|
|
905
|
-
for (const ref of adrReferences) {
|
|
906
|
-
const refNumber = ref.match(/(\d+)/)?.[1];
|
|
907
|
-
if (!refNumber || refNumber === taskAdr.metadata?.number)
|
|
908
|
-
continue;
|
|
909
|
-
// Find tasks from the referenced ADR
|
|
910
|
-
const referencedAdr = adrs.find(adr => adr.metadata?.number === refNumber);
|
|
911
|
-
if (!referencedAdr)
|
|
912
|
-
continue;
|
|
913
|
-
const referencedTasks = tasks.filter(t => t.linkedAdrs.includes(referencedAdr.path));
|
|
914
|
-
for (const refTask of referencedTasks) {
|
|
915
|
-
if (!task.dependencies.includes(refTask.title)) {
|
|
916
|
-
task.dependencies.push(refTask.title);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
//# sourceMappingURL=todo-management-tool-v2.js.map
|