commit 0bde6a48083b4f32ea6b17fc2ba7107a7566cf72 Author: neoricalex Date: Wed Mar 4 06:09:54 2026 +0100 first commit diff --git a/.gitea/actions/setup/action.yml b/.gitea/actions/setup/action.yml new file mode 100644 index 0000000..3030319 --- /dev/null +++ b/.gitea/actions/setup/action.yml @@ -0,0 +1,7 @@ +runs: + using: composite + steps: + - name: "Install UV" + shell: bash + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh \ No newline at end of file diff --git a/.gitea/workflows/code-quality.yml b/.gitea/workflows/code-quality.yml new file mode 100644 index 0000000..ccb7062 --- /dev/null +++ b/.gitea/workflows/code-quality.yml @@ -0,0 +1,48 @@ +name: Python Code Quality +on: [push] +jobs: + lock_file: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uv lock --locked + linting: + runs-on: ubuntu-latest + needs: [lock_file] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uvx ruff check . + formatting: + runs-on: ubuntu-latest + needs: [lock_file] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uvx ruff format --check . + type_consistency: + runs-on: ubuntu-latest + needs: [lock_file] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uv run pyright . + tests: + runs-on: ubuntu-latest + needs: [lock_file] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uv run pytest -v --durations=0 --cov --cov-report=xml + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + build: + runs-on: [ubuntu-latest] + needs: [linting, formatting, type_consistency, tests] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup + - run: uv build \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f201ec4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# === sub-módulos clonados === +src/modules/ +.cache/ + +# === Autotools build artefacts === +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +configure +depcomp +install-sh +missing +py-compile +stamp-h1 + +# === Build & dist directories === +/build/ +/dist/ +!/dist/releases/ +!/dist/releases/* +*.tar.gz +*.tar.bz2 +*.zip + +# === Python cache & venv === +__pycache__/ +*.pyc +*.pyo +*.pyd +*.egg-info/ +.eggs/ +venv/ +.env/ +.venv/ + +# === Editor / OS junk === +*.swp +*.swo +*.bak +*.tmp +*~ +.DS_Store +Thumbs.db + +# === Logs === +*.log +nohup.out + +# === IDE / workspace === +.vscode/ +.idea/ +*.iml + +# === Backup copies === +*.old +*.orig +*.rej diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..fc1ea93 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,125 @@ +SUBDIRS = src + +# =========================== +# Caminhos e artefactos +# =========================== +TOP_DIR = $(shell pwd) +DIST_DIR = $(TOP_DIR)/dist +BUILD_DIR = $(TOP_DIR)/build +GIT_VER = $(shell git describe --tags --always --dirty 2>/dev/null || echo "0.1-dev") +SRC_TAR = $(DIST_DIR)/myhomelab-$(GIT_VER)-src.tar.gz + +# =========================== +# Configurações de Git +# =========================== +GIT_USER ?= "neo.webmaster.2@gmail.com" +GIT_EMAIL ?= "neo.webmaster.2@gmail.com" +GIT_REMOTE ?= "origin" +GIT_BRANCH ?= "main" +COMMIT_MSG ?= "Auto-commit via make git" + +# =========================== +# Alvos principais +# =========================== +.PHONY: all tarball git release run clean-local check-remote + +all: $(DIST_DIR) + +$(DIST_DIR): + @mkdir -p $(DIST_DIR) + +# =========================== +# Empacotamento do código-fonte +# =========================== +tarball: $(SRC_TAR) + +$(SRC_TAR): + @echo "[TAR] Empacotando código-fonte (versão $(GIT_VER))..." + @mkdir -p "$(DIST_DIR)" "$(BUILD_DIR)" + cd "$(TOP_DIR)" && tar \ + --exclude="$(notdir $(SRC_TAR))" \ + --exclude="$(DIST_DIR)" \ + --exclude="$(BUILD_DIR)" \ + --exclude='*/__pycache__' \ + --exclude='*/.venv' \ + --exclude='*/venv' \ + --exclude='*.pyc' \ + --exclude='*.pyo' \ + --exclude='*.o' \ + --exclude='*.a' \ + --exclude='*.so' \ + -czf "$(SRC_TAR)" . + @echo "[✔] Tarball gerado em $(SRC_TAR)" + +# =========================== +# Git (commit + push) +# =========================== +git: check-remote + @echo "📦 Commit automático → Gitea" + @git config user.name $(GIT_USER) + @git config user.email $(GIT_EMAIL) + @git rev-parse --abbrev-ref HEAD >/dev/null 2>&1 || true + @git add -A + @git commit -m "$$(echo '$(COMMIT_MSG)')" || echo "Nenhuma modificação para commitar." + @git push $(GIT_REMOTE) $(GIT_BRANCH) + +# =========================== +# Release (Tarball + Tag) +# =========================== +release: tarball check-remote + @echo "🚀 Publicando build em dist/releases (versão: $(GIT_VER))" + @mkdir -p $(DIST_DIR)/releases + @cp $(SRC_TAR) $(DIST_DIR)/releases/ 2>/dev/null || echo "⚠️ Nenhum tarball encontrado. Execute 'make tarball' primeiro." + @echo "📦 Adicionando releases ignoradas (forçado)" + @git add -f $(DIST_DIR)/releases/* 2>/dev/null || echo "⚠️ Nenhum artefato novo para adicionar." + @git commit -m "Build automático: release $(GIT_VER)" || echo "Nenhum ficheiro novo para commitar." + @git push origin main + @TAG="$(GIT_VER)"; \ + if git rev-parse "$$TAG" >/dev/null 2>&1; then \ + echo "⚠️ Tag $$TAG já existente."; \ + else \ + echo "🏷 Criando tag $$TAG"; \ + git tag -a "$$TAG" -m "Release automática $$TAG"; \ + git push origin "$$TAG"; \ + fi + +# =========================== +# Git Remote (HTTPS → SSH Auto-Fix) +# =========================== +check-remote: + @REMOTE_URL=$$(git remote get-url $(GIT_REMOTE)); \ + if echo $$REMOTE_URL | grep -q '^https://gitea\.neoricalex\.com'; then \ + echo "⚠️ Repositório configurado com HTTPS:"; \ + echo " $$REMOTE_URL"; \ + echo "🔄 Convertendo para SSH (porta 2222)..."; \ + SSH_URL=$$(echo $$REMOTE_URL | sed -E 's|https://gitea\.neoricalex\.com[:/]+|ssh://git@gitea.neoricalex.com:2222/|'); \ + git remote set-url $(GIT_REMOTE) $$SSH_URL; \ + echo "✅ Remote atualizado para:"; \ + git remote -v; \ + else \ + echo "✅ Remote SSH já configurado:"; \ + git remote -v | grep $(GIT_REMOTE); \ + fi; \ + echo "🔍 Testando conectividade SSH com Gitea..."; \ + if ssh -T git@gitea.neoricalex.com -p 2222 2>&1 | grep -q "successfully authenticated"; then \ + echo "✅ Conexão SSH funcional com Gitea."; \ + else \ + echo "❌ Falha na autenticação SSH com Gitea."; \ + echo " Verifique a chave em ~/.ssh/id_ed25519.pub e nas SSH Keys do Gitea."; \ + exit 1; \ + fi + +# =========================== +# Teste +# =========================== +run: + @python3 src/root/__main__.py + +# =========================== +# Limpeza +# =========================== +clean-local: + @echo "[CLEAN] Removendo diretórios temporários..." + @rm -rf $(BUILD_DIR) + @find $(DIST_DIR) -maxdepth 1 -type f ! -path "$(DIST_DIR)/releases/*" -delete 2>/dev/null || true + @echo "[✔] Limpeza concluída (releases preservadas)" diff --git a/README.md b/README.md new file mode 100644 index 0000000..95eec98 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +``` +myhomelab/ +├─ configure.ac +├─ Makefile.am +├─ README.md +├─ pyproject.toml # uv + ruff + (pytest) +├─ uv.lock +├─ src/ +│ └─ neuro/ +│ ├─ __init__.py +│ ├─ cli.py # entrypoints (tui / bench / repl) +│ │ +│ ├─ tui/ +│ │ ├─ app.py # Textual App +│ │ ├─ screens.py # screens/modals +│ │ ├─ widgets.py # componentes reutilizáveis +│ │ └─ state.py # estado e store (sem IA aqui) +│ │ +│ ├─ engine/ +│ │ ├─ __init__.py +│ │ ├─ session.py # Session, Chat/Prompt state +│ │ └─ runtime.py # “orquestração” do loop (streaming, cancel) +│ │ +│ ├─ ai/ +│ │ ├─ __init__.py +│ │ ├─ config.py # dataclasses: dims, vocab, layers, seed +│ │ ├─ tokenizer.py # tokenize/detokenize +│ │ ├─ embeddings.py # tok->vec, pos enc +│ │ ├─ transformer.py # forward() (minimo) +│ │ ├─ head.py # logits/probs +│ │ ├─ sampling.py # greedy, top-k, top-p, temp +│ │ └─ model.py # Model = cola tudo (tokenize->sample) +│ │ +│ ├─ utils/ +│ │ ├─ logging.py +│ │ ├─ rng.py +│ │ └─ perf.py +│ │ +│ └─ data/ +│ ├─ vocab.json # opcional no MVP +│ └─ tiny_weights.npz # opcional (se quiseres pesos fixos) +│ +├─ tests/ +│ ├─ test_tokenizer.py +│ ├─ test_sampling.py +│ └─ test_transformer_shapes.py +└─ tools/ + ├─ bench.py # microbench do forward/sampling + └─ export_vocab.py +``` \ No newline at end of file diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..83727f5 --- /dev/null +++ b/configure.ac @@ -0,0 +1,37 @@ +AC_INIT([MYHOMELAB], [NEO_VERSION], [https://gitea.neoricalex.com/neo/myhomelab.git]) + +# =========================== +# Diretórios base +# =========================== +AC_CONFIG_AUX_DIR([.]) +AC_SUBST([TOP_DIR], ['$(CURDIR)']) +AC_SUBST([BUILD_DIR], ['$(CURDIR)/build']) +AC_SUBST([DIST_DIR], ['$(CURDIR)/dist']) + +# =========================== +# Versão dinâmica (Git) +# =========================== +m4_define([NEO_VERSION], + m4_esyscmd_s([git describe --tags --always --dirty 2>/dev/null || echo "0.1-dev"])) +AC_SUBST([NEO_VERSION]) + +# Caminho do tarball dinâmico (protegido contra M4 expansion) +AC_SUBST([SRC_TAR], + ['$(CURDIR)/dist/myhomelab-@NEO_VERSION@-src.tar.gz']) + +# =========================== +# Automake + Python +# =========================== + +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip]) +AM_PATH_PYTHON([3.0]) + +# =========================== +# Arquivos Makefile +# =========================== +AC_CONFIG_FILES([ + Makefile + src/Makefile + src/neuro/Makefile +]) +AC_OUTPUT diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2ccc5ab --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "neuro" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +authors = [ + { name = "neoricalex", email = "neo.webmaster.2@gmail.com" } +] +requires-python = ">=3.12" +dependencies = [] + +[project.scripts] +neuro = "neuro:main" + +[build-system] +requires = ["uv_build>=0.10.8,<0.11.0"] +build-backend = "uv_build" + +[dependency-groups] +dev = [ + "pyright>=1.1.408", + "pytest>=9.0.2", + "pytest-cov>=7.0.0", +] diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..f192af9 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = root + +bin_SCRIPTS = neuro +CLEANFILES = $(bin_SCRIPTS) +EXTRA_DIST = neuro.in + +# =========================== +# Substituição dinâmica +# =========================== +neuro: neuro.in Makefile + @which git >/dev/null || { echo "⚠️ Git não encontrado — instale-o manualmente."; exit 1; } + sed \ + -e 's,[@]pythondir[@],$(pythondir),g' \ + -e 's,[@]PACKAGE[@],$(PACKAGE),g' \ + -e 's,[@]VERSION[@],$(VERSION),g' \ + < $(srcdir)/neuro.in > neuro + chmod +x neuro + diff --git a/src/neuro.in b/src/neuro.in new file mode 100644 index 0000000..127b044 --- /dev/null +++ b/src/neuro.in @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +import sys +sys.path.insert(1, '@pythondir@') + +from bootstrap import Application + +if __name__ == "__main__": + app = Application(package="@PACKAGE@", version="@VERSION@") + app.run() +