Skip to content

Improve CLI startup and clean generated artifacts - #5

Merged
2233admin merged 6 commits into
masterfrom
codex/startup-lazy-load
Jun 5, 2026
Merged

Improve CLI startup and clean generated artifacts#5
2233admin merged 6 commits into
masterfrom
codex/startup-lazy-load

Conversation

@2233admin

@2233admin 2233admin commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • lazily import heavier CLI/runtime modules to reduce basic startup cost
  • add glyph-arts serve --stdio for low-latency repeated rendering
  • split the large CLI dispatcher into focused command modules
  • remove tracked dist/ and export_test_outputs/ artifacts and ignore regenerated exports
  • decode subprocess text output and user input files as UTF-8 to avoid Windows GBK/cp936 failures

Validation

  • uv run --extra dev ruff check .
  • uv run --extra dev mypy cli_charts --ignore-missing-imports
  • uv run --extra all --extra test python -m pytest tests/ -q (331 passed, 1 skipped)
  • npx nx run glyph-arts:build
  • uv run glyph-arts --check-deps
  • uv run glyph-arts --check-deps --all

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@2233admin, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 minutes and 44 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8cea6941-df27-4fbb-b8f2-42c1ccdc23a6

📥 Commits

Reviewing files that changed from the base of the PR and between aa31a07 and 19bd041.

⛔ Files ignored due to path filters (3)
  • dist/cli_charts-2.4.1-py3-none-any.whl is excluded by !**/dist/**
  • dist/cli_charts-2.4.1.tar.gz is excluded by !**/dist/**, !**/*.gz
  • export_test_outputs/out.png is excluded by !**/*.png
📒 Files selected for processing (97)
  • .gitignore
  • README.md
  • cli_charts/__init__.py
  • cli_charts/cli.py
  • cli_charts/cmd/__init__.py
  • cli_charts/cmd/_helpers.py
  • cli_charts/cmd/animate_stream.py
  • cli_charts/cmd/direct_commands.py
  • cli_charts/cmd/motion_commands.py
  • cli_charts/cmd/parser.py
  • cli_charts/cmd/serve.py
  • cli_charts/cmd/text_input_commands.py
  • cli_charts/cmd/tool_commands.py
  • cli_charts/dashboard.py
  • cli_charts/demo_engine.py
  • cli_charts/media_render.py
  • cli_charts/render/media_engine.py
  • cli_charts/serve_stdio.py
  • export_test_outputs/no-color.html
  • export_test_outputs/out.ansi
  • export_test_outputs/out.txt
  • export_test_outputs/phase7a/0b0dda1d55204461b9bfe40b7aaf7e2d/out.md
  • export_test_outputs/phase7a/0ed2753528c44580bed6a7685bfd4b81/out.md
  • export_test_outputs/phase7a/0f366542013c449caf3b5f2a6fd2e393/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/1058b6d751c845c9a822f9949c7ab07d/out.md
  • export_test_outputs/phase7a/1126bfe51eae483098e0f4333472d13c/out.md
  • export_test_outputs/phase7a/1735db09df58472eb47e6a6706a607d4/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/177060ab73894516ba51c9d214a32d80/out.md
  • export_test_outputs/phase7a/1c1a234f2cdc42e6818b7de3088a4d2b/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/1d775b2a31574040bf00960fe0c820cb/out.md
  • export_test_outputs/phase7a/1e39fb4b5433490b921916a6d453d170/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/1e4ea4f4e18c462bb458c90717ca39da/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/2032e792411d45429dabdc274baa9109/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/21dc582bf6294a28b3dbab1d25c5d9d3/out.md
  • export_test_outputs/phase7a/230f75b5708f44eeabfd729e757637f2/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/23871df2997b4cd9895bc1b2f9f66a43/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/2472e175b6844bf1b376be5f2c61779d/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/262492db3cdc4ef1ab0a9055d9639a3d/out.md
  • export_test_outputs/phase7a/270f550bcba5415eb3b3e4bfebf43038/out.md
  • export_test_outputs/phase7a/2bfcb63b3c2740919efbf1f5e8b2fc67/out.md
  • export_test_outputs/phase7a/2e5a20eef2254a1c8a09472b32b3a566/out.md
  • export_test_outputs/phase7a/34baa3824e464ed8860f183e50327ff0/out.md
  • export_test_outputs/phase7a/3a08dd21febf494c81730fad747a541b/out.md
  • export_test_outputs/phase7a/3a7e58716ee844cdaacbb83f5d9f101e/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/3a977fa1156c4b9799c84837949fcba7/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/3f1218103c7647779de5357730998023/out.md
  • export_test_outputs/phase7a/42b1d1ee18c7462c92272e8b5938f855/out.md
  • export_test_outputs/phase7a/4e80980854a34b5c8c1205513b961bc5/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/4f60600a7bc549459b779800b568eb1e/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/50ab54a56cca4c80bc6355e7283db841/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/53704a248b574288b248742c278155eb/out.md
  • export_test_outputs/phase7a/5b78aa271c554db2852fc8de2a8603c1/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/5e61629e7dde4aa39ab7a4a628ced8d4/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/62ae6095d5ff465aa0b4d41be781a41c/out.md
  • export_test_outputs/phase7a/63fe67e65fb24844aa441d956cf3a558/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/6a40a9aa098e4afe86ed1fb158aa3de1/out.md
  • export_test_outputs/phase7a/6a77fcbb75c144f9873ef532434d8bdc/out.md
  • export_test_outputs/phase7a/7063001ac3284566ae45def7b162adac/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/78ea5d9ce5464d33af68b4764f47b356/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/813f7434bbf548d69b012eb9d42c15be/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/83737e9e4a2b40d28a5ee9178a8c0291/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/8a77813ece05425f9a88997cc0a6cd14/out.md
  • export_test_outputs/phase7a/8b5e10d3ca8449d6b71531a90d91bf24/out.md
  • export_test_outputs/phase7a/8cdbd22358fd45c3af9c8576659b5a43/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/8dbcd82d7704415694cf611dd9ee5266/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/96bb4e08edd04ef6ba515ba2a10cd19a/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/96fe9c9b74d445328319142f93d1acb0/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/9a67e2cb98af4d13b984083dfef7dc32/out.md
  • export_test_outputs/phase7a/9b18df1d99b241f1b930e7bde9dff8ef/out.md
  • export_test_outputs/phase7a/9d7a4dada44e45e8a22eb41981520021/out.md
  • export_test_outputs/phase7a/9e6737caabbb408fa076820c56195ff6/out.md
  • export_test_outputs/phase7a/a55d37a621054aa1bf50e8fa370a0330/out.md
  • export_test_outputs/phase7a/b223c864b0704e0baa68eca9da04655f/out.md
  • export_test_outputs/phase7a/bc3e5e4323d84bbc8dd42db0294f5890/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/bc5ab502d65f4d89a9435458c20c1c0d/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/d1a27a41a565441aa38fd1c4b18dcb04/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/d88dd3ffbd6745a8a54980eca8fd3eb5/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/e002a470a4c7408cbac3f4ad9acb183c/out.md
  • export_test_outputs/phase7a/e3e3496429054a8291fa6338a2f5b422/out.md
  • export_test_outputs/phase7a/e97596824bc74832ab900525e4867dc9/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/edae4dbb48474a0f9caa39137c47711b/out.md
  • export_test_outputs/phase7a/ede01caee14545e9a1603d5267108f72/out.md
  • export_test_outputs/phase7a/f4d64796934f4fbe95cfe69f8214fad2/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/f95b676486ee453db5f78afe82cf14da/out.md
  • export_test_outputs/phase7a/fb3410e8a5a04bb2b7db6f526ddae80c/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/fb7fd22825a74ceabc3b58e20fd1eaf4/.claude/themes/dark-ansi.json
  • export_test_outputs/phase7a/fd533adc35eb4e668c2fce451a663308/out.md
  • export_test_outputs/phase7a_verify.md
  • export_test_outputs/record-demo.cast
  • export_test_outputs/record-dispatch.cast
  • export_test_outputs/strips.html
  • export_test_outputs/wraps.html
  • pyproject.toml
  • tests/test_media_render.py
  • tests/test_serve_stdio.py
  • tests/test_startup_imports.py
  • tests/test_style_routing.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@repowise-bot

repowise-bot Bot commented Jun 5, 2026

Copy link
Copy Markdown

✅ Health: 6.3 → 6.6 (+0.3)
1 file moved · 4 hotspots · 5 hidden couplings · 5 dead-code findings

🚨 Change risk: 9.5/10 (high)
This change's risk is driven by:

  • large diff (many lines added)
  • scattered, high-entropy change
File Score Δ Why
cli_charts/__init__.py 10.0 → 9.1 ▼ -0.9 🔻 introduced nested complexity

💡 cli_charts/__init__.py: Flatten the control flow. Pull early-return guards to the top, extract the deepest branch into a helper, and consider replacing nested conditionals with a strategy table or dispatch dict.

🔥 Hotspots touched (4)
  • cli_charts/demo_engine.py — 1 commits/90d, 1 dependents · primary owner: 2233admin (100%)
  • cli_charts/dashboard.py — 5 commits/90d, 3 dependents · primary owner: 2233admin (100%)
  • cli_charts/cmd/_helpers.py — 6 commits/90d, 42 dependents · primary owner: Curry (83%)
1 more
  • tests/test_style_routing.py — 2 commits/90d, 0 dependents · primary owner: Curry (100%)
🔗 Hidden coupling (3 files)
  • cli_charts/dashboard.py co-changes with these files (not in this PR):
    • cli_charts/chart.py (4× — 🟢 routine)
    • .github/workflows/ci.yml (2× — 🟢 routine)
    • pyproject.toml (2× — 🟢 routine)
  • cli_charts/cmd/_helpers.py co-changes with README.md (2× — 🟢 routine) — not in this PR.
  • cli_charts/__init__.py co-changes with CHANGELOG.md (2× — 🟢 routine) — not in this PR.
💀 Dead code (5 findings)
  • 💀 cli_charts/demo_engine.py render_section (confidence 1.00)
  • 💀 cli_charts/dashboard.py render_sparkline (confidence 1.00)
  • 💀 cli_charts/dashboard.py render_table (confidence 1.00)
2 more
  • 💀 cli_charts/dashboard.py render_metric (confidence 1.00)
  • 💀 cli_charts/dashboard.py render_bar (confidence 1.00)

👀 Suggested reviewers @2233admin @Curry


📊 Full report · ⭐ Star Repowise · 📥 Install bot · Last updated 2026-06-05 04:52 UTC
Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the CLI command dispatching logic by modularizing command-specific handlers and introduces a new serve --stdio worker for processing repeated newline-delimited JSON requests. It also implements lazy version loading in the package initialization. Feedback on the changes suggests fixing a path resolution bug in the lazy version loader of the parser module by importing the version directly from the package. Additionally, improvements are recommended for the stdio server's resilience, specifically handling potential serialization exceptions during response encoding and catching KeyboardInterrupt during request execution to prevent server crashes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread cli_charts/cmd/parser.py
Comment on lines +8 to +34
_VERSION: str | None = None


def _load_version() -> str:
global _VERSION
if _VERSION is not None:
return _VERSION
try:
from pathlib import Path as _Path

_VERSION = (_Path(__file__).parent.parent / "VERSION").read_text(encoding="utf-8").strip()
except Exception:
try:
from importlib.metadata import version as _pkg_version

_VERSION = _pkg_version("glyph-arts")
except Exception:
_VERSION = "unknown"
return _VERSION


class _LazyVersionAction(argparse.Action):
def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, **kwargs):
super().__init__(option_strings=option_strings, dest=dest, nargs=0, default=default, **kwargs)

def __call__(self, parser, namespace, values, option_string=None):
parser.exit(message=f"glyph-arts {_load_version()}\n")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In cli_charts/cmd/parser.py, the _load_version function uses (_Path(__file__).parent.parent / "VERSION") to find the VERSION file. However, since parser.py is located in cli_charts/cmd/, .parent.parent resolves to cli_charts/ rather than the project root directory where the VERSION file actually resides. This causes the file lookup to fail and always fall back to importlib.metadata or "unknown".

Since cli_charts is a lightweight package, we can avoid duplicating the version loading logic entirely and simply import __version__ from cli_charts inside _LazyVersionAction.__call__. This keeps the version loading lazy, fixes the path resolution bug, and simplifies the codebase.

Suggested change
_VERSION: str | None = None
def _load_version() -> str:
global _VERSION
if _VERSION is not None:
return _VERSION
try:
from pathlib import Path as _Path
_VERSION = (_Path(__file__).parent.parent / "VERSION").read_text(encoding="utf-8").strip()
except Exception:
try:
from importlib.metadata import version as _pkg_version
_VERSION = _pkg_version("glyph-arts")
except Exception:
_VERSION = "unknown"
return _VERSION
class _LazyVersionAction(argparse.Action):
def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, **kwargs):
super().__init__(option_strings=option_strings, dest=dest, nargs=0, default=default, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
parser.exit(message=f"glyph-arts {_load_version()}\n")
class _LazyVersionAction(argparse.Action):
def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, **kwargs):
super().__init__(option_strings=option_strings, dest=dest, nargs=0, default=default, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
from cli_charts import __version__
parser.exit(message=f"glyph-arts {__version__}\n")

Comment thread cli_charts/serve_stdio.py
else:
argv, stdin_text = request
response = _run_request(runner, argv, stdin_text)
print(json.dumps(response, ensure_ascii=False), file=output_stream, flush=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the response contains any non-serializable objects or surrogate characters that cannot be encoded, json.dumps will raise an exception. In a persistent, long-running stdio server, an unhandled serialization exception on a single request will crash the entire server process.

Wrapping the serialization and printing in a try...except block ensures that the server remains resilient and can report the serialization error back to the client without crashing.

Suggested change
print(json.dumps(response, ensure_ascii=False), file=output_stream, flush=True)
try:
serialized = json.dumps(response, ensure_ascii=False)
except Exception as exc:
serialized = json.dumps(_error(f"serialization failed: {exc}"), ensure_ascii=False)
print(serialized, file=output_stream, flush=True)

Comment thread cli_charts/serve_stdio.py
Comment on lines +68 to +72
except Exception:
import traceback

traceback.print_exc(file=sys.stderr)
returncode = 4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If a KeyboardInterrupt (e.g., SIGINT / Ctrl+C) is triggered during a request execution, it will propagate out of _run_request and crash the persistent stdio server.

Catching KeyboardInterrupt specifically allows the server to return a proper interrupted status (e.g., exit code 130) and remain alive to process subsequent requests.

            except KeyboardInterrupt:
                returncode = 130
                print("Interrupted", file=sys.stderr)
            except Exception:
                import traceback

                traceback.print_exc(file=sys.stderr)
                returncode = 4

@2233admin
2233admin merged commit 44953ad into master Jun 5, 2026
18 checks passed
@2233admin
2233admin deleted the codex/startup-lazy-load branch June 5, 2026 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant