diff --git a/.gitignore b/.gitignore index 36b13f1..d0983a1 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,6 @@ cython_debug/ # PyPI configuration file .pypirc + +# Custom +config.json diff --git a/README.md b/README.md index 241032e..b100bff 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,21 @@ ## Overview -**TactiTerm** is an interactive software engineering tutor designed with a "guidance over answers" philosophy. Rather than providing copy-paste solutions, TactiTerm uses a **Socratic AI Mentor** to ask probing questions, provide hints, and guide users toward mastering concepts across 10 programming languages. +**TactiTerm** is an interactive software engineering tutor designed with a "guidance over answers" philosophy. Rather than providing copy-paste solutions, TactiTerm utilizes an **LLM Harness** to ask probing questions, provide hints, and guide users toward mastering concepts across various languages. -TactiTerm features both a rich **Terminal User Interface (TUI)** for command-line productivity and a modern **Web UI** featuring the Monaco Editor. +TactiTerm features both a rich **Terminal User Interface (TUI)** for command-line use, and a modern **Web UI** featuring the Monaco Editor. --- ## Features -- **Socratic AI Mentor:** Provides step-by-step guidance, code review, and conceptual hints without spoiling direct answers. +- **AI Mentor:** Provides step-by-step guidance, code review, and conceptual hints without spoiling direct answers. - **Dual Interfaces:** - - **TUI:** Built with Python and Textual for high-productivity, keyboard-driven terminal workflows. + - **TUI:** Built with Python and Textual for lightweight, keyboard-driven terminal workflows. - **Web UI:** Built with React, Vite, TypeScript, Tailwind CSS, and Monaco Editor. - **10 Supported Languages:** Python, C#, C++, Java, JavaScript, TypeScript, Rust, Lua, HTML, and Go. - **Real-time Linting & Execution:** Tree-sitter powered syntax validation and safe local code execution. -- **Interactive Syntax Handbook:** W3Schools-style reference catalog with on-demand AI code examples for functions and core language topics. +- **Interactive Syntax Handbook:** Comprehensive reference catalog with on-demand AI code examples for functions and core language topics. - **AI Challenge Generator (GenTUI):** Create and save custom Markdown programming challenges tailored to specific subjects and difficulties. - **Configurable & Network Ready:** Easily configure LLM endpoints, ports, and enable `"public": true` to host the Web UI across your local network (`0.0.0.0`). @@ -30,10 +30,9 @@ TactiTerm features both a rich **Terminal User Interface (TUI)** for command-lin ### Prerequisites -- Python 3.10+ -- [`uv`](https://github.com/astral-sh/uv) (Python package runner) -- Node.js & npm (for Web UI) -- [Devbox](https://www.jetify.com/devbox) (optional, for reproducible envs) +- [Devbox](https://www.jetify.com/devbox) + +> Currently we only officially support running this through devbox to simplify deployment, though if you have the prequisites installed, you should be able to run TactiTerm without it ### Installation @@ -45,30 +44,35 @@ TactiTerm features both a rich **Terminal User Interface (TUI)** for command-lin 2. Install dependencies: ```bash - make install + devbox run install ``` + *(or `make install` inside `devbox shell`)* --- -## 🎮 Usage +## Usage + +TactiTerm is executed via the use of **Devbox** run commands. ### Terminal Interface (TUI) Launch the interactive terminal application: ```bash -make tui +devbox run tui ``` +*(or `make tui` inside `devbox shell`)* Additional TUI modes: -- `make gentui` - Launch the standalone GenTUI AI Challenge Generator. -- `make tui-debug` - Launch TUI in debug logging mode. +- `devbox run gentui` - Launch the standalone GenTUI AI Challenge Generator. +- `devbox run -- make tui-debug` - Launch TUI in debug logging mode. ### Web Interface (Web UI) Launch the FastAPI backend server and Vite frontend dev server: ```bash -make web +devbox run web ``` +*(or `make web` inside `devbox shell`)* Then open your browser to `http://localhost:5173`. diff --git a/config.json b/config.json index a6cd70b..04239a7 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "llm": { - "base_url": "http://100.82.205.18:1010/", + "base_url": "http://localhost:8080/", "model": "local-model", "api_key": "not-needed", "temperature": 0.9, diff --git a/devbox.json b/devbox.json index 1fb479f..7d8f90e 100644 --- a/devbox.json +++ b/devbox.json @@ -11,6 +11,7 @@ ], "shell": { "scripts": { + "install": "make install", "tui": "make tui", "gentui": "make gentui", "web": "make web" diff --git a/frontend/src/pages/Workspace.tsx b/frontend/src/pages/Workspace.tsx index 8ee97bd..5f59f6a 100644 --- a/frontend/src/pages/Workspace.tsx +++ b/frontend/src/pages/Workspace.tsx @@ -68,13 +68,13 @@ const Workspace: React.FC = ({ challengeId, onBack }) => { const [userQuestion, setUserQuestion] = useState(''); const [isLoadingGuidance, setIsLoadingGuidance] = useState(false); - // Handbook W3Schools state + // Handbook state const [handbookCatalog, setHandbookCatalog] = useState({ functions: [], subjects: [] }); const [handbookTab, setHandbookTab] = useState<'functions' | 'subjects'>('functions'); const [searchQuery, setSearchQuery] = useState(''); const [selectedTopic, setSelectedTopic] = useState(null); const [handbookExample, setHandbookExample] = useState( - 'Select a built-in function or topic above to view W3Schools reference card...' + 'Select a built-in function or topic above to view reference card...' ); const [isLoadingExample, setIsLoadingExample] = useState(false); @@ -248,7 +248,7 @@ const Workspace: React.FC = ({ challengeId, onBack }) => { if (!currentChallenge) return; setSelectedTopic(topic); setIsLoadingExample(true); - setHandbookExample(`⏳ **Generating W3Schools reference card for '${topic.title}' in ${currentChallenge.language}...**\n\n*Consulting LLM backend...*`); + setHandbookExample(`⏳ **Generating reference card for '${topic.title}' in ${currentChallenge.language}...**\n\n*Consulting LLM backend...*`); try { const res = await getHandbookExample(currentChallenge.language, topic.id, topic.title); @@ -392,7 +392,7 @@ const Workspace: React.FC = ({ challengeId, onBack }) => { }`} > - W3Schools Handbook + Syntax Handbook @@ -634,7 +634,7 @@ const Workspace: React.FC = ({ challengeId, onBack }) => { )} - {/* Right Column Mode 2: W3Schools-Style Handbook Sidebar (Scalable Width) */} + {/* Right Column Mode 2: Handbook Sidebar (Scalable Width) */} {rightSidebarMode === 'handbook' && (
= ({ challengeId, onBack }) => { >

- W3Schools Reference ({currentChallenge?.language || 'Python'}) + Syntax Reference ({currentChallenge?.language || 'Python'})

- {/* Generated LLM W3Schools Reference Card View */} + {/* Generated LLM Reference Card View */}
diff --git a/src/api/main.py b/src/api/main.py index d6488b2..c02b032 100644 --- a/src/api/main.py +++ b/src/api/main.py @@ -144,7 +144,7 @@ class HandbookExampleRequest(BaseModel): @app.get("/handbook/catalog/{language}") def get_handbook_catalog_endpoint(language: str): - """Returns W3Schools-style syntax handbook catalog (functions & subjects) for specified language.""" + """Returns syntax handbook catalog (functions & subjects) for specified language.""" catalog = handbook_service.get_catalog(language) return {"language": language, "catalog": catalog} diff --git a/src/core/handbook.py b/src/core/handbook.py index 126465b..4a74ae7 100644 --- a/src/core/handbook.py +++ b/src/core/handbook.py @@ -1,4 +1,4 @@ -"""W3Schools-Style Language Reference Handbook service for built-in functions, methods, primitive types, and topics.""" +"""Language Reference Handbook service for built-in functions, methods, primitive types, and topics.""" import httpx from typing import Dict, List, Any from src.core.config import config @@ -197,7 +197,7 @@ HANDBOOK_CATALOG: Dict[str, Dict[str, List[Dict[str, str]]]] = { class HandbookService: - """W3Schools-Style Language Reference Handbook service.""" + """Language Reference Handbook service.""" def get_catalog(self, language: str) -> Dict[str, List[Dict[str, str]]]: canonical = registry.canonical_name(language) @@ -210,7 +210,7 @@ class HandbookService: lang_name = config_info.get("name", language) if config_info else language prompt = ( - f"Generate a W3Schools-Style Reference Card for '{topic_title}' in {lang_name}.\n" + f"Generate a Reference Card for '{topic_title}' in {lang_name}.\n" f"Structure your response strictly into these four Markdown sections:\n" f"1. **Syntax / Signature:** Clear representation of how to invoke or write it.\n" f"2. **Description & Parameters:** Brief summary of parameter types and return value.\n" @@ -219,7 +219,7 @@ class HandbookService: ) sys_prompt = ( - "You are an expert W3Schools-Style Documentation Assistant for TactiTerm.\n" + "You are an expert Documentation Assistant for TactiTerm.\n" "Provide clean, educational reference cards. Ensure the code example is realistic, complete, and copy-pasteable." ) @@ -259,7 +259,7 @@ class HandbookService: except Exception as e: return { "status": "error", - "message": f"Failed to generate W3Schools reference card via LLM: {e}", + "message": f"Failed to generate reference card via LLM: {e}", } diff --git a/src/tui/app.py b/src/tui/app.py index 0a15bc3..9f7ab5c 100644 --- a/src/tui/app.py +++ b/src/tui/app.py @@ -1,4 +1,4 @@ -"""TactiTerm TUI — Coding Tutor Terminal User Interface with W3Schools-style Handbook & Expandable Output Terminal.""" +"""TactiTerm TUI — Coding Tutor Terminal User Interface with Handbook & Expandable Output Terminal.""" import argparse import logging from typing import List, Dict, Any @@ -336,14 +336,14 @@ class TactiTermTUI(App): yield MentorInputTextArea(id="mentor-question-input") yield Button("💡 Ask Mentor (Enter)", id="btn-send-mentor", variant="warning") - # Right column 2: W3Schools-Style Handbook Sidebar + # Right column 2: Handbook Sidebar with Container(id="handbook-sidebar"): - yield Static("📖 W3Schools Handbook", id="handbook-header") + yield Static("📖 Handbook", id="handbook-header") yield Input(placeholder="🔍 Search built-ins or topics...", id="handbook-search-input") yield Button("Filter: All Items (Click to Switch)", id="btn-handbook-mode", variant="default") yield OptionList(id="handbook_topic_list") with VerticalScroll(id="handbook-example-scroll"): - yield Markdown("Select a function or topic above to view W3Schools reference card...", id="handbook-example-display") + yield Markdown("Select a function or topic above to view reference card...", id="handbook-example-display") yield Static("Ready", id="status-bar") yield Footer() @@ -524,7 +524,7 @@ class TactiTermTUI(App): self.load_handbook_catalog(lang) self.query_one("#handbook_topic_list", OptionList).focus() - self.query_one("#status-bar", Static).update(f"W3Schools Handbook open for {lang}.") + self.query_one("#status-bar", Static).update(f"Handbook open for {lang}.") def on_mentor_input_text_area_submit_question( self, event: MentorInputTextArea.SubmitQuestion @@ -699,7 +699,7 @@ class TactiTermTUI(App): lang = challenge.language if challenge else "Python" self.query_one("#handbook-example-display", Markdown).update( - f"⏳ **Generating W3Schools reference card for '{item['title']}' in {lang}...**" + f"⏳ **Generating reference card for '{item['title']}' in {lang}...**" ) self.run_worker(self._handbook_worker(lang, item["id"], item["title"]))