agent-master-devsecops 0.0.0-stage → 5.1.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/README.md +204 -2
- package/agents/AGENT_DEVSECOPS.md +32 -0
- package/agents/AGENT_INFRA.md +31 -0
- package/agents/AGENT_ORCHESTRATOR.md +39 -0
- package/agents/AGENT_QA.md +58 -0
- package/agents/AGENT_SCRUM.md +23 -0
- package/agents/AGENT_SRE.md +22 -0
- package/agents/AGENT_UIUX.md +26 -0
- package/docs/ARCHITECTURE.md +152 -0
- package/docs/CALCULATIONS.md +17 -0
- package/docs/CHANGELOG.md +112 -0
- package/docs/ENGINEERING_RULES.md +56 -0
- package/docs/IDEAS.md +17 -0
- package/docs/LOCAL_BACKLOG.md +20 -0
- package/docs/STATE.md +111 -0
- package/docs/playbooks/PLAYBOOK_CIRCUIT_BREAKER_LLM.md +58 -0
- package/docs/playbooks/PLAYBOOK_OPENTELEMETRY_TRACING.md +58 -0
- package/package.json +57 -4
- package/scripts/auditors/a11y_auditor.js +462 -0
- package/scripts/auditors/code_quality_auditor.js +444 -0
- package/scripts/auditors/contract_test_validator.js +396 -0
- package/scripts/auditors/eval_harness.js +213 -0
- package/scripts/auditors/git_hygiene_linter.js +391 -0
- package/scripts/auditors/pr_reviewer.js +627 -0
- package/scripts/auditors/sast_scanner.js +442 -0
- package/scripts/auditors/sca_dependency_auditor.js +673 -0
- package/scripts/bin/bootstrap_cli.js +597 -0
- package/scripts/bin/domain_idea_miner.js +658 -0
- package/scripts/bin/smart_onboarding.js +905 -0
- package/scripts/bin/web_inspector.js +578 -0
- package/scripts/core/architecture_advisor.js +378 -0
- package/scripts/core/ast_skeletonizer.js +413 -0
- package/scripts/core/autonomous_remediation_engine.js +305 -0
- package/scripts/core/circuit_breaker.js +546 -0
- package/scripts/core/context_compressor.js +237 -0
- package/scripts/core/fast_feature_scaffold.js +840 -0
- package/scripts/core/hot_state_cache.js +238 -0
- package/scripts/core/knowledge_gateway.js +888 -0
- package/scripts/core/magic_prompt_generator.js +250 -0
- package/scripts/core/multi_agent_orchestrator.js +421 -0
- package/scripts/core/otel_tracer.js +335 -0
- package/scripts/core/perf_benchmark.js +212 -0
- package/scripts/core/sarif_engine.js +299 -0
- package/scripts/core/sre_remediation_engine.js +236 -0
- package/scripts/core/universal_packager.js +357 -0
- package/scripts/integrations/atlassian_client.js +600 -0
- package/scripts/integrations/atlassian_sync_action.js +576 -0
- package/scripts/integrations/confluence_sync.js +684 -0
- package/scripts/integrations/credentials_guard.js +500 -0
- package/scripts/integrations/jira_manager.js +722 -0
- package/scripts/mcp/handlers/atlassian_handlers.js +300 -0
- package/scripts/mcp/handlers/core_handlers.js +419 -0
- package/scripts/mcp/handlers/qa_handlers.js +502 -0
- package/scripts/mcp/handlers/rules_handlers.js +379 -0
- package/scripts/mcp/handlers/scaffold_handlers.js +334 -0
- package/scripts/mcp/handlers/sre_handlers.js +443 -0
- package/scripts/mcp/resources_registry.js +453 -0
- package/scripts/mcp/server.js +408 -0
- package/scripts/mcp/tool_handlers.js +444 -0
- package/scripts/mcp/tools_registry.js +1123 -0
- package/scripts/mcp_server.js +236 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/mcp/resources_registry.js
|
|
3
|
+
*
|
|
4
|
+
* Resources Registry — Catálogo e Leitor de Recursos Canônicos MCP.
|
|
5
|
+
* Fornece acesso à documentação viva (Princípios Canônicos, Arquitetura, Backlog de Ideias,
|
|
6
|
+
* Livro-Razão e Estado Ativo) e barramento de eventos multi-agente.
|
|
7
|
+
* Compatível com o protocolo oficial MCP (Model Context Protocol) resources/list e resources/read.
|
|
8
|
+
*
|
|
9
|
+
* Versão: 5.1.0 Enterprise
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const fs = require('node:fs');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const { createSarifReport } = require('../core/sarif_engine.js');
|
|
17
|
+
|
|
18
|
+
const ROOT_DIR = path.resolve(__dirname, '../..');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Catálogo declarativo imutável de recursos canônicos do Agent Master
|
|
22
|
+
*/
|
|
23
|
+
const RESOURCE_DEFINITIONS = Object.freeze({
|
|
24
|
+
'agent://rules': Object.freeze({
|
|
25
|
+
uri: 'agent://rules',
|
|
26
|
+
name: 'Os 10 Princípios Canônicos de Engenharia de Software & Governança (ENGINEERING_RULES.md)',
|
|
27
|
+
mimeType: 'text/markdown',
|
|
28
|
+
relPath: 'docs/ENGINEERING_RULES.md'
|
|
29
|
+
}),
|
|
30
|
+
'agent://architecture': Object.freeze({
|
|
31
|
+
uri: 'agent://architecture',
|
|
32
|
+
name: 'Arquitetura Multi-Agente & Handovers (ARCHITECTURE.md)',
|
|
33
|
+
mimeType: 'text/markdown',
|
|
34
|
+
relPath: 'docs/ARCHITECTURE.md'
|
|
35
|
+
}),
|
|
36
|
+
'agent://ideas': Object.freeze({
|
|
37
|
+
uri: 'agent://ideas',
|
|
38
|
+
name: 'Backlog Vivo de Ideias & Auto-Evolução (IDEAS.md)',
|
|
39
|
+
mimeType: 'text/markdown',
|
|
40
|
+
relPath: 'docs/IDEAS.md'
|
|
41
|
+
}),
|
|
42
|
+
'agent://events': Object.freeze({
|
|
43
|
+
uri: 'agent://events',
|
|
44
|
+
name: 'Histórico e Barramento de Eventos Multi-Agente',
|
|
45
|
+
mimeType: 'application/json',
|
|
46
|
+
dynamicProvider: () => {
|
|
47
|
+
const { EVENT_TYPES, AGENT_PERSONAS } = require('../core/multi_agent_orchestrator.js');
|
|
48
|
+
return JSON.stringify({
|
|
49
|
+
status: 'ACTIVE',
|
|
50
|
+
busType: 'Mesh-Hierarchical Event Bus',
|
|
51
|
+
supportedEvents: Object.keys(EVENT_TYPES),
|
|
52
|
+
registeredPersonas: Object.keys(AGENT_PERSONAS || {})
|
|
53
|
+
}, null, 2);
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
'agent://changelog': Object.freeze({
|
|
57
|
+
uri: 'agent://changelog',
|
|
58
|
+
name: 'Livro-Razão Imutável de Entregas (CHANGELOG.md)',
|
|
59
|
+
mimeType: 'text/markdown',
|
|
60
|
+
relPath: 'docs/CHANGELOG.md'
|
|
61
|
+
}),
|
|
62
|
+
'agent://state': Object.freeze({
|
|
63
|
+
uri: 'agent://state',
|
|
64
|
+
name: 'Quadro de Execução Ativo do Framework (STATE.md)',
|
|
65
|
+
mimeType: 'text/markdown',
|
|
66
|
+
relPath: 'docs/STATE.md'
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Lista de recursos exposta pelo protocolo MCP resources/list (imutável)
|
|
72
|
+
*/
|
|
73
|
+
const RESOURCES = Object.freeze(
|
|
74
|
+
Object.values(RESOURCE_DEFINITIONS).map(def => Object.freeze({
|
|
75
|
+
uri: def.uri,
|
|
76
|
+
name: def.name,
|
|
77
|
+
mimeType: def.mimeType
|
|
78
|
+
}))
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Helper puro de resolução de caminho absoluto com proteção contra Path Traversal (CWE-22)
|
|
83
|
+
*/
|
|
84
|
+
function resolveDocFile(rootDir, relPath) {
|
|
85
|
+
const safeRoot = path.resolve(rootDir || ROOT_DIR);
|
|
86
|
+
const targetPath = path.resolve(safeRoot, relPath);
|
|
87
|
+
if (!targetPath.startsWith(safeRoot)) {
|
|
88
|
+
throw new Error(`Tentativa de Path Traversal bloqueada: ${relPath}`);
|
|
89
|
+
}
|
|
90
|
+
return targetPath;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Helpers funcionais puros para envelopes JSON-RPC 2.0 (DRY)
|
|
95
|
+
*/
|
|
96
|
+
function buildSuccessResponse(id, result) {
|
|
97
|
+
return {
|
|
98
|
+
jsonrpc: '2.0',
|
|
99
|
+
id: id !== undefined && id !== null ? id : null,
|
|
100
|
+
result
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function buildErrorResponse(id, code, message, data = null) {
|
|
105
|
+
const error = { code, message };
|
|
106
|
+
if (data !== null && data !== undefined) {
|
|
107
|
+
error.data = data;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
jsonrpc: '2.0',
|
|
111
|
+
id: id !== undefined && id !== null ? id : null,
|
|
112
|
+
error
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function buildResourceContentResponse(id, uri, mimeType, text) {
|
|
117
|
+
return buildSuccessResponse(id, {
|
|
118
|
+
contents: [
|
|
119
|
+
{
|
|
120
|
+
uri,
|
|
121
|
+
mimeType,
|
|
122
|
+
text
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Classe Canônica ResourcesRegistry — Gerenciador de Recursos e Documentação Viva MCP
|
|
130
|
+
*/
|
|
131
|
+
class ResourcesRegistry {
|
|
132
|
+
constructor(rootDir = ROOT_DIR, customRegistry = null) {
|
|
133
|
+
this.rootDir = path.resolve(rootDir || ROOT_DIR);
|
|
134
|
+
this.customRegistry = customRegistry ? new Map(Object.entries(customRegistry)) : new Map();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static get ROOT_DIR() {
|
|
138
|
+
return ROOT_DIR;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static get RESOURCES() {
|
|
142
|
+
return RESOURCES;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static get RESOURCE_DEFINITIONS() {
|
|
146
|
+
return RESOURCE_DEFINITIONS;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Registra dinamicamente um novo recurso no registro em runtime
|
|
151
|
+
*/
|
|
152
|
+
registerResource(uri, definition) {
|
|
153
|
+
if (!uri || typeof uri !== 'string') {
|
|
154
|
+
throw new Error('URI do recurso deve ser uma string válida');
|
|
155
|
+
}
|
|
156
|
+
if (!definition || typeof definition !== 'object') {
|
|
157
|
+
throw new Error('Definição do recurso deve ser um objeto válido');
|
|
158
|
+
}
|
|
159
|
+
this.customRegistry.set(uri, Object.freeze({
|
|
160
|
+
uri,
|
|
161
|
+
name: definition.name || uri,
|
|
162
|
+
mimeType: definition.mimeType || 'text/plain',
|
|
163
|
+
relPath: definition.relPath || null,
|
|
164
|
+
dynamicProvider: typeof definition.dynamicProvider === 'function' ? definition.dynamicProvider : null
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Resolve a definição de um recurso por URI
|
|
170
|
+
*/
|
|
171
|
+
getDefinition(uri) {
|
|
172
|
+
if (!uri || typeof uri !== 'string') return null;
|
|
173
|
+
if (this.customRegistry.has(uri)) {
|
|
174
|
+
return this.customRegistry.get(uri);
|
|
175
|
+
}
|
|
176
|
+
return RESOURCE_DEFINITIONS[uri] || null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Lista todos os recursos disponíveis (estático e instância)
|
|
181
|
+
*/
|
|
182
|
+
listResources() {
|
|
183
|
+
const defaultList = [...RESOURCES];
|
|
184
|
+
const customList = Array.from(this.customRegistry.values()).map(def => ({
|
|
185
|
+
uri: def.uri,
|
|
186
|
+
name: def.name,
|
|
187
|
+
mimeType: def.mimeType
|
|
188
|
+
}));
|
|
189
|
+
return [...defaultList, ...customList];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static handleResourcesList(id) {
|
|
193
|
+
return buildSuccessResponse(id, {
|
|
194
|
+
resources: RESOURCES
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
handleResourcesList(id) {
|
|
199
|
+
return buildSuccessResponse(id, {
|
|
200
|
+
resources: this.listResources()
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Resolução síncrona de conteúdo de recurso
|
|
206
|
+
*/
|
|
207
|
+
resolveContentSync(uri) {
|
|
208
|
+
const def = this.getDefinition(uri);
|
|
209
|
+
if (!def) return null;
|
|
210
|
+
|
|
211
|
+
if (typeof def.dynamicProvider === 'function') {
|
|
212
|
+
return {
|
|
213
|
+
uri: def.uri,
|
|
214
|
+
mimeType: def.mimeType,
|
|
215
|
+
text: def.dynamicProvider()
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (def.relPath) {
|
|
220
|
+
const filePath = resolveDocFile(this.rootDir, def.relPath);
|
|
221
|
+
if (fs.existsSync(filePath)) {
|
|
222
|
+
const text = fs.readFileSync(filePath, 'utf8');
|
|
223
|
+
return {
|
|
224
|
+
uri: def.uri,
|
|
225
|
+
mimeType: def.mimeType,
|
|
226
|
+
text
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Resolução assíncrona de conteúdo de recurso
|
|
236
|
+
*/
|
|
237
|
+
async resolveContentAsync(uri) {
|
|
238
|
+
const def = this.getDefinition(uri);
|
|
239
|
+
if (!def) return null;
|
|
240
|
+
|
|
241
|
+
if (typeof def.dynamicProvider === 'function') {
|
|
242
|
+
const res = def.dynamicProvider();
|
|
243
|
+
const text = res instanceof Promise ? await res : res;
|
|
244
|
+
return {
|
|
245
|
+
uri: def.uri,
|
|
246
|
+
mimeType: def.mimeType,
|
|
247
|
+
text
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (def.relPath) {
|
|
252
|
+
const filePath = resolveDocFile(this.rootDir, def.relPath);
|
|
253
|
+
try {
|
|
254
|
+
const text = await fs.promises.readFile(filePath, 'utf8');
|
|
255
|
+
return {
|
|
256
|
+
uri: def.uri,
|
|
257
|
+
mimeType: def.mimeType,
|
|
258
|
+
text
|
|
259
|
+
};
|
|
260
|
+
} catch {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Leitura de recurso MCP síncrona (JSON-RPC 2.0)
|
|
270
|
+
*/
|
|
271
|
+
handleResourceRead(id, params) {
|
|
272
|
+
try {
|
|
273
|
+
const safeParams = params && typeof params === 'object' ? params : {};
|
|
274
|
+
const uri = safeParams.uri;
|
|
275
|
+
const content = this.resolveContentSync(uri);
|
|
276
|
+
|
|
277
|
+
if (content) {
|
|
278
|
+
return buildResourceContentResponse(id, content.uri, content.mimeType, content.text);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return buildErrorResponse(id, -32602, `Recurso não encontrado: ${uri}`);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
return buildErrorResponse(id, -32603, `Falha interna ao ler recurso: ${err.message}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static handleResourceRead(id, params) {
|
|
288
|
+
const defaultInstance = new ResourcesRegistry(ROOT_DIR);
|
|
289
|
+
return defaultInstance.handleResourceRead(id, params);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Leitura de recurso MCP assíncrona (JSON-RPC 2.0)
|
|
294
|
+
*/
|
|
295
|
+
async handleResourceReadAsync(id, params) {
|
|
296
|
+
try {
|
|
297
|
+
const safeParams = params && typeof params === 'object' ? params : {};
|
|
298
|
+
const uri = safeParams.uri;
|
|
299
|
+
const content = await this.resolveContentAsync(uri);
|
|
300
|
+
|
|
301
|
+
if (content) {
|
|
302
|
+
return buildResourceContentResponse(id, content.uri, content.mimeType, content.text);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return buildErrorResponse(id, -32602, `Recurso não encontrado: ${uri}`);
|
|
306
|
+
} catch (err) {
|
|
307
|
+
return buildErrorResponse(id, -32603, `Falha interna ao ler recurso: ${err.message}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
static async handleResourceReadAsync(id, params) {
|
|
312
|
+
const defaultInstance = new ResourcesRegistry(ROOT_DIR);
|
|
313
|
+
return await defaultInstance.handleResourceReadAsync(id, params);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Auditoria de integridade de todos os recursos no padrão OASIS SARIF v2.1.0
|
|
318
|
+
*/
|
|
319
|
+
auditToSarif() {
|
|
320
|
+
const findings = [];
|
|
321
|
+
const allDefs = { ...RESOURCE_DEFINITIONS, ...Object.fromEntries(this.customRegistry) };
|
|
322
|
+
|
|
323
|
+
for (const [uri, def] of Object.entries(allDefs)) {
|
|
324
|
+
if (def.relPath) {
|
|
325
|
+
try {
|
|
326
|
+
const filePath = resolveDocFile(this.rootDir, def.relPath);
|
|
327
|
+
if (!fs.existsSync(filePath)) {
|
|
328
|
+
findings.push({
|
|
329
|
+
ruleId: 'RULE-RES-001',
|
|
330
|
+
severity: 'HIGH',
|
|
331
|
+
filename: def.relPath,
|
|
332
|
+
line: 1,
|
|
333
|
+
column: 1,
|
|
334
|
+
snippet: `URI: ${uri}`,
|
|
335
|
+
message: `Documento de governança '${def.relPath}' não foi encontrado no disco.`,
|
|
336
|
+
remediation: `Restaurar ou provisionar o arquivo '${def.relPath}' para conformidade com a Tríade.`
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
} catch (err) {
|
|
340
|
+
findings.push({
|
|
341
|
+
ruleId: 'RULE-RES-001',
|
|
342
|
+
severity: 'HIGH',
|
|
343
|
+
filename: def.relPath,
|
|
344
|
+
line: 1,
|
|
345
|
+
column: 1,
|
|
346
|
+
snippet: `URI: ${uri}`,
|
|
347
|
+
message: `Erro ao validar caminho do recurso: ${err.message}`,
|
|
348
|
+
remediation: 'Verificar integridade estrutural e permissões de acesso ao arquivo.'
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
} else if (typeof def.dynamicProvider === 'function') {
|
|
352
|
+
try {
|
|
353
|
+
const res = def.dynamicProvider();
|
|
354
|
+
if (!res) throw new Error('Provider retornou payload nulo');
|
|
355
|
+
} catch (err) {
|
|
356
|
+
findings.push({
|
|
357
|
+
ruleId: 'RULE-RES-002',
|
|
358
|
+
severity: 'HIGH',
|
|
359
|
+
filename: 'multi_agent_orchestrator.js',
|
|
360
|
+
line: 1,
|
|
361
|
+
column: 1,
|
|
362
|
+
snippet: `URI: ${uri}`,
|
|
363
|
+
message: `Falha ao gerar recurso dinâmico '${uri}': ${err.message}`,
|
|
364
|
+
remediation: 'Verificar status do barramento de eventos ou imports no orquestrador multi-agente.'
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return createSarifReport({
|
|
371
|
+
toolName: 'agent-master-resources-registry',
|
|
372
|
+
toolVersion: '5.1.0',
|
|
373
|
+
findings,
|
|
374
|
+
properties: {
|
|
375
|
+
totalResources: Object.keys(allDefs).length,
|
|
376
|
+
brokenResources: findings.length
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static auditToSarif() {
|
|
382
|
+
const defaultInstance = new ResourcesRegistry(ROOT_DIR);
|
|
383
|
+
return defaultInstance.auditToSarif();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Gera relatório executivo em Markdown com status de cada recurso
|
|
388
|
+
*/
|
|
389
|
+
formatReport() {
|
|
390
|
+
const allDefs = { ...RESOURCE_DEFINITIONS, ...Object.fromEntries(this.customRegistry) };
|
|
391
|
+
const lines = [
|
|
392
|
+
'# Relatório Executivo: Recursos MCP & Documentação Viva',
|
|
393
|
+
'',
|
|
394
|
+
`| URI | Nome | Tipo MIME | Origem | Status |`,
|
|
395
|
+
`|---|---|---|---|---|`
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
for (const [uri, def] of Object.entries(allDefs)) {
|
|
399
|
+
let status = 'ONLINE';
|
|
400
|
+
let origem = def.relPath ? `docs (${def.relPath})` : 'Barramento Dinâmico';
|
|
401
|
+
|
|
402
|
+
if (def.relPath) {
|
|
403
|
+
const filePath = resolveDocFile(this.rootDir, def.relPath);
|
|
404
|
+
if (!fs.existsSync(filePath)) {
|
|
405
|
+
status = 'AUSENTE (404)';
|
|
406
|
+
}
|
|
407
|
+
} else if (typeof def.dynamicProvider === 'function') {
|
|
408
|
+
try {
|
|
409
|
+
def.dynamicProvider();
|
|
410
|
+
} catch {
|
|
411
|
+
status = 'FALHA DE EXECUÇÃO';
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
lines.push(`| \`${uri}\` | ${def.name} | \`${def.mimeType}\` | ${origem} | ${status} |`);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
lines.push('');
|
|
419
|
+
return lines.join('\n');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
static formatReport() {
|
|
423
|
+
const defaultInstance = new ResourcesRegistry(ROOT_DIR);
|
|
424
|
+
return defaultInstance.formatReport();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Funções stand-alone compatíveis com a API legada
|
|
429
|
+
function handleResourcesList(id) {
|
|
430
|
+
return ResourcesRegistry.handleResourcesList(id);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function handleResourceRead(id, params) {
|
|
434
|
+
return ResourcesRegistry.handleResourceRead(id, params);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function handleResourceReadAsync(id, params) {
|
|
438
|
+
return await ResourcesRegistry.handleResourceReadAsync(id, params);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
module.exports = {
|
|
442
|
+
ResourcesRegistry,
|
|
443
|
+
ROOT_DIR,
|
|
444
|
+
RESOURCES,
|
|
445
|
+
RESOURCE_DEFINITIONS,
|
|
446
|
+
resolveDocFile,
|
|
447
|
+
handleResourcesList,
|
|
448
|
+
handleResourceRead,
|
|
449
|
+
handleResourceReadAsync,
|
|
450
|
+
buildSuccessResponse,
|
|
451
|
+
buildErrorResponse,
|
|
452
|
+
buildResourceContentResponse
|
|
453
|
+
};
|