@vibelet/cli 0.1.35 → 0.1.37
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/app.json +5 -0
- package/dist/advertised-hosts.d.ts +34 -0
- package/dist/advertised-hosts.d.ts.map +1 -0
- package/dist/advertised-hosts.js +176 -0
- package/dist/advertised-hosts.js.map +1 -0
- package/dist/advertised-hosts.test.d.ts +2 -0
- package/dist/advertised-hosts.test.d.ts.map +1 -0
- package/dist/advertised-hosts.test.js +96 -0
- package/dist/advertised-hosts.test.js.map +1 -0
- package/dist/audit.d.ts +30 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +73 -0
- package/dist/audit.js.map +1 -0
- package/dist/audit.test.d.ts +2 -0
- package/dist/audit.test.d.ts.map +1 -0
- package/dist/audit.test.js +33 -0
- package/dist/audit.test.js.map +1 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +27 -0
- package/dist/auth.js.map +1 -0
- package/dist/claude-hooks.d.ts +58 -0
- package/dist/claude-hooks.d.ts.map +1 -0
- package/dist/claude-hooks.js +129 -0
- package/dist/claude-hooks.js.map +1 -0
- package/dist/cli-version.d.ts +3 -0
- package/dist/cli-version.d.ts.map +1 -0
- package/dist/cli-version.js +35 -0
- package/dist/cli-version.js.map +1 -0
- package/dist/cli-version.test.d.ts +2 -0
- package/dist/cli-version.test.d.ts.map +1 -0
- package/dist/cli-version.test.js +38 -0
- package/dist/cli-version.test.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +327 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +184 -0
- package/dist/config.test.js.map +1 -0
- package/dist/dev-auth.test.d.ts +2 -0
- package/dist/dev-auth.test.d.ts.map +1 -0
- package/dist/dev-auth.test.js +154 -0
- package/dist/dev-auth.test.js.map +1 -0
- package/dist/dev-script.test.d.ts +2 -0
- package/dist/dev-script.test.d.ts.map +1 -0
- package/dist/dev-script.test.js +412 -0
- package/dist/dev-script.test.js.map +1 -0
- package/dist/drivers/claude.d.ts +34 -0
- package/dist/drivers/claude.d.ts.map +1 -0
- package/dist/drivers/claude.js +413 -0
- package/dist/drivers/claude.js.map +1 -0
- package/dist/drivers/claude.test.d.ts +2 -0
- package/dist/drivers/claude.test.d.ts.map +1 -0
- package/dist/drivers/claude.test.js +951 -0
- package/dist/drivers/claude.test.js.map +1 -0
- package/dist/drivers/codex.d.ts +38 -0
- package/dist/drivers/codex.d.ts.map +1 -0
- package/dist/drivers/codex.js +771 -0
- package/dist/drivers/codex.js.map +1 -0
- package/dist/drivers/codex.test.d.ts +2 -0
- package/dist/drivers/codex.test.d.ts.map +1 -0
- package/dist/drivers/codex.test.js +939 -0
- package/dist/drivers/codex.test.js.map +1 -0
- package/dist/drivers/types.d.ts +14 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +2 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/e2e.test.d.ts +2 -0
- package/dist/e2e.test.d.ts.map +1 -0
- package/dist/e2e.test.js +111 -0
- package/dist/e2e.test.js.map +1 -0
- package/dist/identity.d.ts +10 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +66 -0
- package/dist/identity.js.map +1 -0
- package/dist/identity.test.d.ts +2 -0
- package/dist/identity.test.d.ts.map +1 -0
- package/dist/identity.test.js +25 -0
- package/dist/identity.test.js.map +1 -0
- package/dist/index-entry.test.d.ts +2 -0
- package/dist/index-entry.test.d.ts.map +1 -0
- package/dist/index-entry.test.js +272 -0
- package/dist/index-entry.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +707 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +31 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +75 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +52 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +89 -0
- package/dist/metrics.js.map +1 -0
- package/dist/pairing-store.d.ts +29 -0
- package/dist/pairing-store.d.ts.map +1 -0
- package/dist/pairing-store.js +131 -0
- package/dist/pairing-store.js.map +1 -0
- package/dist/pairing-store.test.d.ts +2 -0
- package/dist/pairing-store.test.d.ts.map +1 -0
- package/dist/pairing-store.test.js +47 -0
- package/dist/pairing-store.test.js.map +1 -0
- package/dist/paths.d.ts +16 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +18 -0
- package/dist/paths.js.map +1 -0
- package/dist/perf-compare.d.ts +13 -0
- package/dist/perf-compare.d.ts.map +1 -0
- package/dist/perf-compare.js +125 -0
- package/dist/perf-compare.js.map +1 -0
- package/dist/port-conflict.d.ts +9 -0
- package/dist/port-conflict.d.ts.map +1 -0
- package/dist/port-conflict.js +33 -0
- package/dist/port-conflict.js.map +1 -0
- package/dist/port-conflict.test.d.ts +2 -0
- package/dist/port-conflict.test.d.ts.map +1 -0
- package/dist/port-conflict.test.js +38 -0
- package/dist/port-conflict.test.js.map +1 -0
- package/dist/process-scanner.d.ts +43 -0
- package/dist/process-scanner.d.ts.map +1 -0
- package/dist/process-scanner.js +453 -0
- package/dist/process-scanner.js.map +1 -0
- package/dist/process-scanner.perf.test.d.ts +2 -0
- package/dist/process-scanner.perf.test.d.ts.map +1 -0
- package/dist/process-scanner.perf.test.js +186 -0
- package/dist/process-scanner.perf.test.js.map +1 -0
- package/dist/process-scanner.test.d.ts +2 -0
- package/dist/process-scanner.test.d.ts.map +1 -0
- package/dist/process-scanner.test.js +399 -0
- package/dist/process-scanner.test.js.map +1 -0
- package/dist/push-protocol.d.ts +15 -0
- package/dist/push-protocol.d.ts.map +1 -0
- package/dist/push-protocol.js +23 -0
- package/dist/push-protocol.js.map +1 -0
- package/dist/push-protocol.test.d.ts +2 -0
- package/dist/push-protocol.test.d.ts.map +1 -0
- package/dist/push-protocol.test.js +57 -0
- package/dist/push-protocol.test.js.map +1 -0
- package/dist/push-store.d.ts +22 -0
- package/dist/push-store.d.ts.map +1 -0
- package/dist/push-store.js +103 -0
- package/dist/push-store.js.map +1 -0
- package/dist/push-store.test.d.ts +2 -0
- package/dist/push-store.test.d.ts.map +1 -0
- package/dist/push-store.test.js +79 -0
- package/dist/push-store.test.js.map +1 -0
- package/dist/push.d.ts +65 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/push.js +202 -0
- package/dist/push.js.map +1 -0
- package/dist/push.test.d.ts +2 -0
- package/dist/push.test.d.ts.map +1 -0
- package/dist/push.test.js +199 -0
- package/dist/push.test.js.map +1 -0
- package/dist/safe-stdio.d.ts +3 -0
- package/dist/safe-stdio.d.ts.map +1 -0
- package/dist/safe-stdio.js +46 -0
- package/dist/safe-stdio.js.map +1 -0
- package/dist/scanner.d.ts +30 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +859 -0
- package/dist/scanner.js.map +1 -0
- package/dist/scanner.perf.test.d.ts +2 -0
- package/dist/scanner.perf.test.d.ts.map +1 -0
- package/dist/scanner.perf.test.js +320 -0
- package/dist/scanner.perf.test.js.map +1 -0
- package/dist/scanner.test.d.ts +2 -0
- package/dist/scanner.test.d.ts.map +1 -0
- package/dist/scanner.test.js +948 -0
- package/dist/scanner.test.js.map +1 -0
- package/dist/session-inventory.d.ts +63 -0
- package/dist/session-inventory.d.ts.map +1 -0
- package/dist/session-inventory.js +525 -0
- package/dist/session-inventory.js.map +1 -0
- package/dist/session-inventory.perf.test.d.ts +2 -0
- package/dist/session-inventory.perf.test.d.ts.map +1 -0
- package/dist/session-inventory.perf.test.js +220 -0
- package/dist/session-inventory.perf.test.js.map +1 -0
- package/dist/session-inventory.test.d.ts +2 -0
- package/dist/session-inventory.test.d.ts.map +1 -0
- package/dist/session-inventory.test.js +712 -0
- package/dist/session-inventory.test.js.map +1 -0
- package/dist/session-manager.d.ts +75 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +1515 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/session-manager.test.d.ts +2 -0
- package/dist/session-manager.test.d.ts.map +1 -0
- package/dist/session-manager.test.js +2861 -0
- package/dist/session-manager.test.js.map +1 -0
- package/dist/session-store.d.ts +42 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +163 -0
- package/dist/session-store.js.map +1 -0
- package/dist/session-store.test.d.ts +2 -0
- package/dist/session-store.test.d.ts.map +1 -0
- package/dist/session-store.test.js +236 -0
- package/dist/session-store.test.js.map +1 -0
- package/dist/session-title.d.ts +6 -0
- package/dist/session-title.d.ts.map +1 -0
- package/dist/session-title.js +105 -0
- package/dist/session-title.js.map +1 -0
- package/dist/session-title.perf.test.d.ts +2 -0
- package/dist/session-title.perf.test.d.ts.map +1 -0
- package/dist/session-title.perf.test.js +99 -0
- package/dist/session-title.perf.test.js.map +1 -0
- package/dist/session-title.test.d.ts +2 -0
- package/dist/session-title.test.d.ts.map +1 -0
- package/dist/session-title.test.js +199 -0
- package/dist/session-title.test.js.map +1 -0
- package/dist/shutdown-endpoint.test.d.ts +2 -0
- package/dist/shutdown-endpoint.test.d.ts.map +1 -0
- package/dist/shutdown-endpoint.test.js +93 -0
- package/dist/shutdown-endpoint.test.js.map +1 -0
- package/dist/storage-housekeeping.d.ts +28 -0
- package/dist/storage-housekeeping.d.ts.map +1 -0
- package/dist/storage-housekeeping.js +76 -0
- package/dist/storage-housekeeping.js.map +1 -0
- package/dist/storage-housekeeping.test.d.ts +2 -0
- package/dist/storage-housekeeping.test.d.ts.map +1 -0
- package/dist/storage-housekeeping.test.js +65 -0
- package/dist/storage-housekeeping.test.js.map +1 -0
- package/dist/test-daemon-harness.d.ts +31 -0
- package/dist/test-daemon-harness.d.ts.map +1 -0
- package/dist/test-daemon-harness.js +337 -0
- package/dist/test-daemon-harness.js.map +1 -0
- package/dist/token-auth.test.d.ts +2 -0
- package/dist/token-auth.test.d.ts.map +1 -0
- package/dist/token-auth.test.js +52 -0
- package/dist/token-auth.test.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +40 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/dist/utils.test.js +54 -0
- package/dist/utils.test.js.map +1 -0
- package/dist/ws-data.d.ts +4 -0
- package/dist/ws-data.d.ts.map +1 -0
- package/dist/ws-data.js +20 -0
- package/dist/ws-data.js.map +1 -0
- package/dist/ws-data.test.d.ts +2 -0
- package/dist/ws-data.test.d.ts.map +1 -0
- package/dist/ws-data.test.js +17 -0
- package/dist/ws-data.test.js.map +1 -0
- package/package.json +24 -24
- package/perf-reporter.mjs +138 -0
- package/scripts/build-release.mjs +41 -0
- package/scripts/dev.mjs +537 -0
- package/src/advertised-hosts.test.ts +125 -0
- package/src/advertised-hosts.ts +225 -0
- package/src/audit.test.ts +38 -0
- package/src/audit.ts +117 -0
- package/src/auth.ts +31 -0
- package/src/claude-hooks.ts +195 -0
- package/src/cli-version.test.ts +36 -0
- package/src/cli-version.ts +46 -0
- package/src/config.test.ts +254 -0
- package/src/config.ts +324 -0
- package/src/dev-auth.test.ts +183 -0
- package/src/dev-script.test.ts +511 -0
- package/src/drivers/claude.test.ts +1186 -0
- package/src/drivers/claude.ts +443 -0
- package/src/drivers/codex.test.ts +1096 -0
- package/src/drivers/codex.ts +879 -0
- package/src/drivers/types.ts +15 -0
- package/src/e2e.test.ts +139 -0
- package/src/identity.test.ts +26 -0
- package/src/identity.ts +82 -0
- package/src/index-entry.test.ts +336 -0
- package/src/index.ts +781 -0
- package/src/logger.ts +112 -0
- package/src/metrics.ts +117 -0
- package/src/pairing-store.test.ts +53 -0
- package/src/pairing-store.ts +154 -0
- package/src/paths.ts +19 -0
- package/src/perf-compare.ts +164 -0
- package/src/port-conflict.test.ts +45 -0
- package/src/port-conflict.ts +44 -0
- package/src/process-scanner.perf.test.ts +222 -0
- package/src/process-scanner.test.ts +575 -0
- package/src/process-scanner.ts +514 -0
- package/src/push-protocol.test.ts +74 -0
- package/src/push-protocol.ts +36 -0
- package/src/push-store.test.ts +89 -0
- package/src/push-store.ts +126 -0
- package/src/push.test.ts +234 -0
- package/src/push.ts +318 -0
- package/src/safe-stdio.ts +51 -0
- package/src/scanner.perf.test.ts +359 -0
- package/src/scanner.test.ts +1045 -0
- package/src/scanner.ts +924 -0
- package/src/session-inventory.perf.test.ts +250 -0
- package/src/session-inventory.test.ts +1002 -0
- package/src/session-inventory.ts +721 -0
- package/src/session-manager.test.ts +3430 -0
- package/src/session-manager.ts +1775 -0
- package/src/session-store.test.ts +276 -0
- package/src/session-store.ts +202 -0
- package/src/session-title.perf.test.ts +118 -0
- package/src/session-title.test.ts +286 -0
- package/src/session-title.ts +108 -0
- package/src/shutdown-endpoint.test.ts +95 -0
- package/src/storage-housekeeping.test.ts +78 -0
- package/src/storage-housekeeping.ts +111 -0
- package/src/test-daemon-harness.ts +410 -0
- package/src/token-auth.test.ts +67 -0
- package/src/utils.test.ts +65 -0
- package/src/utils.ts +47 -0
- package/src/ws-data.test.ts +20 -0
- package/src/ws-data.ts +26 -0
- package/tsconfig.json +12 -0
- package/README.md +0 -80
- package/bin/cloudflared-quick-tunnel.mjs +0 -11
- package/bin/cloudflared-resolver.mjs +0 -68
- package/bin/vibelet-runtime-policy.mjs +0 -36
- package/bin/vibelet.cjs +0 -12
- package/bin/vibelet.mjs +0 -1035
- package/dist/index.cjs +0 -125
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdir, mkdtemp, rm, utimes, writeFile } from 'fs/promises';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import {
|
|
7
|
+
classifyProcessSnapshot,
|
|
8
|
+
extractExplicitSessionId,
|
|
9
|
+
findRecentSessionFileForCwd,
|
|
10
|
+
hasContinueFlag,
|
|
11
|
+
isRelevantProcessCommand,
|
|
12
|
+
isProcessAlive,
|
|
13
|
+
mergeRunningSessionCandidates,
|
|
14
|
+
type ProcessSnapshot,
|
|
15
|
+
type RunningSessionCandidate,
|
|
16
|
+
} from './process-scanner.js';
|
|
17
|
+
|
|
18
|
+
function snapshot(overrides: Partial<ProcessSnapshot>): ProcessSnapshot {
|
|
19
|
+
return {
|
|
20
|
+
pid: 1,
|
|
21
|
+
agent: 'codex',
|
|
22
|
+
command: 'codex --yolo',
|
|
23
|
+
cwd: '/repo',
|
|
24
|
+
sessionFiles: [],
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test('classifies explicit codex resume as high confidence', () => {
|
|
30
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
31
|
+
pid: 6581,
|
|
32
|
+
command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(candidate, {
|
|
36
|
+
agent: 'codex',
|
|
37
|
+
pid: 6581,
|
|
38
|
+
cwd: '/repo',
|
|
39
|
+
command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
40
|
+
sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
41
|
+
confidence: 'high',
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('classifies explicit Claude resume with permission flags and keeps approval mode', () => {
|
|
46
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
47
|
+
agent: 'claude',
|
|
48
|
+
pid: 6582,
|
|
49
|
+
command: 'claude --resume session-1 --permission-mode acceptEdits',
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
assert.deepEqual(candidate, {
|
|
53
|
+
agent: 'claude',
|
|
54
|
+
pid: 6582,
|
|
55
|
+
cwd: '/repo',
|
|
56
|
+
command: 'claude --resume session-1 --permission-mode acceptEdits',
|
|
57
|
+
sessionId: 'session-1',
|
|
58
|
+
confidence: 'high',
|
|
59
|
+
approvalMode: 'acceptEdits',
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('classifies explicit Claude bypass mode from process command', () => {
|
|
64
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
65
|
+
agent: 'claude',
|
|
66
|
+
pid: 6583,
|
|
67
|
+
command: 'claude --resume session-2 --dangerously-skip-permissions',
|
|
68
|
+
}));
|
|
69
|
+
|
|
70
|
+
assert.equal(candidate?.approvalMode, 'autoApprove');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('classifies explicit Claude resume without forcing normal and keeps unique session file for hydration', () => {
|
|
74
|
+
const filePath = '/Users/test/.claude/projects/-Users-test-repo/session-3.jsonl';
|
|
75
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
76
|
+
agent: 'claude',
|
|
77
|
+
pid: 6584,
|
|
78
|
+
command: 'claude --resume session-3',
|
|
79
|
+
sessionFiles: [filePath],
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
assert.deepEqual(candidate, {
|
|
83
|
+
agent: 'claude',
|
|
84
|
+
pid: 6584,
|
|
85
|
+
cwd: '/repo',
|
|
86
|
+
command: 'claude --resume session-3',
|
|
87
|
+
sessionId: 'session-3',
|
|
88
|
+
confidence: 'high',
|
|
89
|
+
sessionFilePath: filePath,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('classifies a single codex rollout file as medium confidence', () => {
|
|
94
|
+
const filePath = '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d08ac-c265-7270-9497-d14125228a50.jsonl';
|
|
95
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
96
|
+
pid: 52424,
|
|
97
|
+
sessionFiles: [filePath],
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
assert.equal(candidate?.confidence, 'medium');
|
|
101
|
+
assert.equal(candidate?.sessionId, '019d08ac-c265-7270-9497-d14125228a50');
|
|
102
|
+
assert.equal(candidate?.sessionFilePath, filePath);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('drops ambiguous app-server processes with multiple session files', () => {
|
|
106
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
107
|
+
command: 'codex app-server',
|
|
108
|
+
sessionFiles: [
|
|
109
|
+
'/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d08ac-c265-7270-9497-d14125228a50.jsonl',
|
|
110
|
+
'/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-42-17-019d08b1-67e6-75a1-bdb6-3c1b25b1103b.jsonl',
|
|
111
|
+
],
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
assert.equal(candidate, null);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('drops claude --continue without a unique session file', () => {
|
|
118
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
119
|
+
agent: 'claude',
|
|
120
|
+
command: 'claude --dangerously-skip-permissions --continue',
|
|
121
|
+
sessionFiles: [],
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
assert.equal(candidate, null);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('drops claude subagent transcript files', () => {
|
|
128
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
129
|
+
agent: 'claude',
|
|
130
|
+
command: 'claude --dangerously-skip-permissions --continue',
|
|
131
|
+
sessionFiles: [
|
|
132
|
+
'/Users/test/.claude/projects/-Users-test/repo/subagents/agent-aa9cc4dbb140502a8.jsonl',
|
|
133
|
+
],
|
|
134
|
+
}));
|
|
135
|
+
|
|
136
|
+
assert.equal(candidate, null);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ===== extractExplicitSessionId =====
|
|
140
|
+
|
|
141
|
+
test('extracts claude session id from --resume flag', () => {
|
|
142
|
+
assert.equal(
|
|
143
|
+
extractExplicitSessionId('claude', 'claude --resume abc-123-def'),
|
|
144
|
+
'abc-123-def',
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('extracts claude session id from --resume= syntax', () => {
|
|
149
|
+
assert.equal(
|
|
150
|
+
extractExplicitSessionId('claude', 'claude --resume=abc-123-def'),
|
|
151
|
+
'abc-123-def',
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('returns null for claude without --resume', () => {
|
|
156
|
+
assert.equal(
|
|
157
|
+
extractExplicitSessionId('claude', 'claude --dangerously-skip-permissions --continue'),
|
|
158
|
+
null,
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('returns null when --resume has no value', () => {
|
|
163
|
+
assert.equal(
|
|
164
|
+
extractExplicitSessionId('claude', 'claude --resume --other-flag'),
|
|
165
|
+
null,
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('extracts codex session id from resume subcommand', () => {
|
|
170
|
+
assert.equal(
|
|
171
|
+
extractExplicitSessionId('codex', 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111'),
|
|
172
|
+
'019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('returns null for codex without resume subcommand', () => {
|
|
177
|
+
assert.equal(
|
|
178
|
+
extractExplicitSessionId('codex', 'codex --yolo'),
|
|
179
|
+
null,
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('returns null when agent does not match binary in command', () => {
|
|
184
|
+
assert.equal(
|
|
185
|
+
extractExplicitSessionId('claude', 'codex resume abc-123'),
|
|
186
|
+
null,
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('handles quoted tokens in command', () => {
|
|
191
|
+
assert.equal(
|
|
192
|
+
extractExplicitSessionId('claude', 'claude --resume "my-session-id"'),
|
|
193
|
+
'my-session-id',
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('handles full path to binary', () => {
|
|
198
|
+
assert.equal(
|
|
199
|
+
extractExplicitSessionId('claude', '/usr/local/bin/claude --resume sess-1'),
|
|
200
|
+
'sess-1',
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('extracts claude session id from shell-wrapped resume command', () => {
|
|
205
|
+
assert.equal(
|
|
206
|
+
extractExplicitSessionId('claude', "zsh -lc 'cd /repo && claude --resume sess-1'"),
|
|
207
|
+
'sess-1',
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('returns null for empty command', () => {
|
|
212
|
+
assert.equal(
|
|
213
|
+
extractExplicitSessionId('codex', ''),
|
|
214
|
+
null,
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// ===== relevant process command matching =====
|
|
219
|
+
|
|
220
|
+
test('isRelevantProcessCommand matches shell-wrapped claude resume commands', () => {
|
|
221
|
+
assert.equal(
|
|
222
|
+
isRelevantProcessCommand("zsh -lc 'cd /repo && claude --resume sess-1'"),
|
|
223
|
+
true,
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('isRelevantProcessCommand ignores binaries that only contain claude as a substring', () => {
|
|
228
|
+
assert.equal(
|
|
229
|
+
isRelevantProcessCommand("zsh -lc '/usr/local/bin/claude-wrapper --resume sess-1'"),
|
|
230
|
+
false,
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ===== mergeRunningSessionCandidates (continued) =====
|
|
235
|
+
|
|
236
|
+
test('dedupes duplicate running candidates by keeping the higher confidence entry', () => {
|
|
237
|
+
const high: RunningSessionCandidate = {
|
|
238
|
+
agent: 'codex',
|
|
239
|
+
pid: 6581,
|
|
240
|
+
cwd: '/repo',
|
|
241
|
+
command: 'codex resume 019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
242
|
+
sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
243
|
+
confidence: 'high',
|
|
244
|
+
};
|
|
245
|
+
const medium: RunningSessionCandidate = {
|
|
246
|
+
agent: 'codex',
|
|
247
|
+
pid: 72545,
|
|
248
|
+
cwd: '/repo',
|
|
249
|
+
command: 'codex --yolo',
|
|
250
|
+
sessionId: '019d03e3-2672-7011-9c6d-5ba083b71111',
|
|
251
|
+
confidence: 'medium',
|
|
252
|
+
title: 'Recovered title',
|
|
253
|
+
sessionFilePath: '/Users/test/.codex/sessions/2026/03/20/rollout-2026-03-20T08-37-12-019d03e3-2672-7011-9c6d-5ba083b71111.jsonl',
|
|
254
|
+
isResponding: true,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
assert.deepEqual(mergeRunningSessionCandidates([medium, high]), [{
|
|
258
|
+
...high,
|
|
259
|
+
title: 'Recovered title',
|
|
260
|
+
sessionFilePath: medium.sessionFilePath,
|
|
261
|
+
isResponding: true,
|
|
262
|
+
}]);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('mergeRunningSessionCandidates: keeps both when different sessionIds', () => {
|
|
266
|
+
const a: RunningSessionCandidate = {
|
|
267
|
+
agent: 'codex', pid: 1, cwd: '/repo', command: 'codex',
|
|
268
|
+
sessionId: 'aaa', confidence: 'high',
|
|
269
|
+
};
|
|
270
|
+
const b: RunningSessionCandidate = {
|
|
271
|
+
agent: 'codex', pid: 2, cwd: '/repo', command: 'codex',
|
|
272
|
+
sessionId: 'bbb', confidence: 'high',
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
assert.equal(mergeRunningSessionCandidates([a, b]).length, 2);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('mergeRunningSessionCandidates: returns empty for empty input', () => {
|
|
279
|
+
assert.deepEqual(mergeRunningSessionCandidates([]), []);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// ===== classifyProcessSnapshot edge cases =====
|
|
283
|
+
|
|
284
|
+
test('classifies claude --resume as high confidence', () => {
|
|
285
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
286
|
+
agent: 'claude',
|
|
287
|
+
command: 'claude --resume my-session-id-123',
|
|
288
|
+
sessionFiles: [],
|
|
289
|
+
}));
|
|
290
|
+
|
|
291
|
+
assert.equal(candidate?.confidence, 'high');
|
|
292
|
+
assert.equal(candidate?.sessionId, 'my-session-id-123');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('classifies single claude project file as medium confidence', () => {
|
|
296
|
+
const filePath = '/Users/test/.claude/projects/-Users-test-repo/session-abc.jsonl';
|
|
297
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
298
|
+
agent: 'claude',
|
|
299
|
+
command: 'claude --dangerously-skip-permissions',
|
|
300
|
+
sessionFiles: [filePath],
|
|
301
|
+
}));
|
|
302
|
+
|
|
303
|
+
assert.equal(candidate?.confidence, 'medium');
|
|
304
|
+
assert.equal(candidate?.sessionId, 'session-abc');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('returns null for process with no session files and no explicit id', () => {
|
|
308
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
309
|
+
command: 'codex app-server',
|
|
310
|
+
sessionFiles: [],
|
|
311
|
+
}));
|
|
312
|
+
|
|
313
|
+
assert.equal(candidate, null);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test('filters out non-supported session file paths', () => {
|
|
317
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
318
|
+
command: 'codex app-server',
|
|
319
|
+
sessionFiles: ['/tmp/random.jsonl'],
|
|
320
|
+
}));
|
|
321
|
+
|
|
322
|
+
assert.equal(candidate, null);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// ===== extractExplicitSessionId edge cases =====
|
|
326
|
+
|
|
327
|
+
test('extracts codex resume id skipping flags before session id', () => {
|
|
328
|
+
assert.equal(
|
|
329
|
+
extractExplicitSessionId('codex', 'codex resume --some-flag session-id-abc'),
|
|
330
|
+
'session-id-abc',
|
|
331
|
+
);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test('returns null for codex resume with only flags', () => {
|
|
335
|
+
assert.equal(
|
|
336
|
+
extractExplicitSessionId('codex', 'codex resume --flag-only'),
|
|
337
|
+
null,
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test('handles single-quoted session id', () => {
|
|
342
|
+
assert.equal(
|
|
343
|
+
extractExplicitSessionId('claude', "claude --resume 'my-session'"),
|
|
344
|
+
'my-session',
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// ===== classifyProcessSnapshot edge cases =====
|
|
349
|
+
|
|
350
|
+
test('classifies process with single codex session file in supported path', () => {
|
|
351
|
+
const filePath = '/Users/test/.codex/sessions/2026/03/20/some-file-019d08ac-c265-7270-9497-d14125228a50.jsonl';
|
|
352
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
353
|
+
command: 'codex app-server',
|
|
354
|
+
sessionFiles: [filePath],
|
|
355
|
+
}));
|
|
356
|
+
|
|
357
|
+
assert.equal(candidate?.confidence, 'medium');
|
|
358
|
+
assert.equal(candidate?.sessionFilePath, filePath);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test('classifies process with single claude project file', () => {
|
|
362
|
+
const filePath = '/Users/test/.claude/projects/-Users-test-repo/my-session.jsonl';
|
|
363
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
364
|
+
agent: 'claude',
|
|
365
|
+
command: 'claude --continue',
|
|
366
|
+
sessionFiles: [filePath],
|
|
367
|
+
}));
|
|
368
|
+
|
|
369
|
+
assert.equal(candidate?.confidence, 'medium');
|
|
370
|
+
assert.equal(candidate?.sessionId, 'my-session');
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test('ignores duplicate session files (dedupes before counting)', () => {
|
|
374
|
+
const filePath = '/Users/test/.codex/sessions/2026/03/20/rollout-019d08ac-c265-7270-9497-d14125228a50.jsonl';
|
|
375
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
376
|
+
command: 'codex app-server',
|
|
377
|
+
sessionFiles: [filePath, filePath], // duplicate
|
|
378
|
+
}));
|
|
379
|
+
|
|
380
|
+
assert.equal(candidate?.confidence, 'medium');
|
|
381
|
+
assert.equal(candidate?.sessionId, '019d08ac-c265-7270-9497-d14125228a50');
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// ===== mergeRunningSessionCandidates edge cases =====
|
|
385
|
+
|
|
386
|
+
test('mergeRunningSessionCandidates: same confidence uses lower PID as winner', () => {
|
|
387
|
+
const a: RunningSessionCandidate = {
|
|
388
|
+
agent: 'codex', pid: 100, cwd: '/repo', command: 'codex',
|
|
389
|
+
sessionId: 'same-id', confidence: 'medium',
|
|
390
|
+
};
|
|
391
|
+
const b: RunningSessionCandidate = {
|
|
392
|
+
agent: 'codex', pid: 200, cwd: '/other', command: 'codex',
|
|
393
|
+
sessionId: 'same-id', confidence: 'medium',
|
|
394
|
+
title: 'Title from B',
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const result = mergeRunningSessionCandidates([a, b]);
|
|
398
|
+
assert.equal(result.length, 1);
|
|
399
|
+
assert.equal(result[0].pid, 100); // lower PID wins
|
|
400
|
+
assert.equal(result[0].title, 'Title from B'); // title merged from loser
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('mergeRunningSessionCandidates: winner gets cwd from loser when winner has empty cwd', () => {
|
|
404
|
+
const a: RunningSessionCandidate = {
|
|
405
|
+
agent: 'codex', pid: 1, cwd: '', command: 'codex',
|
|
406
|
+
sessionId: 'id-1', confidence: 'high',
|
|
407
|
+
};
|
|
408
|
+
const b: RunningSessionCandidate = {
|
|
409
|
+
agent: 'codex', pid: 2, cwd: '/repo', command: 'codex',
|
|
410
|
+
sessionId: 'id-1', confidence: 'low',
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const result = mergeRunningSessionCandidates([a, b]);
|
|
414
|
+
assert.equal(result[0].cwd, '/repo');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('mergeRunningSessionCandidates: different agents are separate entries', () => {
|
|
418
|
+
const a: RunningSessionCandidate = {
|
|
419
|
+
agent: 'codex', pid: 1, cwd: '/repo', command: 'codex',
|
|
420
|
+
sessionId: 'same-id', confidence: 'high',
|
|
421
|
+
};
|
|
422
|
+
const b: RunningSessionCandidate = {
|
|
423
|
+
agent: 'claude', pid: 2, cwd: '/repo', command: 'claude',
|
|
424
|
+
sessionId: 'same-id', confidence: 'high',
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
const result = mergeRunningSessionCandidates([a, b]);
|
|
428
|
+
assert.equal(result.length, 2); // different agents = different keys
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
test('mergeRunningSessionCandidates: single candidate passes through', () => {
|
|
432
|
+
const a: RunningSessionCandidate = {
|
|
433
|
+
agent: 'codex', pid: 42, cwd: '/repo', command: 'codex resume abc',
|
|
434
|
+
sessionId: 'abc', confidence: 'high', title: 'My Title',
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const result = mergeRunningSessionCandidates([a]);
|
|
438
|
+
assert.equal(result.length, 1);
|
|
439
|
+
assert.deepEqual(result[0], a);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// ===== extractExplicitSessionId: --session-id support =====
|
|
443
|
+
|
|
444
|
+
test('extracts claude session id from --session-id flag', () => {
|
|
445
|
+
assert.equal(
|
|
446
|
+
extractExplicitSessionId('claude', 'claude --session-id 7f03bcf8-d5aa-4eb2-b123-abcdef012345'),
|
|
447
|
+
'7f03bcf8-d5aa-4eb2-b123-abcdef012345',
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('extracts claude session id from --session-id= syntax', () => {
|
|
452
|
+
assert.equal(
|
|
453
|
+
extractExplicitSessionId('claude', 'claude --session-id=7f03bcf8-d5aa-4eb2-b123-abcdef012345'),
|
|
454
|
+
'7f03bcf8-d5aa-4eb2-b123-abcdef012345',
|
|
455
|
+
);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test('extracts claude session id from full path binary with --session-id', () => {
|
|
459
|
+
assert.equal(
|
|
460
|
+
extractExplicitSessionId('claude', '/Users/test/.local/bin/claude --session-id abc-123'),
|
|
461
|
+
'abc-123',
|
|
462
|
+
);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
test('classifies claude --session-id as high confidence', () => {
|
|
466
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
467
|
+
agent: 'claude',
|
|
468
|
+
command: '/Users/test/.local/bin/claude --session-id 7f03bcf8-d5aa-4eb2-b123-abcdef012345',
|
|
469
|
+
sessionFiles: [],
|
|
470
|
+
}));
|
|
471
|
+
|
|
472
|
+
assert.equal(candidate?.confidence, 'high');
|
|
473
|
+
assert.equal(candidate?.sessionId, '7f03bcf8-d5aa-4eb2-b123-abcdef012345');
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// ===== hasContinueFlag =====
|
|
477
|
+
|
|
478
|
+
test('hasContinueFlag detects --continue', () => {
|
|
479
|
+
assert.equal(hasContinueFlag('claude', 'claude --dangerously-skip-permissions --continue'), true);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test('hasContinueFlag detects -c shorthand', () => {
|
|
483
|
+
assert.equal(hasContinueFlag('claude', '/usr/local/bin/claude -c'), true);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
test('hasContinueFlag returns false without --continue', () => {
|
|
487
|
+
assert.equal(hasContinueFlag('claude', 'claude --resume abc'), false);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test('hasContinueFlag returns false for wrong agent', () => {
|
|
491
|
+
assert.equal(hasContinueFlag('codex', 'claude --continue'), false);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// ===== cwd fallback: classifyProcessSnapshot returns null, scanRunningSessions uses filesystem =====
|
|
495
|
+
|
|
496
|
+
test('classifyProcessSnapshot returns null for --continue without session files (fallback skipped)', () => {
|
|
497
|
+
const candidate = classifyProcessSnapshot(snapshot({
|
|
498
|
+
agent: 'claude',
|
|
499
|
+
command: '/Users/test/.local/bin/claude --dangerously-skip-permissions --continue',
|
|
500
|
+
cwd: '/some/project',
|
|
501
|
+
sessionFiles: [],
|
|
502
|
+
}));
|
|
503
|
+
|
|
504
|
+
// classifyProcessSnapshot returns null; scanRunningSessions skips the mtime fallback for --continue
|
|
505
|
+
assert.equal(candidate, null);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
test('findRecentSessionFileForCwd matches Codex fallback by cwd instead of global newest file', async () => {
|
|
509
|
+
const tempHome = await mkdtemp(join(tmpdir(), 'vibe-codex-cwd-'));
|
|
510
|
+
const sessionsDir = join(tempHome, '.codex', 'sessions', '2026', '03', '21');
|
|
511
|
+
const matchingOld = join(sessionsDir, 'matching-old.jsonl');
|
|
512
|
+
const nonMatchingNewest = join(sessionsDir, 'other-cwd.jsonl');
|
|
513
|
+
const matchingNewest = join(sessionsDir, 'matching-new.jsonl');
|
|
514
|
+
const originalHome = process.env.HOME;
|
|
515
|
+
|
|
516
|
+
await mkdir(sessionsDir, { recursive: true });
|
|
517
|
+
await writeFile(matchingOld, `${JSON.stringify({ cwd: '/repo-a', id: 'codex-a-old', title: 'Old match' })}\n`);
|
|
518
|
+
await writeFile(nonMatchingNewest, `${JSON.stringify({ cwd: '/repo-b', id: 'codex-b-new', title: 'Wrong cwd' })}\n`);
|
|
519
|
+
await writeFile(matchingNewest, `${JSON.stringify({ cwd: '/repo-a', id: 'codex-a-new', title: 'New match' })}\n`);
|
|
520
|
+
|
|
521
|
+
await utimes(matchingOld, new Date(1_000), new Date(1_000));
|
|
522
|
+
await utimes(nonMatchingNewest, new Date(4_000), new Date(4_000));
|
|
523
|
+
await utimes(matchingNewest, new Date(3_000), new Date(3_000));
|
|
524
|
+
|
|
525
|
+
process.env.HOME = tempHome;
|
|
526
|
+
|
|
527
|
+
try {
|
|
528
|
+
const result = await findRecentSessionFileForCwd('codex', '/repo-a');
|
|
529
|
+
assert.deepEqual(result, {
|
|
530
|
+
sessionId: 'codex-a-new',
|
|
531
|
+
filePath: matchingNewest,
|
|
532
|
+
});
|
|
533
|
+
} finally {
|
|
534
|
+
process.env.HOME = originalHome;
|
|
535
|
+
await rm(tempHome, { recursive: true, force: true });
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// ===== scanProcessSnapshots / scanRunningSessions (live system tests) =====
|
|
540
|
+
|
|
541
|
+
import { scanProcessSnapshots, scanRunningSessions } from './process-scanner.js';
|
|
542
|
+
|
|
543
|
+
test('scanProcessSnapshots returns an array', async () => {
|
|
544
|
+
const snapshots = await scanProcessSnapshots();
|
|
545
|
+
assert.ok(Array.isArray(snapshots));
|
|
546
|
+
// Each snapshot should have the right shape
|
|
547
|
+
for (const s of snapshots) {
|
|
548
|
+
assert.equal(typeof s.pid, 'number');
|
|
549
|
+
assert.ok(s.agent === 'claude' || s.agent === 'codex');
|
|
550
|
+
assert.equal(typeof s.command, 'string');
|
|
551
|
+
assert.equal(typeof s.cwd, 'string');
|
|
552
|
+
assert.ok(Array.isArray(s.sessionFiles));
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test('scanRunningSessions returns an array of valid candidates', async () => {
|
|
557
|
+
const candidates = await scanRunningSessions();
|
|
558
|
+
assert.ok(Array.isArray(candidates));
|
|
559
|
+
for (const c of candidates) {
|
|
560
|
+
assert.equal(typeof c.sessionId, 'string');
|
|
561
|
+
assert.ok(c.agent === 'claude' || c.agent === 'codex');
|
|
562
|
+
assert.ok(['high', 'medium', 'low'].includes(c.confidence));
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
// ─── isProcessAlive ──────────────────────────────────────────────────────────
|
|
567
|
+
|
|
568
|
+
test('isProcessAlive returns true for the current process', () => {
|
|
569
|
+
assert.equal(isProcessAlive(process.pid), true);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test('isProcessAlive returns false for a non-existent PID', () => {
|
|
573
|
+
// PID 2147483647 (INT32_MAX) is almost certainly not in use.
|
|
574
|
+
assert.equal(isProcessAlive(2147483647), false);
|
|
575
|
+
});
|