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,222 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.WHATSAPP_DEFINITION = void 0;
37
+ exports.whatsAppTool = whatsAppTool;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ exports.WHATSAPP_DEFINITION = {
42
+ name: 'whatsapp',
43
+ description: 'Send WhatsApp messages via Twilio API or configured HTTP gateway. ' +
44
+ 'Configure ~/.aura/whatsapp.json with { "provider": "twilio", "account_sid": "...", "auth_token": "...", "from": "whatsapp:+14155238886" }. ' +
45
+ 'Or { "provider": "gateway", "url": "http://localhost:3000/send" }.',
46
+ parameters: {
47
+ type: 'object',
48
+ properties: {
49
+ action: { type: 'string', description: 'Action: send, send_media, status' },
50
+ to: { type: 'string', description: 'Recipient phone number with country code (e.g., +381641234567)' },
51
+ message: { type: 'string', description: 'Message text' },
52
+ media_url: { type: 'string', description: 'URL of media to send (for send_media)' },
53
+ from: { type: 'string', description: 'Sender WhatsApp number (overrides config)' },
54
+ },
55
+ required: ['action'],
56
+ },
57
+ };
58
+ function loadConfig() {
59
+ const p = path.join(os.homedir(), '.aura', 'whatsapp.json');
60
+ if (!fs.existsSync(p))
61
+ return null;
62
+ try {
63
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ // ─────────────────────────────────────────────────────────────────────────────
70
+ // Providers
71
+ // ─────────────────────────────────────────────────────────────────────────────
72
+ function normalizePhone(phone) {
73
+ // Ensure it starts with + and has whatsapp: prefix for Twilio
74
+ const cleaned = phone.replace(/\s/g, '');
75
+ if (cleaned.startsWith('whatsapp:'))
76
+ return cleaned;
77
+ return `whatsapp:${cleaned.startsWith('+') ? cleaned : '+' + cleaned}`;
78
+ }
79
+ async function sendViaTwilio(config, to, message, from) {
80
+ if (!config.account_sid || !config.auth_token) {
81
+ return 'Error: Twilio account_sid and auth_token required in config';
82
+ }
83
+ const fromNumber = normalizePhone(from ?? config.from ?? '');
84
+ const toNumber = normalizePhone(to);
85
+ const url = `https://api.twilio.com/2010-04-01/Accounts/${config.account_sid}/Messages.json`;
86
+ const params = new URLSearchParams({
87
+ From: fromNumber,
88
+ To: toNumber,
89
+ Body: message,
90
+ });
91
+ const response = await fetch(url, {
92
+ method: 'POST',
93
+ headers: {
94
+ 'Content-Type': 'application/x-www-form-urlencoded',
95
+ 'Authorization': 'Basic ' + Buffer.from(`${config.account_sid}:${config.auth_token}`).toString('base64'),
96
+ },
97
+ body: params.toString(),
98
+ signal: AbortSignal.timeout(15_000),
99
+ });
100
+ const data = await response.json();
101
+ if (!response.ok) {
102
+ return `Error: Twilio API error: ${data.message ?? 'Unknown error'} (code: ${data.code})`;
103
+ }
104
+ return `WhatsApp message sent to ${to} (SID: ${data.sid}, status: ${data.status})`;
105
+ }
106
+ async function sendViaTwilioMedia(config, to, message, mediaUrl, from) {
107
+ if (!config.account_sid || !config.auth_token) {
108
+ return 'Error: Twilio account_sid and auth_token required in config';
109
+ }
110
+ const fromNumber = normalizePhone(from ?? config.from ?? '');
111
+ const toNumber = normalizePhone(to);
112
+ const url = `https://api.twilio.com/2010-04-01/Accounts/${config.account_sid}/Messages.json`;
113
+ const params = new URLSearchParams({
114
+ From: fromNumber,
115
+ To: toNumber,
116
+ Body: message,
117
+ MediaUrl: mediaUrl,
118
+ });
119
+ const response = await fetch(url, {
120
+ method: 'POST',
121
+ headers: {
122
+ 'Content-Type': 'application/x-www-form-urlencoded',
123
+ 'Authorization': 'Basic ' + Buffer.from(`${config.account_sid}:${config.auth_token}`).toString('base64'),
124
+ },
125
+ body: params.toString(),
126
+ signal: AbortSignal.timeout(15_000),
127
+ });
128
+ const data = await response.json();
129
+ if (!response.ok) {
130
+ return `Error: Twilio API error: ${data.message ?? 'Unknown error'}`;
131
+ }
132
+ return `WhatsApp media sent to ${to} (SID: ${data.sid})`;
133
+ }
134
+ async function sendViaGateway(config, to, message) {
135
+ if (!config.url)
136
+ return 'Error: Gateway URL required in config';
137
+ const response = await fetch(config.url, {
138
+ method: 'POST',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ ...(config.api_key ? { 'Authorization': `Bearer ${config.api_key}` } : {}),
142
+ },
143
+ body: JSON.stringify({ to, message }),
144
+ signal: AbortSignal.timeout(15_000),
145
+ });
146
+ if (!response.ok) {
147
+ const text = await response.text();
148
+ return `Error: Gateway returned HTTP ${response.status}: ${text.slice(0, 200)}`;
149
+ }
150
+ return `WhatsApp message sent to ${to} via gateway`;
151
+ }
152
+ async function checkStatus(config) {
153
+ if (config.provider === 'twilio') {
154
+ if (!config.account_sid || !config.auth_token)
155
+ return 'Error: Twilio credentials not configured';
156
+ const url = `https://api.twilio.com/2010-04-01/Accounts/${config.account_sid}.json`;
157
+ const response = await fetch(url, {
158
+ headers: {
159
+ 'Authorization': 'Basic ' + Buffer.from(`${config.account_sid}:${config.auth_token}`).toString('base64'),
160
+ },
161
+ signal: AbortSignal.timeout(10_000),
162
+ });
163
+ if (!response.ok)
164
+ return 'Error: Cannot connect to Twilio';
165
+ const data = await response.json();
166
+ return `Twilio connected. Account: ${data.friendly_name} (${data.status})`;
167
+ }
168
+ if (config.provider === 'gateway') {
169
+ try {
170
+ const response = await fetch(config.url.replace(/\/send$/, '/health'), { signal: AbortSignal.timeout(5000) });
171
+ return response.ok ? 'Gateway is reachable' : `Gateway returned HTTP ${response.status}`;
172
+ }
173
+ catch {
174
+ return 'Gateway is not reachable';
175
+ }
176
+ }
177
+ return 'Error: Unknown provider';
178
+ }
179
+ // ─────────────────────────────────────────────────────────────────────────────
180
+ // Main executor
181
+ // ─────────────────────────────────────────────────────────────────────────────
182
+ async function whatsAppTool(input) {
183
+ const config = loadConfig();
184
+ if (!config) {
185
+ return 'Error: WhatsApp not configured. Create ~/.aura/whatsapp.json with { "provider": "twilio", "account_sid": "...", "auth_token": "...", "from": "whatsapp:+14155238886" } or { "provider": "gateway", "url": "http://localhost:3000/send" }.';
186
+ }
187
+ try {
188
+ switch (input.action) {
189
+ case 'send': {
190
+ if (!input.to)
191
+ return 'Error: to (phone number) required';
192
+ if (!input.message)
193
+ return 'Error: message required';
194
+ if (config.provider === 'twilio')
195
+ return await sendViaTwilio(config, input.to, input.message, input.from);
196
+ if (config.provider === 'gateway')
197
+ return await sendViaGateway(config, input.to, input.message);
198
+ return 'Error: Unknown provider in config';
199
+ }
200
+ case 'send_media': {
201
+ if (!input.to)
202
+ return 'Error: to required';
203
+ if (!input.message)
204
+ return 'Error: message required';
205
+ if (!input.media_url)
206
+ return 'Error: media_url required';
207
+ if (config.provider === 'twilio')
208
+ return await sendViaTwilioMedia(config, input.to, input.message, input.media_url, input.from);
209
+ return 'Error: send_media only supported for Twilio provider';
210
+ }
211
+ case 'status': {
212
+ return await checkStatus(config);
213
+ }
214
+ default:
215
+ return `Error: Unknown whatsapp action: ${input.action}`;
216
+ }
217
+ }
218
+ catch (e) {
219
+ return `WhatsApp error (${input.action}): ${e?.message ?? String(e)}`;
220
+ }
221
+ }
222
+ //# sourceMappingURL=whatsapp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../src/tools/whatsapp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { writeFile } from './tools.js';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeFile = void 0;
4
+ var tools_js_1 = require("./tools.js");
5
+ Object.defineProperty(exports, "writeFile", { enumerable: true, get: function () { return tools_js_1.writeFile; } });
6
+ //# sourceMappingURL=write-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-file.js","sourceRoot":"","sources":["../../src/tools/write-file.ts"],"names":[],"mappings":";;;AAAA,uCAAuC;AAA9B,qGAAA,SAAS,OAAA"}
@@ -0,0 +1,9 @@
1
+ import type { ToolDefinition } from '../providers/types.js';
2
+ export interface YouTubeTranscriptInput {
3
+ url: string;
4
+ lang?: string;
5
+ format?: 'text' | 'timestamps' | 'srt';
6
+ max_chars?: number;
7
+ }
8
+ export declare const YOUTUBE_TRANSCRIPT_DEFINITION: ToolDefinition;
9
+ export declare function youtubeTranscript(input: YouTubeTranscriptInput): Promise<string>;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.YOUTUBE_TRANSCRIPT_DEFINITION = void 0;
4
+ exports.youtubeTranscript = youtubeTranscript;
5
+ const sanitize_js_1 = require("../util/sanitize.js");
6
+ exports.YOUTUBE_TRANSCRIPT_DEFINITION = {
7
+ name: 'youtube_transcript',
8
+ description: 'Extract transcript/captions from a YouTube video. Works with regular videos and Shorts. ' +
9
+ 'No API key required. Supports multiple languages and output formats.',
10
+ parameters: {
11
+ type: 'object',
12
+ properties: {
13
+ url: { type: 'string', description: 'YouTube video URL or video ID' },
14
+ lang: { type: 'string', description: 'Caption language code (default: en). Use "list" to see available languages.' },
15
+ format: { type: 'string', description: 'Output format: "text" (plain text), "timestamps" (with timestamps), "srt" (SRT subtitle format). Default: timestamps' },
16
+ max_chars: { type: 'number', description: 'Max characters to return (default: 50000)' },
17
+ },
18
+ required: ['url'],
19
+ },
20
+ };
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ // Helpers
23
+ // ─────────────────────────────────────────────────────────────────────────────
24
+ function extractVideoId(input) {
25
+ // Handle direct video IDs
26
+ if (/^[a-zA-Z0-9_-]{11}$/.test(input))
27
+ return input;
28
+ const patterns = [
29
+ /(?:youtube\.com\/watch\?.*v=)([a-zA-Z0-9_-]{11})/,
30
+ /(?:youtube\.com\/shorts\/)([a-zA-Z0-9_-]{11})/,
31
+ /(?:youtu\.be\/)([a-zA-Z0-9_-]{11})/,
32
+ /(?:youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
33
+ /(?:youtube\.com\/v\/)([a-zA-Z0-9_-]{11})/,
34
+ ];
35
+ for (const p of patterns) {
36
+ const m = input.match(p);
37
+ if (m)
38
+ return m[1];
39
+ }
40
+ return null;
41
+ }
42
+ function parseTimedText(xml) {
43
+ const segments = [];
44
+ // YouTube returns XML like: <p t="0" d="5000">Hello world</p>
45
+ // or newer format: <text start="0" dur="5">Hello world</text>
46
+ const pRegex = /<p\s[^>]*t="(\d+)"[^>]*d="(\d+)"[^>]*>([\s\S]*?)<\/p>/g;
47
+ let m;
48
+ while ((m = pRegex.exec(xml)) !== null) {
49
+ const start = parseInt(m[1], 10) / 1000;
50
+ const duration = parseInt(m[2], 10) / 1000;
51
+ const text = (0, sanitize_js_1.decodeEntities)((0, sanitize_js_1.stripHtml)(m[3]))
52
+ .replace(/\n/g, ' ')
53
+ .trim();
54
+ if (text)
55
+ segments.push({ start, duration, text });
56
+ }
57
+ // Fallback: try <text start="..." dur="..."> format
58
+ if (segments.length === 0) {
59
+ const textRegex = /<text\s[^>]*start="([\d.]+)"[^>]*dur="([\d.]+)"[^>]*>([\s\S]*?)<\/text>/g;
60
+ while ((m = textRegex.exec(xml)) !== null) {
61
+ const start = parseFloat(m[1]);
62
+ const duration = parseFloat(m[2]);
63
+ const text = (0, sanitize_js_1.decodeEntities)((0, sanitize_js_1.stripHtml)(m[3]))
64
+ .replace(/\n/g, ' ')
65
+ .trim();
66
+ if (text)
67
+ segments.push({ start, duration, text });
68
+ }
69
+ }
70
+ return segments;
71
+ }
72
+ function formatTimestamp(seconds) {
73
+ const h = Math.floor(seconds / 3600);
74
+ const m = Math.floor((seconds % 3600) / 60);
75
+ const s = Math.floor(seconds % 60);
76
+ if (h > 0)
77
+ return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
78
+ return `${m}:${String(s).padStart(2, '0')}`;
79
+ }
80
+ function formatSrtTimestamp(seconds) {
81
+ const h = Math.floor(seconds / 3600);
82
+ const m = Math.floor((seconds % 3600) / 60);
83
+ const s = Math.floor(seconds % 60);
84
+ const ms = Math.floor((seconds % 1) * 1000);
85
+ return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')},${String(ms).padStart(3, '0')}`;
86
+ }
87
+ function formatTranscript(segments, format) {
88
+ switch (format) {
89
+ case 'text':
90
+ return segments.map(s => s.text).join(' ');
91
+ case 'srt':
92
+ return segments.map((s, i) => {
93
+ const end = s.start + s.duration;
94
+ return `${i + 1}\n${formatSrtTimestamp(s.start)} --> ${formatSrtTimestamp(end)}\n${s.text}\n`;
95
+ }).join('\n');
96
+ case 'timestamps':
97
+ default:
98
+ return segments.map(s => `[${formatTimestamp(s.start)}] ${s.text}`).join('\n');
99
+ }
100
+ }
101
+ // ─────────────────────────────────────────────────────────────────────────────
102
+ // Main executor
103
+ // ─────────────────────────────────────────────────────────────────────────────
104
+ async function youtubeTranscript(input) {
105
+ const maxChars = input.max_chars ?? 50_000;
106
+ const format = input.format ?? 'timestamps';
107
+ const lang = input.lang ?? 'en';
108
+ // 1. Extract video ID
109
+ const videoId = extractVideoId(input.url);
110
+ if (!videoId) {
111
+ return `Error: Could not extract video ID from: "${input.url}"\nSupported formats: https://youtube.com/watch?v=ID, https://youtu.be/ID, https://youtube.com/shorts/ID`;
112
+ }
113
+ try {
114
+ // 2. Fetch the YouTube page to find caption tracks
115
+ const pageUrl = `https://www.youtube.com/watch?v=${videoId}`;
116
+ const response = await fetch(pageUrl, {
117
+ headers: {
118
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
119
+ 'Accept-Language': 'en-US,en;q=0.9',
120
+ },
121
+ signal: AbortSignal.timeout(15_000),
122
+ });
123
+ if (!response.ok) {
124
+ return `Error: YouTube returned HTTP ${response.status}`;
125
+ }
126
+ const html = await response.text();
127
+ // 3. Extract ytInitialPlayerResponse from the page
128
+ // Use [\s\S] instead of /s flag for compatibility with older TS targets
129
+ const playerMatch = html.match(/ytInitialPlayerResponse\s*=\s*(\{[\s\S]+?\});\s*(?:var\s|<\/script)/);
130
+ if (!playerMatch) {
131
+ return 'Error: Could not extract player data from YouTube page. The video may be private, age-restricted, or YouTube changed their page structure.';
132
+ }
133
+ const playerJson = playerMatch[1];
134
+ let playerData;
135
+ try {
136
+ playerData = JSON.parse(playerJson);
137
+ }
138
+ catch {
139
+ return 'Error: Failed to parse YouTube player data JSON.';
140
+ }
141
+ // 4. Navigate to caption tracks
142
+ const captions = playerData?.captions?.playerCaptionsTracklistRenderer?.captionTracks;
143
+ if (!captions || captions.length === 0) {
144
+ const videoDetails = playerData?.videoDetails;
145
+ const title = videoDetails?.title ?? 'Unknown';
146
+ return `No captions available for: "${title}" (${videoId})\nThe video may not have subtitles or auto-generated captions.`;
147
+ }
148
+ // 5. If lang=list, show available languages
149
+ if (lang === 'list') {
150
+ const tracks = captions.map((t) => ` - ${t.languageCode}: ${t.name}${t.isTranslatable ? ' (translatable)' : ''}`);
151
+ return `Available caption tracks for ${videoId}:\n${tracks.join('\n')}`;
152
+ }
153
+ // 6. Find the requested language track
154
+ let track = captions.find((t) => t.languageCode === lang);
155
+ if (!track) {
156
+ // Try partial match (e.g., "en" matches "en-US")
157
+ track = captions.find((t) => t.languageCode.startsWith(lang));
158
+ }
159
+ if (!track) {
160
+ // Fall back to first available
161
+ track = captions[0];
162
+ if (!track) {
163
+ return `Error: No caption track found for language "${lang}".`;
164
+ }
165
+ }
166
+ // 7. Fetch the caption XML
167
+ // Remove fmt=srv3 to get simpler XML
168
+ const captionUrl = track.baseUrl.replace(/&fmt=\w+/, '');
169
+ const captionResponse = await fetch(captionUrl, {
170
+ headers: {
171
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
172
+ },
173
+ signal: AbortSignal.timeout(10_000),
174
+ });
175
+ if (!captionResponse.ok) {
176
+ return `Error: Failed to fetch captions (HTTP ${captionResponse.status})`;
177
+ }
178
+ const captionXml = await captionResponse.text();
179
+ // 8. Parse the timed text
180
+ const segments = parseTimedText(captionXml);
181
+ if (segments.length === 0) {
182
+ return `Error: No caption segments found in the response for language "${track.languageCode}".`;
183
+ }
184
+ // 9. Format and return
185
+ const videoDetails = playerData?.videoDetails;
186
+ const title = videoDetails?.title ?? 'Unknown';
187
+ const duration = videoDetails?.lengthSeconds ? `${Math.floor(parseInt(videoDetails.lengthSeconds) / 60)}m${parseInt(videoDetails.lengthSeconds) % 60}s` : '?';
188
+ const header = `YouTube Transcript: "${title}" (${duration})\nLanguage: ${track.languageCode} | Segments: ${segments.length}\nURL: ${pageUrl}\n\n`;
189
+ const body = formatTranscript(segments, format);
190
+ const result = header + body;
191
+ if (result.length > maxChars) {
192
+ return result.slice(0, maxChars) + `\n\n... [truncated at ${maxChars} chars]`;
193
+ }
194
+ return result;
195
+ }
196
+ catch (e) {
197
+ return `Error fetching YouTube transcript: ${e?.message ?? String(e)}`;
198
+ }
199
+ }
200
+ //# sourceMappingURL=youtube-transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube-transcript.js","sourceRoot":"","sources":["../../src/tools/youtube-transcript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Circuit breaker. Trips after N consecutive failures within a time window,
3
+ * then refuses new calls for a cooldown period. Half-open after cooldown:
4
+ * a single trial call decides whether to close again or stay open.
5
+ */
6
+ export type CircuitState = 'closed' | 'open' | 'half-open';
7
+ export interface CircuitBreakerOptions {
8
+ /** Trip after this many consecutive failures. Default 5. */
9
+ failureThreshold?: number;
10
+ /** Time in ms before trying again after the breaker opens. Default 30_000. */
11
+ cooldownMs?: number;
12
+ /** Called on every state transition — for observability. */
13
+ onStateChange?: (state: CircuitState, info: {
14
+ failures: number;
15
+ reason?: string;
16
+ }) => void;
17
+ /** Sleep function for testing. */
18
+ sleep?: (ms: number) => Promise<void>;
19
+ }
20
+ export declare class CircuitOpenError extends Error {
21
+ readonly until: number;
22
+ constructor(until: number);
23
+ }
24
+ export declare class CircuitBreaker {
25
+ private state;
26
+ private failures;
27
+ private openedAt;
28
+ private readonly threshold;
29
+ private readonly cooldown;
30
+ private readonly onStateChange?;
31
+ private readonly sleep;
32
+ constructor(opts?: CircuitBreakerOptions);
33
+ /**
34
+ * Run `fn`. If the breaker is open and still cooling down, throws CircuitOpenError
35
+ * without calling `fn`. Records success/failure and manages state.
36
+ */
37
+ call<T>(fn: () => Promise<T>): Promise<T>;
38
+ /** Synchronous state check (mostly for tests). */
39
+ getState(): CircuitState;
40
+ getFailureCount(): number;
41
+ private onSuccess;
42
+ private onFailure;
43
+ private transition;
44
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CircuitBreaker = exports.CircuitOpenError = void 0;
4
+ class CircuitOpenError extends Error {
5
+ until;
6
+ constructor(until) {
7
+ super(`Circuit breaker open until ${new Date(until).toISOString()}`);
8
+ this.until = until;
9
+ this.name = 'CircuitOpenError';
10
+ }
11
+ }
12
+ exports.CircuitOpenError = CircuitOpenError;
13
+ class CircuitBreaker {
14
+ state = 'closed';
15
+ failures = 0;
16
+ openedAt = 0;
17
+ threshold;
18
+ cooldown;
19
+ onStateChange;
20
+ sleep;
21
+ constructor(opts = {}) {
22
+ this.threshold = opts.failureThreshold ?? 5;
23
+ this.cooldown = opts.cooldownMs ?? 30_000;
24
+ this.onStateChange = opts.onStateChange;
25
+ this.sleep = opts.sleep ?? defaultSleep;
26
+ }
27
+ /**
28
+ * Run `fn`. If the breaker is open and still cooling down, throws CircuitOpenError
29
+ * without calling `fn`. Records success/failure and manages state.
30
+ */
31
+ async call(fn) {
32
+ if (this.state === 'open') {
33
+ if (Date.now() - this.openedAt >= this.cooldown) {
34
+ this.transition('half-open', 'cooldown elapsed');
35
+ }
36
+ else {
37
+ throw new CircuitOpenError(this.openedAt + this.cooldown);
38
+ }
39
+ }
40
+ try {
41
+ const result = await fn();
42
+ this.onSuccess();
43
+ return result;
44
+ }
45
+ catch (e) {
46
+ this.onFailure(e);
47
+ throw e;
48
+ }
49
+ }
50
+ /** Synchronous state check (mostly for tests). */
51
+ getState() { return this.state; }
52
+ getFailureCount() { return this.failures; }
53
+ onSuccess() {
54
+ this.failures = 0;
55
+ if (this.state !== 'closed')
56
+ this.transition('closed', 'call succeeded');
57
+ }
58
+ onFailure(e) {
59
+ this.failures++;
60
+ if (this.state === 'half-open' || (this.state === 'closed' && this.failures >= this.threshold)) {
61
+ this.openedAt = Date.now();
62
+ this.transition('open', e instanceof Error ? e.message : String(e));
63
+ }
64
+ }
65
+ transition(to, reason) {
66
+ if (this.state === to)
67
+ return;
68
+ this.state = to;
69
+ if (to === 'closed')
70
+ this.failures = 0;
71
+ this.onStateChange?.(to, { failures: this.failures, reason });
72
+ }
73
+ }
74
+ exports.CircuitBreaker = CircuitBreaker;
75
+ function defaultSleep(ms) {
76
+ return new Promise(resolve => setTimeout(resolve, ms));
77
+ }
78
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/util/circuit-breaker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Provider-agnostic env-var reader.
3
+ *
4
+ * Tries, in order:
5
+ * 1. The canonical UPPER_SNAKE_CASE var (most SDKs read this)
6
+ * 2. The lowercase variant (some shells / dotenv loaders normalise to this)
7
+ * 3. Common alternates passed as `aliases`
8
+ *
9
+ * Returns `undefined` if none are set, never throws. Returns `undefined`
10
+ * (NOT '') for empty / whitespace / placeholder values, so callers can use
11
+ * the `??` operator and have it fall through to the next fallback.
12
+ */
13
+ export declare function getApiKey(canonical: string, ...aliases: string[]): string | undefined;
14
+ /**
15
+ * Same idea for non-secret env vars (base URLs, model names).
16
+ * Returns `undefined` for unset / empty / whitespace, so `??` chains work.
17
+ */
18
+ export declare function getEnv(canonical: string, ...aliases: string[]): string | undefined;