thoughtleaders-cli 0.6.28__tar.gz → 0.6.31__tar.gz
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.6.28 → thoughtleaders_cli-0.6.31}/.claude-plugin/plugin.json +1 -1
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/PKG-INFO +1 -1
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/pyproject.toml +1 -1
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/SKILL.md +1 -2
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/business-glossary.md +1 -1
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/__init__.py +1 -1
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/self_update.py +176 -11
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/.claude-plugin/marketplace.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/.github/workflows/python-publish.yml +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/.gitignore +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/AGENTS.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/CLAUDE.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/LICENSE +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/README.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/agents/tl-analyst.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/commands/tl-balance.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/commands/tl-reports.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/commands/tl-sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/commands/tl.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/docs/architecture.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/hooks/hooks.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/hooks/scripts/post-usage.sh +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/hooks/scripts/pre-check.sh +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/elasticsearch-schema.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/firebolt-schema.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/postgres-schema.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-import/SKILL.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/SKILL.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/examples/golden_queries.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/columns_brands.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/columns_channels.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/columns_content.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/report_glossary.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/sortable_columns.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/references/widgets.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/column_builder.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/database_query.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/keyword_research.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/name_resolver.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/sample_judge.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/similar_channels.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl-report-builder/tools/widget_builder.md +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/_completions.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/__init__.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/commands.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/finalize.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/login.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/pkce.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/auth/token_store.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/client/__init__.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/client/errors.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/client/http.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/__init__.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/_comments_common.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/ask.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/balance.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/brands.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/bulk_import.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/changelog.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/channels.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/credits.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/db.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/deals.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/describe.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/doctor.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/matches.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/proposals.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/recommender.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/reports.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/schema.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/setup.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/snapshots.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/uploads.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/whoami.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/config.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/filters.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/hints.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/main.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/output/__init__.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/output/formatter.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/__init__.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/test_auth.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/test_filters.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/test_output.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/test_reports.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/tests/test_sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: thoughtleaders-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.31
|
|
4
4
|
Summary: ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence
|
|
5
5
|
Project-URL: Homepage, https://thoughtleaders.io
|
|
6
6
|
Project-URL: Repository, https://github.com/ThoughtLeaders-io/thoughtleaders-cli
|
|
@@ -318,7 +318,7 @@ Always load the [references/business-glossary.md](references/business-glossary.m
|
|
|
318
318
|
|
|
319
319
|
### Key business concepts
|
|
320
320
|
|
|
321
|
-
See [references/business-glossary.md](references/business-glossary.md) for revenue/pipeline definitions, performance grades, ownership fields, MSN/TPP, and team rosters.
|
|
321
|
+
See [references/business-glossary.md](references/business-glossary.md) for revenue/pipeline definitions, performance grades, ownership fields, channel quality and availability, MSN/TPP, and team rosters.
|
|
322
322
|
|
|
323
323
|
### Limitations of the `tl`-only data path
|
|
324
324
|
|
|
@@ -522,4 +522,3 @@ tl recommender inspect-brand Nike # Per-tag breakdo
|
|
|
522
522
|
tl recommender similar-to-profile 842 --limit 30 # Channels closest to a brand profile's ideal profile
|
|
523
523
|
```
|
|
524
524
|
Use `tl recommender top` for category/topic discovery (it's ranked) and `tl channels similar` / `tl brands similar` for 1:1 lookalike searches.
|
|
525
|
-
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/business-glossary.md
RENAMED
|
@@ -18,6 +18,7 @@ Maps business terms to database concepts.
|
|
|
18
18
|
| **Weighted pipeline** | `SUM(weighted_price)` for open opps | Pre-calculated on save |
|
|
19
19
|
| **Ad is live** | `publish_date IS NOT NULL` | Until publish_date is set, ad is not on YouTube |
|
|
20
20
|
| **Cancellation risk** | Sold but `publish_date IS NULL` | Sold deals without publish_date can still be canceled |
|
|
21
|
+
| **Immediately bookable** | `is_tl_channel = true` | TPP channels are immediately bookable |
|
|
21
22
|
|
|
22
23
|
## Performance Grade (`adlink.performance_grade`)
|
|
23
24
|
|
|
@@ -240,4 +241,3 @@ WHERE al.owner_publisher_id IN (218, 5710, 873, 9011, 11361)
|
|
|
240
241
|
SELECT ... FROM thoughtleaders_profile p
|
|
241
242
|
WHERE p.owner_publisher_id IN (71, 9274, 18159, 5799, 5804, 10743, 11592)
|
|
242
243
|
```
|
|
243
|
-
|
|
@@ -23,10 +23,12 @@ from pathlib import Path
|
|
|
23
23
|
|
|
24
24
|
from tl_cli import __version__
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
CACHE_DIR = Path.home() / ".cache" / "tl-cli"
|
|
27
|
+
CACHE_PATH = CACHE_DIR / "version-check.json"
|
|
27
28
|
CACHE_TTL_SECONDS = 3600 # 1 hour
|
|
28
29
|
LATEST_URL = "https://api.github.com/repos/ThoughtLeaders-io/thoughtleaders-cli/releases/latest"
|
|
29
30
|
REQUEST_TIMEOUT = 2 # tight — the user is already waiting to see their shell prompt back
|
|
31
|
+
WIN_UPGRADE_RESCHEDULE_WINDOW = 600 # 10 minutes: don't re-schedule a background upgrade we already queued
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
def _detect_install_method() -> str | None:
|
|
@@ -92,17 +94,24 @@ REPO_URL = "https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git"
|
|
|
92
94
|
|
|
93
95
|
|
|
94
96
|
def _run_upgrade(method: str, latest: str) -> None:
|
|
95
|
-
"""
|
|
96
|
-
stdout stays clean.
|
|
97
|
+
"""Run the upgrade. Progress goes to stderr so piped stdout stays clean.
|
|
97
98
|
|
|
98
99
|
Uses `install --force` with the new tag URL. pipx/uv pin the original
|
|
99
100
|
install spec including the git tag, so a plain `upgrade` re-installs
|
|
100
101
|
the same version — `--force` is the only way to advance the pinned tag.
|
|
101
102
|
|
|
102
|
-
On
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
On Windows the running tl.exe holds an exclusive lock on its own file,
|
|
104
|
+
so pipx/uv can never replace it in-process — every attempt fails with
|
|
105
|
+
WinError 32 and leaves ``~``-prefixed orphan dirs in site-packages
|
|
106
|
+
that wedge the next launch with ``ModuleNotFoundError: No module
|
|
107
|
+
named 'tl_cli'``. The Windows path spawns a detached helper instead
|
|
108
|
+
that waits for our PID to exit and then runs the upgrade.
|
|
109
|
+
|
|
110
|
+
On a successful upgrade (POSIX inline path, or the detached helper),
|
|
111
|
+
Claude Code and OpenCode skills are re-synced if their binaries are
|
|
112
|
+
on PATH, so the new version's skills land in ~/.claude/ and
|
|
113
|
+
~/.config/opencode/ without the user having to remember to run
|
|
114
|
+
`tl setup ...`.
|
|
106
115
|
"""
|
|
107
116
|
tagged_url = f"git+{REPO_URL}@v{latest}"
|
|
108
117
|
cmd = {
|
|
@@ -111,14 +120,25 @@ def _run_upgrade(method: str, latest: str) -> None:
|
|
|
111
120
|
}.get(method)
|
|
112
121
|
if not cmd:
|
|
113
122
|
return
|
|
123
|
+
|
|
124
|
+
if sys.platform == "win32":
|
|
125
|
+
if _spawn_detached_windows_upgrade(cmd, latest):
|
|
126
|
+
print(
|
|
127
|
+
f"[tl-cli] upgrade {__version__} → {latest} scheduled "
|
|
128
|
+
f"(runs after this command exits; log: "
|
|
129
|
+
f"{CACHE_DIR / f'upgrade-{latest}.log'})",
|
|
130
|
+
file=sys.stderr,
|
|
131
|
+
)
|
|
132
|
+
_mark_upgrade_scheduled(latest)
|
|
133
|
+
return
|
|
134
|
+
|
|
114
135
|
print(
|
|
115
136
|
f"[tl-cli] upgrading {__version__} → {latest} via {method}…",
|
|
116
137
|
file=sys.stderr,
|
|
117
138
|
)
|
|
118
|
-
# Capture output so a noisy traceback from a broken upgrader
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# alongside an actionable next-step message.
|
|
139
|
+
# Capture output so a noisy traceback from a broken upgrader doesn't
|
|
140
|
+
# get dumped into the user's shell — we surface it deliberately on
|
|
141
|
+
# failure alongside an actionable next-step message.
|
|
122
142
|
try:
|
|
123
143
|
result = subprocess.run(cmd, check=False, timeout=60, capture_output=True, text=True)
|
|
124
144
|
except (OSError, subprocess.TimeoutExpired) as exc:
|
|
@@ -134,6 +154,146 @@ def _run_upgrade(method: str, latest: str) -> None:
|
|
|
134
154
|
_report_upgrade_failure(method, cmd, result)
|
|
135
155
|
|
|
136
156
|
|
|
157
|
+
def _spawn_detached_windows_upgrade(cmd: list[str], latest: str) -> bool:
|
|
158
|
+
"""Schedule the upgrade to run after this process exits.
|
|
159
|
+
|
|
160
|
+
Writes a small .cmd helper that polls until our PID disappears and
|
|
161
|
+
then runs the upgrader. Spawned with CREATE_NO_WINDOW |
|
|
162
|
+
CREATE_BREAKAWAY_FROM_JOB so it survives this process and any
|
|
163
|
+
job-object-owned shell that launched us. Output is appended to a
|
|
164
|
+
log file under ~/.cache/tl-cli/ so the user can diagnose failures
|
|
165
|
+
after their shell prompt returns.
|
|
166
|
+
|
|
167
|
+
Returns True on successful schedule. Idempotent against repeated
|
|
168
|
+
invocations: see `_already_scheduled`.
|
|
169
|
+
"""
|
|
170
|
+
import os
|
|
171
|
+
|
|
172
|
+
try:
|
|
173
|
+
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
174
|
+
except OSError as exc:
|
|
175
|
+
print(
|
|
176
|
+
f"[tl-cli] could not create cache dir for upgrade helper: {exc}",
|
|
177
|
+
file=sys.stderr,
|
|
178
|
+
)
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
log_path = CACHE_DIR / f"upgrade-{latest}.log"
|
|
182
|
+
script_path = CACHE_DIR / f"upgrade-{latest}.cmd"
|
|
183
|
+
# Per-helper temp file for tasklist output (a pipe would die; see below).
|
|
184
|
+
tmp_path = CACHE_DIR / f"upgrade-{latest}.tasklist.tmp"
|
|
185
|
+
|
|
186
|
+
parent_pid = os.getpid()
|
|
187
|
+
quoted_cmd = " ".join(f'"{a}"' for a in cmd)
|
|
188
|
+
|
|
189
|
+
# CRLF line endings + cmd.exe-safe quoting.
|
|
190
|
+
#
|
|
191
|
+
# We deliberately avoid the pipe-based idiom `tasklist | findstr`: a
|
|
192
|
+
# detached cmd.exe (CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB) has
|
|
193
|
+
# no console for the pipe sub-shells to attach to, and they exit
|
|
194
|
+
# silently the moment the helper hits a `|`. Routing through a temp
|
|
195
|
+
# file keeps every command as a plain redirected child.
|
|
196
|
+
script = (
|
|
197
|
+
"@echo off\r\n"
|
|
198
|
+
f'echo [tl-cli upgrader] waiting for parent PID {parent_pid} to exit > "{log_path}"\r\n'
|
|
199
|
+
":wait\r\n"
|
|
200
|
+
f'tasklist /FI "PID eq {parent_pid}" /NH 2>NUL > "{tmp_path}"\r\n'
|
|
201
|
+
f'findstr /C:"{parent_pid}" "{tmp_path}" >NUL\r\n'
|
|
202
|
+
"if not errorlevel 1 (\r\n"
|
|
203
|
+
" ping -n 2 127.0.0.1 >NUL\r\n"
|
|
204
|
+
" goto wait\r\n"
|
|
205
|
+
")\r\n"
|
|
206
|
+
f'del "{tmp_path}" 2>NUL\r\n'
|
|
207
|
+
f'echo [tl-cli upgrader] running: {quoted_cmd} >> "{log_path}"\r\n'
|
|
208
|
+
f'{quoted_cmd} >> "{log_path}" 2>&1\r\n'
|
|
209
|
+
"set RC=%ERRORLEVEL%\r\n"
|
|
210
|
+
f'echo [tl-cli upgrader] exit code %RC% >> "{log_path}"\r\n'
|
|
211
|
+
"if not %RC%==0 goto end\r\n"
|
|
212
|
+
"where claude >NUL 2>&1\r\n"
|
|
213
|
+
"if not errorlevel 1 (\r\n"
|
|
214
|
+
f' echo [tl-cli upgrader] re-syncing claude skills >> "{log_path}"\r\n'
|
|
215
|
+
f' tl setup claude --json >> "{log_path}" 2>&1\r\n'
|
|
216
|
+
")\r\n"
|
|
217
|
+
"where opencode >NUL 2>&1\r\n"
|
|
218
|
+
"if not errorlevel 1 (\r\n"
|
|
219
|
+
f' echo [tl-cli upgrader] re-syncing opencode skills >> "{log_path}"\r\n'
|
|
220
|
+
f' tl setup opencode --json >> "{log_path}" 2>&1\r\n'
|
|
221
|
+
")\r\n"
|
|
222
|
+
":end\r\n"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
script_path.write_text(script)
|
|
227
|
+
except OSError as exc:
|
|
228
|
+
print(f"[tl-cli] could not write upgrade helper: {exc}", file=sys.stderr)
|
|
229
|
+
return False
|
|
230
|
+
|
|
231
|
+
# creationflags constants — repeated here rather than referenced from
|
|
232
|
+
# subprocess.* so this works on Python builds where the symbols are
|
|
233
|
+
# guarded behind sys.platform checks.
|
|
234
|
+
#
|
|
235
|
+
# CREATE_NO_WINDOW (not DETACHED_PROCESS): a fully-detached cmd.exe
|
|
236
|
+
# has no console for spawned child commands to inherit, which breaks
|
|
237
|
+
# piped sub-shells and a few utilities that try to query the console.
|
|
238
|
+
# CREATE_NO_WINDOW gives us "no visible window" while keeping the
|
|
239
|
+
# console subsystem available for children.
|
|
240
|
+
CREATE_NEW_PROCESS_GROUP = 0x00000200
|
|
241
|
+
CREATE_BREAKAWAY_FROM_JOB = 0x01000000
|
|
242
|
+
CREATE_NO_WINDOW = 0x08000000
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
subprocess.Popen(
|
|
246
|
+
["cmd.exe", "/c", str(script_path)],
|
|
247
|
+
creationflags=(
|
|
248
|
+
CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB
|
|
249
|
+
),
|
|
250
|
+
stdin=subprocess.DEVNULL,
|
|
251
|
+
stdout=subprocess.DEVNULL,
|
|
252
|
+
stderr=subprocess.DEVNULL,
|
|
253
|
+
close_fds=True,
|
|
254
|
+
cwd=str(CACHE_DIR),
|
|
255
|
+
)
|
|
256
|
+
except OSError as exc:
|
|
257
|
+
print(
|
|
258
|
+
f"[tl-cli] could not schedule background upgrade: {exc}\n"
|
|
259
|
+
f"[tl-cli] upgrade manually with:\n {quoted_cmd}",
|
|
260
|
+
file=sys.stderr,
|
|
261
|
+
)
|
|
262
|
+
return False
|
|
263
|
+
return True
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _mark_upgrade_scheduled(latest: str) -> None:
|
|
267
|
+
"""Record in the version-check cache that we've queued a background
|
|
268
|
+
upgrade for ``latest`` so subsequent invocations don't re-schedule
|
|
269
|
+
while the first helper is still pending."""
|
|
270
|
+
try:
|
|
271
|
+
cache = json.loads(CACHE_PATH.read_text())
|
|
272
|
+
except (OSError, json.JSONDecodeError):
|
|
273
|
+
cache = {}
|
|
274
|
+
cache["scheduled_at"] = time.time()
|
|
275
|
+
cache["scheduled_for"] = latest
|
|
276
|
+
try:
|
|
277
|
+
CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
278
|
+
CACHE_PATH.write_text(json.dumps(cache))
|
|
279
|
+
except OSError:
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _already_scheduled(latest: str) -> bool:
|
|
284
|
+
"""True if we recently queued the same upgrade — caller should skip."""
|
|
285
|
+
try:
|
|
286
|
+
cache = json.loads(CACHE_PATH.read_text())
|
|
287
|
+
except (OSError, json.JSONDecodeError):
|
|
288
|
+
return False
|
|
289
|
+
if cache.get("scheduled_for") != latest:
|
|
290
|
+
return False
|
|
291
|
+
scheduled_at = cache.get("scheduled_at")
|
|
292
|
+
if not isinstance(scheduled_at, (int, float)):
|
|
293
|
+
return False
|
|
294
|
+
return time.time() - scheduled_at < WIN_UPGRADE_RESCHEDULE_WINDOW
|
|
295
|
+
|
|
296
|
+
|
|
137
297
|
def _report_upgrade_failure(method: str, cmd: list[str], result: subprocess.CompletedProcess) -> None:
|
|
138
298
|
"""Print a user-friendly failure message after a non-zero upgrader exit.
|
|
139
299
|
|
|
@@ -215,6 +375,11 @@ def check_and_upgrade() -> None:
|
|
|
215
375
|
except ValueError:
|
|
216
376
|
return
|
|
217
377
|
|
|
378
|
+
# On Windows the upgrade is detached: don't re-queue it on every
|
|
379
|
+
# subsequent tl invocation while the first helper is still pending.
|
|
380
|
+
if sys.platform == "win32" and _already_scheduled(latest):
|
|
381
|
+
return
|
|
382
|
+
|
|
218
383
|
_run_upgrade(method, latest)
|
|
219
384
|
except Exception:
|
|
220
385
|
# Never let a version-check bug break the user's workflow.
|
|
File without changes
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/.github/workflows/python-publish.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/elasticsearch-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/firebolt-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/skills/tl/references/postgres-schema.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{thoughtleaders_cli-0.6.28 → thoughtleaders_cli-0.6.31}/src/tl_cli/commands/_comments_common.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|