aura-code 0.3.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 +137 -0
- package/dist/agent/context.d.ts +13 -0
- package/dist/agent/context.js +183 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/loop.d.ts +60 -0
- package/dist/agent/loop.js +228 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/session-store.d.ts +30 -0
- package/dist/agent/session-store.js +178 -0
- package/dist/agent/session-store.js.map +1 -0
- package/dist/agent/spawner.d.ts +57 -0
- package/dist/agent/spawner.js +112 -0
- package/dist/agent/spawner.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +3 -0
- package/dist/agent/system-prompt.js +100 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/architect/engine.d.ts +47 -0
- package/dist/architect/engine.js +217 -0
- package/dist/architect/engine.js.map +1 -0
- package/dist/architect/types.d.ts +61 -0
- package/dist/architect/types.js +6 -0
- package/dist/architect/types.js.map +1 -0
- package/dist/cli/diamond.d.ts +1 -0
- package/dist/cli/diamond.js +23 -0
- package/dist/cli/diamond.js.map +1 -0
- package/dist/cli/display.d.ts +44 -0
- package/dist/cli/display.js +234 -0
- package/dist/cli/display.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +1734 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/defaults.d.ts +46 -0
- package/dist/config/defaults.js +106 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/project-config.d.ts +90 -0
- package/dist/config/project-config.js +141 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/harness/proposer.d.ts +26 -0
- package/dist/harness/proposer.js +204 -0
- package/dist/harness/proposer.js.map +1 -0
- package/dist/harness/weakness-miner.d.ts +28 -0
- package/dist/harness/weakness-miner.js +359 -0
- package/dist/harness/weakness-miner.js.map +1 -0
- package/dist/integrations/harnesses.d.ts +23 -0
- package/dist/integrations/harnesses.js +161 -0
- package/dist/integrations/harnesses.js.map +1 -0
- package/dist/orchestration/competence.d.ts +53 -0
- package/dist/orchestration/competence.js +181 -0
- package/dist/orchestration/competence.js.map +1 -0
- package/dist/orchestration/executor.d.ts +42 -0
- package/dist/orchestration/executor.js +206 -0
- package/dist/orchestration/executor.js.map +1 -0
- package/dist/orchestration/index.d.ts +20 -0
- package/dist/orchestration/index.js +39 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/orchestrator-prompts.d.ts +11 -0
- package/dist/orchestration/orchestrator-prompts.js +153 -0
- package/dist/orchestration/orchestrator-prompts.js.map +1 -0
- package/dist/orchestration/orchestrator.d.ts +27 -0
- package/dist/orchestration/orchestrator.js +169 -0
- package/dist/orchestration/orchestrator.js.map +1 -0
- package/dist/orchestration/plan-store.d.ts +53 -0
- package/dist/orchestration/plan-store.js +176 -0
- package/dist/orchestration/plan-store.js.map +1 -0
- package/dist/orchestration/router-prompts.d.ts +6 -0
- package/dist/orchestration/router-prompts.js +55 -0
- package/dist/orchestration/router-prompts.js.map +1 -0
- package/dist/orchestration/router.d.ts +23 -0
- package/dist/orchestration/router.js +70 -0
- package/dist/orchestration/router.js.map +1 -0
- package/dist/orchestration/ruby-detect.d.ts +6 -0
- package/dist/orchestration/ruby-detect.js +130 -0
- package/dist/orchestration/ruby-detect.js.map +1 -0
- package/dist/orchestration/ruby-types.d.ts +44 -0
- package/dist/orchestration/ruby-types.js +6 -0
- package/dist/orchestration/ruby-types.js.map +1 -0
- package/dist/orchestration/specialist-prompts.d.ts +19 -0
- package/dist/orchestration/specialist-prompts.js +143 -0
- package/dist/orchestration/specialist-prompts.js.map +1 -0
- package/dist/orchestration/specialists.d.ts +66 -0
- package/dist/orchestration/specialists.js +175 -0
- package/dist/orchestration/specialists.js.map +1 -0
- package/dist/orchestration/types.d.ts +82 -0
- package/dist/orchestration/types.js +6 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/perception/extractor.d.ts +7 -0
- package/dist/perception/extractor.js +521 -0
- package/dist/perception/extractor.js.map +1 -0
- package/dist/perception/graph-store.d.ts +25 -0
- package/dist/perception/graph-store.js +117 -0
- package/dist/perception/graph-store.js.map +1 -0
- package/dist/perception/index.d.ts +4 -0
- package/dist/perception/index.js +18 -0
- package/dist/perception/index.js.map +1 -0
- package/dist/perception/queries.d.ts +29 -0
- package/dist/perception/queries.js +354 -0
- package/dist/perception/queries.js.map +1 -0
- package/dist/perception/types.d.ts +103 -0
- package/dist/perception/types.js +6 -0
- package/dist/perception/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +11 -0
- package/dist/providers/anthropic.js +172 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/factory.d.ts +58 -0
- package/dist/providers/factory.js +354 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/fallback.d.ts +24 -0
- package/dist/providers/fallback.js +72 -0
- package/dist/providers/fallback.js.map +1 -0
- package/dist/providers/google.d.ts +11 -0
- package/dist/providers/google.js +129 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +24 -0
- package/dist/providers/openai-compatible.js +216 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/providers/resilient-factory.d.ts +24 -0
- package/dist/providers/resilient-factory.js +57 -0
- package/dist/providers/resilient-factory.js.map +1 -0
- package/dist/providers/resilient.d.ts +63 -0
- package/dist/providers/resilient.js +145 -0
- package/dist/providers/resilient.js.map +1 -0
- package/dist/providers/types.d.ts +84 -0
- package/dist/providers/types.js +6 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/ruby/alternator.d.ts +40 -0
- package/dist/ruby/alternator.js +233 -0
- package/dist/ruby/alternator.js.map +1 -0
- package/dist/ruby/competence.d.ts +34 -0
- package/dist/ruby/competence.js +264 -0
- package/dist/ruby/competence.js.map +1 -0
- package/dist/ruby/episode-capture.d.ts +56 -0
- package/dist/ruby/episode-capture.js +193 -0
- package/dist/ruby/episode-capture.js.map +1 -0
- package/dist/ruby/fine-tune.d.ts +16 -0
- package/dist/ruby/fine-tune.js +253 -0
- package/dist/ruby/fine-tune.js.map +1 -0
- package/dist/ruby/index.d.ts +10 -0
- package/dist/ruby/index.js +26 -0
- package/dist/ruby/index.js.map +1 -0
- package/dist/ruby/ruby-model.d.ts +36 -0
- package/dist/ruby/ruby-model.js +81 -0
- package/dist/ruby/ruby-model.js.map +1 -0
- package/dist/ruby/training-data.d.ts +11 -0
- package/dist/ruby/training-data.js +107 -0
- package/dist/ruby/training-data.js.map +1 -0
- package/dist/ruby/types.d.ts +136 -0
- package/dist/ruby/types.js +20 -0
- package/dist/ruby/types.js.map +1 -0
- package/dist/safety/permissions.d.ts +32 -0
- package/dist/safety/permissions.js +304 -0
- package/dist/safety/permissions.js.map +1 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.js +342 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/session.d.ts +22 -0
- package/dist/server/session.js +16 -0
- package/dist/server/session.js.map +1 -0
- package/dist/setup/first-run.d.ts +41 -0
- package/dist/setup/first-run.js +386 -0
- package/dist/setup/first-run.js.map +1 -0
- package/dist/setup/global-config.d.ts +19 -0
- package/dist/setup/global-config.js +97 -0
- package/dist/setup/global-config.js.map +1 -0
- package/dist/tools/audio-transcribe.d.ts +8 -0
- package/dist/tools/audio-transcribe.js +156 -0
- package/dist/tools/audio-transcribe.js.map +1 -0
- package/dist/tools/browser.d.ts +15 -0
- package/dist/tools/browser.js +241 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/calendar.d.ts +12 -0
- package/dist/tools/calendar.js +196 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/clipboard.d.ts +7 -0
- package/dist/tools/clipboard.js +90 -0
- package/dist/tools/clipboard.js.map +1 -0
- package/dist/tools/cron.d.ts +10 -0
- package/dist/tools/cron.js +167 -0
- package/dist/tools/cron.js.map +1 -0
- package/dist/tools/edit-file.d.ts +6 -0
- package/dist/tools/edit-file.js +98 -0
- package/dist/tools/edit-file.js.map +1 -0
- package/dist/tools/email.d.ts +11 -0
- package/dist/tools/email.js +153 -0
- package/dist/tools/email.js.map +1 -0
- package/dist/tools/git.d.ts +1 -0
- package/dist/tools/git.js +7 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/http-request.d.ts +12 -0
- package/dist/tools/http-request.js +91 -0
- package/dist/tools/http-request.js.map +1 -0
- package/dist/tools/image-read.d.ts +7 -0
- package/dist/tools/image-read.js +125 -0
- package/dist/tools/image-read.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +201 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-dir.d.ts +1 -0
- package/dist/tools/list-dir.js +6 -0
- package/dist/tools/list-dir.js.map +1 -0
- package/dist/tools/mcp.d.ts +11 -0
- package/dist/tools/mcp.js +356 -0
- package/dist/tools/mcp.js.map +1 -0
- package/dist/tools/memory.d.ts +9 -0
- package/dist/tools/memory.js +124 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/notify.d.ts +9 -0
- package/dist/tools/notify.js +40 -0
- package/dist/tools/notify.js.map +1 -0
- package/dist/tools/read-file.d.ts +6 -0
- package/dist/tools/read-file.js +76 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/run-shell.d.ts +1 -0
- package/dist/tools/run-shell.js +6 -0
- package/dist/tools/run-shell.js.map +1 -0
- package/dist/tools/run-tests.d.ts +1 -0
- package/dist/tools/run-tests.js +6 -0
- package/dist/tools/run-tests.js.map +1 -0
- package/dist/tools/search-code.d.ts +1 -0
- package/dist/tools/search-code.js +6 -0
- package/dist/tools/search-code.js.map +1 -0
- package/dist/tools/telegram-bot.d.ts +2 -0
- package/dist/tools/telegram-bot.js +693 -0
- package/dist/tools/telegram-bot.js.map +1 -0
- package/dist/tools/telegram-safety.d.ts +52 -0
- package/dist/tools/telegram-safety.js +189 -0
- package/dist/tools/telegram-safety.js.map +1 -0
- package/dist/tools/telegram.d.ts +16 -0
- package/dist/tools/telegram.js +227 -0
- package/dist/tools/telegram.js.map +1 -0
- package/dist/tools/tools.d.ts +48 -0
- package/dist/tools/tools.js +328 -0
- package/dist/tools/tools.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +11 -0
- package/dist/tools/web-fetch.js +119 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +8 -0
- package/dist/tools/web-search.js +81 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tools/whatsapp.d.ts +10 -0
- package/dist/tools/whatsapp.js +222 -0
- package/dist/tools/whatsapp.js.map +1 -0
- package/dist/tools/write-file.d.ts +1 -0
- package/dist/tools/write-file.js +6 -0
- package/dist/tools/write-file.js.map +1 -0
- package/dist/tools/youtube-transcript.d.ts +9 -0
- package/dist/tools/youtube-transcript.js +200 -0
- package/dist/tools/youtube-transcript.js.map +1 -0
- package/dist/util/circuit-breaker.d.ts +44 -0
- package/dist/util/circuit-breaker.js +78 -0
- package/dist/util/circuit-breaker.js.map +1 -0
- package/dist/util/env.d.ts +18 -0
- package/dist/util/env.js +39 -0
- package/dist/util/env.js.map +1 -0
- package/dist/util/errors.d.ts +42 -0
- package/dist/util/errors.js +121 -0
- package/dist/util/errors.js.map +1 -0
- package/dist/util/rate-limiter.d.ts +71 -0
- package/dist/util/rate-limiter.js +141 -0
- package/dist/util/rate-limiter.js.map +1 -0
- package/dist/util/retry.d.ts +30 -0
- package/dist/util/retry.js +57 -0
- package/dist/util/retry.js.map +1 -0
- package/dist/util/sanitize.d.ts +16 -0
- package/dist/util/sanitize.js +255 -0
- package/dist/util/sanitize.js.map +1 -0
- package/dist/verify/checks.d.ts +21 -0
- package/dist/verify/checks.js +311 -0
- package/dist/verify/checks.js.map +1 -0
- package/dist/verify/index.d.ts +33 -0
- package/dist/verify/index.js +127 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/types.d.ts +20 -0
- package/dist/verify/types.js +3 -0
- package/dist/verify/types.js.map +1 -0
- package/dist/versioncheck.d.ts +22 -0
- package/dist/versioncheck.js +203 -0
- package/dist/versioncheck.js.map +1 -0
- package/dist/viz/index.d.ts +2 -0
- package/dist/viz/index.js +733 -0
- package/dist/viz/index.js.map +1 -0
- package/dist/workflows/engine.d.ts +46 -0
- package/dist/workflows/engine.js +320 -0
- package/dist/workflows/engine.js.map +1 -0
- package/dist/workflows/types.d.ts +92 -0
- package/dist/workflows/types.js +6 -0
- package/dist/workflows/types.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// Aura Telegram Bot — listens for messages, executes real Aura tasks
|
|
4
|
+
// Uses curl for API calls (Node https.request ETIMEDOUT on this system)
|
|
5
|
+
// Usage: npx tsx src/tools/telegram-bot.ts
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const factory_js_1 = require("../providers/factory.js");
|
|
45
|
+
const context_js_1 = require("../agent/context.js");
|
|
46
|
+
const loop_js_1 = require("../agent/loop.js");
|
|
47
|
+
const permissions_js_1 = require("../safety/permissions.js");
|
|
48
|
+
const telegram_safety_js_1 = require("./telegram-safety.js");
|
|
49
|
+
function loadConfig() {
|
|
50
|
+
const configPath = path.join(os.homedir(), '.aura', 'telegram.json');
|
|
51
|
+
if (!fs.existsSync(configPath)) {
|
|
52
|
+
console.error('❌ Config not found. Create ~/.aura/telegram.json');
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
56
|
+
}
|
|
57
|
+
const config = loadConfig();
|
|
58
|
+
const TOKEN = config.bot_token;
|
|
59
|
+
const OFFSET_FILE = path.join(os.homedir(), '.aura', 'telegram.offset');
|
|
60
|
+
// ── Authorized user IDs ───────────────────────────────────────────────────
|
|
61
|
+
// Check: config file, then env var TELEGRAM_BOT_ALLOWED_USER_IDS (comma-sep)
|
|
62
|
+
function loadAuthorizedUserIds() {
|
|
63
|
+
const ids = new Set();
|
|
64
|
+
const raw = config.allowed_user_ids
|
|
65
|
+
?? process.env.TELEGRAM_BOT_ALLOWED_USER_IDS
|
|
66
|
+
?? '';
|
|
67
|
+
for (const part of raw.split(',')) {
|
|
68
|
+
const trimmed = part.trim();
|
|
69
|
+
if (trimmed) {
|
|
70
|
+
const n = Number(trimmed);
|
|
71
|
+
if (!isNaN(n))
|
|
72
|
+
ids.add(n);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return ids;
|
|
76
|
+
}
|
|
77
|
+
const AUTHORIZED_USER_IDS = loadAuthorizedUserIds();
|
|
78
|
+
// The project root for task execution
|
|
79
|
+
const PROJECT_ROOT = process.env.TELEGRAM_BOT_PROJECT_ROOT
|
|
80
|
+
?? path.resolve(__dirname, '../..'); // default to aura-code repo
|
|
81
|
+
// The model to use for task execution
|
|
82
|
+
const TASK_MODEL = process.env.TELEGRAM_BOT_MODEL
|
|
83
|
+
?? process.env.AURA_MODEL
|
|
84
|
+
?? 'mimo-v2.5-pro';
|
|
85
|
+
// ── Safety state ───────────────────────────────────────────────────────────
|
|
86
|
+
let safetyState = (0, telegram_safety_js_1.loadSafetyState)();
|
|
87
|
+
const confirmManager = new telegram_safety_js_1.TelegramConfirmManager();
|
|
88
|
+
function saveState() {
|
|
89
|
+
(0, telegram_safety_js_1.saveSafetyState)(safetyState);
|
|
90
|
+
}
|
|
91
|
+
// ── Provider (created once, reused) ────────────────────────────────────────
|
|
92
|
+
function createLLMProvider() {
|
|
93
|
+
const apiKey = process.env.XIAOMI_API_KEY
|
|
94
|
+
?? process.env.ANTHROPIC_API_KEY
|
|
95
|
+
?? process.env.OPENAI_API_KEY
|
|
96
|
+
?? process.env.GOOGLE_API_KEY
|
|
97
|
+
?? process.env.OPENROUTER_API_KEY;
|
|
98
|
+
return (0, factory_js_1.createProvider)({
|
|
99
|
+
model: TASK_MODEL,
|
|
100
|
+
apiKey,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
104
|
+
// Stub display for Telegram — silent, no terminal output
|
|
105
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
106
|
+
function createSilentDisplay() {
|
|
107
|
+
return {
|
|
108
|
+
agentThinking() { },
|
|
109
|
+
streamText() { },
|
|
110
|
+
streamEnd() { },
|
|
111
|
+
toolStart() { },
|
|
112
|
+
toolCall() { },
|
|
113
|
+
toolResult() { },
|
|
114
|
+
toolBlocked() { },
|
|
115
|
+
warning() { },
|
|
116
|
+
success() { },
|
|
117
|
+
error() { },
|
|
118
|
+
header() { },
|
|
119
|
+
summary() { },
|
|
120
|
+
showPlan() { },
|
|
121
|
+
stepStarted() { },
|
|
122
|
+
stepCompleted() { },
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
126
|
+
// Task execution via runAgentLoop
|
|
127
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
128
|
+
async function executeTask(chatId, task) {
|
|
129
|
+
console.log("DEBUG-EXEC: executeTask entered");
|
|
130
|
+
let provider;
|
|
131
|
+
try {
|
|
132
|
+
console.log("DEBUG-EXEC: creating provider...");
|
|
133
|
+
provider = createLLMProvider();
|
|
134
|
+
console.log("DEBUG-EXEC: provider created");
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
return `❌ Failed to create LLM provider: ${e.message}`;
|
|
138
|
+
}
|
|
139
|
+
let context;
|
|
140
|
+
try {
|
|
141
|
+
console.log("DEBUG-EXEC: loading context...");
|
|
142
|
+
context = await (0, context_js_1.loadProjectContext)(PROJECT_ROOT);
|
|
143
|
+
console.log("DEBUG-EXEC: context loaded");
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
return `❌ Failed to load project context: ${e.message}`;
|
|
147
|
+
}
|
|
148
|
+
// Permissions:
|
|
149
|
+
// safety ON → 'normal' (triggers needsConfirm for destructive ops)
|
|
150
|
+
// safety OFF → 'auto' (no confirm needed)
|
|
151
|
+
const permLevel = safetyState.safetyOn ? 'normal' : 'auto';
|
|
152
|
+
const permissions = new permissions_js_1.PermissionSystem(permLevel, context.root);
|
|
153
|
+
const display = createSilentDisplay();
|
|
154
|
+
let confirmFn;
|
|
155
|
+
if (safetyState.safetyOn) {
|
|
156
|
+
confirmFn = async (message) => {
|
|
157
|
+
// Parse the description from the confirm message
|
|
158
|
+
// "Allow: $ <command>?" or "Allow: overwrite <path>?" or "Allow: toolName({...})?"
|
|
159
|
+
const desc = message
|
|
160
|
+
.replace(/^Allow:\s*/, '')
|
|
161
|
+
.replace(/\?$/, '')
|
|
162
|
+
.trim();
|
|
163
|
+
console.log(`Confirm requested: ${desc}`);
|
|
164
|
+
const { promise, message: approvalMsg } = await new Promise((resolve) => {
|
|
165
|
+
// We need to figure out which tool this is for from the message
|
|
166
|
+
let toolName = 'unknown';
|
|
167
|
+
let description = desc;
|
|
168
|
+
if (desc.startsWith('$ ')) {
|
|
169
|
+
toolName = 'run_shell';
|
|
170
|
+
description = desc.slice(2);
|
|
171
|
+
}
|
|
172
|
+
else if (desc.startsWith('overwrite ')) {
|
|
173
|
+
toolName = 'write_file';
|
|
174
|
+
description = desc;
|
|
175
|
+
}
|
|
176
|
+
const result = confirmManager.waitForApproval(chatId, toolName, description);
|
|
177
|
+
resolve(result);
|
|
178
|
+
});
|
|
179
|
+
// Send the approval request to the user
|
|
180
|
+
try {
|
|
181
|
+
await sendMessage(chatId, approvalMsg);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// If we can't send, deny for safety
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return promise;
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
console.log("Starting agent loop...");
|
|
192
|
+
const result = await (0, loop_js_1.runAgentLoop)({
|
|
193
|
+
provider,
|
|
194
|
+
task,
|
|
195
|
+
context,
|
|
196
|
+
permissions,
|
|
197
|
+
display,
|
|
198
|
+
maxTurns: 50,
|
|
199
|
+
disableSpawn: true, // no sub-agents via Telegram for now
|
|
200
|
+
confirmFn,
|
|
201
|
+
});
|
|
202
|
+
console.log("Agent loop completed");
|
|
203
|
+
// Build a readable response
|
|
204
|
+
const lines = [];
|
|
205
|
+
const tag = (0, telegram_safety_js_1.safetyLabel)(safetyState.safetyOn);
|
|
206
|
+
if (result.success) {
|
|
207
|
+
lines.push(`✅ Done (${result.turns} turn${result.turns !== 1 ? 's' : ''}) ${tag}`);
|
|
208
|
+
if (result.summary) {
|
|
209
|
+
// Trim the summary to a reasonable length
|
|
210
|
+
const summary = result.summary.length > 3000
|
|
211
|
+
? result.summary.slice(0, 3000) + '\n…(truncated)'
|
|
212
|
+
: result.summary;
|
|
213
|
+
lines.push('');
|
|
214
|
+
lines.push(summary);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
lines.push(`❌ Failed (${result.turns} turns) ${tag}`);
|
|
219
|
+
if (result.summary) {
|
|
220
|
+
lines.push('');
|
|
221
|
+
lines.push(result.summary);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return lines.join('\n');
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
console.error("Agent loop error:", e);
|
|
228
|
+
return `❌ Task error: ${e.message}`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
232
|
+
// API helpers via curl (Node https.request ETIMEDOUT on this system)
|
|
233
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
234
|
+
function loadOffset() {
|
|
235
|
+
try {
|
|
236
|
+
return parseInt(fs.readFileSync(OFFSET_FILE, 'utf8').trim(), 10) || 0;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function saveOffset(offset) {
|
|
243
|
+
fs.writeFileSync(OFFSET_FILE, String(offset), 'utf8');
|
|
244
|
+
}
|
|
245
|
+
async function curlPost(method, body) {
|
|
246
|
+
const data = body ? JSON.stringify(body) : '';
|
|
247
|
+
const url = `https://api.telegram.org/bot${TOKEN}/${method}`;
|
|
248
|
+
const escaped = data.replace(/'/g, "'\\''");
|
|
249
|
+
return new Promise((resolve, reject) => {
|
|
250
|
+
(0, child_process_1.exec)(`curl -s -X POST -H "Content-Type: application/json" -d '${escaped}' "${url}"`, { timeout: 30_000, encoding: 'utf8' }, (err, stdout, stderr) => {
|
|
251
|
+
if (err) {
|
|
252
|
+
reject(err);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const parsed = JSON.parse(stdout);
|
|
257
|
+
if (!parsed.ok) {
|
|
258
|
+
reject(new Error(`Telegram: ${parsed.description} (${parsed.error_code})`));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
resolve(parsed.result);
|
|
262
|
+
}
|
|
263
|
+
catch (e) {
|
|
264
|
+
reject(e);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async function curlGet(method, params) {
|
|
270
|
+
const qs = params ? '?' + new URLSearchParams(params).toString() : '';
|
|
271
|
+
const url = `https://api.telegram.org/bot${TOKEN}/${method}${qs}`;
|
|
272
|
+
return new Promise((resolve, reject) => {
|
|
273
|
+
(0, child_process_1.exec)(`curl -s "${url}"`, { timeout: 30_000, encoding: 'utf8' }, (err, stdout, stderr) => {
|
|
274
|
+
if (err) {
|
|
275
|
+
reject(err);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
const parsed = JSON.parse(stdout);
|
|
280
|
+
if (!parsed.ok) {
|
|
281
|
+
reject(new Error(`Telegram: ${parsed.description} (${parsed.error_code})`));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
resolve(parsed.result);
|
|
285
|
+
}
|
|
286
|
+
catch (e) {
|
|
287
|
+
reject(e);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async function sendMessage(chatId, text, parseMode) {
|
|
293
|
+
const chunks = splitMessage(text, 4000);
|
|
294
|
+
for (const chunk of chunks) {
|
|
295
|
+
const body = { chat_id: chatId, text: chunk };
|
|
296
|
+
if (parseMode)
|
|
297
|
+
body.parse_mode = parseMode;
|
|
298
|
+
await curlPost('sendMessage', body);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function splitMessage(text, maxLen) {
|
|
302
|
+
if (text.length <= maxLen)
|
|
303
|
+
return [text];
|
|
304
|
+
const chunks = [];
|
|
305
|
+
let remaining = text;
|
|
306
|
+
while (remaining.length > 0) {
|
|
307
|
+
chunks.push(remaining.slice(0, maxLen));
|
|
308
|
+
remaining = remaining.slice(maxLen);
|
|
309
|
+
}
|
|
310
|
+
return chunks;
|
|
311
|
+
}
|
|
312
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
313
|
+
// Utility helpers
|
|
314
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
315
|
+
const DEFAULT_CWD = process.env.HOME ?? '/tmp';
|
|
316
|
+
function execShell(command, cwd) {
|
|
317
|
+
try {
|
|
318
|
+
const stdout = (0, child_process_1.execSync)(command, {
|
|
319
|
+
cwd: cwd ?? DEFAULT_CWD,
|
|
320
|
+
timeout: 30_000,
|
|
321
|
+
maxBuffer: 1024 * 1024,
|
|
322
|
+
encoding: 'utf8',
|
|
323
|
+
});
|
|
324
|
+
return { stdout, stderr: '', code: 0 };
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
return {
|
|
328
|
+
stdout: err.stdout?.toString() ?? '',
|
|
329
|
+
stderr: err.stderr?.toString() ?? '',
|
|
330
|
+
code: err.status ?? 1,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function readFileTool(filePath) {
|
|
335
|
+
const resolved = path.isAbsolute(filePath) ? filePath : path.join(DEFAULT_CWD, filePath);
|
|
336
|
+
if (!fs.existsSync(resolved))
|
|
337
|
+
return `❌ File not found: ${filePath}`;
|
|
338
|
+
try {
|
|
339
|
+
const content = fs.readFileSync(resolved, 'utf8');
|
|
340
|
+
const lines = content.split('\n');
|
|
341
|
+
const numbered = lines.map((l, i) => `${i + 1}: ${l}`).join('\n');
|
|
342
|
+
return numbered.length > 3500 ? numbered.slice(0, 3500) + '\n... (truncated)' : numbered;
|
|
343
|
+
}
|
|
344
|
+
catch (e) {
|
|
345
|
+
return `❌ Error reading: ${e.message}`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function listDirTool(dirPath) {
|
|
349
|
+
const resolved = path.isAbsolute(dirPath) ? dirPath : path.join(DEFAULT_CWD, dirPath);
|
|
350
|
+
if (!fs.existsSync(resolved))
|
|
351
|
+
return `❌ Directory not found: ${dirPath}`;
|
|
352
|
+
try {
|
|
353
|
+
const entries = fs.readdirSync(resolved, { withFileTypes: true });
|
|
354
|
+
const lines = entries.map(e => {
|
|
355
|
+
const icon = e.isDirectory() ? '📁' : '📄';
|
|
356
|
+
return `${icon} ${e.name}`;
|
|
357
|
+
});
|
|
358
|
+
return lines.length > 50 ? lines.slice(0, 50).join('\n') + `\n... (${lines.length - 50} more)` : lines.join('\n');
|
|
359
|
+
}
|
|
360
|
+
catch (e) {
|
|
361
|
+
return `❌ Error listing: ${e.message}`;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** Escape a string for use inside double quotes in a shell command. */
|
|
365
|
+
function escapeShellDouble(s) {
|
|
366
|
+
return s.replace(/[\\"$]/g, '\\$&').replace(/`/g, '\\`');
|
|
367
|
+
}
|
|
368
|
+
function searchCodeTool(pattern, searchPath) {
|
|
369
|
+
const resolved = searchPath
|
|
370
|
+
? (path.isAbsolute(searchPath) ? searchPath : path.join(DEFAULT_CWD, searchPath))
|
|
371
|
+
: DEFAULT_CWD;
|
|
372
|
+
try {
|
|
373
|
+
const result = (0, child_process_1.execSync)('rg -n --no-heading -i "' + escapeShellDouble(pattern) + '" "' + escapeShellDouble(resolved) + '" 2>/dev/null | head -30', { timeout: 10_000, encoding: 'utf8' });
|
|
374
|
+
return result.trim() || 'No matches for "' + pattern + '"';
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return 'No matches for "' + pattern + '" (or rg not installed)';
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
381
|
+
// Command handlers
|
|
382
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
383
|
+
function handleCommand(chatId, text, from) {
|
|
384
|
+
const lower = text.toLowerCase().trim();
|
|
385
|
+
const tag = (0, telegram_safety_js_1.safetyLabel)(safetyState.safetyOn);
|
|
386
|
+
if (lower === '/start' || lower === '/help') {
|
|
387
|
+
return [
|
|
388
|
+
`💎 Aura Bot — Online ${tag}`,
|
|
389
|
+
``,
|
|
390
|
+
`Commands:`,
|
|
391
|
+
`/status — System status`,
|
|
392
|
+
`/tools — Available tools`,
|
|
393
|
+
`/safety_on — Enable safety mode (default)`,
|
|
394
|
+
`/safety_off CONFIRM — Disable safety mode`,
|
|
395
|
+
`/ping — Connection check`,
|
|
396
|
+
`/whoami — About me`,
|
|
397
|
+
`/ls <dir> — List directory`,
|
|
398
|
+
`/read <file> — Read file`,
|
|
399
|
+
`/search <pattern> — Search code`,
|
|
400
|
+
`/run <cmd> — Run shell command`,
|
|
401
|
+
`/git — Git status`,
|
|
402
|
+
`/cancel — Cancel stuck task`,
|
|
403
|
+
`/clear — Clear context`,
|
|
404
|
+
``,
|
|
405
|
+
`Or just write anything — I'll execute it as an Aura task!`,
|
|
406
|
+
].join('\n');
|
|
407
|
+
}
|
|
408
|
+
if (lower === '/ping')
|
|
409
|
+
return `🏓 Pong! Aura is alive and running. ${tag}`;
|
|
410
|
+
if (lower === '/whoami') {
|
|
411
|
+
return [
|
|
412
|
+
`💎 I am Aura — an agent. ${tag}`,
|
|
413
|
+
``,
|
|
414
|
+
`Framework: Aura (Ancient Greek: she who acts)`,
|
|
415
|
+
`Character: Precise, imperial, self-aware`,
|
|
416
|
+
`Motto: "I don't try. I verify."`,
|
|
417
|
+
`Builder: Dušan Milosavljević`,
|
|
418
|
+
`Tools: 22+`,
|
|
419
|
+
`Tests: 734+ passing`,
|
|
420
|
+
`Version: v0.3.0 (Aura rebrand)`,
|
|
421
|
+
`Mode: ${safetyState.safetyOn ? '🔒 Safe (asks before destructive ops)' : '🔓 Auto (no confirmation)'}`,
|
|
422
|
+
`Project: ${PROJECT_ROOT}`,
|
|
423
|
+
`Model: ${TASK_MODEL}`,
|
|
424
|
+
].join('\n');
|
|
425
|
+
}
|
|
426
|
+
if (lower === '/status') {
|
|
427
|
+
const uptime = process.uptime();
|
|
428
|
+
const hours = Math.floor(uptime / 3600);
|
|
429
|
+
const mins = Math.floor((uptime % 3600) / 60);
|
|
430
|
+
const mem = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
431
|
+
return [
|
|
432
|
+
`📊 Aura Status ${tag}`,
|
|
433
|
+
`Uptime: ${hours}h ${mins}m`,
|
|
434
|
+
`Memory: ${mem}MB`,
|
|
435
|
+
`Node: ${process.version}`,
|
|
436
|
+
`Bot: @Praktessruby_bot`,
|
|
437
|
+
`Status: ✅ Active`,
|
|
438
|
+
`Version: v0.3.0`,
|
|
439
|
+
`Safety: ${safetyState.safetyOn ? '🔒 ON' : '🔓 OFF'}`,
|
|
440
|
+
].join('\n');
|
|
441
|
+
}
|
|
442
|
+
if (lower === '/tools') {
|
|
443
|
+
return [
|
|
444
|
+
`🔧 Available tools: ${tag}`,
|
|
445
|
+
``,
|
|
446
|
+
`📁 /ls <dir> — list directory`,
|
|
447
|
+
`📄 /read <file> — read file`,
|
|
448
|
+
`🔍 /search <pattern> — search code`,
|
|
449
|
+
`⚡ /run <cmd> — shell command`,
|
|
450
|
+
`🌿 /git — git status`,
|
|
451
|
+
`🧠 /clear — clear context`,
|
|
452
|
+
`🔒 /safety_on — enable safety`,
|
|
453
|
+
`🔓 /safety_off CONFIRM — disable safety`,
|
|
454
|
+
`🚫 /cancel — cancel stuck task`,
|
|
455
|
+
].join('\n');
|
|
456
|
+
}
|
|
457
|
+
// ── Safety toggle ───────────────────────────────────────────────────────
|
|
458
|
+
if (lower === '/safety_on') {
|
|
459
|
+
safetyState.safetyOn = true;
|
|
460
|
+
saveState();
|
|
461
|
+
return `🔒 Safety mode enabled. ${(0, telegram_safety_js_1.safetyLabel)(true)} — destructive operations will ask for approval.`;
|
|
462
|
+
}
|
|
463
|
+
if (lower.startsWith('/safety_off')) {
|
|
464
|
+
const rest = text.slice('/safety_off'.length).trim();
|
|
465
|
+
if (rest !== 'CONFIRM') {
|
|
466
|
+
return [
|
|
467
|
+
`⚠️ To disable safety, send:`,
|
|
468
|
+
``,
|
|
469
|
+
`/safety_off CONFIRM`,
|
|
470
|
+
``,
|
|
471
|
+
`This prevents accidental toggling.`,
|
|
472
|
+
`Current state: ${(0, telegram_safety_js_1.safetyLabel)(safetyState.safetyOn)}`,
|
|
473
|
+
].join('\n');
|
|
474
|
+
}
|
|
475
|
+
safetyState.safetyOn = false;
|
|
476
|
+
saveState();
|
|
477
|
+
return `🔓 Safety mode disabled. ${(0, telegram_safety_js_1.safetyLabel)(false)} — all operations will execute without confirmation.`;
|
|
478
|
+
}
|
|
479
|
+
// ── Tool commands ───────────────────────────────────────────────────────
|
|
480
|
+
if (lower.startsWith('/ls')) {
|
|
481
|
+
const dir = text.slice(3).trim() || '.';
|
|
482
|
+
return `📁 ${dir}:\n${listDirTool(dir)}`;
|
|
483
|
+
}
|
|
484
|
+
if (lower.startsWith('/read')) {
|
|
485
|
+
const file = text.slice(5).trim();
|
|
486
|
+
if (!file)
|
|
487
|
+
return '❌ Usage: /read <file>';
|
|
488
|
+
return readFileTool(file);
|
|
489
|
+
}
|
|
490
|
+
if (lower.startsWith('/search')) {
|
|
491
|
+
const pattern = text.slice(7).trim();
|
|
492
|
+
if (!pattern)
|
|
493
|
+
return '❌ Usage: /search <pattern>';
|
|
494
|
+
return `🔍 Results for "${pattern}":\n${searchCodeTool(pattern)}`;
|
|
495
|
+
}
|
|
496
|
+
if (lower.startsWith('/run')) {
|
|
497
|
+
const cmd = text.slice(4).trim();
|
|
498
|
+
if (!cmd)
|
|
499
|
+
return '❌ Usage: /run <command>';
|
|
500
|
+
const dangerous = ['rm -rf', 'mkfs', 'dd if=', 'fork bomb', 'shutdown', 'reboot'];
|
|
501
|
+
if (dangerous.some(d => cmd.toLowerCase().includes(d))) {
|
|
502
|
+
return '🚫 Blocked: dangerous command detected.';
|
|
503
|
+
}
|
|
504
|
+
const result = execShell(cmd);
|
|
505
|
+
const output = result.stdout || result.stderr || '(no output)';
|
|
506
|
+
const truncated = output.length > 3500 ? output.slice(0, 3500) + '\n... (truncated)' : output;
|
|
507
|
+
return `⚡ ${cmd}\n${result.code === 0 ? '✅' : '❌'} exit ${result.code}\n${truncated}`;
|
|
508
|
+
}
|
|
509
|
+
if (lower === '/git') {
|
|
510
|
+
const result = execShell('git status --short && echo "---" && git log --oneline -5');
|
|
511
|
+
return `🌿 Git:\n${result.stdout || '(not a git repo)'}`;
|
|
512
|
+
}
|
|
513
|
+
if (lower === '/clear') {
|
|
514
|
+
return `🧹 Context cleared. Starting fresh. ${tag}`;
|
|
515
|
+
}
|
|
516
|
+
if (lower === '/cancel') {
|
|
517
|
+
if (runningTasks.has(chatId)) {
|
|
518
|
+
runningTasks.delete(chatId);
|
|
519
|
+
return `🚫 Task cancelled. You can send a new task now. ${tag}`;
|
|
520
|
+
}
|
|
521
|
+
return `ℹ️ No task is running for this chat. ${tag}`;
|
|
522
|
+
}
|
|
523
|
+
// Looks like a shell command — run directly
|
|
524
|
+
const looksLikeCommand = /^(ls|cat|pwd|whoami|date|df|du|ps|top|free|uname|which|find|grep|git|npm|node|python|curl)\b/.test(lower);
|
|
525
|
+
if (looksLikeCommand) {
|
|
526
|
+
const result = execShell(text);
|
|
527
|
+
const output = result.stdout || result.stderr || '(no output)';
|
|
528
|
+
const truncated = output.length > 3500 ? output.slice(0, 3500) + '\n... (truncated)' : output;
|
|
529
|
+
return `⚡ ${text}\n${truncated}`;
|
|
530
|
+
}
|
|
531
|
+
// Return null to signal "not a command — treat as task"
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
535
|
+
// Authorization check
|
|
536
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
537
|
+
function isAuthorized(chatId, fromUser) {
|
|
538
|
+
// No open-access fallback — if no IDs configured the bot won't start,
|
|
539
|
+
// but guard here too as defense-in-depth.
|
|
540
|
+
if (AUTHORIZED_USER_IDS.size === 0)
|
|
541
|
+
return false;
|
|
542
|
+
// Check by user ID
|
|
543
|
+
const userId = fromUser?.id;
|
|
544
|
+
if (userId && AUTHORIZED_USER_IDS.has(Number(userId)))
|
|
545
|
+
return true;
|
|
546
|
+
// Also check chat ID (for group chats where the user might be different)
|
|
547
|
+
if (AUTHORIZED_USER_IDS.has(chatId))
|
|
548
|
+
return true;
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
552
|
+
// Main polling loop
|
|
553
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
554
|
+
/**
|
|
555
|
+
* Track whether a task is currently running for a given chat.
|
|
556
|
+
* If a task is running, new non-command messages are queued.
|
|
557
|
+
*/
|
|
558
|
+
const runningTasks = new Set();
|
|
559
|
+
async function poll() {
|
|
560
|
+
let offset = loadOffset();
|
|
561
|
+
console.log('💎 Aura Telegram Bot started');
|
|
562
|
+
console.log(` Bot: @Praktessruby_bot`);
|
|
563
|
+
console.log(` Offset: ${offset}`);
|
|
564
|
+
console.log(` Polling every 3 seconds...`);
|
|
565
|
+
console.log(` Project root: ${PROJECT_ROOT}`);
|
|
566
|
+
console.log(` Task model: ${TASK_MODEL}`);
|
|
567
|
+
console.log(` Safety: ${safetyState.safetyOn ? 'ON' : 'OFF'}`);
|
|
568
|
+
console.log(` Authorized users: ${AUTHORIZED_USER_IDS.size > 0 ? [...AUTHORIZED_USER_IDS].join(', ') : 'ALL (no restriction)'}`);
|
|
569
|
+
console.log('');
|
|
570
|
+
// Clear old updates on first run
|
|
571
|
+
if (offset === 0) {
|
|
572
|
+
try {
|
|
573
|
+
const updates = await curlGet('getUpdates', { offset: '0', limit: '100' });
|
|
574
|
+
if (updates.length > 0) {
|
|
575
|
+
offset = updates[updates.length - 1].update_id + 1;
|
|
576
|
+
saveOffset(offset);
|
|
577
|
+
console.log(` Cleared ${updates.length} old update(s), offset: ${offset}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch (e) {
|
|
581
|
+
console.error(` ⚠️ Clear error: ${e.message}`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
let consecutiveErrors = 0;
|
|
585
|
+
while (true) {
|
|
586
|
+
try {
|
|
587
|
+
const updates = await curlGet('getUpdates', {
|
|
588
|
+
offset: String(offset),
|
|
589
|
+
limit: '100',
|
|
590
|
+
timeout: '3',
|
|
591
|
+
});
|
|
592
|
+
consecutiveErrors = 0;
|
|
593
|
+
for (const update of updates) {
|
|
594
|
+
offset = update.update_id + 1;
|
|
595
|
+
saveOffset(offset);
|
|
596
|
+
const msg = update.message;
|
|
597
|
+
if (!msg)
|
|
598
|
+
continue;
|
|
599
|
+
if (!msg.text && !msg.voice)
|
|
600
|
+
continue;
|
|
601
|
+
const chatId = msg.chat.id;
|
|
602
|
+
const from = msg.from?.first_name ?? msg.from?.username ?? 'unknown';
|
|
603
|
+
// ── Authorization check ────────────────────────────────────────────
|
|
604
|
+
if (!isAuthorized(chatId, msg.from)) {
|
|
605
|
+
console.warn(`🚫 Unauthorized message from ${from} (id: ${msg.from?.id})`);
|
|
606
|
+
// Don't reply to unauthorized users — don't reveal the bot exists
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
// ── Handle voice messages (Phase 2 placeholder) ──────────────────
|
|
610
|
+
if (msg.voice) {
|
|
611
|
+
await sendMessage(chatId, '🎤 Voice messages are not yet supported. Please send text.');
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
const text = msg.text;
|
|
615
|
+
if (!text)
|
|
616
|
+
continue;
|
|
617
|
+
console.log(`📩 [${from}]: ${text}`);
|
|
618
|
+
// ── Check pending approvals first ───────────────────────────────
|
|
619
|
+
const approvedId = confirmManager.handleReply(chatId, text);
|
|
620
|
+
if (approvedId) {
|
|
621
|
+
console.log(`📤 Approval resolved for ${approvedId}`);
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
// ── Handle commands (synchronous) ────────────────────────────────
|
|
625
|
+
const commandResult = handleCommand(chatId, text, from);
|
|
626
|
+
if (commandResult !== null) {
|
|
627
|
+
try {
|
|
628
|
+
await sendMessage(chatId, commandResult);
|
|
629
|
+
console.log(`📤 Replied to ${from}`);
|
|
630
|
+
}
|
|
631
|
+
catch (e) {
|
|
632
|
+
console.error(`❌ Reply error: ${e.message}`);
|
|
633
|
+
}
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
// ── Non-command text → execute as Aura task ─────────────────────
|
|
637
|
+
if (runningTasks.has(chatId)) {
|
|
638
|
+
await sendMessage(chatId, `⏳ A task is already running for this chat. Please wait.`);
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
runningTasks.add(chatId);
|
|
642
|
+
const tag = (0, telegram_safety_js_1.safetyLabel)(safetyState.safetyOn);
|
|
643
|
+
// Send a "thinking" indicator
|
|
644
|
+
await sendMessage(chatId, `⏳ Processing task... ${tag}`);
|
|
645
|
+
// Execute asynchronously — don't block the poll loop
|
|
646
|
+
executeTask(chatId, text)
|
|
647
|
+
.then(async (response) => {
|
|
648
|
+
await sendMessage(chatId, response);
|
|
649
|
+
console.log(`📤 Task result sent to ${from}`);
|
|
650
|
+
})
|
|
651
|
+
.catch(async (e) => {
|
|
652
|
+
console.error(`❌ Task error: ${e.message}`);
|
|
653
|
+
try {
|
|
654
|
+
await sendMessage(chatId, `❌ Error: ${e.message}`);
|
|
655
|
+
}
|
|
656
|
+
catch { /* give up */ }
|
|
657
|
+
})
|
|
658
|
+
.finally(() => {
|
|
659
|
+
runningTasks.delete(chatId);
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
catch (e) {
|
|
664
|
+
consecutiveErrors++;
|
|
665
|
+
console.error(`⚠️ Poll error (${consecutiveErrors}): ${e.message}`);
|
|
666
|
+
if (consecutiveErrors > 10) {
|
|
667
|
+
console.error('💀 Too many errors, waiting 30s...');
|
|
668
|
+
await new Promise(resolve => setTimeout(resolve, 30000));
|
|
669
|
+
consecutiveErrors = 0;
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
678
|
+
// Entry
|
|
679
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
680
|
+
// Refuse to start without authorized user IDs — no open-access bots
|
|
681
|
+
if (AUTHORIZED_USER_IDS.size === 0) {
|
|
682
|
+
console.error('');
|
|
683
|
+
console.error('❌ AUTHORIZED_USER_IDS not configured — refusing to start an unrestricted bot.');
|
|
684
|
+
console.error(' Set allowed_user_ids in ~/.aura/telegram.json or set');
|
|
685
|
+
console.error(' TELEGRAM_BOT_ALLOWED_USER_IDS env var before running.');
|
|
686
|
+
console.error('');
|
|
687
|
+
process.exit(1);
|
|
688
|
+
}
|
|
689
|
+
poll().catch(err => {
|
|
690
|
+
console.error('💀 Fatal polling crash:', err);
|
|
691
|
+
process.exit(1);
|
|
692
|
+
});
|
|
693
|
+
//# sourceMappingURL=telegram-bot.js.map
|