bashbros 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/LICENSE +21 -0
- package/README.md +453 -0
- package/dist/audit-MCFNGOIM.js +11 -0
- package/dist/audit-MCFNGOIM.js.map +1 -0
- package/dist/chunk-43W3RVEL.js +2910 -0
- package/dist/chunk-43W3RVEL.js.map +1 -0
- package/dist/chunk-4R4GV5V2.js +213 -0
- package/dist/chunk-4R4GV5V2.js.map +1 -0
- package/dist/chunk-7OCVIDC7.js +12 -0
- package/dist/chunk-7OCVIDC7.js.map +1 -0
- package/dist/chunk-CSRPOGHY.js +354 -0
- package/dist/chunk-CSRPOGHY.js.map +1 -0
- package/dist/chunk-DEAF6PYM.js +212 -0
- package/dist/chunk-DEAF6PYM.js.map +1 -0
- package/dist/chunk-DLP2O6PN.js +273 -0
- package/dist/chunk-DLP2O6PN.js.map +1 -0
- package/dist/chunk-GD5VNHIN.js +519 -0
- package/dist/chunk-GD5VNHIN.js.map +1 -0
- package/dist/chunk-ID2O2QTI.js +269 -0
- package/dist/chunk-ID2O2QTI.js.map +1 -0
- package/dist/chunk-J37RHCFJ.js +357 -0
- package/dist/chunk-J37RHCFJ.js.map +1 -0
- package/dist/chunk-SB4JS3GU.js +456 -0
- package/dist/chunk-SB4JS3GU.js.map +1 -0
- package/dist/chunk-SG752FZC.js +200 -0
- package/dist/chunk-SG752FZC.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +2448 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-CZMIGNPF.js +13 -0
- package/dist/config-CZMIGNPF.js.map +1 -0
- package/dist/config-parser-XHE7BC7H.js +13 -0
- package/dist/config-parser-XHE7BC7H.js.map +1 -0
- package/dist/db-EHQDB5OL.js +11 -0
- package/dist/db-EHQDB5OL.js.map +1 -0
- package/dist/display-IN4NRJJS.js +18 -0
- package/dist/display-IN4NRJJS.js.map +1 -0
- package/dist/engine-PKLXW6OF.js +9 -0
- package/dist/engine-PKLXW6OF.js.map +1 -0
- package/dist/index.d.ts +1498 -0
- package/dist/index.js +552 -0
- package/dist/index.js.map +1 -0
- package/dist/moltbot-DXZFVK3X.js +11 -0
- package/dist/moltbot-DXZFVK3X.js.map +1 -0
- package/dist/ollama-HY35OHW4.js +9 -0
- package/dist/ollama-HY35OHW4.js.map +1 -0
- package/dist/risk-scorer-Y6KF2XCZ.js +9 -0
- package/dist/risk-scorer-Y6KF2XCZ.js.map +1 -0
- package/dist/static/index.html +410 -0
- package/package.json +68 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadConfig
|
|
4
|
+
} from "./chunk-SB4JS3GU.js";
|
|
5
|
+
|
|
6
|
+
// src/transparency/display.ts
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
var AGENT_DISPLAY_NAMES = {
|
|
9
|
+
"claude-code": "Claude Code",
|
|
10
|
+
"moltbot": "Moltbot",
|
|
11
|
+
"clawdbot": "Clawdbot (legacy)",
|
|
12
|
+
"aider": "Aider",
|
|
13
|
+
"gemini-cli": "Gemini CLI",
|
|
14
|
+
"opencode": "OpenCode",
|
|
15
|
+
"custom": "Custom Agent"
|
|
16
|
+
};
|
|
17
|
+
function formatAgentInfo(info) {
|
|
18
|
+
const lines = [];
|
|
19
|
+
const name = AGENT_DISPLAY_NAMES[info.agent] || info.agent;
|
|
20
|
+
lines.push(chalk.bold(`${name} (${info.agent})`));
|
|
21
|
+
const statusIcon = info.installed ? chalk.green("Installed") : chalk.dim("Not found");
|
|
22
|
+
lines.push(` Status: ${statusIcon}`);
|
|
23
|
+
if (info.version) {
|
|
24
|
+
lines.push(` Version: ${info.version}`);
|
|
25
|
+
}
|
|
26
|
+
if (info.configPath) {
|
|
27
|
+
const configStatus = info.configExists ? chalk.green(info.configPath) : chalk.yellow(`${info.configPath} (not found)`);
|
|
28
|
+
lines.push(` Config: ${configStatus}`);
|
|
29
|
+
} else {
|
|
30
|
+
lines.push(` Config: ${chalk.dim("No known config location")}`);
|
|
31
|
+
}
|
|
32
|
+
if (info.lastModified) {
|
|
33
|
+
lines.push(` Modified: ${info.lastModified.toLocaleDateString()} ${info.lastModified.toLocaleTimeString()}`);
|
|
34
|
+
}
|
|
35
|
+
if (info.hooks && info.hooks.length > 0) {
|
|
36
|
+
lines.push(` Hooks: ${info.hooks.join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
if (info.permissions) {
|
|
39
|
+
lines.push(` Permissions:`);
|
|
40
|
+
if (info.permissions.allowedPaths && info.permissions.allowedPaths.length > 0) {
|
|
41
|
+
const paths = info.permissions.allowedPaths.slice(0, 5).join(", ");
|
|
42
|
+
const more = info.permissions.allowedPaths.length > 5 ? ` (+${info.permissions.allowedPaths.length - 5} more)` : "";
|
|
43
|
+
lines.push(` Allowed paths: ${paths}${more}`);
|
|
44
|
+
}
|
|
45
|
+
if (info.permissions.blockedCommands && info.permissions.blockedCommands.length > 0) {
|
|
46
|
+
lines.push(` Blocked commands: ${info.permissions.blockedCommands.length} patterns`);
|
|
47
|
+
}
|
|
48
|
+
if (info.permissions.rateLimit) {
|
|
49
|
+
lines.push(` Rate limit: ${info.permissions.rateLimit}`);
|
|
50
|
+
}
|
|
51
|
+
if (info.permissions.securityProfile) {
|
|
52
|
+
lines.push(` Security profile: ${info.permissions.securityProfile}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const integrationStatus = info.bashbrosIntegrated ? chalk.green("Hooks installed") : chalk.yellow("Not integrated (no hooks)");
|
|
56
|
+
lines.push(` Bashbros: ${integrationStatus}`);
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
function formatAllAgentsInfo(agents) {
|
|
60
|
+
const lines = [
|
|
61
|
+
chalk.bold.cyan("AGENT CONFIGURATIONS"),
|
|
62
|
+
chalk.dim("=".repeat(40)),
|
|
63
|
+
""
|
|
64
|
+
];
|
|
65
|
+
const installed = agents.filter((a) => a.installed);
|
|
66
|
+
const notInstalled = agents.filter((a) => !a.installed);
|
|
67
|
+
if (installed.length === 0) {
|
|
68
|
+
lines.push(chalk.yellow("No agents detected."));
|
|
69
|
+
lines.push("");
|
|
70
|
+
} else {
|
|
71
|
+
for (const agent of installed) {
|
|
72
|
+
lines.push(formatAgentInfo(agent));
|
|
73
|
+
lines.push("");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (notInstalled.length > 0) {
|
|
77
|
+
lines.push(chalk.dim("Other known agents (not installed):"));
|
|
78
|
+
lines.push(chalk.dim(" " + notInstalled.map((a) => AGENT_DISPLAY_NAMES[a.agent]).join(", ")));
|
|
79
|
+
}
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
function getEffectivePermissions(agentInfo) {
|
|
83
|
+
const bashbrosConfig = loadConfig();
|
|
84
|
+
const bashbrosPaths = bashbrosConfig.paths.allow;
|
|
85
|
+
const bashbrosBlocked = bashbrosConfig.commands.block;
|
|
86
|
+
const bashbrosRiskThreshold = bashbrosConfig.riskScoring.blockThreshold;
|
|
87
|
+
const bashbrosRateLimit = bashbrosConfig.rateLimit.maxPerMinute;
|
|
88
|
+
const agentPaths = agentInfo.permissions?.allowedPaths || [];
|
|
89
|
+
const agentBlocked = agentInfo.permissions?.blockedCommands || [];
|
|
90
|
+
const agentRiskThreshold = typeof agentInfo.permissions?.rateLimit === "number" ? agentInfo.permissions.rateLimit : null;
|
|
91
|
+
const agentRateLimit = null;
|
|
92
|
+
let effectivePaths;
|
|
93
|
+
if (bashbrosPaths.length > 0 && agentPaths.length > 0) {
|
|
94
|
+
effectivePaths = bashbrosPaths.filter(
|
|
95
|
+
(bp) => agentPaths.some((ap) => ap === bp || bp.startsWith(ap) || ap.startsWith(bp))
|
|
96
|
+
);
|
|
97
|
+
if (effectivePaths.length === 0) {
|
|
98
|
+
effectivePaths = bashbrosPaths;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
effectivePaths = bashbrosPaths.length > 0 ? bashbrosPaths : agentPaths;
|
|
102
|
+
}
|
|
103
|
+
const effectiveBlocked = Array.from(/* @__PURE__ */ new Set([...bashbrosBlocked, ...agentBlocked]));
|
|
104
|
+
const effectiveRiskThreshold = agentRiskThreshold !== null ? Math.min(bashbrosRiskThreshold, agentRiskThreshold) : bashbrosRiskThreshold;
|
|
105
|
+
const effectiveRateLimit = agentRateLimit !== null ? Math.min(bashbrosRateLimit, agentRateLimit) : bashbrosRateLimit;
|
|
106
|
+
return {
|
|
107
|
+
allowedPaths: {
|
|
108
|
+
bashbros: bashbrosPaths,
|
|
109
|
+
agent: agentPaths,
|
|
110
|
+
effective: effectivePaths
|
|
111
|
+
},
|
|
112
|
+
riskThreshold: {
|
|
113
|
+
bashbros: bashbrosRiskThreshold,
|
|
114
|
+
agent: agentRiskThreshold,
|
|
115
|
+
effective: effectiveRiskThreshold
|
|
116
|
+
},
|
|
117
|
+
rateLimit: {
|
|
118
|
+
bashbros: bashbrosRateLimit,
|
|
119
|
+
agent: agentRateLimit,
|
|
120
|
+
effective: effectiveRateLimit
|
|
121
|
+
},
|
|
122
|
+
blockedCommands: {
|
|
123
|
+
bashbros: bashbrosBlocked,
|
|
124
|
+
agent: agentBlocked,
|
|
125
|
+
effective: effectiveBlocked
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function formatPermissionsTable(agents) {
|
|
130
|
+
const lines = [
|
|
131
|
+
chalk.bold.cyan("EFFECTIVE PERMISSIONS"),
|
|
132
|
+
chalk.dim("=".repeat(40)),
|
|
133
|
+
""
|
|
134
|
+
];
|
|
135
|
+
const config = loadConfig();
|
|
136
|
+
const installedAgents = agents.filter((a) => a.installed);
|
|
137
|
+
const agentHeaders = installedAgents.map((a) => AGENT_DISPLAY_NAMES[a.agent].padEnd(12));
|
|
138
|
+
lines.push(chalk.bold(" Bashbros " + agentHeaders.join(" ") + " Effective"));
|
|
139
|
+
lines.push(chalk.dim("-".repeat(80)));
|
|
140
|
+
const bashbrosPaths = config.paths.allow.slice(0, 3).join(", ") || "*";
|
|
141
|
+
lines.push(`Allowed paths: ${bashbrosPaths.padEnd(12)}`);
|
|
142
|
+
for (const agent of installedAgents) {
|
|
143
|
+
const perms = getEffectivePermissions(agent);
|
|
144
|
+
const agentPaths = perms.allowedPaths.agent.slice(0, 2).join(", ") || "none";
|
|
145
|
+
const effectivePaths = perms.allowedPaths.effective.slice(0, 2).join(", ") || "*";
|
|
146
|
+
lines[lines.length - 1] += `${agentPaths.padEnd(12)} `;
|
|
147
|
+
if (agent === installedAgents[installedAgents.length - 1]) {
|
|
148
|
+
lines[lines.length - 1] += effectivePaths;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const bashbrosRisk = config.riskScoring.blockThreshold;
|
|
152
|
+
let riskLine = `Risk threshold: ${bashbrosRisk.toString().padEnd(12)}`;
|
|
153
|
+
for (const agent of installedAgents) {
|
|
154
|
+
const perms = getEffectivePermissions(agent);
|
|
155
|
+
const agentRisk = perms.riskThreshold.agent !== null ? perms.riskThreshold.agent.toString() : "none";
|
|
156
|
+
riskLine += `${agentRisk.padEnd(12)} `;
|
|
157
|
+
if (agent === installedAgents[installedAgents.length - 1]) {
|
|
158
|
+
const effectiveRisk = perms.riskThreshold.effective;
|
|
159
|
+
const note = effectiveRisk < bashbrosRisk ? " (stricter)" : "";
|
|
160
|
+
riskLine += `${effectiveRisk}${note}`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
lines.push(riskLine);
|
|
164
|
+
const bashbrosRate = `${config.rateLimit.maxPerMinute}/min`;
|
|
165
|
+
let rateLine = `Rate limit: ${bashbrosRate.padEnd(12)}`;
|
|
166
|
+
for (const agent of installedAgents) {
|
|
167
|
+
const perms = getEffectivePermissions(agent);
|
|
168
|
+
const agentRate = perms.rateLimit.agent !== null ? `${perms.rateLimit.agent}/min` : "none";
|
|
169
|
+
rateLine += `${agentRate.padEnd(12)} `;
|
|
170
|
+
if (agent === installedAgents[installedAgents.length - 1]) {
|
|
171
|
+
rateLine += `${perms.rateLimit.effective}/min`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
lines.push(rateLine);
|
|
175
|
+
const bashbrosBlocked = config.commands.block.length;
|
|
176
|
+
let blockedLine = `Blocked commands: ${bashbrosBlocked.toString().padEnd(12)}`;
|
|
177
|
+
for (const agent of installedAgents) {
|
|
178
|
+
const perms = getEffectivePermissions(agent);
|
|
179
|
+
const agentBlocked = perms.blockedCommands.agent.length;
|
|
180
|
+
blockedLine += `${agentBlocked.toString().padEnd(12)} `;
|
|
181
|
+
if (agent === installedAgents[installedAgents.length - 1]) {
|
|
182
|
+
blockedLine += perms.blockedCommands.effective.length.toString();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
lines.push(blockedLine);
|
|
186
|
+
lines.push("");
|
|
187
|
+
lines.push(chalk.dim("Note: Effective = most restrictive combination of all policies"));
|
|
188
|
+
return lines.join("\n");
|
|
189
|
+
}
|
|
190
|
+
function formatAgentSummary(agents) {
|
|
191
|
+
const lines = [];
|
|
192
|
+
const installed = agents.filter((a) => a.installed);
|
|
193
|
+
if (installed.length === 0) {
|
|
194
|
+
lines.push(chalk.dim(" No agents detected"));
|
|
195
|
+
return lines.join("\n");
|
|
196
|
+
}
|
|
197
|
+
for (const agent of installed) {
|
|
198
|
+
const name = AGENT_DISPLAY_NAMES[agent.agent];
|
|
199
|
+
const config = agent.configExists ? chalk.green("configured") : chalk.yellow("no config");
|
|
200
|
+
const integration = agent.bashbrosIntegrated ? chalk.green("integrated") : chalk.dim("not integrated");
|
|
201
|
+
lines.push(` ${name}: ${config}, ${integration}`);
|
|
202
|
+
}
|
|
203
|
+
return lines.join("\n");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export {
|
|
207
|
+
formatAgentInfo,
|
|
208
|
+
formatAllAgentsInfo,
|
|
209
|
+
getEffectivePermissions,
|
|
210
|
+
formatPermissionsTable,
|
|
211
|
+
formatAgentSummary
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=chunk-4R4GV5V2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transparency/display.ts"],"sourcesContent":["/**\r\n * Display utilities for agent transparency\r\n * Formats agent info and permissions for CLI output\r\n */\r\n\r\nimport chalk from 'chalk'\r\nimport type { AgentConfigInfo, EffectivePermissions, AgentType } from '../types.js'\r\nimport { loadConfig } from '../config.js'\r\n\r\n// Human-readable agent names\r\nconst AGENT_DISPLAY_NAMES: Record<AgentType, string> = {\r\n 'claude-code': 'Claude Code',\r\n 'moltbot': 'Moltbot',\r\n 'clawdbot': 'Clawdbot (legacy)',\r\n 'aider': 'Aider',\r\n 'gemini-cli': 'Gemini CLI',\r\n 'opencode': 'OpenCode',\r\n 'custom': 'Custom Agent'\r\n}\r\n\r\n/**\r\n * Format a single agent's info for display\r\n */\r\nexport function formatAgentInfo(info: AgentConfigInfo): string {\r\n const lines: string[] = []\r\n const name = AGENT_DISPLAY_NAMES[info.agent] || info.agent\r\n\r\n lines.push(chalk.bold(`${name} (${info.agent})`))\r\n\r\n // Status\r\n const statusIcon = info.installed ? chalk.green('Installed') : chalk.dim('Not found')\r\n lines.push(` Status: ${statusIcon}`)\r\n\r\n if (info.version) {\r\n lines.push(` Version: ${info.version}`)\r\n }\r\n\r\n // Config\r\n if (info.configPath) {\r\n const configStatus = info.configExists ? chalk.green(info.configPath) : chalk.yellow(`${info.configPath} (not found)`)\r\n lines.push(` Config: ${configStatus}`)\r\n } else {\r\n lines.push(` Config: ${chalk.dim('No known config location')}`)\r\n }\r\n\r\n if (info.lastModified) {\r\n lines.push(` Modified: ${info.lastModified.toLocaleDateString()} ${info.lastModified.toLocaleTimeString()}`)\r\n }\r\n\r\n // Hooks\r\n if (info.hooks && info.hooks.length > 0) {\r\n lines.push(` Hooks: ${info.hooks.join(', ')}`)\r\n }\r\n\r\n // Permissions\r\n if (info.permissions) {\r\n lines.push(` Permissions:`)\r\n\r\n if (info.permissions.allowedPaths && info.permissions.allowedPaths.length > 0) {\r\n const paths = info.permissions.allowedPaths.slice(0, 5).join(', ')\r\n const more = info.permissions.allowedPaths.length > 5 ? ` (+${info.permissions.allowedPaths.length - 5} more)` : ''\r\n lines.push(` Allowed paths: ${paths}${more}`)\r\n }\r\n\r\n if (info.permissions.blockedCommands && info.permissions.blockedCommands.length > 0) {\r\n lines.push(` Blocked commands: ${info.permissions.blockedCommands.length} patterns`)\r\n }\r\n\r\n if (info.permissions.rateLimit) {\r\n lines.push(` Rate limit: ${info.permissions.rateLimit}`)\r\n }\r\n\r\n if (info.permissions.securityProfile) {\r\n lines.push(` Security profile: ${info.permissions.securityProfile}`)\r\n }\r\n }\r\n\r\n // BashBros integration\r\n const integrationStatus = info.bashbrosIntegrated\r\n ? chalk.green('Hooks installed')\r\n : chalk.yellow('Not integrated (no hooks)')\r\n lines.push(` Bashbros: ${integrationStatus}`)\r\n\r\n return lines.join('\\n')\r\n}\r\n\r\n/**\r\n * Format all agents info\r\n */\r\nexport function formatAllAgentsInfo(agents: AgentConfigInfo[]): string {\r\n const lines: string[] = [\r\n chalk.bold.cyan('AGENT CONFIGURATIONS'),\r\n chalk.dim('='.repeat(40)),\r\n ''\r\n ]\r\n\r\n const installed = agents.filter(a => a.installed)\r\n const notInstalled = agents.filter(a => !a.installed)\r\n\r\n if (installed.length === 0) {\r\n lines.push(chalk.yellow('No agents detected.'))\r\n lines.push('')\r\n } else {\r\n for (const agent of installed) {\r\n lines.push(formatAgentInfo(agent))\r\n lines.push('')\r\n }\r\n }\r\n\r\n // Show not-installed agents briefly\r\n if (notInstalled.length > 0) {\r\n lines.push(chalk.dim('Other known agents (not installed):'))\r\n lines.push(chalk.dim(' ' + notInstalled.map(a => AGENT_DISPLAY_NAMES[a.agent]).join(', ')))\r\n }\r\n\r\n return lines.join('\\n')\r\n}\r\n\r\n/**\r\n * Calculate effective permissions by combining bashbros config with agent config\r\n */\r\nexport function getEffectivePermissions(agentInfo: AgentConfigInfo): EffectivePermissions {\r\n const bashbrosConfig = loadConfig()\r\n\r\n // Get bashbros settings\r\n const bashbrosPaths = bashbrosConfig.paths.allow\r\n const bashbrosBlocked = bashbrosConfig.commands.block\r\n const bashbrosRiskThreshold = bashbrosConfig.riskScoring.blockThreshold\r\n const bashbrosRateLimit = bashbrosConfig.rateLimit.maxPerMinute\r\n\r\n // Get agent settings\r\n const agentPaths = agentInfo.permissions?.allowedPaths || []\r\n const agentBlocked = agentInfo.permissions?.blockedCommands || []\r\n const agentRiskThreshold = typeof agentInfo.permissions?.rateLimit === 'number'\r\n ? agentInfo.permissions.rateLimit\r\n : null\r\n const agentRateLimit = null // Most agents don't have rate limits in their config\r\n\r\n // Calculate effective (most restrictive)\r\n // For paths: intersection if both have values, otherwise the one that exists\r\n let effectivePaths: string[]\r\n if (bashbrosPaths.length > 0 && agentPaths.length > 0) {\r\n // Find paths that appear in both (simplified intersection)\r\n effectivePaths = bashbrosPaths.filter(bp =>\r\n agentPaths.some(ap => ap === bp || bp.startsWith(ap) || ap.startsWith(bp))\r\n )\r\n if (effectivePaths.length === 0) {\r\n effectivePaths = bashbrosPaths // Fall back to bashbros if no overlap\r\n }\r\n } else {\r\n effectivePaths = bashbrosPaths.length > 0 ? bashbrosPaths : agentPaths\r\n }\r\n\r\n // For blocked commands: union\r\n const effectiveBlocked = Array.from(new Set([...bashbrosBlocked, ...agentBlocked]))\r\n\r\n // For numeric thresholds: use the more restrictive (lower) value\r\n const effectiveRiskThreshold = agentRiskThreshold !== null\r\n ? Math.min(bashbrosRiskThreshold, agentRiskThreshold)\r\n : bashbrosRiskThreshold\r\n\r\n const effectiveRateLimit = agentRateLimit !== null\r\n ? Math.min(bashbrosRateLimit, agentRateLimit)\r\n : bashbrosRateLimit\r\n\r\n return {\r\n allowedPaths: {\r\n bashbros: bashbrosPaths,\r\n agent: agentPaths,\r\n effective: effectivePaths\r\n },\r\n riskThreshold: {\r\n bashbros: bashbrosRiskThreshold,\r\n agent: agentRiskThreshold,\r\n effective: effectiveRiskThreshold\r\n },\r\n rateLimit: {\r\n bashbros: bashbrosRateLimit,\r\n agent: agentRateLimit,\r\n effective: effectiveRateLimit\r\n },\r\n blockedCommands: {\r\n bashbros: bashbrosBlocked,\r\n agent: agentBlocked,\r\n effective: effectiveBlocked\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Format permissions comparison table\r\n */\r\nexport function formatPermissionsTable(\r\n agents: AgentConfigInfo[]\r\n): string {\r\n const lines: string[] = [\r\n chalk.bold.cyan('EFFECTIVE PERMISSIONS'),\r\n chalk.dim('='.repeat(40)),\r\n ''\r\n ]\r\n\r\n const config = loadConfig()\r\n\r\n // Header row\r\n const installedAgents = agents.filter(a => a.installed)\r\n const agentHeaders = installedAgents.map(a => AGENT_DISPLAY_NAMES[a.agent].padEnd(12))\r\n\r\n lines.push(chalk.bold(' Bashbros ' + agentHeaders.join(' ') + ' Effective'))\r\n lines.push(chalk.dim('-'.repeat(80)))\r\n\r\n // Allowed paths\r\n const bashbrosPaths = config.paths.allow.slice(0, 3).join(', ') || '*'\r\n lines.push(`Allowed paths: ${bashbrosPaths.padEnd(12)}`)\r\n\r\n for (const agent of installedAgents) {\r\n const perms = getEffectivePermissions(agent)\r\n const agentPaths = perms.allowedPaths.agent.slice(0, 2).join(', ') || 'none'\r\n const effectivePaths = perms.allowedPaths.effective.slice(0, 2).join(', ') || '*'\r\n\r\n lines[lines.length - 1] += `${agentPaths.padEnd(12)} `\r\n\r\n if (agent === installedAgents[installedAgents.length - 1]) {\r\n lines[lines.length - 1] += effectivePaths\r\n }\r\n }\r\n\r\n // Risk threshold\r\n const bashbrosRisk = config.riskScoring.blockThreshold\r\n let riskLine = `Risk threshold: ${bashbrosRisk.toString().padEnd(12)}`\r\n\r\n for (const agent of installedAgents) {\r\n const perms = getEffectivePermissions(agent)\r\n const agentRisk = perms.riskThreshold.agent !== null ? perms.riskThreshold.agent.toString() : 'none'\r\n riskLine += `${agentRisk.padEnd(12)} `\r\n\r\n if (agent === installedAgents[installedAgents.length - 1]) {\r\n const effectiveRisk = perms.riskThreshold.effective\r\n const note = effectiveRisk < bashbrosRisk ? ' (stricter)' : ''\r\n riskLine += `${effectiveRisk}${note}`\r\n }\r\n }\r\n lines.push(riskLine)\r\n\r\n // Rate limit\r\n const bashbrosRate = `${config.rateLimit.maxPerMinute}/min`\r\n let rateLine = `Rate limit: ${bashbrosRate.padEnd(12)}`\r\n\r\n for (const agent of installedAgents) {\r\n const perms = getEffectivePermissions(agent)\r\n const agentRate = perms.rateLimit.agent !== null ? `${perms.rateLimit.agent}/min` : 'none'\r\n rateLine += `${agentRate.padEnd(12)} `\r\n\r\n if (agent === installedAgents[installedAgents.length - 1]) {\r\n rateLine += `${perms.rateLimit.effective}/min`\r\n }\r\n }\r\n lines.push(rateLine)\r\n\r\n // Blocked commands count\r\n const bashbrosBlocked = config.commands.block.length\r\n let blockedLine = `Blocked commands: ${bashbrosBlocked.toString().padEnd(12)}`\r\n\r\n for (const agent of installedAgents) {\r\n const perms = getEffectivePermissions(agent)\r\n const agentBlocked = perms.blockedCommands.agent.length\r\n blockedLine += `${agentBlocked.toString().padEnd(12)} `\r\n\r\n if (agent === installedAgents[installedAgents.length - 1]) {\r\n blockedLine += perms.blockedCommands.effective.length.toString()\r\n }\r\n }\r\n lines.push(blockedLine)\r\n\r\n lines.push('')\r\n lines.push(chalk.dim('Note: Effective = most restrictive combination of all policies'))\r\n\r\n return lines.join('\\n')\r\n}\r\n\r\n/**\r\n * Format a brief summary for scan output\r\n */\r\nexport function formatAgentSummary(agents: AgentConfigInfo[]): string {\r\n const lines: string[] = []\r\n const installed = agents.filter(a => a.installed)\r\n\r\n if (installed.length === 0) {\r\n lines.push(chalk.dim(' No agents detected'))\r\n return lines.join('\\n')\r\n }\r\n\r\n for (const agent of installed) {\r\n const name = AGENT_DISPLAY_NAMES[agent.agent]\r\n const config = agent.configExists\r\n ? chalk.green('configured')\r\n : chalk.yellow('no config')\r\n const integration = agent.bashbrosIntegrated\r\n ? chalk.green('integrated')\r\n : chalk.dim('not integrated')\r\n\r\n lines.push(` ${name}: ${config}, ${integration}`)\r\n }\r\n\r\n return lines.join('\\n')\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
__require
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=chunk-7OCVIDC7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/dashboard/db.ts
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
var DashboardDB = class {
|
|
7
|
+
db;
|
|
8
|
+
constructor(dbPath = ".bashbros.db") {
|
|
9
|
+
this.db = new Database(dbPath);
|
|
10
|
+
this.db.pragma("journal_mode = WAL");
|
|
11
|
+
this.initTables();
|
|
12
|
+
}
|
|
13
|
+
initTables() {
|
|
14
|
+
this.db.exec(`
|
|
15
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
16
|
+
id TEXT PRIMARY KEY,
|
|
17
|
+
timestamp TEXT NOT NULL,
|
|
18
|
+
source TEXT NOT NULL,
|
|
19
|
+
level TEXT NOT NULL,
|
|
20
|
+
category TEXT NOT NULL,
|
|
21
|
+
message TEXT NOT NULL,
|
|
22
|
+
data TEXT
|
|
23
|
+
)
|
|
24
|
+
`);
|
|
25
|
+
this.db.exec(`
|
|
26
|
+
CREATE TABLE IF NOT EXISTS connector_events (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
timestamp TEXT NOT NULL,
|
|
29
|
+
connector TEXT NOT NULL,
|
|
30
|
+
method TEXT NOT NULL,
|
|
31
|
+
direction TEXT NOT NULL,
|
|
32
|
+
payload TEXT NOT NULL,
|
|
33
|
+
resources_accessed TEXT NOT NULL
|
|
34
|
+
)
|
|
35
|
+
`);
|
|
36
|
+
this.db.exec(`
|
|
37
|
+
CREATE TABLE IF NOT EXISTS egress_blocks (
|
|
38
|
+
id TEXT PRIMARY KEY,
|
|
39
|
+
timestamp TEXT NOT NULL,
|
|
40
|
+
pattern TEXT NOT NULL,
|
|
41
|
+
matched_text TEXT NOT NULL,
|
|
42
|
+
redacted_text TEXT NOT NULL,
|
|
43
|
+
connector TEXT,
|
|
44
|
+
destination TEXT,
|
|
45
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
46
|
+
approved_by TEXT,
|
|
47
|
+
approved_at TEXT
|
|
48
|
+
)
|
|
49
|
+
`);
|
|
50
|
+
this.db.exec(`
|
|
51
|
+
CREATE TABLE IF NOT EXISTS exposure_scans (
|
|
52
|
+
id TEXT PRIMARY KEY,
|
|
53
|
+
timestamp TEXT NOT NULL,
|
|
54
|
+
agent TEXT NOT NULL,
|
|
55
|
+
pid INTEGER,
|
|
56
|
+
port INTEGER NOT NULL,
|
|
57
|
+
bind_address TEXT NOT NULL,
|
|
58
|
+
has_auth TEXT NOT NULL,
|
|
59
|
+
severity TEXT NOT NULL,
|
|
60
|
+
action TEXT NOT NULL,
|
|
61
|
+
message TEXT NOT NULL
|
|
62
|
+
)
|
|
63
|
+
`);
|
|
64
|
+
this.db.exec(`
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_events_source ON events(source);
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_events_level ON events(level);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
|
|
68
|
+
CREATE INDEX IF NOT EXISTS idx_connector_events_connector ON connector_events(connector);
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_egress_blocks_status ON egress_blocks(status);
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
// ─────────────────────────────────────────────────────────────
|
|
73
|
+
// Events
|
|
74
|
+
// ─────────────────────────────────────────────────────────────
|
|
75
|
+
insertEvent(input) {
|
|
76
|
+
const id = randomUUID();
|
|
77
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
78
|
+
const data = input.data ? JSON.stringify(input.data) : null;
|
|
79
|
+
const stmt = this.db.prepare(`
|
|
80
|
+
INSERT INTO events (id, timestamp, source, level, category, message, data)
|
|
81
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
82
|
+
`);
|
|
83
|
+
stmt.run(id, timestamp, input.source, input.level, input.category, input.message, data);
|
|
84
|
+
return id;
|
|
85
|
+
}
|
|
86
|
+
getEvents(filter = {}) {
|
|
87
|
+
const conditions = [];
|
|
88
|
+
const params = [];
|
|
89
|
+
if (filter.source) {
|
|
90
|
+
conditions.push("source = ?");
|
|
91
|
+
params.push(filter.source);
|
|
92
|
+
}
|
|
93
|
+
if (filter.level) {
|
|
94
|
+
conditions.push("level = ?");
|
|
95
|
+
params.push(filter.level);
|
|
96
|
+
}
|
|
97
|
+
if (filter.category) {
|
|
98
|
+
conditions.push("category = ?");
|
|
99
|
+
params.push(filter.category);
|
|
100
|
+
}
|
|
101
|
+
if (filter.since) {
|
|
102
|
+
conditions.push("timestamp >= ?");
|
|
103
|
+
params.push(filter.since.toISOString());
|
|
104
|
+
}
|
|
105
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
106
|
+
const limit = filter.limit ?? 100;
|
|
107
|
+
const offset = filter.offset ?? 0;
|
|
108
|
+
const stmt = this.db.prepare(`
|
|
109
|
+
SELECT * FROM events
|
|
110
|
+
${whereClause}
|
|
111
|
+
ORDER BY timestamp DESC
|
|
112
|
+
LIMIT ? OFFSET ?
|
|
113
|
+
`);
|
|
114
|
+
params.push(limit, offset);
|
|
115
|
+
const rows = stmt.all(...params);
|
|
116
|
+
return rows.map((row) => ({
|
|
117
|
+
id: row.id,
|
|
118
|
+
timestamp: new Date(row.timestamp),
|
|
119
|
+
source: row.source,
|
|
120
|
+
level: row.level,
|
|
121
|
+
category: row.category,
|
|
122
|
+
message: row.message,
|
|
123
|
+
data: row.data ? JSON.parse(row.data) : void 0
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
// ─────────────────────────────────────────────────────────────
|
|
127
|
+
// Connector Events
|
|
128
|
+
// ─────────────────────────────────────────────────────────────
|
|
129
|
+
insertConnectorEvent(input) {
|
|
130
|
+
const id = randomUUID();
|
|
131
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
132
|
+
const stmt = this.db.prepare(`
|
|
133
|
+
INSERT INTO connector_events (id, timestamp, connector, method, direction, payload, resources_accessed)
|
|
134
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
135
|
+
`);
|
|
136
|
+
stmt.run(
|
|
137
|
+
id,
|
|
138
|
+
timestamp,
|
|
139
|
+
input.connector,
|
|
140
|
+
input.method,
|
|
141
|
+
input.direction,
|
|
142
|
+
JSON.stringify(input.payload),
|
|
143
|
+
JSON.stringify(input.resourcesAccessed)
|
|
144
|
+
);
|
|
145
|
+
return id;
|
|
146
|
+
}
|
|
147
|
+
getConnectorEvents(connector, limit = 100) {
|
|
148
|
+
const stmt = this.db.prepare(`
|
|
149
|
+
SELECT * FROM connector_events
|
|
150
|
+
WHERE connector = ?
|
|
151
|
+
ORDER BY timestamp DESC
|
|
152
|
+
LIMIT ?
|
|
153
|
+
`);
|
|
154
|
+
const rows = stmt.all(connector, limit);
|
|
155
|
+
return rows.map((row) => ({
|
|
156
|
+
id: row.id,
|
|
157
|
+
timestamp: new Date(row.timestamp),
|
|
158
|
+
connector: row.connector,
|
|
159
|
+
method: row.method,
|
|
160
|
+
direction: row.direction,
|
|
161
|
+
payload: JSON.parse(row.payload),
|
|
162
|
+
resourcesAccessed: JSON.parse(row.resources_accessed)
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
getAllConnectorEvents(limit = 100) {
|
|
166
|
+
const stmt = this.db.prepare(`
|
|
167
|
+
SELECT * FROM connector_events
|
|
168
|
+
ORDER BY timestamp DESC
|
|
169
|
+
LIMIT ?
|
|
170
|
+
`);
|
|
171
|
+
const rows = stmt.all(limit);
|
|
172
|
+
return rows.map((row) => ({
|
|
173
|
+
id: row.id,
|
|
174
|
+
timestamp: new Date(row.timestamp),
|
|
175
|
+
connector: row.connector,
|
|
176
|
+
method: row.method,
|
|
177
|
+
direction: row.direction,
|
|
178
|
+
payload: JSON.parse(row.payload),
|
|
179
|
+
resourcesAccessed: JSON.parse(row.resources_accessed)
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
// ─────────────────────────────────────────────────────────────
|
|
183
|
+
// Egress Blocks
|
|
184
|
+
// ─────────────────────────────────────────────────────────────
|
|
185
|
+
insertEgressBlock(input) {
|
|
186
|
+
const id = randomUUID();
|
|
187
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
188
|
+
const stmt = this.db.prepare(`
|
|
189
|
+
INSERT INTO egress_blocks (id, timestamp, pattern, matched_text, redacted_text, connector, destination, status)
|
|
190
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')
|
|
191
|
+
`);
|
|
192
|
+
stmt.run(
|
|
193
|
+
id,
|
|
194
|
+
timestamp,
|
|
195
|
+
JSON.stringify(input.pattern),
|
|
196
|
+
input.matchedText,
|
|
197
|
+
input.redactedText,
|
|
198
|
+
input.connector ?? null,
|
|
199
|
+
input.destination ?? null
|
|
200
|
+
);
|
|
201
|
+
return id;
|
|
202
|
+
}
|
|
203
|
+
getPendingBlocks() {
|
|
204
|
+
const stmt = this.db.prepare(`
|
|
205
|
+
SELECT * FROM egress_blocks
|
|
206
|
+
WHERE status = 'pending'
|
|
207
|
+
ORDER BY timestamp DESC
|
|
208
|
+
`);
|
|
209
|
+
const rows = stmt.all();
|
|
210
|
+
return rows.map((row) => this.rowToEgressMatch(row));
|
|
211
|
+
}
|
|
212
|
+
getBlock(id) {
|
|
213
|
+
const stmt = this.db.prepare(`
|
|
214
|
+
SELECT * FROM egress_blocks WHERE id = ?
|
|
215
|
+
`);
|
|
216
|
+
const row = stmt.get(id);
|
|
217
|
+
if (!row) return null;
|
|
218
|
+
return this.rowToEgressMatch(row);
|
|
219
|
+
}
|
|
220
|
+
approveBlock(id, approvedBy) {
|
|
221
|
+
const stmt = this.db.prepare(`
|
|
222
|
+
UPDATE egress_blocks
|
|
223
|
+
SET status = 'approved', approved_by = ?, approved_at = ?
|
|
224
|
+
WHERE id = ?
|
|
225
|
+
`);
|
|
226
|
+
stmt.run(approvedBy, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
227
|
+
}
|
|
228
|
+
denyBlock(id, deniedBy) {
|
|
229
|
+
const stmt = this.db.prepare(`
|
|
230
|
+
UPDATE egress_blocks
|
|
231
|
+
SET status = 'denied', approved_by = ?, approved_at = ?
|
|
232
|
+
WHERE id = ?
|
|
233
|
+
`);
|
|
234
|
+
stmt.run(deniedBy, (/* @__PURE__ */ new Date()).toISOString(), id);
|
|
235
|
+
}
|
|
236
|
+
rowToEgressMatch(row) {
|
|
237
|
+
return {
|
|
238
|
+
id: row.id,
|
|
239
|
+
timestamp: new Date(row.timestamp),
|
|
240
|
+
pattern: JSON.parse(row.pattern),
|
|
241
|
+
matchedText: row.matched_text,
|
|
242
|
+
redactedText: row.redacted_text,
|
|
243
|
+
connector: row.connector ?? void 0,
|
|
244
|
+
destination: row.destination ?? void 0,
|
|
245
|
+
status: row.status,
|
|
246
|
+
approvedBy: row.approved_by ?? void 0,
|
|
247
|
+
approvedAt: row.approved_at ? new Date(row.approved_at) : void 0
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
// ─────────────────────────────────────────────────────────────
|
|
251
|
+
// Exposure Scans
|
|
252
|
+
// ─────────────────────────────────────────────────────────────
|
|
253
|
+
insertExposureScan(result) {
|
|
254
|
+
const id = randomUUID();
|
|
255
|
+
const timestamp = result.timestamp.toISOString();
|
|
256
|
+
const stmt = this.db.prepare(`
|
|
257
|
+
INSERT INTO exposure_scans (id, timestamp, agent, pid, port, bind_address, has_auth, severity, action, message)
|
|
258
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
259
|
+
`);
|
|
260
|
+
stmt.run(
|
|
261
|
+
id,
|
|
262
|
+
timestamp,
|
|
263
|
+
result.agent,
|
|
264
|
+
result.pid ?? null,
|
|
265
|
+
result.port,
|
|
266
|
+
result.bindAddress,
|
|
267
|
+
String(result.hasAuth),
|
|
268
|
+
result.severity,
|
|
269
|
+
result.action,
|
|
270
|
+
result.message
|
|
271
|
+
);
|
|
272
|
+
return id;
|
|
273
|
+
}
|
|
274
|
+
getRecentExposures(limit = 100) {
|
|
275
|
+
const stmt = this.db.prepare(`
|
|
276
|
+
SELECT * FROM exposure_scans
|
|
277
|
+
ORDER BY timestamp DESC
|
|
278
|
+
LIMIT ?
|
|
279
|
+
`);
|
|
280
|
+
const rows = stmt.all(limit);
|
|
281
|
+
return rows.map((row) => ({
|
|
282
|
+
agent: row.agent,
|
|
283
|
+
pid: row.pid ?? void 0,
|
|
284
|
+
port: row.port,
|
|
285
|
+
bindAddress: row.bind_address,
|
|
286
|
+
hasAuth: row.has_auth === "true" ? true : row.has_auth === "false" ? false : "unknown",
|
|
287
|
+
severity: row.severity,
|
|
288
|
+
action: row.action,
|
|
289
|
+
message: row.message,
|
|
290
|
+
timestamp: new Date(row.timestamp)
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
// ─────────────────────────────────────────────────────────────
|
|
294
|
+
// Stats
|
|
295
|
+
// ─────────────────────────────────────────────────────────────
|
|
296
|
+
getStats() {
|
|
297
|
+
const totalEventsRow = this.db.prepare("SELECT COUNT(*) as count FROM events").get();
|
|
298
|
+
const sourceRows = this.db.prepare(`
|
|
299
|
+
SELECT source, COUNT(*) as count FROM events GROUP BY source
|
|
300
|
+
`).all();
|
|
301
|
+
const eventsBySource = {};
|
|
302
|
+
for (const row of sourceRows) {
|
|
303
|
+
eventsBySource[row.source] = row.count;
|
|
304
|
+
}
|
|
305
|
+
const levelRows = this.db.prepare(`
|
|
306
|
+
SELECT level, COUNT(*) as count FROM events GROUP BY level
|
|
307
|
+
`).all();
|
|
308
|
+
const eventsByLevel = {};
|
|
309
|
+
for (const row of levelRows) {
|
|
310
|
+
eventsByLevel[row.level] = row.count;
|
|
311
|
+
}
|
|
312
|
+
const pendingBlocksRow = this.db.prepare(`
|
|
313
|
+
SELECT COUNT(*) as count FROM egress_blocks WHERE status = 'pending'
|
|
314
|
+
`).get();
|
|
315
|
+
const connectorCountRow = this.db.prepare(`
|
|
316
|
+
SELECT COUNT(DISTINCT connector) as count FROM connector_events
|
|
317
|
+
`).get();
|
|
318
|
+
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
|
|
319
|
+
const recentExposuresRow = this.db.prepare(`
|
|
320
|
+
SELECT COUNT(*) as count FROM exposure_scans WHERE timestamp >= ?
|
|
321
|
+
`).get(oneDayAgo);
|
|
322
|
+
return {
|
|
323
|
+
totalEvents: totalEventsRow.count,
|
|
324
|
+
eventsBySource,
|
|
325
|
+
eventsByLevel,
|
|
326
|
+
pendingBlocks: pendingBlocksRow.count,
|
|
327
|
+
connectorCount: connectorCountRow.count,
|
|
328
|
+
recentExposures: recentExposuresRow.count
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
// ─────────────────────────────────────────────────────────────
|
|
332
|
+
// Maintenance
|
|
333
|
+
// ─────────────────────────────────────────────────────────────
|
|
334
|
+
cleanup(olderThanDays = 30) {
|
|
335
|
+
const cutoff = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1e3).toISOString();
|
|
336
|
+
const eventsDeleted = this.db.prepare("DELETE FROM events WHERE timestamp < ?").run(cutoff).changes;
|
|
337
|
+
const connectorDeleted = this.db.prepare("DELETE FROM connector_events WHERE timestamp < ?").run(cutoff).changes;
|
|
338
|
+
const blocksDeleted = this.db.prepare(`
|
|
339
|
+
DELETE FROM egress_blocks WHERE timestamp < ? AND status != 'pending'
|
|
340
|
+
`).run(cutoff).changes;
|
|
341
|
+
const exposuresDeleted = this.db.prepare("DELETE FROM exposure_scans WHERE timestamp < ?").run(cutoff).changes;
|
|
342
|
+
return eventsDeleted + connectorDeleted + blocksDeleted + exposuresDeleted;
|
|
343
|
+
}
|
|
344
|
+
close() {
|
|
345
|
+
this.db.close();
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var db_default = DashboardDB;
|
|
349
|
+
|
|
350
|
+
export {
|
|
351
|
+
DashboardDB,
|
|
352
|
+
db_default
|
|
353
|
+
};
|
|
354
|
+
//# sourceMappingURL=chunk-CSRPOGHY.js.map
|