@guandata/guanbi-mcp-server 0.1.10

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 ADDED
@@ -0,0 +1,20 @@
1
+ BI_BASE_URL=https://your-bi-host.example.com
2
+
3
+ # Optional tenant path when BI is mounted below a prefix, for example /guanbi.
4
+ BI_PUBLIC_PATH=
5
+
6
+ # Prefer token for local MCP usage. If absent, password login is used.
7
+ BI_UID_TOKEN=
8
+
9
+ BI_LOGIN_DOMAIN=guanbi
10
+ BI_LOGIN_ID=
11
+ BI_LOGIN_PASSWORD=
12
+
13
+ BI_REQUEST_TIMEOUT_MS=120000
14
+ BI_MAX_ROWS=1000
15
+
16
+ # Optional manual override used by capability checks, for example 8.2.1.
17
+ BI_DATA_VERSION=
18
+
19
+ # Optional anonymous aggregate usage stats opt-out. Use 0/false/off/no to disable.
20
+ GUANBI_MCP_USAGE_STATS=
package/README.md ADDED
@@ -0,0 +1,293 @@
1
+ # @guandata/guanbi-mcp-server
2
+
3
+ 观远 BI MCP Server,用于把 BI 的检索、元信息读取、能力探测和 SQL 查询暴露给支持 MCP 的 Agent。
4
+
5
+ ## 快速开始
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm build
10
+ pnpm start
11
+ ```
12
+
13
+ 本地开发时可以直接运行源码:
14
+
15
+ ```bash
16
+ pnpm dev
17
+ ```
18
+
19
+ ## MCP 配置
20
+
21
+ 使用构建后的本地入口:
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "guanbi": {
27
+ "command": "node",
28
+ "args": ["./dist/index.js"],
29
+ "env": {
30
+ "BI_BASE_URL": "https://your-bi-host.example.com",
31
+ "BI_UID_TOKEN": "your-token"
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ 使用内网 npm package:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "guanbi": {
44
+ "command": "npx",
45
+ "args": [
46
+ "-y",
47
+ "--registry=https://registry.npmmirror.com",
48
+ "--@guandata:registry=https://app.mayidata.com/nexus/repository/guandata-web/",
49
+ "@guandata/guanbi-mcp-server@latest"
50
+ ],
51
+ "env": {
52
+ "BI_BASE_URL": "https://your-bi-host.example.com",
53
+ "BI_UID_TOKEN": "your-token"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ 如果运行环境已经通过 `.npmrc` 配置了 `@guandata` scope 的内网 registry,可以简化为:
61
+
62
+ ```json
63
+ {
64
+ "mcpServers": {
65
+ "guanbi": {
66
+ "command": "npx",
67
+ "args": ["-y", "@guandata/guanbi-mcp-server@latest"],
68
+ "env": {
69
+ "BI_BASE_URL": "https://your-bi-host.example.com",
70
+ "BI_UID_TOKEN": "your-token"
71
+ }
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## 配置项
78
+
79
+ 可以通过 MCP 客户端的 `env` 注入,也可以复制 `.env.example` 为 `.env` 后本地运行。
80
+
81
+ | 变量 | 必填 | 默认值 | 说明 |
82
+ | --- | --- | --- | --- |
83
+ | `BI_BASE_URL` | 是 | - | BI 站点根地址。 |
84
+ | `BI_PUBLIC_PATH` | 否 | 空字符串 | BI 部署在子路径时填写,例如 `/guanbi`。 |
85
+ | `BI_UID_TOKEN` | 否 | - | 登录态 token;配置后优先使用。 |
86
+ | `BI_LOGIN_DOMAIN` | 否 | `guanbi` | 账号密码登录使用的 domain。 |
87
+ | `BI_LOGIN_ID` | 否 | - | 登录账号。 |
88
+ | `BI_LOGIN_PASSWORD` | 否 | - | 登录密码。 |
89
+ | `BI_REQUEST_TIMEOUT_MS` | 否 | `120000` | BI 请求超时时间。 |
90
+ | `BI_MAX_ROWS` | 否 | `1000` | `execute_sql_query` 返回行数上限,会作为 `limit` 参数传给 BI 接口;实际限制以 BI 接口能力为准。 |
91
+ | `BI_DATA_VERSION` | 否 | - | 手工覆盖能力判断使用的 BI 版本,例如 `8.2.1`。 |
92
+ | `GUANBI_MCP_USAGE_STATS` | 否 | 开启 | 匿名聚合使用统计开关;设置为 `0`、`false`、`off` 或 `no` 可关闭。 |
93
+ | `MCP_TRANSPORT` | 否 | `stdio` | 传 `streamable-http` 启用企业 HTTP 模式。 |
94
+ | `MCP_HTTP_HOST` | 否 | `127.0.0.1` | HTTP 监听地址。 |
95
+ | `MCP_HTTP_PORT` | 否 | `3000` | HTTP 监听端口。 |
96
+ | `MCP_ENTRYPOINT_TOKEN` | HTTP 模式建议必填 | - | MCP 入口 bearer token。 |
97
+ | `MCP_TRUSTED_GATEWAY` | 否 | - | 设为 `true` 时跳过 MCP 入口 token 校验,仅用于可信网关已完成鉴权的部署。 |
98
+
99
+ 鉴权需要满足以下任一条件:
100
+
101
+ - 配置 `BI_UID_TOKEN`。
102
+ - 同时配置 `BI_LOGIN_DOMAIN`、`BI_LOGIN_ID`、`BI_LOGIN_PASSWORD`。
103
+
104
+ `stdio` 模式使用上述 BI 鉴权配置作为本地固定调用者。`streamable-http` 模式不使用账号密码登录,也不使用进程级 `BI_UID_TOKEN` 代查;访问 BI 或当前调用者能力的 `tools/call` 必须携带当前真实用户的 BI token。
105
+
106
+ ## Streamable HTTP
107
+
108
+ 最小启动配置:
109
+
110
+ ```bash
111
+ MCP_TRANSPORT=streamable-http \
112
+ MCP_HTTP_HOST=127.0.0.1 \
113
+ MCP_HTTP_PORT=3000 \
114
+ MCP_ENTRYPOINT_TOKEN=change-me \
115
+ BI_BASE_URL=https://your-bi-host.example.com \
116
+ node dist/index.js
117
+ ```
118
+
119
+ HTTP endpoint:
120
+
121
+ - `POST /mcp`:MCP Streamable HTTP endpoint。
122
+ - `GET /healthz`:仅报告服务存活和绑定 BI 站点配置,不验证用户 token。
123
+
124
+ 请求 header contract:
125
+
126
+ | Header | 说明 |
127
+ | --- | --- |
128
+ | `Authorization: Bearer <mcp_service_token>` | MCP 入口凭证;可信网关模式可省略。 |
129
+ | `X-GuanBI-Uid-Token: <uIdToken>` | 当前真实用户的 GuanBI token;用于 BI 数据权限。 |
130
+ | `X-Tenant-Id` / `X-End-User-Id` / `X-Trace-Id` | 审计身份,只用于日志,不作为授权。 |
131
+
132
+ 安全边界:
133
+
134
+ - 一个 MCP 实例绑定一个 `BI_BASE_URL` / `BI_PUBLIC_PATH`;请求 header 不能改 BI base URL。
135
+ - HTTP 模式不支持账号密码登录、不保存跨请求刷新 token、不接受 end user id 代替 BI token。
136
+ - `tools/list` 返回服务级工具列表;具体 BI 版本、权限和 ChatBI 可用性在 `tools/call` 时用当前用户 token 判断。
137
+ - `chatbi_insight_start` 和 `chatbi_insight_poll` 都使用当前请求 token;MCP 不保存 `message_id -> token/user` 授权映射。
138
+
139
+ Smoke test 可使用支持 Streamable HTTP 的 MCP client,或直接用 curl 检查入口鉴权和健康检查:
140
+
141
+ ```bash
142
+ curl -s http://127.0.0.1:3000/healthz
143
+ curl -i http://127.0.0.1:3000/mcp
144
+ curl -i http://127.0.0.1:3000/mcp \
145
+ -H 'Authorization: Bearer change-me' \
146
+ -H 'X-GuanBI-Uid-Token: <uIdToken>' \
147
+ -H 'Content-Type: application/json' \
148
+ -H 'Accept: application/json, text/event-stream' \
149
+ --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"smoke","version":"0.0.0"}}}'
150
+ ```
151
+
152
+ 第二条在未携带入口凭证时应返回 `401`;第三条应返回 MCP initialize 响应并带 `Mcp-Session-Id`。
153
+
154
+ ## 使用统计与隐私
155
+
156
+ MCP server 默认开启匿名、聚合的 tool call 使用统计,用于了解 tools 使用覆盖、版本分布和大致失败比例。敏感环境可以通过环境变量关闭:
157
+
158
+ ```bash
159
+ GUANBI_MCP_USAGE_STATS=0
160
+ ```
161
+
162
+ 单条统计事件只包含以下字段:
163
+
164
+ - `service_domain`:从 `BI_BASE_URL` 解析出的 hostname,不包含 path、query、token 或完整 URL。
165
+ - `app_version`:当前 MCP server package 版本。
166
+ - `tool`:被调用的 MCP tool 名称。
167
+ - `success`:tool 调用是否成功。
168
+ - `duration_ms_bucket`:粗粒度耗时分桶。
169
+ - `error_type`:粗粒度错误类型。
170
+ - `session_id`:固定为 `1`,仅作为 GA realtime/engagement 协议占位,不代表真实会话。
171
+ - `engagement_time_msec`:固定为 `1`,仅作为 GA realtime/engagement 协议占位,不代表真实停留或耗时。
172
+
173
+ 统计不会采集 SQL、自然语言问题、tool 参数、token、cookie、完整 URL、资源 ID、返回内容、用户 ID、账号、客户端 ID 或长期匿名 ID。MCP server 不生成、不读取、不持久化客户端身份;`session_id`、`engagement_time_msec` 和 GA wire-level `client_id` 都是固定协议占位值。该功能只看聚合事件数,不使用 GA 用户数、客户端数、会话数等身份或会话类指标作为验收或分析依据。
174
+
175
+ 新增 tool 时必须通过 `src/tools/index.ts` 里的统一 `registerTool` helper 注册,保持 `withUsageTelemetry` wrapper 覆盖所有 tool。相关测试会持续验证已注册 handler 默认经过 telemetry wrapper,并验证事件 payload 不包含业务输入或返回内容。
176
+
177
+ ## Tools
178
+
179
+ | Tool | 说明 |
180
+ | --- | --- |
181
+ | `get_bi_capabilities` | 获取 BI 版本和当前 MCP 可用能力。 |
182
+ | `global_search` | 搜索卡片、仪表板、数据集、ETL。 |
183
+ | `execute_sql_query` | 调用 `/api/data-source/execute-sql-query` 执行简单单表查询 SQL;接口仅支持查询语句,适合少量结果预览或轻量分析,不适合拉取全量数据。返回行数受 `BI_MAX_ROWS` 控制,默认 `1000`。按 BI 版本能力动态启用。 |
184
+ | `get_dataset_detail` | 获取数据集详情。 |
185
+ | `get_card_info` | 获取卡片元信息。 |
186
+ | `get_page_info` | 获取页面/仪表板元信息。 |
187
+ | `search_metrics` | 搜索指标平台指标,返回后续可用的 `metric_id`、名称、主题、目录、类型、状态和业务口径摘要。 |
188
+ | `list_metric_catalog` | 浏览指标主题和目录;完整树接口可用时也会返回指标节点,适合不知道关键词时发现可用指标。 |
189
+ | `get_metric_detail` | 获取指标业务口径、计算口径、数据集、适用维度、时间维、业务属性、负责人、权限和血缘/引用摘要。 |
190
+ | `query_metric_data` | 查询指标数据,默认读取指标关联卡片预览数据;显式维度查询只修改临时 session,显式高级计算走指标数据接口;不会 save 卡片或调用持久化写入路径。 |
191
+ | `search_metric_trees` | 搜索指标树资源,返回可用于归因分析的 `metric_tree_id`。 |
192
+ | `get_metric_tree_detail` | 获取指标树详情、根指标、时间对比配置、维度拆解配置、指标关系树和权限摘要。 |
193
+ | `query_metric_tree_attribution` | 基于指标树执行指标拆解、单维拆解或全维扫描归因分析。 |
194
+ | `chatbi_list_themes` | 列出当前用户可访问的 ChatBI 主题,可用 `is_insight` 筛选洞察主题。 |
195
+ | `chatbi_query` | 执行 ChatBI L1 同步问数,支持 `theme_id` 或 `theme_name`;`session_id` 只能用于问数续问。 |
196
+ | `chatbi_insight_start` | 发起 ChatBI L2 洞察分析,请求受理后立即返回 `theme_id`、`message_id`、`session_id`,不等待最终报告;同一输入 60 秒内会复用已发起任务。 |
197
+ | `chatbi_insight_poll` | 使用 `chatbi_insight_start` 返回的 `theme_id` 和 `message_id` 查询洞察状态和最终报告;同一 `message_id` 10 秒内重复查询会返回本地缓存。 |
198
+
199
+ ## 指标平台 tools
200
+
201
+ 推荐的指标查询调用链:
202
+
203
+ 1. 用 `search_metrics` 按关键词搜索拿到 `metric_id`;不知道关键词时,可先用 `list_metric_catalog` 按主题/目录浏览,完整树接口可用时也会直接返回指标节点。
204
+ 2. 用 `get_metric_detail` 查看业务口径、计算口径、适用维度和时间维,确认该指标是否适合当前问题。
205
+ 3. 用 `query_metric_data` 查询数据。维度名、筛选字段和排序字段建议优先使用 `get_metric_detail` 返回的字段名称或字段 ID。
206
+
207
+ 推荐的指标树归因调用链:
208
+
209
+ 1. 用 `search_metric_trees` 搜索指标树,拿到 `metric_tree_id`。
210
+ 2. 用 `get_metric_tree_detail` 查看根指标、时间对比、可拆解维度和指标关系树。
211
+ 3. 用 `query_metric_tree_attribution` 执行 `target=metric` 指标拆解、`target=dimension` 单维拆解,或 `target=scan` 全维扫描。
212
+
213
+ `query_metric_data` 会先读取指标详情用于字段和维度解析。普通查询参考 `guandata-web` 指标平台列表/详情页逻辑,使用指标详情里的
214
+ `metricChartCdId`/`metricValueCdId` 创建预览 session,并调用 `/api/card/{cdId}/edit/{sessionId}/data` 读取指标卡预览数据。显式传入维度且未使用高级计算时,
215
+ tool 会在临时 session 内调用 `/api/oriput/card/{cdId}/edit/{sessionId}/modify` 更新 `zoneData.row` 后取数;这不会调用 `save`、`update`、`delete`、`publish`
216
+ 等持久化路径。显式传入高级计算时使用 `/api/metric-platform/metric-data/v2` 指标数据查询接口。若某些维度或高级计算无法表达,tool 会返回
217
+ `status: "unsupported"` 和结构化 `diagnostic`,说明能力边界和相关参数。
218
+
219
+ 指标树详情和归因请求会自动附加指标树页面所需的 `Referer`、`x-dom-id`、`user-id` 上下文 header。账号密码登录配置会直接用于这些 header;仅配置
220
+ `BI_UID_TOKEN` 时,会尝试读取 `/api/user/profile` 补齐缺失的用户上下文,失败时使用 `BI_LOGIN_DOMAIN` 和默认用户上下文。
221
+
222
+ `get_bi_capabilities` 的 `metricPlatform` 字段会列出已注册指标 tools,并标记 `readOnly: true`。当前首版不做指标平台版本门槛探测;若真实环境 API 不存在或权限不足,单个 tool 的错误结果会返回
223
+ `operation`、`path`、`status` 和 `message` 诊断字段。
224
+
225
+ ## ChatBI 地址推导与诊断
226
+
227
+ ChatBI tools 不需要额外的 ChatBI 专用环境变量。Server 会从 `BI_BASE_URL + BI_PUBLIC_PATH`
228
+ 自动尝试以下 Public API base URL:
229
+
230
+ - `/api/chat/public-api`
231
+ - 带部署子路径的 `/api/chat/public-api`
232
+ - 带部署子路径的 `/public-api`
233
+ - `/public-api`
234
+
235
+ ChatBI 请求默认使用 `Cookie: uIdToken=<token>` 鉴权;`chatbi_query` 和 `chatbi_insight_start` 的发送请求会带
236
+ `Device-ID: guanbi_mcp_chatbi`,洞察轮询请求不带 `Device-ID`。如果部署环境需要额外用户上下文 header,
237
+ `get_bi_capabilities` 和 ChatBI tool 错误结果会返回可诊断字段,包括 `operation`、`base_url`、`path`、
238
+ `http_status`、`chatbi_code`、`chatbi_message`、`tried_base_urls` 和 `token_refreshed`。
239
+
240
+ ChatBI tools 均注册 `outputSchema` 并在成功结果里返回 `structuredContent`。L1 `chatbi_query` 直接透出
241
+ `answer`、`sql`、`query_result` 等结构化字段,由调用方自行组织最终回复,不再返回旧版 `markdown` 或
242
+ `final_result` 字段。L2 `chatbi_insight_poll` 的最终展示内容放在
243
+ `final_result: { format: "markdown", content }`,`answer` 保留后端原始答案,不作为展示优先字段。
244
+ `chatbi_insight_start` 只返回 `message_id`、`session_id`、`status`、`deduped`、`retry_after_ms` 等结构化状态字段,
245
+ 不包含最终结果。`chatbi_list_themes` 返回结构化主题列表,不再返回旧版 `markdown` 字段。L2 展示内容会将可解析的
246
+ `GuanViz.json` 代码块降级为 markdown 表格。洞察通常耗时 2-3 分钟,5 分钟仍未完成可视为超时。
247
+ 长洞察任务请使用 `chatbi_insight_start` 发起任务,再按不小于 10 秒的间隔调用 `chatbi_insight_poll`
248
+ 查询结果,避免调用方对单次 MCP `tools/call` 的等待超时,也避免高频轮询压到后台。
249
+ 首版不提供消息回读、主题管理、收藏/反馈、下载、流式响应或前端 iframe/chatPlugin 嵌入能力。
250
+
251
+ ChatBI 会话按模式绑定:同一个 `session_id` 只能在问数或洞察其中一种模式内续问,不能在同一个 session
252
+ 里混用 `chatbi_query` 和 `chatbi_insight_start`。如果需要从问数切到洞察,或从洞察切到问数,请不要复用
253
+ 旧 `session_id`,让 ChatBI 创建新的会话。
254
+
255
+ ## 开发校验
256
+
257
+ ```bash
258
+ pnpm test
259
+ pnpm typecheck
260
+ pnpm build
261
+ ```
262
+
263
+ ## 发版 MR
264
+
265
+ 功能改动合入发版分支后,可以用脚本生成版本提交并创建 MR:
266
+
267
+ ```bash
268
+ pnpm release:mr -- patch --notes "- MCP 新增 ChatBI 支持,可列出主题、执行 L1 自然语言问数,并发起 L2 洞察分析。"
269
+ ```
270
+
271
+ 脚本会更新 `package.json` 版本号、追加 `CHANGELOG.md`、提交 `chore: release vX.Y.Z`、推送当前分支,
272
+ 并通过 `glab mr create` 创建到 `main` 的 MR。`--notes` 应按用户可感知功能编写,不按 MR 或提交逐条罗列。
273
+ 为了避免误提交未确认改动,脚本要求运行前工作区干净。
274
+
275
+ 升级 MR 合并后,在最新 `main` 上执行发布和打 tag:
276
+
277
+ ```bash
278
+ git switch main
279
+ git pull --ff-only origin main
280
+ pnpm release:publish
281
+ ```
282
+
283
+ 发布脚本会要求当前分支为 `main`、工作区干净且本地 `HEAD` 等于 `origin/main`,随后运行
284
+ `pnpm test`、`pnpm typecheck`、`pnpm build`、`pnpm publish --no-git-checks`,并创建和推送
285
+ `vX.Y.Z` tag。可以先用 `pnpm release:publish -- --dry-run` 演练发布流程,演练不会创建或推送 tag。
286
+
287
+ ## 排障
288
+
289
+ - 启动失败且提示缺少鉴权配置:检查是否配置了 `BI_UID_TOKEN`,或完整配置了账号密码登录变量。
290
+ - `execute_sql_query` 不在 tool 列表中:当前 BI 版本可能低于 `8.2.1`,或版本探测失败;可用 `BI_DATA_VERSION` 手工覆盖。
291
+ - `execute_sql_query` 返回 `404`:通常是对应域名没有开启高级 SQL 查询功能,需要在管理后台的高级设置中开启。
292
+ - ChatBI tool 返回 `No static resource public-api/...`:通常表示当前候选 base URL 没有挂载 ChatBI Public API。
293
+ 查看返回的 `tried_base_urls`,确认 `BI_BASE_URL` 和 `BI_PUBLIC_PATH` 是否指向承载 ChatBI 的部署入口。
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import"dotenv/config";import{z as w}from"zod";var Tn=w.object({BI_BASE_URL:w.string().url().optional(),BI_PUBLIC_PATH:w.string().optional().default(""),BI_UID_TOKEN:w.string().optional(),BI_LOGIN_DOMAIN:w.string().optional().default("guanbi"),BI_LOGIN_ID:w.string().optional(),BI_LOGIN_PASSWORD:w.string().optional(),BI_REQUEST_TIMEOUT_MS:w.coerce.number().int().positive().default(12e4),BI_MAX_ROWS:w.coerce.number().int().positive().default(1e3),BI_DATA_VERSION:w.string().optional(),GUANBI_MCP_USAGE_STATS:w.string().optional(),MCP_TRANSPORT:w.enum(["stdio","streamable-http"]).optional().default("stdio"),MCP_HTTP_HOST:w.string().optional().default("127.0.0.1"),MCP_HTTP_PORT:w.coerce.number().int().nonnegative().optional().default(3e3),MCP_ENTRYPOINT_TOKEN:w.string().optional(),MCP_TRUSTED_GATEWAY:w.string().optional()});function qe(t=process.env){let e=Tn.parse(t);return{...e,BI_BASE_URL:e.BI_BASE_URL?.replace(/\/+$/,""),BI_PUBLIC_PATH:Cn(e.BI_PUBLIC_PATH),BI_UID_TOKEN:e.BI_UID_TOKEN?.trim()||void 0,BI_LOGIN_DOMAIN:e.BI_LOGIN_DOMAIN?.trim()||"guanbi",BI_LOGIN_ID:e.BI_LOGIN_ID?.trim()||void 0,BI_LOGIN_PASSWORD:e.BI_LOGIN_PASSWORD?.trim()||void 0,BI_DATA_VERSION:e.BI_DATA_VERSION?.trim()||void 0,GUANBI_MCP_USAGE_STATS:e.GUANBI_MCP_USAGE_STATS?.trim()||void 0,MCP_ENTRYPOINT_TOKEN:e.MCP_ENTRYPOINT_TOKEN?.trim()||void 0,MCP_TRUSTED_GATEWAY:e.MCP_TRUSTED_GATEWAY?.trim()||void 0}}function Cn(t){let e=t?.trim().replace(/^\/+|\/+$/g,"")??"";return e?`/${e}`:""}import{createRequire as vi}from"module";import{createHash as Ai,randomUUID as Ei}from"crypto";import{createServer as Oi}from"http";import{McpServer as xi}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as Mi}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Pi}from"@modelcontextprotocol/sdk/server/streamableHttp.js";var F=class{record(e){console.error(JSON.stringify({audit:Bn({...e})}))}},Q=class{record(){}};function de(t,e,n,r,i){return{transport:e.transport,tool:t,tenantId:e.audit.tenantId,endUserId:e.audit.endUserId,traceId:e.audit.traceId,status:r,durationMs:Math.max(0,Date.now()-n),failureType:r==="error"?wn(i):void 0}}function wn(t){return t instanceof Error?t.name||"Error":typeof t}function Bn(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}async function W(t){if(!t.BI_LOGIN_ID||!t.BI_LOGIN_PASSWORD||!t.BI_LOGIN_DOMAIN)throw new Error("\u5BC6\u7801\u767B\u5F55\u9700\u8981\u914D\u7F6E BI_LOGIN_DOMAIN\u3001BI_LOGIN_ID\u3001BI_LOGIN_PASSWORD\u3002");let e=await fetch(Sn(t,"/api/user/sign-in"),{method:"POST",headers:{"Content-Type":"application/json","raw-backend-response":"TRUE"},body:JSON.stringify({domain:t.BI_LOGIN_DOMAIN,loginId:t.BI_LOGIN_ID,password:Buffer.from(t.BI_LOGIN_PASSWORD,"utf8").toString("base64")}),signal:AbortSignal.timeout(t.BI_REQUEST_TIMEOUT_MS)}),n=await e.text();if(!e.ok)throw new Error(`BI \u767B\u5F55\u5931\u8D25\uFF1AHTTP ${e.status} ${xn(n)}`);let r=kn(e,n);if(!r)throw new Error("BI \u767B\u5F55\u54CD\u5E94\u4E2D\u672A\u627E\u5230 X-Auth-Token/Authorization/uIdToken/authToken/token\u3002");return{token:r}}function Sn(t,e){return`${t.BI_BASE_URL}${t.BI_PUBLIC_PATH}${e}`}function kn(t,e){let n=Rn(t.headers);if(n)return n;let r=vn(e);return r||An(t.headers)}function Rn(t){let e=t.get("x-auth-token")?.trim();if(e)return e;let n=t.get("authorization")?.trim();return n&&(n.match(/^Bearer\s+(.+)$/i)?.[1]??n).trim()||void 0}function vn(t){try{let e=JSON.parse(t);return Ge(e)??Ge(On(e.response))}catch{return}}function An(t){return[...t.getSetCookie?.()??[],...En(t.get("set-cookie"))].map(n=>n.trim().match(/(?:^|;\s*)uIdToken=([^;]+)/)?.[1]).find(Boolean)}function En(t){return t?t.split(/,(?=\s*[^;,]+=)/):[]}function Ge(t){if(t)for(let e of["uIdToken","authToken","token"]){let n=t[e];if(typeof n=="string"&&n)return n}}function On(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}function xn(t,e=500){return t.length>e?`${t.slice(0,e)}...`:t}var Mn="guanbi_mcp_chatbi",B=class extends Error{detail;retryableForBaseUrl;authExpired;constructor(e,n,r={}){super(e),this.name="ChatBIRequestError",this.detail=n,this.retryableForBaseUrl=!!r.retryableForBaseUrl,this.authExpired=!!r.authExpired}},R=class{constructor(e){this.config=e;this.token=e.BI_UID_TOKEN,this.candidates=e.BI_BASE_URL?Pn(`${e.BI_BASE_URL}${e.BI_PUBLIC_PATH}`):[]}config;token;resolvedBaseUrl;candidates;triedBaseUrls=new Set;lastError;loginPromise;refreshPromise;getRegisteredTools(){return["chatbi_list_themes","chatbi_query","chatbi_insight_start","chatbi_insight_poll"]}getResolvedBaseUrl(){return this.resolvedBaseUrl}getTriedBaseUrls(){return[...this.triedBaseUrls]}getLastError(){return this.lastError}async probe(){try{return await this.listThemes(),{available:!0,resolvedBaseUrl:this.resolvedBaseUrl,triedBaseUrls:this.getTriedBaseUrls(),registeredTools:this.getRegisteredTools()}}catch(e){let n=Je(e,"probe");return{available:!1,lastError:n,failureType:Wn(n),triedBaseUrls:this.getTriedBaseUrls(),registeredTools:this.getRegisteredTools()}}}async listThemes(e={}){let n={filter_enable:!0,list_type:"CHAT"};return typeof e.isInsight=="boolean"&&(n.is_insight=e.isInsight),(await this.request("/theme/list-theme",{operation:"listThemes",body:n,retrySafeBaseUrlFallback:!0,validateResponse:zn})).themes}async query(e){let n=await this.resolveThemeId(e.themeId,e.themeName,!1),r={attachments:[],theme_id:n,message:e.message,config:He({fast_mode:e.fastMode??!0,n_samples:e.nSamples})};e.sessionId&&(r.session_id=e.sessionId),e.externalContext&&(r.external_context=e.externalContext);let i=await this.request("/chat/send-message-sync",{operation:"query",body:r,includeDeviceId:!0});try{Yn(i)}catch(s){throw this.operationError("query","/chat/send-message-sync",s)}return i}async insight(e){let n=e.timeoutMs??3e5,r=e.pollIntervalMs??2e3,i=Date.now()+n,s=await this.startInsight({...e,requestTimeoutMs:$e(i)});if(!s.theme_id)throw this.operationError("insight.send","/chat/send-message","ChatBI insight response missing theme_id");if(!s.message_id?.trim())throw this.operationError("insight.send","/chat/send-message","ChatBI insight response missing message_id");for(;;){let o=await this.getAgentAnswer(s.theme_id,s.message_id,$e(i));switch(o.message_id??=s.message_id,o.session_id??=s.session_id,o.status){case"success":return o;case"failure":case"stopped":throw this.operationError("insight.poll","/chat/get-agent-answer",o.detail?.trim()||"Insight request failed")}await er(i,r,n)}}async startInsight(e){let n=await this.resolveThemeId(e.themeId,e.themeName,!0),r={attachments:[],theme_id:n,message:e.message,is_insight:1};e.sessionId&&(r.session_id=e.sessionId),e.externalContext&&(r.external_context=e.externalContext);let i=He({analysis_expert_id:e.analysisExpertId,agent_mode:e.agentMode,analysis_confirmation_enabled:e.analysisConfirmationEnabled});Object.keys(i).length&&(r.config=i);let s=await this.request("/chat/send-message",{operation:"insight.send",body:r,includeDeviceId:!0,requestTimeoutMs:e.requestTimeoutMs});if(!s.message_id?.trim())throw this.operationError("insight.send","/chat/send-message","ChatBI insight response missing message_id");return s.theme_id=n,s}async pollInsight(e){let n=await this.resolveThemeId(e.themeId,e.themeName,!0),r=await this.getAgentAnswer(n,e.messageId,e.requestTimeoutMs);return r.message_id||(r.message_id=e.messageId),r}async getAgentAnswer(e,n,r){let i=new URLSearchParams({theme_id:e,message_id:n});try{return await this.request(`/chat/get-agent-answer?${i.toString()}`,{operation:"insight.poll",retrySafeBaseUrlFallback:!0,requestTimeoutMs:r})}catch(s){if(Hn(s))return{status:"waiting",message_id:n};throw s}}async resolveThemeId(e,n,r){let i=e?.trim();if(i)return i;let s=n?.trim();if(!s)throw new Error("\u7F3A\u5C11\u4E3B\u9898\u9009\u62E9\uFF0C\u8BF7\u4F20 theme_id \u6216 theme_name\u3002");let o=await this.listThemes({isInsight:r?!0:void 0});return Kn(o,s)}async request(e,n){this.assertUsableConfig();let r=this.resolvedBaseUrl?[this.resolvedBaseUrl]:this.candidates,i;for(let s of r){this.triedBaseUrls.add(s);try{let o=await this.requestToBaseUrlWithAuthRetry(s,e,n);return n.validateResponse?.(o,{operation:n.operation,baseUrl:s,path:e}),this.resolvedBaseUrl=s,this.lastError=void 0,o}catch(o){if(i=o,this.lastError=Je(o,n.operation),!Ln(o,n.retrySafeBaseUrlFallback))throw this.withTriedBaseUrls(o)}}throw this.withTriedBaseUrls(i??new Error("\u65E0\u6CD5\u5B9A\u4F4D ChatBI Public API\u3002"))}withTriedBaseUrls(e){return e instanceof B&&(e.detail.tried_base_urls=this.getTriedBaseUrls(),this.lastError=e.detail),e}operationError(e,n,r){let i=r instanceof Error?r.message:String(r);return new B(i,{operation:e,base_url:this.resolvedBaseUrl,path:n,chatbi_message:i,tried_base_urls:this.getTriedBaseUrls(),detail:i})}async requestToBaseUrlWithAuthRetry(e,n,r){let i=await this.ensureToken(),s={operation:r.operation,baseUrl:e,path:n};try{return await this.requestToBaseUrl(e,n,i,r,s)}catch(o){if(!qn(o)||!this.hasPasswordLogin())throw o;let a=await this.refreshToken();return this.requestToBaseUrl(e,n,a,r,{...s,tokenRefreshed:!0})}}async requestToBaseUrl(e,n,r,i,s){let o=i.body===void 0?"GET":"POST",a;try{a=await fetch(`${e}${n}`,{method:o,headers:Dn(r,i),body:i.body===void 0?void 0:JSON.stringify(i.body),signal:AbortSignal.timeout(i.requestTimeoutMs??this.config.BI_REQUEST_TIMEOUT_MS)})}catch(m){throw new B(m instanceof Error?m.message:String(m),{operation:s.operation,base_url:s.baseUrl,path:s.path,token_refreshed:s.tokenRefreshed,detail:m instanceof Error?m.message:String(m)})}let c=await a.text(),d=jn(c,a,s);if(!a.ok||Un(d))throw Nn(d,c,a,s);return this.refreshTokenFromResponse(a,d),d.data}async ensureToken(){return this.token?this.token:(this.loginPromise??=this.signInForToken().finally(()=>{this.loginPromise=void 0}),this.loginPromise)}async refreshToken(){return this.refreshPromise??=this.signInForToken().finally(()=>{this.refreshPromise=void 0}),this.refreshPromise}async signInForToken(){this.token=void 0;let e=await W(this.config);return this.token=e.token,e.token}refreshTokenFromResponse(e,n){let r=Fn(e,n);!r||r===this.token||(this.token=r)}hasPasswordLogin(){return!!(this.config.BI_LOGIN_DOMAIN&&this.config.BI_LOGIN_ID&&this.config.BI_LOGIN_PASSWORD)}assertUsableConfig(){if(!this.config.BI_BASE_URL)throw new Error("\u7F3A\u5C11 BI_BASE_URL\uFF0C\u65E0\u6CD5\u63A8\u5BFC ChatBI Public API \u5730\u5740\u3002")}};function Pn(t){let e=new URL(t),n=[],r=s=>{let o=new URL(e.toString());o.pathname=s,o.search="",o.hash="";let a=o.toString().replace(/\/+$/,"");n.includes(a)||n.push(a)},i=e.pathname.replace(/\/+$/,"");return r("/api/chat/public-api"),i&&r(`${i}/api/chat/public-api`),r(i?`${i}/public-api`:"/public-api"),r("/public-api"),n}function K(t){return t.BI_BASE_URL?t.BI_UID_TOKEN?!0:!!(t.BI_LOGIN_DOMAIN&&t.BI_LOGIN_ID&&t.BI_LOGIN_PASSWORD):!1}function Dn(t,e){let n={Cookie:`uIdToken=${t}`,"User-Agent":"guanbi-mcp-server"};return e.body!==void 0&&(n["Content-Type"]="application/json"),e.includeDeviceId&&(n["Device-ID"]=Mn),n}function jn(t,e,n){if(!t)return{};try{return JSON.parse(t)}catch{throw new B("ChatBI response is not valid JSON",{operation:n.operation,base_url:n.baseUrl,path:n.path,http_status:e.status,token_refreshed:n.tokenRefreshed,detail:Fe(t)},{retryableForBaseUrl:!0})}}function Un(t){let e=Ve(t);return typeof e=="number"&&![0,200].includes(e)||t.result==="fail"||t.success===!1}function Nn(t,e,n,r){let i=Ve(t),s=$n(t),o=s||e||`ChatBI request failed with status ${n.status}`,a={operation:r.operation,base_url:r.baseUrl,path:r.path,http_status:n.status,chatbi_code:i,chatbi_message:s,token_refreshed:r.tokenRefreshed,detail:Fe(e)},c=Vn(o),d=!c&&Gn(n.status,i);return new B(o,a,{authExpired:d,retryableForBaseUrl:c||Jn(n.status,i)})}function Ln(t,e){return!!(e&&t instanceof B&&t.retryableForBaseUrl)}function qn(t){return t instanceof B&&t.authExpired}function Gn(t,e){return t===401||t===403||e===401||e===403||e===5001}function Jn(t,e){return[401,403,404,405].includes(t)||typeof e=="number"&&[401,403,404,405].includes(e)}function Hn(t){return t instanceof B&&t.detail.http_status===200&&t.detail.chatbi_code===404&&t.detail.chatbi_message==="Message not found."}function Ve(t){if(typeof t.code=="number")return t.code;let e=Y(t.error);return typeof e?.status=="number"?e.status:void 0}function $n(t){if(typeof t.message=="string"&&t.message.trim())return t.message;let e=Y(t.error);return typeof e?.message=="string"&&e.message.trim()?e.message:void 0}function Vn(t){return/No static resource/i.test(t)}function Y(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:void 0}function zn(t,e){let n=Y(t);if(!Array.isArray(n?.themes))throw new B("ChatBI list-theme response missing themes",{operation:e.operation,base_url:e.baseUrl,path:e.path,detail:"missing themes"},{retryableForBaseUrl:!0})}function Fn(t,e){let r=[...t.headers.getSetCookie?.()??[],...Qn(t.headers.get("set-cookie"))].map(s=>le(s.trim().match(/(?:^|;\s*)uIdToken=([^;]+)/)?.[1])).find(Boolean);if(r)return r;let i=le(t.headers.get("x-auth-token"));return i||ze(e)}function Qn(t){return t?t.split(/,(?=\s*[^;,]+=)/):[]}function le(t){if(typeof t!="string")return;let e=t.trim();return e&&!/\s/.test(e)?e:void 0}function ze(t){let e=Y(t);if(e){for(let n of["uIdToken","authToken"]){let r=le(e[n]);if(r)return r}for(let n of["data","response"]){let r=ze(e[n]);if(r)return r}}}function Je(t,e){return t instanceof B?t.detail:{operation:e,detail:t instanceof Error?t.message:String(t)}}function Fe(t,e=1e3){return t.length>e?`${t.slice(0,e)}...`:t}function Wn(t){let e=`${t.chatbi_message??""} ${t.detail??""}`;return/BI 登录失败|密码登录|sign-?in|login/i.test(e)?"login_failed":t.http_status===401||t.http_status===403||t.chatbi_code===401||t.chatbi_code===403?"permission_denied":/No static resource|not valid JSON/i.test(e)||t.http_status===404||t.http_status===405||t.chatbi_code===404||t.chatbi_code===405?"public_api_unreachable":"unknown"}function Kn(t,e){let n=e.trim().toLowerCase(),r,i=[];for(let s of t){let o=s.theme_name.trim().toLowerCase();o===n?r=s:o.includes(n)&&i.push(s)}if(r)return r.theme_id;if(i.length===1)return i[0].theme_id;throw i.length>1?new Error(`\u4E3B\u9898\u540D\u5339\u914D\u5230\u591A\u4E2A\u7ED3\u679C\uFF1A${e}`):new Error(`\u672A\u627E\u5230\u4E3B\u9898\uFF1A${e}`)}function He(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>typeof e<"u"))}function Yn(t){if([t.final_status,t.answer_status,t.query_status].some(Zn))throw new Error(`ChatBI query failed: ${Xn(t.query_context?.err_msg,t.query_context?.detail,t.query_context?.msg,t.answer_context?.detail,t.answer_context?.msg,"unknown failure")}`);if(!t.answer?.explain?.trim()&&!(t.query_result?.columns?.length||t.query_result?.preview?.length))throw new Error("ChatBI response missing query content")}function Xn(...t){return t.find(e=>typeof e=="string"&&e.trim())?.trim()}function Zn(t){return typeof t=="string"&&t.trim().toLowerCase()==="failure"}function $e(t){let e=t-Date.now();if(e<=0)throw new Error("Insight request timed out");return e}async function er(t,e,n){let r=t-Date.now();if(r<=0)throw new Error(`Insight request timed out after ${n}ms`);await new Promise(i=>setTimeout(i,Math.min(e,r)))}var G="8.2.1",me=["search_metrics","list_metric_catalog","get_metric_detail","query_metric_data","search_metric_trees","get_metric_tree_detail","query_metric_tree_attribution"],tr=["get_bi_capabilities","global_search",...me,"execute_sql_query","get_dataset_detail","get_card_info","get_page_info"],nr=6e4,pe=new WeakMap;async function H(t,e){let n=pe.get(t);return(!n||n.expiresAt<=Date.now())&&pe.set(t,{expiresAt:Date.now()+nr,promise:ir(t,e).catch(r=>rr(r,e))}),pe.get(t).promise}function Ke(t){let e=!t.BI_BASE_URL,n="HTTP \u6A21\u5F0F\u4E0B execute_sql_query \u4F1A\u5728\u8C03\u7528\u65F6\u4F7F\u7528\u5F53\u524D\u7528\u6237 token \u5224\u65AD BI \u7248\u672C/\u80FD\u529B\u3002",r="HTTP \u6A21\u5F0F\u542F\u52A8\u671F\u5C1A\u672A\u89E3\u6790\u8BF7\u6C42\u8C03\u7528\u8005\u3002";return{ok:!e,error:e?"\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1A\u7F3A\u5C11 BI_BASE_URL\u3002":void 0,versionSource:"api",dataVersion:t.BI_DATA_VERSION,service:ge(t,e?["get_bi_capabilities"]:fe(t)),caller:{ok:!1,error:r,features:{executeSqlQuery:{enabled:!1,minVersion:G,reason:r}},chatbi:J(t,r)},features:{executeSqlQuery:{enabled:!e,minVersion:G,reason:e?"\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1A\u7F3A\u5C11 BI_BASE_URL\u3002":n}},metricPlatform:{registeredTools:e?[]:me,readOnly:!0,lastError:e?"\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1A\u7F3A\u5C11 BI_BASE_URL\u3002":void 0},chatbi:J(t,"HTTP \u6A21\u5F0F\u542F\u52A8\u671F\u4E0D\u4F7F\u7528\u67D0\u4E2A\u7528\u6237 token \u63A2\u6D4B ChatBI \u80FD\u529B\u3002")}}async function Ye(t,e,n){let i=(await H(t,e)).features[n];if(!i.enabled)throw new Error(`\u5F53\u524D BI \u73AF\u5883\u4E0D\u652F\u6301 ${n}\uFF1A${i.reason??"\u80FD\u529B\u672A\u542F\u7528"}`)}function rr(t,e){let n=t instanceof Error?t.message:String(t);return{ok:!1,error:n,versionSource:"api",features:{executeSqlQuery:{enabled:!1,minVersion:G,reason:`\u65E0\u6CD5\u786E\u8BA4 BI \u80FD\u529B\uFF1A${n}`}},metricPlatform:{registeredTools:[],readOnly:!0,lastError:n},chatbi:J(e,n),service:ge(e,fe(e)),caller:{ok:!1,error:n,features:{executeSqlQuery:{enabled:!1,minVersion:G,reason:`\u65E0\u6CD5\u786E\u8BA4 BI \u80FD\u529B\uFF1A${n}`}},chatbi:J(e,n)}}}async function ir(t,e){let n=or(e);if(n.length)throw new Error(`\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1A${n.join("\uFF1B")}\u3002`);let r=e.BI_DATA_VERSION?"env":"api",i=e.BI_DATA_VERSION?{dataVersion:e.BI_DATA_VERSION,capabilityVersion:e.BI_DATA_VERSION}:await ar(t),s=cr(i.capabilityVersion,G),o=await sr(e);return{ok:!0,appVersion:i.appVersion,dataVersion:i.dataVersion,versionSource:r,service:ge(e,fe(e)),caller:{ok:!0,features:{executeSqlQuery:s},chatbi:o},features:{executeSqlQuery:s},metricPlatform:{registeredTools:me,readOnly:!0},chatbi:o}}function fe(t){let e=new Set(tr);if(K(t)||t.MCP_TRANSPORT==="streamable-http")for(let n of new R(t).getRegisteredTools())e.add(n);return[...e]}function ge(t,e){return{mode:t.MCP_TRANSPORT??"stdio",toolList:e,boundBISite:{configured:!!t.BI_BASE_URL,baseUrl:t.BI_BASE_URL,publicPath:t.BI_PUBLIC_PATH}}}async function sr(t){let e=new R(t);return K(t)?e.probe():J(t,"\u7F3A\u5C11 BI_BASE_URL \u6216\u9274\u6743\u914D\u7F6E\u3002")}function J(t,e){return{available:!1,registeredTools:K(t)?new R(t).getRegisteredTools():[],failureType:"unknown",triedBaseUrls:[],lastError:{operation:"probe",chatbi_message:e,detail:e}}}function or(t){let e=[];if(t.BI_BASE_URL||e.push("\u7F3A\u5C11 BI_BASE_URL"),!t.BI_UID_TOKEN){let n=[["BI_LOGIN_DOMAIN",t.BI_LOGIN_DOMAIN],["BI_LOGIN_ID",t.BI_LOGIN_ID],["BI_LOGIN_PASSWORD",t.BI_LOGIN_PASSWORD]].filter(([,r])=>!r).map(([r])=>r);n.length&&e.push(`\u7F3A\u5C11\u9274\u6743\u914D\u7F6E\uFF1A\u8BF7\u914D\u7F6E BI_UID_TOKEN\uFF0C\u6216\u8865\u5168\u8D26\u53F7\u5BC6\u7801\u767B\u5F55\u914D\u7F6E\uFF08\u7F3A\u5C11 ${n.join("\u3001")}\uFF09`)}return e}async function ar(t){let e=await t.get("/api/server-version"),n=We(e.version),r=We(e.dataVersion)??n;if(!r)throw new Error("BI \u7248\u672C\u63A5\u53E3\u672A\u8FD4\u56DE version \u6216 dataVersion\u3002");return{appVersion:n,dataVersion:r,capabilityVersion:r}}function cr(t,e){let n=Qe(t),r=Qe(e);if(!r)throw new Error(`\u5185\u90E8\u914D\u7F6E\u9519\u8BEF\uFF1A\u65E0\u6CD5\u89E3\u6790\u6700\u4F4E\u7248\u672C ${e}\u3002`);if(!n)return{enabled:!1,minVersion:e,reason:`\u65E0\u6CD5\u4ECE\u7248\u672C\u5B57\u7B26\u4E32 "${t}" \u4E2D\u89E3\u6790\u4EA7\u54C1\u7248\u672C\uFF0C\u8BF7\u914D\u7F6E BI_DATA_VERSION\u3002`};let i=ur(n,r)>=0;return{enabled:i,minVersion:e,reason:i?void 0:`\u9700\u8981 BI ${e}+\uFF0C\u5F53\u524D\u7248\u672C\u4E3A ${t}\u3002`}}function Qe(t){let e=t.match(/(\d+)\.(\d+)\.(\d+)/);if(e)return[Number(e[1]),Number(e[2]),Number(e[3])]}function ur(t,e){for(let n=0;n<t.length;n+=1){let r=t[n]-e[n];if(r!==0)return r}return 0}function We(t){return typeof t=="string"&&t.trim()?t.trim():void 0}function dr(t){return{transport:"stdio",biUidToken:t.BI_UID_TOKEN,audit:{}}}function Xe(t){return{resolve:()=>dr(t)}}function lr(t){let e=X(t,"x-guanbi-uid-token")?.trim();if(!e)throw new Error("\u7F3A\u5C11 GuanBI \u7528\u6237\u4EE4\u724C\uFF1A\u8BF7\u901A\u8FC7 X-GuanBI-Uid-Token \u4F20\u5165\u5F53\u524D\u7528\u6237 uIdToken\u3002");return{transport:"streamable-http",biUidToken:e,audit:{tenantId:he(X(t,"x-tenant-id")),endUserId:he(X(t,"x-end-user-id")),traceId:he(X(t,"x-trace-id"))}}}function Ze(){return{resolve:t=>t?.requestInfo?.headers?lr(t.requestInfo.headers):{transport:"streamable-http",audit:{}}}}function X(t,e){if(t instanceof Headers)return t.get(e)??void 0;let n=t.get;if(typeof n=="function")return n.call(t,e)??void 0;let r=e.toLowerCase();for(let[i,s]of Object.entries(t))if(i.toLowerCase()===r)return Array.isArray(s)?s[0]:s}function he(t){return t?.trim()||void 0}var Z=class{constructor(e){this.config=e;this.token=e.BI_UID_TOKEN}config;token;async get(e,n){return this.request("GET",e,void 0,n)}async post(e,n,r){return this.request("POST",e,n,r)}async put(e,n,r){return this.request("PUT",e,n,r)}async getText(e){let n=await this.ensureToken(),r=await fetch(this.buildUrl(e),{method:"GET",headers:{"raw-backend-response":"TRUE",Cookie:`uIdToken=${n}`},signal:AbortSignal.timeout(this.config.BI_REQUEST_TIMEOUT_MS)});if(this.shouldRefreshToken(r)){let s=await this.refreshToken();r=await fetch(this.buildUrl(e),{method:"GET",headers:{"raw-backend-response":"TRUE",Cookie:`uIdToken=${s}`},signal:AbortSignal.timeout(this.config.BI_REQUEST_TIMEOUT_MS)})}let i=await r.text();if(!r.ok)throw new Error(`BI \u8BF7\u6C42\u5931\u8D25\uFF1AGET ${e} HTTP ${r.status} ${et(i)}`);return this.refreshTokenFromResponse(r),i}async request(e,n,r,i){let s=await this.ensureToken(),o=await this.fetchWithToken(e,n,s,r,i);if(this.shouldRefreshToken(o)){let c=await this.refreshToken();o=await this.fetchWithToken(e,n,c,r,i)}let a=await o.text();if(!o.ok)throw new Error(`BI \u8BF7\u6C42\u5931\u8D25\uFF1A${e} ${n} HTTP ${o.status} ${et(a)}`);return this.refreshTokenFromResponse(o),pr(a)}async fetchWithToken(e,n,r,i,s){return fetch(this.buildUrl(n),{method:e,headers:{"Content-Type":"application/json","raw-backend-response":"TRUE",Cookie:`uIdToken=${r}`,...s?.headers},body:e==="POST"||e==="PUT"?JSON.stringify(i??{}):void 0,signal:AbortSignal.timeout(this.config.BI_REQUEST_TIMEOUT_MS)})}async ensureToken(){if(this.token)return this.token;let e=await W(this.config);return this.token=e.token,e.token}async refreshToken(){return this.token=void 0,this.ensureToken()}refreshTokenFromResponse(e){let n=fr(e);!n||n===this.token||(this.token=n)}shouldRefreshToken(e){return this.hasPasswordLogin()&&e.status===401}hasPasswordLogin(){return!!(this.config.BI_LOGIN_DOMAIN&&this.config.BI_LOGIN_ID&&this.config.BI_LOGIN_PASSWORD)}buildUrl(e){let n=e.startsWith("/")?e:`/${e}`;return`${this.config.BI_BASE_URL}${this.config.BI_PUBLIC_PATH}${n}`}};function pr(t){if(!t)return;let e=JSON.parse(t);if(!mr(e))return e;if(e.result&&!["ok","success"].includes(e.result.toLowerCase()))throw new Error(`BI \u8FD4\u56DE\u9519\u8BEF\uFF1A${e.message??JSON.stringify(e.error??e)}`);if(e.success===!1)throw new Error(`BI \u8FD4\u56DE\u9519\u8BEF\uFF1A${e.message??JSON.stringify(e.error??e)}`);return"response"in e?e.response:e}function mr(t){return!t||typeof t!="object"||Array.isArray(t)?!1:"response"in t||"result"in t||"success"in t}function fr(t){return gr(t.headers)??_r(t.headers)}function gr(t){return[...t.getSetCookie?.()??[],...hr(t.get("set-cookie"))].map(n=>tt(n.trim().match(/(?:^|;\s*)uIdToken=([^;]+)/)?.[1])).find(Boolean)}function hr(t){return t?t.split(/,(?=\s*[^;,]+=)/):[]}function _r(t){return tt(t.get("x-auth-token"))}function tt(t){if(typeof t!="string")return;let e=t.trim();return e&&!/\s/.test(e)?e:void 0}function et(t,e=1e3){return t.length>e?`${t.slice(0,e)}...`:t}var ee=class{constructor(e,n={}){this.baseConfig=e;this.options=n}baseConfig;options;stdioClient;create(e){if(e.transport==="stdio"&&this.stdioClient)return this.stdioClient;let n=this.resolveConfig(e),r={client:this.options.clientFactory?.(n)??new Z(n),config:n,context:e};return e.transport==="stdio"&&(this.stdioClient=r),r}resolveConfig(e){let n=e.biUidToken??(e.transport==="stdio"?this.baseConfig.BI_UID_TOKEN:void 0);return{...this.baseConfig,BI_UID_TOKEN:n,BI_LOGIN_DOMAIN:e.transport==="stdio"?this.baseConfig.BI_LOGIN_DOMAIN:"",BI_LOGIN_ID:e.transport==="stdio"?this.baseConfig.BI_LOGIN_ID:void 0,BI_LOGIN_PASSWORD:e.transport==="stdio"?this.baseConfig.BI_LOGIN_PASSWORD:void 0}}};var nt={endpoint:"https://www.google-analytics.com/mp/collect",measurementId:"G-800H8JWDPP",apiSecret:"poAwpMEhQteDl1rXKtNIqg",eventName:"guanbi_mcp_tool_call",clientId:"0000000000.0000000000",sessionId:1,engagementTimeMsec:1,timeoutMs:3e3,maxResponseBytes:1024},te=class{serviceDomain;appVersion;enabled;sender;now;constructor({config:e,appVersion:n,sender:r=yr(),now:i=Date.now}){this.serviceDomain=Cr(e.BI_BASE_URL),this.appVersion=n,this.enabled=Tr(e),this.sender=r,this.now=i}observeToolCallStart(e){return{toolName:e,startedAtMs:this.now()}}observeToolCallEnd(e,n){if(!this.enabled||!this.serviceDomain)return;let r={service_domain:this.serviceDomain,app_version:this.appVersion,tool:e.toolName,success:n.success,duration_ms_bucket:wr(this.now()-e.startedAtMs),error_type:n.success?"none":Sr(n.error)};try{Promise.resolve(this.sender(r)).catch(()=>{})}catch{}}};function br(t=nt){return e=>Ir(e,t)}async function Ir(t,e=nt){try{if(!e.endpoint||!e.measurementId||!e.apiSecret||!t.tool)return;let n=new URL(e.endpoint);n.searchParams.set("measurement_id",e.measurementId),n.searchParams.set("api_secret",e.apiSecret);let r=JSON.stringify({client_id:e.clientId,events:[{name:e.eventName,params:{service_domain:t.service_domain,app_version:t.app_version,tool:t.tool,success:t.success,duration_ms_bucket:t.duration_ms_bucket,error_type:t.error_type,session_id:e.sessionId,engagement_time_msec:e.engagementTimeMsec}}]}),i=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:r,signal:AbortSignal.timeout(e.timeoutMs)});await Br(i,e.maxResponseBytes)}catch{}}function yr(){return kr(process.env)?()=>{}:br()}function Tr(t){let e=t.GUANBI_MCP_USAGE_STATS?.trim().toLowerCase();return e?["0","false","off","no"].includes(e)?!1:(["1","true","on","yes"].includes(e),!0):!0}function rt(t,e,n){return(async(...r)=>{let i=n.observeToolCallStart(t);try{let s=await e(...r);return n.observeToolCallEnd(i,{success:!0}),s}catch(s){throw n.observeToolCallEnd(i,{success:!1,error:s}),s}})}function Cr(t){if(t)try{return new URL(t).hostname}catch{return}}function wr(t){return t<1e3?"<1s":t<5e3?"1-5s":t<3e4?"5-30s":t<12e4?"30-120s":">120s"}async function Br(t,e){let n=t.body?.getReader();if(!n)return;let r=0;try{for(;r<e;){let{done:i,value:s}=await n.read();if(i)return;r+=s.byteLength}}finally{await n.cancel().catch(()=>{})}}function Sr(t){let e=t instanceof Error?t.message:String(t);return/校验|验证|validation|invalid|schema|zod/i.test(e)?"validation":/鉴权|登录|认证|unauthorized|unauthenticated|401|auth/i.test(e)?"auth":/权限|forbidden|permission|403/i.test(e)?"permission":/timeout|network|fetch|econn|enotfound|socket/i.test(e)?"network":/BI 请求失败|BI 返回错误|HTTP \d{3}/i.test(e)?"bi_error":"unknown"}function kr(t){return t.NODE_ENV==="test"||t.VITEST==="true"}var ne=class{constructor(e,n,r=new Q){this.callerContextResolver=e;this.clientFactory=n;this.auditLogger=r}callerContextResolver;clientFactory;auditLogger;async run(e,n,r){let i=Date.now(),s=await this.callerContextResolver.resolve(n);try{let o=await e(this.clientFactory.create(s));if(r){let a=Rr(o)?"error":"success";this.auditLogger.record(de(r,s,i,a,o))}return o}catch(o){throw r&&this.auditLogger.record(de(r,s,i,"error",o)),o}}};function Rr(t){return!!(t&&typeof t=="object"&&t.isError===!0)}function v(t){return{content:[{type:"text",text:JSON.stringify(t,null,2)}]}}function y(t){let e=it(t);return{content:[{type:"text",text:JSON.stringify(e,null,2)}],structuredContent:e}}function $(t){let e=it(t);return{content:[{type:"text",text:JSON.stringify(e,null,2)}],isError:!0}}function it(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}var st={};async function ot(t,e){return v(await H(t,e))}import{createHash as vr}from"crypto";import{z as p}from"zod";var Ar=6e4,P=1e4,at=10*6e4,re=new Map,ie=new Map,_e=new Map,be=new Map,ut=p.object({format:p.literal("markdown").describe("\u6700\u7EC8\u7ED3\u679C\u683C\u5F0F\u3002"),content:p.string().describe("\u6700\u7EC8\u5C55\u793A\u7ED9\u8C03\u7528\u8005\u6216\u7528\u6237\u7684 markdown \u5185\u5BB9\u3002")}),dt={themes:p.array(p.object({theme_id:p.string().optional(),theme_name:p.string().optional(),is_insight_enabled:p.boolean().optional()}).passthrough()),resolved_base_url:p.string().optional(),tried_base_urls:p.array(p.string()).optional()},lt={session_id:p.string().optional(),message_id:p.string().optional(),answer:p.unknown().optional().describe("ChatBI \u540E\u7AEF\u8FD4\u56DE\u7684\u95EE\u6570\u89E3\u91CA\u6216\u539F\u59CB\u7B54\u6848\u7ED3\u6784\u3002"),sql:p.unknown().optional().describe("ChatBI \u540E\u7AEF\u751F\u6210\u7684 SQL \u4FE1\u606F\u3002"),answer_status:p.string().optional(),final_status:p.string().optional(),query_result:p.unknown().optional().describe("ChatBI \u540E\u7AEF\u8FD4\u56DE\u7684\u7ED3\u6784\u5316\u67E5\u8BE2\u7ED3\u679C\uFF0C\u901A\u5E38\u5305\u542B columns\u3001preview\u3001truncated\u3001row_limit\u3002"),resolved_base_url:p.string().optional(),tried_base_urls:p.array(p.string()).optional()},ps={message_id:p.string().optional(),session_id:p.string().optional(),status:p.string(),detail:p.string().nullable().optional(),question:p.string().nullable().optional(),answer:p.unknown().optional(),final_result:ut.describe("\u6700\u7EC8\u5C55\u793A\u7ED3\u679C\uFF1B\u8C03\u7528\u65B9\u5E94\u4F18\u5148\u8BFB\u53D6 final_result.content\uFF0Canswer \u4EC5\u4FDD\u7559\u540E\u7AEF\u539F\u59CB\u7ED3\u679C\u3002"),resolved_base_url:p.string().optional(),tried_base_urls:p.array(p.string()).optional()},pt={theme_id:p.string().optional(),message_id:p.string().optional(),session_id:p.string().optional(),status:p.literal("started"),deduped:p.boolean(),retry_after_ms:p.number().int().nonnegative(),next_action:p.string().optional(),resolved_base_url:p.string().optional(),tried_base_urls:p.array(p.string()).optional()},mt={message_id:p.string().optional(),session_id:p.string().optional(),status:p.string(),detail:p.string().nullable().optional(),question:p.string().nullable().optional(),answer:p.unknown().optional(),throttled:p.boolean(),retry_after_ms:p.number().int().nonnegative(),final_result:ut.describe("\u6700\u7EC8\u5C55\u793A\u7ED3\u679C\uFF1B\u4EC5\u5728 status \u4E3A success \u65F6\u5B58\u5728\u3002\u8C03\u7528\u65B9\u5E94\u4F18\u5148\u8BFB\u53D6 final_result.content\uFF0Canswer \u4EC5\u4FDD\u7559\u540E\u7AEF\u539F\u59CB\u7ED3\u679C\u3002").optional(),next_action:p.string().optional(),resolved_base_url:p.string().optional(),tried_base_urls:p.array(p.string()).optional()},ft={is_insight:p.boolean().optional().describe("\u662F\u5426\u53EA\u5217\u51FA\u6D1E\u5BDF\u4E3B\u9898\u3002")},gt={theme_id:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898 ID\u3002"),theme_name:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898\u540D\u79F0\u3002"),message:p.string().min(1).describe("\u81EA\u7136\u8BED\u8A00\u95EE\u6570\u95EE\u9898\u3002"),session_id:p.string().min(1).optional().describe("\u53EF\u9009\u4F1A\u8BDD ID\uFF0C\u7528\u4E8E\u95EE\u6570\u7EED\u95EE\u3002\u540C\u4E00\u4E2A session_id \u53EA\u80FD\u7EE7\u7EED\u95EE\u6570\uFF0C\u4E0D\u80FD\u518D\u7528\u4E8E\u6D1E\u5BDF\u3002"),external_context:p.string().min(1).optional().describe("\u53EF\u9009\u5916\u90E8\u4E0A\u4E0B\u6587\u3002")},ms={theme_id:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898 ID\u3002"),theme_name:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898\u540D\u79F0\u3002"),message:p.string().min(1).describe("\u81EA\u7136\u8BED\u8A00\u6D1E\u5BDF\u95EE\u9898\u3002"),session_id:p.string().min(1).optional().describe("\u53EF\u9009\u4F1A\u8BDD ID\uFF0C\u7528\u4E8E\u6D1E\u5BDF\u7EED\u95EE\u3002\u540C\u4E00\u4E2A session_id \u53EA\u80FD\u7EE7\u7EED\u6D1E\u5BDF\uFF0C\u4E0D\u80FD\u518D\u7528\u4E8E\u95EE\u6570\u3002"),external_context:p.string().min(1).optional().describe("\u53EF\u9009\u5916\u90E8\u4E0A\u4E0B\u6587\u3002"),timeout_ms:p.number().int().positive().optional().describe("\u7B49\u5F85\u6D1E\u5BDF\u5B8C\u6210\u7684\u8D85\u65F6\u65F6\u95F4\uFF0C\u9ED8\u8BA4 300000ms\u3002"),poll_interval_ms:p.number().int().positive().optional().describe("\u8F6E\u8BE2\u95F4\u9694\uFF0C\u9ED8\u8BA4 2000ms\u3002")},ht={theme_id:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898 ID\u3002"),theme_name:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898\u540D\u79F0\u3002"),message:p.string().min(1).describe("\u81EA\u7136\u8BED\u8A00\u6D1E\u5BDF\u95EE\u9898\u3002\u6D1E\u5BDF\u901A\u5E38\u8017\u65F6 2-3 \u5206\u949F\uFF0C5 \u5206\u949F\u89C6\u4E3A\u8D85\u65F6\uFF1B\u540C\u4E00\u95EE\u9898\u53EA\u53D1\u8D77\u4E00\u6B21\u3002"),session_id:p.string().min(1).optional().describe("\u53EF\u9009\u4F1A\u8BDD ID\uFF0C\u7528\u4E8E\u6D1E\u5BDF\u7EED\u95EE\u3002\u540C\u4E00\u4E2A session_id \u53EA\u80FD\u7EE7\u7EED\u6D1E\u5BDF\uFF0C\u4E0D\u80FD\u518D\u7528\u4E8E\u95EE\u6570\u3002"),external_context:p.string().min(1).optional().describe("\u53EF\u9009\u5916\u90E8\u4E0A\u4E0B\u6587\u3002")},_t={theme_id:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898 ID\u3002\u4F18\u5148\u4F7F\u7528 chatbi_insight_start \u8FD4\u56DE\u7684 theme_id\u3002"),theme_name:p.string().min(1).optional().describe("ChatBI \u4E3B\u9898\u540D\u79F0\uFF1B\u672A\u63D0\u4F9B theme_id \u65F6\u4F1A\u6309\u540D\u79F0\u67E5\u627E\u6D1E\u5BDF\u4E3B\u9898\u3002"),message_id:p.string().min(1).describe("chatbi_insight_start \u8FD4\u56DE\u7684\u6D88\u606F ID\u3002\u5EFA\u8BAE\u81F3\u5C11\u95F4\u9694 10 \u79D2\u67E5\u8BE2\u4E00\u6B21\uFF0C5 \u5206\u949F\u540E\u505C\u6B62\u7B49\u5F85\u3002")};async function bt(t,e){let n=new R(t);try{let r=await n.listThemes({isInsight:e.is_insight});return y({themes:r,resolved_base_url:n.getResolvedBaseUrl(),tried_base_urls:n.getTriedBaseUrls()})}catch(r){return oe(n,r,"listThemes")}}async function It(t,e){let n=new R(t);try{let r=await n.query({themeId:e.theme_id,themeName:e.theme_name,message:e.message,sessionId:e.session_id,externalContext:e.external_context,fastMode:!0});return y({session_id:r.session_id,message_id:r.message_id,answer:r.answer,sql:r.sql,answer_status:r.answer_status,final_status:r.final_status,query_result:r.query_result,resolved_base_url:n.getResolvedBaseUrl(),tried_base_urls:n.getTriedBaseUrls()})}catch(r){return oe(n,r,"query")}}async function yt(t,e){let n=new R(t);try{let r=Ct({caller_scope:wt(t),theme_id:e.theme_id,theme_name:e.theme_name,message:e.message,session_id:e.session_id,external_context:e.external_context}),i=Er(r);if(i)return y({...i,deduped:!0,retry_after_ms:P,next_action:"\u540C\u4E00\u6D1E\u5BDF\u95EE\u9898\u521A\u521A\u5DF2\u7ECF\u53D1\u8D77\uFF0C\u5DF2\u590D\u7528\u5DF2\u6709 message_id\u3002\u8BF7\u4F7F\u7528 chatbi_insight_poll \u67E5\u8BE2\u7ED3\u679C\u3002"});let s=_e.get(r);if(s){let c=await s;return y({...c,deduped:!0,retry_after_ms:P,next_action:"\u540C\u4E00\u6D1E\u5BDF\u95EE\u9898\u6B63\u5728\u53D1\u8D77\u4E2D\uFF0C\u5DF2\u590D\u7528\u5DF2\u6709\u8BF7\u6C42\u7ED3\u679C\u3002\u8BF7\u4F7F\u7528 chatbi_insight_poll \u67E5\u8BE2\u7ED3\u679C\u3002"})}let o=n.startInsight({themeId:e.theme_id,themeName:e.theme_name,message:e.message,sessionId:e.session_id,externalContext:e.external_context}).then(c=>{let d={theme_id:c.theme_id,message_id:c.message_id,session_id:c.session_id,status:"started"};return Or(r,d),d}).finally(()=>{_e.delete(r)});_e.set(r,o);let a=await o;return y({...a,deduped:!1,retry_after_ms:P,next_action:"\u6D1E\u5BDF\u4EFB\u52A1\u5DF2\u53D1\u8D77\u3002\u6D1E\u5BDF\u901A\u5E38\u8017\u65F6 2-3 \u5206\u949F\uFF0C\u8BF7\u4F7F\u7528 chatbi_insight_poll \u643A\u5E26 theme_id \u548C message_id \u67E5\u8BE2\u7ED3\u679C\uFF1B5 \u5206\u949F\u540E\u4ECD\u672A\u6210\u529F\u53EF\u89C6\u4E3A\u8D85\u65F6\u3002",resolved_base_url:n.getResolvedBaseUrl(),tried_base_urls:n.getTriedBaseUrls()})}catch(r){return oe(n,r,"insight.start")}}async function Tt(t,e){let n=new R(t);try{let r=Ct({caller_scope:wt(t),message_id:e.message_id}),i=xr(r);if(i){let f=Ie(i.result),C=Te(i.result,!0);return y({message_id:i.result.message_id,session_id:i.result.session_id,status:i.result.status,detail:ye(i.result),question:i.result.question,answer:i.result.answer,throttled:!0,retry_after_ms:i.retryAfterMs,...f,next_action:C})}let s=be.get(r);if(s){let f=await s,C=Ce(f.status),_=Ie(f),T=Te(f,!0);return y({message_id:f.message_id,session_id:f.session_id,status:f.status,detail:ye(f),question:f.question,answer:f.answer,throttled:!0,retry_after_ms:C?0:P,..._,next_action:T})}let o=n.pollInsight({themeId:e.theme_id,themeName:e.theme_name,messageId:e.message_id}).then(f=>(Mr(r,f),f)).finally(()=>{be.delete(r)});be.set(r,o);let a=await o,c=Ce(a.status),d=Ie(a),m=Te(a,!1);return y({message_id:a.message_id,session_id:a.session_id,status:a.status,detail:ye(a),question:a.question,answer:a.answer,throttled:!1,retry_after_ms:c?0:P,...d,next_action:m,resolved_base_url:n.getResolvedBaseUrl(),tried_base_urls:n.getTriedBaseUrls()})}catch(r){return oe(n,r,"insight.poll")}}function Ie(t){return t.status!=="success"?{}:{final_result:{format:"markdown",content:Bt(t)}}}function ye(t){return t.detail!=null?t.detail:t.status==="failure"||t.status==="stopped"?Pr(t):t.detail}function Te(t,e){if(t.status!=="success")return t.status==="waiting"?e?"\u540C\u4E00 message_id \u6B63\u5728\u67E5\u8BE2\u4E2D\u6216\u521A\u521A\u67E5\u8BE2\u8FC7\uFF0C\u5DF2\u8FD4\u56DE\u5DF2\u6709\u7ED3\u679C\uFF1B\u8BF7\u81F3\u5C11\u95F4\u9694 10 \u79D2\u518D\u67E5\u3002":"\u6D1E\u5BDF\u4EFB\u52A1\u4ECD\u5728\u6267\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u7EE7\u7EED\u8C03\u7528 chatbi_insight_poll \u67E5\u8BE2\u7ED3\u679C\u3002":t.status==="failure"||t.status==="stopped"?"\u6D1E\u5BDF\u4EFB\u52A1\u672A\u6210\u529F\u5B8C\u6210\uFF0C\u8BF7\u67E5\u770B detail\uFF1B\u5982\u9700\u91CD\u8BD5\u8BF7\u91CD\u65B0\u8C03\u7528 chatbi_insight_start\u3002":"\u6D1E\u5BDF\u4EFB\u52A1\u5904\u4E8E\u975E\u6210\u529F\u72B6\u6001\uFF0C\u8BF7\u67E5\u770B status \u548C detail \u540E\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED\u67E5\u8BE2\u3002"}function Er(t){se();let e=re.get(t);if(!(!e||Date.now()-e.createdAt>=Ar))return e.result}function Or(t,e){se(),re.set(t,{createdAt:Date.now(),result:e})}function xr(t){se();let e=ie.get(t);if(!e)return;let n=Date.now()-e.checkedAt,r=Ce(e.result.status);if(!(!r&&n>=P))return{result:e.result,retryAfterMs:r?0:Math.max(0,P-n)}}function Ce(t){return t==="success"||t==="failure"||t==="stopped"}function Mr(t,e){se(),ie.set(t,{checkedAt:Date.now(),result:e})}function se(){let t=Date.now();for(let[e,n]of re)t-n.createdAt>=at&&re.delete(e);for(let[e,n]of ie)t-n.checkedAt>=at&&ie.delete(e)}function Ct(t){return JSON.stringify(Object.keys(t).sort().reduce((e,n)=>{let r=t[n];return typeof r<"u"&&(e[n]=r),e},{}))}function wt(t){return t.BI_UID_TOKEN?`uid:${ct(t.BI_UID_TOKEN)}`:`login:${ct(`${t.BI_LOGIN_DOMAIN??""}\0${t.BI_LOGIN_ID??""}`)}`}function ct(t){return vr("sha256").update(t).digest("hex").slice(0,16)}function Bt(t){let e=t.answer?.trim();if(e)return Lr(e);let n=t.detail?.trim();return n||"\u5206\u6790\u5DF2\u5B8C\u6210\uFF0C\u4F46\u6CA1\u6709\u53EF\u5C55\u793A\u7684 markdown \u5185\u5BB9\u3002"}function Pr(t){switch(t.status){case"success":return Bt(t);case"waiting":return"\u6D1E\u5BDF\u4EFB\u52A1\u4ECD\u5728\u6267\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u7EE7\u7EED\u8C03\u7528 chatbi_insight_poll \u67E5\u8BE2\u7ED3\u679C\u3002";case"failure":case"stopped":return t.detail?.trim()||"\u6D1E\u5BDF\u4EFB\u52A1\u672A\u6210\u529F\u5B8C\u6210\u3002";default:return t.detail?.trim()||`\u6D1E\u5BDF\u4EFB\u52A1\u5F53\u524D\u72B6\u6001\uFF1A${t.status}`}}function Dr(t,e){let n=[`| ${t.join(" | ")} |`,`|${t.map(()=>" --- ").join("|")}|`];for(let r of e)n.push(`| ${t.map((i,s)=>Ur(jr(r[s]))).join(" | ")} |`);return n.join(`
3
+ `)}function jr(t){return t===null||typeof t>"u"||t===""?"-":String(t)}function Ur(t){return t.replaceAll(`\r
4
+ `,"<br>").replaceAll(`
5
+ `,"<br>").replaceAll("\r","<br>").replaceAll("|","\\|")}function Nr(t,e){return t?e&&e>0?`\u7ED3\u679C\u5DF2\u622A\u65AD\uFF0C\u4EC5\u5C55\u793A\u524D ${e} \u884C\u3002`:"\u7ED3\u679C\u5DF2\u622A\u65AD\uFF0C\u4EC5\u5C55\u793A\u90E8\u5206\u6570\u636E\u3002":""}function Lr(t){let e=/```GuanViz\.json\n([\s\S]*?)\n```/g;return t.replace(e,(n,r)=>qr(r)??n)}function qr(t){try{let e=JSON.parse(t),n=e.data_info?.columns,r=e.data_info?.preview;if(!Array.isArray(n)||!n.length||!Array.isArray(r))return;let i=n.map(m=>m.name??"-"),s=Jr(e.viz_config),o=Hr(i,r,s),a=r.map(m=>i.map((f,C)=>$r(m[C],s.get(f),o.get(f)))),c=Dr(i,a),d=Nr(!!e.data_info?.truncated,e.data_info?.row_limit);return d?`${c}
6
+
7
+ ${d}`:c}catch{return}}var we=new Map([["k",1e3],["K",1e3],["M",1e6],["B",1e9],["\u4E07",1e4],["\u4EBF",1e8]]),Gr=[[1e8,"\u4EBF"],[1e4,"\u4E07"]];function Jr(t){let e=t?.chartMeta?.chartMain?.zoneData?.metric,n=new Map;if(!Array.isArray(e))return n;for(let r of e)r.name&&r.fieldFormat?.numberFormat&&n.set(r.name,r.fieldFormat.numberFormat);return n}function Hr(t,e,n){let r=new Map;for(let[i,s]of t.entries()){let o=n.get(s);if(o?.prefixUnit!=="auto")continue;let a=0;for(let d of e){let m=St(d[i]);typeof m=="number"&&(a=Math.max(a,Math.abs(m/kt(o))))}let c=Qr(a);c&&r.set(s,c)}return r}function $r(t,e,n){if(!e)return t;let r=St(t);return typeof r!="number"?t:Vr(r,e,n)}function St(t){if(typeof t=="number"&&Number.isFinite(t))return t;if(typeof t!="string")return;let e=Number(t.trim());return Number.isFinite(e)?e:void 0}function Vr(t,e,n){let r=kt(e),{unit:i,shouldScale:s}=zr(e,n),o=s&&i?we.get(i)??1:1,a=t/r/o,c=Fr(e.decimalPlaces),d=e.useThousandsSeparator?a.toLocaleString("en-US",{minimumFractionDigits:c,maximumFractionDigits:c}):a.toFixed(c),m=i&&e.showPrefixUnit!==!1?i:"",f=e.showSuffix===!1||typeof e.suffix!="string"?"":e.suffix;return`${d}${m}${f}`}function kt(t){if(t.showPrefixUnit!==!1&&typeof t.prefixUnit=="string"&&t.prefixUnit!=="auto"&&we.has(t.prefixUnit))return 1;let e=Number(t.divideDataBy??1);return Number.isFinite(e)&&e!==0?e:1}function zr(t,e){return t.showPrefixUnit===!1?{unit:"",shouldScale:!1}:t.prefixUnit==="auto"?{unit:e??"",shouldScale:!0}:typeof t.prefixUnit=="string"&&we.has(t.prefixUnit)?{unit:t.prefixUnit,shouldScale:!0}:{unit:"",shouldScale:!1}}function Fr(t){return typeof t!="number"||!Number.isFinite(t)?2:Math.max(0,Math.min(100,Math.trunc(t)))}function Qr(t){return Gr.find(([e])=>t>=e)?.[1]??""}function oe(t,e,n){let r=Wr(t,e,n);return $({error:"chatbi_request_failed",requested_operation:n,...r,tried_base_urls:r.tried_base_urls??t.getTriedBaseUrls()})}function Wr(t,e,n){return e instanceof B?e.detail:t.getLastError()??{operation:n,detail:e instanceof Error?e.message:String(e)}}import{z as Be}from"zod";var Rt={dsId:Be.string().min(1).describe("\u6570\u636E\u96C6 ID\u3002")},vt={cdId:Be.string().min(1).describe("\u5361\u7247 ID\u3002")},At={pageId:Be.string().min(1).describe("\u9875\u9762/\u4EEA\u8868\u677F ID\u3002")};async function Et(t,e){let n=await t.get(`/api/data-source/${encodeURIComponent(e.dsId)}`);return v(n)}async function Ot(t,e){let n=await t.get(`/api/card/${encodeURIComponent(e.cdId)}`);return v(n)}async function xt(t,e){let n=await t.get(`/api/page/${encodeURIComponent(e.pageId)}`);return v(n)}import{z as x}from"zod";var Kr=x.object({name:x.string().min(1),query:x.string().min(1)}),Mt={query:x.string().min(1).describe("\u8981\u6267\u884C\u7684\u7B80\u5355\u67E5\u8BE2 SQL\u3002\u4EC5\u652F\u6301\u5355\u8868\u67E5\u8BE2\u548C\u67E5\u8BE2\u8BED\u53E5\uFF0C\u63A8\u8350\u7528\u4E8E\u5C11\u91CF\u7ED3\u679C\u9884\u89C8\u6216\u8F7B\u91CF\u5206\u6790\uFF0C\u4E0D\u9002\u5408\u62C9\u53D6\u5168\u91CF\u6570\u636E\uFF1B\u5EFA\u8BAE\u663E\u5F0F\u5199 LIMIT\u3002"),inputs:x.array(x.string().min(1)).min(1).max(1).describe("SQL \u67E5\u8BE2\u4F9D\u8D56\u7684\u6570\u636E\u96C6 ID \u5217\u8868\u3002\u4EC5\u652F\u6301\u5355\u8868\u67E5\u8BE2\uFF0C\u8BF7\u53EA\u4F20 1 \u4E2A\u6570\u636E\u96C6 ID\u3002"),queryStructure:x.object({ctes:x.array(Kr).optional(),mainQuery:x.string().optional()}).optional().describe("\u7ED3\u6784\u5316\u67E5\u8BE2\u4FE1\u606F\uFF0C\u53EF\u7528\u4E8E\u62C6\u5206 CTE \u548C\u4E3B\u67E5\u8BE2\uFF1B\u4ECD\u4EC5\u9002\u7528\u4E8E\u5355\u8868\u67E5\u8BE2\u3002")};async function Pt(t,e,n){await Ye(t,e,"executeSqlQuery");try{let r=await t.post("/api/data-source/execute-sql-query",{...n,limit:e.BI_MAX_ROWS});return v({maxRowsHint:e.BI_MAX_ROWS,result:r})}catch(r){throw Yr(r)?new Error("execute_sql_query \u8FD4\u56DE 404\u3002\u8BF7\u5728\u7BA1\u7406\u540E\u53F0 -> \u9AD8\u7EA7\u8BBE\u7F6E -> \u5BF9\u5E94\u57DF\u540D\u4E0B\uFF0C\u6253\u5F00\u9AD8\u7EA7SQL\u67E5\u8BE2\u529F\u80FD\u3002"):r}}function Yr(t){return t instanceof Error&&t.message.includes("POST /api/data-source/execute-sql-query HTTP 404")}import{z as A}from"zod";var Dt={keyword:A.string().default("").describe("\u641C\u7D22\u5173\u952E\u8BCD\uFF0C\u7559\u7A7A\u65F6\u8FD4\u56DE\u8D44\u6E90\u5217\u8868\u3002"),resourceType:A.enum(["ALL","CARD","DASHBOARD","DATA_SET","ETL"]).optional().default("ALL"),limit:A.number().int().min(1).max(100).optional().default(20),offset:A.number().int().min(0).optional().default(0),utimeStartTime:A.number().int().optional().describe("\u66F4\u65B0\u65F6\u95F4\u8D77\u70B9\uFF0C\u6BEB\u79D2\u65F6\u95F4\u6233\u3002"),utimeEndTime:A.number().int().optional().describe("\u66F4\u65B0\u65F6\u95F4\u7EC8\u70B9\uFF0C\u6BEB\u79D2\u65F6\u95F4\u6233\u3002"),cardType:A.string().optional().describe("\u5361\u7247\u7C7B\u578B\u8FC7\u6EE4\uFF0C\u4EC5 resourceType \u5305\u542B CARD \u65F6\u4F7F\u7528\u3002"),permissionType:A.string().optional(),orderBy:A.string().optional(),isDesc:A.boolean().optional()};async function jt(t,e){let{cardType:n,...r}=e,i={...r,specificResourceFilters:n?{cardType:n}:void 0},s=await t.post("/api/global-search",i);return v(s)}import{z as l}from"zod";var D=class extends Error{constructor(n,r){super(n.message,{cause:r});this.detail=n;this.name="MetricPlatformRequestError"}detail},E=class{constructor(e,n){this.client=e;this.config=n}client;config;contextHeadersPromise;listProjects(){return this.get("listProjects","/api/metric-platform/projects")}searchMetrics(e){let n=h({projectId:e.projectId,dirId:e.dirId,status:e.status,nameLike:e.keyword,subTypes:e.subTypes?.join(","),orderBy:e.orderBy});return this.post("searchMetrics","/api/metric-platform/metrics",n)}listMetricFullTree(e){return this.get("listMetricFullTree",ke("/api/metric-platform/metrics/full-tree",{projectId:e.projectId,nameLike:e.keyword}))}listMetricDirectoryTree(e){return this.get("listMetricDirectoryTree",ke("/api/directory/METRIC_PLATFORM/unauthorized-tree",{projectId:e}))}getMetricDetail(e){return this.get("getMetricDetail",`/api/metric-platform/metrics/${encodeURIComponent(e)}`)}getMetricLineage(e,n){return this.post("getMetricLineage",`/api/resource-atlas/${encodeURIComponent(e)}`,{resourceTypeName:n})}queryMetricData(e){let{metricId:n,metricName:r,...i}=e;return this.post("queryMetricData","/api/metric-platform/metric-data/v2",h(i))}getCardEditSession(e){return this.get("getCardEditSession",`/api/card/${encodeURIComponent(e)}/edit/session`)}getCardEditMeta(e){return this.get("getCardEditMeta",`/api/card/${encodeURIComponent(e)}/edit`)}modifyCardEditMeta(e,n,r){return this.put("modifyCardEditMeta",`/api/oriput/card/${encodeURIComponent(e)}/edit/${encodeURIComponent(n)}/modify`,r)}queryCardEditData(e,n,r){return this.post("queryCardEditData",`/api/card/${encodeURIComponent(e)}/edit/${encodeURIComponent(n)}/data`,r)}searchMetricTrees(e){return this.get("searchMetricTrees",ke("/api/metric-platform/metric-tree/search",{nameLike:e.keyword,projectId:e.projectId,parentDirId:e.parentDirId,orderBy:e.orderBy}))}async getMetricTreeDetail(e){return this.get("getMetricTreeDetail",`/api/metric-platform/metric-tree/${encodeURIComponent(e)}`,await this.metricTreeHeaders(e,"dimension"))}async queryMetricTreeDrill(e,n){return this.post("queryMetricTreeDrill",`/api/metric-platform/metric-tree/${encodeURIComponent(e)}/drill`,n,await this.metricTreeHeaders(e,"dimension"))}async queryMetricTreeDecompose(e,n){return this.post("queryMetricTreeDecompose",`/api/metric-platform/metric-tree/${encodeURIComponent(e)}/metric-decompose`,n,await this.metricTreeHeaders(e,"metric"))}async put(e,n,r,i){try{return await this.client.put(n,r,i?{headers:i}:void 0)}catch(s){throw Se(e,n,s)}}async get(e,n,r){try{return await this.client.get(n,r?{headers:r}:void 0)}catch(i){throw Se(e,n,i)}}async post(e,n,r,i){try{return await this.client.post(n,r,i?{headers:i}:void 0)}catch(s){throw Se(e,n,s)}}async metricTreeHeaders(e,n){return{Referer:`${this.config.BI_BASE_URL??""}${this.config.BI_PUBLIC_PATH}/metrics-store/hierarchy/${encodeURIComponent(e)}/edit/${n}`,...await this.contextHeaders()}}async contextHeaders(){return this.contextHeadersPromise||(this.contextHeadersPromise=this.resolveContextHeaders()),this.contextHeadersPromise}async resolveContextHeaders(){let e={};if(this.config.BI_LOGIN_DOMAIN&&(e["x-dom-id"]=L(this.config.BI_LOGIN_DOMAIN)),this.config.BI_LOGIN_ID&&(e["user-id"]=L(this.config.BI_LOGIN_ID)),e["x-dom-id"]&&e["user-id"])return e;try{let n=await this.get("getUserProfile","/api/user/profile"),r=Ut(n.domId,n.domainId,n.domain,n.dom_id),i=Ut(n.email,n.loginId,n.userId,n.uId,n.uid);!e["x-dom-id"]&&r&&(e["x-dom-id"]=L(r)),!e["user-id"]&&i&&(e["user-id"]=L(i))}catch{}return e["x-dom-id"]||(e["x-dom-id"]=L(this.config.BI_LOGIN_DOMAIN||"guanbi")),e["user-id"]||(e["user-id"]=L(this.config.BI_LOGIN_ID||"unknown")),e}};function Se(t,e,n){let r=n instanceof Error?n.message:String(n),i=r.match(/\bHTTP\s+(\d{3})\b/);return new D({operation:t,path:e,status:i?Number(i[1]):void 0,message:r},n)}function ke(t,e){let n=new URLSearchParams;for(let[i,s]of Object.entries(e))s!==void 0&&s!==""&&n.set(i,s);let r=n.toString();return r?`${t}?${r}`:t}function h(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}function L(t){return Buffer.from(t,"utf8").toString("base64")}function Ut(...t){for(let e of t)if(typeof e=="string"&&e.trim())return e.trim()}var Oe=l.enum(["asc","desc"]),Xr=l.enum(["EQ","NE","IN","NIN","LIKE","GT","GTE","LT","LTE","BT"]),Vt=l.object({field:l.string().min(1).describe("\u7B5B\u9009\u5B57\u6BB5\u540D\u79F0\u6216\u5B57\u6BB5 ID\u3002"),operator:Xr.describe("\u7B5B\u9009\u64CD\u4F5C\u7B26\u3002BT \u9700\u8981\u4F20\u4E24\u4E2A\u503C\u3002"),values:l.array(l.union([l.string(),l.number(),l.boolean()])).min(1).describe("\u7B5B\u9009\u503C\u3002"),fd_id:l.string().min(1).optional().describe("\u5DF2\u77E5\u5B57\u6BB5 ID \u65F6\u53EF\u76F4\u63A5\u6307\u5B9A\u3002")}),Zr=l.object({field:l.string().min(1).describe("\u6392\u5E8F\u5B57\u6BB5\u540D\u79F0\u6216\u5B57\u6BB5 ID\u3002"),direction:Oe.describe("\u6392\u5E8F\u65B9\u5411\u3002")}),ei=l.object({type:l.enum(["compare","xtd","last","recent","percentage","rank_top"]),compare:l.enum(["yoy","mom","qoq","wow","dod"]).optional(),compare_value:l.enum(["value","rate","rawdata"]).optional(),xtd:l.enum(["ytd","qtd","mtd","wtd","dtd"]).optional(),recent:l.string().regex(/^[1-9]\d*[dwmqy]$/).optional(),recent_base:l.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),percentage_dim:l.string().min(1).optional(),rank_top:l.number().int().positive().optional(),rank_order:Oe.optional(),rank_dim:l.string().min(1).optional()}),zt={keyword:l.string().min(1).optional().describe("\u6307\u6807\u540D\u79F0\u5173\u952E\u8BCD\u3002"),project_id:l.string().min(1).optional().describe("\u6307\u6807\u4E3B\u9898 ID\uFF1B\u4E0D\u4F20\u5219\u8DE8\u53EF\u8BBF\u95EE\u4E3B\u9898\u641C\u7D22\u3002"),dir_id:l.string().min(1).optional().describe("\u76EE\u5F55 ID\u3002"),status:l.string().min(1).optional().describe("\u4E0A\u7EBF\u72B6\u6001\u3002"),sub_types:l.array(l.string().min(1)).optional().describe("\u6307\u6807\u7C7B\u578B\u5217\u8868\u3002"),order_by:l.enum(["utimeDesc","utimeAsc"]).optional().describe("\u6392\u5E8F\u65B9\u5F0F\u3002"),limit:l.number().int().positive().max(200).optional().default(20).describe("\u6700\u591A\u8FD4\u56DE\u6761\u6570\u3002")},Ft={project_id:l.string().min(1).optional().describe("\u6307\u6807\u4E3B\u9898 ID\u3002"),keyword:l.string().min(1).optional().describe("\u540D\u79F0\u5173\u952E\u8BCD\uFF0C\u53EF\u5339\u914D\u4E3B\u9898\u3001\u76EE\u5F55\u6216\u6307\u6807\u3002"),raw:l.boolean().optional().describe("\u662F\u5426\u8FD4\u56DE\u539F\u59CB\u54CD\u5E94\u3002")},Qt={metric_id:l.string().min(1).describe("\u6307\u6807 ID\u3002"),brief:l.boolean().optional().describe("\u662F\u5426\u53EA\u8FD4\u56DE\u8BE6\u60C5\uFF0C\u4E0D\u8865\u5145\u8840\u7F18\u3002"),raw:l.boolean().optional().describe("\u662F\u5426\u8FD4\u56DE\u539F\u59CB\u8BE6\u60C5\u3002")},Wt={metric_id:l.string().min(1).describe("\u6307\u6807 ID\u3002"),dimensions:l.array(l.string().min(1)).optional().describe("\u6309\u540D\u79F0\u6216\u5B57\u6BB5 ID \u6307\u5B9A\u67E5\u8BE2\u7EF4\u5EA6\u3002"),filters:l.array(Vt).optional().describe("\u7B5B\u9009\u6761\u4EF6\u3002"),combine_type:l.enum(["AND","OR"]).optional().default("AND").describe("\u591A\u4E2A\u7B5B\u9009\u6761\u4EF6\u7684\u7EC4\u5408\u65B9\u5F0F\u3002"),sort:l.array(Zr).optional().describe("\u6392\u5E8F\u5B57\u6BB5\u3002"),columns:l.array(l.string().min(1)).optional().describe("\u7ED3\u679C\u5217\u88C1\u526A\u3002"),limit:l.number().int().positive().max(1e3).optional().default(100).describe("\u6700\u591A\u8FD4\u56DE\u884C\u6570\u3002"),advanced_calc:ei.optional().describe("\u9AD8\u7EA7\u8BA1\u7B97\uFF0C\u53EA\u4F7F\u7528\u6307\u6807\u6570\u636E\u67E5\u8BE2\u63A5\u53E3\u8868\u8FBE\u3002"),raw:l.boolean().optional().describe("\u662F\u5426\u8FD4\u56DE\u539F\u59CB\u54CD\u5E94\u3002")},Kt={keyword:l.string().min(1).optional().describe("\u6307\u6807\u6811\u540D\u79F0\u5173\u952E\u8BCD\u3002"),project_id:l.string().min(1).optional().describe("\u6839\u6307\u6807\u6240\u5C5E\u4E3B\u9898 ID\u3002"),parent_dir_id:l.string().min(1).optional().describe("\u6307\u6807\u6811\u76EE\u5F55 ID\u3002"),order_by:l.enum(["utimeDesc","utimeAsc"]).optional().default("utimeDesc").describe("\u6392\u5E8F\u65B9\u5F0F\u3002"),limit:l.number().int().positive().max(200).optional().default(20).describe("\u6700\u591A\u8FD4\u56DE\u6761\u6570\u3002")},Yt={metric_tree_id:l.string().min(1).describe("\u6307\u6807\u6811 ID\u3002"),raw:l.boolean().optional().describe("\u662F\u5426\u8FD4\u56DE\u539F\u59CB\u8BE6\u60C5\u3002")},Xt={metric_tree_id:l.string().min(1).describe("\u6307\u6807\u6811 ID\u3002"),target:l.enum(["metric","dimension","scan"]).describe("\u5F52\u56E0\u7C7B\u578B\uFF1A\u6307\u6807\u62C6\u89E3\u3001\u5355\u7EF4\u62C6\u89E3\u6216\u5168\u7EF4\u626B\u63CF\u3002"),dimension:l.string().min(1).optional().describe("target=dimension \u65F6\u6309\u7EF4\u5EA6\u540D\u79F0\u6307\u5B9A\u3002"),dimension_fd_id:l.string().min(1).optional().describe("target=dimension \u65F6\u6309\u5B57\u6BB5 ID \u6307\u5B9A\u3002"),scan_dimensions:l.array(l.string().min(1)).optional().describe("target=scan \u65F6\u6307\u5B9A\u626B\u63CF\u7EF4\u5EA6\u540D\u79F0\u3002"),exclude_dimensions:l.array(l.string().min(1)).optional().describe("target=scan \u65F6\u6392\u9664\u7EF4\u5EA6\u540D\u79F0\u3002"),period:l.string().min(1).optional().describe("\u5F53\u524D\u671F\uFF0C\u914D\u5408 last_period \u8986\u76D6\u9ED8\u8BA4\u65F6\u95F4\u5BF9\u6BD4\u3002"),last_period:l.string().min(1).optional().describe("\u5BF9\u6BD4\u671F\uFF0C\u914D\u5408 period \u8986\u76D6\u9ED8\u8BA4\u65F6\u95F4\u5BF9\u6BD4\u3002"),time_comparison_json:l.record(l.string(),l.unknown()).optional().describe("\u5B8C\u6574\u65F6\u95F4\u5BF9\u6BD4\u914D\u7F6E\u8986\u76D6\u3002"),filters:l.array(Vt).optional().describe("\u5F52\u56E0\u7B5B\u9009\u6761\u4EF6\u3002"),limit:l.number().int().positive().max(200).optional().default(20).describe("metric/dimension \u8FD4\u56DE\u884C\u6570\u3002"),group_limit:l.number().int().positive().max(50).optional().default(5).describe("scan \u6BCF\u4E2A\u7EF4\u5EA6\u8FD4\u56DE\u884C\u6570\u3002"),sort:Oe.optional().default("desc").describe("\u6309\u8D21\u732E\u503C\u6392\u5E8F\u65B9\u5411\u3002"),raw:l.boolean().optional().describe("\u662F\u5426\u8FD4\u56DE\u539F\u59CB\u54CD\u5E94\u3002")},M={summary:l.unknown().optional(),items:l.array(l.unknown()).optional(),tree:l.unknown().optional(),detail:l.unknown().optional(),columns:l.array(l.unknown()).optional(),rows:l.array(l.unknown()).optional(),raw:l.unknown().optional(),diagnostic:l.unknown().optional(),status:l.string().optional()};async function Zt(t,e,n){let r=new E(t,e);try{let i=n.project_id?[n.project_id]:await ti(r),s=[];for(let a of i){let c=await r.searchMetrics({projectId:a,dirId:n.dir_id,keyword:n.keyword,status:n.status,subTypes:n.sub_types,orderBy:n.order_by});if(s.push(...ni(c)),s.length>=n.limit)break}let o=Ri(s.map(ve),"metric_id").slice(0,n.limit);return y({summary:{keyword:n.keyword,project_id:n.project_id,count:o.length,searched_project_count:i.length,truncated:o.length<s.length},items:o})}catch(i){return N(i,"search_metrics")}}async function en(t,e,n){let r=new E(t,e);try{try{let i=await r.listMetricFullTree({projectId:n.project_id,keyword:n.keyword});return y({summary:{source:"full-tree"},tree:ii(i),raw:n.raw?i:void 0})}catch(i){let s=n.project_id?[{id:n.project_id}]:await an(r),o=[];for(let a of s){let c=u(a.id);if(!c)continue;let d=await r.listMetricDirectoryTree(c);o.push({id:c,name:u(a.name)||c,type:"project",project_id:c,children:si(d,c)})}return y({summary:{source:"directory-fallback",fallback_reason:i instanceof Error?i.message:String(i)},tree:o})}}catch(i){return N(i,"list_metric_catalog")}}async function tn(t,e,n){let r=new E(t,e);try{let i=await r.getMetricDetail(n.metric_id),s=oi(i),o,a;if(!n.brief){let c=u(i.uniformResourceType)||"METRIC_PLATFORM_METRIC";try{o=ai(await r.getMetricLineage(n.metric_id,c))}catch(d){a=d instanceof D?d.detail:String(d)}}return y({detail:{...s,lineage:o,lineage_error:a},raw:n.raw?i:void 0})}catch(i){return N(i,"get_metric_detail")}}async function nn(t,e,n){let r=new E(t,e);try{let i=await r.getMetricDetail(n.metric_id);if(!n.advanced_calc){let a=Lt(i,n);if("unsupported"in a)return O("query_metric_data",a.unsupported);let c=async f=>{let C=await r.getCardEditSession(a.cardId),_=u(C.sessionId);if(!_)throw new Error("\u6307\u6807\u5361\u7247\u9884\u89C8\u4F1A\u8BDD\u54CD\u5E94\u7F3A\u5C11 sessionId\u3002");return a.dimensions.length&&await ci(r,a.cardId,_,a.dimensions),{raw:await r.queryCardEditData(a.cardId,_,f),sessionId:_}};if(n.combine_type==="OR"&&(n.filters?.length??0)>1){let f=[],C=[];for(let _ of n.filters??[]){let T=Lt(i,{...n,combine_type:"AND",filters:[_]});if("unsupported"in T)return O("query_metric_data",T.unsupported);let{raw:k}=await c(T.body);C.push(k),f.push(...qt(k))}return ae(i,f,n,{mode:"metric_card_preview_data",card_id:a.cardId,card_kind:a.cardKind,combine_type:"OR",query_count:C.length},n.raw?C:void 0)}let{raw:d,sessionId:m}=await c(a.body);return ae(i,qt(d),n,{mode:"metric_card_preview_data",card_id:a.cardId,card_kind:a.cardKind,session_id:m,request_body:a.body},n.raw?d:void 0)}let s=Nt(i,n);if("unsupported"in s)return O("query_metric_data",s.unsupported);if(n.combine_type==="OR"&&(n.filters?.length??0)>1){let a=[],c=[];for(let d of n.filters??[]){let m=Nt(i,{...n,combine_type:"AND",filters:[d]});if("unsupported"in m)return O("query_metric_data",m.unsupported);let f=await r.queryMetricData(m.input);c.push(f),a.push(...V(f))}return ae(i,a,n,{mode:"metric_data_v2",combine_type:"OR",query_count:c.length},n.raw?c:void 0)}let o=await r.queryMetricData(s.input);return ae(i,V(o),n,{mode:"metric_data_v2",request_body:s.input},n.raw?o:void 0)}catch(i){return ki(i)?O("query_metric_data",{capability:"metric_data_v2_unavailable",message:"\u5F53\u524D BI \u73AF\u5883\u672A\u63D0\u4F9B /api/metric-platform/metric-data/v2\uFF0C\u65E0\u6CD5\u6267\u884C\u9AD8\u7EA7\u8BA1\u7B97\u67E5\u8BE2\u3002",diagnostic:i.detail}):N(i,"query_metric_data")}}async function rn(t,e,n){let r=new E(t,e);try{let i=await r.searchMetricTrees({keyword:n.keyword,projectId:n.project_id,parentDirId:n.parent_dir_id,orderBy:n.order_by}),s=ri(i).map(ln).slice(0,n.limit);return y({summary:{keyword:n.keyword,count:s.length},items:s})}catch(i){return N(i,"search_metric_trees")}}async function sn(t,e,n){let r=new E(t,e);try{let i=await r.getMetricTreeDetail(n.metric_tree_id);return y({detail:fi(i),raw:n.raw?i:void 0})}catch(i){return N(i,"get_metric_tree_detail")}}async function on(t,e,n){let r=new E(t,e);try{if(n.target==="dimension"&&!n.dimension&&!n.dimension_fd_id)return O("query_metric_tree_attribution",{capability:"dimension_attribution_requires_dimension",message:"target=dimension \u65F6\u5FC5\u987B\u6307\u5B9A dimension \u6216 dimension_fd_id\u3002"});let i=await r.getMetricTreeDetail(n.metric_tree_id),s=u(i.metricId);if(!s)return O("query_metric_tree_attribution",{capability:"missing_root_metric",message:"\u6307\u6807\u6811\u8BE6\u60C5\u7F3A\u5C11\u6839\u6307\u6807 ID\uFF0C\u65E0\u6CD5\u6267\u884C\u5F52\u56E0\u3002"});let o=await r.getMetricDetail(s),a=z(o),c=xe(n.filters??[],a),d=gi(i,n);if("unsupported"in d)return O("query_metric_tree_attribution",d.unsupported);if(n.target==="metric"){let _=hi(i,d.value,c),T=await r.queryMetricTreeDecompose(n.metric_tree_id,_);return Re(i,"metric",_i(T),n,n.raw?T:void 0)}if(n.target==="dimension"){let _=U(a,n.dimension,n.dimension_fd_id);if(!_)return O("query_metric_tree_attribution",{capability:"unknown_dimension",message:`\u7EF4\u5EA6\u4E0D\u5B58\u5728\u6216\u4E0D\u9002\u7528\u4E8E\u6839\u6307\u6807\uFF1A${n.dimension??n.dimension_fd_id}`});let T=Jt(i,_,d.value,c,n.limit,n.sort),k=await r.queryMetricTreeDrill(n.metric_tree_id,T);return Re(i,"dimension",Ht(k,u(_.name)),n,n.raw?k:void 0)}let m=bi(i,a,n.scan_dimensions,n.exclude_dimensions);if(!m.length)return O("query_metric_tree_attribution",{capability:"no_scan_dimensions",message:"\u6CA1\u6709\u53EF\u626B\u63CF\u7EF4\u5EA6\uFF0C\u8BF7\u6307\u5B9A scan_dimensions \u6216\u68C0\u67E5\u6307\u6807\u6811\u7EF4\u5EA6\u62C6\u89E3\u914D\u7F6E\u3002"});let f=[],C=[];for(let _ of m){let T=Jt(i,_,d.value,c,n.group_limit,n.sort),k=await r.queryMetricTreeDrill(n.metric_tree_id,T);C.push({dimension:u(_.name),raw:k}),f.push(...Ht(k,u(_.name)).slice(0,n.group_limit))}return Re(i,"scan",f,n,n.raw?C:void 0,{scanned_dimensions:m.map(_=>u(_.name))})}catch(i){return N(i,"query_metric_tree_attribution")}}async function ti(t){return(await an(t)).map(e=>u(e.id)).filter(Boolean)}async function an(t){return I(await t.listProjects()).map(g).filter(Boolean)}function ni(t){let e=g(t);return I(e.contents??e.items??e.data)}function ri(t){let e=g(t);return I(e.data??e.contents??e.items)}function ve(t){return h({metric_id:u(t.id),name:u(t.name),project_id:u(t.projectId),dir_id:b(t.parentDirId,t.dirId),status:u(t.status),sub_type:u(t.subType),description:u(t.desc),dataset:mn(t.dsInfo),statistics:t.statisticsData,creator:ue(t.creator),business_owner:ue(t.businessOwner),updated_at:u(t.utime),raw:t})}function ii(t){return I(t).map(e=>cn(e,void 0))}function cn(t,e){let n=!!t.isMetric,r=u(t.id),i=!e&&!n?r:e;return h({id:r,name:u(t.name),type:n?"metric":e?"directory":"project",project_id:i,dir_id:!n&&e?r:void 0,metric_id:n?r:void 0,parent_id:u(t.parentId),children:I(t.children).map(s=>cn(s,i))})}function si(t,e){let n=g(t);return u(n.id)?[Ae(n,e)]:I(n.contents??n.children).map(r=>Ae(r,e))}function Ae(t,e){return h({id:u(t.id),name:u(t.name),type:"directory",project_id:e,dir_id:u(t.id),parent_id:b(t.parentDirId,t.parentId),can_use:S(t.canUse),can_manage:S(t.canManage),metric_count:$t(t.metricCnt),all_metric_count:$t(t.allMetricCnt),children:I(t.contents??t.children).map(n=>Ae(n,e))})}function oi(t){return h({metric_id:u(t.id),name:u(t.name),english_name:u(t.engName),status:u(t.status),sub_type:u(t.subType),description:u(t.desc),project_id:u(t.projectId),project_name:u(t.projectName),dir_id:b(t.parentDirId,t.dirId),dir_path:fn(t.dirPath),dataset:mn(t.dsInfo),source_fields:I(t.fdInfos).map(ce),aggregation:b(t.aggrType,t.aggregationType),formula:b(t.formula,t.expression),derive_setting:t.deriveSetting,format:t.format,applicable_dimensions:z(t),time_dimension:g(t.timeDim)?ce(g(t.timeDim)):void 0,business_attributes:I(t.bizAttrs).map(Si),business_owner:ue(t.businessOwner),creator:ue(t.creator),referenced_metrics:I(t.referencedMetrics).map(ve),base_metric:g(t.baseMetric)?ve(g(t.baseMetric)):void 0,linked_metric_id:u(t.linkMetricId),statistics:t.statisticsData,permissions:h({can_use:S(t.canUse),can_manage:S(t.canManage)}),created_at:u(t.ctime),updated_at:u(t.utime),has_draft:S(t.hasDraft)})}function ai(t){let e=g(t);return h({current:e.crtNode,upstream:e.backwardAtlas,downstream:e.forwardAtlas})}function Nt(t,e){let n=u(t.name),r=u(t.projectId);if(!n||!r)return{unsupported:{capability:"metric_detail_incomplete",message:"\u6307\u6807\u8BE6\u60C5\u7F3A\u5C11 name \u6216 projectId\u3002"}};let i=z(t),s=[];for(let a of e.dimensions??[]){let c=U(i,a);if(!c)return{unsupported:{capability:"unsupported_dimension",parameter:a,supported_dimensions:i}};s.push(yi(c))}let o=di(t,i,e.advanced_calc);return"unsupported"in o?{unsupported:o.unsupported}:{input:{projectId:r,metricId:e.metric_id,metricName:n,metricItems:[h({name:n,alias:li(n,e.advanced_calc),advCalc:o.value})],dimensions:s,filters:xe(e.filters??[],i),sorting:un(e.sort??[],t,i),limit:e.limit}}}function Lt(t,e){let n=g(t.metricChartConfig),r=u(n.metricChartCdId),i=u(n.metricValueCdId),s=r||i;if(!s)return{unsupported:{capability:"missing_metric_card",message:"\u6307\u6807\u8BE6\u60C5\u7F3A\u5C11 metricChartConfig.metricChartCdId \u6216 metricValueCdId\uFF0C\u65E0\u6CD5\u8D70\u53EA\u8BFB\u5361\u7247\u53D6\u6570\u3002"}};let o=[...z(t),...Ii(t)],a=[];for(let m of e.dimensions??[]){let f=U(o,m);if(!f||u(f.meta_type).toUpperCase()==="METRIC")return{unsupported:{capability:"unsupported_dimension",parameter:m,supported_dimensions:z(t)}};a.push(Ti(f))}let c=xe(e.filters??[],o),d=un(e.sort??[],t,o);return{cardId:s,cardKind:r?"chart":"value",dimensions:a,body:h({limit:e.limit,filters:c.length?c:void 0,combineType:e.filters?.length?e.combine_type:void 0,sorting:d.length?d:void 0})}}async function ci(t,e,n,r){let i=gn(await t.getCardEditMeta(e))??{},s=ui(i);s.row=r,s.sorting=[],await t.modifyCardEditMeta(e,n,i)}function ui(t){let e=g(t.content),n=g(e.meta),r=g(n.chartMain),i=g(r.zoneData);if(!Object.keys(i).length)throw new Error("\u6307\u6807\u5361\u7247\u7F16\u8F91\u914D\u7F6E\u7F3A\u5C11 content.meta.chartMain.zoneData\u3002");return e.meta=n,n.chartMain=r,r.zoneData=i,t.content=e,i}function di(t,e,n){if(!n)return{value:void 0};let r=g(t.timeDim),i=u(r?.fdId);if(["compare","last"].includes(n.type)&&!i)return{unsupported:{capability:"advanced_calc_requires_time_dimension",parameter:n.type}};if(n.type==="compare"){let a=n.compare??"yoy",c={yoy:["YEAR","YEAR"],mom:["MONTH","MONTH"],qoq:["QUARTER","QUARTER"],wow:["WEEK","WEEK"],dod:["DAY","DAY"]},[d,m]=c[a];return{value:{advType:"COMPARATIVE",advValue:{advType:"COMPARATIVE",dateFdId:i,valueType:(n.compare_value??"value").toUpperCase(),offset:1,offsetType:d,granularity:m}}}}if(n.type==="xtd")return{value:{advType:"XTD",advValue:{advType:"XTD",granularity:{ytd:"YEAR",qtd:"QUARTER",mtd:"MONTH",wtd:"WEEK",dtd:"DAY"}[n.xtd??"ytd"],includeCurrentValue:!0}}};if(n.type==="last")return{value:{advType:"LAST",advValue:{advType:"LAST",dateFdId:i}}};if(n.type==="recent"){let a=pi(n.recent??"7d");return a?{value:{advType:"RECENT_X",advValue:{advType:"RECENT_X",granularity:a.granularity,baselineOffset:[a.count-1,0],includeCurrentValue:!0,baseline:n.recent_base}}}:{unsupported:{capability:"invalid_recent_spec",parameter:n.recent}}}if(n.type==="percentage"){let a=n.percentage_dim?U(e,n.percentage_dim):void 0;return n.percentage_dim&&!a?{unsupported:{capability:"unknown_percentage_dimension",parameter:n.percentage_dim}}:{value:{advType:"LEVEL_PERCENTAGE",advValue:h({advType:"LEVEL_PERCENTAGE",auto:!a,tfdId:u(a?.fd_id)})}}}let o=n.rank_dim?U(e,n.rank_dim):void 0;return n.rank_dim&&!o?{unsupported:{capability:"unknown_rank_dimension",parameter:n.rank_dim}}:{value:{advType:"RANK",advValue:h({advType:"RANK",calDimension:"FIELD",rankType:"RANK",sorting:(n.rank_order??"desc").toUpperCase(),tfdId:u(o?.fd_id),topN:{topType:"CUSTOM_NUMBER",count:n.rank_top??10,calculationType:"COUNT"}})}}}function li(t,e){return e?e.type==="compare"?`${t}_${e.compare??"yoy"}`:e.type==="xtd"?`${t}_${e.xtd??"ytd"}`:e.type==="recent"?`${t}_recent_${e.recent??"7d"}`:`${t}_${e.type}`:t}function pi(t){let e=t.match(/^([1-9]\d*)([dwmqy])$/);if(!e)return;let n={d:"DAY",w:"WEEK",m:"MONTH",q:"QUARTER",y:"YEAR"};return{count:Number(e[1]),granularity:n[e[2]]}}function xe(t,e){return t.map(n=>{let r=U(e,n.field,n.fd_id),i=u(r?.meta_type).toUpperCase();return h({name:r?.name??n.field,fdId:n.fd_id??u(r?.fd_id)??n.field,fdType:u(r?.fd_type),metaType:i||"DIM",filterType:n.operator,filterValue:n.values})})}function un(t,e,n){return t.map(r=>{let i=U(n,r.field),s=u(i?.meta_type).toUpperCase();return h({name:i?.name??(r.field===u(e.name)?u(e.name):r.field),ordering:r.direction,key:u(i?.fd_id)||u(i?.id)||r.field,fdId:u(i?.fd_id),fdType:u(i?.fd_type),metaType:s||(i?"DIM":"METRIC")})})}function ae(t,e,n,r,i){let s=Ci(e.slice(0,n.limit),n.columns);return y({summary:{metric_id:n.metric_id,metric_name:u(t.name),row_count:s.length,truncated:e.length>s.length},columns:pn(s),rows:s,diagnostic:r,raw:i})}function V(t){let e=g(t),n=g(e.data)??e,r=I(n.values??n.rows??e.values??e.rows);if(r.length)return r;let i=I(n.columns??e.columns).map(o=>u(g(o)?.name??o)).filter(Boolean),s=I(n.preview??n.contents);return i.length?s.map(o=>{let a=Array.isArray(o)?o:[];return Object.fromEntries(i.map((c,d)=>[c,a[d]]))}):s}function qt(t){let e=g(t),n=g(e.data)??e,r=g(n.chartMain??e.chartMain??g(g(e.content).data).chartMain);if(!Object.keys(r).length)return V(t);let i=g(r.row),s=g(r.column),o=I(i.fields),a=j(i.data),c=j(r.data),d=mi(s),m=o.map(Ee).filter(Boolean),f=wi([...m,...d]),C=Math.max(a.length,c.length),_=[];for(let T=0;T<C;T+=1){let k=[];k.push(...j(a[T]).map(Gt)),k.push(...j(c[T]).map(Gt)),k.length&&_.push(Object.fromEntries(k.map((yn,Le)=>[f[Le]??`column_${Le+1}`,yn])))}return _}function mi(t){let n=j(t.data).map((r,i)=>{let s=j(r).map(dn).filter(Boolean).join("/");return s||Ee(I(t.fields)[i])||`metric_${i+1}`}).filter(Boolean);return n.length?n:I(t.fields).map(Ee).filter(Boolean)}function Ee(t){return b(t.alias,t.title,t.originTitle,t.name,t.fdId,t.id)??""}function dn(t){let e=g(t);return Object.keys(e).length?b(e.title,e.name,e.originTitle,e.alias,e.v,e.value)??"":u(t)}function Gt(t){let e=g(t);return Object.keys(e).length?"v"in e?e.v:"value"in e?e.value:dn(t):t}function ln(t){return h({metric_tree_id:u(t.metricTreeId),name:u(t.metricTreeName),root_metric_id:u(t.metricId),root_metric_name:u(t.metricName),project_id:u(t.projectId),project_name:u(t.projectName),parent_dir_id:u(t.parentDirId),dir_path:fn(t.dirPath),creator_id:u(t.creatorId),creator_name:u(t.creatorName),can_use:S(t.canUse),can_manage:S(t.canManage),updated_at:u(t.utime)})}function fi(t){let e=g(t.config)??{};return h({...ln(t),dom_id:u(t.domId),created_at:u(t.ctime),time_comparison:e.timeComparisonSetting,comparison_enabled:S(e.comparisonEnabled),contribution_calc_enabled:S(e.contributionCalcEnabled),dimension_decomposition:e.dimensionDecompositionContent,metric_decomposition:e.metricDecompositionContent,permissions:h({can_use:S(t.canUse),can_manage:S(t.canManage)})})}function gi(t,e){let n=g(t.config)??{},r=e.time_comparison_json??gn(g(n.timeComparisonSetting)),i=S(n.comparisonEnabled)??!!r,s=S(n.contributionCalcEnabled)??!1;if(e.period||e.last_period){if(!e.period||!e.last_period)return{unsupported:{capability:"period_requires_last_period",message:"period \u548C last_period \u9700\u8981\u540C\u65F6\u6307\u5B9A\u3002"}};r=r??{};let o=g(r.advValue)??{};r.advValue=o,o.window={period:[e.period],withMacro:!1};let a=Bi(e.period,e.last_period);if(!a)return{unsupported:{capability:"unsupported_period_granularity",message:"\u76EE\u524D\u4EC5\u652F\u6301 YYYY-MM-DD \u683C\u5F0F\u7684 period/last_period\u3002"}};Object.assign(o,a,{mode:"NORMAL"}),r.advType="COMPARATIVE",i=!0}return{value:{setting:r,comparisonEnabled:i,contributionEnabled:s}}}function hi(t,e,n){let r=g(t.config)??{},i=g(r.metricDecompositionContent)??{};return h({timeComparisonSetting:e.setting,comparisonEnabled:e.comparisonEnabled,contributionCalcEnabled:!1,metricDecomposeInfo:{metricRelationTree:i.metricRelationTree,filters:n}})}function Jt(t,e,n,r,i,s){return h({timeComparisonSetting:n.setting,comparisonEnabled:n.comparisonEnabled,contributionCalcEnabled:n.contributionEnabled,drillInfo:{dimensionFdId:u(e.fd_id),drillFilters:r,nodeNum:i,orderBy:s==="asc"?"contributionAsc":"contributionDesc"}})}function _i(t){return V(t).map(e=>h({child_metric:u(g(e.metricInfo)?.name),child_metric_id:u(g(e.metricInfo)?.metricId),current_value:e.currentValue,comparison_value:e.comparisonValue,change_value:e.changeValue,change_rate:e.changeRate,contribution_value:e.contributionValue,contribution_rate:e.contributionRate}))}function Ht(t,e){return V(t).map((n,r)=>h({dimension:e,dimension_value:Array.isArray(n.dimensionValue)?n.dimensionValue.join("/"):n.dimensionValue,current_value:n.currentValue,comparison_value:n.comparisonValue,change_value:n.changeValue,change_rate:n.changeRate,contribution_value:n.contributionValue,contribution_rate:n.contributionRate,rank:r+1}))}function Re(t,e,n,r,i,s){let o=e==="scan"?n:n.slice(0,r.limit);return y({summary:{metric_tree_id:r.metric_tree_id,metric_tree_name:u(t.metricTreeName),root_metric_id:u(t.metricId),root_metric_name:u(t.metricName),target:e,row_count:o.length,...s},columns:pn(o),rows:o,raw:i})}function bi(t,e,n,r){let i=new Set((n??[]).map(d=>d.trim()).filter(Boolean)),s=new Set((r??[]).map(d=>d.trim()).filter(Boolean)),o=new Map(e.map(d=>[u(d.name),d])),a=new Map(e.map(d=>[u(d.fd_id),d])),c=i.size?[...i].map(d=>o.get(d)).filter(d=>!!d):[];if(!c.length){let d=g(t.config)??{},m=g(d.dimensionDecompositionContent)??{};c=j(m.decomposableDimensionIds).map(f=>a.get(String(f))).filter(f=>!!f)}return c.length||(c=e),c.filter(d=>!s.has(u(d.name)))}function z(t){let e=new Set,n=[],r=i=>{if(!i)return;let s=u(i.fdId),o=u(i.name),a=s||o;if(!(!a||e.has(a))){e.add(a),n.push(ce(i));for(let c of I(i.subs))r(c)}};for(let i of I(t.applicableDims))r(i);return r(g(t.timeDim)),n}function Ii(t){let e=I(t.fdInfos).map(ce);return!e.length&&u(t.name)&&e.push(h({id:b(t.id,t.name),fd_id:u(t.id),name:u(t.name),fd_type:"DOUBLE",meta_type:"METRIC"})),e}function ce(t){return h({id:b(t.id,t.fdId),fd_id:u(t.fdId),name:u(t.name),fd_type:u(t.fdType),meta_type:u(t.metaType),ds_id:u(t.dsId),granularity:u(t.granularity)})}function U(t,e,n){let r=(n??e)?.trim();if(r)return t.find(i=>[i.fd_id,i.id,i.name].map(u).includes(r))}function yi(t){return h({name:u(t.name),alias:u(t.name),fdType:b(t.fd_type),metaType:"DIM",key:b(t.fd_id,t.id,t.name),fdId:b(t.fd_id),dsId:b(t.ds_id),granularity:b(t.granularity)})}function Ti(t){return h({name:u(t.name),alias:b(t.name),fdType:b(t.fd_type),metaType:"DIM",key:b(t.fd_id,t.id,t.name),fdId:b(t.fd_id),dsId:b(t.ds_id),granularity:b(t.granularity)})}function Ci(t,e){return e?.length?t.map(n=>Object.fromEntries(e.map(r=>[r,n[r]]))):t}function pn(t){return[...new Set(t.flatMap(e=>Object.keys(e)))]}function wi(t){let e=new Map;return t.map((n,r)=>{let i=n||`column_${r+1}`,s=e.get(i)??0;return e.set(i,s+1),s?`${i}_${s+1}`:i})}function Bi(t,e){let n=Date.parse(t),r=Date.parse(e);if(!/^\d{4}-\d{2}-\d{2}$/.test(t)||!/^\d{4}-\d{2}-\d{2}$/.test(e)||Number.isNaN(n)||Number.isNaN(r))return;let i=Math.round((n-r)/864e5);if(!(i<=0))return{offset:i,offsetType:"DAY",granularity:"DAY"}}function mn(t){let e=g(t);if(e)return h({dataset_id:u(e.dsId),name:u(e.name)})}function ue(t){let e=g(t);if(e)return h({user_id:b(e.uId,e.id),name:u(e.name),deleted:S(e.isDel)})}function Si(t){return h({id:u(t.id),name:u(t.name),type:u(t.valueType),values:I(t.values)})}function fn(t){return I(t).map(e=>u(e.dirName??e.name)).filter(Boolean)}function O(t,e){return y({status:"unsupported",diagnostic:{tool:t,...e}})}function N(t,e){return t instanceof D?$({operation:e,diagnostic:t.detail}):$({operation:e,message:t instanceof Error?t.message:String(t)})}function ki(t){return t instanceof D&&t.detail.operation==="queryMetricData"&&t.detail.path==="/api/metric-platform/metric-data/v2"&&/No static resource metric-platform\/metric-data\/v2/i.test(t.detail.message)}function I(t){return Array.isArray(t)?t.map(g).filter(Boolean):[]}function j(t){return Array.isArray(t)?t:[]}function g(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function u(t){return typeof t=="string"?t:t==null?"":String(t)}function b(...t){return t.map(u).find(e=>e.trim())?.trim()}function S(t){return typeof t=="boolean"?t:void 0}function $t(t){return typeof t=="number"&&Number.isFinite(t)?t:void 0}function Ri(t,e){let n=new Set;return t.filter(r=>{let i=u(r[e]);return!i||n.has(i)?!1:(n.add(i),!0)})}function gn(t){return t?JSON.parse(JSON.stringify(t)):void 0}function hn(t,e,n,r,i={}){let s=i.usageTelemetry??new te({config:n,appVersion:i.appVersion??"unknown"}),o=(c,d,m)=>{t.registerTool.call(t,c,d,rt(c,m,s))},a=c=>!r.service||r.service.toolList.includes(c);o("get_bi_capabilities",{title:"Get BI Capabilities",description:"\u83B7\u53D6\u5F53\u524D BI \u73AF\u5883\u7248\u672C\u548C MCP \u529F\u80FD\u542F\u7528\u72B6\u6001\u3002",inputSchema:st},(c,d)=>e.run(({client:m,config:f})=>ot(m,f),d,"get_bi_capabilities")),["chatbi_list_themes","chatbi_query","chatbi_insight_start","chatbi_insight_poll"].some(a)&&(o("chatbi_list_themes",{title:"List ChatBI Themes",description:"\u5217\u51FA\u5F53\u524D\u767B\u5F55\u7528\u6237\u53EF\u8BBF\u95EE\u7684 ChatBI \u4E3B\u9898\uFF0C\u53EF\u7B5B\u9009\u6D1E\u5BDF\u4E3B\u9898\u3002",inputSchema:ft,outputSchema:dt},(c,d)=>e.run(({config:m})=>bt(m,c),d,"chatbi_list_themes")),o("chatbi_query",{title:"ChatBI Query",description:"\u6267\u884C ChatBI L1 \u540C\u6B65\u95EE\u6570\uFF0C\u652F\u6301\u4E3B\u9898 ID \u6216\u4E3B\u9898\u540D\u3002\u6210\u529F\u7ED3\u679C\u76F4\u63A5\u900F\u51FA answer\u3001sql\u3001query_result \u7B49\u7ED3\u6784\u5316\u5B57\u6BB5\uFF0C\u7531\u8C03\u7528\u65B9\u81EA\u884C\u7EC4\u7EC7\u6700\u7EC8\u56DE\u590D\u3002session_id \u53EA\u80FD\u7528\u4E8E\u95EE\u6570\u7EED\u95EE\uFF0C\u4E0D\u80FD\u4E0E ChatBI \u6D1E\u5BDF\u4F1A\u8BDD\u6DF7\u7528\u3002",inputSchema:gt,outputSchema:lt},(c,d)=>e.run(({config:m})=>It(m,c),d,"chatbi_query")),o("chatbi_insight_start",{title:"Start ChatBI Insight",description:"\u53D1\u8D77 ChatBI L2 \u6D1E\u5BDF\u5206\u6790\u5E76\u5728\u8BF7\u6C42\u53D7\u7406\u540E\u7ACB\u5373\u8FD4\u56DE message_id\uFF0C\u4E0D\u7B49\u5F85\u6700\u7EC8\u62A5\u544A\uFF0C\u4E5F\u4E0D\u8FD4\u56DE final_result\u3002\u6D1E\u5BDF\u901A\u5E38\u8017\u65F6 2-3 \u5206\u949F\uFF0C5 \u5206\u949F\u89C6\u4E3A\u8D85\u65F6\uFF1B\u540C\u4E00\u95EE\u9898\u53EA\u8C03\u7528\u4E00\u6B21\uFF0C\u540E\u7EED\u4F7F\u7528 chatbi_insight_poll \u67E5\u8BE2\u7ED3\u679C\u3002",inputSchema:ht,outputSchema:pt},(c,d)=>e.run(({config:m})=>yt(m,c),d,"chatbi_insight_start")),o("chatbi_insight_poll",{title:"Poll ChatBI Insight",description:"\u67E5\u8BE2 ChatBI L2 \u6D1E\u5BDF\u4EFB\u52A1\u72B6\u6001\u548C\u6700\u7EC8\u62A5\u544A\u3002status=success \u65F6\u6700\u7EC8\u5C55\u793A\u5185\u5BB9\u8BFB\u53D6 structuredContent.final_result.content\uFF1Banswer \u4E3A\u540E\u7AEF\u539F\u59CB\u7B54\u6848\u3002\u4F7F\u7528 chatbi_insight_start \u8FD4\u56DE\u7684 theme_id \u548C message_id\uFF1B\u4E0D\u8981\u9AD8\u9891\u8C03\u7528\uFF0C\u5EFA\u8BAE\u81F3\u5C11\u95F4\u9694 10 \u79D2\uFF0C\u6D1E\u5BDF\u901A\u5E38\u8017\u65F6 2-3 \u5206\u949F\uFF0C5 \u5206\u949F\u540E\u505C\u6B62\u7B49\u5F85\u3002",inputSchema:_t,outputSchema:mt},(c,d)=>e.run(({config:m})=>Tt(m,c),d,"chatbi_insight_poll"))),r.ok&&(a("global_search")&&o("global_search",{title:"Global Search",description:"\u641C\u7D22 BI \u4E2D\u7684\u5361\u7247\u3001\u4EEA\u8868\u677F\u3001\u6570\u636E\u96C6\u548C ETL \u8D44\u6E90\u3002",inputSchema:Dt},(c,d)=>e.run(({client:m})=>jt(m,c),d,"global_search")),a("search_metrics")&&o("search_metrics",{title:"Search Metrics",description:"\u641C\u7D22\u6307\u6807\u5E73\u53F0\u6307\u6807\uFF0C\u8FD4\u56DE metric_id\u3001\u540D\u79F0\u3001\u4E3B\u9898\u3001\u76EE\u5F55\u3001\u7C7B\u578B\u3001\u72B6\u6001\u548C\u4E1A\u52A1\u53E3\u5F84\u6458\u8981\u3002",inputSchema:zt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>Zt(m,f,c),d,"search_metrics")),a("list_metric_catalog")&&o("list_metric_catalog",{title:"List Metric Catalog",description:"\u6D4F\u89C8\u6307\u6807\u4E3B\u9898\u3001\u76EE\u5F55\u548C\u6307\u6807\u8282\u70B9\uFF0C\u9002\u5408\u4E0D\u77E5\u9053\u5173\u952E\u8BCD\u65F6\u53D1\u73B0\u53EF\u7528\u6307\u6807\u3002",inputSchema:Ft,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>en(m,f,c),d,"list_metric_catalog")),a("get_metric_detail")&&o("get_metric_detail",{title:"Get Metric Detail",description:"\u83B7\u53D6\u6307\u6807\u4E1A\u52A1\u53E3\u5F84\u3001\u8BA1\u7B97\u53E3\u5F84\u3001\u9002\u7528\u7EF4\u5EA6\u3001\u65F6\u95F4\u7EF4\u3001\u8840\u7F18/\u5F15\u7528\u6458\u8981\u548C\u6743\u9650\u4FE1\u606F\u3002",inputSchema:Qt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>tn(m,f,c),d,"get_metric_detail")),a("query_metric_data")&&o("query_metric_data",{title:"Query Metric Data",description:"\u5B89\u5168\u67E5\u8BE2\u6307\u6807\u6570\u636E\uFF1B\u666E\u901A/\u7EF4\u5EA6\u67E5\u8BE2\u8BFB\u53D6\u6307\u6807\u5361\u9884\u89C8\u6570\u636E\uFF0C\u7EF4\u5EA6\u67E5\u8BE2\u53EA\u4FEE\u6539\u4E34\u65F6 session\uFF0C\u4E0D\u8C03\u7528 save\u3001update\u3001delete\u3001publish \u7C7B\u6301\u4E45\u5316\u8DEF\u5F84\u3002",inputSchema:Wt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>nn(m,f,c),d,"query_metric_data")),a("search_metric_trees")&&o("search_metric_trees",{title:"Search Metric Trees",description:"\u641C\u7D22\u6307\u6807\u6811\u8D44\u6E90\uFF0C\u8FD4\u56DE\u53EF\u7528\u4E8E\u5F52\u56E0\u5206\u6790\u7684 metric_tree_id\u3002",inputSchema:Kt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>rn(m,f,c),d,"search_metric_trees")),a("get_metric_tree_detail")&&o("get_metric_tree_detail",{title:"Get Metric Tree Detail",description:"\u83B7\u53D6\u6307\u6807\u6811\u8BE6\u60C5\u3001\u6839\u6307\u6807\u3001\u65F6\u95F4\u5BF9\u6BD4\u914D\u7F6E\u3001\u7EF4\u5EA6\u62C6\u89E3\u914D\u7F6E\u548C\u6307\u6807\u5173\u7CFB\u6811\u3002",inputSchema:Yt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>sn(m,f,c),d,"get_metric_tree_detail")),a("query_metric_tree_attribution")&&o("query_metric_tree_attribution",{title:"Query Metric Tree Attribution",description:"\u57FA\u4E8E\u6307\u6807\u6811\u6267\u884C\u6307\u6807\u62C6\u89E3\u3001\u5355\u7EF4\u62C6\u89E3\u6216\u5168\u7EF4\u626B\u63CF\u5F52\u56E0\u5206\u6790\u3002",inputSchema:Xt,outputSchema:M},(c,d)=>e.run(({client:m,config:f})=>on(m,f,c),d,"query_metric_tree_attribution")),a("execute_sql_query")&&o("execute_sql_query",{title:"Execute SQL Query",description:`\u57FA\u4E8E\u5355\u4E2A\u6570\u636E\u96C6\u6267\u884C\u7B80\u5355\u67E5\u8BE2 SQL\u3002\u4EC5\u652F\u6301\u5355\u8868\u67E5\u8BE2\u548C\u67E5\u8BE2\u8BED\u53E5\uFF0C\u9002\u5408\u5C11\u91CF\u7ED3\u679C\u9884\u89C8\u6216\u8F7B\u91CF\u5206\u6790\uFF0C\u4E0D\u9002\u5408\u62C9\u53D6\u5168\u91CF\u6570\u636E\u3002\u8FD4\u56DE\u884C\u6570\u53D7 BI_MAX_ROWS \u63A7\u5236\uFF0C\u5F53\u524D\u914D\u7F6E\u4E3A ${n.BI_MAX_ROWS} \u884C\uFF0C\u9ED8\u8BA4\u503C\u4E3A 1000 \u884C\u3002`,inputSchema:Mt},(c,d)=>e.run(({client:m,config:f})=>Pt(m,f,c),d,"execute_sql_query")),a("get_dataset_detail")&&o("get_dataset_detail",{title:"Get Dataset Detail",description:"\u83B7\u53D6\u6570\u636E\u96C6\u7684\u57FA\u7840\u4FE1\u606F\u3001\u5B57\u6BB5\u7ED3\u6784\u548C\u76F8\u5173\u914D\u7F6E\u3002",inputSchema:Rt},(c,d)=>e.run(({client:m})=>Et(m,c),d,"get_dataset_detail")),a("get_card_info")&&o("get_card_info",{title:"Get Card Info",description:"\u83B7\u53D6\u5361\u7247\u7684\u57FA\u7840\u4FE1\u606F\u3001\u56FE\u8868\u7C7B\u578B\u3001\u6570\u636E\u6765\u6E90\u548C\u914D\u7F6E\u3002",inputSchema:vt},(c,d)=>e.run(({client:m})=>Ot(m,c),d,"get_card_info")),a("get_page_info")&&o("get_page_info",{title:"Get Page Info",description:"\u83B7\u53D6\u9875\u9762/\u4EEA\u8868\u677F\u7684\u57FA\u7840\u4FE1\u606F\u3001\u5E03\u5C40\u3001\u5361\u7247\u5217\u8868\u548C\u76F8\u5173\u914D\u7F6E\u3002",inputSchema:At},(c,d)=>e.run(({client:m})=>xt(m,c),d,"get_page_info")))}var Di=vi(import.meta.url),ji=Di("../package.json"),Pe=class{record(e){console.error(JSON.stringify({runtime:Li(e)}))}};function bn(t,e={}){let n=e.mode??t.MCP_TRANSPORT??"stdio",r={appVersion:e.appVersion,clientFactory:e.clientFactory,callerContextResolver:e.callerContextResolver,guanBIClientFactory:e.guanBIClientFactory,capabilityResolver:e.capabilityResolver,transportFactory:e.transportFactory};return n==="streamable-http"?new je(t,r):new De(t,r)}async function In(t,e={}){let n=e.appVersion??ji.version,r=e.callerContextResolver??Xe(t),i=e.guanBIClientFactory??new ee(t,{clientFactory:e.clientFactory}),s=i.create(await r.resolve()),o=await(e.capabilityResolver??H)(s.client,s.config),a=new xi({name:"guanbi-mcp-server",version:n});return hn(a,new ne(r,i,new F),s.config,o,{appVersion:n}),a}var De=class{constructor(e,n){this.config=e;this.options=n}config;options;mode="stdio";health(){return{status:"ok",mode:this.mode,boundBISite:{configured:!!this.config.BI_BASE_URL,baseUrl:this.config.BI_BASE_URL,publicPath:this.config.BI_PUBLIC_PATH}}}async start(){await(await In(this.config,this.options)).connect(this.options.transportFactory?.()??new Mi)}},je=class{constructor(e,n){this.config=e;this.options=n}config;options;mode="streamable-http";httpServer;sessions=new Map;logger=new Pe;health(){return{status:"ok",mode:this.mode,boundBISite:{configured:!!this.config.BI_BASE_URL,baseUrl:this.config.BI_BASE_URL,publicPath:this.config.BI_PUBLIC_PATH}}}async start(){this.httpServer=Oi((e,n)=>{this.handleRequest(e,n).catch(r=>{this.log("error","mcp_http_internal_error","Streamable HTTP request failed.",e,{statusCode:500,errorMessage:r instanceof Error?r.message:String(r)}),q(n,500,{error:"internal_error",message:r instanceof Error?r.message:String(r)})})}),await new Promise((e,n)=>{this.httpServer?.once("error",r=>{this.log("error","mcp_http_start_failed","Streamable HTTP server failed to start.",void 0,{host:this.config.MCP_HTTP_HOST??"127.0.0.1",port:this.config.MCP_HTTP_PORT??3e3,errorMessage:r.message}),n(r)}),this.httpServer?.listen(this.config.MCP_HTTP_PORT??3e3,this.config.MCP_HTTP_HOST??"127.0.0.1",()=>{this.httpServer?.removeAllListeners("error");let r=this.httpServer?.address(),i=typeof r=="object"&&r?r.port:this.config.MCP_HTTP_PORT??3e3,s=this.config.MCP_HTTP_HOST??"127.0.0.1";this.log("info","mcp_http_started","Streamable HTTP server started.",void 0,{host:s,port:i,url:this.url(),boundBISite:qi(this.config),entrypointTokenConfigured:!!this.config.MCP_ENTRYPOINT_TOKEN,trustedGateway:Ne(this.config.MCP_TRUSTED_GATEWAY)}),e()})})}async stop(){await Promise.all([...this.sessions.values()].map(({server:e})=>e.close())),this.sessions.clear(),this.httpServer&&(await new Promise((e,n)=>{this.httpServer?.close(r=>r?n(r):e())}),this.httpServer=void 0,this.log("info","mcp_http_stopped","Streamable HTTP server stopped.",void 0,{sessionCount:this.sessions.size}))}url(){let e=this.httpServer?.address();if(!(!e||typeof e=="string"))return`http://${Ni(e,this.config.MCP_HTTP_HOST??"127.0.0.1")}:${e.port}`}async handleRequest(e,n){let r=_n(e);if(!r){q(n,400,{error:"bad_request"});return}if(r==="/healthz"&&e.method==="GET"){q(n,200,this.health());return}if(r!=="/mcp"){q(n,404,{error:"not_found"});return}if(!Ui(e.headers,this.config)){this.log("warn","mcp_entrypoint_unauthorized","Rejected MCP request with invalid entrypoint credential.",e,{statusCode:401,entrypointTokenConfigured:!!this.config.MCP_ENTRYPOINT_TOKEN,trustedGateway:Ne(this.config.MCP_TRUSTED_GATEWAY)}),q(n,401,{error:"mcp_entrypoint_unauthorized"});return}let i=Ue(e.headers["mcp-session-id"]);if(i&&!this.sessions.has(i)){this.log("warn","mcp_session_not_found","Rejected MCP request for an unknown session.",e,{statusCode:404,...Me(i),sessionCount:this.sessions.size}),q(n,404,{error:"mcp_session_not_found"});return}let s=await this.resolveSession(e);await s.transport.handleRequest(e,n);let o=s.transport.sessionId;o&&e.method!=="DELETE"&&!this.sessions.has(o)&&(this.sessions.set(o,s),this.log("info","mcp_session_created","Created Streamable HTTP MCP session.",e,{...Me(o),sessionCount:this.sessions.size}))}async resolveSession(e){let n=Ue(e.headers["mcp-session-id"]);if(n){let s=this.sessions.get(n);if(s)return s}let r=new Pi({sessionIdGenerator:Ei,onsessionclosed:async s=>{let o=this.sessions.get(s);this.sessions.delete(s),await o?.server.close(),this.log("info","mcp_session_closed","Closed Streamable HTTP MCP session.",void 0,{...Me(s),sessionCount:this.sessions.size})}}),i=await In(this.config,{...this.options,callerContextResolver:this.options.callerContextResolver??Ze(),capabilityResolver:this.options.capabilityResolver??(async()=>Ke(this.config))});return await i.connect(r),{server:i,transport:r}}log(e,n,r,i,s={}){let o=i?_n(i):void 0;this.logger.record({level:e,event:n,mode:this.mode,message:r,method:i?.method,path:o,...s})}};function Ui(t,e){if(Ne(e.MCP_TRUSTED_GATEWAY))return!0;let n=e.MCP_ENTRYPOINT_TOKEN;return n?Ue(t.authorization)?.trim()===`Bearer ${n}`:!1}function Ue(t){return Array.isArray(t)?t[0]:t}function Ne(t){return["1","true","yes","on"].includes(t?.trim().toLowerCase()??"")}function q(t,e,n){t.headersSent||(t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(n)))}function Ni(t,e){return t.address==="::"||t.address==="0.0.0.0"?e==="0.0.0.0"||e==="::"?"127.0.0.1":e:t.address}function Li(t){return Object.fromEntries(Object.entries(t).filter(([,e])=>e!==void 0))}function _n(t){try{return new URL(t.url??"/",`http://${t.headers.host??"localhost"}`).pathname}catch{return}}function qi(t){let e={configured:!!t.BI_BASE_URL,publicPath:t.BI_PUBLIC_PATH};if(!t.BI_BASE_URL)return e;try{e.origin=new URL(t.BI_BASE_URL).origin}catch{e.configured=!0}return e}function Me(t){return{hasSessionId:!0,sessionIdHash:Ai("sha256").update(t).digest("hex").slice(0,12)}}async function Gi(){let t=qe();await bn(t).start()}Gi().catch(t=>{console.error(t instanceof Error?t.message:t),process.exit(1)});
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@guandata/guanbi-mcp-server",
3
+ "version": "0.1.10",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "MCP server for exposing GuanBI capabilities to AI agents.",
7
+ "packageManager": "pnpm@10.30.3",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "bin": {
12
+ "guanbi-mcp-server": "dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ ".env.example"
17
+ ],
18
+ "scripts": {
19
+ "dev": "tsx src/index.ts",
20
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
21
+ "build": "tsup",
22
+ "release:mr": "node scripts/release-mr.mjs",
23
+ "release:publish": "node scripts/publish-release.mjs",
24
+ "test": "vitest run",
25
+ "typecheck": "tsc -p tsconfig.json --noEmit",
26
+ "start": "node dist/index.js"
27
+ },
28
+ "dependencies": {
29
+ "@modelcontextprotocol/sdk": "^1.29.0",
30
+ "dotenv": "^17.4.2",
31
+ "zod": "^4.4.3"
32
+ },
33
+ "devDependencies": {
34
+ "@guandata/bi-contract": "0.1.0",
35
+ "@types/node": "^25.7.0",
36
+ "tsup": "^8.5.1",
37
+ "tsx": "^4.21.0",
38
+ "typescript": "^6.0.3",
39
+ "vitest": "^4.1.6"
40
+ },
41
+ "engines": {
42
+ "node": ">=20.0.0"
43
+ }
44
+ }