Skip to content

Commit b761a04

Browse files
chore: sync from CloudBase-MCP
1 parent 3bfacc7 commit b761a04

6 files changed

Lines changed: 98 additions & 5 deletions

File tree

‎.plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://open-plugins.com/schemas/1.0.0/plugin.schema.json",
33
"name": "cloudbase",
4-
"version": "0.2.0",
4+
"version": "0.2.1",
55
"description": "Tencent CloudBase — AI models, authentication, NoSQL/PostgreSQL databases, cloud functions, cloud storage, CloudRun backend services, and WeChat Mini Program integration. Powered by cloudbase-mcp.",
66
"author": {
77
"name": "Tencent CloudBase",

‎.qoder-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cloudbase",
3-
"version": "0.2.0",
3+
"version": "0.2.1",
44
"description": "Tencent CloudBase — AI models, authentication, NoSQL/PostgreSQL databases, cloud functions, cloud storage, CloudRun backend services, and WeChat Mini Program integration. Powered by cloudbase-mcp.",
55
"author": {
66
"name": "Tencent CloudBase",

‎docs/qoder-submit.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Tone: product listing, not marketing. Write as a backend platform shipping an of
3535
|-------|-------|
3636
| Display name | CloudBase |
3737
| Technical `name` | `cloudbase` |
38-
| Version | From zip / `.qoder-plugin/plugin.json` (currently `0.2.0`) |
38+
| Version | From zip / `.qoder-plugin/plugin.json` (currently `0.2.1`) |
3939
| Category | Coding / DevOps / Database (if multi-select) |
4040
| Author | Tencent CloudBase |
4141
| Homepage | https://docs.cloudbase.net/ai/cloudbase-ai-toolkit/ |

‎hooks/plugin-telemetry.mjs‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
// - toolkit_plugin_first_use: once per local user profile
66
// Always includes pluginVersion. No prompts, paths, tool args, or skill-injection details.
77
//
8+
// Account attribution: reads ONLY `uin` (主账号 uin) and `envId` from the local CloudBase auth
9+
// file (~/.config/.cloudbase/auth.json). No network, no credential exchange — one file read.
10+
// Secret fields (refreshToken / tmpSecretId / tmpSecretKey / …) are never read, logged or sent.
11+
// Unreadable (no file / not logged in / env-level API Key, which carries no uin) → "unknown".
12+
//
813
// Disable: CLOUDBASE_PLUGIN_TELEMETRY=off (or CLOUDBASE_MCP_TELEMETRY_DISABLED=true)
914
import { createHash, randomBytes } from "crypto";
1015
import {
@@ -34,6 +39,11 @@ var BEACON_UPLOAD_URL = "https://otheve.beacon.qq.com/analytics/v2_upload";
3439
var BEACON_APP_KEY = "0WEB0AD0GM4PUUU1";
3540
var DEFAULT_TIMEOUT_MS = 1500;
3641

42+
// 本地登录态。只读 uin / envId 两个字段 —— 该文件同时装着 refreshToken 与临时密钥。
43+
var AUTH_FILE = join(homedir(), ".config", ".cloudbase", "auth.json");
44+
// CLI 站点配置;slotted 形态下靠它的 isIntl 决定取哪个槽(与 @cloudbase/toolbox 同规则)。
45+
var CLI_CONFIG_FILE = join(homedir(), ".config", ".cloudbase", "config.json");
46+
3747
export var PLUGIN_DAU_EVENT = "toolkit_plugin_dau";
3848
export var PLUGIN_FIRST_USE_EVENT = "toolkit_plugin_first_use";
3949

@@ -215,6 +225,84 @@ function postJson(url, data, timeoutMs = DEFAULT_TIMEOUT_MS) {
215225
});
216226
}
217227

228+
function readJsonQuietly(file) {
229+
try {
230+
return JSON.parse(readFileSync(file, "utf-8"));
231+
} catch {
232+
return undefined;
233+
}
234+
}
235+
236+
/**
237+
* 从登录态里挑出「当前有效的那份凭证」。
238+
*
239+
* 这个文件的形状**会变**,三种都要认(实测都出现过):
240+
* A. `{ credential: { uin, envId, tmpSecretId, … } }` ← flat,当前 CLI 写的就是它
241+
* B. `{ credential: { domestic: {…}, intl: {…} } }` ← slotted,双站点登录 / 旧版
242+
* C. `{ uin, envId, … }` ← 没有 credential 包裹(防御)
243+
*
244+
* slotted 时取哪个槽与 `@cloudbase/toolbox` 的 `migrateSlottedCredentialToFlat` 同规则:
245+
* 读 CLI `config.json` 的 `isIntl`;读不到 / 不是布尔值 ⇒ 退化为「取有凭证的那个,优先 domestic」。
246+
* 取错槽会拿到**另一个站点的 uin**,所以这一步不能省。
247+
*/
248+
function pickCredentialSlot(raw, cliConfigFile) {
249+
if (!raw || typeof raw !== "object") return undefined;
250+
const inner = raw.credential;
251+
const c = inner && typeof inner === "object" ? inner : raw;
252+
if (!c || typeof c !== "object") return undefined;
253+
254+
const domestic =
255+
c.domestic && typeof c.domestic === "object" ? c.domestic : undefined;
256+
const intl = c.intl && typeof c.intl === "object" ? c.intl : undefined;
257+
if (!domestic && !intl) return c; // flat
258+
259+
const cli = readJsonQuietly(cliConfigFile);
260+
const isIntl =
261+
cli && typeof cli.isIntl === "boolean" ? cli.isIntl : undefined;
262+
if (isIntl === true) return intl ?? domestic;
263+
if (isIntl === false) return domestic ?? intl;
264+
return domestic ?? intl;
265+
}
266+
267+
/** uin 可能是数字(实测 123811017)也可能是字符串;空 / "0" 视为没有。 */
268+
function normalizeUin(value) {
269+
if (value === undefined || value === null) return undefined;
270+
const s = String(value).trim();
271+
return s && s !== "0" ? s : undefined;
272+
}
273+
274+
/**
275+
* 从本地登录态读「主账号 uin」与「凭证上绑的环境 id」。
276+
*
277+
* ⚠️ **两者都可能读不到,这是常态**:
278+
* - `uin` 只在**账号级**登录态里有;环境级 API Key 的凭证自身不带 uin。
279+
* - `envId` 由 CLI 登录时写入(MCP 侧从不写),实测历史快照里只有很小一部分带它。
280+
* 读不到一律返回 undefined,由调用方上报 `unknown` —— 不抛错、不阻塞会话。
281+
*
282+
* 🔴 只读 `uin` / `envId`:同文件里的 refreshToken 与临时密钥绝不读取、绝不落日志、绝不上报。
283+
*/
284+
export function resolveLocalAuthFacts(options = {}) {
285+
const facts = { loginUin: undefined, envId: undefined };
286+
const slot = pickCredentialSlot(
287+
readJsonQuietly(options.authFile ?? AUTH_FILE),
288+
options.cliConfigFile ?? CLI_CONFIG_FILE,
289+
);
290+
if (!slot) return facts;
291+
292+
const uin = normalizeUin(slot.uin);
293+
if (uin) facts.loginUin = uin;
294+
if (typeof slot.envId === "string" && slot.envId.trim()) {
295+
facts.envId = slot.envId.trim();
296+
}
297+
return facts;
298+
}
299+
300+
/** 上报字段:读不到就报 `unknown`(与 MCP 侧 `toolkit_tool_call.envId` 同一约定)。 */
301+
export function buildAuthAttribution(options = {}) {
302+
const { loginUin, envId } = resolveLocalAuthFacts(options);
303+
return { login_uin: loginUin ?? "unknown", envId: envId ?? "unknown" };
304+
}
305+
218306
/**
219307
* Report lightweight plugin session telemetry (DAU + first use).
220308
* Stamps are written only after a successful Beacon upload (Vercel-aligned).
@@ -227,6 +315,8 @@ export async function reportPluginSessionTelemetry(options = {}) {
227315
now = new Date(),
228316
timeoutMs = DEFAULT_TIMEOUT_MS,
229317
postFetch = postJson,
318+
authFile,
319+
cliConfigFile,
230320
} = options;
231321

232322
if (!isPluginTelemetryEnabled(env)) {
@@ -236,6 +326,8 @@ export async function reportPluginSessionTelemetry(options = {}) {
236326
const pluginVersion = resolvePluginVersion(pluginRoot);
237327
const deviceId = buildDeviceId();
238328
const userAgent = buildUserAgent(pluginVersion);
329+
// 一次文件读;读不到就是两个 unknown,不影响下面两条事件
330+
const attribution = buildAuthAttribution({ authFile, cliConfigFile });
239331
const sent = [];
240332

241333
const sendEvent = async (eventCode, eventData, onSuccess) => {
@@ -244,6 +336,7 @@ export async function reportPluginSessionTelemetry(options = {}) {
244336
eventData: {
245337
pluginVersion,
246338
value: "1",
339+
...attribution,
247340
...eventData,
248341
},
249342
deviceId,

‎kimi.plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://kimi.com/schemas/kimi.plugin.schema.json",
33
"name": "cloudbase",
4-
"version": "0.2.0",
4+
"version": "0.2.1",
55
"description": "Tencent CloudBase \u2014 AI models, authentication, NoSQL/PostgreSQL databases, cloud functions, cloud storage, CloudRun backend services, and WeChat Mini Program integration. Powered by cloudbase-mcp.",
66
"keywords": [
77
"cloudbase",

‎plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
33
"name": "cloudbase",
4-
"version": "0.2.0",
4+
"version": "0.2.1",
55
"description": "Tencent CloudBase — AI models, authentication, NoSQL/PostgreSQL databases, cloud functions, cloud storage, CloudRun backend services, and WeChat Mini Program integration. Powered by cloudbase-mcp.",
66
"author": {
77
"name": "Tencent CloudBase",

0 commit comments

Comments
 (0)