@thinkingai/ae-cli 1.0.24 → 1.0.28
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 +17 -2
- package/README.zh.md +18 -2
- package/dist/auth-5NSDQFQB.js +454 -0
- package/dist/{auth-4OPL4YWG.js → auth-H2376DEF.js} +2 -2
- package/dist/chunk-AD5V3ZPJ.js +217 -0
- package/dist/chunk-CAQYQA4R.js +399 -0
- package/dist/{chunk-JJCRURTR.js → chunk-CLJF7MQA.js} +1 -1
- package/dist/chunk-GSJGPNKK.js +49 -0
- package/dist/chunk-IMBKVXKY.js +478 -0
- package/dist/chunk-KAEZTSXN.js +99 -0
- package/dist/{chunk-MZW6NOVS.js → chunk-LU7SXK4Q.js} +27 -8
- package/dist/chunk-OJDNO5QY.js +63 -0
- package/dist/{chunk-DC66L5AM.js → chunk-SRJIAOBN.js} +76 -91
- package/dist/{chunk-OVHL4JAC.js → chunk-WCHI7725.js} +44 -47
- package/dist/{client-TDH6MUWM.js → client-FCMK3XEK.js} +5 -3
- package/dist/config-64G36TJL.js +130 -0
- package/dist/index.js +50 -17
- package/dist/model-EZ6K7FXI.js +134 -0
- package/dist/{raw-EM7AP3RT.js → raw-VEF3D6UD.js} +11 -6
- package/dist/sync-NRODEVNH.js +385 -0
- package/dist/te-agent-7U7JLJKU.js +524 -0
- package/dist/{te-analysis-3KFSNUCJ.js → te-analysis-A2OSGHQ4.js} +136 -20
- package/dist/{te-audience-GMYJFCSC.js → te-audience-LI67PPGO.js} +5 -4
- package/dist/{te-common-YLERCMQI.js → te-common-35WVU3C5.js} +19 -8
- package/dist/{te-community-PYDN5A6B.js → te-community-LEAP6PWT.js} +4 -3
- package/dist/{te-dataops-ETWS5O3X.js → te-dataops-N2LGZBOX.js} +4 -3
- package/dist/{te-engage-ROJVZHDA.js → te-engage-H7C72Z46.js} +105 -49
- package/dist/{te-kb-VUNS2CC7.js → te-kb-I2OKTBAI.js} +225 -29
- package/dist/{te-meta-3EFWLM3A.js → te-meta-HBTIEDRO.js} +4 -3
- package/dist/te-team-EM5OWRQL.js +529 -0
- package/package.json +10 -2
- package/skills/ae-agent/SKILL.md +134 -0
- package/skills/ae-analysis/SKILL.md +1 -1
- package/skills/ae-analysis/references/drilldown_user_events.md +1 -1
- package/skills/ae-analysis/references/drilldown_users.md +2 -2
- package/skills/ae-analysis/references/list_clusters.md +4 -2
- package/skills/ae-analysis/references/query_adhoc.md +3 -2
- package/skills/ae-analysis/references/query_entity_details.md +1 -1
- package/skills/ae-analysis-global/SKILL.md +51 -0
- package/skills/ae-analysis-global/references/list_query_clusters.md +67 -0
- package/skills/ae-community/SKILL.md +2 -3
- package/skills/ae-dataops/SKILL.md +1 -2
- package/skills/ae-engage/SKILL.md +26 -2
- package/skills/ae-engage/references/add-approver.md +0 -1
- package/skills/ae-engage/references/add-channel.md +0 -1
- package/skills/ae-engage/references/approver-list.md +0 -1
- package/skills/ae-engage/references/build-task-save-guide.md +283 -0
- package/skills/ae-engage/references/cancel-query-by-request-id.md +0 -1
- package/skills/ae-engage/references/channel-detail.md +0 -1
- package/skills/ae-engage/references/channel-list.md +0 -1
- package/skills/ae-engage/references/config-channel-detail.md +0 -1
- package/skills/ae-engage/references/config-channel-list.md +0 -1
- package/skills/ae-engage/references/config-item-analysis-report.md +0 -1
- package/skills/ae-engage/references/config-item-detail.md +0 -1
- package/skills/ae-engage/references/config-item-list.md +0 -1
- package/skills/ae-engage/references/config-item-strategy-comparison.md +0 -1
- package/skills/ae-engage/references/config-item-trigger-report.md +0 -1
- package/skills/ae-engage/references/copy-config-template.md +0 -1
- package/skills/ae-engage/references/delete-channel.md +0 -1
- package/skills/ae-engage/references/delete-config-channel.md +0 -1
- package/skills/ae-engage/references/delete-config-item.md +0 -1
- package/skills/ae-engage/references/delete-flow.md +0 -1
- package/skills/ae-engage/references/flow-ab-split-node-report.md +0 -1
- package/skills/ae-engage/references/flow-detail.md +0 -1
- package/skills/ae-engage/references/flow-list.md +0 -1
- package/skills/ae-engage/references/flow-node-config-schema.md +0 -1
- package/skills/ae-engage/references/flow-node-detail-report.md +0 -1
- package/skills/ae-engage/references/flow-node-overview-report.md +0 -1
- package/skills/ae-engage/references/flow-process-report.md +0 -1
- package/skills/ae-engage/references/manage-flow.md +0 -1
- package/skills/ae-engage/references/manage-strategy.md +0 -1
- package/skills/ae-engage/references/manage-task.md +0 -1
- package/skills/ae-engage/references/modify-flow-base-info.md +0 -1
- package/skills/ae-engage/references/save-task.md +304 -0
- package/skills/ae-engage/references/strategy-detail.md +0 -1
- package/skills/ae-engage/references/strategy-list.md +0 -1
- package/skills/ae-engage/references/task-data-detail.md +0 -1
- package/skills/ae-engage/references/task-data-overview.md +0 -1
- package/skills/ae-engage/references/task-detail.md +0 -1
- package/skills/ae-engage/references/task-experiment-report.md +0 -1
- package/skills/ae-engage/references/task-list.md +0 -1
- package/skills/ae-engage/references/task-metric-detail.md +0 -1
- package/skills/ae-engage/references/task-stats.md +0 -1
- package/skills/ae-engage/references/update-channel-status.md +0 -1
- package/skills/ae-engage/references/update-config-channel-status.md +0 -1
- package/skills/ae-engage/references/validate-flow-node-config.md +0 -1
- package/skills/ae-engage/references/whitelist-list.md +0 -1
- package/skills/ae-kb/SKILL.md +284 -0
- package/skills/ae-team/SKILL.md +164 -0
- package/skills/ae-team/references/ai-generate.md +39 -0
- package/skills/ae-team/references/create.md +94 -0
- package/skills/ae-team/references/delete.md +39 -0
- package/skills/ae-team/references/list-projects.md +45 -0
- package/skills/ae-team/references/list-templates.md +38 -0
- package/skills/ae-team/references/list.md +39 -0
- package/skills/ae-team/references/run-artifacts.md +51 -0
- package/skills/ae-team/references/run-cancel.md +38 -0
- package/skills/ae-team/references/run-chat.md +57 -0
- package/skills/ae-team/references/run-reply.md +41 -0
- package/skills/ae-team/references/run-result.md +75 -0
- package/skills/ae-team/references/run-start.md +73 -0
- package/skills/ae-team/references/run-watch.md +82 -0
- package/skills/ae-team/references/update.md +47 -0
- package/dist/auth-PBPAZQWP.js +0 -168
- package/dist/chunk-47MTN54I.js +0 -285
- package/dist/config-5ELRYAIH.js +0 -257
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getMcpToken
|
|
3
|
+
} from "./chunk-WCHI7725.js";
|
|
4
|
+
import {
|
|
5
|
+
safeJsonParse
|
|
6
|
+
} from "./chunk-SRJIAOBN.js";
|
|
7
|
+
|
|
8
|
+
// src/core/mcp-access.ts
|
|
9
|
+
function buildUrl(host, path, params = {}) {
|
|
10
|
+
const base = host.replace(/\/$/, "");
|
|
11
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
12
|
+
const url = new URL(`${base}${p}`);
|
|
13
|
+
for (const [key, value] of Object.entries(params)) {
|
|
14
|
+
if (value !== void 0 && value !== null) {
|
|
15
|
+
url.searchParams.set(key, String(value));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return url.toString();
|
|
19
|
+
}
|
|
20
|
+
function parseKbResponse(resp, text) {
|
|
21
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
22
|
+
throw new Error(`KB MCP token auth failed: HTTP ${resp.status} ${resp.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const data = safeJsonParse(text);
|
|
25
|
+
if (data.return_code === -1001) {
|
|
26
|
+
throw new Error(`KB MCP token auth failed: ${data.return_message || "unauthorized"} (code: ${data.return_code})`);
|
|
27
|
+
}
|
|
28
|
+
if (data.return_code !== 0 && data.return_code !== void 0) {
|
|
29
|
+
throw new Error(`AE API error: ${data.return_message || "unknown"} (code: ${data.return_code})`);
|
|
30
|
+
}
|
|
31
|
+
return data.data !== void 0 ? data.data : data;
|
|
32
|
+
}
|
|
33
|
+
async function fetchWithMcpToken(input, init, mcpToken) {
|
|
34
|
+
const headers = new Headers(init.headers);
|
|
35
|
+
headers.set("mcp-token", mcpToken);
|
|
36
|
+
const resp = await fetch(input, { ...init, headers });
|
|
37
|
+
return parseKbResponse(resp, await resp.text());
|
|
38
|
+
}
|
|
39
|
+
async function kbApi(ctx, method, path, params = {}, body) {
|
|
40
|
+
const host = ctx.host();
|
|
41
|
+
const mcpToken = await getMcpToken(host);
|
|
42
|
+
const upperMethod = method.toUpperCase();
|
|
43
|
+
return fetchWithMcpToken(buildUrl(host, path, params), {
|
|
44
|
+
method: upperMethod,
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json"
|
|
47
|
+
},
|
|
48
|
+
body: upperMethod === "GET" ? void 0 : JSON.stringify(body ?? {})
|
|
49
|
+
}, mcpToken);
|
|
50
|
+
}
|
|
51
|
+
async function kbUpload(ctx, path, form, params = {}) {
|
|
52
|
+
const host = ctx.host();
|
|
53
|
+
const mcpToken = await getMcpToken(host);
|
|
54
|
+
return fetchWithMcpToken(buildUrl(host, path, params), {
|
|
55
|
+
method: "POST",
|
|
56
|
+
body: form
|
|
57
|
+
}, mcpToken);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
kbApi,
|
|
62
|
+
kbUpload
|
|
63
|
+
};
|
|
@@ -30,7 +30,7 @@ var Logger = class {
|
|
|
30
30
|
return path.join(this.logDir, `${this.date}_${level}.log`);
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Write a log entry to file (not printed to the console; console output is handled by existing process.stderr.write calls)
|
|
34
34
|
*/
|
|
35
35
|
write(level, message) {
|
|
36
36
|
const ts = this.timestamp();
|
|
@@ -41,19 +41,19 @@ var Logger = class {
|
|
|
41
41
|
} catch {
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
44
|
+
/** Informational log */
|
|
45
45
|
info(message) {
|
|
46
46
|
this.write("info", message);
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
48
|
+
/** Warning log */
|
|
49
49
|
warn(message) {
|
|
50
50
|
this.write("warning", message);
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/** Error log */
|
|
53
53
|
error(message) {
|
|
54
54
|
this.write("error", message);
|
|
55
55
|
}
|
|
56
|
-
/**
|
|
56
|
+
/** Log HTTP API request details */
|
|
57
57
|
api(method, url, status, reqBody, respBody) {
|
|
58
58
|
const parts = [`API ${method} ${url} \u2192 HTTP ${status}`];
|
|
59
59
|
if (reqBody !== void 0 && reqBody !== null) {
|
|
@@ -66,7 +66,7 @@ var Logger = class {
|
|
|
66
66
|
}
|
|
67
67
|
this.info(parts.join(" | "));
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
69
|
+
/** Log command execution */
|
|
70
70
|
command(name, args) {
|
|
71
71
|
const filtered = Object.entries(args).filter(([, v]) => v !== void 0 && v !== null && v !== "").map(([k, v]) => `--${k}=${JSON.stringify(v)}`).join(" ");
|
|
72
72
|
this.info(`CMD ${name}${filtered ? " " + filtered : ""}`);
|
|
@@ -91,48 +91,76 @@ function safeReadJsonFile(filePath) {
|
|
|
91
91
|
// src/core/config.ts
|
|
92
92
|
import fs3 from "fs";
|
|
93
93
|
import path2 from "path";
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (!fs3.existsSync(FALLBACK_MCP_TOKEN_FILE) || fs3.existsSync(MCP_TOKENS_FILE)) {
|
|
103
|
-
return null;
|
|
94
|
+
|
|
95
|
+
// src/core/sandbox-runtime.ts
|
|
96
|
+
import { homedir } from "os";
|
|
97
|
+
import { join } from "path";
|
|
98
|
+
var LINUX_SANDBOX_RUNTIME_ROOT = "/home/ta/te_agent_ta";
|
|
99
|
+
function getDefaultSandboxRuntimeRoot() {
|
|
100
|
+
if (process.platform === "linux") {
|
|
101
|
+
return LINUX_SANDBOX_RUNTIME_ROOT;
|
|
104
102
|
}
|
|
105
|
-
return
|
|
103
|
+
return homedir();
|
|
106
104
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
function getSandboxRuntimeRoot() {
|
|
106
|
+
return process.env.SANDBOX_RUNTIME_ROOT || getDefaultSandboxRuntimeRoot();
|
|
107
|
+
}
|
|
108
|
+
function getSandboxAeConfigDir() {
|
|
109
|
+
return join(getSandboxRuntimeRoot(), ".ae-config");
|
|
110
|
+
}
|
|
111
|
+
function getSandboxMcpTokenFilePath() {
|
|
112
|
+
return join(getSandboxAeConfigDir(), "mcp-token.json");
|
|
113
|
+
}
|
|
114
|
+
function getSandboxClusterInfoFilePath() {
|
|
115
|
+
return join(getSandboxAeConfigDir(), "cluster-info.json");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/core/config.ts
|
|
119
|
+
var CONFIG_DIR = path2.join(process.env.HOME || "", ".ae-cli");
|
|
120
|
+
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
121
|
+
function sandboxMcpTokenCandidatePaths() {
|
|
122
|
+
const paths = [getSandboxMcpTokenFilePath()];
|
|
123
|
+
const homeFallback = path2.join(process.env.HOME || "", ".ae-config", "mcp-token.json");
|
|
124
|
+
if (!paths.includes(homeFallback)) {
|
|
125
|
+
paths.push(homeFallback);
|
|
110
126
|
}
|
|
111
|
-
return
|
|
127
|
+
return paths;
|
|
112
128
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
function readSandboxMcpTokenEntry() {
|
|
130
|
+
for (const file of sandboxMcpTokenCandidatePaths()) {
|
|
131
|
+
if (!fs3.existsSync(file)) continue;
|
|
132
|
+
try {
|
|
133
|
+
const data = safeReadJsonFile(file);
|
|
134
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
135
|
+
const url = data.url;
|
|
136
|
+
const token = data["mcp-token"];
|
|
137
|
+
if (url && token) {
|
|
138
|
+
return { url, token };
|
|
139
|
+
}
|
|
122
140
|
}
|
|
141
|
+
} catch {
|
|
123
142
|
}
|
|
124
|
-
if (Object.keys(tokenStore).length > 0) {
|
|
125
|
-
ensureDir();
|
|
126
|
-
fs3.writeFileSync(MCP_TOKENS_FILE, JSON.stringify(tokenStore, null, 2));
|
|
127
|
-
return tokenStore;
|
|
128
|
-
}
|
|
129
|
-
} catch {
|
|
130
143
|
}
|
|
131
144
|
return null;
|
|
132
145
|
}
|
|
146
|
+
function ensureDir() {
|
|
147
|
+
if (!fs3.existsSync(CONFIG_DIR)) fs3.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
function forceMigrateFromFallback() {
|
|
150
|
+
const entry = readSandboxMcpTokenEntry();
|
|
151
|
+
if (!entry) return null;
|
|
152
|
+
return { [entry.url]: entry.token };
|
|
153
|
+
}
|
|
154
|
+
function getFallbackMcpToken(hostUrl) {
|
|
155
|
+
const store = forceMigrateFromFallback();
|
|
156
|
+
if (!store) return null;
|
|
157
|
+
if (hostUrl && store[hostUrl]) return store[hostUrl];
|
|
158
|
+
const entries = Object.values(store);
|
|
159
|
+
if (entries.length === 1) return entries[0];
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
133
162
|
function loadConfig() {
|
|
134
163
|
try {
|
|
135
|
-
const migratedTokens = migrateFromFallback();
|
|
136
164
|
if (fs3.existsSync(CONFIG_FILE)) {
|
|
137
165
|
const raw = safeReadJsonFile(CONFIG_FILE);
|
|
138
166
|
if (raw.defaultHost && !raw.activeHost) {
|
|
@@ -142,23 +170,6 @@ function loadConfig() {
|
|
|
142
170
|
}
|
|
143
171
|
return raw;
|
|
144
172
|
}
|
|
145
|
-
if (migratedTokens && Object.keys(migratedTokens).length > 0) {
|
|
146
|
-
const hosts = {};
|
|
147
|
-
for (const url of Object.keys(migratedTokens)) {
|
|
148
|
-
hosts[url] = { label: url };
|
|
149
|
-
process.stderr.write(`[ae-cli] Added host: ${url}
|
|
150
|
-
`);
|
|
151
|
-
}
|
|
152
|
-
const activeHost = Object.keys(migratedTokens)[0];
|
|
153
|
-
process.stderr.write(`[ae-cli] Active host set to: ${activeHost}
|
|
154
|
-
`);
|
|
155
|
-
process.stderr.write(`[ae-cli] MCP tokens migrated from ${FALLBACK_MCP_TOKEN_FILE}
|
|
156
|
-
`);
|
|
157
|
-
logger.info(`MCP tokens migrated from fallback: activeHost=${activeHost}, hosts=${Object.keys(hosts).length}`);
|
|
158
|
-
const config = { activeHost, hosts };
|
|
159
|
-
saveConfig(config);
|
|
160
|
-
return config;
|
|
161
|
-
}
|
|
162
173
|
} catch (err) {
|
|
163
174
|
logger.error(`Error loading config: ${err.message}`);
|
|
164
175
|
console.error(`Error loading config: ${err.message}`);
|
|
@@ -187,7 +198,8 @@ function saveConfig(config) {
|
|
|
187
198
|
}
|
|
188
199
|
function getActiveHost() {
|
|
189
200
|
const config = loadConfig();
|
|
190
|
-
return config.activeHost;
|
|
201
|
+
if (config.activeHost) return config.activeHost;
|
|
202
|
+
return readSandboxMcpTokenEntry()?.url ?? "";
|
|
191
203
|
}
|
|
192
204
|
function setActiveHost(url) {
|
|
193
205
|
const config = loadConfig();
|
|
@@ -199,61 +211,34 @@ function setActiveHost(url) {
|
|
|
199
211
|
}
|
|
200
212
|
function addHost(url, label) {
|
|
201
213
|
const config = loadConfig();
|
|
214
|
+
assertUniqueHostLabel(config, label, url);
|
|
202
215
|
config.hosts[url] = { label };
|
|
203
216
|
if (!config.activeHost) {
|
|
204
217
|
config.activeHost = url;
|
|
205
218
|
}
|
|
206
219
|
saveConfig(config);
|
|
207
220
|
}
|
|
208
|
-
function
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
saveConfig(config);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function removeHost(url) {
|
|
216
|
-
const config = loadConfig();
|
|
217
|
-
delete config.hosts[url];
|
|
218
|
-
if (config.activeHost === url) {
|
|
219
|
-
const remaining = Object.keys(config.hosts);
|
|
220
|
-
config.activeHost = remaining.length > 0 ? remaining[0] : "";
|
|
221
|
+
function assertUniqueHostLabel(config, label, excludeUrl) {
|
|
222
|
+
const duplicate = Object.entries(config.hosts).find(([url, entry]) => url !== excludeUrl && entry.label === label);
|
|
223
|
+
if (duplicate) {
|
|
224
|
+
throw new Error(`Label already exists: ${label}. Rename the existing label first: ${duplicate[0]}`);
|
|
221
225
|
}
|
|
222
|
-
saveConfig(config);
|
|
223
|
-
}
|
|
224
|
-
function listHosts() {
|
|
225
|
-
const config = loadConfig();
|
|
226
|
-
return Object.entries(config.hosts).map(([url, entry]) => ({
|
|
227
|
-
url,
|
|
228
|
-
label: entry.label,
|
|
229
|
-
active: url === config.activeHost
|
|
230
|
-
}));
|
|
231
226
|
}
|
|
232
227
|
function getConfigDir() {
|
|
233
228
|
return CONFIG_DIR;
|
|
234
229
|
}
|
|
235
|
-
function extractHostname(fullUrl) {
|
|
236
|
-
try {
|
|
237
|
-
const u = new URL(fullUrl);
|
|
238
|
-
return u.host;
|
|
239
|
-
} catch {
|
|
240
|
-
return fullUrl;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
230
|
|
|
244
231
|
export {
|
|
245
232
|
logger,
|
|
246
233
|
safeJsonParse,
|
|
247
234
|
safeReadJsonFile,
|
|
248
|
-
|
|
235
|
+
getSandboxRuntimeRoot,
|
|
236
|
+
getSandboxClusterInfoFilePath,
|
|
237
|
+
getFallbackMcpToken,
|
|
249
238
|
loadConfig,
|
|
250
239
|
saveConfig,
|
|
251
240
|
getActiveHost,
|
|
252
241
|
setActiveHost,
|
|
253
242
|
addHost,
|
|
254
|
-
|
|
255
|
-
removeHost,
|
|
256
|
-
listHosts,
|
|
257
|
-
getConfigDir,
|
|
258
|
-
extractHostname
|
|
243
|
+
getConfigDir
|
|
259
244
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
getAnalysisMappingPathForClusterMode
|
|
3
|
+
} from "./chunk-GSJGPNKK.js";
|
|
4
|
+
import {
|
|
5
|
+
getToken,
|
|
6
|
+
loadMcpToken
|
|
7
|
+
} from "./chunk-CAQYQA4R.js";
|
|
4
8
|
import {
|
|
5
|
-
forceMigrateFromFallback,
|
|
6
9
|
getActiveHost,
|
|
7
|
-
|
|
10
|
+
getFallbackMcpToken,
|
|
8
11
|
logger,
|
|
9
|
-
safeJsonParse
|
|
10
|
-
|
|
11
|
-
} from "./chunk-DC66L5AM.js";
|
|
12
|
+
safeJsonParse
|
|
13
|
+
} from "./chunk-SRJIAOBN.js";
|
|
12
14
|
|
|
13
15
|
// src/core/mcp.ts
|
|
14
|
-
import fs from "fs";
|
|
15
|
-
import path from "path";
|
|
16
16
|
var MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
17
17
|
var JSONRPC_VERSION = "2.0";
|
|
18
18
|
var serviceMappingMap = /* @__PURE__ */ new Map();
|
|
@@ -37,6 +37,9 @@ function getMcpMapping(serviceName) {
|
|
|
37
37
|
if (!mapping) {
|
|
38
38
|
throw new Error(`MCP mapping not found for service: '${serviceName}'. Please register it using registerMcpMapping() first.`);
|
|
39
39
|
}
|
|
40
|
+
if (serviceName === "analysis") {
|
|
41
|
+
return { ...mapping, mappingPath: getAnalysisMappingPathForClusterMode() };
|
|
42
|
+
}
|
|
40
43
|
return mapping;
|
|
41
44
|
}
|
|
42
45
|
function buildMcpUrl(host, serviceName) {
|
|
@@ -54,22 +57,8 @@ var requestIdCounter = 1;
|
|
|
54
57
|
function genRequestId() {
|
|
55
58
|
return requestIdCounter++;
|
|
56
59
|
}
|
|
57
|
-
var MCP_TOKEN_FILE = path.join(getConfigDir(), "mcp-tokens.json");
|
|
58
60
|
var MCP_TOKEN_GENERATE_PATH = "/v1/ta/mcp/token/generate";
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
if (fs.existsSync(MCP_TOKEN_FILE)) {
|
|
62
|
-
return safeReadJsonFile(MCP_TOKEN_FILE);
|
|
63
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
}
|
|
66
|
-
return {};
|
|
67
|
-
}
|
|
68
|
-
function saveMcpTokenStore(store) {
|
|
69
|
-
const dir = getConfigDir();
|
|
70
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
71
|
-
fs.writeFileSync(MCP_TOKEN_FILE, JSON.stringify(store, null, 2));
|
|
72
|
-
}
|
|
61
|
+
var _mcpTokenCache = /* @__PURE__ */ new Map();
|
|
73
62
|
async function generateMcpToken(hostUrl) {
|
|
74
63
|
const teToken = await getToken(hostUrl);
|
|
75
64
|
const base = hostUrl.replace(/\/+$/, "");
|
|
@@ -95,33 +84,38 @@ async function generateMcpToken(hostUrl) {
|
|
|
95
84
|
}
|
|
96
85
|
async function getMcpToken(hostOverride) {
|
|
97
86
|
const hostUrl = hostOverride || getActiveHost();
|
|
98
|
-
const
|
|
99
|
-
if (
|
|
100
|
-
return
|
|
87
|
+
const cached = _mcpTokenCache.get(hostUrl);
|
|
88
|
+
if (cached) {
|
|
89
|
+
return cached;
|
|
90
|
+
}
|
|
91
|
+
const storedToken = loadMcpToken(hostUrl);
|
|
92
|
+
if (storedToken) {
|
|
93
|
+
_mcpTokenCache.set(hostUrl, storedToken);
|
|
94
|
+
logger.info(`Using persisted MCP token (secure-store) for ${hostUrl}`);
|
|
95
|
+
return storedToken;
|
|
96
|
+
}
|
|
97
|
+
const fallbackToken = getFallbackMcpToken(hostUrl);
|
|
98
|
+
if (fallbackToken) {
|
|
99
|
+
_mcpTokenCache.set(hostUrl, fallbackToken);
|
|
100
|
+
logger.info(`Using sandbox-provisioned MCP token (fallback file) for ${hostUrl}`);
|
|
101
|
+
return fallbackToken;
|
|
101
102
|
}
|
|
102
103
|
logger.info(`Generating MCP token for ${hostUrl}`);
|
|
103
104
|
const mcpToken = await generateMcpToken(hostUrl);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
logger.info(`MCP token generated and cached for ${hostUrl}`);
|
|
105
|
+
_mcpTokenCache.set(hostUrl, mcpToken);
|
|
106
|
+
logger.info(`MCP token generated and in-process cached for ${hostUrl}`);
|
|
107
107
|
return mcpToken;
|
|
108
108
|
}
|
|
109
109
|
function clearMcpToken(hostUrl) {
|
|
110
|
-
const store = loadMcpTokenStore();
|
|
111
110
|
if (hostUrl) {
|
|
112
|
-
delete
|
|
111
|
+
_mcpTokenCache.delete(hostUrl);
|
|
113
112
|
} else {
|
|
114
|
-
|
|
115
|
-
delete store[key];
|
|
116
|
-
}
|
|
113
|
+
_mcpTokenCache.clear();
|
|
117
114
|
}
|
|
118
|
-
saveMcpTokenStore(store);
|
|
119
115
|
}
|
|
120
116
|
function setMcpTokenManual(token, hostUrl) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
saveMcpTokenStore(store);
|
|
124
|
-
logger.info(`MCP token manually set for ${hostUrl}`);
|
|
117
|
+
_mcpTokenCache.set(hostUrl, token);
|
|
118
|
+
logger.info(`MCP token manually set (in-process) for ${hostUrl}`);
|
|
125
119
|
}
|
|
126
120
|
async function validateMcpToken(token, hostUrl) {
|
|
127
121
|
const mapping = getMcpMapping("analysis");
|
|
@@ -184,13 +178,16 @@ async function mcpRequest(url, method, params = {}, hostOverride) {
|
|
|
184
178
|
body: JSON.stringify(body)
|
|
185
179
|
});
|
|
186
180
|
if (!resp.ok) {
|
|
187
|
-
logger.warn(`MCP request failed (HTTP ${resp.status}) for ${hostUrl},
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
181
|
+
logger.warn(`MCP request failed (HTTP ${resp.status}) for ${hostUrl}, re-minting token`);
|
|
182
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
183
|
+
_mcpTokenCache.delete(hostUrl);
|
|
184
|
+
const fallbackToken = getFallbackMcpToken(hostUrl);
|
|
185
|
+
const newToken = fallbackToken ?? await generateMcpToken(hostUrl);
|
|
186
|
+
_mcpTokenCache.set(hostUrl, newToken);
|
|
187
|
+
logger.info(`MCP token re-minted for ${hostUrl}`);
|
|
188
|
+
process.stderr.write(`[ae-cli] MCP token re-minted for ${hostUrl}
|
|
192
189
|
`);
|
|
193
|
-
headers["mcp-token"] =
|
|
190
|
+
headers["mcp-token"] = newToken;
|
|
194
191
|
const retryResp = await fetch(url, {
|
|
195
192
|
method: "POST",
|
|
196
193
|
headers,
|
|
@@ -251,7 +248,7 @@ function parseMcpResult(result) {
|
|
|
251
248
|
export {
|
|
252
249
|
registerMcpMappings,
|
|
253
250
|
resolveMcpUrl,
|
|
254
|
-
|
|
251
|
+
getMcpToken,
|
|
255
252
|
clearMcpToken,
|
|
256
253
|
setMcpTokenManual,
|
|
257
254
|
validateMcpToken,
|
|
@@ -2,17 +2,19 @@ import {
|
|
|
2
2
|
httpDelete,
|
|
3
3
|
httpGet,
|
|
4
4
|
httpPost,
|
|
5
|
+
httpRequest,
|
|
5
6
|
httpUpload,
|
|
6
7
|
queryReportData,
|
|
7
8
|
querySql,
|
|
8
9
|
wsQuery
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-LU7SXK4Q.js";
|
|
11
|
+
import "./chunk-CAQYQA4R.js";
|
|
12
|
+
import "./chunk-SRJIAOBN.js";
|
|
12
13
|
export {
|
|
13
14
|
httpDelete,
|
|
14
15
|
httpGet,
|
|
15
16
|
httpPost,
|
|
17
|
+
httpRequest,
|
|
16
18
|
httpUpload,
|
|
17
19
|
queryReportData,
|
|
18
20
|
querySql,
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printError,
|
|
3
|
+
printOutput
|
|
4
|
+
} from "./chunk-CLJF7MQA.js";
|
|
5
|
+
import {
|
|
6
|
+
GLOBAL_QUERY_CONFIG_KEY,
|
|
7
|
+
getAnalysisMappingPathForClusterMode,
|
|
8
|
+
getClusterInfoFilePath,
|
|
9
|
+
isGlobalQueryModeEnabled,
|
|
10
|
+
setGlobalQueryModeEnabled
|
|
11
|
+
} from "./chunk-GSJGPNKK.js";
|
|
12
|
+
import {
|
|
13
|
+
addHost,
|
|
14
|
+
loadConfig,
|
|
15
|
+
setActiveHost
|
|
16
|
+
} from "./chunk-SRJIAOBN.js";
|
|
17
|
+
|
|
18
|
+
// src/commands/config.ts
|
|
19
|
+
function registerConfig(program) {
|
|
20
|
+
const configCmd = program.command("config").description("AE host and environment configuration").action(() => {
|
|
21
|
+
printError("config", "Missing subcommand.", "Run: ae-cli config --help");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
});
|
|
24
|
+
configCmd.command("list").description("List configured AE environments").action(() => {
|
|
25
|
+
printConfigList(program);
|
|
26
|
+
});
|
|
27
|
+
configCmd.command("current").description("Show the active AE environment").action(() => {
|
|
28
|
+
printCurrentConfig(program);
|
|
29
|
+
});
|
|
30
|
+
configCmd.command("use <env>").description("Switch active AE environment by exact URL or unique label").action((env) => {
|
|
31
|
+
useConfigEnv(program, env);
|
|
32
|
+
});
|
|
33
|
+
configCmd.command("set-host <url>").description("Set the active AE host non-interactively (adds it if not already configured)").option("--label <label>", "Display label for this host (defaults to the host URL)").action((url, opts) => {
|
|
34
|
+
const normalized = normalizeUrl(url);
|
|
35
|
+
const label = opts.label || normalized;
|
|
36
|
+
addHost(normalized, label);
|
|
37
|
+
setActiveHost(normalized);
|
|
38
|
+
printOutput({ activeHost: normalized, label }, program.opts().format || "json");
|
|
39
|
+
});
|
|
40
|
+
const clusterMode = configCmd.command("cluster-mode").description("Manage local multi-cluster analysis MCP mode").action(() => {
|
|
41
|
+
printClusterModeStatus(program);
|
|
42
|
+
});
|
|
43
|
+
clusterMode.command("status").description("Show local multi-cluster analysis MCP mode").action(() => {
|
|
44
|
+
printClusterModeStatus(program);
|
|
45
|
+
});
|
|
46
|
+
clusterMode.command("enable").description("Enable local multi-cluster analysis MCP mode").action(() => {
|
|
47
|
+
setGlobalQueryModeEnabled(true);
|
|
48
|
+
printClusterModeStatus(program);
|
|
49
|
+
});
|
|
50
|
+
clusterMode.command("disable").description("Disable local multi-cluster analysis MCP mode").action(() => {
|
|
51
|
+
setGlobalQueryModeEnabled(false);
|
|
52
|
+
printClusterModeStatus(program);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function printClusterModeStatus(program) {
|
|
56
|
+
const enabled = isGlobalQueryModeEnabled();
|
|
57
|
+
printOutput({
|
|
58
|
+
[GLOBAL_QUERY_CONFIG_KEY]: enabled,
|
|
59
|
+
path: getClusterInfoFilePath(),
|
|
60
|
+
analysisMappingPath: getAnalysisMappingPathForClusterMode(enabled)
|
|
61
|
+
}, program.opts().format || "json", program.opts().jq);
|
|
62
|
+
}
|
|
63
|
+
function readHostViews() {
|
|
64
|
+
const config = loadConfig();
|
|
65
|
+
const hosts = Object.entries(config.hosts).map(([url, entry]) => ({
|
|
66
|
+
url,
|
|
67
|
+
label: entry.label,
|
|
68
|
+
active: url === config.activeHost
|
|
69
|
+
}));
|
|
70
|
+
return { activeHost: config.activeHost, hosts };
|
|
71
|
+
}
|
|
72
|
+
function printConfigList(program) {
|
|
73
|
+
const { activeHost, hosts } = readHostViews();
|
|
74
|
+
printOutput({ activeHost, hosts }, program.opts().format || "json", program.opts().jq);
|
|
75
|
+
}
|
|
76
|
+
function printCurrentConfig(program) {
|
|
77
|
+
const { activeHost, hosts } = readHostViews();
|
|
78
|
+
const current = hosts.find((h) => h.url === activeHost);
|
|
79
|
+
if (!current) {
|
|
80
|
+
failConfig("No active AE environment configured.", "Run: ae-cli config use <env> or ae-cli config list");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
printOutput({ activeHost: current.url, label: current.label }, program.opts().format || "json", program.opts().jq);
|
|
84
|
+
}
|
|
85
|
+
function useConfigEnv(program, env) {
|
|
86
|
+
const target = resolveHost(env);
|
|
87
|
+
if (target.status === "not-found") {
|
|
88
|
+
failConfig(
|
|
89
|
+
`No AE environment matched: ${env}`,
|
|
90
|
+
target.hosts.length > 0 ? `Available environments: ${formatHostOptions(target.hosts)}` : "Run: ae-cli config list"
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (target.status === "duplicate-label") {
|
|
95
|
+
failConfig(
|
|
96
|
+
`Duplicate label: ${env}`,
|
|
97
|
+
`Rename duplicate labels first. Run: ae-cli config list \u2014 ${formatHostOptions(target.matches)}`
|
|
98
|
+
);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
setActiveHost(target.host.url);
|
|
102
|
+
printOutput({ activeHost: target.host.url, label: target.host.label }, program.opts().format || "json", program.opts().jq);
|
|
103
|
+
}
|
|
104
|
+
function resolveHost(env) {
|
|
105
|
+
const raw = env.trim();
|
|
106
|
+
const selector = raw.startsWith("http://") || raw.startsWith("https://") ? normalizeUrl(raw) : raw;
|
|
107
|
+
const { hosts } = readHostViews();
|
|
108
|
+
const byUrl = hosts.find((h) => h.url === selector);
|
|
109
|
+
if (byUrl) return { status: "found", host: byUrl };
|
|
110
|
+
const byLabel = hosts.filter((h) => h.label === raw);
|
|
111
|
+
if (byLabel.length === 1) return { status: "found", host: byLabel[0] };
|
|
112
|
+
if (byLabel.length > 1) return { status: "duplicate-label", matches: byLabel };
|
|
113
|
+
return { status: "not-found", hosts };
|
|
114
|
+
}
|
|
115
|
+
function formatHostOptions(hosts) {
|
|
116
|
+
return hosts.map((h) => `${h.label} (${h.url})`).join(", ");
|
|
117
|
+
}
|
|
118
|
+
function failConfig(message, hint) {
|
|
119
|
+
printError("config", message, hint);
|
|
120
|
+
process.exitCode = 1;
|
|
121
|
+
}
|
|
122
|
+
function normalizeUrl(url) {
|
|
123
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
124
|
+
url = `https://${url}`;
|
|
125
|
+
}
|
|
126
|
+
return url.replace(/\/$/, "");
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
registerConfig
|
|
130
|
+
};
|