@shiplens/cli 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 🚀 Shiplens CLI
2
2
 
3
- > **Shiplens 官方命令行工具面向 Web 前端的用户行为数据统计与 AI Agent 智能分析引擎。**
3
+ > **Official Shiplens CLIAutomated Web User Analytics & AI Agent Analysis Engine.**
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@shiplens/cli.svg)](https://www.npmjs.com/package/@shiplens/cli)
6
6
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
@@ -8,64 +8,64 @@
8
8
 
9
9
  ---
10
10
 
11
- Shiplens CLI [shiplens.dev](https://shiplens.dev) 官方配套的命令行工具。它为前端项目提供自动化的数据统计接入,并与各类 AI Agent(CursorWindsurfCodexClaude 等)无缝协同,实现对话式数据查询与自动化分析。
11
+ Shiplens CLI is the official command-line tool for [shiplens.dev](https://shiplens.dev). It provides automated analytics instrumentation for modern web frontend applications and seamlessly pairs with AI coding agents (Cursor, Windsurf, Codex, Claude, Antigravity, etc.) for conversational data analysis and real-time dashboards.
12
12
 
13
13
  ---
14
14
 
15
- ## 🌟 核心功能
15
+ ## 🌟 Key Features
16
16
 
17
- - **自动化接入与代码插桩**:自动识别前端项目框架(Next.jsViteVueHTML 等),无感注入 `@shiplens/sdk` 数据采集代码;
18
- - **用户行为数据统计**:秒级查看全站流量大盘、访问路径、页面留存与点击热力图;
19
- - **AI Agent 智能分析**:支持通过 CLI 与本地 stdio MCP 代理(`shiplens mcp serve`)与 AI 对话,让 Agent 直接读取产品数据并输出教科书级业务洞察;
20
- - **AI 实时看板生成**:一句话自然语言诉求,云端自动拼装 12 列响应式数据看板;
21
- - **业务上下文与动态自适应**:自动提取页面功能文案辅助 AI 理解业务,并支持按项目自适应记忆个性化分析偏好。
17
+ - **Automated Setup & Instrumentation**: Automatically detects frontend frameworks (Next.js, Vite, Vue, HTML, etc.) and injects `@shiplens/sdk` tracking code.
18
+ - **Web User Analytics**: Real-time traffic summaries, user journeys, retention cohorts, and click heatmaps.
19
+ - **AI Agent Intelligence**: Query and analyze product behavior data directly from AI coding assistants via CLI and local stdio MCP proxy (`shiplens mcp serve`).
20
+ - **AI-Powered Live Dashboards**: Assemble 12-column responsive analytics dashboards from natural language prompts.
21
+ - **Business Context & Adaptive Learning**: Automatically maps DOM hashes to real page names and remembers per-project analysis preferences.
22
22
 
23
23
  ---
24
24
 
25
- ## ⚡ 快速开始
25
+ ## ⚡ Quick Start
26
26
 
27
- 在任何前端项目根目录下执行初始化命令:
27
+ Run the initialization command in the root directory of any frontend project:
28
28
 
29
29
  ```bash
30
- # 通用终端
30
+ # General terminal
31
31
  npx --yes @shiplens/cli init
32
32
 
33
33
  # Windows PowerShell
34
34
  npx.cmd --yes @shiplens/cli init
35
35
 
36
- # 备用镜像源
36
+ # Backup mirror fallback
37
37
  npx --yes --registry=https://registry.npmmirror.com @shiplens/cli init
38
38
  ```
39
39
 
40
40
  ---
41
41
 
42
- ## 📊 常用命令速查
42
+ ## 📊 Core Commands Reference
43
43
 
44
- | 命令 | 说明 |
44
+ | Command | Description |
45
45
  | :--- | :--- |
46
- | `shiplens init` | 为当前项目接入数据统计并下发 AI Skill 规范 |
47
- | `shiplens summary` | 查看产品流量大盘概览(PVUV、时长、受众分布) |
48
- | `shiplens query` | 多维指标聚合与用户转化漏斗查询 |
49
- | `shiplens sql` | 执行自定义安全只读数据分析查询 |
50
- | `shiplens pages` | 页面级访问量与停留时长统计 |
51
- | `shiplens heatmap` | 查看页面点击热力分布与骨架图 |
52
- | `shiplens dashboards create` | 通过自然语言生成官方数据看板 |
53
- | `shiplens doctor` | 检查本地配置、代码插桩与网络通道健康度 |
54
- | `shiplens context show` | 查看当前项目的业务上下文与页面功能文案 |
55
- | `shiplens auth bind` | 绑定邮箱并激活设备数据分析授权 |
56
- | `shiplens mcp serve` | 启动本地 stdio MCP 代理服务供 AI Agent 调度 |
46
+ | `shiplens init` | Onboard project, instrument tracking SDK, and inject AI skill |
47
+ | `shiplens summary` | Macro traffic overview (PV, UV, dwell time, geos, devices) |
48
+ | `shiplens query` | Multi-dimensional metrics aggregation and conversion funnels |
49
+ | `shiplens sql` | Safe read-only custom SQL queries |
50
+ | `shiplens pages` | Page-level visits and average dwell times |
51
+ | `shiplens heatmap` | Visual click heatmaps and skeleton wireframe snapshots |
52
+ | `shiplens dashboards create` | Generate live AI dashboards from natural language |
53
+ | `shiplens doctor` | End-to-end diagnostics on SDK, network, and configuration |
54
+ | `shiplens context show` | Inspect business context and page semantic mappings |
55
+ | `shiplens auth bind` | Request Magic Link to activate authorization and event quota |
56
+ | `shiplens mcp serve` | Start local stdio MCP proxy for AI IDEs and Agents |
57
57
 
58
58
  ---
59
59
 
60
- ## 🔗 相关资源
60
+ ## 🔗 Resources
61
61
 
62
- - 官方网站:[https://shiplens.dev](https://shiplens.dev)
63
- - 常见问题与支持:[https://shiplens.dev/faq](https://shiplens.dev/faq)
64
- - 全命令参考手册:[`docs/02_SHIPLENS_CLI_全命令参考手册.md`](./docs/02_SHIPLENS_CLI_全命令参考手册.md)
62
+ - Website: [https://shiplens.dev](https://shiplens.dev)
63
+ - Support & FAQ: [https://shiplens.dev/faq](https://shiplens.dev/faq)
64
+ - Command Reference: [`docs/02_CLI_COMMAND_REFERENCE.md`](./docs/02_CLI_COMMAND_REFERENCE.md)
65
65
 
66
66
  ---
67
67
 
68
- ## 📜 开源协议
68
+ ## 📜 License
69
69
 
70
70
  Apache-2.0 © Shiplens Team
71
71
 
@@ -0,0 +1,195 @@
1
+ # Shiplens CLI Command Reference
2
+
3
+ > Complete documentation for all Shiplens CLI commands, flags, arguments, and sample outputs for AI Agent execution.
4
+
5
+ ---
6
+
7
+ ## Global Flags
8
+
9
+ | Flag | Type | Description |
10
+ | :--- | :--- | :--- |
11
+ | `--json` | boolean | Output results in JSON format (required for AI Agents) |
12
+ | `--app-id <id>` | string | Explicitly specify target `app_id` (default: auto-read from `.shiplens.json`) |
13
+ | `--env <env>` | string | Target environment: `production` (default) or `staging` |
14
+ | `--secret <key>` | string | Explicitly pass Access Secret |
15
+ | `--api-url <url>` | string | Custom backend API base URL (default: `http://120.26.230.33`) |
16
+ | `--help`, `-h` | boolean | Display help information |
17
+
18
+ ---
19
+
20
+ ## 1. Project Onboarding (`init`)
21
+
22
+ ```bash
23
+ shiplens init [options]
24
+ ```
25
+
26
+ ### Options:
27
+ - `--name <name>`: Project name (default: package.json name)
28
+ - `--description <desc>`: Project description
29
+ - `--industry <ind>`: Industry category
30
+ - `--genre <id>`: Level 1 Genre ID
31
+ - `--subgenre <id>`: Level 2 Sub-genre ID
32
+ - `--tags <tag1,tag2>`: Comma-separated feature tag IDs (max 10)
33
+ - `--email <email>`: Binding email (pass `auto` to use git config)
34
+ - `--framework <type>`: Override detected framework (`nextjs-app`, `nextjs-pages`, `vite`, `vue`, `html`)
35
+ - `--force`: Force overwrite existing local configuration
36
+ - `--no-install`: Skip package manager installation
37
+ - `--no-commit`: Skip automatic Git commit
38
+
39
+ ---
40
+
41
+ ## 2. Authentication (`auth`)
42
+
43
+ ### Subcommands:
44
+ - `shiplens auth status`: Check credential validity
45
+ - `shiplens auth set [secret]`: Save Access Secret to `~/.shiplens/config.json`
46
+ - `shiplens auth whoami`: Display authenticated user details
47
+ - `shiplens auth logout`: Clear local credentials
48
+ - `shiplens auth bind --email <email>`: Request Magic Link activation email
49
+ - `shiplens auth mcp-config --client <client>`: Generate MCP client configuration
50
+ - `shiplens auth configure --client <client>`: Automatically write MCP configuration
51
+
52
+ ---
53
+
54
+ ## 3. Projects Management (`projects`)
55
+
56
+ ### Subcommands:
57
+ - `shiplens projects list`: List all projects associated with current account
58
+ - `shiplens projects bind`: Bind current project to account
59
+ - `shiplens projects delete [--force]`: Delete project and its data
60
+
61
+ ---
62
+
63
+ ## 4. Multi-Dimensional Query (`query`)
64
+
65
+ ```bash
66
+ shiplens query [options]
67
+ ```
68
+
69
+ ### Options:
70
+ - `--metric <name>` / `--metrics <m1,m2>`: Metric name(s)
71
+ - `--range <range>`: Time range (`24h`, `7d`, `14d`, `30d`, `90d`)
72
+ - `--grain <grain>`: Time grain (`hour`, `day`, `week`, `month`)
73
+ - `--group-by <dim>`: Group dimension (`path`, `template_id`, `country`, `browser`, `device_type`)
74
+ - `--filter <key=value>`: Filter condition (e.g. `--filter country=US`)
75
+ - `--limit <num>`: Result limit (default: 30)
76
+ - `--file <path>`: Load full `AnalyticsQueryRequest` from JSON file
77
+
78
+ ---
79
+
80
+ ## 5. Sandboxed SQL (`sql`)
81
+
82
+ ```bash
83
+ shiplens sql --query "<sql>" [options]
84
+ ```
85
+
86
+ ### Options:
87
+ - `--query "<sql>"` / `--sql "<sql>"`: SQL query string
88
+ - `--stdin`: Read SQL query from stdin stream
89
+
90
+ ---
91
+
92
+ ## 6. Product Summary (`summary`)
93
+
94
+ ```bash
95
+ shiplens summary [--range <range>]
96
+ ```
97
+
98
+ Returns total PV, UV, average session duration, bounce rate, top countries, and top devices.
99
+
100
+ ---
101
+
102
+ ## 7. Page Telemetry (`pages`, `paths`, `canvas`)
103
+
104
+ - `shiplens pages [--range 7d] [--limit 10]`: Page-level visits and dwell times
105
+ - `shiplens paths [--range 7d]`: Sankey user flow and transition paths
106
+ - `shiplens canvas [--range 7d]`: Behavioral canvas node-link topology
107
+
108
+ ---
109
+
110
+ ## 8. Click Heatmaps (`heatmap`)
111
+
112
+ ```bash
113
+ shiplens heatmap --template <template_id> [--dom-hash <hash>]
114
+ ```
115
+
116
+ Returns skeleton wireframe SVG URL, total clicks, and element click distribution.
117
+
118
+ ---
119
+
120
+ ## 9. AI Dashboards (`dashboards`)
121
+
122
+ - `shiplens dashboards list`: List all dashboards for project
123
+ - `shiplens dashboards create --title "..." --prompt "..."`: Create responsive dashboard via prompt
124
+ - `shiplens dashboards create --ai --prompt "..."`: AI-driven dashboard generation
125
+
126
+ ---
127
+
128
+ ## 10. Environment Diagnostics (`doctor`)
129
+
130
+ ```bash
131
+ shiplens doctor [--json]
132
+ ```
133
+
134
+ Performs health checks on:
135
+ 1. `local_config`: `.shiplens.json` validity
136
+ 2. `sdk_dependency`: `@shiplens/sdk` in `package.json`
137
+ 3. `code_injection`: SDK import in entry files
138
+ 4. `ingestion_connectivity`: Network latency to API
139
+ 5. `auth_credential`: Access secret resolution
140
+ 6. `email_binding`: Quota activation status
141
+ 7. `schema_freshness`: Schema synchronization age
142
+
143
+ ---
144
+
145
+ ## End-to-End System Topology
146
+
147
+ The full data flow from user action to analytics delivery:
148
+
149
+ ```mermaid
150
+ sequenceDiagram
151
+ participant User as User / Agent
152
+ participant CLI as Shiplens CLI
153
+ participant Cloud as Cloud API
154
+ participant SDK as @shiplens/sdk
155
+ participant MCP as Local MCP Proxy
156
+
157
+ Note over User,MCP: Onboarding Flow (Steps 1-7)
158
+ User->>CLI: 1. npx @shiplens/cli init
159
+ CLI->>Cloud: 2. POST /api/connect (register project, 4-level taxonomy)
160
+ Cloud-->>CLI: app_id + dashboard_url
161
+ CLI->>CLI: 3. Inject SDK code into entry file
162
+ CLI->>CLI: 4. Install @shiplens/sdk dependency
163
+ CLI->>CLI: 5. Scan pages → .shiplens/contexts/<app_id>.md
164
+ User->>CLI: 6. shiplens auth bind --email <email>
165
+ CLI->>Cloud: POST /api/auth/start-email
166
+ Cloud-->>User: 7. Magic Link email → user clicks → project activated
167
+ Cloud-->>CLI: Device credentials → shiplens.env (0600)
168
+
169
+ Note over User,MCP: Analysis Flow (Steps 8-12)
170
+ User->>CLI: 8. shiplens summary / query / sql
171
+ CLI->>CLI: 9. Load shiplens.env credentials
172
+ CLI->>Cloud: 10. Authenticated API request
173
+ Cloud-->>CLI: 11. Analytics data response
174
+ CLI-->>User: 12. JSON output → Agent synthesizes insights
175
+
176
+ Note over User,MCP: MCP Integration (Alternative)
177
+ User->>MCP: shiplens mcp serve (stdio)
178
+ MCP->>Cloud: Proxied requests with shiplens.env credentials
179
+ Cloud-->>MCP: Data response
180
+ MCP-->>User: Structured tool results
181
+ ```
182
+
183
+ ### Component Roles
184
+
185
+ | Component | Responsibility |
186
+ |-----------|---------------|
187
+ | **CLI** (`npx @shiplens/cli`) | Onboarding, SDK injection, local config management, direct analytics queries |
188
+ | **Cloud API** | Project registration, authentication, data aggregation, dashboard hosting |
189
+ | **SDK** (`@shiplens/sdk`) | Client-side event capture (pageviews, clicks, custom events), DOM hashing |
190
+ | **shiplens.env** | Device-level credentials (Access Secret), file permission 0600, auto-gitignored |
191
+ | **Local MCP Proxy** (`shiplens mcp serve`) | stdio bridge for IDE/Agent integration, forwards requests with local credentials |
192
+ | **.shiplens.json** | Project metadata cache (app_id, project_name, schema timestamp) |
193
+ | **.shiplens/contexts/\<app_id\>.md** | Business context dictionary (page routes, button labels, feature descriptions) |
194
+ | **.shiplens/learnings.md** | User preference overrides (date range, metrics, filters) |
195
+
package/lib/api.js CHANGED
@@ -24,25 +24,21 @@ class APIClient {
24
24
  const fullURL = `${this.baseURL}${path}`;
25
25
  const parsed = new URL(fullURL);
26
26
  const isHttps = parsed.protocol === 'https:';
27
- const transport = isHttps ? https : http;
27
+ const lib = isHttps ? https : http;
28
28
 
29
- let pkgVer = '1.3.1';
29
+ const payload = body ? (typeof body === 'string' ? body : JSON.stringify(body)) : null;
30
+ let pkgVer = '1.3.0';
30
31
  try {
31
32
  pkgVer = require('../package.json').version || pkgVer;
32
33
  } catch (e) {}
33
-
34
34
  const headers = {
35
35
  'Content-Type': 'application/json',
36
36
  'User-Agent': `Shiplens-CLI/${pkgVer} (Node.js)`,
37
37
  };
38
-
39
38
  if (this.secret) {
40
39
  headers['Authorization'] = `Bearer ${this.secret}`;
41
40
  }
42
-
43
- let payload = null;
44
- if (body !== null && body !== undefined) {
45
- payload = typeof body === 'string' ? body : JSON.stringify(body);
41
+ if (payload) {
46
42
  headers['Content-Length'] = Buffer.byteLength(payload);
47
43
  }
48
44
 
@@ -56,14 +52,16 @@ class APIClient {
56
52
  };
57
53
 
58
54
  return new Promise((resolve, reject) => {
59
- const req = transport.request(options, (res) => {
60
- let raw = '';
61
- res.on('data', (chunk) => { raw += chunk; });
55
+ const req = lib.request(options, (res) => {
56
+ let resData = '';
57
+ res.on('data', (chunk) => {
58
+ resData += chunk;
59
+ });
62
60
  res.on('end', () => {
63
61
  let json = null;
64
62
  try {
65
- json = JSON.parse(raw);
66
- } catch {
63
+ json = JSON.parse(resData);
64
+ } catch (e) {
67
65
  json = null;
68
66
  }
69
67
 
@@ -77,12 +75,12 @@ class APIClient {
77
75
  case 429: code = ERROR_CODES.RATE_LIMITED; break;
78
76
  case 400: case 422: code = ERROR_CODES.INVALID_SQL; break;
79
77
  }
80
- const msg = (json && (json.message || json.error || (json.detail && (typeof json.detail === 'string' ? json.detail : JSON.stringify(json.detail))))) || raw || `HTTP ${res.statusCode}`;
78
+ const msg = (json && (json.message || json.error || (json.detail && (typeof json.detail === 'string' ? json.detail : JSON.stringify(json.detail))))) || resData || `HTTP ${res.statusCode}`;
81
79
  const err = new Error(msg);
82
80
  err.code = (json && json.code) || code;
83
81
  err.statusCode = res.statusCode;
84
82
  err.status = res.statusCode;
85
- err.response = json || raw;
83
+ err.response = json || resData;
86
84
  err.ok = false;
87
85
  return reject(err);
88
86
  }
@@ -91,16 +89,16 @@ class APIClient {
91
89
  });
92
90
  });
93
91
 
94
- req.on('timeout', () => {
95
- req.destroy();
96
- const err = new Error(`请求超时 (${options.timeout}ms): ${method} ${path}`);
97
- err.code = ERROR_CODES.NETWORK_FAILED;
98
- err.ok = false;
99
- reject(err);
92
+ req.on('error', (err) => {
93
+ const error = new Error(`Network connection error: ${err.message}`);
94
+ error.code = ERROR_CODES.NETWORK_FAILED;
95
+ error.ok = false;
96
+ reject(error);
100
97
  });
101
98
 
102
- req.on('error', (err) => {
103
- const error = new Error(`网络连接异常: ${err.message}`);
99
+ req.on('timeout', () => {
100
+ req.destroy();
101
+ const error = new Error(`Request timed out (${options.timeout}ms)`);
104
102
  error.code = ERROR_CODES.NETWORK_FAILED;
105
103
  error.ok = false;
106
104
  reject(error);
@@ -113,26 +111,26 @@ class APIClient {
113
111
  });
114
112
  }
115
113
 
116
- // 15 秒极速建立连接/上报项目 (POST /api/connect)
114
+ // 15-second connect & project registration (POST /api/connect)
117
115
  async connect(data) {
118
116
  const res = await this.request('POST', '/api/connect', data);
119
117
  if (typeof res === 'object') res.ok = true;
120
118
  return res;
121
119
  }
122
120
 
123
- // 一键发送 Magic Link 邮箱绑定 (POST /api/auth/email/start)
121
+ // Send Magic Link for email binding (POST /api/auth/email/start)
124
122
  async startEmail(data) {
125
123
  const res = await this.request('POST', '/api/auth/email/start', data);
126
124
  if (typeof res === 'object') res.ok = true;
127
125
  return res;
128
126
  }
129
127
 
130
- // 检查邮箱绑定/激活状态 (GET /api/auth/email-status?token=...)
128
+ // Check email activation status (GET /api/auth/email-status?token=...)
131
129
  async checkEmailStatus(token) {
132
130
  return this.request('GET', `/api/auth/email-status?token=${encodeURIComponent(token)}`);
133
131
  }
134
132
 
135
- // startEmail 指数退避重试
133
+ // Exponential backoff retry for startEmail
136
134
  async startEmailWithRetry(data, retry = 2, baseMs = 500) {
137
135
  let lastErr;
138
136
  for (let i = 0; i <= retry; i++) {
@@ -149,60 +147,53 @@ class APIClient {
149
147
  throw lastErr;
150
148
  }
151
149
 
152
- // 查询离线 Access Secret 列表 (GET /api/auth/api-keys)
150
+ // List offline Access Secrets (GET /api/auth/api-keys)
153
151
  async listAccessSecrets() {
154
152
  return this.request('GET', '/api/auth/api-keys');
155
153
  }
156
154
 
157
- // 创建离线 Access Secret (POST /api/auth/api-keys)
155
+ // Create offline Access Secret (POST /api/auth/api-keys)
158
156
  async createAccessSecret(data) {
159
157
  return this.request('POST', '/api/auth/api-keys', data);
160
158
  }
161
159
 
162
- // 吊销离线 Access Secret (DELETE /api/auth/api-keys/:keyId)
160
+ // Revoke offline Access Secret (DELETE /api/auth/api-keys/:keyId)
163
161
  async revokeAccessSecret(apiKeyId) {
164
162
  return this.request('DELETE', `/api/auth/api-keys/${encodeURIComponent(apiKeyId)}`);
165
163
  }
166
164
 
167
- // 获取当前登录用户信息 (GET /api/me)
168
165
  async me() {
169
166
  const res = await this.request('GET', '/api/me');
170
167
  if (typeof res === 'object') res.ok = true;
171
168
  return res;
172
169
  }
173
170
 
174
- // 获取用户项目列表 (GET /api/apps)
175
171
  async listProjects() {
176
172
  const res = await this.request('GET', '/api/apps');
177
173
  if (typeof res === 'object') res.ok = true;
178
174
  return res;
179
175
  }
180
176
 
181
- // 绑定项目到当前登录账号 (POST /api/projects/bind)
182
177
  async bindProject(appId, projectName = '') {
183
178
  return this.request('POST', '/api/projects/bind', { app_id: appId, project_name: projectName });
184
179
  }
185
180
 
186
- // 更新项目分类法配置 (PUT /api/apps/:appId/taxonomy)
187
181
  async updateTaxonomy(appId, data) {
188
182
  const res = await this.request('PUT', `/api/apps/${encodeURIComponent(appId)}/taxonomy`, data);
189
183
  if (typeof res === 'object') res.ok = true;
190
184
  return res;
191
185
  }
192
186
 
193
- // 获取项目分类法配置 (GET /api/apps/:appId/taxonomy)
194
187
  async getTaxonomy(appId) {
195
188
  const res = await this.request('GET', `/api/apps/${encodeURIComponent(appId)}/taxonomy`);
196
189
  if (typeof res === 'object') res.ok = true;
197
190
  return res;
198
191
  }
199
192
 
200
- // 删除项目 (DELETE /api/apps/:appId)
201
193
  async deleteProject(appId) {
202
194
  return this.request('DELETE', `/api/apps/${encodeURIComponent(appId)}`);
203
195
  }
204
196
 
205
- // 综合指标分析查询 (POST /api/ai/apps/:appId/analytics/query)
206
197
  async queryAnalytics(appId, queryReq) {
207
198
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
208
199
  const actualReq = typeof appId === 'object' ? appId : queryReq;
@@ -218,7 +209,7 @@ class APIClient {
218
209
  return this.queryAnalytics(appId, queryReq);
219
210
  }
220
211
 
221
- // 执行只读 SQL 查询 (POST /api/mcp/apps/:appId/sql)
212
+ // executeSQL (POST /api/mcp/apps/:appId/sql, payload: { sql: queryStr })
222
213
  async executeSQL(appId, queryStr) {
223
214
  const start = Date.now();
224
215
  let actualAppId = appId;
@@ -237,7 +228,6 @@ class APIClient {
237
228
  return res;
238
229
  }
239
230
 
240
- // 产品概览数据 (GET /api/ai/apps/:appId/summary)
241
231
  async summary(appId, range = '7d', env = 'production') {
242
232
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
243
233
  const actualRange = typeof appId === 'object' ? (appId.range || range) : range;
@@ -248,7 +238,6 @@ class APIClient {
248
238
  return res;
249
239
  }
250
240
 
251
- // 页面访问与停留时长统计 (GET /api/ai/apps/:appId/pages)
252
241
  async pages(appId, range = '7d', env = 'production', limit = 10) {
253
242
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
254
243
  const actualRange = typeof appId === 'object' ? (appId.range || range) : range;
@@ -264,7 +253,6 @@ class APIClient {
264
253
  return this.pages(data);
265
254
  }
266
255
 
267
- // 用户行为路径/流转分析 (GET /api/ai/apps/:appId/paths)
268
256
  async paths(appId, range = '7d', env = 'production') {
269
257
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
270
258
  const actualRange = typeof appId === 'object' ? (appId.range || range) : range;
@@ -282,7 +270,6 @@ class APIClient {
282
270
  return this.paths(data);
283
271
  }
284
272
 
285
- // 全局行为画布拓扑 (GET /api/ai/apps/:appId/behavior-canvas)
286
273
  async behaviorCanvas(appId, range = '7d', env = 'production') {
287
274
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
288
275
  const actualRange = typeof appId === 'object' ? (appId.range || range) : range;
@@ -293,7 +280,6 @@ class APIClient {
293
280
  return res;
294
281
  }
295
282
 
296
- // 点击热力图与骨架图 (GET /api/ai/apps/:appId/pages/:templateId/heatmap)
297
283
  async heatmap(appId, templateId, env = 'production', domHash = '') {
298
284
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
299
285
  const actualTemplateId = typeof appId === 'object' ? appId.template_id : templateId;
@@ -314,14 +300,12 @@ class APIClient {
314
300
  return this.heatmap(data);
315
301
  }
316
302
 
317
- // 查询仪表盘列表 (GET /api/apps/:appId/dashboards)
318
303
  async listDashboards(appId) {
319
304
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
320
305
  const res = await this.request('GET', `/api/apps/${encodeURIComponent(actualAppId)}/dashboards`);
321
306
  return Array.isArray(res) ? res : (res.dashboards || []);
322
307
  }
323
308
 
324
- // 创建自定义仪表盘 (POST /api/apps/:appId/dashboards)
325
309
  async createDashboard(appId, data) {
326
310
  const actualAppId = typeof appId === 'object' ? (appId.app_id || '') : appId;
327
311
  const actualData = typeof appId === 'object' ? appId : data;
@@ -330,14 +314,12 @@ class APIClient {
330
314
  return res;
331
315
  }
332
316
 
333
- // 测试网络连接与服务端连通性
334
317
  async testConnectivity() {
335
318
  const start = Date.now();
336
319
  await this.request('GET', '/api/ai/tools');
337
320
  return Date.now() - start;
338
321
  }
339
322
 
340
- // 获取指标元数据 Schema (GET /api/ai/apps/:appId/analytics/schema)
341
323
  async getAnalyticsSchema(appId) {
342
324
  const actualAppId = typeof appId === 'object' ? appId.app_id : appId;
343
325
  const res = await this.request('GET', `/api/ai/apps/${encodeURIComponent(actualAppId)}/analytics/schema`);
@@ -345,35 +327,33 @@ class APIClient {
345
327
  return res;
346
328
  }
347
329
 
348
- // 自然语言 AI 生成仪表盘 (POST /api/dashboard)
330
+ // Natural language AI dashboard creation (POST /api/dashboard)
349
331
  async createAIDashboard(data) {
350
332
  const res = await this.request('POST', '/api/dashboard', data);
351
333
  if (typeof res === 'object') res.ok = true;
352
334
  return res;
353
335
  }
354
336
 
355
- // 获取项目业务上下文 (GET /api/apps/:appId/context) - 5秒超时
337
+ // Retrieve project business context (GET /api/apps/:appId/context) - 5s timeout
356
338
  async getProjectContext(appId) {
357
339
  const res = await this.request('GET', `/api/apps/${encodeURIComponent(appId)}/context`, null, { timeout: 5000 });
358
340
  if (typeof res === 'object') res.ok = true;
359
341
  return res;
360
342
  }
361
343
 
362
- // 上传/同步项目业务上下文 (PUT /api/apps/:appId/context) - 5秒超时
344
+ // Upload/sync project business context (PUT /api/apps/:appId/context) - 5s timeout
363
345
  async uploadProjectContext(appId, data) {
364
346
  const res = await this.request('PUT', `/api/apps/${encodeURIComponent(appId)}/context`, data, { timeout: 5000 });
365
347
  if (typeof res === 'object') res.ok = true;
366
348
  return res;
367
349
  }
368
350
 
369
- // 删除云端项目业务上下文 (DELETE /api/apps/:appId/context) - 5秒超时
351
+ // Delete project business context (DELETE /api/apps/:appId/context) - 5s timeout
370
352
  async deleteProjectContext(appId) {
371
- const res = await this.request('DELETE', `/api/apps/${encodeURIComponent(appId)}/context`, null, { timeout: 5000 });
372
- if (typeof res === 'object') res.ok = true;
373
- return res;
353
+ return this.request('DELETE', `/api/apps/${encodeURIComponent(appId)}/context`, null, { timeout: 5000 });
374
354
  }
375
355
 
376
- // 带重试的请求方法
356
+ // Request with exponential backoff retry for general methods
377
357
  async requestWithRetry(method, path, body = null, maxRetries = 2) {
378
358
  let lastErr = null;
379
359
  for (let attempt = 0; attempt <= maxRetries; attempt++) {