From 27b451b8a42850b9c14cf09e4b5f5c99f64eead1 Mon Sep 17 00:00:00 2001 From: Capital Mischief Date: Wed, 19 Aug 2026 08:06:46 -0400 Subject: [PATCH] fix: replace Python shebang with bash wrapper for venv-safe invocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bare #!/usr/bin/env python3 shebang breaks when the system Python upgrades (e.g. Homebrew 3.9 → 3.13) and pip packages like typer/httpx are stranded in the old site-packages. Replace with a bash wrapper (matching ga-cli's pattern) that: - resolves symlinks before computing DIR - finds a .venv at repo-root or skill-root - falls back to system Python only if no venv exists - adds __main__.py so the package works with python -m substack_cli --- skills/substack/scripts/substack | 39 +++++++++++-------- .../substack/scripts/substack_cli/__main__.py | 11 ++++++ 2 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 skills/substack/scripts/substack_cli/__main__.py diff --git a/skills/substack/scripts/substack b/skills/substack/scripts/substack index bb27cb1..ca7aec3 100755 --- a/skills/substack/scripts/substack +++ b/skills/substack/scripts/substack @@ -1,20 +1,25 @@ -#!/usr/bin/env python3 -"""substack — Substack CLI (unofficial API wrapper)""" -import sys -import os +#!/usr/bin/env bash +# substack — Substack CLI (unofficial API wrapper) +# Runs the substack_cli package from a venv adjacent to this script. +set -euo pipefail -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +# Resolve symlinks so venv-relative paths work when called via a symlink. +SELF="$0" +while [ -L "$SELF" ]; do + LINK="$(readlink "$SELF")" + case "$LINK" in /*) SELF="$LINK" ;; *) SELF="$(dirname "$SELF")/$LINK" ;; esac +done +DIR="$(cd "$(dirname "$SELF")" && pwd)" -# Import command modules FIRST so their @app.command() / @x_app.command() -# decorators register before main() invokes the Typer app. -from substack_cli import config as _config # noqa: E402, F401 -from substack_cli import read as _read # noqa: E402, F401 -from substack_cli import publish as _publish # noqa: E402, F401 -from substack_cli import manage as _manage # noqa: E402, F401 -from substack_cli import notes as _notes # noqa: E402, F401 -from substack_cli import chat as _chat # noqa: E402, F401 +# Prefer a venv at $DIR/../../../.venv (repo root) or $DIR/../.venv (skill root), +# falling back to the system Python if neither exists. +if [ -x "$DIR/../../../.venv/bin/python" ]; then + PYTHON="$DIR/../../../.venv/bin/python" +elif [ -x "$DIR/../.venv/bin/python" ]; then + PYTHON="$DIR/../.venv/bin/python" +else + PYTHON="$(command -v python3 || command -v python)" +fi -from substack_cli.app import main # noqa: E402 - -if __name__ == "__main__": - main() \ No newline at end of file +export PYTHONPATH="$DIR${PYTHONPATH:+:$PYTHONPATH}" +exec "$PYTHON" -m substack_cli "$@" diff --git a/skills/substack/scripts/substack_cli/__main__.py b/skills/substack/scripts/substack_cli/__main__.py new file mode 100644 index 0000000..d60721d --- /dev/null +++ b/skills/substack/scripts/substack_cli/__main__.py @@ -0,0 +1,11 @@ +"""Allow `python -m substack_cli` invocation.""" +from substack_cli import config as _config # noqa: F401 +from substack_cli import read as _read # noqa: F401 +from substack_cli import publish as _publish # noqa: F401 +from substack_cli import manage as _manage # noqa: F401 +from substack_cli import notes as _notes # noqa: F401 +from substack_cli import chat as _chat # noqa: F401 + +from substack_cli.app import main + +main()