agent-master-devsecops 0.0.0-stage → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursorignore +23 -0
- package/README.md +371 -3
- package/agents/AGENT_DEVSECOPS.md +417 -0
- package/agents/AGENT_ORCHESTRATOR.md +264 -0
- package/agents/AGENT_QA.md +186 -0
- package/agents/AGENT_SCRUM.md +190 -0
- package/agents/AGENT_SRE.md +173 -0
- package/agents/AGENT_UIUX.md +162 -0
- package/agents/compact/AGENT_ORCHESTRATOR_COMPACTO.md +53 -0
- package/docs/ARCHITECTURE.md +148 -0
- package/docs/CALCULATIONS.md +17 -0
- package/docs/CHANGELOG.md +49 -0
- package/docs/ENGINEERING_RULES.md +252 -0
- package/docs/IDEAS.md +17 -0
- package/docs/STATE.md +43 -0
- package/docs/playbooks/PLAYBOOK_CIRCUIT_BREAKER_LLM.md +58 -0
- package/docs/playbooks/PLAYBOOK_OPENTELEMETRY_TRACING.md +58 -0
- package/package.json +47 -6
- package/scripts/a11y_auditor.js +187 -0
- package/scripts/ast_skeletonizer.js +220 -0
- package/scripts/atlassian_client.js +238 -0
- package/scripts/atlassian_sync_action.js +269 -0
- package/scripts/bootstrap_cli.js +468 -0
- package/scripts/circuit_breaker.js +330 -0
- package/scripts/code_quality_auditor.js +142 -0
- package/scripts/confluence_sync.js +337 -0
- package/scripts/context_compressor.js +139 -0
- package/scripts/contract_test_validator.js +166 -0
- package/scripts/credentials_guard.js +216 -0
- package/scripts/domain_idea_miner.js +364 -0
- package/scripts/eval_harness.js +100 -0
- package/scripts/fast_feature_scaffold.js +338 -0
- package/scripts/git_hygiene_linter.js +186 -0
- package/scripts/hot_state_cache.js +95 -0
- package/scripts/jira_manager.js +408 -0
- package/scripts/magic_prompt_generator.js +205 -0
- package/scripts/mcp_server.js +1884 -0
- package/scripts/multi_agent_orchestrator.js +258 -0
- package/scripts/otel_tracer.js +228 -0
- package/scripts/perf_benchmark.js +153 -0
- package/scripts/pr_reviewer.js +373 -0
- package/scripts/sast_scanner.js +180 -0
- package/scripts/sca_dependency_auditor.js +167 -0
- package/scripts/smart_onboarding.js +610 -0
- package/scripts/sre_remediation_engine.js +174 -0
- package/scripts/universal_packager.js +313 -0
- package/scripts/web_inspector.js +355 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/web_inspector.js
|
|
4
|
+
*
|
|
5
|
+
* Web Dashboard & Playground Interativo Local (AGDEV-28 / I-14).
|
|
6
|
+
* Servidor HTTP leve em Node.js puro (sem frameworks pesados) para inspecionar
|
|
7
|
+
* ferramentas MCP, executar chamadas interativas, copiar prompts e rodar o harness.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const http = require('node:http');
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
const os = require('node:os');
|
|
14
|
+
|
|
15
|
+
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
16
|
+
const { processMessage, TOOLS } = require('./mcp_server.js');
|
|
17
|
+
const { MagicPromptGenerator } = require('./magic_prompt_generator.js');
|
|
18
|
+
const { evaluateCompliance } = require('./eval_harness.js');
|
|
19
|
+
|
|
20
|
+
function getTelemetry() {
|
|
21
|
+
const mem = process.memoryUsage();
|
|
22
|
+
return {
|
|
23
|
+
nodeVersion: process.version,
|
|
24
|
+
platform: process.platform,
|
|
25
|
+
arch: process.arch,
|
|
26
|
+
uptimeSeconds: Math.floor(process.uptime()),
|
|
27
|
+
heapUsedMB: (mem.heapUsed / 1024 / 1024).toFixed(2),
|
|
28
|
+
heapTotalMB: (mem.heapTotal / 1024 / 1024).toFixed(2),
|
|
29
|
+
rssMB: (mem.rss / 1024 / 1024).toFixed(2),
|
|
30
|
+
toolsCount: TOOLS.length
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderHtmlDashboard() {
|
|
35
|
+
const telemetry = getTelemetry();
|
|
36
|
+
const magicGen = new MagicPromptGenerator(ROOT_DIR);
|
|
37
|
+
const bookmarklet = magicGen.generateBookmarklet();
|
|
38
|
+
const magicPrompt = magicGen.generateMagicPrompt();
|
|
39
|
+
|
|
40
|
+
return `<!DOCTYPE html>
|
|
41
|
+
<html lang="pt-BR">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="UTF-8">
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
45
|
+
<title>Agent Master DevSecOps — Web Dashboard & Playground</title>
|
|
46
|
+
<style>
|
|
47
|
+
:root {
|
|
48
|
+
--bg: #090d16;
|
|
49
|
+
--card-bg: #131c2e;
|
|
50
|
+
--border: #23324d;
|
|
51
|
+
--text: #f1f5f9;
|
|
52
|
+
--muted: #94a3b8;
|
|
53
|
+
--primary: #38bdf8;
|
|
54
|
+
--primary-hover: #0284c7;
|
|
55
|
+
--success: #10b981;
|
|
56
|
+
--warning: #f59e0b;
|
|
57
|
+
--danger: #ef4444;
|
|
58
|
+
--code-bg: #05080f;
|
|
59
|
+
}
|
|
60
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
61
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--text); padding: 24px; line-height: 1.5; }
|
|
62
|
+
header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 1px solid var(--border); }
|
|
63
|
+
h1 { font-size: 20px; color: var(--primary); display: flex; align-items: center; gap: 8px; }
|
|
64
|
+
.badge { background: #0c4a6e; color: var(--primary); padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; }
|
|
65
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 20px; }
|
|
66
|
+
.card { background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px; padding: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); }
|
|
67
|
+
.card h2 { font-size: 16px; color: var(--text); margin-bottom: 14px; display: flex; justify-content: space-between; align-items: center; }
|
|
68
|
+
.telemetry-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #1a273f; font-size: 13px; }
|
|
69
|
+
.telemetry-row span:last-child { font-weight: bold; color: var(--primary); }
|
|
70
|
+
select, input, textarea, button { width: 100%; padding: 10px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--code-bg); color: var(--text); font-size: 13px; font-family: inherit; margin-bottom: 12px; }
|
|
71
|
+
textarea { font-family: monospace; min-height: 90px; resize: vertical; }
|
|
72
|
+
button { background: var(--primary); color: #05080f; font-weight: 600; cursor: pointer; border: none; transition: background 0.2s; }
|
|
73
|
+
button:hover { background: var(--primary-hover); }
|
|
74
|
+
pre { background: var(--code-bg); border: 1px solid var(--border); border-radius: 6px; padding: 12px; font-size: 12px; color: #a5f3fc; overflow-x: auto; max-height: 220px; }
|
|
75
|
+
.btn-bm { display: inline-block; text-align: center; background: #0284c7; color: white; padding: 10px 16px; border-radius: 6px; text-decoration: none; font-weight: bold; font-size: 13px; margin-bottom: 12px; }
|
|
76
|
+
.btn-bm:hover { background: #0369a1; }
|
|
77
|
+
.copy-btn { background: #1e293b; color: var(--primary); border: 1px solid var(--border); margin-top: 4px; padding: 6px 12px; font-size: 12px; }
|
|
78
|
+
.copy-btn:hover { background: #334155; }
|
|
79
|
+
</style>
|
|
80
|
+
</head>
|
|
81
|
+
<body>
|
|
82
|
+
<header>
|
|
83
|
+
<h1>⚡ Agent Master DevSecOps <span class="badge">v3.2.0</span></h1>
|
|
84
|
+
<div style="font-size: 13px; color: var(--muted);">Local Web Dashboard & Playground (AGDEV-28)</div>
|
|
85
|
+
</header>
|
|
86
|
+
|
|
87
|
+
<div class="grid">
|
|
88
|
+
<!-- Card 1: Telemetria & Status -->
|
|
89
|
+
<div class="card">
|
|
90
|
+
<h2>📊 Telemetria de Runtime</h2>
|
|
91
|
+
<div class="telemetry-row"><span>Node.js</span><span>${telemetry.nodeVersion}</span></div>
|
|
92
|
+
<div class="telemetry-row"><span>Plataforma</span><span>${telemetry.platform} (${telemetry.arch})</span></div>
|
|
93
|
+
<div class="telemetry-row"><span>V8 Heap Usada</span><span>${telemetry.heapUsedMB} MB</span></div>
|
|
94
|
+
<div class="telemetry-row"><span>Memória RSS</span><span>${telemetry.rssMB} MB</span></div>
|
|
95
|
+
<div class="telemetry-row"><span>Uptime</span><span>${telemetry.uptimeSeconds}s</span></div>
|
|
96
|
+
<div class="telemetry-row"><span>Ferramentas MCP Ativas</span><span>${telemetry.toolsCount}</span></div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<!-- Card 2: 1-Click Magic Prompt & Bookmarklet -->
|
|
100
|
+
<div class="card">
|
|
101
|
+
<h2>🚀 Ativação Web Instantânea</h2>
|
|
102
|
+
<p style="font-size: 13px; color: var(--muted); margin-bottom: 12px;">
|
|
103
|
+
Arraste para a barra de favoritos para ativar o Agent Master em 1 clique em qualquer chat de IA:
|
|
104
|
+
</p>
|
|
105
|
+
<a class="btn-bm" href="${bookmarklet}">⚡ Ativar Agent Master DevSecOps</a>
|
|
106
|
+
<button class="copy-btn" onclick="copyPrompt()">📋 Copiar Magic Prompt (< 900 tokens)</button>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<!-- Card 3: MCP Tool Playground -->
|
|
110
|
+
<div class="card" style="grid-column: span 2;">
|
|
111
|
+
<h2>🛠️ MCP Tools Playground (JSON-RPC 2.0)</h2>
|
|
112
|
+
<label style="font-size: 12px; color: var(--muted); display: block; margin-bottom: 4px;">Selecione a Ferramenta MCP:</label>
|
|
113
|
+
<select id="toolSelect" onchange="loadToolTemplate()">
|
|
114
|
+
${TOOLS.map(t => `<option value="${t.name}">${t.name} — ${t.description.slice(0, 70)}...</option>`).join('')}
|
|
115
|
+
</select>
|
|
116
|
+
|
|
117
|
+
<label style="font-size: 12px; color: var(--muted); display: block; margin-bottom: 4px;">Argumentos JSON:</label>
|
|
118
|
+
<textarea id="toolArgs">{}</textarea>
|
|
119
|
+
|
|
120
|
+
<button onclick="runTool()">▶️ Executar Tool via MCP</button>
|
|
121
|
+
|
|
122
|
+
<label style="font-size: 12px; color: var(--muted); display: block; margin-top: 8px; margin-bottom: 4px;">Resposta JSON-RPC:</label>
|
|
123
|
+
<pre id="toolOutput">// Clique em Executar para ver a resposta</pre>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<!-- Card 4: Evaluation Harness Testbed -->
|
|
127
|
+
<div class="card" style="grid-column: span 2;">
|
|
128
|
+
<h2>🎯 LLM Evaluation Harness Testbed (Regra 14 & Normas)</h2>
|
|
129
|
+
<p style="font-size: 13px; color: var(--muted); margin-bottom: 12px;">
|
|
130
|
+
Avalie empiricamente a resposta de qualquer LLM contra as 14 Regras de Engenharia:
|
|
131
|
+
</p>
|
|
132
|
+
<input type="text" id="evalModel" value="Claude 3.5 Sonnet / GPT-4o" placeholder="Nome do modelo">
|
|
133
|
+
<textarea id="evalResponse" placeholder="Cole a resposta gerada pela LLM aqui para avaliação empírica..."></textarea>
|
|
134
|
+
<button onclick="runEval()">⚖️ Avaliar Conformidade com as 14 Regras</button>
|
|
135
|
+
<pre id="evalOutput">// Resultado do scoring será exibido aqui</pre>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<script>
|
|
140
|
+
const MAGIC_PROMPT = ${JSON.stringify(magicPrompt)};
|
|
141
|
+
|
|
142
|
+
function copyPrompt() {
|
|
143
|
+
navigator.clipboard.writeText(MAGIC_PROMPT).then(() => {
|
|
144
|
+
alert("✅ Magic Prompt copiado para a área de transferência!");
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const TOOL_TEMPLATES = {
|
|
149
|
+
agent_validate_idea: JSON.stringify({
|
|
150
|
+
ideaTitle: "Otimização de buffer de cache",
|
|
151
|
+
ideaDescription: "Poda de registros expirados para evitar memory leak",
|
|
152
|
+
projectStack: "Node.js, Express, SQLite",
|
|
153
|
+
projectDomain: "API de pagamentos e checkout"
|
|
154
|
+
}, null, 2),
|
|
155
|
+
agent_sast_scan: JSON.stringify({
|
|
156
|
+
snippet: "const q = 'SELECT * FROM users WHERE id = ' + req.body.id;"
|
|
157
|
+
}, null, 2),
|
|
158
|
+
agent_audit_quality: JSON.stringify({
|
|
159
|
+
code: "function test(a) { if (a) { return 1; } else { return 0; } }"
|
|
160
|
+
}, null, 2),
|
|
161
|
+
agent_sre_telemetry: JSON.stringify({}, null, 2),
|
|
162
|
+
agent_bootstrap_environment: JSON.stringify({ dryRun: true }, null, 2),
|
|
163
|
+
agent_generate_magic_prompt: JSON.stringify({ dryRun: true }, null, 2)
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
function loadToolTemplate() {
|
|
167
|
+
const tool = document.getElementById('toolSelect').value;
|
|
168
|
+
document.getElementById('toolArgs').value = TOOL_TEMPLATES[tool] || '{}';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function runTool() {
|
|
172
|
+
const tool = document.getElementById('toolSelect').value;
|
|
173
|
+
let args = {};
|
|
174
|
+
try {
|
|
175
|
+
args = JSON.parse(document.getElementById('toolArgs').value);
|
|
176
|
+
} catch (e) {
|
|
177
|
+
alert("JSON inválido nos argumentos!");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
document.getElementById('toolOutput').innerText = "Processando...";
|
|
182
|
+
const res = await fetch('/api/mcp', {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: { 'Content-Type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({ name: tool, arguments: args })
|
|
186
|
+
});
|
|
187
|
+
const data = await res.json();
|
|
188
|
+
document.getElementById('toolOutput').innerText = JSON.stringify(data, null, 2);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function runEval() {
|
|
192
|
+
const modelName = document.getElementById('evalModel').value;
|
|
193
|
+
const responseReceived = document.getElementById('evalResponse').value;
|
|
194
|
+
|
|
195
|
+
if (!responseReceived.trim()) {
|
|
196
|
+
alert("Por favor cole a resposta da LLM.");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
document.getElementById('evalOutput').innerText = "Avaliando resposta...";
|
|
201
|
+
const res = await fetch('/api/eval', {
|
|
202
|
+
method: 'POST',
|
|
203
|
+
headers: { 'Content-Type': 'application/json' },
|
|
204
|
+
body: JSON.stringify({ modelName, responseReceived })
|
|
205
|
+
});
|
|
206
|
+
const data = await res.json();
|
|
207
|
+
document.getElementById('evalOutput').innerText = JSON.stringify(data, null, 2);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
loadToolTemplate();
|
|
211
|
+
</script>
|
|
212
|
+
</body>
|
|
213
|
+
</html>`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function parseJsonBody(req) {
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
let body = '';
|
|
219
|
+
req.on('data', chunk => { body += chunk; });
|
|
220
|
+
req.on('end', () => {
|
|
221
|
+
try {
|
|
222
|
+
resolve(body ? JSON.parse(body) : {});
|
|
223
|
+
} catch (err) {
|
|
224
|
+
reject(err);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
req.on('error', reject);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function createInspectorServer(options = {}) {
|
|
232
|
+
const port = options.port || 4040;
|
|
233
|
+
const host = options.host || '127.0.0.1';
|
|
234
|
+
|
|
235
|
+
const server = http.createServer(async (req, res) => {
|
|
236
|
+
// CORS headers
|
|
237
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
238
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
239
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
240
|
+
|
|
241
|
+
if (req.method === 'OPTIONS') {
|
|
242
|
+
res.writeHead(204);
|
|
243
|
+
res.end();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const parsedUrl = new URL(req.url, `http://${req.headers.host || 'localhost'}`);
|
|
248
|
+
const pathname = parsedUrl.pathname;
|
|
249
|
+
|
|
250
|
+
// 1. Dashboard UI
|
|
251
|
+
if (pathname === '/' && req.method === 'GET') {
|
|
252
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
253
|
+
res.end(renderHtmlDashboard());
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 2. Telemetry & Status API
|
|
258
|
+
if (pathname === '/api/status' && req.method === 'GET') {
|
|
259
|
+
const data = {
|
|
260
|
+
status: 'UP',
|
|
261
|
+
telemetry: getTelemetry(),
|
|
262
|
+
tools: TOOLS.map(t => ({ name: t.name, description: t.description }))
|
|
263
|
+
};
|
|
264
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
265
|
+
res.end(JSON.stringify(data, null, 2));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 3. MCP Tool Proxy
|
|
270
|
+
if (pathname === '/api/mcp' && req.method === 'POST') {
|
|
271
|
+
try {
|
|
272
|
+
const body = await parseJsonBody(req);
|
|
273
|
+
const rpcRequest = {
|
|
274
|
+
jsonrpc: '2.0',
|
|
275
|
+
id: Date.now(),
|
|
276
|
+
method: 'tools/call',
|
|
277
|
+
params: {
|
|
278
|
+
name: body.name,
|
|
279
|
+
arguments: body.arguments || {}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const rpcResponse = processMessage(rpcRequest);
|
|
283
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
284
|
+
res.end(JSON.stringify(rpcResponse, null, 2));
|
|
285
|
+
} catch (err) {
|
|
286
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
287
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
288
|
+
}
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 4. Eval Harness API
|
|
293
|
+
if (pathname === '/api/eval' && req.method === 'POST') {
|
|
294
|
+
try {
|
|
295
|
+
const body = await parseJsonBody(req);
|
|
296
|
+
const evalResult = evaluateCompliance(body.modelName || 'Custom Model', body.promptSent || '', body.responseReceived || '');
|
|
297
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
298
|
+
res.end(JSON.stringify(evalResult, null, 2));
|
|
299
|
+
} catch (err) {
|
|
300
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
301
|
+
res.end(JSON.stringify({ error: String(err) }));
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// 5. Magic Prompt API
|
|
307
|
+
if (pathname === '/api/magic-prompt' && req.method === 'GET') {
|
|
308
|
+
const gen = new MagicPromptGenerator(ROOT_DIR);
|
|
309
|
+
const prompt = gen.generateMagicPrompt();
|
|
310
|
+
const bookmarklet = gen.generateBookmarklet();
|
|
311
|
+
const tokens = gen.estimateTokens(prompt);
|
|
312
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
313
|
+
res.end(JSON.stringify({ prompt, bookmarklet, tokens }));
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// 404 Fallback
|
|
318
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
319
|
+
res.end(JSON.stringify({ error: 'Endpoint não encontrado', pathname }));
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
server,
|
|
324
|
+
port,
|
|
325
|
+
host,
|
|
326
|
+
listen: (cb) => server.listen(port, host, cb),
|
|
327
|
+
close: () => new Promise(resolve => server.close(resolve))
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (require.main === module) {
|
|
332
|
+
const args = process.argv.slice(2);
|
|
333
|
+
let port = 4040;
|
|
334
|
+
const portIdx = args.findIndex(a => a === '--port' || a === '-p');
|
|
335
|
+
if (portIdx !== -1 && args[portIdx + 1]) {
|
|
336
|
+
port = parseInt(args[portIdx + 1], 10);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const inspector = createInspectorServer({ port });
|
|
340
|
+
inspector.listen(() => {
|
|
341
|
+
console.log('\n============================================================');
|
|
342
|
+
console.log('⚡ Agent Master DevSecOps — Web Dashboard & Inspector');
|
|
343
|
+
console.log('============================================================\n');
|
|
344
|
+
console.log(`🌐 Dashboard disponível em: http://localhost:${port}`);
|
|
345
|
+
console.log(`📊 Endpoint de Métricas & Status: http://localhost:${port}/api/status`);
|
|
346
|
+
console.log(`🛠️ Playground MCP: http://localhost:${port}/api/mcp`);
|
|
347
|
+
console.log('\nPressione Ctrl+C para encerrar o servidor.\n');
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
module.exports = {
|
|
352
|
+
createInspectorServer,
|
|
353
|
+
getTelemetry,
|
|
354
|
+
renderHtmlDashboard
|
|
355
|
+
};
|