titan-cli 0.1.2__py3-none-any.whl → 0.1.4__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.
- titan_cli/cli.py +15 -4
- titan_cli/core/plugins/models.py +35 -7
- titan_cli/core/plugins/plugin_registry.py +17 -2
- titan_cli/ui/tui/icons.py +3 -2
- titan_cli/ui/tui/screens/ai_config.py +1 -1
- titan_cli/ui/tui/screens/ai_config_wizard.py +1 -1
- titan_cli/ui/tui/screens/main_menu.py +1 -1
- titan_cli/ui/tui/screens/plugin_config_wizard.py +40 -9
- titan_cli/ui/tui/widgets/status_bar.py +1 -1
- {titan_cli-0.1.2.dist-info → titan_cli-0.1.4.dist-info}/METADATA +1 -1
- {titan_cli-0.1.2.dist-info → titan_cli-0.1.4.dist-info}/RECORD +14 -14
- {titan_cli-0.1.2.dist-info → titan_cli-0.1.4.dist-info}/LICENSE +0 -0
- {titan_cli-0.1.2.dist-info → titan_cli-0.1.4.dist-info}/WHEEL +0 -0
- {titan_cli-0.1.2.dist-info → titan_cli-0.1.4.dist-info}/entry_points.txt +0 -0
titan_cli/cli.py
CHANGED
|
@@ -3,6 +3,8 @@ Titan CLI - Main CLI application
|
|
|
3
3
|
|
|
4
4
|
Combines all tool commands into a single CLI interface.
|
|
5
5
|
"""
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
6
8
|
import typer
|
|
7
9
|
|
|
8
10
|
from titan_cli import __version__
|
|
@@ -31,7 +33,7 @@ def get_version() -> str:
|
|
|
31
33
|
def main(ctx: typer.Context):
|
|
32
34
|
"""Titan CLI - Main entry point"""
|
|
33
35
|
if ctx.invoked_subcommand is None:
|
|
34
|
-
# Check for updates
|
|
36
|
+
# Check for updates BEFORE launching TUI
|
|
35
37
|
try:
|
|
36
38
|
update_info = check_for_updates()
|
|
37
39
|
if update_info["update_available"]:
|
|
@@ -44,13 +46,22 @@ def main(ctx: typer.Context):
|
|
|
44
46
|
# Ask user if they want to update
|
|
45
47
|
if typer.confirm("Would you like to update now?", default=True):
|
|
46
48
|
typer.echo("⏳ Updating Titan CLI...")
|
|
49
|
+
typer.echo()
|
|
47
50
|
result = perform_update()
|
|
48
51
|
|
|
49
52
|
if result["success"]:
|
|
50
53
|
typer.echo(f"✅ Successfully updated to v{latest} using {result['method']}")
|
|
51
|
-
typer.echo("🔄
|
|
54
|
+
typer.echo("🔄 Relaunching Titan with new version...")
|
|
52
55
|
typer.echo()
|
|
53
|
-
|
|
56
|
+
|
|
57
|
+
# Relaunch titan using subprocess
|
|
58
|
+
# Note: sys.executable and sys.argv are controlled by the Python runtime,
|
|
59
|
+
# not user input, so this is safe from command injection
|
|
60
|
+
subprocess.run(
|
|
61
|
+
[sys.executable, "-m", "titan_cli.cli"] + sys.argv[1:],
|
|
62
|
+
shell=False, # Explicitly disable shell to prevent injection
|
|
63
|
+
check=False # Don't raise on non-zero exit
|
|
64
|
+
)
|
|
54
65
|
raise typer.Exit(0)
|
|
55
66
|
else:
|
|
56
67
|
typer.echo(f"❌ Update failed: {result['error']}")
|
|
@@ -64,7 +75,7 @@ def main(ctx: typer.Context):
|
|
|
64
75
|
# Silently ignore update check failures
|
|
65
76
|
pass
|
|
66
77
|
|
|
67
|
-
# Launch TUI
|
|
78
|
+
# Launch TUI (only if no update or update was declined/failed)
|
|
68
79
|
launch_tui()
|
|
69
80
|
|
|
70
81
|
|
titan_cli/core/plugins/models.py
CHANGED
|
@@ -30,15 +30,43 @@ class JiraPluginConfig(BaseModel):
|
|
|
30
30
|
Credentials (base_url, email, api_token) should be configured at global level (~/.titan/config.toml).
|
|
31
31
|
Project-specific settings (default_project) can override at project level (.titan/config.toml).
|
|
32
32
|
"""
|
|
33
|
-
base_url: Optional[str] = Field(
|
|
34
|
-
|
|
33
|
+
base_url: Optional[str] = Field(
|
|
34
|
+
None,
|
|
35
|
+
description="JIRA instance URL (e.g., 'https://jira.company.com')",
|
|
36
|
+
json_schema_extra={"config_scope": "global"}
|
|
37
|
+
)
|
|
38
|
+
email: Optional[str] = Field(
|
|
39
|
+
None,
|
|
40
|
+
description="User email for authentication",
|
|
41
|
+
json_schema_extra={"config_scope": "global"}
|
|
42
|
+
)
|
|
35
43
|
# api_token is stored in secrets, not in config.toml
|
|
36
44
|
# It appears in the JSON schema for interactive configuration but is optional in the model
|
|
37
|
-
api_token: Optional[str] = Field(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
api_token: Optional[str] = Field(
|
|
46
|
+
None,
|
|
47
|
+
description="JIRA API token (Personal Access Token)",
|
|
48
|
+
json_schema_extra={"format": "password", "required_in_schema": True}
|
|
49
|
+
)
|
|
50
|
+
default_project: Optional[str] = Field(
|
|
51
|
+
None,
|
|
52
|
+
description="Default JIRA project key (e.g., 'ECAPP', 'PROJ')",
|
|
53
|
+
json_schema_extra={"config_scope": "project"}
|
|
54
|
+
)
|
|
55
|
+
timeout: int = Field(
|
|
56
|
+
30,
|
|
57
|
+
description="Request timeout in seconds",
|
|
58
|
+
json_schema_extra={"config_scope": "global"}
|
|
59
|
+
)
|
|
60
|
+
enable_cache: bool = Field(
|
|
61
|
+
True,
|
|
62
|
+
description="Enable caching for API responses",
|
|
63
|
+
json_schema_extra={"config_scope": "global"}
|
|
64
|
+
)
|
|
65
|
+
cache_ttl: int = Field(
|
|
66
|
+
300,
|
|
67
|
+
description="Cache time-to-live in seconds",
|
|
68
|
+
json_schema_extra={"config_scope": "global"}
|
|
69
|
+
)
|
|
42
70
|
|
|
43
71
|
@field_validator('base_url')
|
|
44
72
|
@classmethod
|
|
@@ -20,10 +20,19 @@ class PluginRegistry:
|
|
|
20
20
|
logger = logging.getLogger('titan_cli.ui.tui.screens.project_setup_wizard')
|
|
21
21
|
|
|
22
22
|
discovered = entry_points(group='titan.plugins')
|
|
23
|
-
self._discovered_plugin_names = [ep.name for ep in discovered]
|
|
24
|
-
logger.debug(f"PluginRegistry.discover() - Found {len(self._discovered_plugin_names)} plugins: {self._discovered_plugin_names}")
|
|
25
23
|
|
|
24
|
+
# Deduplicate entry points (can happen in dev mode with editable installs)
|
|
25
|
+
seen = {}
|
|
26
|
+
unique_eps = []
|
|
26
27
|
for ep in discovered:
|
|
28
|
+
if ep.name not in seen:
|
|
29
|
+
seen[ep.name] = ep
|
|
30
|
+
unique_eps.append(ep)
|
|
31
|
+
|
|
32
|
+
self._discovered_plugin_names = [ep.name for ep in unique_eps]
|
|
33
|
+
logger.debug(f"PluginRegistry.discover() - Found {len(self._discovered_plugin_names)} plugins: {self._discovered_plugin_names}")
|
|
34
|
+
|
|
35
|
+
for ep in unique_eps:
|
|
27
36
|
try:
|
|
28
37
|
logger.debug(f"Loading plugin: {ep.name}")
|
|
29
38
|
plugin_class = ep.load()
|
|
@@ -63,6 +72,12 @@ class PluginRegistry:
|
|
|
63
72
|
if name in initialized:
|
|
64
73
|
continue
|
|
65
74
|
|
|
75
|
+
# Skip plugins that are disabled in configuration
|
|
76
|
+
if not config.is_plugin_enabled(name):
|
|
77
|
+
logger.debug(f"Skipping disabled plugin: {name}")
|
|
78
|
+
initialized.add(name) # Mark as processed so we don't retry
|
|
79
|
+
continue
|
|
80
|
+
|
|
66
81
|
plugin = self._plugins[name]
|
|
67
82
|
dependencies_met = True
|
|
68
83
|
|
titan_cli/ui/tui/icons.py
CHANGED
|
@@ -17,8 +17,8 @@ class Icons:
|
|
|
17
17
|
# Status indicators
|
|
18
18
|
SUCCESS = "✅"
|
|
19
19
|
ERROR = "❌"
|
|
20
|
-
WARNING = "
|
|
21
|
-
INFO = "
|
|
20
|
+
WARNING = "🟡"
|
|
21
|
+
INFO = "🔵"
|
|
22
22
|
QUESTION = "❓"
|
|
23
23
|
|
|
24
24
|
# Progress states
|
|
@@ -56,6 +56,7 @@ class Icons:
|
|
|
56
56
|
|
|
57
57
|
# AI & Automation
|
|
58
58
|
AI = "🤖"
|
|
59
|
+
AI_CONFIG = "🧠"
|
|
59
60
|
ROBOT = "🤖"
|
|
60
61
|
SPARKLES = "✨"
|
|
61
62
|
|
|
@@ -152,7 +152,7 @@ class AIConfigWizardScreen(BaseScreen):
|
|
|
152
152
|
def __init__(self, config):
|
|
153
153
|
super().__init__(
|
|
154
154
|
config,
|
|
155
|
-
title=f"{Icons.
|
|
155
|
+
title=f"{Icons.AI_CONFIG} Configure AI Provider",
|
|
156
156
|
show_back=True,
|
|
157
157
|
show_status_bar=False
|
|
158
158
|
)
|
|
@@ -108,7 +108,7 @@ class MainMenuScreen(BaseScreen):
|
|
|
108
108
|
options.extend(
|
|
109
109
|
[
|
|
110
110
|
Option(f"{Icons.PLUGIN} Plugin Management", id="plugin_management"),
|
|
111
|
-
Option(f"{Icons.
|
|
111
|
+
Option(f"{Icons.AI_CONFIG} AI Configuration", id="ai_config"),
|
|
112
112
|
]
|
|
113
113
|
)
|
|
114
114
|
|
|
@@ -494,22 +494,43 @@ class PluginConfigWizardScreen(BaseScreen):
|
|
|
494
494
|
|
|
495
495
|
try:
|
|
496
496
|
project_cfg_path = self.config.project_config_path
|
|
497
|
+
global_cfg_path = self.config._global_config_path
|
|
498
|
+
|
|
497
499
|
if not project_cfg_path:
|
|
498
500
|
self.app.notify("No project config found", severity="error")
|
|
499
501
|
return
|
|
500
502
|
|
|
503
|
+
# Load existing configs
|
|
501
504
|
project_cfg_dict = {}
|
|
502
505
|
if project_cfg_path.exists():
|
|
503
506
|
with open(project_cfg_path, "rb") as f:
|
|
504
507
|
project_cfg_dict = tomli.load(f)
|
|
505
508
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
+
global_cfg_dict = {}
|
|
510
|
+
if global_cfg_path.exists():
|
|
511
|
+
with open(global_cfg_path, "rb") as f:
|
|
512
|
+
global_cfg_dict = tomli.load(f)
|
|
513
|
+
|
|
514
|
+
# Prepare plugin tables
|
|
515
|
+
project_plugins_table = project_cfg_dict.setdefault("plugins", {})
|
|
516
|
+
project_plugin_table = project_plugins_table.setdefault(self.plugin_name, {})
|
|
517
|
+
project_config_table = project_plugin_table.setdefault("config", {})
|
|
518
|
+
|
|
519
|
+
global_plugins_table = global_cfg_dict.setdefault("plugins", {})
|
|
520
|
+
global_plugin_table = global_plugins_table.setdefault(self.plugin_name, {})
|
|
521
|
+
global_config_table = global_plugin_table.setdefault("config", {})
|
|
509
522
|
|
|
510
|
-
#
|
|
523
|
+
# Get field metadata from schema
|
|
524
|
+
field_scopes = {}
|
|
525
|
+
if self.schema and "properties" in self.schema:
|
|
526
|
+
for field_name, field_info in self.schema["properties"].items():
|
|
527
|
+
scope = field_info.get("config_scope", "project") # Default to project
|
|
528
|
+
field_scopes[field_name] = scope
|
|
529
|
+
|
|
530
|
+
# Separate secrets and config by scope
|
|
511
531
|
secrets_to_save = {}
|
|
512
|
-
|
|
532
|
+
global_config_values = {}
|
|
533
|
+
project_config_values = {}
|
|
513
534
|
|
|
514
535
|
for field_name, value in self.config_data.items():
|
|
515
536
|
if isinstance(value, dict) and value.get("_is_secret"):
|
|
@@ -524,15 +545,25 @@ class PluginConfigWizardScreen(BaseScreen):
|
|
|
524
545
|
else:
|
|
525
546
|
secrets_to_save[secret_key] = value["_value"]
|
|
526
547
|
else:
|
|
527
|
-
|
|
548
|
+
# Route to global or project based on field scope
|
|
549
|
+
scope = field_scopes.get(field_name, "project")
|
|
550
|
+
if scope == "global":
|
|
551
|
+
global_config_values[field_name] = value
|
|
552
|
+
else:
|
|
553
|
+
project_config_values[field_name] = value
|
|
528
554
|
|
|
529
|
-
# Update
|
|
530
|
-
|
|
555
|
+
# Update configs
|
|
556
|
+
project_config_table.update(project_config_values)
|
|
557
|
+
global_config_table.update(global_config_values)
|
|
531
558
|
|
|
532
|
-
# Write config
|
|
559
|
+
# Write config files
|
|
533
560
|
with open(project_cfg_path, "wb") as f:
|
|
534
561
|
tomli_w.dump(project_cfg_dict, f)
|
|
535
562
|
|
|
563
|
+
if global_config_values: # Only write global if there are global values
|
|
564
|
+
with open(global_cfg_path, "wb") as f:
|
|
565
|
+
tomli_w.dump(global_cfg_dict, f)
|
|
566
|
+
|
|
536
567
|
# Save secrets
|
|
537
568
|
project_name = self.config.get_project_name()
|
|
538
569
|
for secret_key, secret_value in secrets_to_save.items():
|
|
@@ -77,7 +77,7 @@ titan_cli/ai/providers/__init__.py,sha256=sNzrQGY3MM1EmYaHKJux4yRE5tvZMIRUlHcLfG
|
|
|
77
77
|
titan_cli/ai/providers/anthropic.py,sha256=ibfIpseHsouEEc8HdIUihzlMQCJHQgNa1sQNSoPY0WY,4085
|
|
78
78
|
titan_cli/ai/providers/base.py,sha256=X2Mp0acJm4WSEWgF6m7d30x5CjVBwkW4pzdHyETmjwc,1778
|
|
79
79
|
titan_cli/ai/providers/gemini.py,sha256=hQwNe3wKXlORh6mE3vCHa-jm1vCJStqTmZLxDbaFUcA,10004
|
|
80
|
-
titan_cli/cli.py,sha256=
|
|
80
|
+
titan_cli/cli.py,sha256=K4ZeF_PysMtfJM7K6IReQTjwFJlrDuheR05YIIhxf_4,3156
|
|
81
81
|
titan_cli/clients/__init__.py,sha256=gI2mQ8JeuqFa8u7XAbYlyjOph1Z5VR42NnLOjq65iD4,22
|
|
82
82
|
titan_cli/clients/gcloud_client.py,sha256=BXc7PWqcWIjF4-l2GV3w__r11MmfPtl8OW5TFw4hgr4,1902
|
|
83
83
|
titan_cli/core/__init__.py,sha256=Z5dxtLlHbAQu79NUqjlA7Ovh9toDM2B9PiVv0J-kWGQ,71
|
|
@@ -86,9 +86,9 @@ titan_cli/core/discovery.py,sha256=SPU5OcCg7mJTiA8cIR_6gHw8AdZmDVGi-nK80138HRU,1
|
|
|
86
86
|
titan_cli/core/errors.py,sha256=I-xX6CCIFhno0ZUK8IRPX6RhXfj3Q7mckiCj-xintdY,2419
|
|
87
87
|
titan_cli/core/models.py,sha256=468qjAXv6KBK3ZSEg4oV3wVOfNKDFzXIkqugBfMiisI,2373
|
|
88
88
|
titan_cli/core/plugins/available.py,sha256=__ejonPeOqw2Zy9gIRB-CHeFO9SvTFclG095afgnIz4,1163
|
|
89
|
-
titan_cli/core/plugins/models.py,sha256=
|
|
89
|
+
titan_cli/core/plugins/models.py,sha256=CdaktVAEcq4t41X4IfXrBgjFxly6FxdJikqqkyJtTtM,4012
|
|
90
90
|
titan_cli/core/plugins/plugin_base.py,sha256=TtHjO-g1PBS0W0vfAM-5z-0xwL0IT2Ohi3BJ0TIfTEU,2597
|
|
91
|
-
titan_cli/core/plugins/plugin_registry.py,sha256=
|
|
91
|
+
titan_cli/core/plugins/plugin_registry.py,sha256=cuoarcNnsvLv30-01uGnjWwrqy2Jaf_eJGJelzcv_k0,7753
|
|
92
92
|
titan_cli/core/secrets.py,sha256=4A4rszaie1wJh7xccetOO9rM_0jwYiIQIZVgCM0tCT4,4642
|
|
93
93
|
titan_cli/core/workflows/__init__.py,sha256=CvpDKR4Co5Vzbb5aFTt5r6vyoqjGexj6Mt1_x0Z4iwg,653
|
|
94
94
|
titan_cli/core/workflows/models.py,sha256=xMXmZKMTYRawUeuAO0hG5dF6QMRCM-TWFNfoveBxJpQ,4746
|
|
@@ -114,15 +114,15 @@ titan_cli/messages.py,sha256=fBDQKHam94s5e2f5EBfqA0Ir88KfYmoF1Y4MbmUP2hY,5945
|
|
|
114
114
|
titan_cli/ui/tui/__init__.py,sha256=w0rk1XmK6NT-kohOJSd8clhg98QAYKo9eLBFm4Kwf50,9645
|
|
115
115
|
titan_cli/ui/tui/__previews__/statusbar_preview.py,sha256=QWrVbIDuMufveVavEKnPnvVVtjHHhg-leWDk98uj7Rc,3495
|
|
116
116
|
titan_cli/ui/tui/app.py,sha256=96bwBKddqDXBo37POx1zR3oBMDfrF4lrDaaXPL3JJos,3992
|
|
117
|
-
titan_cli/ui/tui/icons.py,sha256=
|
|
117
|
+
titan_cli/ui/tui/icons.py,sha256=i_xNue92PTyie-fWk0IfRGuFYtu208OZnWhRxDioBUA,1341
|
|
118
118
|
titan_cli/ui/tui/screens/__init__.py,sha256=0jqJJPqep7_pVKLRVpyl8iE6q9g8hj5G2kn8KLPhThY,708
|
|
119
|
-
titan_cli/ui/tui/screens/ai_config.py,sha256
|
|
120
|
-
titan_cli/ui/tui/screens/ai_config_wizard.py,sha256=
|
|
119
|
+
titan_cli/ui/tui/screens/ai_config.py,sha256=-e1p_1_NzUkXzxNCDKSjUzwM_eB-wpiCrTMF-r6C09U,16635
|
|
120
|
+
titan_cli/ui/tui/screens/ai_config_wizard.py,sha256=xPIDkT8L8Bjk7NqO_4mG4rhS-cdFwT-b1QeNeQ7XAdc,32123
|
|
121
121
|
titan_cli/ui/tui/screens/base.py,sha256=ufVYBkVzetQxsPQTobN0HgUGdSB0ARfRtvo-02DS2Pk,3695
|
|
122
122
|
titan_cli/ui/tui/screens/cli_launcher.py,sha256=C9XWe1jUr0-Q_PGwchL6bVu9N2g-QLa83jJZGl7ucHI,4385
|
|
123
123
|
titan_cli/ui/tui/screens/global_setup_wizard.py,sha256=gbkGMGXWJdfrIWvRvT5DDFZKKRWmf7nlGUuUkTtDiKI,12115
|
|
124
|
-
titan_cli/ui/tui/screens/main_menu.py,sha256=
|
|
125
|
-
titan_cli/ui/tui/screens/plugin_config_wizard.py,sha256=
|
|
124
|
+
titan_cli/ui/tui/screens/main_menu.py,sha256=5Z27Ny69PPJF0q6_H5zcNPOh8vrRDr_xgYFSmUbn244,4493
|
|
125
|
+
titan_cli/ui/tui/screens/plugin_config_wizard.py,sha256=a8QIsVLGNNCLebJ7bWlRpftZU7yPhTRcf06XOLzFB4w,20416
|
|
126
126
|
titan_cli/ui/tui/screens/plugin_management.py,sha256=2UvdxISzaiQBpm1OW1cpDrQS4ghTSC_87nlpx5Nrjhw,12356
|
|
127
127
|
titan_cli/ui/tui/screens/project_setup_wizard.py,sha256=Q2cCHlzWpiLdtGUTHnkHnXapkxZahRAVTx5MI78sszU,24210
|
|
128
128
|
titan_cli/ui/tui/screens/workflow_execution.py,sha256=JHZlKtqpYRosVP4TVSGzT1L8UxlCoCNorBFVXYPyzik,23526
|
|
@@ -134,13 +134,13 @@ titan_cli/ui/tui/widgets/__init__.py,sha256=NLJMQOyI0IPFLNZ62wrJBulKgOG8bK0J2ute
|
|
|
134
134
|
titan_cli/ui/tui/widgets/button.py,sha256=Z7aRve1PSKpcQOsPo1db2GlKfwKddAVsU2KfhSRarKw,2143
|
|
135
135
|
titan_cli/ui/tui/widgets/header.py,sha256=ZGZuhY4B15q56DcZItXjarOrDX0ASCPdDczIOrYXwJI,3043
|
|
136
136
|
titan_cli/ui/tui/widgets/panel.py,sha256=jcLKZQXVqMGsvi7mVoTyKWijjrmXOgtC2ZuAkk2Ulgc,1818
|
|
137
|
-
titan_cli/ui/tui/widgets/status_bar.py,sha256=
|
|
137
|
+
titan_cli/ui/tui/widgets/status_bar.py,sha256=XiRFpoOb9DPHStaMddNIAaYmHIzg8ZkmyBzvWy4CrZg,3361
|
|
138
138
|
titan_cli/ui/tui/widgets/table.py,sha256=uWXyUda6mvflBybrrUSZh5Nvf794ege8SUe_0D24y3c,1668
|
|
139
139
|
titan_cli/ui/tui/widgets/text.py,sha256=p5h2V9w-JmPigwUFn-ky_D7gyYiix_93FJNqNmCYNHY,4057
|
|
140
140
|
titan_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
141
141
|
titan_cli/utils/autoupdate.py,sha256=Tq3SJp3iOMNONQZOw-48G6AmpKrPOyWV9RxuCA03q4M,4151
|
|
142
|
-
titan_cli-0.1.
|
|
143
|
-
titan_cli-0.1.
|
|
144
|
-
titan_cli-0.1.
|
|
145
|
-
titan_cli-0.1.
|
|
146
|
-
titan_cli-0.1.
|
|
142
|
+
titan_cli-0.1.4.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
143
|
+
titan_cli-0.1.4.dist-info/METADATA,sha256=v_-VyxKvwr3BZJD5jtjp4yDiBLUOAKFLntIJMdVEso4,4526
|
|
144
|
+
titan_cli-0.1.4.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
145
|
+
titan_cli-0.1.4.dist-info/entry_points.txt,sha256=i_Zucivhsx6FcrkKDQS00MJ_Nwse-nAEkuksCcs_Ym8,186
|
|
146
|
+
titan_cli-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|