@clawos-dev/clawd 0.2.605 → 0.2.607

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.
@@ -22843,6 +22843,8 @@ var LarkBotStatusResultSchema = external_exports.object({
22843
22843
  brokenReason: external_exports.string().optional(),
22844
22844
  /** provisioning 态:二维码内容 URL(UI 本地渲染成 QR 图;spec P5 无 expiresAt/倒计时) */
22845
22845
  qrUrl: external_exports.string().optional(),
22846
+ /** 云扫码会话可从中心恢复,供另一设备取消。 */
22847
+ provisionId: external_exports.string().optional(),
22846
22848
  /** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
22847
22849
  errorReason: LarkBotProvisionErrorReasonSchema.optional(),
22848
22850
  groups: external_exports.array(LarkBotGroupSchema),
@@ -23031,7 +23033,7 @@ var PersonaFileSchema = external_exports.object({
23031
23033
  * 上云的就是本机同名 persona,不加后缀发布者自己永远看不到「云上」组。gateway 不认识带后缀的名字,
23032
23034
  * 跟它说话(路径段、登记表)一律用 `cloud.personaId`。
23033
23035
  */
23034
- cloud: external_exports.object({ gatewayUrl: external_exports.string().min(1), personaId: external_exports.string().min(1) }).strict().optional()
23036
+ cloud: external_exports.object({ gatewayUrl: external_exports.string().min(1), personaId: external_exports.string().min(1), publishedByMe: external_exports.boolean().optional() }).strict().optional()
23035
23037
  }).strict();
23036
23038
  var PersonaSkillSummarySchema = external_exports.object({
23037
23039
  // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
@@ -24543,6 +24545,12 @@ var METHOD_DOCS = {
24543
24545
  summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
24544
24546
  args: LarkBotStatusArgs
24545
24547
  },
24548
+ "cloud:larkBot:provision": { summary: "\u4E3A\u672C\u4EBA\u53D1\u5E03\u7684\u4E91 Persona \u626B\u7801\u521B\u5EFA\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotProvisionArgs },
24549
+ "cloud:larkBot:provisionCancel": { summary: "\u53D6\u6D88\u4E91 Persona \u7684\u626B\u7801\u88C5\u914D\uFF1Bowner-only", args: LarkBotProvisionCancelArgs },
24550
+ "cloud:larkBot:bindManual": { summary: "\u4E3A\u672C\u4EBA\u53D1\u5E03\u7684\u4E91 Persona \u624B\u52A8\u7ED1\u5B9A\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotBindManualArgs },
24551
+ "cloud:larkBot:unbind": { summary: "\u89E3\u7ED1\u4E91 Persona \u7684\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotUnbindArgs },
24552
+ "cloud:larkBot:upgrade": { summary: "\u66F4\u65B0\u4E91 Persona \u98DE\u4E66 Bot \u6388\u6743\uFF1Bowner-only", args: LarkBotUpgradeArgs },
24553
+ "cloud:larkBot:status": { summary: "\u67E5\u770B\u4E91 Persona \u98DE\u4E66 Bot \u72B6\u6001\uFF1Bowner-only", args: LarkBotStatusArgs },
24546
24554
  "onboarding:complete": {
24547
24555
  summary: "\u6807\u8BB0\u9996\u542F onboarding \u5B8C\u6210\uFF1A\u5F80 <dataDir>/profile.json \u5199 onboardingCompletedAt\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF0C\u4FDD\u7559\u5176\u5B83\u5B57\u6BB5\uFF0C\u91CD\u590D\u8C03\u7528\u5E42\u7B49\uFF09\uFF1Binfo ready \u5E27\u643A\u5E26\u8BE5\u5B57\u6BB5\u4F9B UI \u5224\u5B9A\u662F\u5426\u8FDB wizard",
24548
24556
  args: OnboardingCompleteArgs
package/dist/cli.cjs CHANGED
@@ -7630,6 +7630,8 @@ var init_lark_bot_schemas = __esm({
7630
7630
  brokenReason: external_exports.string().optional(),
7631
7631
  /** provisioning 态:二维码内容 URL(UI 本地渲染成 QR 图;spec P5 无 expiresAt/倒计时) */
7632
7632
  qrUrl: external_exports.string().optional(),
7633
+ /** 云扫码会话可从中心恢复,供另一设备取消。 */
7634
+ provisionId: external_exports.string().optional(),
7633
7635
  /** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
7634
7636
  errorReason: LarkBotProvisionErrorReasonSchema.optional(),
7635
7637
  groups: external_exports.array(LarkBotGroupSchema),
@@ -7848,7 +7850,7 @@ var init_persona_schemas = __esm({
7848
7850
  * 上云的就是本机同名 persona,不加后缀发布者自己永远看不到「云上」组。gateway 不认识带后缀的名字,
7849
7851
  * 跟它说话(路径段、登记表)一律用 `cloud.personaId`。
7850
7852
  */
7851
- cloud: external_exports.object({ gatewayUrl: external_exports.string().min(1), personaId: external_exports.string().min(1) }).strict().optional()
7853
+ cloud: external_exports.object({ gatewayUrl: external_exports.string().min(1), personaId: external_exports.string().min(1), publishedByMe: external_exports.boolean().optional() }).strict().optional()
7852
7854
  }).strict();
7853
7855
  PersonaSkillSummarySchema = external_exports.object({
7854
7856
  // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
@@ -9458,6 +9460,12 @@ var init_methods = __esm({
9458
9460
  summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
9459
9461
  args: LarkBotStatusArgs
9460
9462
  },
9463
+ "cloud:larkBot:provision": { summary: "\u4E3A\u672C\u4EBA\u53D1\u5E03\u7684\u4E91 Persona \u626B\u7801\u521B\u5EFA\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotProvisionArgs },
9464
+ "cloud:larkBot:provisionCancel": { summary: "\u53D6\u6D88\u4E91 Persona \u7684\u626B\u7801\u88C5\u914D\uFF1Bowner-only", args: LarkBotProvisionCancelArgs },
9465
+ "cloud:larkBot:bindManual": { summary: "\u4E3A\u672C\u4EBA\u53D1\u5E03\u7684\u4E91 Persona \u624B\u52A8\u7ED1\u5B9A\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotBindManualArgs },
9466
+ "cloud:larkBot:unbind": { summary: "\u89E3\u7ED1\u4E91 Persona \u7684\u98DE\u4E66 Bot\uFF1Bowner-only", args: LarkBotUnbindArgs },
9467
+ "cloud:larkBot:upgrade": { summary: "\u66F4\u65B0\u4E91 Persona \u98DE\u4E66 Bot \u6388\u6743\uFF1Bowner-only", args: LarkBotUpgradeArgs },
9468
+ "cloud:larkBot:status": { summary: "\u67E5\u770B\u4E91 Persona \u98DE\u4E66 Bot \u72B6\u6001\uFF1Bowner-only", args: LarkBotStatusArgs },
9461
9469
  "onboarding:complete": {
9462
9470
  summary: "\u6807\u8BB0\u9996\u542F onboarding \u5B8C\u6210\uFF1A\u5F80 <dataDir>/profile.json \u5199 onboardingCompletedAt\uFF08\u6BEB\u79D2\u65F6\u95F4\u6233\uFF0C\u4FDD\u7559\u5176\u5B83\u5B57\u6BB5\uFF0C\u91CD\u590D\u8C03\u7528\u5E42\u7B49\uFF09\uFF1Binfo ready \u5E27\u643A\u5E26\u8BE5\u5B57\u6BB5\u4F9B UI \u5224\u5B9A\u662F\u5426\u8FDB wizard",
9463
9471
  args: OnboardingCompleteArgs
@@ -63234,42 +63242,124 @@ async function refreshTunnelUrlOnStartup(deps) {
63234
63242
  }
63235
63243
  }
63236
63244
 
63237
- // src/lark-bot-connector/binding-store.ts
63238
- var import_node_fs37 = __toESM(require("fs"), 1);
63239
- var import_node_path42 = __toESM(require("path"), 1);
63240
- function createLarkBotBindingStore(personaRoot) {
63241
- const filePath = (personaId2) => import_node_path42.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
63242
- const read = (personaId2) => {
63243
- const file = filePath(personaId2);
63244
- if (!import_node_fs37.default.existsSync(file)) return null;
63245
- try {
63246
- const raw = JSON.parse(import_node_fs37.default.readFileSync(file, "utf8"));
63247
- if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
63248
- return raw;
63249
- } catch {
63250
- return null;
63245
+ // src/handlers/cloud-lark-bot.ts
63246
+ init_protocol();
63247
+ function buildCloudLarkBotHandlers(deps) {
63248
+ const flights = /* @__PURE__ */ new Map();
63249
+ const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve9) => setTimeout(resolve9, ms)));
63250
+ function requireCloudPersona(personaId2, ctx) {
63251
+ if (!ctx || ctx.principal.kind !== "owner") throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "owner only");
63252
+ const persona = deps.getPersona(personaId2);
63253
+ if (!persona?.cloud || !persona.cloud.publishedByMe) {
63254
+ throw new ClawdError(ERROR_CODES.UNAUTHORIZED, "\u53EA\u6709\u4E91 Persona \u7684\u53D1\u5E03\u8005\u80FD\u7BA1\u7406\u98DE\u4E66 Bot");
63255
+ }
63256
+ return persona.cloud.personaId;
63257
+ }
63258
+ const emit = (personaId2, status2) => deps.broadcast({ type: "larkBot:state", personaId: personaId2, ...status2 });
63259
+ async function state(personaId2, gatewayId) {
63260
+ const base = await deps.cloud.status(gatewayId);
63261
+ const flight = flights.get(personaId2);
63262
+ if (!flight || flight.cancelled) return base;
63263
+ return flight.upgrade ? { ...base, upgradeQrUrl: flight.qrUrl, needsUpgrade: true } : { state: "provisioning", qrUrl: flight.qrUrl, groups: [] };
63264
+ }
63265
+ async function poll(personaId2, gatewayId, flight) {
63266
+ const deadline = Date.now() + 60 * 60 * 1e3;
63267
+ let failures = 0;
63268
+ while (flights.get(personaId2) === flight && !flight.cancelled && Date.now() < deadline) {
63269
+ await sleep2(2e3);
63270
+ if (flights.get(personaId2) !== flight || flight.cancelled) return;
63271
+ try {
63272
+ if (flight.upgrade) {
63273
+ const next = await deps.cloud.status(gatewayId);
63274
+ if (next.needsUpgrade !== false) continue;
63275
+ } else {
63276
+ const next = await deps.cloud.provisionStatus(gatewayId, flight.provisionId);
63277
+ if (next.state === "pending") continue;
63278
+ if (next.state === "error") {
63279
+ flights.delete(personaId2);
63280
+ emit(personaId2, { state: "unbound", groups: [], errorReason: "internal_error" });
63281
+ return;
63282
+ }
63283
+ }
63284
+ flights.delete(personaId2);
63285
+ emit(personaId2, await deps.cloud.status(gatewayId));
63286
+ return;
63287
+ } catch (err) {
63288
+ if (++failures < 5) continue;
63289
+ deps.logger?.warn(`cloud bot provision polling failed: ${err.message}`);
63290
+ break;
63291
+ }
63251
63292
  }
63293
+ if (flights.get(personaId2) === flight) {
63294
+ flights.delete(personaId2);
63295
+ emit(personaId2, await deps.cloud.status(gatewayId).catch(() => ({ state: "unbound", groups: [] })));
63296
+ }
63297
+ }
63298
+ const status = async (frame, _client, ctx) => {
63299
+ const { personaId: personaId2 } = parseArgs2(LarkBotStatusArgs, frame, "cloud:larkBot:status");
63300
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63301
+ return { response: { type: "cloud:larkBot:status:ok", ...await state(personaId2, gatewayId) } };
63252
63302
  };
63253
- const write = (personaId2, meta) => {
63254
- const file = filePath(personaId2);
63255
- import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
63256
- const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
63257
- import_node_fs37.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
63258
- import_node_fs37.default.renameSync(tmp, file);
63303
+ const provision = async (frame, _client, ctx) => {
63304
+ const { personaId: personaId2 } = parseArgs2(LarkBotProvisionArgs, frame, "cloud:larkBot:provision");
63305
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63306
+ if (flights.has(personaId2)) throw new Error("\u626B\u7801\u5DF2\u5728\u8FDB\u884C");
63307
+ const { provisionId, qrUrl } = await deps.cloud.provision(gatewayId);
63308
+ const flight = { provisionId, qrUrl, cancelled: false, upgrade: false };
63309
+ flights.set(personaId2, flight);
63310
+ emit(personaId2, { state: "provisioning", qrUrl, groups: [] });
63311
+ void poll(personaId2, gatewayId, flight);
63312
+ return { response: { type: "cloud:larkBot:provision:ok" } };
63259
63313
  };
63260
- return {
63261
- read,
63262
- write,
63263
- remove(personaId2) {
63264
- import_node_fs37.default.rmSync(filePath(personaId2), { force: true });
63265
- },
63266
- addRemovedChat(personaId2, chatId) {
63267
- const meta = read(personaId2);
63268
- if (!meta) return;
63269
- const set = new Set(meta.removedChatIds ?? []);
63270
- set.add(chatId);
63271
- write(personaId2, { ...meta, removedChatIds: [...set] });
63314
+ const cancel = async (frame, _client, ctx) => {
63315
+ const { personaId: personaId2 } = parseArgs2(LarkBotProvisionCancelArgs, frame, "cloud:larkBot:provisionCancel");
63316
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63317
+ const flight = flights.get(personaId2);
63318
+ if (flight) {
63319
+ flight.cancelled = true;
63320
+ flights.delete(personaId2);
63321
+ await deps.cloud.cancel(gatewayId, flight.provisionId);
63322
+ } else {
63323
+ const remote = await deps.cloud.status(gatewayId);
63324
+ if (remote.state === "provisioning" && remote.provisionId) {
63325
+ await deps.cloud.cancel(gatewayId, remote.provisionId);
63326
+ }
63272
63327
  }
63328
+ emit(personaId2, await deps.cloud.status(gatewayId));
63329
+ return { response: { type: "cloud:larkBot:provisionCancel:ok" } };
63330
+ };
63331
+ const bindManual = async (frame, _client, ctx) => {
63332
+ const { personaId: personaId2, appId, appSecret, botName } = parseArgs2(LarkBotBindManualArgs, frame, "cloud:larkBot:bindManual");
63333
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63334
+ await deps.cloud.bindManual(gatewayId, appId, appSecret, botName ?? gatewayId);
63335
+ emit(personaId2, await deps.cloud.status(gatewayId));
63336
+ return { response: { type: "cloud:larkBot:bindManual:ok" } };
63337
+ };
63338
+ const unbind = async (frame, _client, ctx) => {
63339
+ const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "cloud:larkBot:unbind");
63340
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63341
+ await deps.cloud.unbind(gatewayId);
63342
+ emit(personaId2, { state: "unbound", groups: [] });
63343
+ return { response: { type: "cloud:larkBot:unbind:ok" } };
63344
+ };
63345
+ const upgrade = async (frame, _client, ctx) => {
63346
+ const { personaId: personaId2 } = parseArgs2(LarkBotUpgradeArgs, frame, "cloud:larkBot:upgrade");
63347
+ const gatewayId = requireCloudPersona(personaId2, ctx);
63348
+ if (flights.has(personaId2)) throw new Error("\u626B\u7801\u5DF2\u5728\u8FDB\u884C");
63349
+ const { provisionId, qrUrl } = await deps.cloud.upgrade(gatewayId);
63350
+ const flight = { provisionId, qrUrl, cancelled: false, upgrade: true };
63351
+ flights.set(personaId2, flight);
63352
+ emit(personaId2, await state(personaId2, gatewayId));
63353
+ void poll(personaId2, gatewayId, flight);
63354
+ return { response: { type: "cloud:larkBot:upgrade:ok" } };
63355
+ };
63356
+ return {
63357
+ "cloud:larkBot:status": status,
63358
+ "cloud:larkBot:provision": provision,
63359
+ "cloud:larkBot:provisionCancel": cancel,
63360
+ "cloud:larkBot:bindManual": bindManual,
63361
+ "cloud:larkBot:unbind": unbind,
63362
+ "cloud:larkBot:upgrade": upgrade
63273
63363
  };
63274
63364
  }
63275
63365
 
@@ -63412,6 +63502,77 @@ function createLarkBotCloudClient(opts) {
63412
63502
  };
63413
63503
  }
63414
63504
 
63505
+ // src/lark-bot-connector/cloud-persona-client.ts
63506
+ function createCloudPersonaBotClient(opts) {
63507
+ const f2 = opts.fetchImpl ?? fetch;
63508
+ const base = opts.api.replace(/\/+$/, "");
63509
+ const route = (personaId2) => `/api/lark-bot/cloud/${encodeURIComponent(personaId2)}`;
63510
+ async function request(method, path106, body) {
63511
+ const pass = opts.getLoginPass();
63512
+ if (!pass) throw new LarkBotCloudError("\u98DE\u4E66\u767B\u5F55\u540E\u624D\u80FD\u7BA1\u7406\u4E91 Persona \u7684 Bot", 401);
63513
+ const response = await f2(base + path106, {
63514
+ method,
63515
+ headers: { authorization: `Bearer ${pass}`, "content-type": "application/json" },
63516
+ ...body ? { body: JSON.stringify(body) } : {},
63517
+ signal: AbortSignal.timeout(15e3)
63518
+ });
63519
+ const json = await response.json().catch(() => ({}));
63520
+ if (!response.ok) {
63521
+ const detail = typeof json.message === "string" ? json.message : `HTTP ${response.status}`;
63522
+ throw new LarkBotCloudError(`cloud bot ${method} ${path106}: ${detail}`, response.status);
63523
+ }
63524
+ return json;
63525
+ }
63526
+ return {
63527
+ status: async (personaId2) => await request("GET", `${route(personaId2)}/status`),
63528
+ provision: async (personaId2) => await request("POST", `${route(personaId2)}/provision`),
63529
+ provisionStatus: async (personaId2, provisionId) => await request("GET", `${route(personaId2)}/provision/${encodeURIComponent(provisionId)}`),
63530
+ cancel: async (personaId2, provisionId) => await request("DELETE", `${route(personaId2)}/provision/${encodeURIComponent(provisionId)}`),
63531
+ upgrade: async (personaId2) => await request("POST", `${route(personaId2)}/upgrade`),
63532
+ bindManual: async (personaId2, appId, appSecret, botName) => await request("PUT", `${route(personaId2)}/bind`, { personaId: personaId2, appId, appSecret, botName }),
63533
+ unbind: async (personaId2) => await request("DELETE", `${route(personaId2)}/bind`)
63534
+ };
63535
+ }
63536
+
63537
+ // src/lark-bot-connector/binding-store.ts
63538
+ var import_node_fs37 = __toESM(require("fs"), 1);
63539
+ var import_node_path42 = __toESM(require("path"), 1);
63540
+ function createLarkBotBindingStore(personaRoot) {
63541
+ const filePath = (personaId2) => import_node_path42.default.join(personaRoot, safeFileName(personaId2), ".clawd", "lark-bot.json");
63542
+ const read = (personaId2) => {
63543
+ const file = filePath(personaId2);
63544
+ if (!import_node_fs37.default.existsSync(file)) return null;
63545
+ try {
63546
+ const raw = JSON.parse(import_node_fs37.default.readFileSync(file, "utf8"));
63547
+ if (typeof raw?.appId !== "string" || raw.appId.length === 0) return null;
63548
+ return raw;
63549
+ } catch {
63550
+ return null;
63551
+ }
63552
+ };
63553
+ const write = (personaId2, meta) => {
63554
+ const file = filePath(personaId2);
63555
+ import_node_fs37.default.mkdirSync(import_node_path42.default.dirname(file), { recursive: true });
63556
+ const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
63557
+ import_node_fs37.default.writeFileSync(tmp, JSON.stringify(meta, null, 2), { mode: 384 });
63558
+ import_node_fs37.default.renameSync(tmp, file);
63559
+ };
63560
+ return {
63561
+ read,
63562
+ write,
63563
+ remove(personaId2) {
63564
+ import_node_fs37.default.rmSync(filePath(personaId2), { force: true });
63565
+ },
63566
+ addRemovedChat(personaId2, chatId) {
63567
+ const meta = read(personaId2);
63568
+ if (!meta) return;
63569
+ const set = new Set(meta.removedChatIds ?? []);
63570
+ set.add(chatId);
63571
+ write(personaId2, { ...meta, removedChatIds: [...set] });
63572
+ }
63573
+ };
63574
+ }
63575
+
63415
63576
  // src/lark-bot-connector/chat-router.ts
63416
63577
  var import_node_fs38 = __toESM(require("fs"), 1);
63417
63578
  var import_node_path43 = __toESM(require("path"), 1);
@@ -64367,7 +64528,7 @@ var CloudApiKeyRequiredError = class extends Error {
64367
64528
  }
64368
64529
  };
64369
64530
  var CLOUD_PERSONA_ID_SUFFIX = "-cloud";
64370
- function cloudPersonaToFile(p3) {
64531
+ function cloudPersonaToFile(p3, publishedByMe = false) {
64371
64532
  const at3 = p3.registeredAt ?? 0;
64372
64533
  return {
64373
64534
  personaId: p3.personaId + CLOUD_PERSONA_ID_SUFFIX,
@@ -64378,7 +64539,7 @@ function cloudPersonaToFile(p3) {
64378
64539
  public: false,
64379
64540
  createdAt: at3,
64380
64541
  updatedAt: at3,
64381
- cloud: { gatewayUrl: p3.gatewayUrl, personaId: p3.personaId }
64542
+ cloud: { gatewayUrl: p3.gatewayUrl, personaId: p3.personaId, ...publishedByMe ? { publishedByMe: true } : {} }
64382
64543
  };
64383
64544
  }
64384
64545
  var CloudGatewayClient = class {
@@ -73122,6 +73283,12 @@ var METHOD_GRANT_MAP = {
73122
73283
  "larkBot:unbind": ADMIN_ANY,
73123
73284
  "larkBot:status": ADMIN_ANY,
73124
73285
  "larkBot:upgrade": ADMIN_ANY,
73286
+ "cloud:larkBot:provision": ADMIN_ANY,
73287
+ "cloud:larkBot:provisionCancel": ADMIN_ANY,
73288
+ "cloud:larkBot:bindManual": ADMIN_ANY,
73289
+ "cloud:larkBot:unbind": ADMIN_ANY,
73290
+ "cloud:larkBot:status": ADMIN_ANY,
73291
+ "cloud:larkBot:upgrade": ADMIN_ANY,
73125
73292
  // ---- onboarding:* / tools:probe / session:externalScan(首启 wizard,owner-only)----
73126
73293
  "onboarding:complete": ADMIN_ANY,
73127
73294
  "onboarding:iosInterest": ADMIN_ANY,
@@ -73264,7 +73431,7 @@ function computeMethodAccess(args) {
73264
73431
  }
73265
73432
 
73266
73433
  // src/version.ts
73267
- var version = "0.2.605".length > 0 ? "0.2.605" : "dev";
73434
+ var version = "0.2.607".length > 0 ? "0.2.607" : "dev";
73268
73435
 
73269
73436
  // src/cli-probe/probe.ts
73270
73437
  var fs83 = __toESM(require("fs"), 1);
@@ -76426,7 +76593,17 @@ async function startDaemon(config) {
76426
76593
  const refreshCloudPersonas = async () => {
76427
76594
  try {
76428
76595
  const list = await cloudGateway.listPersonas();
76429
- const shadowed = personaRegistry.setCloudSnapshot(list.map(cloudPersonaToFile));
76596
+ const loginPass = ownerIdentityStore.read()?.loginPass;
76597
+ const publishedIds = /* @__PURE__ */ new Set();
76598
+ if (loginPass) {
76599
+ try {
76600
+ const visible = await centralVisiblePersonas({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, loginPass });
76601
+ for (const id of visible.personaIds) publishedIds.add(id);
76602
+ } catch (err) {
76603
+ logger.warn("cloud bot publisher lookup failed; binding controls hidden", { reason: err.message });
76604
+ }
76605
+ }
76606
+ const shadowed = personaRegistry.setCloudSnapshot(list.map((p3) => cloudPersonaToFile(p3, publishedIds.has(p3.personaId))));
76430
76607
  if (shadowed.length > 0) {
76431
76608
  logger.warn("cloud personas shadowed by local personas with the same id", { personaIds: shadowed });
76432
76609
  }
@@ -77056,6 +77233,15 @@ async function startDaemon(config) {
77056
77233
  logger: { warn: (msg) => logger.warn(msg) }
77057
77234
  };
77058
77235
  Object.assign(handlers, buildLarkBotHandlers(larkBotDeps));
77236
+ Object.assign(handlers, buildCloudLarkBotHandlers({
77237
+ getPersona: (personaId2) => personaRegistry.get(personaId2),
77238
+ cloud: createCloudPersonaBotClient({
77239
+ api: config.clawosApi ?? DEFAULT_CLAWOS_API,
77240
+ getLoginPass: () => ownerIdentityStore.read()?.loginPass ?? null
77241
+ }),
77242
+ broadcast: (frame) => wsServer?.broadcastToOwners(frame),
77243
+ logger: { warn: (message) => logger.warn(message) }
77244
+ }));
77059
77245
  Object.assign(
77060
77246
  handlers,
77061
77247
  buildOnboardingHandlers({