thoughtleaders-cli 0.6.9__tar.gz → 0.6.11__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.9 → thoughtleaders_cli-0.6.11}/.claude-plugin/plugin.json +1 -1
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/AGENTS.md +1 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/PKG-INFO +5 -4
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/README.md +4 -3
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/agents/tl-analyst.md +1 -1
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/docs/architecture.md +9 -7
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/pyproject.toml +1 -1
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/SKILL.md +10 -28
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/__init__.py +1 -1
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/http.py +3 -0
- thoughtleaders_cli-0.6.11/src/tl_cli/commands/_comments_common.py +106 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/brands.py +2 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/channels.py +5 -9
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/sponsorships.py +7 -9
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/uploads.py +2 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/main.py +0 -2
- thoughtleaders_cli-0.6.9/src/tl_cli/commands/comments.py +0 -63
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/.claude-plugin/marketplace.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/.github/workflows/python-publish.yml +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/.gitignore +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/CLAUDE.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/LICENSE +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/commands/tl-balance.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/commands/tl-reports.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/commands/tl-sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/commands/tl.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/hooks/hooks.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/hooks/scripts/post-usage.sh +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/hooks/scripts/pre-check.sh +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/business-glossary.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/elasticsearch-schema.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/firebolt-schema.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/postgres-schema.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/SKILL.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/examples/golden_queries.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_brands.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_channels.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_content.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/report_glossary.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sortable_columns.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/references/widgets.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/column_builder.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/database_query.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/keyword_research.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/name_resolver.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/sample_judge.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/similar_channels.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl-report-builder/tools/widget_builder.md +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/_completions.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/__init__.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/commands.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/login.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/pkce.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/auth/token_store.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/__init__.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/client/errors.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/__init__.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/ask.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/balance.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/changelog.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/db.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/deals.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/describe.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/doctor.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/matches.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/proposals.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/recommender.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/reports.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/schema.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/setup.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/snapshots.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/commands/whoami.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/config.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/filters.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/hints.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/output/__init__.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/output/formatter.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/src/tl_cli/self_update.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/tests/__init__.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/tests/test_auth.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/tests/test_filters.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/tests/test_output.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/tests/test_sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/uv.lock +0 -0
|
@@ -95,6 +95,7 @@ The version string is defined in three files and all three must be updated toget
|
|
|
95
95
|
## Coding
|
|
96
96
|
|
|
97
97
|
* Do not reference internal architecture of the ThoughtLeaders app in comments or skills. Specifially: do not reference internal table names, field names, API endpoints, Python modules or functions (including the sanitizer).
|
|
98
|
+
* Do not let server implementation details into skill files (anything under `skills/`). Skills describe *what the CLI does* from the user's seat — observable command surface, inputs, outputs, examples. Do not say "the server enforces X", "the API validates Y on its side", "the backend rejects Z" — those are mechanism notes that drift the moment the server changes. State the user-visible behaviour ("unknown keys come back as 400") without naming where it's enforced.
|
|
98
99
|
* Place all imports at the start of the Python module file
|
|
99
100
|
|
|
100
101
|
# Git commit rules
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: thoughtleaders-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.11
|
|
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
|
|
@@ -125,9 +125,10 @@ tl brands show Nike
|
|
|
125
125
|
# Run a saved report
|
|
126
126
|
tl reports run 42
|
|
127
127
|
|
|
128
|
-
# Comments on
|
|
129
|
-
tl
|
|
130
|
-
tl
|
|
128
|
+
# Comments — available on sponsorships, channels, brands, and uploads
|
|
129
|
+
tl sponsorships comment-list 12345
|
|
130
|
+
tl sponsorships comment-add 12345 "Looks good"
|
|
131
|
+
tl channels comment-add 7890 "Strong recent winners"
|
|
131
132
|
|
|
132
133
|
# Show information about the logged-in user
|
|
133
134
|
tl whoami
|
|
@@ -98,9 +98,10 @@ tl brands show Nike
|
|
|
98
98
|
# Run a saved report
|
|
99
99
|
tl reports run 42
|
|
100
100
|
|
|
101
|
-
# Comments on
|
|
102
|
-
tl
|
|
103
|
-
tl
|
|
101
|
+
# Comments — available on sponsorships, channels, brands, and uploads
|
|
102
|
+
tl sponsorships comment-list 12345
|
|
103
|
+
tl sponsorships comment-add 12345 "Looks good"
|
|
104
|
+
tl channels comment-add 7890 "Strong recent winners"
|
|
104
105
|
|
|
105
106
|
# Show information about the logged-in user
|
|
106
107
|
tl whoami
|
|
@@ -64,7 +64,7 @@ tl db pg "SELECT a.id, a.send_date, a.publish_status, b.name AS brand, ch.channe
|
|
|
64
64
|
ORDER BY a.send_date
|
|
65
65
|
LIMIT 100 OFFSET 0"
|
|
66
66
|
```
|
|
67
|
-
Then suggest `tl
|
|
67
|
+
Then suggest `tl sponsorships comment-add <id> "..."` for each.
|
|
68
68
|
|
|
69
69
|
### Multi-step research (mix raw + similarity)
|
|
70
70
|
"Find channels similar to the ones Nike sponsors and compare their pricing"
|
|
@@ -56,8 +56,9 @@ All data commands use explicit subcommands: `list`, `show`, `create`/`add`. Runn
|
|
|
56
56
|
| `tl brands similar <brand>` | Find similar brands (similarity search, 25 credits) |
|
|
57
57
|
| `tl snapshots channel <id>` | Channel metrics over time (Firebolt channel_metrics) |
|
|
58
58
|
| `tl snapshots video <id> --channel <id>` | Video view curve (Firebolt article_metrics, --channel required) |
|
|
59
|
-
| `tl
|
|
60
|
-
| `tl
|
|
59
|
+
| `tl <entity> comment-list <id>` | List comments on a sponsorship/channel/brand/upload (free) |
|
|
60
|
+
| `tl <entity> comment-add <id> "message"` | Add a comment (free) |
|
|
61
|
+
| `tl <entity> comment-edit <comment-id> "message"` | Edit one of your own comments (author or superuser; free) |
|
|
61
62
|
|
|
62
63
|
### Raw database access (escape hatch for joins / aggregations / complex filters)
|
|
63
64
|
|
|
@@ -180,7 +181,7 @@ tools: [Bash, Read]
|
|
|
180
181
|
|
|
181
182
|
What the agent does:
|
|
182
183
|
- **Multi-step research**: "Find channels similar to the ones Nike sponsors and compare their pricing" → `tl brands show Nike --json` → extract initial channel IDs → `tl channels similar <initial-id> --json` for each (enriched with cpm) → union + dedupe → compile comparison table
|
|
183
|
-
- **Cross-resource analysis**: "Show me deal slippage and add comments" → `tl sponsorships status:pending send-date-end:2026-03 --json` → identify slipping sponsorships → `tl
|
|
184
|
+
- **Cross-resource analysis**: "Show me deal slippage and add comments" → `tl sponsorships status:pending send-date-end:2026-03 --json` → identify slipping sponsorships → `tl sponsorships comment-add <id> "flagged for slippage"` for each
|
|
184
185
|
- **Report comparison**: "Compare my Q1 report to Q4" → `tl reports run <id> --since 2026-01 --until 2026-03 --json` → `tl reports run <id> --since 2025-10 --until 2025-12 --json` → synthesize
|
|
185
186
|
- **Discovery workflows**: "What's my best performing brand this quarter" → `tl sponsorships status:sold purchase-date-start:2026-01 --json` → aggregate by brand → `tl brands show <top_brand> --json` → full picture
|
|
186
187
|
- **Credit-aware**: checks balance before multi-query workflows, estimates total cost, asks user to confirm if expensive
|
|
@@ -315,7 +316,7 @@ tl-cli/
|
|
|
315
316
|
│ │ ├── brands.py # tl brands (show/history/similar)
|
|
316
317
|
│ │ ├── snapshots.py # tl snapshots (Firebolt metrics)
|
|
317
318
|
│ │ ├── reports.py # tl reports / tl reports run
|
|
318
|
-
│ │ ├──
|
|
319
|
+
│ │ ├── _comments_common.py # comment-list/add/edit subcommands shared across entity apps
|
|
319
320
|
│ │ ├── db.py # tl db pg|fb|es (raw read-only queries)
|
|
320
321
|
│ │ ├── schema.py # tl schema pg|fb|es (live schema docs)
|
|
321
322
|
│ │ ├── describe.py # tl describe list/show (schema/filter/pricing discovery)
|
|
@@ -394,8 +395,9 @@ Most CLI endpoints can reuse existing views/utilities rather than being built fr
|
|
|
394
395
|
| **`GET /api/cli/v1/snapshots/video/<id>`** | `api/v2/article-history` (`ArticleHistoryView`) — already queries Firebolt `article_metrics` with pagination, enforces `channel_id:article_id` format. | Direct reuse — already enforces channel_id requirement |
|
|
395
396
|
| **`GET /api/cli/v1/reports`** | `api/campaigns` (`CampaignViewSet.list`) — returns user's saved campaigns with ownership filtering | Filter to user's campaigns, add CLI envelope |
|
|
396
397
|
| **`GET /api/cli/v1/reports/<id>/run`** | `api/campaigns/<id>` detail + the view's existing data loading via `load_campaign_data()` in `data_api_utils.py` — campaigns store their filter config, which gets passed to the appropriate data view (SponsorshipsView, ArticlesView, ThoughtleadersView) | Load campaign config → dispatch to appropriate existing view → wrap results |
|
|
397
|
-
| **`GET /api/cli/v1
|
|
398
|
-
| **`POST /api/cli/v1
|
|
398
|
+
| **`GET /api/cli/v1/<entity_type>/<entity_id>/comments`** | Same query against the `Comment` table; entity_type ∈ {sponsorship, channel, brand, upload} | List comments scoped to caller's organization |
|
|
399
|
+
| **`POST /api/cli/v1/<entity_type>/<entity_id>/comments`** | Insert into `Comment` with the matching FK column | Create comment for the named entity |
|
|
400
|
+
| **`PATCH /api/cli/v1/comment/<comment_id>`** | Update `Comment.content` after author/superuser check | Edit a single comment by ID |
|
|
399
401
|
| **`GET /api/cli/v1/whoami`** | New — reads Profile, Organization, brands M2M | New (joins Profile → User, Organization → Plan, Profile.brands → ChannelList) |
|
|
400
402
|
| **`GET /api/cli/v1/balance`** | New — reads `CliCreditAccount` | New (simple model read) |
|
|
401
403
|
| **`GET /api/cli/v1/describe`** | New — static metadata | New (hardcoded resource definitions) |
|
|
@@ -563,7 +565,7 @@ Build each command + its server endpoint together:
|
|
|
563
565
|
11. `tl snapshots video abc --channel 12345` returns view curve
|
|
564
566
|
12. `tl reports` lists saved reports (free)
|
|
565
567
|
13. `tl reports run 789` executes saved report (credits based on results)
|
|
566
|
-
14. `tl
|
|
568
|
+
14. `tl sponsorships comment-list 12345` lists comments (free) — same shape under `tl channels`, `tl brands`, `tl uploads`
|
|
567
569
|
15. `tl sponsorships create --channel 1 --brand 2` creates proposal (free)
|
|
568
570
|
16. `tl setup claude` installs plugin
|
|
569
571
|
17. Claude Code skill triggers on data questions, uses `tl describe` for discovery
|
|
@@ -141,7 +141,7 @@ Prefer writing Python code, shell code, or `jq` commands that fetche or analysis
|
|
|
141
141
|
tl sponsorships list [filters...] # Sponsorships — list curve, mult 1.0
|
|
142
142
|
tl sponsorships show <id> # Sponsorship detail (2 credits)
|
|
143
143
|
tl sponsorships create --channel <id> --brand <id> # Create proposal (free)
|
|
144
|
-
tl sponsorships update <id> '<json>' # Update
|
|
144
|
+
tl sponsorships update <id> '<json>' # Update a sponsorship (2 credits)
|
|
145
145
|
tl deals list [filters...] # Shortcut: agreed-upon sponsorships (status:deal); same curve as sponsorships list
|
|
146
146
|
tl deals show <id> # Deal detail (2 credits)
|
|
147
147
|
tl matches list [filters...] # Shortcut: possible brand-channel pairings (status:match); same curve
|
|
@@ -153,7 +153,7 @@ tl proposals create --channel <id> --brand <id> # Create proposal (free)
|
|
|
153
153
|
tl uploads list [filters...] # Video uploads from ES — list curve, mult 1.0
|
|
154
154
|
tl uploads show <id> # Upload detail (2 credits)
|
|
155
155
|
tl channels show <id-or-name> # Channel detail (2 credits; accepts numeric ID or name) — for channel search use raw SQL on thoughtleaders_channel
|
|
156
|
-
tl channels update <id> '<json>' # Update
|
|
156
|
+
tl channels update <id> '<json>' # Update a channel (2 credits)
|
|
157
157
|
tl channels history <id-or-name> # Sponsorship history (5 credits/result, linear)
|
|
158
158
|
tl channels similar <id-or-name> # Similarity recommender (25 credits flat; Intelligence plan)
|
|
159
159
|
tl brands show <id-or-name> # Brand detail (1 credit)
|
|
@@ -169,40 +169,24 @@ tl recommender top-brands "<tag>" # Top brands (deduped from profiles) load
|
|
|
169
169
|
tl recommender inspect-channel <ref> # Show a channel's similarity-profile breakdown (25 credits; Intelligence)
|
|
170
170
|
tl recommender inspect-brand <ref> # Show a brand profile's ideal similarity-profile breakdown (25 credits; Intelligence)
|
|
171
171
|
tl recommender similar-to-profile <id> # Channels closest to a brand profile's ideal profile (25 credits; Intelligence)
|
|
172
|
-
tl snapshots channel <id> # Channel metrics over time
|
|
173
|
-
tl snapshots video <id> --channel <id> # Video view curve
|
|
174
|
-
tl reports # List saved reports
|
|
172
|
+
tl snapshots channel <id> # Channel metrics over time (Firebolt-backed)
|
|
173
|
+
tl snapshots video <id> --channel <id> # Video view curve (--channel required!)
|
|
174
|
+
tl reports # List saved reports
|
|
175
175
|
tl reports run <id> # Run a saved report (credits vary)
|
|
176
|
-
tl
|
|
177
|
-
tl
|
|
176
|
+
tl <entity> comment-list <id> # List comments on a sponsorship/channel/brand/upload
|
|
177
|
+
tl <entity> comment-add <id> "msg" # Add a comment (free)
|
|
178
|
+
tl <entity> comment-edit <comment-id> "msg" # Edit own comment (author or superuser; free)
|
|
178
179
|
```
|
|
179
180
|
|
|
180
|
-
**
|
|
181
|
-
|
|
182
|
-
| Rows | mult=1.0 (comments, uploads, sponsorships) | mult=1.2 (snapshots) | mult=1.3 (reports) | mult=1.4 (db.pg / db.fb / db.es) |
|
|
183
|
-
|---:|---:|---:|---:|---:|
|
|
184
|
-
| 1 | 1 | 1 | 1 | 1 |
|
|
185
|
-
| 10 | 3 | 3 | 4 | 4 |
|
|
186
|
-
| 50 | 15 | 18 | 19 | 20 |
|
|
187
|
-
| 100 | 33 | 39 | 42 | 45 |
|
|
188
|
-
| 200 | 74 | 88 | 96 | 103 |
|
|
189
|
-
| 500 | 219 | 263 | 285 | 307 |
|
|
190
|
-
|
|
191
|
-
The marginal per-row cost is exactly proportional to `mult` — a 1.4× resource costs 1.4× the row part of a 1.0× resource at any size. Splitting a 500-row pull into ten 50-row calls saves ~30% but burns 10 setup floors instead of 1; "narrow the query" is almost always the better move than "fragment the pagination."
|
|
181
|
+
**Credit costs are server-authoritative — run `tl describe` (overview) or `tl describe show <resource>` (one resource) to see the current rates and multipliers for every endpoint. Do not memorise rate values — they change.**
|
|
192
182
|
|
|
193
183
|
### Updating records
|
|
194
184
|
|
|
195
|
-
A narrow write surface is exposed for two resources. Each command takes the record id and a single JSON object with the fields to change; the server enforces a hard-coded field whitelist and rejects anything else with a 400. Each call costs 2 credits.
|
|
196
|
-
|
|
197
185
|
```bash
|
|
198
186
|
tl sponsorships update <id> '<json>' # Edit a sponsorship (adlink)
|
|
199
187
|
tl channels update <id> '<json>' # Edit a channel
|
|
200
188
|
```
|
|
201
189
|
|
|
202
|
-
**Sponsorships** — only `publish_status` is editable. Accepts either an int code or a status label (`proposed`, `pending`, `sold`, `matched`, `outreach`, `proposal_approved`, `advertiser_reject`, `publisher_reject`, `agency_reject`, `unavailable`). Non-full-access users may only update sponsorships tied to their own organization (either through `creator_profile` or through the channel's `publication`). Trying to edit a sponsorship outside the user's org returns 403.
|
|
203
|
-
|
|
204
|
-
**Channels** — only the demographic fields are editable: `demographic_usa_share` and `demographic_male_share` (integers 0–100), `demographic_age` / `demographic_device` / `demographic_geo` (JSON objects with numeric values). Requires full-access permission; non-full-access users get a 403. The `demographics_updated_at` timestamp is refreshed automatically when any whitelisted demographic field changes.
|
|
205
|
-
|
|
206
190
|
Examples:
|
|
207
191
|
```bash
|
|
208
192
|
tl sponsorships update 98765 '{"publish_status": "sold"}'
|
|
@@ -212,7 +196,7 @@ tl channels update 12345 '{"demographic_geo": {"US": 60, "UK": 12, "CA": 8}}'
|
|
|
212
196
|
tl channels update 12345 '{"demographic_male_share": 55, "demographic_usa_share": 70}'
|
|
213
197
|
```
|
|
214
198
|
|
|
215
|
-
|
|
199
|
+
Each call costs 2 credits. If a request is rejected with a 400, the response body names the offending key — read it and retry with a smaller body. If the user wants to edit something the API rejects, the change has to be made in the app or by a human with DB access.
|
|
216
200
|
|
|
217
201
|
### Raw queries (`tl db`)
|
|
218
202
|
|
|
@@ -336,8 +320,6 @@ See [references/business-glossary.md](references/business-glossary.md) for reven
|
|
|
336
320
|
| Arbitrary read-only `SELECT` on Postgres | **Available** via `tl db pg`. | SELECT-only, mandatory `LIMIT ≤ 500` + `OFFSET`, only certain SQL forms are allowed. See `references/postgres-schema.md`. |
|
|
337
321
|
| Cross-reference helpers ("channels proposed to brand X", "channels sponsored by MBN brands in last N days") | **Available** via `tl db pg`. | Write the join: `thoughtleaders_adlink` ↔ `adspot` ↔ `channel` ↔ `profile` ↔ `profile_brands` ↔ `brand`. Filter by `publish_status` for proposed/sold and by date range as needed. See `references/postgres-schema.md` for the exact column names. |
|
|
338
322
|
| **AdLink INSERT** with custom price/cost/owner/`weighted_price`/`created_where` | **Unavailable** — `tl sponsorships create` exists but only creates a free *proposal* between a channel and a brand. The `tl db pg` sanitizer accepts SELECT only — no INSERT/UPDATE. | Done in the app or by a human with DB access. |
|
|
339
|
-
| **AdLink UPDATE** of any field other than `publish_status` (price, cost, owner, send_date, …) | **Unavailable** — `tl sponsorships update` only accepts `publish_status` and only for sponsorships in the user's org (full-access bypasses the org check). | Done in the app or by a human with DB access. |
|
|
340
|
-
| **Channel UPDATE** of any field other than the demographic fields (`demographic_usa_share`, `demographic_male_share`, `demographic_age`, `demographic_device`, `demographic_geo`) | **Unavailable** — `tl channels update` only accepts those fields, and only for full-access users. | Done in the app or by a human with DB access. |
|
|
341
323
|
| Pre-insert validation queries (joining `adspot ↔ channel ↔ profile ↔ org` to confirm MSN, integration=1, persona, plan) | **Available** via `tl db pg`. | One SELECT joining the four tables. Use `thoughtleaders_channel.media_selling_network_join_date IS NOT NULL` for MSN, `thoughtleaders_adspot.integration = 1` for mention adspots, `thoughtleaders_profile.persona` for the persona code (see persona constants in `references/postgres-schema.md`). |
|
|
342
324
|
| Firebolt cross-table or join queries; filtering on non-indexed columns in WHERE | **Unavailable** — not accepted. | Fetch a wider slice keyed on `channel_id` (and optionally `id`), filter the rest in `jq`/Python. |
|
|
343
325
|
| ES `query_string`, `regexp`, `wildcard`, `fuzzy`, `more_like_this`, parent/child joins; any `script_*`; multiple aggregations in one body | **Unavailable** — not accepted. | Rewrite using `term`/`terms`/`match`/`bool`/`nested`. For multi-agg dashboards, run multiple `tl db es` calls and combine client-side. For "similar"-style queries, try `tl channels similar` / `tl brands similar` (server-implemented similarity search). |
|
|
@@ -29,6 +29,9 @@ class TLClient:
|
|
|
29
29
|
def post(self, path: str, json_body: dict | None = None) -> dict:
|
|
30
30
|
return self._request("POST", path, json_body=json_body)
|
|
31
31
|
|
|
32
|
+
def patch(self, path: str, json_body: dict | None = None) -> dict:
|
|
33
|
+
return self._request("PATCH", path, json_body=json_body)
|
|
34
|
+
|
|
32
35
|
def _request(
|
|
33
36
|
self,
|
|
34
37
|
method: str,
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Shared helpers for entity comment subcommands.
|
|
2
|
+
|
|
3
|
+
Each entity (sponsorships, channels, brands, uploads) exposes
|
|
4
|
+
`comment-add`, `comment-list`, and `comment-edit` subcommands that
|
|
5
|
+
delegate to these helpers. Comments are free (no credits charged).
|
|
6
|
+
|
|
7
|
+
The server-side endpoints are:
|
|
8
|
+
GET/POST /<entity_type>/<entity_id>/comments
|
|
9
|
+
PATCH /comment/<comment_id>
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import typer
|
|
13
|
+
|
|
14
|
+
from tl_cli.client.errors import ApiError, handle_api_error
|
|
15
|
+
from tl_cli.client.http import get_client
|
|
16
|
+
from tl_cli.output.formatter import detect_format, output, output_single
|
|
17
|
+
|
|
18
|
+
COLUMNS = ["comment_id", "author", "text", "created_at"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def list_comments(entity_type: str, entity_id: str, json_output: bool, toon_output: bool) -> None:
|
|
22
|
+
fmt = detect_format(json_output, False, False, toon_output)
|
|
23
|
+
client = get_client()
|
|
24
|
+
try:
|
|
25
|
+
data = client.get(f"/{entity_type}/{entity_id}/comments")
|
|
26
|
+
for r in data.get("results", []):
|
|
27
|
+
r["comment_id"] = r.pop("id", None)
|
|
28
|
+
output(
|
|
29
|
+
data,
|
|
30
|
+
fmt,
|
|
31
|
+
columns=COLUMNS,
|
|
32
|
+
title=f"Comments on {entity_type} {entity_id}",
|
|
33
|
+
)
|
|
34
|
+
except ApiError as e:
|
|
35
|
+
handle_api_error(e)
|
|
36
|
+
finally:
|
|
37
|
+
client.close()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def add_comment(entity_type: str, entity_id: str, message: str, json_output: bool, toon_output: bool) -> None:
|
|
41
|
+
fmt = detect_format(json_output, False, False, toon_output)
|
|
42
|
+
client = get_client()
|
|
43
|
+
try:
|
|
44
|
+
data = client.post(f"/{entity_type}/{entity_id}/comments", json_body={"text": message})
|
|
45
|
+
for r in data.get("results", []):
|
|
46
|
+
r["comment_id"] = r.pop("id", None)
|
|
47
|
+
output_single(data, fmt)
|
|
48
|
+
except ApiError as e:
|
|
49
|
+
handle_api_error(e)
|
|
50
|
+
finally:
|
|
51
|
+
client.close()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def edit_comment(comment_id: int, message: str, json_output: bool, toon_output: bool) -> None:
|
|
55
|
+
fmt = detect_format(json_output, False, False, toon_output)
|
|
56
|
+
client = get_client()
|
|
57
|
+
try:
|
|
58
|
+
data = client.patch(f"/comment/{comment_id}", json_body={"text": message})
|
|
59
|
+
for r in data.get("results", []):
|
|
60
|
+
r["comment_id"] = r.pop("id", None)
|
|
61
|
+
output_single(data, fmt)
|
|
62
|
+
except ApiError as e:
|
|
63
|
+
handle_api_error(e)
|
|
64
|
+
finally:
|
|
65
|
+
client.close()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def register_comment_commands(app: typer.Typer, entity_type: str, entity_label: str) -> None:
|
|
69
|
+
"""Register comment-list / comment-add / comment-edit subcommands on `app`.
|
|
70
|
+
|
|
71
|
+
`entity_type` matches the server URL segment (sponsorship / channel /
|
|
72
|
+
brand / upload). `entity_label` is the user-facing word shown in help
|
|
73
|
+
text (e.g. "sponsorship", "channel").
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
@app.command("comment-list")
|
|
77
|
+
def comment_list(
|
|
78
|
+
entity_id: str = typer.Argument(..., help=f"{entity_label.capitalize()} ID"),
|
|
79
|
+
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
80
|
+
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
81
|
+
) -> None:
|
|
82
|
+
f"""List comments on a {entity_label} (free, no credits)."""
|
|
83
|
+
list_comments(entity_type, entity_id, json_output, toon_output)
|
|
84
|
+
|
|
85
|
+
@app.command("comment-add")
|
|
86
|
+
def comment_add(
|
|
87
|
+
entity_id: str = typer.Argument(..., help=f"{entity_label.capitalize()} ID"),
|
|
88
|
+
message: str = typer.Argument(..., help="Comment text"),
|
|
89
|
+
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
90
|
+
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
91
|
+
) -> None:
|
|
92
|
+
f"""Add a comment to a {entity_label} (free, no credits)."""
|
|
93
|
+
add_comment(entity_type, entity_id, message, json_output, toon_output)
|
|
94
|
+
|
|
95
|
+
@app.command("comment-edit")
|
|
96
|
+
def comment_edit(
|
|
97
|
+
comment_id: int = typer.Argument(..., help="Comment ID"),
|
|
98
|
+
message: str = typer.Argument(..., help="New comment text"),
|
|
99
|
+
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
100
|
+
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
101
|
+
) -> None:
|
|
102
|
+
"""Edit an existing comment (free, no credits).
|
|
103
|
+
|
|
104
|
+
Only the comment's author can edit it (superusers can edit any comment).
|
|
105
|
+
"""
|
|
106
|
+
edit_comment(comment_id, message, json_output, toon_output)
|
|
@@ -8,10 +8,12 @@ from rich.console import Console
|
|
|
8
8
|
|
|
9
9
|
from tl_cli.client.errors import ApiError, handle_api_error
|
|
10
10
|
from tl_cli.client.http import get_client
|
|
11
|
+
from tl_cli.commands._comments_common import register_comment_commands
|
|
11
12
|
from tl_cli.hints import detail_hint
|
|
12
13
|
from tl_cli.output.formatter import detect_format, output, output_single
|
|
13
14
|
|
|
14
15
|
app = typer.Typer(help="Brand intelligence (detail, sponsorship history, channel mentions)")
|
|
16
|
+
register_comment_commands(app, "brand", "brand")
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
@app.callback(invoke_without_command=True)
|
|
@@ -8,11 +8,13 @@ from rich.console import Console
|
|
|
8
8
|
|
|
9
9
|
from tl_cli.client.errors import ApiError, handle_api_error
|
|
10
10
|
from tl_cli.client.http import get_client
|
|
11
|
+
from tl_cli.commands._comments_common import register_comment_commands
|
|
11
12
|
from tl_cli.filters import parse_filters
|
|
12
13
|
from tl_cli.hints import detail_hint
|
|
13
14
|
from tl_cli.output.formatter import detect_format, output, output_single
|
|
14
15
|
|
|
15
16
|
app = typer.Typer(help="YouTube channels (detail, history, and similar-channel recommendations)")
|
|
17
|
+
register_comment_commands(app, "channel", "channel")
|
|
16
18
|
|
|
17
19
|
# Columns for the `similar` endpoint result table. The server enriches every
|
|
18
20
|
# row so the user can size up each suggestion without follow-up queries.
|
|
@@ -236,19 +238,13 @@ def history_cmd(
|
|
|
236
238
|
@app.command("update")
|
|
237
239
|
def update_cmd(
|
|
238
240
|
channel_id: int = typer.Argument(..., help="Channel ID (numeric)"),
|
|
239
|
-
fields: str = typer.Argument(..., help='JSON object of fields to update
|
|
241
|
+
fields: str = typer.Argument(..., help='JSON object of fields to update'),
|
|
240
242
|
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
241
243
|
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
242
244
|
) -> None:
|
|
243
|
-
"""Update
|
|
245
|
+
"""Update a channel.
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
demographic_age, demographic_device, demographic_geo. The
|
|
247
|
-
demographics_updated_at timestamp is refreshed automatically.
|
|
248
|
-
|
|
249
|
-
Examples:
|
|
250
|
-
tl channels update 12345 '{"demographic_male_share": 62}'
|
|
251
|
-
tl channels update 12345 '{"demographic_geo": {"US": 60, "UK": 12}}'
|
|
247
|
+
Unknown fields are rejected with a 400 listing the offending key.
|
|
252
248
|
"""
|
|
253
249
|
fmt = detect_format(json_output, False, False, toon_output)
|
|
254
250
|
try:
|
|
@@ -8,6 +8,7 @@ from rich.console import Console
|
|
|
8
8
|
|
|
9
9
|
from tl_cli.client.errors import handle_api_error, ApiError
|
|
10
10
|
from tl_cli.client.http import get_client
|
|
11
|
+
from tl_cli.commands._comments_common import register_comment_commands
|
|
11
12
|
from tl_cli.filters import parse_filters
|
|
12
13
|
from tl_cli.hints import detail_hint
|
|
13
14
|
from tl_cli.output.formatter import detect_format, output, output_single
|
|
@@ -197,19 +198,13 @@ def create_cmd(
|
|
|
197
198
|
@app.command("update")
|
|
198
199
|
def update_cmd(
|
|
199
200
|
sponsorship_id: int = typer.Argument(..., help="Sponsorship (adlink) ID"),
|
|
200
|
-
fields: str = typer.Argument(..., help='JSON object of fields to update
|
|
201
|
+
fields: str = typer.Argument(..., help='JSON object of fields to update'),
|
|
201
202
|
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
202
203
|
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
203
204
|
) -> None:
|
|
204
|
-
"""Update
|
|
205
|
+
"""Update a sponsorship.
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
'pending', 'matched'). Non-full-access users may only update sponsorships
|
|
208
|
-
tied to their own organization.
|
|
209
|
-
|
|
210
|
-
Examples:
|
|
211
|
-
tl sponsorships update 98765 '{"publish_status": "sold"}'
|
|
212
|
-
tl sponsorships update 98765 '{"publish_status": 3}'
|
|
207
|
+
Unknown fields are rejected with a 400 listing the offending key.
|
|
213
208
|
"""
|
|
214
209
|
fmt = detect_format(json_output, False, False, toon_output)
|
|
215
210
|
try:
|
|
@@ -229,3 +224,6 @@ def update_cmd(
|
|
|
229
224
|
handle_api_error(e)
|
|
230
225
|
finally:
|
|
231
226
|
client.close()
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
register_comment_commands(app, "sponsorship", "sponsorship")
|
|
@@ -4,10 +4,12 @@ import typer
|
|
|
4
4
|
|
|
5
5
|
from tl_cli.client.errors import ApiError, handle_api_error
|
|
6
6
|
from tl_cli.client.http import get_client
|
|
7
|
+
from tl_cli.commands._comments_common import register_comment_commands
|
|
7
8
|
from tl_cli.filters import parse_filters
|
|
8
9
|
from tl_cli.output.formatter import detect_format, output, output_single
|
|
9
10
|
|
|
10
11
|
app = typer.Typer(help="Video uploads (YouTube content from Elasticsearch)")
|
|
12
|
+
register_comment_commands(app, "upload", "upload")
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
@app.callback(invoke_without_command=True)
|
|
@@ -17,7 +17,6 @@ from tl_cli.commands.balance import app as balance_app
|
|
|
17
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.channels import app as channels_app
|
|
20
|
-
from tl_cli.commands.comments import app as comments_app
|
|
21
20
|
from tl_cli.commands.db import app as db_app
|
|
22
21
|
from tl_cli.commands.deals import app as deals_app
|
|
23
22
|
from tl_cli.commands.matches import app as matches_app
|
|
@@ -94,7 +93,6 @@ app.add_typer(brands_app, name="brands")
|
|
|
94
93
|
app.add_typer(recommender_app, name="recommender")
|
|
95
94
|
app.add_typer(snapshots_app, name="snapshots")
|
|
96
95
|
app.add_typer(reports_app, name="reports")
|
|
97
|
-
app.add_typer(comments_app, name="comments")
|
|
98
96
|
app.add_typer(db_app, name="db")
|
|
99
97
|
|
|
100
98
|
# Discoverability
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"""tl comments — List and add comments on sponsorships."""
|
|
2
|
-
|
|
3
|
-
import typer
|
|
4
|
-
|
|
5
|
-
from tl_cli.client.errors import ApiError, handle_api_error
|
|
6
|
-
from tl_cli.client.http import get_client
|
|
7
|
-
from tl_cli.output.formatter import detect_format, output, output_single
|
|
8
|
-
|
|
9
|
-
app = typer.Typer(help="Comments on sponsorships (free, no credits)")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@app.command("list")
|
|
13
|
-
def list_cmd(
|
|
14
|
-
adlink_id: int = typer.Argument(..., help="Sponsorship (adlink) ID"),
|
|
15
|
-
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
16
|
-
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
17
|
-
) -> None:
|
|
18
|
-
"""List comments on a sponsorship (free, no credits).
|
|
19
|
-
|
|
20
|
-
Examples:
|
|
21
|
-
tl comments list 12345
|
|
22
|
-
"""
|
|
23
|
-
fmt = detect_format(json_output, False, False, toon_output)
|
|
24
|
-
|
|
25
|
-
client = get_client()
|
|
26
|
-
try:
|
|
27
|
-
data = client.get(f"/comments/{adlink_id}")
|
|
28
|
-
for r in data.get("results", []):
|
|
29
|
-
r["comment_id"] = r.pop("id", None)
|
|
30
|
-
output(
|
|
31
|
-
data,
|
|
32
|
-
fmt,
|
|
33
|
-
columns=["comment_id", "author", "text", "created_at"],
|
|
34
|
-
title=f"Comments on Sponsorship #{adlink_id}",
|
|
35
|
-
)
|
|
36
|
-
except ApiError as e:
|
|
37
|
-
handle_api_error(e)
|
|
38
|
-
finally:
|
|
39
|
-
client.close()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@app.command("add")
|
|
43
|
-
def add_comment(
|
|
44
|
-
adlink_id: int = typer.Argument(..., help="Sponsorship (adlink) ID"),
|
|
45
|
-
message: str = typer.Argument(..., help="Comment text"),
|
|
46
|
-
json_output: bool = typer.Option(False, "--json", help="JSON output"),
|
|
47
|
-
toon_output: bool = typer.Option(False, "--toon", help="TOON output (token-efficient for LLMs)"),
|
|
48
|
-
) -> None:
|
|
49
|
-
"""Add a comment to a sponsorship (free, no credits).
|
|
50
|
-
|
|
51
|
-
Examples:
|
|
52
|
-
tl comments add 12345 "Looks good, ready to send"
|
|
53
|
-
"""
|
|
54
|
-
fmt = detect_format(json_output, False, False, toon_output)
|
|
55
|
-
|
|
56
|
-
client = get_client()
|
|
57
|
-
try:
|
|
58
|
-
data = client.post(f"/comments/{adlink_id}", json_body={"text": message})
|
|
59
|
-
output_single(data, fmt)
|
|
60
|
-
except ApiError as e:
|
|
61
|
-
handle_api_error(e)
|
|
62
|
-
finally:
|
|
63
|
-
client.close()
|
|
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.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/business-glossary.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/elasticsearch-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/firebolt-schema.md
RENAMED
|
File without changes
|
{thoughtleaders_cli-0.6.9 → thoughtleaders_cli-0.6.11}/skills/tl/references/postgres-schema.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|