titan-cli 0.1.3__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.
@@ -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(None, description="JIRA instance URL (e.g., 'https://jira.company.com')")
34
- email: Optional[str] = Field(None, description="User email for authentication")
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(None, description="JIRA API token (Personal Access Token)", json_schema_extra={"format": "password", "required_in_schema": True})
38
- default_project: Optional[str] = Field(None, description="Default JIRA project key (e.g., 'ECAPP', 'PROJ')")
39
- timeout: int = Field(30, description="Request timeout in seconds")
40
- enable_cache: bool = Field(True, description="Enable caching for API responses")
41
- cache_ttl: int = Field(300, description="Cache time-to-live in seconds")
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()
@@ -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
- plugins_table = project_cfg_dict.setdefault("plugins", {})
507
- plugin_specific_table = plugins_table.setdefault(self.plugin_name, {})
508
- plugin_config_table = plugin_specific_table.setdefault("config", {})
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
- # Separate secrets from regular config
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
- config_values = {}
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
- config_values[field_name] = value
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 config
530
- plugin_config_table.update(config_values)
555
+ # Update configs
556
+ project_config_table.update(project_config_values)
557
+ global_config_table.update(global_config_values)
531
558
 
532
- # Write config file
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():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: titan-cli
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Modular development tools orchestrator - Streamline your workflows with AI integration and intuitive terminal UI
5
5
  Home-page: https://github.com/masmovil/titan-cli
6
6
  License: MIT
@@ -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=3TFFKLkoIu6wzeFbGh2vGAU-Hr6Bvt9lroY7ZghUugE,3525
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=TcCZCVHW9sL6vlCgv2SnfRFNa0D-5M3urg74yvRNWjQ,7487
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
@@ -122,7 +122,7 @@ titan_cli/ui/tui/screens/base.py,sha256=ufVYBkVzetQxsPQTobN0HgUGdSB0ARfRtvo-02DS
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
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=yxwfBuZk3spn6fT3twoc9ZTokL0kDOvvMnOgKyMzJVQ,18882
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
@@ -139,8 +139,8 @@ titan_cli/ui/tui/widgets/table.py,sha256=uWXyUda6mvflBybrrUSZh5Nvf794ege8SUe_0D2
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.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
143
- titan_cli-0.1.3.dist-info/METADATA,sha256=vKcX5Pq9CGckQCutN1nHA8C9coxz-G3-TurBekhV1VU,4526
144
- titan_cli-0.1.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
145
- titan_cli-0.1.3.dist-info/entry_points.txt,sha256=i_Zucivhsx6FcrkKDQS00MJ_Nwse-nAEkuksCcs_Ym8,186
146
- titan_cli-0.1.3.dist-info/RECORD,,
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,,