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.
- package/dist/adapters/docker.d.ts +8 -0
- package/dist/adapters/docker.d.ts.map +1 -0
- package/dist/adapters/docker.js +60 -0
- package/dist/adapters/docker.js.map +1 -0
- package/dist/adapters/import.d.ts +12 -0
- package/dist/adapters/import.d.ts.map +1 -0
- package/dist/adapters/import.js +76 -0
- package/dist/adapters/import.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +40 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/python.d.ts +9 -0
- package/dist/adapters/python.d.ts.map +1 -0
- package/dist/adapters/python.js +73 -0
- package/dist/adapters/python.js.map +1 -0
- package/dist/adapters/registry.d.ts +6 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +86 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/spawn.d.ts +9 -0
- package/dist/adapters/spawn.d.ts.map +1 -0
- package/dist/adapters/spawn.js +63 -0
- package/dist/adapters/spawn.js.map +1 -0
- package/dist/adapters/types.d.ts +35 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +3 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/branding.d.ts +3 -0
- package/dist/branding.d.ts.map +1 -0
- package/dist/branding.js +21 -0
- package/dist/branding.js.map +1 -0
- package/dist/commands/baselines.d.ts +14 -0
- package/dist/commands/baselines.d.ts.map +1 -0
- package/dist/commands/baselines.js +269 -0
- package/dist/commands/baselines.js.map +1 -0
- package/dist/commands/guard.d.ts +38 -0
- package/dist/commands/guard.d.ts.map +1 -0
- package/dist/commands/guard.js +307 -0
- package/dist/commands/guard.js.map +1 -0
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +356 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/onepassword-migration.d.ts +23 -0
- package/dist/commands/onepassword-migration.d.ts.map +1 -0
- package/dist/commands/onepassword-migration.js +179 -0
- package/dist/commands/onepassword-migration.js.map +1 -0
- package/dist/commands/protect.d.ts +34 -0
- package/dist/commands/protect.d.ts.map +1 -0
- package/dist/commands/protect.js +642 -0
- package/dist/commands/protect.js.map +1 -0
- package/dist/commands/runtime.d.ts +28 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +309 -0
- package/dist/commands/runtime.js.map +1 -0
- package/dist/commands/self-register.d.ts +39 -0
- package/dist/commands/self-register.d.ts.map +1 -0
- package/dist/commands/self-register.js +528 -0
- package/dist/commands/self-register.js.map +1 -0
- package/dist/commands/verify.d.ts +25 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +300 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/contextual/advisor.d.ts +12 -0
- package/dist/contextual/advisor.d.ts.map +1 -0
- package/dist/contextual/advisor.js +94 -0
- package/dist/contextual/advisor.js.map +1 -0
- package/dist/contextual/index.d.ts +3 -0
- package/dist/contextual/index.d.ts.map +1 -0
- package/dist/contextual/index.js +7 -0
- package/dist/contextual/index.js.map +1 -0
- package/dist/guided/attack-walkthrough.d.ts +13 -0
- package/dist/guided/attack-walkthrough.d.ts.map +1 -0
- package/dist/guided/attack-walkthrough.js +113 -0
- package/dist/guided/attack-walkthrough.js.map +1 -0
- package/dist/guided/wizard.d.ts +2 -0
- package/dist/guided/wizard.d.ts.map +1 -0
- package/dist/guided/wizard.js +108 -0
- package/dist/guided/wizard.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +326 -0
- package/dist/index.js.map +1 -0
- package/dist/natural/index.d.ts +4 -0
- package/dist/natural/index.d.ts.map +1 -0
- package/dist/natural/index.js +9 -0
- package/dist/natural/index.js.map +1 -0
- package/dist/natural/intent-map.d.ts +7 -0
- package/dist/natural/intent-map.d.ts.map +1 -0
- package/dist/natural/intent-map.js +145 -0
- package/dist/natural/intent-map.js.map +1 -0
- package/dist/natural/llm-fallback.d.ts +8 -0
- package/dist/natural/llm-fallback.d.ts.map +1 -0
- package/dist/natural/llm-fallback.js +143 -0
- package/dist/natural/llm-fallback.js.map +1 -0
- package/dist/report/interactive-html.d.ts +51 -0
- package/dist/report/interactive-html.d.ts.map +1 -0
- package/dist/report/interactive-html.js +508 -0
- package/dist/report/interactive-html.js.map +1 -0
- package/dist/router.d.ts +23 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +132 -0
- package/dist/router.js.map +1 -0
- package/dist/semantic/command-index.json +182 -0
- package/dist/semantic/index.d.ts +3 -0
- package/dist/semantic/index.d.ts.map +1 -0
- package/dist/semantic/index.js +28 -0
- package/dist/semantic/index.js.map +1 -0
- package/dist/semantic/search.d.ts +17 -0
- package/dist/semantic/search.d.ts.map +1 -0
- package/dist/semantic/search.js +123 -0
- package/dist/semantic/search.js.map +1 -0
- package/dist/util/action-prompt.d.ts +29 -0
- package/dist/util/action-prompt.d.ts.map +1 -0
- package/dist/util/action-prompt.js +126 -0
- package/dist/util/action-prompt.js.map +1 -0
- package/dist/util/advisories.d.ts +43 -0
- package/dist/util/advisories.d.ts.map +1 -0
- package/dist/util/advisories.js +229 -0
- package/dist/util/advisories.js.map +1 -0
- package/dist/util/colors.d.ts +9 -0
- package/dist/util/colors.d.ts.map +1 -0
- package/dist/util/colors.js +18 -0
- package/dist/util/colors.js.map +1 -0
- package/dist/util/credential-patterns.d.ts +38 -0
- package/dist/util/credential-patterns.d.ts.map +1 -0
- package/dist/util/credential-patterns.js +203 -0
- package/dist/util/credential-patterns.js.map +1 -0
- package/dist/util/detect.d.ts +11 -0
- package/dist/util/detect.d.ts.map +1 -0
- package/dist/util/detect.js +49 -0
- package/dist/util/detect.js.map +1 -0
- package/dist/util/format.d.ts +6 -0
- package/dist/util/format.d.ts.map +1 -0
- package/dist/util/format.js +49 -0
- package/dist/util/format.js.map +1 -0
- package/dist/util/report-submission.d.ts +64 -0
- package/dist/util/report-submission.d.ts.map +1 -0
- package/dist/util/report-submission.js +109 -0
- package/dist/util/report-submission.js.map +1 -0
- package/dist/util/spinner.d.ts +10 -0
- package/dist/util/spinner.d.ts.map +1 -0
- package/dist/util/spinner.js +38 -0
- package/dist/util/spinner.js.map +1 -0
- package/dist/util/version.d.ts +5 -0
- package/dist/util/version.d.ts.map +1 -0
- package/dist/util/version.js +24 -0
- package/dist/util/version.js.map +1 -0
- 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, '&')
|
|
79
|
+
.replace(/</g, '<')
|
|
80
|
+
.replace(/>/g, '>')
|
|
81
|
+
.replace(/"/g, '"')
|
|
82
|
+
.replace(/'/g, ''');
|
|
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">▶</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"}
|
package/dist/router.d.ts
ADDED
|
@@ -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
|