{"id":51228948,"url":"https://github.com/jamesworldbuilder/geminline","last_synced_at":"2026-06-28T14:01:55.884Z","repository":{"id":360518818,"uuid":"1250520907","full_name":"jamesworldbuilder/geminline","owner":"jamesworldbuilder","description":"An AI assistant for the terminal","archived":false,"fork":false,"pushed_at":"2026-05-26T18:13:09.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T20:08:36.871Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesworldbuilder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-26T18:01:52.000Z","updated_at":"2026-05-26T18:13:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jamesworldbuilder/geminline","commit_stats":null,"previous_names":["jamesworldbuilder/geminline"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jamesworldbuilder/geminline","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesworldbuilder%2Fgeminline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesworldbuilder%2Fgeminline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesworldbuilder%2Fgeminline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesworldbuilder%2Fgeminline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesworldbuilder","download_url":"https://codeload.github.com/jamesworldbuilder/geminline/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesworldbuilder%2Fgeminline/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34890795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-28T14:01:52.368Z","updated_at":"2026-06-28T14:01:55.878Z","avatar_url":"https://github.com/jamesworldbuilder.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gemini_launcher.py\n\nA lightweight, command-line tool designed to scan your project's local code files and safely send them to Gemini for smart code analysis, automatic refactoring, and quick bug fixing.\n\n## Features\n\n- **Smart Code Scanning**: Automatically reads through your active project folders to look for web development files (like Python, JavaScript, HTML, CSS, and database files) so it can understand the exact structure of your application.\n- **Built-In Waiting Guard**: Keeps track of how many requests you send and how many code words (tokens) you use every minute. If you get too close to the free limits, it automatically pauses your script and runs a countdown timer to prevent Google's servers from blocking you.\n- **Saves Your Secret API Key**: You only have to type your Google AI Studio API key once on your first run. The script saves it securely in a hidden file in your folder, so you don't have to keep copying and pasting it every time you want to use it.\n- **Easy Shortcuts**: Supports specialized command keywords like `expand-code` or `organize-code`. Typing these tells the engine to immediately change its behavior, such as rewriting an entire file cleanly or automatically hunting down redundant logic blocks.\n- **Target Single Files**: Allows you to tell the script to focus purely on one single file instead of reading your whole repository, which saves processing speed and keeps your workspace clear.\n\n## Requirements\n\n- **Python**: Version 3.10 or higher is required to support modern standard library components and async processing pipelines.\n- **Pip Packages**: The official Google GenAI SDK library wrapper must be accessible within your runtime environment.\n  - *Installation*: Run the following command in your terminal interface before executing the utility:\n```bash\n    pip install google-genai\n```\n\n## Configuration Files\n\n- `.gemignore`: A local configuration file intended to explicitly hide heavy resource directories (like `node_modules`), system files, or any other files and/or directories you want the AI assistant to ignore during its analysis are listed in this file.\n\n- `gemini-instructions.txt`: A local configuration file that describes the design rules, professional coding standards, and identity configurations of which the AI assistant is specialized in.\n\n## Setup \u0026 Persistent Alias\n\n1. Place `gemini_launcher.py` and your structural `gemini-instructions.txt` configuration file side-by-side inside your chosen system directory.\n2. Mark the script file as an executable binary asset so Linux can launch it cleanly:\n```bash\n    chmod +x /path/to/your/directory/gemini_launcher.py\n```\n3. Run the following command to append the persistent `geminline` alias to your bash runtime profile configuration and instantly refresh your terminal session environment:\n```bash\n    echo 'alias geminline=\"python3 /path/to/your/directory/gemini_launcher.py\"' \u003e\u003e ~/.bashrc \u0026\u0026 source ~/.bashrc\n```\n\n## Usage\n\n### Ask a General Coding Question\nType your instruction as a sentence in quotes. The script automatically reads your current folder files and helps you work on them:\n```bash\n    geminline \"Look through my variables and check for any typos or spelling mistakes\"\n```\n\n### Focus on a Specific File\nUse the `--targets` modifier to make the tool only scan and edit an individual asset, bypassing the rest of your background project files:\n```bash\n    geminline --targets src/utils/helpers.py \"Consolidate the functions\"\n```\n\n### Check Your Waiting Timers\nTo see how much space you have left in your rolling 60-second free bracket without actually sending a new question to the server, check your status dashboard:\n```bash\n    geminline --status\n```\n\n## Example Output\n```bash\n    geminline --targets ./static/js/sidebar-ui.js \"In transforms-timeline-panel, let's make the following adjustments: 1.) If the set-transform-interval-btn is selected, then the parent transform-row should be automatically selected. 2.) When a transform-row is selected, the first transform-config-element in the transformations-matrix, within the selected transform-row, should be automatically selected/highlighted. Currently, selecting the transform-config-element auto-selects transform-row-1, instead of the current parent transform-row.\"\n```\n```bash\n    === SELECT ASSISTANT TIER ===\n    [1] Free Tier Assistant (gemini-2.5-flash-lite)\n    [2] Paid/Premium Pro Assistant (gemini-2.5-pro)\n    [3] Advanced Flash Assistant (gemini-3.5-flash)\n    Select an assistant option [1-3] (Default: 1): 3\n    Proceeding with engine configuration: gemini-3.5-flash\n    \n    \n    === FREE TIER RUNTIME TELEMETRY ===\n    Active Model Engine: gemini-3.5-flash\n    Requests (Last 60s): 0/15  (Headroom remaining: 15)\n    Daily Quota Used:    2/1500  (Daily remaining: 1498)\n    Tokens Used (Last 60s): 0/1000000 (Headroom remaining: 1000000)\n    Window State: Stable (Next token slot refresh calculation in: 0s)\n    ===================================\n    \n    Loading ignore configuration fields...\n    Loading external AI instructions configuration found...\n    Scanning workspace in '.'...\n    Cyrus is analyzing your codebase and generating revisions...\n    \n    RESPONSE:\n    \n    ========================================\n    REVISION 1\n    ========================================\n    \u003ctarget_file\u003e./static/js/sidebar-ui.js\u003c/target_file\u003e\n    \n    \u003coriginal\u003e\n    // dynamically sets active node and refreshes properties UI panels on single click\n            row.addEventListener('click', (e) =\u003e {\n                if (e.target.tagName === 'BUTTON' || e.target.closest('button') || e.target.tagName === 'INPUT' || e.target.closest('.transform-interval-timing')) return\n                \n                const rowsContainer = document.getElementById('transforms-rows')\n                if (rowsContainer) {\n                    Array.from(rowsContainer.children).forEach(r =\u003e r.style.borderLeftColor = 'transparent')\n                }\n                row.style.borderLeftColor = '#00a8ff'\n    \u003c/original\u003e\n    \n    \u003creplacement\u003e\n    // dynamically sets active node and refreshes properties UI panels on single click\n            row.addEventListener('click', (e) =\u003e {\n                if (e.target.tagName === 'BUTTON' || e.target.closest('button') || e.target.tagName === 'INPUT' || e.target.closest('.transform-interval-timing')) return\n                \n                const rowsContainer = document.getElementById('transforms-rows')\n                if (rowsContainer) {\n                    Array.from(rowsContainer.children).forEach(r =\u003e r.style.borderLeftColor = 'transparent')\n                }\n                row.style.borderLeftColor = '#00a8ff'\n                \n                // Automatically select/highlight the first transform-config-element (index 0)\n                configData.activeTransformEditIndex = 0\n                row.dataset.transformConfig = JSON.stringify(configData)\n                renderMatrixGrid()\n    \u003c/replacement\u003e\n    \n    ========================================\n    REVISION 2\n    ========================================\n    \u003ctarget_file\u003e./static/js/sidebar-ui.js\u003c/target_file\u003e\n    \n    \u003coriginal\u003e\n    matrixBtn.onclick = (e) =\u003e {\n                        e.preventDefault()\n                        e.stopPropagation()\n                        configData.activeTransformEditIndex = i\n                        const tRow = matrixDiv.closest('.transforms-list-item')\n                        if (tRow) tRow.dataset.transformConfig = JSON.stringify(configData)\n                        renderMatrixGrid()\n                        if (rowsContainer \u0026\u0026 rowsContainer.children[i]) {\n                            rowsContainer.children[i].click()\n                        }\n                    }\n    \u003c/original\u003e\n    \n    \u003creplacement\u003e\n    matrixBtn.onclick = (e) =\u003e {\n                        e.preventDefault()\n                        e.stopPropagation()\n                        configData.activeTransformEditIndex = i\n                        const tRow = matrixDiv.closest('.transforms-list-item')\n                        if (tRow) tRow.dataset.transformConfig = JSON.stringify(configData)\n                        renderMatrixGrid()\n                        if (tRow) {\n                            tRow.click()\n                        }\n                    }\n    \u003c/replacement\u003e\n    \n    ========================================\n    REVISION 3\n    ========================================\n    \u003ctarget_file\u003e./static/js/sidebar-ui.js\u003c/target_file\u003e\n    \n    \u003coriginal\u003e\n    timeBtn.onclick = (e) =\u003e {\n                e.preventDefault()\n                e.stopPropagation()\n                const isHidden = timingDiv.style.display === 'none'\n                timingDiv.style.display = isHidden ? 'flex' : 'none'\n                // toggles outer block layout for the matrix wrapper\n                matrixDiv.style.display = isHidden ? 'block' : 'none'\n                timeBtn.style.color = isHidden ? configData.markerColor : '#aaa'\n                timeBtn.style.opacity = isHidden ? '1' : '0.6'\n                \n                const cfg = JSON.parse(row.dataset.transformConfig)\n                cfg.isTimingOpen = isHidden\n                row.dataset.transformConfig = JSON.stringify(cfg)\n                \n                if (typeof activeNode !== 'undefined' \u0026\u0026 activeNode) {\n                    let existingData = activeNode.getAttr('transformGroupData')\n                    const tKey = tRow.dataset.transformKey\n                    if (existingData \u0026\u0026 existingData[tKey]) {\n                        existingData[tKey].isTimingOpen = isHidden\n                        activeNode.setAttr('transformGroupData', existingData)\n                    }\n                }\n    \u003c/original\u003e\n    \n    \u003creplacement\u003e\n    timeBtn.onclick = (e) =\u003e {\n                e.preventDefault()\n                e.stopPropagation()\n                \n                // Automatically select the parent transform-row\n                row.click()\n    \n                const isHidden = timingDiv.style.display === 'none'\n                timingDiv.style.display = isHidden ? 'flex' : 'none'\n                // toggles outer block layout for the matrix wrapper\n                matrixDiv.style.display = isHidden ? 'block' : 'none'\n                timeBtn.style.color = isHidden ? configData.markerColor : '#aaa'\n                timeBtn.style.opacity = isHidden ? '1' : '0.6'\n                \n                const cfg = JSON.parse(row.dataset.transformConfig)\n                cfg.isTimingOpen = isHidden\n                row.dataset.transformConfig = JSON.stringify(cfg)\n                \n                if (typeof activeNode !== 'undefined' \u0026\u0026 activeNode) {\n                    let existingData = activeNode.getAttr('transformGroupData')\n                    const tKey = row.dataset.transformKey\n                    if (existingData \u0026\u0026 existingData[tKey]) {\n                        existingData[tKey].isTimingOpen = isHidden\n                        activeNode.setAttr('transformGroupData', existingData)\n                    }\n                }\n    \u003c/replacement\u003e\n    \n    \n    ========================================\n    Model Engine:     gemini-3.5-flash\n    Prompt Tokens:    137329\n    Output Tokens:    1281\n    Total Session:    138610 tokens\n    Remaining Window: 861390 tokens (Max: 1000000)\n    ========================================\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesworldbuilder%2Fgeminline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesworldbuilder%2Fgeminline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesworldbuilder%2Fgeminline/lists"}