@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,212 @@
|
|
|
1
|
+
import { FeishuCard } from '../feishu/card.js';
|
|
2
|
+
import { createLogger } from '../core/logger.js';
|
|
3
|
+
const log = createLogger('EventHandler');
|
|
4
|
+
const UPDATE_THROTTLE_MS = 1000;
|
|
5
|
+
export class OpenCodeEventHandler {
|
|
6
|
+
sessionManager;
|
|
7
|
+
feishuApi;
|
|
8
|
+
isRunning = false;
|
|
9
|
+
constructor(sessionManager, feishuApi) {
|
|
10
|
+
this.sessionManager = sessionManager;
|
|
11
|
+
this.feishuApi = feishuApi;
|
|
12
|
+
}
|
|
13
|
+
async start(eventStream) {
|
|
14
|
+
if (this.isRunning) {
|
|
15
|
+
log.warn('Already running');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
this.isRunning = true;
|
|
19
|
+
log.info('Started');
|
|
20
|
+
try {
|
|
21
|
+
for await (const event of eventStream.stream) {
|
|
22
|
+
if (!this.isRunning)
|
|
23
|
+
break;
|
|
24
|
+
await this.handleEvent(event);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
log.error({ err: error }, 'Stream error');
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
this.isRunning = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
stop() {
|
|
36
|
+
this.isRunning = false;
|
|
37
|
+
log.info('Stopped');
|
|
38
|
+
}
|
|
39
|
+
async handleEvent(globalEvent) {
|
|
40
|
+
try {
|
|
41
|
+
const payload = globalEvent.payload || globalEvent;
|
|
42
|
+
const props = payload.properties || payload;
|
|
43
|
+
switch (payload.type) {
|
|
44
|
+
case 'message.part.delta':
|
|
45
|
+
await this.handleTextDelta(props);
|
|
46
|
+
break;
|
|
47
|
+
case 'message.part.updated':
|
|
48
|
+
await this.handlePartUpdate(props);
|
|
49
|
+
break;
|
|
50
|
+
case 'session.status':
|
|
51
|
+
await this.handleStatusChange(props);
|
|
52
|
+
break;
|
|
53
|
+
case 'session.error':
|
|
54
|
+
await this.handleError(props);
|
|
55
|
+
break;
|
|
56
|
+
case 'session.idle':
|
|
57
|
+
await this.handleSessionIdle(props);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
log.error({ err }, 'Error handling event');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async handleTextDelta(properties) {
|
|
66
|
+
if (!properties)
|
|
67
|
+
return;
|
|
68
|
+
const chatId = this.sessionManager.getChatIdBySession(properties.sessionID);
|
|
69
|
+
if (!chatId)
|
|
70
|
+
return;
|
|
71
|
+
this.sessionManager.appendContent(chatId, properties.delta);
|
|
72
|
+
await this.flushCard(chatId);
|
|
73
|
+
}
|
|
74
|
+
async handlePartUpdate(properties) {
|
|
75
|
+
const { part } = properties;
|
|
76
|
+
if (part?.type !== 'tool')
|
|
77
|
+
return;
|
|
78
|
+
const chatId = this.sessionManager.getChatIdBySession(properties.sessionID);
|
|
79
|
+
if (!chatId)
|
|
80
|
+
return;
|
|
81
|
+
const session = this.sessionManager.getSession(chatId);
|
|
82
|
+
if (!session)
|
|
83
|
+
return;
|
|
84
|
+
const status = part.state?.status;
|
|
85
|
+
if (!status)
|
|
86
|
+
return;
|
|
87
|
+
if (!session.tools)
|
|
88
|
+
session.tools = [];
|
|
89
|
+
const partId = part.id || part.state?.id || part.state?.title || '';
|
|
90
|
+
const name = part.state?.title || part.tool || partId || 'tool';
|
|
91
|
+
const existing = partId ? session.tools.find(t => t.id === partId) : undefined;
|
|
92
|
+
if (existing) {
|
|
93
|
+
existing.status = status;
|
|
94
|
+
existing.name = name;
|
|
95
|
+
if (status === 'error')
|
|
96
|
+
existing.error = part.state?.error;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
session.tools.push({
|
|
100
|
+
id: partId,
|
|
101
|
+
name,
|
|
102
|
+
status,
|
|
103
|
+
...(status === 'error' ? { error: part.state?.error } : {}),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Tool transitions are rare relative to text deltas — flush immediately
|
|
107
|
+
// so users see progress without waiting for the text throttle window.
|
|
108
|
+
await this.flushCard(chatId, { force: true });
|
|
109
|
+
}
|
|
110
|
+
async handleStatusChange(properties) {
|
|
111
|
+
const chatId = this.sessionManager.getChatIdBySession(properties.sessionID);
|
|
112
|
+
if (!chatId)
|
|
113
|
+
return;
|
|
114
|
+
const session = this.sessionManager.getSession(chatId);
|
|
115
|
+
if (!session)
|
|
116
|
+
return;
|
|
117
|
+
switch (properties.status.type) {
|
|
118
|
+
case 'busy':
|
|
119
|
+
session.status = 'busy';
|
|
120
|
+
if (session.retryMessage) {
|
|
121
|
+
// 重试结束、正常执行恢复,清掉 retry 通知并刷一次
|
|
122
|
+
session.retryMessage = undefined;
|
|
123
|
+
await this.flushCard(chatId, { force: true });
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case 'idle':
|
|
127
|
+
// 不在这里清理 currentMessage,等 session.idle 事件做 final flush 后再清
|
|
128
|
+
session.status = 'idle';
|
|
129
|
+
break;
|
|
130
|
+
case 'retry':
|
|
131
|
+
session.retryMessage = properties.status.message || '等待重试';
|
|
132
|
+
await this.flushCard(chatId, { force: true });
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async handleError(properties) {
|
|
137
|
+
if (!properties.sessionID)
|
|
138
|
+
return;
|
|
139
|
+
const chatId = this.sessionManager.getChatIdBySession(properties.sessionID);
|
|
140
|
+
if (!chatId)
|
|
141
|
+
return;
|
|
142
|
+
await this.feishuApi.sendCard(chatId, FeishuCard.createErrorCard(properties.error));
|
|
143
|
+
const session = this.sessionManager.getSession(chatId);
|
|
144
|
+
if (session) {
|
|
145
|
+
session.tools = undefined;
|
|
146
|
+
session.retryMessage = undefined;
|
|
147
|
+
}
|
|
148
|
+
this.sessionManager.updateStatus(chatId, 'idle');
|
|
149
|
+
this.sessionManager.clearCurrentMessage(chatId);
|
|
150
|
+
}
|
|
151
|
+
async handleSessionIdle(properties) {
|
|
152
|
+
const chatId = this.sessionManager.getChatIdBySession(properties.sessionID);
|
|
153
|
+
if (!chatId)
|
|
154
|
+
return;
|
|
155
|
+
const session = this.sessionManager.getSession(chatId);
|
|
156
|
+
if (!session)
|
|
157
|
+
return;
|
|
158
|
+
const hasContent = !!(session.currentContent && session.currentContent.length > 0);
|
|
159
|
+
const hasTools = !!(session.tools && session.tools.length > 0);
|
|
160
|
+
if (hasContent || hasTools) {
|
|
161
|
+
await this.flushCard(chatId, { force: true, done: true });
|
|
162
|
+
}
|
|
163
|
+
session.tools = undefined;
|
|
164
|
+
session.retryMessage = undefined;
|
|
165
|
+
this.sessionManager.updateStatus(chatId, 'idle');
|
|
166
|
+
this.sessionManager.clearCurrentMessage(chatId);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 合成并推送主流式卡片(一个 chat 对应一张持续更新的卡片)。
|
|
170
|
+
* - 首次调用:sendCard 新建一张并记录 message_id
|
|
171
|
+
* - 后续调用:throttle 到 UPDATE_THROTTLE_MS,改成 updateCard
|
|
172
|
+
* - force=true 绕过节流(工具状态变化 / 最终完成)
|
|
173
|
+
*/
|
|
174
|
+
async flushCard(chatId, opts = {}) {
|
|
175
|
+
const session = this.sessionManager.getSession(chatId);
|
|
176
|
+
if (!session)
|
|
177
|
+
return;
|
|
178
|
+
const content = session.currentContent || '';
|
|
179
|
+
const tools = session.tools || [];
|
|
180
|
+
const card = FeishuCard.createStreamingCard({
|
|
181
|
+
content,
|
|
182
|
+
tools,
|
|
183
|
+
done: !!opts.done,
|
|
184
|
+
retry: session.retryMessage,
|
|
185
|
+
});
|
|
186
|
+
if (!session.currentMessageId) {
|
|
187
|
+
try {
|
|
188
|
+
const message = await this.feishuApi.sendCard(chatId, card);
|
|
189
|
+
if (message && message.message_id) {
|
|
190
|
+
this.sessionManager.setCurrentMessage(chatId, message.message_id);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
log.error({ err }, 'Failed to create card');
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
const lastUpdate = session.lastUpdateTime || 0;
|
|
200
|
+
if (!opts.force && now - lastUpdate <= UPDATE_THROTTLE_MS)
|
|
201
|
+
return;
|
|
202
|
+
// 槽位必须在 await 之前占住,防止 PATCH 耗时 > 节流窗口时触发并发更新。
|
|
203
|
+
session.lastUpdateTime = now;
|
|
204
|
+
try {
|
|
205
|
+
await this.feishuApi.updateCard(session.currentMessageId, card);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
log.error({ err }, 'Failed to update card');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=event-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-handler.js","sourceRoot":"","sources":["../../src/opencode/event-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,mBAAmB,CAAC;AAY7D,QAAA,MAAM,YAAY,EAAE,MA+DnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ConfigManager } from './core/config.js';
|
|
2
|
+
import { SessionManager } from './core/session-manager.js';
|
|
3
|
+
import { MessageHandler } from './core/message-handler.js';
|
|
4
|
+
import { FeishuAPI } from './feishu/api.js';
|
|
5
|
+
import { FeishuEventSource } from './feishu/event-source.js';
|
|
6
|
+
import { OpenCodeClient } from './opencode/client.js';
|
|
7
|
+
import { OpenCodeEventHandler } from './opencode/event-handler.js';
|
|
8
|
+
import { createLogger } from './core/logger.js';
|
|
9
|
+
const log = createLogger('plugin');
|
|
10
|
+
const FeishuPlugin = {
|
|
11
|
+
id: 'feishu',
|
|
12
|
+
server: async (input) => {
|
|
13
|
+
const { client, project, directory } = input;
|
|
14
|
+
log.info('Initializing...');
|
|
15
|
+
try {
|
|
16
|
+
const configManager = new ConfigManager();
|
|
17
|
+
const config = configManager.load();
|
|
18
|
+
log.info({ appId: config.appId, domain: config.domain }, 'Configuration loaded');
|
|
19
|
+
const feishuApi = new FeishuAPI(config);
|
|
20
|
+
await feishuApi.initialize();
|
|
21
|
+
const opencode = new OpenCodeClient({
|
|
22
|
+
baseUrl: config.opencodeUrl,
|
|
23
|
+
directory: directory || project?.root || process.cwd(),
|
|
24
|
+
});
|
|
25
|
+
const sessionManager = new SessionManager(opencode);
|
|
26
|
+
const messageHandler = new MessageHandler(config, sessionManager, feishuApi, opencode);
|
|
27
|
+
let eventHandler;
|
|
28
|
+
if (config.streaming) {
|
|
29
|
+
eventHandler = new OpenCodeEventHandler(sessionManager, feishuApi);
|
|
30
|
+
try {
|
|
31
|
+
// 使用宿主传入的 client 订阅事件
|
|
32
|
+
const events = await client.global.event({});
|
|
33
|
+
eventHandler.start(events).catch((err) => {
|
|
34
|
+
log.error({ err }, 'Event stream error');
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
log.warn({ err }, 'Failed to start event stream');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const feishuEvents = new FeishuEventSource(feishuApi);
|
|
42
|
+
feishuEvents.on('message', async (message) => {
|
|
43
|
+
await messageHandler.handleMessage(message);
|
|
44
|
+
});
|
|
45
|
+
await feishuEvents.connect();
|
|
46
|
+
log.info('Connected to Feishu');
|
|
47
|
+
return {
|
|
48
|
+
cleanup: async () => {
|
|
49
|
+
log.info('Cleaning up...');
|
|
50
|
+
if (eventHandler)
|
|
51
|
+
eventHandler.stop();
|
|
52
|
+
await feishuEvents.disconnect();
|
|
53
|
+
await sessionManager.cleanup();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
log.error({ err }, 'Initialization failed');
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export default FeishuPlugin;
|
|
64
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FeishuConfig } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Preflight checks — pure functions, no console output.
|
|
4
|
+
* Each returns a structured result so the caller (doctor CLI, wizard,
|
|
5
|
+
* or status probe) can render/act on it consistently.
|
|
6
|
+
*/
|
|
7
|
+
export interface CheckResult {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
/** Short human-readable name. */
|
|
10
|
+
label: string;
|
|
11
|
+
/** Optional extra context when `ok` is false — or noteworthy info when true. */
|
|
12
|
+
detail?: string;
|
|
13
|
+
/** Optional remediation hint shown to the user on failure. */
|
|
14
|
+
fix?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function checkConfigFile(configPath?: string): Promise<CheckResult>;
|
|
17
|
+
export declare function checkConfigWritable(configPath?: string): Promise<CheckResult>;
|
|
18
|
+
export declare function checkFeishuCredentials(appId: string | undefined, appSecret: string | undefined, domain?: 'feishu' | 'lark'): Promise<CheckResult>;
|
|
19
|
+
export declare function checkOpenCodeServer(url: string): Promise<CheckResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Run all applicable checks given a (possibly partial) config.
|
|
22
|
+
* Order: cheapest/most foundational first so short-circuit decisions
|
|
23
|
+
* can stop reading once an early failure explains downstream ones.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runAll(config: FeishuConfig | null, opts?: {
|
|
26
|
+
configPath?: string;
|
|
27
|
+
appSecret?: string;
|
|
28
|
+
}): Promise<CheckResult[]>;
|
|
29
|
+
//# sourceMappingURL=preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../../src/setup/preflight.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,wBAAsB,eAAe,CAAC,UAAU,SAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAU5F;AAED,wBAAsB,mBAAmB,CAAC,UAAU,SAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAchG;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,GAAE,QAAQ,GAAG,MAAiB,GACnC,OAAO,CAAC,WAAW,CAAC,CAgDtB;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAyB3E;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,EAC3B,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,OAAO,CAAC,WAAW,EAAE,CAAC,CAkBxB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { existsSync, accessSync, constants } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import * as Lark from '@larksuiteoapi/node-sdk';
|
|
5
|
+
import { silentLogger } from '../feishu/silent-logger.js';
|
|
6
|
+
const DEFAULT_CONFIG_PATH = join(homedir(), '.config', 'opencode', 'feishu.json');
|
|
7
|
+
export async function checkConfigFile(configPath = DEFAULT_CONFIG_PATH) {
|
|
8
|
+
if (!existsSync(configPath)) {
|
|
9
|
+
return {
|
|
10
|
+
ok: false,
|
|
11
|
+
label: 'Config file present',
|
|
12
|
+
detail: `Not found at ${configPath}`,
|
|
13
|
+
fix: 'Run: opencode-feishu setup',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return { ok: true, label: 'Config file present', detail: configPath };
|
|
17
|
+
}
|
|
18
|
+
export async function checkConfigWritable(configPath = DEFAULT_CONFIG_PATH) {
|
|
19
|
+
const dir = dirname(configPath);
|
|
20
|
+
try {
|
|
21
|
+
// Directory must exist & be writable. File may not exist yet.
|
|
22
|
+
accessSync(dir, constants.W_OK);
|
|
23
|
+
return { ok: true, label: 'Config directory writable', detail: dir };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
label: 'Config directory writable',
|
|
29
|
+
detail: `Cannot write to ${dir}`,
|
|
30
|
+
fix: `Check permissions or run: mkdir -p ${dir} && chmod u+w ${dir}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function checkFeishuCredentials(appId, appSecret, domain = 'feishu') {
|
|
35
|
+
if (!appId || !appId.startsWith('cli_')) {
|
|
36
|
+
return {
|
|
37
|
+
ok: false,
|
|
38
|
+
label: 'Feishu credentials',
|
|
39
|
+
detail: 'App ID missing or not in cli_xxx format',
|
|
40
|
+
fix: 'Set `appId` in config (should start with cli_)',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (!appSecret) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
label: 'Feishu credentials',
|
|
47
|
+
detail: 'App secret missing',
|
|
48
|
+
fix: 'Set `appSecret` in config or export FEISHU_APP_SECRET',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const client = new Lark.Client({
|
|
53
|
+
appId,
|
|
54
|
+
appSecret,
|
|
55
|
+
domain: domain === 'lark' ? Lark.Domain.Lark : Lark.Domain.Feishu,
|
|
56
|
+
logger: silentLogger,
|
|
57
|
+
});
|
|
58
|
+
const res = await client.request({
|
|
59
|
+
method: 'GET',
|
|
60
|
+
url: '/open-apis/bot/v3/info',
|
|
61
|
+
});
|
|
62
|
+
const openId = res?.bot?.open_id || res?.data?.bot?.open_id;
|
|
63
|
+
if (!openId) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
label: 'Feishu credentials',
|
|
67
|
+
detail: 'Credentials accepted but /bot/v3/info returned no open_id — bot ability may be disabled on the app',
|
|
68
|
+
fix: 'Enable "机器人" ability in Feishu console and republish the app',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { ok: true, label: 'Feishu credentials', detail: `bot open_id=${openId}` };
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
const msg = err?.message || String(err);
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
label: 'Feishu credentials',
|
|
78
|
+
detail: `SDK call failed: ${msg.substring(0, 120)}`,
|
|
79
|
+
fix: 'Verify appId/appSecret match the Feishu console; confirm the app is published',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function checkOpenCodeServer(url) {
|
|
84
|
+
try {
|
|
85
|
+
const u = new URL(url);
|
|
86
|
+
const res = await fetch(`${u.origin}/session`, {
|
|
87
|
+
// short timeout — if the server is down, don't hang the wizard
|
|
88
|
+
signal: AbortSignal.timeout(3000),
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
label: 'OpenCode server reachable',
|
|
94
|
+
detail: `HTTP ${res.status} at ${url}`,
|
|
95
|
+
fix: `Start it with: opencode serve --port ${u.port || '19876'}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return { ok: true, label: 'OpenCode server reachable', detail: url };
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const msg = err?.message || String(err);
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
label: 'OpenCode server reachable',
|
|
105
|
+
detail: `${msg.substring(0, 120)} at ${url}`,
|
|
106
|
+
fix: `Start it with: opencode serve --port ${new URL(url).port || '19876'}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Run all applicable checks given a (possibly partial) config.
|
|
112
|
+
* Order: cheapest/most foundational first so short-circuit decisions
|
|
113
|
+
* can stop reading once an early failure explains downstream ones.
|
|
114
|
+
*/
|
|
115
|
+
export async function runAll(config, opts = {}) {
|
|
116
|
+
const results = [];
|
|
117
|
+
results.push(await checkConfigFile(opts.configPath));
|
|
118
|
+
results.push(await checkConfigWritable(opts.configPath));
|
|
119
|
+
if (config) {
|
|
120
|
+
results.push(await checkOpenCodeServer(config.opencodeUrl));
|
|
121
|
+
results.push(await checkFeishuCredentials(config.appId, opts.appSecret ?? config.appSecret ?? process.env.FEISHU_APP_SECRET, config.domain));
|
|
122
|
+
}
|
|
123
|
+
return results;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../src/setup/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,KAAK,IAAI,MAAM,yBAAyB,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB1D,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AAElF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAU,GAAG,mBAAmB;IACpE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,qBAAqB;YAC5B,MAAM,EAAE,gBAAgB,UAAU,EAAE;YACpC,GAAG,EAAE,4BAA4B;SAClC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAU,GAAG,mBAAmB;IACxE,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,8DAA8D;QAC9D,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,2BAA2B;YAClC,MAAM,EAAE,mBAAmB,GAAG,EAAE;YAChC,GAAG,EAAE,sCAAsC,GAAG,iBAAiB,GAAG,EAAE;SACrE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAAyB,EACzB,SAA6B,EAC7B,SAA4B,QAAQ;IAEpC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oBAAoB;YAC3B,MAAM,EAAE,yCAAyC;YACjD,GAAG,EAAE,gDAAgD;SACtD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oBAAoB;YAC3B,MAAM,EAAE,oBAAoB;YAC5B,GAAG,EAAE,uDAAuD;SAC7D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC;YAC7B,KAAK;YACL,SAAS;YACT,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;YACjE,MAAM,EAAE,YAAY;SACrB,CAAC,CAAC;QACH,MAAM,GAAG,GAAQ,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,wBAAwB;SAC9B,CAAC,CAAC;QACH,MAAM,MAAM,GAAuB,GAAG,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC;QAChF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,oBAAoB;gBAC3B,MAAM,EAAE,oGAAoG;gBAC5G,GAAG,EAAE,8DAA8D;aACpE,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,eAAe,MAAM,EAAE,EAAE,CAAC;IACpF,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,oBAAoB;YAC3B,MAAM,EAAE,oBAAoB,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACnD,GAAG,EAAE,+EAA+E;SACrF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAW;IACnD,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,UAAU,EAAE;YAC7C,+DAA+D;YAC/D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,2BAA2B;gBAClC,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,OAAO,GAAG,EAAE;gBACtC,GAAG,EAAE,wCAAwC,CAAC,CAAC,IAAI,IAAI,OAAO,EAAE;aACjE,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvE,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,2BAA2B;YAClC,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,EAAE;YAC5C,GAAG,EAAE,wCAAwC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,OAAO,EAAE;SAC5E,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,MAA2B,EAC3B,OAAoD,EAAE;IAEtD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,OAAO,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,MAAM,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAEzD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,MAAM,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CACV,MAAM,sBAAsB,CAC1B,MAAM,CAAC,KAAK,EACZ,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EACnE,MAAM,CAAC,MAAM,CACd,CACF,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FeishuConfig } from '../core/types.js';
|
|
2
|
+
export declare class SetupWizard {
|
|
3
|
+
private configManager;
|
|
4
|
+
constructor(configPath?: string);
|
|
5
|
+
run(): Promise<FeishuConfig>;
|
|
6
|
+
private runQuickSetup;
|
|
7
|
+
private runManualSetup;
|
|
8
|
+
/** Shared preflight check — confirms the app is published, secret is right, bot ability is on. */
|
|
9
|
+
private verifyFeishuCredentials;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=wizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../../src/setup/wizard.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMrD,qBAAa,WAAW;IACtB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,UAAU,CAAC,EAAE,MAAM;IAIzB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;YAwEpB,aAAa;YAgHb,cAAc;IAqF5B,kGAAkG;YACpF,uBAAuB;CAWtC"}
|