forkoff 1.0.11 → 1.0.13
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 +7 -4
- package/dist/__tests__/cli-commands.test.d.ts +6 -0
- package/dist/__tests__/cli-commands.test.d.ts.map +1 -0
- package/dist/__tests__/cli-commands.test.js +213 -0
- package/dist/__tests__/cli-commands.test.js.map +1 -0
- package/dist/__tests__/startup.test.d.ts +11 -0
- package/dist/__tests__/startup.test.d.ts.map +1 -0
- package/dist/__tests__/startup.test.js +234 -0
- package/dist/__tests__/startup.test.js.map +1 -0
- package/dist/__tests__/tools/claude-process.test.js +221 -15
- package/dist/__tests__/tools/claude-process.test.js.map +1 -1
- package/dist/__tests__/tools/permission-hook.test.d.ts +17 -0
- package/dist/__tests__/tools/permission-hook.test.d.ts.map +1 -0
- package/dist/__tests__/tools/permission-hook.test.js +616 -0
- package/dist/__tests__/tools/permission-hook.test.js.map +1 -0
- package/dist/__tests__/tools/permission-ipc.test.d.ts +11 -0
- package/dist/__tests__/tools/permission-ipc.test.d.ts.map +1 -0
- package/dist/__tests__/tools/permission-ipc.test.js +612 -0
- package/dist/__tests__/tools/permission-ipc.test.js.map +1 -0
- package/dist/config.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1010 -898
- package/dist/index.js.map +1 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +45 -15
- package/dist/startup.js.map +1 -1
- package/dist/tools/__tests__/claude-sessions.test.d.ts +2 -0
- package/dist/tools/__tests__/claude-sessions.test.d.ts.map +1 -0
- package/dist/tools/__tests__/claude-sessions.test.js +306 -0
- package/dist/tools/__tests__/claude-sessions.test.js.map +1 -0
- package/dist/tools/claude-process.d.ts +81 -4
- package/dist/tools/claude-process.d.ts.map +1 -1
- package/dist/tools/claude-process.js +332 -20
- package/dist/tools/claude-process.js.map +1 -1
- package/dist/tools/claude-sessions.d.ts +5 -0
- package/dist/tools/claude-sessions.d.ts.map +1 -1
- package/dist/tools/claude-sessions.js +16 -2
- package/dist/tools/claude-sessions.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/permission-hook.d.ts +41 -0
- package/dist/tools/permission-hook.d.ts.map +1 -0
- package/dist/tools/permission-hook.js +312 -0
- package/dist/tools/permission-hook.js.map +1 -0
- package/dist/tools/permission-ipc.d.ts +109 -0
- package/dist/tools/permission-ipc.d.ts.map +1 -0
- package/dist/tools/permission-ipc.js +295 -0
- package/dist/tools/permission-ipc.js.map +1 -0
- package/dist/websocket.d.ts +14 -0
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +34 -4
- package/dist/websocket.js.map +1 -1
- package/jest.config.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,7 @@ Keep this running to receive commands from your mobile app.
|
|
|
79
79
|
| `forkoff startup --enable` | Enable automatic startup |
|
|
80
80
|
| `forkoff startup --disable` | Disable automatic startup |
|
|
81
81
|
| `forkoff startup --status` | Show startup registration status |
|
|
82
|
+
| `forkoff help` | Show available commands and usage |
|
|
82
83
|
|
|
83
84
|
### Configuration Options
|
|
84
85
|
|
|
@@ -117,12 +118,12 @@ This is used by the automatic startup feature and is useful for running ForkOff
|
|
|
117
118
|
|
|
118
119
|
### Automatic Startup
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
ForkOff automatically starts on login so your device stays connected without manual intervention. Startup is **enabled by default** — when you run `forkoff pair` or `forkoff connect`, it registers itself to launch `forkoff connect --quiet` on login.
|
|
121
122
|
|
|
122
|
-
- **Windows**:
|
|
123
|
-
- **macOS**:
|
|
123
|
+
- **Windows**: Adds a `ForkOffCLI` entry to the `HKCU\...\Run` registry key (no admin required)
|
|
124
|
+
- **macOS**: Installs a launchd agent (`~/Library/LaunchAgents/app.forkoff.cli.plist`) with the explicit node binary path for nvm/fnm compatibility
|
|
124
125
|
|
|
125
|
-
To
|
|
126
|
+
To disable automatic startup:
|
|
126
127
|
|
|
127
128
|
```bash
|
|
128
129
|
forkoff startup --disable
|
|
@@ -134,6 +135,8 @@ Once disabled, `pair` and `connect` will not re-register startup. To re-enable:
|
|
|
134
135
|
forkoff startup --enable
|
|
135
136
|
```
|
|
136
137
|
|
|
138
|
+
Running `forkoff disconnect` also removes the startup registration.
|
|
139
|
+
|
|
137
140
|
---
|
|
138
141
|
|
|
139
142
|
## Programmatic Usage
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-commands.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-commands.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for CLI commands: help, unknown command, version
|
|
4
|
+
* Uses createProgram() exported from index.ts
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
// Mock all heavy dependencies so importing index.ts doesn't trigger real connections
|
|
8
|
+
jest.mock('../config', () => ({
|
|
9
|
+
config: {
|
|
10
|
+
deviceId: null,
|
|
11
|
+
deviceName: 'test',
|
|
12
|
+
apiUrl: 'http://localhost:3000',
|
|
13
|
+
wsUrl: 'ws://localhost:3000',
|
|
14
|
+
pairingCode: null,
|
|
15
|
+
pairedAt: null,
|
|
16
|
+
userId: null,
|
|
17
|
+
isPaired: false,
|
|
18
|
+
startupEnabled: null,
|
|
19
|
+
startupBinaryPath: null,
|
|
20
|
+
getPath: () => '/tmp/config.json',
|
|
21
|
+
reset: jest.fn(),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
jest.mock('../api', () => ({
|
|
25
|
+
api: {
|
|
26
|
+
healthCheck: jest.fn(),
|
|
27
|
+
registerDevice: jest.fn(),
|
|
28
|
+
refreshPairingCode: jest.fn(),
|
|
29
|
+
checkPairingStatus: jest.fn(),
|
|
30
|
+
reportConnectedTools: jest.fn(),
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
jest.mock('../websocket', () => ({
|
|
34
|
+
wsClient: {
|
|
35
|
+
connect: jest.fn(),
|
|
36
|
+
disconnect: jest.fn(),
|
|
37
|
+
isConnected: false,
|
|
38
|
+
on: jest.fn(),
|
|
39
|
+
sendTerminalOutput: jest.fn(),
|
|
40
|
+
sendTerminalCwd: jest.fn(),
|
|
41
|
+
sendClaudeSessionUpdate: jest.fn(),
|
|
42
|
+
sendClaudeSessions: jest.fn(),
|
|
43
|
+
sendToolStatusUpdate: jest.fn(),
|
|
44
|
+
sendDirectoryListResponse: jest.fn(),
|
|
45
|
+
sendReadFileResponse: jest.fn(),
|
|
46
|
+
sendTranscriptHistory: jest.fn(),
|
|
47
|
+
sendTranscriptUpdate: jest.fn(),
|
|
48
|
+
sendClaudeApprovalRequest: jest.fn(),
|
|
49
|
+
sendToolActivity: jest.fn(),
|
|
50
|
+
sendPermissionPrompt: jest.fn(),
|
|
51
|
+
sendClaudeSessionEvent: jest.fn(),
|
|
52
|
+
sendRpcResponse: jest.fn(),
|
|
53
|
+
sendPendingPermissionsSync: jest.fn(),
|
|
54
|
+
sendThinkingContent: jest.fn(),
|
|
55
|
+
sendTokenUsage: jest.fn(),
|
|
56
|
+
sendTaskProgress: jest.fn(),
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
jest.mock('../terminal', () => ({
|
|
60
|
+
terminalManager: {
|
|
61
|
+
on: jest.fn(),
|
|
62
|
+
createSession: jest.fn(),
|
|
63
|
+
executeCommand: jest.fn(),
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
jest.mock('../approval', () => ({
|
|
67
|
+
approvalManager: {
|
|
68
|
+
on: jest.fn(),
|
|
69
|
+
handleApprovalResponse: jest.fn(),
|
|
70
|
+
},
|
|
71
|
+
}));
|
|
72
|
+
jest.mock('../tools', () => ({
|
|
73
|
+
toolDetector: { detectAll: jest.fn(), watchToolStatus: jest.fn() },
|
|
74
|
+
claudeHooksManager: { canConfigure: jest.fn(), installHooks: jest.fn(), uninstallHooks: jest.fn(), isHookConfigured: jest.fn() },
|
|
75
|
+
claudeSessionDetector: {
|
|
76
|
+
isClaudeInstalled: jest.fn().mockReturnValue(false),
|
|
77
|
+
scanSessions: jest.fn().mockReturnValue([]),
|
|
78
|
+
getSessions: jest.fn().mockReturnValue([]),
|
|
79
|
+
startWatching: jest.fn(),
|
|
80
|
+
stopWatching: jest.fn(),
|
|
81
|
+
seedKnownSessions: jest.fn(),
|
|
82
|
+
on: jest.fn(),
|
|
83
|
+
},
|
|
84
|
+
claudeProcessManager: {
|
|
85
|
+
isClaudeSession: jest.fn(),
|
|
86
|
+
sendInput: jest.fn(),
|
|
87
|
+
registerSession: jest.fn(),
|
|
88
|
+
markTakenOver: jest.fn(),
|
|
89
|
+
isTakenOver: jest.fn(),
|
|
90
|
+
startSession: jest.fn(),
|
|
91
|
+
startAndSendMessage: jest.fn(),
|
|
92
|
+
handleApprovalResponse: jest.fn(),
|
|
93
|
+
handlePermissionResponse: jest.fn(),
|
|
94
|
+
updatePermissionRules: jest.fn(),
|
|
95
|
+
clearAllTakenOver: jest.fn(),
|
|
96
|
+
autoAllowAllPendingPrompts: jest.fn(),
|
|
97
|
+
cleanupAllPermissionState: jest.fn(),
|
|
98
|
+
getAllPendingPrompts: jest.fn().mockReturnValue([]),
|
|
99
|
+
on: jest.fn(),
|
|
100
|
+
},
|
|
101
|
+
PermissionIpcManager: {
|
|
102
|
+
cleanupStaleTempFiles: jest.fn(),
|
|
103
|
+
},
|
|
104
|
+
}));
|
|
105
|
+
jest.mock('../transcript-streamer', () => ({
|
|
106
|
+
transcriptStreamer: {
|
|
107
|
+
fetchHistory: jest.fn(),
|
|
108
|
+
subscribeToUpdates: jest.fn(),
|
|
109
|
+
unsubscribeFromUpdates: jest.fn(),
|
|
110
|
+
cleanup: jest.fn(),
|
|
111
|
+
on: jest.fn(),
|
|
112
|
+
},
|
|
113
|
+
}));
|
|
114
|
+
jest.mock('../logger', () => ({
|
|
115
|
+
setQuiet: jest.fn(),
|
|
116
|
+
createSpinner: jest.fn(() => ({
|
|
117
|
+
start: jest.fn().mockReturnThis(),
|
|
118
|
+
stop: jest.fn(),
|
|
119
|
+
succeed: jest.fn(),
|
|
120
|
+
fail: jest.fn(),
|
|
121
|
+
info: jest.fn(),
|
|
122
|
+
warn: jest.fn(),
|
|
123
|
+
text: '',
|
|
124
|
+
})),
|
|
125
|
+
}));
|
|
126
|
+
jest.mock('chalk', () => {
|
|
127
|
+
const handler = {
|
|
128
|
+
get: () => new Proxy((s) => s, handler),
|
|
129
|
+
apply: (_target, _thisArg, args) => args[0],
|
|
130
|
+
};
|
|
131
|
+
return new Proxy((s) => s, handler);
|
|
132
|
+
});
|
|
133
|
+
jest.mock('qrcode-terminal', () => ({
|
|
134
|
+
generate: jest.fn(),
|
|
135
|
+
}));
|
|
136
|
+
jest.mock('../startup', () => ({
|
|
137
|
+
enableStartup: jest.fn(),
|
|
138
|
+
disableStartup: jest.fn(),
|
|
139
|
+
isStartupRegistered: jest.fn().mockReturnValue(false),
|
|
140
|
+
getBinaryPath: jest.fn().mockReturnValue('/usr/local/bin/forkoff'),
|
|
141
|
+
}));
|
|
142
|
+
const index_1 = require("../index");
|
|
143
|
+
describe('CLI commands', () => {
|
|
144
|
+
let consoleLogSpy;
|
|
145
|
+
let consoleErrorSpy;
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
148
|
+
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
149
|
+
process.exitCode = undefined;
|
|
150
|
+
});
|
|
151
|
+
afterEach(() => {
|
|
152
|
+
consoleLogSpy.mockRestore();
|
|
153
|
+
consoleErrorSpy.mockRestore();
|
|
154
|
+
process.exitCode = undefined;
|
|
155
|
+
});
|
|
156
|
+
describe('help command', () => {
|
|
157
|
+
it('outputs available commands', async () => {
|
|
158
|
+
const program = (0, index_1.createProgram)();
|
|
159
|
+
// Prevent commander from calling process.exit on help
|
|
160
|
+
program.exitOverride();
|
|
161
|
+
let helpOutput = '';
|
|
162
|
+
program.configureOutput({
|
|
163
|
+
writeOut: (str) => { helpOutput += str; },
|
|
164
|
+
writeErr: (str) => { helpOutput += str; },
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
await program.parseAsync(['node', 'forkoff', 'help']);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Commander throws on exitOverride
|
|
171
|
+
}
|
|
172
|
+
// The help action calls program.outputHelp(), check console.log calls
|
|
173
|
+
const allOutput = helpOutput + consoleLogSpy.mock.calls.map((c) => c.join(' ')).join('\n');
|
|
174
|
+
expect(allOutput).toContain('pair');
|
|
175
|
+
expect(allOutput).toContain('connect');
|
|
176
|
+
expect(allOutput).toContain('disconnect');
|
|
177
|
+
expect(allOutput).toContain('status');
|
|
178
|
+
expect(allOutput).toContain('startup');
|
|
179
|
+
expect(allOutput).toContain('config');
|
|
180
|
+
expect(allOutput).toContain('tools');
|
|
181
|
+
expect(allOutput).toContain('help');
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe('--version flag', () => {
|
|
185
|
+
it('shows version from package.json', async () => {
|
|
186
|
+
const program = (0, index_1.createProgram)();
|
|
187
|
+
program.exitOverride();
|
|
188
|
+
let versionOutput = '';
|
|
189
|
+
program.configureOutput({
|
|
190
|
+
writeOut: (str) => { versionOutput += str; },
|
|
191
|
+
writeErr: (str) => { versionOutput += str; },
|
|
192
|
+
});
|
|
193
|
+
try {
|
|
194
|
+
await program.parseAsync(['node', 'forkoff', '--version']);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Commander throws on exitOverride
|
|
198
|
+
}
|
|
199
|
+
const pkg = require('../../package.json');
|
|
200
|
+
expect(versionOutput).toContain(pkg.version);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
describe('unknown command', () => {
|
|
204
|
+
it('sets process.exitCode = 1 and shows error message', async () => {
|
|
205
|
+
const program = (0, index_1.createProgram)();
|
|
206
|
+
await program.parseAsync(['node', 'forkoff', 'gibberish']);
|
|
207
|
+
expect(process.exitCode).toBe(1);
|
|
208
|
+
const errorOutput = consoleErrorSpy.mock.calls.map((c) => c.join(' ')).join('\n');
|
|
209
|
+
expect(errorOutput).toContain('Unknown command: gibberish');
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
//# sourceMappingURL=cli-commands.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-commands.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-commands.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for startup module
|
|
3
|
+
* Covers:
|
|
4
|
+
* - Windows: .bat wrapper + HKCU Run registry key (no admin needed)
|
|
5
|
+
* - macOS: plist with explicit node path (nvm/fnm compatibility)
|
|
6
|
+
* - disableStartup cleans up .bat file on Windows
|
|
7
|
+
* - isStartupRegistered checks registry (win32) / plist existence (darwin)
|
|
8
|
+
* - getBinaryPath: cached, which/where, fallback to process.argv[1]
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=startup.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/startup.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tests for startup module
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Windows: .bat wrapper + HKCU Run registry key (no admin needed)
|
|
6
|
+
* - macOS: plist with explicit node path (nvm/fnm compatibility)
|
|
7
|
+
* - disableStartup cleans up .bat file on Windows
|
|
8
|
+
* - isStartupRegistered checks registry (win32) / plist existence (darwin)
|
|
9
|
+
* - getBinaryPath: cached, which/where, fallback to process.argv[1]
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const mockExecSync = jest.fn();
|
|
13
|
+
jest.mock('child_process', () => ({
|
|
14
|
+
execSync: mockExecSync,
|
|
15
|
+
}));
|
|
16
|
+
const mockExistsSync = jest.fn();
|
|
17
|
+
const mockWriteFileSync = jest.fn();
|
|
18
|
+
const mockUnlinkSync = jest.fn();
|
|
19
|
+
const mockMkdirSync = jest.fn();
|
|
20
|
+
jest.mock('fs', () => ({
|
|
21
|
+
existsSync: mockExistsSync,
|
|
22
|
+
writeFileSync: mockWriteFileSync,
|
|
23
|
+
unlinkSync: mockUnlinkSync,
|
|
24
|
+
mkdirSync: mockMkdirSync,
|
|
25
|
+
}));
|
|
26
|
+
const mockConfig = {
|
|
27
|
+
startupBinaryPath: null,
|
|
28
|
+
startupEnabled: null,
|
|
29
|
+
};
|
|
30
|
+
jest.mock('../config', () => ({
|
|
31
|
+
config: mockConfig,
|
|
32
|
+
}));
|
|
33
|
+
const startup_1 = require("../startup");
|
|
34
|
+
describe('startup', () => {
|
|
35
|
+
const originalPlatform = process.platform;
|
|
36
|
+
const originalExecPath = process.execPath;
|
|
37
|
+
const originalArgv = [...process.argv];
|
|
38
|
+
function setPlatform(platform) {
|
|
39
|
+
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
40
|
+
}
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
// resetAllMocks clears calls AND implementations (unlike clearAllMocks)
|
|
43
|
+
jest.resetAllMocks();
|
|
44
|
+
mockConfig.startupBinaryPath = null;
|
|
45
|
+
mockConfig.startupEnabled = null;
|
|
46
|
+
mockExistsSync.mockReturnValue(false);
|
|
47
|
+
});
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
50
|
+
Object.defineProperty(process, 'execPath', { value: originalExecPath, configurable: true });
|
|
51
|
+
process.argv = [...originalArgv];
|
|
52
|
+
});
|
|
53
|
+
describe('getBinaryPath', () => {
|
|
54
|
+
it('returns cached path when it exists on disk', () => {
|
|
55
|
+
mockConfig.startupBinaryPath = '/usr/local/bin/forkoff';
|
|
56
|
+
mockExistsSync.mockReturnValue(true);
|
|
57
|
+
expect((0, startup_1.getBinaryPath)()).toBe('/usr/local/bin/forkoff');
|
|
58
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
it('finds via which on darwin', () => {
|
|
61
|
+
setPlatform('darwin');
|
|
62
|
+
mockConfig.startupBinaryPath = null;
|
|
63
|
+
mockExecSync.mockReturnValue('/usr/local/bin/forkoff\n');
|
|
64
|
+
// startupBinaryPath is null → short-circuit, existsSync NOT called for cache.
|
|
65
|
+
// First existsSync call is for the which result → return true.
|
|
66
|
+
mockExistsSync.mockReturnValueOnce(true);
|
|
67
|
+
expect((0, startup_1.getBinaryPath)()).toBe('/usr/local/bin/forkoff');
|
|
68
|
+
expect(mockExecSync).toHaveBeenCalledWith('which forkoff', { encoding: 'utf-8' });
|
|
69
|
+
expect(mockConfig.startupBinaryPath).toBe('/usr/local/bin/forkoff');
|
|
70
|
+
});
|
|
71
|
+
it('finds via where on win32', () => {
|
|
72
|
+
setPlatform('win32');
|
|
73
|
+
mockConfig.startupBinaryPath = null;
|
|
74
|
+
mockExecSync.mockReturnValue('C:\\Program Files\\nodejs\\forkoff\r\n');
|
|
75
|
+
mockExistsSync.mockReturnValueOnce(true);
|
|
76
|
+
expect((0, startup_1.getBinaryPath)()).toBe('C:\\Program Files\\nodejs\\forkoff');
|
|
77
|
+
expect(mockExecSync).toHaveBeenCalledWith('where forkoff', { encoding: 'utf-8' });
|
|
78
|
+
});
|
|
79
|
+
it('falls back to process.argv[1] when which/where fails', () => {
|
|
80
|
+
setPlatform('darwin');
|
|
81
|
+
mockConfig.startupBinaryPath = null;
|
|
82
|
+
mockExecSync.mockImplementation(() => { throw new Error('not found'); });
|
|
83
|
+
process.argv = ['node', '/home/user/.nvm/versions/node/bin/forkoff'];
|
|
84
|
+
expect((0, startup_1.getBinaryPath)()).toBe('/home/user/.nvm/versions/node/bin/forkoff');
|
|
85
|
+
expect(mockConfig.startupBinaryPath).toBe('/home/user/.nvm/versions/node/bin/forkoff');
|
|
86
|
+
});
|
|
87
|
+
it('throws when no binary can be found', () => {
|
|
88
|
+
mockConfig.startupBinaryPath = null;
|
|
89
|
+
mockExecSync.mockImplementation(() => { throw new Error('not found'); });
|
|
90
|
+
process.argv = ['node']; // No argv[1]
|
|
91
|
+
expect(() => (0, startup_1.getBinaryPath)()).toThrow('Could not determine forkoff binary path');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('isStartupRegistered', () => {
|
|
95
|
+
it('returns true on win32 when registry key exists', () => {
|
|
96
|
+
setPlatform('win32');
|
|
97
|
+
mockExecSync.mockReturnValue('');
|
|
98
|
+
expect((0, startup_1.isStartupRegistered)()).toBe(true);
|
|
99
|
+
expect(mockExecSync).toHaveBeenCalledWith(expect.stringContaining('reg query'), { stdio: 'pipe' });
|
|
100
|
+
});
|
|
101
|
+
it('returns false on win32 when registry key missing', () => {
|
|
102
|
+
setPlatform('win32');
|
|
103
|
+
mockExecSync.mockImplementation(() => { throw new Error('not found'); });
|
|
104
|
+
expect((0, startup_1.isStartupRegistered)()).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
it('returns true on darwin when plist file exists', () => {
|
|
107
|
+
setPlatform('darwin');
|
|
108
|
+
mockExistsSync.mockReturnValue(true);
|
|
109
|
+
expect((0, startup_1.isStartupRegistered)()).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
it('returns false on darwin when plist file does not exist', () => {
|
|
112
|
+
setPlatform('darwin');
|
|
113
|
+
mockExistsSync.mockReturnValue(false);
|
|
114
|
+
expect((0, startup_1.isStartupRegistered)()).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
it('returns false on unsupported platform', () => {
|
|
117
|
+
setPlatform('linux');
|
|
118
|
+
expect((0, startup_1.isStartupRegistered)()).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('enableStartup (win32)', () => {
|
|
122
|
+
beforeEach(() => {
|
|
123
|
+
setPlatform('win32');
|
|
124
|
+
Object.defineProperty(process, 'execPath', {
|
|
125
|
+
value: 'C:\\Program Files\\nodejs\\node.exe',
|
|
126
|
+
configurable: true,
|
|
127
|
+
});
|
|
128
|
+
mockConfig.startupBinaryPath = 'C:\\Users\\test\\AppData\\Roaming\\npm\\forkoff';
|
|
129
|
+
mockExistsSync.mockReturnValue(true);
|
|
130
|
+
});
|
|
131
|
+
it('writes .bat wrapper with correct content', async () => {
|
|
132
|
+
await (0, startup_1.enableStartup)();
|
|
133
|
+
const batCall = mockWriteFileSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].endsWith('.bat'));
|
|
134
|
+
expect(batCall).toBeDefined();
|
|
135
|
+
const batContent = batCall[1];
|
|
136
|
+
expect(batContent).toContain('@echo off');
|
|
137
|
+
expect(batContent).toContain('"C:\\Program Files\\nodejs\\node.exe"');
|
|
138
|
+
expect(batContent).toContain('"C:\\Users\\test\\AppData\\Roaming\\npm\\forkoff"');
|
|
139
|
+
expect(batContent).toContain('connect --quiet');
|
|
140
|
+
});
|
|
141
|
+
it('adds registry Run key with .bat path', async () => {
|
|
142
|
+
await (0, startup_1.enableStartup)();
|
|
143
|
+
const regCall = mockExecSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].includes('reg add'));
|
|
144
|
+
expect(regCall).toBeDefined();
|
|
145
|
+
expect(regCall[0]).toContain('startup.bat');
|
|
146
|
+
expect(regCall[0]).toContain('ForkOffCLI');
|
|
147
|
+
});
|
|
148
|
+
it('sets config.startupEnabled = true', async () => {
|
|
149
|
+
await (0, startup_1.enableStartup)();
|
|
150
|
+
expect(mockConfig.startupEnabled).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('enableStartup (darwin)', () => {
|
|
154
|
+
beforeEach(() => {
|
|
155
|
+
setPlatform('darwin');
|
|
156
|
+
Object.defineProperty(process, 'execPath', {
|
|
157
|
+
value: '/Users/test/.nvm/versions/node/v20.0.0/bin/node',
|
|
158
|
+
configurable: true,
|
|
159
|
+
});
|
|
160
|
+
mockConfig.startupBinaryPath = '/usr/local/bin/forkoff';
|
|
161
|
+
mockExistsSync.mockReturnValue(true);
|
|
162
|
+
});
|
|
163
|
+
it('writes plist with process.execPath as first ProgramArgument', async () => {
|
|
164
|
+
await (0, startup_1.enableStartup)();
|
|
165
|
+
const plistCall = mockWriteFileSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].endsWith('.plist'));
|
|
166
|
+
expect(plistCall).toBeDefined();
|
|
167
|
+
const plistContent = plistCall[1];
|
|
168
|
+
const argsMatch = plistContent.match(/<array>([\s\S]*?)<\/array>/);
|
|
169
|
+
expect(argsMatch).toBeDefined();
|
|
170
|
+
const strings = [...argsMatch[1].matchAll(/<string>(.*?)<\/string>/g)].map(m => m[1]);
|
|
171
|
+
expect(strings[0]).toBe('/Users/test/.nvm/versions/node/v20.0.0/bin/node');
|
|
172
|
+
expect(strings[1]).toBe('/usr/local/bin/forkoff');
|
|
173
|
+
expect(strings[2]).toBe('connect');
|
|
174
|
+
expect(strings[3]).toBe('--quiet');
|
|
175
|
+
});
|
|
176
|
+
it('includes node directory in PATH when not in default PATH', async () => {
|
|
177
|
+
await (0, startup_1.enableStartup)();
|
|
178
|
+
const plistCall = mockWriteFileSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].endsWith('.plist'));
|
|
179
|
+
const plistContent = plistCall[1];
|
|
180
|
+
expect(plistContent).toContain('/Users/test/.nvm/versions/node/v20.0.0/bin:');
|
|
181
|
+
});
|
|
182
|
+
it('calls launchctl load', async () => {
|
|
183
|
+
await (0, startup_1.enableStartup)();
|
|
184
|
+
const loadCall = mockExecSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].includes('launchctl load'));
|
|
185
|
+
expect(loadCall).toBeDefined();
|
|
186
|
+
});
|
|
187
|
+
it('sets config.startupEnabled = true', async () => {
|
|
188
|
+
await (0, startup_1.enableStartup)();
|
|
189
|
+
expect(mockConfig.startupEnabled).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
describe('disableStartup (win32)', () => {
|
|
193
|
+
beforeEach(() => {
|
|
194
|
+
setPlatform('win32');
|
|
195
|
+
});
|
|
196
|
+
it('removes registry Run key', async () => {
|
|
197
|
+
await (0, startup_1.disableStartup)();
|
|
198
|
+
const regCall = mockExecSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].includes('reg delete'));
|
|
199
|
+
expect(regCall).toBeDefined();
|
|
200
|
+
expect(regCall[0]).toContain('ForkOffCLI');
|
|
201
|
+
});
|
|
202
|
+
it('removes .bat file if it exists', async () => {
|
|
203
|
+
mockExistsSync.mockReturnValue(true);
|
|
204
|
+
await (0, startup_1.disableStartup)();
|
|
205
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith(expect.stringContaining('startup.bat'));
|
|
206
|
+
});
|
|
207
|
+
it('sets config.startupEnabled = false', async () => {
|
|
208
|
+
await (0, startup_1.disableStartup)();
|
|
209
|
+
expect(mockConfig.startupEnabled).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
describe('disableStartup (darwin)', () => {
|
|
213
|
+
beforeEach(() => {
|
|
214
|
+
setPlatform('darwin');
|
|
215
|
+
});
|
|
216
|
+
it('calls launchctl unload and removes plist when it exists', async () => {
|
|
217
|
+
mockExistsSync.mockReturnValue(true);
|
|
218
|
+
await (0, startup_1.disableStartup)();
|
|
219
|
+
const unloadCall = mockExecSync.mock.calls.find((call) => typeof call[0] === 'string' && call[0].includes('launchctl unload'));
|
|
220
|
+
expect(unloadCall).toBeDefined();
|
|
221
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith(expect.stringContaining('.plist'));
|
|
222
|
+
});
|
|
223
|
+
it('does nothing when plist does not exist', async () => {
|
|
224
|
+
mockExistsSync.mockReturnValue(false);
|
|
225
|
+
await (0, startup_1.disableStartup)();
|
|
226
|
+
expect(mockUnlinkSync).not.toHaveBeenCalled();
|
|
227
|
+
});
|
|
228
|
+
it('sets config.startupEnabled = false', async () => {
|
|
229
|
+
await (0, startup_1.disableStartup)();
|
|
230
|
+
expect(mockConfig.startupEnabled).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
//# sourceMappingURL=startup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.test.js","sourceRoot":"","sources":["../../src/__tests__/startup.test.ts"],"names":[],"mappings":"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"}
|