@neomei/opencode-feishu 0.1.0
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 +67 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/bin/opencode-feishu +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +273 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config.d.ts +48 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +76 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/daemon.d.ts +42 -0
- package/dist/core/daemon.d.ts.map +1 -0
- package/dist/core/daemon.js +134 -0
- package/dist/core/daemon.js.map +1 -0
- package/dist/core/logger.d.ts +10 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +42 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/message-handler.d.ts +13 -0
- package/dist/core/message-handler.d.ts.map +1 -0
- package/dist/core/message-handler.js +120 -0
- package/dist/core/message-handler.js.map +1 -0
- package/dist/core/session-manager.d.ts +34 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +187 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/types.d.ts +87 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/feishu/api.d.ts +23 -0
- package/dist/feishu/api.d.ts.map +1 -0
- package/dist/feishu/api.js +97 -0
- package/dist/feishu/api.js.map +1 -0
- package/dist/feishu/card.d.ts +11 -0
- package/dist/feishu/card.d.ts.map +1 -0
- package/dist/feishu/card.js +62 -0
- package/dist/feishu/card.js.map +1 -0
- package/dist/feishu/event-source.d.ts +19 -0
- package/dist/feishu/event-source.d.ts.map +1 -0
- package/dist/feishu/event-source.js +70 -0
- package/dist/feishu/event-source.js.map +1 -0
- package/dist/feishu/silent-logger.d.ts +16 -0
- package/dist/feishu/silent-logger.d.ts.map +1 -0
- package/dist/feishu/silent-logger.js +16 -0
- package/dist/feishu/silent-logger.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/opencode/client.d.ts +27 -0
- package/dist/opencode/client.d.ts.map +1 -0
- package/dist/opencode/client.js +86 -0
- package/dist/opencode/client.js.map +1 -0
- package/dist/opencode/event-handler.d.ts +26 -0
- package/dist/opencode/event-handler.d.ts.map +1 -0
- package/dist/opencode/event-handler.js +212 -0
- package/dist/opencode/event-handler.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +64 -0
- package/dist/plugin.js.map +1 -0
- package/dist/setup/preflight.d.ts +29 -0
- package/dist/setup/preflight.d.ts.map +1 -0
- package/dist/setup/preflight.js +125 -0
- package/dist/setup/preflight.js.map +1 -0
- package/dist/setup/wizard.d.ts +11 -0
- package/dist/setup/wizard.d.ts.map +1 -0
- package/dist/setup/wizard.js +263 -0
- package/dist/setup/wizard.js.map +1 -0
- package/dist/standalone.d.ts +2 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +116 -0
- package/dist/standalone.js.map +1 -0
- package/dist/types/plugin.d.ts +23 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +2 -0
- package/dist/types/plugin.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface FeishuConfig {
|
|
2
|
+
appId: string;
|
|
3
|
+
/**
|
|
4
|
+
* App secret for obtaining tenant_access_token via the SDK.
|
|
5
|
+
* Can be omitted from the file if FEISHU_APP_SECRET env var is set at runtime.
|
|
6
|
+
*/
|
|
7
|
+
appSecret?: string;
|
|
8
|
+
domain: 'feishu' | 'lark';
|
|
9
|
+
opencodeUrl: string;
|
|
10
|
+
streaming: boolean;
|
|
11
|
+
requireMention: boolean;
|
|
12
|
+
groupPolicy: 'open' | 'allowlist' | 'disabled';
|
|
13
|
+
allowlist?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface FeishuMessage {
|
|
16
|
+
message_id: string;
|
|
17
|
+
root_id?: string;
|
|
18
|
+
parent_id?: string;
|
|
19
|
+
chat_id: string;
|
|
20
|
+
chat_type: 'p2p' | 'group';
|
|
21
|
+
sender: {
|
|
22
|
+
sender_id: {
|
|
23
|
+
union_id: string;
|
|
24
|
+
user_id?: string;
|
|
25
|
+
open_id?: string;
|
|
26
|
+
};
|
|
27
|
+
sender_type: string;
|
|
28
|
+
tenant_key: string;
|
|
29
|
+
};
|
|
30
|
+
content: string;
|
|
31
|
+
message_type: string;
|
|
32
|
+
create_time: string;
|
|
33
|
+
update_time?: string;
|
|
34
|
+
mentions?: Array<{
|
|
35
|
+
key: string;
|
|
36
|
+
id: {
|
|
37
|
+
union_id: string;
|
|
38
|
+
user_id?: string;
|
|
39
|
+
open_id?: string;
|
|
40
|
+
};
|
|
41
|
+
name: string;
|
|
42
|
+
tenant_key: string;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
export interface ToolState {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
status: 'running' | 'completed' | 'error';
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface SessionInfo {
|
|
52
|
+
id: string;
|
|
53
|
+
chatId: string;
|
|
54
|
+
chatType: 'p2p' | 'group';
|
|
55
|
+
status: 'idle' | 'busy';
|
|
56
|
+
currentMessageId?: string;
|
|
57
|
+
currentContent?: string;
|
|
58
|
+
lastUpdateTime?: number;
|
|
59
|
+
tools?: ToolState[];
|
|
60
|
+
retryMessage?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 一张飞书交互卡片的"内容体"。用于 im +messages-send 的 --content 字段,
|
|
64
|
+
* 以及 PATCH /open-apis/im/v1/messages/<id> 里的 content 字段。
|
|
65
|
+
* 外层的 msg_type 不在这里,由发送端单独传。
|
|
66
|
+
*/
|
|
67
|
+
export interface CardContent {
|
|
68
|
+
config?: {
|
|
69
|
+
wide_screen_mode?: boolean;
|
|
70
|
+
};
|
|
71
|
+
header?: {
|
|
72
|
+
title: {
|
|
73
|
+
tag: 'plain_text' | 'lark_md';
|
|
74
|
+
content: string;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
elements: Array<{
|
|
78
|
+
tag: string;
|
|
79
|
+
[key: string]: any;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
82
|
+
export interface FeishuCredentials {
|
|
83
|
+
appId: string;
|
|
84
|
+
appSecret: string;
|
|
85
|
+
tenantKey?: string;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,GAAG,OAAO,CAAC;IAC3B,MAAM,EAAE;QACN,SAAS,EAAE;YACT,QAAQ,EAAE,MAAM,CAAC;YACjB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,EAAE,EAAE;YACF,QAAQ,EAAE,MAAM,CAAC;YACjB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,GAAG,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE;QACP,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;IACF,MAAM,CAAC,EAAE;QACP,KAAK,EAAE;YACL,GAAG,EAAE,YAAY,GAAG,SAAS,CAAC;YAC9B,OAAO,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,mCAAmC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
2
|
+
import type { FeishuConfig, FeishuMessage, CardContent } from '../core/types.js';
|
|
3
|
+
export declare class FeishuAPI {
|
|
4
|
+
private client;
|
|
5
|
+
private appId;
|
|
6
|
+
private appSecret;
|
|
7
|
+
private domain;
|
|
8
|
+
private botOpenId?;
|
|
9
|
+
constructor(config: FeishuConfig);
|
|
10
|
+
initialize(): Promise<void>;
|
|
11
|
+
/** SDK client — exposed so FeishuEventSource can mount WSClient on the same credentials. */
|
|
12
|
+
getClient(): Lark.Client;
|
|
13
|
+
getCredentials(): {
|
|
14
|
+
appId: string;
|
|
15
|
+
appSecret: string;
|
|
16
|
+
domain: Lark.Domain;
|
|
17
|
+
};
|
|
18
|
+
getBotOpenId(): string | undefined;
|
|
19
|
+
sendText(chatId: string, text: string): Promise<FeishuMessage>;
|
|
20
|
+
sendCard(chatId: string, card: CardContent): Promise<FeishuMessage>;
|
|
21
|
+
updateCard(messageId: string, card: CardContent): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/feishu/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAOjF,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,MAAM,EAAE,YAAY;IAa1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBjC,4FAA4F;IAC5F,SAAS,IAAI,IAAI,CAAC,MAAM;IAIxB,cAAc,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAA;KAAE;IAI3E,YAAY,IAAI,MAAM,GAAG,SAAS;IAI5B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAkB9D,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAkBnE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAStE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
2
|
+
import { resolveAppSecret } from '../core/config.js';
|
|
3
|
+
import { createLogger } from '../core/logger.js';
|
|
4
|
+
import { silentLogger } from './silent-logger.js';
|
|
5
|
+
const log = createLogger('FeishuAPI');
|
|
6
|
+
export class FeishuAPI {
|
|
7
|
+
client;
|
|
8
|
+
appId;
|
|
9
|
+
appSecret;
|
|
10
|
+
domain;
|
|
11
|
+
botOpenId;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.appId = config.appId;
|
|
14
|
+
this.appSecret = resolveAppSecret(config);
|
|
15
|
+
this.domain = config.domain === 'lark' ? Lark.Domain.Lark : Lark.Domain.Feishu;
|
|
16
|
+
this.client = new Lark.Client({
|
|
17
|
+
appId: this.appId,
|
|
18
|
+
appSecret: this.appSecret,
|
|
19
|
+
domain: this.domain,
|
|
20
|
+
logger: silentLogger,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async initialize() {
|
|
24
|
+
try {
|
|
25
|
+
const res = await this.client.request({
|
|
26
|
+
method: 'GET',
|
|
27
|
+
url: '/open-apis/bot/v3/info',
|
|
28
|
+
});
|
|
29
|
+
// Feishu returns {code, msg, bot:{open_id,...}} at top level for this endpoint
|
|
30
|
+
const openId = res?.bot?.open_id || res?.data?.bot?.open_id;
|
|
31
|
+
if (openId) {
|
|
32
|
+
this.botOpenId = openId;
|
|
33
|
+
log.info({ openId }, 'Bot open_id resolved');
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
log.warn('Could not resolve bot open_id from /bot/v3/info');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
log.warn({ err }, 'Failed to fetch bot info');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** SDK client — exposed so FeishuEventSource can mount WSClient on the same credentials. */
|
|
44
|
+
getClient() {
|
|
45
|
+
return this.client;
|
|
46
|
+
}
|
|
47
|
+
getCredentials() {
|
|
48
|
+
return { appId: this.appId, appSecret: this.appSecret, domain: this.domain };
|
|
49
|
+
}
|
|
50
|
+
getBotOpenId() {
|
|
51
|
+
return this.botOpenId;
|
|
52
|
+
}
|
|
53
|
+
async sendText(chatId, text) {
|
|
54
|
+
const res = await this.client.im.v1.message.create({
|
|
55
|
+
params: { receive_id_type: 'chat_id' },
|
|
56
|
+
data: {
|
|
57
|
+
receive_id: chatId,
|
|
58
|
+
msg_type: 'text',
|
|
59
|
+
content: JSON.stringify({ text }),
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (res.code !== 0) {
|
|
63
|
+
throw new Error(`Failed to send text: ${res.msg || 'Unknown error'}`);
|
|
64
|
+
}
|
|
65
|
+
if (!res.data?.message_id) {
|
|
66
|
+
throw new Error('sendText returned invalid data: missing message_id');
|
|
67
|
+
}
|
|
68
|
+
return res.data;
|
|
69
|
+
}
|
|
70
|
+
async sendCard(chatId, card) {
|
|
71
|
+
const res = await this.client.im.v1.message.create({
|
|
72
|
+
params: { receive_id_type: 'chat_id' },
|
|
73
|
+
data: {
|
|
74
|
+
receive_id: chatId,
|
|
75
|
+
msg_type: 'interactive',
|
|
76
|
+
content: JSON.stringify(card),
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
if (res.code !== 0) {
|
|
80
|
+
throw new Error(`Failed to send card: ${res.msg || 'Unknown error'}`);
|
|
81
|
+
}
|
|
82
|
+
if (!res.data?.message_id) {
|
|
83
|
+
throw new Error('sendCard returned invalid data: missing message_id');
|
|
84
|
+
}
|
|
85
|
+
return res.data;
|
|
86
|
+
}
|
|
87
|
+
async updateCard(messageId, card) {
|
|
88
|
+
const res = await this.client.im.v1.message.patch({
|
|
89
|
+
path: { message_id: messageId },
|
|
90
|
+
data: { content: JSON.stringify(card) },
|
|
91
|
+
});
|
|
92
|
+
if (res.code !== 0) {
|
|
93
|
+
throw new Error(`Failed to update message: ${res.msg || 'Unknown error'}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/feishu/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CardContent, ToolState } from '../core/types.js';
|
|
2
|
+
export declare class FeishuCard {
|
|
3
|
+
static createErrorCard(error: string): CardContent;
|
|
4
|
+
static createStreamingCard(opts: {
|
|
5
|
+
content: string;
|
|
6
|
+
tools?: ToolState[];
|
|
7
|
+
done?: boolean;
|
|
8
|
+
retry?: string;
|
|
9
|
+
}): CardContent;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/feishu/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQ/D,qBAAa,UAAU;IACrB,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW;IAYlD,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;QAC/B,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;QACpB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,WAAW;CAgDhB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const TOOL_ICON = {
|
|
2
|
+
running: '🔧',
|
|
3
|
+
completed: '✅',
|
|
4
|
+
error: '❌',
|
|
5
|
+
};
|
|
6
|
+
export class FeishuCard {
|
|
7
|
+
static createErrorCard(error) {
|
|
8
|
+
return {
|
|
9
|
+
config: { wide_screen_mode: true },
|
|
10
|
+
header: {
|
|
11
|
+
title: { tag: 'plain_text', content: '❌ 错误' },
|
|
12
|
+
},
|
|
13
|
+
elements: [
|
|
14
|
+
{ tag: 'div', text: { tag: 'lark_md', content: error } },
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
static createStreamingCard(opts) {
|
|
19
|
+
const { content, tools = [], done = false, retry } = opts;
|
|
20
|
+
const anyRunning = tools.some(t => t.status === 'running');
|
|
21
|
+
const headerTitle = done
|
|
22
|
+
? '✅ 完成'
|
|
23
|
+
: retry
|
|
24
|
+
? '🔄 重试中...'
|
|
25
|
+
: anyRunning
|
|
26
|
+
? '🔧 执行工具...'
|
|
27
|
+
: '💭 思考中...';
|
|
28
|
+
const elements = [];
|
|
29
|
+
if (retry) {
|
|
30
|
+
elements.push({
|
|
31
|
+
tag: 'div',
|
|
32
|
+
text: { tag: 'lark_md', content: `🔄 **重试中**:${retry}` },
|
|
33
|
+
});
|
|
34
|
+
elements.push({ tag: 'hr' });
|
|
35
|
+
}
|
|
36
|
+
if (tools.length > 0) {
|
|
37
|
+
const toolLines = tools
|
|
38
|
+
.map(t => {
|
|
39
|
+
const head = `${TOOL_ICON[t.status]} ${t.name}`;
|
|
40
|
+
return t.status === 'error' && t.error
|
|
41
|
+
? `${head}\n\`\`\`\n${t.error}\n\`\`\``
|
|
42
|
+
: head;
|
|
43
|
+
})
|
|
44
|
+
.join('\n');
|
|
45
|
+
elements.push({ tag: 'div', text: { tag: 'lark_md', content: toolLines } });
|
|
46
|
+
if (content)
|
|
47
|
+
elements.push({ tag: 'hr' });
|
|
48
|
+
}
|
|
49
|
+
if (content || (tools.length === 0 && !retry)) {
|
|
50
|
+
elements.push({
|
|
51
|
+
tag: 'div',
|
|
52
|
+
text: { tag: 'lark_md', content: content || '...' },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
config: { wide_screen_mode: true },
|
|
57
|
+
header: { title: { tag: 'plain_text', content: headerTitle } },
|
|
58
|
+
elements,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../../src/feishu/card.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { FeishuAPI } from './api.js';
|
|
3
|
+
/**
|
|
4
|
+
* Long-connection event source backed by Lark.WSClient.
|
|
5
|
+
*
|
|
6
|
+
* Emits `message` (FeishuMessage) for every `im.message.receive_v1` event.
|
|
7
|
+
* Emits `error` on fatal WSClient errors. Reconnection is handled internally
|
|
8
|
+
* by the SDK (autoReconnect=true, ping/pong loop, exponential backoff).
|
|
9
|
+
*/
|
|
10
|
+
export declare class FeishuEventSource extends EventEmitter {
|
|
11
|
+
private wsClient?;
|
|
12
|
+
private api;
|
|
13
|
+
private started;
|
|
14
|
+
constructor(api: FeishuAPI);
|
|
15
|
+
connect(): Promise<void>;
|
|
16
|
+
disconnect(): Promise<void>;
|
|
17
|
+
isConnected(): boolean;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=event-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-source.d.ts","sourceRoot":"","sources":["../../src/feishu/event-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAO1C;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,CAAgB;IACjC,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,OAAO,CAAS;gBAEZ,GAAG,EAAE,SAAS;IAKpB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC,WAAW,IAAI,OAAO;CAGvB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
3
|
+
import { createLogger } from '../core/logger.js';
|
|
4
|
+
import { silentLogger } from './silent-logger.js';
|
|
5
|
+
const log = createLogger('FeishuEventSource');
|
|
6
|
+
/**
|
|
7
|
+
* Long-connection event source backed by Lark.WSClient.
|
|
8
|
+
*
|
|
9
|
+
* Emits `message` (FeishuMessage) for every `im.message.receive_v1` event.
|
|
10
|
+
* Emits `error` on fatal WSClient errors. Reconnection is handled internally
|
|
11
|
+
* by the SDK (autoReconnect=true, ping/pong loop, exponential backoff).
|
|
12
|
+
*/
|
|
13
|
+
export class FeishuEventSource extends EventEmitter {
|
|
14
|
+
wsClient;
|
|
15
|
+
api;
|
|
16
|
+
started = false;
|
|
17
|
+
constructor(api) {
|
|
18
|
+
super();
|
|
19
|
+
this.api = api;
|
|
20
|
+
}
|
|
21
|
+
async connect() {
|
|
22
|
+
if (this.started) {
|
|
23
|
+
log.warn('Already started');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { appId, appSecret, domain } = this.api.getCredentials();
|
|
27
|
+
this.wsClient = new Lark.WSClient({
|
|
28
|
+
appId,
|
|
29
|
+
appSecret,
|
|
30
|
+
domain,
|
|
31
|
+
logger: silentLogger,
|
|
32
|
+
autoReconnect: true,
|
|
33
|
+
});
|
|
34
|
+
const dispatcher = new Lark.EventDispatcher({}).register({
|
|
35
|
+
'im.message.receive_v1': async (data) => {
|
|
36
|
+
// Adapt SDK event payload → FeishuMessage shape expected by MessageHandler:
|
|
37
|
+
// SDK splits sender and message at top level; our MessageHandler expects
|
|
38
|
+
// sender to live inside the message object.
|
|
39
|
+
const message = {
|
|
40
|
+
...data.message,
|
|
41
|
+
sender: data.sender,
|
|
42
|
+
};
|
|
43
|
+
this.emit('message', message);
|
|
44
|
+
return { ok: true };
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// WSClient.start() resolves when the WS connection is established.
|
|
48
|
+
// Any connection failure beyond the first attempt is handled by autoReconnect.
|
|
49
|
+
this.wsClient.start({ eventDispatcher: dispatcher });
|
|
50
|
+
this.started = true;
|
|
51
|
+
log.info('Started (WSClient long connection)');
|
|
52
|
+
}
|
|
53
|
+
async disconnect() {
|
|
54
|
+
if (!this.wsClient)
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
this.wsClient.close({ force: true });
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
log.warn({ err }, 'Close error');
|
|
61
|
+
}
|
|
62
|
+
this.wsClient = undefined;
|
|
63
|
+
this.started = false;
|
|
64
|
+
log.info('Disconnected');
|
|
65
|
+
}
|
|
66
|
+
isConnected() {
|
|
67
|
+
return this.started;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=event-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-source.js","sourceRoot":"","sources":["../../src/feishu/event-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAGhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IACzC,QAAQ,CAAiB;IACzB,GAAG,CAAY;IACf,OAAO,GAAG,KAAK,CAAC;IAExB,YAAY,GAAc;QACxB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/D,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC;YAChC,KAAK;YACL,SAAS;YACT,MAAM;YACN,MAAM,EAAE,YAAY;YACpB,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;YACvD,uBAAuB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACtC,4EAA4E;gBAC5E,yEAAyE;gBACzE,4CAA4C;gBAC5C,MAAM,OAAO,GAAG;oBACd,GAAG,IAAI,CAAC,OAAO;oBACf,MAAM,EAAE,IAAI,CAAC,MAAM;iBACQ,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC9B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;QAEH,mEAAmE;QACnE,+EAA+E;QAC/E,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op logger injected into Lark.Client / WSClient to silence the SDK's
|
|
3
|
+
* default stdout logger. Our own pino logger captures anything we care about.
|
|
4
|
+
*
|
|
5
|
+
* Note: passing `loggerLevel: LoggerLevel.fatal` (value 0) does NOT work —
|
|
6
|
+
* the SDK does `params.loggerLevel || LoggerLevel.info`, so falsy 0 gets
|
|
7
|
+
* overridden back to info and "[info]: [ 'client ready' ]" leaks to stdout.
|
|
8
|
+
*/
|
|
9
|
+
export declare const silentLogger: {
|
|
10
|
+
error: () => void;
|
|
11
|
+
warn: () => void;
|
|
12
|
+
info: () => void;
|
|
13
|
+
debug: () => void;
|
|
14
|
+
trace: () => void;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=silent-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"silent-logger.d.ts","sourceRoot":"","sources":["../../src/feishu/silent-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY;;;;;;CAMxB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op logger injected into Lark.Client / WSClient to silence the SDK's
|
|
3
|
+
* default stdout logger. Our own pino logger captures anything we care about.
|
|
4
|
+
*
|
|
5
|
+
* Note: passing `loggerLevel: LoggerLevel.fatal` (value 0) does NOT work —
|
|
6
|
+
* the SDK does `params.loggerLevel || LoggerLevel.info`, so falsy 0 gets
|
|
7
|
+
* overridden back to info and "[info]: [ 'client ready' ]" leaks to stdout.
|
|
8
|
+
*/
|
|
9
|
+
export const silentLogger = {
|
|
10
|
+
error: () => { },
|
|
11
|
+
warn: () => { },
|
|
12
|
+
info: () => { },
|
|
13
|
+
debug: () => { },
|
|
14
|
+
trace: () => { },
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=silent-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"silent-logger.js","sourceRoot":"","sources":["../../src/feishu/silent-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;CAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { startStandalone } from './standalone.js';
|
|
2
|
+
export { default as FeishuPlugin } from './plugin.js';
|
|
3
|
+
export { SetupWizard } from './setup/wizard.js';
|
|
4
|
+
export { ConfigManager } from './core/config.js';
|
|
5
|
+
export type { FeishuConfig } from './core/types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Main entry point - exports both standalone and plugin modes
|
|
2
|
+
export { startStandalone } from './standalone.js';
|
|
3
|
+
export { default as FeishuPlugin } from './plugin.js';
|
|
4
|
+
export { SetupWizard } from './setup/wizard.js';
|
|
5
|
+
export { ConfigManager } from './core/config.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare class OpenCodeClient {
|
|
2
|
+
private client;
|
|
3
|
+
private baseUrl;
|
|
4
|
+
private directory;
|
|
5
|
+
constructor(options: {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
directory?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
});
|
|
10
|
+
createSession(title?: string): Promise<any>;
|
|
11
|
+
sendPrompt(sessionId: string, text: string): Promise<any>;
|
|
12
|
+
subscribeEvents(): Promise<any>;
|
|
13
|
+
getSessionStatus(): Promise<Record<string, {
|
|
14
|
+
type: string;
|
|
15
|
+
}>>;
|
|
16
|
+
listSessions(): Promise<any[]>;
|
|
17
|
+
abortSession(sessionId: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Probe whether an OpenCode session still exists server-side.
|
|
20
|
+
* Used by SessionManager to reconcile persisted chat→session mappings
|
|
21
|
+
* against the server (sessions may have been deleted externally).
|
|
22
|
+
*/
|
|
23
|
+
sessionExists(sessionId: string): Promise<boolean>;
|
|
24
|
+
getBaseUrl(): string;
|
|
25
|
+
getDirectory(): string;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/opencode/client.ts"],"names":[],"mappings":"AAEA,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;IAmBzE,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAY3C,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAazD,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC;IAK/B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAU7D,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAU9B,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUxD,UAAU,IAAI,MAAM;IAIpB,YAAY,IAAI,MAAM;CAGvB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createOpencodeClient } from '@opencode-ai/sdk/v2/client';
|
|
2
|
+
export class OpenCodeClient {
|
|
3
|
+
client;
|
|
4
|
+
baseUrl;
|
|
5
|
+
directory;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.baseUrl = options.baseUrl;
|
|
8
|
+
this.directory = options.directory || process.cwd();
|
|
9
|
+
const config = {
|
|
10
|
+
baseUrl: this.baseUrl,
|
|
11
|
+
directory: this.directory,
|
|
12
|
+
};
|
|
13
|
+
// 如果提供了密码,添加到请求头
|
|
14
|
+
if (options.password) {
|
|
15
|
+
config.headers = {
|
|
16
|
+
'Authorization': `Basic ${btoa(`opencode:${options.password}`)}`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
this.client = createOpencodeClient(config);
|
|
20
|
+
}
|
|
21
|
+
async createSession(title) {
|
|
22
|
+
const { data, error } = await this.client.session.create({
|
|
23
|
+
title: title || 'Feishu Chat',
|
|
24
|
+
});
|
|
25
|
+
if (error) {
|
|
26
|
+
throw new Error(`Failed to create session: ${error}`);
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
async sendPrompt(sessionId, text) {
|
|
31
|
+
const { data, error } = await this.client.session.prompt({
|
|
32
|
+
sessionID: sessionId,
|
|
33
|
+
parts: [{ type: 'text', text }],
|
|
34
|
+
});
|
|
35
|
+
if (error) {
|
|
36
|
+
throw new Error(`Failed to send prompt: ${error}`);
|
|
37
|
+
}
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
async subscribeEvents() {
|
|
41
|
+
const events = await this.client.global.event({});
|
|
42
|
+
return events;
|
|
43
|
+
}
|
|
44
|
+
async getSessionStatus() {
|
|
45
|
+
const { data, error } = await this.client.session.status({});
|
|
46
|
+
if (error) {
|
|
47
|
+
throw new Error(`Failed to get session status: ${error}`);
|
|
48
|
+
}
|
|
49
|
+
return data || {};
|
|
50
|
+
}
|
|
51
|
+
async listSessions() {
|
|
52
|
+
const { data, error } = await this.client.session.list({});
|
|
53
|
+
if (error) {
|
|
54
|
+
throw new Error(`Failed to list sessions: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
return data || [];
|
|
57
|
+
}
|
|
58
|
+
async abortSession(sessionId) {
|
|
59
|
+
await this.client.session.abort({
|
|
60
|
+
sessionID: sessionId,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Probe whether an OpenCode session still exists server-side.
|
|
65
|
+
* Used by SessionManager to reconcile persisted chat→session mappings
|
|
66
|
+
* against the server (sessions may have been deleted externally).
|
|
67
|
+
*/
|
|
68
|
+
async sessionExists(sessionId) {
|
|
69
|
+
try {
|
|
70
|
+
const { data, error } = await this.client.session.get({ sessionID: sessionId });
|
|
71
|
+
if (error)
|
|
72
|
+
return false;
|
|
73
|
+
return !!data;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
getBaseUrl() {
|
|
80
|
+
return this.baseUrl;
|
|
81
|
+
}
|
|
82
|
+
getDirectory() {
|
|
83
|
+
return this.directory;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/opencode/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SessionManager } from '../core/session-manager.js';
|
|
2
|
+
import type { FeishuAPI } from '../feishu/api.js';
|
|
3
|
+
export declare class OpenCodeEventHandler {
|
|
4
|
+
private sessionManager;
|
|
5
|
+
private feishuApi;
|
|
6
|
+
private isRunning;
|
|
7
|
+
constructor(sessionManager: SessionManager, feishuApi: FeishuAPI);
|
|
8
|
+
start(eventStream: {
|
|
9
|
+
stream: AsyncGenerator<any, void, unknown>;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
stop(): void;
|
|
12
|
+
private handleEvent;
|
|
13
|
+
private handleTextDelta;
|
|
14
|
+
private handlePartUpdate;
|
|
15
|
+
private handleStatusChange;
|
|
16
|
+
private handleError;
|
|
17
|
+
private handleSessionIdle;
|
|
18
|
+
/**
|
|
19
|
+
* 合成并推送主流式卡片(一个 chat 对应一张持续更新的卡片)。
|
|
20
|
+
* - 首次调用:sendCard 新建一张并记录 message_id
|
|
21
|
+
* - 后续调用:throttle 到 UPDATE_THROTTLE_MS,改成 updateCard
|
|
22
|
+
* - force=true 绕过节流(工具状态变化 / 最终完成)
|
|
23
|
+
*/
|
|
24
|
+
private flushCard;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=event-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-handler.d.ts","sourceRoot":"","sources":["../../src/opencode/event-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AASlD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS;IAK1D,KAAK,CAAC,WAAW,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBvF,IAAI,IAAI,IAAI;YAKE,WAAW;YA2BX,eAAe;YAgBf,gBAAgB;YAuChB,kBAAkB;YAgClB,WAAW;YAkBX,iBAAiB;IAqB/B;;;;;OAKG;YACW,SAAS;CAwCxB"}
|