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/Database.js +1 -146
- package/LICENSE +30 -10
- package/Parser.js +2 -759
- package/RAG.js +1 -572
- package/README.md +183 -12
- package/Terminal.js +96 -0
- package/botql.browser.js +686 -1550
- package/botql.js +4 -786
- package/createBot.js +88 -0
- package/package.json +3 -2
- package/Bootstrap.js +0 -74
package/README.md
CHANGED
|
@@ -1,23 +1,194 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
39
|
+
## Getting Started
|
|
17
40
|
|
|
18
|
-
|
|
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
|
-
|
|
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
|
+
[](https://github.com/sponsors/adilson889)
|
|
188
|
+
[](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 };
|