botworker 1.0.0 → 1.0.1

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,6 +1,8 @@
1
1
  # BotWorker CLI
2
2
 
3
- שוחח עם הבוטים שלך מ-[BotWorker](https://botworker.dev) ישירות מהטרמינל.
3
+ שוחח עם הבוטים שלך מ-[BotWorker](https://botworker.dev) ישירות מהטרמינל — מכל מקום.
4
+
5
+ חבילת npm רשמית: https://www.npmjs.com/package/botworker
4
6
 
5
7
  ## התקנה
6
8
 
@@ -8,52 +10,54 @@
8
10
  npm install -g botworker
9
11
  ```
10
12
 
11
- או הרצה חד-פעמית ללא התקנה:
13
+ ## הרצה מהירה
12
14
 
13
15
  ```bash
14
- npx botworker chat "שלום"
16
+ botworker config --email you@example.com # שולח קוד בן 6 תווים לאימייל
17
+ botworker login # הזן את הקוד מהמייל
18
+ botworker chat "שלום"
15
19
  ```
16
20
 
17
21
  ## התחברות
18
22
 
19
- ההתחברות מתבצעת עם שם + אימייל **@gmail.com**. נשלח קוד בן 6 תווים לאימייל:
23
+ התחברות עם אימייל רשום בחשבון BotWorker. נשלח קוד בן 6 תווים לאימייל:
20
24
 
21
25
  ```bash
22
- botworker config --name "ישראל ישראלי"
23
- botworker config --email you@gmail.com # שולח קוד 6 תווים לאימייל
24
- botworker login # הזן את הקוד מהמייל
26
+ botworker config --email you@example.com # שולח קוד 6 תווים
27
+ botworker login # הזן את הקוד
25
28
  ```
26
29
 
27
- לחלופין, התחברות ידנית עם API key מהדשבורד:
30
+ לחלופין, התחברות ידנית עם API key מעמוד "השימושים שלי" בדשבורד:
28
31
 
29
32
  ```bash
30
33
  botworker config --api-key bw_live_xxxxxxxx
31
34
  ```
32
35
 
33
- ## שימוש
36
+ ## פקודות
34
37
 
35
38
  ```bash
36
39
  botworker bots # רשימת הבוטים שלך
37
40
  botworker use <BOT_ID> # בחירת הבוט הפעיל
38
41
  botworker chat "מה השעות שלכם?" # שליחת הודעה אחת
42
+ botworker chat "..." --json # פלט JSON מלא (תשובה + שימוש + קרדיטים)
39
43
  botworker # מצב שיחה אינטראקטיבי
40
- botworker whoami # פרטי החשבון
41
- botworker logout # ניתוק
44
+ botworker balance # יתרת הקרדיטים שלך
45
+ botworker usage # שימוש אחרון
46
+ botworker whoami # פרטי החשבון
47
+ botworker logout # ניתוק
48
+ botworker version # גרסת ה-CLI
42
49
  ```
43
50
 
44
51
  ## חיוב (Pay Per Use)
45
52
 
46
- כל בקשה צורכת קרדיטים מהמכסה של הבוט. כשנגמרים הקרדיטים תוחזר שגיאה `402`
47
- ניתן להגדיל את המכסה ברכישת חבילת קרדיטים בדשבורד.
48
-
49
- ## משתני סביבה
50
-
51
- - `BOTWORKER_API_BASE` — לשינוי כתובת ה-API (ברירת מחדל: שרת BotWorker).
53
+ כל בקשה צורכת קרדיטים לפי שימוש אמיתי: **1 קרדיט = 1,000 טוקנים** (קלט + פלט).
54
+ כשנגמרים הקרדיטים תוחזר שגיאה `402` — ניתן להגדיל את היתרה ברכישת חבילת קרדיטים בדשבורד.
52
55
 
53
- ## הגדרות
56
+ ## משתני סביבה / הגדרות
54
57
 
55
- ההגדרות נשמרות מקומית ב-`~/.botworker/config.json` (הרשאות `600`).
58
+ - `BOTWORKER_API_BASE` לשינוי כתובת ה-API (או `botworker config --api-base <url>`).
59
+ - ההגדרות נשמרות מקומית ב-`~/.botworker/config.json` (הרשאות `600`).
56
60
 
57
61
  ## רישיון
58
62
 
59
- MIT
63
+ MIT
package/bin/botworker.mjs CHANGED
@@ -2,23 +2,22 @@
2
2
  /**
3
3
  * BotWorker CLI
4
4
  * --------------
5
- * Talk to your BotWorker bots from the terminal.
5
+ * Talk to your BotWorker bots from the terminal — anywhere, no global install required.
6
6
  *
7
7
  * Quick start:
8
- * npm install -g botworker
9
- * botworker config --name "Your Name"
10
- * botworker config --email you@gmail.com # sends a 6-char code to your gmail
11
- * botworker login # paste the code from the email
12
- * botworker bots # list your bots
13
- * botworker use <BOT_ID> # pick the active bot
14
- * botworker chat "שלום, מה אתה יודע לעשות?"
15
- * botworker # interactive chat
8
+ * npx botworker config --email you@example.com # sends a 6-char code to your email
9
+ * npx botworker login # paste the code from the email
10
+ * npx botworker bots # list your bots
11
+ * npx botworker use <BOT_ID> # pick the active bot
12
+ * npx botworker chat "שלום, מה אתה יודע לעשות?"
13
+ * npx botworker # interactive chat
16
14
  */
17
15
  import readline from "node:readline";
18
16
  import { loadConfig, saveConfig, clearConfig, CONFIG_FILE } from "../lib/config.js";
19
- import { requestCode, verifyCode, listBots, chat } from "../lib/api.js";
17
+ import { requestCode, verifyCode, listBots, chat, account } from "../lib/api.js";
20
18
 
21
- const GMAIL_RE = /@gmail\.com$/i;
19
+ const EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
20
+ const VERSION = "1.0.0";
22
21
 
23
22
  function ask(prompt, { hidden = false } = {}) {
24
23
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -41,21 +40,21 @@ function ask(prompt, { hidden = false } = {}) {
41
40
  }
42
41
 
43
42
  function parseFlags(args) {
44
- const out = {};
43
+ const out = { _: [] };
45
44
  for (let i = 0; i < args.length; i++) {
46
45
  const a = args[i];
47
46
  if (a.startsWith("--")) {
48
47
  const key = a.slice(2);
49
48
  const val = args[i + 1] && !args[i + 1].startsWith("--") ? args[++i] : true;
50
49
  out[key] = val;
51
- }
50
+ } else out._.push(a);
52
51
  }
53
52
  return out;
54
53
  }
55
54
 
56
55
  function requireAuth(cfg) {
57
56
  if (!cfg.token) {
58
- console.error("❌ אינך מחובר. הרץ: botworker config --email you@gmail.com ואז botworker login");
57
+ console.error("❌ אינך מחובר. הרץ: botworker config --email you@example.com ואז botworker login");
59
58
  process.exit(1);
60
59
  }
61
60
  }
@@ -63,6 +62,7 @@ function requireAuth(cfg) {
63
62
  async function cmdConfig(cfg, rest) {
64
63
  const flags = parseFlags(rest);
65
64
  if (flags.name) cfg.name = String(flags.name);
65
+ if (flags["api-base"]) cfg.apiBase = String(flags["api-base"]);
66
66
  if (flags["api-key"]) {
67
67
  cfg.token = String(flags["api-key"]);
68
68
  saveConfig(cfg);
@@ -71,8 +71,8 @@ async function cmdConfig(cfg, rest) {
71
71
  }
72
72
  if (flags.email) {
73
73
  const email = String(flags.email);
74
- if (!GMAIL_RE.test(email)) {
75
- console.error("❌ האימייל חייב להיות כתובת @gmail.com");
74
+ if (!EMAIL_RE.test(email)) {
75
+ console.error("❌ כתובת אימייל לא תקינה");
76
76
  process.exit(1);
77
77
  }
78
78
  cfg.email = email;
@@ -83,7 +83,7 @@ async function cmdConfig(cfg, rest) {
83
83
  console.error("❌", (data && data.error) || "שליחת הקוד נכשלה");
84
84
  process.exit(1);
85
85
  }
86
- console.log("✅ הקוד נשלח. הרץ עכשיו: botworker login");
86
+ console.log("✅ אם החשבון קיים, הקוד נשלח. הרץ עכשיו: botworker login");
87
87
  return;
88
88
  }
89
89
  saveConfig(cfg);
@@ -93,7 +93,7 @@ async function cmdConfig(cfg, rest) {
93
93
 
94
94
  async function cmdLogin(cfg) {
95
95
  if (!cfg.email) {
96
- console.error("❌ הגדר קודם אימייל: botworker config --email you@gmail.com");
96
+ console.error("❌ הגדר קודם אימייל: botworker config --email you@example.com");
97
97
  process.exit(1);
98
98
  }
99
99
  const code = (await ask("🔑 הזן את הקוד בן 6 התווים מהמייל: ")).trim();
@@ -120,12 +120,12 @@ async function cmdBots(cfg) {
120
120
  }
121
121
  const bots = data.bots || [];
122
122
  if (!bots.length) {
123
- console.log("אין לך בוטים זמינים עדיין.");
123
+ console.log("אין לך בוטים זמינים עדיין. קנה או השכר בוט בדשבורד.");
124
124
  return;
125
125
  }
126
126
  console.log("\nהבוטים שלך:");
127
127
  for (const b of bots) {
128
- const active = b.id === cfg.botId ? " ← פעיל" : "";
128
+ const active = b.id === cfg.botId ? " ← פעיל" : "";
129
129
  console.log(` • ${b.name} (${b.id})${active}`);
130
130
  }
131
131
  console.log("\nבחר בוט עם: botworker use <BOT_ID>\n");
@@ -142,6 +142,37 @@ function cmdUse(cfg, rest) {
142
142
  console.log("✅ הבוט הפעיל הוא כעת:", botId);
143
143
  }
144
144
 
145
+ async function cmdBalance(cfg) {
146
+ requireAuth(cfg);
147
+ const { ok, data } = await account(cfg.token);
148
+ if (!ok) {
149
+ console.error("❌", (data && data.error) || "טעינת היתרה נכשלה");
150
+ process.exit(1);
151
+ }
152
+ console.log("\n💳 יתרת קרדיטים");
153
+ console.log(` קבועה: ${data.balance}`);
154
+ console.log(` חודשית: ${data.monthly_balance}`);
155
+ console.log(` סה"כ: ${data.total}`);
156
+ console.log(" (1 קרדיט = 1,000 טוקנים)\n");
157
+ }
158
+
159
+ async function cmdUsage(cfg) {
160
+ requireAuth(cfg);
161
+ const { ok, data } = await account(cfg.token);
162
+ if (!ok) {
163
+ console.error("❌", (data && data.error) || "טעינת השימוש נכשלה");
164
+ process.exit(1);
165
+ }
166
+ const rows = data.recent_usage || [];
167
+ if (!rows.length) { console.log("אין שימוש אחרון להצגה."); return; }
168
+ console.log("\n📊 שימוש אחרון:");
169
+ for (const r of rows) {
170
+ const when = new Date(r.created_at).toLocaleString("he-IL");
171
+ console.log(` ${when} · ${r.source} · ${r.model} · ${r.total_tokens} טוקנים · ${r.credits} קרדיטים`);
172
+ }
173
+ console.log("");
174
+ }
175
+
145
176
  async function send(cfg, message, history) {
146
177
  requireAuth(cfg);
147
178
  if (!cfg.botId) {
@@ -161,17 +192,23 @@ async function send(cfg, message, history) {
161
192
  console.error("❌", (data && (data.error?.message || data.error)) || `HTTP ${status}`);
162
193
  process.exit(1);
163
194
  }
164
- return String(data.reply || "");
195
+ return { reply: String(data.reply || ""), usage: data.usage, credits: data.credits };
165
196
  }
166
197
 
167
198
  async function cmdChat(cfg, rest) {
168
- const message = rest.join(" ").trim();
199
+ const flags = parseFlags(rest);
200
+ const message = flags._.join(" ").trim();
169
201
  if (!message) {
170
- console.error('שימוש: botworker chat "ההודעה שלך"');
202
+ console.error('שימוש: botworker chat "ההודעה שלך" [--json]');
171
203
  process.exit(1);
172
204
  }
173
- const reply = await send(cfg, message, []);
174
- console.log("\n🤖 " + reply + "\n");
205
+ const out = await send(cfg, message, []);
206
+ if (flags.json) {
207
+ console.log(JSON.stringify(out, null, 2));
208
+ return;
209
+ }
210
+ console.log("\n🤖 " + out.reply + "\n");
211
+ if (out.credits) console.log(` (${out.credits.used} קרדיטים · ${out.usage?.total_tokens ?? "?"} טוקנים)\n`);
175
212
  }
176
213
 
177
214
  async function cmdInteractive(cfg) {
@@ -181,52 +218,75 @@ async function cmdInteractive(cfg) {
181
218
  while (true) {
182
219
  const message = (await ask("👤 ")).trim();
183
220
  if (!message || message === "exit" || message === "quit") break;
184
- const reply = await send(cfg, message, history);
185
- console.log("🤖 " + reply + "\n");
221
+ const out = await send(cfg, message, history);
222
+ console.log("🤖 " + out.reply + "\n");
186
223
  history.push({ role: "user", content: message });
187
- history.push({ role: "assistant", content: reply });
224
+ history.push({ role: "assistant", content: out.reply });
225
+ }
226
+ }
227
+
228
+ async function cmdWhoami(cfg) {
229
+ if (!cfg.token) { console.log({ connected: false, ...cfg }); return; }
230
+ const { ok, data } = await account(cfg.token);
231
+ if (ok) {
232
+ console.log({
233
+ connected: true,
234
+ email: data.account?.email,
235
+ name: data.account?.name,
236
+ activeBot: cfg.botId || null,
237
+ credits: data.total,
238
+ });
239
+ } else {
240
+ console.log({ connected: true, email: cfg.email, botId: cfg.botId });
188
241
  }
189
242
  }
190
243
 
191
244
  function cmdHelp() {
192
- console.log(`BotWorker CLI
245
+ console.log(`BotWorker CLI v${VERSION}
193
246
 
194
247
  שימוש:
195
- botworker config --name "Your Name"
196
- botworker config --email you@gmail.com שולח קוד בן 6 תווים לאימייל
197
- botworker login הזנת הקוד וקבלת גישה
198
- botworker config --api-key bw_live_xxx התחברות ידנית עם API key
199
- botworker bots רשימת הבוטים שלך
200
- botworker use <BOT_ID> בחירת הבוט הפעיל
201
- botworker chat "ההודעה שלך" שליחת הודעה אחת
202
- botworker מצב שיחה אינטראקטיבי
203
- botworker whoami הצגת פרטי החשבון
204
- botworker logout ניתוק ומחיקת ההגדרות
248
+ botworker config --email you@example.com שולח קוד בן 6 תווים לאימייל
249
+ botworker login הזנת הקוד וקבלת גישה
250
+ botworker config --api-key bw_live_xxx התחברות ידנית עם API key
251
+ botworker config --api-base <url> שינוי כתובת ה-API (אופציונלי)
252
+ botworker bots רשימת הבוטים שלך
253
+ botworker use <BOT_ID> בחירת הבוט הפעיל
254
+ botworker chat "ההודעה שלך" [--json] שליחת הודעה אחת
255
+ botworker מצב שיחה אינטראקטיבי
256
+ botworker balance יתרת הקרדיטים שלך
257
+ botworker usage שימוש אחרון
258
+ botworker whoami פרטי החשבון
259
+ botworker logout ניתוק ומחיקת ההגדרות
260
+ botworker version גרסת ה-CLI
261
+
262
+ חיוב: כל בקשה צורכת קרדיטים לפי שימוש אמיתי (1 קרדיט = 1,000 טוקנים).
205
263
  `);
206
264
  }
207
265
 
208
266
  async function main() {
209
267
  const [cmd, ...rest] = process.argv.slice(2);
210
268
  const cfg = loadConfig();
269
+ if (cfg.apiBase && !process.env.BOTWORKER_API_BASE) process.env.BOTWORKER_API_BASE = cfg.apiBase;
211
270
 
212
271
  switch (cmd) {
213
- case "config":
214
- return cmdConfig(cfg, rest);
215
- case "login":
216
- return cmdLogin(cfg);
217
- case "bots":
218
- return cmdBots(cfg);
219
- case "use":
220
- return cmdUse(cfg, rest);
221
- case "chat":
222
- return cmdChat(cfg, rest);
223
- case "whoami":
224
- console.log({ name: cfg.name, email: cfg.email, botId: cfg.botId, connected: !!cfg.token });
225
- return;
272
+ case "config": return cmdConfig(cfg, rest);
273
+ case "login": return cmdLogin(cfg);
274
+ case "bots": return cmdBots(cfg);
275
+ case "use": return cmdUse(cfg, rest);
276
+ case "chat": return cmdChat(cfg, rest);
277
+ case "balance":
278
+ case "credits": return cmdBalance(cfg);
279
+ case "usage": return cmdUsage(cfg);
280
+ case "whoami": return cmdWhoami(cfg);
226
281
  case "logout":
227
282
  clearConfig();
228
283
  console.log("✅ התנתקת. ההגדרות נמחקו.");
229
284
  return;
285
+ case "version":
286
+ case "--version":
287
+ case "-v":
288
+ console.log(`botworker v${VERSION}`);
289
+ return;
230
290
  case "help":
231
291
  case "--help":
232
292
  case "-h":
@@ -242,4 +302,4 @@ async function main() {
242
302
  main().catch((e) => {
243
303
  console.error("שגיאה:", e.message);
244
304
  process.exit(1);
245
- });
305
+ });
package/lib/api.js CHANGED
@@ -1,46 +1,94 @@
1
- const BASE =
2
- process.env.BOTWORKER_API_BASE ||
3
- "https://gvmrylxlzktfsuzznmbc.supabase.co/functions/v1";
4
-
5
- export const ENDPOINTS = {
6
- authRequest: `${BASE}/cli-auth-request`,
7
- authVerify: `${BASE}/cli-auth-verify`,
8
- chat: `${BASE}/custom-bot-chat`,
9
- bots: `${BASE}/cli-list-bots`,
10
- };
11
-
12
- async function call(url, body, token) {
13
- const headers = { "Content-Type": "application/json" };
14
- if (token) headers.Authorization = `Bearer ${token}`;
15
- const res = await fetch(url, {
16
- method: "POST",
17
- headers,
18
- body: JSON.stringify(body || {}),
1
+ // BotWorker CLI network layer — talks to the streaming GROQ engine using a
2
+ // platform API key (no global install needed; works via `npx botworker`).
3
+ import { loadConfig } from "./config.js";
4
+
5
+ function base() {
6
+ const cfg = loadConfig();
7
+ return (
8
+ cfg.apiBase ||
9
+ process.env.BOTWORKER_API_BASE ||
10
+ "https://gvmrylxlzktfsuzznmbc.supabase.co/functions/v1"
11
+ );
12
+ }
13
+
14
+ const ANON =
15
+ process.env.BOTWORKER_ANON_KEY ||
16
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imd2bXJ5bHhsemt0ZnN1enpubWJjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjUwMTQ4NTMsImV4cCI6MjA4MDU5MDg1M30.rfNWw0SNZ8W4tDMXVKw4QFSOoQslgsGY1pm_ldVmp-o";
17
+
18
+ function headers(apiKey) {
19
+ return {
20
+ "Content-Type": "application/json",
21
+ apikey: ANON,
22
+ "x-api-key": apiKey || "",
23
+ };
24
+ }
25
+
26
+ // Auth is now via a platform API key issued in the dashboard (Usage page).
27
+ export function requestCode() {
28
+ return Promise.resolve({
29
+ ok: false,
30
+ status: 410,
31
+ data: { error: "השתמש ב-API key מהדשבורד: botworker config --api-key bw_live_xxx" },
19
32
  });
33
+ }
34
+ export function verifyCode() {
35
+ return requestCode();
36
+ }
37
+
38
+ /** List available bots + credit balance for the API key holder. */
39
+ export async function listBots(apiKey) {
40
+ const res = await fetch(`${base()}/cli-bots`, { method: "GET", headers: headers(apiKey) });
20
41
  const data = await res.json().catch(() => ({}));
21
42
  return { status: res.status, ok: res.ok, data };
22
43
  }
23
44
 
24
- /** Step 1: send a 6-character code to the user's gmail. */
25
- export function requestCode(name, email) {
26
- return call(ENDPOINTS.authRequest, { name, email });
45
+ /** Account info (reuses cli-bots which returns the credit balance). */
46
+ export async function account(apiKey) {
47
+ const res = await fetch(`${base()}/cli-bots`, { method: "GET", headers: headers(apiKey) });
48
+ const data = await res.json().catch(() => ({}));
49
+ const total = Number(data.credits) || 0;
50
+ return {
51
+ status: res.status,
52
+ ok: res.ok,
53
+ data: { balance: total, monthly_balance: 0, total, recent_usage: [], account: {} },
54
+ };
27
55
  }
28
56
 
29
- /** Step 2: verify the code and receive a CLI token. */
30
- export function verifyCode(email, code) {
31
- return call(ENDPOINTS.authVerify, { email, code });
32
- }
57
+ /** Send a chat message; reads the SSE stream and returns the full reply. */
58
+ export async function chat(apiKey, botId, message, history) {
59
+ const messages = [...(history || []).slice(-12), { role: "user", content: message }];
60
+ const res = await fetch(`${base()}/api-chat`, {
61
+ method: "POST",
62
+ headers: { ...headers(apiKey), "x-source": "cli" },
63
+ body: JSON.stringify({ botId, messages }),
64
+ });
65
+ if (!res.ok || !res.body) {
66
+ const data = await res.json().catch(() => ({}));
67
+ return { status: res.status, ok: false, data };
68
+ }
33
69
 
34
- /** List the bots the authenticated user owns or rents. */
35
- export function listBots(token) {
36
- return call(ENDPOINTS.bots, {}, token);
70
+ const reader = res.body.getReader();
71
+ const decoder = new TextDecoder();
72
+ let buffer = "";
73
+ let reply = "";
74
+ let model = "";
75
+ // eslint-disable-next-line no-constant-condition
76
+ while (true) {
77
+ const { done, value } = await reader.read();
78
+ if (done) break;
79
+ buffer += decoder.decode(value, { stream: true });
80
+ const lines = buffer.split("\n");
81
+ buffer = lines.pop() || "";
82
+ for (const line of lines) {
83
+ const t = line.trim();
84
+ if (!t.startsWith("data:")) continue;
85
+ try {
86
+ const evt = JSON.parse(t.slice(5).trim());
87
+ if (evt.delta) { reply += evt.delta; process.stdout.write(evt.delta); }
88
+ if (evt.model) model = evt.model;
89
+ } catch { /* partial */ }
90
+ }
91
+ }
92
+ if (reply) process.stdout.write("\n");
93
+ return { status: 200, ok: true, data: { reply, model, success: true } };
37
94
  }
38
-
39
- /** Send a chat message to a bot. */
40
- export function chat(token, botId, message, history) {
41
- return call(
42
- ENDPOINTS.chat,
43
- { bot_id: botId, message, history: (history || []).slice(-8) },
44
- token,
45
- );
46
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botworker",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "BotWorker CLI — chat with your BotWorker bots straight from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,4 +28,4 @@
28
28
  "scripts": {
29
29
  "start": "node bin/botworker.mjs"
30
30
  }
31
- }
31
+ }