@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.
- package/LICENSE +21 -0
- package/README.md +446 -0
- package/dist/analyzers/ArchitectureDetector.d.ts +44 -0
- package/dist/analyzers/ArchitectureDetector.d.ts.map +1 -0
- package/dist/analyzers/ArchitectureDetector.js +218 -0
- package/dist/analyzers/ArchitectureDetector.js.map +1 -0
- package/dist/analyzers/CSSAnalyzer.d.ts +104 -0
- package/dist/analyzers/CSSAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/CSSAnalyzer.js +578 -0
- package/dist/analyzers/CSSAnalyzer.js.map +1 -0
- package/dist/analyzers/index.d.ts +5 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +5 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +174 -0
- package/dist/cli.js.map +1 -0
- package/dist/design-system/index.d.ts +6 -0
- package/dist/design-system/index.d.ts.map +1 -0
- package/dist/design-system/index.js +6 -0
- package/dist/design-system/index.js.map +1 -0
- package/dist/design-system/tokens.d.ts +106 -0
- package/dist/design-system/tokens.d.ts.map +1 -0
- package/dist/design-system/tokens.js +554 -0
- package/dist/design-system/tokens.js.map +1 -0
- package/dist/engine/AppMonitor.d.ts +162 -0
- package/dist/engine/AppMonitor.d.ts.map +1 -0
- package/dist/engine/AppMonitor.js +754 -0
- package/dist/engine/AppMonitor.js.map +1 -0
- package/dist/engine/AuditLogger.d.ts +138 -0
- package/dist/engine/AuditLogger.d.ts.map +1 -0
- package/dist/engine/AuditLogger.js +448 -0
- package/dist/engine/AuditLogger.js.map +1 -0
- package/dist/engine/GitHubApprovalManager.d.ts +106 -0
- package/dist/engine/GitHubApprovalManager.d.ts.map +1 -0
- package/dist/engine/GitHubApprovalManager.js +315 -0
- package/dist/engine/GitHubApprovalManager.js.map +1 -0
- package/dist/engine/RateLimiter.d.ts +79 -0
- package/dist/engine/RateLimiter.d.ts.map +1 -0
- package/dist/engine/RateLimiter.js +232 -0
- package/dist/engine/RateLimiter.js.map +1 -0
- package/dist/engine/RulesEngine.d.ts +77 -0
- package/dist/engine/RulesEngine.d.ts.map +1 -0
- package/dist/engine/RulesEngine.js +400 -0
- package/dist/engine/RulesEngine.js.map +1 -0
- package/dist/engine/TaskManager.d.ts +173 -0
- package/dist/engine/TaskManager.d.ts.map +1 -0
- package/dist/engine/TaskManager.js +678 -0
- package/dist/engine/TaskManager.js.map +1 -0
- package/dist/engine/index.d.ts +9 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +9 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/architecture.d.ts +9 -0
- package/dist/rules/architecture.d.ts.map +1 -0
- package/dist/rules/architecture.js +322 -0
- package/dist/rules/architecture.js.map +1 -0
- package/dist/rules/azure.d.ts +7 -0
- package/dist/rules/azure.d.ts.map +1 -0
- package/dist/rules/azure.js +138 -0
- package/dist/rules/azure.js.map +1 -0
- package/dist/rules/compliance.d.ts +9 -0
- package/dist/rules/compliance.d.ts.map +1 -0
- package/dist/rules/compliance.js +304 -0
- package/dist/rules/compliance.js.map +1 -0
- package/dist/rules/css.d.ts +10 -0
- package/dist/rules/css.d.ts.map +1 -0
- package/dist/rules/css.js +1239 -0
- package/dist/rules/css.js.map +1 -0
- package/dist/rules/flask.d.ts +7 -0
- package/dist/rules/flask.d.ts.map +1 -0
- package/dist/rules/flask.js +155 -0
- package/dist/rules/flask.js.map +1 -0
- package/dist/rules/index.d.ts +607 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +401 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/ml-ai.d.ts +7 -0
- package/dist/rules/ml-ai.d.ts.map +1 -0
- package/dist/rules/ml-ai.js +150 -0
- package/dist/rules/ml-ai.js.map +1 -0
- package/dist/rules/operational.d.ts +9 -0
- package/dist/rules/operational.d.ts.map +1 -0
- package/dist/rules/operational.js +318 -0
- package/dist/rules/operational.js.map +1 -0
- package/dist/rules/security.d.ts +9 -0
- package/dist/rules/security.d.ts.map +1 -0
- package/dist/rules/security.js +287 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/rules/storage.d.ts +7 -0
- package/dist/rules/storage.d.ts.map +1 -0
- package/dist/rules/storage.js +134 -0
- package/dist/rules/storage.js.map +1 -0
- package/dist/rules/stripe.d.ts +7 -0
- package/dist/rules/stripe.d.ts.map +1 -0
- package/dist/rules/stripe.js +140 -0
- package/dist/rules/stripe.js.map +1 -0
- package/dist/rules/testing.d.ts +7 -0
- package/dist/rules/testing.d.ts.map +1 -0
- package/dist/rules/testing.js +135 -0
- package/dist/rules/testing.js.map +1 -0
- package/dist/rules/ux.d.ts +9 -0
- package/dist/rules/ux.d.ts.map +1 -0
- package/dist/rules/ux.js +280 -0
- package/dist/rules/ux.js.map +1 -0
- package/dist/rules/websocket.d.ts +7 -0
- package/dist/rules/websocket.d.ts.map +1 -0
- package/dist/rules/websocket.js +136 -0
- package/dist/rules/websocket.js.map +1 -0
- package/dist/server.d.ts +49 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +2330 -0
- package/dist/server.js.map +1 -0
- package/dist/supervisor/AgentSupervisor.d.ts +235 -0
- package/dist/supervisor/AgentSupervisor.d.ts.map +1 -0
- package/dist/supervisor/AgentSupervisor.js +596 -0
- package/dist/supervisor/AgentSupervisor.js.map +1 -0
- package/dist/supervisor/ManagedServerRegistry.d.ts +48 -0
- package/dist/supervisor/ManagedServerRegistry.d.ts.map +1 -0
- package/dist/supervisor/ManagedServerRegistry.js +145 -0
- package/dist/supervisor/ManagedServerRegistry.js.map +1 -0
- package/dist/supervisor/ProjectTracker.d.ts +188 -0
- package/dist/supervisor/ProjectTracker.d.ts.map +1 -0
- package/dist/supervisor/ProjectTracker.js +617 -0
- package/dist/supervisor/ProjectTracker.js.map +1 -0
- package/dist/supervisor/index.d.ts +6 -0
- package/dist/supervisor/index.d.ts.map +1 -0
- package/dist/supervisor/index.js +6 -0
- package/dist/supervisor/index.js.map +1 -0
- package/dist/types/index.d.ts +1176 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +391 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/errors.d.ts +86 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +171 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/shell.d.ts +22 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +29 -0
- package/dist/utils/shell.js.map +1 -0
- 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
|