opena2a-cli 0.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 (150) hide show
  1. package/dist/adapters/docker.d.ts +8 -0
  2. package/dist/adapters/docker.d.ts.map +1 -0
  3. package/dist/adapters/docker.js +60 -0
  4. package/dist/adapters/docker.js.map +1 -0
  5. package/dist/adapters/import.d.ts +12 -0
  6. package/dist/adapters/import.d.ts.map +1 -0
  7. package/dist/adapters/import.js +76 -0
  8. package/dist/adapters/import.js.map +1 -0
  9. package/dist/adapters/index.d.ts +9 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +40 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/python.d.ts +9 -0
  14. package/dist/adapters/python.d.ts.map +1 -0
  15. package/dist/adapters/python.js +73 -0
  16. package/dist/adapters/python.js.map +1 -0
  17. package/dist/adapters/registry.d.ts +6 -0
  18. package/dist/adapters/registry.d.ts.map +1 -0
  19. package/dist/adapters/registry.js +86 -0
  20. package/dist/adapters/registry.js.map +1 -0
  21. package/dist/adapters/spawn.d.ts +9 -0
  22. package/dist/adapters/spawn.d.ts.map +1 -0
  23. package/dist/adapters/spawn.js +63 -0
  24. package/dist/adapters/spawn.js.map +1 -0
  25. package/dist/adapters/types.d.ts +35 -0
  26. package/dist/adapters/types.d.ts.map +1 -0
  27. package/dist/adapters/types.js +3 -0
  28. package/dist/adapters/types.js.map +1 -0
  29. package/dist/branding.d.ts +3 -0
  30. package/dist/branding.d.ts.map +1 -0
  31. package/dist/branding.js +21 -0
  32. package/dist/branding.js.map +1 -0
  33. package/dist/commands/baselines.d.ts +14 -0
  34. package/dist/commands/baselines.d.ts.map +1 -0
  35. package/dist/commands/baselines.js +269 -0
  36. package/dist/commands/baselines.js.map +1 -0
  37. package/dist/commands/guard.d.ts +38 -0
  38. package/dist/commands/guard.d.ts.map +1 -0
  39. package/dist/commands/guard.js +307 -0
  40. package/dist/commands/guard.js.map +1 -0
  41. package/dist/commands/init.d.ts +14 -0
  42. package/dist/commands/init.d.ts.map +1 -0
  43. package/dist/commands/init.js +356 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/onepassword-migration.d.ts +23 -0
  46. package/dist/commands/onepassword-migration.d.ts.map +1 -0
  47. package/dist/commands/onepassword-migration.js +179 -0
  48. package/dist/commands/onepassword-migration.js.map +1 -0
  49. package/dist/commands/protect.d.ts +34 -0
  50. package/dist/commands/protect.d.ts.map +1 -0
  51. package/dist/commands/protect.js +642 -0
  52. package/dist/commands/protect.js.map +1 -0
  53. package/dist/commands/runtime.d.ts +28 -0
  54. package/dist/commands/runtime.d.ts.map +1 -0
  55. package/dist/commands/runtime.js +309 -0
  56. package/dist/commands/runtime.js.map +1 -0
  57. package/dist/commands/self-register.d.ts +39 -0
  58. package/dist/commands/self-register.d.ts.map +1 -0
  59. package/dist/commands/self-register.js +528 -0
  60. package/dist/commands/self-register.js.map +1 -0
  61. package/dist/commands/verify.d.ts +25 -0
  62. package/dist/commands/verify.d.ts.map +1 -0
  63. package/dist/commands/verify.js +300 -0
  64. package/dist/commands/verify.js.map +1 -0
  65. package/dist/contextual/advisor.d.ts +12 -0
  66. package/dist/contextual/advisor.d.ts.map +1 -0
  67. package/dist/contextual/advisor.js +94 -0
  68. package/dist/contextual/advisor.js.map +1 -0
  69. package/dist/contextual/index.d.ts +3 -0
  70. package/dist/contextual/index.d.ts.map +1 -0
  71. package/dist/contextual/index.js +7 -0
  72. package/dist/contextual/index.js.map +1 -0
  73. package/dist/guided/attack-walkthrough.d.ts +13 -0
  74. package/dist/guided/attack-walkthrough.d.ts.map +1 -0
  75. package/dist/guided/attack-walkthrough.js +113 -0
  76. package/dist/guided/attack-walkthrough.js.map +1 -0
  77. package/dist/guided/wizard.d.ts +2 -0
  78. package/dist/guided/wizard.d.ts.map +1 -0
  79. package/dist/guided/wizard.js +108 -0
  80. package/dist/guided/wizard.js.map +1 -0
  81. package/dist/index.d.ts +3 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +326 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/natural/index.d.ts +4 -0
  86. package/dist/natural/index.d.ts.map +1 -0
  87. package/dist/natural/index.js +9 -0
  88. package/dist/natural/index.js.map +1 -0
  89. package/dist/natural/intent-map.d.ts +7 -0
  90. package/dist/natural/intent-map.d.ts.map +1 -0
  91. package/dist/natural/intent-map.js +145 -0
  92. package/dist/natural/intent-map.js.map +1 -0
  93. package/dist/natural/llm-fallback.d.ts +8 -0
  94. package/dist/natural/llm-fallback.d.ts.map +1 -0
  95. package/dist/natural/llm-fallback.js +143 -0
  96. package/dist/natural/llm-fallback.js.map +1 -0
  97. package/dist/report/interactive-html.d.ts +51 -0
  98. package/dist/report/interactive-html.d.ts.map +1 -0
  99. package/dist/report/interactive-html.js +508 -0
  100. package/dist/report/interactive-html.js.map +1 -0
  101. package/dist/router.d.ts +23 -0
  102. package/dist/router.d.ts.map +1 -0
  103. package/dist/router.js +132 -0
  104. package/dist/router.js.map +1 -0
  105. package/dist/semantic/command-index.json +182 -0
  106. package/dist/semantic/index.d.ts +3 -0
  107. package/dist/semantic/index.d.ts.map +1 -0
  108. package/dist/semantic/index.js +28 -0
  109. package/dist/semantic/index.js.map +1 -0
  110. package/dist/semantic/search.d.ts +17 -0
  111. package/dist/semantic/search.d.ts.map +1 -0
  112. package/dist/semantic/search.js +123 -0
  113. package/dist/semantic/search.js.map +1 -0
  114. package/dist/util/action-prompt.d.ts +29 -0
  115. package/dist/util/action-prompt.d.ts.map +1 -0
  116. package/dist/util/action-prompt.js +126 -0
  117. package/dist/util/action-prompt.js.map +1 -0
  118. package/dist/util/advisories.d.ts +43 -0
  119. package/dist/util/advisories.d.ts.map +1 -0
  120. package/dist/util/advisories.js +229 -0
  121. package/dist/util/advisories.js.map +1 -0
  122. package/dist/util/colors.d.ts +9 -0
  123. package/dist/util/colors.d.ts.map +1 -0
  124. package/dist/util/colors.js +18 -0
  125. package/dist/util/colors.js.map +1 -0
  126. package/dist/util/credential-patterns.d.ts +38 -0
  127. package/dist/util/credential-patterns.d.ts.map +1 -0
  128. package/dist/util/credential-patterns.js +203 -0
  129. package/dist/util/credential-patterns.js.map +1 -0
  130. package/dist/util/detect.d.ts +11 -0
  131. package/dist/util/detect.d.ts.map +1 -0
  132. package/dist/util/detect.js +49 -0
  133. package/dist/util/detect.js.map +1 -0
  134. package/dist/util/format.d.ts +6 -0
  135. package/dist/util/format.d.ts.map +1 -0
  136. package/dist/util/format.js +49 -0
  137. package/dist/util/format.js.map +1 -0
  138. package/dist/util/report-submission.d.ts +64 -0
  139. package/dist/util/report-submission.d.ts.map +1 -0
  140. package/dist/util/report-submission.js +109 -0
  141. package/dist/util/report-submission.js.map +1 -0
  142. package/dist/util/spinner.d.ts +10 -0
  143. package/dist/util/spinner.d.ts.map +1 -0
  144. package/dist/util/spinner.js +38 -0
  145. package/dist/util/spinner.js.map +1 -0
  146. package/dist/util/version.d.ts +5 -0
  147. package/dist/util/version.d.ts.map +1 -0
  148. package/dist/util/version.js +24 -0
  149. package/dist/util/version.js.map +1 -0
  150. package/package.json +47 -0
@@ -0,0 +1,508 @@
1
+ "use strict";
2
+ /**
3
+ * Interactive HTML report generator (ScoutSuite-style).
4
+ *
5
+ * Generates a self-contained HTML file with:
6
+ * - Dark theme matching HMA website design language
7
+ * - Embedded JSON data (no external dependencies)
8
+ * - Hash-based SPA navigation (#dashboard, #findings, #finding-CRED-001)
9
+ * - Severity filtering and text search
10
+ * - Audience toggle (Executive / Engineering)
11
+ * - SVG donut chart for severity breakdown
12
+ *
13
+ * Design tokens from hackmyagent-web:
14
+ * Background: #0a0a0a, Card: #171717, Border: #262626
15
+ * Primary: #14b8a6 (teal), Muted: #a3a3a3
16
+ * Critical: #ef4444, High: #f97316, Medium: #eab308, Low: #3b82f6
17
+ * Font: system monospace (JetBrains Mono fallback)
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.generateInteractiveHtml = generateInteractiveHtml;
21
+ /**
22
+ * Generate a self-contained interactive HTML report.
23
+ */
24
+ function generateInteractiveHtml(data) {
25
+ const jsonData = JSON.stringify(data);
26
+ return `<!DOCTYPE html>
27
+ <html lang="en">
28
+ <head>
29
+ <meta charset="UTF-8">
30
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
31
+ <title>OpenA2A Security Report - ${escapeHtml(data.metadata.targetName)}</title>
32
+ <style>
33
+ ${CSS}
34
+ </style>
35
+ </head>
36
+ <body>
37
+ <script id="report-data" type="application/json">${escapeHtml(jsonData)}</script>
38
+ <div id="app">
39
+ <header class="header">
40
+ <div class="header-left">
41
+ <h1 class="logo">OpenA2A</h1>
42
+ <span class="header-sep">|</span>
43
+ <span class="header-label">Security Report</span>
44
+ </div>
45
+ <div class="header-right">
46
+ <div class="audience-toggle" id="audience-toggle">
47
+ <button class="toggle-btn active" data-audience="engineering">Engineering</button>
48
+ <button class="toggle-btn" data-audience="executive">Executive</button>
49
+ </div>
50
+ <nav class="nav">
51
+ <a href="#dashboard" class="nav-link active" data-view="dashboard">Dashboard</a>
52
+ <a href="#findings" class="nav-link" data-view="findings">Findings</a>
53
+ </nav>
54
+ </div>
55
+ </header>
56
+
57
+ <main class="main">
58
+ <div id="view-dashboard" class="view active"></div>
59
+ <div id="view-findings" class="view"></div>
60
+ </main>
61
+
62
+ <footer class="footer">
63
+ <span>Generated ${escapeHtml(data.metadata.generatedAt)} by OpenA2A v${escapeHtml(data.metadata.toolVersion)}</span>
64
+ <span class="footer-sep"> | </span>
65
+ <a href="https://opena2a.org/star" target="_blank" rel="noopener noreferrer">Open Source</a>
66
+ <span class="footer-sep"> | </span>
67
+ <a href="https://github.com/opena2a-org" target="_blank" rel="noopener noreferrer">GitHub</a>
68
+ </footer>
69
+ </div>
70
+ <script>
71
+ ${JS}
72
+ </script>
73
+ </body>
74
+ </html>`;
75
+ }
76
+ function escapeHtml(str) {
77
+ return str
78
+ .replace(/&/g, '&amp;')
79
+ .replace(/</g, '&lt;')
80
+ .replace(/>/g, '&gt;')
81
+ .replace(/"/g, '&quot;')
82
+ .replace(/'/g, '&#39;');
83
+ }
84
+ // --- Embedded CSS ---
85
+ const CSS = `
86
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
87
+ :root{
88
+ --bg:#0a0a0a;--card:#171717;--border:#262626;--border-hover:#404040;
89
+ --primary:#14b8a6;--primary-dim:#0d9488;
90
+ --text:#e5e5e5;--muted:#a3a3a3;--dim:#737373;
91
+ --critical:#ef4444;--high:#f97316;--medium:#eab308;--low:#3b82f6;--info:#6b7280;
92
+ --radius:8px;--gap:16px;
93
+ --font:'JetBrains Mono','Fira Code','SF Mono',Menlo,Consolas,monospace;
94
+ }
95
+ body{font-family:var(--font);background:var(--bg);color:var(--text);line-height:1.6;font-size:14px}
96
+ a{color:var(--primary);text-decoration:none}
97
+ a:hover{text-decoration:underline}
98
+
99
+ .header{display:flex;justify-content:space-between;align-items:center;padding:16px 24px;border-bottom:1px solid var(--border);position:sticky;top:0;background:var(--bg);z-index:100}
100
+ .header-left{display:flex;align-items:center;gap:12px}
101
+ .logo{font-size:18px;font-weight:700;color:var(--primary)}
102
+ .header-sep{color:var(--border)}
103
+ .header-label{color:var(--muted);font-size:14px}
104
+ .header-right{display:flex;align-items:center;gap:24px}
105
+
106
+ .audience-toggle{display:flex;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
107
+ .toggle-btn{background:transparent;border:none;color:var(--muted);padding:6px 14px;cursor:pointer;font-family:var(--font);font-size:12px;transition:all .2s}
108
+ .toggle-btn:hover{color:var(--text)}
109
+ .toggle-btn.active{background:var(--primary-dim);color:white}
110
+
111
+ .nav{display:flex;gap:4px}
112
+ .nav-link{color:var(--muted);padding:6px 12px;border-radius:var(--radius);font-size:13px;transition:all .2s}
113
+ .nav-link:hover{color:var(--text);background:var(--card);text-decoration:none}
114
+ .nav-link.active{color:var(--primary);background:var(--card)}
115
+
116
+ .main{max-width:1200px;margin:0 auto;padding:24px}
117
+ .view{display:none}
118
+ .view.active{display:block}
119
+
120
+ .footer{text-align:center;padding:24px;color:var(--dim);font-size:12px;border-top:1px solid var(--border);margin-top:48px}
121
+ .footer-sep{color:var(--border);margin:0 4px}
122
+
123
+ /* Dashboard */
124
+ .stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--gap);margin-bottom:24px}
125
+ .stat-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:20px}
126
+ .stat-value{font-size:32px;font-weight:700}
127
+ .stat-label{color:var(--muted);font-size:12px;margin-top:4px}
128
+
129
+ .chart-section{display:grid;grid-template-columns:300px 1fr;gap:24px;margin-bottom:24px}
130
+ .chart-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:24px;display:flex;flex-direction:column;align-items:center}
131
+ .chart-card h3{margin-bottom:16px;font-size:14px;color:var(--muted)}
132
+ .chart-legend{margin-top:16px;width:100%}
133
+ .legend-item{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:13px}
134
+ .legend-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
135
+
136
+ .action-items{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:24px}
137
+ .action-items h3{font-size:14px;color:var(--muted);margin-bottom:12px}
138
+ .action-item{padding:12px 0;border-bottom:1px solid var(--border)}
139
+ .action-item:last-child{border-bottom:none}
140
+ .action-item-title{font-weight:600;margin-bottom:4px}
141
+ .action-item-desc{color:var(--muted);font-size:13px}
142
+
143
+ /* Score gauge (executive) */
144
+ .score-section{text-align:center;margin-bottom:24px}
145
+ .score-value{font-size:64px;font-weight:700}
146
+ .score-label{font-size:14px;color:var(--muted)}
147
+
148
+ /* Findings */
149
+ .findings-toolbar{display:flex;gap:12px;margin-bottom:16px;flex-wrap:wrap;align-items:center}
150
+ .search-input{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:8px 12px;color:var(--text);font-family:var(--font);font-size:13px;width:280px;outline:none}
151
+ .search-input:focus{border-color:var(--primary)}
152
+ .filter-btn{background:transparent;border:1px solid var(--border);border-radius:var(--radius);padding:6px 12px;color:var(--muted);cursor:pointer;font-family:var(--font);font-size:12px;transition:all .2s}
153
+ .filter-btn:hover{border-color:var(--text);color:var(--text)}
154
+ .filter-btn.active{border-color:var(--primary);color:var(--primary)}
155
+ .filter-btn[data-severity="critical"].active{border-color:var(--critical);color:var(--critical)}
156
+ .filter-btn[data-severity="high"].active{border-color:var(--high);color:var(--high)}
157
+ .filter-btn[data-severity="medium"].active{border-color:var(--medium);color:var(--medium)}
158
+ .filter-btn[data-severity="low"].active{border-color:var(--low);color:var(--low)}
159
+
160
+ .finding-count{color:var(--muted);font-size:13px;margin-left:auto}
161
+
162
+ .finding-card{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);margin-bottom:8px;overflow:hidden;transition:border-color .2s}
163
+ .finding-card:hover{border-color:var(--border-hover)}
164
+ .finding-card[data-severity="critical"]{border-left:3px solid var(--critical)}
165
+ .finding-card[data-severity="high"]{border-left:3px solid var(--high)}
166
+ .finding-card[data-severity="medium"]{border-left:3px solid var(--medium)}
167
+ .finding-card[data-severity="low"]{border-left:3px solid var(--low)}
168
+ .finding-card[data-severity="info"]{border-left:3px solid var(--info)}
169
+
170
+ .finding-header{display:flex;align-items:center;gap:12px;padding:14px 16px;cursor:pointer;user-select:none}
171
+ .finding-header:hover{background:rgba(255,255,255,0.02)}
172
+ .finding-severity{font-size:11px;font-weight:700;text-transform:uppercase;padding:2px 8px;border-radius:4px;flex-shrink:0}
173
+ .sev-critical{background:rgba(239,68,68,0.15);color:var(--critical)}
174
+ .sev-high{background:rgba(249,115,22,0.15);color:var(--high)}
175
+ .sev-medium{background:rgba(234,179,8,0.15);color:var(--medium)}
176
+ .sev-low{background:rgba(59,130,246,0.15);color:var(--low)}
177
+ .sev-info{background:rgba(107,114,128,0.15);color:var(--info)}
178
+
179
+ .finding-title{flex:1;font-weight:500}
180
+ .finding-id{color:var(--dim);font-size:12px;flex-shrink:0}
181
+ .finding-chevron{color:var(--dim);transition:transform .2s;font-size:12px}
182
+ .finding-card.expanded .finding-chevron{transform:rotate(90deg)}
183
+
184
+ .finding-body{display:none;padding:0 16px 16px;border-top:1px solid var(--border)}
185
+ .finding-card.expanded .finding-body{display:block}
186
+ .finding-section{margin-top:12px}
187
+ .finding-section-label{font-size:11px;text-transform:uppercase;color:var(--dim);margin-bottom:4px;letter-spacing:0.05em}
188
+ .finding-text{color:var(--muted);font-size:13px}
189
+ .finding-code{background:var(--bg);border:1px solid var(--border);border-radius:4px;padding:12px;font-size:12px;overflow-x:auto;margin-top:4px;white-space:pre-wrap}
190
+ .finding-location{color:var(--primary);font-size:13px}
191
+
192
+ /* Executive-only */
193
+ .exec-only{display:none}
194
+ .audience-executive .exec-only{display:block}
195
+ .audience-executive .eng-only{display:none}
196
+ .eng-only{display:block}
197
+
198
+ @media(max-width:768px){
199
+ .chart-section{grid-template-columns:1fr}
200
+ .header{flex-direction:column;gap:12px}
201
+ .header-right{width:100%;justify-content:space-between}
202
+ .stats-grid{grid-template-columns:repeat(2,1fr)}
203
+ }
204
+ `;
205
+ // --- Embedded JavaScript ---
206
+ const JS = `
207
+ (function() {
208
+ 'use strict';
209
+
210
+ var data = JSON.parse(document.getElementById('report-data').textContent);
211
+ var currentView = 'dashboard';
212
+ var currentAudience = 'engineering';
213
+ var activeFilters = new Set(['critical','high','medium','low','info']);
214
+ var searchTerm = '';
215
+
216
+ function init() {
217
+ renderDashboard();
218
+ renderFindings();
219
+ bindEvents();
220
+ handleHash();
221
+ window.addEventListener('hashchange', handleHash);
222
+ }
223
+
224
+ function handleHash() {
225
+ var hash = location.hash.slice(1) || 'dashboard';
226
+ if (hash.startsWith('finding-')) {
227
+ switchView('findings');
228
+ setTimeout(function() {
229
+ var el = document.querySelector('[data-finding-id="' + hash.replace('finding-','') + '"]');
230
+ if (el) { el.classList.add('expanded'); el.scrollIntoView({behavior:'smooth',block:'center'}); }
231
+ }, 100);
232
+ } else if (hash === 'findings' || hash === 'dashboard') {
233
+ switchView(hash);
234
+ }
235
+ }
236
+
237
+ function switchView(view) {
238
+ currentView = view;
239
+ document.querySelectorAll('.view').forEach(function(v) { v.classList.remove('active'); });
240
+ document.getElementById('view-' + view).classList.add('active');
241
+ document.querySelectorAll('.nav-link').forEach(function(l) {
242
+ l.classList.toggle('active', l.dataset.view === view);
243
+ });
244
+ }
245
+
246
+ function bindEvents() {
247
+ // Nav links
248
+ document.querySelectorAll('.nav-link').forEach(function(link) {
249
+ link.addEventListener('click', function(e) {
250
+ e.preventDefault();
251
+ switchView(this.dataset.view);
252
+ history.pushState(null, '', '#' + this.dataset.view);
253
+ });
254
+ });
255
+
256
+ // Audience toggle
257
+ document.querySelectorAll('.toggle-btn').forEach(function(btn) {
258
+ btn.addEventListener('click', function() {
259
+ currentAudience = this.dataset.audience;
260
+ document.querySelectorAll('.toggle-btn').forEach(function(b) { b.classList.remove('active'); });
261
+ this.classList.add('active');
262
+ document.getElementById('app').className = 'audience-' + currentAudience;
263
+ renderDashboard();
264
+ });
265
+ });
266
+
267
+ // Severity filters
268
+ document.addEventListener('click', function(e) {
269
+ if (e.target.classList.contains('filter-btn') && e.target.dataset.severity) {
270
+ var sev = e.target.dataset.severity;
271
+ if (sev === 'all') {
272
+ activeFilters = new Set(['critical','high','medium','low','info']);
273
+ document.querySelectorAll('.filter-btn').forEach(function(b) { b.classList.add('active'); });
274
+ } else {
275
+ if (activeFilters.has(sev)) { activeFilters.delete(sev); } else { activeFilters.add(sev); }
276
+ e.target.classList.toggle('active');
277
+ var allBtn = document.querySelector('.filter-btn[data-severity="all"]');
278
+ if (allBtn) allBtn.classList.toggle('active', activeFilters.size === 5);
279
+ }
280
+ applyFilters();
281
+ }
282
+ });
283
+
284
+ // Finding accordion
285
+ document.addEventListener('click', function(e) {
286
+ var header = e.target.closest('.finding-header');
287
+ if (header) {
288
+ header.parentElement.classList.toggle('expanded');
289
+ }
290
+ });
291
+
292
+ // Search
293
+ var searchInput = document.getElementById('search-input');
294
+ if (searchInput) {
295
+ searchInput.addEventListener('input', function() {
296
+ searchTerm = this.value.toLowerCase();
297
+ applyFilters();
298
+ });
299
+ }
300
+ }
301
+
302
+ function applyFilters() {
303
+ var cards = document.querySelectorAll('.finding-card');
304
+ var visible = 0;
305
+ cards.forEach(function(card) {
306
+ var sev = card.dataset.severity;
307
+ var text = card.textContent.toLowerCase();
308
+ var show = activeFilters.has(sev) && (!searchTerm || text.indexOf(searchTerm) !== -1);
309
+ card.style.display = show ? '' : 'none';
310
+ if (show) visible++;
311
+ });
312
+ var counter = document.getElementById('finding-count');
313
+ if (counter) counter.textContent = visible + ' of ' + data.findings.filter(function(f){return !f.passed}).length + ' findings';
314
+ }
315
+
316
+ // --- Dashboard ---
317
+
318
+ function renderDashboard() {
319
+ var el = document.getElementById('view-dashboard');
320
+ var failedFindings = data.findings.filter(function(f) { return !f.passed; });
321
+ var bySev = data.summary.bySeverity;
322
+ var score = data.summary.score;
323
+ var grade = data.summary.grade;
324
+
325
+ var html = '';
326
+
327
+ // Executive: score gauge
328
+ if (currentAudience === 'executive' && (score !== undefined || grade)) {
329
+ html += '<div class="score-section">';
330
+ if (score !== undefined) {
331
+ var scoreColor = score >= 80 ? 'var(--primary)' : score >= 50 ? 'var(--medium)' : 'var(--critical)';
332
+ html += '<div class="score-value" style="color:' + scoreColor + '">' + score + '</div>';
333
+ html += '<div class="score-label">Security Score' + (grade ? ' - Grade ' + grade : '') + '</div>';
334
+ }
335
+ html += '</div>';
336
+ }
337
+
338
+ // Stats grid
339
+ html += '<div class="stats-grid">';
340
+ html += statCard(data.summary.totalFindings, 'Total Findings', 'var(--text)');
341
+ html += statCard(bySev.critical || 0, 'Critical', 'var(--critical)');
342
+ html += statCard(bySev.high || 0, 'High', 'var(--high)');
343
+ html += statCard(bySev.medium || 0, 'Medium', 'var(--medium)');
344
+ html += statCard(bySev.low || 0, 'Low', 'var(--low)');
345
+ html += '</div>';
346
+
347
+ // Chart + action items
348
+ html += '<div class="chart-section">';
349
+ html += '<div class="chart-card"><h3>Severity Breakdown</h3>' + donutChart(bySev) + chartLegend(bySev) + '</div>';
350
+ html += '<div class="action-items"><h3>Top Action Items</h3>' + actionItems(failedFindings) + '</div>';
351
+ html += '</div>';
352
+
353
+ el.innerHTML = html;
354
+ }
355
+
356
+ function statCard(value, label, color) {
357
+ return '<div class="stat-card"><div class="stat-value" style="color:' + color + '">' + value + '</div><div class="stat-label">' + label + '</div></div>';
358
+ }
359
+
360
+ function donutChart(bySev) {
361
+ var total = (bySev.critical||0) + (bySev.high||0) + (bySev.medium||0) + (bySev.low||0) + (bySev.info||0);
362
+ if (total === 0) return '<svg width="160" height="160"><circle cx="80" cy="80" r="60" fill="none" stroke="var(--border)" stroke-width="20"/></svg>';
363
+
364
+ var r = 60, cx = 80, cy = 80, sw = 20;
365
+ var circ = 2 * Math.PI * r;
366
+ var segments = [
367
+ {key:'critical',color:'var(--critical)'},{key:'high',color:'var(--high)'},
368
+ {key:'medium',color:'var(--medium)'},{key:'low',color:'var(--low)'},{key:'info',color:'var(--info)'}
369
+ ];
370
+ var svg = '<svg width="160" height="160" viewBox="0 0 160 160">';
371
+ var offset = 0;
372
+ segments.forEach(function(seg) {
373
+ var count = bySev[seg.key] || 0;
374
+ if (count === 0) return;
375
+ var pct = count / total;
376
+ var dash = pct * circ;
377
+ var gap = circ - dash;
378
+ svg += '<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="'+seg.color+'" stroke-width="'+sw+'" ' +
379
+ 'stroke-dasharray="'+dash+' '+gap+'" stroke-dashoffset="'+(-(offset))+'" transform="rotate(-90 '+cx+' '+cy+')"/>';
380
+ offset += dash;
381
+ });
382
+ svg += '</svg>';
383
+ return svg;
384
+ }
385
+
386
+ function chartLegend(bySev) {
387
+ var items = [
388
+ {key:'critical',label:'Critical',color:'var(--critical)'},
389
+ {key:'high',label:'High',color:'var(--high)'},
390
+ {key:'medium',label:'Medium',color:'var(--medium)'},
391
+ {key:'low',label:'Low',color:'var(--low)'},
392
+ {key:'info',label:'Info',color:'var(--info)'}
393
+ ];
394
+ var html = '<div class="chart-legend">';
395
+ items.forEach(function(item) {
396
+ html += '<div class="legend-item"><span class="legend-dot" style="background:'+item.color+'"></span>' +
397
+ '<span>'+item.label+'</span><span style="margin-left:auto;color:var(--muted)">'+(bySev[item.key]||0)+'</span></div>';
398
+ });
399
+ html += '</div>';
400
+ return html;
401
+ }
402
+
403
+ function actionItems(findings) {
404
+ var critical = findings.filter(function(f){return f.severity==='critical'}).slice(0,3);
405
+ if (critical.length === 0) critical = findings.slice(0,3);
406
+ if (critical.length === 0) return '<div class="action-item"><div class="action-item-title" style="color:var(--primary)">No action items</div><div class="action-item-desc">All checks passed.</div></div>';
407
+
408
+ var html = '';
409
+ critical.forEach(function(f) {
410
+ html += '<div class="action-item">';
411
+ html += '<div class="action-item-title">' + esc(f.title) + '</div>';
412
+ if (currentAudience === 'executive' && f.businessImpact) {
413
+ html += '<div class="action-item-desc">' + esc(f.businessImpact) + '</div>';
414
+ } else {
415
+ html += '<div class="action-item-desc">' + esc(f.description) + '</div>';
416
+ }
417
+ html += '</div>';
418
+ });
419
+ return html;
420
+ }
421
+
422
+ // --- Findings ---
423
+
424
+ function renderFindings() {
425
+ var el = document.getElementById('view-findings');
426
+ var failedFindings = data.findings.filter(function(f) { return !f.passed; });
427
+
428
+ var html = '<div class="findings-toolbar">';
429
+ html += '<input type="text" class="search-input" id="search-input" placeholder="Search findings...">';
430
+ html += '<button class="filter-btn active" data-severity="all">All</button>';
431
+ html += '<button class="filter-btn active" data-severity="critical">Critical</button>';
432
+ html += '<button class="filter-btn active" data-severity="high">High</button>';
433
+ html += '<button class="filter-btn active" data-severity="medium">Medium</button>';
434
+ html += '<button class="filter-btn active" data-severity="low">Low</button>';
435
+ html += '<span class="finding-count" id="finding-count">' + failedFindings.length + ' findings</span>';
436
+ html += '</div>';
437
+
438
+ failedFindings.forEach(function(f) {
439
+ html += findingCard(f);
440
+ });
441
+
442
+ if (failedFindings.length === 0) {
443
+ html += '<div class="stat-card" style="text-align:center;padding:48px"><div class="stat-value" style="color:var(--primary)">0</div><div class="stat-label">No findings. All checks passed.</div></div>';
444
+ }
445
+
446
+ el.innerHTML = html;
447
+ }
448
+
449
+ function findingCard(f) {
450
+ var html = '<div class="finding-card" data-severity="' + f.severity + '" data-finding-id="' + esc(f.id) + '">';
451
+ html += '<div class="finding-header">';
452
+ html += '<span class="finding-severity sev-' + f.severity + '">' + f.severity + '</span>';
453
+ html += '<span class="finding-title">' + esc(f.title) + '</span>';
454
+ html += '<span class="finding-id">' + esc(f.id) + '</span>';
455
+ html += '<span class="finding-chevron">&#9654;</span>';
456
+ html += '</div>';
457
+
458
+ html += '<div class="finding-body">';
459
+
460
+ // Description (always shown)
461
+ html += '<div class="finding-section"><div class="finding-section-label">Description</div>';
462
+ html += '<div class="finding-text">' + esc(f.description) + '</div></div>';
463
+
464
+ // Explanation (executive-friendly)
465
+ if (f.explanation) {
466
+ html += '<div class="finding-section exec-only"><div class="finding-section-label">Why This Matters</div>';
467
+ html += '<div class="finding-text">' + esc(f.explanation) + '</div></div>';
468
+ }
469
+
470
+ // Business impact (executive)
471
+ if (f.businessImpact) {
472
+ html += '<div class="finding-section exec-only"><div class="finding-section-label">Business Impact</div>';
473
+ html += '<div class="finding-text">' + esc(f.businessImpact) + '</div></div>';
474
+ }
475
+
476
+ // Location (engineering only)
477
+ if (f.file) {
478
+ html += '<div class="finding-section eng-only"><div class="finding-section-label">Location</div>';
479
+ html += '<div class="finding-location">' + esc(f.file) + (f.line ? ':' + f.line : '') + '</div></div>';
480
+ }
481
+
482
+ // Fix / remediation (engineering only)
483
+ if (f.fix) {
484
+ html += '<div class="finding-section eng-only"><div class="finding-section-label">Remediation</div>';
485
+ html += '<div class="finding-code">' + esc(f.fix) + '</div></div>';
486
+ }
487
+
488
+ // Evidence
489
+ if (f.evidence) {
490
+ html += '<div class="finding-section eng-only"><div class="finding-section-label">Evidence</div>';
491
+ html += '<div class="finding-code">' + esc(f.evidence) + '</div></div>';
492
+ }
493
+
494
+ html += '</div></div>';
495
+ return html;
496
+ }
497
+
498
+ function esc(s) {
499
+ if (!s) return '';
500
+ var d = document.createElement('div');
501
+ d.textContent = s;
502
+ return d.innerHTML;
503
+ }
504
+
505
+ init();
506
+ })();
507
+ `;
508
+ //# sourceMappingURL=interactive-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-html.js","sourceRoot":"","sources":["../../src/report/interactive-html.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAoCH,0DAoDC;AAvDD;;GAEG;AACH,SAAgB,uBAAuB,CAAC,IAA2B;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEtC,OAAO;;;;;mCAK0B,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;;EAErE,GAAG;;;;mDAI8C,UAAU,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;sBA0BjD,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,gBAAgB,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;;;;;;;;EAQ9G,EAAE;;;QAGI,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,uBAAuB;AAEvB,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHX,CAAC;AAEF,8BAA8B;AAE9B,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6SV,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { RunOptions } from './adapters/types.js';
2
+ export type InputType = 'subcommand' | 'search' | 'context' | 'natural' | 'guided';
3
+ export interface ClassifiedInput {
4
+ type: InputType;
5
+ /** The raw input after the operator (e.g., query after ~) */
6
+ value: string;
7
+ /** Remaining args */
8
+ args: string[];
9
+ }
10
+ /**
11
+ * Three-tier input classifier:
12
+ * 1. ~ prefix -> semantic search
13
+ * 2. ? prefix -> contextual advisor
14
+ * 3. "quoted" -> natural language
15
+ * 4. known cmd -> subcommand dispatch
16
+ * 5. no args -> guided interactive mode
17
+ */
18
+ export declare function classifyInput(argv: string[]): ClassifiedInput;
19
+ /**
20
+ * Dispatch a classified subcommand to the appropriate adapter.
21
+ */
22
+ export declare function dispatchCommand(command: string, args: string[], globalOptions?: Partial<RunOptions>): Promise<number>;
23
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEnF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CA8C7D;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,aAAa,GAAE,OAAO,CAAC,UAAU,CAAM,GACtC,OAAO,CAAC,MAAM,CAAC,CAmFjB"}
package/dist/router.js ADDED
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.classifyInput = classifyInput;
4
+ exports.dispatchCommand = dispatchCommand;
5
+ const index_js_1 = require("./adapters/index.js");
6
+ const protect_js_1 = require("./commands/protect.js");
7
+ /**
8
+ * Three-tier input classifier:
9
+ * 1. ~ prefix -> semantic search
10
+ * 2. ? prefix -> contextual advisor
11
+ * 3. "quoted" -> natural language
12
+ * 4. known cmd -> subcommand dispatch
13
+ * 5. no args -> guided interactive mode
14
+ */
15
+ function classifyInput(argv) {
16
+ if (argv.length === 0) {
17
+ return { type: 'guided', value: '', args: [] };
18
+ }
19
+ const first = argv[0];
20
+ // ~ semantic search operator
21
+ if (first.startsWith('~')) {
22
+ const query = first.slice(1) + (argv.length > 1 ? ' ' + argv.slice(1).join(' ') : '');
23
+ return { type: 'search', value: query.trim(), args: [] };
24
+ }
25
+ // ? contextual operator
26
+ if (first.startsWith('?') || first === '?') {
27
+ const query = first.slice(1) + (argv.length > 1 ? ' ' + argv.slice(1).join(' ') : '');
28
+ return { type: 'context', value: query.trim(), args: [] };
29
+ }
30
+ // Quoted natural language (Commander strips quotes, so check for multi-word non-command)
31
+ if (first.startsWith('"') || first.startsWith("'")) {
32
+ const joined = argv.join(' ');
33
+ const unquoted = joined.replace(/^["']|["']$/g, '');
34
+ return { type: 'natural', value: unquoted, args: [] };
35
+ }
36
+ // Known subcommand
37
+ const KNOWN_COMMANDS = [
38
+ 'init', 'check', 'protect', 'status', 'publish',
39
+ 'scan', 'runtime', 'benchmark', 'crypto', 'secrets',
40
+ 'identity', 'registry', 'research', 'hunt', 'train',
41
+ 'guard', 'dlp', 'broker', 'config', 'self-register',
42
+ 'verify', 'baselines',
43
+ ];
44
+ if (KNOWN_COMMANDS.includes(first)) {
45
+ return { type: 'subcommand', value: first, args: argv.slice(1) };
46
+ }
47
+ // Unknown single word -- try natural language
48
+ if (argv.length > 1) {
49
+ return { type: 'natural', value: argv.join(' '), args: [] };
50
+ }
51
+ // Single unknown word -- suggest search
52
+ return { type: 'search', value: first, args: [] };
53
+ }
54
+ /**
55
+ * Dispatch a classified subcommand to the appropriate adapter.
56
+ */
57
+ async function dispatchCommand(command, args, globalOptions = {}) {
58
+ // Handle 'protect' directly (not adapter-based — it orchestrates HMA + Secretless)
59
+ if (command === 'protect') {
60
+ const targetDir = args[0] ?? process.cwd();
61
+ return (0, protect_js_1.protect)({
62
+ targetDir,
63
+ dryRun: args.includes('--dry-run'),
64
+ verbose: globalOptions.verbose ?? false,
65
+ ci: globalOptions.ci ?? false,
66
+ format: globalOptions.format ?? 'text',
67
+ skipVerify: args.includes('--skip-verify'),
68
+ });
69
+ }
70
+ // Handle 'init' directly (not adapter-based)
71
+ if (command === 'init') {
72
+ const { init } = await import('./commands/init.js');
73
+ return init({
74
+ targetDir: args[0] ?? process.cwd(),
75
+ ci: globalOptions.ci ?? false,
76
+ format: globalOptions.format ?? 'text',
77
+ verbose: globalOptions.verbose ?? false,
78
+ });
79
+ }
80
+ // Handle 'guard' directly (ConfigGuard)
81
+ if (command === 'guard') {
82
+ const { guard } = await import('./commands/guard.js');
83
+ const subcommand = args[0] ?? 'status';
84
+ return guard({
85
+ subcommand: subcommand,
86
+ targetDir: process.cwd(),
87
+ ci: globalOptions.ci ?? false,
88
+ format: globalOptions.format ?? 'text',
89
+ verbose: globalOptions.verbose ?? false,
90
+ });
91
+ }
92
+ // Handle 'runtime' directly (ARP wrapper)
93
+ if (command === 'runtime') {
94
+ const { runtime } = await import('./commands/runtime.js');
95
+ const subcommand = args[0] ?? 'status';
96
+ return runtime({
97
+ subcommand: subcommand,
98
+ targetDir: process.cwd(),
99
+ ci: globalOptions.ci ?? false,
100
+ format: globalOptions.format ?? 'text',
101
+ verbose: globalOptions.verbose ?? false,
102
+ });
103
+ }
104
+ // Intent commands map to adapters
105
+ const INTENT_MAP = {
106
+ check: { adapter: 'scan', defaultArgs: ['secure'] },
107
+ status: { adapter: 'scan', defaultArgs: ['status'] },
108
+ publish: { adapter: 'registry', defaultArgs: ['check'] },
109
+ };
110
+ const intent = INTENT_MAP[command];
111
+ const adapterName = intent?.adapter ?? command;
112
+ const adapterArgs = intent ? [...intent.defaultArgs, ...args] : args;
113
+ const adapter = (0, index_js_1.createAdapter)(adapterName);
114
+ if (!adapter) {
115
+ process.stderr.write(`Unknown command: ${command}\n`);
116
+ process.stderr.write(`Run 'opena2a --help' for available commands.\n`);
117
+ return 1;
118
+ }
119
+ const available = await adapter.isAvailable();
120
+ if (!available) {
121
+ process.stderr.write(`${adapter.config.name} is not installed.\n`);
122
+ process.stderr.write(`Install: npm install -g ${adapter.config.packageName ?? adapter.config.command ?? adapter.config.name}\n`);
123
+ return 1;
124
+ }
125
+ const result = await adapter.run({
126
+ args: adapterArgs,
127
+ ...globalOptions,
128
+ cwd: globalOptions.cwd ?? process.cwd(),
129
+ });
130
+ return result.exitCode;
131
+ }
132
+ //# sourceMappingURL=router.js.map