thepopebot 1.2.76-beta.2 → 1.2.76-beta.21
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 +3 -3
- package/api/CLAUDE.md +11 -4
- package/api/index.js +56 -18
- package/bin/CLAUDE.md +7 -4
- package/bin/cli.js +25 -45
- package/config/CLAUDE.md +23 -4
- package/drizzle/0021_coding_agent_workspace.sql +1 -0
- package/drizzle/0022_organic_apocalypse.sql +16 -0
- package/drizzle/0023_needy_ender_wiggin.sql +1 -0
- package/drizzle/meta/0021_snapshot.json +639 -0
- package/drizzle/meta/0022_snapshot.json +743 -0
- package/drizzle/meta/0023_snapshot.json +750 -0
- package/drizzle/meta/_journal.json +21 -0
- package/lib/CLAUDE.md +2 -2
- package/lib/actions.js +9 -1
- package/lib/ai/CLAUDE.md +72 -57
- package/lib/ai/helper-llm.js +108 -0
- package/lib/ai/index.js +308 -438
- package/lib/ai/line-mappers.js +42 -24
- package/lib/ai/scope.js +26 -0
- package/lib/ai/sdk-adapters/CLAUDE.md +114 -0
- package/lib/ai/sdk-adapters/claude-code.js +120 -8
- package/lib/ai/system-prompt.js +34 -0
- package/lib/ai/workspace-setup.js +19 -35
- package/lib/channels/CLAUDE.md +14 -4
- package/lib/channels/base.js +6 -2
- package/lib/channels/commands/index.js +42 -0
- package/lib/channels/commands/session.js +53 -0
- package/lib/channels/commands/verify.js +18 -0
- package/lib/channels/telegram.js +79 -28
- package/lib/chat/CLAUDE.md +4 -4
- package/lib/chat/actions.js +270 -49
- package/lib/chat/api.js +185 -31
- package/lib/chat/components/CLAUDE.md +6 -2
- package/lib/chat/components/chat-input.js +77 -47
- package/lib/chat/components/chat-input.jsx +77 -40
- package/lib/chat/components/chat-page.js +2 -0
- package/lib/chat/components/chat-page.jsx +3 -0
- package/lib/chat/components/chat.js +62 -14
- package/lib/chat/components/chat.jsx +68 -10
- package/lib/chat/components/code-mode-toggle.js +141 -22
- package/lib/chat/components/code-mode-toggle.jsx +129 -20
- package/lib/chat/components/containers-page.js +58 -40
- package/lib/chat/components/containers-page.jsx +64 -25
- package/lib/chat/components/crons-page.js +17 -3
- package/lib/chat/components/crons-page.jsx +34 -6
- package/lib/chat/components/index.js +2 -2
- package/lib/chat/components/message.js +18 -3
- package/lib/chat/components/message.jsx +18 -3
- package/lib/chat/components/profile-page.js +182 -4
- package/lib/chat/components/profile-page.jsx +196 -1
- package/lib/chat/components/scope-picker.js +21 -0
- package/lib/chat/components/scope-picker.jsx +27 -0
- package/lib/chat/components/settings-chat-page.js +11 -11
- package/lib/chat/components/settings-chat-page.jsx +14 -18
- package/lib/chat/components/settings-coding-agents-page.js +110 -16
- package/lib/chat/components/settings-coding-agents-page.jsx +87 -3
- package/lib/chat/components/settings-github-page.js +5 -0
- package/lib/chat/components/settings-github-page.jsx +5 -0
- package/lib/chat/components/settings-layout.js +3 -3
- package/lib/chat/components/settings-layout.jsx +3 -3
- package/lib/chat/components/settings-secrets-layout.js +1 -2
- package/lib/chat/components/settings-secrets-layout.jsx +1 -2
- package/lib/chat/components/settings-secrets-page.js +180 -75
- package/lib/chat/components/settings-secrets-page.jsx +212 -66
- package/lib/chat/components/triggers-page.js +17 -3
- package/lib/chat/components/triggers-page.jsx +34 -6
- package/lib/chat/components/ui/combobox.js +18 -2
- package/lib/chat/components/ui/combobox.jsx +17 -1
- package/lib/chat/components/ui/dropdown-menu.js +23 -2
- package/lib/chat/components/ui/dropdown-menu.jsx +27 -2
- package/lib/chat/telegram-profile.js +33 -0
- package/lib/cluster/CLAUDE.md +9 -3
- package/lib/code/CLAUDE.md +11 -3
- package/lib/code/actions.js +47 -8
- package/lib/code/terminal-view.js +31 -21
- package/lib/code/terminal-view.jsx +32 -23
- package/lib/config.js +15 -4
- package/lib/containers/CLAUDE.md +16 -6
- package/lib/db/CLAUDE.md +5 -2
- package/lib/db/chats.js +9 -17
- package/lib/db/code-workspaces.js +8 -3
- package/lib/db/config.js +0 -1
- package/lib/db/index.js +12 -0
- package/lib/db/schema.js +24 -1
- package/lib/db/user-channels.js +129 -0
- package/lib/llm-providers.js +8 -0
- package/lib/maintenance.js +31 -21
- package/lib/tools/CLAUDE.md +12 -3
- package/lib/tools/assemblyai.js +17 -0
- package/lib/tools/create-agent-job.js +12 -8
- package/lib/tools/docker.js +34 -10
- package/lib/tools/github.js +34 -0
- package/lib/tools/telegram.js +106 -0
- package/lib/utils/render-md.js +44 -18
- package/package.json +8 -8
- package/setup/CLAUDE.md +11 -5
- package/setup/lib/providers.mjs +2 -1
- package/setup/lib/targets.mjs +13 -16
- package/setup/lib/telegram.mjs +8 -69
- package/templates/.env.example +0 -7
- package/templates/.github/workflows/rebuild-event-handler.yml +1 -1
- package/templates/.gitignore.template +1 -3
- package/templates/CLAUDE.md +1 -1
- package/templates/CLAUDE.md.template +29 -7
- package/templates/agent-job/CLAUDE.md.template +5 -3
- package/templates/agent-job/CRONS.json +16 -0
- package/templates/agent-job/SYSTEM.md +16 -11
- package/templates/agents/CLAUDE.md.template +17 -17
- package/templates/coding-workspace/CLAUDE.md.template +7 -0
- package/templates/data/CLAUDE.md.template +1 -1
- package/templates/docker-compose.custom.yml +1 -0
- package/templates/docker-compose.yml +1 -0
- package/templates/event-handler/CLAUDE.md.template +79 -0
- package/templates/event-handler/TRIGGERS.json +18 -2
- package/templates/skills/CLAUDE.md.template +20 -22
- package/templates/skills/{library/agent-job-secrets → agent-job-secrets}/SKILL.md +2 -2
- package/lib/ai/agent.js +0 -65
- package/lib/ai/async-channel.js +0 -51
- package/lib/ai/model.js +0 -130
- package/lib/ai/tools.js +0 -164
- package/lib/tools/openai.js +0 -37
- package/setup/lib/telegram-verify.mjs +0 -63
- package/setup/setup-telegram.mjs +0 -260
- package/templates/agent-job/SOUL.md +0 -17
- /package/templates/{skills/active/.gitkeep → coding-workspace/SYSTEM.md} +0 -0
- /package/templates/skills/{library/agent-job-secrets → agent-job-secrets}/agent-job-secrets.js +0 -0
- /package/templates/skills/{library/playwright-cli → playwright-cli}/SKILL.md +0 -0
package/lib/chat/actions.js
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
getChatByWorkspaceId,
|
|
8
8
|
getMessagesByChatId,
|
|
9
9
|
deleteChat as dbDeleteChat,
|
|
10
|
-
deleteAllChatsByUser,
|
|
11
10
|
updateChatTitle,
|
|
12
11
|
toggleChatStarred,
|
|
13
12
|
} from '../db/chats.js';
|
|
@@ -139,15 +138,6 @@ export async function starChat(chatId) {
|
|
|
139
138
|
return { success: true, starred };
|
|
140
139
|
}
|
|
141
140
|
|
|
142
|
-
/**
|
|
143
|
-
* Delete all chats for the authenticated user.
|
|
144
|
-
* @returns {Promise<{success: boolean}>}
|
|
145
|
-
*/
|
|
146
|
-
export async function deleteAllChats() {
|
|
147
|
-
const user = await requireAuth();
|
|
148
|
-
deleteAllChatsByUser(user.id);
|
|
149
|
-
return { success: true };
|
|
150
|
-
}
|
|
151
141
|
|
|
152
142
|
/**
|
|
153
143
|
* Get notifications, newest first, with pagination.
|
|
@@ -666,6 +656,10 @@ export async function getCodingAgentSettings() {
|
|
|
666
656
|
const kimiCliEnabled = getConfig('CODING_AGENT_KIMI_CLI_ENABLED');
|
|
667
657
|
const kimiCliProvider = getConfig('CODING_AGENT_KIMI_CLI_PROVIDER') || '';
|
|
668
658
|
const kimiCliModel = getConfig('CODING_AGENT_KIMI_CLI_MODEL') || '';
|
|
659
|
+
const agentModeBranch = getConfig('AGENT_MODE_BRANCH');
|
|
660
|
+
const codeModeBranch = getConfig('CODE_MODE_BRANCH');
|
|
661
|
+
const agentModeGitAction = getConfig('AGENT_MODE_GIT_ACTION');
|
|
662
|
+
const codeModeGitAction = getConfig('CODE_MODE_GIT_ACTION');
|
|
669
663
|
|
|
670
664
|
// Credential readiness
|
|
671
665
|
const oauthTokenCount = getOAuthTokenCount('claudeCode');
|
|
@@ -712,6 +706,10 @@ export async function getCodingAgentSettings() {
|
|
|
712
706
|
provider: kimiCliProvider,
|
|
713
707
|
model: kimiCliModel,
|
|
714
708
|
},
|
|
709
|
+
modeDefaults: {
|
|
710
|
+
agent: { branch: agentModeBranch, gitAction: agentModeGitAction },
|
|
711
|
+
code: { branch: codeModeBranch, gitAction: codeModeGitAction },
|
|
712
|
+
},
|
|
715
713
|
builtinProviders: BUILTIN_PROVIDERS,
|
|
716
714
|
credentialStatuses,
|
|
717
715
|
customProviders,
|
|
@@ -722,6 +720,66 @@ export async function getCodingAgentSettings() {
|
|
|
722
720
|
}
|
|
723
721
|
}
|
|
724
722
|
|
|
723
|
+
/**
|
|
724
|
+
* Return the list of coding agents that are enabled and have valid credentials.
|
|
725
|
+
* Used to populate the right-click agent picker on the Interactive toggle.
|
|
726
|
+
* @returns {Promise<Array<{value: string, label: string}>>}
|
|
727
|
+
*/
|
|
728
|
+
export async function getAvailableCodingAgents() {
|
|
729
|
+
await requireAuth();
|
|
730
|
+
try {
|
|
731
|
+
const settings = await getCodingAgentSettings();
|
|
732
|
+
if (settings.error) return [];
|
|
733
|
+
|
|
734
|
+
const statusMap = new Map((settings.credentialStatuses || []).map(s => [s.key, s.isSet]));
|
|
735
|
+
|
|
736
|
+
function isProviderReady(provider) {
|
|
737
|
+
const builtin = settings.builtinProviders?.[provider];
|
|
738
|
+
if (builtin?.credentialKey) return statusMap.get(builtin.credentialKey) || false;
|
|
739
|
+
// Custom providers store their own credentials — if selected they're ready
|
|
740
|
+
const custom = (settings.customProviders || []).find(p => p.id === provider);
|
|
741
|
+
return !!custom;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const available = [];
|
|
745
|
+
|
|
746
|
+
if (settings.claudeCode?.enabled) {
|
|
747
|
+
const { claudeCode } = settings;
|
|
748
|
+
const backend = claudeCode.backend || 'anthropic';
|
|
749
|
+
const ready = backend === 'anthropic'
|
|
750
|
+
? (claudeCode.auth === 'oauth' ? claudeCode.oauthTokenCount > 0 : claudeCode.anthropicKeySet)
|
|
751
|
+
: isProviderReady(backend);
|
|
752
|
+
if (ready) available.push({ value: 'claude-code', label: 'Claude Code' });
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (settings.pi?.enabled && settings.pi?.provider && isProviderReady(settings.pi.provider)) {
|
|
756
|
+
available.push({ value: 'pi-coding-agent', label: 'Pi' });
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if (settings.geminiCli?.enabled && settings.geminiCli?.googleKeySet) {
|
|
760
|
+
available.push({ value: 'gemini-cli', label: 'Gemini CLI' });
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (settings.codexCli?.enabled) {
|
|
764
|
+
const { codexCli } = settings;
|
|
765
|
+
const ready = codexCli.auth === 'oauth' ? codexCli.oauthTokenCount > 0 : codexCli.codexKeySet;
|
|
766
|
+
if (ready) available.push({ value: 'codex-cli', label: 'Codex CLI' });
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (settings.openCode?.enabled && settings.openCode?.provider && isProviderReady(settings.openCode.provider)) {
|
|
770
|
+
available.push({ value: 'opencode', label: 'OpenCode' });
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (settings.kimiCli?.enabled && settings.kimiCli?.provider && isProviderReady(settings.kimiCli.provider)) {
|
|
774
|
+
available.push({ value: 'kimi-cli', label: 'Kimi CLI' });
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return available;
|
|
778
|
+
} catch {
|
|
779
|
+
return [];
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
725
783
|
/**
|
|
726
784
|
* Update per-agent coding agent config.
|
|
727
785
|
* @param {string} agent - 'claude-code' or 'pi-coding-agent'
|
|
@@ -790,6 +848,54 @@ export async function setCodingAgentDefault(agent) {
|
|
|
790
848
|
}
|
|
791
849
|
}
|
|
792
850
|
|
|
851
|
+
const MODE_BRANCH_VALUES = new Set(['default', 'dynamic']);
|
|
852
|
+
const MODE_GIT_ACTION_VALUES = new Set(['commit', 'push', 'create-pr', 'pull']);
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Get the admin-configured default git action for a chat mode.
|
|
856
|
+
* Used by the chat UI to seed the workspace command dropdown.
|
|
857
|
+
* @param {'agent'|'code'} mode
|
|
858
|
+
*/
|
|
859
|
+
export async function getModeGitActionDefault(mode) {
|
|
860
|
+
await requireAuth();
|
|
861
|
+
if (mode !== 'agent' && mode !== 'code') return null;
|
|
862
|
+
const { getConfig } = await import('../config.js');
|
|
863
|
+
return getConfig(mode === 'code' ? 'CODE_MODE_GIT_ACTION' : 'AGENT_MODE_GIT_ACTION') || null;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Set a per-mode default (branch behavior or git action).
|
|
868
|
+
* @param {'agent'|'code'} mode
|
|
869
|
+
* @param {'branch'|'gitAction'} field
|
|
870
|
+
* @param {string} value
|
|
871
|
+
*/
|
|
872
|
+
export async function setModeDefault(mode, field, value) {
|
|
873
|
+
await requireAuth();
|
|
874
|
+
try {
|
|
875
|
+
if (mode !== 'agent' && mode !== 'code') return { error: 'Invalid mode' };
|
|
876
|
+
if (field === 'branch' && !MODE_BRANCH_VALUES.has(value)) return { error: 'Invalid branch value' };
|
|
877
|
+
if (field === 'gitAction' && !MODE_GIT_ACTION_VALUES.has(value)) return { error: 'Invalid git action value' };
|
|
878
|
+
|
|
879
|
+
const keyMap = {
|
|
880
|
+
'agent.branch': 'AGENT_MODE_BRANCH',
|
|
881
|
+
'code.branch': 'CODE_MODE_BRANCH',
|
|
882
|
+
'agent.gitAction': 'AGENT_MODE_GIT_ACTION',
|
|
883
|
+
'code.gitAction': 'CODE_MODE_GIT_ACTION',
|
|
884
|
+
};
|
|
885
|
+
const key = keyMap[`${mode}.${field}`];
|
|
886
|
+
if (!key) return { error: 'Invalid field' };
|
|
887
|
+
|
|
888
|
+
const { setConfigValue } = await import('../db/config.js');
|
|
889
|
+
const { invalidateConfigCache } = await import('../config.js');
|
|
890
|
+
setConfigValue(key, value);
|
|
891
|
+
invalidateConfigCache();
|
|
892
|
+
return { success: true };
|
|
893
|
+
} catch (err) {
|
|
894
|
+
console.error('Failed to set mode default:', err);
|
|
895
|
+
return { error: 'Failed to set mode default' };
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
793
899
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
794
900
|
// Settings — General sub-tab
|
|
795
901
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -846,7 +952,6 @@ const API_KEY_SECRETS = new Set([
|
|
|
846
952
|
'TELEGRAM_WEBHOOK_SECRET',
|
|
847
953
|
'ASSEMBLYAI_API_KEY',
|
|
848
954
|
]);
|
|
849
|
-
const API_KEY_CONFIGS = new Set(['TELEGRAM_CHAT_ID']);
|
|
850
955
|
|
|
851
956
|
/**
|
|
852
957
|
* Get settings for the API Keys sub-tab.
|
|
@@ -854,11 +959,9 @@ const API_KEY_CONFIGS = new Set(['TELEGRAM_CHAT_ID']);
|
|
|
854
959
|
export async function getApiKeySettings() {
|
|
855
960
|
await requireAuth();
|
|
856
961
|
try {
|
|
857
|
-
const { getSecretStatus
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
const telegramChatId = getConfigValue('TELEGRAM_CHAT_ID');
|
|
861
|
-
return { secrets: statuses, telegramChatId };
|
|
962
|
+
const { getSecretStatus } = await import('../db/config.js');
|
|
963
|
+
const statuses = getSecretStatus([...API_KEY_SECRETS]);
|
|
964
|
+
return { secrets: statuses };
|
|
862
965
|
} catch (err) {
|
|
863
966
|
console.error('Failed to get API key settings:', err);
|
|
864
967
|
return { error: 'Failed to load settings' };
|
|
@@ -870,20 +973,17 @@ export async function getApiKeySettings() {
|
|
|
870
973
|
*/
|
|
871
974
|
export async function updateApiKeySetting(key, value) {
|
|
872
975
|
const user = await requireAuth();
|
|
976
|
+
if (!API_KEY_SECRETS.has(key)) {
|
|
977
|
+
return { error: 'Invalid key' };
|
|
978
|
+
}
|
|
873
979
|
try {
|
|
874
|
-
const { setConfigSecret,
|
|
980
|
+
const { setConfigSecret, deleteConfigSecret } = await import('../db/config.js');
|
|
875
981
|
const { invalidateConfigCache } = await import('../config.js');
|
|
876
982
|
|
|
877
|
-
if (
|
|
878
|
-
|
|
879
|
-
setConfigSecret(key, value, user.id);
|
|
880
|
-
} else {
|
|
881
|
-
deleteConfigSecret(key);
|
|
882
|
-
}
|
|
883
|
-
} else if (API_KEY_CONFIGS.has(key)) {
|
|
884
|
-
setConfigValue(key, value, user.id);
|
|
983
|
+
if (value) {
|
|
984
|
+
setConfigSecret(key, value, user.id);
|
|
885
985
|
} else {
|
|
886
|
-
|
|
986
|
+
deleteConfigSecret(key);
|
|
887
987
|
}
|
|
888
988
|
|
|
889
989
|
invalidateConfigCache();
|
|
@@ -916,12 +1016,114 @@ export async function regenerateWebhookSecret(key) {
|
|
|
916
1016
|
}
|
|
917
1017
|
}
|
|
918
1018
|
|
|
1019
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1020
|
+
// Settings — Telegram setup flow
|
|
1021
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Get Telegram status: bot info (if token valid) and webhook info.
|
|
1025
|
+
* Used by the admin UI to render the current state of each setup step.
|
|
1026
|
+
*/
|
|
1027
|
+
export async function getTelegramStatus() {
|
|
1028
|
+
await requireAuth();
|
|
1029
|
+
try {
|
|
1030
|
+
const { getConfigSecret } = await import('../db/config.js');
|
|
1031
|
+
const { validateBotToken, getTelegramWebhookInfo } = await import('../tools/telegram.js');
|
|
1032
|
+
|
|
1033
|
+
const botToken = getConfigSecret('TELEGRAM_BOT_TOKEN');
|
|
1034
|
+
const webhookSecret = getConfigSecret('TELEGRAM_WEBHOOK_SECRET');
|
|
1035
|
+
|
|
1036
|
+
let botInfo = null;
|
|
1037
|
+
let webhookInfo = null;
|
|
1038
|
+
if (botToken) {
|
|
1039
|
+
const v = await validateBotToken(botToken);
|
|
1040
|
+
if (v.valid) botInfo = { username: v.botInfo.username, id: v.botInfo.id };
|
|
1041
|
+
try {
|
|
1042
|
+
const info = await getTelegramWebhookInfo(botToken);
|
|
1043
|
+
if (info.ok) {
|
|
1044
|
+
webhookInfo = {
|
|
1045
|
+
url: info.result.url || null,
|
|
1046
|
+
hasCustomCertificate: info.result.has_custom_certificate,
|
|
1047
|
+
pendingUpdates: info.result.pending_update_count,
|
|
1048
|
+
lastErrorMessage: info.result.last_error_message || null,
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
} catch {
|
|
1052
|
+
// ignore — webhook info is best-effort
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return {
|
|
1057
|
+
botInfo,
|
|
1058
|
+
botTokenSet: !!botToken,
|
|
1059
|
+
webhookSecretSet: !!webhookSecret,
|
|
1060
|
+
webhookInfo,
|
|
1061
|
+
};
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
console.error('Failed to get Telegram status:', err);
|
|
1064
|
+
return { error: 'Failed to load Telegram status' };
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Validate a Telegram bot token without saving it.
|
|
1070
|
+
* Called from the UI as the user pastes a token to show live feedback.
|
|
1071
|
+
*/
|
|
1072
|
+
export async function validateTelegramToken(token) {
|
|
1073
|
+
await requireAuth();
|
|
1074
|
+
if (!token) return { valid: false, error: 'Token is required' };
|
|
1075
|
+
try {
|
|
1076
|
+
const { validateBotToken } = await import('../tools/telegram.js');
|
|
1077
|
+
const result = await validateBotToken(token);
|
|
1078
|
+
if (result.valid) {
|
|
1079
|
+
return { valid: true, botInfo: { username: result.botInfo.username, id: result.botInfo.id } };
|
|
1080
|
+
}
|
|
1081
|
+
return { valid: false, error: result.error };
|
|
1082
|
+
} catch (err) {
|
|
1083
|
+
return { valid: false, error: err.message };
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Register the Telegram webhook with the currently saved bot token.
|
|
1089
|
+
* Generates a fresh webhook secret, saves it, and calls Telegram's setWebhook.
|
|
1090
|
+
* APP_URL must be configured.
|
|
1091
|
+
*/
|
|
1092
|
+
export async function registerTelegramWebhook() {
|
|
1093
|
+
const user = await requireAuth();
|
|
1094
|
+
try {
|
|
1095
|
+
const { getConfigSecret, setConfigSecret } = await import('../db/config.js');
|
|
1096
|
+
const { invalidateConfigCache, getConfig } = await import('../config.js');
|
|
1097
|
+
const { setTelegramWebhook, generateWebhookSecret } = await import('../tools/telegram.js');
|
|
1098
|
+
|
|
1099
|
+
const botToken = getConfigSecret('TELEGRAM_BOT_TOKEN');
|
|
1100
|
+
if (!botToken) return { error: 'Bot token must be set first' };
|
|
1101
|
+
|
|
1102
|
+
const appUrl = getConfig('APP_URL');
|
|
1103
|
+
if (!appUrl) return { error: 'APP_URL must be configured first' };
|
|
1104
|
+
|
|
1105
|
+
const webhookUrl = `${appUrl.replace(/\/$/, '')}/api/telegram/webhook`;
|
|
1106
|
+
const secret = generateWebhookSecret();
|
|
1107
|
+
setConfigSecret('TELEGRAM_WEBHOOK_SECRET', secret, user.id);
|
|
1108
|
+
invalidateConfigCache();
|
|
1109
|
+
|
|
1110
|
+
const result = await setTelegramWebhook(botToken, webhookUrl, secret);
|
|
1111
|
+
if (!result.ok) {
|
|
1112
|
+
return { error: result.description || 'Failed to register webhook' };
|
|
1113
|
+
}
|
|
1114
|
+
return { success: true, webhookUrl };
|
|
1115
|
+
} catch (err) {
|
|
1116
|
+
console.error('Failed to register Telegram webhook:', err);
|
|
1117
|
+
return { error: err.message };
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
919
1121
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
920
1122
|
// Settings — Chat sub-tab
|
|
921
1123
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
922
1124
|
|
|
923
1125
|
/**
|
|
924
|
-
* Get settings for the
|
|
1126
|
+
* Get settings for the Helper LLM page (and Providers page — both share this).
|
|
925
1127
|
*/
|
|
926
1128
|
export async function getChatSettings() {
|
|
927
1129
|
await requireAuth();
|
|
@@ -936,34 +1138,16 @@ export async function getChatSettings() {
|
|
|
936
1138
|
// Get custom providers (masked)
|
|
937
1139
|
const customProviders = getCustomProviders();
|
|
938
1140
|
|
|
939
|
-
// Get active config
|
|
1141
|
+
// Get active helper LLM config
|
|
940
1142
|
const activeProvider = getConfigValue('LLM_PROVIDER') || '';
|
|
941
1143
|
const activeModel = getConfigValue('LLM_MODEL') || '';
|
|
942
1144
|
const maxTokens = getConfigValue('LLM_MAX_TOKENS') || '4096';
|
|
943
1145
|
const agentBackend = getConfigValue('AGENT_BACKEND') || '';
|
|
944
1146
|
|
|
945
|
-
// Check if the current coding agent has an in-process SDK adapter
|
|
946
|
-
const { getConfig } = await import('../config.js');
|
|
947
|
-
const { getSdkAdapter } = await import('../ai/sdk-adapters/index.js');
|
|
948
|
-
const codingAgent = getConfig('CODING_AGENT');
|
|
949
|
-
const sdkAgentActive = !!getSdkAdapter(codingAgent);
|
|
950
|
-
|
|
951
|
-
// Human-readable agent names
|
|
952
|
-
const agentNames = {
|
|
953
|
-
'claude-code': 'Claude Code',
|
|
954
|
-
'pi-coding-agent': 'Pi Coding Agent',
|
|
955
|
-
'gemini-cli': 'Gemini CLI',
|
|
956
|
-
'codex-cli': 'Codex CLI',
|
|
957
|
-
'opencode': 'OpenCode',
|
|
958
|
-
'kimi-cli': 'Kimi CLI',
|
|
959
|
-
};
|
|
960
|
-
|
|
961
1147
|
return {
|
|
962
1148
|
builtinProviders: BUILTIN_PROVIDERS,
|
|
963
1149
|
credentialStatuses,
|
|
964
1150
|
customProviders,
|
|
965
|
-
sdkAgentActive,
|
|
966
|
-
defaultAgent: agentNames[codingAgent] || codingAgent,
|
|
967
1151
|
active: {
|
|
968
1152
|
provider: activeProvider,
|
|
969
1153
|
model: activeModel,
|
|
@@ -972,8 +1156,8 @@ export async function getChatSettings() {
|
|
|
972
1156
|
},
|
|
973
1157
|
};
|
|
974
1158
|
} catch (err) {
|
|
975
|
-
console.error('Failed to get
|
|
976
|
-
return { error: 'Failed to load
|
|
1159
|
+
console.error('Failed to get helper LLM settings:', err);
|
|
1160
|
+
return { error: 'Failed to load helper LLM settings' };
|
|
977
1161
|
}
|
|
978
1162
|
}
|
|
979
1163
|
|
|
@@ -1189,6 +1373,7 @@ export async function getGitHubConfig() {
|
|
|
1189
1373
|
}
|
|
1190
1374
|
|
|
1191
1375
|
// Build variables list: known names + any extras, with current value
|
|
1376
|
+
const variablesError = !Array.isArray(remoteVariables) ? (remoteVariables?.error || 'Failed to load variables') : null;
|
|
1192
1377
|
const remoteVarMap = new Map(
|
|
1193
1378
|
Array.isArray(remoteVariables) ? remoteVariables.map((v) => [v.name, v.value]) : []
|
|
1194
1379
|
);
|
|
@@ -1199,7 +1384,7 @@ export async function getGitHubConfig() {
|
|
|
1199
1384
|
}
|
|
1200
1385
|
}
|
|
1201
1386
|
|
|
1202
|
-
return { secrets, variables };
|
|
1387
|
+
return { secrets, variables, variablesError };
|
|
1203
1388
|
}
|
|
1204
1389
|
|
|
1205
1390
|
/**
|
|
@@ -1348,3 +1533,39 @@ export async function deleteGitHubVariableAction(name) {
|
|
|
1348
1533
|
}
|
|
1349
1534
|
}
|
|
1350
1535
|
|
|
1536
|
+
/**
|
|
1537
|
+
* Issue (or re-issue) a Telegram verification code for the current user.
|
|
1538
|
+
* Returns the code, expiry, and the bot's @username for instructions.
|
|
1539
|
+
*/
|
|
1540
|
+
export async function issueTelegramCode() {
|
|
1541
|
+
const user = await requireAuth();
|
|
1542
|
+
const { issueCode } = await import('../db/user-channels.js');
|
|
1543
|
+
const { getConfig } = await import('../config.js');
|
|
1544
|
+
const { validateBotToken } = await import('../tools/telegram.js');
|
|
1545
|
+
|
|
1546
|
+
try {
|
|
1547
|
+
const row = issueCode(user.id, 'telegram');
|
|
1548
|
+
const botToken = getConfig('TELEGRAM_BOT_TOKEN');
|
|
1549
|
+
let botUsername = null;
|
|
1550
|
+
if (botToken) {
|
|
1551
|
+
const info = await validateBotToken(botToken);
|
|
1552
|
+
if (info.valid) botUsername = info.botInfo.username;
|
|
1553
|
+
}
|
|
1554
|
+
return { code: row.code, expiresAt: row.codeExpiresAt, botUsername };
|
|
1555
|
+
} catch (err) {
|
|
1556
|
+
// If already verified, surface that so the UI can offer "unlink first"
|
|
1557
|
+
return { error: err.message };
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Unlink the current user's Telegram channel binding.
|
|
1563
|
+
*/
|
|
1564
|
+
export async function unlinkTelegramChannel() {
|
|
1565
|
+
const user = await requireAuth();
|
|
1566
|
+
const { unlink } = await import('../db/user-channels.js');
|
|
1567
|
+
unlink(user.id, 'telegram');
|
|
1568
|
+
return { ok: true };
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
|