@openclaw-plugins/feishu-plus 0.1.7-fork.1

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.
@@ -0,0 +1,165 @@
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ import { createFeishuClient } from "./client.js";
3
+ import { resolveFeishuAccount } from "./accounts.js";
4
+ import { normalizeFeishuTarget } from "./targets.js";
5
+
6
+ export type FeishuDirectoryPeer = {
7
+ kind: "user";
8
+ id: string;
9
+ name?: string;
10
+ };
11
+
12
+ export type FeishuDirectoryGroup = {
13
+ kind: "group";
14
+ id: string;
15
+ name?: string;
16
+ };
17
+
18
+ export async function listFeishuDirectoryPeers(params: {
19
+ cfg: ClawdbotConfig;
20
+ query?: string;
21
+ limit?: number;
22
+ accountId?: string;
23
+ }): Promise<FeishuDirectoryPeer[]> {
24
+ const account = resolveFeishuAccount({ cfg: params.cfg, accountId: params.accountId });
25
+ const feishuCfg = account.config;
26
+ const q = params.query?.trim().toLowerCase() || "";
27
+ const ids = new Set<string>();
28
+
29
+ for (const entry of feishuCfg?.allowFrom ?? []) {
30
+ const trimmed = String(entry).trim();
31
+ if (trimmed && trimmed !== "*") ids.add(trimmed);
32
+ }
33
+
34
+ for (const userId of Object.keys(feishuCfg?.dms ?? {})) {
35
+ const trimmed = userId.trim();
36
+ if (trimmed) ids.add(trimmed);
37
+ }
38
+
39
+ return Array.from(ids)
40
+ .map((raw) => raw.trim())
41
+ .filter(Boolean)
42
+ .map((raw) => normalizeFeishuTarget(raw) ?? raw)
43
+ .filter((id) => (q ? id.toLowerCase().includes(q) : true))
44
+ .slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
45
+ .map((id) => ({ kind: "user" as const, id }));
46
+ }
47
+
48
+ export async function listFeishuDirectoryGroups(params: {
49
+ cfg: ClawdbotConfig;
50
+ query?: string;
51
+ limit?: number;
52
+ accountId?: string;
53
+ }): Promise<FeishuDirectoryGroup[]> {
54
+ const account = resolveFeishuAccount({ cfg: params.cfg, accountId: params.accountId });
55
+ const feishuCfg = account.config;
56
+ const q = params.query?.trim().toLowerCase() || "";
57
+ const ids = new Set<string>();
58
+
59
+ for (const groupId of Object.keys(feishuCfg?.groups ?? {})) {
60
+ const trimmed = groupId.trim();
61
+ if (trimmed && trimmed !== "*") ids.add(trimmed);
62
+ }
63
+
64
+ for (const entry of feishuCfg?.groupAllowFrom ?? []) {
65
+ const trimmed = String(entry).trim();
66
+ if (trimmed && trimmed !== "*") ids.add(trimmed);
67
+ }
68
+
69
+ return Array.from(ids)
70
+ .map((raw) => raw.trim())
71
+ .filter(Boolean)
72
+ .filter((id) => (q ? id.toLowerCase().includes(q) : true))
73
+ .slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
74
+ .map((id) => ({ kind: "group" as const, id }));
75
+ }
76
+
77
+ export async function listFeishuDirectoryPeersLive(params: {
78
+ cfg: ClawdbotConfig;
79
+ query?: string;
80
+ limit?: number;
81
+ accountId?: string;
82
+ }): Promise<FeishuDirectoryPeer[]> {
83
+ const account = resolveFeishuAccount({ cfg: params.cfg, accountId: params.accountId });
84
+ if (!account.configured) {
85
+ return listFeishuDirectoryPeers(params);
86
+ }
87
+
88
+ try {
89
+ const client = createFeishuClient(account);
90
+ const peers: FeishuDirectoryPeer[] = [];
91
+ const limit = params.limit ?? 50;
92
+
93
+ const response = await client.contact.user.list({
94
+ params: {
95
+ page_size: Math.min(limit, 50),
96
+ },
97
+ });
98
+
99
+ if (response.code === 0 && response.data?.items) {
100
+ for (const user of response.data.items) {
101
+ if (user.open_id) {
102
+ const q = params.query?.trim().toLowerCase() || "";
103
+ const name = user.name || "";
104
+ if (!q || user.open_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {
105
+ peers.push({
106
+ kind: "user",
107
+ id: user.open_id,
108
+ name: name || undefined,
109
+ });
110
+ }
111
+ }
112
+ if (peers.length >= limit) break;
113
+ }
114
+ }
115
+
116
+ return peers;
117
+ } catch {
118
+ return listFeishuDirectoryPeers(params);
119
+ }
120
+ }
121
+
122
+ export async function listFeishuDirectoryGroupsLive(params: {
123
+ cfg: ClawdbotConfig;
124
+ query?: string;
125
+ limit?: number;
126
+ accountId?: string;
127
+ }): Promise<FeishuDirectoryGroup[]> {
128
+ const account = resolveFeishuAccount({ cfg: params.cfg, accountId: params.accountId });
129
+ if (!account.configured) {
130
+ return listFeishuDirectoryGroups(params);
131
+ }
132
+
133
+ try {
134
+ const client = createFeishuClient(account);
135
+ const groups: FeishuDirectoryGroup[] = [];
136
+ const limit = params.limit ?? 50;
137
+
138
+ const response = await client.im.chat.list({
139
+ params: {
140
+ page_size: Math.min(limit, 100),
141
+ },
142
+ });
143
+
144
+ if (response.code === 0 && response.data?.items) {
145
+ for (const chat of response.data.items) {
146
+ if (chat.chat_id) {
147
+ const q = params.query?.trim().toLowerCase() || "";
148
+ const name = chat.name || "";
149
+ if (!q || chat.chat_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {
150
+ groups.push({
151
+ kind: "group",
152
+ id: chat.chat_id,
153
+ name: name || undefined,
154
+ });
155
+ }
156
+ }
157
+ if (groups.length >= limit) break;
158
+ }
159
+ }
160
+
161
+ return groups;
162
+ } catch {
163
+ return listFeishuDirectoryGroups(params);
164
+ }
165
+ }
@@ -0,0 +1,47 @@
1
+ import { Type, type Static } from "@sinclair/typebox";
2
+
3
+ export const FeishuDocSchema = Type.Union([
4
+ Type.Object({
5
+ action: Type.Literal("read"),
6
+ doc_token: Type.String({ description: "Document token (extract from URL /docx/XXX)" }),
7
+ }),
8
+ Type.Object({
9
+ action: Type.Literal("write"),
10
+ doc_token: Type.String({ description: "Document token" }),
11
+ content: Type.String({
12
+ description: "Markdown content to write (replaces entire document content)",
13
+ }),
14
+ }),
15
+ Type.Object({
16
+ action: Type.Literal("append"),
17
+ doc_token: Type.String({ description: "Document token" }),
18
+ content: Type.String({ description: "Markdown content to append to end of document" }),
19
+ }),
20
+ Type.Object({
21
+ action: Type.Literal("create"),
22
+ title: Type.String({ description: "Document title" }),
23
+ folder_token: Type.Optional(Type.String({ description: "Target folder token (optional)" })),
24
+ }),
25
+ Type.Object({
26
+ action: Type.Literal("list_blocks"),
27
+ doc_token: Type.String({ description: "Document token" }),
28
+ }),
29
+ Type.Object({
30
+ action: Type.Literal("get_block"),
31
+ doc_token: Type.String({ description: "Document token" }),
32
+ block_id: Type.String({ description: "Block ID (from list_blocks)" }),
33
+ }),
34
+ Type.Object({
35
+ action: Type.Literal("update_block"),
36
+ doc_token: Type.String({ description: "Document token" }),
37
+ block_id: Type.String({ description: "Block ID (from list_blocks)" }),
38
+ content: Type.String({ description: "New text content" }),
39
+ }),
40
+ Type.Object({
41
+ action: Type.Literal("delete_block"),
42
+ doc_token: Type.String({ description: "Document token" }),
43
+ block_id: Type.String({ description: "Block ID" }),
44
+ }),
45
+ ]);
46
+
47
+ export type FeishuDocParams = Static<typeof FeishuDocSchema>;