@thinkingai/ae-cli 1.0.15 → 1.0.20
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 +23 -24
- package/README.zh.md +21 -22
- package/dist/auth-A4NV2VHD.js +153 -0
- package/dist/{auth-4GAHTBVH.js → auth-T3ILGJKW.js} +6 -4
- package/dist/{chunk-TJIMDNAU.js → chunk-5CCFSPAF.js} +79 -3
- package/dist/{chunk-UK6HO5O5.js → chunk-OVMQFFC2.js} +13 -1
- package/dist/{chunk-EBFUVWIZ.js → chunk-TMMUBSKW.js} +52 -0
- package/dist/{chunk-OQ4XEG77.js → chunk-TOXRLDUP.js} +2 -2
- package/dist/{client-HU63573O.js → client-FPA76DGY.js} +3 -3
- package/dist/{config-OLF7RBPM.js → config-QZIEYXQZ.js} +20 -5
- package/dist/index.js +18 -13
- package/dist/{raw-GDO4IWNW.js → raw-MZIKHQH4.js} +3 -3
- package/dist/{te-analysis-ZDJXMWZY.js → te-analysis-CFQBXUCO.js} +93 -7
- package/dist/{te-audience-T5B52EEB.js → te-audience-WPBBWADL.js} +3 -3
- package/dist/{te-common-BPTXXTHQ.js → te-common-GL3KBZPD.js} +3 -3
- package/dist/{te-community-FPB5LH56.js → te-community-3XEJNSQL.js} +3 -3
- package/dist/{te-dataops-2NUJVG47.js → te-dataops-H4WSMCG5.js} +3 -3
- package/dist/{te-engage-K3EANZ5P.js → te-engage-2VFM37ZM.js} +3 -3
- package/dist/te-kb-U6SQUJVC.js +41 -0
- package/dist/{te-meta-JJMV75KB.js → te-meta-BO45GW32.js} +10 -8
- package/package.json +2 -1
- package/skills/ae-analysis/SKILL.md +119 -29
- package/skills/ae-analysis/references/build_event_analysis_qp.md +132 -0
- package/skills/ae-analysis/references/build_funnel_analysis_qp.md +143 -0
- package/skills/ae-analysis/references/build_prop_analysis_qp.md +122 -0
- package/skills/ae-analysis/references/build_retention_analysis_qp.md +141 -0
- package/skills/ae-analysis/references/generate_track_program.md +8 -8
- package/skills/ae-analysis/references/get_analysis_query_schema.md +22 -11
- package/skills/ae-analysis/references/get_metric.md +7 -1
- package/skills/ae-analysis/references/get_report_definition.md +4 -0
- package/skills/ae-analysis/references/list_alerts.md +4 -0
- package/skills/ae-analysis/references/list_clusters.md +4 -0
- package/skills/ae-analysis/references/list_dashboards.md +6 -0
- package/skills/ae-analysis/references/list_events.md +8 -1
- package/skills/ae-analysis/references/list_metrics.md +9 -0
- package/skills/ae-analysis/references/list_properties.md +6 -1
- package/skills/ae-analysis/references/list_reports.md +6 -0
- package/skills/ae-analysis/references/list_tags.md +4 -0
- package/skills/ae-analysis/references/query_adhoc.md +80 -30
- package/skills/ae-community/SKILL.md +14 -101
- package/skills/ae-dataops/SKILL.md +13 -58
- package/skills/ae-engage/SKILL.md +15 -98
- 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` |
|
|
90
|
-
| `analysis_audience` |
|
|
91
|
-
| `analysis_meta` | 20 | Metadata governance: events/properties, metrics, virtual metadata, project config, tracking plan, mark times,
|
|
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
|
-
| `
|
|
94
|
-
| `
|
|
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
|
-
| `
|
|
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
|
|
131
|
+
### ae-analysis
|
|
128
132
|
|
|
129
133
|
Unified AE analysis capabilities:
|
|
130
|
-
- **
|
|
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
|
|
135
|
-
- **Common
|
|
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
|
|
139
|
+
### engage
|
|
140
140
|
|
|
141
141
|
Hermes Engage MCP capabilities:
|
|
142
|
-
- **Channels**: channel management, config channels, approval
|
|
143
|
-
- **Tasks**: task list,
|
|
144
|
-
- **Configs**: config items, strategies,
|
|
145
|
-
- **Flows**: flow creation, node config,
|
|
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
|
|
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
|
|
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
|
-
- **
|
|
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` |
|
|
90
|
-
| `analysis_audience` |
|
|
91
|
-
| `analysis_meta` | 20 |
|
|
89
|
+
| `analysis` | 30+ | 分析工作流:告警、报表、仪表板、即时分析/下钻、实体/事件详情、分析模型 |
|
|
90
|
+
| `analysis_audience` | 10+ | 受众运营:分群、标签及其定义模型 |
|
|
91
|
+
| `analysis_meta` | 20+ | 元数据治理:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间、实体目录 |
|
|
92
92
|
| `engage` | 40+ | Hermes Engage MCP:渠道、任务、配置、流程、策略 |
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
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
|
-
| `
|
|
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
|
|
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
|
|
139
|
+
### engage
|
|
140
140
|
|
|
141
141
|
Hermes Engage MCP 能力:
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
142
|
+
- **渠道**:渠道管理、配置渠道、审批、白名单
|
|
143
|
+
- **任务**:任务列表、详情、数据/指标概览、实验报告
|
|
144
|
+
- **配置**:配置项、策略、对比、触发/分析报告
|
|
145
|
+
- **流程**:流程创建、节点配置、报告、验证
|
|
146
146
|
|
|
147
|
-
### ae-dataops
|
|
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
|
|
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,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printError,
|
|
3
|
+
printOutput
|
|
4
|
+
} from "./chunk-KM57HI5B.js";
|
|
5
|
+
import {
|
|
6
|
+
clearMcpToken,
|
|
7
|
+
loadMcpTokenStore,
|
|
8
|
+
setMcpTokenManual,
|
|
9
|
+
validateMcpToken
|
|
10
|
+
} from "./chunk-5CCFSPAF.js";
|
|
11
|
+
import {
|
|
12
|
+
clearToken,
|
|
13
|
+
getAuthStatus,
|
|
14
|
+
getToken,
|
|
15
|
+
resolveHost,
|
|
16
|
+
setTokenManual,
|
|
17
|
+
validateToken
|
|
18
|
+
} from "./chunk-OVMQFFC2.js";
|
|
19
|
+
import {
|
|
20
|
+
loadConfig,
|
|
21
|
+
saveConfig
|
|
22
|
+
} from "./chunk-TMMUBSKW.js";
|
|
23
|
+
|
|
24
|
+
// src/commands/auth.ts
|
|
25
|
+
function registerAuth(program) {
|
|
26
|
+
const auth = program.command("auth").description("Authentication management");
|
|
27
|
+
auth.command("login").description("Login to AE (auto-extract token from Chrome on macOS)").action(async () => {
|
|
28
|
+
const host = resolveHost(program.opts().host);
|
|
29
|
+
if (!host) {
|
|
30
|
+
printError("config", "No AE host configured.", "Run: ae-cli config set-host");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const token = await getToken(host);
|
|
35
|
+
process.stderr.write(`[ae-cli] Authenticated to ${host}
|
|
36
|
+
`);
|
|
37
|
+
printOutput({ authenticated: true, host, token: token.slice(0, 8) + "..." }, program.opts().format || "json");
|
|
38
|
+
} catch (err) {
|
|
39
|
+
printError("auth", err.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
auth.command("set-token <token>").description("Manually set authentication token for active host").action(async (token) => {
|
|
44
|
+
const host = resolveHost(program.opts().host);
|
|
45
|
+
if (!host) {
|
|
46
|
+
printError("config", "No AE host configured.", "Run: ae-cli config set-host");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const config = loadConfig();
|
|
50
|
+
if (!config.hosts[host]) {
|
|
51
|
+
config.hosts[host] = { label: host };
|
|
52
|
+
if (!config.activeHost) {
|
|
53
|
+
config.activeHost = host;
|
|
54
|
+
}
|
|
55
|
+
saveConfig(config);
|
|
56
|
+
process.stderr.write(`[ae-cli] Config saved for ${host}
|
|
57
|
+
`);
|
|
58
|
+
printOutput({ saved: true, config }, program.opts().format || "json");
|
|
59
|
+
}
|
|
60
|
+
process.stderr.write(`[ae-cli] Validating token...
|
|
61
|
+
`);
|
|
62
|
+
const isValid = await validateToken(token, host);
|
|
63
|
+
if (!isValid) {
|
|
64
|
+
process.stderr.write(`[ae-cli] Token validation failed
|
|
65
|
+
`);
|
|
66
|
+
printError("auth", "Invalid token", "Please check your token and try again");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
setTokenManual(token, host);
|
|
70
|
+
process.stderr.write(`[ae-cli] Token verified and saved for ${host}
|
|
71
|
+
`);
|
|
72
|
+
printOutput({ saved: true, host, verified: true }, program.opts().format || "json");
|
|
73
|
+
});
|
|
74
|
+
auth.command("status").description("Show current authentication status").action(async () => {
|
|
75
|
+
const host = resolveHost(program.opts().host);
|
|
76
|
+
if (!host) {
|
|
77
|
+
printOutput({ authenticated: false, host: "(none)", hint: "Run: ae-cli config set-host" }, program.opts().format || "json");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const tokenStatus = getAuthStatus(host);
|
|
81
|
+
const hasValidToken = tokenStatus.authenticated;
|
|
82
|
+
const mcpStore = loadMcpTokenStore();
|
|
83
|
+
const cachedMcpToken = mcpStore[host];
|
|
84
|
+
let hasValidMcpToken = false;
|
|
85
|
+
if (cachedMcpToken) {
|
|
86
|
+
hasValidMcpToken = await validateMcpToken(cachedMcpToken, host);
|
|
87
|
+
}
|
|
88
|
+
const authenticated = hasValidToken || hasValidMcpToken;
|
|
89
|
+
printOutput({ authenticated, host }, program.opts().format || "json");
|
|
90
|
+
});
|
|
91
|
+
auth.command("logout").description("Clear stored token for active host").action(() => {
|
|
92
|
+
const host = resolveHost(program.opts().host);
|
|
93
|
+
if (!host) {
|
|
94
|
+
printError("config", "No AE host configured.", "Run: ae-cli config set-host");
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
clearToken(host);
|
|
98
|
+
process.stderr.write(`[ae-cli] Token cleared for ${host}
|
|
99
|
+
`);
|
|
100
|
+
printOutput({ cleared: true, host }, program.opts().format || "json");
|
|
101
|
+
});
|
|
102
|
+
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) => {
|
|
103
|
+
const host = opts.host || resolveHost(program.opts().host);
|
|
104
|
+
if (!host) {
|
|
105
|
+
printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const config = loadConfig();
|
|
109
|
+
if (!config.hosts[host]) {
|
|
110
|
+
config.hosts[host] = { label: host };
|
|
111
|
+
if (!config.activeHost) {
|
|
112
|
+
config.activeHost = host;
|
|
113
|
+
}
|
|
114
|
+
saveConfig(config);
|
|
115
|
+
process.stderr.write(`[ae-cli] Host config saved for ${host}
|
|
116
|
+
`);
|
|
117
|
+
}
|
|
118
|
+
process.stderr.write(`[ae-cli] Validating MCP token...
|
|
119
|
+
`);
|
|
120
|
+
const isValid = await validateMcpToken(token, host);
|
|
121
|
+
if (!isValid) {
|
|
122
|
+
process.stderr.write(`[ae-cli] MCP token validation failed
|
|
123
|
+
`);
|
|
124
|
+
printError("auth", "Invalid MCP token", "Please check your MCP token and try again");
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
setMcpTokenManual(token, host);
|
|
128
|
+
process.stderr.write(`[ae-cli] MCP token verified and saved for ${host}
|
|
129
|
+
`);
|
|
130
|
+
printOutput({ saved: true, host, verified: true, type: "mcp-token" }, program.opts().format || "json");
|
|
131
|
+
});
|
|
132
|
+
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) => {
|
|
133
|
+
if (opts.all) {
|
|
134
|
+
clearMcpToken();
|
|
135
|
+
process.stderr.write(`[ae-cli] All MCP tokens cleared
|
|
136
|
+
`);
|
|
137
|
+
printOutput({ cleared: true, type: "all-mcp-tokens" }, program.opts().format || "json");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const host = opts.host || resolveHost(program.opts().host);
|
|
141
|
+
if (!host) {
|
|
142
|
+
printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
clearMcpToken(host);
|
|
146
|
+
process.stderr.write(`[ae-cli] MCP token cleared for ${host}
|
|
147
|
+
`);
|
|
148
|
+
printOutput({ cleared: true, host }, program.opts().format || "json");
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
registerAuth
|
|
153
|
+
};
|
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
loadToken,
|
|
6
6
|
resolveHost,
|
|
7
7
|
saveToken,
|
|
8
|
-
setTokenManual
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
setTokenManual,
|
|
9
|
+
validateToken
|
|
10
|
+
} from "./chunk-OVMQFFC2.js";
|
|
11
|
+
import "./chunk-TMMUBSKW.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
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getToken
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OVMQFFC2.js";
|
|
4
4
|
import {
|
|
5
|
+
forceMigrateFromFallback,
|
|
5
6
|
getActiveHost,
|
|
6
7
|
getConfigDir,
|
|
7
8
|
safeJsonParse,
|
|
8
9
|
safeReadJsonFile
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TMMUBSKW.js";
|
|
10
11
|
|
|
11
12
|
// src/core/mcp.ts
|
|
12
13
|
import fs from "fs";
|
|
@@ -102,8 +103,60 @@ async function getMcpToken(hostOverride) {
|
|
|
102
103
|
saveMcpTokenStore(updatedStore);
|
|
103
104
|
return mcpToken;
|
|
104
105
|
}
|
|
106
|
+
function clearMcpToken(hostUrl) {
|
|
107
|
+
const store = loadMcpTokenStore();
|
|
108
|
+
if (hostUrl) {
|
|
109
|
+
delete store[hostUrl];
|
|
110
|
+
} else {
|
|
111
|
+
for (const key of Object.keys(store)) {
|
|
112
|
+
delete store[key];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
saveMcpTokenStore(store);
|
|
116
|
+
}
|
|
117
|
+
function setMcpTokenManual(token, hostUrl) {
|
|
118
|
+
const store = loadMcpTokenStore();
|
|
119
|
+
store[hostUrl] = token;
|
|
120
|
+
saveMcpTokenStore(store);
|
|
121
|
+
}
|
|
122
|
+
async function validateMcpToken(token, hostUrl) {
|
|
123
|
+
const mapping = getMcpMapping("analysis");
|
|
124
|
+
const base = hostUrl.replace(/\/+$/, "");
|
|
125
|
+
const url = `${base}/mcp/${mapping.componentName}/http/${mapping.mappingPath}`;
|
|
126
|
+
const requestId = 1;
|
|
127
|
+
const body = {
|
|
128
|
+
jsonrpc: JSONRPC_VERSION,
|
|
129
|
+
id: requestId,
|
|
130
|
+
method: "tools/list",
|
|
131
|
+
params: { _meta: { progressToken: requestId } }
|
|
132
|
+
};
|
|
133
|
+
const headers = {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
"Accept": "application/json, text/event-stream",
|
|
136
|
+
"mcp-protocol-version": MCP_PROTOCOL_VERSION,
|
|
137
|
+
"mcp-token": token
|
|
138
|
+
};
|
|
139
|
+
try {
|
|
140
|
+
const resp = await fetch(url, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
headers,
|
|
143
|
+
body: JSON.stringify(body)
|
|
144
|
+
});
|
|
145
|
+
if (!resp.ok) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const data = safeJsonParse(await resp.text());
|
|
149
|
+
if (data.error) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return data.result?.tools !== void 0;
|
|
153
|
+
} catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
105
157
|
async function mcpRequest(url, method, params = {}, hostOverride) {
|
|
106
|
-
const
|
|
158
|
+
const hostUrl = hostOverride || getActiveHost();
|
|
159
|
+
const token = await getMcpToken(hostUrl);
|
|
107
160
|
const requestId = genRequestId();
|
|
108
161
|
const paramsWithMeta = {
|
|
109
162
|
...params,
|
|
@@ -127,6 +180,25 @@ async function mcpRequest(url, method, params = {}, hostOverride) {
|
|
|
127
180
|
body: JSON.stringify(body)
|
|
128
181
|
});
|
|
129
182
|
if (!resp.ok) {
|
|
183
|
+
const migrated = forceMigrateFromFallback();
|
|
184
|
+
if (migrated && migrated[hostUrl]) {
|
|
185
|
+
process.stderr.write(`[ae-cli] MCP token refreshed from fallback for ${hostUrl}
|
|
186
|
+
`);
|
|
187
|
+
headers["mcp-token"] = migrated[hostUrl];
|
|
188
|
+
const retryResp = await fetch(url, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
headers,
|
|
191
|
+
body: JSON.stringify(body)
|
|
192
|
+
});
|
|
193
|
+
if (!retryResp.ok) {
|
|
194
|
+
throw new Error(`MCP HTTP error: ${retryResp.status} ${retryResp.statusText}`);
|
|
195
|
+
}
|
|
196
|
+
const retryData = safeJsonParse(await retryResp.text());
|
|
197
|
+
if (retryData.error) {
|
|
198
|
+
throw new Error(`MCP error: ${retryData.error.message || JSON.stringify(retryData.error)}`);
|
|
199
|
+
}
|
|
200
|
+
return retryData.result;
|
|
201
|
+
}
|
|
130
202
|
throw new Error(`MCP HTTP error: ${resp.status} ${resp.statusText}`);
|
|
131
203
|
}
|
|
132
204
|
const data = safeJsonParse(await resp.text());
|
|
@@ -169,6 +241,10 @@ function parseMcpResult(result) {
|
|
|
169
241
|
export {
|
|
170
242
|
registerMcpMappings,
|
|
171
243
|
resolveMcpUrl,
|
|
244
|
+
loadMcpTokenStore,
|
|
245
|
+
clearMcpToken,
|
|
246
|
+
setMcpTokenManual,
|
|
247
|
+
validateMcpToken,
|
|
172
248
|
callMcpTool,
|
|
173
249
|
parseMcpResult
|
|
174
250
|
};
|
|
@@ -2,8 +2,9 @@ import {
|
|
|
2
2
|
extractHostname,
|
|
3
3
|
getActiveHost,
|
|
4
4
|
getConfigDir,
|
|
5
|
+
safeJsonParse,
|
|
5
6
|
safeReadJsonFile
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TMMUBSKW.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,
|
|
@@ -17,11 +17,46 @@ 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
|
+
return doMigrateFromFallback();
|
|
30
|
+
}
|
|
31
|
+
function forceMigrateFromFallback() {
|
|
32
|
+
if (!fs2.existsSync(FALLBACK_MCP_TOKEN_FILE)) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return doMigrateFromFallback();
|
|
36
|
+
}
|
|
37
|
+
function doMigrateFromFallback() {
|
|
38
|
+
try {
|
|
39
|
+
const fallbackData = safeReadJsonFile(FALLBACK_MCP_TOKEN_FILE);
|
|
40
|
+
const tokenStore = {};
|
|
41
|
+
if (fallbackData && typeof fallbackData === "object" && !Array.isArray(fallbackData)) {
|
|
42
|
+
const url = fallbackData.url;
|
|
43
|
+
const token = fallbackData["mcp-token"];
|
|
44
|
+
if (url && token) {
|
|
45
|
+
tokenStore[url] = token;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (Object.keys(tokenStore).length > 0) {
|
|
49
|
+
ensureDir();
|
|
50
|
+
fs2.writeFileSync(MCP_TOKENS_FILE, JSON.stringify(tokenStore, null, 2));
|
|
51
|
+
return tokenStore;
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
23
57
|
function loadConfig() {
|
|
24
58
|
try {
|
|
59
|
+
const migratedTokens = migrateFromFallback();
|
|
25
60
|
if (fs2.existsSync(CONFIG_FILE)) {
|
|
26
61
|
const raw = safeReadJsonFile(CONFIG_FILE);
|
|
27
62
|
if (raw.defaultHost && !raw.activeHost) {
|
|
@@ -31,6 +66,22 @@ function loadConfig() {
|
|
|
31
66
|
}
|
|
32
67
|
return raw;
|
|
33
68
|
}
|
|
69
|
+
if (migratedTokens && Object.keys(migratedTokens).length > 0) {
|
|
70
|
+
const hosts = {};
|
|
71
|
+
for (const url of Object.keys(migratedTokens)) {
|
|
72
|
+
hosts[url] = { label: url };
|
|
73
|
+
process.stderr.write(`[ae-cli] Added host: ${url}
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
const activeHost = Object.keys(migratedTokens)[0];
|
|
77
|
+
process.stderr.write(`[ae-cli] Active host set to: ${activeHost}
|
|
78
|
+
`);
|
|
79
|
+
process.stderr.write(`[ae-cli] MCP tokens migrated from ${FALLBACK_MCP_TOKEN_FILE}
|
|
80
|
+
`);
|
|
81
|
+
const config = { activeHost, hosts };
|
|
82
|
+
saveConfig(config);
|
|
83
|
+
return config;
|
|
84
|
+
}
|
|
34
85
|
} catch (err) {
|
|
35
86
|
console.error(`Error loading config: ${err.message}`);
|
|
36
87
|
}
|
|
@@ -114,6 +165,7 @@ function extractHostname(fullUrl) {
|
|
|
114
165
|
export {
|
|
115
166
|
safeJsonParse,
|
|
116
167
|
safeReadJsonFile,
|
|
168
|
+
forceMigrateFromFallback,
|
|
117
169
|
loadConfig,
|
|
118
170
|
saveConfig,
|
|
119
171
|
getActiveHost,
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
clearToken,
|
|
3
3
|
getToken,
|
|
4
4
|
resolveHost
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OVMQFFC2.js";
|
|
6
6
|
import {
|
|
7
7
|
safeJsonParse
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-TMMUBSKW.js";
|
|
9
9
|
|
|
10
10
|
// src/core/client.ts
|
|
11
11
|
import WebSocket from "ws";
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
queryReportData,
|
|
5
5
|
querySql,
|
|
6
6
|
wsQuery
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-TOXRLDUP.js";
|
|
8
|
+
import "./chunk-OVMQFFC2.js";
|
|
9
|
+
import "./chunk-TMMUBSKW.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
|
-
|
|
4
|
+
getToken,
|
|
5
|
+
loadToken,
|
|
6
|
+
validateToken
|
|
7
|
+
} from "./chunk-OVMQFFC2.js";
|
|
5
8
|
import {
|
|
6
9
|
addHost,
|
|
7
10
|
listHosts,
|
|
8
11
|
removeHost,
|
|
9
12
|
setActiveHost,
|
|
10
13
|
updateHostLabel
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TMMUBSKW.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
|
-
|
|
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
|
-
|
|
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...
|