@link-assistant/hive-mind 1.65.2 → 1.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Telegram /language command implementation.
3
+ *
4
+ * Allows each user to override the bot's reply language for the current
5
+ * process. The override is in-memory only (resets when the bot restarts).
6
+ *
7
+ * Usage in chat:
8
+ * /language -> show current language
9
+ * /language <en|ru|zh|hi> -> set language for this user
10
+ * /language default -> clear the override (reset|clear also work)
11
+ */
12
+
13
+ import { t, getSupportedLocales, normalizeLocale, setUserLocale, clearUserLocale, resolveLocaleFromTelegramCtx } from './i18n.lib.mjs';
14
+
15
+ export function registerLanguageCommand(bot, options = {}) {
16
+ const { VERBOSE = false, isOldMessage, isForwardedOrReply } = options;
17
+
18
+ bot.command('language', async ctx => {
19
+ VERBOSE && console.log('[VERBOSE] /language command received');
20
+ if (isOldMessage?.(ctx) || isForwardedOrReply?.(ctx)) return;
21
+ const userId = ctx.from?.id;
22
+ const locale = resolveLocaleFromTelegramCtx(ctx);
23
+ const supported = getSupportedLocales();
24
+ const supportedList = supported.join(', ');
25
+ const text = ctx.message?.text || '';
26
+ const parts = text.trim().split(/\s+/);
27
+ const arg = parts.length > 1 ? parts[1] : null;
28
+ if (!arg) {
29
+ const langName = t(`language.${locale}`, {}, { locale });
30
+ await ctx.reply(t('telegram.language_current', { language: langName, supported: supportedList }, { locale }), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id });
31
+ return;
32
+ }
33
+ if (['default', 'reset', 'clear'].includes(arg.toLowerCase())) {
34
+ clearUserLocale(userId);
35
+ const newLocale = resolveLocaleFromTelegramCtx(ctx);
36
+ const langName = t(`language.${newLocale}`, {}, { locale: newLocale });
37
+ await ctx.reply(t('telegram.language_set', { language: langName }, { locale: newLocale }), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id });
38
+ return;
39
+ }
40
+ const target = normalizeLocale(arg);
41
+ if (!target) {
42
+ await ctx.reply(t('telegram.language_invalid', { supported: supportedList }, { locale }), { reply_to_message_id: ctx.message.message_id });
43
+ return;
44
+ }
45
+ setUserLocale(userId, target);
46
+ const langName = t(`language.${target}`, {}, { locale: target });
47
+ await ctx.reply(t('telegram.language_set', { language: langName }, { locale: target }), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id });
48
+ });
49
+ }
@@ -82,8 +82,20 @@ async function editTelegramMessage(ctx, message, text) {
82
82
  }
83
83
  }
84
84
 
85
+ // Issue #378: inject --language LOCALE into spawn args if no language flag is
86
+ // already present, so spawned task sessions inherit the user's effective locale.
87
+ function injectLanguageIfMissing(args, locale) {
88
+ if (!locale || !args || !Array.isArray(args)) return args;
89
+ const langFlags = new Set(['--language', '--ui-language', '--work-language']);
90
+ for (const arg of args) {
91
+ const flag = arg.startsWith('--') ? arg.split('=')[0] : null;
92
+ if (flag && langFlags.has(flag)) return args;
93
+ }
94
+ return [...args, '--language', locale];
95
+ }
96
+
85
97
  export function registerTaskCommands(bot, options) {
86
- const { VERBOSE, taskEnabled, addBreadcrumb, isOldMessage, isGroupChat, isTopicAuthorized, buildAuthErrorMessage, isChatStopped, getStoppedChatRejectMessage, safeReply, executeAndUpdateMessage, createTaskIssue: createTaskIssueFn = createTaskIssue } = options;
98
+ const { VERBOSE, taskEnabled, addBreadcrumb, isOldMessage, isGroupChat, isTopicAuthorized, buildAuthErrorMessage, isChatStopped, getStoppedChatRejectMessage, safeReply, executeAndUpdateMessage, createTaskIssue: createTaskIssueFn = createTaskIssue, resolveLocale = null } = options;
87
99
 
88
100
  async function handleTaskCommand(ctx) {
89
101
  const commandName = getTaskCommandNameFromText(ctx.message?.text) || 'task';
@@ -179,7 +191,9 @@ export function registerTaskCommands(bot, options) {
179
191
 
180
192
  const taskUrlContext = { owner: parsedIssue.owner, repo: parsedIssue.repo, number: parsedIssue.number, type: parsedIssue.type, normalized: parsedIssue.normalized || built.issueUrl };
181
193
  const startingMessage = await safeReply(ctx, formatStartingWorkSessionMessage({ infoBlock }), { reply_to_message_id: ctx.message.message_id });
182
- await executeAndUpdateMessage(ctx, startingMessage, 'task', filteredArgs, infoBlock, perCommandIsolation || null, getTaskToolFromArgs(filteredArgs), taskUrlContext);
194
+ const taskLocale = resolveLocale ? resolveLocale(ctx) : null;
195
+ const argsForExec = injectLanguageIfMissing(filteredArgs, taskLocale);
196
+ await executeAndUpdateMessage(ctx, startingMessage, 'task', argsForExec, infoBlock, perCommandIsolation || null, getTaskToolFromArgs(argsForExec), taskUrlContext);
183
197
  }
184
198
 
185
199
  bot.command(
@@ -0,0 +1,22 @@
1
+ // Issue #378: shared helper that emits a "working language" directive to be
2
+ // appended to every tool's system prompt. The directive is empty for English
3
+ // (default), and tells the model to communicate with the user in the chosen
4
+ // work language for free-form text (PR/issue comments, commit messages, chat),
5
+ // while keeping code, identifiers, and CLI strings as-is.
6
+
7
+ import { getWorkLocale } from './i18n.lib.mjs';
8
+
9
+ const LOCALE_DISPLAY_NAMES = Object.freeze({
10
+ en: 'English',
11
+ ru: 'Russian',
12
+ zh: 'Chinese (Simplified)',
13
+ hi: 'Hindi',
14
+ });
15
+
16
+ export function buildWorkLanguageDirective(locale = getWorkLocale()) {
17
+ if (!locale || locale === 'en') return '';
18
+ const name = LOCALE_DISPLAY_NAMES[locale] || locale;
19
+ return `\n\nWorking language: ${name}. When you communicate with the user via comments, commit messages, pull request titles/descriptions, and chat replies, use ${name}. Code, identifiers, and command-line strings stay in their original form.`;
20
+ }
21
+
22
+ export default { buildWorkLanguageDirective };