@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.
Files changed (106) hide show
  1. package/README.md +655 -0
  2. package/dist/agent/index.d.ts +17 -0
  3. package/dist/agent/index.d.ts.map +1 -0
  4. package/dist/agent/index.js +30 -0
  5. package/dist/agent/index.js.map +1 -0
  6. package/dist/bot/commands/clear.d.ts +7 -0
  7. package/dist/bot/commands/clear.d.ts.map +1 -0
  8. package/dist/bot/commands/clear.js +23 -0
  9. package/dist/bot/commands/clear.js.map +1 -0
  10. package/dist/bot/commands/help.d.ts +3 -0
  11. package/dist/bot/commands/help.d.ts.map +1 -0
  12. package/dist/bot/commands/help.js +16 -0
  13. package/dist/bot/commands/help.js.map +1 -0
  14. package/dist/bot/commands/loader.d.ts +26 -0
  15. package/dist/bot/commands/loader.d.ts.map +1 -0
  16. package/dist/bot/commands/loader.js +206 -0
  17. package/dist/bot/commands/loader.js.map +1 -0
  18. package/dist/bot/commands/start.d.ts +3 -0
  19. package/dist/bot/commands/start.d.ts.map +1 -0
  20. package/dist/bot/commands/start.js +10 -0
  21. package/dist/bot/commands/start.js.map +1 -0
  22. package/dist/bot/commands/watcher.d.ts +11 -0
  23. package/dist/bot/commands/watcher.d.ts.map +1 -0
  24. package/dist/bot/commands/watcher.js +106 -0
  25. package/dist/bot/commands/watcher.js.map +1 -0
  26. package/dist/bot/handlers/document.d.ts +7 -0
  27. package/dist/bot/handlers/document.d.ts.map +1 -0
  28. package/dist/bot/handlers/document.js +128 -0
  29. package/dist/bot/handlers/document.js.map +1 -0
  30. package/dist/bot/handlers/index.d.ts +5 -0
  31. package/dist/bot/handlers/index.d.ts.map +1 -0
  32. package/dist/bot/handlers/index.js +5 -0
  33. package/dist/bot/handlers/index.js.map +1 -0
  34. package/dist/bot/handlers/photo.d.ts +7 -0
  35. package/dist/bot/handlers/photo.d.ts.map +1 -0
  36. package/dist/bot/handlers/photo.js +87 -0
  37. package/dist/bot/handlers/photo.js.map +1 -0
  38. package/dist/bot/handlers/text.d.ts +7 -0
  39. package/dist/bot/handlers/text.d.ts.map +1 -0
  40. package/dist/bot/handlers/text.js +186 -0
  41. package/dist/bot/handlers/text.js.map +1 -0
  42. package/dist/bot/handlers/voice.d.ts +7 -0
  43. package/dist/bot/handlers/voice.d.ts.map +1 -0
  44. package/dist/bot/handlers/voice.js +147 -0
  45. package/dist/bot/handlers/voice.js.map +1 -0
  46. package/dist/bot/middleware/auth.d.ts +7 -0
  47. package/dist/bot/middleware/auth.d.ts.map +1 -0
  48. package/dist/bot/middleware/auth.js +23 -0
  49. package/dist/bot/middleware/auth.js.map +1 -0
  50. package/dist/bot/middleware/rateLimit.d.ts +11 -0
  51. package/dist/bot/middleware/rateLimit.d.ts.map +1 -0
  52. package/dist/bot/middleware/rateLimit.js +49 -0
  53. package/dist/bot/middleware/rateLimit.js.map +1 -0
  54. package/dist/bot.d.ts +11 -0
  55. package/dist/bot.d.ts.map +1 -0
  56. package/dist/bot.js +93 -0
  57. package/dist/bot.js.map +1 -0
  58. package/dist/claude/executor.d.ts +21 -0
  59. package/dist/claude/executor.d.ts.map +1 -0
  60. package/dist/claude/executor.js +185 -0
  61. package/dist/claude/executor.js.map +1 -0
  62. package/dist/claude/parser.d.ts +13 -0
  63. package/dist/claude/parser.d.ts.map +1 -0
  64. package/dist/claude/parser.js +63 -0
  65. package/dist/claude/parser.js.map +1 -0
  66. package/dist/cli.d.ts +3 -0
  67. package/dist/cli.d.ts.map +1 -0
  68. package/dist/cli.js +192 -0
  69. package/dist/cli.js.map +1 -0
  70. package/dist/config.d.ts +216 -0
  71. package/dist/config.d.ts.map +1 -0
  72. package/dist/config.js +396 -0
  73. package/dist/config.js.map +1 -0
  74. package/dist/context/resolver.d.ts +19 -0
  75. package/dist/context/resolver.d.ts.map +1 -0
  76. package/dist/context/resolver.js +171 -0
  77. package/dist/context/resolver.js.map +1 -0
  78. package/dist/index.d.ts +7 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +5 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/logger.d.ts +17 -0
  83. package/dist/logger.d.ts.map +1 -0
  84. package/dist/logger.js +44 -0
  85. package/dist/logger.js.map +1 -0
  86. package/dist/telegram/chunker.d.ts +10 -0
  87. package/dist/telegram/chunker.d.ts.map +1 -0
  88. package/dist/telegram/chunker.js +88 -0
  89. package/dist/telegram/chunker.js.map +1 -0
  90. package/dist/telegram/fileSender.d.ts +8 -0
  91. package/dist/telegram/fileSender.d.ts.map +1 -0
  92. package/dist/telegram/fileSender.js +46 -0
  93. package/dist/telegram/fileSender.js.map +1 -0
  94. package/dist/transcription/whisper.d.ts +11 -0
  95. package/dist/transcription/whisper.d.ts.map +1 -0
  96. package/dist/transcription/whisper.js +58 -0
  97. package/dist/transcription/whisper.js.map +1 -0
  98. package/dist/types.d.ts +22 -0
  99. package/dist/types.d.ts.map +1 -0
  100. package/dist/types.js +2 -0
  101. package/dist/types.js.map +1 -0
  102. package/dist/user/setup.d.ts +26 -0
  103. package/dist/user/setup.d.ts.map +1 -0
  104. package/dist/user/setup.js +73 -0
  105. package/dist/user/setup.js.map +1 -0
  106. package/package.json +56 -0
@@ -0,0 +1,30 @@
1
+ import { join } from "node:path";
2
+ import { executeClaudeQuery } from "../claude/executor.js";
3
+ /**
4
+ * Return the engine-specific skills directory for the given project.
5
+ * Today Claude Code stores skills in `.claude/skills/`.
6
+ * When new engines are supported this function will branch on the engine type.
7
+ */
8
+ export function getSkillsDir(projectCwd) {
9
+ return join(projectCwd, ".claude", "skills");
10
+ }
11
+ /**
12
+ * Create an Agent for the given project context.
13
+ *
14
+ * This factory is the single place where the underlying AI engine is selected.
15
+ * Today it always returns a Claude Code-backed agent. When support for other
16
+ * providers (Codex, Copilot, …) is added, engine selection will happen here
17
+ * based on project config — command handlers never need to change.
18
+ */
19
+ export function createAgent(projectCtx) {
20
+ return {
21
+ async call(prompt, options) {
22
+ const result = await executeClaudeQuery({ prompt, userDir: "", onProgress: options?.onProgress }, projectCtx);
23
+ if (!result.success) {
24
+ throw new Error(result.error ?? "Agent call failed");
25
+ }
26
+ return result.output;
27
+ },
28
+ };
29
+ }
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,OAAO,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,UAA0B;IACpD,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO;YACxB,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,EACxD,UAAU,CACX,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,mBAAmB,CAAC,CAAC;YACvD,CAAC;YACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Context } from "grammy";
2
+ import type { ProjectContext } from "../../types.js";
3
+ /**
4
+ * Returns a handler for the /clear command.
5
+ */
6
+ export declare function createClearHandler(ctx: ProjectContext): (gramCtx: Context) => Promise<void>;
7
+ //# sourceMappingURL=clear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/clear.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,IACtC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAqB/C"}
@@ -0,0 +1,23 @@
1
+ import { join } from "node:path";
2
+ import { clearUserData } from "../../user/setup.js";
3
+ /**
4
+ * Returns a handler for the /clear command.
5
+ */
6
+ export function createClearHandler(ctx) {
7
+ return async (gramCtx) => {
8
+ const userId = gramCtx.from?.id;
9
+ if (!userId) {
10
+ await gramCtx.reply("Could not identify user.");
11
+ return;
12
+ }
13
+ const userDir = join(ctx.config.dataDir, String(userId));
14
+ try {
15
+ await clearUserData(userDir);
16
+ await gramCtx.reply("Conversation history cleared. Your next message will start a fresh conversation.");
17
+ }
18
+ catch (_error) {
19
+ await gramCtx.reply("Failed to clear conversation history. Please try again.");
20
+ }
21
+ };
22
+ }
23
+ //# sourceMappingURL=clear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clear.js","sourceRoot":"","sources":["../../../src/bot/commands/clear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAmB;IACpD,OAAO,KAAK,EAAE,OAAgB,EAAiB,EAAE;QAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAEhC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAEzD,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,OAAO,CAAC,KAAK,CACjB,kFAAkF,CACnF,CAAC;QACJ,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,MAAM,OAAO,CAAC,KAAK,CACjB,yDAAyD,CAC1D,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Context } from "grammy";
2
+ export declare function helpHandler(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB7D"}
@@ -0,0 +1,16 @@
1
+ export async function helpHandler(ctx) {
2
+ await ctx.reply(`*Claude Code Telegram Bot*\n\n` +
3
+ `*Commands:*\n` +
4
+ `/start - Welcome message\n` +
5
+ `/help - Show this help\n` +
6
+ `/clear - Clear conversation history\n\n` +
7
+ `*Usage:*\n` +
8
+ `Just send any message to chat with Claude.\n` +
9
+ `You can also send images and documents for analysis.\n\n` +
10
+ `Your conversation history is preserved between messages. ` +
11
+ `Use /clear to start a fresh conversation.\n\n` +
12
+ `*Configuration:*\n` +
13
+ `Claude reads configuration from your .claude folder.\n` +
14
+ `Edit CLAUDE.md for system prompts and .claude/settings.json for permissions.`, { parse_mode: "Markdown" });
15
+ }
16
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/bot/commands/help.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAY;IAC5C,MAAM,GAAG,CAAC,KAAK,CACb,gCAAgC;QAC9B,eAAe;QACf,4BAA4B;QAC5B,0BAA0B;QAC1B,yCAAyC;QACzC,YAAY;QACZ,8CAA8C;QAC9C,0DAA0D;QAC1D,2DAA2D;QAC3D,+CAA+C;QAC/C,oBAAoB;QACpB,wDAAwD;QACxD,8EAA8E,EAChF,EAAE,UAAU,EAAE,UAAU,EAAE,CAC3B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type pino from "pino";
2
+ export interface CommandEntry {
3
+ command: string;
4
+ description: string;
5
+ filePath: string;
6
+ skillPrompt?: string;
7
+ }
8
+ /**
9
+ * Scan command directories and optionally the skills dir, then return the merged list.
10
+ *
11
+ * Precedence (lowest → highest):
12
+ * engine skills < global .hal/commands < project .hal/commands
13
+ */
14
+ export declare function loadCommands(projectCwd: string, configDir: string, logger: pino.Logger, skillsDir?: string): Promise<CommandEntry[]>;
15
+ /**
16
+ * Resolve a skill entry by command name from the engine's skills directory.
17
+ * Returns null if the skill doesn't exist or its SKILL.md can't be parsed.
18
+ */
19
+ export declare function resolveSkillEntry(commandName: string, skillsDir: string, logger: pino.Logger): Promise<CommandEntry | null>;
20
+ /**
21
+ * Resolve the file path for a single command name.
22
+ * Returns null if not found in either directory.
23
+ * Project-specific takes precedence over global.
24
+ */
25
+ export declare function resolveCommandPath(commandName: string, projectCwd: string, configDir: string): string | null;
26
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAI7B,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAqMD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAsBzB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,GAClB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAwB9B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAcf"}
@@ -0,0 +1,206 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ // ─── Directory helpers ───────────────────────────────────────────────────────
5
+ function projectCommandDir(projectCwd) {
6
+ return join(projectCwd, ".hal", "commands");
7
+ }
8
+ function globalCommandDir(configDir) {
9
+ return join(configDir, ".hal", "commands");
10
+ }
11
+ // ─── Single-file import ──────────────────────────────────────────────────────
12
+ async function importCommandFile(filePath, logger) {
13
+ try {
14
+ // Cache-bust on every import so hot-reload always gets the latest version
15
+ const mod = await import(`${filePath}?t=${Date.now()}`);
16
+ if (typeof mod.description !== "string" || !mod.description.trim()) {
17
+ logger.warn({ filePath }, "Command file missing or empty `description` export — skipping");
18
+ return null;
19
+ }
20
+ // Derive command name from filename (strip .mjs extension)
21
+ const fileName = filePath.split("/").pop() ?? "";
22
+ const command = fileName.replace(/\.mjs$/, "");
23
+ return {
24
+ command,
25
+ description: mod.description,
26
+ filePath,
27
+ };
28
+ }
29
+ catch (err) {
30
+ logger.error({
31
+ filePath,
32
+ error: err instanceof Error ? err.message : String(err),
33
+ stack: err instanceof Error ? err.stack : undefined,
34
+ }, "Failed to import command file — skipping");
35
+ return null;
36
+ }
37
+ }
38
+ // ─── Directory scan ──────────────────────────────────────────────────────────
39
+ async function scanCommandDir(dir, logger) {
40
+ if (!existsSync(dir)) {
41
+ return [];
42
+ }
43
+ let files;
44
+ try {
45
+ files = await readdir(dir);
46
+ }
47
+ catch (err) {
48
+ logger.error({ dir, error: err instanceof Error ? err.message : String(err) }, "Failed to read command directory — skipping");
49
+ return [];
50
+ }
51
+ const mjsFiles = files.filter((f) => f.endsWith(".mjs"));
52
+ const entries = [];
53
+ for (const file of mjsFiles) {
54
+ const filePath = join(dir, file);
55
+ const entry = await importCommandFile(filePath, logger);
56
+ if (entry !== null) {
57
+ entries.push(entry);
58
+ }
59
+ }
60
+ return entries;
61
+ }
62
+ // ─── Skills scan ─────────────────────────────────────────────────────────────
63
+ /**
64
+ * Parse a SKILL.md file and return { name, description, prompt }.
65
+ * `prompt` is the body text after the closing frontmatter delimiter.
66
+ * Returns null if the file cannot be parsed or is missing required fields.
67
+ */
68
+ async function parseSkillMd(filePath, logger) {
69
+ let content;
70
+ try {
71
+ content = await readFile(filePath, "utf-8");
72
+ }
73
+ catch (err) {
74
+ logger.error({ filePath, error: err instanceof Error ? err.message : String(err) }, "Failed to read SKILL.md — skipping");
75
+ return null;
76
+ }
77
+ // Match frontmatter block and capture everything after the closing ---
78
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)/);
79
+ if (!match) {
80
+ logger.warn({ filePath }, "SKILL.md missing frontmatter block — skipping");
81
+ return null;
82
+ }
83
+ const frontmatter = match[1];
84
+ const prompt = match[2].trim();
85
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
86
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
87
+ if (!nameMatch || !descMatch) {
88
+ logger.warn({ filePath }, "SKILL.md frontmatter missing name or description — skipping");
89
+ return null;
90
+ }
91
+ return {
92
+ name: nameMatch[1].trim(),
93
+ description: descMatch[1].trim(),
94
+ prompt,
95
+ };
96
+ }
97
+ /**
98
+ * Scan the engine's skills directory and return a CommandEntry for each skill.
99
+ * The command name is derived from the folder name (how the engine resolves it).
100
+ * A warning is logged when the frontmatter `name` differs from the folder name.
101
+ * Skills have no .mjs filePath — they fall through to the AI engine when invoked.
102
+ */
103
+ async function scanSkillsDir(dir, logger) {
104
+ if (!existsSync(dir)) {
105
+ return [];
106
+ }
107
+ let folders;
108
+ try {
109
+ const entries = await readdir(dir, { withFileTypes: true });
110
+ folders = entries.filter((e) => e.isDirectory()).map((e) => e.name);
111
+ }
112
+ catch (err) {
113
+ logger.error({ dir, error: err instanceof Error ? err.message : String(err) }, "Failed to read skills directory — skipping");
114
+ return [];
115
+ }
116
+ const skills = [];
117
+ for (const folder of folders) {
118
+ const skillMdPath = join(dir, folder, "SKILL.md");
119
+ if (!existsSync(skillMdPath)) {
120
+ continue;
121
+ }
122
+ const parsed = await parseSkillMd(skillMdPath, logger);
123
+ if (!parsed) {
124
+ continue;
125
+ }
126
+ // Command name is the folder name; warn if frontmatter `name` disagrees
127
+ if (parsed.name !== folder) {
128
+ logger.warn({ folder, frontmatterName: parsed.name }, "Skill frontmatter `name` differs from folder name — using folder name as command");
129
+ }
130
+ skills.push({
131
+ command: folder,
132
+ description: parsed.description,
133
+ filePath: "",
134
+ skillPrompt: parsed.prompt,
135
+ });
136
+ }
137
+ return skills;
138
+ }
139
+ // ─── Public API ──────────────────────────────────────────────────────────────
140
+ /**
141
+ * Scan command directories and optionally the skills dir, then return the merged list.
142
+ *
143
+ * Precedence (lowest → highest):
144
+ * engine skills < global .hal/commands < project .hal/commands
145
+ */
146
+ export async function loadCommands(projectCwd, configDir, logger, skillsDir) {
147
+ const globalDir = globalCommandDir(configDir);
148
+ const projectDir = projectCommandDir(projectCwd);
149
+ // Load in ascending precedence order; later entries overwrite earlier ones
150
+ const skillEntries = skillsDir ? await scanSkillsDir(skillsDir, logger) : [];
151
+ const globalEntries = await scanCommandDir(globalDir, logger);
152
+ const projectEntries = await scanCommandDir(projectDir, logger);
153
+ const map = new Map();
154
+ for (const entry of skillEntries) {
155
+ map.set(entry.command, entry);
156
+ }
157
+ for (const entry of globalEntries) {
158
+ map.set(entry.command, entry);
159
+ }
160
+ for (const entry of projectEntries) {
161
+ map.set(entry.command, entry);
162
+ }
163
+ return Array.from(map.values());
164
+ }
165
+ /**
166
+ * Resolve a skill entry by command name from the engine's skills directory.
167
+ * Returns null if the skill doesn't exist or its SKILL.md can't be parsed.
168
+ */
169
+ export async function resolveSkillEntry(commandName, skillsDir, logger) {
170
+ const skillMdPath = join(skillsDir, commandName, "SKILL.md");
171
+ if (!existsSync(skillMdPath)) {
172
+ return null;
173
+ }
174
+ const parsed = await parseSkillMd(skillMdPath, logger);
175
+ if (!parsed) {
176
+ return null;
177
+ }
178
+ if (parsed.name !== commandName) {
179
+ logger.warn({ commandName, frontmatterName: parsed.name }, "Skill frontmatter `name` differs from folder name — using folder name as command");
180
+ }
181
+ return {
182
+ command: commandName,
183
+ description: parsed.description,
184
+ filePath: "",
185
+ skillPrompt: parsed.prompt,
186
+ };
187
+ }
188
+ /**
189
+ * Resolve the file path for a single command name.
190
+ * Returns null if not found in either directory.
191
+ * Project-specific takes precedence over global.
192
+ */
193
+ export function resolveCommandPath(commandName, projectCwd, configDir) {
194
+ // Check project-specific first (higher priority)
195
+ const projectPath = join(projectCommandDir(projectCwd), `${commandName}.mjs`);
196
+ if (existsSync(projectPath)) {
197
+ return projectPath;
198
+ }
199
+ // Fall back to global
200
+ const globalPath = join(globalCommandDir(configDir), `${commandName}.mjs`);
201
+ if (existsSync(globalPath)) {
202
+ return globalPath;
203
+ }
204
+ return null;
205
+ }
206
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/bot/commands/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Context } from "grammy";
2
+ export declare function startHandler(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9D"}
@@ -0,0 +1,10 @@
1
+ export async function startHandler(ctx) {
2
+ const username = ctx.from?.first_name || "there";
3
+ await ctx.reply(`Hello ${username}! I'm a Claude Code assistant bot.\n\n` +
4
+ `You can:\n` +
5
+ `- Send any message to chat with me\n` +
6
+ `- Send images or documents for analysis\n` +
7
+ `- Use /clear to start a new conversation\n\n` +
8
+ `Type /help for more information.`);
9
+ }
10
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/bot/commands/start.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAY;IAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,UAAU,IAAI,OAAO,CAAC;IAEjD,MAAM,GAAG,CAAC,KAAK,CACb,SAAS,QAAQ,wCAAwC;QACvD,YAAY;QACZ,sCAAsC;QACtC,2CAA2C;QAC3C,8CAA8C;QAC9C,kCAAkC,CACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Bot } from "grammy";
2
+ import type pino from "pino";
3
+ export interface CommandWatcher {
4
+ stop: () => Promise<void>;
5
+ }
6
+ /**
7
+ * Start a file watcher that monitors command directories and the skills dir,
8
+ * then re-publishes the full merged command list to Telegram on any change.
9
+ */
10
+ export declare function startCommandWatcher(bot: Bot, projectCwd: string, configDir: string, logger: pino.Logger, skillsDir?: string): CommandWatcher;
11
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../../src/bot/commands/watcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAK7B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAID;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CAqIhB"}
@@ -0,0 +1,106 @@
1
+ import { join } from "node:path";
2
+ import { loadCommands } from "./loader.js";
3
+ // ─── Implementation ──────────────────────────────────────────────────────────
4
+ /**
5
+ * Start a file watcher that monitors command directories and the skills dir,
6
+ * then re-publishes the full merged command list to Telegram on any change.
7
+ */
8
+ export function startCommandWatcher(bot, projectCwd, configDir, logger, skillsDir) {
9
+ const projectCommandDir = join(projectCwd, ".hal", "commands");
10
+ const globalCommandDir = join(configDir, ".hal", "commands");
11
+ let debounceTimer = null;
12
+ async function republish() {
13
+ try {
14
+ const commands = await loadCommands(projectCwd, configDir, logger, skillsDir);
15
+ await bot.api.setMyCommands(commands.map((c) => ({
16
+ command: c.command,
17
+ description: c.description,
18
+ })));
19
+ logger.info({
20
+ count: commands.length,
21
+ commands: commands.map((c) => c.command),
22
+ }, "Commands re-registered with Telegram");
23
+ }
24
+ catch (err) {
25
+ logger.error({ error: err instanceof Error ? err.message : String(err) }, "Failed to re-register commands with Telegram");
26
+ }
27
+ }
28
+ function scheduleRepublish() {
29
+ if (debounceTimer !== null) {
30
+ clearTimeout(debounceTimer);
31
+ }
32
+ debounceTimer = setTimeout(() => {
33
+ debounceTimer = null;
34
+ void republish();
35
+ }, 300);
36
+ }
37
+ // Dynamically import chokidar to start watching
38
+ // We do this in an async IIFE so we can use await
39
+ let watcherInstance = null;
40
+ const watcherReady = (async () => {
41
+ try {
42
+ const chokidar = await import("chokidar");
43
+ const watchPaths = [projectCommandDir, globalCommandDir];
44
+ if (skillsDir) {
45
+ watchPaths.push(skillsDir);
46
+ }
47
+ const watcher = chokidar.watch(watchPaths, {
48
+ ignoreInitial: true,
49
+ persistent: true,
50
+ ignored: (path) => {
51
+ const basename = path.split("/").pop() ?? "";
52
+ // Allow directories (no extension), .mjs files, and SKILL.md files
53
+ return (basename.includes(".") &&
54
+ !basename.endsWith(".mjs") &&
55
+ basename !== "SKILL.md");
56
+ },
57
+ });
58
+ function isRelevant(filePath) {
59
+ return filePath.endsWith(".mjs") || filePath.endsWith("SKILL.md");
60
+ }
61
+ watcher.on("add", (filePath) => {
62
+ if (isRelevant(filePath)) {
63
+ logger.debug({ filePath }, "Command/skill file added");
64
+ scheduleRepublish();
65
+ }
66
+ });
67
+ watcher.on("change", (filePath) => {
68
+ if (isRelevant(filePath)) {
69
+ logger.debug({ filePath }, "Command/skill file changed");
70
+ scheduleRepublish();
71
+ }
72
+ });
73
+ watcher.on("unlink", (filePath) => {
74
+ if (isRelevant(filePath)) {
75
+ logger.debug({ filePath }, "Command/skill file removed");
76
+ scheduleRepublish();
77
+ }
78
+ });
79
+ watcher.on("error", (err) => {
80
+ logger.error({ error: err instanceof Error ? err.message : String(err) }, "Command watcher error");
81
+ });
82
+ watcherInstance = watcher;
83
+ logger.debug({ projectCommandDir, globalCommandDir, skillsDir }, "Command watcher started");
84
+ }
85
+ catch (err) {
86
+ logger.error({ error: err instanceof Error ? err.message : String(err) }, "Failed to start command watcher");
87
+ }
88
+ })();
89
+ return {
90
+ stop: async () => {
91
+ // Cancel any pending debounce
92
+ if (debounceTimer !== null) {
93
+ clearTimeout(debounceTimer);
94
+ debounceTimer = null;
95
+ }
96
+ // Wait for watcher to be ready before closing
97
+ await watcherReady;
98
+ if (watcherInstance !== null) {
99
+ await watcherInstance.close();
100
+ watcherInstance = null;
101
+ logger.debug("Command watcher stopped");
102
+ }
103
+ },
104
+ };
105
+ }
106
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/bot/commands/watcher.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 document messages (PDFs, images, code files, etc.)
5
+ */
6
+ export declare function createDocumentHandler(ctx: ProjectContext): (gramCtx: Context) => Promise<void>;
7
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../../src/bot/handlers/document.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA4CrD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,IACzC,SAAS,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAmH/C"}