@cvtoolman/huawei-lts-cli 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -1,194 +1,261 @@
1
- # huawei-lts-cli — CLI + SKILL
2
-
3
- **简体中文** | [English](README_en.md)
4
-
5
- [![npm version](https://img.shields.io/npm/v/@cvtoolman/huawei-lts-cli.svg)](https://www.npmjs.com/package/@cvtoolman/huawei-lts-cli)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
-
8
- > 让你的 AI 编程助手(Claude Code、Cursor、Copilot、Qoder 等)通过自然语言查询华为云日志服务(LTS)。
9
-
10
- **一个工具,两部分:**
11
-
12
- | 部分 | 作用 |
13
- |---|---|
14
- | **CLI** (`lts-cli`) | 轻量命令行工具,对接华为云 LTS API |
15
- | **SKILL** (`SKILL.md`) | 一份给 AI 看的"说明书",教它如何把自然语言转成 CLI 命令 |
16
-
17
- AI 读完 skill 后,你只需说一句"查下今天的 ERROR 日志",AI 就能自动拼出正确的 `lts-cli` 命令并执行。不用记参数,不用手写 ISO 8601 时间格式。
18
-
19
- ## 为什么用 CLI + SKILL 而不是 MCP?
20
-
21
- AI 编程助手的上下文窗口很宝贵——一边要装代码库、一边要推理、一边还要跑工具。**省 token 就是省时省钱。**
22
-
23
- | | CLI + SKILL | MCP |
24
- |---|---|---|
25
- | **上下文开销** | **低** — skill 就一个短 markdown 文件,CLI 输出是纯文本 | **高** — 工具 schema + 快照数据常驻上下文 |
26
- | **AI 使用方式** | 执行 shell 命令,读取结果 | 通过协议调用结构化工具 |
27
- | **配置难度** | `npm install -g`、一个 skill 文件 | 服务进程、配置连线 |
28
- | **适用场景** | 编码过程中顺手查日志 | 长时间运行的自动化循环 |
29
-
30
- > **一句话:** 如果你想让 AI 在写代码时顺嘴帮你查日志——CLI + SKILL 是更轻、更省钱的方案。
31
-
32
- ## 快速开始
33
-
34
- ### 1. 安装 CLI
35
-
36
- ```bash
37
- npm install -g @cvtoolman/huawei-lts-cli
38
- ```
39
-
40
- ### 2. 配置凭证
41
-
42
- ```bash
43
- lts-cli init
44
- ```
45
-
46
- 向导会依次询问 AK、SK、Project ID、Region,一次配好。配置存储在 `~/.lts-cli/config.json`。
47
-
48
- ### 3. 安装 Skill(给 AI 工具用)
49
-
50
- **Claude Code:**
51
- ```bash
52
- mkdir -p .claude/skills/huawei-lts-log-query
53
- curl -o .claude/skills/huawei-lts-log-query/SKILL.md \
54
- https://raw.githubusercontent.com/jcxy/huawei-lts-cli/main/skills/huawei-lts-log-query/SKILL.md
55
- ```
56
-
57
- **Qoder:**
58
- ```bash
59
- mkdir -p .qoder/skills/huawei-lts-log-query
60
- curl -o .qoder/skills/huawei-lts-log-query/SKILL.md \
61
- https://raw.githubusercontent.com/jcxy/huawei-lts-cli/main/skills/huawei-lts-log-query/SKILL.md
62
- ```
63
-
64
- **手动安装(任意 AI 工具):** 将 [skills/huawei-lts-log-query/SKILL.md](skills/huawei-lts-log-query/SKILL.md) 复制到对应 AI 工具的 skills 目录下(`.claude/skills/`、`.qoder/skills/`、`.cursor/skills/` 等)。
65
-
66
- ### 4. 命令行直接使用(不依赖 AI)
67
-
68
- ```bash
69
- # 基础查询
70
- lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
71
-
72
- # 关键词搜索
73
- lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z -k "ERROR"
74
-
75
- # JSON 格式输出,管道给 jq 处理
76
- lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z -f json | jq .
77
- ```
78
-
79
- ## 命令参考
80
-
81
- ### `lts-cli query` — 查询日志
82
-
83
- ```
84
- lts-cli query [选项]
85
-
86
- 选项:
87
- -g, --group-id <groupId> 日志组 ID(可在配置中预设)
88
- -s, --stream-id <streamId> 日志流 ID(可在配置中预设)
89
- --start-time, --st <time> 开始时间,ISO 8601 格式(必填)
90
- --end-time, --et <time> 结束时间,ISO 8601 格式(必填)
91
- -k, --keyword <keyword> 搜索关键词
92
- -l, --limit <limit> 每页条数(默认: 100)
93
- -o, --offset <offset> 分页偏移量(默认: 0)
94
- -r, --reverse 按时间倒序
95
- -f, --format <format> 输出格式: pretty、json、table(默认: pretty)
96
- --no-paginate 关闭自动翻页
97
- ```
98
-
99
- ### `lts-cli config` — 管理配置
100
-
101
- ```
102
- lts-cli config [选项]
103
-
104
- 选项:
105
- --set <key=value> 设置配置项
106
- --get <key> 查看配置项
107
- --list 列出所有配置
108
- --unset <key> 删除配置项
109
- ```
110
-
111
- ### `lts-cli init` — 配置向导
112
-
113
- ```
114
- lts-cli init
115
-
116
- 交互式向导,引导设置 AK、SK、Project ID、Region、endpoint,
117
- 以及可选的默认日志组和日志流。
118
- ```
119
-
120
- ### `lts-cli completion` — Shell 补全
121
-
122
- ```
123
- lts-cli completion <bash|zsh|powershell>
124
-
125
- 生成 shell 补全脚本。
126
- ```
127
-
128
- ## 配置说明
129
-
130
- 配置存储在 `~/.lts-cli/config.json`(Linux/macOS)或 `%USERPROFILE%\.lts-cli\config.json`(Windows)。
131
-
132
- | 键 | 必填 | 说明 |
133
- |---|---|---|
134
- | `ak` | 是 | 华为云访问密钥 |
135
- | `sk` | 是 | 华为云私有密钥 |
136
- | `projectId` | 是 | 项目 ID |
137
- | `region` | 否 | 如 `cn-south-1` |
138
- | `endpoint` | 否 | 需包含 `https://` |
139
- | `groupId` | 否 | 默认日志组 ID |
140
- | `streamId` | 否 | 默认日志流 ID |
141
-
142
- ### 环境变量
143
-
144
- 所有配置项也支持环境变量(适用于 CI/CD):
145
-
146
- | 配置键 | 环境变量 |
147
- |---|---|
148
- | `ak` | `LTS_AK` |
149
- | `sk` | `LTS_SK` |
150
- | `projectId` | `LTS_PROJECT_ID` |
151
- | `region` | `LTS_REGION` |
152
- | `endpoint` | `LTS_ENDPOINT` |
153
- | `groupId` | `LTS_GROUP_ID` |
154
- | `streamId` | `LTS_STREAM_ID` |
155
-
156
- 环境变量优先级高于配置文件。
157
-
158
- ## 支持的区域
159
-
160
- | 区域 ID | 区域名称 | Endpoint |
161
- |---|---|---|
162
- | `cn-north-1` | 华北-北京一 | `lts.cn-north-1.myhuaweicloud.com` |
163
- | `cn-north-4` | 华北-北京四 | `lts.cn-north-4.myhuaweicloud.com` |
164
- | `cn-east-2` | 华东-上海二 | `lts.cn-east-2.myhuaweicloud.com` |
165
- | `cn-east-3` | 华东-上海三 | `lts.cn-east-3.myhuaweicloud.com` |
166
- | `cn-south-1` | 华南-广州 | `lts.cn-south-1.myhuaweicloud.com` |
167
- | `cn-south-4` | 华南-深圳 | `lts.cn-south-4.myhuaweicloud.com` |
168
- | `cn-southwest-2` | 西南-贵阳一 | `lts.cn-southwest-2.myhuaweicloud.com` |
169
- | `ap-southeast-1` | 亚太-新加坡 | `lts.ap-southeast-1.myhuaweicloud.com` |
170
- | `ap-southeast-2` | 亚太-曼谷 | `lts.ap-southeast-2.myhuaweicloud.com` |
171
- | `ap-southeast-3` | 亚太-雅加达 | `lts.ap-southeast-3.myhuaweicloud.com` |
172
- | `af-south-1` | 非洲-约翰内斯堡 | `lts.af-south-1.myhuaweicloud.com` |
173
-
174
- > 完整列表请参考 [华为云 LTS 终端节点](https://support.huaweicloud.com/api-lts/lts_api_0011.html)。
175
-
176
- ## 开发指南
177
-
178
- ```bash
179
- git clone https://github.com/jcxy/huawei-lts-cli.git
180
- cd huawei-lts-cli
181
- npm install
182
- npm run build
183
-
184
- # 开发模式运行(无需编译)
185
- npm run dev -- query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
186
-
187
- # 本地测试
188
- npm link
189
- lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
190
- ```
191
-
192
- ## License
193
-
194
- [MIT](LICENSE)
1
+ # huawei-lts-cli — CLI + SKILL
2
+
3
+ **简体中文** | [English](README_en.md)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@cvtoolman/huawei-lts-cli.svg)](https://www.npmjs.com/package/@cvtoolman/huawei-lts-cli)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ > 让你的 AI 编程助手(Claude Code、Cursor、Copilot、Qoder 等)通过自然语言查询华为云日志服务(LTS)。
9
+
10
+ **一个工具,两部分:**
11
+
12
+ | 部分 | 作用 |
13
+ |---|---|
14
+ | **CLI** (`lts-cli`) | 轻量命令行工具,对接华为云 LTS API |
15
+ | **SKILL** (`SKILL.md`) | 一份给 AI 看的"说明书",教它如何把自然语言转成 CLI 命令 |
16
+
17
+ AI 读完 skill 后,你只需说一句"查下今天的 ERROR 日志",AI 就能自动拼出正确的 `lts-cli` 命令并执行。不用记参数,不用手写 ISO 8601 时间格式。
18
+
19
+ ## 为什么用 CLI + SKILL 而不是 MCP?
20
+
21
+ AI 编程助手的上下文窗口很宝贵——一边要装代码库、一边要推理、一边还要跑工具。**省 token 就是省时省钱。**
22
+
23
+ | | CLI + SKILL | MCP |
24
+ |---|---|---|
25
+ | **上下文开销** | **低** — skill 就一个短 markdown 文件,CLI 输出是纯文本 | **高** — 工具 schema + 快照数据常驻上下文 |
26
+ | **AI 使用方式** | 执行 shell 命令,读取结果 | 通过协议调用结构化工具 |
27
+ | **配置难度** | `npm install -g`、一个 skill 文件 | 服务进程、配置连线 |
28
+ | **适用场景** | 编码过程中顺手查日志 | 长时间运行的自动化循环 |
29
+
30
+ > **一句话:** 如果你想让 AI 在写代码时顺嘴帮你查日志——CLI + SKILL 是更轻、更省钱的方案。
31
+
32
+ ## 快速开始
33
+
34
+ ### 1. 安装 CLI
35
+
36
+ ```bash
37
+ npm install -g @cvtoolman/huawei-lts-cli
38
+ ```
39
+
40
+ ### 2. 配置凭证
41
+
42
+ ```bash
43
+ lts-cli init
44
+ ```
45
+
46
+ 向导会依次询问 AK、SK、Project ID、Region,一次配好。配置存储在 `~/.lts-cli/config.json`。
47
+
48
+ ### 3. 安装 Skill(给 AI 工具用)
49
+
50
+ **Claude Code:**
51
+ ```bash
52
+ mkdir -p .claude/skills/huawei-lts-log-query
53
+ curl -o .claude/skills/huawei-lts-log-query/SKILL.md \
54
+ https://raw.githubusercontent.com/jcxy/huawei-lts-cli/main/skills/huawei-lts-log-query/SKILL.md
55
+ ```
56
+
57
+ **Qoder:**
58
+ ```bash
59
+ mkdir -p .qoder/skills/huawei-lts-log-query
60
+ curl -o .qoder/skills/huawei-lts-log-query/SKILL.md \
61
+ https://raw.githubusercontent.com/jcxy/huawei-lts-cli/main/skills/huawei-lts-log-query/SKILL.md
62
+ ```
63
+
64
+ **手动安装(任意 AI 工具):** 将 [skills/huawei-lts-log-query/SKILL.md](skills/huawei-lts-log-query/SKILL.md) 复制到对应 AI 工具的 skills 目录下(`.claude/skills/`、`.qoder/skills/`、`.cursor/skills/` 等)。
65
+
66
+ ### 4. 命令行直接使用(不依赖 AI)
67
+
68
+ ```bash
69
+ # 基础查询
70
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
71
+
72
+ # 简单关键词搜索(旧版,向后兼容)
73
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z -k "ERROR"
74
+
75
+ # 高级查询:多字段组合(推荐)
76
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
77
+ -q "content:error AND appName:myapp"
78
+
79
+ # 复杂逻辑查询
80
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
81
+ -q "(level:ERROR OR level:WARN) NOT env:test"
82
+
83
+ # SQL 分析查询
84
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
85
+ -q "SELECT count(*) as cnt, level FROM log GROUP BY level" \
86
+ -f json
87
+
88
+ # JSON 格式输出,管道给 jq 处理
89
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z -f json | jq .
90
+ ```
91
+
92
+ > 💡 **提示**:使用 `-q` 参数可实现与 LTS 控制台相同的多条件组合查询功能。详见 [查询语法速查表](skills/huawei-lts-log-query/references/cheatsheet.md) 和 [高级查询指南](skills/huawei-lts-log-query/references/advanced-query-guide.md)。
93
+
94
+ ## 命令参考
95
+
96
+ ### `lts-cli query` — 查询日志
97
+
98
+ ```bash
99
+ lts-cli query [选项]
100
+
101
+ 选项:
102
+ -g, --group-id <groupId> 日志组 ID(可在配置中预设)
103
+ -s, --stream-id <streamId> 日志流 ID(可在配置中预设)
104
+ --start-time, --st <time> 开始时间,ISO 8601 格式(必填)
105
+ --end-time, --et <time> 结束时间,ISO 8601 格式(必填)
106
+ -k, --keyword <keyword> 简单关键词搜索(旧版,不推荐)
107
+ -q, --query <query> 高级查询表达式(推荐):
108
+ - 字段查询: content:error AND appName:myapp
109
+ - 比较运算: time>60 AND region:r
110
+ - SQL语法: SELECT * FROM log WHERE ...
111
+ - 逻辑运算符: AND, OR, NOT(需空格分隔)
112
+ -l, --limit <limit> 每页条数(默认: 100)
113
+ -o, --offset <offset> 分页偏移量(默认: 0)
114
+ -r, --reverse 按时间倒序
115
+ -f, --format <format> 输出格式: pretty、json、table(默认: pretty)
116
+ --no-paginate 关闭自动翻页
117
+ ```
118
+
119
+ #### 高级查询语法示例
120
+
121
+ **字段查询:**
122
+ ```bash
123
+ # 单字段匹配
124
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
125
+ -q "content:error"
126
+
127
+ # 多字段组合(且关系)
128
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
129
+ -q "content:error AND appName:myapp AND node:server1"
130
+
131
+ # 多字段组合(或关系)
132
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
133
+ -q "level:ERROR OR level:WARN"
134
+
135
+ # 排除条件
136
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
137
+ -q "level:DEBUG NOT module:test"
138
+
139
+ # 数值比较
140
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
141
+ -q "response_time>1000 AND status_code!=200"
142
+
143
+ # 复杂组合
144
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
145
+ -q "(level:ERROR OR level:WARN) NOT env:test"
146
+ ```
147
+
148
+ **SQL 查询:**
149
+ ```bash
150
+ # 统计各应用错误数量
151
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
152
+ -q "SELECT count(*) as cnt, appName FROM log WHERE content LIKE '%error%' GROUP BY appName"
153
+
154
+ # 平均响应时间
155
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z \
156
+ -q "SELECT avg(response_time) as avg_time FROM log WHERE status_code=200"
157
+ ```
158
+
159
+ > ⚠️ **注意**:AND、OR、NOT 前后必须有**空格**!
160
+
161
+ 详细文档请查看:
162
+ - [查询语法速查表](skills/huawei-lts-log-query/references/cheatsheet.md)
163
+ - [高级查询指南](skills/huawei-lts-log-query/references/advanced-query-guide.md)
164
+ - [控制台 vs CLI 对照](skills/huawei-lts-log-query/references/query-comparison.md)
165
+
166
+ ### `lts-cli config` — 管理配置
167
+
168
+ ```
169
+ lts-cli config [选项]
170
+
171
+ 选项:
172
+ --set <key=value> 设置配置项
173
+ --get <key> 查看配置项
174
+ --list 列出所有配置
175
+ --unset <key> 删除配置项
176
+ ```
177
+
178
+ ### `lts-cli init` — 配置向导
179
+
180
+ ```
181
+ lts-cli init
182
+
183
+ 交互式向导,引导设置 AK、SK、Project ID、Region、endpoint,
184
+ 以及可选的默认日志组和日志流。
185
+ ```
186
+
187
+ ### `lts-cli completion` — Shell 补全
188
+
189
+ ```
190
+ lts-cli completion <bash|zsh|powershell>
191
+
192
+ 生成 shell 补全脚本。
193
+ ```
194
+
195
+ ## 配置说明
196
+
197
+ 配置存储在 `~/.lts-cli/config.json`(Linux/macOS)或 `%USERPROFILE%\.lts-cli\config.json`(Windows)。
198
+
199
+ | 键 | 必填 | 说明 |
200
+ |---|---|---|
201
+ | `ak` | 是 | 华为云访问密钥 |
202
+ | `sk` | 是 | 华为云私有密钥 |
203
+ | `projectId` | 是 | 项目 ID |
204
+ | `region` | 否 | 如 `cn-south-1` |
205
+ | `endpoint` | 否 | 需包含 `https://` |
206
+ | `groupId` | 否 | 默认日志组 ID |
207
+ | `streamId` | 否 | 默认日志流 ID |
208
+
209
+ ### 环境变量
210
+
211
+ 所有配置项也支持环境变量(适用于 CI/CD):
212
+
213
+ | 配置键 | 环境变量 |
214
+ |---|---|
215
+ | `ak` | `LTS_AK` |
216
+ | `sk` | `LTS_SK` |
217
+ | `projectId` | `LTS_PROJECT_ID` |
218
+ | `region` | `LTS_REGION` |
219
+ | `endpoint` | `LTS_ENDPOINT` |
220
+ | `groupId` | `LTS_GROUP_ID` |
221
+ | `streamId` | `LTS_STREAM_ID` |
222
+
223
+ 环境变量优先级高于配置文件。
224
+
225
+ ## 支持的区域
226
+
227
+ | 区域 ID | 区域名称 | Endpoint |
228
+ |---|---|---|
229
+ | `cn-north-1` | 华北-北京一 | `lts.cn-north-1.myhuaweicloud.com` |
230
+ | `cn-north-4` | 华北-北京四 | `lts.cn-north-4.myhuaweicloud.com` |
231
+ | `cn-east-2` | 华东-上海二 | `lts.cn-east-2.myhuaweicloud.com` |
232
+ | `cn-east-3` | 华东-上海三 | `lts.cn-east-3.myhuaweicloud.com` |
233
+ | `cn-south-1` | 华南-广州 | `lts.cn-south-1.myhuaweicloud.com` |
234
+ | `cn-south-4` | 华南-深圳 | `lts.cn-south-4.myhuaweicloud.com` |
235
+ | `cn-southwest-2` | 西南-贵阳一 | `lts.cn-southwest-2.myhuaweicloud.com` |
236
+ | `ap-southeast-1` | 亚太-新加坡 | `lts.ap-southeast-1.myhuaweicloud.com` |
237
+ | `ap-southeast-2` | 亚太-曼谷 | `lts.ap-southeast-2.myhuaweicloud.com` |
238
+ | `ap-southeast-3` | 亚太-雅加达 | `lts.ap-southeast-3.myhuaweicloud.com` |
239
+ | `af-south-1` | 非洲-约翰内斯堡 | `lts.af-south-1.myhuaweicloud.com` |
240
+
241
+ > 完整列表请参考 [华为云 LTS 终端节点](https://support.huaweicloud.com/api-lts/lts_api_0011.html)。
242
+
243
+ ## 开发指南
244
+
245
+ ```bash
246
+ git clone https://github.com/jcxy/huawei-lts-cli.git
247
+ cd huawei-lts-cli
248
+ npm install
249
+ npm run build
250
+
251
+ # 开发模式运行(无需编译)
252
+ npm run dev -- query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
253
+
254
+ # 本地测试
255
+ npm link
256
+ lts-cli query --st 2024-01-01T00:00:00Z --et 2024-01-02T00:00:00Z
257
+ ```
258
+
259
+ ## License
260
+
261
+ [MIT](LICENSE)
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadCheckedConfig = loadCheckedConfig;
4
+ exports.resolveGroupStream = resolveGroupStream;
5
+ exports.resolveTimeParams = resolveTimeParams;
6
+ exports.buildQueryExpression = buildQueryExpression;
7
+ exports.resolveFormat = resolveFormat;
8
+ exports.handleCommandError = handleCommandError;
9
+ const config_1 = require("../../config");
10
+ /** 加载配置并校验凭证,缺失时打印引导并退出 */
11
+ function loadCheckedConfig() {
12
+ const config = (0, config_1.loadConfig)();
13
+ if (!config.ak || !config.sk || !config.projectId) {
14
+ console.error('Error: Missing required credentials. Please configure them first:');
15
+ console.error('');
16
+ console.error(' Quick setup (recommended):');
17
+ console.error(' lts-cli init');
18
+ console.error('');
19
+ console.error(' Or set individually:');
20
+ console.error(' lts-cli config --set ak=<your-access-key>');
21
+ console.error(' lts-cli config --set sk=<your-secret-key>');
22
+ console.error(' lts-cli config --set projectId=<your-project-id>');
23
+ process.exit(1);
24
+ }
25
+ return config;
26
+ }
27
+ /** groupId/streamId:CLI 参数优先,其次配置默认值,都没有则报错退出 */
28
+ function resolveGroupStream(options, config) {
29
+ const groupId = options.groupId || config.groupId;
30
+ const streamId = options.streamId || config.streamId;
31
+ if (!groupId || !streamId) {
32
+ console.error('Error: groupId and streamId are required. Provide them via:');
33
+ console.error(' lts-cli config --set groupId=<your-group-id>');
34
+ console.error(' lts-cli config --set streamId=<your-stream-id>');
35
+ console.error(' or use -g <groupId> -s <streamId> flags');
36
+ console.error(' Tip: run "lts-cli groups" / "lts-cli streams" to discover IDs');
37
+ process.exit(1);
38
+ }
39
+ return { groupId, streamId };
40
+ }
41
+ /** 解析时间选项:--last 与 --st/--et 互斥,至少提供一组 */
42
+ function resolveTimeParams(options, defaultLast) {
43
+ const startTime = options.startTime || options.st;
44
+ const endTime = options.endTime || options.et;
45
+ const last = options.last || (!startTime && !endTime ? defaultLast : undefined);
46
+ if (last && (startTime || endTime)) {
47
+ console.error('Error: --last is mutually exclusive with --start-time/--end-time. Provide only one style.');
48
+ process.exit(1);
49
+ }
50
+ if (!last && (!startTime || !endTime)) {
51
+ console.error('Error: time range required. Use --last (e.g. --last 2h) or both --start-time and --end-time.');
52
+ process.exit(1);
53
+ }
54
+ return last ? { last } : { startTime, endTime };
55
+ }
56
+ /** 将 -q 表达式与便捷筛选 flag 合并为一个查询表达式(AND 连接)
57
+ * 字段值统一加双引号:含连字符等分词符的值(如 UUID)不加引号会匹配不到 */
58
+ function buildQueryExpression(options) {
59
+ const parts = [];
60
+ if (options.query) {
61
+ parts.push(options.query);
62
+ }
63
+ if (options.app) {
64
+ parts.push(`appName:"${options.app}"`);
65
+ }
66
+ if (options.content) {
67
+ parts.push(`content:"${options.content}"`);
68
+ }
69
+ if (options.requestId) {
70
+ parts.push(`REQUEST_ID:"${options.requestId}"`);
71
+ }
72
+ return parts.length > 0 ? parts.join(' AND ') : undefined;
73
+ }
74
+ /** 解析输出格式,非法值回退 pretty */
75
+ function resolveFormat(value) {
76
+ return ['json', 'table', 'pretty'].includes(value) ? value : 'pretty';
77
+ }
78
+ /** 统一错误处理:常见错误给出友好提示 */
79
+ function handleCommandError(error) {
80
+ const msg = error.message || String(error);
81
+ if (msg.includes('Invalid URL')) {
82
+ console.error('Error: Invalid endpoint URL. Make sure it starts with https://');
83
+ console.error(' Example: https://lts.cn-south-1.myhuaweicloud.com');
84
+ }
85
+ else if (msg.includes('Authentication failed') || msg.includes('401') || msg.includes('403')) {
86
+ console.error('Error: Authentication failed. Please check your AK/SK credentials:');
87
+ console.error(' lts-cli config --list');
88
+ }
89
+ else if (msg.includes('ENOTFOUND') || msg.includes('ECONNREFUSED')) {
90
+ console.error('Error: Cannot reach the LTS service. Please check your endpoint and network connection.');
91
+ }
92
+ else if (msg.includes('Request failed after retries')) {
93
+ console.error('Error: The service is temporarily unavailable. Please try again later.');
94
+ }
95
+ else {
96
+ console.error('Error:', msg);
97
+ }
98
+ process.exit(1);
99
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createContextCommand = createContextCommand;
4
+ const commander_1 = require("commander");
5
+ const client_1 = require("../../lts/client");
6
+ const output_1 = require("../../output");
7
+ const common_1 = require("./common");
8
+ function createContextCommand() {
9
+ const cmd = new commander_1.Command('context');
10
+ cmd.description('View logs before/after a specific log entry (like "View Context" in the console)')
11
+ .option('-g, --group-id <groupId>', 'Log group ID (can also be set via config)')
12
+ .option('-s, --stream-id <streamId>', 'Log stream ID (can also be set via config)')
13
+ .requiredOption('--line-num <lineNum>', 'line_num of the anchor log entry')
14
+ .requiredOption('--time <time>', 'Timestamp (ms) of the anchor log entry')
15
+ .option('--before <count>', 'Number of logs before the anchor', (v) => parseInt(v, 10), 20)
16
+ .option('--after <count>', 'Number of logs after the anchor', (v) => parseInt(v, 10), 20)
17
+ .option('-f, --format <format>', 'Output format: json, table, pretty', 'pretty')
18
+ .action(async (options) => {
19
+ const config = (0, common_1.loadCheckedConfig)();
20
+ const { groupId, streamId } = (0, common_1.resolveGroupStream)(options, config);
21
+ const format = (0, common_1.resolveFormat)(options.format);
22
+ const client = new client_1.LTSClient(config);
23
+ const params = {
24
+ groupId,
25
+ streamId,
26
+ lineNum: options.lineNum,
27
+ time: options.time,
28
+ before: options.before,
29
+ after: options.after,
30
+ };
31
+ try {
32
+ const result = await client.queryContext(params);
33
+ console.log((0, output_1.formatOutput)(result, format));
34
+ }
35
+ catch (error) {
36
+ (0, common_1.handleCommandError)(error);
37
+ }
38
+ });
39
+ return cmd;
40
+ }
@@ -67,7 +67,13 @@ const ENDPOINT_MAP = {
67
67
  function createInitCommand() {
68
68
  const cmd = new commander_1.Command('init');
69
69
  cmd.description('Interactive setup wizard — configure credentials step by step')
70
- .action(async () => {
70
+ .option('--from-url <url>', 'Import region/groupId/streamId from an LTS console URL (non-interactive)')
71
+ .action(async (options) => {
72
+ // 从控制台 URL 导入:解析 region、groupId、topicId(即 streamId),无需交互
73
+ if (options.fromUrl) {
74
+ importFromConsoleUrl(options.fromUrl);
75
+ return;
76
+ }
71
77
  const rl = readline.createInterface({
72
78
  input: process.stdin,
73
79
  output: process.stdout,
@@ -154,3 +160,52 @@ function createInitCommand() {
154
160
  });
155
161
  return cmd;
156
162
  }
163
+ /** 从华为云 LTS 控制台 URL 中解析 region / groupId / streamId 并写入配置 */
164
+ function importFromConsoleUrl(raw) {
165
+ let url;
166
+ try {
167
+ url = new URL(raw);
168
+ }
169
+ catch {
170
+ console.error('Error: Invalid URL. Please paste the full console URL, e.g.:');
171
+ console.error(' https://console.huaweicloud.com/lts/?region=cn-south-1#/cts/logEventsLeftMenu/events?groupId=...&topicId=...');
172
+ process.exit(1);
173
+ }
174
+ const region = url.searchParams.get('region') || undefined;
175
+ // groupId / topicId 位于 hash 段的查询参数中:#/cts/logEventsLeftMenu/events?groupId=...&topicId=...
176
+ const hash = url.hash || '';
177
+ const qIndex = hash.indexOf('?');
178
+ const hashParams = new URLSearchParams(qIndex >= 0 ? hash.slice(qIndex + 1) : '');
179
+ const groupId = hashParams.get('groupId') || url.searchParams.get('groupId') || undefined;
180
+ const streamId = hashParams.get('topicId') || hashParams.get('streamId') || url.searchParams.get('topicId') || undefined;
181
+ if (!region && !groupId && !streamId) {
182
+ console.error('Error: No region/groupId/topicId found in the URL. Make sure it is an LTS log search page URL.');
183
+ process.exit(1);
184
+ }
185
+ console.log('');
186
+ console.log('Importing from console URL:');
187
+ if (region) {
188
+ (0, config_1.setConfig)('region', region);
189
+ console.log(` region = ${region}`);
190
+ const autoEndpoint = ENDPOINT_MAP[region];
191
+ if (autoEndpoint) {
192
+ (0, config_1.setConfig)('endpoint', `https://${autoEndpoint}`);
193
+ console.log(` endpoint = https://${autoEndpoint} (derived from region)`);
194
+ }
195
+ }
196
+ if (groupId) {
197
+ (0, config_1.setConfig)('groupId', groupId);
198
+ console.log(` groupId = ${groupId}`);
199
+ }
200
+ if (streamId) {
201
+ (0, config_1.setConfig)('streamId', streamId);
202
+ console.log(` streamId = ${streamId}`);
203
+ }
204
+ console.log('');
205
+ console.log('✅ Configuration saved!');
206
+ console.log('');
207
+ console.log('Next steps:');
208
+ console.log(' 1. Configure credentials if not done yet: lts-cli init');
209
+ console.log(' 2. Query logs: lts-cli query --last 2h --content "error"');
210
+ console.log('');
211
+ }