botql 1.0.2 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,23 +1,194 @@
1
- # BotQL — Bot Query Language
1
+ <h1 align="center">
2
+ <span style="background: linear-gradient(90deg, #6C5CE7, #00B894); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 900; font-size: 2.2em;">
3
+ BotQL: Bot Query Language
4
+ </span>
5
+ </h1>
2
6
 
3
- [![npm version](https://img.shields.io/npm/v/botql.svg)](https://www.npmjs.com/package/botql)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/adilson889/botql/pulls)
6
- [![BotQL](https://img.shields.io/badge/BotQL-rules%20language-blue.svg)](https://github.com/adilson889/botql)
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/botql">
9
+ <img src="https://img.shields.io/npm/v/botql.svg" alt="npm version">
10
+ </a>
11
+ <a href="https://opensource.org/licenses/MIT">
12
+ <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT">
13
+ </a>
14
+ <a href="https://github.com/adilson889/botql/pulls">
15
+ <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome">
16
+ </a>
17
+ <a href="https://github.com/adilson889/botql">
18
+ <img src="https://img.shields.io/badge/BotQL-rules%20language-blue.svg" alt="BotQL">
19
+ </a>
20
+ <a href="https://github.com/sponsors/adilson889">
21
+ <img src="https://img.shields.io/badge/Sponsor-%E2%9D%A4-red.svg" alt="Sponsor">
22
+ </a>
23
+ </p>
7
24
 
8
- **BotQL** é uma linguagem de regras simples, inspirada em SQL, para criar bots sem precisar de escrever código tradicional. Todos os comandos são escritos em **MAIÚSCULAS**, e blocos com mais de uma ação usam chaves `{ }`.
25
+ <p align="justify">
26
+ <strong>BotQL</strong> is a simple, SQL-inspired rules language for creating bots without writing traditional code. All commands are written in <strong>UPPERCASE</strong>, and blocks with more than one action use curly braces <code>{ }</code>.
27
+ </p>
9
28
 
10
- Vive no mesmo ficheiro `.sql`, com comandos reais de banco de dados — o bot age e persiste dados na mesma linguagem, sem sair do BotQL. O bot corre localmente, no computador ou servidor do próprio utilizador, e não em servidores geridos por terceiros.
29
+ <p align="justify">
30
+ It lives in <code>.sql</code> files, with real database commands — the bot acts and persists data in the same language, without leaving BotQL. The bot runs locally, on the user's own computer or server, not on third-party managed servers.
31
+ </p>
11
32
 
12
- Não precisas de saber programar para escrever BotQL; precisas apenas de saber o que queres que o teu bot faça.
33
+ <p align="justify">
34
+ You don't need to know how to code to write BotQL; you just need to know what you want your bot to do.
35
+ </p>
13
36
 
14
37
  ---
15
38
 
16
- ## Documentação Completa
39
+ ## Getting Started
17
40
 
18
- Ver **[docs/GETSTARTED.md](docs/GETSTARTED.md)** para o guia completo.
41
+ Want to learn the full syntax, see all commands, and understand how BotQL works? The complete guide walks you through everything from your first bot to advanced features like local knowledge retrieval and AI integration.
19
42
 
20
- ## Instalação
43
+ **[Read the full documentation →](docs/GETSTARTED.md)**
44
+
45
+ ---
46
+
47
+ ## Installation
48
+
49
+ ### Node.js
50
+
51
+ For server-side applications, CLI tools, and any Node.js environment:
21
52
 
22
53
  ```bash
23
- npm install botql
54
+ npm install botql
55
+ ```
56
+
57
+ ```javascript
58
+ // bot.sql
59
+ CREATE BOT "MyBot"
60
+ ON MESSAGE {
61
+ WHEN CONTAINS "hello" REPLY "Hi!"
62
+ }
63
+ RUN BOT
64
+ ```
65
+
66
+ ```javascript
67
+ const { createBot } = require('botql');
68
+
69
+ const bot = await createBot('bot.sql');
70
+ await bot.receiveMessage('+244900000000', 'hello');
71
+ ```
72
+
73
+ `createBot(sqlFilePath, options)` is the standard entry point: it loads the `.sql` file, wires up any `CONNECT`-ed platforms, runs `ON START`, and hands you back a bot that's ready to receive messages.
74
+
75
+ You can also run a bot straight from the command line:
76
+
77
+ ```bash
78
+ node node_modules/botql/createBot.js bot.sql
79
+ ```
80
+
81
+ ### Browser (CDN)
82
+
83
+ For websites, web apps, and in-browser editors — no build step required:
84
+
85
+ ```html
86
+ <!-- jsDelivr -->
87
+ <script src="https://cdn.jsdelivr.net/npm/botql/botql.browser.js"></script>
88
+
89
+ <!-- unpkg -->
90
+ <script src="https://unpkg.com/botql/botql.browser.js"></script>
91
+ ```
92
+
93
+ <p align="justify">
94
+ The browser bundle doesn't include <code>createBot()</code> (it depends on Node's <code>fs</code>/<code>path</code> to read <code>.sql</code> files and connectors). In the browser, use <code>BotQLInterpreter.fromSource(...)</code> directly with the source code as a string, and wire <code>onReply</code>/<code>onThinking</code>/etc yourself — see the JavaScript example below.
95
+ </p>
96
+
97
+ ---
98
+
99
+ ## Usage
100
+
101
+ ### JavaScript — from a file (Node.js)
102
+
103
+ ```javascript
104
+ const { createBot } = require('botql');
105
+
106
+ const bot = await createBot('bot.sql', {
107
+ onReply: ({ text, client }) => console.log(client + ':', text),
108
+ });
109
+
110
+ await bot.receiveMessage('+244900000000', 'hello');
111
+ ```
112
+
113
+ ### JavaScript — from a source string (Node.js or browser)
114
+
115
+ ```javascript
116
+ const { BotQLInterpreter } = require('botql');
117
+
118
+ const bot = BotQLInterpreter.fromSource(`
119
+ CREATE BOT "JSBot"
120
+ ON MESSAGE {
121
+ WHEN CONTAINS "hello" REPLY "Hello!"
122
+ }
123
+ RUN BOT
124
+ `);
125
+
126
+ bot.onReply = ({ text }) => console.log(text);
127
+
128
+ await bot.start();
129
+ await bot.receiveMessage('+244900000000', 'hello');
130
+ ```
131
+
132
+ ### JSX (React)
133
+
134
+ ```jsx
135
+ import { BotQLInterpreter } from 'botql';
136
+
137
+ const bot = BotQLInterpreter.fromSource(`
138
+ CREATE BOT "ReactBot"
139
+ ON MESSAGE {
140
+ WHEN CONTAINS "hello" REPLY "Hello from React!"
141
+ }
142
+ RUN BOT
143
+ `);
144
+
145
+ bot.onReply = ({ text }) => console.log(text);
146
+
147
+ await bot.start();
148
+ ```
149
+
150
+ ### TypeScript
151
+
152
+ ```typescript
153
+ import { createBot } from 'botql';
154
+
155
+ const bot = await createBot('bot.sql', {
156
+ onReply: ({ text }: { text: string }) => console.log(text),
157
+ });
158
+
159
+ await bot.receiveMessage('+244900000000', 'hello');
160
+ ```
161
+
162
+ ### PHP
163
+
164
+ ```php
165
+ <?php
166
+ $code = 'CREATE BOT "PHPBot" ON MESSAGE { WHEN CONTAINS "hello" REPLY "Hello!" } RUN BOT';
167
+ $response = shell_exec('node -e "' . addslashes($code) . '"');
168
+ echo $response;
169
+ ?>
170
+ ```
171
+
172
+ ### Python
173
+
174
+ ```python
175
+ import subprocess
176
+
177
+ code = 'CREATE BOT "PythonBot" ON MESSAGE { WHEN CONTAINS "hello" REPLY "Hello!" } RUN BOT'
178
+ subprocess.run(['node', '-e', code])
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Support
184
+
185
+ If this project helped you, consider supporting:
186
+
187
+ [![GitHub Sponsors](https://img.shields.io/badge/GitHub%20Sponsors-Donate-pink.svg)](https://github.com/sponsors/adilson889)
188
+ [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Donate-yellow.svg)](https://www.buymeacoffee.com/adilson889)
189
+
190
+ ---
191
+
192
+ ### License
193
+
194
+ MIT © Adilson C. Rafael
package/Terminal.js ADDED
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Terminal.js — feedback visual de "a pensar" para quando o BotQL corre
5
+ * num terminal Node.js puro (ex: bot ligado via Bootstrap.js, sem editor
6
+ * nenhum por perto).
7
+
8
+ */
9
+
10
+ const FRAMES = ['|', '/', '-', '\\'];
11
+ const INTERVALO_MS = 100;
12
+
13
+ function isNodeRuntime() {
14
+ return typeof process !== 'undefined' && !!process.versions && !!process.versions.node;
15
+ }
16
+
17
+ function isInteractiveTerminal() {
18
+ return isNodeRuntime() && !!process.stdout && !!process.stdout.isTTY;
19
+ }
20
+
21
+ /**
22
+ * Liga um spinner de terminal ao onThinking do interpretador, e um
23
+ * fallback de console.log a onReply/onForward/onSend — só para os que
24
+ * ainda não tiverem sido definidos.
25
+ *
26
+ * @param {import('./botql.js').BotQLInterpreter} interpreter
27
+ * @returns {() => void} função para desligar o spinner manualmente, se
28
+ * for preciso parar antes do bot terminar (raramente necessário).
29
+ */
30
+ function attachTerminalUI(interpreter) {
31
+ if (!isNodeRuntime()) {
32
+ // Browser/WebView: quem trata da UI é o próprio editor.
33
+ return () => {};
34
+ }
35
+
36
+ let timer = null;
37
+ let ativo = false;
38
+
39
+ function pararSpinner() {
40
+ if (!ativo) return;
41
+ ativo = false;
42
+ if (timer) clearInterval(timer);
43
+ if (isInteractiveTerminal()) {
44
+ process.stdout.write('\r\x1b[K'); // limpa a linha do spinner
45
+ }
46
+ }
47
+
48
+ if (!interpreter.onThinking) {
49
+ interpreter.onThinking = ({ text }) => {
50
+ const rotulo = text ? text + ' ' : '';
51
+
52
+ if (!isInteractiveTerminal()) {
53
+ // Não interativo (ex: saída redirecionada para ficheiro,
54
+ // ou executado em CI): uma linha só, sem animação.
55
+ console.log(rotulo.trim() || '...');
56
+ return;
57
+ }
58
+
59
+ ativo = true;
60
+ let frame = 0;
61
+ timer = setInterval(() => {
62
+ process.stdout.write('\r' + rotulo + FRAMES[frame]);
63
+ frame = (frame + 1) % FRAMES.length;
64
+ }, INTERVALO_MS);
65
+ };
66
+ }
67
+
68
+ // Sem isto o spinner nunca pararia sozinho — onReply/onForward/onSend
69
+ // são os eventos que sinalizam "o THINK/bloco terminou, já há resposta".
70
+ const envolverEPararSpinner = (onEvent) => async (payload) => {
71
+ pararSpinner();
72
+ if (onEvent) await onEvent(payload);
73
+ };
74
+
75
+ if (!interpreter.onReply) {
76
+ interpreter.onReply = envolverEPararSpinner(({ text }) => console.log(text));
77
+ } else {
78
+ interpreter.onReply = envolverEPararSpinner(interpreter.onReply);
79
+ }
80
+
81
+ if (!interpreter.onForward) {
82
+ interpreter.onForward = envolverEPararSpinner(({ target }) => console.log(`(encaminhado para ${target})`));
83
+ } else {
84
+ interpreter.onForward = envolverEPararSpinner(interpreter.onForward);
85
+ }
86
+
87
+ if (!interpreter.onSend) {
88
+ interpreter.onSend = envolverEPararSpinner(({ target, signal }) => console.log(`(enviado para ${target})`, signal));
89
+ } else {
90
+ interpreter.onSend = envolverEPararSpinner(interpreter.onSend);
91
+ }
92
+
93
+ return pararSpinner;
94
+ }
95
+
96
+ module.exports = { attachTerminalUI, isInteractiveTerminal, isNodeRuntime };