xiaozuoassistant 0.2.47 → 0.2.49
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReadLarkDocSkill } from './lark-doc.js';
|
|
1
|
+
import { ReadLarkDocSkill, CreateLarkDocSkill, AppendLarkDocSkill } from './lark-doc.js';
|
|
2
2
|
const plugin = {
|
|
3
3
|
metadata: {
|
|
4
4
|
name: 'lark-skills',
|
|
@@ -8,6 +8,8 @@ const plugin = {
|
|
|
8
8
|
},
|
|
9
9
|
onLoad: (context) => {
|
|
10
10
|
context.registerSkill(new ReadLarkDocSkill());
|
|
11
|
+
context.registerSkill(new CreateLarkDocSkill());
|
|
12
|
+
context.registerSkill(new AppendLarkDocSkill());
|
|
11
13
|
}
|
|
12
14
|
};
|
|
13
15
|
export default plugin;
|
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
import { BaseSkill } from '../../../skills/base-skill.js';
|
|
2
2
|
import * as lark from '@larksuiteoapi/node-sdk';
|
|
3
|
+
// Helper function to resolve document token, especially handling /wiki/ URLs
|
|
4
|
+
async function resolveDocumentToken(client, urlOrToken) {
|
|
5
|
+
let token = urlOrToken;
|
|
6
|
+
let isWiki = false;
|
|
7
|
+
if (urlOrToken.includes('/docx/')) {
|
|
8
|
+
token = urlOrToken.split('/docx/')[1].split(/[?#]/)[0];
|
|
9
|
+
return { token, type: 'docx' };
|
|
10
|
+
}
|
|
11
|
+
else if (urlOrToken.includes('/doc/')) {
|
|
12
|
+
token = urlOrToken.split('/doc/')[1].split(/[?#]/)[0];
|
|
13
|
+
return { token, type: 'doc' };
|
|
14
|
+
}
|
|
15
|
+
else if (urlOrToken.includes('/wiki/')) {
|
|
16
|
+
token = urlOrToken.split('/wiki/')[1].split(/[?#]/)[0];
|
|
17
|
+
isWiki = true;
|
|
18
|
+
}
|
|
19
|
+
else if (urlOrToken.startsWith('wikcn')) {
|
|
20
|
+
isWiki = true;
|
|
21
|
+
}
|
|
22
|
+
if (isWiki) {
|
|
23
|
+
const res = await client.wiki.space.getNode({
|
|
24
|
+
params: { token }
|
|
25
|
+
});
|
|
26
|
+
if (res.code !== 0) {
|
|
27
|
+
throw new Error(`Failed to resolve wiki token. Code: ${res.code}, Msg: ${res.msg}`);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
token: res.data?.node?.obj_token || token,
|
|
31
|
+
type: res.data?.node?.obj_type || 'docx'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Fallback assuming it's a docx token if not wiki
|
|
35
|
+
return { token, type: 'docx' };
|
|
36
|
+
}
|
|
3
37
|
export class ReadLarkDocSkill extends BaseSkill {
|
|
4
38
|
constructor() {
|
|
5
39
|
super(...arguments);
|
|
@@ -26,18 +60,6 @@ export class ReadLarkDocSkill extends BaseSkill {
|
|
|
26
60
|
}
|
|
27
61
|
async execute(args, ctx) {
|
|
28
62
|
try {
|
|
29
|
-
// Extract document token from URL
|
|
30
|
-
// Typical Lark doc URL formats:
|
|
31
|
-
// https://domain.feishu.cn/docx/TOKEN
|
|
32
|
-
// https://domain.feishu.cn/wiki/WIKITOKEN
|
|
33
|
-
let documentToken = args.document_url;
|
|
34
|
-
// Basic extraction logic
|
|
35
|
-
if (args.document_url.includes('/docx/')) {
|
|
36
|
-
documentToken = args.document_url.split('/docx/')[1].split(/[?#]/)[0];
|
|
37
|
-
}
|
|
38
|
-
else if (args.document_url.includes('/doc/')) {
|
|
39
|
-
documentToken = args.document_url.split('/doc/')[1].split(/[?#]/)[0];
|
|
40
|
-
}
|
|
41
63
|
// Fetch config to get app_id and app_secret if not provided
|
|
42
64
|
const configLoader = require('../../../config/loader.js').config;
|
|
43
65
|
let appId = args.app_id;
|
|
@@ -67,6 +89,11 @@ export class ReadLarkDocSkill extends BaseSkill {
|
|
|
67
89
|
appId: appId,
|
|
68
90
|
appSecret: appSecret,
|
|
69
91
|
});
|
|
92
|
+
// Extract and resolve document token from URL
|
|
93
|
+
const { token: documentToken, type: objType } = await resolveDocumentToken(client, args.document_url);
|
|
94
|
+
if (objType !== 'docx' && objType !== 'doc') {
|
|
95
|
+
return { error: `Unsupported document type: ${objType}. Only docx and doc are supported for reading raw text content.` };
|
|
96
|
+
}
|
|
70
97
|
// We use the drive/v1/export API or docx/v1/documents API to read content
|
|
71
98
|
// Let's try the newer DOCX API first to get raw content
|
|
72
99
|
const res = await client.docx.document.rawContent({
|
|
@@ -87,3 +114,162 @@ export class ReadLarkDocSkill extends BaseSkill {
|
|
|
87
114
|
}
|
|
88
115
|
}
|
|
89
116
|
}
|
|
117
|
+
export class CreateLarkDocSkill extends BaseSkill {
|
|
118
|
+
constructor() {
|
|
119
|
+
super(...arguments);
|
|
120
|
+
this.name = 'create_lark_doc';
|
|
121
|
+
this.description = 'Create a new Lark/Feishu document (docx)';
|
|
122
|
+
this.parameters = {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
title: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Title of the new document'
|
|
128
|
+
},
|
|
129
|
+
folder_token: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Optional folder token to create the document in'
|
|
132
|
+
},
|
|
133
|
+
app_id: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: 'The Lark App ID (optional, defaults to configured bot)'
|
|
136
|
+
},
|
|
137
|
+
app_secret: {
|
|
138
|
+
type: 'string',
|
|
139
|
+
description: 'The Lark App Secret (optional)'
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
required: ['title']
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async execute(args, ctx) {
|
|
146
|
+
try {
|
|
147
|
+
const configLoader = require('../../../config/loader.js').config;
|
|
148
|
+
let appId = args.app_id;
|
|
149
|
+
let appSecret = args.app_secret;
|
|
150
|
+
if (!appId || !appSecret) {
|
|
151
|
+
const feishuBots = configLoader.channels?.feishu;
|
|
152
|
+
if (feishuBots && Array.isArray(feishuBots) && feishuBots.length > 0) {
|
|
153
|
+
if (ctx?.metadata?.botName) {
|
|
154
|
+
const specificBot = feishuBots.find((b) => b.name === ctx.metadata.botName);
|
|
155
|
+
if (specificBot) {
|
|
156
|
+
appId = specificBot.appId;
|
|
157
|
+
appSecret = specificBot.appSecret;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!appId || !appSecret) {
|
|
161
|
+
appId = feishuBots[0].appId;
|
|
162
|
+
appSecret = feishuBots[0].appSecret;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return { error: 'Lark App ID and Secret are required.' };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const client = new lark.Client({ appId: appId, appSecret: appSecret });
|
|
170
|
+
const res = await client.docx.document.create({
|
|
171
|
+
data: {
|
|
172
|
+
title: args.title,
|
|
173
|
+
folder_token: args.folder_token || ''
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
if (res.code !== 0) {
|
|
177
|
+
return { error: `Failed to create document. Code: ${res.code}, Msg: ${res.msg}` };
|
|
178
|
+
}
|
|
179
|
+
const docId = res.data?.document?.document_id;
|
|
180
|
+
return {
|
|
181
|
+
success: true,
|
|
182
|
+
document_id: docId,
|
|
183
|
+
url: `https://${client.domain || 'feishu.cn'}/docx/${docId}`
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return { error: `Failed to create document: ${error.message}` };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
export class AppendLarkDocSkill extends BaseSkill {
|
|
192
|
+
constructor() {
|
|
193
|
+
super(...arguments);
|
|
194
|
+
this.name = 'append_lark_doc';
|
|
195
|
+
this.description = 'Append text content to an existing Lark/Feishu document (docx)';
|
|
196
|
+
this.parameters = {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: {
|
|
199
|
+
document_url: {
|
|
200
|
+
type: 'string',
|
|
201
|
+
description: 'The URL or token of the document to append to'
|
|
202
|
+
},
|
|
203
|
+
content: {
|
|
204
|
+
type: 'string',
|
|
205
|
+
description: 'The text content to append'
|
|
206
|
+
},
|
|
207
|
+
app_id: { type: 'string' },
|
|
208
|
+
app_secret: { type: 'string' }
|
|
209
|
+
},
|
|
210
|
+
required: ['document_url', 'content']
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async execute(args, ctx) {
|
|
214
|
+
try {
|
|
215
|
+
const configLoader = require('../../../config/loader.js').config;
|
|
216
|
+
let appId = args.app_id;
|
|
217
|
+
let appSecret = args.app_secret;
|
|
218
|
+
if (!appId || !appSecret) {
|
|
219
|
+
const feishuBots = configLoader.channels?.feishu;
|
|
220
|
+
if (feishuBots && Array.isArray(feishuBots) && feishuBots.length > 0) {
|
|
221
|
+
if (ctx?.metadata?.botName) {
|
|
222
|
+
const specificBot = feishuBots.find((b) => b.name === ctx.metadata.botName);
|
|
223
|
+
if (specificBot) {
|
|
224
|
+
appId = specificBot.appId;
|
|
225
|
+
appSecret = specificBot.appSecret;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!appId || !appSecret) {
|
|
229
|
+
appId = feishuBots[0].appId;
|
|
230
|
+
appSecret = feishuBots[0].appSecret;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return { error: 'Lark App ID and Secret are required.' };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const client = new lark.Client({ appId: appId, appSecret: appSecret });
|
|
238
|
+
const { token: documentToken, type: objType } = await resolveDocumentToken(client, args.document_url);
|
|
239
|
+
if (objType !== 'docx') {
|
|
240
|
+
return { error: `Unsupported document type: ${objType}. Append operation currently only supports docx documents.` };
|
|
241
|
+
}
|
|
242
|
+
// Create blocks from content
|
|
243
|
+
const lines = args.content.split('\n').filter(l => l.trim() !== '');
|
|
244
|
+
const children = lines.map(line => ({
|
|
245
|
+
block_type: 2, // Text block
|
|
246
|
+
text: {
|
|
247
|
+
elements: [
|
|
248
|
+
{
|
|
249
|
+
text_run: { content: line }
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}));
|
|
254
|
+
if (children.length === 0)
|
|
255
|
+
return { success: true, message: 'Nothing to append' };
|
|
256
|
+
const res = await client.docx.documentBlockChildren.create({
|
|
257
|
+
path: {
|
|
258
|
+
document_id: documentToken,
|
|
259
|
+
block_id: documentToken
|
|
260
|
+
},
|
|
261
|
+
data: {
|
|
262
|
+
children: children,
|
|
263
|
+
index: -1
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
if (res.code !== 0) {
|
|
267
|
+
return { error: `Failed to append to document. Code: ${res.code}, Msg: ${res.msg}` };
|
|
268
|
+
}
|
|
269
|
+
return { success: true, message: 'Content appended successfully' };
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
return { error: `Failed to append to document: ${error.message}` };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|