bashbros 0.1.2 → 0.1.4
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/README.md +727 -265
- package/dist/adapters-JAZGGNVP.js +9 -0
- package/dist/chunk-4XZ64P4V.js +47 -0
- package/dist/chunk-4XZ64P4V.js.map +1 -0
- package/dist/{chunk-XCZMQRSX.js → chunk-7OEWYFN3.js} +745 -541
- package/dist/chunk-7OEWYFN3.js.map +1 -0
- package/dist/{chunk-SQCP6IYB.js → chunk-CG6VEHJM.js} +3 -2
- package/dist/chunk-CG6VEHJM.js.map +1 -0
- package/dist/{chunk-DLP2O6PN.js → chunk-EMLEJVJZ.js} +102 -1
- package/dist/chunk-EMLEJVJZ.js.map +1 -0
- package/dist/chunk-IUUBCPMV.js +166 -0
- package/dist/chunk-IUUBCPMV.js.map +1 -0
- package/dist/chunk-J6ONXY6N.js +146 -0
- package/dist/chunk-J6ONXY6N.js.map +1 -0
- package/dist/chunk-KYDMPE4N.js +224 -0
- package/dist/chunk-KYDMPE4N.js.map +1 -0
- package/dist/chunk-LJE4EPIU.js +56 -0
- package/dist/chunk-LJE4EPIU.js.map +1 -0
- package/dist/chunk-LZYW7XQO.js +339 -0
- package/dist/chunk-LZYW7XQO.js.map +1 -0
- package/dist/{chunk-YUMNBQAY.js → chunk-RDNSS3ME.js} +587 -12
- package/dist/chunk-RDNSS3ME.js.map +1 -0
- package/dist/{chunk-BW6XCOJH.js → chunk-RTZ4QWG2.js} +2 -2
- package/dist/chunk-RTZ4QWG2.js.map +1 -0
- package/dist/chunk-SDN6TAGD.js +157 -0
- package/dist/chunk-SDN6TAGD.js.map +1 -0
- package/dist/chunk-T5ONCUHZ.js +198 -0
- package/dist/chunk-T5ONCUHZ.js.map +1 -0
- package/dist/cli.js +1182 -251
- package/dist/cli.js.map +1 -1
- package/dist/{config-JLLOTFLI.js → config-I5NCK3RJ.js} +2 -2
- package/dist/copilot-cli-5WJWK5YT.js +9 -0
- package/dist/{db-OBKEXRTP.js → db-ETWTBXAE.js} +2 -2
- package/dist/db-checks-2YOVECD4.js +133 -0
- package/dist/db-checks-2YOVECD4.js.map +1 -0
- package/dist/{display-6LZ2HBCU.js → display-UH7KEHOW.js} +3 -3
- package/dist/display-UH7KEHOW.js.map +1 -0
- package/dist/gemini-cli-3563EELZ.js +9 -0
- package/dist/gemini-cli-3563EELZ.js.map +1 -0
- package/dist/index.d.ts +195 -72
- package/dist/index.js +119 -398
- package/dist/index.js.map +1 -1
- package/dist/{ollama-HY35OHW4.js → ollama-5JVKNFOV.js} +2 -2
- package/dist/ollama-5JVKNFOV.js.map +1 -0
- package/dist/opencode-DRCY275R.js +9 -0
- package/dist/opencode-DRCY275R.js.map +1 -0
- package/dist/profiles-7CLN6TAT.js +9 -0
- package/dist/profiles-7CLN6TAT.js.map +1 -0
- package/dist/setup-YS27MOPE.js +124 -0
- package/dist/setup-YS27MOPE.js.map +1 -0
- package/dist/static/index.html +4815 -2007
- package/dist/store-WJ5Y7MOE.js +9 -0
- package/dist/store-WJ5Y7MOE.js.map +1 -0
- package/dist/writer-3NAVABN6.js +12 -0
- package/dist/writer-3NAVABN6.js.map +1 -0
- package/package.json +77 -68
- package/dist/chunk-BW6XCOJH.js.map +0 -1
- package/dist/chunk-DLP2O6PN.js.map +0 -1
- package/dist/chunk-SQCP6IYB.js.map +0 -1
- package/dist/chunk-XCZMQRSX.js.map +0 -1
- package/dist/chunk-YUMNBQAY.js.map +0 -1
- /package/dist/{config-JLLOTFLI.js.map → adapters-JAZGGNVP.js.map} +0 -0
- /package/dist/{db-OBKEXRTP.js.map → config-I5NCK3RJ.js.map} +0 -0
- /package/dist/{display-6LZ2HBCU.js.map → copilot-cli-5WJWK5YT.js.map} +0 -0
- /package/dist/{ollama-HY35OHW4.js.map → db-ETWTBXAE.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DashboardWriter,
|
|
4
|
+
writer_default
|
|
5
|
+
} from "./chunk-KYDMPE4N.js";
|
|
6
|
+
import "./chunk-RDNSS3ME.js";
|
|
7
|
+
import "./chunk-7OCVIDC7.js";
|
|
8
|
+
export {
|
|
9
|
+
DashboardWriter,
|
|
10
|
+
writer_default as default
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=writer-3NAVABN6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,68 +1,77 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "bashbros",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"bin": {
|
|
9
|
-
"bashbros": "dist/cli.js"
|
|
10
|
-
},
|
|
11
|
-
"files": [
|
|
12
|
-
"dist",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"build": "tsup && npm run copy-static",
|
|
18
|
-
"copy-static": "node -e \"const fs=require('fs');fs.mkdirSync('dist/static',{recursive:true});fs.cpSync('src/dashboard/static','dist/static',{recursive:true})\"",
|
|
19
|
-
"dev": "tsup --watch",
|
|
20
|
-
"test": "vitest",
|
|
21
|
-
"lint": "eslint src/",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"bash",
|
|
26
|
-
"cli",
|
|
27
|
-
"agent",
|
|
28
|
-
"security",
|
|
29
|
-
"pty",
|
|
30
|
-
"claude",
|
|
31
|
-
"ai",
|
|
32
|
-
"automation"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"node
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "bashbros",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Security middleware and AI sidekick for CLI agents - policy engine, Ollama integration, LoRA adapters, shared context store, and real-time dashboard",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"bashbros": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup && npm run copy-static",
|
|
18
|
+
"copy-static": "node -e \"const fs=require('fs');fs.mkdirSync('dist/static',{recursive:true});fs.cpSync('src/dashboard/static','dist/static',{recursive:true})\"",
|
|
19
|
+
"dev": "tsup --watch",
|
|
20
|
+
"test": "vitest",
|
|
21
|
+
"lint": "eslint src/",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"bash",
|
|
26
|
+
"cli",
|
|
27
|
+
"agent",
|
|
28
|
+
"security",
|
|
29
|
+
"pty",
|
|
30
|
+
"claude",
|
|
31
|
+
"ai",
|
|
32
|
+
"automation",
|
|
33
|
+
"ollama",
|
|
34
|
+
"lora",
|
|
35
|
+
"dashboard",
|
|
36
|
+
"copilot",
|
|
37
|
+
"gemini",
|
|
38
|
+
"context",
|
|
39
|
+
"policy",
|
|
40
|
+
"middleware"
|
|
41
|
+
],
|
|
42
|
+
"author": "GhostPeony",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/GhostPeony/bashbros.git"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://bashbros.ai",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/GhostPeony/bashbros/issues"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"better-sqlite3": "^12.6.2",
|
|
57
|
+
"chalk": "^5.3.0",
|
|
58
|
+
"commander": "^12.1.0",
|
|
59
|
+
"express": "^5.2.1",
|
|
60
|
+
"inquirer": "^9.2.0",
|
|
61
|
+
"node-pty": "^1.0.0",
|
|
62
|
+
"winston": "^3.13.0",
|
|
63
|
+
"ws": "^8.19.0",
|
|
64
|
+
"yaml": "^2.4.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
68
|
+
"@types/express": "^5.0.6",
|
|
69
|
+
"@types/inquirer": "^9.0.9",
|
|
70
|
+
"@types/node": "^20.0.0",
|
|
71
|
+
"@types/ws": "^8.18.1",
|
|
72
|
+
"eslint": "^9.0.0",
|
|
73
|
+
"tsup": "^8.0.0",
|
|
74
|
+
"typescript": "^5.4.0",
|
|
75
|
+
"vitest": "^1.6.0"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { readFileSync, existsSync, statSync } from 'fs'\nimport { parse } from 'yaml'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport type {\n BashBrosConfig,\n SecurityProfile,\n RiskScoringPolicy,\n LoopDetectionPolicy,\n AnomalyDetectionPolicy,\n OutputScanningPolicy,\n UndoPolicy,\n RiskPattern,\n WardPolicy,\n DashboardPolicy\n} from './types.js'\n\nconst CONFIG_FILENAME = '.bashbros.yml'\n\n// Configuration limits for validation\nconst CONFIG_LIMITS = {\n maxPerMinute: { min: 1, max: 10000 },\n maxPerHour: { min: 1, max: 100000 },\n maxPatterns: 100,\n maxPathLength: 1000\n}\n\nexport function findConfig(): string | null {\n // Check current directory\n if (existsSync(CONFIG_FILENAME)) {\n return CONFIG_FILENAME\n }\n\n // Check home directory\n const homeConfig = join(homedir(), CONFIG_FILENAME)\n if (existsSync(homeConfig)) {\n return homeConfig\n }\n\n // Check ~/.bashbros/config.yml\n const dotConfig = join(homedir(), '.bashbros', 'config.yml')\n if (existsSync(dotConfig)) {\n return dotConfig\n }\n\n return null\n}\n\n/**\n * SECURITY: Validate config file permissions\n */\nfunction validateConfigPermissions(configPath: string): void {\n try {\n const stats = statSync(configPath)\n\n // On Unix, check if file is world-writable (security risk)\n if (process.platform !== 'win32') {\n const mode = stats.mode\n const worldWritable = (mode & 0o002) !== 0\n const groupWritable = (mode & 0o020) !== 0\n\n if (worldWritable || groupWritable) {\n console.warn(`⚠️ Warning: Config file ${configPath} has insecure permissions`)\n console.warn(' Run: chmod 600 ' + configPath)\n }\n }\n } catch {\n // Ignore permission check errors\n }\n}\n\nexport function loadConfig(path?: string): BashBrosConfig {\n const configPath = path || findConfig()\n\n if (!configPath) {\n return getDefaultConfig()\n }\n\n // SECURITY: Check file permissions\n validateConfigPermissions(configPath)\n\n const content = readFileSync(configPath, 'utf-8')\n\n // SECURITY: Use safe YAML parsing (no custom tags)\n let parsed: unknown\n try {\n parsed = parse(content, { strict: true })\n } catch (error) {\n console.error('Failed to parse config file:', error)\n return getDefaultConfig()\n }\n\n // SECURITY: Validate parsed config\n const validated = validateConfig(parsed)\n\n return mergeWithDefaults(validated)\n}\n\n/**\n * SECURITY: Validate and sanitize config values\n */\nfunction validateConfig(parsed: unknown): Partial<BashBrosConfig> {\n if (!parsed || typeof parsed !== 'object') {\n return {}\n }\n\n const config = parsed as Record<string, unknown>\n const validated: Partial<BashBrosConfig> = {}\n\n // Validate agent type\n const validAgents = ['claude-code', 'clawdbot', 'gemini-cli', 'aider', 'opencode', 'custom']\n if (typeof config.agent === 'string' && validAgents.includes(config.agent)) {\n validated.agent = config.agent as BashBrosConfig['agent']\n }\n\n // Validate profile\n const validProfiles = ['balanced', 'strict', 'permissive', 'custom']\n if (typeof config.profile === 'string' && validProfiles.includes(config.profile)) {\n validated.profile = config.profile as SecurityProfile\n }\n\n // Validate commands\n if (config.commands && typeof config.commands === 'object') {\n const cmds = config.commands as Record<string, unknown>\n validated.commands = {\n allow: validateStringArray(cmds.allow, CONFIG_LIMITS.maxPatterns),\n block: validateStringArray(cmds.block, CONFIG_LIMITS.maxPatterns)\n }\n }\n\n // Validate paths\n if (config.paths && typeof config.paths === 'object') {\n const paths = config.paths as Record<string, unknown>\n validated.paths = {\n allow: validatePathArray(paths.allow),\n block: validatePathArray(paths.block)\n }\n }\n\n // Validate secrets\n if (config.secrets && typeof config.secrets === 'object') {\n const secrets = config.secrets as Record<string, unknown>\n validated.secrets = {\n enabled: typeof secrets.enabled === 'boolean' ? secrets.enabled : true,\n mode: secrets.mode === 'audit' ? 'audit' : 'block',\n patterns: validateStringArray(secrets.patterns, CONFIG_LIMITS.maxPatterns)\n }\n }\n\n // Validate audit\n if (config.audit && typeof config.audit === 'object') {\n const audit = config.audit as Record<string, unknown>\n validated.audit = {\n enabled: typeof audit.enabled === 'boolean' ? audit.enabled : true,\n destination: validateAuditDestination(audit.destination),\n remotePath: validateRemotePath(audit.remotePath)\n }\n }\n\n // Validate rate limit\n if (config.rateLimit && typeof config.rateLimit === 'object') {\n const rl = config.rateLimit as Record<string, unknown>\n const maxPerMinute = validateNumber(rl.maxPerMinute, CONFIG_LIMITS.maxPerMinute)\n const maxPerHour = validateNumber(rl.maxPerHour, CONFIG_LIMITS.maxPerHour)\n\n // SECURITY: Ensure hour limit >= minute limit\n validated.rateLimit = {\n enabled: typeof rl.enabled === 'boolean' ? rl.enabled : true,\n maxPerMinute,\n maxPerHour: Math.max(maxPerHour, maxPerMinute)\n }\n }\n\n // Validate risk scoring\n if (config.riskScoring && typeof config.riskScoring === 'object') {\n const rs = config.riskScoring as Record<string, unknown>\n validated.riskScoring = {\n enabled: typeof rs.enabled === 'boolean' ? rs.enabled : true,\n blockThreshold: validateNumber(rs.blockThreshold, { min: 1, max: 10 }),\n warnThreshold: validateNumber(rs.warnThreshold, { min: 1, max: 10 }),\n customPatterns: validateRiskPatterns(rs.customPatterns)\n }\n }\n\n // Validate loop detection\n if (config.loopDetection && typeof config.loopDetection === 'object') {\n const ld = config.loopDetection as Record<string, unknown>\n validated.loopDetection = {\n enabled: typeof ld.enabled === 'boolean' ? ld.enabled : true,\n maxRepeats: validateNumber(ld.maxRepeats, { min: 1, max: 100 }),\n maxTurns: validateNumber(ld.maxTurns, { min: 10, max: 10000 }),\n similarityThreshold: validateNumber(ld.similarityThreshold, { min: 0, max: 1 }) / 1, // Keep as float\n cooldownMs: validateNumber(ld.cooldownMs, { min: 0, max: 60000 }),\n windowSize: validateNumber(ld.windowSize, { min: 5, max: 100 }),\n action: ld.action === 'block' ? 'block' : 'warn'\n }\n }\n\n // Validate anomaly detection\n if (config.anomalyDetection && typeof config.anomalyDetection === 'object') {\n const ad = config.anomalyDetection as Record<string, unknown>\n validated.anomalyDetection = {\n enabled: typeof ad.enabled === 'boolean' ? ad.enabled : true,\n workingHours: validateWorkingHours(ad.workingHours),\n typicalCommandsPerMinute: validateNumber(ad.typicalCommandsPerMinute, { min: 1, max: 1000 }),\n learningCommands: validateNumber(ad.learningCommands, { min: 10, max: 500 }),\n suspiciousPatterns: validateStringArray(ad.suspiciousPatterns, 50),\n action: ad.action === 'block' ? 'block' : 'warn'\n }\n }\n\n // Validate output scanning\n if (config.outputScanning && typeof config.outputScanning === 'object') {\n const os = config.outputScanning as Record<string, unknown>\n validated.outputScanning = {\n enabled: typeof os.enabled === 'boolean' ? os.enabled : true,\n scanForSecrets: typeof os.scanForSecrets === 'boolean' ? os.scanForSecrets : true,\n scanForErrors: typeof os.scanForErrors === 'boolean' ? os.scanForErrors : true,\n maxOutputLength: validateNumber(os.maxOutputLength, { min: 1000, max: 10000000 }),\n redactPatterns: validateStringArray(os.redactPatterns, 50)\n }\n }\n\n // Validate undo\n if (config.undo && typeof config.undo === 'object') {\n const undo = config.undo as Record<string, unknown>\n validated.undo = {\n enabled: typeof undo.enabled === 'boolean' ? undo.enabled : true,\n maxStackSize: validateNumber(undo.maxStackSize, { min: 10, max: 1000 }),\n maxFileSize: validateNumber(undo.maxFileSize, { min: 1024, max: 100 * 1024 * 1024 }),\n ttlMinutes: validateNumber(undo.ttlMinutes, { min: 5, max: 1440 }),\n backupPath: typeof undo.backupPath === 'string' ? undo.backupPath.slice(0, 500) : '~/.bashbros/undo'\n }\n }\n\n return validated\n}\n\nfunction validateRiskPatterns(value: unknown): RiskPattern[] {\n if (!Array.isArray(value)) return []\n\n return value\n .filter((item): item is Record<string, unknown> =>\n item && typeof item === 'object' &&\n typeof item.pattern === 'string' &&\n typeof item.score === 'number' &&\n typeof item.factor === 'string'\n )\n .slice(0, 50)\n .map(item => ({\n pattern: String(item.pattern).slice(0, 500),\n score: Math.max(1, Math.min(10, Math.floor(Number(item.score)))),\n factor: String(item.factor).slice(0, 200)\n }))\n}\n\nfunction validateWorkingHours(value: unknown): [number, number] {\n if (!Array.isArray(value) || value.length !== 2) {\n return [6, 22]\n }\n\n const start = Math.max(0, Math.min(23, Math.floor(Number(value[0]) || 0)))\n const end = Math.max(0, Math.min(24, Math.floor(Number(value[1]) || 24)))\n\n return [start, end]\n}\n\nfunction validateStringArray(value: unknown, maxItems: number): string[] {\n if (!Array.isArray(value)) return []\n\n return value\n .filter((item): item is string => typeof item === 'string')\n .slice(0, maxItems)\n .map(s => s.slice(0, 500)) // Limit string length\n}\n\nfunction validatePathArray(value: unknown): string[] {\n if (!Array.isArray(value)) return []\n\n return value\n .filter((item): item is string => typeof item === 'string')\n .slice(0, CONFIG_LIMITS.maxPatterns)\n .map(s => s.slice(0, CONFIG_LIMITS.maxPathLength))\n .filter(s => !s.includes('\\0')) // Block null bytes\n}\n\nfunction validateNumber(value: unknown, limits: { min: number; max: number }): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return limits.min\n }\n return Math.max(limits.min, Math.min(limits.max, Math.floor(value)))\n}\n\nfunction validateAuditDestination(value: unknown): 'local' | 'remote' | 'both' {\n if (value === 'remote' || value === 'both') {\n return value\n }\n return 'local'\n}\n\n/**\n * SECURITY: Validate remote audit path (must be HTTPS)\n */\nfunction validateRemotePath(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined\n }\n\n try {\n const url = new URL(value)\n\n // SECURITY: Only allow HTTPS\n if (url.protocol !== 'https:') {\n console.warn('⚠️ Warning: Remote audit path must use HTTPS. Ignoring:', value)\n return undefined\n }\n\n // Block localhost/private IPs for remote\n const hostname = url.hostname.toLowerCase()\n if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname.startsWith('192.168.') || hostname.startsWith('10.')) {\n // Allow for testing but warn\n console.warn('⚠️ Warning: Remote audit path points to local address')\n }\n\n return value\n } catch {\n console.warn('⚠️ Warning: Invalid remote audit URL:', value)\n return undefined\n }\n}\n\nexport function getDefaultConfig(): BashBrosConfig {\n return {\n agent: 'claude-code',\n profile: 'permissive',\n commands: getDefaultCommands('balanced'),\n paths: getDefaultPaths('balanced'),\n secrets: {\n enabled: true,\n mode: 'block',\n patterns: [\n '.env*',\n '*.pem',\n '*.key',\n '*credentials*',\n '*secret*',\n '.aws/*',\n '.ssh/*'\n ]\n },\n audit: {\n enabled: true,\n destination: 'local'\n },\n rateLimit: {\n enabled: true,\n maxPerMinute: 100,\n maxPerHour: 1000\n },\n riskScoring: getDefaultRiskScoring('balanced'),\n loopDetection: getDefaultLoopDetection('balanced'),\n anomalyDetection: getDefaultAnomalyDetection('balanced'),\n outputScanning: getDefaultOutputScanning('balanced'),\n undo: getDefaultUndo(),\n ward: getDefaultWard(),\n dashboard: getDefaultDashboard()\n }\n}\n\nfunction getDefaultRiskScoring(profile: SecurityProfile): RiskScoringPolicy {\n const thresholds: Record<string, { block: number; warn: number }> = {\n strict: { block: 6, warn: 3 },\n balanced: { block: 9, warn: 6 },\n permissive: { block: 10, warn: 8 }\n }\n const t = thresholds[profile] || thresholds.balanced\n\n return {\n enabled: true,\n blockThreshold: t.block,\n warnThreshold: t.warn,\n customPatterns: []\n }\n}\n\nfunction getDefaultLoopDetection(profile: SecurityProfile): LoopDetectionPolicy {\n const settings: Record<string, { maxRepeats: number; maxTurns: number; action: 'warn' | 'block' }> = {\n strict: { maxRepeats: 2, maxTurns: 50, action: 'block' },\n balanced: { maxRepeats: 3, maxTurns: 100, action: 'warn' },\n permissive: { maxRepeats: 5, maxTurns: 200, action: 'warn' }\n }\n const s = settings[profile] || settings.balanced\n\n return {\n enabled: true,\n maxRepeats: s.maxRepeats,\n maxTurns: s.maxTurns,\n similarityThreshold: 0.85,\n cooldownMs: 1000,\n windowSize: 20,\n action: s.action\n }\n}\n\nfunction getDefaultAnomalyDetection(profile: SecurityProfile): AnomalyDetectionPolicy {\n return {\n enabled: profile !== 'permissive',\n workingHours: [6, 22],\n typicalCommandsPerMinute: 30,\n learningCommands: 50,\n suspiciousPatterns: [],\n action: profile === 'strict' ? 'block' : 'warn'\n }\n}\n\nfunction getDefaultOutputScanning(profile: SecurityProfile): OutputScanningPolicy {\n return {\n enabled: true,\n scanForSecrets: true,\n scanForErrors: true,\n maxOutputLength: 100000,\n redactPatterns: [\n 'password\\\\s*[=:]\\\\s*\\\\S+',\n 'api[_-]?key\\\\s*[=:]\\\\s*\\\\S+',\n 'secret\\\\s*[=:]\\\\s*\\\\S+',\n 'token\\\\s*[=:]\\\\s*\\\\S+',\n 'Bearer\\\\s+[A-Za-z0-9\\\\-._~+/]+=*',\n 'sk-[A-Za-z0-9]{20,}',\n 'ghp_[A-Za-z0-9]{36}',\n 'glpat-[A-Za-z0-9\\\\-]{20,}'\n ]\n }\n}\n\nfunction getDefaultUndo(): UndoPolicy {\n return {\n enabled: true,\n maxStackSize: 100,\n maxFileSize: 10 * 1024 * 1024, // 10MB\n ttlMinutes: 60, // 1 hour\n backupPath: '~/.bashbros/undo'\n }\n}\n\nfunction getDefaultWard(): WardPolicy {\n return {\n enabled: true,\n exposure: {\n scanInterval: 30000, // 30 seconds\n externalProbe: false,\n severityActions: {\n low: 'alert',\n medium: 'alert',\n high: 'block',\n critical: 'block_and_kill'\n }\n },\n connectors: {\n proxyAllMcp: false,\n telemetryRetention: '7d'\n },\n egress: {\n defaultAction: 'block'\n }\n }\n}\n\nfunction getDefaultDashboard(): DashboardPolicy {\n return {\n enabled: true,\n port: 7890,\n bind: '127.0.0.1'\n }\n}\n\nfunction getDefaultCommands(profile: SecurityProfile) {\n const dangerousCommands = [\n // Destructive rm patterns (various flag orders)\n 'rm * /',\n 'rm * ~',\n 'rm * /*',\n 'rm * /home*',\n 'rm * /etc*',\n 'rm * /usr*',\n 'rm * /var*',\n 'rm * /bin*',\n 'rm * /sbin*',\n 'rm * /lib*',\n 'rm * /boot*',\n 'rm * /opt*',\n 'rm * /root*',\n 'rm * /srv*',\n 'rm * /mnt*',\n 'rm * /media*',\n // Windows destructive patterns\n 'rm * C:\\\\*',\n 'rm * C:/*',\n 'Remove-Item * C:\\\\*',\n 'Remove-Item * C:/*',\n 'rd /s *',\n 'rmdir /s *',\n // Fork bomb\n ':(){:|:&};:',\n // Disk destruction\n 'mkfs*',\n 'dd if=/dev/zero*',\n 'dd of=/dev/*',\n '> /dev/sda*',\n '> /dev/nvme*',\n '> /dev/hd*',\n // Dangerous permission changes\n 'chmod -R 777 /*',\n 'chmod -R 777 /',\n 'chmod * 777 /*',\n 'chown -R * /*',\n // Pipe to shell (code execution)\n 'curl * | bash*',\n 'curl * | sh*',\n 'wget * | bash*',\n 'wget * | sh*',\n 'curl * | sudo*',\n 'wget * | sudo*',\n // History/log destruction\n 'history -c*',\n 'shred *',\n // Network attacks\n ':(){ :|:& };:',\n // Dangerous redirects\n '> /etc/passwd*',\n '> /etc/shadow*'\n ]\n\n const commonAllowed = [\n // File operations\n 'ls *', 'dir *', 'cat *', 'head *', 'tail *', 'less *', 'more *',\n 'grep *', 'find *', 'rg *', 'fd *',\n 'mkdir *', 'touch *', 'cp *', 'mv *', 'rm *',\n 'cd *', 'pwd', 'echo *', 'printf *', 'which *', 'where *', 'type *',\n 'tar *', 'zip *', 'unzip *', 'gzip *', 'gunzip *',\n\n // Text processing\n 'sed *', 'awk *', 'sort *', 'uniq *', 'wc *', 'diff *', 'tr *',\n\n // Version control\n 'git *', 'gh *',\n\n // Package managers & runtimes\n 'npm *', 'npx *', 'pnpm *', 'yarn *', 'bun *',\n 'node *', 'deno *', 'tsx *', 'ts-node *',\n 'python *', 'python3 *', 'pip *', 'pip3 *', 'uv *', 'pipx *',\n 'cargo *', 'rustc *', 'rustup *',\n 'go *',\n\n // Build tools\n 'tsc *', 'esbuild *', 'vite *', 'webpack *', 'rollup *', 'tsup *',\n 'make *', 'cmake *',\n\n // Testing & linting\n 'jest *', 'vitest *', 'pytest *', 'mocha *',\n 'eslint *', 'prettier *', 'biome *', 'ruff *', 'black *',\n\n // AI coding assistants & security tools\n 'claude *', 'aider *', 'bashbros *',\n\n // Editors\n 'code *', 'cursor *', 'vim *', 'nvim *', 'nano *', 'emacs *',\n\n // Docker & containers\n 'docker *', 'docker-compose *', 'podman *',\n\n // Network (safe operations)\n 'curl *', 'wget *', 'ping *', 'ssh *',\n\n // System info\n 'env', 'env *', 'printenv *', 'whoami', 'hostname', 'uname *', 'date', 'uptime',\n 'ps *', 'top', 'htop', 'btop',\n\n // Shell basics\n 'clear', 'cls', 'history', 'alias *', 'export *', 'source *', 'exit',\n 'true', 'false', 'test *', 'man *', 'help *',\n\n // PowerShell (Windows)\n 'Get-*', 'Set-*', 'New-*', 'Remove-*', 'Select-*', 'Where-*', 'ForEach-*'\n ]\n\n if (profile === 'strict') {\n return { allow: [], block: dangerousCommands }\n }\n\n if (profile === 'permissive') {\n return { allow: ['*'], block: dangerousCommands }\n }\n\n // balanced\n return { allow: commonAllowed, block: dangerousCommands }\n}\n\nfunction getDefaultPaths(profile: SecurityProfile) {\n const dangerousPaths = [\n '~/.ssh',\n '~/.aws',\n '~/.gnupg',\n '~/.config/gh',\n '/etc/passwd',\n '/etc/shadow'\n ]\n\n if (profile === 'strict') {\n return { allow: ['.'], block: dangerousPaths }\n }\n\n if (profile === 'permissive') {\n return { allow: ['*'], block: dangerousPaths }\n }\n\n // balanced\n return { allow: ['.', '~'], block: dangerousPaths }\n}\n\nfunction mergeWithDefaults(parsed: Partial<BashBrosConfig>): BashBrosConfig {\n const defaults = getDefaultConfig()\n return {\n ...defaults,\n ...parsed,\n commands: { ...defaults.commands, ...parsed.commands },\n paths: { ...defaults.paths, ...parsed.paths },\n secrets: { ...defaults.secrets, ...parsed.secrets },\n audit: { ...defaults.audit, ...parsed.audit },\n rateLimit: { ...defaults.rateLimit, ...parsed.rateLimit },\n riskScoring: { ...defaults.riskScoring, ...parsed.riskScoring },\n loopDetection: { ...defaults.loopDetection, ...parsed.loopDetection },\n anomalyDetection: { ...defaults.anomalyDetection, ...parsed.anomalyDetection },\n outputScanning: { ...defaults.outputScanning, ...parsed.outputScanning },\n undo: { ...defaults.undo, ...parsed.undo },\n ward: { ...defaults.ward, ...parsed.ward },\n dashboard: { ...defaults.dashboard, ...parsed.dashboard }\n }\n}\n\nexport { BashBrosConfig }\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bro/ollama.ts"],"sourcesContent":["/**\r\n * Simple Ollama client for local model inference.\r\n * Keeps it minimal - just what we need for Bash Bro.\r\n */\r\n\r\nexport interface OllamaConfig {\r\n host: string\r\n model: string\r\n timeout: number\r\n}\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant'\r\n content: string\r\n}\r\n\r\nexport interface GenerateResponse {\r\n response: string\r\n done: boolean\r\n context?: number[]\r\n}\r\n\r\nconst DEFAULT_CONFIG: OllamaConfig = {\r\n host: 'http://localhost:11434',\r\n model: 'qwen2.5-coder:7b',\r\n timeout: 30000\r\n}\r\n\r\nexport class OllamaClient {\r\n private config: OllamaConfig\r\n\r\n constructor(config: Partial<OllamaConfig> = {}) {\r\n this.config = { ...DEFAULT_CONFIG, ...config }\r\n }\r\n\r\n /**\r\n * Check if Ollama is running and accessible\r\n */\r\n async isAvailable(): Promise<boolean> {\r\n try {\r\n const controller = new AbortController()\r\n const timeout = setTimeout(() => controller.abort(), 5000)\r\n\r\n const response = await fetch(`${this.config.host}/api/tags`, {\r\n signal: controller.signal\r\n })\r\n\r\n clearTimeout(timeout)\r\n return response.ok\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n /**\r\n * List available models\r\n */\r\n async listModels(): Promise<string[]> {\r\n try {\r\n const response = await fetch(`${this.config.host}/api/tags`)\r\n\r\n if (!response.ok) {\r\n return []\r\n }\r\n\r\n const data = await response.json() as { models?: { name: string }[] }\r\n return data.models?.map((m) => m.name) || []\r\n } catch {\r\n return []\r\n }\r\n }\r\n\r\n /**\r\n * Generate a response from the model\r\n */\r\n async generate(prompt: string, systemPrompt?: string): Promise<string> {\r\n const controller = new AbortController()\r\n const timeout = setTimeout(() => controller.abort(), this.config.timeout)\r\n\r\n try {\r\n const response = await fetch(`${this.config.host}/api/generate`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model: this.config.model,\r\n prompt,\r\n system: systemPrompt,\r\n stream: false\r\n }),\r\n signal: controller.signal\r\n })\r\n\r\n clearTimeout(timeout)\r\n\r\n if (!response.ok) {\r\n throw new Error(`Ollama error: ${response.status}`)\r\n }\r\n\r\n const data = await response.json() as GenerateResponse\r\n return data.response\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new Error('Ollama request timed out')\r\n }\r\n throw error\r\n }\r\n }\r\n\r\n /**\r\n * Chat with the model (multi-turn conversation)\r\n */\r\n async chat(messages: ChatMessage[]): Promise<string> {\r\n const controller = new AbortController()\r\n const timeout = setTimeout(() => controller.abort(), this.config.timeout)\r\n\r\n try {\r\n const response = await fetch(`${this.config.host}/api/chat`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model: this.config.model,\r\n messages,\r\n stream: false\r\n }),\r\n signal: controller.signal\r\n })\r\n\r\n clearTimeout(timeout)\r\n\r\n if (!response.ok) {\r\n throw new Error(`Ollama error: ${response.status}`)\r\n }\r\n\r\n const data = await response.json() as { message?: { content: string } }\r\n return data.message?.content || ''\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new Error('Ollama request timed out')\r\n }\r\n throw error\r\n }\r\n }\r\n\r\n /**\r\n * Ask Bash Bro to suggest a command\r\n */\r\n async suggestCommand(context: string): Promise<string | null> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nGiven the context, suggest the most likely next command the user needs.\r\nRespond with ONLY the command, no explanation. If unsure, respond with \"none\".`\r\n\r\n try {\r\n const response = await this.generate(context, systemPrompt)\r\n const command = response.trim()\r\n\r\n if (command.toLowerCase() === 'none' || command.length > 200) {\r\n return null\r\n }\r\n\r\n return command\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n /**\r\n * Ask Bash Bro to explain a command\r\n */\r\n async explainCommand(command: string): Promise<string> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nExplain what the given command does in 1-2 sentences. Be concise and accurate.`\r\n\r\n try {\r\n return await this.generate(`Explain: ${command}`, systemPrompt)\r\n } catch {\r\n return 'Could not explain command.'\r\n }\r\n }\r\n\r\n /**\r\n * Ask Bash Bro to fix a command that failed\r\n */\r\n async fixCommand(command: string, error: string): Promise<string | null> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nGiven a failed command and its error, suggest a fixed version.\r\nRespond with ONLY the fixed command, no explanation. If you can't fix it, respond with \"none\".`\r\n\r\n try {\r\n const response = await this.generate(\r\n `Command: ${command}\\nError: ${error}\\nFixed command:`,\r\n systemPrompt\r\n )\r\n\r\n const fixed = response.trim()\r\n\r\n if (fixed.toLowerCase() === 'none' || fixed.length > 500) {\r\n return null\r\n }\r\n\r\n return fixed\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n setModel(model: string): void {\r\n this.config.model = model\r\n }\r\n\r\n getModel(): string {\r\n return this.config.model\r\n }\r\n\r\n /**\r\n * Generate a shell script from a natural language description\r\n */\r\n async generateScript(description: string, shell: string = 'bash'): Promise<string | null> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nGenerate a ${shell} script based on the user's description.\r\nOutput ONLY the script, no explanation. Start with the shebang line.\r\nKeep scripts simple, readable, and well-commented.`\r\n\r\n try {\r\n const response = await this.generate(\r\n `Generate a ${shell} script that: ${description}`,\r\n systemPrompt\r\n )\r\n return response.trim()\r\n } catch {\r\n return null\r\n }\r\n }\r\n\r\n /**\r\n * Analyze command safety and provide recommendations\r\n */\r\n async analyzeCommandSafety(command: string): Promise<{\r\n safe: boolean\r\n risk: 'low' | 'medium' | 'high' | 'critical'\r\n explanation: string\r\n suggestions: string[]\r\n }> {\r\n const systemPrompt = `You are Bash Bro, a security-focused command-line assistant.\r\nAnalyze the given command for security risks.\r\nRespond with JSON only, in this format:\r\n{\"safe\": boolean, \"risk\": \"low|medium|high|critical\", \"explanation\": \"...\", \"suggestions\": [\"...\"]}`\r\n\r\n try {\r\n const response = await this.generate(\r\n `Analyze this command for security risks: ${command}`,\r\n systemPrompt\r\n )\r\n\r\n // Try to parse JSON from response\r\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/)\r\n if (jsonMatch) {\r\n return JSON.parse(jsonMatch[0])\r\n }\r\n\r\n // Fallback if not parseable\r\n return {\r\n safe: true,\r\n risk: 'low',\r\n explanation: 'Could not analyze command.',\r\n suggestions: []\r\n }\r\n } catch {\r\n return {\r\n safe: true,\r\n risk: 'low',\r\n explanation: 'Analysis unavailable.',\r\n suggestions: []\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Summarize a series of commands and their outputs\r\n */\r\n async summarizeSession(commands: { command: string; output?: string; error?: string }[]): Promise<string> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nSummarize what happened in this terminal session in 2-3 sentences.\r\nFocus on what was accomplished and any issues encountered.`\r\n\r\n const sessionText = commands.map(c => {\r\n let text = `$ ${c.command}`\r\n if (c.output) text += `\\n${c.output.slice(0, 500)}`\r\n if (c.error) text += `\\nError: ${c.error.slice(0, 200)}`\r\n return text\r\n }).join('\\n\\n')\r\n\r\n try {\r\n return await this.generate(sessionText, systemPrompt)\r\n } catch {\r\n return 'Could not summarize session.'\r\n }\r\n }\r\n\r\n /**\r\n * Get help for a specific tool or command\r\n */\r\n async getHelp(topic: string): Promise<string> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nProvide concise help about the requested command or topic.\r\nInclude common usage examples. Keep it practical and brief.`\r\n\r\n try {\r\n return await this.generate(`Help with: ${topic}`, systemPrompt)\r\n } catch {\r\n return 'Could not get help for this topic.'\r\n }\r\n }\r\n\r\n /**\r\n * Convert natural language to a command\r\n */\r\n async naturalToCommand(description: string): Promise<string | null> {\r\n const systemPrompt = `You are Bash Bro, a helpful command-line assistant.\r\nConvert the user's request into a single command line.\r\nRespond with ONLY the command, no explanation.\r\nIf you can't convert it, respond with \"none\".`\r\n\r\n try {\r\n const response = await this.generate(description, systemPrompt)\r\n const command = response.trim()\r\n\r\n if (command.toLowerCase() === 'none' || command.length > 300) {\r\n return null\r\n }\r\n\r\n return command\r\n } catch {\r\n return null\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|