@arcadialdev/arcality 2.6.6 โ†’ 3.0.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.
@@ -1,122 +1,104 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
4
  };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
- var ArcalityReporter_exports = {};
29
- __export(ArcalityReporter_exports, {
30
- default: () => ArcalityReporter_default
31
- });
32
- module.exports = __toCommonJS(ArcalityReporter_exports);
33
- var import_fs = __toESM(require("fs"));
34
- var import_path = __toESM(require("path"));
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
35
8
  class ArcalityReporter {
36
- outputDir;
37
- results = [];
38
- totalDuration = 0;
39
- startTime = /* @__PURE__ */ new Date();
40
- constructor(options = {}) {
41
- this.outputDir = options.outputDir || "arcality-report";
42
- }
43
- onBegin(config, suite) {
44
- if (import_fs.default.existsSync(this.outputDir)) {
45
- try {
46
- import_fs.default.rmSync(this.outputDir, { recursive: true, force: true });
47
- console.log(`\u{1F9F9} Cleaned old report data at: ${this.outputDir}`);
48
- } catch (err) {
49
- console.warn(`\u26A0\uFE0F Could not fully clean report dir: ${err.message}`);
50
- }
9
+ constructor(options = {}) {
10
+ this.results = [];
11
+ this.totalDuration = 0;
12
+ this.startTime = new Date();
13
+ this.outputDir = options.outputDir || 'arcality-report';
51
14
  }
52
- if (!import_fs.default.existsSync(this.outputDir)) {
53
- import_fs.default.mkdirSync(this.outputDir, { recursive: true });
15
+ onBegin(config, suite) {
16
+ // Clean output directory to avoid stale reports/attachments
17
+ if (fs_1.default.existsSync(this.outputDir)) {
18
+ try {
19
+ fs_1.default.rmSync(this.outputDir, { recursive: true, force: true });
20
+ console.log(`๐Ÿงน Cleaned old report data at: ${this.outputDir}`);
21
+ }
22
+ catch (err) {
23
+ console.warn(`โš ๏ธ Could not fully clean report dir: ${err.message}`);
24
+ }
25
+ }
26
+ if (!fs_1.default.existsSync(this.outputDir)) {
27
+ fs_1.default.mkdirSync(this.outputDir, { recursive: true });
28
+ }
29
+ this.startTime = new Date();
30
+ console.log(`๐Ÿš€ Arcality Mission started at ${this.startTime.toLocaleTimeString()}`);
54
31
  }
55
- this.startTime = /* @__PURE__ */ new Date();
56
- console.log(`\u{1F680} Arcality Mission started at ${this.startTime.toLocaleTimeString()}`);
57
- }
58
- onTestEnd(test, result) {
59
- const stepsHtml = result.steps.map((step) => this.renderStep(step, 0)).join("");
60
- const processedAttachments = result.attachments.map((att) => {
61
- let extension = ".png";
62
- if (att.contentType === "application/json")
63
- extension = ".json";
64
- else if (att.contentType === "text/plain")
65
- extension = ".txt";
66
- else if (att.contentType === "text/yaml")
67
- extension = ".yaml";
68
- const fileName = att.path ? import_path.default.basename(att.path) : `${att.name || "attachment"}-${Date.now()}${extension}`;
69
- const attachmentsDir = import_path.default.join(this.outputDir, "attachments");
70
- const destPath = import_path.default.join(attachmentsDir, fileName);
71
- if (!import_fs.default.existsSync(attachmentsDir)) {
72
- import_fs.default.mkdirSync(attachmentsDir, { recursive: true });
73
- }
74
- try {
75
- if (att.path && import_fs.default.existsSync(att.path)) {
76
- import_fs.default.copyFileSync(att.path, destPath);
77
- } else if (att.body) {
78
- import_fs.default.writeFileSync(destPath, att.body);
79
- }
80
- return { ...att, path: `attachments/${fileName}` };
81
- } catch (e) {
82
- console.error(`Failed to process attachment ${att.name}:`, e);
83
- return att;
84
- }
85
- });
86
- if (result.status === "failed" || result.error) {
87
- console.log(`
88
- \u274C [TEST ENGINE FAILURE] ${test.title} failed:`);
89
- console.log(`${result.error?.message || result.error?.stack || "Unknown error"}
90
- `);
91
- if (result.error?.stack) {
92
- console.log(result.error.stack);
93
- }
32
+ onTestEnd(test, result) {
33
+ // Collect steps with recursion
34
+ const stepsHtml = result.steps.map(step => this.renderStep(step, 0)).join('');
35
+ // Handle attachments: copy to report dir
36
+ const processedAttachments = result.attachments.map(att => {
37
+ let extension = '.png';
38
+ if (att.contentType === 'application/json')
39
+ extension = '.json';
40
+ else if (att.contentType === 'text/plain')
41
+ extension = '.txt';
42
+ else if (att.contentType === 'text/yaml')
43
+ extension = '.yaml';
44
+ const fileName = att.path ? path_1.default.basename(att.path) : `${att.name || 'attachment'}-${Date.now()}${extension}`;
45
+ const attachmentsDir = path_1.default.join(this.outputDir, 'attachments');
46
+ const destPath = path_1.default.join(attachmentsDir, fileName);
47
+ if (!fs_1.default.existsSync(attachmentsDir)) {
48
+ fs_1.default.mkdirSync(attachmentsDir, { recursive: true });
49
+ }
50
+ try {
51
+ if (att.path && fs_1.default.existsSync(att.path)) {
52
+ // Si ya existe el archivo fรญsico, lo copiamos
53
+ fs_1.default.copyFileSync(att.path, destPath);
54
+ }
55
+ else if (att.body) {
56
+ // Si viene como Buffer (evidencia del agente), lo guardamos
57
+ fs_1.default.writeFileSync(destPath, att.body);
58
+ }
59
+ return { ...att, path: `attachments/${fileName}` };
60
+ }
61
+ catch (e) {
62
+ console.error(`Failed to process attachment ${att.name}:`, e);
63
+ return att;
64
+ }
65
+ });
66
+ if (result.status === 'failed' || result.error) {
67
+ const isAppBug = result.error?.message?.includes('APPLICATION BUG');
68
+ const prefix = isAppBug ? '๐Ÿž [APPLICATION BUG FOUND]' : 'โŒ [TEST ENGINE FAILURE]';
69
+ console.log(`\n${prefix} ${test.title} failed:`);
70
+ console.log(`${result.error?.message || result.error?.stack || 'Unknown error'}\n`);
71
+ if (result.error?.stack && !isAppBug) {
72
+ console.log(result.error.stack);
73
+ }
74
+ }
75
+ this.results.push({ test, result, stepsHtml, attachments: processedAttachments });
94
76
  }
95
- this.results.push({ test, result, stepsHtml, attachments: processedAttachments });
96
- }
97
- async onEnd(result) {
98
- this.totalDuration = result.duration;
99
- const htmlContent = this.generateHtml();
100
- const reportPath = import_path.default.join(this.outputDir, "index.html");
101
- import_fs.default.writeFileSync(reportPath, htmlContent);
102
- console.log(`\u2728 Arcality Mission Report generated at: ${reportPath}`);
103
- }
104
- renderStep(step, depth) {
105
- if (step.category === "hook" || step.category === "fixture")
106
- return "";
107
- const padding = depth * 16;
108
- const statusClass = step.error ? "step-error" : "step-passed";
109
- const icon = step.error ? "\u2715" : "\u2713";
110
- const duration = step.duration >= 0 ? `<span class="step-duration">${step.duration}ms</span>` : "";
111
- let title = this.escapeHtml(step.title);
112
- title = title.replace(/^(click|fill|navigate|wait|expect|goto|press)/i, '<span class="step-action">$1</span>');
113
- let children = "";
114
- if (step.steps && step.steps.length > 0) {
115
- children = `<div class="step-children">${step.steps.map((s) => this.renderStep(s, depth + 1)).join("")}</div>`;
77
+ async onEnd(result) {
78
+ this.totalDuration = result.duration;
79
+ const htmlContent = this.generateHtml();
80
+ const reportPath = path_1.default.join(this.outputDir, 'index.html');
81
+ fs_1.default.writeFileSync(reportPath, htmlContent);
82
+ console.log(`โœจ Arcality Mission Report generated at: ${reportPath}`);
116
83
  }
117
- const isExpandable = step.steps && step.steps.length > 0;
118
- const expandableAttr = isExpandable ? 'data-expandable="true"' : "";
119
- return `
84
+ renderStep(step, depth) {
85
+ // Humanize: Hide internal Playwright hooks to only show Agent decisions
86
+ if (step.category === 'hook' || step.category === 'fixture')
87
+ return '';
88
+ const padding = depth * 16;
89
+ const statusClass = step.error ? 'step-error' : 'step-passed';
90
+ const icon = step.error ? 'โœ•' : 'โœ“';
91
+ const duration = step.duration >= 0 ? `<span class="step-duration">${step.duration}ms</span>` : '';
92
+ let title = this.escapeHtml(step.title);
93
+ // Highlight common playwright actions
94
+ title = title.replace(/^(click|fill|navigate|wait|expect|goto|press)/i, '<span class="step-action">$1</span>');
95
+ let children = '';
96
+ if (step.steps && step.steps.length > 0) {
97
+ children = `<div class="step-children">${step.steps.map(s => this.renderStep(s, depth + 1)).join('')}</div>`;
98
+ }
99
+ const isExpandable = step.steps && step.steps.length > 0;
100
+ const expandableAttr = isExpandable ? 'data-expandable="true"' : '';
101
+ return `
120
102
  <div class="step-wrapper ${statusClass}" style="margin-left: ${padding}px" ${expandableAttr}>
121
103
  <div class="step-header">
122
104
  <span class="step-icon">${icon}</span>
@@ -126,28 +108,29 @@ class ArcalityReporter {
126
108
  ${children}
127
109
  </div>
128
110
  `;
129
- }
130
- getEngineVersion() {
131
- try {
132
- const packageJsonPath = import_path.default.join(process.cwd(), "package.json");
133
- if (import_fs.default.existsSync(packageJsonPath)) {
134
- const pkg = JSON.parse(import_fs.default.readFileSync(packageJsonPath, "utf8"));
135
- return pkg.version || "2.2.0";
136
- }
137
- } catch (e) {
138
- console.error("Error reading package.json version:", e);
139
111
  }
140
- return "2.2.0";
141
- }
142
- generateHtml() {
143
- const stats = {
144
- total: this.results.length,
145
- passed: this.results.filter((r) => r.result.status === "passed").length,
146
- failed: this.results.filter((r) => r.result.status === "failed" || r.result.status === "timedOut").length,
147
- skipped: this.results.filter((r) => r.result.status === "skipped").length,
148
- flaky: this.results.filter((r) => r.result.status === "passed" && r.result.retry > 0).length
149
- };
150
- return `
112
+ getEngineVersion() {
113
+ try {
114
+ const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
115
+ if (fs_1.default.existsSync(packageJsonPath)) {
116
+ const pkg = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
117
+ return pkg.version || '2.2.0';
118
+ }
119
+ }
120
+ catch (e) {
121
+ console.error('Error reading package.json version:', e);
122
+ }
123
+ return '2.2.0';
124
+ }
125
+ generateHtml() {
126
+ const stats = {
127
+ total: this.results.length,
128
+ passed: this.results.filter(r => r.result.status === 'passed').length,
129
+ failed: this.results.filter(r => r.result.status === 'failed' || r.result.status === 'timedOut').length,
130
+ skipped: this.results.filter(r => r.result.status === 'skipped').length,
131
+ flaky: this.results.filter(r => r.result.status === 'passed' && r.result.retry > 0).length
132
+ };
133
+ return `
151
134
  <!DOCTYPE html>
152
135
  <html lang="en">
153
136
  <head>
@@ -290,7 +273,7 @@ class ArcalityReporter {
290
273
  gap: 12px;
291
274
  }
292
275
  .success-block::before {
293
- content: "\u2728";
276
+ content: "โœจ";
294
277
  font-size: 1.4rem;
295
278
  }
296
279
 
@@ -475,14 +458,14 @@ class ArcalityReporter {
475
458
  <div class="stat-card"><span class="stat-value val-passed">${stats.passed}</span><span class="stat-label">Successful</span></div>
476
459
  <div class="stat-card"><span class="stat-value val-failed">${stats.failed}</span><span class="stat-label">Fatal Errors</span></div>
477
460
  <div class="stat-card"><span class="stat-value val-flaky">${stats.flaky}</span><span class="stat-label">Flaky Tests</span></div>
478
- <div class="stat-card"><span class="stat-value val-total">${(this.totalDuration / 1e3).toFixed(2)}s</span><span class="stat-label">Total Duration</span></div>
461
+ <div class="stat-card"><span class="stat-value val-total">${(this.totalDuration / 1000).toFixed(2)}s</span><span class="stat-label">Total Duration</span></div>
479
462
  </div>
480
463
 
481
464
  <div class="test-list">
482
465
  ${this.results.map((r, i) => {
483
- const statusClass = `status-${r.result.status}`;
484
- const projectName = r.test.parent.project()?.name || "default";
485
- return `
466
+ const statusClass = `status-${r.result.status}`;
467
+ const projectName = r.test.parent.project()?.name || 'default';
468
+ return `
486
469
  <div class="test-entry ${statusClass}">
487
470
  <div class="test-header" onclick="toggleDetails('details-${i}')">
488
471
  <div class="test-info">
@@ -491,34 +474,34 @@ class ArcalityReporter {
491
474
  <div class="test-name">${this.escapeHtml(r.test.title)}</div>
492
475
  <div class="test-meta">
493
476
  <span class="tag tag-project">${projectName}</span>
494
- ${r.result.retry > 0 ? `<span class="tag tag-retry">Retry #${r.result.retry}</span>` : ""}
495
- <span>${(r.result.duration / 1e3).toFixed(2)}s</span>
477
+ ${r.result.retry > 0 ? `<span class="tag tag-retry">Retry #${r.result.retry}</span>` : ''}
478
+ <span>${(r.result.duration / 1000).toFixed(2)}s</span>
496
479
  </div>
497
480
  </div>
498
481
  </div>
499
482
  <div style="display:flex; gap: 10px; align-items: center;">
500
- <span style="opacity:0.5; font-size: 1.2rem">\u25BC</span>
483
+ <span style="opacity:0.5; font-size: 1.2rem">โ–ผ</span>
501
484
  </div>
502
485
  </div>
503
486
 
504
487
  <div class="test-details" id="details-${i}" style="display: none;">
505
- ${r.result.status === "passed" ? (() => {
506
- const successSummary = r.attachments.find((a) => a.name === "success_summary");
507
- const text = this.getAttachmentText(successSummary);
508
- return text ? `<div class="success-block">${this.escapeHtml(text)}</div>` : "";
509
- })() : ""}
488
+ ${r.result.status === 'passed' ? (() => {
489
+ const successSummary = r.attachments.find(a => a.name === 'success_summary');
490
+ const text = this.getAttachmentText(successSummary);
491
+ return text ? `<div class="success-block">${this.escapeHtml(text)}</div>` : '';
492
+ })() : ''}
510
493
 
511
494
  ${r.result.error ? `
512
495
  <div class="steps-section">
513
496
  <span class="section-title">Analysis of the Obstacle</span>
514
- <div class="error-block">${this.escapeHtml(r.result.error.message || "Unknown Failure")}</div>
497
+ <div class="error-block">${this.escapeHtml(r.result.error.message || 'Unknown Failure')}</div>
515
498
  </div>
516
- ` : ""}
499
+ ` : ''}
517
500
 
518
501
  ${this._renderSecuritySection(r.attachments, i)}
519
502
 
520
503
  <div class="steps-section">
521
- <span class="section-title">\u{1F9E0} Agent Cognitive Process</span>
504
+ <span class="section-title">๐Ÿง  Agent Cognitive Process</span>
522
505
  <div class="steps-container">
523
506
  ${r.stepsHtml || '<p style="opacity:0.5">No steps recorded.</p>'}
524
507
  </div>
@@ -528,36 +511,36 @@ class ArcalityReporter {
528
511
  <div class="steps-section">
529
512
  <span class="section-title">Visual Evidence</span>
530
513
  <div class="attachments-grid">
531
- ${r.attachments.map((att) => {
532
- if (att.contentType.startsWith("image/")) {
533
- return `
514
+ ${r.attachments.map(att => {
515
+ if (att.contentType.startsWith('image/')) {
516
+ return `
534
517
  <div class="attachment-item">
535
518
  <img src="${att.path}" alt="${att.name}" onclick="window.open('${att.path}')">
536
519
  <a href="${att.path}" target="_blank" class="att-label">${att.name}</a>
537
520
  </div>
538
521
  `;
539
- }
540
- if (att.contentType.startsWith("video/")) {
541
- return `
522
+ }
523
+ if (att.contentType.startsWith('video/')) {
524
+ return `
542
525
  <div class="attachment-item">
543
526
  <video controls src="${att.path}"></video>
544
527
  <a href="${att.path}" target="_blank" class="att-label">${att.name}</a>
545
528
  </div>
546
529
  `;
547
- }
548
- return "";
549
- }).join("")}
530
+ }
531
+ return '';
532
+ }).join('')}
550
533
  </div>
551
534
  </div>
552
- ` : ""}
535
+ ` : ''}
553
536
  </div>
554
537
  </div>
555
538
  `;
556
- }).join("")}
539
+ }).join('')}
557
540
  </div>
558
541
 
559
542
  <footer>
560
- ARCALITY ENGINE v${this.getEngineVersion()} \u2022 SYSTEM TIME [${(/* @__PURE__ */ new Date()).toISOString()}] \u2022 GENERATED FOR ARCADIAL
543
+ ARCALITY ENGINE v${this.getEngineVersion()} โ€ข SYSTEM TIME [${new Date().toISOString()}] โ€ข GENERATED FOR ARCADIAL
561
544
  </footer>
562
545
  </div>
563
546
 
@@ -579,78 +562,73 @@ class ArcalityReporter {
579
562
  </body>
580
563
  </html>
581
564
  `;
582
- }
583
- getAttachmentText(att) {
584
- if (!att)
585
- return null;
586
- if (att.body)
587
- return att.body.toString();
588
- if (att.path) {
589
- const actualPath = import_path.default.isAbsolute(att.path) ? att.path : import_path.default.join(this.outputDir, att.path);
590
- if (import_fs.default.existsSync(actualPath)) {
591
- return import_fs.default.readFileSync(actualPath, "utf8");
592
- }
593
565
  }
594
- return null;
595
- }
596
- _renderSecuritySection(attachments, index) {
597
- let vulnerabilities = [];
598
- const reportAtt = attachments.find((a) => a.name === "security_report");
599
- if (reportAtt) {
600
- const text = this.getAttachmentText(reportAtt);
601
- if (text) {
602
- try {
603
- const parsed = JSON.parse(text);
604
- if (Array.isArray(parsed))
605
- vulnerabilities.push(...parsed);
606
- } catch (e) {
566
+ getAttachmentText(att) {
567
+ if (!att)
568
+ return null;
569
+ if (att.body)
570
+ return att.body.toString();
571
+ if (att.path) {
572
+ const actualPath = path_1.default.isAbsolute(att.path) ? att.path : path_1.default.join(this.outputDir, att.path);
573
+ if (fs_1.default.existsSync(actualPath)) {
574
+ return fs_1.default.readFileSync(actualPath, 'utf8');
575
+ }
607
576
  }
608
- }
577
+ return null;
609
578
  }
610
- const findingAtts = attachments.filter((a) => a.name === "security_finding");
611
- for (const findingAtt of findingAtts) {
612
- const text = this.getAttachmentText(findingAtt);
613
- if (text) {
614
- try {
615
- const parsed = JSON.parse(text);
616
- vulnerabilities.push(parsed);
617
- } catch (e) {
579
+ _renderSecuritySection(attachments, index) {
580
+ let vulnerabilities = [];
581
+ const reportAtt = attachments.find(a => a.name === 'security_report');
582
+ if (reportAtt) {
583
+ const text = this.getAttachmentText(reportAtt);
584
+ if (text) {
585
+ try {
586
+ const parsed = JSON.parse(text);
587
+ if (Array.isArray(parsed))
588
+ vulnerabilities.push(...parsed);
589
+ }
590
+ catch (e) { }
591
+ }
618
592
  }
619
- }
620
- }
621
- if (vulnerabilities.length === 0)
622
- return "";
623
- const severityOrder = { "Critical": 0, "High": 1, "Medium": 2, "Low": 3, "Info": 4 };
624
- const severityCounts = { "Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0 };
625
- let worstSeverity = "Info";
626
- vulnerabilities.forEach((v) => {
627
- const severity = v.severity;
628
- if (severityCounts[severity] !== void 0) {
629
- severityCounts[severity]++;
630
- }
631
- if (severityOrder[severity] < severityOrder[worstSeverity]) {
632
- worstSeverity = severity;
633
- }
634
- });
635
- const getSeverityColor = (sev) => {
636
- switch (sev) {
637
- case "Critical":
638
- return "var(--error)";
639
- case "High":
640
- return "#fb923c";
641
- case "Medium":
642
- return "var(--warning)";
643
- case "Low":
644
- return "#38bdf8";
645
- case "Info":
646
- return "#94a3b8";
647
- }
648
- };
649
- const riskColor = getSeverityColor(worstSeverity);
650
- return `
593
+ const findingAtts = attachments.filter(a => a.name === 'security_finding');
594
+ for (const findingAtt of findingAtts) {
595
+ const text = this.getAttachmentText(findingAtt);
596
+ if (text) {
597
+ try {
598
+ const parsed = JSON.parse(text);
599
+ vulnerabilities.push(parsed);
600
+ }
601
+ catch (e) { }
602
+ }
603
+ }
604
+ if (vulnerabilities.length === 0)
605
+ return '';
606
+ const severityOrder = { 'Critical': 0, 'High': 1, 'Medium': 2, 'Low': 3, 'Info': 4 };
607
+ const severityCounts = { 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0 };
608
+ let worstSeverity = 'Info';
609
+ vulnerabilities.forEach(v => {
610
+ const severity = v.severity;
611
+ if (severityCounts[severity] !== undefined) {
612
+ severityCounts[severity]++;
613
+ }
614
+ if (severityOrder[severity] < severityOrder[worstSeverity]) {
615
+ worstSeverity = severity;
616
+ }
617
+ });
618
+ const getSeverityColor = (sev) => {
619
+ switch (sev) {
620
+ case 'Critical': return 'var(--error)';
621
+ case 'High': return '#fb923c';
622
+ case 'Medium': return 'var(--warning)';
623
+ case 'Low': return '#38bdf8';
624
+ case 'Info': return '#94a3b8';
625
+ }
626
+ };
627
+ const riskColor = getSeverityColor(worstSeverity);
628
+ return `
651
629
  <div class="security-section">
652
630
  <div class="security-header" onclick="toggleDetails('security-details-${index}')">
653
- <h3>\u{1F6E1}\uFE0F Security Assessment</h3>
631
+ <h3>๐Ÿ›ก๏ธ Security Assessment</h3>
654
632
  <span class="security-risk-badge" style="background-color: ${riskColor};">${worstSeverity} Risk</span>
655
633
  </div>
656
634
  <div class="security-details" id="security-details-${index}" style="display: block;">
@@ -673,22 +651,22 @@ class ArcalityReporter {
673
651
  </div>
674
652
  </div>
675
653
  <div class="vuln-list">
676
- ${vulnerabilities.map((v) => {
677
- const sev = v.severity;
678
- const cardColor = getSeverityColor(sev);
679
- return `
654
+ ${vulnerabilities.map(v => {
655
+ const sev = v.severity;
656
+ const cardColor = getSeverityColor(sev);
657
+ return `
680
658
  <div class="vuln-card" style="border-left-color: ${cardColor};">
681
659
  <div class="vuln-card-title">
682
660
  <span class="tag" style="background-color: ${cardColor}20; color: ${cardColor};">${v.severity}</span>
683
- <span>${this.escapeHtml(v.category)} ${v.subcategory ? `<span style="opacity:0.7">\u2014 ${this.escapeHtml(v.subcategory)}</span>` : ""}</span>
661
+ <span>${this.escapeHtml(v.category)} ${v.subcategory ? `<span style="opacity:0.7">โ€” ${this.escapeHtml(v.subcategory)}</span>` : ''}</span>
684
662
  </div>
685
663
  <div style="font-size: 0.8rem; opacity: 0.8; margin-top: 5px; margin-bottom: 10px; display: flex; flex-wrap: wrap; gap: 12px;">
686
- ${v.type ? `<span><strong style="color:var(--accent);">Type:</strong> ${this.escapeHtml(v.type)}</span>` : ""}
687
- ${v.confidence ? `<span><strong>Confidence:</strong> ${this.escapeHtml(v.confidence)}</span>` : ""}
688
- ${v.exploitability ? `<span><strong>Exploitability:</strong> ${this.escapeHtml(v.exploitability)}</span>` : ""}
664
+ ${v.type ? `<span><strong style="color:var(--accent);">Type:</strong> ${this.escapeHtml(v.type)}</span>` : ''}
665
+ ${v.confidence ? `<span><strong>Confidence:</strong> ${this.escapeHtml(v.confidence)}</span>` : ''}
666
+ ${v.exploitability ? `<span><strong>Exploitability:</strong> ${this.escapeHtml(v.exploitability)}</span>` : ''}
689
667
  </div>
690
668
  <p class="vuln-card-desc">${this.escapeHtml(v.description)}</p>
691
- ${v.impact ? `<p class="vuln-card-impact" style="font-size: 0.85rem; color: #fb923c; margin-bottom: 10px;"><strong>Potential Impact:</strong> ${this.escapeHtml(v.impact)}</p>` : ""}
669
+ ${v.impact ? `<p class="vuln-card-impact" style="font-size: 0.85rem; color: #fb923c; margin-bottom: 10px;"><strong>Potential Impact:</strong> ${this.escapeHtml(v.impact)}</p>` : ''}
692
670
 
693
671
  <div class="vuln-card-evidence">
694
672
  <strong>Evidence:</strong>
@@ -699,31 +677,36 @@ class ArcalityReporter {
699
677
  <div class="vuln-card-repro" style="margin: 10px 0; background: rgba(0,0,0,0.2); padding: 10px; border-radius: 6px; border-left: 2px solid ${cardColor}80;">
700
678
  <strong style="font-size: 0.85rem; color: var(--text-muted);">Reproduction Steps:</strong>
701
679
  <ol style="margin: 5px 0 0 20px; font-size: 0.85rem; color: var(--text-main);">
702
- ${v.reproductionSteps.map((s) => `<li>${this.escapeHtml(s)}</li>`).join("")}
680
+ ${v.reproductionSteps.map((s) => `<li>${this.escapeHtml(s)}</li>`).join('')}
703
681
  </ol>
704
- </div>` : ""}
682
+ </div>` : ''}
705
683
 
706
684
  <div class="vuln-card-remediation">
707
- <strong>\u2192 Remediation:</strong> ${this.escapeHtml(v.remediation)}
685
+ <strong>โ†’ Remediation:</strong> ${this.escapeHtml(v.remediation)}
708
686
  </div>
709
687
 
710
688
  ${v.classification ? `
711
689
  <div style="font-size: 0.75rem; opacity: 0.5; margin-top: 12px; display: flex; gap: 15px; font-family: 'JetBrains Mono', monospace;">
712
- ${v.classification.owaspTop10 ? `<span>[OWASP: ${this.escapeHtml(v.classification.owaspTop10)}]</span>` : ""}
713
- ${v.classification.cwe ? `<span>[CWE: ${this.escapeHtml(v.classification.cwe)}]</span>` : ""}
714
- </div>` : ""}
690
+ ${v.classification.owaspTop10 ? `<span>[OWASP: ${this.escapeHtml(v.classification.owaspTop10)}]</span>` : ''}
691
+ ${v.classification.cwe ? `<span>[CWE: ${this.escapeHtml(v.classification.cwe)}]</span>` : ''}
692
+ </div>` : ''}
715
693
  </div>
716
694
  `;
717
- }).join("")}
695
+ }).join('')}
718
696
  </div>
719
697
  </div>
720
698
  </div>
721
699
  `;
722
- }
723
- escapeHtml(unsafe) {
724
- if (!unsafe)
725
- return "";
726
- return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
727
- }
700
+ }
701
+ escapeHtml(unsafe) {
702
+ if (!unsafe)
703
+ return '';
704
+ return unsafe
705
+ .replace(/&/g, "&amp;")
706
+ .replace(/</g, "&lt;")
707
+ .replace(/>/g, "&gt;")
708
+ .replace(/"/g, "&quot;")
709
+ .replace(/'/g, "&#039;");
710
+ }
728
711
  }
729
- var ArcalityReporter_default = ArcalityReporter;
712
+ exports.default = ArcalityReporter;