@keyou007/agent-bot 0.1.15-alpha.1 → 0.1.15-alpha.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/CHANGELOG.md +4 -0
- package/dist/feishu/CardRenderer.js +63 -8
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/feishu/FeishuConnector.js +4 -1
- package/dist/feishu/FeishuConnector.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +79 -5
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/feishu/CardRenderer.ts +75 -8
- package/src/feishu/FeishuConnector.ts +4 -1
- package/src/proxy/ProxySessionController.ts +85 -5
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyou007/agent-bot",
|
|
3
|
-
"version": "0.1.15-alpha.
|
|
3
|
+
"version": "0.1.15-alpha.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@keyou007/agent-bot",
|
|
9
|
-
"version": "0.1.15-alpha.
|
|
9
|
+
"version": "0.1.15-alpha.2",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@agentclientprotocol/sdk": "1.2.1",
|
package/package.json
CHANGED
|
@@ -205,6 +205,13 @@ export interface DirectoryBrowserCardView {
|
|
|
205
205
|
footerLines: string[];
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
export interface DirectoryNewFolderCardView {
|
|
209
|
+
directory: string;
|
|
210
|
+
displayDirectory?: string;
|
|
211
|
+
contextKey: string;
|
|
212
|
+
page: number;
|
|
213
|
+
}
|
|
214
|
+
|
|
208
215
|
const DIRECTORY_BROWSER_ROW_COUNT = 16;
|
|
209
216
|
|
|
210
217
|
export type ThinkingCardLayout = "grouped" | "timeline";
|
|
@@ -1213,7 +1220,7 @@ export class CardRenderer {
|
|
|
1213
1220
|
renderDirectoryBrowserCard(view: DirectoryBrowserCardView): Record<string, unknown> {
|
|
1214
1221
|
const elements: Record<string, unknown>[] = [
|
|
1215
1222
|
markdown(`**当前目录**:${inlineCode(view.directory)}`),
|
|
1216
|
-
taskActionRow(view.currentActions),
|
|
1223
|
+
taskActionRow(view.currentActions, undefined, true),
|
|
1217
1224
|
{ tag: "hr" },
|
|
1218
1225
|
];
|
|
1219
1226
|
const entryRows = view.entries.length === 0
|
|
@@ -1230,6 +1237,54 @@ export class CardRenderer {
|
|
|
1230
1237
|
return sectionCard("文件浏览", elements, "blue", "2px");
|
|
1231
1238
|
}
|
|
1232
1239
|
|
|
1240
|
+
renderDirectoryNewFolderCard(view: DirectoryNewFolderCardView): Record<string, unknown> {
|
|
1241
|
+
const actionValue = {
|
|
1242
|
+
action: "directory_new_folder_submit",
|
|
1243
|
+
directory: view.directory,
|
|
1244
|
+
contextKey: view.contextKey,
|
|
1245
|
+
page: String(view.page),
|
|
1246
|
+
};
|
|
1247
|
+
return compactCard("新建目录", "blue", [
|
|
1248
|
+
markdown(`将在当前目录下创建一个子目录:\n${inlineCode(view.displayDirectory ?? view.directory)}`),
|
|
1249
|
+
{
|
|
1250
|
+
tag: "form",
|
|
1251
|
+
name: "directory_new_folder_form",
|
|
1252
|
+
vertical_spacing: "8px",
|
|
1253
|
+
elements: [
|
|
1254
|
+
{
|
|
1255
|
+
tag: "input",
|
|
1256
|
+
element_id: "folder_name_input",
|
|
1257
|
+
name: "folderName",
|
|
1258
|
+
required: true,
|
|
1259
|
+
input_type: "text",
|
|
1260
|
+
width: "fill",
|
|
1261
|
+
max_length: 255,
|
|
1262
|
+
label: { tag: "plain_text", content: "目录名" },
|
|
1263
|
+
placeholder: { tag: "plain_text", content: "请输入目录名" },
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
tag: "button",
|
|
1267
|
+
name: "directory_new_folder_create",
|
|
1268
|
+
text: { tag: "plain_text", content: "Create" },
|
|
1269
|
+
type: "primary",
|
|
1270
|
+
width: "fill",
|
|
1271
|
+
action_type: "form_submit",
|
|
1272
|
+
value: actionValue,
|
|
1273
|
+
},
|
|
1274
|
+
],
|
|
1275
|
+
},
|
|
1276
|
+
taskActionRow([{
|
|
1277
|
+
text: "Back",
|
|
1278
|
+
value: {
|
|
1279
|
+
action: "directory_new_folder_cancel",
|
|
1280
|
+
directory: view.directory,
|
|
1281
|
+
contextKey: view.contextKey,
|
|
1282
|
+
page: String(view.page),
|
|
1283
|
+
},
|
|
1284
|
+
}]),
|
|
1285
|
+
]);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1233
1288
|
renderResetHistoryCard(view: ResetHistoryCardView): Record<string, unknown> {
|
|
1234
1289
|
const elements: Record<string, unknown>[] = [
|
|
1235
1290
|
{
|
|
@@ -2481,13 +2536,25 @@ function resetHistoryEntryRow(
|
|
|
2481
2536
|
};
|
|
2482
2537
|
}
|
|
2483
2538
|
|
|
2484
|
-
function taskActionRow(
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2539
|
+
function taskActionRow(
|
|
2540
|
+
actions: TaskListCardAction[],
|
|
2541
|
+
trailingText?: string,
|
|
2542
|
+
dotSeparated = false,
|
|
2543
|
+
): Record<string, unknown> {
|
|
2544
|
+
const columns = actions.flatMap((action, index) => [
|
|
2545
|
+
...(dotSeparated && index > 0 ? [{
|
|
2546
|
+
tag: "column",
|
|
2547
|
+
width: "auto",
|
|
2548
|
+
vertical_align: "center",
|
|
2549
|
+
elements: [markdown("<font color='grey'>·</font>")],
|
|
2550
|
+
}] : []),
|
|
2551
|
+
{
|
|
2552
|
+
tag: "column",
|
|
2553
|
+
width: "auto",
|
|
2554
|
+
vertical_align: "center",
|
|
2555
|
+
elements: [taskActionElement(action)],
|
|
2556
|
+
},
|
|
2557
|
+
]);
|
|
2491
2558
|
if (trailingText) {
|
|
2492
2559
|
columns.push({
|
|
2493
2560
|
tag: "column",
|
|
@@ -327,7 +327,10 @@ function getCardActionValue(action: Record<string, unknown>): Record<string, unk
|
|
|
327
327
|
const option = parseJsonObject(action.option);
|
|
328
328
|
if (Object.keys(option).length > 0) return option;
|
|
329
329
|
}
|
|
330
|
-
|
|
330
|
+
const value = isRecord(action.value) ? action.value : {};
|
|
331
|
+
return isRecord(action.form_value)
|
|
332
|
+
? { ...value, formValue: action.form_value }
|
|
333
|
+
: value;
|
|
331
334
|
}
|
|
332
335
|
|
|
333
336
|
function getEventId(data: unknown): string | undefined {
|
|
@@ -821,6 +821,30 @@ export class ProxySessionController {
|
|
|
821
821
|
const filePath = directoryFileActionPath(scopedAction.value.filePath);
|
|
822
822
|
await this.assertSendableFile(filePath);
|
|
823
823
|
await this.outbound.sendFile(contextKey, filePath);
|
|
824
|
+
} else if (kind === "directory_new_folder_prompt") {
|
|
825
|
+
const directory = directoryActionPath(scopedAction.value.directory);
|
|
826
|
+
await this.assertBrowsableDirectory(directory);
|
|
827
|
+
await this.outbound.updateInteractiveCard(
|
|
828
|
+
contextKey,
|
|
829
|
+
requiredCardMessageId(scopedAction.messageId),
|
|
830
|
+
this.cardRenderer.renderDirectoryNewFolderCard({
|
|
831
|
+
directory,
|
|
832
|
+
displayDirectory: abbreviateHomeDirectory(directory),
|
|
833
|
+
contextKey,
|
|
834
|
+
page: directoryPageValue(scopedAction.value.page),
|
|
835
|
+
}),
|
|
836
|
+
);
|
|
837
|
+
} else if (kind === "directory_new_folder_submit") {
|
|
838
|
+
await this.createDirectoryFromCard(contextKey, scopedAction);
|
|
839
|
+
} else if (kind === "directory_new_folder_cancel") {
|
|
840
|
+
await this.openDirectoryBrowser(
|
|
841
|
+
contextKey,
|
|
842
|
+
directoryActionPath(scopedAction.value.directory),
|
|
843
|
+
{
|
|
844
|
+
updateMessageId: requiredCardMessageId(scopedAction.messageId),
|
|
845
|
+
page: directoryPageValue(scopedAction.value.page),
|
|
846
|
+
},
|
|
847
|
+
);
|
|
824
848
|
} else if (kind === "directory_new" || kind === "directory_new_group") {
|
|
825
849
|
const directory = directoryActionPath(scopedAction.value.directory);
|
|
826
850
|
await this.assertBrowsableDirectory(directory);
|
|
@@ -4842,12 +4866,12 @@ export class ProxySessionController {
|
|
|
4842
4866
|
const card = this.cardRenderer.renderDirectoryBrowserCard({
|
|
4843
4867
|
directory: abbreviateHomeDirectory(directory),
|
|
4844
4868
|
entries: visibleEntries,
|
|
4845
|
-
currentActions: directoryCreationActions(directory, contextKey),
|
|
4869
|
+
currentActions: directoryCreationActions(directory, contextKey, page),
|
|
4846
4870
|
navigationActions,
|
|
4847
4871
|
footerLines: [
|
|
4848
4872
|
`第 ${page + 1}/${totalPages} 页 · ${directoryCount} 个目录 · ${entries.length - directoryCount} 个文件`,
|
|
4849
4873
|
"",
|
|
4850
|
-
">
|
|
4874
|
+
"> 点击目录名称进入,点击文件名称发送到当前会话;卡片顶部可新建目录、任务或群聊。",
|
|
4851
4875
|
],
|
|
4852
4876
|
});
|
|
4853
4877
|
if (options.updateMessageId) {
|
|
@@ -4913,6 +4937,27 @@ export class ProxySessionController {
|
|
|
4913
4937
|
if (!stats.isDirectory()) throw new Error(`这不是目录:${directory}`);
|
|
4914
4938
|
}
|
|
4915
4939
|
|
|
4940
|
+
private async createDirectoryFromCard(contextKey: string, action: CardAction): Promise<void> {
|
|
4941
|
+
const directory = directoryActionPath(action.value.directory);
|
|
4942
|
+
await this.assertBrowsableDirectory(directory);
|
|
4943
|
+
const folderName = directoryFolderName(cardFormValue(action.value, "folderName"));
|
|
4944
|
+
const newDirectory = path.join(directory, folderName);
|
|
4945
|
+
try {
|
|
4946
|
+
await fs.mkdir(newDirectory);
|
|
4947
|
+
} catch (error) {
|
|
4948
|
+
const code = typeof error === "object" && error !== null && "code" in error
|
|
4949
|
+
? String(error.code)
|
|
4950
|
+
: undefined;
|
|
4951
|
+
if (code === "EEXIST") throw new Error(`目录已存在:${newDirectory}`);
|
|
4952
|
+
throw new Error(`无法创建目录 ${newDirectory}:${runtimeErrorMessage(error)}`);
|
|
4953
|
+
}
|
|
4954
|
+
await this.openDirectoryBrowser(contextKey, directory, {
|
|
4955
|
+
updateMessageId: requiredCardMessageId(action.messageId),
|
|
4956
|
+
page: directoryPageValue(action.value.page),
|
|
4957
|
+
});
|
|
4958
|
+
await this.outbound.sendText(contextKey, `已创建目录:${newDirectory}`);
|
|
4959
|
+
}
|
|
4960
|
+
|
|
4916
4961
|
private async assertSendableFile(filePath: string): Promise<void> {
|
|
4917
4962
|
let stats;
|
|
4918
4963
|
try {
|
|
@@ -6424,10 +6469,45 @@ function directoryFileActionPath(value: unknown): string {
|
|
|
6424
6469
|
return path.resolve(value);
|
|
6425
6470
|
}
|
|
6426
6471
|
|
|
6427
|
-
function
|
|
6472
|
+
function cardFormValue(value: Record<string, unknown>, name: string): unknown {
|
|
6473
|
+
const formValue = value.formValue;
|
|
6474
|
+
return typeof formValue === "object" && formValue !== null
|
|
6475
|
+
? (formValue as Record<string, unknown>)[name]
|
|
6476
|
+
: undefined;
|
|
6477
|
+
}
|
|
6478
|
+
|
|
6479
|
+
function directoryFolderName(value: unknown): string {
|
|
6480
|
+
if (typeof value !== "string" || !value.trim()) throw new Error("请输入目录名。");
|
|
6481
|
+
const name = value.trim();
|
|
6482
|
+
if (name === "." || name === "..") throw new Error("目录名不能是 . 或 ..。");
|
|
6483
|
+
if (name.length > 255) throw new Error("目录名不能超过 255 个字符。");
|
|
6484
|
+
if (/[<>:"/\\|?*\u0000-\u001F]/u.test(name)) {
|
|
6485
|
+
throw new Error("目录名不能包含路径分隔符或以下字符:< > : \" / \\ | ? *");
|
|
6486
|
+
}
|
|
6487
|
+
if (/[. ]$/u.test(name)) throw new Error("目录名不能以空格或句点结尾。");
|
|
6488
|
+
if (/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/iu.test(name)) {
|
|
6489
|
+
throw new Error("该名称是系统保留名称,请使用其他目录名。");
|
|
6490
|
+
}
|
|
6491
|
+
return name;
|
|
6492
|
+
}
|
|
6493
|
+
|
|
6494
|
+
function directoryCreationActions(
|
|
6495
|
+
directory: string,
|
|
6496
|
+
contextKey: string,
|
|
6497
|
+
page: number,
|
|
6498
|
+
): TaskListCardAction[] {
|
|
6428
6499
|
return [
|
|
6429
6500
|
{
|
|
6430
|
-
text: "
|
|
6501
|
+
text: "NewFolder",
|
|
6502
|
+
value: {
|
|
6503
|
+
action: "directory_new_folder_prompt",
|
|
6504
|
+
directory,
|
|
6505
|
+
contextKey,
|
|
6506
|
+
page: String(page),
|
|
6507
|
+
},
|
|
6508
|
+
},
|
|
6509
|
+
{
|
|
6510
|
+
text: "NewTask",
|
|
6431
6511
|
value: {
|
|
6432
6512
|
action: "directory_new",
|
|
6433
6513
|
directory,
|
|
@@ -6435,7 +6515,7 @@ function directoryCreationActions(directory: string, contextKey: string): TaskLi
|
|
|
6435
6515
|
},
|
|
6436
6516
|
},
|
|
6437
6517
|
{
|
|
6438
|
-
text: "
|
|
6518
|
+
text: "NewGroupTask",
|
|
6439
6519
|
value: {
|
|
6440
6520
|
action: "directory_new_group",
|
|
6441
6521
|
directory,
|