ictrp-mcp-server 0.1.0
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/CHANGELOG.md +65 -0
- package/LICENSE +37 -0
- package/README.md +208 -0
- package/README_ZH.md +189 -0
- package/dist/cli/setup-cli.d.ts +14 -0
- package/dist/cli/setup-cli.js +230 -0
- package/dist/cli/setup-cli.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +477 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/bootstrap.d.ts +99 -0
- package/dist/runtime/bootstrap.js +350 -0
- package/dist/runtime/bootstrap.js.map +1 -0
- package/dist/runtime/env-probe.d.ts +108 -0
- package/dist/runtime/env-probe.js +479 -0
- package/dist/runtime/env-probe.js.map +1 -0
- package/dist/runtime/sidecar-client.d.ts +50 -0
- package/dist/runtime/sidecar-client.js +120 -0
- package/dist/runtime/sidecar-client.js.map +1 -0
- package/dist/runtime/supervisor.d.ts +47 -0
- package/dist/runtime/supervisor.js +248 -0
- package/dist/runtime/supervisor.js.map +1 -0
- package/package.json +60 -0
- package/sidecar/ictrp_sidecar.py +602 -0
- package/sidecar/vendor/ictrp_mcp/__init__.py +3 -0
- package/sidecar/vendor/ictrp_mcp/cache/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/cache/store.py +313 -0
- package/sidecar/vendor/ictrp_mcp/data/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/data/columns.py +108 -0
- package/sidecar/vendor/ictrp_mcp/data/jsonio.py +213 -0
- package/sidecar/vendor/ictrp_mcp/data/normalize.py +348 -0
- package/sidecar/vendor/ictrp_mcp/data/query.py +307 -0
- package/sidecar/vendor/ictrp_mcp/errors.py +123 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/__init__.py +0 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/export_guard.py +269 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/htmlstate.py +143 -0
- package/sidecar/vendor/ictrp_mcp/ictrp/session.py +245 -0
- package/sidecar/vendor/ictrp_mcp/offline.py +133 -0
- package/sidecar/vendor/ictrp_mcp/provenance.py +182 -0
- package/sidecar/vendor/ictrp_mcp/server.py +368 -0
- package/sidecar/vendor/ictrp_mcp/tools.py +712 -0
- package/sidecar/vendor/pyproject.toml +25 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime self-setup: create the private venv and install the vendored package.
|
|
3
|
+
*
|
|
4
|
+
* This exists because **a packaged desktop application does not run npm's
|
|
5
|
+
* `postinstall`**. A dmg or an exe is a copied directory tree; npm lifecycle
|
|
6
|
+
* scripts ran on the developer's machine, not on the user's. Anything the
|
|
7
|
+
* package needs at runtime must therefore be able to set itself up on first
|
|
8
|
+
* use, at runtime, with visible progress and a definite failure mode.
|
|
9
|
+
*
|
|
10
|
+
* Two rules govern the whole module:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Never roll back a completed step.** Steps are ordered cheapest-first
|
|
13
|
+
* (venv, then dependencies, then anything large). Re-running is meant to
|
|
14
|
+
* resume, so a failure late in the sequence does not throw away work that
|
|
15
|
+
* succeeded earlier.
|
|
16
|
+
*
|
|
17
|
+
* 2. **A step that did not run is not a step that failed.** `skipped` is
|
|
18
|
+
* reported as its own outcome so the operator can tell "already fine" from
|
|
19
|
+
* "we installed it just now" from "we tried and it broke".
|
|
20
|
+
*/
|
|
21
|
+
import { spawn } from "node:child_process";
|
|
22
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { packageRoot, venvDir, venvPython, PROBE_TIMEOUT_MS } from "./env-probe.js";
|
|
25
|
+
/**
|
|
26
|
+
* PyPI mirrors, most-likely-to-work first for the users this ships to.
|
|
27
|
+
*
|
|
28
|
+
* The fallback chain is not a nicety. A mirror can fail in a way that looks
|
|
29
|
+
* exactly like "this package does not exist" -- notably a 403 on a modern pip
|
|
30
|
+
* user-agent surfaces as `from versions: none`, which sends the operator
|
|
31
|
+
* hunting for a typo instead of a mirror problem. Trying the next mirror turns
|
|
32
|
+
* that misdiagnosis into a non-event.
|
|
33
|
+
*/
|
|
34
|
+
export const PYPI_MIRRORS = {
|
|
35
|
+
aliyun: "https://mirrors.aliyun.com/pypi/simple",
|
|
36
|
+
tencent: "https://mirrors.cloud.tencent.com/pypi/simple",
|
|
37
|
+
tsinghua: "https://pypi.tuna.tsinghua.edu.cn/simple",
|
|
38
|
+
official: "https://pypi.org/simple",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Build the mirror order: the preferred mirror first, then everything else
|
|
42
|
+
* except the official index, then the official index last as the backstop.
|
|
43
|
+
*
|
|
44
|
+
* `official` is pinned last on purpose. It is the most correct source and the
|
|
45
|
+
* slowest / most-blocked from the networks this is expected to run on, so it
|
|
46
|
+
* is the fallback rather than the default.
|
|
47
|
+
*/
|
|
48
|
+
export function mirrorChain(preferred) {
|
|
49
|
+
const chain = [];
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
const push = (name, url) => {
|
|
52
|
+
const key = url.replace(/\/+$/, "");
|
|
53
|
+
if (seen.has(key))
|
|
54
|
+
return;
|
|
55
|
+
seen.add(key);
|
|
56
|
+
chain.push({ name, url });
|
|
57
|
+
};
|
|
58
|
+
const pref = preferred ?? process.env.ICTRP_PIP_MIRROR ?? "aliyun";
|
|
59
|
+
if (pref && pref !== "official") {
|
|
60
|
+
// A raw URL is accepted, so an operator can point at an internal mirror.
|
|
61
|
+
if (PYPI_MIRRORS[pref])
|
|
62
|
+
push(pref, PYPI_MIRRORS[pref]);
|
|
63
|
+
else if (/^https?:\/\//.test(pref))
|
|
64
|
+
push(pref, pref);
|
|
65
|
+
}
|
|
66
|
+
for (const [name, url] of Object.entries(PYPI_MIRRORS)) {
|
|
67
|
+
if (name === "official")
|
|
68
|
+
continue;
|
|
69
|
+
push(name, url);
|
|
70
|
+
}
|
|
71
|
+
push("official", PYPI_MIRRORS["official"]);
|
|
72
|
+
return chain;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Run a child process, streaming its output to `onLine`.
|
|
76
|
+
*
|
|
77
|
+
* Exit codes follow the convention the installer relies on:
|
|
78
|
+
* 124 -- the step timed out and was killed
|
|
79
|
+
* 130 -- the run was aborted by the caller
|
|
80
|
+
* 127 -- the executable could not be spawned at all
|
|
81
|
+
*/
|
|
82
|
+
export function execStreaming(cmd, args, opts = {}) {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
let stdout = "";
|
|
85
|
+
let stderr = "";
|
|
86
|
+
let settled = false;
|
|
87
|
+
let timedOut = false;
|
|
88
|
+
const child = spawn(cmd, args, {
|
|
89
|
+
cwd: opts.cwd ?? packageRoot(),
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
env: {
|
|
92
|
+
...process.env,
|
|
93
|
+
PYTHONUNBUFFERED: "1",
|
|
94
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1",
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const timer = opts.timeoutMs
|
|
98
|
+
? setTimeout(() => {
|
|
99
|
+
timedOut = true;
|
|
100
|
+
child.kill("SIGKILL");
|
|
101
|
+
}, opts.timeoutMs)
|
|
102
|
+
: undefined;
|
|
103
|
+
const onAbort = () => child.kill("SIGKILL");
|
|
104
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
105
|
+
const finish = (code, extra = "") => {
|
|
106
|
+
if (settled)
|
|
107
|
+
return;
|
|
108
|
+
settled = true;
|
|
109
|
+
if (timer)
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
112
|
+
resolve({ code, stdout, stderr: stderr + extra });
|
|
113
|
+
};
|
|
114
|
+
const feed = (chunk, into) => {
|
|
115
|
+
const text = chunk.toString("utf8");
|
|
116
|
+
if (into === "out")
|
|
117
|
+
stdout += text;
|
|
118
|
+
else
|
|
119
|
+
stderr += text;
|
|
120
|
+
if (opts.onLine) {
|
|
121
|
+
// pip redraws its progress bar with carriage returns, so lines must be
|
|
122
|
+
// split on both.
|
|
123
|
+
for (const line of text.split(/[\r\n]+/)) {
|
|
124
|
+
const trimmed = line.trim();
|
|
125
|
+
if (trimmed)
|
|
126
|
+
opts.onLine(trimmed);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
child.stdout?.on("data", (c) => feed(c, "out"));
|
|
131
|
+
child.stderr?.on("data", (c) => feed(c, "err"));
|
|
132
|
+
child.on("error", (err) => {
|
|
133
|
+
stderr += `${err.message}\n`;
|
|
134
|
+
finish(127);
|
|
135
|
+
});
|
|
136
|
+
child.on("close", (code) => {
|
|
137
|
+
if (settled)
|
|
138
|
+
return;
|
|
139
|
+
if (timedOut)
|
|
140
|
+
return finish(124);
|
|
141
|
+
if (opts.signal?.aborted)
|
|
142
|
+
return finish(130);
|
|
143
|
+
finish(code ?? 0);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/** Find a usable system Python, newest acceptable version first. */
|
|
148
|
+
export async function discoverPython() {
|
|
149
|
+
const candidates = process.platform === "win32"
|
|
150
|
+
? ["py", "python3", "python"]
|
|
151
|
+
: ["python3.13", "python3.12", "python3.11", "python3.10", "python3"];
|
|
152
|
+
for (const cmd of candidates) {
|
|
153
|
+
const args = cmd === "py" ? ["-3", "--version"] : ["--version"];
|
|
154
|
+
const res = await execStreaming(cmd, args, { timeoutMs: 10_000 });
|
|
155
|
+
if (res.code !== 0)
|
|
156
|
+
continue;
|
|
157
|
+
const text = `${res.stdout}${res.stderr}`.trim();
|
|
158
|
+
const match = /(\d+)\.(\d+)/.exec(text);
|
|
159
|
+
if (!match)
|
|
160
|
+
continue;
|
|
161
|
+
const major = Number(match[1]);
|
|
162
|
+
const minor = Number(match[2]);
|
|
163
|
+
if (major > 3 || (major === 3 && minor >= 10)) {
|
|
164
|
+
return { cmd, version: `${major}.${minor}` };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create the private virtual environment.
|
|
171
|
+
*
|
|
172
|
+
* The venv lives beside the package by default but is relocatable via
|
|
173
|
+
* `ICTRP_VENV`, which matters when the package directory is read-only (an
|
|
174
|
+
* asar archive) or shared between users.
|
|
175
|
+
*/
|
|
176
|
+
async function ensureVenv(onProgress) {
|
|
177
|
+
const step = "venv";
|
|
178
|
+
const dir = venvDir();
|
|
179
|
+
const python = venvPython();
|
|
180
|
+
if (existsSync(python)) {
|
|
181
|
+
const res = await execStreaming(python, ["--version"], { timeoutMs: PROBE_TIMEOUT_MS });
|
|
182
|
+
if (res.code === 0) {
|
|
183
|
+
return {
|
|
184
|
+
step,
|
|
185
|
+
outcome: "skipped",
|
|
186
|
+
message: `venv already usable (${`${res.stdout}${res.stderr}`.trim()})`,
|
|
187
|
+
attempts: 0,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// A venv that will not run is worse than none: it will shadow a good
|
|
191
|
+
// interpreter and produce confusing errors. Remove and rebuild.
|
|
192
|
+
onProgress({ step, message: "现有的虚拟环境无法运行,正在重建" });
|
|
193
|
+
}
|
|
194
|
+
const found = await discoverPython();
|
|
195
|
+
if (!found) {
|
|
196
|
+
return {
|
|
197
|
+
step,
|
|
198
|
+
outcome: "failed",
|
|
199
|
+
message: "no Python 3.10+ interpreter found on PATH",
|
|
200
|
+
attempts: 0,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
onProgress({ step, message: `使用 ${found.cmd} (python ${found.version}) 创建虚拟环境` });
|
|
204
|
+
mkdirSync(path.dirname(dir), { recursive: true });
|
|
205
|
+
const args = ["-m", "venv", dir];
|
|
206
|
+
const res = await execStreaming(found.cmd, args, {
|
|
207
|
+
timeoutMs: 5 * 60 * 1000,
|
|
208
|
+
onLine: (line) => onProgress({ step, message: line }),
|
|
209
|
+
});
|
|
210
|
+
if (res.code === 0 && existsSync(python)) {
|
|
211
|
+
return { step, outcome: "ok", message: `created ${dir}`, attempts: 1 };
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
step,
|
|
215
|
+
outcome: "failed",
|
|
216
|
+
message: `venv creation failed (exit ${res.code}): ${res.stderr.trim().slice(-400)}`,
|
|
217
|
+
attempts: 1,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Install the vendored package into the venv, trying each mirror in turn.
|
|
222
|
+
*
|
|
223
|
+
* The package is installed from the repository root (`.[offline]` style extras
|
|
224
|
+
* are not needed -- the runtime deps are the base install). When the source
|
|
225
|
+
* tree is not present, the pinned PyPI distribution is used instead.
|
|
226
|
+
*/
|
|
227
|
+
async function installDeps(preferred, onProgress) {
|
|
228
|
+
const step = "deps";
|
|
229
|
+
const python = venvPython();
|
|
230
|
+
const chain = mirrorChain(preferred);
|
|
231
|
+
const triedMirrors = [];
|
|
232
|
+
// Idempotence check first: if everything imports, do not touch the network.
|
|
233
|
+
const probe = "import importlib.util as u;" +
|
|
234
|
+
"print(all(u.find_spec(m) is not None for m in ['mcp','httpx','pydantic']))";
|
|
235
|
+
const check = await execStreaming(python, ["-c", probe], { timeoutMs: PROBE_TIMEOUT_MS });
|
|
236
|
+
if (check.code === 0 && check.stdout.trim() === "True") {
|
|
237
|
+
return { step, outcome: "skipped", message: "dependencies already installed", attempts: 0 };
|
|
238
|
+
}
|
|
239
|
+
// Where does the Python source live?
|
|
240
|
+
//
|
|
241
|
+
// Three layouts, in the order they should be preferred:
|
|
242
|
+
//
|
|
243
|
+
// 1. a checkout -- the npm package sits *inside* the Python project, so
|
|
244
|
+
// the package root has no pyproject.toml while its parent does;
|
|
245
|
+
// 2. a published npm install -- `sidecar/vendor/ictrp_mcp` carries the
|
|
246
|
+
// source, so the dependency is installed from the tarball itself. This
|
|
247
|
+
// is what makes the package self-contained: it does not matter whether
|
|
248
|
+
// a matching release exists on PyPI, and the Python that runs is
|
|
249
|
+
// always the same commit as the JavaScript around it.
|
|
250
|
+
// 3. nothing local -- fall back to the PyPI distribution.
|
|
251
|
+
//
|
|
252
|
+
// The ordering matters. Trying PyPI before the vendored copy would make a
|
|
253
|
+
// published install depend on a release that may not exist yet, which
|
|
254
|
+
// surfaces as the thoroughly unhelpful "from versions: none".
|
|
255
|
+
//
|
|
256
|
+
// Note this searches the *code* location, not ICTRP_HOME. Looking for Python
|
|
257
|
+
// source under a desktop host's private data directory could only ever turn
|
|
258
|
+
// up someone else's file.
|
|
259
|
+
const root = packageRoot();
|
|
260
|
+
const vendored = path.join(root, "sidecar", "vendor");
|
|
261
|
+
const localSource = [root, path.resolve(root, "..")].find((dir) => existsSync(path.join(dir, "pyproject.toml")));
|
|
262
|
+
let target;
|
|
263
|
+
let targetLabel;
|
|
264
|
+
if (localSource) {
|
|
265
|
+
target = localSource;
|
|
266
|
+
targetLabel = "本地源码";
|
|
267
|
+
}
|
|
268
|
+
else if (existsSync(path.join(vendored, "ictrp_mcp"))) {
|
|
269
|
+
target = vendored;
|
|
270
|
+
targetLabel = "包内 vendor";
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
target = "ictrp-mcp-service";
|
|
274
|
+
targetLabel = "PyPI";
|
|
275
|
+
}
|
|
276
|
+
onProgress({ step, message: `安装来源:${targetLabel}` });
|
|
277
|
+
// Upgrade pip first, but never let it block the install: an old pip that can
|
|
278
|
+
// still resolve packages is fine, and a mirror that cannot serve pip is not
|
|
279
|
+
// a reason to give up on the package itself.
|
|
280
|
+
onProgress({ step, message: `升级 pip(${chain[0].name})` });
|
|
281
|
+
await execStreaming(python, ["-m", "pip", "install", "--upgrade", "pip", "-i", chain[0].url], {
|
|
282
|
+
timeoutMs: 5 * 60 * 1000,
|
|
283
|
+
});
|
|
284
|
+
for (const mirror of chain) {
|
|
285
|
+
triedMirrors.push(mirror.name);
|
|
286
|
+
onProgress({ step, message: `安装依赖(${mirror.name})`, percent: undefined });
|
|
287
|
+
const args = ["-m", "pip", "install", "-i", mirror.url, target];
|
|
288
|
+
const res = await execStreaming(python, args, {
|
|
289
|
+
timeoutMs: 30 * 60 * 1000,
|
|
290
|
+
onLine: (line) => {
|
|
291
|
+
const pct = /(\d{1,3})%/.exec(line);
|
|
292
|
+
onProgress({
|
|
293
|
+
step,
|
|
294
|
+
message: line,
|
|
295
|
+
percent: pct ? Number(pct[1]) : undefined,
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
if (res.code === 0) {
|
|
300
|
+
const fellBack = triedMirrors.length > 1;
|
|
301
|
+
return {
|
|
302
|
+
step,
|
|
303
|
+
outcome: "ok",
|
|
304
|
+
message: fellBack
|
|
305
|
+
? `前 ${triedMirrors.length - 1} 个镜像失败后回退成功:${mirror.name}`
|
|
306
|
+
: `installed via ${mirror.name}`,
|
|
307
|
+
attempts: triedMirrors.length,
|
|
308
|
+
triedMirrors,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
onProgress({ step, message: `镜像 ${mirror.name} 失败(exit ${res.code}),尝试下一个` });
|
|
312
|
+
}
|
|
313
|
+
return {
|
|
314
|
+
step,
|
|
315
|
+
outcome: "failed",
|
|
316
|
+
message: `all ${chain.length} mirrors failed`,
|
|
317
|
+
attempts: triedMirrors.length,
|
|
318
|
+
triedMirrors,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Bring the environment to a usable state.
|
|
323
|
+
*
|
|
324
|
+
* Returns rather than throws: the caller (`setup` CLI, or the MCP layer's
|
|
325
|
+
* lazy bootstrap) needs the step list to report *what* went wrong.
|
|
326
|
+
*/
|
|
327
|
+
export async function bootstrapEnvironment(opts = {}) {
|
|
328
|
+
const onProgress = opts.onProgress ?? (() => { });
|
|
329
|
+
const steps = [];
|
|
330
|
+
const errors = [];
|
|
331
|
+
const venv = await ensureVenv(onProgress);
|
|
332
|
+
steps.push(venv);
|
|
333
|
+
if (venv.outcome === "failed") {
|
|
334
|
+
errors.push(`虚拟环境创建失败:${venv.message}`);
|
|
335
|
+
// Everything downstream needs the venv; stopping here is honest.
|
|
336
|
+
return { ok: false, steps, errors };
|
|
337
|
+
}
|
|
338
|
+
if (opts.signal?.aborted) {
|
|
339
|
+
errors.push("已取消");
|
|
340
|
+
return { ok: false, steps, errors };
|
|
341
|
+
}
|
|
342
|
+
const deps = await installDeps(opts.mirror, onProgress);
|
|
343
|
+
steps.push(deps);
|
|
344
|
+
if (deps.outcome === "failed") {
|
|
345
|
+
errors.push(`依赖安装失败:${deps.message}`);
|
|
346
|
+
return { ok: false, steps, errors };
|
|
347
|
+
}
|
|
348
|
+
return { ok: true, steps, errors };
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/runtime/bootstrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only environment inspection.
|
|
3
|
+
*
|
|
4
|
+
* This module never writes to disk and never starts a process that can modify
|
|
5
|
+
* state. It answers one question -- "could this package do its job right now?"
|
|
6
|
+
* -- and it answers it without side effects, because it is called by installers,
|
|
7
|
+
* by `doctor`, and by an MCP tool that a language model may invoke at any time.
|
|
8
|
+
*
|
|
9
|
+
* Three separate readiness notions exist here and they are deliberately not the
|
|
10
|
+
* same thing:
|
|
11
|
+
*
|
|
12
|
+
* - `canRunOnline` -- a venv with the vendored package installed exists, so
|
|
13
|
+
* a live ICTRP search is possible.
|
|
14
|
+
* - `canRunOffline` -- a bundled snapshot is present, so *something* can be
|
|
15
|
+
* answered with no network and no Python at all... almost.
|
|
16
|
+
* In practice the offline path also goes through Python,
|
|
17
|
+
* so this is reported for operator information.
|
|
18
|
+
* - `ready` -- what a client should check before enabling the server.
|
|
19
|
+
*
|
|
20
|
+
* Collapsing them into one boolean would make `doctor` unable to say *why* an
|
|
21
|
+
* installation is not usable, which is the only reason it exists.
|
|
22
|
+
*/
|
|
23
|
+
/** Minimum Python the vendored package supports. Mirrors pyproject.toml. */
|
|
24
|
+
export declare const MIN_PYTHON: readonly [number, number];
|
|
25
|
+
/**
|
|
26
|
+
* Keep this list in sync with the `dependencies` in the Python package's
|
|
27
|
+
* pyproject.toml. A module missing here is a module the sidecar will fail to
|
|
28
|
+
* import at runtime, with a much worse error message.
|
|
29
|
+
*/
|
|
30
|
+
export declare const PYTHON_MODULES: readonly string[];
|
|
31
|
+
/** Per-command timeout for the helper process spawns below. */
|
|
32
|
+
export declare const PROBE_TIMEOUT_MS = 8000;
|
|
33
|
+
/** How long a computed report stays fresh before it is recomputed. */
|
|
34
|
+
export declare const PROBE_TTL_MS = 30000;
|
|
35
|
+
export type CheckStatus = "ok" | "missing" | "outdated" | "error" | "unknown";
|
|
36
|
+
export interface CheckResult {
|
|
37
|
+
status: CheckStatus;
|
|
38
|
+
detail: string;
|
|
39
|
+
hint?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface EnvCheck {
|
|
42
|
+
status: CheckStatus;
|
|
43
|
+
detail: string;
|
|
44
|
+
hint?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface EnvReport {
|
|
47
|
+
root: string;
|
|
48
|
+
platform: string;
|
|
49
|
+
node: EnvCheck;
|
|
50
|
+
venv: EnvCheck;
|
|
51
|
+
pythonVersion: EnvCheck;
|
|
52
|
+
pythonDeps: EnvCheck;
|
|
53
|
+
sidecarScript: EnvCheck;
|
|
54
|
+
sidecar: EnvCheck;
|
|
55
|
+
/** True when a private venv with the vendored package is usable. */
|
|
56
|
+
canRunOnline: boolean;
|
|
57
|
+
/** True when the sidecar process is answering right now. */
|
|
58
|
+
sidecarRunning: boolean;
|
|
59
|
+
ready: boolean;
|
|
60
|
+
summary: string;
|
|
61
|
+
actions: string[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Where the *code* lives: the installed package directory, containing
|
|
65
|
+
* `sidecar/` and `package.json`.
|
|
66
|
+
*
|
|
67
|
+
* This is deliberately NOT affected by `ICTRP_HOME`. Code location and
|
|
68
|
+
* writable-state location are different questions, and conflating them breaks
|
|
69
|
+
* the packaged case: an Electron host sets `ICTRP_HOME` to its private data
|
|
70
|
+
* directory, and if that also redirected this lookup the sidecar script would
|
|
71
|
+
* be searched for inside an empty data directory. It would not be found, and
|
|
72
|
+
* the failure would present as "the package is incomplete" -- pointing at the
|
|
73
|
+
* wrong problem entirely.
|
|
74
|
+
*/
|
|
75
|
+
export declare function packageRoot(): string;
|
|
76
|
+
/**
|
|
77
|
+
* Where writable state goes: virtualenv, snapshots, scratch files.
|
|
78
|
+
*
|
|
79
|
+
* Overridable with `ICTRP_HOME`, which the desktop integration sets to the
|
|
80
|
+
* application's private data directory so that a read-only package directory
|
|
81
|
+
* (an asar archive, a system-path global install) is never written to.
|
|
82
|
+
* Defaults to the package root, which is correct for a normal npm install.
|
|
83
|
+
*/
|
|
84
|
+
export declare function stateRoot(): string;
|
|
85
|
+
/**
|
|
86
|
+
* @deprecated Use {@link packageRoot} for code or {@link stateRoot} for
|
|
87
|
+
* writable state. Kept because it is re-exported from the package entry point;
|
|
88
|
+
* it resolves to the code location, which is the answer most callers wanted.
|
|
89
|
+
*/
|
|
90
|
+
export declare function projectRoot(): string;
|
|
91
|
+
export declare function venvDir(): string;
|
|
92
|
+
export declare function venvPython(): string;
|
|
93
|
+
export declare function sidecarScript(): string;
|
|
94
|
+
/** Where the Node layer caches materialized sets between sidecar restarts. */
|
|
95
|
+
export declare function nodeCacheDir(): string;
|
|
96
|
+
export declare function sidecarBaseUrl(): string;
|
|
97
|
+
export declare function invalidateEnvReport(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Build the environment report.
|
|
100
|
+
*
|
|
101
|
+
* Concurrent calls share one in-flight probe: an installer that fires several
|
|
102
|
+
* checks at once, or a client that renders several status rows, must not spawn
|
|
103
|
+
* a dozen Python processes.
|
|
104
|
+
*/
|
|
105
|
+
export declare function getEnvReport(force?: boolean): Promise<EnvReport>;
|
|
106
|
+
export declare function formatEnvReport(report: EnvReport): string;
|
|
107
|
+
/** True when a path exists and is writable, used by the installer. */
|
|
108
|
+
export declare function isWritable(dir: string): boolean;
|