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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ k8s/01-secrets.yaml

# But keep README.md
!README.md

taskflow-cli/venv
401 changes: 94 additions & 307 deletions core/queue_manager.py

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions taskflow-cli/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
certifi==2026.1.4
charset-normalizer==3.4.4
click==8.3.1
idna==3.11
keyring==25.7.0
markdown-it-py==4.0.0
mdurl==0.1.2
pillow==12.1.0
Pygments==2.19.2
requests==2.32.5
rich==14.2.0
rich-pixels==3.0.1
shellingham==1.5.4
typer==0.21.1
typing_extensions==4.15.0
urllib3==2.6.3
17 changes: 17 additions & 0 deletions taskflow-cli/run_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env python3
"""
TaskFlow CLI Entry Point

This script allows running the CLI from the project root without installation.
"""

import sys
from pathlib import Path

# Add the parent directory to the path so we can import taskflow
sys.path.insert(0, str(Path(__file__).parent))

from taskflow.main import run

if __name__ == "__main__":
run()
28 changes: 28 additions & 0 deletions taskflow-cli/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from setuptools import setup, find_packages

with open("requirements.txt") as f:
requirements = f.read().splitlines()

setup(
name="taskflow-cli",
version="2.1.0",
description="TaskFlow CLI - Distributed Task Orchestrator",
author="TaskFlow Team",
packages=find_packages(),
include_package_data=True,
install_requires=requirements,
entry_points={
"console_scripts": [
"taskflow=taskflow.main:run",
],
},
python_requires=">=3.8",
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Operating System :: OS Independent",
],
)
13 changes: 13 additions & 0 deletions taskflow-cli/taskflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
TaskFlow CLI - Distributed Task Orchestrator

A powerful command-line interface for managing distributed task orchestration.
"""

__version__ = "2.1.0"
__author__ = "TaskFlow Team"

from . import cli, auth, api, main

__all__ = ["cli", "auth", "api", "main"]

36 changes: 36 additions & 0 deletions taskflow-cli/taskflow/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import requests
import os
import json
from pathlib import Path
from rich.console import Console
from .auth import get_token

console = Console()

BASE_URL = "http://localhost:8080"


def get_headers():
"""Get headers with JWT token if available."""
headers = {}
token = get_token()
if token:
headers["Authorization"] = f"Bearer {token}"
return headers


def api_request(method: str, endpoint: str, **kwargs):
"""Make an authenticated API request."""
headers = kwargs.get("headers", {})
headers.update(get_headers())
kwargs["headers"] = headers

# Refresh BASE_URL in case config changed
url = f"{BASE_URL}{endpoint}"

try:
response = requests.request(method, url, **kwargs)
return response
except requests.exceptions.RequestException as e:
console.print(f"[bold red]Connection Error:[/] {e}")
return None
37 changes: 37 additions & 0 deletions taskflow-cli/taskflow/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import keyring
import requests
import os
import json
from pathlib import Path

SERVICE_NAME = "taskflow-cli"
TOKEN_KEY = "jwt_token"

BASE_URL = "http://localhost:8080"


def save_token(token: str):
"""Saves the JWT token to the system's secure keyring."""
keyring.set_password(SERVICE_NAME, TOKEN_KEY, token)


def get_token():
"""Retrieves the stored token for API requests."""
return keyring.get_password(SERVICE_NAME, TOKEN_KEY)


def delete_token():
"""Removes the token on logout."""
keyring.delete_password(SERVICE_NAME, TOKEN_KEY)


def api_request(method, endpoint, **kwargs):
"""Wrapper for requests that automatically injects the Bearer token."""
token = get_token()
headers = kwargs.get("headers", {})
if token:
headers["Authorization"] = f"Bearer {token}"

kwargs["headers"] = headers
url = f"{BASE_URL}{endpoint}"
return requests.request(method, url, **kwargs)
Loading