agent-master-devsecops 3.9.0 → 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.
Files changed (82) hide show
  1. package/README.md +205 -371
  2. package/agents/AGENT_DEVSECOPS.md +32 -417
  3. package/agents/AGENT_INFRA.md +31 -0
  4. package/agents/AGENT_ORCHESTRATOR.md +39 -264
  5. package/agents/AGENT_QA.md +58 -186
  6. package/agents/AGENT_SCRUM.md +23 -190
  7. package/agents/AGENT_SRE.md +22 -173
  8. package/agents/AGENT_UIUX.md +26 -162
  9. package/docs/ARCHITECTURE.md +152 -148
  10. package/docs/CALCULATIONS.md +17 -17
  11. package/docs/CHANGELOG.md +112 -49
  12. package/docs/ENGINEERING_RULES.md +56 -252
  13. package/docs/IDEAS.md +17 -17
  14. package/docs/LOCAL_BACKLOG.md +20 -0
  15. package/docs/STATE.md +111 -43
  16. package/docs/playbooks/PLAYBOOK_CIRCUIT_BREAKER_LLM.md +58 -58
  17. package/docs/playbooks/PLAYBOOK_OPENTELEMETRY_TRACING.md +58 -58
  18. package/package.json +59 -47
  19. package/scripts/auditors/a11y_auditor.js +462 -0
  20. package/scripts/auditors/code_quality_auditor.js +444 -0
  21. package/scripts/auditors/contract_test_validator.js +396 -0
  22. package/scripts/auditors/eval_harness.js +213 -0
  23. package/scripts/auditors/git_hygiene_linter.js +391 -0
  24. package/scripts/auditors/pr_reviewer.js +627 -0
  25. package/scripts/auditors/sast_scanner.js +442 -0
  26. package/scripts/auditors/sca_dependency_auditor.js +673 -0
  27. package/scripts/{bootstrap_cli.js → bin/bootstrap_cli.js} +597 -468
  28. package/scripts/bin/domain_idea_miner.js +658 -0
  29. package/scripts/bin/smart_onboarding.js +905 -0
  30. package/scripts/{web_inspector.js → bin/web_inspector.js} +578 -355
  31. package/scripts/core/architecture_advisor.js +378 -0
  32. package/scripts/core/ast_skeletonizer.js +413 -0
  33. package/scripts/core/autonomous_remediation_engine.js +305 -0
  34. package/scripts/{circuit_breaker.js → core/circuit_breaker.js} +546 -330
  35. package/scripts/core/context_compressor.js +237 -0
  36. package/scripts/core/fast_feature_scaffold.js +840 -0
  37. package/scripts/core/hot_state_cache.js +238 -0
  38. package/scripts/core/knowledge_gateway.js +888 -0
  39. package/scripts/{magic_prompt_generator.js → core/magic_prompt_generator.js} +250 -205
  40. package/scripts/{multi_agent_orchestrator.js → core/multi_agent_orchestrator.js} +421 -258
  41. package/scripts/{otel_tracer.js → core/otel_tracer.js} +335 -228
  42. package/scripts/{perf_benchmark.js → core/perf_benchmark.js} +212 -153
  43. package/scripts/core/sarif_engine.js +299 -0
  44. package/scripts/{sre_remediation_engine.js → core/sre_remediation_engine.js} +236 -174
  45. package/scripts/{universal_packager.js → core/universal_packager.js} +357 -313
  46. package/scripts/integrations/atlassian_client.js +600 -0
  47. package/scripts/integrations/atlassian_sync_action.js +576 -0
  48. package/scripts/integrations/confluence_sync.js +684 -0
  49. package/scripts/integrations/credentials_guard.js +500 -0
  50. package/scripts/integrations/jira_manager.js +722 -0
  51. package/scripts/mcp/handlers/atlassian_handlers.js +300 -0
  52. package/scripts/mcp/handlers/core_handlers.js +419 -0
  53. package/scripts/mcp/handlers/qa_handlers.js +502 -0
  54. package/scripts/mcp/handlers/rules_handlers.js +379 -0
  55. package/scripts/mcp/handlers/scaffold_handlers.js +334 -0
  56. package/scripts/mcp/handlers/sre_handlers.js +443 -0
  57. package/scripts/mcp/resources_registry.js +453 -0
  58. package/scripts/mcp/server.js +408 -0
  59. package/scripts/mcp/tool_handlers.js +444 -0
  60. package/scripts/mcp/tools_registry.js +1123 -0
  61. package/scripts/mcp_server.js +236 -1884
  62. package/.cursorignore +0 -23
  63. package/agents/compact/AGENT_ORCHESTRATOR_COMPACTO.md +0 -53
  64. package/scripts/a11y_auditor.js +0 -187
  65. package/scripts/ast_skeletonizer.js +0 -220
  66. package/scripts/atlassian_client.js +0 -238
  67. package/scripts/atlassian_sync_action.js +0 -269
  68. package/scripts/code_quality_auditor.js +0 -142
  69. package/scripts/confluence_sync.js +0 -337
  70. package/scripts/context_compressor.js +0 -139
  71. package/scripts/contract_test_validator.js +0 -166
  72. package/scripts/credentials_guard.js +0 -216
  73. package/scripts/domain_idea_miner.js +0 -364
  74. package/scripts/eval_harness.js +0 -100
  75. package/scripts/fast_feature_scaffold.js +0 -338
  76. package/scripts/git_hygiene_linter.js +0 -186
  77. package/scripts/hot_state_cache.js +0 -95
  78. package/scripts/jira_manager.js +0 -408
  79. package/scripts/pr_reviewer.js +0 -373
  80. package/scripts/sast_scanner.js +0 -180
  81. package/scripts/sca_dependency_auditor.js +0 -167
  82. package/scripts/smart_onboarding.js +0 -610
@@ -1,228 +1,335 @@
1
- #!/usr/bin/env node
2
- /**
3
- * scripts/otel_tracer.js
4
- *
5
- * Tracer Distribuído OpenTelemetry Nativo (AGDEV-24 / I-8).
6
- * Suporte a W3C TraceContext (traceparent), hierarquia de spans (parent-child),
7
- * exportação OTLP JSON e renderização de flamegraphs para playbooks de SRE.
8
- */
9
-
10
- const crypto = require('crypto');
11
-
12
- function generateTraceId() {
13
- return crypto.randomBytes(16).toString('hex');
14
- }
15
-
16
- function generateSpanId() {
17
- return crypto.randomBytes(8).toString('hex');
18
- }
19
-
20
- function formatTraceparent(traceId, spanId, sampled = true) {
21
- const flags = sampled ? '01' : '00';
22
- return `00-${traceId}-${spanId}-${flags}`;
23
- }
24
-
25
- function parseTraceparent(traceparent) {
26
- if (!traceparent || typeof traceparent !== 'string') return null;
27
- const parts = traceparent.split('-');
28
- if (parts.length !== 4) return null;
29
- return {
30
- version: parts[0],
31
- traceId: parts[1],
32
- spanId: parts[2],
33
- flags: parts[3],
34
- sampled: parts[3] === '01'
35
- };
36
- }
37
-
38
- class Span {
39
- constructor(name, tracer, options = {}) {
40
- this.name = name;
41
- this.tracer = tracer;
42
- this.traceId = options.traceId || tracer.traceId;
43
- this.spanId = generateSpanId();
44
- this.parentSpanId = options.parentSpanId || null;
45
- this.startTime = options.startTime || Date.now();
46
- this.endTime = null;
47
- this.durationMs = 0;
48
- this.attributes = Object.assign({}, options.attributes || {});
49
- this.events = [];
50
- this.status = { code: 'UNSET' };
51
- }
52
-
53
- setAttribute(key, value) {
54
- this.attributes[key] = value;
55
- return this;
56
- }
57
-
58
- addEvent(name, attributes = {}) {
59
- this.events.push({
60
- name,
61
- time: Date.now(),
62
- attributes
63
- });
64
- return this;
65
- }
66
-
67
- setStatus(code, message = '') {
68
- this.status = { code, message };
69
- return this;
70
- }
71
-
72
- end(endTime = Date.now()) {
73
- this.endTime = endTime;
74
- this.durationMs = Math.max(0, this.endTime - this.startTime);
75
- this.tracer._recordSpan(this);
76
- return this;
77
- }
78
- }
79
-
80
- class Tracer {
81
- constructor(serviceName, options = {}) {
82
- this.serviceName = serviceName;
83
- this.traceId = options.traceId || generateTraceId();
84
- this.spans = [];
85
- }
86
-
87
- startSpan(name, options = {}) {
88
- return new Span(name, this, options);
89
- }
90
-
91
- _recordSpan(span) {
92
- this.spans.push(span);
93
- }
94
-
95
- getTraceContext(activeSpan = null) {
96
- const spanId = activeSpan ? activeSpan.spanId : (this.spans[0] ? this.spans[0].spanId : generateSpanId());
97
- return {
98
- traceId: this.traceId,
99
- spanId,
100
- traceparent: formatTraceparent(this.traceId, spanId)
101
- };
102
- }
103
-
104
- analyzeBottlenecks(thresholdMs = 50) {
105
- const bottlenecks = [];
106
- const totalDuration = this.spans.reduce((max, s) => Math.max(max, (s.endTime || s.startTime) - this.spans[0].startTime), 0) || 1;
107
-
108
- for (const span of this.spans) {
109
- const percentage = Math.round((span.durationMs / totalDuration) * 100);
110
- if (span.durationMs >= thresholdMs || percentage >= 40) {
111
- bottlenecks.push({
112
- name: span.name,
113
- durationMs: span.durationMs,
114
- percentageTotal: percentage,
115
- severity: percentage >= 70 ? 'CRÍTICA' : (percentage >= 40 ? 'ALTA' : 'MÉDIA'),
116
- spanId: span.spanId
117
- });
118
- }
119
- }
120
-
121
- return bottlenecks;
122
- }
123
-
124
- renderFlamegraphAscii() {
125
- if (this.spans.length === 0) return 'Trace vazio.';
126
-
127
- const sorted = [...this.spans].sort((a, b) => a.startTime - b.startTime);
128
- const traceStart = sorted[0].startTime;
129
- const traceEnd = Math.max(...sorted.map(s => s.endTime || s.startTime));
130
- const totalDuration = Math.max(1, traceEnd - traceStart);
131
-
132
- let ascii = `=== FLAMEGRAPH DISTRIBUÍDO [Trace: ${this.traceId}] (${totalDuration}ms) ===\n`;
133
-
134
- sorted.forEach((span, index) => {
135
- const offsetMs = span.startTime - traceStart;
136
- const offsetChars = Math.floor((offsetMs / totalDuration) * 30);
137
- const barLength = Math.max(1, Math.floor((span.durationMs / totalDuration) * 40));
138
- const indent = ' '.repeat(offsetChars);
139
- const bar = '█'.repeat(barLength);
140
-
141
- ascii += `[${String(index + 1).padStart(2, '0')}] ${indent}${bar} ${span.name} (${span.durationMs}ms)\n`;
142
- });
143
-
144
- return ascii;
145
- }
146
-
147
- exportOtlpJson() {
148
- return {
149
- resourceSpans: [
150
- {
151
- resource: {
152
- attributes: [
153
- { key: 'service.name', value: { stringValue: this.serviceName } }
154
- ]
155
- },
156
- scopeSpans: [
157
- {
158
- scope: { name: 'agent-master-devsecops-tracer', version: '3.2.0' },
159
- spans: this.spans.map(s => ({
160
- traceId: s.traceId,
161
- spanId: s.spanId,
162
- parentSpanId: s.parentSpanId,
163
- name: s.name,
164
- startTimeUnixNano: String(s.startTime * 1000000),
165
- endTimeUnixNano: String((s.endTime || s.startTime) * 1000000),
166
- attributes: Object.entries(s.attributes).map(([k, v]) => ({
167
- key: k,
168
- value: { stringValue: String(v) }
169
- })),
170
- status: s.status
171
- }))
172
- }
173
- ]
174
- }
175
- ]
176
- };
177
- }
178
- }
179
-
180
- function simulateMultiAgentTrace(serviceName = 'agent-pipeline') {
181
- const tracer = new Tracer(serviceName);
182
-
183
- // 1. Root span: Requisição do Usuário
184
- const root = tracer.startSpan('user_goal_execution').setAttribute('agent.role', 'Orchestrator');
185
-
186
- // 2. Sub-span: Arquiteto planeja
187
- const planSpan = tracer.startSpan('architect_plan', { parentSpanId: root.spanId })
188
- .setAttribute('agent.role', 'Arquiteto')
189
- .setAttribute('model', 'Claude 3.5 Sonnet');
190
- // Simula 25ms
191
- planSpan.end(planSpan.startTime + 25);
192
-
193
- // 3. Sub-span: DevSecOps implementa
194
- const devSpan = tracer.startSpan('devsecops_implementation', { parentSpanId: root.spanId })
195
- .setAttribute('agent.role', 'DevSecOps Lead');
196
- devSpan.end(devSpan.startTime + 60);
197
-
198
- // 4. Sub-span: QA audita
199
- const revSpan = tracer.startSpan('qa_audit', { parentSpanId: root.spanId })
200
- .setAttribute('agent.role', 'QA Independente');
201
- revSpan.end(revSpan.startTime + 15);
202
-
203
- // 5. Finaliza root span
204
- root.end(root.startTime + 105);
205
-
206
- return tracer;
207
- }
208
-
209
- async function runCli() {
210
- const tracer = simulateMultiAgentTrace();
211
- console.log(tracer.renderFlamegraphAscii());
212
- console.log('\nGargalos Identificados (Threshold 30ms):');
213
- console.log(JSON.stringify(tracer.analyzeBottlenecks(30), null, 2));
214
- }
215
-
216
- if (require.main === module) {
217
- runCli().catch(console.error);
218
- }
219
-
220
- module.exports = {
221
- generateTraceId,
222
- generateSpanId,
223
- formatTraceparent,
224
- parseTraceparent,
225
- Span,
226
- Tracer,
227
- simulateMultiAgentTrace
228
- };
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/otel_tracer.js
4
+ *
5
+ * Tracer Distribuído OpenTelemetry Nativo (AGDEV-24 / I-8).
6
+ * Suporte a W3C TraceContext (traceparent), hierarquia de spans (parent-child),
7
+ * exportação OTLP JSON e renderização de flamegraphs para playbooks de SRE.
8
+ */
9
+
10
+ const crypto = require('crypto');
11
+ const { version: PKG_VERSION } = require('../../package.json');
12
+ const { createSarifReport } = require('./sarif_engine.js');
13
+
14
+ function getOfficialOtelApi() {
15
+ try {
16
+ return require('@opentelemetry/api');
17
+ } catch (_) {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ function isOfficialOtelApiAvailable() {
23
+ return getOfficialOtelApi() !== null;
24
+ }
25
+
26
+ function generateTraceId() {
27
+ return crypto.randomBytes(16).toString('hex');
28
+ }
29
+
30
+ function generateSpanId() {
31
+ return crypto.randomBytes(8).toString('hex');
32
+ }
33
+
34
+ function formatTraceparent(traceId, spanId, sampled = true) {
35
+ const flags = sampled ? '01' : '00';
36
+ return `00-${traceId}-${spanId}-${flags}`;
37
+ }
38
+
39
+ function parseTraceparent(traceparent) {
40
+ if (!traceparent || typeof traceparent !== 'string') return null;
41
+ const parts = traceparent.split('-');
42
+ if (parts.length !== 4) return null;
43
+ return {
44
+ version: parts[0],
45
+ traceId: parts[1],
46
+ spanId: parts[2],
47
+ flags: parts[3],
48
+ sampled: parts[3] === '01'
49
+ };
50
+ }
51
+
52
+ class Span {
53
+ constructor(name, tracer, options = {}) {
54
+ this.name = name;
55
+ this.tracer = tracer;
56
+ this.traceId = options.traceId || tracer.traceId;
57
+ this.spanId = generateSpanId();
58
+ this.parentSpanId = options.parentSpanId || null;
59
+ this.startTime = options.startTime || Date.now();
60
+ this.endTime = null;
61
+ this.durationMs = 0;
62
+ this.attributes = Object.assign({}, options.attributes || {});
63
+ this.events = [];
64
+ this.status = { code: 'UNSET' };
65
+ }
66
+
67
+ setAttribute(key, value) {
68
+ this.attributes[key] = value;
69
+ return this;
70
+ }
71
+
72
+ addEvent(name, attributes = {}) {
73
+ this.events.push({
74
+ name,
75
+ time: Date.now(),
76
+ attributes
77
+ });
78
+ return this;
79
+ }
80
+
81
+ setStatus(code, message = '') {
82
+ this.status = { code, message };
83
+ return this;
84
+ }
85
+
86
+ end(endTime = Date.now()) {
87
+ this.endTime = endTime;
88
+ this.durationMs = Math.max(0, this.endTime - this.startTime);
89
+ this.tracer._recordSpan(this);
90
+ return this;
91
+ }
92
+ }
93
+
94
+ class Tracer {
95
+ constructor(serviceName, options = {}) {
96
+ this.serviceName = serviceName;
97
+ this.traceId = options.traceId || generateTraceId();
98
+ this.spans = [];
99
+ }
100
+
101
+ startSpan(name, options = {}) {
102
+ return new Span(name, this, options);
103
+ }
104
+
105
+ _recordSpan(span) {
106
+ this.spans.push(span);
107
+ }
108
+
109
+ getTraceContext(activeSpan = null) {
110
+ const spanId = activeSpan ? activeSpan.spanId : (this.spans[0] ? this.spans[0].spanId : generateSpanId());
111
+ return {
112
+ traceId: this.traceId,
113
+ spanId,
114
+ traceparent: formatTraceparent(this.traceId, spanId)
115
+ };
116
+ }
117
+
118
+ analyzeBottlenecks(thresholdMs = 50) {
119
+ const bottlenecks = [];
120
+ const totalDuration = this.spans.reduce((max, s) => Math.max(max, (s.endTime || s.startTime) - this.spans[0].startTime), 0) || 1;
121
+
122
+ for (const span of this.spans) {
123
+ const percentage = Math.round((span.durationMs / totalDuration) * 100);
124
+ if (span.durationMs >= thresholdMs || percentage >= 40) {
125
+ bottlenecks.push({
126
+ name: span.name,
127
+ durationMs: span.durationMs,
128
+ percentageTotal: percentage,
129
+ severity: percentage >= 70 ? 'CRÍTICA' : (percentage >= 40 ? 'ALTA' : 'MÉDIA'),
130
+ spanId: span.spanId
131
+ });
132
+ }
133
+ }
134
+
135
+ return bottlenecks;
136
+ }
137
+
138
+ renderFlamegraphAscii() {
139
+ if (this.spans.length === 0) return 'Trace vazio.';
140
+
141
+ const sorted = [...this.spans].sort((a, b) => a.startTime - b.startTime);
142
+ const traceStart = sorted[0].startTime;
143
+ const traceEnd = Math.max(...sorted.map(s => s.endTime || s.startTime));
144
+ const totalDuration = Math.max(1, traceEnd - traceStart);
145
+
146
+ let ascii = `=== FLAMEGRAPH DISTRIBUÍDO [Trace: ${this.traceId}] (${totalDuration}ms) ===\n`;
147
+
148
+ sorted.forEach((span, index) => {
149
+ const offsetMs = span.startTime - traceStart;
150
+ const offsetChars = Math.floor((offsetMs / totalDuration) * 30);
151
+ const barLength = Math.max(1, Math.floor((span.durationMs / totalDuration) * 40));
152
+ const indent = ' '.repeat(offsetChars);
153
+ const bar = '█'.repeat(barLength);
154
+
155
+ ascii += `[${String(index + 1).padStart(2, '0')}] ${indent}${bar} ${span.name} (${span.durationMs}ms)\n`;
156
+ });
157
+
158
+ return ascii;
159
+ }
160
+
161
+ exportOtlpJson() {
162
+ return {
163
+ resourceSpans: [
164
+ {
165
+ resource: {
166
+ attributes: [
167
+ { key: 'service.name', value: { stringValue: this.serviceName } }
168
+ ]
169
+ },
170
+ scopeSpans: [
171
+ {
172
+ scope: { name: 'agent-master-devsecops-tracer', version: PKG_VERSION },
173
+ spans: this.spans.map(s => ({
174
+ traceId: s.traceId,
175
+ spanId: s.spanId,
176
+ parentSpanId: s.parentSpanId,
177
+ name: s.name,
178
+ startTimeUnixNano: String(s.startTime * 1000000),
179
+ endTimeUnixNano: String((s.endTime || s.startTime) * 1000000),
180
+ attributes: Object.entries(s.attributes).map(([k, v]) => ({
181
+ key: k,
182
+ value: { stringValue: String(v) }
183
+ })),
184
+ status: s.status
185
+ }))
186
+ }
187
+ ]
188
+ }
189
+ ]
190
+ };
191
+ }
192
+
193
+ async sendToOtlpEndpoint(endpointUrl, options = {}) {
194
+ const payload = JSON.stringify(this.exportOtlpJson());
195
+ const parsedUrl = new URL(endpointUrl);
196
+ const transport = parsedUrl.protocol === 'https:' ? require('node:https') : require('node:http');
197
+ const timeoutMs = options.timeoutMs || 5000;
198
+ const customHeaders = options.headers || {};
199
+
200
+ return new Promise((resolve, reject) => {
201
+ const req = transport.request(parsedUrl, {
202
+ method: 'POST',
203
+ headers: Object.assign({
204
+ 'Content-Type': 'application/json',
205
+ 'Content-Length': Buffer.byteLength(payload),
206
+ 'User-Agent': `agent-master-otel-tracer/${PKG_VERSION}`
207
+ }, customHeaders),
208
+ timeout: timeoutMs
209
+ }, (res) => {
210
+ let responseBody = '';
211
+ res.setEncoding('utf8');
212
+ res.on('data', chunk => { responseBody += chunk; });
213
+ res.on('end', () => {
214
+ const success = res.statusCode >= 200 && res.statusCode < 300;
215
+ resolve({
216
+ success,
217
+ statusCode: res.statusCode,
218
+ statusMessage: res.statusMessage,
219
+ body: responseBody
220
+ });
221
+ });
222
+ });
223
+
224
+ req.on('timeout', () => {
225
+ req.destroy();
226
+ reject(new Error(`Timeout ao exportar spans para OTLP endpoint: ${endpointUrl} (${timeoutMs}ms)`));
227
+ });
228
+
229
+ req.on('error', (err) => {
230
+ reject(new Error(`Falha de conexão ao exportar OTLP para ${endpointUrl}: ${err.message}`));
231
+ });
232
+
233
+ req.write(payload);
234
+ req.end();
235
+ });
236
+ }
237
+
238
+ auditToSarif(bottleneckThresholdMs = 50) {
239
+ const bottlenecks = this.analyzeBottlenecks(bottleneckThresholdMs);
240
+ const findings = [];
241
+
242
+ for (const b of bottlenecks) {
243
+ findings.push({
244
+ ruleId: 'RULE-TRACE-001',
245
+ name: 'DistributedSpanBottleneck',
246
+ severity: 'WARNING',
247
+ message: `Span [${b.name}] consumiu ${b.durationMs}ms (${b.pctOfTotalTrace}% do trace total), excedendo o limiar de ${bottleneckThresholdMs}ms.`,
248
+ remediation: 'Otimize chamadas concorrentes ou adicione cache em operações I/O pesadas.'
249
+ });
250
+ }
251
+
252
+ return createSarifReport({
253
+ toolName: 'agent-master-otel-tracer',
254
+ rules: [
255
+ {
256
+ id: 'RULE-TRACE-001',
257
+ name: 'DistributedSpanBottleneck',
258
+ description: 'Identifica spans distribuídos que excedem o tempo de resposta aceitável',
259
+ severity: 'MEDIUM',
260
+ cwe: 'CWE-400'
261
+ }
262
+ ],
263
+ findings,
264
+ properties: {
265
+ serviceName: this.serviceName,
266
+ totalSpans: this.spans.length,
267
+ bottlenecksCount: bottlenecks.length
268
+ }
269
+ });
270
+ }
271
+
272
+ formatReport() {
273
+ return [
274
+ `### Relatório de Rastreabilidade Distribuída (OpenTelemetry)`,
275
+ `- **Serviço:** \`${this.serviceName}\``,
276
+ `- **Spans Registrados:** ${this.spans.length}`,
277
+ '```text',
278
+ this.renderFlamegraphAscii(),
279
+ '```'
280
+ ].join('\n');
281
+ }
282
+ }
283
+
284
+
285
+ function simulateMultiAgentTrace(serviceName = 'agent-pipeline') {
286
+ const tracer = new Tracer(serviceName);
287
+
288
+ // 1. Root span: Requisição do Usuário
289
+ const root = tracer.startSpan('user_goal_execution').setAttribute('agent.role', 'Orchestrator');
290
+
291
+ // 2. Sub-span: Arquiteto planeja
292
+ const planSpan = tracer.startSpan('architect_plan', { parentSpanId: root.spanId })
293
+ .setAttribute('agent.role', 'Arquiteto')
294
+ .setAttribute('model', 'Claude 3.5 Sonnet');
295
+ // Simula 25ms
296
+ planSpan.end(planSpan.startTime + 25);
297
+
298
+ // 3. Sub-span: DevSecOps implementa
299
+ const devSpan = tracer.startSpan('devsecops_implementation', { parentSpanId: root.spanId })
300
+ .setAttribute('agent.role', 'DevSecOps Lead');
301
+ devSpan.end(devSpan.startTime + 60);
302
+
303
+ // 4. Sub-span: QA audita
304
+ const revSpan = tracer.startSpan('qa_audit', { parentSpanId: root.spanId })
305
+ .setAttribute('agent.role', 'QA Independente');
306
+ revSpan.end(revSpan.startTime + 15);
307
+
308
+ // 5. Finaliza root span
309
+ root.end(root.startTime + 105);
310
+
311
+ return tracer;
312
+ }
313
+
314
+ async function runCli() {
315
+ const tracer = simulateMultiAgentTrace();
316
+ console.log(tracer.renderFlamegraphAscii());
317
+ console.log('\nGargalos Identificados (Threshold 30ms):');
318
+ console.log(JSON.stringify(tracer.analyzeBottlenecks(30), null, 2));
319
+ }
320
+
321
+ if (require.main === module) {
322
+ runCli().catch(console.error);
323
+ }
324
+
325
+ module.exports = {
326
+ generateTraceId,
327
+ generateSpanId,
328
+ formatTraceparent,
329
+ parseTraceparent,
330
+ Span,
331
+ Tracer,
332
+ simulateMultiAgentTrace,
333
+ getOfficialOtelApi,
334
+ isOfficialOtelApiAvailable
335
+ };