@bty/customer-service-cli 0.6.10 → 0.6.12

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.12 (2026-08-31)
4
+
5
+ - `channel-metric query` 新增 `--format json|markdown|table`(默认 json):markdown 输出适合贴文档/群消息,table 输出终端表格;json 保持原结构不变。
6
+
7
+ ## 0.6.11 (2026-08-27)
8
+
9
+ - `workspace points-consumes` 改用 `customer-observability-api` 备库 Cursor 接口,支持 `--cursor`、`--start`、`--end`、`--limit`,可继续读取超过 10000 条的历史积分流水。
10
+
3
11
  ## 0.6.10 (2026-08-26)
4
12
 
5
13
  - `context-search`:`query_content` 增加最少 2 个字符的本地校验,避免过短关键词触发服务端全量扫描。
package/dist/bin.js CHANGED
@@ -1159,11 +1159,42 @@ function renderGroupedTable(groups) {
1159
1159
  \u5171 ${total} \u6761\u8BB0\u5F55
1160
1160
  `);
1161
1161
  }
1162
+ function renderMarkdownTable(groups) {
1163
+ let total = 0;
1164
+ const escape = (value) => value.replace(/\|/g, "\\|");
1165
+ for (const group of groups) {
1166
+ process.stdout.write(`
1167
+ ### ${group.stat_date} \xB7 ${group.channel}\uFF08${group.items.length} \u4E2A\u8D26\u53F7\uFF09
1168
+
1169
+ `);
1170
+ const first = group.items[0];
1171
+ const headers = (first?.metrics_json ?? []).map((field) => field.label);
1172
+ const headCells = ["account_id", ...headers].map(escape);
1173
+ process.stdout.write(`| ${headCells.join(" | ")} |
1174
+ `);
1175
+ process.stdout.write(`| ${headCells.map(() => "---").join(" | ")} |
1176
+ `);
1177
+ for (const row of group.items) {
1178
+ const cells = [
1179
+ String(row.account_id),
1180
+ ...row.metrics_json.map(
1181
+ (field) => field.value === void 0 || field.value === null ? "-" : escape(String(field.value))
1182
+ )
1183
+ ];
1184
+ process.stdout.write(`| ${cells.join(" | ")} |
1185
+ `);
1186
+ }
1187
+ total += group.items.length;
1188
+ }
1189
+ process.stdout.write(`
1190
+ \u5171 ${total} \u6761\u8BB0\u5F55
1191
+ `);
1192
+ }
1162
1193
  function registerChannelMetricCommand(program2) {
1163
1194
  const channelMetric = program2.command("channel-metric").description("\u6E20\u9053\u76D1\u63A7\u6307\u6807\u67E5\u8BE2 \u2014\u2014 \u67E5\u8BE2\u5343\u725B\u7B49\u6E20\u9053\u5E97\u94FA\u5BA2\u670D\u7684\u6BCF\u65E5\u6392\u884C\u6307\u6807\uFF08channel_metric_snapshot\uFF09");
1164
1195
  channelMetric.command("query").description(
1165
1196
  "\u6309 workspace + \u65E5\u671F\u533A\u95F4\uFF08+ \u53EF\u9009 agent / \u6E20\u9053\uFF09\u67E5\u8BE2\u6307\u6807\uFF0C\u6309\u65E5\u671F\xD7\u6E20\u9053\u5206\u7EC4\u8F93\u51FA\u3002\u4E0D\u4F20 --agent \u8F93\u51FA\u8BE5 workspace \u4E0B\u5168\u90E8 agent\uFF0C\u4E0D\u4F20 --platform \u8F93\u51FA\u5168\u90E8\u6E20\u9053"
1166
- ).requiredOption("--workspace-id <workspace_id>", "\u5DE5\u4F5C\u7A7A\u95F4 ID\uFF08\u5FC5\u4F20\uFF0C\u4E0E\u670D\u52A1\u7AEF\u5F52\u5C5E\u6821\u9A8C\u4E00\u81F4\uFF09").option("--agent <agent_id>", "Agent \u914D\u7F6E ID\uFF1B\u7F3A\u7701\u67E5\u8BE2\u8BE5 workspace \u4E0B\u5168\u90E8 agent").requiredOption("--start <date>", "\u8D77\u59CB\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").requiredOption("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").option("--platform <channel>", "\u6E20\u9053\uFF08platform\uFF09\uFF0C\u5982 qianniu\uFF1B\u7F3A\u7701\u67E5\u8BE2\u5168\u90E8\u6E20\u9053").action(async (opts) => {
1197
+ ).requiredOption("--workspace-id <workspace_id>", "\u5DE5\u4F5C\u7A7A\u95F4 ID\uFF08\u5FC5\u4F20\uFF0C\u4E0E\u670D\u52A1\u7AEF\u5F52\u5C5E\u6821\u9A8C\u4E00\u81F4\uFF09").option("--agent <agent_id>", "Agent \u914D\u7F6E ID\uFF1B\u7F3A\u7701\u67E5\u8BE2\u8BE5 workspace \u4E0B\u5168\u90E8 agent").requiredOption("--start <date>", "\u8D77\u59CB\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").requiredOption("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF08YYYY-MM-DD\uFF09").option("--platform <channel>", "\u6E20\u9053\uFF08platform\uFF09\uFF0C\u5982 qianniu\uFF1B\u7F3A\u7701\u67E5\u8BE2\u5168\u90E8\u6E20\u9053").option("--format <format>", "\u8F93\u51FA\u683C\u5F0F\uFF1Ajson\uFF08\u9ED8\u8BA4\uFF09/ markdown / table", "json").action(async (opts) => {
1167
1198
  try {
1168
1199
  setRuntimeWorkspaceId(opts.workspaceId);
1169
1200
  const data = await queryChannelMetrics({
@@ -1174,11 +1205,24 @@ function registerChannelMetricCommand(program2) {
1174
1205
  channel: opts.platform
1175
1206
  });
1176
1207
  const groups = data?.groups ?? [];
1177
- if (groups.length === 0) {
1178
- process.stdout.write("(empty)\n");
1179
- return;
1208
+ switch (opts.format) {
1209
+ case "markdown":
1210
+ if (groups.length === 0) {
1211
+ process.stdout.write("(empty)\n");
1212
+ return;
1213
+ }
1214
+ renderMarkdownTable(groups);
1215
+ break;
1216
+ case "table":
1217
+ if (groups.length === 0) {
1218
+ process.stdout.write("(empty)\n");
1219
+ return;
1220
+ }
1221
+ renderGroupedTable(groups);
1222
+ break;
1223
+ default:
1224
+ formatOutput({ success: true, data }, false);
1180
1225
  }
1181
- renderGroupedTable(groups);
1182
1226
  } catch (err) {
1183
1227
  reportCaughtError(err);
1184
1228
  process.exit(toExitCode(err));
@@ -1258,16 +1302,31 @@ async function getDailyDeduction(opts) {
1258
1302
  }
1259
1303
  );
1260
1304
  }
1305
+ var MAX_POINTS_CURSOR_PAGES = 500;
1261
1306
  async function getPointsConsumes(opts) {
1262
1307
  const request = createRequest();
1263
- return request(
1264
- getCustomerServiceUrl(),
1265
- "/v1/workspace/points_consumes",
1266
- {
1267
- method: "POST",
1268
- body: { page: opts.page, page_size: opts.pageSize, debug: true }
1308
+ const items = [];
1309
+ let cursor = opts.cursor;
1310
+ let fetchedPages = 0;
1311
+ while (fetchedPages < MAX_POINTS_CURSOR_PAGES) {
1312
+ fetchedPages += 1;
1313
+ const page = await request(getObservabilityUrl(), "/v1/points/consumes", {
1314
+ method: "GET",
1315
+ query: {
1316
+ cursor,
1317
+ start_time: opts.startTime,
1318
+ end_time: opts.endTime,
1319
+ limit: opts.limit
1320
+ }
1321
+ });
1322
+ items.push(...page.items);
1323
+ const nextCursor = page.has_more && page.next_cursor ? page.next_cursor : void 0;
1324
+ if (!nextCursor) {
1325
+ return { ...page, items, next_cursor: null, has_more: false, fetched_pages: fetchedPages };
1269
1326
  }
1270
- );
1327
+ cursor = nextCursor;
1328
+ }
1329
+ throw new Error(`\u79EF\u5206\u6D41\u6C34\u5206\u9875\u8D85\u8FC7 ${MAX_POINTS_CURSOR_PAGES} \u9875\uFF0C\u8BF7\u7F29\u5C0F\u65F6\u95F4\u8303\u56F4`);
1271
1330
  }
1272
1331
 
1273
1332
  // src/commands/config.ts
@@ -7511,17 +7570,18 @@ function registerWorkspaceCommand(program2) {
7511
7570
  process.exit(toExitCode(err));
7512
7571
  }
7513
7572
  });
7514
- workspace.command("points-consumes").description("\u5206\u9875\u67E5\u8BE2\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u7684\u79EF\u5206\u8D26\u6237\u6D88\u8017\u6D41\u6C34\uFF0C\u56FA\u5B9A\u8FD4\u56DE extra \u8C03\u8BD5\u5B57\u6BB5").option("--page <number>", "\u9875\u7801\uFF0C\u9ED8\u8BA4 1", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF\uFF0C\u9ED8\u8BA4 20", "20").action(async (opts) => {
7573
+ workspace.command("points-consumes").description("\u4F7F\u7528\u6E38\u6807\u67E5\u8BE2\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u7684\u79EF\u5206\u6D41\u6C34\uFF08\u8BFB\u53D6\u89C2\u6D4B\u670D\u52A1\u5907\u5E93\uFF09").option("--cursor <token>", "\u4E0B\u4E00\u9875\u6E38\u6807").option("--start <ISO>", "\u8D77\u59CB\u65F6\u95F4\uFF08\u542B\uFF09").option("--end <ISO>", "\u7ED3\u675F\u65F6\u95F4\uFF08\u4E0D\u542B\uFF09").option("--limit <number>", "\u6BCF\u6279\u6570\u91CF\uFF0C\u9ED8\u8BA4 100", "100").action(async (opts) => {
7515
7574
  try {
7516
- const page = Number(opts.page);
7517
- const pageSize = Number(opts.pageSize);
7518
- if (!Number.isInteger(page) || page <= 0) {
7519
- throw new Error("--page \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
7520
- }
7521
- if (!Number.isInteger(pageSize) || pageSize <= 0) {
7522
- throw new Error("--page-size \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
7575
+ const limit = Number(opts.limit);
7576
+ if (!Number.isInteger(limit) || limit <= 0 || limit > 500) {
7577
+ throw new Error("--limit \u5FC5\u987B\u4E3A 1-500 \u7684\u6574\u6570");
7523
7578
  }
7524
- const data = await getPointsConsumes({ page, pageSize });
7579
+ const data = await getPointsConsumes({
7580
+ cursor: opts.cursor,
7581
+ startTime: opts.start,
7582
+ endTime: opts.end,
7583
+ limit
7584
+ });
7525
7585
  formatOutput({ success: true, data }, program2.opts().table);
7526
7586
  } catch (err) {
7527
7587
  reportCaughtError(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bty/customer-service-cli",
3
- "version": "0.6.10",
3
+ "version": "0.6.12",
4
4
  "description": "AI Customer Service CLI - Agent friendly",
5
5
  "type": "module",
6
6
  "main": "./dist/bin.js",