everything-mcp 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl
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.
- everything_mcp/__init__.py +14 -14
- everything_mcp/backend.py +455 -455
- everything_mcp/config.py +253 -253
- everything_mcp/server.py +745 -745
- {everything_mcp-1.0.1.dist-info → everything_mcp-1.0.3.dist-info}/METADATA +53 -11
- everything_mcp-1.0.3.dist-info/RECORD +11 -0
- {everything_mcp-1.0.1.dist-info → everything_mcp-1.0.3.dist-info}/licenses/LICENSE +1 -1
- everything_mcp-1.0.1.dist-info/RECORD +0 -11
- {everything_mcp-1.0.1.dist-info → everything_mcp-1.0.3.dist-info}/WHEEL +0 -0
- {everything_mcp-1.0.1.dist-info → everything_mcp-1.0.3.dist-info}/entry_points.txt +0 -0
everything_mcp/config.py
CHANGED
|
@@ -1,253 +1,253 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Auto-detection and configuration for voidtools Everything.
|
|
3
|
-
|
|
4
|
-
Finds es.exe, detects Everything version/instance, and validates the setup.
|
|
5
|
-
Zero-config by default
|
|
6
|
-
locations, and the Windows Registry.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import logging
|
|
12
|
-
import os
|
|
13
|
-
import shutil
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
|
-
from dataclasses import dataclass, field
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
|
|
19
|
-
__all__ = ["EverythingConfig"]
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger("everything_mcp")
|
|
22
|
-
|
|
23
|
-
# ── Search locations for es.exe ───────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
ES_SEARCH_PATHS: list[str] = [
|
|
26
|
-
os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\WindowsApps"),
|
|
27
|
-
r"C:\Program Files\Everything",
|
|
28
|
-
r"C:\Program Files (x86)\Everything",
|
|
29
|
-
r"C:\Program Files\Everything 1.5a",
|
|
30
|
-
r"C:\Program Files (x86)\Everything 1.5a",
|
|
31
|
-
os.path.expandvars(r"%LOCALAPPDATA%\Everything"),
|
|
32
|
-
os.path.expandvars(r"%USERPROFILE%\Everything"),
|
|
33
|
-
os.path.expandvars(r"%PROGRAMDATA%\Everything"),
|
|
34
|
-
os.path.expandvars(r"%USERPROFILE%\scoop\shims"),
|
|
35
|
-
os.path.expandvars(r"%USERPROFILE%\scoop\apps\everything\current"),
|
|
36
|
-
os.path.expandvars(r"%PROGRAMDATA%\chocolatey\bin"),
|
|
37
|
-
]
|
|
38
|
-
|
|
39
|
-
# Suppress console window on Windows
|
|
40
|
-
_CREATE_NO_WINDOW: int = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@dataclass
|
|
44
|
-
class EverythingConfig:
|
|
45
|
-
"""Configuration for communicating with Everything."""
|
|
46
|
-
|
|
47
|
-
es_path: str = ""
|
|
48
|
-
instance: str = ""
|
|
49
|
-
timeout: int = 30
|
|
50
|
-
max_results_cap: int = 1000
|
|
51
|
-
errors: list[str] = field(default_factory=list)
|
|
52
|
-
warnings: list[str] = field(default_factory=list)
|
|
53
|
-
version_info: str = ""
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def is_valid(self) -> bool:
|
|
57
|
-
"""True when es.exe was found and Everything is responding."""
|
|
58
|
-
return bool(self.es_path) and len(self.errors) == 0
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def auto_detect(cls) -> EverythingConfig:
|
|
62
|
-
"""Auto-detect Everything installation and return a ready config.
|
|
63
|
-
|
|
64
|
-
Detection order:
|
|
65
|
-
1. ``EVERYTHING_ES_PATH`` / ``EVERYTHING_INSTANCE`` env vars
|
|
66
|
-
2. ``es.exe`` on ``PATH`` (verified via ``-get-everything-version``)
|
|
67
|
-
3. Common installation directories
|
|
68
|
-
4. Windows Registry
|
|
69
|
-
5. Instance auto-detection (default → 1.5a)
|
|
70
|
-
6. Connectivity test
|
|
71
|
-
"""
|
|
72
|
-
config = cls()
|
|
73
|
-
|
|
74
|
-
env_path = os.environ.get("EVERYTHING_ES_PATH", "").strip()
|
|
75
|
-
env_instance = os.environ.get("EVERYTHING_INSTANCE", "").strip()
|
|
76
|
-
|
|
77
|
-
if env_instance:
|
|
78
|
-
config.instance = env_instance
|
|
79
|
-
logger.info("Using instance from EVERYTHING_INSTANCE=%s", env_instance)
|
|
80
|
-
|
|
81
|
-
config.es_path = _find_es_exe(env_path)
|
|
82
|
-
|
|
83
|
-
if not config.es_path:
|
|
84
|
-
config.errors.append(
|
|
85
|
-
"es.exe not found. Install from https://github.com/voidtools/es/releases "
|
|
86
|
-
"or set the EVERYTHING_ES_PATH environment variable. "
|
|
87
|
-
"Everything (https://www.voidtools.com/) must be installed and running."
|
|
88
|
-
)
|
|
89
|
-
return config
|
|
90
|
-
|
|
91
|
-
logger.info("Found es.exe: %s", config.es_path)
|
|
92
|
-
|
|
93
|
-
if not config.instance:
|
|
94
|
-
config.instance = _detect_instance(config.es_path)
|
|
95
|
-
if config.instance:
|
|
96
|
-
logger.info("Auto-detected instance: %s", config.instance)
|
|
97
|
-
|
|
98
|
-
ok, info = _test_connection(config.es_path, config.instance)
|
|
99
|
-
if ok:
|
|
100
|
-
config.version_info = info
|
|
101
|
-
logger.info("Everything connection OK: %s", info)
|
|
102
|
-
else:
|
|
103
|
-
config.errors.append(
|
|
104
|
-
f"Cannot connect to Everything: {info}. "
|
|
105
|
-
"Ensure Everything is running (check your system tray). "
|
|
106
|
-
"If you use Everything 1.5 alpha, try EVERYTHING_INSTANCE=1.5a"
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
return config
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# ── Internal helpers ──────────────────────────────────────────────────────
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _find_es_exe(env_override: str = "") -> str:
|
|
116
|
-
"""Locate the es.exe executable."""
|
|
117
|
-
if env_override:
|
|
118
|
-
p = Path(env_override)
|
|
119
|
-
if p.is_file() and p.name.lower() == "es.exe":
|
|
120
|
-
if _is_everything_es(str(p)):
|
|
121
|
-
return str(p)
|
|
122
|
-
elif p.is_dir():
|
|
123
|
-
candidate = p / "es.exe"
|
|
124
|
-
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
125
|
-
return str(candidate)
|
|
126
|
-
logger.warning("EVERYTHING_ES_PATH='%s' not valid, continuing search", env_override)
|
|
127
|
-
|
|
128
|
-
for name in ("es", "es.exe"):
|
|
129
|
-
found = shutil.which(name)
|
|
130
|
-
if found and _is_everything_es(found):
|
|
131
|
-
return found
|
|
132
|
-
|
|
133
|
-
for search_dir in ES_SEARCH_PATHS:
|
|
134
|
-
candidate = Path(search_dir) / "es.exe"
|
|
135
|
-
try:
|
|
136
|
-
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
137
|
-
return str(candidate)
|
|
138
|
-
except OSError:
|
|
139
|
-
continue
|
|
140
|
-
|
|
141
|
-
return _find_via_registry()
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def _is_everything_es(path: str) -> bool:
|
|
145
|
-
"""Verify that *path* is voidtools Everything's es.exe."""
|
|
146
|
-
try:
|
|
147
|
-
result = subprocess.run(
|
|
148
|
-
[path, "-get-everything-version"],
|
|
149
|
-
capture_output=True, text=True, timeout=5,
|
|
150
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
151
|
-
)
|
|
152
|
-
output = result.stdout.strip()
|
|
153
|
-
return bool(output) and any(c.isdigit() for c in output)
|
|
154
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
155
|
-
pass
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
result = subprocess.run(
|
|
159
|
-
[path, "-version"],
|
|
160
|
-
capture_output=True, text=True, timeout=5,
|
|
161
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
162
|
-
)
|
|
163
|
-
return "everything" in result.stdout.lower()
|
|
164
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
165
|
-
return False
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def _find_via_registry() -> str:
|
|
169
|
-
"""Look up the Everything install path from the Windows Registry."""
|
|
170
|
-
if sys.platform != "win32":
|
|
171
|
-
return ""
|
|
172
|
-
try:
|
|
173
|
-
import winreg
|
|
174
|
-
except ImportError:
|
|
175
|
-
return ""
|
|
176
|
-
|
|
177
|
-
for hive in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER):
|
|
178
|
-
for subkey in (
|
|
179
|
-
r"SOFTWARE\voidtools\Everything",
|
|
180
|
-
r"SOFTWARE\WOW6432Node\voidtools\Everything",
|
|
181
|
-
):
|
|
182
|
-
try:
|
|
183
|
-
with winreg.OpenKey(hive, subkey) as key:
|
|
184
|
-
install_path, _ = winreg.QueryValueEx(key, "InstallPath")
|
|
185
|
-
candidate = Path(install_path) / "es.exe"
|
|
186
|
-
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
187
|
-
return str(candidate)
|
|
188
|
-
except (FileNotFoundError, OSError):
|
|
189
|
-
continue
|
|
190
|
-
|
|
191
|
-
return ""
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def _detect_instance(es_path: str) -> str:
|
|
195
|
-
"""Detect which Everything instance is running (default vs 1.5a)."""
|
|
196
|
-
try:
|
|
197
|
-
result = subprocess.run(
|
|
198
|
-
[es_path, "-get-everything-version"],
|
|
199
|
-
capture_output=True, text=True, timeout=5,
|
|
200
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
201
|
-
)
|
|
202
|
-
if result.returncode == 0 and result.stdout.strip():
|
|
203
|
-
return ""
|
|
204
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
205
|
-
pass
|
|
206
|
-
|
|
207
|
-
try:
|
|
208
|
-
result = subprocess.run(
|
|
209
|
-
[es_path, "-instance", "1.5a", "-get-everything-version"],
|
|
210
|
-
capture_output=True, text=True, timeout=5,
|
|
211
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
212
|
-
)
|
|
213
|
-
if result.returncode == 0 and result.stdout.strip():
|
|
214
|
-
return "1.5a"
|
|
215
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
216
|
-
pass
|
|
217
|
-
|
|
218
|
-
return ""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def _test_connection(es_path: str, instance: str) -> tuple[bool, str]:
|
|
222
|
-
"""Verify Everything is running and responsive."""
|
|
223
|
-
base = [es_path]
|
|
224
|
-
if instance:
|
|
225
|
-
base.extend(["-instance", instance])
|
|
226
|
-
|
|
227
|
-
try:
|
|
228
|
-
result = subprocess.run(
|
|
229
|
-
[*base, "-get-everything-version"],
|
|
230
|
-
capture_output=True, text=True, timeout=10,
|
|
231
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
232
|
-
)
|
|
233
|
-
if result.returncode == 0 and result.stdout.strip():
|
|
234
|
-
return True, f"Everything v{result.stdout.strip()}"
|
|
235
|
-
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
236
|
-
pass
|
|
237
|
-
|
|
238
|
-
try:
|
|
239
|
-
result = subprocess.run(
|
|
240
|
-
[*base, "-n", "1", "*.txt"],
|
|
241
|
-
capture_output=True, text=True, timeout=10,
|
|
242
|
-
creationflags=_CREATE_NO_WINDOW,
|
|
243
|
-
)
|
|
244
|
-
if result.returncode == 0:
|
|
245
|
-
return True, "Everything connected (version unknown)"
|
|
246
|
-
err = result.stderr.strip() or result.stdout.strip() or "Unknown error"
|
|
247
|
-
return False, err
|
|
248
|
-
except subprocess.TimeoutExpired:
|
|
249
|
-
return False, "Connection timed out"
|
|
250
|
-
except FileNotFoundError:
|
|
251
|
-
return False, f"es.exe not found at {es_path}"
|
|
252
|
-
except OSError as exc:
|
|
253
|
-
return False, str(exc)
|
|
1
|
+
"""
|
|
2
|
+
Auto-detection and configuration for voidtools Everything.
|
|
3
|
+
|
|
4
|
+
Finds es.exe, detects Everything version/instance, and validates the setup.
|
|
5
|
+
Zero-config by default - discovers installation via PATH, common install
|
|
6
|
+
locations, and the Windows Registry.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
import shutil
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
__all__ = ["EverythingConfig"]
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("everything_mcp")
|
|
22
|
+
|
|
23
|
+
# ── Search locations for es.exe ───────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
ES_SEARCH_PATHS: list[str] = [
|
|
26
|
+
os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\WindowsApps"),
|
|
27
|
+
r"C:\Program Files\Everything",
|
|
28
|
+
r"C:\Program Files (x86)\Everything",
|
|
29
|
+
r"C:\Program Files\Everything 1.5a",
|
|
30
|
+
r"C:\Program Files (x86)\Everything 1.5a",
|
|
31
|
+
os.path.expandvars(r"%LOCALAPPDATA%\Everything"),
|
|
32
|
+
os.path.expandvars(r"%USERPROFILE%\Everything"),
|
|
33
|
+
os.path.expandvars(r"%PROGRAMDATA%\Everything"),
|
|
34
|
+
os.path.expandvars(r"%USERPROFILE%\scoop\shims"),
|
|
35
|
+
os.path.expandvars(r"%USERPROFILE%\scoop\apps\everything\current"),
|
|
36
|
+
os.path.expandvars(r"%PROGRAMDATA%\chocolatey\bin"),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# Suppress console window on Windows
|
|
40
|
+
_CREATE_NO_WINDOW: int = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class EverythingConfig:
|
|
45
|
+
"""Configuration for communicating with Everything."""
|
|
46
|
+
|
|
47
|
+
es_path: str = ""
|
|
48
|
+
instance: str = ""
|
|
49
|
+
timeout: int = 30
|
|
50
|
+
max_results_cap: int = 1000
|
|
51
|
+
errors: list[str] = field(default_factory=list)
|
|
52
|
+
warnings: list[str] = field(default_factory=list)
|
|
53
|
+
version_info: str = ""
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def is_valid(self) -> bool:
|
|
57
|
+
"""True when es.exe was found and Everything is responding."""
|
|
58
|
+
return bool(self.es_path) and len(self.errors) == 0
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def auto_detect(cls) -> EverythingConfig:
|
|
62
|
+
"""Auto-detect Everything installation and return a ready config.
|
|
63
|
+
|
|
64
|
+
Detection order:
|
|
65
|
+
1. ``EVERYTHING_ES_PATH`` / ``EVERYTHING_INSTANCE`` env vars
|
|
66
|
+
2. ``es.exe`` on ``PATH`` (verified via ``-get-everything-version``)
|
|
67
|
+
3. Common installation directories
|
|
68
|
+
4. Windows Registry
|
|
69
|
+
5. Instance auto-detection (default → 1.5a)
|
|
70
|
+
6. Connectivity test
|
|
71
|
+
"""
|
|
72
|
+
config = cls()
|
|
73
|
+
|
|
74
|
+
env_path = os.environ.get("EVERYTHING_ES_PATH", "").strip()
|
|
75
|
+
env_instance = os.environ.get("EVERYTHING_INSTANCE", "").strip()
|
|
76
|
+
|
|
77
|
+
if env_instance:
|
|
78
|
+
config.instance = env_instance
|
|
79
|
+
logger.info("Using instance from EVERYTHING_INSTANCE=%s", env_instance)
|
|
80
|
+
|
|
81
|
+
config.es_path = _find_es_exe(env_path)
|
|
82
|
+
|
|
83
|
+
if not config.es_path:
|
|
84
|
+
config.errors.append(
|
|
85
|
+
"es.exe not found. Install from https://github.com/voidtools/es/releases "
|
|
86
|
+
"or set the EVERYTHING_ES_PATH environment variable. "
|
|
87
|
+
"Everything (https://www.voidtools.com/) must be installed and running."
|
|
88
|
+
)
|
|
89
|
+
return config
|
|
90
|
+
|
|
91
|
+
logger.info("Found es.exe: %s", config.es_path)
|
|
92
|
+
|
|
93
|
+
if not config.instance:
|
|
94
|
+
config.instance = _detect_instance(config.es_path)
|
|
95
|
+
if config.instance:
|
|
96
|
+
logger.info("Auto-detected instance: %s", config.instance)
|
|
97
|
+
|
|
98
|
+
ok, info = _test_connection(config.es_path, config.instance)
|
|
99
|
+
if ok:
|
|
100
|
+
config.version_info = info
|
|
101
|
+
logger.info("Everything connection OK: %s", info)
|
|
102
|
+
else:
|
|
103
|
+
config.errors.append(
|
|
104
|
+
f"Cannot connect to Everything: {info}. "
|
|
105
|
+
"Ensure Everything is running (check your system tray). "
|
|
106
|
+
"If you use Everything 1.5 alpha, try EVERYTHING_INSTANCE=1.5a"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return config
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# ── Internal helpers ──────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _find_es_exe(env_override: str = "") -> str:
|
|
116
|
+
"""Locate the es.exe executable."""
|
|
117
|
+
if env_override:
|
|
118
|
+
p = Path(env_override)
|
|
119
|
+
if p.is_file() and p.name.lower() == "es.exe":
|
|
120
|
+
if _is_everything_es(str(p)):
|
|
121
|
+
return str(p)
|
|
122
|
+
elif p.is_dir():
|
|
123
|
+
candidate = p / "es.exe"
|
|
124
|
+
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
125
|
+
return str(candidate)
|
|
126
|
+
logger.warning("EVERYTHING_ES_PATH='%s' not valid, continuing search", env_override)
|
|
127
|
+
|
|
128
|
+
for name in ("es", "es.exe"):
|
|
129
|
+
found = shutil.which(name)
|
|
130
|
+
if found and _is_everything_es(found):
|
|
131
|
+
return found
|
|
132
|
+
|
|
133
|
+
for search_dir in ES_SEARCH_PATHS:
|
|
134
|
+
candidate = Path(search_dir) / "es.exe"
|
|
135
|
+
try:
|
|
136
|
+
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
137
|
+
return str(candidate)
|
|
138
|
+
except OSError:
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
return _find_via_registry()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _is_everything_es(path: str) -> bool:
|
|
145
|
+
"""Verify that *path* is voidtools Everything's es.exe."""
|
|
146
|
+
try:
|
|
147
|
+
result = subprocess.run(
|
|
148
|
+
[path, "-get-everything-version"],
|
|
149
|
+
capture_output=True, text=True, timeout=5,
|
|
150
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
151
|
+
)
|
|
152
|
+
output = result.stdout.strip()
|
|
153
|
+
return bool(output) and any(c.isdigit() for c in output)
|
|
154
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
result = subprocess.run(
|
|
159
|
+
[path, "-version"],
|
|
160
|
+
capture_output=True, text=True, timeout=5,
|
|
161
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
162
|
+
)
|
|
163
|
+
return "everything" in result.stdout.lower()
|
|
164
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _find_via_registry() -> str:
|
|
169
|
+
"""Look up the Everything install path from the Windows Registry."""
|
|
170
|
+
if sys.platform != "win32":
|
|
171
|
+
return ""
|
|
172
|
+
try:
|
|
173
|
+
import winreg
|
|
174
|
+
except ImportError:
|
|
175
|
+
return ""
|
|
176
|
+
|
|
177
|
+
for hive in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER):
|
|
178
|
+
for subkey in (
|
|
179
|
+
r"SOFTWARE\voidtools\Everything",
|
|
180
|
+
r"SOFTWARE\WOW6432Node\voidtools\Everything",
|
|
181
|
+
):
|
|
182
|
+
try:
|
|
183
|
+
with winreg.OpenKey(hive, subkey) as key:
|
|
184
|
+
install_path, _ = winreg.QueryValueEx(key, "InstallPath")
|
|
185
|
+
candidate = Path(install_path) / "es.exe"
|
|
186
|
+
if candidate.is_file() and _is_everything_es(str(candidate)):
|
|
187
|
+
return str(candidate)
|
|
188
|
+
except (FileNotFoundError, OSError):
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
return ""
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _detect_instance(es_path: str) -> str:
|
|
195
|
+
"""Detect which Everything instance is running (default vs 1.5a)."""
|
|
196
|
+
try:
|
|
197
|
+
result = subprocess.run(
|
|
198
|
+
[es_path, "-get-everything-version"],
|
|
199
|
+
capture_output=True, text=True, timeout=5,
|
|
200
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
201
|
+
)
|
|
202
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
203
|
+
return ""
|
|
204
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
result = subprocess.run(
|
|
209
|
+
[es_path, "-instance", "1.5a", "-get-everything-version"],
|
|
210
|
+
capture_output=True, text=True, timeout=5,
|
|
211
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
212
|
+
)
|
|
213
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
214
|
+
return "1.5a"
|
|
215
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
216
|
+
pass
|
|
217
|
+
|
|
218
|
+
return ""
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _test_connection(es_path: str, instance: str) -> tuple[bool, str]:
|
|
222
|
+
"""Verify Everything is running and responsive."""
|
|
223
|
+
base = [es_path]
|
|
224
|
+
if instance:
|
|
225
|
+
base.extend(["-instance", instance])
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
result = subprocess.run(
|
|
229
|
+
[*base, "-get-everything-version"],
|
|
230
|
+
capture_output=True, text=True, timeout=10,
|
|
231
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
232
|
+
)
|
|
233
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
234
|
+
return True, f"Everything v{result.stdout.strip()}"
|
|
235
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
result = subprocess.run(
|
|
240
|
+
[*base, "-n", "1", "*.txt"],
|
|
241
|
+
capture_output=True, text=True, timeout=10,
|
|
242
|
+
creationflags=_CREATE_NO_WINDOW,
|
|
243
|
+
)
|
|
244
|
+
if result.returncode == 0:
|
|
245
|
+
return True, "Everything connected (version unknown)"
|
|
246
|
+
err = result.stderr.strip() or result.stdout.strip() or "Unknown error"
|
|
247
|
+
return False, err
|
|
248
|
+
except subprocess.TimeoutExpired:
|
|
249
|
+
return False, "Connection timed out"
|
|
250
|
+
except FileNotFoundError:
|
|
251
|
+
return False, f"es.exe not found at {es_path}"
|
|
252
|
+
except OSError as exc:
|
|
253
|
+
return False, str(exc)
|