@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.
Files changed (90) hide show
  1. package/README.md +1 -16
  2. package/README.zh.md +1 -16
  3. package/dist/auth-H3GJD55A.js +457 -0
  4. package/dist/{auth-TXFJHPXU.js → auth-U25QJU5D.js} +3 -3
  5. package/dist/{chunk-B4UL2VIJ.js → chunk-CLJF7MQA.js} +1 -1
  6. package/dist/{chunk-6T7245YE.js → chunk-EGEIXA2Z.js} +90 -18
  7. package/dist/{chunk-2NGWYMLB.js → chunk-GLNZSDKO.js} +88 -50
  8. package/dist/chunk-GSJGPNKK.js +49 -0
  9. package/dist/{chunk-VT6VC4PA.js → chunk-I42JGQ2J.js} +26 -11
  10. package/dist/chunk-JM34JPCO.js +239 -0
  11. package/dist/chunk-NOO24N7W.js +11 -0
  12. package/dist/chunk-SF3KTPIC.js +98 -0
  13. package/dist/chunk-SRJIAOBN.js +244 -0
  14. package/dist/chunk-U6TKB3IV.js +171 -0
  15. package/dist/{chunk-TG64AQV4.js → chunk-VJFUB3H3.js} +99 -56
  16. package/dist/{client-IU2E5IOL.js → client-IN42F223.js} +4 -4
  17. package/dist/config-64G36TJL.js +130 -0
  18. package/dist/index.js +52 -25
  19. package/dist/{model-CC7U5XOJ.js → model-VZCYNIOG.js} +11 -10
  20. package/dist/{raw-TUHZQ4UB.js → raw-WJIWC6YP.js} +13 -7
  21. package/dist/{sync-EVEDS7YE.js → sync-NVASAISS.js} +146 -47
  22. package/dist/{te-agent-FLTDYV3L.js → te-agent-YV4DXEXK.js} +24 -23
  23. package/dist/{te-analysis-CMXADIJM.js → te-analysis-CB3DA5I5.js} +61 -13
  24. package/dist/{te-audience-LPZFFSXM.js → te-audience-W7SCQFC7.js} +7 -5
  25. package/dist/{te-common-BXQFKTB3.js → te-common-FBXVWBSI.js} +21 -9
  26. package/dist/{te-community-K5S3VOZY.js → te-community-LNVDZSGW.js} +6 -4
  27. package/dist/{te-dataops-567IMCQG.js → te-dataops-IPCSSWYH.js} +29 -27
  28. package/dist/{te-engage-TBUTGW5F.js → te-engage-KARARMIR.js} +6 -4
  29. package/dist/{te-kb-XHVBWP5E.js → te-kb-2Z2CARN3.js} +7 -5
  30. package/dist/{te-meta-NQ4U3VJW.js → te-meta-PDKLMWXN.js} +6 -4
  31. package/dist/{te-team-556APRIU.js → te-team-SW5B7DHO.js} +17 -12
  32. package/package.json +6 -2
  33. package/skills/ae-agent/SKILL.md +2 -1
  34. package/skills/ae-analysis/SKILL.md +1 -1
  35. package/skills/ae-analysis/references/list_clusters.md +4 -2
  36. package/skills/ae-analysis-global/SKILL.md +51 -0
  37. package/skills/ae-analysis-global/references/list_query_clusters.md +67 -0
  38. package/skills/ae-community/SKILL.md +2 -3
  39. package/skills/ae-dataops/SKILL.md +1 -2
  40. package/skills/ae-engage/SKILL.md +1 -0
  41. package/skills/ae-engage/references/add-approver.md +0 -1
  42. package/skills/ae-engage/references/add-channel.md +0 -1
  43. package/skills/ae-engage/references/approver-list.md +0 -1
  44. package/skills/ae-engage/references/cancel-query-by-request-id.md +0 -1
  45. package/skills/ae-engage/references/channel-detail.md +0 -1
  46. package/skills/ae-engage/references/channel-list.md +0 -1
  47. package/skills/ae-engage/references/config-channel-detail.md +0 -1
  48. package/skills/ae-engage/references/config-channel-list.md +0 -1
  49. package/skills/ae-engage/references/config-item-analysis-report.md +0 -1
  50. package/skills/ae-engage/references/config-item-detail.md +0 -1
  51. package/skills/ae-engage/references/config-item-list.md +0 -1
  52. package/skills/ae-engage/references/config-item-strategy-comparison.md +0 -1
  53. package/skills/ae-engage/references/config-item-trigger-report.md +0 -1
  54. package/skills/ae-engage/references/copy-config-template.md +0 -1
  55. package/skills/ae-engage/references/delete-channel.md +0 -1
  56. package/skills/ae-engage/references/delete-config-channel.md +0 -1
  57. package/skills/ae-engage/references/delete-config-item.md +0 -1
  58. package/skills/ae-engage/references/delete-flow.md +0 -1
  59. package/skills/ae-engage/references/flow-ab-split-node-report.md +0 -1
  60. package/skills/ae-engage/references/flow-detail.md +0 -1
  61. package/skills/ae-engage/references/flow-list.md +0 -1
  62. package/skills/ae-engage/references/flow-node-config-schema.md +0 -1
  63. package/skills/ae-engage/references/flow-node-detail-report.md +0 -1
  64. package/skills/ae-engage/references/flow-node-overview-report.md +0 -1
  65. package/skills/ae-engage/references/flow-process-report.md +0 -1
  66. package/skills/ae-engage/references/manage-flow.md +0 -1
  67. package/skills/ae-engage/references/manage-strategy.md +0 -1
  68. package/skills/ae-engage/references/manage-task.md +0 -1
  69. package/skills/ae-engage/references/modify-flow-base-info.md +0 -1
  70. package/skills/ae-engage/references/strategy-detail.md +0 -1
  71. package/skills/ae-engage/references/strategy-list.md +0 -1
  72. package/skills/ae-engage/references/task-data-detail.md +0 -1
  73. package/skills/ae-engage/references/task-data-overview.md +0 -1
  74. package/skills/ae-engage/references/task-detail.md +0 -1
  75. package/skills/ae-engage/references/task-experiment-report.md +0 -1
  76. package/skills/ae-engage/references/task-list.md +0 -1
  77. package/skills/ae-engage/references/task-metric-detail.md +0 -1
  78. package/skills/ae-engage/references/task-stats.md +0 -1
  79. package/skills/ae-engage/references/update-channel-status.md +0 -1
  80. package/skills/ae-engage/references/update-config-channel-status.md +0 -1
  81. package/skills/ae-engage/references/validate-flow-node-config.md +0 -1
  82. package/skills/ae-engage/references/whitelist-list.md +0 -1
  83. package/skills/ae-kb/SKILL.md +1 -0
  84. package/skills/ae-team/SKILL.md +1 -1
  85. package/dist/auth-W2JZ3DKA.js +0 -170
  86. package/dist/chunk-BI5ZVD6T.js +0 -186
  87. package/dist/chunk-MNHE6SSI.js +0 -79
  88. package/dist/chunk-MWWYGZ76.js +0 -130
  89. package/dist/chunk-SRRUNQIM.js +0 -312
  90. 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
- const runtimeRoot = process.env.SANDBOX_RUNTIME_ROOT ?? "/home/ta/te_agent_ta";
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
- `${envPath} \u8BFB\u53D6\u5931\u8D25\uFF1A${err?.message ?? err}`,
36
- "\u8BF7\u68C0\u67E5\u6587\u4EF6\u6743\u9650\uFF0C\u6216\u901A\u8FC7 TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY \u6CE8\u5165\u8FD0\u884C\u65F6\u51ED\u8BC1"
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
- `${credPath} \u89E3\u6790\u5931\u8D25\uFF1A${err.message}`,
60
- "\u51ED\u8BC1\u6587\u4EF6\u53EF\u80FD\u5DF2\u635F\u574F\uFF1B\u4E5F\u53EF\u4EE5\u901A\u8FC7 TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY \u6CE8\u5165\u8FD0\u884C\u65F6\u51ED\u8BC1"
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
- `${credPath} \u8BFB\u53D6\u5931\u8D25\uFF1A${err?.message ?? err}`,
65
- "\u8BF7\u68C0\u67E5\u6587\u4EF6\u6743\u9650\uFF0C\u6216\u901A\u8FC7 TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY \u6CE8\u5165\u8FD0\u884C\u65F6\u51ED\u8BC1"
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 loadTeAgentCredentials() {
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
- throw new TeAgentCredentialsError(
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
- return { mainApp: { url, sandboxId, sandboxSecretKey } };
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(`\u8BF7\u6C42\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09\uFF1A${url}`, 0, "TIMEOUT");
118
+ throw new TeAgentApiError(`Request timed out (${timeoutMs}ms): ${url}`, 0, "TIMEOUT");
128
119
  }
129
- throw new TeAgentApiError(`\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A${err?.message ?? err}`, 0, "NETWORK_ERROR");
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 signRequest(method, path, rawBody) {
135
- const cred = loadTeAgentCredentials();
136
- const { url: baseUrl, sandboxId, sandboxSecretKey } = cred.mainApp;
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
- "X-Sandbox-Id": sandboxId,
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, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
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, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
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, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
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, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
256
+ return parseResponse(response, "Main app returned");
229
257
  }
230
258
  async function uploadToMainApp(path, formData) {
231
- const cred = loadTeAgentCredentials();
232
- const baseUrl = cred.mainApp.url.replace(/\/$/, "");
233
- const url = `${baseUrl}${path}`;
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
- url,
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, "\u4E0A\u4F20\u5931\u8D25");
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-VT6VC4PA.js";
11
- import "./chunk-SRRUNQIM.js";
12
- import "./chunk-BI5ZVD6T.js";
13
- import "./chunk-MNHE6SSI.js";
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
+ };