@harbinger-ai/harbinger 0.1.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.
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/agents/README.md +76 -0
- package/agents/_template/CONFIG.yaml +7 -0
- package/agents/_template/HEARTBEAT.md +59 -0
- package/agents/_template/IDENTITY.md +4 -0
- package/agents/_template/SKILLS.md +1 -0
- package/agents/_template/SOUL.md +25 -0
- package/agents/_template/TOOLS.md +3 -0
- package/agents/binary-reverser/CONFIG.yaml +21 -0
- package/agents/binary-reverser/HEARTBEAT.md +65 -0
- package/agents/binary-reverser/IDENTITY.md +1 -0
- package/agents/binary-reverser/SKILLS.md +1 -0
- package/agents/binary-reverser/SOUL.md +23 -0
- package/agents/binary-reverser/TOOLS.md +99 -0
- package/agents/browser-agent/CONFIG.yaml +20 -0
- package/agents/browser-agent/HEARTBEAT.md +79 -0
- package/agents/browser-agent/IDENTITY.md +5 -0
- package/agents/browser-agent/SKILLS.md +86 -0
- package/agents/browser-agent/SOUL.md +23 -0
- package/agents/browser-agent/TOOLS.md +186 -0
- package/agents/cloud-infiltrator/CONFIG.yaml +22 -0
- package/agents/cloud-infiltrator/HEARTBEAT.md +78 -0
- package/agents/cloud-infiltrator/IDENTITY.md +1 -0
- package/agents/cloud-infiltrator/SKILLS.md +1 -0
- package/agents/cloud-infiltrator/SOUL.md +23 -0
- package/agents/cloud-infiltrator/TOOLS.md +68 -0
- package/agents/coding-assistant/CONFIG.yaml +22 -0
- package/agents/coding-assistant/HEARTBEAT.md +57 -0
- package/agents/coding-assistant/IDENTITY.md +5 -0
- package/agents/coding-assistant/SKILLS.md +69 -0
- package/agents/coding-assistant/SOUL.md +60 -0
- package/agents/coding-assistant/TOOLS.md +168 -0
- package/agents/learning-agent/CONFIG.yaml +21 -0
- package/agents/learning-agent/HEARTBEAT.md +63 -0
- package/agents/learning-agent/IDENTITY.md +5 -0
- package/agents/learning-agent/SKILLS.md +86 -0
- package/agents/learning-agent/SOUL.md +77 -0
- package/agents/learning-agent/TOOLS.md +145 -0
- package/agents/maintainer/CONFIG.yaml +31 -0
- package/agents/maintainer/HEARTBEAT.md +28 -0
- package/agents/maintainer/IDENTITY.md +33 -0
- package/agents/maintainer/SKILLS.md +24 -0
- package/agents/maintainer/SOUL.md +61 -0
- package/agents/maintainer/TOOLS.md +29 -0
- package/agents/maintainer/lib/engine.js +279 -0
- package/agents/maintainer/lib/safe-fixer.js +183 -0
- package/agents/morning-brief/CONFIG.yaml +22 -0
- package/agents/morning-brief/HEARTBEAT.md +60 -0
- package/agents/morning-brief/IDENTITY.md +5 -0
- package/agents/morning-brief/SKILLS.md +56 -0
- package/agents/morning-brief/SOUL.md +64 -0
- package/agents/morning-brief/TOOLS.md +112 -0
- package/agents/osint-detective/CONFIG.yaml +24 -0
- package/agents/osint-detective/HEARTBEAT.md +66 -0
- package/agents/osint-detective/IDENTITY.md +1 -0
- package/agents/osint-detective/SKILLS.md +1 -0
- package/agents/osint-detective/SOUL.md +23 -0
- package/agents/osint-detective/TOOLS.md +81 -0
- package/agents/recon-scout/CONFIG.yaml +22 -0
- package/agents/recon-scout/HEARTBEAT.md +79 -0
- package/agents/recon-scout/IDENTITY.md +1 -0
- package/agents/recon-scout/SKILLS.md +1 -0
- package/agents/recon-scout/SOUL.md +23 -0
- package/agents/recon-scout/TOOLS.md +93 -0
- package/agents/report-writer/CONFIG.yaml +21 -0
- package/agents/report-writer/HEARTBEAT.md +63 -0
- package/agents/report-writer/IDENTITY.md +1 -0
- package/agents/report-writer/SKILLS.md +1 -0
- package/agents/report-writer/SOUL.md +23 -0
- package/agents/report-writer/TOOLS.md +69 -0
- package/agents/shared/README.md +13 -0
- package/agents/web-hacker/CONFIG.yaml +24 -0
- package/agents/web-hacker/HEARTBEAT.md +78 -0
- package/agents/web-hacker/IDENTITY.md +1 -0
- package/agents/web-hacker/SKILLS.md +1 -0
- package/agents/web-hacker/SOUL.md +23 -0
- package/agents/web-hacker/TOOLS.md +86 -0
- package/api/CLAUDE.md +19 -0
- package/api/index.js +274 -0
- package/bin/cli.js +620 -0
- package/bin/local.sh +31 -0
- package/bin/postinstall.js +63 -0
- package/config/index.js +24 -0
- package/config/instrumentation.js +93 -0
- package/drizzle/0000_initial.sql +52 -0
- package/drizzle/0001_bounty_and_registry.sql +82 -0
- package/drizzle/0002_sync_columns.sql +7 -0
- package/drizzle/0003_graceful_bloodscream.sql +86 -0
- package/drizzle/meta/0000_snapshot.json +321 -0
- package/drizzle/meta/0003_snapshot.json +878 -0
- package/drizzle/meta/_journal.json +34 -0
- package/drizzle/relations.ts +3 -0
- package/drizzle/schema.ts +145 -0
- package/lib/actions.js +47 -0
- package/lib/agents.js +166 -0
- package/lib/ai/agent.js +96 -0
- package/lib/ai/autonomous-engine.js +261 -0
- package/lib/ai/index.js +359 -0
- package/lib/ai/model-router.js +254 -0
- package/lib/ai/model.js +73 -0
- package/lib/ai/tools.js +84 -0
- package/lib/auth/actions.js +28 -0
- package/lib/auth/config.js +27 -0
- package/lib/auth/edge-config.js +27 -0
- package/lib/auth/index.js +27 -0
- package/lib/auth/middleware.js +53 -0
- package/lib/bounty/actions.js +119 -0
- package/lib/bounty/findings.js +64 -0
- package/lib/bounty/programs.js +34 -0
- package/lib/bounty/sync-targets.js +267 -0
- package/lib/bounty/targets.js +33 -0
- package/lib/channels/base.js +56 -0
- package/lib/channels/index.js +15 -0
- package/lib/channels/telegram.js +148 -0
- package/lib/chat/actions.js +288 -0
- package/lib/chat/api.js +135 -0
- package/lib/chat/components/app-sidebar.js +237 -0
- package/lib/chat/components/app-sidebar.jsx +289 -0
- package/lib/chat/components/chat-header.js +27 -0
- package/lib/chat/components/chat-header.jsx +37 -0
- package/lib/chat/components/chat-input.js +230 -0
- package/lib/chat/components/chat-input.jsx +228 -0
- package/lib/chat/components/chat-nav-context.js +11 -0
- package/lib/chat/components/chat-nav-context.jsx +11 -0
- package/lib/chat/components/chat-page.js +81 -0
- package/lib/chat/components/chat-page.jsx +100 -0
- package/lib/chat/components/chat.js +150 -0
- package/lib/chat/components/chat.jsx +182 -0
- package/lib/chat/components/chats-page.js +302 -0
- package/lib/chat/components/chats-page.jsx +330 -0
- package/lib/chat/components/crons-page.js +172 -0
- package/lib/chat/components/crons-page.jsx +244 -0
- package/lib/chat/components/enhanced-tool-call.js +103 -0
- package/lib/chat/components/enhanced-tool-call.jsx +139 -0
- package/lib/chat/components/findings-page.js +175 -0
- package/lib/chat/components/findings-page.jsx +214 -0
- package/lib/chat/components/greeting.js +22 -0
- package/lib/chat/components/greeting.jsx +26 -0
- package/lib/chat/components/icons.js +777 -0
- package/lib/chat/components/icons.jsx +741 -0
- package/lib/chat/components/index.js +26 -0
- package/lib/chat/components/mcp-page.js +260 -0
- package/lib/chat/components/mcp-page.jsx +355 -0
- package/lib/chat/components/message.js +289 -0
- package/lib/chat/components/message.jsx +315 -0
- package/lib/chat/components/messages.js +66 -0
- package/lib/chat/components/messages.jsx +77 -0
- package/lib/chat/components/notifications-page.js +56 -0
- package/lib/chat/components/notifications-page.jsx +87 -0
- package/lib/chat/components/page-layout.js +21 -0
- package/lib/chat/components/page-layout.jsx +28 -0
- package/lib/chat/components/registry-page.js +222 -0
- package/lib/chat/components/registry-page.jsx +255 -0
- package/lib/chat/components/settings-layout.js +40 -0
- package/lib/chat/components/settings-layout.jsx +54 -0
- package/lib/chat/components/settings-secrets-page.js +216 -0
- package/lib/chat/components/settings-secrets-page.jsx +264 -0
- package/lib/chat/components/sidebar-history-item.js +132 -0
- package/lib/chat/components/sidebar-history-item.jsx +113 -0
- package/lib/chat/components/sidebar-history.js +115 -0
- package/lib/chat/components/sidebar-history.jsx +157 -0
- package/lib/chat/components/sidebar-user-nav.js +63 -0
- package/lib/chat/components/sidebar-user-nav.jsx +73 -0
- package/lib/chat/components/status-bar.js +39 -0
- package/lib/chat/components/status-bar.jsx +51 -0
- package/lib/chat/components/swarm-page.js +157 -0
- package/lib/chat/components/swarm-page.jsx +210 -0
- package/lib/chat/components/targets-page.js +376 -0
- package/lib/chat/components/targets-page.jsx +389 -0
- package/lib/chat/components/tool-call.js +86 -0
- package/lib/chat/components/tool-call.jsx +104 -0
- package/lib/chat/components/tool-panel.js +107 -0
- package/lib/chat/components/tool-panel.jsx +145 -0
- package/lib/chat/components/triggers-page.js +153 -0
- package/lib/chat/components/triggers-page.jsx +221 -0
- package/lib/chat/components/ui/confirm-dialog.js +53 -0
- package/lib/chat/components/ui/confirm-dialog.jsx +57 -0
- package/lib/chat/components/ui/dropdown-menu.js +98 -0
- package/lib/chat/components/ui/dropdown-menu.jsx +116 -0
- package/lib/chat/components/ui/rename-dialog.js +74 -0
- package/lib/chat/components/ui/rename-dialog.jsx +72 -0
- package/lib/chat/components/ui/scroll-area.js +13 -0
- package/lib/chat/components/ui/scroll-area.jsx +17 -0
- package/lib/chat/components/ui/separator.js +21 -0
- package/lib/chat/components/ui/separator.jsx +18 -0
- package/lib/chat/components/ui/sheet.js +75 -0
- package/lib/chat/components/ui/sheet.jsx +95 -0
- package/lib/chat/components/ui/sidebar.js +227 -0
- package/lib/chat/components/ui/sidebar.jsx +245 -0
- package/lib/chat/components/ui/tooltip.js +56 -0
- package/lib/chat/components/ui/tooltip.jsx +66 -0
- package/lib/chat/components/upgrade-dialog.js +151 -0
- package/lib/chat/components/upgrade-dialog.jsx +170 -0
- package/lib/chat/utils.js +11 -0
- package/lib/cron.js +246 -0
- package/lib/db/api-keys.js +163 -0
- package/lib/db/chats.js +145 -0
- package/lib/db/index.js +52 -0
- package/lib/db/notifications.js +99 -0
- package/lib/db/schema.js +145 -0
- package/lib/db/update-check.js +96 -0
- package/lib/db/users.js +89 -0
- package/lib/mcp/actions.js +104 -0
- package/lib/mcp/client.js +79 -0
- package/lib/mcp/handler.js +57 -0
- package/lib/mcp/server.js +165 -0
- package/lib/paths.js +46 -0
- package/lib/registry/actions.js +164 -0
- package/lib/registry/catalog.js +137 -0
- package/lib/registry/tools.js +71 -0
- package/lib/tools/create-job.js +99 -0
- package/lib/tools/github.js +217 -0
- package/lib/tools/openai.js +35 -0
- package/lib/tools/telegram.js +292 -0
- package/lib/triggers.js +118 -0
- package/lib/utils/render-md.js +102 -0
- package/package.json +103 -0
- package/setup/lib/auth.mjs +81 -0
- package/setup/lib/env.mjs +21 -0
- package/setup/lib/fs-utils.mjs +20 -0
- package/setup/lib/github.mjs +149 -0
- package/setup/lib/prerequisites.mjs +155 -0
- package/setup/lib/prompts.mjs +267 -0
- package/setup/lib/providers.mjs +48 -0
- package/setup/lib/sync.mjs +125 -0
- package/setup/lib/targets.mjs +45 -0
- package/setup/lib/telegram-verify.mjs +63 -0
- package/setup/lib/telegram.mjs +76 -0
- package/setup/setup-telegram.mjs +264 -0
- package/setup/setup.mjs +842 -0
- package/templates/.dockerignore +5 -0
- package/templates/.env.example +63 -0
- package/templates/.github/workflows/auto-merge.yml +117 -0
- package/templates/.github/workflows/build-image.yml +36 -0
- package/templates/.github/workflows/notify-job-failed.yml +64 -0
- package/templates/.github/workflows/notify-pr-complete.yml +119 -0
- package/templates/.github/workflows/rebuild-event-handler.yml +121 -0
- package/templates/.github/workflows/run-job.yml +89 -0
- package/templates/.github/workflows/upgrade-event-handler.yml +62 -0
- package/templates/.gitignore.template +45 -0
- package/templates/.pi/extensions/env-sanitizer/index.ts +48 -0
- package/templates/.pi/extensions/env-sanitizer/package.json +5 -0
- package/templates/CLAUDE.md +29 -0
- package/templates/CLAUDE.md.template +307 -0
- package/templates/app/api/[...thepopebot]/route.js +1 -0
- package/templates/app/api/auth/[...nextauth]/route.js +1 -0
- package/templates/app/chat/[chatId]/page.js +8 -0
- package/templates/app/chats/page.js +7 -0
- package/templates/app/components/ascii-logo.jsx +10 -0
- package/templates/app/components/login-form.jsx +92 -0
- package/templates/app/components/setup-form.jsx +82 -0
- package/templates/app/components/theme-provider.jsx +11 -0
- package/templates/app/components/theme-toggle.jsx +38 -0
- package/templates/app/components/ui/button.jsx +21 -0
- package/templates/app/components/ui/card.jsx +23 -0
- package/templates/app/components/ui/input.jsx +10 -0
- package/templates/app/components/ui/label.jsx +10 -0
- package/templates/app/crons/page.js +5 -0
- package/templates/app/findings/page.js +7 -0
- package/templates/app/globals.css +90 -0
- package/templates/app/layout.js +19 -0
- package/templates/app/login/page.js +15 -0
- package/templates/app/notifications/page.js +7 -0
- package/templates/app/page.js +7 -0
- package/templates/app/settings/crons/page.js +5 -0
- package/templates/app/settings/layout.js +7 -0
- package/templates/app/settings/mcp/page.js +5 -0
- package/templates/app/settings/page.js +5 -0
- package/templates/app/settings/secrets/page.js +5 -0
- package/templates/app/settings/triggers/page.js +5 -0
- package/templates/app/stream/chat/route.js +1 -0
- package/templates/app/swarm/page.js +7 -0
- package/templates/app/targets/page.js +7 -0
- package/templates/app/toolbox/page.js +7 -0
- package/templates/app/triggers/page.js +5 -0
- package/templates/config/AGENT.md +34 -0
- package/templates/config/CRONS.json +56 -0
- package/templates/config/EVENT_HANDLER.md +224 -0
- package/templates/config/HEARTBEAT.md +3 -0
- package/templates/config/JOB_SUMMARY.md +130 -0
- package/templates/config/MCP_SERVERS.json +1 -0
- package/templates/config/SKILL_BUILDING_GUIDE.md +90 -0
- package/templates/config/SOUL.md +17 -0
- package/templates/config/TRIGGERS.json +58 -0
- package/templates/docker/event-handler/Dockerfile +20 -0
- package/templates/docker/event-handler/ecosystem.config.cjs +8 -0
- package/templates/docker/job-claude-code/Dockerfile +34 -0
- package/templates/docker/job-claude-code/entrypoint.sh +139 -0
- package/templates/docker/job-pi-coding-agent/Dockerfile +44 -0
- package/templates/docker/job-pi-coding-agent/entrypoint.sh +163 -0
- package/templates/docker-compose.yml +63 -0
- package/templates/instrumentation.js +6 -0
- package/templates/middleware.js +1 -0
- package/templates/next.config.mjs +3 -0
- package/templates/postcss.config.mjs +5 -0
- package/templates/skills/LICENSE +21 -0
- package/templates/skills/README.md +119 -0
- package/templates/skills/brave-search/SKILL.md +79 -0
- package/templates/skills/brave-search/content.js +86 -0
- package/templates/skills/brave-search/package-lock.json +621 -0
- package/templates/skills/brave-search/package.json +14 -0
- package/templates/skills/brave-search/search.js +199 -0
- package/templates/skills/browser-tools/SKILL.md +196 -0
- package/templates/skills/browser-tools/browser-content.js +103 -0
- package/templates/skills/browser-tools/browser-cookies.js +35 -0
- package/templates/skills/browser-tools/browser-eval.js +53 -0
- package/templates/skills/browser-tools/browser-hn-scraper.js +108 -0
- package/templates/skills/browser-tools/browser-nav.js +44 -0
- package/templates/skills/browser-tools/browser-pick.js +162 -0
- package/templates/skills/browser-tools/browser-screenshot.js +34 -0
- package/templates/skills/browser-tools/browser-start.js +87 -0
- package/templates/skills/browser-tools/package-lock.json +2556 -0
- package/templates/skills/browser-tools/package.json +19 -0
- package/templates/skills/llm-secrets/SKILL.md +34 -0
- package/templates/skills/llm-secrets/llm-secrets.js +33 -0
- package/templates/skills/modify-self/SKILL.md +12 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import * as clack from '@clack/prompts';
|
|
6
|
+
|
|
7
|
+
import { checkPrerequisites } from './lib/prerequisites.mjs';
|
|
8
|
+
import { setVariables, setSecrets } from './lib/github.mjs';
|
|
9
|
+
import { setTelegramWebhook, validateBotToken, generateVerificationCode, getBotFatherURL } from './lib/telegram.mjs';
|
|
10
|
+
import { confirm, keepOrReconfigure, generateTelegramWebhookSecret, promptForOptionalKey, maskSecret } from './lib/prompts.mjs';
|
|
11
|
+
import { updateEnvVariable } from './lib/auth.mjs';
|
|
12
|
+
import { runVerificationFlow } from './lib/telegram-verify.mjs';
|
|
13
|
+
import { loadEnvFile } from './lib/env.mjs';
|
|
14
|
+
|
|
15
|
+
const logo = `
|
|
16
|
+
_____ _ ____ ____ _
|
|
17
|
+
|_ _| |__ ___| _ \\ ___ _ __ ___| __ ) ___ | |_
|
|
18
|
+
| | | '_ \\ / _ \\ |_) / _ \\| '_ \\ / _ \\ _ \\ / _ \\| __|
|
|
19
|
+
| | | | | | __/ __/ (_) | |_) | __/ |_) | (_) | |_
|
|
20
|
+
|_| |_| |_|\\___|_| \\___/| .__/ \\___|____/ \\___/ \\__|
|
|
21
|
+
|_|
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
async function main() {
|
|
25
|
+
console.log(chalk.cyan(logo));
|
|
26
|
+
clack.intro('Telegram Setup');
|
|
27
|
+
clack.log.info('Connect a Telegram bot to your agent. This wizard will walk you through creating a bot, registering a webhook, and linking your chat.');
|
|
28
|
+
|
|
29
|
+
const TOTAL_STEPS = 6;
|
|
30
|
+
let currentStep = 0;
|
|
31
|
+
|
|
32
|
+
// Track values for summary
|
|
33
|
+
let botUsername = null;
|
|
34
|
+
let webhookUrl = null;
|
|
35
|
+
let telegramChatId = null;
|
|
36
|
+
|
|
37
|
+
// ─── Step 1: Prerequisites ──────────────────────────────────────────
|
|
38
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] Checking prerequisites`);
|
|
39
|
+
clack.log.info('Verifying git remote and loading existing configuration.');
|
|
40
|
+
|
|
41
|
+
const prereqs = await checkPrerequisites();
|
|
42
|
+
|
|
43
|
+
if (!prereqs.git.remoteInfo) {
|
|
44
|
+
clack.log.error('Could not detect GitHub repository from git remote.');
|
|
45
|
+
clack.cancel('Run setup first to initialize your repository.');
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { owner, repo } = prereqs.git.remoteInfo;
|
|
50
|
+
clack.log.success(`Repository: ${owner}/${repo}`);
|
|
51
|
+
|
|
52
|
+
const env = loadEnvFile();
|
|
53
|
+
|
|
54
|
+
if (env) {
|
|
55
|
+
clack.log.info('Existing .env detected — previously configured values can be skipped.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ─── Step 2: App URL ────────────────────────────────────────────────
|
|
59
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] App URL`);
|
|
60
|
+
clack.log.info('Your bot needs a public HTTPS URL so Telegram can deliver messages to it via webhook.');
|
|
61
|
+
clack.log.warn('Make sure your server is running and publicly accessible.');
|
|
62
|
+
|
|
63
|
+
let appUrl = null;
|
|
64
|
+
|
|
65
|
+
if (await keepOrReconfigure('APP_URL', env?.APP_URL || null)) {
|
|
66
|
+
appUrl = env.APP_URL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!appUrl) {
|
|
70
|
+
clack.log.info(
|
|
71
|
+
'Enter the public URL where your agent is running.\n' +
|
|
72
|
+
' Examples:\n' +
|
|
73
|
+
' ngrok: https://abc123.ngrok.io\n' +
|
|
74
|
+
' VPS: https://mybot.example.com\n' +
|
|
75
|
+
' PaaS: https://mybot.vercel.app'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
while (!appUrl) {
|
|
79
|
+
const url = await clack.text({
|
|
80
|
+
message: 'Enter your APP_URL (https://...):',
|
|
81
|
+
validate: (input) => {
|
|
82
|
+
if (!input) return 'URL is required';
|
|
83
|
+
if (!input.startsWith('https://')) return 'URL must start with https://';
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
if (clack.isCancel(url)) {
|
|
87
|
+
clack.cancel('Setup cancelled.');
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
appUrl = url.replace(/\/$/, '');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update APP_URL and APP_HOSTNAME in .env
|
|
95
|
+
const appHostname = new URL(appUrl).hostname;
|
|
96
|
+
updateEnvVariable('APP_URL', appUrl);
|
|
97
|
+
updateEnvVariable('APP_HOSTNAME', appHostname);
|
|
98
|
+
clack.log.success('APP_URL saved to .env');
|
|
99
|
+
|
|
100
|
+
// Set APP_URL variable on GitHub
|
|
101
|
+
const urlSpinner = clack.spinner();
|
|
102
|
+
urlSpinner.start('Updating APP_URL variable on GitHub...');
|
|
103
|
+
const urlResult = await setVariables(owner, repo, { APP_URL: appUrl });
|
|
104
|
+
if (urlResult.APP_URL.success) {
|
|
105
|
+
urlSpinner.stop('APP_URL variable updated on GitHub');
|
|
106
|
+
} else {
|
|
107
|
+
urlSpinner.stop(`Failed: ${urlResult.APP_URL.error}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── Step 3: Bot Token ──────────────────────────────────────────────
|
|
111
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] Telegram Bot Token`);
|
|
112
|
+
clack.log.info('Your agent needs a Telegram bot token from @BotFather to send and receive messages.');
|
|
113
|
+
|
|
114
|
+
let token = null;
|
|
115
|
+
|
|
116
|
+
if (await keepOrReconfigure('Telegram Bot', env?.TELEGRAM_BOT_TOKEN ? maskSecret(env.TELEGRAM_BOT_TOKEN) : null)) {
|
|
117
|
+
// Validate existing token
|
|
118
|
+
token = env.TELEGRAM_BOT_TOKEN;
|
|
119
|
+
const validateSpinner = clack.spinner();
|
|
120
|
+
validateSpinner.start('Validating existing bot token...');
|
|
121
|
+
const validation = await validateBotToken(token);
|
|
122
|
+
if (validation.valid) {
|
|
123
|
+
botUsername = validation.botInfo.username;
|
|
124
|
+
validateSpinner.stop(`Bot: @${botUsername}`);
|
|
125
|
+
} else {
|
|
126
|
+
validateSpinner.stop(`Invalid token in .env: ${validation.error}`);
|
|
127
|
+
clack.log.warn('Existing token is invalid — you\'ll need to enter a new one.');
|
|
128
|
+
token = null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!token) {
|
|
133
|
+
clack.log.info(
|
|
134
|
+
'Create a Telegram bot via @BotFather:\n' +
|
|
135
|
+
' 1. Open @BotFather in Telegram\n' +
|
|
136
|
+
' 2. Send /newbot and follow the prompts\n' +
|
|
137
|
+
' 3. Copy the bot token'
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const openBotFather = await confirm('Open BotFather in browser?');
|
|
141
|
+
if (openBotFather) {
|
|
142
|
+
await open(getBotFatherURL());
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let tokenValid = false;
|
|
146
|
+
while (!tokenValid) {
|
|
147
|
+
const inputToken = await clack.password({
|
|
148
|
+
message: 'Telegram bot token:',
|
|
149
|
+
validate: (input) => {
|
|
150
|
+
if (!input) return 'Token is required';
|
|
151
|
+
if (!/^\d+:[A-Za-z0-9_-]+$/.test(input)) {
|
|
152
|
+
return 'Invalid format. Should be like 123456789:ABC-DEF...';
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
if (clack.isCancel(inputToken)) {
|
|
157
|
+
clack.cancel('Setup cancelled.');
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const validateSpinner = clack.spinner();
|
|
162
|
+
validateSpinner.start('Validating bot token...');
|
|
163
|
+
const validation = await validateBotToken(inputToken);
|
|
164
|
+
|
|
165
|
+
if (!validation.valid) {
|
|
166
|
+
validateSpinner.stop(`Invalid token: ${validation.error}`);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
token = inputToken;
|
|
171
|
+
botUsername = validation.botInfo.username;
|
|
172
|
+
validateSpinner.stop(`Bot: @${botUsername}`);
|
|
173
|
+
tokenValid = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Bug fix #146: save token to .env
|
|
178
|
+
updateEnvVariable('TELEGRAM_BOT_TOKEN', token);
|
|
179
|
+
|
|
180
|
+
// ─── Step 4: Webhook ────────────────────────────────────────────────
|
|
181
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] Register Webhook`);
|
|
182
|
+
clack.log.info('Registering a webhook tells Telegram where to send messages for your bot.');
|
|
183
|
+
|
|
184
|
+
// Handle webhook secret
|
|
185
|
+
let webhookSecret = env?.TELEGRAM_WEBHOOK_SECRET;
|
|
186
|
+
if (webhookSecret) {
|
|
187
|
+
clack.log.success('Using existing webhook secret');
|
|
188
|
+
} else {
|
|
189
|
+
webhookSecret = await generateTelegramWebhookSecret();
|
|
190
|
+
updateEnvVariable('TELEGRAM_WEBHOOK_SECRET', webhookSecret);
|
|
191
|
+
clack.log.success('Generated webhook secret');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Register Telegram webhook
|
|
195
|
+
webhookUrl = `${appUrl}/api/telegram/webhook`;
|
|
196
|
+
const tgSpinner = clack.spinner();
|
|
197
|
+
tgSpinner.start('Registering Telegram webhook...');
|
|
198
|
+
const tgResult = await setTelegramWebhook(token, webhookUrl, webhookSecret);
|
|
199
|
+
if (tgResult.ok) {
|
|
200
|
+
tgSpinner.stop('Telegram webhook registered');
|
|
201
|
+
} else {
|
|
202
|
+
tgSpinner.stop(`Failed: ${tgResult.description}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ─── Step 5: Chat Verification ──────────────────────────────────────
|
|
206
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] Chat Verification`);
|
|
207
|
+
clack.log.info('Link the bot to your Telegram chat so it only responds to you.');
|
|
208
|
+
|
|
209
|
+
telegramChatId = env?.TELEGRAM_CHAT_ID || null;
|
|
210
|
+
|
|
211
|
+
if (await keepOrReconfigure('Chat ID', telegramChatId)) {
|
|
212
|
+
// Keep existing — already set
|
|
213
|
+
} else {
|
|
214
|
+
telegramChatId = null;
|
|
215
|
+
const verificationCode = generateVerificationCode();
|
|
216
|
+
updateEnvVariable('TELEGRAM_VERIFICATION', verificationCode);
|
|
217
|
+
|
|
218
|
+
clack.log.warn('Waiting for server to restart with new verification code...');
|
|
219
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
220
|
+
|
|
221
|
+
const chatId = await runVerificationFlow(verificationCode, { allowSkip: true });
|
|
222
|
+
|
|
223
|
+
if (chatId) {
|
|
224
|
+
telegramChatId = chatId;
|
|
225
|
+
updateEnvVariable('TELEGRAM_CHAT_ID', chatId);
|
|
226
|
+
clack.log.success(`Chat ID saved: ${chatId}`);
|
|
227
|
+
} else {
|
|
228
|
+
clack.log.warn('Chat ID is required — the bot will not respond without it.');
|
|
229
|
+
clack.log.info('Run npm run setup-telegram again to complete setup.');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ─── Step 6: Optional Keys ──────────────────────────────────────────
|
|
234
|
+
clack.log.step(`[${++currentStep}/${TOTAL_STEPS}] Optional Keys`);
|
|
235
|
+
clack.log.info('An OpenAI API key enables voice message transcription via Whisper.');
|
|
236
|
+
|
|
237
|
+
if (await keepOrReconfigure('OpenAI key', env?.OPENAI_API_KEY ? maskSecret(env.OPENAI_API_KEY) : null)) {
|
|
238
|
+
// Keep existing
|
|
239
|
+
} else {
|
|
240
|
+
const openaiKey = await promptForOptionalKey('openai', 'voice messages');
|
|
241
|
+
if (openaiKey) {
|
|
242
|
+
updateEnvVariable('OPENAI_API_KEY', openaiKey);
|
|
243
|
+
const s = clack.spinner();
|
|
244
|
+
s.start('Setting OpenAI secret on GitHub...');
|
|
245
|
+
await setSecrets(owner, repo, { AGENT_OPENAI_API_KEY: openaiKey });
|
|
246
|
+
s.stop('OpenAI secret set');
|
|
247
|
+
clack.log.success(`OpenAI key added for voice (${maskSecret(openaiKey)})`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ─── Summary ────────────────────────────────────────────────────────
|
|
252
|
+
let summary = '';
|
|
253
|
+
summary += `Bot: @${botUsername || '(unknown)'}\n`;
|
|
254
|
+
summary += `Webhook: ${webhookUrl}\n`;
|
|
255
|
+
summary += `Chat ID: ${telegramChatId || '(not set)'}`;
|
|
256
|
+
clack.note(summary, 'Telegram Configuration');
|
|
257
|
+
|
|
258
|
+
clack.outro('Telegram setup complete!');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
main().catch((error) => {
|
|
262
|
+
clack.log.error(`Failed: ${error.message}`);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
});
|