@keyou007/agent-bot 0.1.15 → 0.1.16-alpha.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,110 @@
1
+ import type { MissingFeishuAppConfiguration } from "./FeishuAppConfiguration.js";
2
+ import { cliLanguage, cliText, type CliLanguage } from "./i18n.js";
3
+
4
+ interface LocalizedFeatureDescription {
5
+ en: string;
6
+ zh: string;
7
+ }
8
+
9
+ export interface FeishuConfigurationFeature {
10
+ item: string;
11
+ feature: string;
12
+ }
13
+
14
+ const FEATURE_DESCRIPTIONS: Readonly<Record<string, LocalizedFeatureDescription>> = {
15
+ "application:application:self_manage": {
16
+ en: "allowing Agent Bot to inspect and complete this Lark app's configuration during initialization",
17
+ zh: "允许 Agent Bot 在初始化时检查并补全当前飞书应用配置",
18
+ },
19
+ "im:chat:create": {
20
+ en: "creating Lark groups with /newgroup and /forkgroup",
21
+ zh: "使用 /newgroup 和 /forkgroup 创建飞书群",
22
+ },
23
+ "im:chat:delete": {
24
+ en: "dissolving task groups with /dismiss",
25
+ zh: "使用 /dismiss 解散任务群",
26
+ },
27
+ "im:chat:read": {
28
+ en: "reading group information and synchronizing task titles after group renames",
29
+ zh: "读取群信息,并在群重命名后同步任务标题",
30
+ },
31
+ "im:message.group_msg": {
32
+ en: "responding to ordinary group messages that do not mention the bot",
33
+ zh: "响应未 @ 机器人的普通群消息",
34
+ },
35
+ "im:message.p2p_msg:readonly": {
36
+ en: "receiving and responding to private messages",
37
+ zh: "接收并响应私聊消息",
38
+ },
39
+ "im:message.reactions:write_only": {
40
+ en: "showing message-processing status with reactions",
41
+ zh: "使用 Reaction 显示消息处理状态",
42
+ },
43
+ "im:message:readonly": {
44
+ en: "reading referenced, forwarded, and image messages",
45
+ zh: "读取引用消息、转发消息和图片消息",
46
+ },
47
+ "im:message:send_as_bot": {
48
+ en: "sending Agent Bot replies, cards, files, and notifications",
49
+ zh: "发送 Agent Bot 回复、卡片、文件和通知",
50
+ },
51
+ "im:message:update": {
52
+ en: "updating sent progress cards",
53
+ zh: "更新已发送的进度卡片",
54
+ },
55
+ "im:resource": {
56
+ en: "uploading and downloading images or files, and setting group avatars",
57
+ zh: "上传和下载图片或文件,以及设置群头像",
58
+ },
59
+ "im.message.receive_v1": {
60
+ en: "receiving private, group, and topic messages",
61
+ zh: "接收私聊、群聊和话题消息",
62
+ },
63
+ "im.chat.updated_v1": {
64
+ en: "detecting group renames and synchronizing task titles",
65
+ zh: "感知群名称变更并同步任务标题",
66
+ },
67
+ "card.action.trigger": {
68
+ en: "using card buttons and interactive actions",
69
+ zh: "使用卡片按钮和交互操作",
70
+ },
71
+ };
72
+
73
+ export function feishuConfigurationFeatures(
74
+ missing: MissingFeishuAppConfiguration,
75
+ language: CliLanguage = cliLanguage,
76
+ ): FeishuConfigurationFeature[] {
77
+ return [...missing.scopes, ...missing.events, ...missing.callbacks].map((item) => ({
78
+ item,
79
+ feature: localizeFeature(item, language),
80
+ }));
81
+ }
82
+
83
+ export function formatFeishuConfigurationFeatureIntroduction(
84
+ missing: MissingFeishuAppConfiguration,
85
+ language: CliLanguage = cliLanguage,
86
+ ): string {
87
+ const features = feishuConfigurationFeatures(missing, language);
88
+ if (features.length === 0) return "";
89
+
90
+ return [
91
+ cliText("What this configuration enables:", "这些配置对应的功能:", language),
92
+ ...features.map(({ item, feature }) => ` ${item}: ${feature}`),
93
+ "",
94
+ ].join("\n");
95
+ }
96
+
97
+ export function feishuAffectedFeatures(
98
+ missing: MissingFeishuAppConfiguration,
99
+ language: CliLanguage = cliLanguage,
100
+ ): string[] {
101
+ return [...new Set(feishuConfigurationFeatures(missing, language).map(({ feature }) => feature))];
102
+ }
103
+
104
+ function localizeFeature(item: string, language: CliLanguage): string {
105
+ const description = FEATURE_DESCRIPTIONS[item];
106
+ if (!description) {
107
+ return cliText("supporting Agent Bot's Lark integration", "支持 Agent Bot 的飞书集成", language);
108
+ }
109
+ return cliText(description.en, description.zh, language);
110
+ }
@@ -0,0 +1,135 @@
1
+ import type { Readable, Writable } from "node:stream";
2
+ import {
3
+ cancel,
4
+ intro,
5
+ isCancel,
6
+ log,
7
+ multiselect,
8
+ note,
9
+ outro,
10
+ select,
11
+ } from "@clack/prompts";
12
+ import { cliText } from "./i18n.js";
13
+
14
+ export interface InitUiOption<Value extends string | number> {
15
+ value: Value;
16
+ label: string;
17
+ hint?: string;
18
+ }
19
+
20
+ export interface InitUiOptions {
21
+ interactive: boolean;
22
+ input?: Readable;
23
+ output?: Writable;
24
+ }
25
+
26
+ export class InitializationPromptCancelledError extends Error {
27
+ constructor() {
28
+ super(cliText("Initialization was cancelled.", "初始化已取消。"));
29
+ this.name = "InitializationPromptCancelledError";
30
+ }
31
+ }
32
+
33
+ export class InitUi {
34
+ readonly interactive: boolean;
35
+ private readonly input: Readable;
36
+ private readonly output: Writable;
37
+
38
+ constructor(options: InitUiOptions) {
39
+ this.interactive = options.interactive;
40
+ this.input = options.input ?? process.stdin;
41
+ this.output = options.output ?? process.stderr;
42
+ }
43
+
44
+ start(title: string): void {
45
+ if (this.interactive) intro(title, this.commonOptions());
46
+ }
47
+
48
+ finish(message: string): void {
49
+ if (this.interactive) outro(message, this.commonOptions());
50
+ }
51
+
52
+ step(message: string): void {
53
+ if (this.interactive) log.step(message, this.commonOptions());
54
+ }
55
+
56
+ info(message: string): void {
57
+ if (this.interactive) log.info(message, this.commonOptions());
58
+ }
59
+
60
+ success(message: string): void {
61
+ if (this.interactive) log.success(message, this.commonOptions());
62
+ }
63
+
64
+ warn(message: string): void {
65
+ if (this.interactive) log.warn(message, this.commonOptions());
66
+ }
67
+
68
+ note(title: string, message: string): void {
69
+ if (this.interactive) note(message, title, this.commonOptions());
70
+ }
71
+
72
+ async select<Value extends string | number>(options: {
73
+ message: string;
74
+ options: InitUiOption<Value>[];
75
+ initialValue?: Value;
76
+ }): Promise<Value> {
77
+ this.requireInteractive();
78
+ const value = await select<string | number>({
79
+ message: options.message,
80
+ options: promptOptions(options.options),
81
+ ...(options.initialValue !== undefined ? { initialValue: options.initialValue } : {}),
82
+ ...this.commonOptions(),
83
+ });
84
+ return this.requireValue(value) as Value;
85
+ }
86
+
87
+ async multiselect<Value extends string | number>(options: {
88
+ message: string;
89
+ options: InitUiOption<Value>[];
90
+ initialValues?: Value[];
91
+ required?: boolean;
92
+ }): Promise<Value[]> {
93
+ this.requireInteractive();
94
+ const values = await multiselect<string | number>({
95
+ message: options.message,
96
+ options: promptOptions(options.options),
97
+ ...(options.initialValues ? { initialValues: options.initialValues } : {}),
98
+ ...(options.required !== undefined ? { required: options.required } : {}),
99
+ ...this.commonOptions(),
100
+ });
101
+ return this.requireValue(values) as Value[];
102
+ }
103
+
104
+ private commonOptions(): { input: Readable; output: Writable } {
105
+ return { input: this.input, output: this.output };
106
+ }
107
+
108
+ private requireInteractive(): void {
109
+ if (!this.interactive) {
110
+ throw new Error("Interactive initialization is not available in this terminal.");
111
+ }
112
+ }
113
+
114
+ private requireValue<Value>(value: Value | symbol): Value {
115
+ if (!isCancel(value)) return value;
116
+ cancel(cliText("Initialization cancelled.", "初始化已取消。"), this.commonOptions());
117
+ throw new InitializationPromptCancelledError();
118
+ }
119
+ }
120
+
121
+ function promptOptions<Value extends string | number>(
122
+ options: InitUiOption<Value>[],
123
+ ): Array<InitUiOption<string> | InitUiOption<number>> {
124
+ return options.map(({ value, label, hint }) => typeof value === "number"
125
+ ? { value: value as number, label, ...(hint ? { hint } : {}) }
126
+ : { value: value as string, label, ...(hint ? { hint } : {}) });
127
+ }
128
+
129
+ export function shouldUseInteractiveInitialization(
130
+ json: boolean,
131
+ inputIsTty = process.stdin.isTTY === true,
132
+ outputIsTty = process.stderr.isTTY === true,
133
+ ): boolean {
134
+ return !json && inputIsTty && outputIsTty;
135
+ }