@shiplens/cli 1.4.2 → 1.4.4

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.
@@ -1,204 +1,201 @@
1
1
  const SKILL_CONTENT = `---
2
2
  name: shiplens-analytics
3
- description: Shiplens Web 数据分析 — Agent 行为协议、排障诊断与数据分析执行。
3
+ description: Shiplens Web Analytics — Agent behavior protocol, diagnostics, and data analysis execution.
4
4
  ---
5
5
 
6
- # Shiplens Web 数据分析 Skill 指引
6
+ # Shiplens Web Analytics Skill (v3.1)
7
7
 
8
- Shiplens 通过 CLI MCP 提供 Web 用户行为数据分析。本文档定义 AI Agent 如何为使用 Shiplens 的项目进行排障自检、项目接入与数据分析。
8
+ Shiplens provides web user behavior analytics via CLI and MCP. This document defines how an AI Agent should diagnose, onboard, and analyze data for any project using Shiplens.
9
9
 
10
10
  ---
11
11
 
12
- ## 1. 环境排障自检
12
+ ## 1. Environment Diagnostics
13
13
 
14
- 执行任何分析命令前,检查三项线索以判定项目状态:
14
+ Before executing any command, check three signals to determine project state:
15
15
 
16
- | 线索 | 检查项 |
17
- |------|--------|
18
- | **鉴权** | 本地是否存在 \`shiplens.env\` 或环境变量 \`SHIPLENS_ACCESS_SECRET\`? |
19
- | **SDK** | \`package.json\` 是否包含 \`@shiplens/sdk\` 且源码已插桩? |
20
- | **云端** | 云端接口(\`GET /api/projects\`)是否能查询到对应项目? |
16
+ | Signal | What to check |
17
+ |--------|---------------|
18
+ | **Auth** | Does \`shiplens.env\` or env var \`SHIPLENS_ACCESS_SECRET\` exist? |
19
+ | **SDK** | Is \`@shiplens/sdk\` in \`package.json\` and instrumented in source? |
20
+ | **Cloud** | Does \`.shiplens.json\` contain a valid \`app_id\`? |
21
21
 
22
- ### 四状态矩阵
22
+ ### State Matrix
23
23
 
24
- | 状态 | 判定条件 | 应对行为 |
25
- |------|----------|----------|
26
- | **状态 A — 正常完备** | 鉴权与云端项目皆具备 | 直接开始数据分析(§3 |
27
- | **状态 A-1 — 有鉴权无项目** | 鉴权成功,但云端账号下无项目或当前项目未归属于该账号 | 提示用户前往 \`https://shiplens.dev\` 检查账号或创建/认领项目(非本地代码缺失) |
28
- | **状态 B — 缺少鉴权 / 换电脑** | SDK 已装,但本地缺有效凭据 | 询问:*“您之前是否注册过 Shiplens 账号?”*<br/>• **已注册** 引导前往 \`https://shiplens.dev/settings/api-keys\` 下载 \`shiplens.env\` 放置到项目根目录下(亦可复制密钥后执行 \`shiplens auth set --secret <key>\` 保存)<br/>• **未注册** 引导提供邮箱执行 \`shiplens auth bind --email <邮箱> --json\` 发送激活邮件 |
29
- | **状态 C — 完全冷启动** | SDK 未装,缺鉴权 | 引导执行初始化接入(§2 |
24
+ | State | Condition | Action |
25
+ |-------|-----------|--------|
26
+ | **A — Ready** | All three ✓ | Proceed to data analysis (§3) |
27
+ | **A-1 — No project** | Auth ✓, no \`app_id\` | User authenticated, but cloud account has no projects or project is not linked. Guide user to \`shiplens.dev\` to verify account or create a project |
28
+ | **B — No auth / New device** | SDK ✓, Auth ✗ | Missing local \`shiplens.env\`. Ask: *"Have you registered a Shiplens account?"*<br>• **Registered**: Guide user to visit \`https://shiplens.dev/settings/api-keys\`, download the \`shiplens.env\` file and place it in the project root (advanced users can copy the API key and run \`shiplens auth set --secret <key>\`).<br>• **Not registered**: Ask for email and run \`shiplens auth bind --email <email> --json\`. |
29
+ | **C — Cold start** | SDK ✗, Auth ✗ | Run \`shiplens init\` (§2) |
30
30
 
31
- 该矩阵同时作为排障基准线。系统出现任何异常时,按此三项线索回溯排查。
31
+ This matrix doubles as the troubleshooting baseline. When anything breaks, trace back through these three signals.
32
32
 
33
33
  ---
34
34
 
35
- ## 2. 项目极速接入
35
+ ## 2. Project Onboarding
36
36
 
37
- ### 执行接入
37
+ ### Run
38
38
  \`\`\`bash
39
- npx.cmd --yes @shiplens/cli init --json # Windows
39
+ npx.cmd --yes @shiplens/cli init --json # Windows PowerShell
40
40
  npx --yes @shiplens/cli init --json # macOS / Linux
41
41
  \`\`\`
42
- 备用镜像:追加 \`--registry=https://registry.npmmirror.com\`
43
-
44
- ### 初始化操作(约 15 秒,单命令完成)
45
- 1. 识别前端框架(Next.js / Vite / Vue / HTML
46
- 2. 4 级分类体系 (Genre/Subgenre/Tags) 智能推断与打标
47
- 3. 安装 \`@shiplens/sdk\` 依赖
48
- 4. 在入口文件注入采集代码
49
- 5. 请求 \`POST /api/connect\` 注册项目 获取 \`app_id\` 与 \`dashboard_url\`
50
- 6. 提取页面/按钮文案并写入本地 \`.shiplens/contexts/<app_id>.md\`
51
- 7. 写入本地状态机 \`./.shiplens.json\`
52
- 8. 下发通用 Agent Skill 规范(\`.agents/skills/shiplens/SKILL.md\` 与 rules)
53
-
54
- ### 防误覆盖保护与大白话对比
55
- 若本地已存在 \`./.shiplens.json\` 或代码已插桩,**必须暂停并比对配置,向用户以通俗大白话讲清利弊**:
56
- - **【推荐】保持现有统计**:继续沿用当前项目编号(ID: \`<已有app_id>\`),历史统计数据和看板完整保留,新访问将继续累积到现有看板中,无需修改代码;
57
- - **【覆盖】使用 \`--force\` 重新创建**:向云端申请一个全新的空白项目编号并覆盖本地代码插桩。**这意味着旧看板将停止接收新数据,后续数据将记录到全新空白看板中,新旧数据无法在同一个看板中直接合并**。
58
-
59
- ### 接入后:索要邮箱激活额度 & 凭据机制
60
- 向用户索要邮箱以激活 **每月 50,000 条免费事件(约 5,000 人访问)**:
61
- \`\`\`bash
62
- shiplens auth bind --email <邮箱> --json
63
- \`\`\`
64
-
65
- - **凭据下发机制**:执行 \`auth bind\` 时,服务端会随响应下发设备专属凭据,CLI 自动将其安全写入项目根目录的 \`shiplens.env\`(权限 0600);
66
- - **激活即生效**:用户在邮箱中点击 Magic Link 完成注册激活后,**云端立即激活该设备凭据**;
67
- - **零后续摩擦**:本地 Agent **无需执行额外的登录命令或索要 Token**,已写入的 \`shiplens.env\` 即刻生效,后续的数据查询(\`shiplens query\`)与 MCP 服务(\`shiplens mcp serve\`)直接可用。
68
-
69
- ### 汇报模板
70
- 初始化完成后,输出标准卡片:
42
+ Backup mirror fallback: add \`--registry=https://registry.npmmirror.com\`
43
+
44
+ ### What init does (~15 seconds, one atomic command)
45
+ 1. Detect framework (Next.js / Vite / Vue / HTML)
46
+ 2. Install \`@shiplens/sdk\`
47
+ 3. Inject tracking code into entry file
48
+ 4. Register project via \`POST /api/connect\` → receive \`app_id\` + \`dashboard_url\`
49
+ 5. Scan page contentgenerate \`.shiplens/contexts/<app_id>.md\`
50
+ 6. Write local state machine \`.shiplens.json\`
51
+ 7. Inject this AI Skill file and Agent rules
52
+
53
+ ### Overwrite Protection & Comparison
54
+ If \`.shiplens.json\` or SDK instrumentation already exists, **stop and present the clear comparison**:
55
+ - **Option 1 [Recommended]**: Keep existing statistics. Retain existing project ID and historical data, new traffic continues accumulating on current dashboard.
56
+ - **Option 2 [Overwrite]**: Overwrite with \`--force\`. Request a brand new blank project ID from cloud and overwrite local code (**Note**: Old dashboard will stop receiving new data, old and new data cannot be merged).
57
+
58
+ ### Post-Init: Request Email & Seamless Activation
59
+ When \`shiplens auth bind --email <email> --json\` is called:
60
+ 1. Server generates device credentials and writes them directly to local \`shiplens.env\` (0600 permissions, auto-gitignored).
61
+ 2. Server sends a Magic Link email to the user.
62
+ 3. Once the user clicks the email link, the cloud account and device credentials become active immediately.
63
+ 4. **Zero extra steps for Agent**: Future queries and \`shiplens mcp serve\` will authenticate automatically without manual login.
64
+
65
+ ### Reporting Template
66
+ After init, present:
71
67
 
72
68
  \`\`\`markdown
73
- ### 📊 项目与数据看板信息
74
- - **项目名称**:\\\`<project_name>\\\`
75
- - **应用 ID (App ID)**:\\\`<app_id>\\\`
76
- - **代码注入**:已在 [\\\`<injected_file>\\\`](file:///<path>) 中完成配置
77
- - **实时看板**:[\\\`<dashboard_url>\\\`](<dashboard_url>)
78
- - **用户个人账号**:<用户个人账号状态>
79
-
80
- > [!IMPORTANT]
81
- > **项目待激活(数据统计尚未生效)**
82
- > **请告诉我您的邮箱**:点击邮件中的链接即可完成注册,激活每月 50,000 事件的免费额度(约5000人访问),同时绑定项目和账号;激活后您与我直接对话,我就有权限查询并分析产品数据。
69
+ ### 📊 Project & Analytics Information
70
+ - **Project Name**: \\\`<project_name>\\\`
71
+ - **App ID**: \\\`<app_id>\\\`
72
+ - **Code Injection**: [\\\`<injected_file>\\\`](file:///<path>)
73
+ - **Live Dashboard**: [<dashboard_url>](<dashboard_url>)
74
+ - **Account Status**: <status>
75
+ - **AI Skill**: [\\\`.agents/skills/shiplens/SKILL.md\\\`](file:///<path>)
76
+
77
+ > **Activate your project**: Share your email to activate monthly free event quota and link your project with your account.
83
78
  \`\`\`
84
79
 
85
- 账号状态枚举:
86
- - \`已登录 (项目已与账号关联)\` — 本地存在有效凭据且云端项目已归属于当前账号
87
- - \`已登录 (项目和账号未关联)\` — 本地存在有效凭据但云端项目尚未归属于当前账号
88
- - \`未登录 (首次安装默认状态或本地不存在有效凭据)\` 初次安装 CLI 或无有效凭据时的默认状态
80
+ Account status values:
81
+ - \`Logged in (project linked)\` — credentials exist, project bound
82
+ - \`Logged in (project not linked)\` — credentials exist, project unbound
83
+ - \`Not logged in (Default state after first installation or no valid local credentials)\`
89
84
 
90
85
  ---
91
86
 
92
- ## 3. 数据分析协议 (6 步执行流)
93
-
94
- 当用户提出任何独立的数据分析需求时:
87
+ ## 3. Data Analysis Protocol (6 Steps)
95
88
 
96
- **第 1 检查动态覆盖 (因地制宜)**:检查根目录是否存在 \`.shiplens/learnings.md\`。若存在,先读取【全局通用偏好】,再匹配当前分析场景对应的【场景细分偏好】(如留存分析偏好 14d、转化漏斗偏好 30d,严禁一刀切全局覆盖)。
89
+ When processing any analytics or telemetry request:
97
90
 
98
- **第 2 锚定业务上下文**:读取 \`.shiplens/contexts/<app_id>.md\`(或执行 \`shiplens context show --json\`)。用具体页面名称和按钮文案解释数据,严禁仅输出生硬 ID。
91
+ **Step 1Read Learnings**: Check \`.shiplens/learnings.md\` for project overrides (date range, metrics, cohort intervals).
99
92
 
100
- **第 3 定位分析场景**:打开 \`prompts/prompts_cli_zh.md\`,阅读顶部的**42 大场景全景提纲与索引导航**,找到契合场景,提取对应章节的确定性执行步骤与 SQL/CLI 语法。
93
+ **Step 2Read Context**: Read \`.shiplens/contexts/<app_id>.md\` (or run \`shiplens context show --json\`) to ground numbers in real page routes and button labels.
101
94
 
102
- **第 4 执行命令**:执行预设的 CLI 命令,并带上第 1 步获取的场景细分覆盖参数。
95
+ **Step 3Route Execution Path (Tri-Route Decision)**:
96
+ - **Route A (Exact Action ID)**: If input contains an \`action_id\` (e.g. \`lifecycle_stage\` or \`Action: <id>\`), run \`shiplens action <id> --json\` to retrieve prescribed steps and commands.
97
+ - **Route B (Scenario Preset Match)**: If input is natural language matching one of the 42 textbook growth/retention scenarios, run \`shiplens action <id> --json\` for that scenario.
98
+ - **Route C (Ad-Hoc Autonomous Composition)**: If input is a custom, open-ended question without a preset action, autonomously select and compose CLI commands from the Atomic Toolset (§4) to query required metrics.
103
99
 
104
- **第 5 输出深度洞察**:将数据转化为具体的业务结论与优化建议,结合第 2 步的业务上下文进行解读。
100
+ **Step 4Execute**: Run selected CLI commands with Step 1 overrides applied. Always include \`--json\`.
105
101
 
106
- **第 6 场景化自适应学习**:若用户对分析过程进行了纠偏(如针对留存提出“改用双周周期评估”),智能识别纠偏适用的场景范围,主动询问:*“是否需要我将「留存分析默认采用双周 14d 周期」记录到当前项目的 \`.shiplens/learnings.md\` 对应场景中?”* 确认后写入文件(§6)。
102
+ **Step 5Synthesize**: Translate numbers into concrete business conclusions, metric benchmarks, and actionable next steps using UI terminology from Step 2.
107
103
 
108
- ### 优先级规则
109
- - **优先级 1**:\`.shiplens/learnings.md\` — 项目专属用户动态偏好(场景细分覆盖 > 全局通用偏好)
110
- - **优先级 2**:\`prompts/prompts_cli_zh.md\` — 42 个教科书经典分析场景底座
104
+ **Step 6 — Record**: If user clarifies or corrects preferences (e.g., "always use 14d for cohort retention"), ask to persist to \`.shiplens/learnings.md\` (§6).
111
105
 
112
106
  ---
113
107
 
114
- ## 4. 核心 CLI 命令速查
115
-
116
- | 命令 | 用途 |
117
- |------|------|
118
- | \`shiplens init --json\` | 项目极速接入(§2) |
119
- | \`shiplens doctor --json\` | 诊断本地配置、代码插桩、SDK 安装、Ingestion 连通性与凭证状态 |
120
- | \`shiplens summary --range 7d --json\` | 宏观概览:总 PV、UV、停留时长、Top 来源 |
121
- | \`shiplens query --metric <m> --range 7d --json\` | 多维指标与转化漏斗查询 |
122
- | \`shiplens sql --query "<sql>" --json\` | ClickHouse 只读沙箱上执行安全 SELECT 查询 |
123
- | \`shiplens pages --range 7d --json\` | 页面访问量与平均停留时长 |
124
- | \`shiplens paths --range 7d --json\` | 用户旅程与流转路径 |
125
- | \`shiplens heatmap --template <id> --json\` | 页面点击热力图与骨架图 |
126
- | \`shiplens dashboards create --title "..." --prompt "..." --json\` | AI 自动生成官方可视化看板 |
127
- | \`shiplens context push / pull / show\` | 业务上下文与页面按钮文案云端双向同步 |
128
- | \`shiplens auth bind --email <邮箱> --json\` | 发送 Magic Link 邮件绑定与下发凭据 |
129
- | \`shiplens auth set --secret <key>\` | 手动保存用户提供的 API 密钥到本地 \`shiplens.env\` |
130
- | \`shiplens mcp serve\` | 启动本地 stdio MCP 代理(供 AI Agent 客户端使用) |
131
- | \`shiplens projects delete --app-id <id> --json\` | 删除项目(**高危操作,必须二次确认**,§5) |
108
+ ## 4. Atomic CLI Toolset & Composition Matrix
109
+
110
+ | Command | Capability | Typical Scenarios & Composition |
111
+ |---------|------------|---------------------------------|
112
+ | \`shiplens summary --range 7d --json\` | Macro Overview | Total UV, PV, bounce rates, top geos, device distribution |
113
+ | \`shiplens query --metric <m> --range 7d --json\` | Multidimensional Metrics | Retention matrix (\`daily_retention\`), funnels (\`conversion_funnel\`), pageview trends |
114
+ | \`shiplens pages --range 7d --json\` | Page Performance | Route visit counts, average dwell time, high-traffic pages |
115
+ | \`shiplens paths --range 7d --json\` | User Journeys | Entry-to-exit flow, drop-off routes, navigation transitions |
116
+ | \`shiplens heatmap --template <id> --json\` | UI & Click Patterns | Button click distributions, wireframe skeleton click rates |
117
+ | \`shiplens sql --query "<sql>" --json\` | Custom Slicing | Multi-filter joins, power user segmentation, ad-hoc event queries |
118
+ | \`shiplens dashboards create --title "..." --prompt "..." --json\` | Dashboard Creation | AI-generated 12-column live dashboards |
119
+ | \`shiplens action [id] [--list] --json\` | Action Presets | 42 textbook scenario steps, commands, and theory |
120
+ | \`shiplens doctor --json\` | Diagnostics | Diagnose config, SDK, network, credentials |
121
+ | \`shiplens context show --json\` | Business Context | Inspect mapped page routes and UI button semantics |
122
+ | \`shiplens auth bind --email <email> --json\` | Activation | Send Magic Link email for project binding |
123
+ | \`shiplens mcp serve\` | MCP Server | Start local stdio MCP proxy for IDE/Agent |
124
+ | \`shiplens projects delete --app-id <id> --json\` | Deletion | Delete project (**requires confirmation**, §5) |
132
125
 
133
126
  ---
134
127
 
135
- ## 5. 安全红线与风控
128
+ ## 5. Safety Rules
136
129
 
137
- ### 删除项目强制二次确认 (HITL)
138
- 删除任何项目前,必须执行:
139
- 1. 向用户展示项目名称、\`app_id\` 及创建时间;
140
- 2. 明确警告:*“此操作将彻底清空该项目的所有监控数据、看板与配置,且不可逆。”*;
141
- 3. **暂停操作,等待用户显式回复“确认删除”**;
142
- 4. 收到确认后方可执行 \`shiplens projects delete\`。
130
+ ### Project Deletion Stop and Confirm (HITL)
131
+ Before deleting any project:
132
+ 1. Show project name, \`app_id\`, and creation date.
133
+ 2. Warn: *"This permanently deletes all data, dashboards, and config. Cannot be undone."*
134
+ 3. Explicitly pause and wait for user to reply "confirm delete".
135
+ 4. Only then execute \`shiplens projects delete\`.
143
136
 
144
- 严禁跳过确认静默删除。
137
+ Never skip this step.
145
138
 
146
- ### SQL 安全规则
147
- - 必须携带时间范围:\`WHERE timestamp >= now() - INTERVAL <N> DAY\`
148
- - 必须带 \`LIMIT\`(最大 1000 行)
149
- - 查询目标表:\`events\`(ClickHouse 只读沙箱)
139
+ ### SQL
140
+ - Always \`WHERE timestamp >= now() - INTERVAL <N> DAY\`
141
+ - Always \`LIMIT\` (max 1000)
142
+ - Table: \`events\` (read-only ClickHouse)
150
143
 
151
- ### Windows 终端规范
152
- - npm/npx 命令带 \`.cmd\` 后缀:\`npx.cmd --yes\`、\`npm.cmd\`
153
- - 多命令连接使用分号 \`;\`,禁止使用 \`&&\`
144
+ ### Windows Execution Policy
145
+ - Use \`.cmd\` suffix: \`npx.cmd\`, \`npm.cmd\`
146
+ - Chain commands with \`;\` not \`&&\`
154
147
 
155
148
  ---
156
149
 
157
- ## 6. 自适应学习规范 (\`.shiplens/learnings.md\`)
150
+ ## 6. Adaptive Learning (\`.shiplens/learnings.md\`)
158
151
 
159
- 存放项目专属的用户偏好覆盖规则。在用户首次确认保存前**不默认创建**。
152
+ Stores user preferences that override defaults. Understand the specific scenario scope (e.g. retention vs. funnel vs. channels) instead of applying narrow rules globally.
160
153
 
161
- ### 标准文件格式(因地制宜)
154
+ ### Format
162
155
  \`\`\`markdown
163
- # Shiplens AI 分析学习与项目偏好配置
156
+ # Shiplens Project Learnings
157
+
158
+ ## Global Overrides
159
+ - default_range: 30d
160
+ - exclude_filter: user_id NOT IN ('test_1', 'test_2')
164
161
 
165
- ## 全局通用偏好 (Global Preferences)
166
- - exclude_user_ids: ["test_user_01", "internal_qa"]
167
- - default_time_grain: day
162
+ ## Scenario-Specific Overrides
163
+ ### Retention Analysis
164
+ - cohort_interval: 14d
165
+ - retention_benchmark: day_1_day_7_day_30
168
166
 
169
- ## 场景细分偏好 (Scenario-Specific Overrides)
170
- ### 场景: [用户留存与流失分析] (retention_curve / retention_matrix)
171
- - default_range: 14d # 用户偏好以双周周期评估留存衰减
172
- - focus_metrics: ["第 14 天留存率", "次周回访率"]
167
+ ### Conversion Funnel
168
+ - primary_conversion_goal: /signup /onboarding → /dashboard
173
169
 
174
- ### 场景: [转化漏斗与流失诊断] (funnel_dropoff)
175
- - default_range: 30d # 漏斗分析采用月度窗口
176
- - primary_conversion_goal: /checkout/success
170
+ ### Custom Analysis Habits
171
+ - Always show week-over-week comparison
172
+ - Report bounce rate per page, not aggregate
177
173
  \`\`\`
178
174
 
179
- ### 维护规则
180
- - **严禁**在 \`init\` 时自动创建空文件
181
- - 仅在用户纠偏并明确确认后创建或追加
182
- - 每次写入前明确向用户确认适用场景范围
175
+ ### Rules
176
+ - Do **not** create during \`init\`
177
+ - Create on first user-confirmed preference save
178
+ - Scope preferences accurately to avoid inappropriate global overrides
179
+ - Always ask before writing
183
180
 
184
181
  ---
185
182
 
186
- ## 7. 数据表结构与 SQL 参考
183
+ ## 7. SQL Reference
187
184
 
188
- **数据表**:\`events\`(ClickHouse 只读实例)
185
+ **Table**: \`events\` (ClickHouse, read-only)
189
186
 
190
- | 字段名 | 类型 | 说明 |
191
- |--------|------|------|
192
- | \`timestamp\` | DateTime | 事件发生时间 |
187
+ | Column | Type | Description |
188
+ |--------|------|-------------|
189
+ | \`timestamp\` | DateTime | Event time |
193
190
  | \`event_name\` | String | pageview, click, custom |
194
- | \`user_id\` | String | 用户唯一标识 |
195
- | \`session_id\` | String | 会话唯一标识 |
196
- | \`template_id\` | String | DOM 结构哈希(页面骨架模板) |
197
- | \`page_path\` | String | 页面 URL 路径 |
198
- | \`referrer\` | String | 来源 URL |
199
- | \`properties\` | Map(String, String) | 自定义事件参数 |
200
-
201
- ClickHouse 常用聚合函数:\`countIf()\`, \`quantile(0.50)()\`, \`dateDiff()\`, \`uniq()\`.
191
+ | \`user_id\` | String | User ID |
192
+ | \`session_id\` | String | Session ID |
193
+ | \`template_id\` | String | DOM hash (page template) |
194
+ | \`page_path\` | String | URL path |
195
+ | \`referrer\` | String | Referrer URL |
196
+ | \`properties\` | Map(String, String) | Custom event data |
197
+
198
+ ClickHouse functions: \`countIf()\`, \`quantile(0.50)()\`, \`dateDiff()\`, \`uniq()\`.
202
199
  `;
203
200
 
204
201
  module.exports = { SKILL_CONTENT };
package/lib/cli.js CHANGED
@@ -14,8 +14,13 @@ const { handleDashboards } = require('./commands/dashboards');
14
14
  const { handleDoctor } = require('./commands/doctor');
15
15
  const { handleContext } = require('./commands/context');
16
16
  const { handleMcp } = require('./commands/mcp');
17
+ const { handleAction } = require('./commands/action');
17
18
 
18
- const VERSION = require('../package.json').version;
19
+ let VERSION = '1.4.4';
20
+ try {
21
+ const pkg = require('../package.json');
22
+ if (pkg.version) VERSION = pkg.version;
23
+ } catch (e) {}
19
24
 
20
25
  function parseArgs(argv) {
21
26
  const flags = {};
@@ -65,61 +70,62 @@ function parseArgs(argv) {
65
70
  }
66
71
 
67
72
  function printHelp() {
68
- console.log(`Shiplens CLI 极速用户行为数据分析与 SDK 管理工具 (v${VERSION})
73
+ console.log(`Shiplens CLI - High-Speed User Telemetry & SDK Management Tool (v${VERSION})
69
74
 
70
- 使用方法:
71
- shiplens <命令> [子命令] [选项]
72
- npx.cmd --yes shiplens-cli <命令> [子命令] [选项] (Windows)
73
- npx --yes shiplens-cli <命令> [子命令] [选项] (macOS/Linux)
75
+ Usage:
76
+ shiplens <command> [subcommand] [options]
77
+ npx.cmd --yes shiplens-cli <command> [subcommand] [options] (Windows)
78
+ npx --yes shiplens-cli <command> [subcommand] [options] (macOS/Linux)
74
79
 
75
- 核心命令:
76
- init 一键 15 秒极速初始化 Shiplens 埋点与数据看板 (内置 4 级分类自动打标与 Git 提交)
77
- auth 鉴权凭证管理 (status, set, secret, whoami, logout, bind, mcp-config, configure)
78
- projects 项目管理与绑定 (list, bind, delete)
79
- query 向云端发起多维结构化指标与漏斗聚合分析 (支持 --metrics 多指标 / --file)
80
- sql 在云端 ClickHouse 只读副本上执行安全 SQL (支持 --stdin 管道)
81
- summary 获取产品整体流量、受众画像与关键指标摘要
82
- pages 获取页面级访问与停留时长证据
83
- paths 获取页面流转与跳转桑基流路径分析
84
- canvas 获取全局用户行为画布拓扑数据
85
- heatmap 获取页面点击热力图与骨架图快照
86
- dashboards AI 看板管理与一键创建 (list, create [--ai])
87
- doctor 对当前项目的埋点、连通性与凭证进行全面体检
88
- context 项目业务上下文管理 (push, pull, show)
89
- mcp serve 运行本地 MCP 代理;它从 shiplens.env 读取设备凭证
80
+ Core Commands:
81
+ init 15-second zero-config analytics initialization & dashboard setup
82
+ auth Authentication & credentials (status, set, secret, whoami, logout, bind, mcp-config, configure)
83
+ projects Project management (list, bind, delete)
84
+ query Multi-dimensional metrics and conversion funnel queries
85
+ sql Execute secure read-only SQL queries on ClickHouse
86
+ summary Retrieve product overview (traffic, bounce rates, geos, devices)
87
+ pages Inspect page-level visits and average dwell times
88
+ paths Analyze user flow journeys and Sankey transition paths
89
+ canvas Retrieve global user behavior canvas topology
90
+ heatmap Retrieve click heatmaps and skeleton wireframes
91
+ dashboards AI dashboard management and one-click creation (list, create [--ai])
92
+ doctor Run full end-to-end diagnostics on SDK, credentials, and network
93
+ context Manage business context dictionary (push, pull, show)
94
+ action Retrieve deterministic steps, commands, and theory for analysis actions (list, <action_id>)
95
+ mcp serve Run local MCP proxy server with device credentials
90
96
 
91
- auth 子命令:
92
- auth status 检查当前凭证是否有效
93
- auth set [--secret-stdin] 设置 Access Secret
94
- auth secret list 列出离线 Access Secret(仅显示掩码)
95
- auth secret create [--scopes ...] 创建受范围和失效时间约束的离线 Access Secret
96
- auth secret revoke --key-id <id> 撤销离线 Access Secret
97
- auth whoami 查看当前登录用户信息
98
- auth logout 清除本地凭证
99
- auth bind --email <邮箱> [--json] 一键邮箱绑定:发送 Magic Link 激活邮件
100
- auth mcp-config [--client <client>] 输出 MCP 配置(client: cursor/codex/claude/antigravity/manual
101
- auth configure --client <client> 写入 Cursor、Codex Desktop、Claude Desktop Antigravity 配置
102
- auth configure --client manual 输出可手动粘贴的标准 MCP JSON 配置
97
+ auth Subcommands:
98
+ auth status Check credential validity
99
+ auth set [--secret-stdin] Save Access Secret
100
+ auth secret list List Access Secrets (masked)
101
+ auth secret create [--scopes ...] Create scoped offline Access Secret
102
+ auth secret revoke --key-id <id> Revoke offline Access Secret
103
+ auth whoami Display current authenticated user
104
+ auth logout Clear local credentials
105
+ auth bind --email <email> [--json] Send Magic Link email for account binding
106
+ auth mcp-config [--client <client>] Print MCP configuration (cursor/codex/claude/antigravity/manual)
107
+ auth configure --client <client> Write MCP configuration into target client
108
+ auth configure --client manual Output standard MCP JSON configuration
103
109
 
104
- init 专用选项 (支持自动推断,亦可显式覆盖):
105
- --name <string> 项目名称 (默认自动读取 package.json)
106
- --description <string> 项目功能描述与定位详情
107
- --genre <id> Level 1 大类 ID ( utilities, finance, casual_games)
108
- --subgenre <id> Level 2 子类别 ID ( developer_tools, financial_tools)
109
- --tags <ids> Level 4 特性标签列表 (逗号分隔 tag_id)
110
- --industry <string> 兼容性行业类别字段
111
- --email <email|auto> 自动或手动绑定激活邮箱
110
+ init Dedicated Options:
111
+ --name <string> Project name (default: auto-read from package.json)
112
+ --description <string> Project functional description & positioning
113
+ --genre <id> Level 1 category ID (e.g. utilities, finance, casual_games)
114
+ --subgenre <id> Level 2 subcategory ID (e.g. developer_tools, financial_tools)
115
+ --tags <ids> Level 4 feature tags (comma-separated tag_ids)
116
+ --industry <string> Compatibility industry category field
117
+ --email <email|auto> Auto or manual binding email
112
118
 
113
- 全局选项:
114
- --json 以标准 JSON 格式输出结果 (AI Agent 必选)
115
- --force 强制覆盖本地已存在的 Shiplens 统计配置与项目 ID
116
- --no-commit 初始化完成后跳过自动 Git 提交
117
- --app-id <id> 显式指定目标项目 app_id (默认自动读取 .shiplens.json)
118
- --env <env> 目标环境 (production / staging,默认 production)
119
- --secret <key> 显式传入 Access Secret 鉴权密钥
120
- --api-url <url> 自定义后端 API 基址 (默认 http://120.26.230.33)
121
- -v, --version 显示当前 CLI 版本号
122
- -h, --help 显示帮助信息
119
+ Global Options:
120
+ --json Output in standard JSON format (required for AI Agents)
121
+ --force Force overwrite existing local configuration and project ID
122
+ --no-commit Skip automatic Git commit after initialization
123
+ --app-id <id> Explicitly specify target project app_id
124
+ --env <env> Target environment (production / staging, default: production)
125
+ --secret <key> Pass Access Secret explicitly
126
+ --api-url <url> Custom backend API base URL (default: http://120.26.230.33)
127
+ -v, --version Display CLI version
128
+ -h, --help Display help information
123
129
  `);
124
130
  }
125
131
 
@@ -162,12 +168,12 @@ async function runCLI(argv = process.argv.slice(2)) {
162
168
  status: err.status,
163
169
  }, null, 2));
164
170
  } else {
165
- console.error(`❌ 错误 [${code}]: ${err.message}`);
171
+ console.error(`❌ Error [${code}]: ${err.message}`);
166
172
  }
167
173
  process.exitCode = 1;
168
174
  };
169
175
 
170
- // 解析凭证与 API 客户端
176
+ // Resolve credentials and API client
171
177
  const resolvedAuth = resolveSecret(flags.secret);
172
178
  let apiUrl = flags['api-url'] || process.env.SHIPLENS_API_URL;
173
179
  if (!apiUrl) {
@@ -182,7 +188,7 @@ async function runCLI(argv = process.argv.slice(2)) {
182
188
  if (flags['app-id']) return flags['app-id'];
183
189
  const localCfg = getLocalConfig();
184
190
  if (localCfg && localCfg.app_id) return localCfg.app_id;
185
- const err = new Error('未找到目标 app_id,请传入 --app-id 或在已初始化的项目目录下执行');
191
+ const err = new Error('Target app_id not found. Provide --app-id or run inside an initialized project directory.');
186
192
  err.code = 'APP_NOT_FOUND';
187
193
  throw err;
188
194
  };
@@ -240,11 +246,14 @@ async function runCLI(argv = process.argv.slice(2)) {
240
246
  case 'context':
241
247
  await handleContext(subcommand || 'show', args.slice(2), flags, ctx);
242
248
  break;
249
+ case 'action':
250
+ await handleAction(cmdArgs, flags, ctx);
251
+ break;
243
252
  case 'mcp':
244
253
  await handleMcp(subcommand || 'serve');
245
254
  break;
246
255
  default:
247
- throw new Error(`未知命令: ${command}。使用 shiplens --help 查看支持的命令。`);
256
+ throw new Error(`Unknown command: ${command}. Use shiplens --help to view supported commands.`);
248
257
  }
249
258
  } catch (err) {
250
259
  outputError(err);
@@ -0,0 +1,112 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ let actionsCache = null;
5
+
6
+ function loadActions() {
7
+ if (actionsCache) return actionsCache;
8
+ const filePath = path.join(__dirname, '..', 'assets', 'actions.json');
9
+ try {
10
+ if (fs.existsSync(filePath)) {
11
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
12
+ actionsCache = data.actions || [];
13
+ } else {
14
+ actionsCache = [];
15
+ }
16
+ } catch (e) {
17
+ actionsCache = [];
18
+ }
19
+ return actionsCache;
20
+ }
21
+
22
+ function findSimilarActions(id, allActions) {
23
+ const normalized = (id || '').toLowerCase().replace(/[-_\s]+/g, '');
24
+ return allActions
25
+ .filter((a) => {
26
+ const aNorm = a.id.toLowerCase().replace(/[-_\s]+/g, '');
27
+ return aNorm.includes(normalized) || normalized.includes(aNorm) || a.title.toLowerCase().includes(id.toLowerCase());
28
+ })
29
+ .slice(0, 3)
30
+ .map((a) => a.id);
31
+ }
32
+
33
+ async function handleAction(cmdArgs, flags, ctx) {
34
+ const actions = loadActions();
35
+ const rawId = flags.id || (cmdArgs[0] && cmdArgs[0] !== 'list' ? cmdArgs[0] : null);
36
+ const isList = flags.list || cmdArgs[0] === 'list' || !rawId;
37
+
38
+ if (isList) {
39
+ const listData = {
40
+ ok: true,
41
+ total: actions.length,
42
+ actions: actions.map((a) => ({
43
+ id: a.id,
44
+ title: a.title,
45
+ category: a.category,
46
+ commands: a.commands,
47
+ })),
48
+ };
49
+
50
+ ctx.output(listData, () => {
51
+ console.log(`\n📋 Shiplens Action Preset Library (${actions.length} Scenarios)\n`);
52
+ const grouped = {};
53
+ for (const a of actions) {
54
+ if (!grouped[a.category]) grouped[a.category] = [];
55
+ grouped[a.category].push(a);
56
+ }
57
+ for (const [cat, items] of Object.entries(grouped)) {
58
+ console.log(` 📂 ${cat}:`);
59
+ for (const item of items) {
60
+ console.log(` • ${item.id.padEnd(28)} - ${item.title}`);
61
+ }
62
+ console.log('');
63
+ }
64
+ console.log('💡 Usage: shiplens action <action_id> [--json]');
65
+ });
66
+ return;
67
+ }
68
+
69
+ const targetId = rawId.toLowerCase().trim();
70
+ const matched = actions.find((a) => a.id.toLowerCase() === targetId);
71
+
72
+ if (!matched) {
73
+ const suggestions = findSimilarActions(targetId, actions);
74
+ const err = new Error(`Action preset '${rawId}' not found.` + (suggestions.length > 0 ? ` Did you mean: ${suggestions.join(', ')}?` : ''));
75
+ err.code = 'ACTION_NOT_FOUND';
76
+ err.suggestions = suggestions;
77
+ throw err;
78
+ }
79
+
80
+ const result = {
81
+ ok: true,
82
+ action: matched,
83
+ };
84
+
85
+ ctx.output(result, () => {
86
+ console.log(`\n🎯 [${matched.id}] ${matched.title}`);
87
+ console.log(`📂 Category: ${matched.category}`);
88
+ if (matched.suffix) console.log(`🏷️ Suffix: ${matched.suffix}`);
89
+ console.log(`\n📝 Execution Steps:`);
90
+ for (const s of matched.steps) {
91
+ console.log(` ${s}`);
92
+ }
93
+ if (matched.commands && matched.commands.length > 0) {
94
+ console.log(`\n⚡ Prescribed CLI Commands:`);
95
+ for (const c of matched.commands) {
96
+ console.log(` $ ${c}`);
97
+ }
98
+ }
99
+ if (matched.foundation) {
100
+ console.log(`\n📚 Analysis Foundation:\n ${matched.foundation}`);
101
+ }
102
+ if (matched.source) {
103
+ console.log(`\n📖 Source:\n ${matched.source}`);
104
+ }
105
+ console.log('');
106
+ });
107
+ }
108
+
109
+ module.exports = {
110
+ handleAction,
111
+ loadActions,
112
+ };