@ats-cx/cx-cli 0.1.0
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/.env.example +8 -0
- package/README.md +119 -0
- package/bin/cx-cli.cjs +90 -0
- package/config/apm-provider.json +7 -0
- package/config/apm-provider.template.jsonc +48 -0
- package/config/diagnostic-rules.json +54 -0
- package/config/diagnostic-rules.template.jsonc +82 -0
- package/config/event-semantics.json +828 -0
- package/config/event-semantics.template.jsonc +13 -0
- package/config/toolkit.json +3 -0
- package/dist/apm-help.d.ts +5 -0
- package/dist/apm-help.js +108 -0
- package/dist/apm-output.d.ts +49 -0
- package/dist/apm-output.js +115 -0
- package/dist/budget.d.ts +14 -0
- package/dist/budget.js +16 -0
- package/dist/cli.d.ts +20 -0
- package/dist/cli.js +596 -0
- package/dist/context.d.ts +12 -0
- package/dist/context.js +20 -0
- package/dist/contract.d.ts +11 -0
- package/dist/contract.js +4 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/dist/init.d.ts +17 -0
- package/dist/init.js +194 -0
- package/dist/output.d.ts +7 -0
- package/dist/output.js +7 -0
- package/dist/project-pull.d.ts +32 -0
- package/dist/project-pull.js +81 -0
- package/dist/report.d.ts +3 -0
- package/dist/report.js +42 -0
- package/dist/skills.d.ts +12 -0
- package/dist/skills.js +430 -0
- package/dist/tools/apm-tools.d.ts +115 -0
- package/dist/tools/apm-tools.js +329 -0
- package/dist/tools/conclusion-tools.d.ts +24 -0
- package/dist/tools/conclusion-tools.js +61 -0
- package/dist/tools/create-run.d.ts +61 -0
- package/dist/tools/create-run.js +273 -0
- package/dist/tools/log-tools.d.ts +68 -0
- package/dist/tools/log-tools.js +116 -0
- package/dist/tools/project-tools.d.ts +82 -0
- package/dist/tools/project-tools.js +139 -0
- package/dist/workspace.d.ts +51 -0
- package/dist/workspace.js +104 -0
- package/package.json +37 -0
- package/skills/apm-query/SKILL.md +304 -0
- package/skills/apm-query/agents/openai.yaml +10 -0
- package/skills/cx-cli-setup/SKILL.md +120 -0
- package/skills/cx-cli-setup/agents/openai.yaml +11 -0
- package/skills/editor-diagnostic/SKILL.md +255 -0
- package/skills/editor-diagnostic/agents/openai.yaml +13 -0
- package/skills/semantics-curation/SKILL.md +151 -0
- package/skills/semantics-curation/agents/openai.yaml +12 -0
package/.env.example
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# cx-cli
|
|
2
|
+
|
|
3
|
+
面向编辑器研发与客诉排查同事的诊断工具箱:提供 `cx-cli` 命令行,以及可安装到 Claude Code / Codex 的 `editor-diagnostic`、`apm-query`、`cx-cli-setup`、`semantics-curation` 四个 Agent skills。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
在你日常默认的 node(哪怕是 10.x)下安装:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -g @ats-cx/cx-cli && cx-cli skills install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> 前提:机器上有一份 ≥ 22.12 的 node(`nvm install 24` 一次即可,**不必**改 default、不必 `nvm use`)。`nvm install` 会把当前终端切到 24——装 cx-cli 请开一个新终端(回到你日常的 node),再执行 `npm i -g @ats-cx/cx-cli`,否则包会装进 24 的目录,日常 node 10 的终端里找不到命令。
|
|
14
|
+
>
|
|
15
|
+
> npm 6(node 10 自带)安装时会打印下面这些警告,**这是预期的**,包已经装好;`cx-cli` 启动时会自动改用 `~/.nvm` 里 ≥ 22.12 的最高版本 node:
|
|
16
|
+
>
|
|
17
|
+
> ```text
|
|
18
|
+
> npm WARN notsup Unsupported engine for @ats-cx/cx-cli@<版本>: wanted: {"node":">=22.12"} (current: {"node":"10.24.0","npm":"6.14.11"})
|
|
19
|
+
> npm WARN notsup Not compatible with your version of node/npm: @ats-cx/cx-cli@<版本>
|
|
20
|
+
> npm WARN notsup Unsupported engine for @ats-cx/cx-core@<版本>: wanted: {"node":">=22.12"} (current: {"node":"10.24.0","npm":"6.14.11"})
|
|
21
|
+
> npm WARN notsup Not compatible with your version of node/npm: @ats-cx/cx-core@<版本>
|
|
22
|
+
> npm WARN notsup Unsupported engine for commander@15.0.0: wanted: {"node":">=22.12.0"} (current: {"node":"10.24.0","npm":"6.14.11"})
|
|
23
|
+
> npm WARN notsup Not compatible with your version of node/npm: commander@15.0.0
|
|
24
|
+
> npm WARN notsup Unsupported engine for sql-escaper@1.5.1: …
|
|
25
|
+
> npm WARN notsup Unsupported engine for sax@1.6.1: …
|
|
26
|
+
> npm WARN mysql2@3.24.2 requires a peer of @types/node@>= 8 but none is installed. You must install peer dependencies yourself.
|
|
27
|
+
> ```
|
|
28
|
+
>
|
|
29
|
+
> npm 6.11.x(node 10.17 自带)**一行 engines 警告都不打**,也正常。npm ≥ 7(node 16/18 自带)的同款警告长这样:`npm warn EBADENGINE Unsupported engine { package: '@ats-cx/cx-cli@<版本>', required: { node: '>=22.12' }, current: { node: 'v18.20.8', npm: '10.8.2' } }`。
|
|
30
|
+
>
|
|
31
|
+
> 验证:`cx-cli --version` 打印版本号即成功。若看到 `[cx-cli] 当前 node vX 低于要求(>= 22.12),且未找到可用的新版 node。` 按第二行提示做:`nvm install 24`,或(非 nvm 用户)`export CX_CLI_NODE=<node 可执行文件绝对路径>`。
|
|
32
|
+
>
|
|
33
|
+
> 只有 `~/.npmrc` 写了 `engine-strict=true` 时 `npm i -g` 会以 `npm ERR! code ENOTSUP` 拒装——临时加 `--no-engine-strict` 或删掉那行。
|
|
34
|
+
|
|
35
|
+
## 装进 Agent
|
|
36
|
+
|
|
37
|
+
`cx-cli skills install` 会把包内四个 skill 先链到 `~/.agents/skills/`,再链到 `~/.claude/skills/`;Codex 使用前者,Claude Code 使用后者。它是幂等命令,可以安全重跑。
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cx-cli skills status
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
全部链就绪时返回 `ok: true`;未就绪时会列出问题与修复命令。
|
|
44
|
+
|
|
45
|
+
## 初始化工作区
|
|
46
|
+
|
|
47
|
+
每个编辑器源码仓库执行一次:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd <编辑器源码仓库>
|
|
51
|
+
cx-cli init
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
也可以在该仓库的 Agent 会话里说「安装 cx-cli」,由 `cx-cli-setup` skill 引导完成。
|
|
55
|
+
|
|
56
|
+
## 站点地址
|
|
57
|
+
|
|
58
|
+
APM 站点地址不随包分发。请向团队获取实际值,填入 `~/.config/cx-cli/apm-provider.local.json`:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{"baseUrl":"https://…","defaults":{"host":"www.…"}}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
未配置时会看到类似:`apm 未配置:请在 /Users/<用户名>/.config/cx-cli/apm-provider.local.json 填 baseUrl 与 defaults.host(值向团队获取)。`
|
|
65
|
+
|
|
66
|
+
## DB 凭据
|
|
67
|
+
|
|
68
|
+
只有 `cx-cli project pull` 读取 DB 凭据。在编辑器源码仓库的 `.cx-cli/.env` 填写:
|
|
69
|
+
|
|
70
|
+
```dotenv
|
|
71
|
+
DB_HOST=
|
|
72
|
+
DB_USER=
|
|
73
|
+
DB_PASSWORD=
|
|
74
|
+
DB_NAME=
|
|
75
|
+
DB_PORT=
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
这五个值向团队获取,只留本机,不要入库或转发。
|
|
79
|
+
|
|
80
|
+
## 升级
|
|
81
|
+
|
|
82
|
+
升级、降级同形;在安装时所用的 node 版本下执行:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm i -g @ats-cx/cx-cli@latest && cx-cli skills install
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`skills install` 幂等:新版本新增的 skill 会链上(created),更名 / 删除的旧链自动清理(pruned),其余不动。
|
|
89
|
+
升级不碰任何仓库的 `.cx-cli/` 工作区与 `~/.config/cx-cli/`,无需重跑 `cx-cli init`,Agent 无需重启。
|
|
90
|
+
随时可用 `cx-cli skills status` 检查链是否就绪(未就绪 exit 1 并给出修复命令)。
|
|
91
|
+
|
|
92
|
+
## 卸载
|
|
93
|
+
|
|
94
|
+
先解链再删包(反过来链会悬空且没命令可删):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cx-cli skills uninstall && npm rm -g @ats-cx/cx-cli
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`nvm uninstall <装包的 node 版本>` 等同于删包,之前同样先 `cx-cli skills uninstall`。
|
|
101
|
+
可选清理(都是手动,cx-cli 不代删):
|
|
102
|
+
|
|
103
|
+
- `rm -rf ~/.config/cx-cli`:机器级覆盖目录,含 apm 覆盖、`.env` 回落与无工作区时的 `runs/ out/ data/` 产物。
|
|
104
|
+
- `rm -rf <编辑器源码仓库>/.cx-cli`:该仓库的诊断工作区(含全部 run 产物)。其中 `event-semantics.json` 与 `curation/` 随宿主仓库 git 留档,先决定去留。
|
|
105
|
+
|
|
106
|
+
顺序做反了、或 `nvm uninstall` 之后没 `cx-cli` 可用:`npx @ats-cx/cx-cli skills uninstall` 会清掉悬空链。
|
|
107
|
+
不想装任何东西:`find ~/.agents/skills ~/.claude/skills ~/.codex/skills -maxdepth 1 -type l ! -exec test -e {} \; -delete`(删这三处全部悬空链,含非 cx-cli 的)。
|
|
108
|
+
|
|
109
|
+
## nvm 多个 node 版本
|
|
110
|
+
|
|
111
|
+
全局包按 node 版本隔离:在哪个版本下装,就在哪个版本下升级 / 卸载;切到别的版本后 `cx-cli` 命令消失(包与链都还在)。
|
|
112
|
+
迁移到新版本:`nvm use <新> && nvm reinstall-packages <旧>`,然后重跑 `cx-cli skills install`。
|
|
113
|
+
装了两份时 `cx-cli skills status` 会报 `stale` 并说明链指向哪一份。
|
|
114
|
+
|
|
115
|
+
## 用法入口
|
|
116
|
+
|
|
117
|
+
运行 `cx-cli --help` 查看完整命令;支持 `--json` 稳定 JSON 输出。退出码:`0` 成功、`1` 业务失败、`2` 参数错误。
|
|
118
|
+
|
|
119
|
+
源码仓库为私有仓库,不提供公开链接;遇到问题请联系工具箱维护者。
|
package/bin/cx-cli.cjs
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// cx-cli 启动器。宿主编辑器仓库常把 shell 的 node 钉在 10.x(.nvmrc),而 dist/ 是 ESM,
|
|
4
|
+
// 老 node 连 `import` 语句都解析不了,报出来的是一坨 SyntaxError 堆栈。本文件只用老 node 也能解析的
|
|
5
|
+
// 语法:先查版本,不达标就找一个达标的 node 重新执行自己($CX_CLI_NODE 优先,其次 ~/.nvm 里最高的
|
|
6
|
+
// 达标版本);找不到再给出人能照做的提示。达标时直接加载 dist/index.js,行为与之前完全一致。
|
|
7
|
+
var MIN_NODE = [22, 12];
|
|
8
|
+
var fs = require("fs");
|
|
9
|
+
var os = require("os");
|
|
10
|
+
var path = require("path");
|
|
11
|
+
var childProcess = require("child_process");
|
|
12
|
+
|
|
13
|
+
function parseVersion(text) {
|
|
14
|
+
var match = /v?(\d+)\.(\d+)/.exec(text || "");
|
|
15
|
+
return match ? [Number(match[1]), Number(match[2])] : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function satisfies(version) {
|
|
19
|
+
return !!version && (version[0] > MIN_NODE[0] || (version[0] === MIN_NODE[0] && version[1] >= MIN_NODE[1]));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isExecutable(file) {
|
|
23
|
+
try {
|
|
24
|
+
fs.accessSync(file, fs.constants.X_OK);
|
|
25
|
+
return true;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isCompatibleNode(file) {
|
|
32
|
+
if (!isExecutable(file)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
var result = childProcess.spawnSync(file, ["--version"], { encoding: "utf8" });
|
|
36
|
+
return !result.error && result.status === 0 && satisfies(parseVersion(result.stdout));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function findNewerNode() {
|
|
40
|
+
var candidates = [];
|
|
41
|
+
if (process.env.CX_CLI_NODE) {
|
|
42
|
+
candidates.push(process.env.CX_CLI_NODE);
|
|
43
|
+
}
|
|
44
|
+
var nvmNodeDir = path.join(process.env.NVM_DIR || path.join(os.homedir(), ".nvm"), "versions", "node");
|
|
45
|
+
var names = [];
|
|
46
|
+
try {
|
|
47
|
+
names = fs.readdirSync(nvmNodeDir);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
names = [];
|
|
50
|
+
}
|
|
51
|
+
names
|
|
52
|
+
.map(function (name) { return { name: name, version: parseVersion(name) }; })
|
|
53
|
+
.filter(function (item) { return satisfies(item.version); })
|
|
54
|
+
.sort(function (a, b) { return b.version[0] - a.version[0] || b.version[1] - a.version[1]; })
|
|
55
|
+
.forEach(function (item) { candidates.push(path.join(nvmNodeDir, item.name, "bin", "node")); });
|
|
56
|
+
for (var i = 0; i < candidates.length; i += 1) {
|
|
57
|
+
if (isCompatibleNode(candidates[i])) {
|
|
58
|
+
return candidates[i];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var entry = path.join(__dirname, "..", "dist", "index.js");
|
|
65
|
+
|
|
66
|
+
if (satisfies(parseVersion(process.versions.node))) {
|
|
67
|
+
// 用 Function 包一层:本文件必须能被老 node 解析,不能直接写 import() 语法。
|
|
68
|
+
new Function("specifier", "return import(specifier)")(require("url").pathToFileURL(entry).href).catch(function (error) {
|
|
69
|
+
console.error(error && error.stack ? error.stack : String(error));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
var newerNode = findNewerNode();
|
|
74
|
+
if (!newerNode) {
|
|
75
|
+
console.error(
|
|
76
|
+
"[cx-cli] 当前 node v" + process.versions.node + " 低于要求(>= " + MIN_NODE.join(".") + "),且未找到可用的新版 node。\n" +
|
|
77
|
+
"请安装 node 24(nvm install 24),或设置 CX_CLI_NODE=<node 可执行文件绝对路径> 后重试。"
|
|
78
|
+
);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
var result = childProcess.spawnSync(newerNode, [entry].concat(process.argv.slice(2)), {
|
|
82
|
+
stdio: "inherit",
|
|
83
|
+
env: process.env,
|
|
84
|
+
});
|
|
85
|
+
if (result.error) {
|
|
86
|
+
console.error("[cx-cli] 无法用 " + newerNode + " 启动:" + result.error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
90
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"baseUrl": "",
|
|
3
|
+
"defaults": { "bizline_id": "US", "app_id": "10001", "host": "" },
|
|
4
|
+
"runPreset": { "type": "user_behav", "log_time_start": "" },
|
|
5
|
+
"fetch": { "pageSize": 5000, "maxPages": 50 },
|
|
6
|
+
"timeoutMs": { "query": 300000, "flush": 30000, "portal": 30000 }
|
|
7
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
// APM 网页端根地址,供全部 query / flush / portal 路径使用。
|
|
3
|
+
// 只允许 http(s) URL;运行时会移除尾部斜杠。
|
|
4
|
+
"baseUrl": "https://apm.example.com",
|
|
5
|
+
|
|
6
|
+
// 默认过滤值:apm query 未显式传参时使用,run new 的日志预设也复用 app_id / bizline_id;
|
|
7
|
+
// bizline_id 与 app_id 都必须是非空字符串。
|
|
8
|
+
// host 供 apm resolve / apm project 使用,必须是至少三段的完整站点 host,如 www.example.com。
|
|
9
|
+
"defaults": {
|
|
10
|
+
"bizline_id": "US",
|
|
11
|
+
"app_id": "10001",
|
|
12
|
+
"host": "www.example.com"
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
// 只供 run new 直拉日志使用。type 必须是以下 9 种日志类型之一:
|
|
16
|
+
// error / performance / api / paint / user_behav / network / server_error / footprint / server_api。
|
|
17
|
+
// log_time_start 为空或缺省表示拉项目全史;非空时支持 YYYY-MM-DD、
|
|
18
|
+
// YYYY-MM-DD HH:mm:ss、YYYY-MM-DDTHH:mm:ss,且不能携带时区后缀。
|
|
19
|
+
"runPreset": {
|
|
20
|
+
"type": "user_behav",
|
|
21
|
+
"log_time_start": ""
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// apm query 与 run new 共用的取数页设置,均须为正整数。
|
|
25
|
+
// pageSize 是单次接口取数行数;maxPages 是结果不完整前的硬上限。
|
|
26
|
+
"fetch": {
|
|
27
|
+
"pageSize": 5000,
|
|
28
|
+
"maxPages": 50
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// 各端点超时,单位毫秒,均须为正整数:query 供 apm query / run new,
|
|
32
|
+
// flush 供查询前自动同步与 apm flush,portal 供 apm resolve / apm project。
|
|
33
|
+
"timeoutMs": {
|
|
34
|
+
"query": 300000,
|
|
35
|
+
"flush": 30000,
|
|
36
|
+
"portal": 30000
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 站点地址不随包分发。本机覆盖写在 ~/.config/cx-cli/apm-provider.local.json(分发通道;
|
|
40
|
+
// 遵 $XDG_CONFIG_HOME),或本文件同目录的 apm-provider.local.json(开发通道单 clone 试验用,最后合并、最优先);
|
|
41
|
+
// 运行时与本文件同形状深合并。同事只需填这两项(值向团队获取):
|
|
42
|
+
// { "baseUrl": "https://apm.example.com", "defaults": { "host": "www.example.com" } }
|
|
43
|
+
// 切到别的站点时可再覆盖:
|
|
44
|
+
// { "defaults": { "host": "www.example.org", "bizline_id": "<业务线>" } }
|
|
45
|
+
//
|
|
46
|
+
// 以下机制不在配置文件里:请求形状、order 恒传、origin header、值校验与翻页逻辑;
|
|
47
|
+
// 它们由 core 客户端固定,local 覆盖只能改值,不能改机制。
|
|
48
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": [
|
|
3
|
+
{
|
|
4
|
+
"id": "explicit_error_signal",
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"kind": "explicit_error",
|
|
7
|
+
"severity": "high",
|
|
8
|
+
"description": "识别事件本身带错误语义,或者 payload 内显式包含 message/stack 的情况。",
|
|
9
|
+
"reasonTemplates": {
|
|
10
|
+
"default": "事件 {eventName} 具有显式失败语义,建议直接查看错误信息、调用栈和相关接口响应。"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "state_change_without_save",
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"kind": "state_change_without_save",
|
|
17
|
+
"includePossibleStateChange": true,
|
|
18
|
+
"description": "识别发生状态变更后,没有看到保存就离开页面的情况。",
|
|
19
|
+
"severityByStateChange": {
|
|
20
|
+
"definite": "medium",
|
|
21
|
+
"possible": "low"
|
|
22
|
+
},
|
|
23
|
+
"reasonTemplates": {
|
|
24
|
+
"default": "最后一个 {stateChangeLabel} 是 {lastEventTime} 的 {lastEventName},但在离开页面前没有看到保存事件。"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "reentry_after_leave",
|
|
29
|
+
"enabled": true,
|
|
30
|
+
"kind": "reentry_after_leave",
|
|
31
|
+
"severity": "low",
|
|
32
|
+
"maxGapSeconds": 30,
|
|
33
|
+
"description": "识别用户离开编辑器后短时间内重新进入的链路。",
|
|
34
|
+
"reasonTemplates": {
|
|
35
|
+
"default": "用户在离开编辑器 {gapSeconds} 秒后再次进入,这通常意味着刷新、异常恢复或手动重开。"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "state_change_save_reentry",
|
|
40
|
+
"enabled": true,
|
|
41
|
+
"kind": "state_change_save_reentry",
|
|
42
|
+
"includePossibleStateChange": true,
|
|
43
|
+
"lookahead": 8,
|
|
44
|
+
"description": "识别状态变更之后出现保存,并且随后重新进入编辑器的链路。",
|
|
45
|
+
"severityByStateChange": {
|
|
46
|
+
"definite": "medium",
|
|
47
|
+
"possible": "low"
|
|
48
|
+
},
|
|
49
|
+
"reasonTemplates": {
|
|
50
|
+
"default": "{stateChangeLabel} {eventName} 之后出现了保存,随后又重新进入编辑器。建议对比这个时间点前后的 project 版本,确认状态是否真正落盘。"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
// 这个文件是中文注释模板,不参与运行。
|
|
3
|
+
// 真正生效的配置文件是 diagnostic-rules.json。
|
|
4
|
+
//
|
|
5
|
+
// 维护原则:
|
|
6
|
+
// 1. 规则尽量围绕“语义标签”写,不围绕具体事件名写。
|
|
7
|
+
// 2. 新增事件时优先补 event-semantics.json,而不是直接新增规则。
|
|
8
|
+
// 3. 只有当现有通用规则覆盖不了某类客诉时,再新增规则。
|
|
9
|
+
//
|
|
10
|
+
// 支持的规则 kind:
|
|
11
|
+
// - explicit_error: 显式失败信号
|
|
12
|
+
// - state_change_without_save: 变更后离开但没保存
|
|
13
|
+
// - reentry_after_leave: 离开后快速重进
|
|
14
|
+
// - state_change_save_reentry: 变更后保存,再次进入
|
|
15
|
+
//
|
|
16
|
+
// 通用字段:
|
|
17
|
+
// - id: 规则唯一标识,输出报告时会带上
|
|
18
|
+
// - enabled: 是否启用
|
|
19
|
+
// - kind: 规则类型
|
|
20
|
+
// - severity: 固定严重级别,可选
|
|
21
|
+
// - description: 给团队看的说明
|
|
22
|
+
// - reasonTemplates.default: 输出给报告的中文文案模板
|
|
23
|
+
//
|
|
24
|
+
// 部分规则专用字段:
|
|
25
|
+
// - includePossibleStateChange: 是否把 stateChange=possible 也算入规则
|
|
26
|
+
// - severityByStateChange: 根据 none/possible/definite/commit 动态给严重级别
|
|
27
|
+
// - maxGapSeconds: 两个事件之间允许的最大秒数
|
|
28
|
+
// - lookahead: 向后看多少条事件
|
|
29
|
+
|
|
30
|
+
"rules": [
|
|
31
|
+
{
|
|
32
|
+
"id": "explicit_error_signal",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"kind": "explicit_error",
|
|
35
|
+
"severity": "high",
|
|
36
|
+
"description": "识别事件自带错误语义的情况。",
|
|
37
|
+
"reasonTemplates": {
|
|
38
|
+
"default": "事件 {eventName} 具有显式失败语义,建议直接查看错误信息、调用栈和相关接口响应。"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "state_change_without_save",
|
|
43
|
+
"enabled": true,
|
|
44
|
+
"kind": "state_change_without_save",
|
|
45
|
+
"includePossibleStateChange": true,
|
|
46
|
+
"severityByStateChange": {
|
|
47
|
+
"definite": "medium",
|
|
48
|
+
"possible": "low"
|
|
49
|
+
},
|
|
50
|
+
"description": "识别发生状态变更之后离开页面,但没有看到保存事件。",
|
|
51
|
+
"reasonTemplates": {
|
|
52
|
+
"default": "最后一个 {stateChangeLabel} 是 {lastEventTime} 的 {lastEventName},但在离开页面前没有看到保存事件。"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "reentry_after_leave",
|
|
57
|
+
"enabled": true,
|
|
58
|
+
"kind": "reentry_after_leave",
|
|
59
|
+
"severity": "low",
|
|
60
|
+
"maxGapSeconds": 30,
|
|
61
|
+
"description": "识别离开后短时间内重新进入的情况。",
|
|
62
|
+
"reasonTemplates": {
|
|
63
|
+
"default": "用户在离开编辑器 {gapSeconds} 秒后再次进入,这通常意味着刷新、异常恢复或手动重开。"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "state_change_save_reentry",
|
|
68
|
+
"enabled": true,
|
|
69
|
+
"kind": "state_change_save_reentry",
|
|
70
|
+
"includePossibleStateChange": true,
|
|
71
|
+
"lookahead": 8,
|
|
72
|
+
"severityByStateChange": {
|
|
73
|
+
"definite": "medium",
|
|
74
|
+
"possible": "low"
|
|
75
|
+
},
|
|
76
|
+
"description": "识别状态变更之后出现保存,并在之后重新进入编辑器的链路。",
|
|
77
|
+
"reasonTemplates": {
|
|
78
|
+
"default": "{stateChangeLabel} {eventName} 之后出现了保存,随后又重新进入编辑器。建议对比这个时间点前后的 project 版本,确认状态是否真正落盘。"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|