@nextclaw/channel-plugin-feishu 0.2.29-beta.0 → 0.2.29-beta.2

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 (114) hide show
  1. package/dist/index.d.ts +23 -0
  2. package/dist/index.js +45 -0
  3. package/dist/src/accounts.js +141 -0
  4. package/dist/src/app-scope-checker.js +36 -0
  5. package/dist/src/async.js +34 -0
  6. package/dist/src/auth-errors.js +72 -0
  7. package/dist/src/bitable.js +495 -0
  8. package/dist/src/bot.d.ts +35 -0
  9. package/dist/src/bot.js +941 -0
  10. package/dist/src/calendar-calendar.js +54 -0
  11. package/dist/src/calendar-event-attendee.js +98 -0
  12. package/dist/src/calendar-event.js +193 -0
  13. package/dist/src/calendar-freebusy.js +40 -0
  14. package/dist/src/calendar-shared.js +23 -0
  15. package/dist/src/calendar.js +16 -0
  16. package/dist/src/card-action.js +49 -0
  17. package/dist/src/channel.d.ts +7 -0
  18. package/dist/src/channel.js +413 -0
  19. package/dist/src/chat-schema.js +25 -0
  20. package/dist/src/chat.js +87 -0
  21. package/dist/src/client.d.ts +16 -0
  22. package/dist/src/client.js +112 -0
  23. package/dist/src/config-schema.d.ts +357 -0
  24. package/dist/src/dedup.js +126 -0
  25. package/dist/src/device-flow.js +109 -0
  26. package/dist/src/directory.js +101 -0
  27. package/dist/src/doc-schema.js +148 -0
  28. package/dist/src/docx-batch-insert.js +104 -0
  29. package/dist/src/docx-color-text.js +80 -0
  30. package/dist/src/docx-table-ops.js +197 -0
  31. package/dist/src/docx.js +858 -0
  32. package/dist/src/domains.js +14 -0
  33. package/dist/src/drive-schema.js +41 -0
  34. package/dist/src/drive.js +126 -0
  35. package/dist/src/dynamic-agent.js +93 -0
  36. package/dist/src/external-keys.js +13 -0
  37. package/dist/src/feishu-fetch.js +12 -0
  38. package/dist/src/identity.js +92 -0
  39. package/dist/src/lark-ticket.js +11 -0
  40. package/dist/src/media.d.ts +75 -0
  41. package/dist/src/media.js +304 -0
  42. package/dist/src/mention.d.ts +52 -0
  43. package/dist/src/mention.js +82 -0
  44. package/dist/src/monitor.account.d.ts +1 -0
  45. package/dist/src/monitor.account.js +393 -0
  46. package/dist/src/monitor.d.ts +11 -0
  47. package/dist/src/monitor.js +58 -0
  48. package/dist/src/monitor.startup.js +24 -0
  49. package/dist/src/monitor.state.d.ts +1 -0
  50. package/dist/src/monitor.state.js +80 -0
  51. package/dist/src/monitor.transport.js +167 -0
  52. package/dist/src/nextclaw-sdk/account-id.js +15 -0
  53. package/dist/src/nextclaw-sdk/core-channel.js +150 -0
  54. package/dist/src/nextclaw-sdk/core-pairing.js +151 -0
  55. package/dist/src/nextclaw-sdk/dedupe.js +164 -0
  56. package/dist/src/nextclaw-sdk/feishu.d.ts +1 -0
  57. package/dist/src/nextclaw-sdk/feishu.js +14 -0
  58. package/dist/src/nextclaw-sdk/history.js +69 -0
  59. package/dist/src/nextclaw-sdk/network-body.js +180 -0
  60. package/dist/src/nextclaw-sdk/network-fetch.js +63 -0
  61. package/dist/src/nextclaw-sdk/network-webhook.js +126 -0
  62. package/dist/src/nextclaw-sdk/network.js +4 -0
  63. package/dist/src/nextclaw-sdk/runtime-store.js +21 -0
  64. package/dist/src/nextclaw-sdk/secrets-config.js +65 -0
  65. package/dist/src/nextclaw-sdk/secrets-core.d.ts +1 -0
  66. package/dist/src/nextclaw-sdk/secrets-core.js +68 -0
  67. package/dist/src/nextclaw-sdk/secrets-prompt.js +193 -0
  68. package/dist/src/nextclaw-sdk/secrets.d.ts +1 -0
  69. package/dist/src/nextclaw-sdk/secrets.js +4 -0
  70. package/dist/src/nextclaw-sdk/types.d.ts +242 -0
  71. package/dist/src/oauth.js +171 -0
  72. package/dist/src/onboarding.js +381 -0
  73. package/dist/src/outbound.js +150 -0
  74. package/dist/src/perm-schema.js +49 -0
  75. package/dist/src/perm.js +90 -0
  76. package/dist/src/policy.js +61 -0
  77. package/dist/src/post.js +160 -0
  78. package/dist/src/probe.d.ts +11 -0
  79. package/dist/src/probe.js +85 -0
  80. package/dist/src/raw-request.js +24 -0
  81. package/dist/src/reactions.d.ts +67 -0
  82. package/dist/src/reactions.js +91 -0
  83. package/dist/src/reply-dispatcher.js +250 -0
  84. package/dist/src/runtime.js +5 -0
  85. package/dist/src/secret-input.js +3 -0
  86. package/dist/src/send-result.js +12 -0
  87. package/dist/src/send-target.js +22 -0
  88. package/dist/src/send.d.ts +51 -0
  89. package/dist/src/send.js +265 -0
  90. package/dist/src/sheets-shared.js +193 -0
  91. package/dist/src/sheets.js +95 -0
  92. package/dist/src/streaming-card.js +263 -0
  93. package/dist/src/targets.js +39 -0
  94. package/dist/src/task-comment.js +76 -0
  95. package/dist/src/task-shared.js +13 -0
  96. package/dist/src/task-subtask.js +79 -0
  97. package/dist/src/task-task.js +144 -0
  98. package/dist/src/task-tasklist.js +136 -0
  99. package/dist/src/task.js +16 -0
  100. package/dist/src/token-store.js +154 -0
  101. package/dist/src/tool-account.js +65 -0
  102. package/dist/src/tool-result.js +18 -0
  103. package/dist/src/tool-scopes.js +62 -0
  104. package/dist/src/tools-config.js +30 -0
  105. package/dist/src/types.d.ts +43 -0
  106. package/dist/src/typing.js +145 -0
  107. package/dist/src/uat-client.js +102 -0
  108. package/dist/src/user-tool-client.js +132 -0
  109. package/dist/src/user-tool-helpers.js +110 -0
  110. package/dist/src/user-tool-result.js +10 -0
  111. package/dist/src/wiki-schema.js +45 -0
  112. package/dist/src/wiki.js +144 -0
  113. package/package.json +8 -4
  114. package/index.ts +0 -75
@@ -0,0 +1,54 @@
1
+ import { assertLarkOk, createToolContext, handleInvokeError, json, registerTool } from "./user-tool-helpers.js";
2
+ import { Type } from "@sinclair/typebox";
3
+ //#region src/calendar-calendar.ts
4
+ const CalendarCalendarSchema = Type.Union([
5
+ Type.Object({
6
+ action: Type.Literal("list"),
7
+ page_size: Type.Optional(Type.Number()),
8
+ page_token: Type.Optional(Type.String())
9
+ }),
10
+ Type.Object({
11
+ action: Type.Literal("get"),
12
+ calendar_id: Type.String()
13
+ }),
14
+ Type.Object({ action: Type.Literal("primary") })
15
+ ]);
16
+ function registerFeishuCalendarCalendarTool(api) {
17
+ const { toolClient } = createToolContext(api, "feishu_calendar_calendar");
18
+ registerTool(api, {
19
+ name: "feishu_calendar_calendar",
20
+ label: "Feishu Calendar",
21
+ description: "按本人身份查询飞书日历列表、主日历和指定日历详情。",
22
+ parameters: CalendarCalendarSchema,
23
+ async execute(_toolCallId, params) {
24
+ const payload = params;
25
+ try {
26
+ const client = toolClient();
27
+ if (payload.action === "list") {
28
+ const response = await client.invoke("feishu_calendar_calendar.list", (sdk, opts) => sdk.calendar.calendar.list({ params: {
29
+ page_size: payload.page_size,
30
+ page_token: payload.page_token
31
+ } }, opts), { as: "user" });
32
+ assertLarkOk(response);
33
+ return json({
34
+ calendars: response.data?.calendar_list ?? [],
35
+ has_more: response.data?.has_more ?? false,
36
+ page_token: response.data?.page_token
37
+ });
38
+ }
39
+ if (payload.action === "primary") {
40
+ const response = await client.invoke("feishu_calendar_calendar.primary", (sdk, opts) => sdk.calendar.calendar.primary({}, opts), { as: "user" });
41
+ assertLarkOk(response);
42
+ return json({ calendars: response.data?.calendars ?? [] });
43
+ }
44
+ const response = await client.invoke("feishu_calendar_calendar.get", (sdk, opts) => sdk.calendar.calendar.get({ path: { calendar_id: payload.calendar_id } }, opts), { as: "user" });
45
+ assertLarkOk(response);
46
+ return json({ calendar: response.data?.calendar ?? response.data });
47
+ } catch (error) {
48
+ return handleInvokeError(error, api);
49
+ }
50
+ }
51
+ }, { name: "feishu_calendar_calendar" });
52
+ }
53
+ //#endregion
54
+ export { registerFeishuCalendarCalendarTool };
@@ -0,0 +1,98 @@
1
+ import { StringEnum, assertLarkOk, createToolContext, handleInvokeError, json, registerTool } from "./user-tool-helpers.js";
2
+ import { Type } from "@sinclair/typebox";
3
+ //#region src/calendar-event-attendee.ts
4
+ const CalendarAttendeeSchema = Type.Union([Type.Object({
5
+ action: Type.Literal("create"),
6
+ calendar_id: Type.String(),
7
+ event_id: Type.String(),
8
+ attendees: Type.Array(Type.Object({
9
+ type: StringEnum([
10
+ "user",
11
+ "chat",
12
+ "resource",
13
+ "third_party"
14
+ ]),
15
+ attendee_id: Type.String()
16
+ })),
17
+ need_notification: Type.Optional(Type.Boolean())
18
+ }), Type.Object({
19
+ action: Type.Literal("list"),
20
+ calendar_id: Type.String(),
21
+ event_id: Type.String(),
22
+ page_size: Type.Optional(Type.Number()),
23
+ page_token: Type.Optional(Type.String()),
24
+ user_id_type: Type.Optional(StringEnum([
25
+ "open_id",
26
+ "union_id",
27
+ "user_id"
28
+ ]))
29
+ })]);
30
+ function registerFeishuCalendarEventAttendeeTool(api) {
31
+ const { toolClient } = createToolContext(api, "feishu_calendar_event_attendee");
32
+ registerTool(api, {
33
+ name: "feishu_calendar_event_attendee",
34
+ label: "Feishu Calendar Event Attendee",
35
+ description: "按本人身份添加日程参会人或查看参会人列表。",
36
+ parameters: CalendarAttendeeSchema,
37
+ async execute(_toolCallId, params) {
38
+ const payload = params;
39
+ try {
40
+ const client = toolClient();
41
+ if (payload.action === "create") {
42
+ const attendeePayload = (payload.attendees ?? []).map((attendee) => {
43
+ if (attendee.type === "user") return {
44
+ type: attendee.type,
45
+ user_id: attendee.attendee_id
46
+ };
47
+ if (attendee.type === "chat") return {
48
+ type: attendee.type,
49
+ chat_id: attendee.attendee_id
50
+ };
51
+ if (attendee.type === "resource") return {
52
+ type: attendee.type,
53
+ room_id: attendee.attendee_id
54
+ };
55
+ return {
56
+ type: attendee.type,
57
+ third_party_email: attendee.attendee_id
58
+ };
59
+ });
60
+ const response = await client.invoke("feishu_calendar_event_attendee.create", (sdk, opts) => sdk.calendar.calendarEventAttendee.create({
61
+ path: {
62
+ calendar_id: payload.calendar_id,
63
+ event_id: payload.event_id
64
+ },
65
+ params: { user_id_type: "open_id" },
66
+ data: {
67
+ attendees: attendeePayload,
68
+ need_notification: payload.need_notification ?? true
69
+ }
70
+ }, opts), { as: "user" });
71
+ assertLarkOk(response);
72
+ return json({ attendees: response.data?.attendees ?? [] });
73
+ }
74
+ const response = await client.invoke("feishu_calendar_event_attendee.list", (sdk, opts) => sdk.calendar.calendarEventAttendee.list({
75
+ path: {
76
+ calendar_id: payload.calendar_id,
77
+ event_id: payload.event_id
78
+ },
79
+ params: {
80
+ page_size: payload.page_size,
81
+ page_token: payload.page_token,
82
+ user_id_type: payload.user_id_type ?? "open_id"
83
+ }
84
+ }, opts), { as: "user" });
85
+ assertLarkOk(response);
86
+ return json({
87
+ attendees: response.data?.items ?? [],
88
+ has_more: response.data?.has_more ?? false,
89
+ page_token: response.data?.page_token
90
+ });
91
+ } catch (error) {
92
+ return handleInvokeError(error, api);
93
+ }
94
+ }
95
+ }, { name: "feishu_calendar_event_attendee" });
96
+ }
97
+ //#endregion
98
+ export { registerFeishuCalendarEventAttendeeTool };
@@ -0,0 +1,193 @@
1
+ import { StringEnum, assertLarkOk, createToolContext, handleInvokeError, json, parseTimeToTimestamp, registerTool } from "./user-tool-helpers.js";
2
+ import { normalizeEventTimes, resolveCalendarId } from "./calendar-shared.js";
3
+ import { Type } from "@sinclair/typebox";
4
+ //#region src/calendar-event.ts
5
+ const CalendarEventSchema = Type.Union([
6
+ Type.Object({
7
+ action: Type.Literal("create"),
8
+ start_time: Type.String(),
9
+ end_time: Type.String(),
10
+ summary: Type.Optional(Type.String()),
11
+ calendar_id: Type.Optional(Type.String()),
12
+ description: Type.Optional(Type.String()),
13
+ attendees: Type.Optional(Type.Array(Type.Object({
14
+ type: StringEnum([
15
+ "user",
16
+ "chat",
17
+ "resource",
18
+ "third_party"
19
+ ]),
20
+ id: Type.String()
21
+ }))),
22
+ user_open_id: Type.Optional(Type.String()),
23
+ need_notification: Type.Optional(Type.Boolean()),
24
+ location: Type.Optional(Type.String())
25
+ }),
26
+ Type.Object({
27
+ action: Type.Literal("list"),
28
+ start_time: Type.String(),
29
+ end_time: Type.String(),
30
+ calendar_id: Type.Optional(Type.String()),
31
+ page_size: Type.Optional(Type.Number()),
32
+ page_token: Type.Optional(Type.String())
33
+ }),
34
+ Type.Object({
35
+ action: Type.Literal("get"),
36
+ event_id: Type.String(),
37
+ calendar_id: Type.Optional(Type.String())
38
+ }),
39
+ Type.Object({
40
+ action: Type.Literal("patch"),
41
+ event_id: Type.String(),
42
+ calendar_id: Type.Optional(Type.String()),
43
+ summary: Type.Optional(Type.String()),
44
+ description: Type.Optional(Type.String()),
45
+ start_time: Type.Optional(Type.String()),
46
+ end_time: Type.Optional(Type.String()),
47
+ location: Type.Optional(Type.String())
48
+ }),
49
+ Type.Object({
50
+ action: Type.Literal("delete"),
51
+ event_id: Type.String(),
52
+ calendar_id: Type.Optional(Type.String()),
53
+ need_notification: Type.Optional(Type.Boolean())
54
+ })
55
+ ]);
56
+ function buildAttendees(payload) {
57
+ return [...payload.user_open_id ? [{
58
+ type: "user",
59
+ id: payload.user_open_id
60
+ }] : [], ...payload.attendees ?? []].map((attendee) => {
61
+ if (attendee.type === "user") return {
62
+ type: attendee.type,
63
+ user_id: attendee.id
64
+ };
65
+ if (attendee.type === "chat") return {
66
+ type: attendee.type,
67
+ chat_id: attendee.id
68
+ };
69
+ if (attendee.type === "resource") return {
70
+ type: attendee.type,
71
+ room_id: attendee.id
72
+ };
73
+ return {
74
+ type: attendee.type,
75
+ third_party_email: attendee.id
76
+ };
77
+ });
78
+ }
79
+ function registerFeishuCalendarEventTool(api) {
80
+ const { toolClient } = createToolContext(api, "feishu_calendar_event");
81
+ registerTool(api, {
82
+ name: "feishu_calendar_event",
83
+ label: "Feishu Calendar Event",
84
+ description: "按本人身份创建、查询、修改、删除飞书日程。",
85
+ parameters: CalendarEventSchema,
86
+ async execute(_toolCallId, params) {
87
+ const payload = params;
88
+ try {
89
+ const client = toolClient();
90
+ const calendarId = await resolveCalendarId(client, payload.calendar_id);
91
+ if (payload.action === "create") {
92
+ const startTs = payload.start_time ? parseTimeToTimestamp(payload.start_time) : null;
93
+ const endTs = payload.end_time ? parseTimeToTimestamp(payload.end_time) : null;
94
+ if (!startTs || !endTs) return json({ error: "start_time 和 end_time 必须为带时区的 ISO 8601 / RFC 3339 时间。" });
95
+ const response = await client.invoke("feishu_calendar_event.create", (sdk, opts) => sdk.calendar.calendarEvent.create({
96
+ path: { calendar_id: calendarId },
97
+ data: {
98
+ summary: payload.summary,
99
+ description: payload.description,
100
+ start_time: { timestamp: startTs },
101
+ end_time: { timestamp: endTs },
102
+ ...payload.location ? { location: { name: payload.location } } : {}
103
+ }
104
+ }, opts), { as: "user" });
105
+ assertLarkOk(response);
106
+ const event = response.data?.event;
107
+ const attendeePayload = buildAttendees(payload);
108
+ if (event?.event_id && attendeePayload.length > 0) await client.invoke("feishu_calendar_event.create", (sdk, opts) => sdk.calendar.calendarEventAttendee.create({
109
+ path: {
110
+ calendar_id: calendarId,
111
+ event_id: event.event_id
112
+ },
113
+ params: { user_id_type: "open_id" },
114
+ data: {
115
+ attendees: attendeePayload,
116
+ need_notification: payload.need_notification ?? true
117
+ }
118
+ }, opts), { as: "user" });
119
+ return json({ event: normalizeEventTimes(response.data?.event) });
120
+ }
121
+ if (payload.action === "list") {
122
+ const startTs = payload.start_time ? parseTimeToTimestamp(payload.start_time) : null;
123
+ const endTs = payload.end_time ? parseTimeToTimestamp(payload.end_time) : null;
124
+ if (!startTs || !endTs) return json({ error: "start_time 和 end_time 必须为带时区的 ISO 8601 / RFC 3339 时间。" });
125
+ const response = await client.invoke("feishu_calendar_event.instance_view", (sdk, opts) => sdk.calendar.calendarEvent.instanceView({
126
+ path: { calendar_id: calendarId },
127
+ params: {
128
+ start_time: startTs,
129
+ end_time: endTs,
130
+ page_size: payload.page_size,
131
+ page_token: payload.page_token,
132
+ user_id_type: "open_id"
133
+ }
134
+ }, opts), { as: "user" });
135
+ assertLarkOk(response);
136
+ return json({
137
+ events: (response.data?.items ?? []).map(normalizeEventTimes),
138
+ has_more: response.data?.has_more ?? false,
139
+ page_token: response.data?.page_token
140
+ });
141
+ }
142
+ if (payload.action === "get") {
143
+ const response = await client.invoke("feishu_calendar_event.get", (sdk, opts) => sdk.calendar.calendarEvent.get({ path: {
144
+ calendar_id: calendarId,
145
+ event_id: payload.event_id
146
+ } }, opts), { as: "user" });
147
+ assertLarkOk(response);
148
+ return json({ event: normalizeEventTimes(response.data?.event) });
149
+ }
150
+ if (payload.action === "patch") {
151
+ const updateData = {};
152
+ if (payload.summary) updateData.summary = payload.summary;
153
+ if (payload.description) updateData.description = payload.description;
154
+ if (payload.location) updateData.location = { name: payload.location };
155
+ if (payload.start_time) {
156
+ const startTs = parseTimeToTimestamp(payload.start_time);
157
+ if (!startTs) return json({ error: "start_time 必须为带时区的 ISO 8601 / RFC 3339 时间。" });
158
+ updateData.start_time = { timestamp: startTs };
159
+ }
160
+ if (payload.end_time) {
161
+ const endTs = parseTimeToTimestamp(payload.end_time);
162
+ if (!endTs) return json({ error: "end_time 必须为带时区的 ISO 8601 / RFC 3339 时间。" });
163
+ updateData.end_time = { timestamp: endTs };
164
+ }
165
+ const response = await client.invoke("feishu_calendar_event.patch", (sdk, opts) => sdk.calendar.calendarEvent.patch({
166
+ path: {
167
+ calendar_id: calendarId,
168
+ event_id: payload.event_id
169
+ },
170
+ data: updateData
171
+ }, opts), { as: "user" });
172
+ assertLarkOk(response);
173
+ return json({ event: normalizeEventTimes(response.data?.event) });
174
+ }
175
+ assertLarkOk(await client.invoke("feishu_calendar_event.delete", (sdk, opts) => sdk.calendar.calendarEvent.delete({
176
+ path: {
177
+ calendar_id: calendarId,
178
+ event_id: payload.event_id
179
+ },
180
+ params: { need_notification: payload.need_notification ?? true }
181
+ }, opts), { as: "user" }));
182
+ return json({
183
+ success: true,
184
+ event_id: payload.event_id
185
+ });
186
+ } catch (error) {
187
+ return handleInvokeError(error, api);
188
+ }
189
+ }
190
+ }, { name: "feishu_calendar_event" });
191
+ }
192
+ //#endregion
193
+ export { registerFeishuCalendarEventTool };
@@ -0,0 +1,40 @@
1
+ import { assertLarkOk, createToolContext, handleInvokeError, json, parseTimeToRFC3339, registerTool } from "./user-tool-helpers.js";
2
+ import { Type } from "@sinclair/typebox";
3
+ //#region src/calendar-freebusy.ts
4
+ const CalendarFreebusySchema = Type.Object({
5
+ action: Type.Literal("list"),
6
+ user_ids: Type.Array(Type.String()),
7
+ time_min: Type.String(),
8
+ time_max: Type.String()
9
+ });
10
+ function registerFeishuCalendarFreebusyTool(api) {
11
+ const { toolClient } = createToolContext(api, "feishu_calendar_freebusy");
12
+ registerTool(api, {
13
+ name: "feishu_calendar_freebusy",
14
+ label: "Feishu Calendar Freebusy",
15
+ description: "按本人身份查询 1-10 位用户在一段时间内的忙闲状态。",
16
+ parameters: CalendarFreebusySchema,
17
+ async execute(_toolCallId, params) {
18
+ const payload = params;
19
+ try {
20
+ if (!payload.user_ids?.length || payload.user_ids.length > 10) return json({ error: "user_ids 必须是 1-10 个用户 open_id。" });
21
+ const timeMin = parseTimeToRFC3339(payload.time_min);
22
+ const timeMax = parseTimeToRFC3339(payload.time_max);
23
+ if (!timeMin || !timeMax) return json({ error: "time_min 和 time_max 必须是带时区的 RFC 3339 时间。" });
24
+ const response = await toolClient().invoke("feishu_calendar_freebusy.list", (sdk, opts) => sdk.calendar.freebusy.batch({ data: {
25
+ time_min: timeMin,
26
+ time_max: timeMax,
27
+ user_ids: payload.user_ids,
28
+ include_external_calendar: true,
29
+ only_busy: true
30
+ } }, opts), { as: "user" });
31
+ assertLarkOk(response);
32
+ return json({ freebusy_lists: response.data?.freebusy_lists ?? [] });
33
+ } catch (error) {
34
+ return handleInvokeError(error, api);
35
+ }
36
+ }
37
+ }, { name: "feishu_calendar_freebusy" });
38
+ }
39
+ //#endregion
40
+ export { registerFeishuCalendarFreebusyTool };
@@ -0,0 +1,23 @@
1
+ import { assertLarkOk, unixTimestampToISO8601 } from "./user-tool-helpers.js";
2
+ //#region src/calendar-shared.ts
3
+ function normalizeEventTimes(event) {
4
+ if (!event) return event;
5
+ const typed = event;
6
+ const start = typed.start_time;
7
+ const end = typed.end_time;
8
+ return {
9
+ ...typed,
10
+ start_time_iso8601: unixTimestampToISO8601(start?.timestamp),
11
+ end_time_iso8601: unixTimestampToISO8601(end?.timestamp)
12
+ };
13
+ }
14
+ async function resolveCalendarId(client, calendarId) {
15
+ if (calendarId) return calendarId;
16
+ const response = await client.invoke("feishu_calendar_calendar.primary", (sdk, opts) => sdk.calendar.calendar.primary({}, opts), { as: "user" });
17
+ assertLarkOk(response);
18
+ const primaryId = (response.data?.calendars)?.[0]?.calendar_id;
19
+ if (!primaryId) throw new Error("No primary calendar found for current user.");
20
+ return primaryId;
21
+ }
22
+ //#endregion
23
+ export { normalizeEventTimes, resolveCalendarId };
@@ -0,0 +1,16 @@
1
+ import { registerFeishuCalendarCalendarTool } from "./calendar-calendar.js";
2
+ import { registerFeishuCalendarEventTool } from "./calendar-event.js";
3
+ import { registerFeishuCalendarEventAttendeeTool } from "./calendar-event-attendee.js";
4
+ import { registerFeishuCalendarFreebusyTool } from "./calendar-freebusy.js";
5
+ import { resolveRegisteredFeishuToolsConfig } from "./tool-account.js";
6
+ //#region src/calendar.ts
7
+ function registerFeishuCalendarTools(api) {
8
+ if (!api.config) return;
9
+ if (!resolveRegisteredFeishuToolsConfig(api.config).calendar) return;
10
+ registerFeishuCalendarCalendarTool(api);
11
+ registerFeishuCalendarEventTool(api);
12
+ registerFeishuCalendarEventAttendeeTool(api);
13
+ registerFeishuCalendarFreebusyTool(api);
14
+ }
15
+ //#endregion
16
+ export { registerFeishuCalendarTools };
@@ -0,0 +1,49 @@
1
+ import { resolveFeishuAccount } from "./accounts.js";
2
+ import { withTicket } from "./lark-ticket.js";
3
+ import { handleFeishuMessage } from "./bot.js";
4
+ //#region src/card-action.ts
5
+ async function handleFeishuCardAction(params) {
6
+ const { cfg, event, runtime, accountId } = params;
7
+ const account = resolveFeishuAccount({
8
+ cfg,
9
+ accountId
10
+ });
11
+ const log = runtime?.log ?? console.log;
12
+ const actionValue = event.action.value;
13
+ let content = "";
14
+ if (typeof actionValue === "object" && actionValue !== null) if ("text" in actionValue && typeof actionValue.text === "string") content = actionValue.text;
15
+ else if ("command" in actionValue && typeof actionValue.command === "string") content = actionValue.command;
16
+ else content = JSON.stringify(actionValue);
17
+ else content = String(actionValue);
18
+ const messageEvent = {
19
+ sender: { sender_id: {
20
+ open_id: event.operator.open_id,
21
+ user_id: event.operator.user_id,
22
+ union_id: event.operator.union_id
23
+ } },
24
+ message: {
25
+ message_id: `card-action-${event.token}`,
26
+ chat_id: event.context.chat_id || event.operator.open_id,
27
+ chat_type: event.context.chat_id ? "group" : "p2p",
28
+ message_type: "text",
29
+ content: JSON.stringify({ text: content })
30
+ }
31
+ };
32
+ log(`feishu[${account.accountId}]: handling card action from ${event.operator.open_id}: ${content}`);
33
+ await withTicket({
34
+ accountId: account.accountId,
35
+ messageId: messageEvent.message.message_id,
36
+ chatId: messageEvent.message.chat_id,
37
+ senderOpenId: event.operator.open_id,
38
+ chatType: messageEvent.message.chat_type,
39
+ startTime: Date.now()
40
+ }, () => handleFeishuMessage({
41
+ cfg,
42
+ event: messageEvent,
43
+ botOpenId: params.botOpenId,
44
+ runtime,
45
+ accountId
46
+ }));
47
+ }
48
+ //#endregion
49
+ export { handleFeishuCardAction };
@@ -0,0 +1,7 @@
1
+ import { ChannelPlugin } from "./nextclaw-sdk/types.js";
2
+ import { ResolvedFeishuAccount } from "./types.js";
3
+
4
+ //#region src/channel.d.ts
5
+ declare const feishuPlugin: ChannelPlugin<ResolvedFeishuAccount>;
6
+ //#endregion
7
+ export { feishuPlugin };