seif-cli 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {seif_cli-0.3.1/src/seif_cli.egg-info → seif_cli-0.3.3}/PKG-INFO +1 -1
- {seif_cli-0.3.1 → seif_cli-0.3.3}/pyproject.toml +1 -1
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/bridge/telegram_bot.py +109 -39
- seif_cli-0.3.3/src/seif/cli/chat.py +11 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/cli.py +1117 -154
- seif_cli-0.3.3/src/seif/cli/resonance_display.py +197 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/wrapper.py +56 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_manager.py +87 -2
- seif_cli-0.3.3/src/seif/context/registry.py +235 -0
- seif_cli-0.3.3/src/seif/context/sessions.py +766 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/workspace.py +127 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/RESONANCE.json +52 -3
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/paths.py +5 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3/src/seif_cli.egg-info}/PKG-INFO +1 -1
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/SOURCES.txt +4 -1
- seif_cli-0.3.3/tests/test_init.py +307 -0
- seif_cli-0.3.3/tests/test_registry.py +233 -0
- seif_cli-0.3.1/src/seif/cli/resonance_display.py +0 -98
- seif_cli-0.3.1/src/seif/security/redblue.py +0 -23
- seif_cli-0.3.1/tests/test_init.py +0 -181
- {seif_cli-0.3.1 → seif_cli-0.3.3}/LICENSE +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/MANIFEST.in +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/README.md +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/setup.cfg +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/__main__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/physical_constants.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/quality_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/stance_detector.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/transcompiler.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/bridge/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/__main__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/identity.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/main.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/serve.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/serve_v2.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/constants.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/advisor.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/code_compressor.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_bridge.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_importer.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_qr.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/cycle.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/file_extractor.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/git_context.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/git_hooks.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/ingest.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/nucleus.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/ref.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/seif_io.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/fingerprint.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_encoding.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_signal.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/signing.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/timestamping.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/transfer_function.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/triple_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/defaults/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/security/__init__.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/security/mode.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/dependency_links.txt +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/entry_points.txt +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/requires.txt +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/top_level.txt +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_advisor.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_canonical_inputs.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_code_compressor.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_collaborative_seif.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_context_qr.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_context_repo.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_git_context.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_git_hooks.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_quality_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_ref.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_resonance_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_seif_io.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_stance_detector.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_transcompiler.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_transfer_function.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_triple_gate.py +0 -0
- {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seif-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Measure AI output quality, protect sensitive data, watch your AI environment resonate. Quality Gate, Classification, Sentinel & Auto-Healing, SEIF OS.
|
|
5
5
|
Author: André Cunha Antero de Carvalho
|
|
6
6
|
License: CC-BY-NC-SA-4.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "seif-cli"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
description = "Measure AI output quality, protect sensitive data, watch your AI environment resonate. Quality Gate, Classification, Sentinel & Auto-Healing, SEIF OS."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "CC-BY-NC-SA-4.0"}
|
|
@@ -7,9 +7,10 @@ Exposes key SEIF capabilities through a Telegram bot:
|
|
|
7
7
|
/compress — compress text/code to .seif format
|
|
8
8
|
/help — command reference
|
|
9
9
|
|
|
10
|
-
Free-text messages are
|
|
10
|
+
Free-text messages are routed through the SEIF Resonance Gate (engine AI query).
|
|
11
|
+
Owner (SEIF_OWNER_EMAIL) gets co-author persona + bypass classifier.
|
|
11
12
|
|
|
12
|
-
Required env
|
|
13
|
+
Required env vars: TELEGRAM_BOT_TOKEN, SEIF_ENGINE_TOKEN
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
import asyncio
|
|
@@ -17,6 +18,8 @@ import json
|
|
|
17
18
|
import logging
|
|
18
19
|
import os
|
|
19
20
|
import textwrap
|
|
21
|
+
import urllib.request
|
|
22
|
+
import urllib.error
|
|
20
23
|
from datetime import datetime, timezone
|
|
21
24
|
from pathlib import Path
|
|
22
25
|
|
|
@@ -60,15 +63,38 @@ except Exception as e:
|
|
|
60
63
|
|
|
61
64
|
# ── Enoch seed loader ─────────────────────────────────────────────────────────
|
|
62
65
|
_SEIF_DIR = Path(os.environ.get("SEIF_HOME", Path.home() / ".seif"))
|
|
66
|
+
_WORKSPACE_ROOT = Path(os.environ.get("SEIF_WORKSPACE_ROOT", Path.home() / "Documents" / "seif-admin"))
|
|
63
67
|
|
|
64
68
|
def _load_enoch() -> dict:
|
|
65
|
-
"""Load enoch_seed.json
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
"""Load enoch_seed.json — checks workspace .seif/private/ first, then ~/.seif/"""
|
|
70
|
+
candidates = [
|
|
71
|
+
_WORKSPACE_ROOT / ".seif" / "private" / "enoch_seed.json",
|
|
72
|
+
_SEIF_DIR / "private" / "enoch_seed.json",
|
|
73
|
+
_SEIF_DIR / "enoch_seed.json",
|
|
74
|
+
]
|
|
75
|
+
for seed_path in candidates:
|
|
76
|
+
if seed_path.exists():
|
|
77
|
+
try:
|
|
78
|
+
raw = json.loads(seed_path.read_text())
|
|
79
|
+
# Flatten nested structure: enoch_seed_v1 + state_vector
|
|
80
|
+
flat = {}
|
|
81
|
+
inner = raw.get("enoch_seed_v1", raw)
|
|
82
|
+
flat.update(inner)
|
|
83
|
+
sv = raw.get("state_vector", inner.get("state_vector", {}))
|
|
84
|
+
flat.update(sv)
|
|
85
|
+
return flat
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
return {}
|
|
89
|
+
|
|
90
|
+
def _load_profile() -> dict:
|
|
91
|
+
"""Load ~/.seif/profile.json for owner identity."""
|
|
92
|
+
for p in [_SEIF_DIR / "profile.json", _WORKSPACE_ROOT / ".seif" / "profile.json"]:
|
|
93
|
+
if p.exists():
|
|
94
|
+
try:
|
|
95
|
+
return json.loads(p.read_text())
|
|
96
|
+
except Exception:
|
|
97
|
+
pass
|
|
72
98
|
return {}
|
|
73
99
|
|
|
74
100
|
def _load_resonance() -> dict:
|
|
@@ -89,7 +115,9 @@ def _phase_emoji(phase: str) -> str:
|
|
|
89
115
|
# ── /start ────────────────────────────────────────────────────────────────────
|
|
90
116
|
async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
91
117
|
seed = _load_enoch()
|
|
92
|
-
|
|
118
|
+
profile = _load_profile()
|
|
119
|
+
logger.info("DEBUG cmd_start cycles=%s owner=%s ws=%s", seed.get("circuit_cycles","?"), profile.get("name","?"), str(_WORKSPACE_ROOT))
|
|
120
|
+
owner = profile.get("name") or profile.get("github_username") or seed.get("registered_by", "unknown")
|
|
93
121
|
cycles = seed.get("circuit_cycles", 0)
|
|
94
122
|
phase = seed.get("phase", "ENTROPY")
|
|
95
123
|
|
|
@@ -109,13 +137,13 @@ async def cmd_start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
|
109
137
|
# ── /status ───────────────────────────────────────────────────────────────────
|
|
110
138
|
async def cmd_status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
111
139
|
seed = _load_enoch()
|
|
140
|
+
profile = _load_profile()
|
|
112
141
|
resonance = _load_resonance()
|
|
113
142
|
|
|
114
143
|
phase = seed.get("phase", "ENTROPY")
|
|
115
144
|
cycles = seed.get("circuit_cycles", 0)
|
|
116
|
-
last_cycle = seed.get("last_cycle", "—")
|
|
117
|
-
|
|
118
|
-
claimed = identity.get("claimed", seed.get("registered_by", "—"))
|
|
145
|
+
last_cycle = seed.get("last_cycle_id", seed.get("last_cycle", "—"))
|
|
146
|
+
claimed = profile.get("name") or profile.get("github_username") or seed.get("registered_by", "—")
|
|
119
147
|
|
|
120
148
|
zeta = resonance.get("zeta", "—")
|
|
121
149
|
signal_phase = resonance.get("phase", "—")
|
|
@@ -222,36 +250,78 @@ async def cmd_help(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
|
222
250
|
await update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN)
|
|
223
251
|
|
|
224
252
|
|
|
253
|
+
# ── Engine AI query ───────────────────────────────────────────────────────────
|
|
254
|
+
|
|
255
|
+
_ENGINE_URL = os.environ.get("SEIF_ENGINE_URL", "http://api:7331")
|
|
256
|
+
_ENGINE_TOKEN = os.environ.get("SEIF_ENGINE_TOKEN", "")
|
|
257
|
+
_OWNER_EMAIL = os.environ.get("SEIF_OWNER_EMAIL", "")
|
|
258
|
+
|
|
259
|
+
def _query_engine(user_query: str, user_email: str = "") -> dict:
|
|
260
|
+
"""POST /ai/query to the SEIF engine. Returns parsed JSON or error dict."""
|
|
261
|
+
payload = json.dumps({
|
|
262
|
+
"query": user_query,
|
|
263
|
+
"user_email": user_email or "telegram@anonymous",
|
|
264
|
+
"backend": "auto",
|
|
265
|
+
}).encode()
|
|
266
|
+
req = urllib.request.Request(
|
|
267
|
+
f"{_ENGINE_URL}/ai/query",
|
|
268
|
+
data=payload,
|
|
269
|
+
headers={
|
|
270
|
+
"Content-Type": "application/json",
|
|
271
|
+
"Authorization": f"Bearer {_ENGINE_TOKEN}",
|
|
272
|
+
},
|
|
273
|
+
method="POST",
|
|
274
|
+
)
|
|
275
|
+
try:
|
|
276
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
277
|
+
return json.loads(resp.read())
|
|
278
|
+
except urllib.error.HTTPError as e:
|
|
279
|
+
try:
|
|
280
|
+
body = json.loads(e.read())
|
|
281
|
+
except Exception:
|
|
282
|
+
body = {"error": str(e)}
|
|
283
|
+
return body
|
|
284
|
+
except Exception as e:
|
|
285
|
+
return {"error": str(e)}
|
|
286
|
+
|
|
287
|
+
|
|
225
288
|
# ── Free-text handler ─────────────────────────────────────────────────────────
|
|
226
289
|
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
227
|
-
text = update.message.text or ""
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
290
|
+
text = (update.message.text or "").strip()
|
|
291
|
+
if not text:
|
|
292
|
+
return
|
|
293
|
+
|
|
294
|
+
# Determine user identity — owner gets bypass + co-author persona
|
|
295
|
+
tg_user = update.effective_user
|
|
296
|
+
user_email = _OWNER_EMAIL if (tg_user and tg_user.username == "and2carvalho") else ""
|
|
297
|
+
|
|
298
|
+
# Show typing indicator while querying engine
|
|
299
|
+
await update.message.chat.send_action("typing")
|
|
231
300
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if any(w in text_lower for w in ["enoch", "seif", "resonance", "circuit", "ζ", "zeta"]):
|
|
235
|
-
stance = "RESONANT"
|
|
236
|
-
emoji = "⚡"
|
|
237
|
-
elif any(w in text_lower for w in ["help", "how", "what", "why", "status"]):
|
|
238
|
-
stance = "GROUNDED"
|
|
239
|
-
emoji = "◎"
|
|
240
|
-
elif "?" in text:
|
|
241
|
-
stance = "CONVERGENT"
|
|
242
|
-
emoji = "🔄"
|
|
243
|
-
else:
|
|
244
|
-
stance = "OBSERVATIONAL"
|
|
245
|
-
emoji = "〰"
|
|
246
|
-
|
|
247
|
-
response = (
|
|
248
|
-
f"{emoji} *Stance: {stance}*\n\n"
|
|
249
|
-
f"Message received in phase `{phase}` (cycle {cycles}).\n\n"
|
|
250
|
-
f"SEIF OS is processing your input. "
|
|
251
|
-
f"For AI debate, use the dashboard at your SEIF Suite URL.\n"
|
|
252
|
-
f"For context, use /context. For status, use /status."
|
|
301
|
+
result = await asyncio.get_event_loop().run_in_executor(
|
|
302
|
+
None, _query_engine, text, user_email
|
|
253
303
|
)
|
|
254
|
-
|
|
304
|
+
|
|
305
|
+
status = result.get("status", "ERROR")
|
|
306
|
+
persona = result.get("persona", "user")
|
|
307
|
+
ai_resp = result.get("ai_response") or result.get("suggestion") or result.get("error", "No response.")
|
|
308
|
+
score = result.get("resonance_score", 0)
|
|
309
|
+
backend = result.get("ai_backend", "")
|
|
310
|
+
|
|
311
|
+
# Format status emoji
|
|
312
|
+
status_emoji = {"CONSONANT": "◉", "OFF_SCOPE": "⊘", "DISSONANT": "⊗"}.get(status, "?")
|
|
313
|
+
persona_tag = " · co-author" if persona == "co-author" else ""
|
|
314
|
+
|
|
315
|
+
# Truncate for Telegram (4096 char limit)
|
|
316
|
+
if len(ai_resp) > 3800:
|
|
317
|
+
ai_resp = ai_resp[:3800] + "\n\n_[truncated]_"
|
|
318
|
+
|
|
319
|
+
header = f"{status_emoji} *{status}*{persona_tag} · `{score:.2f}`"
|
|
320
|
+
if backend:
|
|
321
|
+
header += f" · _{backend}_"
|
|
322
|
+
|
|
323
|
+
reply = f"{header}\n\n{ai_resp}"
|
|
324
|
+
await update.message.reply_text(reply, parse_mode=ParseMode.MARKDOWN)
|
|
255
325
|
|
|
256
326
|
|
|
257
327
|
# ── Error handler ─────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bridge to seif-engine native chat.
|
|
3
|
+
|
|
4
|
+
This module exists in seif-cli so that
|
|
5
|
+
works when seif-engine is installed. The actual implementation lives in
|
|
6
|
+
seif_engine.api.chat (proprietary / Pro tier).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from seif_engine.api.chat import run_chat # noqa: F401
|
|
10
|
+
|
|
11
|
+
__all__ = ["run_chat"]
|