locally796 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Prathmesh Ravindra Salunkhe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: locally796
3
+ Version: 0.1.0
4
+ Summary: AI-powered CLI tool to setup GitHub repositories locally
5
+ Author-email: Prathmesh Salunkhe <salunkheprathmesh0@gmail.com>
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: typer
10
+ Requires-Dist: rich
11
+ Requires-Dist: gitpython
12
+ Requires-Dist: langchain
13
+ Dynamic: license-file
14
+
15
+ # Locally796
16
+
17
+ **Locally796** is an AI-powered CLI tool that automatically clones any GitHub repository and sets it up on your local machine — no manual configuration needed. Powered by a LangChain agent, it detects the project stack, installs dependencies, configures environment variables, and runs the project for you.
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - 🤖 **AI-Driven Setup** — A LangChain agent acts as a senior DevOps engineer, analysing the repository, running the right install commands, and resolving errors automatically.
24
+ - 🔍 **Stack Detection** — Automatically identifies the project stack (Node.js, Python, Go, etc.) and applies the appropriate setup steps.
25
+ - ⚙️ **Dependency Installation** — Runs `npm install`, `pip install -r requirements.txt`, `go mod tidy`, and similar commands as needed.
26
+ - 🌿 **Environment Configuration** — Detects `.env.example` files and sets up environment variables for you.
27
+ - 🚀 **Project Launch** — Starts the project after setup and confirms it is running.
28
+ - 📦 **pip Package** — Distributed as a Python package, so you can install and use it anywhere with a single command.
29
+
30
+ ---
31
+
32
+ ## Requirements
33
+
34
+ - Python 3.11 or higher
35
+ - A [Groq](https://console.groq.com/) API key to power the AI agent.
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ You can install `locally796` globally using `pip`:
42
+
43
+ ```bash
44
+ pip install locally796
45
+ ```
46
+
47
+ *(Alternatively, to install from source: clone this repo and run `pip install -e .` inside the folder.)*
48
+
49
+ ### Setup Your API Key
50
+
51
+ Before using `locally796` for the first time, you need to configure your Groq API key. The agent defaults to `llama-3.3-70b-versatile`, which is available for any standard Groq account.
52
+
53
+ ```bash
54
+ locally796 set-key <YOUR_GROQ_API_KEY>
55
+ ```
56
+
57
+ This securely saves your key in a global config file (`~/.locally796/.env`), meaning you can run the tool from anywhere on your system without having to set up `.env` files manually.
58
+
59
+ ---
60
+
61
+ ## Usage
62
+
63
+ ```bash
64
+ locally796 [GITHUB_REPO_URL] --path [CLONING_PATH]
65
+ ```
66
+
67
+ ### Arguments
68
+
69
+ | Argument | Description |
70
+ |---|---|
71
+ | `GITHUB_REPO_URL` | The full URL of the GitHub repository to clone and set up |
72
+ | `--path` / `-p` | *(Optional)* Local directory path where the repo will be cloned. Defaults to a folder named after the repo in the current directory |
73
+
74
+ ### Example
75
+
76
+ ```bash
77
+ locally796 https://github.com/prathmesh796/pubsubs --path ./test-clone
78
+ ```
79
+
80
+ This single command will autonomously:
81
+ 1. Clone the repository into `./test-clone`
82
+ 2. Detect the technology stack (e.g. Node.js, Python)
83
+ 3. Launch the LangChain Agent to investigate the codebase.
84
+ 4. Install all required dependencies (`npm install`, `pip install`, etc.)
85
+ 5. Configure environment variables (if `.env.example` is present)
86
+ 6. Start the local development server (e.g., `npm run dev`)
87
+ 7. Automatically detect and fix any deployment errors if the server fails to start!
88
+
89
+ ---
90
+
91
+ ## How It Works
92
+
93
+ 1. **Clone** — The repo is cloned to the specified (or auto-generated) local path using GitPython.
94
+ 2. **Detect** — The stack detector inspects the repository files to identify languages and frameworks.
95
+ 3. **Agent Setup** — A LangChain agent equipped with shell, file-read, and file-write tools executes the full setup autonomously. If a command fails or crashes, the agent reads the error output, figures out the fix, and retries until success!
96
+ 4. **Done** — The agent reports `SETUP_COMPLETE` and leaves the server running for you.
97
+
98
+ ---
99
+
100
+ ## License
101
+
102
+ MIT
103
+
@@ -0,0 +1,89 @@
1
+ # Locally796
2
+
3
+ **Locally796** is an AI-powered CLI tool that automatically clones any GitHub repository and sets it up on your local machine — no manual configuration needed. Powered by a LangChain agent, it detects the project stack, installs dependencies, configures environment variables, and runs the project for you.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - 🤖 **AI-Driven Setup** — A LangChain agent acts as a senior DevOps engineer, analysing the repository, running the right install commands, and resolving errors automatically.
10
+ - 🔍 **Stack Detection** — Automatically identifies the project stack (Node.js, Python, Go, etc.) and applies the appropriate setup steps.
11
+ - ⚙️ **Dependency Installation** — Runs `npm install`, `pip install -r requirements.txt`, `go mod tidy`, and similar commands as needed.
12
+ - 🌿 **Environment Configuration** — Detects `.env.example` files and sets up environment variables for you.
13
+ - 🚀 **Project Launch** — Starts the project after setup and confirms it is running.
14
+ - 📦 **pip Package** — Distributed as a Python package, so you can install and use it anywhere with a single command.
15
+
16
+ ---
17
+
18
+ ## Requirements
19
+
20
+ - Python 3.11 or higher
21
+ - A [Groq](https://console.groq.com/) API key to power the AI agent.
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ You can install `locally796` globally using `pip`:
28
+
29
+ ```bash
30
+ pip install locally796
31
+ ```
32
+
33
+ *(Alternatively, to install from source: clone this repo and run `pip install -e .` inside the folder.)*
34
+
35
+ ### Setup Your API Key
36
+
37
+ Before using `locally796` for the first time, you need to configure your Groq API key. The agent defaults to `llama-3.3-70b-versatile`, which is available for any standard Groq account.
38
+
39
+ ```bash
40
+ locally796 set-key <YOUR_GROQ_API_KEY>
41
+ ```
42
+
43
+ This securely saves your key in a global config file (`~/.locally796/.env`), meaning you can run the tool from anywhere on your system without having to set up `.env` files manually.
44
+
45
+ ---
46
+
47
+ ## Usage
48
+
49
+ ```bash
50
+ locally796 [GITHUB_REPO_URL] --path [CLONING_PATH]
51
+ ```
52
+
53
+ ### Arguments
54
+
55
+ | Argument | Description |
56
+ |---|---|
57
+ | `GITHUB_REPO_URL` | The full URL of the GitHub repository to clone and set up |
58
+ | `--path` / `-p` | *(Optional)* Local directory path where the repo will be cloned. Defaults to a folder named after the repo in the current directory |
59
+
60
+ ### Example
61
+
62
+ ```bash
63
+ locally796 https://github.com/prathmesh796/pubsubs --path ./test-clone
64
+ ```
65
+
66
+ This single command will autonomously:
67
+ 1. Clone the repository into `./test-clone`
68
+ 2. Detect the technology stack (e.g. Node.js, Python)
69
+ 3. Launch the LangChain Agent to investigate the codebase.
70
+ 4. Install all required dependencies (`npm install`, `pip install`, etc.)
71
+ 5. Configure environment variables (if `.env.example` is present)
72
+ 6. Start the local development server (e.g., `npm run dev`)
73
+ 7. Automatically detect and fix any deployment errors if the server fails to start!
74
+
75
+ ---
76
+
77
+ ## How It Works
78
+
79
+ 1. **Clone** — The repo is cloned to the specified (or auto-generated) local path using GitPython.
80
+ 2. **Detect** — The stack detector inspects the repository files to identify languages and frameworks.
81
+ 3. **Agent Setup** — A LangChain agent equipped with shell, file-read, and file-write tools executes the full setup autonomously. If a command fails or crashes, the agent reads the error output, figures out the fix, and retries until success!
82
+ 4. **Done** — The agent reports `SETUP_COMPLETE` and leaves the server running for you.
83
+
84
+ ---
85
+
86
+ ## License
87
+
88
+ MIT
89
+
File without changes
File without changes
@@ -0,0 +1,59 @@
1
+ import typer
2
+ import os
3
+ from typing import Optional
4
+ from rich.console import Console
5
+
6
+ from app.services.repo import clone_repo
7
+ from app.services.detector import detect_stack
8
+ from app.core.agent import run_setup_and_start
9
+ from app.utils.logger import logger
10
+
11
+ app = typer.Typer(help="Locally796 - AI powered CLI tool to clone and run any repo.", add_completion=False)
12
+ console = Console()
13
+
14
+ @app.command()
15
+ def set_key(api_key: str = typer.Argument(..., help="Your Groq API Key")):
16
+ """Sets the global Groq API key for Locally796."""
17
+ home_dir = os.path.expanduser("~/.locally796")
18
+ os.makedirs(home_dir, exist_ok=True)
19
+ env_file = os.path.join(home_dir, ".env")
20
+
21
+ with open(env_file, "w") as f:
22
+ f.write(f"GROQ_API_KEY={api_key}\n")
23
+
24
+ console.print("[bold green]✅ API Key saved successfully![/bold green] You can now run `locally796` from anywhere.")
25
+
26
+ @app.command()
27
+ def clone_and_run(
28
+ repo_url: str = typer.Argument(..., help="The GitHub repository URL to process"),
29
+ path: Optional[str] = typer.Option(None, "--path", "-p", help="Destination path for cloning"),
30
+ ):
31
+ """
32
+ Clone a repository, detect stack, install dependencies, and run it.
33
+ """
34
+ console.print(f"[bold blue]Starting Locally796 for:[/bold blue] {repo_url}")
35
+ if path:
36
+ target_path = path
37
+ else:
38
+ # Predict the repo name from the url
39
+ base_name = repo_url.rstrip('/').split('/')[-1]
40
+ if base_name.endswith('.git'):
41
+ base_name = base_name[:-4]
42
+ target_path = os.path.join(os.getcwd(), base_name)
43
+
44
+ console.print(f"[bold blue]Target path:[/bold blue] {target_path}")
45
+
46
+ # Step 1: Clone Repo
47
+ success = clone_repo(repo_url, target_path)
48
+ if not success:
49
+ console.print("[bold red]Aborting due to clone failure.[/bold red]")
50
+ raise typer.Exit(code=1)
51
+
52
+ # Step 2: Detect Stack
53
+ detected_stacks = detect_stack(target_path)
54
+
55
+ # Step 3: Run Setup Agent
56
+ run_setup_and_start(target_path, detected_stacks)
57
+
58
+ if __name__ == "__main__":
59
+ app()
File without changes
@@ -0,0 +1,10 @@
1
+ import platform
2
+
3
+ os_name = platform.system()
4
+
5
+ if os_name == "Windows":
6
+ print("Running on Windows")
7
+ elif os_name == "Darwin":
8
+ print("Mac")
9
+ else:
10
+ print("Linux")
@@ -0,0 +1,14 @@
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ home_env = os.path.expanduser("~/.locally796/.env")
5
+ if os.path.exists(home_env):
6
+ load_dotenv(home_env)
7
+
8
+ load_dotenv()
9
+
10
+ class Settings:
11
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
12
+ LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
13
+
14
+ settings = Settings()
File without changes
@@ -0,0 +1,58 @@
1
+ from langchain_classic.agents import AgentExecutor, create_tool_calling_agent
2
+ from langchain_core.tools import tool
3
+ from langchain_core.prompts import ChatPromptTemplate
4
+ from app.core.llm import get_llm
5
+ from app.core.tools import run_shell_command, read_file, list_dir, write_file
6
+ from app.utils.logger import logger, console
7
+
8
+ AGENT_SYSTEM_PROMPT = """You are a senior DevOps engineer and setup assistant.
9
+ Your task is to properly setup and run a software project.
10
+
11
+ You have the following capabilities:
12
+ 1. Examine project files and directories to understand the structure.
13
+ 2. Formulate necessary setup commands (e.g. `npm install`, `pip install -r requirements.txt`, `go mod tidy`).
14
+ 3. Set up environment variables if a `.env.example` exists.
15
+ 4. Execute run commands (e.g. `npm run dev`, `python app.py`) to verify it works.
16
+
17
+ If a command fails, read its output, figure out the issue, fix it, and retry.
18
+ NEVER execute obviously destructive commands (like `rm -rf /`).
19
+ Always execute commands in the correct `cwd` which the user provides as context.
20
+ Important: When running a dev server that blocks (like `npm run dev`), if it prints 'compiled successfully' or starts listening on a port, consider the step SUCCESSFUL. Our executor incorporates a 60-second timeout. If it prints a timeout error but indicates a server has started, consider the operation successful.
21
+
22
+ When you have successfully set everything up and run the project, respond with "SETUP_COMPLETE" and explain what you did.
23
+
24
+ CRITICAL TOOL USAGE INSTRUCTION:
25
+ When calling a tool, ensure the tool name strictly matches the function name (e.g., 'list_dir'). DO NOT put JSON arguments or string blocks inside the tool name field itself! Provide arguments normally via the valid arguments object.
26
+ """
27
+
28
+ def run_setup_and_start(target_path: str, detected_stacks: list):
29
+ try:
30
+ llm = get_llm()
31
+ except Exception as e:
32
+ console.print(f"[bold red]LLM Initialization Error:[/bold red] {e}")
33
+ return
34
+
35
+ tools = [run_shell_command, read_file, list_dir, write_file]
36
+
37
+ prompt = ChatPromptTemplate.from_messages([
38
+ ("system", AGENT_SYSTEM_PROMPT),
39
+ ("human", "Set up the project in the `{target_path}` directory.\nDetected stacks: {detected_stacks}.\nPlease execute the installation steps and then run the project. Use your tools sequentially to accomplish this."),
40
+ ("placeholder", "{agent_scratchpad}"),
41
+ ])
42
+
43
+ agent = create_tool_calling_agent(llm, tools, prompt)
44
+ agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
45
+
46
+ console.print(f"[bold blue]Initializing Setup Agent for:[/bold blue] {target_path}")
47
+ logger.info("Starting agent executor.")
48
+
49
+ try:
50
+ response = agent_executor.invoke({
51
+ "target_path": target_path,
52
+ "detected_stacks": ", ".join(detected_stacks) if detected_stacks else "Unknown"
53
+ })
54
+ console.print("[bold green]Agent completed its process.[/bold green]")
55
+ logger.info(f"Agent response: {response.get('output', '')}")
56
+ except Exception as e:
57
+ console.print(f"[bold red]Agent encountered a fatal error:[/bold red] {e}")
58
+ logger.error(f"Agent execution failed: {e}")
@@ -0,0 +1,12 @@
1
+ from langchain_groq import ChatGroq
2
+ from app.config.settings import settings
3
+
4
+ def get_llm():
5
+ if not settings.GROQ_API_KEY:
6
+ raise ValueError("GROQ_API_KEY is not set. Please run 'locally796 set-key <YOUR_API_KEY>' to configure it globally.")
7
+ return ChatGroq(
8
+ model="llama-3.3-70b-versatile",
9
+ api_key=settings.GROQ_API_KEY,
10
+ temperature=0.2,
11
+ max_retries=2
12
+ )
@@ -0,0 +1,49 @@
1
+ import os
2
+ from langchain.tools import tool
3
+ from app.services.executor import execute_command
4
+
5
+ @tool
6
+ def run_shell_command(command: str, cwd: str) -> str:
7
+ """
8
+ Executes a shell command in the specified directory (cwd) and returns its output.
9
+ Useful for installing dependencies, running the app, or fixing environments.
10
+ """
11
+ res = execute_command(command, cwd)
12
+ output = f"Status: {res['status']}\nExit code: {res['return_code']}\n"
13
+ if res['stdout']:
14
+ output += f"STDOUT:\n{res['stdout']}\n"
15
+ if res['stderr']:
16
+ output += f"STDERR:\n{res['stderr']}\n"
17
+ return output
18
+
19
+ @tool
20
+ def read_file(file_path: str) -> str:
21
+ """Reads the contents of a file."""
22
+ if not os.path.exists(file_path):
23
+ return f"Error: File '{file_path}' does not exist."
24
+ try:
25
+ with open(file_path, "r", encoding="utf-8") as f:
26
+ return f.read()
27
+ except Exception as e:
28
+ return f"Error reading file '{file_path}': {str(e)}"
29
+
30
+ @tool
31
+ def list_dir(directory: str) -> str:
32
+ """Lists files and directories in the specified directory."""
33
+ if not os.path.exists(directory):
34
+ return f"Error: Directory '{directory}' does not exist."
35
+ try:
36
+ items = os.listdir(directory)
37
+ return "\n".join(items) if items else "Directory is empty."
38
+ except Exception as e:
39
+ return f"Error listing directory '{directory}': {str(e)}"
40
+
41
+ @tool
42
+ def write_file(file_path: str, content: str) -> str:
43
+ """Writes content to a file. Useful for creating .env files or fixing configs."""
44
+ try:
45
+ with open(file_path, "w", encoding="utf-8") as f:
46
+ f.write(content)
47
+ return f"File '{file_path}' written successfully."
48
+ except Exception as e:
49
+ return f"Error writing file '{file_path}': {str(e)}"
@@ -0,0 +1,5 @@
1
+ import typer
2
+ from app.cli.app import app
3
+
4
+ if __name__ == "__main__":
5
+ app()
File without changes
@@ -0,0 +1,24 @@
1
+ import os
2
+ from typing import List
3
+ from app.utils.constants import STACK_FILES
4
+ from app.utils.logger import logger, console
5
+
6
+ def detect_stack(target_path: str) -> List[str]:
7
+ detected = []
8
+ logger.info(f"Detecting stack in {target_path}...")
9
+ for filename, stack_name in STACK_FILES.items():
10
+ file_path = os.path.join(target_path, filename)
11
+ if os.path.exists(file_path):
12
+ detected.append(stack_name)
13
+
14
+ # Deduplicate while preserving order if needed
15
+ detected = list(set(detected))
16
+
17
+ if detected:
18
+ console.print(f"[bold green]✓ Detected Stack:[/bold green] {', '.join(detected)}")
19
+ logger.info(f"Detected stacks: {detected}")
20
+ else:
21
+ console.print("[yellow]⚠ Could not automatically detect a standard stack.[/yellow]")
22
+ logger.warning("No stack detected.")
23
+
24
+ return detected
@@ -0,0 +1,58 @@
1
+ import subprocess
2
+ import sys
3
+ from typing import Dict, Any
4
+ from app.utils.logger import logger, console
5
+
6
+ def execute_command(command: str, cwd: str, timeout: int = 60) -> Dict[str, Any]:
7
+ """Execute a shell command and return its output. Includes a timeout for long-running processes."""
8
+ logger.info(f"Executing: `{command}` in {cwd} with timeout {timeout}s")
9
+ console.print(f"[dim]Running:[/dim] {command}")
10
+
11
+ try:
12
+ process = subprocess.Popen(
13
+ command,
14
+ cwd=cwd,
15
+ shell=True,
16
+ text=True,
17
+ stdout=subprocess.PIPE,
18
+ stderr=subprocess.PIPE
19
+ )
20
+
21
+ try:
22
+ stdout, stderr = process.communicate(timeout=timeout)
23
+ return {
24
+ "command": command,
25
+ "return_code": process.returncode,
26
+ "stdout": stdout.strip() if stdout else "",
27
+ "stderr": stderr.strip() if stderr else "",
28
+ "status": "completed"
29
+ }
30
+ except subprocess.TimeoutExpired:
31
+ logger.warning(f"Execution timed out after {timeout} seconds.")
32
+
33
+ if sys.platform == "win32":
34
+ subprocess.run(f"taskkill /F /T /PID {process.pid}", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
35
+ else:
36
+ process.kill()
37
+
38
+ try:
39
+ stdout, stderr = process.communicate(timeout=2)
40
+ except subprocess.TimeoutExpired:
41
+ stdout, stderr = "Process is still running (Timeout reached). Likely a server started successfully.", ""
42
+
43
+ return {
44
+ "command": command,
45
+ "return_code": 0,
46
+ "stdout": stdout.strip() if stdout else "Process is still running (Timeout reached). Likely a server started successfully.",
47
+ "stderr": stderr.strip() if stderr else "",
48
+ "status": "timeout"
49
+ }
50
+ except Exception as e:
51
+ logger.error(f"Execution failed: {e}")
52
+ return {
53
+ "command": command,
54
+ "return_code": -1,
55
+ "stdout": "",
56
+ "stderr": str(e),
57
+ "status": "error"
58
+ }
@@ -0,0 +1,21 @@
1
+ import os
2
+ import git
3
+ from app.utils.logger import logger, console
4
+
5
+ def clone_repo(repo_url: str, target_path: str) -> bool:
6
+ try:
7
+ if os.path.exists(target_path) and os.path.isdir(target_path):
8
+ if os.listdir(target_path):
9
+ logger.info(f"Target directory {target_path} already exists and is not empty.")
10
+ console.print(f"[yellow]Skipping clone, directory not empty: {target_path}[/yellow]")
11
+ return True
12
+ logger.info(f"Cloning {repo_url} into {target_path}...")
13
+ with console.status(f"[bold green]Cloning {repo_url}...[/bold green]"):
14
+ git.Repo.clone_from(repo_url, target_path)
15
+ logger.info("Clone completed successfully.")
16
+ console.print("[bold green]✓ Repository cloned successfully.[/bold green]")
17
+ return True
18
+ except Exception as e:
19
+ logger.error(f"Failed to clone repository: {str(e)}")
20
+ console.print(f"[bold red]✗ Failed to clone repository: {str(e)}[/bold red]")
21
+ return False
File without changes
@@ -0,0 +1,9 @@
1
+ STACK_FILES = {
2
+ "package.json": "Node.js",
3
+ "requirements.txt": "Python",
4
+ "pyproject.toml": "Python",
5
+ "go.mod": "Go",
6
+ "Cargo.toml": "Rust",
7
+ "pom.xml": "Java",
8
+ "Dockerfile": "Docker"
9
+ }
@@ -0,0 +1,16 @@
1
+ import logging
2
+ from rich.console import Console
3
+ from rich.logging import RichHandler
4
+
5
+ console = Console()
6
+
7
+ def get_logger(name: str):
8
+ logging.basicConfig(
9
+ level="INFO",
10
+ format="%(message)s",
11
+ datefmt="[%X]",
12
+ handlers=[RichHandler(rich_tracebacks=True)]
13
+ )
14
+ return logging.getLogger(name)
15
+
16
+ logger = get_logger("locally796")
@@ -0,0 +1,103 @@
1
+ Metadata-Version: 2.4
2
+ Name: locally796
3
+ Version: 0.1.0
4
+ Summary: AI-powered CLI tool to setup GitHub repositories locally
5
+ Author-email: Prathmesh Salunkhe <salunkheprathmesh0@gmail.com>
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: typer
10
+ Requires-Dist: rich
11
+ Requires-Dist: gitpython
12
+ Requires-Dist: langchain
13
+ Dynamic: license-file
14
+
15
+ # Locally796
16
+
17
+ **Locally796** is an AI-powered CLI tool that automatically clones any GitHub repository and sets it up on your local machine — no manual configuration needed. Powered by a LangChain agent, it detects the project stack, installs dependencies, configures environment variables, and runs the project for you.
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - 🤖 **AI-Driven Setup** — A LangChain agent acts as a senior DevOps engineer, analysing the repository, running the right install commands, and resolving errors automatically.
24
+ - 🔍 **Stack Detection** — Automatically identifies the project stack (Node.js, Python, Go, etc.) and applies the appropriate setup steps.
25
+ - ⚙️ **Dependency Installation** — Runs `npm install`, `pip install -r requirements.txt`, `go mod tidy`, and similar commands as needed.
26
+ - 🌿 **Environment Configuration** — Detects `.env.example` files and sets up environment variables for you.
27
+ - 🚀 **Project Launch** — Starts the project after setup and confirms it is running.
28
+ - 📦 **pip Package** — Distributed as a Python package, so you can install and use it anywhere with a single command.
29
+
30
+ ---
31
+
32
+ ## Requirements
33
+
34
+ - Python 3.11 or higher
35
+ - A [Groq](https://console.groq.com/) API key to power the AI agent.
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ You can install `locally796` globally using `pip`:
42
+
43
+ ```bash
44
+ pip install locally796
45
+ ```
46
+
47
+ *(Alternatively, to install from source: clone this repo and run `pip install -e .` inside the folder.)*
48
+
49
+ ### Setup Your API Key
50
+
51
+ Before using `locally796` for the first time, you need to configure your Groq API key. The agent defaults to `llama-3.3-70b-versatile`, which is available for any standard Groq account.
52
+
53
+ ```bash
54
+ locally796 set-key <YOUR_GROQ_API_KEY>
55
+ ```
56
+
57
+ This securely saves your key in a global config file (`~/.locally796/.env`), meaning you can run the tool from anywhere on your system without having to set up `.env` files manually.
58
+
59
+ ---
60
+
61
+ ## Usage
62
+
63
+ ```bash
64
+ locally796 [GITHUB_REPO_URL] --path [CLONING_PATH]
65
+ ```
66
+
67
+ ### Arguments
68
+
69
+ | Argument | Description |
70
+ |---|---|
71
+ | `GITHUB_REPO_URL` | The full URL of the GitHub repository to clone and set up |
72
+ | `--path` / `-p` | *(Optional)* Local directory path where the repo will be cloned. Defaults to a folder named after the repo in the current directory |
73
+
74
+ ### Example
75
+
76
+ ```bash
77
+ locally796 https://github.com/prathmesh796/pubsubs --path ./test-clone
78
+ ```
79
+
80
+ This single command will autonomously:
81
+ 1. Clone the repository into `./test-clone`
82
+ 2. Detect the technology stack (e.g. Node.js, Python)
83
+ 3. Launch the LangChain Agent to investigate the codebase.
84
+ 4. Install all required dependencies (`npm install`, `pip install`, etc.)
85
+ 5. Configure environment variables (if `.env.example` is present)
86
+ 6. Start the local development server (e.g., `npm run dev`)
87
+ 7. Automatically detect and fix any deployment errors if the server fails to start!
88
+
89
+ ---
90
+
91
+ ## How It Works
92
+
93
+ 1. **Clone** — The repo is cloned to the specified (or auto-generated) local path using GitPython.
94
+ 2. **Detect** — The stack detector inspects the repository files to identify languages and frameworks.
95
+ 3. **Agent Setup** — A LangChain agent equipped with shell, file-read, and file-write tools executes the full setup autonomously. If a command fails or crashes, the agent reads the error output, figures out the fix, and retries until success!
96
+ 4. **Done** — The agent reports `SETUP_COMPLETE` and leaves the server running for you.
97
+
98
+ ---
99
+
100
+ ## License
101
+
102
+ MIT
103
+
@@ -0,0 +1,28 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ app/__init__.py
5
+ app/main.py
6
+ app/cli/__init__.py
7
+ app/cli/app.py
8
+ app/config/__init__.py
9
+ app/config/env.py
10
+ app/config/settings.py
11
+ app/core/__init__.py
12
+ app/core/agent.py
13
+ app/core/llm.py
14
+ app/core/tools.py
15
+ app/services/__init__.py
16
+ app/services/detector.py
17
+ app/services/executor.py
18
+ app/services/repo.py
19
+ app/utils/__init__.py
20
+ app/utils/constants.py
21
+ app/utils/logger.py
22
+ locally796.egg-info/PKG-INFO
23
+ locally796.egg-info/SOURCES.txt
24
+ locally796.egg-info/dependency_links.txt
25
+ locally796.egg-info/entry_points.txt
26
+ locally796.egg-info/requires.txt
27
+ locally796.egg-info/top_level.txt
28
+ tests/test.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ locally796 = app.main:app
@@ -0,0 +1,4 @@
1
+ typer
2
+ rich
3
+ gitpython
4
+ langchain
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "locally796"
3
+ version = "0.1.0"
4
+ description = "AI-powered CLI tool to setup GitHub repositories locally"
5
+ authors = [
6
+ { name="Prathmesh Salunkhe", email="salunkheprathmesh0@gmail.com" }
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.11"
10
+
11
+ dependencies = [
12
+ "typer",
13
+ "rich",
14
+ "gitpython",
15
+ "langchain",
16
+ ]
17
+
18
+ [project.scripts]
19
+ locally796 = "app.main:app"
20
+
21
+ [build-system]
22
+ requires = ["setuptools>=61.0.0", "wheel"]
23
+ build-backend = "setuptools.build_meta"
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["."]
27
+ include = ["app*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ import langchain_core
2
+ import langchain_community
3
+
4
+ print("Langchain Core version:", langchain_core.__version__)
5
+ print("Langchain Community version:", langchain_community.__version__)