musubi-sdd 5.0.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.
Files changed (232) hide show
  1. package/README.ja.md +106 -48
  2. package/README.md +110 -32
  3. package/bin/musubi-analyze.js +74 -67
  4. package/bin/musubi-browser.js +27 -26
  5. package/bin/musubi-change.js +48 -47
  6. package/bin/musubi-checkpoint.js +10 -7
  7. package/bin/musubi-convert.js +25 -25
  8. package/bin/musubi-costs.js +27 -10
  9. package/bin/musubi-gui.js +52 -46
  10. package/bin/musubi-init.js +1952 -10
  11. package/bin/musubi-orchestrate.js +327 -239
  12. package/bin/musubi-remember.js +69 -56
  13. package/bin/musubi-resolve.js +53 -45
  14. package/bin/musubi-trace.js +51 -22
  15. package/bin/musubi-validate.js +39 -30
  16. package/bin/musubi-workflow.js +33 -34
  17. package/bin/musubi.js +39 -2
  18. package/package.json +1 -1
  19. package/src/agents/agent-loop.js +94 -95
  20. package/src/agents/agentic/code-generator.js +119 -109
  21. package/src/agents/agentic/code-reviewer.js +105 -108
  22. package/src/agents/agentic/index.js +4 -4
  23. package/src/agents/browser/action-executor.js +13 -13
  24. package/src/agents/browser/ai-comparator.js +11 -10
  25. package/src/agents/browser/context-manager.js +6 -6
  26. package/src/agents/browser/index.js +5 -5
  27. package/src/agents/browser/nl-parser.js +31 -46
  28. package/src/agents/browser/screenshot.js +2 -2
  29. package/src/agents/browser/test-generator.js +6 -4
  30. package/src/agents/function-tool.js +71 -65
  31. package/src/agents/index.js +7 -7
  32. package/src/agents/schema-generator.js +98 -94
  33. package/src/analyzers/ast-extractor.js +164 -145
  34. package/src/analyzers/codegraph-auto-update.js +858 -0
  35. package/src/analyzers/complexity-analyzer.js +536 -0
  36. package/src/analyzers/context-optimizer.js +247 -125
  37. package/src/analyzers/impact-analyzer.js +1 -1
  38. package/src/analyzers/large-project-analyzer.js +766 -0
  39. package/src/analyzers/repository-map.js +83 -80
  40. package/src/analyzers/security-analyzer.js +19 -11
  41. package/src/analyzers/stuck-detector.js +19 -17
  42. package/src/converters/index.js +78 -57
  43. package/src/converters/ir/types.js +12 -12
  44. package/src/converters/parsers/musubi-parser.js +134 -126
  45. package/src/converters/parsers/openapi-parser.js +70 -53
  46. package/src/converters/parsers/speckit-parser.js +239 -175
  47. package/src/converters/writers/musubi-writer.js +123 -118
  48. package/src/converters/writers/speckit-writer.js +124 -113
  49. package/src/generators/rust-migration-generator.js +512 -0
  50. package/src/gui/public/index.html +1365 -1211
  51. package/src/gui/server.js +41 -40
  52. package/src/gui/services/file-watcher.js +23 -8
  53. package/src/gui/services/project-scanner.js +26 -20
  54. package/src/gui/services/replanning-service.js +27 -23
  55. package/src/gui/services/traceability-service.js +8 -8
  56. package/src/gui/services/workflow-service.js +14 -7
  57. package/src/index.js +151 -0
  58. package/src/integrations/cicd.js +90 -104
  59. package/src/integrations/codegraph-mcp.js +643 -0
  60. package/src/integrations/documentation.js +142 -103
  61. package/src/integrations/examples.js +95 -80
  62. package/src/integrations/github-client.js +17 -17
  63. package/src/integrations/index.js +5 -5
  64. package/src/integrations/mcp/index.js +21 -21
  65. package/src/integrations/mcp/mcp-context-provider.js +76 -78
  66. package/src/integrations/mcp/mcp-discovery.js +74 -72
  67. package/src/integrations/mcp/mcp-tool-registry.js +99 -94
  68. package/src/integrations/mcp-connector.js +70 -66
  69. package/src/integrations/platforms.js +50 -49
  70. package/src/integrations/tool-discovery.js +37 -31
  71. package/src/llm-providers/anthropic-provider.js +11 -11
  72. package/src/llm-providers/base-provider.js +16 -18
  73. package/src/llm-providers/copilot-provider.js +22 -19
  74. package/src/llm-providers/index.js +26 -25
  75. package/src/llm-providers/ollama-provider.js +11 -11
  76. package/src/llm-providers/openai-provider.js +12 -12
  77. package/src/managers/agent-memory.js +36 -24
  78. package/src/managers/checkpoint-manager.js +4 -8
  79. package/src/managers/delta-spec.js +19 -19
  80. package/src/managers/index.js +13 -4
  81. package/src/managers/memory-condenser.js +35 -45
  82. package/src/managers/repo-skill-manager.js +57 -31
  83. package/src/managers/skill-loader.js +25 -22
  84. package/src/managers/skill-tools.js +36 -72
  85. package/src/managers/workflow.js +30 -22
  86. package/src/monitoring/cost-tracker.js +53 -44
  87. package/src/monitoring/incident-manager.js +123 -103
  88. package/src/monitoring/index.js +144 -134
  89. package/src/monitoring/observability.js +82 -59
  90. package/src/monitoring/quality-dashboard.js +51 -39
  91. package/src/monitoring/release-manager.js +70 -50
  92. package/src/orchestration/agent-skill-binding.js +39 -47
  93. package/src/orchestration/error-handler.js +65 -107
  94. package/src/orchestration/guardrails/base-guardrail.js +26 -24
  95. package/src/orchestration/guardrails/guardrail-rules.js +50 -64
  96. package/src/orchestration/guardrails/index.js +5 -5
  97. package/src/orchestration/guardrails/input-guardrail.js +58 -45
  98. package/src/orchestration/guardrails/output-guardrail.js +104 -81
  99. package/src/orchestration/guardrails/safety-check.js +79 -79
  100. package/src/orchestration/index.js +38 -55
  101. package/src/orchestration/mcp-tool-adapters.js +96 -99
  102. package/src/orchestration/orchestration-engine.js +21 -21
  103. package/src/orchestration/pattern-registry.js +60 -45
  104. package/src/orchestration/patterns/auto.js +34 -47
  105. package/src/orchestration/patterns/group-chat.js +59 -65
  106. package/src/orchestration/patterns/handoff.js +67 -65
  107. package/src/orchestration/patterns/human-in-loop.js +51 -72
  108. package/src/orchestration/patterns/nested.js +25 -40
  109. package/src/orchestration/patterns/sequential.js +35 -34
  110. package/src/orchestration/patterns/swarm.js +63 -56
  111. package/src/orchestration/patterns/triage.js +150 -109
  112. package/src/orchestration/reasoning/index.js +9 -9
  113. package/src/orchestration/reasoning/planning-engine.js +143 -140
  114. package/src/orchestration/reasoning/reasoning-engine.js +206 -144
  115. package/src/orchestration/reasoning/self-correction.js +121 -128
  116. package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
  117. package/src/orchestration/replanning/alternative-generator.js +37 -42
  118. package/src/orchestration/replanning/config.js +63 -59
  119. package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
  120. package/src/orchestration/replanning/index.js +24 -20
  121. package/src/orchestration/replanning/plan-evaluator.js +49 -50
  122. package/src/orchestration/replanning/plan-monitor.js +32 -28
  123. package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
  124. package/src/orchestration/replanning/replan-history.js +33 -26
  125. package/src/orchestration/replanning/replanning-engine.js +106 -108
  126. package/src/orchestration/skill-executor.js +107 -109
  127. package/src/orchestration/skill-registry.js +85 -89
  128. package/src/orchestration/workflow-examples.js +228 -231
  129. package/src/orchestration/workflow-executor.js +65 -68
  130. package/src/orchestration/workflow-orchestrator.js +72 -73
  131. package/src/phase4-integration.js +47 -40
  132. package/src/phase5-integration.js +89 -30
  133. package/src/reporters/coverage-report.js +82 -30
  134. package/src/reporters/hierarchical-reporter.js +498 -0
  135. package/src/reporters/traceability-matrix-report.js +29 -20
  136. package/src/resolvers/issue-resolver.js +43 -31
  137. package/src/steering/advanced-validation.js +133 -124
  138. package/src/steering/auto-updater.js +60 -73
  139. package/src/steering/index.js +6 -6
  140. package/src/steering/quality-metrics.js +41 -35
  141. package/src/steering/steering-auto-update.js +83 -86
  142. package/src/steering/steering-validator.js +98 -106
  143. package/src/steering/template-constraints.js +53 -54
  144. package/src/templates/agents/claude-code/CLAUDE.md +32 -32
  145. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
  146. package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
  147. package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
  148. package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
  149. package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
  150. package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
  151. package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
  152. package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
  153. package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
  154. package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
  155. package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
  156. package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
  157. package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
  158. package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
  159. package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
  160. package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
  161. package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
  162. package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
  163. package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
  164. package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
  165. package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
  166. package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
  167. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
  168. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
  169. package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
  170. package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
  171. package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
  172. package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
  173. package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
  174. package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
  175. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
  176. package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
  177. package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
  178. package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
  179. package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
  180. package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
  181. package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
  182. package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
  183. package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
  184. package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
  185. package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
  186. package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
  187. package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
  188. package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
  189. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
  190. package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
  191. package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
  192. package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
  193. package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
  194. package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
  195. package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
  196. package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
  197. package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
  198. package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
  199. package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
  200. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
  201. package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
  202. package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
  203. package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
  204. package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
  205. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
  206. package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
  207. package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
  208. package/src/templates/agents/codex/AGENTS.md +74 -42
  209. package/src/templates/agents/cursor/AGENTS.md +74 -42
  210. package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
  211. package/src/templates/agents/github-copilot/AGENTS.md +83 -51
  212. package/src/templates/agents/qwen-code/QWEN.md +74 -42
  213. package/src/templates/agents/windsurf/AGENTS.md +74 -42
  214. package/src/templates/architectures/README.md +41 -0
  215. package/src/templates/architectures/clean-architecture/README.md +113 -0
  216. package/src/templates/architectures/event-driven/README.md +162 -0
  217. package/src/templates/architectures/hexagonal/README.md +130 -0
  218. package/src/templates/index.js +6 -1
  219. package/src/templates/locale-manager.js +16 -16
  220. package/src/templates/shared/delta-spec-template.md +20 -13
  221. package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
  222. package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
  223. package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
  224. package/src/templates/shared/steering/structure.md +95 -0
  225. package/src/templates/skills/browser-agent.md +21 -16
  226. package/src/templates/skills/web-gui.md +8 -0
  227. package/src/templates/template-constraints.js +50 -53
  228. package/src/validators/advanced-validation.js +30 -36
  229. package/src/validators/constitutional-validator.js +77 -73
  230. package/src/validators/critic-system.js +49 -59
  231. package/src/validators/delta-format.js +59 -55
  232. package/src/validators/traceability-validator.js +7 -11
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * Incident Manager - Incident response and management
3
- *
3
+ *
4
4
  * Provides incident management capabilities:
5
5
  * - Incident lifecycle management
6
6
  * - Runbook execution
7
7
  * - Post-mortem generation
8
8
  * - On-call management
9
+ *
10
+ * Part of MUSUBI v5.0.0 - Production Readiness
11
+ *
12
+ * @module monitoring/incident-manager
13
+ * @version 1.0.0
14
+ *
15
+ * @traceability
16
+ * - Requirement: REQ-P5-002 (Incident Management)
17
+ * - Design: docs/design/tdd-musubi-v5.0.0.md#3.2
18
+ * - Test: tests/monitoring/incident-manager.test.js
9
19
  */
10
20
 
11
21
  const { EventEmitter } = require('events');
@@ -18,7 +28,7 @@ const IncidentSeverity = {
18
28
  SEV2: 'sev2', // High - significant impact
19
29
  SEV3: 'sev3', // Medium - limited impact
20
30
  SEV4: 'sev4', // Low - minimal impact
21
- SEV5: 'sev5' // Informational
31
+ SEV5: 'sev5', // Informational
22
32
  };
23
33
 
24
34
  /**
@@ -32,7 +42,7 @@ const IncidentStatus = {
32
42
  MITIGATING: 'mitigating',
33
43
  MONITORING: 'monitoring',
34
44
  RESOLVED: 'resolved',
35
- CLOSED: 'closed'
45
+ CLOSED: 'closed',
36
46
  };
37
47
 
38
48
  /**
@@ -43,7 +53,7 @@ const StepStatus = {
43
53
  IN_PROGRESS: 'in-progress',
44
54
  COMPLETED: 'completed',
45
55
  FAILED: 'failed',
46
- SKIPPED: 'skipped'
56
+ SKIPPED: 'skipped',
47
57
  };
48
58
 
49
59
  /**
@@ -56,35 +66,37 @@ class Incident {
56
66
  this.description = options.description || '';
57
67
  this.severity = options.severity || IncidentSeverity.SEV3;
58
68
  this.status = options.status || IncidentStatus.DETECTED;
59
-
69
+
60
70
  this.detectedAt = options.detectedAt || new Date();
61
71
  this.acknowledgedAt = null;
62
72
  this.mitigatedAt = null;
63
73
  this.resolvedAt = null;
64
74
  this.closedAt = null;
65
-
75
+
66
76
  this.affectedServices = options.affectedServices || [];
67
77
  this.impactSummary = options.impactSummary || '';
68
78
  this.customerImpact = options.customerImpact || {
69
79
  affected: 0,
70
- percentage: 0
80
+ percentage: 0,
71
81
  };
72
-
82
+
73
83
  this.assignee = options.assignee || null;
74
84
  this.responders = options.responders || [];
75
85
  this.commander = options.commander || null;
76
-
77
- this.timeline = [{
78
- timestamp: this.detectedAt,
79
- action: 'detected',
80
- description: 'Incident detected',
81
- actor: 'system'
82
- }];
83
-
86
+
87
+ this.timeline = [
88
+ {
89
+ timestamp: this.detectedAt,
90
+ action: 'detected',
91
+ description: 'Incident detected',
92
+ actor: 'system',
93
+ },
94
+ ];
95
+
84
96
  this.rootCause = null;
85
97
  this.resolution = null;
86
98
  this.postMortem = null;
87
-
99
+
88
100
  this.relatedIncidents = options.relatedIncidents || [];
89
101
  this.tags = options.tags || [];
90
102
  this.metadata = options.metadata || {};
@@ -97,15 +109,15 @@ class Incident {
97
109
  if (this.acknowledgedAt) {
98
110
  throw new Error('Incident already acknowledged');
99
111
  }
100
-
112
+
101
113
  this.acknowledgedAt = new Date();
102
114
  this.status = IncidentStatus.TRIAGING;
103
115
  this.assignee = responder;
104
-
116
+
105
117
  if (!this.responders.includes(responder)) {
106
118
  this.responders.push(responder);
107
119
  }
108
-
120
+
109
121
  this._addTimelineEntry('acknowledged', `Acknowledged by ${responder}`, responder);
110
122
  return this;
111
123
  }
@@ -127,7 +139,11 @@ class Incident {
127
139
  setCommander(commander) {
128
140
  this.commander = commander;
129
141
  this.addResponder(commander, 'commander');
130
- this._addTimelineEntry('commander_assigned', `${commander} assigned as incident commander`, commander);
142
+ this._addTimelineEntry(
143
+ 'commander_assigned',
144
+ `${commander} assigned as incident commander`,
145
+ commander
146
+ );
131
147
  return this;
132
148
  }
133
149
 
@@ -137,9 +153,13 @@ class Incident {
137
153
  updateStatus(newStatus, note = '', actor = 'system') {
138
154
  const previousStatus = this.status;
139
155
  this.status = newStatus;
140
-
141
- this._addTimelineEntry('status_change', `Status changed from ${previousStatus} to ${newStatus}. ${note}`, actor);
142
-
156
+
157
+ this._addTimelineEntry(
158
+ 'status_change',
159
+ `Status changed from ${previousStatus} to ${newStatus}. ${note}`,
160
+ actor
161
+ );
162
+
143
163
  // Update timestamps
144
164
  if (newStatus === IncidentStatus.MITIGATING && !this.mitigatedAt) {
145
165
  // Record when mitigation started
@@ -150,7 +170,7 @@ class Incident {
150
170
  if (newStatus === IncidentStatus.CLOSED) {
151
171
  this.closedAt = new Date();
152
172
  }
153
-
173
+
154
174
  return this;
155
175
  }
156
176
 
@@ -160,7 +180,11 @@ class Incident {
160
180
  updateSeverity(newSeverity, reason = '', actor = 'system') {
161
181
  const previousSeverity = this.severity;
162
182
  this.severity = newSeverity;
163
- this._addTimelineEntry('severity_change', `Severity changed from ${previousSeverity} to ${newSeverity}. ${reason}`, actor);
183
+ this._addTimelineEntry(
184
+ 'severity_change',
185
+ `Severity changed from ${previousSeverity} to ${newSeverity}. ${reason}`,
186
+ actor
187
+ );
164
188
  return this;
165
189
  }
166
190
 
@@ -198,21 +222,17 @@ class Incident {
198
222
  */
199
223
  getMetrics() {
200
224
  const now = new Date();
201
-
225
+
202
226
  return {
203
- timeToAcknowledge: this.acknowledgedAt
204
- ? (this.acknowledgedAt - this.detectedAt) / 1000
205
- : null,
206
- timeToMitigate: this.mitigatedAt
207
- ? (this.mitigatedAt - this.detectedAt) / 1000
208
- : null,
209
- timeToResolve: this.resolvedAt
210
- ? (this.resolvedAt - this.detectedAt) / 1000
227
+ timeToAcknowledge: this.acknowledgedAt
228
+ ? (this.acknowledgedAt - this.detectedAt) / 1000
211
229
  : null,
212
- totalDuration: this.closedAt
213
- ? (this.closedAt - this.detectedAt) / 1000
230
+ timeToMitigate: this.mitigatedAt ? (this.mitigatedAt - this.detectedAt) / 1000 : null,
231
+ timeToResolve: this.resolvedAt ? (this.resolvedAt - this.detectedAt) / 1000 : null,
232
+ totalDuration: this.closedAt
233
+ ? (this.closedAt - this.detectedAt) / 1000
214
234
  : (now - this.detectedAt) / 1000,
215
- isOpen: !this.closedAt
235
+ isOpen: !this.closedAt,
216
236
  };
217
237
  }
218
238
 
@@ -225,7 +245,7 @@ class Incident {
225
245
  timestamp: new Date(),
226
246
  action,
227
247
  description,
228
- actor
248
+ actor,
229
249
  });
230
250
  }
231
251
 
@@ -260,7 +280,7 @@ class Incident {
260
280
  rootCause: this.rootCause,
261
281
  resolution: this.resolution,
262
282
  tags: this.tags,
263
- metrics: this.getMetrics()
283
+ metrics: this.getMetrics(),
264
284
  };
265
285
  }
266
286
  }
@@ -277,7 +297,7 @@ class Runbook {
277
297
  this.category = options.category || 'general';
278
298
  this.tags = options.tags || [];
279
299
  this.estimatedDuration = options.estimatedDuration || '15 minutes';
280
-
300
+
281
301
  this.steps = (options.steps || []).map((step, index) => ({
282
302
  id: step.id || `step-${index + 1}`,
283
303
  order: step.order || index + 1,
@@ -287,9 +307,9 @@ class Runbook {
287
307
  expectedOutput: step.expectedOutput || null,
288
308
  onFailure: step.onFailure || 'abort', // abort, continue, retry
289
309
  timeout: step.timeout || 300, // seconds
290
- requiresConfirmation: step.requiresConfirmation || false
310
+ requiresConfirmation: step.requiresConfirmation || false,
291
311
  }));
292
-
312
+
293
313
  this.metadata = options.metadata || {};
294
314
  }
295
315
 
@@ -303,7 +323,7 @@ class Runbook {
303
323
  tags: this.tags,
304
324
  estimatedDuration: this.estimatedDuration,
305
325
  steps: this.steps,
306
- metadata: this.metadata
326
+ metadata: this.metadata,
307
327
  };
308
328
  }
309
329
  }
@@ -319,16 +339,16 @@ class RunbookExecution {
319
339
  this.startedAt = new Date();
320
340
  this.completedAt = null;
321
341
  this.status = 'running';
322
-
342
+
323
343
  this.stepResults = runbook.steps.map(step => ({
324
344
  stepId: step.id,
325
345
  status: StepStatus.PENDING,
326
346
  startedAt: null,
327
347
  completedAt: null,
328
348
  output: null,
329
- error: null
349
+ error: null,
330
350
  }));
331
-
351
+
332
352
  this.currentStepIndex = 0;
333
353
  }
334
354
 
@@ -355,13 +375,13 @@ class RunbookExecution {
355
375
  result.output = output;
356
376
  this.currentStepIndex++;
357
377
  }
358
-
378
+
359
379
  // Check if all steps completed
360
380
  if (this.currentStepIndex >= this.runbook.steps.length) {
361
381
  this.status = 'completed';
362
382
  this.completedAt = new Date();
363
383
  }
364
-
384
+
365
385
  return this;
366
386
  }
367
387
 
@@ -375,7 +395,7 @@ class RunbookExecution {
375
395
  result.completedAt = new Date();
376
396
  result.error = error;
377
397
  }
378
-
398
+
379
399
  // Get step config to determine action
380
400
  const step = this.runbook.steps.find(s => s.id === stepId);
381
401
  if (step && step.onFailure === 'abort') {
@@ -384,7 +404,7 @@ class RunbookExecution {
384
404
  } else if (step && step.onFailure === 'continue') {
385
405
  this.currentStepIndex++;
386
406
  }
387
-
407
+
388
408
  return this;
389
409
  }
390
410
 
@@ -416,16 +436,15 @@ class RunbookExecution {
416
436
  * Get execution progress
417
437
  */
418
438
  getProgress() {
419
- const completed = this.stepResults.filter(r =>
420
- r.status === StepStatus.COMPLETED ||
421
- r.status === StepStatus.SKIPPED
439
+ const completed = this.stepResults.filter(
440
+ r => r.status === StepStatus.COMPLETED || r.status === StepStatus.SKIPPED
422
441
  ).length;
423
-
442
+
424
443
  return {
425
444
  total: this.runbook.steps.length,
426
445
  completed,
427
446
  percentage: Math.round((completed / this.runbook.steps.length) * 100),
428
- currentStep: this.getCurrentStep()
447
+ currentStep: this.getCurrentStep(),
429
448
  };
430
449
  }
431
450
 
@@ -439,7 +458,7 @@ class RunbookExecution {
439
458
  completedAt: this.completedAt,
440
459
  status: this.status,
441
460
  stepResults: this.stepResults,
442
- progress: this.getProgress()
461
+ progress: this.getProgress(),
443
462
  };
444
463
  }
445
464
  }
@@ -454,30 +473,30 @@ class PostMortem {
454
473
  this.title = `Post-Mortem: ${incident.title}`;
455
474
  this.createdAt = new Date();
456
475
  this.status = 'draft';
457
-
476
+
458
477
  // Auto-populate from incident
459
478
  this.summary = {
460
479
  severity: incident.severity,
461
480
  duration: incident.getMetrics().totalDuration,
462
481
  affectedServices: incident.affectedServices,
463
- customerImpact: incident.customerImpact
482
+ customerImpact: incident.customerImpact,
464
483
  };
465
-
484
+
466
485
  this.timeline = incident.timeline;
467
486
  this.rootCause = incident.rootCause || 'TBD';
468
487
  this.resolution = incident.resolution || 'TBD';
469
-
488
+
470
489
  this.detection = {
471
490
  method: 'TBD',
472
- timeToDetect: incident.getMetrics().timeToAcknowledge
491
+ timeToDetect: incident.getMetrics().timeToAcknowledge,
473
492
  };
474
-
493
+
475
494
  this.response = {
476
495
  responders: incident.responders,
477
496
  commander: incident.commander,
478
- timeToMitigate: incident.getMetrics().timeToMitigate
497
+ timeToMitigate: incident.getMetrics().timeToMitigate,
479
498
  };
480
-
499
+
481
500
  this.actionItems = [];
482
501
  this.lessonsLearned = [];
483
502
  this.whatWentWell = [];
@@ -496,7 +515,7 @@ class PostMortem {
496
515
  priority: item.priority || 'medium',
497
516
  dueDate: item.dueDate || null,
498
517
  status: 'open',
499
- createdAt: new Date()
518
+ createdAt: new Date(),
500
519
  });
501
520
  return this;
502
521
  }
@@ -611,7 +630,7 @@ class PostMortem {
611
630
  whatWentWell: this.whatWentWell,
612
631
  whatWentPoorly: this.whatWentPoorly,
613
632
  lessonsLearned: this.lessonsLearned,
614
- actionItems: this.actionItems
633
+ actionItems: this.actionItems,
615
634
  };
616
635
  }
617
636
  }
@@ -626,16 +645,16 @@ class IncidentManager extends EventEmitter {
626
645
  this.runbooks = new Map();
627
646
  this.executions = new Map();
628
647
  this.postMortems = new Map();
629
-
648
+
630
649
  this.oncall = {
631
650
  primary: options.primaryOncall || null,
632
651
  secondary: options.secondaryOncall || null,
633
- escalation: options.escalation || []
652
+ escalation: options.escalation || [],
634
653
  };
635
-
654
+
636
655
  this.options = {
637
656
  autoAcknowledgeTimeout: options.autoAcknowledgeTimeout || 300, // 5 minutes
638
- ...options
657
+ ...options,
639
658
  };
640
659
  }
641
660
 
@@ -646,16 +665,16 @@ class IncidentManager extends EventEmitter {
646
665
  const incident = options instanceof Incident ? options : new Incident(options);
647
666
  this.incidents.set(incident.id, incident);
648
667
  this.emit('incidentCreated', incident);
649
-
668
+
650
669
  // Auto-notify on-call
651
670
  if (this.oncall.primary) {
652
671
  this.emit('notify', {
653
672
  type: 'incident',
654
673
  incident,
655
- recipient: this.oncall.primary
674
+ recipient: this.oncall.primary,
656
675
  });
657
676
  }
658
-
677
+
659
678
  return incident;
660
679
  }
661
680
 
@@ -671,7 +690,7 @@ class IncidentManager extends EventEmitter {
671
690
  */
672
691
  listIncidents(filter = {}) {
673
692
  let incidents = [...this.incidents.values()];
674
-
693
+
675
694
  if (filter.status) {
676
695
  const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
677
696
  incidents = incidents.filter(i => statuses.includes(i.status));
@@ -681,12 +700,11 @@ class IncidentManager extends EventEmitter {
681
700
  incidents = incidents.filter(i => severities.includes(i.severity));
682
701
  }
683
702
  if (filter.open) {
684
- incidents = incidents.filter(i =>
685
- i.status !== IncidentStatus.RESOLVED &&
686
- i.status !== IncidentStatus.CLOSED
703
+ incidents = incidents.filter(
704
+ i => i.status !== IncidentStatus.RESOLVED && i.status !== IncidentStatus.CLOSED
687
705
  );
688
706
  }
689
-
707
+
690
708
  return incidents.map(i => i.toJSON());
691
709
  }
692
710
 
@@ -696,7 +714,7 @@ class IncidentManager extends EventEmitter {
696
714
  acknowledgeIncident(incidentId, responder) {
697
715
  const incident = this.incidents.get(incidentId);
698
716
  if (!incident) throw new Error(`Incident not found: ${incidentId}`);
699
-
717
+
700
718
  incident.acknowledge(responder);
701
719
  this.emit('incidentAcknowledged', incident);
702
720
  return incident;
@@ -708,7 +726,7 @@ class IncidentManager extends EventEmitter {
708
726
  updateIncidentStatus(incidentId, newStatus, note = '', actor = 'system') {
709
727
  const incident = this.incidents.get(incidentId);
710
728
  if (!incident) throw new Error(`Incident not found: ${incidentId}`);
711
-
729
+
712
730
  incident.updateStatus(newStatus, note, actor);
713
731
  this.emit('incidentStatusChanged', { incident, newStatus });
714
732
  return incident;
@@ -720,7 +738,7 @@ class IncidentManager extends EventEmitter {
720
738
  resolveIncident(incidentId, resolution, actor = 'system') {
721
739
  const incident = this.incidents.get(incidentId);
722
740
  if (!incident) throw new Error(`Incident not found: ${incidentId}`);
723
-
741
+
724
742
  incident.setResolution(resolution, actor);
725
743
  this.emit('incidentResolved', incident);
726
744
  return incident;
@@ -748,14 +766,14 @@ class IncidentManager extends EventEmitter {
748
766
  */
749
767
  listRunbooks(filter = {}) {
750
768
  let runbooks = [...this.runbooks.values()];
751
-
769
+
752
770
  if (filter.category) {
753
771
  runbooks = runbooks.filter(r => r.category === filter.category);
754
772
  }
755
773
  if (filter.tag) {
756
774
  runbooks = runbooks.filter(r => r.tags.includes(filter.tag));
757
775
  }
758
-
776
+
759
777
  return runbooks.map(r => r.toJSON());
760
778
  }
761
779
 
@@ -765,16 +783,16 @@ class IncidentManager extends EventEmitter {
765
783
  executeRunbook(runbookId, incident = null) {
766
784
  const runbook = this.runbooks.get(runbookId);
767
785
  if (!runbook) throw new Error(`Runbook not found: ${runbookId}`);
768
-
786
+
769
787
  const execution = new RunbookExecution(runbook, incident);
770
788
  this.executions.set(execution.id, execution);
771
789
  this.emit('runbookExecutionStarted', execution);
772
-
790
+
773
791
  // Link to incident if provided
774
792
  if (incident) {
775
793
  incident.addUpdate(`Runbook "${runbook.name}" execution started`, 'system');
776
794
  }
777
-
795
+
778
796
  return execution;
779
797
  }
780
798
 
@@ -791,11 +809,11 @@ class IncidentManager extends EventEmitter {
791
809
  createPostMortem(incidentId) {
792
810
  const incident = this.incidents.get(incidentId);
793
811
  if (!incident) throw new Error(`Incident not found: ${incidentId}`);
794
-
812
+
795
813
  const postMortem = new PostMortem(incident);
796
814
  this.postMortems.set(postMortem.id, postMortem);
797
815
  incident.postMortem = postMortem.id;
798
-
816
+
799
817
  this.emit('postMortemCreated', postMortem);
800
818
  return postMortem;
801
819
  }
@@ -830,10 +848,8 @@ class IncidentManager extends EventEmitter {
830
848
  getStatistics(options = {}) {
831
849
  const incidents = [...this.incidents.values()];
832
850
  const { since } = options;
833
-
834
- const filtered = since
835
- ? incidents.filter(i => i.detectedAt >= since)
836
- : incidents;
851
+
852
+ const filtered = since ? incidents.filter(i => i.detectedAt >= since) : incidents;
837
853
 
838
854
  const metrics = filtered.map(i => i.getMetrics());
839
855
  const acknowledged = metrics.filter(m => m.timeToAcknowledge !== null);
@@ -841,15 +857,19 @@ class IncidentManager extends EventEmitter {
841
857
 
842
858
  return {
843
859
  total: filtered.length,
844
- open: filtered.filter(i => i.status !== IncidentStatus.CLOSED && i.status !== IncidentStatus.RESOLVED).length,
860
+ open: filtered.filter(
861
+ i => i.status !== IncidentStatus.CLOSED && i.status !== IncidentStatus.RESOLVED
862
+ ).length,
845
863
  bySeverity: this._countBy(filtered, 'severity'),
846
864
  byStatus: this._countBy(filtered, 'status'),
847
- mttr: resolved.length > 0
848
- ? resolved.reduce((sum, m) => sum + m.timeToResolve, 0) / resolved.length
849
- : null,
850
- mtta: acknowledged.length > 0
851
- ? acknowledged.reduce((sum, m) => sum + m.timeToAcknowledge, 0) / acknowledged.length
852
- : null
865
+ mttr:
866
+ resolved.length > 0
867
+ ? resolved.reduce((sum, m) => sum + m.timeToResolve, 0) / resolved.length
868
+ : null,
869
+ mtta:
870
+ acknowledged.length > 0
871
+ ? acknowledged.reduce((sum, m) => sum + m.timeToAcknowledge, 0) / acknowledged.length
872
+ : null,
853
873
  };
854
874
  }
855
875
 
@@ -879,12 +899,12 @@ module.exports = {
879
899
  RunbookExecution,
880
900
  PostMortem,
881
901
  IncidentManager,
882
-
902
+
883
903
  // Constants
884
904
  IncidentSeverity,
885
905
  IncidentStatus,
886
906
  StepStatus,
887
-
907
+
888
908
  // Factory
889
- createIncidentManager
909
+ createIncidentManager,
890
910
  };