@follenfang/fupload 0.0.0-bootstrap.0 → 0.0.2
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 +236 -3
- package/fupload/SKILL.md +142 -0
- package/fupload/agents/openai.yaml +4 -0
- package/fupload/examples/curseforge-plugin-upload.json +21 -0
- package/fupload/examples/dd-config-delete.json +5 -0
- package/fupload/examples/dd-config-update.json +25 -0
- package/fupload/examples/dd-plugin-delete.json +5 -0
- package/fupload/examples/dd-plugin-update.json +9 -0
- package/fupload/examples/dd-wa-delete.json +5 -0
- package/fupload/examples/dd-wa-edit.json +9 -0
- package/fupload/examples/newbee-config-delete.json +5 -0
- package/fupload/examples/newbee-config-update.json +10 -0
- package/fupload/examples/newbee-plugin-create.json +14 -0
- package/fupload/examples/newbee-plugin-delete.json +5 -0
- package/fupload/examples/newbee-wa-delete.json +5 -0
- package/fupload/examples/newbee-wa-update.json +8 -0
- package/fupload/references/curseforge.md +233 -0
- package/fupload/references/dd.md +105 -0
- package/fupload/references/newbee-official-cli.md +288 -0
- package/fupload/references/newbee.md +80 -0
- package/fupload/references/workflow.md +67 -0
- package/fupload/scripts/fupload.py +17 -0
- package/fupload/scripts/fupload_cli/__init__.py +3 -0
- package/fupload/scripts/fupload_cli/cli.py +281 -0
- package/fupload/scripts/fupload_cli/curseforge.py +186 -0
- package/fupload/scripts/fupload_cli/dd.py +2406 -0
- package/fupload/scripts/fupload_cli/dd_broker.py +634 -0
- package/fupload/scripts/fupload_cli/dd_sidecar.py +860 -0
- package/fupload/scripts/fupload_cli/errors.py +94 -0
- package/fupload/scripts/fupload_cli/io.py +125 -0
- package/fupload/scripts/fupload_cli/newbee.py +1412 -0
- package/fupload/scripts/fupload_cli/newbee_auth.py +135 -0
- package/fupload/scripts/fupload_cli/schema.py +587 -0
- package/fupload/scripts/fupload_cli/transport.py +125 -0
- package/fupload/scripts/fupload_cli/trust.py +207 -0
- package/npm/bin/fupload.mjs +92 -0
- package/npm/lib/curseforge-config.mjs +36 -0
- package/npm/lib/managed-install.mjs +86 -0
- package/npm/lib/options.mjs +38 -0
- package/npm/lib/python.mjs +45 -0
- package/npm/lib/skill-installer.mjs +228 -0
- package/npm/lib/uninstall.mjs +211 -0
- package/npm/lib/update.mjs +102 -0
- package/npm/lib/versions.mjs +63 -0
- package/npm/postinstall.mjs +21 -0
- package/npm/skill-manifest.json +179 -0
- package/package.json +50 -6
package/README.md
CHANGED
|
@@ -1,4 +1,237 @@
|
|
|
1
|
-
# Fuploader
|
|
1
|
+
# Fuploader
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Fuploader 是一个面向 Agent 的《魔兽世界》作者发布 Skill 和 CLI。npm 安装后统一使用 `fupload` 命令;命令内部运行随 Skill 分发的纯 Python 实现。新手盒子(NewBeeBox)默认优先使用官方 `ncc` CLI,用户显式要求第三方管理工具时才使用 Fuploader 通道;网易 DD 使用 Fuploader 调用官方无头客户端;CurseForge 使用 Core API 查询作者公开项目,并使用 Authors Upload API 上传插件 ZIP。
|
|
4
|
+
|
|
5
|
+
项目强调显式调用、完整字段收集、写入前确认和写入后读回验证。CLI 只负责单次原子读写,业务选择、执行计划和异常恢复由 Agent 在对话中完成。
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
- 支持新手盒子官方 `ncc`、第三方 Python 管理通道、网易 DD 和 CurseForge。
|
|
10
|
+
- CurseForge 支持按作者 ID 查询 WoW 公开项目、读取上传用游戏版本,以及向已有项目上传插件 ZIP;不创建 Project,也不枚举私有、草稿或待审 Project。
|
|
11
|
+
- 支持插件、配置分享、WA/字符串的创建、内容更新与元数据编辑。
|
|
12
|
+
- 官方通道严格采用已安装 `ncc` 暴露的能力;第三方 Python 通道覆盖版本、游戏分支、分类、媒体、可见性、审核、商业设置、频道、关联内容和配置备份选择等页面字段。
|
|
13
|
+
- 第三方 Python 以 Creator Center 网页的请求和表单状态为基准,编辑和更新采用 `GET -> 动态选项查询 -> presence-aware patch -> 写入 -> 读回`;关联作者/内容在主记录读回后替换并再次读回。官方通道采用 `ncc` 文档规定的只读查询、写入和读回命令。
|
|
14
|
+
- 第三方 Python 写入使用严格 JSON Schema:未知字段、重复键、`NaN` 和 `Infinity` 均会被拒绝;官方 `ncc` 使用参数和 `-o json` 结构化输出。
|
|
15
|
+
- 新手盒子官方通道复用本机 `ncc login` 或预先注入的 `NCC_TOKEN`,第三方通道复用桌面客户端登录状态;不接收或输出 token、cookie、JWT、签名 URL、DD `clientNo`、原始 WA 字符串或原始配置内容。
|
|
16
|
+
- DD 通过已安装官方客户端的无头运行环境完成原生登录、签名和官方 `WowUIInterface.parseWa` WA2 解析;一次发布任务只建立一个串行会话,任务结束立即退出。
|
|
17
|
+
- DD 写入前按官方网页的详情投影和表单校验重建完整请求;可选 VIP/频道依赖只在启用时查询,插件版本历史遍历分页,WA 新版本只接受纯数字。4xx/业务错误会在 DD 版本目录的 `Fupload/logs` 保存经过递归脱敏且按 UTF-8 字节限长的请求与响应记录。
|
|
18
|
+
- DD 回归以 `resource × action × field × state` 表驱动矩阵覆盖 195 个 create/update/edit/delete 输入字段;每个字段校验正常值、替代值、遗漏、null、非法类型及适用的 false/0/空值/边界,并捕获 JSON 序列化后的最终 endpoint、请求体、上传和 mutation 次数。
|
|
19
|
+
|
|
20
|
+
## 目录
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
npm/ # npm 启动器、Skill 安装/卸载及发布检查
|
|
24
|
+
fupload/
|
|
25
|
+
|- SKILL.md # Agent Skill 主入口
|
|
26
|
+
|- agents/openai.yaml # Skill 元数据
|
|
27
|
+
|- references/ # 工作流和双平台完整字段契约
|
|
28
|
+
|- examples/ # 双平台 JSON 输入示例
|
|
29
|
+
`- scripts/
|
|
30
|
+
|- fupload.py # CLI 入口
|
|
31
|
+
|- fupload_cli/ # Python 实现
|
|
32
|
+
`- tests/ # 回归测试
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`analyze/` 用于本地探索、真实验证中间文件和报告,已被 Git 忽略。
|
|
36
|
+
|
|
37
|
+
## 环境要求
|
|
38
|
+
|
|
39
|
+
- Fuploader npm CLI:Node.js >= 18.18、Python >= 3.9
|
|
40
|
+
- 新手盒子官方通道:Windows、macOS 或 Linux,Node.js >= 18、官方 `ncc` CLI 与本机登录态
|
|
41
|
+
- 新手盒子第三方 Python 通道:Windows、Python 3、已安装并登录新手盒子桌面客户端
|
|
42
|
+
- 网易 DD:Windows、Python 3、已安装并登录官方客户端
|
|
43
|
+
|
|
44
|
+
官方 `ncc` 的安装命令为 `npm i -g @newbeebox/newbeebox-creator-center-cli@latest`。Fuploader 不读取其凭据文件;用户在自己的终端完成 `ncc login`,Agent 仅用 `ncc whoami -o json` 验证。自动化可在启动 Agent 前注入 `NCC_TOKEN`,令牌不得写入命令参数、项目文件或 Git。
|
|
45
|
+
|
|
46
|
+
第三方 Python 通道的认证目录由 Windows Known Folder API 定位到用户 Roaming AppData 下的 `NewBeeBox/auth-store`。NewBee API、认证、元数据和上传 origin 固定为官方 HTTPS 地址,环境变量不能重定向凭据或文件。DD 会自动查找安装目录,验证 `netease_dd.exe` 的 Authenticode 官方发布者后再启动,并把稳定的 sidecar 设备状态保存在 Roaming AppData 下的 `CCVoiceHub/Fupload/sidecar-device.json`。
|
|
47
|
+
|
|
48
|
+
## 安装
|
|
49
|
+
|
|
50
|
+
```powershell
|
|
51
|
+
npm install -g @follenfang/fupload
|
|
52
|
+
fupload --version
|
|
53
|
+
fupload --help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
全局安装会同时创建 `fupload` 命令,并把版本匹配的 Skill 原子安装到 `~/.agents/skills/fupload/`。可用 `FUPLOAD_AGENT_HOME` 把默认位置改为 `<home>/skills/fupload`,或在单次命令中使用 `--skill-dir <完整路径>`;所有成功管理过的 Skill 路径都会登记,供完整卸载使用。
|
|
57
|
+
|
|
58
|
+
安装和 `fupload update` 还会幂等创建缺失的 `~/.fupload/curseforge.env`;已有文件逐字节保留,不覆盖或补写其中的值:
|
|
59
|
+
|
|
60
|
+
```dotenv
|
|
61
|
+
CURSEFORGE_AUTHOR_ID=
|
|
62
|
+
CURSEFORGE_API_KEY=
|
|
63
|
+
CURSEFORGE_UPLOAD_TOKEN=
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`CURSEFORGE_AUTHOR_ID` 是可在对话中提供的非秘密数字 ID;Core API Key 与 Upload Token 是两套不同秘密。请只在本机 env 文件或进程环境中填写秘密,不要粘贴到 Agent 对话、命令参数、项目文件或 Git。
|
|
67
|
+
|
|
68
|
+
## 作为 Skill 使用
|
|
69
|
+
|
|
70
|
+
安装后显式调用:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
$fupload
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
该 Skill 不会因普通提及“发布”“新手盒子”“DD”或“CurseForge”而自动触发。Agent 会先询问平台、资源和动作。新手盒子会自动检测 `ncc`:已安装即默认使用官方通道;未安装时先询问是否安装;只有用户显式选择第三方 Python 管理工具才进入项目内 CLI。CurseForge 上传缺少作者 ID 时,Agent 会主动询问;缺少 API Key 或 Upload Token 时,只会引导用户在本机填写 `~/.fupload/curseforge.env`,不会要求在对话中提供秘密。Agent 在被发布项目中创建 `publish/<时间>-<平台>-<资源>-<动作>/`,同一次发布的脱敏 JSON 按原子步骤保存为 `01-<动作>.json`、`02-<动作>.json`。展示完整写入计划并得到确认后才会真实写入。
|
|
77
|
+
|
|
78
|
+
## CLI 使用
|
|
79
|
+
|
|
80
|
+
新手盒子官方 CLI:
|
|
81
|
+
|
|
82
|
+
```powershell
|
|
83
|
+
npm i -g @newbeebox/newbeebox-creator-center-cli@latest
|
|
84
|
+
ncc -V
|
|
85
|
+
ncc docs
|
|
86
|
+
ncc whoami -o json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
创建令牌和本机登录说明见[官方 CLI 文档](https://creator.newbeebox.com/cli-docs)。不要把令牌粘贴到 Agent 对话;在自己的终端完成 `ncc login`。
|
|
90
|
+
|
|
91
|
+
以下为 Fuploader 第三方 NewBeeBox、DD 与 CurseForge 执行层。
|
|
92
|
+
|
|
93
|
+
查看总帮助:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
fupload --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
检查 CurseForge 配置、查询作者公开项目和读取游戏版本:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
fupload curseforge session doctor
|
|
103
|
+
fupload curseforge project list
|
|
104
|
+
fupload curseforge project list --author-id 138844367
|
|
105
|
+
fupload curseforge plugin game-versions
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
上传前先执行本地 dry-run;确认完整计划后再移除 `--dry-run`:
|
|
109
|
+
|
|
110
|
+
```powershell
|
|
111
|
+
fupload curseforge plugin upload --input fupload\examples\curseforge-plugin-upload.json --dry-run
|
|
112
|
+
fupload curseforge plugin upload --input publish\20260807-120000-curseforge-plugin-upload\01-upload.json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
查看具体操作的可执行字段契约:
|
|
116
|
+
|
|
117
|
+
```powershell
|
|
118
|
+
fupload newbee plugin create --help
|
|
119
|
+
fupload dd config update --help
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
检查桌面登录与安装状态:
|
|
123
|
+
|
|
124
|
+
```powershell
|
|
125
|
+
fupload newbee session doctor
|
|
126
|
+
fupload dd session doctor
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
DD doctor 不会登录。若输出 `gui_running=true`,需先取得用户同意,随后关闭已验证的官方 GUI 并建立一个任务会话:
|
|
130
|
+
|
|
131
|
+
```powershell
|
|
132
|
+
fupload dd session start --confirm-close-gui
|
|
133
|
+
fupload dd options game-types --session <session-id>
|
|
134
|
+
fupload dd session stop --session <session-id>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
GUI 未运行时,`session start` 不加 `--confirm-close-gui`。后续 DD 的动态查询、写入和读回都传同一个 `--session`,并在 `finally` 中 stop。
|
|
138
|
+
|
|
139
|
+
读取当前游戏分支:
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
fupload newbee plugin game-versions
|
|
143
|
+
fupload dd options game-types
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
写操作只接受 JSON 输入。建议先 dry-run:
|
|
147
|
+
|
|
148
|
+
```powershell
|
|
149
|
+
fupload newbee plugin create --input fupload\examples\newbee-plugin-create.json --dry-run
|
|
150
|
+
fupload dd plugin update --input fupload\examples\dd-plugin-update.json --dry-run
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
所有命令输出一个 `schema=fupload.output.v1` 的 JSON 对象。退出码 `0` 表示成功,退出码 `2` 表示校验、会话、平台或写后验证错误。
|
|
154
|
+
|
|
155
|
+
## 升级与完整卸载
|
|
156
|
+
|
|
157
|
+
```powershell
|
|
158
|
+
fupload update
|
|
159
|
+
fupload uninstall
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`fupload update` 固定安装 `@follenfang/fupload@latest`,随后把默认位置和所有登记有效的自定义 Skill 同步到同一版本。未知目录不会被覆盖。
|
|
163
|
+
|
|
164
|
+
`fupload uninstall` 先删除所有仍有有效 npm 管理标记的 Fuploader Skill,再调用 npm 删除 `@follenfang/fupload` 和 `fupload` 命令。Skill 清理失败时 npm 包保持可用,处理占用或权限问题后可重试。项目中的 `publish/`、新手盒子/DD 登录数据、DD 日志和 `~/.fupload/curseforge.env` 始终保留。
|
|
165
|
+
|
|
166
|
+
npm 7 及以上不执行卸载 lifecycle,因此直接运行 `npm uninstall -g @follenfang/fupload` 只删除 npm 包和 CLI,可能留下 Skill;它不属于完整卸载流程。
|
|
167
|
+
|
|
168
|
+
## 工作流约束
|
|
169
|
+
|
|
170
|
+
1. 写入前先运行目标 leaf command 的 `--help`,以运行时 Schema 为准。
|
|
171
|
+
2. 使用只读命令获取账号记录、分类、版本、备份、频道和关联候选,不猜测 ID;DD 的全部命令复用一个任务 session。
|
|
172
|
+
3. DD 配置按 `backup_sn -> backup detail -> WTF 账号/服务器/角色 -> 该账号的 WA` 逐层选择,依赖闭合后只生成一次最终 JSON。
|
|
173
|
+
4. 每次独立发布都在目标项目的 `publish/` 下创建新目录,不把 JSON 写入 Skill 目录,也不自动删除发布记录。
|
|
174
|
+
5. 第三方 Python 写入先执行 `--dry-run`;官方 `ncc` 只对文档声明支持的叶子执行 dry-run,例如 `addons push --dry-run`。
|
|
175
|
+
6. 得到明确确认后串行写入,每步成功后立即读回验证。
|
|
176
|
+
7. 遇到 `verification_required` 时先读取远端状态,再决定是否重试。
|
|
177
|
+
|
|
178
|
+
完整契约见:
|
|
179
|
+
|
|
180
|
+
- [工作流与 CLI 契约](fupload/references/workflow.md)
|
|
181
|
+
- [新手盒子官方 CLI 完整参考](fupload/references/newbee-official-cli.md)
|
|
182
|
+
- [新手盒子第三方 Python 字段参考](fupload/references/newbee.md)
|
|
183
|
+
- [网易 DD 字段参考](fupload/references/dd.md)
|
|
184
|
+
- [CurseForge API、字段与上传参考](fupload/references/curseforge.md)
|
|
185
|
+
|
|
186
|
+
## 测试
|
|
187
|
+
|
|
188
|
+
```powershell
|
|
189
|
+
npm test
|
|
190
|
+
npm run check:manifest
|
|
191
|
+
npm run test:pack
|
|
192
|
+
npm run test:install
|
|
193
|
+
python -m unittest discover -s fupload\scripts\tests
|
|
194
|
+
python -m compileall -q fupload\scripts
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
当前回归测试覆盖 CLI 路由、严格 JSON、字段 Schema、平台 builder、动态选项校验、字段保留与清空语义,以及所有内置示例的 dry-run。
|
|
198
|
+
|
|
199
|
+
DD 逐字段 wire 矩阵可单独运行并生成本地审计报告:
|
|
200
|
+
|
|
201
|
+
```powershell
|
|
202
|
+
python -m unittest discover -s fupload\scripts\tests -p test_dd_wire_matrix.py -v
|
|
203
|
+
python fupload\scripts\tests\generate_dd_wire_matrix_report.py > analyze\dd-field-by-field-wire-regression-20260801.md
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 版本与发布
|
|
207
|
+
|
|
208
|
+
正式版本使用 SemVer。Git tag 固定为 `vX.Y.Z`,去掉 `v` 后必须与以下位置完全一致:
|
|
209
|
+
|
|
210
|
+
- `package.json` 和 `package-lock.json`
|
|
211
|
+
- `fupload/SKILL.md` 的 `metadata.version`
|
|
212
|
+
- `fupload/scripts/fupload_cli/__init__.py` 的 `__version__`
|
|
213
|
+
- `npm/skill-manifest.json` 的包版本与 Skill 版本
|
|
214
|
+
|
|
215
|
+
当前版本为 `0.0.2`,对应 tag `v0.0.2`。`.github/workflows/publish-npm.yml` 在 pull request、`main` push 和 `v*` tag 上运行 Windows/Linux CI;只有 tag CI 全部通过时才通过 npm Trusted Publishing/OIDC 发布,不使用长期 `NPM_TOKEN`。
|
|
216
|
+
|
|
217
|
+
发布前在 npm 包设置中绑定 Trusted Publisher:
|
|
218
|
+
|
|
219
|
+
- npm package:`@follenfang/fupload`
|
|
220
|
+
- GitHub organization/user:`Follen`
|
|
221
|
+
- repository:`Fuploader`
|
|
222
|
+
- workflow:`publish-npm.yml`
|
|
223
|
+
|
|
224
|
+
然后从已推送且干净的 `main` 创建 annotated tag:
|
|
225
|
+
|
|
226
|
+
```powershell
|
|
227
|
+
npm run check:versions
|
|
228
|
+
npm run check:release -- v0.0.2
|
|
229
|
+
git tag -a v0.0.2 -m "Fuploader 0.0.2"
|
|
230
|
+
git push origin v0.0.2
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
npm 对首次创建的包可能要求先由账号所有者完成一次 bootstrap 发布;该步骤只用于建立包身份,正式 `latest` 由版本 tag workflow 发布。需要人工处理时,不要把 npm token 写入仓库或 GitHub Secret。
|
|
234
|
+
|
|
235
|
+
## 说明
|
|
236
|
+
|
|
237
|
+
官方 `ncc` 通道以已安装版本的 `ncc docs` 和叶子 `--help` 为执行契约;仓库内官方文档是获取时的完整快照。第三方 Python 与 DD 通道依赖桌面客户端和线上接口的当前行为,客户端版本或接口变化后应先运行 session doctor 和只读命令。Fuploader 项目本身不是新手盒子或网易 DD 的官方项目。
|
package/fupload/SKILL.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fupload
|
|
3
|
+
description: Explicit author-publishing workflow for World of Warcraft plugins, configuration shares, and WA/strings on NewBeeBox, NetEase DD, and CurseForge, including CurseForge author project lookup and plugin ZIP upload. 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, plugins, configurations, or WA.
|
|
4
|
+
metadata:
|
|
5
|
+
version: "0.0.2"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Fupload
|
|
9
|
+
|
|
10
|
+
Act as the publishing operator. For NewBeeBox, prefer the official `ncc` CLI whenever it is installed unless the user explicitly requests the third-party Python management tool. For DD, CurseForge, and an explicitly selected third-party NewBeeBox workflow, use the bundled Python CLI. Keep investigation, choices, planning, confirmation, and recovery in the conversation.
|
|
11
|
+
|
|
12
|
+
When installed from npm, interpret `<fupload-cli>` as `fupload`. Only while maintaining the source repository, directly installing this Skill, or when `fupload` is absent from PATH, use `python <skill-root>/scripts/fupload.py`. Keep the user's current project as the working directory in either mode.
|
|
13
|
+
|
|
14
|
+
## Establish intent
|
|
15
|
+
|
|
16
|
+
When the user has not already stated both dimensions, ask in one short message:
|
|
17
|
+
|
|
18
|
+
1. Platform: NewBeeBox, DD, or CurseForge.
|
|
19
|
+
2. Resource and action: plugin/configuration/WA, then create/content update/metadata edit/delete. CurseForge supports public project listing and uploading a plugin ZIP to an existing project only.
|
|
20
|
+
|
|
21
|
+
Map natural language consistently:
|
|
22
|
+
|
|
23
|
+
- `create`: create the main record. If first content is a separate platform action, plan it as a following atomic step.
|
|
24
|
+
- `update`: publish a plugin version, change selected configuration-backup content, or publish a WA/string version.
|
|
25
|
+
- `edit`: change fields allowed by the target platform's action allowlist. For DD plugins, this is existing-record commercial, association, room/channel, and creation-statement settings; first-publication metadata, categories, media, and version fields are create/update-only.
|
|
26
|
+
- `delete`: delete one main record only. It never deletes an individual version, media object, or associated record.
|
|
27
|
+
|
|
28
|
+
Never offer bulk delete, version-file delete, drafts, guides, messages, or GUI control automation. The DD task-session command may close verified official GUI processes only after the consent flow below.
|
|
29
|
+
|
|
30
|
+
CurseForge cannot create a project or enumerate private, draft, or pending-review projects. Direct project creation to the Authors website; use the Core API list only as the public-project view for one numeric author ID.
|
|
31
|
+
|
|
32
|
+
## Select the execution channel
|
|
33
|
+
|
|
34
|
+
For DD, use the bundled Python CLI.
|
|
35
|
+
|
|
36
|
+
For CurseForge, use the bundled Python CLI. Do not substitute direct HTTP calls or the CurseForge for Studios API for uploads: public project lookup uses the Core API, while game-version lookup and upload use the separate Upload API and credential.
|
|
37
|
+
|
|
38
|
+
For NewBeeBox, apply this order exactly:
|
|
39
|
+
|
|
40
|
+
1. If the user explicitly requests the third-party Python management tool, use the bundled Python CLI even when `ncc` is installed.
|
|
41
|
+
2. Otherwise detect `ncc` locally. On PowerShell use `Get-Command ncc -ErrorAction SilentlyContinue`; on POSIX shells use `command -v ncc`. Do not ask the user to report a fact the environment can show.
|
|
42
|
+
3. If installed, select official `ncc` by default. Run `ncc -V`, `ncc --help`, `ncc docs`, and `ncc whoami -o json`. Treat the installed `ncc docs` and target leaf `--help` as the execution contract. From `whoami`, retain or report only the creator identity and module permissions needed for the task; redact token names, prefixes, timestamps, and other credential metadata.
|
|
43
|
+
4. If not installed, ask whether the user wants the official CLI. If yes, check `node -v` is at least 18, help install Node.js when needed, then run `npm i -g @newbeebox/newbeebox-creator-center-cli@latest`. Verify `ncc -V` and `ncc --help`; installation success is not authentication success.
|
|
44
|
+
5. After installation, direct the user to `https://creator.newbeebox.com/creator-center/cli-token` to create a token and have them run `ncc login` in their own terminal. Resume only after `ncc whoami -o json` verifies the expected creator identity. For automation, accept an `NCC_TOKEN` already present in the Agent process environment without printing it.
|
|
45
|
+
6. If the user declines official installation, or official docs do not support the target action, explain the exact boundary. Use the Python channel only after the user explicitly chooses the third-party Python management tool.
|
|
46
|
+
|
|
47
|
+
Never switch channels silently. Before changing channels, re-read remote state and present a new plan so the same create, version, or edit cannot be submitted twice.
|
|
48
|
+
|
|
49
|
+
## Protect credentials
|
|
50
|
+
|
|
51
|
+
For NewBeeBox, prefer an existing official `ncc login`, then a caller-provided `NCC_TOKEN`, then user-performed local login. Never ask the user to paste a token into the conversation. Never place a real NewBeeBox token in `--token`, shell history, command output, JSON, `.env`, `publish/`, `analyze/`, tests, Skill files, references, or Git. Do not inspect or copy the official CLI credential store.
|
|
52
|
+
|
|
53
|
+
For CurseForge, use `~/.fupload/curseforge.env`, created idempotently by npm install/update, with `CURSEFORGE_AUTHOR_ID`, `CURSEFORGE_API_KEY`, and `CURSEFORGE_UPLOAD_TOKEN`. The author ID is non-secret: if absent, proactively ask for its numeric value or offer `--author-id`. The API key and upload token are secrets: never ask the user to paste either into the conversation; direct them to fill the local env file in their own editor or terminal, then run `curseforge session doctor`. Never print file contents or secret values. Process environment values may override the file without being shown.
|
|
54
|
+
|
|
55
|
+
If a token is pasted into the conversation, do not repeat or use it. Tell the user to revoke or regenerate it at its provider and configure the replacement locally. Check only whether the expected field is present, never its length, prefix, hash, or value.
|
|
56
|
+
|
|
57
|
+
## Locate the Fuploader CLI
|
|
58
|
+
|
|
59
|
+
Run `<fupload-cli> --help` from the user's project. The npm launcher resolves and verifies the installed Skill relative to the package, then invokes its bundled Python implementation; do not change the working directory to the Skill.
|
|
60
|
+
|
|
61
|
+
When the npm command is absent and the source/direct-Skill fallback is required, resolve `<skill-root>` from this `SKILL.md` and use `python <skill-root>/scripts/fupload.py`. On Windows, prefer `py -3` only if `python` is unavailable. Do not use a binary, Go source, repository-relative fallback, browser automation, Computer Use, or direct handcrafted HTTP calls. NewBeeBox's official `ncc` is not this bundled CLI and must not be wrapped as a Python `--input` command.
|
|
62
|
+
|
|
63
|
+
For npm package maintenance, use `fupload update` to update the CLI and every registered managed Skill to `@follenfang/fupload@latest`. For a complete removal, use `fupload uninstall`; it removes every registered Skill that still has a valid Fuploader npm ownership marker, then removes the npm package and command. Do not use direct `npm install -g` or `npm uninstall -g` as the normal Agent-managed update/removal workflow.
|
|
64
|
+
|
|
65
|
+
## Load only the needed contract
|
|
66
|
+
|
|
67
|
+
- Read [references/workflow.md](references/workflow.md) for every write workflow.
|
|
68
|
+
- For official NewBeeBox, read [references/newbee-official-cli.md](references/newbee-official-cli.md), then run the installed `ncc docs` and exact leaf `--help`. The bundled reference is a complete official snapshot, but runtime docs win when versions differ.
|
|
69
|
+
- Read [references/newbee.md](references/newbee.md) only when the user explicitly selected the third-party Python NewBeeBox channel.
|
|
70
|
+
- Read [references/dd.md](references/dd.md) only for DD.
|
|
71
|
+
- Read [references/curseforge.md](references/curseforge.md) for every CurseForge lookup or upload.
|
|
72
|
+
- For Python, run the exact leaf command with `--help` before creating its input. Treat help as the executable schema contract.
|
|
73
|
+
|
|
74
|
+
## Investigate
|
|
75
|
+
|
|
76
|
+
Inspect the user-provided project or current workspace for `.toc`, README, changelog, Git changes, archives, screenshots, logos, and WA material files. Do not modify or package the user's project until that is part of the agreed plan.
|
|
77
|
+
|
|
78
|
+
Use read-only commands from the selected channel to discover the current account's records, target detail, versions, backups, categories, game branches/builds, installation paths, life types, VIP levels, channels, and association candidates. Never ask the user to copy an ID that the selected CLI can query.
|
|
79
|
+
|
|
80
|
+
For CurseForge, run `curseforge session doctor`, then `curseforge project list` using `CURSEFORGE_AUTHOR_ID` or the user-provided non-secret `--author-id`. Select a public project by name plus `project_id`. Before a version-tagged upload, run `curseforge plugin game-versions` and select returned IDs or names; do not guess IDs from display names. A parent-file upload instead uses `parent_file_id` and omits both game-version fields. Inspect the ZIP and local release notes. An empty public list does not prove the account has no private, draft, or pending-review projects.
|
|
81
|
+
|
|
82
|
+
For official NewBeeBox, use the documented `ncc wow addons list|info|categories|versions`, `wa list|info|categories`, `uipack list|info`, `cloudbackup list|info`, and related commands needed by the action. Use the exact options returned by the installed help. `addons push` compatibility uses explicit build strings or documented `auto`; never substitute a parent branch ID. An empty required option list blocks the write.
|
|
83
|
+
|
|
84
|
+
For third-party Python NewBeeBox, use Creator Center webpage requests and form behavior as the business baseline. Always read `newbee options content-origins`, `subscribe-plans`, and `time-ranges` when the corresponding field is present. Also read plugin categories/builds, WA categories, attachment paths, and each resource's `co-author`/`reference` candidates for those fields. Empty option output blocks the write. Plugin compatibility uses build strings from `game-versions.items[].versions`, never the parent branch `id`. Preserve omitted edit fields; an explicit empty `co_authors` or `references` array replaces and clears that complete relation only after the main record readback succeeds.
|
|
85
|
+
|
|
86
|
+
For DD, use the one active task session to read game types/builds and the resource-specific category tree. Resolve parent/child choices in dependency order, display only children returned for the selected parent, and invalidate all descendants when a parent changes. A plugin primary category is a top-level item and secondary IDs are children of that item. Validate associations as `(act_type,sn)`. A room-only selection has `room_id` with empty `channel_id` and `channel_type`; a channel selection requires both channel fields. Query VIP levels only when anchor VIP is enabled and query room/channel data only when room linkage is enabled; disabled optional features do not depend on those endpoints.
|
|
87
|
+
|
|
88
|
+
For every existing DD update or edit, GET the detail first and rebuild the official full form before preparing the write. If a legacy record lacks a field now required by the official submit validator, such as `creation_statement`, stop before upload and collect that value. When the missing field belongs to a different action allowlist, plan and confirm the prerequisite edit first, read it back, then run the content update. Do not send `null`, create defaults, or guessed values to bypass the missing field.
|
|
89
|
+
|
|
90
|
+
For DD WA create, collect user choices before generating JSON, then let the Python CLI supply only the official create defaults for omitted form values: seven-day share and purchase lifetimes, `need_buy=false`, category `ui_original`, `Interface/Addons`, empty VIP levels, and version `0`. Submit category IDs as strings even when a discovery response represents them numerically. WA create/update versions contain digits only; update must be numerically greater than the current remote value. Every `!WA:2!` create/update/edit is reparsed by the installed official `WowUIInterface.parseWa` chain, including unchanged edit content. Do not carry create defaults into WA update/edit; omitted existing fields preserve their remote value.
|
|
91
|
+
|
|
92
|
+
For official NewBeeBox, use only `ncc whoami -o json` to verify authentication; do not inspect its credential files. For third-party Python NewBeeBox, run `newbee session doctor`; credentials must come from the Windows Known Folder auth-store and all authenticated requests must use fixed official HTTPS origins. For DD, run `dd session doctor`; discovery must accept only an Authenticode-valid executable from an allowed official NetEase publisher. Doctor is local-only and must not start a native login. Do not set endpoint, credential-directory, or DD executable-path environment overrides.
|
|
93
|
+
|
|
94
|
+
## Own one DD task session
|
|
95
|
+
|
|
96
|
+
Before any DD live GET or write, run `dd session doctor`. If it reports `gui_running=true`, tell the user that continuing will close the listed official DD GUI instances and ask for explicit consent. Without consent, do not run start, do not close a process, and do not issue a native login. After consent, run `dd session start --confirm-close-gui`; when no GUI is running, run `dd session start` without that flag.
|
|
97
|
+
|
|
98
|
+
Keep the returned opaque `session_id` only in task memory and pass it as `--session <id>` to every DD GET, write, readback, status, and delete. Reuse this one session for the complete task, serialize all commands, stop on the first failure, and never start one session per item in a batch. In a `finally` path, always run `dd session stop --session <id>` and require `cleanup_complete=true`; the ten-minute idle timeout is only an abnormal-exit fallback.
|
|
99
|
+
|
|
100
|
+
For every DD configuration, first list backups, select `backup_sn`, then run `dd config backup-get --sn <backup>`. Select a WTF account/server/role before presenting that account's known/unknown WA choices. For a retail configuration, present the safe edit-mode and cooldown selector metadata. Send only stable IDs and returned selectors; never request, display, store, or reconstruct raw backup objects or retail import strings.
|
|
101
|
+
|
|
102
|
+
For a configuration, require a cloud backup already uploaded by the matching desktop client. If none exists, ask the user to upload one in the client and stop before writing.
|
|
103
|
+
|
|
104
|
+
## Collect every business choice
|
|
105
|
+
|
|
106
|
+
Expose every business field writable through the selected channel. Do not silently accept a webpage preselection or invent a business default. This includes applicable game type/build, categories, origin, format, visibility, review submission, payment, lifetime, price, room/channel, synchronization, membership, associations, backup content, WTF roles, incremental selections, retail UI data, WA material mode, and install path. When official `ncc` does not expose a webpage field or action, state that capability boundary; do not guess a hidden flag or silently switch to Python.
|
|
107
|
+
|
|
108
|
+
Use existing remote values only for omitted fields in `edit` or `update`, where omission means preserve. Show candidates by human name plus ID/SN and relevant status. Ask only choices that cannot be determined from the user's explicit request, local artifacts, or remote reads. For CurseForge upload, collect project ID, ZIP path, changelog, release type, version IDs/names or parent file choice, and each requested optional metadata field; do not infer visibility or approval from upload acceptance. For DD, do not draft the executable JSON incrementally: close the full dependency graph first, then generate one final JSON containing parent fields and stable child IDs/selectors. Python repeats the live GETs before upload or mutation and rejects missing or cross-parent selections; detail is authoritative when DD list and detail timestamps differ. When an existing plugin or WA has `assign_user_sn`, only public scope is selectable and the final rebuilt form must remain public.
|
|
109
|
+
|
|
110
|
+
## Prepare and confirm
|
|
111
|
+
|
|
112
|
+
Create a durable release directory under the target project's root, never under or beside the installed Skill. Use `publish/<YYYYMMDD-HHmmss>-<platform>-<resource>-<action>/`; if that name already exists, append `-2`, `-3`, and so on instead of reusing it. Put every atomic step in a versioned JSON file ordered as `01-<action>.json`, `02-<action>.json`, and so on. A retry or readback for the same plan reuses its directory; a new independent publishing plan gets a new directory. Use JSON, not YAML. Keep the directory after execution as the target project's publishing record, and do not change its ignore rules unless the user asks.
|
|
113
|
+
|
|
114
|
+
For Python, these are executable `--input` documents using the leaf schema. For official `ncc`, these are redacted plan records containing the channel, working directory, argument vector, non-secret business inputs, local file references, and expected readback; `ncc` does not consume them. Never store a token, API key, raw WA string, raw configuration content, or signed URL in a plan record. Use `@file` or local path references for content. Run `--dry-run` where the selected leaf documents it, especially `ncc wow addons push --dry-run` and every CurseForge upload; do not invent dry-run support for other official commands.
|
|
115
|
+
|
|
116
|
+
Before the first write, present one complete human-readable plan containing:
|
|
117
|
+
|
|
118
|
+
- platform, account-visible target name and ID/SN;
|
|
119
|
+
- ordered atomic commands;
|
|
120
|
+
- every changed, preserved, and explicitly cleared field;
|
|
121
|
+
- archive/media/material files and versions;
|
|
122
|
+
- backup and all content selections;
|
|
123
|
+
- commercial, channel, association, visibility, and review effects;
|
|
124
|
+
- possible retained object or uploaded media if a later step fails.
|
|
125
|
+
|
|
126
|
+
Obtain one explicit confirmation for that exact plan. If the plan changes materially, confirm the changed plan once.
|
|
127
|
+
|
|
128
|
+
For CurseForge, confirmation must name the public project and numeric ID, ZIP path, selected game-version IDs/names or parent file ID, changelog, release type, optional metadata and relations, and whether manual release is requested. After confirmation, execute exactly one upload attempt. A dry-run performs local validation only and is not remote permission or ID validation.
|
|
129
|
+
|
|
130
|
+
For a Python delete, first run the resource `get` command, show the exact name and ID/SN, and obtain confirmation for that single record. NewBeeBox delete input contains only the schema, `id`, and `confirm: "DELETE"`; DD delete input contains only the schema, `sn`, and `confirm_delete: true`. Do not reuse confirmation for another record and do not retry an uncertain delete. Official `ncc` currently documents plugin, WA, and configuration main-record deletion as web-only; state that boundary and wait for an explicit third-party selection before offering the Python delete command.
|
|
131
|
+
|
|
132
|
+
## Execute and verify
|
|
133
|
+
|
|
134
|
+
Run writes serially. For official `ncc`, always request `-o json`, parse stdout as JSON, and treat stderr only as progress diagnostics. For Python, parse its stable JSON output. Never scrape human text. After each successful step, immediately run the corresponding info/get/list/versions/history command and compare the intended fields in the same DD session when applicable. DD performs a bounded GET-only readback poll and never resends a mutation during verification. For DD plugin update, use a nonempty `/addon/addon_versions` result only as a pre-upload duplicate guard; the matching author-list item's `latest_version` is the primary success confirmation and `detail_v2` is supplementary. Plugin edit also uses the same-SN author projection when detail remains stale. An empty history is diagnostic-only. Treat “submitted for review” and “under review” as distinct from “approved” or “publicly visible.”
|
|
135
|
+
|
|
136
|
+
For CurseForge, treat the Upload API's returned file ID as upload acceptance only. Record the ID and command result, then report that moderation, processing, manual release, and public visibility are separate states. On an interrupted or ambiguous upload, do not resend automatically because that can create a duplicate file; inspect the Authors project page or public file list before deciding on a new attempt. Follow the HTTP/error handling table in the CurseForge reference.
|
|
137
|
+
|
|
138
|
+
In the third-party Python NewBeeBox channel, public plugin publication is three atomic writes: create privately, upload and verify the first version, then edit to public with explicit review intent. Never send a public `share_state` during Python create. In the official channel, follow the installed `ncc docs` sequence for create, init, push, and visibility instead of applying Python wire rules.
|
|
139
|
+
|
|
140
|
+
Stop on the first failure. Report completed steps, retained IDs/SNs or media references, the redacted failure stage, whether verification is required, and the smallest safe retry. Explicit DD HTTP/business rejection has `verification_required=false`; interrupted PUT/mutation or failed readback after an accepted write has `verification_required=true`. Native DD failures may include a bounded message, HTTP status, native business code, field validation hints, and `details.log_path`. When `log_path` is present, read only the referenced Fuploader JSONL record under the DD version directory; do not inspect DD's other logs or any credential files. The Fuploader record contains sanitized request and response JSON/body plus byte counts and truncation flags, with signed URLs, cookies, JWTs, credentials, client identifiers, signatures, and tokens recursively redacted. Read back after an uncertain write before resending it. Official NewBeeBox exit codes are `0` success, `1` business error, `2` authentication failure, and `3` network error. Never loop on `quota_exceeded`.
|
|
141
|
+
|
|
142
|
+
Never print or persist tokens, cookies, JWTs, signed URLs, DD `clientNo`, raw WA strings, or raw configuration backup contents.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "fupload.v1.curseforge.plugin.upload",
|
|
3
|
+
"project_id": 123456,
|
|
4
|
+
"file": "./addon.zip",
|
|
5
|
+
"changelog": "Release notes for 1.0.0",
|
|
6
|
+
"changelog_type": "markdown",
|
|
7
|
+
"display_name": "Example AddOn 1.0.0",
|
|
8
|
+
"game_versions": [12345],
|
|
9
|
+
"game_version_names": ["Retail"],
|
|
10
|
+
"release_type": "release",
|
|
11
|
+
"relations": {
|
|
12
|
+
"projects": [
|
|
13
|
+
{
|
|
14
|
+
"slug": "example-library",
|
|
15
|
+
"project_id": 74924,
|
|
16
|
+
"type": "requiredDependency"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"is_marked_for_manual_release": false
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "fupload.v1.dd.config.update",
|
|
3
|
+
"share_sn": "config-share-sn",
|
|
4
|
+
"backup_sn": "backup-sn",
|
|
5
|
+
"update_desc": "Backup content update",
|
|
6
|
+
"known_addon_ids": [],
|
|
7
|
+
"known_addon_update_ids": [],
|
|
8
|
+
"unknown_addon_ids": [],
|
|
9
|
+
"unknown_addon_update_ids": [],
|
|
10
|
+
"wtf_role_ids": [],
|
|
11
|
+
"material_names": [],
|
|
12
|
+
"material_update_names": [],
|
|
13
|
+
"font_names": [],
|
|
14
|
+
"font_update_names": [],
|
|
15
|
+
"known_wa_ids": [],
|
|
16
|
+
"known_wa_update_ids": [],
|
|
17
|
+
"unknown_wa_ids": [],
|
|
18
|
+
"unknown_wa_update_ids": [],
|
|
19
|
+
"retail_ui_config": {
|
|
20
|
+
"edit_mode_selectors": ["em_from_backup_get"],
|
|
21
|
+
"default_edit_mode_selector": "em_from_backup_get",
|
|
22
|
+
"cool_down_selectors": ["cd_from_backup_get"],
|
|
23
|
+
"enable_dd_setup_wizard": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "fupload.v1.newbee.plugin.create",
|
|
3
|
+
"name": "Example AddOn",
|
|
4
|
+
"mod_categories": [101],
|
|
5
|
+
"content_origin": 1,
|
|
6
|
+
"content_format": 2,
|
|
7
|
+
"intro": "Short introduction",
|
|
8
|
+
"description": "Full description",
|
|
9
|
+
"logo_file": "./logo.png",
|
|
10
|
+
"screenshot_files": ["./screenshot.png"],
|
|
11
|
+
"public": false,
|
|
12
|
+
"subscribe_plan_level": 0,
|
|
13
|
+
"link_to_channel": false
|
|
14
|
+
}
|