thoughtleaders-cli 0.9.3__tar.gz → 0.9.4__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.
Files changed (157) hide show
  1. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.github/workflows/ci.yml +2 -2
  3. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.github/workflows/cli-integration.yml +2 -2
  4. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.github/workflows/python-publish.yml +1 -1
  5. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/API.md +4 -0
  6. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/PKG-INFO +16 -1
  7. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/README.md +15 -0
  8. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/pyproject.toml +1 -1
  9. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl/SKILL.md +17 -3
  10. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/__init__.py +1 -1
  11. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/client/http.py +12 -8
  12. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/balance.py +6 -0
  13. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/db.py +5 -3
  14. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/setup.py +30 -1
  15. thoughtleaders_cli-0.9.4/src/tl_cli/commands/skills.py +437 -0
  16. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/main.py +9 -0
  17. thoughtleaders_cli-0.9.4/src/tl_cli/skill_registry.py +312 -0
  18. thoughtleaders_cli-0.9.4/tests/test_setup_marker_respect.py +214 -0
  19. thoughtleaders_cli-0.9.4/tests/test_skill_registry.py +376 -0
  20. thoughtleaders_cli-0.9.4/tests/test_skills_command.py +420 -0
  21. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/uv.lock +7 -19
  22. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.claude-plugin/marketplace.json +0 -0
  23. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.github/dependabot.yml +0 -0
  24. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/.gitignore +0 -0
  25. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/AGENTS.md +0 -0
  26. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/CLAUDE.md +0 -0
  27. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/LICENSE +0 -0
  28. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/agents/keyword-context-classifier.md +0 -0
  29. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/agents/keyword-entity-resolver.md +0 -0
  30. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/agents/keyword-relevance-validator.md +0 -0
  31. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/agents/tl-analyst.md +0 -0
  32. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/agents/youtube-comment-classifier.md +0 -0
  33. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/hooks/hooks.json +0 -0
  34. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/hooks/scripts/load-tl-skill.mjs +0 -0
  35. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/hooks/scripts/post-usage.sh +0 -0
  36. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/hooks/scripts/pre-check.sh +0 -0
  37. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl/references/business-glossary.md +0 -0
  38. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl/references/elasticsearch-schema.md +0 -0
  39. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl/references/firebolt-schema.md +0 -0
  40. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl/references/postgres-schema.md +0 -0
  41. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/.gitignore +0 -0
  42. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/SKILL.md +0 -0
  43. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/references/comment-patterns.md +0 -0
  44. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/references/peer-cohort.md +0 -0
  45. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/references/red-flags.md +0 -0
  46. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/references/scoring.md +0 -0
  47. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/_io_utf8.py +0 -0
  48. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/analyze_channel.py +0 -0
  49. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/anomaly_detector.py +0 -0
  50. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/comment_analyzer.py +0 -0
  51. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/comment_scraper.py +0 -0
  52. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/engagement_ratios.py +0 -0
  53. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/peer_cohort.py +0 -0
  54. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/report.py +0 -0
  55. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/resolve_channel.py +0 -0
  56. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/score.py +0 -0
  57. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/tl_cli.py +0 -0
  58. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/video_integrity.py +0 -0
  59. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-channel-authenticity/scripts/view_curves.py +0 -0
  60. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-create-workflow/SKILL.md +0 -0
  61. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-create-workflow/references/creating-in-app.md +0 -0
  62. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-create-workflow/references/methodology.md +0 -0
  63. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-create-workflow/references/pitfalls.md +0 -0
  64. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-create-workflow/references/workflow-model.md +0 -0
  65. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/SKILL.md +0 -0
  66. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/references/elasticsearch-content-search.md +0 -0
  67. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/references/help.md +0 -0
  68. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/build_report.py +0 -0
  69. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/expand_entities.py +0 -0
  70. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/fetch_context.py +0 -0
  71. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/probe.py +0 -0
  72. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/search_channels.py +0 -0
  73. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/search_videos.py +0 -0
  74. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-keyword-research/scripts/select_keywords.py +0 -0
  75. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/SKILL.md +0 -0
  76. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/columns_brands.md +0 -0
  77. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/columns_channels.md +0 -0
  78. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/columns_content.md +0 -0
  79. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/columns_sponsorships.md +0 -0
  80. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/intelligence_filterset_schema.json +0 -0
  81. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/intelligence_widget_schema.json +0 -0
  82. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/report_glossary.md +0 -0
  83. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/sortable_columns.json +0 -0
  84. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/sponsorship_filterset_schema.json +0 -0
  85. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/sponsorship_widget_schema.json +0 -0
  86. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-save-report/references/widgets.md +0 -0
  87. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-top-partnerships/SKILL.md +0 -0
  88. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-top-partnerships/scripts/top_partnerships.py +0 -0
  89. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-views-guarantee/SKILL.md +0 -0
  90. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/skills/tl-views-guarantee/scripts/vg.py +0 -0
  91. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/_completions.py +0 -0
  92. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/_typer_utils.py +0 -0
  93. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/auth/__init__.py +0 -0
  94. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/auth/commands.py +0 -0
  95. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/auth/login.py +0 -0
  96. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/auth/pkce.py +0 -0
  97. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/auth/token_store.py +0 -0
  98. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/client/__init__.py +0 -0
  99. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/client/errors.py +0 -0
  100. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/__init__.py +0 -0
  101. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/_comments_common.py +0 -0
  102. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/brands.py +0 -0
  103. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/bulk_import.py +0 -0
  104. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/changelog.py +0 -0
  105. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/channels.py +0 -0
  106. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/credits.py +0 -0
  107. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/deals.py +0 -0
  108. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/describe.py +0 -0
  109. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/doctor.py +0 -0
  110. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/matches.py +0 -0
  111. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/profiles.py +0 -0
  112. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/proposals.py +0 -0
  113. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/recommender.py +0 -0
  114. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/reports.py +0 -0
  115. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/schema.py +0 -0
  116. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/snapshots.py +0 -0
  117. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/sponsorships.py +0 -0
  118. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/uploads.py +0 -0
  119. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/whoami.py +0 -0
  120. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/commands/workflows.py +0 -0
  121. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/config.py +0 -0
  122. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/filters.py +0 -0
  123. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/hints.py +0 -0
  124. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/output/__init__.py +0 -0
  125. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/output/formatter.py +0 -0
  126. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/query_history.py +0 -0
  127. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/src/tl_cli/self_update.py +0 -0
  128. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/__init__.py +0 -0
  129. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_auth.py +0 -0
  130. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_brands_winner_channels.py +0 -0
  131. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_build_report.py +0 -0
  132. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_channels_lookalike.py +0 -0
  133. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_db_repeat_warning.py +0 -0
  134. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_describe.py +0 -0
  135. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_error_hints.py +0 -0
  136. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_expand_entities.py +0 -0
  137. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_filters.py +0 -0
  138. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_http_auth.py +0 -0
  139. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_output.py +0 -0
  140. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_probe.py +0 -0
  141. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_profiles.py +0 -0
  142. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_reports.py +0 -0
  143. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_scripts_executable.py +0 -0
  144. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_search_channels.py +0 -0
  145. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_search_videos.py +0 -0
  146. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_select_keywords.py +0 -0
  147. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_setup.py +0 -0
  148. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_sponsorships.py +0 -0
  149. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests/test_workflows.py +0 -0
  150. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/AGENTS.md +0 -0
  151. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/conftest.py +0 -0
  152. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_balance.py +0 -0
  153. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_db_es.py +0 -0
  154. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_db_fb.py +0 -0
  155. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_db_pg.py +0 -0
  156. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_schema.py +0 -0
  157. {thoughtleaders_cli-0.9.3 → thoughtleaders_cli-0.9.4}/tests_cli/test_whoami.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "ThoughtLeaders CLI — query sponsorship deals, channels, brands, uploads, and intelligence from the terminal",
5
5
  "author": {
6
6
  "name": "ThoughtLeaders",
@@ -26,8 +26,8 @@ jobs:
26
26
  # Matches `requires-python = ">=3.12"`.
27
27
  python-version: ["3.12", "3.13", "3.14"]
28
28
  steps:
29
- - uses: actions/checkout@v6
30
- - uses: astral-sh/setup-uv@v6
29
+ - uses: actions/checkout@v7
30
+ - uses: astral-sh/setup-uv@v7
31
31
  with:
32
32
  enable-cache: true
33
33
  - name: Sync locked dependencies
@@ -29,8 +29,8 @@ jobs:
29
29
  name: Live read-only CLI tests
30
30
  runs-on: ubuntu-latest
31
31
  steps:
32
- - uses: actions/checkout@v6
33
- - uses: astral-sh/setup-uv@v6
32
+ - uses: actions/checkout@v7
33
+ - uses: astral-sh/setup-uv@v7
34
34
  with:
35
35
  enable-cache: true
36
36
  - name: Sync locked dependencies (installs the `tl` CLI)
@@ -11,7 +11,7 @@ jobs:
11
11
  release-build:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v6
14
+ - uses: actions/checkout@v7
15
15
  - uses: actions/setup-python@v6
16
16
  with:
17
17
  python-version: "3.12"
@@ -142,6 +142,8 @@ Useful for verifying the API key resolves to the user you expect before kicking
142
142
 
143
143
  `GET /balance` — credit balance plus the last 10 metered calls for the org. Free.
144
144
 
145
+ `balance` is the combined total of two pools: `topup_balance` (plan-granted credits, reset to the plan allowance each top-up period, spent first) and `purchased_balance` (bought credits — they survive top-up resets, are spent last, and keep working after the per-user session quota is exhausted).
146
+
145
147
  ```bash
146
148
  curl -sS "$TL_API_BASE/balance" \
147
149
  -H "Authorization: Bearer $TL_API_KEY" \
@@ -155,6 +157,8 @@ print(get('/balance'))
155
157
  ```json
156
158
  {
157
159
  "balance": 9995.88,
160
+ "topup_balance": 8995.88,
161
+ "purchased_balance": 1000.00,
158
162
  "allow_overage": false,
159
163
  "recent_usage": [
160
164
  {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thoughtleaders-cli
3
- Version: 0.9.3
3
+ Version: 0.9.4
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
@@ -284,6 +284,21 @@ The plugin ships several focused skills (installed by all the `tl setup *` comma
284
284
  - **`tl-views-guarantee`** — sizes a multi-video sponsorship buy for a channel, returning the video bundle size, views guarantee, and likelihood to hit.
285
285
  - **`tl-top-partnerships`** — brand-user performance report. Ranks a brand's sold sponsorships by live eCPM vs the sold-date projection, aggregates per channel, and delivers a two-tab Google Sheet ("By Deal" / "By Channel") via `gws`. Uses only public CLI commands (`tl whoami`, `tl sponsorships list`).
286
286
 
287
+ ## Distributed skills
288
+
289
+ Beyond the bundled set above, an organization can be granted additional skills that aren't part of a CLI release — `tl skill` fetches and installs them on demand into the same directories `tl setup` uses (Claude Code's standalone skills directory, OpenCode's skills directory, and the directory shared by Gemini and Codex), so every supported agent picks them up automatically.
290
+
291
+ ```bash
292
+ tl skill list # skills available to your organization, with installed/latest versions
293
+ tl skill list --all # full catalog (full-access accounts only)
294
+ tl skill download my-skill # fetch and install into every AI-agent skill directory
295
+ tl skill download my-skill --force # overwrite a directory tl doesn't already manage
296
+ tl skill update # refresh every downloaded skill to its latest version
297
+ tl skill remove my-skill # uninstall a downloaded skill
298
+ ```
299
+
300
+ A directory `tl skill download` doesn't already manage (no prior `tl`-managed install there) is left alone unless `--force` is passed — it never overwrites a skill you installed some other way. `tl` warns once a day, on any command, when a downloaded skill has a newer version available. `tl setup` and self-update re-syncs also respect these directories: a downloaded skill is never rmtree'd or overwritten, even if its name collides with a bundled skill.
301
+
287
302
  ## Output Formats
288
303
 
289
304
  By default, output is a styled table in the terminal and JSON when piped.
@@ -256,6 +256,21 @@ The plugin ships several focused skills (installed by all the `tl setup *` comma
256
256
  - **`tl-views-guarantee`** — sizes a multi-video sponsorship buy for a channel, returning the video bundle size, views guarantee, and likelihood to hit.
257
257
  - **`tl-top-partnerships`** — brand-user performance report. Ranks a brand's sold sponsorships by live eCPM vs the sold-date projection, aggregates per channel, and delivers a two-tab Google Sheet ("By Deal" / "By Channel") via `gws`. Uses only public CLI commands (`tl whoami`, `tl sponsorships list`).
258
258
 
259
+ ## Distributed skills
260
+
261
+ Beyond the bundled set above, an organization can be granted additional skills that aren't part of a CLI release — `tl skill` fetches and installs them on demand into the same directories `tl setup` uses (Claude Code's standalone skills directory, OpenCode's skills directory, and the directory shared by Gemini and Codex), so every supported agent picks them up automatically.
262
+
263
+ ```bash
264
+ tl skill list # skills available to your organization, with installed/latest versions
265
+ tl skill list --all # full catalog (full-access accounts only)
266
+ tl skill download my-skill # fetch and install into every AI-agent skill directory
267
+ tl skill download my-skill --force # overwrite a directory tl doesn't already manage
268
+ tl skill update # refresh every downloaded skill to its latest version
269
+ tl skill remove my-skill # uninstall a downloaded skill
270
+ ```
271
+
272
+ A directory `tl skill download` doesn't already manage (no prior `tl`-managed install there) is left alone unless `--force` is passed — it never overwrites a skill you installed some other way. `tl` warns once a day, on any command, when a downloaded skill has a newer version available. `tl setup` and self-update re-syncs also respect these directories: a downloaded skill is never rmtree'd or overwritten, even if its name collides with a bundled skill.
273
+
259
274
  ## Output Formats
260
275
 
261
276
  By default, output is a styled table in the terminal and JSON when piped.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "thoughtleaders-cli"
7
- version = "0.9.3"
7
+ version = "0.9.4"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -251,9 +251,8 @@ contact field:
251
251
 
252
252
  The channel's full email archive (`all_emails` — a JSON object keyed by email address,
253
253
  each value recording when and where the address was found) is **not editable here**;
254
- sending it returns a 400. It is append-only: new addresses are added with the
255
- internal CLI's `tl-internal channels add-email` command (superuser-only), which never
256
- modifies or removes existing entries.
254
+ sending it returns a 400. It is append-only and managed through an internal-only
255
+ process that never modifies or removes existing entries — not available via this CLI.
257
256
 
258
257
  **Profile notes.** `tl profiles update` (superuser only) edits a brand/publisher profile's
259
258
  **`superuser_notes`** — the internal free-text notes field on the customer record
@@ -503,6 +502,21 @@ tl changelog since v0.4.10 # Notes from v0.4.10 to latest
503
502
  tl changelog --md > CHANGELOG.md # Capture for a doc
504
503
  ```
505
504
 
505
+ #### Distributed skills — beyond the bundled set
506
+
507
+ An organization can be granted additional skills that aren't part of a CLI release. `tl skill` fetches and installs them on demand into the same directories `tl setup` uses (Claude Code's standalone skills directory, OpenCode's skills directory, and the directory shared by Gemini and Codex), so every supported agent picks them up automatically — no restart or reconfiguration needed beyond re-reading the skill listing.
508
+
509
+ ```bash
510
+ tl skill list # Skills available to your org, with installed/latest versions (free)
511
+ tl skill list --all # Full catalog (full-access accounts only)
512
+ tl skill download <name> # Fetch and install into every AI-agent skill directory on this machine
513
+ tl skill download <name> --force # Overwrite a directory tl doesn't already manage
514
+ tl skill update # Refresh every downloaded skill to its latest version
515
+ tl skill remove <name> # Uninstall a downloaded skill
516
+ ```
517
+
518
+ If a user asks to find, add, or refresh a skill by capability ("is there a skill for X", "get me the latest Y skill"), check `tl skill list` before saying no — the bundled set isn't the whole catalog. `tl skill download` never overwrites a directory it doesn't already manage unless `--force` is passed, so it's safe to run without clobbering a manually-installed skill of the same name. `tl` warns once a day, on any command, when a downloaded skill has a newer version available — surface that nag to the user rather than silently ignoring it, and offer to run `tl skill update`.
519
+
506
520
  #### Channel & video discovery — pick the path for the question shape
507
521
 
508
522
  Four first-class paths, each with a different signal. **Pick by the SHAPE of the user's question, not by habit.** "Recommender first" is the right default only for path 2 — for paths 1, 3, and 4 the recommender is the wrong tool.
@@ -1,3 +1,3 @@
1
1
  """ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence."""
2
2
 
3
- __version__ = "0.9.3"
3
+ __version__ = "0.9.4"
@@ -23,8 +23,8 @@ class TLClient:
23
23
  },
24
24
  )
25
25
 
26
- def get(self, path: str, params: dict | None = None) -> dict:
27
- return self._request("GET", path, params=params)
26
+ def get(self, path: str, params: dict | None = None, timeout: float | None = None) -> dict:
27
+ return self._request("GET", path, params=params, timeout=timeout)
28
28
 
29
29
  def post(self, path: str, json_body: dict | None = None) -> dict:
30
30
  return self._request("POST", path, json_body=json_body)
@@ -38,20 +38,24 @@ class TLClient:
38
38
  path: str,
39
39
  params: dict | None = None,
40
40
  json_body: dict | None = None,
41
+ timeout: float | None = None,
41
42
  ) -> dict:
42
43
  headers = self._auth_headers()
44
+ # Only overrides the client's default timeout when the caller asks
45
+ # for one — passing `timeout=None` through to httpx means "no
46
+ # timeout", not "use the default", so it's omitted entirely here.
47
+ request_kwargs = {"params": params, "json": json_body, "headers": headers}
48
+ if timeout is not None:
49
+ request_kwargs["timeout"] = timeout
43
50
 
44
- response = self._client.request(
45
- method, path, params=params, json=json_body, headers=headers
46
- )
51
+ response = self._client.request(method, path, **request_kwargs)
47
52
 
48
53
  # On 401, try refreshing the token once
49
54
  if response.status_code == 401:
50
55
  headers = self._refresh_and_get_headers()
51
56
  if headers:
52
- response = self._client.request(
53
- method, path, params=params, json=json_body, headers=headers
54
- )
57
+ request_kwargs["headers"] = headers
58
+ response = self._client.request(method, path, **request_kwargs)
55
59
 
56
60
  if response.status_code >= 400:
57
61
  detail = self._extract_detail(response)
@@ -44,6 +44,12 @@ def balance(
44
44
  allow_overage = data.get("allow_overage", False)
45
45
 
46
46
  console.print(f"\n[bold]Credit Balance:[/bold] [cyan]{balance_val}[/cyan] credits")
47
+ # Older servers return only the combined balance; newer ones split it
48
+ # into the plan-granted (top-up) pool and the purchased pool.
49
+ topup_val = data.get("topup_balance")
50
+ purchased_val = data.get("purchased_balance")
51
+ if topup_val is not None and purchased_val is not None:
52
+ console.print(f"[dim]Plan (top-up) credits: {topup_val} · Purchased: {purchased_val}[/dim]")
47
53
  if allow_overage:
48
54
  console.print("[dim]Overage: enabled[/dim]")
49
55
 
@@ -99,9 +99,11 @@ def pg_cmd(
99
99
  Common traps — check before writing SQL:
100
100
 
101
101
  - Column names follow the current schema: subscribers, projected_views,
102
- scheduled_date, is_tpp, advertiser_profile_id, views_guarantee NOT the
103
- older reach / impression / send_date / is_tl_channel / creator_profile_id
104
- / impressions_guarantee.
102
+ scheduled_date, is_tpp, advertiser_profile_id, views_guarantee, url (the
103
+ channel's own URL) — NOT the older reach / impression / send_date /
104
+ is_tl_channel / creator_profile_id / impressions_guarantee / channel_url.
105
+ - thoughtleaders_adlink has no bare `url` column — the live sponsored-video
106
+ URL is `media_url`.
105
107
  - The sponsorship table (thoughtleaders_adlink) hides its relations behind
106
108
  joins: no channel_id/channel_name (join thoughtleaders_adspot via
107
109
  ad_spot_id, then thoughtleaders_channel) and no brand_id (join
@@ -21,6 +21,7 @@ from pytoon import encode as toon_encode
21
21
  from rich.console import Console
22
22
 
23
23
  from tl_cli import __version__
24
+ from tl_cli.skill_registry import is_marked_for
24
25
 
25
26
  app = typer.Typer(cls=AlphaSortedTyperGroup, help="Set up integrations (Claude Code, OpenCode, Gemini, Codex)")
26
27
  console = Console(stderr=True)
@@ -201,6 +202,20 @@ def check_plugin_version() -> list[str]:
201
202
  return warnings
202
203
 
203
204
 
205
+ def _warn_marker_skip(path: Path, name: str) -> None:
206
+ """Print the standard warning when setup leaves a tl-managed skill dir alone.
207
+
208
+ Shared by every place in this module that would otherwise rmtree/copytree
209
+ over a skill directory — a directory carrying a valid `.tl-skill.json`
210
+ marker was installed by `tl skill download` and must never be clobbered
211
+ by a bundled-skill sync, regardless of name collision or content match.
212
+ """
213
+ console.print(
214
+ f" [yellow]![/yellow] skipping {path}: managed by 'tl skill' downloads — "
215
+ f"remove with [cyan]tl skill remove {name}[/cyan] if you want the bundled version"
216
+ )
217
+
218
+
204
219
  def _install_standalone_skills(plugin_root: Path) -> int:
205
220
  """Copy skills and commands to ~/.claude/ for non-namespaced invocation.
206
221
 
@@ -214,6 +229,9 @@ def _install_standalone_skills(plugin_root: Path) -> int:
214
229
  for skill_dir in skills_src.iterdir():
215
230
  if skill_dir.is_dir() and (skill_dir / "SKILL.md").is_file():
216
231
  dst = CLAUDE_SKILLS_DIR / skill_dir.name
232
+ if dst.exists() and is_marked_for(dst, skill_dir.name):
233
+ _warn_marker_skip(dst, skill_dir.name)
234
+ continue
217
235
  if dst.exists():
218
236
  shutil.rmtree(dst)
219
237
  shutil.copytree(skill_dir, dst)
@@ -279,6 +297,11 @@ def _remove_matching_standalone_skills(plugin_root: Path) -> tuple[int, int]:
279
297
  standalone = CLAUDE_SKILLS_DIR / skill_dir.name
280
298
  if not standalone.is_dir():
281
299
  continue
300
+ if is_marked_for(standalone, skill_dir.name):
301
+ # tl-managed download — excluded from deletion candidates entirely,
302
+ # regardless of whether its content happens to match the bundled skill.
303
+ _warn_marker_skip(standalone, skill_dir.name)
304
+ continue
282
305
  if _trees_identical(skill_dir, standalone):
283
306
  shutil.rmtree(standalone)
284
307
  removed += 1
@@ -537,7 +560,10 @@ def _install_skill_trees(plugin_root: Path, target_dir: Path) -> int:
537
560
  (OpenCode, Gemini, Codex) — each agent reads skills from a different
538
561
  base directory, so we just parameterise on that. A `.tl-version`
539
562
  stamp is written into the target so `check_plugin_version()` can
540
- detect drift later. Returns the number of skills installed.
563
+ detect drift later. A destination carrying a `.tl-skill.json` marker
564
+ for this skill name is a `tl skill download` install — it's skipped
565
+ (with a warning) rather than clobbered, and isn't counted in the
566
+ returned total. Returns the number of skills installed.
541
567
  """
542
568
  count = 0
543
569
  skills_src = plugin_root / "skills"
@@ -545,6 +571,9 @@ def _install_skill_trees(plugin_root: Path, target_dir: Path) -> int:
545
571
  for skill_dir in skills_src.iterdir():
546
572
  if skill_dir.is_dir() and (skill_dir / "SKILL.md").is_file():
547
573
  dst = target_dir / skill_dir.name
574
+ if dst.exists() and is_marked_for(dst, skill_dir.name):
575
+ _warn_marker_skip(dst, skill_dir.name)
576
+ continue
548
577
  if dst.exists():
549
578
  shutil.rmtree(dst)
550
579
  shutil.copytree(skill_dir, dst)