musubi-sdd 5.1.0 → 5.6.1
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.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +158 -146
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +241 -126
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +77 -81
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +48 -46
- package/src/monitoring/incident-manager.js +116 -106
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +75 -62
- package/src/monitoring/quality-dashboard.js +45 -41
- package/src/monitoring/release-manager.js +63 -53
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- package/src/validators/traceability-validator.js +7 -11
|
@@ -19,7 +19,7 @@ const PLAN_STATUS = {
|
|
|
19
19
|
PAUSED: 'paused',
|
|
20
20
|
COMPLETED: 'completed',
|
|
21
21
|
FAILED: 'failed',
|
|
22
|
-
CANCELLED: 'cancelled'
|
|
22
|
+
CANCELLED: 'cancelled',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -33,7 +33,7 @@ const TASK_STATUS = {
|
|
|
33
33
|
BLOCKED: 'blocked',
|
|
34
34
|
COMPLETED: 'completed',
|
|
35
35
|
FAILED: 'failed',
|
|
36
|
-
SKIPPED: 'skipped'
|
|
36
|
+
SKIPPED: 'skipped',
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -45,7 +45,7 @@ const PRIORITY = {
|
|
|
45
45
|
HIGH: 1,
|
|
46
46
|
MEDIUM: 2,
|
|
47
47
|
LOW: 3,
|
|
48
|
-
OPTIONAL: 4
|
|
48
|
+
OPTIONAL: 4,
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -96,19 +96,19 @@ class PlanningEngine extends EventEmitter {
|
|
|
96
96
|
*/
|
|
97
97
|
constructor(options = {}) {
|
|
98
98
|
super();
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
this.maxTasks = options.maxTasks ?? 50;
|
|
101
101
|
this.parallelExecution = options.parallelExecution ?? true;
|
|
102
102
|
this.maxParallel = options.maxParallel ?? 4;
|
|
103
103
|
this.adaptivePlanning = options.adaptivePlanning ?? true;
|
|
104
104
|
this.replanThreshold = options.replanThreshold ?? 0.3;
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
// State
|
|
107
107
|
this.plans = new Map();
|
|
108
108
|
this.activePlan = null;
|
|
109
109
|
this.taskCounter = 0;
|
|
110
110
|
}
|
|
111
|
-
|
|
111
|
+
|
|
112
112
|
/**
|
|
113
113
|
* Create a plan from a goal
|
|
114
114
|
* @param {string} goal - High-level goal description
|
|
@@ -117,7 +117,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
117
117
|
*/
|
|
118
118
|
async createPlan(goal, context = {}) {
|
|
119
119
|
const planId = this.generateId('plan');
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
const plan = {
|
|
122
122
|
id: planId,
|
|
123
123
|
goal,
|
|
@@ -133,43 +133,43 @@ class PlanningEngine extends EventEmitter {
|
|
|
133
133
|
failedTasks: 0,
|
|
134
134
|
skippedTasks: 0,
|
|
135
135
|
totalEstimatedTime: 0,
|
|
136
|
-
actualTime: 0
|
|
137
|
-
}
|
|
136
|
+
actualTime: 0,
|
|
137
|
+
},
|
|
138
138
|
};
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
this.emit('plan:creating', { planId, goal });
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
// Decompose goal into tasks
|
|
143
143
|
const tasks = await this.decomposeGoal(goal, context);
|
|
144
144
|
plan.tasks = tasks;
|
|
145
145
|
plan.metrics.totalTasks = tasks.length;
|
|
146
146
|
plan.metrics.totalEstimatedTime = tasks.reduce((sum, t) => sum + t.estimatedTime, 0);
|
|
147
|
-
|
|
147
|
+
|
|
148
148
|
// Optimize task order
|
|
149
149
|
this.optimizeTaskOrder(plan);
|
|
150
|
-
|
|
150
|
+
|
|
151
151
|
// Update status
|
|
152
152
|
plan.status = PLAN_STATUS.READY;
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
this.plans.set(planId, plan);
|
|
155
155
|
this.emit('plan:created', { plan });
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
return plan;
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
/**
|
|
161
161
|
* Decompose goal into tasks
|
|
162
162
|
* @private
|
|
163
163
|
*/
|
|
164
|
-
async decomposeGoal(goal,
|
|
164
|
+
async decomposeGoal(goal, _context) {
|
|
165
165
|
const tasks = [];
|
|
166
|
-
|
|
166
|
+
|
|
167
167
|
// Analyze goal for key components
|
|
168
168
|
const components = this.analyzeGoal(goal);
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
for (let i = 0; i < components.length; i++) {
|
|
171
171
|
const component = components[i];
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
const task = {
|
|
174
174
|
id: this.generateId('task'),
|
|
175
175
|
name: component.name,
|
|
@@ -183,21 +183,21 @@ class PlanningEngine extends EventEmitter {
|
|
|
183
183
|
result: null,
|
|
184
184
|
metadata: {
|
|
185
185
|
component: component.type,
|
|
186
|
-
index: i
|
|
187
|
-
}
|
|
186
|
+
index: i,
|
|
187
|
+
},
|
|
188
188
|
};
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
// Add dependencies from previous tasks if sequential
|
|
191
191
|
if (i > 0 && component.dependsOnPrevious !== false) {
|
|
192
192
|
task.dependencies.push(tasks[i - 1].id);
|
|
193
193
|
}
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
tasks.push(task);
|
|
196
196
|
}
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
return tasks;
|
|
199
199
|
}
|
|
200
|
-
|
|
200
|
+
|
|
201
201
|
/**
|
|
202
202
|
* Analyze goal to extract components
|
|
203
203
|
* @private
|
|
@@ -205,7 +205,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
205
205
|
analyzeGoal(goal) {
|
|
206
206
|
const components = [];
|
|
207
207
|
const goalLower = goal.toLowerCase();
|
|
208
|
-
|
|
208
|
+
|
|
209
209
|
// Pattern matching for common goal structures
|
|
210
210
|
const patterns = [
|
|
211
211
|
{ keyword: 'create', type: 'creation', priority: PRIORITY.HIGH },
|
|
@@ -217,9 +217,9 @@ class PlanningEngine extends EventEmitter {
|
|
|
217
217
|
{ keyword: 'refactor', type: 'refactoring', priority: PRIORITY.MEDIUM },
|
|
218
218
|
{ keyword: 'document', type: 'documentation', priority: PRIORITY.LOW },
|
|
219
219
|
{ keyword: 'analyze', type: 'analysis', priority: PRIORITY.MEDIUM },
|
|
220
|
-
{ keyword: 'review', type: 'review', priority: PRIORITY.MEDIUM }
|
|
220
|
+
{ keyword: 'review', type: 'review', priority: PRIORITY.MEDIUM },
|
|
221
221
|
];
|
|
222
|
-
|
|
222
|
+
|
|
223
223
|
// Match patterns
|
|
224
224
|
for (const pattern of patterns) {
|
|
225
225
|
if (goalLower.includes(pattern.keyword)) {
|
|
@@ -228,11 +228,11 @@ class PlanningEngine extends EventEmitter {
|
|
|
228
228
|
description: `${pattern.type} task for: ${goal.substring(0, 50)}`,
|
|
229
229
|
type: pattern.type,
|
|
230
230
|
priority: pattern.priority,
|
|
231
|
-
estimatedTime: this.estimateTime(pattern.type)
|
|
231
|
+
estimatedTime: this.estimateTime(pattern.type),
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
|
-
|
|
235
|
+
|
|
236
236
|
// If no patterns matched, create generic decomposition
|
|
237
237
|
if (components.length === 0) {
|
|
238
238
|
components.push(
|
|
@@ -241,35 +241,35 @@ class PlanningEngine extends EventEmitter {
|
|
|
241
241
|
description: 'Analyze requirements and context',
|
|
242
242
|
type: 'analysis',
|
|
243
243
|
priority: PRIORITY.HIGH,
|
|
244
|
-
estimatedTime: 3000
|
|
244
|
+
estimatedTime: 3000,
|
|
245
245
|
},
|
|
246
246
|
{
|
|
247
247
|
name: 'Planning',
|
|
248
248
|
description: 'Create detailed implementation plan',
|
|
249
249
|
type: 'planning',
|
|
250
250
|
priority: PRIORITY.HIGH,
|
|
251
|
-
estimatedTime: 2000
|
|
251
|
+
estimatedTime: 2000,
|
|
252
252
|
},
|
|
253
253
|
{
|
|
254
254
|
name: 'Execution',
|
|
255
255
|
description: 'Execute the main task',
|
|
256
256
|
type: 'execution',
|
|
257
257
|
priority: PRIORITY.HIGH,
|
|
258
|
-
estimatedTime: 10000
|
|
258
|
+
estimatedTime: 10000,
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
name: 'Validation',
|
|
262
262
|
description: 'Validate results and quality',
|
|
263
263
|
type: 'validation',
|
|
264
264
|
priority: PRIORITY.MEDIUM,
|
|
265
|
-
estimatedTime: 3000
|
|
265
|
+
estimatedTime: 3000,
|
|
266
266
|
}
|
|
267
267
|
);
|
|
268
268
|
}
|
|
269
|
-
|
|
269
|
+
|
|
270
270
|
return components;
|
|
271
271
|
}
|
|
272
|
-
|
|
272
|
+
|
|
273
273
|
/**
|
|
274
274
|
* Estimate time for task type
|
|
275
275
|
* @private
|
|
@@ -285,12 +285,12 @@ class PlanningEngine extends EventEmitter {
|
|
|
285
285
|
refactoring: 15000,
|
|
286
286
|
documentation: 5000,
|
|
287
287
|
analysis: 5000,
|
|
288
|
-
review: 6000
|
|
288
|
+
review: 6000,
|
|
289
289
|
};
|
|
290
|
-
|
|
290
|
+
|
|
291
291
|
return estimates[type] || 10000;
|
|
292
292
|
}
|
|
293
|
-
|
|
293
|
+
|
|
294
294
|
/**
|
|
295
295
|
* Optimize task order based on dependencies and priorities
|
|
296
296
|
* @private
|
|
@@ -300,15 +300,15 @@ class PlanningEngine extends EventEmitter {
|
|
|
300
300
|
const sorted = [];
|
|
301
301
|
const visited = new Set();
|
|
302
302
|
const visiting = new Set();
|
|
303
|
-
|
|
304
|
-
const visit =
|
|
303
|
+
|
|
304
|
+
const visit = taskId => {
|
|
305
305
|
if (visited.has(taskId)) return;
|
|
306
306
|
if (visiting.has(taskId)) {
|
|
307
307
|
throw new Error(`Circular dependency detected for task ${taskId}`);
|
|
308
308
|
}
|
|
309
|
-
|
|
309
|
+
|
|
310
310
|
visiting.add(taskId);
|
|
311
|
-
|
|
311
|
+
|
|
312
312
|
const task = plan.tasks.find(t => t.id === taskId);
|
|
313
313
|
if (task) {
|
|
314
314
|
for (const depId of task.dependencies) {
|
|
@@ -317,18 +317,18 @@ class PlanningEngine extends EventEmitter {
|
|
|
317
317
|
visited.add(taskId);
|
|
318
318
|
sorted.push(task);
|
|
319
319
|
}
|
|
320
|
-
|
|
320
|
+
|
|
321
321
|
visiting.delete(taskId);
|
|
322
322
|
};
|
|
323
|
-
|
|
323
|
+
|
|
324
324
|
// Sort by priority first, then visit
|
|
325
325
|
const byPriority = [...plan.tasks].sort((a, b) => a.priority - b.priority);
|
|
326
326
|
for (const task of byPriority) {
|
|
327
327
|
visit(task.id);
|
|
328
328
|
}
|
|
329
|
-
|
|
329
|
+
|
|
330
330
|
plan.tasks = sorted;
|
|
331
|
-
|
|
331
|
+
|
|
332
332
|
// Update ready status for tasks with no dependencies
|
|
333
333
|
for (const task of plan.tasks) {
|
|
334
334
|
if (task.dependencies.length === 0) {
|
|
@@ -336,7 +336,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
|
-
|
|
339
|
+
|
|
340
340
|
/**
|
|
341
341
|
* Execute a plan
|
|
342
342
|
* @param {string} planId - Plan identifier
|
|
@@ -349,38 +349,37 @@ class PlanningEngine extends EventEmitter {
|
|
|
349
349
|
if (plan.status === PLAN_STATUS.EXECUTING) {
|
|
350
350
|
throw new Error('Plan is already executing');
|
|
351
351
|
}
|
|
352
|
-
|
|
352
|
+
|
|
353
353
|
plan.status = PLAN_STATUS.EXECUTING;
|
|
354
354
|
plan.startedAt = Date.now();
|
|
355
355
|
this.activePlan = plan;
|
|
356
|
-
|
|
356
|
+
|
|
357
357
|
this.emit('plan:executing', { planId });
|
|
358
|
-
|
|
358
|
+
|
|
359
359
|
try {
|
|
360
360
|
if (this.parallelExecution) {
|
|
361
361
|
await this.executeParallel(plan, executor);
|
|
362
362
|
} else {
|
|
363
363
|
await this.executeSequential(plan, executor);
|
|
364
364
|
}
|
|
365
|
-
|
|
365
|
+
|
|
366
366
|
// Determine final status
|
|
367
367
|
const hasFailures = plan.tasks.some(t => t.status === TASK_STATUS.FAILED);
|
|
368
368
|
plan.status = hasFailures ? PLAN_STATUS.FAILED : PLAN_STATUS.COMPLETED;
|
|
369
|
-
|
|
370
369
|
} catch (error) {
|
|
371
370
|
plan.status = PLAN_STATUS.FAILED;
|
|
372
371
|
this.emit('plan:error', { planId, error: error.message });
|
|
373
372
|
}
|
|
374
|
-
|
|
373
|
+
|
|
375
374
|
plan.completedAt = Date.now();
|
|
376
375
|
plan.metrics.actualTime = plan.completedAt - plan.startedAt;
|
|
377
376
|
this.activePlan = null;
|
|
378
|
-
|
|
377
|
+
|
|
379
378
|
this.emit('plan:completed', { plan });
|
|
380
|
-
|
|
379
|
+
|
|
381
380
|
return plan;
|
|
382
381
|
}
|
|
383
|
-
|
|
382
|
+
|
|
384
383
|
/**
|
|
385
384
|
* Execute tasks sequentially
|
|
386
385
|
* @private
|
|
@@ -388,31 +387,31 @@ class PlanningEngine extends EventEmitter {
|
|
|
388
387
|
async executeSequential(plan, executor) {
|
|
389
388
|
for (const task of plan.tasks) {
|
|
390
389
|
if (task.status === TASK_STATUS.SKIPPED) continue;
|
|
391
|
-
|
|
390
|
+
|
|
392
391
|
// Check dependencies
|
|
393
392
|
const blocked = task.dependencies.some(depId => {
|
|
394
393
|
const dep = plan.tasks.find(t => t.id === depId);
|
|
395
394
|
return dep && dep.status === TASK_STATUS.FAILED;
|
|
396
395
|
});
|
|
397
|
-
|
|
396
|
+
|
|
398
397
|
if (blocked) {
|
|
399
398
|
task.status = TASK_STATUS.SKIPPED;
|
|
400
399
|
plan.metrics.skippedTasks++;
|
|
401
400
|
continue;
|
|
402
401
|
}
|
|
403
|
-
|
|
402
|
+
|
|
404
403
|
await this.executeTask(task, executor, plan);
|
|
405
404
|
}
|
|
406
405
|
}
|
|
407
|
-
|
|
406
|
+
|
|
408
407
|
/**
|
|
409
408
|
* Execute tasks in parallel where possible
|
|
410
409
|
* @private
|
|
411
410
|
*/
|
|
412
411
|
async executeParallel(plan, executor) {
|
|
413
412
|
const completed = new Set();
|
|
414
|
-
|
|
415
|
-
|
|
413
|
+
|
|
414
|
+
for (;;) {
|
|
416
415
|
// Find tasks that are ready to execute
|
|
417
416
|
const ready = plan.tasks.filter(task => {
|
|
418
417
|
if (task.status !== TASK_STATUS.READY && task.status !== TASK_STATUS.PENDING) {
|
|
@@ -421,16 +420,17 @@ class PlanningEngine extends EventEmitter {
|
|
|
421
420
|
// Check all dependencies are completed
|
|
422
421
|
return task.dependencies.every(depId => completed.has(depId));
|
|
423
422
|
});
|
|
424
|
-
|
|
423
|
+
|
|
425
424
|
if (ready.length === 0) {
|
|
426
425
|
// No more tasks ready - check if we're done
|
|
427
|
-
const remaining = plan.tasks.filter(
|
|
428
|
-
t
|
|
429
|
-
|
|
430
|
-
|
|
426
|
+
const remaining = plan.tasks.filter(
|
|
427
|
+
t =>
|
|
428
|
+
t.status === TASK_STATUS.PENDING ||
|
|
429
|
+
t.status === TASK_STATUS.READY ||
|
|
430
|
+
t.status === TASK_STATUS.IN_PROGRESS
|
|
431
431
|
);
|
|
432
432
|
if (remaining.length === 0) break;
|
|
433
|
-
|
|
433
|
+
|
|
434
434
|
// Check for blocked tasks (dependencies failed)
|
|
435
435
|
for (const task of remaining) {
|
|
436
436
|
const hasFailed = task.dependencies.some(depId => {
|
|
@@ -444,14 +444,16 @@ class PlanningEngine extends EventEmitter {
|
|
|
444
444
|
}
|
|
445
445
|
break;
|
|
446
446
|
}
|
|
447
|
-
|
|
447
|
+
|
|
448
448
|
// Execute batch of ready tasks
|
|
449
449
|
const batch = ready.slice(0, this.maxParallel);
|
|
450
|
-
await Promise.all(
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
450
|
+
await Promise.all(
|
|
451
|
+
batch.map(async task => {
|
|
452
|
+
await this.executeTask(task, executor, plan);
|
|
453
|
+
completed.add(task.id);
|
|
454
|
+
})
|
|
455
|
+
);
|
|
456
|
+
|
|
455
457
|
// Mark newly ready tasks
|
|
456
458
|
for (const task of plan.tasks) {
|
|
457
459
|
if (task.status === TASK_STATUS.PENDING) {
|
|
@@ -463,7 +465,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
463
465
|
}
|
|
464
466
|
}
|
|
465
467
|
}
|
|
466
|
-
|
|
468
|
+
|
|
467
469
|
/**
|
|
468
470
|
* Execute a single task
|
|
469
471
|
* @private
|
|
@@ -471,33 +473,32 @@ class PlanningEngine extends EventEmitter {
|
|
|
471
473
|
async executeTask(task, executor, plan) {
|
|
472
474
|
task.status = TASK_STATUS.IN_PROGRESS;
|
|
473
475
|
const startTime = Date.now();
|
|
474
|
-
|
|
476
|
+
|
|
475
477
|
this.emit('task:start', { taskId: task.id, planId: plan.id, task });
|
|
476
|
-
|
|
478
|
+
|
|
477
479
|
try {
|
|
478
480
|
const result = await executor(task);
|
|
479
481
|
task.result = result;
|
|
480
482
|
task.status = TASK_STATUS.COMPLETED;
|
|
481
483
|
plan.metrics.completedTasks++;
|
|
482
|
-
|
|
484
|
+
|
|
483
485
|
this.emit('task:complete', { taskId: task.id, planId: plan.id, result });
|
|
484
|
-
|
|
486
|
+
|
|
485
487
|
// Check for replanning
|
|
486
488
|
if (this.adaptivePlanning) {
|
|
487
489
|
await this.checkReplan(plan, task);
|
|
488
490
|
}
|
|
489
|
-
|
|
490
491
|
} catch (error) {
|
|
491
492
|
task.result = { error: error.message };
|
|
492
493
|
task.status = TASK_STATUS.FAILED;
|
|
493
494
|
plan.metrics.failedTasks++;
|
|
494
|
-
|
|
495
|
+
|
|
495
496
|
this.emit('task:error', { taskId: task.id, planId: plan.id, error: error.message });
|
|
496
497
|
}
|
|
497
|
-
|
|
498
|
+
|
|
498
499
|
task.actualTime = Date.now() - startTime;
|
|
499
500
|
}
|
|
500
|
-
|
|
501
|
+
|
|
501
502
|
/**
|
|
502
503
|
* Check if replanning is needed
|
|
503
504
|
* @private
|
|
@@ -505,21 +506,23 @@ class PlanningEngine extends EventEmitter {
|
|
|
505
506
|
async checkReplan(plan, completedTask) {
|
|
506
507
|
// Calculate deviation from estimates
|
|
507
508
|
if (!completedTask.actualTime || !completedTask.estimatedTime) return;
|
|
508
|
-
|
|
509
|
-
const deviation =
|
|
510
|
-
|
|
509
|
+
|
|
510
|
+
const deviation =
|
|
511
|
+
Math.abs(completedTask.actualTime - completedTask.estimatedTime) /
|
|
512
|
+
completedTask.estimatedTime;
|
|
513
|
+
|
|
511
514
|
if (deviation > this.replanThreshold) {
|
|
512
|
-
this.emit('plan:replan-trigger', {
|
|
513
|
-
planId: plan.id,
|
|
514
|
-
taskId: completedTask.id,
|
|
515
|
-
deviation
|
|
515
|
+
this.emit('plan:replan-trigger', {
|
|
516
|
+
planId: plan.id,
|
|
517
|
+
taskId: completedTask.id,
|
|
518
|
+
deviation,
|
|
516
519
|
});
|
|
517
|
-
|
|
520
|
+
|
|
518
521
|
// Adjust estimates for remaining tasks
|
|
519
|
-
const remaining = plan.tasks.filter(
|
|
520
|
-
t.status === TASK_STATUS.PENDING || t.status === TASK_STATUS.READY
|
|
522
|
+
const remaining = plan.tasks.filter(
|
|
523
|
+
t => t.status === TASK_STATUS.PENDING || t.status === TASK_STATUS.READY
|
|
521
524
|
);
|
|
522
|
-
|
|
525
|
+
|
|
523
526
|
for (const task of remaining) {
|
|
524
527
|
if (task.metadata.component === completedTask.metadata.component) {
|
|
525
528
|
// Adjust based on actual vs estimated ratio
|
|
@@ -529,7 +532,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
529
532
|
}
|
|
530
533
|
}
|
|
531
534
|
}
|
|
532
|
-
|
|
535
|
+
|
|
533
536
|
/**
|
|
534
537
|
* Pause plan execution
|
|
535
538
|
* @param {string} planId - Plan identifier
|
|
@@ -537,13 +540,13 @@ class PlanningEngine extends EventEmitter {
|
|
|
537
540
|
pausePlan(planId) {
|
|
538
541
|
const plan = this.plans.get(planId);
|
|
539
542
|
if (!plan) throw new Error(`Plan ${planId} not found`);
|
|
540
|
-
|
|
543
|
+
|
|
541
544
|
if (plan.status === PLAN_STATUS.EXECUTING) {
|
|
542
545
|
plan.status = PLAN_STATUS.PAUSED;
|
|
543
546
|
this.emit('plan:paused', { planId });
|
|
544
547
|
}
|
|
545
548
|
}
|
|
546
|
-
|
|
549
|
+
|
|
547
550
|
/**
|
|
548
551
|
* Resume plan execution
|
|
549
552
|
* @param {string} planId - Plan identifier
|
|
@@ -553,15 +556,15 @@ class PlanningEngine extends EventEmitter {
|
|
|
553
556
|
async resumePlan(planId, executor) {
|
|
554
557
|
const plan = this.plans.get(planId);
|
|
555
558
|
if (!plan) throw new Error(`Plan ${planId} not found`);
|
|
556
|
-
|
|
559
|
+
|
|
557
560
|
if (plan.status !== PLAN_STATUS.PAUSED) {
|
|
558
561
|
throw new Error('Plan is not paused');
|
|
559
562
|
}
|
|
560
|
-
|
|
563
|
+
|
|
561
564
|
this.emit('plan:resuming', { planId });
|
|
562
565
|
return this.executePlan(planId, executor);
|
|
563
566
|
}
|
|
564
|
-
|
|
567
|
+
|
|
565
568
|
/**
|
|
566
569
|
* Cancel plan execution
|
|
567
570
|
* @param {string} planId - Plan identifier
|
|
@@ -569,10 +572,10 @@ class PlanningEngine extends EventEmitter {
|
|
|
569
572
|
cancelPlan(planId) {
|
|
570
573
|
const plan = this.plans.get(planId);
|
|
571
574
|
if (!plan) throw new Error(`Plan ${planId} not found`);
|
|
572
|
-
|
|
575
|
+
|
|
573
576
|
plan.status = PLAN_STATUS.CANCELLED;
|
|
574
577
|
plan.completedAt = Date.now();
|
|
575
|
-
|
|
578
|
+
|
|
576
579
|
// Mark pending tasks as skipped
|
|
577
580
|
for (const task of plan.tasks) {
|
|
578
581
|
if (task.status === TASK_STATUS.PENDING || task.status === TASK_STATUS.READY) {
|
|
@@ -580,10 +583,10 @@ class PlanningEngine extends EventEmitter {
|
|
|
580
583
|
plan.metrics.skippedTasks++;
|
|
581
584
|
}
|
|
582
585
|
}
|
|
583
|
-
|
|
586
|
+
|
|
584
587
|
this.emit('plan:cancelled', { planId });
|
|
585
588
|
}
|
|
586
|
-
|
|
589
|
+
|
|
587
590
|
/**
|
|
588
591
|
* Add task to existing plan
|
|
589
592
|
* @param {string} planId - Plan identifier
|
|
@@ -593,7 +596,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
593
596
|
addTask(planId, taskDef) {
|
|
594
597
|
const plan = this.plans.get(planId);
|
|
595
598
|
if (!plan) throw new Error(`Plan ${planId} not found`);
|
|
596
|
-
|
|
599
|
+
|
|
597
600
|
const task = {
|
|
598
601
|
id: this.generateId('task'),
|
|
599
602
|
name: taskDef.name,
|
|
@@ -605,9 +608,9 @@ class PlanningEngine extends EventEmitter {
|
|
|
605
608
|
estimatedTime: taskDef.estimatedTime || 5000,
|
|
606
609
|
actualTime: null,
|
|
607
610
|
result: null,
|
|
608
|
-
metadata: taskDef.metadata || {}
|
|
611
|
+
metadata: taskDef.metadata || {},
|
|
609
612
|
};
|
|
610
|
-
|
|
613
|
+
|
|
611
614
|
// Insert at appropriate position based on dependencies
|
|
612
615
|
if (taskDef.after) {
|
|
613
616
|
const afterIndex = plan.tasks.findIndex(t => t.id === taskDef.after);
|
|
@@ -620,15 +623,15 @@ class PlanningEngine extends EventEmitter {
|
|
|
620
623
|
} else {
|
|
621
624
|
plan.tasks.push(task);
|
|
622
625
|
}
|
|
623
|
-
|
|
626
|
+
|
|
624
627
|
plan.metrics.totalTasks++;
|
|
625
628
|
plan.metrics.totalEstimatedTime += task.estimatedTime;
|
|
626
|
-
|
|
629
|
+
|
|
627
630
|
this.emit('task:added', { planId, task });
|
|
628
|
-
|
|
631
|
+
|
|
629
632
|
return task;
|
|
630
633
|
}
|
|
631
|
-
|
|
634
|
+
|
|
632
635
|
/**
|
|
633
636
|
* Remove task from plan
|
|
634
637
|
* @param {string} planId - Plan identifier
|
|
@@ -637,24 +640,24 @@ class PlanningEngine extends EventEmitter {
|
|
|
637
640
|
removeTask(planId, taskId) {
|
|
638
641
|
const plan = this.plans.get(planId);
|
|
639
642
|
if (!plan) throw new Error(`Plan ${planId} not found`);
|
|
640
|
-
|
|
643
|
+
|
|
641
644
|
const index = plan.tasks.findIndex(t => t.id === taskId);
|
|
642
645
|
if (index < 0) throw new Error(`Task ${taskId} not found`);
|
|
643
|
-
|
|
646
|
+
|
|
644
647
|
const task = plan.tasks[index];
|
|
645
|
-
|
|
648
|
+
|
|
646
649
|
// Remove from other tasks' dependencies
|
|
647
650
|
for (const t of plan.tasks) {
|
|
648
651
|
t.dependencies = t.dependencies.filter(d => d !== taskId);
|
|
649
652
|
}
|
|
650
|
-
|
|
653
|
+
|
|
651
654
|
plan.tasks.splice(index, 1);
|
|
652
655
|
plan.metrics.totalTasks--;
|
|
653
656
|
plan.metrics.totalEstimatedTime -= task.estimatedTime;
|
|
654
|
-
|
|
657
|
+
|
|
655
658
|
this.emit('task:removed', { planId, taskId });
|
|
656
659
|
}
|
|
657
|
-
|
|
660
|
+
|
|
658
661
|
/**
|
|
659
662
|
* Get plan by ID
|
|
660
663
|
* @param {string} planId - Plan identifier
|
|
@@ -663,7 +666,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
663
666
|
getPlan(planId) {
|
|
664
667
|
return this.plans.get(planId) || null;
|
|
665
668
|
}
|
|
666
|
-
|
|
669
|
+
|
|
667
670
|
/**
|
|
668
671
|
* Get all plans
|
|
669
672
|
* @returns {Plan[]}
|
|
@@ -671,7 +674,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
671
674
|
getAllPlans() {
|
|
672
675
|
return Array.from(this.plans.values());
|
|
673
676
|
}
|
|
674
|
-
|
|
677
|
+
|
|
675
678
|
/**
|
|
676
679
|
* Get plan progress
|
|
677
680
|
* @param {string} planId - Plan identifier
|
|
@@ -680,14 +683,14 @@ class PlanningEngine extends EventEmitter {
|
|
|
680
683
|
getProgress(planId) {
|
|
681
684
|
const plan = this.plans.get(planId);
|
|
682
685
|
if (!plan) return null;
|
|
683
|
-
|
|
686
|
+
|
|
684
687
|
const total = plan.metrics.totalTasks;
|
|
685
688
|
const completed = plan.metrics.completedTasks;
|
|
686
689
|
const failed = plan.metrics.failedTasks;
|
|
687
690
|
const skipped = plan.metrics.skippedTasks;
|
|
688
691
|
const inProgress = plan.tasks.filter(t => t.status === TASK_STATUS.IN_PROGRESS).length;
|
|
689
692
|
const pending = total - completed - failed - skipped - inProgress;
|
|
690
|
-
|
|
693
|
+
|
|
691
694
|
return {
|
|
692
695
|
total,
|
|
693
696
|
completed,
|
|
@@ -698,10 +701,10 @@ class PlanningEngine extends EventEmitter {
|
|
|
698
701
|
percentage: total > 0 ? Math.round((completed / total) * 100) : 0,
|
|
699
702
|
estimatedRemaining: plan.tasks
|
|
700
703
|
.filter(t => t.status === TASK_STATUS.PENDING || t.status === TASK_STATUS.READY)
|
|
701
|
-
.reduce((sum, t) => sum + t.estimatedTime, 0)
|
|
704
|
+
.reduce((sum, t) => sum + t.estimatedTime, 0),
|
|
702
705
|
};
|
|
703
706
|
}
|
|
704
|
-
|
|
707
|
+
|
|
705
708
|
/**
|
|
706
709
|
* Get dependency graph
|
|
707
710
|
* @param {string} planId - Plan identifier
|
|
@@ -710,24 +713,24 @@ class PlanningEngine extends EventEmitter {
|
|
|
710
713
|
getDependencyGraph(planId) {
|
|
711
714
|
const plan = this.plans.get(planId);
|
|
712
715
|
if (!plan) return null;
|
|
713
|
-
|
|
716
|
+
|
|
714
717
|
const nodes = plan.tasks.map(t => ({
|
|
715
718
|
id: t.id,
|
|
716
719
|
name: t.name,
|
|
717
720
|
status: t.status,
|
|
718
|
-
priority: t.priority
|
|
721
|
+
priority: t.priority,
|
|
719
722
|
}));
|
|
720
|
-
|
|
723
|
+
|
|
721
724
|
const edges = [];
|
|
722
725
|
for (const task of plan.tasks) {
|
|
723
726
|
for (const dep of task.dependencies) {
|
|
724
727
|
edges.push({ from: dep, to: task.id });
|
|
725
728
|
}
|
|
726
729
|
}
|
|
727
|
-
|
|
730
|
+
|
|
728
731
|
return { nodes, edges };
|
|
729
732
|
}
|
|
730
|
-
|
|
733
|
+
|
|
731
734
|
/**
|
|
732
735
|
* Generate unique ID
|
|
733
736
|
* @private
|
|
@@ -735,7 +738,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
735
738
|
generateId(prefix) {
|
|
736
739
|
return `${prefix}-${++this.taskCounter}-${Date.now().toString(36)}`;
|
|
737
740
|
}
|
|
738
|
-
|
|
741
|
+
|
|
739
742
|
/**
|
|
740
743
|
* Clear all plans
|
|
741
744
|
*/
|
|
@@ -744,7 +747,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
744
747
|
this.activePlan = null;
|
|
745
748
|
this.taskCounter = 0;
|
|
746
749
|
}
|
|
747
|
-
|
|
750
|
+
|
|
748
751
|
/**
|
|
749
752
|
* Export plan to readable format
|
|
750
753
|
* @param {string} planId - Plan identifier
|
|
@@ -753,14 +756,14 @@ class PlanningEngine extends EventEmitter {
|
|
|
753
756
|
exportPlan(planId) {
|
|
754
757
|
const plan = this.plans.get(planId);
|
|
755
758
|
if (!plan) return '';
|
|
756
|
-
|
|
759
|
+
|
|
757
760
|
let output = `# Plan: ${plan.goal}\n\n`;
|
|
758
761
|
output += `**ID:** ${plan.id}\n`;
|
|
759
762
|
output += `**Status:** ${plan.status}\n`;
|
|
760
763
|
output += `**Created:** ${new Date(plan.createdAt).toISOString()}\n\n`;
|
|
761
|
-
|
|
764
|
+
|
|
762
765
|
output += `## Tasks (${plan.metrics.totalTasks})\n\n`;
|
|
763
|
-
|
|
766
|
+
|
|
764
767
|
for (let i = 0; i < plan.tasks.length; i++) {
|
|
765
768
|
const task = plan.tasks[i];
|
|
766
769
|
const statusIcon = this.getStatusIcon(task.status);
|
|
@@ -771,7 +774,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
771
774
|
}
|
|
772
775
|
output += `\n`;
|
|
773
776
|
}
|
|
774
|
-
|
|
777
|
+
|
|
775
778
|
output += `## Metrics\n\n`;
|
|
776
779
|
output += `- Completed: ${plan.metrics.completedTasks}\n`;
|
|
777
780
|
output += `- Failed: ${plan.metrics.failedTasks}\n`;
|
|
@@ -779,10 +782,10 @@ class PlanningEngine extends EventEmitter {
|
|
|
779
782
|
if (plan.metrics.actualTime) {
|
|
780
783
|
output += `- Total Time: ${plan.metrics.actualTime}ms\n`;
|
|
781
784
|
}
|
|
782
|
-
|
|
785
|
+
|
|
783
786
|
return output;
|
|
784
787
|
}
|
|
785
|
-
|
|
788
|
+
|
|
786
789
|
/**
|
|
787
790
|
* Get status icon
|
|
788
791
|
* @private
|
|
@@ -795,7 +798,7 @@ class PlanningEngine extends EventEmitter {
|
|
|
795
798
|
[TASK_STATUS.BLOCKED]: '🚫',
|
|
796
799
|
[TASK_STATUS.COMPLETED]: '✅',
|
|
797
800
|
[TASK_STATUS.FAILED]: '❌',
|
|
798
|
-
[TASK_STATUS.SKIPPED]: '⏭️'
|
|
801
|
+
[TASK_STATUS.SKIPPED]: '⏭️',
|
|
799
802
|
};
|
|
800
803
|
return icons[status] || '•';
|
|
801
804
|
}
|
|
@@ -827,5 +830,5 @@ module.exports = {
|
|
|
827
830
|
createPlan,
|
|
828
831
|
PLAN_STATUS,
|
|
829
832
|
TASK_STATUS,
|
|
830
|
-
PRIORITY
|
|
833
|
+
PRIORITY,
|
|
831
834
|
};
|