@thinkingai/ae-cli 1.0.15 → 1.0.18

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.
Files changed (31) hide show
  1. package/README.md +23 -24
  2. package/README.zh.md +21 -22
  3. package/dist/auth-2UTBG5U3.js +144 -0
  4. package/dist/{auth-4GAHTBVH.js → auth-ECD46NBA.js} +6 -4
  5. package/dist/{chunk-UK6HO5O5.js → chunk-4KQ7H7DY.js} +13 -1
  6. package/dist/{chunk-TJIMDNAU.js → chunk-7QBNU44L.js} +101 -3
  7. package/dist/{chunk-OQ4XEG77.js → chunk-LAAS6ITR.js} +2 -2
  8. package/dist/{chunk-EBFUVWIZ.js → chunk-MR57UIKC.js} +42 -0
  9. package/dist/{client-HU63573O.js → client-O56G2SNJ.js} +3 -3
  10. package/dist/{config-OLF7RBPM.js → config-BU5FHGGE.js} +20 -5
  11. package/dist/index.js +13 -13
  12. package/dist/{raw-GDO4IWNW.js → raw-A3VN2B6I.js} +3 -3
  13. package/dist/{te-analysis-ZDJXMWZY.js → te-analysis-UGKESPBE.js} +3 -3
  14. package/dist/{te-audience-T5B52EEB.js → te-audience-THZNVHYB.js} +3 -3
  15. package/dist/{te-common-BPTXXTHQ.js → te-common-QZOUME3S.js} +3 -3
  16. package/dist/{te-community-FPB5LH56.js → te-community-AZVW3NFX.js} +3 -3
  17. package/dist/{te-dataops-2NUJVG47.js → te-dataops-OE5PX2K6.js} +3 -3
  18. package/dist/{te-engage-K3EANZ5P.js → te-engage-RYGEQTYK.js} +3 -3
  19. package/dist/{te-meta-JJMV75KB.js → te-meta-MGO5BCMG.js} +6 -4
  20. package/package.json +1 -1
  21. package/skills/ae-analysis/SKILL.md +58 -0
  22. package/skills/ae-analysis/references/generate_track_program.md +8 -8
  23. package/skills/ae-analysis/references/list_alerts.md +4 -0
  24. package/skills/ae-analysis/references/list_clusters.md +4 -0
  25. package/skills/ae-analysis/references/list_dashboards.md +4 -0
  26. package/skills/ae-analysis/references/list_events.md +4 -0
  27. package/skills/ae-analysis/references/list_metrics.md +4 -0
  28. package/skills/ae-analysis/references/list_reports.md +4 -0
  29. package/skills/ae-analysis/references/list_tags.md +4 -0
  30. package/skills/ae-analysis/references/query_adhoc.md +10 -0
  31. package/dist/auth-U2GHFMFY.js +0 -81
package/README.md CHANGED
@@ -86,14 +86,18 @@ ae-cli auth logout
86
86
 
87
87
  | Domain | Commands | Description |
88
88
  |--------|----------|-------------|
89
- | `analysis` | 31 | Analysis workflows: alerts, reports, dashboards, ad-hoc/drilldown, clusters/tags, metadata/metrics, project tools, entity details, analysis schema |
90
- | `analysis_audience` | 14 | Audience operations: clusters, tags, and cluster/tag definition schema |
91
- | `analysis_meta` | 20 | Metadata governance: events/properties, metrics, virtual metadata, project config, tracking plan, mark times, resource links |
89
+ | `analysis` | 30+ | Analysis workflows: alerts, reports, dashboards, ad-hoc/drilldown, entity/event details, analysis schema |
90
+ | `analysis_audience` | 10+ | Audience operations: clusters, tags, and cluster/tag definition schema |
91
+ | `analysis_meta` | 20+ | Metadata governance: events/properties, metrics, virtual metadata, project config, tracking plan, mark times, entity catalog |
92
92
  | `engage` | 40+ | Hermes Engage MCP: channels, tasks, configs, flows, strategies |
93
- | `te_dataops` | 50+ | Data warehouse management: repos, datatables, flows, IDE queries, integration, operations |
94
- | `te_community` | 30+ | Community analysis: posts search, sentiment analysis, topic trends, livestream data |
93
+ | `dataops_repo` | 8 | Data warehouse repos: spaces, catalogs, schemas, members |
94
+ | `dataops_datatable` | 10+ | Data tables: table creation, views, batch operations, data dictionary |
95
+ | `dataops_flow` | 20+ | Task flows: flow creation, task nodes, scheduling, execution, monitoring |
96
+ | `dataops_ide` | 10+ | IDE queries: metadata browsing, SQL execution, query management |
97
+ | `dataops_integration` | 20+ | Data integration: datasource management, sync solutions, data synchronization |
98
+ | `community` | 10+ | Community analysis: posts search, sentiment analysis, topic trends, livestream data |
95
99
  | `analysis_common` | 2 | Cross-module common constraints: resource link completion, project ID gate |
96
- | `operation` | 11 | Tasks, flows, channels, space navigation |
100
+ | `auth` / `config` | 2 | Authentication and host configuration |
97
101
 
98
102
  ### Global Options
99
103
 
@@ -124,44 +128,39 @@ npx skills add ThinkingAIAgenticEngine/ae-cli -g -y
124
128
 
125
129
  ## Skill Details
126
130
 
127
- ### ae-analysis (67 tools)
131
+ ### ae-analysis
128
132
 
129
133
  Unified AE analysis capabilities:
130
- - **Alerts**: view, create, update alert definitions
131
- - **Reports & Dashboards**: create, query, update reports and dashboards
132
- - **Model Analysis**: event analysis, retention analysis, funnel analysis, SQL analysis, user property analysis, distribution analysis, interval analysis, path analysis, attribution analysis
134
+ - **Analysis**: alerts, reports, dashboards, ad-hoc/drilldown, entity/event details, analysis schema
133
135
  - **Audience**: cluster and tag lifecycle management, plus definition schema tools
134
- - **Metadata Governance**: events/properties, metrics, virtual metadata, project config, tracking plans, mark times, entity catalog
135
- - **Common Constraints**: mandatory project ID gate and post-write resource-link completion
136
- - **Entity/Event Details**: query details, generate analysis SQL
137
- - **Schema Helpers**: analysis query schema, filter schema, groupby schema
136
+ - **Metadata**: events/properties, metrics, virtual metadata, project config, tracking plans, mark times
137
+ - **Common**: mandatory project ID gate and post-write resource-link completion
138
138
 
139
- ### engage (40+ tools)
139
+ ### engage
140
140
 
141
141
  Hermes Engage MCP capabilities:
142
- - **Channels**: channel management, config channels, approval management
143
- - **Tasks**: task list, task details, task data/metrics overview, experiment reports
144
- - **Configs**: config items, strategies, strategy comparison, trigger/analysis reports
145
- - **Flows**: flow creation, node config, flow reports, flow validation
142
+ - **Channels**: channel management, config channels, approval, whitelist
143
+ - **Tasks**: task list, details, data/metrics overview, experiment reports
144
+ - **Configs**: config items, strategies, comparison, trigger/analysis reports
145
+ - **Flows**: flow creation, node config, reports, validation
146
146
 
147
- ### ae-dataops (50+ tools)
147
+ ### ae-dataops
148
148
 
149
149
  Data warehouse management:
150
150
  - **Repo Management**: spaces, catalogs, schemas, members
151
151
  - **Data Tables**: table creation, views, batch operations, data dictionary
152
152
  - **Task Flows**: flow creation, task nodes, scheduling, execution, monitoring
153
153
  - **IDE Queries**: metadata browsing, SQL execution, query management
154
- - **Integration**: datasource management, sync solutions, data synchronization
155
- - **Operations**: flow instances, task instances, backfill jobs
154
+ - **Data Integration**: datasource management, sync solutions, data synchronization
156
155
 
157
- ### ae-community (30+ tools)
156
+ ### ae-community
158
157
 
159
158
  Community social media analysis:
160
159
  - **Posts**: search, detail, corpus tags
161
160
  - **Comments**: sentiment analysis, tag analysis, summary
162
161
  - **Topics**: hot topics, trends, daily summaries
163
162
  - **Livestreams**: rooms, sessions, analysis, metrics
164
- - **Advanced Analysis**: activity analysis, character analysis, weekly reports, release analysis
163
+ - **Channel Info**: channel overview metrics
165
164
 
166
165
  ## Architecture
167
166
 
package/README.zh.md CHANGED
@@ -86,14 +86,18 @@ ae-cli auth logout
86
86
 
87
87
  | 域 | 命令数 | 描述 |
88
88
  |---|---|---|
89
- | `analysis` | 31 | 分析工作流:告警、报表、仪表板、即时分析/下钻、分群/标签、元数据/指标、项目工具、实体详情、分析模型 |
90
- | `analysis_audience` | 14 | 受众运营:分群、标签及其定义模型 |
91
- | `analysis_meta` | 20 | 元数据治理:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间、资源链接 |
89
+ | `analysis` | 30+ | 分析工作流:告警、报表、仪表板、即时分析/下钻、实体/事件详情、分析模型 |
90
+ | `analysis_audience` | 10+ | 受众运营:分群、标签及其定义模型 |
91
+ | `analysis_meta` | 20+ | 元数据治理:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间、实体目录 |
92
92
  | `engage` | 40+ | Hermes Engage MCP:渠道、任务、配置、流程、策略 |
93
- | `te_dataops` | 50+ | 数仓管理:仓库、数据表、任务流、IDE 查询、数据集成、运维管理 |
94
- | `te_community` | 30+ | 社区分析:帖子搜索、情感分析、话题趋势、直播数据 |
93
+ | `dataops_repo` | 8 | 数仓仓库:空间、目录、模式、成员 |
94
+ | `dataops_datatable` | 10+ | 数据表:表创建、视图、批量操作、数据字典 |
95
+ | `dataops_flow` | 20+ | 任务流:流程创建、任务节点、调度、执行、监控 |
96
+ | `dataops_ide` | 10+ | IDE 查询:元数据浏览、SQL 执行、查询管理 |
97
+ | `dataops_integration` | 20+ | 数据集成:数据源管理、同步方案、数据同步 |
98
+ | `community` | 10+ | 社区分析:帖子搜索、情感分析、话题趋势、直播数据 |
95
99
  | `analysis_common` | 2 | 跨模块通用约束:资源链接补全、项目 ID 门控 |
96
- | `operation` | 11 | 任务、流程、渠道、空间导航 |
100
+ | `auth` / `config` | 2 | 身份验证和主机配置 |
97
101
 
98
102
  ### 全局选项
99
103
 
@@ -124,27 +128,23 @@ npx skills add ThinkingAIAgenticEngine/ae-cli -g -y
124
128
 
125
129
  ## Skill 详情
126
130
 
127
- ### ae-analysis(67 个工具)
131
+ ### ae-analysis
128
132
 
129
133
  统一的 AE 分析能力:
130
- - **告警**:查看、创建、更新告警定义
131
- - **报表和仪表板**:创建、查询、更新报表和仪表板
132
- - **模型分析**:事件分析、留存分析、漏斗分析、SQL 分析、用户属性分析、分布分析、间隔分析、路径分析、归因分析
134
+ - **分析**:告警、报表、仪表板、即时分析/下钻、实体/事件详情、分析模型
133
135
  - **受众**:分群和标签生命周期管理,以及定义模型工具
134
- - **元数据治理**:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间、实体目录
136
+ - **元数据**:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间
135
137
  - **通用约束**:强制的项目 ID 门控和写入后资源链接补全
136
- - **实体/事件详情**:查询详情、生成分析 SQL
137
- - **模型辅助**:分析查询模型、过滤模型、分组模型
138
138
 
139
- ### engage(40+ 个工具)
139
+ ### engage
140
140
 
141
141
  Hermes Engage MCP 能力:
142
- - **渠道**:渠道管理、配置渠道、审批管理
143
- - **任务**:任务列表、任务详情、任务数据/指标概览、实验报告
144
- - **配置**:配置项、策略、策略对比、触发/分析报告
145
- - **流程**:流程创建、节点配置、流程报告、流程验证
142
+ - **渠道**:渠道管理、配置渠道、审批、白名单
143
+ - **任务**:任务列表、详情、数据/指标概览、实验报告
144
+ - **配置**:配置项、策略、对比、触发/分析报告
145
+ - **流程**:流程创建、节点配置、报告、验证
146
146
 
147
- ### ae-dataops(50+ 个工具)
147
+ ### ae-dataops
148
148
 
149
149
  数仓管理:
150
150
  - **仓库管理**:空间、目录、模式、成员
@@ -152,16 +152,15 @@ Hermes Engage MCP 能力:
152
152
  - **任务流**:流程创建、任务节点、调度、执行、监控
153
153
  - **IDE 查询**:元数据浏览、SQL 执行、查询管理
154
154
  - **数据集成**:数据源管理、同步方案、数据同步
155
- - **运维管理**:流程实例、任务实例、补数据任务
156
155
 
157
- ### ae-community(30+ 个工具)
156
+ ### ae-community
158
157
 
159
158
  社区社媒分析:
160
159
  - **帖子**:搜索、详情、语料标签
161
160
  - **评论**:情感分析、标签分析、摘要
162
161
  - **话题**:热门话题、趋势、每日摘要
163
162
  - **直播**:直播间、场次、分析、指标
164
- - **高级分析**:活动分析、角色分析、周报、发布分析
163
+ - **渠道信息**:渠道概览指标
165
164
 
166
165
  ## 架构
167
166
 
@@ -0,0 +1,144 @@
1
+ import {
2
+ printError,
3
+ printOutput
4
+ } from "./chunk-KM57HI5B.js";
5
+ import {
6
+ clearMcpToken,
7
+ setMcpTokenManual,
8
+ validateMcpToken
9
+ } from "./chunk-7QBNU44L.js";
10
+ import {
11
+ clearToken,
12
+ getAuthStatus,
13
+ getToken,
14
+ resolveHost,
15
+ setTokenManual,
16
+ validateToken
17
+ } from "./chunk-4KQ7H7DY.js";
18
+ import {
19
+ loadConfig,
20
+ saveConfig
21
+ } from "./chunk-MR57UIKC.js";
22
+
23
+ // src/commands/auth.ts
24
+ function registerAuth(program) {
25
+ const auth = program.command("auth").description("Authentication management");
26
+ auth.command("login").description("Login to AE (auto-extract token from Chrome on macOS)").action(async () => {
27
+ const host = resolveHost(program.opts().host);
28
+ if (!host) {
29
+ printError("config", "No AE host configured.", "Run: ae-cli config set-host");
30
+ process.exit(1);
31
+ }
32
+ try {
33
+ const token = await getToken(host);
34
+ process.stderr.write(`[ae-cli] Authenticated to ${host}
35
+ `);
36
+ printOutput({ authenticated: true, host, token: token.slice(0, 8) + "..." }, program.opts().format || "json");
37
+ } catch (err) {
38
+ printError("auth", err.message);
39
+ process.exit(1);
40
+ }
41
+ });
42
+ auth.command("set-token <token>").description("Manually set authentication token for active host").action(async (token) => {
43
+ const host = resolveHost(program.opts().host);
44
+ if (!host) {
45
+ printError("config", "No AE host configured.", "Run: ae-cli config set-host");
46
+ process.exit(1);
47
+ }
48
+ const config = loadConfig();
49
+ if (!config.hosts[host]) {
50
+ config.hosts[host] = { label: host };
51
+ if (!config.activeHost) {
52
+ config.activeHost = host;
53
+ }
54
+ saveConfig(config);
55
+ process.stderr.write(`[ae-cli] Config saved for ${host}
56
+ `);
57
+ printOutput({ saved: true, config }, program.opts().format || "json");
58
+ }
59
+ process.stderr.write(`[ae-cli] Validating token...
60
+ `);
61
+ const isValid = await validateToken(token, host);
62
+ if (!isValid) {
63
+ process.stderr.write(`[ae-cli] Token validation failed
64
+ `);
65
+ printError("auth", "Invalid token", "Please check your token and try again");
66
+ process.exit(1);
67
+ }
68
+ setTokenManual(token, host);
69
+ process.stderr.write(`[ae-cli] Token verified and saved for ${host}
70
+ `);
71
+ printOutput({ saved: true, host, verified: true }, program.opts().format || "json");
72
+ });
73
+ auth.command("status").description("Show current authentication status").action(() => {
74
+ const host = resolveHost(program.opts().host);
75
+ if (!host) {
76
+ printOutput({ authenticated: false, host: "(none)", hint: "Run: ae-cli config set-host" }, program.opts().format || "json");
77
+ return;
78
+ }
79
+ const status = getAuthStatus(host);
80
+ printOutput(status, program.opts().format || "json");
81
+ });
82
+ auth.command("logout").description("Clear stored token for active host").action(() => {
83
+ const host = resolveHost(program.opts().host);
84
+ if (!host) {
85
+ printError("config", "No AE host configured.", "Run: ae-cli config set-host");
86
+ process.exit(1);
87
+ }
88
+ clearToken(host);
89
+ process.stderr.write(`[ae-cli] Token cleared for ${host}
90
+ `);
91
+ printOutput({ cleared: true, host }, program.opts().format || "json");
92
+ });
93
+ auth.command("set-mcp-token <token>").description("Manually set MCP token for a host").option("--host <host>", "Target host URL (defaults to active host)").action(async (token, opts) => {
94
+ const host = opts.host || resolveHost(program.opts().host);
95
+ if (!host) {
96
+ printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host");
97
+ process.exit(1);
98
+ }
99
+ const config = loadConfig();
100
+ if (!config.hosts[host]) {
101
+ config.hosts[host] = { label: host };
102
+ if (!config.activeHost) {
103
+ config.activeHost = host;
104
+ }
105
+ saveConfig(config);
106
+ process.stderr.write(`[ae-cli] Host config saved for ${host}
107
+ `);
108
+ }
109
+ process.stderr.write(`[ae-cli] Validating MCP token...
110
+ `);
111
+ const isValid = await validateMcpToken(token, host);
112
+ if (!isValid) {
113
+ process.stderr.write(`[ae-cli] MCP token validation failed
114
+ `);
115
+ printError("auth", "Invalid MCP token", "Please check your MCP token and try again");
116
+ process.exit(1);
117
+ }
118
+ setMcpTokenManual(token, host);
119
+ process.stderr.write(`[ae-cli] MCP token verified and saved for ${host}
120
+ `);
121
+ printOutput({ saved: true, host, verified: true, type: "mcp-token" }, program.opts().format || "json");
122
+ });
123
+ auth.command("clear-mcp-token").description("Clear stored MCP token for a host").option("--host <host>", "Target host URL (defaults to active host)").option("--all", "Clear MCP tokens for all hosts").action((opts) => {
124
+ if (opts.all) {
125
+ clearMcpToken();
126
+ process.stderr.write(`[ae-cli] All MCP tokens cleared
127
+ `);
128
+ printOutput({ cleared: true, type: "all-mcp-tokens" }, program.opts().format || "json");
129
+ return;
130
+ }
131
+ const host = opts.host || resolveHost(program.opts().host);
132
+ if (!host) {
133
+ printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host");
134
+ process.exit(1);
135
+ }
136
+ clearMcpToken(host);
137
+ process.stderr.write(`[ae-cli] MCP token cleared for ${host}
138
+ `);
139
+ printOutput({ cleared: true, host }, program.opts().format || "json");
140
+ });
141
+ }
142
+ export {
143
+ registerAuth
144
+ };
@@ -5,9 +5,10 @@ import {
5
5
  loadToken,
6
6
  resolveHost,
7
7
  saveToken,
8
- setTokenManual
9
- } from "./chunk-UK6HO5O5.js";
10
- import "./chunk-EBFUVWIZ.js";
8
+ setTokenManual,
9
+ validateToken
10
+ } from "./chunk-4KQ7H7DY.js";
11
+ import "./chunk-MR57UIKC.js";
11
12
  export {
12
13
  clearToken,
13
14
  getAuthStatus,
@@ -15,5 +16,6 @@ export {
15
16
  loadToken,
16
17
  resolveHost,
17
18
  saveToken,
18
- setTokenManual
19
+ setTokenManual,
20
+ validateToken
19
21
  };
@@ -2,8 +2,9 @@ import {
2
2
  extractHostname,
3
3
  getActiveHost,
4
4
  getConfigDir,
5
+ safeJsonParse,
5
6
  safeReadJsonFile
6
- } from "./chunk-EBFUVWIZ.js";
7
+ } from "./chunk-MR57UIKC.js";
7
8
 
8
9
  // src/core/auth.ts
9
10
  import fs from "fs";
@@ -22,6 +23,16 @@ function resolveHost(hostOverride) {
22
23
  if (hostOverride) return hostOverride;
23
24
  return getActiveHost();
24
25
  }
26
+ async function validateToken(token, hostUrl) {
27
+ const url = `${hostUrl}/v1/oauth/checkToken?accessToken=${token}`;
28
+ try {
29
+ const resp = await fetch(url, { method: "POST" });
30
+ const respJson = safeJsonParse(await resp.text());
31
+ return respJson?.return_code === 0;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
25
36
  function loadAllTokens() {
26
37
  try {
27
38
  const legacyTokens = path.join(LEGACY_DIR, "tokens.json");
@@ -209,6 +220,7 @@ Options:
209
220
 
210
221
  export {
211
222
  resolveHost,
223
+ validateToken,
212
224
  loadToken,
213
225
  saveToken,
214
226
  clearToken,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  getToken
3
- } from "./chunk-UK6HO5O5.js";
3
+ } from "./chunk-4KQ7H7DY.js";
4
4
  import {
5
5
  getActiveHost,
6
6
  getConfigDir,
7
7
  safeJsonParse,
8
8
  safeReadJsonFile
9
- } from "./chunk-EBFUVWIZ.js";
9
+ } from "./chunk-MR57UIKC.js";
10
10
 
11
11
  // src/core/mcp.ts
12
12
  import fs from "fs";
@@ -54,6 +54,7 @@ function genRequestId() {
54
54
  }
55
55
  var MCP_TOKEN_FILE = path.join(getConfigDir(), "mcp-tokens.json");
56
56
  var MCP_TOKEN_GENERATE_PATH = "/v1/ta/mcp/token/generate";
57
+ var FALLBACK_MCP_TOKEN_FILE = "/data/app/te_agent_ta/.ae-config/mcp-token.json";
57
58
  function loadMcpTokenStore() {
58
59
  try {
59
60
  if (fs.existsSync(MCP_TOKEN_FILE)) {
@@ -68,6 +69,23 @@ function saveMcpTokenStore(store) {
68
69
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
69
70
  fs.writeFileSync(MCP_TOKEN_FILE, JSON.stringify(store, null, 2));
70
71
  }
72
+ function getFallbackMcpToken(hostUrl) {
73
+ try {
74
+ if (!fs.existsSync(FALLBACK_MCP_TOKEN_FILE)) {
75
+ return null;
76
+ }
77
+ const fallbackData = safeReadJsonFile(FALLBACK_MCP_TOKEN_FILE);
78
+ if (fallbackData && typeof fallbackData === "object" && !Array.isArray(fallbackData)) {
79
+ const url = fallbackData.url;
80
+ const token = fallbackData["mcp-token"];
81
+ if (url === hostUrl && token) {
82
+ return token;
83
+ }
84
+ }
85
+ } catch {
86
+ }
87
+ return null;
88
+ }
71
89
  async function generateMcpToken(hostUrl) {
72
90
  const teToken = await getToken(hostUrl);
73
91
  const base = hostUrl.replace(/\/+$/, "");
@@ -102,8 +120,60 @@ async function getMcpToken(hostOverride) {
102
120
  saveMcpTokenStore(updatedStore);
103
121
  return mcpToken;
104
122
  }
123
+ function clearMcpToken(hostUrl) {
124
+ const store = loadMcpTokenStore();
125
+ if (hostUrl) {
126
+ delete store[hostUrl];
127
+ } else {
128
+ for (const key of Object.keys(store)) {
129
+ delete store[key];
130
+ }
131
+ }
132
+ saveMcpTokenStore(store);
133
+ }
134
+ function setMcpTokenManual(token, hostUrl) {
135
+ const store = loadMcpTokenStore();
136
+ store[hostUrl] = token;
137
+ saveMcpTokenStore(store);
138
+ }
139
+ async function validateMcpToken(token, hostUrl) {
140
+ const mapping = getMcpMapping("analysis");
141
+ const base = hostUrl.replace(/\/+$/, "");
142
+ const url = `${base}/mcp/${mapping.componentName}/http/${mapping.mappingPath}`;
143
+ const requestId = 1;
144
+ const body = {
145
+ jsonrpc: JSONRPC_VERSION,
146
+ id: requestId,
147
+ method: "tools/list",
148
+ params: { _meta: { progressToken: requestId } }
149
+ };
150
+ const headers = {
151
+ "Content-Type": "application/json",
152
+ "Accept": "application/json, text/event-stream",
153
+ "mcp-protocol-version": MCP_PROTOCOL_VERSION,
154
+ "mcp-token": token
155
+ };
156
+ try {
157
+ const resp = await fetch(url, {
158
+ method: "POST",
159
+ headers,
160
+ body: JSON.stringify(body)
161
+ });
162
+ if (!resp.ok) {
163
+ return false;
164
+ }
165
+ const data = safeJsonParse(await resp.text());
166
+ if (data.error) {
167
+ return false;
168
+ }
169
+ return data.result?.tools !== void 0;
170
+ } catch {
171
+ return false;
172
+ }
173
+ }
105
174
  async function mcpRequest(url, method, params = {}, hostOverride) {
106
- const token = await getMcpToken(hostOverride);
175
+ const hostUrl = hostOverride || getActiveHost();
176
+ const token = await getMcpToken(hostUrl);
107
177
  const requestId = genRequestId();
108
178
  const paramsWithMeta = {
109
179
  ...params,
@@ -126,6 +196,31 @@ async function mcpRequest(url, method, params = {}, hostOverride) {
126
196
  headers,
127
197
  body: JSON.stringify(body)
128
198
  });
199
+ if (resp.status === 403) {
200
+ const fallbackToken = getFallbackMcpToken(hostUrl);
201
+ if (fallbackToken) {
202
+ const store = loadMcpTokenStore();
203
+ store[hostUrl] = fallbackToken;
204
+ saveMcpTokenStore(store);
205
+ process.stderr.write(`[ae-cli] MCP token refreshed from fallback for ${hostUrl}
206
+ `);
207
+ headers["mcp-token"] = fallbackToken;
208
+ const retryResp = await fetch(url, {
209
+ method: "POST",
210
+ headers,
211
+ body: JSON.stringify(body)
212
+ });
213
+ if (!retryResp.ok) {
214
+ throw new Error(`MCP HTTP error: ${retryResp.status} ${retryResp.statusText}`);
215
+ }
216
+ const retryData = safeJsonParse(await retryResp.text());
217
+ if (retryData.error) {
218
+ throw new Error(`MCP error: ${retryData.error.message || JSON.stringify(retryData.error)}`);
219
+ }
220
+ return retryData.result;
221
+ }
222
+ throw new Error(`MCP token expired or invalid. Please set a new MCP token: ae-cli auth set-mcp-token <token> --host ${hostUrl}`);
223
+ }
129
224
  if (!resp.ok) {
130
225
  throw new Error(`MCP HTTP error: ${resp.status} ${resp.statusText}`);
131
226
  }
@@ -169,6 +264,9 @@ function parseMcpResult(result) {
169
264
  export {
170
265
  registerMcpMappings,
171
266
  resolveMcpUrl,
267
+ clearMcpToken,
268
+ setMcpTokenManual,
269
+ validateMcpToken,
172
270
  callMcpTool,
173
271
  parseMcpResult
174
272
  };
@@ -2,10 +2,10 @@ import {
2
2
  clearToken,
3
3
  getToken,
4
4
  resolveHost
5
- } from "./chunk-UK6HO5O5.js";
5
+ } from "./chunk-4KQ7H7DY.js";
6
6
  import {
7
7
  safeJsonParse
8
- } from "./chunk-EBFUVWIZ.js";
8
+ } from "./chunk-MR57UIKC.js";
9
9
 
10
10
  // src/core/client.ts
11
11
  import WebSocket from "ws";
@@ -17,11 +17,37 @@ import fs2 from "fs";
17
17
  import path from "path";
18
18
  var CONFIG_DIR = path.join(process.env.HOME || "", ".ae-cli");
19
19
  var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
20
+ var MCP_TOKENS_FILE = path.join(CONFIG_DIR, "mcp-tokens.json");
21
+ var FALLBACK_MCP_TOKEN_FILE = "/data/app/te_agent_ta/.ae-config/mcp-token.json";
20
22
  function ensureDir() {
21
23
  if (!fs2.existsSync(CONFIG_DIR)) fs2.mkdirSync(CONFIG_DIR, { recursive: true });
22
24
  }
25
+ function migrateFromFallback() {
26
+ if (!fs2.existsSync(FALLBACK_MCP_TOKEN_FILE) || fs2.existsSync(MCP_TOKENS_FILE)) {
27
+ return null;
28
+ }
29
+ try {
30
+ const fallbackData = safeReadJsonFile(FALLBACK_MCP_TOKEN_FILE);
31
+ const tokenStore = {};
32
+ if (fallbackData && typeof fallbackData === "object" && !Array.isArray(fallbackData)) {
33
+ const url = fallbackData.url;
34
+ const token = fallbackData["mcp-token"];
35
+ if (url && token) {
36
+ tokenStore[url] = token;
37
+ }
38
+ }
39
+ if (Object.keys(tokenStore).length > 0) {
40
+ ensureDir();
41
+ fs2.writeFileSync(MCP_TOKENS_FILE, JSON.stringify(tokenStore, null, 2));
42
+ return tokenStore;
43
+ }
44
+ } catch {
45
+ }
46
+ return null;
47
+ }
23
48
  function loadConfig() {
24
49
  try {
50
+ const migratedTokens = migrateFromFallback();
25
51
  if (fs2.existsSync(CONFIG_FILE)) {
26
52
  const raw = safeReadJsonFile(CONFIG_FILE);
27
53
  if (raw.defaultHost && !raw.activeHost) {
@@ -31,6 +57,22 @@ function loadConfig() {
31
57
  }
32
58
  return raw;
33
59
  }
60
+ if (migratedTokens && Object.keys(migratedTokens).length > 0) {
61
+ const hosts = {};
62
+ for (const url of Object.keys(migratedTokens)) {
63
+ hosts[url] = { label: url };
64
+ process.stderr.write(`[ae-cli] Added host: ${url}
65
+ `);
66
+ }
67
+ const activeHost = Object.keys(migratedTokens)[0];
68
+ process.stderr.write(`[ae-cli] Active host set to: ${activeHost}
69
+ `);
70
+ process.stderr.write(`[ae-cli] MCP tokens migrated from ${FALLBACK_MCP_TOKEN_FILE}
71
+ `);
72
+ const config = { activeHost, hosts };
73
+ saveConfig(config);
74
+ return config;
75
+ }
34
76
  } catch (err) {
35
77
  console.error(`Error loading config: ${err.message}`);
36
78
  }
@@ -4,9 +4,9 @@ import {
4
4
  queryReportData,
5
5
  querySql,
6
6
  wsQuery
7
- } from "./chunk-OQ4XEG77.js";
8
- import "./chunk-UK6HO5O5.js";
9
- import "./chunk-EBFUVWIZ.js";
7
+ } from "./chunk-LAAS6ITR.js";
8
+ import "./chunk-4KQ7H7DY.js";
9
+ import "./chunk-MR57UIKC.js";
10
10
  export {
11
11
  httpGet,
12
12
  httpPost,
@@ -1,14 +1,17 @@
1
1
  import {
2
+ clearToken,
2
3
  getAuthStatus,
3
- getToken
4
- } from "./chunk-UK6HO5O5.js";
4
+ getToken,
5
+ loadToken,
6
+ validateToken
7
+ } from "./chunk-4KQ7H7DY.js";
5
8
  import {
6
9
  addHost,
7
10
  listHosts,
8
11
  removeHost,
9
12
  setActiveHost,
10
13
  updateHostLabel
11
- } from "./chunk-EBFUVWIZ.js";
14
+ } from "./chunk-MR57UIKC.js";
12
15
 
13
16
  // src/commands/config.ts
14
17
  import * as readline from "readline";
@@ -136,9 +139,21 @@ Delete \x1B[1m${label}\x1B[0m (${url})? [y/N]: `, (a) => {
136
139
  async function ensureAuth(hostUrl) {
137
140
  const status = getAuthStatus(hostUrl);
138
141
  if (status.authenticated) {
139
- process.stderr.write(`\x1B[32m\u2713\x1B[0m Token valid for ${hostUrl}
142
+ const cached = loadToken(hostUrl);
143
+ if (cached && cached.token) {
144
+ process.stderr.write(`\x1B[2m[ae-cli] Validating token...\x1B[0m
140
145
  `);
141
- return;
146
+ const isValid = await validateToken(cached.token, hostUrl);
147
+ if (isValid) {
148
+ process.stderr.write(`\x1B[32m\u2713\x1B[0m Token valid for ${hostUrl}
149
+ `);
150
+ return;
151
+ } else {
152
+ clearToken(hostUrl);
153
+ process.stderr.write(`\x1B[33m!\x1B[0m Token expired or invalid. Re-authenticating...
154
+ `);
155
+ }
156
+ }
142
157
  }
143
158
  process.stderr.write(`
144
159
  \x1B[33m!\x1B[0m No valid token for ${hostUrl}. Starting login...
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  getActiveHost,
7
7
  safeJsonParse
8
- } from "./chunk-EBFUVWIZ.js";
8
+ } from "./chunk-MR57UIKC.js";
9
9
 
10
10
  // src/index.ts
11
11
  import { Command as CommanderCommand } from "commander";
@@ -62,7 +62,7 @@ function createRuntimeContext(cmd, opts, globalOpts) {
62
62
  let _clientModule = null;
63
63
  async function getClient() {
64
64
  if (!_clientModule) {
65
- _clientModule = await import("./client-HU63573O.js");
65
+ _clientModule = await import("./client-O56G2SNJ.js");
66
66
  }
67
67
  return _clientModule;
68
68
  }
@@ -105,7 +105,7 @@ function createRuntimeContext(cmd, opts, globalOpts) {
105
105
  return client.queryReportData(projectId, reportId, qp, eventModel, options, ctx.host());
106
106
  },
107
107
  async token() {
108
- const { getToken } = await import("./auth-4GAHTBVH.js");
108
+ const { getToken } = await import("./auth-ECD46NBA.js");
109
109
  return getToken(ctx.host());
110
110
  },
111
111
  host() {
@@ -210,37 +210,37 @@ program.name("ae-cli").version(version).description("CLI tool for ThinkingAI (AE
210
210
  async function loadCommands() {
211
211
  const commands = [];
212
212
  try {
213
- const teAnalysis = await import("./te-analysis-ZDJXMWZY.js");
213
+ const teAnalysis = await import("./te-analysis-UGKESPBE.js");
214
214
  commands.push(...teAnalysis.default);
215
215
  } catch {
216
216
  }
217
217
  try {
218
- const teAudience = await import("./te-audience-T5B52EEB.js");
218
+ const teAudience = await import("./te-audience-THZNVHYB.js");
219
219
  commands.push(...teAudience.default);
220
220
  } catch {
221
221
  }
222
222
  try {
223
- const teMeta = await import("./te-meta-JJMV75KB.js");
223
+ const teMeta = await import("./te-meta-MGO5BCMG.js");
224
224
  commands.push(...teMeta.default);
225
225
  } catch {
226
226
  }
227
227
  try {
228
- const teCommon = await import("./te-common-BPTXXTHQ.js");
228
+ const teCommon = await import("./te-common-QZOUME3S.js");
229
229
  commands.push(...teCommon.default);
230
230
  } catch {
231
231
  }
232
232
  try {
233
- const engage = await import("./te-engage-K3EANZ5P.js");
233
+ const engage = await import("./te-engage-RYGEQTYK.js");
234
234
  commands.push(...engage.default);
235
235
  } catch {
236
236
  }
237
237
  try {
238
- const community = await import("./te-community-FPB5LH56.js");
238
+ const community = await import("./te-community-AZVW3NFX.js");
239
239
  commands.push(...community.default);
240
240
  } catch {
241
241
  }
242
242
  try {
243
- const dataops = await import("./te-dataops-2NUJVG47.js");
243
+ const dataops = await import("./te-dataops-OE5PX2K6.js");
244
244
  commands.push(...dataops.default);
245
245
  } catch {
246
246
  }
@@ -248,21 +248,21 @@ async function loadCommands() {
248
248
  }
249
249
  async function registerAuthCommands() {
250
250
  try {
251
- const { registerAuth } = await import("./auth-U2GHFMFY.js");
251
+ const { registerAuth } = await import("./auth-2UTBG5U3.js");
252
252
  registerAuth(program);
253
253
  } catch {
254
254
  }
255
255
  }
256
256
  async function registerConfigCommands() {
257
257
  try {
258
- const { registerConfig } = await import("./config-OLF7RBPM.js");
258
+ const { registerConfig } = await import("./config-BU5FHGGE.js");
259
259
  registerConfig(program);
260
260
  } catch {
261
261
  }
262
262
  }
263
263
  async function registerApiCommand() {
264
264
  try {
265
- const { registerApi } = await import("./raw-GDO4IWNW.js");
265
+ const { registerApi } = await import("./raw-A3VN2B6I.js");
266
266
  registerApi(program);
267
267
  } catch {
268
268
  }
@@ -5,13 +5,13 @@ import {
5
5
  import {
6
6
  httpGet,
7
7
  httpPost
8
- } from "./chunk-OQ4XEG77.js";
8
+ } from "./chunk-LAAS6ITR.js";
9
9
  import {
10
10
  resolveHost
11
- } from "./chunk-UK6HO5O5.js";
11
+ } from "./chunk-4KQ7H7DY.js";
12
12
  import {
13
13
  safeJsonParse
14
- } from "./chunk-EBFUVWIZ.js";
14
+ } from "./chunk-MR57UIKC.js";
15
15
 
16
16
  // src/api/raw.ts
17
17
  function registerApi(program) {
@@ -2,9 +2,9 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-TJIMDNAU.js";
6
- import "./chunk-UK6HO5O5.js";
7
- import "./chunk-EBFUVWIZ.js";
5
+ } from "./chunk-7QBNU44L.js";
6
+ import "./chunk-4KQ7H7DY.js";
7
+ import "./chunk-MR57UIKC.js";
8
8
 
9
9
  // src/commands/te-analysis/shared.ts
10
10
  function createMcpCommand(config) {
@@ -2,9 +2,9 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-TJIMDNAU.js";
6
- import "./chunk-UK6HO5O5.js";
7
- import "./chunk-EBFUVWIZ.js";
5
+ } from "./chunk-7QBNU44L.js";
6
+ import "./chunk-4KQ7H7DY.js";
7
+ import "./chunk-MR57UIKC.js";
8
8
 
9
9
  // src/commands/te-audience/shared.ts
10
10
  function createMcpCommand(config) {
@@ -2,9 +2,9 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-TJIMDNAU.js";
6
- import "./chunk-UK6HO5O5.js";
7
- import "./chunk-EBFUVWIZ.js";
5
+ } from "./chunk-7QBNU44L.js";
6
+ import "./chunk-4KQ7H7DY.js";
7
+ import "./chunk-MR57UIKC.js";
8
8
 
9
9
  // src/commands/te-common/shared.ts
10
10
  function createMcpCommand(config) {
@@ -3,9 +3,9 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-TJIMDNAU.js";
7
- import "./chunk-UK6HO5O5.js";
8
- import "./chunk-EBFUVWIZ.js";
6
+ } from "./chunk-7QBNU44L.js";
7
+ import "./chunk-4KQ7H7DY.js";
8
+ import "./chunk-MR57UIKC.js";
9
9
 
10
10
  // src/commands/te-community/get_channel_info.ts
11
11
  var getChannelInfo = {
@@ -3,9 +3,9 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-TJIMDNAU.js";
7
- import "./chunk-UK6HO5O5.js";
8
- import "./chunk-EBFUVWIZ.js";
6
+ } from "./chunk-7QBNU44L.js";
7
+ import "./chunk-4KQ7H7DY.js";
8
+ import "./chunk-MR57UIKC.js";
9
9
 
10
10
  // src/commands/te-dataops/datatable/list-tables-by-page.ts
11
11
  var listTablesByPage = {
@@ -3,9 +3,9 @@ import {
3
3
  parseMcpResult,
4
4
  registerMcpMappings,
5
5
  resolveMcpUrl
6
- } from "./chunk-TJIMDNAU.js";
7
- import "./chunk-UK6HO5O5.js";
8
- import "./chunk-EBFUVWIZ.js";
6
+ } from "./chunk-7QBNU44L.js";
7
+ import "./chunk-4KQ7H7DY.js";
8
+ import "./chunk-MR57UIKC.js";
9
9
 
10
10
  // src/commands/te-engage/utils.ts
11
11
  function buildMcpDryRun(ctx, serviceName44, toolName44, args) {
@@ -2,9 +2,9 @@ import {
2
2
  callMcpTool,
3
3
  parseMcpResult,
4
4
  resolveMcpUrl
5
- } from "./chunk-TJIMDNAU.js";
6
- import "./chunk-UK6HO5O5.js";
7
- import "./chunk-EBFUVWIZ.js";
5
+ } from "./chunk-7QBNU44L.js";
6
+ import "./chunk-4KQ7H7DY.js";
7
+ import "./chunk-MR57UIKC.js";
8
8
 
9
9
  // src/commands/te-meta/shared.ts
10
10
  function createMcpCommand(config) {
@@ -380,12 +380,14 @@ var generateTrackProgram = createMcpCommand({
380
380
  description: "Generate a tracking plan from structured business context (async)",
381
381
  flags: [
382
382
  { name: "project_id", type: "number", required: true, alias: "p", desc: "Project ID" },
383
- { name: "form_data", type: "json", required: true, desc: "Structured business context JSON object with optional fields: account_system, revenue_model, core_gameplay, currency_system, main_entries, language, predefinedEvent, developmentCarrier" }
383
+ { name: "language", type: "string", required: true, alias: "l", desc: "Language code (zh-CN, en-US, ja-JP, ko-KR)" },
384
+ { name: "form_data", type: "json", required: true, desc: "Structured business context JSON object, optional fields for example: account_system, revenue_model, core_gameplay, currency_system, main_entries, predefinedEvent, developmentCarrier" }
384
385
  ],
385
386
  risk: "write",
386
387
  mcpService: "te_analysis_extend",
387
388
  buildArgs: (ctx) => ({
388
389
  projectId: ctx.num("project_id"),
390
+ language: ctx.str("language"),
389
391
  formData: ctx.json("form_data")
390
392
  })
391
393
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinkingai/ae-cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
4
4
  "description": "CLI tool for ThinkingAI (AE) analytics platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,6 +52,15 @@ Safety constraints:
52
52
  - Write commands require explicit user intent and normally keep the confirmation prompt.
53
53
  - Use `--dry-run` before risky or complex writes.
54
54
  - Never invent command names, flags, JSON payloads, `project_id`, resource IDs, field names, event names, property names, metric definitions, or date formats. Read the matching command reference and discover real project metadata first.
55
+ - **NEVER fabricate or guess resource names** (reports, dashboards, events, properties, metrics, clusters, tags, alerts). Always use list commands to discover real resources first. If a resource is not found after fuzzy search and full list fallback, explicitly tell the user "resource not found" and stop - do not proceed with fabricated names.
56
+
57
+ Language consistency:
58
+ - **Input-output language matching**: Always respond in the same language as the user's input.
59
+ - User asks in Chinese → Respond in Chinese, including result interpretation and error messages
60
+ - User asks in English → Respond in English
61
+ - **CLI output handling**: CLI returns JSON in English, but your interpretation and summary MUST match user's language
62
+ - **Resource names**: Keep original resource names as-is (don't translate), but descriptions and explanations should match user's language
63
+ - **Error messages**: Translate CLI error messages to user's language when presenting results
55
64
 
56
65
  ## When to Use
57
66
 
@@ -109,6 +118,55 @@ Closed-loop check (must be explicit in result):
109
118
  - `+get_resource_url` called or skipped (no ID)
110
119
  - Link completion status
111
120
 
121
+ ### C. FUZZY_SEARCH_FALLBACK
122
+
123
+ For list commands with `--query` parameter (list_reports, list_dashboards, list_events, list_clusters, list_tags, list_alerts, list_metrics):
124
+
125
+ 1. **First attempt**: Use `--query` with user-provided keyword for fuzzy search
126
+ 2. **If no results found**, retry up to 2 more times with:
127
+ - Broader keywords (remove modifiers, use root words)
128
+ - Alternative terms or synonyms
129
+ 3. **After 3 failed fuzzy attempts**, fall back to full list (omit `--query`)
130
+ 4. **Present full list** to user and ask them to identify the target resource
131
+ 5. **Never proceed** with operations on non-existent resources
132
+
133
+ **Example workflow:**
134
+ - User asks: "Find active user report"
135
+ - Attempt 1: `--query "active user"` → no results
136
+ - Attempt 2: `--query "active"` → no results
137
+ - Attempt 3: `--query "user"` → no results
138
+ - Fallback: list all reports, show to user, ask for selection
139
+
140
+ ### D. QUERY_EXISTING_FIRST
141
+
142
+ Before executing ad-hoc queries (`query_adhoc`), MUST check for existing reports/dashboards first:
143
+
144
+ **Mandatory workflow for data queries:**
145
+
146
+ 1. **Identify user intent** - Extract what metrics/dimensions/filters the user wants
147
+ 2. **Search existing reports** - Use `list_reports --query <keyword>` to find matching reports
148
+ 3. **Search existing dashboards** - Use `list_dashboards --query <keyword>` to find matching dashboards
149
+ 4. **If found** - Use `query_report_data` or `query_dashboard_report_data` to get data from existing assets
150
+ 5. **If not found** - Only then use `query_adhoc` for ad-hoc analysis
151
+
152
+ **Rationale:**
153
+ - **Performance**: Existing reports are pre-computed and faster
154
+ - **Consistency**: Reports have business-defined metrics and calibrated logic
155
+ - **Resource efficiency**: Avoid redundant computation
156
+ - **Permissions**: Users may have report access but not ad-hoc query permissions
157
+
158
+ **Example:**
159
+ - User: "Query active users in last 7 days"
160
+ - Step 1: `list_reports --query "active user"` → found "DAU Active Users Report"
161
+ - Step 2: `query_report_data --report_id <id>` → return data
162
+ - ❌ WRONG: Directly use `query_adhoc` without checking existing reports
163
+
164
+ **Exceptions (when ad-hoc is acceptable):**
165
+ - User explicitly requests "ad-hoc query" or "ad-hoc analysis"
166
+ - User wants custom filters/groupings not available in existing reports
167
+ - User is exploring data for new insights (exploratory analysis)
168
+ - No matching reports found after search + fallback
169
+
112
170
  ## Tool Groups (69)
113
171
 
114
172
  ### analysis (31)
@@ -16,26 +16,26 @@ Domain: **Project Configuration**
16
16
 
17
17
  ## Commands
18
18
  ```bash
19
- ae-cli analysis_meta +generate_track_program --project_id <project_id> --form_data '{}'
19
+ ae-cli analysis_meta +generate_track_program --project_id <project_id> --language <language> --form_data '{}'
20
20
  ae-cli analysis_meta +generate_track_program --dry-run
21
21
  ```
22
22
 
23
23
  ## Parameters
24
- | Parameter | Required | Description |
25
- |-----------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
26
- | `--project_id` / `-p` | Yes | Project ID |
27
- | `--form_data` | Yes | Structured business context JSON object. Optional fields: account_system, revenue_model, core_gameplay, currency_system, main_entries, language, predefinedEvent (array of event names like install, start, close), developmentCarrier (array of platforms like Android, iOS, Unity, Cocos, Douyin Mini Game, WeChat Mini Game). All fields can be customized based on business needs. |
24
+ | Parameter | Required | Description |
25
+ |-----------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
26
+ | `--project_id` / `-p` | Yes | Project ID |
27
+ | `--language` / `-l` | Yes | Language code. Supported values: `zh-CN`, `en-US`, `ja-JP`, `ko-KR` |
28
+ | `--form_data` | Yes | Structured business context JSON object. Optional fields for example: account_system, revenue_model, core_gameplay, currency_system, main_entries, predefinedEvent (array of event names like install, start, close), developmentCarrier (array of platforms like Android, iOS, Unity, Cocos, Douyin Mini Game, WeChat Mini Game). All fields can be customized based on business needs. |
28
29
 
29
30
  ## Decision Rules
30
31
  - **CRITICAL: Always call `+get_track_program` first to check existing tracking plan before generating.**
31
- - First run should only pass the required parameters (`--project_id`, `--form_data`).
32
+ - First run should only pass the required parameters (`--project_id`, `--language`, `--form_data`).
32
33
  - Wrap JSON arguments in single quotes (for example `--form_data '{}'`) to avoid shell escaping issues.
33
34
  - This is an asynchronous operation; check in-site message center for generation results.
34
35
  - For cross-project troubleshooting, first confirm whether `--project_id` matches the current permissions and target environment.
35
36
 
36
37
  ## Next Steps After Failure
37
- - If required parameters are missing, fall back to the smallest runnable command and fill them in (focus on `--project_id` and `--form_data`).
38
- - If `FORM_DATA_REQUIRED_FIELDS_MISSING` occurs, ensure all required fields are provided: account_system, revenue_model, core_gameplay, currency_system, main_entries, language.
38
+ - If required parameters are missing, fall back to the smallest runnable command and fill them in (focus on `--project_id`, `--language`, and `--form_data`).
39
39
  - If `Invalid JSON` occurs, validate with the smallest JSON structure first.
40
40
 
41
41
  ## Agent Response Flow
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Metadata Lookup**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List all alerts in the project. Supports keyword filtering by alert name. Returns a paginated list containing alerts array and pager result with total count.
9
13
  - List all alerts in the project.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Cluster Management**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List cluster metadata accessible to the current user in the project.
9
13
  - Supports payload governance parameters: `query`, `fields`, `limit`, `offset`.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Dashboard management**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List dashboard metadata accessible to the current user in the project. Supports keyword filtering and returns dashboard IDs, names, descriptions, and related metadata, but not dashboard configuration or report data.
9
13
  - List dashboard metadata accessible to the current user in the project.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Metadata Query**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - Read-only query for SYSTEM METADATA already effective in the project. Use for super events in production metadata. Do NOT use for tracking-plan metadata (bury/track program); that belongs to BuryProgramTool.
9
13
  - Read-only query for SYSTEM METADATA already effective in the project.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Metadata Query**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List metric metadata in the project. Supports keyword filtering and returns metric IDs, names, display names, model types, remarks, and related metadata, but not metric calculation results.
9
13
  - Supports pagination with fields/limit/offset for payload governance.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Report management**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List report metadata accessible to the current user in the project. Supports keyword filtering and returns report IDs, names, model types, update times, and related metadata, but not report definitions or analysis data.
9
13
  - List report metadata accessible to the current user in the project.
@@ -4,6 +4,10 @@
4
4
 
5
5
  Domain: **Tag Management**
6
6
 
7
+ ## Constraints
8
+
9
+ **Fuzzy Search Fallback:** If `--query` returns no results, retry with broader keywords (max 3 attempts), then fall back to full list. See [SKILL.md § C. FUZZY_SEARCH_FALLBACK](../SKILL.md#c-fuzzy_search_fallback).
10
+
7
11
  ## Use Cases
8
12
  - List tag metadata accessible to the current user in the project.
9
13
  - Supports payload governance parameters: `query`, `fields`, `limit`, `offset`.
@@ -4,6 +4,16 @@
4
4
 
5
5
  Domain: **Model analysis**
6
6
 
7
+ ## Constraints
8
+
9
+ **⚠️ QUERY_EXISTING_FIRST:** Before using ad-hoc query, you MUST first check for existing reports/dashboards with `list_reports` and `list_dashboards`. Only use `query_adhoc` if no matching reports found. See [SKILL.md § D. QUERY_EXISTING_FIRST](../SKILL.md#d-query_existing_first).
10
+
11
+ **Quick check workflow:**
12
+ 1. `list_reports --query <keyword>` - search matching reports
13
+ 2. `list_dashboards --query <keyword>` - search matching dashboards
14
+ 3. If found → use `query_report_data` or `query_dashboard_report_data`
15
+ 4. If not found → only then use `query_adhoc`
16
+
7
17
  ## Use Cases
8
18
  - Precondition helper: call `+get_analysis_query_schema` to get the structure before using this tool.
9
19
  - When constructing a real `qp`, you must supplement it with real project metadata; first call `analysis_meta +list_events` and `analysis_meta +list_properties`.
@@ -1,81 +0,0 @@
1
- import {
2
- printError,
3
- printOutput
4
- } from "./chunk-KM57HI5B.js";
5
- import {
6
- clearToken,
7
- getAuthStatus,
8
- getToken,
9
- resolveHost,
10
- setTokenManual
11
- } from "./chunk-UK6HO5O5.js";
12
- import {
13
- loadConfig,
14
- saveConfig
15
- } from "./chunk-EBFUVWIZ.js";
16
-
17
- // src/commands/auth.ts
18
- function registerAuth(program) {
19
- const auth = program.command("auth").description("Authentication management");
20
- auth.command("login").description("Login to AE (auto-extract token from Chrome on macOS)").action(async () => {
21
- const host = resolveHost(program.opts().host);
22
- if (!host) {
23
- printError("config", "No AE host configured.", "Run: ae-cli config set-host");
24
- process.exit(1);
25
- }
26
- try {
27
- const token = await getToken(host);
28
- process.stderr.write(`[ae-cli] Authenticated to ${host}
29
- `);
30
- printOutput({ authenticated: true, host, token: token.slice(0, 8) + "..." }, program.opts().format || "json");
31
- } catch (err) {
32
- printError("auth", err.message);
33
- process.exit(1);
34
- }
35
- });
36
- auth.command("set-token <token>").description("Manually set authentication token for active host").action((token) => {
37
- const host = resolveHost(program.opts().host);
38
- if (!host) {
39
- printError("config", "No AE host configured.", "Run: ae-cli config set-host");
40
- process.exit(1);
41
- }
42
- const config = loadConfig();
43
- if (!config.hosts[host]) {
44
- config.hosts[host] = { label: host };
45
- if (!config.activeHost) {
46
- config.activeHost = host;
47
- }
48
- saveConfig(config);
49
- process.stderr.write(`[ae-cli] Config saved for ${host}
50
- `);
51
- printOutput({ saved: true, config }, program.opts().format || "json");
52
- }
53
- setTokenManual(token, host);
54
- process.stderr.write(`[ae-cli] Token saved for ${host}
55
- `);
56
- printOutput({ saved: true, host }, program.opts().format || "json");
57
- });
58
- auth.command("status").description("Show current authentication status").action(() => {
59
- const host = resolveHost(program.opts().host);
60
- if (!host) {
61
- printOutput({ authenticated: false, host: "(none)", hint: "Run: ae-cli config set-host" }, program.opts().format || "json");
62
- return;
63
- }
64
- const status = getAuthStatus(host);
65
- printOutput(status, program.opts().format || "json");
66
- });
67
- auth.command("logout").description("Clear stored token for active host").action(() => {
68
- const host = resolveHost(program.opts().host);
69
- if (!host) {
70
- printError("config", "No AE host configured.", "Run: ae-cli config set-host");
71
- process.exit(1);
72
- }
73
- clearToken(host);
74
- process.stderr.write(`[ae-cli] Token cleared for ${host}
75
- `);
76
- printOutput({ cleared: true, host }, program.opts().format || "json");
77
- });
78
- }
79
- export {
80
- registerAuth
81
- };