skill-base 2.0.3 → 2.0.6

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. package/README.md +189 -85
  2. package/bin/skill-base.js +33 -7
  3. package/package.json +3 -1
  4. package/src/cappy.js +416 -0
  5. package/src/database.js +11 -0
  6. package/src/index.js +87 -24
  7. package/src/middleware/auth.js +96 -32
  8. package/src/routes/auth.js +1 -1
  9. package/src/routes/skills.js +10 -5
  10. package/src/utils/zip.js +15 -4
  11. package/static/android-chrome-192x192.png +0 -0
  12. package/static/android-chrome-512x512.png +0 -0
  13. package/static/apple-touch-icon.png +0 -0
  14. package/static/assets/index-BgwubB87.css +1 -0
  15. package/static/assets/index-DBHCo8Mz.js +230 -0
  16. package/static/favicon-16x16.png +0 -0
  17. package/static/favicon-32x32.png +0 -0
  18. package/static/favicon.ico +0 -0
  19. package/static/favicon.svg +14 -0
  20. package/static/index.html +18 -248
  21. package/static/site.webmanifest +1 -0
  22. package/static/admin/users.html +0 -593
  23. package/static/cli-code.html +0 -203
  24. package/static/css/.gitkeep +0 -0
  25. package/static/css/style.css +0 -1567
  26. package/static/diff.html +0 -466
  27. package/static/file.html +0 -443
  28. package/static/js/.gitkeep +0 -0
  29. package/static/js/admin/users.js +0 -346
  30. package/static/js/app.js +0 -508
  31. package/static/js/auth.js +0 -151
  32. package/static/js/cli-code.js +0 -184
  33. package/static/js/collaborators.js +0 -283
  34. package/static/js/diff.js +0 -540
  35. package/static/js/file.js +0 -619
  36. package/static/js/i18n.js +0 -739
  37. package/static/js/index.js +0 -168
  38. package/static/js/publish.js +0 -718
  39. package/static/js/settings.js +0 -124
  40. package/static/js/setup.js +0 -157
  41. package/static/js/skill.js +0 -808
  42. package/static/login.html +0 -82
  43. package/static/publish.html +0 -459
  44. package/static/settings.html +0 -163
  45. package/static/setup.html +0 -101
  46. package/static/skill.html +0 -851
package/static/login.html DELETED
@@ -1,82 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title data-i18n="login.title">登录 - Skill Base</title>
7
- <link rel="stylesheet" href="/css/style.css">
8
- </head>
9
- <body class="login-body">
10
- <div class="login-page">
11
- <div class="login-devtools" aria-label="登录">
12
- <header class="devtools-chrome">
13
- <div class="devtools-titlebar">
14
- <div class="devtools-traffic" aria-hidden="true">
15
- <span class="devtools-dot devtools-dot--close"></span>
16
- <span class="devtools-dot devtools-dot--min"></span>
17
- <span class="devtools-dot devtools-dot--max"></span>
18
- </div>
19
- <span class="devtools-titlebar-title">DevTools — Skill Base · Sign in</span>
20
- </div>
21
- </header>
22
-
23
- <div class="login-card">
24
- <div class="login-panel-toolbar">
25
- <span class="login-panel-breadcrumb">Application</span>
26
- <span class="login-panel-sep">›</span>
27
- <span class="login-panel-breadcrumb login-panel-breadcrumb--accent">Session</span>
28
- </div>
29
-
30
- <div class="login-header">
31
- <h1 class="login-title"><span class="login-title-prompt">$</span> Skill Base</h1>
32
- <p class="login-subtitle" data-i18n="login.subtitle">// 内网 Skill 管理平台 · 需要凭证</p>
33
- </div>
34
-
35
- <div id="loginError" class="login-error" role="alert"></div>
36
-
37
- <form id="loginForm">
38
- <div class="form-group">
39
- <label for="username" class="form-label"><span class="login-prop">username</span></label>
40
- <input
41
- type="text"
42
- id="username"
43
- name="username"
44
- placeholder="&quot;operator&quot;"
45
- autocomplete="username"
46
- required
47
- class="login-input"
48
- >
49
- </div>
50
-
51
- <div class="form-group">
52
- <label for="password" class="form-label"><span class="login-prop">password</span></label>
53
- <input
54
- type="password"
55
- id="password"
56
- name="password"
57
- placeholder="••••••••"
58
- autocomplete="current-password"
59
- required
60
- class="login-input"
61
- >
62
- </div>
63
-
64
- <div class="form-group login-actions">
65
- <button type="submit" id="loginButton" class="btn btn-devtools btn-block btn-lg">
66
- <svg class="btn-devtools-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
67
- <polygon points="5 3 19 12 5 21 5 3"/>
68
- </svg>
69
- <span data-i18n="login.submit">执行登录</span>
70
- </button>
71
- </div>
72
- </form>
73
- </div>
74
- </div>
75
- </div>
76
-
77
- <!-- 引入 JS -->
78
- <script src="/js/i18n.js"></script>
79
- <script src="/js/app.js"></script>
80
- <script src="/js/auth.js"></script>
81
- </body>
82
- </html>
@@ -1,459 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title data-i18n="publish.title">发布新版本 - Skill Base</title>
7
- <link rel="stylesheet" href="/css/style.css">
8
- <script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
9
- <style>
10
- /* 面包屑导航 */
11
- .breadcrumb {
12
- display: flex;
13
- align-items: center;
14
- gap: var(--spacing-sm);
15
- margin-bottom: var(--spacing-lg);
16
- font-size: 0.875rem;
17
- color: var(--text-secondary);
18
- }
19
-
20
- .breadcrumb a {
21
- color: var(--text-secondary);
22
- }
23
-
24
- .breadcrumb a:hover {
25
- color: var(--primary-color);
26
- }
27
-
28
- .breadcrumb-separator {
29
- color: var(--text-muted);
30
- }
31
-
32
- .breadcrumb-current {
33
- color: var(--text-color);
34
- font-weight: 500;
35
- }
36
-
37
- /* 发布表单卡片 */
38
- .publish-card {
39
- max-width: 720px;
40
- margin: 0 auto;
41
- }
42
-
43
- .publish-card .card-title {
44
- font-size: 1.25rem;
45
- margin-bottom: var(--spacing-lg);
46
- }
47
-
48
- /* Skill 选择区域 */
49
- .skill-select-group {
50
- display: flex;
51
- gap: var(--spacing-md);
52
- margin-bottom: var(--spacing-md);
53
- }
54
-
55
- .skill-select-group select {
56
- flex: 1;
57
- }
58
-
59
- /* 新建字段组 */
60
- /* 包内元信息只读展示 */
61
- .skill-meta-readonly input[readonly],
62
- .skill-meta-readonly textarea[readonly] {
63
- background-color: var(--bg-color);
64
- color: var(--text-color);
65
- cursor: default;
66
- }
67
-
68
- /* 拖拽上传区域增强 */
69
- .drop-zone {
70
- min-height: 180px;
71
- display: flex;
72
- flex-direction: column;
73
- align-items: center;
74
- justify-content: center;
75
- }
76
-
77
- .drop-zone.drag-over {
78
- border-color: var(--primary-color);
79
- background-color: var(--primary-light);
80
- }
81
-
82
- .drop-zone-subtitle {
83
- font-size: 0.875rem;
84
- color: var(--primary-color);
85
- cursor: pointer;
86
- margin-top: var(--spacing-xs);
87
- }
88
-
89
- .drop-zone-subtitle:hover {
90
- text-decoration: underline;
91
- }
92
-
93
- /* 分隔线 */
94
- .divider {
95
- display: flex;
96
- align-items: center;
97
- margin: var(--spacing-lg) 0;
98
- color: var(--text-muted);
99
- font-size: 0.875rem;
100
- }
101
-
102
- .divider::before,
103
- .divider::after {
104
- content: '';
105
- flex: 1;
106
- height: 1px;
107
- background-color: var(--border-color);
108
- }
109
-
110
- .divider span {
111
- padding: 0 var(--spacing-md);
112
- }
113
-
114
- /* zip 文件选择按钮 */
115
- .zip-select-btn {
116
- display: inline-flex;
117
- align-items: center;
118
- gap: var(--spacing-sm);
119
- }
120
-
121
- .zip-file-input {
122
- display: none;
123
- }
124
-
125
- /* 文件预览区域 */
126
- .file-preview {
127
- margin-top: var(--spacing-md);
128
- padding: var(--spacing-md);
129
- background-color: var(--bg-color);
130
- border-radius: var(--radius);
131
- display: none;
132
- }
133
-
134
- .file-preview.visible {
135
- display: block;
136
- }
137
-
138
- .file-preview-header {
139
- display: flex;
140
- align-items: center;
141
- justify-content: space-between;
142
- margin-bottom: var(--spacing-sm);
143
- font-weight: 500;
144
- color: var(--text-color);
145
- }
146
-
147
- .file-preview-clear {
148
- background: none;
149
- border: none;
150
- color: var(--text-muted);
151
- cursor: pointer;
152
- padding: var(--spacing-xs);
153
- font-size: 0.75rem;
154
- }
155
-
156
- .file-preview-clear:hover {
157
- color: var(--error-color);
158
- }
159
-
160
- .file-preview-list {
161
- font-family: 'SF Mono', Monaco, 'Courier New', monospace;
162
- font-size: 0.75rem;
163
- color: var(--text-secondary);
164
- max-height: 200px;
165
- overflow-y: auto;
166
- line-height: 1.6;
167
- }
168
-
169
- .file-preview-list .file-item {
170
- padding: var(--spacing-xs) 0;
171
- border-bottom: 1px solid var(--border-color);
172
- }
173
-
174
- .file-preview-list .file-item:last-child {
175
- border-bottom: none;
176
- }
177
-
178
- .file-preview-more {
179
- color: var(--text-muted);
180
- font-style: italic;
181
- padding-top: var(--spacing-sm);
182
- }
183
-
184
- .file-preview-summary {
185
- margin-top: var(--spacing-sm);
186
- padding-top: var(--spacing-sm);
187
- border-top: 1px solid var(--border-color);
188
- font-size: 0.75rem;
189
- color: var(--text-muted);
190
- }
191
-
192
- /* 按钮栏 */
193
- .form-actions {
194
- display: flex;
195
- gap: var(--spacing-md);
196
- justify-content: flex-end;
197
- margin-top: var(--spacing-xl);
198
- padding-top: var(--spacing-lg);
199
- border-top: 1px solid var(--border-color);
200
- }
201
-
202
- /* 进度条 */
203
- .progress-container {
204
- margin-top: var(--spacing-lg);
205
- display: none;
206
- }
207
-
208
- .progress-container.visible {
209
- display: block;
210
- }
211
-
212
- .progress-bar-wrapper {
213
- height: 8px;
214
- background-color: var(--bg-color);
215
- border-radius: var(--radius-full);
216
- overflow: hidden;
217
- }
218
-
219
- .progress-bar {
220
- height: 100%;
221
- background-color: var(--primary-color);
222
- border-radius: var(--radius-full);
223
- width: 0%;
224
- transition: width 0.3s ease;
225
- }
226
-
227
- .progress-text {
228
- margin-top: var(--spacing-sm);
229
- font-size: 0.875rem;
230
- color: var(--text-secondary);
231
- text-align: center;
232
- }
233
-
234
- /* 成功提示 */
235
- .success-container {
236
- margin-top: var(--spacing-lg);
237
- padding: var(--spacing-lg);
238
- background-color: var(--success-light);
239
- border-radius: var(--radius);
240
- text-align: center;
241
- display: none;
242
- }
243
-
244
- .success-container.visible {
245
- display: block;
246
- }
247
-
248
- .success-icon {
249
- font-size: 3rem;
250
- margin-bottom: var(--spacing-md);
251
- }
252
-
253
- .success-title {
254
- font-size: 1.125rem;
255
- font-weight: 600;
256
- color: var(--success-color);
257
- margin-bottom: var(--spacing-sm);
258
- }
259
-
260
- .success-message {
261
- color: var(--text-secondary);
262
- margin-bottom: var(--spacing-md);
263
- }
264
-
265
- .success-actions {
266
- display: flex;
267
- gap: var(--spacing-md);
268
- justify-content: center;
269
- }
270
-
271
- @media (max-width: 768px) {
272
- .skill-select-group {
273
- flex-direction: column;
274
- }
275
-
276
- .form-actions {
277
- flex-direction: column-reverse;
278
- }
279
-
280
- .form-actions .btn {
281
- width: 100%;
282
- }
283
-
284
- .success-actions {
285
- flex-direction: column;
286
- }
287
-
288
- .success-actions .btn {
289
- width: 100%;
290
- }
291
- }
292
- </style>
293
- </head>
294
- <body class="app-devtools">
295
- <!-- 导航栏 -->
296
- <nav class="navbar">
297
- <div class="container">
298
- <a href="/" class="navbar-brand">
299
- <svg class="navbar-brand-icon" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
300
- <span>Skill Base</span>
301
- </a>
302
- <div class="navbar-nav">
303
- <a href="/" data-i18n="nav.home">首页</a>
304
- <a href="/publish.html" class="active hide-mobile" data-i18n="nav.publish">发布</a>
305
- </div>
306
- <!-- 用户区域由 JS 动态渲染 -->
307
- </div>
308
- </nav>
309
-
310
- <!-- 页面内容 -->
311
- <main class="page-content">
312
- <div class="container">
313
- <!-- 面包屑导航 -->
314
- <nav class="breadcrumb">
315
- <a href="/" data-i18n="skill.breadcrumbHome">首页</a>
316
- <span class="breadcrumb-separator">/</span>
317
- <span class="breadcrumb-current" data-i18n="publish.breadcrumbCurrent">发布新版本</span>
318
- </nav>
319
-
320
- <!-- 发布表单卡片 -->
321
- <div class="card publish-card">
322
- <h1 class="card-title" data-i18n="publish.heading">发布新版本</h1>
323
-
324
- <form id="publishForm">
325
- <!-- 上传优先:进入页面即可拖文件夹 / zip,并自动填 SKILL.md 信息 -->
326
- <div class="form-group">
327
- <label class="form-label required" data-i18n="publish.uploadLabel">上传文件</label>
328
- <div id="drop-zone" class="drop-zone">
329
- <div class="drop-zone-icon">📁</div>
330
- <div class="drop-zone-text" data-i18n="publish.dropText">拖拽 Skill 文件夹或 zip 到此处</div>
331
- <div class="drop-zone-subtitle" data-i18n="publish.dropSubtitle">或点击选择文件夹</div>
332
- <div class="drop-zone-hint" data-i18n="publish.dropHint">Skill ID、名称、描述均从包内读取(文件夹名 / zip 文件名 + SKILL.md),不可手改</div>
333
- </div>
334
-
335
- <div class="divider">
336
- <span data-i18n="publish.or">或</span>
337
- </div>
338
-
339
- <div>
340
- <label class="btn btn-secondary zip-select-btn">
341
- <span>📎</span>
342
- <span data-i18n="publish.selectZip">选择 zip 文件...</span>
343
- <input type="file" id="zip-file-input" class="zip-file-input" accept=".zip">
344
- </label>
345
- </div>
346
-
347
- <div id="file-preview" class="file-preview">
348
- <div class="file-preview-header">
349
- <span data-i18n="publish.selectedFiles">已选择文件</span>
350
- <button type="button" class="file-preview-clear" id="clear-files" data-i18n="publish.clearFiles">清除</button>
351
- </div>
352
- <div id="file-preview-list" class="file-preview-list">
353
- <!-- 由 JS 动态填充 -->
354
- </div>
355
- <div id="file-preview-summary" class="file-preview-summary"></div>
356
- </div>
357
- </div>
358
-
359
- <!-- Skill 选择 -->
360
- <div class="form-group">
361
- <label for="skill-select" class="form-label" data-i18n="publish.selectSkill">选择 Skill</label>
362
- <div class="skill-select-group">
363
- <select id="skill-select">
364
- <option value="" data-i18n="publish.createNew">-- 创建新 Skill --</option>
365
- <!-- 由 JS 动态填充已有 Skill -->
366
- </select>
367
- </div>
368
- <p class="form-hint" data-i18n="publish.skillSelectHint">更新已有 Skill 时请选择与包内 Skill ID 一致的一项;新建则保持「创建新 Skill」</p>
369
- </div>
370
-
371
- <div class="skill-meta-readonly">
372
- <!-- Skill ID:来自文件夹名 / zip 文件名 -->
373
- <div class="form-group">
374
- <label for="skill-id" class="form-label required" data-i18n="publish.idLabel">Skill ID</label>
375
- <input
376
- type="text"
377
- id="skill-id"
378
- readonly
379
- data-i18n-placeholder="publish.idPlaceholder"
380
- placeholder="上传文件夹或 zip 后自动填入"
381
- pattern="[a-z0-9\-_]+"
382
- >
383
- <p class="form-hint" data-i18n="publish.idHint">由文件夹名或 zip 文件名推导(小写字母、数字、连字符、下划线)</p>
384
- </div>
385
-
386
- <div class="form-group">
387
- <label for="skill-name" class="form-label required" data-i18n="publish.nameLabel">Skill 名称</label>
388
- <input
389
- type="text"
390
- id="skill-name"
391
- readonly
392
- data-i18n-placeholder="publish.namePlaceholder"
393
- placeholder="上传后从 SKILL.md 读取"
394
- >
395
- <p class="form-hint" data-i18n="publish.nameHint">来自 SKILL.md(frontmatter 或首行标题)</p>
396
- </div>
397
-
398
- <div class="form-group">
399
- <label for="skill-description" class="form-label required" data-i18n="publish.descLabel">描述</label>
400
- <textarea
401
- id="skill-description"
402
- rows="3"
403
- readonly
404
- maxlength="500"
405
- data-i18n-placeholder="publish.descPlaceholder"
406
- placeholder="上传后从 SKILL.md 读取"
407
- ></textarea>
408
- <p class="form-hint"><span id="skill-description-count">0</span> / 500 字(与包内一致,截断至 500 字)</p>
409
- </div>
410
- </div>
411
-
412
- <!-- 更新说明 -->
413
- <div class="form-group">
414
- <label for="changelog" class="form-label" data-i18n="publish.changelogLabel">更新说明</label>
415
- <textarea
416
- id="changelog"
417
- rows="4"
418
- data-i18n-placeholder="publish.changelogPlaceholder"
419
- placeholder="描述本次更新的内容...&#10;&#10;例如:&#10;- 新增 xxx 功能&#10;- 修复 xxx 问题"
420
- ></textarea>
421
- </div>
422
-
423
- <!-- 按钮栏 -->
424
- <div class="form-actions">
425
- <a href="/" class="btn btn-secondary" data-i18n="publish.cancelBtn">取消</a>
426
- <button type="submit" id="submit-btn" class="btn btn-primary" data-i18n="publish.submitBtn">
427
- 发布新版本
428
- </button>
429
- </div>
430
-
431
- <!-- 进度条 -->
432
- <div id="progress-container" class="progress-container">
433
- <div class="progress-bar-wrapper">
434
- <div id="progress-bar" class="progress-bar"></div>
435
- </div>
436
- <div id="progress-text" class="progress-text">正在上传...</div>
437
- </div>
438
- </form>
439
-
440
- <!-- 成功提示 -->
441
- <div id="success-container" class="success-container">
442
- <div class="success-icon">✅</div>
443
- <div class="success-title" data-i18n="publish.successTitle">发布成功!</div>
444
- <div id="success-message" class="success-message"></div>
445
- <div class="success-actions">
446
- <a id="view-skill-link" href="#" class="btn btn-primary" data-i18n="publish.viewDetail">查看详情</a>
447
- <a href="/publish.html" class="btn btn-secondary" data-i18n="publish.publishAnother">继续发布</a>
448
- </div>
449
- </div>
450
- </div>
451
- </div>
452
- </main>
453
-
454
- <!-- 引入 JS -->
455
- <script src="/js/i18n.js"></script>
456
- <script src="/js/app.js"></script>
457
- <script src="/js/publish.js"></script>
458
- </body>
459
- </html>