@aswless_854771076/ai_short_studio_cli 0.1.63 → 0.1.65

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.
Files changed (36) hide show
  1. package/README.md +35 -2
  2. package/dist/client/api-client.js +19 -2
  3. package/dist/commands/canvas/asset/select.d.ts +2 -1
  4. package/dist/commands/canvas/asset/select.js +22 -3
  5. package/dist/commands/canvas/edge/list.js +4 -1
  6. package/dist/commands/canvas/node/list.d.ts +4 -0
  7. package/dist/commands/canvas/node/list.js +43 -2
  8. package/dist/commands/canvas/node/run.d.ts +3 -0
  9. package/dist/commands/canvas/node/run.js +103 -5
  10. package/dist/commands/config/ai-provider/capabilities.d.ts +26 -0
  11. package/dist/commands/config/ai-provider/capabilities.js +90 -0
  12. package/dist/commands/config/ai-provider/get.d.ts +21 -0
  13. package/dist/commands/config/ai-provider/get.js +21 -0
  14. package/dist/commands/config/ai-provider/list.d.ts +20 -0
  15. package/dist/commands/config/ai-provider/list.js +19 -0
  16. package/dist/commands/config/ai-provider/models.d.ts +21 -0
  17. package/dist/commands/config/ai-provider/models.js +21 -0
  18. package/dist/commands/config/ai-provider/set.d.ts +40 -0
  19. package/dist/commands/config/ai-provider/set.js +65 -0
  20. package/dist/commands/config/ai-provider/test.d.ts +24 -0
  21. package/dist/commands/config/ai-provider/test.js +24 -0
  22. package/dist/commands/config/set.d.ts +1 -0
  23. package/dist/commands/config/set.js +55 -2
  24. package/dist/commands/task/wait.d.ts +1 -0
  25. package/dist/commands/task/wait.js +6 -1
  26. package/dist/domain/ai-provider-capabilities.d.ts +109 -0
  27. package/dist/domain/ai-provider-capabilities.js +180 -0
  28. package/dist/domain/ai-provider-command-helpers.d.ts +27 -0
  29. package/dist/domain/ai-provider-command-helpers.js +55 -0
  30. package/dist/domain/vvicat-api.d.ts +42 -2
  31. package/dist/domain/vvicat-api.js +56 -3
  32. package/dist/preflight.js +9 -0
  33. package/package.json +1 -1
  34. package/skills/using-vvicat-ai-short-studio-cli/SKILL.md +15 -1
  35. package/skills/using-vvicat-ai-short-studio-cli/references/commands/project.md +20 -1
  36. package/skills/using-vvicat-ai-short-studio-cli/references/project-and-canvas.md +1 -1
@@ -19,6 +19,11 @@ interface CanvasDto extends JsonObject {
19
19
  edges: JsonObject[];
20
20
  nodeTypesByVersionId?: Record<string, NodeType>;
21
21
  }
22
+ interface CanvasNodeRunResponse extends JsonObject {
23
+ task: JsonObject & {
24
+ id?: string;
25
+ };
26
+ }
22
27
  interface NodeType extends JsonObject {
23
28
  kind: string;
24
29
  title: string;
@@ -126,7 +131,7 @@ export declare class VvicatApi {
126
131
  targetHandle: string;
127
132
  }): Promise<JsonObject>;
128
133
  disconnect(projectId: string, edgeId: string): Promise<JsonObject>;
129
- runNode(projectId: string, nodeId: string): Promise<JsonObject>;
134
+ runNode(projectId: string, nodeId: string): Promise<CanvasNodeRunResponse>;
130
135
  listAssets(projectId: string, query?: string): Promise<JsonObject>;
131
136
  asset(projectId: string, assetId: string): Promise<JsonObject>;
132
137
  selectAssetVersion(projectId: string, assetId: string, versionId: string): Promise<JsonObject>;
@@ -137,11 +142,46 @@ export declare class VvicatApi {
137
142
  };
138
143
  }>;
139
144
  cancelTask(taskId: string): Promise<JsonObject>;
140
- waitTask(taskId: string, interval?: number): Promise<JsonObject & {
145
+ waitTask(taskId: string, interval?: number, options?: {
146
+ maxWaitMs?: number;
147
+ signal?: AbortSignal;
148
+ }): Promise<JsonObject & {
141
149
  status: string;
142
150
  }>;
143
151
  config(): Promise<JsonObject>;
144
152
  updateConfig(input: JsonObject): Promise<JsonObject>;
153
+ listAiProviders(): Promise<{
154
+ items: JsonObject[];
155
+ total: number;
156
+ }>;
157
+ getAiProvider(providerId: string): Promise<{
158
+ item: JsonObject;
159
+ }>;
160
+ createAiProvider(input: JsonObject): Promise<{
161
+ item: JsonObject;
162
+ }>;
163
+ updateAiProvider(providerId: string, input: JsonObject): Promise<{
164
+ item: JsonObject;
165
+ }>;
166
+ testAiProvider(providerId: string): Promise<JsonObject>;
167
+ fetchAiProviderModels(providerId: string): Promise<{
168
+ item: {
169
+ providerId: string;
170
+ upstreamModelsSyncedAt: string | null;
171
+ models: JsonObject[];
172
+ };
173
+ }>;
174
+ clearAiProviderSecret(providerId: string): Promise<{
175
+ success: boolean;
176
+ }>;
177
+ seedAiProviderFromPreset(presetType: string, options?: {
178
+ baseUrl?: string;
179
+ apiKey?: string;
180
+ sortOrder?: number;
181
+ }): Promise<{
182
+ item: JsonObject;
183
+ preset: JsonObject;
184
+ }>;
145
185
  raw(path: string, options?: ApiRequestOptions): Promise<unknown>;
146
186
  }
147
187
  export {};
@@ -318,6 +318,13 @@ export class VvicatApi {
318
318
  }
319
319
  uploadAsset(projectId, formData) {
320
320
  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).
321
328
  return this.client.request('/api/asset-hub/creative-assets/upload', { method: 'POST', body: formData });
322
329
  }
323
330
  task(taskId) {
@@ -327,11 +334,26 @@ export class VvicatApi {
327
334
  cancelTask(taskId) {
328
335
  return this.client.request(`/api/tasks/${taskId}`, { method: 'DELETE' });
329
336
  }
330
- async waitTask(taskId, interval = 1_000) {
337
+ // waitTask 只负责轮询,不做任何重试 / cancel 决策。retry 与 cancel 由调用方
338
+ // (canvas node run)根据 task.error?.retryable / task.attempt 自行决定。
339
+ async waitTask(taskId, interval = 1_000, options = {}) {
340
+ const maxWaitMs = options.maxWaitMs ?? Number.POSITIVE_INFINITY;
341
+ const startedAt = Date.now();
331
342
  while (true) {
343
+ if (options.signal?.aborted) {
344
+ throw new Error('wait aborted');
345
+ }
332
346
  const { task } = await this.task(taskId);
333
347
  if (['completed', 'failed', 'canceled', 'dismissed'].includes(task.status))
334
348
  return task;
349
+ const elapsed = Date.now() - startedAt;
350
+ if (elapsed >= maxWaitMs) {
351
+ // 抛出时附带最新 task 状态,让调用方(canvas node run)可以决定是
352
+ // cancel 后重试还是直接退出。
353
+ const err = new Error(`wait timeout after ${maxWaitMs}ms`);
354
+ Object.assign(err, { taskId, status: task.status, attempt: task.attempt });
355
+ throw err;
356
+ }
335
357
  await this.sleep(interval);
336
358
  }
337
359
  }
@@ -340,10 +362,41 @@ export class VvicatApi {
340
362
  return this.client.request('/api/user/api-config?redactSecrets=1');
341
363
  }
342
364
  updateConfig(input) {
343
- if (Object.hasOwn(input, 'providers') || Object.hasOwn(input, 'models'))
344
- throw new Error('供应商和模型目录只能由管理员维护');
365
+ if (Object.hasOwn(input, 'providers') || Object.hasOwn(input, 'models') || Object.hasOwn(input, 'workflowConcurrency')) {
366
+ throw new Error('供应商、模型目录和工作流并发只能由管理员维护');
367
+ }
345
368
  return this.client.request('/api/user/api-config', { method: 'PUT', body: input });
346
369
  }
370
+ // ===== admin AI provider commands(服务端 requireAdminAuth)=====
371
+ // 仓库级供应商目录(不是用户私有配置)。
372
+ // agent 用这些方法查询当前可用的 provider / model,再决定任务里用哪个 modelKey。
373
+ listAiProviders() {
374
+ return this.client.request('/api/admin/ai-providers');
375
+ }
376
+ getAiProvider(providerId) {
377
+ return this.client.request(`/api/admin/ai-providers/${providerId}`);
378
+ }
379
+ createAiProvider(input) {
380
+ return this.client.request('/api/admin/ai-providers', { method: 'POST', body: input });
381
+ }
382
+ updateAiProvider(providerId, input) {
383
+ return this.client.request(`/api/admin/ai-providers/${providerId}`, { method: 'PATCH', body: input });
384
+ }
385
+ testAiProvider(providerId) {
386
+ return this.client.request(`/api/admin/ai-providers/${providerId}/test`, { method: 'POST' });
387
+ }
388
+ fetchAiProviderModels(providerId) {
389
+ return this.client.request(`/api/admin/ai-providers/${providerId}/fetch-models`, { method: 'POST' });
390
+ }
391
+ clearAiProviderSecret(providerId) {
392
+ return this.client.request(`/api/admin/ai-providers/${providerId}/secret`, { method: 'DELETE' });
393
+ }
394
+ seedAiProviderFromPreset(presetType, options = {}) {
395
+ return this.client.request('/api/admin/ai-providers/seed-from-preset', {
396
+ method: 'POST',
397
+ body: { presetType, options },
398
+ });
399
+ }
347
400
  raw(path, options) {
348
401
  return this.client.request(path, options);
349
402
  }
package/dist/preflight.js CHANGED
@@ -18,9 +18,18 @@ export async function fetchBootstrap(baseUrl, fetcher = fetch) {
18
18
  });
19
19
  }
20
20
  catch {
21
+ // root cause: undici fetch close + @napi-rs/keyring handle race;
22
+ // setImmediate alone not enough, need real delay.
23
+ //
24
+ // 让 fetch 内部句柄先收尾再 throw,避免在 @napi-rs/keyring 仍持有句柄时立刻
25
+ // 关闭 libuv handle 导致 Windows 上 `UV_HANDLE_CLOSING assertion failed`。
26
+ // Node 21+ 配合 undici 的 fetch 实现,未 sleep 真实时间就 throw 会让
27
+ // 尚未 close 的 handle 留给 GC,最终触发崩溃(退出码 3221226505)。
28
+ await new Promise((resolve) => setTimeout(resolve, 50));
21
29
  throw new Error(`无法连接 VVICAT 服务,请检查 API base URL:${normalizedBaseUrl}`);
22
30
  }
23
31
  if (!response.ok) {
32
+ await new Promise((resolve) => setTimeout(resolve, 50));
24
33
  throw new Error(`VVICAT 服务预检失败:HTTP ${response.status};请检查 API base URL:${normalizedBaseUrl}`);
25
34
  }
26
35
  const payload = await response.json().catch(() => null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aswless_854771076/ai_short_studio_cli",
3
- "version": "0.1.63",
3
+ "version": "0.1.65",
4
4
  "description": "VVICAT 无限画布项目命令行工具",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -3,6 +3,20 @@ name: using-vvicat-ai-short-studio-cli
3
3
  description: Use when an agent needs to inspect or operate VVICAT infinite-canvas projects through the ai-short-studio CLI, including assets, storyboard-to-video rolling generation, task recovery, editing, captions, audio balancing, and final delivery.
4
4
  ---
5
5
 
6
+ <!-- 🛡️ 2026-09-05 asset-ssot Phase 1.1 sync note: 5 trivial `/api/asset-hub/*` routes deleted
7
+ (generate-image / modify-image / select-image / undo-image / update-asset-label) and 5 GET
8
+ handlers removed from multi-method routes. CLI does not call these endpoints directly.
9
+ `/api/asset-hub/creative-assets/upload` (route #25, complex) is preserved and still used by
10
+ `uploadAsset` in `src/domain/vvicat-api.ts`. See `docs/asset-management-api-matrix.md` Phase 1.1. -->
11
+
12
+
13
+ <!-- 🛡️ 2026-09-06 cli-backend-sync Layer 1+2: 服务器 bootstrap 现暴露
14
+ data.cliDrift 字段;packages/ai_short_studio_cli/package.json 的 name 字段被
15
+ pre-commit guard 锁定为 @aswless_854771076/ai_short_studio_cli。Agent 升级 CLI
16
+ 前请跑 `config ai-provider capabilities` 看是否有 cliDrift;如有,按
17
+ data.cliDrift.reason (PACKAGE_NAME_DRIFT / VERSION_DRIFT) 走对应修复路径。
18
+ 详见本仓库 .agents/skills/vvicat-cli-adapter/SKILL.md §3.1。 -->
19
+
6
20
  # 使用 VVICAT AI Short Studio CLI
7
21
 
8
22
  ## 按需读取
@@ -22,7 +36,7 @@ description: Use when an agent needs to inspect or operate VVICAT infinite-canva
22
36
 
23
37
  把 `ai-short-studio` 当作机器可读的远程控制接口。目标、素材含义、平台、语言、画幅、时长、风格、人物、场景、道具、模型、实时 schema、候选版本、付费范围或覆盖影响存在未知、缺失或矛盾时,合并询问最少必要问题;得到答复前只做只读检查。不得用示例值替用户作创作决定。
24
38
 
25
- 优先使用一次 `canvas inspect` 聚合查询。同阶段可合并的 settings、节点和连线分别使用 `canvas settings set --file`、`canvas apply`、`canvas node update-many`。生成链使用单个调度循环滚动提交,不用 `--wait` 把整批阶段串行化:节点一完成就刷新画布并立即提交它已就绪的下游节点。默认每类并发 4、总并发上限 16;同一节点同一输入指纹只允许一个在途任务,不并发启动多个相互竞争的调度器。409 重读并确认,401/403、schema、业务门禁和付费错误必须停下修正。
39
+ 优先使用一次 `canvas inspect` 聚合查询。同阶段可合并的 settings、节点和连线分别使用 `canvas settings set --file`、`canvas apply`、`canvas node update-many`。生成链使用单个调度循环滚动提交,不用 `--wait` 把整批阶段串行化:节点一完成就刷新画布并立即提交它已就绪的下游节点。默认每类并发 4、总并发上限 16;同一节点同一输入指纹只允许一个在途任务,不并发启动多个相互竞争的调度器。409 重读并确认,401/403、schema、业务门禁和付费错误必须停下修正;`MODEL_PRICING_NOT_CONFIGURED` 表示当前能力参数没有已发布价格档位,不能盲目重试。
26
40
 
27
41
  ## 主流程
28
42
 
@@ -62,4 +62,23 @@ ai-short-studio config get --json
62
62
  ai-short-studio config set --file config.json --json
63
63
  ```
64
64
 
65
- `config set` 只接受个人默认模型、能力默认值和并发;供应商、密钥与全局模型目录只能由管理员维护。
65
+ `config set` 只接受个人默认模型和能力默认值;供应商、密钥、全局模型目录与工作流并发只能由管理员维护。
66
+
67
+ ## 管理员 AI Provider
68
+
69
+ 仅管理员账号可用。Agent 在排查"我能不能用这个 provider / 还缺什么配置"时,先跑 `config ai-provider capabilities`,再决定后续命令。
70
+
71
+ ```bash
72
+ ai-short-studio config ai-provider list --json
73
+ ai-short-studio config ai-provider get --id <providerId> --json
74
+ ai-short-studio config ai-provider set --id <providerId> [--base-url <url>] [--api-key-stdin] [--enabled true|false] [--preset <name>] [--json]
75
+ ai-short-studio config ai-provider test --id <providerId> --json
76
+ ai-short-studio config ai-provider models --id <providerId> --json
77
+ ai-short-studio config ai-provider capabilities --json
78
+ ```
79
+
80
+ - `--api-key-stdin` 从隐藏 stdin 读取;CI 用 `VVICAT_AI_PROVIDER_<ID>_API_KEY` 注入。
81
+ - `--preset <name>` 触发服务端 Preset(如 `openai-compatible`、`runninghub`、`comfly`)一键种子。
82
+ - `test` 不消耗 token,只报告 HTTP/延迟;`models` 仅在 `enabled` 且最近 `test` 成功时返回。
83
+ - `capabilities` 报告当前生效的私有/LAN baseUrl 白名单(环境变量 `VVICAT_ALLOW_PRIVATE_PROVIDER_BASE_URLS`,CSV `host:port`)、已注册 Provider、缺失项与诊断。
84
+ - 私有/LAN baseUrl(如本地 ComfyUI `http://127.0.0.1:8188`、`http://192.168.3.30:8188`)需要在 Next.js 运行环境里设置 `VVICAT_ALLOW_PRIVATE_PROVIDER_BASE_URLS` 显式打开;公网 URL 仍强制 HTTPS 与公网 IP。
@@ -5,7 +5,7 @@
5
5
  ## 初始化和配置
6
6
 
7
7
  1. `preflight --json` 检查地址、CLI 版本、认证和标准能力;`restartRequired` 为真时重跑。仅缺可确定的账户 `capabilityDefaults` 时,从实时 options、目标项目有效值或模型默认值补齐并回读;模型不可用或候选缺失时停下询问。
8
- 2. `config get` 只管理个人默认模型、能力默认值和工作流并发。供应商、密钥和全局模型目录由管理员维护。
8
+ 2. `config get` 展示个人默认模型、能力默认值和管理员下发的工作流并发;`config set` 只能修改前两项。供应商、密钥、全局模型目录和工作流并发由管理员维护。
9
9
  3. 新项目按“确认名称/用途 → `project create` → `project get` + 一次 `canvas inspect`”执行;既有项目先聚合读取。项目配置回读通过前不得创建创作节点。
10
10
  4. `canvas settings get` 必须确认项目覆盖值、继承后的有效值、来源和实时候选。默认推荐 `storyboardImageType: grid`;`visualBible` 按实时 schema 构造。`outputLanguage` 必须与用户确认的交付语言一致;“自动”只适合用户明确要求跟随输入且源剧本语言单一的普通拆镜。CLI `--locale` 只影响命令界面和输出消息,不代表内容语言。
11
11
  5. `imageResolution`、`imageQuality`、`videoResolution` 优先由项目统一设置;节点只有确需不同且实时能力允许时才覆盖。H3 模型必须与 `videoPromptType: "h3"` 同次写入。