@thinkingai/ae-cli 1.0.27 → 1.0.30
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 -16
- package/README.zh.md +1 -16
- package/dist/auth-H3GJD55A.js +457 -0
- package/dist/{auth-TXFJHPXU.js → auth-U25QJU5D.js} +3 -3
- package/dist/{chunk-B4UL2VIJ.js → chunk-CLJF7MQA.js} +1 -1
- package/dist/{chunk-6T7245YE.js → chunk-EGEIXA2Z.js} +90 -18
- package/dist/{chunk-2NGWYMLB.js → chunk-GLNZSDKO.js} +88 -50
- package/dist/chunk-GSJGPNKK.js +49 -0
- package/dist/{chunk-VT6VC4PA.js → chunk-I42JGQ2J.js} +26 -11
- package/dist/chunk-JM34JPCO.js +239 -0
- package/dist/chunk-NOO24N7W.js +11 -0
- package/dist/chunk-SF3KTPIC.js +98 -0
- package/dist/chunk-SRJIAOBN.js +244 -0
- package/dist/chunk-U6TKB3IV.js +171 -0
- package/dist/{chunk-TG64AQV4.js → chunk-VJFUB3H3.js} +99 -56
- package/dist/{client-IU2E5IOL.js → client-IN42F223.js} +4 -4
- package/dist/config-64G36TJL.js +130 -0
- package/dist/index.js +52 -25
- package/dist/{model-CC7U5XOJ.js → model-VZCYNIOG.js} +11 -10
- package/dist/{raw-TUHZQ4UB.js → raw-WJIWC6YP.js} +13 -7
- package/dist/{sync-EVEDS7YE.js → sync-NVASAISS.js} +146 -47
- package/dist/{te-agent-FLTDYV3L.js → te-agent-YV4DXEXK.js} +24 -23
- package/dist/{te-analysis-CMXADIJM.js → te-analysis-CB3DA5I5.js} +61 -13
- package/dist/{te-audience-LPZFFSXM.js → te-audience-W7SCQFC7.js} +7 -5
- package/dist/{te-common-BXQFKTB3.js → te-common-FBXVWBSI.js} +21 -9
- package/dist/{te-community-K5S3VOZY.js → te-community-LNVDZSGW.js} +6 -4
- package/dist/{te-dataops-567IMCQG.js → te-dataops-IPCSSWYH.js} +29 -27
- package/dist/{te-engage-TBUTGW5F.js → te-engage-KARARMIR.js} +6 -4
- package/dist/{te-kb-XHVBWP5E.js → te-kb-2Z2CARN3.js} +7 -5
- package/dist/{te-meta-NQ4U3VJW.js → te-meta-PDKLMWXN.js} +6 -4
- package/dist/{te-team-556APRIU.js → te-team-SW5B7DHO.js} +17 -12
- package/package.json +6 -2
- package/skills/ae-agent/SKILL.md +2 -1
- package/skills/ae-analysis/SKILL.md +1 -1
- package/skills/ae-analysis/references/list_clusters.md +4 -2
- 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 +1 -0
- 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/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/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 +1 -0
- package/skills/ae-team/SKILL.md +1 -1
- package/dist/auth-W2JZ3DKA.js +0 -170
- package/dist/chunk-BI5ZVD6T.js +0 -186
- package/dist/chunk-MNHE6SSI.js +0 -79
- package/dist/chunk-MWWYGZ76.js +0 -130
- package/dist/chunk-SRRUNQIM.js +0 -312
- package/dist/config-WH3R3IRY.js +0 -258
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SecureStoreAuthError,
|
|
3
|
+
getValidAccessToken
|
|
4
|
+
} from "./chunk-JM34JPCO.js";
|
|
5
|
+
import {
|
|
6
|
+
getActiveHost,
|
|
7
|
+
getConfigDir,
|
|
8
|
+
logger,
|
|
9
|
+
safeJsonParse,
|
|
10
|
+
safeReadJsonFile
|
|
11
|
+
} from "./chunk-SRJIAOBN.js";
|
|
12
|
+
|
|
13
|
+
// src/core/auth.ts
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import path from "path";
|
|
16
|
+
var TOKENS_FILE = path.join(getConfigDir(), "tokens.json");
|
|
17
|
+
var LEGACY_MCP_TOKENS_FILE = path.join(getConfigDir(), "mcp-tokens.json");
|
|
18
|
+
var LEGACY_DIR = path.join(process.env.HOME || "", ".te-mcp");
|
|
19
|
+
(function removeLegacyMcpTokens() {
|
|
20
|
+
try {
|
|
21
|
+
if (fs.existsSync(LEGACY_MCP_TOKENS_FILE)) {
|
|
22
|
+
fs.rmSync(LEGACY_MCP_TOKENS_FILE);
|
|
23
|
+
logger.info("auth: removed legacy mcp-tokens.json (plaintext MCP token file)");
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
function ensureDir() {
|
|
29
|
+
const dir = getConfigDir();
|
|
30
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
function resolveHost(hostOverride) {
|
|
33
|
+
if (hostOverride) return hostOverride;
|
|
34
|
+
return getActiveHost();
|
|
35
|
+
}
|
|
36
|
+
async function validateToken(token, hostUrl) {
|
|
37
|
+
const url = `${hostUrl}/v1/oauth/checkToken`;
|
|
38
|
+
try {
|
|
39
|
+
const resp = await fetch(url, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
42
|
+
body: new URLSearchParams({ accessToken: token }).toString()
|
|
43
|
+
});
|
|
44
|
+
const respJson = safeJsonParse(await resp.text());
|
|
45
|
+
return respJson?.return_code === 0;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function loadAllTokens() {
|
|
51
|
+
try {
|
|
52
|
+
const legacyTokens = path.join(LEGACY_DIR, "tokens.json");
|
|
53
|
+
if (fs.existsSync(legacyTokens) && !fs.existsSync(TOKENS_FILE)) {
|
|
54
|
+
const data = safeReadJsonFile(legacyTokens);
|
|
55
|
+
const migrated = {};
|
|
56
|
+
for (const [key, val] of Object.entries(data)) {
|
|
57
|
+
const url = key.startsWith("http") ? key : `https://${key}`;
|
|
58
|
+
migrated[url] = val;
|
|
59
|
+
}
|
|
60
|
+
ensureDir();
|
|
61
|
+
fs.writeFileSync(TOKENS_FILE, JSON.stringify(migrated, null, 2));
|
|
62
|
+
return migrated;
|
|
63
|
+
}
|
|
64
|
+
if (fs.existsSync(TOKENS_FILE)) {
|
|
65
|
+
const data = safeReadJsonFile(TOKENS_FILE);
|
|
66
|
+
let needsMigration = false;
|
|
67
|
+
const migrated = {};
|
|
68
|
+
for (const [key, val] of Object.entries(data)) {
|
|
69
|
+
if (!key.startsWith("http")) {
|
|
70
|
+
migrated[`https://${key}`] = val;
|
|
71
|
+
needsMigration = true;
|
|
72
|
+
} else {
|
|
73
|
+
migrated[key] = val;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (needsMigration) {
|
|
77
|
+
fs.writeFileSync(TOKENS_FILE, JSON.stringify(migrated, null, 2));
|
|
78
|
+
return migrated;
|
|
79
|
+
}
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
function saveAllTokens(tokens) {
|
|
87
|
+
ensureDir();
|
|
88
|
+
fs.writeFileSync(TOKENS_FILE, JSON.stringify(tokens, null, 2));
|
|
89
|
+
try {
|
|
90
|
+
fs.chmodSync(TOKENS_FILE, 384);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function loadToken(hostUrl) {
|
|
95
|
+
const tokens = loadAllTokens();
|
|
96
|
+
const entry = tokens[hostUrl];
|
|
97
|
+
if (!entry || !entry.token) return null;
|
|
98
|
+
return { host: hostUrl, token: entry.token, updatedAt: entry.updatedAt };
|
|
99
|
+
}
|
|
100
|
+
function saveToken(token, hostUrl) {
|
|
101
|
+
const tokens = loadAllTokens();
|
|
102
|
+
tokens[hostUrl] = { token, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
103
|
+
saveAllTokens(tokens);
|
|
104
|
+
logger.info(`Token saved for ${hostUrl}`);
|
|
105
|
+
}
|
|
106
|
+
function clearToken(hostUrl) {
|
|
107
|
+
const tokens = loadAllTokens();
|
|
108
|
+
delete tokens[hostUrl];
|
|
109
|
+
saveAllTokens(tokens);
|
|
110
|
+
}
|
|
111
|
+
function setTokenManual(token, hostUrl) {
|
|
112
|
+
saveToken(token, hostUrl);
|
|
113
|
+
}
|
|
114
|
+
function getAuthStatus(hostUrl) {
|
|
115
|
+
if (process.env.TE_TOKEN) {
|
|
116
|
+
return { authenticated: true, host: hostUrl, source: "env:TE_TOKEN" };
|
|
117
|
+
}
|
|
118
|
+
const cached = loadToken(hostUrl);
|
|
119
|
+
if (cached) {
|
|
120
|
+
const ageMs = Date.now() - new Date(cached.updatedAt).getTime();
|
|
121
|
+
const hours = Math.round(ageMs / 36e5);
|
|
122
|
+
return { authenticated: true, host: hostUrl, tokenAge: `${hours}h ago`, source: "cache" };
|
|
123
|
+
}
|
|
124
|
+
return { authenticated: false, host: hostUrl };
|
|
125
|
+
}
|
|
126
|
+
async function getToken(hostUrl) {
|
|
127
|
+
if (!hostUrl) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`No AE host configured.
|
|
130
|
+
Run: ae-cli config set-host <url>`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (process.env.TE_TOKEN) {
|
|
134
|
+
logger.info("Using token from env:TE_TOKEN");
|
|
135
|
+
return process.env.TE_TOKEN;
|
|
136
|
+
}
|
|
137
|
+
const cached = loadToken(hostUrl);
|
|
138
|
+
if (cached && cached.token) {
|
|
139
|
+
logger.info(`Using cached token for ${hostUrl}`);
|
|
140
|
+
return cached.token;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const secureToken = await getValidAccessToken(hostUrl);
|
|
144
|
+
logger.info(`Using secure-store token for ${hostUrl}`);
|
|
145
|
+
return secureToken;
|
|
146
|
+
} catch (e) {
|
|
147
|
+
if (e instanceof SecureStoreAuthError) {
|
|
148
|
+
logger.info(`secure-store: ${e.message}`);
|
|
149
|
+
} else {
|
|
150
|
+
logger.warn(`secure-store unexpected error: ${e.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
throw new Error(
|
|
154
|
+
`Cannot obtain token for ${hostUrl}.
|
|
155
|
+
Options:
|
|
156
|
+
1. ae-cli auth login (device code flow, cross-platform)
|
|
157
|
+
2. ae-cli auth set-token <token>
|
|
158
|
+
3. export TE_TOKEN=<token> (CI/headless)`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
resolveHost,
|
|
164
|
+
validateToken,
|
|
165
|
+
loadToken,
|
|
166
|
+
saveToken,
|
|
167
|
+
clearToken,
|
|
168
|
+
setTokenManual,
|
|
169
|
+
getAuthStatus,
|
|
170
|
+
getToken
|
|
171
|
+
};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getActiveHost,
|
|
3
|
+
getSandboxRuntimeRoot
|
|
4
|
+
} from "./chunk-SRJIAOBN.js";
|
|
5
|
+
|
|
1
6
|
// src/core/te-agent-credentials.ts
|
|
2
7
|
import { readFileSync } from "fs";
|
|
3
8
|
import { homedir } from "os";
|
|
@@ -6,8 +11,7 @@ function getCredentialsPath() {
|
|
|
6
11
|
return join(process.env.HOME || homedir(), ".te-agent", "credentials.json");
|
|
7
12
|
}
|
|
8
13
|
function getPersistentEnvPath() {
|
|
9
|
-
|
|
10
|
-
return join(runtimeRoot, ".env");
|
|
14
|
+
return join(getSandboxRuntimeRoot(), ".env");
|
|
11
15
|
}
|
|
12
16
|
function parseDotEnv(raw) {
|
|
13
17
|
const result = {};
|
|
@@ -32,8 +36,8 @@ function readPersistentEnv() {
|
|
|
32
36
|
} catch (err) {
|
|
33
37
|
if (err?.code === "ENOENT") return null;
|
|
34
38
|
throw new TeAgentCredentialsError(
|
|
35
|
-
|
|
36
|
-
"
|
|
39
|
+
`Failed to read ${envPath}: ${err?.message ?? err}`,
|
|
40
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
37
41
|
);
|
|
38
42
|
}
|
|
39
43
|
}
|
|
@@ -56,43 +60,30 @@ function readLegacyCredentials() {
|
|
|
56
60
|
if (err?.code === "ENOENT") return null;
|
|
57
61
|
if (err instanceof SyntaxError) {
|
|
58
62
|
throw new TeAgentCredentialsError(
|
|
59
|
-
|
|
60
|
-
"
|
|
63
|
+
`Failed to parse ${credPath}: ${err.message}`,
|
|
64
|
+
"The credentials file may be corrupted; alternatively inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
61
65
|
);
|
|
62
66
|
}
|
|
63
67
|
throw new TeAgentCredentialsError(
|
|
64
|
-
|
|
65
|
-
"
|
|
68
|
+
`Failed to read ${credPath}: ${err?.message ?? err}`,
|
|
69
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
66
70
|
);
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
|
-
function
|
|
73
|
+
function tryLoadTeAgentSandboxCredentials() {
|
|
70
74
|
const legacy = readLegacyCredentials();
|
|
71
|
-
const credPath = getCredentialsPath();
|
|
72
|
-
const envPath = getPersistentEnvPath();
|
|
73
75
|
const persistent = readPersistentEnv();
|
|
74
76
|
const url = process.env.TE_CLAUDE_BASE_URL || persistent?.TE_CLAUDE_BASE_URL || legacy?.url;
|
|
75
|
-
const sandboxId = process.env.SANDBOX_ID || persistent?.SANDBOX_ID || legacy?.sandboxId;
|
|
76
|
-
const sandboxSecretKey = process.env.SECRET_KEY || process.env.SANDBOX_SECRET_KEY || persistent?.SECRET_KEY || persistent?.SANDBOX_SECRET_KEY || legacy?.sandboxSecretKey || legacy?.secretKey;
|
|
77
77
|
if (typeof url !== "string" || !url) {
|
|
78
|
-
|
|
79
|
-
"TE_CLAUDE_BASE_URL \u7F3A\u5931",
|
|
80
|
-
`\u8BF7\u5728 te-agent \u6C99\u7BB1\u5185\u6267\u884C\uFF0C\u6216\u914D\u7F6E ${envPath} / ${credPath}`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
if (typeof sandboxId !== "string" || !sandboxId) {
|
|
84
|
-
throw new TeAgentCredentialsError(
|
|
85
|
-
"SANDBOX_ID \u7F3A\u5931",
|
|
86
|
-
`\u8BF7\u5728 te-agent \u6C99\u7BB1\u5185\u6267\u884C\uFF0C\u6216\u914D\u7F6E ${envPath} / ${credPath}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
if (typeof sandboxSecretKey !== "string" || !sandboxSecretKey) {
|
|
90
|
-
throw new TeAgentCredentialsError(
|
|
91
|
-
"SECRET_KEY \u7F3A\u5931",
|
|
92
|
-
`\u8BF7\u5728 te-agent \u6C99\u7BB1\u5185\u6267\u884C\uFF0C\u6216\u914D\u7F6E ${envPath} / ${credPath}`
|
|
93
|
-
);
|
|
78
|
+
return null;
|
|
94
79
|
}
|
|
95
|
-
|
|
80
|
+
const sandboxId = process.env.SANDBOX_ID || persistent?.SANDBOX_ID || legacy?.sandboxId || null;
|
|
81
|
+
const sandboxSecretKey = process.env.SECRET_KEY || process.env.SANDBOX_SECRET_KEY || persistent?.SECRET_KEY || persistent?.SANDBOX_SECRET_KEY || legacy?.sandboxSecretKey || legacy?.secretKey || null;
|
|
82
|
+
return {
|
|
83
|
+
url,
|
|
84
|
+
sandboxId: typeof sandboxId === "string" ? sandboxId : null,
|
|
85
|
+
sandboxSecretKey: typeof sandboxSecretKey === "string" ? sandboxSecretKey : null
|
|
86
|
+
};
|
|
96
87
|
}
|
|
97
88
|
function getClaudeConfigDir() {
|
|
98
89
|
const fromEnv = process.env.CLAUDE_CONFIG_DIR;
|
|
@@ -124,19 +115,49 @@ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
124
115
|
return await fetch(url, { ...init, signal: controller.signal });
|
|
125
116
|
} catch (err) {
|
|
126
117
|
if (err?.name === "AbortError") {
|
|
127
|
-
throw new TeAgentApiError(
|
|
118
|
+
throw new TeAgentApiError(`Request timed out (${timeoutMs}ms): ${url}`, 0, "TIMEOUT");
|
|
128
119
|
}
|
|
129
|
-
throw new TeAgentApiError(
|
|
120
|
+
throw new TeAgentApiError(`Network request failed: ${err?.message ?? err}`, 0, "NETWORK_ERROR");
|
|
130
121
|
} finally {
|
|
131
122
|
clearTimeout(timer);
|
|
132
123
|
}
|
|
133
124
|
}
|
|
134
|
-
function
|
|
135
|
-
const
|
|
136
|
-
|
|
125
|
+
function teClaudeBaseFromActiveHost() {
|
|
126
|
+
const override = process.env.TE_CLAUDE_BASE_URL;
|
|
127
|
+
if (override) return override.replace(/\/+$/, "");
|
|
128
|
+
const h = getActiveHost();
|
|
129
|
+
if (!h) return void 0;
|
|
130
|
+
const base = h.replace(/\/+$/, "");
|
|
131
|
+
const bp = process.env.TE_CLAUDE_BASE_PATH || "/agent";
|
|
132
|
+
return base.endsWith(bp) ? base : base + bp;
|
|
133
|
+
}
|
|
134
|
+
async function signRequest(method, path, rawBody) {
|
|
135
|
+
const sandboxCred = tryLoadTeAgentSandboxCredentials();
|
|
136
|
+
if (sandboxCred && sandboxCred.sandboxId && sandboxCred.sandboxSecretKey) {
|
|
137
|
+
const headers2 = {
|
|
138
|
+
"X-Sandbox-Id": sandboxCred.sandboxId,
|
|
139
|
+
"X-Sandbox-Secret-Key": sandboxCred.sandboxSecretKey
|
|
140
|
+
};
|
|
141
|
+
if (method === "POST" || method === "PATCH") {
|
|
142
|
+
headers2["Content-Type"] = "application/json";
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
url: `${sandboxCred.url.replace(/\/$/, "")}${path}`,
|
|
146
|
+
headers: headers2,
|
|
147
|
+
rawBody
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const { getToken } = await import("./auth-U25QJU5D.js");
|
|
151
|
+
const baseUrl = sandboxCred?.url || teClaudeBaseFromActiveHost();
|
|
152
|
+
if (!baseUrl) {
|
|
153
|
+
throw new TeAgentCredentialsError(
|
|
154
|
+
"Cannot determine the te-claude service URL",
|
|
155
|
+
"Run ae-cli config set-host <url> to configure the service URL, or execute inside a te-agent sandbox"
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const accessToken = await getToken(getActiveHost() || baseUrl);
|
|
137
159
|
const headers = {
|
|
138
|
-
"
|
|
139
|
-
"X-Sandbox-Secret-Key": sandboxSecretKey
|
|
160
|
+
"Authorization": `bearer ${accessToken}`
|
|
140
161
|
};
|
|
141
162
|
if (method === "POST" || method === "PATCH") {
|
|
142
163
|
headers["Content-Type"] = "application/json";
|
|
@@ -158,6 +179,14 @@ async function parseResponse(response, defaultErrorPrefix) {
|
|
|
158
179
|
}
|
|
159
180
|
}
|
|
160
181
|
if (!response.ok) {
|
|
182
|
+
if (response.status === 401) {
|
|
183
|
+
throw new TeAgentApiError(
|
|
184
|
+
`Session expired or unauthorized. Please run: ae-cli auth login`,
|
|
185
|
+
response.status,
|
|
186
|
+
"auth_expired",
|
|
187
|
+
parsed
|
|
188
|
+
);
|
|
189
|
+
}
|
|
161
190
|
const message = typeof parsed === "object" && parsed && typeof parsed.error === "string" ? parsed.error : `${defaultErrorPrefix} ${response.status}`;
|
|
162
191
|
const code = typeof parsed === "object" && parsed && typeof parsed.code === "string" ? parsed.code : void 0;
|
|
163
192
|
throw new TeAgentApiError(message, response.status, code, parsed);
|
|
@@ -166,21 +195,21 @@ async function parseResponse(response, defaultErrorPrefix) {
|
|
|
166
195
|
}
|
|
167
196
|
async function postToMainApp(path, body) {
|
|
168
197
|
const rawBody = JSON.stringify(body);
|
|
169
|
-
const signed = signRequest("POST", path, rawBody);
|
|
198
|
+
const signed = await signRequest("POST", path, rawBody);
|
|
170
199
|
const response = await fetchWithTimeout(signed.url, {
|
|
171
200
|
method: "POST",
|
|
172
201
|
headers: signed.headers,
|
|
173
202
|
body: signed.rawBody
|
|
174
203
|
});
|
|
175
|
-
return parseResponse(response, "
|
|
204
|
+
return parseResponse(response, "Main app returned");
|
|
176
205
|
}
|
|
177
206
|
async function getFromMainApp(path) {
|
|
178
|
-
const signed = signRequest("GET", path, "");
|
|
207
|
+
const signed = await signRequest("GET", path, "");
|
|
179
208
|
const response = await fetchWithTimeout(signed.url, {
|
|
180
209
|
method: "GET",
|
|
181
210
|
headers: signed.headers
|
|
182
211
|
});
|
|
183
|
-
return parseResponse(response, "
|
|
212
|
+
return parseResponse(response, "Main app returned");
|
|
184
213
|
}
|
|
185
214
|
async function getSandboxModels(currentModelId) {
|
|
186
215
|
const qs = currentModelId ? `?current=${encodeURIComponent(currentModelId)}` : "";
|
|
@@ -205,45 +234,59 @@ async function postSandboxSyncPull(args) {
|
|
|
205
234
|
kind: args.kind,
|
|
206
235
|
skills: args.skills,
|
|
207
236
|
mcp: args.mcp,
|
|
208
|
-
mode: "merge"
|
|
209
|
-
ifUnmodifiedSince: args.ifUnmodifiedSince
|
|
237
|
+
mode: "merge"
|
|
210
238
|
});
|
|
211
239
|
}
|
|
212
240
|
async function deleteFromMainApp(path) {
|
|
213
|
-
const signed = signRequest("DELETE", path, "");
|
|
241
|
+
const signed = await signRequest("DELETE", path, "");
|
|
214
242
|
const response = await fetchWithTimeout(signed.url, {
|
|
215
243
|
method: "DELETE",
|
|
216
244
|
headers: signed.headers
|
|
217
245
|
});
|
|
218
|
-
return parseResponse(response, "
|
|
246
|
+
return parseResponse(response, "Main app returned");
|
|
219
247
|
}
|
|
220
248
|
async function patchToMainApp(path, body) {
|
|
221
249
|
const rawBody = JSON.stringify(body);
|
|
222
|
-
const signed = signRequest("PATCH", path, rawBody);
|
|
250
|
+
const signed = await signRequest("PATCH", path, rawBody);
|
|
223
251
|
const response = await fetchWithTimeout(signed.url, {
|
|
224
252
|
method: "PATCH",
|
|
225
253
|
headers: signed.headers,
|
|
226
254
|
body: signed.rawBody
|
|
227
255
|
});
|
|
228
|
-
return parseResponse(response, "
|
|
256
|
+
return parseResponse(response, "Main app returned");
|
|
229
257
|
}
|
|
230
258
|
async function uploadToMainApp(path, formData) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
259
|
+
const sandboxCred = tryLoadTeAgentSandboxCredentials();
|
|
260
|
+
let baseUrl;
|
|
261
|
+
let authHeaders;
|
|
262
|
+
if (sandboxCred && sandboxCred.sandboxId && sandboxCred.sandboxSecretKey) {
|
|
263
|
+
baseUrl = sandboxCred.url.replace(/\/$/, "");
|
|
264
|
+
authHeaders = {
|
|
265
|
+
"X-Sandbox-Id": sandboxCred.sandboxId,
|
|
266
|
+
"X-Sandbox-Secret-Key": sandboxCred.sandboxSecretKey
|
|
267
|
+
};
|
|
268
|
+
} else {
|
|
269
|
+
const { getToken } = await import("./auth-U25QJU5D.js");
|
|
270
|
+
baseUrl = (sandboxCred?.url || teClaudeBaseFromActiveHost() || "").replace(/\/$/, "");
|
|
271
|
+
if (!baseUrl) {
|
|
272
|
+
throw new TeAgentCredentialsError(
|
|
273
|
+
"Cannot determine the te-claude service URL",
|
|
274
|
+
"Run ae-cli config set-host <url> to configure the service URL, or execute inside a te-agent sandbox"
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
const accessToken = await getToken(getActiveHost() || baseUrl);
|
|
278
|
+
authHeaders = { "Authorization": `bearer ${accessToken}` };
|
|
279
|
+
}
|
|
234
280
|
const response = await fetchWithTimeout(
|
|
235
|
-
|
|
281
|
+
`${baseUrl}${path}`,
|
|
236
282
|
{
|
|
237
283
|
method: "POST",
|
|
238
|
-
headers:
|
|
239
|
-
"X-Sandbox-Id": cred.mainApp.sandboxId,
|
|
240
|
-
"X-Sandbox-Secret-Key": cred.mainApp.sandboxSecretKey
|
|
241
|
-
},
|
|
284
|
+
headers: authHeaders,
|
|
242
285
|
body: formData
|
|
243
286
|
},
|
|
244
287
|
UPLOAD_TIMEOUT_MS
|
|
245
288
|
);
|
|
246
|
-
return parseResponse(response, "
|
|
289
|
+
return parseResponse(response, "Upload failed");
|
|
247
290
|
}
|
|
248
291
|
|
|
249
292
|
export {
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
queryReportData,
|
|
8
8
|
querySql,
|
|
9
9
|
wsQuery
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-I42JGQ2J.js";
|
|
11
|
+
import "./chunk-U6TKB3IV.js";
|
|
12
|
+
import "./chunk-JM34JPCO.js";
|
|
13
|
+
import "./chunk-SRJIAOBN.js";
|
|
14
14
|
export {
|
|
15
15
|
httpDelete,
|
|
16
16
|
httpGet,
|
|
@@ -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
|
+
};
|