@neomei/opencode-feishu 0.1.2 → 0.2.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.
- package/CHANGELOG.md +29 -4
- package/LICENSE +0 -0
- package/README.md +114 -6
- package/dist/cli.js +154 -6
- package/dist/cli.js.map +1 -1
- package/dist/core/config.d.ts +30 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +41 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/daemon.d.ts.map +1 -1
- package/dist/core/daemon.js +2 -1
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/dedup.d.ts +29 -0
- package/dist/core/dedup.d.ts.map +1 -0
- package/dist/core/dedup.js +69 -0
- package/dist/core/dedup.js.map +1 -0
- package/dist/core/file-downloader.d.ts +24 -0
- package/dist/core/file-downloader.d.ts.map +1 -0
- package/dist/core/file-downloader.js +79 -0
- package/dist/core/file-downloader.js.map +1 -0
- package/dist/core/hook-manager.d.ts +14 -0
- package/dist/core/hook-manager.d.ts.map +1 -0
- package/dist/core/hook-manager.js +71 -0
- package/dist/core/hook-manager.js.map +1 -0
- package/dist/core/message-handler.d.ts +17 -1
- package/dist/core/message-handler.d.ts.map +1 -1
- package/dist/core/message-handler.js +151 -8
- package/dist/core/message-handler.js.map +1 -1
- package/dist/core/profile-manager.d.ts +27 -0
- package/dist/core/profile-manager.d.ts.map +1 -0
- package/dist/core/profile-manager.js +149 -0
- package/dist/core/profile-manager.js.map +1 -0
- package/dist/core/session-manager.d.ts +8 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +27 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/types.d.ts +13 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/feishu/api.d.ts +17 -0
- package/dist/feishu/api.d.ts.map +1 -1
- package/dist/feishu/api.js +106 -0
- package/dist/feishu/api.js.map +1 -1
- package/dist/feishu/card.d.ts +4 -1
- package/dist/feishu/card.d.ts.map +1 -1
- package/dist/feishu/card.js +26 -6
- package/dist/feishu/card.js.map +1 -1
- package/dist/feishu/event-source.d.ts.map +1 -1
- package/dist/feishu/event-source.js +3 -0
- package/dist/feishu/event-source.js.map +1 -1
- package/dist/feishu/silent-logger.d.ts +5 -5
- package/dist/feishu/silent-logger.d.ts.map +1 -1
- package/dist/feishu/silent-logger.js +5 -5
- package/dist/feishu/silent-logger.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/opencode/client.d.ts +5 -1
- package/dist/opencode/client.d.ts.map +1 -1
- package/dist/opencode/client.js +15 -2
- package/dist/opencode/client.js.map +1 -1
- package/dist/opencode/event-handler.d.ts +6 -1
- package/dist/opencode/event-handler.d.ts.map +1 -1
- package/dist/opencode/event-handler.js +31 -3
- package/dist/opencode/event-handler.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +4 -2
- package/dist/plugin.js.map +1 -1
- package/dist/services/approval-service.d.ts +20 -0
- package/dist/services/approval-service.d.ts.map +1 -0
- package/dist/services/approval-service.js +123 -0
- package/dist/services/approval-service.js.map +1 -0
- package/dist/services/base-service.d.ts +22 -0
- package/dist/services/base-service.d.ts.map +1 -0
- package/dist/services/base-service.js +47 -0
- package/dist/services/base-service.js.map +1 -0
- package/dist/services/calendar-service.d.ts +25 -0
- package/dist/services/calendar-service.d.ts.map +1 -0
- package/dist/services/calendar-service.js +220 -0
- package/dist/services/calendar-service.js.map +1 -0
- package/dist/services/chat-service.d.ts +52 -0
- package/dist/services/chat-service.d.ts.map +1 -0
- package/dist/services/chat-service.js +170 -0
- package/dist/services/chat-service.js.map +1 -0
- package/dist/services/contact-service.d.ts +40 -0
- package/dist/services/contact-service.d.ts.map +1 -0
- package/dist/services/contact-service.js +137 -0
- package/dist/services/contact-service.js.map +1 -0
- package/dist/services/doc-service.d.ts +137 -0
- package/dist/services/doc-service.d.ts.map +1 -0
- package/dist/services/doc-service.js +516 -0
- package/dist/services/doc-service.js.map +1 -0
- package/dist/services/im-service.d.ts +64 -0
- package/dist/services/im-service.d.ts.map +1 -0
- package/dist/services/im-service.js +215 -0
- package/dist/services/im-service.js.map +1 -0
- package/dist/services/index.d.ts +9 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +10 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/task-service.d.ts +19 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +126 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/setup/device-flow.d.ts +31 -0
- package/dist/setup/device-flow.d.ts.map +1 -0
- package/dist/setup/device-flow.js +133 -0
- package/dist/setup/device-flow.js.map +1 -0
- package/dist/setup/preflight.d.ts +1 -0
- package/dist/setup/preflight.d.ts.map +1 -1
- package/dist/setup/preflight.js +167 -1
- package/dist/setup/preflight.js.map +1 -1
- package/dist/setup/wizard.d.ts +3 -1
- package/dist/setup/wizard.d.ts.map +1 -1
- package/dist/setup/wizard.js +113 -125
- package/dist/setup/wizard.js.map +1 -1
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +49 -13
- package/dist/standalone.js.map +1 -1
- package/dist/types/extended.d.ts +196 -0
- package/dist/types/extended.d.ts.map +1 -0
- package/dist/types/extended.js +6 -0
- package/dist/types/extended.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory message deduplicator with TTL.
|
|
3
|
+
* Prevents processing the same message multiple times (e.g. from WS reconnects).
|
|
4
|
+
*/
|
|
5
|
+
export declare class MessageDeduplicator {
|
|
6
|
+
private seen;
|
|
7
|
+
private ttlMs;
|
|
8
|
+
private cleanupInterval?;
|
|
9
|
+
constructor(ttlMs?: number);
|
|
10
|
+
/**
|
|
11
|
+
* Check if a message has been seen before.
|
|
12
|
+
* If not, record it and return false.
|
|
13
|
+
* If yes, return true (it's a duplicate).
|
|
14
|
+
*/
|
|
15
|
+
isDuplicate(messageId: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Get the current size of the dedup cache.
|
|
18
|
+
*/
|
|
19
|
+
size(): number;
|
|
20
|
+
/**
|
|
21
|
+
* Clean up expired entries.
|
|
22
|
+
*/
|
|
23
|
+
private cleanup;
|
|
24
|
+
/**
|
|
25
|
+
* Stop the cleanup interval.
|
|
26
|
+
*/
|
|
27
|
+
stop(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=dedup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/core/dedup.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,KAAK,SAAU;IAW3B;;;;OAIG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAavC;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,OAAO,CAAC,OAAO;IAcf;;OAEG;IACH,IAAI,IAAI,IAAI;CAOb"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createLogger } from './logger.js';
|
|
2
|
+
const log = createLogger('MessageDeduplicator');
|
|
3
|
+
/**
|
|
4
|
+
* Simple in-memory message deduplicator with TTL.
|
|
5
|
+
* Prevents processing the same message multiple times (e.g. from WS reconnects).
|
|
6
|
+
*/
|
|
7
|
+
export class MessageDeduplicator {
|
|
8
|
+
seen = new Map();
|
|
9
|
+
ttlMs;
|
|
10
|
+
cleanupInterval;
|
|
11
|
+
constructor(ttlMs = 600_000) {
|
|
12
|
+
// Default 10 minutes
|
|
13
|
+
this.ttlMs = ttlMs;
|
|
14
|
+
// Run cleanup every TTL interval
|
|
15
|
+
this.cleanupInterval = setInterval(() => this.cleanup(), ttlMs);
|
|
16
|
+
// Ensure cleanup doesn't keep process alive
|
|
17
|
+
if (this.cleanupInterval.unref) {
|
|
18
|
+
this.cleanupInterval.unref();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a message has been seen before.
|
|
23
|
+
* If not, record it and return false.
|
|
24
|
+
* If yes, return true (it's a duplicate).
|
|
25
|
+
*/
|
|
26
|
+
isDuplicate(messageId) {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const entry = this.seen.get(messageId);
|
|
29
|
+
if (entry && now - entry.timestamp < this.ttlMs) {
|
|
30
|
+
log.debug({ messageId, ageMs: now - entry.timestamp }, 'Duplicate message detected');
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
this.seen.set(messageId, { timestamp: now });
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the current size of the dedup cache.
|
|
38
|
+
*/
|
|
39
|
+
size() {
|
|
40
|
+
return this.seen.size;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Clean up expired entries.
|
|
44
|
+
*/
|
|
45
|
+
cleanup() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
let cleaned = 0;
|
|
48
|
+
for (const [id, entry] of this.seen.entries()) {
|
|
49
|
+
if (now - entry.timestamp > this.ttlMs) {
|
|
50
|
+
this.seen.delete(id);
|
|
51
|
+
cleaned++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (cleaned > 0) {
|
|
55
|
+
log.debug({ cleaned, remaining: this.seen.size }, 'Dedup cache cleaned');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Stop the cleanup interval.
|
|
60
|
+
*/
|
|
61
|
+
stop() {
|
|
62
|
+
if (this.cleanupInterval) {
|
|
63
|
+
clearInterval(this.cleanupInterval);
|
|
64
|
+
this.cleanupInterval = undefined;
|
|
65
|
+
}
|
|
66
|
+
this.seen.clear();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/core/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,GAAG,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAMhD;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IACtB,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAC;IACrC,KAAK,CAAS;IACd,eAAe,CAAkB;IAEzC,YAAY,KAAK,GAAG,OAAO;QACzB,qBAAqB;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,iCAAiC;QACjC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;QAChE,4CAA4C;QAC5C,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,WAAW,CAAC,SAAiB;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEvC,IAAI,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAChD,GAAG,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,4BAA4B,CAAC,CAAC;YACrF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED;;OAEG;IACK,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YAC9C,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBACvC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACrB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,qBAAqB,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface DownloadedFile {
|
|
2
|
+
filePath: string;
|
|
3
|
+
fileName: string;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Download files from Feishu to local storage.
|
|
8
|
+
* Files are saved to ~/.config/opencode/feishu-attachments/
|
|
9
|
+
*/
|
|
10
|
+
export declare class FileDownloader {
|
|
11
|
+
private baseDir;
|
|
12
|
+
constructor(baseDir?: string);
|
|
13
|
+
/**
|
|
14
|
+
* Download a file from a URL and save it locally.
|
|
15
|
+
* Returns the local file path.
|
|
16
|
+
*/
|
|
17
|
+
downloadFromUrl(url: string, fileName: string, mimeType: string): Promise<DownloadedFile>;
|
|
18
|
+
/**
|
|
19
|
+
* Save a buffer directly to a file.
|
|
20
|
+
*/
|
|
21
|
+
saveBuffer(buffer: Buffer, fileName: string, mimeType: string): Promise<DownloadedFile>;
|
|
22
|
+
private sanitizeFileName;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=file-downloader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-downloader.d.ts","sourceRoot":"","sources":["../../src/core/file-downloader.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,CAAC,EAAE,MAAM;IAO5B;;;OAGG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA0C/F;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAmB7F,OAAO,CAAC,gBAAgB;CAOzB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { createLogger } from './logger.js';
|
|
5
|
+
const log = createLogger('FileDownloader');
|
|
6
|
+
const DEFAULT_ATTACHMENTS_DIR = join(homedir(), '.config', 'opencode', 'feishu-attachments');
|
|
7
|
+
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB limit
|
|
8
|
+
/**
|
|
9
|
+
* Download files from Feishu to local storage.
|
|
10
|
+
* Files are saved to ~/.config/opencode/feishu-attachments/
|
|
11
|
+
*/
|
|
12
|
+
export class FileDownloader {
|
|
13
|
+
baseDir;
|
|
14
|
+
constructor(baseDir) {
|
|
15
|
+
this.baseDir = baseDir || DEFAULT_ATTACHMENTS_DIR;
|
|
16
|
+
if (!existsSync(this.baseDir)) {
|
|
17
|
+
mkdirSync(this.baseDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Download a file from a URL and save it locally.
|
|
22
|
+
* Returns the local file path.
|
|
23
|
+
*/
|
|
24
|
+
async downloadFromUrl(url, fileName, mimeType) {
|
|
25
|
+
try {
|
|
26
|
+
log.info({ url, fileName }, 'Downloading file from URL');
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
const timeout = setTimeout(() => controller.abort(), 30000); // 30s timeout
|
|
29
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
30
|
+
clearTimeout(timeout);
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
33
|
+
}
|
|
34
|
+
const contentLength = response.headers.get('content-length');
|
|
35
|
+
if (contentLength && parseInt(contentLength) > MAX_FILE_SIZE) {
|
|
36
|
+
throw new Error(`File too large: ${contentLength} bytes (max ${MAX_FILE_SIZE})`);
|
|
37
|
+
}
|
|
38
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
39
|
+
if (buffer.length > MAX_FILE_SIZE) {
|
|
40
|
+
throw new Error(`File too large: ${buffer.length} bytes (max ${MAX_FILE_SIZE})`);
|
|
41
|
+
}
|
|
42
|
+
// Sanitize filename
|
|
43
|
+
const safeName = this.sanitizeFileName(fileName);
|
|
44
|
+
const timestamp = Date.now();
|
|
45
|
+
const uniqueName = `${timestamp}_${safeName}`;
|
|
46
|
+
const filePath = join(this.baseDir, uniqueName);
|
|
47
|
+
writeFileSync(filePath, buffer);
|
|
48
|
+
log.info({ filePath, size: buffer.length }, 'File downloaded successfully');
|
|
49
|
+
return { filePath, fileName: safeName, mimeType };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
log.error({ err, url, fileName }, 'Failed to download file');
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Save a buffer directly to a file.
|
|
58
|
+
*/
|
|
59
|
+
async saveBuffer(buffer, fileName, mimeType) {
|
|
60
|
+
if (buffer.length > MAX_FILE_SIZE) {
|
|
61
|
+
throw new Error(`File too large: ${buffer.length} bytes (max ${MAX_FILE_SIZE})`);
|
|
62
|
+
}
|
|
63
|
+
const safeName = this.sanitizeFileName(fileName);
|
|
64
|
+
const timestamp = Date.now();
|
|
65
|
+
const uniqueName = `${timestamp}_${safeName}`;
|
|
66
|
+
const filePath = join(this.baseDir, uniqueName);
|
|
67
|
+
writeFileSync(filePath, buffer);
|
|
68
|
+
log.info({ filePath, size: buffer.length }, 'Buffer saved to file');
|
|
69
|
+
return { filePath, fileName: safeName, mimeType };
|
|
70
|
+
}
|
|
71
|
+
sanitizeFileName(name) {
|
|
72
|
+
// Remove path traversal characters and limit length
|
|
73
|
+
return name
|
|
74
|
+
.replace(/[\x00-\x1f\x7f]/g, '') // Control chars
|
|
75
|
+
.replace(/[/\\?%<>|":]/g, '_') // Invalid path chars
|
|
76
|
+
.substring(0, 200); // Limit length
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=file-downloader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-downloader.js","sourceRoot":"","sources":["../../src/core/file-downloader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HookConfig } from './types.js';
|
|
2
|
+
export interface HookContext {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
opencodeUrl: string;
|
|
5
|
+
[key: string]: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare class HookManager {
|
|
8
|
+
private config;
|
|
9
|
+
private projectDir;
|
|
10
|
+
constructor(config: HookConfig, projectDir: string);
|
|
11
|
+
run(hookName: keyof HookConfig, ctx: HookContext): Promise<void>;
|
|
12
|
+
private execScript;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=hook-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-manager.d.ts","sourceRoot":"","sources":["../../src/core/hook-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM;IAK5C,GAAG,CAAC,QAAQ,EAAE,MAAM,UAAU,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IActE,OAAO,CAAC,UAAU;CAoDnB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { createLogger } from './logger.js';
|
|
3
|
+
const log = createLogger('HookManager');
|
|
4
|
+
export class HookManager {
|
|
5
|
+
config;
|
|
6
|
+
projectDir;
|
|
7
|
+
constructor(config, projectDir) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
this.projectDir = projectDir;
|
|
10
|
+
}
|
|
11
|
+
async run(hookName, ctx) {
|
|
12
|
+
const scriptPath = this.config[hookName];
|
|
13
|
+
if (!scriptPath)
|
|
14
|
+
return;
|
|
15
|
+
log.info({ hook: hookName, script: scriptPath, sessionId: ctx.sessionId }, 'Running hook');
|
|
16
|
+
try {
|
|
17
|
+
await this.execScript(scriptPath, ctx);
|
|
18
|
+
log.info({ hook: hookName, sessionId: ctx.sessionId }, 'Hook completed');
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
log.error({ err, hook: hookName, sessionId: ctx.sessionId }, 'Hook failed');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
execScript(scriptPath, ctx) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
const absPath = scriptPath.startsWith('/')
|
|
27
|
+
? scriptPath
|
|
28
|
+
: `${this.projectDir}/${scriptPath}`;
|
|
29
|
+
const env = {
|
|
30
|
+
...process.env,
|
|
31
|
+
HOOK_SESSION_ID: ctx.sessionId,
|
|
32
|
+
HOOK_OPENCODE_URL: ctx.opencodeUrl,
|
|
33
|
+
};
|
|
34
|
+
// Pass additional context as HOOK_<KEY> env vars
|
|
35
|
+
for (const [key, value] of Object.entries(ctx)) {
|
|
36
|
+
if (value !== undefined) {
|
|
37
|
+
env[`HOOK_${key.toUpperCase()}`] = value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const child = spawn(absPath, [], {
|
|
41
|
+
env,
|
|
42
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
43
|
+
timeout: 30000,
|
|
44
|
+
});
|
|
45
|
+
let stdout = '';
|
|
46
|
+
let stderr = '';
|
|
47
|
+
child.stdout?.on('data', (data) => {
|
|
48
|
+
stdout += data.toString();
|
|
49
|
+
});
|
|
50
|
+
child.stderr?.on('data', (data) => {
|
|
51
|
+
stderr += data.toString();
|
|
52
|
+
});
|
|
53
|
+
child.on('close', (code) => {
|
|
54
|
+
if (code === 0) {
|
|
55
|
+
if (stdout.trim())
|
|
56
|
+
log.info({ stdout: stdout.trim() }, 'Hook stdout');
|
|
57
|
+
resolve();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
log.warn({ code, stderr: stderr.trim(), stdout: stdout.trim() }, 'Hook exited non-zero');
|
|
61
|
+
resolve(); // Don't reject — hook failures shouldn't break the main flow
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
child.on('error', (err) => {
|
|
65
|
+
log.warn({ err }, 'Failed to spawn hook script');
|
|
66
|
+
resolve(); // Don't reject
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=hook-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-manager.js","sourceRoot":"","sources":["../../src/core/hook-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,28 @@ import type { FeishuConfig, FeishuMessage } from '../core/types.js';
|
|
|
2
2
|
import type { SessionManager } from '../core/session-manager.js';
|
|
3
3
|
import type { FeishuAPI } from '../feishu/api.js';
|
|
4
4
|
import type { OpenCodeClient } from '../opencode/client.js';
|
|
5
|
+
import type { DocService } from '../services/doc-service.js';
|
|
5
6
|
export declare class MessageHandler {
|
|
6
7
|
private config;
|
|
7
8
|
private sessionManager;
|
|
8
9
|
private feishuApi;
|
|
9
10
|
private opencode;
|
|
10
|
-
|
|
11
|
+
private dedup;
|
|
12
|
+
private fileDownloader;
|
|
13
|
+
private docService?;
|
|
14
|
+
private botName;
|
|
15
|
+
private thinkingTimers;
|
|
16
|
+
constructor(config: FeishuConfig, sessionManager: SessionManager, feishuApi: FeishuAPI, opencode: OpenCodeClient, docService?: DocService, botName?: string);
|
|
11
17
|
handleMessage(message: FeishuMessage): Promise<void>;
|
|
18
|
+
private stopThinkingAnimation;
|
|
19
|
+
/**
|
|
20
|
+
* Detect document creation intent from user message.
|
|
21
|
+
* Supports patterns like: "创建文档 XXX", "新建一个文档", "写个文档"
|
|
22
|
+
*/
|
|
23
|
+
private detectDocCreationIntent;
|
|
24
|
+
/**
|
|
25
|
+
* Unified media download handler for images, files, audio, and video.
|
|
26
|
+
*/
|
|
27
|
+
private downloadMedia;
|
|
12
28
|
}
|
|
13
29
|
//# sourceMappingURL=message-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-handler.d.ts","sourceRoot":"","sources":["../../src/core/message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"message-handler.d.ts","sourceRoot":"","sources":["../../src/core/message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAQ7D,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAqD;gBAGzE,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,cAAc,EACxB,UAAU,CAAC,EAAE,UAAU,EACvB,OAAO,SAAO;IAYV,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA4Q1D,OAAO,CAAC,qBAAqB;IAQ7B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;YACW,aAAa;CAsB5B"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FeishuCard } from '../feishu/card.js';
|
|
2
|
+
import { MessageDeduplicator } from './dedup.js';
|
|
3
|
+
import { FileDownloader } from './file-downloader.js';
|
|
2
4
|
import { createLogger } from './logger.js';
|
|
3
5
|
const log = createLogger('MessageHandler');
|
|
4
6
|
export class MessageHandler {
|
|
@@ -6,11 +8,20 @@ export class MessageHandler {
|
|
|
6
8
|
sessionManager;
|
|
7
9
|
feishuApi;
|
|
8
10
|
opencode;
|
|
9
|
-
|
|
11
|
+
dedup;
|
|
12
|
+
fileDownloader;
|
|
13
|
+
docService;
|
|
14
|
+
botName;
|
|
15
|
+
thinkingTimers = new Map();
|
|
16
|
+
constructor(config, sessionManager, feishuApi, opencode, docService, botName = '点点') {
|
|
10
17
|
this.config = config;
|
|
11
18
|
this.sessionManager = sessionManager;
|
|
12
19
|
this.feishuApi = feishuApi;
|
|
13
20
|
this.opencode = opencode;
|
|
21
|
+
this.docService = docService;
|
|
22
|
+
this.botName = botName;
|
|
23
|
+
this.dedup = new MessageDeduplicator(config.dedupTtl || 600_000);
|
|
24
|
+
this.fileDownloader = new FileDownloader();
|
|
14
25
|
}
|
|
15
26
|
async handleMessage(message) {
|
|
16
27
|
try {
|
|
@@ -30,6 +41,11 @@ export class MessageHandler {
|
|
|
30
41
|
log.info('Skipping message from app/bot itself');
|
|
31
42
|
return;
|
|
32
43
|
}
|
|
44
|
+
// Deduplicate: skip if we've seen this message before
|
|
45
|
+
if (this.dedup.isDuplicate(message.message_id)) {
|
|
46
|
+
log.info({ messageId: message.message_id }, 'Duplicate message, skipping');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
33
49
|
const chatId = message.chat_id;
|
|
34
50
|
const chatType = message.chat_type;
|
|
35
51
|
log.info({ chatType, sender: message.sender.sender_id?.union_id || 'unknown' }, 'Processing message');
|
|
@@ -69,16 +85,42 @@ export class MessageHandler {
|
|
|
69
85
|
await this.feishuApi.sendText(chatId, '⏳ 正在处理上一条消息,请稍候...');
|
|
70
86
|
return;
|
|
71
87
|
}
|
|
72
|
-
//
|
|
88
|
+
// Resolve sender name (with cache)
|
|
89
|
+
const senderUnionId = message.sender.sender_id?.union_id || 'unknown';
|
|
90
|
+
const senderName = await this.feishuApi.getUserName(senderUnionId);
|
|
91
|
+
log.info({ senderName, senderId: senderUnionId }, 'Resolved sender name');
|
|
92
|
+
// Extract content and download files based on message type
|
|
73
93
|
let text = '';
|
|
94
|
+
const files = [];
|
|
74
95
|
try {
|
|
75
96
|
const content = JSON.parse(message.content);
|
|
76
|
-
|
|
77
|
-
|
|
97
|
+
switch (message.message_type) {
|
|
98
|
+
case 'text':
|
|
99
|
+
text = content.text || '';
|
|
100
|
+
break;
|
|
101
|
+
case 'image':
|
|
102
|
+
text = await this.downloadMedia(message.message_id, content.image_key, 'image', 'image.jpg', 'image/jpeg', '图片');
|
|
103
|
+
break;
|
|
104
|
+
case 'file':
|
|
105
|
+
text = await this.downloadMedia(message.message_id, content.file_key, 'file', content.file_name || 'unknown', 'application/octet-stream', '文件');
|
|
106
|
+
break;
|
|
107
|
+
case 'audio':
|
|
108
|
+
text = await this.downloadMedia(message.message_id, content.file_key, 'file', 'audio.opus', 'audio/opus', '语音');
|
|
109
|
+
break;
|
|
110
|
+
case 'media':
|
|
111
|
+
text = await this.downloadMedia(message.message_id, content.file_key, 'file', content.file_name || 'video.mp4', 'video/mp4', '视频');
|
|
112
|
+
break;
|
|
113
|
+
case 'sticker':
|
|
114
|
+
text = `[表情消息]`;
|
|
115
|
+
break;
|
|
116
|
+
default:
|
|
117
|
+
text = `[不支持的消息类型: ${message.message_type}]`;
|
|
118
|
+
}
|
|
119
|
+
log.info({ text: text.substring(0, 100), type: message.message_type, files: files.length }, 'Extracted content');
|
|
78
120
|
}
|
|
79
121
|
catch {
|
|
80
|
-
log.warn({ content: message.content }, 'Failed to parse message content');
|
|
81
|
-
text =
|
|
122
|
+
log.warn({ content: message.content, type: message.message_type }, 'Failed to parse message content');
|
|
123
|
+
text = `[不支持的消息类型: ${message.message_type}]`;
|
|
82
124
|
}
|
|
83
125
|
// Remove @mention from text if present
|
|
84
126
|
if (message.mentions) {
|
|
@@ -87,11 +129,32 @@ export class MessageHandler {
|
|
|
87
129
|
}
|
|
88
130
|
log.info({ text: text.substring(0, 100) }, 'Text after removing mentions');
|
|
89
131
|
}
|
|
132
|
+
// Prepend sender name in group chats for context
|
|
133
|
+
if (chatType === 'group' && senderName && senderName !== senderUnionId) {
|
|
134
|
+
text = `[${senderName}]: ${text}`;
|
|
135
|
+
}
|
|
90
136
|
if (!text) {
|
|
91
137
|
log.info('Empty text content, ignoring');
|
|
92
138
|
return;
|
|
93
139
|
}
|
|
94
140
|
log.info({ chatType, chatId, text: text.substring(0, 100) }, 'Message content');
|
|
141
|
+
// Check for document creation intent
|
|
142
|
+
if (this.docService) {
|
|
143
|
+
const docIntent = this.detectDocCreationIntent(text);
|
|
144
|
+
if (docIntent.intent) {
|
|
145
|
+
log.info({ title: docIntent.title }, 'Document creation intent detected');
|
|
146
|
+
try {
|
|
147
|
+
const doc = await this.docService.createDocumentFromMarkdown(docIntent.title, `# ${docIntent.title}\n\n> 由 OpenCode AI 助手创建\n\n请在此处编辑文档内容...\n`);
|
|
148
|
+
await this.feishuApi.sendText(chatId, `✅ 已为您创建文档「${doc.title}」\n🔗 ${doc.url}\n\n您可以点击链接查看和编辑文档。`);
|
|
149
|
+
// Continue to OpenCode to let AI generate a friendly response
|
|
150
|
+
text = `${text}\n\n[系统提示:已为用户创建飞书文档「${doc.title}」,链接:${doc.url}。请告诉用户文档已创建,并简要说明可以如何使用。]`;
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
log.error({ err, title: docIntent.title }, 'Failed to create document');
|
|
154
|
+
await this.feishuApi.sendText(chatId, '❌ 创建文档失败,请确认已开通文档相关权限(docx:document、docx:document:readonly)');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
95
158
|
// Atomically check and set busy status to prevent race conditions
|
|
96
159
|
const currentSession = this.sessionManager.getSession(chatId);
|
|
97
160
|
if (!currentSession || currentSession.status === 'busy') {
|
|
@@ -99,10 +162,38 @@ export class MessageHandler {
|
|
|
99
162
|
return;
|
|
100
163
|
}
|
|
101
164
|
this.sessionManager.updateStatus(chatId, 'busy');
|
|
165
|
+
// Show thinking card immediately before sending prompt
|
|
166
|
+
if (!this.config.showProcess) {
|
|
167
|
+
const dots = ['.', '..', '...', '....'];
|
|
168
|
+
let frame = 0;
|
|
169
|
+
const thinkingCard = FeishuCard.createThinkingCard(this.botName, dots[frame]);
|
|
170
|
+
const msg = await this.feishuApi.sendCard(chatId, thinkingCard);
|
|
171
|
+
if (msg?.message_id) {
|
|
172
|
+
this.sessionManager.setCurrentMessage(chatId, msg.message_id);
|
|
173
|
+
// Animate the ellipsis until content arrives
|
|
174
|
+
const timer = setInterval(async () => {
|
|
175
|
+
const session = this.sessionManager.getSession(chatId);
|
|
176
|
+
if (!session?.currentMessageId || !this.thinkingTimers.has(chatId)) {
|
|
177
|
+
clearInterval(timer);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (session.currentContent) {
|
|
181
|
+
this.stopThinkingAnimation(chatId);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
frame = (frame + 1) % dots.length;
|
|
185
|
+
try {
|
|
186
|
+
await this.feishuApi.updateCard(session.currentMessageId, FeishuCard.createThinkingCard(this.botName, dots[frame]));
|
|
187
|
+
}
|
|
188
|
+
catch { /* best-effort */ }
|
|
189
|
+
}, 500);
|
|
190
|
+
this.thinkingTimers.set(chatId, timer);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
102
193
|
// Send message to OpenCode
|
|
103
194
|
try {
|
|
104
|
-
log.info({ sessionId: session.id }, 'Sending prompt to OpenCode');
|
|
105
|
-
await this.opencode.sendPrompt(session.id, text);
|
|
195
|
+
log.info({ sessionId: session.id, files: files.length }, 'Sending prompt to OpenCode');
|
|
196
|
+
await this.opencode.sendPrompt(session.id, text, files.length > 0 ? files : undefined);
|
|
106
197
|
log.info('Prompt sent successfully');
|
|
107
198
|
}
|
|
108
199
|
catch (err) {
|
|
@@ -110,6 +201,7 @@ export class MessageHandler {
|
|
|
110
201
|
await this.feishuApi.sendCard(chatId, FeishuCard.createErrorCard(`发送消息失败: ${err instanceof Error ? err.message : String(err)}`));
|
|
111
202
|
this.sessionManager.updateStatus(chatId, 'idle');
|
|
112
203
|
this.sessionManager.clearCurrentMessage(chatId);
|
|
204
|
+
this.stopThinkingAnimation(chatId);
|
|
113
205
|
}
|
|
114
206
|
}
|
|
115
207
|
catch (err) {
|
|
@@ -122,5 +214,56 @@ export class MessageHandler {
|
|
|
122
214
|
}
|
|
123
215
|
}
|
|
124
216
|
}
|
|
217
|
+
stopThinkingAnimation(chatId) {
|
|
218
|
+
const timer = this.thinkingTimers.get(chatId);
|
|
219
|
+
if (timer) {
|
|
220
|
+
clearInterval(timer);
|
|
221
|
+
this.thinkingTimers.delete(chatId);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Detect document creation intent from user message.
|
|
226
|
+
* Supports patterns like: "创建文档 XXX", "新建一个文档", "写个文档"
|
|
227
|
+
*/
|
|
228
|
+
detectDocCreationIntent(text) {
|
|
229
|
+
const patterns = [
|
|
230
|
+
/(?:创建|新建|写个?)(?:一个|个)?(?:飞书)?(?:云)?文档[,::]?\s*["「『【]([^"」』】]+)["」』】]/i,
|
|
231
|
+
/(?:创建|新建|写个?)(?:一个|个)?(?:飞书)?(?:云)?文档[,::]?\s*(.+?)(?:\n|$)/i,
|
|
232
|
+
/(?:创建|新建|写个?)(?:一个|个)?(.+?)(?:的|的)?(?:飞书)?(?:云)?文档/i,
|
|
233
|
+
/(?:帮我|请)?(?:创建|新建|写)(?:一个|个)?(.+)/i,
|
|
234
|
+
];
|
|
235
|
+
for (const pattern of patterns) {
|
|
236
|
+
const match = text.match(pattern);
|
|
237
|
+
if (match && match[1]) {
|
|
238
|
+
const title = match[1].trim().replace(/^(?:一个|个|这份|这个|的)\s*/, '');
|
|
239
|
+
if (title && title.length > 0 && title.length < 100) {
|
|
240
|
+
return { intent: true, title };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Simple keyword detection as fallback
|
|
245
|
+
if (/^(?:创建|新建|写个?)文档/.test(text.trim())) {
|
|
246
|
+
return { intent: true, title: '未命名文档' };
|
|
247
|
+
}
|
|
248
|
+
return { intent: false, title: '' };
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Unified media download handler for images, files, audio, and video.
|
|
252
|
+
*/
|
|
253
|
+
async downloadMedia(messageId, fileKey, resourceType, fileName, mimeType, typeLabel) {
|
|
254
|
+
if (!fileKey) {
|
|
255
|
+
return `[${typeLabel}消息]`;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
log.info({ messageId, fileKey, fileName }, `Downloading ${typeLabel}...`);
|
|
259
|
+
const buffer = await this.feishuApi.downloadMedia(messageId, fileKey, resourceType);
|
|
260
|
+
const downloaded = await this.fileDownloader.saveBuffer(buffer, fileName, mimeType);
|
|
261
|
+
return `[${typeLabel}已上传: ${downloaded.filePath}]`;
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
log.error({ err, messageId, fileKey }, `Failed to download ${typeLabel}`);
|
|
265
|
+
return `[${typeLabel}消息(下载失败)]`;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
125
268
|
}
|
|
126
269
|
//# sourceMappingURL=message-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../src/core/message-handler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;AAE3C,MAAM,OAAO,cAAc;IACjB,MAAM,CAAe;IACrB,cAAc,CAAiB;IAC/B,SAAS,CAAY;IACrB,QAAQ,CAAiB;IAEjC,YACE,MAAoB,EACpB,cAA8B,EAC9B,SAAoB,EACpB,QAAwB;QAExB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAsB;QACxC,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,WAAW;gBACxC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;aAC5C,EAAE,kBAAkB,CAAC,CAAC;YAEvB,sBAAsB;YACtB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,GAAG,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YAED,oCAAoC;YACpC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;gBACzC,GAAG,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;gBACjD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;YAEnC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,IAAI,SAAS,EAAE,EAAE,oBAAoB,CAAC,CAAC;YAEtG,uCAAuC;YACvC,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;gBACvD,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,mBAAmB,CAAC,CAAC;gBAC9D,qDAAqD;gBACrD,yDAAyD;gBACzD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;gBAChD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,EAAE,OAAO,KAAK,SAAS,CAChD,CAAC;gBAEF,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,2CAA2C,CAAC,CAAC;oBAClE,OAAO;gBACT,CAAC;gBACD,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAChC,CAAC;YAED,qBAAqB;YACrB,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBACnE,GAAG,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;gBACpC,OAAO;YACT,CAAC;YAED,kBAAkB;YAClB,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC;gBACpD,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC3D,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,CAAC,CAAC;oBAClD,OAAO;gBACT,CAAC;YACH,CAAC;YAED,wBAAwB;YACxB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,6BAA6B,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC/E,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC;YAE7E,kDAAkD;YAClD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9B,GAAG,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;gBAClD,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAC3B,MAAM,EACN,oBAAoB,CACrB,CAAC;gBACF,OAAO;YACT,CAAC;YAED,uBAAuB;YACvB,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC5C,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC1B,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,iCAAiC,CAAC,CAAC;gBAC1E,IAAI,GAAG,YAAY,CAAC;YACtB,CAAC;YAED,uCAAuC;YACvC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACvC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC9C,CAAC;gBACD,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,8BAA8B,CAAC,CAAC;YAC7E,CAAC;YAED,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,GAAG,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;gBACzC,OAAO;YACT,CAAC;YAED,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;YAEhF,kEAAkE;YAClE,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC9D,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBACxD,GAAG,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAEjD,2BAA2B;YAC3B,IAAI,CAAC;gBACH,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,4BAA4B,CAAC,CAAC;gBAClE,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBACjD,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACvC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,uBAAuB,CAAC,CAAC;gBAE5C,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAC3B,MAAM,EACN,UAAU,CAAC,eAAe,CACxB,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9D,CACF,CAAC;gBAEF,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACjD,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAClD,CAAC;QAEH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;YAE7C,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAC3B,OAAO,CAAC,OAAO,EACf,iBAAiB,CAClB,CAAC;YACJ,CAAC;YAAC,OAAO,OAAO,EAAE,CAAC;gBACjB,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,8BAA8B,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../src/core/message-handler.ts"],"names":[],"mappings":"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"}
|