titan-cli 0.1.0__py3-none-any.whl → 0.1.2__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/__init__.py +3 -1
- titan_cli/cli.py +27 -5
- titan_cli/core/config.py +12 -7
- titan_cli/ui/tui/__init__.py +9 -8
- titan_cli/ui/tui/icons.py +7 -7
- titan_cli/utils/autoupdate.py +1 -1
- {titan_cli-0.1.0.dist-info → titan_cli-0.1.2.dist-info}/METADATA +3 -6
- {titan_cli-0.1.0.dist-info → titan_cli-0.1.2.dist-info}/RECORD +12 -12
- {titan_cli-0.1.0.dist-info → titan_cli-0.1.2.dist-info}/WHEEL +1 -1
- {titan_cli-0.1.0.dist-info → titan_cli-0.1.2.dist-info}/entry_points.txt +0 -1
- titan_plugin_jira/clients/jira_client.py +7 -6
- {titan_cli-0.1.0.dist-info/licenses → titan_cli-0.1.2.dist-info}/LICENSE +0 -0
titan_cli/__init__.py
CHANGED
titan_cli/cli.py
CHANGED
|
@@ -8,7 +8,7 @@ import typer
|
|
|
8
8
|
from titan_cli import __version__
|
|
9
9
|
from titan_cli.messages import msg
|
|
10
10
|
from titan_cli.ui.tui import launch_tui
|
|
11
|
-
from titan_cli.utils.autoupdate import check_for_updates,
|
|
11
|
+
from titan_cli.utils.autoupdate import check_for_updates, perform_update
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
@@ -34,10 +34,32 @@ def main(ctx: typer.Context):
|
|
|
34
34
|
# Check for updates (non-blocking, silent on errors)
|
|
35
35
|
try:
|
|
36
36
|
update_info = check_for_updates()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
if update_info["update_available"]:
|
|
38
|
+
current = update_info["current_version"]
|
|
39
|
+
latest = update_info["latest_version"]
|
|
40
|
+
|
|
41
|
+
typer.echo(f"🔔 Update available: v{current} → v{latest}")
|
|
42
|
+
typer.echo()
|
|
43
|
+
|
|
44
|
+
# Ask user if they want to update
|
|
45
|
+
if typer.confirm("Would you like to update now?", default=True):
|
|
46
|
+
typer.echo("⏳ Updating Titan CLI...")
|
|
47
|
+
result = perform_update()
|
|
48
|
+
|
|
49
|
+
if result["success"]:
|
|
50
|
+
typer.echo(f"✅ Successfully updated to v{latest} using {result['method']}")
|
|
51
|
+
typer.echo("🔄 Please restart Titan to use the new version")
|
|
52
|
+
typer.echo()
|
|
53
|
+
# Exit so user can restart
|
|
54
|
+
raise typer.Exit(0)
|
|
55
|
+
else:
|
|
56
|
+
typer.echo(f"❌ Update failed: {result['error']}")
|
|
57
|
+
typer.echo(" Please try manually: pipx upgrade titan-cli")
|
|
58
|
+
typer.echo()
|
|
59
|
+
# Continue to TUI even if update fails
|
|
60
|
+
else:
|
|
61
|
+
typer.echo("⏭ Skipping update. Run 'pipx upgrade titan-cli' to update later.")
|
|
62
|
+
typer.echo()
|
|
41
63
|
except Exception:
|
|
42
64
|
# Silently ignore update check failures
|
|
43
65
|
pass
|
titan_cli/core/config.py
CHANGED
|
@@ -16,7 +16,8 @@ class TitanConfig:
|
|
|
16
16
|
def __init__(
|
|
17
17
|
self,
|
|
18
18
|
registry: Optional[PluginRegistry] = None,
|
|
19
|
-
global_config_path: Optional[Path] = None
|
|
19
|
+
global_config_path: Optional[Path] = None,
|
|
20
|
+
skip_plugin_init: bool = False
|
|
20
21
|
):
|
|
21
22
|
# Core dependencies
|
|
22
23
|
self.registry = registry or PluginRegistry()
|
|
@@ -32,12 +33,15 @@ class TitanConfig:
|
|
|
32
33
|
self._global_config_path = global_config_path or self.GLOBAL_CONFIG
|
|
33
34
|
|
|
34
35
|
# Initial load
|
|
35
|
-
self.load()
|
|
36
|
+
self.load(skip_plugin_init=skip_plugin_init)
|
|
36
37
|
|
|
37
|
-
def load(self):
|
|
38
|
+
def load(self, skip_plugin_init: bool = False):
|
|
38
39
|
"""
|
|
39
40
|
Reloads the entire configuration from disk, including global config
|
|
40
41
|
and the project config from the current working directory.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
skip_plugin_init: If True, skip plugin initialization. Useful during setup wizards.
|
|
41
45
|
"""
|
|
42
46
|
# Load global config
|
|
43
47
|
self.global_config = self._load_toml(self._global_config_path)
|
|
@@ -61,10 +65,11 @@ class TitanConfig:
|
|
|
61
65
|
secrets_path = Path.cwd()
|
|
62
66
|
self.secrets = SecretManager(project_path=secrets_path if secrets_path.is_dir() else None)
|
|
63
67
|
|
|
64
|
-
# Reset and re-initialize plugins
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
# Reset and re-initialize plugins (unless skipped during setup)
|
|
69
|
+
if not skip_plugin_init:
|
|
70
|
+
self.registry.reset()
|
|
71
|
+
self.registry.initialize_plugins(config=self, secrets=self.secrets)
|
|
72
|
+
self._plugin_warnings = self.registry.list_failed()
|
|
68
73
|
|
|
69
74
|
# Re-initialize WorkflowRegistry
|
|
70
75
|
# Use current working directory for workflows
|
titan_cli/ui/tui/__init__.py
CHANGED
|
@@ -32,8 +32,9 @@ def launch_tui():
|
|
|
32
32
|
|
|
33
33
|
if not global_config_path.exists():
|
|
34
34
|
# First-time setup: Launch global setup wizard
|
|
35
|
+
# Skip plugin initialization until after setup completes
|
|
35
36
|
plugin_registry = PluginRegistry()
|
|
36
|
-
config = TitanConfig(registry=plugin_registry)
|
|
37
|
+
config = TitanConfig(registry=plugin_registry, skip_plugin_init=True)
|
|
37
38
|
|
|
38
39
|
# We'll create a special wrapper screen that handles the wizard flow
|
|
39
40
|
from .screens.base import BaseScreen
|
|
@@ -136,15 +137,13 @@ def launch_tui():
|
|
|
136
137
|
app.run()
|
|
137
138
|
return
|
|
138
139
|
|
|
139
|
-
# Global config exists,
|
|
140
|
-
plugin_registry = PluginRegistry()
|
|
141
|
-
config = TitanConfig(registry=plugin_registry)
|
|
142
|
-
|
|
143
|
-
# Check if project config exists in current directory
|
|
140
|
+
# Global config exists, check if project config exists in current directory
|
|
144
141
|
project_config_path = Path.cwd() / ".titan" / "config.toml"
|
|
145
142
|
|
|
146
143
|
if not project_config_path.exists():
|
|
147
|
-
# Project not configured:
|
|
144
|
+
# Project not configured: Skip plugin initialization until after setup
|
|
145
|
+
plugin_registry = PluginRegistry()
|
|
146
|
+
config = TitanConfig(registry=plugin_registry, skip_plugin_init=True)
|
|
148
147
|
# Create a wrapper screen similar to global wizard flow
|
|
149
148
|
from .screens.base import BaseScreen
|
|
150
149
|
from textual.app import ComposeResult
|
|
@@ -200,6 +199,8 @@ def launch_tui():
|
|
|
200
199
|
app.run()
|
|
201
200
|
return
|
|
202
201
|
|
|
203
|
-
# Both global and project configs exist:
|
|
202
|
+
# Both global and project configs exist: Initialize normally with plugins
|
|
203
|
+
plugin_registry = PluginRegistry()
|
|
204
|
+
config = TitanConfig(registry=plugin_registry) # Plugins will initialize here
|
|
204
205
|
app = TitanApp(config=config)
|
|
205
206
|
app.run()
|
titan_cli/ui/tui/icons.py
CHANGED
|
@@ -17,16 +17,16 @@ 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
|
|
25
|
-
PENDING = "
|
|
25
|
+
PENDING = "⏸ "
|
|
26
26
|
RUNNING = "⏳"
|
|
27
27
|
COMPLETED = SUCCESS # Alias
|
|
28
28
|
FAILED = ERROR # Alias
|
|
29
|
-
SKIPPED = "
|
|
29
|
+
SKIPPED = "⏭ "
|
|
30
30
|
|
|
31
31
|
# Workflow & execution
|
|
32
32
|
WORKFLOW = "⚡"
|
|
@@ -51,8 +51,8 @@ class Icons:
|
|
|
51
51
|
# Git & VCS
|
|
52
52
|
GIT_BRANCH = "🌿"
|
|
53
53
|
GIT_COMMIT = "💾"
|
|
54
|
-
GIT_PULL = "
|
|
55
|
-
GIT_PUSH = "
|
|
54
|
+
GIT_PULL = "⬇ "
|
|
55
|
+
GIT_PUSH = "⬆ "
|
|
56
56
|
|
|
57
57
|
# AI & Automation
|
|
58
58
|
AI = "🤖"
|
|
@@ -61,7 +61,7 @@ class Icons:
|
|
|
61
61
|
|
|
62
62
|
# General UI
|
|
63
63
|
MENU = "☰"
|
|
64
|
-
SETTINGS = "
|
|
64
|
+
SETTINGS = "⚙ "
|
|
65
65
|
SEARCH = "🔍"
|
|
66
66
|
STAR = "⭐"
|
|
67
67
|
CHECK = "✓"
|
titan_cli/utils/autoupdate.py
CHANGED
|
@@ -108,7 +108,7 @@ def perform_update() -> Dict[str, any]:
|
|
|
108
108
|
# Try pipx first (recommended)
|
|
109
109
|
try:
|
|
110
110
|
subprocess.check_call(
|
|
111
|
-
["pipx", "upgrade", "titan-cli"],
|
|
111
|
+
["pipx", "upgrade", "--force", "titan-cli"],
|
|
112
112
|
stdout=subprocess.DEVNULL,
|
|
113
113
|
stderr=subprocess.DEVNULL
|
|
114
114
|
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: titan-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Modular development tools orchestrator - Streamline your workflows with AI integration and intuitive terminal UI
|
|
5
|
+
Home-page: https://github.com/masmovil/titan-cli
|
|
5
6
|
License: MIT
|
|
6
|
-
License-File: LICENSE
|
|
7
7
|
Keywords: cli,workflow,orchestrator,automation,devtools,ai
|
|
8
8
|
Author: finxo
|
|
9
9
|
Author-email: finxeto@gmail.com
|
|
@@ -19,8 +19,6 @@ Classifier: Programming Language :: Python :: 3
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
24
22
|
Requires-Dist: anthropic (>=0.75.0,<0.76.0)
|
|
25
23
|
Requires-Dist: google-auth (>=2.43.0,<3.0.0)
|
|
26
24
|
Requires-Dist: google-genai (>=1.58.0,<2.0.0)
|
|
@@ -36,7 +34,6 @@ Requires-Dist: tomli (>=2.0.0,<3.0.0)
|
|
|
36
34
|
Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
|
|
37
35
|
Requires-Dist: typer (>=0.20.0,<1.0.0)
|
|
38
36
|
Project-URL: Documentation, https://github.com/masmovil/titan-cli
|
|
39
|
-
Project-URL: Homepage, https://github.com/masmovil/titan-cli
|
|
40
37
|
Project-URL: Repository, https://github.com/masmovil/titan-cli
|
|
41
38
|
Description-Content-Type: text/markdown
|
|
42
39
|
|
|
@@ -46,7 +46,7 @@ titan_plugin_jira/agents/prompts.py,sha256=MWiEbLz_vnHwdnT8toPiS4wDCK0m8lw1kLW6T
|
|
|
46
46
|
titan_plugin_jira/agents/response_parser.py,sha256=BoM64QhXUcr2APikqjcc2d78U-fdwClSoa3Nv7sm7uI,13881
|
|
47
47
|
titan_plugin_jira/agents/token_tracker.py,sha256=yNJQ8HYQl0S-nTZsPHYbb5Vc70rzGHpAsiWE83Gy2zA,7191
|
|
48
48
|
titan_plugin_jira/agents/validators.py,sha256=PzwtSbjzN1mrsU2gNQn6EqBJSVI-pTPhbpQiHuG3LXc,8186
|
|
49
|
-
titan_plugin_jira/clients/jira_client.py,sha256=
|
|
49
|
+
titan_plugin_jira/clients/jira_client.py,sha256=ttjP1-Y20niofNGsnZv_RcdBj2dP2x3WDgggVqTKlao,24068
|
|
50
50
|
titan_plugin_jira/config/jira_agent.toml,sha256=IOBaBlM3c7KsNiMCwOdKdibjB0QjRo71w1Kaf65CrHs,3114
|
|
51
51
|
titan_plugin_jira/config/templates/issue_analysis.md.j2,sha256=xPznSjW3U8GXFtumRx2BwtyS4erFYWHk2zCUrT7XCQA,1452
|
|
52
52
|
titan_plugin_jira/exceptions.py,sha256=NCOVDhynbVmyNFvi_zihl2JPTMr4twIsIb2Bk-v7ZJU,902
|
|
@@ -63,7 +63,7 @@ titan_plugin_jira/utils/__init__.py,sha256=CW540Bjbw33xaoiPlawEtNE7ncr4K3Pg_sFgZ
|
|
|
63
63
|
titan_plugin_jira/utils/issue_sorter.py,sha256=5l5K20ppb1zfhuEOyXXkmfV_zh1wTio1IUWMU2IBaRE,4012
|
|
64
64
|
titan_plugin_jira/utils/saved_queries.py,sha256=bWFI1LSs8ydCRprcJTHk6DMrq1wXN27pb5zoYYVJpRw,5111
|
|
65
65
|
titan_plugin_jira/workflows/analyze-jira-issues.yaml,sha256=VQ-_trGZGxvQUFsbXmrc8r2q9TIi5bfO-T4l6r-JyMw,802
|
|
66
|
-
titan_cli/__init__.py,sha256=
|
|
66
|
+
titan_cli/__init__.py,sha256=1gPtpwnCCyNpmlPD35zE08IPu1OhMErhfRA0sakZLJE,134
|
|
67
67
|
titan_cli/__main__.py,sha256=4tNjZ0tzDfvLID_RSjWREFBqEQ7pRnnerIqAv9Qd5uY,68
|
|
68
68
|
titan_cli/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
69
|
titan_cli/ai/agents/__init__.py,sha256=u5KT7ROBAvhpl_cVoju6rYtmKunxp2dti2clqTzVU00,341
|
|
@@ -77,11 +77,11 @@ 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=qgPl0IDKG-PBJK7DfGemod5652hys1a2CuMWIR7cDbY,2573
|
|
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
|
|
84
|
-
titan_cli/core/config.py,sha256=
|
|
84
|
+
titan_cli/core/config.py,sha256=gI_32djLbKSV2QJ4FbRx3yXEgoaACbT_FTE3SFOd7HI,11496
|
|
85
85
|
titan_cli/core/discovery.py,sha256=SPU5OcCg7mJTiA8cIR_6gHw8AdZmDVGi-nK80138HRU,1816
|
|
86
86
|
titan_cli/core/errors.py,sha256=I-xX6CCIFhno0ZUK8IRPX6RhXfj3Q7mckiCj-xintdY,2419
|
|
87
87
|
titan_cli/core/models.py,sha256=468qjAXv6KBK3ZSEg4oV3wVOfNKDFzXIkqugBfMiisI,2373
|
|
@@ -111,10 +111,10 @@ titan_cli/external_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
111
111
|
titan_cli/external_cli/configs.py,sha256=thW7_8sRYC3t76Wsjvw20vovNOSz1MhVukzabfdFCOo,417
|
|
112
112
|
titan_cli/external_cli/launcher.py,sha256=2t8UJmGwjGsrPk4PRSba_ZnYgEpZNrCvKUENvHxwaSw,2450
|
|
113
113
|
titan_cli/messages.py,sha256=fBDQKHam94s5e2f5EBfqA0Ir88KfYmoF1Y4MbmUP2hY,5945
|
|
114
|
-
titan_cli/ui/tui/__init__.py,sha256=
|
|
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=KMlcDmjsLoVpN4nQVqkCQzMU0DdBM4YIvahc_On1aGE,1318
|
|
118
118
|
titan_cli/ui/tui/screens/__init__.py,sha256=0jqJJPqep7_pVKLRVpyl8iE6q9g8hj5G2kn8KLPhThY,708
|
|
119
119
|
titan_cli/ui/tui/screens/ai_config.py,sha256=jDI-IsrlWs6bPgUA_7ZSRxw_JS9XvakJqi2WxOcUUAU,16634
|
|
120
120
|
titan_cli/ui/tui/screens/ai_config_wizard.py,sha256=BnbOwvW0FqFOEtCfzfjl0YfgxM1KPGxpGI91YkNrloU,32122
|
|
@@ -138,9 +138,9 @@ titan_cli/ui/tui/widgets/status_bar.py,sha256=7pbDfdorHM4JGf5qsjI0Z60G6MEJnMH466
|
|
|
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
|
-
titan_cli/utils/autoupdate.py,sha256=
|
|
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.
|
|
141
|
+
titan_cli/utils/autoupdate.py,sha256=Tq3SJp3iOMNONQZOw-48G6AmpKrPOyWV9RxuCA03q4M,4151
|
|
142
|
+
titan_cli-0.1.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
143
|
+
titan_cli-0.1.2.dist-info/METADATA,sha256=ZhF_YczaaFKY8lzbs_ltDHYNKCvOVgR8ZKv5GvaQlKA,4526
|
|
144
|
+
titan_cli-0.1.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
145
|
+
titan_cli-0.1.2.dist-info/entry_points.txt,sha256=i_Zucivhsx6FcrkKDQS00MJ_Nwse-nAEkuksCcs_Ym8,186
|
|
146
|
+
titan_cli-0.1.2.dist-info/RECORD,,
|
|
@@ -50,18 +50,19 @@ class JiraClient:
|
|
|
50
50
|
JIRA Server/Next uses Basic Auth with Personal Access Token.
|
|
51
51
|
For JIRA Cloud: API tokens can be created at https://id.atlassian.com/manage/api-tokens
|
|
52
52
|
"""
|
|
53
|
+
# Validate before processing
|
|
54
|
+
if not base_url:
|
|
55
|
+
raise JiraAPIError("JIRA base URL not provided")
|
|
56
|
+
|
|
57
|
+
if not api_token:
|
|
58
|
+
raise JiraAPIError("JIRA API token not provided")
|
|
59
|
+
|
|
53
60
|
self.base_url = base_url.rstrip("/")
|
|
54
61
|
self.email = email
|
|
55
62
|
self.api_token = api_token
|
|
56
63
|
self.project_key = project_key
|
|
57
64
|
self.timeout = timeout
|
|
58
65
|
|
|
59
|
-
if not self.api_token:
|
|
60
|
-
raise JiraAPIError("JIRA API token not provided")
|
|
61
|
-
|
|
62
|
-
if not self.base_url:
|
|
63
|
-
raise JiraAPIError("JIRA base URL not provided")
|
|
64
|
-
|
|
65
66
|
if not self.email:
|
|
66
67
|
raise JiraAPIError("JIRA user email not provided")
|
|
67
68
|
|
|
File without changes
|