brosh 0.2.2
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 +181 -0
- package/brosh_brandmark.svg +3 -0
- package/brosh_logo.svg +27 -0
- package/cli_icon.svg +52 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +138 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +618 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.d.ts +25 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +28 -0
- package/dist/lib.js.map +1 -0
- package/dist/mode-selector.d.ts +7 -0
- package/dist/mode-selector.d.ts.map +1 -0
- package/dist/mode-selector.js +138 -0
- package/dist/mode-selector.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +79 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/recording/index.d.ts +4 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/manager.d.ts +62 -0
- package/dist/recording/manager.d.ts.map +1 -0
- package/dist/recording/manager.js +123 -0
- package/dist/recording/manager.js.map +1 -0
- package/dist/recording/recorder.d.ts +95 -0
- package/dist/recording/recorder.d.ts.map +1 -0
- package/dist/recording/recorder.js +330 -0
- package/dist/recording/recorder.js.map +1 -0
- package/dist/recording/types.d.ts +65 -0
- package/dist/recording/types.d.ts.map +1 -0
- package/dist/recording/types.js +2 -0
- package/dist/recording/types.js.map +1 -0
- package/dist/sandbox/ModeSelector.d.ts +2 -0
- package/dist/sandbox/ModeSelector.d.ts.map +1 -0
- package/dist/sandbox/ModeSelector.js +2 -0
- package/dist/sandbox/ModeSelector.js.map +1 -0
- package/dist/sandbox/config.d.ts +46 -0
- package/dist/sandbox/config.d.ts.map +1 -0
- package/dist/sandbox/config.js +144 -0
- package/dist/sandbox/config.js.map +1 -0
- package/dist/sandbox/controller.d.ts +72 -0
- package/dist/sandbox/controller.d.ts.map +1 -0
- package/dist/sandbox/controller.js +208 -0
- package/dist/sandbox/controller.js.map +1 -0
- package/dist/sandbox/index.d.ts +6 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/mode-prompt.d.ts +10 -0
- package/dist/sandbox/mode-prompt.d.ts.map +1 -0
- package/dist/sandbox/mode-prompt.js +130 -0
- package/dist/sandbox/mode-prompt.js.map +1 -0
- package/dist/sandbox/prompt.d.ts +10 -0
- package/dist/sandbox/prompt.d.ts.map +1 -0
- package/dist/sandbox/prompt.js +434 -0
- package/dist/sandbox/prompt.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +59 -0
- package/dist/server.js.map +1 -0
- package/dist/terminal/index.d.ts +5 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +3 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/manager.d.ts +153 -0
- package/dist/terminal/manager.d.ts.map +1 -0
- package/dist/terminal/manager.js +276 -0
- package/dist/terminal/manager.js.map +1 -0
- package/dist/terminal/session.d.ts +137 -0
- package/dist/terminal/session.d.ts.map +1 -0
- package/dist/terminal/session.js +752 -0
- package/dist/terminal/session.js.map +1 -0
- package/dist/tools/definitions.d.ts +18 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +114 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/getContent.d.ts +32 -0
- package/dist/tools/getContent.d.ts.map +1 -0
- package/dist/tools/getContent.js +38 -0
- package/dist/tools/getContent.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +49 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/screenshot.d.ts +20 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +28 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/sendKey.d.ts +31 -0
- package/dist/tools/sendKey.d.ts.map +1 -0
- package/dist/tools/sendKey.js +38 -0
- package/dist/tools/sendKey.js.map +1 -0
- package/dist/tools/startRecording.d.ts +68 -0
- package/dist/tools/startRecording.d.ts.map +1 -0
- package/dist/tools/startRecording.js +111 -0
- package/dist/tools/startRecording.js.map +1 -0
- package/dist/tools/stopRecording.d.ts +31 -0
- package/dist/tools/stopRecording.d.ts.map +1 -0
- package/dist/tools/stopRecording.js +76 -0
- package/dist/tools/stopRecording.js.map +1 -0
- package/dist/tools/type.d.ts +31 -0
- package/dist/tools/type.d.ts.map +1 -0
- package/dist/tools/type.js +31 -0
- package/dist/tools/type.js.map +1 -0
- package/dist/transport/gui-protocol.d.ts +163 -0
- package/dist/transport/gui-protocol.d.ts.map +1 -0
- package/dist/transport/gui-protocol.js +68 -0
- package/dist/transport/gui-protocol.js.map +1 -0
- package/dist/transport/gui-stream.d.ts +139 -0
- package/dist/transport/gui-stream.d.ts.map +1 -0
- package/dist/transport/gui-stream.js +440 -0
- package/dist/transport/gui-stream.js.map +1 -0
- package/dist/transport/index.d.ts +6 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +6 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/socket.d.ts +46 -0
- package/dist/transport/socket.d.ts.map +1 -0
- package/dist/transport/socket.js +310 -0
- package/dist/transport/socket.js.map +1 -0
- package/dist/types/mcp-client-info.d.ts +226 -0
- package/dist/types/mcp-client-info.d.ts.map +1 -0
- package/dist/types/mcp-client-info.js +62 -0
- package/dist/types/mcp-client-info.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +84 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/utils/env.d.ts +17 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +35 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/keys.d.ts +16 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +155 -0
- package/dist/utils/keys.js.map +1 -0
- package/dist/utils/platform.d.ts +16 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +41 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/session-logger.d.ts +31 -0
- package/dist/utils/session-logger.d.ts.map +1 -0
- package/dist/utils/session-logger.js +125 -0
- package/dist/utils/session-logger.js.map +1 -0
- package/dist/utils/stats.d.ts +46 -0
- package/dist/utils/stats.d.ts.map +1 -0
- package/dist/utils/stats.js +89 -0
- package/dist/utils/stats.js.map +1 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +9 -0
- package/dist/utils/version.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +61 -0
- package/packages/desktop-electron/THIRD-PARTY-NOTICES +56 -0
- package/packages/desktop-electron/build/afterPack.cjs +147 -0
- package/packages/desktop-electron/package-lock.json +10071 -0
- package/packages/desktop-electron/package.json +170 -0
- package/packages/desktop-electron/resources/icons/mac/icon.icns +0 -0
- package/packages/desktop-electron/resources/icons/png/1024x1024.png +0 -0
- package/packages/desktop-electron/resources/icons/png/128x128.png +0 -0
- package/packages/desktop-electron/resources/icons/png/16x16.png +0 -0
- package/packages/desktop-electron/resources/icons/png/24x24.png +0 -0
- package/packages/desktop-electron/resources/icons/png/256x256.png +0 -0
- package/packages/desktop-electron/resources/icons/png/32x32.png +0 -0
- package/packages/desktop-electron/resources/icons/png/48x48.png +0 -0
- package/packages/desktop-electron/resources/icons/png/512x512.png +0 -0
- package/packages/desktop-electron/resources/icons/png/64x64.png +0 -0
- package/packages/desktop-electron/resources/icons/win/icon.ico +0 -0
- package/packages/desktop-electron/scripts/download-models.js +97 -0
- package/packages/desktop-electron/scripts/prepare-sandbox-bins.js +186 -0
- package/packages/desktop-electron/tests/main/ai-detection/additionalFunctions.test.ts +224 -0
- package/packages/desktop-electron/tests/main/ai-detection/checkOverridePrefix.test.ts +162 -0
- package/packages/desktop-electron/tests/main/ai-detection/classifyInput.test.ts +132 -0
- package/packages/desktop-electron/tests/main/ai-detection/detectTypos.test.ts +342 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/commands.ts +134 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/natural-language.ts +133 -0
- package/packages/desktop-electron/tests/main/ai-detection/fixtures/typos.ts +123 -0
- package/packages/desktop-electron/tests/main/ai-detection/hasValidSubcommand.test.ts +218 -0
- package/packages/desktop-electron/tests/main/ai-detection/isCommandNotFound.test.ts +117 -0
- package/packages/desktop-electron/tests/main/error-triage/buildTriagePrompt.test.ts +133 -0
- package/packages/desktop-electron/tests/main/error-triage/parseTriageResponse.test.ts +123 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/battery-optimization.test.ts +243 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/command-fast-track.test.ts +292 -0
- package/packages/desktop-electron/tests/main/terminal-bridge/default-cwd.test.ts +70 -0
- package/packages/desktop-electron/tests/setup.ts +274 -0
- package/packages/desktop-electron/tsconfig.json +18 -0
- package/packages/desktop-electron/tsconfig.main.json +20 -0
- package/packages/desktop-electron/vite.config.ts +19 -0
- package/packages/desktop-electron/vitest.config.ts +18 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tests for default cwd behavior in terminal sessions.
|
|
6
|
+
*
|
|
7
|
+
* When creating a new terminal session, if no cwd is specified,
|
|
8
|
+
* the session should start in the user's home directory.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
describe('Default CWD Behavior', () => {
|
|
12
|
+
describe('cwd fallback logic', () => {
|
|
13
|
+
// This tests the logic pattern used in terminal-bridge.ts:
|
|
14
|
+
// const cwd = options?.cwd ?? os.homedir();
|
|
15
|
+
|
|
16
|
+
it('should return provided cwd when specified', () => {
|
|
17
|
+
const options = { cwd: '/custom/path' };
|
|
18
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
19
|
+
expect(cwd).toBe('/custom/path');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return home directory when cwd is undefined', () => {
|
|
23
|
+
const options: { cwd?: string } = { cwd: undefined };
|
|
24
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
25
|
+
expect(cwd).toBe(os.homedir());
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should return home directory when options is undefined', () => {
|
|
29
|
+
const options: { cwd?: string } | undefined = undefined;
|
|
30
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
31
|
+
expect(cwd).toBe(os.homedir());
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return home directory when options is empty object', () => {
|
|
35
|
+
const options: { cwd?: string } = {};
|
|
36
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
37
|
+
expect(cwd).toBe(os.homedir());
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should preserve empty string cwd if explicitly set', () => {
|
|
41
|
+
// Empty string is falsy but is still a valid value with ??
|
|
42
|
+
const options = { cwd: '' };
|
|
43
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
44
|
+
// Note: ?? only falls back on null/undefined, not empty string
|
|
45
|
+
expect(cwd).toBe('');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle null cwd by falling back to home', () => {
|
|
49
|
+
const options = { cwd: null as unknown as string };
|
|
50
|
+
const cwd = options?.cwd ?? os.homedir();
|
|
51
|
+
expect(cwd).toBe(os.homedir());
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('os.homedir()', () => {
|
|
56
|
+
it('should return a non-empty string', () => {
|
|
57
|
+
const home = os.homedir();
|
|
58
|
+
expect(home).toBeTruthy();
|
|
59
|
+
expect(typeof home).toBe('string');
|
|
60
|
+
expect(home.length).toBeGreaterThan(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return an absolute path', () => {
|
|
64
|
+
const home = os.homedir();
|
|
65
|
+
// On Unix systems, absolute paths start with /
|
|
66
|
+
// On Windows, they start with a drive letter like C:\
|
|
67
|
+
expect(home.startsWith('/') || /^[A-Z]:\\/i.test(home)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
// Mock the ML classifier to provide predictable classifications in tests
|
|
5
|
+
// This simulates the actual ML model behavior without loading the model
|
|
6
|
+
vi.mock('../src/main/ml-classifier.js', () => {
|
|
7
|
+
// Simple heuristics to simulate ML classification
|
|
8
|
+
const classifyWithML = async (input: string) => {
|
|
9
|
+
const trimmed = input.trim().toLowerCase();
|
|
10
|
+
|
|
11
|
+
// Empty input
|
|
12
|
+
if (!trimmed) return null;
|
|
13
|
+
|
|
14
|
+
// Questions (ends with ? or starts with question words)
|
|
15
|
+
const questionWords = ['how', 'what', 'why', 'where', 'when', 'who', 'which', 'can', 'could', 'would', 'should'];
|
|
16
|
+
const firstWord = trimmed.split(/\s+/)[0];
|
|
17
|
+
if (trimmed.endsWith('?') || questionWords.includes(firstWord)) {
|
|
18
|
+
return {
|
|
19
|
+
classification: 'NATURAL_LANGUAGE' as const,
|
|
20
|
+
confidence: 0.95,
|
|
21
|
+
scores: { command: 0.05, naturalLanguage: 0.95 },
|
|
22
|
+
inferenceTimeMs: 5,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// First-person statements
|
|
27
|
+
const firstPersonWords = ['i', "i'm", "i've", "i'd", 'my', 'me'];
|
|
28
|
+
if (firstPersonWords.includes(firstWord)) {
|
|
29
|
+
return {
|
|
30
|
+
classification: 'NATURAL_LANGUAGE' as const,
|
|
31
|
+
confidence: 0.85,
|
|
32
|
+
scores: { command: 0.15, naturalLanguage: 0.85 },
|
|
33
|
+
inferenceTimeMs: 5,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Default to command - the ML model primarily identifies commands
|
|
38
|
+
// and the non-command heuristics above handle NL cases
|
|
39
|
+
return {
|
|
40
|
+
classification: 'COMMAND' as const,
|
|
41
|
+
confidence: 0.9,
|
|
42
|
+
scores: { command: 0.9, naturalLanguage: 0.1 },
|
|
43
|
+
inferenceTimeMs: 5,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
classifyWithML,
|
|
49
|
+
preloadModel: vi.fn().mockResolvedValue(true),
|
|
50
|
+
getModelStatus: vi.fn().mockReturnValue({
|
|
51
|
+
loaded: true,
|
|
52
|
+
loading: false,
|
|
53
|
+
error: null,
|
|
54
|
+
modelName: 'brosh-ky-mock',
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Comprehensive list of common commands for realistic testing
|
|
60
|
+
const MOCK_COMMANDS = [
|
|
61
|
+
// Core Unix utilities
|
|
62
|
+
'ls', 'cd', 'pwd', 'echo', 'cat', 'grep', 'find', 'mkdir', 'rm', 'cp', 'mv',
|
|
63
|
+
'chmod', 'chown', 'chgrp', 'ln', 'touch', 'stat', 'file', 'realpath', 'basename', 'dirname',
|
|
64
|
+
|
|
65
|
+
// Text processing
|
|
66
|
+
'sed', 'awk', 'sort', 'uniq', 'head', 'tail', 'wc', 'cut', 'paste', 'tr', 'rev',
|
|
67
|
+
'tee', 'xargs', 'yes', 'true', 'false',
|
|
68
|
+
|
|
69
|
+
// File viewing
|
|
70
|
+
'less', 'more', 'diff', 'cmp', 'comm', 'strings', 'hexdump', 'od',
|
|
71
|
+
|
|
72
|
+
// Search and find
|
|
73
|
+
'locate', 'updatedb', 'which', 'whereis', 'type', 'command',
|
|
74
|
+
|
|
75
|
+
// Version control
|
|
76
|
+
'git', 'svn', 'hg', 'cvs',
|
|
77
|
+
|
|
78
|
+
// Package managers
|
|
79
|
+
'npm', 'npx', 'yarn', 'pnpm', 'bun',
|
|
80
|
+
'pip', 'pip3', 'pipx', 'poetry', 'conda',
|
|
81
|
+
'brew', 'apt', 'apt-get', 'yum', 'dnf', 'pacman', 'zypper',
|
|
82
|
+
'cargo', 'rustup',
|
|
83
|
+
'go', 'gem', 'bundle',
|
|
84
|
+
|
|
85
|
+
// Container/orchestration
|
|
86
|
+
'docker', 'docker-compose', 'podman', 'kubectl', 'helm', 'minikube', 'kind',
|
|
87
|
+
|
|
88
|
+
// Cloud CLIs
|
|
89
|
+
'aws', 'gcloud', 'az', 'terraform', 'pulumi',
|
|
90
|
+
'gh', 'hub', 'gitlab',
|
|
91
|
+
|
|
92
|
+
// Languages/runtimes
|
|
93
|
+
'node', 'deno', 'bun',
|
|
94
|
+
'python', 'python3', 'python2',
|
|
95
|
+
'ruby', 'irb', 'rake',
|
|
96
|
+
'perl', 'php',
|
|
97
|
+
'java', 'javac', 'jar',
|
|
98
|
+
'rustc', 'swift', 'kotlin',
|
|
99
|
+
|
|
100
|
+
// Build tools
|
|
101
|
+
'make', 'cmake', 'ninja', 'meson',
|
|
102
|
+
'gcc', 'g++', 'clang', 'clang++', 'ld',
|
|
103
|
+
'mvn', 'gradle', 'ant',
|
|
104
|
+
|
|
105
|
+
// Editors
|
|
106
|
+
'vim', 'nvim', 'vi', 'nano', 'emacs', 'code', 'subl', 'atom',
|
|
107
|
+
|
|
108
|
+
// Network
|
|
109
|
+
'ssh', 'scp', 'sftp', 'rsync', 'curl', 'wget', 'httpie',
|
|
110
|
+
'ping', 'traceroute', 'netstat', 'ss', 'ip', 'ifconfig',
|
|
111
|
+
'nc', 'netcat', 'socat', 'nmap',
|
|
112
|
+
'dig', 'nslookup', 'host', 'whois',
|
|
113
|
+
|
|
114
|
+
// Archive/compression
|
|
115
|
+
'tar', 'gzip', 'gunzip', 'bzip2', 'xz', 'unzip', 'zip', '7z', 'rar',
|
|
116
|
+
|
|
117
|
+
// Process management
|
|
118
|
+
'ps', 'top', 'htop', 'kill', 'pkill', 'killall', 'pgrep',
|
|
119
|
+
'nice', 'renice', 'nohup', 'timeout',
|
|
120
|
+
'jobs', 'fg', 'bg', 'wait', 'disown',
|
|
121
|
+
|
|
122
|
+
// System info
|
|
123
|
+
'df', 'du', 'free', 'uname', 'uptime', 'hostname', 'hostnamectl',
|
|
124
|
+
'lscpu', 'lsmem', 'lsblk', 'lsusb', 'lspci',
|
|
125
|
+
'w', 'who', 'whoami', 'id', 'groups', 'users', 'last', 'lastlog',
|
|
126
|
+
|
|
127
|
+
// Date/time
|
|
128
|
+
'date', 'cal', 'time', 'timedatectl',
|
|
129
|
+
|
|
130
|
+
// Documentation
|
|
131
|
+
'man', 'info', 'help', 'apropos', 'whatis',
|
|
132
|
+
|
|
133
|
+
// Shell utilities
|
|
134
|
+
'env', 'export', 'source', 'alias', 'unalias', 'set', 'unset',
|
|
135
|
+
'history', 'fc', 'exit', 'logout', 'clear', 'reset',
|
|
136
|
+
'test', 'expr', 'bc', 'dc', 'printf', 'read',
|
|
137
|
+
|
|
138
|
+
// Terminal multiplexers
|
|
139
|
+
'tmux', 'screen', 'mosh', 'byobu',
|
|
140
|
+
|
|
141
|
+
// Modern CLI tools
|
|
142
|
+
'jq', 'yq', 'fx',
|
|
143
|
+
'bat', 'exa', 'eza', 'lsd', 'tree',
|
|
144
|
+
'rg', 'ag', 'ack',
|
|
145
|
+
'fd', 'fzf', 'sk',
|
|
146
|
+
'delta', 'difft',
|
|
147
|
+
'tldr', 'cheat',
|
|
148
|
+
'zoxide', 'autojump', 'fasd',
|
|
149
|
+
'direnv', 'asdf', 'mise',
|
|
150
|
+
|
|
151
|
+
// Database clients
|
|
152
|
+
'mysql', 'psql', 'sqlite3', 'mongo', 'redis-cli',
|
|
153
|
+
|
|
154
|
+
// Testing/linting
|
|
155
|
+
'jest', 'mocha', 'pytest', 'rspec',
|
|
156
|
+
'eslint', 'prettier', 'black', 'flake8', 'mypy',
|
|
157
|
+
'shellcheck', 'shfmt',
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
// Mock child_process to return a predictable set of commands
|
|
161
|
+
vi.mock('child_process', () => ({
|
|
162
|
+
execSync: vi.fn((cmd: string) => {
|
|
163
|
+
// Return common commands for command cache initialization
|
|
164
|
+
if (cmd.includes('compgen') || cmd.includes('commands')) {
|
|
165
|
+
return MOCK_COMMANDS.join('\n');
|
|
166
|
+
}
|
|
167
|
+
// Return some common aliases
|
|
168
|
+
if (cmd.includes('alias')) {
|
|
169
|
+
return [
|
|
170
|
+
'alias ll="ls -la"',
|
|
171
|
+
'alias la="ls -a"',
|
|
172
|
+
'alias l="ls -CF"',
|
|
173
|
+
'alias g="git"',
|
|
174
|
+
'alias gst="git status"',
|
|
175
|
+
'alias gco="git checkout"',
|
|
176
|
+
'alias gp="git push"',
|
|
177
|
+
'alias gl="git pull"',
|
|
178
|
+
'alias dc="docker-compose"',
|
|
179
|
+
'alias k="kubectl"',
|
|
180
|
+
].join('\n');
|
|
181
|
+
}
|
|
182
|
+
// Return shell functions for function cache initialization
|
|
183
|
+
if (cmd.includes('functions') || cmd.includes('declare -F')) {
|
|
184
|
+
return MOCK_FUNCTIONS.join('\n');
|
|
185
|
+
}
|
|
186
|
+
// Handle `command -v <cmd>` queries
|
|
187
|
+
if (cmd.startsWith('command -v ')) {
|
|
188
|
+
const cmdToCheck = cmd.replace('command -v ', '').trim();
|
|
189
|
+
// Empty or invalid command should throw
|
|
190
|
+
if (!cmdToCheck || cmdToCheck.length === 0) {
|
|
191
|
+
throw new Error('command not found');
|
|
192
|
+
}
|
|
193
|
+
// Check if command is in our mock list or dynamic list
|
|
194
|
+
const allKnown = [...MOCK_COMMANDS, 'newcmd', 'latestool', 'll', 'la', 'l', 'g', 'gst', 'gco', 'gp', 'gl', 'dc', 'k'];
|
|
195
|
+
if (allKnown.includes(cmdToCheck)) {
|
|
196
|
+
return `/usr/bin/${cmdToCheck}`;
|
|
197
|
+
}
|
|
198
|
+
// Unknown command throws
|
|
199
|
+
throw new Error('command not found');
|
|
200
|
+
}
|
|
201
|
+
return '';
|
|
202
|
+
}),
|
|
203
|
+
exec: vi.fn(),
|
|
204
|
+
}));
|
|
205
|
+
|
|
206
|
+
// Mock fs to simulate PATH lookups for commands not in the initial cache
|
|
207
|
+
// This allows testing the "checkPathDirectly" fallback
|
|
208
|
+
vi.mock('fs', async () => {
|
|
209
|
+
const actual = await vi.importActual('fs');
|
|
210
|
+
return {
|
|
211
|
+
...actual,
|
|
212
|
+
existsSync: vi.fn((filePath: string) => {
|
|
213
|
+
// Don't match empty or invalid paths
|
|
214
|
+
if (!filePath || filePath.length < 2) return false;
|
|
215
|
+
|
|
216
|
+
// Simulate finding commands in PATH
|
|
217
|
+
// Extract command name from path like "/usr/bin/eza"
|
|
218
|
+
const cmd = path.basename(filePath);
|
|
219
|
+
|
|
220
|
+
// Don't match empty command names
|
|
221
|
+
if (!cmd || cmd.length === 0) return false;
|
|
222
|
+
|
|
223
|
+
// Commands in MOCK_COMMANDS are "found" in PATH
|
|
224
|
+
if (MOCK_COMMANDS.includes(cmd)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
// Also check for commands that might be discovered dynamically
|
|
228
|
+
const dynamicCommands = ['newcmd', 'latestool'];
|
|
229
|
+
if (dynamicCommands.includes(cmd)) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}),
|
|
234
|
+
statSync: vi.fn((filePath: string) => {
|
|
235
|
+
if (!filePath || filePath.length < 2) {
|
|
236
|
+
throw new Error('ENOENT');
|
|
237
|
+
}
|
|
238
|
+
const cmd = path.basename(filePath);
|
|
239
|
+
if (!cmd || cmd.length === 0) {
|
|
240
|
+
throw new Error('ENOENT');
|
|
241
|
+
}
|
|
242
|
+
if (MOCK_COMMANDS.includes(cmd) || ['newcmd', 'latestool'].includes(cmd)) {
|
|
243
|
+
return { isFile: () => true };
|
|
244
|
+
}
|
|
245
|
+
throw new Error('ENOENT');
|
|
246
|
+
}),
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Mock shell functions (like those loaded from .zshrc plugins)
|
|
251
|
+
const MOCK_FUNCTIONS = [
|
|
252
|
+
// Powerlevel10k
|
|
253
|
+
'p10k',
|
|
254
|
+
// Node version manager
|
|
255
|
+
'nvm',
|
|
256
|
+
// Python version manager
|
|
257
|
+
'pyenv',
|
|
258
|
+
// Ruby version manager
|
|
259
|
+
'rbenv',
|
|
260
|
+
// Direnv
|
|
261
|
+
'direnv',
|
|
262
|
+
// Zoxide
|
|
263
|
+
'z',
|
|
264
|
+
'__zoxide_z',
|
|
265
|
+
// FZF
|
|
266
|
+
'fzf-history-widget',
|
|
267
|
+
// Some internal functions (should be filtered out)
|
|
268
|
+
'_p10k_worker_start',
|
|
269
|
+
'_nvm_auto',
|
|
270
|
+
'-my-hidden-func',
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
// Export for tests that need to verify mock data
|
|
274
|
+
export { MOCK_COMMANDS, MOCK_FUNCTIONS };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/renderer/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "dist/main",
|
|
8
|
+
"rootDir": "src/main",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/main/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
base: './',
|
|
8
|
+
root: 'src/renderer',
|
|
9
|
+
build: {
|
|
10
|
+
outDir: '../../dist/renderer',
|
|
11
|
+
emptyOutDir: true,
|
|
12
|
+
rollupOptions: {
|
|
13
|
+
input: resolve(__dirname, 'src/renderer/index.html'),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
server: {
|
|
17
|
+
port: 5173,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: 'node',
|
|
6
|
+
include: ['tests/**/*.test.ts'],
|
|
7
|
+
setupFiles: ['./tests/setup.ts'],
|
|
8
|
+
coverage: {
|
|
9
|
+
provider: 'v8',
|
|
10
|
+
include: ['src/main/ai-detection.ts'],
|
|
11
|
+
thresholds: {
|
|
12
|
+
lines: 80,
|
|
13
|
+
functions: 80,
|
|
14
|
+
branches: 75,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"jsx": "react"
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|