@agentearth.ai/cli 0.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +89 -0
  2. package/bin/ae.mjs +31 -0
  3. package/dist/commands/detail.d.ts +2 -0
  4. package/dist/commands/detail.js +71 -0
  5. package/dist/commands/detail.js.map +1 -0
  6. package/dist/commands/execute.d.ts +2 -0
  7. package/dist/commands/execute.js +118 -0
  8. package/dist/commands/execute.js.map +1 -0
  9. package/dist/commands/list.d.ts +2 -0
  10. package/dist/commands/list.js +94 -0
  11. package/dist/commands/list.js.map +1 -0
  12. package/dist/commands/login.d.ts +2 -0
  13. package/dist/commands/login.js +96 -0
  14. package/dist/commands/login.js.map +1 -0
  15. package/dist/commands/recommend.d.ts +2 -0
  16. package/dist/commands/recommend.js +58 -0
  17. package/dist/commands/recommend.js.map +1 -0
  18. package/dist/commands/update.d.ts +2 -0
  19. package/dist/commands/update.js +67 -0
  20. package/dist/commands/update.js.map +1 -0
  21. package/dist/commands/updateCheck.d.ts +10 -0
  22. package/dist/commands/updateCheck.js +98 -0
  23. package/dist/commands/updateCheck.js.map +1 -0
  24. package/dist/commands/updateHint.d.ts +9 -0
  25. package/dist/commands/updateHint.js +25 -0
  26. package/dist/commands/updateHint.js.map +1 -0
  27. package/dist/commands/updateNpm.d.ts +13 -0
  28. package/dist/commands/updateNpm.js +64 -0
  29. package/dist/commands/updateNpm.js.map +1 -0
  30. package/dist/constants.d.ts +20 -0
  31. package/dist/constants.js +34 -0
  32. package/dist/constants.js.map +1 -0
  33. package/dist/core/args.d.ts +2 -0
  34. package/dist/core/args.js +110 -0
  35. package/dist/core/args.js.map +1 -0
  36. package/dist/core/backendErrors.d.ts +10 -0
  37. package/dist/core/backendErrors.js +69 -0
  38. package/dist/core/backendErrors.js.map +1 -0
  39. package/dist/core/errors.d.ts +20 -0
  40. package/dist/core/errors.js +44 -0
  41. package/dist/core/errors.js.map +1 -0
  42. package/dist/core/hiddenInput.d.ts +10 -0
  43. package/dist/core/hiddenInput.js +53 -0
  44. package/dist/core/hiddenInput.js.map +1 -0
  45. package/dist/core/http.d.ts +9 -0
  46. package/dist/core/http.js +144 -0
  47. package/dist/core/http.js.map +1 -0
  48. package/dist/core/output.d.ts +11 -0
  49. package/dist/core/output.js +33 -0
  50. package/dist/core/output.js.map +1 -0
  51. package/dist/main.d.ts +1 -0
  52. package/dist/main.js +300 -0
  53. package/dist/main.js.map +1 -0
  54. package/dist/storage/credentials.d.ts +9 -0
  55. package/dist/storage/credentials.js +97 -0
  56. package/dist/storage/credentials.js.map +1 -0
  57. package/dist/storage/fileProtection.d.ts +12 -0
  58. package/dist/storage/fileProtection.js +51 -0
  59. package/dist/storage/fileProtection.js.map +1 -0
  60. package/dist/storage/paths.d.ts +6 -0
  61. package/dist/storage/paths.js +55 -0
  62. package/dist/storage/paths.js.map +1 -0
  63. package/dist/storage/session.d.ts +23 -0
  64. package/dist/storage/session.js +175 -0
  65. package/dist/storage/session.js.map +1 -0
  66. package/dist/storage/telemetryQueue.d.ts +14 -0
  67. package/dist/storage/telemetryQueue.js +252 -0
  68. package/dist/storage/telemetryQueue.js.map +1 -0
  69. package/dist/storage/updateCache.d.ts +19 -0
  70. package/dist/storage/updateCache.js +80 -0
  71. package/dist/storage/updateCache.js.map +1 -0
  72. package/dist/telemetry/events.d.ts +42 -0
  73. package/dist/telemetry/events.js +80 -0
  74. package/dist/telemetry/events.js.map +1 -0
  75. package/dist/telemetry/uploader.d.ts +2 -0
  76. package/dist/telemetry/uploader.js +46 -0
  77. package/dist/telemetry/uploader.js.map +1 -0
  78. package/dist/types/api.d.ts +47 -0
  79. package/dist/types/api.js +9 -0
  80. package/dist/types/api.js.map +1 -0
  81. package/dist/types/cli.d.ts +42 -0
  82. package/dist/types/cli.js +9 -0
  83. package/dist/types/cli.js.map +1 -0
  84. package/package.json +29 -0
  85. package/skills/agentearth/SKILL.md +37 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `ae update` 命令入口。
3
+ *
4
+ * 本文件只编排 CLI 本地更新流程:
5
+ * 1. 读取 fresh update-cache;无缓存时执行 npm view 查询最新版本;
6
+ * 2. 无更新时直接输出 no-op;
7
+ * 3. 有更新时执行 npm install -g @agentearth.ai/cli@latest;
8
+ * 4. 更新后读取 ae --version 验证当前 PATH 下的 ae 是否真的变化。
9
+ */
10
+ import { CLI_VERSION } from "../constants.js";
11
+ import { CliError } from "../core/errors.js";
12
+ import { readOrRefreshUpdateCache } from "./updateCheck.js";
13
+ import { buildCliVersionCommand, buildNpmInstallLatestCommand, runProcess } from "./updateNpm.js";
14
+ export async function runUpdate(context) {
15
+ // update 是用户确认后的显式动作;没有 fresh cache 时也要主动查 npm registry。
16
+ const cache = await readOrRefreshUpdateCache({ throwOnFailure: true });
17
+ if (!cache) {
18
+ context.telemetry.updateResult = "failed";
19
+ throw new CliError("version_check_failed", "npm registry version check failed.", "Retry later or check npm registry/network access.");
20
+ }
21
+ if (!cache.has_update) {
22
+ context.telemetry.updateResult = "no_update";
23
+ return {
24
+ updated: false,
25
+ current_version: cache.current_version,
26
+ latest_version: cache.latest_version,
27
+ message: cache.message ?? "AgentEarth CLI is already up to date."
28
+ };
29
+ }
30
+ const startedAt = Date.now();
31
+ // cache 已经来自 npm view;这里执行固定 npm install latest,不让 agent 拼包名或平台命令。
32
+ const npmCommand = buildNpmInstallLatestCommand();
33
+ const npmResult = await runProcess(npmCommand.command, npmCommand.args);
34
+ if (npmResult.exitCode !== 0) {
35
+ context.telemetry.updateResult = "failed";
36
+ throw new CliError("update_failed", "npm install latest failed.", "Retry later or check npm global package permissions.");
37
+ }
38
+ // npm 返回成功后必须重新读取 ae --version,确认当前 PATH 下的 ae 是否真的更新。
39
+ const versionCommand = buildCliVersionCommand();
40
+ const versionResult = await runProcess(versionCommand.command, versionCommand.args);
41
+ const updatedVersion = versionResult.stdout.trim();
42
+ if (versionResult.exitCode !== 0 || !updatedVersion) {
43
+ context.telemetry.updateResult = "failed";
44
+ throw new CliError("update_verify_failed", "Updated CLI version could not be verified.", "Run ae --version and check that the updated ae command is on PATH.");
45
+ }
46
+ if (updatedVersion === CLI_VERSION) {
47
+ context.telemetry.updateResult = "failed";
48
+ throw new CliError("update_not_applied", "Update command completed but CLI version did not change.", "There may be multiple ae installations. Check PATH and npm global prefix.");
49
+ }
50
+ if (updatedVersion !== cache.latest_version) {
51
+ context.telemetry.updateResult = "failed";
52
+ throw new CliError("update_verify_failed", "Updated CLI version does not match the expected latest version.", "Run ae update again after refreshing the version cache.");
53
+ }
54
+ context.telemetry.updateResult = "updated";
55
+ const result = {
56
+ updated: true,
57
+ from_version: CLI_VERSION,
58
+ to_version: updatedVersion,
59
+ duration_ms: Date.now() - startedAt
60
+ };
61
+ const releaseNotes = Array.isArray(cache.release_notes) ? cache.release_notes : [];
62
+ if (releaseNotes.length > 0) {
63
+ result.release_notes = releaseNotes;
64
+ }
65
+ return result;
66
+ }
67
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type UpdateCache } from "../storage/updateCache.js";
2
+ export interface ReadOrRefreshUpdateOptions {
3
+ env?: NodeJS.ProcessEnv;
4
+ throwOnFailure?: boolean;
5
+ }
6
+ export declare function readOrRefreshUpdateCache(options?: ReadOrRefreshUpdateOptions): Promise<UpdateCache | null>;
7
+ export declare function refreshUpdateCacheFromNpm(env?: NodeJS.ProcessEnv): Promise<UpdateCache>;
8
+ export declare function readLatestVersionFromNpm(env?: NodeJS.ProcessEnv): Promise<string>;
9
+ export declare function parseNpmViewVersionOutput(stdout: string): string | null;
10
+ export declare function compareVersions(left: string, right: string): number;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * npm registry 版本检查模块。
3
+ *
4
+ * list/recommend 成功后会走这里做轻量检查:先复用 fresh update-cache,
5
+ * 缓存不存在或过期时再执行 npm view。工具发现主流程不能被更新检查阻断,
6
+ * 但 ae update 会把检查失败映射成稳定 version_check_failed。
7
+ */
8
+ import { CLI_VERSION, UPDATE_COMMAND_TEXT } from "../constants.js";
9
+ import { CliError } from "../core/errors.js";
10
+ import { readUpdateCache, writeUpdateCache } from "../storage/updateCache.js";
11
+ import { buildNpmViewVersionCommand, runProcess } from "./updateNpm.js";
12
+ export async function readOrRefreshUpdateCache(options = {}) {
13
+ const cache = await readUpdateCache();
14
+ if (cache) {
15
+ return cache;
16
+ }
17
+ const env = options.env ?? process.env;
18
+ if (isUpdateCheckSkipped(env) && !options.throwOnFailure) {
19
+ return null;
20
+ }
21
+ try {
22
+ return await refreshUpdateCacheFromNpm(env);
23
+ }
24
+ catch (error) {
25
+ if (options.throwOnFailure) {
26
+ throw error;
27
+ }
28
+ return null;
29
+ }
30
+ }
31
+ export async function refreshUpdateCacheFromNpm(env = process.env) {
32
+ const latestVersion = await readLatestVersionFromNpm(env);
33
+ const hasUpdate = compareVersions(latestVersion, CLI_VERSION) > 0;
34
+ return writeUpdateCache({
35
+ current_version: CLI_VERSION,
36
+ latest_version: latestVersion,
37
+ has_update: hasUpdate,
38
+ message: hasUpdate
39
+ ? `AgentEarth CLI ${latestVersion} is available.`
40
+ : "AgentEarth CLI is already up to date.",
41
+ update_command: UPDATE_COMMAND_TEXT
42
+ });
43
+ }
44
+ export async function readLatestVersionFromNpm(env = process.env) {
45
+ const command = buildNpmViewVersionCommand();
46
+ const result = await runProcess(command.command, command.args, env);
47
+ if (result.exitCode !== 0) {
48
+ throw versionCheckFailed();
49
+ }
50
+ const version = parseNpmViewVersionOutput(result.stdout);
51
+ if (!version) {
52
+ throw versionCheckFailed();
53
+ }
54
+ return version;
55
+ }
56
+ export function parseNpmViewVersionOutput(stdout) {
57
+ try {
58
+ const parsed = JSON.parse(stdout.trim());
59
+ if (typeof parsed === "string" && isVersionString(parsed)) {
60
+ return parsed;
61
+ }
62
+ return null;
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ export function compareVersions(left, right) {
69
+ const leftParts = parseVersionParts(left);
70
+ const rightParts = parseVersionParts(right);
71
+ if (!leftParts || !rightParts) {
72
+ return 0;
73
+ }
74
+ for (let index = 0; index < 3; index += 1) {
75
+ if (leftParts[index] > rightParts[index])
76
+ return 1;
77
+ if (leftParts[index] < rightParts[index])
78
+ return -1;
79
+ }
80
+ return 0;
81
+ }
82
+ function isUpdateCheckSkipped(env) {
83
+ return env.AE_SKIP_UPDATE_CHECK === "1" || env.AE_SKIP_UPDATE_CHECK === "true";
84
+ }
85
+ function isVersionString(value) {
86
+ return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/u.test(value);
87
+ }
88
+ function parseVersionParts(value) {
89
+ const match = /^(\d+)\.(\d+)\.(\d+)/u.exec(value);
90
+ if (!match) {
91
+ return null;
92
+ }
93
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
94
+ }
95
+ function versionCheckFailed() {
96
+ return new CliError("version_check_failed", "npm registry version check failed.", "Retry later or check npm registry/network access.");
97
+ }
98
+ //# sourceMappingURL=updateCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateCheck.js","sourceRoot":"","sources":["../../src/commands/updateCheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface UpdateHint {
2
+ has_update: true;
3
+ current_version: string;
4
+ latest_version: string;
5
+ message: string;
6
+ command: "ae update";
7
+ release_notes?: unknown[];
8
+ }
9
+ export declare function readUpdateHint(): Promise<UpdateHint | undefined>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 工具发现阶段的更新提示 helper。
3
+ *
4
+ * 这里优先消费 fresh update-cache;缓存失效时尝试 npm view 刷新。
5
+ * npm registry 检查失败不会影响工具发现主流程,只是不输出 update 字段。
6
+ */
7
+ import { readOrRefreshUpdateCache } from "./updateCheck.js";
8
+ export async function readUpdateHint() {
9
+ const cache = await readOrRefreshUpdateCache();
10
+ if (!cache || !cache.has_update) {
11
+ return undefined;
12
+ }
13
+ const hint = {
14
+ has_update: true,
15
+ current_version: cache.current_version,
16
+ latest_version: cache.latest_version,
17
+ message: cache.message ?? "AgentEarth CLI update is available.",
18
+ command: "ae update"
19
+ };
20
+ if (Array.isArray(cache.release_notes) && cache.release_notes.length > 0) {
21
+ hint.release_notes = cache.release_notes;
22
+ }
23
+ return hint;
24
+ }
25
+ //# sourceMappingURL=updateHint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateHint.js","sourceRoot":"","sources":["../../src/commands/updateHint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAW5D,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,KAAK,GAAG,MAAM,wBAAwB,EAAE,CAAC;IAC/C,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAChC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAe;QACvB,UAAU,EAAE,IAAI;QAChB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,qCAAqC;QAC/D,OAAO,EAAE,WAAW;KACrB,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface NpmCommand {
2
+ command: string;
3
+ args: string[];
4
+ }
5
+ export interface ProcessResult {
6
+ exitCode: number;
7
+ stdout: string;
8
+ stderr: string;
9
+ }
10
+ export declare function buildNpmViewVersionCommand(platform?: NodeJS.Platform): NpmCommand;
11
+ export declare function buildNpmInstallLatestCommand(platform?: NodeJS.Platform): NpmCommand;
12
+ export declare function buildCliVersionCommand(platform?: NodeJS.Platform): NpmCommand;
13
+ export declare function runProcess(command: string, args: string[], env?: NodeJS.ProcessEnv): Promise<ProcessResult>;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * npm 更新命令执行模块。
3
+ *
4
+ * 这里集中处理平台命令选择和外部进程执行:
5
+ * Windows 使用 npm.cmd / ae.cmd,macOS 和 Linux 使用 npm / ae。
6
+ * npm 与 ae 的 stdout/stderr 不直接透传给 agent,避免污染 CLI JSON 输出。
7
+ */
8
+ import { spawn } from "node:child_process";
9
+ import { platform as currentPlatform } from "node:os";
10
+ import { PACKAGE_NAME } from "../constants.js";
11
+ export function buildNpmViewVersionCommand(platform = currentPlatform()) {
12
+ return {
13
+ command: platform === "win32" ? "npm.cmd" : "npm",
14
+ args: ["view", PACKAGE_NAME, "version", "--json"]
15
+ };
16
+ }
17
+ export function buildNpmInstallLatestCommand(platform = currentPlatform()) {
18
+ return {
19
+ command: platform === "win32" ? "npm.cmd" : "npm",
20
+ args: ["install", "-g", `${PACKAGE_NAME}@latest`]
21
+ };
22
+ }
23
+ export function buildCliVersionCommand(platform = currentPlatform()) {
24
+ return {
25
+ command: platform === "win32" ? "ae.cmd" : "ae",
26
+ args: ["--version"]
27
+ };
28
+ }
29
+ export async function runProcess(command, args, env = process.env) {
30
+ return new Promise((resolve) => {
31
+ let stdout = "";
32
+ let stderr = "";
33
+ // Windows 通过 cmd.exe 执行 .cmd;不使用 shell:true,避免 Node DEP0190 警告污染 stderr。
34
+ const isWindows = currentPlatform() === "win32";
35
+ const child = spawn(isWindows ? (env.ComSpec ?? "cmd.exe") : command, isWindows ? ["/d", "/s", "/c", commandLine(command, args)] : args, {
36
+ env,
37
+ windowsHide: true,
38
+ stdio: ["ignore", "pipe", "pipe"]
39
+ });
40
+ child.stdout.on("data", (chunk) => {
41
+ stdout += chunk.toString();
42
+ });
43
+ child.stderr.on("data", (chunk) => {
44
+ stderr += chunk.toString();
45
+ });
46
+ child.on("error", (error) => {
47
+ resolve({ exitCode: -1, stdout, stderr: error.message });
48
+ });
49
+ child.on("close", (code) => {
50
+ resolve({ exitCode: code ?? -1, stdout, stderr });
51
+ });
52
+ });
53
+ }
54
+ function commandLine(command, args) {
55
+ // 命令和参数均由 CLI 固定生成;这里仍做最小 quoting,避免路径或参数里有空格时 cmd 解析错误。
56
+ return [command, ...args].map(quoteCmdArg).join(" ");
57
+ }
58
+ function quoteCmdArg(value) {
59
+ if (!/[\s"]/u.test(value)) {
60
+ return value;
61
+ }
62
+ return `"${value.replace(/"/g, "\"\"")}"`;
63
+ }
64
+ //# sourceMappingURL=updateNpm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateNpm.js","sourceRoot":"","sources":["../../src/commands/updateNpm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 全局常量集中定义文件。
3
+ *
4
+ * 这里保存 CLI 中会被多个模块复用的固定值,例如包名、版本号、默认后端地址、
5
+ * 后端 API 路径和本地缓存数量限制。把这些字符串集中放在这里,可以避免不同
6
+ * 文件里手写重复路径,后续接口调整时也更容易统一修改。
7
+ */
8
+ export declare const PACKAGE_NAME = "@agentearth.ai/cli";
9
+ export declare const UPDATE_COMMAND_TEXT = "npm install -g @agentearth.ai/cli@latest";
10
+ export declare const CLI_VERSION = "0.1.0";
11
+ export declare const DEFAULT_BASE_URL = "https://agentearth.ai";
12
+ export declare const RECOMMEND_PATH = "/agent-api/v1/tool/recommend";
13
+ export declare const TOOLS_LIST_PATH = "/agent-api/v1/tools/list";
14
+ export declare const TOOL_DETAIL_PATH = "/agent-api/v1/tool/detail";
15
+ export declare const EXECUTE_PATH = "/agent-api/v1/tool/execute";
16
+ export declare const TELEMETRY_PATH = "/agent-api/v1/cli/events";
17
+ export declare const DEFAULT_TIMEOUT_MS = 30000;
18
+ export declare const TOOL_CACHE_LIMIT = 200;
19
+ export declare const TELEMETRY_QUEUE_MAX_LINES = 1000;
20
+ export declare const TELEMETRY_QUEUE_MAX_BYTES: number;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 全局常量集中定义文件。
3
+ *
4
+ * 这里保存 CLI 中会被多个模块复用的固定值,例如包名、版本号、默认后端地址、
5
+ * 后端 API 路径和本地缓存数量限制。把这些字符串集中放在这里,可以避免不同
6
+ * 文件里手写重复路径,后续接口调整时也更容易统一修改。
7
+ */
8
+ // npm 包名;发布前如果包名变更,优先改这里和 package.json。
9
+ export const PACKAGE_NAME = "@agentearth.ai/cli";
10
+ // 固定更新命令;ae update 实际执行也使用这个命令。
11
+ export const UPDATE_COMMAND_TEXT = `npm install -g ${PACKAGE_NAME}@latest`;
12
+ // CLI 自身版本号;login 输出、埋点字段和 --version 都会用到它。
13
+ export const CLI_VERSION = "0.1.0";
14
+ // 默认后端域名;调试时可以通过 --base-url 或 AGENT_EARTH_BASE_URL 覆盖。
15
+ export const DEFAULT_BASE_URL = "https://agentearth.ai";
16
+ // recommend 接口:agent 不确定工具类别时,用自然语言任务让后端推荐工具。
17
+ export const RECOMMEND_PATH = "/agent-api/v1/tool/recommend";
18
+ // list 接口:agent 已经知道大致工具类别时,读取工具市场/工具列表。
19
+ export const TOOLS_LIST_PATH = "/agent-api/v1/tools/list";
20
+ // detail 接口:agent 在 execute 前读取某个工具的参数契约和详情。
21
+ export const TOOL_DETAIL_PATH = "/agent-api/v1/tool/detail";
22
+ // execute 标准接口路径:实际请求使用后端返回的完整 tool_url,埋点只记录这个标准 path。
23
+ export const EXECUTE_PATH = "/agent-api/v1/tool/execute";
24
+ // CLI 埋点上传接口:只上传后端不知道的本地行为和本地错误。
25
+ export const TELEMETRY_PATH = "/agent-api/v1/cli/events";
26
+ // HTTP 默认超时时间,单位是毫秒;这里是 30 秒。
27
+ export const DEFAULT_TIMEOUT_MS = 30_000;
28
+ // 本地最多缓存 200 个工具,防止高频 recommend/list/detail 把磁盘撑大。
29
+ export const TOOL_CACHE_LIMIT = 200;
30
+ // 本地最多保留 1000 条待上传埋点,避免埋点后端长期不可用时无限增长。
31
+ export const TELEMETRY_QUEUE_MAX_LINES = 1000;
32
+ // 本地埋点队列最多保留 5MB;param 可能包含 query/params,所以需要字节上限。
33
+ export const TELEMETRY_QUEUE_MAX_BYTES = 5 * 1024 * 1024;
34
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wCAAwC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAEjD,gCAAgC;AAChC,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,YAAY,SAAS,CAAC;AAE3E,4CAA4C;AAC5C,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,uDAAuD;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,cAAc,GAAG,8BAA8B,CAAC;AAE7D,yCAAyC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAE1D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAE5D,wDAAwD;AACxD,MAAM,CAAC,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAEzD,iCAAiC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAEzD,8BAA8B;AAC9B,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,mDAAmD;AACnD,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAEpC,uCAAuC;AACvC,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C,mDAAmD;AACnD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ParsedArgs } from "../types/cli.js";
2
+ export declare function parseArgs(argv: string[]): ParsedArgs;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * 命令行参数解析模块。
3
+ *
4
+ * Node.js 传进来的参数只是字符串数组,本文件负责把它拆成两部分:
5
+ * 1. command 和 positionals:例如 `ae execute mock_tool "{}"` 里的 execute/mock_tool/{}。
6
+ * 2. options:例如 `--api-key`、`--base-url`、`--json` 这类全局选项。
7
+ *
8
+ * 当前项目没有引入第三方参数解析库,所以这里是一个小型手写解析器。
9
+ */
10
+ import { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS } from "../constants.js";
11
+ import { usageError } from "./errors.js";
12
+ export function parseArgs(argv) {
13
+ // positionals 收集不以 -- 开头的普通参数。
14
+ // 第一个普通参数稍后会被当成命令名。
15
+ const positionals = [];
16
+ // options 先填默认值;遇到命令行参数时再覆盖。
17
+ const options = {
18
+ apiKey: undefined,
19
+ apiKeyStdin: false,
20
+ // baseUrl 可由环境变量覆盖,方便本地联调或测试 mock server。
21
+ baseUrl: resolveBaseUrl(),
22
+ json: false,
23
+ noColor: process.env.NO_COLOR === "1",
24
+ noTelemetry: process.env.AE_NO_TELEMETRY === "1",
25
+ timeoutMs: DEFAULT_TIMEOUT_MS,
26
+ help: false,
27
+ version: false
28
+ };
29
+ // 用普通 for 循环,是因为 --api-key/--base-url/--timeout 会消耗下一个参数。
30
+ for (let index = 0; index < argv.length; index += 1) {
31
+ const arg = argv[index];
32
+ if (arg === "--json") {
33
+ // 显式要求 JSON 输出。核心命令即使没有它,也会在 main.ts 默认 JSON。
34
+ options.json = true;
35
+ }
36
+ else if (arg === "--api-key") {
37
+ // ++index 表示读取 --api-key 后面的值,并跳过这个值。
38
+ options.apiKey = readOptionValue(argv, ++index, "--api-key");
39
+ }
40
+ else if (arg === "--api-key-stdin") {
41
+ // 从 stdin 读取 key,适合 agent/脚本,避免 key 出现在命令行参数中。
42
+ options.apiKeyStdin = true;
43
+ }
44
+ else if (arg === "--base-url") {
45
+ // 调试时可以把请求打到 mock server 或测试环境。
46
+ options.baseUrl = readNonBlankOptionValue(argv, ++index, "--base-url");
47
+ }
48
+ else if (arg === "--timeout") {
49
+ // 用户传入的是秒;内部统一换成毫秒。
50
+ const raw = readOptionValue(argv, ++index, "--timeout");
51
+ const seconds = Number(raw);
52
+ // timeout 必须是正数,否则 AbortController 的行为会不符合预期。
53
+ if (!Number.isFinite(seconds) || seconds <= 0) {
54
+ throw usageError("--timeout must be a positive number.");
55
+ }
56
+ // 正数秒转换成毫秒时向上取整,避免极小正数变成 0ms。
57
+ options.timeoutMs = Math.ceil(seconds * 1000);
58
+ }
59
+ else if (arg === "--no-color") {
60
+ options.noColor = true;
61
+ }
62
+ else if (arg === "--no-telemetry") {
63
+ options.noTelemetry = true;
64
+ }
65
+ else if (arg === "--help" || arg === "-h") {
66
+ options.help = true;
67
+ }
68
+ else if (arg === "--version" || arg === "-v") {
69
+ options.version = true;
70
+ }
71
+ else if (arg.startsWith("--")) {
72
+ // 未知 --xxx 必须报错,避免 agent 以为某个无效参数已经生效。
73
+ throw usageError(`Unknown option: ${arg}`);
74
+ }
75
+ else {
76
+ // 普通参数不在这里解释,交给具体命令处理。
77
+ positionals.push(arg);
78
+ }
79
+ }
80
+ return {
81
+ // 第一个普通参数就是命令名,例如 login/recommend/list。
82
+ command: positionals[0],
83
+ // 命令名后面的参数才是该命令自己的位置参数。
84
+ positionals: positionals.slice(1),
85
+ options
86
+ };
87
+ }
88
+ function readOptionValue(argv, index, optionName) {
89
+ // 读取需要值的选项,例如 --api-key abc 中的 abc。
90
+ const value = argv[index];
91
+ // 如果没有下一个参数,或者下一个参数仍是 --xxx,就说明用户漏传了值。
92
+ if (!value || value.startsWith("--")) {
93
+ throw usageError(`${optionName} requires a value.`);
94
+ }
95
+ return value;
96
+ }
97
+ function readNonBlankOptionValue(argv, index, optionName) {
98
+ const value = readOptionValue(argv, index, optionName).trim();
99
+ // 显式命令行参数为空白时代表 agent 传参错误,不能静默回退默认值。
100
+ if (!value) {
101
+ throw usageError(`${optionName} requires a non-empty value.`);
102
+ }
103
+ return value;
104
+ }
105
+ function resolveBaseUrl() {
106
+ // 空环境变量常见于 shell/CI 占位,不能覆盖默认线上地址。
107
+ const envBaseUrl = process.env.AGENT_EARTH_BASE_URL?.trim();
108
+ return envBaseUrl || DEFAULT_BASE_URL;
109
+ }
110
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/core/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 后端错误映射模块。
3
+ *
4
+ * 当前 AgentAPI 的 error_msg 主要是自由文本。CLI 不能把这些文本直接暴露为
5
+ * agent 的控制依据,所以这里把后端文本统一映射成稳定的 CliError。
6
+ * 所有字符串匹配集中在本文件,避免每个命令模块都写一份重复判断。
7
+ */
8
+ import { CliError } from "./errors.js";
9
+ export type BackendOperation = "login" | "recommend" | "list" | "detail" | "execute";
10
+ export declare function mapBackendError(operation: BackendOperation, errorMsg?: string): CliError;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * 后端错误映射模块。
3
+ *
4
+ * 当前 AgentAPI 的 error_msg 主要是自由文本。CLI 不能把这些文本直接暴露为
5
+ * agent 的控制依据,所以这里把后端文本统一映射成稳定的 CliError。
6
+ * 所有字符串匹配集中在本文件,避免每个命令模块都写一份重复判断。
7
+ */
8
+ import { CliError } from "./errors.js";
9
+ export function mapBackendError(operation, errorMsg) {
10
+ // 后端错误文案可能为空,先兜底成空字符串,再统一转小写,方便 includes 判断。
11
+ const normalized = (errorMsg ?? "").toLowerCase();
12
+ // 鉴权错误在所有接口里含义一致:key 不可用,需要重新 login。
13
+ if (isAuthError(normalized)) {
14
+ return backendVisibleError("auth_invalid", "API key is invalid.", "Generate a valid API key and run ae login again.");
15
+ }
16
+ // detail 阶段的 tool not found 表示 agent 选择的 tool_name 不存在。
17
+ if (operation === "detail" && isToolNameError(normalized)) {
18
+ return backendVisibleError("tool_name_invalid", "Tool name is invalid.", "Run ae recommend or ae list and use a returned tool_name.");
19
+ }
20
+ // execute 阶段余额不足是明确业务归因,给出补余额建议。
21
+ if (operation === "execute" && isBalanceError(normalized)) {
22
+ return backendVisibleError("balance_insufficient", "Account balance is insufficient.", "Ask the owner to top up the AgentEarth account.");
23
+ }
24
+ // execute 参数错误说明 agent 传给工具的 params 不符合后端要求。
25
+ if (operation === "execute" && isExecuteParamsError(normalized)) {
26
+ return backendVisibleError("params_invalid", "Execute params are invalid.", "Run ae detail <tool_name> and provide params that match the schema.");
27
+ }
28
+ // execute 的工具不存在或工具执行失败,统一归为上游工具问题。
29
+ if (operation === "execute" && isUpstreamToolError(normalized)) {
30
+ return backendVisibleError("upstream_tool_error", "Tool execution failed.", "Try another recommended tool_name or retry later.");
31
+ }
32
+ // 其余后端业务错误都归为 backend_error,避免发散出未经确认的错误码。
33
+ return backendVisibleError("backend_error", "Backend returned an error.", "Retry later.");
34
+ }
35
+ function backendVisibleError(code, message, hint) {
36
+ // 这些错误来自后端 error_no/error_msg,后端业务日志已经可见,CLI 不重复上传。
37
+ return new CliError(code, message, hint, 1, { telemetryEligible: false });
38
+ }
39
+ function isAuthError(message) {
40
+ // 兼容后端可能返回的几种 key 无效/无权限表达。
41
+ return message.includes("invalid_api_key")
42
+ || message.includes("x-api-key has expired")
43
+ || message.includes("x-api-key has invalid")
44
+ || message.includes("api key is invalid")
45
+ || message.includes("api key invalid")
46
+ || message.includes("unauthorized")
47
+ || message.includes("forbidden");
48
+ }
49
+ function isBalanceError(message) {
50
+ // 当前后端余额不足文案里会包含 insufficient balance。
51
+ return message.includes("insufficient balance");
52
+ }
53
+ function isExecuteParamsError(message) {
54
+ // execute 参数错误通常会提示请求体必须是 JSON object,并且包含 params 字段。
55
+ return message.includes("invalid request body")
56
+ || message.includes("body is a valid json object with a 'params' field")
57
+ || message.includes("body is a valid json object with a \"params\" field");
58
+ }
59
+ function isToolNameError(message) {
60
+ // tool not found 和 tool_name is required 都说明工具名不可用。
61
+ return message.includes("tool not found")
62
+ || message.includes("tool_name is required");
63
+ }
64
+ function isUpstreamToolError(message) {
65
+ // execute 链路里,工具名错误和工具执行失败都属于上游工具侧问题。
66
+ return isToolNameError(message)
67
+ || message.includes("tool execution failed");
68
+ }
69
+ //# sourceMappingURL=backendErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backendErrors.js","sourceRoot":"","sources":["../../src/core/backendErrors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CLI 稳定错误模型。
3
+ *
4
+ * 命令模块不要直接把原生 Error 抛给 main.ts,而是尽量抛 CliError。
5
+ * 这样 agent 可以稳定读取 error.code,埋点也可以直接使用同一层 error_code。
6
+ * message 和 hint 是给人或 agent 看的安全文案,不应该包含后端原始敏感信息。
7
+ */
8
+ export type ErrorCode = "usage_error" | "auth_missing" | "auth_invalid" | "rate_limited" | "network_error" | "timeout" | "backend_error" | "credentials_write_failed" | "session_write_failed" | "tool_name_parse_failed" | "schema_missing" | "tool_name_invalid" | "params_invalid" | "backend_response_invalid" | "balance_insufficient" | "upstream_tool_error" | "version_check_failed" | "update_failed" | "update_verify_failed" | "update_not_applied" | "unknown";
9
+ export interface CliErrorOptions {
10
+ telemetryEligible?: boolean;
11
+ }
12
+ export declare class CliError extends Error {
13
+ readonly code: ErrorCode;
14
+ readonly hint: string;
15
+ readonly exitCode: number;
16
+ readonly telemetryEligible: boolean;
17
+ constructor(code: ErrorCode, message: string, hint: string, exitCode?: number, options?: CliErrorOptions);
18
+ }
19
+ export declare function usageError(message: string, hint?: string): CliError;
20
+ export declare function normalizeUnknownError(error: unknown): CliError;