@aswless_854771076/ai_short_studio_cli 0.1.86 → 0.1.88

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
@@ -57,14 +57,15 @@ CLI 不提供分集删除或任务人工复核提交;这两类需要确认生
57
57
  ```bash
58
58
  ai-short-studio config ai-provider list --json
59
59
  ai-short-studio config ai-provider get --id <providerId> --json
60
- ai-short-studio config ai-provider set --id <providerId> [--base-url <url>] [--api-key-stdin] [--enabled true|false] [--preset <name>] [--json]
60
+ ai-short-studio config ai-provider set --id <providerId> [--base-url <url>] [--api-key <key>] [--protocol <mode>] [--enabled true|false] [--json]
61
61
  ai-short-studio config ai-provider test --id <providerId> --json
62
62
  ai-short-studio config ai-provider models --id <providerId> --json
63
63
  ai-short-studio config ai-provider capabilities --json
64
64
  ```
65
65
 
66
- - `--api-key-stdin` 从隐藏 stdin 读取密钥,禁止写入 shell 历史或日志;非交互环境使用 `VVICAT_AI_PROVIDER_<ID>_API_KEY` 显式注入。
67
- - `--preset <name>` 调用服务端内置 Preset(如 `openai-compatible`、`runninghub`、`comfly`)一键种子。
66
+ - `--api-key <key>` 仅写入、不会回显,但会留在 shell 历史里。**CI / 脚本场景改用 `--file <path.json>`**(省略 `--file` 时从 stdin 读完整 JSON body),避免密钥进命令行。
67
+ - `--protocol <mode>` 取值 `openai` / `comfyui-official` / `runninghub`;`--api-mode` 用于 gateway 协议族字段。
68
+ - `--file` 传完整 JSON body;`--create` 强制走 POST 创建(默认 PATCH 404 时自动回退 create)。
68
69
  - `test` 输出延迟与 HTTP 状态,不消耗配额外的 token。`models` 只在 `enabled` 且最近一次 `test` 成功时返回目录。
69
70
  - `capabilities` 报告当前生效的私有/LAN baseUrl 白名单(来自环境变量 `VVICAT_ALLOW_PRIVATE_PROVIDER_BASE_URLS`,CSV `host:port`)、已注册 Provider 数量、未配置 Provider 类型与缺失项,方便 Agent 明确自己能做什么、缺什么。
70
71
  - 设置 Provider `baseUrl` 时若目标是私有/LAN 主机(如 `http://127.0.0.1:8188`、`http://192.168.3.30:8188` 本地 ComfyUI),必须在运行 Next.js 的环境里把 `VVICAT_ALLOW_PRIVATE_PROVIDER_BASE_URLS=127.0.0.1:8188,192.168.3.30:8188` 显式打开;公网 URL 仍强制 HTTPS 与公网 IP 校验。
@@ -84,6 +85,194 @@ ai-short-studio canvas folder copy-cross-project --project <sourceProjectId> --a
84
85
 
85
86
  `canvas folder copy-cross-project` 可用 `--target-episode-id` 指定复制品所属分集;省略 `--target-folder-id` 时,复制品进入该分集的未分类资产。目标目录必须属于目标项目和目标分集。两个参数都会去除首尾空白并拒绝空白值。该命令只复制资产及版本,不复制源目录结构。
86
87
 
88
+ ## 命令参考
89
+
90
+ 本节按 `src/commands/**` 的实际命令定义逐条列出。退出码由 `src/base-command.ts` 的 `exitCode()` 统一映射:`0` 成功、`3` 未认证(HTTP 401)、`4` 不存在(HTTP 404)、`5` 禁止或冲突(HTTP 403 / 409)、`6` 参数错误(HTTP 400 / 422)、`7` 其他错误(其他 HTTP 状态或本地异常)、`8` 仅 `task wait` 专有——批量等待结束但仍有任务未 `completed` 时以 8 退出。
91
+
92
+ ### 全局 flag
93
+
94
+ 所有命令继承 `BaseCommand.baseFlags`(`src/base-command.ts`):
95
+
96
+ | Flag | 类型 | 默认值 | 必填 | 说明 |
97
+ | ---- | ---- | ------ | ---- | ---- |
98
+ | `--base-url` | string | 无 | 否 | VVICAT 服务地址;env `VVICAT_BASE_URL` |
99
+ | `--json` | boolean | `false` | 否 | 输出稳定 JSON |
100
+ | `--locale` | string | `zh` | 否 | 响应语言,可选 `zh` / `en` |
101
+ | `--profile` | string | 无 | 否 | 配置档案名称 |
102
+ | `--episode` | string | 无 | 否 | 画布分集 ID 或集数;env `VVICAT_CANVAS_EPISODE` |
103
+
104
+ `--project <projectId>`(`command-helpers.ts` 的 `projectFlag`)在所有画布/项目子命令中**必填**。
105
+
106
+ ### preflight
107
+
108
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
109
+ | ---- | ---- | ----------- | ---- | ---------- |
110
+ | `preflight` | 创作前检查 CLI 版本、服务连通性、认证和模型配置 | `--update`(boolean,默认 `true`,`allowNo`,用 `--no-update` 关闭;服务端声明的 `minCliVersion` 强制升级时不可跳过) | `ai-short-studio preflight --json` | 3 / 4 / 7 |
111
+
112
+ 更新成功后输出 `restartRequired: true` 与 `nextAction`,必须重跑 preflight。
113
+
114
+ ### auth
115
+
116
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
117
+ | ---- | ---- | ----------- | ---- | ---------- |
118
+ | `auth signup` | 使用邮箱和密码注册账号 | `--email`、`--password-stdin`(boolean,默认 `false`)、`--supabase-url`(env `VVICAT_SUPABASE_URL`)、`--supabase-publishable-key`(env `VVICAT_SUPABASE_PUBLISHABLE_KEY`)、`--locale` | `ai-short-studio auth signup --email user@example.com --password-stdin` | 6 / 7 |
119
+ | `auth login` | 登录并把 refresh token 保存到系统钥匙串 | `--email`、`--google`(boolean,默认 `false`)、`--password-stdin`(默认 `false`)、`--supabase-url`、`--supabase-publishable-key` | `ai-short-studio auth login --google` | 3 / 7 |
120
+ | `auth logout` | 注销并清除本机 refresh token 与 session 缓存 | 仅全局 flag | `ai-short-studio auth logout --json` | 7 |
121
+ | `auth status` | 检查当前登录状态 | 仅全局 flag | `ai-short-studio auth status --json` | 3 / 7 |
122
+
123
+ `auth signup` 输出 `registrationAccepted` / `authenticated` / `confirmationRequired`。
124
+
125
+ ### project
126
+
127
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
128
+ | ---- | ---- | ----------- | ---- | ---------- |
129
+ | `project list` | 列出无限画布项目 | `--page`(integer,默认 `1`)、`--page-size`(integer,默认 `50`)、`--search` | `ai-short-studio project list --json` | 3 / 7 |
130
+ | `project create` | 创建无限画布项目 | `--name`(**必填**)、`--description` | `ai-short-studio project create --name "CLI Draft" --json` | 5 / 6 / 7 |
131
+ | `project get` | 读取单个项目 | 位置参数 `projectId`(**必填**) | `ai-short-studio project get <projectId> --json` | 4 / 7 |
132
+ | `project update` | 更新项目名称与描述 | 位置参数 `projectId`(**必填**)、`--name`、`--description` | `ai-short-studio project update <projectId> --name "新名称" --json` | 4 / 5 / 7 |
133
+ | `project delete` | 删除项目(不可逆) | 位置参数 `projectId`(**必填**)、`--yes`(**必填** boolean) | `ai-short-studio project delete <projectId> --yes --json` | 4 / 5 / 6 |
134
+
135
+ 项目创建与列表固定限定 `INFINITE_CANVAS`。
136
+
137
+ ### project provider(Pexels 素材供应商)
138
+
139
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
140
+ | ---- | ---- | ----------- | ---- | ---------- |
141
+ | `project provider get` | 读取项目 Pexels 供应商配置 | 位置参数 `projectId`(**必填**) | `ai-short-studio project provider get <projectId> --json` | 4 / 7 |
142
+ | `project provider set` | 写入项目 Pexels 供应商配置 | 位置参数 `projectId`(**必填**)、`--file`(JSON 文件,省略时读 stdin) | `ai-short-studio project provider set <projectId> --file pexels.json --json` | 4 / 6 / 7 |
143
+ | `project provider test` | 测试项目 Pexels 供应商连通性 | 位置参数 `projectId`(**必填**) | `ai-short-studio project provider test <projectId> --json` | 4 / 7 |
144
+
145
+ ### canvas(读取与图补丁)
146
+
147
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
148
+ | ---- | ---- | ----------- | ---- | ---------- |
149
+ | `canvas get` | 读取整张画布(节点 + 连线) | `--project`(必填) | `ai-short-studio canvas get --project "$PROJECT_ID" --json` | 4 / 7 |
150
+ | `canvas inspect` | 一次读取并筛选节点、连线、资产、设置与节点目录 | `--include`(multiple,默认 `['summary','nodes','edges']`,可选 `summary/nodes/edges/assets/settings/node-types`)、`--kind`(multiple)、`--status`(multiple)、`--search`、`--operation`、`--resource-type`、`--producer-node` | `ai-short-studio canvas inspect --project "$PROJECT_ID" --include assets --include node-types --json` | 4 / 7 |
151
+ | `canvas apply` | 执行低层画布图补丁(节点/连线/删除/视口) | `--file`(patch JSON,省略时读 stdin)、`--canvas-id`(已知画布 ID)、`--expected-version`(integer) | `ai-short-studio canvas apply --project "$PROJECT_ID" --canvas-id "$CANVAS_ID" --expected-version 7 --file patch.json --json` | 4 / 5 / 6 / 7 |
152
+
153
+ `--canvas-id` 与 `--expected-version` 同时提供时跳过保存前的全图预读。
154
+
155
+ ### canvas settings
156
+
157
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
158
+ | ---- | ---- | ----------- | ---- | ---------- |
159
+ | `canvas settings get` | 读取项目设置(覆盖值 / 生效值 / 来源 + 实时 options) | `--project`(必填) | `ai-short-studio canvas settings get --project "$PROJECT_ID" --json` | 4 / 7 |
160
+ | `canvas settings set` | 原子更新项目设置 | `--field` + `--value`(互斥于 `--file`)、`--file`(JSON 文件,省略时读 stdin) | `ai-short-studio canvas settings set --project "$PROJECT_ID" --file settings.json --json` | 4 / 5 / 6 / 7 |
161
+
162
+ `--field` 与 `--value` 必须成对提供;`--file` 与二者互斥。批量写入时 `expectedVersion` 取最近一次 `settings get` 返回的 `version`;409 冲突后重新 `get` 再重试。
163
+
164
+ ### canvas node
165
+
166
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
167
+ | ---- | ---- | ----------- | ---- | ---------- |
168
+ | `canvas node types` | 读取服务端实时节点类型、默认配置与 schema | 位置参数 `kind`(可选,只看单个 kind) | `ai-short-studio canvas node types tts --json` | 4 / 7 |
169
+ | `canvas node list` | 列出节点(客户端过滤) | `--kind`(multiple)、`--status`(multiple)、`--search`、`--producer-node` | `ai-short-studio canvas node list --project "$PROJECT_ID" --kind storyboard-shot --json` | 4 / 7 |
170
+ | `canvas node get` | 读取单个节点 | 位置参数 `nodeId`(**必填**) | `ai-short-studio canvas node get <nodeId> --project "$PROJECT_ID" --json` | 4 / 7 |
171
+ | `canvas node add` | 新建节点(只提交 kind + 配置,版本由服务端固定) | 位置参数 `kind`(**必填**)、`--x`(默认 `0`)、`--y`(默认 `0`)、`--title`、`--config`(JSON 文件) | `ai-short-studio canvas node add video-frame-extract --project "$PROJECT_ID" --config extract.json --json` | 5 / 6 / 7 |
172
+ | `canvas node update` | 字段级更新单个节点 | 位置参数 `nodeId`(**必填**)、`--set 'key=<JSON>'`(multiple)、`--unset key`(multiple)、`--title`、`--x`、`--y`、`--config`(兼容旧入口,省略且无字段 flag 时读 stdin) | `ai-short-studio canvas node update <nodeId> --project "$PROJECT_ID" --set 'gridSize=9' --unset legacyField --json` | 4 / 5 / 6 / 7 |
173
+ | `canvas node update-many` | 一次画布版本基线上原子更新多个节点 | `--file`(含 `updates` 数组的 JSON,省略时读 stdin) | `ai-short-studio canvas node update-many --project "$PROJECT_ID" --file updates.json --json` | 4 / 5 / 6 / 7 |
174
+ | `canvas node delete` | 删除节点 | 位置参数 `nodeId`(**必填**)、`--yes`(**必填** boolean) | `ai-short-studio canvas node delete <nodeId> --project "$PROJECT_ID" --yes --json` | 4 / 5 / 6 |
175
+ | `canvas node run` | 提交节点执行,可批量并等待 | 位置参数 `nodeId`(可选)、`--node`(multiple,批量)、`--concurrency`(默认 `4`,范围 1–16)、`--wait`(默认 `false`)、`--interval`(默认 `1000` ms)、`--max-wait-ms`(默认 `0` = 不超时)、`--max-attempts`(默认 `0` = 不重试)、`--auto-select-version`(默认 `false`) | `ai-short-studio canvas node run --project "$PROJECT_ID" --node <node1> --node <node2> --concurrency 4 --wait --json` | 4 / 5 / 7 |
176
+ | `canvas node edit-shot` | 编辑镜头并追加人工 DOCUMENT 版本 | 位置参数 `nodeId`(**必填**,必须 `kind=storyboard-shot`)、`--file`(镜头 JSON,省略时读 stdin) | `ai-short-studio canvas node edit-shot <nodeId> --project "$PROJECT_ID" --file shot.json --json` | 4 / 5 / 6 / 7 |
177
+ | `canvas node edit-resource` | 编辑结构化资源并追加人工版本 | 位置参数 `nodeId`(**必填**,必须 `artifact.type=GENERATED_RESOURCE`)、`--file`(结构化资源 JSON,省略时读 stdin) | `ai-short-studio canvas node edit-resource <nodeId> --project "$PROJECT_ID" --file resource.json --json` | 4 / 5 / 6 / 7 |
178
+
179
+ `--max-attempts > 0` 只在单节点下生效,批量时 CLI 打印 warn 并忽略。`edit-shot` / `edit-resource` 具有独立并发基线,409 后需重新读取画布与当前选版。
180
+
181
+ ### canvas edge
182
+
183
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
184
+ | ---- | ---- | ----------- | ---- | ---------- |
185
+ | `canvas edge add`(别名实现 `edge connect`) | 创建连线 | `--from <sourceNodeId>:<sourceHandle>`(**必填**)、`--to <targetNodeId>:<targetHandle>`(**必填**) | `ai-short-studio canvas edge add --project "$PROJECT_ID" --from <n1>:image --to <n2>:start-frame --json` | 4 / 6 / 7 |
186
+ | `canvas edge delete`(别名实现 `edge disconnect`) | 删除连线 | 位置参数 `edgeId`(**必填**)、`--yes`(**必填** boolean) | `ai-short-studio canvas edge delete <edgeId> --project "$PROJECT_ID" --yes --json` | 4 / 5 / 6 |
187
+ | `canvas edge list` | 列出连线 | `--project`(必填) | `ai-short-studio canvas edge list --project "$PROJECT_ID" --json` | 4 / 7 |
188
+
189
+ ### canvas continuity
190
+
191
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
192
+ | ---- | ---- | ----------- | ---- | ---------- |
193
+ | `canvas continuity analyze` | 生成视频前零费用分析镜头依赖,可修复已具备源视频的首尾帧连线 | `--apply-ready`(boolean,默认 `false`;开启后以分析返回的 `canvasVersion` 为 `expectedVersion` 提交 `applyAll: true`) | `ai-short-studio canvas continuity analyze --project "$PROJECT_ID" --apply-ready --json` | 4 / 5 / 7 |
194
+
195
+ ### canvas asset
196
+
197
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
198
+ | ---- | ---- | ----------- | ---- | ---------- |
199
+ | `canvas asset list` | 列出画布资产 | `--kind`、`--search` | `ai-short-studio canvas asset list --project "$PROJECT_ID" --json` | 4 / 7 |
200
+ | `canvas asset get` | 读取单个资产及版本 | 位置参数 `assetId`(**必填**) | `ai-short-studio canvas asset get <assetId> --project "$PROJECT_ID" --json` | 4 / 7 |
201
+ | `canvas asset upload` | 上传资产到 `/api/assets/upload` | 位置参数 `file`(**必填**,本地文件路径)、`--kind`(可选 `image` / `video` / `audio` / `voice`;缺省按扩展名推断,无法识别时报错) | `ai-short-studio canvas asset upload ./voice.wav --project "$PROJECT_ID" --kind voice --json` | 4 / 6 / 7 |
202
+ | `canvas asset download` | 下载资产媒体 | 位置参数 `assetId`(**必填**)、`--version`(缺省用 selected version)、`--output`(默认 `.`) | `ai-short-studio canvas asset download <assetId> --project "$PROJECT_ID" --output ./downloads` | 4 / 7 |
203
+ | `canvas asset select-version`(实现 `asset select`) | 选择资产版本 | 位置参数 `assetId`(可选,与 `--asset` 二选一,不能同时给)、`--asset`、`--version`(**必填**) | `ai-short-studio canvas asset select-version <assetId> --project "$PROJECT_ID" --version <versionId> --json` | 4 / 6 / 7 |
204
+
205
+ `--kind voice` 只接受音频文件(CLI 本地先拦截,不发必然 400 的请求)。下载先写 `.part` 再原子改名,文件名中的 `\/:*?"<>|` 替换为 `_`。
206
+
207
+ ### canvas folder
208
+
209
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
210
+ | ---- | ---- | ----------- | ---- | ---------- |
211
+ | `canvas folder list` | 列出目录树 | `--include-soft-deleted`(boolean,默认 `false`) | `ai-short-studio canvas folder list --project "$PROJECT_ID" --json` | 4 / 7 |
212
+ | `canvas folder create` | 新建子目录 | `--name`(**必填**)、`--parent-id`(别名 `--parent`,省略挂到项目根) | `ai-short-studio canvas folder create --project "$PROJECT_ID" --name "武器" --json` | 4 / 5 / 7 |
213
+ | `canvas folder rename` | 重命名目录 | `--folder-id`(别名 `--folder`,**必填**)、`--name`(**必填**) | `ai-short-studio canvas folder rename --project "$PROJECT_ID" --folder <folderId> --name "新名称" --json` | 4 / 5 / 7 |
214
+ | `canvas folder move` | 同项目内移动目录 | `--folder-id`(**必填**)、`--parent-id`(**必填**) | `ai-short-studio canvas folder move --project "$PROJECT_ID" --folder <folderId> --parent-id <newParentId> --json` | 4 / 5 / 7 |
215
+ | `canvas folder delete` | 软删目录 | `--folder-id`(**必填**) | `ai-short-studio canvas folder delete --project "$PROJECT_ID" --folder <folderId> --json` | 4 / 5 / 7 |
216
+ | `canvas folder restore` | 恢复 30 天回收窗口内的软删目录 | `--folder-id`(**必填**) | `ai-short-studio canvas folder restore --project "$PROJECT_ID" --folder <folderId> --json` | 4 / 5 / 7 |
217
+ | `canvas folder copy-cross-project` | 跨项目/跨分集复制资产(只复制资产与版本,不复制目录结构) | `--asset-id`(别名 `--asset`,**必填**)、`--target-project`(**必填**)、`--target-folder-id`(省略进未分类)、`--target-episode-id`(省略沿用服务端默认分集);后两者拒绝空白值 | `ai-short-studio canvas folder copy-cross-project --project <src> --asset-id <assetId> --target-project <dst> --target-episode-id <epId> --target-folder-id <folderId> --json` | 4 / 5 / 6 / 7 |
218
+
219
+ 目录类错误码见 zh/en 用户手册的 `FOLDER_*` 对照表(`FOLDER_NOT_FOUND` 404 / `FOLDER_CONFLICT` 409 / `FOLDER_PRESET_IMMUTABLE` 409 / `FOLDER_IN_USE` 409 / `FOLDER_CYCLE_DETECTED` 409 / `FOLDER_INVALID_PARAMS` 422 / `FOLDER_FORBIDDEN` 403 / `FOLDER_GONE` 410)。
220
+
221
+ ### canvas episode
222
+
223
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
224
+ | ---- | ---- | ----------- | ---- | ---------- |
225
+ | `canvas episode list` | 列出分集 | `--project`(必填) | `ai-short-studio canvas episode list --project "$PROJECT_ID" --json` | 4 / 7 |
226
+ | `canvas episode create` | 创建分集 | `--number`(integer,**必填**,`min: 1`)、`--name` | `ai-short-studio canvas episode create --project "$PROJECT_ID" --number 2 --json` | 4 / 5 / 6 |
227
+
228
+ 其他画布命令用 `--episode <ID|集数>` 选择分集(env `VVICAT_CANVAS_EPISODE`)。CLI 不提供分集删除。
229
+
230
+ ### task
231
+
232
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
233
+ | ---- | ---- | ----------- | ---- | ---------- |
234
+ | `task get` | 读取单个异步任务 | 位置参数 `taskId`(**必填**) | `ai-short-studio task get <taskId> --json` | 4 / 7 |
235
+ | `task wait` | 轮询等待任务完成 | 位置参数 `taskId`(可选)、`--task`(multiple,批量)、`--concurrency`(默认 `4`,范围 1–16)、`--interval`(默认 `1000` ms)、`--max-wait-ms`(默认 `0` = 不超时) | `ai-short-studio task wait --task <task1> --task <task2> --concurrency 4 --json` | 4 / 7 / **8** |
236
+ | `task cancel` | 取消异步任务 | 位置参数 `taskId`(**必填**)、`--yes`(**必填** boolean) | `ai-short-studio task cancel <taskId> --yes --json` | 4 / 5 / 6 |
237
+
238
+ `task wait` 在批量结果中仍有任务未 `completed` 时以退出码 **8** 结束(`src/commands/task/wait.ts`),其他命令不产生 8。
239
+
240
+ ### config
241
+
242
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
243
+ | ---- | ---- | ----------- | ---- | ---------- |
244
+ | `config get` | 读取个人默认值与管理员已发布的全局模型(不含供应商密钥) | 仅全局 flag | `ai-short-studio config get --json` | 3 / 7 |
245
+ | `config set` | 写入个人默认模型与能力默认值 | `--file`(JSON,省略时读 stdin)、`--verify`(boolean,默认 `false`;set 后再 GET 一次并 diff 请求值与服务端实际值) | `ai-short-studio config set --file ./config.json --verify --json` | 3 / 5 / 6 / 7 |
246
+
247
+ `config set` 拒绝写入 `providers`、`models` 或工作流并发(CLI 与服务端双重校验)。
248
+
249
+ ### config ai-provider(仅管理员)
250
+
251
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
252
+ | ---- | ---- | ----------- | ---- | ---------- |
253
+ | `config ai-provider list` | 列出所有 AI Provider(apiKey 脱敏) | 仅全局 flag | `ai-short-studio config ai-provider list --json` | 3 / 5 / 7 |
254
+ | `config ai-provider get` | 查看单个 Provider 详情 | 位置参数 `providerId`(**必填**) | `ai-short-studio config ai-provider get comfyui --json` | 3 / 4 / 5 |
255
+ | `config ai-provider set` | 配置 Provider 的 baseUrl / apiKey / 协议 / enabled 等 | 位置参数 `providerId`(**必填**)、`--base-url`、`--api-key`、`--api-mode`、`--name`、`--protocol`、`--enabled`(`allowNo`,即 `--no-enabled`)、`--sort-order`、`--file`(完整 JSON body,省略时读 stdin)、`--create`(默认 `false`;默认 PATCH 404 时自动回退 create) | `ai-short-studio config ai-provider set comfyui --base-url http://127.0.0.1:8188 --enabled true --json` | 3 / 4 / 5 / 6 / 7 |
256
+ | `config ai-provider test` | 触发服务端连通性探测(`GET /models` 或 `/system_stats`) | 位置参数 `providerId`(**必填**) | `ai-short-studio config ai-provider test comfyui --json` | 3 / 4 / 5 / 7 |
257
+ | `config ai-provider models` | 拉取 Provider 远端真实模型清单 | 位置参数 `providerId`(**必填**) | `ai-short-studio config ai-provider models comfyui --json` | 3 / 4 / 5 / 7 |
258
+ | `config ai-provider capabilities` | 聚合视图:当前能跑哪些模型、缺什么配置 | `--no-reachability`(默认 `false`,跳过连通性探测)、`--reachability-concurrency`(默认 `4`) | `ai-short-studio config ai-provider capabilities --json` | 3 / 5 / 7 |
259
+
260
+ `--file` 模式要求 JSON body 含 `type` + `name`,此时 CLI 不再叠加任何 flag。`models` 只在 provider `enabled` 且最近一次 `test` 成功时返回目录。
261
+
262
+ ### skill
263
+
264
+ | 命令 | 用途 | 参数 / flag | 示例 | 失败退出码 |
265
+ | ---- | ---- | ----------- | ---- | ---------- |
266
+ | `skill install`(实现与 `skill update` 相同) | 安装/更新内置 Agent Skill | `--target`(默认 `codex`,可选 `codex` / `agents`)、`--skill`(默认 `all`,可选 `all` / `using-vvicat-ai-short-studio-cli` / `short-drama` / `humanizer`)、`--root`(全部内置 Skill 根目录)、`--directory`(兼容旧版,主 Skill 精确目录;与 `--root` 互斥)、`--force`(覆盖非托管或已修改的 Skill) | `ai-short-studio skill update --target codex --skill humanizer --json` | 7 |
267
+ | `skill status` | 查看已安装 Skill 版本与修改状态 | 同上(无 `--force`) | `ai-short-studio skill status --target codex --json` | 7 |
268
+ | `skill path` | 打印内置 Skill 打包路径与目标安装路径 | 同上(无 `--force`) | `ai-short-studio skill path --target agents --json` | 7 |
269
+
270
+ `--target agents` 安装到 `~/.agents/skills`,`--target codex`(默认)安装到 `~/.codex/skills`。`--root` 对应 env `VVICAT_SKILLS_ROOT`;旧 env `VVICAT_SKILL_DIRECTORY` 保持主 Skill 精确目录语义。`VVICAT_SKIP_SKILL_INSTALL=1` 关闭 `postinstall` 自动安装。
271
+
272
+ ### 未覆盖细节的说明
273
+
274
+ 上表覆盖 `src/commands/**` 下全部 61 个命令入口(含 `select-version`/`select`、`edge add`/`connect`、`edge delete`/`disconnect`、`skill install`/`update` 等实现别名)。个别后端业务错误码(如 `MODEL_PRICING_NOT_CONFIGURED`、目录类 `FOLDER_*` 细分码)的完整枚举以 `ai-short-studio <命令> --help` 与 `packages/ai_short_studio_cli/api-surface.json` 的 `notes` 字段为准,本表不臆造未在源码中出现的取值。
275
+
87
276
  ## 项目配置
88
277
 
89
278
  ```bash
@@ -179,6 +368,22 @@ npm run test:local-e2e
179
368
 
180
369
  该命令先构建真实 CLI,再启动隔离的本地 mock API,通过多个 `bin/run.js` 子进程验证聚合查询、字段级与多节点更新、`canvas apply` 免预读、批量执行/等待和旧位置参数兼容;同时启动 8 个独立认证进程,确认共享 session 缓存只触发一次模拟 Keychain 读取和一次刷新。测试不连接生产服务、不调用模型,所有配置、令牌、画布和任务数据均在系统临时目录中创建并在结束时清理。
181
370
 
371
+ ### 真环境只读冒烟(T3 · Phase 1.7 SC4 / D-14)
372
+
373
+ 发布链 `release:ci` / `release:ci:test` 在 `publish --verify` 之后追加 `node scripts/smoke-remote.mjs`,对远端 dev 环境跑认证态全链路四条只读命令:
374
+
375
+ ```bash
376
+ # 凭据就绪时(CI secret / 本地 export):
377
+ export VVICAT_BASE_URL="https://dev.example.com" # 远端 dev 13002 公网入口
378
+ export VVICAT_ACCESS_TOKEN="<专用测试账号长期令牌>" # CI 加密变量名沿用此约定
379
+ node scripts/smoke-remote.mjs # 真实冒烟
380
+
381
+ # 无凭据 / CI 结构自检:
382
+ node scripts/smoke-remote.mjs --dry-run # 打印命令清单 + 白名单断言
383
+ ```
384
+
385
+ 只读约束:`scripts/smoke-remote.mjs` 命令白名单硬编码为 `preflight --json` / `project list --json` / `canvas node types --json` / `config get --json`,任何写命令(`upload` / `run` / `update`)一律禁入;即使专用测试账号也不放宽(远端是共享 dev 环境,写命令会产生真实数据与费用)。凭据纪律:`token` 只从环境变量读,不入参数/不入 Git/不入日志;脚本输出过滤 token 后再回放到 stdout/stderr。
386
+
182
387
  标准创作中,用户未指定时角色、道具、场景/背景和分镜图统一使用 `16:9`。视频时长以当前模型实时 `durationOptions` 为准;只有实时模型仅提供 5、10、15 秒时,才按镜头目标时长向上取这三档为剪辑保留余量,其他模型不硬编码三档。每批生成后 Agent 必须重新读取任务与资产、核对最终时长在实时合法选项中,并实际检查预览,完成自我审计后才能继续或交付。
183
388
 
184
389
  ```bash
@@ -241,3 +446,64 @@ CLI 与服务端 `/api/v1/bootstrap` 必须就包身份(`name` + `latestVersio
241
446
  - 升级发布流程见 `.github/workflows/cli-publish.yml`(push main 自动 `npm run release -- --verify`)。
242
447
  - 手动 release SOP 见本仓库 `.agents/skills/vvicat-cli-adapter/references/cli-release-sop.md`。
243
448
  - 服务端 `/api/v1/bootstrap` 现暴露 `data.cliDrift` 字段,drift 时返回 `reason` + `manifest` + `npm` 三组对照信息;Agent 进入新环境跑 `config ai-provider capabilities --json` 即可看到。
449
+
450
+ ### 最低兼容版本(minCliVersion · Phase 1.7 SC3 / D-12/D-13)
451
+
452
+ 服务端 `/api/v1/bootstrap` 在 `data.cli.minCliVersion` 下发最低兼容 CLI 版本(Phase 1.7 SC3);当前版本低于该值时 `preflight` **强制升级**,且 `--no-update` 不可跳过。
453
+
454
+ - 声明载体优先级:env `VVICAT_CLI_MIN_VERSION`(紧急回滚通道)> 仓库 `packages/ai_short_studio_cli/cli-min-version.json`(PR 可审查 + 历史可追溯)> 未声明(additive 缺省)。
455
+ - bump 时机与 merge gate 联动(D-13):breaking PR 必须同步 bump;声明 `CLI-Impact: verified-none` 的 PR 无需 bump;`CLI-Impact: deferred` 补适配时随适配 PR bump。
456
+ - 非法 SemVer(env 或文件值都不匹配 `x.y.z`)→ 中文告警后按未声明降级,不静默吞掉,确保运维能从日志发现兜底失效。
457
+
458
+ ## 维护流程
459
+
460
+ 本节描述维护 CLI ↔ 后端契约时必须走的流程与门禁,适用于包维护者与 Agent。
461
+
462
+ ### 1. 契约方向约定(2026-09-29 定)
463
+
464
+ - **`public/api-docs/openapi.json`(OpenAPI spec)是后端契约的唯一事实源。** 它描述后端实际暴露的路由、方法、请求/响应结构。
465
+ - **`packages/ai_short_studio_cli/api-surface.json` 是 CLI 侧的调用声明**,登记 CLI 实际会打的端点(当前 45 条,见下文"消费面清单")。
466
+ - 方向是 **CLI 向 spec 适配**,不是让后端迁就 CLI 的手写清单。`api-surface.json` 不是新的契约来源,它必须随时反映 CLI 源码真实调用点,并与 spec 覆盖关系保持一致(`--require-spec` 校验 spec 覆盖 ⊇ 清单路径集合)。**不得**为了保清单而要求后端保留已废弃路由。
467
+
468
+ ### 2. 后端接口变更 → CLI 适配的 checklist
469
+
470
+ - [ ] **1. 后端改路由/字段 → 先同步更新 `public/api-docs/openapi.json`。** spec 是唯一事实源,spec 未更新等于契约未定义。
471
+ - [ ] **2. CLI 侧调用点变化 → 同步更新 `packages/ai_short_studio_cli/api-surface.json`。** 新增/改名/删除调用端点时,编辑对应条目的 `path` / `httpMethod` / `cliCaller` / `backendFile`(必要时补 `notes`)。CLI 新增一个 API 调用 = 必须新增或修改一条清单条目;**清单失真会让所有下游门禁失真**。
472
+ - [ ] **3. 本地跑门禁**(两条都要过):
473
+ ```bash
474
+ node scripts/guards/cli-api-surface-guard.mjs --json # CLI 源码调用点 ↔ 清单条目双向对账
475
+ node scripts/guards/cli-api-surface-guard.mjs --require-spec # 追加 spec 覆盖 ⊇ 清单路径集合校验
476
+ ```
477
+ 正常输出应显示 `ok: true`、`specCheck.ok: true`、无 `errors`、无 `missing`;对账条数应等于调用点数(当前为 45)。
478
+ - [ ] **4. 破坏性变更需追加 commit trailer 豁免。** 后端变更若触及 CLI 消费面而 CLI 本次未适配,merge gate(`scripts/guards/cli-contract-gate.mjs`)会拦截,需在 commit message 末尾追加:
479
+ - `CLI-Impact: verified-none` —— 声明本次变更不影响 CLI 契约语义,无需 bump `minCliVersion`;
480
+ - `CLI-Impact: deferred` —— 声明需后续补适配,CI 自动开跟踪 issue(凭据缺失时降级为 issue 草稿 artifact);补适配 PR 需同步 bump `minCliVersion`。
481
+ **枚举值与 `.husky/commit-msg` 和 `cli-contract-gate.mjs` 保持同源,合法值只有 `verified-none` 与 `deferred` 两个**(commit-msg 用 `LEGAL_VALUES="verified-none deferred"` 校验,其他值或多余尾随内容 abort)。豁免是可选项:提交不含该 trailer 时 hook 一律放行。**用 trailer 走可审计通道,不要用 `--no-verify` 绕过 hook。**
482
+ - [ ] **5. 破坏性变更还要 bump 最低兼容版本。** 编辑 `packages/ai_short_studio_cli/cli-min-version.json` 的 `minCliVersion`(格式 `x.y.z`;`verified-none` 无需 bump,`deferred` 在补适配 PR bump)。服务端 `/api/v1/bootstrap` 在 `data.cli.minCliVersion` 下发该值,低于它的 CLI 会被 `preflight` 强制升级。
483
+
484
+ ### 3. 端点迁移实例:`/api/assets/upload` 收敛(2026-09-29)
485
+
486
+ 这是"后端收敛后 CLI 必须跟上"的真实案例。
487
+
488
+ - **后端动作**:commit `9a55588c`(asset-core P3 收口,41→16 路由)把 `/api/asset-hub/creative-assets/upload` **合并进** `/api/assets/upload`,并删除旧路由。`/api/assets/upload` 成为资产域 SSOT 的单一上传入口。
489
+ - **CLI 后果**:CLI 的 `canvas asset upload` 当时仍指向旧路径,运行时**必然 404**——但这类"后端已删、CLI 未跟"的漂移不会在编译期暴露,只在真实调用时炸。直到 2026-09-29 才修复。
490
+ - **修复内容**:CLI 改指 `/api/assets/upload`;同时补上 `kind` 参数。后端按 `kind` 分发资产域——`voice` → `GlobalVoice`,`image` / `video` / `audio` → `GlobalCreativeAsset`;`kind=voice` **仅接受音频**(CLI 本地先拦截,避免发必然 400 的请求)。清单中 `assets-upload` 条目的 `notes` 已记录本次迁移与契约要点。
491
+ - **教训**:后端合并/删除端点时,必须同步 grep CLI 是否有调用点(本例通过 `cli-api-surface-guard` 对账发现并修复)。**只要 api-surface 中登记的路径被后端删改,就必须走上面的完整 checklist 重新对账。**
492
+
493
+ ### 4. 新增/废弃 CLI 命令的登记义务
494
+
495
+ - **新增一个会打后端 API 的 CLI 命令** → 必须在 `api-surface.json` 增一条登记(`path` / `httpMethod` / `cliCaller` / `backendFile`),否则 `cli-api-surface-guard` 的双向对账会报"清单缺失调用点"。
496
+ - **废弃/下线一个 CLI 命令** → 必须**同步从 `api-surface.json` 移除对应条目**。若命令已下线但清单条目仍在,门禁会因"清单条目陈旧"(源码已无对应调用点)报错。移除清单条目同样要跑 `node scripts/guards/cli-api-surface-guard.mjs --json` 确认对账通过。
497
+ - 纯本地命令(如 `skill *`、`preflight` 之外的若干不涉及 API 的辅助命令)不进清单;`preflight` 的 `/api/v1/bootstrap` 与 `/api/auth/session` 已单独登记。
498
+
499
+ ### 消费面清单(`api-surface.json`)
500
+
501
+ `api-surface.json` 当前登记 45 条 CLI 消费端点,字段含义:
502
+
503
+ - `id` —— 稳定条目 ID;
504
+ - `path` —— 端点路径(动态段用 `{param}` 占位,查询串已剥离);
505
+ - `httpMethod` —— HTTP 方法;
506
+ - `cliCaller` —— CLI 侧调用点(API 方法名或命令);
507
+ - `backendFile` —— 后端实现文件;
508
+ - `deadEndpoint` —— 标记后端已删、运行时必 404 的死端点(spec/T1/冒烟排除;当前为 0 条);
509
+ - `notes` —— 契约要点与迁移备注。
@@ -1,11 +1,24 @@
1
1
  import { BaseCommand } from '../../../base-command.js';
2
+ /**
3
+ * 后端 `/api/assets/upload` 按 `kind` 分发资产域:
4
+ * image / video / audio → GlobalCreativeAsset;voice → GlobalVoice。
5
+ * 允许的取值以 src/lib/asset-core/media-view/types.ts 的 kind 域为准。
6
+ */
7
+ export declare const UPLOAD_KINDS: readonly ["image", "video", "audio", "voice"];
8
+ export type UploadKind = (typeof UPLOAD_KINDS)[number];
2
9
  export declare function mimeTypeForUpload(filename: string): string;
10
+ /**
11
+ * 由扩展名推断 `kind`;无法识别时返回 null 交由调用方显式传 --kind,
12
+ * 避免把未知文件静默送进错误资产域(后端不校验 kind 与实际内容是否一致)。
13
+ */
14
+ export declare function kindForUpload(filename: string): UploadKind | null;
3
15
  export default class CanvasAssetUpload extends BaseCommand {
4
16
  static args: {
5
17
  file: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
18
  };
7
19
  static flags: {
8
20
  project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
21
+ kind: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
22
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
23
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
24
  locale: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
@@ -1,6 +1,6 @@
1
1
  import { basename, extname } from 'node:path';
2
2
  import { readFile } from 'node:fs/promises';
3
- import { Args } from '@oclif/core';
3
+ import { Args, Flags } from '@oclif/core';
4
4
  import { BaseCommand } from '../../../base-command.js';
5
5
  import { commandApi, projectFlag } from '../../../command-helpers.js';
6
6
  const MIME_BY_EXTENSION = {
@@ -18,11 +18,51 @@ const MIME_BY_EXTENSION = {
18
18
  '.aac': 'audio/aac',
19
19
  '.ogg': 'audio/ogg',
20
20
  };
21
+ /**
22
+ * 后端 `/api/assets/upload` 按 `kind` 分发资产域:
23
+ * image / video / audio → GlobalCreativeAsset;voice → GlobalVoice。
24
+ * 允许的取值以 src/lib/asset-core/media-view/types.ts 的 kind 域为准。
25
+ */
26
+ export const UPLOAD_KINDS = ['image', 'video', 'audio', 'voice'];
27
+ const EXTENSION_KIND = {
28
+ '.png': 'image', '.jpg': 'image', '.jpeg': 'image', '.webp': 'image', '.gif': 'image',
29
+ '.mp4': 'video', '.mov': 'video', '.webm': 'video',
30
+ '.mp3': 'audio', '.wav': 'audio', '.m4a': 'audio', '.aac': 'audio', '.ogg': 'audio',
31
+ };
21
32
  export function mimeTypeForUpload(filename) {
22
33
  return MIME_BY_EXTENSION[extname(filename).toLowerCase()] || 'application/octet-stream';
23
34
  }
35
+ /**
36
+ * 由扩展名推断 `kind`;无法识别时返回 null 交由调用方显式传 --kind,
37
+ * 避免把未知文件静默送进错误资产域(后端不校验 kind 与实际内容是否一致)。
38
+ */
39
+ export function kindForUpload(filename) {
40
+ return EXTENSION_KIND[extname(filename).toLowerCase()] ?? null;
41
+ }
24
42
  export default class CanvasAssetUpload extends BaseCommand {
25
43
  static args = { file: Args.string({ required: true }) };
26
- static flags = { ...BaseCommand.baseFlags, project: projectFlag };
27
- async run() { const { args, flags } = await this.parse(CanvasAssetUpload); const bytes = await readFile(args.file); const form = new FormData(); form.set('file', new Blob([bytes], { type: mimeTypeForUpload(args.file) }), basename(args.file)); const { api } = await commandApi(flags); this.print(await api.uploadAsset(flags.project, form)); }
44
+ static flags = {
45
+ ...BaseCommand.baseFlags,
46
+ project: projectFlag,
47
+ kind: Flags.string({ options: [...UPLOAD_KINDS], help: '资产类型;缺省按文件扩展名推断,无法识别时报错退出' }),
48
+ };
49
+ async run() {
50
+ const { args, flags } = await this.parse(CanvasAssetUpload);
51
+ const bytes = await readFile(args.file);
52
+ const kind = flags.kind ?? kindForUpload(args.file);
53
+ if (!kind) {
54
+ this.error(`无法从文件名推断资产类型(${basename(args.file)}),请显式传 --kind <${UPLOAD_KINDS.join('|')}>`);
55
+ }
56
+ const form = new FormData();
57
+ const mime = mimeTypeForUpload(args.file);
58
+ // 后端 kind=voice 分支只接受音频(route.ts:93 isAudioFile),本地先拦一道给出可读错误,
59
+ // 避免把必然 400 的请求发出去。
60
+ if (kind === 'voice' && !mime.startsWith('audio/')) {
61
+ this.error(`--kind voice 仅支持音频文件,当前文件类型为 ${mime}`);
62
+ }
63
+ form.set('file', new Blob([bytes], { type: mime }), basename(args.file));
64
+ form.set('kind', kind);
65
+ const { api } = await commandApi(flags);
66
+ this.print(await api.uploadAsset(flags.project, form));
67
+ }
28
68
  }
@@ -18,7 +18,15 @@ export default class Preflight extends BaseCommand {
18
18
  const bootstrap = await fetchBootstrap(baseUrl);
19
19
  const current = await readCurrentPackageIdentity();
20
20
  const hasUpdate = compareStableVersions(current.version, bootstrap.cli.latestVersion) < 0;
21
- const version = flags.update
21
+ // 服务端声明的最低兼容版本(Phase 1.7 SC3 / D-12/D-13)。
22
+ // 低于该版本即说明当前 CLI 与服务端契约不兼容 —— 强制升级(不可跳过,
23
+ // 与 hasUpdate 的软提示本质不同)。bump 时机由 cli-contract-gate 与
24
+ // CLI-Impact trailer 联动控制(verified-none 无需 bump;deferred 补
25
+ // 适配时随适配 PR bump)。
26
+ const minimum = bootstrap.cli.minCliVersion;
27
+ const forcedUpdate = minimum !== undefined && compareStableVersions(current.version, minimum) < 0;
28
+ const shouldUpdate = flags.update || forcedUpdate;
29
+ const version = shouldUpdate
22
30
  ? updateCliPackage({ current, latest: bootstrap.cli })
23
31
  : {
24
32
  updated: false,
@@ -135,6 +135,18 @@ export declare class VvicatApi {
135
135
  listAssets(projectId: string, query?: string): Promise<JsonObject>;
136
136
  asset(projectId: string, assetId: string): Promise<JsonObject>;
137
137
  selectAssetVersion(projectId: string, assetId: string, versionId: string): Promise<JsonObject>;
138
+ /**
139
+ * 画布资产上传 —— 端点为 `/api/assets/upload`(资产域 SSOT 单一入口)。
140
+ *
141
+ * 迁移背景:原 `/api/asset-hub/creative-assets/upload` 已由后端 commit 9a55588c
142
+ * (asset-core P3 收口,41 路由 → 16 路由)合并进 `/api/assets/upload` 并删除。
143
+ * 此前 CLI 侧留有「Phase C 再迁移」的注释,其前提(旧路由仍在)已失效,运行时必 404。
144
+ *
145
+ * 契约要点(见 src/app/api/assets/upload/route.ts 头部注释):后端按 `kind` 分发到
146
+ * 不同资产域——voice → GlobalVoice,image/video/audio → GlobalCreativeAsset;
147
+ * 若要写入既有形象/场景图则用 `target=appearance|image` + `id`。此处保持「新建画布资产」
148
+ * 语义,故要求调用方提供 `kind`。
149
+ */
138
150
  uploadAsset(projectId: string, formData: FormData): Promise<JsonObject>;
139
151
  task(taskId: string): Promise<{
140
152
  task: JsonObject & {
@@ -316,16 +316,21 @@ export class VvicatApi {
316
316
  method: 'PATCH', body: { selectedVersionId: versionId },
317
317
  });
318
318
  }
319
+ /**
320
+ * 画布资产上传 —— 端点为 `/api/assets/upload`(资产域 SSOT 单一入口)。
321
+ *
322
+ * 迁移背景:原 `/api/asset-hub/creative-assets/upload` 已由后端 commit 9a55588c
323
+ * (asset-core P3 收口,41 路由 → 16 路由)合并进 `/api/assets/upload` 并删除。
324
+ * 此前 CLI 侧留有「Phase C 再迁移」的注释,其前提(旧路由仍在)已失效,运行时必 404。
325
+ *
326
+ * 契约要点(见 src/app/api/assets/upload/route.ts 头部注释):后端按 `kind` 分发到
327
+ * 不同资产域——voice → GlobalVoice,image/video/audio → GlobalCreativeAsset;
328
+ * 若要写入既有形象/场景图则用 `target=appearance|image` + `id`。此处保持「新建画布资产」
329
+ * 语义,故要求调用方提供 `kind`。
330
+ */
319
331
  uploadAsset(projectId, formData) {
320
332
  formData.set('sourceProjectId', projectId);
321
- // 🛡️ Phase 1.1 (asset-ssot SSOT): the upstream `/api/asset-hub/creative-assets/upload`
322
- // route is intentionally preserved here — it is route #25 (complex; Project +
323
- // CanvasFolder + CanvasEpisode cascade-delete semantics) and is scheduled for
324
- // Phase C migration, not Phase 1.1. The Phase 1.1 deletions only target
325
- // already-migrated trivial routes (generate-image / modify-image /
326
- // select-image / undo-image / update-asset-label) and read-side GETs.
327
- // See docs/asset-management-api-matrix.md (Phase 1.1 section).
328
- return this.client.request('/api/asset-hub/creative-assets/upload', { method: 'POST', body: formData });
333
+ return this.client.request('/api/assets/upload', { method: 'POST', body: formData });
329
334
  }
330
335
  task(taskId) {
331
336
  return this.client.request(`/api/tasks/${taskId}`);
@@ -2,6 +2,7 @@ export interface BootstrapConfig {
2
2
  cli: {
3
3
  packageName: string;
4
4
  latestVersion: string;
5
+ minCliVersion?: string;
5
6
  };
6
7
  supabase: {
7
8
  url: string;
package/dist/preflight.js CHANGED
@@ -44,7 +44,11 @@ export async function fetchBootstrap(baseUrl, fetcher = fetch) {
44
44
  throw new Error('VVICAT 服务返回的 bootstrap 配置无效');
45
45
  compareStableVersions(cli.latestVersion, cli.latestVersion);
46
46
  return {
47
- cli: { packageName: cli.packageName, latestVersion: cli.latestVersion },
47
+ cli: {
48
+ packageName: cli.packageName,
49
+ latestVersion: cli.latestVersion,
50
+ ...(typeof cli.minCliVersion === 'string' ? { minCliVersion: cli.minCliVersion } : {}),
51
+ },
48
52
  supabase: { url: supabase.url, publishableKey: supabase.publishableKey },
49
53
  };
50
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aswless_854771076/ai_short_studio_cli",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
4
4
  "description": "VVICAT 无限画布项目命令行工具",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -33,11 +33,12 @@
33
33
  "prepack": "npm run build",
34
34
  "release:dry-run": "node scripts/publish.mjs --dry-run",
35
35
  "release:test": "node scripts/publish.mjs --name @aswless_854771076/ai_short_studio_cli --tag beta",
36
- "release:ci:test": "npm test && npm run typecheck && node scripts/publish.mjs --name @aswless_854771076/ai_short_studio_cli --tag beta --verify",
37
- "release:ci": "npm test && npm run typecheck && node scripts/publish.mjs --tag latest --verify",
36
+ "release:ci:test": "npm test && npm run typecheck && node scripts/publish.mjs --name @aswless_854771076/ai_short_studio_cli --tag beta --verify && node scripts/smoke-remote.mjs",
37
+ "release:ci": "npm test && npm run typecheck && node scripts/publish.mjs --tag latest --verify && node scripts/smoke-remote.mjs",
38
38
  "release": "node scripts/publish.mjs --tag latest",
39
39
  "test": "vitest run",
40
40
  "test:local-e2e": "npm run build && node scripts/local-e2e.mjs",
41
+ "test:smoke": "node scripts/smoke-remote.mjs",
41
42
  "typecheck": "tsc -p tsconfig.json --noEmit"
42
43
  },
43
44
  "dependencies": {