nothumanallowed 16.0.63 → 17.0.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 +98 -26
- package/bin/nha +3 -2
- package/package.json +7 -4
- package/src/bootstrap.mjs +30 -66
- package/src/cli.mjs +62 -20
- package/src/commands/autostart.mjs +1 -1
- package/src/commands/chat.mjs +1 -1
- package/src/commands/ops.mjs +1 -1
- package/src/config.mjs +37 -1
- package/src/constants.mjs +8 -2
- package/src/downloader.mjs +8 -3
- package/src/legion/agents/ade.mjs +201 -0
- package/src/legion/agents/athena.mjs +162 -0
- package/src/legion/agents/atlas.mjs +159 -0
- package/src/legion/agents/babel.mjs +167 -0
- package/src/legion/agents/cartographer.mjs +213 -0
- package/src/legion/agents/cassandra.mjs +185 -0
- package/src/legion/agents/conductor.mjs +183 -0
- package/src/legion/agents/cron.mjs +165 -0
- package/src/legion/agents/echo.mjs +165 -0
- package/src/legion/agents/edi.mjs +166 -0
- package/src/legion/agents/epicure.mjs +211 -0
- package/src/legion/agents/flux.mjs +165 -0
- package/src/legion/agents/forge.mjs +166 -0
- package/src/legion/agents/glitch.mjs +169 -0
- package/src/legion/agents/heimdall.mjs +171 -0
- package/src/legion/agents/herald.mjs +208 -0
- package/src/legion/agents/hermes.mjs +163 -0
- package/src/legion/agents/jarvis.mjs +163 -0
- package/src/legion/agents/link.mjs +163 -0
- package/src/legion/agents/logos.mjs +171 -0
- package/src/legion/agents/macro.mjs +158 -0
- package/src/legion/agents/mercury.mjs +234 -0
- package/src/legion/agents/murasaki.mjs +163 -0
- package/src/legion/agents/muse.mjs +217 -0
- package/src/legion/agents/navi.mjs +161 -0
- package/src/legion/agents/oracle.mjs +165 -0
- package/src/legion/agents/pipe.mjs +160 -0
- package/src/legion/agents/polyglot.mjs +226 -0
- package/src/legion/agents/prometheus.mjs +171 -0
- package/src/legion/agents/quill.mjs +165 -0
- package/src/legion/agents/saber.mjs +162 -0
- package/src/legion/agents/sauron.mjs +173 -0
- package/src/legion/agents/scheherazade.mjs +179 -0
- package/src/legion/agents/shell.mjs +166 -0
- package/src/legion/agents/shogun.mjs +163 -0
- package/src/legion/agents/tempest.mjs +211 -0
- package/src/legion/agents/veritas.mjs +166 -0
- package/src/legion/agents/zero.mjs +162 -0
- package/src/legion/legion-x.mjs +12114 -0
- package/src/legion-bundle.mjs +64 -0
- package/src/legion-config.mjs +134 -0
- package/src/server/index.mjs +51 -7
- package/src/services/llm.mjs +44 -15
- package/src/services/message-responder.mjs +1 -1
- package/src/spawn.mjs +22 -44
- package/src/updater.mjs +48 -63
package/README.md
CHANGED
|
@@ -8,21 +8,27 @@
|
|
|
8
8
|
# Install globally
|
|
9
9
|
npm install -g nothumanallowed
|
|
10
10
|
|
|
11
|
-
# Configure your LLM provider
|
|
11
|
+
# Configure your LLM provider with your own API key...
|
|
12
12
|
nha config set provider anthropic
|
|
13
13
|
nha config set key sk-ant-api03-YOUR_KEY
|
|
14
14
|
|
|
15
|
+
# ...or, for deliberations, a local model with no key at all
|
|
16
|
+
nha config set legion-provider ollama
|
|
17
|
+
nha config set ollama-model qwen2.5:7b
|
|
18
|
+
|
|
15
19
|
# Ask a single agent directly (no server, instant response)
|
|
16
20
|
nha ask saber "Audit this Express app for OWASP Top 10"
|
|
17
21
|
nha ask oracle "Analyze this dataset" --file data.csv
|
|
18
22
|
|
|
19
|
-
# Run multi-agent deliberation
|
|
23
|
+
# Run multi-agent deliberation, entirely on your machine
|
|
20
24
|
nha run "Design a Kubernetes deployment for a 10K RPS API"
|
|
21
25
|
|
|
22
26
|
# Open the web UI with Studio, Chat, Email, Calendar, Drive, Tasks and more
|
|
23
27
|
nha ui
|
|
24
28
|
```
|
|
25
29
|
|
|
30
|
+
**Do I need a local model?** No. You need one LLM, and you choose which: an API key of a cloud provider, or a model running on your machine. A local model is the option that needs no key and sends nothing out. The hosted free tier (Liara) that earlier versions used by default is currently offline: set a provider before the first prompt.
|
|
31
|
+
|
|
26
32
|
## Studio — Visual Agentic Workflows
|
|
27
33
|
|
|
28
34
|
Studio is a visual workflow builder inside the `nha ui` web interface. Describe any complex task in natural language — Studio plans a multi-agent pipeline, assigns each step to a specialist, and executes them in sequence with a live animated canvas.
|
|
@@ -34,7 +40,7 @@ EmailAgent → WebSearchAgent → WriterAgent
|
|
|
34
40
|
(reads) (searches) (synthesizes)
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
- **No configuration** — works with
|
|
43
|
+
- **No extra configuration** — works with the LLM provider you already set
|
|
38
44
|
- **Live canvas** — see each agent activate, stream output, and hand off to the next
|
|
39
45
|
- **HTML dashboard** — canvas generates a downloadable visual report (HTML + PDF)
|
|
40
46
|
- **Parliament mode** — enable for 2+ specialist agents to cross-read and deliberate: R1 (independent), R2 (agents read each other), R3 (HERALD mediation), convergence score
|
|
@@ -69,7 +75,7 @@ Open nha ui → click WebCraft in the sidebar
|
|
|
69
75
|
|
|
70
76
|
### WebCraft Agent
|
|
71
77
|
|
|
72
|
-
An AI assistant permanently available in the chat panel
|
|
78
|
+
An AI assistant permanently available in the chat panel, powered by the LLM provider you configured.
|
|
73
79
|
|
|
74
80
|
**What it can do:**
|
|
75
81
|
- Edit files surgically (old → new string replace) or rewrite them completely
|
|
@@ -96,7 +102,7 @@ Add more skill files (unlimited) for specific integrations (Stripe, email templa
|
|
|
96
102
|
| **Search** 🔍 | Grep across all project files — click a result to jump to that file |
|
|
97
103
|
| **Snapshot** 💾 | Save a full point-in-time backup of all files. Restore any snapshot with one click |
|
|
98
104
|
| **Plan mode** | Type `/plan your request` — agent proposes a plan first, you approve before any file is touched |
|
|
99
|
-
| **Auto-fix** | Sandbox errors (MODULE_NOT_FOUND etc.) trigger automatic
|
|
105
|
+
| **Auto-fix** | Sandbox errors (MODULE_NOT_FOUND etc.) trigger automatic fix attempts with your provider |
|
|
100
106
|
|
|
101
107
|
### Example session
|
|
102
108
|
|
|
@@ -151,9 +157,10 @@ OpenClaw reads your email with 1 generic agent. NHA sends it through 5 specialis
|
|
|
151
157
|
|
|
152
158
|
### Privacy
|
|
153
159
|
|
|
154
|
-
**
|
|
160
|
+
**Your emails, calendar and tasks never touch NHA servers.** The network calls are:
|
|
155
161
|
- Google APIs (your OAuth token, direct from your machine)
|
|
156
162
|
- Your LLM provider (your API key, direct from your machine)
|
|
163
|
+
- One usage ping per command to nothumanallowed.com: platform name and CLI version, nothing else (see Privacy & Ownership)
|
|
157
164
|
|
|
158
165
|
All data stored locally in `~/.nha/ops/`. Tokens encrypted with AES-256-GCM. You own everything. Inspect it, delete it, export it anytime.
|
|
159
166
|
|
|
@@ -247,6 +254,62 @@ When you don't specify `--agents`, NHA automatically:
|
|
|
247
254
|
|
|
248
255
|
This is real deliberation, not prompt chaining. Agents read and respond to each other.
|
|
249
256
|
|
|
257
|
+
### It runs on your machine
|
|
258
|
+
|
|
259
|
+
Since v17 the whole deliberation is local. Legion X and the 38 agents ship inside this package; routing (PROMETHEUS), the adversarial tribunal (CASSANDRA), the convergence measurement and the final audit (ATHENA) all run with **your** models. No NHA server takes part, and nothing is downloaded to deliberate.
|
|
260
|
+
|
|
261
|
+
**Choose the models.** Any mix of:
|
|
262
|
+
|
|
263
|
+
| Kind | Providers | Needs |
|
|
264
|
+
|---|---|---|
|
|
265
|
+
| Cloud | `anthropic`, `openai`, `gemini`, `deepseek`, `grok`, `mistral`, `cohere` | that provider's API key |
|
|
266
|
+
| Local | `ollama` (one or several models), `local-openai` (LM Studio, llama.cpp, vLLM, any OpenAI-compatible endpoint) | no key |
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# One cloud provider
|
|
270
|
+
nha config set provider anthropic
|
|
271
|
+
nha config set key sk-ant-api03-YOUR_KEY
|
|
272
|
+
|
|
273
|
+
# More than one: agents are spread across every provider that has a key
|
|
274
|
+
nha config set openai-key sk-YOUR_OPENAI_KEY
|
|
275
|
+
nha config set gemini-key YOUR_GEMINI_KEY
|
|
276
|
+
|
|
277
|
+
# A local model, no key
|
|
278
|
+
nha config set legion-provider ollama
|
|
279
|
+
nha config set ollama-model qwen2.5:7b
|
|
280
|
+
|
|
281
|
+
# Several local models: agents are spread across them
|
|
282
|
+
nha config set ollama-models llama3.1,qwen2.5:7b,mistral
|
|
283
|
+
|
|
284
|
+
# An OpenAI-compatible local server
|
|
285
|
+
nha config set legion-provider local-openai
|
|
286
|
+
nha config set local-openai-url http://localhost:1234/v1/chat/completions
|
|
287
|
+
nha config set local-openai-model my-model
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Cloud and local can work together in the same deliberation. To keep a deliberation on the machine even though a cloud key is configured for chat:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
nha config set local-only true
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Other settings**
|
|
297
|
+
|
|
298
|
+
| Key | What it does |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `orchestrator-provider` | Which provider runs routing, tribunal and audit (default: the first available) |
|
|
301
|
+
| `economy` / `nha run "..." --economy` | Shorter cross-reading, synthesis from the final positions: about half the tokens |
|
|
302
|
+
| `cross-reading-chars` | Characters of each proposal the other agents read (0 = no cap) |
|
|
303
|
+
| `ollama-embed-model` | A local embedding model for a semantic convergence measurement (default: word overlap) |
|
|
304
|
+
| `fact-check` | Turn the claim review off (`false`) |
|
|
305
|
+
| `rounds`, `convergence`, `tribunal` | Deliberation rounds, convergence threshold, tribunal on/off |
|
|
306
|
+
|
|
307
|
+
**What to expect.** A deliberation is many model calls: one per agent per round, plus routing, tribunal, synthesis and audit. A typical one with six agents and three rounds used about 770,000 tokens on a cloud model, about 350,000 with `--economy`, and took about 14 minutes on a 7B model running on a laptop. Small local models complete the deliberation but follow the structured steps less reliably.
|
|
308
|
+
|
|
309
|
+
**The fact-check is a model reviewing claims.** Nothing is verified against external sources, and the output says so. Earlier versions queried a knowledge base on the NHA server; that no longer exists.
|
|
310
|
+
|
|
311
|
+
**Everything is saved.** Each deliberation leaves a transcript in `~/.legion/sessions/` (Markdown and JSON), the session state in `~/.legion/geth-sessions/`, and what the agents learned in `~/.legion/local-store.json`. `nha geth:sessions` lists them.
|
|
312
|
+
|
|
250
313
|
## Extensions
|
|
251
314
|
|
|
252
315
|
15 downloadable agent modules for specific workflows:
|
|
@@ -270,10 +333,13 @@ nha ask forge "prompt" # DevOps & infrastructure
|
|
|
270
333
|
nha ask saber "review this" --file app.js # Attach a file
|
|
271
334
|
nha ask saber "prompt" --provider openai # Override provider
|
|
272
335
|
|
|
273
|
-
# Multi-agent
|
|
336
|
+
# Multi-agent deliberation (runs on your machine, with your models)
|
|
274
337
|
nha run "prompt" # Auto-route to best agents
|
|
275
338
|
nha run "prompt" --agents saber,zero # Specific agents
|
|
339
|
+
nha run "prompt" --economy # About half the tokens
|
|
276
340
|
nha run --file prompt.txt # From file
|
|
341
|
+
nha geth:sessions # Past deliberations
|
|
342
|
+
nha geth:providers # Providers a deliberation can use
|
|
277
343
|
|
|
278
344
|
# Explore agents
|
|
279
345
|
nha agents # List all 38 agents
|
|
@@ -293,44 +359,50 @@ nha pif feed # Activity feed
|
|
|
293
359
|
nha config # Show settings
|
|
294
360
|
nha config set provider anthropic
|
|
295
361
|
nha config set key YOUR_KEY
|
|
296
|
-
nha
|
|
362
|
+
nha config set legion-provider ollama # Deliberate with a local model
|
|
363
|
+
nha update # Update the package (Legion X and agents come with it)
|
|
297
364
|
nha doctor # Health check
|
|
298
365
|
nha mcp # Start MCP server (Claude Code, Cursor)
|
|
299
366
|
```
|
|
300
367
|
|
|
301
368
|
## Supported Providers
|
|
302
369
|
|
|
303
|
-
Anthropic, OpenAI, Google Gemini, DeepSeek, xAI Grok, Mistral, Cohere.
|
|
370
|
+
**Cloud:** Anthropic, OpenAI, Google Gemini, DeepSeek, xAI Grok, Mistral, Cohere.
|
|
371
|
+
|
|
372
|
+
**Local, no key:** Ollama (one or several models) and any OpenAI-compatible endpoint. Local models are available to deliberations (`nha run`); chat and the web UI use the cloud provider set with `nha config set provider`.
|
|
304
373
|
|
|
305
|
-
Use
|
|
374
|
+
Use several at once — each agent can run on a different model, cloud or local, for genuine multi-model reasoning.
|
|
306
375
|
|
|
307
376
|
## Privacy & Ownership
|
|
308
377
|
|
|
309
|
-
- **Your API
|
|
310
|
-
- **
|
|
311
|
-
- **
|
|
312
|
-
- **Agents are local files** — inspect, modify, fork them
|
|
313
|
-
- **Works offline**
|
|
378
|
+
- **Your API keys go to your own LLM provider and nowhere else.** They are stored in `~/.nha/config.json`, readable by your user only.
|
|
379
|
+
- **Deliberations run on your machine.** With local models and `local-only`, nothing leaves it.
|
|
380
|
+
- **One usage ping per command.** The CLI sends the platform name (`cli`) and its version to nothumanallowed.com. The server sees your IP address, as for any web request. No prompt, file, key or answer is sent.
|
|
381
|
+
- **Agents are local files** in `~/.nha/agents/` — inspect, modify, fork them. A package upgrade replaces them with the new version.
|
|
382
|
+
- **Works offline** with a local model: Legion X and the agents are in the package.
|
|
314
383
|
|
|
315
384
|
## How It Works
|
|
316
385
|
|
|
317
386
|
```
|
|
318
|
-
Your Machine
|
|
319
|
-
|
|
320
|
-
│
|
|
321
|
-
│
|
|
322
|
-
│
|
|
323
|
-
│
|
|
324
|
-
|
|
387
|
+
Your Machine
|
|
388
|
+
┌──────────────────────────────────────────────┐
|
|
389
|
+
│ nha run "prompt" │
|
|
390
|
+
│ │
|
|
391
|
+
│ PROMETHEUS routes ─► 38 agents deliberate │ ┌──────────────────────┐
|
|
392
|
+
│ CASSANDRA challenges (round 1, 2, 3) │ ───► │ YOUR LLM provider │
|
|
393
|
+
│ convergence measured ─► synthesis │ │ cloud API with your │
|
|
394
|
+
│ ATHENA audits │ │ key, or a local model│
|
|
395
|
+
│ │ └──────────────────────┘
|
|
396
|
+
│ transcript saved in ~/.legion/sessions/ │
|
|
397
|
+
└──────────────────────────────────────────────┘
|
|
325
398
|
```
|
|
326
399
|
|
|
327
400
|
## Links
|
|
328
401
|
|
|
329
402
|
- [Website](https://nothumanallowed.com)
|
|
330
|
-
- [
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
- [Epistemic Datasets](https://nothumanallowed.com/datasets) — Download reasoning traces
|
|
403
|
+
- [Source code and issues](https://github.com/adoslabsproject-gif/nothumanallowed)
|
|
404
|
+
|
|
405
|
+
This README is the documentation. `nha help` lists every command; `nha agents` lists the 38 agents.
|
|
334
406
|
|
|
335
407
|
## License
|
|
336
408
|
|
package/bin/nha
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* nha — NotHumanAllowed CLI
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Launcher for Legion X (multi-agent deliberation, shipped inside this package
|
|
6
|
+
* and run on this machine) and the rest of the toolkit. The first run copies
|
|
7
|
+
* the 38 agents to ~/.nha/agents; nothing is downloaded to deliberate.
|
|
7
8
|
*
|
|
8
9
|
* Usage:
|
|
9
10
|
* npx nha run "Compare React vs Vue for enterprise"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`.
|
|
3
|
+
"version": "17.0.0",
|
|
4
|
+
"description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, multi-agent deliberation that runs entirely on your machine (Legion X), visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Bring your own LLM: an API key or a local model (Ollama, any OpenAI-compatible endpoint). Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"nha": "bin/nha",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"openai",
|
|
33
33
|
"gemini",
|
|
34
34
|
"deepseek",
|
|
35
|
+
"ollama",
|
|
36
|
+
"local-llm",
|
|
35
37
|
"telegram-bot",
|
|
36
38
|
"discord-bot",
|
|
37
39
|
"voice-assistant",
|
|
@@ -55,10 +57,11 @@
|
|
|
55
57
|
"homepage": "https://nothumanallowed.com",
|
|
56
58
|
"scripts": {
|
|
57
59
|
"check-bundle": "node check-bundle.mjs",
|
|
60
|
+
"check-legion-source": "node check-legion-source.mjs",
|
|
58
61
|
"build:ui": "cd ../nha-ui && pnpm build",
|
|
59
62
|
"prebuild": "cd ../nha-ui && pnpm build",
|
|
60
|
-
"test": "node test/sandbox.test.mjs",
|
|
61
|
-
"prepublishOnly": "node check-bundle.mjs && node
|
|
63
|
+
"test": "node test/sandbox.test.mjs && node --test test/legion-bundle.test.mjs test/legion-run.test.mjs test/hosted-offline.test.mjs",
|
|
64
|
+
"prepublishOnly": "node check-bundle.mjs && node check-legion-source.mjs && npm test"
|
|
62
65
|
},
|
|
63
66
|
"dependencies": {
|
|
64
67
|
"acorn": "^8.16.0",
|
package/src/bootstrap.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
/** First-run provisioner — creates ~/.nha/ and
|
|
1
|
+
/** First-run provisioner — creates ~/.nha/ and installs the agents shipped with the package */
|
|
2
2
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import {
|
|
5
5
|
NHA_DIR, CORE_DIR, AGENTS_DIR, EXTENSIONS_DIR, SESSIONS_DIR, MEMORY_DIR,
|
|
6
|
-
BASE_URL, LEGION_FILE, PIF_FILE, VERSIONS_FILE,
|
|
6
|
+
BASE_URL, LEGION_FILE, PIF_FILE, VERSIONS_FILE,
|
|
7
7
|
} from './constants.mjs';
|
|
8
|
-
import { download
|
|
8
|
+
import { download } from './downloader.mjs';
|
|
9
9
|
import { loadConfig, saveConfig } from './config.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import { bundledLegionVersion, syncBundledAgents } from './legion-bundle.mjs';
|
|
11
|
+
import { banner, info, ok, fail, warn } from './ui.mjs';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* Check if bootstrap is needed (
|
|
14
|
+
* Check if bootstrap is needed (agents not installed yet).
|
|
14
15
|
*/
|
|
15
16
|
export function needsBootstrap() {
|
|
16
17
|
if (!fs.existsSync(LEGION_FILE) || !fs.existsSync(AGENTS_DIR)) return true;
|
|
@@ -23,7 +24,10 @@ export function needsBootstrap() {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* Run full bootstrap: create dirs,
|
|
27
|
+
* Run full bootstrap: create dirs, install the bundled agents.
|
|
28
|
+
* Legion X and the agents come from the package itself, so this works offline.
|
|
29
|
+
* Only PIF (the client of the NHA platform) is still fetched, and its absence
|
|
30
|
+
* stops nothing else.
|
|
27
31
|
*/
|
|
28
32
|
export async function bootstrap() {
|
|
29
33
|
banner();
|
|
@@ -35,87 +39,47 @@ export async function bootstrap() {
|
|
|
35
39
|
}
|
|
36
40
|
ok('Created ~/.nha/ directory structure');
|
|
37
41
|
|
|
38
|
-
// ──
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!versionsOk) {
|
|
42
|
-
fail('Could not reach nothumanallowed.com — check your connection.');
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let versions;
|
|
47
|
-
try {
|
|
48
|
-
versions = JSON.parse(fs.readFileSync(VERSIONS_FILE, 'utf-8'));
|
|
49
|
-
} catch {
|
|
50
|
-
fail('Corrupt versions.json');
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const legionVersion = versions['legion-x']?.latest ?? 'unknown';
|
|
55
|
-
const pifVersion = versions['pif']?.latest ?? 'unknown';
|
|
56
|
-
|
|
57
|
-
// ── Download core files ──────────────────────────────────────────────────
|
|
58
|
-
info(`Downloading Legion X v${legionVersion}...`);
|
|
59
|
-
const legionOk = await download(`${BASE_URL}/legion-x.mjs`, LEGION_FILE, { timeout: 60_000 });
|
|
60
|
-
if (!legionOk) {
|
|
61
|
-
fail('Failed to download Legion X');
|
|
42
|
+
// ── Legion X and the agents, from the package ────────────────────────────
|
|
43
|
+
if (!fs.existsSync(LEGION_FILE)) {
|
|
44
|
+
fail('Legion X is missing from this installation. Reinstall: npm install -g nothumanallowed');
|
|
62
45
|
process.exit(1);
|
|
63
46
|
}
|
|
64
|
-
ok(`Legion X v${
|
|
47
|
+
ok(`Legion X v${bundledLegionVersion()} ready`);
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
fail('Failed to download PIF');
|
|
49
|
+
const agents = syncBundledAgents();
|
|
50
|
+
if (agents.missing.length > 0) {
|
|
51
|
+
fail(`${agents.missing.length} agents are missing from this installation (${agents.missing.join(', ')}). Reinstall: npm install -g nothumanallowed`);
|
|
70
52
|
process.exit(1);
|
|
71
53
|
}
|
|
72
|
-
ok(
|
|
73
|
-
|
|
74
|
-
// ── Download all 38 agents ───────────────────────────────────────────────
|
|
75
|
-
info(`Downloading ${AGENTS.length} agents...`);
|
|
76
|
-
const agentTasks = AGENTS.map(name => ({
|
|
77
|
-
url: `${BASE_URL}/agents/${name}.mjs`,
|
|
78
|
-
dest: `${AGENTS_DIR}/${name}.mjs`,
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
const result = await downloadBatch(agentTasks, 8, (done, total) => {
|
|
82
|
-
progress(done, total, `agents`);
|
|
83
|
-
});
|
|
54
|
+
ok(`${agents.copied} agents installed in ~/.nha/agents`);
|
|
84
55
|
|
|
85
|
-
|
|
86
|
-
|
|
56
|
+
// ── PIF, the client of the NHA platform (optional) ───────────────────────
|
|
57
|
+
const versionsOk = await download(`${BASE_URL}/versions.json`, VERSIONS_FILE);
|
|
58
|
+
const pifOk = versionsOk && await download(`${BASE_URL}/pif.mjs`, PIF_FILE, { timeout: 60_000 });
|
|
59
|
+
if (pifOk) {
|
|
60
|
+
ok('PIF installed');
|
|
87
61
|
} else {
|
|
88
|
-
|
|
62
|
+
warn('PIF could not be downloaded: the "nha pif" and "nha mcp" commands stay unavailable. Everything else works.');
|
|
89
63
|
}
|
|
90
64
|
|
|
91
65
|
// ── Initialize config (migrates legacy if present) ───────────────────────
|
|
92
66
|
const config = loadConfig();
|
|
93
67
|
saveConfig(config);
|
|
94
68
|
|
|
95
|
-
// ── Symlink sessions for backward compat ─────────────────────────────────
|
|
96
|
-
const legacySessionsDir = `${process.env.HOME}/.legion/sessions`;
|
|
97
|
-
if (fs.existsSync(legacySessionsDir) && !fs.existsSync(SESSIONS_DIR + '/.migrated')) {
|
|
98
|
-
try {
|
|
99
|
-
const files = fs.readdirSync(legacySessionsDir);
|
|
100
|
-
if (files.length > 0) {
|
|
101
|
-
info(`Found ${files.length} legacy session files — linked`);
|
|
102
|
-
}
|
|
103
|
-
} catch { /* ignore */ }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
69
|
// ── Done ─────────────────────────────────────────────────────────────────
|
|
107
70
|
console.log('');
|
|
108
71
|
ok('NHA is ready!\n');
|
|
109
72
|
|
|
110
73
|
if (!config.llm.apiKey) {
|
|
111
|
-
console.log(` ${'\x1b[1;33m'}Next step:${'\x1b[0m'}
|
|
112
|
-
console.log(` ${'\x1b[1;
|
|
113
|
-
console.log(` nha config set provider nha`);
|
|
114
|
-
console.log(` ${'\x1b[2m'}Powered by Liara (Qwen3 32B). Free, slower (5-15s). No key required.${'\x1b[0m'}\n`);
|
|
115
|
-
console.log(` ${'\x1b[1;36m'}Option 2 — Your own API key (faster, more capable):${'\x1b[0m'}`);
|
|
74
|
+
console.log(` ${'\x1b[1;33m'}Next step:${'\x1b[0m'} choose where your models run:\n`);
|
|
75
|
+
console.log(` ${'\x1b[1;36m'}Option 1 — Your own API key:${'\x1b[0m'}`);
|
|
116
76
|
console.log(` nha config set provider anthropic`);
|
|
117
77
|
console.log(` nha config set key sk-ant-api03-YOUR_KEY_HERE`);
|
|
118
78
|
console.log(` ${'\x1b[2m'}Supported: anthropic, openai, gemini, deepseek, grok, mistral, cohere${'\x1b[0m'}\n`);
|
|
79
|
+
console.log(` ${'\x1b[1;32m'}Option 2 — A local model, no key (deliberations with "nha run"):${'\x1b[0m'}`);
|
|
80
|
+
console.log(` nha config set legion-provider ollama`);
|
|
81
|
+
console.log(` nha config set ollama-model qwen2.5:7b`);
|
|
82
|
+
console.log(` ${'\x1b[2m'}Any model served by Ollama, or any OpenAI-compatible endpoint (local-openai-url).${'\x1b[0m'}\n`);
|
|
119
83
|
}
|
|
120
84
|
|
|
121
85
|
return true;
|
package/src/cli.mjs
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import { VERSION, NHA_DIR, AGENTS_DIR, EXTENSIONS_DIR, AGENTS, EXTENSIONS, BASE_URL } from './constants.mjs';
|
|
5
|
+
import { VERSION, NHA_DIR, AGENTS_DIR, EXTENSIONS_DIR, AGENTS, EXTENSIONS, BASE_URL, LEGION_FILE } from './constants.mjs';
|
|
6
6
|
import { needsBootstrap, bootstrap } from './bootstrap.mjs';
|
|
7
7
|
import { spawnCore } from './spawn.mjs';
|
|
8
8
|
import { loadConfig, setConfigValue } from './config.mjs';
|
|
9
|
+
import { buildLegionConfig, legionReadiness } from './legion-config.mjs';
|
|
10
|
+
import { bundledLegionVersion, syncBundledAgents } from './legion-bundle.mjs';
|
|
9
11
|
import { checkForUpdates, runUpdate, checkNpmVersion } from './updater.mjs';
|
|
10
12
|
import { download } from './downloader.mjs';
|
|
11
13
|
import { cmdAsk } from './commands/ask.mjs';
|
|
@@ -31,6 +33,9 @@ export async function main(argv) {
|
|
|
31
33
|
if (needsBootstrap() && cmd !== 'help' && cmd !== 'version' && cmd !== '--help' && cmd !== '-h') {
|
|
32
34
|
await bootstrap();
|
|
33
35
|
if (cmd === 'setup') return; // setup was the goal
|
|
36
|
+
} else if (cmd !== 'help' && cmd !== 'version' && cmd !== '--help' && cmd !== '-h') {
|
|
37
|
+
// After a package upgrade the agents of the new version replace the old ones.
|
|
38
|
+
try { syncBundledAgents(); } catch (err) { warn(`Could not refresh the agents: ${err.message}`); }
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
// ── Telemetry ping (anonymous, fire-and-forget, non-blocking) ────────────
|
|
@@ -221,6 +226,14 @@ export async function main(argv) {
|
|
|
221
226
|
const { cmdPlugin: runPlugin } = await import('./commands/plugin.mjs');
|
|
222
227
|
return runPlugin(['run', cmd, ...args]);
|
|
223
228
|
}
|
|
229
|
+
// Legion's own config:set writes a file that is rebuilt from the nha
|
|
230
|
+
// config at every run: a value set there would vanish without a word.
|
|
231
|
+
if (cmd === 'config:set') {
|
|
232
|
+
fail('Settings are kept in the nha config. Use: nha config set <key> <value>');
|
|
233
|
+
info('Deliberation keys: legion-provider, ollama-url, ollama-model, ollama-models, ollama-embed-model,');
|
|
234
|
+
info('local-openai-url, local-openai-model, local-openai-key, orchestrator-provider, economy, fact-check, cross-reading-chars');
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
224
237
|
// Try as Legion command passthrough (only if legion is installed)
|
|
225
238
|
try {
|
|
226
239
|
const { LEGION_FILE } = await import('./constants.mjs');
|
|
@@ -422,12 +435,19 @@ async function cmdRun(args) {
|
|
|
422
435
|
process.exit(1);
|
|
423
436
|
}
|
|
424
437
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
438
|
+
// A deliberation runs on this machine with the user's own models: a cloud
|
|
439
|
+
// provider with its key, or a local model with no key at all.
|
|
440
|
+
const readiness = legionReadiness(buildLegionConfig(loadConfig()));
|
|
441
|
+
if (!readiness.ready) {
|
|
442
|
+
fail(readiness.reason);
|
|
443
|
+
console.log('');
|
|
444
|
+
console.log(' With an API key (anthropic, openai, gemini, deepseek, grok, mistral, cohere):');
|
|
445
|
+
console.log(' nha config set provider anthropic');
|
|
446
|
+
console.log(' nha config set key sk-ant-api03-YOUR_KEY');
|
|
428
447
|
console.log('');
|
|
429
|
-
console.log('
|
|
430
|
-
console.log('
|
|
448
|
+
console.log(' With a local model, no key (Ollama or any OpenAI-compatible endpoint):');
|
|
449
|
+
console.log(' nha config set legion-provider ollama');
|
|
450
|
+
console.log(' nha config set ollama-model qwen2.5:7b');
|
|
431
451
|
console.log('');
|
|
432
452
|
process.exit(1);
|
|
433
453
|
}
|
|
@@ -533,6 +553,8 @@ function cmdConfig(args) {
|
|
|
533
553
|
console.log('');
|
|
534
554
|
info('Keys: provider, key, openai-key, gemini-key, deepseek-key, grok-key (X.AI), groq-key (voice/Whisper), mistral-key, cohere-key, model, timeout');
|
|
535
555
|
info(' verbose, immersive, deliberation, rounds, convergence, tribunal, knowledge');
|
|
556
|
+
info(' legion-provider, ollama-url, ollama-model, ollama-models, ollama-embed-model (local models for "nha run")');
|
|
557
|
+
info(' local-openai-url, local-openai-model, local-openai-key, orchestrator-provider, economy, fact-check, cross-reading-chars');
|
|
536
558
|
info(' google-client-id, google-client-secret');
|
|
537
559
|
info(' microsoft-client-id, microsoft-client-secret, microsoft-tenant');
|
|
538
560
|
info(' telegram-bot-token, discord-bot-token, responder-auto-route');
|
|
@@ -541,7 +563,9 @@ function cmdConfig(args) {
|
|
|
541
563
|
}
|
|
542
564
|
const success = setConfigValue(key, value);
|
|
543
565
|
if (success) {
|
|
544
|
-
|
|
566
|
+
// A secret is never echoed back, whatever it starts with.
|
|
567
|
+
const secret = /(key|token|secret)$/i.test(key) || value.startsWith('sk-');
|
|
568
|
+
ok(`${key} = ${secret ? '***' : value}`);
|
|
545
569
|
} else {
|
|
546
570
|
fail(`Unknown config key: ${key}`);
|
|
547
571
|
}
|
|
@@ -577,6 +601,14 @@ function cmdConfig(args) {
|
|
|
577
601
|
console.log(` Rounds: ${W}${config.deliberation.rounds}${NC}`);
|
|
578
602
|
console.log(` Convergence: ${W}${config.deliberation.convergence}${NC}`);
|
|
579
603
|
console.log(` Tribunal: ${config.deliberation.tribunalEnabled ? G + 'yes' : D + 'no'}${NC}`);
|
|
604
|
+
const legionConfig = buildLegionConfig(config);
|
|
605
|
+
const readiness = legionReadiness(legionConfig);
|
|
606
|
+
console.log(` Provider: ${W}${legionConfig.provider || '(any configured)'}${NC}`);
|
|
607
|
+
console.log(` Can run with: ${readiness.ready ? G + readiness.providers.join(', ') : R + readiness.reason}${NC}`);
|
|
608
|
+
if (legionConfig.ollamaModels || legionConfig.ollamaModel) {
|
|
609
|
+
console.log(` Local models: ${W}${legionConfig.ollamaModels || legionConfig.ollamaModel}${NC} ${D}(${legionConfig.ollamaUrl})${NC}`);
|
|
610
|
+
}
|
|
611
|
+
if (legionConfig.economy) console.log(` Economy: ${G}yes${NC}`);
|
|
580
612
|
|
|
581
613
|
console.log(`\n ${C}Agent Identity${NC}`);
|
|
582
614
|
if (config.agent.name) {
|
|
@@ -745,10 +777,10 @@ async function cmdDoctor() {
|
|
|
745
777
|
console.log(` Node.js: ${nodeV >= 22 ? G + process.version : Y + process.version + ' (need 22+)'}${NC}`);
|
|
746
778
|
|
|
747
779
|
// Check core files
|
|
748
|
-
const legionOk = fs.existsSync(
|
|
780
|
+
const legionOk = fs.existsSync(LEGION_FILE);
|
|
749
781
|
const pifOk = fs.existsSync(path.join(NHA_DIR, 'core', 'pif.mjs'));
|
|
750
|
-
console.log(` Legion X: ${legionOk ? G + '
|
|
751
|
-
console.log(` PIF: ${pifOk ? G + 'installed' :
|
|
782
|
+
console.log(` Legion X: ${legionOk ? G + 'v' + bundledLegionVersion() + ' (bundled)' : R + 'missing'}${NC}`);
|
|
783
|
+
console.log(` PIF: ${pifOk ? G + 'installed' : D + 'not installed (optional)'}${NC}`);
|
|
752
784
|
|
|
753
785
|
// Check agents
|
|
754
786
|
const agentCount = AGENTS.filter(a => fs.existsSync(path.join(AGENTS_DIR, `${a}.mjs`))).length;
|
|
@@ -769,6 +801,10 @@ async function cmdDoctor() {
|
|
|
769
801
|
// Check API key
|
|
770
802
|
console.log(` API Key: ${config.llm.apiKey ? G + 'configured (' + config.llm.provider + ')' : R + 'NOT SET'}${NC}`);
|
|
771
803
|
|
|
804
|
+
// Deliberations run locally: which of the user's providers they can use
|
|
805
|
+
const readiness = legionReadiness(buildLegionConfig(config));
|
|
806
|
+
console.log(` Deliberations: ${readiness.ready ? G + 'ready (' + readiness.providers.join(', ') + ')' : R + readiness.reason}${NC}`);
|
|
807
|
+
|
|
772
808
|
// Check connectivity
|
|
773
809
|
try {
|
|
774
810
|
const res = await fetch('https://nothumanallowed.com/api/v1/health', {
|
|
@@ -787,24 +823,27 @@ async function cmdDoctor() {
|
|
|
787
823
|
if (!config.llm.apiKey) {
|
|
788
824
|
warn('Configure an API key: nha config set provider anthropic && nha config set key YOUR_KEY');
|
|
789
825
|
}
|
|
790
|
-
if (!
|
|
791
|
-
warn('
|
|
826
|
+
if (!readiness.ready) {
|
|
827
|
+
warn('For "nha run" with a local model and no key: nha config set legion-provider ollama && nha config set ollama-model <model>');
|
|
828
|
+
}
|
|
829
|
+
if (!legionOk) {
|
|
830
|
+
warn('Legion X is missing from this installation. Reinstall: npm install -g nothumanallowed');
|
|
792
831
|
}
|
|
793
832
|
if (agentCount < AGENTS.length) {
|
|
794
|
-
warn(`${AGENTS.length - agentCount} agents missing. Run "nha update" to
|
|
833
|
+
warn(`${AGENTS.length - agentCount} agents missing. Run "nha update" to restore them from the package.`);
|
|
795
834
|
}
|
|
796
835
|
}
|
|
797
836
|
|
|
798
837
|
// ── nha version ────────────────────────────────────────────────────────────
|
|
799
838
|
function cmdVersion() {
|
|
800
839
|
console.log(`nha v${VERSION}`);
|
|
840
|
+
console.log(`Legion X v${bundledLegionVersion()}`);
|
|
801
841
|
|
|
802
|
-
//
|
|
842
|
+
// PIF is downloaded separately: show its version if it is there
|
|
803
843
|
const versionsFile = path.join(NHA_DIR, 'core', 'versions.json');
|
|
804
844
|
if (fs.existsSync(versionsFile)) {
|
|
805
845
|
try {
|
|
806
846
|
const v = JSON.parse(fs.readFileSync(versionsFile, 'utf-8'));
|
|
807
|
-
if (v['legion-x']?.latest) console.log(`Legion X v${v['legion-x'].latest}`);
|
|
808
847
|
if (v['pif']?.latest) console.log(`PIF v${v['pif'].latest}`);
|
|
809
848
|
} catch {}
|
|
810
849
|
}
|
|
@@ -823,8 +862,10 @@ function cmdHelp() {
|
|
|
823
862
|
console.log(` agents info <name> Show agent capabilities & domain`);
|
|
824
863
|
console.log(` scan <path> Security scan a project with SABER + ZERO`);
|
|
825
864
|
console.log(` scan . ${D}--output report.md${NC} Save report to file`);
|
|
826
|
-
console.log(` run "prompt" Multi-agent
|
|
827
|
-
console.log(` run "prompt" ${D}--agents saber,zero${NC}
|
|
865
|
+
console.log(` run "prompt" Multi-agent deliberation, on this machine with your own models`);
|
|
866
|
+
console.log(` run "prompt" ${D}--agents saber,zero${NC} Deliberate with specific agents`);
|
|
867
|
+
console.log(` run "prompt" ${D}--economy${NC} About half the tokens (shorter cross-reading)`);
|
|
868
|
+
console.log(` ${D}Local model, no key: config set legion-provider ollama + config set ollama-model <model>${NC}\n`);
|
|
828
869
|
|
|
829
870
|
console.log(` ${C}Daily Operations${NC} ${D}(Gmail + Calendar + Tasks)${NC}`);
|
|
830
871
|
console.log(` ui Open local web dashboard (http://127.0.0.1:3847)`);
|
|
@@ -902,7 +943,7 @@ function cmdHelp() {
|
|
|
902
943
|
console.log(` ${C}Configuration${NC}`);
|
|
903
944
|
console.log(` config Show current config`);
|
|
904
945
|
console.log(` config set <k> <v> Set a config value`);
|
|
905
|
-
console.log(` update Update
|
|
946
|
+
console.log(` update Update the npm package (Legion X and agents come with it)`);
|
|
906
947
|
console.log(` upgrade Update npm package only (alias: self-update)`);
|
|
907
948
|
console.log(` doctor Health check`);
|
|
908
949
|
console.log(` mcp Start MCP server (Claude Code, Cursor)\n`);
|
|
@@ -914,6 +955,7 @@ function cmdHelp() {
|
|
|
914
955
|
|
|
915
956
|
console.log(` ${D}38 agents: security, code, data, devops, creative, integration, and more.${NC}`);
|
|
916
957
|
console.log(` ${D}Use them solo or let them collaborate via multi-round deliberation.${NC}`);
|
|
917
|
-
console.log(` ${D}Your API
|
|
918
|
-
console.log(` ${D}
|
|
958
|
+
console.log(` ${D}Your API keys go to your own LLM provider and nowhere else.${NC}`);
|
|
959
|
+
console.log(` ${D}Each command sends one usage ping (platform and version) to nothumanallowed.com.${NC}`);
|
|
960
|
+
console.log(` ${D}Docs: https://github.com/adoslabsproject-gif/nothumanallowed#readme — v${VERSION}${NC}\n`);
|
|
919
961
|
}
|
|
@@ -146,7 +146,7 @@ function launchdStatus() {
|
|
|
146
146
|
function generateSystemdUnit() {
|
|
147
147
|
return `[Unit]
|
|
148
148
|
Description=NHA PAO Background Daemon
|
|
149
|
-
Documentation=https://
|
|
149
|
+
Documentation=https://github.com/adoslabsproject-gif/nothumanallowed#readme
|
|
150
150
|
After=network-online.target
|
|
151
151
|
Wants=network-online.target
|
|
152
152
|
|
package/src/commands/chat.mjs
CHANGED
|
@@ -572,7 +572,7 @@ export async function cmdChat(args) {
|
|
|
572
572
|
|
|
573
573
|
const activeProvider = config.llm.provider || 'anthropic';
|
|
574
574
|
if (activeProvider !== 'nha' && !config.llm.apiKey) {
|
|
575
|
-
fail('No API key configured. Run: nha config set key YOUR_KEY
|
|
575
|
+
fail('No API key configured. Run: nha config set key YOUR_KEY');
|
|
576
576
|
process.exit(1);
|
|
577
577
|
}
|
|
578
578
|
|
package/src/commands/ops.mjs
CHANGED
|
@@ -105,7 +105,7 @@ export async function cmdOps(args) {
|
|
|
105
105
|
let inactiveHintTel = 'configured but inactive (try: nha ops stop && nha ops start)';
|
|
106
106
|
if (reason.startsWith('missing_key:')) {
|
|
107
107
|
const p = reason.slice('missing_key:'.length);
|
|
108
|
-
inactiveHintTel = `configured but LLM key missing for provider "${p}" — fix with: nha config set
|
|
108
|
+
inactiveHintTel = `configured but LLM key missing for provider "${p}" — fix with: nha config set key YOUR_KEY`;
|
|
109
109
|
}
|
|
110
110
|
console.log(` Telegram: ${responder.telegram ? G + 'active' + NC : telegramConfigured ? Y + inactiveHintTel + NC : D + 'not configured' + NC}`);
|
|
111
111
|
console.log(` Discord: ${responder.discord ? G + 'active' + NC : discordConfigured ? Y + inactiveHintTel + NC : D + 'not configured' + NC}`);
|