@follenfang/fupload 0.0.7 → 0.0.9

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 CHANGED
@@ -42,7 +42,7 @@ fupload/
42
42
  - 网易 DD:Windows、Python 3、已安装并登录官方客户端
43
43
  - Heybox Workshop:Windows、Python 3、已安装并登录 Heybox 桌面客户端
44
44
 
45
- npm 安装和 `fupload update` 会在用户状态目录中创建 Fuploader 专用 Python venv,并自动安装 Heybox ZIP 上传所需的腾讯官方 COS SDK;不会修改系统 Python。使用 `npm --ignore-scripts` 安装时,首次运行实际 CLI 命令会校验并补齐该 runtime。
45
+ npm 安装和 `fupload update` 会在用户状态目录中创建 Fuploader 专用 Python venv,优先使用可用的 `uv` 向其中安装固定版本依赖,并自动安装 Heybox ZIP 上传所需的腾讯官方 COS SDK;未安装 `uv` 时回退到 venv 自带的 pip,不会修改系统 Python。使用 `npm --ignore-scripts` 安装时,首次运行实际 CLI 命令会校验并补齐该 runtime。
46
46
 
47
47
  官方 `ncc` 的安装命令为 `npm i -g @newbeebox/newbeebox-creator-center-cli@latest`。Fuploader 不读取其凭据文件;用户在自己的终端完成 `ncc login`,Agent 仅用 `ncc whoami -o json` 验证。自动化可在启动 Agent 前注入 `NCC_TOKEN`,令牌不得写入命令参数、项目文件或 Git。
48
48
 
package/fupload/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
  name: fupload
3
3
  description: Explicit author-publishing workflow for World of Warcraft plugins, configuration shares, and WA/strings on NewBeeBox, NetEase DD, CurseForge, and Heybox Workshop, including CurseForge author project lookup, plugin ZIP upload, and Heybox web-session version management. Use only when the user explicitly invokes `$fupload`, explicitly asks to use the Fupload Skill, or loads this Skill by path. Do not trigger from ordinary mentions of publishing, NewBeeBox, DD, CurseForge, Heybox, plugins, configurations, or WA.
4
4
  metadata:
5
- version: "0.0.7"
5
+ version: "0.0.9"
6
6
  ---
7
7
 
8
8
  # Fupload
@@ -1,3 +1,3 @@
1
1
  """Fupload Python CLI."""
2
2
 
3
- __version__ = "0.0.7"
3
+ __version__ = "0.0.9"
@@ -76,7 +76,9 @@ async function main() {
76
76
  return 1;
77
77
  }
78
78
  const script = path.join(target, "scripts", "fupload.py");
79
- const result = runPython(runtime.python, script, options.forwarded);
79
+ const result = runPython(runtime.python, script, options.forwarded, {
80
+ runtimeRoot: runtime.root,
81
+ });
80
82
  if (result.error) {
81
83
  emitError("PYTHON_LAUNCH_FAILED", result.error.message);
82
84
  return 1;
@@ -6,7 +6,7 @@ import path from "node:path";
6
6
 
7
7
  import { productStateRoot } from "./managed-install.mjs";
8
8
 
9
- export const PYTHON_RUNTIME_SCHEMA = "fupload.python-runtime.v1";
9
+ export const PYTHON_RUNTIME_SCHEMA = "fupload.python-runtime.v2";
10
10
  const RUNTIME_DIRECTORY = "python";
11
11
  const RUNTIME_MARKER = "runtime.json";
12
12
  const RUNTIME_LOCK_WAIT_MS = 5 * 60 * 1000;
@@ -45,10 +45,30 @@ export function discoverPython({ platform = process.platform, minimumMinor = 9 }
45
45
  return null;
46
46
  }
47
47
 
48
+ export function discoverUv({ run = spawnSync } = {}) {
49
+ const result = run("uv", ["--version"], {
50
+ encoding: "utf8",
51
+ shell: false,
52
+ windowsHide: true,
53
+ });
54
+ if (result.error || result.status !== 0) {
55
+ return null;
56
+ }
57
+ const match = result.stdout.trim().match(/^uv (\d+)\.(\d+)\.(\d+)(?:\s|$)/);
58
+ if (!match) {
59
+ return null;
60
+ }
61
+ return { command: "uv", args: [], version: match.slice(1).map(Number) };
62
+ }
63
+
48
64
  export function runPython(python, script, args, options = {}) {
49
- return spawnSync(python.command, [...python.args, script, ...args], {
65
+ const run = options.run || spawnSync;
66
+ const env = options.runtimeRoot
67
+ ? runtimeEnvironment(options.runtimeRoot, options.env || process.env)
68
+ : options.env || process.env;
69
+ return run(python.command, [...python.args, script, ...args], {
50
70
  cwd: options.cwd || process.cwd(),
51
- env: options.env || process.env,
71
+ env,
52
72
  stdio: options.stdio || "inherit",
53
73
  encoding: options.encoding,
54
74
  shell: false,
@@ -125,7 +145,10 @@ function probeRuntime(executable, root, env, run = spawnSync) {
125
145
 
126
146
  function inspectRuntime({ root, platform, requirementsHash, env, run }) {
127
147
  const marker = readMarker(root);
128
- if (marker?.schema !== PYTHON_RUNTIME_SCHEMA || marker.requirements_sha256 !== requirementsHash) {
148
+ if (
149
+ marker?.schema !== PYTHON_RUNTIME_SCHEMA ||
150
+ marker.requirements_sha256 !== requirementsHash
151
+ ) {
129
152
  return null;
130
153
  }
131
154
  const command = pythonRuntimeExecutable(root, platform);
@@ -206,6 +229,7 @@ export function ensurePythonRuntime({
206
229
  home = os.homedir(),
207
230
  run = spawnSync,
208
231
  discover = discoverPython,
232
+ discoverUv: locateUv = discoverUv,
209
233
  } = {}) {
210
234
  const requirements = pythonRequirementsFile(packageRoot);
211
235
  const content = fs.readFileSync(requirements);
@@ -214,7 +238,15 @@ export function ensurePythonRuntime({
214
238
  const parent = path.dirname(root);
215
239
  const lock = acquireRuntimeLock(root);
216
240
  try {
217
- const current = inspectRuntime({ root, platform, requirementsHash, env, run });
241
+ const uv = locateUv({ run });
242
+ const dependencyInstaller = uv ? "uv" : "pip";
243
+ const current = inspectRuntime({
244
+ root,
245
+ platform,
246
+ requirementsHash,
247
+ env,
248
+ run,
249
+ });
218
250
  if (current) {
219
251
  return { status: "current", root, requirements, python: current };
220
252
  }
@@ -232,9 +264,22 @@ export function ensurePythonRuntime({
232
264
  try {
233
265
  runChecked(run, base.command, [...base.args, "-m", "venv", staging], "Could not create the Fuploader Python runtime");
234
266
  const stagingPython = pythonRuntimeExecutable(staging, platform);
235
- runChecked(run, stagingPython, [
236
- "-m", "pip", "install", "--disable-pip-version-check", "--no-input", "--requirement", requirements,
237
- ], "Could not install Fuploader Python dependencies");
267
+ if (uv) {
268
+ runChecked(run, uv.command, [
269
+ ...uv.args,
270
+ "pip", "install",
271
+ "--python", stagingPython,
272
+ "--requirements", requirements,
273
+ "--link-mode", "copy",
274
+ "--no-config",
275
+ "--no-progress",
276
+ "--no-python-downloads",
277
+ ], "Could not install Fuploader Python dependencies with uv");
278
+ } else {
279
+ runChecked(run, stagingPython, [
280
+ "-m", "pip", "install", "--disable-pip-version-check", "--no-input", "--requirement", requirements,
281
+ ], "Could not install Fuploader Python dependencies");
282
+ }
238
283
  runChecked(run, stagingPython, [
239
284
  "-m", "playwright", "install", "chromium",
240
285
  ], "Could not install Fuploader Chromium", {
@@ -247,6 +292,8 @@ export function ensurePythonRuntime({
247
292
  writeMarker(staging, {
248
293
  schema: PYTHON_RUNTIME_SCHEMA,
249
294
  requirements_sha256: requirementsHash,
295
+ dependency_installer: dependencyInstaller,
296
+ dependency_installer_version: uv ? uv.version.join(".") : null,
250
297
  python_version: installed.version.join("."),
251
298
  dependency_version: installed.dependencyVersion,
252
299
  playwright_version: installed.playwrightVersion,
@@ -265,7 +312,13 @@ export function ensurePythonRuntime({
265
312
  }
266
313
  throw error;
267
314
  }
268
- created = inspectRuntime({ root, platform, requirementsHash, env, run });
315
+ created = inspectRuntime({
316
+ root,
317
+ platform,
318
+ requirementsHash,
319
+ env,
320
+ run,
321
+ });
269
322
  if (!created) {
270
323
  fs.rmSync(root, { recursive: true, force: true });
271
324
  if (movedOld) {
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema": "fupload.npm-skill-manifest.v1",
3
3
  "package_name": "@follenfang/fupload",
4
- "package_version": "0.0.7",
5
- "skill_version": "0.0.7",
6
- "tree_sha256": "f2693bc26ecd3f9bab3ed691a2f372c5702b6ac5f72f52880fc6cee40ca90314",
4
+ "package_version": "0.0.9",
5
+ "skill_version": "0.0.9",
6
+ "tree_sha256": "515a7cdff306e466484f7974521025ca9072a3869cc021207a0e692dae977676",
7
7
  "files": [
8
8
  {
9
9
  "path": "agents/openai.yaml",
@@ -108,7 +108,7 @@
108
108
  {
109
109
  "path": "scripts/fupload_cli/__init__.py",
110
110
  "bytes": 49,
111
- "sha256": "b44c52f9e6b2989921c93580a400ddcd3dd3e5c1cc787e9984baf0dabdfd93e7"
111
+ "sha256": "7762ec22ff37c14cc8942b1f136910050aea07e4e6904f98b3ab8434e6b89800"
112
112
  },
113
113
  {
114
114
  "path": "scripts/fupload_cli/blackbox_web.py",
@@ -188,7 +188,7 @@
188
188
  {
189
189
  "path": "SKILL.md",
190
190
  "bytes": 23242,
191
- "sha256": "941f2c5f615dded9fcfe086516a9bf903f54db52351815c38d26c2691f71793b"
191
+ "sha256": "1b9e444846724b03ee3e2e0ab89f50b85d33c1dfc4edbcb19d64118af2412571"
192
192
  }
193
193
  ]
194
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@follenfang/fupload",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "Install and run the Fuploader Agent Skill and Python CLI.",
5
5
  "type": "module",
6
6
  "bin": {