@thinkingai/ae-cli 1.0.22 → 1.0.27
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 +39 -1
- package/README.zh.md +40 -1
- package/dist/{auth-YM7OI23X.js → auth-TXFJHPXU.js} +3 -2
- package/dist/{auth-5S7SPPEJ.js → auth-W2JZ3DKA.js} +11 -4
- package/dist/{chunk-MPFTXJFG.js → chunk-2NGWYMLB.js} +14 -2
- package/dist/chunk-6T7245YE.js +478 -0
- package/dist/{chunk-KM57HI5B.js → chunk-B4UL2VIJ.js} +7 -1
- package/dist/{chunk-TMMUBSKW.js → chunk-BI5ZVD6T.js} +8 -1
- package/dist/chunk-MNHE6SSI.js +79 -0
- package/dist/chunk-MWWYGZ76.js +130 -0
- package/dist/{chunk-24ZKQWG2.js → chunk-SRRUNQIM.js} +51 -4
- package/dist/chunk-TG64AQV4.js +262 -0
- package/dist/{chunk-NBFTPIAH.js → chunk-VT6VC4PA.js} +15 -4
- package/dist/{client-7S23DVHH.js → client-IU2E5IOL.js} +6 -3
- package/dist/{config-RVUESJRF.js → config-WH3R3IRY.js} +3 -2
- package/dist/index.js +195 -20
- package/dist/model-CC7U5XOJ.js +131 -0
- package/dist/{raw-5SYAUCJQ.js → raw-TUHZQ4UB.js} +5 -4
- package/dist/sync-EVEDS7YE.js +383 -0
- package/dist/te-agent-FLTDYV3L.js +522 -0
- package/dist/{te-analysis-RQST6AT3.js → te-analysis-CMXADIJM.js} +101 -12
- package/dist/{te-audience-TJ74UJI3.js → te-audience-LPZFFSXM.js} +4 -3
- package/dist/{te-common-W5URM2SH.js → te-common-BXQFKTB3.js} +4 -3
- package/dist/{te-community-YRV2VAD4.js → te-community-K5S3VOZY.js} +4 -3
- package/dist/{te-dataops-ZPH72BCK.js → te-dataops-567IMCQG.js} +4 -3
- package/dist/{te-engage-57UKFV74.js → te-engage-TBUTGW5F.js} +105 -49
- package/dist/{te-kb-GD7SJRYB.js → te-kb-XHVBWP5E.js} +227 -38
- package/dist/{te-meta-25SLZFXJ.js → te-meta-NQ4U3VJW.js} +25 -4
- package/dist/te-team-556APRIU.js +529 -0
- package/package.json +6 -1
- package/skills/ae-agent/SKILL.md +133 -0
- package/skills/ae-analysis/references/create_entity.md +39 -0
- package/skills/ae-analysis/references/create_space.md +34 -0
- 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/query_adhoc.md +3 -2
- package/skills/ae-analysis/references/query_entity_details.md +1 -1
- package/skills/ae-engage/SKILL.md +25 -2
- package/skills/ae-engage/references/build-task-save-guide.md +283 -0
- package/skills/ae-engage/references/save-task.md +304 -0
- package/skills/ae-kb/SKILL.md +283 -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
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadMcpTokenStore
|
|
3
|
+
} from "./chunk-2NGWYMLB.js";
|
|
4
|
+
import {
|
|
5
|
+
forceMigrateFromFallback,
|
|
6
|
+
safeJsonParse
|
|
7
|
+
} from "./chunk-BI5ZVD6T.js";
|
|
8
|
+
import {
|
|
9
|
+
logger
|
|
10
|
+
} from "./chunk-MNHE6SSI.js";
|
|
11
|
+
|
|
12
|
+
// src/core/mcp-access.ts
|
|
13
|
+
function buildUrl(host, path, params = {}) {
|
|
14
|
+
const base = host.replace(/\/$/, "");
|
|
15
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
16
|
+
const url = new URL(`${base}${p}`);
|
|
17
|
+
for (const [key, value] of Object.entries(params)) {
|
|
18
|
+
if (value !== void 0 && value !== null) {
|
|
19
|
+
url.searchParams.set(key, String(value));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return url.toString();
|
|
23
|
+
}
|
|
24
|
+
function getMcpTokenForHost(host) {
|
|
25
|
+
const store = loadMcpTokenStore();
|
|
26
|
+
const normalizedHost = host.replace(/\/+$/, "");
|
|
27
|
+
if (store[host]) return store[host];
|
|
28
|
+
if (store[normalizedHost]) return store[normalizedHost];
|
|
29
|
+
for (const [key, token] of Object.entries(store)) {
|
|
30
|
+
if (key.replace(/\/+$/, "") === normalizedHost) {
|
|
31
|
+
return token;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
function getTokenFromStore(store, host) {
|
|
37
|
+
const normalizedHost = host.replace(/\/+$/, "");
|
|
38
|
+
if (store[host]) return store[host];
|
|
39
|
+
if (store[normalizedHost]) return store[normalizedHost];
|
|
40
|
+
for (const [key, token] of Object.entries(store)) {
|
|
41
|
+
if (key.replace(/\/+$/, "") === normalizedHost) {
|
|
42
|
+
return token;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
function refreshMcpTokenFromFallback(host) {
|
|
48
|
+
logger.warn(`KB MCP request failed for ${host}, trying fallback`);
|
|
49
|
+
const migrated = forceMigrateFromFallback();
|
|
50
|
+
const token = migrated ? getTokenFromStore(migrated, host) : void 0;
|
|
51
|
+
if (token) {
|
|
52
|
+
logger.info(`KB MCP token refreshed from fallback for ${host}`);
|
|
53
|
+
process.stderr.write(`[ae-cli] MCP token refreshed from fallback for ${host}
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
return token;
|
|
57
|
+
}
|
|
58
|
+
function isMcpAuthFailure(resp, data) {
|
|
59
|
+
return !resp.ok || data.return_code === -1001;
|
|
60
|
+
}
|
|
61
|
+
function parseKbResponse(resp, text) {
|
|
62
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
63
|
+
throw new Error(`KB MCP token auth failed: HTTP ${resp.status} ${resp.statusText}`);
|
|
64
|
+
}
|
|
65
|
+
const data = safeJsonParse(text);
|
|
66
|
+
if (data.return_code === -1001) {
|
|
67
|
+
throw new Error(`KB MCP token auth failed: ${data.return_message || "unauthorized"} (code: ${data.return_code})`);
|
|
68
|
+
}
|
|
69
|
+
if (data.return_code !== 0 && data.return_code !== void 0) {
|
|
70
|
+
throw new Error(`AE API error: ${data.return_message || "unknown"} (code: ${data.return_code})`);
|
|
71
|
+
}
|
|
72
|
+
return data.data !== void 0 ? data.data : data;
|
|
73
|
+
}
|
|
74
|
+
async function fetchWithMcpToken(host, input, init, mcpToken) {
|
|
75
|
+
const headers = new Headers(init.headers);
|
|
76
|
+
headers.set("mcp-token", mcpToken);
|
|
77
|
+
const resp = await fetch(input, { ...init, headers });
|
|
78
|
+
const text = await resp.text();
|
|
79
|
+
if (!resp.ok) {
|
|
80
|
+
const refreshedToken = refreshMcpTokenFromFallback(host);
|
|
81
|
+
if (refreshedToken) {
|
|
82
|
+
headers.set("mcp-token", refreshedToken);
|
|
83
|
+
const retryResp = await fetch(input, { ...init, headers });
|
|
84
|
+
return parseKbResponse(retryResp, await retryResp.text());
|
|
85
|
+
}
|
|
86
|
+
return parseKbResponse(resp, text);
|
|
87
|
+
}
|
|
88
|
+
const data = safeJsonParse(text);
|
|
89
|
+
if (isMcpAuthFailure(resp, data)) {
|
|
90
|
+
const refreshedToken = refreshMcpTokenFromFallback(host);
|
|
91
|
+
if (refreshedToken) {
|
|
92
|
+
headers.set("mcp-token", refreshedToken);
|
|
93
|
+
const retryResp = await fetch(input, { ...init, headers });
|
|
94
|
+
return parseKbResponse(retryResp, await retryResp.text());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return parseKbResponse(resp, text);
|
|
98
|
+
}
|
|
99
|
+
async function kbApi(ctx, method, path, params = {}, body) {
|
|
100
|
+
const host = ctx.host();
|
|
101
|
+
const mcpToken = getMcpTokenForHost(host);
|
|
102
|
+
if (!mcpToken) {
|
|
103
|
+
return ctx.api(method, path, params, body);
|
|
104
|
+
}
|
|
105
|
+
const upperMethod = method.toUpperCase();
|
|
106
|
+
return fetchWithMcpToken(host, buildUrl(host, path, params), {
|
|
107
|
+
method: upperMethod,
|
|
108
|
+
headers: {
|
|
109
|
+
"Content-Type": "application/json"
|
|
110
|
+
},
|
|
111
|
+
body: upperMethod === "GET" ? void 0 : JSON.stringify(body ?? {})
|
|
112
|
+
}, mcpToken);
|
|
113
|
+
}
|
|
114
|
+
async function kbUpload(ctx, path, form, params = {}) {
|
|
115
|
+
const host = ctx.host();
|
|
116
|
+
const mcpToken = getMcpTokenForHost(host);
|
|
117
|
+
if (!mcpToken) {
|
|
118
|
+
const { httpUpload } = await import("./client-IU2E5IOL.js");
|
|
119
|
+
return httpUpload(path, form, params, host);
|
|
120
|
+
}
|
|
121
|
+
return fetchWithMcpToken(host, buildUrl(host, path, params), {
|
|
122
|
+
method: "POST",
|
|
123
|
+
body: form
|
|
124
|
+
}, mcpToken);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
kbApi,
|
|
129
|
+
kbUpload
|
|
130
|
+
};
|
|
@@ -4,13 +4,17 @@ import {
|
|
|
4
4
|
getConfigDir,
|
|
5
5
|
safeJsonParse,
|
|
6
6
|
safeReadJsonFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BI5ZVD6T.js";
|
|
8
|
+
import {
|
|
9
|
+
logger
|
|
10
|
+
} from "./chunk-MNHE6SSI.js";
|
|
8
11
|
|
|
9
12
|
// src/core/auth.ts
|
|
10
13
|
import fs from "fs";
|
|
11
14
|
import path from "path";
|
|
12
15
|
import { execFileSync } from "child_process";
|
|
13
16
|
var TOKENS_FILE = path.join(getConfigDir(), "tokens.json");
|
|
17
|
+
var MCP_TOKENS_FILE = path.join(getConfigDir(), "mcp-tokens.json");
|
|
14
18
|
var LEGACY_DIR = path.join(process.env.HOME || "", ".te-mcp");
|
|
15
19
|
var TOKEN_TTL_MS = 20 * 60 * 60 * 1e3;
|
|
16
20
|
var OSASCRIPT_POLL_INTERVAL_MS = 2e3;
|
|
@@ -90,6 +94,7 @@ function saveToken(token, hostUrl) {
|
|
|
90
94
|
const tokens = loadAllTokens();
|
|
91
95
|
tokens[hostUrl] = { token, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
92
96
|
saveAllTokens(tokens);
|
|
97
|
+
logger.info(`Token saved for ${hostUrl}`);
|
|
93
98
|
}
|
|
94
99
|
function clearToken(hostUrl) {
|
|
95
100
|
const tokens = loadAllTokens();
|
|
@@ -111,6 +116,23 @@ function getAuthStatus(hostUrl) {
|
|
|
111
116
|
}
|
|
112
117
|
return { authenticated: false, host: hostUrl };
|
|
113
118
|
}
|
|
119
|
+
function getCachedMcpToken(hostUrl) {
|
|
120
|
+
try {
|
|
121
|
+
if (!fs.existsSync(MCP_TOKENS_FILE)) return void 0;
|
|
122
|
+
const store = safeReadJsonFile(MCP_TOKENS_FILE);
|
|
123
|
+
const normalizedHost = hostUrl.replace(/\/+$/, "");
|
|
124
|
+
if (store[hostUrl]) return store[hostUrl];
|
|
125
|
+
if (store[normalizedHost]) return store[normalizedHost];
|
|
126
|
+
for (const [key, token] of Object.entries(store)) {
|
|
127
|
+
if (key.replace(/\/+$/, "") === normalizedHost) {
|
|
128
|
+
return token;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return void 0;
|
|
132
|
+
} catch {
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
114
136
|
function extractTokenViaOsascript(hostUrl) {
|
|
115
137
|
if (process.platform !== "darwin") return { token: null, error: "not_mac" };
|
|
116
138
|
const hostname = extractHostname(hostUrl);
|
|
@@ -172,6 +194,7 @@ function extractTokenFromAllTabs() {
|
|
|
172
194
|
}
|
|
173
195
|
}
|
|
174
196
|
async function requestTokenViaOsascript(hostUrl) {
|
|
197
|
+
logger.info(`Opening Chrome to ${hostUrl} for token extraction`);
|
|
175
198
|
process.stderr.write(`[ae-cli] No AE tab found in Chrome. Opening ${hostUrl} ...
|
|
176
199
|
`);
|
|
177
200
|
process.stderr.write(`[ae-cli] Please login, then your token will be captured automatically.
|
|
@@ -189,24 +212,36 @@ async function requestTokenViaOsascript(hostUrl) {
|
|
|
189
212
|
];
|
|
190
213
|
execFileSync("osascript", openScript.flatMap((line) => ["-e", line]), { timeout: 5e3 });
|
|
191
214
|
} catch {
|
|
215
|
+
logger.warn(`Failed to open Chrome, user may need to open ${hostUrl} manually`);
|
|
192
216
|
process.stderr.write(`[ae-cli] Could not open browser. Please open ${hostUrl} in Chrome manually.
|
|
193
217
|
`);
|
|
194
218
|
}
|
|
195
219
|
const deadline = Date.now() + OSASCRIPT_POLL_TIMEOUT_MS;
|
|
220
|
+
let pollCount = 0;
|
|
196
221
|
while (Date.now() < deadline) {
|
|
197
222
|
await new Promise((r) => setTimeout(r, OSASCRIPT_POLL_INTERVAL_MS));
|
|
223
|
+
pollCount++;
|
|
198
224
|
let result = extractTokenViaOsascript(hostUrl);
|
|
199
225
|
if (result.error === "no_tab") {
|
|
200
226
|
const fallback = extractTokenFromAllTabs();
|
|
201
|
-
if (fallback.token)
|
|
227
|
+
if (fallback.token) {
|
|
228
|
+
logger.info("Token captured via all-tabs fallback search");
|
|
229
|
+
result = fallback;
|
|
230
|
+
}
|
|
202
231
|
}
|
|
203
232
|
if (result.token) {
|
|
233
|
+
saveToken(result.token, hostUrl);
|
|
234
|
+
logger.info(`Token captured after ${pollCount} poll(s)`);
|
|
204
235
|
process.stderr.write(`[ae-cli] Token captured from Chrome for ${hostUrl}.
|
|
205
236
|
`);
|
|
206
237
|
return result.token;
|
|
207
238
|
}
|
|
208
|
-
if (result.error === "no_js_permission")
|
|
239
|
+
if (result.error === "no_js_permission") {
|
|
240
|
+
logger.warn("Chrome JS permission denied during polling");
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
209
243
|
}
|
|
244
|
+
logger.warn(`Token polling timed out after ${OSASCRIPT_POLL_TIMEOUT_MS / 1e3}s (${pollCount} polls)`);
|
|
210
245
|
process.stderr.write(`[ae-cli] Polling timed out after ${OSASCRIPT_POLL_TIMEOUT_MS / 1e3}s.
|
|
211
246
|
`);
|
|
212
247
|
return null;
|
|
@@ -219,12 +254,24 @@ Run: ae-cli config set-host`
|
|
|
219
254
|
);
|
|
220
255
|
}
|
|
221
256
|
if (process.env.TE_TOKEN) {
|
|
257
|
+
logger.info("Using token from env:TE_TOKEN");
|
|
222
258
|
return process.env.TE_TOKEN;
|
|
223
259
|
}
|
|
224
260
|
const cached = loadToken(hostUrl);
|
|
225
|
-
if (cached && cached.token)
|
|
261
|
+
if (cached && cached.token) {
|
|
262
|
+
logger.info(`Using cached token for ${hostUrl}`);
|
|
263
|
+
return cached.token;
|
|
264
|
+
}
|
|
265
|
+
if (getCachedMcpToken(hostUrl)) {
|
|
266
|
+
logger.info(`MCP token exists for ${hostUrl}; skipping browser token extraction`);
|
|
267
|
+
throw new Error(
|
|
268
|
+
`MCP token already exists for ${hostUrl}; skipped browser login.
|
|
269
|
+
Use an MCP-token aware command, or run: ae-cli auth set-token <token>`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
226
272
|
const { token: osascriptToken, error } = extractTokenViaOsascript(hostUrl);
|
|
227
273
|
if (error === "no_js_permission") {
|
|
274
|
+
logger.warn("Chrome JS Apple Events not enabled");
|
|
228
275
|
throw new Error(
|
|
229
276
|
`Chrome JavaScript from Apple Events is not enabled.
|
|
230
277
|
Enable it: Chrome menu \u2192 View \u2192 Developer \u2192 Allow JavaScript from Apple Events`
|
|
@@ -0,0 +1,262 @@
|
|
|
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
|
+
};
|
|
@@ -2,10 +2,13 @@ import {
|
|
|
2
2
|
clearToken,
|
|
3
3
|
getToken,
|
|
4
4
|
resolveHost
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SRRUNQIM.js";
|
|
6
6
|
import {
|
|
7
7
|
safeJsonParse
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BI5ZVD6T.js";
|
|
9
|
+
import {
|
|
10
|
+
logger
|
|
11
|
+
} from "./chunk-MNHE6SSI.js";
|
|
9
12
|
|
|
10
13
|
// src/core/client.ts
|
|
11
14
|
import WebSocket from "ws";
|
|
@@ -39,11 +42,13 @@ async function request(method, modulePath, params = {}, body = null, retry = tru
|
|
|
39
42
|
const options = { method, headers };
|
|
40
43
|
if (body && method !== "GET") options.body = JSON.stringify(body);
|
|
41
44
|
const resp = await fetch(url, options);
|
|
45
|
+
const text = await resp.text();
|
|
46
|
+
const data = safeJsonParse(text);
|
|
47
|
+
logger.api(method, url, resp.status, body, data);
|
|
42
48
|
if ((resp.status === 401 || resp.status === 403) && retry) {
|
|
43
49
|
clearToken(resolvedHost);
|
|
44
50
|
return request(method, modulePath, params, body, false, resolvedHost);
|
|
45
51
|
}
|
|
46
|
-
const data = safeJsonParse(await resp.text());
|
|
47
52
|
if (data.return_code === -1001 && retry) {
|
|
48
53
|
clearToken(resolvedHost);
|
|
49
54
|
return request(method, modulePath, params, body, false, resolvedHost);
|
|
@@ -59,6 +64,9 @@ async function httpGet(modulePath, params = {}, hostUrl) {
|
|
|
59
64
|
async function httpPost(modulePath, params = {}, body, hostUrl) {
|
|
60
65
|
return request("POST", modulePath, params, body ?? {}, true, hostUrl);
|
|
61
66
|
}
|
|
67
|
+
async function httpRequest(method, modulePath, params = {}, body, hostUrl) {
|
|
68
|
+
return request(method.toUpperCase(), modulePath, params, body ?? {}, true, hostUrl);
|
|
69
|
+
}
|
|
62
70
|
async function httpDelete(modulePath, params = {}, body, hostUrl) {
|
|
63
71
|
return request("DELETE", modulePath, params, body ?? null, true, hostUrl);
|
|
64
72
|
}
|
|
@@ -70,11 +78,13 @@ async function uploadRequest(modulePath, form, params = {}, retry = true, hostUr
|
|
|
70
78
|
"Authorization": `bearer ${token}`
|
|
71
79
|
};
|
|
72
80
|
const resp = await fetch(url, { method: "POST", headers, body: form });
|
|
81
|
+
const text = await resp.text();
|
|
82
|
+
const data = safeJsonParse(text);
|
|
83
|
+
logger.api("POST", url, resp.status, { upload: true }, data);
|
|
73
84
|
if ((resp.status === 401 || resp.status === 403) && retry) {
|
|
74
85
|
clearToken(resolvedHost);
|
|
75
86
|
return uploadRequest(modulePath, form, params, false, resolvedHost);
|
|
76
87
|
}
|
|
77
|
-
const data = safeJsonParse(await resp.text());
|
|
78
88
|
if (data.return_code === -1001 && retry) {
|
|
79
89
|
clearToken(resolvedHost);
|
|
80
90
|
return uploadRequest(modulePath, form, params, false, resolvedHost);
|
|
@@ -170,6 +180,7 @@ async function queryReportData(projectId, reportId, qp, eventModel, options = {}
|
|
|
170
180
|
export {
|
|
171
181
|
httpGet,
|
|
172
182
|
httpPost,
|
|
183
|
+
httpRequest,
|
|
173
184
|
httpDelete,
|
|
174
185
|
httpUpload,
|
|
175
186
|
wsQuery,
|
|
@@ -2,17 +2,20 @@ 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-VT6VC4PA.js";
|
|
11
|
+
import "./chunk-SRRUNQIM.js";
|
|
12
|
+
import "./chunk-BI5ZVD6T.js";
|
|
13
|
+
import "./chunk-MNHE6SSI.js";
|
|
12
14
|
export {
|
|
13
15
|
httpDelete,
|
|
14
16
|
httpGet,
|
|
15
17
|
httpPost,
|
|
18
|
+
httpRequest,
|
|
16
19
|
httpUpload,
|
|
17
20
|
queryReportData,
|
|
18
21
|
querySql,
|
|
@@ -4,14 +4,15 @@ import {
|
|
|
4
4
|
getToken,
|
|
5
5
|
loadToken,
|
|
6
6
|
validateToken
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SRRUNQIM.js";
|
|
8
8
|
import {
|
|
9
9
|
addHost,
|
|
10
10
|
listHosts,
|
|
11
11
|
removeHost,
|
|
12
12
|
setActiveHost,
|
|
13
13
|
updateHostLabel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BI5ZVD6T.js";
|
|
15
|
+
import "./chunk-MNHE6SSI.js";
|
|
15
16
|
|
|
16
17
|
// src/commands/config.ts
|
|
17
18
|
import * as readline from "readline";
|