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
67 changes: 67 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Build and Deploy Docs

on:
push:
branches:
- main
paths:
- 'docs/**'
pull_request:
branches:
- main
paths:
- 'docs/**'
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: 'docs/package-lock.json'

- name: Install dependencies
run: |
cd docs
npm ci

- name: Build documentation
run: |
cd docs
npm run build

- name: Upload GitHub Pages artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: docs/out

deploy:
if: github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
23 changes: 19 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ __pycache__/
*.py[cod]
*.pyo

# Build & Distribution artifacts
build/
dist/
*.egg-info/

# Temp runner / editor files
*.temcoderunner
tempCodeRunnerFile.py
Expand All @@ -23,8 +28,18 @@ tempCodeRunnerFile.py
.DS_Store
Thumbs.db

#Temporarily ignored
.github/

# AI Code Bridge
# Ignored AI bridge
.agent/

# Node modules
docs/node_modules/
docs/.next/
docs/.cache
docs/out/

# Docs build caches
docs/.source/
docs/tsconfig.tsbuildinfo

# For PYPI
flux_cli
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

An AI coding agent built from scratch — inspired by Claude Code CLI and Gemini CLI — featuring full multi-tool orchestration, streaming responses, sub-agent delegation, MCP server integration, dynamic lifecycle hooks, safety approval policies, and a styled Rich terminal UI with gradient ASCII branding.

```text
[![flux-cli.png](https://i.postimg.cc/HWKhbWrT/flux-cli.png)](https://postimg.cc/rz1jkkGH)

<!-- ```text
██╗ ███████╗██╗ ██╗ ██╗██╗ ██╗
╚██╗ ██╔════╝██║ ██║ ██║╚██╗██╔╝
╚██╗ █████╗ ██║ ██║ ██║ ╚███╔╝
██╔╝ ██╔══╝ ██║ ██║ ██║ ██╔██╗
██╔╝ ██║ ███████╗╚██████╔╝██╔╝ ██╗
╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝
```
``` -->

---

Expand Down Expand Up @@ -183,10 +185,10 @@ pip install -r requirements.txt

```bash
# Recommended for CLI tools:
pipx install flux-cli-ai
pipx install flux-cli

# Or via standard pip:
pip install flux-cli-ai
pip install flux-cli

# Launch directly from anywhere in your terminal:
flux
Expand Down
9 changes: 9 additions & 0 deletions config/loader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
import os
from typing import Any
from platformdirs import user_config_dir, user_data_dir
import tomli
Expand Down Expand Up @@ -97,6 +98,14 @@ def load_config(cwd: Path | None) -> Config:
if agent_md_content:
config_dict['developer_instructions'] = agent_md_content

if "api_key" in config_dict and isinstance(config_dict["api_key"], str):
if not os.environ.get("API_KEY"):
os.environ["API_KEY"] = config_dict["api_key"]

if "base_url" in config_dict and isinstance(config_dict["base_url"], str):
if not os.environ.get("BASE_URL"):
os.environ["BASE_URL"] = config_dict["base_url"]

try:
config = Config(**config_dict)
except Exception as e:
Expand Down
79 changes: 79 additions & 0 deletions config/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import os
import re
from pathlib import Path
from rich.console import Console
from rich.prompt import Prompt
from rich.panel import Panel
from rich import box
from rich.text import Text
from config.loader import get_config_dir, get_system_config_path

console = Console()


def run_config_wizard() -> bool:
console.print()
console.print(
Panel(
Text("Welcome to Flux-CLI First-Time Setup Wizard!\nThis wizard will configure your API key, Base URL, and Model ID.", style="bold #7fe4eb"),
title="✦ Flux-CLI Setup",
border_style="#374151",
box=box.ROUNDED,
padding=(1, 2)
)
)

# 1. API Key
while True:
api_key = Prompt.ask("[bold #a191f8]Enter your API Key[/]").strip()
if api_key:
break
console.print("[red]API Key cannot be empty.[/red]")

# 2. Base URL
default_base_url = "https://openrouter.ai/api/v1"
while True:
base_url = Prompt.ask(
"[bold #8bcefc]Enter Base URL[/]",
default=default_base_url
).strip()
if base_url.startswith("http://") or base_url.startswith("https://"):
break
console.print("[red]Invalid Base URL. Must start with http:// or https://[/red]")

# 3. Model ID
default_model = "nvidia/nemotron-3-super-120b-a12b"
model_id = Prompt.ask(
"[bold #e7aafb]Enter Model ID[/]",
default=default_model
).strip() or default_model

# Build TOML content
config_dir = get_config_dir()
config_dir.mkdir(parents=True, exist_ok=True)
config_path = get_system_config_path()

toml_content = f"""# Flux-CLI System Configuration
api_key = "{api_key}"
base_url = "{base_url}"

[model]
name = "{model_id}"
temperature = 0.7
"""

try:
config_path.write_text(toml_content, encoding="utf-8")
console.print(
Panel(
Text(f"Configuration successfully saved to:\n{config_path}", style="bold #4ade80"),
title="✦ Setup Complete",
border_style="#4ade80",
box=box.ROUNDED,
padding=(1, 2)
)
)
return True
except Exception as e:
console.print(f"[bold red]Failed to save configuration: {e}[/bold red]")
return False
59 changes: 59 additions & 0 deletions docs/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { getPage, getPages } from '@/lib/source'
import defaultMdxComponents from 'fumadocs-ui/mdx'
import { Callout } from '@/components/callout'
import { FeatureCard } from '@/components/feature-card'
import { MermaidDiagram } from '@/components/mermaid-diagram'
import { CodeExample } from '@/components/code-example'
import { AsciiLogo } from '@/components/ascii-logo'
import { GradientBanner } from '@/components/gradient-banner'
import { CopyButton } from '@/components/copy-button'
import type { Metadata } from 'next'
import { DocsPage } from 'fumadocs-ui/page'
import { notFound } from 'next/navigation'

export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
const resolvedParams = await params
const slug = resolvedParams.slug ?? ['introduction']
const page = getPage(slug)

if (!page) {
notFound()
}

const MDX = page.data.body

return (
<DocsPage
toc={page.data.toc}
breadcrumb={{
enabled: true,
includePage: true,
}}
tableOfContent={{
enabled: true,
style: 'clerk',
}}
>
<MDX components={{ ...defaultMdxComponents, Callout, FeatureCard, MermaidDiagram, CodeExample, AsciiLogo, GradientBanner, CopyButton }} />
</DocsPage>
)
}

export async function generateStaticParams() {
return getPages().map((page) => ({
slug: page.slugs,
}))
}

export async function generateMetadata({ params }: { params: Promise<{ slug?: string[] }> }) {
const resolvedParams = await params
const slug = resolvedParams.slug ?? ['introduction']
const page = getPage(slug)

if (!page) return {}

return {
title: page.data.title,
description: page.data.description,
} satisfies Metadata
}
23 changes: 23 additions & 0 deletions docs/app/docs/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
import type { ReactNode } from 'react'
import { pageTree } from '@/lib/source'

export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
tree={pageTree}
nav={{
title: 'Flux-CLI',
transparentMode: 'top',
}}
sidebar={{
defaultOpenLevel: 1,
}}
themeSwitch={{
enabled: true,
}}
>
{children}
</DocsLayout>
)
}
Loading