antahkarana-cli 0.1.0__py3-none-any.whl

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.
ant/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ # Author - Deepak Soni
2
+ """ant — the Antaḥkaraṇa governed-AI operator CLI. `pip install antahkarana-cli`, run `ant`, prompt your copilot."""
3
+ __version__ = "0.1.0"
ant/cli.py ADDED
@@ -0,0 +1,179 @@
1
+ # Author - Deepak Soni
2
+ """ant — Antaḥkaraṇa governed-AI operator CLI.
3
+
4
+ `pip install antahkarana-cli` → run `ant` → connect to your copilot → prompt it. It investigates a machine,
5
+ reasons, runs read-only commands immediately, and asks y/N before any state-changing action (catastrophic
6
+ commands are hard-blocked server-side). Thin client over the copilot's /api/chat (the model + control ring).
7
+
8
+ Commands:
9
+ ant interactive REPL (banner + prompt)
10
+ ant "check open ports" one-shot
11
+ ant connect <url> save the copilot endpoint
12
+ ant login <token> save an auth token (sent as Bearer)
13
+ ant status show connection + model health
14
+ In the REPL, slash commands: /connect /login /model /status /help /clear /exit
15
+ """
16
+ import json, os, sys, urllib.request, urllib.error
17
+
18
+ # ── cross-OS terminal setup (Windows / macOS / Linux) ──
19
+ try: # never crash on non-UTF-8 consoles (e.g. Windows cmd)
20
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
21
+ except Exception:
22
+ pass
23
+ if os.name == "nt":
24
+ os.system("") # enable ANSI escape processing on Windows 10+
25
+ _COLOR = sys.stdout.isatty() and os.environ.get("NO_COLOR") is None
26
+ _uni = (getattr(sys.stdout, "encoding", "") or "").lower().startswith("utf")
27
+ TOOL_ICON, WARN_ICON = ("🔧", "⚠") if _uni else ("[*]", "[!]")
28
+
29
+ CFG_DIR = os.path.expanduser("~/.ant")
30
+ CFG = os.path.join(CFG_DIR, "config.json")
31
+ DEFAULT_URL = "http://129.146.3.254:8090"
32
+ _RAW = {"g": "\033[32m", "y": "\033[33m", "r": "\033[31m", "c": "\033[36m", "b": "\033[1m", "d": "\033[2m", "x": "\033[0m"}
33
+ C = {k: (v if _COLOR else "") for k, v in _RAW.items()}
34
+
35
+ if _uni:
36
+ _ART = " ▄▀█ █▄░█ ▀█▀ · Antaḥkaraṇa\n █▀█ █░▀█ ░█░ · governed AI operator"
37
+ else:
38
+ _ART = " a n t : Antahkarana\n governed AI operator"
39
+ BANNER = f"{C['c']}{C['b']}\n{_ART}{C['x']}{C['d']}\n prompt a machine - read-only runs - changes need y/N - catastrophic blocked{C['x']}\n"
40
+
41
+
42
+ def load():
43
+ try:
44
+ return json.load(open(CFG))
45
+ except Exception:
46
+ return {"url": DEFAULT_URL, "token": "", "model": ""}
47
+
48
+
49
+ def save(cfg):
50
+ os.makedirs(CFG_DIR, exist_ok=True)
51
+ json.dump(cfg, open(CFG, "w"), indent=2)
52
+
53
+
54
+ def _headers(cfg):
55
+ h = {"Content-Type": "application/json"}
56
+ if cfg.get("token"):
57
+ h["Authorization"] = "Bearer " + cfg["token"]
58
+ return h
59
+
60
+
61
+ def health(cfg):
62
+ try:
63
+ req = urllib.request.Request(cfg["url"].rstrip("/") + "/api/health", headers=_headers(cfg))
64
+ return json.load(urllib.request.urlopen(req, timeout=8))
65
+ except Exception as e: # noqa: BLE001
66
+ return {"error": str(e)}
67
+
68
+
69
+ def chat(cfg, history, approved):
70
+ """Stream the agent's steps; return commands awaiting approval."""
71
+ body = json.dumps({"messages": history, "approved": approved}).encode()
72
+ req = urllib.request.Request(cfg["url"].rstrip("/") + "/api/chat", body, _headers(cfg))
73
+ pending, buf = [], ""
74
+ with urllib.request.urlopen(req, timeout=300) as r:
75
+ for chunk in r:
76
+ buf += chunk.decode("utf-8", "ignore")
77
+ while "\n\n" in buf:
78
+ line, buf = buf.split("\n\n", 1)
79
+ line = line.strip()
80
+ if not line.startswith("data:"):
81
+ continue
82
+ e = json.loads(line[5:].strip()); t = e.get("type")
83
+ if t == "tool":
84
+ col = {"allow": C["g"], "soft_block": C["y"], "hard_block": C["r"]}.get(e["tier"], "")
85
+ print(f" {C['d']}{TOOL_ICON} {e['name']}({e.get('target','')}){C['x']} {col}[{e['tier']}]{C['x']}")
86
+ elif t == "approval":
87
+ pending.append(e["command"])
88
+ elif t == "message":
89
+ print(f"\n{e.get('markdown','')}\n")
90
+ history.append({"role": "assistant", "content": e.get("markdown", "")})
91
+ elif t == "error":
92
+ print(f" {C['r']}error: {e['text']}{C['x']}")
93
+ return pending
94
+
95
+
96
+ def ask(cfg, history, approved, q):
97
+ history.append({"role": "user", "content": q})
98
+ pending = chat(cfg, history, approved)
99
+ while pending:
100
+ granted = False
101
+ for cmd in pending:
102
+ a = input(f" {C['y']}{WARN_ICON} approve state-changing command?{C['x']} {C['b']}{cmd}{C['x']} [y/N] ").strip().lower()
103
+ if a == "y":
104
+ granted = True
105
+ if cmd not in approved:
106
+ approved.append(cmd)
107
+ history.append({"role": "user", "content": "Approved — run the approved command(s) now."
108
+ if granted else "Denied — do not run that; stop or suggest a safer alternative."})
109
+ pending = chat(cfg, history, approved)
110
+
111
+
112
+ def status(cfg):
113
+ h = health(cfg)
114
+ ok = "error" not in h
115
+ print(f" endpoint : {cfg['url']}")
116
+ print(f" auth : {'token set' if cfg.get('token') else 'none'}")
117
+ if ok:
118
+ print(f" copilot : {C['g']}up{C['x']} model: {h.get('model','?')} llm: {'ready' if h.get('llm_ready') else 'loading'}")
119
+ else:
120
+ print(f" copilot : {C['r']}unreachable{C['x']} ({h['error']})")
121
+
122
+
123
+ def repl(cfg):
124
+ print(BANNER)
125
+ status(cfg)
126
+ print(f" {C['d']}type a prompt, or /help for commands{C['x']}\n")
127
+ history, approved = [], []
128
+ while True:
129
+ try:
130
+ q = input(f"{C['b']}{C['c']}ant>{C['x']} ").strip()
131
+ except (EOFError, KeyboardInterrupt):
132
+ print(); break
133
+ if not q:
134
+ continue
135
+ if q.startswith("/"):
136
+ parts = q[1:].split(maxsplit=1); cmd = parts[0]; arg = parts[1] if len(parts) > 1 else ""
137
+ if cmd in ("exit", "quit"):
138
+ break
139
+ elif cmd == "help":
140
+ print(" /connect <url> /login <token> /model /status /clear /exit")
141
+ elif cmd == "connect":
142
+ cfg["url"] = arg or cfg["url"]; save(cfg); status(cfg)
143
+ elif cmd == "login":
144
+ cfg["token"] = arg; save(cfg); print(" token saved")
145
+ elif cmd == "model":
146
+ print(f" model: {health(cfg).get('model','?')} (served by the copilot)")
147
+ elif cmd == "status":
148
+ status(cfg)
149
+ elif cmd == "clear":
150
+ history, approved = [], []; print(" conversation cleared")
151
+ else:
152
+ print(f" unknown command: /{cmd}")
153
+ continue
154
+ try:
155
+ ask(cfg, history, approved, q)
156
+ except urllib.error.HTTPError as e:
157
+ print(f" {C['r']}HTTP {e.code}: {e.read().decode('utf-8','ignore')[:160]}{C['x']}")
158
+ except Exception as e: # noqa: BLE001
159
+ print(f" {C['r']}request failed: {e}{C['x']}")
160
+
161
+
162
+ def main():
163
+ cfg = load()
164
+ a = sys.argv[1:]
165
+ if not a:
166
+ repl(cfg); return
167
+ if a[0] == "connect" and len(a) > 1:
168
+ cfg["url"] = a[1]; save(cfg); print(f"connected to {a[1]}"); status(cfg)
169
+ elif a[0] == "login" and len(a) > 1:
170
+ cfg["token"] = a[1]; save(cfg); print("token saved")
171
+ elif a[0] == "status":
172
+ status(cfg)
173
+ else: # one-shot prompt
174
+ print(BANNER)
175
+ ask(cfg, [], [], " ".join(a))
176
+
177
+
178
+ if __name__ == "__main__":
179
+ main()
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: antahkarana-cli
3
+ Version: 0.1.0
4
+ Summary: ant — the Antaḥkaraṇa governed-AI operator CLI: prompt your on-box copilot to investigate/operate a machine, read-only by default, with y/N approval for changes and catastrophic commands hard-blocked.
5
+ Author: Deepak Soni
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://pypi.org/project/antahkarana/
8
+ Keywords: llm,agent,cli,security,mcp,antahkarana,governed,ssh
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+
12
+ # ant — Antaḥkaraṇa governed-AI operator CLI
13
+
14
+ Author — Deepak Soni. A tiny, dependency-free CLI that prompts your **on-box copilot** (the Antaḥkaraṇa model +
15
+ control ring) from any terminal — Claude-Code style. It investigates a machine, reasons, runs **read-only**
16
+ commands immediately, and asks **y/N before any state-changing action**; catastrophic commands are hard-blocked
17
+ server-side.
18
+
19
+ ## Install
20
+ ```bash
21
+ pip install antahkarana-cli
22
+ ```
23
+
24
+ ## Use
25
+ ```bash
26
+ ant connect http://YOUR-BOX:8090 # point it at your copilot (saved to ~/.ant/config.json)
27
+ ant # interactive: banner + prompt
28
+ ant "what is listening on this server?" # one-shot
29
+ ant status # connection + model health
30
+ ```
31
+ In the REPL, slash commands: `/connect <url>` · `/login <token>` · `/model` · `/status` · `/clear` · `/exit`.
32
+
33
+ ## What you can ask
34
+ - `what OS is this and what's listening on its ports?` → runs read-only, reports
35
+ - `create a file /tmp/demo.txt` → proposes it, asks **[y/N]**, runs only if you approve
36
+ - `rm -rf /tmp/x` → **hard-blocked** by the control ring
37
+ - `assess example.com` → passive web-recon → prioritized report
38
+
39
+ ## How it works
40
+ `ant` is a thin client over the copilot's `/api/chat` — the model (e.g. Qwen2.5-14B), the governed `run_shell`,
41
+ the web-recon tools, and the control ring all live on the box (or a remote SSH target the copilot is pointed at).
42
+ Nothing runs locally; every decision is governed and audited server-side.
43
+
44
+ Requires a running Antaḥkaraṇa copilot (see `antahkarana-net/box/copilot/`).
@@ -0,0 +1,7 @@
1
+ ant/__init__.py,sha256=2l5J6_CrEfngomOjmced3POM7OdTSnQQjs0Ehy3PTWE,168
2
+ ant/cli.py,sha256=OlFewO69SkpQlBrW60DwN4pptXKHvTFoSJfhM86YozE,7347
3
+ antahkarana_cli-0.1.0.dist-info/METADATA,sha256=GpjBWAhHljzqXfFd1DNcC7T3mO9bwP3n8zO4TBVKB0U,2100
4
+ antahkarana_cli-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ antahkarana_cli-0.1.0.dist-info/entry_points.txt,sha256=Y6KfPuLvtohyfYX-g7h645Zbr140zodtjBoW2hJx2PU,37
6
+ antahkarana_cli-0.1.0.dist-info/top_level.txt,sha256=8g98uTVZGWavv2MVXE4KhTMrVT3XOxBl6Hh9Wh_wGAg,4
7
+ antahkarana_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ant = ant.cli:main
@@ -0,0 +1 @@
1
+ ant