thoughtleaders-cli 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thoughtleaders_cli-0.5.0.dist-info/METADATA +215 -0
- thoughtleaders_cli-0.5.0.dist-info/RECORD +59 -0
- thoughtleaders_cli-0.5.0.dist-info/WHEEL +4 -0
- thoughtleaders_cli-0.5.0.dist-info/entry_points.txt +2 -0
- thoughtleaders_cli-0.5.0.dist-info/licenses/LICENSE +21 -0
- tl_cli/__init__.py +3 -0
- tl_cli/_completions.py +4 -0
- tl_cli/_plugin/.claude-plugin/marketplace.json +17 -0
- tl_cli/_plugin/.claude-plugin/plugin.json +12 -0
- tl_cli/_plugin/agents/tl-analyst.md +66 -0
- tl_cli/_plugin/commands/tl-balance.md +10 -0
- tl_cli/_plugin/commands/tl-brands.md +16 -0
- tl_cli/_plugin/commands/tl-channels.md +31 -0
- tl_cli/_plugin/commands/tl-reports.md +16 -0
- tl_cli/_plugin/commands/tl-sponsorships.md +23 -0
- tl_cli/_plugin/commands/tl.md +28 -0
- tl_cli/_plugin/hooks/hooks.json +26 -0
- tl_cli/_plugin/hooks/scripts/post-usage.sh +26 -0
- tl_cli/_plugin/hooks/scripts/pre-check.sh +30 -0
- tl_cli/_plugin/skills/tl/SKILL.md +413 -0
- tl_cli/_plugin/skills/tl/references/business-glossary.md +159 -0
- tl_cli/_plugin/skills/tl/references/elasticsearch-schema.md +259 -0
- tl_cli/_plugin/skills/tl/references/firebolt-schema.md +208 -0
- tl_cli/_plugin/skills/tl/references/postgres-schema.md +269 -0
- tl_cli/auth/__init__.py +0 -0
- tl_cli/auth/commands.py +49 -0
- tl_cli/auth/login.py +328 -0
- tl_cli/auth/pkce.py +21 -0
- tl_cli/auth/token_store.py +98 -0
- tl_cli/client/__init__.py +0 -0
- tl_cli/client/errors.py +72 -0
- tl_cli/client/http.py +109 -0
- tl_cli/commands/__init__.py +0 -0
- tl_cli/commands/ask.py +54 -0
- tl_cli/commands/balance.py +68 -0
- tl_cli/commands/brands.py +174 -0
- tl_cli/commands/changelog.py +119 -0
- tl_cli/commands/channels.py +291 -0
- tl_cli/commands/comments.py +63 -0
- tl_cli/commands/db.py +104 -0
- tl_cli/commands/deals.py +52 -0
- tl_cli/commands/describe.py +166 -0
- tl_cli/commands/doctor.py +70 -0
- tl_cli/commands/matches.py +69 -0
- tl_cli/commands/proposals.py +69 -0
- tl_cli/commands/reports.py +346 -0
- tl_cli/commands/schema.py +55 -0
- tl_cli/commands/setup.py +401 -0
- tl_cli/commands/snapshots.py +93 -0
- tl_cli/commands/sponsorships.py +193 -0
- tl_cli/commands/uploads.py +84 -0
- tl_cli/commands/whoami.py +206 -0
- tl_cli/config.py +55 -0
- tl_cli/filters.py +88 -0
- tl_cli/hints.py +53 -0
- tl_cli/main.py +209 -0
- tl_cli/output/__init__.py +0 -0
- tl_cli/output/formatter.py +436 -0
- tl_cli/self_update.py +173 -0
tl_cli/self_update.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Post-command version check and auto-upgrade for pipx/uv installs.
|
|
2
|
+
|
|
3
|
+
Runs once per CLI invocation via atexit. Skipped for dev / pip installs
|
|
4
|
+
(we only know how to upgrade pipx and `uv tool` installations cleanly).
|
|
5
|
+
|
|
6
|
+
Network fetches are cached for 1 hour in ~/.cache/tl-cli/version-check.json,
|
|
7
|
+
so repeated invocations don't hammer the GitHub API.
|
|
8
|
+
|
|
9
|
+
All failure paths are silent — version-check issues must never break the
|
|
10
|
+
user's actual command output.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
import time
|
|
19
|
+
import urllib.error
|
|
20
|
+
import urllib.request
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from tl_cli import __version__
|
|
24
|
+
|
|
25
|
+
CACHE_PATH = Path.home() / ".cache" / "tl-cli" / "version-check.json"
|
|
26
|
+
CACHE_TTL_SECONDS = 3600 # 1 hour
|
|
27
|
+
LATEST_URL = "https://api.github.com/repos/ThoughtLeaders-io/thoughtleaders-cli/releases/latest"
|
|
28
|
+
REQUEST_TIMEOUT = 2 # tight — the user is already waiting to see their shell prompt back
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _detect_install_method() -> str | None:
|
|
32
|
+
"""Return 'pipx', 'uv', or None (dev/pip install — don't auto-upgrade).
|
|
33
|
+
|
|
34
|
+
Both the new distribution name (`thoughtleaders-cli`) and the legacy one
|
|
35
|
+
(`tl-cli`) are matched so users who installed before the rename keep
|
|
36
|
+
auto-updating.
|
|
37
|
+
"""
|
|
38
|
+
exe = sys.executable
|
|
39
|
+
for dist_name in ("thoughtleaders-cli", "tl-cli"):
|
|
40
|
+
if f"/pipx/venvs/{dist_name}/" in exe:
|
|
41
|
+
return "pipx"
|
|
42
|
+
if f"/uv/tools/{dist_name}/" in exe:
|
|
43
|
+
return "uv"
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _read_cache() -> dict | None:
|
|
48
|
+
try:
|
|
49
|
+
cache = json.loads(CACHE_PATH.read_text())
|
|
50
|
+
except (OSError, json.JSONDecodeError):
|
|
51
|
+
return None
|
|
52
|
+
if time.time() - cache.get("checked_at", 0) >= CACHE_TTL_SECONDS:
|
|
53
|
+
return None
|
|
54
|
+
return cache
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _write_cache(latest: str | None) -> None:
|
|
58
|
+
try:
|
|
59
|
+
CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
60
|
+
CACHE_PATH.write_text(json.dumps({"checked_at": time.time(), "latest": latest}))
|
|
61
|
+
except OSError as e:
|
|
62
|
+
print(f"Error writing cache: {e}", file=sys.stderr)
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _fetch_latest_version() -> str | None:
|
|
67
|
+
"""Fetch latest release tag from GitHub. Returns the plain version
|
|
68
|
+
string (e.g. '0.4.2') or None on any failure."""
|
|
69
|
+
try:
|
|
70
|
+
req = urllib.request.Request(
|
|
71
|
+
LATEST_URL,
|
|
72
|
+
headers={
|
|
73
|
+
"Accept": "application/vnd.github+json",
|
|
74
|
+
"User-Agent": f"tl-cli/{__version__}",
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as resp:
|
|
78
|
+
data = json.load(resp)
|
|
79
|
+
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, OSError):
|
|
80
|
+
return None
|
|
81
|
+
tag = (data.get("tag_name") or "").lstrip("v")
|
|
82
|
+
return tag or None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _version_tuple(v: str) -> tuple[int, ...]:
|
|
86
|
+
return tuple(int(p) for p in v.split(".") if p.isdigit())
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
REPO_URL = "https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _run_upgrade(method: str, latest: str) -> None:
|
|
93
|
+
"""Block briefly to run the upgrade. Progress goes to stderr so piped
|
|
94
|
+
stdout stays clean.
|
|
95
|
+
|
|
96
|
+
Uses `install --force` with the new tag URL. pipx/uv pin the original
|
|
97
|
+
install spec including the git tag, so a plain `upgrade` re-installs
|
|
98
|
+
the same version — `--force` is the only way to advance the pinned tag.
|
|
99
|
+
"""
|
|
100
|
+
tagged_url = f"git+{REPO_URL}@v{latest}"
|
|
101
|
+
cmd = {
|
|
102
|
+
"pipx": ["pipx", "install", "--force", tagged_url],
|
|
103
|
+
"uv": ["uv", "tool", "install", "--force", tagged_url],
|
|
104
|
+
}.get(method)
|
|
105
|
+
if not cmd:
|
|
106
|
+
return
|
|
107
|
+
print(
|
|
108
|
+
f"[tl-cli] upgrading {__version__} → {latest} via {method}…",
|
|
109
|
+
file=sys.stderr,
|
|
110
|
+
)
|
|
111
|
+
try:
|
|
112
|
+
subprocess.run(cmd, check=False, timeout=60)
|
|
113
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def check_and_upgrade() -> None:
|
|
118
|
+
"""Entry point. Runs via atexit; silent on every failure path."""
|
|
119
|
+
try:
|
|
120
|
+
method = _detect_install_method()
|
|
121
|
+
if not method:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
cache = _read_cache()
|
|
125
|
+
if cache is None:
|
|
126
|
+
latest = _fetch_latest_version()
|
|
127
|
+
_write_cache(latest)
|
|
128
|
+
else:
|
|
129
|
+
latest = cache.get("latest")
|
|
130
|
+
|
|
131
|
+
if not latest:
|
|
132
|
+
return
|
|
133
|
+
try:
|
|
134
|
+
if _version_tuple(latest) <= _version_tuple(__version__):
|
|
135
|
+
return
|
|
136
|
+
except ValueError:
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
_run_upgrade(method, latest)
|
|
140
|
+
except Exception:
|
|
141
|
+
# Never let a version-check bug break the user's workflow.
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def force_upgrade() -> None:
|
|
146
|
+
"""Explicitly requested upgrade — bypasses cache, prints verbose output."""
|
|
147
|
+
method = _detect_install_method()
|
|
148
|
+
if not method:
|
|
149
|
+
print(
|
|
150
|
+
"tl-cli was not installed via pipx or uv — cannot auto-upgrade.\n"
|
|
151
|
+
"Update it with the same tool you used to install it.",
|
|
152
|
+
file=sys.stderr,
|
|
153
|
+
)
|
|
154
|
+
sys.exit(1)
|
|
155
|
+
|
|
156
|
+
print(f"Checking for updates (current: {__version__})…", file=sys.stderr)
|
|
157
|
+
latest = _fetch_latest_version()
|
|
158
|
+
if latest is None:
|
|
159
|
+
print("Could not reach GitHub to check for updates.", file=sys.stderr)
|
|
160
|
+
sys.exit(1)
|
|
161
|
+
|
|
162
|
+
_write_cache(latest)
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
newer = _version_tuple(latest) > _version_tuple(__version__)
|
|
166
|
+
except ValueError:
|
|
167
|
+
newer = False
|
|
168
|
+
|
|
169
|
+
if not newer:
|
|
170
|
+
print(f"tl-cli {__version__} is already the latest version.", file=sys.stderr)
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
_run_upgrade(method, latest)
|