@trentapps/manager-protocol 1.3.0

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