Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ANGEL_LOG_LEVEL=INFO
ANGEL_STORAGE_PATH=
20 changes: 20 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: CD

on:
push:
tags:
- 'v*'

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Build
run: |
python -m pip install --upgrade pip
pip install build
python -m build
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: CI

on:
pull_request:
push:
branches: [main, develop]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
pip install -e .
- name: Lint
run: ruff check .
- name: Format
run: black --check .
- name: Tests
run: pytest
20 changes: 20 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Docs

on:
push:
branches: [main]

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install mkdocs
run: |
python -m pip install --upgrade pip
pip install mkdocs-material
- name: Build docs
run: mkdocs build
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Python
__pycache__/
*.py[cod]
*.pyo
*.pyd
*.egg-info/
.pytest_cache/
.mypy_cache/
.ruff_cache/

# Virtualenv
.venv/
venv/

# Coverage
.coverage
htmlcov/

# IDE
.vscode/
.idea/

# OS
.DS_Store
Thumbs.db

# Logs
*.log

# Build
build/
dist/
13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
repos:
- repo: https://github.com/psf/black
rev: 24.2.0
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
hooks:
- id: ruff
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 ANGEL Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ANGEL

ANGEL (Automated Navigator for Gathering and Executing Local tools) is a cross-platform CLI + web console for storing and managing your personal toolkit and repositories.

## Features
- CLI for tool and repository management
- Local FastAPI web console
- SQLite-backed metadata storage
- Configurable storage paths and settings

## Quick Start
```bash
python -m venv .venv
source .venv/bin/activate # Windows: .\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
pip install -e .
angel init
angel web
```

## Configuration
Configuration is stored in `~/.config/angel/config.toml` (Linux/macOS) or `%APPDATA%\angel\config.toml` (Windows). Use `angel config` to manage settings.

## Development
```bash
pip install -r requirements-dev.txt
pre-commit install
pytest
```

## License
MIT
35 changes: 35 additions & 0 deletions alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[alembic]
script_location = migrations
sqlalchemy.url = sqlite:///angel.db

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_sqlalchemy]
level = WARN
handlers = console
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers = console
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
5 changes: 5 additions & 0 deletions angel_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""ANGEL CLI package."""

__all__ = ["__version__"]

__version__ = "0.1.0"
5 changes: 5 additions & 0 deletions angel_cli/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Entry point for python -m angel_cli."""
from angel_cli.cli import main

if __name__ == "__main__":
main()
25 changes: 25 additions & 0 deletions angel_cli/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Main CLI entry point for ANGEL."""
from __future__ import annotations

import click
from rich.console import Console

from angel_cli.commands import auth, config, maintenance, repos, tools

console = Console()


@click.group(help="ANGEL CLI - manage tools and repositories.")
@click.option("--config-path", type=click.Path(), help="Custom config path.")
@click.pass_context
def main(ctx: click.Context, config_path: str | None) -> None:
"""Root command group."""
ctx.ensure_object(dict)
ctx.obj["config_path"] = config_path


main.add_command(auth.group)
main.add_command(tools.group)
main.add_command(repos.group)
main.add_command(maintenance.group)
main.add_command(config.group)
1 change: 1 addition & 0 deletions angel_cli/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""CLI command modules."""
28 changes: 28 additions & 0 deletions angel_cli/commands/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Authentication commands."""
import click
from rich.console import Console

console = Console()


@click.group(name="auth", help="Authentication commands.")
def group() -> None:
"""Auth command group."""


@group.command("login")
def login() -> None:
"""Login to the local instance."""
console.print("[green]Login flow not yet implemented.[/green]")


@group.command("logout")
def logout() -> None:
"""Logout from the local instance."""
console.print("[green]Logout flow not yet implemented.[/green]")


@group.command("change-password")
def change_password() -> None:
"""Change the current user's password."""
console.print("[yellow]Password change not yet implemented.[/yellow]")
16 changes: 16 additions & 0 deletions angel_cli/commands/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Configuration commands."""
import click
from rich.console import Console

console = Console()


@click.group(name="config", help="Configuration management.")
def group() -> None:
"""Config command group."""


@group.command("show")
def show_config() -> None:
"""Show current configuration."""
console.print("[green]Config display not yet implemented.[/green]")
16 changes: 16 additions & 0 deletions angel_cli/commands/maintenance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Maintenance commands."""
import click
from rich.console import Console

console = Console()


@click.group(name="maintenance", help="Maintenance tasks.")
def group() -> None:
"""Maintenance command group."""


@group.command("doctor")
def doctor() -> None:
"""Run a health check."""
console.print("[green]All checks passed (stub).[/green]")
16 changes: 16 additions & 0 deletions angel_cli/commands/repos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Repository commands."""
import click
from rich.console import Console

console = Console()


@click.group(name="repos", help="Manage repositories.")
def group() -> None:
"""Repos command group."""


@group.command("list")
def list_repos() -> None:
"""List tracked repositories."""
console.print("[green]No repositories available (stub).[/green]")
23 changes: 23 additions & 0 deletions angel_cli/commands/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Tool management commands."""
import click
from rich.console import Console

console = Console()


@click.group(name="tools", help="Manage tools.")
def group() -> None:
"""Tools command group."""


@group.command("list")
def list_tools() -> None:
"""List stored tools."""
console.print("[green]No tools available (stub).[/green]")


@group.command("add")
@click.argument("path", required=False)
def add_tool(path: str | None) -> None:
"""Add a tool from a file path."""
console.print(f"[green]Add tool stub: {path}[/green]")
1 change: 1 addition & 0 deletions angel_cli/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Core utilities for ANGEL."""
14 changes: 14 additions & 0 deletions angel_cli/core/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Authentication utilities."""
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def hash_password(password: str) -> str:
"""Hash a password using bcrypt."""
return pwd_context.hash(password)


def verify_password(password: str, hashed: str) -> bool:
"""Verify a password against a hash."""
return pwd_context.verify(password, hashed)
Loading
Loading