gitinstall 1.1.0__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.
- gitinstall/__init__.py +61 -0
- gitinstall/_sdk.py +541 -0
- gitinstall/academic.py +831 -0
- gitinstall/admin.html +327 -0
- gitinstall/auto_update.py +384 -0
- gitinstall/autopilot.py +349 -0
- gitinstall/badge.py +476 -0
- gitinstall/checkpoint.py +330 -0
- gitinstall/cicd.py +499 -0
- gitinstall/clawhub.html +718 -0
- gitinstall/config_schema.py +353 -0
- gitinstall/db.py +984 -0
- gitinstall/db_backend.py +445 -0
- gitinstall/dep_chain.py +337 -0
- gitinstall/dependency_audit.py +1153 -0
- gitinstall/detector.py +542 -0
- gitinstall/doctor.py +493 -0
- gitinstall/education.py +869 -0
- gitinstall/enterprise.py +802 -0
- gitinstall/error_fixer.py +953 -0
- gitinstall/event_bus.py +251 -0
- gitinstall/executor.py +577 -0
- gitinstall/feature_flags.py +138 -0
- gitinstall/fetcher.py +921 -0
- gitinstall/huggingface.py +922 -0
- gitinstall/hw_detect.py +988 -0
- gitinstall/i18n.py +664 -0
- gitinstall/installer_registry.py +362 -0
- gitinstall/knowledge_base.py +379 -0
- gitinstall/license_check.py +605 -0
- gitinstall/llm.py +569 -0
- gitinstall/log.py +236 -0
- gitinstall/main.py +1408 -0
- gitinstall/mcp_agent.py +841 -0
- gitinstall/mcp_server.py +386 -0
- gitinstall/monorepo.py +810 -0
- gitinstall/multi_source.py +425 -0
- gitinstall/onboard.py +276 -0
- gitinstall/planner.py +222 -0
- gitinstall/planner_helpers.py +323 -0
- gitinstall/planner_known_projects.py +1010 -0
- gitinstall/planner_templates.py +996 -0
- gitinstall/remote_gpu.py +633 -0
- gitinstall/resilience.py +608 -0
- gitinstall/run_tests.py +572 -0
- gitinstall/skills.py +476 -0
- gitinstall/tool_schemas.py +324 -0
- gitinstall/trending.py +279 -0
- gitinstall/uninstaller.py +415 -0
- gitinstall/validate_top100.py +607 -0
- gitinstall/watchdog.py +180 -0
- gitinstall/web.py +1277 -0
- gitinstall/web_ui.html +2277 -0
- gitinstall-1.1.0.dist-info/METADATA +275 -0
- gitinstall-1.1.0.dist-info/RECORD +59 -0
- gitinstall-1.1.0.dist-info/WHEEL +5 -0
- gitinstall-1.1.0.dist-info/entry_points.txt +3 -0
- gitinstall-1.1.0.dist-info/licenses/LICENSE +21 -0
- gitinstall-1.1.0.dist-info/top_level.txt +1 -0
gitinstall/admin.html
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>gitinstall — 管理后台</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
|
+
:root {
|
|
10
|
+
--bg: #0a0a0f;
|
|
11
|
+
--bg-card: rgba(255,255,255,0.03);
|
|
12
|
+
--bg-glass: rgba(255,255,255,0.04);
|
|
13
|
+
--bg-elevated: rgba(255,255,255,0.06);
|
|
14
|
+
--border: rgba(255,255,255,0.06);
|
|
15
|
+
--border-hover: rgba(255,255,255,0.12);
|
|
16
|
+
--text: #f0f0f5;
|
|
17
|
+
--text-sec: #94949e;
|
|
18
|
+
--text-muted: #5a5a66;
|
|
19
|
+
--accent: #8b5cf6;
|
|
20
|
+
--accent-3: #a78bfa;
|
|
21
|
+
--cyan: #22d3ee;
|
|
22
|
+
--green: #34d399;
|
|
23
|
+
--red: #f87171;
|
|
24
|
+
--amber: #fbbf24;
|
|
25
|
+
--mono: 'JetBrains Mono','SF Mono',Consolas,monospace;
|
|
26
|
+
--sans: 'Inter',system-ui,-apple-system,sans-serif;
|
|
27
|
+
--radius: 16px;
|
|
28
|
+
--radius-sm: 10px;
|
|
29
|
+
--radius-xs: 6px;
|
|
30
|
+
}
|
|
31
|
+
body {
|
|
32
|
+
font-family: var(--sans);
|
|
33
|
+
background: var(--bg);
|
|
34
|
+
color: var(--text);
|
|
35
|
+
line-height: 1.6;
|
|
36
|
+
min-height: 100vh;
|
|
37
|
+
}
|
|
38
|
+
.app { max-width: 960px; margin: 0 auto; padding: 2rem 1.5rem; }
|
|
39
|
+
|
|
40
|
+
h1 { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.3rem; }
|
|
41
|
+
.subtitle { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 2rem; }
|
|
42
|
+
|
|
43
|
+
/* Auth gate */
|
|
44
|
+
.auth-gate {
|
|
45
|
+
max-width: 380px;
|
|
46
|
+
margin: 4rem auto;
|
|
47
|
+
background: var(--bg-glass);
|
|
48
|
+
border: 1px solid var(--border);
|
|
49
|
+
border-radius: var(--radius);
|
|
50
|
+
padding: 2rem;
|
|
51
|
+
text-align: center;
|
|
52
|
+
}
|
|
53
|
+
.auth-gate h2 { font-size: 1.1rem; margin-bottom: 1rem; }
|
|
54
|
+
.auth-gate input {
|
|
55
|
+
display: block; width: 100%; padding: 0.6rem 0.8rem; margin-bottom: 0.6rem;
|
|
56
|
+
background: rgba(255,255,255,0.03); border: 1px solid var(--border);
|
|
57
|
+
border-radius: var(--radius-xs); color: var(--text); font-size: 0.85rem;
|
|
58
|
+
font-family: var(--sans); outline: none;
|
|
59
|
+
}
|
|
60
|
+
.auth-gate input:focus { border-color: var(--accent); }
|
|
61
|
+
.auth-gate button {
|
|
62
|
+
width: 100%; padding: 0.6rem; margin-top: 0.3rem;
|
|
63
|
+
background: linear-gradient(135deg, var(--accent), #6366f1);
|
|
64
|
+
border: none; border-radius: var(--radius-xs);
|
|
65
|
+
color: #fff; font-size: 0.85rem; cursor: pointer;
|
|
66
|
+
font-family: var(--sans); font-weight: 600;
|
|
67
|
+
}
|
|
68
|
+
.auth-gate button:hover { opacity: 0.9; }
|
|
69
|
+
.auth-msg { margin-top: 0.5rem; font-size: 0.8rem; color: var(--red); min-height: 1.2rem; }
|
|
70
|
+
|
|
71
|
+
/* Dashboard */
|
|
72
|
+
.dashboard { display: none; }
|
|
73
|
+
.dashboard.visible { display: block; }
|
|
74
|
+
|
|
75
|
+
.stats-grid {
|
|
76
|
+
display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem;
|
|
77
|
+
}
|
|
78
|
+
@media (max-width: 600px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } }
|
|
79
|
+
.stat-item {
|
|
80
|
+
text-align: center; padding: 1.2rem 0.5rem;
|
|
81
|
+
background: var(--bg-glass); border-radius: var(--radius-sm); border: 1px solid var(--border);
|
|
82
|
+
}
|
|
83
|
+
.stat-num {
|
|
84
|
+
font-size: 1.8rem; font-weight: 700; font-family: var(--mono);
|
|
85
|
+
background: linear-gradient(135deg, var(--accent), var(--cyan));
|
|
86
|
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
|
|
87
|
+
}
|
|
88
|
+
.stat-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.3rem; }
|
|
89
|
+
|
|
90
|
+
.panel {
|
|
91
|
+
background: var(--bg-glass); border: 1px solid var(--border);
|
|
92
|
+
border-radius: var(--radius-sm); padding: 1rem; margin-bottom: 1rem;
|
|
93
|
+
}
|
|
94
|
+
.panel-title { font-size: 0.85rem; font-weight: 600; color: var(--text-sec); margin-bottom: 0.6rem; }
|
|
95
|
+
|
|
96
|
+
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
|
|
97
|
+
@media (max-width: 600px) { .detail-grid { grid-template-columns: 1fr; } }
|
|
98
|
+
|
|
99
|
+
.row { display: flex; justify-content: space-between; align-items: center; font-size: 0.8rem; padding: 0.3rem 0; color: var(--text-sec); }
|
|
100
|
+
.bar { height: 4px; background: var(--bg-elevated); border-radius: 2px; flex: 1; margin: 0 0.6rem; overflow: hidden; }
|
|
101
|
+
.bar-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--cyan)); border-radius: 2px; }
|
|
102
|
+
|
|
103
|
+
/* Recent installs table */
|
|
104
|
+
.table-wrap { overflow-x: auto; }
|
|
105
|
+
table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
|
|
106
|
+
th { text-align: left; color: var(--text-muted); font-weight: 600; padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border); }
|
|
107
|
+
td { padding: 0.5rem 0.6rem; border-bottom: 1px solid rgba(255,255,255,0.03); color: var(--text-sec); }
|
|
108
|
+
.badge-ok { color: var(--green); }
|
|
109
|
+
.badge-fail { color: var(--red); }
|
|
110
|
+
|
|
111
|
+
/* Daily trend chart (simple CSS bars) */
|
|
112
|
+
.trend-chart { display: flex; align-items: flex-end; gap: 2px; height: 80px; margin-top: 0.5rem; }
|
|
113
|
+
.trend-bar {
|
|
114
|
+
flex: 1; background: linear-gradient(to top, var(--accent), var(--cyan));
|
|
115
|
+
border-radius: 2px 2px 0 0; min-width: 4px; transition: height 0.4s;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.btn-back {
|
|
119
|
+
display: inline-block; margin-bottom: 1.5rem; color: var(--text-muted); font-size: 0.8rem;
|
|
120
|
+
text-decoration: none; border: 1px solid var(--border); padding: 0.3rem 0.8rem;
|
|
121
|
+
border-radius: var(--radius-xs);
|
|
122
|
+
}
|
|
123
|
+
.btn-back:hover { color: var(--text); border-color: var(--border-hover); }
|
|
124
|
+
|
|
125
|
+
.header-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.3rem; }
|
|
126
|
+
.btn-logout {
|
|
127
|
+
background: none; border: 1px solid rgba(248,113,113,0.3); color: var(--red);
|
|
128
|
+
padding: 0.3rem 0.8rem; border-radius: var(--radius-xs); cursor: pointer;
|
|
129
|
+
font-size: 0.75rem; font-family: var(--sans);
|
|
130
|
+
}
|
|
131
|
+
.btn-logout:hover { background: rgba(248,113,113,0.1); }
|
|
132
|
+
</style>
|
|
133
|
+
</head>
|
|
134
|
+
<body>
|
|
135
|
+
<div class="app">
|
|
136
|
+
|
|
137
|
+
<!-- Auth gate -->
|
|
138
|
+
<div class="auth-gate" id="auth-gate">
|
|
139
|
+
<h2>🔒 管理后台</h2>
|
|
140
|
+
<p style="color:var(--text-muted);font-size:0.8rem;margin-bottom:1rem">请使用管理员账号登录</p>
|
|
141
|
+
<form onsubmit="adminLogin(event)">
|
|
142
|
+
<input type="email" id="admin-email" placeholder="管理员邮箱" required>
|
|
143
|
+
<input type="password" id="admin-pw" placeholder="密码" required>
|
|
144
|
+
<button type="submit">登录</button>
|
|
145
|
+
</form>
|
|
146
|
+
<div class="auth-msg" id="auth-msg"></div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- Dashboard (hidden until auth) -->
|
|
150
|
+
<div class="dashboard" id="dashboard">
|
|
151
|
+
<a class="btn-back" href="/">← 返回主页</a>
|
|
152
|
+
<div class="header-row">
|
|
153
|
+
<div>
|
|
154
|
+
<h1>📊 gitinstall 管理后台</h1>
|
|
155
|
+
<div class="subtitle">欢迎,<span id="admin-name"></span></div>
|
|
156
|
+
</div>
|
|
157
|
+
<button class="btn-logout" onclick="adminLogout()">退出</button>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="stats-grid">
|
|
161
|
+
<div class="stat-item"><div class="stat-num" id="s-plans">-</div><div class="stat-label">安装计划</div></div>
|
|
162
|
+
<div class="stat-item"><div class="stat-num" id="s-installs">-</div><div class="stat-label">成功安装</div></div>
|
|
163
|
+
<div class="stat-item"><div class="stat-num" id="s-users">-</div><div class="stat-label">注册用户</div></div>
|
|
164
|
+
<div class="stat-item"><div class="stat-num" id="s-rate">-</div><div class="stat-label">成功率</div></div>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<div class="detail-grid">
|
|
168
|
+
<div class="panel">
|
|
169
|
+
<div class="panel-title">🏆 热门项目</div>
|
|
170
|
+
<div id="top-projects"></div>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="panel">
|
|
173
|
+
<div class="panel-title">💻 操作系统分布</div>
|
|
174
|
+
<div id="os-dist"></div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<div class="panel">
|
|
179
|
+
<div class="panel-title">📈 近 30 天趋势</div>
|
|
180
|
+
<div class="trend-chart" id="trend-chart"></div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div class="panel">
|
|
184
|
+
<div class="panel-title">🕐 最近安装</div>
|
|
185
|
+
<div class="table-wrap">
|
|
186
|
+
<table>
|
|
187
|
+
<thead><tr><th>项目</th><th>策略</th><th>置信度</th><th>结果</th><th>耗时</th></tr></thead>
|
|
188
|
+
<tbody id="recent-tbody"></tbody>
|
|
189
|
+
</table>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<script>
|
|
197
|
+
const $ = id => document.getElementById(id);
|
|
198
|
+
let adminToken = localStorage.getItem('gitinstall_admin_token') || '';
|
|
199
|
+
|
|
200
|
+
// Try auto-login if token exists
|
|
201
|
+
if (adminToken) loadDashboard();
|
|
202
|
+
|
|
203
|
+
async function adminLogin(e) {
|
|
204
|
+
e.preventDefault();
|
|
205
|
+
const msg = $('auth-msg');
|
|
206
|
+
msg.textContent = '登录中...';
|
|
207
|
+
msg.style.color = 'var(--text-muted)';
|
|
208
|
+
try {
|
|
209
|
+
const res = await fetch('/api/login', {
|
|
210
|
+
method: 'POST',
|
|
211
|
+
headers: {'Content-Type': 'application/json'},
|
|
212
|
+
body: JSON.stringify({ email: $('admin-email').value, password: $('admin-pw').value }),
|
|
213
|
+
});
|
|
214
|
+
const d = await res.json();
|
|
215
|
+
if (d.status !== 'ok') { msg.textContent = d.message || '登录失败'; msg.style.color = ''; return; }
|
|
216
|
+
adminToken = d.token;
|
|
217
|
+
localStorage.setItem('gitinstall_admin_token', adminToken);
|
|
218
|
+
loadDashboard();
|
|
219
|
+
} catch (err) {
|
|
220
|
+
msg.textContent = '网络错误';
|
|
221
|
+
msg.style.color = '';
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function loadDashboard() {
|
|
226
|
+
try {
|
|
227
|
+
const res = await fetch('/api/stats', {
|
|
228
|
+
headers: {'Authorization': 'Bearer ' + adminToken},
|
|
229
|
+
});
|
|
230
|
+
const d = await res.json();
|
|
231
|
+
if (d.status !== 'ok') {
|
|
232
|
+
// Not admin or token expired
|
|
233
|
+
adminToken = '';
|
|
234
|
+
localStorage.removeItem('gitinstall_admin_token');
|
|
235
|
+
$('auth-gate').style.display = '';
|
|
236
|
+
$('dashboard').classList.remove('visible');
|
|
237
|
+
$('auth-msg').textContent = d.message || '权限不足,请使用管理员账号';
|
|
238
|
+
$('auth-msg').style.color = '';
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Get user info
|
|
243
|
+
const userRes = await fetch('/api/user', { headers: {'Authorization': 'Bearer ' + adminToken} });
|
|
244
|
+
const userData = await userRes.json();
|
|
245
|
+
$('admin-name').textContent = userData.user ? userData.user.username : '管理员';
|
|
246
|
+
|
|
247
|
+
// Show dashboard
|
|
248
|
+
$('auth-gate').style.display = 'none';
|
|
249
|
+
$('dashboard').classList.add('visible');
|
|
250
|
+
|
|
251
|
+
// Fill stats
|
|
252
|
+
$('s-plans').textContent = fmtNum(d.total_plans);
|
|
253
|
+
$('s-installs').textContent = fmtNum(d.total_installs);
|
|
254
|
+
$('s-users').textContent = fmtNum(d.total_users);
|
|
255
|
+
$('s-rate').textContent = d.success_rate + '%';
|
|
256
|
+
|
|
257
|
+
// Top projects
|
|
258
|
+
if (d.top_projects && d.top_projects.length) {
|
|
259
|
+
const max = d.top_projects[0].count;
|
|
260
|
+
$('top-projects').innerHTML = d.top_projects.map(p => {
|
|
261
|
+
const pct = Math.round(p.count / max * 100);
|
|
262
|
+
return `<div class="row"><span>${esc(p.project)}</span><div class="bar"><div class="bar-fill" style="width:${pct}%"></div></div><span>${p.count}</span></div>`;
|
|
263
|
+
}).join('');
|
|
264
|
+
} else {
|
|
265
|
+
$('top-projects').innerHTML = '<div style="color:var(--text-muted);font-size:0.8rem">暂无数据</div>';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// OS distribution
|
|
269
|
+
if (d.os_distribution && d.os_distribution.length) {
|
|
270
|
+
const total = d.os_distribution.reduce((s, o) => s + o.count, 0);
|
|
271
|
+
$('os-dist').innerHTML = d.os_distribution.map(o => {
|
|
272
|
+
const pct = Math.round(o.count / total * 100);
|
|
273
|
+
return `<div class="row"><span>${esc(o.os)}</span><div class="bar"><div class="bar-fill" style="width:${pct}%"></div></div><span>${pct}%</span></div>`;
|
|
274
|
+
}).join('');
|
|
275
|
+
} else {
|
|
276
|
+
$('os-dist').innerHTML = '<div style="color:var(--text-muted);font-size:0.8rem">暂无数据</div>';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Daily trend
|
|
280
|
+
if (d.daily_trend && d.daily_trend.length) {
|
|
281
|
+
const maxC = Math.max(...d.daily_trend.map(t => t.count));
|
|
282
|
+
$('trend-chart').innerHTML = d.daily_trend.map(t => {
|
|
283
|
+
const h = Math.max(4, Math.round(t.count / maxC * 76));
|
|
284
|
+
return `<div class="trend-bar" style="height:${h}px" title="${t.date}: ${t.count}"></div>`;
|
|
285
|
+
}).join('');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Recent installs
|
|
289
|
+
if (d.recent_installs && d.recent_installs.length) {
|
|
290
|
+
$('recent-tbody').innerHTML = d.recent_installs.map(r => {
|
|
291
|
+
const ok = r.success;
|
|
292
|
+
const badge = ok === true ? '<span class="badge-ok">✓ 成功</span>'
|
|
293
|
+
: ok === false ? '<span class="badge-fail">✗ 失败</span>'
|
|
294
|
+
: '<span style="color:var(--text-muted)">-</span>';
|
|
295
|
+
const dur = r.duration != null ? r.duration + 's' : '-';
|
|
296
|
+
return `<tr><td>${esc(r.project)}</td><td>${esc(r.strategy||'-')}</td><td>${esc(r.confidence||'-')}</td><td>${badge}</td><td>${dur}</td></tr>`;
|
|
297
|
+
}).join('');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
} catch (err) {
|
|
301
|
+
$('auth-msg').textContent = '加载失败:' + err.message;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function adminLogout() {
|
|
306
|
+
adminToken = '';
|
|
307
|
+
localStorage.removeItem('gitinstall_admin_token');
|
|
308
|
+
$('auth-gate').style.display = '';
|
|
309
|
+
$('dashboard').classList.remove('visible');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function fmtNum(n) {
|
|
313
|
+
if (typeof n !== 'number') return '0';
|
|
314
|
+
if (n >= 10000) return (n / 10000).toFixed(1) + 'w';
|
|
315
|
+
if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
|
|
316
|
+
return String(n);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function esc(s) {
|
|
320
|
+
if (!s) return '';
|
|
321
|
+
const d = document.createElement('div');
|
|
322
|
+
d.textContent = String(s);
|
|
323
|
+
return d.innerHTML;
|
|
324
|
+
}
|
|
325
|
+
</script>
|
|
326
|
+
</body>
|
|
327
|
+
</html>
|