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.
- package/README.md +17 -3
- package/bin/musubi-change.js +623 -10
- package/bin/musubi-orchestrate.js +456 -0
- package/bin/musubi-trace.js +393 -0
- package/package.json +3 -2
- package/src/analyzers/impact-analyzer.js +682 -0
- package/src/integrations/cicd.js +782 -0
- package/src/integrations/documentation.js +740 -0
- package/src/integrations/examples.js +789 -0
- package/src/integrations/index.js +23 -0
- package/src/integrations/platforms.js +929 -0
- package/src/llm-providers/anthropic-provider.js +175 -0
- package/src/llm-providers/base-provider.js +221 -0
- package/src/llm-providers/copilot-provider.js +262 -0
- package/src/llm-providers/index.js +214 -0
- package/src/llm-providers/openai-provider.js +205 -0
- package/src/managers/delta-spec.js +484 -0
- package/src/monitoring/incident-manager.js +890 -0
- package/src/monitoring/index.js +633 -0
- package/src/monitoring/observability.js +938 -0
- package/src/monitoring/release-manager.js +622 -0
- package/src/orchestration/index.js +193 -0
- package/src/orchestration/orchestration-engine.js +409 -0
- package/src/orchestration/pattern-registry.js +319 -0
- package/src/orchestration/patterns/auto.js +386 -0
- package/src/orchestration/patterns/group-chat.js +395 -0
- package/src/orchestration/patterns/human-in-loop.js +506 -0
- package/src/orchestration/patterns/nested.js +322 -0
- package/src/orchestration/patterns/sequential.js +278 -0
- package/src/orchestration/patterns/swarm.js +502 -0
- package/src/orchestration/replanning/alternative-generator.js +508 -0
- package/src/orchestration/replanning/config.js +378 -0
- package/src/orchestration/replanning/index.js +40 -0
- package/src/orchestration/replanning/plan-evaluator.js +455 -0
- package/src/orchestration/replanning/plan-monitor.js +379 -0
- package/src/orchestration/replanning/replan-history.js +402 -0
- package/src/orchestration/replanning/replanning-engine.js +706 -0
- package/src/orchestration/workflow-orchestrator.js +738 -0
- package/src/reporters/coverage-report.js +452 -0
- package/src/reporters/traceability-matrix-report.js +684 -0
- package/src/steering/advanced-validation.js +812 -0
- package/src/steering/auto-updater.js +670 -0
- package/src/steering/index.js +119 -0
- package/src/steering/quality-metrics.js +650 -0
- package/src/steering/template-constraints.js +789 -0
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +22 -0
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +21 -0
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +90 -28
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +32 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +27 -0
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +30 -0
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +21 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +27 -0
- package/src/templates/agents/codex/AGENTS.md +36 -1
- package/src/templates/agents/cursor/AGENTS.md +36 -1
- package/src/templates/agents/gemini-cli/GEMINI.md +36 -1
- package/src/templates/agents/github-copilot/AGENTS.md +65 -1
- package/src/templates/agents/qwen-code/QWEN.md +36 -1
- package/src/templates/agents/windsurf/AGENTS.md +36 -1
- package/src/templates/shared/delta-spec-template.md +246 -0
- package/src/validators/delta-format.js +474 -0
- 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 };
|