Skip to content

Commit 636537b

Browse files
tbitcsoz-agent
andcommitted
feat: CLI startup PyPI version check (once per shell session)
- Add _maybe_notify_pypi_update() — checks PyPI on first CLI invocation - Prints one-liner if outdated: 'specsmith X.Y.Z available (you have ...)' - 3-second timeout, never blocks CLI, once per shell session via env var - Skippable with SPECSMITH_NO_AUTO_UPDATE=1 Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 1620a4b commit 636537b

3 files changed

Lines changed: 45 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"role":"error","text":"[Apr 9, 09:18:43 AM] Agent process ended (exit code 1) — send a message to restart","ts":"2026-04-09T13:18:43.464Z"}
2+
{"role":"error","text":"specsmith not responding (tried: \"C:\\Users\\trist\\.specsmith\\venv\\Scripts\\specsmith.exe\")\nTo fix:\n • Ctrl+Shift+P → specsmith: Install or Upgrade\n • Or set specsmith.executablePath in VS Code settings\n • On Windows / pip install path:\n %LOCALAPPDATA%\\Python\\pythoncore-3.12-64\\Scripts\\specsmith.exe","ts":"2026-04-09T13:19:02.885Z"}

scaffold.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ platforms:
66
- linux
77
- macos
88
spec_version: 0.3.6
9+
aee_phase: inception
910
description: Applied Epistemic Engineering toolkit for AI-assisted development.
1011
vcs_platform: github
1112
branching_strategy: gitflow

src/specsmith/cli.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def invoke(self, ctx: click.Context) -> object:
6464

6565
if not skip:
6666
_maybe_prompt_project_update()
67+
_maybe_notify_pypi_update()
6768

6869
return super().invoke(ctx)
6970

@@ -125,6 +126,47 @@ def _maybe_prompt_project_update() -> None:
125126
pass # Never break the actual command on version check errors
126127

127128

129+
def _maybe_notify_pypi_update() -> None:
130+
"""Check PyPI for a newer specsmith version. Prints one-liner if outdated.
131+
132+
Runs at most once per shell session (tracked via env var). Uses a 3-second
133+
timeout to avoid blocking the CLI. Only checks stable versions.
134+
"""
135+
import os
136+
137+
session_key = "SPECSMITH_PYPI_CHECKED"
138+
if os.environ.get(session_key):
139+
return
140+
os.environ[session_key] = "1"
141+
142+
try:
143+
import json as _json # noqa: PLC0415
144+
from urllib.request import urlopen # noqa: PLC0415
145+
146+
resp = urlopen("https://pypi.org/pypi/specsmith/json", timeout=3) # noqa: S310
147+
data = _json.loads(resp.read())
148+
latest = data.get("info", {}).get("version", "")
149+
if not latest:
150+
return
151+
152+
# Simple version comparison: split into tuples of ints
153+
def _ver(v: str) -> tuple[int, ...]:
154+
import re
155+
156+
clean = re.match(r"(\d+\.\d+\.\d+)", v)
157+
return tuple(int(x) for x in clean.group(1).split(".")) if clean else (0,)
158+
159+
if _ver(latest) > _ver(__version__):
160+
console.print(
161+
f" [dim]specsmith [bold]{latest}[/bold] available "
162+
f"(you have {__version__}). "
163+
f"Run [bold]specsmith self-update[/bold] or "
164+
f"[bold]pipx upgrade specsmith[/bold].[/dim]"
165+
)
166+
except Exception: # noqa: BLE001
167+
pass # Never block the CLI on network errors
168+
169+
128170
@click.group(cls=_AutoUpdateGroup)
129171
@click.version_option(version=__version__, prog_name="specsmith")
130172
def main() -> None:

0 commit comments

Comments
 (0)