@highflame/overwatch 1.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.
Files changed (156) hide show
  1. package/README.md +337 -0
  2. package/bin/overwatch +12 -0
  3. package/dist/auth/cli-oauth.d.ts +13 -0
  4. package/dist/auth/cli-oauth.d.ts.map +1 -0
  5. package/dist/auth/html-utils.d.ts +20 -0
  6. package/dist/auth/html-utils.d.ts.map +1 -0
  7. package/dist/auth/index.d.ts +10 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/oauth.d.ts +81 -0
  10. package/dist/auth/oauth.d.ts.map +1 -0
  11. package/dist/auth/pkce.d.ts +26 -0
  12. package/dist/auth/pkce.d.ts.map +1 -0
  13. package/dist/auth/token-store.d.ts +44 -0
  14. package/dist/auth/token-store.d.ts.map +1 -0
  15. package/dist/bin/overwatch +12 -0
  16. package/dist/cli.d.ts +6 -0
  17. package/dist/cli.d.ts.map +1 -0
  18. package/dist/cli.js +5449 -0
  19. package/dist/cli.js.map +7 -0
  20. package/dist/config/index.d.ts +5 -0
  21. package/dist/config/index.d.ts.map +1 -0
  22. package/dist/config/manager.d.ts +54 -0
  23. package/dist/config/manager.d.ts.map +1 -0
  24. package/dist/daemon.d.ts +11 -0
  25. package/dist/daemon.d.ts.map +1 -0
  26. package/dist/daemon.js +6004 -0
  27. package/dist/daemon.js.map +7 -0
  28. package/dist/data/ingestor.d.ts +31 -0
  29. package/dist/data/ingestor.d.ts.map +1 -0
  30. package/dist/data/processor.d.ts +96 -0
  31. package/dist/data/processor.d.ts.map +1 -0
  32. package/dist/data/reader.d.ts +24 -0
  33. package/dist/data/reader.d.ts.map +1 -0
  34. package/dist/data/recorder.d.ts +12 -0
  35. package/dist/data/recorder.d.ts.map +1 -0
  36. package/dist/engines/cedar.d.ts +41 -0
  37. package/dist/engines/cedar.d.ts.map +1 -0
  38. package/dist/engines/remote.d.ts +21 -0
  39. package/dist/engines/remote.d.ts.map +1 -0
  40. package/dist/engines/yara.d.ts +12 -0
  41. package/dist/engines/yara.d.ts.map +1 -0
  42. package/dist/handlers/dashboard-handler.d.ts +7 -0
  43. package/dist/handlers/dashboard-handler.d.ts.map +1 -0
  44. package/dist/handlers/hook-handler.d.ts +23 -0
  45. package/dist/handlers/hook-handler.d.ts.map +1 -0
  46. package/dist/handlers/oauth-handler.d.ts +12 -0
  47. package/dist/handlers/oauth-handler.d.ts.map +1 -0
  48. package/dist/handlers/scan-handler.d.ts +13 -0
  49. package/dist/handlers/scan-handler.d.ts.map +1 -0
  50. package/dist/handlers/utils.d.ts +11 -0
  51. package/dist/handlers/utils.d.ts.map +1 -0
  52. package/dist/hooks/claudecode/hooks.json.template +20 -0
  53. package/dist/hooks/cursor/hooks.json.template +74 -0
  54. package/dist/hooks/universal-hook.sh +36 -0
  55. package/dist/http/server.d.ts +38 -0
  56. package/dist/http/server.d.ts.map +1 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +5941 -0
  60. package/dist/index.js.map +7 -0
  61. package/dist/installer.d.ts +25 -0
  62. package/dist/installer.d.ts.map +1 -0
  63. package/dist/javelin/admin-client.d.ts +75 -0
  64. package/dist/javelin/admin-client.d.ts.map +1 -0
  65. package/dist/javelin/client.d.ts +30 -0
  66. package/dist/javelin/client.d.ts.map +1 -0
  67. package/dist/javelin/config-reader.d.ts +70 -0
  68. package/dist/javelin/config-reader.d.ts.map +1 -0
  69. package/dist/javelin/index.d.ts +5 -0
  70. package/dist/javelin/index.d.ts.map +1 -0
  71. package/dist/javelin/types.d.ts +81 -0
  72. package/dist/javelin/types.d.ts.map +1 -0
  73. package/dist/lib/policy-engine.d.ts +34 -0
  74. package/dist/lib/policy-engine.d.ts.map +1 -0
  75. package/dist/lib/policy-manager.d.ts +86 -0
  76. package/dist/lib/policy-manager.d.ts.map +1 -0
  77. package/dist/module.d.ts +52 -0
  78. package/dist/module.d.ts.map +1 -0
  79. package/dist/pipeline/context-mapper.d.ts +16 -0
  80. package/dist/pipeline/context-mapper.d.ts.map +1 -0
  81. package/dist/pipeline/extractors/claude-extractor.d.ts +48 -0
  82. package/dist/pipeline/extractors/claude-extractor.d.ts.map +1 -0
  83. package/dist/pipeline/extractors/cursor-extractor.d.ts +44 -0
  84. package/dist/pipeline/extractors/cursor-extractor.d.ts.map +1 -0
  85. package/dist/pipeline/extractors/github-copilot-extractor.d.ts +49 -0
  86. package/dist/pipeline/extractors/github-copilot-extractor.d.ts.map +1 -0
  87. package/dist/pipeline/extractors/index.d.ts +47 -0
  88. package/dist/pipeline/extractors/index.d.ts.map +1 -0
  89. package/dist/pipeline/extractors/registry.d.ts +38 -0
  90. package/dist/pipeline/extractors/registry.d.ts.map +1 -0
  91. package/dist/pipeline/hook-pipeline.d.ts +25 -0
  92. package/dist/pipeline/hook-pipeline.d.ts.map +1 -0
  93. package/dist/policy.cedar +783 -0
  94. package/dist/rules/pre/command_injection.yar +60 -0
  95. package/dist/rules/pre/cross_origin_escalation.yar +106 -0
  96. package/dist/rules/pre/mcp_config_risk.yar +35 -0
  97. package/dist/rules/pre/path_traversal.yar +50 -0
  98. package/dist/rules/pre/prompt_injection.yar +101 -0
  99. package/dist/rules/pre/secrets_leakage.yar +100 -0
  100. package/dist/rules/pre/sql_injection.yar +65 -0
  101. package/dist/scanner.d.ts +80 -0
  102. package/dist/scanner.d.ts.map +1 -0
  103. package/dist/service.d.ts +18 -0
  104. package/dist/service.d.ts.map +1 -0
  105. package/dist/services/interface.d.ts +11 -0
  106. package/dist/services/interface.d.ts.map +1 -0
  107. package/dist/services/launchd.d.ts +12 -0
  108. package/dist/services/launchd.d.ts.map +1 -0
  109. package/dist/services/systemd.d.ts +12 -0
  110. package/dist/services/systemd.d.ts.map +1 -0
  111. package/dist/services/windows.d.ts +7 -0
  112. package/dist/services/windows.d.ts.map +1 -0
  113. package/dist/skills/index.d.ts +7 -0
  114. package/dist/skills/index.d.ts.map +1 -0
  115. package/dist/skills/scanner.d.ts +44 -0
  116. package/dist/skills/scanner.d.ts.map +1 -0
  117. package/dist/skills/types.d.ts +29 -0
  118. package/dist/skills/types.d.ts.map +1 -0
  119. package/dist/types/config.d.ts +165 -0
  120. package/dist/types/config.d.ts.map +1 -0
  121. package/dist/types/events.d.ts +225 -0
  122. package/dist/types/events.d.ts.map +1 -0
  123. package/dist/types/index.d.ts +6 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/remote-policy.d.ts +129 -0
  126. package/dist/types/remote-policy.d.ts.map +1 -0
  127. package/dist/types/requests.d.ts +45 -0
  128. package/dist/types/requests.d.ts.map +1 -0
  129. package/dist/types/responses.d.ts +60 -0
  130. package/dist/types/responses.d.ts.map +1 -0
  131. package/dist/ui/images/highflame-mono.png +0 -0
  132. package/dist/ui/views/dashboard.ejs +301 -0
  133. package/dist/ui/views/dashboard.js +785 -0
  134. package/dist/ui/views/partials/commands-table.ejs +54 -0
  135. package/dist/ui/views/partials/events-table.ejs +36 -0
  136. package/dist/ui/views/partials/filter-dropdown.ejs +12 -0
  137. package/dist/ui/views/partials/overview-charts.ejs +149 -0
  138. package/dist/ui/views/partials/scans-table.ejs +136 -0
  139. package/dist/ui/views/partials/sessions-table.ejs +50 -0
  140. package/dist/ui/views/partials/stats-grid.ejs +23 -0
  141. package/dist/ui/views/partials/threats-table.ejs +60 -0
  142. package/dist/utils/index.d.ts +3 -0
  143. package/dist/utils/index.d.ts.map +1 -0
  144. package/dist/utils/logger.d.ts +28 -0
  145. package/dist/utils/logger.d.ts.map +1 -0
  146. package/dist/utils/performance.d.ts +26 -0
  147. package/dist/utils/performance.d.ts.map +1 -0
  148. package/dist/utils/port-manager.d.ts +6 -0
  149. package/dist/utils/port-manager.d.ts.map +1 -0
  150. package/dist/yara/engine.d.ts +58 -0
  151. package/dist/yara/engine.d.ts.map +1 -0
  152. package/dist/yara/index.d.ts +5 -0
  153. package/dist/yara/index.d.ts.map +1 -0
  154. package/lib/platform-loader.js +210 -0
  155. package/package.json +63 -0
  156. package/scripts/postinstall.js +121 -0
@@ -0,0 +1,54 @@
1
+ <%# Commands Table - Tool/shell execution log %>
2
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden">
3
+ <table id="command-table" class="w-full text-left">
4
+ <thead class="bg-zinc-50 dark:bg-zinc-950 text-[11px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-wider border-b border-zinc-200 dark:border-zinc-800">
5
+ <tr>
6
+ <th class="px-6 py-4">Timestamp</th>
7
+ <th class="px-6 py-4">Source</th>
8
+ <th class="px-6 py-4">Risk</th>
9
+ <th class="px-6 py-4">Command / Tool</th>
10
+ <th class="px-6 py-4">Resolution</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody class="divide-y divide-zinc-200/50 dark:divide-zinc-800/50">
14
+ <% commands.forEach((cmd, idx) => { %>
15
+ <%
16
+ const risk = (cmd.risk || '').toLowerCase();
17
+ const riskColor = risk === 'critical' ? 'text-red-500' :
18
+ risk === 'high' ? 'text-red-400' :
19
+ risk === 'medium' ? 'text-orange-400' :
20
+ 'text-green-500';
21
+ const dotColor = (risk === 'critical' || risk === 'high') ? 'bg-red-500' :
22
+ risk === 'medium' ? 'bg-orange-500' : 'bg-green-500';
23
+ %>
24
+ <tr data-event-type="commands"
25
+ data-event-index="<%= idx %>"
26
+ data-source="<%= cmd.source %>"
27
+ class="hover:bg-zinc-100/50 dark:hover:bg-zinc-900/30 transition-colors cursor-pointer event-row">
28
+ <td class="px-6 py-4 text-[11px] text-zinc-600 dark:text-zinc-500"><%= new Date(cmd.timestamp).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) %></td>
29
+ <td class="px-6 py-4 text-[10px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-widest"><%= cmd.source %></td>
30
+ <td class="px-6 py-4">
31
+ <div class="flex items-center gap-1.5">
32
+ <div class="w-1.5 h-1.5 rounded-full <%= dotColor %>"></div>
33
+ <span class="text-[10px] font-bold uppercase tracking-wider <%= riskColor %>"><%= cmd.risk %></span>
34
+ </div>
35
+ </td>
36
+ <td class="px-6 py-4">
37
+ <code class="text-xs font-mono text-zinc-700 dark:text-zinc-300 bg-zinc-50 dark:bg-zinc-950 px-2 py-1 rounded border border-zinc-200 dark:border-zinc-800/50 break-all">
38
+ <%= cmd.command %>
39
+ </code>
40
+ </td>
41
+ <td class="px-6 py-4">
42
+ <p class="text-xs font-medium text-zinc-900 dark:text-zinc-200"><%= cmd.allowed ? 'Allowed' : 'Blocked' %></p>
43
+ <p class="text-[10px] text-zinc-600 dark:text-zinc-500 mt-0.5 italic"><%= cmd.reason %></p>
44
+ </td>
45
+ </tr>
46
+ <% }); %>
47
+ <% if (commands.length === 0) { %>
48
+ <tr>
49
+ <td colspan="5" class="px-6 py-12 text-center text-zinc-500 dark:text-zinc-600 text-sm italic">No tool/shell executions recorded</td>
50
+ </tr>
51
+ <% } %>
52
+ </tbody>
53
+ </table>
54
+ </div>
@@ -0,0 +1,36 @@
1
+ <%# Events Table - All event log %>
2
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden">
3
+ <table id="event-table" class="w-full text-left">
4
+ <thead class="bg-zinc-50 dark:bg-zinc-950 text-[11px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-wider border-b border-zinc-200 dark:border-zinc-800">
5
+ <tr>
6
+ <th class="px-6 py-4">Timestamp</th>
7
+ <th class="px-6 py-4">Source</th>
8
+ <th class="px-6 py-4">Event Type</th>
9
+ <th class="px-6 py-4">Details</th>
10
+ <th class="px-6 py-4">Outcome</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody class="divide-y divide-zinc-200/50 dark:divide-zinc-800/50">
14
+ <% events.forEach((event, idx) => { %>
15
+ <tr data-event-type="events"
16
+ data-event-index="<%= idx %>"
17
+ data-source="<%= event.source %>"
18
+ class="hover:bg-zinc-100/50 dark:hover:bg-zinc-900/30 transition-colors cursor-pointer event-row">
19
+ <td class="px-6 py-4 text-[10px] text-zinc-600 dark:text-zinc-500 tabular-nums"><%= new Date(event.timestamp).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) %></td>
20
+ <td class="px-6 py-4 text-[10px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-widest"><%= event.source %></td>
21
+ <td class="px-6 py-4 text-xs font-mono text-zinc-700 dark:text-zinc-300"><%= event.event %></td>
22
+ <td class="px-6 py-4">
23
+ <p class="text-xs text-zinc-600 dark:text-zinc-400 truncate max-w-md">
24
+ <%= event.input.prompt || event.input.command || event.input.tool_name || 'N/A' %>
25
+ </p>
26
+ </td>
27
+ <td class="px-6 py-4">
28
+ <span class="text-[10px] font-bold px-2 py-0.5 rounded uppercase tracking-wider <%= event.allowed ? 'bg-green-500/10 text-green-500' : 'bg-red-500/10 text-red-500' %>">
29
+ <%= event.allowed ? 'ALLOW' : 'DENY' %>
30
+ </span>
31
+ </td>
32
+ </tr>
33
+ <% }); %>
34
+ </tbody>
35
+ </table>
36
+ </div>
@@ -0,0 +1,12 @@
1
+ <%# Filter Dropdown - IDE source filter for tables %>
2
+ <div class="flex justify-end mb-4">
3
+ <select
4
+ onchange="Dashboard.filterTable('<%= tableId %>', this.value)"
5
+ class="bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 text-xs rounded px-2 py-1 outline-none focus:ring-1 focus:ring-zinc-300 dark:focus:ring-zinc-700 text-zinc-900 dark:text-zinc-300"
6
+ >
7
+ <option value="">All IDEs</option>
8
+ <option value="cursor">Cursor</option>
9
+ <option value="claudecode">Claude Code</option>
10
+ <option value="github_copilot">GitHub Copilot</option>
11
+ </select>
12
+ </div>
@@ -0,0 +1,149 @@
1
+ <%# Overview Charts - Activity graph, hook stats, tool usage, environment status %>
2
+
3
+ <!-- Graph Row -->
4
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
5
+ <!-- Activity Graph -->
6
+ <div class="lg:col-span-2 bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6">
7
+ <div class="flex items-center justify-between mb-6">
8
+ <h3 class="text-sm font-semibold text-zinc-900 dark:text-white">Activity Graph</h3>
9
+ <div class="flex items-center gap-4 text-[10px] font-bold uppercase tracking-wider text-zinc-700 dark:text-zinc-300">
10
+ <div class="flex items-center gap-1.5"><span class="w-2 h-2 rounded-full bg-blue-500"></span> Cursor</div>
11
+ <div class="flex items-center gap-1.5"><span class="w-2 h-2 rounded-full bg-zinc-900 dark:bg-white"></span> Claude</div>
12
+ <div class="flex items-center gap-1.5"><span class="w-2 h-2 rounded-full bg-violet-500"></span> GitHub Copilot</div>
13
+ </div>
14
+ </div>
15
+ <div class="h-[240px] w-full">
16
+ <canvas id="activityChart"></canvas>
17
+ </div>
18
+ </div>
19
+
20
+ <!-- Top Cursor Hooks -->
21
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6">
22
+ <h3 class="text-sm font-semibold mb-6 text-zinc-900 dark:text-white">Top Cursor Hook Events</h3>
23
+ <div class="space-y-4">
24
+ <% topCursorHooks.forEach((hook, i) => { %>
25
+ <div class="space-y-1.5">
26
+ <div class="flex justify-between text-[11px] font-medium">
27
+ <span class="text-zinc-600 dark:text-zinc-400 font-mono"><%= hook.event %></span>
28
+ <span class="text-zinc-900 dark:text-zinc-100"><%= hook.count %></span>
29
+ </div>
30
+ <div class="h-1 w-full bg-zinc-200 dark:bg-zinc-800 rounded-full overflow-hidden">
31
+ <div class="h-full bg-blue-600 rounded-full" style="width: <%= (hook.count / topCursorHooks[0].count) * 100 %>%"></div>
32
+ </div>
33
+ </div>
34
+ <% }); %>
35
+ <% if (topCursorHooks.length === 0) { %>
36
+ <p class="text-xs text-zinc-500 dark:text-zinc-600 text-center py-8">No data available</p>
37
+ <% } %>
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ <!-- Second Row -->
43
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
44
+ <!-- Claude Tool Usage -->
45
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6">
46
+ <h3 class="text-sm font-semibold mb-6 text-zinc-900 dark:text-white">Claude Tool Usage</h3>
47
+ <div class="space-y-4">
48
+ <% topClaudeTools.forEach(tool => { %>
49
+ <% const maxCount = Math.max(...topClaudeTools.map(t => t.count), 1); %>
50
+ <div class="space-y-1.5">
51
+ <div class="flex justify-between text-[11px] font-medium">
52
+ <span class="text-zinc-600 dark:text-zinc-400 font-mono"><%= tool.tool %></span>
53
+ <span class="text-zinc-900 dark:text-zinc-100"><%= tool.count %></span>
54
+ </div>
55
+ <div class="h-1 w-full bg-zinc-200 dark:bg-zinc-800 rounded-full overflow-hidden">
56
+ <div class="h-full bg-zinc-400 dark:bg-zinc-300 rounded-full" style="width: <%= (tool.count / maxCount) * 100 %>%"></div>
57
+ </div>
58
+ </div>
59
+ <% }); %>
60
+ <% if (topClaudeTools.length === 0) { %>
61
+ <p class="text-xs text-zinc-500 dark:text-zinc-600 text-center py-8">No tool activity</p>
62
+ <% } %>
63
+ </div>
64
+ </div>
65
+
66
+ <!-- Top GitHub Copilot Hooks -->
67
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6">
68
+ <h3 class="text-sm font-semibold mb-6 text-zinc-900 dark:text-white">Top GitHub Copilot Hook Events</h3>
69
+ <div class="space-y-4">
70
+ <% topGitHubCopilotHooks.forEach((hook, i) => { %>
71
+ <div class="space-y-1.5">
72
+ <div class="flex justify-between text-[11px] font-medium">
73
+ <span class="text-zinc-600 dark:text-zinc-400 font-mono"><%= hook.event %></span>
74
+ <span class="text-zinc-900 dark:text-zinc-100"><%= hook.count %></span>
75
+ </div>
76
+ <div class="h-1 w-full bg-zinc-200 dark:bg-zinc-800 rounded-full overflow-hidden">
77
+ <div class="h-full bg-violet-600 rounded-full" style="width: <%= (hook.count / topGitHubCopilotHooks[0].count) * 100 %>%"></div>
78
+ </div>
79
+ </div>
80
+ <% }); %>
81
+ <% if (topGitHubCopilotHooks.length === 0) { %>
82
+ <p class="text-xs text-zinc-500 dark:text-zinc-600 text-center py-8">No data available</p>
83
+ <% } %>
84
+ </div>
85
+ </div>
86
+
87
+ <!-- Environment Status -->
88
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6">
89
+ <h3 class="text-sm font-semibold mb-6 text-zinc-900 dark:text-white">Environment Status</h3>
90
+ <div class="space-y-4">
91
+ <!-- Cursor -->
92
+ <div class="flex items-center justify-between p-4 rounded-xl bg-transparent dark:bg-zinc-900/60 border border-zinc-200 dark:border-zinc-800">
93
+ <div class="flex items-center gap-4">
94
+ <div class="w-10 h-10 rounded-lg bg-zinc-200 dark:bg-zinc-800 flex items-center justify-center p-2">
95
+ <svg viewBox="0 0 24 24" fill="currentColor" class="text-zinc-900 dark:text-white"><path d="M12 0l-12 12h12v12l12-12h-12v-12z"/></svg>
96
+ </div>
97
+ <div>
98
+ <p class="text-sm font-bold text-zinc-900 dark:text-white">Cursor</p>
99
+ <p class="text-[10px] text-zinc-600 dark:text-zinc-500 font-medium tracking-wide">AI CODE EDITOR</p>
100
+ </div>
101
+ </div>
102
+ <div class="text-right">
103
+ <span class="<%= installation.cursor.installed ? 'text-green-500' : 'text-zinc-600 dark:text-zinc-600' %> text-[10px] font-bold uppercase tracking-widest">
104
+ <%= installation.cursor.installed ? 'Online' : 'Not Detected' %>
105
+ </span>
106
+ <p class="text-[10px] text-zinc-500 dark:text-zinc-500 mt-0.5"><%= installation.cursor.version || 'Version unknown' %></p>
107
+ </div>
108
+ </div>
109
+
110
+ <!-- Claude Code -->
111
+ <div class="flex items-center justify-between p-4 rounded-xl bg-transparent dark:bg-zinc-900/60 border border-zinc-200 dark:border-zinc-800">
112
+ <div class="flex items-center gap-4">
113
+ <div class="w-10 h-10 rounded-lg bg-zinc-200 dark:bg-zinc-800 flex items-center justify-center p-2">
114
+ <svg viewBox="0 0 24 24" fill="currentColor" class="text-zinc-900 dark:text-white"><path d="M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71L12 2z"/></svg>
115
+ </div>
116
+ <div>
117
+ <p class="text-sm font-bold text-zinc-900 dark:text-white">Claude Code</p>
118
+ <p class="text-[10px] text-zinc-600 dark:text-zinc-500 font-medium tracking-wide">CLI AGENT</p>
119
+ </div>
120
+ </div>
121
+ <div class="text-right">
122
+ <span class="<%= installation.claudecode.installed ? 'text-green-500' : 'text-zinc-600 dark:text-zinc-600' %> text-[10px] font-bold uppercase tracking-widest">
123
+ <%= installation.claudecode.installed ? 'Online' : 'Not Detected' %>
124
+ </span>
125
+ <p class="text-[10px] text-zinc-500 dark:text-zinc-500 mt-0.5">CLI Mode</p>
126
+ </div>
127
+ </div>
128
+
129
+ <!-- GitHub Copilot -->
130
+ <div class="flex items-center justify-between p-4 rounded-xl bg-transparent dark:bg-zinc-900/60 border border-zinc-200 dark:border-zinc-800">
131
+ <div class="flex items-center gap-4">
132
+ <div class="w-10 h-10 rounded-lg bg-violet-100 dark:bg-violet-900/30 flex items-center justify-center p-2">
133
+ <svg viewBox="0 0 24 24" fill="currentColor" class="text-violet-600 dark:text-violet-400"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
134
+ </div>
135
+ <div>
136
+ <p class="text-sm font-bold text-zinc-900 dark:text-white">GitHub Copilot</p>
137
+ <p class="text-[10px] text-zinc-600 dark:text-zinc-500 font-medium tracking-wide">CLI AGENT</p>
138
+ </div>
139
+ </div>
140
+ <div class="text-right">
141
+ <span class="<%= installation.github_copilot.installed ? 'text-green-500' : 'text-zinc-600 dark:text-zinc-600' %> text-[10px] font-bold uppercase tracking-widest">
142
+ <%= installation.github_copilot.installed ? 'Online' : 'Not Detected' %>
143
+ </span>
144
+ <p class="text-[10px] text-zinc-500 dark:text-zinc-500 mt-0.5">0.36.2</p>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
@@ -0,0 +1,136 @@
1
+ <%# MCP Scans Table - Display scan results with servers and threats %>
2
+ <div class="space-y-4">
3
+ <% scans.forEach((scan, scanIdx) => { %>
4
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden">
5
+ <!-- Scan Header -->
6
+ <div class="bg-zinc-50/50 dark:bg-zinc-950/50 border-b border-zinc-200 dark:border-zinc-800 px-6 py-4">
7
+ <div class="flex items-center justify-between">
8
+ <div class="flex items-center gap-4">
9
+ <div>
10
+ <h3 class="text-sm font-bold text-zinc-900 dark:text-zinc-200">Scan #<%= scanIdx + 1 %></h3>
11
+ <p class="text-xs text-zinc-600 dark:text-zinc-500 font-mono mt-0.5"><%= new Date(scan.timestamp).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) %></p>
12
+ </div>
13
+ <div class="h-4 w-[1px] bg-zinc-300 dark:bg-zinc-800"></div>
14
+ <div class="flex items-center gap-3">
15
+ <div class="text-xs">
16
+ <span class="text-zinc-600 dark:text-zinc-500">Servers:</span>
17
+ <span class="font-bold text-zinc-700 dark:text-zinc-300 ml-1"><%= scan.total_servers %></span>
18
+ </div>
19
+ <div class="h-3 w-[1px] bg-zinc-300 dark:bg-zinc-800"></div>
20
+ <div class="text-xs">
21
+ <span class="text-zinc-600 dark:text-zinc-500">Issues:</span>
22
+ <span class="font-bold <%= scan.total_issues > 0 ? 'text-red-500' : 'text-green-500' %> ml-1"><%= scan.total_issues %></span>
23
+ </div>
24
+ <% if (scan.max_severity) { %>
25
+ <div class="h-3 w-[1px] bg-zinc-300 dark:bg-zinc-800"></div>
26
+ <div class="text-xs">
27
+ <span class="text-zinc-600 dark:text-zinc-500">Max Severity:</span>
28
+ <%
29
+ const sev = scan.max_severity.toLowerCase();
30
+ const sevColor = sev === 'critical' ? 'text-red-500' :
31
+ sev === 'high' ? 'text-red-400' :
32
+ sev === 'medium' ? 'text-orange-500' :
33
+ 'text-yellow-500';
34
+ %>
35
+ <span class="font-bold <%= sevColor %> uppercase ml-1"><%= scan.max_severity %></span>
36
+ </div>
37
+ <% } %>
38
+ </div>
39
+ </div>
40
+ <div class="text-xs text-zinc-600 dark:text-zinc-500 font-mono uppercase tracking-widest">
41
+ <%= scan.source %>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <!-- Servers List -->
47
+ <div class="divide-y divide-zinc-200/50 dark:divide-zinc-800/50">
48
+ <% scan.servers.forEach((server, serverIdx) => { %>
49
+ <div class="px-6 py-4 hover:bg-zinc-100/50 dark:hover:bg-zinc-900/30 transition-colors">
50
+ <div class="flex items-start justify-between mb-2">
51
+ <div class="flex-1">
52
+ <h4 class="text-sm font-bold text-zinc-900 dark:text-zinc-200 flex items-center gap-2">
53
+ <svg class="w-4 h-4 text-zinc-600 dark:text-zinc-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
54
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
55
+ </svg>
56
+ <%= server.server_name %>
57
+ </h4>
58
+ <% if (server.url) { %>
59
+ <p class="text-xs text-zinc-600 dark:text-zinc-500 font-mono mt-1 truncate max-w-md"><%= server.url %></p>
60
+ <% } %>
61
+ </div>
62
+ <div class="text-xs">
63
+ <% if (server.issues.length === 0) { %>
64
+ <span class="px-2 py-1 rounded bg-green-500/20 text-green-500 font-bold uppercase tracking-widest">Clean</span>
65
+ <% } else { %>
66
+ <span class="px-2 py-1 rounded bg-red-500/20 text-red-500 font-bold uppercase tracking-widest">
67
+ <%= server.issues.length %> <%= server.issues.length === 1 ? 'Issue' : 'Issues' %>
68
+ </span>
69
+ <% } %>
70
+ </div>
71
+ </div>
72
+
73
+ <!-- Server Issues -->
74
+ <% if (server.issues.length > 0) { %>
75
+ <div class="mt-3 space-y-2">
76
+ <% server.issues.forEach((issue, issueIdx) => { %>
77
+ <div class="bg-zinc-50 dark:bg-zinc-950/50 border border-zinc-200 dark:border-zinc-800/50 rounded-lg p-3">
78
+ <div class="flex items-start justify-between gap-3">
79
+ <div class="flex-1">
80
+ <div class="flex items-center gap-2 mb-1">
81
+ <%
82
+ const sev = issue.severity.toLowerCase();
83
+ const sevBg = sev === 'critical' ? 'bg-red-500 text-white' :
84
+ sev === 'high' ? 'bg-red-500/20 text-red-500' :
85
+ sev === 'medium' ? 'bg-orange-500/20 text-orange-500' :
86
+ 'bg-yellow-500/20 text-yellow-500';
87
+ %>
88
+ <span class="text-[10px] font-bold px-2 py-0.5 rounded uppercase tracking-widest <%= sevBg %>">
89
+ <%= issue.severity %>
90
+ </span>
91
+ <% if (issue.target_type) { %>
92
+ <span class="text-[10px] text-zinc-600 dark:text-zinc-500 font-mono uppercase">
93
+ <%= issue.target_type %>
94
+ </span>
95
+ <% } %>
96
+ <% if (issue.status) { %>
97
+ <span class="text-[10px] text-zinc-600 dark:text-zinc-500 font-mono">
98
+ Status: <%= issue.status %>
99
+ </span>
100
+ <% } %>
101
+ </div>
102
+ <% if (issue.rule_name) { %>
103
+ <p class="text-xs font-bold text-zinc-700 dark:text-zinc-300 font-mono mb-1"><%= issue.rule_name %></p>
104
+ <% } %>
105
+ <% if (issue.description) { %>
106
+ <p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed"><%= issue.description %></p>
107
+ <% } %>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ <% }); %>
112
+ </div>
113
+ <% } %>
114
+ </div>
115
+ <% }); %>
116
+
117
+ <% if (scan.servers.length === 0) { %>
118
+ <div class="px-6 py-8 text-center text-zinc-500 dark:text-zinc-600 text-sm italic">
119
+ No servers found in this scan
120
+ </div>
121
+ <% } %>
122
+ </div>
123
+ </div>
124
+ <% }); %>
125
+
126
+ <% if (scans.length === 0) { %>
127
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl p-12 text-center">
128
+ <svg class="w-12 h-12 text-zinc-400 dark:text-zinc-700 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
129
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
130
+ </svg>
131
+ <p class="text-zinc-600 dark:text-zinc-500 text-sm mb-2">No MCP scans recorded yet</p>
132
+ <p class="text-zinc-500 dark:text-zinc-600 text-xs">Run a scan using: <code class="bg-zinc-100 dark:bg-zinc-950 px-2 py-1 rounded text-zinc-700 dark:text-zinc-400">overwatch scan</code></p>
133
+ </div>
134
+ <% } %>
135
+ </div>
136
+
@@ -0,0 +1,50 @@
1
+ <%# Sessions Table - List of all sessions %>
2
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden">
3
+ <table id="session-table" class="w-full text-left">
4
+ <thead class="bg-zinc-50 dark:bg-zinc-950 text-[11px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-wider border-b border-zinc-200 dark:border-zinc-800">
5
+ <tr>
6
+ <th class="px-6 py-4">Session ID</th>
7
+ <th class="px-6 py-4">IDE</th>
8
+ <th class="px-6 py-4">Started</th>
9
+ <th class="px-6 py-4">Events</th>
10
+ <th class="px-6 py-4">Threats</th>
11
+ <th class="px-6 py-4">Result</th>
12
+ </tr>
13
+ </thead>
14
+ <tbody class="divide-y divide-zinc-200/50 dark:divide-zinc-800/50">
15
+ <% sessions.forEach(session => { %>
16
+ <tr data-session-id="<%= session.id %>"
17
+ data-source="<%= session.source %>"
18
+ class="hover:bg-zinc-100/50 dark:hover:bg-zinc-900/30 transition-colors cursor-pointer group session-row">
19
+ <td class="px-6 py-4">
20
+ <span class="text-xs font-mono text-zinc-700 dark:text-zinc-300 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors underline-offset-4 group-hover:underline">
21
+ <%= session.id.includes('::') ? session.id.split('::')[0] : session.id %>
22
+ </span>
23
+ </td>
24
+ <td class="px-6 py-4">
25
+ <span class="text-[10px] font-bold px-2 py-1 rounded bg-zinc-200 dark:bg-zinc-800 uppercase tracking-widest text-zinc-700 dark:text-zinc-300">
26
+ <%= session.source %>
27
+ </span>
28
+ </td>
29
+ <td class="px-6 py-4 text-xs text-zinc-600 dark:text-zinc-400"><%= new Date(session.startTime).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) %></td>
30
+ <td class="px-6 py-4 text-xs font-medium text-zinc-900 dark:text-white"><%= session.eventCount %></td>
31
+ <td class="px-6 py-4">
32
+ <span class="text-xs font-bold <%= session.threatCount > 0 ? 'text-orange-500' : 'text-zinc-500 dark:text-zinc-600' %>">
33
+ <%= session.threatCount %>
34
+ </span>
35
+ </td>
36
+ <td class="px-6 py-4">
37
+ <span class="text-[10px] font-bold px-2 py-0.5 rounded uppercase tracking-wider <%= session.allowed ? 'bg-green-500/10 text-green-500' : 'bg-red-500/10 text-red-500' %>">
38
+ <%= session.allowed ? 'ALLOWED' : 'BLOCKED' %>
39
+ </span>
40
+ </td>
41
+ </tr>
42
+ <% }); %>
43
+ <% if (sessions.length === 0) { %>
44
+ <tr>
45
+ <td colspan="6" class="px-6 py-12 text-center text-zinc-500 dark:text-zinc-600 text-sm italic">No active sessions</td>
46
+ </tr>
47
+ <% } %>
48
+ </tbody>
49
+ </table>
50
+ </div>
@@ -0,0 +1,23 @@
1
+ <%# Stats Grid - Overview statistics cards %>
2
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
3
+ <div class="bg-transparent dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 p-5 rounded-xl">
4
+ <p class="text-xs font-medium text-zinc-600 dark:text-zinc-500 mb-1">Total Events</p>
5
+ <h3 class="text-2xl font-bold tabular-nums text-zinc-900 dark:text-white"><%= stats.totalEvents %></h3>
6
+ </div>
7
+ <div class="bg-transparent dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 p-5 rounded-xl">
8
+ <p class="text-xs font-medium text-zinc-600 dark:text-zinc-500 mb-1">Active Sessions</p>
9
+ <h3 class="text-2xl font-bold tabular-nums text-zinc-900 dark:text-white"><%= stats.activeSessions %></h3>
10
+ </div>
11
+ <div class="bg-transparent dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 p-5 rounded-xl">
12
+ <p class="text-xs font-medium text-zinc-600 dark:text-zinc-500 mb-1">Threats Logged</p>
13
+ <h3 class="text-2xl font-bold tabular-nums text-orange-500"><%= stats.totalThreats %></h3>
14
+ </div>
15
+ <div class="bg-transparent dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 p-5 rounded-xl">
16
+ <p class="text-xs font-medium text-zinc-600 dark:text-zinc-500 mb-1">Blocked Actions</p>
17
+ <h3 class="text-2xl font-bold tabular-nums text-red-500"><%= stats.blockedCalls %></h3>
18
+ </div>
19
+ <div class="bg-transparent dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 p-5 rounded-xl">
20
+ <p class="text-xs font-medium text-zinc-600 dark:text-zinc-500 mb-1">Scanned Servers</p>
21
+ <h3 class="text-2xl font-bold tabular-nums text-green-500"><%= stats.serversScanned %></h3>
22
+ </div>
23
+ </div>
@@ -0,0 +1,60 @@
1
+ <%# Threats Table - Security threat events %>
2
+ <div class="bg-transparent dark:bg-zinc-900/40 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden">
3
+ <table id="threat-table" class="w-full text-left">
4
+ <thead class="bg-zinc-50 dark:bg-zinc-950 text-[11px] font-bold text-zinc-600 dark:text-zinc-500 uppercase tracking-wider border-b border-zinc-200 dark:border-zinc-800">
5
+ <tr>
6
+ <th class="px-6 py-4">Timestamp</th>
7
+ <th class="px-6 py-4">Severity</th>
8
+ <th class="px-6 py-4">Rule / Engine</th>
9
+ <th class="px-6 py-4">Category</th>
10
+ <th class="px-6 py-4 w-1/3">Matched Content</th>
11
+ </tr>
12
+ </thead>
13
+ <tbody class="divide-y divide-zinc-200/50 dark:divide-zinc-800/50">
14
+ <%
15
+ // Sort threats by timestamp in descending order (most recent first)
16
+ const sortedThreats = threats.map((threat, idx) => ({ threat, originalIdx: idx }))
17
+ .sort((a, b) =>
18
+ new Date(b.threat.timestamp).getTime() - new Date(a.threat.timestamp).getTime()
19
+ );
20
+ %>
21
+ <% sortedThreats.forEach((item) => { %>
22
+ <%
23
+ const threat = item.threat;
24
+ const originalIdx = item.originalIdx;
25
+ const sev = (threat.severity || '').toLowerCase();
26
+ const sevColor = sev === 'critical' ? 'bg-red-500 text-white' :
27
+ sev === 'high' ? 'bg-red-500/20 text-red-500' :
28
+ sev === 'medium' ? 'bg-orange-500/20 text-orange-500' :
29
+ 'bg-zinc-200 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400';
30
+ %>
31
+ <tr data-event-type="threats"
32
+ data-event-index="<%= originalIdx %>"
33
+ data-source="<%= threat.source %>"
34
+ class="hover:bg-zinc-100/50 dark:hover:bg-zinc-900/30 transition-colors cursor-pointer event-row">
35
+ <td class="px-6 py-4 text-[11px] text-zinc-600 dark:text-zinc-500"><%= new Date(threat.timestamp).toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) %></td>
36
+ <td class="px-6 py-4">
37
+ <span class="text-[10px] font-bold px-2 py-0.5 rounded uppercase tracking-widest <%= sevColor %>">
38
+ <%= threat.severity %>
39
+ </span>
40
+ </td>
41
+ <td class="px-6 py-4">
42
+ <p class="text-xs font-bold text-zinc-900 dark:text-zinc-200"><%= threat.rule %></p>
43
+ <p class="text-[10px] text-zinc-600 dark:text-zinc-500 font-mono uppercase tracking-widest mt-0.5"><%= threat.source %></p>
44
+ </td>
45
+ <td class="px-6 py-4 text-xs text-zinc-600 dark:text-zinc-400 truncate max-w-[150px]"><%= threat.category %></td>
46
+ <td class="px-6 py-4">
47
+ <div class="p-2 rounded bg-zinc-50 dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800/50 font-mono text-[10px] text-zinc-700 dark:text-zinc-300 break-all whitespace-pre-wrap max-h-24 overflow-y-auto custom-scrollbar">
48
+ <%= threat.content || 'N/A' %>
49
+ </div>
50
+ </td>
51
+ </tr>
52
+ <% }); %>
53
+ <% if (threats.length === 0) { %>
54
+ <tr>
55
+ <td colspan="5" class="px-6 py-12 text-center text-zinc-500 dark:text-zinc-600 text-sm italic">No threats recorded</td>
56
+ </tr>
57
+ <% } %>
58
+ </tbody>
59
+ </table>
60
+ </div>
@@ -0,0 +1,3 @@
1
+ export * from "./logger";
2
+ export * from "./performance";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Log levels
3
+ */
4
+ export declare enum LogLevel {
5
+ DEBUG = 0,
6
+ INFO = 1,
7
+ WARN = 2,
8
+ ERROR = 3
9
+ }
10
+ /**
11
+ * Simple logger utility with file output
12
+ */
13
+ export declare class Logger {
14
+ private level;
15
+ private fileEnabled;
16
+ constructor(level?: LogLevel);
17
+ private ensureLogDir;
18
+ setLevel(level: LogLevel): void;
19
+ private getCallerFile;
20
+ private formatArgs;
21
+ private writeToFile;
22
+ debug(message: string, ...args: unknown[]): void;
23
+ info(message: string, ...args: unknown[]): void;
24
+ warn(message: string, ...args: unknown[]): void;
25
+ error(message: string, ...args: unknown[]): void;
26
+ }
27
+ export declare const logger: Logger;
28
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAKD;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,WAAW,CAAiB;gBAExB,KAAK,GAAE,QAAwB;IAK3C,OAAO,CAAC,YAAY;IAWpB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,WAAW;IAenB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAQhD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAQ/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAQ/C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAOjD;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Performance measurement utility
3
+ */
4
+ export declare class PerformanceMonitor {
5
+ private startTime;
6
+ constructor();
7
+ /**
8
+ * Measure execution time of async function
9
+ */
10
+ static measure<T>(fn: () => Promise<T>): Promise<{
11
+ result: T;
12
+ duration: number;
13
+ }>;
14
+ /**
15
+ * Measure execution time of sync function
16
+ */
17
+ static measureSync<T>(fn: () => T): {
18
+ result: T;
19
+ duration: number;
20
+ };
21
+ /**
22
+ * Get uptime in milliseconds
23
+ */
24
+ getUptime(): number;
25
+ }
26
+ //# sourceMappingURL=performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../src/utils/performance.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAAS;;IAM1B;;OAEG;WACU,OAAO,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC;QAAE,MAAM,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAO3C;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG;QAAE,MAAM,EAAE,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAOnE;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
@@ -0,0 +1,6 @@
1
+ export declare const GUARDIAN_PORTS: number[];
2
+ export declare class PortManager {
3
+ static isPortAvailable(port: number): Promise<boolean>;
4
+ static findAvailablePort(): Promise<number | null>;
5
+ }
6
+ //# sourceMappingURL=port-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port-manager.d.ts","sourceRoot":"","sources":["../../src/utils/port-manager.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,UAAsC,CAAC;AAElE,qBAAa,WAAW;WACT,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAW/C,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAQzD"}