@clawos-dev/clawd 0.2.437 → 0.2.438

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/dist/cli.cjs CHANGED
@@ -6944,13 +6944,14 @@ var init_github = __esm({
6944
6944
  });
6945
6945
 
6946
6946
  // ../protocol/src/lark-bot-schemas.ts
6947
- var LarkBotPersonaArgs, LarkBotUnbindArgs, LarkBotStatusArgs, LarkBotProvisionArgs, LarkBotProvisionCancelArgs, LARK_BOT_PROVISION_ERROR_REASONS, LarkBotProvisionErrorReasonSchema, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
6947
+ var LarkBotPersonaArgs, LarkBotUnbindArgs, LarkBotUpgradeArgs, LarkBotStatusArgs, LarkBotProvisionArgs, LarkBotProvisionCancelArgs, LARK_BOT_PROVISION_ERROR_REASONS, LarkBotProvisionErrorReasonSchema, LarkBotBindManualArgs, LarkBotGroupSchema, LarkBotStatusResultSchema, LarkBotStateFrameSchema;
6948
6948
  var init_lark_bot_schemas = __esm({
6949
6949
  "../protocol/src/lark-bot-schemas.ts"() {
6950
6950
  "use strict";
6951
6951
  init_zod();
6952
6952
  LarkBotPersonaArgs = external_exports.object({ personaId: external_exports.string().min(1) });
6953
6953
  LarkBotUnbindArgs = LarkBotPersonaArgs;
6954
+ LarkBotUpgradeArgs = external_exports.object({ personaId: external_exports.string().min(1) });
6954
6955
  LarkBotStatusArgs = LarkBotPersonaArgs;
6955
6956
  LarkBotProvisionArgs = LarkBotPersonaArgs;
6956
6957
  LarkBotProvisionCancelArgs = LarkBotPersonaArgs;
@@ -6984,7 +6985,21 @@ var init_lark_bot_schemas = __esm({
6984
6985
  qrUrl: external_exports.string().optional(),
6985
6986
  /** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
6986
6987
  errorReason: LarkBotProvisionErrorReasonSchema.optional(),
6987
- groups: external_exports.array(LarkBotGroupSchema)
6988
+ groups: external_exports.array(LarkBotGroupSchema),
6989
+ /**
6990
+ * bound 态:该 bot 实际授予的 scope 缺了 LARK_PROVISION_ADDONS 里声明的项
6991
+ * (spec 2026-09-01)——addons 是扫码时一次性写进飞书应用配置的,后来新增的
6992
+ * scope / 事件对存量 bot 不生效,不提示的话用户只会觉得「功能没生效」。
6993
+ * 判定真源是飞书回读的 granted scopes,不落库任何版本号。
6994
+ */
6995
+ needsUpgrade: external_exports.boolean().optional(),
6996
+ /**
6997
+ * bound 态叠加:正在扫码更新授权(spec 2026-09-01)。
6998
+ * **不复用 provisioning 态**——升级期间 bot 仍在正常服务(长连接不断、群照常响应),
6999
+ * 降级成 provisioning 会丢掉 botName / groups,UI 上像是断了。
7000
+ * 有值即渲染二维码弹层;升级结束(成功或取消)该字段消失。
7001
+ */
7002
+ upgradeQrUrl: external_exports.string().optional()
6988
7003
  });
6989
7004
  LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
6990
7005
  personaId: external_exports.string().min(1)
@@ -8712,6 +8727,10 @@ var init_methods = __esm({
8712
8727
  summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
8713
8728
  args: LarkBotUnbindArgs
8714
8729
  },
8730
+ "larkBot:upgrade": {
8731
+ summary: "\u626B\u7801\u66F4\u65B0\u5DF2\u7ED1\u5B9A bot \u7684\u6388\u6743\uFF08\u8865\u540E\u6765\u65B0\u589E\u7684 scope / \u4E8B\u4EF6\uFF09\uFF1B\u5168\u7A0B\u4FDD\u6301 bound\uFF0Cbot \u4E0D\u65AD\u8FDE\uFF1Bowner-only",
8732
+ args: LarkBotUpgradeArgs
8733
+ },
8715
8734
  "larkBot:status": {
8716
8735
  summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
8717
8736
  args: LarkBotStatusArgs
@@ -54030,6 +54049,7 @@ function buildShiftInternalHandlers(deps) {
54030
54049
  init_protocol();
54031
54050
  var PROVISION_ERROR_SET = new Set(LARK_BOT_PROVISION_ERROR_REASONS);
54032
54051
  var PROVISION_POLL_INTERVAL_MS = 2e3;
54052
+ var UPGRADE_POLL_MAX_FAILURES = 5;
54033
54053
  var PROVISION_MAX_CONSECUTIVE_FAILURES = 5;
54034
54054
  var PROVISION_POLL_MAX_MS = 60 * 60 * 1e3;
54035
54055
  function normalizeProvisionReason(reason) {
@@ -54043,6 +54063,7 @@ function buildLarkBotHandlers(deps) {
54043
54063
  const sleep2 = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
54044
54064
  const pollIntervalMs = deps.pollIntervalMs ?? PROVISION_POLL_INTERVAL_MS;
54045
54065
  const inFlight = /* @__PURE__ */ new Map();
54066
+ const upgradeInFlight = /* @__PURE__ */ new Map();
54046
54067
  const groupsOf = (personaId2) => {
54047
54068
  const removed = new Set(deps.store.read(personaId2)?.removedChatIds ?? []);
54048
54069
  return deps.listLarkSessions(personaId2).filter((g2) => !removed.has(g2.chatId));
@@ -54141,8 +54162,121 @@ function buildLarkBotHandlers(deps) {
54141
54162
  void runProvisionPolling(personaId2, provisionId);
54142
54163
  return { response: { type: "larkBot:provision:ok" } };
54143
54164
  };
54165
+ const runUpgradePolling = async (personaId2) => {
54166
+ const backToBound = (needsUpgrade) => {
54167
+ upgradeInFlight.delete(personaId2);
54168
+ const fresh = deps.store.read(personaId2);
54169
+ if (!fresh) {
54170
+ emit(personaId2, { state: "unbound", groups: [] });
54171
+ return;
54172
+ }
54173
+ emit(personaId2, {
54174
+ state: "bound",
54175
+ appId: fresh.appId,
54176
+ botName: fresh.botName,
54177
+ ...needsUpgrade ? { needsUpgrade: true } : {},
54178
+ groups: groupsOf(personaId2)
54179
+ });
54180
+ };
54181
+ const startedAt = now();
54182
+ let failures = 0;
54183
+ for (; ; ) {
54184
+ await sleep2(pollIntervalMs);
54185
+ const entry = upgradeInFlight.get(personaId2);
54186
+ if (!entry || entry.cancelled) return;
54187
+ if (now() - startedAt >= PROVISION_POLL_MAX_MS) {
54188
+ deps.logger?.warn(`larkBot upgrade poll deadline exceeded: ${personaId2}`);
54189
+ backToBound(true);
54190
+ return;
54191
+ }
54192
+ let stillNeeds;
54193
+ try {
54194
+ const binding = (await deps.cloud.listBindings()).find((b2) => b2.personaId === personaId2);
54195
+ if (!binding) {
54196
+ backToBound(false);
54197
+ return;
54198
+ }
54199
+ stillNeeds = binding.needsUpgrade !== false;
54200
+ failures = 0;
54201
+ if (!upgradeInFlight.get(personaId2) || upgradeInFlight.get(personaId2)?.cancelled) return;
54202
+ } catch (err) {
54203
+ failures += 1;
54204
+ deps.logger?.warn(`larkBot upgrade poll failed (${failures}): ${err.message}`);
54205
+ if (failures >= UPGRADE_POLL_MAX_FAILURES) {
54206
+ backToBound(true);
54207
+ return;
54208
+ }
54209
+ await sleep2(pollIntervalMs * 2 ** failures);
54210
+ continue;
54211
+ }
54212
+ if (!stillNeeds) {
54213
+ backToBound(false);
54214
+ return;
54215
+ }
54216
+ }
54217
+ };
54218
+ const upgrade = async (frame) => {
54219
+ const { personaId: personaId2 } = parseArgs2(LarkBotUpgradeArgs, frame, "larkBot:upgrade");
54220
+ const meta = deps.store.read(personaId2);
54221
+ if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
54222
+ if (inFlight.has(personaId2) || upgradeInFlight.has(personaId2)) {
54223
+ throw new Error(`larkBot provision already in flight: ${personaId2}`);
54224
+ }
54225
+ upgradeInFlight.set(personaId2, { provisionId: "", qrUrl: "", cancelled: false });
54226
+ let provisionId;
54227
+ let qrUrl;
54228
+ try {
54229
+ ;
54230
+ ({ provisionId, qrUrl } = await deps.cloud.provisionUpgrade({ personaId: personaId2 }));
54231
+ } catch (err) {
54232
+ upgradeInFlight.delete(personaId2);
54233
+ throw err;
54234
+ }
54235
+ const placeholder = upgradeInFlight.get(personaId2);
54236
+ if (!placeholder || placeholder.cancelled) {
54237
+ upgradeInFlight.delete(personaId2);
54238
+ void deps.cloud.provisionCancel(provisionId).catch(
54239
+ (err) => deps.logger?.warn(`larkBot upgrade cancel-during-begin: ${err.message}`)
54240
+ );
54241
+ return { response: { type: "larkBot:upgrade:ok" } };
54242
+ }
54243
+ upgradeInFlight.set(personaId2, { provisionId, qrUrl, cancelled: false });
54244
+ emit(personaId2, {
54245
+ state: "bound",
54246
+ appId: meta.appId,
54247
+ botName: meta.botName,
54248
+ needsUpgrade: true,
54249
+ upgradeQrUrl: qrUrl,
54250
+ groups: groupsOf(personaId2)
54251
+ });
54252
+ void runUpgradePolling(personaId2);
54253
+ return { response: { type: "larkBot:upgrade:ok" } };
54254
+ };
54144
54255
  const provisionCancel = async (frame) => {
54145
54256
  const { personaId: personaId2 } = parseArgs2(LarkBotProvisionCancelArgs, frame, "larkBot:provisionCancel");
54257
+ const upgrading = upgradeInFlight.get(personaId2);
54258
+ if (upgrading) {
54259
+ upgrading.cancelled = true;
54260
+ upgradeInFlight.delete(personaId2);
54261
+ if (upgrading.provisionId) {
54262
+ await deps.cloud.provisionCancel(upgrading.provisionId).catch(
54263
+ (err) => deps.logger?.warn(`larkBot upgrade cancel cloud failed: ${err.message}`)
54264
+ );
54265
+ }
54266
+ const meta = deps.store.read(personaId2);
54267
+ emit(
54268
+ personaId2,
54269
+ meta ? {
54270
+ state: "bound",
54271
+ appId: meta.appId,
54272
+ botName: meta.botName,
54273
+ // 取消了就是没升成,提示条留着
54274
+ needsUpgrade: true,
54275
+ groups: groupsOf(personaId2)
54276
+ } : { state: "unbound", groups: [] }
54277
+ );
54278
+ return { response: { type: "larkBot:provisionCancel:ok" } };
54279
+ }
54146
54280
  const entry = inFlight.get(personaId2);
54147
54281
  if (!entry) throw new Error(`larkBot provision not in flight: ${personaId2}`);
54148
54282
  entry.cancelled = true;
@@ -54182,6 +54316,7 @@ function buildLarkBotHandlers(deps) {
54182
54316
  const ownerId = deps.getOwnerId();
54183
54317
  if (!ownerId) throw new Error("larkBot bind requires feishu login (owner identity)");
54184
54318
  const name = botName ?? deps.getPersonaName(personaId2) ?? personaId2;
54319
+ upgradeInFlight.delete(personaId2);
54185
54320
  await deps.cloud.bind({ personaId: personaId2, appId, appSecret, botName: name, tunnelUrl, ownerId });
54186
54321
  deps.store.write(personaId2, { appId, botName: name, boundAt: now() });
54187
54322
  emit(personaId2, { state: "bound", appId, botName: name, groups: groupsOf(personaId2) });
@@ -54189,6 +54324,7 @@ function buildLarkBotHandlers(deps) {
54189
54324
  };
54190
54325
  const unbind = async (frame) => {
54191
54326
  const { personaId: personaId2 } = parseArgs2(LarkBotUnbindArgs, frame, "larkBot:unbind");
54327
+ upgradeInFlight.delete(personaId2);
54192
54328
  const meta = deps.store.read(personaId2);
54193
54329
  if (!meta) throw new Error(`larkBot not bound: ${personaId2}`);
54194
54330
  try {
@@ -54214,6 +54350,8 @@ function buildLarkBotHandlers(deps) {
54214
54350
  }
54215
54351
  };
54216
54352
  }
54353
+ const upgrading = upgradeInFlight.get(personaId2);
54354
+ const upgradingQr = upgrading && !upgrading.cancelled ? upgrading.qrUrl : void 0;
54217
54355
  const meta = deps.store.read(personaId2);
54218
54356
  let cloudReachable = false;
54219
54357
  let cloudBinding;
@@ -54235,7 +54373,10 @@ function buildLarkBotHandlers(deps) {
54235
54373
  state: broken2 ? "broken" : "bound",
54236
54374
  appId: cloudBinding.appId,
54237
54375
  botName: cloudBinding.botName,
54376
+ ...upgradingQr ? { needsUpgrade: true, upgradeQrUrl: upgradingQr } : {},
54238
54377
  ...broken2 ? { brokenReason: cloudBinding.brokenReason ?? "unknown" } : {},
54378
+ // 云端判定(它持有飞书回读的 granted scopes),daemon 只透传(spec 2026-09-01)
54379
+ ...cloudBinding.needsUpgrade ? { needsUpgrade: true } : {},
54239
54380
  groups: groupsOf(personaId2)
54240
54381
  };
54241
54382
  return { response: { type: "larkBot:status:ok", ...result2 } };
@@ -54262,7 +54403,10 @@ function buildLarkBotHandlers(deps) {
54262
54403
  state: broken ? "broken" : "bound",
54263
54404
  appId: cloudBinding?.appId ?? meta.appId,
54264
54405
  botName: cloudBinding?.botName ?? meta.botName,
54406
+ ...upgradingQr ? { needsUpgrade: true, upgradeQrUrl: upgradingQr } : {},
54265
54407
  ...broken ? { brokenReason: cloudBinding?.brokenReason ?? "unknown" } : {},
54408
+ // 云端不可达时 cloudBinding 为空 → 不提示升级(宁可不提示也不误报)
54409
+ ...cloudBinding?.needsUpgrade ? { needsUpgrade: true } : {},
54266
54410
  groups: groupsOf(personaId2)
54267
54411
  };
54268
54412
  return { response: { type: "larkBot:status:ok", ...result } };
@@ -54272,7 +54416,8 @@ function buildLarkBotHandlers(deps) {
54272
54416
  "larkBot:provisionCancel": provisionCancel,
54273
54417
  "larkBot:bindManual": bindManual,
54274
54418
  "larkBot:unbind": unbind,
54275
- "larkBot:status": status
54419
+ "larkBot:status": status,
54420
+ "larkBot:upgrade": upgrade
54276
54421
  };
54277
54422
  }
54278
54423
  async function refreshTunnelUrlOnStartup(deps) {
@@ -54392,6 +54537,10 @@ function createLarkBotCloudClient(opts) {
54392
54537
  const json = await request("POST", "/api/lark-bot/provision", { ...args });
54393
54538
  return { provisionId: String(json.provisionId), qrUrl: String(json.qrUrl) };
54394
54539
  },
54540
+ async provisionUpgrade(args) {
54541
+ const json = await request("POST", "/api/lark-bot/upgrade", { ...args });
54542
+ return { provisionId: String(json.provisionId), qrUrl: String(json.qrUrl) };
54543
+ },
54395
54544
  async provisionStatus(provisionId) {
54396
54545
  const json = await request("GET", `/api/lark-bot/provision/${encodeURIComponent(provisionId)}`);
54397
54546
  if (json.state === "success") {
@@ -62521,6 +62670,7 @@ var METHOD_GRANT_MAP = {
62521
62670
  "larkBot:bindManual": ADMIN_ANY,
62522
62671
  "larkBot:unbind": ADMIN_ANY,
62523
62672
  "larkBot:status": ADMIN_ANY,
62673
+ "larkBot:upgrade": ADMIN_ANY,
62524
62674
  // ---- onboarding:* / tools:probe / session:externalScan(首启 wizard,owner-only)----
62525
62675
  "onboarding:complete": ADMIN_ANY,
62526
62676
  "onboarding:iosInterest": ADMIN_ANY,
@@ -62657,7 +62807,7 @@ function computeMethodAccess(args) {
62657
62807
  }
62658
62808
 
62659
62809
  // src/version.ts
62660
- var version = "0.2.437".length > 0 ? "0.2.437" : "dev";
62810
+ var version = "0.2.438".length > 0 ? "0.2.438" : "dev";
62661
62811
 
62662
62812
  // src/cli-probe/probe.ts
62663
62813
  var fs65 = __toESM(require("fs"), 1);
@@ -22118,6 +22118,7 @@ var GithubPrRequestReviewersArgs = external_exports.object({
22118
22118
  // ../protocol/src/lark-bot-schemas.ts
22119
22119
  var LarkBotPersonaArgs = external_exports.object({ personaId: external_exports.string().min(1) });
22120
22120
  var LarkBotUnbindArgs = LarkBotPersonaArgs;
22121
+ var LarkBotUpgradeArgs = external_exports.object({ personaId: external_exports.string().min(1) });
22121
22122
  var LarkBotStatusArgs = LarkBotPersonaArgs;
22122
22123
  var LarkBotProvisionArgs = LarkBotPersonaArgs;
22123
22124
  var LarkBotProvisionCancelArgs = LarkBotPersonaArgs;
@@ -22151,7 +22152,21 @@ var LarkBotStatusResultSchema = external_exports.object({
22151
22152
  qrUrl: external_exports.string().optional(),
22152
22153
  /** provision 失败后的 unbound 帧携带;正常 unbound 无此字段 */
22153
22154
  errorReason: LarkBotProvisionErrorReasonSchema.optional(),
22154
- groups: external_exports.array(LarkBotGroupSchema)
22155
+ groups: external_exports.array(LarkBotGroupSchema),
22156
+ /**
22157
+ * bound 态:该 bot 实际授予的 scope 缺了 LARK_PROVISION_ADDONS 里声明的项
22158
+ * (spec 2026-09-01)——addons 是扫码时一次性写进飞书应用配置的,后来新增的
22159
+ * scope / 事件对存量 bot 不生效,不提示的话用户只会觉得「功能没生效」。
22160
+ * 判定真源是飞书回读的 granted scopes,不落库任何版本号。
22161
+ */
22162
+ needsUpgrade: external_exports.boolean().optional(),
22163
+ /**
22164
+ * bound 态叠加:正在扫码更新授权(spec 2026-09-01)。
22165
+ * **不复用 provisioning 态**——升级期间 bot 仍在正常服务(长连接不断、群照常响应),
22166
+ * 降级成 provisioning 会丢掉 botName / groups,UI 上像是断了。
22167
+ * 有值即渲染二维码弹层;升级结束(成功或取消)该字段消失。
22168
+ */
22169
+ upgradeQrUrl: external_exports.string().optional()
22155
22170
  });
22156
22171
  var LarkBotStateFrameSchema = LarkBotStatusResultSchema.extend({
22157
22172
  personaId: external_exports.string().min(1)
@@ -23772,6 +23787,10 @@ var METHOD_DOCS = {
23772
23787
  summary: "\u89E3\u7ED1 persona \u7684\u98DE\u4E66 bot\uFF08\u5220\u4E91\u7AEF\u7ED1\u5B9A + \u65AD\u957F\u8FDE\u63A5\uFF0C\u98DE\u4E66\u4FA7 app \u4FDD\u7559\uFF09\uFF1Bowner-only",
23773
23788
  args: LarkBotUnbindArgs
23774
23789
  },
23790
+ "larkBot:upgrade": {
23791
+ summary: "\u626B\u7801\u66F4\u65B0\u5DF2\u7ED1\u5B9A bot \u7684\u6388\u6743\uFF08\u8865\u540E\u6765\u65B0\u589E\u7684 scope / \u4E8B\u4EF6\uFF09\uFF1B\u5168\u7A0B\u4FDD\u6301 bound\uFF0Cbot \u4E0D\u65AD\u8FDE\uFF1Bowner-only",
23792
+ args: LarkBotUpgradeArgs
23793
+ },
23775
23794
  "larkBot:status": {
23776
23795
  summary: "\u67E5 persona \u7684\u98DE\u4E66 bot \u72B6\u6001\uFF08unbound/bound/broken + \u670D\u52A1\u4E2D\u7FA4\u6E05\u5355\uFF09\uFF1Bowner-only",
23777
23796
  args: LarkBotStatusArgs