@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.
- package/dist/index.d.ts +23 -0
- package/dist/index.js +45 -0
- package/dist/src/accounts.js +141 -0
- package/dist/src/app-scope-checker.js +36 -0
- package/dist/src/async.js +34 -0
- package/dist/src/auth-errors.js +72 -0
- package/dist/src/bitable.js +495 -0
- package/dist/src/bot.d.ts +35 -0
- package/dist/src/bot.js +941 -0
- package/dist/src/calendar-calendar.js +54 -0
- package/dist/src/calendar-event-attendee.js +98 -0
- package/dist/src/calendar-event.js +193 -0
- package/dist/src/calendar-freebusy.js +40 -0
- package/dist/src/calendar-shared.js +23 -0
- package/dist/src/calendar.js +16 -0
- package/dist/src/card-action.js +49 -0
- package/dist/src/channel.d.ts +7 -0
- package/dist/src/channel.js +413 -0
- package/dist/src/chat-schema.js +25 -0
- package/dist/src/chat.js +87 -0
- package/dist/src/client.d.ts +16 -0
- package/dist/src/client.js +112 -0
- package/dist/src/config-schema.d.ts +357 -0
- package/dist/src/dedup.js +126 -0
- package/dist/src/device-flow.js +109 -0
- package/dist/src/directory.js +101 -0
- package/dist/src/doc-schema.js +148 -0
- package/dist/src/docx-batch-insert.js +104 -0
- package/dist/src/docx-color-text.js +80 -0
- package/dist/src/docx-table-ops.js +197 -0
- package/dist/src/docx.js +858 -0
- package/dist/src/domains.js +14 -0
- package/dist/src/drive-schema.js +41 -0
- package/dist/src/drive.js +126 -0
- package/dist/src/dynamic-agent.js +93 -0
- package/dist/src/external-keys.js +13 -0
- package/dist/src/feishu-fetch.js +12 -0
- package/dist/src/identity.js +92 -0
- package/dist/src/lark-ticket.js +11 -0
- package/dist/src/media.d.ts +75 -0
- package/dist/src/media.js +304 -0
- package/dist/src/mention.d.ts +52 -0
- package/dist/src/mention.js +82 -0
- package/dist/src/monitor.account.d.ts +1 -0
- package/dist/src/monitor.account.js +393 -0
- package/dist/src/monitor.d.ts +11 -0
- package/dist/src/monitor.js +58 -0
- package/dist/src/monitor.startup.js +24 -0
- package/dist/src/monitor.state.d.ts +1 -0
- package/dist/src/monitor.state.js +80 -0
- package/dist/src/monitor.transport.js +167 -0
- package/dist/src/nextclaw-sdk/account-id.js +15 -0
- package/dist/src/nextclaw-sdk/core-channel.js +150 -0
- package/dist/src/nextclaw-sdk/core-pairing.js +151 -0
- package/dist/src/nextclaw-sdk/dedupe.js +164 -0
- package/dist/src/nextclaw-sdk/feishu.d.ts +1 -0
- package/dist/src/nextclaw-sdk/feishu.js +14 -0
- package/dist/src/nextclaw-sdk/history.js +69 -0
- package/dist/src/nextclaw-sdk/network-body.js +180 -0
- package/dist/src/nextclaw-sdk/network-fetch.js +63 -0
- package/dist/src/nextclaw-sdk/network-webhook.js +126 -0
- package/dist/src/nextclaw-sdk/network.js +4 -0
- package/dist/src/nextclaw-sdk/runtime-store.js +21 -0
- package/dist/src/nextclaw-sdk/secrets-config.js +65 -0
- package/dist/src/nextclaw-sdk/secrets-core.d.ts +1 -0
- package/dist/src/nextclaw-sdk/secrets-core.js +68 -0
- package/dist/src/nextclaw-sdk/secrets-prompt.js +193 -0
- package/dist/src/nextclaw-sdk/secrets.d.ts +1 -0
- package/dist/src/nextclaw-sdk/secrets.js +4 -0
- package/dist/src/nextclaw-sdk/types.d.ts +242 -0
- package/dist/src/oauth.js +171 -0
- package/dist/src/onboarding.js +381 -0
- package/dist/src/outbound.js +150 -0
- package/dist/src/perm-schema.js +49 -0
- package/dist/src/perm.js +90 -0
- package/dist/src/policy.js +61 -0
- package/dist/src/post.js +160 -0
- package/dist/src/probe.d.ts +11 -0
- package/dist/src/probe.js +85 -0
- package/dist/src/raw-request.js +24 -0
- package/dist/src/reactions.d.ts +67 -0
- package/dist/src/reactions.js +91 -0
- package/dist/src/reply-dispatcher.js +250 -0
- package/dist/src/runtime.js +5 -0
- package/dist/src/secret-input.js +3 -0
- package/dist/src/send-result.js +12 -0
- package/dist/src/send-target.js +22 -0
- package/dist/src/send.d.ts +51 -0
- package/dist/src/send.js +265 -0
- package/dist/src/sheets-shared.js +193 -0
- package/dist/src/sheets.js +95 -0
- package/dist/src/streaming-card.js +263 -0
- package/dist/src/targets.js +39 -0
- package/dist/src/task-comment.js +76 -0
- package/dist/src/task-shared.js +13 -0
- package/dist/src/task-subtask.js +79 -0
- package/dist/src/task-task.js +144 -0
- package/dist/src/task-tasklist.js +136 -0
- package/dist/src/task.js +16 -0
- package/dist/src/token-store.js +154 -0
- package/dist/src/tool-account.js +65 -0
- package/dist/src/tool-result.js +18 -0
- package/dist/src/tool-scopes.js +62 -0
- package/dist/src/tools-config.js +30 -0
- package/dist/src/types.d.ts +43 -0
- package/dist/src/typing.js +145 -0
- package/dist/src/uat-client.js +102 -0
- package/dist/src/user-tool-client.js +132 -0
- package/dist/src/user-tool-helpers.js +110 -0
- package/dist/src/user-tool-result.js +10 -0
- package/dist/src/wiki-schema.js +45 -0
- package/dist/src/wiki.js +144 -0
- package/package.json +8 -4
- 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 };
|