beervid-app-cli 0.2.3 → 0.2.5

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 (38) hide show
  1. package/README.md +57 -1
  2. package/dist/cli.mjs +84 -65
  3. package/package.json +2 -4
  4. package/skills/beervid-app-cli/SKILL.md +318 -0
  5. package/skills/beervid-app-cli/docs/database-schema.md +231 -0
  6. package/skills/beervid-app-cli/docs/oauth-callback.md +282 -0
  7. package/skills/beervid-app-cli/docs/retry-and-idempotency.md +295 -0
  8. package/skills/beervid-app-cli/docs/tt-poll-task.md +239 -0
  9. package/skills/beervid-app-cli/docs/tts-product-cache.md +256 -0
  10. package/skills/beervid-app-cli/example/express/README.md +58 -0
  11. package/skills/beervid-app-cli/example/express/package.json +20 -0
  12. package/skills/beervid-app-cli/example/express/server.ts +431 -0
  13. package/skills/beervid-app-cli/example/express/tsconfig.json +12 -0
  14. package/skills/beervid-app-cli/example/nextjs/.env.example +3 -0
  15. package/skills/beervid-app-cli/example/nextjs/README.md +54 -0
  16. package/skills/beervid-app-cli/example/nextjs/app/api/oauth/callback/route.ts +34 -0
  17. package/skills/beervid-app-cli/example/nextjs/app/api/oauth/url/route.ts +30 -0
  18. package/skills/beervid-app-cli/example/nextjs/app/api/products/route.ts +43 -0
  19. package/skills/beervid-app-cli/example/nextjs/app/api/publish/tt/route.ts +116 -0
  20. package/skills/beervid-app-cli/example/nextjs/app/api/publish/tts/route.ts +58 -0
  21. package/skills/beervid-app-cli/example/nextjs/app/api/status/[shareId]/route.ts +41 -0
  22. package/skills/beervid-app-cli/example/nextjs/app/layout.tsx +9 -0
  23. package/skills/beervid-app-cli/example/nextjs/app/page.tsx +80 -0
  24. package/skills/beervid-app-cli/example/nextjs/lib/beervid-client.ts +107 -0
  25. package/skills/beervid-app-cli/example/nextjs/next.config.ts +4 -0
  26. package/skills/beervid-app-cli/example/nextjs/package.json +19 -0
  27. package/skills/beervid-app-cli/example/nextjs/tsconfig.json +23 -0
  28. package/skills/beervid-app-cli/example/standard/README.md +51 -0
  29. package/skills/beervid-app-cli/example/standard/api-client.ts +181 -0
  30. package/skills/beervid-app-cli/example/standard/get-oauth-url.ts +44 -0
  31. package/skills/beervid-app-cli/example/standard/package.json +18 -0
  32. package/skills/beervid-app-cli/example/standard/query-products.ts +141 -0
  33. package/skills/beervid-app-cli/example/standard/tsconfig.json +12 -0
  34. package/skills/beervid-app-cli/example/standard/tt-publish-flow.ts +194 -0
  35. package/skills/beervid-app-cli/example/standard/tts-publish-flow.ts +246 -0
  36. package/SKILL.md +0 -486
  37. package/agents/openai.yaml +0 -7
  38. /package/{references → skills/beervid-app-cli/references}/api-reference.md +0 -0
package/README.md CHANGED
@@ -30,6 +30,40 @@ node dist/cli.mjs --help
30
30
  node dist/cli.mjs config --show
31
31
  ```
32
32
 
33
+ ### 在 Claude Code / Codex / Antigravity 中使用(以下说明面向 AI Agent)
34
+
35
+ #### 方式一:通过 `npx skills add` 安装(推荐)
36
+
37
+ ```bash
38
+ npx skills add Lupeiwen0/beervid-app-cli
39
+ ```
40
+
41
+ 安装后 Skill 会自动注册到你的 skills 目录中,Claude Code 等 Agent 即可发现和调用。
42
+
43
+ #### 方式二:手动安装
44
+
45
+ 如果你是 Claude Code、Codex、Antigravity,或任何支持 Skill 的 AI Agent,请严格按下面规则执行:
46
+
47
+ - 用户把 GitHub 仓库链接发给你,**不等于**这个 Skill 已经安装到你的 skills 目录中。
48
+ - 只有当 `skills/beervid-app-cli/` 目录被完整安装到你的 skills 目录后,才算这个 Skill 可用。
49
+
50
+ 你必须先把以下目录复制到你自己的 skills 目录中:
51
+
52
+ ```text
53
+ skills/beervid-app-cli/
54
+ SKILL.md
55
+ references/
56
+ docs/
57
+ example/
58
+ ```
59
+
60
+ 安装完成后,你应从 skills 目录中的 `SKILL.md` 加载本 Skill,而不是只读取仓库根目录里的 `README.md` 或 `package.json`。
61
+
62
+ 对 AI Agent 来说,应这样区分:
63
+
64
+ - 目标是使用 CLI:安装 npm 包即可。
65
+ - 目标是使用 Skill:必须额外安装 Skill 文件;仓库链接本身不完成这一步。
66
+
33
67
  ## 配置
34
68
 
35
69
  ```bash
@@ -83,4 +117,26 @@ beervid publish-tts-flow --creator-id open_user_abc --file ./video.mp4 --interac
83
117
  beervid publish-tts-flow --creator-id open_user_abc --file ./video.mp4 --product-id prod_123 --product-title "Widget"
84
118
  ```
85
119
 
86
- 详细用法见 [SKILL.md](./SKILL.md)。完整 API 参考见 [references/api-reference.md](./references/api-reference.md)。
120
+ 详细用法见 [SKILL.md](./skills/beervid-app-cli/SKILL.md)。完整 API 参考见 [references/api-reference.md](./skills/beervid-app-cli/references/api-reference.md)。
121
+
122
+ ## 落地文档
123
+
124
+ 面向接入方后端工程师的项目落地建议:
125
+
126
+ | 文档 | 内容 |
127
+ |------|------|
128
+ | [数据表字段建议](./skills/beervid-app-cli/docs/database-schema.md) | accounts/videos/products 表结构设计 |
129
+ | [OAuth 回调存储建议](./skills/beervid-app-cli/docs/oauth-callback.md) | State Token 防 CSRF、回调持久化、异步头像同步 |
130
+ | [TT 轮询任务建议](./skills/beervid-app-cli/docs/tt-poll-task.md) | 阶梯递增轮询间隔、Cron/队列三层保障 |
131
+ | [TTS 商品缓存建议](./skills/beervid-app-cli/docs/tts-product-cache.md) | 全量拉取、缓存过期、图片 URL 解析 |
132
+ | [失败重试与幂等建议](./skills/beervid-app-cli/docs/retry-and-idempotency.md) | 各 API 幂等性分析、指数退避、幂等键设计 |
133
+
134
+ ## 示例工程
135
+
136
+ 三种接入场景的可运行示例:
137
+
138
+ | 示例 | 场景 | 入口 |
139
+ |------|------|------|
140
+ | [Standard](./skills/beervid-app-cli/example/standard/) | 纯 Node.js 脚本,快速验证 | `npx tsx tt-publish-flow.ts` |
141
+ | [Express](./skills/beervid-app-cli/example/express/) | Express 后端服务,含 OAuth 回调 | `npx tsx server.ts` |
142
+ | [Next.js](./skills/beervid-app-cli/example/nextjs/) | Next.js App Router API Route | `npm run dev` |
package/dist/cli.mjs CHANGED
@@ -151,6 +151,28 @@ function rethrowIfProcessExit(error) {
151
151
  throw error;
152
152
  }
153
153
  }
154
+ function getRawOptionValues(rawArgs, optionName) {
155
+ const values = [];
156
+ const prefix = `${optionName}=`;
157
+ for (let i = 0; i < rawArgs.length; i++) {
158
+ const arg = rawArgs[i];
159
+ if (arg === optionName) {
160
+ const next = rawArgs[i + 1];
161
+ if (typeof next === "string" && !next.startsWith("-")) {
162
+ values.push(next);
163
+ i++;
164
+ }
165
+ continue;
166
+ }
167
+ if (arg.startsWith(prefix)) {
168
+ values.push(arg.slice(prefix.length));
169
+ }
170
+ }
171
+ return values;
172
+ }
173
+ function getRawOptionValue(rawArgs, optionName) {
174
+ return getRawOptionValues(rawArgs, optionName).at(-1);
175
+ }
154
176
 
155
177
  // src/commands/oauth.ts
156
178
  function register(cli2) {
@@ -186,8 +208,9 @@ function register(cli2) {
186
208
  // src/commands/account.ts
187
209
  function register2(cli2) {
188
210
  cli2.command("get-account-info", "\u67E5\u8BE2 TikTok \u8D26\u53F7\u4FE1\u606F").option("--type <type>", "\u8D26\u53F7\u7C7B\u578B: TT \u6216 TTS").option("--account-id <id>", "\u8D26\u53F7 ID").action(async (options) => {
189
- if (!options.type || !options.accountId) {
190
- const missing = [!options.type && "--type", !options.accountId && "--account-id"].filter(Boolean).join(", ");
211
+ const accountId = getRawOptionValue(cli2.rawArgs, "--account-id");
212
+ if (!options.type || !accountId) {
213
+ const missing = [!options.type && "--type", !accountId && "--account-id"].filter(Boolean).join(", ");
191
214
  console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing}
192
215
  `);
193
216
  console.error("\u7528\u6CD5: beervid get-account-info --type <TT|TTS> --account-id <id>");
@@ -201,7 +224,7 @@ function register2(cli2) {
201
224
  try {
202
225
  const data = await openApiPost("/api/v1/open/account/info", {
203
226
  accountType,
204
- accountId: options.accountId
227
+ accountId
205
228
  });
206
229
  printResult(data);
207
230
  } catch (err) {
@@ -256,19 +279,20 @@ function register3(cli2) {
256
279
  process.exit(1);
257
280
  }
258
281
  const uploadType = (options.type ?? "normal").toLowerCase();
282
+ const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
259
283
  if (!VALID_UPLOAD_TYPES.includes(uploadType)) {
260
284
  console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 tts");
261
285
  process.exit(1);
262
286
  }
263
- if (uploadType === "tts" && !options.creatorId) {
287
+ if (uploadType === "tts" && !creatorId) {
264
288
  console.error("\u9519\u8BEF: TTS \u4E0A\u4F20\u6A21\u5F0F\u9700\u8981 --creator-id \u53C2\u6570");
265
289
  process.exit(1);
266
290
  }
267
291
  try {
268
292
  let data;
269
293
  if (uploadType === "tts") {
270
- console.log(`TTS \u4E0A\u4F20\u6A21\u5F0F\uFF0CcreatorUserOpenId: ${options.creatorId}`);
271
- data = await uploadTtsVideo(options.file, options.creatorId, options.token);
294
+ console.log(`TTS \u4E0A\u4F20\u6A21\u5F0F\uFF0CcreatorUserOpenId: ${creatorId}`);
295
+ data = await uploadTtsVideo(options.file, creatorId, options.token);
272
296
  } else {
273
297
  console.log("\u666E\u901A\u4E0A\u4F20\u6A21\u5F0F");
274
298
  data = await uploadNormalVideo(options.file, options.token);
@@ -293,6 +317,10 @@ function register4(cli2) {
293
317
  }).option("--caption <text>", "\u89C6\u9891\u63CF\u8FF0/\u6587\u6848\uFF08\u53EF\u9009\uFF09").action(
294
318
  async (options) => {
295
319
  const publishType = (options.type ?? "normal").toLowerCase();
320
+ const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
321
+ const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
322
+ const fileId = getRawOptionValue(cli2.rawArgs, "--file-id");
323
+ const productId = getRawOptionValue(cli2.rawArgs, "--product-id");
296
324
  if (!VALID_PUBLISH_TYPES.includes(publishType)) {
297
325
  console.error("\u9519\u8BEF: --type \u5FC5\u987B\u4E3A normal \u6216 shoppable");
298
326
  process.exit(1);
@@ -301,9 +329,9 @@ function register4(cli2) {
301
329
  let data;
302
330
  if (publishType === "shoppable") {
303
331
  const missing = [
304
- !options.creatorId && "--creator-id",
305
- !options.fileId && "--file-id",
306
- !options.productId && "--product-id",
332
+ !creatorId && "--creator-id",
333
+ !fileId && "--file-id",
334
+ !productId && "--product-id",
307
335
  !options.productTitle && "--product-title"
308
336
  ].filter(Boolean);
309
337
  if (missing.length > 0) {
@@ -325,17 +353,17 @@ function register4(cli2) {
325
353
  data = await openApiPost(
326
354
  "/api/v1/open/tts/shoppable-video/publish",
327
355
  {
328
- creatorUserOpenId: options.creatorId,
329
- fileId: options.fileId,
356
+ creatorUserOpenId: creatorId,
357
+ fileId,
330
358
  title: options.caption ?? "",
331
- productId: options.productId,
359
+ productId,
332
360
  productTitle
333
361
  }
334
362
  );
335
363
  console.log("\n\u53D1\u5E03\u6210\u529F\uFF08\u6302\u8F66\u89C6\u9891\u7ACB\u5373\u5B8C\u6210\uFF09:");
336
364
  } else {
337
365
  const missing = [
338
- !options.businessId && "--business-id",
366
+ !businessId && "--business-id",
339
367
  !options.videoUrl && "--video-url"
340
368
  ].filter(Boolean);
341
369
  if (missing.length > 0) {
@@ -350,14 +378,14 @@ function register4(cli2) {
350
378
  data = await openApiPost(
351
379
  "/api/v1/open/tiktok/video/publish",
352
380
  {
353
- businessId: options.businessId,
381
+ businessId,
354
382
  videoUrl: options.videoUrl,
355
383
  caption: options.caption ?? ""
356
384
  }
357
385
  );
358
386
  console.log("\n\u53D1\u5E03\u5DF2\u63D0\u4EA4\uFF08\u9700\u8F6E\u8BE2\u72B6\u6001\uFF09:");
359
387
  console.log(
360
- `\u63D0\u793A: \u4F7F\u7528 beervid poll-status --business-id ${options.businessId} --share-id ${data.shareId} \u8F6E\u8BE2\u8FDB\u5EA6`
388
+ `\u63D0\u793A: \u4F7F\u7528 beervid poll-status --business-id ${businessId} --share-id ${data.shareId} \u8F6E\u8BE2\u8FDB\u5EA6`
361
389
  );
362
390
  }
363
391
  printResult(data);
@@ -377,10 +405,12 @@ function sleep(ms) {
377
405
  function register5(cli2) {
378
406
  cli2.command("poll-status", "\u8F6E\u8BE2\u666E\u901A\u89C6\u9891\u53D1\u5E03\u72B6\u6001").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--share-id <id>", "\u53D1\u5E03\u65F6\u8FD4\u56DE\u7684 shareId\uFF08\u5FC5\u586B\uFF09").option("--interval <sec>", "\u8F6E\u8BE2\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--max-polls <n>", "\u6700\u5927\u8F6E\u8BE2\u6B21\u6570\uFF08\u9ED8\u8BA4 60\uFF09").action(
379
407
  async (options) => {
380
- if (!options.businessId || !options.shareId) {
408
+ const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
409
+ const shareId = getRawOptionValue(cli2.rawArgs, "--share-id");
410
+ if (!businessId || !shareId) {
381
411
  const missing = [
382
- !options.businessId && "--business-id",
383
- !options.shareId && "--share-id"
412
+ !businessId && "--business-id",
413
+ !shareId && "--share-id"
384
414
  ].filter(Boolean);
385
415
  console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
386
416
  `);
@@ -399,14 +429,14 @@ function register5(cli2) {
399
429
  }
400
430
  try {
401
431
  console.log(`\u5F00\u59CB\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001 (\u95F4\u9694 ${intervalSec}s, \u6700\u591A ${maxPolls} \u6B21)`);
402
- console.log(`businessId: ${options.businessId}`);
403
- console.log(`shareId: ${options.shareId}
432
+ console.log(`businessId: ${businessId}`);
433
+ console.log(`shareId: ${shareId}
404
434
  `);
405
435
  let lastStatus = "UNKNOWN";
406
436
  for (let i = 1; i <= maxPolls; i++) {
407
437
  const data = await openApiPost("/api/v1/open/tiktok/video/status", {
408
- businessId: options.businessId,
409
- shareId: options.shareId
438
+ businessId,
439
+ shareId
410
440
  });
411
441
  const status = data.status ?? data.Status ?? "UNKNOWN";
412
442
  const postIds = data.post_ids ?? [];
@@ -423,7 +453,7 @@ function register5(cli2) {
423
453
  console.log("\u53D1\u5E03\u6210\u529F!");
424
454
  console.log(`\u89C6\u9891 ID: ${postIds[0]}`);
425
455
  console.log(
426
- `\u63D0\u793A: \u4F7F\u7528 beervid query-video --business-id ${options.businessId} --item-ids ${postIds[0]} \u67E5\u8BE2\u6570\u636E`
456
+ `\u63D0\u793A: \u4F7F\u7528 beervid query-video --business-id ${businessId} --item-ids ${postIds[0]} \u67E5\u8BE2\u6570\u636E`
427
457
  );
428
458
  printResult(data);
429
459
  process.exit(0);
@@ -452,11 +482,13 @@ function register5(cli2) {
452
482
  // src/commands/query-video.ts
453
483
  function register6(cli2) {
454
484
  cli2.command("query-video", "\u67E5\u8BE2\u89C6\u9891\u7EDF\u8BA1\u6570\u636E").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--item-ids <ids>", "\u89C6\u9891 ID\uFF0C\u652F\u6301\u91CD\u590D\u4F20\u53C2\u6216\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").action(
455
- async (options) => {
456
- if (!options.businessId || !options.itemIds) {
485
+ async () => {
486
+ const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
487
+ const rawItemIdArgs = getRawOptionValues(cli2.rawArgs, "--item-ids");
488
+ if (!businessId || rawItemIdArgs.length === 0) {
457
489
  const missing = [
458
- !options.businessId && "--business-id",
459
- !options.itemIds && "--item-ids"
490
+ !businessId && "--business-id",
491
+ rawItemIdArgs.length === 0 && "--item-ids"
460
492
  ].filter(Boolean);
461
493
  console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
462
494
  `);
@@ -465,7 +497,7 @@ function register6(cli2) {
465
497
  );
466
498
  process.exit(1);
467
499
  }
468
- const itemIds = (Array.isArray(options.itemIds) ? options.itemIds : [options.itemIds]).flatMap((value) => value.split(",")).map((id) => id.trim()).filter(Boolean);
500
+ const itemIds = rawItemIdArgs.flatMap((value) => value.split(",")).map((id) => id.trim()).filter(Boolean);
469
501
  if (itemIds.length === 0) {
470
502
  console.error("\u9519\u8BEF: --item-ids \u4E0D\u80FD\u4E3A\u7A7A");
471
503
  process.exit(1);
@@ -474,7 +506,7 @@ function register6(cli2) {
474
506
  console.log(`\u67E5\u8BE2 ${itemIds.length} \u4E2A\u89C6\u9891\u7684\u6570\u636E...
475
507
  `);
476
508
  const data = await openApiPost("/api/v1/open/tiktok/video/query", {
477
- businessId: options.businessId,
509
+ businessId,
478
510
  itemIds
479
511
  });
480
512
  const list = data.videoList ?? data.videos ?? [];
@@ -771,12 +803,12 @@ var VALID_PRODUCT_TYPES = ["shop", "showcase", "all"];
771
803
  function register7(cli2) {
772
804
  cli2.command("query-products", "\u67E5\u8BE2 TTS \u5546\u54C1\u5217\u8868").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u5FC5\u586B\uFF09").option("--product-type <type>", "\u5546\u54C1\u6765\u6E90: shop / showcase / all\uFF08\u9ED8\u8BA4 all\uFF09").option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09").option("--cursor <cursor>", "\u5206\u9875\u6E38\u6807\uFF08\u9996\u9875\u4E0D\u4F20\uFF09").action(
773
805
  async (options) => {
774
- if (!options.creatorId) {
806
+ const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
807
+ if (!creatorId) {
775
808
  console.error("\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: --creator-id\n");
776
809
  console.error("\u7528\u6CD5: beervid query-products --creator-id <id>");
777
810
  process.exit(1);
778
811
  }
779
- const creatorId = options.creatorId;
780
812
  const productType = (options.productType ?? "all").toLowerCase();
781
813
  const pageSize = parseInt(options.pageSize ?? "20", 10);
782
814
  const cursor = options.cursor ?? "";
@@ -845,9 +877,10 @@ function parsePositiveInt(value, optionName, defaultValue) {
845
877
  function register8(cli2) {
846
878
  cli2.command("publish-tt-flow", "\u6267\u884C TT \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\uFF1A\u4E0A\u4F20\u3001\u53D1\u5E03\u3001\u8F6E\u8BE2\u3001\u67E5\u8BE2\u6570\u636E").option("--business-id <id>", "TT \u8D26\u53F7 businessId\uFF08\u5FC5\u586B\uFF09").option("--file <path>", "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84\u6216 URL\uFF08\u5FC5\u586B\uFF09").option("--caption <text>", "\u89C6\u9891\u63CF\u8FF0/\u6587\u6848\uFF08\u53EF\u9009\uFF09").option("--token <token>", "\u5DF2\u6709\u4E0A\u4F20\u51ED\u8BC1\uFF08\u53EF\u9009\uFF09").option("--interval <sec>", "\u8F6E\u8BE2\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--max-polls <n>", "\u6700\u5927\u8F6E\u8BE2\u6B21\u6570\uFF08\u9ED8\u8BA4 60\uFF09").option("--query-interval <sec>", "\u89C6\u9891\u6570\u636E\u67E5\u8BE2\u91CD\u8BD5\u95F4\u9694\u79D2\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--query-max-attempts <n>", "\u89C6\u9891\u6570\u636E\u67E5\u8BE2\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF08\u9ED8\u8BA4 3\uFF09").action(
847
879
  async (options) => {
848
- if (!options.businessId || !options.file) {
880
+ const businessId = getRawOptionValue(cli2.rawArgs, "--business-id");
881
+ if (!businessId || !options.file) {
849
882
  const missing = [
850
- !options.businessId && "--business-id",
883
+ !businessId && "--business-id",
851
884
  !options.file && "--file"
852
885
  ].filter(Boolean);
853
886
  console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
@@ -870,28 +903,14 @@ function register8(cli2) {
870
903
  console.log("1/4 \u6B63\u5728\u4E0A\u4F20\u89C6\u9891...");
871
904
  const upload = await uploadNormalVideo(options.file, options.token);
872
905
  console.log("2/4 \u6B63\u5728\u53D1\u5E03\u89C6\u9891...");
873
- const publish = await publishNormalVideo(
874
- options.businessId,
875
- upload.fileUrl,
876
- options.caption
877
- );
906
+ const publish = await publishNormalVideo(businessId, upload.fileUrl, options.caption);
878
907
  console.log("3/4 \u6B63\u5728\u8F6E\u8BE2\u53D1\u5E03\u72B6\u6001...");
879
- const status = await pollNormalVideoStatus(
880
- options.businessId,
881
- publish.shareId,
882
- intervalSec,
883
- maxPolls
884
- );
908
+ const status = await pollNormalVideoStatus(businessId, publish.shareId, intervalSec, maxPolls);
885
909
  const videoId = status.postIds[0] ?? null;
886
910
  let query = null;
887
911
  if (status.finalStatus === "PUBLISH_COMPLETE" && videoId) {
888
912
  console.log("4/4 \u6B63\u5728\u67E5\u8BE2\u89C6\u9891\u6570\u636E...");
889
- const queryResult = await queryVideoWithRetry(
890
- options.businessId,
891
- videoId,
892
- queryIntervalSec,
893
- queryMaxAttempts
894
- );
913
+ const queryResult = await queryVideoWithRetry(businessId, videoId, queryIntervalSec, queryMaxAttempts);
895
914
  query = queryResult.query;
896
915
  for (const warning of queryResult.warnings) {
897
916
  console.warn(warning.message);
@@ -952,9 +971,11 @@ function buildManualProduct(productId, productTitle, matchedProduct) {
952
971
  function register9(cli2) {
953
972
  cli2.command("publish-tts-flow", "\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\uFF1A\u67E5\u5546\u54C1\u3001\u9009\u5546\u54C1\u3001\u4E0A\u4F20\u3001\u53D1\u5E03").option("--creator-id <id>", "TTS \u8D26\u53F7 creatorUserOpenId\uFF08\u5FC5\u586B\uFF09").option("--file <path>", "\u89C6\u9891\u6587\u4EF6\u8DEF\u5F84\u6216 URL\uFF08\u5FC5\u586B\uFF09").option("--caption <text>", "\u89C6\u9891\u6807\u9898/\u6587\u6848\uFF08\u53EF\u9009\uFF09").option("--token <token>", "\u5DF2\u6709\u4E0A\u4F20\u51ED\u8BC1\uFF08\u53EF\u9009\uFF09").option("--product-type <type>", "\u5546\u54C1\u6765\u6E90: shop / showcase / all\uFF08\u9ED8\u8BA4 all\uFF09").option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09").option("--max-product-pages <n>", "\u5546\u54C1\u626B\u63CF\u6700\u5927\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF09").option("--product-id <id>", "\u624B\u52A8\u6307\u5B9A\u5546\u54C1 ID").option("--product-title <title>", "\u624B\u52A8\u6307\u5B9A\u5546\u54C1\u6807\u9898").option("--interactive", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u5546\u54C1").action(
954
973
  async (options) => {
955
- if (!options.creatorId || !options.file) {
974
+ const creatorId = getRawOptionValue(cli2.rawArgs, "--creator-id");
975
+ const productId = getRawOptionValue(cli2.rawArgs, "--product-id");
976
+ if (!creatorId || !options.file) {
956
977
  const missing = [
957
- !options.creatorId && "--creator-id",
978
+ !creatorId && "--creator-id",
958
979
  !options.file && "--file"
959
980
  ].filter(Boolean);
960
981
  console.error(`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${missing.join(", ")}
@@ -969,11 +990,11 @@ function register9(cli2) {
969
990
  console.error("\u9519\u8BEF: --product-type \u5FC5\u987B\u4E3A shop\u3001showcase \u6216 all");
970
991
  process.exit(1);
971
992
  }
972
- if (options.productId && options.interactive) {
993
+ if (productId && options.interactive) {
973
994
  console.error("\u9519\u8BEF: --product-id \u4E0E --interactive \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
974
995
  process.exit(1);
975
996
  }
976
- if (options.productTitle && !options.productId) {
997
+ if (options.productTitle && !productId) {
977
998
  console.error("\u9519\u8BEF: --product-title \u9700\u8981\u4E0E --product-id \u4E00\u8D77\u4F7F\u7528");
978
999
  process.exit(1);
979
1000
  }
@@ -987,13 +1008,13 @@ function register9(cli2) {
987
1008
  console.log("\u5F00\u59CB\u6267\u884C TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B...");
988
1009
  let selectedProduct;
989
1010
  let queriedProducts = null;
990
- if (options.productId && options.productTitle) {
1011
+ if (productId && options.productTitle) {
991
1012
  console.log("1/4 \u5DF2\u624B\u52A8\u6307\u5B9A\u5546\u54C1\uFF0C\u8DF3\u8FC7\u5546\u54C1\u67E5\u8BE2...");
992
- selectedProduct = buildManualProduct(options.productId, options.productTitle);
1013
+ selectedProduct = buildManualProduct(productId, options.productTitle);
993
1014
  } else {
994
1015
  console.log("1/4 \u6B63\u5728\u67E5\u8BE2\u5546\u54C1\u5217\u8868...");
995
1016
  const productPool = await fetchProductPool(
996
- options.creatorId,
1017
+ creatorId,
997
1018
  productType,
998
1019
  pageSize,
999
1020
  maxProductPages
@@ -1007,10 +1028,8 @@ function register9(cli2) {
1007
1028
  `\u4EE5\u4E0B\u5546\u54C1\u6E90\u8BF7\u6C42\u5931\u8D25: ${productPool.summary.failedSources.join(", ")}\uFF0C\u5546\u54C1\u6C60\u53EF\u80FD\u4E0D\u5B8C\u6574`
1008
1029
  );
1009
1030
  }
1010
- if (options.productId) {
1011
- const matchedProduct = productPool.products.find(
1012
- (product) => product.id === options.productId
1013
- );
1031
+ if (productId) {
1032
+ const matchedProduct = productPool.products.find((product) => product.id === productId);
1014
1033
  const resolvedTitle = matchedProduct?.title;
1015
1034
  if (!resolvedTitle) {
1016
1035
  console.error(
@@ -1018,7 +1037,7 @@ function register9(cli2) {
1018
1037
  );
1019
1038
  process.exit(1);
1020
1039
  }
1021
- selectedProduct = buildManualProduct(options.productId, resolvedTitle, matchedProduct);
1040
+ selectedProduct = buildManualProduct(productId, resolvedTitle, matchedProduct);
1022
1041
  } else if (options.interactive) {
1023
1042
  if (productPool.products.length === 0) {
1024
1043
  console.error("TTS \u5B8C\u6574\u53D1\u5E03\u6D41\u7A0B\u5931\u8D25: \u5F53\u524D\u5546\u54C1\u6C60\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u9009\u62E9\u5546\u54C1");
@@ -1043,10 +1062,10 @@ function register9(cli2) {
1043
1062
  }
1044
1063
  }
1045
1064
  console.log("3/4 \u6B63\u5728\u4E0A\u4F20\u6302\u8F66\u89C6\u9891...");
1046
- const upload = await uploadTtsVideo(options.file, options.creatorId, options.token);
1065
+ const upload = await uploadTtsVideo(options.file, creatorId, options.token);
1047
1066
  console.log("4/4 \u6B63\u5728\u53D1\u5E03\u6302\u8F66\u89C6\u9891...");
1048
1067
  const publishResult = await publishTtsVideo(
1049
- options.creatorId,
1068
+ creatorId,
1050
1069
  upload.videoFileId,
1051
1070
  selectedProduct.id,
1052
1071
  selectedProduct.title,
@@ -1111,7 +1130,7 @@ function register10(cli2) {
1111
1130
 
1112
1131
  // src/cli.ts
1113
1132
  var cli = cac("beervid");
1114
- var cliVersion = true ? "0.2.3" : pkg.version;
1133
+ var cliVersion = true ? "0.2.5" : pkg.version;
1115
1134
  register10(cli);
1116
1135
  register(cli);
1117
1136
  register2(cli);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beervid-app-cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "BEERVID App CLI — TikTok video publish, account auth, and data query",
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,9 +11,7 @@
11
11
  },
12
12
  "files": [
13
13
  "dist/",
14
- "agents/",
15
- "references/",
16
- "SKILL.md",
14
+ "skills/",
17
15
  "README.md"
18
16
  ],
19
17
  "scripts": {