@marcopeg/hal 1.0.11
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 +655 -0
- package/dist/agent/index.d.ts +17 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +30 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/bot/commands/clear.d.ts +7 -0
- package/dist/bot/commands/clear.d.ts.map +1 -0
- package/dist/bot/commands/clear.js +23 -0
- package/dist/bot/commands/clear.js.map +1 -0
- package/dist/bot/commands/help.d.ts +3 -0
- package/dist/bot/commands/help.d.ts.map +1 -0
- package/dist/bot/commands/help.js +16 -0
- package/dist/bot/commands/help.js.map +1 -0
- package/dist/bot/commands/loader.d.ts +26 -0
- package/dist/bot/commands/loader.d.ts.map +1 -0
- package/dist/bot/commands/loader.js +206 -0
- package/dist/bot/commands/loader.js.map +1 -0
- package/dist/bot/commands/start.d.ts +3 -0
- package/dist/bot/commands/start.d.ts.map +1 -0
- package/dist/bot/commands/start.js +10 -0
- package/dist/bot/commands/start.js.map +1 -0
- package/dist/bot/commands/watcher.d.ts +11 -0
- package/dist/bot/commands/watcher.d.ts.map +1 -0
- package/dist/bot/commands/watcher.js +106 -0
- package/dist/bot/commands/watcher.js.map +1 -0
- package/dist/bot/handlers/document.d.ts +7 -0
- package/dist/bot/handlers/document.d.ts.map +1 -0
- package/dist/bot/handlers/document.js +128 -0
- package/dist/bot/handlers/document.js.map +1 -0
- package/dist/bot/handlers/index.d.ts +5 -0
- package/dist/bot/handlers/index.d.ts.map +1 -0
- package/dist/bot/handlers/index.js +5 -0
- package/dist/bot/handlers/index.js.map +1 -0
- package/dist/bot/handlers/photo.d.ts +7 -0
- package/dist/bot/handlers/photo.d.ts.map +1 -0
- package/dist/bot/handlers/photo.js +87 -0
- package/dist/bot/handlers/photo.js.map +1 -0
- package/dist/bot/handlers/text.d.ts +7 -0
- package/dist/bot/handlers/text.d.ts.map +1 -0
- package/dist/bot/handlers/text.js +186 -0
- package/dist/bot/handlers/text.js.map +1 -0
- package/dist/bot/handlers/voice.d.ts +7 -0
- package/dist/bot/handlers/voice.d.ts.map +1 -0
- package/dist/bot/handlers/voice.js +147 -0
- package/dist/bot/handlers/voice.js.map +1 -0
- package/dist/bot/middleware/auth.d.ts +7 -0
- package/dist/bot/middleware/auth.d.ts.map +1 -0
- package/dist/bot/middleware/auth.js +23 -0
- package/dist/bot/middleware/auth.js.map +1 -0
- package/dist/bot/middleware/rateLimit.d.ts +11 -0
- package/dist/bot/middleware/rateLimit.d.ts.map +1 -0
- package/dist/bot/middleware/rateLimit.js +49 -0
- package/dist/bot/middleware/rateLimit.js.map +1 -0
- package/dist/bot.d.ts +11 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +93 -0
- package/dist/bot.js.map +1 -0
- package/dist/claude/executor.d.ts +21 -0
- package/dist/claude/executor.d.ts.map +1 -0
- package/dist/claude/executor.js +185 -0
- package/dist/claude/executor.js.map +1 -0
- package/dist/claude/parser.d.ts +13 -0
- package/dist/claude/parser.d.ts.map +1 -0
- package/dist/claude/parser.js +63 -0
- package/dist/claude/parser.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +192 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +216 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +396 -0
- package/dist/config.js.map +1 -0
- package/dist/context/resolver.d.ts +19 -0
- package/dist/context/resolver.d.ts.map +1 -0
- package/dist/context/resolver.js +171 -0
- package/dist/context/resolver.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +44 -0
- package/dist/logger.js.map +1 -0
- package/dist/telegram/chunker.d.ts +10 -0
- package/dist/telegram/chunker.d.ts.map +1 -0
- package/dist/telegram/chunker.js +88 -0
- package/dist/telegram/chunker.js.map +1 -0
- package/dist/telegram/fileSender.d.ts +8 -0
- package/dist/telegram/fileSender.d.ts.map +1 -0
- package/dist/telegram/fileSender.js +46 -0
- package/dist/telegram/fileSender.js.map +1 -0
- package/dist/transcription/whisper.d.ts +11 -0
- package/dist/transcription/whisper.d.ts.map +1 -0
- package/dist/transcription/whisper.js +58 -0
- package/dist/transcription/whisper.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/user/setup.d.ts +26 -0
- package/dist/user/setup.d.ts.map +1 -0
- package/dist/user/setup.js +73 -0
- package/dist/user/setup.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { executeClaudeQuery } from "../../claude/executor.js";
|
|
4
|
+
import { parseClaudeOutput } from "../../claude/parser.js";
|
|
5
|
+
import { sendChunkedResponse } from "../../telegram/chunker.js";
|
|
6
|
+
import { sendDownloadFiles } from "../../telegram/fileSender.js";
|
|
7
|
+
import { ensureUserSetup, getDownloadsPath, getSessionId, getUploadsPath, saveSessionId, } from "../../user/setup.js";
|
|
8
|
+
const SUPPORTED_MIME_TYPES = [
|
|
9
|
+
"application/pdf",
|
|
10
|
+
"text/plain",
|
|
11
|
+
"text/markdown",
|
|
12
|
+
"text/csv",
|
|
13
|
+
"application/json",
|
|
14
|
+
"application/xml",
|
|
15
|
+
"text/html",
|
|
16
|
+
"image/jpeg",
|
|
17
|
+
"image/png",
|
|
18
|
+
"image/gif",
|
|
19
|
+
"image/webp",
|
|
20
|
+
];
|
|
21
|
+
const SUPPORTED_EXTENSIONS = [
|
|
22
|
+
".pdf",
|
|
23
|
+
".txt",
|
|
24
|
+
".md",
|
|
25
|
+
".csv",
|
|
26
|
+
".json",
|
|
27
|
+
".xml",
|
|
28
|
+
".html",
|
|
29
|
+
".js",
|
|
30
|
+
".ts",
|
|
31
|
+
".py",
|
|
32
|
+
".go",
|
|
33
|
+
".rs",
|
|
34
|
+
".java",
|
|
35
|
+
".jpg",
|
|
36
|
+
".jpeg",
|
|
37
|
+
".png",
|
|
38
|
+
".gif",
|
|
39
|
+
".webp",
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Returns a handler for document messages (PDFs, images, code files, etc.)
|
|
43
|
+
*/
|
|
44
|
+
export function createDocumentHandler(ctx) {
|
|
45
|
+
return async (gramCtx) => {
|
|
46
|
+
const { config, logger } = ctx;
|
|
47
|
+
const userId = gramCtx.from?.id;
|
|
48
|
+
const document = gramCtx.message?.document;
|
|
49
|
+
const caption = gramCtx.message?.caption || "Please analyze this document.";
|
|
50
|
+
if (!userId || !document) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const mimeType = document.mime_type || "";
|
|
54
|
+
const fileName = document.file_name || "document";
|
|
55
|
+
const ext = fileName.includes(".")
|
|
56
|
+
? `.${fileName.split(".").pop()?.toLowerCase()}`
|
|
57
|
+
: "";
|
|
58
|
+
const isSupported = SUPPORTED_MIME_TYPES.includes(mimeType) ||
|
|
59
|
+
SUPPORTED_EXTENSIONS.includes(ext);
|
|
60
|
+
if (!isSupported) {
|
|
61
|
+
await gramCtx.reply("Unsupported file type. Supported: PDF, images, text, and code files.");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
logger.debug({ fileName, mimeType }, "Document received");
|
|
65
|
+
const userDir = resolve(join(config.dataDir, String(userId)));
|
|
66
|
+
try {
|
|
67
|
+
await ensureUserSetup(userDir);
|
|
68
|
+
const file = await gramCtx.api.getFile(document.file_id);
|
|
69
|
+
const filePath = file.file_path;
|
|
70
|
+
if (!filePath) {
|
|
71
|
+
await gramCtx.reply("Could not download the document.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const fileUrl = `https://api.telegram.org/file/bot${config.telegram.botToken}/${filePath}`;
|
|
75
|
+
const response = await fetch(fileUrl);
|
|
76
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
77
|
+
const safeName = fileName.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
78
|
+
const uploadsDir = getUploadsPath(userDir);
|
|
79
|
+
const docPath = join(uploadsDir, safeName);
|
|
80
|
+
await writeFile(docPath, buffer);
|
|
81
|
+
logger.debug({ path: docPath }, "Document saved");
|
|
82
|
+
const prompt = `Please read the file "./uploads/${safeName}" and ${caption}`;
|
|
83
|
+
const sessionId = await getSessionId(userDir);
|
|
84
|
+
const statusMsg = await gramCtx.reply("_Processing..._", {
|
|
85
|
+
parse_mode: "Markdown",
|
|
86
|
+
});
|
|
87
|
+
let lastProgressUpdate = Date.now();
|
|
88
|
+
let lastProgressText = "Processing...";
|
|
89
|
+
const onProgress = async (message) => {
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
if (now - lastProgressUpdate > 2000 && message !== lastProgressText) {
|
|
92
|
+
lastProgressUpdate = now;
|
|
93
|
+
lastProgressText = message;
|
|
94
|
+
try {
|
|
95
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_${message}_`, { parse_mode: "Markdown" });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Ignore edit errors
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const downloadsPath = getDownloadsPath(userDir);
|
|
103
|
+
logger.debug("Executing Claude query with document");
|
|
104
|
+
const result = await executeClaudeQuery({ prompt, gramCtx, userDir, downloadsPath, sessionId, onProgress }, ctx);
|
|
105
|
+
try {
|
|
106
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Ignore delete errors
|
|
110
|
+
}
|
|
111
|
+
const parsed = parseClaudeOutput(result);
|
|
112
|
+
if (parsed.sessionId) {
|
|
113
|
+
await saveSessionId(userDir, parsed.sessionId);
|
|
114
|
+
}
|
|
115
|
+
await sendChunkedResponse(gramCtx, parsed.text);
|
|
116
|
+
const filesSent = await sendDownloadFiles(gramCtx, userDir, ctx);
|
|
117
|
+
if (filesSent > 0) {
|
|
118
|
+
logger.info({ filesSent }, "Sent download files to user");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
logger.error({ error }, "Document handler error");
|
|
123
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
124
|
+
await gramCtx.reply(`An error occurred processing the document: ${errorMessage}`);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../../src/bot/handlers/document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bot/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from "grammy";
|
|
2
|
+
import type { ProjectContext } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns a handler for photo messages.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createPhotoHandler(ctx: ProjectContext): (gramCtx: Context) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=photo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers/photo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AASrD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,IACtC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAqG/C"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { executeClaudeQuery } from "../../claude/executor.js";
|
|
4
|
+
import { parseClaudeOutput } from "../../claude/parser.js";
|
|
5
|
+
import { sendChunkedResponse } from "../../telegram/chunker.js";
|
|
6
|
+
import { sendDownloadFiles } from "../../telegram/fileSender.js";
|
|
7
|
+
import { ensureUserSetup, getDownloadsPath, getSessionId, getUploadsPath, saveSessionId, } from "../../user/setup.js";
|
|
8
|
+
/**
|
|
9
|
+
* Returns a handler for photo messages.
|
|
10
|
+
*/
|
|
11
|
+
export function createPhotoHandler(ctx) {
|
|
12
|
+
return async (gramCtx) => {
|
|
13
|
+
const { config, logger } = ctx;
|
|
14
|
+
const userId = gramCtx.from?.id;
|
|
15
|
+
const photo = gramCtx.message?.photo;
|
|
16
|
+
const caption = gramCtx.message?.caption || "Please analyze this image.";
|
|
17
|
+
if (!userId || !photo || photo.length === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
logger.debug({ userId }, "Photo received");
|
|
21
|
+
const userDir = resolve(join(config.dataDir, String(userId)));
|
|
22
|
+
try {
|
|
23
|
+
await ensureUserSetup(userDir);
|
|
24
|
+
// Get the largest photo (last in array)
|
|
25
|
+
const largestPhoto = photo[photo.length - 1];
|
|
26
|
+
const file = await gramCtx.api.getFile(largestPhoto.file_id);
|
|
27
|
+
const filePath = file.file_path;
|
|
28
|
+
if (!filePath) {
|
|
29
|
+
await gramCtx.reply("Could not download the image.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const fileUrl = `https://api.telegram.org/file/bot${config.telegram.botToken}/${filePath}`;
|
|
33
|
+
const response = await fetch(fileUrl);
|
|
34
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
35
|
+
const ext = filePath.split(".").pop() || "jpg";
|
|
36
|
+
const imageName = `image_${Date.now()}.${ext}`;
|
|
37
|
+
const uploadsDir = getUploadsPath(userDir);
|
|
38
|
+
const imagePath = join(uploadsDir, imageName);
|
|
39
|
+
await writeFile(imagePath, buffer);
|
|
40
|
+
logger.debug({ path: imagePath }, "Image saved");
|
|
41
|
+
const prompt = `Please look at the image file "./uploads/${imageName}" and ${caption}`;
|
|
42
|
+
const sessionId = await getSessionId(userDir);
|
|
43
|
+
const statusMsg = await gramCtx.reply("_Processing..._", {
|
|
44
|
+
parse_mode: "Markdown",
|
|
45
|
+
});
|
|
46
|
+
let lastProgressUpdate = Date.now();
|
|
47
|
+
let lastProgressText = "Processing...";
|
|
48
|
+
const onProgress = async (message) => {
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
if (now - lastProgressUpdate > 2000 && message !== lastProgressText) {
|
|
51
|
+
lastProgressUpdate = now;
|
|
52
|
+
lastProgressText = message;
|
|
53
|
+
try {
|
|
54
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_${message}_`, { parse_mode: "Markdown" });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Ignore edit errors
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const downloadsPath = getDownloadsPath(userDir);
|
|
62
|
+
logger.debug("Executing Claude query with image");
|
|
63
|
+
const result = await executeClaudeQuery({ prompt, gramCtx, userDir, downloadsPath, sessionId, onProgress }, ctx);
|
|
64
|
+
try {
|
|
65
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Ignore delete errors
|
|
69
|
+
}
|
|
70
|
+
const parsed = parseClaudeOutput(result);
|
|
71
|
+
if (parsed.sessionId) {
|
|
72
|
+
await saveSessionId(userDir, parsed.sessionId);
|
|
73
|
+
}
|
|
74
|
+
await sendChunkedResponse(gramCtx, parsed.text);
|
|
75
|
+
const filesSent = await sendDownloadFiles(gramCtx, userDir, ctx);
|
|
76
|
+
if (filesSent > 0) {
|
|
77
|
+
logger.info({ filesSent }, "Sent download files to user");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
logger.error({ error }, "Photo handler error");
|
|
82
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
83
|
+
await gramCtx.reply(`An error occurred processing the image: ${errorMessage}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=photo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photo.js","sourceRoot":"","sources":["../../../src/bot/handlers/photo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from "grammy";
|
|
2
|
+
import type { ProjectContext } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns a handler for text messages.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createTextHandler(ctx: ProjectContext): (gramCtx: Context) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers/text.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AASrD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,IACrC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAqO/C"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import { createAgent, getSkillsDir } from "../../agent/index.js";
|
|
3
|
+
import { executeClaudeQuery } from "../../claude/executor.js";
|
|
4
|
+
import { resolveContext } from "../../context/resolver.js";
|
|
5
|
+
import { sendChunkedResponse } from "../../telegram/chunker.js";
|
|
6
|
+
import { sendDownloadFiles } from "../../telegram/fileSender.js";
|
|
7
|
+
import { ensureUserSetup, getDownloadsPath, getSessionId, saveSessionId, } from "../../user/setup.js";
|
|
8
|
+
import { resolveCommandPath, resolveSkillEntry } from "../commands/loader.js";
|
|
9
|
+
/**
|
|
10
|
+
* Returns a handler for text messages.
|
|
11
|
+
*/
|
|
12
|
+
export function createTextHandler(ctx) {
|
|
13
|
+
return async (gramCtx) => {
|
|
14
|
+
const { config, logger } = ctx;
|
|
15
|
+
const userId = gramCtx.from?.id;
|
|
16
|
+
const messageText = gramCtx.message?.text;
|
|
17
|
+
if (!userId || !messageText) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
logger.debug({
|
|
21
|
+
userId,
|
|
22
|
+
username: gramCtx.from?.username,
|
|
23
|
+
name: gramCtx.from?.first_name,
|
|
24
|
+
}, "Message received");
|
|
25
|
+
// ── Slash command interception ────────────────────────────────────────────
|
|
26
|
+
if (messageText.startsWith("/")) {
|
|
27
|
+
// Parse command name: /deploy staging → "deploy", strip @botname suffix
|
|
28
|
+
const firstToken = messageText.slice(1).split(/\s+/)[0] ?? "";
|
|
29
|
+
const commandName = firstToken.split("@")[0];
|
|
30
|
+
const argsText = messageText.slice(1 + firstToken.length).trim();
|
|
31
|
+
const args = argsText ? argsText.split(/\s+/) : [];
|
|
32
|
+
if (commandName) {
|
|
33
|
+
const filePath = resolveCommandPath(commandName, config.cwd, config.configDir);
|
|
34
|
+
if (filePath !== null) {
|
|
35
|
+
try {
|
|
36
|
+
const context = await resolveContext({
|
|
37
|
+
gramCtx,
|
|
38
|
+
configContext: config.context,
|
|
39
|
+
bootContext: ctx.bootContext,
|
|
40
|
+
configDir: config.configDir,
|
|
41
|
+
projectCwd: config.cwd,
|
|
42
|
+
projectName: config.name,
|
|
43
|
+
projectSlug: config.slug,
|
|
44
|
+
logger,
|
|
45
|
+
});
|
|
46
|
+
const agent = createAgent(ctx);
|
|
47
|
+
// Cache-bust on every dispatch call
|
|
48
|
+
const mod = await import(`${filePath}?t=${Date.now()}`);
|
|
49
|
+
const result = await mod.default({
|
|
50
|
+
args,
|
|
51
|
+
ctx: context,
|
|
52
|
+
gram: gramCtx,
|
|
53
|
+
agent,
|
|
54
|
+
projectCtx: ctx,
|
|
55
|
+
});
|
|
56
|
+
if (typeof result === "string") {
|
|
57
|
+
await sendChunkedResponse(gramCtx, result);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
logger.error({
|
|
62
|
+
commandName,
|
|
63
|
+
filePath,
|
|
64
|
+
error: err instanceof Error ? err.message : String(err),
|
|
65
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
66
|
+
}, "Command execution failed");
|
|
67
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
68
|
+
await gramCtx.reply(`Command failed: ${errorMessage}`);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// No .mjs handler — check if this is a registered skill
|
|
73
|
+
const skillEntry = await resolveSkillEntry(commandName, getSkillsDir(config.cwd), logger);
|
|
74
|
+
if (skillEntry?.skillPrompt) {
|
|
75
|
+
const prompt = args.length > 0
|
|
76
|
+
? `${skillEntry.skillPrompt}\n\nUser input: ${args.join(" ")}`
|
|
77
|
+
: skillEntry.skillPrompt;
|
|
78
|
+
const agent = createAgent(ctx);
|
|
79
|
+
const statusMsg = await gramCtx.reply("_Processing..._", {
|
|
80
|
+
parse_mode: "Markdown",
|
|
81
|
+
});
|
|
82
|
+
let lastProgressUpdate = Date.now();
|
|
83
|
+
try {
|
|
84
|
+
const result = await agent.call(prompt, {
|
|
85
|
+
onProgress: async (message) => {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
if (now - lastProgressUpdate > 2000) {
|
|
88
|
+
lastProgressUpdate = now;
|
|
89
|
+
try {
|
|
90
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_${message}_`, { parse_mode: "Markdown" });
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore edit errors
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
99
|
+
await sendChunkedResponse(gramCtx, result);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
logger.error({
|
|
103
|
+
commandName,
|
|
104
|
+
error: err instanceof Error ? err.message : String(err),
|
|
105
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
106
|
+
}, "Skill execution failed");
|
|
107
|
+
try {
|
|
108
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Ignore delete errors
|
|
112
|
+
}
|
|
113
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
114
|
+
await gramCtx.reply(`Skill failed: ${errorMessage}`);
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Not a .mjs command or skill — fall through to Claude
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── End slash command interception ────────────────────────────────────────
|
|
122
|
+
const userDir = resolve(join(config.dataDir, String(userId)));
|
|
123
|
+
try {
|
|
124
|
+
await ensureUserSetup(userDir);
|
|
125
|
+
if (!messageText.trim()) {
|
|
126
|
+
await gramCtx.reply("Please provide a message.");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const sessionId = await getSessionId(userDir);
|
|
130
|
+
logger.debug({ sessionId: sessionId || "new" }, "Session");
|
|
131
|
+
const statusMsg = await gramCtx.reply("_Processing..._", {
|
|
132
|
+
parse_mode: "Markdown",
|
|
133
|
+
});
|
|
134
|
+
let lastProgressUpdate = Date.now();
|
|
135
|
+
let lastProgressText = "Processing...";
|
|
136
|
+
const onProgress = async (message) => {
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
if (now - lastProgressUpdate > 2000 && message !== lastProgressText) {
|
|
139
|
+
lastProgressUpdate = now;
|
|
140
|
+
lastProgressText = message;
|
|
141
|
+
try {
|
|
142
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_${message}_`, { parse_mode: "Markdown" });
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Ignore edit errors
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const downloadsPath = getDownloadsPath(userDir);
|
|
150
|
+
logger.debug("Executing Claude query");
|
|
151
|
+
const result = await executeClaudeQuery({
|
|
152
|
+
prompt: messageText,
|
|
153
|
+
gramCtx,
|
|
154
|
+
userDir,
|
|
155
|
+
downloadsPath,
|
|
156
|
+
sessionId,
|
|
157
|
+
onProgress,
|
|
158
|
+
}, ctx);
|
|
159
|
+
logger.debug({ success: result.success, error: result.error }, "Claude result");
|
|
160
|
+
try {
|
|
161
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// Ignore delete errors
|
|
165
|
+
}
|
|
166
|
+
if (result.sessionId) {
|
|
167
|
+
await saveSessionId(userDir, result.sessionId);
|
|
168
|
+
logger.debug({ sessionId: result.sessionId }, "Session saved");
|
|
169
|
+
}
|
|
170
|
+
const responseText = result.success
|
|
171
|
+
? result.output
|
|
172
|
+
: result.error || "An error occurred";
|
|
173
|
+
await sendChunkedResponse(gramCtx, responseText);
|
|
174
|
+
const filesSent = await sendDownloadFiles(gramCtx, userDir, ctx);
|
|
175
|
+
if (filesSent > 0) {
|
|
176
|
+
logger.info({ filesSent }, "Sent download files to user");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
logger.error({ error }, "Text handler error");
|
|
181
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
182
|
+
await gramCtx.reply(`An error occurred: ${errorMessage}`);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/bot/handlers/text.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from "grammy";
|
|
2
|
+
import type { ProjectContext } from "../../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns a handler for voice messages (transcribe + route to Claude).
|
|
5
|
+
*/
|
|
6
|
+
export declare function createVoiceHandler(ctx: ProjectContext): (gramCtx: Context) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=voice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers/voice.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAiCrD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,IACtC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAsK/C"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { executeClaudeQuery } from "../../claude/executor.js";
|
|
6
|
+
import { parseClaudeOutput } from "../../claude/parser.js";
|
|
7
|
+
import { sendChunkedResponse } from "../../telegram/chunker.js";
|
|
8
|
+
import { sendDownloadFiles } from "../../telegram/fileSender.js";
|
|
9
|
+
import { transcribeAudio } from "../../transcription/whisper.js";
|
|
10
|
+
import { ensureUserSetup, getDownloadsPath, getSessionId, getUploadsPath, saveSessionId, } from "../../user/setup.js";
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
/**
|
|
13
|
+
* Convert OGA/OGG (Opus) to WAV for Whisper compatibility
|
|
14
|
+
*/
|
|
15
|
+
async function convertToWav(inputPath, outputPath, ctx) {
|
|
16
|
+
const { logger } = ctx;
|
|
17
|
+
try {
|
|
18
|
+
await execAsync(`ffmpeg -i "${inputPath}" -ar 16000 -ac 1 -y "${outputPath}"`);
|
|
19
|
+
logger.debug({ inputPath, outputPath }, "Audio converted to WAV");
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logger.error({ error }, "ffmpeg conversion failed");
|
|
23
|
+
throw new Error("Failed to convert audio. Ensure ffmpeg is installed: brew install ffmpeg");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns a handler for voice messages (transcribe + route to Claude).
|
|
28
|
+
*/
|
|
29
|
+
export function createVoiceHandler(ctx) {
|
|
30
|
+
return async (gramCtx) => {
|
|
31
|
+
const { config, logger } = ctx;
|
|
32
|
+
if (!config.transcription) {
|
|
33
|
+
await gramCtx.reply("Voice messages are not configured for this bot. Add a 'transcription' section to your project config.");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const userId = gramCtx.from?.id;
|
|
37
|
+
const voice = gramCtx.message?.voice;
|
|
38
|
+
if (!userId || !voice) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
logger.debug({ userId, duration: voice.duration, fileSize: voice.file_size }, "Voice message received");
|
|
42
|
+
const userDir = resolve(join(config.dataDir, String(userId)));
|
|
43
|
+
try {
|
|
44
|
+
await ensureUserSetup(userDir);
|
|
45
|
+
// Download voice file from Telegram
|
|
46
|
+
const file = await gramCtx.api.getFile(voice.file_id);
|
|
47
|
+
const filePath = file.file_path;
|
|
48
|
+
if (!filePath) {
|
|
49
|
+
await gramCtx.reply("Could not download the voice message.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const fileUrl = `https://api.telegram.org/file/bot${config.telegram.botToken}/${filePath}`;
|
|
53
|
+
const response = await fetch(fileUrl);
|
|
54
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
55
|
+
const timestamp = Date.now();
|
|
56
|
+
const uploadsDir = getUploadsPath(userDir);
|
|
57
|
+
const ogaPath = join(uploadsDir, `voice_${timestamp}.oga`);
|
|
58
|
+
const wavPath = join(uploadsDir, `voice_${timestamp}.wav`);
|
|
59
|
+
await writeFile(ogaPath, buffer);
|
|
60
|
+
logger.debug({ path: ogaPath }, "Voice file saved");
|
|
61
|
+
const statusMsg = await gramCtx.reply("_Transcribing voice message..._", {
|
|
62
|
+
parse_mode: "Markdown",
|
|
63
|
+
});
|
|
64
|
+
// Convert to WAV (Whisper requires WAV/MP3 input)
|
|
65
|
+
await convertToWav(ogaPath, wavPath, ctx);
|
|
66
|
+
// Transcribe with local Whisper
|
|
67
|
+
const transcription = await transcribeAudio(wavPath, ctx);
|
|
68
|
+
if (!transcription.text) {
|
|
69
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
70
|
+
await gramCtx.reply("Could not transcribe the voice message. Please try again.");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Optionally show transcription to user
|
|
74
|
+
if (config.transcription.showTranscription) {
|
|
75
|
+
try {
|
|
76
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_Transcribed: "${transcription.text}"_\n\n_Processing with Claude..._`, { parse_mode: "Markdown" });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Ignore edit errors
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
try {
|
|
84
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, "_Processing..._", { parse_mode: "Markdown" });
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Ignore edit errors
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Clean up temporary files
|
|
91
|
+
try {
|
|
92
|
+
await unlink(ogaPath);
|
|
93
|
+
await unlink(wavPath);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Ignore cleanup errors
|
|
97
|
+
}
|
|
98
|
+
const sessionId = await getSessionId(userDir);
|
|
99
|
+
let lastProgressUpdate = Date.now();
|
|
100
|
+
let lastProgressText = "Processing...";
|
|
101
|
+
const onProgress = async (message) => {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
if (now - lastProgressUpdate > 2000 && message !== lastProgressText) {
|
|
104
|
+
lastProgressUpdate = now;
|
|
105
|
+
lastProgressText = message;
|
|
106
|
+
try {
|
|
107
|
+
await gramCtx.api.editMessageText(gramCtx.chat.id, statusMsg.message_id, `_${message}_`, { parse_mode: "Markdown" });
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Ignore edit errors
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const downloadsPath = getDownloadsPath(userDir);
|
|
115
|
+
logger.debug({ transcription: transcription.text }, "Executing Claude query");
|
|
116
|
+
const result = await executeClaudeQuery({
|
|
117
|
+
prompt: transcription.text,
|
|
118
|
+
gramCtx,
|
|
119
|
+
userDir,
|
|
120
|
+
downloadsPath,
|
|
121
|
+
sessionId,
|
|
122
|
+
onProgress,
|
|
123
|
+
}, ctx);
|
|
124
|
+
try {
|
|
125
|
+
await gramCtx.api.deleteMessage(gramCtx.chat.id, statusMsg.message_id);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Ignore delete errors
|
|
129
|
+
}
|
|
130
|
+
const parsed = parseClaudeOutput(result);
|
|
131
|
+
if (parsed.sessionId) {
|
|
132
|
+
await saveSessionId(userDir, parsed.sessionId);
|
|
133
|
+
}
|
|
134
|
+
await sendChunkedResponse(gramCtx, parsed.text);
|
|
135
|
+
const filesSent = await sendDownloadFiles(gramCtx, userDir, ctx);
|
|
136
|
+
if (filesSent > 0) {
|
|
137
|
+
logger.info({ filesSent }, "Sent download files to user");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
logger.error({ error }, "Voice handler error");
|
|
142
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
143
|
+
await gramCtx.reply(`An error occurred processing the voice message: ${errorMessage}`);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=voice.js.map
|