@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.
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
- reasons.push(`\u6587\u4EF6\u7CFB\u7EDF\u7A7A\u95F4\u4E0D\u8DB3\uFF1A\u53EF\u7528 ${disk.availableBytes} \u5B57\u8282\uFF0C\u9700\u8981 ${disk.requiredBytes} \u5B57\u8282`);
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") throw Object.assign(new Error(result.reasons.join("\uFF1B")), { code: "RESOURCE_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
- if (!directory && !artifact2?.bundled) return fetch(url, options);
1046
- if (!artifact2) throw new Error("\u672C\u673A\u4EA7\u7269\u76EE\u5F55\u7F3A\u5C11\u8BE5\u56FA\u5B9A\u53D1\u884C\u8D44\u6E90");
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
- return new Response(Readable.toWeb(createReadStream2(join6(root, artifact2.sha256 + ".tgz"), { signal: options?.signal ?? void 0 })));
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
- record = await install(home, catalog, { fetcher, progress });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pab-iprg/huohuo",
3
- "version": "1.0.0-preview.1",
3
+ "version": "1.0.0-preview.3",
4
4
  "type": "module",
5
5
  "description": "火火投研伙伴安装入口",
6
6
  "bin": {
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/3357844499b0a3ee1e273eccc4ce7c4afde2d354a9ff4f473720e7875cdbabf7.tgz",
17
- "sha256": "3357844499b0a3ee1e273eccc4ce7c4afde2d354a9ff4f473720e7875cdbabf7",
18
- "integrity": "sha512-Yzy/15UCnJiyFjL5gnGFS5ro0Orkd155EFGs2YTLtY37mo/nxnfkRrLPMsdh4aABEfCS0Dpu6ve+MKqkiyh5qQ==",
19
- "downloadBytes": 2542280,
20
- "expandedBytes": 8237016,
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": {