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.
Files changed (87) hide show
  1. {seif_cli-0.3.1/src/seif_cli.egg-info → seif_cli-0.3.3}/PKG-INFO +1 -1
  2. {seif_cli-0.3.1 → seif_cli-0.3.3}/pyproject.toml +1 -1
  3. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/bridge/telegram_bot.py +109 -39
  4. seif_cli-0.3.3/src/seif/cli/chat.py +11 -0
  5. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/cli.py +1117 -154
  6. seif_cli-0.3.3/src/seif/cli/resonance_display.py +197 -0
  7. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/wrapper.py +56 -0
  8. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_manager.py +87 -2
  9. seif_cli-0.3.3/src/seif/context/registry.py +235 -0
  10. seif_cli-0.3.3/src/seif/context/sessions.py +766 -0
  11. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/workspace.py +127 -0
  12. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/RESONANCE.json +52 -3
  13. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/paths.py +5 -0
  14. {seif_cli-0.3.1 → seif_cli-0.3.3/src/seif_cli.egg-info}/PKG-INFO +1 -1
  15. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/SOURCES.txt +4 -1
  16. seif_cli-0.3.3/tests/test_init.py +307 -0
  17. seif_cli-0.3.3/tests/test_registry.py +233 -0
  18. seif_cli-0.3.1/src/seif/cli/resonance_display.py +0 -98
  19. seif_cli-0.3.1/src/seif/security/redblue.py +0 -23
  20. seif_cli-0.3.1/tests/test_init.py +0 -181
  21. {seif_cli-0.3.1 → seif_cli-0.3.3}/LICENSE +0 -0
  22. {seif_cli-0.3.1 → seif_cli-0.3.3}/MANIFEST.in +0 -0
  23. {seif_cli-0.3.1 → seif_cli-0.3.3}/README.md +0 -0
  24. {seif_cli-0.3.1 → seif_cli-0.3.3}/setup.cfg +0 -0
  25. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/__init__.py +0 -0
  26. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/__main__.py +0 -0
  27. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/__init__.py +0 -0
  28. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/physical_constants.py +0 -0
  29. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/quality_gate.py +0 -0
  30. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/stance_detector.py +0 -0
  31. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/analysis/transcompiler.py +0 -0
  32. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/bridge/__init__.py +0 -0
  33. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/__init__.py +0 -0
  34. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/__main__.py +0 -0
  35. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/identity.py +0 -0
  36. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/main.py +0 -0
  37. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/serve.py +0 -0
  38. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/cli/serve_v2.py +0 -0
  39. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/constants.py +0 -0
  40. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/__init__.py +0 -0
  41. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/advisor.py +0 -0
  42. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/code_compressor.py +0 -0
  43. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_bridge.py +0 -0
  44. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_importer.py +0 -0
  45. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/context_qr.py +0 -0
  46. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/cycle.py +0 -0
  47. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/file_extractor.py +0 -0
  48. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/git_context.py +0 -0
  49. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/git_hooks.py +0 -0
  50. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/ingest.py +0 -0
  51. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/nucleus.py +0 -0
  52. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/ref.py +0 -0
  53. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/context/seif_io.py +0 -0
  54. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/__init__.py +0 -0
  55. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/fingerprint.py +0 -0
  56. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_encoding.py +0 -0
  57. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_gate.py +0 -0
  58. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/resonance_signal.py +0 -0
  59. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/signing.py +0 -0
  60. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/timestamping.py +0 -0
  61. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/transfer_function.py +0 -0
  62. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/core/triple_gate.py +0 -0
  63. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/__init__.py +0 -0
  64. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/data/defaults/__init__.py +0 -0
  65. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/security/__init__.py +0 -0
  66. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif/security/mode.py +0 -0
  67. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/dependency_links.txt +0 -0
  68. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/entry_points.txt +0 -0
  69. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/requires.txt +0 -0
  70. {seif_cli-0.3.1 → seif_cli-0.3.3}/src/seif_cli.egg-info/top_level.txt +0 -0
  71. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_advisor.py +0 -0
  72. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_canonical_inputs.py +0 -0
  73. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_code_compressor.py +0 -0
  74. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_collaborative_seif.py +0 -0
  75. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_context_qr.py +0 -0
  76. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_context_repo.py +0 -0
  77. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_git_context.py +0 -0
  78. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_git_hooks.py +0 -0
  79. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_quality_gate.py +0 -0
  80. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_ref.py +0 -0
  81. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_resonance_gate.py +0 -0
  82. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_seif_io.py +0 -0
  83. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_stance_detector.py +0 -0
  84. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_transcompiler.py +0 -0
  85. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_transfer_function.py +0 -0
  86. {seif_cli-0.3.1 → seif_cli-0.3.3}/tests/test_triple_gate.py +0 -0
  87. {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.1
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.1"
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 answered with SEIF context awareness.
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 var: TELEGRAM_BOT_TOKEN
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 from ~/.seif/"""
66
- seed_path = _SEIF_DIR / "enoch_seed.json"
67
- if seed_path.exists():
68
- try:
69
- return json.loads(seed_path.read_text())
70
- except Exception:
71
- pass
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
- owner = seed.get("registered_by", "unknown")
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
- identity = seed.get("identity_commitment", {})
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
- seed = _load_enoch()
229
- phase = seed.get("phase", "ENTROPY")
230
- cycles = seed.get("circuit_cycles", 0)
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
- # Basic resonance classification
233
- text_lower = text.lower()
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
- await update.message.reply_text(response, parse_mode=ParseMode.MARKDOWN)
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"]