@bty/customer-service-cli 0.6.14 → 0.6.18

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.18 (2026-09-21)
4
+
5
+ - `agent update` 只应传需要修改的字段:`--data` 的帮助文案不再宣传 `knowledge_base_config` / `database_config`,并明确提示不要 `agent get` 导出后整对象回传。这两个字段由服务端维护,`customer-servhub-api PUT /v1/customer-agent/{config_id}` 已改为拒绝更新(传入返回 400)。背景:整份回传会把知识库/数据库列表整份写回,并在 fork 时被放大成平台侧大量重复分区创建。
6
+
7
+ ## 0.6.17 (2026-09-10)
8
+
9
+ - 新增 `product image-identify`:按自定义提示词只重新识别某一张主图/详情图,寻址用 `--main <n>` / `--detail <n>`(从 1 开始,二选一),`--prompt "..."`(支持 `@文件`)覆盖本次提示词。默认只打印新旧对照,`--apply` 才写回识别文字(main→`轮播图识别结果`,detail→`商品详情页识别结果`);`--show-prompt` 只回当前生效提示词与解析出的图片 URL,不识别、不写回。对接 `customer-servhub-api POST /v1/knowledge/product/image/identify`。
10
+
11
+ ## 0.6.16 (2026-09-08)
12
+
13
+ - 新增 `product shelf`:批量设置商品上下架状态,写 BTY「店铺商品目录」的「商品状态」列(合法值仅 `上架` / `下架`),与商品详情页的上架/下架下拉框同一个 `POST /v1/knowledge/product/update` 接口。标为 `下架` 后商品推荐类工具不再选中该商品(服务端据此派生只读的 `is_downshelf`)。商品用 `--ids` / `--ids-file` 指定;批量前先整体翻一遍商品列表建 `product_id → knowledge_id` 索引(避免逐个商品重复分页);已是目标状态的商品跳过不写;每条写入后**回读校验**「商品状态」确实变更,防接口假成功。支持 `--concurrency`(默认 5)与 `--yes`(≥20 条时跳过二次确认),输出标准批量报告,部分失败退出码 2、全部失败 1。
14
+
3
15
  ## 0.6.14 (2026-09-02)
4
16
 
5
17
  - `agent fork` 新增 `--copy-authorized-shop-id`:与 `--clone-tools` 同用时,克隆的工具沿用来源工具的店铺授权 `authorized_shop_id`;默认关闭(清空),仅在用户明确要求全量复制工具时开启。
package/README.md CHANGED
@@ -247,6 +247,7 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
247
247
  | `product list --agent <id> [--keyword <关键词>] [--status <状态>] [--tag <标签>]` | 列出商品 |
248
248
  | `product get --agent <id> --product-id <商品ID>` | 获取商品详情(自动获取 db_id) |
249
249
  | `product update --agent <id> --product-id <商品ID> --update <json\|@file>` | 更新商品信息 |
250
+ | `product shelf --agent <id> --status <上架\|下架> (--ids <id,id> \| --ids-file <path>) [--concurrency <n>] [--yes]` | 批量设置商品上下架状态(写「商品状态」列,写后回读校验) |
250
251
  | `product update-sku --agent <id> (--sku <SKU名称> \| --sku-id <id>) --update <json\|@file>` | 更新 SKU 信息(`--sku-id` 优先于 `--sku`) |
251
252
  | `product add --agent <id> --data <json\|@file> [--source <type>] [--no-identify]` | 直接传入结构化商品数据(JSON 数组)异步学习(manual / identify 默认开启) |
252
253
  | `product learn --agent <id> --url <URL...> [--source <type>] [--no-identify]` | 通过商品 URL 异步学习(manual / identify 默认开启) |
package/dist/bin.js CHANGED
@@ -563,6 +563,13 @@ async function patchActivityEnabled(activityId, enabled) {
563
563
  body: { enabled }
564
564
  });
565
565
  }
566
+ async function patchActivityFeatured(activityId, isFeatured) {
567
+ const request = createRequest();
568
+ return request(getCustomerServiceUrl(), `${PATH_PREFIX}/${activityId}/featured`, {
569
+ method: "PATCH",
570
+ body: { is_featured: isFeatured }
571
+ });
572
+ }
566
573
  async function deleteActivity(activityId) {
567
574
  const request = createRequest();
568
575
  return request(getCustomerServiceUrl(), `${PATH_PREFIX}/${activityId}`, {
@@ -704,6 +711,19 @@ function registerActivityCommand(program2) {
704
711
  process.exit(toExitCode(err));
705
712
  }
706
713
  });
714
+ activity.command("set-featured").description(
715
+ "\u5207\u6362\u5355\u6761\u6D3B\u52A8\u4E3B\u63A8\u72B6\u6001\uFF08\u5217\u8868\u884C toggle \u7528\uFF0CPATCH /featured\uFF09\u3002\u4EC5\u5199 is_featured \u4E00\u4E2A\u5B57\u6BB5"
716
+ ).argument("<activity_id>", "\u6D3B\u52A8 ID").requiredOption("--featured <bool>", "true | false").action(async (activityIdRaw, opts) => {
717
+ try {
718
+ const activityId = parseActivityId(activityIdRaw);
719
+ const featured = parseEnabledFlag(opts.featured);
720
+ const data = await patchActivityFeatured(activityId, featured);
721
+ formatOutput({ success: true, data }, program2.opts().table);
722
+ } catch (err) {
723
+ reportCaughtError(err);
724
+ process.exit(toExitCode(err));
725
+ }
726
+ });
707
727
  activity.command("delete").description("\u8F6F\u5220\u6D3B\u52A8 + \u7EA7\u8054\u8F6F\u5220 activity_product \u5173\u8054").argument("<activity_id>", "\u6D3B\u52A8 ID").action(async (activityIdRaw) => {
708
728
  try {
709
729
  const activityId = parseActivityId(activityIdRaw);
@@ -800,10 +820,10 @@ function registerAgentCommand(program2) {
800
820
  }
801
821
  });
802
822
  agent.command("update").description(
803
- "\u66F4\u65B0 Agent \u914D\u7F6E\uFF08\u5982 customer_config\u3001forbidden_words \u7B49\uFF09\u3002\u5EFA\u8BAE\u5148 agent get \u5BFC\u51FA\u5F53\u524D\u914D\u7F6E\u518D\u4FEE\u6539"
823
+ "\u66F4\u65B0 Agent \u914D\u7F6E\uFF08\u5982 customer_config\u3001forbidden_words \u7B49\uFF09\u3002\u53EA\u4F20\u9700\u8981\u4FEE\u6539\u7684\u5B57\u6BB5\uFF0C\u4E0D\u8981\u6574\u5BF9\u8C61\u56DE\u4F20"
804
824
  ).argument("<config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption(
805
825
  "--data <json>",
806
- "JSON \u6570\u636E\u6216 @\u6587\u4EF6\u8DEF\u5F84\u3002\u53EF\u66F4\u65B0\u5B57\u6BB5\u5305\u62EC customer_config\u3001forbidden_words\u3001knowledge_base_config \u7B49"
826
+ "JSON \u6570\u636E\u6216 @\u6587\u4EF6\u8DEF\u5F84\u3002\u53EF\u66F4\u65B0\u5B57\u6BB5\u5305\u62EC customer_config\u3001forbidden_words \u7B49\uFF1Bdatabase_config / knowledge_base_config \u7531\u670D\u52A1\u7AEF\u7EF4\u62A4\uFF0CCLI \u62D2\u7EDD\u66F4\u65B0"
807
827
  ).action(async (configId, opts) => {
808
828
  try {
809
829
  const body = parseDataOption(opts.data);
@@ -1784,6 +1804,9 @@ function csvToRows(csv) {
1784
1804
  return obj;
1785
1805
  });
1786
1806
  }
1807
+ function toPublicOssDownloadUrl(url) {
1808
+ return url.replace("-internal.aliyuncs.com", ".aliyuncs.com");
1809
+ }
1787
1810
  async function exportShopData(opts) {
1788
1811
  const request = createRequest();
1789
1812
  const body = {
@@ -1797,10 +1820,11 @@ async function exportShopData(opts) {
1797
1820
  `${DASHBOARD_PREFIX}/export`,
1798
1821
  { method: "POST", body }
1799
1822
  );
1800
- const downloadUrl = data?.download_url;
1801
- if (!downloadUrl) {
1823
+ const rawDownloadUrl = data?.download_url;
1824
+ if (!rawDownloadUrl) {
1802
1825
  throw new APIError(1, "\u5BFC\u51FA\u63A5\u53E3\u672A\u8FD4\u56DE download_url");
1803
1826
  }
1827
+ const downloadUrl = toPublicOssDownloadUrl(rawDownloadUrl);
1804
1828
  const timeoutMs = getRuntimeRequestTimeoutMs() ?? 6e4;
1805
1829
  const resp = await fetch(downloadUrl, { signal: AbortSignal.timeout(timeoutMs) });
1806
1830
  if (!resp.ok) {
@@ -2231,6 +2255,24 @@ async function syncSingleTaobaoProduct(opts) {
2231
2255
  }
2232
2256
  });
2233
2257
  }
2258
+ async function identifyProductImage(opts) {
2259
+ const request = createRequest();
2260
+ return request(
2261
+ getCustomerServiceUrl(),
2262
+ "/v1/knowledge/product/image/identify",
2263
+ {
2264
+ method: "POST",
2265
+ body: {
2266
+ customer_agent_config_id: opts.agentConfigId,
2267
+ product_id: opts.productId,
2268
+ image_type: opts.imageType,
2269
+ image_index: opts.imageIndex,
2270
+ ...opts.prompt !== void 0 ? { prompt: opts.prompt } : {},
2271
+ dry_run: opts.dryRun ?? false
2272
+ }
2273
+ }
2274
+ );
2275
+ }
2234
2276
  async function identifyAllProducts(opts) {
2235
2277
  const request = createRequest();
2236
2278
  return request(getCustomerServiceUrl(), "/v1/knowledge/products/identify/all", {
@@ -5609,6 +5651,40 @@ function registerOpsAgentCommand(program2) {
5609
5651
  // src/commands/product.ts
5610
5652
  import fs10 from "fs";
5611
5653
 
5654
+ // src/lib/product-image.ts
5655
+ function applyImageRecognition(list, index0, value, imageUrl) {
5656
+ const next = Array.isArray(list) ? list.map((item) => ({ ...item })) : [];
5657
+ while (next.length <= index0) {
5658
+ const fillIdx = next.length;
5659
+ next.push({
5660
+ [`image_url${fillIdx + 1}`]: "",
5661
+ [`image_desc${fillIdx + 1}`]: ""
5662
+ });
5663
+ }
5664
+ const urlKey = `image_url${index0 + 1}`;
5665
+ const descKey = `image_desc${index0 + 1}`;
5666
+ const existingUrl = next[index0]?.[urlKey] || "";
5667
+ next[index0] = {
5668
+ [urlKey]: existingUrl || imageUrl || "",
5669
+ [descKey]: value
5670
+ };
5671
+ return next;
5672
+ }
5673
+
5674
+ // src/lib/product-shelf.ts
5675
+ var SHELF_STATUSES = ["\u4E0A\u67B6", "\u4E0B\u67B6"];
5676
+ function normalizeShelfStatus(raw) {
5677
+ return String(raw ?? "").trim() === "\u4E0B\u67B6" ? "\u4E0B\u67B6" : "\u4E0A\u67B6";
5678
+ }
5679
+ function parseShelfStatusOption(value) {
5680
+ const normalized = String(value ?? "").trim();
5681
+ const matched = SHELF_STATUSES.find((status) => status === normalized);
5682
+ if (!matched) {
5683
+ throw new Error(`--status \u53EA\u80FD\u662F ${SHELF_STATUSES.join(" \u6216 ")}\uFF0C\u6536\u5230: ${value}`);
5684
+ }
5685
+ return matched;
5686
+ }
5687
+
5612
5688
  // src/lib/supplement.ts
5613
5689
  function parseSupplementField(value) {
5614
5690
  let current = value;
@@ -5698,6 +5774,57 @@ async function findProduct(agentConfigId, productId) {
5698
5774
  }
5699
5775
  }
5700
5776
  }
5777
+ async function buildProductIndex(agentConfigId) {
5778
+ const pageSize = 100;
5779
+ const index = /* @__PURE__ */ new Map();
5780
+ for (let page = 1; ; page += 1) {
5781
+ const result = await listProducts({ agentConfigId, page, pageSize });
5782
+ const items = result.items ?? [];
5783
+ for (const item of items) {
5784
+ if (!index.has(item.product_id)) index.set(item.product_id, item.knowledge_id);
5785
+ }
5786
+ const fetched = page * pageSize;
5787
+ const exhausted = items.length < pageSize || typeof result.total === "number" && fetched >= result.total;
5788
+ if (exhausted) return index;
5789
+ }
5790
+ }
5791
+ function resolveImageTarget(opts) {
5792
+ const hasMain = opts.main !== void 0;
5793
+ const hasDetail = opts.detail !== void 0;
5794
+ if (hasMain === hasDetail) {
5795
+ throw new Error("\u8BF7\u4E14\u4EC5\u6307\u5B9A --main <n> \u6216 --detail <n> \u5176\u4E2D\u4E4B\u4E00");
5796
+ }
5797
+ const rawValue = hasMain ? opts.main : opts.detail;
5798
+ const imageIndex = Number.parseInt(rawValue, 10);
5799
+ if (!Number.isInteger(imageIndex) || imageIndex < 1) {
5800
+ throw new Error("\u56FE\u7247\u5E8F\u53F7\u5FC5\u987B\u662F\u4ECE 1 \u5F00\u59CB\u7684\u6B63\u6574\u6570");
5801
+ }
5802
+ return { imageType: hasMain ? "main" : "detail", imageIndex };
5803
+ }
5804
+ function readPromptText(value) {
5805
+ if (value.startsWith("@")) {
5806
+ const filePath = value.slice(1);
5807
+ if (!filePath) {
5808
+ throw new Error("@ \u540E\u7684\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
5809
+ }
5810
+ return fs10.readFileSync(filePath, "utf-8");
5811
+ }
5812
+ return value;
5813
+ }
5814
+ function parseRecognitionField(value) {
5815
+ if (Array.isArray(value)) {
5816
+ return value;
5817
+ }
5818
+ if (typeof value === "string" && value.trim()) {
5819
+ try {
5820
+ const parsed = JSON.parse(value);
5821
+ return Array.isArray(parsed) ? parsed : [];
5822
+ } catch {
5823
+ return [];
5824
+ }
5825
+ }
5826
+ return [];
5827
+ }
5701
5828
  async function loadProductSupplement(agentConfigId, productId) {
5702
5829
  const [dbId, matched] = await Promise.all([
5703
5830
  getDbId(agentConfigId),
@@ -5809,6 +5936,131 @@ function registerProductCommand(program2) {
5809
5936
  process.exit(toExitCode(err));
5810
5937
  }
5811
5938
  });
5939
+ product.command("image-identify").description(
5940
+ "\u5355\u56FE\u91CD\u65B0\u8BC6\u522B\uFF1A\u6309\u81EA\u5B9A\u4E49\u63D0\u793A\u8BCD\u53EA\u91CD\u8BC6\u522B\u67D0\u4E00\u5F20\u4E3B\u56FE/\u8BE6\u60C5\u56FE\u3002\u9ED8\u8BA4\u53EA\u6253\u5370\u65B0\u65E7\u5BF9\u7167\uFF0C--apply \u624D\u5199\u56DE\u8BC6\u522B\u6587\u5B57\u3002--show-prompt \u53EA\u770B\u5F53\u524D\u751F\u6548\u63D0\u793A\u8BCD"
5941
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--product-id <product_id>", "\u5546\u54C1 ID\uFF08\u4ECE product list \u83B7\u53D6\uFF09").option("--main <n>", "\u7B2C\u51E0\u5F20\u4E3B\u56FE\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u4E0E --detail \u4E8C\u9009\u4E00").option("--detail <n>", "\u7B2C\u51E0\u5F20\u8BE6\u60C5\u56FE\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u4E0E --main \u4E8C\u9009\u4E00").option("--prompt <text|@file>", "\u81EA\u5B9A\u4E49\u63D0\u793A\u8BCD\uFF0C@\u524D\u7F00\u8BFB\u6587\u4EF6\uFF1B\u7559\u7A7A\u56DE\u9000\u5E73\u53F0\u9ED8\u8BA4").option("--show-prompt", "\u53EA\u6253\u5370\u5F53\u524D\u751F\u6548\u63D0\u793A\u8BCD\u4E0E\u89E3\u6790\u51FA\u7684\u56FE\u7247 URL\uFF0C\u4E0D\u8BC6\u522B\u3001\u4E0D\u5199\u56DE", false).option("--apply", "\u628A\u8BC6\u522B\u7ED3\u679C\u5199\u56DE\u5546\u54C1\u8BC6\u522B\u6587\u5B57\uFF08\u9ED8\u8BA4\u53EA\u6253\u5370\u5BF9\u7167\uFF09", false).action(async (opts) => {
5942
+ try {
5943
+ const { imageType, imageIndex } = resolveImageTarget(opts);
5944
+ const prompt = opts.prompt !== void 0 ? readPromptText(opts.prompt) : void 0;
5945
+ if (opts.showPrompt) {
5946
+ const data = await identifyProductImage({
5947
+ agentConfigId: opts.agent,
5948
+ productId: opts.productId,
5949
+ imageType,
5950
+ imageIndex,
5951
+ prompt,
5952
+ dryRun: true
5953
+ });
5954
+ formatOutput({ success: true, data }, program2.opts().table);
5955
+ return;
5956
+ }
5957
+ const result = await identifyProductImage({
5958
+ agentConfigId: opts.agent,
5959
+ productId: opts.productId,
5960
+ imageType,
5961
+ imageIndex,
5962
+ prompt
5963
+ });
5964
+ if (!opts.apply) {
5965
+ formatOutput({ success: true, data: { ...result, applied: false } }, program2.opts().table);
5966
+ return;
5967
+ }
5968
+ const [dbId, matched] = await Promise.all([
5969
+ getDbId(opts.agent),
5970
+ findProduct(opts.agent, opts.productId)
5971
+ ]);
5972
+ const detail = await getProductDetail({
5973
+ agentConfigId: opts.agent,
5974
+ dbId,
5975
+ productId: opts.productId
5976
+ });
5977
+ const field = imageType === "main" ? "\u8F6E\u64AD\u56FE\u8BC6\u522B\u7ED3\u679C" : "\u5546\u54C1\u8BE6\u60C5\u9875\u8BC6\u522B\u7ED3\u679C";
5978
+ const nextList = applyImageRecognition(
5979
+ parseRecognitionField(detail[field]),
5980
+ imageIndex - 1,
5981
+ result.identify_result,
5982
+ result.image_url
5983
+ );
5984
+ await updateProduct({
5985
+ dataId: detail.id,
5986
+ knowledgeId: matched.knowledge_id,
5987
+ dbId,
5988
+ updateDict: { [field]: JSON.stringify(nextList) }
5989
+ });
5990
+ formatOutput({ success: true, data: { ...result, applied: true, field } }, program2.opts().table);
5991
+ } catch (err) {
5992
+ reportCaughtError(err);
5993
+ process.exit(toExitCode(err));
5994
+ }
5995
+ });
5996
+ product.command("shelf").description(
5997
+ "\u6279\u91CF\u8BBE\u7F6E\u5546\u54C1\u4E0A\u4E0B\u67B6\u72B6\u6001\uFF08\u5199 BTY\u300C\u5546\u54C1\u72B6\u6001\u300D\u5217\uFF0C\u4E0E\u5546\u54C1\u8BE6\u60C5\u9875\u7684\u4E0A\u67B6/\u4E0B\u67B6\u4E0B\u62C9\u6846\u540C\u4E00\u63A5\u53E3\uFF09\u3002\u6807\u4E3A\u300C\u4E0B\u67B6\u300D\u540E\u5546\u54C1\u63A8\u8350\u7C7B\u5DE5\u5177\u4E0D\u518D\u9009\u8BE5\u5546\u54C1\u3002\u6BCF\u6761\u5199\u5B8C\u56DE\u8BFB\u6821\u9A8C\uFF0C\u5DF2\u662F\u76EE\u6807\u72B6\u6001\u7684\u8DF3\u8FC7"
5998
+ ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--status <status>", "\u76EE\u6807\u72B6\u6001: \u4E0A\u67B6 | \u4E0B\u67B6").option("--ids <ids>", "\u5546\u54C1 ID\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u4E0E --ids-file \u4E8C\u9009\u4E00\uFF09").option("--ids-file <path>", "\u5546\u54C1 ID \u6587\u4EF6\uFF0C\u4E00\u884C\u4E00\u4E2A\uFF1B\u7A7A\u884C\u4E0E # \u5F00\u5934\u884C\u5FFD\u7565").option("--concurrency <n>", "\u5E76\u53D1\u6570\uFF08\u9ED8\u8BA4 5\uFF09", "5").option("--yes", "\u8DF3\u8FC7 20 \u6761\u4EE5\u4E0A\u7684\u4E8C\u6B21\u786E\u8BA4\uFF08CI / \u811A\u672C\uFF09").action(async (opts) => {
5999
+ let batchReport = null;
6000
+ try {
6001
+ const status = parseShelfStatusOption(opts.status);
6002
+ const ids = parseIdsInput({ ids: opts.ids, idsFile: opts.idsFile });
6003
+ const concurrency = Number(opts.concurrency);
6004
+ if (!Number.isFinite(concurrency) || concurrency < 1) {
6005
+ throw new Error(`--concurrency \u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF0C\u6536\u5230: ${opts.concurrency}`);
6006
+ }
6007
+ await confirmBatch({
6008
+ count: ids.length,
6009
+ action: `\u5C06\u5546\u54C1\u72B6\u6001\u6539\u4E3A\u300C${status}\u300D`,
6010
+ yes: opts.yes
6011
+ });
6012
+ const [dbId, index] = await Promise.all([
6013
+ getDbId(opts.agent),
6014
+ buildProductIndex(opts.agent)
6015
+ ]);
6016
+ batchReport = await runBatch({
6017
+ ids,
6018
+ concurrency,
6019
+ perItem: async (id) => {
6020
+ const knowledgeId = index.get(id);
6021
+ if (!knowledgeId) {
6022
+ throw new Error(`\u672A\u627E\u5230\u5546\u54C1 product_id=${id}\uFF08\u4E0D\u5728\u8BE5 Agent \u7684\u5546\u54C1\u5E93\u91CC\uFF09`);
6023
+ }
6024
+ const detail = await getProductDetail({
6025
+ agentConfigId: opts.agent,
6026
+ dbId,
6027
+ productId: id
6028
+ });
6029
+ if (normalizeShelfStatus(detail.\u5546\u54C1\u72B6\u6001) === status) {
6030
+ return { status: "skipped", id, reason: `\u5DF2\u662F\u300C${status}\u300D` };
6031
+ }
6032
+ await updateProduct({
6033
+ dataId: detail.id,
6034
+ knowledgeId,
6035
+ dbId,
6036
+ updateDict: { \u5546\u54C1\u72B6\u6001: status }
6037
+ });
6038
+ const after = await getProductDetail({
6039
+ agentConfigId: opts.agent,
6040
+ dbId,
6041
+ productId: id
6042
+ });
6043
+ const actual = normalizeShelfStatus(after.\u5546\u54C1\u72B6\u6001);
6044
+ if (actual !== status) {
6045
+ throw new Error(`\u56DE\u8BFB\u6821\u9A8C\u5931\u8D25\uFF1A\u671F\u671B\u300C${status}\u300D\uFF0C\u5B9E\u9645\u300C${actual}\u300D`);
6046
+ }
6047
+ return { status: "success", id };
6048
+ }
6049
+ });
6050
+ formatOutput(
6051
+ { success: batchReport.failed_count === 0, data: batchReport },
6052
+ program2.opts().table
6053
+ );
6054
+ } catch (err) {
6055
+ reportCaughtError(err);
6056
+ process.exit(toExitCode(err));
6057
+ return;
6058
+ }
6059
+ if (batchReport !== null) {
6060
+ const code = reportToExitCode(batchReport);
6061
+ if (code !== 0) process.exit(code);
6062
+ }
6063
+ });
5812
6064
  product.command("learn").description(
5813
6065
  "\u901A\u8FC7\u5546\u54C1 URL \u8BA9 Agent \u5B66\u4E60\u5546\u54C1\uFF08\u5F02\u6B65\u4E0A\u4F20\u8BC6\u522B\uFF09\uFF0C\u9ED8\u8BA4 source_type=manual / identify=true\u3002--no-identify \u53EF\u5173\u95ED\u81EA\u52A8\u8BC6\u522B"
5814
6066
  ).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").requiredOption("--url <urls...>", "\u5546\u54C1 URL \u5217\u8868\uFF08\u53EF\u591A\u4E2A\uFF0C\u7A7A\u683C\u5206\u9694\uFF09").option("--source <type>", "\u6765\u6E90\u7C7B\u578B\uFF08\u5982 manual / batch\uFF09", "manual").option("--no-identify", "\u5173\u95ED\u81EA\u52A8\u8BC6\u522B\u5546\u54C1\u4FE1\u606F\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09").action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bty/customer-service-cli",
3
- "version": "0.6.14",
3
+ "version": "0.6.18",
4
4
  "description": "AI Customer Service CLI - Agent friendly",
5
5
  "type": "module",
6
6
  "main": "./dist/bin.js",