radsimcli 1.2.1__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.
Files changed (91) hide show
  1. radsim/__init__.py +127 -0
  2. radsim/__main__.py +6 -0
  3. radsim/access_control.py +93 -0
  4. radsim/adversarial.py +511 -0
  5. radsim/agent.py +2663 -0
  6. radsim/agent_config.py +372 -0
  7. radsim/api_client.py +912 -0
  8. radsim/archaeology.py +595 -0
  9. radsim/background.py +188 -0
  10. radsim/browser.py +172 -0
  11. radsim/cli.py +301 -0
  12. radsim/code_quality.py +191 -0
  13. radsim/commands.py +2443 -0
  14. radsim/complexity.py +436 -0
  15. radsim/config.py +692 -0
  16. radsim/diff_display.py +288 -0
  17. radsim/escape_listener.py +180 -0
  18. radsim/file_tools.py +432 -0
  19. radsim/git_tools.py +207 -0
  20. radsim/health.py +253 -0
  21. radsim/hooks.py +225 -0
  22. radsim/jobs.py +549 -0
  23. radsim/keybindings.py +66 -0
  24. radsim/learning/__init__.py +119 -0
  25. radsim/learning/active_learner.py +356 -0
  26. radsim/learning/analytics.py +351 -0
  27. radsim/learning/error_analyzer.py +278 -0
  28. radsim/learning/few_shot_assembler.py +294 -0
  29. radsim/learning/preference_learner.py +366 -0
  30. radsim/learning/reflection_engine.py +399 -0
  31. radsim/learning/self_improver.py +578 -0
  32. radsim/learning/tool_optimizer.py +383 -0
  33. radsim/log_config.py +29 -0
  34. radsim/memory.py +489 -0
  35. radsim/menu.py +119 -0
  36. radsim/model_router.py +253 -0
  37. radsim/modes.py +351 -0
  38. radsim/onboarding.py +991 -0
  39. radsim/output.py +1492 -0
  40. radsim/panning.py +259 -0
  41. radsim/patch.py +240 -0
  42. radsim/planner.py +449 -0
  43. radsim/prompts.py +468 -0
  44. radsim/rate_limiter.py +351 -0
  45. radsim/repo_map.py +296 -0
  46. radsim/response_validator.py +180 -0
  47. radsim/safety.py +300 -0
  48. radsim/scheduler.py +308 -0
  49. radsim/search_tools.py +391 -0
  50. radsim/shell_tools.py +181 -0
  51. radsim/skill_registry.py +148 -0
  52. radsim/skills/README.md +54 -0
  53. radsim/skills/browser_automation.md +191 -0
  54. radsim/skills/directory_operations.md +100 -0
  55. radsim/skills/file_operations.md +150 -0
  56. radsim/skills/git_operations.md +229 -0
  57. radsim/skills/production_readiness.md +153 -0
  58. radsim/skills/search.md +178 -0
  59. radsim/skills/shell_commands.md +138 -0
  60. radsim/skills/web_tools.md +135 -0
  61. radsim/skills.py +350 -0
  62. radsim/sub_agent.py +590 -0
  63. radsim/task_logger.py +328 -0
  64. radsim/telegram.py +661 -0
  65. radsim/todo.py +126 -0
  66. radsim/tool_result.py +115 -0
  67. radsim/tools/__init__.py +435 -0
  68. radsim/tools/advanced.py +660 -0
  69. radsim/tools/code_intel.py +209 -0
  70. radsim/tools/command_policy.py +168 -0
  71. radsim/tools/constants.py +89 -0
  72. radsim/tools/definitions.py +1152 -0
  73. radsim/tools/dependencies.py +328 -0
  74. radsim/tools/directory_ops.py +95 -0
  75. radsim/tools/file_ops.py +354 -0
  76. radsim/tools/git.py +194 -0
  77. radsim/tools/project.py +208 -0
  78. radsim/tools/search.py +186 -0
  79. radsim/tools/shell.py +57 -0
  80. radsim/tools/testing.py +285 -0
  81. radsim/tools/validation.py +170 -0
  82. radsim/tools/web.py +49 -0
  83. radsim/ui.py +328 -0
  84. radsim/update_checker.py +144 -0
  85. radsim/vector_memory.py +649 -0
  86. radsimcli-1.2.1.dist-info/METADATA +665 -0
  87. radsimcli-1.2.1.dist-info/RECORD +91 -0
  88. radsimcli-1.2.1.dist-info/WHEEL +4 -0
  89. radsimcli-1.2.1.dist-info/entry_points.txt +2 -0
  90. radsimcli-1.2.1.dist-info/licenses/LICENSE +21 -0
  91. radsimcli-1.2.1.dist-info/licenses/NOTICE +24 -0
radsim/__init__.py ADDED
@@ -0,0 +1,127 @@
1
+ # RadSim - AI Coding Agent
2
+ # Copyright (c) 2024-2026 Matthew Bright
3
+ # Licensed under the MIT License. See LICENSE file for details.
4
+
5
+ """RadSim Agent Framework - Radically Simple Code Generation."""
6
+
7
+ __version__ = "1.2.1"
8
+ __author__ = "Emera Digital Tools"
9
+
10
+ # Core exports
11
+ from .health import (
12
+ HealthChecker,
13
+ HealthStatus,
14
+ SecretExpirationMonitor,
15
+ check_health,
16
+ check_secret_expirations,
17
+ get_expiration_monitor,
18
+ get_health_checker,
19
+ validate_startup,
20
+ )
21
+ from .hooks import (
22
+ HookContext,
23
+ HooksManager,
24
+ HookType,
25
+ get_hooks_manager,
26
+ on_error,
27
+ post_api,
28
+ post_tool,
29
+ pre_api,
30
+ pre_tool,
31
+ )
32
+ from .model_router import (
33
+ ModelRouter,
34
+ TaskComplexity,
35
+ get_router,
36
+ select_model_for_task,
37
+ )
38
+ from .skill_registry import (
39
+ SkillRegistry,
40
+ get_skill_registry,
41
+ load_skill,
42
+ load_skill_for_tool,
43
+ )
44
+ from .sub_agent import (
45
+ SubAgentResult,
46
+ SubAgentTask,
47
+ delegate_task,
48
+ execute_subagent_task,
49
+ list_available_models,
50
+ quick_task,
51
+ resolve_model_name,
52
+ )
53
+ from .task_logger import (
54
+ TaskLogger,
55
+ get_logger,
56
+ log_api,
57
+ log_error,
58
+ log_tool,
59
+ )
60
+ from .tool_result import ToolResult, wrap_tool_call
61
+ from .vector_memory import (
62
+ VectorMemory,
63
+ get_context,
64
+ get_memory_backend,
65
+ is_vector_memory_available,
66
+ recall,
67
+ remember,
68
+ )
69
+
70
+ __all__ = [
71
+ # Version
72
+ "__version__",
73
+ "__author__",
74
+ # Tool Results
75
+ "ToolResult",
76
+ "wrap_tool_call",
77
+ # Skill Registry
78
+ "SkillRegistry",
79
+ "get_skill_registry",
80
+ "load_skill",
81
+ "load_skill_for_tool",
82
+ # Hooks
83
+ "HookType",
84
+ "HookContext",
85
+ "HooksManager",
86
+ "get_hooks_manager",
87
+ "pre_tool",
88
+ "post_tool",
89
+ "pre_api",
90
+ "post_api",
91
+ "on_error",
92
+ # Logging
93
+ "TaskLogger",
94
+ "get_logger",
95
+ "log_tool",
96
+ "log_api",
97
+ "log_error",
98
+ # Model Routing
99
+ "ModelRouter",
100
+ "TaskComplexity",
101
+ "get_router",
102
+ "select_model_for_task",
103
+ # Vector Memory
104
+ "VectorMemory",
105
+ "remember",
106
+ "recall",
107
+ "get_context",
108
+ "is_vector_memory_available",
109
+ "get_memory_backend",
110
+ # Sub-Agent Delegation
111
+ "SubAgentTask",
112
+ "SubAgentResult",
113
+ "delegate_task",
114
+ "quick_task",
115
+ "execute_subagent_task",
116
+ "list_available_models",
117
+ "resolve_model_name",
118
+ # Health Checks
119
+ "HealthChecker",
120
+ "HealthStatus",
121
+ "SecretExpirationMonitor",
122
+ "check_health",
123
+ "check_secret_expirations",
124
+ "get_expiration_monitor",
125
+ "get_health_checker",
126
+ "validate_startup",
127
+ ]
radsim/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Allow running RadSim as a module: python -m radsim."""
2
+
3
+ from .cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,93 @@
1
+ """Secure Access Control - RadSim Principle: Defense in Depth.
2
+
3
+ Access code security:
4
+ 1. Never logged to any file or database
5
+ 2. Never printed to console (uses getpass)
6
+ 3. Never committed to version control
7
+ 4. Loaded from environment variable only
8
+ 5. Uses constant-time comparison (prevents timing attacks)
9
+ """
10
+
11
+ import hmac
12
+ import os
13
+
14
+
15
+ def _secure_compare(provided: str, stored: str) -> bool:
16
+ """Compare strings in constant time to prevent timing attacks.
17
+
18
+ RadSim Principle: Security by Default
19
+ Timing attacks can reveal password length/characters by measuring
20
+ comparison time. HMAC compare_digest prevents this.
21
+ """
22
+ return hmac.compare_digest(provided.encode("utf-8"), stored.encode("utf-8"))
23
+
24
+
25
+ def get_access_code_from_env() -> str | None:
26
+ """Load access code from environment (never log this value)."""
27
+ # Check ~/.radsim/.env first, then system env
28
+ from .config import load_env_file
29
+
30
+ env_config = load_env_file()
31
+
32
+ # Look for RADSIM_ACCESS_CODE in .env keys
33
+ if "keys" in env_config and "RADSIM_ACCESS_CODE" in env_config["keys"]:
34
+ return env_config["keys"]["RADSIM_ACCESS_CODE"]
35
+
36
+ # Fall back to system environment
37
+ return os.getenv("RADSIM_ACCESS_CODE")
38
+
39
+
40
+ def is_access_protected() -> bool:
41
+ """Check if access code protection is enabled."""
42
+ code = get_access_code_from_env()
43
+ return bool(code and code.strip())
44
+
45
+
46
+ def verify_access_code(user_input: str) -> bool:
47
+ """Verify access code without logging.
48
+
49
+ SECURITY: This function never logs the input or stored code.
50
+ Returns True if code matches, False otherwise.
51
+ """
52
+ stored_code = get_access_code_from_env()
53
+
54
+ if not stored_code:
55
+ return True # No code configured = no protection
56
+
57
+ return _secure_compare(user_input.strip(), stored_code.strip())
58
+
59
+
60
+ def prompt_for_access() -> bool:
61
+ """Prompt user for access code in interactive mode.
62
+
63
+ Uses getpass to hide input from terminal.
64
+ Never logs or prints the entered code.
65
+ """
66
+ if not is_access_protected():
67
+ return True
68
+
69
+ import getpass
70
+
71
+ max_attempts = 3
72
+ for attempt in range(max_attempts):
73
+ try:
74
+ code = getpass.getpass("🔐 Enter access code: ")
75
+ if verify_access_code(code):
76
+ return True
77
+ remaining = max_attempts - attempt - 1
78
+ if remaining > 0:
79
+ print(f" ❌ Invalid code. {remaining} attempts remaining.")
80
+ except (KeyboardInterrupt, EOFError):
81
+ print("\n Access cancelled.")
82
+ return False
83
+
84
+ print(" ❌ Access denied.")
85
+ return False
86
+
87
+
88
+ def check_access_on_startup() -> bool:
89
+ """Verify access code on startup if protection is enabled.
90
+
91
+ Call this from CLI before starting the agent.
92
+ """
93
+ return prompt_for_access()