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.
Files changed (288) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/agent/context.d.ts +13 -0
  4. package/dist/agent/context.js +183 -0
  5. package/dist/agent/context.js.map +1 -0
  6. package/dist/agent/loop.d.ts +60 -0
  7. package/dist/agent/loop.js +228 -0
  8. package/dist/agent/loop.js.map +1 -0
  9. package/dist/agent/session-store.d.ts +30 -0
  10. package/dist/agent/session-store.js +178 -0
  11. package/dist/agent/session-store.js.map +1 -0
  12. package/dist/agent/spawner.d.ts +57 -0
  13. package/dist/agent/spawner.js +112 -0
  14. package/dist/agent/spawner.js.map +1 -0
  15. package/dist/agent/system-prompt.d.ts +3 -0
  16. package/dist/agent/system-prompt.js +100 -0
  17. package/dist/agent/system-prompt.js.map +1 -0
  18. package/dist/architect/engine.d.ts +47 -0
  19. package/dist/architect/engine.js +217 -0
  20. package/dist/architect/engine.js.map +1 -0
  21. package/dist/architect/types.d.ts +61 -0
  22. package/dist/architect/types.js +6 -0
  23. package/dist/architect/types.js.map +1 -0
  24. package/dist/cli/diamond.d.ts +1 -0
  25. package/dist/cli/diamond.js +23 -0
  26. package/dist/cli/diamond.js.map +1 -0
  27. package/dist/cli/display.d.ts +44 -0
  28. package/dist/cli/display.js +234 -0
  29. package/dist/cli/display.js.map +1 -0
  30. package/dist/cli/index.d.ts +2 -0
  31. package/dist/cli/index.js +1734 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/config/defaults.d.ts +46 -0
  34. package/dist/config/defaults.js +106 -0
  35. package/dist/config/defaults.js.map +1 -0
  36. package/dist/config/project-config.d.ts +90 -0
  37. package/dist/config/project-config.js +141 -0
  38. package/dist/config/project-config.js.map +1 -0
  39. package/dist/harness/proposer.d.ts +26 -0
  40. package/dist/harness/proposer.js +204 -0
  41. package/dist/harness/proposer.js.map +1 -0
  42. package/dist/harness/weakness-miner.d.ts +28 -0
  43. package/dist/harness/weakness-miner.js +359 -0
  44. package/dist/harness/weakness-miner.js.map +1 -0
  45. package/dist/integrations/harnesses.d.ts +23 -0
  46. package/dist/integrations/harnesses.js +161 -0
  47. package/dist/integrations/harnesses.js.map +1 -0
  48. package/dist/orchestration/competence.d.ts +53 -0
  49. package/dist/orchestration/competence.js +181 -0
  50. package/dist/orchestration/competence.js.map +1 -0
  51. package/dist/orchestration/executor.d.ts +42 -0
  52. package/dist/orchestration/executor.js +206 -0
  53. package/dist/orchestration/executor.js.map +1 -0
  54. package/dist/orchestration/index.d.ts +20 -0
  55. package/dist/orchestration/index.js +39 -0
  56. package/dist/orchestration/index.js.map +1 -0
  57. package/dist/orchestration/orchestrator-prompts.d.ts +11 -0
  58. package/dist/orchestration/orchestrator-prompts.js +153 -0
  59. package/dist/orchestration/orchestrator-prompts.js.map +1 -0
  60. package/dist/orchestration/orchestrator.d.ts +27 -0
  61. package/dist/orchestration/orchestrator.js +169 -0
  62. package/dist/orchestration/orchestrator.js.map +1 -0
  63. package/dist/orchestration/plan-store.d.ts +53 -0
  64. package/dist/orchestration/plan-store.js +176 -0
  65. package/dist/orchestration/plan-store.js.map +1 -0
  66. package/dist/orchestration/router-prompts.d.ts +6 -0
  67. package/dist/orchestration/router-prompts.js +55 -0
  68. package/dist/orchestration/router-prompts.js.map +1 -0
  69. package/dist/orchestration/router.d.ts +23 -0
  70. package/dist/orchestration/router.js +70 -0
  71. package/dist/orchestration/router.js.map +1 -0
  72. package/dist/orchestration/ruby-detect.d.ts +6 -0
  73. package/dist/orchestration/ruby-detect.js +130 -0
  74. package/dist/orchestration/ruby-detect.js.map +1 -0
  75. package/dist/orchestration/ruby-types.d.ts +44 -0
  76. package/dist/orchestration/ruby-types.js +6 -0
  77. package/dist/orchestration/ruby-types.js.map +1 -0
  78. package/dist/orchestration/specialist-prompts.d.ts +19 -0
  79. package/dist/orchestration/specialist-prompts.js +143 -0
  80. package/dist/orchestration/specialist-prompts.js.map +1 -0
  81. package/dist/orchestration/specialists.d.ts +66 -0
  82. package/dist/orchestration/specialists.js +175 -0
  83. package/dist/orchestration/specialists.js.map +1 -0
  84. package/dist/orchestration/types.d.ts +82 -0
  85. package/dist/orchestration/types.js +6 -0
  86. package/dist/orchestration/types.js.map +1 -0
  87. package/dist/perception/extractor.d.ts +7 -0
  88. package/dist/perception/extractor.js +521 -0
  89. package/dist/perception/extractor.js.map +1 -0
  90. package/dist/perception/graph-store.d.ts +25 -0
  91. package/dist/perception/graph-store.js +117 -0
  92. package/dist/perception/graph-store.js.map +1 -0
  93. package/dist/perception/index.d.ts +4 -0
  94. package/dist/perception/index.js +18 -0
  95. package/dist/perception/index.js.map +1 -0
  96. package/dist/perception/queries.d.ts +29 -0
  97. package/dist/perception/queries.js +354 -0
  98. package/dist/perception/queries.js.map +1 -0
  99. package/dist/perception/types.d.ts +103 -0
  100. package/dist/perception/types.js +6 -0
  101. package/dist/perception/types.js.map +1 -0
  102. package/dist/providers/anthropic.d.ts +11 -0
  103. package/dist/providers/anthropic.js +172 -0
  104. package/dist/providers/anthropic.js.map +1 -0
  105. package/dist/providers/factory.d.ts +58 -0
  106. package/dist/providers/factory.js +354 -0
  107. package/dist/providers/factory.js.map +1 -0
  108. package/dist/providers/fallback.d.ts +24 -0
  109. package/dist/providers/fallback.js +72 -0
  110. package/dist/providers/fallback.js.map +1 -0
  111. package/dist/providers/google.d.ts +11 -0
  112. package/dist/providers/google.js +129 -0
  113. package/dist/providers/google.js.map +1 -0
  114. package/dist/providers/openai-compatible.d.ts +24 -0
  115. package/dist/providers/openai-compatible.js +216 -0
  116. package/dist/providers/openai-compatible.js.map +1 -0
  117. package/dist/providers/resilient-factory.d.ts +24 -0
  118. package/dist/providers/resilient-factory.js +57 -0
  119. package/dist/providers/resilient-factory.js.map +1 -0
  120. package/dist/providers/resilient.d.ts +63 -0
  121. package/dist/providers/resilient.js +145 -0
  122. package/dist/providers/resilient.js.map +1 -0
  123. package/dist/providers/types.d.ts +84 -0
  124. package/dist/providers/types.js +6 -0
  125. package/dist/providers/types.js.map +1 -0
  126. package/dist/ruby/alternator.d.ts +40 -0
  127. package/dist/ruby/alternator.js +233 -0
  128. package/dist/ruby/alternator.js.map +1 -0
  129. package/dist/ruby/competence.d.ts +34 -0
  130. package/dist/ruby/competence.js +264 -0
  131. package/dist/ruby/competence.js.map +1 -0
  132. package/dist/ruby/episode-capture.d.ts +56 -0
  133. package/dist/ruby/episode-capture.js +193 -0
  134. package/dist/ruby/episode-capture.js.map +1 -0
  135. package/dist/ruby/fine-tune.d.ts +16 -0
  136. package/dist/ruby/fine-tune.js +253 -0
  137. package/dist/ruby/fine-tune.js.map +1 -0
  138. package/dist/ruby/index.d.ts +10 -0
  139. package/dist/ruby/index.js +26 -0
  140. package/dist/ruby/index.js.map +1 -0
  141. package/dist/ruby/ruby-model.d.ts +36 -0
  142. package/dist/ruby/ruby-model.js +81 -0
  143. package/dist/ruby/ruby-model.js.map +1 -0
  144. package/dist/ruby/training-data.d.ts +11 -0
  145. package/dist/ruby/training-data.js +107 -0
  146. package/dist/ruby/training-data.js.map +1 -0
  147. package/dist/ruby/types.d.ts +136 -0
  148. package/dist/ruby/types.js +20 -0
  149. package/dist/ruby/types.js.map +1 -0
  150. package/dist/safety/permissions.d.ts +32 -0
  151. package/dist/safety/permissions.js +304 -0
  152. package/dist/safety/permissions.js.map +1 -0
  153. package/dist/server/index.d.ts +9 -0
  154. package/dist/server/index.js +342 -0
  155. package/dist/server/index.js.map +1 -0
  156. package/dist/server/session.d.ts +22 -0
  157. package/dist/server/session.js +16 -0
  158. package/dist/server/session.js.map +1 -0
  159. package/dist/setup/first-run.d.ts +41 -0
  160. package/dist/setup/first-run.js +386 -0
  161. package/dist/setup/first-run.js.map +1 -0
  162. package/dist/setup/global-config.d.ts +19 -0
  163. package/dist/setup/global-config.js +97 -0
  164. package/dist/setup/global-config.js.map +1 -0
  165. package/dist/tools/audio-transcribe.d.ts +8 -0
  166. package/dist/tools/audio-transcribe.js +156 -0
  167. package/dist/tools/audio-transcribe.js.map +1 -0
  168. package/dist/tools/browser.d.ts +15 -0
  169. package/dist/tools/browser.js +241 -0
  170. package/dist/tools/browser.js.map +1 -0
  171. package/dist/tools/calendar.d.ts +12 -0
  172. package/dist/tools/calendar.js +196 -0
  173. package/dist/tools/calendar.js.map +1 -0
  174. package/dist/tools/clipboard.d.ts +7 -0
  175. package/dist/tools/clipboard.js +90 -0
  176. package/dist/tools/clipboard.js.map +1 -0
  177. package/dist/tools/cron.d.ts +10 -0
  178. package/dist/tools/cron.js +167 -0
  179. package/dist/tools/cron.js.map +1 -0
  180. package/dist/tools/edit-file.d.ts +6 -0
  181. package/dist/tools/edit-file.js +98 -0
  182. package/dist/tools/edit-file.js.map +1 -0
  183. package/dist/tools/email.d.ts +11 -0
  184. package/dist/tools/email.js +153 -0
  185. package/dist/tools/email.js.map +1 -0
  186. package/dist/tools/git.d.ts +1 -0
  187. package/dist/tools/git.js +7 -0
  188. package/dist/tools/git.js.map +1 -0
  189. package/dist/tools/http-request.d.ts +12 -0
  190. package/dist/tools/http-request.js +91 -0
  191. package/dist/tools/http-request.js.map +1 -0
  192. package/dist/tools/image-read.d.ts +7 -0
  193. package/dist/tools/image-read.js +125 -0
  194. package/dist/tools/image-read.js.map +1 -0
  195. package/dist/tools/index.d.ts +3 -0
  196. package/dist/tools/index.js +201 -0
  197. package/dist/tools/index.js.map +1 -0
  198. package/dist/tools/list-dir.d.ts +1 -0
  199. package/dist/tools/list-dir.js +6 -0
  200. package/dist/tools/list-dir.js.map +1 -0
  201. package/dist/tools/mcp.d.ts +11 -0
  202. package/dist/tools/mcp.js +356 -0
  203. package/dist/tools/mcp.js.map +1 -0
  204. package/dist/tools/memory.d.ts +9 -0
  205. package/dist/tools/memory.js +124 -0
  206. package/dist/tools/memory.js.map +1 -0
  207. package/dist/tools/notify.d.ts +9 -0
  208. package/dist/tools/notify.js +40 -0
  209. package/dist/tools/notify.js.map +1 -0
  210. package/dist/tools/read-file.d.ts +6 -0
  211. package/dist/tools/read-file.js +76 -0
  212. package/dist/tools/read-file.js.map +1 -0
  213. package/dist/tools/run-shell.d.ts +1 -0
  214. package/dist/tools/run-shell.js +6 -0
  215. package/dist/tools/run-shell.js.map +1 -0
  216. package/dist/tools/run-tests.d.ts +1 -0
  217. package/dist/tools/run-tests.js +6 -0
  218. package/dist/tools/run-tests.js.map +1 -0
  219. package/dist/tools/search-code.d.ts +1 -0
  220. package/dist/tools/search-code.js +6 -0
  221. package/dist/tools/search-code.js.map +1 -0
  222. package/dist/tools/telegram-bot.d.ts +2 -0
  223. package/dist/tools/telegram-bot.js +693 -0
  224. package/dist/tools/telegram-bot.js.map +1 -0
  225. package/dist/tools/telegram-safety.d.ts +52 -0
  226. package/dist/tools/telegram-safety.js +189 -0
  227. package/dist/tools/telegram-safety.js.map +1 -0
  228. package/dist/tools/telegram.d.ts +16 -0
  229. package/dist/tools/telegram.js +227 -0
  230. package/dist/tools/telegram.js.map +1 -0
  231. package/dist/tools/tools.d.ts +48 -0
  232. package/dist/tools/tools.js +328 -0
  233. package/dist/tools/tools.js.map +1 -0
  234. package/dist/tools/web-fetch.d.ts +11 -0
  235. package/dist/tools/web-fetch.js +119 -0
  236. package/dist/tools/web-fetch.js.map +1 -0
  237. package/dist/tools/web-search.d.ts +8 -0
  238. package/dist/tools/web-search.js +81 -0
  239. package/dist/tools/web-search.js.map +1 -0
  240. package/dist/tools/whatsapp.d.ts +10 -0
  241. package/dist/tools/whatsapp.js +222 -0
  242. package/dist/tools/whatsapp.js.map +1 -0
  243. package/dist/tools/write-file.d.ts +1 -0
  244. package/dist/tools/write-file.js +6 -0
  245. package/dist/tools/write-file.js.map +1 -0
  246. package/dist/tools/youtube-transcript.d.ts +9 -0
  247. package/dist/tools/youtube-transcript.js +200 -0
  248. package/dist/tools/youtube-transcript.js.map +1 -0
  249. package/dist/util/circuit-breaker.d.ts +44 -0
  250. package/dist/util/circuit-breaker.js +78 -0
  251. package/dist/util/circuit-breaker.js.map +1 -0
  252. package/dist/util/env.d.ts +18 -0
  253. package/dist/util/env.js +39 -0
  254. package/dist/util/env.js.map +1 -0
  255. package/dist/util/errors.d.ts +42 -0
  256. package/dist/util/errors.js +121 -0
  257. package/dist/util/errors.js.map +1 -0
  258. package/dist/util/rate-limiter.d.ts +71 -0
  259. package/dist/util/rate-limiter.js +141 -0
  260. package/dist/util/rate-limiter.js.map +1 -0
  261. package/dist/util/retry.d.ts +30 -0
  262. package/dist/util/retry.js +57 -0
  263. package/dist/util/retry.js.map +1 -0
  264. package/dist/util/sanitize.d.ts +16 -0
  265. package/dist/util/sanitize.js +255 -0
  266. package/dist/util/sanitize.js.map +1 -0
  267. package/dist/verify/checks.d.ts +21 -0
  268. package/dist/verify/checks.js +311 -0
  269. package/dist/verify/checks.js.map +1 -0
  270. package/dist/verify/index.d.ts +33 -0
  271. package/dist/verify/index.js +127 -0
  272. package/dist/verify/index.js.map +1 -0
  273. package/dist/verify/types.d.ts +20 -0
  274. package/dist/verify/types.js +3 -0
  275. package/dist/verify/types.js.map +1 -0
  276. package/dist/versioncheck.d.ts +22 -0
  277. package/dist/versioncheck.js +203 -0
  278. package/dist/versioncheck.js.map +1 -0
  279. package/dist/viz/index.d.ts +2 -0
  280. package/dist/viz/index.js +733 -0
  281. package/dist/viz/index.js.map +1 -0
  282. package/dist/workflows/engine.d.ts +46 -0
  283. package/dist/workflows/engine.js +320 -0
  284. package/dist/workflows/engine.js.map +1 -0
  285. package/dist/workflows/types.d.ts +92 -0
  286. package/dist/workflows/types.js +6 -0
  287. package/dist/workflows/types.js.map +1 -0
  288. 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