@anionex/dsh-vision-toolkit 0.1.28 → 0.1.29
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 +6 -4
- package/README.zh.md +6 -4
- package/assets/python-bootstrap.json +47 -0
- package/lib/exposure.js +27 -5
- package/lib/exposure.js.map +1 -1
- package/lib/runtime-install.js +291 -5
- package/lib/runtime-install.js.map +1 -1
- package/lib/skill.js +2 -2
- package/lib/skill.js.map +1 -1
- package/lib/types/exposure.d.ts +4 -0
- package/lib/types/exposure.d.ts.map +1 -1
- package/lib/types/runtime-install.d.ts +30 -0
- package/lib/types/runtime-install.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/exposure.ts +28 -6
- package/src/runtime-install.ts +337 -7
- package/src/skill.ts +2 -2
package/README.md
CHANGED
|
@@ -143,7 +143,7 @@ dsh plugin --profile headless add @anionex/dsh-vision-toolkit
|
|
|
143
143
|
|
|
144
144
|
Restart a running Web Profile, then open **Settings → Vision Toolkit**. The free provider is already configured; run **Test vision model** to confirm it is reachable.
|
|
145
145
|
|
|
146
|
-
The first start prepares an isolated runtime,
|
|
146
|
+
The first start prepares an isolated runtime: the plugin prefers a system Python 3.11+; when none is found, it downloads a hash-verified standalone Python (about 35 MB) from a pinned release source on first use. A normal installation does not require an `agent-vision-toolkit` source checkout or a local path setting.
|
|
147
147
|
|
|
148
148
|
### 3. Paste an image and describe the outcome you want
|
|
149
149
|
|
|
@@ -274,15 +274,17 @@ For a trusted internal endpoint that uses a self-signed certificate or MITM prox
|
|
|
274
274
|
|
|
275
275
|
- A DeepSeek Harness Web or Headless Profile.
|
|
276
276
|
- Node.js `^22.19.0` or `>=24.0.0`.
|
|
277
|
-
- Python 3.11
|
|
277
|
+
- Python 3.11+ is usually not needed in advance: the plugin prefers a system Python and otherwise downloads a pinned standalone Python 3.13 automatically, preparing its own isolated environment. Only that first automatic download needs network access.
|
|
278
278
|
- Only `vision_html_screenshot` requires Chrome, Chromium, or Edge.
|
|
279
279
|
- Inputs must be PNG, JPEG, GIF, or WebP files in the session workspace, the platform temporary directory, or an explicitly allowed directory.
|
|
280
280
|
|
|
281
281
|
### Configure the Python runtime
|
|
282
282
|
|
|
283
|
+
By default the plugin picks a system Python 3.11+, or downloads a standalone Python when none is found; most users never need to configure this section. The rest is for advanced setups where automatic discovery fails, a specific interpreter is required, or an external runtime is used.
|
|
284
|
+
|
|
283
285
|
The packaged `managed` runtime creates its own isolated virtual environment. `runtime.python` selects the Python executable used to bootstrap or refresh that environment; it does not replace the managed environment with the interpreter's global site-packages. Set it when automatic discovery fails or when several Python installations exist. The override is also used by `runtime.mode: external`.
|
|
284
286
|
|
|
285
|
-
Python 3.11 or newer is required. Without an override, the plugin tries `python3` then `python` on macOS/Linux, and `python`, `py -3`, then `python3` on Windows. A configured value is passed as one executable name or path, not as a shell command with arguments, so use `py` (not `py -3`) for the Windows launcher; use an absolute path when you need a specific version.
|
|
287
|
+
Python 3.11 or newer is required; the automatically downloaded standalone Python is 3.13.15 and, like a system interpreter, is only used to bootstrap the isolated environment. Without an override, the plugin tries `python3` then `python` on macOS/Linux, and `python`, `py -3`, then `python3` on Windows, before falling back to the standalone download. A configured value is passed as one executable name or path, not as a shell command with arguments, so use `py` (not `py -3`) for the Windows launcher; use an absolute path when you need a specific version.
|
|
286
288
|
|
|
287
289
|
Configure it in the Profile patch:
|
|
288
290
|
|
|
@@ -385,7 +387,7 @@ The updater revalidates the Profile before mutation, snapshots the original mani
|
|
|
385
387
|
| The free service returns 429 | Wait for the `Retry-After` interval, or switch to your own endpoint when you need stable higher volume |
|
|
386
388
|
| The image exceeds a size or pixel limit | Crop or resize it first; the error identifies whether bytes or decoded pixels caused the rejection |
|
|
387
389
|
| A custom Credential is missing | Enter the API key in **Settings → Vision Toolkit** and confirm the Credential name matches the provider configuration |
|
|
388
|
-
| First-time runtime setup fails |
|
|
390
|
+
| First-time runtime setup fails | The standalone-Python download needs network and disk access. Check connectivity or package-cache access, or install Python 3.11+ / configure `runtime.python` in Settings, then retry the model test |
|
|
389
391
|
| Chrome is not found | Install Chrome, Chromium, or Edge. Only HTML screenshot rendering is unavailable; the other tools still work |
|
|
390
392
|
| An artifact cannot be previewed | Use **Open file** or the workspace path in the result. Preview URLs exist only while the Web route is available |
|
|
391
393
|
|
package/README.zh.md
CHANGED
|
@@ -146,7 +146,7 @@ dsh plugin --profile headless add @anionex/dsh-vision-toolkit
|
|
|
146
146
|
|
|
147
147
|
重启正在运行的 Web Profile,打开 **设置 → 视觉工具**。默认免费服务已经配置好;你可以直接运行**测试视觉模型**确认连接。
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
首次启动会自动准备隔离运行环境:插件优先使用系统已有的 Python 3.11+;如果系统没有,会自动从固定发布源下载一个带完整性校验的托管 Python(约 35MB,仅首次需要网络)。普通安装不需要下载 `agent-vision-toolkit` 源码,也不需要设置本地路径。
|
|
150
150
|
|
|
151
151
|
### 3. 粘贴图片,直接说你要做什么
|
|
152
152
|
|
|
@@ -275,15 +275,17 @@ API Key: https://agent-vision.anionex.me(自动填写)
|
|
|
275
275
|
|
|
276
276
|
- DeepSeek Harness Web 或 Headless Profile。
|
|
277
277
|
- Node.js `^22.19.0` 或 `>=24.0.0`。
|
|
278
|
-
- Python 3.11
|
|
278
|
+
- Python 3.11+,通常无需预装:插件优先使用系统 Python;找不到时会自动下载固定版本托管 Python(3.13)并创建隔离环境,仅首次自动下载需要网络。
|
|
279
279
|
- 只有 `vision_html_screenshot` 需要 Chrome、Chromium 或 Edge。
|
|
280
280
|
- 图片需为 PNG、JPEG、GIF 或 WebP,并位于会话工作区、平台临时目录或明确允许的目录中。
|
|
281
281
|
|
|
282
282
|
### 配置 Python 运行时
|
|
283
283
|
|
|
284
|
+
默认情况下插件会自动选择系统 Python 3.11+,找不到时下载托管 Python,普通用户无需配置本节。以下内容供自动发现失败、需要固定版本或使用外部运行时的高级场景参考。
|
|
285
|
+
|
|
284
286
|
打包的 `managed` 运行时会创建自己的隔离虚拟环境。`runtime.python` 指定的是引导或刷新该环境时使用的 Python 解释器,并不会把 managed 运行时替换成系统解释器的全局 site-packages。当自动发现失败或机器上有多个 Python 时,应设置这个选项;`runtime.mode: external` 也使用该覆盖值。
|
|
285
287
|
|
|
286
|
-
要求 Python 3.11
|
|
288
|
+
要求 Python 3.11 或更高版本;自动下载的托管 Python 为 3.13.15,与系统 Python 一样只用于引导隔离环境。不设置覆盖值时,插件在 macOS/Linux 上依次尝试 `python3`、`python`,在 Windows 上依次尝试 `python`、`py -3`、`python3`,全部不可用时会自动下载托管 Python。手动配置的值会作为一个可执行文件名或路径传入,而不是作为带参数的 Shell 命令,因此 Windows 启动器应填写 `py`(不要填写 `py -3`);需要固定版本时,请填写绝对路径。
|
|
287
289
|
|
|
288
290
|
在 Profile patch 中配置:
|
|
289
291
|
|
|
@@ -386,7 +388,7 @@ dsh plugin --profile web remove @anionex/dsh-vision-toolkit
|
|
|
386
388
|
| 免费服务提示 429 | 按错误中的 `Retry-After` 等待后重试;如果需要稳定高额度,切换到自己的视觉端点 |
|
|
387
389
|
| 图片过大或像素超限 | 先裁剪或缩放图片;错误会明确显示是字节还是像素限制 |
|
|
388
390
|
| 自定义 Credential 缺失 | 在 **设置 → 视觉工具** 填写 API Key,并确认 Credential 名称与配置一致 |
|
|
389
|
-
| 首次运行时准备失败 |
|
|
391
|
+
| 首次运行时准备失败 | 自动下载托管 Python 需要网络和磁盘权限;失败时检查网络或包缓存,也可以安装 Python 3.11+ 或在 Settings 中配置 `runtime.python`,然后重新测试 |
|
|
390
392
|
| 找不到 Chrome | 安装 Chrome、Chromium 或 Edge;只有 HTML 截图不可用,其他工具不受影响 |
|
|
391
393
|
| 产物无法预览 | 使用“打开文件”或结果中的工作区路径;预览 URL 只在 Web 路由可用时存在 |
|
|
392
394
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"pythonVersion": "3.13.15",
|
|
4
|
+
"buildTag": "20260814",
|
|
5
|
+
"artifacts": {
|
|
6
|
+
"darwin-arm64": {
|
|
7
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-aarch64-apple-darwin-install_only_stripped.tar.gz",
|
|
8
|
+
"sha256": "6d472fc49a4d95e58214a992c4c92aa73fe2a935837a01a9a36bab0bec6d72f3",
|
|
9
|
+
"size": 25153453
|
|
10
|
+
},
|
|
11
|
+
"darwin-x64": {
|
|
12
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-x86_64-apple-darwin-install_only_stripped.tar.gz",
|
|
13
|
+
"sha256": "bf87354efcd9ae517da606fcda4e3a3f0d73a6f05ca7cba3c6d3c5270074bfc8",
|
|
14
|
+
"size": 24928435
|
|
15
|
+
},
|
|
16
|
+
"linux-x64": {
|
|
17
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz",
|
|
18
|
+
"sha256": "aaca2af2ab4d7b68a712660d1334c0cfd5ec13c0312ccd30c29122d8d0342320",
|
|
19
|
+
"size": 34818695
|
|
20
|
+
},
|
|
21
|
+
"linux-arm64": {
|
|
22
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz",
|
|
23
|
+
"sha256": "985efd78c1c6521b379f7c64c2a25e6a1130f07441d1af8be441aa05260886aa",
|
|
24
|
+
"size": 29229985
|
|
25
|
+
},
|
|
26
|
+
"linux-x64-musl": {
|
|
27
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-x86_64-unknown-linux-musl-install_only_stripped.tar.gz",
|
|
28
|
+
"sha256": "cec161969cbd60f306c366066701a7ab2d40b78718e7d372281cabe5743423e6",
|
|
29
|
+
"size": 27741839
|
|
30
|
+
},
|
|
31
|
+
"linux-arm64-musl": {
|
|
32
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-aarch64-unknown-linux-musl-install_only_stripped.tar.gz",
|
|
33
|
+
"sha256": "6e0de96340a1096cac81c9b95226c410c71cdf81e3d4419c536ccad9b57ae1f7",
|
|
34
|
+
"size": 28018801
|
|
35
|
+
},
|
|
36
|
+
"win32-x64": {
|
|
37
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-x86_64-pc-windows-msvc-install_only_stripped.tar.gz",
|
|
38
|
+
"sha256": "07c977bbe4abad07e3bbc314608633e6c74eab482a7bae81f4361cda970b45e6",
|
|
39
|
+
"size": 21936392
|
|
40
|
+
},
|
|
41
|
+
"win32-arm64": {
|
|
42
|
+
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20260814/cpython-3.13.15+20260814-aarch64-pc-windows-msvc-install_only_stripped.tar.gz",
|
|
43
|
+
"sha256": "f6bf0fa39ad3668dc1996052ec6eff58c54aa126bf203cf3728a47a830af2b5d",
|
|
44
|
+
"size": 20657919
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
package/lib/exposure.js
CHANGED
|
@@ -127,6 +127,10 @@ export class VisionToolExposure {
|
|
|
127
127
|
const listeners = [
|
|
128
128
|
this.ctx.on('agent/created', ({ agent }) => { this.attach(agent); }),
|
|
129
129
|
this.ctx.on('agent/disposed', ({ agent }) => { this.detach(agent); }),
|
|
130
|
+
this.ctx.on('session/event', (session, event) => {
|
|
131
|
+
if (event.type === 'step/end')
|
|
132
|
+
this.applyHideActivationForSession(session);
|
|
133
|
+
}),
|
|
130
134
|
this.ctx.on('tools/result', (exec, result) => {
|
|
131
135
|
if (result.isError === false
|
|
132
136
|
&& exec.name === 'skill'
|
|
@@ -175,24 +179,42 @@ export class VisionToolExposure {
|
|
|
175
179
|
return { activated: false, tools: [...state.toolNames] };
|
|
176
180
|
const definitions = this.createTools();
|
|
177
181
|
const toolDisposers = [];
|
|
178
|
-
let hideActivation;
|
|
179
182
|
try {
|
|
180
183
|
for (const definition of definitions)
|
|
181
184
|
toolDisposers.push(agent.ctx.tools.register(definition));
|
|
182
|
-
|
|
185
|
+
// A Skill call and the bootstrap can be issued in the same model step.
|
|
186
|
+
// Restricting immediately would turn the still-in-flight bootstrap call
|
|
187
|
+
// into an UNKNOWN_TOOL error, so live sessions hide at step/end.
|
|
188
|
+
if (!this.isLiveSession(agent.session))
|
|
189
|
+
this.applyHideActivation(agent);
|
|
183
190
|
}
|
|
184
191
|
catch (error) {
|
|
185
|
-
hideActivation?.();
|
|
186
192
|
for (const dispose of toolDisposers.reverse())
|
|
187
193
|
dispose();
|
|
188
194
|
throw error;
|
|
189
195
|
}
|
|
190
196
|
state.active = true;
|
|
191
|
-
state.hideActivation = hideActivation;
|
|
192
197
|
state.toolDisposers = toolDisposers;
|
|
193
198
|
state.toolNames = definitions.map(definition => definition.name);
|
|
194
199
|
return { activated: true, tools: [...state.toolNames] };
|
|
195
200
|
}
|
|
201
|
+
/** Whether the session is attached to the live SessionStore (production). */
|
|
202
|
+
isLiveSession(session) {
|
|
203
|
+
return this.ctx.sessions.get(session.id) === session;
|
|
204
|
+
}
|
|
205
|
+
applyHideActivationForSession(session) {
|
|
206
|
+
for (const agent of this.ctx.agents.list()) {
|
|
207
|
+
if (agent.session === session && this.states.get(agent)?.active === true) {
|
|
208
|
+
this.applyHideActivation(agent);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
applyHideActivation(agent) {
|
|
213
|
+
const state = this.states.get(agent);
|
|
214
|
+
if (state === undefined || state.liftRestriction !== undefined)
|
|
215
|
+
return;
|
|
216
|
+
state.liftRestriction = agent.ctx.tools.restrict({ deny: [VISION_TOOLKIT_ACTIVATE] });
|
|
217
|
+
}
|
|
196
218
|
detach(agent) {
|
|
197
219
|
const state = this.states.get(agent);
|
|
198
220
|
if (state === undefined)
|
|
@@ -206,7 +228,7 @@ export class VisionToolExposure {
|
|
|
206
228
|
this.states.clear();
|
|
207
229
|
}
|
|
208
230
|
disposeState(state) {
|
|
209
|
-
state.
|
|
231
|
+
state.liftRestriction?.();
|
|
210
232
|
for (const dispose of state.toolDisposers.reverse())
|
|
211
233
|
dispose();
|
|
212
234
|
}
|
package/lib/exposure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exposure.js","sourceRoot":"","sources":["../src/exposure.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"exposure.js","sourceRoot":"","sources":["../src/exposure.ts"],"names":[],"mappings":"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"}
|
package/lib/runtime-install.js
CHANGED
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
* @module dsh-vision-toolkit/runtime-install
|
|
7
7
|
*/
|
|
8
8
|
import { createHash, randomUUID } from 'node:crypto';
|
|
9
|
-
import { lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, utimes, writeFile, } from 'node:fs/promises';
|
|
9
|
+
import { access, chmod, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, utimes, writeFile, } from 'node:fs/promises';
|
|
10
|
+
import { createWriteStream } from 'node:fs';
|
|
10
11
|
import { homedir } from 'node:os';
|
|
11
12
|
import { dirname, join, resolve } from 'node:path';
|
|
13
|
+
import { Transform } from 'node:stream';
|
|
14
|
+
import { pipeline } from 'node:stream/promises';
|
|
12
15
|
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { x as extractTar } from 'tar';
|
|
17
|
+
import { EnvHttpProxyAgent } from 'undici';
|
|
18
|
+
import { request as undiciRequest } from 'undici';
|
|
13
19
|
import { VisionToolkitError } from "./errors.js";
|
|
14
20
|
import { UPSTREAM_COMMIT, UPSTREAM_REPOSITORY, UPSTREAM_VERSION } from "./version.js";
|
|
15
21
|
const PACKAGE_ROOT = dirname(fileURLToPath(new URL('../package.json', import.meta.url)));
|
|
@@ -180,7 +186,271 @@ async function pythonMetadata(ctx, command, cwd) {
|
|
|
180
186
|
return undefined;
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
|
-
|
|
189
|
+
const PYTHON_BOOTSTRAP_MANIFEST_PATH = join(PACKAGE_ROOT, 'assets', 'python-bootstrap.json');
|
|
190
|
+
const PYTHON_DOWNLOAD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
191
|
+
const PYTHON_DOWNLOAD_ATTEMPTS = 3;
|
|
192
|
+
async function readPythonBootstrapManifest() {
|
|
193
|
+
let parsed;
|
|
194
|
+
try {
|
|
195
|
+
parsed = JSON.parse(await readFile(PYTHON_BOOTSTRAP_MANIFEST_PATH, 'utf8'));
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
throw new VisionToolkitError('runtime', `python bootstrap manifest is unreadable: ${PYTHON_BOOTSTRAP_MANIFEST_PATH}`, { cause: error });
|
|
199
|
+
}
|
|
200
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
201
|
+
throw new VisionToolkitError('runtime', 'python bootstrap manifest is not an object');
|
|
202
|
+
}
|
|
203
|
+
const manifest = parsed;
|
|
204
|
+
if (manifest.schemaVersion !== 1
|
|
205
|
+
|| typeof manifest.pythonVersion !== 'string'
|
|
206
|
+
|| !/^3\.\d+\.\d+$/u.test(manifest.pythonVersion)
|
|
207
|
+
|| typeof manifest.buildTag !== 'string'
|
|
208
|
+
|| !/^\d{8}$/u.test(manifest.buildTag)
|
|
209
|
+
|| typeof manifest.artifacts !== 'object'
|
|
210
|
+
|| manifest.artifacts === null) {
|
|
211
|
+
throw new VisionToolkitError('runtime', 'python bootstrap manifest is invalid');
|
|
212
|
+
}
|
|
213
|
+
for (const [target, artifact] of Object.entries(manifest.artifacts)) {
|
|
214
|
+
if (typeof artifact !== 'object'
|
|
215
|
+
|| artifact === null
|
|
216
|
+
|| typeof artifact.url !== 'string'
|
|
217
|
+
|| !artifact.url.startsWith('https://github.com/astral-sh/python-build-standalone/releases/download/')
|
|
218
|
+
|| typeof artifact.sha256 !== 'string'
|
|
219
|
+
|| !/^[a-f0-9]{64}$/u.test(artifact.sha256)
|
|
220
|
+
|| !Number.isInteger(artifact.size)
|
|
221
|
+
|| artifact.size <= 0) {
|
|
222
|
+
throw new VisionToolkitError('runtime', `python bootstrap manifest has an invalid artifact: ${target}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return manifest;
|
|
226
|
+
}
|
|
227
|
+
/** Map Node platform/arch to the pinned artifact name, including musl Linux. */
|
|
228
|
+
export function pythonBootstrapTarget(platform, arch, musl) {
|
|
229
|
+
return platform === 'linux' && musl ? `${platform}-${arch}-musl` : `${platform}-${arch}`;
|
|
230
|
+
}
|
|
231
|
+
async function runningMusl() {
|
|
232
|
+
if (process.platform !== 'linux')
|
|
233
|
+
return false;
|
|
234
|
+
try {
|
|
235
|
+
await access(join('/', 'etc', 'alpine-release'));
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// Fall through to the loader-name probe.
|
|
240
|
+
}
|
|
241
|
+
const loader = process.arch === 'arm64' ? 'aarch64' : 'x86_64';
|
|
242
|
+
try {
|
|
243
|
+
await access(join('/', 'lib', `ld-musl-${loader}.so.1`));
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const DOWNLOAD_HOSTS = new Set([
|
|
251
|
+
'github.com',
|
|
252
|
+
'objects.githubusercontent.com',
|
|
253
|
+
'release-assets.githubusercontent.com',
|
|
254
|
+
]);
|
|
255
|
+
async function defaultDownloadRequest(url, signal) {
|
|
256
|
+
const dispatcher = new EnvHttpProxyAgent();
|
|
257
|
+
let current = url;
|
|
258
|
+
try {
|
|
259
|
+
for (let redirects = 0;; redirects++) {
|
|
260
|
+
const host = new URL(current).hostname;
|
|
261
|
+
if (!DOWNLOAD_HOSTS.has(host))
|
|
262
|
+
throw new Error(`download redirected outside GitHub: ${host}`);
|
|
263
|
+
const response = await undiciRequest(current, {
|
|
264
|
+
dispatcher,
|
|
265
|
+
signal,
|
|
266
|
+
headers: { 'user-agent': 'dsh-vision-toolkit' },
|
|
267
|
+
});
|
|
268
|
+
if (response.statusCode >= 300 && response.statusCode < 400) {
|
|
269
|
+
const location = response.headers.location;
|
|
270
|
+
await response.body.dump().catch(() => { });
|
|
271
|
+
if (typeof location !== 'string' || location.length === 0 || redirects >= 5) {
|
|
272
|
+
throw new Error('download redirected too many times or without a Location header');
|
|
273
|
+
}
|
|
274
|
+
current = new URL(location, current).toString();
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
statusCode: response.statusCode,
|
|
279
|
+
headers: response.headers,
|
|
280
|
+
body: response.body,
|
|
281
|
+
close: () => dispatcher.close().catch(() => { }),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
await dispatcher.close().catch(() => { });
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async function downloadBundledPythonOnce(artifact, destination, requestImpl = defaultDownloadRequest) {
|
|
291
|
+
const signal = AbortSignal.timeout(PYTHON_DOWNLOAD_TIMEOUT_MS);
|
|
292
|
+
let response;
|
|
293
|
+
try {
|
|
294
|
+
response = await requestImpl(artifact.url, signal);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
throw new Error(`download request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
if (response.statusCode !== 200)
|
|
301
|
+
throw new Error(`download returned HTTP ${response.statusCode}`);
|
|
302
|
+
const hash = createHash('sha256');
|
|
303
|
+
let bytes = 0;
|
|
304
|
+
const hasher = new Transform({
|
|
305
|
+
transform(chunk, _encoding, callback) {
|
|
306
|
+
hash.update(chunk);
|
|
307
|
+
bytes += chunk.length;
|
|
308
|
+
callback(null, chunk);
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
await pipeline(response.body, hasher, createWriteStream(destination));
|
|
312
|
+
if (bytes !== artifact.size)
|
|
313
|
+
throw new Error(`size mismatch: expected ${artifact.size}, received ${bytes}`);
|
|
314
|
+
if (hash.digest('hex') !== artifact.sha256)
|
|
315
|
+
throw new Error('sha256 mismatch');
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
await response.close();
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function downloadBundledPython(artifact, destination, requestImpl) {
|
|
322
|
+
let lastError;
|
|
323
|
+
for (let attempt = 0; attempt < PYTHON_DOWNLOAD_ATTEMPTS; attempt++) {
|
|
324
|
+
try {
|
|
325
|
+
await downloadBundledPythonOnce(artifact, destination, requestImpl);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
lastError = error;
|
|
330
|
+
if (attempt + 1 < PYTHON_DOWNLOAD_ATTEMPTS) {
|
|
331
|
+
await new Promise(resolveWait => setTimeout(resolveWait, 500 * 2 ** attempt));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
throw lastError;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Cross-process directory lock with a stale-lock timeout and heartbeat,
|
|
339
|
+
* matching the managed-runtime lock semantics.
|
|
340
|
+
*/
|
|
341
|
+
async function withDirectoryLock(lockPath, fn) {
|
|
342
|
+
const owner = randomUUID();
|
|
343
|
+
let acquired = false;
|
|
344
|
+
await mkdir(dirname(lockPath), { recursive: true });
|
|
345
|
+
try {
|
|
346
|
+
await mkdir(lockPath, { recursive: false });
|
|
347
|
+
acquired = true;
|
|
348
|
+
await writeFile(join(lockPath, 'owner'), `${owner}\n`, { flag: 'wx' });
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
if (acquired) {
|
|
352
|
+
await rm(lockPath, { recursive: true, force: true }).catch(() => { });
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
if (error.code !== 'EEXIST')
|
|
356
|
+
throw error;
|
|
357
|
+
const started = Date.now();
|
|
358
|
+
while (Date.now() - started < PREPARE_TIMEOUT_MS) {
|
|
359
|
+
try {
|
|
360
|
+
const info = await stat(lockPath);
|
|
361
|
+
if (Date.now() - info.mtimeMs > LOCK_STALE_MS) {
|
|
362
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
363
|
+
return withDirectoryLock(lockPath, fn);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
return withDirectoryLock(lockPath, fn);
|
|
368
|
+
}
|
|
369
|
+
await new Promise(resolveWait => setTimeout(resolveWait, 250));
|
|
370
|
+
}
|
|
371
|
+
throw new VisionToolkitError('runtime', 'timed out waiting for another process to prepare the bundled Python');
|
|
372
|
+
}
|
|
373
|
+
const heartbeat = setInterval(() => {
|
|
374
|
+
const now = new Date();
|
|
375
|
+
void utimes(lockPath, now, now).catch(() => { });
|
|
376
|
+
}, LOCK_HEARTBEAT_MS);
|
|
377
|
+
heartbeat.unref();
|
|
378
|
+
try {
|
|
379
|
+
return await fn();
|
|
380
|
+
}
|
|
381
|
+
finally {
|
|
382
|
+
clearInterval(heartbeat);
|
|
383
|
+
try {
|
|
384
|
+
if ((await readFile(join(lockPath, 'owner'), 'utf8')).trim() === owner) {
|
|
385
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
// The lock was already removed or replaced.
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
export async function acquireBundledPython(ctx, stateRoot, cwd, manifestOverride, requestImpl) {
|
|
394
|
+
const manifest = manifestOverride ?? await readPythonBootstrapManifest();
|
|
395
|
+
const target = pythonBootstrapTarget(process.platform, process.arch, await runningMusl());
|
|
396
|
+
const artifact = manifest.artifacts[target];
|
|
397
|
+
if (artifact === undefined) {
|
|
398
|
+
throw new VisionToolkitError('runtime', `no bundled Python ${manifest.pythonVersion} artifact for ${target}; install Python 3.11+ or configure runtime.python`);
|
|
399
|
+
}
|
|
400
|
+
const root = join(stateRoot, 'python-bootstrap', `${manifest.pythonVersion}-${target}`);
|
|
401
|
+
const interpreter = process.platform === 'win32' ? join(root, 'python.exe') : join(root, 'bin', 'python3');
|
|
402
|
+
const command = { program: interpreter, prefix: [], display: interpreter };
|
|
403
|
+
const cached = await pythonMetadata(ctx, command, cwd);
|
|
404
|
+
if (cached !== undefined)
|
|
405
|
+
return { command, version: cached.version };
|
|
406
|
+
await withDirectoryLock(`${root}.lock`, async () => {
|
|
407
|
+
const ready = await pythonMetadata(ctx, command, cwd);
|
|
408
|
+
if (ready !== undefined)
|
|
409
|
+
return;
|
|
410
|
+
const parent = dirname(root);
|
|
411
|
+
await mkdir(parent, { recursive: true });
|
|
412
|
+
await rm(root, { recursive: true, force: true });
|
|
413
|
+
const work = await mkdtemp(join(parent, '.python-bootstrap-'));
|
|
414
|
+
try {
|
|
415
|
+
const archive = join(work, 'python.tar.gz');
|
|
416
|
+
const extractDir = join(work, 'extract');
|
|
417
|
+
await mkdir(extractDir, { recursive: true });
|
|
418
|
+
try {
|
|
419
|
+
await downloadBundledPython(artifact, archive, requestImpl ?? defaultDownloadRequest);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
throw new VisionToolkitError('runtime', `bundled Python ${manifest.pythonVersion} could not be downloaded for ${target} (${error instanceof Error ? error.message : String(error)}); install Python 3.11+ or configure runtime.python`, { cause: error });
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
await extractTar({ file: archive, cwd: extractDir, strip: 1 });
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
throw new VisionToolkitError('runtime', `bundled Python ${manifest.pythonVersion} could not be extracted for ${target}`, { cause: error });
|
|
429
|
+
}
|
|
430
|
+
const extractedInterpreter = process.platform === 'win32'
|
|
431
|
+
? join(extractDir, 'python.exe')
|
|
432
|
+
: join(extractDir, 'bin', 'python3');
|
|
433
|
+
try {
|
|
434
|
+
await access(extractedInterpreter);
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
throw new VisionToolkitError('runtime', `bundled Python ${manifest.pythonVersion} for ${target} is missing its interpreter`, { cause: error });
|
|
438
|
+
}
|
|
439
|
+
if (process.platform !== 'win32')
|
|
440
|
+
await chmod(extractedInterpreter, 0o755);
|
|
441
|
+
await rename(extractDir, root);
|
|
442
|
+
}
|
|
443
|
+
finally {
|
|
444
|
+
await rm(work, { recursive: true, force: true });
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
const metadata = await pythonMetadata(ctx, command, cwd);
|
|
448
|
+
if (metadata === undefined) {
|
|
449
|
+
throw new VisionToolkitError('runtime', 'bundled Python did not start after extraction');
|
|
450
|
+
}
|
|
451
|
+
return { command, version: metadata.version };
|
|
452
|
+
}
|
|
453
|
+
export async function resolveBootstrapPython(ctx, configured, cwd, manifestOverride, requestImpl) {
|
|
184
454
|
const candidates = configured === undefined
|
|
185
455
|
? process.platform === 'win32'
|
|
186
456
|
? [
|
|
@@ -199,9 +469,25 @@ async function resolveBootstrapPython(ctx, configured, cwd) {
|
|
|
199
469
|
return { command, ...metadata };
|
|
200
470
|
}
|
|
201
471
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
472
|
+
if (configured !== undefined) {
|
|
473
|
+
throw new VisionToolkitError('runtime', `vision-toolkit requires Python 3.11 or newer: ${configured}`);
|
|
474
|
+
}
|
|
475
|
+
try {
|
|
476
|
+
const stateRoot = visionToolkitStateRoot();
|
|
477
|
+
await mkdir(stateRoot, { recursive: true });
|
|
478
|
+
const bundled = await acquireBundledPython(ctx, stateRoot, cwd, manifestOverride, requestImpl);
|
|
479
|
+
return {
|
|
480
|
+
command: bundled.command,
|
|
481
|
+
version: bundled.version,
|
|
482
|
+
major: Number.parseInt(bundled.version.split('.')[0] ?? '', 10),
|
|
483
|
+
minor: Number.parseInt(bundled.version.split('.')[1] ?? '', 10),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
if (error instanceof VisionToolkitError)
|
|
488
|
+
throw error;
|
|
489
|
+
throw new VisionToolkitError('runtime', 'vision-toolkit requires Python 3.11 or newer; tried python3, python, and the Windows py launcher, and automatic bundled-Python preparation failed', { cause: error });
|
|
490
|
+
}
|
|
205
491
|
}
|
|
206
492
|
/** Persistent per-DSH-home cache root shared by runtime and Web support files. */
|
|
207
493
|
export function visionToolkitStateRoot() {
|