@thinkingai/ae-cli 6.0.55 → 6.0.57
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 +35 -6
- package/README.zh.md +35 -6
- package/bin/ae-cli.js +5 -0
- package/bin/runtime-capabilities.json +5 -0
- package/cli-installation-guide.md +24 -3
- package/dist/{auth-RQBO6MTY.js → auth-YEIJLBFY.js} +61 -19
- package/dist/{automation-VAAQBM7Y.js → automation-NAR5DDGL.js} +94 -38
- package/dist/{capability-JRIFC4AJ.js → capability-P7DD4Q73.js} +50 -21
- package/dist/{chunk-5XJYLEVC.js → chunk-72NJKS7O.js} +4 -4
- package/dist/chunk-752BSLZC.js +222 -0
- package/dist/{chunk-RGYPSEYD.js → chunk-7ABK2PEJ.js} +3 -3
- package/dist/{chunk-Q5US7JC5.js → chunk-7JAVT5TK.js} +3 -3
- package/dist/{chunk-GHXZK54S.js → chunk-H3K5UGYC.js} +41 -13
- package/dist/{chunk-OP44TT4H.js → chunk-IN7KKL6K.js} +4 -2
- package/dist/{chunk-VZZNLV3I.js → chunk-JCWM2TYP.js} +61 -15
- package/dist/{chunk-S6M42KND.js → chunk-JEUXDY3B.js} +1 -1
- package/dist/{chunk-ZL7SGNIA.js → chunk-JNVVJ273.js} +58 -46
- package/dist/chunk-N6XBLRB7.js +105 -0
- package/dist/{chunk-AP7YP2NX.js → chunk-OAWPT7VP.js} +2 -2
- package/dist/{chunk-7KU2WNQE.js → chunk-QEMQKVHW.js} +37 -15
- package/dist/{chunk-CT7QDJS6.js → chunk-QVRIDN42.js} +2 -2
- package/dist/{chunk-RPBOAQQQ.js → chunk-QZUVLFNR.js} +1 -1
- package/dist/{chunk-3YVEAZUN.js → chunk-RJHGDWSC.js} +32 -21
- package/dist/{chunk-374V5R6N.js → chunk-TKVVACEJ.js} +6 -4
- package/dist/chunk-TULINOLS.js +2283 -0
- package/dist/chunk-YVG6QD3V.js +233 -0
- package/dist/{chunk-WNGFSIOB.js → chunk-Z3Q2AEIN.js} +237 -86
- package/dist/chunk-ZGIYG473.js +132 -0
- package/dist/{community-report-client-PEERQCX2.js → community-report-client-TJVCLZ3K.js} +1 -1
- package/dist/compat-check-PMEGUPZU.js +32 -0
- package/dist/{config-SICKWZ2A.js → config-VWVPR4WW.js} +43 -10
- package/dist/{context-NGVFPCBK.js → context-F6FCGTF3.js} +4 -4
- package/dist/{data-integration-BCLQFTGU.js → data-integration-6UAZO4GG.js} +207 -24
- package/dist/evaluation-4LO2O4AF.js +3714 -0
- package/dist/index.js +343 -79
- package/dist/{local-data-upload-client-TWMHFLUA.js → local-data-upload-client-KCMG6J62.js} +1 -1
- package/dist/{memory-CQKH2JAV.js → memory-HHPX3NF2.js} +6 -6
- package/dist/{metadata-EMFGUI2W.js → metadata-HEQQEEG3.js} +17 -9
- package/dist/{model-VX5M2CJ6.js → model-7UHGWYVR.js} +4 -4
- package/dist/{personal-semantic-preference-SLWVVYZ4.js → personal-semantic-preference-V4L6ZWR2.js} +7 -6
- package/dist/{project-semantic-DPSZBKQD.js → project-semantic-NKHKJX6M.js} +7 -6
- package/dist/{sync-RZIAV37C.js → sync-ZJMXCRIN.js} +8 -7
- package/dist/{te-agent-AORRE2FM.js → te-agent-WBKIFEQD.js} +757 -94
- package/dist/{te-analysis-ISXKJKRT.js → te-analysis-ADX7RKO4.js} +578 -94
- package/dist/{te-community-42M7ICDO.js → te-community-PREDRXG3.js} +722 -228
- package/dist/{te-dataops-BNKNZ4F2.js → te-dataops-ITWJHO2U.js} +9 -6
- package/dist/{te-engage-BZE3MBKT.js → te-engage-VE2NUH5V.js} +7 -6
- package/dist/{te-kb-ULATOTQ3.js → te-kb-WSMOW7WS.js} +407 -83
- package/dist/{te-system-UGHVKBVV.js → te-system-YM657FKO.js} +6 -6
- package/dist/{te-team-YA6SNOJ3.js → te-team-T2WRLOOD.js} +64 -41
- package/dist/{things-DTCOQIQB.js → things-6QOMFXOG.js} +7 -7
- package/dist/{update-ESNYKUVR.js → update-I4MOUYOX.js} +11 -7
- package/dist/{workspace-JEOHKFPX.js → workspace-LYDAP647.js} +6 -6
- package/package.json +25 -11
- package/skills/ae-agent/SKILL.md +20 -3
- package/skills/ae-agent/references/command_index.md +8 -0
- package/skills/ae-agent/references/resource-package.md +57 -0
- package/skills/ae-analysis/SKILL.md +23 -10
- package/skills/ae-analysis/references/adhoc_export.md +1 -1
- package/skills/ae-analysis/references/agent_review_preflight.md +55 -10
- package/skills/ae-analysis/references/agent_review_priorities_comparisons.md +5 -3
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +60 -24
- package/skills/ae-analysis/references/ai_models/event.md +58 -2
- package/skills/ae-analysis/references/ai_models/rank_list.md +1 -0
- package/skills/ae-analysis/references/ai_models/retention.md +2 -0
- package/skills/ae-analysis/references/ai_models/revenue.md +2 -0
- package/skills/ae-analysis/references/analysis_data_export.md +11 -1
- package/skills/ae-analysis/references/asset_batch_info_export.md +2 -2
- package/skills/ae-analysis/references/asset_batch_sql_export.md +2 -2
- package/skills/ae-analysis/references/asset_export.md +1 -1
- package/skills/ae-analysis/references/bi_panel_page_data_export.md +1 -1
- package/skills/ae-analysis/references/check_export.md +1 -1
- package/skills/ae-analysis/references/command_index.md +39 -26
- package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_get.md +6 -2
- package/skills/ae-analysis/references/dashboard_report_update.md +24 -5
- package/skills/ae-analysis/references/feedback_submit.md +1 -1
- package/skills/ae-analysis/references/governance_recommendation_export.md +40 -18
- package/skills/ae-analysis/references/governance_recommendation_run_update.md +13 -0
- package/skills/ae-analysis/references/live_data_export.md +1 -1
- package/skills/ae-analysis/references/metric_create.md +29 -0
- package/skills/ae-analysis/references/metric_get.md +2 -0
- package/skills/ae-analysis/references/metric_update.md +2 -0
- package/skills/ae-analysis/references/operation_record_export.md +1 -1
- package/skills/ae-analysis/references/plan_change_log_export.md +1 -1
- package/skills/ae-analysis/references/plan_export.md +1 -1
- package/skills/ae-analysis/references/project_info_get.md +4 -0
- package/skills/ae-analysis/references/project_member_group_add_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_create.md +25 -0
- package/skills/ae-analysis/references/project_member_group_delete.md +34 -0
- package/skills/ae-analysis/references/project_member_group_list.md +29 -0
- package/skills/ae-analysis/references/project_member_group_members.md +28 -0
- package/skills/ae-analysis/references/project_member_group_remove_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_rename.md +26 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +9 -1
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +6 -1
- package/skills/ae-analysis/references/report_data_export.md +1 -1
- package/skills/ae-analysis/references/scenario_append.md +31 -0
- package/skills/ae-analysis/references/scenario_begin.md +11 -0
- package/skills/ae-analysis/references/scenario_collect.md +43 -0
- package/skills/ae-analysis/references/scenario_evaluation.md +18 -0
- package/skills/ae-analysis/references/scenario_get.md +15 -0
- package/skills/ae-analysis/references/scenario_list.md +64 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +73 -4
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/company-kb.mjs +14 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +5 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/execution-contract.mjs +173 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +109 -64
- package/skills/ae-automation/SKILL.md +2 -2
- package/skills/ae-automation/references/cli.md +18 -1
- package/skills/ae-capability/SKILL.md +7 -3
- package/skills/ae-community/SKILL.md +77 -27
- package/skills/ae-community/references/community-analyzing-theme-comment.md +10 -8
- package/skills/ae-community/references/community-data-quality.md +68 -0
- package/skills/ae-community/references/community-query-evidence.md +85 -0
- package/skills/ae-community/references/community-scenario-capabilities.md +137 -0
- package/skills/ae-community/references/community-weekly-report.md +6 -3
- package/skills/ae-community/references/get_channel_info.md +7 -4
- package/skills/ae-community/references/get_comment_tag_analysis.md +3 -3
- package/skills/ae-community/references/get_comments_summary.md +4 -4
- package/skills/ae-community/references/get_corpus_tags.md +3 -3
- package/skills/ae-community/references/get_daily_summary.md +3 -3
- package/skills/ae-community/references/get_hot_topics.md +3 -3
- package/skills/ae-community/references/get_livestream_analysis.md +3 -3
- package/skills/ae-community/references/get_livestream_detail.md +4 -4
- package/skills/ae-community/references/get_livestream_list.md +3 -3
- package/skills/ae-community/references/get_livestream_overview.md +3 -3
- package/skills/ae-community/references/get_livestream_room_metrics.md +3 -3
- package/skills/ae-community/references/get_livestream_rooms.md +3 -3
- package/skills/ae-community/references/get_overview_metrics.md +3 -3
- package/skills/ae-community/references/get_post_detail.md +4 -4
- package/skills/ae-community/references/get_risk_content.md +5 -5
- package/skills/ae-community/references/get_sentiment_overview.md +4 -4
- package/skills/ae-community/references/get_tag_trends.md +3 -3
- package/skills/ae-community/references/get_topic_detail.md +3 -3
- package/skills/ae-community/references/list_sources.md +28 -0
- package/skills/ae-community/references/list_spaces.md +39 -0
- package/skills/ae-community/references/search_posts.md +21 -7
- package/skills/ae-data-integration/SKILL.md +6 -4
- package/skills/ae-data-integration/references/error-handling.md +1 -0
- package/skills/ae-data-integration/references/handoff.md +1 -1
- package/skills/ae-data-integration/references/sink-upload.md +11 -0
- package/skills/ae-data-integration/references/source-inspect.md +2 -1
- package/skills/ae-data-integration/references/transform.md +1 -1
- package/skills/ae-data-integration/references/ue-mapping.md +1 -1
- package/skills/ae-evaluation/SKILL.md +83 -0
- package/skills/ae-evaluation/references/access-and-members.md +55 -0
- package/skills/ae-evaluation/references/connections.md +78 -0
- package/skills/ae-evaluation/references/datasets.md +57 -0
- package/skills/ae-evaluation/references/evaluators.md +81 -0
- package/skills/ae-evaluation/references/files.md +33 -0
- package/skills/ae-evaluation/references/integrations.md +39 -0
- package/skills/ae-evaluation/references/runs.md +160 -0
- package/skills/ae-evaluation/references/schedules.md +31 -0
- package/skills/ae-kb/SKILL.md +33 -6
- package/skills/ae-kb/references/publication.md +81 -0
- package/skills/ae-kb/references/query-workflow.md +14 -1
- package/skills/ae-metadata/SKILL.md +3 -2
- package/skills/ae-metadata/references/metadata_data_table_download.md +7 -1
- package/skills/ae-metadata/references/metadata_data_table_get.md +37 -0
- package/skills/ae-team/SKILL.md +2 -2
- package/skills/ae-team/references/run-start.md +1 -0
- package/skills/ae-team/references/run-watch.md +7 -5
- package/skills/ae-things/SKILL.md +53 -51
- package/skills/ae-things/references/cli.md +56 -54
- package/skills/ae-things-progress/SKILL.md +20 -20
- package/skills/ae-things-review/SKILL.md +19 -19
- package/dist/chunk-6VNIR4AP.js +0 -1422
- package/dist/chunk-CI24BDR2.js +0 -43
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
CliValidationError,
|
|
4
|
+
logger
|
|
5
|
+
} from "./chunk-Z3Q2AEIN.js";
|
|
6
|
+
|
|
7
|
+
// src/core/eval-endpoint.ts
|
|
8
|
+
function resolveEvaluationHost(host) {
|
|
9
|
+
let endpoint;
|
|
10
|
+
try {
|
|
11
|
+
endpoint = new URL(host);
|
|
12
|
+
if (endpoint.username || endpoint.password || endpoint.search || endpoint.hash || /[?#\s]/.test(host)) throw new Error();
|
|
13
|
+
} catch {
|
|
14
|
+
throw new CliValidationError("Evaluation AE Host must be an absolute HTTP(S) URL without credentials, query, or fragment.", {
|
|
15
|
+
code: "EVAL_ENDPOINT_INVALID"
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const hostname = endpoint.hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
19
|
+
const mappedIpv4 = /^::ffff:([0-9a-f]+):[0-9a-f]+$/.exec(hostname);
|
|
20
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "::1" || hostname === "::" || hostname === "0.0.0.0" || hostname.startsWith("127.") || mappedIpv4 && parseInt(mappedIpv4[1], 16) >> 8 === 127 || hostname === "::ffff:0:0") {
|
|
21
|
+
throw new CliValidationError("Loopback evaluation endpoints are unsupported.", {
|
|
22
|
+
code: "EVAL_ENDPOINT_LOOPBACK_UNSUPPORTED",
|
|
23
|
+
hint: "Select an online AE Host with --host."
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:") {
|
|
27
|
+
throw new CliValidationError("Evaluation AE Host must use HTTP or HTTPS.", {
|
|
28
|
+
code: "EVAL_ENDPOINT_INVALID"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return endpoint.toString().replace(/\/+$/, "").replace(/\/agent$/, "");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/core/eval-client.ts
|
|
35
|
+
import { open, unlink } from "fs/promises";
|
|
36
|
+
import { resolve } from "path";
|
|
37
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
38
|
+
var EvalApiError = class extends Error {
|
|
39
|
+
code;
|
|
40
|
+
httpStatus;
|
|
41
|
+
hint;
|
|
42
|
+
details;
|
|
43
|
+
constructor(message, options) {
|
|
44
|
+
const redact = evaluationErrorRedactor([
|
|
45
|
+
...options.sensitiveValues ?? [],
|
|
46
|
+
process.env.AE_EVAL_ACCESS_TOKEN ?? ""
|
|
47
|
+
]);
|
|
48
|
+
super(redact(message));
|
|
49
|
+
this.name = "EvalApiError";
|
|
50
|
+
this.code = options.code;
|
|
51
|
+
this.httpStatus = options.httpStatus;
|
|
52
|
+
this.hint = options.hint === void 0 ? void 0 : redact(options.hint);
|
|
53
|
+
this.details = options.details === void 0 ? void 0 : redact(options.details);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
function evaluationErrorRedactor(secrets) {
|
|
57
|
+
const forms = [...new Set(secrets.filter(Boolean).flatMap((secret) => [
|
|
58
|
+
secret,
|
|
59
|
+
JSON.stringify(secret).slice(1, -1),
|
|
60
|
+
encodeURIComponent(secret)
|
|
61
|
+
]))].sort((a, b) => b.length - a.length);
|
|
62
|
+
const redact = (value) => {
|
|
63
|
+
if (typeof value === "string") {
|
|
64
|
+
for (const secret of forms) value = value.split(secret).join("[REDACTED]");
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (Array.isArray(value)) return value.map(redact);
|
|
68
|
+
if (value && typeof value === "object") {
|
|
69
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [redact(key), redact(item)]));
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
};
|
|
73
|
+
return redact;
|
|
74
|
+
}
|
|
75
|
+
async function evalRequest(options) {
|
|
76
|
+
const url = buildEvalUrl(options.baseUrl, options.path, options.params);
|
|
77
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
78
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
79
|
+
const controller = new AbortController();
|
|
80
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
81
|
+
const headers = {
|
|
82
|
+
...options.headers,
|
|
83
|
+
Accept: options.responseType === "bytes" ? "application/octet-stream, application/json" : "application/json"
|
|
84
|
+
};
|
|
85
|
+
const isMultipart = options.body instanceof FormData;
|
|
86
|
+
if (options.body !== void 0 && !isMultipart) {
|
|
87
|
+
headers["Content-Type"] = "application/json";
|
|
88
|
+
}
|
|
89
|
+
if (options.idempotencyKey) {
|
|
90
|
+
headers["Idempotency-Key"] = options.idempotencyKey;
|
|
91
|
+
}
|
|
92
|
+
let response;
|
|
93
|
+
let responseText = "";
|
|
94
|
+
let bytes;
|
|
95
|
+
try {
|
|
96
|
+
response = await fetchImpl(url, {
|
|
97
|
+
method: options.method,
|
|
98
|
+
headers,
|
|
99
|
+
body: options.body === void 0 ? void 0 : options.body instanceof FormData ? options.body : JSON.stringify(options.body),
|
|
100
|
+
redirect: "error",
|
|
101
|
+
signal: controller.signal
|
|
102
|
+
});
|
|
103
|
+
if (response.ok && options.responseType === "bytes") {
|
|
104
|
+
bytes = new Uint8Array(await response.arrayBuffer());
|
|
105
|
+
} else {
|
|
106
|
+
responseText = await response.text();
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const timedOut = controller.signal.aborted || error instanceof Error && error.name === "AbortError";
|
|
110
|
+
logEvalRequest(options.method, url, response?.status ?? "unavailable");
|
|
111
|
+
if (timedOut) {
|
|
112
|
+
throw new EvalApiError(`Evaluation API request timed out after ${timeoutMs} ms.`, {
|
|
113
|
+
code: "EVAL_API_TIMEOUT",
|
|
114
|
+
httpStatus: 0,
|
|
115
|
+
hint: "Verify the evaluation platform is reachable at the configured endpoint."
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
throw new EvalApiError("Evaluation API request failed before a response was received.", {
|
|
119
|
+
code: "EVAL_API_NETWORK_ERROR",
|
|
120
|
+
httpStatus: 0,
|
|
121
|
+
hint: "Verify the --endpoint URL and network path."
|
|
122
|
+
});
|
|
123
|
+
} finally {
|
|
124
|
+
clearTimeout(timeout);
|
|
125
|
+
}
|
|
126
|
+
logEvalRequest(options.method, url, response.status);
|
|
127
|
+
if (bytes !== void 0) return bytes;
|
|
128
|
+
const responseBody = parseEvalResponseBody(responseText, response.status);
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const sensitiveValues = Object.values(options.headers).flatMap((value) => [value, value.replace(/^Bearer\s+/i, "")]);
|
|
131
|
+
if (isRecord(options.body)) {
|
|
132
|
+
for (const key of ["secret", "data_token", "report_source"]) {
|
|
133
|
+
if (typeof options.body[key] === "string") sensitiveValues.push(options.body[key]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw evalErrorFromBody(responseBody, response.status, sensitiveValues);
|
|
137
|
+
}
|
|
138
|
+
return responseBody;
|
|
139
|
+
}
|
|
140
|
+
async function evalDownloadFile(options, outputPath) {
|
|
141
|
+
const path = resolve(outputPath);
|
|
142
|
+
let file;
|
|
143
|
+
try {
|
|
144
|
+
file = await open(path, "wx", 384);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error.code === "EEXIST") {
|
|
147
|
+
throw new CliValidationError("Output file already exists; choose a new --output path.", {
|
|
148
|
+
code: "EVAL_OUTPUT_EXISTS"
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
let completed = false;
|
|
154
|
+
try {
|
|
155
|
+
const bytes = await evalRequest({ ...options, responseType: "bytes" });
|
|
156
|
+
await file.writeFile(bytes);
|
|
157
|
+
completed = true;
|
|
158
|
+
return { path, byte_size: bytes.byteLength };
|
|
159
|
+
} finally {
|
|
160
|
+
await file.close();
|
|
161
|
+
if (!completed) await unlink(path);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function buildEvalUrl(baseUrl, path, params) {
|
|
165
|
+
const base = resolveEvaluationHost(baseUrl);
|
|
166
|
+
const url = new URL(`${base}${path}`);
|
|
167
|
+
if (params) {
|
|
168
|
+
for (const [key, value] of Object.entries(params)) {
|
|
169
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
170
|
+
url.searchParams.set(key, String(value));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return url.toString();
|
|
174
|
+
}
|
|
175
|
+
function parseEvalResponseBody(text, httpStatus) {
|
|
176
|
+
if (!text.trim()) {
|
|
177
|
+
if (httpStatus === 204) return void 0;
|
|
178
|
+
throw new EvalApiError("Evaluation API returned an empty response body.", {
|
|
179
|
+
code: "EVAL_API_INVALID_RESPONSE",
|
|
180
|
+
httpStatus
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(text);
|
|
185
|
+
} catch {
|
|
186
|
+
throw new EvalApiError("Evaluation API returned a non-JSON response body.", {
|
|
187
|
+
code: "EVAL_API_INVALID_RESPONSE",
|
|
188
|
+
httpStatus
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function evalErrorFromBody(body, httpStatus, sensitiveValues) {
|
|
193
|
+
const error = body?.error;
|
|
194
|
+
if (isRecord(error) && typeof error.message === "string" && error.message.trim()) {
|
|
195
|
+
return new EvalApiError(error.message.trim(), {
|
|
196
|
+
code: typeof error.code === "string" && /^[A-Z][A-Z0-9_]{0,127}$/.test(error.code) ? error.code : `EVAL_API_HTTP_${httpStatus}`,
|
|
197
|
+
httpStatus,
|
|
198
|
+
hint: typeof error.details === "string" ? error.details : void 0,
|
|
199
|
+
details: isRecord(error.details) ? error.details : void 0,
|
|
200
|
+
sensitiveValues
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return new EvalApiError(`Evaluation API returned HTTP ${httpStatus}.`, {
|
|
204
|
+
code: `EVAL_API_HTTP_${httpStatus}`,
|
|
205
|
+
httpStatus,
|
|
206
|
+
hint: httpStatus >= 500 ? "The server response was suppressed. Check the evaluation platform logs; the CLI did not retry." : void 0
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function isRecord(value) {
|
|
210
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
211
|
+
}
|
|
212
|
+
function logEvalRequest(method, url, status) {
|
|
213
|
+
logger.info(`EVAL ${method} ${redactEvalLogUrl(url)} status=${status}`);
|
|
214
|
+
}
|
|
215
|
+
function redactEvalLogUrl(url) {
|
|
216
|
+
try {
|
|
217
|
+
const parsed = new URL(url);
|
|
218
|
+
parsed.username = "";
|
|
219
|
+
parsed.password = "";
|
|
220
|
+
parsed.search = "";
|
|
221
|
+
parsed.hash = "";
|
|
222
|
+
return parsed.toString();
|
|
223
|
+
} catch {
|
|
224
|
+
return "[invalid evaluation URL]";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export {
|
|
229
|
+
resolveEvaluationHost,
|
|
230
|
+
EvalApiError,
|
|
231
|
+
evalRequest,
|
|
232
|
+
evalDownloadFile
|
|
233
|
+
};
|
|
@@ -48,101 +48,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
48
48
|
));
|
|
49
49
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
50
50
|
|
|
51
|
-
// src/core/logger.ts
|
|
52
|
-
import fs from "fs";
|
|
53
|
-
import path from "path";
|
|
54
|
-
var LOG_DIR = path.join(process.env.HOME || "", ".ae-cli", "log");
|
|
55
|
-
var Logger = class {
|
|
56
|
-
logDir;
|
|
57
|
-
date;
|
|
58
|
-
constructor() {
|
|
59
|
-
this.logDir = LOG_DIR;
|
|
60
|
-
this.date = this.today();
|
|
61
|
-
this.ensureDir();
|
|
62
|
-
}
|
|
63
|
-
today() {
|
|
64
|
-
const d = /* @__PURE__ */ new Date();
|
|
65
|
-
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, "0")}${String(d.getDate()).padStart(2, "0")}`;
|
|
66
|
-
}
|
|
67
|
-
timestamp() {
|
|
68
|
-
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").split(".")[0];
|
|
69
|
-
}
|
|
70
|
-
ensureDir() {
|
|
71
|
-
if (!fs.existsSync(this.logDir)) {
|
|
72
|
-
fs.mkdirSync(this.logDir, { recursive: true });
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
filePath(level) {
|
|
76
|
-
const today = this.today();
|
|
77
|
-
if (today !== this.date) {
|
|
78
|
-
this.date = today;
|
|
79
|
-
}
|
|
80
|
-
return path.join(this.logDir, `${this.date}_${level}.log`);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Write a log entry to file (not printed to the console; console output is handled by existing process.stderr.write calls)
|
|
84
|
-
*/
|
|
85
|
-
write(level, message) {
|
|
86
|
-
const ts = this.timestamp();
|
|
87
|
-
const line = `[${ts}] ${message}
|
|
88
|
-
`;
|
|
89
|
-
try {
|
|
90
|
-
fs.appendFileSync(this.filePath(level), line);
|
|
91
|
-
} catch {
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/** Informational log */
|
|
95
|
-
info(message) {
|
|
96
|
-
this.write("info", message);
|
|
97
|
-
}
|
|
98
|
-
/** Warning log */
|
|
99
|
-
warn(message) {
|
|
100
|
-
this.write("warning", message);
|
|
101
|
-
}
|
|
102
|
-
/** Error log */
|
|
103
|
-
error(message) {
|
|
104
|
-
this.write("error", message);
|
|
105
|
-
}
|
|
106
|
-
/** Log HTTP API request details */
|
|
107
|
-
api(method, url, status, reqBody, respBody) {
|
|
108
|
-
const parts = [`API ${method} ${url} \u2192 HTTP ${status}`];
|
|
109
|
-
if (reqBody !== void 0 && reqBody !== null) {
|
|
110
|
-
const s = typeof reqBody === "string" ? reqBody : JSON.stringify(reqBody);
|
|
111
|
-
parts.push(`REQ: ${s.slice(0, 500)}`);
|
|
112
|
-
}
|
|
113
|
-
if (respBody !== void 0 && respBody !== null) {
|
|
114
|
-
const s = typeof respBody === "string" ? respBody : JSON.stringify(respBody);
|
|
115
|
-
parts.push(`RESP: ${s.slice(0, 500)}`);
|
|
116
|
-
}
|
|
117
|
-
this.info(parts.join(" | "));
|
|
118
|
-
}
|
|
119
|
-
/** Log command execution (sensitive flags redacted to ***) */
|
|
120
|
-
command(name, args, sensitiveFlags = []) {
|
|
121
|
-
const normalizeFlagName = (name2) => name2.toLowerCase().replace(/[-_]/g, "");
|
|
122
|
-
const explicitSensitive = new Set(Array.from(sensitiveFlags, normalizeFlagName));
|
|
123
|
-
const SENSITIVE = ["token", "apikey", "secret", "accesstoken", "headers"];
|
|
124
|
-
const isSensitive = (k) => {
|
|
125
|
-
const normalized = normalizeFlagName(k);
|
|
126
|
-
return explicitSensitive.has(normalized) || SENSITIVE.some((s) => normalized.includes(s));
|
|
127
|
-
};
|
|
128
|
-
const filtered = Object.entries(args).filter(([, v]) => v !== void 0 && v !== null && v !== "").map(([k, v]) => `--${k}=${isSensitive(k) ? "***" : JSON.stringify(v)}`).join(" ");
|
|
129
|
-
this.info(`CMD ${name}${filtered ? " " + filtered : ""}`);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
var logger = new Logger();
|
|
133
|
-
|
|
134
51
|
// src/core/errors.ts
|
|
135
52
|
var PermissionError = class extends Error {
|
|
136
|
-
constructor(message, code, hint, details) {
|
|
53
|
+
constructor(message, code, hint, details, meta) {
|
|
137
54
|
super(message);
|
|
138
55
|
this.code = code;
|
|
139
56
|
this.hint = hint;
|
|
140
57
|
this.details = details;
|
|
58
|
+
this.meta = meta;
|
|
141
59
|
this.name = "PermissionError";
|
|
142
60
|
}
|
|
143
61
|
code;
|
|
144
62
|
hint;
|
|
145
63
|
details;
|
|
64
|
+
meta;
|
|
146
65
|
};
|
|
147
66
|
function isApiErrorType(value) {
|
|
148
67
|
return value === "auth" || value === "permission" || value === "validation" || value === "not_found" || value === "api";
|
|
@@ -212,6 +131,228 @@ var LocalDataUploadError = class extends Error {
|
|
|
212
131
|
}
|
|
213
132
|
};
|
|
214
133
|
|
|
134
|
+
// src/core/kb-read-context.ts
|
|
135
|
+
import fs from "fs";
|
|
136
|
+
var secrets = /* @__PURE__ */ new Set();
|
|
137
|
+
function fail(code) {
|
|
138
|
+
throw new CliValidationError(code, { code });
|
|
139
|
+
}
|
|
140
|
+
function kbExecutionContextRequired() {
|
|
141
|
+
return process.env.AE_KB_READ_CONTEXT_REQUIRED !== void 0 || process.env.AE_KB_READ_CONTEXT_FILE !== void 0;
|
|
142
|
+
}
|
|
143
|
+
function isKbQueryPath(method, pathname) {
|
|
144
|
+
return method === "POST" && /^\/(?:agent\/)?api\/external\/knowledge-bases\/(list|index|grep|read)$/.test(pathname);
|
|
145
|
+
}
|
|
146
|
+
function readKbExecutionContext() {
|
|
147
|
+
if (!kbExecutionContextRequired()) return void 0;
|
|
148
|
+
const file = process.env.AE_KB_READ_CONTEXT_FILE;
|
|
149
|
+
if (process.env.AE_KB_READ_CONTEXT_REQUIRED !== "1" || !file) fail("KB_READ_CONTEXT_REQUIRED");
|
|
150
|
+
let fd;
|
|
151
|
+
let data;
|
|
152
|
+
try {
|
|
153
|
+
fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
154
|
+
const stat = fs.fstatSync(fd);
|
|
155
|
+
if (!stat.isFile() || stat.size > 16384 || (stat.mode & 511) !== 384 || process.getuid && stat.uid !== process.getuid())
|
|
156
|
+
throw new Error();
|
|
157
|
+
data = JSON.parse(fs.readFileSync(fd, "utf8"));
|
|
158
|
+
if (!data || Array.isArray(data) || Object.keys(data).sort().join(",") !== "executionRef,expiresAt,formatVersion,origin,readContextId,required,token" || data.formatVersion !== 1 || data.required !== true || typeof data.executionRef !== "string" || !/^[^\s\0]{1,191}$/.test(data.executionRef) || typeof data.readContextId !== "string" || !/^[^\s\0]{1,191}$/.test(data.readContextId) || typeof data.token !== "string" || !/^cli_kbr_[A-Za-z0-9_-]{43,}$/.test(data.token) || typeof data.expiresAt !== "string" || !Number.isFinite(Date.parse(data.expiresAt)))
|
|
159
|
+
throw new Error();
|
|
160
|
+
const origin = new URL(data.origin);
|
|
161
|
+
if (!["http:", "https:"].includes(origin.protocol) || origin.username || origin.password || origin.origin !== data.origin)
|
|
162
|
+
throw new Error();
|
|
163
|
+
} catch {
|
|
164
|
+
fail("KB_READ_CONTEXT_REQUIRED");
|
|
165
|
+
} finally {
|
|
166
|
+
if (fd !== void 0) fs.closeSync(fd);
|
|
167
|
+
}
|
|
168
|
+
secrets.add(data.token);
|
|
169
|
+
if (Date.parse(data.expiresAt) <= Date.now()) fail("KB_READ_CONTEXT_EXPIRED");
|
|
170
|
+
return data;
|
|
171
|
+
}
|
|
172
|
+
function kbReadHeaders(url, explicitId) {
|
|
173
|
+
const context = readKbExecutionContext();
|
|
174
|
+
if (!context) return explicitId ? { "X-KB-Read-Context": explicitId } : void 0;
|
|
175
|
+
if (new URL(url).origin !== context.origin || explicitId && explicitId !== context.readContextId)
|
|
176
|
+
fail("KB_READ_CONTEXT_MISMATCH");
|
|
177
|
+
return { "cli-token": context.token, "X-KB-Read-Context": context.readContextId };
|
|
178
|
+
}
|
|
179
|
+
function redactKbReadCredential(value) {
|
|
180
|
+
for (const token of secrets) value = value.split(token).join("[REDACTED]");
|
|
181
|
+
return value.replace(/cli_kbr_[A-Za-z0-9_-]+/g, "[REDACTED]");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/core/url-utils.ts
|
|
185
|
+
function normalizeUrl(url) {
|
|
186
|
+
if (!url) return url;
|
|
187
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
188
|
+
url = `https://${url}`;
|
|
189
|
+
}
|
|
190
|
+
return url.replace(/\/$/, "");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/core/external-cli-token.ts
|
|
194
|
+
import fs2 from "fs";
|
|
195
|
+
var ExternalCliTokenError = class extends Error {
|
|
196
|
+
constructor(message, code = "EXTERNAL_CLI_TOKEN_INVALID") {
|
|
197
|
+
super(message);
|
|
198
|
+
this.code = code;
|
|
199
|
+
this.name = "ExternalCliTokenError";
|
|
200
|
+
}
|
|
201
|
+
code;
|
|
202
|
+
hint = "Set AE_CLI_TOKEN with AE_CLI_TOKEN_HOST, or use a JSON CLI token file containing url and token. Remove external token settings to use stored accounts.";
|
|
203
|
+
};
|
|
204
|
+
var explicitTokenFile;
|
|
205
|
+
var diagnosticSecrets = /* @__PURE__ */ new Set();
|
|
206
|
+
function setExternalCliTokenFile(file) {
|
|
207
|
+
explicitTokenFile = file;
|
|
208
|
+
}
|
|
209
|
+
function normalizedHost(value) {
|
|
210
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
211
|
+
throw new ExternalCliTokenError("The external CLI token requires a host URL.");
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const url = new URL(value);
|
|
215
|
+
if (!["http:", "https:"].includes(url.protocol) || !url.hostname || url.username || url.password || url.search || url.hash || /\s/.test(value)) throw new Error();
|
|
216
|
+
return normalizeUrl(url.toString());
|
|
217
|
+
} catch {
|
|
218
|
+
throw new ExternalCliTokenError("The external CLI token host must be an HTTP(S) URL without credentials, query, or fragment.");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function credential(url, value, source) {
|
|
222
|
+
if (typeof value !== "string" || !/^cli_[!-~]+$/.test(value.trim())) {
|
|
223
|
+
throw new ExternalCliTokenError("The external CLI token must be a non-empty ASCII cli_ token without whitespace.");
|
|
224
|
+
}
|
|
225
|
+
return { url: normalizedHost(url), token: value.trim(), source };
|
|
226
|
+
}
|
|
227
|
+
function readExternalCliToken(hostOverride) {
|
|
228
|
+
let entry;
|
|
229
|
+
const file = explicitTokenFile ?? (process.env.AE_CLI_TOKEN === void 0 ? process.env.AE_CLI_TOKEN_FILE : void 0);
|
|
230
|
+
if (file !== void 0) {
|
|
231
|
+
if (!file.trim()) throw new ExternalCliTokenError("The external CLI token file path is empty.");
|
|
232
|
+
let data;
|
|
233
|
+
try {
|
|
234
|
+
const stat = fs2.statSync(file);
|
|
235
|
+
if (!stat.isFile() || stat.size > 64 * 1024) throw new Error();
|
|
236
|
+
data = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
237
|
+
} catch {
|
|
238
|
+
throw new ExternalCliTokenError("The external CLI token file must be a readable JSON file no larger than 64 KiB.");
|
|
239
|
+
}
|
|
240
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
241
|
+
throw new ExternalCliTokenError("The external CLI token file must contain an object with url and token.");
|
|
242
|
+
}
|
|
243
|
+
entry = credential(data.url, data.token ?? data["cli-token"], "file-cli-token");
|
|
244
|
+
} else if (process.env.AE_CLI_TOKEN !== void 0) {
|
|
245
|
+
entry = credential(process.env.AE_CLI_TOKEN_HOST, process.env.AE_CLI_TOKEN, "environment-cli-token");
|
|
246
|
+
} else if (process.env.AE_CLI_TOKEN_HOST !== void 0) {
|
|
247
|
+
throw new ExternalCliTokenError("AE_CLI_TOKEN_HOST requires AE_CLI_TOKEN.");
|
|
248
|
+
}
|
|
249
|
+
if (entry && hostOverride && normalizedHost(hostOverride) !== entry.url) {
|
|
250
|
+
throw new ExternalCliTokenError("The selected host does not match the external CLI token host.");
|
|
251
|
+
}
|
|
252
|
+
if (entry) diagnosticSecrets.add(entry.token);
|
|
253
|
+
return entry;
|
|
254
|
+
}
|
|
255
|
+
function externalCliTokenRequestOptions(destination) {
|
|
256
|
+
const external = readExternalCliToken();
|
|
257
|
+
if (!external) return {};
|
|
258
|
+
if (new URL(destination).origin !== new URL(external.url).origin) {
|
|
259
|
+
throw new ExternalCliTokenError("The request destination does not match the external CLI token host.");
|
|
260
|
+
}
|
|
261
|
+
return { redirect: "error" };
|
|
262
|
+
}
|
|
263
|
+
function redactExternalCliToken(value) {
|
|
264
|
+
try {
|
|
265
|
+
readExternalCliToken();
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
const forms = [...diagnosticSecrets].flatMap((token) => [token, JSON.stringify(token).slice(1, -1), encodeURIComponent(token)]);
|
|
269
|
+
for (const form of [...new Set(forms)].sort((a, b) => b.length - a.length)) value = value.split(form).join("[REDACTED]");
|
|
270
|
+
return redactKbReadCredential(value);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/core/logger.ts
|
|
274
|
+
import fs3 from "fs";
|
|
275
|
+
import path from "path";
|
|
276
|
+
var LOG_DIR = path.join(process.env.HOME || "", ".ae-cli", "log");
|
|
277
|
+
var Logger = class {
|
|
278
|
+
logDir;
|
|
279
|
+
date;
|
|
280
|
+
constructor() {
|
|
281
|
+
this.logDir = LOG_DIR;
|
|
282
|
+
this.date = this.today();
|
|
283
|
+
this.ensureDir();
|
|
284
|
+
}
|
|
285
|
+
today() {
|
|
286
|
+
const d = /* @__PURE__ */ new Date();
|
|
287
|
+
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, "0")}${String(d.getDate()).padStart(2, "0")}`;
|
|
288
|
+
}
|
|
289
|
+
timestamp() {
|
|
290
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").split(".")[0];
|
|
291
|
+
}
|
|
292
|
+
ensureDir() {
|
|
293
|
+
if (!fs3.existsSync(this.logDir)) {
|
|
294
|
+
fs3.mkdirSync(this.logDir, { recursive: true });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
filePath(level) {
|
|
298
|
+
const today = this.today();
|
|
299
|
+
if (today !== this.date) {
|
|
300
|
+
this.date = today;
|
|
301
|
+
}
|
|
302
|
+
return path.join(this.logDir, `${this.date}_${level}.log`);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Write a log entry to file (not printed to the console; console output is handled by existing process.stderr.write calls)
|
|
306
|
+
*/
|
|
307
|
+
write(level, message) {
|
|
308
|
+
const ts = this.timestamp();
|
|
309
|
+
const line = `[${ts}] ${redactExternalCliToken(message)}
|
|
310
|
+
`;
|
|
311
|
+
try {
|
|
312
|
+
fs3.appendFileSync(this.filePath(level), line);
|
|
313
|
+
} catch {
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/** Informational log */
|
|
317
|
+
info(message) {
|
|
318
|
+
this.write("info", message);
|
|
319
|
+
}
|
|
320
|
+
/** Warning log */
|
|
321
|
+
warn(message) {
|
|
322
|
+
this.write("warning", message);
|
|
323
|
+
}
|
|
324
|
+
/** Error log */
|
|
325
|
+
error(message) {
|
|
326
|
+
this.write("error", message);
|
|
327
|
+
}
|
|
328
|
+
/** Log HTTP API request details */
|
|
329
|
+
api(method, url, status, reqBody, respBody) {
|
|
330
|
+
const parts = [`API ${method} ${url} \u2192 HTTP ${status}`];
|
|
331
|
+
if (reqBody !== void 0 && reqBody !== null) {
|
|
332
|
+
const s = typeof reqBody === "string" ? reqBody : JSON.stringify(reqBody);
|
|
333
|
+
parts.push(`REQ: ${s.slice(0, 500)}`);
|
|
334
|
+
}
|
|
335
|
+
if (respBody !== void 0 && respBody !== null) {
|
|
336
|
+
const s = typeof respBody === "string" ? respBody : JSON.stringify(respBody);
|
|
337
|
+
parts.push(`RESP: ${s.slice(0, 500)}`);
|
|
338
|
+
}
|
|
339
|
+
this.info(parts.join(" | "));
|
|
340
|
+
}
|
|
341
|
+
/** Log command execution (sensitive flags redacted to ***) */
|
|
342
|
+
command(name, args, sensitiveFlags = []) {
|
|
343
|
+
const normalizeFlagName = (name2) => name2.toLowerCase().replace(/[-_]/g, "");
|
|
344
|
+
const explicitSensitive = new Set(Array.from(sensitiveFlags, normalizeFlagName));
|
|
345
|
+
const SENSITIVE = ["token", "apikey", "secret", "accesstoken", "headers"];
|
|
346
|
+
const isSensitive = (k) => {
|
|
347
|
+
const normalized = normalizeFlagName(k);
|
|
348
|
+
return explicitSensitive.has(normalized) || SENSITIVE.some((s) => normalized.includes(s));
|
|
349
|
+
};
|
|
350
|
+
const filtered = Object.entries(args).filter(([, v]) => v !== void 0 && v !== null && v !== "").map(([k, v]) => `--${k}=${isSensitive(k) ? "***" : JSON.stringify(v)}`).join(" ");
|
|
351
|
+
this.info(`CMD ${name}${filtered ? " " + filtered : ""}`);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
var logger = new Logger();
|
|
355
|
+
|
|
215
356
|
export {
|
|
216
357
|
__require,
|
|
217
358
|
__esm,
|
|
@@ -219,11 +360,21 @@ export {
|
|
|
219
360
|
__export,
|
|
220
361
|
__toESM,
|
|
221
362
|
__toCommonJS,
|
|
222
|
-
logger,
|
|
223
363
|
PermissionError,
|
|
224
364
|
isApiErrorType,
|
|
225
365
|
CliValidationError,
|
|
226
366
|
CliApiError,
|
|
227
367
|
CommunityReportError,
|
|
228
|
-
LocalDataUploadError
|
|
368
|
+
LocalDataUploadError,
|
|
369
|
+
kbExecutionContextRequired,
|
|
370
|
+
isKbQueryPath,
|
|
371
|
+
readKbExecutionContext,
|
|
372
|
+
kbReadHeaders,
|
|
373
|
+
normalizeUrl,
|
|
374
|
+
ExternalCliTokenError,
|
|
375
|
+
setExternalCliTokenFile,
|
|
376
|
+
readExternalCliToken,
|
|
377
|
+
externalCliTokenRequestOptions,
|
|
378
|
+
redactExternalCliToken,
|
|
379
|
+
logger
|
|
229
380
|
};
|