scitex 2.17.0__py3-none-any.whl → 2.17.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 (73) 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 +169 -0
  6. scitex/_dev/_dashboard/_scripts.py +301 -0
  7. scitex/_dev/_dashboard/_styles.py +205 -0
  8. scitex/_dev/_dashboard/_templates.py +117 -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/_ssh.py +332 -0
  15. scitex/_dev/_versions.py +272 -0
  16. scitex/_mcp_tools/__init__.py +2 -0
  17. scitex/_mcp_tools/dev.py +186 -0
  18. scitex/audio/_audio_check.py +84 -41
  19. scitex/cli/capture.py +45 -22
  20. scitex/cli/dev.py +494 -0
  21. scitex/cli/main.py +2 -0
  22. scitex/cli/stats.py +48 -20
  23. scitex/cli/verify.py +33 -36
  24. scitex/plt/__init__.py +16 -6
  25. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  26. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  27. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  28. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  29. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  30. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  31. scitex/template/__init__.py +18 -1
  32. scitex/template/clone_research_minimal.py +111 -0
  33. scitex/verify/README.md +0 -12
  34. scitex/verify/__init__.py +0 -4
  35. scitex/verify/_visualize.py +0 -4
  36. scitex/verify/_viz/__init__.py +0 -18
  37. {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/METADATA +2 -1
  38. {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/RECORD +41 -49
  39. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  40. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  41. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  42. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  43. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  44. scitex/scholar/data/.gitkeep +0 -0
  45. scitex/scholar/data/README.md +0 -44
  46. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  47. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  48. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  49. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  50. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  51. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  52. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  53. scitex/scholar/data/bib_files/pac.bib +0 -698
  54. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  55. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  56. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  57. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  58. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  59. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  60. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  61. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  62. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  63. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  64. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  65. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  66. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  67. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  68. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  69. scitex/scholar/data/impact_factor.db +0 -0
  70. scitex/verify/_viz/_plotly.py +0 -193
  71. {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/WHEEL +0 -0
  72. {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/entry_points.txt +0 -0
  73. {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-02
3
+ # File: scitex/_dev/_dashboard/_templates.py
4
+
5
+ """HTML template generation for the dashboard."""
6
+
7
+ from ._scripts import get_javascript
8
+ from ._styles import get_css
9
+
10
+
11
+ def get_dashboard_html() -> str:
12
+ """Generate the main dashboard HTML."""
13
+ css = get_css()
14
+ js = get_javascript()
15
+
16
+ return f"""<!DOCTYPE html>
17
+ <html lang="en">
18
+ <head>
19
+ <meta charset="UTF-8">
20
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
21
+ <title>SciTeX Version Dashboard</title>
22
+ <link rel="icon" type="image/svg+xml" href="/static/version-dashboard-favicon.svg">
23
+ <style>{css}</style>
24
+ </head>
25
+ <body>
26
+ <div class="container">
27
+ <header>
28
+ <div>
29
+ <h1>SciTeX Version Dashboard</h1>
30
+ <span class="last-updated" id="lastUpdated">Loading...</span>
31
+ </div>
32
+ <div class="actions">
33
+ <button class="btn-secondary" onclick="exportJSON()">Export JSON</button>
34
+ <button class="btn-secondary" id="autoRefreshBtn" onclick="cycleAutoRefresh()">Auto: Off</button>
35
+ <button class="btn-primary" onclick="refreshData()">Refresh</button>
36
+ </div>
37
+ </header>
38
+
39
+ <div class="filters">
40
+ <div class="filter-group">
41
+ <h3>Packages</h3>
42
+ <div class="filter-options" id="packageFilters"></div>
43
+ </div>
44
+ <div class="filter-group">
45
+ <h3>Status</h3>
46
+ <div class="filter-options" id="statusFilters">
47
+ <label><input type="checkbox" value="ok" checked> OK</label>
48
+ <label><input type="checkbox" value="unreleased" checked> Unreleased</label>
49
+ <label><input type="checkbox" value="mismatch" checked> Mismatch</label>
50
+ <label><input type="checkbox" value="outdated" checked> Outdated</label>
51
+ <label><input type="checkbox" value="unavailable" checked> Unavailable</label>
52
+ </div>
53
+ </div>
54
+ <div class="filter-group">
55
+ <h3>Hosts</h3>
56
+ <div class="filter-options" id="hostFilters"></div>
57
+ </div>
58
+ <div class="filter-group">
59
+ <h3>Remotes</h3>
60
+ <div class="filter-options" id="remoteFilters"></div>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="summary" id="summary"></div>
65
+ <div class="packages" id="packages"></div>
66
+ </div>
67
+
68
+ <div class="overlay" id="overlay"></div>
69
+ <div class="loading" id="loading">
70
+ <div class="spinner"></div>
71
+ <p>Loading version data...</p>
72
+ </div>
73
+
74
+ <script>{js}</script>
75
+ </body>
76
+ </html>
77
+ """
78
+
79
+
80
+ def get_error_html(error: str) -> str:
81
+ """Generate error page HTML."""
82
+ return f"""<!DOCTYPE html>
83
+ <html>
84
+ <head>
85
+ <title>Error - SciTeX Dashboard</title>
86
+ <style>
87
+ body {{
88
+ font-family: sans-serif;
89
+ background: #1a1a2e;
90
+ color: #eee;
91
+ display: flex;
92
+ justify-content: center;
93
+ align-items: center;
94
+ height: 100vh;
95
+ margin: 0;
96
+ }}
97
+ .error {{
98
+ background: #16213e;
99
+ padding: 40px;
100
+ border-radius: 10px;
101
+ text-align: center;
102
+ }}
103
+ .error h1 {{ color: #e94560; }}
104
+ .error p {{ color: #aaa; }}
105
+ </style>
106
+ </head>
107
+ <body>
108
+ <div class="error">
109
+ <h1>Error</h1>
110
+ <p>{error}</p>
111
+ </div>
112
+ </body>
113
+ </html>
114
+ """
115
+
116
+
117
+ # EOF
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="scitex-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2160 2160">
3
+ <defs>
4
+ <style>
5
+ .snake-fill { fill: #4a9b7e; stroke-width: 0px; }
6
+ </style>
7
+ </defs>
8
+ <g>
9
+ <path class="snake-fill" d="m934.04,1199.85c-.1-.02-.22-.05-.34-.05-.34-.02-.8-.05-1.33-.05-.19-.29-.34-.49-.44-.63-.44-.63-.02-.24.8.17.46.24.97.44,1.31.56Z"/>
10
+ <path class="snake-fill" d="m1733.04,862.1c-1.25-10.54-3.55-19.84-6.08-28.08-2.58-8.26-5.45-15.48-8.33-21.77-5.83-12.56-11.51-21.35-15.67-27.01-2.07-2.83-3.74-4.87-4.87-6.24-.98-1.12-1.53-1.79-1.72-1.95.07.16.46.93,1.14,2.32.77,1.58,1.86,3.95,3.11,7.15,2.55,6.36,5.78,16.06,8.1,28.9,2.27,12.76,3.76,28.94,1.23,46.65-1.25,8.77-3.67,17.87-7.75,26.04-4.02,8.17-9.84,14.99-17.01,19.19-3.53,2.13-7.52,3.6-11.81,4.67-4.34,1-9.07,1.46-14.18,1.44-10.19-.02-21.82-2.2-34.05-6.01-3.04-.97-5.31-1.81-9.33-3.16l-2.74-.93c.12.02.19.02.23.02-.09-.09-.42-.16-.44-.19l-.63-.26-1.25-.51c-1.72-.67-3.41-1.35-5.11-2.02-6.8-2.79-13.6-5.78-20.31-8.98-13.39-6.55-26.62-13.97-38.74-22.68-12.12-8.66-23.33-18.29-32.05-28.99-8.87-10.63-15.27-21.93-18.94-33.21-1.86-5.66-3.06-11.3-3.64-17.06-.7-5.71-.79-11.51-.46-17.5.58-11.93,3.2-24.86,7.22-38.88,4.15-14.02,9.89-29.1,17.17-44.89,1.88-3.92,3.67-7.94,5.66-11.95.95-2.02,2-4.04,3.02-6.08l1.55-3.02c.51-1.02,1-1.86,1.51-2.79l1.46-2.72,1.69-3.27,1.95-3.81.97-1.9.49-.95.02-.02c-.02.14-.16.53.28-.51,4.39-9.59,8.4-20.21,11.49-32.1,3.02-11.86,5.06-25.02,5.41-39.04.35-13.99-1.02-28.8-4.53-43.28-3.46-14.44-8.87-28.36-15.5-40.92-6.61-12.51-14.39-23.6-22.54-33.28-16.39-19.45-33.82-33.21-50.62-44.28-16.85-11.05-33.4-19.24-49.53-26.11-32.26-13.44-63.38-21.33-94.18-26.62-30.8-5.22-61.25-7.47-91.68-7.77-60.85-.23-121.66,7.06-183.28,23.05-30.8,8.03-61.78,18.5-92.79,32.33-15.53,6.89-31.01,14.78-46.44,23.74-15.41,9.03-30.8,19.03-45.84,30.77-14.99,11.7-29.78,24.83-43.68,39.97-6.94,7.61-13.62,15.67-20.05,24.21-1.6,2.14-3.18,4.29-4.69,6.52-1.55,2.18-3.11,4.41-4.6,6.71-1.53,2.27-2.9,4.36-4.76,7.33l-2.58,4.18-1.11,1.88-.65,1.14-3.57,6.41-3.37,6.38c-2.25,4.22-4.39,8.7-6.5,13.18-2.14,4.41-4.13,9.07-6.1,13.79-2,4.62-3.81,9.54-5.59,14.41-7.1,19.66-12.7,41.22-15.13,64.38-2.46,23.09-1.97,47.6,2.67,71.39l1.79,8.87,2.25,8.75c1.42,5.87,3.39,11.44,5.25,17.13,3.99,11.07,8.54,21.91,13.86,31.89,10.42,20.21,23,37.78,36.25,53.13,13.28,15.39,27.27,28.71,41.47,40.43,28.43,23.46,57.51,41.43,86.52,56.86,29.03,15.34,58,28.11,86.92,39.46,57.84,22.58,115.37,39.83,172.6,54.68,14.32,3.64,28.52,7.5,42.59,11.63,14.06,4.15,28.01,8.59,41.94,13.02,7.06,2.18,14.09,4.36,21.12,6.52l10.19,3.04,5.08,1.51,1.44.42,1.07.35,2.11.67c11.37,3.64,22.37,7.59,32.77,12.09,20.86,8.96,39.73,19.66,54.98,31.63,7.59,5.94,14.32,12.14,19.87,18.43,5.55,6.27,9.98,12.53,13.3,18.43,3.2,5.94,5.38,11.51,6.45,16.48.6,2.51.79,4.85,1,7.03.02,2.23.09,4.25-.09,6.22-.46,3.9-1.16,7.4-2.46,10.98-1.16,3.5-2.81,7.22-4.94,11.19-4.15,8.01-10.82,17.41-20.08,27.36-9.33,9.93-21.21,20.15-35,29.73l-2.51,1.76-2.02,1.35-2,1.37-4.02,2.53-6.03,3.78c-2.18,1.35-4.34,2.72-6.55,3.99-8.77,5.25-17.52,10.28-26.27,15.09-17.52,9.59-35,18.29-52.17,25.92-17.17,7.61-34.07,14.25-50.22,19.29-16.15,5.13-31.59,8.7-45.14,10.42-6.78.88-13.07,1.28-18.75,1.35-5.64.09-10.61-.3-14.9-.88-8.59-1.28-14.23-3.04-19.54-6.8-5.36-3.71-10.4-10.65-13.97-21.03-1.74-5.13-3.11-11-3.99-17.34l-.32-2.41-.16-1.18-.09-.98c-.14-1.28-.28-2.53-.44-3.85-.07-2.46-.12-4.9-.21-7.36l-.05-1.81c-.02.53-.02.84-.05,1v-1.67l-.02-4.08c-.14-21.79-1.3-43.54-3.76-65.59-2.48-22.05-6.43-44.33-13.65-67.68-3.57-11.65-8.19-23.58-14.25-35.67-6.2-12.07-13.76-24.41-23.86-36.18-9.98-11.72-22.49-22.77-36.65-31.22-14.13-8.52-29.52-14.41-44.12-17.59-14.65-3.27-28.41-4.06-40.8-3.67-5.22.14-10.21.51-15.02,1.04-6.64.72-12.9,1.74-18.85,2.93-20.4,4.25-37.18,10.24-52.08,16.36-4.32,1.83-8.49,3.67-12.51,5.52-9.79,4.48-18.71,9-26.95,13.53-11.67,6.36-22.14,12.53-31.56,18.52-16.41,10.26-29.96,19.66-41.22,27.71l-28.25,8.66c-56.07,17.22-98.73,63.45-110.85,120.11l-24.97,117.02c-4.87,22.84,2.09,46.21,18.38,62.27-1.3,1.9-2.58,3.85-3.92,5.8-39.39,57.95-83.04,77.8-108.62,84.6-4.78,1.28-4.36,8.12.53,8.91,33.26,5.22,62.92-1.11,76.54-4.92,3.5-.97,7.03,1.72,6.87,5.34-1.07,26.18,18.1,57.12,31.38,75.27,2.44,3.3,7.57.86,6.66-3.13-12.74-53.89,4.22-107.32,25.51-148.47,25.6,10.19,55.24,9.28,81.37-3.57l86.57-42.59c58.65-28.85,97.45-86.76,101.1-150.84l3.04-53.15,5.52-3.74c1.88-.93,3.76-1.81,5.66-2.67,7.94-3.62,15.97-6.55,22.47-7.91,3.2-.67,6.01-1.07,7.94-1.14h.88c-.21-.3-.35-.49-.44-.63-.44-.63-.02-.26.79.16.46.25.97.44,1.32.56-.09-.02-.23-.05-.35-.05-.35-.02-.79-.05-1.32-.05.53.88,1.39,2.44,2.34,4.64,1.25,2.97,2.72,7.03,3.97,12,.7,2.44,1.28,5.2,1.86,7.98.49,2.92,1,5.89,1.42,9.1.84,6.36,1.46,13.25,1.83,20.59.79,14.62.32,30.8-.77,47.83l-.23,3.2-.05.81c-.02.14-.02.21-.02.25,0,0-.02.21-.07,1.93l-.09,1.83c-.16,2.44-.3,4.9-.44,7.36-.05,3.64-.09,7.29-.14,10.96l-.02,2.74.05,2.51.09,5.06c.39,13.55,1.58,27.71,4.15,42.5,2.53,14.81,6.52,30.22,12.44,45.88,5.96,15.6,13.88,31.45,24.18,46.49,10.24,15.04,22.74,29.15,36.76,41.45,14.02,12.25,29.5,22.74,45.42,31.24,15.94,8.45,32.35,15.06,48.74,20.17,16.34,5.01,32.68,8.59,48.83,10.98,32.33,4.87,63.8,5.13,94.51,2.6,30.64-2.67,60.55-8.22,89.59-16.36,29.06-8.1,57.28-18.75,84.6-31.56,13.65-6.43,27.06-13.39,40.22-20.91,3.32-1.86,6.59-3.81,9.86-5.73l2.44-1.46,1.23-.7,2.46-1.53,4.06-2.55,4.09-2.6,5.99-3.92,5.94-4.02,5.34-3.76c28.06-20.01,55.35-44.42,79.49-74.8,12-15.2,23.16-32.01,32.89-50.34,9.75-18.31,17.75-38.48,23.79-59.81,2.85-10.75,5.27-21.72,6.87-33.05.91-5.59,1.42-11.37,2-17.06.42-5.8.81-11.53.81-17.38.37-23.21-2.46-46.88-8.42-69.42-2.99-11.33-6.73-22.3-11.09-32.93-4.5-10.51-9.45-20.82-15.06-30.43-11.14-19.38-24.39-36.62-38.62-51.83-14.3-15.11-29.59-28.17-45.28-39.48-15.74-11.3-31.82-20.82-48.02-29.1-32.4-16.48-65.03-27.9-97.32-36.39-16.15-4.25-32.19-7.78-48.18-10.58-13.65-2.32-27.34-4.64-41.06-6.99-6.73-1.11-13.41-2.37-20.12-3.64-6.64-1.35-13.35-2.67-19.94-4.25-13.23-3.09-26.3-6.82-39.18-11-51.5-16.62-101.98-35.63-148.47-58.25-23.16-11.35-45.42-23.46-65.47-36.69-20.03-13.14-38.11-27.2-52.01-41.36-13.9-14.11-23.16-28.22-26.48-38.67-1.02-2.62-1.42-4.99-1.93-7.22-.05-1.09-.42-2.16-.37-3.2-.02-.51-.07-1.02-.14-1.53.02-.49.05-1,.02-1.49-.09-3.92.67-7.78,1.86-12.37,1.18-4.6,3.34-10.07,6.38-16.36.79-1.55,1.51-3.13,2.48-4.8.9-1.65,1.79-3.3,2.9-5.06,1.02-1.69,2.04-3.41,3.27-5.2l1.65-2.55c-.05.07-.09.16-.14.26l.51-.74,1.42-2.18.74-1.07c.28-.44.16-.16.26-.3.12-.07.21-.12.28-.19.07,0,.65-.7,1.11-1.23.44-.58.97-1.16,1.49-1.74.49-.56,1.02-1.14,1.58-1.72,2.14-2.3,4.53-4.67,7.15-7.01,5.2-4.73,11.47-9.52,18.47-14.14,7.01-4.59,14.85-9.1,23.26-13.32,8.45-4.2,17.43-8.08,26.83-11.74,18.82-7.24,39.22-13.18,60.13-17.85,41.94-9.28,86.1-13.39,127.81-12.88,20.84.18,41.1,1.53,59.9,3.76,18.73,2.21,36.09,5.62,49.55,9.4,5.62,1.51,10.44,3.2,14.09,4.53l-.93,3.74c-.84,3.25-1.63,6.52-2.37,9.84-1.53,6.61-2.97,13.28-4.2,19.98-4.94,26.83-7.8,54.63-6.94,83.14.84,28.45,5.38,57.7,15.25,85.55,9.68,27.83,24.95,53.71,43.31,74.36,18.31,20.8,39.22,36.41,59.79,47.83,20.66,11.49,40.94,19.26,60.39,24.88,19.43,5.52,37.97,9.14,55.63,11.6,8.82,1.28,17.43,2.23,25.83,2.95,2.09.19,4.18.35,6.27.51l1.56.14.77.05c.46.07.05-.05,1.21.16l2.92.16c3.44.23,8.66.6,13,.79,17.38.53,34.86-.65,51.78-5.41,8.45-2.41,16.69-5.71,24.28-10.05,7.61-4.46,14.55-9.89,20.17-16.11,5.66-6.2,10.1-13.02,13.23-19.87,3.2-6.85,5.25-13.65,6.52-20.15,2.48-13.02,2.2-24.83.95-35.32Zm-891.34,427.81l-2.74,14.18c-3.23,16.78-14.6,31.1-30.36,38.29l-19.82,9.05c-9.4,4.27-19.82-2.55-19.33-12.67l.19-4.18c1.16-25.27,17.15-47.97,40.87-58.07l9.14-3.9c11.93-5.08,24.44,4.73,22.05,17.29Z"/>
11
+ </g>
12
+ </svg>
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-03
3
+ # File: scitex/_dev/_ecosystem.py
4
+
5
+ """SciTeX ecosystem package registry."""
6
+
7
+ from pathlib import Path
8
+ from typing import TypedDict
9
+
10
+
11
+ class PackageInfo(TypedDict, total=False):
12
+ """Package information structure."""
13
+
14
+ local_path: str
15
+ pypi_name: str
16
+ github_repo: str
17
+ import_name: str
18
+
19
+
20
+ # Ordered dict - order matters for display
21
+ ECOSYSTEM: dict[str, PackageInfo] = {
22
+ "scitex": {
23
+ "local_path": "~/proj/scitex-python",
24
+ "pypi_name": "scitex",
25
+ "github_repo": "ywatanabe1989/scitex-python",
26
+ "import_name": "scitex",
27
+ },
28
+ "scitex-cloud": {
29
+ "local_path": "~/proj/scitex-cloud",
30
+ "pypi_name": "scitex-cloud",
31
+ "github_repo": "ywatanabe1989/scitex-cloud",
32
+ "import_name": "scitex_cloud",
33
+ },
34
+ "figrecipe": {
35
+ "local_path": "~/proj/figrecipe",
36
+ "pypi_name": "figrecipe",
37
+ "github_repo": "ywatanabe1989/figrecipe",
38
+ "import_name": "figrecipe",
39
+ },
40
+ "openalex-local": {
41
+ "local_path": "~/proj/openalex-local",
42
+ "pypi_name": "openalex-local",
43
+ "github_repo": "ywatanabe1989/openalex-local",
44
+ "import_name": "openalex_local",
45
+ },
46
+ "crossref-local": {
47
+ "local_path": "~/proj/crossref-local",
48
+ "pypi_name": "crossref-local",
49
+ "github_repo": "ywatanabe1989/crossref-local",
50
+ "import_name": "crossref_local",
51
+ },
52
+ "scitex-writer": {
53
+ "local_path": "~/proj/scitex-writer",
54
+ "pypi_name": "scitex-writer",
55
+ "github_repo": "ywatanabe1989/scitex-writer",
56
+ "import_name": "scitex_writer",
57
+ },
58
+ "scitex-dataset": {
59
+ "local_path": "~/proj/scitex-dataset",
60
+ "pypi_name": "scitex-dataset",
61
+ "github_repo": "ywatanabe1989/scitex-dataset",
62
+ "import_name": "scitex_dataset",
63
+ },
64
+ "socialia": {
65
+ "local_path": "~/proj/socialia",
66
+ "pypi_name": "socialia",
67
+ "github_repo": "ywatanabe1989/socialia",
68
+ "import_name": "socialia",
69
+ },
70
+ "automated-research-demo": {
71
+ "local_path": "~/proj/automated-research-demo",
72
+ "pypi_name": "automated-research-demo",
73
+ "github_repo": "ywatanabe1989/automated-research-demo",
74
+ "import_name": "automated_research_demo",
75
+ },
76
+ "scitex-research-template": {
77
+ "local_path": "~/proj/scitex-research-template",
78
+ "pypi_name": "scitex-research-template",
79
+ "github_repo": "ywatanabe1989/scitex-research-template",
80
+ "import_name": "scitex_research_template",
81
+ },
82
+ "pip-project-template": {
83
+ "local_path": "~/proj/pip-project-template",
84
+ "pypi_name": "pip-project-template",
85
+ "github_repo": "ywatanabe1989/pip-project-template",
86
+ "import_name": "pip_project_template",
87
+ },
88
+ "singularity-template": {
89
+ "local_path": "~/proj/singularity-template",
90
+ "pypi_name": "singularity-template",
91
+ "github_repo": "ywatanabe1989/singularity-template",
92
+ "import_name": "singularity_template",
93
+ },
94
+ }
95
+
96
+
97
+ def get_local_path(package: str) -> Path | None:
98
+ """Get expanded local path for a package."""
99
+ if package not in ECOSYSTEM:
100
+ return None
101
+ return Path(ECOSYSTEM[package]["local_path"]).expanduser()
102
+
103
+
104
+ def get_all_packages() -> list[str]:
105
+ """Get list of all ecosystem package names."""
106
+ return list(ECOSYSTEM.keys())
107
+
108
+
109
+ # EOF
scitex/_dev/_github.py ADDED
@@ -0,0 +1,360 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-02
3
+ # File: scitex/_dev/_github.py
4
+
5
+ """GitHub API integration for version checking."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import urllib.request
11
+ from typing import Any
12
+
13
+ from ._config import DevConfig, GitHubRemote, get_enabled_remotes, load_config
14
+
15
+
16
+ def _get_github_token() -> str | None:
17
+ """Get GitHub token from environment."""
18
+ return os.getenv("GITHUB_TOKEN") or os.getenv("GH_TOKEN")
19
+
20
+
21
+ def _github_api_request(url: str) -> dict[str, Any] | list[Any] | None:
22
+ """Make a GitHub API request.
23
+
24
+ Parameters
25
+ ----------
26
+ url : str
27
+ API URL to fetch.
28
+
29
+ Returns
30
+ -------
31
+ dict | list | None
32
+ JSON response or None on error.
33
+ """
34
+ import json
35
+
36
+ headers = {
37
+ "Accept": "application/vnd.github.v3+json",
38
+ "User-Agent": "scitex-dev",
39
+ }
40
+
41
+ token = _get_github_token()
42
+ if token:
43
+ headers["Authorization"] = f"token {token}"
44
+
45
+ req = urllib.request.Request(url, headers=headers)
46
+
47
+ try:
48
+ with urllib.request.urlopen(req, timeout=10) as response:
49
+ return json.loads(response.read().decode())
50
+ except urllib.error.HTTPError as e:
51
+ if e.code == 404:
52
+ return None
53
+ raise
54
+ except Exception:
55
+ return None
56
+
57
+
58
+ def get_github_tags(org: str, repo: str) -> list[str]:
59
+ """Get tags from a GitHub repository.
60
+
61
+ Parameters
62
+ ----------
63
+ org : str
64
+ GitHub organization or user.
65
+ repo : str
66
+ Repository name.
67
+
68
+ Returns
69
+ -------
70
+ list[str]
71
+ List of tag names (most recent first).
72
+ """
73
+ url = f"https://api.github.com/repos/{org}/{repo}/tags?per_page=10"
74
+ data = _github_api_request(url)
75
+
76
+ if not data or not isinstance(data, list):
77
+ return []
78
+
79
+ return [tag.get("name", "") for tag in data if tag.get("name")]
80
+
81
+
82
+ def get_github_latest_tag(org: str, repo: str) -> str | None:
83
+ """Get the latest version tag from a GitHub repository.
84
+
85
+ Parameters
86
+ ----------
87
+ org : str
88
+ GitHub organization or user.
89
+ repo : str
90
+ Repository name.
91
+
92
+ Returns
93
+ -------
94
+ str | None
95
+ Latest version tag or None.
96
+ """
97
+ tags = get_github_tags(org, repo)
98
+
99
+ # Filter to version tags (v*)
100
+ version_tags = [t for t in tags if t.startswith("v")]
101
+ if version_tags:
102
+ return version_tags[0]
103
+
104
+ # Fallback: any tags
105
+ return tags[0] if tags else None
106
+
107
+
108
+ def get_github_release(org: str, repo: str) -> dict[str, Any] | None:
109
+ """Get the latest release from a GitHub repository.
110
+
111
+ Parameters
112
+ ----------
113
+ org : str
114
+ GitHub organization or user.
115
+ repo : str
116
+ Repository name.
117
+
118
+ Returns
119
+ -------
120
+ dict | None
121
+ Release info with keys: tag_name, name, published_at, prerelease.
122
+ """
123
+ url = f"https://api.github.com/repos/{org}/{repo}/releases/latest"
124
+ data = _github_api_request(url)
125
+
126
+ if not data or not isinstance(data, dict):
127
+ return None
128
+
129
+ return {
130
+ "tag_name": data.get("tag_name"),
131
+ "name": data.get("name"),
132
+ "published_at": data.get("published_at"),
133
+ "prerelease": data.get("prerelease", False),
134
+ }
135
+
136
+
137
+ def get_github_repo_info(org: str, repo: str) -> dict[str, Any] | None:
138
+ """Get basic info about a GitHub repository.
139
+
140
+ Parameters
141
+ ----------
142
+ org : str
143
+ GitHub organization or user.
144
+ repo : str
145
+ Repository name.
146
+
147
+ Returns
148
+ -------
149
+ dict | None
150
+ Repository info with keys: default_branch, description, stars, forks.
151
+ """
152
+ url = f"https://api.github.com/repos/{org}/{repo}"
153
+ data = _github_api_request(url)
154
+
155
+ if not data or not isinstance(data, dict):
156
+ return None
157
+
158
+ return {
159
+ "default_branch": data.get("default_branch"),
160
+ "description": data.get("description"),
161
+ "stars": data.get("stargazers_count", 0),
162
+ "forks": data.get("forks_count", 0),
163
+ "private": data.get("private", False),
164
+ }
165
+
166
+
167
+ def check_github_remote(
168
+ remote: GitHubRemote,
169
+ packages: list[str],
170
+ config: DevConfig | None = None,
171
+ ) -> dict[str, dict[str, Any]]:
172
+ """Check versions for packages on a GitHub remote.
173
+
174
+ Parameters
175
+ ----------
176
+ remote : GitHubRemote
177
+ GitHub remote configuration.
178
+ packages : list[str]
179
+ List of package names to check.
180
+ config : DevConfig | None
181
+ Configuration for package -> repo mapping.
182
+
183
+ Returns
184
+ -------
185
+ dict
186
+ Package name -> version info mapping.
187
+ """
188
+ if config is None:
189
+ config = load_config()
190
+
191
+ from ._ecosystem import ECOSYSTEM
192
+
193
+ results = {}
194
+
195
+ for pkg in packages:
196
+ # Get repo name from ecosystem or config
197
+ repo = None
198
+ if pkg in ECOSYSTEM:
199
+ github_repo = ECOSYSTEM[pkg].get("github_repo", "")
200
+ if github_repo:
201
+ # Extract repo name (last part after /)
202
+ repo = github_repo.split("/")[-1]
203
+
204
+ # Check config packages
205
+ if not repo:
206
+ for pkg_conf in config.packages:
207
+ if pkg_conf.name == pkg and pkg_conf.github_repo:
208
+ repo = pkg_conf.github_repo.split("/")[-1]
209
+ break
210
+
211
+ if not repo:
212
+ # Try package name as repo name
213
+ repo = pkg
214
+
215
+ # Get tag and release info
216
+ try:
217
+ latest_tag = get_github_latest_tag(remote.org, repo)
218
+ release = get_github_release(remote.org, repo)
219
+
220
+ results[pkg] = {
221
+ "org": remote.org,
222
+ "repo": repo,
223
+ "latest_tag": latest_tag,
224
+ "release": release.get("tag_name") if release else None,
225
+ "release_date": release.get("published_at") if release else None,
226
+ "status": "ok" if latest_tag else "no_tags",
227
+ }
228
+ except Exception as e:
229
+ results[pkg] = {
230
+ "org": remote.org,
231
+ "repo": repo,
232
+ "latest_tag": None,
233
+ "release": None,
234
+ "status": "error",
235
+ "error": str(e),
236
+ }
237
+
238
+ return results
239
+
240
+
241
+ def check_all_remotes(
242
+ packages: list[str] | None = None,
243
+ remotes: list[str] | None = None,
244
+ config: DevConfig | None = None,
245
+ ) -> dict[str, dict[str, dict[str, Any]]]:
246
+ """Check versions on all enabled GitHub remotes.
247
+
248
+ Parameters
249
+ ----------
250
+ packages : list[str] | None
251
+ List of package names. If None, uses ecosystem packages.
252
+ remotes : list[str] | None
253
+ List of remote names to check. If None, checks all enabled remotes.
254
+ config : DevConfig | None
255
+ Configuration to use. If None, loads default config.
256
+
257
+ Returns
258
+ -------
259
+ dict
260
+ Mapping: remote_name -> package_name -> version_info
261
+ """
262
+ if config is None:
263
+ config = load_config()
264
+
265
+ if packages is None:
266
+ from ._ecosystem import get_all_packages
267
+
268
+ packages = get_all_packages()
269
+
270
+ enabled_remotes = get_enabled_remotes(config)
271
+ if remotes:
272
+ enabled_remotes = [r for r in enabled_remotes if r.name in remotes]
273
+
274
+ results = {}
275
+
276
+ for remote in enabled_remotes:
277
+ results[remote.name] = check_github_remote(remote, packages, config)
278
+ results[remote.name]["_remote"] = {
279
+ "org": remote.org,
280
+ }
281
+
282
+ return results
283
+
284
+
285
+ def compare_with_local(
286
+ packages: list[str] | None = None,
287
+ config: DevConfig | None = None,
288
+ ) -> dict[str, dict[str, Any]]:
289
+ """Compare local versions with GitHub remotes.
290
+
291
+ Parameters
292
+ ----------
293
+ packages : list[str] | None
294
+ List of package names. If None, uses ecosystem packages.
295
+ config : DevConfig | None
296
+ Configuration to use.
297
+
298
+ Returns
299
+ -------
300
+ dict
301
+ Comparison results with local vs remote versions.
302
+ """
303
+ if config is None:
304
+ config = load_config()
305
+
306
+ if packages is None:
307
+ from ._ecosystem import get_all_packages
308
+
309
+ packages = get_all_packages()
310
+
311
+ from ._versions import list_versions
312
+
313
+ local_versions = list_versions(packages)
314
+ remote_versions = check_all_remotes(packages, config=config)
315
+
316
+ results = {}
317
+
318
+ for pkg in packages:
319
+ local_info = local_versions.get(pkg, {})
320
+ local_tag = local_info.get("git", {}).get("latest_tag")
321
+ local_toml = local_info.get("local", {}).get("pyproject_toml")
322
+
323
+ pkg_result = {
324
+ "local": {
325
+ "tag": local_tag,
326
+ "toml": local_toml,
327
+ },
328
+ "remotes": {},
329
+ "sync_status": "ok",
330
+ "issues": [],
331
+ }
332
+
333
+ for remote_name, remote_data in remote_versions.items():
334
+ if remote_name.startswith("_"):
335
+ continue
336
+
337
+ pkg_remote = remote_data.get(pkg, {})
338
+ remote_tag = pkg_remote.get("latest_tag")
339
+
340
+ pkg_result["remotes"][remote_name] = {
341
+ "tag": remote_tag,
342
+ "release": pkg_remote.get("release"),
343
+ }
344
+
345
+ # Check sync status
346
+ if local_tag and remote_tag and local_tag != remote_tag:
347
+ pkg_result["issues"].append(
348
+ f"local tag ({local_tag}) != {remote_name} ({remote_tag})"
349
+ )
350
+ pkg_result["sync_status"] = "out_of_sync"
351
+
352
+ if pkg_result["issues"]:
353
+ pkg_result["sync_status"] = "out_of_sync"
354
+
355
+ results[pkg] = pkg_result
356
+
357
+ return results
358
+
359
+
360
+ # EOF
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-02
3
+ # File: scitex/_dev/_mcp/__init__.py
4
+
5
+ """MCP handlers for developer utilities."""
6
+
7
+ from .handlers import check_versions_handler, list_versions_handler
8
+
9
+ __all__ = ["list_versions_handler", "check_versions_handler"]
10
+
11
+ # EOF