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
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-02-02
3
+ # File: scitex/_dev/_dashboard/_styles.py
4
+
5
+ """CSS styles for the dashboard."""
6
+
7
+
8
+ def get_css() -> str:
9
+ """Return dashboard CSS."""
10
+ return """
11
+ :root {
12
+ --bg-primary: #1a1a2e;
13
+ --bg-secondary: #16213e;
14
+ --bg-card: #0f3460;
15
+ --text-primary: #eee;
16
+ --text-secondary: #aaa;
17
+ --accent: #e94560;
18
+ --success: #4ade80;
19
+ --warning: #fbbf24;
20
+ --error: #f87171;
21
+ --info: #60a5fa;
22
+ }
23
+ * { margin: 0; padding: 0; box-sizing: border-box; }
24
+ body {
25
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
26
+ background: var(--bg-primary);
27
+ color: var(--text-primary);
28
+ min-height: 100vh;
29
+ padding: 20px;
30
+ }
31
+ .container { max-width: 1400px; margin: 0 auto; }
32
+ header {
33
+ display: flex;
34
+ justify-content: space-between;
35
+ align-items: center;
36
+ margin-bottom: 30px;
37
+ padding: 20px;
38
+ background: var(--bg-secondary);
39
+ border-radius: 10px;
40
+ }
41
+ h1 { font-size: 1.8rem; color: var(--accent); }
42
+ .actions { display: flex; gap: 10px; }
43
+ button {
44
+ padding: 10px 20px;
45
+ border: none;
46
+ border-radius: 5px;
47
+ cursor: pointer;
48
+ font-size: 0.9rem;
49
+ transition: all 0.3s ease;
50
+ }
51
+ .btn-primary { background: var(--accent); color: white; }
52
+ .btn-primary:hover { background: #c9184a; }
53
+ .btn-secondary { background: var(--bg-card); color: var(--text-primary); }
54
+ .btn-secondary:hover { background: #1a4d80; }
55
+ .filters {
56
+ display: grid;
57
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
58
+ gap: 20px;
59
+ margin-bottom: 30px;
60
+ padding: 20px;
61
+ background: var(--bg-secondary);
62
+ border-radius: 10px;
63
+ }
64
+ .filter-group { display: flex; flex-direction: column; gap: 10px; }
65
+ .filter-group h3 {
66
+ font-size: 0.9rem;
67
+ color: var(--text-secondary);
68
+ text-transform: uppercase;
69
+ letter-spacing: 1px;
70
+ }
71
+ .filter-options { display: flex; flex-wrap: wrap; gap: 8px; }
72
+ .filter-options label {
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 5px;
76
+ padding: 5px 10px;
77
+ background: var(--bg-card);
78
+ border-radius: 5px;
79
+ cursor: pointer;
80
+ font-size: 0.85rem;
81
+ transition: all 0.2s ease;
82
+ }
83
+ .filter-options label:hover { background: #1a4d80; }
84
+ .filter-options input[type="checkbox"],
85
+ .filter-options input[type="radio"] { accent-color: var(--accent); }
86
+ .summary {
87
+ display: grid;
88
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
89
+ gap: 15px;
90
+ margin-bottom: 30px;
91
+ }
92
+ .summary-card {
93
+ padding: 20px;
94
+ background: var(--bg-secondary);
95
+ border-radius: 10px;
96
+ text-align: center;
97
+ }
98
+ .summary-card .number { font-size: 2rem; font-weight: bold; }
99
+ .summary-card .label { font-size: 0.85rem; color: var(--text-secondary); margin-top: 5px; }
100
+ .summary-card.ok .number { color: var(--success); }
101
+ .summary-card.unreleased .number { color: var(--warning); }
102
+ .summary-card.mismatch .number { color: var(--error); }
103
+ .summary-card.total .number { color: var(--info); }
104
+ .packages { display: grid; gap: 20px; }
105
+ .package-card { background: var(--bg-secondary); border-radius: 10px; overflow: hidden; }
106
+ .package-header {
107
+ display: flex;
108
+ justify-content: space-between;
109
+ align-items: center;
110
+ padding: 15px 20px;
111
+ background: var(--bg-card);
112
+ }
113
+ .package-name { font-size: 1.1rem; font-weight: bold; }
114
+ .status-badge {
115
+ padding: 5px 12px;
116
+ border-radius: 15px;
117
+ font-size: 0.75rem;
118
+ font-weight: bold;
119
+ text-transform: uppercase;
120
+ }
121
+ .status-ok { background: rgba(74, 222, 128, 0.2); color: var(--success); }
122
+ .status-unreleased { background: rgba(251, 191, 36, 0.2); color: var(--warning); }
123
+ .status-mismatch { background: rgba(248, 113, 113, 0.2); color: var(--error); }
124
+ .status-outdated { background: rgba(167, 139, 250, 0.2); color: #a78bfa; }
125
+ .status-unavailable { background: rgba(156, 163, 175, 0.2); color: #9ca3af; }
126
+ .status-error { background: rgba(248, 113, 113, 0.2); color: var(--error); }
127
+ .package-body { padding: 20px; }
128
+ .version-grid {
129
+ display: grid;
130
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
131
+ gap: 15px;
132
+ }
133
+ .version-section { padding: 10px; background: var(--bg-primary); border-radius: 5px; }
134
+ .version-section h4 {
135
+ font-size: 0.8rem;
136
+ color: var(--text-secondary);
137
+ margin-bottom: 8px;
138
+ text-transform: uppercase;
139
+ }
140
+ .version-item { display: flex; justify-content: space-between; padding: 5px 0; font-size: 0.9rem; }
141
+ .version-item .key { color: var(--text-secondary); }
142
+ .version-item .value { font-family: monospace; }
143
+ .issues {
144
+ margin-top: 15px;
145
+ padding: 10px;
146
+ background: rgba(248, 113, 113, 0.1);
147
+ border-radius: 5px;
148
+ border-left: 3px solid var(--error);
149
+ }
150
+ .issues h4 { font-size: 0.8rem; color: var(--error); margin-bottom: 5px; }
151
+ .issues ul { list-style: none; font-size: 0.85rem; color: var(--text-secondary); }
152
+ .issues li::before { content: "!"; margin-right: 8px; color: var(--error); }
153
+ .loading {
154
+ display: none;
155
+ position: fixed;
156
+ top: 50%;
157
+ left: 50%;
158
+ transform: translate(-50%, -50%);
159
+ background: var(--bg-secondary);
160
+ padding: 30px;
161
+ border-radius: 10px;
162
+ text-align: center;
163
+ z-index: 1000;
164
+ }
165
+ .loading.active { display: block; }
166
+ .spinner {
167
+ border: 4px solid var(--bg-card);
168
+ border-top: 4px solid var(--accent);
169
+ border-radius: 50%;
170
+ width: 40px;
171
+ height: 40px;
172
+ animation: spin 1s linear infinite;
173
+ margin: 0 auto 15px;
174
+ }
175
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
176
+ .overlay {
177
+ display: none;
178
+ position: fixed;
179
+ top: 0; left: 0; right: 0; bottom: 0;
180
+ background: rgba(0, 0, 0, 0.5);
181
+ z-index: 999;
182
+ }
183
+ .overlay.active { display: block; }
184
+ .last-updated { font-size: 0.8rem; color: var(--text-secondary); }
185
+ .loading-section { opacity: 0.5; position: relative; }
186
+ .loading-section::after {
187
+ content: "⟳";
188
+ position: absolute;
189
+ right: 5px;
190
+ top: -20px;
191
+ font-size: 1rem;
192
+ animation: spin 1s linear infinite;
193
+ color: var(--accent);
194
+ }
195
+ .just-updated {
196
+ animation: flash-green 0.5s ease;
197
+ }
198
+ @keyframes flash-green {
199
+ 0% { background: rgba(74, 222, 128, 0.3); }
200
+ 100% { background: transparent; }
201
+ }
202
+ .rtd-passing { color: var(--success); }
203
+ .rtd-failing { color: var(--error); }
204
+ .rtd-unknown { color: var(--warning); }
205
+ .rtd-passing a, .rtd-failing a, .rtd-unknown a {
206
+ color: inherit;
207
+ text-decoration: none;
208
+ }
209
+ .rtd-passing a:hover, .rtd-failing a:hover, .rtd-unknown a:hover {
210
+ text-decoration: underline;
211
+ }
212
+ /* Collapsible cards */
213
+ .package-card .package-header {
214
+ cursor: pointer;
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 10px;
218
+ }
219
+ .package-card .fold-icon {
220
+ transition: transform 0.2s ease;
221
+ font-size: 0.8rem;
222
+ color: var(--text-secondary);
223
+ }
224
+ .package-card:not(.collapsed) .fold-icon {
225
+ transform: rotate(90deg);
226
+ }
227
+ .package-card.collapsed .package-body {
228
+ display: none;
229
+ }
230
+ .package-card .package-name {
231
+ color: var(--accent);
232
+ text-decoration: none;
233
+ font-weight: bold;
234
+ }
235
+ .package-card .package-name:hover {
236
+ text-decoration: underline;
237
+ }
238
+ .package-card .quick-links {
239
+ margin-left: auto;
240
+ display: flex;
241
+ gap: 8px;
242
+ font-size: 1rem;
243
+ }
244
+ .package-card .quick-links a {
245
+ text-decoration: none;
246
+ opacity: 0.7;
247
+ transition: opacity 0.2s;
248
+ }
249
+ .package-card .quick-links a:hover {
250
+ opacity: 1;
251
+ }
252
+ /* Collapsible filters */
253
+ .filters.collapsed .filter-group {
254
+ display: none;
255
+ }
256
+ .filters-toggle {
257
+ cursor: pointer;
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 8px;
261
+ padding: 10px;
262
+ margin: -20px -20px 15px -20px;
263
+ background: var(--bg-card);
264
+ border-radius: 10px 10px 0 0;
265
+ color: var(--text-secondary);
266
+ font-size: 0.9rem;
267
+ }
268
+ .filters-toggle .fold-icon {
269
+ transition: transform 0.2s ease;
270
+ }
271
+ .filters:not(.collapsed) .filters-toggle .fold-icon {
272
+ transform: rotate(90deg);
273
+ }
274
+ .expand-controls {
275
+ display: flex;
276
+ gap: 10px;
277
+ margin-bottom: 15px;
278
+ }
279
+ .expand-controls button {
280
+ padding: 5px 12px;
281
+ font-size: 0.8rem;
282
+ }
283
+ /* Section header links */
284
+ .version-section h4 a {
285
+ color: var(--text-secondary);
286
+ text-decoration: none;
287
+ }
288
+ .version-section h4 a:hover {
289
+ color: var(--accent);
290
+ text-decoration: underline;
291
+ }
292
+ """
293
+
294
+
295
+ # EOF
@@ -0,0 +1,130 @@
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 collapsed">
40
+ <div class="filters-toggle" onclick="toggleFilters()">
41
+ <span class="fold-icon">▶</span>
42
+ <span>Filters &amp; Config</span>
43
+ </div>
44
+ <div class="filter-group">
45
+ <h3>Packages</h3>
46
+ <div class="filter-options" id="packageFilters"></div>
47
+ </div>
48
+ <div class="filter-group">
49
+ <h3>Status</h3>
50
+ <div class="filter-options" id="statusFilters">
51
+ <label><input type="checkbox" value="ok" checked> OK</label>
52
+ <label><input type="checkbox" value="unreleased" checked> Unreleased</label>
53
+ <label><input type="checkbox" value="mismatch" checked> Mismatch</label>
54
+ <label><input type="checkbox" value="outdated" checked> Outdated</label>
55
+ <label><input type="checkbox" value="unavailable" checked> Unavailable</label>
56
+ </div>
57
+ </div>
58
+ <div class="filter-group">
59
+ <h3>Hosts</h3>
60
+ <div class="filter-options" id="hostFilters"></div>
61
+ </div>
62
+ <div class="filter-group">
63
+ <h3>Remotes</h3>
64
+ <div class="filter-options" id="remoteFilters"></div>
65
+ </div>
66
+ <div class="filter-group">
67
+ <h3>RTD</h3>
68
+ <div class="filter-options" id="rtdFilters"></div>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="expand-controls">
73
+ <button class="btn-secondary" onclick="toggleAllCards(true)">Expand All</button>
74
+ <button class="btn-secondary" onclick="toggleAllCards(false)">Collapse All</button>
75
+ </div>
76
+
77
+ <div class="summary" id="summary"></div>
78
+ <div class="packages" id="packages"></div>
79
+ </div>
80
+
81
+ <div class="overlay" id="overlay"></div>
82
+ <div class="loading" id="loading">
83
+ <div class="spinner"></div>
84
+ <p>Loading version data...</p>
85
+ </div>
86
+
87
+ <script>{js}</script>
88
+ </body>
89
+ </html>
90
+ """
91
+
92
+
93
+ def get_error_html(error: str) -> str:
94
+ """Generate error page HTML."""
95
+ return f"""<!DOCTYPE html>
96
+ <html>
97
+ <head>
98
+ <title>Error - SciTeX Dashboard</title>
99
+ <style>
100
+ body {{
101
+ font-family: sans-serif;
102
+ background: #1a1a2e;
103
+ color: #eee;
104
+ display: flex;
105
+ justify-content: center;
106
+ align-items: center;
107
+ height: 100vh;
108
+ margin: 0;
109
+ }}
110
+ .error {{
111
+ background: #16213e;
112
+ padding: 40px;
113
+ border-radius: 10px;
114
+ text-align: center;
115
+ }}
116
+ .error h1 {{ color: #e94560; }}
117
+ .error p {{ color: #aaa; }}
118
+ </style>
119
+ </head>
120
+ <body>
121
+ <div class="error">
122
+ <h1>Error</h1>
123
+ <p>{error}</p>
124
+ </div>
125
+ </body>
126
+ </html>
127
+ """
128
+
129
+
130
+ # 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