scitex 2.16.2__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.
- scitex/_dev/__init__.py +122 -0
- scitex/_dev/_config.py +391 -0
- scitex/_dev/_dashboard/__init__.py +11 -0
- scitex/_dev/_dashboard/_app.py +89 -0
- scitex/_dev/_dashboard/_routes.py +169 -0
- scitex/_dev/_dashboard/_scripts.py +301 -0
- scitex/_dev/_dashboard/_styles.py +205 -0
- scitex/_dev/_dashboard/_templates.py +117 -0
- scitex/_dev/_dashboard/static/version-dashboard-favicon.svg +12 -0
- scitex/_dev/_ecosystem.py +109 -0
- scitex/_dev/_github.py +360 -0
- scitex/_dev/_mcp/__init__.py +11 -0
- scitex/_dev/_mcp/handlers.py +182 -0
- scitex/_dev/_ssh.py +332 -0
- scitex/_dev/_versions.py +272 -0
- scitex/_mcp_resources/_cheatsheet.py +1 -1
- scitex/_mcp_resources/_modules.py +1 -1
- scitex/_mcp_tools/__init__.py +4 -0
- scitex/_mcp_tools/dev.py +186 -0
- scitex/_mcp_tools/verify.py +256 -0
- scitex/audio/_audio_check.py +84 -41
- scitex/cli/capture.py +45 -22
- scitex/cli/dev.py +494 -0
- scitex/cli/main.py +4 -0
- scitex/cli/stats.py +48 -20
- scitex/cli/verify.py +473 -0
- scitex/dev/plt/__init__.py +1 -1
- scitex/dev/plt/mpl/get_dir_ax.py +1 -1
- scitex/dev/plt/mpl/get_signatures.py +1 -1
- scitex/dev/plt/mpl/get_signatures_details.py +1 -1
- scitex/io/_load.py +8 -1
- scitex/io/_save.py +12 -0
- scitex/plt/__init__.py +16 -6
- scitex/session/README.md +2 -2
- scitex/session/__init__.py +1 -0
- scitex/session/_decorator.py +57 -33
- scitex/session/_lifecycle/__init__.py +23 -0
- scitex/session/_lifecycle/_close.py +225 -0
- scitex/session/_lifecycle/_config.py +112 -0
- scitex/session/_lifecycle/_matplotlib.py +83 -0
- scitex/session/_lifecycle/_start.py +246 -0
- scitex/session/_lifecycle/_utils.py +186 -0
- scitex/session/_manager.py +40 -3
- scitex/session/template.py +1 -1
- scitex/template/__init__.py +18 -1
- scitex/template/_templates/plt.py +1 -1
- scitex/template/_templates/session.py +1 -1
- scitex/template/clone_research_minimal.py +111 -0
- scitex/verify/README.md +300 -0
- scitex/verify/__init__.py +208 -0
- scitex/verify/_chain.py +369 -0
- scitex/verify/_db.py +600 -0
- scitex/verify/_hash.py +187 -0
- scitex/verify/_integration.py +127 -0
- scitex/verify/_rerun.py +253 -0
- scitex/verify/_tracker.py +330 -0
- scitex/verify/_visualize.py +44 -0
- scitex/verify/_viz/__init__.py +38 -0
- scitex/verify/_viz/_colors.py +84 -0
- scitex/verify/_viz/_format.py +302 -0
- scitex/verify/_viz/_json.py +192 -0
- scitex/verify/_viz/_mermaid.py +440 -0
- scitex/verify/_viz/_templates.py +246 -0
- scitex/verify/_viz/_utils.py +56 -0
- {scitex-2.16.2.dist-info → scitex-2.17.3.dist-info}/METADATA +2 -1
- {scitex-2.16.2.dist-info → scitex-2.17.3.dist-info}/RECORD +69 -28
- scitex/session/_lifecycle.py +0 -827
- {scitex-2.16.2.dist-info → scitex-2.17.3.dist-info}/WHEEL +0 -0
- {scitex-2.16.2.dist-info → scitex-2.17.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.16.2.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
|