Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and

[中文版](CHANGELOG.zh.md) · [README](README.md) · [Contributing](CONTRIBUTING.md)

## [2.8.2] - 2026-11-04

### Internal

- Improve CLI usage statistics.

## [2.8.1] - 2026-11-04

### Added
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

[English](CHANGELOG.md) · [README](README.zh.md) · [参与贡献](CONTRIBUTING.zh.md)

## [2.8.2] - 2026-11-04

### 内部维护

- 完善 CLI 使用统计。

## [2.8.1] - 2026-11-04

### 新增
Expand Down
36 changes: 25 additions & 11 deletions docs/agents/telemetry-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ source-config 只用于百炼 / DashScope API 侧消费,不发送到通用网

- `command`、`timestamp`、`durationMs`、`success`
- `cliVersion`、`nodeVersion`、`os`
- `commandPrefix`(调用入口,来自 `Identity`)
- `authMethod`
- `callerType`(必填:`agent` 或 `unknown`);`callerType=agent` 时可选 `callerName`、`skillName`、`skillVersion`
- 失败时的 `errorMessage`、`exitCode`、`httpStatus`、`requestId`
Expand All @@ -119,20 +120,32 @@ source-config 只用于百炼 / DashScope API 侧消费,不发送到通用网

底层 Node tracker 还会附加公共设备字段:OS 类型/版本、Node 应用名与版本、平台,以及由本机网络标识计算的 MD5 `device_id`。

当前 AEM 事件没有 `binName` 或 `clientName` 产品维度,并且 `bl`、`kscli` 共用 `pid=bailian-cli-node`。两边相同路径的 `config show`、`config set`、`update` 无法仅凭当前事件稳定区分产品;Knowledge 命令虽然因路径映射不同而表现为 `knowledge chat` 与 `chat`,也不应把命令路径当作长期产品标识。后端 source-config 的 `t2` 已能区分 `bl/kscli`,但这个维度尚未进入 AEM 客户端事件。
从 2.8.2 起,每条命令事件通过 `commandPrefix` 显式记录调用入口,三种入口仍共用 `pid=bailian-cli-node`:

| 调用入口 | `commandPrefix` |
| ----------- | --------------- |
| `bl` | `bl` |
| `kscli` | `kscli` |
| `aliyun bl` | `aliyun bl` |

`commandPrefix` 使用 `formatCommand(identity)` 从结构化的 `commandInvocation` 生成,未设置时回落到 `binName`。Aliyun 兼容入口由产品入口识别并注入 `Identity.commandInvocation = { bin: "aliyun", path: ["bl"] }`;telemetry 不读取环境变量或 argv 猜测来源,也不采用旧的显示覆盖字段。命令路径保持不变:如三种入口的 `config show` 仍以 `config show` 为事件名,按 `commandPrefix` 区分入口。调用方 `callerType` / `callerName` 是独立维度。

该字段同时进入本地 JSONL 与远端 AEM `ext`,成功与失败均携带。旧版本缺少入口字段的事件保留为入口未知,不能自动归为 `bl`,也不能靠命令路径可靠补回。后端 source-config 和 User-Agent 的既有口径不变。

`createTrackingEvent()` 必须传入 `identity`,统一从中读取 `cliVersion` 并生成 `commandPrefix`。`trackCommandExecution()` 传入产品 `Identity`,因此本版 CLI 命令事件始终包含 `commandPrefix`。

AEM 映射:

| AEM 字段 | 内容 |
| ---------- | -------------------------------------------------------------------------------- |
| event name | 命令路径 |
| `et` | `EXP` |
| `ext` | 除 `command`、`params` 外的结构化事件字段,含 `callerType` 与失败时的 `exitCode` |
| `c1` | allowlist 参数 |
| `c2` | `success` / `failure` |
| `c3` | HTTP status |
| `c4` | 错误文案,最多 500 字符 |
| `c5` | request ID |
| AEM 字段 | 内容 |
| ---------- | ------------------------------------------------------------------------------------------------- |
| event name | 命令路径 |
| `et` | `EXP` |
| `ext` | 除 `command`、`params` 外的结构化事件字段,含 `commandPrefix`、`callerType` 与失败时的 `exitCode` |
| `c1` | allowlist 参数 |
| `c2` | `success` / `failure` |
| `c3` | HTTP status |
| `c4` | 错误文案,最多 500 字符 |
| `c5` | request ID |

远端发送是 best-effort,不得阻塞命令或改变退出码。正常退出最多等待 1 秒,SIGINT 最多等待 500 ms。

Expand All @@ -159,6 +172,7 @@ AEM 映射:

- [ ] 更新 `TrackingEvent`、`createTrackingEvent()` 与 `buildRemoteAemOptions()` 的字段映射
- [ ] 本地 JSONL 与远端 AEM 必须基于同一结构化事件,不能维护两套字段口径
- [ ] 三种入口分别核对 `commandPrefix`;共享路径也必须可区分,旧数据缺字段保留为未知
- [ ] 调用方字段经 `readCaller` → `TrackingDeps.caller` → 事件;仅显式 `agent` / `ai_agent` 为 `agent`,其余为 `unknown`
- [ ] 成功与失败均覆盖;遥测异常必须静默且不改变业务退出码
- [ ] runtime 本地语义错误应记录 `exitCode`;新增字段默认随 AEM `ext` 上报,无需占用新的 `c1`—`c5`
Expand Down
2 changes: 1 addition & 1 deletion packages/bailian-kb-dsh/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-kb-dsh",
"version": "2.8.1",
"version": "2.8.2",
"description": "Bailian knowledge-base tools for DeepSeek Harness: kb_search and kb_chat over the DashScope RAG API, plus the bl CLI management skill.",
"keywords": [
"alibaba-cloud",
Expand Down
2 changes: 1 addition & 1 deletion packages/bailian-memo-dsh/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-memo-dsh",
"version": "2.8.1",
"version": "2.8.2",
"description": "Bailian personal memory for DeepSeek Harness: automatic recall, silent curation, and user-controlled remember/forget.",
"keywords": [
"alibaba-cloud",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli",
"version": "2.8.1",
"version": "2.8.2",
"description": "CLI for Aliyun Model Studio (DashScope) AI Platform.",
"keywords": [
"agent",
Expand Down
2 changes: 1 addition & 1 deletion packages/commands/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli-commands",
"version": "2.8.1",
"version": "2.8.2",
"description": "Command library for bailian-cli products (knowledge, memory, media, …). See https://www.npmjs.com/package/bailian-cli for usage.",
"homepage": "https://bailian.console.aliyun.com/cli",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli-core",
"version": "2.8.1",
"version": "2.8.2",
"description": "Core SDK for bailian-cli. See https://www.npmjs.com/package/bailian-cli for usage.",
"homepage": "https://bailian.console.aliyun.com/cli",
"bugs": {
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/telemetry/event.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Identity } from "../config/schema.ts";
import { formatCommand } from "../output/command.ts";
import type { AuthRequirement } from "../types/command.ts";
import type { CallerAttribution } from "./caller.ts";

Expand All @@ -11,6 +13,7 @@ export interface TrackingEvent {
httpStatus?: number;
requestId?: string;
cliVersion: string;
commandPrefix: string;
nodeVersion: string;
os: string;
authMethod?: AuthRequirement;
Expand All @@ -27,7 +30,7 @@ export function createTrackingEvent(opts: {
durationMs: number;
success: boolean;
error?: { message?: string; exitCode?: number; httpStatus?: number; requestId?: string };
cliVersion: string;
identity: Identity;
authMethod?: AuthRequirement;
params?: Record<string, unknown>;
caller: CallerAttribution;
Expand All @@ -37,7 +40,8 @@ export function createTrackingEvent(opts: {
timestamp: new Date().toISOString(),
durationMs: opts.durationMs,
success: opts.success,
cliVersion: opts.cliVersion,
cliVersion: opts.identity.version,
commandPrefix: formatCommand(opts.identity),
nodeVersion: process.version,
os: process.platform,
callerType: opts.caller.callerType,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/telemetry/tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export async function trackCommandExecution(
durationMs,
success,
error: success ? undefined : { message: errorMessage, exitCode, httpStatus, requestId },
cliVersion: deps.identity.version,
identity: deps.identity,
authMethod: deps.authMethod,
params: extractParams(flags),
caller: deps.caller,
Expand Down
118 changes: 117 additions & 1 deletion packages/core/tests/telemetry-tracker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type { Identity, Settings } from "../src/config/schema.ts";
import { BailianError } from "../src/errors/base.ts";
import { ExitCode } from "../src/errors/codes.ts";
import type { CallerAttribution } from "../src/telemetry/caller.ts";
import { buildRemoteAemOptions, type TrackingEvent } from "../src/telemetry/event.ts";
import {
buildRemoteAemOptions,
createTrackingEvent,
type TrackingEvent,
} from "../src/telemetry/event.ts";

const sinkMocks = vi.hoisted(() => ({
localSink: vi.fn<(event: TrackingEvent) => Promise<void>>(async () => {}),
Expand All @@ -29,6 +33,118 @@ const agentCaller: CallerAttribution = {
skillVersion: "2.5.0",
};

test("derives event version and prefix from identity", () => {
const event = createTrackingEvent({
command: "config show",
durationMs: 1,
success: true,
identity: { ...identity, version: "identity-version" },
caller: unknownCaller,
});
expect(event).toMatchObject({
command: "config show",
cliVersion: "identity-version",
commandPrefix: "bl",
});
expect(buildRemoteAemOptions(event)).toMatchObject({
ext: { cliVersion: "identity-version", commandPrefix: "bl" },
});
});

const entryIdentities = [
{
label: "bl",
identity: { ...identity, clientName: "bailian-cli" },
expected: { commandPrefix: "bl" },
},
{
label: "kscli",
identity: {
...identity,
binName: "kscli",
clientName: "knowledge-studio-cli",
npmPackage: "knowledge-studio-cli",
},
expected: { commandPrefix: "kscli" },
},
{
label: "aliyun bl",
identity: {
...identity,
commandInvocation: { bin: "aliyun", path: ["bl"] },
clientName: "bailian-cli",
},
expected: { commandPrefix: "aliyun bl" },
},
];

test.each(
entryIdentities.flatMap((entry) => [true, false].map((success) => ({ ...entry, success }))),
)("preserves $label entry in local and remote events (success=$success)", async (entry) => {
sinkMocks.localSink.mockClear();
sinkMocks.remoteSink.mockClear();
const error = new BailianError("Example failure", ExitCode.GENERAL);
const execution = trackCommandExecution(
{
identity: entry.identity,
settings: { telemetry: true } as Settings,
authMethod: "none",
caller: agentCaller,
},
["config", "show"],
{ commandPrefix: "untrusted flag", clientName: "untrusted flag" },
async () => {
if (!entry.success) throw error;
},
);
if (entry.success) await execution;
else await expect(execution).rejects.toBe(error);

expect(sinkMocks.localSink).toHaveBeenCalledOnce();
expect(sinkMocks.remoteSink).toHaveBeenCalledOnce();
const localEvent = sinkMocks.localSink.mock.calls[0]![0];
const remoteEvent = sinkMocks.remoteSink.mock.calls[0]![0];
expect(localEvent).toMatchObject({
...entry.expected,
command: "config show",
cliVersion: "0.0.0-test",
success: entry.success,
callerType: "agent",
callerName: "cursor",
});
expect(localEvent.params).toBeUndefined();
expect(remoteEvent).toEqual(localEvent);
expect(buildRemoteAemOptions(remoteEvent)).toMatchObject({
ext: entry.expected,
c2: entry.success ? "success" : "failure",
});
for (const field of ["binName", "clientName"]) {
expect(localEvent).not.toHaveProperty(field);
expect(buildRemoteAemOptions(remoteEvent).ext).not.toHaveProperty(field);
}
});

test("ignores obsolete display overrides when deriving the entry", async () => {
sinkMocks.localSink.mockClear();
sinkMocks.remoteSink.mockClear();
const legacyIdentity = { ...identity, commandPrefix: "untrusted legacy override" };
await trackCommandExecution(
{
identity: legacyIdentity,
settings: { telemetry: true } as Settings,
caller: unknownCaller,
},
["config", "show"],
{},
async () => {},
);
const event = sinkMocks.localSink.mock.calls[0]![0];
expect(event).toMatchObject({ commandPrefix: "bl" });
expect(buildRemoteAemOptions(event)).toMatchObject({
ext: { commandPrefix: "bl" },
});
});

test("records BailianError exitCode in local events and AEM ext", async () => {
sinkMocks.localSink.mockClear();
sinkMocks.remoteSink.mockClear();
Expand Down
2 changes: 1 addition & 1 deletion packages/kscli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "knowledge-studio-cli",
"version": "2.8.1",
"version": "2.8.2",
"description": "Lightweight RAG CLI for Aliyun Model Studio — focused on knowledge-base retrieval.",
"keywords": [
"alibaba-cloud",
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bailian-cli-runtime",
"version": "2.8.1",
"version": "2.8.2",
"description": "Runtime framework for bailian-cli (createCli, registry, args, output, pipeline). See https://www.npmjs.com/package/bailian-cli for usage.",
"homepage": "https://bailian.console.aliyun.com/cli",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-cli
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-finetune/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-finetune
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-gen/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-gen
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-knowledge/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-knowledge
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-managed-agent/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-managed-agent
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-memory/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-memory
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-protocol/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-protocol
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-sandbox/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-sandbox
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
2 changes: 1 addition & 1 deletion skills/bailian-web-search/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: bailian-web-search
metadata:
version: "2.8.1"
version: "2.8.2"
requires:
bins: ["bl"]
description: >-
Expand Down
Loading