@oriro/orirocli 0.1.3 → 0.1.4
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 +16 -12
- package/dist/cli.js +48 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,21 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
# ORIRO‑Terminal - **“Head | Memory | Eyeball for AI”**
|
|
4
4
|
|
|
5
|
-
# **FREE
|
|
5
|
+
# **FREE · KEYLESS · BYOK** | **Works in 100 Languages | Deterministic Security Guardian V3**
|
|
6
6
|
|
|
7
|
-
A
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
A free, keyless terminal AI coder — built on the Pi agent harness (used as a library).
|
|
8
|
+
It **writes and runs code** from a pool of free routers, works in **your language**, **guards every action**,
|
|
9
|
+
can **inspect a live site's structure**, and greets you with an **avatar in its own on-device voice**.
|
|
10
10
|
Your language, your machine, no paid keys required.
|
|
11
11
|
|
|
12
|
-
## What's inside
|
|
13
|
-
- **Keyless free-router Mux** — best-router selection + invisible failover across free providers, with an on-device floor. Never a paid key.
|
|
14
|
-
- **100 languages** —
|
|
15
|
-
- **Guardian V3** — a security gate on every tool call
|
|
16
|
-
- **Head** —
|
|
17
|
-
- **Scriber** — a consent-gated
|
|
18
|
-
- **323 skills
|
|
19
|
-
- **Channels** —
|
|
12
|
+
## What's inside (this release)
|
|
13
|
+
- **Keyless free-router Mux** — best-router selection + invisible failover across free providers, with an on-device floor. **Never a paid key.** BYOK optional (live-validated).
|
|
14
|
+
- **100 languages** — pick yours at first run; the model works in English. On-device NLLB translation is an optional add-on (without it, your text passes through as-is).
|
|
15
|
+
- **Guardian V3 (Lite)** — a **deterministic** security gate on every tool call (default-on, fail-closed): blocks `curl|sh` remote-exec, destructive wipes, reverse shells, and env/secret exfil. No weights, no tokenizer, no download.
|
|
16
|
+
- **Head** — fetches a live site, detects its **sections/structure**, and reports the gaps to build from (the coder writes the code from that report).
|
|
17
|
+
- **Scriber (memory)** — a consent-gated local work journal, **off by default**; turns are recalled across sessions and never leave your machine.
|
|
18
|
+
- **323 skills** (CORE/TAIL tiered) + **multi-agent orchestration** on the free pool.
|
|
19
|
+
- **MCP connector catalog** (59) and **Channels** — run ORIRO from Telegram/Discord/WhatsApp with **your own** bot.
|
|
20
|
+
- **Avatar** — pick a face at onboarding; it greets you aloud in its paired on-device voice.
|
|
21
|
+
|
|
22
|
+
## On the roadmap (not in this release)
|
|
23
|
+
Full-page **screenshot → code** Head (Playwright), the **two-way voice loop** (speak + listen/STT), in-REPL **permission modes**, and **`oriro mcp`** guided setup. Today the Head is fetch/structure-based and voice is the avatar's spoken greeting.
|
|
20
24
|
|
|
21
25
|
## Install
|
|
22
26
|
|
package/dist/cli.js
CHANGED
|
@@ -475,6 +475,10 @@ var REVERSE_SHELL = [
|
|
|
475
475
|
];
|
|
476
476
|
var SECRET_PATHS = /(\.ssh\/id_|\.ssh\/.*_rsa|\.aws\/credentials|\.oriro\/credentials|\.config\/gcloud|\.env(\.|\b)|\.netrc|id_ed25519|\.kube\/config|wallet\.dat|\.gnupg\/)/i;
|
|
477
477
|
var NET_SINK = /\b(curl|wget|nc|ncat|socat|scp|rsync|ftp|tftp|invoke-webrequest|invoke-restmethod)\b/i;
|
|
478
|
+
var ENV_EXFIL = [
|
|
479
|
+
/\$\(\s*(printenv|env)\b/i,
|
|
480
|
+
/\$\(\s*cat\b[^)]*(\.ssh|\.aws|\.env|\.netrc|credential|secret|token|id_rsa|id_ed25519)/i
|
|
481
|
+
];
|
|
478
482
|
var PERSISTENCE = [
|
|
479
483
|
/\bcrontab\b\s+(-|\S+)/i,
|
|
480
484
|
// crontab install
|
|
@@ -542,6 +546,14 @@ var DEFAULT_RULES = [
|
|
|
542
546
|
return null;
|
|
543
547
|
}
|
|
544
548
|
},
|
|
549
|
+
{
|
|
550
|
+
id: "env-exfiltration",
|
|
551
|
+
description: "Block dumping env vars / secret files into a network request (curl \u2026$(printenv SECRET)).",
|
|
552
|
+
match: (c) => {
|
|
553
|
+
const cmd = norm(cmdOf(c));
|
|
554
|
+
return cmd && NET_SINK.test(cmd) && anyMatch(ENV_EXFIL, cmd) ? block("env-exfiltration", "Sending environment variables / secret files off the machine") : null;
|
|
555
|
+
}
|
|
556
|
+
},
|
|
545
557
|
{
|
|
546
558
|
id: "persistence",
|
|
547
559
|
description: "Flag cron/rc/startup/service edits used for Trojan persistence.",
|
|
@@ -2813,6 +2825,17 @@ function setupNllbTranslator(opts) {
|
|
|
2813
2825
|
}
|
|
2814
2826
|
|
|
2815
2827
|
// src/repl.ts
|
|
2828
|
+
function replHelp() {
|
|
2829
|
+
return `
|
|
2830
|
+
${accent("ORIRO terminal \u2014 help")}
|
|
2831
|
+
${dim("Just type to chat; ORIRO writes and runs code for you (keyless, free).")}
|
|
2832
|
+
|
|
2833
|
+
${accent("/help")} this help ${accent("/exit")} or ${accent("/quit")} leave ${dim("Ctrl-D / Ctrl-C also exit")}
|
|
2834
|
+
${dim("Run these OUTSIDE the chat (in your shell):")}
|
|
2835
|
+
${dim("oriro skills \xB7 routers \xB7 connectors \xB7 channels \xB7 scribe \xB7 language \xB7 avatar")}
|
|
2836
|
+
|
|
2837
|
+
`;
|
|
2838
|
+
}
|
|
2816
2839
|
async function runRepl() {
|
|
2817
2840
|
if (isFirstRun()) await runOnboarding();
|
|
2818
2841
|
else stdout4.write(banner());
|
|
@@ -2831,6 +2854,10 @@ async function runRepl() {
|
|
|
2831
2854
|
}
|
|
2832
2855
|
if (!line) continue;
|
|
2833
2856
|
if (line === "/exit" || line === "/quit") break;
|
|
2857
|
+
if (line === "/help" || line === "/?") {
|
|
2858
|
+
stdout4.write(replHelp());
|
|
2859
|
+
continue;
|
|
2860
|
+
}
|
|
2834
2861
|
const english = await translateForCoder(line, lang);
|
|
2835
2862
|
let out = "";
|
|
2836
2863
|
const unsub = session.subscribe((e) => {
|
|
@@ -4284,6 +4311,9 @@ function writeAdded(slugs) {
|
|
|
4284
4311
|
function listConnectors(category) {
|
|
4285
4312
|
return category ? CONNECTOR_CATALOG.filter((c) => c.category === category) : CONNECTOR_CATALOG;
|
|
4286
4313
|
}
|
|
4314
|
+
function connectorCategories() {
|
|
4315
|
+
return [...new Set(CONNECTOR_CATALOG.map((c) => c.category))].sort();
|
|
4316
|
+
}
|
|
4287
4317
|
function addConnector(slug) {
|
|
4288
4318
|
const entry = connectorBySlug(slug);
|
|
4289
4319
|
if (!entry) return { ok: false, error: `unknown connector '${slug}' \u2014 run \`oriro connectors list\`` };
|
|
@@ -4297,13 +4327,20 @@ function addedConnectors() {
|
|
|
4297
4327
|
return CONNECTOR_CATALOG.filter((c) => added.has(c.slug));
|
|
4298
4328
|
}
|
|
4299
4329
|
function removeConnector(slug) {
|
|
4300
|
-
|
|
4330
|
+
const before = readAdded();
|
|
4331
|
+
if (!before.includes(slug)) return false;
|
|
4332
|
+
writeAdded(before.filter((s) => s !== slug));
|
|
4333
|
+
return true;
|
|
4301
4334
|
}
|
|
4302
4335
|
|
|
4303
4336
|
// src/commands/connectors.ts
|
|
4304
4337
|
function registerConnectorsCommand(program2) {
|
|
4305
4338
|
const connectors = program2.command("connectors").description("MCP connectors \u2014 add external tools/services (inert until used)");
|
|
4306
4339
|
connectors.command("list [category]").description("list the connector catalog (optionally filtered by category)").action((category) => {
|
|
4340
|
+
if (category && !connectorCategories().includes(category)) {
|
|
4341
|
+
info(`unknown category '${category}' \u2014 categories: ${connectorCategories().join(", ")}`);
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4307
4344
|
const entries = listConnectors(category);
|
|
4308
4345
|
const added = new Set(addedConnectors().map((c) => c.slug));
|
|
4309
4346
|
heading(category ? `Connectors \xB7 ${category}` : "Connectors");
|
|
@@ -4320,8 +4357,8 @@ function registerConnectorsCommand(program2) {
|
|
|
4320
4357
|
ok(`added ${accent(slug)} \u2014 inert until a session uses it`);
|
|
4321
4358
|
});
|
|
4322
4359
|
connectors.command("remove <slug>").description("remove a connector").action((slug) => {
|
|
4323
|
-
removeConnector(slug);
|
|
4324
|
-
|
|
4360
|
+
if (removeConnector(slug)) ok(`removed ${accent(slug)}`);
|
|
4361
|
+
else info(`'${slug}' is not in your added list \u2014 nothing to remove`);
|
|
4325
4362
|
});
|
|
4326
4363
|
}
|
|
4327
4364
|
|
|
@@ -4571,6 +4608,10 @@ function registerChannelsCommand(program2) {
|
|
|
4571
4608
|
});
|
|
4572
4609
|
channels.command("remove <kind>").description("remove a configured channel").action((kind) => {
|
|
4573
4610
|
if (!isKind(kind)) die(`unknown channel '${kind}' \u2014 one of: ${KINDS.join(", ")}`);
|
|
4611
|
+
if (!readChannels().some((c) => c.kind === kind)) {
|
|
4612
|
+
info(`no ${kind} channel configured \u2014 nothing to remove`);
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4574
4615
|
removeChannel(kind);
|
|
4575
4616
|
ok(`removed ${accent(kind)}`);
|
|
4576
4617
|
});
|
|
@@ -4595,6 +4636,9 @@ function registerSkillsCommand(program2) {
|
|
|
4595
4636
|
|
|
4596
4637
|
// src/commands/language.ts
|
|
4597
4638
|
import { stdin as stdin5 } from "process";
|
|
4639
|
+
function resolveLanguage(input) {
|
|
4640
|
+
return languageByCode(input) ?? LANGUAGES.find((l) => l.name.toLowerCase() === input.trim().toLowerCase());
|
|
4641
|
+
}
|
|
4598
4642
|
function registerLanguageCommand(program2) {
|
|
4599
4643
|
program2.command("language").description("show or change your terminal language").argument("[code]", "switch directly to this language (ISO code or name, e.g. es)").option("-a, --all", "list every available language").action(async (code, opts) => {
|
|
4600
4644
|
if (opts.all) {
|
|
@@ -4607,7 +4651,7 @@ function registerLanguageCommand(program2) {
|
|
|
4607
4651
|
return;
|
|
4608
4652
|
}
|
|
4609
4653
|
if (code) {
|
|
4610
|
-
const lang =
|
|
4654
|
+
const lang = resolveLanguage(code);
|
|
4611
4655
|
if (!lang) die(`unknown language '${code}' \u2014 run \`oriro language --all\` to see the list`);
|
|
4612
4656
|
setTerminalLanguage(lang);
|
|
4613
4657
|
ok(`${accent(lang.name)} is now your terminal language.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oriro/orirocli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "ORIRO — a free, on-device-friendly terminal AI agent. Built on the Pi agent harness (used as a library).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dev": "tsx src/cli.ts",
|
|
23
23
|
"build": "tsup",
|
|
24
24
|
"typecheck": "tsc --noEmit",
|
|
25
|
-
"test:unit": "tsx scripts/test-tool-sanitize.ts",
|
|
25
|
+
"test:unit": "tsx scripts/test-tool-sanitize.ts && tsx scripts/test-guardian.ts",
|
|
26
26
|
"smoke": "npm run build && node scripts/smoke.mjs",
|
|
27
27
|
"prepublishOnly": "npm run build && npm run test:unit && node scripts/smoke.mjs && node scripts/prepublish-check.mjs",
|
|
28
28
|
"start": "node dist/cli.js"
|