oasis_test_v2 2.2.112 → 2.2.113

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.
@@ -11,13 +11,15 @@
11
11
  # LARK_BIN — 真实 lark-cli 绝对路径(避免递归调用自身)
12
12
  # FEISHU_CREDS_FILE — 凭据文件路径(内含 export LARKSUITE_CLI_* 行)
13
13
  #
14
- # 按 Agent 限制可用模块(产品反馈「飞书连接器·按 Agent 的权限模型」):凭据文件里有
15
- # OASIS_FEISHU_ALLOW 时,只放行所选模块的 `lark-cli <domain>` 与 `lark-cli api <METHOD> /open-apis/<service>/…`,
16
- # 机器人与用户身份一样拦(bot 的企业 token 能调应用开通的全集,飞书侧分不开)。放行表由 inject() 按
17
- # FEISHU_AUTH_SELECTION 算好写入(feishuModulePolicyEnv),这里不认识任何模块,只查表。
14
+ # 按 Agent 限制可用模块(产品反馈「飞书连接器·按 Agent 的权限模型」):只放行所选模块的
15
+ # `lark-cli <domain> …` 与 `lark-cli api <METHOD> /open-apis/<service>/…`,机器人与用户身份一样拦
16
+ # (bot 的企业 token 能调应用开通的全集,飞书侧分不开)。放行表由 inject() 按 FEISHU_AUTH_SELECTION
17
+ # 算好写入凭据文件(feishuModulePolicyEnv),这里不认识任何模块,只按规则表(OASIS_FEISHU_RULES)查。
18
+ # 共用的 drive 命令/接口按子命令、路径细分。**没有放行表、没有有效选择都按一个模块都没开放拦**,不会退成不限制。
18
19
  # 被拦时照 lark-cli 的错误形状往 stderr 打一段 JSON、退出码 3(与 lark-cli 自己的鉴权失败同码)。
19
20
 
20
21
  set -euo pipefail
22
+ shopt -s extglob # 放行规则用 +([!/]) / ?(/*) 表示「一段」「零到多段」
21
23
 
22
24
  OASIS_BIN_VAR="LARK_BIN"
23
25
  OASIS_CMD_NAME="lark-cli"
@@ -28,7 +30,7 @@ oasis_resolve_bin
28
30
  oasis_check_available
29
31
 
30
32
  # 放行表只认凭据文件里的:先清掉 agent 环境里可能带进来的同名变量。
31
- unset OASIS_FEISHU_ALLOW OASIS_FEISHU_NEED OASIS_FEISHU_MODULES
33
+ unset OASIS_FEISHU_POLICY OASIS_FEISHU_ALLOW OASIS_FEISHU_RULES OASIS_FEISHU_LABELS OASIS_FEISHU_MODULES
32
34
 
33
35
  # Load feishu credentials into THIS process only (not visible to the agent).
34
36
  if [ -n "${FEISHU_CREDS_FILE:-}" ] && [ -f "${FEISHU_CREDS_FILE}" ]; then
@@ -41,34 +43,82 @@ FEISHU_NEUTRAL_COMMANDS=" help schema skills whoami doctor completion auth confi
41
43
  # 任何模块都放行的接口 service;与 scopes.ts FEISHU_NEUTRAL_API_SERVICES 同一份。
42
44
  FEISHU_NEUTRAL_API=" authen auth "
43
45
 
46
+ feishu_reply_blocked() {
47
+ printf '{\n "ok": false,\n "error": {\n "type": "oasis_module_blocked",\n "message": "%s",\n "hint": "%s"\n }\n}\n' "$1" "$2" >&2
48
+ exit 3
49
+ }
50
+
44
51
  feishu_blocked() {
45
- # $1 = 放行表里的键(cmd:<domain> / api:<service>);$2 = 给人看的命令写法(已过滤成安全字符)。
46
- local key="$1" shown="$2" need="" message hint
47
- local entry
48
- for entry in ${OASIS_FEISHU_NEED:-}; do
49
- if [ "${entry%%=*}" = "$key" ]; then need="${entry#*=}"; break; fi
50
- done
51
- if [ -n "$need" ]; then
52
- message="本 agent 的飞书连接器没有开放「${need}」模块,${shown} 已被 Oasis 拦下(机器人与用户身份都不可用)。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。"
53
- hint="如需使用,请让配置人在 Oasis 里这个 agent 的飞书连接器详情点「重新连接」,勾选「${need}」后完成授权。"
54
- else
55
- message="${shown} 不属于任何可勾选的飞书功能模块;本 agent 的飞书调用已按模块限制,Oasis 不放行它。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。"
56
- hint="请改用已开放模块对应的 lark-cli 命令;确需此能力请联系 Oasis 管理员。"
52
+ # $1 = 规则要求的模块(逗号分隔,空 = 不属于任何模块);$2 = 给人看的命令写法(已过滤成安全字符)。
53
+ local mods="$1" shown="$2" need="" m entry label
54
+ local reconnect="请让配置人在 Oasis 里这个 agent 的飞书连接器详情点「重新连接」"
55
+ case "${OASIS_FEISHU_POLICY:-}" in
56
+ ok) ;;
57
+ none)
58
+ feishu_reply_blocked "本 agent 的飞书连接器还没有保存过可用模块的选择,Oasis 按「一个模块都没开放」处理,${shown} 已被拦下(机器人与用户身份都不可用)。" \
59
+ "${reconnect},勾选需要的模块后完成授权。" ;;
60
+ invalid)
61
+ feishu_reply_blocked "本 agent 的飞书连接器保存的模块选择无法识别,Oasis 按「一个模块都没开放」处理,${shown} 已被拦下(机器人与用户身份都不可用)。" \
62
+ "${reconnect},重新勾选模块后完成授权。" ;;
63
+ *)
64
+ feishu_reply_blocked "本次运行没有拿到飞书模块放行表,Oasis 不放行 ${shown}(机器人与用户身份都不可用)。" \
65
+ "请重新发起任务;仍出现请联系 Oasis 管理员检查飞书连接器。" ;;
66
+ esac
67
+ if [ -n "$mods" ]; then
68
+ for m in ${mods//,/ }; do
69
+ label="$m"
70
+ for entry in ${OASIS_FEISHU_LABELS:-}; do
71
+ if [ "${entry%%=*}" = "$m" ]; then label="${entry#*=}"; break; fi
72
+ done
73
+ need="${need:+${need}」或「}${label}"
74
+ done
75
+ feishu_reply_blocked "本 agent 的飞书连接器没有开放「${need}」模块,${shown} 已被 Oasis 拦下(机器人与用户身份都不可用)。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。" \
76
+ "如需使用,${reconnect},勾选「${need}」后完成授权。"
57
77
  fi
58
- printf '{\n "ok": false,\n "error": {\n "type": "oasis_module_blocked",\n "message": "%s",\n "hint": "%s"\n }\n}\n' "$message" "$hint" >&2
59
- exit 3
78
+ feishu_reply_blocked "${shown} 不属于任何可勾选的飞书功能模块;本 agent 的飞书调用已按模块限制,Oasis 不放行它。当前开放的模块:${OASIS_FEISHU_MODULES:-无}。" \
79
+ "请改用已开放模块对应的 lark-cli 命令;共用的 drive 子命令须紧跟在 drive 之后写。确需此能力请联系 Oasis 管理员。"
60
80
  }
61
81
 
62
82
  # 只把「看起来像命令名 / service 名」的字符串回显出来,其余一律写成占位——它要进 JSON。
63
83
  feishu_safe() {
64
84
  case "$1" in
65
- ''|*[!A-Za-z0-9_.-]*) printf '%s' "该命令" ;;
85
+ ''|*[!A-Za-z0-9_.+-]*) printf '%s' "该命令" ;;
86
+ *) printf '%s' "$1" ;;
87
+ esac
88
+ }
89
+
90
+ # 按规则表判 $1(cmd/<domain>/… 或 api/<METHOD>/<service>/…):命中且所需模块里有一个已放行 → 放行;
91
+ # 命中但都没放行 → 拦并说缺哪个;一条都没命中 → 拦(不属于任何模块)。
92
+ feishu_check_key() {
93
+ local key="$1" shown="$2" entry pat mods m
94
+ set -f
95
+ for entry in ${OASIS_FEISHU_RULES:-}; do
96
+ pat="${entry%=*}"; mods="${entry##*=}"
97
+ # shellcheck disable=SC2254
98
+ case "$key" in
99
+ $pat)
100
+ set +f
101
+ if [ "${OASIS_FEISHU_POLICY:-}" = "ok" ]; then
102
+ for m in ${mods//,/ }; do
103
+ case "${OASIS_FEISHU_ALLOW:-}" in *" $m "*) return 0 ;; esac
104
+ done
105
+ fi
106
+ feishu_blocked "$mods" "$shown" ;;
107
+ esac
108
+ done
109
+ set +f
110
+ feishu_blocked "" "$shown"
111
+ }
112
+
113
+ # 命令行里的一个词能不能原样进规则 key:只允许命令名字符,其余写成 ?(不会命中任何规则)。
114
+ feishu_seg() {
115
+ case "$1" in
116
+ ''|*[!A-Za-z0-9_.+-]*) printf '?' ;;
66
117
  *) printf '%s' "$1" ;;
67
118
  esac
68
119
  }
69
120
 
70
121
  feishu_enforce_modules() {
71
- [ -n "${OASIS_FEISHU_ALLOW:-}" ] || return 0 # 没保存过模块选择:不限制
72
122
  local args=("$@") i=0 n=$# cmd=""
73
123
  # 跳过命令前的全局参数(--profile X、-h/--help、-v/--version)。
74
124
  while [ "$i" -lt "$n" ]; do
@@ -82,8 +132,8 @@ feishu_enforce_modules() {
82
132
  case "$FEISHU_NEUTRAL_COMMANDS" in *" $cmd "*) return 0 ;; esac
83
133
 
84
134
  if [ "$cmd" = "api" ]; then
85
- # lark-cli api <METHOD> <path> [flags]:取 api 之后第二个位置参数为 path(跳过带值的参数)。
86
- local pos=0 path="" a
135
+ # lark-cli api <METHOD> <path> [flags]:api 之后第一、二个位置参数为 method、path(跳过带值的参数)。
136
+ local pos=0 method="" path="" a
87
137
  i=$((i + 1))
88
138
  while [ "$i" -lt "$n" ]; do
89
139
  a="${args[$i]}"
@@ -92,27 +142,49 @@ feishu_enforce_modules() {
92
142
  -*) i=$((i + 1)); continue ;;
93
143
  esac
94
144
  pos=$((pos + 1))
145
+ if [ "$pos" -eq 1 ]; then method="$a"; fi
95
146
  if [ "$pos" -eq 2 ]; then path="$a"; break; fi
96
147
  i=$((i + 1))
97
148
  done
98
149
  [ -n "$path" ] || return 0 # 没给 path:lark-cli 自己报用法错,不会发请求
99
- # 归一成 <service>/…:lark-cli 接受完整 URL、/open-apis/ 前缀可省、前导斜杠可省。
150
+ # 归一成 <service>/…:lark-cli 接受完整 URL、/open-apis/ 前缀可省、前导斜杠可省;连续斜杠并成一个。
100
151
  local p="$path"
101
152
  p="${p#http://}"; p="${p#https://}"
102
153
  case "$path" in http://*|https://*) p="${p#*/}" ;; esac
103
154
  while [ "${p#/}" != "$p" ]; do p="${p#/}"; done
104
155
  p="${p#open-apis/}"
105
156
  while [ "${p#/}" != "$p" ]; do p="${p#/}"; done
106
- # 路径里带 .. 或百分号编码的,不去猜它最后落到哪个 service——直接拒。
107
- case "$p" in *..*|*%*|*\\*) feishu_blocked "api:?" "lark-cli api(路径含 .. 或编码字符)" ;; esac
108
- local svc="${p%%[/?#]*}"
157
+ p="${p%%[?#]*}"
158
+ while [ "${p//\/\//\/}" != "$p" ]; do p="${p//\/\//\/}"; done
159
+ # 路径里带 ..、. 段或百分号编码的,不去猜它最后落到哪个接口——直接拒。
160
+ case "/$p/" in *..*|*%*|*\\*|*/./*) feishu_blocked "" "lark-cli api(路径含 .. 或编码字符)" ;; esac
161
+ local svc="${p%%/*}"
109
162
  case "$FEISHU_NEUTRAL_API" in *" $svc "*) return 0 ;; esac
110
- case "$OASIS_FEISHU_ALLOW" in *" api:$svc "*) return 0 ;; esac
111
- feishu_blocked "api:$svc" "lark-cli api …/open-apis/$(feishu_safe "$svc")/…"
163
+ case "$p" in *[!A-Za-z0-9_./:-]*) feishu_blocked "" "lark-cli api(路径含非法字符)" ;; esac
164
+ # 方法名转大写(macOS 自带 bash 3.2 没有 ${x^^})。
165
+ method="$(feishu_seg "$method" | tr '[:lower:]' '[:upper:]')"
166
+ feishu_check_key "api/$method/$p" "lark-cli api …/open-apis/$(feishu_safe "$svc")/…"
167
+ return 0
112
168
  fi
113
169
 
114
- case "$OASIS_FEISHU_ALLOW" in *" cmd:$cmd "*) return 0 ;; esac
115
- feishu_blocked "cmd:$cmd" "lark-cli $(feishu_safe "$cmd")"
170
+ # lark-cli <domain> [子命令] [方法]:只取紧跟在 domain 后面的词(drive 这类共用 domain 按子命令分模块);
171
+ # domain 后面先出现参数的,key 里记成「-」,共用 domain 的细分规则一条都不会命中。
172
+ local key="cmd/$(feishu_seg "$cmd")" depth=0 j=$((i + 1)) only_help=1 w
173
+ while [ "$j" -lt "$n" ]; do
174
+ case "${args[$j]}" in -h|--help) ;; *) only_help=0 ;; esac
175
+ j=$((j + 1))
176
+ done
177
+ [ "$only_help" -eq 1 ] && [ $((i + 1)) -lt "$n" ] && return 0 # lark-cli <domain> --help
178
+ j=$((i + 1))
179
+ while [ "$j" -lt "$n" ] && [ "$depth" -lt 2 ]; do
180
+ w="${args[$j]}"
181
+ case "$w" in -*) key="$key/-"; break ;; esac
182
+ key="$key/$(feishu_seg "$w")"
183
+ depth=$((depth + 1)); j=$((j + 1))
184
+ done
185
+ local shown="lark-cli $(feishu_safe "$cmd")"
186
+ [ "$depth" -ge 1 ] && shown="$shown $(feishu_safe "${args[$((i + 1))]}")"
187
+ feishu_check_key "$key" "$shown"
116
188
  }
117
189
 
118
190
  feishu_enforce_modules "$@"
package/dist/index.js CHANGED
@@ -19673,49 +19673,69 @@ function feishuAuthSelectionRecord(sel, sendAsUserRequested, tokenResponse) {
19673
19673
  ...granted ? { grantedScopes: granted } : {}
19674
19674
  };
19675
19675
  }
19676
- function feishuModulePolicyEnv(modules) {
19677
- const picked = modules.filter((m2) => FEISHU_MODULE_ACCESS[m2]);
19678
- if (picked.length === 0) return null;
19679
- const allow = /* @__PURE__ */ new Set();
19680
- for (const m2 of picked) {
19681
- for (const c of FEISHU_MODULE_ACCESS[m2].commands) allow.add(`cmd:${c}`);
19682
- for (const s2 of FEISHU_MODULE_ACCESS[m2].apiServices) allow.add(`api:${s2}`);
19683
- }
19684
- const need2 = /* @__PURE__ */ new Map();
19685
- for (const [m2, a] of Object.entries(FEISHU_MODULE_ACCESS)) {
19686
- for (const k2 of [...a.commands.map((c) => `cmd:${c}`), ...a.apiServices.map((s2) => `api:${s2}`)]) {
19687
- if (allow.has(k2)) continue;
19688
- need2.set(k2, [...need2.get(k2) ?? [], (FEISHU_MODULE_LABELS[m2] ?? m2).replace(/\s+/g, "")]);
19689
- }
19690
- }
19691
- return {
19692
- OASIS_FEISHU_ALLOW: ` ${[...allow].sort().join(" ")} `,
19693
- OASIS_FEISHU_NEED: ` ${[...need2].sort(([a], [b2]) => a.localeCompare(b2)).map(([k2, v2]) => `${k2}=${v2.join("/")}`).join(" ")} `,
19694
- OASIS_FEISHU_MODULES: picked.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001")
19695
- };
19676
+ function feishuModuleRules() {
19677
+ const own3 = Object.entries(FEISHU_MODULE_ACCESS).flatMap(([m2, a]) => [
19678
+ ...a.commands.map((c) => ({ pattern: `cmd/${c}/**`, modules: [m2] })),
19679
+ ...a.apiServices.map((s2) => ({ pattern: `api/*/${s2}/**`, modules: [m2] }))
19680
+ ]);
19681
+ return [...own3, ...FEISHU_SHARED_RULES];
19696
19682
  }
19697
- function feishuSelectedModules(raw) {
19698
- if (!raw) return [];
19683
+ function ruleToExtglob(pattern) {
19684
+ const tail = pattern.endsWith("/**");
19685
+ const body2 = (tail ? pattern.slice(0, -3) : pattern).split("/").map((seg) => seg === "*" ? "+([!/])" : seg).join("/");
19686
+ return tail ? `${body2}?(/*)` : body2;
19687
+ }
19688
+ function feishuParseSelection(raw) {
19689
+ if (!raw) return { state: "none", modules: [] };
19690
+ let parsed;
19699
19691
  try {
19700
- const parsed = JSON.parse(raw);
19701
- return Array.isArray(parsed.modules) ? parsed.modules.filter((m2) => typeof m2 === "string" && !!FEISHU_MODULE_ACCESS[m2]) : [];
19692
+ parsed = JSON.parse(raw);
19702
19693
  } catch {
19703
- return [];
19694
+ return { state: "invalid", modules: [] };
19704
19695
  }
19696
+ const modules = Array.isArray(parsed?.modules) ? [...new Set(parsed.modules.filter((m2) => typeof m2 === "string" && !!FEISHU_MODULE_ACCESS[m2]))] : [];
19697
+ return modules.length > 0 ? { state: "ok", modules } : { state: "invalid", modules: [] };
19698
+ }
19699
+ function feishuModulePolicyEnv(selection) {
19700
+ const picked = selection.state === "ok" ? selection.modules.filter((m2) => FEISHU_MODULE_ACCESS[m2]) : [];
19701
+ const label2 = (m2) => (FEISHU_MODULE_LABELS[m2] ?? m2).replace(/\s+/g, "");
19702
+ return {
19703
+ OASIS_FEISHU_POLICY: picked.length > 0 ? "ok" : selection.state === "ok" ? "invalid" : selection.state,
19704
+ OASIS_FEISHU_ALLOW: ` ${picked.join(" ")} `,
19705
+ OASIS_FEISHU_RULES: feishuModuleRules().map((r) => `${ruleToExtglob(r.pattern)}=${r.modules.join(",")}`).join(" "),
19706
+ OASIS_FEISHU_LABELS: Object.keys(FEISHU_MODULE_ACCESS).map((m2) => `${m2}=${label2(m2)}`).join(" "),
19707
+ OASIS_FEISHU_MODULES: picked.map((m2) => FEISHU_MODULE_LABELS[m2] ?? m2).join("\u3001")
19708
+ };
19705
19709
  }
19706
19710
  function feishuModuleAccessReport(input) {
19707
19711
  const granted = input.grantedScopes ? new Set(input.grantedScopes) : null;
19708
- const tenant = (input.appScopes ?? []).filter((s2) => s2.scope_type === "tenant" && s2.scope_name);
19712
+ const tenant = /* @__PURE__ */ new Map();
19713
+ for (const s2 of input.appScopes ?? []) {
19714
+ if (s2.scope_type !== "tenant" || !s2.scope_name) continue;
19715
+ const ok3 = s2.grant_status === void 0 || s2.grant_status === 1;
19716
+ tenant.set(s2.scope_name, (tenant.get(s2.scope_name) ?? false) || ok3);
19717
+ }
19709
19718
  return input.modules.filter((m2) => FEISHU_MODULE_ACCESS[m2]).map((m2) => {
19710
- const prefixes = FEISHU_MODULE_ACCESS[m2].botScopePrefixes;
19711
- const mine = tenant.filter((s2) => prefixes.some((p2) => s2.scope_name.startsWith(p2)));
19712
- const bot = input.appScopes === null ? "unknown" : mine.some((s2) => s2.grant_status === void 0 || s2.grant_status === 1) ? "granted" : mine.length > 0 ? "pending" : "missing";
19719
+ const gaps = [];
19720
+ let anyGranted = false;
19721
+ let anyPending = false;
19722
+ for (const cap of FEISHU_MODULE_ACCESS[m2].botCapabilities) {
19723
+ if (cap.anyOf.some((s2) => tenant.get(s2) === true)) {
19724
+ anyGranted = true;
19725
+ continue;
19726
+ }
19727
+ const pending = cap.anyOf.some((s2) => tenant.has(s2));
19728
+ if (pending) anyPending = true;
19729
+ gaps.push({ label: cap.label, state: pending ? "pending" : "missing", scopes: [...cap.anyOf] });
19730
+ }
19731
+ const bot = input.appScopes === null ? "unknown" : gaps.length === 0 ? "granted" : anyGranted ? "partial" : anyPending ? "pending" : "missing";
19713
19732
  const missingUserScopes = granted ? (FEISHU_DOMAIN_SCOPES[m2]?.scopes ?? []).filter((s2) => !granted.has(s2)) : [];
19714
- const user = input.userAuthInvalid ? "invalid" : !input.hasUserAuth ? "none" : missingUserScopes.length > 0 ? "partial" : "granted";
19733
+ const user = input.userAuthInvalid ? "invalid" : !input.hasUserAuth ? "none" : !granted ? "unknown" : missingUserScopes.length > 0 ? "partial" : "granted";
19715
19734
  return {
19716
19735
  id: m2,
19717
19736
  label: FEISHU_MODULE_LABELS[m2] ?? m2,
19718
19737
  bot,
19738
+ missingBotCapabilities: bot === "unknown" ? [] : gaps,
19719
19739
  user,
19720
19740
  missingUserScopes: user === "partial" ? missingUserScopes : []
19721
19741
  };
@@ -19730,7 +19750,7 @@ function feishuSendAsUserState(sel) {
19730
19750
  function feishuAppPermissionConsoleUrl(appId) {
19731
19751
  return `https://open.feishu.cn/app/${encodeURIComponent(appId)}/auth`;
19732
19752
  }
19733
- 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, FEISHU_MODULE_ACCESS, FEISHU_MODULE_LABELS;
19753
+ 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, FEISHU_MODULE_ACCESS, DRIVE_DOCS_ONLY_SHORTCUTS, DRIVE_DOCS_ONLY_RESOURCES, DRIVE_SHARED_SHORTCUTS, FEISHU_SHARED_RULES, FEISHU_MODULE_LABELS;
19734
19754
  var init_scopes = __esm({
19735
19755
  "../connectors/src/feishu/scopes.ts"() {
19736
19756
  "use strict";
@@ -20134,25 +20154,154 @@ var init_scopes = __esm({
20134
20154
  FEISHU_AUTH_SELECTION_VAR = "FEISHU_AUTH_SELECTION";
20135
20155
  AUTO_APPROVED = new Set(FEISHU_BASIC_SCOPES);
20136
20156
  FEISHU_MODULE_ACCESS = {
20137
- im: { commands: ["im"], apiServices: ["im"], botScopePrefixes: ["im:"] },
20138
- calendar: { commands: ["calendar"], apiServices: ["calendar"], botScopePrefixes: ["calendar:"] },
20139
- docs: { commands: ["docs", "drive", "markdown", "mindnotes"], apiServices: ["docx", "doc", "docs", "drive", "mindnote", "mindnotes", "suite"], botScopePrefixes: ["docs:", "docx:", "space:"] },
20140
- drive: { commands: ["drive", "markdown"], apiServices: ["drive"], botScopePrefixes: ["drive:"] },
20141
- sheets: { commands: ["sheets"], apiServices: ["sheets"], botScopePrefixes: ["sheets:"] },
20142
- base: { commands: ["base"], apiServices: ["bitable", "base"], botScopePrefixes: ["base:", "bitable:"] },
20143
- wiki: { commands: ["wiki"], apiServices: ["wiki"], botScopePrefixes: ["wiki:"] },
20144
- slides: { commands: ["slides"], apiServices: ["slides", "slides_ai"], botScopePrefixes: ["slides:"] },
20145
- task: { commands: ["task"], apiServices: ["task"], botScopePrefixes: ["task:"] },
20146
- approval: { commands: ["approval"], apiServices: ["approval"], botScopePrefixes: ["approval:"] },
20147
- mail: { commands: ["mail"], apiServices: ["mail"], botScopePrefixes: ["mail:"] },
20148
- minutes: { commands: ["minutes"], apiServices: ["minutes"], botScopePrefixes: ["minutes:"] },
20149
- vc: { commands: ["vc", "note"], apiServices: ["vc"], botScopePrefixes: ["vc:"] },
20150
- contact: { commands: ["contact"], apiServices: ["contact", "search"], botScopePrefixes: ["contact:"] },
20151
- okr: { commands: ["okr"], apiServices: ["okr"], botScopePrefixes: ["okr:"] },
20152
- attendance: { commands: ["attendance"], apiServices: ["attendance"], botScopePrefixes: ["attendance:"] },
20153
- board: { commands: ["whiteboard"], apiServices: ["board"], botScopePrefixes: ["board:"] },
20154
- spark: { commands: ["apps"], apiServices: ["spark"], botScopePrefixes: ["spark:"] }
20155
- };
20157
+ im: { commands: ["im"], apiServices: ["im"], botCapabilities: [
20158
+ { label: "\u53D1\u6D88\u606F", anyOf: ["im:message:send_as_bot", "im:message", "im:message:send"] },
20159
+ { label: "\u8BFB\u6D88\u606F", anyOf: ["im:message:readonly", "im:message", "im:message.group_msg", "im:message.p2p_msg:readonly", "im:message.group_at_msg:readonly"] },
20160
+ { label: "\u7FA4\u4FE1\u606F", anyOf: ["im:chat:readonly", "im:chat:read", "im:chat"] }
20161
+ ] },
20162
+ calendar: { commands: ["calendar"], apiServices: ["calendar"], botCapabilities: [
20163
+ { label: "\u8BFB\u65E5\u7A0B", anyOf: ["calendar:calendar:readonly", "calendar:calendar", "calendar:calendar:read", "calendar:calendar.event:read"] },
20164
+ { label: "\u5199\u65E5\u7A0B", anyOf: ["calendar:calendar", "calendar:calendar.event:create", "calendar:calendar.event:update"] }
20165
+ ] },
20166
+ docs: { commands: ["docs", "mindnotes"], apiServices: ["docx", "doc", "docs", "mindnote", "mindnotes", "suite"], botCapabilities: [
20167
+ { label: "\u8BFB\u6587\u6863", anyOf: ["docx:document:readonly", "docx:document", "docs:document.content:read", "docs:doc:readonly", "docs:doc"] },
20168
+ { label: "\u5199\u6587\u6863", anyOf: ["docx:document", "docx:document:create", "docx:document:write_only", "docs:doc"] }
20169
+ ] },
20170
+ drive: { commands: ["markdown"], apiServices: [], botCapabilities: [
20171
+ { label: "\u4E0B\u8F7D\u6587\u4EF6", anyOf: ["drive:drive:readonly", "drive:drive", "drive:file:download", "drive:file:readonly", "drive:file"] },
20172
+ { label: "\u4E0A\u4F20\u6587\u4EF6", anyOf: ["drive:drive", "drive:file:upload", "drive:file"] }
20173
+ ] },
20174
+ sheets: { commands: ["sheets"], apiServices: ["sheets"], botCapabilities: [
20175
+ { label: "\u8BFB\u8868\u683C", anyOf: ["sheets:spreadsheet:readonly", "sheets:spreadsheet", "sheets:spreadsheet:read"] },
20176
+ { label: "\u5199\u8868\u683C", anyOf: ["sheets:spreadsheet", "sheets:spreadsheet:write_only", "sheets:spreadsheet:create"] }
20177
+ ] },
20178
+ base: { commands: ["base"], apiServices: ["bitable", "base"], botCapabilities: [
20179
+ { label: "\u8BFB\u8BB0\u5F55", anyOf: ["bitable:app:readonly", "bitable:app", "base:record:read", "base:app:read"] },
20180
+ { label: "\u5199\u8BB0\u5F55", anyOf: ["bitable:app", "base:record:create", "base:record:update"] }
20181
+ ] },
20182
+ wiki: { commands: ["wiki"], apiServices: ["wiki"], botCapabilities: [
20183
+ { label: "\u8BFB\u77E5\u8BC6\u5E93", anyOf: ["wiki:wiki:readonly", "wiki:wiki", "wiki:node:read", "wiki:space:read"] },
20184
+ { label: "\u5199\u77E5\u8BC6\u5E93", anyOf: ["wiki:wiki", "wiki:node:create", "wiki:space:write_only"] }
20185
+ ] },
20186
+ slides: { commands: ["slides"], apiServices: ["slides", "slides_ai"], botCapabilities: [
20187
+ { label: "\u8BFB\u5E7B\u706F\u7247", anyOf: ["slides:presentation:read", "slides:presentation:readonly", "slides:presentation"] },
20188
+ { label: "\u5199\u5E7B\u706F\u7247", anyOf: ["slides:presentation:update", "slides:presentation:write_only", "slides:presentation:create", "slides:presentation"] }
20189
+ ] },
20190
+ task: { commands: ["task"], apiServices: ["task"], botCapabilities: [
20191
+ { label: "\u8BFB\u4EFB\u52A1", anyOf: ["task:task:read", "task:task:readonly", "task:task"] },
20192
+ { label: "\u5199\u4EFB\u52A1", anyOf: ["task:task:write", "task:task"] }
20193
+ ] },
20194
+ approval: { commands: ["approval"], apiServices: ["approval"], botCapabilities: [
20195
+ { label: "\u8BFB\u5BA1\u6279", anyOf: ["approval:instance:read", "approval:approval:readonly", "approval:approval"] },
20196
+ { label: "\u5904\u7406\u5BA1\u6279", anyOf: ["approval:instance:write", "approval:task:write", "approval:approval"] }
20197
+ ] },
20198
+ mail: { commands: ["mail"], apiServices: ["mail"], botCapabilities: [
20199
+ { label: "\u8BFB\u90AE\u4EF6", anyOf: ["mail:user_mailbox.message:readonly", "mail:user_mailbox:readonly", "mail:user_mailbox"] }
20200
+ ] },
20201
+ minutes: { commands: ["minutes"], apiServices: ["minutes"], botCapabilities: [
20202
+ { label: "\u8BFB\u5999\u8BB0", anyOf: ["minutes:minutes:readonly", "minutes:minutes", "minutes:minutes.search:read"] }
20203
+ ] },
20204
+ vc: { commands: ["vc", "note"], apiServices: ["vc"], botCapabilities: [
20205
+ { label: "\u8BFB\u4F1A\u8BAE", anyOf: ["vc:meeting:readonly", "vc:meeting", "vc:meeting.meetingevent:read", "vc:record:readonly"] }
20206
+ ] },
20207
+ contact: { commands: ["contact"], apiServices: ["contact"], botCapabilities: [
20208
+ { label: "\u8BFB\u901A\u8BAF\u5F55", anyOf: ["contact:user.base:readonly", "contact:contact:readonly_as_app", "contact:contact:readonly", "contact:contact", "contact:user.basic_profile:readonly"] }
20209
+ ] },
20210
+ okr: { commands: ["okr"], apiServices: ["okr"], botCapabilities: [
20211
+ { label: "\u8BFB OKR", anyOf: ["okr:okr:readonly", "okr:okr", "okr:okr:read"] }
20212
+ ] },
20213
+ attendance: { commands: ["attendance"], apiServices: ["attendance"], botCapabilities: [
20214
+ { label: "\u8BFB\u8003\u52E4", anyOf: ["attendance:task:readonly", "attendance:record:read", "attendance:task"] }
20215
+ ] },
20216
+ board: { commands: ["whiteboard"], apiServices: ["board"], botCapabilities: [
20217
+ { label: "\u8BFB\u767D\u677F", anyOf: ["board:whiteboard:node:read"] },
20218
+ { label: "\u5199\u767D\u677F", anyOf: ["board:whiteboard:node:create"] }
20219
+ ] },
20220
+ spark: { commands: ["apps"], apiServices: ["spark"], botCapabilities: [
20221
+ { label: "\u8BFB\u5E94\u7528", anyOf: ["spark:app:read"] },
20222
+ { label: "\u5199\u5E94\u7528", anyOf: ["spark:app:write"] }
20223
+ ] }
20224
+ };
20225
+ DRIVE_DOCS_ONLY_SHORTCUTS = [
20226
+ // 评论
20227
+ "+add-comment",
20228
+ "+add-reply",
20229
+ "+batch-query-comments",
20230
+ "+delete-reply",
20231
+ "+list-comments",
20232
+ "+list-replies",
20233
+ "+react-reply",
20234
+ "+resolve-comment",
20235
+ "+restore-comment",
20236
+ "+update-reply",
20237
+ // 协作者与分享权限
20238
+ "+apply-permission",
20239
+ "+member-add",
20240
+ "+member-list",
20241
+ "+member-remove",
20242
+ "+permission-get-setting",
20243
+ // 导入导出、搜索、密级
20244
+ "+export",
20245
+ "+export-download",
20246
+ "+import",
20247
+ "+search",
20248
+ "+secure-label-list",
20249
+ "+secure-label-update"
20250
+ ];
20251
+ DRIVE_DOCS_ONLY_RESOURCES = [
20252
+ "file.comment.reply.reactions",
20253
+ "file.comment.replys",
20254
+ "file.comments",
20255
+ "permission.members",
20256
+ "permission.public",
20257
+ "user"
20258
+ ];
20259
+ DRIVE_SHARED_SHORTCUTS = ["+copy", "+create-folder", "+create-shortcut", "+delete", "+move", "+update-title", "+inspect", "+task_result"];
20260
+ FEISHU_SHARED_RULES = [
20261
+ ...DRIVE_DOCS_ONLY_SHORTCUTS.map((s2) => ({ pattern: `cmd/drive/${s2}/**`, modules: ["docs"] })),
20262
+ ...DRIVE_DOCS_ONLY_RESOURCES.map((r) => ({ pattern: `cmd/drive/${r}/*/**`, modules: ["docs"] })),
20263
+ ...DRIVE_SHARED_SHORTCUTS.map((s2) => ({ pattern: `cmd/drive/${s2}/**`, modules: ["docs", "drive"] })),
20264
+ ...["copy", "create_folder", "patch"].map((m2) => ({ pattern: `cmd/drive/files/${m2}/**`, modules: ["docs", "drive"] })),
20265
+ { pattern: "cmd/drive/metas/*/**", modules: ["docs", "drive"] },
20266
+ // drive 后面先写参数再写子命令的(`drive --as bot +add-comment`),认不出子命令归谁——谁都不放行。
20267
+ { pattern: "cmd/drive/-/**", modules: [] },
20268
+ { pattern: "cmd/drive/**", modules: ["drive"] },
20269
+ ...[
20270
+ "drive/v1/permissions/**",
20271
+ "drive/v2/permissions/**",
20272
+ "drive/permission/**",
20273
+ "drive/v1/files/*/comments/**",
20274
+ "drive/v1/files/*/new_comments/**",
20275
+ "drive/v2/files/*/comments/**",
20276
+ "drive/v2/files/*/likes/**",
20277
+ "drive/v1/files/*/subscribe/**",
20278
+ "drive/v1/files/*/get_subscribe/**",
20279
+ "drive/v1/files/*/delete_subscribe/**",
20280
+ "drive/v1/files/*/subscriptions/**",
20281
+ "drive/v1/user/**",
20282
+ "drive/v1/import_tasks/**",
20283
+ "drive/v1/export_tasks/**",
20284
+ "drive/v1/medias/**",
20285
+ "drive/v2/files/*/secure_label/**",
20286
+ "drive/v2/my_secure_labels/**"
20287
+ ].map((p2) => ({ pattern: `api/*/${p2}`, modules: ["docs"] })),
20288
+ ...[
20289
+ "*/drive/v1/files/create_folder/**",
20290
+ "*/drive/v1/files/create_shortcut/**",
20291
+ "*/drive/v1/files/task_check/**",
20292
+ "*/drive/v1/files/*/move/**",
20293
+ "*/drive/v1/files/*/copy/**",
20294
+ "DELETE/drive/v1/files/*",
20295
+ "PATCH/drive/v1/files/*",
20296
+ "*/drive/v1/metas/**",
20297
+ "*/drive/v2/files/query_by_token/**",
20298
+ "*/drive/explorer/**"
20299
+ ].map((p2) => ({ pattern: `api/${p2}`, modules: ["docs", "drive"] })),
20300
+ { pattern: "api/*/drive/**", modules: ["drive"] },
20301
+ { pattern: "api/*/search/v1/user/**", modules: ["contact"] },
20302
+ { pattern: "api/*/search/v2/message/**", modules: ["im"] },
20303
+ { pattern: "api/*/search/v2/doc_wiki/**", modules: ["docs", "wiki"] }
20304
+ ];
20156
20305
  FEISHU_MODULE_LABELS = {
20157
20306
  im: "\u5373\u65F6\u6D88\u606F",
20158
20307
  calendar: "\u65E5\u5386",
@@ -20403,7 +20552,7 @@ var init_feishu = __esm({
20403
20552
  if (!appSecret) throw new Error("feishu inject: missing app_secret");
20404
20553
  const userAccessToken = credentials2["user_access_token"] ?? credentials2["FEISHU_USER_ACCESS_TOKEN"];
20405
20554
  const modulePolicy = feishuModulePolicyEnv(
20406
- feishuSelectedModules(credentials2["auth_selection"] ?? credentials2[FEISHU_AUTH_SELECTION_VAR])
20555
+ feishuParseSelection(credentials2["auth_selection"] ?? credentials2[FEISHU_AUTH_SELECTION_VAR])
20407
20556
  );
20408
20557
  const tenantAccessToken = this.isSimulated() ? null : await this.fetchTenantToken(appId, appSecret) ?? previousTenantToken(sessionEnv.get("FEISHU_CREDS_FILE"), appId);
20409
20558
  const creds = await writeSessionCredsFile(this.config.slug, {
@@ -20411,7 +20560,7 @@ var init_feishu = __esm({
20411
20560
  LARKSUITE_CLI_APP_SECRET: appSecret,
20412
20561
  ...tenantAccessToken ? { LARKSUITE_CLI_TENANT_ACCESS_TOKEN: tenantAccessToken } : {},
20413
20562
  ...userAccessToken ? { LARKSUITE_CLI_USER_ACCESS_TOKEN: userAccessToken } : {},
20414
- ...modulePolicy ?? {}
20563
+ ...modulePolicy
20415
20564
  }, sessionEnv.get("FEISHU_RUN_TMPDIR"));
20416
20565
  const configDir = (0, import_node_path12.join)(creds.dir, "lark-config");
20417
20566
  await (0, import_promises5.mkdir)(configDir, { recursive: true, mode: 448 });
@@ -212007,10 +212156,10 @@ async function feishuModuleAccess(store, actorId, fetchScopes = fetchFeishuAppSc
212007
212156
  const appSecret = await read3("FEISHU_APP_SECRET");
212008
212157
  if (!appId || !appSecret) return { configured: false };
212009
212158
  const rawSelection = await read3(FEISHU_AUTH_SELECTION_VAR);
212010
- const modules = feishuSelectedModules(rawSelection);
212159
+ const { state: selection, modules } = feishuParseSelection(rawSelection);
212011
212160
  let parsed = {};
212012
212161
  try {
212013
- parsed = rawSelection ? JSON.parse(rawSelection) : {};
212162
+ parsed = rawSelection ? JSON.parse(rawSelection) ?? {} : {};
212014
212163
  } catch {
212015
212164
  parsed = {};
212016
212165
  }
@@ -212028,7 +212177,7 @@ async function feishuModuleAccess(store, actorId, fetchScopes = fetchFeishuAppSc
212028
212177
  }
212029
212178
  return {
212030
212179
  configured: true,
212031
- restricted: modules.length > 0,
212180
+ selection,
212032
212181
  modules: feishuModuleAccessReport({ modules, grantedScopes, hasUserAuth, userAuthInvalid, appScopes }),
212033
212182
  hasUserAuth,
212034
212183
  userAuthInvalid,
@@ -286888,53 +287037,43 @@ function createConnectorRenewalRuntime(options) {
286888
287037
  return "sent";
286889
287038
  };
286890
287039
  const recipientsFor = async (companyId, store, actorId) => {
286891
- const out = /* @__PURE__ */ new Set();
286892
287040
  const by = await store.revealVariable(FEISHU_AUTHORIZED_BY_VAR, actorId).catch(() => null);
286893
- if (by && isHumanActorId(by)) out.add(by);
286894
- if (out.size === 0 && actorId) {
286895
- if (isHumanActorId(actorId)) out.add(actorId);
286896
- else {
286897
- const human = await options.boundHuman(actorId, companyId).catch(() => null);
286898
- if (human) out.add(human);
286899
- }
286900
- }
286901
- return [...out];
287041
+ if (by && isHumanActorId(by)) return { recipients: [by], authorizer: by };
287042
+ if (!actorId) return { recipients: [], authorizer: null };
287043
+ if (isHumanActorId(actorId)) return { recipients: [actorId], authorizer: null };
287044
+ const human = await options.boundHuman(actorId, companyId).catch(() => null);
287045
+ return { recipients: human ? [human] : [], authorizer: null };
286902
287046
  };
286903
- const recoverOpenId = async (companyId, app, recipients) => {
286904
- for (const human of recipients) {
286905
- const email2 = await options.memberEmail?.(human, companyId).catch(() => null);
286906
- if (!email2) continue;
286907
- const openId = await lookupFeishuOpenIdByEmail({ ...app, email: email2 });
286908
- if (openId) return openId;
286909
- }
286910
- return null;
287047
+ const recoverOpenId = async (companyId, app, authorizer) => {
287048
+ const email2 = await options.memberEmail?.(authorizer, companyId).catch(() => null);
287049
+ return email2 ? lookupFeishuOpenIdByEmail({ ...app, email: email2 }) : null;
286911
287050
  };
286912
287051
  const deliverInvalidNotice = async (companyId, store, actorId, marker) => {
286913
287052
  const prev = marker.notice ?? { inApp: false, dm: "pending", attempts: 0 };
286914
287053
  const state = { ...prev, attempts: prev.attempts + 1 };
286915
287054
  const who = `actor=${actorId ?? "-"} \u7B2C ${state.attempts}/${MAX_NOTICE_ATTEMPTS} \u6B21`;
286916
287055
  const name = await agentName(companyId, actorId);
286917
- const recipients = await recipientsFor(companyId, store, actorId);
287056
+ const { recipients, authorizer } = await recipientsFor(companyId, store, actorId);
287057
+ const unverified = !authorizer && !await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId).catch(() => "?");
286918
287058
  if (!state.inApp) {
286919
287059
  try {
286920
287060
  const ledger = await options.notifications(companyId);
286921
- if (ledger) {
286922
- const rows = [];
286923
- for (const recipient of recipients) {
286924
- rows.push(await ledger.insert({
286925
- recipient,
286926
- category: "connector",
286927
- kind: "feishu-auth-invalid",
286928
- // 每次失效一条:键里带失效时刻,重新授权后再失效还会再提醒;同一次失效补发 / 重复扫描不重发(唯一约束)。
286929
- sourceKey: `connector:feishu:${actorId ?? "org"}@invalid:${marker.at}`,
286930
- title: `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u9700\u8981\u91CD\u65B0\u6388\u6743`,
286931
- ...actorId ? { actorId } : {},
286932
- enteredAt: marker.at
286933
- }));
286934
- }
286935
- if (rows.length > 0) options.onNotifications?.(companyId, rows);
287061
+ if (!ledger) throw new Error("\u8BE5\u516C\u53F8\u7684\u901A\u77E5\u53F0\u8D26\u4E0D\u53EF\u7528");
287062
+ if (recipients.length === 0) throw new Error("\u6CA1\u6709\u6536\u4EF6\u4EBA\uFF08\u6CA1\u8BB0\u6388\u6743\u4EBA\u3001\u5458\u5DE5\u4E5F\u6CA1\u6709\u7ED1\u5B9A\u771F\u4EBA\uFF09");
287063
+ const rows = [];
287064
+ for (const recipient of recipients) {
287065
+ rows.push(await ledger.insert({
287066
+ recipient,
287067
+ category: "connector",
287068
+ kind: "feishu-auth-invalid",
287069
+ // 每次失效一条:键里带失效时刻,重新授权后再失效还会再提醒;同一次失效补发 / 重复扫描不重发(唯一约束)。
287070
+ sourceKey: `connector:feishu:${actorId ?? "org"}@invalid:${marker.at}`,
287071
+ title: unverified ? `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u8BF7\u5230\u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5` : `\u300C${name}\u300D\u7684\u98DE\u4E66\u7528\u6237\u6388\u6743\u5DF2\u5931\u6548\uFF0C\u9700\u8981\u91CD\u65B0\u6388\u6743`,
287072
+ ...actorId ? { actorId } : {},
287073
+ enteredAt: marker.at
287074
+ }));
286936
287075
  }
286937
- if (recipients.length === 0) console.warn(`[credential-refresh] \u98DE\u4E66\u6388\u6743\u5931\u6548\u7AD9\u5185\u901A\u77E5\u6CA1\u6709\u6536\u4EF6\u4EBA actor=${actorId ?? "-"}`);
287076
+ options.onNotifications?.(companyId, rows);
286938
287077
  state.inApp = true;
286939
287078
  } catch (err) {
286940
287079
  options.warn(new Error(`\u98DE\u4E66\u6388\u6743\u5931\u6548\u7AD9\u5185\u901A\u77E5\u672A\u5199\u5165\uFF08${who}\uFF0C\u4E0B\u4E00\u62CD\u91CD\u8BD5\uFF09: ${String(err)}`));
@@ -286943,12 +287082,13 @@ function createConnectorRenewalRuntime(options) {
286943
287082
  if (state.dm === "pending") {
286944
287083
  try {
286945
287084
  const app = await appCredentials(store, actorId);
286946
- const stored = await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId);
286947
- const recovered = !stored && app ? await recoverOpenId(companyId, app, recipients) : null;
286948
- const openId = stored || recovered;
287085
+ const storedOpenId = await store.revealVariable(FEISHU_USER_OPEN_ID_VAR, actorId);
287086
+ const recovered = !storedOpenId && app && authorizer ? await recoverOpenId(companyId, app, authorizer) : null;
287087
+ const openId = storedOpenId || recovered;
286949
287088
  if (!app || !openId) {
286950
287089
  state.dm = "unavailable";
286951
- console.warn(`[credential-refresh] \u98DE\u4E66\u6388\u6743\u5931\u6548\u79C1\u4FE1\u65E0\u4ECE\u53D1\u51FA\uFF08${app ? "\u6CA1\u8BB0\u6388\u6743\u4EBA\u3001\u901A\u8BAF\u5F55\u4E5F\u6CA1\u6309\u6210\u5458\u90AE\u7BB1\u627E\u5230\u672C\u4EBA" : "\u6CA1\u6709\u5E94\u7528\u51ED\u636E"}\uFF09actor=${actorId ?? "-"}\uFF1B\u53EA\u6709\u7AD9\u5185\u901A\u77E5`);
287090
+ const why = !app ? "\u6CA1\u6709\u5E94\u7528\u51ED\u636E" : unverified ? "\u6CA1\u8BB0\u539F\u6388\u6743\u4EBA\uFF0C\u6838\u5B9E\u4E0D\u4E86\u672C\u4EBA\uFF0C\u4E0D\u7B7E\u94FE\u63A5\uFF1B\u9700\u5230\u8FDE\u63A5\u5668\u9875\u91CD\u65B0\u8FDE\u63A5" : "\u901A\u8BAF\u5F55\u6CA1\u6309\u539F\u6388\u6743\u4EBA\u7684\u8D26\u53F7\u90AE\u7BB1\u627E\u5230\u4ED6";
287091
+ console.warn(`[credential-refresh] \u98DE\u4E66\u6388\u6743\u5931\u6548\u79C1\u4FE1\u65E0\u4ECE\u53D1\u51FA\uFF08${why}\uFF09actor=${actorId ?? "-"}\uFF1B\u53EA\u6709\u7AD9\u5185\u901A\u77E5`);
286952
287092
  } else {
286953
287093
  const token2 = await issueFeishuReauthToken(options.links, store, {
286954
287094
  companyId,
@@ -300944,7 +301084,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
300944
301084
  }
300945
301085
  }
300946
301086
  }
300947
- var CLI_VERSION = "2.2.112" ? "2.2.112" : "dev";
301087
+ var CLI_VERSION = "2.2.113" ? "2.2.113" : "dev";
300948
301088
  function apiHeaders(token2, company) {
300949
301089
  const headers = {
300950
301090
  authorization: `Bearer ${token2}`,
@@ -305115,7 +305255,7 @@ function shimScript() {
305115
305255
  }
305116
305256
 
305117
305257
  // src/index.ts
305118
- var PKG_VERSION = true ? "2.2.112" : "dev";
305258
+ var PKG_VERSION = true ? "2.2.113" : "dev";
305119
305259
  var LOCAL_BIN = localBin();
305120
305260
  var NPM_PREFIX = npmPrefix();
305121
305261
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.112",
3
+ "version": "2.2.113",
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": "278bdc2558b23bd381c4c3007a8d40330244edc1"
29
+ "sourceHead": "590c9d80c3286fa10fdb0eb14de96140b1520130"
30
30
  }
31
31
  }