oasis_test_v2 2.2.107 → 2.2.109

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.
Files changed (2) hide show
  1. package/dist/index.js +382 -11
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -206747,6 +206747,35 @@ var init_host_isolation = __esm({
206747
206747
  });
206748
206748
 
206749
206749
  // ../connectors/src/feishu/index.ts
206750
+ async function fetchFeishuTenantAccessToken(appId, appSecret) {
206751
+ try {
206752
+ const resp = await fetch(FEISHU_TENANT_TOKEN_URL, {
206753
+ method: "POST",
206754
+ headers: { "Content-Type": "application/json; charset=utf-8" },
206755
+ body: JSON.stringify({ app_id: appId, app_secret: appSecret }),
206756
+ signal: AbortSignal.timeout(TENANT_TOKEN_TIMEOUT_MS)
206757
+ });
206758
+ const data = await resp.json();
206759
+ if (!resp.ok || data.code !== 0 || typeof data.tenant_access_token !== "string" || !data.tenant_access_token) {
206760
+ log("[feishu]", `\u6362\u4F01\u4E1A token \u5931\u8D25\uFF08\u672C\u8F6E bot \u8EAB\u4EFD\u4E0D\u53EF\u7528\uFF09: HTTP ${resp.status} code=${String(data.code)} ${String(data.msg ?? "")}`.trim());
206761
+ return null;
206762
+ }
206763
+ return data.tenant_access_token;
206764
+ } catch (err) {
206765
+ log("[feishu]", `\u6362\u4F01\u4E1A token \u5931\u8D25\uFF08\u672C\u8F6E bot \u8EAB\u4EFD\u4E0D\u53EF\u7528\uFF09: ${String(err?.message ?? err).slice(0, 200)}`);
206766
+ return null;
206767
+ }
206768
+ }
206769
+ function previousTenantToken(credsFile, appId) {
206770
+ if (!credsFile) return null;
206771
+ try {
206772
+ const prev = readSessionCredsFile(credsFile);
206773
+ if (prev["LARKSUITE_CLI_APP_ID"] !== appId) return null;
206774
+ return prev["LARKSUITE_CLI_TENANT_ACCESS_TOKEN"] || null;
206775
+ } catch {
206776
+ return null;
206777
+ }
206778
+ }
206750
206779
  function parseFeishuTokenResponse(data, nowMs) {
206751
206780
  const accessToken = String(data["access_token"] ?? "");
206752
206781
  const refreshToken = String(data["refresh_token"] ?? "");
@@ -206765,7 +206794,7 @@ function parseFeishuTokenResponse(data, nowMs) {
206765
206794
  expiresAt: new Date(expiresAtMs)
206766
206795
  };
206767
206796
  }
206768
- var import_node_child_process14, import_node_util4, import_node_path16, import_node_url3, import_promises9, execFileAsync2, __dirname2, FEISHU_WELL_KNOWN_SKILLS_BASE, FEISHU_TOKEN_URL, FeishuConnector;
206797
+ var import_node_child_process14, import_node_util4, import_node_path16, import_node_url3, import_promises9, execFileAsync2, __dirname2, FEISHU_WELL_KNOWN_SKILLS_BASE, FEISHU_TOKEN_URL, FEISHU_TENANT_TOKEN_URL, TENANT_TOKEN_TIMEOUT_MS, FeishuConnector;
206769
206798
  var init_feishu = __esm({
206770
206799
  "../connectors/src/feishu/index.ts"() {
206771
206800
  "use strict";
@@ -206775,10 +206804,13 @@ var init_feishu = __esm({
206775
206804
  import_node_url3 = require("node:url");
206776
206805
  import_promises9 = require("node:fs/promises");
206777
206806
  init_base();
206807
+ init_logger();
206778
206808
  execFileAsync2 = (0, import_node_util4.promisify)(import_node_child_process14.execFile);
206779
206809
  __dirname2 = (0, import_node_path16.dirname)((0, import_node_url3.fileURLToPath)(__esm_import_meta_url));
206780
206810
  FEISHU_WELL_KNOWN_SKILLS_BASE = "https://open.feishu.cn/.well-known/skills";
206781
206811
  FEISHU_TOKEN_URL = "https://open.feishu.cn/open-apis/authen/v2/oauth/token";
206812
+ FEISHU_TENANT_TOKEN_URL = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal";
206813
+ TENANT_TOKEN_TIMEOUT_MS = 5e3;
206782
206814
  FeishuConnector = class extends CliConnector {
206783
206815
  config = {
206784
206816
  slug: "feishu",
@@ -206876,9 +206908,12 @@ var init_feishu = __esm({
206876
206908
  /** 厂商技能包源——平台自动拉取飞书官方技能包时用。 */
206877
206909
  wellKnownSkillsBase = FEISHU_WELL_KNOWN_SKILLS_BASE;
206878
206910
  larkBin;
206879
- constructor(larkBin) {
206911
+ fetchTenantToken;
206912
+ /** `fetchTenantToken` 只给测试替换(不打真飞书);生产一律用 {@link fetchFeishuTenantAccessToken}。 */
206913
+ constructor(larkBin, opts = {}) {
206880
206914
  super(__dirname2);
206881
206915
  this.larkBin = larkBin ?? this.resolveLarkBin();
206916
+ this.fetchTenantToken = opts.fetchTenantToken ?? fetchFeishuTenantAccessToken;
206882
206917
  }
206883
206918
  /**
206884
206919
  * 解析 user_info 的 JSON。lark-cli 的 `ok:false` 也是**退出码 0** 的正常输出,
@@ -206909,6 +206944,7 @@ var init_feishu = __esm({
206909
206944
  /**
206910
206945
  * Agent run 开始:把凭据作为 lark-cli「外部凭据」写进凭据文件(不进 agent env)。
206911
206946
  * credentials 接受:app_id, app_secret, user_access_token?(及其 FEISHU_* 别名)。
206947
+ * 企业 token 不随 job 下发,由这里用 app_id/app_secret 现换(换不到只是本轮没有 bot 身份,不抛)。
206912
206948
  *
206913
206949
  * 注入的 sessionEnv 键(全部非敏感):
206914
206950
  * FEISHU_CREDS_FILE — 凭据文件路径,wrapper source 它
@@ -206921,9 +206957,11 @@ var init_feishu = __esm({
206921
206957
  if (!appId) throw new Error("feishu inject: missing app_id");
206922
206958
  if (!appSecret) throw new Error("feishu inject: missing app_secret");
206923
206959
  const userAccessToken = credentials2["user_access_token"] ?? credentials2["FEISHU_USER_ACCESS_TOKEN"];
206960
+ const tenantAccessToken = this.isSimulated() ? null : await this.fetchTenantToken(appId, appSecret) ?? previousTenantToken(sessionEnv.get("FEISHU_CREDS_FILE"), appId);
206924
206961
  const creds = await writeSessionCredsFile(this.config.slug, {
206925
206962
  LARKSUITE_CLI_APP_ID: appId,
206926
206963
  LARKSUITE_CLI_APP_SECRET: appSecret,
206964
+ ...tenantAccessToken ? { LARKSUITE_CLI_TENANT_ACCESS_TOKEN: tenantAccessToken } : {},
206927
206965
  ...userAccessToken ? { LARKSUITE_CLI_USER_ACCESS_TOKEN: userAccessToken } : {}
206928
206966
  }, sessionEnv.get("FEISHU_RUN_TMPDIR"));
206929
206967
  const configDir = (0, import_node_path16.join)(creds.dir, "lark-config");
@@ -206993,7 +207031,65 @@ var init_feishu = __esm({
206993
207031
  });
206994
207032
 
206995
207033
  // ../connectors/src/feishu/scopes.ts
206996
- var FEISHU_BASIC_SCOPES, FEISHU_USER_SCOPES, FEISHU_USER_SCOPE_STRING;
207034
+ function scopesForDomains(domains) {
207035
+ const set = /* @__PURE__ */ new Set(["offline_access"]);
207036
+ for (const d of domains) {
207037
+ const g2 = FEISHU_DOMAIN_SCOPES[d];
207038
+ if (g2) for (const s2 of g2.scopes) set.add(s2);
207039
+ }
207040
+ return [...set];
207041
+ }
207042
+ function feishuModuleNeedsApproval(module2) {
207043
+ const g2 = FEISHU_DOMAIN_SCOPES[module2];
207044
+ return !!g2 && g2.scopes.some((s2) => !AUTO_APPROVED.has(s2));
207045
+ }
207046
+ function normalizeFeishuAuthSelection(body2) {
207047
+ const all2 = Object.keys(FEISHU_DOMAIN_SCOPES);
207048
+ let raw = body2.modules;
207049
+ if (raw === void 0) {
207050
+ if (body2.scopeLevel === "full") raw = all2;
207051
+ else if (body2.scopeLevel === "basic") raw = all2.filter((m2) => !feishuModuleNeedsApproval(m2));
207052
+ else raw = body2.domains;
207053
+ }
207054
+ const picked = new Set(Array.isArray(raw) ? raw.filter((m2) => typeof m2 === "string") : []);
207055
+ const modules = all2.filter((m2) => picked.has(m2));
207056
+ if (modules.length === 0) return null;
207057
+ return { modules, sendAsUser: body2.sendAsUser === true };
207058
+ }
207059
+ function scopesForSelection(sel, includeSendAsUser) {
207060
+ const scopes = scopesForDomains(sel.modules);
207061
+ if (includeSendAsUser) scopes.push(FEISHU_SEND_AS_USER_SCOPE);
207062
+ return scopes;
207063
+ }
207064
+ async function appHasScope(appId, appSecret, scope2, fetchImpl = fetch) {
207065
+ const tokenResp = await fetchImpl("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
207066
+ method: "POST",
207067
+ headers: { "Content-Type": "application/json; charset=utf-8" },
207068
+ body: JSON.stringify({ app_id: appId, app_secret: appSecret })
207069
+ });
207070
+ const tokenBody = await tokenResp.json();
207071
+ if (tokenBody.code !== 0 || !tokenBody.tenant_access_token) {
207072
+ throw new Error(`tenant_access_token failed: code=${tokenBody.code} msg=${tokenBody.msg ?? ""}`);
207073
+ }
207074
+ const resp = await fetchImpl("https://open.feishu.cn/open-apis/application/v6/scopes", {
207075
+ headers: { authorization: `Bearer ${tokenBody.tenant_access_token}` }
207076
+ });
207077
+ const body2 = await resp.json();
207078
+ if (body2.code !== 0) throw new Error(`application/v6/scopes failed: code=${body2.code} msg=${body2.msg ?? ""}`);
207079
+ return (body2.data?.scopes ?? []).some(
207080
+ (s2) => s2.scope_name === scope2 && (!s2.scope_type || s2.scope_type === "user")
207081
+ );
207082
+ }
207083
+ function feishuAuthSelectionRecord(sel, sendAsUserRequested, tokenResponse) {
207084
+ const granted = typeof tokenResponse["scope"] === "string" ? tokenResponse["scope"].split(/\s+/).filter(Boolean) : void 0;
207085
+ return {
207086
+ modules: sel.modules,
207087
+ sendAsUser: sel.sendAsUser,
207088
+ sendAsUserRequested,
207089
+ ...granted ? { grantedScopes: granted } : {}
207090
+ };
207091
+ }
207092
+ var FEISHU_BASIC_SCOPES, FEISHU_DOMAIN_SCOPES, FEISHU_USER_SCOPES, FEISHU_USER_SCOPE_STRING, FEISHU_SEND_AS_USER_SCOPE, FEISHU_AUTH_SELECTION_VAR, AUTO_APPROVED;
206997
207093
  var init_scopes = __esm({
206998
207094
  "../connectors/src/feishu/scopes.ts"() {
206999
207095
  "use strict";
@@ -207136,6 +207232,231 @@ var init_scopes = __esm({
207136
207232
  "offline_access"
207137
207233
  // refresh_token(--recommend 不含,但 token 刷新必须)
207138
207234
  ];
207235
+ FEISHU_DOMAIN_SCOPES = {
207236
+ im: {
207237
+ label: "\u5373\u65F6\u6D88\u606F\uFF08\u53D1\u6D88\u606F\u3001\u7FA4\u804A\u3001\u53CD\u5E94\uFF09",
207238
+ scopes: [
207239
+ "im:chat.members:read",
207240
+ "im:chat.members:write_only",
207241
+ "im:chat:read",
207242
+ "im:chat:update",
207243
+ "im:feed.flag:read",
207244
+ "im:feed.flag:write",
207245
+ "im:message",
207246
+ "im:message.group_msg:get_as_user",
207247
+ "im:message.p2p_msg:get_as_user",
207248
+ "im:message.pins:read",
207249
+ "im:message.pins:write_only",
207250
+ "im:message.reactions:read",
207251
+ "im:message.reactions:write_only",
207252
+ "im:message:readonly"
207253
+ ]
207254
+ },
207255
+ calendar: {
207256
+ label: "\u65E5\u5386\uFF08\u65E5\u7A0B\u8BFB\u5199\uFF09",
207257
+ scopes: [
207258
+ "calendar:calendar:read",
207259
+ "calendar:calendar:create",
207260
+ "calendar:calendar:update",
207261
+ "calendar:calendar:delete",
207262
+ "calendar:calendar.event:read",
207263
+ "calendar:calendar.event:create",
207264
+ "calendar:calendar.event:update",
207265
+ "calendar:calendar.event:delete",
207266
+ "calendar:calendar.free_busy:read"
207267
+ ]
207268
+ },
207269
+ docs: {
207270
+ label: "\u4E91\u6587\u6863\uFF08\u6587\u6863\u3001\u6743\u9650\u3001\u8BC4\u8BBA\uFF09",
207271
+ scopes: [
207272
+ "docs:document.content:read",
207273
+ "docs:document:copy",
207274
+ "docs:document:export",
207275
+ "docs:document:import",
207276
+ "docs:document.comment:read",
207277
+ "docs:document.comment:create",
207278
+ "docs:document.comment:update",
207279
+ "docs:document.comment:delete",
207280
+ "docs:document.comment:write_only",
207281
+ "docs:document.media:download",
207282
+ "docs:document.media:upload",
207283
+ "docs:event:subscribe",
207284
+ "docs:permission.member:apply",
207285
+ "docs:permission.member:auth",
207286
+ "docs:permission.member:create",
207287
+ "docs:permission.member:transfer",
207288
+ "docs:permission.setting:read",
207289
+ "docs:permission.setting:write_only",
207290
+ "docs:secure_label:write_only",
207291
+ "docx:document:create",
207292
+ "docx:document:readonly",
207293
+ "docx:document:write_only",
207294
+ "space:document:delete",
207295
+ "space:document:move",
207296
+ "space:document:shortcut",
207297
+ "space:folder:create"
207298
+ ]
207299
+ },
207300
+ drive: {
207301
+ label: "\u4E91\u76D8\uFF08\u6587\u4EF6\u4E0A\u4F20\u4E0B\u8F7D\uFF09",
207302
+ scopes: [
207303
+ "drive:drive.metadata:readonly",
207304
+ "drive:file:download",
207305
+ "drive:file:upload",
207306
+ "drive:file:view_record:readonly",
207307
+ "drive:quota_detail:read_one"
207308
+ ]
207309
+ },
207310
+ sheets: {
207311
+ label: "\u7535\u5B50\u8868\u683C",
207312
+ scopes: [
207313
+ "sheets:spreadsheet:create",
207314
+ "sheets:spreadsheet:read",
207315
+ "sheets:spreadsheet:write_only",
207316
+ "sheets:spreadsheet.meta:read",
207317
+ "sheets:spreadsheet.meta:write_only"
207318
+ ]
207319
+ },
207320
+ base: {
207321
+ label: "\u591A\u7EF4\u8868\u683C\uFF08Base\uFF09",
207322
+ scopes: [
207323
+ "base:app:copy",
207324
+ "base:app:create",
207325
+ "base:app:read",
207326
+ "base:app:update",
207327
+ "base:dashboard:create",
207328
+ "base:dashboard:delete",
207329
+ "base:dashboard:read",
207330
+ "base:dashboard:update",
207331
+ "base:field:create",
207332
+ "base:field:delete",
207333
+ "base:field:read",
207334
+ "base:field:update",
207335
+ "base:form:create",
207336
+ "base:form:delete",
207337
+ "base:form:read",
207338
+ "base:form:update",
207339
+ "base:history:read",
207340
+ "base:record:create",
207341
+ "base:record:delete",
207342
+ "base:record:read",
207343
+ "base:record:update",
207344
+ "base:role:create",
207345
+ "base:role:delete",
207346
+ "base:role:read",
207347
+ "base:role:update",
207348
+ "base:table:create",
207349
+ "base:table:delete",
207350
+ "base:table:read",
207351
+ "base:table:update",
207352
+ "base:view:read",
207353
+ "base:view:write_only",
207354
+ "base:workflow:create",
207355
+ "base:workflow:read",
207356
+ "base:workflow:update"
207357
+ ]
207358
+ },
207359
+ wiki: {
207360
+ label: "\u77E5\u8BC6\u5E93",
207361
+ scopes: [
207362
+ "wiki:member:create",
207363
+ "wiki:member:retrieve",
207364
+ "wiki:member:update",
207365
+ "wiki:node:copy",
207366
+ "wiki:node:create",
207367
+ "wiki:node:move",
207368
+ "wiki:node:read",
207369
+ "wiki:node:retrieve",
207370
+ "wiki:space:read",
207371
+ "wiki:space:retrieve",
207372
+ "wiki:space:write_only"
207373
+ ]
207374
+ },
207375
+ slides: {
207376
+ label: "\u5E7B\u706F\u7247",
207377
+ scopes: [
207378
+ "slides:presentation:create",
207379
+ "slides:presentation:read",
207380
+ "slides:presentation:update",
207381
+ "slides:presentation:write_only"
207382
+ ]
207383
+ },
207384
+ task: {
207385
+ label: "\u4EFB\u52A1",
207386
+ scopes: [
207387
+ "task:attachment:write",
207388
+ "task:comment:write",
207389
+ "task:custom_field:read",
207390
+ "task:custom_field:write",
207391
+ "task:section:read",
207392
+ "task:section:write",
207393
+ "task:task:read",
207394
+ "task:task:write",
207395
+ "task:tasklist:read",
207396
+ "task:tasklist:write"
207397
+ ]
207398
+ },
207399
+ approval: {
207400
+ label: "\u5BA1\u6279",
207401
+ scopes: [
207402
+ "approval:instance:read",
207403
+ "approval:instance:write",
207404
+ "approval:task:read",
207405
+ "approval:task:write"
207406
+ ]
207407
+ },
207408
+ mail: {
207409
+ label: "\u90AE\u4EF6",
207410
+ scopes: [
207411
+ "mail:user_mailbox:readonly",
207412
+ "mail:user_mailbox.message:modify",
207413
+ "mail:user_mailbox.message.address:read",
207414
+ "mail:user_mailbox.message.body:read",
207415
+ "mail:user_mailbox.message.subject:read",
207416
+ "mail:user_mailbox.message:readonly",
207417
+ "mail:user_mailbox.mail_contact:read",
207418
+ "mail:user_mailbox.mail_contact:write",
207419
+ "mail:event"
207420
+ ]
207421
+ },
207422
+ minutes: {
207423
+ label: "\u5999\u8BB0\uFF08\u4F1A\u8BAE\u5F55\u97F3\uFF09",
207424
+ scopes: ["minutes:minutes.search:read", "minutes:minutes.upload:write"]
207425
+ },
207426
+ vc: {
207427
+ label: "\u89C6\u9891\u4F1A\u8BAE",
207428
+ scopes: [
207429
+ "vc:meeting.meetingevent:read",
207430
+ "vc:meeting.search:read",
207431
+ "vc:note:read",
207432
+ "vc:record:readonly"
207433
+ ]
207434
+ },
207435
+ contact: {
207436
+ label: "\u901A\u8BAF\u5F55",
207437
+ scopes: [
207438
+ "contact:user.base:readonly",
207439
+ "contact:user:search",
207440
+ "contact:user.basic_profile:readonly"
207441
+ ]
207442
+ },
207443
+ okr: {
207444
+ label: "OKR",
207445
+ scopes: ["okr:okr:read"]
207446
+ },
207447
+ attendance: {
207448
+ label: "\u8003\u52E4",
207449
+ scopes: ["attendance:record:read"]
207450
+ },
207451
+ board: {
207452
+ label: "\u767D\u677F",
207453
+ scopes: ["board:whiteboard:node:create", "board:whiteboard:node:read"]
207454
+ },
207455
+ spark: {
207456
+ label: "\u5E94\u7528\uFF08Spark\uFF09",
207457
+ scopes: ["spark:app:read", "spark:app:write"]
207458
+ }
207459
+ };
207139
207460
  FEISHU_USER_SCOPES = [
207140
207461
  // ── 自动审批权限(与 FEISHU_BASIC_SCOPES 完全相同)────────────────────
207141
207462
  ...FEISHU_BASIC_SCOPES,
@@ -207168,6 +207489,9 @@ var init_scopes = __esm({
207168
207489
  "space:document:retrieve"
207169
207490
  ];
207170
207491
  FEISHU_USER_SCOPE_STRING = FEISHU_USER_SCOPES.join(" ");
207492
+ FEISHU_SEND_AS_USER_SCOPE = "im:message.send_as_user";
207493
+ FEISHU_AUTH_SELECTION_VAR = "FEISHU_AUTH_SELECTION";
207494
+ AUTO_APPROVED = new Set(FEISHU_BASIC_SCOPES);
207171
207495
  }
207172
207496
  });
207173
207497
 
@@ -210646,7 +210970,7 @@ async function prepareConnectorsForJob(job, deps) {
210646
210970
  await connector.inject(credentials2, sessionEnv);
210647
210971
  for (const [k2, v2] of sessionEnv) envOverrides[k2] = v2;
210648
210972
  cleanups.push(() => connector.cleanup(sessionEnv));
210649
- injected.set(slug5, { connector, sessionEnv, credsFingerprint: credentialsFingerprint(credentials2) });
210973
+ injected.set(slug5, { connector, sessionEnv, credentials: credentials2, credsFingerprint: credentialsFingerprint(credentials2) });
210650
210974
  status.credsReady = true;
210651
210975
  } catch (err) {
210652
210976
  status.error = String(err);
@@ -210772,7 +211096,12 @@ async function renewInjectedCredentials(injected, fetchCredentials) {
210772
211096
  try {
210773
211097
  fresh = await fetchCredentials();
210774
211098
  } catch (err) {
210775
- for (const slug5 of injected.keys()) outcome.failed.push({ slug: slug5, error: String(err) });
211099
+ for (const [slug5, target] of injected) {
211100
+ outcome.failed.push({ slug: slug5, error: String(err) });
211101
+ await target.connector.inject(target.credentials, target.sessionEnv).catch((reErr) => {
211102
+ log("[node-connectors]", `\u26A0 \u7EED\u671F\uFF1A${slug5} \u6309\u65E7\u51ED\u636E\u91CD\u6CE8\u5931\u8D25: ${String(reErr)}`);
211103
+ });
211104
+ }
210776
211105
  log("[node-connectors]", `\u7EED\u671F\uFF1A\u5411 server \u53D6\u51ED\u636E\u5931\u8D25\uFF0C\u672C\u8F6E\u6CBF\u7528\u65E7\u51ED\u636E: ${String(err)}`);
210777
211106
  return outcome;
210778
211107
  }
@@ -210781,6 +211110,7 @@ async function renewInjectedCredentials(injected, fetchCredentials) {
210781
211110
  if (!target) continue;
210782
211111
  try {
210783
211112
  await target.connector.inject(credentials2, target.sessionEnv);
211113
+ target.credentials = credentials2;
210784
211114
  const fingerprint2 = credentialsFingerprint(credentials2);
210785
211115
  if (fingerprint2 !== target.credsFingerprint) {
210786
211116
  target.credsFingerprint = fingerprint2;
@@ -217139,15 +217469,34 @@ ${composed}`;
217139
217469
  return;
217140
217470
  }
217141
217471
  if (url.pathname === "/api/connectors/feishu/login/start" && req.method === "POST") {
217142
- const { appId, actorId } = JSON.parse(rawBody);
217472
+ const startBody = JSON.parse(rawBody);
217473
+ const { appId, actorId } = startBody;
217143
217474
  if (!appId) {
217144
217475
  res.writeHead(400).end(JSON.stringify({ error: "appId required" }));
217145
217476
  return;
217146
217477
  }
217478
+ const selection = normalizeFeishuAuthSelection(startBody);
217479
+ if (!selection) {
217480
+ res.writeHead(400).end(JSON.stringify({ error: "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u529F\u80FD\u6A21\u5757" }));
217481
+ return;
217482
+ }
217147
217483
  try {
217148
217484
  const startSvc = await connectorActorsService();
217149
217485
  const appSecret = startSvc ? await startSvc.revealResolvedVariable("FEISHU_APP_SECRET", actorId) : null;
217150
217486
  if (!appSecret) throw new Error("FEISHU_APP_SECRET not found \u2014 please complete app setup first");
217487
+ let sendAsUserRequested = false;
217488
+ let notice;
217489
+ if (selection.sendAsUser) {
217490
+ try {
217491
+ sendAsUserRequested = await appHasScope(appId, appSecret, FEISHU_SEND_AS_USER_SCOPE);
217492
+ if (!sendAsUserRequested) {
217493
+ notice = "\u8BE5\u98DE\u4E66\u5E94\u7528\u5C1A\u672A\u5F00\u901A\u300C\u4EE5\u7528\u6237\u8EAB\u4EFD\u53D1\u6D88\u606F\u300D\u6743\u9650\uFF08im:message.send_as_user\uFF09\uFF0C\u672C\u6B21\u6388\u6743\u5DF2\u8DF3\u8FC7\u8FD9\u4E00\u9879\uFF0C\u5176\u4F59\u6743\u9650\u7167\u5E38\u7533\u8BF7\u3002\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u5E94\u7528\u5F00\u901A\u540E\u91CD\u65B0\u8FDE\u63A5\u5373\u53EF\u3002";
217494
+ }
217495
+ } catch (e) {
217496
+ console.error(`[feishu-oauth] app scopes check failed: ${String(e)}`);
217497
+ notice = "\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u8BE5\u98DE\u4E66\u5E94\u7528\u662F\u5426\u5F00\u901A\u4E86\u300C\u4EE5\u7528\u6237\u8EAB\u4EFD\u53D1\u6D88\u606F\u300D\u6743\u9650\uFF0C\u672C\u6B21\u6388\u6743\u5DF2\u8DF3\u8FC7\u8FD9\u4E00\u9879\uFF0C\u5176\u4F59\u6743\u9650\u7167\u5E38\u7533\u8BF7\u3002\u7A0D\u540E\u53EF\u91CD\u65B0\u8FDE\u63A5\u518D\u8BD5\u3002";
217498
+ }
217499
+ }
217151
217500
  const basicAuth = Buffer.from(`${appId}:${appSecret}`).toString("base64");
217152
217501
  const resp = await fetch("https://accounts.feishu.cn/oauth/v1/device_authorization", {
217153
217502
  method: "POST",
@@ -217155,7 +217504,10 @@ ${composed}`;
217155
217504
  "Content-Type": "application/x-www-form-urlencoded",
217156
217505
  "Authorization": `Basic ${basicAuth}`
217157
217506
  },
217158
- body: new URLSearchParams({ client_id: appId, scope: FEISHU_USER_SCOPE_STRING }).toString()
217507
+ body: new URLSearchParams({
217508
+ client_id: appId,
217509
+ scope: scopesForSelection(selection, sendAsUserRequested).join(" ")
217510
+ }).toString()
217159
217511
  });
217160
217512
  const data = await resp.json();
217161
217513
  if (!resp.ok || data["error"]) {
@@ -217163,14 +217515,22 @@ ${composed}`;
217163
217515
  }
217164
217516
  const verificationUrl = String(data["verification_uri_complete"] ?? data["verification_uri"] ?? "");
217165
217517
  if (!verificationUrl) throw new Error("no verification_uri in response");
217166
- res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ verificationUrl, deviceCode: data["device_code"] }));
217518
+ res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({
217519
+ verificationUrl,
217520
+ deviceCode: data["device_code"],
217521
+ modules: selection.modules,
217522
+ sendAsUser: selection.sendAsUser,
217523
+ sendAsUserRequested,
217524
+ ...notice ? { notice } : {}
217525
+ }));
217167
217526
  } catch (e) {
217168
217527
  res.writeHead(500).end(JSON.stringify({ error: String(e) }));
217169
217528
  }
217170
217529
  return;
217171
217530
  }
217172
217531
  if (url.pathname === "/api/connectors/feishu/login/poll" && req.method === "POST") {
217173
- const { appId, deviceCode, actorId } = JSON.parse(rawBody);
217532
+ const pollBody = JSON.parse(rawBody);
217533
+ const { appId, deviceCode, actorId } = pollBody;
217174
217534
  if (!appId || !deviceCode) {
217175
217535
  res.writeHead(400).end(JSON.stringify({ error: "appId and deviceCode required" }));
217176
217536
  return;
@@ -217210,6 +217570,17 @@ ${composed}`;
217210
217570
  }
217211
217571
  await persistFeishuUserTokens(svc, actorId, data, Date.now());
217212
217572
  const nameScope = actorId ? { scope: "personal", actorId } : { scope: "global" };
217573
+ const pollSelection = pollBody.modules === void 0 ? null : normalizeFeishuAuthSelection(pollBody);
217574
+ if (pollSelection) {
217575
+ const record10 = feishuAuthSelectionRecord(pollSelection, pollBody.sendAsUserRequested === true, data);
217576
+ await svc.putVariable({
217577
+ key: FEISHU_AUTH_SELECTION_VAR,
217578
+ value: JSON.stringify(record10),
217579
+ ...nameScope,
217580
+ connectorId: "feishu",
217581
+ encrypted: false
217582
+ });
217583
+ }
217213
217584
  try {
217214
217585
  const uiResp = await fetch("https://open.feishu.cn/open-apis/authen/v1/user_info", {
217215
217586
  headers: { authorization: `Bearer ${String(data["access_token"])}` }
@@ -299347,7 +299718,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
299347
299718
  }
299348
299719
  }
299349
299720
  }
299350
- var CLI_VERSION = "2.2.107" ? "2.2.107" : "dev";
299721
+ var CLI_VERSION = "2.2.109" ? "2.2.109" : "dev";
299351
299722
  function apiHeaders(token2, company) {
299352
299723
  const headers = {
299353
299724
  authorization: `Bearer ${token2}`,
@@ -303518,7 +303889,7 @@ function shimScript() {
303518
303889
  }
303519
303890
 
303520
303891
  // src/index.ts
303521
- var PKG_VERSION = true ? "2.2.107" : "dev";
303892
+ var PKG_VERSION = true ? "2.2.109" : "dev";
303522
303893
  var LOCAL_BIN = localBin();
303523
303894
  var NPM_PREFIX = npmPrefix();
303524
303895
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.107",
3
+ "version": "2.2.109",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "180e4e814716f1a7eb4870a1f88cd4d10398d726"
29
+ "sourceHead": "ed886e183f5c2444ee63e480a04b46976ddcf303"
30
30
  }
31
31
  }