e10-data 0.1.24 → 0.1.26
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 +132 -0
- package/README.md +109 -0
- package/bin/e10-data.mjs +232 -11
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,137 @@
|
|
|
1
1
|
# 变更记录
|
|
2
2
|
|
|
3
|
+
## 0.1.26(2026-10-15)—— 新增 `refusal rules`:拒答话术规则
|
|
4
|
+
|
|
5
|
+
### 1. `refusal` 族新增子命令 `rules`
|
|
6
|
+
|
|
7
|
+
- 端点:`/api/dw/newetl/chatBi/getRefusalSpeechRules`,**无入参**(CLI 不传任何参数,也不提供任何入参开关 —— 参数面比 `refusal get` 更窄);
|
|
8
|
+
返回对象的 `data` = **需要使用的对象数组**(拒答话术规则清单,字段由后端定义、**CLI 不裁剪不改写**;允许为空数组 `[]`,**空 ≠ 失败**)。
|
|
9
|
+
- 调用方式**完全比照 `refusal get`**(同一族、同一策略,排障口径统一):
|
|
10
|
+
- 默认 `--http auto` = 先发 **POST 空 multipart 表单** → 判定拿不到 `data` 才回退 **`GET`(不带 query)**,任一条拿到 `data` 即止
|
|
11
|
+
(正常路径只发 1 次请求;回退仅在首条拿不到 `data` 时触发);
|
|
12
|
+
- `--http post` = 仅 POST 空表单;`--http get` = 仅 GET;取值非法直接报用法错误。
|
|
13
|
+
- 输出:人读直接打印 `data` 数组(漂亮 JSON,缩进 1;空数组打印 `[]` 并向 stderr 提示「拒答话术规则 0 条」);
|
|
14
|
+
`--json` = 原样输出整个响应对象(成功标记看 `actionMsg.code`,无顶层 `code`/`msg`)。
|
|
15
|
+
- 排障:`E10_DATA_DEBUG=1` 向 stderr 打印实际生效通道;两种通道均未拿到 `data` → 抛错并列出每条通道的 `code/msg`;
|
|
16
|
+
凭据失效(401)**不换通道重试**,直接报登录态失效(与 `refusal get` 同口径)。
|
|
17
|
+
- 与 `refusal get` 的**差异仅两点**:① 无入参(表单不带字段 / GET 不带 query);② `data` 是数组而非字符串。
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
e10-data refusal rules # 人读:直接打印规则数组
|
|
21
|
+
e10-data refusal rules --json # 原样输出整个响应对象(data 数组 + actionMsg)
|
|
22
|
+
e10-data refusal rules --http get # 锁定 GET 单通道
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. 同步改动
|
|
26
|
+
|
|
27
|
+
- `CMD_SUBS` 白名单 `refusal: ["get"]` → `refusal: ["get", "rules"]`;
|
|
28
|
+
`main()` 的 `refusal` 分支新增 `rules`;`usage()` 的 `refusal` 帮助段新增 `rules` 条目;
|
|
29
|
+
头部注释新增 `refusal rules` 一行;`README.md` / `CHANGELOG.md` / `package.json`(版本 + description)同步。
|
|
30
|
+
另见 §4:`refusal get` / `refusal rules` 的通道循环抽出为共用实现 `refusalTryModes`(含错误归因,两条命令口径同源)。
|
|
31
|
+
|
|
32
|
+
### 3. 实测确认(2026-10-15)
|
|
33
|
+
|
|
34
|
+
**最终结论(12:43,服务端修复后复测通过)**:
|
|
35
|
+
|
|
36
|
+
- ✅ **POST 空 multipart 表单(不带任何字段)即命中**:`POST /api/dw/newetl/chatBi/getRefusalSpeechRules` →
|
|
37
|
+
`{"data":[…6 条规则…],"actionMsg":{"code":0,"message":"成功"}}` ⇒ **`auto` 正常路径只发 1 次请求**(POST 先命中)。
|
|
38
|
+
- ✅ **GET 同样可用**,且实测 `--http get` 与 `--http post` 的返回体**逐字相同**(`stdout` 全等)⇒ 两条通道均可,
|
|
39
|
+
不存在"只吃其中一条"的情况。
|
|
40
|
+
- **实测数据形状(`data` = 对象数组,6 条)**:元素字段 = `id` / `createTime` / `updateTime` / `creator` / `tenantKey` /
|
|
41
|
+
`deleteType` / `confKey` / `confValue`(话术正文)/ `confAttrs`(命中条件)[/ `confPlan`];
|
|
42
|
+
`confKey` 实测清单 = `加载完成_1`、`交付前_1`、`交付前_2`、`业务域确认完成_1`(带 `confPlan`)、`交付前_3`、`取数前_1`。
|
|
43
|
+
- **人读输出**实测:stderr `# 规则 6 条` + stdout 漂亮 JSON 数组(stdout 纯净,可重定向)。
|
|
44
|
+
|
|
45
|
+
**排障时间线(保留记录,非当前状态)**:本次实测跨了三个阶段,前两阶段的结论**已被推翻**,留档用于复现排障思路 ——
|
|
46
|
+
|
|
47
|
+
1. **401(登录态整体过期)**:首次测试时请求在网关层即被拒 ——
|
|
48
|
+
`HTTP 401 {"error":"authentication required","code":-2,"logout_url":"/_zt/logout?…"}`;
|
|
49
|
+
同一时刻 `getRefusalSpeechTechnique` / `getSceneGroups` 乃至配置中心接口**全部返回同一个 401** ⇒ 属**登录态整体过期**
|
|
50
|
+
(`weaver-work-cli auth status` 报 `loggedIn:true, valid:false`、凭据文件停留在前一日),非本命令特有问题。
|
|
51
|
+
重新登录(`weaver-work-cli auth login` / `auth xiaoe`)后即恢复。
|
|
52
|
+
2. **业务 500(服务端未就绪)**:登录态恢复后,请求能被业务逻辑受理,但**6 种请求形态全部返回同一个笼统业务错误** ——
|
|
53
|
+
空 multipart 表单 / multipart 带 `type` / JSON `{}` / JSON 带 `type` / urlencoded 空 / GET(无 query)/ GET 带 `type`、`skillKey`
|
|
54
|
+
⇒ 一律 `HTTP 200 {"code":500,"msg":"请求失败,请稍后再试","status":false,"fail":true}`;
|
|
55
|
+
追加 POST 上下文维度(AgentType UA、`agentType`/`isAgent` 头、表单 `datasetClient=agent`、`referer=/sp/ebddesigner/…`、
|
|
56
|
+
JSON `{datasetClient:"agent"}`)**响应逐字相同** ⇒ 与客户端可变的任何维度都无关。
|
|
57
|
+
同时确认**路由存在**(同前缀错误路径返回 `HTTP 404 Not Found`,与业务 500 可区分)⇒ 非路径错、非认证问题、非缺参。
|
|
58
|
+
该阶段催生了 §4 的错误归因改进(当时报错只写"已尝试 N 种通道",容易把排障方向带偏成"通道选错了")。
|
|
59
|
+
3. **↗ 服务端修复后(12:43)复测通过** —— 即本节的最终结论;**CLI 侧自始至终未做任何针对性改动**,
|
|
60
|
+
第 2 阶段的失败纯属服务端未就绪(或内部异常被折叠成该笼统错误)。
|
|
61
|
+
|
|
62
|
+
### 4. 错误归因改进(2026-10-15,未发布即改,不新开版本)
|
|
63
|
+
|
|
64
|
+
**问题**(由 §3 的实测暴露):`refusal get` / `refusal rules` 在"各通道都没拿到 `data`"时,只报
|
|
65
|
+
`已尝试 N 种通道 → post: code=500 … | get: code=500 …`。这句话把**两种性质完全不同**的失败混为一谈,
|
|
66
|
+
容易把排障方向带偏成"通道选错了",而实际可能是"请求已被业务逻辑受理、只是业务上失败"(如本接口的笼统 500)。
|
|
67
|
+
|
|
68
|
+
**改法**:
|
|
69
|
+
|
|
70
|
+
- 把通道循环从 `refusalCall` 中**抽出为共用实现 `refusalTryModes({label, ctx, modes, request, hasData})`**,
|
|
71
|
+
`refusal get` 与 `refusal rules` **共用同一份**(口径不会悄悄漂移);`refusalRequest` / `refusalRulesRequest` 保留为各自的取数函数。
|
|
72
|
+
- 新增 `refusalBusinessFail(r)`:识别**业务错误**(HTTP 200 但 `fail:true` / `status:false` / `code` 非 0),
|
|
73
|
+
非业务错误则维持原「`code=… msg=(无 data 字段)`」写法。
|
|
74
|
+
- 仅当**所有**失败都是业务错误时,在报错末尾补一句:
|
|
75
|
+
`;提示:以上均为业务错误(HTTP 200 + 业务码失败)—— 非通道问题,请以 msg 为准排查服务端/配置`;
|
|
76
|
+
若混有网络异常 / 无 `data` 字段,则**不补**(那种情况换通道仍有意义)。
|
|
77
|
+
- **行为不变**:分类只影响报错文案,**不改变「auto 两条通道都试」**、也不改变 401 立即中止的既有逻辑。
|
|
78
|
+
|
|
79
|
+
**验证(隔离单元测试,7/7 通过)**:把本文件复制一份、把末尾 `main()` 换成 `export { refusalTryModes }` 后,
|
|
80
|
+
用假 `request` 函数覆盖 ① 首条命中只发 1 次请求、② 首条业务错误仍回退且第二条命中、③ 全业务错误含归因提示、
|
|
81
|
+
④ 混合失败(网络异常 + 业务错误)不误报归因、⑤ 无 `data` 且无错误码如实提示、⑥ 401 立即中止不换通道、
|
|
82
|
+
⑦ 单通道 + 自定义上下文文案正确。真实接口侧同时确认:所有 `type` 目前均返回 `配置不存在`,
|
|
83
|
+
即 `refusal get` 在本环境暂无可用样本(与 2026-10-13 记录的 `type=Extraterritorial` 可命中**已不一致**,疑为该租户配置被移除)。
|
|
84
|
+
|
|
85
|
+
## 0.1.25(2026-10-14)—— 新增 `scene groups|items`:场景定位元数据
|
|
86
|
+
|
|
87
|
+
### 1. 新命令族 `scene`(子命令 `groups` / `items`)
|
|
88
|
+
|
|
89
|
+
- 端点:`/api/dw/newetl/chatBi/getSceneGroups`(别名 `/getAgentSceneGroups`,等价),**不传 `groupId` = ① 分组骨架,传 `groupId` = ② 组内条目**。
|
|
90
|
+
- 来源:技能 `references/scene-locate/scripts/locate.mjs` **整体迁入**(scene-locate.md §6 原计划的 CLI 替换),迁入后技能侧不再直连接口。
|
|
91
|
+
参数名、输出字段集、计数走 stderr 等口径与原脚本**保持一致**。
|
|
92
|
+
- 定位:这是**元数据定位**接口(**不取业务数据**)—— 技能硬约束「禁手工 HTTP」的明确例外项;取数仍必须走 `module call` / `query` / `ds` / `hrm`。
|
|
93
|
+
- 输出:默认打印**精简 JSON**(`groups` → `groupId/groupName/itemCount/groupDesc`;
|
|
94
|
+
`items` → `id/datasetName/datasetType/sourceId`,接口/数据源条目另带 `moduleName`/`sourceType`/`sourceGroupId`/`appId`,并保留 `datasetDesc`);
|
|
95
|
+
`--json` = 原样输出接口返回(等价原脚本 `--raw`);分组数 / 条目数打印到 stderr,**stdout 保持纯净**。
|
|
96
|
+
⚠️ **顶层形状(见 §4):默认与 `--json` 一律为数组** —— `groups` = 分组数组、`items` = 分组数组(元素内含 `datasets`)。
|
|
97
|
+
- `--client agent|all|connector`(= `datasetClient`),默认 `agent`;取值非法直接报用法错误。
|
|
98
|
+
- 错误语义与原脚本对齐:HTTP 401 / `code=401「暂无权限!」` / `code=-1「token为空或失效」` 均原样报出并终止,**不换参数重试**。
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
e10-data scene groups # ① 分组骨架(24 个分组)
|
|
102
|
+
e10-data scene items --group 1060565684758507520 # ② 该分组的条目(接口 / 数据源)
|
|
103
|
+
e10-data scene items --group 1060565684758507520 --json # 原样输出接口返回(排查用)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. 同步改动
|
|
107
|
+
|
|
108
|
+
- `CMD_SUBS` 白名单新增 `scene: ["groups","items"]`;`main()` 分发表新增 `scene` 分支;`usage()` 新增 `scene` 帮助段;
|
|
109
|
+
头部注释与 `package.json` description 同步。
|
|
110
|
+
- ⚠️ 与原脚本的**差异**:不再支持单次 `--base-url` 覆盖(环境一律取当前登录 profile 的 baseUrl,避免"同一凭据打错环境");
|
|
111
|
+
原脚本内置的调试 `eteamsid` 亦不迁入(凭据唯一来源 = `weaver-work-cli`)。
|
|
112
|
+
|
|
113
|
+
### 3. 实测确认(2026-10-14)
|
|
114
|
+
|
|
115
|
+
- 用法/参数分支实测:未知子命令 → 用法提示(退出码 1);`scene items` 缺 `--group` → `ERROR: 缺少必填参数 --group <groupId>`;
|
|
116
|
+
`--client bad` → `ERROR: --client 值必须为 agent|all|connector(当前: bad)`。
|
|
117
|
+
- 接口连通性:当前登录 profile(`https://www.e-cology.com.cn`)下 `scene groups` 返回 **HTTP 401**,
|
|
118
|
+
与同环境已知接口(`skill/getChatDocsBySkillKey`)表现一致 ⇒ **登录态已过期所致**,非本命令特有问题(重新登录后即可用)。
|
|
119
|
+
|
|
120
|
+
### 4. 形状修订(2026-10-14 复核后修正,未发布即改,不新开版本)
|
|
121
|
+
|
|
122
|
+
**问题**:`scene items` 默认输出把接口返回的单元素数组展开成了**对象**(`const g = Array.isArray(data) ? data[0] : data`),
|
|
123
|
+
导致 ① `groups` 默认=数组 / `items` 默认=对象(**跨子命令不一致**);② `items` 的**默认(对象)与 `--json`(数组)顶层类型相反**;
|
|
124
|
+
③ `data[0]` 会**静默丢弃**第 2 个及以后的分组元素;④ 空分组输出裸 `[]`,与对象形态不自洽;
|
|
125
|
+
⑤ 与本技能 `references/scene-locate/scene-locate.md` §1.1/§1.2 的既有契约(数组)**矛盾**,也与本仓库 `README.md` 的原示例(对象)互相打架。
|
|
126
|
+
|
|
127
|
+
**修正**:`cmdSceneItems` **不再展开 `data[0]`**,默认输出与接口同构的**数组**(仅裁字段),空集合统一为 `[]`。
|
|
128
|
+
修正后 —— ① 两条子命令顶层一律数组、互相同构;② 与技能 §1.1/§1.2 契约一致(**技能文档无需改动**);
|
|
129
|
+
③ 默认 / `--json` 的差异**收敛为"字段是否裁剪"**,形状不再翻转;④ 消除丢元素与空集合不自洽。
|
|
130
|
+
|
|
131
|
+
**顺带**:`cmdSceneGroups` 对「接口返回非数组形态」不再静默当空数组,改为包成单元素数组并在 stderr 提示;
|
|
132
|
+
`usage()` 末尾「认证」段为 2026-09-24 之前的旧口径(写 `e10-login` 出口 + 明文镜像),已同步为
|
|
133
|
+
「凭据唯一来源 = `weaver-work-cli`,不设 `e10-login` 回退」。
|
|
134
|
+
|
|
3
135
|
## 0.1.23(2026-10-13)—— 新增 `refusal get`:拒答话术
|
|
4
136
|
|
|
5
137
|
### 1. 新命令族 `refusal`(子命令 `get`)
|
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ e10-data exp status|manifest|commits|file|pull|init|commit|lock|release|roll
|
|
|
27
27
|
e10-data attend statis 考勤假期余额统计 getAttendInfoStatis(hr-attendance 病假/事假等,v0.1.5 新增)
|
|
28
28
|
e10-data module call 模块配置接口调用(配置中心驱动;已确定「哪个模块的哪条具体接口」之后的统一取数入口,v0.1.21 新增)
|
|
29
29
|
e10-data refusal get --type <type> 拒答话术 getRefusalSpeechTechnique(入参 type → data 话术字符串,v0.1.23 新增)
|
|
30
|
+
e10-data refusal rules 拒答话术规则 getRefusalSpeechRules(**无入参** → data 对象数组,v0.1.26 新增)
|
|
31
|
+
e10-data scene groups|items 场景定位元数据 getSceneGroups(① 分组骨架 ② 组内条目;**不取业务数据**,v0.1.25 新增)
|
|
30
32
|
```
|
|
31
33
|
|
|
32
34
|
## 通用约定
|
|
@@ -94,6 +96,8 @@ e10-data attend statis --user 6264843388578732287 --begin 2026-09-01 --end 2026-
|
|
|
94
96
|
e10-data refusal get --type <type> # 拒答话术(人读:直接打印话术正文)
|
|
95
97
|
e10-data refusal get --type <type> --json # 原样输出整个响应对象(data + actionMsg)
|
|
96
98
|
e10-data refusal get --type <type> --http get # 强制走 GET ?type=(默认 auto:POST 表单优先、失败回退 GET)
|
|
99
|
+
e10-data refusal rules # 拒答话术规则(无入参;人读:直接打印 data 数组)
|
|
100
|
+
e10-data refusal rules --json # 原样输出整个响应对象(data 数组 + actionMsg)
|
|
97
101
|
# 无凭据时先登录(环境变量里的 XiaoE 全局 token 换 ETEAMSID)
|
|
98
102
|
XIAOE_USER_TOKEN=<XiaoE token> XIAOE_DOMAIN=<erpa域名> e10-data login xiaoe-env --domain https://www.e-cology.com.cn
|
|
99
103
|
```
|
|
@@ -340,6 +344,10 @@ e10-data refusal get --type <type> [--http auto|post|get] [--json]
|
|
|
340
344
|
- **`--json`**:原样输出整个响应对象(`{"data":"…","actionMsg":{"code":0,"message":"成功"}}`;**成功标记看 `actionMsg.code`,无顶层 `code`/`msg`**),供脚本 / Agent 消费。
|
|
341
345
|
- **排障**:`E10_DATA_DEBUG=1` 时向 **stderr** 打印实际生效的通道(`post` / `get`),stdout 保持纯净。
|
|
342
346
|
- **两种通道均未拿到 `data`**:抛错并列出每条通道的 `code/msg`;凭据失效(401)时**不换通道重试**,直接报登录态失效。
|
|
347
|
+
- **报错归因(v0.1.26 起)**:若各通道返回的都是**业务错误**(HTTP 200 + 业务码失败,如 `{"code":500,"fail":true}`),
|
|
348
|
+
报错末尾会补一句 `;提示:以上均为业务错误(HTTP 200 + 业务码失败)—— 非通道问题,请以 msg 为准排查服务端/配置`,
|
|
349
|
+
避免误判成通道选择问题;若失败里**混有网络异常 / 无 `data` 字段**等情况,则不补该句(此时换通道仍有意义)。
|
|
350
|
+
**注意:该分类只影响报错文案,不改变「auto 两条通道都试」的行为。**
|
|
343
351
|
|
|
344
352
|
```bash
|
|
345
353
|
# 人读:直接拿到话术正文
|
|
@@ -352,3 +360,104 @@ e10-data refusal get --type 1 --json
|
|
|
352
360
|
e10-data refusal get --type 1 --http get
|
|
353
361
|
```
|
|
354
362
|
|
|
363
|
+
## refusal rules 拒答话术规则(v0.1.26 新增)
|
|
364
|
+
|
|
365
|
+
**用途**:查询**拒答话术规则清单**(命中拒答场景时要使用的规则集合)。接口 `/api/dw/newetl/chatBi/getRefusalSpeechRules`,
|
|
366
|
+
**无入参**,返回对象中的 `data` 即**需要使用的对象数组**(规则清单)。
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
e10-data refusal rules [--http auto|post|get] [--json]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
| 参数 | 说明 |
|
|
373
|
+
|---|---|
|
|
374
|
+
| (无位置参数) | 该接口**不接收任何入参**,CLI 也不提供任何入参开关(参数面比 `refusal get` 更窄) |
|
|
375
|
+
| `--http` | 通道,**语义与 `refusal get` 完全一致**:`auto`(默认)= 先 POST **空** multipart 表单 → 返回不含 `data` 时**自动回退** `GET`(不带 query),任一条拿到 `data` 即止;`post` = 仅 POST 空表单;`get` = 仅 `GET` |
|
|
376
|
+
|
|
377
|
+
- **返回契约**:`data` 为**对象数组**(每个元素一条规则,字段由后端定义、**CLI 不裁剪不改写**);允许为空数组 `[]`(语义 = 当前无规则,**空 ≠ 调用失败**)。
|
|
378
|
+
- **已实测的接口契约**(2026-10-15,泛微网络租户 `t7akvdnf84`):**POST 空 multipart 表单即命中** ——
|
|
379
|
+
`POST /api/dw/newetl/chatBi/getRefusalSpeechRules`(表单不带任何字段)→
|
|
380
|
+
`{"data":[…6 条规则…],"actionMsg":{"code":0,"message":"成功"}}`;**GET 同样可用,且返回体与 POST 逐字相同**
|
|
381
|
+
⇒ `auto` 正常路径**只发 1 次请求**。
|
|
382
|
+
- **规则元素字段**(接口原样下发,CLI **不裁剪不改写**):
|
|
383
|
+
|
|
384
|
+
| 字段 | 含义 |
|
|
385
|
+
|---|---|
|
|
386
|
+
| `confKey` | 规则标识,如 `加载完成_1`、`交付前_1/2/3`、`业务域确认完成_1`、`取数前_1` |
|
|
387
|
+
| `confValue` | **话术正文**(含 `<datasetName>` 等占位符,交付前需替换) |
|
|
388
|
+
| `confAttrs` | **命中条件**(判定说明) |
|
|
389
|
+
| `confPlan` | 可选;带选项计划时出现(如 `业务域确认完成_1` 会给出后续问题选项) |
|
|
390
|
+
| `id` / `createTime` / `updateTime` / `creator` / `tenantKey` / `deleteType` | 记录元信息 |
|
|
391
|
+
|
|
392
|
+
- **人读输出**:直接打印 `data` 数组(漂亮 JSON,缩进 1);空数组打印 `[]` 并向 **stderr** 提示「拒答话术规则 0 条」,**stdout 保持纯净**(可安全重定向/管道)。
|
|
393
|
+
- **`--json`**:原样输出整个响应对象(`{"data":[…],"actionMsg":{"code":0,"message":"成功"}}`;**成功标记看 `actionMsg.code`,无顶层 `code`/`msg`**),供脚本 / Agent 消费。
|
|
394
|
+
- **排障**:`E10_DATA_DEBUG=1` 时向 **stderr** 打印实际生效的通道(`post` / `get`)。
|
|
395
|
+
- **两种通道均未拿到 `data`**:抛错并列出每条通道的 `code/msg`;凭据失效(401)时**不换通道重试**,直接报登录态失效。
|
|
396
|
+
- **报错归因(v0.1.26 起)**:若各通道返回的都是**业务错误**(HTTP 200 + 业务码失败,如 `{"code":500,"fail":true}`),
|
|
397
|
+
报错末尾会补一句 `;提示:以上均为业务错误(HTTP 200 + 业务码失败)—— 非通道问题,请以 msg 为准排查服务端/配置`,
|
|
398
|
+
避免误判成通道选择问题;若失败里**混有网络异常 / 无 `data` 字段**等情况,则不补该句(此时换通道仍有意义)。
|
|
399
|
+
**注意:该分类只影响报错文案,不改变「auto 两条通道都试」的行为。**
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# 人读:直接打印规则数组
|
|
403
|
+
e10-data refusal rules
|
|
404
|
+
|
|
405
|
+
# 取结构化结果(Agent / 脚本)
|
|
406
|
+
e10-data refusal rules --json
|
|
407
|
+
|
|
408
|
+
# 该端点确认走 GET 时,锁定单通道(少一次探测请求)
|
|
409
|
+
e10-data refusal rules --http get
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
## scene groups|items 场景定位元数据(v0.1.25 新增)
|
|
413
|
+
|
|
414
|
+
**用途**:E10「场景分组 → 接口/数据源」两级**定位**(**不取业务数据**)。端点 `/api/dw/newetl/chatBi/getSceneGroups`
|
|
415
|
+
(别名 `/getAgentSceneGroups`,等价),**不传 `groupId` 返回分组骨架,传 `groupId` 返回该分组的条目**。
|
|
416
|
+
本命令由技能 `references/scene-locate/scripts/locate.mjs` **整体迁入**(属技能硬约束「禁手工 HTTP」的例外项;
|
|
417
|
+
**取数**仍必须走 `module call` / `query` / `ds` / `hrm`)。
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
e10-data scene groups # ① 分组骨架
|
|
421
|
+
e10-data scene items --group <groupId> # ② 组内条目
|
|
422
|
+
e10-data scene groups [--client agent|all|connector] [--json]
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
| 参数 | 说明 |
|
|
426
|
+
|---|---|
|
|
427
|
+
| `groups` / `items` | `groups` = 分组骨架(每个分组带 `groupDesc` = `【场景】`+`【触发词】`+`【取数顺序】`);`items` = 组内条目 |
|
|
428
|
+
| `--group` | `items` **必填**;分组 id(19 位雪花号,按字符串传参) |
|
|
429
|
+
| `--client` | `datasetClient`,取值 `agent`(默认)/ `all` / `connector`;取值非法直接报用法错误 |
|
|
430
|
+
| `--json` | 原样输出接口返回(等价原脚本 `--raw`),供排查 |
|
|
431
|
+
|
|
432
|
+
**默认输出(精简 JSON,供 Agent 消费;分组数 / 条目数打印到 stderr,stdout 保持纯净)**:
|
|
433
|
+
|
|
434
|
+
> ⚠️ **顶层形状(2026-10-14 修订)**:两条子命令的默认输出**与 `--json` 一律为数组**,二者同构 ——
|
|
435
|
+
> `groups` = 分组数组;`items` = 分组数组(元素内含 `datasets`)。默认与 `--json` 的差异**仅在于字段是否裁剪**,
|
|
436
|
+
> 顶层形状不翻转。此口径与技能 `references/scene-locate/scene-locate.md` §1.1 / §1.2 契约一致。
|
|
437
|
+
|
|
438
|
+
```jsonc
|
|
439
|
+
// scene groups
|
|
440
|
+
[{ "groupId": "1060565684758507520", "groupName": "EHR考勤/人事", "itemCount": 47, "groupDesc": "【场景】… 【触发词】… 【取数顺序】…" }]
|
|
441
|
+
|
|
442
|
+
// scene items --group 1060565684758507520
|
|
443
|
+
[{ "groupId": "…", "groupName": "…", "itemCount": 47, "datasets": [
|
|
444
|
+
{ "id": "…", "datasetName": "查询历史在职数量统计", "datasetType": "interface",
|
|
445
|
+
"sourceId": "POST_EHR_GET_COUNT_DATA_4", "datasetDesc": "…" },
|
|
446
|
+
{ "id": "…", "datasetName": "项目 PMO 指标宽表", "datasetType": "datasource",
|
|
447
|
+
"sourceId": "1307594250577248258", "moduleName": "项目 PMO 指标", "sourceType": "ETEAMS",
|
|
448
|
+
"sourceGroupId": "-98", "appId": "…", "datasetDesc": "【通道】…【口径】…【回退】…【禁项】…【边界】…" }
|
|
449
|
+
] }]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**分流(拿到条目后)**:
|
|
453
|
+
|
|
454
|
+
- `datasetType=interface` → `e10-data module call --conf-key <sourceId> --group <moduleName>`(`moduleName` 随条目下发,勿用 confKey 拆段猜);
|
|
455
|
+
- `datasetType=datasource` → 按 `datasetDesc` 五段式走 `query`(DSL,`from.table` 用 desc 里的密文表 `t_*`)
|
|
456
|
+
或 `ds`(`--source-type <sourceType>` / `--group <sourceGroupId>` / `--app-id <appId>`,⚠️ `ds --table` 用 `sourceId`,**不是**密文表名)。
|
|
457
|
+
|
|
458
|
+
**错误语义**(与原脚本对齐):`code=401「暂无权限!」` = 该接口在当前环境未开放或账号无权限(**先确认接口已部署**,不要反复重登);
|
|
459
|
+
`code=-1「token为空或失效」` / HTTP 401 = 登录态失效 → 重新登录;均**原样报错终止,不换参数重试**。
|
|
460
|
+
|
|
461
|
+
> ⚠️ 与原脚本的**差异**:不再支持单次 `--base-url` 覆盖(环境一律取当前登录 profile 的 `baseUrl`,避免"同一凭据打错环境"),
|
|
462
|
+
> 内置调试 `eteamsid` 亦不迁入(凭据唯一来源 = `weaver-work-cli`)。
|
|
463
|
+
|
package/bin/e10-data.mjs
CHANGED
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
* 复用本 CLI 凭据缓存与 conf 通道、零临时文件
|
|
31
31
|
* e10-data refusal get 拒答话术 getRefusalSpeechTechnique(入参 type → data 话术字符串;
|
|
32
32
|
* auto 通道 = POST 表单优先、GET ?type= 回退,2026-10-13)
|
|
33
|
+
* e10-data refusal rules 拒答话术规则 getRefusalSpeechRules(**无入参** → data 对象数组;
|
|
34
|
+
* auto 通道 = POST 空表单优先、GET 回退;2026-10-15 实测 POST 空表单即命中(6 条规则))
|
|
35
|
+
* e10-data scene groups|items 场景定位元数据 getSceneGroups(2026-10-14 新增)
|
|
36
|
+
* groups 分组骨架(每个分组带 groupDesc =【场景】【触发词】【取数顺序】)
|
|
37
|
+
* items 组内条目(interface=接口 / datasource=数据源,每条带 datasetDesc)
|
|
38
|
+
* 来源:技能 references/scene-locate/scripts/locate.mjs 整体迁入 ——
|
|
39
|
+
* 属**元数据定位**接口(不取业务数据),技能硬约束「禁手工 HTTP」的例外项
|
|
33
40
|
*
|
|
34
41
|
* 通用:--json 原样输出;复杂 JSON 参数支持 @文件 或 内联(中文走 @文件 更稳)
|
|
35
42
|
* 认证:凭据**唯一来源 = weaver-work-cli**(本 CLI 不实现任何加解密,**不设 e10-login 回退**):
|
|
@@ -709,7 +716,8 @@ const CMD_SUBS = {
|
|
|
709
716
|
exp: ["status", "manifest", "commits", "file", "pull", "init", "commit", "lock", "release", "rollback"],
|
|
710
717
|
attend: ["statis"],
|
|
711
718
|
module: ["call"],
|
|
712
|
-
refusal: ["get"],
|
|
719
|
+
refusal: ["get", "rules"],
|
|
720
|
+
scene: ["groups", "items"],
|
|
713
721
|
};
|
|
714
722
|
function commandIsKnown(pos) {
|
|
715
723
|
const family = pos[0], sub = pos[1];
|
|
@@ -2694,27 +2702,58 @@ async function refusalRequest(mode, type) {
|
|
|
2694
2702
|
if (mode === "get") return getUrl(REFUSAL_PATH + "?type=" + encodeURIComponent(type));
|
|
2695
2703
|
return postMultipart(REFUSAL_PATH, { type }); // 与 fieldsForDSL 同口径:multipart 表单字段 type
|
|
2696
2704
|
}
|
|
2697
|
-
//
|
|
2698
|
-
|
|
2699
|
-
|
|
2705
|
+
// ---- 通道选择与错误分类(refusal get / refusal rules 共用,2026-10-15 抽出)----
|
|
2706
|
+
// 为什么共用:两条命令的通道策略必须**逐字同源**,否则口径会悄悄漂移(一个改了另一个忘记改)。
|
|
2707
|
+
// 「没拿到 data」其实是两种性质完全不同的情况,必须分开报,否则排障方向会跑偏:
|
|
2708
|
+
// ① **业务错误**:HTTP 200 但业务码失败(fail:true / status:false / code 非 0)⇒ 请求**已被业务逻辑受理**,
|
|
2709
|
+
// 换通道不会改变结果。2026-10-15 实测 getRefusalSpeechRules 的 6 种请求形态返回**同一个** code=500,
|
|
2710
|
+
// 就是典型情形(详见 CHANGELOG 0.1.26 §3)——此时应照 msg 查服务端/配置,而不是继续换通道。
|
|
2711
|
+
// ② **形态不符**:响应正常但就是没有 data 字段(如裸 ResultBean、非 JSON 包装)⇒ 才值得换通道再试。
|
|
2712
|
+
// 注意:分类只影响**报错文案**,不改变「auto 两条通道都试」的行为(避免误杀"第一条通道不支持、第二条能用"的端点)。
|
|
2713
|
+
function refusalBusinessFail(r) {
|
|
2714
|
+
if (!r || typeof r !== "object") return null;
|
|
2715
|
+
const code = r.code;
|
|
2716
|
+
const bad = r.fail === true || r.status === false || (code !== undefined && Number(code) !== 0);
|
|
2717
|
+
if (!bad) return null;
|
|
2718
|
+
return "code=" + code + " msg=" + (r.msg || r.message || r.error || "(无 msg)");
|
|
2719
|
+
}
|
|
2720
|
+
/** 依序试通道:拿到 data 即返回 { r, mode };全失败则抛出「含每通道明细 + 业务错误归因」的错误 */
|
|
2721
|
+
async function refusalTryModes({ label, ctx, modes, request, hasData }) {
|
|
2700
2722
|
const tried = [];
|
|
2723
|
+
let allBusiness = true; // 「全部失败都是业务错误」时才敢断言"换通道没用"
|
|
2701
2724
|
for (const mode of modes) {
|
|
2702
2725
|
let r;
|
|
2703
2726
|
try {
|
|
2704
|
-
r = await
|
|
2727
|
+
r = await request(mode);
|
|
2705
2728
|
} catch (e) {
|
|
2706
2729
|
const msg = (e && e.message) || String(e);
|
|
2707
2730
|
if (/登录态失效|401/.test(msg)) throw e; // 凭据问题与「通道选哪条」无关,不换通道重试(避免重复报错)
|
|
2708
2731
|
tried.push(mode + ": " + msg);
|
|
2732
|
+
allBusiness = false;
|
|
2709
2733
|
continue;
|
|
2710
2734
|
}
|
|
2711
|
-
if (
|
|
2712
|
-
if (process.env.E10_DATA_DEBUG) console.error("[debug]
|
|
2735
|
+
if (hasData(r)) {
|
|
2736
|
+
if (process.env.E10_DATA_DEBUG) console.error("[debug] " + label + " 命中通道=" + mode);
|
|
2713
2737
|
return { r, mode };
|
|
2714
2738
|
}
|
|
2715
|
-
|
|
2739
|
+
const biz = refusalBusinessFail(r);
|
|
2740
|
+
if (biz) tried.push(mode + ": " + biz);
|
|
2741
|
+
else { tried.push(mode + ": code=" + (r && r.code) + " msg=" + ((r && r.msg) || "(无 data 字段)")); allBusiness = false; }
|
|
2716
2742
|
}
|
|
2717
|
-
throw new Error("
|
|
2743
|
+
throw new Error(label + " 调用失败(" + ctx + ")已尝试 " + modes.length + " 种通道 → " + tried.join(" | ")
|
|
2744
|
+
+ (allBusiness && tried.length
|
|
2745
|
+
? ";提示:以上均为业务错误(HTTP 200 + 业务码失败)—— 非通道问题,请以 msg 为准排查服务端/配置"
|
|
2746
|
+
: ""));
|
|
2747
|
+
}
|
|
2748
|
+
// 返回 { r, mode }:r = 命中的响应体,mode = 实际生效的通道(post/get),供排障展示
|
|
2749
|
+
async function refusalCall(type, httpMode) {
|
|
2750
|
+
return refusalTryModes({
|
|
2751
|
+
label: "getRefusalSpeechTechnique",
|
|
2752
|
+
ctx: "type=" + type,
|
|
2753
|
+
modes: httpMode === "auto" ? ["post", "get"] : [httpMode],
|
|
2754
|
+
request: (mode) => refusalRequest(mode, type),
|
|
2755
|
+
hasData: refusalHasData,
|
|
2756
|
+
});
|
|
2718
2757
|
}
|
|
2719
2758
|
async function cmdRefusalGet(args, json) {
|
|
2720
2759
|
const type = need("type", args);
|
|
@@ -2731,6 +2770,166 @@ async function cmdRefusalGet(args, json) {
|
|
|
2731
2770
|
console.log(typeof d === "object" ? JSON.stringify(d, null, 1) : String(d));
|
|
2732
2771
|
}
|
|
2733
2772
|
|
|
2773
|
+
// ---------------- refusal rules:拒答话术规则 getRefusalSpeechRules(2026-10-15 新增)----------------
|
|
2774
|
+
// 端点:/api/dw/newetl/chatBi/getRefusalSpeechRules
|
|
2775
|
+
// 入参:**无**(CLI 不传任何参数,也不提供任何入参开关 —— 参数面比 refusal get 更窄)
|
|
2776
|
+
// 返回:对象,其中 data = **需要使用的对象数组**(拒答话术规则清单;可能为空数组 [],空 ≠ 失败)
|
|
2777
|
+
// 通道选择:与 refusal get **完全同口径**(同一族、同一策略,便于排障时口径统一):
|
|
2778
|
+
// auto(默认)= 先 POST 空 multipart 表单 → 判定拿不到 data 才回退 GET;任一条拿到 data 即止
|
|
2779
|
+
// (正常路径只发 1 次请求,回退仅在首条拿不到 data 时触发);可 --http post|get 强制单一通道。
|
|
2780
|
+
// 与 refusal get 的差异仅两点:① 无入参(表单不带字段 / GET 不带 query);② data 是数组而非字符串。
|
|
2781
|
+
// ✅ 2026-10-15 实测确认(泛微网络租户 t7akvdnf84):**POST 空 multipart 表单即命中** ——
|
|
2782
|
+
// 返回 { data: [6 条规则], actionMsg: { code: 0, message: "成功" } };GET 同样可用且**返回体与 POST 逐字相同**
|
|
2783
|
+
// (实测 `--http get` 与 `--http post` 的 stdout 完全一致)⇒ auto 正常路径**只发 1 次请求**(POST 先命中)。
|
|
2784
|
+
// 规则元素字段(接口原样下发,CLI 不裁剪):id / createTime / updateTime / creator / tenantKey /
|
|
2785
|
+
// deleteType / confKey(如「加载完成_1」「交付前_1」「取数前_1」)/ confValue(话术正文)/
|
|
2786
|
+
// confAttrs(命中条件)/ confPlan(可选,如「业务域确认完成_1」带选项计划)。
|
|
2787
|
+
const REFUSAL_RULES_PATH = "/api/dw/newetl/chatBi/getRefusalSpeechRules";
|
|
2788
|
+
// 有效返回判定:对象且带 data 字段(data 允许为空数组 —— 语义是「当前无规则」,不等于失败)
|
|
2789
|
+
function refusalRulesHasData(r) {
|
|
2790
|
+
return !!r && typeof r === "object" && r.data !== undefined && r.data !== null;
|
|
2791
|
+
}
|
|
2792
|
+
async function refusalRulesRequest(mode) {
|
|
2793
|
+
if (mode === "get") return getUrl(REFUSAL_RULES_PATH);
|
|
2794
|
+
return postMultipart(REFUSAL_RULES_PATH, {}); // 与 refusal get 同口径:multipart 表单,但无字段
|
|
2795
|
+
}
|
|
2796
|
+
// 返回 { r, mode }:r = 命中的响应体,mode = 实际生效的通道(post/get),供排障展示。
|
|
2797
|
+
// 通道循环与错误分类统一走 refusalTryModes —— 与 refusal get **同一份实现**(口径不会漂移)。
|
|
2798
|
+
async function refusalRulesCall(httpMode) {
|
|
2799
|
+
return refusalTryModes({
|
|
2800
|
+
label: "getRefusalSpeechRules",
|
|
2801
|
+
ctx: "该接口无入参",
|
|
2802
|
+
modes: httpMode === "auto" ? ["post", "get"] : [httpMode],
|
|
2803
|
+
request: (mode) => refusalRulesRequest(mode),
|
|
2804
|
+
hasData: refusalRulesHasData,
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
2807
|
+
async function cmdRefusalRules(args, json) {
|
|
2808
|
+
const httpMode = args.http === undefined ? "auto" : String(args.http).toLowerCase();
|
|
2809
|
+
if (!REFUSAL_HTTP_MODES.includes(httpMode)) throw new Error("--http 值必须为 " + REFUSAL_HTTP_MODES.join("|") + "(当前: " + args.http + ")");
|
|
2810
|
+
const { r } = await refusalRulesCall(httpMode);
|
|
2811
|
+
if (json) return r; // 原样输出整个响应对象(含 data)
|
|
2812
|
+
const d = r.data;
|
|
2813
|
+
if (Array.isArray(d)) {
|
|
2814
|
+
if (!d.length) { console.log("[]"); process.stderr.write("# 空:拒答话术规则 0 条\n"); return; }
|
|
2815
|
+
process.stderr.write("# 规则 " + d.length + " 条\n");
|
|
2816
|
+
console.log(JSON.stringify(d, null, 1));
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
console.log(typeof d === "object" ? JSON.stringify(d, null, 1) : String(d));
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
// ---------------- scene:场景定位元数据 getSceneGroups(2026-10-14 新增)----------------
|
|
2823
|
+
// 端点:/api/dw/newetl/chatBi/getSceneGroups(别名 /getAgentSceneGroups,等价)
|
|
2824
|
+
// ① scene groups → 分组骨架(不传 groupId;每个分组带 groupDesc 三段式)
|
|
2825
|
+
// ② scene items --group <groupId> → 该分组的条目(传 groupId;datasetType = interface / datasource)
|
|
2826
|
+
// 来源:由技能 `references/scene-locate/scripts/locate.mjs` **整体迁入**(scene-locate.md §6 原计划的 CLI 替换),
|
|
2827
|
+
// 迁入后技能侧不再直连接口。参数与输出口径与脚本保持一致(`--client` 默认 agent、精简字段集、计数走 stderr)。
|
|
2828
|
+
// 形状口径(2026-10-14 修订):**默认输出顶层一律为数组** —— ① groups = 分组数组;② items = 分组数组
|
|
2829
|
+
// (元素内含 `datasets`)。`--json` 仍为「接口原样返回」(同为数组)⇒ 默认与 `--json` 的差异**仅在于字段是否裁剪**,
|
|
2830
|
+
// 顶层形状不翻转。该口径与技能 `references/scene-locate/scene-locate.md` §1.1 / §1.2 契约一致。
|
|
2831
|
+
// 定位:这是**元数据定位**接口(不取业务数据)—— 技能硬约束「禁手工 HTTP」的明确例外项;
|
|
2832
|
+
// 取数仍必须走 `module call` / `query` / `ds` / `hrm`,不得用本命令替代取数。
|
|
2833
|
+
// 代理:Node 原生 fetch **不读** `https_proxy` ⇒ 内网域名可直连;用 curl 手工验证才需 `--noproxy '*'`。
|
|
2834
|
+
const SCENE_PATH = "/api/dw/newetl/chatBi/getSceneGroups";
|
|
2835
|
+
const SCENE_CLIENTS = ["agent", "all", "connector"];
|
|
2836
|
+
|
|
2837
|
+
/** --client(datasetClient):限定取「哪个客户端」的场景集,默认 agent */
|
|
2838
|
+
function sceneClient(args) {
|
|
2839
|
+
const c = args.client === undefined ? "agent" : String(args.client).trim();
|
|
2840
|
+
if (!SCENE_CLIENTS.includes(c)) {
|
|
2841
|
+
throw new Error("--client 值必须为 " + SCENE_CLIENTS.join("|") + "(当前: " + args.client + ")");
|
|
2842
|
+
}
|
|
2843
|
+
return c;
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
/** 发一次 scene 元数据请求(GET;Cookie/eteamsid/AgentType-UA 三件套 + X-Requested-With),返回解包后的 data */
|
|
2847
|
+
async function sceneRequest(params) {
|
|
2848
|
+
const q = new URLSearchParams(params).toString();
|
|
2849
|
+
const resp = await fetch(BASE + SCENE_PATH + (q ? "?" + q : ""), {
|
|
2850
|
+
method: "GET",
|
|
2851
|
+
headers: {
|
|
2852
|
+
"accept": "application/json, text/plain, */*",
|
|
2853
|
+
"langType": "zh_CN",
|
|
2854
|
+
"cookie": auth.cookie,
|
|
2855
|
+
"eteamsid": auth.eteamsid,
|
|
2856
|
+
"user-agent": moduleUserAgent(),
|
|
2857
|
+
"x-requested-with": "XMLHttpRequest",
|
|
2858
|
+
},
|
|
2859
|
+
});
|
|
2860
|
+
const text = await resp.text();
|
|
2861
|
+
let j; try { j = parseJsonSafe(text); } catch { throw new Error("HTTP " + resp.status + " 非JSON响应: " + text.slice(0, 300)); }
|
|
2862
|
+
checkAuthFail(resp, text, j);
|
|
2863
|
+
// 业务错误校验:E10 常见形态 { code:401|-1, msg },HTTP 仍为 200(与原脚本同口径)
|
|
2864
|
+
if (j && typeof j === "object" && !Array.isArray(j)) {
|
|
2865
|
+
const bad = (j.code !== undefined && Number(j.code) !== 0) || j.fail === true;
|
|
2866
|
+
if (bad) {
|
|
2867
|
+
throw new Error("getSceneGroups 返回业务错误:code=" + j.code + " msg=" + (j.msg || j.message || "(无 msg)")
|
|
2868
|
+
+ "(HTTP " + resp.status + ";常见:401「暂无权限!」= 该接口在当前环境未开放或账号无权限;"
|
|
2869
|
+
+ "-1「token为空或失效」= 登录态失效,请重新登录)");
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
// 兼容 ResultBean 包装({ code, data })与裸数组
|
|
2873
|
+
return j && typeof j === "object" && !Array.isArray(j) && "data" in j ? j.data : j;
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
/** ① 分组骨架(24 个分组;默认输出精简字段,--json 原样输出接口返回)
|
|
2877
|
+
* ⚠️ 形状口径(2026-10-14 修订):默认输出**顶层为数组**(与 ② items 同构)。 */
|
|
2878
|
+
async function cmdSceneGroups(args, json) {
|
|
2879
|
+
const data = await sceneRequest({ datasetClient: sceneClient(args) });
|
|
2880
|
+
if (json) return data;
|
|
2881
|
+
// 非数组形态一律包成数组 —— 避免「接口异常形态」被静默当成「没有分组」
|
|
2882
|
+
const arr = Array.isArray(data) ? data : (data == null ? [] : [data]);
|
|
2883
|
+
if (data != null && !Array.isArray(data)) {
|
|
2884
|
+
process.stderr.write("# 注意:接口返回非数组形态(" + typeof data + "),已按单元素数组处理\n");
|
|
2885
|
+
}
|
|
2886
|
+
process.stderr.write("# 分组 " + arr.length + " 个\n");
|
|
2887
|
+
console.log(JSON.stringify(arr.map((g) => ({
|
|
2888
|
+
groupId: String(g.groupId ?? ""),
|
|
2889
|
+
groupName: g.groupName ?? "",
|
|
2890
|
+
itemCount: Number(g.itemCount ?? 0),
|
|
2891
|
+
groupDesc: g.groupDesc ?? "",
|
|
2892
|
+
})), null, 1));
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
/** ② 组内条目(接口 / 数据源;groupId 为 19 位雪花号,按字符串传参)
|
|
2896
|
+
* ⚠️ 形状口径(2026-10-14 修订):默认输出**顶层一律数组**(与 ① groups 同构,亦与技能
|
|
2897
|
+
* `references/scene-locate/scene-locate.md` §1.2 契约一致);**不得**再展开 `data[0]` 成单对象
|
|
2898
|
+
* —— 展开会(a)与 ① 及 `--json` 的形状翻转、(b)静默丢弃第 2 个及以后的分组元素。 */
|
|
2899
|
+
async function cmdSceneItems(args, json) {
|
|
2900
|
+
const group = args.group || args.groupId;
|
|
2901
|
+
if (!group) throw new Error("缺少必填参数 --group <groupId>");
|
|
2902
|
+
const data = await sceneRequest({ datasetClient: sceneClient(args), groupId: String(group) });
|
|
2903
|
+
if (json) return data;
|
|
2904
|
+
const arr = Array.isArray(data) ? data : (data == null ? [] : [data]);
|
|
2905
|
+
const out = arr.map((g) => {
|
|
2906
|
+
const items = (g.datasets || []).map((d) => {
|
|
2907
|
+
const o = {
|
|
2908
|
+
id: String(d.id ?? ""),
|
|
2909
|
+
datasetName: d.datasetName ?? "",
|
|
2910
|
+
datasetType: d.datasetType ?? "",
|
|
2911
|
+
sourceId: d.sourceId ?? "",
|
|
2912
|
+
};
|
|
2913
|
+
// 取数通道参数(接口已下发时带出):模块标识 / 数据源类型 / 数据源分组 / 应用标识
|
|
2914
|
+
if (d.moduleName) o.moduleName = d.moduleName;
|
|
2915
|
+
if (d.sourceType) o.sourceType = d.sourceType;
|
|
2916
|
+
if (d.sourceGroupId) o.sourceGroupId = d.sourceGroupId;
|
|
2917
|
+
if (d.appId) o.appId = d.appId;
|
|
2918
|
+
o.datasetDesc = d.datasetDesc ?? "";
|
|
2919
|
+
return o;
|
|
2920
|
+
});
|
|
2921
|
+
return {
|
|
2922
|
+
groupId: String(g.groupId ?? group),
|
|
2923
|
+
groupName: g.groupName ?? "",
|
|
2924
|
+
itemCount: Number(g.itemCount ?? items.length),
|
|
2925
|
+
datasets: items,
|
|
2926
|
+
};
|
|
2927
|
+
});
|
|
2928
|
+
if (!out.length) { console.log("[]"); process.stderr.write("# 未找到该分组\n"); return; }
|
|
2929
|
+
process.stderr.write("# 条目 " + out.reduce((n, g) => n + g.datasets.length, 0) + " 条\n");
|
|
2930
|
+
console.log(JSON.stringify(out, null, 1));
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2734
2933
|
// ---------------- main ----------------
|
|
2735
2934
|
function usage() {
|
|
2736
2935
|
console.log(`e10-data CLI(data-assistant 数据接口统一命令行,2026-09-03 扩展)
|
|
@@ -2841,8 +3040,25 @@ refusal 拒答话术(chatBi,2026-10-13 新增)
|
|
|
2841
3040
|
# --http:auto(默认)= 先 POST multipart 表单(同 ds fields-dsl 口径),
|
|
2842
3041
|
# 返回不含 data 时自动回退 GET ?type=;post = 仅 POST 表单;get = 仅 GET query
|
|
2843
3042
|
# 人读输出直接打印 data 话术正文(空串 → 提示该 type 无话术);--json 原样输出整个响应对象
|
|
2844
|
-
|
|
2845
|
-
|
|
3043
|
+
refusal rules [--http auto|post|get] [--json] # 接口 /api/dw/newetl/chatBi/getRefusalSpeechRules
|
|
3044
|
+
# **无入参**(参数面比 get 更窄,CLI 不传任何参数);返回对象的 data = **对象数组**(规则清单)
|
|
3045
|
+
# --http 语义同 refusal get:auto(默认)= 先 POST 空 multipart 表单,返回不含 data 时回退 GET;
|
|
3046
|
+
# post = 仅 POST 空表单;get = 仅 GET(不带 query)
|
|
3047
|
+
# 人读输出直接打印 data 数组(漂亮 JSON;空数组打印 []);--json 原样输出整个响应对象
|
|
3048
|
+
scene 场景定位元数据(chatBi getSceneGroups,2026-10-14 新增;**不取业务数据**,只做「分组 → 条目」定位)
|
|
3049
|
+
scene groups [--client agent|all|connector] # ① 分组骨架(groupDesc =【场景】【触发词】【取数顺序】)
|
|
3050
|
+
scene items --group <groupId> [--client …] # ② 组内条目(每组带 datasetDesc;datasetType 决定分流)
|
|
3051
|
+
# 端点 /api/dw/newetl/chatBi/getSceneGroups(别名 getAgentSceneGroups,等价)
|
|
3052
|
+
# 默认输出**精简 JSON**(groups: groupId/groupName/itemCount/groupDesc;
|
|
3053
|
+
# items: id/datasetName/datasetType/sourceId[/moduleName/sourceType/sourceGroupId/appId]/datasetDesc);
|
|
3054
|
+
# --json = 原样输出接口返回;分组数 / 条目数打印到 stderr(stdout 保持纯净)
|
|
3055
|
+
# ⚠️ 顶层形状(2026-10-14 修订):默认与 --json **一律为数组** —— groups = 分组数组;
|
|
3056
|
+
# items = 分组数组(元素内含 datasets),二者同构;默认与 --json 只差「字段是否裁剪」
|
|
3057
|
+
# 分流提示:items 里 datasetType=interface → module call(--conf-key sourceId,--group 取 moduleName);
|
|
3058
|
+
# datasetType=datasource → query(DSL)/ ds(数据源,--source-type/--group/--app-id 见条目字段)
|
|
3059
|
+
# 示例: scene groups | scene items --group 1060565684758507520
|
|
3060
|
+
认证: 凭据**唯一来源 = weaver-work-cli**(本 CLI 不实现任何加解密,**不设 e10-login 回退**);
|
|
3061
|
+
未登录 / 凭据失效时执行 weaver-work-cli auth login(无浏览器:login xiaoe-env 用环境变量 token)`);
|
|
2846
3062
|
}
|
|
2847
3063
|
|
|
2848
3064
|
async function main() {
|
|
@@ -2904,6 +3120,11 @@ async function main() {
|
|
|
2904
3120
|
}
|
|
2905
3121
|
} else if (family === "refusal") {
|
|
2906
3122
|
if (sub === "get") result = await cmdRefusalGet(args, json);
|
|
3123
|
+
else if (sub === "rules") result = await cmdRefusalRules(args, json);
|
|
3124
|
+
else { usage(); process.exit(1); }
|
|
3125
|
+
} else if (family === "scene") {
|
|
3126
|
+
if (sub === "groups") result = await cmdSceneGroups(args, json);
|
|
3127
|
+
else if (sub === "items") result = await cmdSceneItems(args, json);
|
|
2907
3128
|
else { usage(); process.exit(1); }
|
|
2908
3129
|
} else if (family === "attend") {
|
|
2909
3130
|
if (sub === "statis") result = await cmdAttendStatis(args, json);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "e10-data",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):登录(login xiaoe-env,环境变量 XiaoE 全局 token 换 ETEAMSID,免浏览器/免 python)/DSL 查询/数据源/文档/词库/关联字段翻译/环境参数配置中心(conf,支持 confGroup 分组)/专家包版本管理;ds 取数(list/chart/stat/count)的 appId 由调用方显式传入 --app-id(v0.1.14 起 CLI 不再自动反查;EB 建模表单 weaver-ebuilder-form-service 必须带,appId 取自 ebdf_obj.app_id;2026-10-09 起不再做 EB 权限前置校验);认证凭据**唯一来源 = weaver-work-cli**(通过 `auth export-weaver-env` 命令出口取明文凭据,**不设 e10-login 回退**;加解密由该 CLI 自行负责,本 CLI 不实现任何加解密;仅 login xiaoe-env 在无凭据时自行换 token,写 profile 仍交 e10-login set)。v0.1.17 性能改造:免凭据命令(--version/--help/未知命令)提前返回、直连 e10-login JS 入口(去掉 shell:true 的 cmd.exe 开销)、新增凭据进程间 TTL 缓存(不落明文);v0.1.19(2026-09-24)新增 ds 发现层聚合 groups/find/describe(进程内并发,全 58 分组扫表实测 ~5.5s),并修复 ds tables --name 因 listByPage 端点切换导致的关键词过滤静默失效;v0.1.18(2026-09-24)新增 ds fields-dsl(接口 /api/dw/newetl/chatBi/ds/fieldsForDSL),并移除凭据明文镜像同步(不再写 ~/.workbuddy/e10-login-cache.md);v0.1.20(2026-09-24)凭据来源切换为 weaver-work-cli 唯一来源、移除 e10-login 回退,并补齐 userId/tenantKey 传递(修复 attend statis 等命令报「缺少查询人员」的问题)。v0.1.21(2026-09-28)新增 module call —— 模块配置接口调用(配置中心驱动):已确定「哪个模块的哪条具体接口」之后的一条命令取数入口(精取该条 confAttrs → 按 http_method/input_params 组参 → 发请求(自动禁代理 + Cookie/eteamsid/UA 三件套)→ 提取精简结果),与技能自带 script/call_module.py 等价(参数名/退出码/提取口径全对齐),复用本 CLI 凭据缓存与 conf 通道、零临时文件;同时 auth 归一化与凭据缓存补齐 userAgent(供 AgentType UA 使用,缺失时从 cookie 的 agentType= 推导)。v0.1.22(2026-10-10):移除 `eb perm-page` 命令(EB 建模表单取数不再做权限前置校验,appId 直接取 ebdf_obj.app_id);`--fields`/`--group-by`/`--order` 等逗号列表支持 `@文件`(逗号字符串或 JSON 数组,与 --where/--stat/--dsl 一致,规避 shell 拆分导致的静默丢列/0 行)。v0.1.23(2026-10-13)新增 `refusal get` —— 拒答话术 getRefusalSpeechTechnique(入参仅 type,返回对象的 data = 话术字符串;默认 auto 通道 = POST multipart 表单优先、返回不含 data 时自动回退 GET ?type=,可用 --http post|get 锁定单通道)。",
|
|
3
|
+
"version": "0.1.26",
|
|
4
|
+
"description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):登录(login xiaoe-env,环境变量 XiaoE 全局 token 换 ETEAMSID,免浏览器/免 python)/DSL 查询/数据源/文档/词库/关联字段翻译/环境参数配置中心(conf,支持 confGroup 分组)/专家包版本管理;ds 取数(list/chart/stat/count)的 appId 由调用方显式传入 --app-id(v0.1.14 起 CLI 不再自动反查;EB 建模表单 weaver-ebuilder-form-service 必须带,appId 取自 ebdf_obj.app_id;2026-10-09 起不再做 EB 权限前置校验);认证凭据**唯一来源 = weaver-work-cli**(通过 `auth export-weaver-env` 命令出口取明文凭据,**不设 e10-login 回退**;加解密由该 CLI 自行负责,本 CLI 不实现任何加解密;仅 login xiaoe-env 在无凭据时自行换 token,写 profile 仍交 e10-login set)。v0.1.17 性能改造:免凭据命令(--version/--help/未知命令)提前返回、直连 e10-login JS 入口(去掉 shell:true 的 cmd.exe 开销)、新增凭据进程间 TTL 缓存(不落明文);v0.1.19(2026-09-24)新增 ds 发现层聚合 groups/find/describe(进程内并发,全 58 分组扫表实测 ~5.5s),并修复 ds tables --name 因 listByPage 端点切换导致的关键词过滤静默失效;v0.1.18(2026-09-24)新增 ds fields-dsl(接口 /api/dw/newetl/chatBi/ds/fieldsForDSL),并移除凭据明文镜像同步(不再写 ~/.workbuddy/e10-login-cache.md);v0.1.20(2026-09-24)凭据来源切换为 weaver-work-cli 唯一来源、移除 e10-login 回退,并补齐 userId/tenantKey 传递(修复 attend statis 等命令报「缺少查询人员」的问题)。v0.1.21(2026-09-28)新增 module call —— 模块配置接口调用(配置中心驱动):已确定「哪个模块的哪条具体接口」之后的一条命令取数入口(精取该条 confAttrs → 按 http_method/input_params 组参 → 发请求(自动禁代理 + Cookie/eteamsid/UA 三件套)→ 提取精简结果),与技能自带 script/call_module.py 等价(参数名/退出码/提取口径全对齐),复用本 CLI 凭据缓存与 conf 通道、零临时文件;同时 auth 归一化与凭据缓存补齐 userAgent(供 AgentType UA 使用,缺失时从 cookie 的 agentType= 推导)。v0.1.22(2026-10-10):移除 `eb perm-page` 命令(EB 建模表单取数不再做权限前置校验,appId 直接取 ebdf_obj.app_id);`--fields`/`--group-by`/`--order` 等逗号列表支持 `@文件`(逗号字符串或 JSON 数组,与 --where/--stat/--dsl 一致,规避 shell 拆分导致的静默丢列/0 行)。v0.1.23(2026-10-13)新增 `refusal get` —— 拒答话术 getRefusalSpeechTechnique(入参仅 type,返回对象的 data = 话术字符串;默认 auto 通道 = POST multipart 表单优先、返回不含 data 时自动回退 GET ?type=,可用 --http post|get 锁定单通道)。v0.1.25(2026-10-14)新增 `scene groups|items` —— 场景定位元数据 getSceneGroups(① groups 分组骨架 / ② items --group <groupId> 组内条目),由技能 references/scene-locate/scripts/locate.mjs 整体迁入(属元数据定位接口、不取业务数据):默认输出精简 JSON(groups: groupId/groupName/itemCount/groupDesc;items: id/datasetName/datasetType/sourceId[/moduleName/sourceType/sourceGroupId/appId]/datasetDesc),--json 原样输出接口返回,计数走 stderr;--client agent|all|connector 默认 agent。v0.1.26(2026-10-15)新增 `refusal rules` —— 拒答话术规则 getRefusalSpeechRules(**无入参**,返回对象的 data = 对象数组;调用方式与 refusal get 同口径:默认 auto 通道 = POST 空 multipart 表单优先、返回不含 data 时回退 GET,可用 --http post|get 锁定单通道;人读直接打印 data 数组,--json 原样输出整个响应对象)。",
|
|
5
5
|
"author": "e10-dw",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|