@bty/customer-service-cli 0.5.3 → 0.5.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.
- package/CHANGELOG.md +13 -0
- package/README.md +20 -0
- package/dist/bin.js +253 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.5 (2026-06-07)
|
|
4
|
+
|
|
5
|
+
- 修复 `debug ask --messages` 重放多轮对话时,历史消息时间戳晚于当前时间导致本次 Agent 回复插入历史消息中间、review 页面消息乱序的问题。
|
|
6
|
+
- 发送前将整段历史消息的时间戳统一平移,使最晚消息对齐当前时间;保留消息原有相对顺序与时间间隔,且不修改调用方传入的原始消息对象。
|
|
7
|
+
|
|
8
|
+
## 0.5.4 (2026-06-03)
|
|
9
|
+
|
|
10
|
+
- `ops-agent` 新增 `conversations` 子命令:`ops-agent conversations [--agent-id <id>] [--customer-id <id>] [--page N] [--page-size N]`,对接 `GET /v1/ops-agent/conversations`,按当前 workspace 查询客服助手会话列表,返回 `workspace_id`、`customer_id`、`title`、`agent_id`、`created_at`、`updated_at`。
|
|
11
|
+
- 补充 `ops-agent` 命令注册测试与 API 客户端测试,覆盖会话列表查询命令注册、请求路径、workspace 透传与筛选参数。
|
|
12
|
+
- `product` 新增 `identify-all` 子命令:`product identify-all --agent <id>`,对接 `POST /v1/knowledge/products/identify/all`,为当前 Agent 一键提交所有待增强商品进入增强学习队列。
|
|
13
|
+
- 补充 `product` CLI 测试与 API 客户端测试,覆盖增强学习命令注册、请求路径与请求体。
|
|
14
|
+
- `testset` 新增 `create` 子命令:`testset create --customer-agent-config-id <id> --file <cases.xlsx> [--name <text>] [--description <text>] [--use-type <text>]`,对接 `POST /v1/test_sets/file/upload`,通过 xlsx 模板上传创建测试集。
|
|
15
|
+
|
|
3
16
|
## 0.5.3 (2026-05-28)
|
|
4
17
|
|
|
5
18
|
- 新增 `activity` 主语,覆盖活动 V2(Issue #34)增删改查 + per-tenant 总开关。对接 `customer-servhub-api /v1/activity*`,契约详情参见 [`docs/devkit/specs/2026-05-28-activity-v2-api-reference.md`](../../docs/devkit/specs/2026-05-28-activity-v2-api-reference.md):
|
package/README.md
CHANGED
|
@@ -224,6 +224,7 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
|
224
224
|
| `product update-sku --agent <id> (--sku <SKU名称> \| --sku-id <id>) --update <json\|@file>` | 更新 SKU 信息(`--sku-id` 优先于 `--sku`) |
|
|
225
225
|
| `product add --agent <id> --data <json\|@file> [--source <type>] [--no-identify]` | 直接传入结构化商品数据(JSON 数组)异步学习(manual / identify 默认开启) |
|
|
226
226
|
| `product learn --agent <id> --url <URL...> [--source <type>] [--no-identify]` | 通过商品 URL 异步学习(manual / identify 默认开启) |
|
|
227
|
+
| `product identify-all --agent <id>` | 一键增强学习当前 Agent 下所有待增强商品 |
|
|
227
228
|
| `product sync-taobao --agent <id> [--skip-hash-check] [--sync-type <full\|incremental>]` | 触发淘宝店铺商品同步 |
|
|
228
229
|
| `product sync-taobao-item --agent <id> --product-id <商品ID>` | 触发单个淘宝商品同步 |
|
|
229
230
|
|
|
@@ -233,6 +234,8 @@ cs-cli workspace points-consumes-daily --start 2026-04-01 --end 2026-04-23
|
|
|
233
234
|
|
|
234
235
|
`product learn` 提交商品详情页 URL 进入异步学习队列(`/v1/knowledge/products/upload`),返回 `flow_id` 和 `knowledge_ids`。`--url` 可多值,用空格分隔;`--source` 默认 `manual`;传 `--no-identify` 可关闭自动识别。
|
|
235
236
|
|
|
237
|
+
`product identify-all` 对接 `POST /v1/knowledge/products/identify/all`,会为当前 Agent 一键提交所有“已可用但尚未增强”的商品进入增强学习队列。它不是全量重学;当没有待增强商品时,服务端会返回“暂无需要识图的商品”。
|
|
238
|
+
|
|
236
239
|
`product sync-taobao` / `product sync-taobao-item` 调用 customer-servhub-api 的授权店铺同步接口,要求 `--agent` 已唯一绑定一个淘宝授权店铺。前者支持 `--sync-type full|incremental`,默认 `full`;后者按 `product_id` 补同步单个淘宝商品。
|
|
237
240
|
|
|
238
241
|
注意:这两个命令仅对已开通“高级工具”的店铺 Agent 生效。未开通高级工具时,即使 `--agent` 已绑定淘宝授权店铺,请求也可能在服务端失败。
|
|
@@ -578,6 +581,7 @@ cs-cli change-consumer delivery complete <delivery_id> --status completed \
|
|
|
578
581
|
| 命令 | 说明 |
|
|
579
582
|
| --- | --- |
|
|
580
583
|
| `testset list --customer-agent-config-id <id>` | 列出测试集(分页,Agent ID 必填) |
|
|
584
|
+
| `testset create --customer-agent-config-id <id> --file <cases.xlsx> [--name ...] [--description ...] [--use-type ...]` | 通过 xlsx 模板上传创建测试集 |
|
|
581
585
|
| `testset show <id>` | 测试集详情 |
|
|
582
586
|
| `testset update <id> [--name ...] [--description ...] [--data @file.json]` | 更新测试集元数据(至少一项) |
|
|
583
587
|
| `testset delete <id>` | 软删除测试集 |
|
|
@@ -827,3 +831,19 @@ cs-cli ops-record update <record_id> --data '{"remark":"已完成配置更新","
|
|
|
827
831
|
# 删除运维操作记录
|
|
828
832
|
cs-cli ops-record delete <record_id>
|
|
829
833
|
```
|
|
834
|
+
|
|
835
|
+
### Ops Agent (`ops-agent`)
|
|
836
|
+
|
|
837
|
+
| 命令 | 说明 |
|
|
838
|
+
| --- | --- |
|
|
839
|
+
| `ops-agent conversations [--agent-id <id>] [--customer-id <id>] [--page N] [--page-size N]` | 查询客服助手会话列表 |
|
|
840
|
+
|
|
841
|
+
`ops-agent conversations` 对接 `customer-servhub-api /v1/ops-agent/conversations`,返回字段固定为 `workspace_id`、`customer_id`、`title`、`agent_id`、`created_at`、`updated_at`。命令会自动带当前 `workspace-id`;`--agent-id` 对应 Ops Agent 配置 ID(`customer_agent_config_id`),`--customer-id` 可选。
|
|
842
|
+
|
|
843
|
+
```bash
|
|
844
|
+
# 查询当前 workspace 下某个客服运维助手的会话
|
|
845
|
+
cs-cli ops-agent conversations --agent-id <customer_agent_config_id>
|
|
846
|
+
|
|
847
|
+
# 按 customer 进一步过滤
|
|
848
|
+
cs-cli ops-agent conversations --agent-id <customer_agent_config_id> --customer-id <customer_id>
|
|
849
|
+
```
|
package/dist/bin.js
CHANGED
|
@@ -276,7 +276,7 @@ function toExitCode(err) {
|
|
|
276
276
|
return 1;
|
|
277
277
|
}
|
|
278
278
|
function createRequest(globalTimeout) {
|
|
279
|
-
return async function request(baseUrl,
|
|
279
|
+
return async function request(baseUrl, path6, options) {
|
|
280
280
|
const headers = {
|
|
281
281
|
"Content-Type": "application/json",
|
|
282
282
|
...options.headers
|
|
@@ -304,7 +304,7 @@ function createRequest(globalTimeout) {
|
|
|
304
304
|
if (workspaceId) {
|
|
305
305
|
headers["workspace-id"] = workspaceId;
|
|
306
306
|
}
|
|
307
|
-
let url = `${baseUrl}${
|
|
307
|
+
let url = `${baseUrl}${path6}`;
|
|
308
308
|
if (options.query) {
|
|
309
309
|
const params = new URLSearchParams();
|
|
310
310
|
for (const [key, value] of Object.entries(options.query)) {
|
|
@@ -1343,22 +1343,22 @@ function registerConversationCommand(program2) {
|
|
|
1343
1343
|
var DASHBOARD_PREFIX = "/v1/dashboard";
|
|
1344
1344
|
async function getDashboardSummary(opts) {
|
|
1345
1345
|
const request = createRequest();
|
|
1346
|
-
const
|
|
1346
|
+
const path6 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/summary` : `${DASHBOARD_PREFIX}/summary`;
|
|
1347
1347
|
const query = {};
|
|
1348
1348
|
if (opts.startDate) query.start_date = opts.startDate;
|
|
1349
1349
|
if (opts.endDate) query.end_date = opts.endDate;
|
|
1350
1350
|
if (opts.channel) query.channel = opts.channel;
|
|
1351
|
-
return request(getCustomerServiceUrl(),
|
|
1351
|
+
return request(getCustomerServiceUrl(), path6, { method: "GET", query });
|
|
1352
1352
|
}
|
|
1353
1353
|
async function getDashboardTrend(opts) {
|
|
1354
1354
|
const request = createRequest();
|
|
1355
|
-
const
|
|
1355
|
+
const path6 = opts.configId ? `${DASHBOARD_PREFIX}/${opts.configId}/trend` : `${DASHBOARD_PREFIX}/trend`;
|
|
1356
1356
|
const query = {};
|
|
1357
1357
|
if (opts.startDate) query.start_date = opts.startDate;
|
|
1358
1358
|
if (opts.endDate) query.end_date = opts.endDate;
|
|
1359
1359
|
if (opts.granularity) query.granularity = opts.granularity;
|
|
1360
1360
|
if (opts.channel) query.channel = opts.channel;
|
|
1361
|
-
return request(getCustomerServiceUrl(),
|
|
1361
|
+
return request(getCustomerServiceUrl(), path6, { method: "GET", query });
|
|
1362
1362
|
}
|
|
1363
1363
|
async function listShopStatistics(opts) {
|
|
1364
1364
|
const request = createRequest();
|
|
@@ -1578,12 +1578,12 @@ function registerDashboardCommand(program2) {
|
|
|
1578
1578
|
channel: opts.channel
|
|
1579
1579
|
});
|
|
1580
1580
|
if (opts.out) {
|
|
1581
|
-
const { path:
|
|
1581
|
+
const { path: path6, bytes } = await writeBinaryToFile(
|
|
1582
1582
|
opts.out,
|
|
1583
1583
|
Buffer.from(result.csv, "utf-8")
|
|
1584
1584
|
);
|
|
1585
1585
|
formatOutput(
|
|
1586
|
-
{ success: true, data: { path:
|
|
1586
|
+
{ success: true, data: { path: path6, bytes, count: result.rows.length } },
|
|
1587
1587
|
program2.opts().table
|
|
1588
1588
|
);
|
|
1589
1589
|
} else {
|
|
@@ -1628,6 +1628,23 @@ function registerDashboardCommand(program2) {
|
|
|
1628
1628
|
|
|
1629
1629
|
// src/client/debug-api.ts
|
|
1630
1630
|
var DEFAULT_FLOW_WORKSPACE_ID = "531c14d1ece047cbaec22914e1f1364d";
|
|
1631
|
+
function toTimestampSeconds(value) {
|
|
1632
|
+
const timestamp = typeof value === "string" && Number.isNaN(Number(value)) ? Math.floor(new Date(value).getTime() / 1e3) : Math.floor(Number(value));
|
|
1633
|
+
if (!Number.isFinite(timestamp)) return null;
|
|
1634
|
+
return timestamp > 9999999999 ? Math.floor(timestamp / 1e3) : timestamp;
|
|
1635
|
+
}
|
|
1636
|
+
function rebaseMsgListTimestamps(msgList) {
|
|
1637
|
+
const timestamps = msgList.map(
|
|
1638
|
+
(message) => typeof message === "object" && message !== null ? toTimestampSeconds(message.timestamp) : null
|
|
1639
|
+
).filter((timestamp) => timestamp !== null);
|
|
1640
|
+
if (timestamps.length === 0) return msgList;
|
|
1641
|
+
const offset = Math.floor(Date.now() / 1e3) - Math.max(...timestamps);
|
|
1642
|
+
return msgList.map((message) => {
|
|
1643
|
+
if (typeof message !== "object" || message === null) return message;
|
|
1644
|
+
const timestamp = toTimestampSeconds(message.timestamp);
|
|
1645
|
+
return timestamp === null ? message : { ...message, timestamp: timestamp + offset };
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1631
1648
|
async function createDebugConversation(opts) {
|
|
1632
1649
|
const request = createRequest();
|
|
1633
1650
|
return request(getCustomerServiceUrl(), "/v1/chat/conversation", {
|
|
@@ -1642,7 +1659,7 @@ async function createDebugConversation(opts) {
|
|
|
1642
1659
|
async function sendAgentMessage(opts) {
|
|
1643
1660
|
let msgList;
|
|
1644
1661
|
if (opts.msgList) {
|
|
1645
|
-
msgList = opts.msgList;
|
|
1662
|
+
msgList = rebaseMsgListTimestamps(opts.msgList);
|
|
1646
1663
|
} else {
|
|
1647
1664
|
if (opts.text == null) {
|
|
1648
1665
|
throw new Error("sendAgentMessage: either msgList or text must be provided");
|
|
@@ -3769,6 +3786,44 @@ function registerMonitorCommand(program2) {
|
|
|
3769
3786
|
});
|
|
3770
3787
|
}
|
|
3771
3788
|
|
|
3789
|
+
// src/client/ops-agent-api.ts
|
|
3790
|
+
async function listOpsAgentConversations(opts) {
|
|
3791
|
+
const workspaceId = getWorkspaceId(opts.workspaceId);
|
|
3792
|
+
const request = createRequest();
|
|
3793
|
+
const query = {
|
|
3794
|
+
page: opts.page ?? 1,
|
|
3795
|
+
page_size: opts.pageSize ?? 20
|
|
3796
|
+
};
|
|
3797
|
+
if (opts.customerId) query.customer_id = opts.customerId;
|
|
3798
|
+
if (opts.agentId) query.agent_id = opts.agentId;
|
|
3799
|
+
return request(getCustomerServiceUrl(), "/v1/ops-agent/conversations", {
|
|
3800
|
+
method: "GET",
|
|
3801
|
+
query,
|
|
3802
|
+
headers: { "workspace-id": workspaceId }
|
|
3803
|
+
});
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
// src/commands/ops-agent.ts
|
|
3807
|
+
function registerOpsAgentCommand(program2) {
|
|
3808
|
+
const opsAgent = program2.command("ops-agent").description("Ops Agent\uFF08\u5BA2\u670D\u52A9\u624B\uFF09\u67E5\u8BE2\u547D\u4EE4");
|
|
3809
|
+
opsAgent.command("conversations").description(
|
|
3810
|
+
"\u67E5\u8BE2\u5BA2\u670D\u52A9\u624B\u4F1A\u8BDD\u5217\u8868\u3002\u8FD4\u56DE workspace_id\u3001customer_id\u3001title\u3001agent_id\u3001created_at\u3001updated_at"
|
|
3811
|
+
).option("--customer-id <id>", "\u6309 customer_id \u7B5B\u9009").option("--agent-id <id>", "\u6309 Ops Agent \u914D\u7F6E ID\uFF08customer_agent_config_id\uFF09\u7B5B\u9009").option("--page <number>", "\u9875\u7801", "1").option("--page-size <number>", "\u6BCF\u9875\u6570\u91CF", "20").action(async (opts) => {
|
|
3812
|
+
try {
|
|
3813
|
+
const data = await listOpsAgentConversations({
|
|
3814
|
+
customerId: opts.customerId,
|
|
3815
|
+
agentId: opts.agentId,
|
|
3816
|
+
page: Number(opts.page),
|
|
3817
|
+
pageSize: Number(opts.pageSize)
|
|
3818
|
+
});
|
|
3819
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
3820
|
+
} catch (err) {
|
|
3821
|
+
reportCaughtError(err);
|
|
3822
|
+
process.exit(toExitCode(err));
|
|
3823
|
+
}
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3772
3827
|
// src/client/operations-record-api.ts
|
|
3773
3828
|
var PATH_PREFIX2 = "/v1/agent_operations_records";
|
|
3774
3829
|
async function listOperationsRecords(opts) {
|
|
@@ -3981,6 +4036,15 @@ async function syncSingleTaobaoProduct(opts) {
|
|
|
3981
4036
|
}
|
|
3982
4037
|
});
|
|
3983
4038
|
}
|
|
4039
|
+
async function identifyAllProducts(opts) {
|
|
4040
|
+
const request = createRequest();
|
|
4041
|
+
return request(getCustomerServiceUrl(), "/v1/knowledge/products/identify/all", {
|
|
4042
|
+
method: "POST",
|
|
4043
|
+
body: {
|
|
4044
|
+
customer_agent_config_id: opts.agentConfigId
|
|
4045
|
+
}
|
|
4046
|
+
});
|
|
4047
|
+
}
|
|
3984
4048
|
|
|
3985
4049
|
// src/commands/product.ts
|
|
3986
4050
|
async function getDbId(agentConfigId) {
|
|
@@ -4118,6 +4182,19 @@ function registerProductCommand(program2) {
|
|
|
4118
4182
|
process.exit(toExitCode(err));
|
|
4119
4183
|
}
|
|
4120
4184
|
});
|
|
4185
|
+
product.command("identify-all").description(
|
|
4186
|
+
"\u4E00\u952E\u589E\u5F3A\u5B66\u4E60\u5F53\u524D Agent \u4E0B\u6240\u6709\u5F85\u589E\u5F3A\u5546\u54C1\u3002\u5BF9\u63A5 POST /v1/knowledge/products/identify/all\uFF0C\u5F02\u6B65\u63D0\u4EA4\u5546\u54C1\u589E\u5F3A\u5B66\u4E60\u4EFB\u52A1"
|
|
4187
|
+
).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u4ECE agent list \u83B7\u53D6\uFF09").action(async (opts) => {
|
|
4188
|
+
try {
|
|
4189
|
+
const data = await identifyAllProducts({
|
|
4190
|
+
agentConfigId: opts.agent
|
|
4191
|
+
});
|
|
4192
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4193
|
+
} catch (err) {
|
|
4194
|
+
reportCaughtError(err);
|
|
4195
|
+
process.exit(toExitCode(err));
|
|
4196
|
+
}
|
|
4197
|
+
});
|
|
4121
4198
|
product.command("sync-taobao").description(
|
|
4122
4199
|
"\u89E6\u53D1\u6DD8\u5B9D\u5E97\u94FA\u5546\u54C1\u540C\u6B65\u3002\u8C03\u7528 customer-servhub-api \u7684\u6388\u6743\u5E97\u94FA\u540C\u6B65\u63A5\u53E3\uFF0C\u6309 Agent \u914D\u7F6E\u627E\u5230\u552F\u4E00\u7ED1\u5B9A\u5E97\u94FA\u540E\u5F02\u6B65\u542F\u52A8\u540C\u6B65\u4EFB\u52A1"
|
|
4123
4200
|
).requiredOption("--agent <config_id>", "Agent \u914D\u7F6E ID\uFF08\u5FC5\u987B\u5DF2\u552F\u4E00\u7ED1\u5B9A\u4E00\u4E2A\u6DD8\u5B9D\u6388\u6743\u5E97\u94FA\uFF09").option("--skip-hash-check", "\u8DF3\u8FC7\u54C8\u5E0C\u6821\u9A8C\uFF0C\u5F3A\u5236\u91CD\u65B0\u540C\u6B65\u5546\u54C1").option("--sync-type <type>", "\u540C\u6B65\u7C7B\u578B\uFF1Afull / incremental\uFF0C\u9ED8\u8BA4 full", "full").action(async (opts) => {
|
|
@@ -4467,10 +4544,132 @@ function registerSACommand(program2) {
|
|
|
4467
4544
|
});
|
|
4468
4545
|
}
|
|
4469
4546
|
|
|
4470
|
-
// src/commands/
|
|
4547
|
+
// src/commands/special-project.ts
|
|
4471
4548
|
import fs9 from "fs";
|
|
4472
4549
|
|
|
4550
|
+
// src/client/special-project-api.ts
|
|
4551
|
+
async function createSpecialProject(input) {
|
|
4552
|
+
const request = createRequest();
|
|
4553
|
+
return request(getCsAdminUrl(), "/api/special-projects", {
|
|
4554
|
+
method: "POST",
|
|
4555
|
+
body: input
|
|
4556
|
+
});
|
|
4557
|
+
}
|
|
4558
|
+
async function listSpecialProjects(opts = {}) {
|
|
4559
|
+
const request = createRequest();
|
|
4560
|
+
const query = {};
|
|
4561
|
+
if (opts.ownerUserId !== void 0) query.ownerUserId = opts.ownerUserId;
|
|
4562
|
+
if (opts.status) query.status = opts.status;
|
|
4563
|
+
const result = await request(getCsAdminUrl(), "/api/special-projects", {
|
|
4564
|
+
method: "GET",
|
|
4565
|
+
query
|
|
4566
|
+
});
|
|
4567
|
+
return result.rows ?? [];
|
|
4568
|
+
}
|
|
4569
|
+
async function updateSpecialProject(projectId, patch) {
|
|
4570
|
+
const request = createRequest();
|
|
4571
|
+
return request(
|
|
4572
|
+
getCsAdminUrl(),
|
|
4573
|
+
`/api/special-projects/${projectId}`,
|
|
4574
|
+
{ method: "PATCH", body: patch }
|
|
4575
|
+
);
|
|
4576
|
+
}
|
|
4577
|
+
async function closeSpecialProject(projectId) {
|
|
4578
|
+
return updateSpecialProject(projectId, { status: "\u5DF2\u5B8C\u6210" });
|
|
4579
|
+
}
|
|
4580
|
+
async function upsertSpecialProjects(items, apply) {
|
|
4581
|
+
const request = createRequest();
|
|
4582
|
+
return request(getCsAdminUrl(), "/api/special-projects/batch", {
|
|
4583
|
+
method: "POST",
|
|
4584
|
+
body: { items, apply }
|
|
4585
|
+
});
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
// src/commands/special-project.ts
|
|
4589
|
+
function readJsonArg(value) {
|
|
4590
|
+
if (value.startsWith("@")) {
|
|
4591
|
+
return fs9.readFileSync(value.slice(1), "utf-8");
|
|
4592
|
+
}
|
|
4593
|
+
return value;
|
|
4594
|
+
}
|
|
4595
|
+
function registerSpecialProjectCommand(program2) {
|
|
4596
|
+
const sp = program2.command("special-project").description(
|
|
4597
|
+
"\u4E13\u9879\uFF08special_project\uFF09\u7BA1\u7406 \u2014\u2014 \u5DE5\u4F5C\u8D1F\u8F7D\u770B\u677F\u7684\u4E13\u9879\u6570\u636E\u3002\u4E3B\u529B\u5F55\u5165\u901A\u9053\uFF1A\u65E9\u4F1A\u9010\u5B57\u7A3F \u2192 Agent \u89E3\u6790 \u2192 upsert\uFF08\u5148\u770B diff\uFF0C\u786E\u8BA4\u540E --apply\uFF09"
|
|
4598
|
+
);
|
|
4599
|
+
sp.command("create").description("\u521B\u5EFA\u5355\u4E2A\u4E13\u9879").requiredOption("--name <name>", "\u4E13\u9879\u540D").requiredOption("--owner <id>", "\u627F\u63A5\u5DE5\u7A0B\u5E08 cs_admin_user_id").requiredOption("--daily-effort <personDays>", "\u9884\u4F30\u6BCF\u65E5\u6295\u5165\uFF08\u4EBA\u5929\uFF0C\u5982 0.5\uFF09").requiredOption("--start-date <YYYY-MM-DD>", "\u5F00\u59CB\u65E5\u671F").requiredOption("--duration-days <n>", "\u9884\u4F30\u6709\u6548\u6295\u5165\u5929\u6570").option("--workspace <id>", "\u5173\u8054\u5BA2\u6237 workspace_id\uFF08\u53EF\u7A7A\uFF0C\u5185\u90E8\u4E13\u9879\u4E0D\u586B\uFF09").option("--description <text>", "\u63CF\u8FF0").option("--source-ref <ref>", "\u7A33\u5B9A\u5916\u90E8\u952E\uFF08\u9010\u5B57\u7A3F\u6765\u6E90 id\uFF09\uFF0Cupsert \u5E42\u7B49\u7528").action(async (opts) => {
|
|
4600
|
+
try {
|
|
4601
|
+
const data = await createSpecialProject({
|
|
4602
|
+
name: opts.name,
|
|
4603
|
+
ownerUserId: Number(opts.owner),
|
|
4604
|
+
dailyEffort: Number(opts.dailyEffort),
|
|
4605
|
+
startDate: opts.startDate,
|
|
4606
|
+
durationDays: Number(opts.durationDays),
|
|
4607
|
+
workspaceId: opts.workspace,
|
|
4608
|
+
description: opts.description,
|
|
4609
|
+
sourceRef: opts.sourceRef
|
|
4610
|
+
});
|
|
4611
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4612
|
+
} catch (err) {
|
|
4613
|
+
reportCaughtError(err);
|
|
4614
|
+
process.exit(toExitCode(err));
|
|
4615
|
+
}
|
|
4616
|
+
});
|
|
4617
|
+
sp.command("list").description("\u5217\u51FA\u4E13\u9879").option("--owner <id>", "\u6309\u627F\u63A5\u5DE5\u7A0B\u5E08 cs_admin_user_id \u8FC7\u6EE4").option("--status <status>", "\u6309\u72B6\u6001\u8FC7\u6EE4\uFF08\u8FDB\u884C\u4E2D/\u6682\u505C/\u9700\u786E\u8BA4/\u5DF2\u5B8C\u6210\uFF09").action(async (opts) => {
|
|
4618
|
+
try {
|
|
4619
|
+
const data = await listSpecialProjects({
|
|
4620
|
+
ownerUserId: opts.owner !== void 0 ? Number(opts.owner) : void 0,
|
|
4621
|
+
status: opts.status
|
|
4622
|
+
});
|
|
4623
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4624
|
+
} catch (err) {
|
|
4625
|
+
reportCaughtError(err);
|
|
4626
|
+
process.exit(toExitCode(err));
|
|
4627
|
+
}
|
|
4628
|
+
});
|
|
4629
|
+
sp.command("update <id>").description("\u66F4\u65B0\u4E13\u9879\uFF08\u4EFB\u610F\u5B50\u96C6\uFF1B\u72B6\u6001\u8FC1\u79FB\u53D7\u670D\u52A1\u7AEF\u72B6\u6001\u673A\u7EA6\u675F\uFF09").option("--progress <n>", "\u8FDB\u5EA6 0-100").option("--status <status>", "\u72B6\u6001\uFF08\u8FDB\u884C\u4E2D/\u6682\u505C/\u9700\u786E\u8BA4/\u5DF2\u5B8C\u6210\uFF09").option("--daily-effort <personDays>", "\u6BCF\u65E5\u6295\u5165\uFF08\u4EBA\u5929\uFF09").option("--duration-days <n>", "\u6709\u6548\u6295\u5165\u5929\u6570").option("--description <text>", "\u63CF\u8FF0").action(async (id, opts) => {
|
|
4630
|
+
try {
|
|
4631
|
+
const patch = {};
|
|
4632
|
+
if (opts.progress !== void 0) patch.progress = Number(opts.progress);
|
|
4633
|
+
if (opts.status !== void 0) patch.status = opts.status;
|
|
4634
|
+
if (opts.dailyEffort !== void 0) patch.dailyEffort = Number(opts.dailyEffort);
|
|
4635
|
+
if (opts.durationDays !== void 0) patch.durationDays = Number(opts.durationDays);
|
|
4636
|
+
if (opts.description !== void 0) patch.description = opts.description;
|
|
4637
|
+
const data = await updateSpecialProject(Number(id), patch);
|
|
4638
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4639
|
+
} catch (err) {
|
|
4640
|
+
reportCaughtError(err);
|
|
4641
|
+
process.exit(toExitCode(err));
|
|
4642
|
+
}
|
|
4643
|
+
});
|
|
4644
|
+
sp.command("close <id>").description("\u5173\u95ED\u4E13\u9879\uFF08\u7F6E\u4E3A\u5DF2\u5B8C\u6210\uFF09").action(async (id) => {
|
|
4645
|
+
try {
|
|
4646
|
+
const data = await closeSpecialProject(Number(id));
|
|
4647
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4648
|
+
} catch (err) {
|
|
4649
|
+
reportCaughtError(err);
|
|
4650
|
+
process.exit(toExitCode(err));
|
|
4651
|
+
}
|
|
4652
|
+
});
|
|
4653
|
+
sp.command("upsert").description(
|
|
4654
|
+
"\u6279\u91CF upsert\uFF08\u9010\u5B57\u7A3F\u540C\u6B65\uFF09\u3002--items \u63A5 JSON \u6570\u7EC4\u6216 @\u6587\u4EF6\u3002\u9ED8\u8BA4\u53EA\u6253\u5370 diff \u4E0D\u5199\u5E93\uFF1B\u52A0 --apply \u624D\u843D\u5E93"
|
|
4655
|
+
).requiredOption("--items <json|@file>", "items JSON \u6570\u7EC4\uFF0C\u6216 @path \u8BFB\u6587\u4EF6").option("--apply", "\u843D\u5E93\uFF08\u7F3A\u7701\u53EA\u7B97 diff \u4E0D\u5199\uFF09", false).action(async (opts) => {
|
|
4656
|
+
try {
|
|
4657
|
+
const items = JSON.parse(readJsonArg(opts.items));
|
|
4658
|
+
const data = await upsertSpecialProjects(items, opts.apply === true);
|
|
4659
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
4660
|
+
} catch (err) {
|
|
4661
|
+
reportCaughtError(err);
|
|
4662
|
+
process.exit(toExitCode(err));
|
|
4663
|
+
}
|
|
4664
|
+
});
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
// src/commands/testset.ts
|
|
4668
|
+
import fs11 from "fs";
|
|
4669
|
+
|
|
4473
4670
|
// src/client/testset-api.ts
|
|
4671
|
+
import fs10 from "fs";
|
|
4672
|
+
import path5 from "path";
|
|
4474
4673
|
function unwrapPaginated(raw, fallbackPageSize) {
|
|
4475
4674
|
return {
|
|
4476
4675
|
items: Array.isArray(raw?.data) ? raw?.data : [],
|
|
@@ -4496,6 +4695,28 @@ async function listTestSets(query) {
|
|
|
4496
4695
|
);
|
|
4497
4696
|
return unwrapPaginated(raw, query.pageSize ?? 20);
|
|
4498
4697
|
}
|
|
4698
|
+
async function createTestSetFromFile(input) {
|
|
4699
|
+
const request = createRequest();
|
|
4700
|
+
const fileBytes = fs10.readFileSync(input.filePath);
|
|
4701
|
+
const formData = new FormData();
|
|
4702
|
+
formData.append(
|
|
4703
|
+
"file",
|
|
4704
|
+
new Blob([fileBytes], {
|
|
4705
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
4706
|
+
}),
|
|
4707
|
+
path5.basename(input.filePath)
|
|
4708
|
+
);
|
|
4709
|
+
return request(getCustomerServiceUrl(), "/v1/test_sets/file/upload", {
|
|
4710
|
+
method: "POST",
|
|
4711
|
+
query: {
|
|
4712
|
+
customer_agent_config_id: input.customerAgentConfigId,
|
|
4713
|
+
test_set_name: input.testSetName,
|
|
4714
|
+
test_set_description: input.testSetDescription,
|
|
4715
|
+
use_type: input.useType
|
|
4716
|
+
},
|
|
4717
|
+
body: formData
|
|
4718
|
+
});
|
|
4719
|
+
}
|
|
4499
4720
|
async function getTestSet(id) {
|
|
4500
4721
|
const request = createRequest();
|
|
4501
4722
|
return request(getCustomerServiceUrl(), `/v1/test_sets/${id}`, {
|
|
@@ -4980,7 +5201,7 @@ function readPromptInput(value) {
|
|
|
4980
5201
|
if (!filePath) {
|
|
4981
5202
|
throw new Error("File path cannot be empty after @");
|
|
4982
5203
|
}
|
|
4983
|
-
return
|
|
5204
|
+
return fs11.readFileSync(filePath, "utf-8");
|
|
4984
5205
|
}
|
|
4985
5206
|
return value;
|
|
4986
5207
|
}
|
|
@@ -5013,6 +5234,25 @@ function registerTestsetCommand(program2) {
|
|
|
5013
5234
|
process.exit(toExitCode(err));
|
|
5014
5235
|
}
|
|
5015
5236
|
});
|
|
5237
|
+
testset.command("create").description("\u901A\u8FC7 xlsx \u6587\u4EF6\u521B\u5EFA\u6D4B\u8BD5\u96C6").requiredOption("--customer-agent-config-id <id>", "Agent \u914D\u7F6E ID\uFF08\u5FC5\u586B\uFF0C\u4E0E\u540E\u7AEF\u5951\u7EA6\u5BF9\u9F50\uFF09").requiredOption("--file <path>", "\u6D4B\u8BD5\u96C6 xlsx \u6587\u4EF6\u8DEF\u5F84").option("--name <text>", "\u6D4B\u8BD5\u96C6\u540D\u79F0\uFF1B\u4E0D\u4F20\u5219\u540E\u7AEF\u53D6\u6587\u4EF6\u540D").option("--description <text>", "\u6D4B\u8BD5\u96C6\u63CF\u8FF0").option("--use-type <text>", "\u6587\u4EF6\u7528\u9014\u6807\u8BC6").action(async (opts) => {
|
|
5238
|
+
try {
|
|
5239
|
+
if (!fs11.existsSync(opts.file)) {
|
|
5240
|
+
outputError(1, `\u6587\u4EF6\u4E0D\u5B58\u5728: ${opts.file}`);
|
|
5241
|
+
process.exit(1);
|
|
5242
|
+
}
|
|
5243
|
+
const data = await createTestSetFromFile({
|
|
5244
|
+
customerAgentConfigId: opts.customerAgentConfigId,
|
|
5245
|
+
filePath: opts.file,
|
|
5246
|
+
testSetName: opts.name,
|
|
5247
|
+
testSetDescription: opts.description,
|
|
5248
|
+
useType: opts.useType
|
|
5249
|
+
});
|
|
5250
|
+
formatOutput({ success: true, data }, program2.opts().table);
|
|
5251
|
+
} catch (err) {
|
|
5252
|
+
reportCaughtError(err);
|
|
5253
|
+
process.exit(toExitCode(err));
|
|
5254
|
+
}
|
|
5255
|
+
});
|
|
5016
5256
|
testset.command("show").description("\u67E5\u770B\u5355\u4E2A\u6D4B\u8BD5\u96C6\u8BE6\u60C5").argument("<id>", "\u6D4B\u8BD5\u96C6 ID").action(async (id) => {
|
|
5017
5257
|
try {
|
|
5018
5258
|
const data = await getTestSet(id);
|
|
@@ -5165,6 +5405,7 @@ registerAuthCommand(program);
|
|
|
5165
5405
|
registerConfigCommand(program);
|
|
5166
5406
|
registerWorkspaceCommand(program);
|
|
5167
5407
|
registerAgentCommand(program);
|
|
5408
|
+
registerOpsAgentCommand(program);
|
|
5168
5409
|
registerSACommand(program);
|
|
5169
5410
|
registerProductCommand(program);
|
|
5170
5411
|
registerKnowledgeCommand(program);
|
|
@@ -5180,6 +5421,7 @@ registerRepairRecordCommand(program);
|
|
|
5180
5421
|
registerOperationsRecordCommand(program);
|
|
5181
5422
|
registerChangeConsumerCommand(program);
|
|
5182
5423
|
registerTestsetCommand(program);
|
|
5424
|
+
registerSpecialProjectCommand(program);
|
|
5183
5425
|
process.on("uncaughtException", (err) => {
|
|
5184
5426
|
outputError(3, err.message);
|
|
5185
5427
|
process.exit(3);
|