thoughtleaders-cli 0.6.16__tar.gz → 0.6.18__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.16 → thoughtleaders_cli-0.6.18}/.claude-plugin/plugin.json +1 -1
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/PKG-INFO +1 -1
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/pyproject.toml +1 -1
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/SKILL.md +54 -5
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/report_glossary.md +2 -1
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/__init__.py +1 -1
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/self_update.py +40 -2
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/.claude-plugin/marketplace.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/.github/workflows/python-publish.yml +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/.gitignore +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/AGENTS.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/CLAUDE.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/LICENSE +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/README.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/agents/tl-analyst.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/commands/tl-balance.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/commands/tl-reports.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/commands/tl-sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/commands/tl.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/docs/architecture.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/hooks/hooks.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/hooks/scripts/post-usage.sh +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/hooks/scripts/pre-check.sh +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/SKILL.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/business-glossary.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/elasticsearch-schema.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/firebolt-schema.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/postgres-schema.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/examples/golden_queries.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/columns_brands.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/columns_channels.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/columns_content.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/sortable_columns.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/references/widgets.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/column_builder.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/database_query.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/keyword_research.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/name_resolver.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/sample_judge.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/similar_channels.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl-report-builder/tools/widget_builder.md +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/_completions.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/auth/__init__.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/auth/commands.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/auth/login.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/auth/pkce.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/auth/token_store.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/client/__init__.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/client/errors.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/client/http.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/__init__.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/_comments_common.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/ask.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/balance.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/brands.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/changelog.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/channels.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/db.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/deals.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/describe.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/doctor.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/matches.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/proposals.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/recommender.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/reports.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/schema.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/setup.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/snapshots.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/uploads.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/commands/whoami.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/config.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/filters.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/hints.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/main.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/output/__init__.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/src/tl_cli/output/formatter.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/__init__.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/test_auth.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/test_filters.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/test_output.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/test_reports.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/tests/test_sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/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.18
|
|
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
|
|
@@ -314,13 +314,13 @@ There is no fifth phase. Phase 4's output IS the deliverable. The skill itself n
|
|
|
314
314
|
> 1. **Write the JSON to `/tmp/`** via the `Write` tool. The path **MUST** be under the system temp directory (`/tmp/` on Linux/macOS, `%TEMP%` / `$TMPDIR` on whatever platform the agent is running on). Use a name like `/tmp/tl-report-builder-<short-slug>.json`. **Never write to the user's current working directory or any project path** — the file is a transport, not a deliverable, and leaving `foo_report.json` in the user's repo or cwd pollutes their workspace. If the system temp dir isn't writable, fall back to another temp-shaped location, never to cwd.
|
|
315
315
|
> 2. **Invoke `tl reports create --config-file <that-same-tmp-path> --yes`** via the `Bash` tool. This is what actually saves the report. Read the CLI's response: success returns a `campaign_id` and `report_url` to echo to the user; failure returns a non-zero exit and an error message — surface that error verbatim, do NOT silently mark the report as saved.
|
|
316
316
|
>
|
|
317
|
-
> **Preview mechanics** (default): show takeaways
|
|
317
|
+
> **Preview mechanics** (default): show **the sample-rows table FIRST**, then takeaways, then the closing "say save" tail. The table is the deliverable in preview mode — takeaways describe it, but the table itself is what the user asked for. **Skipping the table is a regression bug** (Phase 4 hard rule 14). Use the `db_sample` rows Phase 2 already collected (top 5–10 by sort key) and format as a tight Markdown table with 2–4 type-relevant columns:
|
|
318
318
|
> - Type 3 (channels): `Channel | Subscribers | Last published`
|
|
319
319
|
> - Type 1 (videos/uploads): `Title | Channel | Views | Date`
|
|
320
320
|
> - Type 2 (brands): `Brand | Mentions | Channels`
|
|
321
321
|
> - Type 8 (deals/sponsorships): `Channel | Brand | Status | Send date`
|
|
322
322
|
>
|
|
323
|
-
>
|
|
323
|
+
> After the table, give 2–4 takeaways (count, niche fit, noise warnings, sort note). Then close with a one-liner: *"If you want this saved as a campaign you can come back to, say save."* (Skip the closing line only when the user's prompt was clearly purely informational like "are there any …".)
|
|
324
324
|
>
|
|
325
325
|
> **The JSON config never appears in chat in either path.** In save mode it's in the `/tmp/` file; in preview mode it stays in working memory. JSON in chat is implementation noise and a regression we already shipped a fix for once.
|
|
326
326
|
>
|
|
@@ -1026,10 +1026,10 @@ Date filter required (per Phase 2 edge-case rule — type-8 without dates is rej
|
|
|
1026
1026
|
|
|
1027
1027
|
#### Postgres CTE fallback (smoke-check only)
|
|
1028
1028
|
|
|
1029
|
-
If ES is unavailable for an intelligence-report validation AND the FilterSet has tight indexed predicates (reach floor + narrow language + small keyword set), the PG smoke-check uses the CTE pattern:
|
|
1029
|
+
If ES is unavailable for an intelligence-report validation AND the FilterSet has tight indexed predicates (reach floor + narrow language + small keyword set), the PG smoke-check uses the CTE pattern with **`AS MATERIALIZED`** (this is mandatory — Postgres 12+ inlines CTEs by default, which collapses the pattern back into a flat WHERE that the sandbox planner rejects):
|
|
1030
1030
|
|
|
1031
1031
|
```sql
|
|
1032
|
-
WITH filtered AS (
|
|
1032
|
+
WITH filtered AS MATERIALIZED (
|
|
1033
1033
|
SELECT id, channel_name, description, reach
|
|
1034
1034
|
FROM thoughtleaders_channel
|
|
1035
1035
|
WHERE is_active = TRUE
|
|
@@ -1040,7 +1040,42 @@ WHERE <keyword ILIKE predicate>
|
|
|
1040
1040
|
LIMIT 1 OFFSET 0
|
|
1041
1041
|
```
|
|
1042
1042
|
|
|
1043
|
-
|
|
1043
|
+
`MATERIALIZED` forces the CTE to evaluate first as an optimization fence; the outer ILIKE then runs on the small pre-filtered set instead of a flattened plan over the full table.
|
|
1044
|
+
|
|
1045
|
+
**Do NOT use `ILIKE ANY(ARRAY[...])` in the outer SELECT.** Postgres can't index-optimize array-element ILIKE — it expands to a sequential scan with N ILIKE comparisons per row. Use explicit `OR`-chains, or better yet skip PG entirely for keyword work (next section).
|
|
1046
|
+
|
|
1047
|
+
This pattern works only with substantial pre-filter pruning (≤ a few thousand rows after the indexed predicates). **Don't use the CTE smoke-check as the production validation path** — its limits (timeouts on broad predicates, substring noise from ILIKE, planner rejection on wide keyword sets) are real and surfaced in the e2e findings. ES is the right tool.
|
|
1048
|
+
|
|
1049
|
+
#### "Known ID set + keyword filter" pattern
|
|
1050
|
+
|
|
1051
|
+
A common case: the FilterSet pins a small ID set in `channels: [...]` (TPP, similar-to-channels, cross-references) AND has keyword filters. When this happens, **don't try to do everything in PG** — the combination of `id IN (long list)` + multi-keyword ILIKE blows past the sandbox cost cap (this regression has been observed in the wild for TPP + niche-keyword queries).
|
|
1052
|
+
|
|
1053
|
+
The correct shape is two queries on two engines:
|
|
1054
|
+
|
|
1055
|
+
1. **PG** (already done if the IDs came from a previous resolution step): just have the ID list.
|
|
1056
|
+
2. **ES** (validation count + sample): use a `terms` filter on `id` to scope to the pinned set, combined with the standard intelligence-report `match_phrase` queries for keywords. ES handles keyword matching with proper indexes; passing the IDs as a filter sidesteps the missing `is_tl_channel` (or whatever scoping field) on the ES side.
|
|
1057
|
+
|
|
1058
|
+
```json
|
|
1059
|
+
{
|
|
1060
|
+
"query": {
|
|
1061
|
+
"bool": {
|
|
1062
|
+
"filter": [
|
|
1063
|
+
{ "terms": { "id": [549, 1629, 2314, ...] } },
|
|
1064
|
+
{ "term": { "is_active": true } },
|
|
1065
|
+
{ "range": { "reach": { "gte": 100000 } } }
|
|
1066
|
+
],
|
|
1067
|
+
"should": [
|
|
1068
|
+
{ "match_phrase": { "description": "motorcycle" } },
|
|
1069
|
+
{ "match_phrase": { "channel_topic_description": "drone footage" } },
|
|
1070
|
+
...
|
|
1071
|
+
],
|
|
1072
|
+
"minimum_should_match": 1
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
This works whether or not ES has a `is_tl_channel`-like field — the resolved IDs are the scoping mechanism. **If you find yourself building a PG query with `id IN (long-list)` AND ILIKE keyword predicates, stop and switch to this pattern instead.**
|
|
1044
1079
|
|
|
1045
1080
|
### Step 2.V2 — Run the count query (with timeout / fallback handling)
|
|
1046
1081
|
|
|
@@ -1377,6 +1412,20 @@ Pseudo-shape (not runnable JSON — `<int>`, `|`-unions, and `/* notes */` are p
|
|
|
1377
1412
|
11. **Writing the file is NOT saving the report.** The save happens when `tl reports create --config-file <path> --yes` returns success. Until that command's exit code is read, the report does not exist. **Never tell the user "saved as <path>.json"** — that confuses the transport file (which is throwaway) with the saved Campaign (which is what they asked for). The save-success message must come from the CLI response: a `campaign_id` and `report_url`.
|
|
1378
1413
|
12. **Default to preview, not save.** Phases 1–4 always run, but the chat output is takeaways + a sample-rows table by default. **Only save when the user's prompt contains explicit save intent** — see the Save-or-preview policy near the top for the trigger word lists. Ambiguous middle ("build a report on X", "create a campaign for Y") → preview + the closing "say save" tail. Save is the explicit, opt-in path; preview is the conservative default.
|
|
1379
1414
|
13. **In preview mode the agent does not invoke `tl reports create`** and does not write a temp file. The campaign config stays in working memory. If the user follows up with "save" / "yes" / "go ahead", re-use that same in-memory config — do not re-run Phases 1–4.
|
|
1415
|
+
14. **Preview output MUST include a sample-rows table.** Use the `db_sample` rows Phase 2 already collected (top 5–10 by sort key) and render them as a tight Markdown table with type-specific columns per the Save-or-preview policy:
|
|
1416
|
+
- Type 3 (channels): `Channel | Subscribers | Last published`
|
|
1417
|
+
- Type 1 (videos/uploads): `Title | Channel | Views | Date`
|
|
1418
|
+
- Type 2 (brands): `Brand | Mentions | Channels`
|
|
1419
|
+
- Type 8 (deals/sponsorships): `Channel | Brand | Status | Send date`
|
|
1420
|
+
**Takeaways alone are not a preview** — the user asked for results; takeaways describe the result, the table IS the result. Skipping the sample table because the result feels narrow, or because the prompt felt "report-y", is a regression bug. The table comes from data Phase 2 already pulled; it costs nothing extra to render.
|
|
1421
|
+
15. **When save intent is detected, the agent MUST invoke `tl reports create` itself.** Telling the user "Save it via POST to the report-creation API endpoint when ready" or "to save, run `tl reports create --config '<json>'`" or any other form of "you save it yourself" is a regression bug — that's the obsolete pre-v0.6.12 fallback. If the prompt contains any save-intent word (see Save-or-preview policy: "save", "create the report", "create a campaign", "make a campaign for me to come back to", "publish", "persist") the flow is: write to `/tmp/<slug>.json` with the `Write` tool → run `tl reports create --config-file /tmp/<slug>.json --yes` with `Bash` → echo the campaign_id + report_url from the CLI's response. The user never sees the JSON, never gets told to do something themselves. If the CLI returns an error, surface it; do not fall back to "here's the JSON, you do it".
|
|
1422
|
+
16. **Forbidden phrases** (these are regression markers — if you see yourself about to type any of these, stop and re-read rule 15):
|
|
1423
|
+
- "Save it via POST to the report-creation API endpoint when ready"
|
|
1424
|
+
- "Save it via the report-creation API endpoint when ready"
|
|
1425
|
+
- "to save, run `tl reports create --config '<json>'`"
|
|
1426
|
+
- "Saved as <path>.json" (without a campaign_id from the CLI)
|
|
1427
|
+
- "Saved to <path>" (without a campaign_id)
|
|
1428
|
+
- Any instruction telling the user to take a save action themselves when the original prompt was a save-intent prompt.
|
|
1380
1429
|
|
|
1381
1430
|
## Follow-Up Interactions
|
|
1382
1431
|
|
|
@@ -35,7 +35,7 @@ These can mean different report types depending on context. Phase 1 must surface
|
|
|
35
35
|
| Term | Meaning | Where it shows up |
|
|
36
36
|
|---|---|---|
|
|
37
37
|
| **MSN** | Media Selling Network — broad ~11K opted-in channel pool | `msn_channels_only` |
|
|
38
|
-
| **TPP** | ThoughtLeaders Premier Partners — smaller ~169 high-touch managed pool |
|
|
38
|
+
| **TPP** | ThoughtLeaders Premier Partners — smaller ~169 high-touch managed pool | Filter via `is_tl_channel = TRUE` on the channel table. There is no top-level boolean flag in the FilterSet that maps to TPP; the canonical pattern is to **resolve the TPP roster** with `tl db pg "SELECT id FROM thoughtleaders_channel WHERE is_tl_channel = TRUE AND is_active = TRUE ORDER BY id"` and **pin the resulting IDs in `filterset.channels`** (the M2M include list). The roster is small and stable enough that pinning is cheap; just rerun the resolution if the TPP set changes. **Do not** narrate this as "TPP isn't a typed filter" — TPP IS a recognised filter; the implementation detail is the resolve-and-pin pattern. |
|
|
39
39
|
| **MBN** | Media Buying Network — managed-services advertisers (brand side) | `cross_references` type `include_sponsored_by_mbn` |
|
|
40
40
|
| **AM** / **Account Manager** | The advertiser-side owner of a deal | `owner_advertiser_name` (in `filters_json` for type 8) |
|
|
41
41
|
| **TM** / **Talent Manager** / **Publisher Manager** | The publisher-side owner of a deal | `owner_publisher_name` (in `filters_json` for type 8) |
|
|
@@ -179,3 +179,4 @@ Don't put something in `filters_json` that already has a typed field — it conf
|
|
|
179
179
|
- **Brand and channel names are NOT IDs.** Always run the `name_resolver` tool to convert `"PewDiePie"` → `<channel_id>` before emitting `channels: [...]` / `brands: [...]`. Type 8 with unresolved names is a hard failure.
|
|
180
180
|
- **`tl_sponsorships_only`** restricts to channels TL has sponsorship history with — not "channels currently in MSN." Different from `msn_channels_only`. Pick based on intent.
|
|
181
181
|
- **"Campaign" is a colliding term.** In Django, `Campaign` is the umbrella model for ALL reports. In TL business language, "campaign" often means a sponsorship campaign (type 8). Phase 1 must clarify when "campaign report" appears in the user's wording.
|
|
182
|
+
- **Free-text niches → keywords ONLY, never `content_categories` as a pre-filter.** When the user describes their target niches in free text — *"motorcycle, cycling, travel vlog, adventure sports, drone, tech review, photography, sailing, running"*, *"investing/finance"*, *"action sports"*, etc. — match those niches with `keyword_groups` (or `keywords`) against `content_fields` (description / ai_description / topic descriptions / channel name). **Do not** map them onto `content_categories`. The TL `ContentCategory` enum is a coarse 22-bucket taxonomy (LIFESTYLE / TRAVEL / SPORTS / HOWTO / ENTERTAINMENT / PHOTOGRAPHY / TECHNOLOGY / …); a single niche like "motorcycle vlogging" can scatter across LIFESTYLE, SPORTS, HOWTO, and ENTERTAINMENT depending on how each channel was tagged. Using `content_categories` as a pre-filter actively excludes channels that fit the niche but happen to be tagged in a sibling bucket. Only use `content_categories` when the user explicitly names one of TL's category labels (e.g. *"Lifestyle channels"*, *"channels in the Sports category"*) — that's a precise category request, not a niche description.
|
|
@@ -13,6 +13,7 @@ user's actual command output.
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import shutil
|
|
16
17
|
import subprocess
|
|
17
18
|
import sys
|
|
18
19
|
import time
|
|
@@ -96,6 +97,11 @@ def _run_upgrade(method: str, latest: str) -> None:
|
|
|
96
97
|
Uses `install --force` with the new tag URL. pipx/uv pin the original
|
|
97
98
|
install spec including the git tag, so a plain `upgrade` re-installs
|
|
98
99
|
the same version — `--force` is the only way to advance the pinned tag.
|
|
100
|
+
|
|
101
|
+
On a successful upgrade, re-syncs Claude Code and OpenCode skills if
|
|
102
|
+
their respective binaries are on PATH, so the new version's skills
|
|
103
|
+
land in ~/.claude/ and ~/.config/opencode/ without the user having
|
|
104
|
+
to remember to run `tl setup ...`.
|
|
99
105
|
"""
|
|
100
106
|
tagged_url = f"git+{REPO_URL}@v{latest}"
|
|
101
107
|
cmd = {
|
|
@@ -109,9 +115,41 @@ def _run_upgrade(method: str, latest: str) -> None:
|
|
|
109
115
|
file=sys.stderr,
|
|
110
116
|
)
|
|
111
117
|
try:
|
|
112
|
-
subprocess.run(cmd, check=False, timeout=60)
|
|
118
|
+
result = subprocess.run(cmd, check=False, timeout=60)
|
|
113
119
|
except (OSError, subprocess.TimeoutExpired):
|
|
114
|
-
|
|
120
|
+
return
|
|
121
|
+
if result.returncode == 0:
|
|
122
|
+
_resync_integrations()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _resync_integrations() -> None:
|
|
126
|
+
"""Re-sync Claude Code and OpenCode skills after a self-upgrade.
|
|
127
|
+
|
|
128
|
+
Spawned as a subprocess against the freshly-installed `tl` binary —
|
|
129
|
+
the running process holds the OLD code in memory, so calling the
|
|
130
|
+
setup functions in-process would (depending on import caching) copy
|
|
131
|
+
the wrong assets. Subprocess re-execs the new code from disk.
|
|
132
|
+
|
|
133
|
+
Conditional on each tool's binary being on PATH; everything is
|
|
134
|
+
silent on failure (a skill resync issue must never fail the
|
|
135
|
+
upgrade itself).
|
|
136
|
+
"""
|
|
137
|
+
tl_bin = shutil.which("tl")
|
|
138
|
+
if not tl_bin:
|
|
139
|
+
return
|
|
140
|
+
for tool, binary in (("claude", "claude"), ("opencode", "opencode")):
|
|
141
|
+
if not shutil.which(binary):
|
|
142
|
+
continue
|
|
143
|
+
print(f"[tl-cli] re-syncing {tool} skills…", file=sys.stderr)
|
|
144
|
+
try:
|
|
145
|
+
subprocess.run(
|
|
146
|
+
[tl_bin, "setup", tool, "--json"],
|
|
147
|
+
capture_output=True,
|
|
148
|
+
timeout=120,
|
|
149
|
+
check=False,
|
|
150
|
+
)
|
|
151
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
152
|
+
pass
|
|
115
153
|
|
|
116
154
|
|
|
117
155
|
def check_and_upgrade() -> None:
|
|
File without changes
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/.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
|
|
File without changes
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/business-glossary.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/elasticsearch-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/skills/tl/references/firebolt-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/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
|
{thoughtleaders_cli-0.6.16 → thoughtleaders_cli-0.6.18}/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
|