musubi-sdd 3.0.1 → 3.6.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 (62) hide show
  1. package/README.md +17 -3
  2. package/bin/musubi-change.js +623 -10
  3. package/bin/musubi-orchestrate.js +456 -0
  4. package/bin/musubi-trace.js +393 -0
  5. package/package.json +3 -2
  6. package/src/analyzers/impact-analyzer.js +682 -0
  7. package/src/integrations/cicd.js +782 -0
  8. package/src/integrations/documentation.js +740 -0
  9. package/src/integrations/examples.js +789 -0
  10. package/src/integrations/index.js +23 -0
  11. package/src/integrations/platforms.js +929 -0
  12. package/src/llm-providers/anthropic-provider.js +175 -0
  13. package/src/llm-providers/base-provider.js +221 -0
  14. package/src/llm-providers/copilot-provider.js +262 -0
  15. package/src/llm-providers/index.js +214 -0
  16. package/src/llm-providers/openai-provider.js +205 -0
  17. package/src/managers/delta-spec.js +484 -0
  18. package/src/monitoring/incident-manager.js +890 -0
  19. package/src/monitoring/index.js +633 -0
  20. package/src/monitoring/observability.js +938 -0
  21. package/src/monitoring/release-manager.js +622 -0
  22. package/src/orchestration/index.js +193 -0
  23. package/src/orchestration/orchestration-engine.js +409 -0
  24. package/src/orchestration/pattern-registry.js +319 -0
  25. package/src/orchestration/patterns/auto.js +386 -0
  26. package/src/orchestration/patterns/group-chat.js +395 -0
  27. package/src/orchestration/patterns/human-in-loop.js +506 -0
  28. package/src/orchestration/patterns/nested.js +322 -0
  29. package/src/orchestration/patterns/sequential.js +278 -0
  30. package/src/orchestration/patterns/swarm.js +502 -0
  31. package/src/orchestration/replanning/alternative-generator.js +508 -0
  32. package/src/orchestration/replanning/config.js +378 -0
  33. package/src/orchestration/replanning/index.js +40 -0
  34. package/src/orchestration/replanning/plan-evaluator.js +455 -0
  35. package/src/orchestration/replanning/plan-monitor.js +379 -0
  36. package/src/orchestration/replanning/replan-history.js +402 -0
  37. package/src/orchestration/replanning/replanning-engine.js +706 -0
  38. package/src/orchestration/workflow-orchestrator.js +738 -0
  39. package/src/reporters/coverage-report.js +452 -0
  40. package/src/reporters/traceability-matrix-report.js +684 -0
  41. package/src/steering/advanced-validation.js +812 -0
  42. package/src/steering/auto-updater.js +670 -0
  43. package/src/steering/index.js +119 -0
  44. package/src/steering/quality-metrics.js +650 -0
  45. package/src/steering/template-constraints.js +789 -0
  46. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +22 -0
  47. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +21 -0
  48. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +90 -28
  49. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +32 -0
  50. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +27 -0
  51. package/src/templates/agents/claude-code/skills/steering/SKILL.md +30 -0
  52. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +21 -0
  53. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +27 -0
  54. package/src/templates/agents/codex/AGENTS.md +36 -1
  55. package/src/templates/agents/cursor/AGENTS.md +36 -1
  56. package/src/templates/agents/gemini-cli/GEMINI.md +36 -1
  57. package/src/templates/agents/github-copilot/AGENTS.md +65 -1
  58. package/src/templates/agents/qwen-code/QWEN.md +36 -1
  59. package/src/templates/agents/windsurf/AGENTS.md +36 -1
  60. package/src/templates/shared/delta-spec-template.md +246 -0
  61. package/src/validators/delta-format.js +474 -0
  62. package/src/validators/traceability-validator.js +561 -0
@@ -0,0 +1,379 @@
1
+ /**
2
+ * @fileoverview Plan Monitor for MUSUBI Replanning Engine
3
+ * Monitors task execution and triggers replanning when needed
4
+ * @module orchestration/replanning/plan-monitor
5
+ * @version 1.0.0
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const EventEmitter = require('events');
11
+ const { ReplanTrigger } = require('./config');
12
+
13
+ /**
14
+ * Plan Monitor - Watches task execution and detects replanning triggers
15
+ */
16
+ class PlanMonitor extends EventEmitter {
17
+ /**
18
+ * Create a plan monitor
19
+ * @param {Object} options - Monitor options
20
+ * @param {Object} [options.config] - Trigger configuration
21
+ */
22
+ constructor(options = {}) {
23
+ super();
24
+ this.config = options.config || {};
25
+ this.watchedContexts = new Map();
26
+ this.failureCounts = new Map();
27
+ this.timeouts = new Map();
28
+ this.isWatching = false;
29
+ }
30
+
31
+ /**
32
+ * Start watching a task execution context
33
+ * @param {string} contextId - Unique context identifier
34
+ * @param {Object} context - Execution context
35
+ * @param {Object} context.plan - Current plan
36
+ * @param {Array} context.tasks - List of tasks
37
+ * @param {Object} [context.engine] - Orchestration engine reference
38
+ * @returns {void}
39
+ */
40
+ watch(contextId, context) {
41
+ if (this.watchedContexts.has(contextId)) {
42
+ this.unwatch(contextId);
43
+ }
44
+
45
+ const watchContext = {
46
+ ...context,
47
+ startTime: Date.now(),
48
+ taskResults: [],
49
+ failureCount: 0,
50
+ lastUpdate: Date.now()
51
+ };
52
+
53
+ this.watchedContexts.set(contextId, watchContext);
54
+ this.failureCounts.set(contextId, 0);
55
+ this.isWatching = true;
56
+
57
+ // Set up timeout if configured
58
+ const taskTimeout = this.config.triggers?.taskTimeout;
59
+ if (taskTimeout) {
60
+ this.setupTimeout(contextId, taskTimeout);
61
+ }
62
+
63
+ this.emit('watch:started', { contextId, context: watchContext });
64
+ }
65
+
66
+ /**
67
+ * Stop watching a context
68
+ * @param {string} contextId - Context identifier
69
+ */
70
+ unwatch(contextId) {
71
+ this.watchedContexts.delete(contextId);
72
+ this.failureCounts.delete(contextId);
73
+
74
+ // Clear timeout
75
+ const timeout = this.timeouts.get(contextId);
76
+ if (timeout) {
77
+ clearTimeout(timeout);
78
+ this.timeouts.delete(contextId);
79
+ }
80
+
81
+ if (this.watchedContexts.size === 0) {
82
+ this.isWatching = false;
83
+ }
84
+
85
+ this.emit('watch:stopped', { contextId });
86
+ }
87
+
88
+ /**
89
+ * Report task result and check for triggers
90
+ * @param {string} contextId - Context identifier
91
+ * @param {Object} result - Task result
92
+ * @param {string} result.taskId - Task identifier
93
+ * @param {string} result.status - Task status ('success', 'failed', 'timeout')
94
+ * @param {*} [result.output] - Task output
95
+ * @param {Error} [result.error] - Task error if failed
96
+ * @returns {ReplanTriggerEvent|null} Trigger event if replanning needed
97
+ */
98
+ reportResult(contextId, result) {
99
+ const context = this.watchedContexts.get(contextId);
100
+ if (!context) {
101
+ return null;
102
+ }
103
+
104
+ // Update context
105
+ context.taskResults.push(result);
106
+ context.lastUpdate = Date.now();
107
+
108
+ // Reset timeout
109
+ this.resetTimeout(contextId);
110
+
111
+ // Check for triggers based on result
112
+ const trigger = this.checkTriggers(contextId, result, context);
113
+
114
+ if (trigger) {
115
+ this.emit('trigger', trigger);
116
+ return trigger;
117
+ }
118
+
119
+ return null;
120
+ }
121
+
122
+ /**
123
+ * Report context change
124
+ * @param {string} contextId - Context identifier
125
+ * @param {Object} changes - Context changes
126
+ * @returns {ReplanTriggerEvent|null} Trigger event if replanning needed
127
+ */
128
+ reportContextChange(contextId, changes) {
129
+ const context = this.watchedContexts.get(contextId);
130
+ if (!context) {
131
+ return null;
132
+ }
133
+
134
+ const enabledTriggers = this.config.triggers?.enabled || [];
135
+ if (!enabledTriggers.includes(ReplanTrigger.CONTEXT_CHANGED)) {
136
+ return null;
137
+ }
138
+
139
+ const trigger = {
140
+ type: ReplanTrigger.CONTEXT_CHANGED,
141
+ contextId,
142
+ timestamp: Date.now(),
143
+ data: {
144
+ changes,
145
+ previousContext: { ...context },
146
+ reason: 'Context or requirements changed'
147
+ }
148
+ };
149
+
150
+ // Update context with changes
151
+ Object.assign(context, changes);
152
+
153
+ this.emit('trigger', trigger);
154
+ return trigger;
155
+ }
156
+
157
+ /**
158
+ * Request replanning manually
159
+ * @param {string} contextId - Context identifier
160
+ * @param {string} [reason] - Reason for request
161
+ * @returns {ReplanTriggerEvent} Trigger event
162
+ */
163
+ requestReplan(contextId, reason = 'Human requested replanning') {
164
+ const context = this.watchedContexts.get(contextId);
165
+
166
+ const trigger = {
167
+ type: ReplanTrigger.HUMAN_REQUEST,
168
+ contextId,
169
+ timestamp: Date.now(),
170
+ data: {
171
+ reason,
172
+ context: context || null
173
+ }
174
+ };
175
+
176
+ this.emit('trigger', trigger);
177
+ return trigger;
178
+ }
179
+
180
+ /**
181
+ * Check for trigger conditions based on task result
182
+ * @param {string} contextId - Context identifier
183
+ * @param {Object} result - Task result
184
+ * @param {Object} context - Execution context
185
+ * @returns {ReplanTriggerEvent|null}
186
+ * @private
187
+ */
188
+ checkTriggers(contextId, result, context) {
189
+ const enabledTriggers = this.config.triggers?.enabled || [
190
+ ReplanTrigger.TASK_FAILED,
191
+ ReplanTrigger.TIMEOUT
192
+ ];
193
+
194
+ // Check for task failure
195
+ if (result.status === 'failed' && enabledTriggers.includes(ReplanTrigger.TASK_FAILED)) {
196
+ const failureCount = (this.failureCounts.get(contextId) || 0) + 1;
197
+ this.failureCounts.set(contextId, failureCount);
198
+
199
+ const threshold = this.config.triggers?.failureThreshold || 2;
200
+
201
+ if (failureCount >= threshold) {
202
+ return {
203
+ type: ReplanTrigger.TASK_FAILED,
204
+ contextId,
205
+ timestamp: Date.now(),
206
+ data: {
207
+ taskId: result.taskId,
208
+ error: result.error,
209
+ failureCount,
210
+ threshold,
211
+ context: this.sanitizeContext(context)
212
+ }
213
+ };
214
+ }
215
+ }
216
+
217
+ // Check for timeout
218
+ if (result.status === 'timeout' && enabledTriggers.includes(ReplanTrigger.TIMEOUT)) {
219
+ return {
220
+ type: ReplanTrigger.TIMEOUT,
221
+ contextId,
222
+ timestamp: Date.now(),
223
+ data: {
224
+ taskId: result.taskId,
225
+ elapsed: Date.now() - context.startTime,
226
+ context: this.sanitizeContext(context)
227
+ }
228
+ };
229
+ }
230
+
231
+ // Check for goal unreachable (based on error analysis)
232
+ if (result.status === 'failed' &&
233
+ enabledTriggers.includes(ReplanTrigger.GOAL_UNREACHABLE) &&
234
+ this.isGoalUnreachable(result)) {
235
+ return {
236
+ type: ReplanTrigger.GOAL_UNREACHABLE,
237
+ contextId,
238
+ timestamp: Date.now(),
239
+ data: {
240
+ taskId: result.taskId,
241
+ error: result.error,
242
+ reason: 'Goal determined to be unreachable',
243
+ context: this.sanitizeContext(context)
244
+ }
245
+ };
246
+ }
247
+
248
+ return null;
249
+ }
250
+
251
+ /**
252
+ * Check if the goal is unreachable based on error
253
+ * @param {Object} result - Task result
254
+ * @returns {boolean}
255
+ * @private
256
+ */
257
+ isGoalUnreachable(result) {
258
+ if (!result.error) return false;
259
+
260
+ const unreachablePatterns = [
261
+ /not found/i,
262
+ /does not exist/i,
263
+ /permission denied/i,
264
+ /access denied/i,
265
+ /unauthorized/i,
266
+ /impossible/i,
267
+ /cannot be completed/i
268
+ ];
269
+
270
+ const errorMessage = result.error.message || String(result.error);
271
+ return unreachablePatterns.some(pattern => pattern.test(errorMessage));
272
+ }
273
+
274
+ /**
275
+ * Setup timeout for a context
276
+ * @param {string} contextId - Context identifier
277
+ * @param {number} timeout - Timeout in milliseconds
278
+ * @private
279
+ */
280
+ setupTimeout(contextId, timeout) {
281
+ const timeoutHandle = setTimeout(() => {
282
+ const context = this.watchedContexts.get(contextId);
283
+ if (context) {
284
+ const trigger = {
285
+ type: ReplanTrigger.TIMEOUT,
286
+ contextId,
287
+ timestamp: Date.now(),
288
+ data: {
289
+ reason: 'Overall task timeout exceeded',
290
+ elapsed: Date.now() - context.startTime,
291
+ context: this.sanitizeContext(context)
292
+ }
293
+ };
294
+ this.emit('trigger', trigger);
295
+ }
296
+ }, timeout);
297
+
298
+ this.timeouts.set(contextId, timeoutHandle);
299
+ }
300
+
301
+ /**
302
+ * Reset timeout for a context
303
+ * @param {string} contextId - Context identifier
304
+ * @private
305
+ */
306
+ resetTimeout(contextId) {
307
+ const timeout = this.timeouts.get(contextId);
308
+ if (timeout) {
309
+ clearTimeout(timeout);
310
+ const taskTimeout = this.config.triggers?.taskTimeout;
311
+ if (taskTimeout) {
312
+ this.setupTimeout(contextId, taskTimeout);
313
+ }
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Sanitize context for event emission
319
+ * @param {Object} context - Execution context
320
+ * @returns {Object} Sanitized context
321
+ * @private
322
+ */
323
+ sanitizeContext(context) {
324
+ // Remove circular references and large objects
325
+ return {
326
+ startTime: context.startTime,
327
+ lastUpdate: context.lastUpdate,
328
+ failureCount: context.failureCount,
329
+ taskResultCount: context.taskResults?.length || 0,
330
+ plan: context.plan ? {
331
+ id: context.plan.id,
332
+ version: context.plan.version,
333
+ taskCount: context.plan.tasks?.length
334
+ } : null
335
+ };
336
+ }
337
+
338
+ /**
339
+ * Get current monitoring stats
340
+ * @returns {Object} Monitoring statistics
341
+ */
342
+ getStats() {
343
+ const contexts = [];
344
+ for (const [contextId, context] of this.watchedContexts) {
345
+ contexts.push({
346
+ contextId,
347
+ startTime: context.startTime,
348
+ lastUpdate: context.lastUpdate,
349
+ failureCount: this.failureCounts.get(contextId) || 0,
350
+ taskResultCount: context.taskResults?.length || 0
351
+ });
352
+ }
353
+
354
+ return {
355
+ isWatching: this.isWatching,
356
+ activeContexts: this.watchedContexts.size,
357
+ contexts
358
+ };
359
+ }
360
+
361
+ /**
362
+ * Clear all watched contexts
363
+ */
364
+ clear() {
365
+ for (const contextId of this.watchedContexts.keys()) {
366
+ this.unwatch(contextId);
367
+ }
368
+ }
369
+ }
370
+
371
+ /**
372
+ * @typedef {Object} ReplanTriggerEvent
373
+ * @property {string} type - Trigger type from ReplanTrigger enum
374
+ * @property {string} contextId - Context identifier
375
+ * @property {number} timestamp - Event timestamp
376
+ * @property {Object} data - Trigger-specific data
377
+ */
378
+
379
+ module.exports = { PlanMonitor };