@pab-iprg/huohuo 1.0.0-preview.1 → 1.0.0-preview.3
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.
|
Binary file
|
package/cli.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// distribution/bootstrap/entry.ts
|
|
4
|
-
import { readFile as readFile7, realpath as realpath5 } from "node:fs/promises";
|
|
5
|
-
import { createReadStream as createReadStream2 } from "node:fs";
|
|
4
|
+
import { open as open3, readFile as readFile7, realpath as realpath5 } from "node:fs/promises";
|
|
6
5
|
import { Readable } from "node:stream";
|
|
7
6
|
import { homedir } from "node:os";
|
|
8
7
|
import { dirname as dirname5, join as join6, resolve as resolve5 } from "node:path";
|
|
@@ -457,10 +456,6 @@ function evaluateResources(sample, policy, costs, phase) {
|
|
|
457
456
|
blocked = true;
|
|
458
457
|
reasons.push("\u7CFB\u7EDF\u5185\u5B58\u538B\u529B\u4E25\u91CD");
|
|
459
458
|
}
|
|
460
|
-
if (sample.pressure === "high" || sample.pressure === "unknown") {
|
|
461
|
-
limited = true;
|
|
462
|
-
reasons.push(sample.pressure === "high" ? "\u7CFB\u7EDF\u5185\u5B58\u538B\u529B\u504F\u9AD8" : "\u538B\u529B\u4FE1\u53F7\u7F3A\u5931\uFF0C\u4FDD\u5B88\u8FD0\u884C");
|
|
463
|
-
}
|
|
464
459
|
const disks = diskBudgets(sample, costs, policy.diskReserveBytes);
|
|
465
460
|
for (const disk of disks) {
|
|
466
461
|
if (disk.availableBytes === null) {
|
|
@@ -468,9 +463,16 @@ function evaluateResources(sample, policy, costs, phase) {
|
|
|
468
463
|
reasons.push(`\u6587\u4EF6\u7CFB\u7EDF\u53EF\u7528\u7A7A\u95F4\u672A\u77E5\uFF1A${disk.device}`);
|
|
469
464
|
} else if (disk.availableBytes < disk.requiredBytes) {
|
|
470
465
|
blocked = true;
|
|
471
|
-
|
|
466
|
+
const available = (disk.availableBytes / 1e9).toFixed(2);
|
|
467
|
+
const required = (disk.requiredBytes / 1e9).toFixed(2);
|
|
468
|
+
const missing = (Math.ceil((disk.requiredBytes - disk.availableBytes) / 1e7) / 100).toFixed(2);
|
|
469
|
+
reasons.push(`\u78C1\u76D8\u7A7A\u95F4\u4E0D\u8DB3\uFF1A\u5269\u4F59 ${available} GB\uFF0C\u9700\u8981 ${required} GB\u3002\u8BF7\u81F3\u5C11\u518D\u817E\u51FA ${missing} GB\u3002`);
|
|
472
470
|
}
|
|
473
471
|
}
|
|
472
|
+
if (sample.pressure === "high" || sample.pressure === "unknown") {
|
|
473
|
+
limited = true;
|
|
474
|
+
reasons.push(sample.pressure === "high" ? "\u5F53\u524D\u5185\u5B58\u6BD4\u8F83\u7D27\u5F20\uFF0C\u53EF\u4EE5\u5148\u5173\u95ED\u6682\u65F6\u4E0D\u7528\u7684\u5E94\u7528\u3002" : "\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u5185\u5B58\u538B\u529B\u3002");
|
|
475
|
+
}
|
|
474
476
|
const status = blocked ? "blocked" : unknown ? "unknown" : limited ? "limited" : "pass";
|
|
475
477
|
return { status, reasons, disks, sample, policy, concurrency: status === "pass" ? Math.min(1, availableParallelism()) : 0 };
|
|
476
478
|
}
|
|
@@ -585,6 +587,32 @@ async function install(home, candidate, hooks = {}, programsOnly = false) {
|
|
|
585
587
|
if (!programsOnly && !record && (await readdir(home)).some((name) => name !== "state")) throw new Error("\u76EE\u5F55\u542B\u65E0\u5B89\u88C5\u8BB0\u5F55\u7684\u65E2\u6709\u5185\u5BB9\uFF1B\u8BF7\u6838\u67E5\u5F52\u5C5E\u6216\u9009\u62E9\u7A7A\u76EE\u5F55");
|
|
586
588
|
if (!programsOnly && !record && (await readdir(join3(home, "state"))).some((name) => name !== "install.lock")) throw new Error("\u76EE\u5F55\u542B\u65E0\u6CD5\u786E\u8BA4\u5F52\u5C5E\u7684\u72B6\u6001\uFF1B\u672A\u91CD\u5EFA\u5B89\u88C5");
|
|
587
589
|
if (programsOnly && (await readInstallation(home))?.status !== "ready") throw new Error("\u5F53\u524D\u5B89\u88C5\u4E0D\u5B8C\u6574\uFF0C\u5148\u4FEE\u590D\u539F\u7248\u672C");
|
|
590
|
+
const bundleDirectory = hooks.bundleDirectory;
|
|
591
|
+
if (!programsOnly && record && bundleDirectory && candidate && ["installing", "blocked", "failed"].includes(record.status) && ["preflight", "download"].includes(record.stage) && Object.keys(record.stages).every((stage2) => stage2 === "preflight" || stage2 === "download")) {
|
|
592
|
+
const hasFile = async (path) => {
|
|
593
|
+
try {
|
|
594
|
+
await access(path);
|
|
595
|
+
return true;
|
|
596
|
+
} catch (error) {
|
|
597
|
+
if (error.code === "ENOENT") return false;
|
|
598
|
+
throw error;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
const bundled = (release2) => [release2.runtime, release2.python, release2.pythonDependencies].filter((artifact2) => artifact2.bundled);
|
|
602
|
+
const oldAssets = bundled(record.release);
|
|
603
|
+
const available = await Promise.all(oldAssets.map(async (artifact2) => {
|
|
604
|
+
const file = artifact2.sha256 + ".tgz";
|
|
605
|
+
return await hasFile(join3(bundleDirectory, file)) || await hasFile(join3(home, "cache", file));
|
|
606
|
+
}));
|
|
607
|
+
if (available.includes(false)) {
|
|
608
|
+
const next = validateRelease(candidate);
|
|
609
|
+
const nextAssets = bundled(next);
|
|
610
|
+
if (next.runtime.bundled && next.version === record.release.version && (await Promise.all(nextAssets.map((artifact2) => hasFile(join3(bundleDirectory, artifact2.sha256 + ".tgz"))))).every(Boolean)) {
|
|
611
|
+
record = void 0;
|
|
612
|
+
hooks.progress?.("resume-current-package");
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
588
616
|
const release = record?.release ?? validateRelease(candidate);
|
|
589
617
|
if (release.platform.os !== process.platform || release.platform.arch !== process.arch || !versionAtLeast(osRelease(), release.platform.minimumOsRelease) || !versionAtLeast(process.versions.node, "24.8.0") || Number(process.versions.node.split(".")[0]) !== release.nodeMajor) {
|
|
590
618
|
throw new Error("\u6B64\u53D1\u884C\u5C1A\u672A\u9A8C\u8BC1\u5F53\u524D OS/CPU/Node \u7EC4\u5408\uFF1B\u672A\u5F00\u59CB\u91CD\u4E0B\u8F7D");
|
|
@@ -656,7 +684,12 @@ async function install(home, candidate, hooks = {}, programsOnly = false) {
|
|
|
656
684
|
}
|
|
657
685
|
const result = evaluateResources(observation, release.budget, costs, "install");
|
|
658
686
|
await atomicJSON(join3(home, "state/resources.json"), result);
|
|
659
|
-
if (result.status === "unknown" || result.status === "blocked")
|
|
687
|
+
if (result.status === "unknown" || result.status === "blocked") {
|
|
688
|
+
const details = result.reasons.map((reason) => `- ${reason}`).join("\n");
|
|
689
|
+
throw Object.assign(new Error(`\u706B\u706B\u6682\u65F6\u65E0\u6CD5\u7EE7\u7EED\u5B89\u88C5\u3002
|
|
690
|
+
${details}
|
|
691
|
+
\u5904\u7406\u540E\uFF0C\u91CD\u65B0\u8FD0\u884C\u521A\u624D\u7684\u5B89\u88C5\u547D\u4EE4\u3002`), { code: "RESOURCE_BLOCKED" });
|
|
692
|
+
}
|
|
660
693
|
};
|
|
661
694
|
const stage = async (name, action) => {
|
|
662
695
|
hooks.progress?.(name);
|
|
@@ -1041,11 +1074,18 @@ async function uninstall(home, hooks = {}) {
|
|
|
1041
1074
|
// distribution/bootstrap/entry.ts
|
|
1042
1075
|
function artifactSource(source, directory) {
|
|
1043
1076
|
return async (url, options) => {
|
|
1077
|
+
const bundled = /^https:\/\/bundled\.invalid\/([a-f0-9]{64})\.tgz$/.exec(String(url));
|
|
1078
|
+
if (!directory && !bundled) return fetch(url, options);
|
|
1044
1079
|
const artifact2 = source && [source.runtime, source.python, source.pythonDependencies].find((item) => item.url === String(url));
|
|
1045
|
-
|
|
1046
|
-
if (!
|
|
1080
|
+
const sha256 = bundled?.[1] ?? artifact2?.sha256;
|
|
1081
|
+
if (!sha256) throw new Error("\u672C\u673A\u4EA7\u7269\u76EE\u5F55\u7F3A\u5C11\u8BE5\u56FA\u5B9A\u53D1\u884C\u8D44\u6E90");
|
|
1047
1082
|
const root = directory ?? join6(dirname5(fileURLToPath(import.meta.url)), "assets");
|
|
1048
|
-
|
|
1083
|
+
const path = join6(root, sha256 + ".tgz");
|
|
1084
|
+
const file = await open3(path).catch((error) => {
|
|
1085
|
+
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");
|
|
1086
|
+
throw error;
|
|
1087
|
+
});
|
|
1088
|
+
return new Response(Readable.toWeb(file.createReadStream({ signal: options?.signal ?? void 0 })));
|
|
1049
1089
|
};
|
|
1050
1090
|
}
|
|
1051
1091
|
async function main(args = process.argv.slice(2)) {
|
|
@@ -1081,7 +1121,8 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1081
1121
|
"install-runtime": "\u51C6\u5907 Python \u8FD0\u884C\u73AF\u5883",
|
|
1082
1122
|
"install-dependencies": "\u5B89\u88C5\u706B\u706B\u4E0E\u56FA\u5B9A\u4F9D\u8D56",
|
|
1083
1123
|
"assemble-profiles": "\u914D\u7F6E\u5BF9\u8BDD\u4E0E\u540E\u53F0\u7814\u7A76",
|
|
1084
|
-
verify: "\u68C0\u67E5\u5B89\u88C5\u7ED3\u679C"
|
|
1124
|
+
verify: "\u68C0\u67E5\u5B89\u88C5\u7ED3\u679C",
|
|
1125
|
+
"resume-current-package": "\u4E0A\u6B21\u5B89\u88C5\u5C1A\u672A\u5199\u5165\u8FD0\u884C\u73AF\u5883\uFF0C\u5C06\u4F7F\u7528\u5F53\u524D\u7248\u672C\u91CD\u65B0\u68C0\u67E5"
|
|
1085
1126
|
};
|
|
1086
1127
|
const progress = (stage) => console.log(`\u706B\u706B\uFF1A${labels[stage] ?? stage}`);
|
|
1087
1128
|
if (command === "upgrade") {
|
|
@@ -1136,7 +1177,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1136
1177
|
}
|
|
1137
1178
|
if (!record || record.status !== "ready") {
|
|
1138
1179
|
let catalog = null;
|
|
1139
|
-
if (!record) {
|
|
1180
|
+
if (!record || ["preflight", "download"].includes(record.stage)) {
|
|
1140
1181
|
try {
|
|
1141
1182
|
catalog = JSON.parse(await readFile7(releaseFile ?? join6(dirname5(fileURLToPath(import.meta.url)), "release.json"), "utf8"));
|
|
1142
1183
|
} catch (e) {
|
|
@@ -1145,7 +1186,8 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1145
1186
|
}
|
|
1146
1187
|
const source = (await readInstallation(home))?.release ?? catalog;
|
|
1147
1188
|
const fetcher = artifactSource(source, artifactDirectory);
|
|
1148
|
-
|
|
1189
|
+
const bundleDirectory = !releaseFile && !artifactDirectory ? join6(dirname5(fileURLToPath(import.meta.url)), "assets") : void 0;
|
|
1190
|
+
record = await install(home, catalog, { fetcher, progress, bundleDirectory });
|
|
1149
1191
|
}
|
|
1150
1192
|
const installedHome = record.home;
|
|
1151
1193
|
await run(process.execPath, [join6(installationPaths(installedHome, record.release).runtime, "lib/distribution/managed.js"), "start", installedHome, ...noOpen ? ["--no-open"] : []], installedHome);
|
package/package.json
CHANGED
package/release.json
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
"runtime": {
|
|
14
14
|
"name": "@huohuo/research-agent",
|
|
15
15
|
"version": "1.0.0",
|
|
16
|
-
"url": "https://bundled.invalid/
|
|
17
|
-
"sha256": "
|
|
18
|
-
"integrity": "sha512-
|
|
19
|
-
"downloadBytes":
|
|
20
|
-
"expandedBytes":
|
|
16
|
+
"url": "https://bundled.invalid/99aad243ba1aa9749053a7c136aa6b8e4d8fe043075cb3dfca7853359cb94a76.tgz",
|
|
17
|
+
"sha256": "99aad243ba1aa9749053a7c136aa6b8e4d8fe043075cb3dfca7853359cb94a76",
|
|
18
|
+
"integrity": "sha512-mXfudYnjEC4Oqwrg6mrOjnu8Q+S5wAxbK/gTSeAyPTzPF5uj9jyqNaWLE+nXe+gc2IazdRRhBii917dFsLUZyA==",
|
|
19
|
+
"downloadBytes": 2543158,
|
|
20
|
+
"expandedBytes": 8239765,
|
|
21
21
|
"bundled": true
|
|
22
22
|
},
|
|
23
23
|
"python": {
|