@kevlns/ship-cli 0.0.0-stage → 0.1.0
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/AGENTS.md +25 -0
- package/LICENSE +21 -0
- package/README.md +83 -2
- package/dist/cli.mjs +2851 -0
- package/dist/index.mjs +2879 -0
- package/docs/research/steam.md +14 -0
- package/docs/research/wechat-minigame.md +31 -0
- package/package.json +77 -4
- package/schemas/ship-config.schema.json +191 -0
- package/v-cli.plugin.json +486 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Steam 官方契约
|
|
2
|
+
|
|
3
|
+
核验日期:2026-10-09。依据 Valve [Uploading to Steam](https://partner.steamgames.com/doc/sdk/uploading)、[Steamworks API](https://partner.steamgames.com/doc/sdk/api)、[Depots](https://partner.steamgames.com/doc/store/application/depots)。
|
|
4
|
+
|
|
5
|
+
- SteamPipe 通过 steamcmd 的 +login / +run_app_build / +quit 构建上传已生成的产物。ship-cli 不执行引擎构建。
|
|
6
|
+
- AppBuild VDF 指定 AppID、Desc、ContentRoot、BuildOutput、Preview、SetLive、Depots;DepotBuild VDF 指定 DepotID、ContentRoot、FileMapping、FileExclusion。
|
|
7
|
+
- Preview=1 产生本地日志和清单,不上传。SetLive 仅用于测试分支,default 分支必须在 Steamworks 后台处理。
|
|
8
|
+
- BuildOutput 保存缓存和日志,必须与上传产物分离;工具校验真实路径,包括 Windows junction,拒绝目录交叠和产物链接。
|
|
9
|
+
- Steam API 分发库为 Windows 的 steam_api.dll / steam_api64.dll、Linux 的 libsteam_api.so、macOS 的 libsteam_api.dylib。steam test 检查文件与 AppID,不启动游戏,也不能证明 SDK 初始化成功。
|
|
10
|
+
- 本地绕过 Steam 客户端启动时通过 steam_appid.txt 提供 AppID;正常从 Steam 启动的发行包不依赖该文件。
|
|
11
|
+
|
|
12
|
+
Valve 没有承诺稳定的机器可读日志协议。工具采取保守判定:非零退出、错误日志、登录 Guard 提示均失败;成功记录须包含当前 AppID 的 Successfully finished ... build,真实上传还须包含 BuildID。无法确定时返回 STM_BUILD_UNKNOWN_OUTCOME。这条日志解析规则仍需真实账号日志验证。
|
|
13
|
+
|
|
14
|
+
工具仅读取 SHIP_STEAM_*。免密登录需要有效的 steamcmd 缓存;SHIP_STEAM_CONFIG_VDF 提供 base64 缓存,拒绝覆盖不同的已有文件。缓存存在不代表账号或权限有效。进度和日志脱敏包括跨输出块拆分的密码及运行时生成的 Guard 码;执行超时为一小时。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 微信小游戏官方契约
|
|
2
|
+
|
|
3
|
+
核验日期:2026-10-09。官方页面直接获取成功,同时核对微信 SDK README 和 npm registry。
|
|
4
|
+
|
|
5
|
+
## 官方依据
|
|
6
|
+
|
|
7
|
+
- [代码包](https://developers.weixin.qq.com/minigame/dev/guide/base-ability/code-package.html)
|
|
8
|
+
- [使用分包](https://developers.weixin.qq.com/minigame/dev/guide/base-ability/subPackage/useSubPackage.html)
|
|
9
|
+
- [独立分包](https://developers.weixin.qq.com/minigame/dev/guide/base-ability/independent-sub-packages.html)
|
|
10
|
+
- [Worker](https://developers.weixin.qq.com/minigame/dev/guide/base-ability/workers)
|
|
11
|
+
- [game.json](https://developers.weixin.qq.com/minigame/dev/reference/configuration/app.html)
|
|
12
|
+
- [project.config.json](https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html)
|
|
13
|
+
- [官方 miniprogram-ci README](https://github.com/wechat-miniprogram/miniprogram-ci-dist/blob/master/README.md)
|
|
14
|
+
|
|
15
|
+
## 结构与体积
|
|
16
|
+
|
|
17
|
+
上传默认主包 4 MiB、每个独立分包 4 MiB、总包 30 MiB;普通分包没有单独大小上限。开放数据域计入主包。目录分包根目录需要 game.js,单 JS 文件也可以成为分包。
|
|
18
|
+
|
|
19
|
+
官方示例 /moduleA/ 是小游戏内路径,工具规范为 moduleA,不当作操作系统绝对路径;拒绝系统盘符、网络路径、目录穿越、根目录交叠。Worker 支持字符串目录以及 {path, isSubpackage:true};分包能力从基础库 2.27.3 起提供,不属于 independent 分包。
|
|
20
|
+
|
|
21
|
+
离线统计支持 packOptions 的 file / folder / suffix / prefix / regexp / glob,include 优先于 ignore;SDK Project ignores 独立生效,默认 node_modules/**/*。统计标记 filtered-source-estimate,源码编译压缩后大小会变化。wx validate 是保守离线预算门禁,不代表平台实际编译包大小;最终上传结果由 SDK 和服务器决定。
|
|
22
|
+
|
|
23
|
+
## SDK 契约
|
|
24
|
+
|
|
25
|
+
使用 new ci.Project({appid,type:'miniGame',projectPath,privateKeyPath,ignores}),以及 ci.upload / ci.preview 的 Node API。robot 为 1–30 的数字;setting 默认 useProjectConfig=true。配置使用明确布尔字段,不存在 ciArgs 透传。preview 使用 qrcodeFormat=image 与实际 qrcodeOutputDest。
|
|
26
|
+
|
|
27
|
+
bigPackageSizeSupport 只用于 preview,不改变上传限制,也不承诺小游戏具有固定 8 MiB 预览额度。registry 当前可安装 2.1.31,官方 README 版本列表已到 2.1.48,两者不能混用;工具支持 >=2.1.31 <3。
|
|
28
|
+
|
|
29
|
+
SDK 必须返回有效完成记录;退出 0 不等于完成。subPackageInfo 可选,原样保留在 JSON 结果中。preview 还必须实际生成 PNG 二维码。私钥须为可解析 PEM,放在上传目录之外;二维码也在产物之外,默认 build/ship-preview/<随机标识>/qr.png,拒绝覆盖已有文件。执行默认超时 15 分钟,可通过 timeoutMs 配置。
|
|
30
|
+
|
|
31
|
+
upload 创建开发版本;体验版、体验者、提审和发布在微信后台处理。preview 调用微信服务生成扫码入口,不创建开发版本,也不是离线预演。
|
package/package.json
CHANGED
|
@@ -1,6 +1,79 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevlns/ship-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Cross-platform game shipping CLI. Validate, package and push builds to game platforms (Steam via steamcmd VDF builds, WeChat mini games via miniprogram-ci). Never publishes to players on its own.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public",
|
|
8
|
+
"provenance": true
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"ship-cli": "dist/cli.mjs"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./dist/index.mjs",
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/",
|
|
20
|
+
"schemas/",
|
|
21
|
+
"v-cli.plugin.json",
|
|
22
|
+
"AGENTS.md",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"docs/research/"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsup",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"lint": "eslint src tests scripts",
|
|
32
|
+
"check": "npm run build && npm run typecheck && npm run test && npm run lint && npm run pack:guard",
|
|
33
|
+
"pack:guard": "node scripts/pack-guard.mjs",
|
|
34
|
+
"test:package": "node scripts/test-package-install.mjs",
|
|
35
|
+
"prepack": "npm run build",
|
|
36
|
+
"pretest": "npm run build"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"game",
|
|
40
|
+
"shipping",
|
|
41
|
+
"steam",
|
|
42
|
+
"steamcmd",
|
|
43
|
+
"steampipe",
|
|
44
|
+
"wechat",
|
|
45
|
+
"minigame",
|
|
46
|
+
"miniprogram-ci",
|
|
47
|
+
"publish"
|
|
48
|
+
],
|
|
49
|
+
"author": "kevlns",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"ajv": "8.20.0",
|
|
56
|
+
"commander": "12.1.0",
|
|
57
|
+
"minimatch": "9.0.9"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "9.6.0",
|
|
61
|
+
"@types/node": "20.19.0",
|
|
62
|
+
"eslint": "9.6.0",
|
|
63
|
+
"tsup": "8.5.1",
|
|
64
|
+
"typescript": "5.6.3",
|
|
65
|
+
"typescript-eslint": "8.71.1",
|
|
66
|
+
"vitest": "4.1.11"
|
|
67
|
+
},
|
|
68
|
+
"vCli": {
|
|
69
|
+
"manifest": "v-cli.plugin.json"
|
|
70
|
+
},
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "git+https://github.com/kevlns/ship-cli.git"
|
|
74
|
+
},
|
|
75
|
+
"homepage": "https://github.com/kevlns/ship-cli#readme",
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/kevlns/ship-cli/issues"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://github.com/kevlns/ship-cli/schemas/ship-config.schema.json",
|
|
4
|
+
"title": "ship-cli project configuration (ship.config.json)",
|
|
5
|
+
"description": "Non-secret, repo-committed configuration for shipping a game project to distribution platforms. Secrets (Steam credentials, WeChat upload keys) are never stored here: they come from environment variables or user-level key files referenced by path.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schemaVersion"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": {
|
|
11
|
+
"const": 1,
|
|
12
|
+
"description": "Config schema version. Only 1 is supported."
|
|
13
|
+
},
|
|
14
|
+
"name": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"minLength": 1,
|
|
17
|
+
"description": "Optional human-readable project name used in output."
|
|
18
|
+
},
|
|
19
|
+
"steam": {
|
|
20
|
+
"$ref": "#/definitions/steam"
|
|
21
|
+
},
|
|
22
|
+
"wechat": {
|
|
23
|
+
"$ref": "#/definitions/wechat"
|
|
24
|
+
},
|
|
25
|
+
"limits": {
|
|
26
|
+
"$ref": "#/definitions/limits"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"definitions": {
|
|
30
|
+
"relativePath": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"minLength": 1,
|
|
33
|
+
"pattern": "^(?![/\\\\])(?![A-Za-z]:)(?!.*(?:^|[/\\\\])\\.\\.(?:[/\\\\]|$))(?!.*[\\u0000-\\u001f]).+$",
|
|
34
|
+
"description": "Relative path, forward or back slashes, no leading slash, no '..' segments."
|
|
35
|
+
},
|
|
36
|
+
"steam": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": ["appId", "contentRoot", "buildOutput", "depots"],
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"properties": {
|
|
41
|
+
"appId": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"minimum": 1,
|
|
44
|
+
"description": "Steam AppID of the base application."
|
|
45
|
+
},
|
|
46
|
+
"contentRoot": {
|
|
47
|
+
"$ref": "#/definitions/relativePath",
|
|
48
|
+
"description": "Root directory of built content. Resolved against the config file location."
|
|
49
|
+
},
|
|
50
|
+
"buildOutput": {
|
|
51
|
+
"$ref": "#/definitions/relativePath",
|
|
52
|
+
"description": "steamcmd BuildOutput directory (logs + chunk cache). Must NOT be inside contentRoot."
|
|
53
|
+
},
|
|
54
|
+
"executable": {
|
|
55
|
+
"$ref": "#/definitions/relativePath",
|
|
56
|
+
"description": "Optional main executable relative to contentRoot, checked by 'steam test'."
|
|
57
|
+
},
|
|
58
|
+
"steamcmdPath": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"minLength": 1,
|
|
61
|
+
"description": "Optional explicit steamcmd executable path. Env SHIP_STEAMCMD wins over this."
|
|
62
|
+
},
|
|
63
|
+
"depots": {
|
|
64
|
+
"type": "array",
|
|
65
|
+
"minItems": 1,
|
|
66
|
+
"items": {
|
|
67
|
+
"$ref": "#/definitions/depot"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"depot": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"required": ["id", "source"],
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"properties": {
|
|
77
|
+
"id": {
|
|
78
|
+
"type": "integer",
|
|
79
|
+
"minimum": 1,
|
|
80
|
+
"description": "Depot ID. Convention: base app depots start at appId+1."
|
|
81
|
+
},
|
|
82
|
+
"source": {
|
|
83
|
+
"$ref": "#/definitions/relativePath",
|
|
84
|
+
"description": "Directory inside contentRoot whose CONTENTS map to the depot root. Use \".\" for the whole contentRoot."
|
|
85
|
+
},
|
|
86
|
+
"exclusions": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"items": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"minLength": 1
|
|
91
|
+
},
|
|
92
|
+
"description": "FileExclusion glob patterns for this depot, e.g. *.pdb, *_BurstDebugInformation_DoNotShip*."
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"wechat": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"required": ["appid", "projectPath"],
|
|
99
|
+
"additionalProperties": false,
|
|
100
|
+
"properties": {
|
|
101
|
+
"appid": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"pattern": "^wx[0-9a-f]{16}$",
|
|
104
|
+
"description": "WeChat mini game AppID."
|
|
105
|
+
},
|
|
106
|
+
"projectPath": {
|
|
107
|
+
"$ref": "#/definitions/relativePath",
|
|
108
|
+
"description": "Mini game project directory (contains game.json / game.js / project.config.json)."
|
|
109
|
+
},
|
|
110
|
+
"robot": {
|
|
111
|
+
"type": "integer",
|
|
112
|
+
"minimum": 1,
|
|
113
|
+
"maximum": 30,
|
|
114
|
+
"default": 1,
|
|
115
|
+
"description": "miniprogram-ci robot slot (1-30). Different robots keep separate dev-version records in the MP backend."
|
|
116
|
+
},
|
|
117
|
+
"privateKeyPath": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"minLength": 1,
|
|
120
|
+
"description": "Path to the code-upload private key file downloaded from the MP backend. Env SHIP_WX_PRIVATE_KEY / WX_UPLOAD_KEY wins over this. May contain '~'."
|
|
121
|
+
},
|
|
122
|
+
"ignores": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"items": {
|
|
125
|
+
"type": "string",
|
|
126
|
+
"minLength": 1
|
|
127
|
+
},
|
|
128
|
+
"default": ["node_modules/**/*"],
|
|
129
|
+
"description": "Glob rules passed directly to ci.Project and used by source-size estimation."
|
|
130
|
+
},
|
|
131
|
+
"setting": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"additionalProperties": false,
|
|
134
|
+
"properties": {
|
|
135
|
+
"useProjectConfig": {
|
|
136
|
+
"type": "boolean"
|
|
137
|
+
},
|
|
138
|
+
"es6": {
|
|
139
|
+
"type": "boolean"
|
|
140
|
+
},
|
|
141
|
+
"es7": {
|
|
142
|
+
"type": "boolean"
|
|
143
|
+
},
|
|
144
|
+
"minify": {
|
|
145
|
+
"type": "boolean"
|
|
146
|
+
},
|
|
147
|
+
"minifyJS": {
|
|
148
|
+
"type": "boolean"
|
|
149
|
+
},
|
|
150
|
+
"codeProtect": {
|
|
151
|
+
"type": "boolean"
|
|
152
|
+
},
|
|
153
|
+
"autoPrefixWXSS": {
|
|
154
|
+
"type": "boolean"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"bigPackageSizeSupport": {
|
|
159
|
+
"type": "boolean",
|
|
160
|
+
"default": false,
|
|
161
|
+
"description": "SDK preview-only option; does not alter upload limits."
|
|
162
|
+
},
|
|
163
|
+
"timeoutMs": {
|
|
164
|
+
"type": "integer",
|
|
165
|
+
"minimum": 1000,
|
|
166
|
+
"maximum": 3600000,
|
|
167
|
+
"default": 900000
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"limits": {
|
|
172
|
+
"type": "object",
|
|
173
|
+
"additionalProperties": false,
|
|
174
|
+
"description": "WeChat package size limits in bytes (1024-based M). Defaults follow official rules as of 2026-10; override only when WeChat changes them.",
|
|
175
|
+
"properties": {
|
|
176
|
+
"wxMainBytes": {
|
|
177
|
+
"type": "integer",
|
|
178
|
+
"minimum": 1
|
|
179
|
+
},
|
|
180
|
+
"wxIndependentSubpackageBytes": {
|
|
181
|
+
"type": "integer",
|
|
182
|
+
"minimum": 1
|
|
183
|
+
},
|
|
184
|
+
"wxTotalBytes": {
|
|
185
|
+
"type": "integer",
|
|
186
|
+
"minimum": 1
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|