hypercore-cli 1.1.0
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.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/api-XGC7D5AW.js +162 -0
- package/dist/auth-DNQWYQKT.js +21 -0
- package/dist/background-2EGCAAQH.js +14 -0
- package/dist/backlog-Q2NZCLNY.js +24 -0
- package/dist/chunk-2CMSCWQW.js +162 -0
- package/dist/chunk-2LJ2DVEB.js +167 -0
- package/dist/chunk-3RPFCQKJ.js +288 -0
- package/dist/chunk-43OLRXM5.js +263 -0
- package/dist/chunk-4DVYJAJL.js +57 -0
- package/dist/chunk-6OL3GA3P.js +173 -0
- package/dist/chunk-AUHU7ALH.js +2023 -0
- package/dist/chunk-B6A2AKLN.js +139 -0
- package/dist/chunk-BE46C7JW.js +46 -0
- package/dist/chunk-CUVAUOXL.js +58 -0
- package/dist/chunk-GH7E2OJE.js +223 -0
- package/dist/chunk-GOOTEPBK.js +271 -0
- package/dist/chunk-GPPMJYSM.js +133 -0
- package/dist/chunk-GU2FZQ6A.js +69 -0
- package/dist/chunk-IOPKN5GD.js +190 -0
- package/dist/chunk-IXOIOGR5.js +1505 -0
- package/dist/chunk-KRPOPWGA.js +251 -0
- package/dist/chunk-MGLJ53QN.js +219 -0
- package/dist/chunk-MV4TTRYX.js +533 -0
- package/dist/chunk-OPZYEVYR.js +150 -0
- package/dist/chunk-QTSLP47C.js +166 -0
- package/dist/chunk-R3GPQC7I.js +393 -0
- package/dist/chunk-RKB2JOV2.js +43 -0
- package/dist/chunk-RNG3K465.js +80 -0
- package/dist/chunk-TGTYKBGC.js +86 -0
- package/dist/chunk-U5SGAIMM.js +681 -0
- package/dist/chunk-V5UHPPSY.js +140 -0
- package/dist/chunk-WHLVZCQY.js +245 -0
- package/dist/chunk-XDRCBMZZ.js +66 -0
- package/dist/chunk-XOS6HPEF.js +134 -0
- package/dist/chunk-ZSBHUGWR.js +262 -0
- package/dist/claude-NSQ442XD.js +12 -0
- package/dist/commands-CK3WFAGI.js +128 -0
- package/dist/commands-U63OEO5J.js +1044 -0
- package/dist/commands-ZE6GD3WC.js +232 -0
- package/dist/config-4EW42BSF.js +8 -0
- package/dist/config-loader-SXO674TF.js +24 -0
- package/dist/diagnose-AFW3ZTZ4.js +12 -0
- package/dist/display-IIUBEYWN.js +58 -0
- package/dist/extractor-QV53W2YJ.js +129 -0
- package/dist/history-WMSCHERZ.js +180 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +406 -0
- package/dist/instance-registry-YSIJXSO7.js +15 -0
- package/dist/keybindings-JAAMLH3G.js +15 -0
- package/dist/loader-WHNTZTLP.js +58 -0
- package/dist/network-MM6YWPGO.js +279 -0
- package/dist/notify-HPTALZDC.js +14 -0
- package/dist/openai-compat-UQWJXBEK.js +12 -0
- package/dist/permissions-JUKXMNDH.js +10 -0
- package/dist/prompt-QV45TXRL.js +166 -0
- package/dist/quality-ST7PPNFR.js +16 -0
- package/dist/repl-RT3AHL7M.js +3375 -0
- package/dist/roadmap-5OBEKROY.js +17 -0
- package/dist/server-PORT7OEG.js +57 -0
- package/dist/session-4VUNDWLH.js +21 -0
- package/dist/skills-V4A35XKG.js +175 -0
- package/dist/store-Y4LU5QTO.js +25 -0
- package/dist/team-HO7Z4SIM.js +385 -0
- package/dist/telemetry-6R4EIE6O.js +30 -0
- package/dist/test-runner-ZQH5Y6OJ.js +619 -0
- package/dist/theme-3SYJ3UQA.js +14 -0
- package/dist/upgrade-7TGI3SXO.js +83 -0
- package/dist/verify-JUDKTPKZ.js +14 -0
- package/dist/web/static/app.js +562 -0
- package/dist/web/static/index.html +132 -0
- package/dist/web/static/mirror.css +1001 -0
- package/dist/web/static/mirror.html +184 -0
- package/dist/web/static/mirror.js +1125 -0
- package/dist/web/static/onboard.css +302 -0
- package/dist/web/static/onboard.html +140 -0
- package/dist/web/static/onboard.js +260 -0
- package/dist/web/static/style.css +602 -0
- package/dist/web/static/workspace.css +1568 -0
- package/dist/web/static/workspace.html +408 -0
- package/dist/web/static/workspace.js +1683 -0
- package/dist/web-Z5HSCQHW.js +39 -0
- package/package.json +67 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/* Onboarding — 暗色主题,复用 workspace CSS 变量 */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--ob-bg: #0d1117;
|
|
5
|
+
--ob-surface: #161b22;
|
|
6
|
+
--ob-surface-hover: #1c2129;
|
|
7
|
+
--ob-border: #30363d;
|
|
8
|
+
--ob-text: #e6edf3;
|
|
9
|
+
--ob-text-dim: #8b949e;
|
|
10
|
+
--ob-accent: #58a6ff;
|
|
11
|
+
--ob-accent-dim: rgba(88, 166, 255, 0.15);
|
|
12
|
+
--ob-success: #3fb950;
|
|
13
|
+
--ob-error: #f85149;
|
|
14
|
+
--ob-radius: 8px;
|
|
15
|
+
--ob-radius-lg: 12px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
background: var(--ob-bg);
|
|
22
|
+
color: var(--ob-text);
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
24
|
+
min-height: 100vh;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Container */
|
|
31
|
+
.ob-container {
|
|
32
|
+
width: 100%;
|
|
33
|
+
max-width: 640px;
|
|
34
|
+
padding: 40px 24px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Logo */
|
|
38
|
+
.ob-logo {
|
|
39
|
+
text-align: center;
|
|
40
|
+
font-size: 24px;
|
|
41
|
+
font-weight: 700;
|
|
42
|
+
margin-bottom: 32px;
|
|
43
|
+
letter-spacing: -0.5px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Progress */
|
|
47
|
+
.ob-progress {
|
|
48
|
+
height: 3px;
|
|
49
|
+
background: var(--ob-border);
|
|
50
|
+
border-radius: 2px;
|
|
51
|
+
margin-bottom: 8px;
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ob-progress-bar {
|
|
56
|
+
height: 100%;
|
|
57
|
+
background: var(--ob-accent);
|
|
58
|
+
border-radius: 2px;
|
|
59
|
+
transition: width 0.4s ease;
|
|
60
|
+
width: 14.28%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ob-step-label {
|
|
64
|
+
text-align: center;
|
|
65
|
+
font-size: 12px;
|
|
66
|
+
color: var(--ob-text-dim);
|
|
67
|
+
margin-bottom: 24px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Card */
|
|
71
|
+
.ob-card {
|
|
72
|
+
background: var(--ob-surface);
|
|
73
|
+
border: 1px solid var(--ob-border);
|
|
74
|
+
border-radius: var(--ob-radius-lg);
|
|
75
|
+
padding: 32px 28px;
|
|
76
|
+
min-height: 380px;
|
|
77
|
+
position: relative;
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Steps */
|
|
82
|
+
.ob-step {
|
|
83
|
+
display: none;
|
|
84
|
+
animation: fadeIn 0.3s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.ob-step.active {
|
|
88
|
+
display: block;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes fadeIn {
|
|
92
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
93
|
+
to { opacity: 1; transform: translateY(0); }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ob-step h2 {
|
|
97
|
+
font-size: 20px;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
margin-bottom: 8px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ob-desc {
|
|
103
|
+
color: var(--ob-text-dim);
|
|
104
|
+
font-size: 14px;
|
|
105
|
+
margin-bottom: 24px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Options Grid */
|
|
109
|
+
.ob-options {
|
|
110
|
+
display: grid;
|
|
111
|
+
grid-template-columns: repeat(2, 1fr);
|
|
112
|
+
gap: 10px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ob-option {
|
|
116
|
+
background: var(--ob-bg);
|
|
117
|
+
border: 1px solid var(--ob-border);
|
|
118
|
+
border-radius: var(--ob-radius);
|
|
119
|
+
padding: 12px 16px;
|
|
120
|
+
color: var(--ob-text);
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
text-align: left;
|
|
124
|
+
transition: all 0.2s;
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
gap: 8px;
|
|
128
|
+
position: relative;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.ob-option:hover {
|
|
132
|
+
background: var(--ob-surface-hover);
|
|
133
|
+
border-color: var(--ob-accent);
|
|
134
|
+
transform: scale(1.01);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.ob-option.selected {
|
|
138
|
+
background: var(--ob-accent-dim);
|
|
139
|
+
border-color: var(--ob-accent);
|
|
140
|
+
color: var(--ob-accent);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.ob-tag {
|
|
144
|
+
display: inline-block;
|
|
145
|
+
font-size: 10px;
|
|
146
|
+
color: var(--ob-success);
|
|
147
|
+
background: rgba(63, 185, 80, 0.1);
|
|
148
|
+
padding: 2px 6px;
|
|
149
|
+
border-radius: 4px;
|
|
150
|
+
margin-left: auto;
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Input Groups */
|
|
155
|
+
.ob-input-group {
|
|
156
|
+
margin-top: 16px;
|
|
157
|
+
position: relative;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.ob-input-group label {
|
|
161
|
+
display: block;
|
|
162
|
+
font-size: 13px;
|
|
163
|
+
color: var(--ob-text-dim);
|
|
164
|
+
margin-bottom: 6px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ob-optional {
|
|
168
|
+
font-size: 11px;
|
|
169
|
+
color: var(--ob-text-dim);
|
|
170
|
+
opacity: 0.6;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.ob-input {
|
|
174
|
+
width: 100%;
|
|
175
|
+
background: var(--ob-bg);
|
|
176
|
+
border: 1px solid var(--ob-border);
|
|
177
|
+
border-radius: var(--ob-radius);
|
|
178
|
+
padding: 10px 14px;
|
|
179
|
+
color: var(--ob-text);
|
|
180
|
+
font-size: 14px;
|
|
181
|
+
outline: none;
|
|
182
|
+
transition: border-color 0.2s;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.ob-input:focus {
|
|
186
|
+
border-color: var(--ob-accent);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.ob-toggle-pw {
|
|
190
|
+
position: absolute;
|
|
191
|
+
right: 10px;
|
|
192
|
+
top: 30px;
|
|
193
|
+
background: none;
|
|
194
|
+
border: none;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
font-size: 14px;
|
|
197
|
+
opacity: 0.5;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.ob-toggle-pw:hover { opacity: 1; }
|
|
201
|
+
|
|
202
|
+
/* Textarea */
|
|
203
|
+
.ob-textarea {
|
|
204
|
+
width: 100%;
|
|
205
|
+
background: var(--ob-bg);
|
|
206
|
+
border: 1px solid var(--ob-border);
|
|
207
|
+
border-radius: var(--ob-radius);
|
|
208
|
+
padding: 12px 14px;
|
|
209
|
+
color: var(--ob-text);
|
|
210
|
+
font-size: 14px;
|
|
211
|
+
outline: none;
|
|
212
|
+
resize: vertical;
|
|
213
|
+
min-height: 120px;
|
|
214
|
+
font-family: inherit;
|
|
215
|
+
transition: border-color 0.2s;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.ob-textarea:focus {
|
|
219
|
+
border-color: var(--ob-accent);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Navigation */
|
|
223
|
+
.ob-nav {
|
|
224
|
+
display: flex;
|
|
225
|
+
justify-content: space-between;
|
|
226
|
+
margin-top: 20px;
|
|
227
|
+
gap: 12px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.ob-btn {
|
|
231
|
+
padding: 10px 24px;
|
|
232
|
+
border-radius: var(--ob-radius);
|
|
233
|
+
font-size: 14px;
|
|
234
|
+
font-weight: 500;
|
|
235
|
+
cursor: pointer;
|
|
236
|
+
border: none;
|
|
237
|
+
transition: all 0.2s;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.ob-btn-back {
|
|
241
|
+
background: transparent;
|
|
242
|
+
color: var(--ob-text-dim);
|
|
243
|
+
border: 1px solid var(--ob-border);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.ob-btn-back:hover {
|
|
247
|
+
color: var(--ob-text);
|
|
248
|
+
border-color: var(--ob-text-dim);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.ob-btn-next {
|
|
252
|
+
background: var(--ob-accent);
|
|
253
|
+
color: #fff;
|
|
254
|
+
margin-left: auto;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.ob-btn-next:hover {
|
|
258
|
+
filter: brightness(1.1);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.ob-btn-next:disabled {
|
|
262
|
+
opacity: 0.4;
|
|
263
|
+
cursor: not-allowed;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.ob-btn-next.loading {
|
|
267
|
+
pointer-events: none;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* Error */
|
|
271
|
+
.ob-error {
|
|
272
|
+
text-align: center;
|
|
273
|
+
color: var(--ob-error);
|
|
274
|
+
font-size: 13px;
|
|
275
|
+
margin-top: 12px;
|
|
276
|
+
min-height: 20px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Responsive */
|
|
280
|
+
@media (max-width: 520px) {
|
|
281
|
+
.ob-container { padding: 20px 16px; }
|
|
282
|
+
.ob-card { padding: 24px 20px; }
|
|
283
|
+
.ob-options { grid-template-columns: 1fr; }
|
|
284
|
+
.ob-step h2 { font-size: 18px; }
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Loading spinner for submit */
|
|
288
|
+
.ob-spinner {
|
|
289
|
+
display: inline-block;
|
|
290
|
+
width: 16px;
|
|
291
|
+
height: 16px;
|
|
292
|
+
border: 2px solid rgba(255,255,255,0.3);
|
|
293
|
+
border-top-color: #fff;
|
|
294
|
+
border-radius: 50%;
|
|
295
|
+
animation: obSpin 0.6s linear infinite;
|
|
296
|
+
vertical-align: middle;
|
|
297
|
+
margin-right: 6px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@keyframes obSpin {
|
|
301
|
+
to { transform: rotate(360deg); }
|
|
302
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
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>Hypercore — 开始使用</title>
|
|
7
|
+
<link rel="stylesheet" href="onboard.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="ob-container">
|
|
11
|
+
<!-- Logo -->
|
|
12
|
+
<div class="ob-logo">⚡ Hypercore</div>
|
|
13
|
+
|
|
14
|
+
<!-- Progress Bar -->
|
|
15
|
+
<div class="ob-progress">
|
|
16
|
+
<div class="ob-progress-bar" id="progressBar"></div>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="ob-step-label" id="stepLabel">第 1 步,共 7 步</div>
|
|
19
|
+
|
|
20
|
+
<!-- Wizard Card -->
|
|
21
|
+
<div class="ob-card" id="wizardCard">
|
|
22
|
+
|
|
23
|
+
<!-- Step 1: Industry -->
|
|
24
|
+
<div class="ob-step active" data-step="1">
|
|
25
|
+
<h2>你所在的行业?</h2>
|
|
26
|
+
<p class="ob-desc">我们会根据行业推荐最合适的工具和模板</p>
|
|
27
|
+
<div class="ob-options" data-field="industry">
|
|
28
|
+
<button class="ob-option" data-value="marketing">📢 营销/广告</button>
|
|
29
|
+
<button class="ob-option" data-value="ecommerce">🛒 电商/零售</button>
|
|
30
|
+
<button class="ob-option" data-value="education">📚 教育/培训</button>
|
|
31
|
+
<button class="ob-option" data-value="tech">💻 科技/互联网</button>
|
|
32
|
+
<button class="ob-option" data-value="finance">💰 金融/财务</button>
|
|
33
|
+
<button class="ob-option" data-value="media">🎬 媒体/内容</button>
|
|
34
|
+
<button class="ob-option" data-value="consulting">🏢 咨询/服务</button>
|
|
35
|
+
<button class="ob-option" data-value="other">🎯 其他</button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- Step 2: Role -->
|
|
40
|
+
<div class="ob-step" data-step="2">
|
|
41
|
+
<h2>你的角色是?</h2>
|
|
42
|
+
<p class="ob-desc">不同角色有不同的工作重心</p>
|
|
43
|
+
<div class="ob-options" data-field="role">
|
|
44
|
+
<button class="ob-option" data-value="founder">🚀 创始人/CEO</button>
|
|
45
|
+
<button class="ob-option" data-value="marketer">📣 市场/营销</button>
|
|
46
|
+
<button class="ob-option" data-value="content-creator">✍️ 内容创作者</button>
|
|
47
|
+
<button class="ob-option" data-value="product-manager">📋 产品经理</button>
|
|
48
|
+
<button class="ob-option" data-value="researcher">🔬 研究/分析</button>
|
|
49
|
+
<button class="ob-option" data-value="operations">⚙️ 运营/管理</button>
|
|
50
|
+
<button class="ob-option" data-value="freelancer">🎯 自由职业者</button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<!-- Step 3: Automation Needs (Multi-select) -->
|
|
55
|
+
<div class="ob-step" data-step="3">
|
|
56
|
+
<h2>最想自动化哪些工作?</h2>
|
|
57
|
+
<p class="ob-desc">可多选,我们会为你预装对应的生产线</p>
|
|
58
|
+
<div class="ob-options ob-multi" data-field="automationNeeds">
|
|
59
|
+
<button class="ob-option" data-value="content-writing">✍️ 内容写作</button>
|
|
60
|
+
<button class="ob-option" data-value="research">🔍 调研分析</button>
|
|
61
|
+
<button class="ob-option" data-value="reports">📊 报告/周报</button>
|
|
62
|
+
<button class="ob-option" data-value="social-media">📱 社交媒体</button>
|
|
63
|
+
<button class="ob-option" data-value="competitor-analysis">🏷️ 竞品分析</button>
|
|
64
|
+
<button class="ob-option" data-value="meeting-notes">📝 会议纪要</button>
|
|
65
|
+
<button class="ob-option" data-value="data-analysis">📈 数据分析</button>
|
|
66
|
+
<button class="ob-option" data-value="customer-outreach">🤝 客户触达</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- Step 4: Team Size -->
|
|
71
|
+
<div class="ob-step" data-step="4">
|
|
72
|
+
<h2>团队规模?</h2>
|
|
73
|
+
<p class="ob-desc">这决定了是否开启协作功能</p>
|
|
74
|
+
<div class="ob-options" data-field="teamSize">
|
|
75
|
+
<button class="ob-option" data-value="solo">🧑 独立工作</button>
|
|
76
|
+
<button class="ob-option" data-value="2-5">👥 2-5 人</button>
|
|
77
|
+
<button class="ob-option" data-value="6-20">🏢 6-20 人</button>
|
|
78
|
+
<button class="ob-option" data-value="20+">🏛️ 20+ 人</button>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<!-- Step 5: Platforms (Multi-select) -->
|
|
83
|
+
<div class="ob-step" data-step="5">
|
|
84
|
+
<h2>主要发布平台?</h2>
|
|
85
|
+
<p class="ob-desc">可多选,帮你适配内容格式</p>
|
|
86
|
+
<div class="ob-options ob-multi" data-field="platforms">
|
|
87
|
+
<button class="ob-option" data-value="wechat">💬 微信公众号</button>
|
|
88
|
+
<button class="ob-option" data-value="xiaohongshu">📕 小红书</button>
|
|
89
|
+
<button class="ob-option" data-value="douyin">🎵 抖音</button>
|
|
90
|
+
<button class="ob-option" data-value="website">🌐 网站/博客</button>
|
|
91
|
+
<button class="ob-option" data-value="email">📧 邮件</button>
|
|
92
|
+
<button class="ob-option" data-value="linkedin">💼 LinkedIn</button>
|
|
93
|
+
<button class="ob-option" data-value="twitter">🐦 Twitter/X</button>
|
|
94
|
+
<button class="ob-option" data-value="none">➖ 暂无</button>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<!-- Step 6: AI Provider + Key -->
|
|
99
|
+
<div class="ob-step" data-step="6">
|
|
100
|
+
<h2>选择 AI 模型</h2>
|
|
101
|
+
<p class="ob-desc">API Key 仅存储在本地,不会上传</p>
|
|
102
|
+
<div class="ob-options" data-field="provider">
|
|
103
|
+
<button class="ob-option" data-value="gemini">✨ Google Gemini 2.5 Flash<span class="ob-tag">推荐·免费额度</span></button>
|
|
104
|
+
<button class="ob-option" data-value="minimax">🤖 MiniMax M2.5<span class="ob-tag">性价比高</span></button>
|
|
105
|
+
<button class="ob-option" data-value="deepseek">🧊 DeepSeek<span class="ob-tag">国产首选</span></button>
|
|
106
|
+
<button class="ob-option" data-value="anthropic">🧠 Anthropic Claude<span class="ob-tag">最强推理</span></button>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="ob-input-group">
|
|
109
|
+
<label for="apiKeyInput">API Key</label>
|
|
110
|
+
<input type="password" id="apiKeyInput" class="ob-input" placeholder="粘贴你的 API Key…">
|
|
111
|
+
<button class="ob-toggle-pw" id="togglePw" title="显示/隐藏" aria-label="切换密码可见性" type="button">👁️</button>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="ob-input-group">
|
|
114
|
+
<label for="tavilyKeyInput">Tavily API Key <span class="ob-optional">可选</span></label>
|
|
115
|
+
<input type="password" id="tavilyKeyInput" class="ob-input" placeholder="用于网络搜索(可跳过)">
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- Step 7: Free Description (Optional) -->
|
|
120
|
+
<div class="ob-step" data-step="7">
|
|
121
|
+
<h2>还有什么要补充的吗?</h2>
|
|
122
|
+
<p class="ob-desc">描述你的具体工作场景,帮助我们更好地定制(可跳过)</p>
|
|
123
|
+
<textarea id="freeDescription" class="ob-textarea" rows="5"
|
|
124
|
+
placeholder="例如:我是一个跨境电商卖家,主要在亚马逊和独立站销售家居产品,需要定期做竞品调研和写产品描述…"></textarea>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<!-- Navigation -->
|
|
129
|
+
<div class="ob-nav">
|
|
130
|
+
<button class="ob-btn ob-btn-back" id="btnBack" style="visibility:hidden">← 上一步</button>
|
|
131
|
+
<button class="ob-btn ob-btn-next" id="btnNext">下一步 →</button>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<!-- Error message -->
|
|
135
|
+
<div class="ob-error" id="errorMsg" role="alert" aria-live="polite"></div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<script src="onboard.js"></script>
|
|
139
|
+
</body>
|
|
140
|
+
</html>
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding Wizard — 6步卡片向导 + 可选自由描述
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
class OnboardingWizard {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.totalSteps = 7;
|
|
8
|
+
this.currentStep = 1;
|
|
9
|
+
this.isSubmitting = false;
|
|
10
|
+
this._navDebounce = false;
|
|
11
|
+
this.answers = {
|
|
12
|
+
industry: '',
|
|
13
|
+
role: '',
|
|
14
|
+
automationNeeds: [],
|
|
15
|
+
teamSize: '',
|
|
16
|
+
platforms: [],
|
|
17
|
+
provider: '',
|
|
18
|
+
apiKey: '',
|
|
19
|
+
tavilyKey: '',
|
|
20
|
+
freeDescription: '',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.els = {
|
|
24
|
+
progressBar: document.getElementById('progressBar'),
|
|
25
|
+
stepLabel: document.getElementById('stepLabel'),
|
|
26
|
+
btnBack: document.getElementById('btnBack'),
|
|
27
|
+
btnNext: document.getElementById('btnNext'),
|
|
28
|
+
errorMsg: document.getElementById('errorMsg'),
|
|
29
|
+
apiKeyInput: document.getElementById('apiKeyInput'),
|
|
30
|
+
tavilyKeyInput: document.getElementById('tavilyKeyInput'),
|
|
31
|
+
freeDescription: document.getElementById('freeDescription'),
|
|
32
|
+
togglePw: document.getElementById('togglePw'),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
this.init();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
init() {
|
|
39
|
+
// Option click handlers
|
|
40
|
+
document.querySelectorAll('.ob-options').forEach(group => {
|
|
41
|
+
const isMulti = group.classList.contains('ob-multi');
|
|
42
|
+
group.querySelectorAll('.ob-option').forEach(btn => {
|
|
43
|
+
btn.addEventListener('click', () => {
|
|
44
|
+
if (isMulti) {
|
|
45
|
+
btn.classList.toggle('selected');
|
|
46
|
+
} else {
|
|
47
|
+
group.querySelectorAll('.ob-option').forEach(b => b.classList.remove('selected'));
|
|
48
|
+
btn.classList.add('selected');
|
|
49
|
+
}
|
|
50
|
+
this.clearError();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Navigation
|
|
56
|
+
this.els.btnBack.addEventListener('click', () => this.prev());
|
|
57
|
+
this.els.btnNext.addEventListener('click', () => this.next());
|
|
58
|
+
|
|
59
|
+
// Password toggle
|
|
60
|
+
this.els.togglePw.addEventListener('click', () => {
|
|
61
|
+
const input = this.els.apiKeyInput;
|
|
62
|
+
input.type = input.type === 'password' ? 'text' : 'password';
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Keyboard shortcut
|
|
66
|
+
document.addEventListener('keydown', (e) => {
|
|
67
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
this.next();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this.render();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
render() {
|
|
77
|
+
// Progress
|
|
78
|
+
const pct = (this.currentStep / this.totalSteps) * 100;
|
|
79
|
+
this.els.progressBar.style.width = `${pct}%`;
|
|
80
|
+
this.els.stepLabel.textContent = `第 ${this.currentStep} 步,共 ${this.totalSteps} 步`;
|
|
81
|
+
|
|
82
|
+
// Show/hide steps
|
|
83
|
+
document.querySelectorAll('.ob-step').forEach(step => {
|
|
84
|
+
const stepNum = parseInt(step.dataset.step, 10);
|
|
85
|
+
step.classList.toggle('active', stepNum === this.currentStep);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Back button visibility
|
|
89
|
+
this.els.btnBack.style.visibility = this.currentStep > 1 ? 'visible' : 'hidden';
|
|
90
|
+
|
|
91
|
+
// Next button text
|
|
92
|
+
if (this.currentStep === this.totalSteps) {
|
|
93
|
+
this.els.btnNext.textContent = '🚀 生成工作台';
|
|
94
|
+
} else if (this.currentStep === this.totalSteps - 1) {
|
|
95
|
+
// Step 6 (API key) — normal "next"
|
|
96
|
+
this.els.btnNext.textContent = '下一步 →';
|
|
97
|
+
} else {
|
|
98
|
+
this.els.btnNext.textContent = '下一步 →';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.clearError();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getStepField(step) {
|
|
105
|
+
const fields = {
|
|
106
|
+
1: 'industry',
|
|
107
|
+
2: 'role',
|
|
108
|
+
3: 'automationNeeds',
|
|
109
|
+
4: 'teamSize',
|
|
110
|
+
5: 'platforms',
|
|
111
|
+
6: 'provider',
|
|
112
|
+
};
|
|
113
|
+
return fields[step] || null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
collectStepValue(step) {
|
|
117
|
+
const field = this.getStepField(step);
|
|
118
|
+
if (!field) return true; // step 7 (free text) always valid
|
|
119
|
+
|
|
120
|
+
const group = document.querySelector(`.ob-step[data-step="${step}"] .ob-options[data-field="${field}"]`);
|
|
121
|
+
if (!group) return true;
|
|
122
|
+
|
|
123
|
+
const isMulti = group.classList.contains('ob-multi');
|
|
124
|
+
const selected = group.querySelectorAll('.ob-option.selected');
|
|
125
|
+
|
|
126
|
+
if (isMulti) {
|
|
127
|
+
const values = [...selected].map(b => b.dataset.value);
|
|
128
|
+
this.answers[field] = values;
|
|
129
|
+
return values.length > 0;
|
|
130
|
+
} else {
|
|
131
|
+
if (selected.length === 0) return false;
|
|
132
|
+
this.answers[field] = selected[0].dataset.value;
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
validate() {
|
|
138
|
+
const step = this.currentStep;
|
|
139
|
+
|
|
140
|
+
// Steps 1-5: option selection
|
|
141
|
+
if (step >= 1 && step <= 5) {
|
|
142
|
+
if (!this.collectStepValue(step)) {
|
|
143
|
+
this.showError('请至少选择一个选项');
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Step 6: provider + API key
|
|
150
|
+
if (step === 6) {
|
|
151
|
+
if (!this.collectStepValue(6)) {
|
|
152
|
+
this.showError('请选择一个 AI 提供商');
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const apiKey = this.els.apiKeyInput.value.trim();
|
|
156
|
+
if (!apiKey || apiKey.length < 10) {
|
|
157
|
+
this.showError('请输入有效的 API Key(至少 10 个字符)');
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
this.answers.apiKey = apiKey;
|
|
161
|
+
this.answers.tavilyKey = this.els.tavilyKeyInput.value.trim();
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Step 7: free description (always valid, optional)
|
|
166
|
+
if (step === 7) {
|
|
167
|
+
this.answers.freeDescription = this.els.freeDescription.value.trim();
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
next() {
|
|
175
|
+
if (this._navDebounce || this.isSubmitting) return;
|
|
176
|
+
this._navDebounce = true;
|
|
177
|
+
setTimeout(() => { this._navDebounce = false; }, 300);
|
|
178
|
+
|
|
179
|
+
if (!this.validate()) return;
|
|
180
|
+
|
|
181
|
+
if (this.currentStep === this.totalSteps) {
|
|
182
|
+
this.submit();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.currentStep++;
|
|
187
|
+
this.render();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
prev() {
|
|
191
|
+
if (this._navDebounce || this.isSubmitting) return;
|
|
192
|
+
this._navDebounce = true;
|
|
193
|
+
setTimeout(() => { this._navDebounce = false; }, 300);
|
|
194
|
+
|
|
195
|
+
if (this.currentStep > 1) {
|
|
196
|
+
this.currentStep--;
|
|
197
|
+
this.render();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
showError(msg) {
|
|
202
|
+
this.els.errorMsg.textContent = msg;
|
|
203
|
+
// 5秒后自动清除
|
|
204
|
+
clearTimeout(this._errorTimer);
|
|
205
|
+
this._errorTimer = setTimeout(() => this.clearError(), 5000);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
clearError() {
|
|
209
|
+
this.els.errorMsg.textContent = '';
|
|
210
|
+
clearTimeout(this._errorTimer);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async submit() {
|
|
214
|
+
if (this.isSubmitting) return;
|
|
215
|
+
this.isSubmitting = true;
|
|
216
|
+
|
|
217
|
+
const btn = this.els.btnNext;
|
|
218
|
+
btn.innerHTML = '<span class="ob-spinner"></span>生成中…';
|
|
219
|
+
btn.classList.add('loading');
|
|
220
|
+
btn.disabled = true;
|
|
221
|
+
|
|
222
|
+
const controller = new AbortController();
|
|
223
|
+
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const res = await fetch('/api/onboard', {
|
|
227
|
+
method: 'POST',
|
|
228
|
+
headers: { 'Content-Type': 'application/json' },
|
|
229
|
+
body: JSON.stringify(this.answers),
|
|
230
|
+
signal: controller.signal,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
clearTimeout(timeout);
|
|
234
|
+
const data = await res.json();
|
|
235
|
+
|
|
236
|
+
if (!res.ok) {
|
|
237
|
+
throw new Error(data.error || '初始化失败');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Success — redirect to workspace
|
|
241
|
+
btn.innerHTML = '✅ 就绪!正在跳转…';
|
|
242
|
+
btn.style.background = '#3fb950';
|
|
243
|
+
|
|
244
|
+
setTimeout(() => {
|
|
245
|
+
window.location.href = '/workspace';
|
|
246
|
+
}, 800);
|
|
247
|
+
|
|
248
|
+
} catch (err) {
|
|
249
|
+
const msg = err.name === 'AbortError' ? '请求超时,请重试' : (err.message || '提交失败,请检查网络');
|
|
250
|
+
this.showError(msg);
|
|
251
|
+
btn.innerHTML = '🚀 生成工作台';
|
|
252
|
+
btn.classList.remove('loading');
|
|
253
|
+
btn.disabled = false;
|
|
254
|
+
this.isSubmitting = false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Boot
|
|
260
|
+
const wizard = new OnboardingWizard();
|