beecork 1.7.1 → 2.0.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/README.md +52 -111
- package/dist/index.js +1394 -581
- package/package.json +26 -54
- package/dist/capabilities/index.d.ts +0 -3
- package/dist/capabilities/index.js +0 -2
- package/dist/capabilities/manager.d.ts +0 -13
- package/dist/capabilities/manager.js +0 -115
- package/dist/capabilities/packs.d.ts +0 -2
- package/dist/capabilities/packs.js +0 -54
- package/dist/capabilities/types.d.ts +0 -21
- package/dist/capabilities/types.js +0 -1
- package/dist/channels/admin.d.ts +0 -10
- package/dist/channels/admin.js +0 -20
- package/dist/channels/command-handler.d.ts +0 -19
- package/dist/channels/command-handler.js +0 -235
- package/dist/channels/discord.d.ts +0 -17
- package/dist/channels/discord.js +0 -266
- package/dist/channels/index.d.ts +0 -7
- package/dist/channels/index.js +0 -6
- package/dist/channels/loader.d.ts +0 -7
- package/dist/channels/loader.js +0 -87
- package/dist/channels/pipeline.d.ts +0 -50
- package/dist/channels/pipeline.js +0 -92
- package/dist/channels/registry.d.ts +0 -36
- package/dist/channels/registry.js +0 -80
- package/dist/channels/send-helpers.d.ts +0 -19
- package/dist/channels/send-helpers.js +0 -21
- package/dist/channels/telegram.d.ts +0 -47
- package/dist/channels/telegram.js +0 -649
- package/dist/channels/types.d.ts +0 -41
- package/dist/channels/types.js +0 -1
- package/dist/channels/voice-state.d.ts +0 -29
- package/dist/channels/voice-state.js +0 -45
- package/dist/channels/webhook.d.ts +0 -16
- package/dist/channels/webhook.js +0 -222
- package/dist/channels/whatsapp.d.ts +0 -28
- package/dist/channels/whatsapp.js +0 -323
- package/dist/cli/capabilities.d.ts +0 -3
- package/dist/cli/capabilities.js +0 -72
- package/dist/cli/channel.d.ts +0 -3
- package/dist/cli/channel.js +0 -202
- package/dist/cli/commands.d.ts +0 -15
- package/dist/cli/commands.js +0 -279
- package/dist/cli/doctor.d.ts +0 -1
- package/dist/cli/doctor.js +0 -208
- package/dist/cli/handoff.d.ts +0 -8
- package/dist/cli/handoff.js +0 -33
- package/dist/cli/helpers.d.ts +0 -2
- package/dist/cli/helpers.js +0 -21
- package/dist/cli/mcp.d.ts +0 -3
- package/dist/cli/mcp.js +0 -47
- package/dist/cli/media.d.ts +0 -2
- package/dist/cli/media.js +0 -125
- package/dist/cli/setup.d.ts +0 -1
- package/dist/cli/setup.js +0 -239
- package/dist/cli/store.d.ts +0 -3
- package/dist/cli/store.js +0 -108
- package/dist/config.d.ts +0 -11
- package/dist/config.js +0 -115
- package/dist/cron/scheduler.d.ts +0 -22
- package/dist/cron/scheduler.js +0 -220
- package/dist/cron/store.d.ts +0 -12
- package/dist/cron/store.js +0 -83
- package/dist/daemon.d.ts +0 -1
- package/dist/daemon.js +0 -345
- package/dist/dashboard/html.d.ts +0 -1
- package/dist/dashboard/html.js +0 -849
- package/dist/dashboard/routes.d.ts +0 -17
- package/dist/dashboard/routes.js +0 -623
- package/dist/dashboard/server.d.ts +0 -1
- package/dist/dashboard/server.js +0 -104
- package/dist/db/connection.d.ts +0 -29
- package/dist/db/connection.js +0 -37
- package/dist/db/index.d.ts +0 -14
- package/dist/db/index.js +0 -127
- package/dist/db/migrations.d.ts +0 -2
- package/dist/db/migrations.js +0 -384
- package/dist/delegation/manager.d.ts +0 -18
- package/dist/delegation/manager.js +0 -89
- package/dist/index.d.ts +0 -2
- package/dist/knowledge/index.d.ts +0 -2
- package/dist/knowledge/index.js +0 -1
- package/dist/knowledge/manager.d.ts +0 -17
- package/dist/knowledge/manager.js +0 -160
- package/dist/knowledge/types.d.ts +0 -7
- package/dist/knowledge/types.js +0 -1
- package/dist/machines/forwarder.d.ts +0 -7
- package/dist/machines/forwarder.js +0 -35
- package/dist/machines/index.d.ts +0 -1
- package/dist/machines/index.js +0 -1
- package/dist/machines/registry.d.ts +0 -15
- package/dist/machines/registry.js +0 -46
- package/dist/mcp/handlers.d.ts +0 -37
- package/dist/mcp/handlers.js +0 -520
- package/dist/mcp/server.d.ts +0 -2
- package/dist/mcp/server.js +0 -86
- package/dist/mcp/tool-definitions.d.ts +0 -1225
- package/dist/mcp/tool-definitions.js +0 -412
- package/dist/mcp/validate.d.ts +0 -23
- package/dist/mcp/validate.js +0 -65
- package/dist/media/factory.d.ts +0 -6
- package/dist/media/factory.js +0 -36
- package/dist/media/generators/dall-e.d.ts +0 -10
- package/dist/media/generators/dall-e.js +0 -41
- package/dist/media/generators/elevenlabs-music.d.ts +0 -9
- package/dist/media/generators/elevenlabs-music.js +0 -34
- package/dist/media/generators/elevenlabs-sfx.d.ts +0 -9
- package/dist/media/generators/elevenlabs-sfx.js +0 -33
- package/dist/media/generators/kling.d.ts +0 -9
- package/dist/media/generators/kling.js +0 -47
- package/dist/media/generators/lyria.d.ts +0 -10
- package/dist/media/generators/lyria.js +0 -41
- package/dist/media/generators/nano-banana.d.ts +0 -10
- package/dist/media/generators/nano-banana.js +0 -45
- package/dist/media/generators/poll-util.d.ts +0 -12
- package/dist/media/generators/poll-util.js +0 -22
- package/dist/media/generators/recraft.d.ts +0 -9
- package/dist/media/generators/recraft.js +0 -52
- package/dist/media/generators/runway.d.ts +0 -9
- package/dist/media/generators/runway.js +0 -49
- package/dist/media/generators/stable-diffusion.d.ts +0 -9
- package/dist/media/generators/stable-diffusion.js +0 -35
- package/dist/media/generators/veo.d.ts +0 -9
- package/dist/media/generators/veo.js +0 -32
- package/dist/media/index.d.ts +0 -6
- package/dist/media/index.js +0 -8
- package/dist/media/loader.d.ts +0 -8
- package/dist/media/loader.js +0 -46
- package/dist/media/store.d.ts +0 -17
- package/dist/media/store.js +0 -69
- package/dist/media/types.d.ts +0 -43
- package/dist/media/types.js +0 -1
- package/dist/memory/extractor.d.ts +0 -5
- package/dist/memory/extractor.js +0 -157
- package/dist/notifications/index.d.ts +0 -4
- package/dist/notifications/index.js +0 -21
- package/dist/notifications/ntfy.d.ts +0 -9
- package/dist/notifications/ntfy.js +0 -25
- package/dist/notifications/pushover.d.ts +0 -9
- package/dist/notifications/pushover.js +0 -26
- package/dist/notifications/types.d.ts +0 -5
- package/dist/notifications/types.js +0 -1
- package/dist/notifications/webhook-provider.d.ts +0 -9
- package/dist/notifications/webhook-provider.js +0 -24
- package/dist/observability/analytics.d.ts +0 -30
- package/dist/observability/analytics.js +0 -118
- package/dist/pipe/anthropic-client.d.ts +0 -9
- package/dist/pipe/anthropic-client.js +0 -50
- package/dist/pipe/brain.d.ts +0 -16
- package/dist/pipe/brain.js +0 -89
- package/dist/pipe/memory-store.d.ts +0 -8
- package/dist/pipe/memory-store.js +0 -39
- package/dist/pipe/project-scanner.d.ts +0 -6
- package/dist/pipe/project-scanner.js +0 -26
- package/dist/pipe/types.d.ts +0 -34
- package/dist/pipe/types.js +0 -1
- package/dist/projects/index.d.ts +0 -4
- package/dist/projects/index.js +0 -2
- package/dist/projects/manager.d.ts +0 -13
- package/dist/projects/manager.js +0 -166
- package/dist/projects/router.d.ts +0 -17
- package/dist/projects/router.js +0 -246
- package/dist/projects/types.d.ts +0 -19
- package/dist/projects/types.js +0 -1
- package/dist/service/install.d.ts +0 -4
- package/dist/service/install.js +0 -146
- package/dist/service/templates.d.ts +0 -4
- package/dist/service/templates.js +0 -52
- package/dist/service/windows.d.ts +0 -8
- package/dist/service/windows.js +0 -59
- package/dist/session/budget-guard.d.ts +0 -20
- package/dist/session/budget-guard.js +0 -31
- package/dist/session/circuit-breaker.d.ts +0 -19
- package/dist/session/circuit-breaker.js +0 -91
- package/dist/session/context-compactor.d.ts +0 -32
- package/dist/session/context-compactor.js +0 -45
- package/dist/session/context-monitor.d.ts +0 -15
- package/dist/session/context-monitor.js +0 -44
- package/dist/session/handoff.d.ts +0 -21
- package/dist/session/handoff.js +0 -50
- package/dist/session/manager.d.ts +0 -60
- package/dist/session/manager.js +0 -416
- package/dist/session/memory-store.d.ts +0 -29
- package/dist/session/memory-store.js +0 -45
- package/dist/session/message-queue.d.ts +0 -28
- package/dist/session/message-queue.js +0 -52
- package/dist/session/pending-dispatcher.d.ts +0 -31
- package/dist/session/pending-dispatcher.js +0 -120
- package/dist/session/pending-store.d.ts +0 -60
- package/dist/session/pending-store.js +0 -118
- package/dist/session/stale-session.d.ts +0 -31
- package/dist/session/stale-session.js +0 -45
- package/dist/session/subprocess.d.ts +0 -32
- package/dist/session/subprocess.js +0 -230
- package/dist/session/tab-store.d.ts +0 -28
- package/dist/session/tab-store.js +0 -78
- package/dist/session/tool-classifier.d.ts +0 -4
- package/dist/session/tool-classifier.js +0 -56
- package/dist/tasks/scheduler.d.ts +0 -45
- package/dist/tasks/scheduler.js +0 -329
- package/dist/tasks/store.d.ts +0 -11
- package/dist/tasks/store.js +0 -103
- package/dist/timeline/index.d.ts +0 -3
- package/dist/timeline/index.js +0 -2
- package/dist/timeline/logger.d.ts +0 -8
- package/dist/timeline/logger.js +0 -11
- package/dist/timeline/query.d.ts +0 -11
- package/dist/timeline/query.js +0 -67
- package/dist/timeline/types.d.ts +0 -12
- package/dist/timeline/types.js +0 -1
- package/dist/types.d.ts +0 -225
- package/dist/types.js +0 -3
- package/dist/users/index.d.ts +0 -2
- package/dist/users/index.js +0 -1
- package/dist/users/service.d.ts +0 -17
- package/dist/users/service.js +0 -46
- package/dist/util/auto-heal.d.ts +0 -43
- package/dist/util/auto-heal.js +0 -107
- package/dist/util/install-info.d.ts +0 -37
- package/dist/util/install-info.js +0 -80
- package/dist/util/logger.d.ts +0 -18
- package/dist/util/logger.js +0 -118
- package/dist/util/paths.d.ts +0 -13
- package/dist/util/paths.js +0 -55
- package/dist/util/platform.d.ts +0 -2
- package/dist/util/platform.js +0 -11
- package/dist/util/progress.d.ts +0 -34
- package/dist/util/progress.js +0 -133
- package/dist/util/rate-limiter.d.ts +0 -14
- package/dist/util/rate-limiter.js +0 -50
- package/dist/util/retry.d.ts +0 -2
- package/dist/util/retry.js +0 -18
- package/dist/util/text.d.ts +0 -32
- package/dist/util/text.js +0 -101
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -4
- package/dist/voice/index.d.ts +0 -17
- package/dist/voice/index.js +0 -42
- package/dist/voice/stt.d.ts +0 -16
- package/dist/voice/stt.js +0 -57
- package/dist/voice/tts.d.ts +0 -23
- package/dist/voice/tts.js +0 -84
- package/dist/watchers/evaluator.d.ts +0 -5
- package/dist/watchers/evaluator.js +0 -45
- package/dist/watchers/index.d.ts +0 -4
- package/dist/watchers/index.js +0 -3
- package/dist/watchers/scheduler.d.ts +0 -20
- package/dist/watchers/scheduler.js +0 -183
- package/dist/watchers/store.d.ts +0 -10
- package/dist/watchers/store.js +0 -56
- package/dist/watchers/types.d.ts +0 -15
- package/dist/watchers/types.js +0 -1
- package/scripts/postinstall.mjs +0 -50
package/dist/util/logger.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { getLogsDir } from './paths.js';
|
|
4
|
-
const LEVEL_PRIORITY = {
|
|
5
|
-
debug: 0,
|
|
6
|
-
info: 1,
|
|
7
|
-
warn: 2,
|
|
8
|
-
error: 3,
|
|
9
|
-
};
|
|
10
|
-
// Patterns that should never reach disk or stdout. Each channel uses a per-call
|
|
11
|
-
// sanitizer too (defense-in-depth), but the Logger is the last line of defense
|
|
12
|
-
// for any third-party error object that happens to embed a secret in its message.
|
|
13
|
-
const REDACTION_PATTERNS = [
|
|
14
|
-
{ re: /bot\d+:[A-Za-z0-9_-]+/g, replacement: 'bot<REDACTED>' }, // Telegram bot token
|
|
15
|
-
];
|
|
16
|
-
function redact(s) {
|
|
17
|
-
let out = s;
|
|
18
|
-
for (const { re, replacement } of REDACTION_PATTERNS)
|
|
19
|
-
out = out.replace(re, replacement);
|
|
20
|
-
return out;
|
|
21
|
-
}
|
|
22
|
-
const ROTATE_BYTES = 10 * 1024 * 1024;
|
|
23
|
-
class Logger {
|
|
24
|
-
minLevel = 'info';
|
|
25
|
-
logFile = null;
|
|
26
|
-
stream = null;
|
|
27
|
-
bytesWritten = 0;
|
|
28
|
-
setLevel(level) {
|
|
29
|
-
this.minLevel = level;
|
|
30
|
-
}
|
|
31
|
-
setLogFile(name) {
|
|
32
|
-
const dir = getLogsDir();
|
|
33
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
34
|
-
this.logFile = path.join(dir, name);
|
|
35
|
-
this.stream = fs.createWriteStream(this.logFile, { flags: 'a' });
|
|
36
|
-
// Seed bytesWritten from the existing file size so we don't reset the
|
|
37
|
-
// rotation counter on every daemon restart.
|
|
38
|
-
try {
|
|
39
|
-
this.bytesWritten = fs.statSync(this.logFile).size;
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
this.bytesWritten = 0;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
write(level, msg, ...args) {
|
|
46
|
-
if (LEVEL_PRIORITY[level] < LEVEL_PRIORITY[this.minLevel])
|
|
47
|
-
return;
|
|
48
|
-
const timestamp = new Date().toISOString();
|
|
49
|
-
const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
|
|
50
|
-
const raw = args.length > 0
|
|
51
|
-
? `${prefix} ${msg} ${args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ')}`
|
|
52
|
-
: `${prefix} ${msg}`;
|
|
53
|
-
const line = redact(raw);
|
|
54
|
-
if (this.stream) {
|
|
55
|
-
const out = line + '\n';
|
|
56
|
-
this.stream.write(out);
|
|
57
|
-
this.bytesWritten += out.length;
|
|
58
|
-
if (this.bytesWritten > ROTATE_BYTES)
|
|
59
|
-
this.checkRotation();
|
|
60
|
-
}
|
|
61
|
-
if (level === 'error') {
|
|
62
|
-
console.error(line);
|
|
63
|
-
}
|
|
64
|
-
else if (level === 'warn') {
|
|
65
|
-
console.warn(line);
|
|
66
|
-
}
|
|
67
|
-
else if (level !== 'debug') {
|
|
68
|
-
console.log(line);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
debug(msg, ...args) {
|
|
72
|
-
this.write('debug', msg, ...args);
|
|
73
|
-
}
|
|
74
|
-
info(msg, ...args) {
|
|
75
|
-
this.write('info', msg, ...args);
|
|
76
|
-
}
|
|
77
|
-
warn(msg, ...args) {
|
|
78
|
-
this.write('warn', msg, ...args);
|
|
79
|
-
}
|
|
80
|
-
error(msg, ...args) {
|
|
81
|
-
this.write('error', msg, ...args);
|
|
82
|
-
}
|
|
83
|
-
checkRotation() {
|
|
84
|
-
if (!this.logFile || !this.stream)
|
|
85
|
-
return;
|
|
86
|
-
// bytesWritten-based gate already triggered us; rotate without statSync.
|
|
87
|
-
try {
|
|
88
|
-
this.stream.end();
|
|
89
|
-
const rotated = this.logFile + '.1';
|
|
90
|
-
try {
|
|
91
|
-
fs.unlinkSync(rotated);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
/* not fatal */
|
|
95
|
-
}
|
|
96
|
-
fs.renameSync(this.logFile, rotated);
|
|
97
|
-
this.stream = fs.createWriteStream(this.logFile, { flags: 'a' });
|
|
98
|
-
this.bytesWritten = 0;
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
/* rotation failure shouldn't kill the daemon */
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
close() {
|
|
105
|
-
if (this.stream) {
|
|
106
|
-
this.stream.end();
|
|
107
|
-
this.stream = null;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export const logger = new Logger();
|
|
112
|
-
// Allow operators to bump verbosity at runtime without recompiling.
|
|
113
|
-
// e.g. `BEECORK_LOG_LEVEL=debug beecork start` surfaces every claude subprocess
|
|
114
|
-
// stdout/stderr line via the logger.debug calls.
|
|
115
|
-
const envLevel = process.env.BEECORK_LOG_LEVEL?.toLowerCase();
|
|
116
|
-
if (envLevel === 'debug' || envLevel === 'info' || envLevel === 'warn' || envLevel === 'error') {
|
|
117
|
-
logger.setLevel(envLevel);
|
|
118
|
-
}
|
package/dist/util/paths.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function getBeecorkHome(): string;
|
|
2
|
-
export declare function getConfigPath(): string;
|
|
3
|
-
export declare function getDbPath(): string;
|
|
4
|
-
export declare function getCrontabPath(): string;
|
|
5
|
-
export declare function getMcpConfigPath(): string;
|
|
6
|
-
export declare function getLogsDir(): string;
|
|
7
|
-
export declare function getPidPath(): string;
|
|
8
|
-
export declare function getRuntimeInfoPath(): string;
|
|
9
|
-
export declare function getCronReloadSignalPath(): string;
|
|
10
|
-
export declare function getWatcherReloadSignalPath(): string;
|
|
11
|
-
export declare function getWhatsappSessionPath(): string;
|
|
12
|
-
export declare function ensureBeecorkDirs(): void;
|
|
13
|
-
export declare function expandHome(p: string): string;
|
package/dist/util/paths.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import os from 'node:os';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
const BEECORK_DIR = '.beecork';
|
|
5
|
-
export function getBeecorkHome() {
|
|
6
|
-
return process.env.BEECORK_HOME || path.join(os.homedir(), BEECORK_DIR);
|
|
7
|
-
}
|
|
8
|
-
export function getConfigPath() {
|
|
9
|
-
return path.join(getBeecorkHome(), 'config.json');
|
|
10
|
-
}
|
|
11
|
-
export function getDbPath() {
|
|
12
|
-
return path.join(getBeecorkHome(), 'memory.db');
|
|
13
|
-
}
|
|
14
|
-
export function getCrontabPath() {
|
|
15
|
-
return path.join(getBeecorkHome(), 'crontab.json');
|
|
16
|
-
}
|
|
17
|
-
export function getMcpConfigPath() {
|
|
18
|
-
return path.join(getBeecorkHome(), 'mcp-config.json');
|
|
19
|
-
}
|
|
20
|
-
export function getLogsDir() {
|
|
21
|
-
return path.join(getBeecorkHome(), 'logs');
|
|
22
|
-
}
|
|
23
|
-
export function getPidPath() {
|
|
24
|
-
return path.join(getBeecorkHome(), 'beecork.pid');
|
|
25
|
-
}
|
|
26
|
-
export function getRuntimeInfoPath() {
|
|
27
|
-
return path.join(getBeecorkHome(), 'runtime.json');
|
|
28
|
-
}
|
|
29
|
-
export function getCronReloadSignalPath() {
|
|
30
|
-
return path.join(getBeecorkHome(), '.cron-reload');
|
|
31
|
-
}
|
|
32
|
-
export function getWatcherReloadSignalPath() {
|
|
33
|
-
return path.join(getBeecorkHome(), '.watcher-reload');
|
|
34
|
-
}
|
|
35
|
-
export function getWhatsappSessionPath() {
|
|
36
|
-
return path.join(getBeecorkHome(), 'whatsapp-session');
|
|
37
|
-
}
|
|
38
|
-
export function ensureBeecorkDirs() {
|
|
39
|
-
const home = getBeecorkHome();
|
|
40
|
-
fs.mkdirSync(home, { recursive: true, mode: 0o700 });
|
|
41
|
-
// Upgrade an existing dir that was created with a looser umask before this fix landed.
|
|
42
|
-
try {
|
|
43
|
-
fs.chmodSync(home, 0o700);
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
/* not fatal if mode change fails */
|
|
47
|
-
}
|
|
48
|
-
fs.mkdirSync(getLogsDir(), { recursive: true, mode: 0o700 });
|
|
49
|
-
}
|
|
50
|
-
export function expandHome(p) {
|
|
51
|
-
if (p.startsWith('~/') || p === '~') {
|
|
52
|
-
return path.join(os.homedir(), p.slice(1));
|
|
53
|
-
}
|
|
54
|
-
return p;
|
|
55
|
-
}
|
package/dist/util/platform.d.ts
DELETED
package/dist/util/platform.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
|
-
export function getPlatform() {
|
|
3
|
-
const p = os.platform();
|
|
4
|
-
if (p === 'darwin')
|
|
5
|
-
return 'mac';
|
|
6
|
-
if (p === 'linux')
|
|
7
|
-
return 'linux';
|
|
8
|
-
if (p === 'win32')
|
|
9
|
-
return 'windows';
|
|
10
|
-
throw new Error(`Unsupported platform: ${p}. Beecork supports Mac, Linux, and Windows.`);
|
|
11
|
-
}
|
package/dist/util/progress.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Collects tool use events and sends batched progress updates
|
|
3
|
-
* with escalating intervals and next-update predictions.
|
|
4
|
-
*
|
|
5
|
-
* Schedule: 15s → 30s → 1m → 2m → 3m → 4m → ... (grows by 1m after 2m)
|
|
6
|
-
* Each update tells the user when the next one will come.
|
|
7
|
-
* Works across all channels (Telegram, Discord, WhatsApp, etc.)
|
|
8
|
-
*/
|
|
9
|
-
export declare class ProgressTracker {
|
|
10
|
-
private events;
|
|
11
|
-
private startTime;
|
|
12
|
-
private onReport;
|
|
13
|
-
private timer;
|
|
14
|
-
private tabName;
|
|
15
|
-
private reportCount;
|
|
16
|
-
private readonly intervals;
|
|
17
|
-
constructor(tabName: string, onReport: (message: string) => void);
|
|
18
|
-
/** Record a tool use event */
|
|
19
|
-
record(toolName: string, toolInput: Record<string, unknown>): void;
|
|
20
|
-
/** Stop the timer (called when task finishes) */
|
|
21
|
-
stop(): void;
|
|
22
|
-
/** Get the interval for the current report number */
|
|
23
|
-
private getInterval;
|
|
24
|
-
/** Format a duration in ms to a human-readable string */
|
|
25
|
-
private formatDuration;
|
|
26
|
-
/** Schedule the next progress report */
|
|
27
|
-
private scheduleNext;
|
|
28
|
-
/** Flush pending events as a progress report */
|
|
29
|
-
private flush;
|
|
30
|
-
/** Summarize a tool call into a human-readable one-liner */
|
|
31
|
-
private summarizeTool;
|
|
32
|
-
private extractPath;
|
|
33
|
-
private extractCommand;
|
|
34
|
-
}
|
package/dist/util/progress.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { logger } from './logger.js';
|
|
2
|
-
/**
|
|
3
|
-
* Collects tool use events and sends batched progress updates
|
|
4
|
-
* with escalating intervals and next-update predictions.
|
|
5
|
-
*
|
|
6
|
-
* Schedule: 15s → 30s → 1m → 2m → 3m → 4m → ... (grows by 1m after 2m)
|
|
7
|
-
* Each update tells the user when the next one will come.
|
|
8
|
-
* Works across all channels (Telegram, Discord, WhatsApp, etc.)
|
|
9
|
-
*/
|
|
10
|
-
export class ProgressTracker {
|
|
11
|
-
events = [];
|
|
12
|
-
startTime;
|
|
13
|
-
onReport;
|
|
14
|
-
timer = null;
|
|
15
|
-
tabName;
|
|
16
|
-
reportCount = 0;
|
|
17
|
-
// Escalating intervals in ms: 15s, 30s, 1m, 2m, then +1m each
|
|
18
|
-
intervals = [15000, 30000, 60000, 120000];
|
|
19
|
-
constructor(tabName, onReport) {
|
|
20
|
-
this.tabName = tabName;
|
|
21
|
-
this.startTime = Date.now();
|
|
22
|
-
this.onReport = onReport;
|
|
23
|
-
this.scheduleNext();
|
|
24
|
-
}
|
|
25
|
-
/** Record a tool use event */
|
|
26
|
-
record(toolName, toolInput) {
|
|
27
|
-
this.events.push({ tool: toolName, summary: this.summarizeTool(toolName, toolInput) });
|
|
28
|
-
}
|
|
29
|
-
/** Stop the timer (called when task finishes) */
|
|
30
|
-
stop() {
|
|
31
|
-
if (this.timer) {
|
|
32
|
-
clearTimeout(this.timer);
|
|
33
|
-
this.timer = null;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/** Get the interval for the current report number */
|
|
37
|
-
getInterval() {
|
|
38
|
-
if (this.reportCount < this.intervals.length) {
|
|
39
|
-
return this.intervals[this.reportCount];
|
|
40
|
-
}
|
|
41
|
-
// After the fixed intervals, grow by 1 minute each time (3m, 4m, 5m, ...)
|
|
42
|
-
const extraMinutes = this.reportCount - this.intervals.length + 3;
|
|
43
|
-
return extraMinutes * 60000;
|
|
44
|
-
}
|
|
45
|
-
/** Format a duration in ms to a human-readable string */
|
|
46
|
-
formatDuration(ms) {
|
|
47
|
-
const seconds = Math.round(ms / 1000);
|
|
48
|
-
if (seconds < 60)
|
|
49
|
-
return `${seconds}s`;
|
|
50
|
-
const minutes = Math.floor(seconds / 60);
|
|
51
|
-
const secs = seconds % 60;
|
|
52
|
-
return secs > 0 ? `${minutes}m ${secs}s` : `${minutes}m`;
|
|
53
|
-
}
|
|
54
|
-
/** Schedule the next progress report */
|
|
55
|
-
scheduleNext() {
|
|
56
|
-
const interval = this.getInterval();
|
|
57
|
-
this.timer = setTimeout(() => {
|
|
58
|
-
this.flush();
|
|
59
|
-
this.reportCount++;
|
|
60
|
-
this.scheduleNext();
|
|
61
|
-
}, interval);
|
|
62
|
-
}
|
|
63
|
-
/** Flush pending events as a progress report */
|
|
64
|
-
flush() {
|
|
65
|
-
if (this.events.length === 0)
|
|
66
|
-
return;
|
|
67
|
-
const elapsed = Date.now() - this.startTime;
|
|
68
|
-
const elapsedStr = this.formatDuration(elapsed);
|
|
69
|
-
// Build the activity summary
|
|
70
|
-
const lines = [];
|
|
71
|
-
for (const event of this.events) {
|
|
72
|
-
lines.push(` ${event.summary}`);
|
|
73
|
-
}
|
|
74
|
-
this.events = [];
|
|
75
|
-
// Calculate when the next update will come
|
|
76
|
-
const nextInterval = this.getInterval();
|
|
77
|
-
const nextStr = this.formatDuration(nextInterval);
|
|
78
|
-
const message = [
|
|
79
|
-
`\uD83D\uDD04 Working on "${this.tabName}" (${elapsedStr} elapsed)`,
|
|
80
|
-
...lines,
|
|
81
|
-
`\n\u23F3 Next update in ${nextStr} or when finished.`,
|
|
82
|
-
].join('\n');
|
|
83
|
-
try {
|
|
84
|
-
this.onReport(message);
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
logger.warn('Progress report failed:', err);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/** Summarize a tool call into a human-readable one-liner */
|
|
91
|
-
summarizeTool(name, input) {
|
|
92
|
-
switch (name) {
|
|
93
|
-
case 'Write':
|
|
94
|
-
case 'write':
|
|
95
|
-
return `\uD83D\uDCDD Created ${this.extractPath(input)}`;
|
|
96
|
-
case 'Edit':
|
|
97
|
-
case 'edit':
|
|
98
|
-
return `\uD83D\uDCDD Edited ${this.extractPath(input)}`;
|
|
99
|
-
case 'Read':
|
|
100
|
-
case 'read':
|
|
101
|
-
return `\uD83D\uDC41 Read ${this.extractPath(input)}`;
|
|
102
|
-
case 'Bash':
|
|
103
|
-
case 'bash':
|
|
104
|
-
return `\uD83D\uDD27 Ran: ${this.extractCommand(input)}`;
|
|
105
|
-
case 'Glob':
|
|
106
|
-
case 'glob':
|
|
107
|
-
return `\uD83D\uDD0D Searched for files: ${input.pattern || '...'}`;
|
|
108
|
-
case 'Grep':
|
|
109
|
-
case 'grep':
|
|
110
|
-
return `\uD83D\uDD0D Searched code: ${input.pattern || '...'}`;
|
|
111
|
-
case 'WebSearch':
|
|
112
|
-
case 'web_search':
|
|
113
|
-
return `\uD83C\uDF10 Searched: ${input.query || '...'}`;
|
|
114
|
-
case 'WebFetch':
|
|
115
|
-
case 'web_fetch':
|
|
116
|
-
return `\uD83C\uDF10 Fetched: ${input.url || '...'}`;
|
|
117
|
-
default:
|
|
118
|
-
return `\u2699\uFE0F ${name}`;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
extractPath(input) {
|
|
122
|
-
const p = (input.file_path || input.path || input.filePath || '');
|
|
123
|
-
if (p.includes('/'))
|
|
124
|
-
return p.split('/').pop() || p;
|
|
125
|
-
if (p.includes('\\'))
|
|
126
|
-
return p.split('\\').pop() || p;
|
|
127
|
-
return p || '...';
|
|
128
|
-
}
|
|
129
|
-
extractCommand(input) {
|
|
130
|
-
const cmd = (input.command || input.cmd || '');
|
|
131
|
-
return cmd.length > 60 ? cmd.slice(0, 57) + '...' : cmd || '...';
|
|
132
|
-
}
|
|
133
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export declare class RateLimiter {
|
|
2
|
-
private globalLimit;
|
|
3
|
-
private perKeyLimit;
|
|
4
|
-
private windowMs;
|
|
5
|
-
private global;
|
|
6
|
-
private perKey;
|
|
7
|
-
constructor(globalLimit?: number, perKeyLimit?: number, windowMs?: number);
|
|
8
|
-
/** Returns true if the request is allowed */
|
|
9
|
-
check(key: string): boolean;
|
|
10
|
-
}
|
|
11
|
-
/** Shared singleton rate limiter for inbound messages */
|
|
12
|
-
export declare const inboundLimiter: RateLimiter;
|
|
13
|
-
/** Rate limiter for group responses */
|
|
14
|
-
export declare const groupLimiter: RateLimiter;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { logger } from './logger.js';
|
|
2
|
-
export class RateLimiter {
|
|
3
|
-
globalLimit;
|
|
4
|
-
perKeyLimit;
|
|
5
|
-
windowMs;
|
|
6
|
-
global = { count: 0, resetAt: Date.now() + 60000 };
|
|
7
|
-
perKey = new Map();
|
|
8
|
-
constructor(globalLimit = 20, perKeyLimit = 10, windowMs = 60000) {
|
|
9
|
-
this.globalLimit = globalLimit;
|
|
10
|
-
this.perKeyLimit = perKeyLimit;
|
|
11
|
-
this.windowMs = windowMs;
|
|
12
|
-
}
|
|
13
|
-
/** Returns true if the request is allowed */
|
|
14
|
-
check(key) {
|
|
15
|
-
const now = Date.now();
|
|
16
|
-
// Reset global window
|
|
17
|
-
if (now > this.global.resetAt) {
|
|
18
|
-
this.global = { count: 0, resetAt: now + this.windowMs };
|
|
19
|
-
}
|
|
20
|
-
if (this.global.count >= this.globalLimit) {
|
|
21
|
-
logger.warn(`Rate limit: global limit reached (${this.globalLimit}/min)`);
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
// Bound the per-key map so a daemon that has seen many one-off keys
|
|
25
|
-
// (e.g. thousands of Telegram groups over months) doesn't leak memory.
|
|
26
|
-
if (this.perKey.size > 1000) {
|
|
27
|
-
for (const [k, w] of this.perKey) {
|
|
28
|
-
if (now > w.resetAt)
|
|
29
|
-
this.perKey.delete(k);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// Reset per-key window
|
|
33
|
-
let keyWindow = this.perKey.get(key);
|
|
34
|
-
if (!keyWindow || now > keyWindow.resetAt) {
|
|
35
|
-
keyWindow = { count: 0, resetAt: now + this.windowMs };
|
|
36
|
-
this.perKey.set(key, keyWindow);
|
|
37
|
-
}
|
|
38
|
-
if (keyWindow.count >= this.perKeyLimit) {
|
|
39
|
-
logger.warn(`Rate limit: channel ${key} limit reached (${this.perKeyLimit}/min)`);
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
this.global.count++;
|
|
43
|
-
keyWindow.count++;
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
/** Shared singleton rate limiter for inbound messages */
|
|
48
|
-
export const inboundLimiter = new RateLimiter(60, 30);
|
|
49
|
-
/** Rate limiter for group responses */
|
|
50
|
-
export const groupLimiter = new RateLimiter(10, 3, 60000); // 10 global, 3 per group per minute
|
package/dist/util/retry.d.ts
DELETED
package/dist/util/retry.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { logger } from './logger.js';
|
|
2
|
-
/** Retry a function with exponential backoff */
|
|
3
|
-
export async function retryWithBackoff(fn, delays = [1000, 5000, 15000], label = 'operation') {
|
|
4
|
-
let lastError;
|
|
5
|
-
for (let attempt = 0; attempt <= delays.length; attempt++) {
|
|
6
|
-
try {
|
|
7
|
-
return await fn();
|
|
8
|
-
}
|
|
9
|
-
catch (err) {
|
|
10
|
-
lastError = err instanceof Error ? err : new Error(String(err));
|
|
11
|
-
if (attempt < delays.length) {
|
|
12
|
-
logger.warn(`${label} failed (attempt ${attempt + 1}/${delays.length + 1}), retrying in ${delays[attempt]}ms: ${lastError.message}`);
|
|
13
|
-
await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
throw lastError ?? new Error(`${label} failed after ${delays.length + 1} attempts`);
|
|
18
|
-
}
|
package/dist/util/text.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { MediaAttachment } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Shared message-size limits. Single source of truth so caps don't drift
|
|
4
|
-
* between channels, MCP, and dashboard.
|
|
5
|
-
*/
|
|
6
|
-
export declare const MESSAGE_LIMITS: {
|
|
7
|
-
/** Per-chunk send size (Telegram = 4096; other channels chunk to this too). */
|
|
8
|
-
readonly CHUNK: 4096;
|
|
9
|
-
/** HTTP request body cap (webhook + dashboard endpoints). */
|
|
10
|
-
readonly HTTP_BODY: number;
|
|
11
|
-
/** Webhook channel single-message payload. */
|
|
12
|
-
readonly WEBHOOK_PROMPT: 100000;
|
|
13
|
-
/** MCP tool content/message field. Tight because it goes through Claude's tool-result token budget. */
|
|
14
|
-
readonly MCP_CONTENT: 10240;
|
|
15
|
-
};
|
|
16
|
-
/** Split long text into chunks that fit within a message limit */
|
|
17
|
-
export declare function chunkText(text: string, maxLength?: number): string[];
|
|
18
|
-
/** Format an ISO date as a human-readable relative time */
|
|
19
|
-
export declare function timeAgo(isoDate: string): string;
|
|
20
|
-
/** Parse a "/tab <name> <prompt>" message into tabName + prompt */
|
|
21
|
-
export declare function parseTabMessage(text: string): {
|
|
22
|
-
tabName: string;
|
|
23
|
-
prompt: string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Build the channel-side message text with an optional [tabName] prefix.
|
|
27
|
-
* Used by all three channels' sendResponse paths so the prefix format is
|
|
28
|
-
* consistent and the gate logic (skip "default", skip empty) lives in one place.
|
|
29
|
-
*/
|
|
30
|
-
export declare function formatTabbedResponse(text: string, tabName?: string): string;
|
|
31
|
-
/** Build prompt text from media attachments */
|
|
32
|
-
export declare function buildMediaPrompt(media: MediaAttachment[], textPrompt: string): string;
|
package/dist/util/text.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared message-size limits. Single source of truth so caps don't drift
|
|
3
|
-
* between channels, MCP, and dashboard.
|
|
4
|
-
*/
|
|
5
|
-
export const MESSAGE_LIMITS = {
|
|
6
|
-
/** Per-chunk send size (Telegram = 4096; other channels chunk to this too). */
|
|
7
|
-
CHUNK: 4096,
|
|
8
|
-
/** HTTP request body cap (webhook + dashboard endpoints). */
|
|
9
|
-
HTTP_BODY: 1024 * 1024, // 1 MB
|
|
10
|
-
/** Webhook channel single-message payload. */
|
|
11
|
-
WEBHOOK_PROMPT: 100_000, // 100 KB
|
|
12
|
-
/** MCP tool content/message field. Tight because it goes through Claude's tool-result token budget. */
|
|
13
|
-
MCP_CONTENT: 10_240, // 10 KB
|
|
14
|
-
};
|
|
15
|
-
const DEFAULT_MAX_LENGTH = MESSAGE_LIMITS.CHUNK;
|
|
16
|
-
/** Split long text into chunks that fit within a message limit */
|
|
17
|
-
export function chunkText(text, maxLength = DEFAULT_MAX_LENGTH) {
|
|
18
|
-
if (text.length <= maxLength)
|
|
19
|
-
return [text];
|
|
20
|
-
const chunks = [];
|
|
21
|
-
let remaining = text;
|
|
22
|
-
while (remaining.length > 0) {
|
|
23
|
-
if (remaining.length <= maxLength) {
|
|
24
|
-
chunks.push(remaining);
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
// Try to break at a newline
|
|
28
|
-
let breakPoint = remaining.lastIndexOf('\n', maxLength);
|
|
29
|
-
if (breakPoint <= 0 || breakPoint < maxLength * 0.5) {
|
|
30
|
-
// Try to break at a space
|
|
31
|
-
breakPoint = remaining.lastIndexOf(' ', maxLength);
|
|
32
|
-
}
|
|
33
|
-
if (breakPoint <= 0 || breakPoint < maxLength * 0.5) {
|
|
34
|
-
// Hard break
|
|
35
|
-
breakPoint = maxLength;
|
|
36
|
-
}
|
|
37
|
-
chunks.push(remaining.slice(0, breakPoint));
|
|
38
|
-
remaining = remaining.slice(breakPoint).trimStart();
|
|
39
|
-
}
|
|
40
|
-
return chunks;
|
|
41
|
-
}
|
|
42
|
-
/** Format an ISO date as a human-readable relative time */
|
|
43
|
-
export function timeAgo(isoDate) {
|
|
44
|
-
const diff = Date.now() - new Date(isoDate).getTime();
|
|
45
|
-
const mins = Math.floor(diff / 60000);
|
|
46
|
-
if (mins < 1)
|
|
47
|
-
return 'just now';
|
|
48
|
-
if (mins < 60)
|
|
49
|
-
return `${mins}m ago`;
|
|
50
|
-
const hours = Math.floor(mins / 60);
|
|
51
|
-
if (hours < 24)
|
|
52
|
-
return `${hours}h ago`;
|
|
53
|
-
const days = Math.floor(hours / 24);
|
|
54
|
-
return `${days}d ago`;
|
|
55
|
-
}
|
|
56
|
-
/** Parse a "/tab <name> <prompt>" message into tabName + prompt */
|
|
57
|
-
export function parseTabMessage(text) {
|
|
58
|
-
if (text.startsWith('/tab ')) {
|
|
59
|
-
const rest = text.slice(5);
|
|
60
|
-
const spaceIdx = rest.indexOf(' ');
|
|
61
|
-
if (spaceIdx === -1)
|
|
62
|
-
return { tabName: rest, prompt: '' };
|
|
63
|
-
return { tabName: rest.slice(0, spaceIdx), prompt: rest.slice(spaceIdx + 1).trim() };
|
|
64
|
-
}
|
|
65
|
-
return { tabName: 'default', prompt: text };
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Build the channel-side message text with an optional [tabName] prefix.
|
|
69
|
-
* Used by all three channels' sendResponse paths so the prefix format is
|
|
70
|
-
* consistent and the gate logic (skip "default", skip empty) lives in one place.
|
|
71
|
-
*/
|
|
72
|
-
export function formatTabbedResponse(text, tabName) {
|
|
73
|
-
if (!tabName || tabName === 'default')
|
|
74
|
-
return text;
|
|
75
|
-
return `[${tabName}] ${text}`;
|
|
76
|
-
}
|
|
77
|
-
/** Build prompt text from media attachments */
|
|
78
|
-
export function buildMediaPrompt(media, textPrompt) {
|
|
79
|
-
if (media.length === 0)
|
|
80
|
-
return textPrompt;
|
|
81
|
-
const descriptions = media.map((m) => {
|
|
82
|
-
if (m.type === 'voice' && m.caption?.startsWith('[Transcribed'))
|
|
83
|
-
return m.caption;
|
|
84
|
-
switch (m.type) {
|
|
85
|
-
case 'image':
|
|
86
|
-
return `User sent an image: ${m.filePath}`;
|
|
87
|
-
case 'voice':
|
|
88
|
-
return `User sent a voice message: ${m.filePath}`;
|
|
89
|
-
case 'audio':
|
|
90
|
-
return `User sent an audio file: ${m.filePath}${m.fileName ? ` (${m.fileName})` : ''}`;
|
|
91
|
-
case 'video':
|
|
92
|
-
return `User sent a video: ${m.filePath}`;
|
|
93
|
-
case 'document':
|
|
94
|
-
return `User sent a file: ${m.filePath}${m.fileName ? ` (${m.fileName})` : ''}`;
|
|
95
|
-
default:
|
|
96
|
-
return `User sent a file: ${m.filePath}`;
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
const mediaText = descriptions.join('\n');
|
|
100
|
-
return textPrompt ? `${mediaText}\n\n${textPrompt}` : mediaText;
|
|
101
|
-
}
|
package/dist/version.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const VERSION: string;
|
package/dist/version.js
DELETED
package/dist/voice/index.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export { createSTTProvider, type STTProvider } from './stt.js';
|
|
2
|
-
export { createTTSProvider, type TTSProvider } from './tts.js';
|
|
3
|
-
import { type STTProvider } from './stt.js';
|
|
4
|
-
import { type TTSProvider } from './tts.js';
|
|
5
|
-
import type { VoiceConfig } from '../types.js';
|
|
6
|
-
export declare function initVoiceProviders(voice?: VoiceConfig): {
|
|
7
|
-
stt: STTProvider | null;
|
|
8
|
-
tts: TTSProvider | null;
|
|
9
|
-
};
|
|
10
|
-
export declare function transcribeVoiceMessages(media: Array<{
|
|
11
|
-
type: string;
|
|
12
|
-
filePath?: string;
|
|
13
|
-
caption?: string;
|
|
14
|
-
}>, sttProvider: {
|
|
15
|
-
transcribe(path: string): Promise<string>;
|
|
16
|
-
warmup?(): void;
|
|
17
|
-
}, channelId: string, warmedUp: boolean): Promise<boolean>;
|
package/dist/voice/index.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export { createSTTProvider } from './stt.js';
|
|
2
|
-
export { createTTSProvider } from './tts.js';
|
|
3
|
-
import { createSTTProvider } from './stt.js';
|
|
4
|
-
import { createTTSProvider } from './tts.js';
|
|
5
|
-
import { logger } from '../util/logger.js';
|
|
6
|
-
export function initVoiceProviders(voice) {
|
|
7
|
-
let stt = null;
|
|
8
|
-
let tts = null;
|
|
9
|
-
if (voice?.sttProvider && voice.sttProvider !== 'none') {
|
|
10
|
-
stt = createSTTProvider({ provider: voice.sttProvider, apiKey: voice.sttApiKey });
|
|
11
|
-
}
|
|
12
|
-
if (voice?.ttsProvider && voice.ttsProvider !== 'none') {
|
|
13
|
-
tts = createTTSProvider({
|
|
14
|
-
provider: voice.ttsProvider,
|
|
15
|
-
apiKey: voice.ttsApiKey,
|
|
16
|
-
voice: voice.ttsVoice,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return { stt, tts };
|
|
20
|
-
}
|
|
21
|
-
export async function transcribeVoiceMessages(media, sttProvider, channelId, warmedUp) {
|
|
22
|
-
if (!sttProvider)
|
|
23
|
-
return warmedUp;
|
|
24
|
-
if (!warmedUp) {
|
|
25
|
-
sttProvider.warmup?.();
|
|
26
|
-
warmedUp = true;
|
|
27
|
-
}
|
|
28
|
-
for (const m of media) {
|
|
29
|
-
if (m.type === 'voice' && m.filePath) {
|
|
30
|
-
const start = Date.now();
|
|
31
|
-
try {
|
|
32
|
-
const transcription = await sttProvider.transcribe(m.filePath);
|
|
33
|
-
m.caption = `[Transcribed from voice message]: ${transcription}`;
|
|
34
|
-
logger.info(`[${channelId}] Voice transcription: ${Date.now() - start}ms`);
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
logger.warn('Voice transcription failed, passing file path instead:', err);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return warmedUp;
|
|
42
|
-
}
|