@weavelogic/knowledge-graph-agent 0.11.8 → 0.12.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/dist/claude/hook-capture.d.ts +1 -0
- package/dist/claude/hook-capture.d.ts.map +1 -1
- package/dist/claude/hook-capture.js +24 -8
- package/dist/claude/hook-capture.js.map +1 -1
- package/dist/cli/commands/sparc.d.ts +14 -0
- package/dist/cli/commands/sparc.d.ts.map +1 -0
- package/dist/cli/commands/sparc.js +262 -0
- package/dist/cli/commands/sparc.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +7 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/node_modules/@typescript-eslint/project-service/dist/index.js +1 -1
- package/dist/node_modules/tinyglobby/dist/index.js +1 -1
- package/dist/sparc/consensus.d.ts +149 -0
- package/dist/sparc/consensus.d.ts.map +1 -0
- package/dist/sparc/consensus.js +356 -0
- package/dist/sparc/consensus.js.map +1 -0
- package/dist/sparc/decision-log.d.ts +131 -0
- package/dist/sparc/decision-log.d.ts.map +1 -0
- package/dist/sparc/decision-log.js +325 -0
- package/dist/sparc/decision-log.js.map +1 -0
- package/dist/sparc/index.d.ts +14 -0
- package/dist/sparc/index.d.ts.map +1 -0
- package/dist/sparc/index.js +15 -0
- package/dist/sparc/index.js.map +1 -0
- package/dist/sparc/review-process.d.ts +72 -0
- package/dist/sparc/review-process.d.ts.map +1 -0
- package/dist/sparc/review-process.js +609 -0
- package/dist/sparc/review-process.js.map +1 -0
- package/dist/sparc/sparc-planner.d.ts +144 -0
- package/dist/sparc/sparc-planner.d.ts.map +1 -0
- package/dist/sparc/sparc-planner.js +757 -0
- package/dist/sparc/sparc-planner.js.map +1 -0
- package/dist/sparc/types.d.ts +664 -0
- package/dist/sparc/types.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, readFileSync } from "fs";
|
|
2
|
+
import { join, extname, relative } from "path";
|
|
3
|
+
import { createLogger } from "../utils/logger.js";
|
|
4
|
+
import { createDecisionLogManager } from "./decision-log.js";
|
|
5
|
+
import { createConsensusBuilder, ConsensusBuilder } from "./consensus.js";
|
|
6
|
+
import { createReviewProcess } from "./review-process.js";
|
|
7
|
+
const logger = createLogger("sparc-planner");
|
|
8
|
+
class SPARCPlanner {
|
|
9
|
+
options;
|
|
10
|
+
plan;
|
|
11
|
+
decisionLog;
|
|
12
|
+
consensusBuilder;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = {
|
|
15
|
+
outputDir: join(options.projectRoot, ".sparc"),
|
|
16
|
+
parallelResearch: true,
|
|
17
|
+
reviewPasses: 3,
|
|
18
|
+
autoConsensus: true,
|
|
19
|
+
kgEnabled: true,
|
|
20
|
+
vectorEnabled: true,
|
|
21
|
+
...options
|
|
22
|
+
};
|
|
23
|
+
this.plan = this.initializePlan();
|
|
24
|
+
this.decisionLog = createDecisionLogManager({
|
|
25
|
+
outputDir: this.options.outputDir,
|
|
26
|
+
planId: this.plan.id
|
|
27
|
+
});
|
|
28
|
+
this.consensusBuilder = createConsensusBuilder({
|
|
29
|
+
defaultThreshold: 0.67,
|
|
30
|
+
method: "majority"
|
|
31
|
+
});
|
|
32
|
+
logger.info("SPARC Planner initialized", {
|
|
33
|
+
planId: this.plan.id,
|
|
34
|
+
projectRoot: this.options.projectRoot
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Initialize a new plan
|
|
39
|
+
*/
|
|
40
|
+
initializePlan() {
|
|
41
|
+
const now = /* @__PURE__ */ new Date();
|
|
42
|
+
const id = `plan_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
name: this.options.name,
|
|
46
|
+
description: this.options.description,
|
|
47
|
+
status: "draft",
|
|
48
|
+
currentPhase: "specification",
|
|
49
|
+
projectRoot: this.options.projectRoot,
|
|
50
|
+
outputDir: this.options.outputDir,
|
|
51
|
+
tasks: [],
|
|
52
|
+
parallelGroups: [],
|
|
53
|
+
criticalPath: [],
|
|
54
|
+
executionOrder: [],
|
|
55
|
+
researchFindings: [],
|
|
56
|
+
decisionLog: {
|
|
57
|
+
id: `dlog_${id}`,
|
|
58
|
+
planId: id,
|
|
59
|
+
decisions: [],
|
|
60
|
+
statistics: {
|
|
61
|
+
total: 0,
|
|
62
|
+
approved: 0,
|
|
63
|
+
rejected: 0,
|
|
64
|
+
deferred: 0,
|
|
65
|
+
highConfidence: 0,
|
|
66
|
+
lowConfidence: 0,
|
|
67
|
+
consensusRequired: 0
|
|
68
|
+
},
|
|
69
|
+
createdAt: now,
|
|
70
|
+
updatedAt: now
|
|
71
|
+
},
|
|
72
|
+
createdAt: now,
|
|
73
|
+
updatedAt: now,
|
|
74
|
+
version: "1.0.0",
|
|
75
|
+
author: "sparc-planner",
|
|
76
|
+
statistics: {
|
|
77
|
+
totalTasks: 0,
|
|
78
|
+
completedTasks: 0,
|
|
79
|
+
parallelizableTasks: 0,
|
|
80
|
+
estimatedHours: 0,
|
|
81
|
+
researchFindings: 0,
|
|
82
|
+
decisions: 0,
|
|
83
|
+
kgNodes: 0
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Execute the full planning process
|
|
89
|
+
*/
|
|
90
|
+
async executePlanning() {
|
|
91
|
+
logger.info("Starting SPARC planning process", { planId: this.plan.id });
|
|
92
|
+
try {
|
|
93
|
+
this.plan.status = "researching";
|
|
94
|
+
await this.executeResearchPhase();
|
|
95
|
+
this.plan.status = "planning";
|
|
96
|
+
await this.executeSpecificationPhase();
|
|
97
|
+
await this.executePseudocodePhase();
|
|
98
|
+
await this.executeArchitecturePhase();
|
|
99
|
+
await this.executeRefinementPhase();
|
|
100
|
+
this.plan.status = "reviewing";
|
|
101
|
+
const reviewResult = await this.executeReviewPhase();
|
|
102
|
+
this.plan.reviewResult = reviewResult;
|
|
103
|
+
if (reviewResult.overallStatus === "approved") {
|
|
104
|
+
this.plan.status = "approved";
|
|
105
|
+
} else if (reviewResult.overallStatus === "rejected") {
|
|
106
|
+
this.plan.status = "failed";
|
|
107
|
+
} else {
|
|
108
|
+
this.plan.status = "planning";
|
|
109
|
+
}
|
|
110
|
+
this.updateStatistics();
|
|
111
|
+
this.savePlan();
|
|
112
|
+
logger.info("SPARC planning completed", {
|
|
113
|
+
planId: this.plan.id,
|
|
114
|
+
status: this.plan.status,
|
|
115
|
+
tasks: this.plan.tasks.length
|
|
116
|
+
});
|
|
117
|
+
return this.plan;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
this.plan.status = "failed";
|
|
120
|
+
logger.error("SPARC planning failed", error instanceof Error ? error : new Error(String(error)));
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Execute research phase
|
|
126
|
+
*/
|
|
127
|
+
async executeResearchPhase() {
|
|
128
|
+
logger.info("Executing research phase");
|
|
129
|
+
this.plan.currentPhase = "specification";
|
|
130
|
+
const srcPath = join(this.options.projectRoot, "src");
|
|
131
|
+
if (existsSync(srcPath)) {
|
|
132
|
+
this.plan.existingCode = await this.analyzeExistingCode(srcPath);
|
|
133
|
+
this.addDecision(
|
|
134
|
+
"Existing Code Integration",
|
|
135
|
+
"Integrate with existing codebase in src/",
|
|
136
|
+
"specification",
|
|
137
|
+
"high",
|
|
138
|
+
"Existing code found and analyzed for patterns and integration points",
|
|
139
|
+
["Start from scratch", "Partial rewrite", "Full integration"]
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const researchTasks = this.defineResearchTasks();
|
|
143
|
+
for (const task of researchTasks) {
|
|
144
|
+
const finding = await this.executeResearchTask(task);
|
|
145
|
+
this.plan.researchFindings.push(finding);
|
|
146
|
+
}
|
|
147
|
+
logger.info("Research phase completed", {
|
|
148
|
+
findings: this.plan.researchFindings.length,
|
|
149
|
+
hasExistingCode: !!this.plan.existingCode
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Analyze existing code in src directory
|
|
154
|
+
*/
|
|
155
|
+
async analyzeExistingCode(srcPath) {
|
|
156
|
+
const analysis = {
|
|
157
|
+
hasSrcDirectory: true,
|
|
158
|
+
srcPath,
|
|
159
|
+
fileCount: 0,
|
|
160
|
+
languages: {},
|
|
161
|
+
keyFiles: [],
|
|
162
|
+
patterns: [],
|
|
163
|
+
dependencies: [],
|
|
164
|
+
entryPoints: []
|
|
165
|
+
};
|
|
166
|
+
const analyzeDir = (dir) => {
|
|
167
|
+
const entries = readdirSync(dir);
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
const fullPath = join(dir, entry);
|
|
170
|
+
const stat = statSync(fullPath);
|
|
171
|
+
if (stat.isDirectory()) {
|
|
172
|
+
if (!entry.startsWith(".") && entry !== "node_modules") {
|
|
173
|
+
analyzeDir(fullPath);
|
|
174
|
+
}
|
|
175
|
+
} else if (stat.isFile()) {
|
|
176
|
+
analysis.fileCount++;
|
|
177
|
+
const ext = extname(entry);
|
|
178
|
+
analysis.languages[ext] = (analysis.languages[ext] || 0) + 1;
|
|
179
|
+
if (entry === "index.ts" || entry === "index.js") {
|
|
180
|
+
analysis.entryPoints.push(relative(this.options.projectRoot, fullPath));
|
|
181
|
+
}
|
|
182
|
+
if (entry === "package.json") {
|
|
183
|
+
try {
|
|
184
|
+
const pkg = JSON.parse(readFileSync(fullPath, "utf-8"));
|
|
185
|
+
analysis.dependencies = Object.keys(pkg.dependencies || {});
|
|
186
|
+
} catch {
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
analyzeDir(srcPath);
|
|
193
|
+
if (analysis.languages[".ts"] > 0 || analysis.languages[".tsx"] > 0) {
|
|
194
|
+
analysis.patterns.push("TypeScript");
|
|
195
|
+
}
|
|
196
|
+
if (existsSync(join(this.options.projectRoot, "tests")) || existsSync(join(this.options.projectRoot, "__tests__"))) {
|
|
197
|
+
analysis.patterns.push("Test-Driven Development");
|
|
198
|
+
analysis.testCoverage = { hasTests: true };
|
|
199
|
+
}
|
|
200
|
+
return analysis;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Define research tasks
|
|
204
|
+
*/
|
|
205
|
+
defineResearchTasks() {
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
id: "research-requirements",
|
|
209
|
+
agentType: "researcher",
|
|
210
|
+
description: "Research and analyze project requirements",
|
|
211
|
+
topics: ["functional requirements", "non-functional requirements", "constraints"],
|
|
212
|
+
context: [this.options.description]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "research-patterns",
|
|
216
|
+
agentType: "researcher",
|
|
217
|
+
description: "Research applicable design patterns",
|
|
218
|
+
topics: ["design patterns", "architecture patterns", "best practices"],
|
|
219
|
+
context: this.plan.existingCode?.patterns || []
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: "research-technology",
|
|
223
|
+
agentType: "researcher",
|
|
224
|
+
description: "Research technology choices and alternatives",
|
|
225
|
+
topics: ["technology stack", "frameworks", "libraries"],
|
|
226
|
+
context: this.plan.existingCode?.dependencies || []
|
|
227
|
+
}
|
|
228
|
+
];
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Execute a research task (stub - would spawn agent)
|
|
232
|
+
*/
|
|
233
|
+
async executeResearchTask(task) {
|
|
234
|
+
return {
|
|
235
|
+
id: `finding_${task.id}`,
|
|
236
|
+
agent: task.agentType,
|
|
237
|
+
topic: task.topics[0],
|
|
238
|
+
summary: `Research findings for ${task.description}`,
|
|
239
|
+
details: `Detailed research results for topics: ${task.topics.join(", ")}`,
|
|
240
|
+
confidence: "medium",
|
|
241
|
+
evidence: task.context,
|
|
242
|
+
relatedFindings: [],
|
|
243
|
+
kgReferences: [],
|
|
244
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Execute specification phase
|
|
249
|
+
*/
|
|
250
|
+
async executeSpecificationPhase() {
|
|
251
|
+
logger.info("Executing specification phase");
|
|
252
|
+
this.plan.currentPhase = "specification";
|
|
253
|
+
const spec = {
|
|
254
|
+
id: `spec_${this.plan.id}`,
|
|
255
|
+
projectName: this.options.name,
|
|
256
|
+
version: "1.0.0",
|
|
257
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
258
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
259
|
+
summary: this.options.description,
|
|
260
|
+
problemStatement: this.extractProblemStatement(),
|
|
261
|
+
goals: this.extractGoals(),
|
|
262
|
+
requirements: this.generateRequirements(),
|
|
263
|
+
features: this.generateFeatures(),
|
|
264
|
+
constraints: this.extractConstraints(),
|
|
265
|
+
assumptions: [],
|
|
266
|
+
outOfScope: [],
|
|
267
|
+
successMetrics: this.generateSuccessMetrics(),
|
|
268
|
+
kgReferences: []
|
|
269
|
+
};
|
|
270
|
+
this.plan.specification = spec;
|
|
271
|
+
this.addDecision(
|
|
272
|
+
"Requirements Definition",
|
|
273
|
+
`Defined ${spec.requirements.length} requirements and ${spec.features.length} features`,
|
|
274
|
+
"specification",
|
|
275
|
+
"high",
|
|
276
|
+
"Requirements derived from research findings and project description"
|
|
277
|
+
);
|
|
278
|
+
logger.info("Specification phase completed", {
|
|
279
|
+
requirements: spec.requirements.length,
|
|
280
|
+
features: spec.features.length
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Execute pseudocode phase
|
|
285
|
+
*/
|
|
286
|
+
async executePseudocodePhase() {
|
|
287
|
+
logger.info("Executing pseudocode phase");
|
|
288
|
+
this.plan.currentPhase = "pseudocode";
|
|
289
|
+
const algorithms = [];
|
|
290
|
+
for (const feature of this.plan.specification?.features || []) {
|
|
291
|
+
const algorithm = this.generateAlgorithmDesign(feature);
|
|
292
|
+
algorithms.push(algorithm);
|
|
293
|
+
}
|
|
294
|
+
this.plan.algorithms = algorithms;
|
|
295
|
+
logger.info("Pseudocode phase completed", {
|
|
296
|
+
algorithms: algorithms.length
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Execute architecture phase
|
|
301
|
+
*/
|
|
302
|
+
async executeArchitecturePhase() {
|
|
303
|
+
logger.info("Executing architecture phase");
|
|
304
|
+
this.plan.currentPhase = "architecture";
|
|
305
|
+
const arch = {
|
|
306
|
+
id: `arch_${this.plan.id}`,
|
|
307
|
+
version: "1.0.0",
|
|
308
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
309
|
+
overview: this.generateArchitectureOverview(),
|
|
310
|
+
patterns: this.identifyArchitecturePatterns(),
|
|
311
|
+
components: this.generateComponents(),
|
|
312
|
+
decisions: [],
|
|
313
|
+
dataFlow: this.describeDataFlow(),
|
|
314
|
+
securityConsiderations: this.identifySecurityConsiderations(),
|
|
315
|
+
scalabilityConsiderations: [],
|
|
316
|
+
diagrams: []
|
|
317
|
+
};
|
|
318
|
+
this.plan.architecture = arch;
|
|
319
|
+
this.addDecision(
|
|
320
|
+
"Architecture Design",
|
|
321
|
+
`Defined ${arch.components.length} components using ${arch.patterns.join(", ")} patterns`,
|
|
322
|
+
"architecture",
|
|
323
|
+
"medium",
|
|
324
|
+
"Architecture designed based on requirements and existing patterns",
|
|
325
|
+
["Microservices", "Monolith", "Modular monolith"]
|
|
326
|
+
);
|
|
327
|
+
logger.info("Architecture phase completed", {
|
|
328
|
+
components: arch.components.length,
|
|
329
|
+
patterns: arch.patterns.length
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Execute refinement phase (task breakdown)
|
|
334
|
+
*/
|
|
335
|
+
async executeRefinementPhase() {
|
|
336
|
+
logger.info("Executing refinement phase");
|
|
337
|
+
this.plan.currentPhase = "refinement";
|
|
338
|
+
const tasks = [];
|
|
339
|
+
tasks.push(this.createTask(
|
|
340
|
+
"Research and Analysis",
|
|
341
|
+
"Comprehensive research on project requirements and patterns",
|
|
342
|
+
"specification",
|
|
343
|
+
"research",
|
|
344
|
+
"high",
|
|
345
|
+
4
|
|
346
|
+
));
|
|
347
|
+
for (const component of this.plan.architecture?.components || []) {
|
|
348
|
+
tasks.push(this.createTask(
|
|
349
|
+
`Implement ${component.name}`,
|
|
350
|
+
`Implement the ${component.name} component: ${component.description}`,
|
|
351
|
+
"refinement",
|
|
352
|
+
"implementation",
|
|
353
|
+
this.getComponentPriority(component),
|
|
354
|
+
this.estimateComponentHours(component)
|
|
355
|
+
));
|
|
356
|
+
}
|
|
357
|
+
tasks.push(this.createTask(
|
|
358
|
+
"Unit Testing",
|
|
359
|
+
"Create comprehensive unit tests for all components",
|
|
360
|
+
"refinement",
|
|
361
|
+
"testing",
|
|
362
|
+
"high",
|
|
363
|
+
8
|
|
364
|
+
));
|
|
365
|
+
tasks.push(this.createTask(
|
|
366
|
+
"Integration Testing",
|
|
367
|
+
"Create integration tests for component interactions",
|
|
368
|
+
"refinement",
|
|
369
|
+
"testing",
|
|
370
|
+
"medium",
|
|
371
|
+
6
|
|
372
|
+
));
|
|
373
|
+
tasks.push(this.createTask(
|
|
374
|
+
"API Documentation",
|
|
375
|
+
"Document all public APIs and interfaces",
|
|
376
|
+
"completion",
|
|
377
|
+
"documentation",
|
|
378
|
+
"medium",
|
|
379
|
+
4
|
|
380
|
+
));
|
|
381
|
+
this.plan.tasks = tasks;
|
|
382
|
+
this.calculateParallelGroups();
|
|
383
|
+
this.calculateCriticalPath();
|
|
384
|
+
logger.info("Refinement phase completed", {
|
|
385
|
+
tasks: tasks.length,
|
|
386
|
+
parallelGroups: this.plan.parallelGroups.length
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Execute review phase
|
|
391
|
+
*/
|
|
392
|
+
async executeReviewPhase() {
|
|
393
|
+
logger.info("Executing review phase");
|
|
394
|
+
this.plan.currentPhase = "completion";
|
|
395
|
+
this.plan.decisionLog = this.decisionLog.getLog();
|
|
396
|
+
const reviewProcess = createReviewProcess({
|
|
397
|
+
plan: this.plan,
|
|
398
|
+
passes: this.options.reviewPasses,
|
|
399
|
+
autoFix: false,
|
|
400
|
+
strictMode: false
|
|
401
|
+
});
|
|
402
|
+
const result = await reviewProcess.executeReview();
|
|
403
|
+
logger.info("Review phase completed", {
|
|
404
|
+
status: result.overallStatus,
|
|
405
|
+
totalFindings: result.totalFindings,
|
|
406
|
+
criticalFindings: result.criticalFindings
|
|
407
|
+
});
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Add a decision to the log
|
|
412
|
+
*/
|
|
413
|
+
addDecision(title, description, phase, confidence, rationale, alternatives) {
|
|
414
|
+
const decision = this.decisionLog.addDecision({
|
|
415
|
+
title,
|
|
416
|
+
description,
|
|
417
|
+
phase,
|
|
418
|
+
confidence,
|
|
419
|
+
rationale,
|
|
420
|
+
alternatives,
|
|
421
|
+
decidedBy: "sparc-planner"
|
|
422
|
+
});
|
|
423
|
+
if (this.options.autoConsensus && ConsensusBuilder.needsConsensus(confidence)) {
|
|
424
|
+
logger.info("Building consensus for low-confidence decision", {
|
|
425
|
+
decisionId: decision.id,
|
|
426
|
+
confidence
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Create a SPARC task
|
|
432
|
+
*/
|
|
433
|
+
createTask(name, description, phase, type, priority, estimatedHours) {
|
|
434
|
+
return {
|
|
435
|
+
id: `task_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
436
|
+
name,
|
|
437
|
+
description,
|
|
438
|
+
phase,
|
|
439
|
+
type,
|
|
440
|
+
priority,
|
|
441
|
+
estimatedHours,
|
|
442
|
+
dependencies: [],
|
|
443
|
+
parallelizable: type === "implementation" || type === "testing",
|
|
444
|
+
status: "pending",
|
|
445
|
+
contextLinks: [],
|
|
446
|
+
kgReferences: []
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Calculate parallel task groups
|
|
451
|
+
*/
|
|
452
|
+
calculateParallelGroups() {
|
|
453
|
+
const parallelizable = this.plan.tasks.filter((t) => t.parallelizable);
|
|
454
|
+
const groups = [];
|
|
455
|
+
const phases = ["specification", "pseudocode", "architecture", "refinement", "completion"];
|
|
456
|
+
for (const phase of phases) {
|
|
457
|
+
const phaseTasks = parallelizable.filter((t) => t.phase === phase);
|
|
458
|
+
if (phaseTasks.length > 0) {
|
|
459
|
+
groups.push(phaseTasks.map((t) => t.id));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
this.plan.parallelGroups = groups;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Calculate critical path
|
|
466
|
+
*/
|
|
467
|
+
calculateCriticalPath() {
|
|
468
|
+
const critical = this.plan.tasks.filter((t) => t.priority === "critical" || t.priority === "high").sort((a, b) => {
|
|
469
|
+
const phaseOrder = ["specification", "pseudocode", "architecture", "refinement", "completion"];
|
|
470
|
+
return phaseOrder.indexOf(a.phase) - phaseOrder.indexOf(b.phase);
|
|
471
|
+
}).map((t) => t.id);
|
|
472
|
+
this.plan.criticalPath = critical;
|
|
473
|
+
this.plan.executionOrder = this.plan.tasks.map((t) => t.id);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Update plan statistics
|
|
477
|
+
*/
|
|
478
|
+
updateStatistics() {
|
|
479
|
+
this.plan.statistics = {
|
|
480
|
+
totalTasks: this.plan.tasks.length,
|
|
481
|
+
completedTasks: this.plan.tasks.filter((t) => t.status === "completed").length,
|
|
482
|
+
parallelizableTasks: this.plan.tasks.filter((t) => t.parallelizable).length,
|
|
483
|
+
estimatedHours: this.plan.tasks.reduce((sum, t) => sum + t.estimatedHours, 0),
|
|
484
|
+
researchFindings: this.plan.researchFindings.length,
|
|
485
|
+
decisions: this.decisionLog.getDecisions().length,
|
|
486
|
+
kgNodes: this.plan.tasks.reduce((sum, t) => sum + (t.kgReferences?.length || 0), 0)
|
|
487
|
+
};
|
|
488
|
+
this.plan.updatedAt = /* @__PURE__ */ new Date();
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Save plan to disk
|
|
492
|
+
*/
|
|
493
|
+
savePlan() {
|
|
494
|
+
const dir = this.options.outputDir;
|
|
495
|
+
if (!existsSync(dir)) {
|
|
496
|
+
mkdirSync(dir, { recursive: true });
|
|
497
|
+
}
|
|
498
|
+
const planPath = join(dir, "sparc-plan.json");
|
|
499
|
+
writeFileSync(planPath, JSON.stringify(this.plan, null, 2));
|
|
500
|
+
const mdPath = join(dir, "sparc-plan.md");
|
|
501
|
+
writeFileSync(mdPath, this.generateMarkdownSummary());
|
|
502
|
+
this.decisionLog.save();
|
|
503
|
+
this.decisionLog.saveMarkdown();
|
|
504
|
+
logger.info("Plan saved", { dir });
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Generate markdown summary
|
|
508
|
+
*/
|
|
509
|
+
generateMarkdownSummary() {
|
|
510
|
+
const lines = [
|
|
511
|
+
`# SPARC Plan: ${this.plan.name}`,
|
|
512
|
+
"",
|
|
513
|
+
`**Status:** ${this.plan.status}`,
|
|
514
|
+
`**Version:** ${this.plan.version}`,
|
|
515
|
+
`**Created:** ${this.plan.createdAt.toISOString()}`,
|
|
516
|
+
"",
|
|
517
|
+
"## Summary",
|
|
518
|
+
"",
|
|
519
|
+
this.plan.description,
|
|
520
|
+
"",
|
|
521
|
+
"## Statistics",
|
|
522
|
+
"",
|
|
523
|
+
`| Metric | Value |`,
|
|
524
|
+
`|--------|-------|`,
|
|
525
|
+
`| Total Tasks | ${this.plan.statistics.totalTasks} |`,
|
|
526
|
+
`| Parallelizable | ${this.plan.statistics.parallelizableTasks} |`,
|
|
527
|
+
`| Estimated Hours | ${this.plan.statistics.estimatedHours} |`,
|
|
528
|
+
`| Research Findings | ${this.plan.statistics.researchFindings} |`,
|
|
529
|
+
`| Decisions | ${this.plan.statistics.decisions} |`,
|
|
530
|
+
""
|
|
531
|
+
];
|
|
532
|
+
if (this.plan.specification) {
|
|
533
|
+
lines.push("## Specification");
|
|
534
|
+
lines.push("");
|
|
535
|
+
lines.push(`- **Requirements:** ${this.plan.specification.requirements.length}`);
|
|
536
|
+
lines.push(`- **Features:** ${this.plan.specification.features.length}`);
|
|
537
|
+
lines.push("");
|
|
538
|
+
}
|
|
539
|
+
if (this.plan.architecture) {
|
|
540
|
+
lines.push("## Architecture");
|
|
541
|
+
lines.push("");
|
|
542
|
+
lines.push(`- **Components:** ${this.plan.architecture.components.length}`);
|
|
543
|
+
lines.push(`- **Patterns:** ${this.plan.architecture.patterns.join(", ")}`);
|
|
544
|
+
lines.push("");
|
|
545
|
+
}
|
|
546
|
+
lines.push("## Tasks");
|
|
547
|
+
lines.push("");
|
|
548
|
+
for (const task of this.plan.tasks) {
|
|
549
|
+
lines.push(`### ${task.name}`);
|
|
550
|
+
lines.push("");
|
|
551
|
+
lines.push(`- **Phase:** ${task.phase}`);
|
|
552
|
+
lines.push(`- **Type:** ${task.type}`);
|
|
553
|
+
lines.push(`- **Priority:** ${task.priority}`);
|
|
554
|
+
lines.push(`- **Estimated:** ${task.estimatedHours}h`);
|
|
555
|
+
lines.push(`- **Parallelizable:** ${task.parallelizable ? "Yes" : "No"}`);
|
|
556
|
+
lines.push("");
|
|
557
|
+
lines.push(task.description);
|
|
558
|
+
lines.push("");
|
|
559
|
+
}
|
|
560
|
+
if (this.plan.reviewResult) {
|
|
561
|
+
lines.push("## Review Result");
|
|
562
|
+
lines.push("");
|
|
563
|
+
lines.push(`- **Status:** ${this.plan.reviewResult.overallStatus}`);
|
|
564
|
+
lines.push(`- **Total Findings:** ${this.plan.reviewResult.totalFindings}`);
|
|
565
|
+
lines.push(`- **Critical Findings:** ${this.plan.reviewResult.criticalFindings}`);
|
|
566
|
+
lines.push("");
|
|
567
|
+
if (this.plan.reviewResult.recommendations.length > 0) {
|
|
568
|
+
lines.push("### Recommendations");
|
|
569
|
+
lines.push("");
|
|
570
|
+
for (const rec of this.plan.reviewResult.recommendations) {
|
|
571
|
+
lines.push(`- ${rec}`);
|
|
572
|
+
}
|
|
573
|
+
lines.push("");
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return lines.join("\n");
|
|
577
|
+
}
|
|
578
|
+
// Helper methods for content generation
|
|
579
|
+
extractProblemStatement() {
|
|
580
|
+
return `Problem to solve: ${this.options.description}`;
|
|
581
|
+
}
|
|
582
|
+
extractGoals() {
|
|
583
|
+
return [
|
|
584
|
+
"Implement all specified features",
|
|
585
|
+
"Ensure code quality and maintainability",
|
|
586
|
+
"Provide comprehensive documentation",
|
|
587
|
+
"Enable parallel development where possible"
|
|
588
|
+
];
|
|
589
|
+
}
|
|
590
|
+
generateRequirements() {
|
|
591
|
+
return [
|
|
592
|
+
{
|
|
593
|
+
id: "req-001",
|
|
594
|
+
type: "functional",
|
|
595
|
+
description: "Core functionality as described",
|
|
596
|
+
priority: "must-have",
|
|
597
|
+
source: "User request",
|
|
598
|
+
acceptanceCriteria: ["Feature works as specified"],
|
|
599
|
+
relatedRequirements: []
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
id: "req-002",
|
|
603
|
+
type: "non-functional",
|
|
604
|
+
description: "Code must be well-documented",
|
|
605
|
+
priority: "should-have",
|
|
606
|
+
source: "Best practices",
|
|
607
|
+
acceptanceCriteria: ["API documentation exists"],
|
|
608
|
+
relatedRequirements: []
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
id: "req-003",
|
|
612
|
+
type: "non-functional",
|
|
613
|
+
description: "Test coverage must be adequate",
|
|
614
|
+
priority: "should-have",
|
|
615
|
+
source: "Best practices",
|
|
616
|
+
acceptanceCriteria: ["Unit tests exist for core functionality"],
|
|
617
|
+
relatedRequirements: []
|
|
618
|
+
}
|
|
619
|
+
];
|
|
620
|
+
}
|
|
621
|
+
generateFeatures() {
|
|
622
|
+
return [
|
|
623
|
+
{
|
|
624
|
+
id: "feat-001",
|
|
625
|
+
name: "Core Implementation",
|
|
626
|
+
description: "Main feature implementation",
|
|
627
|
+
userStories: [`As a user, I want ${this.options.description}`],
|
|
628
|
+
requirements: ["req-001"],
|
|
629
|
+
complexity: "medium",
|
|
630
|
+
dependencies: [],
|
|
631
|
+
parallelizable: true
|
|
632
|
+
}
|
|
633
|
+
];
|
|
634
|
+
}
|
|
635
|
+
extractConstraints() {
|
|
636
|
+
return [
|
|
637
|
+
"Must follow existing code patterns if present",
|
|
638
|
+
"Must maintain backwards compatibility"
|
|
639
|
+
];
|
|
640
|
+
}
|
|
641
|
+
generateSuccessMetrics() {
|
|
642
|
+
return [
|
|
643
|
+
"All tests pass",
|
|
644
|
+
"Documentation is complete",
|
|
645
|
+
"Code review approved"
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
generateAlgorithmDesign(feature) {
|
|
649
|
+
return {
|
|
650
|
+
id: `algo_${feature.id}`,
|
|
651
|
+
name: `${feature.name} Algorithm`,
|
|
652
|
+
purpose: feature.description,
|
|
653
|
+
steps: [
|
|
654
|
+
{
|
|
655
|
+
step: 1,
|
|
656
|
+
description: "Initialize",
|
|
657
|
+
pseudocode: "// Initialize component",
|
|
658
|
+
inputs: [],
|
|
659
|
+
outputs: []
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
step: 2,
|
|
663
|
+
description: "Process",
|
|
664
|
+
pseudocode: "// Process input",
|
|
665
|
+
inputs: ["input"],
|
|
666
|
+
outputs: ["result"]
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
step: 3,
|
|
670
|
+
description: "Return",
|
|
671
|
+
pseudocode: "// Return result",
|
|
672
|
+
inputs: ["result"],
|
|
673
|
+
outputs: ["output"]
|
|
674
|
+
}
|
|
675
|
+
],
|
|
676
|
+
timeComplexity: "O(n)",
|
|
677
|
+
spaceComplexity: "O(1)",
|
|
678
|
+
edgeCases: ["Empty input", "Invalid input"],
|
|
679
|
+
relatedFeatures: [feature.id]
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
generateArchitectureOverview() {
|
|
683
|
+
return `Architecture for ${this.options.name}: ${this.options.description}`;
|
|
684
|
+
}
|
|
685
|
+
identifyArchitecturePatterns() {
|
|
686
|
+
const patterns = ["Modular"];
|
|
687
|
+
if (this.plan.existingCode?.patterns.includes("TypeScript")) {
|
|
688
|
+
patterns.push("Type-Safe");
|
|
689
|
+
}
|
|
690
|
+
if (this.plan.existingCode?.patterns.includes("Test-Driven Development")) {
|
|
691
|
+
patterns.push("TDD");
|
|
692
|
+
}
|
|
693
|
+
return patterns;
|
|
694
|
+
}
|
|
695
|
+
generateComponents() {
|
|
696
|
+
return [
|
|
697
|
+
{
|
|
698
|
+
id: "comp-core",
|
|
699
|
+
name: "Core Module",
|
|
700
|
+
type: "module",
|
|
701
|
+
description: "Core functionality module",
|
|
702
|
+
responsibilities: ["Main feature implementation"],
|
|
703
|
+
interfaces: [],
|
|
704
|
+
dependencies: [],
|
|
705
|
+
technologies: ["TypeScript"]
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
id: "comp-api",
|
|
709
|
+
name: "API Layer",
|
|
710
|
+
type: "api",
|
|
711
|
+
description: "Public API interface",
|
|
712
|
+
responsibilities: ["Expose public API"],
|
|
713
|
+
interfaces: [],
|
|
714
|
+
dependencies: ["comp-core"],
|
|
715
|
+
technologies: ["TypeScript"]
|
|
716
|
+
}
|
|
717
|
+
];
|
|
718
|
+
}
|
|
719
|
+
describeDataFlow() {
|
|
720
|
+
return "Input -> API Layer -> Core Module -> Output";
|
|
721
|
+
}
|
|
722
|
+
identifySecurityConsiderations() {
|
|
723
|
+
return [
|
|
724
|
+
"Input validation",
|
|
725
|
+
"Error handling"
|
|
726
|
+
];
|
|
727
|
+
}
|
|
728
|
+
getComponentPriority(component) {
|
|
729
|
+
if (component.dependencies.length === 0) return "high";
|
|
730
|
+
return "medium";
|
|
731
|
+
}
|
|
732
|
+
estimateComponentHours(component) {
|
|
733
|
+
const base = 4;
|
|
734
|
+
const depFactor = component.dependencies.length * 2;
|
|
735
|
+
return base + depFactor;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Get the current plan
|
|
739
|
+
*/
|
|
740
|
+
getPlan() {
|
|
741
|
+
return this.plan;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Get decision log manager
|
|
745
|
+
*/
|
|
746
|
+
getDecisionLog() {
|
|
747
|
+
return this.decisionLog;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function createSPARCPlanner(options) {
|
|
751
|
+
return new SPARCPlanner(options);
|
|
752
|
+
}
|
|
753
|
+
export {
|
|
754
|
+
SPARCPlanner,
|
|
755
|
+
createSPARCPlanner
|
|
756
|
+
};
|
|
757
|
+
//# sourceMappingURL=sparc-planner.js.map
|