@follenfang/fupload 0.0.8 → 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.8"
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.8"
3
+ __version__ = "0.0.9"
@@ -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,6 +45,22 @@ 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
65
  const run = options.run || spawnSync;
50
66
  const env = options.runtimeRoot
@@ -129,7 +145,10 @@ function probeRuntime(executable, root, env, run = spawnSync) {
129
145
 
130
146
  function inspectRuntime({ root, platform, requirementsHash, env, run }) {
131
147
  const marker = readMarker(root);
132
- if (marker?.schema !== PYTHON_RUNTIME_SCHEMA || marker.requirements_sha256 !== requirementsHash) {
148
+ if (
149
+ marker?.schema !== PYTHON_RUNTIME_SCHEMA ||
150
+ marker.requirements_sha256 !== requirementsHash
151
+ ) {
133
152
  return null;
134
153
  }
135
154
  const command = pythonRuntimeExecutable(root, platform);
@@ -210,6 +229,7 @@ export function ensurePythonRuntime({
210
229
  home = os.homedir(),
211
230
  run = spawnSync,
212
231
  discover = discoverPython,
232
+ discoverUv: locateUv = discoverUv,
213
233
  } = {}) {
214
234
  const requirements = pythonRequirementsFile(packageRoot);
215
235
  const content = fs.readFileSync(requirements);
@@ -218,7 +238,15 @@ export function ensurePythonRuntime({
218
238
  const parent = path.dirname(root);
219
239
  const lock = acquireRuntimeLock(root);
220
240
  try {
221
- 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
+ });
222
250
  if (current) {
223
251
  return { status: "current", root, requirements, python: current };
224
252
  }
@@ -236,9 +264,22 @@ export function ensurePythonRuntime({
236
264
  try {
237
265
  runChecked(run, base.command, [...base.args, "-m", "venv", staging], "Could not create the Fuploader Python runtime");
238
266
  const stagingPython = pythonRuntimeExecutable(staging, platform);
239
- runChecked(run, stagingPython, [
240
- "-m", "pip", "install", "--disable-pip-version-check", "--no-input", "--requirement", requirements,
241
- ], "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
+ }
242
283
  runChecked(run, stagingPython, [
243
284
  "-m", "playwright", "install", "chromium",
244
285
  ], "Could not install Fuploader Chromium", {
@@ -251,6 +292,8 @@ export function ensurePythonRuntime({
251
292
  writeMarker(staging, {
252
293
  schema: PYTHON_RUNTIME_SCHEMA,
253
294
  requirements_sha256: requirementsHash,
295
+ dependency_installer: dependencyInstaller,
296
+ dependency_installer_version: uv ? uv.version.join(".") : null,
254
297
  python_version: installed.version.join("."),
255
298
  dependency_version: installed.dependencyVersion,
256
299
  playwright_version: installed.playwrightVersion,
@@ -269,7 +312,13 @@ export function ensurePythonRuntime({
269
312
  }
270
313
  throw error;
271
314
  }
272
- created = inspectRuntime({ root, platform, requirementsHash, env, run });
315
+ created = inspectRuntime({
316
+ root,
317
+ platform,
318
+ requirementsHash,
319
+ env,
320
+ run,
321
+ });
273
322
  if (!created) {
274
323
  fs.rmSync(root, { recursive: true, force: true });
275
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.8",
5
- "skill_version": "0.0.8",
6
- "tree_sha256": "19b487eaba532263a849d4bfd48f4f40166edbf156f5317e5dbcc040fdc9819e",
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": "7f13892a82918a297a8af731adf5b20a540dd3a873d089bf133225a0a642a840"
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": "ad3813733c9fd7aac62683f704bf1adc25982b6d45a14e4d749b6734a2bee3c3"
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.8",
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": {