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
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
findConfig,
|
|
4
4
|
getDefaultConfig,
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RTZ4QWG2.js";
|
|
7
7
|
import "./chunk-7OCVIDC7.js";
|
|
8
8
|
export {
|
|
9
9
|
findConfig,
|
|
10
10
|
getDefaultConfig,
|
|
11
11
|
loadConfig
|
|
12
12
|
};
|
|
13
|
-
//# sourceMappingURL=config-
|
|
13
|
+
//# sourceMappingURL=config-I5NCK3RJ.js.map
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
DashboardDB,
|
|
4
4
|
db_default
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RDNSS3ME.js";
|
|
6
6
|
import "./chunk-7OCVIDC7.js";
|
|
7
7
|
export {
|
|
8
8
|
DashboardDB,
|
|
9
9
|
db_default as default
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=db-
|
|
11
|
+
//# sourceMappingURL=db-ETWTBXAE.js.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-7OCVIDC7.js";
|
|
3
|
+
|
|
4
|
+
// src/policy/db-checks.ts
|
|
5
|
+
function normalize(command) {
|
|
6
|
+
return command.toLowerCase().replace(/["']/g, "").replace(/\s+/g, " ").replace(/\d+/g, "N").replace(/[a-f0-9]{8,}/gi, "H").trim();
|
|
7
|
+
}
|
|
8
|
+
function jaccardSimilarity(a, b) {
|
|
9
|
+
const wordsA = new Set(a.split(/\s+/));
|
|
10
|
+
const wordsB = new Set(b.split(/\s+/));
|
|
11
|
+
const intersection = new Set([...wordsA].filter((x) => wordsB.has(x)));
|
|
12
|
+
const union = /* @__PURE__ */ new Set([...wordsA, ...wordsB]);
|
|
13
|
+
if (union.size === 0) return 1;
|
|
14
|
+
return intersection.size / union.size;
|
|
15
|
+
}
|
|
16
|
+
function checkLoopDetection(command, config, db) {
|
|
17
|
+
if (!config.enabled) return { violation: null, warning: null };
|
|
18
|
+
const totalCount = db.getTotalCommandCount();
|
|
19
|
+
if (totalCount >= config.maxTurns) {
|
|
20
|
+
const msg = `Maximum turns reached (${config.maxTurns}). Session may be stuck.`;
|
|
21
|
+
if (config.action === "block") {
|
|
22
|
+
return { violation: { type: "loop", rule: "max_turns", message: msg }, warning: null };
|
|
23
|
+
}
|
|
24
|
+
return { violation: null, warning: msg };
|
|
25
|
+
}
|
|
26
|
+
const recent = db.getRecentCommandTexts(config.windowSize);
|
|
27
|
+
const exactCount = recent.filter((r) => r.command === command).length;
|
|
28
|
+
if (exactCount >= config.maxRepeats) {
|
|
29
|
+
const msg = `Command repeated ${exactCount + 1} times: "${command.slice(0, 50)}"`;
|
|
30
|
+
if (config.action === "block") {
|
|
31
|
+
return { violation: { type: "loop", rule: "exact_repeat", message: msg }, warning: null };
|
|
32
|
+
}
|
|
33
|
+
return { violation: null, warning: msg };
|
|
34
|
+
}
|
|
35
|
+
const normalizedCmd = normalize(command);
|
|
36
|
+
const similarCount = recent.filter(
|
|
37
|
+
(r) => jaccardSimilarity(normalize(r.command), normalizedCmd) >= config.similarityThreshold
|
|
38
|
+
).length;
|
|
39
|
+
if (similarCount >= config.maxRepeats) {
|
|
40
|
+
const msg = `Similar commands repeated ${similarCount + 1} times`;
|
|
41
|
+
if (config.action === "block") {
|
|
42
|
+
return { violation: { type: "loop", rule: "semantic_repeat", message: msg }, warning: null };
|
|
43
|
+
}
|
|
44
|
+
return { violation: null, warning: msg };
|
|
45
|
+
}
|
|
46
|
+
return { violation: null, warning: null };
|
|
47
|
+
}
|
|
48
|
+
var DEFAULT_SUSPICIOUS_PATTERNS = [
|
|
49
|
+
/\bpasswd\b/,
|
|
50
|
+
/\bshadow\b/,
|
|
51
|
+
/\/root\//,
|
|
52
|
+
/\.ssh\//,
|
|
53
|
+
/\.gnupg\//,
|
|
54
|
+
/\.aws\//,
|
|
55
|
+
/\.kube\//,
|
|
56
|
+
/wallet/i,
|
|
57
|
+
/crypto/i,
|
|
58
|
+
/bitcoin/i,
|
|
59
|
+
/ethereum/i,
|
|
60
|
+
/private.*key/i
|
|
61
|
+
];
|
|
62
|
+
function checkAnomalyDetection(command, config, db) {
|
|
63
|
+
if (!config.enabled) return { violation: null, warning: null };
|
|
64
|
+
const totalCount = db.getTotalCommandCount();
|
|
65
|
+
if (totalCount < config.learningCommands) {
|
|
66
|
+
return { violation: null, warning: null };
|
|
67
|
+
}
|
|
68
|
+
const findings = [];
|
|
69
|
+
const hour = (/* @__PURE__ */ new Date()).getHours();
|
|
70
|
+
const [start, end] = config.workingHours;
|
|
71
|
+
if (hour < start || hour >= end) {
|
|
72
|
+
findings.push(`Activity outside working hours (${hour}:00, allowed ${start}-${end})`);
|
|
73
|
+
}
|
|
74
|
+
const oneMinuteAgo = new Date(Date.now() - 6e4).toISOString();
|
|
75
|
+
const recentCount = db.getCommandCountSince(oneMinuteAgo);
|
|
76
|
+
if (recentCount > config.typicalCommandsPerMinute * 2) {
|
|
77
|
+
findings.push(`High command rate: ${recentCount}/min (typical: ${config.typicalCommandsPerMinute})`);
|
|
78
|
+
}
|
|
79
|
+
const configPatterns = (config.suspiciousPatterns || []).map((p) => {
|
|
80
|
+
try {
|
|
81
|
+
return new RegExp(p, "i");
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}).filter((p) => p !== null);
|
|
86
|
+
const allPatterns = [...DEFAULT_SUSPICIOUS_PATTERNS, ...configPatterns];
|
|
87
|
+
for (const pattern of allPatterns) {
|
|
88
|
+
if (pattern.test(command)) {
|
|
89
|
+
findings.push(`Suspicious pattern: ${pattern.source}`);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (findings.length === 0) return { violation: null, warning: null };
|
|
94
|
+
const msg = `Anomaly: ${findings.join("; ")}`;
|
|
95
|
+
if (config.action === "block") {
|
|
96
|
+
return { violation: { type: "anomaly", rule: "anomaly_detection", message: msg }, warning: null };
|
|
97
|
+
}
|
|
98
|
+
return { violation: null, warning: msg };
|
|
99
|
+
}
|
|
100
|
+
function checkRateLimit(config, db) {
|
|
101
|
+
if (!config.enabled) return { violation: null, warning: null };
|
|
102
|
+
const oneMinuteAgo = new Date(Date.now() - 6e4).toISOString();
|
|
103
|
+
const perMinute = db.getCommandCountSince(oneMinuteAgo);
|
|
104
|
+
if (perMinute >= config.maxPerMinute) {
|
|
105
|
+
return {
|
|
106
|
+
violation: {
|
|
107
|
+
type: "rate_limit",
|
|
108
|
+
rule: "rate_per_minute",
|
|
109
|
+
message: `Rate limit exceeded: ${perMinute}/${config.maxPerMinute} per minute`
|
|
110
|
+
},
|
|
111
|
+
warning: null
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const oneHourAgo = new Date(Date.now() - 36e5).toISOString();
|
|
115
|
+
const perHour = db.getCommandCountSince(oneHourAgo);
|
|
116
|
+
if (perHour >= config.maxPerHour) {
|
|
117
|
+
return {
|
|
118
|
+
violation: {
|
|
119
|
+
type: "rate_limit",
|
|
120
|
+
rule: "rate_per_hour",
|
|
121
|
+
message: `Rate limit exceeded: ${perHour}/${config.maxPerHour} per hour`
|
|
122
|
+
},
|
|
123
|
+
warning: null
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return { violation: null, warning: null };
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
checkAnomalyDetection,
|
|
130
|
+
checkLoopDetection,
|
|
131
|
+
checkRateLimit
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=db-checks-2YOVECD4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/policy/db-checks.ts"],"sourcesContent":["/**\r\n * DB-backed cross-process security checks\r\n * Each function takes a DashboardDB + config section and returns a violation or warning.\r\n */\r\n\r\nimport type { DashboardDB } from '../dashboard/db.js'\r\nimport type {\r\n LoopDetectionPolicy,\r\n AnomalyDetectionPolicy,\r\n RateLimitPolicy,\r\n PolicyViolation\r\n} from '../types.js'\r\n\r\nexport interface CheckResult {\r\n violation: PolicyViolation | null\r\n warning: string | null\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────\r\n// Helpers (mirrored from LoopDetector for DB-backed checks)\r\n// ─────────────────────────────────────────────────────────────\r\n\r\nfunction normalize(command: string): string {\r\n return command\r\n .toLowerCase()\r\n .replace(/[\"']/g, '')\r\n .replace(/\\s+/g, ' ')\r\n .replace(/\\d+/g, 'N')\r\n .replace(/[a-f0-9]{8,}/gi, 'H')\r\n .trim()\r\n}\r\n\r\nfunction jaccardSimilarity(a: string, b: string): number {\r\n const wordsA = new Set(a.split(/\\s+/))\r\n const wordsB = new Set(b.split(/\\s+/))\r\n const intersection = new Set([...wordsA].filter(x => wordsB.has(x)))\r\n const union = new Set([...wordsA, ...wordsB])\r\n if (union.size === 0) return 1\r\n return intersection.size / union.size\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────\r\n// Loop Detection (DB-backed)\r\n// ─────────────────────────────────────────────────────────────\r\n\r\nexport function checkLoopDetection(\r\n command: string,\r\n config: LoopDetectionPolicy,\r\n db: DashboardDB\r\n): CheckResult {\r\n if (!config.enabled) return { violation: null, warning: null }\r\n\r\n // Check max turns\r\n const totalCount = db.getTotalCommandCount()\r\n if (totalCount >= config.maxTurns) {\r\n const msg = `Maximum turns reached (${config.maxTurns}). Session may be stuck.`\r\n if (config.action === 'block') {\r\n return { violation: { type: 'loop', rule: 'max_turns', message: msg }, warning: null }\r\n }\r\n return { violation: null, warning: msg }\r\n }\r\n\r\n // Check recent commands for repeats\r\n const recent = db.getRecentCommandTexts(config.windowSize)\r\n\r\n // Exact repeats\r\n const exactCount = recent.filter(r => r.command === command).length\r\n if (exactCount >= config.maxRepeats) {\r\n const msg = `Command repeated ${exactCount + 1} times: \"${command.slice(0, 50)}\"`\r\n if (config.action === 'block') {\r\n return { violation: { type: 'loop', rule: 'exact_repeat', message: msg }, warning: null }\r\n }\r\n return { violation: null, warning: msg }\r\n }\r\n\r\n // Semantic repeats\r\n const normalizedCmd = normalize(command)\r\n const similarCount = recent.filter(\r\n r => jaccardSimilarity(normalize(r.command), normalizedCmd) >= config.similarityThreshold\r\n ).length\r\n if (similarCount >= config.maxRepeats) {\r\n const msg = `Similar commands repeated ${similarCount + 1} times`\r\n if (config.action === 'block') {\r\n return { violation: { type: 'loop', rule: 'semantic_repeat', message: msg }, warning: null }\r\n }\r\n return { violation: null, warning: msg }\r\n }\r\n\r\n return { violation: null, warning: null }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────\r\n// Anomaly Detection (DB-backed)\r\n// ─────────────────────────────────────────────────────────────\r\n\r\n// Default suspicious patterns (same as anomaly-detector.ts)\r\nconst DEFAULT_SUSPICIOUS_PATTERNS: RegExp[] = [\r\n /\\bpasswd\\b/,\r\n /\\bshadow\\b/,\r\n /\\/root\\//,\r\n /\\.ssh\\//,\r\n /\\.gnupg\\//,\r\n /\\.aws\\//,\r\n /\\.kube\\//,\r\n /wallet/i,\r\n /crypto/i,\r\n /bitcoin/i,\r\n /ethereum/i,\r\n /private.*key/i,\r\n]\r\n\r\nexport function checkAnomalyDetection(\r\n command: string,\r\n config: AnomalyDetectionPolicy,\r\n db: DashboardDB\r\n): CheckResult {\r\n if (!config.enabled) return { violation: null, warning: null }\r\n\r\n // Still learning — skip checks\r\n const totalCount = db.getTotalCommandCount()\r\n if (totalCount < config.learningCommands) {\r\n return { violation: null, warning: null }\r\n }\r\n\r\n const findings: string[] = []\r\n\r\n // Check working hours\r\n const hour = new Date().getHours()\r\n const [start, end] = config.workingHours\r\n if (hour < start || hour >= end) {\r\n findings.push(`Activity outside working hours (${hour}:00, allowed ${start}-${end})`)\r\n }\r\n\r\n // Check frequency (commands in last minute)\r\n const oneMinuteAgo = new Date(Date.now() - 60_000).toISOString()\r\n const recentCount = db.getCommandCountSince(oneMinuteAgo)\r\n if (recentCount > config.typicalCommandsPerMinute * 2) {\r\n findings.push(`High command rate: ${recentCount}/min (typical: ${config.typicalCommandsPerMinute})`)\r\n }\r\n\r\n // Check suspicious patterns (config + built-in)\r\n const configPatterns = (config.suspiciousPatterns || []).map(p => {\r\n try { return new RegExp(p, 'i') } catch { return null }\r\n }).filter((p): p is RegExp => p !== null)\r\n\r\n const allPatterns = [...DEFAULT_SUSPICIOUS_PATTERNS, ...configPatterns]\r\n for (const pattern of allPatterns) {\r\n if (pattern.test(command)) {\r\n findings.push(`Suspicious pattern: ${pattern.source}`)\r\n break // one is enough\r\n }\r\n }\r\n\r\n if (findings.length === 0) return { violation: null, warning: null }\r\n\r\n const msg = `Anomaly: ${findings.join('; ')}`\r\n if (config.action === 'block') {\r\n return { violation: { type: 'anomaly', rule: 'anomaly_detection', message: msg }, warning: null }\r\n }\r\n return { violation: null, warning: msg }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────\r\n// Rate Limiting (DB-backed)\r\n// ─────────────────────────────────────────────────────────────\r\n\r\nexport function checkRateLimit(\r\n config: RateLimitPolicy,\r\n db: DashboardDB\r\n): CheckResult {\r\n if (!config.enabled) return { violation: null, warning: null }\r\n\r\n // Per-minute check\r\n const oneMinuteAgo = new Date(Date.now() - 60_000).toISOString()\r\n const perMinute = db.getCommandCountSince(oneMinuteAgo)\r\n if (perMinute >= config.maxPerMinute) {\r\n return {\r\n violation: {\r\n type: 'rate_limit',\r\n rule: 'rate_per_minute',\r\n message: `Rate limit exceeded: ${perMinute}/${config.maxPerMinute} per minute`\r\n },\r\n warning: null\r\n }\r\n }\r\n\r\n // Per-hour check\r\n const oneHourAgo = new Date(Date.now() - 3_600_000).toISOString()\r\n const perHour = db.getCommandCountSince(oneHourAgo)\r\n if (perHour >= config.maxPerHour) {\r\n return {\r\n violation: {\r\n type: 'rate_limit',\r\n rule: 'rate_per_hour',\r\n message: `Rate limit exceeded: ${perHour}/${config.maxPerHour} per hour`\r\n },\r\n warning: null\r\n }\r\n }\r\n\r\n return { violation: null, warning: null }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
formatAllAgentsInfo,
|
|
6
6
|
formatPermissionsTable,
|
|
7
7
|
getEffectivePermissions
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-CG6VEHJM.js";
|
|
9
|
+
import "./chunk-RTZ4QWG2.js";
|
|
10
10
|
import "./chunk-7OCVIDC7.js";
|
|
11
11
|
export {
|
|
12
12
|
formatAgentInfo,
|
|
@@ -15,4 +15,4 @@ export {
|
|
|
15
15
|
formatPermissionsTable,
|
|
16
16
|
getEffectivePermissions
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=display-
|
|
18
|
+
//# sourceMappingURL=display-UH7KEHOW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ interface BashBrosConfig {
|
|
|
16
16
|
ward: WardPolicy;
|
|
17
17
|
dashboard: DashboardPolicy;
|
|
18
18
|
}
|
|
19
|
-
type AgentType = 'claude-code' | 'clawdbot' | 'moltbot' | 'gemini-cli' | 'aider' | 'opencode' | 'custom';
|
|
19
|
+
type AgentType = 'claude-code' | 'clawdbot' | 'moltbot' | 'gemini-cli' | 'copilot-cli' | 'aider' | 'opencode' | 'custom';
|
|
20
20
|
interface MoltbotGatewayInfo {
|
|
21
21
|
port: number;
|
|
22
22
|
host: string;
|
|
@@ -117,7 +117,7 @@ interface CommandResult {
|
|
|
117
117
|
violations: PolicyViolation[];
|
|
118
118
|
}
|
|
119
119
|
interface PolicyViolation {
|
|
120
|
-
type: 'command' | 'path' | 'secrets' | 'rate_limit';
|
|
120
|
+
type: 'command' | 'path' | 'secrets' | 'rate_limit' | 'risk_score' | 'loop' | 'anomaly' | 'output';
|
|
121
121
|
rule: string;
|
|
122
122
|
message: string;
|
|
123
123
|
}
|
|
@@ -311,6 +311,133 @@ declare class SystemProfiler {
|
|
|
311
311
|
toContext(): string;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Simple Ollama client for local model inference.
|
|
316
|
+
* Keeps it minimal - just what we need for Bash Bro.
|
|
317
|
+
*/
|
|
318
|
+
interface OllamaConfig {
|
|
319
|
+
host: string;
|
|
320
|
+
model: string;
|
|
321
|
+
timeout: number;
|
|
322
|
+
}
|
|
323
|
+
interface ChatMessage {
|
|
324
|
+
role: 'system' | 'user' | 'assistant';
|
|
325
|
+
content: string;
|
|
326
|
+
}
|
|
327
|
+
interface ModelInfo {
|
|
328
|
+
modelfile: string;
|
|
329
|
+
parameters: string;
|
|
330
|
+
template: string;
|
|
331
|
+
details: {
|
|
332
|
+
parent_model: string;
|
|
333
|
+
format: string;
|
|
334
|
+
family: string;
|
|
335
|
+
families: string[];
|
|
336
|
+
parameter_size: string;
|
|
337
|
+
quantization_level: string;
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
interface RunningModel {
|
|
341
|
+
name: string;
|
|
342
|
+
model: string;
|
|
343
|
+
size: number;
|
|
344
|
+
size_vram: number;
|
|
345
|
+
digest: string;
|
|
346
|
+
details: {
|
|
347
|
+
family: string;
|
|
348
|
+
parameter_size: string;
|
|
349
|
+
quantization_level: string;
|
|
350
|
+
};
|
|
351
|
+
expires_at: string;
|
|
352
|
+
}
|
|
353
|
+
declare class OllamaClient {
|
|
354
|
+
private config;
|
|
355
|
+
constructor(config?: Partial<OllamaConfig>);
|
|
356
|
+
/**
|
|
357
|
+
* Check if Ollama is running and accessible
|
|
358
|
+
*/
|
|
359
|
+
isAvailable(): Promise<boolean>;
|
|
360
|
+
/**
|
|
361
|
+
* List available models
|
|
362
|
+
*/
|
|
363
|
+
listModels(): Promise<string[]>;
|
|
364
|
+
/**
|
|
365
|
+
* Generate a response from the model
|
|
366
|
+
*/
|
|
367
|
+
generate(prompt: string, systemPrompt?: string): Promise<string>;
|
|
368
|
+
/**
|
|
369
|
+
* Chat with the model (multi-turn conversation)
|
|
370
|
+
*/
|
|
371
|
+
chat(messages: ChatMessage[]): Promise<string>;
|
|
372
|
+
/**
|
|
373
|
+
* Ask Bash Bro to suggest a command
|
|
374
|
+
*/
|
|
375
|
+
suggestCommand(context: string): Promise<string | null>;
|
|
376
|
+
/**
|
|
377
|
+
* Ask Bash Bro to explain a command
|
|
378
|
+
*/
|
|
379
|
+
explainCommand(command: string): Promise<string>;
|
|
380
|
+
/**
|
|
381
|
+
* Ask Bash Bro to fix a command that failed
|
|
382
|
+
*/
|
|
383
|
+
fixCommand(command: string, error: string): Promise<string | null>;
|
|
384
|
+
/**
|
|
385
|
+
* Show detailed info about a model
|
|
386
|
+
*/
|
|
387
|
+
showModel(name: string): Promise<ModelInfo | null>;
|
|
388
|
+
/**
|
|
389
|
+
* Delete a model
|
|
390
|
+
*/
|
|
391
|
+
deleteModel(name: string): Promise<boolean>;
|
|
392
|
+
/**
|
|
393
|
+
* List currently running models
|
|
394
|
+
*/
|
|
395
|
+
listRunning(): Promise<RunningModel[]>;
|
|
396
|
+
/**
|
|
397
|
+
* Pull a model from the registry
|
|
398
|
+
*/
|
|
399
|
+
pullModel(name: string): Promise<boolean>;
|
|
400
|
+
/**
|
|
401
|
+
* Create a model from a Modelfile
|
|
402
|
+
*/
|
|
403
|
+
createModel(name: string, modelfile: string): Promise<boolean>;
|
|
404
|
+
setModel(model: string): void;
|
|
405
|
+
getModel(): string;
|
|
406
|
+
/**
|
|
407
|
+
* Generate a shell script from a natural language description
|
|
408
|
+
*/
|
|
409
|
+
generateScript(description: string, shell?: string): Promise<string | null>;
|
|
410
|
+
/**
|
|
411
|
+
* Analyze command safety and provide recommendations
|
|
412
|
+
*/
|
|
413
|
+
analyzeCommandSafety(command: string): Promise<{
|
|
414
|
+
safe: boolean;
|
|
415
|
+
risk: 'low' | 'medium' | 'high' | 'critical';
|
|
416
|
+
explanation: string;
|
|
417
|
+
suggestions: string[];
|
|
418
|
+
}>;
|
|
419
|
+
/**
|
|
420
|
+
* Summarize a series of commands and their outputs
|
|
421
|
+
*/
|
|
422
|
+
summarizeSession(commands: {
|
|
423
|
+
command: string;
|
|
424
|
+
output?: string;
|
|
425
|
+
error?: string;
|
|
426
|
+
}[]): Promise<string>;
|
|
427
|
+
/**
|
|
428
|
+
* Get help for a specific tool or command
|
|
429
|
+
*/
|
|
430
|
+
getHelp(topic: string): Promise<string>;
|
|
431
|
+
/**
|
|
432
|
+
* Convert natural language to a command
|
|
433
|
+
*/
|
|
434
|
+
naturalToCommand(description: string): Promise<string | null>;
|
|
435
|
+
/**
|
|
436
|
+
* Generate with a temporary model override (for adapter-specific calls)
|
|
437
|
+
*/
|
|
438
|
+
generateWithAdapter(modelOverride: string, prompt: string, systemPrompt?: string): Promise<string>;
|
|
439
|
+
}
|
|
440
|
+
|
|
314
441
|
type RouteDecision = 'bro' | 'main' | 'both';
|
|
315
442
|
interface RoutingResult {
|
|
316
443
|
decision: RouteDecision;
|
|
@@ -320,9 +447,11 @@ interface RoutingResult {
|
|
|
320
447
|
declare class TaskRouter {
|
|
321
448
|
private rules;
|
|
322
449
|
private profile;
|
|
323
|
-
|
|
450
|
+
private ollama;
|
|
451
|
+
constructor(profile?: SystemProfile | null, ollama?: OllamaClient | null);
|
|
324
452
|
private buildDefaultRules;
|
|
325
453
|
route(command: string): RoutingResult;
|
|
454
|
+
routeAsync(command: string): Promise<RoutingResult>;
|
|
326
455
|
private looksSimple;
|
|
327
456
|
addRule(pattern: RegExp, route: RouteDecision, reason: string): void;
|
|
328
457
|
updateProfile(profile: SystemProfile): void;
|
|
@@ -338,9 +467,12 @@ declare class CommandSuggester {
|
|
|
338
467
|
private history;
|
|
339
468
|
private profile;
|
|
340
469
|
private patterns;
|
|
341
|
-
|
|
470
|
+
private ollama;
|
|
471
|
+
private aiCache;
|
|
472
|
+
constructor(profile?: SystemProfile | null, ollama?: OllamaClient | null);
|
|
342
473
|
private initPatterns;
|
|
343
474
|
suggest(context: SuggestionContext): Suggestion[];
|
|
475
|
+
suggestAsync(context: SuggestionContext): Promise<Suggestion[]>;
|
|
344
476
|
private suggestFromPatterns;
|
|
345
477
|
private suggestFromHistory;
|
|
346
478
|
private suggestFromContext;
|
|
@@ -381,6 +513,23 @@ declare class BackgroundWorker extends EventEmitter {
|
|
|
381
513
|
formatStatus(): string;
|
|
382
514
|
}
|
|
383
515
|
|
|
516
|
+
type AdapterPurpose = 'suggest' | 'safety' | 'route' | 'explain' | 'fix' | 'script' | 'general';
|
|
517
|
+
interface AdapterEntry {
|
|
518
|
+
name: string;
|
|
519
|
+
baseModel: string;
|
|
520
|
+
purpose: AdapterPurpose;
|
|
521
|
+
adapterPath: string;
|
|
522
|
+
trainedAt: string;
|
|
523
|
+
tracesUsed: number;
|
|
524
|
+
qualityScore: number;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
interface ModelProfile {
|
|
528
|
+
name: string;
|
|
529
|
+
baseModel: string;
|
|
530
|
+
adapters: Partial<Record<AdapterPurpose, string>>;
|
|
531
|
+
}
|
|
532
|
+
|
|
384
533
|
interface BroConfig {
|
|
385
534
|
modelEndpoint?: string;
|
|
386
535
|
modelName?: string;
|
|
@@ -389,6 +538,7 @@ interface BroConfig {
|
|
|
389
538
|
enableBackground?: boolean;
|
|
390
539
|
enableOllama?: boolean;
|
|
391
540
|
enableBashgymIntegration?: boolean;
|
|
541
|
+
activeProfile?: string;
|
|
392
542
|
}
|
|
393
543
|
declare class BashBro extends EventEmitter {
|
|
394
544
|
private profiler;
|
|
@@ -400,6 +550,9 @@ declare class BashBro extends EventEmitter {
|
|
|
400
550
|
private config;
|
|
401
551
|
private ollamaAvailable;
|
|
402
552
|
private bashgymModelVersion;
|
|
553
|
+
private adapterRegistry;
|
|
554
|
+
private profileManager;
|
|
555
|
+
private activeProfile;
|
|
403
556
|
constructor(config?: BroConfig);
|
|
404
557
|
/**
|
|
405
558
|
* Initialize bashgym integration for model hot-swap
|
|
@@ -414,6 +567,14 @@ declare class BashBro extends EventEmitter {
|
|
|
414
567
|
scanProject(projectPath: string): void;
|
|
415
568
|
route(command: string): RoutingResult;
|
|
416
569
|
suggest(context: SuggestionContext): Suggestion[];
|
|
570
|
+
/**
|
|
571
|
+
* AI-enhanced async routing - uses pattern matching first, falls back to Ollama
|
|
572
|
+
*/
|
|
573
|
+
routeAsync(command: string): Promise<RoutingResult>;
|
|
574
|
+
/**
|
|
575
|
+
* AI-enhanced async suggestions - pattern matching + Ollama suggestions with caching
|
|
576
|
+
*/
|
|
577
|
+
suggestAsync(context: SuggestionContext): Promise<Suggestion[]>;
|
|
417
578
|
/**
|
|
418
579
|
* SECURITY FIX: Safe command execution with validation
|
|
419
580
|
*/
|
|
@@ -484,84 +645,27 @@ declare class BashBro extends EventEmitter {
|
|
|
484
645
|
* Force refresh the bashgym model (check for updates)
|
|
485
646
|
*/
|
|
486
647
|
refreshBashgymModel(): boolean;
|
|
487
|
-
status(): string;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Simple Ollama client for local model inference.
|
|
492
|
-
* Keeps it minimal - just what we need for Bash Bro.
|
|
493
|
-
*/
|
|
494
|
-
interface OllamaConfig {
|
|
495
|
-
host: string;
|
|
496
|
-
model: string;
|
|
497
|
-
timeout: number;
|
|
498
|
-
}
|
|
499
|
-
interface ChatMessage {
|
|
500
|
-
role: 'system' | 'user' | 'assistant';
|
|
501
|
-
content: string;
|
|
502
|
-
}
|
|
503
|
-
declare class OllamaClient {
|
|
504
|
-
private config;
|
|
505
|
-
constructor(config?: Partial<OllamaConfig>);
|
|
506
|
-
/**
|
|
507
|
-
* Check if Ollama is running and accessible
|
|
508
|
-
*/
|
|
509
|
-
isAvailable(): Promise<boolean>;
|
|
510
|
-
/**
|
|
511
|
-
* List available models
|
|
512
|
-
*/
|
|
513
|
-
listModels(): Promise<string[]>;
|
|
514
|
-
/**
|
|
515
|
-
* Generate a response from the model
|
|
516
|
-
*/
|
|
517
|
-
generate(prompt: string, systemPrompt?: string): Promise<string>;
|
|
518
|
-
/**
|
|
519
|
-
* Chat with the model (multi-turn conversation)
|
|
520
|
-
*/
|
|
521
|
-
chat(messages: ChatMessage[]): Promise<string>;
|
|
522
648
|
/**
|
|
523
|
-
*
|
|
524
|
-
*/
|
|
525
|
-
suggestCommand(context: string): Promise<string | null>;
|
|
526
|
-
/**
|
|
527
|
-
* Ask Bash Bro to explain a command
|
|
649
|
+
* Get model name for a specific purpose (checks active profile for adapter override)
|
|
528
650
|
*/
|
|
529
|
-
|
|
651
|
+
private getModelForPurpose;
|
|
530
652
|
/**
|
|
531
|
-
*
|
|
653
|
+
* Get discovered LoRA adapters
|
|
532
654
|
*/
|
|
533
|
-
|
|
534
|
-
setModel(model: string): void;
|
|
535
|
-
getModel(): string;
|
|
536
|
-
/**
|
|
537
|
-
* Generate a shell script from a natural language description
|
|
538
|
-
*/
|
|
539
|
-
generateScript(description: string, shell?: string): Promise<string | null>;
|
|
540
|
-
/**
|
|
541
|
-
* Analyze command safety and provide recommendations
|
|
542
|
-
*/
|
|
543
|
-
analyzeCommandSafety(command: string): Promise<{
|
|
544
|
-
safe: boolean;
|
|
545
|
-
risk: 'low' | 'medium' | 'high' | 'critical';
|
|
546
|
-
explanation: string;
|
|
547
|
-
suggestions: string[];
|
|
548
|
-
}>;
|
|
655
|
+
getAdapters(): AdapterEntry[];
|
|
549
656
|
/**
|
|
550
|
-
*
|
|
657
|
+
* Get available model profiles
|
|
551
658
|
*/
|
|
552
|
-
|
|
553
|
-
command: string;
|
|
554
|
-
output?: string;
|
|
555
|
-
error?: string;
|
|
556
|
-
}[]): Promise<string>;
|
|
659
|
+
getProfiles(): ModelProfile[];
|
|
557
660
|
/**
|
|
558
|
-
* Get
|
|
661
|
+
* Get the active model profile
|
|
559
662
|
*/
|
|
560
|
-
|
|
663
|
+
getActiveProfile(): ModelProfile | null;
|
|
561
664
|
/**
|
|
562
|
-
*
|
|
665
|
+
* Set the active model profile by name
|
|
563
666
|
*/
|
|
564
|
-
|
|
667
|
+
setActiveProfile(name: string): boolean;
|
|
668
|
+
status(): string;
|
|
565
669
|
}
|
|
566
670
|
|
|
567
671
|
/**
|
|
@@ -1073,8 +1177,27 @@ declare class ClaudeCodeHooks {
|
|
|
1073
1177
|
static getStatus(): {
|
|
1074
1178
|
claudeInstalled: boolean;
|
|
1075
1179
|
hooksInstalled: boolean;
|
|
1180
|
+
allToolsInstalled: boolean;
|
|
1076
1181
|
hooks: string[];
|
|
1077
1182
|
};
|
|
1183
|
+
/**
|
|
1184
|
+
* Check if all-tools recording is installed
|
|
1185
|
+
*/
|
|
1186
|
+
static isAllToolsInstalled(settings?: ClaudeSettings): boolean;
|
|
1187
|
+
/**
|
|
1188
|
+
* Install all-tools recording hook (records ALL Claude Code tools, not just Bash)
|
|
1189
|
+
*/
|
|
1190
|
+
static installAllTools(): {
|
|
1191
|
+
success: boolean;
|
|
1192
|
+
message: string;
|
|
1193
|
+
};
|
|
1194
|
+
/**
|
|
1195
|
+
* Uninstall all-tools recording hook
|
|
1196
|
+
*/
|
|
1197
|
+
static uninstallAllTools(): {
|
|
1198
|
+
success: boolean;
|
|
1199
|
+
message: string;
|
|
1200
|
+
};
|
|
1078
1201
|
}
|
|
1079
1202
|
/**
|
|
1080
1203
|
* Gate command - called by PreToolUse hook
|