scitex 2.14.0__py3-none-any.whl → 2.15.3__py3-none-any.whl

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 (264) hide show
  1. scitex/__init__.py +71 -17
  2. scitex/_env_loader.py +156 -0
  3. scitex/_mcp_resources/__init__.py +37 -0
  4. scitex/_mcp_resources/_cheatsheet.py +135 -0
  5. scitex/_mcp_resources/_figrecipe.py +138 -0
  6. scitex/_mcp_resources/_formats.py +102 -0
  7. scitex/_mcp_resources/_modules.py +337 -0
  8. scitex/_mcp_resources/_session.py +149 -0
  9. scitex/_mcp_tools/__init__.py +4 -0
  10. scitex/_mcp_tools/audio.py +66 -0
  11. scitex/_mcp_tools/diagram.py +11 -95
  12. scitex/_mcp_tools/introspect.py +210 -0
  13. scitex/_mcp_tools/plt.py +260 -305
  14. scitex/_mcp_tools/scholar.py +74 -0
  15. scitex/_mcp_tools/social.py +27 -0
  16. scitex/_mcp_tools/template.py +24 -0
  17. scitex/_mcp_tools/writer.py +17 -210
  18. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  19. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  20. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  21. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  22. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  23. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  24. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  25. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  26. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  27. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  28. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
  29. scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
  30. scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
  31. scitex/audio/README.md +40 -36
  32. scitex/audio/__init__.py +129 -61
  33. scitex/audio/_branding.py +185 -0
  34. scitex/audio/_mcp/__init__.py +32 -0
  35. scitex/audio/_mcp/handlers.py +59 -6
  36. scitex/audio/_mcp/speak_handlers.py +238 -0
  37. scitex/audio/_relay.py +225 -0
  38. scitex/audio/_tts.py +18 -10
  39. scitex/audio/engines/base.py +17 -10
  40. scitex/audio/engines/elevenlabs_engine.py +7 -2
  41. scitex/audio/mcp_server.py +228 -75
  42. scitex/canvas/README.md +1 -1
  43. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  44. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  45. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  46. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  47. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  48. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  49. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  50. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  51. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  52. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  53. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  54. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  55. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  56. scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
  57. scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
  58. scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
  59. scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
  60. scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
  61. scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
  62. scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
  63. scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
  64. scitex/canvas/editor/flask_editor/_core.py +25 -1684
  65. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  66. scitex/cli/__init__.py +38 -43
  67. scitex/cli/audio.py +160 -41
  68. scitex/cli/capture.py +133 -20
  69. scitex/cli/introspect.py +488 -0
  70. scitex/cli/main.py +200 -109
  71. scitex/cli/mcp.py +60 -34
  72. scitex/cli/plt.py +414 -0
  73. scitex/cli/repro.py +15 -8
  74. scitex/cli/resource.py +15 -8
  75. scitex/cli/scholar/__init__.py +154 -8
  76. scitex/cli/scholar/_crossref_scitex.py +296 -0
  77. scitex/cli/scholar/_fetch.py +25 -3
  78. scitex/cli/social.py +355 -0
  79. scitex/cli/stats.py +136 -11
  80. scitex/cli/template.py +129 -12
  81. scitex/cli/tex.py +15 -8
  82. scitex/cli/writer.py +49 -299
  83. scitex/cloud/__init__.py +41 -2
  84. scitex/config/README.md +1 -1
  85. scitex/config/__init__.py +16 -2
  86. scitex/config/_env_registry.py +256 -0
  87. scitex/context/__init__.py +22 -0
  88. scitex/dev/__init__.py +20 -1
  89. scitex/diagram/__init__.py +42 -19
  90. scitex/diagram/mcp_server.py +13 -125
  91. scitex/gen/__init__.py +50 -14
  92. scitex/gen/_list_packages.py +4 -4
  93. scitex/introspect/__init__.py +82 -0
  94. scitex/introspect/_call_graph.py +303 -0
  95. scitex/introspect/_class_hierarchy.py +163 -0
  96. scitex/introspect/_core.py +41 -0
  97. scitex/introspect/_docstring.py +131 -0
  98. scitex/introspect/_examples.py +113 -0
  99. scitex/introspect/_imports.py +271 -0
  100. scitex/{gen/_inspect_module.py → introspect/_list_api.py} +48 -56
  101. scitex/introspect/_mcp/__init__.py +41 -0
  102. scitex/introspect/_mcp/handlers.py +233 -0
  103. scitex/introspect/_members.py +155 -0
  104. scitex/introspect/_resolve.py +89 -0
  105. scitex/introspect/_signature.py +131 -0
  106. scitex/introspect/_source.py +80 -0
  107. scitex/introspect/_type_hints.py +172 -0
  108. scitex/io/_save.py +1 -2
  109. scitex/io/bundle/README.md +1 -1
  110. scitex/logging/_formatters.py +19 -9
  111. scitex/mcp_server.py +98 -5
  112. scitex/os/__init__.py +4 -0
  113. scitex/{gen → os}/_check_host.py +4 -5
  114. scitex/plt/__init__.py +245 -550
  115. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  116. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  117. scitex/plt/gallery/README.md +1 -1
  118. scitex/plt/utils/_hitmap/__init__.py +82 -0
  119. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  120. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  121. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  122. scitex/plt/utils/_hitmap/_constants.py +40 -0
  123. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  124. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  125. scitex/plt/utils/_hitmap/_query.py +113 -0
  126. scitex/plt/utils/_hitmap.py +46 -1616
  127. scitex/plt/utils/_metadata/__init__.py +80 -0
  128. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  129. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  130. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  131. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  132. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  133. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  134. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  135. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  136. scitex/plt/utils/_metadata/_csv.py +416 -0
  137. scitex/plt/utils/_metadata/_detect.py +225 -0
  138. scitex/plt/utils/_metadata/_legend.py +127 -0
  139. scitex/plt/utils/_metadata/_rounding.py +117 -0
  140. scitex/plt/utils/_metadata/_verification.py +202 -0
  141. scitex/schema/README.md +1 -1
  142. scitex/scholar/__init__.py +8 -0
  143. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  144. scitex/scholar/core/Scholar.py +63 -1700
  145. scitex/scholar/core/_mixins/__init__.py +36 -0
  146. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  147. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  148. scitex/scholar/core/_mixins/_loaders.py +103 -0
  149. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  150. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  151. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  152. scitex/scholar/core/_mixins/_savers.py +69 -0
  153. scitex/scholar/core/_mixins/_search.py +103 -0
  154. scitex/scholar/core/_mixins/_services.py +88 -0
  155. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  156. scitex/scholar/crossref_scitex.py +367 -0
  157. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  158. scitex/scholar/examples/00_run_all.sh +120 -0
  159. scitex/scholar/jobs/_executors.py +27 -3
  160. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  161. scitex/scholar/pdf_download/_cli.py +154 -0
  162. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  163. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  164. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  165. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  166. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  167. scitex/scholar/pipelines/_single_steps.py +71 -36
  168. scitex/scholar/storage/_LibraryManager.py +97 -1695
  169. scitex/scholar/storage/_mixins/__init__.py +30 -0
  170. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  171. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  172. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  173. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  174. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  175. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  176. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  177. scitex/security/README.md +3 -3
  178. scitex/session/README.md +1 -1
  179. scitex/session/__init__.py +26 -7
  180. scitex/session/_decorator.py +1 -1
  181. scitex/sh/README.md +1 -1
  182. scitex/sh/__init__.py +7 -4
  183. scitex/social/__init__.py +155 -0
  184. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  185. scitex/stats/_mcp/_handlers/__init__.py +31 -0
  186. scitex/stats/_mcp/_handlers/_corrections.py +113 -0
  187. scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
  188. scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
  189. scitex/stats/_mcp/_handlers/_format.py +94 -0
  190. scitex/stats/_mcp/_handlers/_normality.py +110 -0
  191. scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
  192. scitex/stats/_mcp/_handlers/_power.py +247 -0
  193. scitex/stats/_mcp/_handlers/_recommend.py +102 -0
  194. scitex/stats/_mcp/_handlers/_run_test.py +279 -0
  195. scitex/stats/_mcp/_handlers/_stars.py +48 -0
  196. scitex/stats/_mcp/handlers.py +19 -1171
  197. scitex/stats/auto/_stat_style.py +175 -0
  198. scitex/stats/auto/_style_definitions.py +411 -0
  199. scitex/stats/auto/_styles.py +22 -620
  200. scitex/stats/descriptive/__init__.py +11 -8
  201. scitex/stats/descriptive/_ci.py +39 -0
  202. scitex/stats/power/_power.py +15 -4
  203. scitex/str/__init__.py +2 -1
  204. scitex/str/_title_case.py +63 -0
  205. scitex/template/README.md +1 -1
  206. scitex/template/__init__.py +25 -10
  207. scitex/template/_code_templates.py +147 -0
  208. scitex/template/_mcp/handlers.py +81 -0
  209. scitex/template/_mcp/tool_schemas.py +55 -0
  210. scitex/template/_templates/__init__.py +51 -0
  211. scitex/template/_templates/audio.py +233 -0
  212. scitex/template/_templates/canvas.py +312 -0
  213. scitex/template/_templates/capture.py +268 -0
  214. scitex/template/_templates/config.py +43 -0
  215. scitex/template/_templates/diagram.py +294 -0
  216. scitex/template/_templates/io.py +107 -0
  217. scitex/template/_templates/module.py +53 -0
  218. scitex/template/_templates/plt.py +202 -0
  219. scitex/template/_templates/scholar.py +267 -0
  220. scitex/template/_templates/session.py +130 -0
  221. scitex/template/_templates/session_minimal.py +43 -0
  222. scitex/template/_templates/session_plot.py +67 -0
  223. scitex/template/_templates/session_stats.py +77 -0
  224. scitex/template/_templates/stats.py +323 -0
  225. scitex/template/_templates/writer.py +296 -0
  226. scitex/template/clone_writer_directory.py +5 -5
  227. scitex/ui/_backends/_email.py +10 -2
  228. scitex/ui/_backends/_webhook.py +5 -1
  229. scitex/web/_search_pubmed.py +10 -6
  230. scitex/writer/README.md +1 -1
  231. scitex/writer/__init__.py +43 -34
  232. scitex/writer/_mcp/handlers.py +11 -744
  233. scitex/writer/_mcp/tool_schemas.py +5 -335
  234. scitex-2.15.3.dist-info/METADATA +667 -0
  235. {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/RECORD +241 -120
  236. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  237. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  238. scitex/diagram/_compile.py +0 -312
  239. scitex/diagram/_diagram.py +0 -355
  240. scitex/diagram/_mcp/__init__.py +0 -4
  241. scitex/diagram/_mcp/handlers.py +0 -400
  242. scitex/diagram/_mcp/tool_schemas.py +0 -157
  243. scitex/diagram/_presets.py +0 -173
  244. scitex/diagram/_schema.py +0 -182
  245. scitex/diagram/_split.py +0 -278
  246. scitex/gen/_ci.py +0 -12
  247. scitex/gen/_title_case.py +0 -89
  248. scitex/plt/_mcp/__init__.py +0 -4
  249. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  250. scitex/plt/_mcp/_handlers_figure.py +0 -195
  251. scitex/plt/_mcp/_handlers_plot.py +0 -252
  252. scitex/plt/_mcp/_handlers_style.py +0 -219
  253. scitex/plt/_mcp/handlers.py +0 -74
  254. scitex/plt/_mcp/tool_schemas.py +0 -497
  255. scitex/plt/mcp_server.py +0 -231
  256. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  257. scitex/scholar/examples/dev.py +0 -38
  258. scitex-2.14.0.dist-info/METADATA +0 -1238
  259. /scitex/{gen → context}/_detect_environment.py +0 -0
  260. /scitex/{gen → context}/_get_notebook_path.py +0 -0
  261. /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
  262. {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/WHEEL +0 -0
  263. {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/entry_points.txt +0 -0
  264. {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/licenses/LICENSE +0 -0
scitex/cli/main.py CHANGED
@@ -15,11 +15,14 @@ from . import (
15
15
  cloud,
16
16
  config,
17
17
  convert,
18
+ introspect,
18
19
  mcp,
20
+ plt,
19
21
  repro,
20
22
  resource,
21
23
  scholar,
22
24
  security,
25
+ social,
23
26
  stats,
24
27
  template,
25
28
  tex,
@@ -28,36 +31,36 @@ from . import (
28
31
  )
29
32
 
30
33
 
31
- @click.group(context_settings={"help_option_names": ["-h", "--help"]})
34
+ @click.group(
35
+ context_settings={"help_option_names": ["-h", "--help"]},
36
+ invoke_without_command=True,
37
+ )
32
38
  @click.version_option()
33
- def cli():
39
+ @click.option("--help-recursive", is_flag=True, help="Show help for all commands")
40
+ @click.pass_context
41
+ def cli(ctx, help_recursive):
34
42
  """
35
43
  SciTeX - Integrated Scientific Research Platform
36
44
 
37
45
  \b
38
46
  Examples:
39
- scitex config list # Show all configured paths
40
- scitex config init # Initialize directories
41
- scitex cloud login
42
- scitex cloud clone ywatanabe/my-project
43
- scitex scholar bibtex papers.bib --project myresearch
44
- scitex scholar single --doi "10.1038/nature12373"
45
- scitex security check --save
46
- scitex web get-urls https://example.com
47
- scitex web download-images https://example.com --output ./downloads
48
- scitex audio speak "Hello world"
49
- scitex capture snap --output screenshot.jpg
50
- scitex resource usage
51
- scitex stats recommend --data data.csv
52
- scitex mcp list # List all MCP tools
53
- scitex mcp serve # Start MCP server
47
+ scitex config list # Show configured paths
48
+ scitex cloud clone user/project # Clone from cloud
49
+ scitex scholar bibtex papers.bib # Manage papers
50
+ scitex audio speak "Hello" # Text-to-speech
51
+ scitex mcp list-tools # List MCP tools
52
+ scitex mcp start # Start MCP server
54
53
 
55
54
  \b
56
55
  Enable tab-completion:
57
56
  scitex completion # Auto-install for your shell
58
57
  scitex completion --show # Show installation instructions
59
58
  """
60
- pass
59
+ if help_recursive:
60
+ _print_help_recursive(ctx)
61
+ ctx.exit(0)
62
+ elif ctx.invoked_subcommand is None:
63
+ click.echo(ctx.get_help())
61
64
 
62
65
 
63
66
  # Add command groups
@@ -67,11 +70,14 @@ cli.add_command(capture.capture)
67
70
  cli.add_command(cloud.cloud)
68
71
  cli.add_command(config.config)
69
72
  cli.add_command(convert.convert)
73
+ cli.add_command(introspect.introspect)
70
74
  cli.add_command(mcp.mcp)
75
+ cli.add_command(plt.plt)
71
76
  cli.add_command(repro.repro)
72
77
  cli.add_command(resource.resource)
73
78
  cli.add_command(scholar.scholar)
74
79
  cli.add_command(security.security)
80
+ cli.add_command(social.social)
75
81
  cli.add_command(stats.stats)
76
82
  cli.add_command(template.template)
77
83
  cli.add_command(tex.tex)
@@ -93,10 +99,8 @@ def _get_all_command_paths(group, prefix=""):
93
99
  return paths
94
100
 
95
101
 
96
- @cli.command("help-recursive")
97
- @click.pass_context
98
- def help_recursive(ctx):
99
- """Show help for all commands recursively."""
102
+ def _print_help_recursive(ctx):
103
+ """Print help for all commands recursively."""
100
104
  # Show main CLI help first
101
105
  click.secho("━━━ scitex ━━━", fg="cyan", bold=True)
102
106
  click.echo(cli.get_help(ctx))
@@ -111,49 +115,88 @@ def help_recursive(ctx):
111
115
  click.echo(cmd.get_help(sub_ctx))
112
116
 
113
117
 
114
- @cli.command()
115
- @click.option(
116
- "--shell",
117
- type=click.Choice(["bash", "zsh", "fish"], case_sensitive=False),
118
- help="Shell type (auto-detected if not provided)",
119
- )
120
- @click.option(
121
- "--show", is_flag=True, help="Show completion script instead of installing"
122
- )
123
- def completion(shell, show):
118
+ def _detect_shell() -> str | None:
119
+ """Auto-detect current shell."""
120
+ shell_env = os.environ.get("SHELL", "")
121
+ if "bash" in shell_env:
122
+ return "bash"
123
+ elif "zsh" in shell_env:
124
+ return "zsh"
125
+ elif "fish" in shell_env:
126
+ return "fish"
127
+ return None
128
+
129
+
130
+ def _get_rc_file(shell: str) -> str:
131
+ """Get shell config file path."""
132
+ if shell == "bash":
133
+ return os.path.expanduser("~/.bashrc")
134
+ elif shell == "zsh":
135
+ return os.path.expanduser("~/.zshrc")
136
+ elif shell == "fish":
137
+ return os.path.expanduser("~/.config/fish/config.fish")
138
+ return ""
139
+
140
+
141
+ def _generate_completion_script(shell: str) -> str:
142
+ """Generate completion script for scitex CLI."""
143
+ import shutil
144
+
145
+ cli_path = shutil.which("scitex")
146
+ if not cli_path:
147
+ return ""
148
+
149
+ if shell == "bash":
150
+ return f'# scitex tab completion\neval "$(_SCITEX_COMPLETE=bash_source {cli_path})"'
151
+ elif shell == "zsh":
152
+ return (
153
+ f'# scitex tab completion\neval "$(_SCITEX_COMPLETE=zsh_source {cli_path})"'
154
+ )
155
+ elif shell == "fish":
156
+ return f"# scitex tab completion\neval (env _SCITEX_COMPLETE=fish_source {cli_path})"
157
+ return ""
158
+
159
+
160
+ @cli.group(invoke_without_command=True)
161
+ @click.pass_context
162
+ def completion(ctx):
124
163
  """
125
- Install or show shell completion for scitex commands.
164
+ Shell completion for scitex CLI.
126
165
 
127
166
  \b
128
- Supported shells: bash, zsh, fish
167
+ Commands:
168
+ scitex completion install # Install completion (default)
169
+ scitex completion status # Check installation status
170
+ scitex completion bash # Show bash completion script
171
+ scitex completion zsh # Show zsh completion script
129
172
 
130
173
  \b
131
- Installation:
132
- # Auto-detect shell and install
133
- scitex completion
174
+ Quick install:
175
+ scitex completion install
176
+ """
177
+ if ctx.invoked_subcommand is None:
178
+ # Default to install
179
+ ctx.invoke(completion_install)
134
180
 
135
- # Specify shell
136
- scitex completion --shell bash
137
- scitex completion --shell zsh
138
181
 
139
- # Show completion script
140
- scitex completion --show
182
+ @completion.command("install")
183
+ @click.option(
184
+ "--shell",
185
+ type=click.Choice(["bash", "zsh", "fish"], case_sensitive=False),
186
+ help="Shell type (auto-detected if not provided).",
187
+ )
188
+ def completion_install(shell):
189
+ """
190
+ Install shell completion for scitex CLI.
141
191
 
142
192
  \b
143
- After installation, restart your shell or run:
144
- source ~/.bashrc # for bash
145
- source ~/.zshrc # for zsh
193
+ Examples:
194
+ scitex completion install # Auto-detect shell
195
+ scitex completion install --shell bash
146
196
  """
147
- # Auto-detect shell if not provided
148
197
  if not shell:
149
- shell_env = os.environ.get("SHELL", "")
150
- if "bash" in shell_env:
151
- shell = "bash"
152
- elif "zsh" in shell_env:
153
- shell = "zsh"
154
- elif "fish" in shell_env:
155
- shell = "fish"
156
- else:
198
+ shell = _detect_shell()
199
+ if not shell:
157
200
  click.secho(
158
201
  "Could not auto-detect shell. Please specify with --shell option.",
159
202
  fg="red",
@@ -162,72 +205,120 @@ def completion(shell, show):
162
205
  sys.exit(1)
163
206
 
164
207
  shell = shell.lower()
208
+ rc_file = _get_rc_file(shell)
209
+ completion_script = _generate_completion_script(shell)
165
210
 
166
- # Get full path to scitex executable
167
- scitex_path = sys.argv[0]
168
- if not os.path.isabs(scitex_path):
169
- # If relative path, find the full path
170
- import shutil
171
-
172
- scitex_full = shutil.which("scitex") or scitex_path
173
- else:
174
- scitex_full = scitex_path
175
-
176
- # Generate completion script
177
- if shell == "bash":
178
- rc_file = os.path.expanduser("~/.bashrc")
179
- eval_line = f'eval "$(_SCITEX_COMPLETE=bash_source {scitex_full})"'
180
- elif shell == "zsh":
181
- rc_file = os.path.expanduser("~/.zshrc")
182
- eval_line = f'eval "$(_SCITEX_COMPLETE=zsh_source {scitex_full})"'
183
- elif shell == "fish":
184
- rc_file = os.path.expanduser("~/.config/fish/config.fish")
185
- eval_line = f"eval (env _SCITEX_COMPLETE=fish_source {scitex_full})"
186
-
187
- if show:
188
- # Just show the completion script
189
- click.echo(f"Add this line to your {rc_file}:")
190
- click.echo()
191
- click.secho(eval_line, fg="green")
192
- sys.exit(0)
211
+ if not completion_script:
212
+ click.secho("scitex CLI not found in PATH.", fg="red", err=True)
213
+ sys.exit(1)
193
214
 
194
- # Check if already installed (and not commented out)
215
+ # Check if already installed
195
216
  if os.path.exists(rc_file):
196
217
  with open(rc_file) as f:
197
- for line in f:
198
- # Check if the line exists and is not commented
199
- stripped = line.strip()
200
- if stripped == eval_line and not stripped.startswith("#"):
201
- click.secho(
202
- f"Tab completion is already installed in {rc_file}", fg="yellow"
203
- )
204
- click.echo()
205
- click.echo("To reload, run:")
206
- click.secho(f" source {rc_file}", fg="cyan")
207
- sys.exit(0)
208
-
209
- # Install completion
218
+ content = f.read()
219
+ if "scitex tab completion" in content:
220
+ click.secho(f"Completion already installed in {rc_file}", fg="yellow")
221
+ click.echo(
222
+ "\nTo reinstall, first remove the existing block, then run again."
223
+ )
224
+ click.echo("\nTo reload, run:")
225
+ click.secho(f" source {rc_file}", fg="cyan")
226
+ sys.exit(0)
227
+
228
+ # Install
210
229
  try:
211
- # Create config directory if it doesn't exist (for fish)
212
230
  os.makedirs(os.path.dirname(rc_file), exist_ok=True)
213
-
214
231
  with open(rc_file, "a") as f:
215
- f.write("\n# SciTeX tab completion\n")
216
- f.write(f"{eval_line}\n")
232
+ f.write(f"\n{completion_script}\n")
217
233
 
218
- click.secho(f"Successfully installed tab completion to {rc_file}", fg="green")
219
- click.echo()
220
- click.echo("To activate completion in current shell, run:")
234
+ click.secho(f"Installed scitex completion to {rc_file}", fg="green")
235
+ click.echo("\nTo activate, run:")
221
236
  click.secho(f" source {rc_file}", fg="cyan")
222
- click.echo()
223
- click.echo("Or restart your shell.")
224
- sys.exit(0)
225
237
 
226
238
  except Exception as e:
227
- click.secho(f"ERROR: Failed to install completion: {e}", fg="red", err=True)
228
- click.echo()
229
- click.echo("You can manually add this line to your shell config:")
230
- click.secho(eval_line, fg="green")
239
+ click.secho(f"ERROR: {e}", fg="red", err=True)
240
+ click.echo("\nManually add to your shell config:")
241
+ click.echo(completion_script)
242
+ sys.exit(1)
243
+
244
+
245
+ @completion.command("status")
246
+ def completion_status():
247
+ """
248
+ Check shell completion installation status.
249
+
250
+ \b
251
+ Shows:
252
+ - Current shell
253
+ - Config file path
254
+ - Installation status
255
+ """
256
+ import shutil
257
+
258
+ shell = _detect_shell() or "unknown"
259
+ rc_file = _get_rc_file(shell) if shell != "unknown" else "N/A"
260
+
261
+ click.secho("Shell Completion Status", fg="cyan", bold=True)
262
+ click.echo(f" Shell: {shell}")
263
+ click.echo(f" Config: {rc_file}")
264
+
265
+ # Check if installed
266
+ installed = False
267
+ if rc_file != "N/A" and os.path.exists(rc_file):
268
+ with open(rc_file) as f:
269
+ content = f.read()
270
+ if "scitex tab completion" in content:
271
+ installed = True
272
+
273
+ status = (
274
+ click.style("installed", fg="green")
275
+ if installed
276
+ else click.style("not installed", fg="yellow")
277
+ )
278
+ click.echo(f" Status: {status}")
279
+
280
+ # Check if scitex is in PATH
281
+ cli_path = shutil.which("scitex")
282
+ path_status = (
283
+ click.style("OK", fg="green") if cli_path else click.style("missing", fg="red")
284
+ )
285
+ click.echo(f" scitex in PATH: {path_status}")
286
+
287
+ if not installed:
288
+ click.echo("\nTo install completion:")
289
+ click.secho(" scitex completion install", fg="cyan")
290
+
291
+
292
+ @completion.command("bash")
293
+ def completion_bash():
294
+ """Show bash completion script."""
295
+ script = _generate_completion_script("bash")
296
+ if script:
297
+ click.echo(script)
298
+ else:
299
+ click.secho("scitex CLI not found in PATH.", fg="red", err=True)
300
+ sys.exit(1)
301
+
302
+
303
+ @completion.command("zsh")
304
+ def completion_zsh():
305
+ """Show zsh completion script."""
306
+ script = _generate_completion_script("zsh")
307
+ if script:
308
+ click.echo(script)
309
+ else:
310
+ click.secho("scitex CLI not found in PATH.", fg="red", err=True)
311
+ sys.exit(1)
312
+
313
+
314
+ @completion.command("fish")
315
+ def completion_fish():
316
+ """Show fish completion script."""
317
+ script = _generate_completion_script("fish")
318
+ if script:
319
+ click.echo(script)
320
+ else:
321
+ click.secho("scitex CLI not found in PATH.", fg="red", err=True)
231
322
  sys.exit(1)
232
323
 
233
324
 
scitex/cli/mcp.py CHANGED
@@ -13,23 +13,26 @@ Commands:
13
13
  import click
14
14
 
15
15
 
16
- @click.group()
17
- def mcp():
16
+ @click.group(invoke_without_command=True)
17
+ @click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
18
+ @click.pass_context
19
+ def mcp(ctx, help_recursive):
18
20
  """
19
21
  MCP (Model Context Protocol) server management.
20
22
 
21
23
  \b
22
24
  Examples:
23
- scitex mcp list # List all tools
24
- scitex mcp list --module audio # List audio tools only
25
- scitex mcp doctor # Check server health
26
- scitex mcp serve # Start stdio server
27
- scitex mcp serve -t sse -p 8085 # Start SSE server
25
+ scitex mcp list-tools # List all tools
26
+ scitex mcp start # Start MCP server
28
27
  """
29
- pass
28
+ if help_recursive:
29
+ _print_help_recursive(ctx)
30
+ ctx.exit(0)
31
+ elif ctx.invoked_subcommand is None:
32
+ click.echo(ctx.get_help())
30
33
 
31
34
 
32
- @mcp.command("list")
35
+ @mcp.command("list-tools")
33
36
  @click.option(
34
37
  "--module",
35
38
  "-m",
@@ -44,9 +47,8 @@ def list_tools(module: str, as_json: bool):
44
47
 
45
48
  \b
46
49
  Examples:
47
- scitex mcp list # List all 106 tools
48
- scitex mcp list --module audio # List audio tools only
49
- scitex mcp list --json # Output as JSON
50
+ scitex mcp list-tools
51
+ scitex mcp list-tools --module audio
50
52
  """
51
53
  try:
52
54
  from scitex.mcp_server import FASTMCP_AVAILABLE
@@ -268,11 +270,8 @@ def doctor(verbose: bool):
268
270
  raise SystemExit(1 if issues else 0)
269
271
 
270
272
 
271
- @mcp.command("help-recursive")
272
- @click.pass_context
273
- def help_recursive(ctx):
274
- """Show help for all MCP commands recursively."""
275
- # Create a fake parent context to show "scitex mcp" in Usage
273
+ def _print_help_recursive(ctx):
274
+ """Print help for mcp and all its subcommands."""
276
275
  fake_parent = click.Context(click.Group(), info_name="scitex")
277
276
  parent_ctx = click.Context(mcp, info_name="mcp", parent=fake_parent)
278
277
 
@@ -289,7 +288,7 @@ def help_recursive(ctx):
289
288
  click.echo(cmd.get_help(sub_ctx))
290
289
 
291
290
 
292
- @mcp.command("serve")
291
+ @mcp.command("start")
293
292
  @click.option(
294
293
  "--transport",
295
294
  "-t",
@@ -301,27 +300,14 @@ def help_recursive(ctx):
301
300
  @click.option(
302
301
  "--port", "-p", default=8085, type=int, help="Port to bind (default: 8085)"
303
302
  )
304
- def serve(transport: str, host: str, port: int):
303
+ def start(transport: str, host: str, port: int):
305
304
  """
306
305
  Start the unified MCP server.
307
306
 
308
- \b
309
- Transport types:
310
- stdio - Standard I/O (for Claude Desktop)
311
- sse - Server-Sent Events (for remote via SSH)
312
- http - HTTP streamable (for web clients)
313
-
314
307
  \b
315
308
  Examples:
316
- scitex mcp serve # Start stdio server
317
- scitex mcp serve -t sse -p 8085 # Start SSE server
318
- scitex mcp serve -t http -p 8085 # Start HTTP server
319
-
320
- \b
321
- Remote Setup (SSE):
322
- 1. Local: scitex mcp serve -t sse -p 8085
323
- 2. SSH: ssh -R 8085:localhost:8085 remote-host
324
- 3. Config: {"type": "sse", "url": "http://localhost:8085/sse"}
309
+ scitex mcp start
310
+ scitex mcp start -t sse -p 8085
325
311
  """
326
312
  try:
327
313
  from scitex.mcp_server import run_server
@@ -333,4 +319,44 @@ def serve(transport: str, host: str, port: int):
333
319
  run_server(transport=transport, host=host, port=port)
334
320
 
335
321
 
322
+ @mcp.command("installation")
323
+ def installation():
324
+ """
325
+ Show Claude Desktop configuration for SciTeX MCP server.
326
+
327
+ \b
328
+ Examples:
329
+ scitex mcp installation
330
+ """
331
+ import shutil
332
+ import sys
333
+
334
+ from scitex import __version__
335
+
336
+ click.secho(f"SciTeX MCP Server v{__version__}", fg="cyan", bold=True)
337
+ click.echo()
338
+
339
+ # Get actual path
340
+ scitex_path = shutil.which("scitex")
341
+ python_path = sys.executable
342
+
343
+ if scitex_path:
344
+ click.echo(f"Your installation path: {scitex_path}")
345
+ click.echo(f"Your Python path: {python_path}")
346
+ click.echo()
347
+
348
+ click.secho("Claude Desktop Configuration:", fg="green", bold=True)
349
+ click.echo(
350
+ "Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)"
351
+ )
352
+ click.echo("or %APPDATA%\\Claude\\claude_desktop_config.json (Windows):")
353
+ click.echo()
354
+
355
+ config = f'''"scitex": {{
356
+ "command": "{scitex_path or "/path/to/.venv/bin/scitex"}",
357
+ "args": ["mcp", "start"]
358
+ }}'''
359
+ click.secho(config, fg="yellow")
360
+
361
+
336
362
  # EOF