riciplay-cli 1.7.0__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 (96) hide show
  1. riciplay_cli-1.7.0/MANIFEST.in +1 -0
  2. riciplay_cli-1.7.0/PKG-INFO +12 -0
  3. riciplay_cli-1.7.0/pyproject.toml +27 -0
  4. riciplay_cli-1.7.0/riciplay_cli/__init__.py +2 -0
  5. riciplay_cli-1.7.0/riciplay_cli/auto_updater.py +250 -0
  6. riciplay_cli-1.7.0/riciplay_cli/chat_engine.py +797 -0
  7. riciplay_cli-1.7.0/riciplay_cli/client.py +349 -0
  8. riciplay_cli-1.7.0/riciplay_cli/cmd_ai.py +412 -0
  9. riciplay_cli-1.7.0/riciplay_cli/cmd_auth.py +175 -0
  10. riciplay_cli-1.7.0/riciplay_cli/cmd_chat.py +542 -0
  11. riciplay_cli-1.7.0/riciplay_cli/cmd_gateway.py +376 -0
  12. riciplay_cli-1.7.0/riciplay_cli/cmd_init.py +216 -0
  13. riciplay_cli-1.7.0/riciplay_cli/cmd_monitor.py +82 -0
  14. riciplay_cli-1.7.0/riciplay_cli/cmd_recon.py +135 -0
  15. riciplay_cli-1.7.0/riciplay_cli/cmd_repair.py +116 -0
  16. riciplay_cli-1.7.0/riciplay_cli/cmd_report.py +300 -0
  17. riciplay_cli-1.7.0/riciplay_cli/cmd_review.py +696 -0
  18. riciplay_cli-1.7.0/riciplay_cli/cmd_scan.py +471 -0
  19. riciplay_cli-1.7.0/riciplay_cli/cmd_update.py +121 -0
  20. riciplay_cli-1.7.0/riciplay_cli/command_palette.py +275 -0
  21. riciplay_cli-1.7.0/riciplay_cli/compressor.py +276 -0
  22. riciplay_cli-1.7.0/riciplay_cli/config.py +211 -0
  23. riciplay_cli-1.7.0/riciplay_cli/credits.py +463 -0
  24. riciplay_cli-1.7.0/riciplay_cli/display.py +83 -0
  25. riciplay_cli-1.7.0/riciplay_cli/error_taxonomy.py +169 -0
  26. riciplay_cli-1.7.0/riciplay_cli/investigation/__init__.py +6 -0
  27. riciplay_cli-1.7.0/riciplay_cli/investigation/checkpoint_writer.py +305 -0
  28. riciplay_cli-1.7.0/riciplay_cli/investigation/context_assembler.py +322 -0
  29. riciplay_cli-1.7.0/riciplay_cli/investigation/leader.py +153 -0
  30. riciplay_cli-1.7.0/riciplay_cli/investigation/orchestrator.py +641 -0
  31. riciplay_cli-1.7.0/riciplay_cli/investigation/permission_gate.py +101 -0
  32. riciplay_cli-1.7.0/riciplay_cli/investigation/rag_promoter.py +216 -0
  33. riciplay_cli-1.7.0/riciplay_cli/investigation/session_manager.py +222 -0
  34. riciplay_cli-1.7.0/riciplay_cli/investigation/shared_memory.py +52 -0
  35. riciplay_cli-1.7.0/riciplay_cli/investigation/specialist.py +392 -0
  36. riciplay_cli-1.7.0/riciplay_cli/investigation/specialist_stats.py +232 -0
  37. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/__init__.py +21 -0
  38. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/api.py +23 -0
  39. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/auth.py +23 -0
  40. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/business_logic.py +23 -0
  41. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/cloud.py +23 -0
  42. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/recon.py +22 -0
  43. riciplay_cli-1.7.0/riciplay_cli/investigation/specialists/web.py +23 -0
  44. riciplay_cli-1.7.0/riciplay_cli/investigation/tool_viz.py +149 -0
  45. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/__init__.py +8 -0
  46. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/auth.py +88 -0
  47. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/browser.py +81 -0
  48. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/definitions.py +252 -0
  49. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/executor.py +285 -0
  50. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/external.py +104 -0
  51. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/recon.py +129 -0
  52. riciplay_cli-1.7.0/riciplay_cli/investigation/tools/scanner.py +182 -0
  53. riciplay_cli-1.7.0/riciplay_cli/investigation/types.py +45 -0
  54. riciplay_cli-1.7.0/riciplay_cli/log_preprocessor.py +176 -0
  55. riciplay_cli-1.7.0/riciplay_cli/main.py +148 -0
  56. riciplay_cli-1.7.0/riciplay_cli/model_router.py +162 -0
  57. riciplay_cli-1.7.0/riciplay_cli/notebook.py +410 -0
  58. riciplay_cli-1.7.0/riciplay_cli/notebook_embeddings.py +288 -0
  59. riciplay_cli-1.7.0/riciplay_cli/pipeline/__init__.py +8 -0
  60. riciplay_cli-1.7.0/riciplay_cli/pipeline/attack_graph.py +297 -0
  61. riciplay_cli-1.7.0/riciplay_cli/pipeline/correlator.py +489 -0
  62. riciplay_cli-1.7.0/riciplay_cli/pipeline/discovery.py +279 -0
  63. riciplay_cli-1.7.0/riciplay_cli/pipeline/hypothesis.py +280 -0
  64. riciplay_cli-1.7.0/riciplay_cli/pipeline/report.py +316 -0
  65. riciplay_cli-1.7.0/riciplay_cli/pipeline/runner.py +799 -0
  66. riciplay_cli-1.7.0/riciplay_cli/pipeline/triager.py +333 -0
  67. riciplay_cli-1.7.0/riciplay_cli/planning_mode.py +345 -0
  68. riciplay_cli-1.7.0/riciplay_cli/pricing.py +240 -0
  69. riciplay_cli-1.7.0/riciplay_cli/proxy_manager.py +676 -0
  70. riciplay_cli-1.7.0/riciplay_cli/riciplay_md.py +244 -0
  71. riciplay_cli-1.7.0/riciplay_cli/rules_engine.py +563 -0
  72. riciplay_cli-1.7.0/riciplay_cli/sanitizer.py +207 -0
  73. riciplay_cli-1.7.0/riciplay_cli/semantic_cache.py +133 -0
  74. riciplay_cli-1.7.0/riciplay_cli/session_store.py +210 -0
  75. riciplay_cli-1.7.0/riciplay_cli/skill_generator.py +538 -0
  76. riciplay_cli-1.7.0/riciplay_cli/skill_loader.py +221 -0
  77. riciplay_cli-1.7.0/riciplay_cli/skills/__init__.py +0 -0
  78. riciplay_cli-1.7.0/riciplay_cli/skills/api-review.md +105 -0
  79. riciplay_cli-1.7.0/riciplay_cli/skills/auth-review.md +99 -0
  80. riciplay_cli-1.7.0/riciplay_cli/skills/deserialization.md +86 -0
  81. riciplay_cli-1.7.0/riciplay_cli/skills/sql-injection.md +70 -0
  82. riciplay_cli-1.7.0/riciplay_cli/skills/supply-chain.md +99 -0
  83. riciplay_cli-1.7.0/riciplay_cli/skills/xss-audit.md +67 -0
  84. riciplay_cli-1.7.0/riciplay_cli/slash_handler.py +1397 -0
  85. riciplay_cli-1.7.0/riciplay_cli/todo_manager.py +255 -0
  86. riciplay_cli-1.7.0/riciplay_cli/token_utils.py +86 -0
  87. riciplay_cli-1.7.0/riciplay_cli/tool_runners.py +838 -0
  88. riciplay_cli-1.7.0/riciplay_cli/tools/__init__.py +44 -0
  89. riciplay_cli-1.7.0/riciplay_cli/tools/registry.py +1157 -0
  90. riciplay_cli-1.7.0/riciplay_cli.egg-info/PKG-INFO +12 -0
  91. riciplay_cli-1.7.0/riciplay_cli.egg-info/SOURCES.txt +94 -0
  92. riciplay_cli-1.7.0/riciplay_cli.egg-info/dependency_links.txt +1 -0
  93. riciplay_cli-1.7.0/riciplay_cli.egg-info/entry_points.txt +2 -0
  94. riciplay_cli-1.7.0/riciplay_cli.egg-info/requires.txt +5 -0
  95. riciplay_cli-1.7.0/riciplay_cli.egg-info/top_level.txt +1 -0
  96. riciplay_cli-1.7.0/setup.cfg +4 -0
@@ -0,0 +1 @@
1
+ recursive-include riciplay_cli/skills *.md
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: riciplay-cli
3
+ Version: 1.7.0
4
+ Summary: Riciplay Security Platform — Command Line Interface
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: typer[all]>=0.9.0
9
+ Requires-Dist: httpx>=0.27.0
10
+ Requires-Dist: rich>=13.0
11
+ Requires-Dist: keyring>=25.0
12
+ Requires-Dist: tiktoken>=0.7.0
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "riciplay-cli"
7
+ version = "1.7.0"
8
+ description = "Riciplay Security Platform — Command Line Interface"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ dependencies = [
13
+ "typer[all]>=0.9.0",
14
+ "httpx>=0.27.0",
15
+ "rich>=13.0",
16
+ "keyring>=25.0",
17
+ "tiktoken>=0.7.0",
18
+ ]
19
+
20
+ [project.scripts]
21
+ riciplay = "riciplay_cli.main:app"
22
+
23
+ [tool.setuptools.packages.find]
24
+ include = ["riciplay_cli*"]
25
+
26
+ [tool.setuptools.package-data]
27
+ "riciplay_cli.skills" = ["*.md"]
@@ -0,0 +1,2 @@
1
+ """Riciplay CLI — Command-line interface for the Riciplay Security Platform."""
2
+ __version__ = "1.7.0"
@@ -0,0 +1,250 @@
1
+ """
2
+ Auto-Updater (Phase F Part 3)
3
+
4
+ Checks for Riciplay CLI updates from GitHub releases.
5
+ Supports stable/beta/nightly channels. Checks on startup and on-demand.
6
+ Never auto-installs — always requires user confirmation.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import logging
13
+ import subprocess
14
+ import sys
15
+ import time
16
+ from datetime import datetime, timezone
17
+ from pathlib import Path
18
+ from typing import Optional
19
+
20
+ import httpx
21
+ from packaging.version import Version, InvalidVersion
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Default configuration keys
26
+ DEFAULT_UPDATE_ENABLED = True
27
+ DEFAULT_UPDATE_CHANNEL = "stable"
28
+ DEFAULT_UPDATE_CHECK_INTERVAL = 86400 # 24 hours
29
+
30
+ # GitHub releases API
31
+ GITHUB_API_URL = "https://api.github.com/repos/Zaidux/Riciplay/releases"
32
+ UPDATE_CHECK_TIMEOUT = 10.0 # seconds
33
+
34
+
35
+ def _get_current_version() -> str:
36
+ """Read current version from the riciplay package metadata."""
37
+ try:
38
+ from importlib.metadata import version
39
+ return version("riciplay-cli")
40
+ except Exception:
41
+ pass
42
+
43
+ # Fallback: try reading from nearby pyproject.toml
44
+ pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml"
45
+ if pyproject.exists():
46
+ try:
47
+ content = pyproject.read_text(encoding="utf-8")
48
+ for line in content.split("\n"):
49
+ stripped = line.strip()
50
+ if stripped.startswith("version"):
51
+ parts = stripped.split("=", 1)
52
+ if len(parts) == 2:
53
+ return parts[1].strip().strip('"').strip("'")
54
+ except Exception:
55
+ pass
56
+
57
+ return "0.0.0"
58
+
59
+
60
+ def _parse_version(version_str: str) -> Version:
61
+ """Parse a version string, stripping leading 'v' if present."""
62
+ clean = version_str.lstrip("v").strip()
63
+ return Version(clean)
64
+
65
+
66
+ class UpdateInfo:
67
+ """Information about an available update."""
68
+ def __init__(self, version: str, channel: str, release_notes: str, download_url: str, published_at: str):
69
+ self.version = version
70
+ self.channel = channel
71
+ self.release_notes = release_notes
72
+ self.download_url = download_url
73
+ self.published_at = published_at
74
+
75
+ @property
76
+ def is_newer(self) -> bool:
77
+ try:
78
+ current = _parse_version(_get_current_version())
79
+ new = _parse_version(self.version)
80
+ return new > current
81
+ except (InvalidVersion, ValueError):
82
+ return False
83
+
84
+
85
+ class AutoUpdater:
86
+ """Checks for and manages Riciplay CLI updates."""
87
+
88
+ def __init__(self, config_path: Optional[Path] = None):
89
+ self.config_path = config_path or (Path.home() / ".riciplay" / "update-config.json")
90
+ self.config_path.parent.mkdir(parents=True, exist_ok=True)
91
+ self._config = self._load_config()
92
+
93
+ def _load_config(self) -> dict:
94
+ if self.config_path.exists():
95
+ try:
96
+ return json.loads(self.config_path.read_text(encoding="utf-8"))
97
+ except (json.JSONDecodeError, KeyError):
98
+ pass
99
+ return {
100
+ "auto_update": DEFAULT_UPDATE_ENABLED,
101
+ "channel": DEFAULT_UPDATE_CHANNEL,
102
+ "check_interval": DEFAULT_UPDATE_CHECK_INTERVAL,
103
+ "last_check": None,
104
+ "update_history": [],
105
+ }
106
+
107
+ def _save_config(self) -> None:
108
+ self.config_path.write_text(json.dumps(self._config, indent=2, ensure_ascii=False), encoding="utf-8")
109
+
110
+ @property
111
+ def is_enabled(self) -> bool:
112
+ return self._config.get("auto_update", DEFAULT_UPDATE_ENABLED)
113
+
114
+ @property
115
+ def channel(self) -> str:
116
+ return self._config.get("channel", DEFAULT_UPDATE_CHANNEL)
117
+
118
+ @property
119
+ def should_check(self) -> bool:
120
+ if not self.is_enabled:
121
+ return False
122
+ interval = self._config.get("check_interval", DEFAULT_UPDATE_CHECK_INTERVAL)
123
+ last = self._config.get("last_check")
124
+ if not last:
125
+ return True
126
+ try:
127
+ last_time = datetime.fromisoformat(last).timestamp()
128
+ return (time.time() - last_time) > interval
129
+ except (ValueError, TypeError):
130
+ return True
131
+
132
+ async def check_for_updates(self) -> Optional[UpdateInfo]:
133
+ """Check GitHub releases for a newer version. Returns UpdateInfo if available."""
134
+ if not self.should_check:
135
+ return None
136
+
137
+ try:
138
+ async with httpx.AsyncClient(timeout=UPDATE_CHECK_TIMEOUT) as client:
139
+ resp = await client.get(
140
+ GITHUB_API_URL,
141
+ headers={"Accept": "application/vnd.github.v3+json"},
142
+ )
143
+
144
+ if resp.status_code != 200:
145
+ logger.debug("GitHub API returned %d — skipping update check", resp.status_code)
146
+ return None
147
+
148
+ releases = resp.json()
149
+ if not releases:
150
+ return None
151
+
152
+ current_version_str = _get_current_version()
153
+ current = _parse_version(current_version_str)
154
+
155
+ # Filter by channel
156
+ for release in releases:
157
+ tag = release.get("tag_name", "")
158
+ is_prerelease = release.get("prerelease", False)
159
+
160
+ # Channel filtering
161
+ if self.channel == "stable" and is_prerelease:
162
+ continue
163
+ elif self.channel == "beta":
164
+ if "beta" not in tag.lower() and not is_prerelease:
165
+ continue
166
+ elif self.channel == "nightly":
167
+ if "nightly" not in tag.lower() and "dev" not in tag.lower():
168
+ continue
169
+
170
+ try:
171
+ release_version = _parse_version(tag)
172
+ except (InvalidVersion, ValueError):
173
+ continue
174
+
175
+ if release_version > current:
176
+ self._config["last_check"] = datetime.now(timezone.utc).isoformat()
177
+ self._save_config()
178
+
179
+ return UpdateInfo(
180
+ version=tag,
181
+ channel=self.channel,
182
+ release_notes=release.get("body", "")[:500],
183
+ download_url=release.get("html_url", ""),
184
+ published_at=release.get("published_at", ""),
185
+ )
186
+
187
+ except Exception as exc:
188
+ logger.debug("Update check failed: %s", exc)
189
+
190
+ self._config["last_check"] = datetime.now(timezone.utc).isoformat()
191
+ self._save_config()
192
+ return None
193
+
194
+ def install_update(self) -> tuple[bool, str]:
195
+ """Install the latest version via pip. Returns (success, message)."""
196
+ try:
197
+ result = subprocess.run(
198
+ [sys.executable, "-m", "pip", "install", "--upgrade", "riciplay-cli"],
199
+ capture_output=True,
200
+ text=True,
201
+ timeout=60,
202
+ )
203
+
204
+ if result.returncode == 0:
205
+ new_version = _get_current_version()
206
+ self._config.setdefault("update_history", []).append({
207
+ "version": new_version,
208
+ "channel": self.channel,
209
+ "date": datetime.now(timezone.utc).isoformat(),
210
+ })
211
+ self._config["last_check"] = datetime.now(timezone.utc).isoformat()
212
+ self._save_config()
213
+ return True, f"Updated to riciplay-cli v{new_version}"
214
+ else:
215
+ error_msg = result.stderr.strip()[:200] or result.stdout.strip()[:200]
216
+ return False, f"pip install failed: {error_msg}"
217
+
218
+ except subprocess.TimeoutExpired:
219
+ return False, "pip install timed out after 60 seconds"
220
+ except Exception as exc:
221
+ return False, f"Install failed: {exc}"
222
+
223
+ def set_channel(self, channel: str) -> bool:
224
+ valid = {"stable", "beta", "nightly"}
225
+ if channel not in valid:
226
+ return False
227
+ self._config["channel"] = channel
228
+ self._save_config()
229
+ return True
230
+
231
+ def set_auto_update(self, enabled: bool) -> None:
232
+ self._config["auto_update"] = enabled
233
+ self._save_config()
234
+
235
+ def get_status(self) -> dict:
236
+ return {
237
+ "current_version": _get_current_version(),
238
+ "channel": self.channel,
239
+ "auto_update": self.is_enabled,
240
+ "last_check": self._config.get("last_check"),
241
+ "update_history": self._config.get("update_history", []),
242
+ }
243
+
244
+ def manual_update_instructions(self) -> str:
245
+ return (
246
+ "To update manually:\n"
247
+ " pip install --upgrade riciplay-cli\n"
248
+ "Or from source:\n"
249
+ " cd /path/to/Riciplay/cli && pip install -e ."
250
+ )