@thinkingai/ae-cli 1.0.27 → 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.
Files changed (88) hide show
  1. package/dist/auth-5NSDQFQB.js +454 -0
  2. package/dist/{auth-TXFJHPXU.js → auth-H2376DEF.js} +2 -3
  3. package/dist/chunk-AD5V3ZPJ.js +217 -0
  4. package/dist/chunk-CAQYQA4R.js +399 -0
  5. package/dist/{chunk-B4UL2VIJ.js → chunk-CLJF7MQA.js} +1 -1
  6. package/dist/chunk-GSJGPNKK.js +49 -0
  7. package/dist/{chunk-6T7245YE.js → chunk-IMBKVXKY.js} +8 -8
  8. package/dist/chunk-KAEZTSXN.js +99 -0
  9. package/dist/{chunk-VT6VC4PA.js → chunk-LU7SXK4Q.js} +24 -11
  10. package/dist/chunk-OJDNO5QY.js +63 -0
  11. package/dist/chunk-SRJIAOBN.js +244 -0
  12. package/dist/{chunk-2NGWYMLB.js → chunk-WCHI7725.js} +45 -50
  13. package/dist/{client-IU2E5IOL.js → client-FCMK3XEK.js} +3 -4
  14. package/dist/config-64G36TJL.js +130 -0
  15. package/dist/index.js +28 -23
  16. package/dist/{model-CC7U5XOJ.js → model-EZ6K7FXI.js} +15 -12
  17. package/dist/{raw-TUHZQ4UB.js → raw-VEF3D6UD.js} +11 -7
  18. package/dist/{sync-EVEDS7YE.js → sync-NRODEVNH.js} +36 -34
  19. package/dist/{te-agent-FLTDYV3L.js → te-agent-7U7JLJKU.js} +25 -23
  20. package/dist/{te-analysis-CMXADIJM.js → te-analysis-A2OSGHQ4.js} +59 -13
  21. package/dist/{te-audience-LPZFFSXM.js → te-audience-LI67PPGO.js} +5 -5
  22. package/dist/{te-common-BXQFKTB3.js → te-common-35WVU3C5.js} +19 -9
  23. package/dist/{te-community-K5S3VOZY.js → te-community-LEAP6PWT.js} +4 -4
  24. package/dist/{te-dataops-567IMCQG.js → te-dataops-N2LGZBOX.js} +4 -4
  25. package/dist/{te-engage-TBUTGW5F.js → te-engage-H7C72Z46.js} +4 -4
  26. package/dist/{te-kb-XHVBWP5E.js → te-kb-I2OKTBAI.js} +5 -5
  27. package/dist/{te-meta-NQ4U3VJW.js → te-meta-HBTIEDRO.js} +4 -4
  28. package/dist/{te-team-556APRIU.js → te-team-EM5OWRQL.js} +7 -7
  29. package/package.json +6 -2
  30. package/skills/ae-agent/SKILL.md +1 -0
  31. package/skills/ae-analysis/SKILL.md +1 -1
  32. package/skills/ae-analysis/references/list_clusters.md +4 -2
  33. package/skills/ae-analysis-global/SKILL.md +51 -0
  34. package/skills/ae-analysis-global/references/list_query_clusters.md +67 -0
  35. package/skills/ae-community/SKILL.md +2 -3
  36. package/skills/ae-dataops/SKILL.md +1 -2
  37. package/skills/ae-engage/SKILL.md +1 -0
  38. package/skills/ae-engage/references/add-approver.md +0 -1
  39. package/skills/ae-engage/references/add-channel.md +0 -1
  40. package/skills/ae-engage/references/approver-list.md +0 -1
  41. package/skills/ae-engage/references/cancel-query-by-request-id.md +0 -1
  42. package/skills/ae-engage/references/channel-detail.md +0 -1
  43. package/skills/ae-engage/references/channel-list.md +0 -1
  44. package/skills/ae-engage/references/config-channel-detail.md +0 -1
  45. package/skills/ae-engage/references/config-channel-list.md +0 -1
  46. package/skills/ae-engage/references/config-item-analysis-report.md +0 -1
  47. package/skills/ae-engage/references/config-item-detail.md +0 -1
  48. package/skills/ae-engage/references/config-item-list.md +0 -1
  49. package/skills/ae-engage/references/config-item-strategy-comparison.md +0 -1
  50. package/skills/ae-engage/references/config-item-trigger-report.md +0 -1
  51. package/skills/ae-engage/references/copy-config-template.md +0 -1
  52. package/skills/ae-engage/references/delete-channel.md +0 -1
  53. package/skills/ae-engage/references/delete-config-channel.md +0 -1
  54. package/skills/ae-engage/references/delete-config-item.md +0 -1
  55. package/skills/ae-engage/references/delete-flow.md +0 -1
  56. package/skills/ae-engage/references/flow-ab-split-node-report.md +0 -1
  57. package/skills/ae-engage/references/flow-detail.md +0 -1
  58. package/skills/ae-engage/references/flow-list.md +0 -1
  59. package/skills/ae-engage/references/flow-node-config-schema.md +0 -1
  60. package/skills/ae-engage/references/flow-node-detail-report.md +0 -1
  61. package/skills/ae-engage/references/flow-node-overview-report.md +0 -1
  62. package/skills/ae-engage/references/flow-process-report.md +0 -1
  63. package/skills/ae-engage/references/manage-flow.md +0 -1
  64. package/skills/ae-engage/references/manage-strategy.md +0 -1
  65. package/skills/ae-engage/references/manage-task.md +0 -1
  66. package/skills/ae-engage/references/modify-flow-base-info.md +0 -1
  67. package/skills/ae-engage/references/strategy-detail.md +0 -1
  68. package/skills/ae-engage/references/strategy-list.md +0 -1
  69. package/skills/ae-engage/references/task-data-detail.md +0 -1
  70. package/skills/ae-engage/references/task-data-overview.md +0 -1
  71. package/skills/ae-engage/references/task-detail.md +0 -1
  72. package/skills/ae-engage/references/task-experiment-report.md +0 -1
  73. package/skills/ae-engage/references/task-list.md +0 -1
  74. package/skills/ae-engage/references/task-metric-detail.md +0 -1
  75. package/skills/ae-engage/references/task-stats.md +0 -1
  76. package/skills/ae-engage/references/update-channel-status.md +0 -1
  77. package/skills/ae-engage/references/update-config-channel-status.md +0 -1
  78. package/skills/ae-engage/references/validate-flow-node-config.md +0 -1
  79. package/skills/ae-engage/references/whitelist-list.md +0 -1
  80. package/skills/ae-kb/SKILL.md +1 -0
  81. package/skills/ae-team/SKILL.md +1 -1
  82. package/dist/auth-W2JZ3DKA.js +0 -170
  83. package/dist/chunk-BI5ZVD6T.js +0 -186
  84. package/dist/chunk-MNHE6SSI.js +0 -79
  85. package/dist/chunk-MWWYGZ76.js +0 -130
  86. package/dist/chunk-SRRUNQIM.js +0 -312
  87. package/dist/chunk-TG64AQV4.js +0 -262
  88. package/dist/config-WH3R3IRY.js +0 -258
@@ -1,262 +0,0 @@
1
- // src/core/te-agent-credentials.ts
2
- import { readFileSync } from "fs";
3
- import { homedir } from "os";
4
- import { join } from "path";
5
- function getCredentialsPath() {
6
- return join(process.env.HOME || homedir(), ".te-agent", "credentials.json");
7
- }
8
- function getPersistentEnvPath() {
9
- const runtimeRoot = process.env.SANDBOX_RUNTIME_ROOT ?? "/home/ta/te_agent_ta";
10
- return join(runtimeRoot, ".env");
11
- }
12
- function parseDotEnv(raw) {
13
- const result = {};
14
- for (const line of raw.split("\n")) {
15
- if (/^\s*#/.test(line) || line.trim() === "") continue;
16
- const match = /^\s*([^=]+)=(.*)$/.exec(line);
17
- if (!match) continue;
18
- const key = match[1].trim();
19
- let value = match[2].trim();
20
- if (value.startsWith('"') && value.endsWith('"')) {
21
- value = value.slice(1, -1).replace(/\\"/g, '"');
22
- }
23
- if (value !== "") result[key] = value;
24
- }
25
- return result;
26
- }
27
- function readPersistentEnv() {
28
- const envPath = getPersistentEnvPath();
29
- try {
30
- const raw = readFileSync(envPath, "utf8");
31
- return parseDotEnv(raw);
32
- } catch (err) {
33
- if (err?.code === "ENOENT") return null;
34
- 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"
37
- );
38
- }
39
- }
40
- var TeAgentCredentialsError = class extends Error {
41
- constructor(message, hint) {
42
- super(message);
43
- this.hint = hint;
44
- this.name = "TeAgentCredentialsError";
45
- }
46
- hint;
47
- };
48
- function readLegacyCredentials() {
49
- const credPath = getCredentialsPath();
50
- try {
51
- const raw = readFileSync(credPath, "utf8");
52
- const parsed = JSON.parse(raw);
53
- const main = parsed?.mainApp;
54
- return main && typeof main === "object" ? main : null;
55
- } catch (err) {
56
- if (err?.code === "ENOENT") return null;
57
- if (err instanceof SyntaxError) {
58
- 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"
61
- );
62
- }
63
- 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"
66
- );
67
- }
68
- }
69
- function loadTeAgentCredentials() {
70
- const legacy = readLegacyCredentials();
71
- const credPath = getCredentialsPath();
72
- const envPath = getPersistentEnvPath();
73
- const persistent = readPersistentEnv();
74
- 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
- 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
- );
94
- }
95
- return { mainApp: { url, sandboxId, sandboxSecretKey } };
96
- }
97
- function getClaudeConfigDir() {
98
- const fromEnv = process.env.CLAUDE_CONFIG_DIR;
99
- if (typeof fromEnv === "string" && fromEnv.length > 0) {
100
- return fromEnv;
101
- }
102
- return join(homedir(), ".claude");
103
- }
104
-
105
- // src/core/te-agent-client.ts
106
- var TeAgentApiError = class extends Error {
107
- constructor(message, status, code, body) {
108
- super(message);
109
- this.status = status;
110
- this.code = code;
111
- this.body = body;
112
- this.name = "TeAgentApiError";
113
- }
114
- status;
115
- code;
116
- body;
117
- };
118
- var DEFAULT_TIMEOUT_MS = 3e4;
119
- var UPLOAD_TIMEOUT_MS = 12e4;
120
- async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
121
- const controller = new AbortController();
122
- const timer = setTimeout(() => controller.abort(), timeoutMs);
123
- try {
124
- return await fetch(url, { ...init, signal: controller.signal });
125
- } catch (err) {
126
- if (err?.name === "AbortError") {
127
- throw new TeAgentApiError(`\u8BF7\u6C42\u8D85\u65F6\uFF08${timeoutMs}ms\uFF09\uFF1A${url}`, 0, "TIMEOUT");
128
- }
129
- throw new TeAgentApiError(`\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF1A${err?.message ?? err}`, 0, "NETWORK_ERROR");
130
- } finally {
131
- clearTimeout(timer);
132
- }
133
- }
134
- function signRequest(method, path, rawBody) {
135
- const cred = loadTeAgentCredentials();
136
- const { url: baseUrl, sandboxId, sandboxSecretKey } = cred.mainApp;
137
- const headers = {
138
- "X-Sandbox-Id": sandboxId,
139
- "X-Sandbox-Secret-Key": sandboxSecretKey
140
- };
141
- if (method === "POST" || method === "PATCH") {
142
- headers["Content-Type"] = "application/json";
143
- }
144
- return {
145
- url: `${baseUrl.replace(/\/$/, "")}${path}`,
146
- headers,
147
- rawBody
148
- };
149
- }
150
- async function parseResponse(response, defaultErrorPrefix) {
151
- const text = await response.text();
152
- let parsed = void 0;
153
- if (text) {
154
- try {
155
- parsed = JSON.parse(text);
156
- } catch {
157
- parsed = text;
158
- }
159
- }
160
- if (!response.ok) {
161
- const message = typeof parsed === "object" && parsed && typeof parsed.error === "string" ? parsed.error : `${defaultErrorPrefix} ${response.status}`;
162
- const code = typeof parsed === "object" && parsed && typeof parsed.code === "string" ? parsed.code : void 0;
163
- throw new TeAgentApiError(message, response.status, code, parsed);
164
- }
165
- return parsed;
166
- }
167
- async function postToMainApp(path, body) {
168
- const rawBody = JSON.stringify(body);
169
- const signed = signRequest("POST", path, rawBody);
170
- const response = await fetchWithTimeout(signed.url, {
171
- method: "POST",
172
- headers: signed.headers,
173
- body: signed.rawBody
174
- });
175
- return parseResponse(response, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
176
- }
177
- async function getFromMainApp(path) {
178
- const signed = signRequest("GET", path, "");
179
- const response = await fetchWithTimeout(signed.url, {
180
- method: "GET",
181
- headers: signed.headers
182
- });
183
- return parseResponse(response, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
184
- }
185
- async function getSandboxModels(currentModelId) {
186
- const qs = currentModelId ? `?current=${encodeURIComponent(currentModelId)}` : "";
187
- const data = await getFromMainApp(`/api/sandbox/models${qs}`);
188
- return Array.isArray(data?.models) ? data.models : [];
189
- }
190
- async function postSandboxModelSelection(args) {
191
- return postToMainApp("/api/sandbox/models/select", args);
192
- }
193
- async function getSandboxSyncPullCandidates(args) {
194
- const qs = new URLSearchParams({
195
- workspacePath: args.workspacePath,
196
- kind: args.kind
197
- });
198
- return getFromMainApp(
199
- `/api/sandbox/sync/pull/candidates?${qs.toString()}`
200
- );
201
- }
202
- async function postSandboxSyncPull(args) {
203
- return postToMainApp("/api/sandbox/sync/pull", {
204
- workspacePath: args.workspacePath,
205
- kind: args.kind,
206
- skills: args.skills,
207
- mcp: args.mcp,
208
- mode: "merge",
209
- ifUnmodifiedSince: args.ifUnmodifiedSince
210
- });
211
- }
212
- async function deleteFromMainApp(path) {
213
- const signed = signRequest("DELETE", path, "");
214
- const response = await fetchWithTimeout(signed.url, {
215
- method: "DELETE",
216
- headers: signed.headers
217
- });
218
- return parseResponse(response, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
219
- }
220
- async function patchToMainApp(path, body) {
221
- const rawBody = JSON.stringify(body);
222
- const signed = signRequest("PATCH", path, rawBody);
223
- const response = await fetchWithTimeout(signed.url, {
224
- method: "PATCH",
225
- headers: signed.headers,
226
- body: signed.rawBody
227
- });
228
- return parseResponse(response, "\u4E3B\u5E94\u7528\u8FD4\u56DE");
229
- }
230
- async function uploadToMainApp(path, formData) {
231
- const cred = loadTeAgentCredentials();
232
- const baseUrl = cred.mainApp.url.replace(/\/$/, "");
233
- const url = `${baseUrl}${path}`;
234
- const response = await fetchWithTimeout(
235
- url,
236
- {
237
- method: "POST",
238
- headers: {
239
- "X-Sandbox-Id": cred.mainApp.sandboxId,
240
- "X-Sandbox-Secret-Key": cred.mainApp.sandboxSecretKey
241
- },
242
- body: formData
243
- },
244
- UPLOAD_TIMEOUT_MS
245
- );
246
- return parseResponse(response, "\u4E0A\u4F20\u5931\u8D25");
247
- }
248
-
249
- export {
250
- TeAgentCredentialsError,
251
- getClaudeConfigDir,
252
- TeAgentApiError,
253
- postToMainApp,
254
- getFromMainApp,
255
- getSandboxModels,
256
- postSandboxModelSelection,
257
- getSandboxSyncPullCandidates,
258
- postSandboxSyncPull,
259
- deleteFromMainApp,
260
- patchToMainApp,
261
- uploadToMainApp
262
- };
@@ -1,258 +0,0 @@
1
- import {
2
- clearToken,
3
- getAuthStatus,
4
- getToken,
5
- loadToken,
6
- validateToken
7
- } from "./chunk-SRRUNQIM.js";
8
- import {
9
- addHost,
10
- listHosts,
11
- removeHost,
12
- setActiveHost,
13
- updateHostLabel
14
- } from "./chunk-BI5ZVD6T.js";
15
- import "./chunk-MNHE6SSI.js";
16
-
17
- // src/commands/config.ts
18
- import * as readline from "readline";
19
- function registerConfig(program) {
20
- program.command("config").description("Interactive AE host configuration manager").action(async () => {
21
- await runConfigUI(program);
22
- });
23
- }
24
- async function runConfigUI(program) {
25
- const hosts = listHosts();
26
- if (hosts.length === 0) {
27
- process.stderr.write("\x1B[1m[ae-cli] No AE hosts configured. Let's add one.\x1B[0m\n\n");
28
- const newHost = await promptNewHost();
29
- if (!newHost) {
30
- process.stderr.write("Cancelled.\n");
31
- return;
32
- }
33
- addHost(newHost.url, newHost.label);
34
- setActiveHost(newHost.url);
35
- process.stderr.write(`
36
- \x1B[32m\u2713\x1B[0m Added and activated: \x1B[1m${newHost.label}\x1B[0m ${newHost.url}
37
- `);
38
- await ensureAuth(newHost.url);
39
- return;
40
- }
41
- await hostManagerLoop(program);
42
- }
43
- async function hostManagerLoop(program) {
44
- while (true) {
45
- const hosts = listHosts();
46
- const items = hosts.map((h) => ({
47
- display: formatHostLine(h),
48
- type: "host",
49
- url: h.url,
50
- label: h.label,
51
- active: h.active
52
- }));
53
- items.push({ display: "\x1B[2m + Add new host...\x1B[0m", type: "add", url: "", label: "", active: false });
54
- const activeIdx = items.findIndex((i) => i.active);
55
- process.stderr.write("\n\x1B[1mTE Host Manager\x1B[0m (\u2191\u2193 select \xB7 Enter switch \xB7 e edit label \xB7 d delete \xB7 a add \xB7 q quit)\n\n");
56
- const result = await interactiveHostSelect(items, activeIdx >= 0 ? activeIdx : 0);
57
- if (result.action === "quit" || result.action === "cancel") {
58
- break;
59
- }
60
- const item = items[result.index];
61
- if (result.action === "select") {
62
- if (item.type === "add") {
63
- await handleAddHost();
64
- } else {
65
- setActiveHost(item.url);
66
- process.stderr.write(`
67
- \x1B[32m\u2713\x1B[0m Switched to: \x1B[1m${item.label}\x1B[0m ${item.url}
68
- `);
69
- await ensureAuth(item.url);
70
- break;
71
- }
72
- } else if (result.action === "edit" && item.type === "host") {
73
- await handleEditLabel(item.url, item.label);
74
- } else if (result.action === "delete" && item.type === "host") {
75
- await handleDeleteHost(item.url, item.label, item.active);
76
- } else if (result.action === "add") {
77
- await handleAddHost();
78
- }
79
- }
80
- }
81
- function formatHostLine(h) {
82
- const marker = h.active ? "\x1B[32m\u25CF\x1B[0m" : "\x1B[2m\u25CB\x1B[0m";
83
- const labelText = h.active ? `\x1B[1;32m${h.label}\x1B[0m` : `\x1B[1m${h.label}\x1B[0m`;
84
- const authInfo = getAuthStatus(h.url);
85
- const authBadge = authInfo.authenticated ? `\x1B[32m\u2713\x1B[0m` : `\x1B[31m\u2717\x1B[0m`;
86
- return `${marker} ${labelText} ${h.url} ${authBadge}`;
87
- }
88
- async function handleAddHost() {
89
- const newHost = await promptNewHost();
90
- if (!newHost) {
91
- process.stderr.write("Cancelled.\n");
92
- return;
93
- }
94
- addHost(newHost.url, newHost.label);
95
- setActiveHost(newHost.url);
96
- process.stderr.write(`
97
- \x1B[32m\u2713\x1B[0m Added and activated: \x1B[1m${newHost.label}\x1B[0m ${newHost.url}
98
- `);
99
- await ensureAuth(newHost.url);
100
- }
101
- async function handleEditLabel(url, currentLabel) {
102
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
103
- const newLabel = await new Promise(
104
- (resolve) => rl.question(`
105
- New label [${currentLabel}]: `, (a) => {
106
- rl.close();
107
- resolve(a.trim() || currentLabel);
108
- })
109
- );
110
- if (newLabel !== currentLabel) {
111
- updateHostLabel(url, newLabel);
112
- process.stderr.write(`\x1B[32m\u2713\x1B[0m Label updated: ${newLabel}
113
- `);
114
- }
115
- }
116
- async function handleDeleteHost(url, label, isActive) {
117
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
118
- const answer = await new Promise(
119
- (resolve) => rl.question(`
120
- Delete \x1B[1m${label}\x1B[0m (${url})? [y/N]: `, (a) => {
121
- rl.close();
122
- resolve(a.trim().toLowerCase());
123
- })
124
- );
125
- if (answer === "y" || answer === "yes") {
126
- removeHost(url);
127
- process.stderr.write(`\x1B[32m\u2713\x1B[0m Deleted: ${label}
128
- `);
129
- if (isActive) {
130
- const remaining = listHosts();
131
- if (remaining.length > 0) {
132
- process.stderr.write(` Active host switched to: ${remaining[0].label}
133
- `);
134
- } else {
135
- process.stderr.write(" No hosts remaining. Run ae-cli config to add one.\n");
136
- }
137
- }
138
- }
139
- }
140
- async function ensureAuth(hostUrl) {
141
- const status = getAuthStatus(hostUrl);
142
- if (status.authenticated) {
143
- const cached = loadToken(hostUrl);
144
- if (cached && cached.token) {
145
- process.stderr.write(`\x1B[2m[ae-cli] Validating token...\x1B[0m
146
- `);
147
- const isValid = await validateToken(cached.token, hostUrl);
148
- if (isValid) {
149
- process.stderr.write(`\x1B[32m\u2713\x1B[0m Token valid for ${hostUrl}
150
- `);
151
- return;
152
- } else {
153
- clearToken(hostUrl);
154
- process.stderr.write(`\x1B[33m!\x1B[0m Token expired or invalid. Re-authenticating...
155
- `);
156
- }
157
- }
158
- }
159
- process.stderr.write(`
160
- \x1B[33m!\x1B[0m No valid token for ${hostUrl}. Starting login...
161
- `);
162
- try {
163
- await getToken(hostUrl);
164
- process.stderr.write(`\x1B[32m\u2713\x1B[0m Authenticated to ${hostUrl}
165
- `);
166
- } catch (err) {
167
- process.stderr.write(`\x1B[31m\u2717\x1B[0m Auth failed: ${err.message}
168
- `);
169
- process.stderr.write(` You can set token manually: ae-cli auth set-token <token>
170
- `);
171
- }
172
- }
173
- async function promptNewHost() {
174
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
175
- const ask = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
176
- const url = await ask("AE host URL (e.g., https://ta.thinkingdata.cn): ");
177
- if (!url) {
178
- rl.close();
179
- return null;
180
- }
181
- const label = await ask("Label: ");
182
- rl.close();
183
- if (!label) return null;
184
- return { url: normalizeUrl(url), label };
185
- }
186
- function normalizeUrl(url) {
187
- if (!url.startsWith("http://") && !url.startsWith("https://")) {
188
- url = `https://${url}`;
189
- }
190
- return url.replace(/\/$/, "");
191
- }
192
- function interactiveHostSelect(items, initialIndex) {
193
- return new Promise((resolve) => {
194
- let cursor = initialIndex;
195
- const stdin = process.stdin;
196
- const stderr = process.stderr;
197
- let renderCount = 0;
198
- stderr.write("\x1B[?25l");
199
- function render() {
200
- if (renderCount > 0) {
201
- stderr.write(`\x1B[${items.length}A`);
202
- }
203
- for (let i = 0; i < items.length; i++) {
204
- const pointer = i === cursor ? "\x1B[36m\u276F\x1B[0m" : " ";
205
- stderr.write(`${pointer} ${items[i].display}\x1B[K
206
- `);
207
- }
208
- renderCount++;
209
- }
210
- render();
211
- if (!stdin.isTTY) {
212
- stderr.write("\x1B[?25h");
213
- resolve({ action: "select", index: initialIndex });
214
- return;
215
- }
216
- stdin.setRawMode(true);
217
- stdin.resume();
218
- stdin.setEncoding("utf8");
219
- function cleanup() {
220
- stdin.setRawMode(false);
221
- stdin.pause();
222
- stdin.removeListener("data", onData);
223
- stderr.write("\x1B[?25h");
224
- }
225
- function onData(key) {
226
- if (key === "\x1B[A" || key === "k") {
227
- cursor = (cursor - 1 + items.length) % items.length;
228
- render();
229
- } else if (key === "\x1B[B" || key === "j") {
230
- cursor = (cursor + 1) % items.length;
231
- render();
232
- } else if (key === "\r" || key === "\n") {
233
- cleanup();
234
- resolve({ action: "select", index: cursor });
235
- } else if (key === "e" || key === "E") {
236
- if (items[cursor].type === "host") {
237
- cleanup();
238
- resolve({ action: "edit", index: cursor });
239
- }
240
- } else if (key === "d" || key === "D") {
241
- if (items[cursor].type === "host") {
242
- cleanup();
243
- resolve({ action: "delete", index: cursor });
244
- }
245
- } else if (key === "a" || key === "A") {
246
- cleanup();
247
- resolve({ action: "add", index: cursor });
248
- } else if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
249
- cleanup();
250
- resolve({ action: "quit", index: cursor });
251
- }
252
- }
253
- stdin.on("data", onData);
254
- });
255
- }
256
- export {
257
- registerConfig
258
- };