@thinkingai/ae-cli 6.0.41 → 6.0.44
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/dist/{auth-GBMV6TEJ.js → auth-2WTQOP77.js} +3 -3
- package/dist/{auth-NDSXE54J.js → auth-77BUFLGC.js} +57 -13
- package/dist/{capability-CETVHGXF.js → capability-ENHWPMTG.js} +12 -12
- package/dist/{capability-ZSQBMNOE.js → capability-WA37LSIR.js} +12 -12
- package/dist/{chunk-AFXA7BRK.js → chunk-4KVPKXFX.js} +5 -5
- package/dist/chunk-4SGZG4XY.js +311 -0
- package/dist/chunk-6EIJSNBD.js +8 -0
- package/dist/chunk-C4MGVGJW.js +13 -0
- package/dist/{chunk-4E3DB4MM.js → chunk-EE45RGOO.js} +7 -7
- package/dist/{chunk-WZRX4KOH.js → chunk-GT46FPXN.js} +4 -6
- package/dist/{chunk-5XUSIK27.js → chunk-ILIU36SU.js} +10 -7
- package/dist/{chunk-JHENBQ5B.js → chunk-LYVNONC4.js} +0 -35
- package/dist/{chunk-WANVG6SY.js → chunk-MGU2N3HW.js} +7 -7
- package/dist/{chunk-JUW4AJXN.js → chunk-P3FGXJTU.js} +12 -7
- package/dist/{chunk-FNZA5RZA.js → chunk-QEFCIRNJ.js} +4 -4
- package/dist/chunk-QGM4M3NI.js +37 -0
- package/dist/{chunk-J2N4PB56.js → chunk-QI524WPY.js} +4 -4
- package/dist/{chunk-VLWOLBGZ.js → chunk-UOUS37JQ.js} +149 -161
- package/dist/{chunk-AXDXJTPC.js → chunk-UW5UN47B.js} +19 -2
- package/dist/chunk-VPKZ7I72.js +509 -0
- package/dist/chunk-ZZUOD757.js +598 -0
- package/dist/{client-L2YDMHQ6.js → client-TKG4WBHN.js} +4 -5
- package/dist/{community-report-client-M2RW4MXD.js → community-report-client-FI4LNVYS.js} +3 -2
- package/dist/{config-OL2LWGBV.js → config-RE6CMGPK.js} +7 -7
- package/dist/data-integration-2MYMANJI.js +3383 -0
- package/dist/index.js +74 -40
- package/dist/local-data-upload-client-BWHSUQQK.js +167 -0
- package/dist/{memory-MUP7PPL7.js → memory-CHRU2F7W.js} +7 -6
- package/dist/{memory-U4O5PMXH.js → memory-YK33G4T7.js} +7 -6
- package/dist/{metadata-UKZDNLLQ.js → metadata-AXVHAAZG.js} +22 -18
- package/dist/{metadata-XXMJFN2M.js → metadata-GGEHHPBE.js} +22 -18
- package/dist/{model-JTUEO5M4.js → model-K3KLWIW6.js} +7 -3
- package/dist/model-NR3JHFSJ.js +139 -0
- package/dist/{sync-MOSFNBVR.js → sync-DAVKYVMW.js} +8 -6
- package/dist/sync-FCKOVWWS.js +10261 -0
- package/dist/{te-agent-IFKZDHZI.js → te-agent-4BKBODMF.js} +686 -71
- package/dist/te-agent-HLW4VTQK.js +3893 -0
- package/dist/{te-analysis-3QLLS35K.js → te-analysis-WX7LRVAV.js} +86 -63
- package/dist/{te-analysis-YSK2DBVL.js → te-analysis-YKFDBMA6.js} +86 -63
- package/dist/{te-community-HNKVTERD.js → te-community-6HPBWJUZ.js} +24 -19
- package/dist/{te-community-IWE5B7W6.js → te-community-HLC43QKH.js} +24 -20
- package/dist/{te-dataops-KXCEB4CS.js → te-dataops-EJP56W3K.js} +57 -34
- package/dist/{te-dataops-KQPYNAE3.js → te-dataops-HDRUXY4K.js} +59 -34
- package/dist/{te-engage-6RNGK5GH.js → te-engage-UBHPAJCO.js} +401 -15
- package/dist/{te-engage-IRMHTSQK.js → te-engage-WLDTS5J5.js} +401 -15
- package/dist/{te-kb-OIH3T6CS.js → te-kb-APXBWBDY.js} +6 -6
- package/dist/{te-system-AZ3URMUO.js → te-system-YARIK4S5.js} +7 -4
- package/dist/te-system-Z77IKZFN.js +2213 -0
- package/dist/{te-team-GZPU6UWA.js → te-team-EFKWYKMK.js} +7 -7
- package/dist/{update-TOBFXF2V.js → update-OGPSZM5A.js} +7 -7
- package/package.json +13 -3
- package/skills/ae-agent/SKILL.md +21 -11
- package/skills/ae-agent/references/approval-effect.md +44 -0
- package/skills/ae-agent/references/approval-request.md +46 -0
- package/skills/ae-agent/references/approval-task.md +45 -0
- package/skills/ae-agent/references/approval-type.md +32 -0
- package/skills/ae-agent/references/command_index.md +19 -0
- package/skills/ae-analysis/SKILL.md +11 -7
- package/skills/ae-analysis/references/adhoc_run.md +2 -0
- package/skills/ae-analysis/references/ai_models.md +31 -1
- package/skills/ae-analysis/references/alert_list.md +2 -3
- package/skills/ae-analysis/references/analysis_gateway_assets.md +8 -7
- package/skills/ae-analysis/references/bi_panel_list.md +2 -2
- package/skills/ae-analysis/references/command_index.md +18 -15
- package/skills/ae-analysis/references/dashboard_get.md +8 -2
- package/skills/ae-analysis/references/dashboard_list.md +2 -2
- package/skills/ae-analysis/references/dashboard_report_data_run.md +3 -1
- package/skills/ae-analysis/references/dashboard_update.md +4 -1
- package/skills/ae-analysis/references/favorite_add.md +2 -2
- package/skills/ae-analysis/references/favorite_remove.md +2 -2
- package/skills/ae-analysis/references/metric_create.md +7 -8
- package/skills/ae-analysis/references/project_space_business_filter_upsert.md +17 -0
- package/skills/ae-analysis/references/project_space_list.md +2 -2
- package/skills/ae-analysis/references/public_link_list.md +2 -2
- package/skills/ae-analysis/references/report_list.md +3 -3
- package/skills/ae-analysis/references/report_list_export.md +2 -2
- package/skills/ae-analysis/references/sql_table_list.md +3 -2
- package/skills/ae-analysis/references/user_cluster_update.md +4 -2
- package/skills/ae-analysis/references/user_tag_models.md +4 -4
- package/skills/ae-analysis/references/user_tag_update.md +4 -2
- package/skills/ae-analysis/references/virtual_property_sql_rule_update.md +3 -3
- package/skills/ae-data-integration/SKILL.md +54 -0
- package/skills/ae-data-integration/references/handoff.md +43 -0
- package/skills/ae-data-integration/references/local-analysis.md +27 -0
- package/skills/ae-data-integration/references/reuse.md +41 -0
- package/skills/ae-data-integration/references/sink-upload.md +58 -0
- package/skills/ae-data-integration/references/source-inspect.md +55 -0
- package/skills/ae-data-integration/references/sync-json-upload.md +60 -0
- package/skills/ae-data-integration/references/tracking-plan.md +35 -0
- package/skills/ae-data-integration/references/transform.md +65 -0
- package/skills/ae-data-integration/references/ue-mapping.md +142 -0
- package/skills/ae-data-integration/references/ue-routing.md +35 -0
- package/skills/ae-data-integration-helper/SKILL.md +1 -1
- package/skills/ae-dataops/SKILL.md +1 -1
- package/skills/ae-dataops/references/dataops-query.md +4 -4
- package/skills/ae-engage/SKILL.md +10 -2
- package/skills/ae-engage/references/flow-metric-user.md +2 -1
- package/skills/ae-engage/references/flow-node-metric-user.md +2 -1
- package/skills/ae-engage/references/flow-node-user.md +2 -1
- package/skills/ae-engage/references/task-indicator-user.md +104 -0
- package/skills/ae-engage/references/task-user-detail-export.md +31 -0
- package/skills/ae-generate-tracking-plan/SKILL.md +54 -3
- package/skills/ae-metadata/SKILL.md +0 -1
- package/skills/ae-metadata/references/metadata_property_dimension_table_bind_existing.md +1 -1
- package/dist/chunk-3FY3RJ26.js +0 -293
- package/dist/chunk-S5NTSDBS.js +0 -198
- package/dist/chunk-ZQKDZXDO.js +0 -317
- package/dist/cli-token-4UPER74P.js +0 -21
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// src/core/errors.ts
|
|
2
2
|
var PermissionError = class extends Error {
|
|
3
|
-
constructor(message, code) {
|
|
3
|
+
constructor(message, code, hint) {
|
|
4
4
|
super(message);
|
|
5
5
|
this.code = code;
|
|
6
|
+
this.hint = hint;
|
|
6
7
|
this.name = "PermissionError";
|
|
7
8
|
}
|
|
8
9
|
code;
|
|
10
|
+
hint;
|
|
9
11
|
};
|
|
10
12
|
var CliValidationError = class extends Error {
|
|
11
13
|
code;
|
|
@@ -45,9 +47,24 @@ var CommunityReportError = class extends Error {
|
|
|
45
47
|
this.meta = options.meta;
|
|
46
48
|
}
|
|
47
49
|
};
|
|
50
|
+
var LocalDataUploadError = class extends Error {
|
|
51
|
+
code;
|
|
52
|
+
httpStatus;
|
|
53
|
+
hint;
|
|
54
|
+
meta;
|
|
55
|
+
constructor(message, options = {}) {
|
|
56
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
57
|
+
this.name = "LocalDataUploadError";
|
|
58
|
+
this.code = options.code;
|
|
59
|
+
this.httpStatus = options.httpStatus;
|
|
60
|
+
this.hint = options.hint;
|
|
61
|
+
this.meta = options.meta;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
48
64
|
|
|
49
65
|
export {
|
|
50
66
|
PermissionError,
|
|
51
67
|
CliValidationError,
|
|
52
|
-
CommunityReportError
|
|
68
|
+
CommunityReportError,
|
|
69
|
+
LocalDataUploadError
|
|
53
70
|
};
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internalCallSourceHeaders
|
|
3
|
+
} from "./chunk-6EIJSNBD.js";
|
|
4
|
+
import {
|
|
5
|
+
clearCliToken,
|
|
6
|
+
getCliToken
|
|
7
|
+
} from "./chunk-4SGZG4XY.js";
|
|
8
|
+
import {
|
|
9
|
+
getActiveHost,
|
|
10
|
+
getSandboxRuntimeRoot
|
|
11
|
+
} from "./chunk-ZZUOD757.js";
|
|
12
|
+
import {
|
|
13
|
+
PermissionError
|
|
14
|
+
} from "./chunk-UW5UN47B.js";
|
|
15
|
+
|
|
16
|
+
// src/core/te-agent-credentials.ts
|
|
17
|
+
import { readFileSync } from "fs";
|
|
18
|
+
import { homedir } from "os";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
function getCredentialsPath() {
|
|
21
|
+
return join(process.env.HOME || homedir(), ".te-agent", "credentials.json");
|
|
22
|
+
}
|
|
23
|
+
function getPersistentEnvPath() {
|
|
24
|
+
return join(getSandboxRuntimeRoot(), ".env");
|
|
25
|
+
}
|
|
26
|
+
function parseDotEnv(raw) {
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const line of raw.split("\n")) {
|
|
29
|
+
if (/^\s*#/.test(line) || line.trim() === "") continue;
|
|
30
|
+
const match = /^\s*([^=]+)=(.*)$/.exec(line);
|
|
31
|
+
if (!match) continue;
|
|
32
|
+
const key = match[1].trim();
|
|
33
|
+
let value = match[2].trim();
|
|
34
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
35
|
+
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
36
|
+
}
|
|
37
|
+
if (value !== "") result[key] = value;
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
function readPersistentEnv() {
|
|
42
|
+
const envPath = getPersistentEnvPath();
|
|
43
|
+
try {
|
|
44
|
+
const raw = readFileSync(envPath, "utf8");
|
|
45
|
+
return parseDotEnv(raw);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err?.code === "ENOENT") return null;
|
|
48
|
+
throw new TeAgentCredentialsError(
|
|
49
|
+
`Failed to read ${envPath}: ${err?.message ?? err}`,
|
|
50
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var TeAgentCredentialsError = class extends Error {
|
|
55
|
+
constructor(message, hint) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.hint = hint;
|
|
58
|
+
this.name = "TeAgentCredentialsError";
|
|
59
|
+
}
|
|
60
|
+
hint;
|
|
61
|
+
};
|
|
62
|
+
function readLegacyCredentials() {
|
|
63
|
+
const credPath = getCredentialsPath();
|
|
64
|
+
try {
|
|
65
|
+
const raw = readFileSync(credPath, "utf8");
|
|
66
|
+
const parsed = JSON.parse(raw);
|
|
67
|
+
const main = parsed?.mainApp;
|
|
68
|
+
return main && typeof main === "object" ? main : null;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (err?.code === "ENOENT") return null;
|
|
71
|
+
if (err instanceof SyntaxError) {
|
|
72
|
+
throw new TeAgentCredentialsError(
|
|
73
|
+
`Failed to parse ${credPath}: ${err.message}`,
|
|
74
|
+
"The credentials file may be corrupted; alternatively inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
throw new TeAgentCredentialsError(
|
|
78
|
+
`Failed to read ${credPath}: ${err?.message ?? err}`,
|
|
79
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function tryLoadTeAgentSandboxCredentials() {
|
|
84
|
+
const legacy = readLegacyCredentials();
|
|
85
|
+
const persistent = readPersistentEnv();
|
|
86
|
+
const url = process.env.TE_CLAUDE_BASE_URL || persistent?.TE_CLAUDE_BASE_URL || legacy?.url;
|
|
87
|
+
if (typeof url !== "string" || !url) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const sandboxId = process.env.SANDBOX_ID || persistent?.SANDBOX_ID || legacy?.sandboxId || null;
|
|
91
|
+
const sandboxSecretKey = process.env.SECRET_KEY || process.env.SANDBOX_SECRET_KEY || persistent?.SECRET_KEY || persistent?.SANDBOX_SECRET_KEY || legacy?.sandboxSecretKey || legacy?.secretKey || null;
|
|
92
|
+
return {
|
|
93
|
+
url,
|
|
94
|
+
sandboxId: typeof sandboxId === "string" ? sandboxId : null,
|
|
95
|
+
sandboxSecretKey: typeof sandboxSecretKey === "string" ? sandboxSecretKey : null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function getClaudeConfigDir() {
|
|
99
|
+
const fromEnv = process.env.CLAUDE_CONFIG_DIR;
|
|
100
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0) {
|
|
101
|
+
return fromEnv;
|
|
102
|
+
}
|
|
103
|
+
return join(homedir(), ".claude");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/core/te-agent-client.ts
|
|
107
|
+
import { open, unlink } from "fs/promises";
|
|
108
|
+
import path from "path";
|
|
109
|
+
import { Readable } from "stream";
|
|
110
|
+
import { pipeline } from "stream/promises";
|
|
111
|
+
var TeAgentApiError = class extends Error {
|
|
112
|
+
constructor(message, status, code, body) {
|
|
113
|
+
super(message);
|
|
114
|
+
this.status = status;
|
|
115
|
+
this.code = code;
|
|
116
|
+
this.body = body;
|
|
117
|
+
this.name = "TeAgentApiError";
|
|
118
|
+
}
|
|
119
|
+
status;
|
|
120
|
+
code;
|
|
121
|
+
body;
|
|
122
|
+
};
|
|
123
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
124
|
+
var UPLOAD_TIMEOUT_MS = 12e4;
|
|
125
|
+
var DOWNLOAD_TIMEOUT_MS = 12e4;
|
|
126
|
+
async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
129
|
+
try {
|
|
130
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
131
|
+
} catch (err) {
|
|
132
|
+
if (err?.name === "AbortError") {
|
|
133
|
+
throw new TeAgentApiError(
|
|
134
|
+
`Request timed out (${timeoutMs}ms) for ${safeRequestOrigin(url)}`,
|
|
135
|
+
0,
|
|
136
|
+
"TIMEOUT"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
throw networkRequestError(url, err);
|
|
140
|
+
} finally {
|
|
141
|
+
clearTimeout(timer);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function safeRequestOrigin(url) {
|
|
145
|
+
try {
|
|
146
|
+
return new URL(url).origin;
|
|
147
|
+
} catch {
|
|
148
|
+
return "the configured service";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function networkRequestError(url, error) {
|
|
152
|
+
const nestedCause = error && typeof error === "object" && "cause" in error ? error.cause : void 0;
|
|
153
|
+
const root = nestedCause ?? error;
|
|
154
|
+
const detail = root && typeof root === "object" ? root : {};
|
|
155
|
+
const code = typeof detail.code === "string" ? detail.code : void 0;
|
|
156
|
+
const address = typeof detail.address === "string" ? detail.address : typeof detail.hostname === "string" ? detail.hostname : void 0;
|
|
157
|
+
const port = typeof detail.port === "number" || typeof detail.port === "string" ? String(detail.port) : void 0;
|
|
158
|
+
const endpoint = address ? `${address}${port ? `:${port}` : ""}` : void 0;
|
|
159
|
+
const cause = [code, endpoint].filter(Boolean).join(" ");
|
|
160
|
+
const suffix = cause ? ` (${cause})` : "";
|
|
161
|
+
return new TeAgentApiError(
|
|
162
|
+
`Network request failed for ${safeRequestOrigin(url)}${suffix}`,
|
|
163
|
+
0,
|
|
164
|
+
"NETWORK_ERROR"
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
function teClaudeBaseFromActiveHost(hostOverride) {
|
|
168
|
+
const override = hostOverride ? void 0 : process.env.TE_CLAUDE_BASE_URL;
|
|
169
|
+
if (override) return override.replace(/\/+$/, "");
|
|
170
|
+
const h = hostOverride || getActiveHost();
|
|
171
|
+
if (!h) return void 0;
|
|
172
|
+
const base = h.replace(/\/+$/, "");
|
|
173
|
+
const bp = process.env.TE_CLAUDE_BASE_PATH || "/agent";
|
|
174
|
+
return base.endsWith(bp) ? base : base + bp;
|
|
175
|
+
}
|
|
176
|
+
async function signRequest(method, path2, hostOverride, includeJsonContentType = true) {
|
|
177
|
+
const sandboxCred = tryLoadTeAgentSandboxCredentials();
|
|
178
|
+
if (!hostOverride && sandboxCred && sandboxCred.sandboxId && sandboxCred.sandboxSecretKey) {
|
|
179
|
+
const headers = {
|
|
180
|
+
"X-Sandbox-Id": sandboxCred.sandboxId,
|
|
181
|
+
"X-Sandbox-Secret-Key": sandboxCred.sandboxSecretKey
|
|
182
|
+
};
|
|
183
|
+
if (includeJsonContentType && (method === "POST" || method === "PATCH" || method === "PUT")) {
|
|
184
|
+
headers["Content-Type"] = "application/json";
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
url: `${sandboxCred.url.replace(/\/$/, "")}${path2}`,
|
|
188
|
+
headers,
|
|
189
|
+
authKind: "sandbox"
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
const baseUrl = hostOverride ? teClaudeBaseFromActiveHost(hostOverride) : sandboxCred?.url || teClaudeBaseFromActiveHost();
|
|
193
|
+
if (!baseUrl) {
|
|
194
|
+
throw new TeAgentCredentialsError(
|
|
195
|
+
"Cannot determine the te-claude service URL",
|
|
196
|
+
"Run ae-cli config set-host <url> to configure the service URL, or execute inside a te-agent sandbox"
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
const hostForToken = hostOverride || getActiveHost() || baseUrl;
|
|
200
|
+
const contentTypeHeader = includeJsonContentType && (method === "POST" || method === "PATCH" || method === "PUT") ? { "Content-Type": "application/json" } : {};
|
|
201
|
+
const cliToken = await getCliToken(hostForToken);
|
|
202
|
+
return {
|
|
203
|
+
url: `${baseUrl.replace(/\/$/, "")}${path2}`,
|
|
204
|
+
headers: {
|
|
205
|
+
"cli-token": cliToken,
|
|
206
|
+
...internalCallSourceHeaders(),
|
|
207
|
+
...contentTypeHeader
|
|
208
|
+
},
|
|
209
|
+
authKind: "cli-token",
|
|
210
|
+
tokenHost: hostForToken
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function fetchSignedWithRetry(options) {
|
|
214
|
+
let signed = await signRequest(
|
|
215
|
+
options.method,
|
|
216
|
+
options.path,
|
|
217
|
+
options.hostOverride,
|
|
218
|
+
options.includeJsonContentType
|
|
219
|
+
);
|
|
220
|
+
const request = (requestToSend) => fetchWithTimeout(
|
|
221
|
+
requestToSend.url,
|
|
222
|
+
{
|
|
223
|
+
method: options.method,
|
|
224
|
+
headers: requestToSend.headers,
|
|
225
|
+
body: options.body
|
|
226
|
+
},
|
|
227
|
+
options.timeoutMs
|
|
228
|
+
);
|
|
229
|
+
let response = await request(signed);
|
|
230
|
+
if (response.status === 401 && signed.authKind === "cli-token" && signed.tokenHost) {
|
|
231
|
+
clearCliToken(signed.tokenHost);
|
|
232
|
+
signed = await signRequest(
|
|
233
|
+
options.method,
|
|
234
|
+
options.path,
|
|
235
|
+
options.hostOverride,
|
|
236
|
+
options.includeJsonContentType
|
|
237
|
+
);
|
|
238
|
+
response = await request(signed);
|
|
239
|
+
}
|
|
240
|
+
return response;
|
|
241
|
+
}
|
|
242
|
+
function errorDetails(parsed, defaultErrorPrefix, status) {
|
|
243
|
+
const nested = parsed && typeof parsed === "object" && parsed.error && typeof parsed.error === "object" ? parsed.error : parsed;
|
|
244
|
+
const message = typeof parsed?.error === "string" ? parsed.error : typeof nested?.message === "string" ? nested.message : typeof parsed?.message === "string" ? parsed.message : typeof parsed?.return_message === "string" ? parsed.return_message : `${defaultErrorPrefix} ${status}`;
|
|
245
|
+
const code = typeof nested?.code === "string" ? nested.code : typeof parsed?.code === "string" ? parsed.code : void 0;
|
|
246
|
+
const hint = typeof nested?.hint === "string" ? nested.hint : typeof parsed?.hint === "string" ? parsed.hint : void 0;
|
|
247
|
+
return { message, code, hint };
|
|
248
|
+
}
|
|
249
|
+
async function parseResponse(response, defaultErrorPrefix) {
|
|
250
|
+
const text = await response.text();
|
|
251
|
+
let parsed = void 0;
|
|
252
|
+
if (text) {
|
|
253
|
+
try {
|
|
254
|
+
parsed = JSON.parse(text);
|
|
255
|
+
} catch {
|
|
256
|
+
parsed = text;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
const details = errorDetails(parsed, defaultErrorPrefix, response.status);
|
|
261
|
+
if (response.status === 403) {
|
|
262
|
+
throw new PermissionError(details.message, details.code, details.hint);
|
|
263
|
+
}
|
|
264
|
+
if (response.status === 401) {
|
|
265
|
+
throw new TeAgentApiError(
|
|
266
|
+
"Session expired or unauthorized. Please run: ae-cli auth login",
|
|
267
|
+
response.status,
|
|
268
|
+
"auth_expired",
|
|
269
|
+
parsed
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
throw new TeAgentApiError(details.message, response.status, details.code, parsed);
|
|
273
|
+
}
|
|
274
|
+
return parsed;
|
|
275
|
+
}
|
|
276
|
+
async function postToMainApp(path2, body, hostOverride) {
|
|
277
|
+
const rawBody = JSON.stringify(body);
|
|
278
|
+
const response = await fetchSignedWithRetry({
|
|
279
|
+
method: "POST",
|
|
280
|
+
path: path2,
|
|
281
|
+
body: rawBody,
|
|
282
|
+
hostOverride
|
|
283
|
+
});
|
|
284
|
+
return parseResponse(response, "Main app returned");
|
|
285
|
+
}
|
|
286
|
+
async function getFromMainApp(path2, hostOverride) {
|
|
287
|
+
const response = await fetchSignedWithRetry({
|
|
288
|
+
method: "GET",
|
|
289
|
+
path: path2,
|
|
290
|
+
hostOverride
|
|
291
|
+
});
|
|
292
|
+
return parseResponse(response, "Main app returned");
|
|
293
|
+
}
|
|
294
|
+
async function getSandboxModels(currentModelId) {
|
|
295
|
+
const qs = currentModelId ? `?current=${encodeURIComponent(currentModelId)}` : "";
|
|
296
|
+
const data = await getFromMainApp(`/api/sandbox/models${qs}`);
|
|
297
|
+
return Array.isArray(data?.models) ? data.models : [];
|
|
298
|
+
}
|
|
299
|
+
async function postSandboxModelSelection(args) {
|
|
300
|
+
return postToMainApp("/api/sandbox/models/select", args);
|
|
301
|
+
}
|
|
302
|
+
async function getSandboxSyncPullCandidates(args) {
|
|
303
|
+
const qs = new URLSearchParams({
|
|
304
|
+
workspacePath: args.workspacePath,
|
|
305
|
+
kind: args.kind
|
|
306
|
+
});
|
|
307
|
+
return getFromMainApp(
|
|
308
|
+
`/api/sandbox/sync/pull/candidates?${qs.toString()}`
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
async function postSandboxSyncPull(args) {
|
|
312
|
+
return postToMainApp("/api/sandbox/sync/pull", {
|
|
313
|
+
workspacePath: args.workspacePath,
|
|
314
|
+
kind: args.kind,
|
|
315
|
+
skills: args.skills,
|
|
316
|
+
mcp: args.mcp,
|
|
317
|
+
mode: "merge"
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async function deleteFromMainApp(path2, hostOverride) {
|
|
321
|
+
const response = await fetchSignedWithRetry({
|
|
322
|
+
method: "DELETE",
|
|
323
|
+
path: path2,
|
|
324
|
+
hostOverride
|
|
325
|
+
});
|
|
326
|
+
return parseResponse(response, "Main app returned");
|
|
327
|
+
}
|
|
328
|
+
async function patchToMainApp(path2, body, hostOverride) {
|
|
329
|
+
const rawBody = JSON.stringify(body);
|
|
330
|
+
const response = await fetchSignedWithRetry({
|
|
331
|
+
method: "PATCH",
|
|
332
|
+
path: path2,
|
|
333
|
+
body: rawBody,
|
|
334
|
+
hostOverride
|
|
335
|
+
});
|
|
336
|
+
return parseResponse(response, "Main app returned");
|
|
337
|
+
}
|
|
338
|
+
async function putToMainApp(path2, body, hostOverride) {
|
|
339
|
+
const rawBody = JSON.stringify(body);
|
|
340
|
+
const response = await fetchSignedWithRetry({
|
|
341
|
+
method: "PUT",
|
|
342
|
+
path: path2,
|
|
343
|
+
body: rawBody,
|
|
344
|
+
hostOverride
|
|
345
|
+
});
|
|
346
|
+
return parseResponse(response, "Main app returned");
|
|
347
|
+
}
|
|
348
|
+
async function getBufferFromMainApp(path2, hostOverride) {
|
|
349
|
+
const response = await fetchSignedWithRetry({
|
|
350
|
+
method: "GET",
|
|
351
|
+
path: path2,
|
|
352
|
+
hostOverride
|
|
353
|
+
});
|
|
354
|
+
if (!response.ok) {
|
|
355
|
+
await parseResponse(response, "Main app returned");
|
|
356
|
+
}
|
|
357
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
358
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
359
|
+
const cd = response.headers.get("Content-Disposition") || "";
|
|
360
|
+
const match = cd.match(/filename\*=UTF-8''([^;]+)/);
|
|
361
|
+
const fileName = match ? decodeURIComponent(match[1]) : null;
|
|
362
|
+
const contentType = response.headers.get("Content-Type");
|
|
363
|
+
return { buffer, fileName, contentType };
|
|
364
|
+
}
|
|
365
|
+
function responseFileName(response) {
|
|
366
|
+
const disposition = response.headers.get("Content-Disposition") ?? "";
|
|
367
|
+
const encoded = disposition.match(/filename\*=UTF-8''([^;]+)/i)?.[1];
|
|
368
|
+
if (encoded) {
|
|
369
|
+
try {
|
|
370
|
+
return decodeURIComponent(encoded.trim());
|
|
371
|
+
} catch {
|
|
372
|
+
return encoded.trim();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return disposition.match(/filename="([^"]+)"/i)?.[1] ?? disposition.match(/filename=([^;]+)/i)?.[1]?.trim() ?? null;
|
|
376
|
+
}
|
|
377
|
+
async function* responseBodyChunks(body) {
|
|
378
|
+
const reader = body.getReader();
|
|
379
|
+
try {
|
|
380
|
+
while (true) {
|
|
381
|
+
const chunk = await reader.read();
|
|
382
|
+
if (chunk.done) return;
|
|
383
|
+
yield chunk.value;
|
|
384
|
+
}
|
|
385
|
+
} finally {
|
|
386
|
+
reader.releaseLock();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async function downloadFromMainApp(requestPath, outputPath, hostOverride) {
|
|
390
|
+
const absolutePath = path.resolve(outputPath);
|
|
391
|
+
let fileHandle;
|
|
392
|
+
let created = false;
|
|
393
|
+
const controller = new AbortController();
|
|
394
|
+
const timer = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS);
|
|
395
|
+
try {
|
|
396
|
+
try {
|
|
397
|
+
fileHandle = await open(absolutePath, "wx");
|
|
398
|
+
created = true;
|
|
399
|
+
} catch (error) {
|
|
400
|
+
if (error.code === "EEXIST") {
|
|
401
|
+
throw new TeAgentApiError(
|
|
402
|
+
`Output file already exists: ${absolutePath}`,
|
|
403
|
+
0,
|
|
404
|
+
"OUTPUT_EXISTS"
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
throw new TeAgentApiError(
|
|
408
|
+
`Unable to create output file: ${absolutePath}`,
|
|
409
|
+
0,
|
|
410
|
+
"OUTPUT_ERROR"
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
let signed = await signRequest("GET", requestPath, hostOverride);
|
|
414
|
+
let response;
|
|
415
|
+
const request = async (requestToSend) => {
|
|
416
|
+
try {
|
|
417
|
+
return await fetch(requestToSend.url, {
|
|
418
|
+
method: "GET",
|
|
419
|
+
headers: requestToSend.headers,
|
|
420
|
+
signal: controller.signal
|
|
421
|
+
});
|
|
422
|
+
} catch (error) {
|
|
423
|
+
if (error?.name === "AbortError") {
|
|
424
|
+
throw new TeAgentApiError(
|
|
425
|
+
`Request timed out (${DOWNLOAD_TIMEOUT_MS}ms) for ${safeRequestOrigin(requestToSend.url)}`,
|
|
426
|
+
0,
|
|
427
|
+
"TIMEOUT"
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
throw networkRequestError(requestToSend.url, error);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
response = await request(signed);
|
|
434
|
+
if (response.status === 401 && signed.authKind === "cli-token" && signed.tokenHost) {
|
|
435
|
+
clearCliToken(signed.tokenHost);
|
|
436
|
+
signed = await signRequest("GET", requestPath, hostOverride);
|
|
437
|
+
response = await request(signed);
|
|
438
|
+
}
|
|
439
|
+
if (!response.ok) {
|
|
440
|
+
await parseResponse(response, "Main app returned");
|
|
441
|
+
}
|
|
442
|
+
if (!response.body) {
|
|
443
|
+
throw new TeAgentApiError("Main app returned an empty download stream", 0, "EMPTY_BODY");
|
|
444
|
+
}
|
|
445
|
+
const output = fileHandle.createWriteStream();
|
|
446
|
+
try {
|
|
447
|
+
await pipeline(
|
|
448
|
+
Readable.from(responseBodyChunks(response.body)),
|
|
449
|
+
output
|
|
450
|
+
);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
if (error?.name === "AbortError") {
|
|
453
|
+
throw new TeAgentApiError(
|
|
454
|
+
`Request timed out (${DOWNLOAD_TIMEOUT_MS}ms): ${signed.url}`,
|
|
455
|
+
0,
|
|
456
|
+
"TIMEOUT"
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
throw new TeAgentApiError(
|
|
460
|
+
`Download failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
461
|
+
0,
|
|
462
|
+
"DOWNLOAD_ERROR"
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
path: absolutePath,
|
|
467
|
+
bytes: output.bytesWritten,
|
|
468
|
+
fileName: responseFileName(response),
|
|
469
|
+
contentType: response.headers.get("Content-Type")
|
|
470
|
+
};
|
|
471
|
+
} catch (error) {
|
|
472
|
+
if (fileHandle) await fileHandle.close().catch(() => void 0);
|
|
473
|
+
if (created) await unlink(absolutePath).catch(() => void 0);
|
|
474
|
+
throw error;
|
|
475
|
+
} finally {
|
|
476
|
+
clearTimeout(timer);
|
|
477
|
+
controller.abort();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async function uploadToMainApp(path2, formData, hostOverride) {
|
|
481
|
+
const response = await fetchSignedWithRetry({
|
|
482
|
+
method: "POST",
|
|
483
|
+
path: path2,
|
|
484
|
+
body: formData,
|
|
485
|
+
hostOverride,
|
|
486
|
+
includeJsonContentType: false,
|
|
487
|
+
timeoutMs: UPLOAD_TIMEOUT_MS
|
|
488
|
+
});
|
|
489
|
+
return parseResponse(response, "Upload failed");
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export {
|
|
493
|
+
TeAgentCredentialsError,
|
|
494
|
+
tryLoadTeAgentSandboxCredentials,
|
|
495
|
+
getClaudeConfigDir,
|
|
496
|
+
TeAgentApiError,
|
|
497
|
+
postToMainApp,
|
|
498
|
+
getFromMainApp,
|
|
499
|
+
getSandboxModels,
|
|
500
|
+
postSandboxModelSelection,
|
|
501
|
+
getSandboxSyncPullCandidates,
|
|
502
|
+
postSandboxSyncPull,
|
|
503
|
+
deleteFromMainApp,
|
|
504
|
+
patchToMainApp,
|
|
505
|
+
putToMainApp,
|
|
506
|
+
getBufferFromMainApp,
|
|
507
|
+
downloadFromMainApp,
|
|
508
|
+
uploadToMainApp
|
|
509
|
+
};
|