From 8ba30d4b3dac19bde49f339b93bfa4ca5eeb4db3 Mon Sep 17 00:00:00 2001
From: aimidi
Date: Sun, 19 Apr 2026 01:10:19 +0800
Subject: [PATCH] fix: align lldb docs and repl skin
---
README.md | 6 +-
.../cli_anything/lldb/utils/repl_skin.py | 120 +++++++++---------
2 files changed, 61 insertions(+), 65 deletions(-)
diff --git a/README.md b/README.md
index 0cf444a50..3d19bd474 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ CLI-Anything: Bridging the Gap Between AI Agents and the World's Software
-
+
@@ -587,7 +587,7 @@ AI agents are great at reasoning but terrible at using real professional softwar
| 💸 "UI automation breaks constantly" | No screenshots, no clicking, no RPA fragility. Pure command-line reliability with structured interfaces |
| 📊 "Agents need structured data" | Built-in JSON output for seamless agent consumption + human-readable formats for debugging |
| 🔧 "Custom integrations are expensive" | One Claude plugin auto-generates CLIs for ANY codebase through proven 7-phase pipeline |
-| âš¡ "Prototype vs Production gap" | 2,159+ tests with real software validation. Battle-tested across 31 major applications |
+| âš¡ "Prototype vs Production gap" | 2,173+ tests with real software validation. Battle-tested across 31 major applications |
---
@@ -1339,7 +1339,7 @@ MIT License — free to use, modify, and distribute.
**CLI-Anything** — *Make any software with a codebase Agent-native.*
-A methodology for the age of AI agents | 31 professional software demos | 2,159 passing tests
+A methodology for the age of AI agents | 31 professional software demos | 2,173 passing tests
diff --git a/lldb/agent-harness/cli_anything/lldb/utils/repl_skin.py b/lldb/agent-harness/cli_anything/lldb/utils/repl_skin.py
index 201ff6414..c7312348a 100644
--- a/lldb/agent-harness/cli_anything/lldb/utils/repl_skin.py
+++ b/lldb/agent-harness/cli_anything/lldb/utils/repl_skin.py
@@ -30,7 +30,7 @@ _ITALIC = "\033[3m"
_UNDERLINE = "\033[4m"
# Brand colors
-_CYAN = "\033[38;5;80m" # cli-anything brand cyan
+_CYAN = "\033[38;5;80m" # cli-anything brand cyan
_CYAN_BG = "\033[48;5;80m"
_WHITE = "\033[97m"
_GRAY = "\033[38;5;245m"
@@ -39,16 +39,16 @@ _LIGHT_GRAY = "\033[38;5;250m"
# Software accent colors — each software gets a unique accent
_ACCENT_COLORS = {
- "gimp": "\033[38;5;214m", # warm orange
- "blender": "\033[38;5;208m", # deep orange
- "inkscape": "\033[38;5;39m", # bright blue
- "audacity": "\033[38;5;33m", # navy blue
- "libreoffice": "\033[38;5;40m", # green
- "obs_studio": "\033[38;5;55m", # purple
- "kdenlive": "\033[38;5;69m", # slate blue
- "shotcut": "\033[38;5;35m", # teal green
+ "gimp": "\033[38;5;214m", # warm orange
+ "blender": "\033[38;5;208m", # deep orange
+ "inkscape": "\033[38;5;39m", # bright blue
+ "audacity": "\033[38;5;33m", # navy blue
+ "libreoffice": "\033[38;5;40m", # green
+ "obs_studio": "\033[38;5;55m", # purple
+ "kdenlive": "\033[38;5;69m", # slate blue
+ "shotcut": "\033[38;5;35m", # teal green
}
-_DEFAULT_ACCENT = "\033[38;5;75m" # default sky blue
+_DEFAULT_ACCENT = "\033[38;5;75m" # default sky blue
# Status colors
_GREEN = "\033[38;5;78m"
@@ -81,7 +81,6 @@ _CROSS = "┼"
def _strip_ansi(text: str) -> str:
"""Remove ANSI escape codes for length calculation."""
import re
-
return re.sub(r"\033\[[^m]*m", "", text)
@@ -97,7 +96,8 @@ class ReplSkin:
across all CLI harnesses built with the cli-anything methodology.
"""
- def __init__(self, software: str, version: str = "1.0.0", history_file: str | None = None, skill_path: str | None = None):
+ def __init__(self, software: str, version: str = "1.0.0",
+ history_file: str | None = None, skill_path: str | None = None):
"""Initialize the REPL skin.
Args:
@@ -118,7 +118,6 @@ class ReplSkin:
# cli_anything//skills/SKILL.md (target)
if skill_path is None:
from pathlib import Path
-
_auto = Path(__file__).resolve().parent.parent / "skills" / "SKILL.md"
if _auto.is_file():
skill_path = str(_auto)
@@ -128,7 +127,6 @@ class ReplSkin:
# History file
if history_file is None:
from pathlib import Path
-
hist_dir = Path.home() / f".cli-anything-{self.software}"
hist_dir.mkdir(parents=True, exist_ok=True)
self.history_file = str(hist_dir / "history")
@@ -200,7 +198,8 @@ class ReplSkin:
# ── Prompt ────────────────────────────────────────────────────────
- def prompt(self, project_name: str = "", modified: bool = False, context: str = "") -> str:
+ def prompt(self, project_name: str = "", modified: bool = False,
+ context: str = "") -> str:
"""Build a styled prompt string for prompt_toolkit or input().
Args:
@@ -234,7 +233,8 @@ class ReplSkin:
return "".join(parts)
- def prompt_tokens(self, project_name: str = "", modified: bool = False, context: str = ""):
+ def prompt_tokens(self, project_name: str = "", modified: bool = False,
+ context: str = ""):
"""Build prompt_toolkit formatted text tokens for the prompt.
Use with prompt_toolkit's FormattedText for proper ANSI handling.
@@ -272,25 +272,23 @@ class ReplSkin:
accent_hex = _ANSI_256_TO_HEX.get(self.accent, "#5fafff")
- return Style.from_dict(
- {
- "icon": "#5fdfdf bold", # cyan brand color
- "software": f"{accent_hex} bold",
- "bracket": "#585858",
- "context": "#bcbcbc",
- "arrow": "#808080",
- # Completion menu
- "completion-menu.completion": "bg:#303030 #bcbcbc",
- "completion-menu.completion.current": f"bg:{accent_hex} #000000",
- "completion-menu.meta.completion": "bg:#303030 #808080",
- "completion-menu.meta.completion.current": f"bg:{accent_hex} #000000",
- # Auto-suggest
- "auto-suggest": "#585858",
- # Bottom toolbar
- "bottom-toolbar": "bg:#1c1c1c #808080",
- "bottom-toolbar.text": "#808080",
- }
- )
+ return Style.from_dict({
+ "icon": "#5fdfdf bold", # cyan brand color
+ "software": f"{accent_hex} bold",
+ "bracket": "#585858",
+ "context": "#bcbcbc",
+ "arrow": "#808080",
+ # Completion menu
+ "completion-menu.completion": "bg:#303030 #bcbcbc",
+ "completion-menu.completion.current": f"bg:{accent_hex} #000000",
+ "completion-menu.meta.completion": "bg:#303030 #808080",
+ "completion-menu.meta.completion.current": f"bg:{accent_hex} #000000",
+ # Auto-suggest
+ "auto-suggest": "#585858",
+ # Bottom toolbar
+ "bottom-toolbar": "bg:#1c1c1c #808080",
+ "bottom-toolbar.text": "#808080",
+ })
# ── Messages ──────────────────────────────────────────────────────
@@ -367,7 +365,8 @@ class ReplSkin:
# ── Table display ─────────────────────────────────────────────────
- def table(self, headers: list[str], rows: list[list[str]], max_col_width: int = 40):
+ def table(self, headers: list[str], rows: list[list[str]],
+ max_col_width: int = 40):
"""Print a formatted table with box-drawing characters.
Args:
@@ -383,19 +382,25 @@ class ReplSkin:
for row in rows:
for i, cell in enumerate(row):
if i < len(col_widths):
- col_widths[i] = min(max(col_widths[i], len(str(cell))), max_col_width)
+ col_widths[i] = min(
+ max(col_widths[i], len(str(cell))), max_col_width
+ )
def pad(text: str, width: int) -> str:
t = str(text)[:width]
return t + " " * (width - len(t))
# Header
- header_cells = [self._c(_CYAN + _BOLD, pad(h, col_widths[i])) for i, h in enumerate(headers)]
+ header_cells = [
+ self._c(_CYAN + _BOLD, pad(h, col_widths[i]))
+ for i, h in enumerate(headers)
+ ]
sep = self._c(_DARK_GRAY, f" {_V_LINE} ")
header_line = f" {sep.join(header_cells)}"
print(header_line)
# Separator
+ sep_parts = [self._c(_DARK_GRAY, _H_LINE * w) for w in col_widths]
sep_line = self._c(_DARK_GRAY, f" {'───'.join([_H_LINE * w for w in col_widths])}")
print(sep_line)
@@ -438,18 +443,11 @@ class ReplSkin:
Returns:
A configured PromptSession, or None if prompt_toolkit unavailable.
"""
- # prompt_toolkit's Windows console backend requires a real TTY/console
- # handle. When the CLI is driven by subprocess pipes for tests or agent
- # automation, fall back to plain input() instead of crashing.
- if not getattr(sys.stdin, "isatty", lambda: False)():
- return None
- if not getattr(sys.stdout, "isatty", lambda: False)():
- return None
-
try:
from prompt_toolkit import PromptSession
- from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.history import FileHistory
+ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
+ from prompt_toolkit.formatted_text import FormattedText
style = self.get_prompt_style()
@@ -463,7 +461,8 @@ class ReplSkin:
except ImportError:
return None
- def get_input(self, pt_session, project_name: str = "", modified: bool = False, context: str = "") -> str:
+ def get_input(self, pt_session, project_name: str = "",
+ modified: bool = False, context: str = "") -> str:
"""Get input from user using prompt_toolkit or fallback.
Args:
@@ -477,11 +476,11 @@ class ReplSkin:
"""
if pt_session is not None:
from prompt_toolkit.formatted_text import FormattedText
-
tokens = self.prompt_tokens(project_name, modified, context)
return pt_session.prompt(FormattedText(tokens)).strip()
- raw_prompt = self.prompt(project_name, modified, context)
- return input(raw_prompt).strip()
+ else:
+ raw_prompt = self.prompt(project_name, modified, context)
+ return input(raw_prompt).strip()
# ── Toolbar builder ───────────────────────────────────────────────
@@ -494,10 +493,8 @@ class ReplSkin:
Returns:
A callable that returns FormattedText for the toolbar.
"""
-
def toolbar():
from prompt_toolkit.formatted_text import FormattedText
-
parts = []
for i, (k, v) in enumerate(items.items()):
if i > 0:
@@ -505,21 +502,20 @@ class ReplSkin:
parts.append(("class:bottom-toolbar.text", f" {k}: "))
parts.append(("class:bottom-toolbar", v))
return FormattedText(parts)
-
return toolbar
# ── ANSI 256-color to hex mapping (for prompt_toolkit styles) ─────────
_ANSI_256_TO_HEX = {
- "\033[38;5;33m": "#0087ff", # audacity navy blue
- "\033[38;5;35m": "#00af5f", # shotcut teal
- "\033[38;5;39m": "#00afff", # inkscape bright blue
- "\033[38;5;40m": "#00d700", # libreoffice green
- "\033[38;5;55m": "#5f00af", # obs purple
- "\033[38;5;69m": "#5f87ff", # kdenlive slate blue
- "\033[38;5;75m": "#5fafff", # default sky blue
- "\033[38;5;80m": "#5fd7d7", # brand cyan
+ "\033[38;5;33m": "#0087ff", # audacity navy blue
+ "\033[38;5;35m": "#00af5f", # shotcut teal
+ "\033[38;5;39m": "#00afff", # inkscape bright blue
+ "\033[38;5;40m": "#00d700", # libreoffice green
+ "\033[38;5;55m": "#5f00af", # obs purple
+ "\033[38;5;69m": "#5f87ff", # kdenlive slate blue
+ "\033[38;5;75m": "#5fafff", # default sky blue
+ "\033[38;5;80m": "#5fd7d7", # brand cyan
"\033[38;5;208m": "#ff8700", # blender deep orange
"\033[38;5;214m": "#ffaf00", # gimp warm orange
}