@trentapps/manager-protocol 1.1.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 (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +446 -0
  3. package/dist/analyzers/ArchitectureDetector.d.ts +44 -0
  4. package/dist/analyzers/ArchitectureDetector.d.ts.map +1 -0
  5. package/dist/analyzers/ArchitectureDetector.js +218 -0
  6. package/dist/analyzers/ArchitectureDetector.js.map +1 -0
  7. package/dist/analyzers/CSSAnalyzer.d.ts +104 -0
  8. package/dist/analyzers/CSSAnalyzer.d.ts.map +1 -0
  9. package/dist/analyzers/CSSAnalyzer.js +578 -0
  10. package/dist/analyzers/CSSAnalyzer.js.map +1 -0
  11. package/dist/analyzers/index.d.ts +5 -0
  12. package/dist/analyzers/index.d.ts.map +1 -0
  13. package/dist/analyzers/index.js +5 -0
  14. package/dist/analyzers/index.js.map +1 -0
  15. package/dist/cli.d.ts +8 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +174 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/design-system/index.d.ts +6 -0
  20. package/dist/design-system/index.d.ts.map +1 -0
  21. package/dist/design-system/index.js +6 -0
  22. package/dist/design-system/index.js.map +1 -0
  23. package/dist/design-system/tokens.d.ts +106 -0
  24. package/dist/design-system/tokens.d.ts.map +1 -0
  25. package/dist/design-system/tokens.js +554 -0
  26. package/dist/design-system/tokens.js.map +1 -0
  27. package/dist/engine/AppMonitor.d.ts +162 -0
  28. package/dist/engine/AppMonitor.d.ts.map +1 -0
  29. package/dist/engine/AppMonitor.js +754 -0
  30. package/dist/engine/AppMonitor.js.map +1 -0
  31. package/dist/engine/AuditLogger.d.ts +138 -0
  32. package/dist/engine/AuditLogger.d.ts.map +1 -0
  33. package/dist/engine/AuditLogger.js +448 -0
  34. package/dist/engine/AuditLogger.js.map +1 -0
  35. package/dist/engine/GitHubApprovalManager.d.ts +106 -0
  36. package/dist/engine/GitHubApprovalManager.d.ts.map +1 -0
  37. package/dist/engine/GitHubApprovalManager.js +315 -0
  38. package/dist/engine/GitHubApprovalManager.js.map +1 -0
  39. package/dist/engine/RateLimiter.d.ts +79 -0
  40. package/dist/engine/RateLimiter.d.ts.map +1 -0
  41. package/dist/engine/RateLimiter.js +232 -0
  42. package/dist/engine/RateLimiter.js.map +1 -0
  43. package/dist/engine/RulesEngine.d.ts +77 -0
  44. package/dist/engine/RulesEngine.d.ts.map +1 -0
  45. package/dist/engine/RulesEngine.js +400 -0
  46. package/dist/engine/RulesEngine.js.map +1 -0
  47. package/dist/engine/TaskManager.d.ts +173 -0
  48. package/dist/engine/TaskManager.d.ts.map +1 -0
  49. package/dist/engine/TaskManager.js +678 -0
  50. package/dist/engine/TaskManager.js.map +1 -0
  51. package/dist/engine/index.d.ts +9 -0
  52. package/dist/engine/index.d.ts.map +1 -0
  53. package/dist/engine/index.js +9 -0
  54. package/dist/engine/index.js.map +1 -0
  55. package/dist/index.d.ts +21 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +29 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/rules/architecture.d.ts +9 -0
  60. package/dist/rules/architecture.d.ts.map +1 -0
  61. package/dist/rules/architecture.js +322 -0
  62. package/dist/rules/architecture.js.map +1 -0
  63. package/dist/rules/azure.d.ts +7 -0
  64. package/dist/rules/azure.d.ts.map +1 -0
  65. package/dist/rules/azure.js +138 -0
  66. package/dist/rules/azure.js.map +1 -0
  67. package/dist/rules/compliance.d.ts +9 -0
  68. package/dist/rules/compliance.d.ts.map +1 -0
  69. package/dist/rules/compliance.js +304 -0
  70. package/dist/rules/compliance.js.map +1 -0
  71. package/dist/rules/css.d.ts +10 -0
  72. package/dist/rules/css.d.ts.map +1 -0
  73. package/dist/rules/css.js +1239 -0
  74. package/dist/rules/css.js.map +1 -0
  75. package/dist/rules/flask.d.ts +7 -0
  76. package/dist/rules/flask.d.ts.map +1 -0
  77. package/dist/rules/flask.js +155 -0
  78. package/dist/rules/flask.js.map +1 -0
  79. package/dist/rules/index.d.ts +607 -0
  80. package/dist/rules/index.d.ts.map +1 -0
  81. package/dist/rules/index.js +401 -0
  82. package/dist/rules/index.js.map +1 -0
  83. package/dist/rules/ml-ai.d.ts +7 -0
  84. package/dist/rules/ml-ai.d.ts.map +1 -0
  85. package/dist/rules/ml-ai.js +150 -0
  86. package/dist/rules/ml-ai.js.map +1 -0
  87. package/dist/rules/operational.d.ts +9 -0
  88. package/dist/rules/operational.d.ts.map +1 -0
  89. package/dist/rules/operational.js +318 -0
  90. package/dist/rules/operational.js.map +1 -0
  91. package/dist/rules/security.d.ts +9 -0
  92. package/dist/rules/security.d.ts.map +1 -0
  93. package/dist/rules/security.js +287 -0
  94. package/dist/rules/security.js.map +1 -0
  95. package/dist/rules/storage.d.ts +7 -0
  96. package/dist/rules/storage.d.ts.map +1 -0
  97. package/dist/rules/storage.js +134 -0
  98. package/dist/rules/storage.js.map +1 -0
  99. package/dist/rules/stripe.d.ts +7 -0
  100. package/dist/rules/stripe.d.ts.map +1 -0
  101. package/dist/rules/stripe.js +140 -0
  102. package/dist/rules/stripe.js.map +1 -0
  103. package/dist/rules/testing.d.ts +7 -0
  104. package/dist/rules/testing.d.ts.map +1 -0
  105. package/dist/rules/testing.js +135 -0
  106. package/dist/rules/testing.js.map +1 -0
  107. package/dist/rules/ux.d.ts +9 -0
  108. package/dist/rules/ux.d.ts.map +1 -0
  109. package/dist/rules/ux.js +280 -0
  110. package/dist/rules/ux.js.map +1 -0
  111. package/dist/rules/websocket.d.ts +7 -0
  112. package/dist/rules/websocket.d.ts.map +1 -0
  113. package/dist/rules/websocket.js +136 -0
  114. package/dist/rules/websocket.js.map +1 -0
  115. package/dist/server.d.ts +49 -0
  116. package/dist/server.d.ts.map +1 -0
  117. package/dist/server.js +2330 -0
  118. package/dist/server.js.map +1 -0
  119. package/dist/supervisor/AgentSupervisor.d.ts +235 -0
  120. package/dist/supervisor/AgentSupervisor.d.ts.map +1 -0
  121. package/dist/supervisor/AgentSupervisor.js +596 -0
  122. package/dist/supervisor/AgentSupervisor.js.map +1 -0
  123. package/dist/supervisor/ManagedServerRegistry.d.ts +48 -0
  124. package/dist/supervisor/ManagedServerRegistry.d.ts.map +1 -0
  125. package/dist/supervisor/ManagedServerRegistry.js +145 -0
  126. package/dist/supervisor/ManagedServerRegistry.js.map +1 -0
  127. package/dist/supervisor/ProjectTracker.d.ts +188 -0
  128. package/dist/supervisor/ProjectTracker.d.ts.map +1 -0
  129. package/dist/supervisor/ProjectTracker.js +617 -0
  130. package/dist/supervisor/ProjectTracker.js.map +1 -0
  131. package/dist/supervisor/index.d.ts +6 -0
  132. package/dist/supervisor/index.d.ts.map +1 -0
  133. package/dist/supervisor/index.js +6 -0
  134. package/dist/supervisor/index.js.map +1 -0
  135. package/dist/types/index.d.ts +1176 -0
  136. package/dist/types/index.d.ts.map +1 -0
  137. package/dist/types/index.js +391 -0
  138. package/dist/types/index.js.map +1 -0
  139. package/dist/utils/errors.d.ts +86 -0
  140. package/dist/utils/errors.d.ts.map +1 -0
  141. package/dist/utils/errors.js +171 -0
  142. package/dist/utils/errors.js.map +1 -0
  143. package/dist/utils/index.d.ts +5 -0
  144. package/dist/utils/index.d.ts.map +1 -0
  145. package/dist/utils/index.js +5 -0
  146. package/dist/utils/index.js.map +1 -0
  147. package/dist/utils/shell.d.ts +22 -0
  148. package/dist/utils/shell.d.ts.map +1 -0
  149. package/dist/utils/shell.js +29 -0
  150. package/dist/utils/shell.js.map +1 -0
  151. package/package.json +63 -0
package/dist/server.js ADDED
@@ -0,0 +1,2330 @@
1
+ /**
2
+ * Enterprise Agent Supervisor - MCP Server
3
+ *
4
+ * Model Context Protocol server exposing agent governance tools.
5
+ */
6
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
9
+ import { AgentSupervisor } from './supervisor/AgentSupervisor.js';
10
+ import { projectTracker } from './supervisor/ProjectTracker.js';
11
+ import { rulePresets } from './rules/index.js';
12
+ import { taskManager } from './engine/TaskManager.js';
13
+ import { cssAnalyzer } from './analyzers/index.js';
14
+ import { z } from 'zod';
15
+ import { AgentActionSchema, BusinessContextSchema, BusinessRuleSchema, RateLimitConfigSchema, AuditEventTypeSchema } from './types/index.js';
16
+ // Initialize supervisor
17
+ const supervisor = new AgentSupervisor({
18
+ config: {
19
+ environment: process.env.NODE_ENV || 'development'
20
+ },
21
+ auditOptions: {
22
+ enableConsoleLog: process.env.DEBUG === 'true',
23
+ dbPath: process.env.AUDIT_DB_PATH || '/tmp/agent-supervisor/audit.db'
24
+ }
25
+ });
26
+ // ============================================================================
27
+ // COMPACT RESPONSE HELPERS - Keep MCP responses concise
28
+ // ============================================================================
29
+ /** Compact JSON (no pretty printing) */
30
+ const json = (obj) => JSON.stringify(obj);
31
+ /** MCP text response wrapper */
32
+ const resp = (obj) => ({ content: [{ type: 'text', text: json(obj) }] });
33
+ /** Slim task: only essential fields */
34
+ const slimTask = (t) => ({
35
+ id: t.id,
36
+ title: t.title,
37
+ status: t.status,
38
+ priority: t.priority,
39
+ labels: t.labels,
40
+ url: t.metadata?.url
41
+ });
42
+ /** Slim evaluation result */
43
+ const slimEval = (r) => ({
44
+ status: r.status,
45
+ riskScore: r.riskScore,
46
+ riskLevel: r.riskLevel,
47
+ allowed: r.allowed,
48
+ requiresHumanApproval: r.requiresHumanApproval,
49
+ violations: r.violations?.map((v) => ({ rule: v.ruleId, msg: v.message })),
50
+ warnings: r.warnings
51
+ });
52
+ // ============================================================================
53
+ // MCP TOOL ARGUMENT VALIDATION SCHEMAS
54
+ // ============================================================================
55
+ const EvaluateActionArgsSchema = z.object({
56
+ action: AgentActionSchema,
57
+ context: BusinessContextSchema.optional()
58
+ });
59
+ const ApplyBusinessRulesArgsSchema = z.object({
60
+ context: BusinessContextSchema
61
+ });
62
+ const RequireHumanApprovalArgsSchema = z.object({
63
+ reason: z.string(),
64
+ actionId: z.string().optional(),
65
+ details: z.string().optional(),
66
+ priority: z.enum(['urgent', 'high', 'normal', 'low']).optional(),
67
+ riskScore: z.number().min(0).max(100).optional(),
68
+ context: BusinessContextSchema.optional(),
69
+ metadata: z.record(z.unknown()).optional()
70
+ });
71
+ const LogEventArgsSchema = z.object({
72
+ action: z.string(),
73
+ eventType: AuditEventTypeSchema.optional(),
74
+ agentId: z.string().optional(),
75
+ sessionId: z.string().optional(),
76
+ userId: z.string().optional(),
77
+ outcome: z.enum(['success', 'failure', 'pending']).optional(),
78
+ metadata: z.record(z.unknown()).optional()
79
+ });
80
+ const AddRuleArgsSchema = z.object({
81
+ rule: BusinessRuleSchema
82
+ });
83
+ const LoadPresetArgsSchema = z.object({
84
+ preset: z.enum(['minimal', 'standard', 'strict', 'financial', 'healthcare', 'development'])
85
+ });
86
+ const GetAuditEventsArgsSchema = z.object({
87
+ eventType: AuditEventTypeSchema.optional(),
88
+ agentId: z.string().optional(),
89
+ sessionId: z.string().optional(),
90
+ userId: z.string().optional(),
91
+ outcome: z.enum(['success', 'failure', 'pending']).optional(),
92
+ since: z.string().optional(),
93
+ until: z.string().optional(),
94
+ limit: z.number().min(1).max(1000).optional()
95
+ });
96
+ const UpdateConfigArgsSchema = z.object({
97
+ strictMode: z.boolean().optional(),
98
+ defaultRiskThreshold: z.number().min(0).max(100).optional(),
99
+ requireApprovalAboveRisk: z.number().min(0).max(100).optional(),
100
+ features: z.object({
101
+ riskScoring: z.boolean(),
102
+ rateLimiting: z.boolean(),
103
+ auditLogging: z.boolean(),
104
+ humanApproval: z.boolean(),
105
+ complianceChecks: z.boolean(),
106
+ uxValidation: z.boolean(),
107
+ architectureValidation: z.boolean()
108
+ }).partial().optional()
109
+ });
110
+ const AddRateLimitArgsSchema = z.object({
111
+ config: RateLimitConfigSchema
112
+ });
113
+ const AddMonitoredAppArgsSchema = z.object({
114
+ name: z.string().min(1),
115
+ path: z.string().min(1),
116
+ port: z.number().min(1).max(65535),
117
+ description: z.string().optional(),
118
+ healthEndpoint: z.string().optional(),
119
+ expectedResponseCode: z.number().optional(),
120
+ checkIntervalMs: z.number().min(5000).optional(),
121
+ timeoutMs: z.number().min(1000).optional(),
122
+ autoStart: z.boolean().optional(),
123
+ tags: z.array(z.string()).optional(),
124
+ metadata: z.record(z.unknown()).optional()
125
+ });
126
+ const UpdateMonitoredAppArgsSchema = z.object({
127
+ appId: z.string(),
128
+ updates: z.object({
129
+ name: z.string().optional(),
130
+ description: z.string().optional(),
131
+ healthEndpoint: z.string().optional(),
132
+ expectedResponseCode: z.number().optional(),
133
+ checkIntervalMs: z.number().min(5000).optional(),
134
+ timeoutMs: z.number().min(1000).optional(),
135
+ enabled: z.boolean().optional(),
136
+ tags: z.array(z.string()).optional(),
137
+ metadata: z.record(z.unknown()).optional()
138
+ })
139
+ });
140
+ const ExportAuditLogArgsSchema = z.object({
141
+ since: z.string().optional(),
142
+ until: z.string().optional(),
143
+ eventType: AuditEventTypeSchema.optional()
144
+ });
145
+ const GetAppStatusArgsSchema = z.object({
146
+ appId: z.string().optional(),
147
+ appName: z.string().optional(),
148
+ historyLimit: z.number().optional()
149
+ }).refine(data => data.appId || data.appName, {
150
+ message: "Either appId or appName must be provided"
151
+ });
152
+ const CheckAppHealthArgsSchema = z.object({
153
+ appId: z.string().optional(),
154
+ appName: z.string().optional()
155
+ }).refine(data => data.appId || data.appName, {
156
+ message: "Either appId or appName must be provided"
157
+ });
158
+ const ApproveRequestArgsSchema = z.object({
159
+ requestId: z.string(),
160
+ approverId: z.string(),
161
+ comments: z.string().optional(),
162
+ repo: z.string().optional()
163
+ });
164
+ const DenyRequestArgsSchema = z.object({
165
+ requestId: z.string(),
166
+ denierId: z.string(),
167
+ reason: z.string().optional(),
168
+ repo: z.string().optional()
169
+ });
170
+ const RemoveRuleArgsSchema = z.object({
171
+ ruleId: z.string()
172
+ });
173
+ const GetAuditStatsArgsSchema = z.object({
174
+ since: z.string().optional()
175
+ });
176
+ const RemoveMonitoredAppArgsSchema = z.object({
177
+ appId: z.string()
178
+ });
179
+ const SetAppMonitoringEnabledArgsSchema = z.object({
180
+ appId: z.string(),
181
+ enabled: z.boolean()
182
+ });
183
+ const GetAppLogsArgsSchema = z.object({
184
+ appId: z.string().optional(),
185
+ appName: z.string().optional(),
186
+ lines: z.number().optional()
187
+ }).refine(data => data.appId || data.appName, {
188
+ message: "Either appId or appName must be provided"
189
+ });
190
+ const GetAppStatusHistoryArgsSchema = z.object({
191
+ appId: z.string().optional(),
192
+ appName: z.string().optional(),
193
+ limit: z.number().optional()
194
+ }).refine(data => data.appId || data.appName, {
195
+ message: "Either appId or appName must be provided"
196
+ });
197
+ // Task management schemas
198
+ const CreateTaskArgsSchema = z.object({
199
+ projectName: z.string().optional(),
200
+ title: z.string(),
201
+ description: z.string().optional(),
202
+ priority: z.enum(['critical', 'high', 'medium', 'low']).optional(),
203
+ assignee: z.string().optional(),
204
+ labels: z.array(z.string()).optional(),
205
+ dueDate: z.string().optional(),
206
+ estimatedHours: z.number().optional(),
207
+ parentTaskId: z.string().optional(),
208
+ dependencies: z.array(z.string()).optional(),
209
+ metadata: z.record(z.unknown()).optional(),
210
+ needsApproval: z.boolean().optional()
211
+ });
212
+ const GetTasksArgsSchema = z.object({
213
+ projectName: z.string().optional(),
214
+ status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled']).optional(),
215
+ priority: z.enum(['critical', 'high', 'medium', 'low']).optional(),
216
+ assignee: z.string().optional(),
217
+ labels: z.array(z.string()).optional()
218
+ });
219
+ const GetTaskArgsSchema = z.object({
220
+ projectName: z.string().optional(),
221
+ taskId: z.string()
222
+ });
223
+ const UpdateTaskArgsSchema = z.object({
224
+ projectName: z.string().optional(),
225
+ taskId: z.string(),
226
+ title: z.string().optional(),
227
+ description: z.string().optional(),
228
+ priority: z.enum(['critical', 'high', 'medium', 'low']).optional(),
229
+ status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled']).optional(),
230
+ assignee: z.string().optional(),
231
+ labels: z.array(z.string()).optional(),
232
+ comment: z.string().optional(),
233
+ commits: z.array(z.string()).optional()
234
+ });
235
+ const UpdateTaskStatusArgsSchema = z.object({
236
+ projectName: z.string().optional(),
237
+ taskId: z.string(),
238
+ status: z.enum(['pending', 'in_progress', 'completed', 'blocked', 'cancelled'])
239
+ });
240
+ const AddTaskCommentArgsSchema = z.object({
241
+ projectName: z.string().optional(),
242
+ taskId: z.string(),
243
+ comment: z.string().optional(),
244
+ commits: z.array(z.string()).optional()
245
+ });
246
+ const LinkCommitsArgsSchema = z.object({
247
+ projectName: z.string().optional(),
248
+ taskId: z.string(),
249
+ commits: z.array(z.string()),
250
+ message: z.string().optional()
251
+ });
252
+ const CloseTaskWithCommentArgsSchema = z.object({
253
+ projectName: z.string().optional(),
254
+ taskId: z.string(),
255
+ resolution: z.string(),
256
+ commits: z.array(z.string()).optional()
257
+ });
258
+ const SearchTasksArgsSchema = z.object({
259
+ query: z.string(),
260
+ projectName: z.string().optional()
261
+ });
262
+ // Define MCP tools
263
+ const tools = [
264
+ // ============================================================================
265
+ // CORE GOVERNANCE TOOLS
266
+ // ============================================================================
267
+ {
268
+ name: 'evaluate_action',
269
+ description: `Evaluate an agent action against governance rules. Returns risk score, approval status, violations, and recommendations.
270
+
271
+ Use this BEFORE executing any significant agent action to ensure compliance and safety.
272
+
273
+ Returns:
274
+ - status: approved | denied | pending_approval | rate_limited | requires_review
275
+ - riskScore: 0-100 numeric score
276
+ - riskLevel: critical | high | medium | low | minimal
277
+ - violations: Array of rule violations
278
+ - warnings: Array of warnings
279
+ - requiresHumanApproval: Whether human approval is needed`,
280
+ inputSchema: {
281
+ type: 'object',
282
+ properties: {
283
+ action: {
284
+ type: 'object',
285
+ description: 'The agent action to evaluate',
286
+ properties: {
287
+ name: { type: 'string', description: 'Name of the action (e.g., "read_file", "call_api")' },
288
+ category: {
289
+ type: 'string',
290
+ enum: ['data_access', 'data_modification', 'external_api', 'file_system', 'code_execution', 'network', 'authentication', 'authorization', 'financial', 'pii_access', 'system_config', 'user_communication', 'resource_allocation', 'custom'],
291
+ description: 'Category of the action'
292
+ },
293
+ description: { type: 'string', description: 'Human-readable description' },
294
+ parameters: { type: 'object', description: 'Action parameters/arguments' },
295
+ agentId: { type: 'string', description: 'ID of the agent performing action' },
296
+ sessionId: { type: 'string', description: 'Current session ID' },
297
+ metadata: { type: 'object', description: 'Additional metadata' }
298
+ },
299
+ required: ['name', 'category']
300
+ },
301
+ context: {
302
+ type: 'object',
303
+ description: 'Business context for evaluation',
304
+ properties: {
305
+ environment: { type: 'string', enum: ['development', 'staging', 'production'] },
306
+ agentId: { type: 'string' },
307
+ agentType: { type: 'string' },
308
+ userId: { type: 'string' },
309
+ userRole: { type: 'string' },
310
+ sessionId: { type: 'string' },
311
+ organizationId: { type: 'string' },
312
+ department: { type: 'string' },
313
+ dataClassification: { type: 'string', enum: ['public', 'internal', 'confidential', 'restricted'] },
314
+ complianceFrameworks: { type: 'array', items: { type: 'string' } }
315
+ }
316
+ }
317
+ },
318
+ required: ['action']
319
+ }
320
+ },
321
+ {
322
+ name: 'apply_business_rules',
323
+ description: `Apply business rules to a context to determine constraints and recommendations.
324
+
325
+ Use this to understand what rules apply to a given operational context before taking actions.
326
+
327
+ Returns:
328
+ - rulesApplied: Which rules matched
329
+ - constraints: Active constraints (prohibitions, requirements)
330
+ - recommendations: Suggested best practices
331
+ - aggregateRiskScore: Overall risk assessment`,
332
+ inputSchema: {
333
+ type: 'object',
334
+ properties: {
335
+ context: {
336
+ type: 'object',
337
+ description: 'Business context to evaluate',
338
+ properties: {
339
+ environment: { type: 'string', enum: ['development', 'staging', 'production'] },
340
+ agentId: { type: 'string' },
341
+ agentType: { type: 'string' },
342
+ userId: { type: 'string' },
343
+ userRole: { type: 'string' },
344
+ sessionId: { type: 'string' },
345
+ organizationId: { type: 'string' },
346
+ department: { type: 'string' },
347
+ costCenter: { type: 'string' },
348
+ dataClassification: { type: 'string', enum: ['public', 'internal', 'confidential', 'restricted'] },
349
+ complianceFrameworks: { type: 'array', items: { type: 'string' } },
350
+ customAttributes: { type: 'object' }
351
+ }
352
+ }
353
+ },
354
+ required: ['context']
355
+ }
356
+ },
357
+ {
358
+ name: 'require_human_approval',
359
+ description: `Request human approval for an action that requires oversight.
360
+
361
+ Use when an action is high-risk, outside normal parameters, or governance rules require human-in-the-loop.
362
+
363
+ Returns approval request ID that can be checked later.`,
364
+ inputSchema: {
365
+ type: 'object',
366
+ properties: {
367
+ reason: { type: 'string', description: 'Why human approval is needed' },
368
+ actionId: { type: 'string', description: 'ID of the action requiring approval' },
369
+ details: { type: 'string', description: 'Detailed explanation for approver' },
370
+ priority: {
371
+ type: 'string',
372
+ enum: ['urgent', 'high', 'normal', 'low'],
373
+ description: 'Priority of approval request'
374
+ },
375
+ context: {
376
+ type: 'object',
377
+ description: 'Business context'
378
+ },
379
+ riskScore: { type: 'number', minimum: 0, maximum: 100, description: 'Risk score if known' },
380
+ metadata: { type: 'object', description: 'Additional metadata' }
381
+ },
382
+ required: ['reason']
383
+ }
384
+ },
385
+ {
386
+ name: 'log_event',
387
+ description: `Log an audit event for compliance and observability.
388
+
389
+ Use to record significant actions, decisions, and outcomes for audit trail.
390
+
391
+ All logged events are queryable and exportable.`,
392
+ inputSchema: {
393
+ type: 'object',
394
+ properties: {
395
+ action: { type: 'string', description: 'Name/description of the action being logged' },
396
+ eventType: {
397
+ type: 'string',
398
+ enum: ['action_evaluated', 'action_approved', 'action_denied', 'action_executed', 'rule_triggered', 'approval_requested', 'approval_granted', 'approval_denied', 'rate_limit_hit', 'security_alert', 'compliance_violation', 'config_changed', 'system_event', 'custom'],
399
+ description: 'Type of event'
400
+ },
401
+ outcome: {
402
+ type: 'string',
403
+ enum: ['success', 'failure', 'pending'],
404
+ description: 'Outcome of the action'
405
+ },
406
+ agentId: { type: 'string' },
407
+ sessionId: { type: 'string' },
408
+ userId: { type: 'string' },
409
+ metadata: { type: 'object', description: 'Additional metadata to log' }
410
+ },
411
+ required: ['action']
412
+ }
413
+ },
414
+ // ============================================================================
415
+ // APPROVAL MANAGEMENT TOOLS
416
+ // ============================================================================
417
+ {
418
+ name: 'check_approval_status',
419
+ description: 'Check the status of a pending approval request',
420
+ inputSchema: {
421
+ type: 'object',
422
+ properties: {
423
+ requestId: { type: 'string', description: 'ID of the approval request' },
424
+ issueNumber: { type: 'number', description: 'GitHub issue number (alternative to requestId)' },
425
+ repo: { type: 'string', description: 'Repository in owner/repo format (required for GitHub-based approvals)' }
426
+ }
427
+ }
428
+ },
429
+ {
430
+ name: 'list_pending_approvals',
431
+ description: 'List all pending approval requests',
432
+ inputSchema: {
433
+ type: 'object',
434
+ properties: {
435
+ priority: { type: 'string', enum: ['urgent', 'high', 'normal', 'low'] },
436
+ agentId: { type: 'string' },
437
+ minRiskScore: { type: 'number', minimum: 0, maximum: 100 },
438
+ repo: { type: 'string', description: 'Repository in owner/repo format (required for GitHub-based approvals)' }
439
+ }
440
+ }
441
+ },
442
+ {
443
+ name: 'approve_request',
444
+ description: 'Approve a pending approval request (requires approver privileges)',
445
+ inputSchema: {
446
+ type: 'object',
447
+ properties: {
448
+ requestId: { type: 'string', description: 'ID of the request to approve (or issue number)' },
449
+ approverId: { type: 'string', description: 'ID of the approver' },
450
+ comments: { type: 'string', description: 'Approval comments' },
451
+ repo: { type: 'string', description: 'Repository in owner/repo format (required for GitHub-based approvals)' }
452
+ },
453
+ required: ['requestId', 'approverId']
454
+ }
455
+ },
456
+ {
457
+ name: 'deny_request',
458
+ description: 'Deny a pending approval request',
459
+ inputSchema: {
460
+ type: 'object',
461
+ properties: {
462
+ requestId: { type: 'string', description: 'ID of the request to deny (or issue number)' },
463
+ denierId: { type: 'string', description: 'ID of the denier' },
464
+ reason: { type: 'string', description: 'Reason for denial' },
465
+ repo: { type: 'string', description: 'Repository in owner/repo format (required for GitHub-based approvals)' }
466
+ },
467
+ required: ['requestId', 'denierId']
468
+ }
469
+ },
470
+ // ============================================================================
471
+ // RULE MANAGEMENT TOOLS
472
+ // ============================================================================
473
+ {
474
+ name: 'list_rules',
475
+ description: `List configured governance rules with advanced filtering.
476
+
477
+ IMPORTANT: Use filtering to reduce result size. Without filters, returns 190+ rules!
478
+
479
+ Filters:
480
+ - profile: Get rules for specific tech stack (flask, dotnet-azure, react, playwright, ml-ai, stripe, websocket, fullstack, api)
481
+ - preset: Use predefined rule sets (minimal, standard, strict, financial, healthcare, development, frontend)
482
+ - type: Filter by rule category
483
+ - enabled: Filter by enabled status
484
+ - tags: Filter by tags array
485
+ - minPriority: Minimum priority threshold (0-1000)
486
+ - maxPriority: Maximum priority threshold
487
+ - limit: Limit number of results (default: 50, max: 200)
488
+ - summary: Return summary only (rule counts by type)`,
489
+ inputSchema: {
490
+ type: 'object',
491
+ properties: {
492
+ profile: {
493
+ type: 'string',
494
+ enum: ['flask', 'dotnet-azure', 'react', 'playwright', 'ml-ai', 'stripe', 'websocket', 'fullstack', 'api'],
495
+ description: 'Filter by project profile/tech stack'
496
+ },
497
+ preset: {
498
+ type: 'string',
499
+ enum: ['minimal', 'standard', 'strict', 'financial', 'healthcare', 'development', 'frontend'],
500
+ description: 'Use predefined rule preset'
501
+ },
502
+ type: {
503
+ type: 'string',
504
+ enum: ['compliance', 'security', 'operational', 'financial', 'ux', 'architecture', 'data_governance', 'rate_limit', 'custom'],
505
+ description: 'Filter by rule type'
506
+ },
507
+ enabled: { type: 'boolean', description: 'Filter by enabled status' },
508
+ tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
509
+ minPriority: { type: 'number', minimum: 0, maximum: 1000, description: 'Minimum priority threshold' },
510
+ maxPriority: { type: 'number', minimum: 0, maximum: 1000, description: 'Maximum priority threshold' },
511
+ limit: { type: 'number', minimum: 1, maximum: 200, description: 'Limit number of results (default: 50)' },
512
+ summary: { type: 'boolean', description: 'Return summary only (counts by type)' }
513
+ }
514
+ }
515
+ },
516
+ {
517
+ name: 'list_project_profiles',
518
+ description: `List available project profiles with tech stack information.
519
+
520
+ Returns available profiles you can use with list_rules(profile=...) to get relevant rules for your project.
521
+
522
+ Profiles include: flask, dotnet-azure, react, playwright, ml-ai, stripe, websocket, fullstack, api`,
523
+ inputSchema: {
524
+ type: 'object',
525
+ properties: {}
526
+ }
527
+ },
528
+ {
529
+ name: 'discover_relevant_rules',
530
+ description: `Analyze a project directory and suggest relevant rule profiles based on detected technologies.
531
+
532
+ Scans package.json, *.csproj, requirements.txt, and other config files to detect tech stack.
533
+
534
+ Returns:
535
+ - detectedTechnologies: Array of detected technologies
536
+ - recommendedProfiles: Array of suggested project profiles
537
+ - ruleCount: Total number of relevant rules
538
+ - priorities: Suggested priority order for implementation`,
539
+ inputSchema: {
540
+ type: 'object',
541
+ properties: {
542
+ projectPath: {
543
+ type: 'string',
544
+ description: 'Path to project directory (e.g., /path/to/my-project)'
545
+ },
546
+ autoDetect: {
547
+ type: 'boolean',
548
+ description: 'Auto-detect technologies from project files (default: true)'
549
+ }
550
+ },
551
+ required: ['projectPath']
552
+ }
553
+ },
554
+ {
555
+ name: 'add_rule',
556
+ description: 'Add a custom governance rule',
557
+ inputSchema: {
558
+ type: 'object',
559
+ properties: {
560
+ rule: {
561
+ type: 'object',
562
+ properties: {
563
+ id: { type: 'string' },
564
+ name: { type: 'string' },
565
+ description: { type: 'string' },
566
+ type: { type: 'string', enum: ['compliance', 'security', 'operational', 'financial', 'ux', 'architecture', 'data_governance', 'rate_limit', 'custom'] },
567
+ enabled: { type: 'boolean' },
568
+ priority: { type: 'number', minimum: 0, maximum: 1000 },
569
+ conditions: {
570
+ type: 'array',
571
+ items: {
572
+ type: 'object',
573
+ properties: {
574
+ field: { type: 'string' },
575
+ operator: { type: 'string', enum: ['equals', 'not_equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'in', 'not_in', 'matches_regex', 'exists', 'not_exists', 'custom'] },
576
+ value: {}
577
+ }
578
+ }
579
+ },
580
+ conditionLogic: { type: 'string', enum: ['all', 'any'] },
581
+ actions: {
582
+ type: 'array',
583
+ items: {
584
+ type: 'object',
585
+ properties: {
586
+ type: { type: 'string', enum: ['allow', 'deny', 'require_approval', 'warn', 'log', 'rate_limit', 'transform', 'escalate', 'notify'] },
587
+ message: { type: 'string' }
588
+ }
589
+ }
590
+ },
591
+ riskWeight: { type: 'number', minimum: 0, maximum: 100 },
592
+ tags: { type: 'array', items: { type: 'string' } }
593
+ },
594
+ required: ['id', 'name', 'type', 'conditions', 'actions']
595
+ }
596
+ },
597
+ required: ['rule']
598
+ }
599
+ },
600
+ {
601
+ name: 'remove_rule',
602
+ description: 'Remove a governance rule',
603
+ inputSchema: {
604
+ type: 'object',
605
+ properties: {
606
+ ruleId: { type: 'string', description: 'ID of the rule to remove' }
607
+ },
608
+ required: ['ruleId']
609
+ }
610
+ },
611
+ {
612
+ name: 'load_preset',
613
+ description: 'Load a predefined rule preset (minimal, standard, strict, financial, healthcare, development)',
614
+ inputSchema: {
615
+ type: 'object',
616
+ properties: {
617
+ preset: {
618
+ type: 'string',
619
+ enum: ['minimal', 'standard', 'strict', 'financial', 'healthcare', 'development'],
620
+ description: 'Preset to load'
621
+ }
622
+ },
623
+ required: ['preset']
624
+ }
625
+ },
626
+ // ============================================================================
627
+ // AUDIT & REPORTING TOOLS
628
+ // ============================================================================
629
+ {
630
+ name: 'get_audit_events',
631
+ description: 'Query audit events with optional filters',
632
+ inputSchema: {
633
+ type: 'object',
634
+ properties: {
635
+ eventType: { type: 'string' },
636
+ agentId: { type: 'string' },
637
+ sessionId: { type: 'string' },
638
+ userId: { type: 'string' },
639
+ outcome: { type: 'string', enum: ['success', 'failure', 'pending'] },
640
+ since: { type: 'string', format: 'date-time' },
641
+ until: { type: 'string', format: 'date-time' },
642
+ limit: { type: 'number', minimum: 1, maximum: 1000 }
643
+ }
644
+ }
645
+ },
646
+ {
647
+ name: 'get_audit_stats',
648
+ description: 'Get audit statistics summary',
649
+ inputSchema: {
650
+ type: 'object',
651
+ properties: {
652
+ since: { type: 'string', format: 'date-time', description: 'Start time for stats' }
653
+ }
654
+ }
655
+ },
656
+ {
657
+ name: 'get_approval_stats',
658
+ description: 'Get approval workflow statistics',
659
+ inputSchema: {
660
+ type: 'object',
661
+ properties: {}
662
+ }
663
+ },
664
+ {
665
+ name: 'export_audit_log',
666
+ description: 'Export audit log as JSON',
667
+ inputSchema: {
668
+ type: 'object',
669
+ properties: {
670
+ since: { type: 'string', format: 'date-time' },
671
+ until: { type: 'string', format: 'date-time' },
672
+ eventType: { type: 'string' }
673
+ }
674
+ }
675
+ },
676
+ // ============================================================================
677
+ // CONFIGURATION TOOLS
678
+ // ============================================================================
679
+ {
680
+ name: 'get_config',
681
+ description: 'Get current supervisor configuration',
682
+ inputSchema: {
683
+ type: 'object',
684
+ properties: {}
685
+ }
686
+ },
687
+ {
688
+ name: 'update_config',
689
+ description: 'Update supervisor configuration',
690
+ inputSchema: {
691
+ type: 'object',
692
+ properties: {
693
+ strictMode: { type: 'boolean' },
694
+ defaultRiskThreshold: { type: 'number', minimum: 0, maximum: 100 },
695
+ requireApprovalAboveRisk: { type: 'number', minimum: 0, maximum: 100 },
696
+ features: {
697
+ type: 'object',
698
+ properties: {
699
+ riskScoring: { type: 'boolean' },
700
+ rateLimiting: { type: 'boolean' },
701
+ auditLogging: { type: 'boolean' },
702
+ humanApproval: { type: 'boolean' },
703
+ complianceChecks: { type: 'boolean' },
704
+ uxValidation: { type: 'boolean' },
705
+ architectureValidation: { type: 'boolean' }
706
+ }
707
+ }
708
+ }
709
+ }
710
+ },
711
+ // ============================================================================
712
+ // RATE LIMITING TOOLS
713
+ // ============================================================================
714
+ {
715
+ name: 'check_rate_limit',
716
+ description: 'Check rate limit status for an action',
717
+ inputSchema: {
718
+ type: 'object',
719
+ properties: {
720
+ agentId: { type: 'string' },
721
+ sessionId: { type: 'string' },
722
+ userId: { type: 'string' },
723
+ actionCategory: { type: 'string' }
724
+ }
725
+ }
726
+ },
727
+ {
728
+ name: 'add_rate_limit',
729
+ description: 'Add a rate limit configuration',
730
+ inputSchema: {
731
+ type: 'object',
732
+ properties: {
733
+ config: {
734
+ type: 'object',
735
+ properties: {
736
+ id: { type: 'string' },
737
+ name: { type: 'string' },
738
+ windowMs: { type: 'number', minimum: 1000 },
739
+ maxRequests: { type: 'number', minimum: 1 },
740
+ scope: { type: 'string', enum: ['global', 'agent', 'session', 'user', 'action_type'] },
741
+ actionCategories: { type: 'array', items: { type: 'string' } },
742
+ burstLimit: { type: 'number' },
743
+ enabled: { type: 'boolean' }
744
+ },
745
+ required: ['id', 'name', 'windowMs', 'maxRequests', 'scope']
746
+ }
747
+ },
748
+ required: ['config']
749
+ }
750
+ },
751
+ // ============================================================================
752
+ // RISK ASSESSMENT TOOLS
753
+ // ============================================================================
754
+ {
755
+ name: 'calculate_risk_score',
756
+ description: 'Calculate risk score for a hypothetical action without recording it',
757
+ inputSchema: {
758
+ type: 'object',
759
+ properties: {
760
+ action: {
761
+ type: 'object',
762
+ properties: {
763
+ name: { type: 'string' },
764
+ category: { type: 'string' },
765
+ parameters: { type: 'object' }
766
+ },
767
+ required: ['name', 'category']
768
+ },
769
+ context: { type: 'object' }
770
+ },
771
+ required: ['action']
772
+ }
773
+ },
774
+ // ============================================================================
775
+ // HEALTH & STATUS TOOLS
776
+ // ============================================================================
777
+ {
778
+ name: 'health_check',
779
+ description: 'Check supervisor health and status',
780
+ inputSchema: {
781
+ type: 'object',
782
+ properties: {
783
+ repo: {
784
+ type: 'string',
785
+ description: 'Optional repository to check pending approvals for (format: owner/repo)'
786
+ }
787
+ }
788
+ }
789
+ },
790
+ // ============================================================================
791
+ // CSS EVALUATION TOOLS
792
+ // ============================================================================
793
+ {
794
+ name: 'css_eval',
795
+ description: `Evaluate a new CSS rule before adding it. Checks for:
796
+
797
+ - **Duplicates**: Finds existing rules that could be reused instead
798
+ - **Externalization**: Recommends moving inline/style-tag CSS to external files
799
+ - **Globalization**: Identifies patterns that should be global styles
800
+ - **Removables**: Finds existing CSS that can be safely removed
801
+ - **Variables**: Suggests CSS custom properties for colors, spacing, typography
802
+ - **Utilities**: Recommends utility classes when a utility framework is available
803
+ - **Specificity**: Warns about ID selectors, deep nesting, !important
804
+ - **Naming**: Suggests BEM naming and semantic class names
805
+ - **Accessibility**: Checks focus styles, outline removal, motion preferences
806
+
807
+ Use this BEFORE creating any new CSS rule (inline styles, style tags, or stylesheets).
808
+
809
+ Returns:
810
+ - shouldExternalize: Whether to move to external file
811
+ - shouldMakeGlobal: Whether to add to global styles
812
+ - duplicates: Existing rules that match
813
+ - suggestions: Prioritized list of improvements
814
+ - removableCandidates: CSS rules that can be removed
815
+ - riskScore: 0-100 based on violations
816
+ - summary: Human-readable summary`,
817
+ inputSchema: {
818
+ type: 'object',
819
+ properties: {
820
+ newRule: {
821
+ type: 'object',
822
+ description: 'The CSS rule being added',
823
+ properties: {
824
+ selector: { type: 'string', description: 'CSS selector (e.g., ".my-class", "#my-id")' },
825
+ properties: {
826
+ type: 'object',
827
+ description: 'CSS properties as key-value pairs',
828
+ additionalProperties: { type: 'string' }
829
+ },
830
+ source: {
831
+ type: 'string',
832
+ enum: ['inline', 'style_tag', 'external', 'unknown'],
833
+ description: 'Where this CSS is being added'
834
+ },
835
+ file: { type: 'string', description: 'File path if known' },
836
+ line: { type: 'number', description: 'Line number if known' }
837
+ },
838
+ required: ['selector', 'properties', 'source']
839
+ },
840
+ existingRules: {
841
+ type: 'array',
842
+ description: 'Existing CSS rules to check for duplicates',
843
+ items: {
844
+ type: 'object',
845
+ properties: {
846
+ selector: { type: 'string' },
847
+ properties: { type: 'object', additionalProperties: { type: 'string' } },
848
+ source: { type: 'string', enum: ['inline', 'style_tag', 'external', 'unknown'] },
849
+ file: { type: 'string' },
850
+ line: { type: 'number' }
851
+ }
852
+ }
853
+ },
854
+ context: {
855
+ type: 'object',
856
+ description: 'Project context for better analysis',
857
+ properties: {
858
+ projectType: {
859
+ type: 'string',
860
+ enum: ['spa', 'mpa', 'component_library', 'website'],
861
+ description: 'Type of project'
862
+ },
863
+ framework: {
864
+ type: 'string',
865
+ enum: ['react', 'vue', 'angular', 'svelte', 'vanilla', 'other'],
866
+ description: 'Frontend framework in use'
867
+ },
868
+ hasStyleSystem: {
869
+ type: 'boolean',
870
+ description: 'Whether a utility CSS framework (Tailwind, etc.) is available'
871
+ },
872
+ styleSystemName: {
873
+ type: 'string',
874
+ description: 'Name of the style system (e.g., "tailwind", "bootstrap")'
875
+ },
876
+ globalStylesFile: {
877
+ type: 'string',
878
+ description: 'Path to global styles file'
879
+ },
880
+ componentName: {
881
+ type: 'string',
882
+ description: 'Name of component this CSS belongs to'
883
+ }
884
+ }
885
+ }
886
+ },
887
+ required: ['newRule']
888
+ }
889
+ },
890
+ {
891
+ name: 'analyze_css_cleanup',
892
+ description: `Analyze existing CSS for cleanup opportunities.
893
+
894
+ Finds:
895
+ - Duplicate/redundant rules
896
+ - Unused CSS candidates
897
+ - Rules that should be consolidated
898
+ - Opportunities to use CSS variables
899
+ - Specificity issues
900
+
901
+ Provide existing rules and get a cleanup report.`,
902
+ inputSchema: {
903
+ type: 'object',
904
+ properties: {
905
+ rules: {
906
+ type: 'array',
907
+ description: 'Existing CSS rules to analyze',
908
+ items: {
909
+ type: 'object',
910
+ properties: {
911
+ selector: { type: 'string' },
912
+ properties: { type: 'object', additionalProperties: { type: 'string' } },
913
+ source: { type: 'string', enum: ['inline', 'style_tag', 'external', 'unknown'] },
914
+ file: { type: 'string' },
915
+ line: { type: 'number' }
916
+ },
917
+ required: ['selector', 'properties']
918
+ }
919
+ },
920
+ context: {
921
+ type: 'object',
922
+ properties: {
923
+ framework: { type: 'string' },
924
+ hasStyleSystem: { type: 'boolean' }
925
+ }
926
+ }
927
+ },
928
+ required: ['rules']
929
+ }
930
+ },
931
+ {
932
+ name: 'suggest_css_variables',
933
+ description: `Analyze CSS for values that should be CSS custom properties.
934
+
935
+ Identifies:
936
+ - Color values that should be variables
937
+ - Spacing values that should be tokenized
938
+ - Typography values for consistency
939
+ - Animation durations and easings
940
+
941
+ Returns variable suggestions with recommended names.`,
942
+ inputSchema: {
943
+ type: 'object',
944
+ properties: {
945
+ rules: {
946
+ type: 'array',
947
+ description: 'CSS rules to analyze for variable opportunities',
948
+ items: {
949
+ type: 'object',
950
+ properties: {
951
+ selector: { type: 'string' },
952
+ properties: { type: 'object', additionalProperties: { type: 'string' } }
953
+ },
954
+ required: ['selector', 'properties']
955
+ }
956
+ }
957
+ },
958
+ required: ['rules']
959
+ }
960
+ },
961
+ // ============================================================================
962
+ // APP MONITORING TOOLS
963
+ // ============================================================================
964
+ {
965
+ name: 'add_monitored_app',
966
+ description: `Add a production application to monitor. The app must exist in /mnt/prod/ or at the specified absolute path.
967
+
968
+ Monitors:
969
+ - Port availability (is the app listening?)
970
+ - HTTP health endpoint (optional)
971
+ - Process info (PID, memory, CPU, uptime)
972
+ - Response times
973
+
974
+ Returns the created app configuration with initial health check.`,
975
+ inputSchema: {
976
+ type: 'object',
977
+ properties: {
978
+ name: { type: 'string', description: 'Unique name for the app (e.g., "api-server", "web-app")' },
979
+ path: { type: 'string', description: 'Path to app directory (relative to /mnt/prod/ or absolute)' },
980
+ port: { type: 'number', minimum: 1, maximum: 65535, description: 'Port the app listens on' },
981
+ description: { type: 'string', description: 'Description of what the app does' },
982
+ healthEndpoint: { type: 'string', description: 'HTTP endpoint to check (e.g., "/health", "/api/health")' },
983
+ expectedResponseCode: { type: 'number', description: 'Expected HTTP status code (default: 200)' },
984
+ checkIntervalMs: { type: 'number', minimum: 5000, description: 'How often to check health in ms (default: 30000)' },
985
+ timeoutMs: { type: 'number', minimum: 1000, description: 'Health check timeout in ms (default: 5000)' },
986
+ tags: { type: 'array', items: { type: 'string' }, description: 'Tags for grouping/filtering apps' },
987
+ metadata: { type: 'object', description: 'Additional metadata' },
988
+ autoStart: { type: 'boolean', description: 'Start monitoring immediately (default: true)' }
989
+ },
990
+ required: ['name', 'path', 'port']
991
+ }
992
+ },
993
+ {
994
+ name: 'remove_monitored_app',
995
+ description: 'Remove an app from monitoring',
996
+ inputSchema: {
997
+ type: 'object',
998
+ properties: {
999
+ appId: { type: 'string', description: 'ID of the app to remove' }
1000
+ },
1001
+ required: ['appId']
1002
+ }
1003
+ },
1004
+ {
1005
+ name: 'list_monitored_apps',
1006
+ description: 'List all monitored applications with their current status',
1007
+ inputSchema: {
1008
+ type: 'object',
1009
+ properties: {
1010
+ includeHealth: { type: 'boolean', description: 'Include last health check results (default: true)' },
1011
+ tag: { type: 'string', description: 'Filter by tag' }
1012
+ }
1013
+ }
1014
+ },
1015
+ {
1016
+ name: 'get_app_status',
1017
+ description: 'Get detailed status for a specific app including process info and health history',
1018
+ inputSchema: {
1019
+ type: 'object',
1020
+ properties: {
1021
+ appId: { type: 'string', description: 'ID of the app' },
1022
+ appName: { type: 'string', description: 'Name of the app (alternative to appId)' },
1023
+ historyLimit: { type: 'number', description: 'Number of history entries to include (default: 10)' }
1024
+ }
1025
+ }
1026
+ },
1027
+ {
1028
+ name: 'check_app_health',
1029
+ description: 'Perform an immediate health check on a specific app',
1030
+ inputSchema: {
1031
+ type: 'object',
1032
+ properties: {
1033
+ appId: { type: 'string', description: 'ID of the app' },
1034
+ appName: { type: 'string', description: 'Name of the app (alternative to appId)' }
1035
+ }
1036
+ }
1037
+ },
1038
+ {
1039
+ name: 'check_all_apps_health',
1040
+ description: 'Perform health checks on all monitored apps and return summary',
1041
+ inputSchema: {
1042
+ type: 'object',
1043
+ properties: {}
1044
+ }
1045
+ },
1046
+ {
1047
+ name: 'get_app_monitor_stats',
1048
+ description: 'Get overall app monitoring statistics',
1049
+ inputSchema: {
1050
+ type: 'object',
1051
+ properties: {}
1052
+ }
1053
+ },
1054
+ {
1055
+ name: 'update_monitored_app',
1056
+ description: 'Update configuration for a monitored app',
1057
+ inputSchema: {
1058
+ type: 'object',
1059
+ properties: {
1060
+ appId: { type: 'string', description: 'ID of the app to update' },
1061
+ updates: {
1062
+ type: 'object',
1063
+ description: 'Fields to update',
1064
+ properties: {
1065
+ name: { type: 'string' },
1066
+ description: { type: 'string' },
1067
+ healthEndpoint: { type: 'string' },
1068
+ expectedResponseCode: { type: 'number' },
1069
+ checkIntervalMs: { type: 'number', minimum: 5000 },
1070
+ timeoutMs: { type: 'number', minimum: 1000 },
1071
+ enabled: { type: 'boolean' },
1072
+ tags: { type: 'array', items: { type: 'string' } },
1073
+ metadata: { type: 'object' }
1074
+ }
1075
+ }
1076
+ },
1077
+ required: ['appId', 'updates']
1078
+ }
1079
+ },
1080
+ {
1081
+ name: 'set_app_monitoring_enabled',
1082
+ description: 'Enable or disable monitoring for an app',
1083
+ inputSchema: {
1084
+ type: 'object',
1085
+ properties: {
1086
+ appId: { type: 'string', description: 'ID of the app' },
1087
+ enabled: { type: 'boolean', description: 'Whether to enable monitoring' }
1088
+ },
1089
+ required: ['appId', 'enabled']
1090
+ }
1091
+ },
1092
+ {
1093
+ name: 'get_offline_apps',
1094
+ description: 'Get list of apps that are currently offline',
1095
+ inputSchema: {
1096
+ type: 'object',
1097
+ properties: {}
1098
+ }
1099
+ },
1100
+ {
1101
+ name: 'get_degraded_apps',
1102
+ description: 'Get list of apps that are in degraded state (slow response or partial failure)',
1103
+ inputSchema: {
1104
+ type: 'object',
1105
+ properties: {}
1106
+ }
1107
+ },
1108
+ {
1109
+ name: 'scan_prod_apps',
1110
+ description: 'Scan /mnt/prod/ directory for potential apps that can be monitored',
1111
+ inputSchema: {
1112
+ type: 'object',
1113
+ properties: {}
1114
+ }
1115
+ },
1116
+ {
1117
+ name: 'get_app_logs',
1118
+ description: 'Get recent logs for a monitored app (from PM2, journalctl, or log files)',
1119
+ inputSchema: {
1120
+ type: 'object',
1121
+ properties: {
1122
+ appId: { type: 'string', description: 'ID of the app' },
1123
+ appName: { type: 'string', description: 'Name of the app (alternative to appId)' },
1124
+ lines: { type: 'number', minimum: 1, maximum: 500, description: 'Number of log lines to retrieve (default: 50)' }
1125
+ }
1126
+ }
1127
+ },
1128
+ {
1129
+ name: 'get_app_status_history',
1130
+ description: 'Get status history for an app to see uptime patterns',
1131
+ inputSchema: {
1132
+ type: 'object',
1133
+ properties: {
1134
+ appId: { type: 'string', description: 'ID of the app' },
1135
+ appName: { type: 'string', description: 'Name of the app (alternative to appId)' },
1136
+ limit: { type: 'number', minimum: 1, maximum: 1000, description: 'Number of history entries (default: 100)' }
1137
+ }
1138
+ }
1139
+ },
1140
+ // ============================================================================
1141
+ // SESSION MANAGEMENT TOOLS
1142
+ // ============================================================================
1143
+ {
1144
+ name: 'register_session',
1145
+ description: `Register a Claude session working on a project.
1146
+
1147
+ IMPORTANT: Call this at the START of working on a project to appear in the supervisor dashboard.
1148
+
1149
+ This explicitly registers your session for tracking. Without calling this, you won't show up in the agents list.
1150
+
1151
+ Use cases:
1152
+ - Start of a Claude session: Register with project path and session info
1153
+ - Scheduler spawning Claude: Register the spawned instance
1154
+ - Service check-ins: Report that a service is active
1155
+
1156
+ Returns the registered agent info.`,
1157
+ inputSchema: {
1158
+ type: 'object',
1159
+ properties: {
1160
+ agentId: {
1161
+ type: 'string',
1162
+ description: 'Unique agent ID (e.g., "claude-{pid}", "scheduler", or generate one)'
1163
+ },
1164
+ sessionId: {
1165
+ type: 'string',
1166
+ description: 'Session ID for this work session'
1167
+ },
1168
+ projectPath: {
1169
+ type: 'string',
1170
+ description: 'Absolute path to the project directory'
1171
+ },
1172
+ agentType: {
1173
+ type: 'string',
1174
+ enum: ['claude', 'scheduler', 'service', 'manual'],
1175
+ description: 'Type of agent (claude=Claude instance, scheduler=Automated scheduler, service=Background service, manual=Human-initiated)'
1176
+ },
1177
+ metadata: {
1178
+ type: 'object',
1179
+ description: 'Optional metadata (e.g., {task: "implement feature X", mode: "scan"})'
1180
+ }
1181
+ },
1182
+ required: ['agentId', 'sessionId', 'projectPath']
1183
+ }
1184
+ },
1185
+ {
1186
+ name: 'complete_session',
1187
+ description: `Mark a session as complete.
1188
+
1189
+ Call this at the END of your work session to properly close out tracking.
1190
+
1191
+ This marks your session as disconnected and will be cleaned up after retention period.`,
1192
+ inputSchema: {
1193
+ type: 'object',
1194
+ properties: {
1195
+ agentId: {
1196
+ type: 'string',
1197
+ description: 'Agent ID used in register_session'
1198
+ },
1199
+ outcome: {
1200
+ type: 'string',
1201
+ enum: ['success', 'failure', 'cancelled'],
1202
+ description: 'Outcome of the session'
1203
+ }
1204
+ },
1205
+ required: ['agentId']
1206
+ }
1207
+ },
1208
+ // ============================================================================
1209
+ // TASK MANAGEMENT TOOLS
1210
+ // ============================================================================
1211
+ {
1212
+ name: 'create_task',
1213
+ description: `Create a new task (GitHub Issue) for a project.
1214
+
1215
+ Use needsApproval: true for significant changes that require human approval before implementation.
1216
+
1217
+ Returns the created task with its GitHub issue number and URL.`,
1218
+ inputSchema: {
1219
+ type: 'object',
1220
+ properties: {
1221
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1222
+ title: { type: 'string', description: 'Task title' },
1223
+ description: { type: 'string', description: 'Detailed task description' },
1224
+ priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'], description: 'Task priority (default: medium)' },
1225
+ assignee: { type: 'string', description: 'GitHub username to assign (use "@me" for yourself)' },
1226
+ labels: { type: 'array', items: { type: 'string' }, description: 'Additional labels (e.g., ["bug", "security"])' },
1227
+ dueDate: { type: 'string', description: 'Due date or milestone' },
1228
+ estimatedHours: { type: 'number', description: 'Estimated hours to complete' },
1229
+ parentTaskId: { type: 'string', description: 'Parent task ID for subtasks' },
1230
+ dependencies: { type: 'array', items: { type: 'string' }, description: 'Task IDs this task depends on' },
1231
+ metadata: { type: 'object', description: 'Additional metadata' },
1232
+ needsApproval: { type: 'boolean', description: 'Flag for significant changes requiring approval (adds needs-approval label)' }
1233
+ },
1234
+ required: ['title']
1235
+ }
1236
+ },
1237
+ {
1238
+ name: 'get_tasks',
1239
+ description: `Get all tasks for a project with optional filtering.
1240
+
1241
+ Filter by status, priority, assignee, or labels.`,
1242
+ inputSchema: {
1243
+ type: 'object',
1244
+ properties: {
1245
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1246
+ status: { type: 'string', enum: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'], description: 'Filter by status' },
1247
+ priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'], description: 'Filter by priority' },
1248
+ assignee: { type: 'string', description: 'Filter by assignee' },
1249
+ labels: { type: 'array', items: { type: 'string' }, description: 'Filter by labels' }
1250
+ }
1251
+ }
1252
+ },
1253
+ {
1254
+ name: 'get_pending_tasks',
1255
+ description: `Get all pending tasks for a project (excludes tasks with needs-approval label).
1256
+
1257
+ These are tasks ready to work on.`,
1258
+ inputSchema: {
1259
+ type: 'object',
1260
+ properties: {
1261
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' }
1262
+ }
1263
+ }
1264
+ },
1265
+ {
1266
+ name: 'get_approved_tasks',
1267
+ description: `Get all approved tasks ready to work on for a project.
1268
+
1269
+ Returns open tasks that do NOT have the 'needs-approval' label.
1270
+ These are tasks that either never needed approval or have been approved.
1271
+
1272
+ Perfect for automated agents to find work to do.`,
1273
+ inputSchema: {
1274
+ type: 'object',
1275
+ properties: {
1276
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' }
1277
+ }
1278
+ }
1279
+ },
1280
+ {
1281
+ name: 'get_task',
1282
+ description: 'Get a specific task by ID (issue number)',
1283
+ inputSchema: {
1284
+ type: 'object',
1285
+ properties: {
1286
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1287
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' }
1288
+ },
1289
+ required: ['taskId']
1290
+ }
1291
+ },
1292
+ {
1293
+ name: 'update_task',
1294
+ description: `Update a task with new information.
1295
+
1296
+ Can update title, description, priority, status, assignee, labels, and add comments/commits.`,
1297
+ inputSchema: {
1298
+ type: 'object',
1299
+ properties: {
1300
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1301
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' },
1302
+ title: { type: 'string', description: 'New title' },
1303
+ description: { type: 'string', description: 'New description' },
1304
+ priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'], description: 'New priority' },
1305
+ status: { type: 'string', enum: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'], description: 'New status' },
1306
+ assignee: { type: 'string', description: 'New assignee' },
1307
+ labels: { type: 'array', items: { type: 'string' }, description: 'New labels' },
1308
+ comment: { type: 'string', description: 'Comment to add' },
1309
+ commits: { type: 'array', items: { type: 'string' }, description: 'Commit SHAs to link' }
1310
+ },
1311
+ required: ['taskId']
1312
+ }
1313
+ },
1314
+ {
1315
+ name: 'update_task_status',
1316
+ description: 'Update the status of a task',
1317
+ inputSchema: {
1318
+ type: 'object',
1319
+ properties: {
1320
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1321
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' },
1322
+ status: { type: 'string', enum: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'], description: 'New status' }
1323
+ },
1324
+ required: ['taskId', 'status']
1325
+ }
1326
+ },
1327
+ {
1328
+ name: 'add_task_comment',
1329
+ description: `Add a comment to a task with optional commit links.
1330
+
1331
+ Useful for documenting progress or linking related commits.`,
1332
+ inputSchema: {
1333
+ type: 'object',
1334
+ properties: {
1335
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1336
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' },
1337
+ comment: { type: 'string', description: 'Comment text' },
1338
+ commits: { type: 'array', items: { type: 'string' }, description: 'Commit SHAs to link' }
1339
+ },
1340
+ required: ['taskId']
1341
+ }
1342
+ },
1343
+ {
1344
+ name: 'link_commits',
1345
+ description: `Link commits to a task by adding a comment with commit references.
1346
+
1347
+ Helps track which commits are related to a task.`,
1348
+ inputSchema: {
1349
+ type: 'object',
1350
+ properties: {
1351
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1352
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' },
1353
+ commits: { type: 'array', items: { type: 'string' }, description: 'Commit SHAs to link' },
1354
+ message: { type: 'string', description: 'Optional message to include' }
1355
+ },
1356
+ required: ['taskId', 'commits']
1357
+ }
1358
+ },
1359
+ {
1360
+ name: 'close_task_with_comment',
1361
+ description: `Close a task with a resolution comment and optional commit links.
1362
+
1363
+ IMPORTANT: Use this after completing work on a task to document what was done.`,
1364
+ inputSchema: {
1365
+ type: 'object',
1366
+ properties: {
1367
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1368
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' },
1369
+ resolution: { type: 'string', description: 'Resolution description (what was done to complete the task)' },
1370
+ commits: { type: 'array', items: { type: 'string' }, description: 'Commit SHAs related to this task' }
1371
+ },
1372
+ required: ['taskId', 'resolution']
1373
+ }
1374
+ },
1375
+ {
1376
+ name: 'delete_task',
1377
+ description: 'Delete a task (closes as "not planned")',
1378
+ inputSchema: {
1379
+ type: 'object',
1380
+ properties: {
1381
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' },
1382
+ taskId: { type: 'string', description: 'Task ID (GitHub issue number)' }
1383
+ },
1384
+ required: ['taskId']
1385
+ }
1386
+ },
1387
+ {
1388
+ name: 'list_projects',
1389
+ description: 'List all projects (repositories) with task counts',
1390
+ inputSchema: {
1391
+ type: 'object',
1392
+ properties: {}
1393
+ }
1394
+ },
1395
+ {
1396
+ name: 'get_project_stats',
1397
+ description: 'Get task statistics for a project (total, by status, by priority, etc.)',
1398
+ inputSchema: {
1399
+ type: 'object',
1400
+ properties: {
1401
+ projectName: { type: 'string', description: 'Repository in "owner/repo" format. Auto-detects if not provided.' }
1402
+ }
1403
+ }
1404
+ },
1405
+ {
1406
+ name: 'search_tasks',
1407
+ description: 'Search tasks across projects using GitHub search syntax',
1408
+ inputSchema: {
1409
+ type: 'object',
1410
+ properties: {
1411
+ query: { type: 'string', description: 'Search query' },
1412
+ projectName: { type: 'string', description: 'Optional: limit search to specific repository' }
1413
+ },
1414
+ required: ['query']
1415
+ }
1416
+ }
1417
+ ];
1418
+ // Create and configure MCP server
1419
+ const server = new Server({
1420
+ name: 'agent-supervisor',
1421
+ version: '1.1.1'
1422
+ }, {
1423
+ capabilities: {
1424
+ tools: {},
1425
+ resources: {}
1426
+ }
1427
+ });
1428
+ // List tools handler
1429
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
1430
+ tools
1431
+ }));
1432
+ // List resources handler
1433
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
1434
+ resources: [
1435
+ {
1436
+ uri: 'supervisor://rules/all',
1437
+ name: 'All Governance Rules',
1438
+ description: 'Complete list of all configured governance rules',
1439
+ mimeType: 'application/json'
1440
+ },
1441
+ {
1442
+ uri: 'supervisor://rules/presets',
1443
+ name: 'Rule Presets',
1444
+ description: 'Available rule presets and their configurations',
1445
+ mimeType: 'application/json'
1446
+ },
1447
+ {
1448
+ uri: 'supervisor://config',
1449
+ name: 'Supervisor Configuration',
1450
+ description: 'Current supervisor configuration',
1451
+ mimeType: 'application/json'
1452
+ },
1453
+ {
1454
+ uri: 'supervisor://stats',
1455
+ name: 'Supervisor Statistics',
1456
+ description: 'Current audit and approval statistics',
1457
+ mimeType: 'application/json'
1458
+ },
1459
+ {
1460
+ uri: 'supervisor://apps',
1461
+ name: 'Monitored Applications',
1462
+ description: 'All monitored production applications with their current status',
1463
+ mimeType: 'application/json'
1464
+ },
1465
+ {
1466
+ uri: 'supervisor://apps/stats',
1467
+ name: 'App Monitor Statistics',
1468
+ description: 'Overall app monitoring statistics',
1469
+ mimeType: 'application/json'
1470
+ }
1471
+ ]
1472
+ }));
1473
+ // Read resource handler
1474
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1475
+ const { uri } = request.params;
1476
+ switch (uri) {
1477
+ case 'supervisor://rules/all':
1478
+ return {
1479
+ contents: [{
1480
+ uri,
1481
+ mimeType: 'application/json',
1482
+ text: JSON.stringify(supervisor.getRules(), null, 2)
1483
+ }]
1484
+ };
1485
+ case 'supervisor://rules/presets':
1486
+ return {
1487
+ contents: [{
1488
+ uri,
1489
+ mimeType: 'application/json',
1490
+ text: JSON.stringify({
1491
+ available: Object.keys(rulePresets),
1492
+ descriptions: {
1493
+ minimal: 'Basic security and logging only',
1494
+ standard: 'Balanced security and operations',
1495
+ strict: 'Full compliance and governance',
1496
+ financial: 'Optimized for financial services',
1497
+ healthcare: 'Optimized for healthcare (HIPAA)',
1498
+ development: 'Relaxed rules for development'
1499
+ }
1500
+ }, null, 2)
1501
+ }]
1502
+ };
1503
+ case 'supervisor://config':
1504
+ return {
1505
+ contents: [{
1506
+ uri,
1507
+ mimeType: 'application/json',
1508
+ text: JSON.stringify(supervisor.getConfig(), null, 2)
1509
+ }]
1510
+ };
1511
+ case 'supervisor://stats':
1512
+ return {
1513
+ contents: [{
1514
+ uri,
1515
+ mimeType: 'application/json',
1516
+ text: JSON.stringify({
1517
+ audit: supervisor.getAuditStats(),
1518
+ approvals: supervisor.getApprovalStats()
1519
+ }, null, 2)
1520
+ }]
1521
+ };
1522
+ case 'supervisor://apps': {
1523
+ const apps = supervisor.getAllMonitoredApps();
1524
+ const appsWithHealth = apps.map(app => ({
1525
+ ...app,
1526
+ currentStatus: supervisor.getLastAppHealthCheck(app.id)
1527
+ }));
1528
+ return {
1529
+ contents: [{
1530
+ uri,
1531
+ mimeType: 'application/json',
1532
+ text: JSON.stringify(appsWithHealth, null, 2)
1533
+ }]
1534
+ };
1535
+ }
1536
+ case 'supervisor://apps/stats':
1537
+ return {
1538
+ contents: [{
1539
+ uri,
1540
+ mimeType: 'application/json',
1541
+ text: JSON.stringify(supervisor.getAppMonitorStats(), null, 2)
1542
+ }]
1543
+ };
1544
+ default:
1545
+ throw new Error(`Unknown resource: ${uri}`);
1546
+ }
1547
+ });
1548
+ // Tool execution handler
1549
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1550
+ const { name, arguments: args } = request.params;
1551
+ try {
1552
+ await supervisor.initialize();
1553
+ switch (name) {
1554
+ // Core governance tools
1555
+ case 'evaluate_action': {
1556
+ const validated = EvaluateActionArgsSchema.parse(args);
1557
+ const result = await supervisor.evaluateAction(validated.action, validated.context);
1558
+ return resp(slimEval(result));
1559
+ }
1560
+ case 'apply_business_rules': {
1561
+ const validated = ApplyBusinessRulesArgsSchema.parse(args);
1562
+ const result = await supervisor.applyBusinessRules(validated.context);
1563
+ // Slim: only return key constraints
1564
+ return resp({
1565
+ riskScore: result.aggregateRiskScore,
1566
+ rulesApplied: result.rulesApplied?.length || 0,
1567
+ constraints: result.constraints?.slice(0, 5),
1568
+ recommendations: result.recommendations?.slice(0, 3)
1569
+ });
1570
+ }
1571
+ case 'require_human_approval': {
1572
+ const validated = RequireHumanApprovalArgsSchema.parse(args);
1573
+ const result = await supervisor.requireHumanApproval(validated);
1574
+ return resp({ requestId: result.requestId, status: result.status, priority: result.priority });
1575
+ }
1576
+ case 'log_event': {
1577
+ const validated = LogEventArgsSchema.parse(args);
1578
+ const result = await supervisor.logEvent(validated);
1579
+ return resp({ eventId: result.eventId, logged: true });
1580
+ }
1581
+ // Approval management
1582
+ case 'check_approval_status': {
1583
+ const repo = typeof args?.repo === 'string' ? args.repo : undefined;
1584
+ const pending = await supervisor.getPendingApprovals(repo);
1585
+ const request = pending.find((r) => r.requestId === args?.requestId || r.issueNumber === args?.issueNumber);
1586
+ if (!request)
1587
+ return resp({ status: 'not_found' });
1588
+ return resp({ status: request.status, reason: request.reason, priority: request.priority });
1589
+ }
1590
+ case 'list_pending_approvals': {
1591
+ const repo = typeof args?.repo === 'string' ? args.repo : undefined;
1592
+ const approvals = await supervisor.getPendingApprovals(repo);
1593
+ return resp({ count: approvals.length, approvals: approvals.map((a) => ({ id: a.requestId, reason: a.reason, priority: a.priority })) });
1594
+ }
1595
+ case 'approve_request': {
1596
+ const validated = ApproveRequestArgsSchema.parse(args);
1597
+ const repo = typeof args?.repo === 'string' ? args.repo : undefined;
1598
+ await supervisor.approveRequest(validated.requestId, validated.approverId, validated.comments, repo);
1599
+ return resp({ approved: true, requestId: validated.requestId });
1600
+ }
1601
+ case 'deny_request': {
1602
+ const validated = DenyRequestArgsSchema.parse(args);
1603
+ const repo = typeof args?.repo === 'string' ? args.repo : undefined;
1604
+ await supervisor.denyRequest(validated.requestId, validated.denierId, validated.reason, repo);
1605
+ return resp({ denied: true, requestId: validated.requestId });
1606
+ }
1607
+ // Rule management
1608
+ case 'list_rules': {
1609
+ const { getRulesByProfile, getRuleSummary } = await import('./rules/index.js');
1610
+ let rules = supervisor.getRules();
1611
+ if (args?.profile)
1612
+ rules = getRulesByProfile(args.profile);
1613
+ else if (args?.preset) {
1614
+ const { rulePresets } = await import('./rules/index.js');
1615
+ const preset = rulePresets[args.preset];
1616
+ rules = preset ? preset.rules : rules;
1617
+ }
1618
+ if (args?.type)
1619
+ rules = rules.filter(r => r.type === args.type);
1620
+ if (args?.enabled !== undefined)
1621
+ rules = rules.filter(r => r.enabled === args.enabled);
1622
+ if (args?.tags && Array.isArray(args.tags)) {
1623
+ const tags = args.tags.filter((t) => typeof t === 'string');
1624
+ rules = rules.filter(r => r.tags?.some(t => tags.includes(t)));
1625
+ }
1626
+ if (args?.minPriority !== undefined && typeof args.minPriority === 'number') {
1627
+ const min = args.minPriority;
1628
+ const max = args?.maxPriority;
1629
+ rules = rules.filter(r => max !== undefined && typeof max === 'number' ? r.priority >= min && r.priority <= max : r.priority >= min);
1630
+ }
1631
+ if (args?.summary) {
1632
+ const summary = getRuleSummary();
1633
+ return resp({ total: Object.values(summary).reduce((a, b) => a + b, 0), byType: summary });
1634
+ }
1635
+ const limit = Math.min(typeof args?.limit === 'number' ? args.limit : 50, 200);
1636
+ const slimRules = rules.slice(0, limit).map(r => ({ id: r.id, name: r.name, type: r.type, priority: r.priority }));
1637
+ return resp({ count: rules.length, showing: slimRules.length, rules: slimRules });
1638
+ }
1639
+ case 'list_project_profiles': {
1640
+ const { listProjectProfiles } = await import('./rules/index.js');
1641
+ const profiles = listProjectProfiles();
1642
+ return resp(profiles.map(p => ({ key: p.key, name: p.name, ruleCount: p.ruleCount })));
1643
+ }
1644
+ case 'discover_relevant_rules': {
1645
+ const fs = await import('fs/promises');
1646
+ const path = await import('path');
1647
+ const { projectProfiles } = await import('./rules/index.js');
1648
+ const projectPath = args?.projectPath;
1649
+ const autoDetect = args?.autoDetect !== false;
1650
+ if (!autoDetect) {
1651
+ return { content: [{ type: 'text', text: JSON.stringify({
1652
+ error: 'Manual detection not yet supported. Use autoDetect: true'
1653
+ }) }] };
1654
+ }
1655
+ const detectedTechnologies = [];
1656
+ const recommendedProfiles = [];
1657
+ try {
1658
+ // Check for package.json (Node.js/TypeScript)
1659
+ try {
1660
+ const packageJson = await fs.readFile(path.join(projectPath, 'package.json'), 'utf-8');
1661
+ const pkg = JSON.parse(packageJson);
1662
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
1663
+ if (allDeps['@playwright/test']) {
1664
+ detectedTechnologies.push('Playwright');
1665
+ recommendedProfiles.push('playwright');
1666
+ }
1667
+ if (allDeps['react'] || allDeps['next'] || allDeps['vue'] || allDeps['svelte']) {
1668
+ detectedTechnologies.push('React/Frontend');
1669
+ recommendedProfiles.push('react');
1670
+ }
1671
+ if (allDeps['express'] || allDeps['fastify'] || allDeps['koa']) {
1672
+ detectedTechnologies.push('Node.js API');
1673
+ recommendedProfiles.push('api');
1674
+ }
1675
+ if (allDeps['socket.io'] || allDeps['ws']) {
1676
+ detectedTechnologies.push('WebSocket');
1677
+ recommendedProfiles.push('websocket');
1678
+ }
1679
+ }
1680
+ catch { }
1681
+ // Check for requirements.txt (Python)
1682
+ try {
1683
+ const requirements = await fs.readFile(path.join(projectPath, 'requirements.txt'), 'utf-8');
1684
+ if (requirements.includes('flask')) {
1685
+ detectedTechnologies.push('Flask');
1686
+ recommendedProfiles.push('flask');
1687
+ }
1688
+ if (requirements.includes('torch') || requirements.includes('transformers') || requirements.includes('diffusers')) {
1689
+ detectedTechnologies.push('ML/AI (PyTorch)');
1690
+ recommendedProfiles.push('ml-ai');
1691
+ }
1692
+ if (requirements.includes('stripe')) {
1693
+ detectedTechnologies.push('Stripe');
1694
+ recommendedProfiles.push('stripe');
1695
+ }
1696
+ if (requirements.includes('flask-socketio') || requirements.includes('python-socketio')) {
1697
+ detectedTechnologies.push('WebSocket (Python)');
1698
+ recommendedProfiles.push('websocket');
1699
+ }
1700
+ }
1701
+ catch { }
1702
+ // Check for .csproj files (.NET/Azure)
1703
+ try {
1704
+ const files = await fs.readdir(projectPath);
1705
+ const csprojFiles = files.filter(f => f.endsWith('.csproj'));
1706
+ if (csprojFiles.length > 0) {
1707
+ detectedTechnologies.push('.NET/C#');
1708
+ // Check for Azure Functions
1709
+ for (const file of csprojFiles) {
1710
+ const content = await fs.readFile(path.join(projectPath, file), 'utf-8');
1711
+ if (content.includes('Microsoft.Azure.Functions') || content.includes('Microsoft.NET.Sdk.Functions')) {
1712
+ detectedTechnologies.push('Azure Functions');
1713
+ recommendedProfiles.push('dotnet-azure');
1714
+ break;
1715
+ }
1716
+ }
1717
+ }
1718
+ }
1719
+ catch { }
1720
+ // Deduplicate profiles
1721
+ const uniqueProfiles = [...new Set(recommendedProfiles)];
1722
+ // Calculate total rule count
1723
+ let totalRules = 0;
1724
+ uniqueProfiles.forEach(profile => {
1725
+ const profileConfig = projectProfiles[profile];
1726
+ if (profileConfig) {
1727
+ totalRules += profileConfig.rules.length;
1728
+ }
1729
+ });
1730
+ return { content: [{ type: 'text', text: JSON.stringify({
1731
+ projectPath,
1732
+ detectedTechnologies,
1733
+ recommendedProfiles: uniqueProfiles,
1734
+ ruleCount: totalRules,
1735
+ priorities: {
1736
+ critical: uniqueProfiles.filter(p => ['stripe', 'ml-ai', 'flask'].includes(p)),
1737
+ high: uniqueProfiles.filter(p => ['dotnet-azure', 'websocket'].includes(p)),
1738
+ medium: uniqueProfiles.filter(p => ['playwright', 'react'].includes(p))
1739
+ },
1740
+ usage: `Use: list_rules(profile="${uniqueProfiles[0]}") to see relevant rules`
1741
+ }, null, 2) }] };
1742
+ }
1743
+ catch (error) {
1744
+ return { content: [{ type: 'text', text: JSON.stringify({
1745
+ error: 'Failed to analyze project',
1746
+ message: error.message,
1747
+ projectPath
1748
+ }) }] };
1749
+ }
1750
+ }
1751
+ case 'add_rule': {
1752
+ const validated = AddRuleArgsSchema.parse(args);
1753
+ supervisor.addRule(validated.rule);
1754
+ return { content: [{ type: 'text', text: JSON.stringify({ success: true, ruleId: validated.rule.id }) }] };
1755
+ }
1756
+ case 'remove_rule': {
1757
+ const validated = RemoveRuleArgsSchema.parse(args);
1758
+ const removed = supervisor.removeRule(validated.ruleId);
1759
+ return { content: [{ type: 'text', text: JSON.stringify({ success: removed }) }] };
1760
+ }
1761
+ case 'load_preset': {
1762
+ const validated = LoadPresetArgsSchema.parse(args);
1763
+ await supervisor.loadPreset(validated.preset);
1764
+ return { content: [{ type: 'text', text: JSON.stringify({ success: true, preset: validated.preset }) }] };
1765
+ }
1766
+ // Audit & reporting
1767
+ case 'get_audit_events': {
1768
+ const validated = GetAuditEventsArgsSchema.parse(args);
1769
+ const events = supervisor.getAuditEvents(validated);
1770
+ return { content: [{ type: 'text', text: JSON.stringify(events, null, 2) }] };
1771
+ }
1772
+ case 'get_audit_stats': {
1773
+ const validated = GetAuditStatsArgsSchema.parse(args || {});
1774
+ const stats = supervisor.getAuditStats(validated.since);
1775
+ return { content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }] };
1776
+ }
1777
+ case 'get_approval_stats': {
1778
+ const stats = supervisor.getApprovalStats();
1779
+ return { content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }] };
1780
+ }
1781
+ case 'export_audit_log': {
1782
+ const validated = ExportAuditLogArgsSchema.parse(args || {});
1783
+ const exported = supervisor.exportAuditLog(validated);
1784
+ return { content: [{ type: 'text', text: exported }] };
1785
+ }
1786
+ // Configuration
1787
+ case 'get_config': {
1788
+ const config = supervisor.getConfig();
1789
+ return { content: [{ type: 'text', text: JSON.stringify(config, null, 2) }] };
1790
+ }
1791
+ case 'update_config': {
1792
+ const validated = UpdateConfigArgsSchema.parse(args || {});
1793
+ await supervisor.updateConfig(validated);
1794
+ return { content: [{ type: 'text', text: JSON.stringify({ success: true }) }] };
1795
+ }
1796
+ // Rate limiting
1797
+ case 'check_rate_limit': {
1798
+ // This would need access to rate limiter internals
1799
+ return { content: [{ type: 'text', text: JSON.stringify({ message: 'Rate limit check - use evaluate_action for full check' }) }] };
1800
+ }
1801
+ case 'add_rate_limit': {
1802
+ const validated = AddRateLimitArgsSchema.parse(args);
1803
+ supervisor.addRateLimit(validated.config);
1804
+ return { content: [{ type: 'text', text: JSON.stringify({ success: true }) }] };
1805
+ }
1806
+ // Risk assessment
1807
+ case 'calculate_risk_score': {
1808
+ const validated = EvaluateActionArgsSchema.parse(args);
1809
+ const result = await supervisor.evaluateAction(validated.action, validated.context);
1810
+ return {
1811
+ content: [{
1812
+ type: 'text',
1813
+ text: JSON.stringify({
1814
+ riskScore: result.riskScore,
1815
+ riskLevel: result.riskLevel,
1816
+ violations: result.violations.length,
1817
+ warnings: result.warnings.length
1818
+ }, null, 2)
1819
+ }]
1820
+ };
1821
+ }
1822
+ // Health check
1823
+ case 'health_check': {
1824
+ const config = supervisor.getConfig();
1825
+ const stats = supervisor.getAuditStats();
1826
+ // Try to get pending approvals, but don't fail if no repo is available
1827
+ let pendingApprovalsCount = 0;
1828
+ try {
1829
+ const repo = typeof args?.repo === 'string' ? args.repo : undefined;
1830
+ if (repo) {
1831
+ const pendingApprovals = await supervisor.getPendingApprovals(repo);
1832
+ pendingApprovalsCount = pendingApprovals.length;
1833
+ }
1834
+ }
1835
+ catch {
1836
+ // No repo available or error - that's fine for health check
1837
+ }
1838
+ return {
1839
+ content: [{
1840
+ type: 'text',
1841
+ text: JSON.stringify({
1842
+ status: 'healthy',
1843
+ version: config.version,
1844
+ environment: config.environment,
1845
+ rulesLoaded: supervisor.getRules().length,
1846
+ auditEventsLogged: stats.total,
1847
+ pendingApprovals: pendingApprovalsCount,
1848
+ features: config.features
1849
+ }, null, 2)
1850
+ }]
1851
+ };
1852
+ }
1853
+ // CSS Evaluation tools
1854
+ case 'css_eval': {
1855
+ const newRule = args?.newRule;
1856
+ const existingRules = args?.existingRules;
1857
+ const context = args?.context;
1858
+ const analysisContext = {
1859
+ newRule,
1860
+ existingRules,
1861
+ projectType: context?.projectType,
1862
+ framework: context?.framework,
1863
+ hasStyleSystem: context?.hasStyleSystem,
1864
+ styleSystemName: context?.styleSystemName,
1865
+ globalStylesFile: context?.globalStylesFile,
1866
+ componentName: context?.componentName
1867
+ };
1868
+ const result = cssAnalyzer.analyze(analysisContext);
1869
+ // Also log this evaluation
1870
+ await supervisor.logEvent({
1871
+ action: 'css_eval',
1872
+ eventType: 'action_evaluated',
1873
+ outcome: result.riskScore > 50 ? 'failure' : 'success',
1874
+ metadata: {
1875
+ selector: newRule.selector,
1876
+ source: newRule.source,
1877
+ riskScore: result.riskScore,
1878
+ suggestionCount: result.suggestions.length,
1879
+ duplicateCount: result.duplicates.length
1880
+ }
1881
+ });
1882
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
1883
+ }
1884
+ case 'analyze_css_cleanup': {
1885
+ const rules = args?.rules;
1886
+ const context = args?.context;
1887
+ // Analyze each rule against others
1888
+ const allSuggestions = [];
1889
+ for (let i = 0; i < rules.length; i++) {
1890
+ const rule = rules[i];
1891
+ const otherRules = [...rules.slice(0, i), ...rules.slice(i + 1)];
1892
+ const result = cssAnalyzer.analyze({
1893
+ newRule: rule,
1894
+ existingRules: otherRules,
1895
+ framework: context?.framework,
1896
+ hasStyleSystem: context?.hasStyleSystem
1897
+ });
1898
+ if (result.suggestions.length > 0 || result.duplicates.length > 0) {
1899
+ allSuggestions.push({
1900
+ ruleSelector: rule.selector,
1901
+ suggestions: result.suggestions,
1902
+ duplicates: result.duplicates,
1903
+ removable: result.removableCandidates.length > 0
1904
+ });
1905
+ }
1906
+ }
1907
+ // Calculate overall stats
1908
+ const totalDuplicates = allSuggestions.reduce((sum, s) => sum + s.duplicates.length, 0);
1909
+ const totalSuggestions = allSuggestions.reduce((sum, s) => sum + s.suggestions.length, 0);
1910
+ const removableCount = allSuggestions.filter(s => s.removable).length;
1911
+ return {
1912
+ content: [{
1913
+ type: 'text',
1914
+ text: JSON.stringify({
1915
+ summary: {
1916
+ rulesAnalyzed: rules.length,
1917
+ rulesWithIssues: allSuggestions.length,
1918
+ totalDuplicates,
1919
+ totalSuggestions,
1920
+ removableCandidates: removableCount
1921
+ },
1922
+ details: allSuggestions
1923
+ }, null, 2)
1924
+ }]
1925
+ };
1926
+ }
1927
+ case 'suggest_css_variables': {
1928
+ const rules = args?.rules;
1929
+ const variableSuggestions = [];
1930
+ // Patterns for variable candidates
1931
+ const patterns = [
1932
+ { regex: /^#[0-9a-fA-F]{3,8}$/, category: 'color', prefix: '--color-' },
1933
+ { regex: /^rgb\(|^rgba\(|^hsl\(|^hsla\(/, category: 'color', prefix: '--color-' },
1934
+ { regex: /^\d+(px|rem|em)$/, category: 'spacing', prefix: '--spacing-', minPx: 8 },
1935
+ { regex: /^\d{3}$/, category: 'font-weight', prefix: '--font-weight-' },
1936
+ { regex: /^(\d+(\.\d+)?)(s|ms)$/, category: 'duration', prefix: '--duration-' }
1937
+ ];
1938
+ // Track unique values for naming
1939
+ const colorValues = new Map();
1940
+ const spacingValues = new Map();
1941
+ for (const rule of rules) {
1942
+ for (const [property, value] of Object.entries(rule.properties)) {
1943
+ for (const pattern of patterns) {
1944
+ if (pattern.regex.test(value)) {
1945
+ // Skip small pixel values for spacing
1946
+ if (pattern.category === 'spacing' && pattern.minPx) {
1947
+ const numValue = parseInt(value);
1948
+ if (numValue < pattern.minPx)
1949
+ continue;
1950
+ }
1951
+ // Generate suggested variable name
1952
+ let varName = pattern.prefix;
1953
+ if (pattern.category === 'color') {
1954
+ const count = colorValues.get(value) || colorValues.size + 1;
1955
+ colorValues.set(value, count);
1956
+ varName += `${count}`;
1957
+ }
1958
+ else if (pattern.category === 'spacing') {
1959
+ const count = spacingValues.get(value) || spacingValues.size + 1;
1960
+ spacingValues.set(value, count);
1961
+ varName += `${count}`;
1962
+ }
1963
+ else {
1964
+ varName += value.replace(/[^a-zA-Z0-9]/g, '-');
1965
+ }
1966
+ variableSuggestions.push({
1967
+ selector: rule.selector,
1968
+ property,
1969
+ currentValue: value,
1970
+ suggestedVariable: `var(${varName})`,
1971
+ category: pattern.category
1972
+ });
1973
+ break;
1974
+ }
1975
+ }
1976
+ }
1977
+ }
1978
+ // Group by category
1979
+ const byCategory = variableSuggestions.reduce((acc, s) => {
1980
+ acc[s.category] = acc[s.category] || [];
1981
+ acc[s.category].push(s);
1982
+ return acc;
1983
+ }, {});
1984
+ return {
1985
+ content: [{
1986
+ type: 'text',
1987
+ text: JSON.stringify({
1988
+ summary: {
1989
+ totalSuggestions: variableSuggestions.length,
1990
+ byCategory: Object.fromEntries(Object.entries(byCategory).map(([k, v]) => [k, v.length]))
1991
+ },
1992
+ suggestions: byCategory
1993
+ }, null, 2)
1994
+ }]
1995
+ };
1996
+ }
1997
+ // App monitoring tools
1998
+ case 'add_monitored_app': {
1999
+ const validated = AddMonitoredAppArgsSchema.parse(args);
2000
+ const result = await supervisor.addMonitoredApp(validated);
2001
+ const healthCheck = supervisor.getLastAppHealthCheck(result.id);
2002
+ return {
2003
+ content: [{
2004
+ type: 'text',
2005
+ text: JSON.stringify({ app: result, initialHealth: healthCheck }, null, 2)
2006
+ }]
2007
+ };
2008
+ }
2009
+ case 'remove_monitored_app': {
2010
+ const validated = RemoveMonitoredAppArgsSchema.parse(args);
2011
+ const removed = await supervisor.removeMonitoredApp(validated.appId);
2012
+ return { content: [{ type: 'text', text: JSON.stringify({ success: removed }) }] };
2013
+ }
2014
+ case 'list_monitored_apps': {
2015
+ let apps = supervisor.getAllMonitoredApps();
2016
+ if (args?.tag && typeof args.tag === 'string') {
2017
+ apps = supervisor.findAppsByTag(args.tag);
2018
+ }
2019
+ const includeHealth = args?.includeHealth !== false;
2020
+ const result = apps.map(app => {
2021
+ const base = { ...app };
2022
+ if (includeHealth) {
2023
+ return {
2024
+ ...base,
2025
+ lastHealth: supervisor.getLastAppHealthCheck(app.id)
2026
+ };
2027
+ }
2028
+ return base;
2029
+ });
2030
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
2031
+ }
2032
+ case 'get_app_status': {
2033
+ const validated = GetAppStatusArgsSchema.parse(args);
2034
+ let app = validated.appId
2035
+ ? supervisor.getMonitoredApp(validated.appId)
2036
+ : validated.appName
2037
+ ? supervisor.getMonitoredAppByName(validated.appName)
2038
+ : undefined;
2039
+ if (!app) {
2040
+ return {
2041
+ content: [{ type: 'text', text: JSON.stringify({ error: 'App not found' }) }],
2042
+ isError: true
2043
+ };
2044
+ }
2045
+ const healthCheck = supervisor.getLastAppHealthCheck(app.id);
2046
+ const history = supervisor.getAppStatusHistory(app.id, validated.historyLimit || 10);
2047
+ return {
2048
+ content: [{
2049
+ type: 'text',
2050
+ text: JSON.stringify({
2051
+ app,
2052
+ currentHealth: healthCheck,
2053
+ recentHistory: history
2054
+ }, null, 2)
2055
+ }]
2056
+ };
2057
+ }
2058
+ case 'check_app_health': {
2059
+ const validated = CheckAppHealthArgsSchema.parse(args);
2060
+ let appId = validated.appId;
2061
+ if (!appId && validated.appName) {
2062
+ const app = supervisor.getMonitoredAppByName(validated.appName);
2063
+ if (app)
2064
+ appId = app.id;
2065
+ }
2066
+ if (!appId) {
2067
+ return {
2068
+ content: [{ type: 'text', text: JSON.stringify({ error: 'App not found' }) }],
2069
+ isError: true
2070
+ };
2071
+ }
2072
+ const result = await supervisor.checkAppHealth(appId);
2073
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
2074
+ }
2075
+ case 'check_all_apps_health': {
2076
+ const results = await supervisor.checkAllAppsHealth();
2077
+ const stats = supervisor.getAppMonitorStats();
2078
+ return {
2079
+ content: [{
2080
+ type: 'text',
2081
+ text: JSON.stringify({ stats, results }, null, 2)
2082
+ }]
2083
+ };
2084
+ }
2085
+ case 'get_app_monitor_stats': {
2086
+ const stats = supervisor.getAppMonitorStats();
2087
+ return { content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }] };
2088
+ }
2089
+ case 'update_monitored_app': {
2090
+ const validated = UpdateMonitoredAppArgsSchema.parse(args);
2091
+ const result = await supervisor.updateMonitoredApp(validated.appId, validated.updates);
2092
+ if (!result) {
2093
+ return {
2094
+ content: [{ type: 'text', text: JSON.stringify({ error: 'App not found' }) }],
2095
+ isError: true
2096
+ };
2097
+ }
2098
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
2099
+ }
2100
+ case 'set_app_monitoring_enabled': {
2101
+ const validated = SetAppMonitoringEnabledArgsSchema.parse(args);
2102
+ const success = supervisor.setAppMonitoringEnabled(validated.appId, validated.enabled);
2103
+ return { content: [{ type: 'text', text: JSON.stringify({ success }) }] };
2104
+ }
2105
+ case 'get_offline_apps': {
2106
+ const offlineApps = supervisor.getOfflineApps();
2107
+ const result = offlineApps.map(app => ({
2108
+ ...app,
2109
+ lastHealth: supervisor.getLastAppHealthCheck(app.id)
2110
+ }));
2111
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
2112
+ }
2113
+ case 'get_degraded_apps': {
2114
+ const degradedApps = supervisor.getDegradedApps();
2115
+ const result = degradedApps.map(app => ({
2116
+ ...app,
2117
+ lastHealth: supervisor.getLastAppHealthCheck(app.id)
2118
+ }));
2119
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
2120
+ }
2121
+ case 'scan_prod_apps': {
2122
+ const potentialApps = await supervisor.scanForApps();
2123
+ return { content: [{ type: 'text', text: JSON.stringify(potentialApps, null, 2) }] };
2124
+ }
2125
+ case 'get_app_logs': {
2126
+ const validated = GetAppLogsArgsSchema.parse(args);
2127
+ let appId = validated.appId;
2128
+ if (!appId && validated.appName) {
2129
+ const app = supervisor.getMonitoredAppByName(validated.appName);
2130
+ if (app)
2131
+ appId = app.id;
2132
+ }
2133
+ if (!appId) {
2134
+ return {
2135
+ content: [{ type: 'text', text: JSON.stringify({ error: 'App not found' }) }],
2136
+ isError: true
2137
+ };
2138
+ }
2139
+ const logs = await supervisor.getAppLogs(appId, validated.lines || 50);
2140
+ return { content: [{ type: 'text', text: JSON.stringify(logs, null, 2) }] };
2141
+ }
2142
+ case 'get_app_status_history': {
2143
+ const validated = GetAppStatusHistoryArgsSchema.parse(args);
2144
+ let appId = validated.appId;
2145
+ if (!appId && validated.appName) {
2146
+ const app = supervisor.getMonitoredAppByName(validated.appName);
2147
+ if (app)
2148
+ appId = app.id;
2149
+ }
2150
+ if (!appId) {
2151
+ return {
2152
+ content: [{ type: 'text', text: JSON.stringify({ error: 'App not found' }) }],
2153
+ isError: true
2154
+ };
2155
+ }
2156
+ const history = supervisor.getAppStatusHistory(appId, validated.limit || 100);
2157
+ return { content: [{ type: 'text', text: JSON.stringify(history, null, 2) }] };
2158
+ }
2159
+ // Session management tools
2160
+ case 'register_session': {
2161
+ const validated = z.object({
2162
+ agentId: z.string(),
2163
+ sessionId: z.string(),
2164
+ projectPath: z.string(),
2165
+ agentType: z.enum(['claude', 'scheduler', 'service', 'manual']).optional(),
2166
+ metadata: z.record(z.any()).optional()
2167
+ }).parse(args);
2168
+ const agent = projectTracker.registerSession({
2169
+ agentId: validated.agentId,
2170
+ sessionId: validated.sessionId,
2171
+ projectPath: validated.projectPath,
2172
+ agentType: validated.agentType,
2173
+ metadata: validated.metadata
2174
+ });
2175
+ return {
2176
+ content: [{
2177
+ type: 'text',
2178
+ text: JSON.stringify({ registered: true, agent }, null, 2)
2179
+ }]
2180
+ };
2181
+ }
2182
+ case 'complete_session': {
2183
+ const validated = z.object({
2184
+ agentId: z.string(),
2185
+ outcome: z.enum(['success', 'failure', 'cancelled']).optional()
2186
+ }).parse(args);
2187
+ projectTracker.completeSession(validated.agentId, validated.outcome);
2188
+ return {
2189
+ content: [{
2190
+ type: 'text',
2191
+ text: JSON.stringify({ completed: true }, null, 2)
2192
+ }]
2193
+ };
2194
+ }
2195
+ // Task management tools
2196
+ case 'create_task': {
2197
+ const validated = CreateTaskArgsSchema.parse(args);
2198
+ const task = await taskManager.createTask(validated);
2199
+ return resp(slimTask(task));
2200
+ }
2201
+ case 'get_tasks': {
2202
+ const validated = GetTasksArgsSchema.parse(args || {});
2203
+ const tasks = await taskManager.getTasksByProject(validated.projectName, {
2204
+ status: validated.status,
2205
+ priority: validated.priority,
2206
+ assignee: validated.assignee,
2207
+ labels: validated.labels
2208
+ });
2209
+ return resp({ count: tasks.length, tasks: tasks.map(slimTask) });
2210
+ }
2211
+ case 'get_pending_tasks': {
2212
+ const projectName = typeof args?.projectName === 'string' ? args.projectName : undefined;
2213
+ const tasks = await taskManager.getPendingTasks(projectName);
2214
+ const approvedTasks = tasks.filter(task => !task.labels?.includes('needs-approval'));
2215
+ return resp({ count: approvedTasks.length, tasks: approvedTasks.map(slimTask) });
2216
+ }
2217
+ case 'get_approved_tasks': {
2218
+ const projectName = typeof args?.projectName === 'string' ? args.projectName : undefined;
2219
+ const allTasks = await taskManager.getTasksByProject(projectName);
2220
+ const approvedTasks = allTasks.filter(task => (task.status === 'pending' || task.status === 'in_progress') &&
2221
+ task.labels?.includes('approved'));
2222
+ return resp({ count: approvedTasks.length, tasks: approvedTasks.map(slimTask) });
2223
+ }
2224
+ case 'get_task': {
2225
+ const validated = GetTaskArgsSchema.parse(args);
2226
+ const task = await taskManager.getTask(validated.projectName, validated.taskId);
2227
+ if (!task) {
2228
+ return { content: [{ type: 'text', text: json({ error: 'Task not found' }) }], isError: true };
2229
+ }
2230
+ return resp(slimTask(task));
2231
+ }
2232
+ case 'update_task': {
2233
+ const validated = UpdateTaskArgsSchema.parse(args);
2234
+ const task = await taskManager.updateTask(validated.projectName, validated.taskId, {
2235
+ title: validated.title,
2236
+ description: validated.description,
2237
+ priority: validated.priority,
2238
+ status: validated.status,
2239
+ assignee: validated.assignee,
2240
+ labels: validated.labels,
2241
+ comment: validated.comment,
2242
+ commits: validated.commits
2243
+ });
2244
+ if (!task) {
2245
+ return { content: [{ type: 'text', text: json({ error: 'Update failed' }) }], isError: true };
2246
+ }
2247
+ return resp(slimTask(task));
2248
+ }
2249
+ case 'update_task_status': {
2250
+ const validated = UpdateTaskStatusArgsSchema.parse(args);
2251
+ const task = await taskManager.updateTaskStatus(validated.projectName, validated.taskId, validated.status);
2252
+ if (!task) {
2253
+ return { content: [{ type: 'text', text: json({ error: 'Status update failed' }) }], isError: true };
2254
+ }
2255
+ return resp(slimTask(task));
2256
+ }
2257
+ case 'add_task_comment': {
2258
+ const validated = AddTaskCommentArgsSchema.parse(args);
2259
+ const success = await taskManager.addComment(validated.projectName, validated.taskId, validated.comment, validated.commits);
2260
+ return resp({ success });
2261
+ }
2262
+ case 'link_commits': {
2263
+ const validated = LinkCommitsArgsSchema.parse(args);
2264
+ const success = await taskManager.linkCommits(validated.projectName, validated.taskId, validated.commits, validated.message);
2265
+ return resp({ success });
2266
+ }
2267
+ case 'close_task_with_comment': {
2268
+ const validated = CloseTaskWithCommentArgsSchema.parse(args);
2269
+ const task = await taskManager.closeWithComment(validated.projectName, validated.taskId, validated.resolution, validated.commits);
2270
+ if (!task) {
2271
+ return { content: [{ type: 'text', text: json({ error: 'Close failed' }) }], isError: true };
2272
+ }
2273
+ return resp(slimTask(task));
2274
+ }
2275
+ case 'delete_task': {
2276
+ const projectName = typeof args?.projectName === 'string' ? args.projectName : undefined;
2277
+ const taskId = typeof args?.taskId === 'string' ? args.taskId : '';
2278
+ if (!taskId) {
2279
+ return { content: [{ type: 'text', text: json({ error: 'taskId required' }) }], isError: true };
2280
+ }
2281
+ const success = await taskManager.deleteTask(projectName, taskId);
2282
+ return resp({ success });
2283
+ }
2284
+ case 'list_projects': {
2285
+ const projects = await taskManager.listProjects();
2286
+ return resp(projects);
2287
+ }
2288
+ case 'get_project_stats': {
2289
+ const projectName = typeof args?.projectName === 'string' ? args.projectName : undefined;
2290
+ const stats = await taskManager.getProjectStats(projectName);
2291
+ if (!stats) {
2292
+ return {
2293
+ content: [{ type: 'text', text: JSON.stringify({ error: 'Failed to get project stats' }) }],
2294
+ isError: true
2295
+ };
2296
+ }
2297
+ return { content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }] };
2298
+ }
2299
+ case 'search_tasks': {
2300
+ const validated = SearchTasksArgsSchema.parse(args);
2301
+ const tasks = await taskManager.searchTasks(validated.query, validated.projectName);
2302
+ return { content: [{ type: 'text', text: JSON.stringify({
2303
+ query: validated.query,
2304
+ count: tasks.length,
2305
+ tasks
2306
+ }, null, 2) }] };
2307
+ }
2308
+ default:
2309
+ throw new Error(`Unknown tool: ${name}`);
2310
+ }
2311
+ }
2312
+ catch (error) {
2313
+ const errorMessage = error instanceof Error ? error.message : String(error);
2314
+ return {
2315
+ content: [{
2316
+ type: 'text',
2317
+ text: JSON.stringify({ error: errorMessage }, null, 2)
2318
+ }],
2319
+ isError: true
2320
+ };
2321
+ }
2322
+ });
2323
+ // Export server and start function
2324
+ export { server };
2325
+ export async function startServer() {
2326
+ const transport = new StdioServerTransport();
2327
+ await server.connect(transport);
2328
+ console.error('Agent Supervisor MCP Server running on stdio');
2329
+ }
2330
+ //# sourceMappingURL=server.js.map