thoughtleaders-cli 0.6.39__tar.gz → 0.6.40__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 (93) hide show
  1. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/PKG-INFO +1 -1
  3. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/pyproject.toml +1 -1
  4. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/__init__.py +1 -1
  5. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/doctor.py +6 -2
  6. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/setup.py +161 -37
  7. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/self_update.py +6 -1
  8. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/.claude-plugin/marketplace.json +0 -0
  9. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/.github/workflows/python-publish.yml +0 -0
  10. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/.gitignore +0 -0
  11. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/AGENTS.md +0 -0
  12. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/CLAUDE.md +0 -0
  13. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/LICENSE +0 -0
  14. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/README.md +0 -0
  15. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/agents/tl-analyst.md +0 -0
  16. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/docs/architecture.md +0 -0
  17. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/hooks/hooks.json +0 -0
  18. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/hooks/scripts/load-tl-skill.mjs +0 -0
  19. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/hooks/scripts/post-usage.sh +0 -0
  20. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/hooks/scripts/pre-check.sh +0 -0
  21. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl/SKILL.md +0 -0
  22. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl/references/business-glossary.md +0 -0
  23. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl/references/elasticsearch-schema.md +0 -0
  24. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl/references/firebolt-schema.md +0 -0
  25. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl/references/postgres-schema.md +0 -0
  26. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-import/SKILL.md +0 -0
  27. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/SKILL.md +0 -0
  28. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
  29. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/examples/golden_queries.md +0 -0
  30. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/columns_brands.md +0 -0
  31. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/columns_channels.md +0 -0
  32. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/columns_content.md +0 -0
  33. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
  34. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/intelligence_filterset_schema.json +0 -0
  35. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
  36. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/report_glossary.md +0 -0
  37. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/sortable_columns.json +0 -0
  38. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
  39. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
  40. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/references/widgets.md +0 -0
  41. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/column_builder.md +0 -0
  42. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/database_query.md +0 -0
  43. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/keyword_research.md +0 -0
  44. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/name_resolver.md +0 -0
  45. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/sample_judge.md +0 -0
  46. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/similar_channels.md +0 -0
  47. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
  48. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/skills/tl-report-builder/tools/widget_builder.md +0 -0
  49. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/_completions.py +0 -0
  50. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/__init__.py +0 -0
  51. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/commands.py +0 -0
  52. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/finalize.py +0 -0
  53. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/login.py +0 -0
  54. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/pkce.py +0 -0
  55. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/auth/token_store.py +0 -0
  56. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/client/__init__.py +0 -0
  57. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/client/errors.py +0 -0
  58. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/client/http.py +0 -0
  59. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/__init__.py +0 -0
  60. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/_comments_common.py +0 -0
  61. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/ask.py +0 -0
  62. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/balance.py +0 -0
  63. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/brands.py +0 -0
  64. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/bulk_import.py +0 -0
  65. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/changelog.py +0 -0
  66. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/channels.py +0 -0
  67. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/credits.py +0 -0
  68. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/db.py +0 -0
  69. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/deals.py +0 -0
  70. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/describe.py +0 -0
  71. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/matches.py +0 -0
  72. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/proposals.py +0 -0
  73. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/recommender.py +0 -0
  74. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/reports.py +0 -0
  75. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/schema.py +0 -0
  76. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/snapshots.py +0 -0
  77. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/sponsorships.py +0 -0
  78. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/uploads.py +0 -0
  79. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/commands/whoami.py +0 -0
  80. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/config.py +0 -0
  81. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/filters.py +0 -0
  82. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/hints.py +0 -0
  83. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/main.py +0 -0
  84. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/output/__init__.py +0 -0
  85. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/src/tl_cli/output/formatter.py +0 -0
  86. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/__init__.py +0 -0
  87. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_auth.py +0 -0
  88. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_filters.py +0 -0
  89. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_http_auth.py +0 -0
  90. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_output.py +0 -0
  91. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_reports.py +0 -0
  92. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/tests/test_sponsorships.py +0 -0
  93. {thoughtleaders_cli-0.6.39 → thoughtleaders_cli-0.6.40}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.6.39",
3
+ "version": "0.6.40",
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.4
2
2
  Name: thoughtleaders-cli
3
- Version: 0.6.39
3
+ Version: 0.6.40
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.6.39"
7
+ version = "0.6.40"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence."""
2
2
 
3
- __version__ = "0.6.39"
3
+ __version__ = "0.6.40"
@@ -148,10 +148,14 @@ def doctor(ctx: typer.Context) -> None:
148
148
  console.print(" Auth: [red]not logged in[/red]")
149
149
  all_ok = False
150
150
  elif tokens.is_expired:
151
- console.print(f" Auth: [yellow]token expired[/yellow] ({tokens.email})")
151
+ console.print(
152
+ f" Auth: [yellow]token expired[/yellow] (OAuth2, {tokens.email})"
153
+ )
152
154
  all_ok = False
153
155
  else:
154
- console.print(f" Auth: [green]ok[/green] ({tokens.email})")
156
+ method = "API key" if tokens.is_api_key else "OAuth2"
157
+ identity = tokens.email or ("via API key" if tokens.is_api_key else "unknown")
158
+ console.print(f" Auth: [green]ok[/green] ({method}, {identity})")
155
159
 
156
160
  # Connectivity + balance + latency timing. The first /balance call
157
161
  # doubles as the connectivity probe; subsequent calls feed the
@@ -1,4 +1,11 @@
1
- """tl setup — Install Claude Code plugin and other integrations."""
1
+ """tl setup — Install Claude Code plugin and other integrations.
2
+
3
+ Agents-style installs (Gemini / Codex): both CLIs read skills from
4
+ `~/.agents/skills/`, so they share a single install target. Any `tl
5
+ setup …` command that installs skill files also mirrors them there
6
+ whenever either `gemini` or `codex` is on PATH. Behaviour follows the
7
+ OpenCode pattern (full per-skill tree copy, .tl-version stamp).
8
+ """
2
9
 
3
10
  import json
4
11
  import shutil
@@ -10,7 +17,7 @@ from rich.console import Console
10
17
 
11
18
  from tl_cli import __version__
12
19
 
13
- app = typer.Typer(help="Set up integrations (Claude Code, OpenCode)")
20
+ app = typer.Typer(help="Set up integrations (Claude Code, OpenCode, Gemini, Codex)")
14
21
  console = Console(stderr=True)
15
22
 
16
23
  MARKETPLACE_SOURCE = "ThoughtLeaders-io/thoughtleaders-cli"
@@ -25,6 +32,13 @@ CLAUDE_COMMANDS_DIR = CLAUDE_HOME / "commands"
25
32
 
26
33
  OPENCODE_SKILLS_DIR = Path.home() / ".config" / "opencode" / "skills"
27
34
 
35
+ # Shared install target for the "agents-style" CLIs that read skills from
36
+ # `~/.agents/skills/`. Whenever any of these binaries is on PATH we mirror
37
+ # the skill tree there once — the directory is the same regardless of
38
+ # which CLI triggered the install.
39
+ AGENTS_SKILLS_DIR = Path.home() / ".agents" / "skills"
40
+ AGENTS_SKILLS_BINARIES = ("gemini", "codex")
41
+
28
42
 
29
43
  def _find_plugin_root() -> Path | None:
30
44
  """Locate the plugin assets directory.
@@ -97,6 +111,16 @@ def check_plugin_version() -> list[str]:
97
111
  if installed != __version__:
98
112
  warnings.append(f"OpenCode skill is outdated (v{installed} vs CLI v{__version__}). Run 'tl setup opencode' to update.")
99
113
 
114
+ # Gemini / Codex (shared ~/.agents/skills/ target)
115
+ agents_version_file = AGENTS_SKILLS_DIR / ".tl-version"
116
+ if agents_version_file.exists():
117
+ installed = agents_version_file.read_text().strip()
118
+ if installed != __version__:
119
+ warnings.append(
120
+ f"Gemini/Codex skills are outdated (v{installed} vs CLI v{__version__}). "
121
+ f"Run 'tl setup gemini' or 'tl setup codex' to update."
122
+ )
123
+
100
124
  return warnings
101
125
 
102
126
 
@@ -308,68 +332,95 @@ def _setup_noninteractive() -> None:
308
332
  # --- OpenCode setup ---
309
333
 
310
334
 
311
- def _install_opencode_skills(plugin_root: Path) -> int:
312
- """Copy skills to ~/.config/opencode/skills/ for OpenCode discovery.
335
+ def _install_skill_trees(plugin_root: Path, target_dir: Path) -> int:
336
+ """Copy every `skills/<name>/` tree under `plugin_root` into `target_dir`.
313
337
 
314
- Returns the number of skills installed.
338
+ Shared primitive used by every "external agent" install path
339
+ (OpenCode, Gemini, Codex) — each agent reads skills from a different
340
+ base directory, so we just parameterise on that. A `.tl-version`
341
+ stamp is written into the target so `check_plugin_version()` can
342
+ detect drift later. Returns the number of skills installed.
315
343
  """
316
344
  count = 0
317
345
  skills_src = plugin_root / "skills"
318
346
  if skills_src.is_dir():
319
347
  for skill_dir in skills_src.iterdir():
320
348
  if skill_dir.is_dir() and (skill_dir / "SKILL.md").is_file():
321
- dst = OPENCODE_SKILLS_DIR / skill_dir.name
349
+ dst = target_dir / skill_dir.name
322
350
  if dst.exists():
323
351
  shutil.rmtree(dst)
324
352
  shutil.copytree(skill_dir, dst)
325
353
  count += 1
354
+ if count > 0 or target_dir.exists():
355
+ target_dir.mkdir(parents=True, exist_ok=True)
356
+ (target_dir / ".tl-version").write_text(__version__)
326
357
  return count
327
358
 
328
359
 
329
- @app.command("opencode")
330
- def setup_opencode(
331
- json_output: bool = typer.Option(False, "--json", help="JSON output (non-interactive)"),
332
- ) -> None:
333
- """Install the TL CLI skills for OpenCode.
360
+ # Back-compat names — both delegate to the shared primitive. Kept so other
361
+ # modules that import them continue to work without changes.
362
+ def _install_opencode_skills(plugin_root: Path) -> int:
363
+ return _install_skill_trees(plugin_root, OPENCODE_SKILLS_DIR)
334
364
 
335
- Copies skill files to ~/.config/opencode/skills/ so OpenCode's
336
- agent can discover and use them automatically.
337
365
 
338
- Examples:
339
- tl setup opencode
340
- tl setup opencode --json
366
+ def _install_agents_skills(plugin_root: Path) -> int:
367
+ return _install_skill_trees(plugin_root, AGENTS_SKILLS_DIR)
368
+
369
+
370
+ def _setup_external_agent(
371
+ *,
372
+ agent_label: str,
373
+ agent_binary: str,
374
+ command_name: str,
375
+ target_dir: Path,
376
+ post_install_lines: list[str] | None,
377
+ json_output: bool,
378
+ ) -> None:
379
+ """Shared body for the OpenCode / Gemini / Codex setup commands.
380
+
381
+ All three follow the same shape: copy skill trees into a target
382
+ directory, stamp a `.tl-version` file, print a status report.
383
+ Arguments customise the diagnostic text and the install target.
384
+ Auto-discovery between agents has been intentionally removed —
385
+ `tl update` is responsible for re-syncing every detected agent
386
+ after a self-upgrade; the per-agent setup commands stay scoped to
387
+ their one agent.
341
388
  """
389
+ plugin_root = _find_plugin_root()
390
+
342
391
  if json_output:
343
- result = {"cli_version": __version__}
344
- plugin_root = _find_plugin_root()
392
+ result: dict = {"cli_version": __version__}
345
393
  if plugin_root is None:
346
394
  result["status"] = "error"
347
395
  result["error"] = "Plugin assets not found"
348
396
  print(json.dumps(result, indent=2))
349
397
  raise SystemExit(1)
350
- count = _install_opencode_skills(plugin_root)
351
- OPENCODE_SKILLS_DIR.mkdir(parents=True, exist_ok=True)
352
- (OPENCODE_SKILLS_DIR / ".tl-version").write_text(__version__)
398
+ result[f"{agent_binary}_detected"] = shutil.which(agent_binary) is not None
399
+ count = _install_skill_trees(plugin_root, target_dir)
353
400
  result["skills_installed"] = count
401
+ result["install_dir"] = str(target_dir)
354
402
  result["status"] = "ok"
355
403
  print(json.dumps(result, indent=2))
356
404
  return
357
405
 
358
406
  console.print()
359
- console.print(f"[bold]tl-cli[/bold] v{__version__} — OpenCode Setup")
407
+ console.print(f"[bold]tl-cli[/bold] v{__version__} — {agent_label} Setup")
360
408
  console.print()
361
409
 
362
- # Check tl is on PATH
363
410
  tl_bin = shutil.which("tl")
364
411
  if tl_bin:
365
412
  console.print(f" [green]✓[/green] tl CLI found: {tl_bin}")
366
413
  else:
367
414
  console.print(" [red]✗[/red] tl CLI not found on PATH")
368
- console.print(" OpenCode's Bash tool won't be able to run tl commands.")
415
+ console.print(f" {agent_label}'s shell tool won't be able to run tl commands.")
369
416
  console.print(" Install with: [cyan]pipx install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git[/cyan]")
370
417
 
371
- # Find plugin assets
372
- plugin_root = _find_plugin_root()
418
+ agent_bin = shutil.which(agent_binary)
419
+ if agent_bin:
420
+ console.print(f" [green]✓[/green] {agent_binary} binary found: {agent_bin}")
421
+ else:
422
+ console.print(f" [yellow]![/yellow] {agent_binary} binary not found on PATH (installing skills anyway)")
423
+
373
424
  if plugin_root is None:
374
425
  console.print(" [red]✗[/red] Plugin assets not found")
375
426
  console.print(" Try reinstalling: [cyan]pipx install --force git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git[/cyan]")
@@ -377,23 +428,96 @@ def setup_opencode(
377
428
  console.print(f" [green]✓[/green] Plugin assets found: {plugin_root}")
378
429
  console.print()
379
430
 
380
- # Install skills
381
431
  console.print("[bold]Installing skills...[/bold]")
382
- count = _install_opencode_skills(plugin_root)
432
+ count = _install_skill_trees(plugin_root, target_dir)
383
433
  if count > 0:
384
- console.print(f" [green]✓[/green] Installed {count} skill(s) to {OPENCODE_SKILLS_DIR}/")
434
+ console.print(f" [green]✓[/green] Installed {count} skill(s) to {target_dir}/")
385
435
  else:
386
436
  console.print(" [yellow]![/yellow] No skills found to install")
387
437
  raise SystemExit(1)
388
438
 
389
- # Write version stamp
390
- OPENCODE_SKILLS_DIR.mkdir(parents=True, exist_ok=True)
391
- (OPENCODE_SKILLS_DIR / ".tl-version").write_text(__version__)
392
-
393
439
  console.print()
394
440
  console.print("[green]Setup complete![/green]")
395
441
  console.print()
396
- console.print("OpenCode will automatically discover the tl skill.")
397
- console.print("The agent can use it when you ask about sponsorships, deals, channels, or brands.")
398
- console.print()
399
- console.print("[dim]To update, run: tl setup opencode[/dim]")
442
+ for line in post_install_lines or []:
443
+ console.print(line)
444
+ if post_install_lines:
445
+ console.print()
446
+ console.print(f"[dim]To update, run: tl setup {command_name}[/dim]")
447
+
448
+
449
+ @app.command("opencode")
450
+ def setup_opencode(
451
+ json_output: bool = typer.Option(False, "--json", help="JSON output (non-interactive)"),
452
+ ) -> None:
453
+ """Install the TL CLI skills for OpenCode.
454
+
455
+ Copies skill files to ~/.config/opencode/skills/ so OpenCode's
456
+ agent can discover and use them automatically.
457
+
458
+ Examples:
459
+ tl setup opencode
460
+ tl setup opencode --json
461
+ """
462
+ _setup_external_agent(
463
+ agent_label="OpenCode",
464
+ agent_binary="opencode",
465
+ command_name="opencode",
466
+ target_dir=OPENCODE_SKILLS_DIR,
467
+ post_install_lines=[
468
+ "OpenCode will automatically discover the tl skill.",
469
+ "The agent can use it when you ask about sponsorships, deals, channels, or brands.",
470
+ ],
471
+ json_output=json_output,
472
+ )
473
+
474
+
475
+ # --- Gemini / Codex setup (shared ~/.agents/skills/ target) ---
476
+
477
+
478
+ @app.command("gemini")
479
+ def setup_gemini(
480
+ json_output: bool = typer.Option(False, "--json", help="JSON output (non-interactive)"),
481
+ ) -> None:
482
+ """Install the TL CLI skills for the Gemini CLI.
483
+
484
+ Copies skill files to ~/.agents/skills/ so the Gemini CLI can
485
+ discover and use them automatically. Shares its install target with
486
+ `tl setup codex` — running either installs the same files.
487
+
488
+ Examples:
489
+ tl setup gemini
490
+ tl setup gemini --json
491
+ """
492
+ _setup_external_agent(
493
+ agent_label="Gemini",
494
+ agent_binary="gemini",
495
+ command_name="gemini",
496
+ target_dir=AGENTS_SKILLS_DIR,
497
+ post_install_lines=None,
498
+ json_output=json_output,
499
+ )
500
+
501
+
502
+ @app.command("codex")
503
+ def setup_codex(
504
+ json_output: bool = typer.Option(False, "--json", help="JSON output (non-interactive)"),
505
+ ) -> None:
506
+ """Install the TL CLI skills for the Codex CLI.
507
+
508
+ Copies skill files to ~/.agents/skills/ so the Codex CLI can
509
+ discover and use them automatically. Shares its install target with
510
+ `tl setup gemini` — running either installs the same files.
511
+
512
+ Examples:
513
+ tl setup codex
514
+ tl setup codex --json
515
+ """
516
+ _setup_external_agent(
517
+ agent_label="Codex",
518
+ agent_binary="codex",
519
+ command_name="codex",
520
+ target_dir=AGENTS_SKILLS_DIR,
521
+ post_install_lines=None,
522
+ json_output=json_output,
523
+ )
@@ -405,7 +405,12 @@ def _resync_integrations() -> None:
405
405
  tl_bin = shutil.which("tl")
406
406
  if not tl_bin:
407
407
  return
408
- for tool, binary in (("claude", "claude"), ("opencode", "opencode")):
408
+ for tool, binary in (
409
+ ("claude", "claude"),
410
+ ("opencode", "opencode"),
411
+ ("gemini", "gemini"),
412
+ ("codex", "codex"),
413
+ ):
409
414
  if not shutil.which(binary):
410
415
  continue
411
416
  print(f"[tl-cli] re-syncing {tool} skills…", file=sys.stderr)