@talesofai/neta-skills 0.14.1 → 0.14.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/CHANGELOG.md +12 -0
- package/README.md +7 -0
- package/README.zh_cn.md +7 -0
- package/bin/commands/load.js +63 -10
- package/bin/utils/telemetry.js +78 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -223,6 +223,13 @@ Both the AI agent skills and the CLI require the following environment configura
|
|
|
223
223
|
|----------|----------|---------|-------------|
|
|
224
224
|
| `NETA_TOKEN` | ✅ | - | Your Neta Art API access token. |
|
|
225
225
|
| `NETA_API_BASE_URL` | ❌ | default: `https://api.talesofai.com` | Base URL for the Neta API. |
|
|
226
|
+
| `DISABLE_TELEMETRY` | ❌ | unset | Set to `1` to disable CLI usage analytics (see below). |
|
|
227
|
+
|
|
228
|
+
### CLI usage analytics (telemetry)
|
|
229
|
+
|
|
230
|
+
The `@talesofai/neta-skills` CLI sends lightweight usage data—such as which command ran, the options you passed, CLI version and locale, a coarse API-region hint, outcomes and timing, and your user UUID when signed in (not your API token)—so we can measure reliability and improve the experience.
|
|
231
|
+
|
|
232
|
+
To disable analytics entirely, set `DISABLE_TELEMETRY=1` in your environment; no telemetry HTTP requests are sent.
|
|
226
233
|
|
|
227
234
|
### i18n and locale detection
|
|
228
235
|
|
package/README.zh_cn.md
CHANGED
|
@@ -222,6 +222,13 @@ neta-skills/
|
|
|
222
222
|
|--------|------|--------|------|
|
|
223
223
|
| `NETA_TOKEN` | ✅ | - | Neta Art API 访问令牌 |
|
|
224
224
|
| `NETA_API_BASE_URL` | ❌ | default: `https://api.talesofai.com` | Neta API 网关地址 |
|
|
225
|
+
| `DISABLE_TELEMETRY` | ❌ | 未设置 | 设为 `1` 可关闭 CLI 使用数据统计(见下文) |
|
|
226
|
+
|
|
227
|
+
### CLI 使用数据(埋点 / 遥测)
|
|
228
|
+
|
|
229
|
+
`@talesofai/neta-skills` CLI 会上报轻量使用数据(例如执行的命令、命令行参数、CLI 版本与语言、大致 API 区域、执行结果与耗时、登录时的用户 UUID 等;**不包含** API Token),用于衡量稳定性并改进产品体验。
|
|
230
|
+
|
|
231
|
+
若不希望参与统计,请在环境中设置 `DISABLE_TELEMETRY=1`,此时不会发起相关上报请求。
|
|
225
232
|
|
|
226
233
|
### 多语言与本地化(i18n)
|
|
227
234
|
|
package/bin/commands/load.js
CHANGED
|
@@ -14,7 +14,9 @@ import { Type } from "@sinclair/typebox";
|
|
|
14
14
|
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
15
15
|
import { createApis } from "../apis/index.js";
|
|
16
16
|
import { ApiResponseError } from "../utils/errors.js";
|
|
17
|
+
import { getLocale } from "../utils/lang.js";
|
|
17
18
|
import { setLocale } from "../utils/parse_meta.js";
|
|
19
|
+
import { formatCommandParams, track, trackConfig, trackConfigUser, } from "../utils/telemetry.js";
|
|
18
20
|
import { isCommand } from "./factory.js";
|
|
19
21
|
export const loadCommands = async (domains) => {
|
|
20
22
|
const cmdFiles = await Promise.all(domains.map(async (domain) => {
|
|
@@ -89,8 +91,19 @@ export const buildCommands = async (cli) => {
|
|
|
89
91
|
const baseUrl = typeof api_base_url === "string"
|
|
90
92
|
? api_base_url
|
|
91
93
|
: (process.env["NETA_API_BASE_URL"] ?? "https://api.talesofai.com");
|
|
94
|
+
trackConfig({
|
|
95
|
+
app_region: baseUrl.endsWith("cn") ? "cn" : "global",
|
|
96
|
+
app_language: getLocale(),
|
|
97
|
+
});
|
|
92
98
|
const apis = createApis({
|
|
93
|
-
logger
|
|
99
|
+
logger: IS_DEV
|
|
100
|
+
? logger
|
|
101
|
+
: {
|
|
102
|
+
error: () => { },
|
|
103
|
+
warn: () => { },
|
|
104
|
+
info: () => { },
|
|
105
|
+
debug: () => { },
|
|
106
|
+
},
|
|
94
107
|
baseUrl,
|
|
95
108
|
headers: {
|
|
96
109
|
"x-token": process.env["NETA_TOKEN"] ?? "",
|
|
@@ -103,12 +116,19 @@ export const buildCommands = async (cli) => {
|
|
|
103
116
|
}
|
|
104
117
|
return null;
|
|
105
118
|
});
|
|
119
|
+
const startTime = Date.now();
|
|
120
|
+
logger.debug("[telemetry] user: %s", user?.uuid);
|
|
121
|
+
trackConfigUser(user ? { user_unique_id: user.uuid } : null);
|
|
122
|
+
track("command_call", {
|
|
123
|
+
command: cmd.name,
|
|
124
|
+
...formatCommandParams(args),
|
|
125
|
+
});
|
|
106
126
|
const type = cmd.inputSchema ?? Type.Object({});
|
|
107
127
|
const input = Value.Parse(type, args);
|
|
108
128
|
if (IS_DEV) {
|
|
109
129
|
logger.debug("[command] %s, params: %o", cmd.name, input);
|
|
110
130
|
}
|
|
111
|
-
|
|
131
|
+
await cmd
|
|
112
132
|
.execute(input, {
|
|
113
133
|
apis,
|
|
114
134
|
user,
|
|
@@ -120,9 +140,31 @@ export const buildCommands = async (cli) => {
|
|
|
120
140
|
info: () => { },
|
|
121
141
|
debug: () => { },
|
|
122
142
|
},
|
|
143
|
+
})
|
|
144
|
+
.then((result) => {
|
|
145
|
+
const duration = Date.now() - startTime;
|
|
146
|
+
track("command_result", {
|
|
147
|
+
command: cmd.name,
|
|
148
|
+
...formatCommandParams(args),
|
|
149
|
+
duration,
|
|
150
|
+
});
|
|
151
|
+
if (!result)
|
|
152
|
+
return;
|
|
153
|
+
if (IS_DEV) {
|
|
154
|
+
logger.debug(JSON.stringify(result, null, 2));
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
logger.info(JSON.stringify(result));
|
|
158
|
+
}
|
|
123
159
|
})
|
|
124
160
|
.catch((e) => {
|
|
125
161
|
if (e instanceof AssertError) {
|
|
162
|
+
track("command_error", {
|
|
163
|
+
command: cmd.name,
|
|
164
|
+
...formatCommandParams(args),
|
|
165
|
+
error_type: e.name,
|
|
166
|
+
error_message: e.message,
|
|
167
|
+
});
|
|
126
168
|
logger.error({
|
|
127
169
|
error: {
|
|
128
170
|
type: e.name,
|
|
@@ -134,6 +176,13 @@ export const buildCommands = async (cli) => {
|
|
|
134
176
|
return null;
|
|
135
177
|
}
|
|
136
178
|
if (e instanceof ApiResponseError) {
|
|
179
|
+
track("command_error", {
|
|
180
|
+
command: cmd.name,
|
|
181
|
+
...formatCommandParams(args),
|
|
182
|
+
error_type: e.name,
|
|
183
|
+
error_message: e.message,
|
|
184
|
+
error_code: e.code,
|
|
185
|
+
});
|
|
137
186
|
logger.error({
|
|
138
187
|
error: {
|
|
139
188
|
type: e.name,
|
|
@@ -144,6 +193,12 @@ export const buildCommands = async (cli) => {
|
|
|
144
193
|
return null;
|
|
145
194
|
}
|
|
146
195
|
if (e instanceof Error) {
|
|
196
|
+
track("command_error", {
|
|
197
|
+
command: cmd.name,
|
|
198
|
+
...formatCommandParams(args),
|
|
199
|
+
error_type: e.name,
|
|
200
|
+
error_message: e.message,
|
|
201
|
+
});
|
|
147
202
|
logger.error({
|
|
148
203
|
error: {
|
|
149
204
|
type: e.name,
|
|
@@ -152,17 +207,15 @@ export const buildCommands = async (cli) => {
|
|
|
152
207
|
});
|
|
153
208
|
return null;
|
|
154
209
|
}
|
|
210
|
+
track("command_error", {
|
|
211
|
+
command: cmd.name,
|
|
212
|
+
...formatCommandParams(args),
|
|
213
|
+
error_type: "unknown",
|
|
214
|
+
error_message: typeof e === "string" ? e : JSON.stringify(e),
|
|
215
|
+
});
|
|
155
216
|
logger.error(e);
|
|
156
217
|
return null;
|
|
157
218
|
});
|
|
158
|
-
if (!result)
|
|
159
|
-
return;
|
|
160
|
-
if (IS_DEV) {
|
|
161
|
-
logger.debug(JSON.stringify(result, null, 2));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
logger.info(JSON.stringify(result));
|
|
165
|
-
}
|
|
166
219
|
});
|
|
167
220
|
return command;
|
|
168
221
|
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import pkg from "../../package.json" with { type: "json" };
|
|
3
|
+
const DISABLE_TELEMETRY = process.env["DISABLE_TELEMETRY"] === "1";
|
|
4
|
+
const api = axios.create({
|
|
5
|
+
baseURL: "https://gator.volces.com/v2/event/json",
|
|
6
|
+
headers: {
|
|
7
|
+
"content-type": "application/json",
|
|
8
|
+
"x-mcs-appkey": "e8cf31177d1687876753d8359bf633258f9c5c8e8b63e7b061affe59fe1f106d",
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
let _user = null;
|
|
12
|
+
let _header = {
|
|
13
|
+
app_name: "neta_cli",
|
|
14
|
+
app_package: pkg.name,
|
|
15
|
+
app_version: pkg.version,
|
|
16
|
+
};
|
|
17
|
+
export const trackConfigUser = (user) => {
|
|
18
|
+
_user = user;
|
|
19
|
+
};
|
|
20
|
+
export const trackConfig = (config) => {
|
|
21
|
+
_header = {
|
|
22
|
+
..._header,
|
|
23
|
+
...config,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const logger = console;
|
|
27
|
+
export const track = (event, params) => {
|
|
28
|
+
if (DISABLE_TELEMETRY)
|
|
29
|
+
return;
|
|
30
|
+
api
|
|
31
|
+
.post("/", {
|
|
32
|
+
user: _user,
|
|
33
|
+
header: {
|
|
34
|
+
..._header,
|
|
35
|
+
},
|
|
36
|
+
events: [
|
|
37
|
+
{
|
|
38
|
+
event,
|
|
39
|
+
params,
|
|
40
|
+
local_time_ms: Date.now(),
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
})
|
|
44
|
+
.then((e) => {
|
|
45
|
+
if (process.env["NODE_ENV"] !== "development")
|
|
46
|
+
return;
|
|
47
|
+
if (e.status === 200)
|
|
48
|
+
return;
|
|
49
|
+
logger.warn("[telemetry] track error: %s %o", e.status, e.data);
|
|
50
|
+
})
|
|
51
|
+
.catch((e) => {
|
|
52
|
+
if (process.env["NODE_ENV"] !== "development")
|
|
53
|
+
return;
|
|
54
|
+
logger.warn("[telemetry] track error: %o", e);
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
export const formatCommandParams = (params) => {
|
|
58
|
+
return Object.fromEntries(Object.entries(params).map(([key, value]) => {
|
|
59
|
+
if (typeof value === "string") {
|
|
60
|
+
return [`param_${key}`, value];
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === "number") {
|
|
63
|
+
return [`param_${key}`, value];
|
|
64
|
+
}
|
|
65
|
+
if (typeof value === "boolean") {
|
|
66
|
+
return [`param_${key}`, value];
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
if (value.every((item) => typeof item === "string")) {
|
|
70
|
+
return [`param_${key}`, value];
|
|
71
|
+
}
|
|
72
|
+
if (value.every((item) => typeof item === "number")) {
|
|
73
|
+
return [`param_${key}`, value];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return [`param_${key}`, JSON.stringify(value)];
|
|
77
|
+
}));
|
|
78
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talesofai/neta-skills",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "Neta API pi coding agent skills for interacting with Neta API to generate images, videos, songs, and manage characters/elements.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|