@pab-iprg/huohuo 1.0.0-preview.7 → 1.0.0-preview.8
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 +3 -0
- package/cli.js +126 -10
- package/package.json +4 -4
- package/release.json +18 -18
package/README.md
CHANGED
|
@@ -31,3 +31,6 @@ npx.cmd --yes --prefer-online @pab-iprg/huohuo@preview
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
默认目录无需手动填写。需要独立试用目录时,CMD 使用 `--home "%USERPROFILE%\.huohuo-windows-trial-01"`,PowerShell 使用 `--home "$env:USERPROFILE\.huohuo-windows-trial-01"`。程序内部使用系统自带 PowerShell 采样,不要求用户用 PowerShell 启动。两种终端的首装、Ctrl+C、再次启动及数据保留均需分别实机验收。
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
平台静态资源缺失、版本不匹配或损坏时,入口会自动补齐该固定版本并核对发行摘要,普通用户无需追加可选依赖、registry或cache参数。恢复只操作火火的受管资源缓存,不执行资源包脚本、不改变npm全局配置,继续原来固定的安装版本。
|
package/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// distribution/bootstrap/entry.ts
|
|
4
|
-
import { open as
|
|
4
|
+
import { open as open4, readFile as readFile9, realpath as realpath5 } from "node:fs/promises";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
import { homedir as homedir2 } from "node:os";
|
|
7
7
|
import { dirname as dirname6, join as join9, resolve as resolve5 } from "node:path";
|
|
@@ -377,7 +377,7 @@ async function transfer(artifact2, path, source, fetcher, onBytes) {
|
|
|
377
377
|
timer.unref();
|
|
378
378
|
};
|
|
379
379
|
const signal = AbortSignal.any([idle.signal, AbortSignal.timeout(30 * 6e4)]);
|
|
380
|
-
keepAlive();
|
|
380
|
+
if (!artifact2.bundled) keepAlive();
|
|
381
381
|
try {
|
|
382
382
|
const response = await requestSource(artifact2, source, fetcher, signal, "GET", keepAlive);
|
|
383
383
|
if (!response.ok || !response.body) {
|
|
@@ -420,7 +420,7 @@ function safePath(root, path) {
|
|
|
420
420
|
if (target !== root && !target.startsWith(root + sep)) throw new Error("\u538B\u7F29\u5305\u8DEF\u5F84\u8D8A\u754C");
|
|
421
421
|
return target;
|
|
422
422
|
}
|
|
423
|
-
async function extractArchive(archive, root, expandedLimit) {
|
|
423
|
+
async function extractArchive(archive, root, expandedLimit, allowedFiles) {
|
|
424
424
|
root = resolve(root);
|
|
425
425
|
await mkdir2(root, { mode: 448 });
|
|
426
426
|
root = await realpath(root);
|
|
@@ -469,6 +469,11 @@ async function extractArchive(archive, root, expandedLimit) {
|
|
|
469
469
|
} else {
|
|
470
470
|
const prefix = string(header.subarray(345, 500));
|
|
471
471
|
const name = pax.path ?? (prefix ? prefix + "/" : "") + string(header.subarray(0, 100));
|
|
472
|
+
if (allowedFiles) {
|
|
473
|
+
const directory = name.replace(/\/+$/, "");
|
|
474
|
+
const allowed = kind === "0" ? allowedFiles.has(name) : kind === "5" && [...allowedFiles].some((path) => path.startsWith(directory + "/"));
|
|
475
|
+
if (!allowed) throw new Error("\u5B89\u88C5\u8D44\u6E90\u538B\u7F29\u5305\u542B\u672A\u5141\u8BB8\u7684\u6587\u4EF6\u6216\u94FE\u63A5");
|
|
476
|
+
}
|
|
472
477
|
const target = safePath(root, name);
|
|
473
478
|
const linkText = pax.linkpath ?? string(header.subarray(157, 257));
|
|
474
479
|
if (Object.keys(pax).some((key) => /sparse|size/i.test(key))) throw new Error("\u4E0D\u652F\u6301\u7A00\u758F\u6216\u6539\u5199\u5927\u5C0F\u7684\u538B\u7F29\u5305");
|
|
@@ -1571,7 +1576,8 @@ async function showStatus(home, watch) {
|
|
|
1571
1576
|
|
|
1572
1577
|
// distribution/bootstrap/assets.ts
|
|
1573
1578
|
import { createRequire } from "node:module";
|
|
1574
|
-
import { readFile as readFile8 } from "node:fs/promises";
|
|
1579
|
+
import { readFile as readFile8, mkdir as mkdir4, mkdtemp, open as open3, rename as rename5, rm as rm5, lstat as lstat3 } from "node:fs/promises";
|
|
1580
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
1575
1581
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
1576
1582
|
import { fileURLToPath } from "node:url";
|
|
1577
1583
|
async function assetsDirectory(release, entryURL = import.meta.url) {
|
|
@@ -1589,18 +1595,127 @@ async function assetsDirectory(release, entryURL = import.meta.url) {
|
|
|
1589
1595
|
}
|
|
1590
1596
|
return join8(dirname5(file), "assets");
|
|
1591
1597
|
}
|
|
1598
|
+
var recovering = /* @__PURE__ */ new Map();
|
|
1599
|
+
async function bundledAssetPath(release, artifact2, home, options = {}) {
|
|
1600
|
+
const localFile = async () => join8(await assetsDirectory(release, options.entryURL), artifact2.sha256 + ".tgz");
|
|
1601
|
+
if (!release.assetPackage) return localFile();
|
|
1602
|
+
const expected = release.assetPackage;
|
|
1603
|
+
if (expected.name !== `@pab-iprg/huohuo-assets-${release.platform.os}-${release.platform.arch}` || !/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(expected.version) || ![release.runtime, release.pythonDependencies].some((a) => a.bundled && a.sha256 === artifact2.sha256)) throw new Error("\u5E73\u53F0\u5B89\u88C5\u8D44\u6E90\u8EAB\u4EFD\u65E0\u6548");
|
|
1604
|
+
try {
|
|
1605
|
+
const file = await localFile();
|
|
1606
|
+
await verifyArtifact(file, artifact2);
|
|
1607
|
+
return file;
|
|
1608
|
+
} catch {
|
|
1609
|
+
}
|
|
1610
|
+
const key = createHash3("sha256").update(JSON.stringify([expected.name, expected.version, release.runtime.sha256, release.pythonDependencies.sha256])).digest("hex");
|
|
1611
|
+
const directory = join8(home, "cache", "platform-assets", key);
|
|
1612
|
+
let pending = recovering.get(directory);
|
|
1613
|
+
if (!pending) {
|
|
1614
|
+
pending = recoverCompanion(directory, release, options);
|
|
1615
|
+
recovering.set(directory, pending);
|
|
1616
|
+
void pending.finally(() => {
|
|
1617
|
+
if (recovering.get(directory) === pending) recovering.delete(directory);
|
|
1618
|
+
}).catch(() => {
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
return join8(await pending, "assets", artifact2.sha256 + ".tgz");
|
|
1622
|
+
}
|
|
1623
|
+
async function validateCompanion(directory, release) {
|
|
1624
|
+
const meta = await lstat3(directory);
|
|
1625
|
+
if (!meta.isDirectory() || meta.isSymbolicLink()) throw new Error("\u5B89\u88C5\u8D44\u6E90\u7F13\u5B58\u8EAB\u4EFD\u65E0\u6548");
|
|
1626
|
+
const file = join8(directory, "package.json");
|
|
1627
|
+
if ((await lstat3(file)).size > 64 * 1024) throw new Error("\u5B89\u88C5\u8D44\u6E90\u6E05\u5355\u8FC7\u5927");
|
|
1628
|
+
const manifest = JSON.parse(await readFile8(file, "utf8"));
|
|
1629
|
+
if (manifest.name !== release.assetPackage.name || manifest.version !== release.assetPackage.version) throw new Error("\u5B89\u88C5\u8D44\u6E90\u8EAB\u4EFD\u6821\u9A8C\u672A\u901A\u8FC7");
|
|
1630
|
+
for (const artifact2 of [release.runtime, release.pythonDependencies]) await verifyArtifact(join8(directory, "assets", artifact2.sha256 + ".tgz"), artifact2);
|
|
1631
|
+
}
|
|
1632
|
+
async function recoverCompanion(directory, release, options) {
|
|
1633
|
+
try {
|
|
1634
|
+
await validateCompanion(directory, release);
|
|
1635
|
+
return directory;
|
|
1636
|
+
} catch {
|
|
1637
|
+
}
|
|
1638
|
+
const { name, version: version2 } = release.assetPackage;
|
|
1639
|
+
const basename = name.split("/")[1];
|
|
1640
|
+
const url = `https://registry.npmjs.org/${name}/-/${basename}-${encodeURIComponent(version2)}.tgz`;
|
|
1641
|
+
const limit = release.runtime.downloadBytes + release.pythonDependencies.downloadBytes + 128 * 1024;
|
|
1642
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) throw new Error("\u5B89\u88C5\u8D44\u6E90\u5927\u5C0F\u65E0\u6548");
|
|
1643
|
+
const parent = dirname5(directory);
|
|
1644
|
+
await mkdir4(parent, { recursive: true, mode: 448 });
|
|
1645
|
+
const stage = await mkdtemp(join8(parent, ".recover-"));
|
|
1646
|
+
try {
|
|
1647
|
+
options.progress?.("\u6B63\u5728\u81EA\u52A8\u8865\u9F50\u5F53\u524D\u8BBE\u5907\u7684\u5B89\u88C5\u8D44\u6E90\u2026");
|
|
1648
|
+
const archive = join8(stage, "companion.tgz");
|
|
1649
|
+
await downloadCompanion(url, archive, limit, options.fetcher ?? fetch, options.signal);
|
|
1650
|
+
const unpacked = join8(stage, "unpacked");
|
|
1651
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
1652
|
+
"package/package.json",
|
|
1653
|
+
"package/README.md",
|
|
1654
|
+
...[release.runtime, release.pythonDependencies].map((a) => "package/assets/" + a.sha256 + ".tgz")
|
|
1655
|
+
]);
|
|
1656
|
+
await extractArchive(archive, unpacked, limit, allowed);
|
|
1657
|
+
const root = join8(unpacked, "package");
|
|
1658
|
+
await validateCompanion(root, release);
|
|
1659
|
+
try {
|
|
1660
|
+
await rename5(directory, directory + ".invalid-" + stage.slice(-6));
|
|
1661
|
+
} catch (error) {
|
|
1662
|
+
if (error.code !== "ENOENT") throw error;
|
|
1663
|
+
}
|
|
1664
|
+
await rename5(root, directory);
|
|
1665
|
+
options.progress?.("\u5B89\u88C5\u8D44\u6E90\u5DF2\u8865\u9F50\u5E76\u6821\u9A8C\uFF0C\u7EE7\u7EED\u5B89\u88C5\u3002");
|
|
1666
|
+
return directory;
|
|
1667
|
+
} catch (error) {
|
|
1668
|
+
throw new Error("\u5B89\u88C5\u8D44\u6E90\u6682\u65F6\u672A\u80FD\u51C6\u5907\u597D\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u65B0\u8FD0\u884C\u540C\u4E00\u6761\u542F\u52A8\u547D\u4EE4\uFF0C\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4\u4F1A\u4FDD\u7559\u3002", { cause: error });
|
|
1669
|
+
} finally {
|
|
1670
|
+
await rm5(stage, { recursive: true, force: true });
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
async function downloadCompanion(url, path, limit, fetcher, signal) {
|
|
1674
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
1675
|
+
const file = await open3(path, "w", 384);
|
|
1676
|
+
const idle = new AbortController();
|
|
1677
|
+
let timer;
|
|
1678
|
+
const touch = () => {
|
|
1679
|
+
clearTimeout(timer);
|
|
1680
|
+
timer = setTimeout(() => idle.abort(), 45e3);
|
|
1681
|
+
timer.unref();
|
|
1682
|
+
};
|
|
1683
|
+
touch();
|
|
1684
|
+
try {
|
|
1685
|
+
const response = await fetcher(url, { redirect: "error", signal: AbortSignal.any([idle.signal, AbortSignal.timeout(30 * 6e4), ...signal ? [signal] : []]) });
|
|
1686
|
+
if (!response.ok || !response.body) {
|
|
1687
|
+
await response.body?.cancel();
|
|
1688
|
+
throw new Error(`\u5B89\u88C5\u8D44\u6E90\u4E0B\u8F7D\u6682\u4E0D\u53EF\u7528\uFF08HTTP ${response.status}\uFF09`);
|
|
1689
|
+
}
|
|
1690
|
+
touch();
|
|
1691
|
+
let size = 0;
|
|
1692
|
+
for await (const chunk of response.body) {
|
|
1693
|
+
touch();
|
|
1694
|
+
size += chunk.byteLength;
|
|
1695
|
+
if (size > limit) throw new Error("\u5B89\u88C5\u8D44\u6E90\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
1696
|
+
await file.writeFile(chunk);
|
|
1697
|
+
}
|
|
1698
|
+
await file.sync();
|
|
1699
|
+
return;
|
|
1700
|
+
} catch (error) {
|
|
1701
|
+
if (attempt === 1 || signal?.aborted) throw error;
|
|
1702
|
+
} finally {
|
|
1703
|
+
clearTimeout(timer);
|
|
1704
|
+
await file.close();
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1592
1708
|
|
|
1593
1709
|
// distribution/bootstrap/entry.ts
|
|
1594
|
-
function artifactSource(source, directory) {
|
|
1710
|
+
function artifactSource(source, directory, home) {
|
|
1595
1711
|
return async (url, options) => {
|
|
1596
1712
|
const bundled = /^https:\/\/bundled\.invalid\/([a-f0-9]{64})\.tgz$/.exec(String(url));
|
|
1597
1713
|
if (!directory && !bundled) return fetch(url, options);
|
|
1598
1714
|
const artifact2 = source && [source.runtime, source.python, source.pythonDependencies].find((item) => item.url === String(url));
|
|
1599
1715
|
const sha256 = bundled?.[1] ?? artifact2?.sha256;
|
|
1600
1716
|
if (!sha256) throw new Error("\u672C\u673A\u4EA7\u7269\u76EE\u5F55\u7F3A\u5C11\u8BE5\u56FA\u5B9A\u53D1\u884C\u8D44\u6E90");
|
|
1601
|
-
const
|
|
1602
|
-
const
|
|
1603
|
-
const file = await open3(path).catch((error) => {
|
|
1717
|
+
const path = !directory && bundled && source && artifact2 && home ? await bundledAssetPath(source, artifact2, home, { entryURL: import.meta.url, signal: options?.signal ?? void 0, progress: (message) => console.log(message) }) : join9(directory ?? await assetsDirectory(source, import.meta.url), sha256 + ".tgz");
|
|
1718
|
+
const file = await open4(path).catch((error) => {
|
|
1604
1719
|
if (error.code === "ENOENT" && bundled) throw new Error("\u7F3A\u5C11\u4E0A\u6B21\u5B89\u88C5\u4F7F\u7528\u7684\u6587\u4EF6\u3002\u8BF7\u7528\u4E0A\u6B21\u5B89\u88C5\u65F6\u7684\u7248\u672C\u7EE7\u7EED\u3002");
|
|
1605
1720
|
throw error;
|
|
1606
1721
|
});
|
|
@@ -1656,7 +1771,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1656
1771
|
const ui = installUI(assumeYes);
|
|
1657
1772
|
if (command === "upgrade") {
|
|
1658
1773
|
const candidate = selectRelease(JSON.parse(await readFile9(releaseFile ?? join9(dirname6(fileURLToPath2(import.meta.url)), "release.json"), "utf8")));
|
|
1659
|
-
await upgrade(home, candidate, { fetcher: artifactSource(candidate, artifactDirectory), progress, ...ui });
|
|
1774
|
+
await upgrade(home, candidate, { fetcher: artifactSource(candidate, artifactDirectory, home), progress, ...ui });
|
|
1660
1775
|
const current = await readInstallation(home);
|
|
1661
1776
|
if (await control(home, current.releaseDigest, noOpen ? "status" : "open")) return;
|
|
1662
1777
|
await run(process.execPath, [join9(installationPaths(home, current.release).runtime, "lib/distribution/managed.js"), "start", home, ...noOpen ? ["--no-open"] : []], home, process.env, () => control(home, current.releaseDigest, "stop"));
|
|
@@ -1716,7 +1831,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1716
1831
|
}
|
|
1717
1832
|
source = selectRelease(catalog);
|
|
1718
1833
|
}
|
|
1719
|
-
const fetcher = artifactSource(source, artifactDirectory);
|
|
1834
|
+
const fetcher = artifactSource(source, artifactDirectory, home);
|
|
1720
1835
|
record = await install(home, source, { fetcher, progress, ...ui });
|
|
1721
1836
|
}
|
|
1722
1837
|
const installedHome = record.home;
|
|
@@ -1729,5 +1844,6 @@ if (process.argv[1] && await realpath5(resolve5(process.argv[1])).catch(() => ""
|
|
|
1729
1844
|
});
|
|
1730
1845
|
}
|
|
1731
1846
|
export {
|
|
1847
|
+
artifactSource,
|
|
1732
1848
|
main
|
|
1733
1849
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pab-iprg/huohuo",
|
|
3
|
-
"version": "1.0.0-preview.
|
|
3
|
+
"version": "1.0.0-preview.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "火火多平台安装入口(实验预览)",
|
|
6
6
|
"bin": {
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"README.md"
|
|
16
16
|
],
|
|
17
17
|
"optionalDependencies": {
|
|
18
|
-
"@pab-iprg/huohuo-assets-darwin-arm64": "1.0.0-preview.
|
|
19
|
-
"@pab-iprg/huohuo-assets-linux-x64": "1.0.0-preview.
|
|
20
|
-
"@pab-iprg/huohuo-assets-win32-x64": "1.0.0-preview.
|
|
18
|
+
"@pab-iprg/huohuo-assets-darwin-arm64": "1.0.0-preview.8",
|
|
19
|
+
"@pab-iprg/huohuo-assets-linux-x64": "1.0.0-preview.8",
|
|
20
|
+
"@pab-iprg/huohuo-assets-win32-x64": "1.0.0-preview.8"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public",
|
package/release.json
CHANGED
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"runtime": {
|
|
19
19
|
"name": "@huohuo/research-agent",
|
|
20
20
|
"version": "1.0.0",
|
|
21
|
-
"url": "https://bundled.invalid/
|
|
21
|
+
"url": "https://bundled.invalid/0a7dabb24c07e97d1bff0a4b10350998e72c5f32f095e13bd3b81322a9ca689e.tgz",
|
|
22
22
|
"bundled": true,
|
|
23
|
-
"sha256": "
|
|
24
|
-
"integrity": "sha512-
|
|
25
|
-
"downloadBytes":
|
|
26
|
-
"expandedBytes":
|
|
23
|
+
"sha256": "0a7dabb24c07e97d1bff0a4b10350998e72c5f32f095e13bd3b81322a9ca689e",
|
|
24
|
+
"integrity": "sha512-pZhVfMCto3Pm3ASdDuFnxfmNV8P8LfT8WHZ3gIkd1R9ygJD0SN55nad0SBMZh/WZdgZUcNv/z76m0tUeykdXIg==",
|
|
25
|
+
"downloadBytes": 2615359,
|
|
26
|
+
"expandedBytes": 8348241
|
|
27
27
|
},
|
|
28
28
|
"python": {
|
|
29
29
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.13.18%2B20261026-aarch64-apple-darwin-install_only_stripped.tar.gz",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
},
|
|
100
100
|
"assetPackage": {
|
|
101
101
|
"name": "@pab-iprg/huohuo-assets-darwin-arm64",
|
|
102
|
-
"version": "1.0.0-preview.
|
|
102
|
+
"version": "1.0.0-preview.8"
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
{
|
|
@@ -118,12 +118,12 @@
|
|
|
118
118
|
"runtime": {
|
|
119
119
|
"name": "@huohuo/research-agent",
|
|
120
120
|
"version": "1.0.0",
|
|
121
|
-
"url": "https://bundled.invalid/
|
|
121
|
+
"url": "https://bundled.invalid/11495b66f6a1c6816978cf9f360c2a473b44332638506f5cb95c9cd0af047775.tgz",
|
|
122
122
|
"bundled": true,
|
|
123
|
-
"sha256": "
|
|
124
|
-
"integrity": "sha512-
|
|
125
|
-
"downloadBytes":
|
|
126
|
-
"expandedBytes":
|
|
123
|
+
"sha256": "11495b66f6a1c6816978cf9f360c2a473b44332638506f5cb95c9cd0af047775",
|
|
124
|
+
"integrity": "sha512-Y7d6X7XBeRmy54ZzWb3iR4dQuh6fkflNIwPf0K60QueXUiCxcARRvzB0HtN1WKbqZGFSjQ4m+v6M0uwuBtQT6w==",
|
|
125
|
+
"downloadBytes": 2615361,
|
|
126
|
+
"expandedBytes": 8348259
|
|
127
127
|
},
|
|
128
128
|
"python": {
|
|
129
129
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.13.18%2B20261026-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
},
|
|
199
199
|
"assetPackage": {
|
|
200
200
|
"name": "@pab-iprg/huohuo-assets-linux-x64",
|
|
201
|
-
"version": "1.0.0-preview.
|
|
201
|
+
"version": "1.0.0-preview.8"
|
|
202
202
|
}
|
|
203
203
|
},
|
|
204
204
|
{
|
|
@@ -216,12 +216,12 @@
|
|
|
216
216
|
"runtime": {
|
|
217
217
|
"name": "@huohuo/research-agent",
|
|
218
218
|
"version": "1.0.0",
|
|
219
|
-
"url": "https://bundled.invalid/
|
|
219
|
+
"url": "https://bundled.invalid/823a7ee2018ab91fbab69b09ef34a2d97f9ce0b88ecf23361a9485b92b31585a.tgz",
|
|
220
220
|
"bundled": true,
|
|
221
|
-
"sha256": "
|
|
222
|
-
"integrity": "sha512-
|
|
223
|
-
"downloadBytes":
|
|
224
|
-
"expandedBytes":
|
|
221
|
+
"sha256": "823a7ee2018ab91fbab69b09ef34a2d97f9ce0b88ecf23361a9485b92b31585a",
|
|
222
|
+
"integrity": "sha512-ywdwTv+V0TRIs6xOL2esvfuYFY9Y2Z2SRS2+Xhwqw4Lw5Y/+JLBiJCguB3pGOwfqHCLkq0ygm1Jg2E7lby1dqw==",
|
|
223
|
+
"downloadBytes": 2615361,
|
|
224
|
+
"expandedBytes": 8348257
|
|
225
225
|
},
|
|
226
226
|
"python": {
|
|
227
227
|
"url": "https://github.com/astral-sh/python-build-standalone/releases/download/20261026/cpython-3.13.18%2B20261026-x86_64-pc-windows-msvc-install_only_stripped.tar.gz",
|
|
@@ -296,7 +296,7 @@
|
|
|
296
296
|
},
|
|
297
297
|
"assetPackage": {
|
|
298
298
|
"name": "@pab-iprg/huohuo-assets-win32-x64",
|
|
299
|
-
"version": "1.0.0-preview.
|
|
299
|
+
"version": "1.0.0-preview.8"
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
]
|