souleyez 2.43.26__py3-none-any.whl → 2.43.34__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.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +23434 -10286
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.26.dist-info/RECORD +0 -379
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
souleyez/ui/deliverables_view.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Deliverables dashboard view for interactive UI."""
|
|
2
|
+
|
|
2
3
|
import click
|
|
3
4
|
from rich.console import Console
|
|
4
5
|
from rich.table import Table
|
|
5
6
|
from rich.progress import Progress, BarColumn, TextColumn
|
|
7
|
+
|
|
6
8
|
try:
|
|
7
9
|
from rich.progress import TaskProgressColumn
|
|
8
10
|
except ImportError:
|
|
@@ -32,98 +34,155 @@ def show_deliverables_dashboard(engagement_id):
|
|
|
32
34
|
# Header
|
|
33
35
|
width = DesignSystem.get_terminal_width()
|
|
34
36
|
click.echo("\n┌" + "─" * (width - 2) + "┐")
|
|
35
|
-
click.echo(
|
|
37
|
+
click.echo(
|
|
38
|
+
"│"
|
|
39
|
+
+ click.style(
|
|
40
|
+
" DELIVERABLES & ACCEPTANCE CRITERIA ".center(width - 2),
|
|
41
|
+
bold=True,
|
|
42
|
+
fg="cyan",
|
|
43
|
+
)
|
|
44
|
+
+ "│"
|
|
45
|
+
)
|
|
36
46
|
click.echo("└" + "─" * (width - 2) + "┘")
|
|
37
47
|
click.echo()
|
|
38
48
|
|
|
39
49
|
# Summary
|
|
40
50
|
summary = dm.get_summary(engagement_id)
|
|
41
51
|
|
|
42
|
-
if summary[
|
|
52
|
+
if summary["total"] == 0:
|
|
43
53
|
# Go directly to template selector when no deliverables exist
|
|
44
54
|
from souleyez.ui.template_selector import show_template_selector
|
|
55
|
+
|
|
45
56
|
loaded = show_template_selector(engagement_id)
|
|
46
57
|
if loaded:
|
|
47
58
|
continue # Reload deliverables view
|
|
48
59
|
break # Back if cancelled
|
|
49
60
|
|
|
50
61
|
click.echo(f" Engagement: {current['name']}")
|
|
51
|
-
click.echo(
|
|
62
|
+
click.echo(
|
|
63
|
+
f" Overall Progress: {summary['completed']}/{summary['total']} deliverables ({summary['completion_rate']*100:.0f}%)"
|
|
64
|
+
)
|
|
52
65
|
click.echo()
|
|
53
66
|
|
|
54
67
|
# Progress bar
|
|
55
68
|
bar_width = min(50, width - 30)
|
|
56
|
-
completed = summary[
|
|
57
|
-
total = summary[
|
|
69
|
+
completed = summary["completed"]
|
|
70
|
+
total = summary["total"] if summary["total"] > 0 else 1
|
|
58
71
|
filled = int((completed / total) * bar_width)
|
|
59
72
|
bar = "█" * filled + "░" * (bar_width - filled)
|
|
60
|
-
|
|
73
|
+
|
|
61
74
|
click.echo(f" Progress: [{bar}] {completed}/{total}")
|
|
62
75
|
click.echo()
|
|
63
76
|
|
|
64
77
|
# Deliverables by category
|
|
65
78
|
deliverables = dm.list_deliverables(engagement_id)
|
|
66
79
|
|
|
67
|
-
categories = [
|
|
80
|
+
categories = [
|
|
81
|
+
"reconnaissance",
|
|
82
|
+
"enumeration",
|
|
83
|
+
"exploitation",
|
|
84
|
+
"post_exploitation",
|
|
85
|
+
"techniques",
|
|
86
|
+
]
|
|
68
87
|
|
|
69
88
|
for category in categories:
|
|
70
|
-
cat_deliverables = [d for d in deliverables if d[
|
|
89
|
+
cat_deliverables = [d for d in deliverables if d["category"] == category]
|
|
71
90
|
|
|
72
91
|
if not cat_deliverables:
|
|
73
92
|
continue
|
|
74
93
|
|
|
75
|
-
click.echo(
|
|
94
|
+
click.echo(
|
|
95
|
+
click.style(
|
|
96
|
+
f"\n {category.upper().replace('_', ' ')}", bold=True, fg="cyan"
|
|
97
|
+
)
|
|
98
|
+
)
|
|
76
99
|
click.echo(" " + "─" * (width - 4))
|
|
77
100
|
|
|
78
101
|
for d in cat_deliverables:
|
|
79
102
|
# Status icon
|
|
80
103
|
status_icon = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}.get(d[
|
|
104
|
+
"completed": "✅",
|
|
105
|
+
"in_progress": "🔄",
|
|
106
|
+
"pending": "⚠️",
|
|
107
|
+
"failed": "❌",
|
|
108
|
+
}.get(d["status"], "?")
|
|
86
109
|
|
|
87
110
|
# Progress
|
|
88
|
-
if d[
|
|
89
|
-
current_val = d[
|
|
90
|
-
target_val = d[
|
|
111
|
+
if d["target_type"] == "count":
|
|
112
|
+
current_val = d["current_value"] or 0
|
|
113
|
+
target_val = d["target_value"]
|
|
91
114
|
progress_str = f"[{current_val}/{target_val}]"
|
|
92
|
-
elif d[
|
|
93
|
-
progress_str = "[✓]" if d[
|
|
115
|
+
elif d["target_type"] == "boolean":
|
|
116
|
+
progress_str = "[✓]" if d["status"] == "completed" else "[✗]"
|
|
94
117
|
else:
|
|
95
118
|
progress_str = "[Manual]"
|
|
96
119
|
|
|
97
120
|
# Priority color
|
|
98
121
|
priority_styles = {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
"critical": "red",
|
|
123
|
+
"high": "yellow",
|
|
124
|
+
"medium": "white",
|
|
125
|
+
"low": "bright_black",
|
|
103
126
|
}
|
|
104
|
-
priority_color = priority_styles.get(d[
|
|
127
|
+
priority_color = priority_styles.get(d["priority"], "white")
|
|
105
128
|
|
|
106
|
-
title_line =
|
|
107
|
-
|
|
129
|
+
title_line = (
|
|
130
|
+
f" {status_icon} [{d['id']}] {d['title']} {progress_str}"
|
|
131
|
+
)
|
|
132
|
+
if d["priority"] in ["critical", "high"]:
|
|
108
133
|
title_line = click.style(title_line, fg=priority_color)
|
|
109
|
-
|
|
134
|
+
|
|
110
135
|
click.echo(title_line)
|
|
111
136
|
|
|
112
|
-
if d[
|
|
113
|
-
click.echo(
|
|
137
|
+
if d["description"] and d["status"] != "completed":
|
|
138
|
+
click.echo(
|
|
139
|
+
click.style(f" {d['description']}", fg="bright_black")
|
|
140
|
+
)
|
|
114
141
|
|
|
115
142
|
# Menu with standardized numbered options
|
|
116
143
|
from souleyez.ui.menu_components import StandardMenu
|
|
117
144
|
|
|
118
145
|
options = [
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
|
|
146
|
+
{
|
|
147
|
+
"number": 1,
|
|
148
|
+
"label": "Validate All Deliverables",
|
|
149
|
+
"description": "Auto-validate all deliverables based on evidence",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"number": 2,
|
|
153
|
+
"label": "Mark as Complete",
|
|
154
|
+
"description": "Mark specific deliverable as complete",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"number": 3,
|
|
158
|
+
"label": "Link Evidence",
|
|
159
|
+
"description": "Associate evidence with deliverable",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"number": 4,
|
|
163
|
+
"label": "View Timeline",
|
|
164
|
+
"description": "Display timeline and velocity metrics",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"number": 5,
|
|
168
|
+
"label": "Export Deliverables",
|
|
169
|
+
"description": "Generate deliverables report",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"number": 6,
|
|
173
|
+
"label": "Smart Recommendations",
|
|
174
|
+
"description": "View AI-powered recommendations",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"number": 7,
|
|
178
|
+
"label": "Team Collaboration",
|
|
179
|
+
"description": "Manage team assignments and status",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"number": 8,
|
|
183
|
+
"label": "Refresh View",
|
|
184
|
+
"description": "Reload deliverables data",
|
|
185
|
+
},
|
|
127
186
|
]
|
|
128
187
|
|
|
129
188
|
choice = StandardMenu.render(options)
|
|
@@ -133,9 +192,11 @@ def show_deliverables_dashboard(engagement_id):
|
|
|
133
192
|
elif choice == 1:
|
|
134
193
|
# Validate
|
|
135
194
|
click.echo()
|
|
136
|
-
click.echo(click.style(" Validating all deliverables...", fg=
|
|
195
|
+
click.echo(click.style(" Validating all deliverables...", fg="cyan"))
|
|
137
196
|
stats = dm.validate_all(engagement_id)
|
|
138
|
-
click.echo(
|
|
197
|
+
click.echo(
|
|
198
|
+
click.style(f" ✓ Updated {stats['updated']} deliverables", fg="green")
|
|
199
|
+
)
|
|
139
200
|
click.echo(f" Completed: {stats['completed']}")
|
|
140
201
|
click.echo(f" In Progress: {stats['in_progress']}")
|
|
141
202
|
click.pause()
|
|
@@ -144,49 +205,67 @@ def show_deliverables_dashboard(engagement_id):
|
|
|
144
205
|
from souleyez.ui.interactive_selector import interactive_select
|
|
145
206
|
|
|
146
207
|
# Get incomplete deliverables
|
|
147
|
-
incomplete = [d for d in deliverables if d[
|
|
208
|
+
incomplete = [d for d in deliverables if d["status"] != "completed"]
|
|
148
209
|
|
|
149
210
|
if not incomplete:
|
|
150
|
-
click.echo(
|
|
211
|
+
click.echo(
|
|
212
|
+
click.style(
|
|
213
|
+
"\n All deliverables are already completed!", fg="green"
|
|
214
|
+
)
|
|
215
|
+
)
|
|
151
216
|
click.pause()
|
|
152
217
|
continue
|
|
153
218
|
|
|
154
219
|
selected_ids = set()
|
|
155
220
|
columns = [
|
|
156
|
-
{
|
|
157
|
-
{
|
|
158
|
-
{
|
|
159
|
-
{
|
|
160
|
-
{
|
|
221
|
+
{"name": "ID", "width": 6, "key": "id", "justify": "right"},
|
|
222
|
+
{"name": "Category", "width": 15, "key": "category"},
|
|
223
|
+
{"name": "Status", "width": 12, "key": "status"},
|
|
224
|
+
{"name": "Priority", "width": 10, "key": "priority"},
|
|
225
|
+
{"name": "Title", "key": "title"},
|
|
161
226
|
]
|
|
162
227
|
|
|
163
228
|
def format_deliverable_cell(item: dict, key: str) -> str:
|
|
164
229
|
value = item.get(key)
|
|
165
230
|
if value is None:
|
|
166
|
-
return
|
|
167
|
-
if key ==
|
|
168
|
-
colors = {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
color = colors.get(value,
|
|
174
|
-
return f
|
|
175
|
-
|
|
231
|
+
return "-"
|
|
232
|
+
if key == "status":
|
|
233
|
+
colors = {
|
|
234
|
+
"pending": "yellow",
|
|
235
|
+
"in_progress": "cyan",
|
|
236
|
+
"failed": "red",
|
|
237
|
+
}
|
|
238
|
+
color = colors.get(value, "white")
|
|
239
|
+
return f"[{color}]{value}[/{color}]"
|
|
240
|
+
if key == "priority":
|
|
241
|
+
colors = {
|
|
242
|
+
"critical": "red",
|
|
243
|
+
"high": "yellow",
|
|
244
|
+
"medium": "white",
|
|
245
|
+
"low": "dim",
|
|
246
|
+
}
|
|
247
|
+
color = colors.get(value, "white")
|
|
248
|
+
return f"[{color}]{value}[/{color}]"
|
|
249
|
+
return str(value) if value else "-"
|
|
176
250
|
|
|
177
251
|
interactive_select(
|
|
178
252
|
items=incomplete,
|
|
179
253
|
columns=columns,
|
|
180
254
|
selected_ids=selected_ids,
|
|
181
|
-
get_id=lambda d: d.get(
|
|
182
|
-
title=
|
|
183
|
-
format_cell=format_deliverable_cell
|
|
255
|
+
get_id=lambda d: d.get("id"),
|
|
256
|
+
title="SELECT DELIVERABLES TO MARK COMPLETE",
|
|
257
|
+
format_cell=format_deliverable_cell,
|
|
184
258
|
)
|
|
185
259
|
|
|
186
260
|
if selected_ids:
|
|
187
261
|
for did in selected_ids:
|
|
188
262
|
dm.mark_complete(did)
|
|
189
|
-
click.echo(
|
|
263
|
+
click.echo(
|
|
264
|
+
click.style(
|
|
265
|
+
f"\n ✓ Marked {len(selected_ids)} deliverable(s) as completed",
|
|
266
|
+
fg="green",
|
|
267
|
+
)
|
|
268
|
+
)
|
|
190
269
|
else:
|
|
191
270
|
click.echo("\n No deliverables selected.")
|
|
192
271
|
click.pause()
|
|
@@ -196,29 +275,36 @@ def show_deliverables_dashboard(engagement_id):
|
|
|
196
275
|
deliverable = dm.get_deliverable(deliverable_id)
|
|
197
276
|
if deliverable:
|
|
198
277
|
from souleyez.ui.evidence_linking_view import show_evidence_linking_view
|
|
278
|
+
|
|
199
279
|
show_evidence_linking_view(deliverable_id)
|
|
200
280
|
else:
|
|
201
|
-
click.echo(
|
|
281
|
+
click.echo(
|
|
282
|
+
click.style(f" Deliverable {deliverable_id} not found", fg="red")
|
|
283
|
+
)
|
|
202
284
|
click.pause()
|
|
203
285
|
elif choice == 4:
|
|
204
286
|
# View timeline and velocity
|
|
205
287
|
from souleyez.ui.timeline_view import show_timeline_view
|
|
288
|
+
|
|
206
289
|
show_timeline_view(engagement_id)
|
|
207
290
|
elif choice == 5:
|
|
208
291
|
# Export deliverables
|
|
209
292
|
from souleyez.ui.export_view import show_export_view
|
|
293
|
+
|
|
210
294
|
show_export_view(engagement_id)
|
|
211
295
|
elif choice == 6:
|
|
212
296
|
# Smart recommendations
|
|
213
297
|
from souleyez.ui.recommendations_view import show_recommendations_dashboard
|
|
298
|
+
|
|
214
299
|
show_recommendations_dashboard(engagement_id)
|
|
215
300
|
elif choice == 7:
|
|
216
301
|
# Team collaboration
|
|
217
302
|
from souleyez.ui.team_dashboard import show_team_dashboard
|
|
303
|
+
|
|
218
304
|
show_team_dashboard(engagement_id)
|
|
219
305
|
elif choice == 8:
|
|
220
306
|
# Refresh
|
|
221
307
|
continue
|
|
222
308
|
else:
|
|
223
|
-
click.echo(click.style(" Invalid choice", fg=
|
|
309
|
+
click.echo(click.style(" Invalid choice", fg="yellow"))
|
|
224
310
|
click.pause()
|
souleyez/ui/design_system.py
CHANGED
|
@@ -16,19 +16,19 @@ class DesignSystem:
|
|
|
16
16
|
"""Centralized design system for SoulEyez UI."""
|
|
17
17
|
|
|
18
18
|
# Box Styles
|
|
19
|
-
HEADER_BOX = box.DOUBLE
|
|
20
|
-
TABLE_BOX = box.SIMPLE
|
|
19
|
+
HEADER_BOX = box.DOUBLE # ╔═╗ - App header only
|
|
20
|
+
TABLE_BOX = box.SIMPLE # ─── - All tables
|
|
21
21
|
|
|
22
22
|
# Widths
|
|
23
|
-
DEFAULT_WIDTH = 100
|
|
24
|
-
MIN_WIDTH = 80
|
|
23
|
+
DEFAULT_WIDTH = 100 # Default terminal width
|
|
24
|
+
MIN_WIDTH = 80 # Minimum supported width
|
|
25
25
|
|
|
26
26
|
# Separators
|
|
27
|
-
SECTION_SEP = "─"
|
|
27
|
+
SECTION_SEP = "─" # Section separator character
|
|
28
28
|
|
|
29
29
|
# Spacing
|
|
30
|
-
SECTION_SPACING = 2
|
|
31
|
-
CONTENT_SPACING = 1
|
|
30
|
+
SECTION_SPACING = 2 # Blank lines between sections
|
|
31
|
+
CONTENT_SPACING = 1 # Blank lines after separator
|
|
32
32
|
|
|
33
33
|
@staticmethod
|
|
34
34
|
def get_terminal_width() -> int:
|
|
@@ -44,7 +44,7 @@ class DesignSystem:
|
|
|
44
44
|
"""Generate section separator line."""
|
|
45
45
|
w = width or DesignSystem.get_terminal_width()
|
|
46
46
|
return DesignSystem.SECTION_SEP * w
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
@staticmethod
|
|
49
49
|
def clear_screen():
|
|
50
50
|
"""
|
|
@@ -57,10 +57,10 @@ class DesignSystem:
|
|
|
57
57
|
import sys
|
|
58
58
|
|
|
59
59
|
# Use system clear command - most reliable across all terminals
|
|
60
|
-
if os.name ==
|
|
61
|
-
os.system(
|
|
60
|
+
if os.name == "posix":
|
|
61
|
+
os.system("clear")
|
|
62
62
|
else:
|
|
63
|
-
os.system(
|
|
63
|
+
os.system("cls")
|
|
64
64
|
|
|
65
65
|
@staticmethod
|
|
66
66
|
def create_table(expand: bool = True, **kwargs) -> Table:
|
|
@@ -80,7 +80,7 @@ class DesignSystem:
|
|
|
80
80
|
padding=(0, 1),
|
|
81
81
|
show_header=True,
|
|
82
82
|
header_style="bold",
|
|
83
|
-
**kwargs
|
|
83
|
+
**kwargs,
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
@staticmethod
|
|
@@ -100,7 +100,7 @@ class DesignSystem:
|
|
|
100
100
|
lines = [
|
|
101
101
|
f"{emoji} {title}",
|
|
102
102
|
DesignSystem.SECTION_SEP * w,
|
|
103
|
-
"" # Blank line after separator
|
|
103
|
+
"", # Blank line after separator
|
|
104
104
|
]
|
|
105
105
|
return lines
|
|
106
106
|
|