tunacode-cli 0.0.32__py3-none-any.whl → 0.0.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 tunacode-cli might be problematic. Click here for more details.

tunacode/cli/commands.py CHANGED
@@ -6,7 +6,7 @@ from enum import Enum
6
6
  from typing import Any, Dict, List, Optional, Type
7
7
 
8
8
  from .. import utils
9
- from ..exceptions import ValidationError
9
+ from ..exceptions import ConfigurationError, ValidationError
10
10
  from ..types import CommandArgs, CommandContext, CommandResult, ProcessRequestCallback
11
11
  from ..ui import console as ui
12
12
 
@@ -184,8 +184,8 @@ class IterationsCommand(SimpleCommand):
184
184
  if args:
185
185
  try:
186
186
  new_limit = int(args[0])
187
- if new_limit < 1 or new_limit > 50:
188
- await ui.error("Iterations must be between 1 and 50")
187
+ if new_limit < 1 or new_limit > 100:
188
+ await ui.error("Iterations must be between 1 and 100")
189
189
  return
190
190
 
191
191
  # Update the user config
@@ -198,9 +198,9 @@ class IterationsCommand(SimpleCommand):
198
198
  except ValueError:
199
199
  await ui.error("Please provide a valid number")
200
200
  else:
201
- current = state.user_config.get("settings", {}).get("max_iterations", 15)
201
+ current = state.user_config.get("settings", {}).get("max_iterations", 40)
202
202
  await ui.info(f"Current maximum iterations: {current}")
203
- await ui.muted("Usage: /iterations <number> (1-50)")
203
+ await ui.muted("Usage: /iterations <number> (1-100)")
204
204
 
205
205
 
206
206
  class ClearCommand(SimpleCommand):
@@ -628,9 +628,13 @@ class ModelCommand(SimpleCommand):
628
628
 
629
629
  # Check if setting as default
630
630
  if len(args) > 1 and args[1] == "default":
631
- utils.user_configuration.set_default_model(model_name, context.state_manager)
632
- await ui.muted("Updating default model")
633
- return "restart"
631
+ try:
632
+ utils.user_configuration.set_default_model(model_name, context.state_manager)
633
+ await ui.muted("Updating default model")
634
+ return "restart"
635
+ except ConfigurationError as e:
636
+ await ui.error(str(e))
637
+ return None
634
638
 
635
639
  # Show success message with the new model
636
640
  await ui.success(f"Switched to model: {model_name}")
@@ -669,6 +673,35 @@ class CommandFactory:
669
673
  setattr(self.dependencies, key, value)
670
674
 
671
675
 
676
+ class InitCommand(SimpleCommand):
677
+ """Creates or updates TUNACODE.md with project-specific context."""
678
+
679
+ spec = CommandSpec(
680
+ name="/init",
681
+ aliases=[],
682
+ description="Analyze codebase and create/update TUNACODE.md file",
683
+ category=CommandCategory.DEVELOPMENT,
684
+ )
685
+
686
+ async def execute(self, args, context: CommandContext) -> CommandResult:
687
+ """Execute the init command."""
688
+ # Minimal implementation to make test pass
689
+ prompt = """Please analyze this codebase and create a TUNACODE.md file containing:
690
+ 1. Build/lint/test commands - especially for running a single test
691
+ 2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
692
+
693
+ The file you create will be given to agentic coding agents (such as yourself) that operate in this repository.
694
+ Make it about 20 lines long.
695
+ If there's already a TUNACODE.md, improve it.
696
+ If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md),
697
+ make sure to include them."""
698
+
699
+ # Call the agent to analyze and create/update the file
700
+ await context.process_request(prompt, context.state_manager)
701
+
702
+ return None
703
+
704
+
672
705
  class CommandRegistry:
673
706
  """Registry for managing commands with auto-discovery and categories."""
674
707
 
@@ -726,6 +759,7 @@ class CommandRegistry:
726
759
  BranchCommand,
727
760
  CompactCommand,
728
761
  ModelCommand,
762
+ InitCommand,
729
763
  ]
730
764
 
731
765
  # Register all discovered commands
tunacode/cli/repl.py CHANGED
@@ -88,12 +88,16 @@ async def _tool_confirm(tool_call, node, state_manager: StateManager):
88
88
 
89
89
  async def _tool_handler(part, node, state_manager: StateManager):
90
90
  """Handle tool execution with separated business logic and UI."""
91
- await ui.info(f"Tool({part.tool_name})")
91
+ # Create tool handler with state first to check if confirmation is needed
92
+ tool_handler = ToolHandler(state_manager)
93
+
94
+ # Only show tool info for tools that require confirmation
95
+ if tool_handler.should_confirm(part.tool_name):
96
+ await ui.info(f"Tool({part.tool_name})")
97
+
92
98
  state_manager.session.spinner.stop()
93
99
 
94
100
  try:
95
- # Create tool handler with state
96
- tool_handler = ToolHandler(state_manager)
97
101
  args = _parse_args(part.args)
98
102
 
99
103
  # Use a synchronous function in run_in_terminal to avoid async deadlocks
@@ -18,7 +18,7 @@ DEFAULT_USER_CONFIG: UserConfig = {
18
18
  },
19
19
  "settings": {
20
20
  "max_retries": 10,
21
- "max_iterations": 20,
21
+ "max_iterations": 40,
22
22
  "tool_ignore": [TOOL_READ_FILE],
23
23
  "guide_file": GUIDE_FILE_NAME,
24
24
  "fallback_response": True,
tunacode/constants.py CHANGED
@@ -7,7 +7,7 @@ Centralizes all magic strings, UI text, error messages, and application constant
7
7
 
8
8
  # Application info
9
9
  APP_NAME = "TunaCode"
10
- APP_VERSION = "0.0.32"
10
+ APP_VERSION = "0.0.34"
11
11
 
12
12
  # File patterns
13
13
  GUIDE_FILE_PATTERN = "{name}.md"
@@ -345,6 +345,11 @@ async def _process_node(
345
345
  # Check if ALL tools in this node are read-only
346
346
  all_read_only = all(part.tool_name in READ_ONLY_TOOLS for part in tool_parts)
347
347
 
348
+ # TODO: Currently only batches if ALL tools are read-only. Should be updated to use
349
+ # batch_read_only_tools() function to group consecutive read-only tools and execute
350
+ # them in parallel even when mixed with write/execute tools. For example:
351
+ # [read, read, write, read] should execute as: [read||read], [write], [read]
352
+ # instead of all sequential. The batch_read_only_tools() function exists but is unused.
348
353
  if all_read_only and len(tool_parts) > 1 and buffering_callback:
349
354
  # Execute read-only tools in parallel!
350
355
  import time
@@ -452,6 +457,26 @@ def get_or_create_agent(model: ModelName, state_manager: StateManager) -> Pydant
452
457
  # Use a default system prompt if neither file exists
453
458
  system_prompt = "You are a helpful AI assistant for software development tasks."
454
459
 
460
+ # Load TUNACODE.md context
461
+ # Use sync version of get_code_style to avoid nested event loop issues
462
+ try:
463
+ from pathlib import Path as PathlibPath
464
+
465
+ tunacode_path = PathlibPath.cwd() / "TUNACODE.md"
466
+ if tunacode_path.exists():
467
+ tunacode_content = tunacode_path.read_text(encoding="utf-8")
468
+ if tunacode_content.strip():
469
+ # Log that we found TUNACODE.md
470
+ print("📄 TUNACODE.md located: Loading context...")
471
+
472
+ system_prompt += "\n\n# Project Context from TUNACODE.md\n" + tunacode_content
473
+ else:
474
+ # Log that TUNACODE.md was not found
475
+ print("📄 TUNACODE.md not found: Using default context")
476
+ except Exception:
477
+ # Ignore errors loading TUNACODE.md
478
+ pass
479
+
455
480
  state_manager.session.agents[model] = Agent(
456
481
  model=model,
457
482
  system_prompt=system_prompt,
@@ -651,8 +676,8 @@ async def process_request(
651
676
  ) -> AgentRun:
652
677
  agent = get_or_create_agent(model, state_manager)
653
678
  mh = state_manager.session.messages.copy()
654
- # Get max iterations from config (default: 20)
655
- max_iterations = state_manager.session.user_config.get("settings", {}).get("max_iterations", 20)
679
+ # Get max iterations from config (default: 40)
680
+ max_iterations = state_manager.session.user_config.get("settings", {}).get("max_iterations", 40)
656
681
  fallback_enabled = state_manager.session.user_config.get("settings", {}).get(
657
682
  "fallback_response", True
658
683
  )
@@ -665,6 +690,14 @@ async def process_request(
665
690
  # Create a request-level buffer for batching read-only tools across nodes
666
691
  tool_buffer = ToolBuffer()
667
692
 
693
+ # Show TUNACODE.md preview if it was loaded and thoughts are enabled
694
+ if state_manager.session.show_thoughts and hasattr(state_manager, "tunacode_preview"):
695
+ from tunacode.ui import console as ui
696
+
697
+ await ui.muted(state_manager.tunacode_preview)
698
+ # Clear the preview after displaying it once
699
+ delattr(state_manager, "tunacode_preview")
700
+
668
701
  # Show what we're sending to the API when thoughts are enabled
669
702
  if state_manager.session.show_thoughts:
670
703
  from tunacode.ui import console as ui
@@ -82,9 +82,13 @@ class ConfigSetup(BaseSetup):
82
82
  ):
83
83
  self.state_manager.session.user_config = {}
84
84
  self.state_manager.session.user_config = DEFAULT_USER_CONFIG.copy()
85
- user_configuration.save_config(
86
- self.state_manager
87
- ) # Save the default config initially
85
+ try:
86
+ user_configuration.save_config(
87
+ self.state_manager
88
+ ) # Save the default config initially
89
+ except ConfigurationError as e:
90
+ await ui.error(str(e))
91
+ raise
88
92
  await self._onboarding()
89
93
  else:
90
94
  # No config found - show CLI usage instead of onboarding
@@ -172,11 +176,12 @@ class ConfigSetup(BaseSetup):
172
176
  # Compare configs to see if anything changed
173
177
  current_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
174
178
  if initial_config != current_config:
175
- if user_configuration.save_config(self.state_manager):
179
+ try:
180
+ user_configuration.save_config(self.state_manager)
176
181
  message = f"Config saved to: [bold]{self.config_file}[/bold]"
177
182
  await ui.panel("Finished", message, top=0, border_style=UI_COLORS["success"])
178
- else:
179
- await ui.error("Failed to save configuration.")
183
+ except ConfigurationError as e:
184
+ await ui.error(str(e))
180
185
  else:
181
186
  await ui.panel(
182
187
  "Setup canceled",
@@ -320,8 +325,9 @@ class ConfigSetup(BaseSetup):
320
325
  ]
321
326
 
322
327
  # Save the configuration
323
- if user_configuration.save_config(self.state_manager):
328
+ try:
329
+ user_configuration.save_config(self.state_manager)
324
330
  await ui.warning("Model set without validation - verify the model name is correct")
325
331
  await ui.success(f"Configuration saved to: {self.config_file}")
326
- else:
327
- await ui.error("Failed to save configuration.")
332
+ except ConfigurationError as e:
333
+ await ui.error(str(e))
@@ -58,11 +58,23 @@ def save_config(state_manager: "StateManager") -> bool:
58
58
  """Save user config to file"""
59
59
  app_settings = ApplicationSettings()
60
60
  try:
61
+ # Ensure config directory exists
62
+ app_settings.paths.config_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
63
+
64
+ # Write config file
61
65
  with open(app_settings.paths.config_file, "w") as f:
62
66
  json.dump(state_manager.session.user_config, f, indent=4)
63
67
  return True
64
- except Exception:
65
- return False
68
+ except PermissionError as e:
69
+ raise ConfigurationError(
70
+ f"Permission denied writing to {app_settings.paths.config_file}: {e}"
71
+ )
72
+ except OSError as e:
73
+ raise ConfigurationError(
74
+ f"Failed to save configuration to {app_settings.paths.config_file}: {e}"
75
+ )
76
+ except Exception as e:
77
+ raise ConfigurationError(f"Unexpected error saving configuration: {e}")
66
78
 
67
79
 
68
80
  def get_mcp_servers(state_manager: "StateManager") -> MCPServers:
@@ -73,4 +85,9 @@ def get_mcp_servers(state_manager: "StateManager") -> MCPServers:
73
85
  def set_default_model(model_name: ModelName, state_manager: "StateManager") -> bool:
74
86
  """Set the default model in the user config and save"""
75
87
  state_manager.session.user_config["default_model"] = model_name
76
- return save_config(state_manager)
88
+ try:
89
+ save_config(state_manager)
90
+ return True
91
+ except ConfigurationError:
92
+ # Re-raise ConfigurationError to be handled by caller
93
+ raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tunacode-cli
3
- Version: 0.0.32
3
+ Version: 0.0.34
4
4
  Summary: Your agentic CLI developer.
5
5
  Author-email: larock22 <noreply@github.com>
6
6
  License-Expression: MIT
@@ -40,6 +40,7 @@ Dynamic: license-file
40
40
  <div align="center">
41
41
 
42
42
  [![PyPI version](https://badge.fury.io/py/tunacode-cli.svg)](https://badge.fury.io/py/tunacode-cli)
43
+ [![Downloads](https://pepy.tech/badge/tunacode-cli)](https://pepy.tech/project/tunacode-cli)
43
44
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
44
45
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
46
 
@@ -78,6 +79,17 @@ tunacode --model "openrouter:openai/gpt-4o" --key "sk-or-your-openrouter-key"
78
79
 
79
80
  Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.config/tunacode.json`)
80
81
 
82
+ ### Recommended Models
83
+
84
+ Based on extensive testing, these models provide the best performance:
85
+ - `google/gemini-2.5-pro` - Excellent for complex reasoning
86
+ - `openai/gpt-4.1` - Strong general-purpose model
87
+ - `deepseek/deepseek-r1-0528` - Great for code generation
88
+ - `openai/gpt-4.1-mini` - Fast and cost-effective
89
+ - `anthropic/claude-4-sonnet-20250522` - Superior context handling
90
+
91
+ *Note: Formal evaluations coming soon. Any model can work, but these have shown the best results in practice.*
92
+
81
93
  ## Start Coding
82
94
 
83
95
  ```bash
@@ -105,6 +117,13 @@ TunaCode leverages parallel execution for read-only operations, achieving **3x f
105
117
 
106
118
  Multiple file reads, directory listings, and searches execute concurrently using async I/O, making code exploration significantly faster.
107
119
 
120
+ ## Features in Development
121
+
122
+ - **Streaming UI**: Currently working on implementing streaming responses for better user experience
123
+ - **Bug Fixes**: Actively addressing issues - please report any bugs you encounter!
124
+
125
+ *Note: While the tool is fully functional, we're focusing on stability and core features before optimizing for speed.*
126
+
108
127
  ## Safety First
109
128
 
110
129
  ⚠️ **Important**: TunaCode can modify your codebase. Always:
@@ -1,20 +1,18 @@
1
- api/auth.py,sha256=_ysF1RCXvtJR1S35lbYQZexES1lif4J6VVzEyqNK74Q,303
2
- api/users.py,sha256=WRcy1Vsr4cEC8CW2qeN3XrA9EMyIk47ufpMyvQ4nLuw,193
3
1
  tunacode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- tunacode/constants.py,sha256=HQGb-0hAm65zPpwvAmYoDMW-Ye_iMny4mNpeAxab_xU,4074
2
+ tunacode/constants.py,sha256=SIhhV5x1ESvfVaAki0nJ9XVlKZOwwomqIMT73FLyjPY,4074
5
3
  tunacode/context.py,sha256=6sterdRvPOyG3LU0nEAXpBsEPZbO3qtPyTlJBi-_VXE,2612
6
4
  tunacode/exceptions.py,sha256=mTWXuWyr1k16CGLWN2tsthDGi7lbx1JK0ekIqogYDP8,3105
7
5
  tunacode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
6
  tunacode/setup.py,sha256=dYn0NeAxtNIDSogWEmGSyjb9wsr8AonZ8vAo5sw9NIw,1909
9
7
  tunacode/types.py,sha256=BciT-uxnQ44iC-4QiDY72OD23LOtqSyMOuK_N0ttlaA,7676
10
8
  tunacode/cli/__init__.py,sha256=zgs0UbAck8hfvhYsWhWOfBe5oK09ug2De1r4RuQZREA,55
11
- tunacode/cli/commands.py,sha256=w1bqLuxkKoavvXrpARFi5qg3yfYx_MA-1COyPj9RJGw,29884
9
+ tunacode/cli/commands.py,sha256=DEEfDVNzDmMRUhA7JfWGh8antnMeb3G6LmaJLqNVsoI,31293
12
10
  tunacode/cli/main.py,sha256=PIcFnfmIoI_pmK2y-zB_ouJbzR5fbSI7zsKQNPB_J8o,2406
13
- tunacode/cli/repl.py,sha256=AYVU-k8yKa8LjJg3s3vu5LrHyMUIShtgUlyakwb-rh4,13583
11
+ tunacode/cli/repl.py,sha256=o3bn9BYQsy3TFCWJq-fzeHKLrM2KInSrMF5E5_RqSOY,13736
14
12
  tunacode/cli/textual_app.py,sha256=14-Nt0IIETmyHBrNn9uwSF3EwCcutwTp6gdoKgNm0sY,12593
15
13
  tunacode/cli/textual_bridge.py,sha256=LvqiTtF0hu3gNujzpKaW9h-m6xzEP3OH2M8KL2pCwRc,6333
16
14
  tunacode/configuration/__init__.py,sha256=MbVXy8bGu0yKehzgdgZ_mfWlYGvIdb1dY2Ly75nfuPE,17
17
- tunacode/configuration/defaults.py,sha256=oLgmHprB3cTaFvT9dn_rgg206zoj09GRXRbI7MYijxA,801
15
+ tunacode/configuration/defaults.py,sha256=lNeJUW1S8zj4-XTCkMP9UaDc-tHWXLff9K8t0uPA_oE,801
18
16
  tunacode/configuration/models.py,sha256=XPobkLM_TzKTuMIWhK-svJfGRGFT9r2LhKEM6rv6QHk,3756
19
17
  tunacode/configuration/settings.py,sha256=lm2ov8rG1t4C5JIXMOhIKik5FAsjpuLVYtFmnE1ZQ3k,995
20
18
  tunacode/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -22,14 +20,14 @@ tunacode/core/code_index.py,sha256=jgAx3lSWP_DwnyiP5Jkm1YvX4JJyI4teMzlNrJSpEOA,1
22
20
  tunacode/core/state.py,sha256=PHGCGjx_X03I5jO-T1JkREQm4cwYEXQty59JJlnk24c,1608
23
21
  tunacode/core/tool_handler.py,sha256=BPjR013OOO0cLXPdLeL2FDK0ixUwOYu59FfHdcdFhp4,2277
24
22
  tunacode/core/agents/__init__.py,sha256=UUJiPYb91arwziSpjd7vIk7XNGA_4HQbsOIbskSqevA,149
25
- tunacode/core/agents/main.py,sha256=HuDVLFp18MWONjrAtAPZgigVpAGB8KmbA-Idx0ElAQs,37736
23
+ tunacode/core/agents/main.py,sha256=-QwKSKoPLdD-JlKPjwMUSxNu_TSrj-pdUleWR2FN-A0,39441
26
24
  tunacode/core/background/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
25
  tunacode/core/background/manager.py,sha256=rJdl3eDLTQwjbT7VhxXcJbZopCNR3M8ZGMbmeVnwwMc,1126
28
26
  tunacode/core/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
27
  tunacode/core/setup/__init__.py,sha256=lzdpY6rIGf9DDlDBDGFvQZaSOQeFsNglHbkpq1-GtU8,376
30
28
  tunacode/core/setup/agent_setup.py,sha256=trELO8cPnWo36BBnYmXDEnDPdhBg0p-VLnx9A8hSSSQ,1401
31
29
  tunacode/core/setup/base.py,sha256=cbyT2-xK2mWgH4EO17VfM_OM2bj0kT895NW2jSXbe3c,968
32
- tunacode/core/setup/config_setup.py,sha256=A1MEbkZq2FvVg9FNlLD9_JO_vlr0ixP-6Ay0-2W7VvQ,14330
30
+ tunacode/core/setup/config_setup.py,sha256=LnIGZrqDCWUhiMhJMnKX1gyaZhy6pKM8xf_fy_t9B3U,14516
33
31
  tunacode/core/setup/coordinator.py,sha256=oVTN2xIeJERXitVJpkIk9tDGLs1D1bxIRmaogJwZJFI,2049
34
32
  tunacode/core/setup/environment_setup.py,sha256=n3IrObKEynHZSwtUJ1FddMg2C4sHz7ca42awemImV8s,2225
35
33
  tunacode/core/setup/git_safety_setup.py,sha256=CRIqrQt0QUJQRS344njty_iCqTorrDhHlXRuET7w0Tk,6714
@@ -69,10 +67,10 @@ tunacode/utils/ripgrep.py,sha256=AXUs2FFt0A7KBV996deS8wreIlUzKOlAHJmwrcAr4No,583
69
67
  tunacode/utils/system.py,sha256=FSoibTIH0eybs4oNzbYyufIiV6gb77QaeY2yGqW39AY,11381
70
68
  tunacode/utils/text_utils.py,sha256=zRBaorvtyd7HBEWtIfCH1Wce1L6rhsQwpORUEGBFMjA,2981
71
69
  tunacode/utils/token_counter.py,sha256=nGCWwrHHFbKywqeDCEuJnADCkfJuzysWiB6cCltJOKI,648
72
- tunacode/utils/user_configuration.py,sha256=IGvUH37wWtZ4M5xpukZEWYhtuKKyKcl6DaeObGXdleU,2610
73
- tunacode_cli-0.0.32.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
74
- tunacode_cli-0.0.32.dist-info/METADATA,sha256=uX02OQdTT5lrmAm6XFSO1IKEmv9uw9lkG1UGaVOcbcU,4023
75
- tunacode_cli-0.0.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
76
- tunacode_cli-0.0.32.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
77
- tunacode_cli-0.0.32.dist-info/top_level.txt,sha256=GuU751acRvOhM5yLKFW0-gBg62JGh5zycDSq4tRFOYE,13
78
- tunacode_cli-0.0.32.dist-info/RECORD,,
70
+ tunacode/utils/user_configuration.py,sha256=Ilz8dpGVJDBE2iLWHAPT0xR8D51VRKV3kIbsAz8Bboc,3275
71
+ tunacode_cli-0.0.34.dist-info/licenses/LICENSE,sha256=Btzdu2kIoMbdSp6OyCLupB1aRgpTCJ_szMimgEnpkkE,1056
72
+ tunacode_cli-0.0.34.dist-info/METADATA,sha256=uZKr-BnaxT_7vB1gTSIMEnWx1tfOSbBtPAt7gY4pibY,4943
73
+ tunacode_cli-0.0.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
74
+ tunacode_cli-0.0.34.dist-info/entry_points.txt,sha256=hbkytikj4dGu6rizPuAd_DGUPBGF191RTnhr9wdhORY,51
75
+ tunacode_cli-0.0.34.dist-info/top_level.txt,sha256=lKy2P6BWNi5XSA4DHFvyjQ14V26lDZctwdmhEJrxQbU,9
76
+ tunacode_cli-0.0.34.dist-info/RECORD,,
api/auth.py DELETED
@@ -1,13 +0,0 @@
1
- import jwt
2
-
3
-
4
- def authenticate(username, password):
5
- # TODO: Add password hashing
6
- if username == "admin" and password == "admin":
7
- return generate_token(username)
8
- return None
9
-
10
-
11
- def generate_token(username):
12
- # TODO: Add expiration
13
- return jwt.encode({"user": username}, "secret")
api/users.py DELETED
@@ -1,8 +0,0 @@
1
- from .auth import authenticate
2
-
3
-
4
- class UserManager:
5
- def login(self, username, password):
6
- token = authenticate(username, password)
7
- # TODO: Store session
8
- return token