janito 0.15.0__py3-none-any.whl → 1.0.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 (109) hide show
  1. janito/__init__.py +1 -5
  2. janito/__main__.py +3 -5
  3. janito/agent/__init__.py +1 -0
  4. janito/agent/agent.py +96 -0
  5. janito/agent/config.py +113 -0
  6. janito/agent/config_defaults.py +10 -0
  7. janito/agent/conversation.py +107 -0
  8. janito/agent/queued_tool_handler.py +16 -0
  9. janito/agent/runtime_config.py +30 -0
  10. janito/agent/tool_handler.py +124 -0
  11. janito/agent/tools/__init__.py +11 -0
  12. janito/agent/tools/ask_user.py +63 -0
  13. janito/agent/tools/bash_exec.py +58 -0
  14. janito/agent/tools/create_directory.py +19 -0
  15. janito/agent/tools/create_file.py +43 -0
  16. janito/agent/tools/fetch_url.py +48 -0
  17. janito/agent/tools/file_str_replace.py +48 -0
  18. janito/agent/tools/find_files.py +37 -0
  19. janito/agent/tools/gitignore_utils.py +40 -0
  20. janito/agent/tools/move_file.py +37 -0
  21. janito/agent/tools/remove_file.py +19 -0
  22. janito/agent/tools/rich_live.py +37 -0
  23. janito/agent/tools/rich_utils.py +31 -0
  24. janito/agent/tools/search_text.py +41 -0
  25. janito/agent/tools/view_file.py +34 -0
  26. janito/cli/__init__.py +0 -6
  27. janito/cli/_print_config.py +68 -0
  28. janito/cli/_utils.py +8 -0
  29. janito/cli/arg_parser.py +26 -0
  30. janito/cli/config_commands.py +131 -0
  31. janito/cli/logging_setup.py +27 -0
  32. janito/cli/main.py +39 -0
  33. janito/cli/runner.py +138 -0
  34. janito/cli_chat_shell/__init__.py +1 -0
  35. janito/cli_chat_shell/chat_loop.py +148 -0
  36. janito/cli_chat_shell/commands.py +202 -0
  37. janito/cli_chat_shell/config_shell.py +75 -0
  38. janito/cli_chat_shell/load_prompt.py +15 -0
  39. janito/cli_chat_shell/session_manager.py +60 -0
  40. janito/cli_chat_shell/ui.py +136 -0
  41. janito/render_prompt.py +12 -0
  42. janito/templates/system_instructions.j2 +38 -0
  43. janito/web/__init__.py +0 -0
  44. janito/web/__main__.py +17 -0
  45. janito/web/app.py +132 -0
  46. janito-1.0.1.dist-info/METADATA +144 -0
  47. janito-1.0.1.dist-info/RECORD +51 -0
  48. {janito-0.15.0.dist-info → janito-1.0.1.dist-info}/WHEEL +2 -1
  49. janito-1.0.1.dist-info/entry_points.txt +2 -0
  50. {janito-0.15.0.dist-info → janito-1.0.1.dist-info}/licenses/LICENSE +2 -2
  51. janito-1.0.1.dist-info/top_level.txt +1 -0
  52. janito/callbacks.py +0 -34
  53. janito/cli/agent/__init__.py +0 -7
  54. janito/cli/agent/conversation.py +0 -149
  55. janito/cli/agent/initialization.py +0 -168
  56. janito/cli/agent/query.py +0 -112
  57. janito/cli/agent.py +0 -12
  58. janito/cli/app.py +0 -178
  59. janito/cli/commands/__init__.py +0 -12
  60. janito/cli/commands/config.py +0 -30
  61. janito/cli/commands/history.py +0 -119
  62. janito/cli/commands/profile.py +0 -93
  63. janito/cli/commands/validation.py +0 -24
  64. janito/cli/commands/workspace.py +0 -31
  65. janito/cli/commands.py +0 -12
  66. janito/cli/output.py +0 -29
  67. janito/cli/utils.py +0 -22
  68. janito/config/README.md +0 -104
  69. janito/config/__init__.py +0 -16
  70. janito/config/cli/__init__.py +0 -28
  71. janito/config/cli/commands.py +0 -397
  72. janito/config/cli/validators.py +0 -77
  73. janito/config/core/__init__.py +0 -23
  74. janito/config/core/file_operations.py +0 -90
  75. janito/config/core/properties.py +0 -316
  76. janito/config/core/singleton.py +0 -282
  77. janito/config/profiles/__init__.py +0 -8
  78. janito/config/profiles/definitions.py +0 -38
  79. janito/config/profiles/manager.py +0 -80
  80. janito/data/instructions_template.txt +0 -34
  81. janito/token_report.py +0 -154
  82. janito/tools/__init__.py +0 -44
  83. janito/tools/bash/bash.py +0 -157
  84. janito/tools/bash/unix_persistent_bash.py +0 -215
  85. janito/tools/bash/win_persistent_bash.py +0 -341
  86. janito/tools/decorators.py +0 -90
  87. janito/tools/delete_file.py +0 -65
  88. janito/tools/fetch_webpage/__init__.py +0 -23
  89. janito/tools/fetch_webpage/core.py +0 -182
  90. janito/tools/find_files.py +0 -220
  91. janito/tools/move_file.py +0 -72
  92. janito/tools/prompt_user.py +0 -57
  93. janito/tools/replace_file.py +0 -63
  94. janito/tools/rich_console.py +0 -176
  95. janito/tools/search_text.py +0 -226
  96. janito/tools/str_replace_editor/__init__.py +0 -6
  97. janito/tools/str_replace_editor/editor.py +0 -55
  98. janito/tools/str_replace_editor/handlers/__init__.py +0 -16
  99. janito/tools/str_replace_editor/handlers/create.py +0 -60
  100. janito/tools/str_replace_editor/handlers/insert.py +0 -100
  101. janito/tools/str_replace_editor/handlers/str_replace.py +0 -94
  102. janito/tools/str_replace_editor/handlers/undo.py +0 -64
  103. janito/tools/str_replace_editor/handlers/view.py +0 -165
  104. janito/tools/str_replace_editor/utils.py +0 -33
  105. janito/tools/think.py +0 -37
  106. janito/tools/usage_tracker.py +0 -137
  107. janito-0.15.0.dist-info/METADATA +0 -481
  108. janito-0.15.0.dist-info/RECORD +0 -64
  109. janito-0.15.0.dist-info/entry_points.txt +0 -2
janito/config/__init__.py DELETED
@@ -1,16 +0,0 @@
1
- """
2
- Configuration module for Janito.
3
- Provides a singleton Config class to access configuration values.
4
- Supports both local and global configuration with merging functionality.
5
- """
6
- from .core.singleton import Config
7
- from .profiles.definitions import PROFILES
8
- from .profiles.manager import get_available_profiles, get_profile
9
-
10
- # Convenience function to get the config instance
11
- def get_config() -> Config:
12
- """Get the singleton Config instance."""
13
- return Config()
14
-
15
- # Re-export the Config class for backward compatibility
16
- __all__ = ["Config", "PROFILES", "get_config", "get_available_profiles", "get_profile"]
@@ -1,28 +0,0 @@
1
- """
2
- CLI integration for Janito configuration.
3
- Provides command handling and validation for configuration-related CLI commands.
4
- """
5
- from .commands import (
6
- handle_reset_config,
7
- handle_reset_local_config,
8
- handle_reset_global_config,
9
- handle_show_config,
10
- handle_set_api_key,
11
- handle_set_local_config,
12
- handle_set_global_config,
13
- handle_config_commands
14
- )
15
- from .validators import validate_temperature, validate_boolean_value
16
-
17
- __all__ = [
18
- "handle_reset_config",
19
- "handle_reset_local_config",
20
- "handle_reset_global_config",
21
- "handle_show_config",
22
- "handle_set_api_key",
23
- "handle_set_local_config",
24
- "handle_set_global_config",
25
- "handle_config_commands",
26
- "validate_temperature",
27
- "validate_boolean_value"
28
- ]
@@ -1,397 +0,0 @@
1
- """
2
- Command handling functions for configuration-related CLI commands.
3
- """
4
- import sys
5
- import os
6
- from pathlib import Path
7
- from typing import Optional, Dict, Any
8
- import typer
9
- from rich.console import Console
10
-
11
- from ..core.singleton import Config
12
- from .validators import validate_temperature, validate_boolean_value, validate_config_key_value
13
-
14
- console = Console()
15
-
16
- def handle_reset_config(reset_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
17
- """
18
- Handle the --reset-config parameter (deprecated, kept for backward compatibility).
19
- This function now does nothing as --reset-config has been replaced by --reset-local-config and --reset-global-config.
20
-
21
- Args:
22
- reset_config: Whether to reset the configuration (ignored)
23
- ctx: Typer context
24
- query: Query string
25
-
26
- Returns:
27
- bool: Always returns False
28
- """
29
- # This function is kept for backward compatibility but does nothing
30
- # Users should use --reset-local-config or --reset-global-config instead
31
- return False
32
-
33
- def handle_reset_local_config(reset_local_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
34
- """
35
- Handle the --reset-local-config parameter.
36
- This removes the local configuration file (.janito/config.json) in the current workspace.
37
-
38
- Args:
39
- reset_local_config: Whether to reset the local configuration
40
- ctx: Typer context
41
- query: Query string
42
-
43
- Returns:
44
- bool: True if the program should exit after this operation
45
- """
46
- if reset_local_config:
47
- try:
48
- config_path = Path(Config().workspace_dir) / ".janito" / "config.json"
49
- if Config().reset_local_config():
50
- console.print(f"[bold green]✅ Local configuration reset[/bold green]")
51
- else:
52
- console.print(f"[bold yellow]⚠️ No local configuration found[/bold yellow]")
53
- except Exception as e:
54
- console.print(f"[bold red]Error removing configuration file:[/bold red] {str(e)}")
55
-
56
- # Exit after resetting config if no other operation is requested
57
- return ctx.invoked_subcommand is None and not query
58
-
59
- return False
60
-
61
- def handle_reset_global_config(reset_global_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
62
- """
63
- Handle the --reset-global-config parameter.
64
- This removes the global configuration file (~/.janito/config.json) in the user's home directory.
65
-
66
- Args:
67
- reset_global_config: Whether to reset the global configuration
68
- ctx: Typer context
69
- query: Query string
70
-
71
- Returns:
72
- bool: True if the program should exit after this operation
73
- """
74
- if reset_global_config:
75
- try:
76
- config_path = Path.home() / ".janito" / "config.json"
77
- if Config().reset_global_config():
78
- console.print(f"[bold green]✅ Global configuration reset[/bold green]")
79
- else:
80
- console.print(f"[bold yellow]⚠️ No global configuration found[/bold yellow]")
81
- except Exception as e:
82
- console.print(f"[bold red]Error removing configuration file:[/bold red] {str(e)}")
83
-
84
- # Exit after resetting config if no other operation is requested
85
- return ctx.invoked_subcommand is None and not query
86
-
87
- return False
88
-
89
- def handle_show_config(show_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
90
- """
91
- Handle the --show-config parameter.
92
-
93
- Args:
94
- show_config: Whether to show the configuration
95
- ctx: Typer context
96
- query: Query string
97
-
98
- Returns:
99
- bool: True if the program should exit after this operation
100
- """
101
- if show_config:
102
- config = Config()
103
- console.print("[bold blue]⚙️ Current Configuration:[/bold blue]")
104
-
105
- # Show configuration file paths
106
- local_config_path = Path(config.workspace_dir) / ".janito" / "config.json"
107
- global_config_path = Path.home() / ".janito" / "config.json"
108
- console.print(f"[bold]📁 Local Configuration File:[/bold] {local_config_path}")
109
- console.print(f"[bold]🏠 Global Configuration File:[/bold] {global_config_path}")
110
-
111
- # Show API key status
112
- api_key_global = Config().get_api_key()
113
- if api_key_global:
114
- console.print(f"[bold]🔑 API Key:[/bold] [green]Set in global config[/green]")
115
- else:
116
- console.print(f"[bold]🔑 API Key:[/bold] [red]Not set[/red]")
117
-
118
- # Show merged configuration (effective settings)
119
- console.print("\n[bold blue]🔄 Merged Configuration (Effective Settings):[/bold blue]")
120
- console.print(f"[bold]🔊 Verbose Mode:[/bold] {'Enabled' if config.verbose else 'Disabled'}")
121
- console.print(f"[bold]❓ Ask Mode:[/bold] {'Enabled' if config.ask_mode else 'Disabled'} [dim](runtime-only setting)[/dim]")
122
- console.print(f"[bold]📊 Show Usage Report:[/bold] {'Enabled' if config.show_usage_report else 'Disabled'}")
123
- console.print(f"[bold]👤 Role:[/bold] [bold white on blue]{config.role}[/bold white on blue]")
124
- console.print(f"[bold]🌡️ Temperature:[/bold] {config.temperature}")
125
-
126
- # Show profile information if one is set
127
- if config.profile:
128
- profile_data = config.get_available_profiles()[config.profile]
129
- console.print(f"[bold]📋 Active Profile:[/bold] {config.profile} - {profile_data['description']}")
130
-
131
- # Show local configuration
132
- local_config = config.get_local_config()
133
- if local_config:
134
- console.print("\n[bold blue]📁 Local Configuration:[/bold blue]")
135
- for key, value in local_config.items():
136
- # Don't show API key or runtime-only settings like ask_mode
137
- if key != "api_key" and key != "ask_mode":
138
- console.print(f"[bold]🔹 {key}:[/bold] {value}")
139
- else:
140
- console.print("\n[bold blue]📁 Local Configuration:[/bold blue] [dim]Empty[/dim]")
141
-
142
- # Show global configuration
143
- global_config = config.get_global_config()
144
- if global_config:
145
- console.print("\n[bold blue]🏠 Global Configuration:[/bold blue]")
146
- for key, value in global_config.items():
147
- # Don't show API key or runtime-only settings like ask_mode
148
- if key != "api_key" and key != "ask_mode":
149
- console.print(f"[bold]🔹 {key}:[/bold] {value}")
150
- else:
151
- console.print("\n[bold blue]🏠 Global Configuration:[/bold blue] [dim]Empty[/dim]")
152
-
153
- # Show available profiles
154
- profiles = config.get_available_profiles()
155
- if profiles:
156
- console.print("\n[bold blue]📋 Available Parameter Profiles:[/bold blue]")
157
- for name, data in profiles.items():
158
- console.print(f"[bold]🔹 {name}[/bold] - {data['description']}")
159
-
160
- # Exit if this was the only operation requested
161
- return ctx.invoked_subcommand is None and not query
162
-
163
- return False
164
-
165
- def handle_set_api_key(set_api_key: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
166
- """
167
- Handle the --set-api-key parameter.
168
-
169
- Args:
170
- set_api_key: API key
171
- ctx: Typer context
172
- query: Query string
173
-
174
- Returns:
175
- bool: True if the program should exit after this operation
176
- """
177
- if set_api_key is not None:
178
- try:
179
- Config().set_api_key(set_api_key)
180
- console.print(f"[bold green]✅ API key saved[/bold green]")
181
-
182
- # Exit after setting API key if no other operation is requested
183
- return ctx.invoked_subcommand is None and not query
184
- except Exception as e:
185
- console.print(f"[bold red]Error:[/bold red] {str(e)}")
186
- sys.exit(1)
187
-
188
- return False
189
-
190
- def _handle_config_setting(key: str, value: str, config_type: str = "local") -> bool:
191
- """
192
- Handle setting a configuration value.
193
-
194
- Args:
195
- key: Configuration key
196
- value: Configuration value
197
- config_type: Type of configuration to update ("local" or "global")
198
-
199
- Returns:
200
- bool: True if the operation was successful
201
- """
202
- try:
203
- if key == "profile":
204
- try:
205
- Config().set_profile(value, config_type)
206
- profile_data = Config().get_available_profiles()[value.lower()]
207
- console.print(f"[bold green]✅ Profile set to '{value.lower()}'[/bold green]")
208
- return True
209
- except ValueError as e:
210
- console.print(f"[bold red]Error:[/bold red] {str(e)}")
211
- return False
212
- elif key == "temperature":
213
- is_valid, result = validate_temperature(value)
214
- if not is_valid:
215
- console.print(f"[bold red]Error:[/bold red] {result}")
216
- return False
217
-
218
- if config_type == "local":
219
- Config().temperature = result, "local"
220
- else:
221
- Config().temperature = result, "global"
222
- console.print(f"[bold green]✅ Temperature set to {result}[/bold green]")
223
- return True
224
- # top_k and top_p are now only accessible through profiles
225
- elif key == "role":
226
- if config_type == "local":
227
- Config().role = value, "local"
228
- else:
229
- Config().role = value, "global"
230
- console.print(f"[bold green]✅ Role set to '{value}'[/bold green]")
231
- return True
232
- elif key == "ask_mode":
233
- is_valid, result = validate_boolean_value(value)
234
- if not is_valid:
235
- console.print(f"[bold red]Error:[/bold red] {result}")
236
- return False
237
-
238
- # ask_mode is a runtime-only setting, inform the user
239
- console.print(f"[bold yellow]⚠️ Ask mode is a runtime-only setting and cannot be stored in configuration.[/bold yellow]")
240
- console.print(f"[bold yellow]Use the --ask flag when running the command instead.[/bold yellow]")
241
- return True
242
- elif key == "show_usage_report":
243
- is_valid, result = validate_boolean_value(value)
244
- if not is_valid:
245
- console.print(f"[bold red]Error:[/bold red] {result}")
246
- return False
247
-
248
- if config_type == "local":
249
- Config().show_usage_report = result, "local"
250
- else:
251
- Config().show_usage_report = result, "global"
252
- console.print(f"[bold green]✅ Show usage report set to {result}[/bold green]")
253
- return True
254
- else:
255
- # For other keys, set them directly in the configuration
256
- if config_type == "local":
257
- Config().set_local_config(key, value)
258
- else:
259
- Config().set_global_config(key, value)
260
- console.print(f"[bold green]✅ {key} set to '{value}'[/bold green]")
261
- return True
262
- except Exception as e:
263
- console.print(f"[bold red]Error:[/bold red] {str(e)}")
264
- return False
265
-
266
-
267
- def handle_set_local_config(config_str: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
268
- """
269
- Handle the --set-local-config parameter.
270
-
271
- Args:
272
- config_str: Configuration string in format 'key=value'
273
- ctx: Typer context
274
- query: Query string
275
-
276
- Returns:
277
- bool: True if the program should exit after this operation
278
- """
279
- if config_str is not None:
280
- is_valid, result = validate_config_key_value(config_str)
281
- if not is_valid:
282
- console.print(f"[bold red]Error:[/bold red] {result}")
283
- return ctx.invoked_subcommand is None and not query
284
-
285
- key, value = result
286
- _handle_config_setting(key, value, "local")
287
-
288
- # Exit after applying config changes if no other operation is requested
289
- return ctx.invoked_subcommand is None and not query
290
-
291
- return False
292
-
293
- def handle_set_global_config(config_str: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
294
- """
295
- Handle the --set-global-config parameter.
296
-
297
- Args:
298
- config_str: Configuration string in format 'key=value'
299
- ctx: Typer context
300
- query: Query string
301
-
302
- Returns:
303
- bool: True if the program should exit after this operation
304
- """
305
- if config_str is not None:
306
- is_valid, result = validate_config_key_value(config_str)
307
- if not is_valid:
308
- console.print(f"[bold red]Error:[/bold red] {result}")
309
- return ctx.invoked_subcommand is None and not query
310
-
311
- key, value = result
312
- _handle_config_setting(key, value, "global")
313
-
314
- # Exit after applying config changes if no other operation is requested
315
- return ctx.invoked_subcommand is None and not query
316
-
317
- return False
318
-
319
- def handle_config_commands(
320
- ctx: typer.Context,
321
- reset_config: bool,
322
- reset_local_config: bool = False,
323
- reset_global_config: bool = False,
324
- workspace: Optional[str] = None,
325
- show_config: bool = False,
326
- profile: Optional[str] = None,
327
- role: Optional[str] = None,
328
- set_api_key: Optional[str] = None,
329
- set_local_config: Optional[str] = None,
330
- set_global_config: Optional[str] = None,
331
- query: Optional[str] = None,
332
- continue_flag: Optional[str] = None,
333
- history_flag: bool = False,
334
- history_count: Optional[int] = None
335
- ) -> bool:
336
- """
337
- Handle all configuration-related commands.
338
-
339
- Args:
340
- ctx: Typer context
341
- reset_config: Deprecated parameter kept for backward compatibility
342
- reset_local_config: Whether to reset the local configuration
343
- reset_global_config: Whether to reset the global configuration
344
- workspace: Workspace directory path
345
- show_config: Whether to show the configuration
346
- profile: Profile name
347
- role: Role name
348
- set_api_key: API key
349
- set_local_config: Configuration string in format 'key=value' for local config
350
- set_global_config: Configuration string in format 'key=value' for global config
351
- query: Query string
352
- continue_flag: Optional string that can be empty (flag only) or contain a chat ID
353
- history_flag: Whether to show conversation history (--history flag)
354
- history_count: Number of history entries to display (value after --history)
355
-
356
- Returns:
357
- bool: True if the program should exit after these operations
358
- """
359
- # Import these here to avoid circular imports
360
- from janito.cli.commands.workspace import handle_workspace
361
- from janito.cli.commands.profile import handle_profile, handle_role
362
- from janito.cli.commands.history import handle_history
363
-
364
- # Handle each command and check if we should exit after it
365
- if handle_reset_config(reset_config, ctx, query):
366
- return True
367
-
368
- if handle_reset_local_config(reset_local_config, ctx, query):
369
- return True
370
-
371
- if handle_reset_global_config(reset_global_config, ctx, query):
372
- return True
373
-
374
- handle_workspace(workspace)
375
-
376
- if handle_show_config(show_config, ctx, query):
377
- return True
378
-
379
- if handle_profile(profile, ctx, query):
380
- return True
381
-
382
- if handle_role(role, ctx, query):
383
- return True
384
-
385
- if handle_set_api_key(set_api_key, ctx, query):
386
- return True
387
-
388
- if handle_set_local_config(set_local_config, ctx, query):
389
- return True
390
-
391
- if handle_set_global_config(set_global_config, ctx, query):
392
- return True
393
-
394
- if handle_history(history_flag, history_count, ctx, query):
395
- return True
396
-
397
- return False
@@ -1,77 +0,0 @@
1
- """
2
- Validation functions for configuration-related CLI commands.
3
- """
4
- from typing import Tuple, Any, Union, Optional
5
-
6
- def validate_temperature(value: str) -> Tuple[bool, Union[float, str]]:
7
- """
8
- Validate a temperature value from a string input.
9
-
10
- Args:
11
- value: String representation of a temperature value
12
-
13
- Returns:
14
- Tuple of (is_valid, result)
15
- If valid, result is the float value
16
- If invalid, result is an error message
17
- """
18
- try:
19
- temp_value = float(value)
20
- if temp_value < 0.0 or temp_value > 1.0:
21
- return False, "Temperature must be between 0.0 and 1.0"
22
- return True, temp_value
23
- except ValueError:
24
- return False, f"Invalid temperature value: {value}. Must be a float between 0.0 and 1.0."
25
-
26
- def validate_boolean_value(value: str) -> Tuple[bool, Union[bool, str]]:
27
- """
28
- Validate a boolean value from a string input.
29
-
30
- Args:
31
- value: String representation of a boolean value
32
-
33
- Returns:
34
- Tuple of (is_valid, result)
35
- If valid, result is the boolean value
36
- If invalid, result is an error message
37
- """
38
- try:
39
- lower_value = value.lower()
40
- if lower_value in ["true", "yes", "1", "on", "y"]:
41
- return True, True
42
- elif lower_value in ["false", "no", "0", "off", "n"]:
43
- return True, False
44
- else:
45
- return False, f"Invalid boolean value: {value}. Use 'true', 'false', 'yes', 'no', '1', '0', 'on', or 'off'."
46
- except Exception:
47
- return False, f"Invalid boolean value: {value}. Use 'true', 'false', 'yes', 'no', '1', '0', 'on', or 'off'."
48
-
49
- def validate_config_key_value(config_str: str) -> Tuple[bool, Union[Tuple[str, str], str]]:
50
- """
51
- Validate a configuration key-value pair from a string input.
52
-
53
- Args:
54
- config_str: String in the format 'key=value'
55
-
56
- Returns:
57
- Tuple of (is_valid, result)
58
- If valid, result is a tuple of (key, value)
59
- If invalid, result is an error message
60
- """
61
- try:
62
- # Parse the config string
63
- config_parts = config_str.split("=", 1)
64
- if len(config_parts) != 2:
65
- return False, "Invalid configuration format. Use 'key=value' format."
66
-
67
- key = config_parts[0].strip()
68
- value = config_parts[1].strip()
69
-
70
- # Remove quotes if present
71
- if (value.startswith("'") and value.endswith("'")) or \
72
- (value.startswith('"') and value.endswith('"')):
73
- value = value[1:-1]
74
-
75
- return True, (key, value)
76
- except Exception as e:
77
- return False, f"Invalid configuration format: {str(e)}"
@@ -1,23 +0,0 @@
1
- """
2
- Core configuration components for Janito.
3
- Provides the base Config class and related functionality.
4
- """
5
- from .singleton import Config
6
- from .properties import ConfigProperties
7
- from .file_operations import (
8
- get_global_config_path,
9
- get_local_config_path,
10
- load_config_file,
11
- save_config_file,
12
- merge_configs
13
- )
14
-
15
- __all__ = [
16
- "Config",
17
- "ConfigProperties",
18
- "get_global_config_path",
19
- "get_local_config_path",
20
- "load_config_file",
21
- "save_config_file",
22
- "merge_configs"
23
- ]
@@ -1,90 +0,0 @@
1
- """
2
- File operations for configuration management.
3
- """
4
- import json
5
- from pathlib import Path
6
- from typing import Dict, Any, Optional
7
-
8
- def get_global_config_path() -> Path:
9
- """
10
- Get the path to the global configuration file.
11
-
12
- Returns:
13
- Path object pointing to the global configuration file (~/.janito/config.json)
14
- """
15
- return Path.home() / ".janito" / "config.json"
16
-
17
- def get_local_config_path(workspace_dir: str) -> Path:
18
- """
19
- Get the path to the local configuration file.
20
-
21
- Args:
22
- workspace_dir: Current workspace directory
23
-
24
- Returns:
25
- Path object pointing to the local configuration file (.janito/config.json)
26
- """
27
- return Path(workspace_dir) / ".janito" / "config.json"
28
-
29
- def load_config_file(config_path: Path) -> Dict[str, Any]:
30
- """
31
- Load configuration from a file.
32
-
33
- Args:
34
- config_path: Path to the configuration file
35
-
36
- Returns:
37
- Dict containing the configuration, empty dict if file doesn't exist or error occurs
38
- """
39
- if not config_path.exists():
40
- return {}
41
-
42
- try:
43
- with open(config_path, "r", encoding="utf-8") as f:
44
- return json.load(f)
45
- except Exception as e:
46
- print(f"Warning: Failed to load configuration from {config_path}: {str(e)}")
47
- return {}
48
-
49
- def save_config_file(config_path: Path, config_data: Dict[str, Any]) -> bool:
50
- """
51
- Save configuration to a file.
52
-
53
- Args:
54
- config_path: Path to the configuration file
55
- config_data: Configuration data to save
56
-
57
- Returns:
58
- True if successful, False otherwise
59
- """
60
- try:
61
- # Ensure directory exists
62
- config_path.parent.mkdir(parents=True, exist_ok=True)
63
-
64
- # Write configuration to file
65
- with open(config_path, "w", encoding="utf-8") as f:
66
- json.dump(config_data, f, indent=2)
67
- return True
68
- except Exception as e:
69
- print(f"Warning: Failed to save configuration to {config_path}: {str(e)}")
70
- return False
71
-
72
- def merge_configs(global_config: Dict[str, Any], local_config: Dict[str, Any]) -> Dict[str, Any]:
73
- """
74
- Merge global and local configurations with local taking precedence.
75
-
76
- Args:
77
- global_config: Global configuration dictionary
78
- local_config: Local configuration dictionary
79
-
80
- Returns:
81
- Merged configuration dictionary
82
- """
83
- # Start with global config
84
- merged_config = global_config.copy()
85
-
86
- # Override with local config
87
- for key, value in local_config.items():
88
- merged_config[key] = value
89
-
90
- return merged_config