@thinkingai/ae-cli 6.0.20 → 6.0.24
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 +1 -4
- package/README.zh.md +1 -4
- package/dist/{auth-GHBMJ5ZR.js → auth-A2XXG5K4.js} +34 -110
- package/dist/auth-IDPKDFSY.js +13 -0
- package/dist/chunk-2OW2RENH.js +193 -0
- package/dist/{chunk-I5CRVM2S.js → chunk-4FQ36OGO.js} +44 -17
- package/dist/{chunk-6W4QOZAL.js → chunk-65DKFJZB.js} +26 -16
- package/dist/chunk-AKORWVHJ.js +59 -0
- package/dist/{chunk-BJX3GXWC.js → chunk-F3ZDMC2W.js} +8 -8
- package/dist/chunk-FIT4CFIN.js +59 -0
- package/dist/{chunk-5OC7CYCG.js → chunk-IDXW6MEJ.js} +14 -14
- package/dist/{chunk-DMMEPCST.js → chunk-NGJDCOYA.js} +25 -115
- package/dist/chunk-NXJP4CES.js +209 -0
- package/dist/chunk-OCQPQYHZ.js +105 -0
- package/dist/{chunk-2DUEAXV3.js → chunk-ONOA6DYB.js} +1 -1
- package/dist/{chunk-RSHMZ3LG.js → chunk-PFJFZVCK.js} +13 -134
- package/dist/chunk-V5R5UIRM.js +195 -0
- package/dist/{chunk-PN3OS34E.js → chunk-WXBCP6SD.js} +1 -1
- package/dist/cli-token-OZXHC3U2.js +14 -0
- package/dist/{client-2UJ63MVQ.js → client-7L735LVY.js} +3 -3
- package/dist/{config-NCUGK6NS.js → config-SXD2JKSL.js} +3 -3
- package/dist/index.js +312 -197
- package/dist/metadata-QWUAX625.js +411 -0
- package/dist/metadata-XWTEGEN2.js +411 -0
- package/dist/{model-SJSOZTRS.js → model-3OVX42DA.js} +2 -2
- package/dist/{raw-7NVWSVJP.js → raw-IANB4AV5.js} +4 -4
- package/dist/{sync-GRVO4K3U.js → sync-4HQ3CXSK.js} +3 -3
- package/dist/{te-agent-CYZUC4US.js → te-agent-OYNNTJDU.js} +2 -2
- package/dist/{te-analysis-HJ22TUAA.js → te-analysis-CRPFK3LX.js} +1114 -358
- package/dist/te-analysis-JX3V76OI.js +2281 -0
- package/dist/{te-audience-MYDE5WEH.js → te-audience-77FGNG5E.js} +27 -18
- package/dist/te-audience-RO2IZOUC.js +599 -0
- package/dist/{te-common-WNCZB7R7.js → te-common-4TRJPRC5.js} +5 -4
- package/dist/te-common-PUXBUPOL.js +130 -0
- package/dist/{te-community-JEEFXPB3.js → te-community-NPDZQKMY.js} +5 -4
- package/dist/te-community-XKE526DS.js +687 -0
- package/dist/te-dataops-6KWLFNV4.js +1841 -0
- package/dist/{te-dataops-ZTS7XMXM.js → te-dataops-PW74WP76.js} +5 -5
- package/dist/{te-engage-4XHCTS6I.js → te-engage-HTLMUN7G.js} +5 -4
- package/dist/te-engage-YPQIVF5H.js +1510 -0
- package/dist/{te-kb-OWM3RQRH.js → te-kb-DOGDQIU4.js} +4 -5
- package/dist/{te-meta-JVO4QJBH.js → te-meta-5ESSQ5B3.js} +26 -19
- package/dist/te-meta-Z47X4VT3.js +595 -0
- package/dist/{te-team-YY24VORI.js → te-team-SOVKZIDD.js} +5 -6
- package/package.json +3 -2
- package/skills/ae-analysis/SKILL.md +60 -27
- package/skills/ae-analysis/references/analysis_gateway_assets.md +114 -0
- package/skills/ae-analysis/references/bi_panel_copy.md +15 -0
- package/skills/ae-analysis/references/bi_panel_create.md +15 -0
- package/skills/ae-analysis/references/bi_panel_delete.md +15 -0
- package/skills/ae-analysis/references/bi_panel_get.md +18 -0
- package/skills/ae-analysis/references/bi_panel_list.md +15 -0
- package/skills/ae-analysis/references/bi_panel_page_data_export.md +15 -0
- package/skills/ae-analysis/references/bi_panel_page_data_run.md +15 -0
- package/skills/ae-analysis/references/bi_panel_share.md +15 -0
- package/skills/ae-analysis/references/bi_panel_update.md +15 -0
- package/skills/ae-analysis/references/build_attribution_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_cluster_definition.md +2 -0
- package/skills/ae-analysis/references/build_distribution_analysis_qp.md +2 -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 +2 -0
- package/skills/ae-analysis/references/build_interval_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_path_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_prop_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_rank_list_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_retention_analysis_qp.md +2 -0
- package/skills/ae-analysis/references/build_tag_definition.md +2 -0
- package/skills/ae-analysis/references/dashboard_abnormal_get.md +15 -0
- package/skills/ae-analysis/references/dashboard_copy.md +15 -0
- package/skills/ae-analysis/references/dashboard_create.md +15 -0
- package/skills/ae-analysis/references/dashboard_daily_report_send.md +15 -0
- package/skills/ae-analysis/references/dashboard_daily_report_update.md +15 -0
- package/skills/ae-analysis/references/dashboard_definition_export.md +15 -0
- package/skills/ae-analysis/references/dashboard_definition_import.md +15 -0
- package/skills/ae-analysis/references/dashboard_delete.md +15 -0
- package/skills/ae-analysis/references/dashboard_freeze.md +15 -0
- package/skills/ae-analysis/references/dashboard_get.md +15 -0
- package/skills/ae-analysis/references/dashboard_handover.md +15 -0
- package/skills/ae-analysis/references/dashboard_list.md +15 -0
- package/skills/ae-analysis/references/dashboard_report_data_export.md +15 -0
- package/skills/ae-analysis/references/dashboard_report_data_run.md +15 -0
- package/skills/ae-analysis/references/dashboard_share.md +15 -0
- package/skills/ae-analysis/references/dashboard_share_info.md +15 -0
- package/skills/ae-analysis/references/dashboard_task_status.md +15 -0
- package/skills/ae-analysis/references/dashboard_update.md +16 -0
- package/skills/ae-analysis/references/favorite_add.md +15 -0
- package/skills/ae-analysis/references/favorite_remove.md +15 -0
- package/skills/ae-analysis/references/folder_create.md +15 -0
- package/skills/ae-analysis/references/folder_delete.md +15 -0
- package/skills/ae-analysis/references/folder_members.md +15 -0
- package/skills/ae-analysis/references/folder_share.md +15 -0
- package/skills/ae-analysis/references/list_clusters.md +3 -1
- package/skills/ae-analysis/references/list_events.md +5 -2
- package/skills/ae-analysis/references/list_metrics.md +4 -2
- package/skills/ae-analysis/references/list_properties.md +4 -2
- package/skills/ae-analysis/references/list_tags.md +3 -1
- package/skills/ae-analysis/references/project_space_create.md +15 -0
- package/skills/ae-analysis/references/project_space_delete.md +15 -0
- package/skills/ae-analysis/references/project_space_get.md +18 -0
- package/skills/ae-analysis/references/project_space_list.md +15 -0
- package/skills/ae-analysis/references/project_space_members.md +15 -0
- package/skills/ae-analysis/references/project_space_share.md +15 -0
- package/skills/ae-analysis/references/public_link_create.md +15 -0
- package/skills/ae-analysis/references/public_link_delete.md +15 -0
- package/skills/ae-analysis/references/public_link_list.md +15 -0
- package/skills/ae-analysis/references/public_link_offline.md +15 -0
- package/skills/ae-analysis/references/public_link_update.md +15 -0
- package/skills/ae-analysis/references/query_cancel.md +15 -0
- 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 +31 -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 +32 -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 +32 -0
- package/skills/ae-metadata/references/metadata_property_get.md +54 -0
- package/dist/auth-DYC2BGLM.js +0 -21
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
|
|
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
|
|
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
printError,
|
|
3
3
|
printOutput
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ONOA6DYB.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-OCQPQYHZ.js";
|
|
12
9
|
import {
|
|
13
10
|
clear,
|
|
14
|
-
clearToken,
|
|
15
|
-
getAuthStatus,
|
|
16
11
|
load,
|
|
17
12
|
resolveHost,
|
|
18
|
-
save
|
|
19
|
-
|
|
20
|
-
validateToken
|
|
21
|
-
} from "./chunk-RSHMZ3LG.js";
|
|
13
|
+
save
|
|
14
|
+
} from "./chunk-PFJFZVCK.js";
|
|
22
15
|
import {
|
|
16
|
+
getFallbackCliToken,
|
|
23
17
|
loadConfig,
|
|
24
18
|
logger,
|
|
25
19
|
removeHost,
|
|
26
20
|
saveConfig
|
|
27
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-65DKFJZB.js";
|
|
28
22
|
|
|
29
23
|
// src/core/device-auth.ts
|
|
30
24
|
import { execFileSync } from "child_process";
|
|
@@ -246,7 +240,7 @@ function activateHostAfterLogin(host, explicitHostOverride) {
|
|
|
246
240
|
saveConfig(config);
|
|
247
241
|
logger.info(`Active host set to ${host} after login`);
|
|
248
242
|
}
|
|
249
|
-
function persistDeviceTokens(host, tokens) {
|
|
243
|
+
async function persistDeviceTokens(host, tokens) {
|
|
250
244
|
const DEFAULT_EXPIRES_IN = 72e3;
|
|
251
245
|
const MAX_EXPIRES_IN = 86400 * 365;
|
|
252
246
|
let expiresInSeconds = tokens.expires_in ?? DEFAULT_EXPIRES_IN;
|
|
@@ -258,16 +252,15 @@ function persistDeviceTokens(host, tokens) {
|
|
|
258
252
|
save(host, {
|
|
259
253
|
accessToken: tokens.access_token,
|
|
260
254
|
refreshToken: tokens.refresh_token ?? "",
|
|
261
|
-
accessExpiresAt: expiresAt
|
|
262
|
-
mcpToken: tokens.mcp_token ?? void 0
|
|
255
|
+
accessExpiresAt: expiresAt
|
|
263
256
|
});
|
|
257
|
+
await mintCliToken(host);
|
|
264
258
|
}
|
|
265
259
|
function loginSummary(host, tokens) {
|
|
266
260
|
return {
|
|
267
261
|
authenticated: true,
|
|
268
262
|
host,
|
|
269
|
-
token: tokens.access_token.slice(0, 8) + "..."
|
|
270
|
-
mcpToken: tokens.mcp_token ? tokens.mcp_token.slice(0, 8) + "..." : null
|
|
263
|
+
token: tokens.access_token.slice(0, 8) + "..."
|
|
271
264
|
};
|
|
272
265
|
}
|
|
273
266
|
function resolveLoginTeClaudeBase(host) {
|
|
@@ -303,7 +296,7 @@ function registerAuth(program) {
|
|
|
303
296
|
try {
|
|
304
297
|
if (opts.deviceCode) {
|
|
305
298
|
const tokens2 = await pollDeviceFlow(teClaudeBase, opts.deviceCode, {}, emit);
|
|
306
|
-
persistDeviceTokens(host, tokens2);
|
|
299
|
+
await persistDeviceTokens(host, tokens2);
|
|
307
300
|
activateHostAfterLogin(host, explicitHost);
|
|
308
301
|
logger.info(`Device flow login successful for ${host} (resumed)`);
|
|
309
302
|
emit("Login successful! Token saved securely.");
|
|
@@ -326,7 +319,7 @@ function registerAuth(program) {
|
|
|
326
319
|
return;
|
|
327
320
|
}
|
|
328
321
|
const tokens = await runDeviceFlow(teClaudeBase, { noBrowser }, emit);
|
|
329
|
-
persistDeviceTokens(host, tokens);
|
|
322
|
+
await persistDeviceTokens(host, tokens);
|
|
330
323
|
activateHostAfterLogin(host, explicitHost);
|
|
331
324
|
logger.info(`Device flow login successful for ${host}`);
|
|
332
325
|
emit("Login successful! Token saved securely.");
|
|
@@ -336,7 +329,7 @@ function registerAuth(program) {
|
|
|
336
329
|
printError(
|
|
337
330
|
"auth",
|
|
338
331
|
err.message,
|
|
339
|
-
"
|
|
332
|
+
"Upgrade the AE server to a version that supports device login."
|
|
340
333
|
);
|
|
341
334
|
process.exit(1);
|
|
342
335
|
}
|
|
@@ -344,39 +337,6 @@ function registerAuth(program) {
|
|
|
344
337
|
process.exit(1);
|
|
345
338
|
}
|
|
346
339
|
});
|
|
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
340
|
auth.command("status").description("Show authentication status for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
|
|
381
341
|
const host = resolveAuthHost(program, opts);
|
|
382
342
|
if (!host) {
|
|
@@ -394,74 +354,38 @@ function registerAuth(program) {
|
|
|
394
354
|
accessExpiresAt: secureEntry.accessExpiresAt,
|
|
395
355
|
accessExpiresAtNote: "advisory: access token auto-slides on use server-side; re-login only if a command returns an auth error",
|
|
396
356
|
pastStaticExpiry,
|
|
397
|
-
|
|
357
|
+
hasCliToken: !!secureEntry.cliToken
|
|
358
|
+
},
|
|
359
|
+
program.opts().format || "json"
|
|
360
|
+
);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const fallbackCliToken = getFallbackCliToken(host);
|
|
364
|
+
if (fallbackCliToken) {
|
|
365
|
+
printOutput(
|
|
366
|
+
{
|
|
367
|
+
authenticated: true,
|
|
368
|
+
host,
|
|
369
|
+
source: "sandbox-cli-token",
|
|
370
|
+
hasCliToken: true,
|
|
371
|
+
note: "sandbox-provisioned cli-token.json; no user access token in secure-store"
|
|
398
372
|
},
|
|
399
373
|
program.opts().format || "json"
|
|
400
374
|
);
|
|
401
375
|
return;
|
|
402
376
|
}
|
|
403
|
-
|
|
404
|
-
const authenticated = tokenStatus.authenticated;
|
|
405
|
-
printOutput({ authenticated, host, source: tokenStatus.source ?? "none" }, program.opts().format || "json");
|
|
377
|
+
printOutput({ authenticated: false, host, source: "none" }, program.opts().format || "json");
|
|
406
378
|
});
|
|
407
|
-
auth.command("logout").description("Clear stored token for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action((opts) => {
|
|
379
|
+
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
380
|
const host = resolveAuthHost(program, opts);
|
|
409
381
|
if (!host) {
|
|
410
382
|
printError("config", "No AE host configured.", "Run: ae-cli config set-host <url>");
|
|
411
383
|
process.exit(1);
|
|
412
384
|
}
|
|
413
|
-
|
|
385
|
+
clearCliToken(host);
|
|
414
386
|
clear(host);
|
|
415
387
|
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}
|
|
388
|
+
process.stderr.write(`[ae-cli] Credentials and config cleared for ${host}
|
|
465
389
|
`);
|
|
466
390
|
printOutput({ cleared: true, host }, program.opts().format || "json");
|
|
467
391
|
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PermissionError
|
|
3
|
+
} from "./chunk-NOO24N7W.js";
|
|
4
|
+
import {
|
|
5
|
+
clearCliToken,
|
|
6
|
+
getCliToken
|
|
7
|
+
} from "./chunk-OCQPQYHZ.js";
|
|
8
|
+
import {
|
|
9
|
+
logger,
|
|
10
|
+
safeJsonParse
|
|
11
|
+
} from "./chunk-65DKFJZB.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, hint) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.httpStatus = httpStatus;
|
|
21
|
+
this.hint = hint;
|
|
22
|
+
this.name = "CapabilityGatewayError";
|
|
23
|
+
}
|
|
24
|
+
code;
|
|
25
|
+
httpStatus;
|
|
26
|
+
hint;
|
|
27
|
+
};
|
|
28
|
+
function buildCapabilityGatewayUrl(host, domain, pathAfterV1, queryParams = {}) {
|
|
29
|
+
const base = host.replace(/\/+$/, "");
|
|
30
|
+
const cleanDomain = domain.replace(/^\/+|\/+$/g, "");
|
|
31
|
+
const cleanPath = pathAfterV1.replace(/^\/+|\/+$/g, "");
|
|
32
|
+
const gatewayPrefix = cleanDomain === "" ? "/api/cli/v1" : `/api/cli/${cleanDomain}/v1`;
|
|
33
|
+
const url = new URL(`${base}${gatewayPrefix}/${cleanPath}`);
|
|
34
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
35
|
+
if (value !== void 0 && value !== null) {
|
|
36
|
+
url.searchParams.set(key, String(value));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return url.toString();
|
|
40
|
+
}
|
|
41
|
+
async function permissionMessage(resp) {
|
|
42
|
+
const text = await resp.text().catch(() => "");
|
|
43
|
+
try {
|
|
44
|
+
const d = safeJsonParse(text);
|
|
45
|
+
const msg = d && (d.error?.message || (typeof d.error === "string" ? d.error : void 0) || d.message);
|
|
46
|
+
if (msg && typeof msg === "string") return msg;
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
return "Permission denied for this resource (HTTP 403)";
|
|
50
|
+
}
|
|
51
|
+
function parseCapabilityResponse(text) {
|
|
52
|
+
if (!text) return void 0;
|
|
53
|
+
try {
|
|
54
|
+
return safeJsonParse(text);
|
|
55
|
+
} catch {
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function unwrapCapabilityEnvelope(body) {
|
|
60
|
+
if (body == null) {
|
|
61
|
+
throw new CapabilityGatewayError("Empty capability gateway response");
|
|
62
|
+
}
|
|
63
|
+
if (typeof body.ok === "boolean") {
|
|
64
|
+
if (body.ok) {
|
|
65
|
+
return body.data;
|
|
66
|
+
}
|
|
67
|
+
const err = body.error ?? {};
|
|
68
|
+
const code = nonEmptyString(err.code);
|
|
69
|
+
const message = nonEmptyString(err.message) ?? code ?? "Capability gateway request failed";
|
|
70
|
+
const hint = nonEmptyString(err.hint);
|
|
71
|
+
throw new CapabilityGatewayError(message, code, err.http_status ?? err.httpStatus, hint);
|
|
72
|
+
}
|
|
73
|
+
return body;
|
|
74
|
+
}
|
|
75
|
+
function nonEmptyString(value) {
|
|
76
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
77
|
+
}
|
|
78
|
+
function buildCapabilityHttpError(resp, body) {
|
|
79
|
+
const fallback = `Capability gateway HTTP error: ${resp.status} ${resp.statusText}`.trim();
|
|
80
|
+
if (body && typeof body === "object") {
|
|
81
|
+
const err = body.error ?? body.data?.error ?? body;
|
|
82
|
+
const code = nonEmptyString(err.code) ?? nonEmptyString(err.errorCode) ?? nonEmptyString(body.code);
|
|
83
|
+
const message = nonEmptyString(err.message) ?? nonEmptyString(body.message);
|
|
84
|
+
const hint = nonEmptyString(err.hint) ?? nonEmptyString(body.hint);
|
|
85
|
+
const details = [code, message, hint ? `Hint: ${hint}` : void 0].filter(Boolean);
|
|
86
|
+
if (details.length > 0) {
|
|
87
|
+
return new CapabilityGatewayError(message ?? fallback, code, resp.status, hint);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (typeof body === "string" && body.trim()) {
|
|
91
|
+
return new CapabilityGatewayError(`${fallback}: ${body.slice(0, 500)}`, void 0, resp.status);
|
|
92
|
+
}
|
|
93
|
+
return new CapabilityGatewayError(fallback, void 0, resp.status);
|
|
94
|
+
}
|
|
95
|
+
async function throwCapabilityHttpError(resp) {
|
|
96
|
+
const body = parseCapabilityResponse(await resp.text());
|
|
97
|
+
throw buildCapabilityHttpError(resp, body);
|
|
98
|
+
}
|
|
99
|
+
async function requestOnce(url, method, token, body) {
|
|
100
|
+
const headers = {
|
|
101
|
+
"cli-token": token,
|
|
102
|
+
"Accept": "application/json"
|
|
103
|
+
};
|
|
104
|
+
const init = { method, headers };
|
|
105
|
+
if (body !== void 0 && method !== "GET") {
|
|
106
|
+
headers["Content-Type"] = "application/json";
|
|
107
|
+
init.body = JSON.stringify(body);
|
|
108
|
+
}
|
|
109
|
+
return fetch(url, init);
|
|
110
|
+
}
|
|
111
|
+
async function requestMultipartOnce(url, token, form) {
|
|
112
|
+
return fetch(url, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: {
|
|
115
|
+
"cli-token": token,
|
|
116
|
+
"Accept": "application/json"
|
|
117
|
+
},
|
|
118
|
+
body: form
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async function callGateway(host, domain, pathAfterV1, method, body) {
|
|
122
|
+
const url = buildCapabilityGatewayUrl(host, domain, pathAfterV1);
|
|
123
|
+
const token = await getCliToken(host);
|
|
124
|
+
let resp = await requestOnce(url, method, token, body);
|
|
125
|
+
if (resp.status === 403) {
|
|
126
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
127
|
+
}
|
|
128
|
+
if (resp.status === 401) {
|
|
129
|
+
logger.warn(`Capability gateway request failed (HTTP 401) for ${host}, refreshing CLI token`);
|
|
130
|
+
clearCliToken(host);
|
|
131
|
+
const newToken = await getCliToken(host);
|
|
132
|
+
process.stderr.write(`[ae-cli] CLI token refreshed for ${host}
|
|
133
|
+
`);
|
|
134
|
+
resp = await requestOnce(url, method, newToken, body);
|
|
135
|
+
if (resp.status === 403) {
|
|
136
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
137
|
+
}
|
|
138
|
+
if (!resp.ok) {
|
|
139
|
+
await throwCapabilityHttpError(resp);
|
|
140
|
+
}
|
|
141
|
+
} else if (!resp.ok) {
|
|
142
|
+
await throwCapabilityHttpError(resp);
|
|
143
|
+
}
|
|
144
|
+
return unwrapCapabilityEnvelope(parseCapabilityResponse(await resp.text()));
|
|
145
|
+
}
|
|
146
|
+
async function executeCapability(host, domain, capabilityId, input = {}) {
|
|
147
|
+
return callGateway(host, domain, `capabilities/${capabilityId}/execute`, "POST", { input });
|
|
148
|
+
}
|
|
149
|
+
async function uploadInputFile(host, domain, projectId, purpose, filePath) {
|
|
150
|
+
const fileBytes = await readFile(filePath);
|
|
151
|
+
return uploadInputFileBytes(host, domain, projectId, purpose, fileBytes, basename(filePath));
|
|
152
|
+
}
|
|
153
|
+
async function uploadInputFileBytes(host, domain, projectId, purpose, bytes, filename, contentType = "application/octet-stream") {
|
|
154
|
+
const url = buildCapabilityGatewayUrl(host, domain, "input-files");
|
|
155
|
+
const fileBuffer = bytes instanceof ArrayBuffer ? bytes : bytes.buffer.slice(
|
|
156
|
+
bytes.byteOffset,
|
|
157
|
+
bytes.byteOffset + bytes.byteLength
|
|
158
|
+
);
|
|
159
|
+
const form = new FormData();
|
|
160
|
+
form.append("project_id", String(projectId));
|
|
161
|
+
form.append("purpose", purpose);
|
|
162
|
+
form.append("file", new Blob([fileBuffer], { type: contentType }), filename);
|
|
163
|
+
const token = await getCliToken(host);
|
|
164
|
+
let resp = await requestMultipartOnce(url, token, form);
|
|
165
|
+
if (resp.status === 403) {
|
|
166
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
167
|
+
}
|
|
168
|
+
if (resp.status === 401) {
|
|
169
|
+
logger.warn(`Capability gateway request failed (HTTP 401) for ${host}, refreshing CLI token`);
|
|
170
|
+
clearCliToken(host);
|
|
171
|
+
const newToken = await getCliToken(host);
|
|
172
|
+
process.stderr.write(`[ae-cli] CLI token refreshed for ${host}
|
|
173
|
+
`);
|
|
174
|
+
resp = await requestMultipartOnce(url, newToken, form);
|
|
175
|
+
if (resp.status === 403) {
|
|
176
|
+
throw new PermissionError(await permissionMessage(resp));
|
|
177
|
+
}
|
|
178
|
+
if (!resp.ok) {
|
|
179
|
+
await throwCapabilityHttpError(resp);
|
|
180
|
+
}
|
|
181
|
+
} else if (!resp.ok) {
|
|
182
|
+
await throwCapabilityHttpError(resp);
|
|
183
|
+
}
|
|
184
|
+
return unwrapCapabilityEnvelope(parseCapabilityResponse(await resp.text()));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
CapabilityGatewayError,
|
|
189
|
+
buildCapabilityGatewayUrl,
|
|
190
|
+
executeCapability,
|
|
191
|
+
uploadInputFile,
|
|
192
|
+
uploadInputFileBytes
|
|
193
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getActiveHost,
|
|
3
3
|
getSandboxRuntimeRoot
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-65DKFJZB.js";
|
|
5
5
|
|
|
6
6
|
// src/core/te-agent-credentials.ts
|
|
7
7
|
import { readFileSync } from "fs";
|
|
@@ -134,39 +134,66 @@ function teClaudeBaseFromActiveHost() {
|
|
|
134
134
|
async function signRequest(method, path, rawBody) {
|
|
135
135
|
const sandboxCred = tryLoadTeAgentSandboxCredentials();
|
|
136
136
|
if (sandboxCred && sandboxCred.sandboxId && sandboxCred.sandboxSecretKey) {
|
|
137
|
-
const
|
|
137
|
+
const headers = {
|
|
138
138
|
"X-Sandbox-Id": sandboxCred.sandboxId,
|
|
139
139
|
"X-Sandbox-Secret-Key": sandboxCred.sandboxSecretKey
|
|
140
140
|
};
|
|
141
141
|
if (method === "POST" || method === "PATCH") {
|
|
142
|
-
|
|
142
|
+
headers["Content-Type"] = "application/json";
|
|
143
143
|
}
|
|
144
144
|
return {
|
|
145
145
|
url: `${sandboxCred.url.replace(/\/$/, "")}${path}`,
|
|
146
|
-
headers
|
|
146
|
+
headers,
|
|
147
147
|
rawBody
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
-
const { getToken } = await import("./auth-
|
|
150
|
+
const { getToken } = await import("./auth-IDPKDFSY.js");
|
|
151
|
+
const { getCliToken } = await import("./cli-token-OZXHC3U2.js");
|
|
151
152
|
const baseUrl = sandboxCred?.url || teClaudeBaseFromActiveHost();
|
|
153
|
+
const hostForToken = getActiveHost() || baseUrl;
|
|
152
154
|
if (!baseUrl) {
|
|
153
155
|
throw new TeAgentCredentialsError(
|
|
154
156
|
"Cannot determine the te-claude service URL",
|
|
155
157
|
"Run ae-cli config set-host <url> to configure the service URL, or execute inside a te-agent sandbox"
|
|
156
158
|
);
|
|
157
159
|
}
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
const contentTypeHeader = method === "POST" || method === "PATCH" ? { "Content-Type": "application/json" } : {};
|
|
161
|
+
let accessToken = null;
|
|
162
|
+
try {
|
|
163
|
+
accessToken = await getToken(hostForToken);
|
|
164
|
+
} catch {
|
|
165
|
+
accessToken = null;
|
|
164
166
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
if (accessToken) {
|
|
168
|
+
return {
|
|
169
|
+
url: `${baseUrl.replace(/\/$/, "")}${path}`,
|
|
170
|
+
headers: {
|
|
171
|
+
"Authorization": `bearer ${accessToken}`,
|
|
172
|
+
...contentTypeHeader
|
|
173
|
+
},
|
|
174
|
+
rawBody
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
let cliToken = null;
|
|
178
|
+
try {
|
|
179
|
+
cliToken = await getCliToken(hostForToken);
|
|
180
|
+
} catch {
|
|
181
|
+
cliToken = null;
|
|
182
|
+
}
|
|
183
|
+
if (cliToken) {
|
|
184
|
+
return {
|
|
185
|
+
url: `${baseUrl.replace(/\/$/, "")}${path}`,
|
|
186
|
+
headers: {
|
|
187
|
+
"cli-token": cliToken,
|
|
188
|
+
...contentTypeHeader
|
|
189
|
+
},
|
|
190
|
+
rawBody
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
throw new TeAgentCredentialsError(
|
|
194
|
+
"No te-claude credentials available",
|
|
195
|
+
"Run ae-cli auth login, or execute inside a te-agent sandbox"
|
|
196
|
+
);
|
|
170
197
|
}
|
|
171
198
|
async function parseResponse(response, defaultErrorPrefix) {
|
|
172
199
|
const text = await response.text();
|
|
@@ -266,7 +293,7 @@ async function uploadToMainApp(path, formData) {
|
|
|
266
293
|
"X-Sandbox-Secret-Key": sandboxCred.sandboxSecretKey
|
|
267
294
|
};
|
|
268
295
|
} else {
|
|
269
|
-
const { getToken } = await import("./auth-
|
|
296
|
+
const { getToken } = await import("./auth-IDPKDFSY.js");
|
|
270
297
|
baseUrl = (sandboxCred?.url || teClaudeBaseFromActiveHost() || "").replace(/\/$/, "");
|
|
271
298
|
if (!baseUrl) {
|
|
272
299
|
throw new TeAgentCredentialsError(
|
|
@@ -108,8 +108,8 @@ function getSandboxRuntimeRoot() {
|
|
|
108
108
|
function getSandboxAeConfigDir() {
|
|
109
109
|
return join(getSandboxRuntimeRoot(), ".ae-config");
|
|
110
110
|
}
|
|
111
|
-
function
|
|
112
|
-
return join(getSandboxAeConfigDir(), "
|
|
111
|
+
function getSandboxCliTokenFilePath() {
|
|
112
|
+
return join(getSandboxAeConfigDir(), "cli-token.json");
|
|
113
113
|
}
|
|
114
114
|
function getSandboxClusterInfoFilePath() {
|
|
115
115
|
return join(getSandboxAeConfigDir(), "cluster-info.json");
|
|
@@ -118,22 +118,22 @@ function getSandboxClusterInfoFilePath() {
|
|
|
118
118
|
// src/core/config.ts
|
|
119
119
|
var CONFIG_DIR = path2.join(process.env.HOME || "", ".ae-cli");
|
|
120
120
|
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
121
|
-
function
|
|
122
|
-
const paths = [
|
|
123
|
-
const homeFallback = path2.join(process.env.HOME || "", ".ae-config", "
|
|
121
|
+
function sandboxCliTokenCandidatePaths() {
|
|
122
|
+
const paths = [getSandboxCliTokenFilePath()];
|
|
123
|
+
const homeFallback = path2.join(process.env.HOME || "", ".ae-config", "cli-token.json");
|
|
124
124
|
if (!paths.includes(homeFallback)) {
|
|
125
125
|
paths.push(homeFallback);
|
|
126
126
|
}
|
|
127
127
|
return paths;
|
|
128
128
|
}
|
|
129
|
-
function
|
|
130
|
-
for (const file of
|
|
129
|
+
function readSandboxCliTokenEntry() {
|
|
130
|
+
for (const file of sandboxCliTokenCandidatePaths()) {
|
|
131
131
|
if (!fs3.existsSync(file)) continue;
|
|
132
132
|
try {
|
|
133
133
|
const data = safeReadJsonFile(file);
|
|
134
134
|
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
135
135
|
const url = data.url;
|
|
136
|
-
const token = data
|
|
136
|
+
const token = data.token;
|
|
137
137
|
if (url && token) {
|
|
138
138
|
return { url, token };
|
|
139
139
|
}
|
|
@@ -143,15 +143,12 @@ function readSandboxMcpTokenEntry() {
|
|
|
143
143
|
}
|
|
144
144
|
return null;
|
|
145
145
|
}
|
|
146
|
-
function ensureDir() {
|
|
147
|
-
if (!fs3.existsSync(CONFIG_DIR)) fs3.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
148
|
-
}
|
|
149
146
|
function forceMigrateFromFallback() {
|
|
150
|
-
const entry =
|
|
147
|
+
const entry = readSandboxCliTokenEntry();
|
|
151
148
|
if (!entry) return null;
|
|
152
149
|
return { [entry.url]: entry.token };
|
|
153
150
|
}
|
|
154
|
-
function
|
|
151
|
+
function getFallbackCliToken(hostUrl) {
|
|
155
152
|
const store = forceMigrateFromFallback();
|
|
156
153
|
if (!store) return null;
|
|
157
154
|
if (hostUrl && store[hostUrl]) return store[hostUrl];
|
|
@@ -159,6 +156,9 @@ function getFallbackMcpToken(hostUrl) {
|
|
|
159
156
|
if (entries.length === 1) return entries[0];
|
|
160
157
|
return null;
|
|
161
158
|
}
|
|
159
|
+
function ensureDir() {
|
|
160
|
+
if (!fs3.existsSync(CONFIG_DIR)) fs3.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
161
|
+
}
|
|
162
162
|
function loadConfig() {
|
|
163
163
|
try {
|
|
164
164
|
if (fs3.existsSync(CONFIG_FILE)) {
|
|
@@ -197,9 +197,10 @@ function saveConfig(config) {
|
|
|
197
197
|
logger.info(`Config saved: activeHost=${config.activeHost}, hosts=${Object.keys(config.hosts).length}`);
|
|
198
198
|
}
|
|
199
199
|
function getActiveHost() {
|
|
200
|
+
const sandboxHost = readSandboxCliTokenEntry()?.url;
|
|
201
|
+
if (sandboxHost) return sandboxHost;
|
|
200
202
|
const config = loadConfig();
|
|
201
|
-
|
|
202
|
-
return readSandboxMcpTokenEntry()?.url ?? "";
|
|
203
|
+
return config.activeHost || "";
|
|
203
204
|
}
|
|
204
205
|
function setActiveHost(url) {
|
|
205
206
|
const config = loadConfig();
|
|
@@ -233,6 +234,14 @@ function removeHost(url) {
|
|
|
233
234
|
}
|
|
234
235
|
saveConfig(config);
|
|
235
236
|
}
|
|
237
|
+
function listHosts() {
|
|
238
|
+
const config = loadConfig();
|
|
239
|
+
return Object.entries(config.hosts).map(([url, entry]) => ({
|
|
240
|
+
url,
|
|
241
|
+
label: entry.label,
|
|
242
|
+
active: url === config.activeHost
|
|
243
|
+
}));
|
|
244
|
+
}
|
|
236
245
|
function getConfigDir() {
|
|
237
246
|
return CONFIG_DIR;
|
|
238
247
|
}
|
|
@@ -243,12 +252,13 @@ export {
|
|
|
243
252
|
safeReadJsonFile,
|
|
244
253
|
getSandboxRuntimeRoot,
|
|
245
254
|
getSandboxClusterInfoFilePath,
|
|
246
|
-
|
|
255
|
+
getFallbackCliToken,
|
|
247
256
|
loadConfig,
|
|
248
257
|
saveConfig,
|
|
249
258
|
getActiveHost,
|
|
250
259
|
setActiveHost,
|
|
251
260
|
addHost,
|
|
252
261
|
removeHost,
|
|
262
|
+
listHosts,
|
|
253
263
|
getConfigDir
|
|
254
264
|
};
|