@hwj123weijian/pi-feishu 0.9.0 → 0.10.0
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/README.md +1 -1
- package/package.json +1 -1
- package/src/controller.ts +24 -1
- package/src/extension.ts +4 -18
- package/src/gateway.ts +3 -2
- package/src/scopes.ts +48 -0
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
- 消息需要排队时发送“排队中(第 N 位)”提示,轮到处理时自动撤回;队列变化时提示自动改写为新位数
|
|
17
17
|
- Owner 在排队中的消息上点 ❌(`CrossMark`)表情即可取消该消息
|
|
18
18
|
- 未绑定的群里被 @ 时,bot 会回复绑定引导而不是沉默;非授权成员的普通群消息完全不会触发回复
|
|
19
|
-
- Bot 被拉进新群时,会私聊 Owner
|
|
19
|
+
- Bot 被拉进新群时,会私聊 Owner 发送绑定引导和群聊权限体检结果;启动成功后也会私聊 Owner 发送欢迎语和权限体检
|
|
20
20
|
- Assistant 文本通过 Pi 的 `message_update` 增量渲染到同一张飞书卡片
|
|
21
21
|
- 工具执行时仅显示安全的状态摘要,不展示参数、命令、文件内容或工具输出
|
|
22
22
|
- SDK 以 500ms / 120 字符节流卡片更新;完成、失败、中止都会收尾卡片,失败原因(脱敏后)会写进回复
|
package/package.json
CHANGED
package/src/controller.ts
CHANGED
|
@@ -25,7 +25,12 @@ import { MessageDeduplicator } from "./message-deduplicator.js";
|
|
|
25
25
|
import { SerialMessageQueue } from "./message-queue.js";
|
|
26
26
|
import { OwnerBinding } from "./owner-binding.js";
|
|
27
27
|
import { executeRemoteCommand, type ParsedRemoteCommand, parseRemoteCommand } from "./remote-commands.js";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
buildBotAddedGuidance,
|
|
30
|
+
buildGroupPermissionReminder,
|
|
31
|
+
buildScopeHealthSection,
|
|
32
|
+
buildStartupWelcome,
|
|
33
|
+
} from "./scopes.js";
|
|
29
34
|
|
|
30
35
|
// 与 easycodeclient 的飞书集成一致:THINKING 表情兼作"已读 + 处理中"回执。
|
|
31
36
|
const READ_REACTION_EMOJI = "THINKING";
|
|
@@ -136,6 +141,8 @@ export class FeishuController {
|
|
|
136
141
|
...(existing.ownerOpenId ? { ownerOpenId: existing.ownerOpenId } : {}),
|
|
137
142
|
...(existing.managedGroupIds ? { managedGroupIds: existing.managedGroupIds } : {}),
|
|
138
143
|
...(existing.groupSessions ? { groupSessions: existing.groupSessions } : {}),
|
|
144
|
+
...(existing.allowlist ? { allowlist: existing.allowlist } : {}),
|
|
145
|
+
...(existing.allowlistNames ? { allowlistNames: existing.allowlistNames } : {}),
|
|
139
146
|
}
|
|
140
147
|
: credentials;
|
|
141
148
|
await this.store.save(next);
|
|
@@ -175,10 +182,26 @@ export class FeishuController {
|
|
|
175
182
|
gateway.onReaction((event) => this.handleReaction(event));
|
|
176
183
|
this.botAddedUnsubscribe = gateway.onBotAdded?.((event) => void this.handleBotAdded(event));
|
|
177
184
|
|
|
185
|
+
// 对齐 easycodeclient:网关启动后私聊 Owner 发欢迎语 + 权限体检。
|
|
186
|
+
// 主动 await 保证欢迎语先于任何消息回复送达;probe/发送失败都不阻塞启动。
|
|
187
|
+
if (credentials.ownerOpenId) await this.sendStartupWelcome(gateway, credentials);
|
|
188
|
+
|
|
178
189
|
const bindingCode = binding.getOrCreateCode();
|
|
179
190
|
return bindingCode ? { alreadyRunning: false, bindingCode } : { alreadyRunning: false };
|
|
180
191
|
}
|
|
181
192
|
|
|
193
|
+
/** Bot 上线后私聊 Owner 的欢迎语;probe 失败时只发正文,不猜权限状态。 */
|
|
194
|
+
private async sendStartupWelcome(gateway: FeishuGateway, credentials: FeishuCredentials): Promise<void> {
|
|
195
|
+
const ownerOpenId = credentials.ownerOpenId;
|
|
196
|
+
if (!ownerOpenId) return;
|
|
197
|
+
const probe = await this.probeScopes();
|
|
198
|
+
const welcome = buildStartupWelcome({
|
|
199
|
+
cwd: process.cwd(),
|
|
200
|
+
healthSection: buildScopeHealthSection(credentials.appId, probe.grantedScopes),
|
|
201
|
+
});
|
|
202
|
+
await gateway.sendText(ownerOpenId, welcome).catch(() => undefined);
|
|
203
|
+
}
|
|
204
|
+
|
|
182
205
|
async createGroupChat(name: string): Promise<string> {
|
|
183
206
|
const gateway = this.gateway;
|
|
184
207
|
const ownerOpenId = this.credentials?.ownerOpenId;
|
package/src/extension.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
buildEventSubUrl,
|
|
11
11
|
buildPermissionPageUrl,
|
|
12
12
|
buildScopeApplyUrl,
|
|
13
|
+
buildScopeHealthSection,
|
|
13
14
|
hasScope,
|
|
14
15
|
missingScopes,
|
|
15
16
|
REQUIRED_APP_SCOPES,
|
|
@@ -336,24 +337,9 @@ export async function appendScopeHealthHint(
|
|
|
336
337
|
dashboard: string,
|
|
337
338
|
grantedScopes?: string[],
|
|
338
339
|
): Promise<string> {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (missing.length === 0 && hasGroupMsg) {
|
|
343
|
-
return `${dashboard}\n\n✅ 应用权限配置完整,所有功能均可正常使用。`;
|
|
344
|
-
}
|
|
345
|
-
const lines = ["", "⚠️ 以下应用权限尚未开通,对应功能会受限:"];
|
|
346
|
-
if (missing.length > 0) {
|
|
347
|
-
lines.push(`📋 缺失 ${missing.length} 项基础权限,点击一键申请:`);
|
|
348
|
-
lines.push(`👉 ${buildScopeApplyUrl({ appId, scopes: missing })}`);
|
|
349
|
-
}
|
|
350
|
-
if (!hasGroupMsg) {
|
|
351
|
-
lines.push("💬 「免 @ 响应」权限未开:群内需 @机器人 才能触发,点击开通:");
|
|
352
|
-
lines.push(`👉 ${buildScopeApplyUrl({ appId, scopes: [SENSITIVE_GROUP_MSG_SCOPE] })}`);
|
|
353
|
-
}
|
|
354
|
-
lines.push("🔄 权限生效(需发布应用版本):");
|
|
355
|
-
lines.push(`👉 ${buildPermissionPageUrl(appId)}`);
|
|
356
|
-
return `${dashboard}\n${lines.join("\n")}`;
|
|
340
|
+
const section = buildScopeHealthSection(appId, grantedScopes);
|
|
341
|
+
if (!section) return dashboard;
|
|
342
|
+
return `${dashboard}\n\n${section}`;
|
|
357
343
|
}
|
|
358
344
|
|
|
359
345
|
export function renderFeishuStatus(status: FeishuStatus, scopeHealth?: string[]): string {
|
package/src/gateway.ts
CHANGED
|
@@ -407,8 +407,9 @@ class SdkFeishuReply implements FeishuReply {
|
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
async fail(reason?: string): Promise<void> {
|
|
410
|
-
const
|
|
411
|
-
|
|
410
|
+
const detail = reason ? `处理消息失败:${reason}` : "处理消息失败,请稍后再试。";
|
|
411
|
+
const text = this.snapshot.text ? `${this.snapshot.text}\n\n⚠️ ${detail}` : detail;
|
|
412
|
+
await this.finish({ text, status: "处理失败" }, detail);
|
|
412
413
|
}
|
|
413
414
|
|
|
414
415
|
async cancel(): Promise<void> {
|
package/src/scopes.ts
CHANGED
|
@@ -164,3 +164,51 @@ export function buildBotAddedGuidance(params: {
|
|
|
164
164
|
lines.push(`🔄 权限变更后需发布新版本生效:${buildPermissionPageUrl(params.appId)}`);
|
|
165
165
|
return lines.join("\n");
|
|
166
166
|
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 权限体检段落:grantedScopes 未知时返回 null(不猜);
|
|
170
|
+
* 全部就绪时返回 ✅ 段落,否则返回缺失清单 + 一键申请链接。
|
|
171
|
+
*/
|
|
172
|
+
export function buildScopeHealthSection(appId: string, grantedScopes?: readonly string[]): string | null {
|
|
173
|
+
if (!grantedScopes) return null;
|
|
174
|
+
const missing = missingScopes(grantedScopes, REQUIRED_APP_SCOPES);
|
|
175
|
+
const hasGroupMsg = hasScope(grantedScopes, SENSITIVE_GROUP_MSG_SCOPE);
|
|
176
|
+
if (missing.length === 0 && hasGroupMsg) {
|
|
177
|
+
return "✅ 应用权限配置完整,所有功能均可正常使用。";
|
|
178
|
+
}
|
|
179
|
+
const lines = ["⚠️ 以下应用权限尚未开通,对应功能会受限:"];
|
|
180
|
+
if (missing.length > 0) {
|
|
181
|
+
lines.push(`📋 缺失 ${missing.length} 项基础权限,点击一键申请:`);
|
|
182
|
+
lines.push(`👉 ${buildScopeApplyUrl({ appId, scopes: missing })}`);
|
|
183
|
+
}
|
|
184
|
+
if (!hasGroupMsg) {
|
|
185
|
+
lines.push("💬 「免 @ 响应」权限未开:群内需 @机器人 才能触发,点击开通:");
|
|
186
|
+
lines.push(`👉 ${buildScopeApplyUrl({ appId, scopes: [SENSITIVE_GROUP_MSG_SCOPE] })}`);
|
|
187
|
+
}
|
|
188
|
+
lines.push("🔄 权限生效(需发布应用版本):");
|
|
189
|
+
lines.push(`👉 ${buildPermissionPageUrl(appId)}`);
|
|
190
|
+
return lines.join("\n");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 对齐 easycodeclient:Bot 上线后私聊 Owner 的欢迎语,
|
|
195
|
+
* 包含工作目录、使用提示和权限体检结果。
|
|
196
|
+
*/
|
|
197
|
+
export function buildStartupWelcome(params: { cwd?: string; healthSection?: string | null }): string {
|
|
198
|
+
const lines = ["👋 Pi 飞书 Bot 已上线,随时待命。"];
|
|
199
|
+
if (params.cwd) {
|
|
200
|
+
lines.push("", "**📂 主会话工作目录**", `\`${params.cwd}\``);
|
|
201
|
+
}
|
|
202
|
+
lines.push(
|
|
203
|
+
"",
|
|
204
|
+
"**💡 使用提示**",
|
|
205
|
+
"- 私聊直接发送问题即可",
|
|
206
|
+
"- Owner 在群里发送 /bind 可把群绑定到独立 Pi 会话",
|
|
207
|
+
"",
|
|
208
|
+
"**❓ 需要帮助**:发送 /help 查看所有可用命令",
|
|
209
|
+
);
|
|
210
|
+
if (params.healthSection) {
|
|
211
|
+
lines.push("", "---", "", params.healthSection);
|
|
212
|
+
}
|
|
213
|
+
return lines.join("\n");
|
|
214
|
+
}
|