@thinkingai/ae-cli 6.0.18 → 6.0.22
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 +8 -10
- package/README.zh.md +9 -11
- package/dist/{auth-DYC2BGLM.js → auth-I2G7OAU2.js} +2 -4
- package/dist/{auth-GHBMJ5ZR.js → auth-RDN6D5HU.js} +32 -104
- package/dist/{chunk-5OC7CYCG.js → chunk-2W7HULUD.js} +14 -14
- package/dist/chunk-4EUZRJPO.js +163 -0
- package/dist/{chunk-DMMEPCST.js → chunk-5FBLRSMU.js} +25 -115
- package/dist/{chunk-BJX3GXWC.js → chunk-E34XH4GW.js} +2 -2
- package/dist/chunk-FPE5LGVU.js +105 -0
- package/dist/{chunk-I5CRVM2S.js → chunk-H52CSLJW.js} +44 -17
- package/dist/{chunk-RSHMZ3LG.js → chunk-U6QPKCN3.js} +6 -20
- package/dist/{chunk-6W4QOZAL.js → chunk-WPXHCP4A.js} +23 -13
- package/dist/{chunk-PN3OS34E.js → chunk-XE2PI5DS.js} +1 -1
- package/dist/{chunk-2DUEAXV3.js → chunk-YACCPUNQ.js} +1 -1
- package/dist/cli-token-6AGEDJF4.js +14 -0
- package/dist/{client-2UJ63MVQ.js → client-VTJMUZ4O.js} +3 -3
- package/dist/{config-NCUGK6NS.js → config-2SDTLGOC.js} +3 -3
- package/dist/index.js +314 -197
- package/dist/metadata-JZ2OTWBK.js +420 -0
- package/dist/{model-SJSOZTRS.js → model-ZYMRN4VS.js} +2 -2
- package/dist/{raw-7NVWSVJP.js → raw-NGYHAL3F.js} +4 -4
- package/dist/{sync-GRVO4K3U.js → sync-JVLX6TGW.js} +3 -3
- package/dist/{te-agent-KZRIEN4N.js → te-agent-QPZTLHPH.js} +545 -21
- package/dist/{te-analysis-VAR4KUOK.js → te-analysis-WWX3Z6RP.js} +352 -52
- package/dist/te-audience-UXGHUVBB.js +599 -0
- package/dist/{te-common-WNCZB7R7.js → te-common-7XXH73MF.js} +5 -4
- package/dist/{te-community-JEEFXPB3.js → te-community-QKE67HR2.js} +5 -4
- package/dist/te-dataops-6W7NNYST.js +1841 -0
- package/dist/{te-engage-4XHCTS6I.js → te-engage-NCFAQFX3.js} +5 -4
- package/dist/{te-kb-B62KFP2A.js → te-kb-K5BQYUCM.js} +50 -26
- package/dist/{te-meta-EPZGQN56.js → te-meta-LJZBOSMO.js} +48 -24
- package/dist/{te-team-YY24VORI.js → te-team-DHK5R7MV.js} +5 -6
- package/package.json +3 -2
- package/skills/ae-agent/SKILL.md +103 -4
- package/skills/ae-analysis/SKILL.md +75 -21
- package/skills/ae-analysis/references/build_attribution_analysis_qp.md +62 -0
- package/skills/ae-analysis/references/build_cluster_definition.md +62 -0
- package/skills/ae-analysis/references/build_distribution_analysis_qp.md +67 -0
- package/skills/ae-analysis/references/build_event_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_funnel_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_heat_map_analysis_qp.md +54 -0
- package/skills/ae-analysis/references/build_interval_analysis_qp.md +60 -0
- package/skills/ae-analysis/references/build_path_analysis_qp.md +53 -0
- package/skills/ae-analysis/references/build_prop_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_rank_list_analysis_qp.md +63 -0
- package/skills/ae-analysis/references/build_retention_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_tag_definition.md +65 -0
- package/skills/ae-analysis/references/cancel_query.md +2 -3
- package/skills/ae-analysis/references/copy_dashboard.md +33 -0
- package/skills/ae-analysis/references/create_id_cluster.md +40 -0
- package/skills/ae-analysis/references/create_id_tag.md +39 -0
- package/skills/ae-analysis/references/delete_alert.md +27 -0
- package/skills/ae-analysis/references/delete_cluster.md +27 -0
- package/skills/ae-analysis/references/delete_dashboard.md +30 -0
- package/skills/ae-analysis/references/delete_metric.md +27 -0
- package/skills/ae-analysis/references/delete_report.md +27 -0
- package/skills/ae-analysis/references/delete_tag.md +27 -0
- package/skills/ae-analysis/references/drilldown_user_events.md +4 -4
- package/skills/ae-analysis/references/drilldown_users.md +3 -3
- package/skills/ae-analysis/references/freeze_dashboards.md +29 -0
- package/skills/ae-analysis/references/get_table_columns.md +11 -12
- package/skills/ae-analysis/references/list_cluster_members.md +4 -4
- package/skills/ae-analysis/references/list_clusters.md +5 -3
- package/skills/ae-analysis/references/list_dashboards.md +3 -3
- package/skills/ae-analysis/references/list_entities.md +1 -1
- package/skills/ae-analysis/references/list_events.md +7 -4
- package/skills/ae-analysis/references/list_metrics.md +5 -3
- package/skills/ae-analysis/references/list_properties.md +6 -4
- package/skills/ae-analysis/references/list_reports.md +3 -3
- package/skills/ae-analysis/references/list_spaces.md +27 -0
- package/skills/ae-analysis/references/list_tag_members.md +4 -4
- package/skills/ae-analysis/references/list_tags.md +4 -2
- package/skills/ae-analysis/references/move_dashboard.md +33 -0
- package/skills/ae-analysis/references/query_adhoc.md +2 -2
- package/skills/ae-analysis/references/query_bi_panel_data.md +2 -2
- package/skills/ae-analysis/references/query_dashboard_report_data.md +4 -4
- package/skills/ae-analysis/references/query_entity_details.md +4 -4
- package/skills/ae-analysis/references/query_event_details.md +3 -3
- package/skills/ae-analysis/references/query_report_data.md +37 -3
- package/skills/ae-analysis/references/update_id_cluster.md +36 -0
- package/skills/ae-analysis/references/update_id_tag.md +37 -0
- package/skills/ae-analysis/references/update_report.md +35 -0
- package/skills/ae-analysis-intent/SKILL.md +1 -1
- package/skills/ae-dataops/SKILL.md +54 -522
- package/skills/ae-dataops/references/dataops-flow-create.md +78 -75
- package/skills/ae-dataops/references/dataops-flow-monitor.md +58 -51
- package/skills/ae-dataops/references/dataops-integration.md +80 -41
- package/skills/ae-dataops/references/dataops-query.md +54 -53
- package/skills/ae-dataops/references/dataops-table.md +28 -59
- package/skills/ae-generate-tracking-code/SKILL.md +68 -31
- package/skills/ae-generate-tracking-code/references/snippet-delivery.md +26 -1
- package/skills/ae-generate-tracking-code/references/te-api.md +47 -164
- package/skills/ae-generate-tracking-plan/SKILL.md +109 -32
- package/skills/ae-generate-tracking-plan/references/te-api.md +57 -27
- package/skills/ae-metadata/SKILL.md +90 -0
- package/skills/ae-metadata/references/metadata_data_table_csv_delete.md +15 -0
- package/skills/ae-metadata/references/metadata_data_table_csv_write.md +29 -0
- package/skills/ae-metadata/references/metadata_data_table_download.md +17 -0
- package/skills/ae-metadata/references/metadata_data_table_get.md +24 -0
- package/skills/ae-metadata/references/metadata_data_table_list.md +27 -0
- package/skills/ae-metadata/references/metadata_data_table_property_bindings_update.md +17 -0
- package/skills/ae-metadata/references/metadata_data_table_sql_delete.md +15 -0
- package/skills/ae-metadata/references/metadata_data_table_sql_write.md +31 -0
- package/skills/ae-metadata/references/metadata_event_get.md +52 -0
- package/skills/ae-metadata/references/metadata_input_file_upload.md +29 -0
- package/skills/ae-metadata/references/metadata_property_dimension_table_bind_existing.md +27 -0
- package/skills/ae-metadata/references/metadata_property_dimension_table_create_and_bind_csv.md +30 -0
- package/skills/ae-metadata/references/metadata_property_get.md +54 -0
- package/dist/te-audience-KMKYI2YJ.js +0 -400
- package/dist/te-dataops-GD3XBYCS.js +0 -1830
package/README.md
CHANGED
|
@@ -67,12 +67,9 @@ ae-cli kb +read --source '{"scope":"company","name":"engineering-handbook"}' \
|
|
|
67
67
|
Authentication is handled per-host. Each AE host URL maintains its own token.
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
#
|
|
70
|
+
# Device code login (cross-platform)
|
|
71
71
|
ae-cli auth login
|
|
72
72
|
|
|
73
|
-
# Manually set token
|
|
74
|
-
ae-cli auth set-token <your-token>
|
|
75
|
-
|
|
76
73
|
# Check status
|
|
77
74
|
ae-cli auth status
|
|
78
75
|
|
|
@@ -90,11 +87,12 @@ ae-cli auth logout
|
|
|
90
87
|
| `analysis_audience` | 10+ | Audience operations: clusters, tags, and cluster/tag definition schema |
|
|
91
88
|
| `analysis_meta` | 20+ | Metadata governance: events/properties, metrics, virtual metadata, project config, tracking plan, mark times, entity catalog |
|
|
92
89
|
| `engage` | 40+ | Hermes Engage MCP: channels, tasks, configs, flows, strategies |
|
|
93
|
-
| `dataops_repo` |
|
|
94
|
-
| `dataops_datatable` |
|
|
95
|
-
| `dataops_flow` |
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
90
|
+
| `dataops_repo` | 1 | DataOps repo utilities: space discovery |
|
|
91
|
+
| `dataops_datatable` | 5 | Data tables: table/view creation, publishing, details, data dictionary |
|
|
92
|
+
| `dataops_flow` | 15 | Task flows: flow creation, task nodes, scheduling, execution, release preview |
|
|
93
|
+
| `dataops_operations` | 4 | Operations: workflow instance search, instance detail, task logs, stop |
|
|
94
|
+
| `dataops_ide` | 9 | IDE queries: metadata browsing, SQL execution, query management |
|
|
95
|
+
| `dataops_integration` | 19 | Data integration: datasource management, sync solutions, data synchronization |
|
|
98
96
|
| `community` | 10+ | Community analysis: posts search, sentiment analysis, topic trends, livestream data |
|
|
99
97
|
| `analysis_common` | 2 | Cross-module common constraints: resource link completion, project ID gate |
|
|
100
98
|
| `team` | 14 | AI Agent Team: manage teams (list/create/update/delete/ai-generate/templates/projects) and execute TeamRuns (start/watch/chat/reply/cancel/result/artifacts) |
|
|
@@ -169,7 +167,7 @@ Hermes Engage MCP capabilities:
|
|
|
169
167
|
### ae-dataops
|
|
170
168
|
|
|
171
169
|
Data warehouse management:
|
|
172
|
-
- **Repo
|
|
170
|
+
- **Repo Utilities**: space discovery
|
|
173
171
|
- **Data Tables**: table creation, views, batch operations, data dictionary
|
|
174
172
|
- **Task Flows**: flow creation, task nodes, scheduling, execution, monitoring
|
|
175
173
|
- **IDE Queries**: metadata browsing, SQL execution, query management
|
package/README.zh.md
CHANGED
|
@@ -67,12 +67,9 @@ ae-cli kb +read --source '{"scope":"company","name":"engineering-handbook"}' \
|
|
|
67
67
|
每个 AE 主机 URL 维护独立的身份验证 token。
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
#
|
|
70
|
+
# 设备码登录(跨平台)
|
|
71
71
|
ae-cli auth login
|
|
72
72
|
|
|
73
|
-
# 手动设置 token
|
|
74
|
-
ae-cli auth set-token <your-token>
|
|
75
|
-
|
|
76
73
|
# 检查状态
|
|
77
74
|
ae-cli auth status
|
|
78
75
|
|
|
@@ -90,11 +87,12 @@ ae-cli auth logout
|
|
|
90
87
|
| `analysis_audience` | 10+ | 受众运营:分群、标签及其定义模型 |
|
|
91
88
|
| `analysis_meta` | 20+ | 元数据治理:事件/属性、指标、虚拟元数据、项目配置、埋点方案、标记时间、实体目录 |
|
|
92
89
|
| `engage` | 40+ | Hermes Engage MCP:渠道、任务、配置、流程、策略 |
|
|
93
|
-
| `dataops_repo` |
|
|
94
|
-
| `dataops_datatable` |
|
|
95
|
-
| `dataops_flow` |
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
90
|
+
| `dataops_repo` | 1 | DataOps 仓库辅助:空间发现 |
|
|
91
|
+
| `dataops_datatable` | 5 | 数据表:表/视图创建、发布、详情、数据字典 |
|
|
92
|
+
| `dataops_flow` | 15 | 任务流:流程创建、任务节点、调度、执行、监控、发布预览 |
|
|
93
|
+
| `dataops_operations` | 4 | 运维:工作流实例搜索、实例详情、任务日志、停止执行 |
|
|
94
|
+
| `dataops_ide` | 9 | IDE 查询:元数据浏览、SQL 执行、查询管理 |
|
|
95
|
+
| `dataops_integration` | 19 | 数据集成:数据源管理、同步方案、数据同步 |
|
|
98
96
|
| `community` | 10+ | 社区分析:帖子搜索、情感分析、话题趋势、直播数据 |
|
|
99
97
|
| `analysis_common` | 2 | 跨模块通用约束:资源链接补全、项目 ID 门控 |
|
|
100
98
|
| `agent` | 15 | Agent 平台资源管理:模型、MCP 服务、Skill、附件库的增删查和启停 |
|
|
@@ -170,7 +168,7 @@ Hermes Engage MCP 能力:
|
|
|
170
168
|
### ae-dataops
|
|
171
169
|
|
|
172
170
|
数仓管理:
|
|
173
|
-
-
|
|
171
|
+
- **仓库辅助**:空间发现
|
|
174
172
|
- **数据表**:表创建、视图、批量操作、数据字典
|
|
175
173
|
- **任务流**:流程创建、任务节点、调度、执行、监控
|
|
176
174
|
- **IDE 查询**:元数据浏览、SQL 执行、查询管理
|
|
@@ -223,4 +221,4 @@ npm run verify:analysis-common-tools
|
|
|
223
221
|
|
|
224
222
|
## 许可证
|
|
225
223
|
|
|
226
|
-
MIT
|
|
224
|
+
MIT
|
|
@@ -5,10 +5,9 @@ import {
|
|
|
5
5
|
loadToken,
|
|
6
6
|
resolveHost,
|
|
7
7
|
saveToken,
|
|
8
|
-
setTokenManual,
|
|
9
8
|
validateToken
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-U6QPKCN3.js";
|
|
10
|
+
import "./chunk-WPXHCP4A.js";
|
|
12
11
|
export {
|
|
13
12
|
clearToken,
|
|
14
13
|
getAuthStatus,
|
|
@@ -16,6 +15,5 @@ export {
|
|
|
16
15
|
loadToken,
|
|
17
16
|
resolveHost,
|
|
18
17
|
saveToken,
|
|
19
|
-
setTokenManual,
|
|
20
18
|
validateToken
|
|
21
19
|
};
|
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
printError,
|
|
3
3
|
printOutput
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YACCPUNQ.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "./chunk-DMMEPCST.js";
|
|
10
|
-
import "./chunk-PN3OS34E.js";
|
|
11
|
-
import "./chunk-NOO24N7W.js";
|
|
6
|
+
clearCliToken,
|
|
7
|
+
mintCliToken
|
|
8
|
+
} from "./chunk-FPE5LGVU.js";
|
|
12
9
|
import {
|
|
13
10
|
clear,
|
|
14
11
|
clearToken,
|
|
15
12
|
getAuthStatus,
|
|
16
13
|
load,
|
|
17
14
|
resolveHost,
|
|
18
|
-
save
|
|
19
|
-
|
|
20
|
-
validateToken
|
|
21
|
-
} from "./chunk-RSHMZ3LG.js";
|
|
15
|
+
save
|
|
16
|
+
} from "./chunk-U6QPKCN3.js";
|
|
22
17
|
import {
|
|
18
|
+
getFallbackCliToken,
|
|
23
19
|
loadConfig,
|
|
24
20
|
logger,
|
|
25
21
|
removeHost,
|
|
26
22
|
saveConfig
|
|
27
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-WPXHCP4A.js";
|
|
28
24
|
|
|
29
25
|
// src/core/device-auth.ts
|
|
30
26
|
import { execFileSync } from "child_process";
|
|
@@ -246,7 +242,7 @@ function activateHostAfterLogin(host, explicitHostOverride) {
|
|
|
246
242
|
saveConfig(config);
|
|
247
243
|
logger.info(`Active host set to ${host} after login`);
|
|
248
244
|
}
|
|
249
|
-
function persistDeviceTokens(host, tokens) {
|
|
245
|
+
async function persistDeviceTokens(host, tokens) {
|
|
250
246
|
const DEFAULT_EXPIRES_IN = 72e3;
|
|
251
247
|
const MAX_EXPIRES_IN = 86400 * 365;
|
|
252
248
|
let expiresInSeconds = tokens.expires_in ?? DEFAULT_EXPIRES_IN;
|
|
@@ -258,16 +254,15 @@ function persistDeviceTokens(host, tokens) {
|
|
|
258
254
|
save(host, {
|
|
259
255
|
accessToken: tokens.access_token,
|
|
260
256
|
refreshToken: tokens.refresh_token ?? "",
|
|
261
|
-
accessExpiresAt: expiresAt
|
|
262
|
-
mcpToken: tokens.mcp_token ?? void 0
|
|
257
|
+
accessExpiresAt: expiresAt
|
|
263
258
|
});
|
|
259
|
+
await mintCliToken(host);
|
|
264
260
|
}
|
|
265
261
|
function loginSummary(host, tokens) {
|
|
266
262
|
return {
|
|
267
263
|
authenticated: true,
|
|
268
264
|
host,
|
|
269
|
-
token: tokens.access_token.slice(0, 8) + "..."
|
|
270
|
-
mcpToken: tokens.mcp_token ? tokens.mcp_token.slice(0, 8) + "..." : null
|
|
265
|
+
token: tokens.access_token.slice(0, 8) + "..."
|
|
271
266
|
};
|
|
272
267
|
}
|
|
273
268
|
function resolveLoginTeClaudeBase(host) {
|
|
@@ -303,7 +298,7 @@ function registerAuth(program) {
|
|
|
303
298
|
try {
|
|
304
299
|
if (opts.deviceCode) {
|
|
305
300
|
const tokens2 = await pollDeviceFlow(teClaudeBase, opts.deviceCode, {}, emit);
|
|
306
|
-
persistDeviceTokens(host, tokens2);
|
|
301
|
+
await persistDeviceTokens(host, tokens2);
|
|
307
302
|
activateHostAfterLogin(host, explicitHost);
|
|
308
303
|
logger.info(`Device flow login successful for ${host} (resumed)`);
|
|
309
304
|
emit("Login successful! Token saved securely.");
|
|
@@ -326,7 +321,7 @@ function registerAuth(program) {
|
|
|
326
321
|
return;
|
|
327
322
|
}
|
|
328
323
|
const tokens = await runDeviceFlow(teClaudeBase, { noBrowser }, emit);
|
|
329
|
-
persistDeviceTokens(host, tokens);
|
|
324
|
+
await persistDeviceTokens(host, tokens);
|
|
330
325
|
activateHostAfterLogin(host, explicitHost);
|
|
331
326
|
logger.info(`Device flow login successful for ${host}`);
|
|
332
327
|
emit("Login successful! Token saved securely.");
|
|
@@ -336,7 +331,7 @@ function registerAuth(program) {
|
|
|
336
331
|
printError(
|
|
337
332
|
"auth",
|
|
338
333
|
err.message,
|
|
339
|
-
"
|
|
334
|
+
"Upgrade the AE server to a version that supports device login."
|
|
340
335
|
);
|
|
341
336
|
process.exit(1);
|
|
342
337
|
}
|
|
@@ -344,39 +339,6 @@ function registerAuth(program) {
|
|
|
344
339
|
process.exit(1);
|
|
345
340
|
}
|
|
346
341
|
});
|
|
347
|
-
auth.command("set-token <token>").description("Manually set authentication token for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (token, opts) => {
|
|
348
|
-
const host = resolveAuthHost(program, opts);
|
|
349
|
-
if (!host) {
|
|
350
|
-
printError("config", "No AE host configured.", "Run: ae-cli config set-host <url>");
|
|
351
|
-
process.exit(1);
|
|
352
|
-
}
|
|
353
|
-
const config = loadConfig();
|
|
354
|
-
if (!config.hosts[host]) {
|
|
355
|
-
config.hosts[host] = { label: host };
|
|
356
|
-
if (!config.activeHost) {
|
|
357
|
-
config.activeHost = host;
|
|
358
|
-
}
|
|
359
|
-
saveConfig(config);
|
|
360
|
-
process.stderr.write(`[ae-cli] Config saved for ${host}
|
|
361
|
-
`);
|
|
362
|
-
printOutput({ saved: true, config }, program.opts().format || "json");
|
|
363
|
-
}
|
|
364
|
-
process.stderr.write(`[ae-cli] Validating token...
|
|
365
|
-
`);
|
|
366
|
-
const isValid = await validateToken(token, host);
|
|
367
|
-
if (!isValid) {
|
|
368
|
-
logger.warn(`Token validation failed for ${host}`);
|
|
369
|
-
process.stderr.write(`[ae-cli] Token validation failed
|
|
370
|
-
`);
|
|
371
|
-
printError("auth", "Invalid token", "Please check your token and try again");
|
|
372
|
-
process.exit(1);
|
|
373
|
-
}
|
|
374
|
-
setTokenManual(token, host);
|
|
375
|
-
logger.info(`Token manually set and validated for ${host}`);
|
|
376
|
-
process.stderr.write(`[ae-cli] Token verified and saved for ${host}
|
|
377
|
-
`);
|
|
378
|
-
printOutput({ saved: true, host, verified: true }, program.opts().format || "json");
|
|
379
|
-
});
|
|
380
342
|
auth.command("status").description("Show authentication status for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
|
|
381
343
|
const host = resolveAuthHost(program, opts);
|
|
382
344
|
if (!host) {
|
|
@@ -394,7 +356,20 @@ function registerAuth(program) {
|
|
|
394
356
|
accessExpiresAt: secureEntry.accessExpiresAt,
|
|
395
357
|
accessExpiresAtNote: "advisory: access token auto-slides on use server-side; re-login only if a command returns an auth error",
|
|
396
358
|
pastStaticExpiry,
|
|
397
|
-
|
|
359
|
+
hasCliToken: !!secureEntry.cliToken
|
|
360
|
+
},
|
|
361
|
+
program.opts().format || "json"
|
|
362
|
+
);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const fallbackCliToken = getFallbackCliToken(host);
|
|
366
|
+
if (fallbackCliToken) {
|
|
367
|
+
printOutput(
|
|
368
|
+
{
|
|
369
|
+
authenticated: true,
|
|
370
|
+
host,
|
|
371
|
+
source: "sandbox-cli-token",
|
|
372
|
+
hasCliToken: true
|
|
398
373
|
},
|
|
399
374
|
program.opts().format || "json"
|
|
400
375
|
);
|
|
@@ -404,64 +379,17 @@ function registerAuth(program) {
|
|
|
404
379
|
const authenticated = tokenStatus.authenticated;
|
|
405
380
|
printOutput({ authenticated, host, source: tokenStatus.source ?? "none" }, program.opts().format || "json");
|
|
406
381
|
});
|
|
407
|
-
auth.command("logout").description("Clear stored token for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action((opts) => {
|
|
382
|
+
auth.command("logout").description("Clear stored credentials (access token, CLI token, and host config) for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action((opts) => {
|
|
408
383
|
const host = resolveAuthHost(program, opts);
|
|
409
384
|
if (!host) {
|
|
410
385
|
printError("config", "No AE host configured.", "Run: ae-cli config set-host <url>");
|
|
411
386
|
process.exit(1);
|
|
412
387
|
}
|
|
388
|
+
clearCliToken(host);
|
|
413
389
|
clearToken(host);
|
|
414
390
|
clear(host);
|
|
415
391
|
removeHost(host);
|
|
416
|
-
process.stderr.write(`[ae-cli]
|
|
417
|
-
`);
|
|
418
|
-
printOutput({ cleared: true, host }, program.opts().format || "json");
|
|
419
|
-
});
|
|
420
|
-
auth.command("set-mcp-token <token>").description("Manually set MCP token for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (token, opts) => {
|
|
421
|
-
const host = resolveAuthHost(program, opts);
|
|
422
|
-
if (!host) {
|
|
423
|
-
printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host <url>");
|
|
424
|
-
process.exit(1);
|
|
425
|
-
}
|
|
426
|
-
const config = loadConfig();
|
|
427
|
-
if (!config.hosts[host]) {
|
|
428
|
-
config.hosts[host] = { label: host };
|
|
429
|
-
if (!config.activeHost) {
|
|
430
|
-
config.activeHost = host;
|
|
431
|
-
}
|
|
432
|
-
saveConfig(config);
|
|
433
|
-
process.stderr.write(`[ae-cli] Host config saved for ${host}
|
|
434
|
-
`);
|
|
435
|
-
}
|
|
436
|
-
process.stderr.write(`[ae-cli] Validating MCP token...
|
|
437
|
-
`);
|
|
438
|
-
const isValid = await validateMcpToken(token, host);
|
|
439
|
-
if (!isValid) {
|
|
440
|
-
process.stderr.write(`[ae-cli] MCP token validation failed
|
|
441
|
-
`);
|
|
442
|
-
printError("auth", "Invalid MCP token", "Please check your MCP token and try again");
|
|
443
|
-
process.exit(1);
|
|
444
|
-
}
|
|
445
|
-
setMcpTokenManual(token, host);
|
|
446
|
-
process.stderr.write(`[ae-cli] MCP token verified and saved for ${host}
|
|
447
|
-
`);
|
|
448
|
-
printOutput({ saved: true, host, verified: true, type: "mcp-token" }, program.opts().format || "json");
|
|
449
|
-
});
|
|
450
|
-
auth.command("clear-mcp-token").description("Clear stored MCP token for a host (--host or active host; --all clears all)").option("--host <url>", HOST_OPTION_DESC).option("--all", "Clear MCP tokens for all hosts").action((opts) => {
|
|
451
|
-
if (opts.all) {
|
|
452
|
-
clearMcpToken();
|
|
453
|
-
process.stderr.write(`[ae-cli] All MCP tokens cleared
|
|
454
|
-
`);
|
|
455
|
-
printOutput({ cleared: true, type: "all-mcp-tokens" }, program.opts().format || "json");
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
const host = resolveAuthHost(program, opts);
|
|
459
|
-
if (!host) {
|
|
460
|
-
printError("config", "No AE host configured.", "Use --host <url> or run: ae-cli config set-host <url>");
|
|
461
|
-
process.exit(1);
|
|
462
|
-
}
|
|
463
|
-
clearMcpToken(host);
|
|
464
|
-
process.stderr.write(`[ae-cli] MCP token cleared for ${host}
|
|
392
|
+
process.stderr.write(`[ae-cli] Credentials and config cleared for ${host}
|
|
465
393
|
`);
|
|
466
394
|
printOutput({ cleared: true, host }, program.opts().format || "json");
|
|
467
395
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getMcpToken
|
|
3
|
-
} from "./chunk-DMMEPCST.js";
|
|
4
1
|
import {
|
|
5
2
|
PermissionError
|
|
6
3
|
} from "./chunk-NOO24N7W.js";
|
|
4
|
+
import {
|
|
5
|
+
getCliToken
|
|
6
|
+
} from "./chunk-FPE5LGVU.js";
|
|
7
7
|
import {
|
|
8
8
|
safeJsonParse
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-WPXHCP4A.js";
|
|
10
10
|
|
|
11
11
|
// src/core/mcp-access.ts
|
|
12
12
|
function buildUrl(host, path, params = {}) {
|
|
@@ -52,21 +52,21 @@ function parseKbResponse(resp, text) {
|
|
|
52
52
|
}
|
|
53
53
|
return data.data !== void 0 ? data.data : data;
|
|
54
54
|
}
|
|
55
|
-
async function
|
|
55
|
+
async function fetchWithCliToken(input, init, cliToken) {
|
|
56
56
|
const headers = new Headers(init.headers);
|
|
57
|
-
headers.set("
|
|
57
|
+
headers.set("cli-token", cliToken);
|
|
58
58
|
const resp = await fetch(input, { ...init, headers });
|
|
59
59
|
return parseKbResponse(resp, await resp.text());
|
|
60
60
|
}
|
|
61
61
|
async function getAuthHeaders(ctx) {
|
|
62
|
-
const
|
|
63
|
-
return { "
|
|
62
|
+
const cliToken = await getCliToken(ctx.host());
|
|
63
|
+
return { "cli-token": cliToken };
|
|
64
64
|
}
|
|
65
65
|
async function kbApi(ctx, method, path, params = {}, body) {
|
|
66
66
|
const host = ctx.host();
|
|
67
|
-
const
|
|
67
|
+
const cliToken = await getCliToken(host);
|
|
68
68
|
const upperMethod = method.toUpperCase();
|
|
69
|
-
return
|
|
69
|
+
return fetchWithCliToken(
|
|
70
70
|
buildUrl(host, path, params),
|
|
71
71
|
{
|
|
72
72
|
method: upperMethod,
|
|
@@ -75,19 +75,19 @@ async function kbApi(ctx, method, path, params = {}, body) {
|
|
|
75
75
|
},
|
|
76
76
|
body: upperMethod === "GET" ? void 0 : JSON.stringify(body ?? {})
|
|
77
77
|
},
|
|
78
|
-
|
|
78
|
+
cliToken
|
|
79
79
|
);
|
|
80
80
|
}
|
|
81
81
|
async function kbUpload(ctx, path, form, params = {}) {
|
|
82
82
|
const host = ctx.host();
|
|
83
|
-
const
|
|
84
|
-
return
|
|
83
|
+
const cliToken = await getCliToken(host);
|
|
84
|
+
return fetchWithCliToken(
|
|
85
85
|
buildUrl(host, path, params),
|
|
86
86
|
{
|
|
87
87
|
method: "POST",
|
|
88
88
|
body: form
|
|
89
89
|
},
|
|
90
|
-
|
|
90
|
+
cliToken
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PermissionError
|
|
3
|
+
} from "./chunk-NOO24N7W.js";
|
|
4
|
+
import {
|
|
5
|
+
clearCliToken,
|
|
6
|
+
getCliToken
|
|
7
|
+
} from "./chunk-FPE5LGVU.js";
|
|
8
|
+
import {
|
|
9
|
+
logger,
|
|
10
|
+
safeJsonParse
|
|
11
|
+
} from "./chunk-WPXHCP4A.js";
|
|
12
|
+
|
|
13
|
+
// src/core/capability-api.ts
|
|
14
|
+
import { readFile } from "fs/promises";
|
|
15
|
+
import { basename } from "path";
|
|
16
|
+
var CapabilityGatewayError = class extends Error {
|
|
17
|
+
constructor(message, code, httpStatus) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.httpStatus = httpStatus;
|
|
21
|
+
this.name = "CapabilityGatewayError";
|
|
22
|
+
}
|
|
23
|
+
code;
|
|
24
|
+
httpStatus;
|
|
25
|
+
};
|
|
26
|
+
function buildCapabilityGatewayUrl(host, domain, pathAfterV1, queryParams = {}) {
|
|
27
|
+
const base = host.replace(/\/+$/, "");
|
|
28
|
+
const cleanDomain = domain.replace(/^\/+|\/+$/g, "");
|
|
29
|
+
const cleanPath = pathAfterV1.replace(/^\/+|\/+$/g, "");
|
|
30
|
+
const url = new URL(`${base}/api/cli/${cleanDomain}/v1/${cleanPath}`);
|
|
31
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
32
|
+
if (value !== void 0 && value !== null) {
|
|
33
|
+
url.searchParams.set(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return url.toString();
|
|
37
|
+
}
|
|
38
|
+
async function permissionMessage(resp) {
|
|
39
|
+
const text = await resp.text().catch(() => "");
|
|
40
|
+
try {
|
|
41
|
+
const d = safeJsonParse(text);
|
|
42
|
+
const msg = d && (d.error?.message || (typeof d.error === "string" ? d.error : void 0) || d.message);
|
|
43
|
+
if (msg && typeof msg === "string") return msg;
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
return "Permission denied for this resource (HTTP 403)";
|
|
47
|
+
}
|
|
48
|
+
function parseCapabilityResponse(text) {
|
|
49
|
+
if (!text) return void 0;
|
|
50
|
+
try {
|
|
51
|
+
return safeJsonParse(text);
|
|
52
|
+
} catch {
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function unwrapCapabilityEnvelope(body) {
|
|
57
|
+
if (body == null) {
|
|
58
|
+
throw new CapabilityGatewayError("Empty capability gateway response");
|
|
59
|
+
}
|
|
60
|
+
if (typeof body.ok === "boolean") {
|
|
61
|
+
if (body.ok) {
|
|
62
|
+
return body.data;
|
|
63
|
+
}
|
|
64
|
+
const err = body.error ?? {};
|
|
65
|
+
const message = err.message || err.code || "Capability gateway request failed";
|
|
66
|
+
throw new CapabilityGatewayError(message, err.code, err.http_status ?? err.httpStatus);
|
|
67
|
+
}
|
|
68
|
+
return body;
|
|
69
|
+
}
|
|
70
|
+
async function requestOnce(url, method, token, body) {
|
|
71
|
+
const headers = {
|
|
72
|
+
"cli-token": token,
|
|
73
|
+
"Accept": "application/json"
|
|
74
|
+
};
|
|
75
|
+
const init = { method, headers };
|
|
76
|
+
if (body !== void 0 && method !== "GET") {
|
|
77
|
+
headers["Content-Type"] = "application/json";
|
|
78
|
+
init.body = JSON.stringify(body);
|
|
79
|
+
}
|
|
80
|
+
return fetch(url, init);
|
|
81
|
+
}
|
|
82
|
+
async function requestMultipartOnce(url, token, form) {
|
|
83
|
+
return fetch(url, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: {
|
|
86
|
+
"cli-token": token,
|
|
87
|
+
"Accept": "application/json"
|
|
88
|
+
},
|
|
89
|
+
body: form
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function callGateway(host, domain, pathAfterV1, method, body) {
|
|
93
|
+
const url = buildCapabilityGatewayUrl(host, domain, pathAfterV1);
|
|
94
|
+
const token = await getCliToken(host);
|
|
95
|
+
let resp = await requestOnce(url, method, token, body);
|
|
96
|
+
if (resp.status === 403) {
|
|
97
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
98
|
+
}
|
|
99
|
+
if (resp.status === 401) {
|
|
100
|
+
logger.warn(`Capability gateway request failed (HTTP 401) for ${host}, refreshing CLI token`);
|
|
101
|
+
clearCliToken(host);
|
|
102
|
+
const newToken = await getCliToken(host);
|
|
103
|
+
process.stderr.write(`[ae-cli] CLI token refreshed for ${host}
|
|
104
|
+
`);
|
|
105
|
+
resp = await requestOnce(url, method, newToken, body);
|
|
106
|
+
if (resp.status === 403) {
|
|
107
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
108
|
+
}
|
|
109
|
+
if (!resp.ok) {
|
|
110
|
+
throw new Error(`Capability gateway HTTP error: ${resp.status} ${resp.statusText}`);
|
|
111
|
+
}
|
|
112
|
+
} else if (!resp.ok) {
|
|
113
|
+
throw new Error(`Capability gateway HTTP error: ${resp.status} ${resp.statusText}`);
|
|
114
|
+
}
|
|
115
|
+
return unwrapCapabilityEnvelope(parseCapabilityResponse(await resp.text()));
|
|
116
|
+
}
|
|
117
|
+
async function executeCapability(host, domain, capabilityId, input = {}) {
|
|
118
|
+
return callGateway(host, domain, `capabilities/${capabilityId}/execute`, "POST", { input });
|
|
119
|
+
}
|
|
120
|
+
async function uploadInputFile(host, domain, projectId, purpose, filePath) {
|
|
121
|
+
const fileBytes = await readFile(filePath);
|
|
122
|
+
return uploadInputFileBytes(host, domain, projectId, purpose, fileBytes, basename(filePath));
|
|
123
|
+
}
|
|
124
|
+
async function uploadInputFileBytes(host, domain, projectId, purpose, bytes, filename, contentType = "application/octet-stream") {
|
|
125
|
+
const url = buildCapabilityGatewayUrl(host, domain, "input-files");
|
|
126
|
+
const fileBuffer = bytes instanceof ArrayBuffer ? bytes : bytes.buffer.slice(
|
|
127
|
+
bytes.byteOffset,
|
|
128
|
+
bytes.byteOffset + bytes.byteLength
|
|
129
|
+
);
|
|
130
|
+
const form = new FormData();
|
|
131
|
+
form.append("project_id", String(projectId));
|
|
132
|
+
form.append("purpose", purpose);
|
|
133
|
+
form.append("file", new Blob([fileBuffer], { type: contentType }), filename);
|
|
134
|
+
const token = await getCliToken(host);
|
|
135
|
+
let resp = await requestMultipartOnce(url, token, form);
|
|
136
|
+
if (resp.status === 403) {
|
|
137
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
138
|
+
}
|
|
139
|
+
if (resp.status === 401) {
|
|
140
|
+
logger.warn(`Capability gateway request failed (HTTP 401) for ${host}, refreshing CLI token`);
|
|
141
|
+
clearCliToken(host);
|
|
142
|
+
const newToken = await getCliToken(host);
|
|
143
|
+
process.stderr.write(`[ae-cli] CLI token refreshed for ${host}
|
|
144
|
+
`);
|
|
145
|
+
resp = await requestMultipartOnce(url, newToken, form);
|
|
146
|
+
if (resp.status === 403) {
|
|
147
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
148
|
+
}
|
|
149
|
+
if (!resp.ok) {
|
|
150
|
+
throw new Error(`Capability gateway HTTP error: ${resp.status} ${resp.statusText}`);
|
|
151
|
+
}
|
|
152
|
+
} else if (!resp.ok) {
|
|
153
|
+
throw new Error(`Capability gateway HTTP error: ${resp.status} ${resp.statusText}`);
|
|
154
|
+
}
|
|
155
|
+
return unwrapCapabilityEnvelope(parseCapabilityResponse(await resp.text()));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
buildCapabilityGatewayUrl,
|
|
160
|
+
executeCapability,
|
|
161
|
+
uploadInputFile,
|
|
162
|
+
uploadInputFileBytes
|
|
163
|
+
};
|