scitex 2.17.0__py3-none-any.whl → 2.17.4__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 (46) hide show
  1. scitex/_dev/__init__.py +122 -0
  2. scitex/_dev/_config.py +391 -0
  3. scitex/_dev/_dashboard/__init__.py +11 -0
  4. scitex/_dev/_dashboard/_app.py +89 -0
  5. scitex/_dev/_dashboard/_routes.py +182 -0
  6. scitex/_dev/_dashboard/_scripts.py +422 -0
  7. scitex/_dev/_dashboard/_styles.py +295 -0
  8. scitex/_dev/_dashboard/_templates.py +130 -0
  9. scitex/_dev/_dashboard/static/version-dashboard-favicon.svg +12 -0
  10. scitex/_dev/_ecosystem.py +109 -0
  11. scitex/_dev/_github.py +360 -0
  12. scitex/_dev/_mcp/__init__.py +11 -0
  13. scitex/_dev/_mcp/handlers.py +182 -0
  14. scitex/_dev/_rtd.py +122 -0
  15. scitex/_dev/_ssh.py +362 -0
  16. scitex/_dev/_versions.py +272 -0
  17. scitex/_mcp_tools/__init__.py +2 -0
  18. scitex/_mcp_tools/dev.py +186 -0
  19. scitex/audio/_audio_check.py +84 -41
  20. scitex/cli/capture.py +45 -22
  21. scitex/cli/dev.py +494 -0
  22. scitex/cli/main.py +2 -0
  23. scitex/cli/stats.py +48 -20
  24. scitex/cli/verify.py +33 -36
  25. scitex/plt/__init__.py +16 -6
  26. scitex/scholar/_mcp/crossref_handlers.py +45 -7
  27. scitex/scholar/_mcp/openalex_handlers.py +45 -7
  28. scitex/scholar/config/default.yaml +2 -0
  29. scitex/scholar/local_dbs/__init__.py +5 -1
  30. scitex/scholar/local_dbs/export.py +93 -0
  31. scitex/scholar/local_dbs/unified.py +505 -0
  32. scitex/scholar/metadata_engines/ScholarEngine.py +11 -0
  33. scitex/scholar/metadata_engines/individual/OpenAlexLocalEngine.py +346 -0
  34. scitex/scholar/metadata_engines/individual/__init__.py +1 -0
  35. scitex/template/__init__.py +18 -1
  36. scitex/template/clone_research_minimal.py +111 -0
  37. scitex/verify/README.md +0 -12
  38. scitex/verify/__init__.py +0 -4
  39. scitex/verify/_visualize.py +0 -4
  40. scitex/verify/_viz/__init__.py +0 -18
  41. {scitex-2.17.0.dist-info → scitex-2.17.4.dist-info}/METADATA +2 -1
  42. {scitex-2.17.0.dist-info → scitex-2.17.4.dist-info}/RECORD +45 -24
  43. scitex/verify/_viz/_plotly.py +0 -193
  44. {scitex-2.17.0.dist-info → scitex-2.17.4.dist-info}/WHEEL +0 -0
  45. {scitex-2.17.0.dist-info → scitex-2.17.4.dist-info}/entry_points.txt +0 -0
  46. {scitex-2.17.0.dist-info → scitex-2.17.4.dist-info}/licenses/LICENSE +0 -0
scitex/cli/dev.py ADDED
@@ -0,0 +1,494 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-02
3
+ # File: scitex/cli/dev.py
4
+
5
+ """
6
+ SciTeX Developer CLI Commands (Internal).
7
+
8
+ Commands for managing and inspecting the scitex ecosystem.
9
+ """
10
+
11
+ import click
12
+
13
+
14
+ @click.group(
15
+ context_settings={"help_option_names": ["-h", "--help"]},
16
+ invoke_without_command=True,
17
+ )
18
+ @click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
19
+ @click.pass_context
20
+ def dev(ctx, help_recursive):
21
+ """
22
+ Developer utilities (internal).
23
+
24
+ \b
25
+ Examples:
26
+ scitex dev versions # List all ecosystem versions
27
+ scitex dev versions --check # Check version consistency
28
+ scitex dev versions --json # Output as JSON
29
+ scitex dev versions -p scitex # Check specific package
30
+ """
31
+ if help_recursive:
32
+ from . import print_help_recursive
33
+
34
+ print_help_recursive(ctx, dev)
35
+ ctx.exit(0)
36
+ elif ctx.invoked_subcommand is None:
37
+ click.echo(ctx.get_help())
38
+
39
+
40
+ @dev.command("versions")
41
+ @click.option(
42
+ "--check",
43
+ is_flag=True,
44
+ help="Check version consistency and show summary",
45
+ )
46
+ @click.option(
47
+ "--json",
48
+ "as_json",
49
+ is_flag=True,
50
+ help="Output as JSON",
51
+ )
52
+ @click.option(
53
+ "-p",
54
+ "--package",
55
+ multiple=True,
56
+ help="Filter to specific package(s)",
57
+ )
58
+ @click.option(
59
+ "--local-only",
60
+ is_flag=True,
61
+ help="Skip remote (PyPI) version checks",
62
+ )
63
+ @click.option(
64
+ "--host",
65
+ multiple=True,
66
+ help="Check specific SSH host(s)",
67
+ )
68
+ @click.option(
69
+ "--all-hosts",
70
+ is_flag=True,
71
+ help="Check all configured SSH hosts",
72
+ )
73
+ @click.option(
74
+ "--remote",
75
+ multiple=True,
76
+ help="Check specific GitHub remote(s)",
77
+ )
78
+ @click.option(
79
+ "--all-remotes",
80
+ is_flag=True,
81
+ help="Check all configured GitHub remotes",
82
+ )
83
+ def versions(check, as_json, package, local_only, host, all_hosts, remote, all_remotes):
84
+ """
85
+ List versions across the scitex ecosystem.
86
+
87
+ \b
88
+ Shows version information from multiple sources:
89
+ - pyproject.toml (local source)
90
+ - installed package (pip/importlib.metadata)
91
+ - git tag (latest version tag)
92
+ - git branch (current branch)
93
+ - PyPI (remote published version)
94
+ - SSH hosts (if configured)
95
+ - GitHub remotes (if configured)
96
+
97
+ \b
98
+ Examples:
99
+ scitex dev versions # List all versions
100
+ scitex dev versions --check # Check consistency
101
+ scitex dev versions --json # JSON output
102
+ scitex dev versions -p scitex # Single package
103
+ scitex dev versions -p scitex -p figrecipe # Multiple packages
104
+ scitex dev versions --local-only # Skip PyPI checks
105
+ scitex dev versions --host myhost # Check specific host
106
+ scitex dev versions --all-hosts # Check all hosts
107
+ scitex dev versions --remote ywatanabe1989 # Check GitHub remote
108
+ scitex dev versions --all-remotes # Check all remotes
109
+ """
110
+ import json as json_module
111
+
112
+ from scitex._dev import check_versions, list_versions
113
+
114
+ packages = list(package) if package else None
115
+
116
+ if check:
117
+ result = check_versions(packages)
118
+ if local_only:
119
+ for pkg_info in result["packages"].values():
120
+ pkg_info.get("remote", {}).pop("pypi", None)
121
+ else:
122
+ result = list_versions(packages)
123
+ if local_only:
124
+ for pkg_info in result.values():
125
+ pkg_info.get("remote", {}).pop("pypi", None)
126
+
127
+ # Add host data if requested
128
+ if host or all_hosts:
129
+ from scitex._dev import check_all_hosts
130
+
131
+ hosts_filter = list(host) if host else None
132
+ try:
133
+ result["hosts"] = check_all_hosts(packages=packages, hosts=hosts_filter)
134
+ except Exception as e:
135
+ result["hosts"] = {"error": str(e)}
136
+
137
+ # Add remote data if requested
138
+ if remote or all_remotes:
139
+ from scitex._dev import check_all_remotes
140
+
141
+ remotes_filter = list(remote) if remote else None
142
+ try:
143
+ result["remotes"] = check_all_remotes(
144
+ packages=packages, remotes=remotes_filter
145
+ )
146
+ except Exception as e:
147
+ result["remotes"] = {"error": str(e)}
148
+
149
+ if as_json:
150
+ click.echo(json_module.dumps(result, indent=2))
151
+ return
152
+
153
+ # Human-readable output
154
+ if check:
155
+ _print_check_result(result)
156
+ else:
157
+ _print_versions(result)
158
+
159
+ # Print host data
160
+ if "hosts" in result and result["hosts"]:
161
+ _print_hosts(result["hosts"])
162
+
163
+ # Print remote data
164
+ if "remotes" in result and result["remotes"]:
165
+ _print_remotes(result["remotes"])
166
+
167
+
168
+ def _print_versions(versions: dict) -> None:
169
+ """Print version information in human-readable format."""
170
+ click.secho("SciTeX Ecosystem Versions", fg="cyan", bold=True)
171
+ click.echo("=" * 60)
172
+ click.echo()
173
+
174
+ for pkg, info in versions.items():
175
+ status = info.get("status", "unknown")
176
+ status_color = {
177
+ "ok": "green",
178
+ "unreleased": "yellow",
179
+ "mismatch": "red",
180
+ "outdated": "magenta",
181
+ "unavailable": "white",
182
+ "unknown": "white",
183
+ }.get(status, "white")
184
+
185
+ click.secho(f"{pkg}", fg="cyan", bold=True, nl=False)
186
+ click.echo(" ", nl=False)
187
+ click.secho(f"[{status}]", fg=status_color)
188
+
189
+ # Local versions
190
+ local = info.get("local", {})
191
+ if local.get("pyproject_toml"):
192
+ click.echo(f" toml: {local['pyproject_toml']}")
193
+ if local.get("installed"):
194
+ click.echo(f" installed: {local['installed']}")
195
+
196
+ # Git info
197
+ git = info.get("git", {})
198
+ if git.get("latest_tag"):
199
+ click.echo(f" git tag: {git['latest_tag']}")
200
+ if git.get("branch"):
201
+ click.echo(f" branch: {git['branch']}")
202
+
203
+ # Remote
204
+ remote = info.get("remote", {})
205
+ if remote.get("pypi"):
206
+ click.echo(f" pypi: {remote['pypi']}")
207
+
208
+ # Issues
209
+ issues = info.get("issues", [])
210
+ if issues:
211
+ for issue in issues:
212
+ click.secho(f" ! {issue}", fg="yellow")
213
+
214
+ click.echo()
215
+
216
+
217
+ def _print_check_result(result: dict) -> None:
218
+ """Print version check result with summary."""
219
+ _print_versions(result.get("packages", {}))
220
+
221
+ summary = result.get("summary", {})
222
+ click.secho("Summary", fg="cyan", bold=True)
223
+ click.echo("-" * 30)
224
+
225
+ total = summary.get("total", 0)
226
+ ok = summary.get("ok", 0)
227
+ unreleased = summary.get("unreleased", 0)
228
+ mismatch = summary.get("mismatch", 0)
229
+ outdated = summary.get("outdated", 0)
230
+ unavailable = summary.get("unavailable", 0)
231
+
232
+ click.echo(f" Total: {total}")
233
+ click.secho(f" OK: {ok}", fg="green" if ok else "white")
234
+ if unreleased:
235
+ click.secho(f" Unreleased: {unreleased}", fg="yellow")
236
+ if mismatch:
237
+ click.secho(f" Mismatch: {mismatch}", fg="red")
238
+ if outdated:
239
+ click.secho(f" Outdated: {outdated}", fg="magenta")
240
+ if unavailable:
241
+ click.secho(f" Unavailable: {unavailable}", fg="white")
242
+
243
+ click.echo()
244
+ if mismatch > 0:
245
+ click.secho("Some packages have version mismatches!", fg="red", bold=True)
246
+ elif unreleased > 0:
247
+ click.secho("Some packages are ready to release.", fg="yellow")
248
+ else:
249
+ click.secho("All versions are consistent.", fg="green", bold=True)
250
+
251
+
252
+ def _print_hosts(hosts_data: dict) -> None:
253
+ """Print host version data."""
254
+ click.echo()
255
+ click.secho("SSH Hosts", fg="cyan", bold=True)
256
+ click.echo("-" * 40)
257
+
258
+ if "error" in hosts_data:
259
+ click.secho(f" Error: {hosts_data['error']}", fg="red")
260
+ return
261
+
262
+ for host_name, host_info in hosts_data.items():
263
+ if host_name.startswith("_"):
264
+ continue
265
+ click.secho(f" {host_name}", fg="yellow", bold=True)
266
+ meta = host_info.get("_host", {})
267
+ if meta:
268
+ click.echo(f" ({meta.get('hostname', '')} - {meta.get('role', '')})")
269
+ for pkg, pkg_info in host_info.items():
270
+ if pkg.startswith("_"):
271
+ continue
272
+ status = pkg_info.get("status", "unknown")
273
+ installed = pkg_info.get("installed", "-")
274
+ color = (
275
+ "green" if status == "ok" else "red" if status == "error" else "yellow"
276
+ )
277
+ click.echo(f" {pkg}: ", nl=False)
278
+ click.secho(f"{installed}", fg=color)
279
+
280
+
281
+ def _print_remotes(remotes_data: dict) -> None:
282
+ """Print GitHub remote version data."""
283
+ click.echo()
284
+ click.secho("GitHub Remotes", fg="cyan", bold=True)
285
+ click.echo("-" * 40)
286
+
287
+ if "error" in remotes_data:
288
+ click.secho(f" Error: {remotes_data['error']}", fg="red")
289
+ return
290
+
291
+ for remote_name, remote_info in remotes_data.items():
292
+ if remote_name.startswith("_"):
293
+ continue
294
+ click.secho(f" {remote_name}", fg="yellow", bold=True)
295
+ meta = remote_info.get("_remote", {})
296
+ if meta:
297
+ click.echo(f" (org: {meta.get('org', '')})")
298
+ for pkg, pkg_info in remote_info.items():
299
+ if pkg.startswith("_"):
300
+ continue
301
+ tag = pkg_info.get("latest_tag", "-")
302
+ release = pkg_info.get("release", "-")
303
+ click.echo(f" {pkg}: tag={tag}, release={release}")
304
+
305
+
306
+ # MCP subgroup
307
+ @dev.group(invoke_without_command=True)
308
+ @click.pass_context
309
+ def mcp(ctx):
310
+ """
311
+ MCP (Model Context Protocol) server operations.
312
+
313
+ \b
314
+ Commands:
315
+ list-tools - List available MCP tools
316
+
317
+ \b
318
+ Examples:
319
+ scitex dev mcp list-tools
320
+ """
321
+ if ctx.invoked_subcommand is None:
322
+ click.echo(ctx.get_help())
323
+
324
+
325
+ @mcp.command("list-tools")
326
+ @click.option("-v", "--verbose", count=True, help="-v params, -vv returns")
327
+ def list_tools(verbose):
328
+ """List available MCP tools for dev module."""
329
+ click.secho("Dev MCP Tools", fg="cyan", bold=True)
330
+ click.echo()
331
+ tools = [
332
+ ("dev_list_versions", "List versions across ecosystem", "packages", "JSON"),
333
+ ("dev_check_versions", "Check version consistency", "packages", "JSON"),
334
+ ("dev_check_hosts", "Check versions on SSH hosts", "packages, hosts", "JSON"),
335
+ ("dev_check_remotes", "Check versions on GitHub", "packages, remotes", "JSON"),
336
+ ("dev_get_config", "Get current configuration", "", "JSON"),
337
+ (
338
+ "dev_full_versions",
339
+ "Get comprehensive data",
340
+ "packages, hosts, remotes",
341
+ "JSON",
342
+ ),
343
+ ]
344
+ for name, desc, params, returns in tools:
345
+ click.secho(f" {name}", fg="green", bold=True, nl=False)
346
+ click.echo(f": {desc}")
347
+ if verbose >= 1 and params:
348
+ click.echo(f" params: {params}")
349
+ if verbose >= 2 and returns:
350
+ click.echo(f" returns: {returns}")
351
+
352
+
353
+ @dev.command("list-python-apis")
354
+ @click.option("-v", "--verbose", count=True, help="Verbosity: -v +doc, -vv full doc")
355
+ @click.option("-d", "--max-depth", type=int, default=5, help="Max recursion depth")
356
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
357
+ @click.pass_context
358
+ def list_python_apis(ctx, verbose, max_depth, as_json):
359
+ """List Python APIs (alias for: scitex introspect api scitex._dev)."""
360
+ from scitex.cli.introspect import api
361
+
362
+ ctx.invoke(
363
+ api,
364
+ dotted_path="scitex._dev",
365
+ verbose=verbose,
366
+ max_depth=max_depth,
367
+ as_json=as_json,
368
+ )
369
+
370
+
371
+ @dev.command("dashboard")
372
+ @click.option("--host", default="127.0.0.1", help="Host to bind to")
373
+ @click.option("--port", "-p", default=5000, type=int, help="Port to listen on")
374
+ @click.option("--debug", is_flag=True, help="Enable debug mode")
375
+ @click.option("--no-browser", is_flag=True, help="Don't open browser")
376
+ def dashboard(host, port, debug, no_browser):
377
+ """
378
+ Start the Flask version dashboard.
379
+
380
+ \b
381
+ Examples:
382
+ scitex dev dashboard # Start on localhost:5000
383
+ scitex dev dashboard --port 5001 # Custom port
384
+ scitex dev dashboard --no-browser # Don't open browser
385
+ """
386
+ from scitex._dev import run_dashboard
387
+
388
+ run_dashboard(host=host, port=port, debug=debug, open_browser=not no_browser)
389
+
390
+
391
+ # Config subgroup
392
+ @dev.group(invoke_without_command=True)
393
+ @click.pass_context
394
+ def config(ctx):
395
+ """
396
+ Configuration management.
397
+
398
+ \b
399
+ Commands:
400
+ show - Show current configuration
401
+ validate - Validate configuration file
402
+ create - Create default config file
403
+
404
+ \b
405
+ Examples:
406
+ scitex dev config show
407
+ scitex dev config create
408
+ """
409
+ if ctx.invoked_subcommand is None:
410
+ click.echo(ctx.get_help())
411
+
412
+
413
+ @config.command("show")
414
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
415
+ def config_show(as_json):
416
+ """Show current configuration."""
417
+ import json as json_module
418
+
419
+ from scitex._dev import get_config_path, load_config
420
+
421
+ config_path = get_config_path()
422
+ cfg = load_config()
423
+
424
+ if as_json:
425
+ data = {
426
+ "config_path": str(config_path),
427
+ "exists": config_path.exists(),
428
+ "packages": [p.name for p in cfg.packages],
429
+ "hosts": [{"name": h.name, "enabled": h.enabled} for h in cfg.hosts],
430
+ "remotes": [
431
+ {"name": r.name, "enabled": r.enabled} for r in cfg.github_remotes
432
+ ],
433
+ "branches": cfg.branches,
434
+ }
435
+ click.echo(json_module.dumps(data, indent=2))
436
+ return
437
+
438
+ click.secho("Configuration", fg="cyan", bold=True)
439
+ click.echo(f" Path: {config_path}")
440
+ click.echo(f" Exists: {config_path.exists()}")
441
+ click.echo()
442
+ click.secho("Packages:", fg="yellow")
443
+ for p in cfg.packages:
444
+ click.echo(f" - {p.name} ({p.pypi_name})")
445
+ click.echo()
446
+ click.secho("Hosts:", fg="yellow")
447
+ for h in cfg.hosts:
448
+ status = "enabled" if h.enabled else "disabled"
449
+ click.echo(f" - {h.name} ({h.hostname}) [{status}]")
450
+ click.echo()
451
+ click.secho("GitHub Remotes:", fg="yellow")
452
+ for r in cfg.github_remotes:
453
+ status = "enabled" if r.enabled else "disabled"
454
+ click.echo(f" - {r.name} (org: {r.org}) [{status}]")
455
+
456
+
457
+ @config.command("create")
458
+ @click.option("--force", is_flag=True, help="Overwrite existing config")
459
+ def config_create(force):
460
+ """Create default configuration file."""
461
+ from scitex._dev import create_default_config, get_config_path
462
+
463
+ config_path = get_config_path()
464
+ if config_path.exists() and not force:
465
+ click.secho(f"Config already exists: {config_path}", fg="yellow")
466
+ click.echo("Use --force to overwrite.")
467
+ return
468
+
469
+ path = create_default_config()
470
+ click.secho(f"Created config: {path}", fg="green")
471
+
472
+
473
+ @config.command("validate")
474
+ def config_validate():
475
+ """Validate configuration file."""
476
+ from scitex._dev import get_config_path, load_config
477
+
478
+ config_path = get_config_path()
479
+ if not config_path.exists():
480
+ click.secho(f"Config not found: {config_path}", fg="red")
481
+ click.echo("Run 'scitex dev config create' to create one.")
482
+ return
483
+
484
+ try:
485
+ cfg = load_config()
486
+ click.secho("Configuration is valid.", fg="green")
487
+ click.echo(f" Packages: {len(cfg.packages)}")
488
+ click.echo(f" Hosts: {len(cfg.hosts)}")
489
+ click.echo(f" Remotes: {len(cfg.github_remotes)}")
490
+ except Exception as e:
491
+ click.secho(f"Configuration error: {e}", fg="red")
492
+
493
+
494
+ # EOF
scitex/cli/main.py CHANGED
@@ -30,6 +30,7 @@ from . import (
30
30
  config,
31
31
  convert,
32
32
  dataset,
33
+ dev,
33
34
  introspect,
34
35
  mcp,
35
36
  plt,
@@ -87,6 +88,7 @@ cli.add_command(cloud.cloud)
87
88
  cli.add_command(config.config)
88
89
  cli.add_command(convert.convert)
89
90
  cli.add_command(dataset.dataset)
91
+ cli.add_command(dev.dev)
90
92
  cli.add_command(introspect.introspect)
91
93
  cli.add_command(mcp.mcp)
92
94
  cli.add_command(plt.plt)
scitex/cli/stats.py CHANGED
@@ -438,30 +438,58 @@ def doctor():
438
438
 
439
439
 
440
440
  @mcp.command("list-tools")
441
- def list_tools():
442
- """
443
- List available MCP tools
444
-
445
- \b
446
- Example:
447
- scitex stats mcp list-tools
448
- """
441
+ @click.option("-v", "--verbose", count=True, help="-v params, -vv returns")
442
+ def list_tools(verbose):
443
+ """List available MCP tools for statistics."""
449
444
  click.secho("Stats MCP Tools", fg="cyan", bold=True)
450
445
  click.echo()
446
+ # (name, desc, params, returns)
451
447
  tools = [
452
- ("stats_recommend_tests", "Recommend appropriate statistical tests"),
453
- ("stats_run_test", "Execute a statistical test on data"),
454
- ("stats_format_results", "Format results in journal style"),
455
- ("stats_power_analysis", "Calculate power or sample size"),
456
- ("stats_correct_pvalues", "Apply multiple comparison correction"),
457
- ("stats_describe", "Calculate descriptive statistics"),
458
- ("stats_effect_size", "Calculate effect size"),
459
- ("stats_normality_test", "Test for normal distribution"),
460
- ("stats_posthoc_test", "Run post-hoc pairwise comparisons"),
461
- ("stats_p_to_stars", "Convert p-value to significance stars"),
448
+ (
449
+ "recommend_tests",
450
+ "Recommend statistical tests",
451
+ "data_description: str",
452
+ "JSON",
453
+ ),
454
+ (
455
+ "run_test",
456
+ "Execute a statistical test",
457
+ "test_name: str, data: list",
458
+ "JSON",
459
+ ),
460
+ ("format_results", "Format results in journal style", "results: dict", "str"),
461
+ (
462
+ "power_analysis",
463
+ "Calculate power or sample size",
464
+ "test: str, effect=0.5",
465
+ "JSON",
466
+ ),
467
+ (
468
+ "correct_pvalues",
469
+ "Apply multiple comparison correction",
470
+ "pvalues: list",
471
+ "JSON",
472
+ ),
473
+ ("describe", "Calculate descriptive statistics", "data: list", "JSON"),
474
+ ("effect_size", "Calculate effect size", "group1: list, group2: list", "JSON"),
475
+ ("normality_test", "Test for normal distribution", "data: list", "JSON"),
476
+ ("posthoc_test", "Run post-hoc pairwise comparisons", "groups: list", "JSON"),
477
+ (
478
+ "p_to_stars",
479
+ "Convert p-value to significance stars",
480
+ "p_value: float",
481
+ "str",
482
+ ),
462
483
  ]
463
- for name, desc in tools:
464
- click.echo(f" {name}: {desc}")
484
+ for name, desc, params, returns in tools:
485
+ click.secho(f" stats_{name}", fg="green", bold=True, nl=False)
486
+ click.echo(f": {desc}")
487
+ if verbose >= 1 and params:
488
+ click.echo(f" params: {params}")
489
+ if verbose >= 2:
490
+ click.echo(f" returns: {returns}")
491
+ if verbose >= 1:
492
+ click.echo()
465
493
 
466
494
 
467
495
  @stats.command("list-python-apis")
scitex/cli/verify.py CHANGED
@@ -262,13 +262,12 @@ def verify_chain_cmd(target_file, verbose, mermaid, as_json):
262
262
  @click.option("--session", "-s", help="Session ID to visualize")
263
263
  @click.option("--file", "-f", "target_file", help="Target file to trace chain")
264
264
  @click.option("--title", "-t", default="Verification DAG", help="Title for output")
265
- @click.option("--plotly", "-p", is_flag=True, help="Use Plotly (interactive)")
266
- def render_cmd(output_path, session, target_file, title, plotly):
265
+ def render_cmd(output_path, session, target_file, title):
267
266
  """
268
267
  Render verification DAG to file (HTML, PNG, SVG, or Mermaid).
269
268
 
270
269
  The output format is determined by the file extension:
271
- - .html: Interactive HTML (Mermaid.js or Plotly with --plotly)
270
+ - .html: Interactive HTML with Mermaid.js
272
271
  - .png: PNG image
273
272
  - .svg: SVG image
274
273
  - .mmd: Raw Mermaid code
@@ -276,7 +275,6 @@ def render_cmd(output_path, session, target_file, title, plotly):
276
275
  \b
277
276
  Examples:
278
277
  scitex verify render dag.html --file ./results/fig.png
279
- scitex verify render dag.html --file ./results/fig.png --plotly
280
278
  scitex verify render dag.png --session 2025Y-11M-18D-09h12m03s
281
279
  """
282
280
  try:
@@ -284,24 +282,14 @@ def render_cmd(output_path, session, target_file, title, plotly):
284
282
  click.secho("Error: Specify --session or --file", fg="red", err=True)
285
283
  sys.exit(1)
286
284
 
287
- if plotly:
288
- from scitex.verify import render_plotly_dag
285
+ from scitex.verify import render_dag
289
286
 
290
- result_path = render_plotly_dag(
291
- output_path=output_path,
292
- session_id=session,
293
- target_file=target_file,
294
- title=title,
295
- )
296
- else:
297
- from scitex.verify import render_dag
298
-
299
- result_path = render_dag(
300
- output_path=output_path,
301
- session_id=session,
302
- target_file=target_file,
303
- title=title,
304
- )
287
+ result_path = render_dag(
288
+ output_path=output_path,
289
+ session_id=session,
290
+ target_file=target_file,
291
+ title=title,
292
+ )
305
293
  click.secho(f"Rendered to: {result_path}", fg="green")
306
294
 
307
295
  except Exception as e:
@@ -433,25 +421,34 @@ def mcp(ctx):
433
421
 
434
422
 
435
423
  @mcp.command("list-tools")
436
- def list_tools():
437
- """
438
- List available MCP tools for verification.
439
-
440
- \b
441
- Example:
442
- scitex verify mcp list-tools
443
- """
424
+ @click.option("-v", "--verbose", count=True, help="-v params, -vv returns")
425
+ def list_tools(verbose):
426
+ """List available MCP tools for verification."""
444
427
  click.secho("Verify MCP Tools", fg="cyan", bold=True)
445
428
  click.echo()
429
+ # (name, desc, params, returns)
446
430
  tools = [
447
- ("verify_list", "List all tracked runs with verification status"),
448
- ("verify_run", "Verify a specific session run"),
449
- ("verify_chain", "Verify dependency chain for a target file"),
450
- ("verify_status", "Show verification status (like git status)"),
451
- ("verify_stats", "Show database statistics"),
431
+ ("verify_list", "List tracked runs", "limit=50, status_filter=None", "JSON"),
432
+ ("verify_run", "Verify a session run", "session_or_path: str", "JSON"),
433
+ ("verify_chain", "Verify dependency chain", "target_file: str", "JSON"),
434
+ ("verify_status", "Show status (like git status)", "", "JSON"),
435
+ ("verify_stats", "Show database statistics", "", "JSON"),
436
+ (
437
+ "verify_mermaid",
438
+ "Generate Mermaid DAG",
439
+ "session_id=None, target_file=None",
440
+ "str",
441
+ ),
452
442
  ]
453
- for name, desc in tools:
454
- click.echo(f" {name}: {desc}")
443
+ for name, desc, params, returns in tools:
444
+ click.secho(f" {name}", fg="green", bold=True, nl=False)
445
+ click.echo(f": {desc}")
446
+ if verbose >= 1 and params:
447
+ click.echo(f" params: {params}")
448
+ if verbose >= 2:
449
+ click.echo(f" returns: {returns}")
450
+ if verbose >= 1:
451
+ click.echo()
455
452
 
456
453
 
457
454
  @verify.command("list-python-apis")