musubi-sdd 3.10.0 → 5.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.
Files changed (44) hide show
  1. package/README.md +24 -19
  2. package/package.json +1 -1
  3. package/src/agents/agent-loop.js +532 -0
  4. package/src/agents/agentic/code-generator.js +767 -0
  5. package/src/agents/agentic/code-reviewer.js +698 -0
  6. package/src/agents/agentic/index.js +43 -0
  7. package/src/agents/function-tool.js +432 -0
  8. package/src/agents/index.js +45 -0
  9. package/src/agents/schema-generator.js +514 -0
  10. package/src/analyzers/ast-extractor.js +870 -0
  11. package/src/analyzers/context-optimizer.js +681 -0
  12. package/src/analyzers/repository-map.js +692 -0
  13. package/src/integrations/index.js +7 -1
  14. package/src/integrations/mcp/index.js +175 -0
  15. package/src/integrations/mcp/mcp-context-provider.js +472 -0
  16. package/src/integrations/mcp/mcp-discovery.js +436 -0
  17. package/src/integrations/mcp/mcp-tool-registry.js +467 -0
  18. package/src/integrations/mcp-connector.js +818 -0
  19. package/src/integrations/tool-discovery.js +589 -0
  20. package/src/managers/index.js +7 -0
  21. package/src/managers/skill-tools.js +565 -0
  22. package/src/monitoring/cost-tracker.js +7 -0
  23. package/src/monitoring/incident-manager.js +10 -0
  24. package/src/monitoring/observability.js +10 -0
  25. package/src/monitoring/quality-dashboard.js +491 -0
  26. package/src/monitoring/release-manager.js +10 -0
  27. package/src/orchestration/agent-skill-binding.js +655 -0
  28. package/src/orchestration/error-handler.js +827 -0
  29. package/src/orchestration/index.js +235 -1
  30. package/src/orchestration/mcp-tool-adapters.js +896 -0
  31. package/src/orchestration/reasoning/index.js +58 -0
  32. package/src/orchestration/reasoning/planning-engine.js +831 -0
  33. package/src/orchestration/reasoning/reasoning-engine.js +710 -0
  34. package/src/orchestration/reasoning/self-correction.js +751 -0
  35. package/src/orchestration/skill-executor.js +665 -0
  36. package/src/orchestration/skill-registry.js +650 -0
  37. package/src/orchestration/workflow-examples.js +1072 -0
  38. package/src/orchestration/workflow-executor.js +779 -0
  39. package/src/phase4-integration.js +248 -0
  40. package/src/phase5-integration.js +402 -0
  41. package/src/steering/steering-auto-update.js +572 -0
  42. package/src/steering/steering-validator.js +547 -0
  43. package/src/templates/template-constraints.js +646 -0
  44. package/src/validators/advanced-validation.js +580 -0
@@ -0,0 +1,646 @@
1
+ /**
2
+ * Template Constraints Engine
3
+ * LLM制約テンプレート構文と不確実性マーカー
4
+ *
5
+ * @module templates/template-constraints
6
+ */
7
+
8
+ const EventEmitter = require('events');
9
+
10
+ /**
11
+ * Constraint types
12
+ */
13
+ const CONSTRAINT_TYPE = {
14
+ REQUIRED: 'required',
15
+ OPTIONAL: 'optional',
16
+ FORBIDDEN: 'forbidden',
17
+ CONDITIONAL: 'conditional',
18
+ PATTERN: 'pattern',
19
+ RANGE: 'range',
20
+ ENUM: 'enum'
21
+ };
22
+
23
+ /**
24
+ * Uncertainty levels
25
+ */
26
+ const UNCERTAINTY = {
27
+ CERTAIN: 'certain', // 100% confidence
28
+ HIGH: 'high', // 80-99%
29
+ MEDIUM: 'medium', // 50-79%
30
+ LOW: 'low', // 20-49%
31
+ UNCERTAIN: 'uncertain' // <20%
32
+ };
33
+
34
+ /**
35
+ * Marker types for structured thinking
36
+ */
37
+ const MARKER_TYPE = {
38
+ ASSUMPTION: 'assumption',
39
+ DECISION: 'decision',
40
+ RISK: 'risk',
41
+ TODO: 'todo',
42
+ QUESTION: 'question',
43
+ VERIFIED: 'verified',
44
+ UNCERTAIN: 'uncertain'
45
+ };
46
+
47
+ /**
48
+ * Default constraint templates
49
+ */
50
+ const DEFAULT_TEMPLATES = {
51
+ 'requirements': {
52
+ name: 'Requirements Template',
53
+ sections: [
54
+ { name: 'overview', required: true, minLength: 50 },
55
+ { name: 'functional', required: true, format: 'ears' },
56
+ { name: 'non-functional', required: false },
57
+ { name: 'constraints', required: false },
58
+ { name: 'assumptions', required: true }
59
+ ],
60
+ markers: [MARKER_TYPE.ASSUMPTION, MARKER_TYPE.RISK]
61
+ },
62
+ 'design': {
63
+ name: 'Design Template',
64
+ sections: [
65
+ { name: 'architecture', required: true },
66
+ { name: 'components', required: true, format: 'c4' },
67
+ { name: 'decisions', required: true, format: 'adr' },
68
+ { name: 'interfaces', required: false },
69
+ { name: 'data-model', required: false }
70
+ ],
71
+ markers: [MARKER_TYPE.DECISION, MARKER_TYPE.ASSUMPTION]
72
+ },
73
+ 'implementation': {
74
+ name: 'Implementation Template',
75
+ sections: [
76
+ { name: 'approach', required: true },
77
+ { name: 'tasks', required: true, format: 'checklist' },
78
+ { name: 'dependencies', required: false },
79
+ { name: 'testing', required: true }
80
+ ],
81
+ markers: [MARKER_TYPE.TODO, MARKER_TYPE.RISK]
82
+ }
83
+ };
84
+
85
+ /**
86
+ * Template Constraints Engine
87
+ */
88
+ class TemplateConstraints extends EventEmitter {
89
+ /**
90
+ * @param {Object} options
91
+ * @param {Object} options.templates - Custom templates
92
+ * @param {boolean} options.strict - Strict mode
93
+ * @param {boolean} options.trackUncertainty - Track uncertainty markers
94
+ */
95
+ constructor(options = {}) {
96
+ super();
97
+
98
+ this.templates = {
99
+ ...DEFAULT_TEMPLATES,
100
+ ...(options.templates || {})
101
+ };
102
+
103
+ this.strict = options.strict ?? false;
104
+ this.trackUncertainty = options.trackUncertainty ?? true;
105
+ this.customConstraints = new Map();
106
+ this.validationHistory = [];
107
+ }
108
+
109
+ /**
110
+ * Validate content against a template
111
+ * @param {string} content - Content to validate
112
+ * @param {string} templateId - Template identifier
113
+ * @returns {Object} Validation result
114
+ */
115
+ validate(content, templateId) {
116
+ const template = this.templates[templateId];
117
+ if (!template) {
118
+ return {
119
+ valid: false,
120
+ errors: [{ type: 'unknown_template', message: `Unknown template: ${templateId}` }],
121
+ warnings: [],
122
+ score: 0
123
+ };
124
+ }
125
+
126
+ const errors = [];
127
+ const warnings = [];
128
+ const markers = this.extractMarkers(content);
129
+ const sections = this.extractSections(content);
130
+
131
+ // Validate required sections
132
+ for (const section of template.sections) {
133
+ const found = sections.find(s =>
134
+ s.name.toLowerCase().includes(section.name.toLowerCase())
135
+ );
136
+
137
+ if (section.required && !found) {
138
+ errors.push({
139
+ type: 'missing_section',
140
+ section: section.name,
141
+ message: `Required section missing: ${section.name}`
142
+ });
143
+ } else if (found) {
144
+ // Validate section content
145
+ if (section.minLength && found.content.length < section.minLength) {
146
+ warnings.push({
147
+ type: 'short_section',
148
+ section: section.name,
149
+ message: `Section "${section.name}" is too short (${found.content.length} < ${section.minLength})`
150
+ });
151
+ }
152
+
153
+ if (section.format) {
154
+ const formatValid = this.validateFormat(found.content, section.format);
155
+ if (!formatValid) {
156
+ warnings.push({
157
+ type: 'format_mismatch',
158
+ section: section.name,
159
+ format: section.format,
160
+ message: `Section "${section.name}" doesn't match expected format: ${section.format}`
161
+ });
162
+ }
163
+ }
164
+ }
165
+ }
166
+
167
+ // Check for required markers
168
+ if (template.markers && template.markers.length > 0) {
169
+ for (const markerType of template.markers) {
170
+ const hasMarker = markers.some(m => m.type === markerType);
171
+ if (!hasMarker && this.trackUncertainty) {
172
+ warnings.push({
173
+ type: 'missing_marker',
174
+ markerType,
175
+ message: `Expected marker type not found: ${markerType}`
176
+ });
177
+ }
178
+ }
179
+ }
180
+
181
+ // Apply custom constraints
182
+ for (const [name, constraint] of this.customConstraints) {
183
+ const result = constraint.validate(content, sections, markers);
184
+ if (!result.valid) {
185
+ if (constraint.severity === 'error') {
186
+ errors.push({ type: 'custom_constraint', name, ...result });
187
+ } else {
188
+ warnings.push({ type: 'custom_constraint', name, ...result });
189
+ }
190
+ }
191
+ }
192
+
193
+ const score = this.calculateScore(template, errors, warnings);
194
+ const valid = errors.length === 0 && (score >= 50 || !this.strict);
195
+
196
+ const result = {
197
+ valid,
198
+ templateId,
199
+ templateName: template.name,
200
+ errors,
201
+ warnings,
202
+ markers,
203
+ sections: sections.map(s => s.name),
204
+ score,
205
+ timestamp: new Date().toISOString()
206
+ };
207
+
208
+ this.validationHistory.push(result);
209
+ this.emit('validated', result);
210
+
211
+ return result;
212
+ }
213
+
214
+ /**
215
+ * Extract sections from content
216
+ * @param {string} content
217
+ * @returns {Array}
218
+ */
219
+ extractSections(content) {
220
+ const sections = [];
221
+ const headerRegex = /^(#{1,3})\s+(.+?)$/gm;
222
+ let match;
223
+ const matches = [];
224
+
225
+ while ((match = headerRegex.exec(content)) !== null) {
226
+ matches.push({
227
+ level: match[1].length,
228
+ name: match[2].trim(),
229
+ index: match.index
230
+ });
231
+ }
232
+
233
+ for (let i = 0; i < matches.length; i++) {
234
+ const start = matches[i].index;
235
+ const end = i < matches.length - 1 ? matches[i + 1].index : content.length;
236
+ const sectionContent = content.slice(start, end).trim();
237
+
238
+ sections.push({
239
+ level: matches[i].level,
240
+ name: matches[i].name,
241
+ content: sectionContent,
242
+ length: sectionContent.length
243
+ });
244
+ }
245
+
246
+ return sections;
247
+ }
248
+
249
+ /**
250
+ * Extract uncertainty and decision markers
251
+ * @param {string} content
252
+ * @returns {Array}
253
+ */
254
+ extractMarkers(content) {
255
+ const markers = [];
256
+ const markerPatterns = {
257
+ [MARKER_TYPE.ASSUMPTION]: /\[ASSUMPTION\]:\s*(.+?)(?:\n|$)/gi,
258
+ [MARKER_TYPE.DECISION]: /\[DECISION\]:\s*(.+?)(?:\n|$)/gi,
259
+ [MARKER_TYPE.RISK]: /\[RISK\]:\s*(.+?)(?:\n|$)/gi,
260
+ [MARKER_TYPE.TODO]: /\[TODO\]:\s*(.+?)(?:\n|$)/gi,
261
+ [MARKER_TYPE.QUESTION]: /\[QUESTION\]:\s*(.+?)(?:\n|$)/gi,
262
+ [MARKER_TYPE.VERIFIED]: /\[VERIFIED\]:\s*(.+?)(?:\n|$)/gi,
263
+ [MARKER_TYPE.UNCERTAIN]: /\[UNCERTAIN(?:\s*:\s*(\d+)%)?\]:\s*(.+?)(?:\n|$)/gi
264
+ };
265
+
266
+ for (const [type, pattern] of Object.entries(markerPatterns)) {
267
+ let match;
268
+ while ((match = pattern.exec(content)) !== null) {
269
+ if (type === MARKER_TYPE.UNCERTAIN) {
270
+ markers.push({
271
+ type,
272
+ confidence: match[1] ? parseInt(match[1]) : 50,
273
+ text: match[2].trim(),
274
+ index: match.index
275
+ });
276
+ } else {
277
+ markers.push({
278
+ type,
279
+ text: match[1].trim(),
280
+ index: match.index
281
+ });
282
+ }
283
+ }
284
+ }
285
+
286
+ return markers.sort((a, b) => a.index - b.index);
287
+ }
288
+
289
+ /**
290
+ * Validate content format
291
+ * @param {string} content
292
+ * @param {string} format
293
+ * @returns {boolean}
294
+ */
295
+ validateFormat(content, format) {
296
+ const formatValidators = {
297
+ ears: (c) => {
298
+ // EARS format: When/While/If/Where patterns
299
+ return /\b(when|while|if|where|shall|should|must)\b/i.test(c);
300
+ },
301
+ c4: (c) => {
302
+ // C4 model references
303
+ return /\b(system|container|component|context|boundary)\b/i.test(c);
304
+ },
305
+ adr: (c) => {
306
+ // ADR format: Status, Context, Decision, Consequences
307
+ return /\b(status|context|decision|consequences|accepted|proposed|deprecated)\b/i.test(c);
308
+ },
309
+ checklist: (c) => {
310
+ // Checklist format
311
+ return /^\s*[-*\[\]]\s+/m.test(c);
312
+ }
313
+ };
314
+
315
+ const validator = formatValidators[format];
316
+ return validator ? validator(content) : true;
317
+ }
318
+
319
+ /**
320
+ * Calculate validation score
321
+ */
322
+ calculateScore(template, errors, warnings) {
323
+ let score = 100;
324
+ const totalSections = template.sections.length;
325
+ const requiredSections = template.sections.filter(s => s.required).length;
326
+
327
+ // Deduct for errors
328
+ const missingSections = errors.filter(e => e.type === 'missing_section').length;
329
+ score -= (missingSections / requiredSections) * 50;
330
+
331
+ // Deduct for warnings
332
+ score -= warnings.length * 5;
333
+
334
+ // Deduct for other errors
335
+ const otherErrors = errors.filter(e => e.type !== 'missing_section').length;
336
+ score -= otherErrors * 10;
337
+
338
+ return Math.max(0, Math.min(100, Math.round(score)));
339
+ }
340
+
341
+ /**
342
+ * Add a template
343
+ * @param {string} id
344
+ * @param {Object} template
345
+ */
346
+ addTemplate(id, template) {
347
+ if (!template.name || !template.sections) {
348
+ throw new Error('Template must have name and sections');
349
+ }
350
+ this.templates[id] = template;
351
+ this.emit('template-added', { id, template });
352
+ }
353
+
354
+ /**
355
+ * Remove a template
356
+ * @param {string} id
357
+ * @returns {boolean}
358
+ */
359
+ removeTemplate(id) {
360
+ if (this.templates[id]) {
361
+ delete this.templates[id];
362
+ return true;
363
+ }
364
+ return false;
365
+ }
366
+
367
+ /**
368
+ * Add a custom constraint
369
+ * @param {string} name
370
+ * @param {Object} constraint
371
+ */
372
+ addConstraint(name, constraint) {
373
+ if (!constraint.validate || typeof constraint.validate !== 'function') {
374
+ throw new Error('Constraint must have a validate function');
375
+ }
376
+ this.customConstraints.set(name, {
377
+ severity: 'warning',
378
+ ...constraint
379
+ });
380
+ }
381
+
382
+ /**
383
+ * Remove a constraint
384
+ * @param {string} name
385
+ * @returns {boolean}
386
+ */
387
+ removeConstraint(name) {
388
+ return this.customConstraints.delete(name);
389
+ }
390
+
391
+ /**
392
+ * Get validation history
393
+ * @param {Object} filter
394
+ * @returns {Array}
395
+ */
396
+ getHistory(filter = {}) {
397
+ let history = [...this.validationHistory];
398
+
399
+ if (filter.templateId) {
400
+ history = history.filter(h => h.templateId === filter.templateId);
401
+ }
402
+
403
+ if (filter.valid !== undefined) {
404
+ history = history.filter(h => h.valid === filter.valid);
405
+ }
406
+
407
+ if (filter.minScore !== undefined) {
408
+ history = history.filter(h => h.score >= filter.minScore);
409
+ }
410
+
411
+ return history;
412
+ }
413
+
414
+ /**
415
+ * Get statistics
416
+ * @returns {Object}
417
+ */
418
+ getStats() {
419
+ const total = this.validationHistory.length;
420
+ const valid = this.validationHistory.filter(h => h.valid).length;
421
+ const avgScore = total > 0
422
+ ? this.validationHistory.reduce((sum, h) => sum + h.score, 0) / total
423
+ : 0;
424
+
425
+ const byTemplate = {};
426
+ for (const h of this.validationHistory) {
427
+ if (!byTemplate[h.templateId]) {
428
+ byTemplate[h.templateId] = { total: 0, valid: 0, totalScore: 0 };
429
+ }
430
+ byTemplate[h.templateId].total++;
431
+ if (h.valid) byTemplate[h.templateId].valid++;
432
+ byTemplate[h.templateId].totalScore += h.score;
433
+ }
434
+
435
+ for (const id in byTemplate) {
436
+ byTemplate[id].avgScore = byTemplate[id].totalScore / byTemplate[id].total;
437
+ delete byTemplate[id].totalScore;
438
+ }
439
+
440
+ return {
441
+ total,
442
+ valid,
443
+ invalid: total - valid,
444
+ validRate: total > 0 ? (valid / total) * 100 : 0,
445
+ avgScore: Math.round(avgScore),
446
+ byTemplate,
447
+ templateCount: Object.keys(this.templates).length,
448
+ constraintCount: this.customConstraints.size
449
+ };
450
+ }
451
+
452
+ /**
453
+ * List available templates
454
+ * @returns {Array}
455
+ */
456
+ listTemplates() {
457
+ return Object.entries(this.templates).map(([id, template]) => ({
458
+ id,
459
+ name: template.name,
460
+ sections: template.sections.length,
461
+ requiredSections: template.sections.filter(s => s.required).length,
462
+ markers: template.markers || []
463
+ }));
464
+ }
465
+
466
+ /**
467
+ * Clear history
468
+ */
469
+ clearHistory() {
470
+ this.validationHistory = [];
471
+ this.emit('history-cleared');
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Structured Thinking Checklist
477
+ */
478
+ class ThinkingChecklist extends EventEmitter {
479
+ /**
480
+ * @param {Object} options
481
+ * @param {Array} options.items - Checklist items
482
+ * @param {string} options.name - Checklist name
483
+ */
484
+ constructor(options = {}) {
485
+ super();
486
+
487
+ this.name = options.name || 'Thinking Checklist';
488
+ this.items = options.items || this.getDefaultItems();
489
+ this.completedItems = new Set();
490
+ this.notes = new Map();
491
+ }
492
+
493
+ /**
494
+ * Get default checklist items
495
+ */
496
+ getDefaultItems() {
497
+ return [
498
+ { id: 'understand', category: 'Analysis', text: 'Do I fully understand the requirements?' },
499
+ { id: 'assumptions', category: 'Analysis', text: 'What assumptions am I making?' },
500
+ { id: 'constraints', category: 'Analysis', text: 'What constraints exist?' },
501
+ { id: 'alternatives', category: 'Design', text: 'Have I considered alternatives?' },
502
+ { id: 'tradeoffs', category: 'Design', text: 'What are the tradeoffs?' },
503
+ { id: 'edge-cases', category: 'Design', text: 'Have I considered edge cases?' },
504
+ { id: 'risks', category: 'Risk', text: 'What could go wrong?' },
505
+ { id: 'dependencies', category: 'Risk', text: 'What are the dependencies?' },
506
+ { id: 'testing', category: 'Quality', text: 'How will this be tested?' },
507
+ { id: 'maintainability', category: 'Quality', text: 'Is this maintainable?' }
508
+ ];
509
+ }
510
+
511
+ /**
512
+ * Mark item as complete
513
+ * @param {string} itemId
514
+ * @param {string} note
515
+ */
516
+ complete(itemId, note = '') {
517
+ if (!this.items.find(i => i.id === itemId)) {
518
+ throw new Error(`Unknown item: ${itemId}`);
519
+ }
520
+ this.completedItems.add(itemId);
521
+ if (note) {
522
+ this.notes.set(itemId, note);
523
+ }
524
+ this.emit('item-completed', { itemId, note });
525
+ }
526
+
527
+ /**
528
+ * Unmark item
529
+ * @param {string} itemId
530
+ */
531
+ uncomplete(itemId) {
532
+ this.completedItems.delete(itemId);
533
+ this.notes.delete(itemId);
534
+ }
535
+
536
+ /**
537
+ * Get progress
538
+ * @returns {Object}
539
+ */
540
+ getProgress() {
541
+ const total = this.items.length;
542
+ const completed = this.completedItems.size;
543
+ const remaining = this.items.filter(i => !this.completedItems.has(i.id));
544
+
545
+ const byCategory = {};
546
+ for (const item of this.items) {
547
+ if (!byCategory[item.category]) {
548
+ byCategory[item.category] = { total: 0, completed: 0 };
549
+ }
550
+ byCategory[item.category].total++;
551
+ if (this.completedItems.has(item.id)) {
552
+ byCategory[item.category].completed++;
553
+ }
554
+ }
555
+
556
+ return {
557
+ total,
558
+ completed,
559
+ remaining: remaining.map(i => i.id),
560
+ percentage: Math.round((completed / total) * 100),
561
+ byCategory,
562
+ isComplete: completed === total
563
+ };
564
+ }
565
+
566
+ /**
567
+ * Export as markdown
568
+ * @returns {string}
569
+ */
570
+ toMarkdown() {
571
+ let md = `# ${this.name}\n\n`;
572
+
573
+ const byCategory = {};
574
+ for (const item of this.items) {
575
+ if (!byCategory[item.category]) {
576
+ byCategory[item.category] = [];
577
+ }
578
+ byCategory[item.category].push(item);
579
+ }
580
+
581
+ for (const [category, items] of Object.entries(byCategory)) {
582
+ md += `## ${category}\n\n`;
583
+ for (const item of items) {
584
+ const checked = this.completedItems.has(item.id) ? 'x' : ' ';
585
+ md += `- [${checked}] ${item.text}\n`;
586
+ if (this.notes.has(item.id)) {
587
+ md += ` - Note: ${this.notes.get(item.id)}\n`;
588
+ }
589
+ }
590
+ md += '\n';
591
+ }
592
+
593
+ const progress = this.getProgress();
594
+ md += `---\nProgress: ${progress.completed}/${progress.total} (${progress.percentage}%)\n`;
595
+
596
+ return md;
597
+ }
598
+
599
+ /**
600
+ * Add custom item
601
+ * @param {Object} item
602
+ */
603
+ addItem(item) {
604
+ if (!item.id || !item.text) {
605
+ throw new Error('Item must have id and text');
606
+ }
607
+ this.items.push({
608
+ category: 'Custom',
609
+ ...item
610
+ });
611
+ }
612
+
613
+ /**
614
+ * Reset checklist
615
+ */
616
+ reset() {
617
+ this.completedItems.clear();
618
+ this.notes.clear();
619
+ this.emit('reset');
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Factory function
625
+ */
626
+ function createTemplateConstraints(options = {}) {
627
+ return new TemplateConstraints(options);
628
+ }
629
+
630
+ /**
631
+ * Factory function for checklist
632
+ */
633
+ function createThinkingChecklist(options = {}) {
634
+ return new ThinkingChecklist(options);
635
+ }
636
+
637
+ module.exports = {
638
+ TemplateConstraints,
639
+ ThinkingChecklist,
640
+ createTemplateConstraints,
641
+ createThinkingChecklist,
642
+ CONSTRAINT_TYPE,
643
+ UNCERTAINTY,
644
+ MARKER_TYPE,
645
+ DEFAULT_TEMPLATES
646
+ };