@agentearth.ai/cli 0.1.0-beta.1 → 0.1.0-beta.3
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 +1 -1
- package/dist/commands/execute.js +24 -1
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/list.js +10 -0
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/login.js +14 -8
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/update.js +5 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/updateCheck.js +20 -3
- package/dist/commands/updateCheck.js.map +1 -1
- package/dist/commands/updateHint.js +6 -4
- package/dist/commands/updateHint.js.map +1 -1
- package/dist/commands/updateNpm.js +7 -0
- package/dist/commands/updateNpm.js.map +1 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.js +6 -3
- package/dist/constants.js.map +1 -1
- package/dist/core/args.js +15 -7
- package/dist/core/args.js.map +1 -1
- package/dist/core/backendErrors.js +3 -0
- package/dist/core/backendErrors.js.map +1 -1
- package/dist/core/errors.js +3 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/hiddenInput.js +10 -0
- package/dist/core/hiddenInput.js.map +1 -1
- package/dist/core/http.d.ts +25 -1
- package/dist/core/http.js +71 -16
- package/dist/core/http.js.map +1 -1
- package/dist/core/output.js +3 -1
- package/dist/core/output.js.map +1 -1
- package/dist/storage/credentials.d.ts +5 -1
- package/dist/storage/credentials.js +18 -6
- package/dist/storage/credentials.js.map +1 -1
- package/dist/storage/fileProtection.js +4 -0
- package/dist/storage/fileProtection.js.map +1 -1
- package/dist/storage/paths.d.ts +1 -0
- package/dist/storage/paths.js +6 -0
- package/dist/storage/paths.js.map +1 -1
- package/dist/storage/session.js +91 -23
- package/dist/storage/session.js.map +1 -1
- package/dist/storage/telemetryQueue.js +6 -0
- package/dist/storage/telemetryQueue.js.map +1 -1
- package/dist/storage/telemetryUploadState.d.ts +13 -0
- package/dist/storage/telemetryUploadState.js +84 -0
- package/dist/storage/telemetryUploadState.js.map +1 -0
- package/dist/storage/updateCache.js +2 -2
- package/dist/telemetry/uploader.js +104 -29
- package/dist/telemetry/uploader.js.map +1 -1
- package/dist/types/cli.d.ts +1 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { CliError } from "./errors.js";
|
|
9
9
|
export function mapBackendError(operation, errorMsg) {
|
|
10
|
+
// 命令模块在发现 error_no 非 0 时进入这里,把后端自由文本收敛成 CLI 稳定错误码。
|
|
10
11
|
// 后端错误文案可能为空,先兜底成空字符串,再统一转小写,方便 includes 判断。
|
|
11
12
|
const normalized = (errorMsg ?? "").toLowerCase();
|
|
12
13
|
// 鉴权错误在所有接口里含义一致:key 不可用,需要重新 login。
|
|
@@ -33,10 +34,12 @@ export function mapBackendError(operation, errorMsg) {
|
|
|
33
34
|
return backendVisibleError("backend_error", "Backend returned an error.", "Retry later.");
|
|
34
35
|
}
|
|
35
36
|
function backendVisibleError(code, message, hint) {
|
|
37
|
+
// 这里集中创建 telemetryEligible=false 的错误,避免各分支忘记关闭重复埋点。
|
|
36
38
|
// 这些错误来自后端 error_no/error_msg,后端业务日志已经可见,CLI 不重复上传。
|
|
37
39
|
return new CliError(code, message, hint, 1, { telemetryEligible: false });
|
|
38
40
|
}
|
|
39
41
|
function isAuthError(message) {
|
|
42
|
+
// 这里用 includes 而不是精确等于,是为了兼容后端包裹前缀、英文句子或网关文案。
|
|
40
43
|
// 兼容后端可能返回的几种 key 无效/无权限表达。
|
|
41
44
|
return message.includes("invalid_api_key")
|
|
42
45
|
|| message.includes("x-api-key has expired")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backendErrors.js","sourceRoot":"","sources":["../../src/core/backendErrors.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"backendErrors.js","sourceRoot":"","sources":["../../src/core/backendErrors.ts"],"names":[],"mappings":"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"}
|
package/dist/core/errors.js
CHANGED
|
@@ -15,6 +15,7 @@ export class CliError extends Error {
|
|
|
15
15
|
// 是否允许作为 CLI 本地埋点上传;后端已经可见的错误会显式置为 false。
|
|
16
16
|
telemetryEligible;
|
|
17
17
|
constructor(code, message, hint, exitCode = 1, options = {}) {
|
|
18
|
+
// 构造函数把“机器可读的 code”和“人/agent 可读的 message/hint”绑在一起。
|
|
18
19
|
// 调用父类 Error,让错误对象拥有 message 和 stack。
|
|
19
20
|
super(message);
|
|
20
21
|
// 设置 name,方便调试时看出这是项目自定义错误。
|
|
@@ -22,6 +23,7 @@ export class CliError extends Error {
|
|
|
22
23
|
this.code = code;
|
|
23
24
|
this.hint = hint;
|
|
24
25
|
this.exitCode = exitCode;
|
|
26
|
+
// 默认认为本地错误需要埋点;后端可见错误由创建方显式传 telemetryEligible=false。
|
|
25
27
|
this.telemetryEligible = options.telemetryEligible ?? true;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
@@ -30,6 +32,7 @@ export function usageError(message, hint = "Run ae --help.") {
|
|
|
30
32
|
return new CliError("usage_error", message, hint, 2);
|
|
31
33
|
}
|
|
32
34
|
export function normalizeUnknownError(error) {
|
|
35
|
+
// main.ts 的 catch 会调用这里,所以这个函数是所有未知异常的最后一道稳定输出防线。
|
|
33
36
|
// 如果本来就是 CliError,说明上游已经完成归因,直接返回即可。
|
|
34
37
|
if (error instanceof CliError) {
|
|
35
38
|
return error;
|
package/dist/core/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmDH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,yBAAyB;IAChB,IAAI,CAAY;IACzB,6BAA6B;IACpB,IAAI,CAAS;IACtB,oCAAoC;IAC3B,QAAQ,CAAS;IAC1B,0CAA0C;IACjC,iBAAiB,CAAU;IAEpC,YAAY,IAAe,EAAE,OAAe,EAAE,IAAY,EAAE,QAAQ,GAAG,CAAC,EAAE,UAA2B,EAAE;QACrG,oDAAoD;QACpD,sCAAsC;QACtC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,4BAA4B;QAC5B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,sDAAsD;QACtD,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,IAAI,CAAC;IAC7D,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,IAAI,GAAG,gBAAgB;IACjE,0BAA0B;IAC1B,OAAO,IAAI,QAAQ,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,kDAAkD;IAClD,qCAAqC;IACrC,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gDAAgD;IAChD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IAED,4CAA4C;IAC5C,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,yBAAyB,CAAC,CAAC;AAC3E,CAAC"}
|
package/dist/core/hiddenInput.js
CHANGED
|
@@ -9,11 +9,15 @@ import { emitKeypressEvents } from "node:readline";
|
|
|
9
9
|
import { CliError } from "./errors.js";
|
|
10
10
|
export async function readHiddenInput(promptText, input = process.stdin, output = process.stderr) {
|
|
11
11
|
// 非 TTY 场景通常是 agent/脚本调用,不能阻塞等待人工输入。
|
|
12
|
+
// isTTY 表示“这个流连接的是终端窗口”;如果 stdin 来自管道或文件,这里会是 false。
|
|
13
|
+
// setRawMode 是 Node 终端输入的低层能力;没有它就无法做到逐键读取且不回显。
|
|
12
14
|
if (!input.isTTY || !output.isTTY || typeof input.setRawMode !== "function") {
|
|
13
15
|
throw new CliError("auth_missing", "Interactive API key prompt requires a TTY.", "Pipe the API key into ae login --api-key-stdin.");
|
|
14
16
|
}
|
|
15
17
|
return new Promise((resolve, reject) => {
|
|
18
|
+
// value 是用户已经输入但尚未提交的 API key。
|
|
16
19
|
let value = "";
|
|
20
|
+
// 如果进入本函数前终端已经处于 raw mode,退出时需要恢复成原状态。
|
|
17
21
|
const previousRawMode = input.isRaw === true;
|
|
18
22
|
const cleanup = (writeNewline) => {
|
|
19
23
|
// 无论成功、取消还是异常,都恢复进入前的 raw mode。
|
|
@@ -24,16 +28,19 @@ export async function readHiddenInput(promptText, input = process.stdin, output
|
|
|
24
28
|
}
|
|
25
29
|
};
|
|
26
30
|
const onKeypress = (character, key = {}) => {
|
|
31
|
+
// Ctrl+C 代表用户取消输入。这里抛 auth_missing,而不是让进程直接异常退出。
|
|
27
32
|
if (key.ctrl && key.name === "c") {
|
|
28
33
|
cleanup(true);
|
|
29
34
|
reject(new CliError("auth_missing", "API key input cancelled.", "Pipe the API key into ae login --api-key-stdin."));
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
37
|
+
// Enter/Return 表示输入结束,此时把当前 value 交给调用方。
|
|
32
38
|
if (key.name === "return" || key.name === "enter") {
|
|
33
39
|
cleanup(true);
|
|
34
40
|
resolve(value);
|
|
35
41
|
return;
|
|
36
42
|
}
|
|
43
|
+
// Backspace 只影响内存里的 value,不在终端里删除字符,因为输入本来就没有回显。
|
|
37
44
|
if (key.name === "backspace") {
|
|
38
45
|
value = value.slice(0, -1);
|
|
39
46
|
return;
|
|
@@ -43,9 +50,12 @@ export async function readHiddenInput(promptText, input = process.stdin, output
|
|
|
43
50
|
value += character;
|
|
44
51
|
}
|
|
45
52
|
};
|
|
53
|
+
// 先输出提示语,再启用 keypress 事件和 raw mode。
|
|
54
|
+
// raw mode 下,终端会把每个按键立即交给程序,而不是等用户按 Enter。
|
|
46
55
|
output.write(promptText);
|
|
47
56
|
emitKeypressEvents(input);
|
|
48
57
|
input.setRawMode(true);
|
|
58
|
+
// resume 让 stdin 从暂停状态开始发事件;否则 keypress 监听器可能收不到输入。
|
|
49
59
|
input.resume();
|
|
50
60
|
input.on("keypress", onKeypress);
|
|
51
61
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hiddenInput.js","sourceRoot":"","sources":["../../src/core/hiddenInput.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsBvC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,QAAQ,OAAO,CAAC,KAA0B,EAC1C,SAAS,OAAO,CAAC,MAA4B;IAE7C,qCAAqC;IACrC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC5E,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,4CAA4C,EAAE,iDAAiD,CAAC,CAAC;IACtI,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,MAAM,eAAe,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;QAE7C,MAAM,OAAO,GAAG,CAAC,YAAqB,EAAQ,EAAE;YAC9C,gCAAgC;YAChC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAClC,KAAK,CAAC,UAAU,EAAE,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,MAAoB,EAAE,EAAQ,EAAE;YACrE,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,QAAQ,CAAC,cAAc,EAAE,0BAA0B,EAAE,iDAAiD,CAAC,CAAC,CAAC;gBACpH,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO,CAAC,KAAK,CAAC,CAAC;gBACf,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC7B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YAED,8BAA8B;YAC9B,IAAI,SAAS,IAAI,SAAS,IAAI,GAAG,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC5D,KAAK,IAAI,SAAS,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACzB,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvB,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"hiddenInput.js","sourceRoot":"","sources":["../../src/core/hiddenInput.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsBvC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,QAAQ,OAAO,CAAC,KAA0B,EAC1C,SAAS,OAAO,CAAC,MAA4B;IAE7C,qCAAqC;IACrC,qDAAqD;IACrD,gDAAgD;IAChD,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAC5E,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,4CAA4C,EAAE,iDAAiD,CAAC,CAAC;IACtI,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,+BAA+B;QAC/B,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,uCAAuC;QACvC,MAAM,eAAe,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;QAE7C,MAAM,OAAO,GAAG,CAAC,YAAqB,EAAQ,EAAE;YAC9C,gCAAgC;YAChC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAClC,KAAK,CAAC,UAAU,EAAE,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,MAAoB,EAAE,EAAQ,EAAE;YACrE,iDAAiD;YACjD,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,QAAQ,CAAC,cAAc,EAAE,0BAA0B,EAAE,iDAAiD,CAAC,CAAC,CAAC;gBACpH,OAAO;YACT,CAAC;YAED,yCAAyC;YACzC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO,CAAC,KAAK,CAAC,CAAC;gBACf,OAAO;YACT,CAAC;YAED,iDAAiD;YACjD,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC7B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YAED,8BAA8B;YAC9B,IAAI,SAAS,IAAI,SAAS,IAAI,GAAG,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC5D,KAAK,IAAI,SAAS,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;QAEF,oCAAoC;QACpC,2CAA2C;QAC3C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACzB,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACvB,oDAAoD;QACpD,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/core/http.d.ts
CHANGED
|
@@ -5,5 +5,29 @@ export interface HttpOptions {
|
|
|
5
5
|
}
|
|
6
6
|
export type QueryValue = string | number | boolean;
|
|
7
7
|
export declare function postJson<TResponse>(pathOrUrl: string, body: unknown, options: HttpOptions): Promise<TResponse>;
|
|
8
|
-
export
|
|
8
|
+
export type TelemetryPostResult = {
|
|
9
|
+
kind: "success";
|
|
10
|
+
status: number;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "permanent_failure";
|
|
13
|
+
status: number;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "auth_failed";
|
|
16
|
+
status: 401 | 403;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "payload_too_large";
|
|
19
|
+
status: 413;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "rate_limited";
|
|
22
|
+
status: 429;
|
|
23
|
+
retryAfterMs?: number;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "server_error";
|
|
26
|
+
status: number;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "network_error";
|
|
29
|
+
} | {
|
|
30
|
+
kind: "timeout";
|
|
31
|
+
};
|
|
32
|
+
export declare function postTelemetryJson(pathOrUrl: string, body: unknown, options: HttpOptions): Promise<TelemetryPostResult>;
|
|
9
33
|
export declare function getJson<TResponse>(pathOrUrl: string, query: Record<string, QueryValue>, options: HttpOptions): Promise<TResponse>;
|
package/dist/core/http.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 业务接口和埋点接口的响应规则不同:
|
|
5
5
|
* - recommend/list/detail/execute 这类业务接口需要返回 JSON,命令模块会读取 error_no。
|
|
6
|
-
* - CLI
|
|
6
|
+
* - CLI 埋点上传接口按 HTTP 状态分类,不要求响应体。
|
|
7
7
|
*
|
|
8
8
|
* 因此这里提供两类 helper:`postJson/getJson` 用于业务接口,
|
|
9
|
-
* `
|
|
9
|
+
* `postTelemetryJson` 用于埋点上传。
|
|
10
10
|
*/
|
|
11
11
|
import { CliError } from "./errors.js";
|
|
12
12
|
export async function postJson(pathOrUrl, body, options) {
|
|
@@ -17,13 +17,58 @@ export async function postJson(pathOrUrl, body, options) {
|
|
|
17
17
|
body: JSON.stringify(body)
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
-
export async function
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
export async function postTelemetryJson(pathOrUrl, body, options) {
|
|
21
|
+
// AbortController 是 Node/fetch 的标准超时写法:到点后主动取消请求。
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
// setTimeout 返回的 timer 后面必须 clear,避免 CLI 命令结束后进程还被 timer 挂住。
|
|
24
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
25
|
+
try {
|
|
26
|
+
// 埋点接口和业务接口共用 X-Api-Key;body 在这里统一序列化,调用方不直接碰 fetch 细节。
|
|
27
|
+
const response = await fetch(resolveUrl(pathOrUrl, options.baseUrl), {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
"X-Api-Key": options.apiKey
|
|
32
|
+
},
|
|
33
|
+
body: JSON.stringify(body),
|
|
34
|
+
signal: controller.signal
|
|
35
|
+
});
|
|
36
|
+
// response.ok 表示 HTTP 2xx,不要求必须是 200;后端未来返回 202 也会被视为成功。
|
|
37
|
+
if (response.ok) {
|
|
38
|
+
return { kind: "success", status: response.status };
|
|
39
|
+
}
|
|
40
|
+
// 当前后端第一版主要返回 401;保留 403 是为了兼容未来权限细分。
|
|
41
|
+
if (response.status === 401 || response.status === 403) {
|
|
42
|
+
return { kind: "auth_failed", status: response.status };
|
|
43
|
+
}
|
|
44
|
+
// 413 表示请求体超过后端限制,uploader.ts 会尝试把批次拆小。
|
|
45
|
+
if (response.status === 413) {
|
|
46
|
+
return { kind: "payload_too_large", status: 413 };
|
|
47
|
+
}
|
|
48
|
+
// 429 如果出现,优先尊重 Retry-After;没有该头时交给调用方用默认退避。
|
|
49
|
+
if (response.status === 429) {
|
|
50
|
+
return {
|
|
51
|
+
kind: "rate_limited",
|
|
52
|
+
status: 429,
|
|
53
|
+
retryAfterMs: parseRetryAfterMs(response.headers.get("retry-after"))
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// 5xx 通常是后端临时问题,队列应该保留,等待之后重试。
|
|
57
|
+
if (response.status >= 500) {
|
|
58
|
+
return { kind: "server_error", status: response.status };
|
|
59
|
+
}
|
|
60
|
+
// 走到这里的是 4xx 里没有单独处理的永久错误,例如 400 或未来可能的 415。
|
|
61
|
+
return { kind: "permanent_failure", status: response.status };
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
65
|
+
return { kind: "timeout" };
|
|
66
|
+
}
|
|
67
|
+
return { kind: "network_error" };
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
clearTimeout(timeout);
|
|
71
|
+
}
|
|
27
72
|
}
|
|
28
73
|
export async function getJson(pathOrUrl, query, options) {
|
|
29
74
|
// GET 请求没有 body,参数统一拼到 URL 的 query string 上。
|
|
@@ -36,13 +81,6 @@ async function requestJson(pathOrUrl, options, init) {
|
|
|
36
81
|
const response = await request(pathOrUrl, options, init);
|
|
37
82
|
return parseJsonResponse(response);
|
|
38
83
|
}
|
|
39
|
-
async function requestNoResponse(pathOrUrl, options, init) {
|
|
40
|
-
// 先发请求,再只判断 HTTP 状态码。
|
|
41
|
-
const response = await request(pathOrUrl, options, init);
|
|
42
|
-
if (!response.ok) {
|
|
43
|
-
throw new CliError("backend_error", `Backend returned HTTP ${response.status}.`, "Retry later.", 1, { telemetryEligible: false });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
84
|
async function request(pathOrUrl, options, init) {
|
|
47
85
|
// AbortController 用来在 timeoutMs 后主动取消 fetch。
|
|
48
86
|
const controller = new AbortController();
|
|
@@ -137,6 +175,23 @@ function resolveUrl(pathOrUrl, baseUrl) {
|
|
|
137
175
|
// 其他接口通常传相对 path,这里和 baseUrl 拼起来,并处理多余斜杠。
|
|
138
176
|
return `${baseUrl.replace(/\/$/, "")}/${pathOrUrl.replace(/^\//, "")}`;
|
|
139
177
|
}
|
|
178
|
+
function parseRetryAfterMs(value) {
|
|
179
|
+
// Retry-After 既可能是秒数,也可能是 HTTP 日期;两种格式都要兼容。
|
|
180
|
+
if (!value) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
// 第一种格式:Retry-After: 120,表示 120 秒后重试。
|
|
184
|
+
const seconds = Number(value);
|
|
185
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
186
|
+
return Math.floor(seconds * 1000);
|
|
187
|
+
}
|
|
188
|
+
// 第二种格式:Retry-After: Wed, 21 Oct 2015 07:28:00 GMT。
|
|
189
|
+
const retryAt = Date.parse(value);
|
|
190
|
+
if (!Number.isFinite(retryAt)) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
return Math.max(0, retryAt - Date.now());
|
|
194
|
+
}
|
|
140
195
|
function isRecord(value) {
|
|
141
196
|
// object 会包含数组;响应 payload 的顶层必须是普通对象才可能有 error_no 字段。
|
|
142
197
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
package/dist/core/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAcvC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,SAAiB,EACjB,IAAa,EACb,OAAoB;IAEpB,8CAA8C;IAC9C,OAAO,WAAW,CAAY,SAAS,EAAE,OAAO,EAAE;QAChD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;AACL,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"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"}
|
package/dist/core/output.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export function writeSuccess(result, json) {
|
|
2
|
+
// result 已经由具体 command 组装好,这里不再判断字段含义,只负责选择输出形式。
|
|
2
3
|
// json=true 时,直接输出完整 JSON,方便 agent 解析字段。
|
|
3
4
|
if (json) {
|
|
4
5
|
// null, 2 表示格式化缩进 2 个空格;这不影响 JSON 可解析性。
|
|
@@ -16,6 +17,7 @@ export function writeSuccess(result, json) {
|
|
|
16
17
|
export function writeError(error, json) {
|
|
17
18
|
// 失败结构固定为 { error: { code, message, hint } }。
|
|
18
19
|
// 不再输出布尔 success 字段,失败由非 0 exit code 表示。
|
|
20
|
+
// payload 是 stderr 的最终 JSON 形状;所有失败都必须长成这个样子。
|
|
19
21
|
const payload = {
|
|
20
22
|
error: {
|
|
21
23
|
code: error.code,
|
|
@@ -23,7 +25,7 @@ export function writeError(error, json) {
|
|
|
23
25
|
hint: error.hint
|
|
24
26
|
}
|
|
25
27
|
};
|
|
26
|
-
// agent
|
|
28
|
+
// agent 模式保留完整 JSON;人类模式只显示 code/message/hint,减少终端噪音。
|
|
27
29
|
const output = json
|
|
28
30
|
? JSON.stringify(payload, null, 2)
|
|
29
31
|
: `${error.code}: ${error.message}\nHint: ${error.hint}`;
|
package/dist/core/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/core/output.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,YAAY,CAAC,MAAsB,EAAE,IAAa;IAChE,yCAAyC;IACzC,IAAI,IAAI,EAAE,CAAC;QACT,wCAAwC;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,0CAA0C;IAC1C,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAe,EAAE,IAAa;IACvD,8CAA8C;IAC9C,yCAAyC;IACzC,MAAM,OAAO,GAAmB;QAC9B,KAAK,EAAE;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB;KACF,CAAC;IAEF,
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/core/output.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,YAAY,CAAC,MAAsB,EAAE,IAAa;IAChE,iDAAiD;IACjD,yCAAyC;IACzC,IAAI,IAAI,EAAE,CAAC;QACT,wCAAwC;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,0CAA0C;IAC1C,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAe,EAAE,IAAa;IACvD,8CAA8C;IAC9C,yCAAyC;IACzC,8CAA8C;IAC9C,MAAM,OAAO,GAAmB;QAC9B,KAAK,EAAE;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB;KACF,CAAC;IAEF,sDAAsD;IACtD,MAAM,MAAM,GAAG,IAAI;QACjB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC;IAE3D,qCAAqC;IACrC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { GlobalOptions } from "../types/cli.js";
|
|
2
|
+
import { type ProtectSensitiveFileOptions } from "./fileProtection.js";
|
|
2
3
|
export interface AgentEarthCredentials {
|
|
3
4
|
api_key: string;
|
|
4
5
|
saved_at: string;
|
|
5
6
|
}
|
|
7
|
+
export interface WriteCredentialsOptions {
|
|
8
|
+
fileProtection?: ProtectSensitiveFileOptions;
|
|
9
|
+
}
|
|
6
10
|
export declare function readCredentials(): Promise<AgentEarthCredentials | null>;
|
|
7
|
-
export declare function writeCredentials(apiKey: string): Promise<void>;
|
|
11
|
+
export declare function writeCredentials(apiKey: string, options?: WriteCredentialsOptions): Promise<void>;
|
|
8
12
|
export declare function resolveApiKey(options: GlobalOptions): Promise<string>;
|
|
9
13
|
export declare function resolveLoginApiKey(options: GlobalOptions): string;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 本文件只负责本地读写和优先级选择,不负责后端验证。
|
|
11
11
|
*/
|
|
12
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
12
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
13
13
|
import { CliError } from "../core/errors.js";
|
|
14
14
|
import { protectSensitiveFile } from "./fileProtection.js";
|
|
15
15
|
import { ensureAgentEarthDir, getCredentialsPath } from "./paths.js";
|
|
@@ -25,7 +25,7 @@ export async function readCredentials() {
|
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
export async function writeCredentials(apiKey) {
|
|
28
|
+
export async function writeCredentials(apiKey, options = {}) {
|
|
29
29
|
// 写文件前先确保数据目录存在。
|
|
30
30
|
await ensureAgentEarthDir();
|
|
31
31
|
// 进入落盘前再做一次 trim,确保 credentials.json 不保存前后空白。
|
|
@@ -35,10 +35,19 @@ export async function writeCredentials(apiKey) {
|
|
|
35
35
|
saved_at: new Date().toISOString()
|
|
36
36
|
};
|
|
37
37
|
const filePath = getCredentialsPath();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const temporaryPath = makeTemporaryCredentialsPath(filePath);
|
|
39
|
+
try {
|
|
40
|
+
// 临时文件里已经包含 API key,所以必须先保护临时文件,再发布成正式 credentials.json。
|
|
41
|
+
await writeFile(temporaryPath, `${JSON.stringify(credentials, null, 2)}\n`, { mode: 0o600 });
|
|
42
|
+
// 如果权限收紧失败,rename 不会发生,用户不会得到一个“登录失败但 key 已发布”的状态。
|
|
43
|
+
await protectSensitiveFile(temporaryPath, options.fileProtection);
|
|
44
|
+
await rename(temporaryPath, filePath);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
// 临时文件里包含 API key;任何失败都要 best-effort 删除。
|
|
48
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
42
51
|
}
|
|
43
52
|
export async function resolveApiKey(options) {
|
|
44
53
|
// 1. 命令行临时 key 优先级最高,适合调试或一次性覆盖。
|
|
@@ -75,6 +84,9 @@ function normalizeApiKey(value) {
|
|
|
75
84
|
}
|
|
76
85
|
return normalized;
|
|
77
86
|
}
|
|
87
|
+
function makeTemporaryCredentialsPath(filePath) {
|
|
88
|
+
return `${filePath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
89
|
+
}
|
|
78
90
|
function normalizeCredentials(value) {
|
|
79
91
|
// 只有非空字符串 api_key 才能作为真实凭据;损坏结构一律当作没有本地凭据。
|
|
80
92
|
if (!isRecord(value) || typeof value.api_key !== "string") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/storage/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/storage/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ import { execFile } from "node:child_process";
|
|
|
8
8
|
import { chmod, stat } from "node:fs/promises";
|
|
9
9
|
import { platform as currentPlatform } from "node:os";
|
|
10
10
|
import { promisify } from "node:util";
|
|
11
|
+
// promisify 把 Node 回调风格的 execFile 转成 Promise,方便 async/await 调用。
|
|
11
12
|
const execFileAsync = promisify(execFile);
|
|
12
13
|
export async function pathExists(filePath) {
|
|
13
14
|
// 写入前只需要区分“是否已经有这个文件”,用于避免重复执行昂贵的 ACL 命令。
|
|
@@ -20,6 +21,7 @@ export async function pathExists(filePath) {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
export async function protectSensitiveFile(filePath, options = {}) {
|
|
24
|
+
// 没有传测试 platform 时,使用 Node 的 os.platform() 判断真实系统。
|
|
23
25
|
const targetPlatform = options.platform ?? currentPlatform();
|
|
24
26
|
if (targetPlatform === "win32") {
|
|
25
27
|
await protectWindowsSensitiveFile(filePath, options.runner ?? runCommand);
|
|
@@ -39,9 +41,11 @@ async function protectWindowsSensitiveFile(filePath, runner) {
|
|
|
39
41
|
await runner("icacls", [filePath, "/inheritance:r", "/grant:r", `*${sid}:F`]);
|
|
40
42
|
}
|
|
41
43
|
export function parseWindowsUserSid(output) {
|
|
44
|
+
// whoami /user /fo csv 的输出里会包含 S-1-... 形式的 SID,这里只抽取 SID 本身。
|
|
42
45
|
return output.match(/S-\d-\d+(?:-\d+)+/)?.[0] ?? null;
|
|
43
46
|
}
|
|
44
47
|
async function runCommand(command, args) {
|
|
48
|
+
// execFile 不经过 shell,参数作为数组传入,比拼接命令字符串更安全。
|
|
45
49
|
const result = await execFileAsync(command, [...args], { encoding: "utf8", windowsHide: true });
|
|
46
50
|
return {
|
|
47
51
|
stdout: String(result.stdout),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileProtection.js","sourceRoot":"","sources":["../../src/storage/fileProtection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"fileProtection.js","sourceRoot":"","sources":["../../src/storage/fileProtection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,gEAAgE;AAChE,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAmB1C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,0CAA0C;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAgB,EAAE,UAAuC,EAAE;IACpG,mDAAmD;IACnD,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;IAE7D,IAAI,cAAc,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,2BAA2B,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,MAAM,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,KAAK,UAAU,2BAA2B,CAAC,QAAgB,EAAE,MAAmC;IAC9F,mCAAmC;IACnC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,mDAAmD;IACnD,qDAAqD;IACrD,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,6DAA6D;IAC7D,OAAO,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,IAAuB;IAChE,2CAA2C;IAC3C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IAChG,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;KAC9B,CAAC;AACJ,CAAC"}
|
package/dist/storage/paths.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ export declare function getAgentEarthDir(): string;
|
|
|
2
2
|
export declare function getCredentialsPath(): string;
|
|
3
3
|
export declare function getSessionPath(): string;
|
|
4
4
|
export declare function getTelemetryQueuePath(): string;
|
|
5
|
+
export declare function getTelemetryUploadStatePath(): string;
|
|
5
6
|
export declare function getUpdateCachePath(): string;
|
|
6
7
|
export declare function ensureAgentEarthDir(): Promise<void>;
|
package/dist/storage/paths.js
CHANGED
|
@@ -22,6 +22,7 @@ export function getAgentEarthDir() {
|
|
|
22
22
|
return path.join(homedir(), ".config", "agentearth");
|
|
23
23
|
}
|
|
24
24
|
function resolveLocalAppData() {
|
|
25
|
+
// process.env 是 Node 读取环境变量的方式;?.trim() 表示变量不存在时不报错。
|
|
25
26
|
const localAppData = process.env.LOCALAPPDATA?.trim();
|
|
26
27
|
// LOCALAPPDATA 为空白时不能作为目录,否则 credentials 可能落到当前工作目录。
|
|
27
28
|
return localAppData || path.join(homedir(), "AppData", "Local");
|
|
@@ -38,11 +39,16 @@ export function getTelemetryQueuePath() {
|
|
|
38
39
|
// events.jsonl 一行一个埋点事件,上传成功后从队头删除。
|
|
39
40
|
return path.join(getAgentEarthDir(), "events.jsonl");
|
|
40
41
|
}
|
|
42
|
+
export function getTelemetryUploadStatePath() {
|
|
43
|
+
// telemetry-upload-state 保存上传暂停窗口和 key 指纹,不保存完整 API key。
|
|
44
|
+
return path.join(getAgentEarthDir(), "telemetry-upload-state.json");
|
|
45
|
+
}
|
|
41
46
|
export function getUpdateCachePath() {
|
|
42
47
|
// update-cache 保存版本检查结果,不保存 API key。
|
|
43
48
|
return path.join(getAgentEarthDir(), "update-cache.json");
|
|
44
49
|
}
|
|
45
50
|
export async function ensureAgentEarthDir() {
|
|
51
|
+
// 所有本地文件写入前都先调用这里,避免各模块重复 mkdir 逻辑。
|
|
46
52
|
const dir = getAgentEarthDir();
|
|
47
53
|
// recursive=true 表示父目录不存在时一起创建。
|
|
48
54
|
// mode=0o700 表示当前用户可读写执行,其他用户无权限;Windows 上会部分依赖 ACL。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/storage/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,gBAAgB;IAC9B,4DAA4D;IAC5D,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,kCAAkC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,0CAA0C;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACtD,qDAAqD;IACrD,OAAO,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,8BAA8B;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,gCAAgC;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,oCAAoC;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,qCAAqC;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,mBAAmB,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAE/B,gCAAgC;IAChC,qDAAqD;IACrD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEnD,uDAAuD;IACvD,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/storage/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,gBAAgB;IAC9B,4DAA4D;IAC5D,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,kCAAkC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,0CAA0C;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,mBAAmB;IAC1B,qDAAqD;IACrD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IACtD,qDAAqD;IACrD,OAAO,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,8BAA8B;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,gCAAgC;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,oCAAoC;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,cAAc,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,yDAAyD;IACzD,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,6BAA6B,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,qCAAqC;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,mBAAmB,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,oCAAoC;IACpC,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAE/B,gCAAgC;IAChC,qDAAqD;IACrD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEnD,uDAAuD;IACvD,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
|