thoughtleaders-cli 0.9.19__tar.gz → 0.9.20__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 (215) hide show
  1. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/PKG-INFO +1 -1
  3. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/pyproject.toml +1 -1
  4. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/_shared/tl_data.py +20 -0
  5. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/SKILL.md +2 -0
  6. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/build_html.py +6 -0
  7. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/analyze_channel.py +8 -1
  8. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/SKILL.md +3 -1
  9. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-views-guarantee/scripts/vg.py +18 -1
  10. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/__init__.py +1 -1
  11. thoughtleaders_cli-0.9.20/src/tl_cli/commands/agent.py +57 -0
  12. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/main.py +12 -9
  13. thoughtleaders_cli-0.9.20/tests/test_agent_complete.py +81 -0
  14. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_shared_tl_data.py +18 -0
  15. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/uv.lock +1 -1
  16. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.claude-plugin/marketplace.json +0 -0
  17. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.github/dependabot.yml +0 -0
  18. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.github/workflows/ci.yml +0 -0
  19. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.github/workflows/cli-integration.yml +0 -0
  20. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.github/workflows/python-publish.yml +0 -0
  21. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/.gitignore +0 -0
  22. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/AGENTS.md +0 -0
  23. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/API.md +0 -0
  24. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/CLAUDE.md +0 -0
  25. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/LICENSE +0 -0
  26. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/README.md +0 -0
  27. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/cast-sheet.md +0 -0
  28. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/gem-classifier.md +0 -0
  29. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/keyword-context-classifier.md +0 -0
  30. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/keyword-entity-resolver.md +0 -0
  31. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/keyword-relevance-validator.md +0 -0
  32. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/merge-shard.md +0 -0
  33. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/tl-analyst.md +0 -0
  34. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/agents/youtube-comment-classifier.md +0 -0
  35. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/hooks/hooks.json +0 -0
  36. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/hooks/scripts/load-tl-skill.mjs +0 -0
  37. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/hooks/scripts/post-usage.sh +0 -0
  38. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/hooks/scripts/pre-check.sh +0 -0
  39. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/connector-impact/SKILL.md +0 -0
  40. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/connector-impact/references/help.md +0 -0
  41. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/connector-impact/references/impact-schema.md +0 -0
  42. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/connector-impact/references/impact-to-tl-mapping.md +0 -0
  43. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl/SKILL.md +0 -0
  44. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl/references/business-glossary.md +0 -0
  45. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl/references/elasticsearch-schema.md +0 -0
  46. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl/references/firebolt-schema.md +0 -0
  47. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl/references/postgres-schema.md +0 -0
  48. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/cast-sheet.md +0 -0
  49. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/creator-brief-template.md +0 -0
  50. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/cue-phrases.txt +0 -0
  51. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/evidence-rules.md +0 -0
  52. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/extractor-rubric.md +0 -0
  53. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/identity-lane.md +0 -0
  54. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/profile-spec.md +0 -0
  55. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/references/transcript-mining.md +0 -0
  56. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/assemble_extracts.py +0 -0
  57. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/authenticate.py +0 -0
  58. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/bio_lane.py +0 -0
  59. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/brand_reads.py +0 -0
  60. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/cast_sheet.py +0 -0
  61. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/channel_context.py +0 -0
  62. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/cluster_gems.py +0 -0
  63. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/extractor_prompt.py +0 -0
  64. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/fetch_cues.py +0 -0
  65. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/identity_prompt.py +0 -0
  66. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/ledger_meta.py +0 -0
  67. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/merge_pass.py +0 -0
  68. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/page.css +0 -0
  69. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/start_run.py +0 -0
  70. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/store_io.py +0 -0
  71. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/tier_hint.py +0 -0
  72. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-brand-creator-connection/scripts/verify_quotes.py +0 -0
  73. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/.gitignore +0 -0
  74. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/SKILL.md +0 -0
  75. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/references/comment-patterns.md +0 -0
  76. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/references/peer-cohort.md +0 -0
  77. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/references/red-flags.md +0 -0
  78. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/references/scoring.md +0 -0
  79. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/_io_utf8.py +0 -0
  80. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/anomaly_detector.py +0 -0
  81. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/channel_lookup.py +0 -0
  82. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/comment_analyzer.py +0 -0
  83. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/comment_scraper.py +0 -0
  84. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/engagement_ratios.py +0 -0
  85. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/peer_cohort.py +0 -0
  86. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/report.py +0 -0
  87. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/resolve_channel.py +0 -0
  88. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/score.py +0 -0
  89. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/video_integrity.py +0 -0
  90. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-channel-authenticity/scripts/view_curves.py +0 -0
  91. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-create-workflow/SKILL.md +0 -0
  92. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-create-workflow/references/creating-in-app.md +0 -0
  93. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-create-workflow/references/methodology.md +0 -0
  94. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-create-workflow/references/pitfalls.md +0 -0
  95. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-create-workflow/references/workflow-model.md +0 -0
  96. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/SKILL.md +0 -0
  97. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/references/elasticsearch-content-search.md +0 -0
  98. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/references/help.md +0 -0
  99. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/build_report.py +0 -0
  100. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/expand_entities.py +0 -0
  101. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/fetch_context.py +0 -0
  102. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/probe.py +0 -0
  103. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/search_channels.py +0 -0
  104. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/search_videos.py +0 -0
  105. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-keyword-research/scripts/select_keywords.py +0 -0
  106. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/columns_brands.md +0 -0
  107. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/columns_channels.md +0 -0
  108. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/columns_content.md +0 -0
  109. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/columns_sponsorships.md +0 -0
  110. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/intelligence_filterset_schema.json +0 -0
  111. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/intelligence_widget_schema.json +0 -0
  112. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/report_glossary.md +0 -0
  113. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/sortable_columns.json +0 -0
  114. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/sponsorship_filterset_schema.json +0 -0
  115. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/sponsorship_widget_schema.json +0 -0
  116. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-save-report/references/widgets.md +0 -0
  117. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-top-partnerships/SKILL.md +0 -0
  118. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-top-partnerships/scripts/top_partnerships.py +0 -0
  119. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/skills/tl-views-guarantee/SKILL.md +0 -0
  120. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/__main__.py +0 -0
  121. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/_completions.py +0 -0
  122. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/_typer_utils.py +0 -0
  123. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/auth/__init__.py +0 -0
  124. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/auth/commands.py +0 -0
  125. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/auth/login.py +0 -0
  126. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/auth/pkce.py +0 -0
  127. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/auth/token_store.py +0 -0
  128. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/client/__init__.py +0 -0
  129. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/client/errors.py +0 -0
  130. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/client/http.py +0 -0
  131. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/__init__.py +0 -0
  132. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/_comments_common.py +0 -0
  133. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/balance.py +0 -0
  134. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/brands.py +0 -0
  135. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/bulk_import.py +0 -0
  136. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/changelog.py +0 -0
  137. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/channels.py +0 -0
  138. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/credits.py +0 -0
  139. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/db.py +0 -0
  140. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/deals.py +0 -0
  141. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/describe.py +0 -0
  142. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/doctor.py +0 -0
  143. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/matches.py +0 -0
  144. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/memory.py +0 -0
  145. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/profiles.py +0 -0
  146. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/proposals.py +0 -0
  147. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/recommender.py +0 -0
  148. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/reports.py +0 -0
  149. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/schema.py +0 -0
  150. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/setup.py +0 -0
  151. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/skills.py +0 -0
  152. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/snapshots.py +0 -0
  153. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/sponsorships.py +0 -0
  154. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/uploads.py +0 -0
  155. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/whoami.py +0 -0
  156. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/commands/workflows.py +0 -0
  157. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/config.py +0 -0
  158. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/filters.py +0 -0
  159. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/hints.py +0 -0
  160. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/output/__init__.py +0 -0
  161. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/output/formatter.py +0 -0
  162. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/query_history.py +0 -0
  163. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/self_update.py +0 -0
  164. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/src/tl_cli/skill_registry.py +0 -0
  165. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/__init__.py +0 -0
  166. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_assemble_extracts.py +0 -0
  167. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_auth.py +0 -0
  168. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_bio_lane.py +0 -0
  169. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_brands_winner_channels.py +0 -0
  170. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_build_report.py +0 -0
  171. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_cast_sheet.py +0 -0
  172. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_channels_lookalike.py +0 -0
  173. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_cluster_gems.py +0 -0
  174. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_creator_brief_accuracy.py +0 -0
  175. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_creator_brief_scripts.py +0 -0
  176. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_db_repeat_warning.py +0 -0
  177. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_describe.py +0 -0
  178. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_error_hints.py +0 -0
  179. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_expand_entities.py +0 -0
  180. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_extractor_prompt.py +0 -0
  181. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_fetch_cues.py +0 -0
  182. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_filters.py +0 -0
  183. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_http_auth.py +0 -0
  184. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_ledger_meta.py +0 -0
  185. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_memory.py +0 -0
  186. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_merge_pass.py +0 -0
  187. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_output.py +0 -0
  188. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_probe.py +0 -0
  189. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_profiles.py +0 -0
  190. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_quota_refusal_message.py +0 -0
  191. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_refusal_rendering.py +0 -0
  192. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_reports.py +0 -0
  193. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_scripts_executable.py +0 -0
  194. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_search_channels.py +0 -0
  195. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_search_videos.py +0 -0
  196. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_select_keywords.py +0 -0
  197. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_setup.py +0 -0
  198. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_setup_marker_respect.py +0 -0
  199. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_skill_registry.py +0 -0
  200. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_skills_command.py +0 -0
  201. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_sponsorships.py +0 -0
  202. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_start_run.py +0 -0
  203. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_whoami_newsletter.py +0 -0
  204. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests/test_workflows.py +0 -0
  205. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/AGENTS.md +0 -0
  206. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/conftest.py +0 -0
  207. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_balance.py +0 -0
  208. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_db_es.py +0 -0
  209. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_db_fb.py +0 -0
  210. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_db_pg.py +0 -0
  211. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_schema.py +0 -0
  212. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tests_cli/test_whoami.py +0 -0
  213. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tools/tl-brand-creator-connection/references/cue-phrases.trained-2026-09-15.txt +0 -0
  214. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tools/tl-brand-creator-connection/references/cue-training.md +0 -0
  215. {thoughtleaders_cli-0.9.19 → thoughtleaders_cli-0.9.20}/tools/tl-brand-creator-connection/scripts/train_cues.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.9.19",
3
+ "version": "0.9.20",
4
4
  "description": "ThoughtLeaders CLI — query sponsorship deals, channels, brands, uploads, and intelligence from the terminal",
5
5
  "author": {
6
6
  "name": "ThoughtLeaders",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: thoughtleaders-cli
3
- Version: 0.9.19
3
+ Version: 0.9.20
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "thoughtleaders-cli"
7
- version = "0.9.19"
7
+ version = "0.9.20"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -235,6 +235,26 @@ def preflight() -> None:
235
235
  _tl(["whoami"], timeout=60)
236
236
 
237
237
 
238
+ def report_run(skill: str, outcome: str = "completed") -> None:
239
+ """Tell ThoughtLeaders a skill opened from one of its surfaces has finished.
240
+
241
+ Best effort, never raises: the skill's own result is already on the way
242
+ to the user, and a report that cannot be delivered must not change that.
243
+ A skill started by hand has no run to close; the CLI says so and exits 0.
244
+ """
245
+ exe = shutil.which(TL_BIN) or TL_BIN
246
+ try:
247
+ subprocess.run(
248
+ [exe, "agent", "complete", skill, "--outcome", outcome],
249
+ capture_output=True,
250
+ env=_child_env(),
251
+ timeout=30,
252
+ check=False,
253
+ )
254
+ except (OSError, subprocess.SubprocessError):
255
+ pass
256
+
257
+
238
258
  if __name__ == "__main__":
239
259
  if len(sys.argv) == 2 and sys.argv[1] == "preflight":
240
260
  preflight()
@@ -224,6 +224,8 @@ PROFILE completion, three lines:
224
224
  2. Fact count and what the socials lane did: `socials off, N linked platforms listed unread` or `socials on, N websites opened, N sources read, N facts`. Report "on" with 0 facts as such.
225
225
  3. What was cached on the channel record this run (host name, format label, host aliases, sibling channels), from `host_name_cache` and `cache`.
226
226
 
227
+ A PROFILE-only run (no brand) is finished here: run `tl agent complete tl-brand-creator-connection` so a run opened from a ThoughtLeaders surface is counted (the CONNECT page reports itself). If the ledger could not be built, run it with `--outcome failed`.
228
+
227
229
  **Fast run** (a run shape, not a flag): PROFILE only, primary channel only, socials OFF without asking, default selection, no corroboration round.
228
230
 
229
231
  ## 4. CONNECT pipeline
@@ -86,6 +86,10 @@ from collections import Counter, defaultdict
86
86
  sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent))
87
87
  import tier_hint # sibling module # noqa: E402
88
88
  from store_io import read_ledger # sibling module # noqa: E402
89
+ sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "_shared"))
90
+ import tl_data # noqa: E402
91
+
92
+ SKILL = "tl-brand-creator-connection"
89
93
 
90
94
  BADGES = {
91
95
  "direct": "direct",
@@ -2092,6 +2096,8 @@ def main() -> None:
2092
2096
  elapsed_s=round(time.monotonic() - t0, 1))
2093
2097
  if problems:
2094
2098
  print("PAGE CONTRACT: " + "; ".join(problems), file=sys.stderr)
2099
+ # The connections page is the deliverable; a no-fit page is still a result.
2100
+ tl_data.report_run(SKILL)
2095
2101
 
2096
2102
 
2097
2103
  if __name__ == "__main__":
@@ -42,6 +42,7 @@ import tl_data
42
42
 
43
43
  import channel_lookup
44
44
 
45
+ SKILL = "tl-channel-authenticity"
45
46
  OUT_DIR = Path("/tmp")
46
47
 
47
48
 
@@ -147,12 +148,18 @@ def main() -> None:
147
148
  if args.finalize:
148
149
  if len(args.finalize) < 2:
149
150
  ap.error("--finalize needs STATE and at least one LLM file")
150
- res = finalize(args.finalize[0], args.finalize[1:])
151
+ try:
152
+ res = finalize(args.finalize[0], args.finalize[1:])
153
+ except Exception:
154
+ tl_data.report_run(SKILL, "failed")
155
+ raise
151
156
  print(res["markdown"])
152
157
  print(
153
158
  f"\n<!-- final JSON: {res['final_json']} · "
154
159
  f"report: {res['report_md']} -->"
155
160
  )
161
+ # The verdict is the deliverable; the run is counted once it is printed.
162
+ tl_data.report_run(SKILL)
156
163
  elif args.ref:
157
164
  res = collect(args.ref)
158
165
  print(json.dumps(res, indent=2))
@@ -505,9 +505,11 @@ The follow-up offer matters because **FilterSet changes (keywords, demographics,
505
505
 
506
506
  If the user requests a chart, create it as a SVG graphic.
507
507
 
508
+ Then, as the last step, run `tl agent complete tl-save-report`. A run opened from a ThoughtLeaders surface (the Chrome extension's skill buttons) is counted as finished by it; one started by hand gets a short note and nothing else, which is fine.
509
+
508
510
  ### On failure
509
511
 
510
- If the command exits non-zero, the CLI prints the error on stderr (shape: `Error (NNN): <detail>` for most codes; specific lines for 401/402/403). **Surface the error verbatim** — do NOT silently report success.
512
+ If the command exits non-zero, the CLI prints the error on stderr (shape: `Error (NNN): <detail>` for most codes; specific lines for 401/402/403). **Surface the error verbatim** — do NOT silently report success. Then run `tl agent complete tl-save-report --outcome failed`.
511
513
 
512
514
  Map the visible code + detail to the likely cause:
513
515
 
@@ -15,12 +15,18 @@ Usage:
15
15
  import argparse
16
16
  import datetime
17
17
  import json
18
+ import pathlib as _pathlib
18
19
  import random
19
20
  import subprocess
20
21
  import sys
21
22
  from dataclasses import dataclass
22
23
  from typing import TypedDict
23
24
 
25
+ sys.path.insert(0, str(_pathlib.Path(__file__).resolve().parents[2] / "_shared"))
26
+ import tl_data # noqa: E402
27
+
28
+ SKILL = "tl-views-guarantee"
29
+
24
30
  SEED = 42 # passed to a fresh random.Random in bootstrap_sweep so each call starts from the same RNG state
25
31
  DEFAULT_MAX_BUNDLE_SIZE = 4
26
32
  HARD_MAX_BUNDLE_SIZE = 10
@@ -368,4 +374,15 @@ def main() -> None:
368
374
 
369
375
 
370
376
  if __name__ == "__main__":
371
- main()
377
+ # The run is counted once the four lines are out; a data shortfall (a
378
+ # message exit) is a run with nothing to show, a crash is a failed one.
379
+ try:
380
+ main()
381
+ except SystemExit as exc:
382
+ if exc.code not in (None, 0):
383
+ tl_data.report_run(SKILL, "no_results" if isinstance(exc.code, str) else "failed")
384
+ raise
385
+ except Exception:
386
+ tl_data.report_run(SKILL, "failed")
387
+ raise
388
+ tl_data.report_run(SKILL)
@@ -1,3 +1,3 @@
1
1
  """ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence."""
2
2
 
3
- __version__ = "0.9.19"
3
+ __version__ = "0.9.20"
@@ -0,0 +1,57 @@
1
+ """tl agent — the AI agent you open ThoughtLeaders skills in.
2
+
3
+ A skill handed over from a ThoughtLeaders surface (the Chrome extension's skill
4
+ buttons, the web app's export door) is counted as finished when it reports back
5
+ here with its slug and how it ended.
6
+ """
7
+
8
+ import typer
9
+ from rich.console import Console
10
+
11
+ from tl_cli._typer_utils import AlphaSortedTyperGroup
12
+ from tl_cli.client.errors import ApiError, handle_api_error
13
+ from tl_cli.client.http import get_client
14
+ from tl_cli.output.formatter import detect_format, output_single
15
+
16
+ app = typer.Typer(cls=AlphaSortedTyperGroup, help="Your AI agent: report a skill it ran as finished (free)")
17
+
18
+ OUTCOMES = ("completed", "no_results", "failed")
19
+ NO_RUN_CODE = "run_not_found"
20
+
21
+
22
+ @app.command("complete")
23
+ def complete_cmd(
24
+ skill: str = typer.Argument(..., help="The skill's slug, e.g. tl-views-guarantee"),
25
+ outcome: str = typer.Option("completed", "--outcome", help="How the run ended: completed, no_results or failed"),
26
+ json_output: bool = typer.Option(False, "--json", help="JSON output"),
27
+ toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
28
+ ) -> None:
29
+ """Report that a skill opened from a ThoughtLeaders surface has finished.
30
+
31
+ Skills call this as their last step. Only a skill opened from a ThoughtLeaders
32
+ surface has a run to close; one started by hand is simply not counted, and
33
+ this command says so and exits cleanly, so a skill's own result is never
34
+ lost over it.
35
+
36
+ Examples:
37
+ tl agent complete tl-views-guarantee
38
+ tl agent complete tl-channel-authenticity --outcome no_results
39
+ tl agent complete tl-brand-creator-connection --outcome failed
40
+ """
41
+ fmt = detect_format(json_output, False, False, toon_output)
42
+ err = Console(stderr=True)
43
+ if outcome not in OUTCOMES:
44
+ err.print(f"[red]Error:[/red] --outcome must be one of: {', '.join(OUTCOMES)}.")
45
+ raise typer.Exit(1)
46
+
47
+ client = get_client()
48
+ try:
49
+ data = client.post("/agent/complete", json_body={"skill": skill, "outcome": outcome})
50
+ output_single(data, fmt)
51
+ except ApiError as e:
52
+ if e.status_code == 404 and isinstance(e.raw, dict) and e.raw.get("code") == NO_RUN_CODE:
53
+ err.print(f"[dim]No open run of {skill} from a ThoughtLeaders surface; nothing to report.[/dim]")
54
+ return
55
+ handle_api_error(e)
56
+ finally:
57
+ client.close()
@@ -10,33 +10,35 @@ import typer
10
10
  from rich.console import Console
11
11
 
12
12
  from tl_cli import __version__
13
- from tl_cli._typer_utils import AlphaSortedTyperGroup
14
13
  from tl_cli import config as tl_config
14
+ from tl_cli._typer_utils import AlphaSortedTyperGroup
15
15
  from tl_cli.auth.commands import app as auth_app
16
+ from tl_cli.commands.agent import app as agent_app
16
17
  from tl_cli.commands.balance import app as balance_app
17
- from tl_cli.commands.changelog import changelog_command
18
18
  from tl_cli.commands.brands import app as brands_app
19
19
  from tl_cli.commands.bulk_import import bulk_import_command
20
- from tl_cli.commands.credits import app as credits_app
20
+ from tl_cli.commands.changelog import changelog_command
21
21
  from tl_cli.commands.channels import app as channels_app
22
+ from tl_cli.commands.credits import app as credits_app
22
23
  from tl_cli.commands.db import app as db_app
23
24
  from tl_cli.commands.deals import app as deals_app
25
+ from tl_cli.commands.describe import app as describe_app
26
+ from tl_cli.commands.doctor import app as doctor_app
24
27
  from tl_cli.commands.matches import app as matches_app
25
28
  from tl_cli.commands.memory import app as memory_app
26
29
  from tl_cli.commands.profiles import app as profiles_app
27
30
  from tl_cli.commands.proposals import app as proposals_app
28
31
  from tl_cli.commands.recommender import app as recommender_app
29
- from tl_cli.commands.sponsorships import app as sponsorships_app
30
- from tl_cli.commands.describe import app as describe_app
31
- from tl_cli.commands.schema import app as schema_app
32
- from tl_cli.commands.doctor import app as doctor_app
33
32
  from tl_cli.commands.reports import app as reports_app
34
- from tl_cli.commands.workflows import app as workflows_app
33
+ from tl_cli.commands.schema import app as schema_app
35
34
  from tl_cli.commands.setup import app as setup_app
36
- from tl_cli.commands.skills import app as skills_app, check_skill_staleness
35
+ from tl_cli.commands.skills import app as skills_app
36
+ from tl_cli.commands.skills import check_skill_staleness
37
37
  from tl_cli.commands.snapshots import app as snapshots_app
38
+ from tl_cli.commands.sponsorships import app as sponsorships_app
38
39
  from tl_cli.commands.uploads import app as uploads_app
39
40
  from tl_cli.commands.whoami import app as whoami_app
41
+ from tl_cli.commands.workflows import app as workflows_app
40
42
 
41
43
  app = typer.Typer(
42
44
  name="tl",
@@ -124,6 +126,7 @@ app.add_typer(balance_app, name="balance")
124
126
  app.add_typer(credits_app, name="credits")
125
127
  app.add_typer(doctor_app, name="doctor")
126
128
  app.add_typer(whoami_app, name="whoami")
129
+ app.add_typer(agent_app, name="agent")
127
130
 
128
131
  # `changelog` is a single command (not a sub-typer) so positional version args
129
132
  # don't get interpreted as subcommand names.
@@ -0,0 +1,81 @@
1
+ """Tests for `tl agent complete`: the skill reports its slug and outcome, and a
2
+ skill with no run behind it exits cleanly so the skill's own result survives."""
3
+
4
+ from unittest.mock import patch
5
+
6
+ from typer.testing import CliRunner
7
+
8
+ from tl_cli.client.errors import ApiError
9
+ from tl_cli.commands import agent as agent_mod
10
+ from tl_cli.main import app as root_app
11
+
12
+ runner = CliRunner()
13
+
14
+
15
+ class _FakeClient:
16
+ def __init__(self, payload: dict | None = None, error: ApiError | None = None) -> None:
17
+ self.payload = payload or {}
18
+ self.error = error
19
+ self.posts: list[tuple[str, dict]] = []
20
+
21
+ def post(self, path: str, json_body: dict | None = None, timeout: float | None = None) -> dict:
22
+ self.posts.append((path, json_body or {}))
23
+ if self.error is not None:
24
+ raise self.error
25
+ return self.payload
26
+
27
+ def close(self) -> None:
28
+ pass
29
+
30
+
31
+ def _done() -> dict:
32
+ return {
33
+ "run_id": "0123456789abcdef",
34
+ "skill": "tl-views-guarantee",
35
+ "outcome": "completed",
36
+ "usage": {"credits_charged": 0},
37
+ }
38
+
39
+
40
+ def test_reports_the_skill_with_the_default_outcome() -> None:
41
+ fake = _FakeClient(_done())
42
+ with patch.object(agent_mod, "get_client", return_value=fake):
43
+ result = runner.invoke(root_app, ["agent", "complete", "tl-views-guarantee", "--json"])
44
+ assert result.exit_code == 0, result.output
45
+ assert fake.posts == [("/agent/complete", {"skill": "tl-views-guarantee", "outcome": "completed"})]
46
+ assert '"run_id": "0123456789abcdef"' in result.output
47
+
48
+
49
+ def test_outcome_is_passed_through() -> None:
50
+ fake = _FakeClient(_done())
51
+ with patch.object(agent_mod, "get_client", return_value=fake):
52
+ result = runner.invoke(root_app, ["agent", "complete", "tl-channel-authenticity", "--outcome", "no_results"])
53
+ assert result.exit_code == 0, result.output
54
+ assert fake.posts[0][1] == {"skill": "tl-channel-authenticity", "outcome": "no_results"}
55
+
56
+
57
+ def test_unknown_outcome_is_refused_before_any_request() -> None:
58
+ fake = _FakeClient(_done())
59
+ with patch.object(agent_mod, "get_client", return_value=fake):
60
+ result = runner.invoke(root_app, ["agent", "complete", "tl-views-guarantee", "--outcome", "done"])
61
+ assert result.exit_code == 1
62
+ assert fake.posts == []
63
+
64
+
65
+ def test_a_skill_started_by_hand_exits_cleanly() -> None:
66
+ # The command sits at the end of a skill's script; a non-zero exit here would
67
+ # read as the skill failing, when it only has nothing to report.
68
+ error = ApiError(404, "No open run", raw={"code": "run_not_found"})
69
+ fake = _FakeClient(error=error)
70
+ with patch.object(agent_mod, "get_client", return_value=fake):
71
+ result = runner.invoke(root_app, ["agent", "complete", "tl-views-guarantee"])
72
+ assert result.exit_code == 0, result.output
73
+ assert "No open run of tl-views-guarantee" in result.stderr
74
+
75
+
76
+ def test_other_errors_still_fail() -> None:
77
+ error = ApiError(401, "Not signed in", raw={"code": "not_authenticated"})
78
+ fake = _FakeClient(error=error)
79
+ with patch.object(agent_mod, "get_client", return_value=fake), patch.object(agent_mod, "handle_api_error") as handled:
80
+ runner.invoke(root_app, ["agent", "complete", "tl-views-guarantee"])
81
+ handled.assert_called_once_with(error)
@@ -166,3 +166,21 @@ class TestTransientRetry:
166
166
  _use(monkeypatch, self._flaky(tmp_path, 1, "no such table"))
167
167
  with pytest.raises(tl_data.DataError, match="no such table"):
168
168
  tl_data.db_pg("SELECT 1")
169
+
170
+
171
+ class TestReportRun:
172
+ def test_reports_the_skill_and_outcome(self, tmp_path: Path, monkeypatch) -> None:
173
+ runner = _stub(tmp_path, exit_code=0, stdout="{}")
174
+ monkeypatch.setattr(tl_data, "TL_BIN", str(runner))
175
+ tl_data.report_run("tl-views-guarantee", "no_results")
176
+ call = json.loads((tmp_path / "call.json").read_text())
177
+ assert call["argv"] == ["agent", "complete", "tl-views-guarantee", "--outcome", "no_results"]
178
+
179
+ def test_never_raises(self, tmp_path: Path, monkeypatch) -> None:
180
+ # The report sits after the skill's own result; a missing or failing
181
+ # CLI must not turn a finished run into a crash.
182
+ monkeypatch.setattr(tl_data, "TL_BIN", str(tmp_path / "no-such-tl"))
183
+ tl_data.report_run("tl-views-guarantee")
184
+ runner = _stub(tmp_path, exit_code=3, stderr="server error")
185
+ monkeypatch.setattr(tl_data, "TL_BIN", str(runner))
186
+ tl_data.report_run("tl-views-guarantee", "failed")
@@ -422,7 +422,7 @@ wheels = [
422
422
 
423
423
  [[package]]
424
424
  name = "thoughtleaders-cli"
425
- version = "0.9.19"
425
+ version = "0.9.20"
426
426
  source = { editable = "." }
427
427
  dependencies = [
428
428
  { name = "authlib" },