packaging things
- SHA
b3834c182964743e9546ba03ff43a861b92b71b7- Parents
-
8ef2f0d - Tree
0f0b4db
b3834c1
b3834c182964743e9546ba03ff43a861b92b71b78ef2f0d
0f0b4db| Status | File | + | - |
|---|---|---|---|
| A |
Makefile
|
220 | 0 |
| A |
config/parrot.toml.example
|
110 | 0 |
| A |
parrot.spec
|
99 | 0 |
| A |
scripts/post-install.sh
|
280 | 0 |
Makefileadded@@ -0,0 +1,220 @@ | ||
| 1 | +# Makefile for parrot | |
| 2 | +# Intelligent CLI command failure assistant | |
| 3 | + | |
| 4 | +# Project configuration | |
| 5 | +PROJECT_NAME = parrot | |
| 6 | +VERSION = 1.0.0 | |
| 7 | +TARGET = parrot | |
| 8 | + | |
| 9 | +# Go configuration | |
| 10 | +GOCMD = go | |
| 11 | +GOBUILD = $(GOCMD) build | |
| 12 | +GOCLEAN = $(GOCMD) clean | |
| 13 | +GOTEST = $(GOCMD) test | |
| 14 | +GOGET = $(GOCMD) get | |
| 15 | +GOMOD = $(GOCMD) mod | |
| 16 | + | |
| 17 | +# Build flags | |
| 18 | +LDFLAGS = -ldflags="-w -s" | |
| 19 | +BUILD_FLAGS = $(LDFLAGS) | |
| 20 | + | |
| 21 | +# Directories | |
| 22 | +SRCDIR = . | |
| 23 | +BUILDDIR = build | |
| 24 | +RPMDIR = rpmbuild | |
| 25 | +DISTDIR = dist | |
| 26 | + | |
| 27 | +# RPM configuration | |
| 28 | +RPMVERSION = $(VERSION) | |
| 29 | +RPMRELEASE = 1 | |
| 30 | +RPM_TOPDIR = $(shell pwd)/$(RPMDIR) | |
| 31 | +SPEC_FILE = $(PROJECT_NAME).spec | |
| 32 | + | |
| 33 | +# Default target | |
| 34 | +.PHONY: all | |
| 35 | +all: build | |
| 36 | + | |
| 37 | +# Build the Go binary | |
| 38 | +.PHONY: build | |
| 39 | +build: | |
| 40 | + @echo "Building $(PROJECT_NAME)..." | |
| 41 | + $(GOMOD) download | |
| 42 | + $(GOBUILD) $(BUILD_FLAGS) -o $(TARGET) $(SRCDIR) | |
| 43 | + @echo "✓ Build complete: $(TARGET)" | |
| 44 | + | |
| 45 | +# Clean build artifacts | |
| 46 | +.PHONY: clean | |
| 47 | +clean: | |
| 48 | + @echo "Cleaning build artifacts..." | |
| 49 | + $(GOCLEAN) | |
| 50 | + rm -f $(TARGET) | |
| 51 | + rm -rf $(BUILDDIR) | |
| 52 | + rm -rf $(RPMDIR) | |
| 53 | + rm -rf $(DISTDIR) | |
| 54 | + @echo "✓ Clean complete" | |
| 55 | + | |
| 56 | +# Run tests | |
| 57 | +.PHONY: test | |
| 58 | +test: | |
| 59 | + @echo "Running tests..." | |
| 60 | + $(GOTEST) -v ./... | |
| 61 | + | |
| 62 | +# Install locally | |
| 63 | +.PHONY: install | |
| 64 | +install: build | |
| 65 | + @echo "Installing $(TARGET)..." | |
| 66 | + @mkdir -p $(HOME)/.local/bin | |
| 67 | + @mkdir -p $(HOME)/.local/share/$(PROJECT_NAME) | |
| 68 | + @mkdir -p $(HOME)/.config/$(PROJECT_NAME) | |
| 69 | + @cp $(TARGET) $(HOME)/.local/bin/ | |
| 70 | + @cp parrot-hook.sh $(HOME)/.local/share/$(PROJECT_NAME)/ | |
| 71 | + @cp config/parrot.toml.example $(HOME)/.config/$(PROJECT_NAME)/ 2>/dev/null || true | |
| 72 | + @echo "✓ Installed to ~/.local/bin/$(TARGET)" | |
| 73 | + @echo "Make sure ~/.local/bin is in your PATH" | |
| 74 | + @echo "Run '$(TARGET) setup' to complete configuration" | |
| 75 | + | |
| 76 | +# Uninstall locally | |
| 77 | +.PHONY: uninstall | |
| 78 | +uninstall: | |
| 79 | + @echo "Uninstalling $(PROJECT_NAME)..." | |
| 80 | + @rm -f $(HOME)/.local/bin/$(TARGET) | |
| 81 | + @rm -rf $(HOME)/.local/share/$(PROJECT_NAME) | |
| 82 | + @echo "✓ Uninstalled (config preserved in ~/.config/$(PROJECT_NAME))" | |
| 83 | + | |
| 84 | +# Create source tarball for RPM | |
| 85 | +.PHONY: tarball | |
| 86 | +tarball: clean | |
| 87 | + @echo "Creating source tarball..." | |
| 88 | + @mkdir -p $(DISTDIR) | |
| 89 | + @git archive --format=tar.gz --prefix=$(PROJECT_NAME)-$(VERSION)/ HEAD > $(DISTDIR)/$(PROJECT_NAME)-$(VERSION).tar.gz | |
| 90 | + @echo "✓ Created $(DISTDIR)/$(PROJECT_NAME)-$(VERSION).tar.gz" | |
| 91 | + | |
| 92 | +# Prepare RPM build environment | |
| 93 | +.PHONY: rpm-prep | |
| 94 | +rpm-prep: tarball | |
| 95 | + @echo "Preparing RPM build environment..." | |
| 96 | + @mkdir -p $(RPM_TOPDIR)/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} | |
| 97 | + @cp $(DISTDIR)/$(PROJECT_NAME)-$(VERSION).tar.gz $(RPM_TOPDIR)/SOURCES/ | |
| 98 | + @cp $(SPEC_FILE) $(RPM_TOPDIR)/SPECS/ | |
| 99 | + @echo "✓ RPM environment ready" | |
| 100 | + | |
| 101 | +# Build source RPM | |
| 102 | +.PHONY: srpm | |
| 103 | +srpm: rpm-prep | |
| 104 | + @echo "Building source RPM..." | |
| 105 | + rpmbuild --define "_topdir $(RPM_TOPDIR)" -bs $(RPM_TOPDIR)/SPECS/$(SPEC_FILE) | |
| 106 | + @echo "✓ Source RPM created in $(RPMDIR)/SRPMS/" | |
| 107 | + | |
| 108 | +# Build binary RPM | |
| 109 | +.PHONY: rpm | |
| 110 | +rpm: rpm-prep | |
| 111 | + @echo "Building RPM package..." | |
| 112 | + rpmbuild --define "_topdir $(RPM_TOPDIR)" -ba $(RPM_TOPDIR)/SPECS/$(SPEC_FILE) | |
| 113 | + @echo "✓ RPM packages created:" | |
| 114 | + @find $(RPMDIR)/RPMS -name "*.rpm" -exec echo " {}" \; | |
| 115 | + @find $(RPMDIR)/SRPMS -name "*.rpm" -exec echo " {}" \; | |
| 116 | + | |
| 117 | +# Copy RPMs to repository structure (matching existing projects) | |
| 118 | +.PHONY: copy-rpms | |
| 119 | +copy-rpms: rpm | |
| 120 | + @echo "Copying RPMs to repository structure..." | |
| 121 | + @mkdir -p ../repos-musicsian-com/RPMS/ | |
| 122 | + @cp $(RPMDIR)/RPMS/x86_64/$(PROJECT_NAME)-*.rpm ../repos-musicsian-com/RPMS/ | |
| 123 | + @cp $(RPMDIR)/SRPMS/$(PROJECT_NAME)-*.src.rpm ../repos-musicsian-com/RPMS/ | |
| 124 | + @echo "✓ RPMs copied to ../repos-musicsian-com/RPMS/" | |
| 125 | + | |
| 126 | +# Format Go code | |
| 127 | +.PHONY: format | |
| 128 | +format: | |
| 129 | + @echo "Formatting Go code..." | |
| 130 | + @command -v gofmt >/dev/null 2>&1 && gofmt -w . || echo "gofmt not found" | |
| 131 | + @command -v goimports >/dev/null 2>&1 && goimports -w . || echo "goimports not found" | |
| 132 | + | |
| 133 | +# Lint Go code | |
| 134 | +.PHONY: lint | |
| 135 | +lint: | |
| 136 | + @echo "Running Go linter..." | |
| 137 | + @command -v golangci-lint >/dev/null 2>&1 && golangci-lint run || echo "golangci-lint not found" | |
| 138 | + | |
| 139 | +# Run development cycle | |
| 140 | +.PHONY: dev | |
| 141 | +dev: clean format lint test build | |
| 142 | + | |
| 143 | +# Quick smoke test | |
| 144 | +.PHONY: smoke-test | |
| 145 | +smoke-test: build | |
| 146 | + @echo "Running smoke test..." | |
| 147 | + @./$(TARGET) --version >/dev/null && echo "✓ Version command works" | |
| 148 | + @./$(TARGET) --help >/dev/null && echo "✓ Help command works" | |
| 149 | + @./$(TARGET) status >/dev/null 2>&1 && echo "✓ Status command works" || echo "⚠ Status command needs configuration" | |
| 150 | + | |
| 151 | +# Create .repo file for YUM repository | |
| 152 | +.PHONY: repo-file | |
| 153 | +repo-file: | |
| 154 | + @echo "Creating repository file..." | |
| 155 | + @mkdir -p $(DISTDIR) | |
| 156 | + @cat > $(DISTDIR)/$(PROJECT_NAME).repo << 'EOF' | |
| 157 | +[$(PROJECT_NAME)] | |
| 158 | +name=Parrot - Intelligent CLI Assistant | |
| 159 | +baseurl=https://repos.musicsian.com/ | |
| 160 | +enabled=1 | |
| 161 | +gpgcheck=0 | |
| 162 | + @echo "✓ Created $(DISTDIR)/$(PROJECT_NAME).repo" | |
| 163 | + | |
| 164 | +# Show build information | |
| 165 | +.PHONY: info | |
| 166 | +info: | |
| 167 | + @echo "Project: $(PROJECT_NAME) v$(VERSION)" | |
| 168 | + @echo "Target: $(TARGET)" | |
| 169 | + @echo "Go version: $(shell $(GOCMD) version)" | |
| 170 | + @echo "RPM build directory: $(RPM_TOPDIR)" | |
| 171 | + | |
| 172 | +# Check dependencies | |
| 173 | +.PHONY: deps | |
| 174 | +deps: | |
| 175 | + @echo "Checking dependencies..." | |
| 176 | + @echo "Required tools:" | |
| 177 | + @command -v $(GOCMD) >/dev/null 2>&1 && echo " $(GOCMD) - $(shell $(GOCMD) version)" || echo " $(GOCMD) - REQUIRED" | |
| 178 | + @command -v make >/dev/null 2>&1 && echo " make" || echo " make - REQUIRED" | |
| 179 | + @echo "RPM build tools:" | |
| 180 | + @command -v rpmbuild >/dev/null 2>&1 && echo " rpmbuild" || echo " rpmbuild - for RPM building" | |
| 181 | + @echo "Optional tools:" | |
| 182 | + @command -v gofmt >/dev/null 2>&1 && echo " gofmt" || echo " gofmt - for formatting" | |
| 183 | + @command -v golangci-lint >/dev/null 2>&1 && echo " golangci-lint" || echo " golangci-lint - for linting" | |
| 184 | + @command -v goimports >/dev/null 2>&1 && echo " goimports" || echo " goimports - for import management" | |
| 185 | + | |
| 186 | +# Help target | |
| 187 | +.PHONY: help | |
| 188 | +help: | |
| 189 | + @echo "$(PROJECT_NAME) Makefile" | |
| 190 | + @echo "" | |
| 191 | + @echo "Targets:" | |
| 192 | + @echo " build Build the Go binary" | |
| 193 | + @echo " clean Remove build artifacts" | |
| 194 | + @echo " test Run tests" | |
| 195 | + @echo " install Install locally to ~/.local/bin" | |
| 196 | + @echo " uninstall Remove local installation" | |
| 197 | + @echo " format Format Go code" | |
| 198 | + @echo " lint Run Go linter" | |
| 199 | + @echo " dev Development cycle (clean + format + lint + test + build)" | |
| 200 | + @echo " smoke-test Quick functionality check" | |
| 201 | + @echo "" | |
| 202 | + @echo "RPM Packaging:" | |
| 203 | + @echo " tarball Create source tarball" | |
| 204 | + @echo " rpm-prep Prepare RPM build environment" | |
| 205 | + @echo " srpm Build source RPM" | |
| 206 | + @echo " rpm Build binary RPM" | |
| 207 | + @echo " copy-rpms Copy RPMs to repository structure" | |
| 208 | + @echo " repo-file Create .repo file for YUM" | |
| 209 | + @echo "" | |
| 210 | + @echo "Utilities:" | |
| 211 | + @echo " info Show build information" | |
| 212 | + @echo " deps Check dependencies" | |
| 213 | + @echo " help Show this help" | |
| 214 | + @echo "" | |
| 215 | + @echo "Example workflow:" | |
| 216 | + @echo " make dev # Development cycle" | |
| 217 | + @echo " make rpm # Build RPM packages" | |
| 218 | + @echo " make copy-rpms # Deploy to repository" | |
| 219 | + | |
| 220 | +.PHONY: all build clean test install uninstall tarball rpm-prep srpm rpm copy-rpms format lint dev smoke-test repo-file info deps help | |
config/parrot.toml.exampleadded@@ -0,0 +1,110 @@ | ||
| 1 | +# Parrot Configuration Example | |
| 2 | +# Copy this file to one of the following locations: | |
| 3 | +# - ~/.config/parrot/parrot.toml (user-specific) | |
| 4 | +# - ~/.parrot.toml (user-specific, legacy) | |
| 5 | +# - /etc/parrot/parrot.toml (system-wide) | |
| 6 | + | |
| 7 | +# ==================== BACKEND CONFIGURATION ==================== | |
| 8 | + | |
| 9 | +# Backend priority: "api", "local", "fallback" | |
| 10 | +# The system will try backends in this order until one works | |
| 11 | +backend_priority = ["local", "api", "fallback"] | |
| 12 | + | |
| 13 | +# Default backend to use (overrides priority for direct selection) | |
| 14 | +# default_backend = "local" | |
| 15 | + | |
| 16 | +# ==================== API BACKEND SETTINGS ==================== | |
| 17 | + | |
| 18 | +[api] | |
| 19 | +# OpenAI-compatible API endpoint | |
| 20 | +base_url = "https://api.openai.com/v1" | |
| 21 | + | |
| 22 | +# API key for authentication | |
| 23 | +# Can also be set via PARROT_API_KEY environment variable | |
| 24 | +# api_key = "your-api-key-here" | |
| 25 | + | |
| 26 | +# Model to use for generation | |
| 27 | +model = "gpt-4o-mini" | |
| 28 | + | |
| 29 | +# Maximum tokens for response | |
| 30 | +max_tokens = 150 | |
| 31 | + | |
| 32 | +# Temperature for response creativity (0.0 = deterministic, 1.0 = creative) | |
| 33 | +temperature = 0.7 | |
| 34 | + | |
| 35 | +# Request timeout in seconds | |
| 36 | +timeout = 30 | |
| 37 | + | |
| 38 | +# ==================== LOCAL BACKEND SETTINGS ==================== | |
| 39 | + | |
| 40 | +[local] | |
| 41 | +# Ollama server endpoint | |
| 42 | +base_url = "http://localhost:11434" | |
| 43 | + | |
| 44 | +# Model to use (will be pulled automatically if not present) | |
| 45 | +model = "phi3.5:3.8b" | |
| 46 | + | |
| 47 | +# Generation options | |
| 48 | +max_tokens = 150 | |
| 49 | +temperature = 0.7 | |
| 50 | +timeout = 45 | |
| 51 | + | |
| 52 | +# Model management | |
| 53 | +auto_pull = true # Automatically pull model if not available | |
| 54 | +pull_timeout = 300 # Timeout for model pulling in seconds | |
| 55 | + | |
| 56 | +# ==================== PERSONALITY SETTINGS ==================== | |
| 57 | + | |
| 58 | +# Personality level: "mild", "sarcastic", "savage" | |
| 59 | +personality = "sarcastic" | |
| 60 | + | |
| 61 | +# Enable colored output | |
| 62 | +colors = true | |
| 63 | + | |
| 64 | +# Color scheme per personality (auto-detected if not specified) | |
| 65 | +# [colors] | |
| 66 | +# mild = "blue" | |
| 67 | +# sarcastic = "yellow" | |
| 68 | +# savage = "red" | |
| 69 | + | |
| 70 | +# ==================== SHELL INTEGRATION ==================== | |
| 71 | + | |
| 72 | +[shell] | |
| 73 | +# Enable shell integration hooks | |
| 74 | +enabled = true | |
| 75 | + | |
| 76 | +# Shells to integrate with (detected automatically) | |
| 77 | +# supported_shells = ["bash", "zsh"] | |
| 78 | + | |
| 79 | +# Hook installation paths (auto-detected) | |
| 80 | +# bash_profile = "~/.bashrc" | |
| 81 | +# zsh_profile = "~/.zshrc" | |
| 82 | + | |
| 83 | +# ==================== ADVANCED SETTINGS ==================== | |
| 84 | + | |
| 85 | +[advanced] | |
| 86 | +# Enable debug logging | |
| 87 | +debug = false | |
| 88 | + | |
| 89 | +# Log file location (empty = no file logging) | |
| 90 | +# log_file = "~/.config/parrot/parrot.log" | |
| 91 | + | |
| 92 | +# Cache settings | |
| 93 | +cache_enabled = true | |
| 94 | +cache_duration = 3600 # seconds | |
| 95 | + | |
| 96 | +# Retry settings | |
| 97 | +max_retries = 3 | |
| 98 | +retry_delay = 1 # seconds | |
| 99 | + | |
| 100 | +# ==================== FEATURE FLAGS ==================== | |
| 101 | + | |
| 102 | +[features] | |
| 103 | +# Enable experimental features | |
| 104 | +experimental = false | |
| 105 | + | |
| 106 | +# Enable telemetry (anonymous usage statistics) | |
| 107 | +telemetry = false | |
| 108 | + | |
| 109 | +# Enable auto-updates check | |
| 110 | +auto_update_check = true | |
parrot.specadded@@ -0,0 +1,99 @@ | ||
| 1 | +Name: parrot | |
| 2 | +Version: 1.0.0 | |
| 3 | +Release: 1%{?dist} | |
| 4 | +Summary: Intelligent CLI command failure assistant with AI-powered responses | |
| 5 | + | |
| 6 | +License: MIT | |
| 7 | +URL: https://github.com/tenseleyFlow/parrot | |
| 8 | +Source0: %{name}-%{version}.tar.gz | |
| 9 | + | |
| 10 | +BuildArch: x86_64 | |
| 11 | +BuildRequires: golang >= 1.21 | |
| 12 | +BuildRequires: make | |
| 13 | +Requires: bash | |
| 14 | +Suggests: ollama | |
| 15 | +Suggests: curl | |
| 16 | + | |
| 17 | +%description | |
| 18 | +Parrot is an intelligent CLI assistant that listens for failed command executions | |
| 19 | +and provides witty, AI-powered responses with helpful suggestions. It supports | |
| 20 | +multiple backend modes including API integration (OpenAI-compatible), local | |
| 21 | +LLM models via Ollama, and fallback responses for guaranteed functionality. | |
| 22 | + | |
| 23 | +Features: | |
| 24 | +- Multi-backend architecture (API → Local → Fallback) | |
| 25 | +- Three personality levels (mild, sarcastic, savage) | |
| 26 | +- Shell integration for bash and zsh | |
| 27 | +- Interactive configuration wizard | |
| 28 | +- Comprehensive setup automation | |
| 29 | +- Terminal color theming | |
| 30 | +- Zero external dependencies required for basic operation | |
| 31 | + | |
| 32 | +%prep | |
| 33 | +%autosetup | |
| 34 | + | |
| 35 | +%build | |
| 36 | +# Build Go binary with release optimizations | |
| 37 | +go mod download | |
| 38 | +go build -ldflags="-w -s" -o parrot . | |
| 39 | + | |
| 40 | +%install | |
| 41 | +# Install main binary | |
| 42 | +install -d %{buildroot}%{_bindir} | |
| 43 | +install -m 755 parrot %{buildroot}%{_bindir}/parrot | |
| 44 | + | |
| 45 | +# Install shell integration hooks | |
| 46 | +install -d %{buildroot}%{_datadir}/%{name} | |
| 47 | +install -m 644 parrot-hook.sh %{buildroot}%{_datadir}/%{name}/parrot-hook.sh | |
| 48 | + | |
| 49 | +# Install configuration templates | |
| 50 | +install -d %{buildroot}%{_sysconfdir}/%{name} | |
| 51 | +install -m 644 config/parrot.toml.example %{buildroot}%{_sysconfdir}/%{name}/parrot.toml.example | |
| 52 | + | |
| 53 | +# Install documentation | |
| 54 | +install -d %{buildroot}%{_docdir}/%{name} | |
| 55 | +install -m 644 README.md %{buildroot}%{_docdir}/%{name}/ | |
| 56 | +install -m 644 INSTALLATION_FLOWS.md %{buildroot}%{_docdir}/%{name}/ | |
| 57 | + | |
| 58 | +%post | |
| 59 | +# Post-install setup guidance | |
| 60 | +echo "🦜 Parrot has been installed successfully!" | |
| 61 | +echo "" | |
| 62 | +echo "Next steps to complete setup:" | |
| 63 | +echo "1. Run 'parrot setup' to configure your preferred backend" | |
| 64 | +echo "2. Follow the interactive prompts to enable shell integration" | |
| 65 | +echo "" | |
| 66 | +echo "Backend options:" | |
| 67 | +echo " • API Backend: Use OpenAI-compatible services (requires API key)" | |
| 68 | +echo " • Local Backend: Use Ollama for privacy-focused local AI" | |
| 69 | +echo " • Fallback: Built-in responses (no setup required)" | |
| 70 | +echo "" | |
| 71 | +echo "For detailed setup instructions, see: /usr/share/doc/%{name}/INSTALLATION_FLOWS.md" | |
| 72 | +echo "Example configuration: /etc/%{name}/parrot.toml.example" | |
| 73 | +echo "" | |
| 74 | +echo "Run 'parrot --help' to get started!" | |
| 75 | + | |
| 76 | +%preun | |
| 77 | +# Clean up shell integrations on uninstall | |
| 78 | +if [ "$1" = "0" ]; then | |
| 79 | + # Only on complete removal, not upgrade | |
| 80 | + echo "Removing Parrot shell integrations..." | |
| 81 | + # Note: Users should run 'parrot setup --remove' before uninstalling | |
| 82 | + echo "If you have shell integration enabled, please restart your terminal sessions." | |
| 83 | +fi | |
| 84 | + | |
| 85 | +%files | |
| 86 | +%doc README.md INSTALLATION_FLOWS.md | |
| 87 | +%{_bindir}/parrot | |
| 88 | +%{_datadir}/%{name}/parrot-hook.sh | |
| 89 | +%{_sysconfdir}/%{name}/parrot.toml.example | |
| 90 | +%{_docdir}/%{name}/ | |
| 91 | + | |
| 92 | +%changelog | |
| 93 | +* Sun Aug 25 2025 mfw <espadonne@outlook.com> - 1.0.0-1 | |
| 94 | +- Initial RPM release | |
| 95 | +- Multi-backend architecture with API, Local, and Fallback support | |
| 96 | +- Interactive setup wizard with automated backend configuration | |
| 97 | +- Shell integration for bash and zsh | |
| 98 | +- Three personality levels with terminal color theming | |
| 99 | +- Comprehensive installation flows and setup automation | |
scripts/post-install.shadded@@ -0,0 +1,280 @@ | ||
| 1 | +#!/bin/bash | |
| 2 | +# Parrot post-installation setup script | |
| 3 | +# This script provides guided setup for backend configuration | |
| 4 | + | |
| 5 | +set -e | |
| 6 | + | |
| 7 | +# Colors for output | |
| 8 | +RED='\033[0;31m' | |
| 9 | +GREEN='\033[0;32m' | |
| 10 | +YELLOW='\033[1;33m' | |
| 11 | +BLUE='\033[0;34m' | |
| 12 | +PURPLE='\033[0;35m' | |
| 13 | +NC='\033[0m' # No Color | |
| 14 | + | |
| 15 | +# Configuration | |
| 16 | +PARROT_BIN="/usr/bin/parrot" | |
| 17 | +CONFIG_DIR="$HOME/.config/parrot" | |
| 18 | +CONFIG_FILE="$CONFIG_DIR/parrot.toml" | |
| 19 | +EXAMPLE_CONFIG="/etc/parrot/parrot.toml.example" | |
| 20 | + | |
| 21 | +# Helper functions | |
| 22 | +print_header() { | |
| 23 | + echo -e "${BLUE}🦜 Parrot Setup Assistant${NC}" | |
| 24 | + echo -e "${BLUE}=========================${NC}" | |
| 25 | + echo | |
| 26 | +} | |
| 27 | + | |
| 28 | +print_success() { | |
| 29 | + echo -e "${GREEN}✓${NC} $1" | |
| 30 | +} | |
| 31 | + | |
| 32 | +print_warning() { | |
| 33 | + echo -e "${YELLOW}⚠${NC} $1" | |
| 34 | +} | |
| 35 | + | |
| 36 | +print_error() { | |
| 37 | + echo -e "${RED}✗${NC} $1" | |
| 38 | +} | |
| 39 | + | |
| 40 | +print_info() { | |
| 41 | + echo -e "${BLUE}ℹ${NC} $1" | |
| 42 | +} | |
| 43 | + | |
| 44 | +check_command() { | |
| 45 | + command -v "$1" >/dev/null 2>&1 | |
| 46 | +} | |
| 47 | + | |
| 48 | +detect_backends() { | |
| 49 | + local backends=() | |
| 50 | + | |
| 51 | + # Check for Ollama | |
| 52 | + if check_command ollama && ollama list >/dev/null 2>&1; then | |
| 53 | + backends+=("local") | |
| 54 | + print_success "Ollama detected and running" | |
| 55 | + else | |
| 56 | + print_warning "Ollama not found or not running" | |
| 57 | + fi | |
| 58 | + | |
| 59 | + # Check for API key environment variable | |
| 60 | + if [[ -n "${PARROT_API_KEY:-}" ]] || [[ -n "${OPENAI_API_KEY:-}" ]]; then | |
| 61 | + backends+=("api") | |
| 62 | + print_success "API key detected in environment" | |
| 63 | + else | |
| 64 | + print_warning "No API keys found in environment" | |
| 65 | + fi | |
| 66 | + | |
| 67 | + # Fallback is always available | |
| 68 | + backends+=("fallback") | |
| 69 | + print_success "Fallback backend available" | |
| 70 | + | |
| 71 | + echo "${backends[@]}" | |
| 72 | +} | |
| 73 | + | |
| 74 | +setup_config_dir() { | |
| 75 | + if [[ ! -d "$CONFIG_DIR" ]]; then | |
| 76 | + mkdir -p "$CONFIG_DIR" | |
| 77 | + print_success "Created configuration directory: $CONFIG_DIR" | |
| 78 | + fi | |
| 79 | +} | |
| 80 | + | |
| 81 | +create_basic_config() { | |
| 82 | + local backend_priority="$1" | |
| 83 | + local personality="${2:-sarcastic}" | |
| 84 | + | |
| 85 | + cat > "$CONFIG_FILE" << EOF | |
| 86 | +# Parrot Configuration | |
| 87 | +# Generated by post-install setup | |
| 88 | + | |
| 89 | +backend_priority = ["$backend_priority"] | |
| 90 | +personality = "$personality" | |
| 91 | +colors = true | |
| 92 | + | |
| 93 | +[shell] | |
| 94 | +enabled = true | |
| 95 | + | |
| 96 | +[advanced] | |
| 97 | +debug = false | |
| 98 | +cache_enabled = true | |
| 99 | +EOF | |
| 100 | + | |
| 101 | + print_success "Created basic configuration: $CONFIG_FILE" | |
| 102 | +} | |
| 103 | + | |
| 104 | +setup_ollama() { | |
| 105 | + print_info "Setting up Ollama backend..." | |
| 106 | + | |
| 107 | + if ! check_command ollama; then | |
| 108 | + print_error "Ollama is not installed" | |
| 109 | + echo "To install Ollama:" | |
| 110 | + echo " curl -fsSL https://ollama.com/install.sh | sh" | |
| 111 | + echo | |
| 112 | + return 1 | |
| 113 | + fi | |
| 114 | + | |
| 115 | + if ! ollama list >/dev/null 2>&1; then | |
| 116 | + print_warning "Ollama service is not running" | |
| 117 | + echo "To start Ollama:" | |
| 118 | + echo " systemctl --user enable ollama" | |
| 119 | + echo " systemctl --user start ollama" | |
| 120 | + echo | |
| 121 | + return 1 | |
| 122 | + fi | |
| 123 | + | |
| 124 | + # Check if phi3.5 model is available | |
| 125 | + if ! ollama list | grep -q "phi3.5:3.8b"; then | |
| 126 | + print_info "Downloading phi3.5:3.8b model (this may take a few minutes)..." | |
| 127 | + if ollama pull phi3.5:3.8b; then | |
| 128 | + print_success "Downloaded phi3.5:3.8b model" | |
| 129 | + else | |
| 130 | + print_error "Failed to download model" | |
| 131 | + return 1 | |
| 132 | + fi | |
| 133 | + else | |
| 134 | + print_success "phi3.5:3.8b model already available" | |
| 135 | + fi | |
| 136 | + | |
| 137 | + return 0 | |
| 138 | +} | |
| 139 | + | |
| 140 | +setup_api_backend() { | |
| 141 | + print_info "Setting up API backend..." | |
| 142 | + | |
| 143 | + if [[ -n "${PARROT_API_KEY:-}" ]]; then | |
| 144 | + print_success "Using PARROT_API_KEY from environment" | |
| 145 | + return 0 | |
| 146 | + elif [[ -n "${OPENAI_API_KEY:-}" ]]; then | |
| 147 | + print_success "Using OPENAI_API_KEY from environment" | |
| 148 | + return 0 | |
| 149 | + else | |
| 150 | + print_warning "No API key found in environment" | |
| 151 | + echo "To use API backend, set one of:" | |
| 152 | + echo " export PARROT_API_KEY='your-api-key'" | |
| 153 | + echo " export OPENAI_API_KEY='your-api-key'" | |
| 154 | + echo | |
| 155 | + echo "Or configure it in: $CONFIG_FILE" | |
| 156 | + return 1 | |
| 157 | + fi | |
| 158 | +} | |
| 159 | + | |
| 160 | +setup_shell_integration() { | |
| 161 | + print_info "Shell integration will be configured when you run 'parrot setup'" | |
| 162 | + print_info "This enables automatic command failure detection" | |
| 163 | +} | |
| 164 | + | |
| 165 | +interactive_setup() { | |
| 166 | + print_header | |
| 167 | + | |
| 168 | + echo "Welcome to Parrot! Let's set up your intelligent CLI assistant." | |
| 169 | + echo | |
| 170 | + | |
| 171 | + # Detect available backends | |
| 172 | + print_info "Detecting available backends..." | |
| 173 | + local available_backends | |
| 174 | + available_backends=($(detect_backends)) | |
| 175 | + echo | |
| 176 | + | |
| 177 | + # Choose personality | |
| 178 | + echo "Choose your parrot's personality:" | |
| 179 | + echo " 1) mild - Gentle and helpful" | |
| 180 | + echo " 2) sarcastic - Witty with attitude (recommended)" | |
| 181 | + echo " 3) savage - Brutally honest" | |
| 182 | + echo | |
| 183 | + read -p "Select personality [1-3, default: 2]: " personality_choice | |
| 184 | + | |
| 185 | + local personality="sarcastic" | |
| 186 | + case ${personality_choice:-2} in | |
| 187 | + 1) personality="mild" ;; | |
| 188 | + 2) personality="sarcastic" ;; | |
| 189 | + 3) personality="savage" ;; | |
| 190 | + *) personality="sarcastic" ;; | |
| 191 | + esac | |
| 192 | + | |
| 193 | + # Choose backend | |
| 194 | + echo | |
| 195 | + echo "Choose your preferred backend:" | |
| 196 | + local backend_options=() | |
| 197 | + local backend_descriptions=() | |
| 198 | + | |
| 199 | + if [[ " ${available_backends[@]} " =~ " local " ]]; then | |
| 200 | + backend_options+=("local") | |
| 201 | + backend_descriptions+=("Local AI (Ollama) - Private and fast") | |
| 202 | + fi | |
| 203 | + | |
| 204 | + if [[ " ${available_backends[@]} " =~ " api " ]]; then | |
| 205 | + backend_options+=("api") | |
| 206 | + backend_descriptions+=("API Backend - Requires API key, highest quality") | |
| 207 | + fi | |
| 208 | + | |
| 209 | + backend_options+=("fallback") | |
| 210 | + backend_descriptions+=("Fallback - Built-in responses, no setup required") | |
| 211 | + | |
| 212 | + for i in "${!backend_options[@]}"; do | |
| 213 | + echo " $((i+1))) ${backend_descriptions[i]}" | |
| 214 | + done | |
| 215 | + | |
| 216 | + echo | |
| 217 | + read -p "Select backend [1-${#backend_options[@]}, default: 1]: " backend_choice | |
| 218 | + | |
| 219 | + local selected_backend="${backend_options[$((${backend_choice:-1}-1))]}" | |
| 220 | + | |
| 221 | + # Set up configuration | |
| 222 | + setup_config_dir | |
| 223 | + create_basic_config "$selected_backend" "$personality" | |
| 224 | + | |
| 225 | + # Backend-specific setup | |
| 226 | + case "$selected_backend" in | |
| 227 | + "local") | |
| 228 | + if ! setup_ollama; then | |
| 229 | + print_warning "Ollama setup incomplete, falling back to basic responses" | |
| 230 | + create_basic_config "fallback" "$personality" | |
| 231 | + fi | |
| 232 | + ;; | |
| 233 | + "api") | |
| 234 | + if ! setup_api_backend; then | |
| 235 | + print_warning "API setup incomplete, you'll need to configure it manually" | |
| 236 | + fi | |
| 237 | + ;; | |
| 238 | + "fallback") | |
| 239 | + print_success "Fallback backend configured - no additional setup required" | |
| 240 | + ;; | |
| 241 | + esac | |
| 242 | + | |
| 243 | + # Shell integration | |
| 244 | + echo | |
| 245 | + setup_shell_integration | |
| 246 | + | |
| 247 | + echo | |
| 248 | + print_success "Parrot setup complete!" | |
| 249 | + echo | |
| 250 | + echo "Next steps:" | |
| 251 | + echo " 1. Run 'parrot setup' to enable shell integration" | |
| 252 | + echo " 2. Try 'parrot mock \"git push\" 1' to test it out" | |
| 253 | + echo " 3. Run 'parrot configure' to adjust settings" | |
| 254 | + echo | |
| 255 | + echo "For help: parrot --help" | |
| 256 | + print_info "Configuration file: $CONFIG_FILE" | |
| 257 | +} | |
| 258 | + | |
| 259 | +# Main execution | |
| 260 | +main() { | |
| 261 | + # Check if running interactively | |
| 262 | + if [[ -t 0 && -t 1 ]]; then | |
| 263 | + # Interactive mode | |
| 264 | + interactive_setup | |
| 265 | + else | |
| 266 | + # Non-interactive mode (RPM post-install) | |
| 267 | + print_header | |
| 268 | + echo "Parrot has been installed successfully!" | |
| 269 | + echo | |
| 270 | + echo "To complete setup, run:" | |
| 271 | + echo " parrot setup" | |
| 272 | + echo | |
| 273 | + echo "This will guide you through backend configuration and shell integration." | |
| 274 | + echo | |
| 275 | + print_info "For manual configuration, see: $EXAMPLE_CONFIG" | |
| 276 | + fi | |
| 277 | +} | |
| 278 | + | |
| 279 | +# Run main function | |
| 280 | +main "$@" | |