nothumanallowed 9.2.3 → 9.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.
package/README.md CHANGED
@@ -1,8 +1,12 @@
1
- # NotHumanAllowed
1
+ # NotHumanAllowed (v9.3)
2
2
 
3
- **Your agents. Your machine. Your rules.**
3
+ **Tell the AI what you need. It does it.**
4
4
 
5
- 38 specialized AI agents + 50 productivity tools + web search. Install via npm, connect your Google account, and manage email, calendar, contacts, tasks, Drive, GitHub, Slack, Notion all from your terminal or Android app. Streaming responses, multi-conversation history, export. 100% local. Zero data on our servers.
5
+ Your AI assistant for email, calendar, web search, files, and everything else. Type what you want in plain language NHA handles it. Read emails, schedule meetings, search the web, manage tasks, analyze documents, browse Google Drive, check GitHub, Slack, Notion all from one place.
6
+
7
+ 38 AI agents. 58 tools. Web search built in. Streaming chat. Multiple conversations with history and export. Browser automation. Voice chat. Available on **PC, Mac, Linux, and Android**.
8
+
9
+ 100% private — your data never leaves your machine. Zero data on our servers. Free and open source.
6
10
 
7
11
  ## Install
8
12
 
@@ -22,13 +26,13 @@ nha config set key sk-ant-api03-YOUR_KEY
22
26
  # Connect Google (Gmail, Calendar, Drive, Contacts, Tasks)
23
27
  nha google auth
24
28
 
25
- # Start chatting — 50 tools available
29
+ # Start chatting — 58 tools available
26
30
  nha chat
27
31
  ```
28
32
 
29
33
  ## What You Can Do
30
34
 
31
- ### Chat with 50 Tools + Web Search
35
+ ### Chat with 58 Tools + Web Search + Browser
32
36
 
33
37
  ```bash
34
38
  nha chat
@@ -58,7 +62,34 @@ NHA: Available 60-min slots:
58
62
  3. Wed Apr 9, 02:00 PM - 04:00 PM
59
63
  ```
60
64
 
61
- ### 50 Tools
65
+ ### Browser Automation (Zero Dependencies)
66
+
67
+ ```bash
68
+ nha browse open https://example.com # Open page in headless Chrome
69
+ nha browse screenshot # Capture screenshot
70
+ nha browse extract "h1" # Extract content by CSS selector
71
+ nha browse js "document.title" # Execute JavaScript
72
+ nha browse close # Close browser
73
+ ```
74
+
75
+ Control Chrome headless via the Chrome DevTools Protocol — no Puppeteer, no Playwright, no npm dependencies. Pure WebSocket CDP client built from scratch.
76
+
77
+ All browser tools are also available in `nha chat` and `nha ui`:
78
+
79
+ ```
80
+ You: Open google.com and search for "NHA AI agents"
81
+ NHA: [Browser: google.com] Page loaded: "Google"
82
+ [Typed: NHA AI agents] into search field
83
+ [Key: Enter] submitted search
84
+ [Extracted: results] Found 10 results...
85
+
86
+ You: Take a screenshot
87
+ NHA: [Screenshot] Captured and saved to ~/nha-screenshot.png
88
+ ```
89
+
90
+ 10 browser tools: `browser_open`, `browser_screenshot`, `browser_click`, `browser_type`, `browser_extract`, `browser_js`, `browser_wait`, `browser_scroll`, `browser_key`, `browser_close`. SSRF-protected — blocks localhost and private IPs.
91
+
92
+ ### 58 Tools
62
93
 
63
94
  | Category | Tools |
64
95
  |----------|-------|
@@ -71,6 +102,7 @@ NHA: Available 60-min slots:
71
102
  | **Slack** | List channels, read messages, send messages |
72
103
  | **Notion** | Search pages/databases, read page content |
73
104
  | **Web** | Web search (DuckDuckGo), fetch URL content, deep search with page extraction |
105
+ | **Browser** | Open pages, screenshot, click, type, extract text/HTML, execute JS, wait for elements, scroll, keyboard input, close |
74
106
  | **Other** | Maps directions, reminders, file reading |
75
107
 
76
108
  Every tool is called directly from your machine to the provider's API. NHA servers are never involved.
@@ -105,7 +137,7 @@ nha ask jarvis "Build a REST API for user management"
105
137
  nha voice
106
138
  ```
107
139
 
108
- Same 50 tools, spoken responses. Opens a local web UI with speech recognition.
140
+ Same 58 tools, spoken responses. Opens a local web UI with speech recognition.
109
141
 
110
142
  ### Background Daemon
111
143
 
@@ -185,19 +217,21 @@ Runs in the background. Alerts you before meetings, monitors email, auto-respond
185
217
 
186
218
  Run `nha agents` to see all 38 with capabilities.
187
219
 
188
- ## Android App
220
+ ## Android App (v1.2)
189
221
 
190
- NHA is also available as an Android app with the same 50 tools:
222
+ Download: [nothumanallowed.com/NHAapp-1.2.apk](https://nothumanallowed.com/NHAapp-1.2.apk)
191
223
 
192
- - Chat with all tools (email, calendar, tasks, contacts, Drive)
193
- - 38 agents accessible from a grid
194
- - Week calendar with event creation
195
- - Gmail inbox with caching
196
- - Notes, tasks, birthdays, smart scheduler
197
- - Google Drive browser
198
- - GitHub, Slack, Notion integration
199
- - Voice chat with text-to-speech
200
- - Daily plan generator
224
+ Everything the CLI does, on your phone:
225
+
226
+ - **Streaming chat** see words appear as the AI thinks
227
+ - **Web search** search the internet and read any webpage, right from chat
228
+ - **Multiple conversations** — save, switch, export your chats
229
+ - **58 tools** — email, calendar, tasks, contacts, Drive, GitHub, Slack, Notion, browser
230
+ - **38 agents** — tap any agent, ask anything
231
+ - **Voice chat** talk instead of typing, in 6 languages
232
+ - **Daily plan** — AI analyzes your emails + calendar every morning
233
+ - **Files & images** — attach PDFs, photos, documents for analysis
234
+ - **Tool indicators** — see "Searching the web...", "Reading email..." in real time
201
235
 
202
236
  All API calls go directly from your phone to providers. Zero data through NHA servers.
203
237
 
@@ -217,7 +251,7 @@ All API calls go directly from your phone to providers. Zero data through NHA se
217
251
  Your Machine Provider APIs
218
252
  ┌──────────────────┐ ┌─────────────────────┐
219
253
  │ 38 agents │────→│ Google (Gmail, Cal, │
220
- 50 tools │ │ Drive, Contacts) │
254
+ 58 tools │ │ Drive, Contacts) │
221
255
  │ Your API keys │────→│ Your LLM provider │
222
256
  │ Your data │────→│ GitHub, Slack, Notion│
223
257
  │ (encrypted) │ └─────────────────────┘
@@ -250,6 +284,13 @@ Inside `nha chat`, use slash commands:
250
284
  /clear Clear current conversation
251
285
  /help Show all commands
252
286
  /quit Exit
287
+
288
+ # Browser (in chat)
289
+ "Open example.com" → browser_open
290
+ "Take a screenshot" → browser_screenshot
291
+ "Click the submit button" → browser_click
292
+ "Type hello in the search" → browser_type
293
+ "Extract all links" → browser_extract
253
294
  ```
254
295
 
255
296
  Inline agent routing: `@saber audit this function for SQL injection`
@@ -257,7 +298,7 @@ Inline agent routing: `@saber audit this function for SQL injection`
257
298
  ## Commands
258
299
 
259
300
  ```bash
260
- # Chat (50 tools + web search, streaming)
301
+ # Chat (58 tools + web search, streaming)
261
302
  nha chat # Interactive chat with tools
262
303
  nha voice # Voice chat with TTS
263
304
 
@@ -275,6 +316,13 @@ nha ops start # Background daemon
275
316
  # Google
276
317
  nha google auth # Connect Google account
277
318
 
319
+ # Browser
320
+ nha browse open <url> # Open in headless Chrome
321
+ nha browse screenshot # Save screenshot to ~/
322
+ nha browse extract "selector" # Extract text by CSS selector
323
+ nha browse js "code" # Execute JavaScript
324
+ nha browse close # Close browser
325
+
278
326
  # Config
279
327
  nha config # Show settings
280
328
  nha config set provider anthropic # Set LLM provider
@@ -284,12 +332,39 @@ nha doctor # Health check
284
332
  nha mcp # Start MCP server
285
333
  ```
286
334
 
335
+ ## Web Dashboard
336
+
337
+ ```bash
338
+ nha ui
339
+ ```
340
+
341
+ Opens a local web dashboard on `localhost:3847` with streaming chat, multi-conversation, email, calendar, tasks, contacts, drive, agents, notes, settings — all in your browser. Zero framework, pure HTML/CSS/JS. Screenshots from browser automation appear inline in the chat.
342
+
343
+ ## NHA vs OpenClaw
344
+
345
+ NHA was built after the [OpenClaw/Moltbook security breach](https://nothumanallowed.com/vs-openclaw) — 7 CVEs, 1.49M leaked records, 1.5M exposed API keys. See the [full comparison](https://nothumanallowed.com/vs-openclaw).
346
+
347
+ | | OpenClaw | NHA |
348
+ |---|---|---|
349
+ | Security | 7 CVEs, no WAF | SENTINEL WAF (Rust), 0 CVEs |
350
+ | Agents | 1 generic | 38 specialists |
351
+ | Tools | Install from hub | 58 built-in + web search + browser automation |
352
+ | Knowledge | None | 2.6M facts from 16 datasets |
353
+ | Daily Plan | None | 5-agent analysis |
354
+ | Browser | Chrome instance (heavy, attack surface) | Custom CDP engine, zero deps, SSRF-protected |
355
+ | Dependencies | Electron + Chrome | Zero |
356
+ | Privacy | Moltbook leaked 1.49M records | Zero data on our servers |
357
+
287
358
  ## Links
288
359
 
289
360
  - [Website](https://nothumanallowed.com)
290
361
  - [Documentation](https://nothumanallowed.com/docs/cli)
362
+ - [Android App](https://nothumanallowed.com/NHAapp-1.2.apk)
363
+ - [NHA vs OpenClaw](https://nothumanallowed.com/vs-openclaw)
364
+ - [Agents Guide](https://nothumanallowed.com/docs/agents)
365
+ - [Mobile Docs](https://nothumanallowed.com/docs/mobile)
366
+ - [GitHub](https://github.com/adoslabsproject-gif/nothumanallowed)
291
367
  - [Privacy Policy](https://nothumanallowed.com/privacy)
292
- - [Terms of Service](https://nothumanallowed.com/terms)
293
368
 
294
369
  ## License
295
370
 
package/bin/nha.mjs CHANGED
@@ -1,3 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { main } from '../src/cli.mjs';
3
- main(process.argv.slice(2));
2
+ import { main, showUiTipOnce } from '../src/cli.mjs';
3
+ const cmd = process.argv[2] || 'help';
4
+ await main(process.argv.slice(2));
5
+ showUiTipOnce(cmd);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "9.2.3",
4
- "description": "NotHumanAllowed — 38 AI agents + 50 tools + web search. Streaming chat, multi-conversation, export. Gmail, Calendar, Drive, GitHub, Notion, Slack. Zero-dependency CLI.",
3
+ "version": "9.3.0",
4
+ "description": "NotHumanAllowed — 38 AI agents + 58 tools + browser automation + web search. Streaming chat, headless Chrome CDP, multi-conversation, export. Gmail, Calendar, Drive, GitHub, Notion, Slack. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "nha": "./bin/nha.mjs",
package/src/cli.mjs CHANGED
@@ -22,6 +22,22 @@ import { cmdVoice } from './commands/voice.mjs';
22
22
  import { cmdPlugin, findPluginForCommand } from './commands/plugin.mjs';
23
23
  import { banner, info, ok, warn, fail, C, G, Y, D, W, BOLD, NC, M, B, R } from './ui.mjs';
24
24
 
25
+ // Show web UI tip once after first real command
26
+ export function showUiTipOnce(cmd) {
27
+ const skipCmds = ['ui', 'help', 'version', 'setup', 'update', 'config', 'doctor', '--help', '-h'];
28
+ if (skipCmds.includes(cmd)) return;
29
+ try {
30
+ const marker = path.join(NHA_DIR, '.ui-tip-shown');
31
+ if (fs.existsSync(marker)) return;
32
+ console.log('');
33
+ console.log(` ${G}Tip:${NC} Run ${C}nha ui${NC} to open the full web dashboard in your browser.`);
34
+ console.log(` Use ${C}nha ui --lan${NC} to access it from your phone or tablet on the same Wi-Fi.`);
35
+ console.log(` ${D}Docs: https://nothumanallowed.com/docs/web-dashboard${NC}`);
36
+ fs.mkdirSync(NHA_DIR, { recursive: true });
37
+ fs.writeFileSync(marker, new Date().toISOString());
38
+ } catch {}
39
+ }
40
+
25
41
  export async function main(argv) {
26
42
  const cmd = argv[0] || 'help';
27
43
  const args = argv.slice(1);
@@ -112,6 +128,10 @@ export async function main(argv) {
112
128
  case 'voice':
113
129
  return cmdVoice(args);
114
130
 
131
+ case 'browse':
132
+ case 'browser':
133
+ return cmdBrowse(args);
134
+
115
135
  case 'plugin':
116
136
  case 'plugins':
117
137
  return cmdPlugin(args);
@@ -161,6 +181,7 @@ export async function main(argv) {
161
181
  return spawnCore('legion', [cmd, ...args]);
162
182
  }
163
183
  }
184
+
164
185
  }
165
186
 
166
187
  // ── nha responder ─────────────────────────────────────────────────────────
@@ -230,6 +251,111 @@ async function cmdResponder(args) {
230
251
  }
231
252
  }
232
253
 
254
+ // ── nha browse ────────────────────────────────────────────────────────────
255
+ async function cmdBrowse(args) {
256
+ const sub = args[0];
257
+
258
+ if (sub === 'open' && args[1]) {
259
+ const { browserOpen, browserInfo } = await import('./services/browser-engine.mjs');
260
+ info(`Opening ${args[1]}...`);
261
+ const result = await browserOpen(args[1]);
262
+ if (result.error) {
263
+ fail(result.message);
264
+ process.exit(1);
265
+ }
266
+ ok(`${result.title}`);
267
+ info(`URL: ${result.url}`);
268
+
269
+ // If there are more args, execute them as a sequence
270
+ if (args.length <= 2) {
271
+ info('Browser is running. Use "nha browse screenshot", "nha browse extract", etc.');
272
+ info('Or use "nha chat" — browser tools are available in chat.');
273
+ }
274
+ return;
275
+ }
276
+
277
+ if (sub === 'screenshot') {
278
+ const { browserScreenshot, isBrowserRunning } = await import('./services/browser-engine.mjs');
279
+ if (!isBrowserRunning()) {
280
+ fail('No browser open. Run: nha browse open <url>');
281
+ process.exit(1);
282
+ }
283
+ const saveTo = args[1] || path.join(os.homedir(), `nha-screenshot-${Date.now()}.png`);
284
+ info('Capturing screenshot...');
285
+ const result = await browserScreenshot({ saveTo });
286
+ if (result.error) {
287
+ fail(result.message);
288
+ process.exit(1);
289
+ }
290
+ ok(`Screenshot saved: ${result.savedTo}`);
291
+ return;
292
+ }
293
+
294
+ if (sub === 'extract') {
295
+ const { browserExtract, isBrowserRunning } = await import('./services/browser-engine.mjs');
296
+ if (!isBrowserRunning()) {
297
+ fail('No browser open. Run: nha browse open <url>');
298
+ process.exit(1);
299
+ }
300
+ const selector = args[1] || 'body';
301
+ const result = await browserExtract({ selector, mode: 'text' });
302
+ if (result.error) {
303
+ fail(result.message);
304
+ process.exit(1);
305
+ }
306
+ console.log(result.content);
307
+ return;
308
+ }
309
+
310
+ if (sub === 'js' && args[1]) {
311
+ const { browserEval, isBrowserRunning } = await import('./services/browser-engine.mjs');
312
+ if (!isBrowserRunning()) {
313
+ fail('No browser open. Run: nha browse open <url>');
314
+ process.exit(1);
315
+ }
316
+ const code = args.slice(1).join(' ');
317
+ const result = await browserEval(code);
318
+ if (result.error) {
319
+ fail(result.message);
320
+ process.exit(1);
321
+ }
322
+ console.log(result.result);
323
+ return;
324
+ }
325
+
326
+ if (sub === 'close') {
327
+ const { browserClose } = await import('./services/browser-engine.mjs');
328
+ const result = await browserClose();
329
+ ok(result.message);
330
+ return;
331
+ }
332
+
333
+ // Help
334
+ console.log(`
335
+ ${BOLD}${C}NHA Browser${NC} ${D}— Headless Chrome automation${NC}
336
+
337
+ ${C}Usage:${NC}
338
+ nha browse open <url> Open a page in headless Chrome
339
+ nha browse screenshot Save screenshot to ~/
340
+ nha browse screenshot out.png Save to specific path
341
+ nha browse extract Extract all text from page
342
+ nha browse extract "h1" Extract text from CSS selector
343
+ nha browse js "code" Execute JavaScript in page
344
+ nha browse close Close the browser
345
+
346
+ ${C}In Chat:${NC} All browser tools are available in ${W}nha chat${NC}:
347
+ "Open google.com and search for NHA"
348
+ "Take a screenshot of the page"
349
+ "Click the submit button"
350
+ "Fill the email field with test@example.com"
351
+ "Extract all links from the page"
352
+
353
+ ${D}Requires Chrome or Chromium installed. Set CHROME_PATH to override.${NC}
354
+ ${D}SSRF-protected — blocks localhost and private IPs.${NC}
355
+ ${D}Zero npm dependencies — pure CDP WebSocket.${NC}
356
+ `);
357
+ }
358
+
233
359
  // ── nha run ────────────────────────────────────────────────────────────────
234
360
  async function cmdRun(args) {
235
361
  if (args.length === 0) {
@@ -551,8 +677,17 @@ function cmdHelp() {
551
677
  console.log(` run "prompt" Multi-agent collaboration (server-routed)`);
552
678
  console.log(` run "prompt" ${D}--agents saber,zero${NC} Collaborate with specific agents\n`);
553
679
 
680
+ console.log(` ${C}Browser Automation${NC} ${D}(headless Chrome, zero dependencies)${NC}`);
681
+ console.log(` browse open <url> Open page in headless Chrome (CDP)`);
682
+ console.log(` browse screenshot Capture screenshot to file`);
683
+ console.log(` browse extract Extract page text (CSS selector)`);
684
+ console.log(` browse js "code" Execute JavaScript in page`);
685
+ console.log(` browse close Close browser`);
686
+ console.log(` ${D}Also available as tools in nha chat (browser_open, browser_click, etc.)${NC}\n`);
687
+
554
688
  console.log(` ${C}Daily Operations${NC} ${D}(Gmail + Calendar + Tasks)${NC}`);
555
- console.log(` ui Open local web dashboard (http://127.0.0.1:3847)`);
689
+ console.log(` ui Open local web dashboard (http://localhost:3847)`);
690
+ console.log(` ui --lan Access from phone/tablet on the same Wi-Fi`);
556
691
  console.log(` ui --port=4000 Custom port ui --no-browser Don't auto-open`);
557
692
  console.log(` chat Interactive chat — manage email/calendar/tasks naturally`);
558
693
  console.log(` voice Voice-powered chat (opens browser with mic interface)`);
@@ -22,7 +22,7 @@ import { AGENTS_DIR, AGENTS } from '../constants.mjs';
22
22
  import { callLLMStream, parseAgentFile } from '../services/llm.mjs';
23
23
 
24
24
  import { extractMemory } from '../services/memory.mjs';
25
- import { fail, info, ok, warn, C, G, Y, D, W, BOLD, NC, R } from '../ui.mjs';
25
+ import { fail, info, ok, warn, C, G, Y, D, W, BOLD, NC, R, M } from '../ui.mjs';
26
26
  import {
27
27
  DESTRUCTIVE_ACTIONS,
28
28
  parseActions,
@@ -433,6 +433,26 @@ function formatToolLabel(action, params) {
433
433
  return `Searching the web for "${params.query || '...'}"...`;
434
434
  case 'fetch_url':
435
435
  return `Fetching ${params.url || 'URL'}...`;
436
+ case 'browser_open':
437
+ return `Opening ${params.url || 'page'} in browser...`;
438
+ case 'browser_screenshot':
439
+ return `Taking screenshot...`;
440
+ case 'browser_click':
441
+ return `Clicking ${params.selector || `(${params.x}, ${params.y})`}...`;
442
+ case 'browser_type':
443
+ return `Typing into ${params.selector || 'field'}...`;
444
+ case 'browser_extract':
445
+ return `Extracting content from ${params.selector || 'page'}...`;
446
+ case 'browser_js':
447
+ return `Executing JavaScript...`;
448
+ case 'browser_wait':
449
+ return `Waiting for ${params.selector || 'element'}...`;
450
+ case 'browser_scroll':
451
+ return `Scrolling ${params.direction || 'down'}...`;
452
+ case 'browser_key':
453
+ return `Pressing ${params.key || 'key'}...`;
454
+ case 'browser_close':
455
+ return `Closing browser...`;
436
456
  case 'gmail_list':
437
457
  return `Searching emails...`;
438
458
  case 'gmail_read':
@@ -476,6 +496,28 @@ function formatToolResult(action, params, result) {
476
496
  const domain = (params.url || '').replace(/^https?:\/\//, '').split('/')[0];
477
497
  return `${C}[Fetched: ${domain}]${NC}`;
478
498
  }
499
+ case 'browser_open': {
500
+ const domain = (params.url || '').replace(/^https?:\/\//, '').split('/')[0];
501
+ return `${M}[Browser: ${domain}]${NC}`;
502
+ }
503
+ case 'browser_screenshot':
504
+ return `${M}[Screenshot]${NC}`;
505
+ case 'browser_click':
506
+ return `${M}[Click: ${params.selector || `(${params.x}, ${params.y})`}]${NC}`;
507
+ case 'browser_type':
508
+ return `${M}[Typed: ${(params.text || '').slice(0, 30)}${(params.text || '').length > 30 ? '...' : ''}]${NC}`;
509
+ case 'browser_extract':
510
+ return `${M}[Extracted: ${params.selector || 'page'}]${NC}`;
511
+ case 'browser_js':
512
+ return `${M}[JS executed]${NC}`;
513
+ case 'browser_wait':
514
+ return `${M}[Found: ${params.selector}]${NC}`;
515
+ case 'browser_scroll':
516
+ return `${M}[Scrolled ${params.direction || 'down'}]${NC}`;
517
+ case 'browser_key':
518
+ return `${M}[Key: ${params.key}]${NC}`;
519
+ case 'browser_close':
520
+ return `${M}[Browser closed]${NC}`;
479
521
  case 'gmail_list':
480
522
  case 'gmail_read':
481
523
  case 'gmail_send':
@@ -1164,6 +1164,30 @@ export async function cmdUI(args) {
1164
1164
  for (const { action, params } of actions) {
1165
1165
  sendSSE('tool', { action, status: 'executing' });
1166
1166
  try {
1167
+ // For browser_screenshot in web UI: capture and send base64 image
1168
+ if (action === 'browser_screenshot') {
1169
+ const be = await import('../services/browser-engine.mjs');
1170
+ if (!be.isBrowserRunning()) {
1171
+ toolResults.push({ action, result: 'No browser open. Use browser_open first.' });
1172
+ sendSSE('tool', { action, status: 'error', error: 'No browser open' });
1173
+ continue;
1174
+ }
1175
+ const ssResult = await be.browserScreenshot({
1176
+ fullPage: params.fullPage || false,
1177
+ format: params.format || 'png',
1178
+ quality: params.quality,
1179
+ });
1180
+ if (!ssResult.error) {
1181
+ sendSSE('screenshot', { base64: ssResult.base64, format: params.format || 'png' });
1182
+ toolResults.push({ action, result: `Screenshot captured (${Math.round(ssResult.size / 1024)}KB)` });
1183
+ sendSSE('tool', { action, status: 'done', result: 'Screenshot captured' });
1184
+ } else {
1185
+ toolResults.push({ action, result: `Error: ${ssResult.message}` });
1186
+ sendSSE('tool', { action, status: 'error', error: ssResult.message });
1187
+ }
1188
+ continue;
1189
+ }
1190
+
1167
1191
  const result = await executeTool(action, params, config);
1168
1192
  toolResults.push({ action, result: typeof result === 'object' ? JSON.stringify(result) : String(result) });
1169
1193
  sendSSE('tool', { action, status: 'done', result: typeof result === 'string' ? result.slice(0, 500) : '' });
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '9.2.3';
8
+ export const VERSION = '9.3.0';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11