@agentearth.ai/cli 0.1.0-beta.2 → 0.1.0-beta.4

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 (44) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/execute.js +24 -1
  3. package/dist/commands/execute.js.map +1 -1
  4. package/dist/commands/list.js +10 -0
  5. package/dist/commands/list.js.map +1 -1
  6. package/dist/commands/login.js +14 -8
  7. package/dist/commands/login.js.map +1 -1
  8. package/dist/commands/update.js +5 -0
  9. package/dist/commands/update.js.map +1 -1
  10. package/dist/commands/updateCheck.js +20 -3
  11. package/dist/commands/updateCheck.js.map +1 -1
  12. package/dist/commands/updateHint.js +6 -4
  13. package/dist/commands/updateHint.js.map +1 -1
  14. package/dist/commands/updateNpm.js +7 -0
  15. package/dist/commands/updateNpm.js.map +1 -1
  16. package/dist/core/backendErrors.js +3 -0
  17. package/dist/core/backendErrors.js.map +1 -1
  18. package/dist/core/errors.js +3 -0
  19. package/dist/core/errors.js.map +1 -1
  20. package/dist/core/hiddenInput.js +10 -0
  21. package/dist/core/hiddenInput.js.map +1 -1
  22. package/dist/core/http.d.ts +0 -1
  23. package/dist/core/http.js +14 -17
  24. package/dist/core/http.js.map +1 -1
  25. package/dist/core/output.js +3 -1
  26. package/dist/core/output.js.map +1 -1
  27. package/dist/storage/credentials.d.ts +5 -1
  28. package/dist/storage/credentials.js +18 -6
  29. package/dist/storage/credentials.js.map +1 -1
  30. package/dist/storage/fileProtection.js +4 -0
  31. package/dist/storage/fileProtection.js.map +1 -1
  32. package/dist/storage/paths.js +3 -0
  33. package/dist/storage/paths.js.map +1 -1
  34. package/dist/storage/session.js +91 -23
  35. package/dist/storage/session.js.map +1 -1
  36. package/dist/storage/telemetryQueue.js +6 -0
  37. package/dist/storage/telemetryQueue.js.map +1 -1
  38. package/dist/storage/telemetryUploadState.js +16 -0
  39. package/dist/storage/telemetryUploadState.js.map +1 -1
  40. package/dist/storage/updateCache.js +2 -2
  41. package/dist/telemetry/uploader.js +33 -1
  42. package/dist/telemetry/uploader.js.map +1 -1
  43. package/package.json +1 -1
  44. package/skills/agentearth/SKILL.md +102 -21
@@ -1,7 +1,15 @@
1
+ /**
2
+ * 埋点上传暂停状态模块。
3
+ *
4
+ * telemetry uploader 遇到 401、429、5xx、网络错误或超时时,不应该每次命令结束都立刻重试。
5
+ * 本文件把“暂停到什么时候、为什么暂停、对应哪个 API key”写入本地状态文件。
6
+ * 注意这里永远不保存完整 API key,只保存短 hash 指纹,用来判断用户是否已经换了 key。
7
+ */
1
8
  import { createHash } from "node:crypto";
2
9
  import { readFile, unlink, writeFile } from "node:fs/promises";
3
10
  import { ensureAgentEarthDir, getTelemetryUploadStatePath } from "./paths.js";
4
11
  export async function readTelemetryUploadState() {
12
+ // 读取失败、文件不存在或结构损坏都返回 null;埋点状态不能影响主命令。
5
13
  try {
6
14
  const raw = await readFile(getTelemetryUploadStatePath(), "utf8");
7
15
  return normalizeTelemetryUploadState(JSON.parse(raw));
@@ -11,6 +19,7 @@ export async function readTelemetryUploadState() {
11
19
  }
12
20
  }
13
21
  export async function writeTelemetryUploadState(state) {
22
+ // 写状态前确保 AgentEarth 本地数据目录存在。
14
23
  await ensureAgentEarthDir();
15
24
  await writeFile(getTelemetryUploadStatePath(), `${JSON.stringify(state, null, 2)}\n`, {
16
25
  encoding: "utf8",
@@ -18,6 +27,7 @@ export async function writeTelemetryUploadState(state) {
18
27
  });
19
28
  }
20
29
  export async function clearTelemetryUploadState() {
30
+ // 上传成功或 key 变化后清掉暂停状态,让后续命令可以继续正常冲刷队列。
21
31
  try {
22
32
  await unlink(getTelemetryUploadStatePath());
23
33
  }
@@ -26,13 +36,17 @@ export async function clearTelemetryUploadState() {
26
36
  }
27
37
  }
28
38
  export function createApiKeyFingerprint(apiKey) {
39
+ // sha256 是单向 hash;slice(0, 16) 足够做本地变化判断,又避免保存完整 key。
29
40
  return createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
30
41
  }
31
42
  export function isTelemetryUploadPaused(state, now = new Date()) {
43
+ // suspended_until 解析失败时不暂停,避免坏状态文件让上传永久停住。
32
44
  const suspendedUntil = Date.parse(state.suspended_until);
33
45
  return Number.isFinite(suspendedUntil) && suspendedUntil > now.getTime();
34
46
  }
47
+ // uploader 根据 HTTP 分类结果调用这里生成下一次暂停状态。
35
48
  export function createTelemetryUploadState(reason, delayMs, apiKeyFingerprint, previousState, now = new Date()) {
49
+ // delayMs 小于 0 时按 0 处理,避免写出过去时间。
36
50
  return {
37
51
  suspended_until: new Date(now.getTime() + Math.max(0, delayMs)).toISOString(),
38
52
  reason,
@@ -41,6 +55,7 @@ export function createTelemetryUploadState(reason, delayMs, apiKeyFingerprint, p
41
55
  };
42
56
  }
43
57
  function normalizeTelemetryUploadState(value) {
58
+ // 本地文件可被用户手动修改,所以每个字段都要运行时校验。
44
59
  if (!isRecord(value)) {
45
60
  return null;
46
61
  }
@@ -63,6 +78,7 @@ function normalizeTelemetryUploadState(value) {
63
78
  };
64
79
  }
65
80
  function isRecord(value) {
81
+ // JavaScript 里数组也是 object;这里排除数组,确保后面能按字段名读取。
66
82
  return typeof value === "object" && value !== null && !Array.isArray(value);
67
83
  }
68
84
  //# sourceMappingURL=telemetryUploadState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryUploadState.js","sourceRoot":"","sources":["../../src/storage/telemetryUploadState.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"telemetryUploadState.js","sourceRoot":"","sources":["../../src/storage/telemetryUploadState.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,8 @@
2
2
  * 更新检查缓存模块。
3
3
  *
4
4
  * list/recommend 会读取这个文件展示 fresh 更新提示。
5
- * 缓存失效时,CLI 通过 npm view 查询 npm registry,并把检查结果写回这里,
6
- * 避免每次工具发现都请求 registry。
5
+ * 缓存失效时,工具发现命令不主动刷新;ae update 会通过 npm view 查询
6
+ * npm registry,并把检查结果写回这里,避免工具发现链路请求 registry
7
7
  */
8
8
  import { readFile, writeFile } from "node:fs/promises";
9
9
  import { pathExists, protectSensitiveFile } from "./fileProtection.js";
@@ -1,28 +1,46 @@
1
+ /**
2
+ * CLI 埋点上传器。
3
+ *
4
+ * main.ts 每次命令结束后都会调用 flushTelemetry。它会读取本地 events.jsonl 队列,
5
+ * 尝试把一批事件 POST 到日志接口。上传失败不能影响主命令,所以本模块内部会吞掉异常,
6
+ * 并根据 HTTP 分类决定保留队列、删除坏批次、拆小批次或写入暂停状态。
7
+ */
1
8
  import { TELEMETRY_PATH } from "../constants.js";
2
9
  import { postTelemetryJson } from "../core/http.js";
3
10
  import { resolveApiKey } from "../storage/credentials.js";
4
11
  import { dropTelemetryQueueHead, readTelemetryQueueBatch } from "../storage/telemetryQueue.js";
5
12
  import { clearTelemetryUploadState, createApiKeyFingerprint, createTelemetryUploadState, isTelemetryUploadPaused, readTelemetryUploadState, writeTelemetryUploadState } from "../storage/telemetryUploadState.js";
13
+ // 默认每次最多上传 20 条,避免单次请求体过大。
6
14
  const DEFAULT_BATCH_SIZE = 20;
15
+ // API key 失败通常需要用户重新登录,不要每次命令都刷同一批 401。
7
16
  const AUTH_PAUSE_MS = 24 * 60 * 60 * 1000;
17
+ // 当前后端不设计专门 429,但如果网关返回,CLI 仍按短退避处理。
8
18
  const RATE_LIMIT_PAUSE_MS = 5 * 60 * 1000;
19
+ // 5xx、网络失败、超时属于临时失败,保留队列并稍后再试。
9
20
  const TEMPORARY_FAILURE_PAUSE_MS = 60 * 1000;
10
21
  export async function flushTelemetry(options) {
22
+ // 用户显式关闭埋点时,本轮既不读队列也不上传。
11
23
  if (options.noTelemetry) {
12
24
  return;
13
25
  }
14
26
  try {
27
+ // 上传接口也需要 X-Api-Key;如果本地没有 key,resolveApiKey 会抛错并被外层吞掉。
15
28
  const apiKey = await resolveApiKey(options);
29
+ // 只保存 hash 指纹到暂停状态,避免把真实 key 写入 telemetry-upload-state.json。
16
30
  const apiKeyFingerprint = createApiKeyFingerprint(apiKey);
31
+ // existingState 记录上一次失败后的暂停窗口和原因。
17
32
  const existingState = await readTelemetryUploadState();
18
33
  if (await shouldSkipUpload(existingState, apiKeyFingerprint)) {
19
34
  return;
20
35
  }
36
+ // batchLimit 可能因为 413 被逐步减半,所以用 while 而不是固定读取一次。
21
37
  let batchLimit = DEFAULT_BATCH_SIZE;
22
38
  while (batchLimit >= 1) {
39
+ // 每轮都重新读队头,因为上一轮可能已经删除了成功/坏数据。
23
40
  const batch = await readTelemetryQueueBatch(batchLimit);
24
41
  const events = batch.events;
25
42
  if (events.length === 0) {
43
+ // 没有有效事件但消费过坏行时,说明队头是损坏数据,直接清理掉。
26
44
  if (batch.consumedLineCount > 0) {
27
45
  await dropTelemetryQueueHead(batch.consumedLineCount);
28
46
  }
@@ -30,24 +48,30 @@ export async function flushTelemetry(options) {
30
48
  }
31
49
  const result = await postTelemetryJson(TELEMETRY_PATH, { events }, {
32
50
  apiKey,
51
+ // 日志上传可以和业务接口使用不同 host;未配置时才回退到业务 baseUrl。
33
52
  baseUrl: options.telemetryBaseUrl || options.baseUrl,
34
53
  timeoutMs: options.timeoutMs
35
54
  });
36
55
  if (result.kind === "success") {
56
+ // 后端确认接收后才能删除队头;同时清掉历史暂停状态。
37
57
  await dropTelemetryQueueHead(batch.consumedLineCount);
38
58
  await clearTelemetryUploadState();
39
59
  return;
40
60
  }
41
61
  if (result.kind === "permanent_failure") {
62
+ // 400/415 等永久错误说明这批数据结构不被接受,继续重试只会卡住队列。
42
63
  await dropTelemetryQueueHead(batch.consumedLineCount);
43
64
  return;
44
65
  }
45
66
  if (result.kind === "auth_failed") {
67
+ // 鉴权失败不删除队列;等用户换 key 后可以继续上传旧事件。
46
68
  await pauseUpload("auth_failed", AUTH_PAUSE_MS, apiKeyFingerprint, existingState);
47
69
  return;
48
70
  }
49
71
  if (result.kind === "payload_too_large") {
72
+ // 413 时先拆小批次;如果单条都太大,只能丢弃该事件避免永久卡队头。
50
73
  if (events.length > 1) {
74
+ // 减半后 continue 回 while 顶部,重新按更小 batchLimit 读取同一个队头。
51
75
  batchLimit = Math.max(1, Math.floor(events.length / 2));
52
76
  continue;
53
77
  }
@@ -55,34 +79,42 @@ export async function flushTelemetry(options) {
55
79
  return;
56
80
  }
57
81
  if (result.kind === "rate_limited") {
82
+ // 如果后端或网关给 Retry-After,就优先使用服务端建议的暂停时长。
58
83
  await pauseUpload("rate_limited", result.retryAfterMs ?? RATE_LIMIT_PAUSE_MS, apiKeyFingerprint, existingState);
59
84
  return;
60
85
  }
86
+ // 剩下的 network_error、timeout、server_error 都属于临时失败:保留队列并短暂停。
61
87
  await pauseUpload("temporary_failure", TEMPORARY_FAILURE_PAUSE_MS, apiKeyFingerprint, existingState);
62
88
  return;
63
89
  }
64
90
  }
65
91
  catch {
66
- // Telemetry is best-effort and must never change command output or exit code.
92
+ // 这里故意不再抛出:埋点只是辅助数据,不能改变 ae 命令本身的输出和退出码。
67
93
  }
68
94
  }
95
+ // 根据暂停状态判断本轮是否应该跳过上传。
69
96
  async function shouldSkipUpload(state, apiKeyFingerprint) {
70
97
  if (!state) {
71
98
  return false;
72
99
  }
73
100
  if (!isTelemetryUploadPaused(state)) {
101
+ // 暂停时间过期后清理状态,让本轮继续上传。
74
102
  await clearTelemetryUploadState();
75
103
  return false;
76
104
  }
77
105
  if (state.reason !== "auth_failed") {
106
+ // 非鉴权类暂停只看时间窗口,没到期就跳过。
78
107
  return true;
79
108
  }
80
109
  if (state.api_key_fingerprint === apiKeyFingerprint) {
110
+ // 同一个 key 已经失败过,继续重试没有意义。
81
111
  return true;
82
112
  }
113
+ // key 指纹变了,说明用户可能重新 login,本轮允许恢复上传。
83
114
  await clearTelemetryUploadState();
84
115
  return false;
85
116
  }
117
+ // 统一写入暂停状态,避免各分支重复计算 suspended_until/retry_count。
86
118
  async function pauseUpload(reason, delayMs, apiKeyFingerprint, previousState) {
87
119
  await writeTelemetryUploadState(createTelemetryUploadState(reason, delayMs, apiKeyFingerprint, previousState));
88
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../src/telemetry/uploader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../src/telemetry/uploader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentearth.ai/cli",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Agent-first CLI that helps AI agents discover, inspect, and execute AgentEarth tools from any shell.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,30 +1,92 @@
1
- # AgentEarth CLI Skill
1
+ ---
2
+ name: agentearth
3
+ description: >-
4
+ Discover, inspect, and execute AgentEarth marketplace tools through the AgentEarth CLI.
5
+ Use when the user explicitly asks to use AgentEarth/agentearth, asks for AgentEarth tools,
6
+ or needs an external tool workflow such as live data retrieval, structured web/API results,
7
+ document or media conversion, translation, calculations, image/video generation,
8
+ presentation editing, or other tool-backed services. Follow host approval, credential,
9
+ network, and safety policies before invoking external commands.
2
10
 
3
- Use AgentEarth CLI when the user asks you to discover, inspect, or execute AgentEarth tools.
11
+ requirements:
12
+ env:
13
+ - AGENTEARTH_API_KEY
4
14
 
5
- ## Commands
15
+ credentials:
16
+ type: api_key
17
+ env: AGENTEARTH_API_KEY
18
+ injection: environment
19
+ required: true
20
+ ---
6
21
 
7
- - Use `ae list` when the user task clearly belongs to a known tool category, such as image generation, video generation, or PPT editing.
8
- - For filtered list queries, write the query JSON to `query.json` and run `ae list @query.json`; do not hand-write inline JSON in PowerShell.
9
- - Use `ae recommend "<query>"` when the user task is ambiguous and you are not sure which tool category should be used.
10
- - Use `ae detail <tool_name>` before execution to read the tool input schema.
11
- - Use `ae execute <tool_name> @params.json` to execute the selected tool.
12
- - Use `ae update` only after the user confirms they want to update the CLI.
22
+ # AgentEarth
13
23
 
14
- ## Rules
24
+ Use AgentEarth as an external tool marketplace. Treat the user's request as the task to solve, then discover the best matching tool, inspect its schema, validate parameters, execute it, and summarize the result.
15
25
 
16
- - All agent-facing commands output JSON by default.
17
- - Select tools by `tool_name`.
18
- - Do not use `tool_url` as an argument.
19
- - Do not call the removed `ae schema` command.
20
- - Do not pass API keys to normal tool commands; `ae login` stores credentials for later use.
21
- - If login is required, read the API key only from the caller-provided `AGENTEARTH_API_KEY` environment variable and pipe it to `ae login --api-key-stdin`; do not search the filesystem for API keys.
26
+ ## Command Surface
22
27
 
23
- ## Typical Flows
28
+ Prefer `ae` on Unix-like shells and `ae.cmd` in Windows PowerShell when the PowerShell shim is blocked by execution policy.
24
29
 
25
- Known category:
30
+ Use these commands:
26
31
 
27
- Create `query.json`:
32
+ - `ae recommend "<task>"` to discover tools for ambiguous or natural-language tasks.
33
+ - `ae list @query.json` to list tools for a known category or keyword.
34
+ - `ae detail <tool_name>` to inspect a selected tool's schema before execution.
35
+ - `ae execute <tool_name> @params.json` to run the selected tool with validated parameters.
36
+ - `ae update` only when the user confirms they want to update the CLI.
37
+
38
+ All agent-facing commands return JSON by default. Select tools by `tool_name`; never use `tool_url` as a CLI argument. Do not call removed or undocumented commands such as `ae schema`.
39
+
40
+ ## Credential Handling
41
+
42
+ Use credentials only through the active host environment.
43
+
44
+ - Read the API key from `AGENTEARTH_API_KEY` when the host provides it.
45
+ - If login is required, pipe the caller-provided key to `ae login --api-key-stdin`.
46
+ - Never ask the user to paste a key unless the host explicitly requires manual credential setup.
47
+ - Never search the filesystem, shell history, logs, or config files for API keys.
48
+ - Never print, log, echo, or include secrets in generated files.
49
+
50
+ If authentication fails, report that AgentEarth authentication failed and ask the user to verify the configured API key or login state. Do not expose request headers or secret values.
51
+
52
+ ## Execution Workflow
53
+
54
+ 1. Restate the task internally as a concise AgentEarth query.
55
+ 2. Discover candidate tools with `ae recommend "<task>"`, or `ae list @query.json` when the category is already clear.
56
+ 3. Inspect the best candidate with `ae detail <tool_name>`.
57
+ 4. Build `params.json` strictly from the inspected input schema.
58
+ 5. Validate required fields, types, enums, formats, and `additionalProperties` when present.
59
+ 6. Execute with `ae execute <tool_name> @params.json`.
60
+ 7. Summarize the useful result for the user and omit internal command noise unless it is needed for troubleshooting.
61
+
62
+ Use a fallback tool only when the first suitable tool fails for a recoverable reason or clearly does not satisfy the task.
63
+
64
+ ## Tool Selection
65
+
66
+ Choose the tool that best matches the task intent and can be safely executed with available context.
67
+
68
+ Prefer candidates with:
69
+
70
+ - clear task relevance;
71
+ - complete and understandable input schema;
72
+ - required parameters that can be filled from the user's request or conversation context;
73
+ - lower cost when otherwise equivalent;
74
+ - narrower, more specialized behavior for the requested job.
75
+
76
+ If no candidate is suitable, refine the query once. If discovery still fails, tell the user that AgentEarth did not return a suitable tool.
77
+
78
+ ## Parameter Rules
79
+
80
+ Build parameter files as JSON objects matching the selected tool schema.
81
+
82
+ - Use only values from the user's request, conversation context, or deterministic transformations of those values.
83
+ - Do not invent required values such as URLs, IDs, tokens, locations, dates, file paths, or account-specific inputs.
84
+ - Ask a concise clarification question when a required value is missing.
85
+ - Remove keys not defined by the schema when `additionalProperties` is `false`.
86
+ - Do not reuse example keys unless they exist in the selected schema.
87
+ - Write query or execution payloads to JSON files instead of hand-writing inline JSON in PowerShell.
88
+
89
+ Known-category list example:
28
90
 
29
91
  ```json
30
92
  {"keyword":"image"}
@@ -36,10 +98,29 @@ ae detail <tool_name>
36
98
  ae execute <tool_name> @params.json
37
99
  ```
38
100
 
39
- Ambiguous task:
101
+ Ambiguous-task example:
40
102
 
41
103
  ```text
42
- ae recommend "<user task>"
104
+ ae recommend "find current hotel prices in Sapporo for next weekend"
43
105
  ae detail <tool_name>
44
106
  ae execute <tool_name> @params.json
45
107
  ```
108
+
109
+ ## Error Handling
110
+
111
+ On command or tool failure:
112
+
113
+ - Read the JSON error message before retrying.
114
+ - Retry once only when the failure is likely transient or caused by a fixable parameter issue.
115
+ - Correct parameters only when the correction is supported by the schema and available context.
116
+ - Try a fallback candidate only when it is clearly relevant to the original task.
117
+ - Stop and explain the failure when the error is authentication, authorization, missing user input, unsupported task, or repeated tool failure.
118
+
119
+ ## Result Presentation
120
+
121
+ Return the final answer, not a transcript of internal discovery.
122
+
123
+ - Summarize key facts, generated asset links, converted file paths, or tool outputs.
124
+ - Include caveats from the tool result when relevant.
125
+ - Mention AgentEarth only when useful for provenance or when troubleshooting is needed.
126
+ - Do not expose raw credentials, internal request headers, or irrelevant JSON fields.