clawaid 1.0.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/README.md +118 -0
- package/dist/diagnose.d.ts +41 -0
- package/dist/diagnose.d.ts.map +1 -0
- package/dist/diagnose.js +410 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/execute.d.ts +16 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +153 -0
- package/dist/execute.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/loop.d.ts +43 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +316 -0
- package/dist/loop.js.map +1 -0
- package/dist/observe.d.ts +29 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +330 -0
- package/dist/observe.js.map +1 -0
- package/dist/rules.d.ts +11 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +300 -0
- package/dist/rules.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +126 -0
- package/dist/server.js.map +1 -0
- package/dist/verify.d.ts +10 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +29 -0
- package/dist/verify.js.map +1 -0
- package/package.json +32 -0
- package/web/index.html +1226 -0
package/web/index.html
ADDED
|
@@ -0,0 +1,1226 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ClawAid</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
|
+
|
|
10
|
+
body {
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', Roboto, sans-serif;
|
|
12
|
+
background: #fafafa;
|
|
13
|
+
color: #202124;
|
|
14
|
+
min-height: 100vh;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
align-items: center;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.container {
|
|
21
|
+
width: 100%;
|
|
22
|
+
max-width: 600px;
|
|
23
|
+
padding: 48px 24px 80px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Header */
|
|
27
|
+
.header {
|
|
28
|
+
text-align: center;
|
|
29
|
+
margin-bottom: 40px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.logo {
|
|
33
|
+
font-size: 40px;
|
|
34
|
+
margin-bottom: 8px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.header h1 {
|
|
38
|
+
font-size: 28px;
|
|
39
|
+
font-weight: 400;
|
|
40
|
+
color: #202124;
|
|
41
|
+
margin-bottom: 6px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.header p {
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
color: #5f6368;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Status card */
|
|
50
|
+
.card {
|
|
51
|
+
background: #fff;
|
|
52
|
+
border: 1px solid #e8eaed;
|
|
53
|
+
border-radius: 12px;
|
|
54
|
+
padding: 32px;
|
|
55
|
+
margin-bottom: 16px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Progress log */
|
|
59
|
+
.log-area {
|
|
60
|
+
background: #f8f9fa;
|
|
61
|
+
border: 1px solid #e0e0e0;
|
|
62
|
+
border-radius: 8px;
|
|
63
|
+
padding: 16px;
|
|
64
|
+
font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
|
|
65
|
+
font-size: 12px;
|
|
66
|
+
color: #3c4043;
|
|
67
|
+
line-height: 1.6;
|
|
68
|
+
max-height: 280px;
|
|
69
|
+
overflow-y: auto;
|
|
70
|
+
white-space: pre-wrap;
|
|
71
|
+
word-break: break-word;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.log-area .log-line { display: block; }
|
|
75
|
+
.log-area .log-line.success { color: #137333; }
|
|
76
|
+
.log-area .log-line.error { color: #c5221f; }
|
|
77
|
+
.log-area .log-line.warn { color: #e37400; }
|
|
78
|
+
.log-area .log-line.meta { color: #1a73e8; font-weight: 600; }
|
|
79
|
+
|
|
80
|
+
/* Show details toggle */
|
|
81
|
+
.details-toggle {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 6px;
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
color: #1a73e8;
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
margin-top: 12px;
|
|
89
|
+
user-select: none;
|
|
90
|
+
background: none;
|
|
91
|
+
border: none;
|
|
92
|
+
padding: 0;
|
|
93
|
+
}
|
|
94
|
+
.details-toggle:hover { text-decoration: underline; }
|
|
95
|
+
.details-toggle .toggle-arrow { transition: transform 0.2s; display: inline-block; }
|
|
96
|
+
.details-toggle.open .toggle-arrow { transform: rotate(90deg); }
|
|
97
|
+
|
|
98
|
+
.details-panel {
|
|
99
|
+
margin-top: 8px;
|
|
100
|
+
display: none;
|
|
101
|
+
}
|
|
102
|
+
.details-panel.open { display: block; }
|
|
103
|
+
|
|
104
|
+
/* Spinner */
|
|
105
|
+
.spinner {
|
|
106
|
+
display: inline-block;
|
|
107
|
+
width: 18px;
|
|
108
|
+
height: 18px;
|
|
109
|
+
border: 2px solid #e0e0e0;
|
|
110
|
+
border-top-color: #1a73e8;
|
|
111
|
+
border-radius: 50%;
|
|
112
|
+
animation: spin 0.8s linear infinite;
|
|
113
|
+
flex-shrink: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@keyframes spin {
|
|
117
|
+
to { transform: rotate(360deg); }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Status row */
|
|
121
|
+
.status-row {
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
gap: 10px;
|
|
125
|
+
font-size: 15px;
|
|
126
|
+
color: #202124;
|
|
127
|
+
margin-bottom: 4px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.status-sub {
|
|
131
|
+
font-size: 12px;
|
|
132
|
+
color: #9aa0a6;
|
|
133
|
+
margin-left: 28px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Phase label */
|
|
137
|
+
.phase-label {
|
|
138
|
+
font-size: 10px;
|
|
139
|
+
font-weight: 600;
|
|
140
|
+
text-transform: uppercase;
|
|
141
|
+
letter-spacing: 1px;
|
|
142
|
+
color: #9aa0a6;
|
|
143
|
+
margin-bottom: 16px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Diagnosis card */
|
|
147
|
+
.diagnosis-section {
|
|
148
|
+
margin-bottom: 20px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.section-label {
|
|
152
|
+
font-size: 11px;
|
|
153
|
+
font-weight: 600;
|
|
154
|
+
color: #9aa0a6;
|
|
155
|
+
text-transform: uppercase;
|
|
156
|
+
letter-spacing: 0.5px;
|
|
157
|
+
margin-bottom: 8px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.diagnosis-text {
|
|
161
|
+
font-size: 15px;
|
|
162
|
+
color: #202124;
|
|
163
|
+
line-height: 1.6;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.root-cause {
|
|
167
|
+
background: #fef7e0;
|
|
168
|
+
border: 1px solid #f9ab00;
|
|
169
|
+
border-radius: 8px;
|
|
170
|
+
padding: 10px 14px;
|
|
171
|
+
font-size: 13px;
|
|
172
|
+
color: #7a4f00;
|
|
173
|
+
margin-top: 10px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.confidence-bar {
|
|
177
|
+
height: 4px;
|
|
178
|
+
background: #e8f0fe;
|
|
179
|
+
border-radius: 2px;
|
|
180
|
+
margin-top: 12px;
|
|
181
|
+
overflow: hidden;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.confidence-fill {
|
|
185
|
+
height: 100%;
|
|
186
|
+
background: #1a73e8;
|
|
187
|
+
border-radius: 2px;
|
|
188
|
+
transition: width 0.5s ease;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.confidence-label {
|
|
192
|
+
font-size: 11px;
|
|
193
|
+
color: #9aa0a6;
|
|
194
|
+
margin-top: 4px;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Collapsible reasoning */
|
|
198
|
+
.collapsible-toggle {
|
|
199
|
+
display: flex;
|
|
200
|
+
align-items: center;
|
|
201
|
+
gap: 6px;
|
|
202
|
+
font-size: 12px;
|
|
203
|
+
color: #5f6368;
|
|
204
|
+
cursor: pointer;
|
|
205
|
+
margin-top: 12px;
|
|
206
|
+
background: none;
|
|
207
|
+
border: none;
|
|
208
|
+
padding: 0;
|
|
209
|
+
user-select: none;
|
|
210
|
+
}
|
|
211
|
+
.collapsible-toggle:hover { color: #202124; }
|
|
212
|
+
.collapsible-toggle .arrow { transition: transform 0.2s; display: inline-block; }
|
|
213
|
+
.collapsible-toggle.open .arrow { transform: rotate(90deg); }
|
|
214
|
+
.collapsible-panel { display: none; margin-top: 8px; }
|
|
215
|
+
.collapsible-panel.open { display: block; }
|
|
216
|
+
|
|
217
|
+
/* Divider */
|
|
218
|
+
.divider {
|
|
219
|
+
border: none;
|
|
220
|
+
border-top: 1px solid #f1f3f4;
|
|
221
|
+
margin: 16px 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Option cards */
|
|
225
|
+
.options-list {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
228
|
+
gap: 12px;
|
|
229
|
+
margin-top: 8px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.option-card {
|
|
233
|
+
border: 1.5px solid #e0e0e0;
|
|
234
|
+
border-radius: 10px;
|
|
235
|
+
padding: 16px;
|
|
236
|
+
transition: border-color 0.15s;
|
|
237
|
+
position: relative;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.option-card.recommended {
|
|
241
|
+
border-color: #1a73e8;
|
|
242
|
+
background: #f8fbff;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.option-card-header {
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: flex-start;
|
|
248
|
+
gap: 10px;
|
|
249
|
+
margin-bottom: 8px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.option-letter {
|
|
253
|
+
width: 26px;
|
|
254
|
+
height: 26px;
|
|
255
|
+
border-radius: 50%;
|
|
256
|
+
background: #e8eaed;
|
|
257
|
+
color: #3c4043;
|
|
258
|
+
font-size: 13px;
|
|
259
|
+
font-weight: 700;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
justify-content: center;
|
|
263
|
+
flex-shrink: 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.option-card.recommended .option-letter {
|
|
267
|
+
background: #1a73e8;
|
|
268
|
+
color: #fff;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.option-title-row {
|
|
272
|
+
flex: 1;
|
|
273
|
+
display: flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
gap: 8px;
|
|
276
|
+
flex-wrap: wrap;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.option-title {
|
|
280
|
+
font-size: 14px;
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
color: #202124;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.recommended-badge {
|
|
286
|
+
font-size: 10px;
|
|
287
|
+
background: #e8f0fe;
|
|
288
|
+
color: #1a73e8;
|
|
289
|
+
border: 1px solid #c5d9f7;
|
|
290
|
+
border-radius: 4px;
|
|
291
|
+
padding: 2px 6px;
|
|
292
|
+
font-weight: 600;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.risk-badge {
|
|
296
|
+
font-size: 10px;
|
|
297
|
+
padding: 2px 6px;
|
|
298
|
+
border-radius: 4px;
|
|
299
|
+
font-weight: 600;
|
|
300
|
+
}
|
|
301
|
+
.risk-low { background: #e6f4ea; color: #137333; }
|
|
302
|
+
.risk-medium { background: #fef7e0; color: #7a4f00; }
|
|
303
|
+
.risk-high { background: #fce8e6; color: #c5221f; }
|
|
304
|
+
|
|
305
|
+
.option-description {
|
|
306
|
+
font-size: 13px;
|
|
307
|
+
color: #5f6368;
|
|
308
|
+
line-height: 1.5;
|
|
309
|
+
margin-left: 36px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.option-fix-btn {
|
|
313
|
+
display: inline-flex;
|
|
314
|
+
align-items: center;
|
|
315
|
+
gap: 6px;
|
|
316
|
+
margin-top: 12px;
|
|
317
|
+
margin-left: 36px;
|
|
318
|
+
padding: 8px 18px;
|
|
319
|
+
font-size: 13px;
|
|
320
|
+
font-weight: 500;
|
|
321
|
+
background: #f1f3f4;
|
|
322
|
+
color: #3c4043;
|
|
323
|
+
border: none;
|
|
324
|
+
border-radius: 6px;
|
|
325
|
+
cursor: pointer;
|
|
326
|
+
transition: background 0.15s;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.option-card.recommended .option-fix-btn {
|
|
330
|
+
background: #1a73e8;
|
|
331
|
+
color: #fff;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.option-fix-btn:hover { opacity: 0.85; }
|
|
335
|
+
.option-fix-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
336
|
+
|
|
337
|
+
/* Auto-fix progress */
|
|
338
|
+
.auto-fix-row {
|
|
339
|
+
display: flex;
|
|
340
|
+
align-items: center;
|
|
341
|
+
gap: 12px;
|
|
342
|
+
padding: 12px 0;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.auto-fix-icon {
|
|
346
|
+
font-size: 20px;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.auto-fix-text {
|
|
350
|
+
font-size: 15px;
|
|
351
|
+
font-weight: 500;
|
|
352
|
+
color: #202124;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.auto-fix-sub {
|
|
356
|
+
font-size: 12px;
|
|
357
|
+
color: #9aa0a6;
|
|
358
|
+
margin-top: 2px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* Buttons */
|
|
362
|
+
.btn {
|
|
363
|
+
display: inline-flex;
|
|
364
|
+
align-items: center;
|
|
365
|
+
gap: 8px;
|
|
366
|
+
padding: 12px 24px;
|
|
367
|
+
font-size: 15px;
|
|
368
|
+
font-weight: 500;
|
|
369
|
+
border: none;
|
|
370
|
+
border-radius: 8px;
|
|
371
|
+
cursor: pointer;
|
|
372
|
+
transition: background 0.15s, transform 0.1s;
|
|
373
|
+
width: 100%;
|
|
374
|
+
justify-content: center;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.btn:active { transform: scale(0.98); }
|
|
378
|
+
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
379
|
+
|
|
380
|
+
.btn-primary {
|
|
381
|
+
background: #1a73e8;
|
|
382
|
+
color: #fff;
|
|
383
|
+
}
|
|
384
|
+
.btn-primary:hover:not(:disabled) { background: #1557b0; }
|
|
385
|
+
|
|
386
|
+
.btn-secondary {
|
|
387
|
+
background: #f1f3f4;
|
|
388
|
+
color: #3c4043;
|
|
389
|
+
}
|
|
390
|
+
.btn-secondary:hover:not(:disabled) { background: #e8eaed; }
|
|
391
|
+
|
|
392
|
+
.btn-coffee {
|
|
393
|
+
background: #FFDD00;
|
|
394
|
+
color: #000;
|
|
395
|
+
font-size: 14px;
|
|
396
|
+
}
|
|
397
|
+
.btn-coffee:hover:not(:disabled) { background: #f0cf00; }
|
|
398
|
+
|
|
399
|
+
/* Input field */
|
|
400
|
+
.input-group { margin-bottom: 16px; }
|
|
401
|
+
|
|
402
|
+
.input-label {
|
|
403
|
+
display: block;
|
|
404
|
+
font-size: 13px;
|
|
405
|
+
font-weight: 500;
|
|
406
|
+
color: #3c4043;
|
|
407
|
+
margin-bottom: 6px;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.input-field {
|
|
411
|
+
width: 100%;
|
|
412
|
+
padding: 10px 14px;
|
|
413
|
+
font-size: 14px;
|
|
414
|
+
border: 1px solid #dadce0;
|
|
415
|
+
border-radius: 8px;
|
|
416
|
+
outline: none;
|
|
417
|
+
transition: border-color 0.15s;
|
|
418
|
+
font-family: monospace;
|
|
419
|
+
color: #202124;
|
|
420
|
+
}
|
|
421
|
+
.input-field:focus { border-color: #1a73e8; box-shadow: 0 0 0 2px rgba(26,115,232,0.2); }
|
|
422
|
+
|
|
423
|
+
.trust-badge {
|
|
424
|
+
display: flex;
|
|
425
|
+
align-items: center;
|
|
426
|
+
gap: 6px;
|
|
427
|
+
font-size: 12px;
|
|
428
|
+
color: #137333;
|
|
429
|
+
margin-top: 8px;
|
|
430
|
+
background: #e6f4ea;
|
|
431
|
+
padding: 6px 10px;
|
|
432
|
+
border-radius: 6px;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* Result screens */
|
|
436
|
+
.result-icon {
|
|
437
|
+
font-size: 48px;
|
|
438
|
+
text-align: center;
|
|
439
|
+
margin-bottom: 16px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.result-title {
|
|
443
|
+
font-size: 22px;
|
|
444
|
+
font-weight: 500;
|
|
445
|
+
text-align: center;
|
|
446
|
+
margin-bottom: 8px;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.result-desc {
|
|
450
|
+
font-size: 14px;
|
|
451
|
+
color: #5f6368;
|
|
452
|
+
text-align: center;
|
|
453
|
+
line-height: 1.6;
|
|
454
|
+
margin-bottom: 24px;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.report-area {
|
|
458
|
+
background: #f8f9fa;
|
|
459
|
+
border: 1px solid #e0e0e0;
|
|
460
|
+
border-radius: 8px;
|
|
461
|
+
padding: 16px;
|
|
462
|
+
font-family: monospace;
|
|
463
|
+
font-size: 11px;
|
|
464
|
+
color: #3c4043;
|
|
465
|
+
max-height: 200px;
|
|
466
|
+
overflow-y: auto;
|
|
467
|
+
white-space: pre-wrap;
|
|
468
|
+
word-break: break-all;
|
|
469
|
+
margin-bottom: 12px;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* Alternatives */
|
|
473
|
+
.alt-list { list-style: none; margin-top: 6px; }
|
|
474
|
+
.alt-list li {
|
|
475
|
+
font-size: 13px;
|
|
476
|
+
color: #5f6368;
|
|
477
|
+
padding: 4px 0;
|
|
478
|
+
display: flex;
|
|
479
|
+
gap: 6px;
|
|
480
|
+
}
|
|
481
|
+
.alt-list li::before { content: '→'; color: #9aa0a6; flex-shrink: 0; }
|
|
482
|
+
|
|
483
|
+
/* Sections */
|
|
484
|
+
.section { display: none; }
|
|
485
|
+
.section.visible { display: block; }
|
|
486
|
+
|
|
487
|
+
@keyframes fadeIn {
|
|
488
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
489
|
+
to { opacity: 1; transform: translateY(0); }
|
|
490
|
+
}
|
|
491
|
+
.fade-in { animation: fadeIn 0.25s ease; }
|
|
492
|
+
|
|
493
|
+
/* Footer */
|
|
494
|
+
.footer {
|
|
495
|
+
text-align: center;
|
|
496
|
+
font-size: 12px;
|
|
497
|
+
color: #9aa0a6;
|
|
498
|
+
margin-top: 32px;
|
|
499
|
+
}
|
|
500
|
+
.footer a { color: #1a73e8; text-decoration: none; }
|
|
501
|
+
.footer a:hover { text-decoration: underline; }
|
|
502
|
+
|
|
503
|
+
/* Copy button */
|
|
504
|
+
.copy-btn {
|
|
505
|
+
background: none;
|
|
506
|
+
border: 1px solid #dadce0;
|
|
507
|
+
border-radius: 6px;
|
|
508
|
+
padding: 6px 12px;
|
|
509
|
+
font-size: 12px;
|
|
510
|
+
cursor: pointer;
|
|
511
|
+
color: #5f6368;
|
|
512
|
+
transition: background 0.15s;
|
|
513
|
+
}
|
|
514
|
+
.copy-btn:hover { background: #f1f3f4; }
|
|
515
|
+
|
|
516
|
+
/* Round badge */
|
|
517
|
+
.round-badge {
|
|
518
|
+
display: inline-flex;
|
|
519
|
+
align-items: center;
|
|
520
|
+
gap: 6px;
|
|
521
|
+
background: #e8f0fe;
|
|
522
|
+
color: #1a73e8;
|
|
523
|
+
font-size: 12px;
|
|
524
|
+
font-weight: 600;
|
|
525
|
+
padding: 4px 10px;
|
|
526
|
+
border-radius: 20px;
|
|
527
|
+
margin-bottom: 12px;
|
|
528
|
+
}
|
|
529
|
+
</style>
|
|
530
|
+
</head>
|
|
531
|
+
<body>
|
|
532
|
+
<div class="container">
|
|
533
|
+
|
|
534
|
+
<!-- Header -->
|
|
535
|
+
<div class="header">
|
|
536
|
+
<div class="logo" style="font-size:48px; line-height:1;">🦞🩹</div>
|
|
537
|
+
<h1>ClawAid</h1>
|
|
538
|
+
<p>Automatic diagnostics and repair for OpenClaw</p>
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<!-- ===== SECTION: Privacy ===== -->
|
|
542
|
+
<div id="section-privacy" class="section visible card fade-in">
|
|
543
|
+
<div style="text-align:center; font-size:32px; margin-bottom:12px;">🔒</div>
|
|
544
|
+
<div style="font-size:16px; font-weight:500; text-align:center; margin-bottom:12px;">Before we start</div>
|
|
545
|
+
<div style="font-size:13px; color:#5f6368; line-height:1.6; margin-bottom:16px;">
|
|
546
|
+
ClawAid will collect your OpenClaw config, gateway status, and recent logs to diagnose issues.
|
|
547
|
+
<ul style="margin-top:8px; padding-left:20px;">
|
|
548
|
+
<li>API keys are partially redacted before sending</li>
|
|
549
|
+
<li>Data is sent to <strong>our diagnostic service</strong> for analysis only</li>
|
|
550
|
+
<li>Nothing is stored or shared beyond this session</li>
|
|
551
|
+
</ul>
|
|
552
|
+
</div>
|
|
553
|
+
<button class="btn btn-primary" id="btn-start-scan">
|
|
554
|
+
🩺 Start Scan
|
|
555
|
+
</button>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<!-- ===== SECTION: Scanning ===== -->
|
|
559
|
+
<div id="section-scanning" class="section card fade-in">
|
|
560
|
+
<div class="phase-label">Phase 1 — Scanning</div>
|
|
561
|
+
<div class="status-row">
|
|
562
|
+
<span class="spinner"></span>
|
|
563
|
+
<span id="scan-status-text">Starting scan...</span>
|
|
564
|
+
</div>
|
|
565
|
+
<div class="status-sub" id="scan-sub-text"></div>
|
|
566
|
+
|
|
567
|
+
<button class="details-toggle" id="btn-toggle-scan-log" onclick="toggleDetails('scan-log')">
|
|
568
|
+
<span class="toggle-arrow">▶</span> Show details
|
|
569
|
+
</button>
|
|
570
|
+
<div class="details-panel" id="details-scan-log">
|
|
571
|
+
<div class="log-area" id="log-area">Connecting to diagnostic engine...</div>
|
|
572
|
+
</div>
|
|
573
|
+
</div>
|
|
574
|
+
|
|
575
|
+
<!-- ===== SECTION: API Key Input ===== -->
|
|
576
|
+
<div id="section-apikey" class="section card fade-in">
|
|
577
|
+
<div class="phase-label">Action Required</div>
|
|
578
|
+
<div class="diagnosis-section">
|
|
579
|
+
<div class="section-label">API Key Required</div>
|
|
580
|
+
<p class="diagnosis-text" id="apikey-instructions">
|
|
581
|
+
ClawAid needs an OpenRouter API key to run diagnostics.
|
|
582
|
+
</p>
|
|
583
|
+
</div>
|
|
584
|
+
<hr class="divider">
|
|
585
|
+
<div class="input-group">
|
|
586
|
+
<label class="input-label" for="apikey-input">OpenRouter API Key</label>
|
|
587
|
+
<input
|
|
588
|
+
class="input-field"
|
|
589
|
+
id="apikey-input"
|
|
590
|
+
type="password"
|
|
591
|
+
placeholder="sk-or-..."
|
|
592
|
+
autocomplete="off"
|
|
593
|
+
spellcheck="false"
|
|
594
|
+
/>
|
|
595
|
+
<div class="trust-badge">
|
|
596
|
+
🔒 Local only. Not stored. Only sent to OpenRouter for AI diagnosis.
|
|
597
|
+
</div>
|
|
598
|
+
<div style="margin-top: 6px;">
|
|
599
|
+
<a href="https://openrouter.ai/keys" target="_blank" style="font-size: 12px; color: #1a73e8;">
|
|
600
|
+
Get an OpenRouter API key →
|
|
601
|
+
</a>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
<button class="btn btn-primary" id="btn-submit-key">
|
|
605
|
+
Start Diagnosis
|
|
606
|
+
</button>
|
|
607
|
+
</div>
|
|
608
|
+
|
|
609
|
+
<!-- ===== SECTION: Diagnosis ===== -->
|
|
610
|
+
<div id="section-diagnosis" class="section card fade-in">
|
|
611
|
+
<div class="phase-label">Phase 2 — Diagnosis</div>
|
|
612
|
+
<div id="round-badge-diag" class="round-badge" style="display:none;">
|
|
613
|
+
<span>🔄</span><span id="round-badge-text">Round 2</span>
|
|
614
|
+
</div>
|
|
615
|
+
|
|
616
|
+
<div class="diagnosis-section">
|
|
617
|
+
<div class="section-label">What's wrong</div>
|
|
618
|
+
<p class="diagnosis-text" id="diag-text">Analyzing...</p>
|
|
619
|
+
<div class="root-cause" id="root-cause-box"></div>
|
|
620
|
+
<div class="confidence-bar">
|
|
621
|
+
<div class="confidence-fill" id="confidence-fill" style="width:0%"></div>
|
|
622
|
+
</div>
|
|
623
|
+
<div class="confidence-label" id="confidence-label">Confidence: —</div>
|
|
624
|
+
</div>
|
|
625
|
+
|
|
626
|
+
<button class="collapsible-toggle" id="toggle-reasoning" onclick="toggleReasoning()">
|
|
627
|
+
<span class="arrow">▶</span> Diagnostic details
|
|
628
|
+
</button>
|
|
629
|
+
<div class="collapsible-panel" id="reasoning-panel">
|
|
630
|
+
<div class="log-area" id="reasoning-log" style="max-height:180px;"></div>
|
|
631
|
+
</div>
|
|
632
|
+
|
|
633
|
+
<div id="alternatives-section" style="display:none; margin-top:12px;">
|
|
634
|
+
<hr class="divider">
|
|
635
|
+
<div class="section-label">Other possibilities</div>
|
|
636
|
+
<ul class="alt-list" id="alt-list"></ul>
|
|
637
|
+
</div>
|
|
638
|
+
</div>
|
|
639
|
+
|
|
640
|
+
<!-- ===== SECTION: Options (user choice) ===== -->
|
|
641
|
+
<div id="section-options" class="section card fade-in">
|
|
642
|
+
<div class="phase-label">Phase 3 — Choose a Fix</div>
|
|
643
|
+
<div id="round-badge-opts" class="round-badge" style="display:none;">
|
|
644
|
+
<span>🔄</span><span id="round-opts-text">Round 2</span>
|
|
645
|
+
</div>
|
|
646
|
+
<p style="font-size:14px; color:#5f6368; margin-bottom:16px;">
|
|
647
|
+
Select a repair option below. The recommended fix is highlighted.
|
|
648
|
+
</p>
|
|
649
|
+
<div class="options-list" id="options-list"></div>
|
|
650
|
+
</div>
|
|
651
|
+
|
|
652
|
+
<!-- ===== SECTION: Auto-executing ===== -->
|
|
653
|
+
<div id="section-auto-fix" class="section card fade-in">
|
|
654
|
+
<div class="phase-label">Phase 3 — Auto-fixing</div>
|
|
655
|
+
<div class="auto-fix-row">
|
|
656
|
+
<div class="auto-fix-icon">🔧</div>
|
|
657
|
+
<div>
|
|
658
|
+
<div class="auto-fix-text">Auto-fixing...</div>
|
|
659
|
+
<div class="auto-fix-sub" id="auto-fix-sub">Applying recommended fix</div>
|
|
660
|
+
</div>
|
|
661
|
+
<span class="spinner" style="margin-left:auto;"></span>
|
|
662
|
+
</div>
|
|
663
|
+
|
|
664
|
+
<button class="details-toggle" id="btn-toggle-fix-log" onclick="toggleDetails('fix-log')">
|
|
665
|
+
<span class="toggle-arrow">▶</span> Show details
|
|
666
|
+
</button>
|
|
667
|
+
<div class="details-panel" id="details-fix-log">
|
|
668
|
+
<div class="log-area" id="exec-log"></div>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
<!-- ===== SECTION: Fixed ===== -->
|
|
673
|
+
<div id="section-fixed" class="section card fade-in">
|
|
674
|
+
<div class="result-icon">✅</div>
|
|
675
|
+
<div class="result-title">OpenClaw is fixed!</div>
|
|
676
|
+
|
|
677
|
+
<div id="fixed-summary" style="text-align:left; margin: 20px 0;">
|
|
678
|
+
<div style="margin-bottom:16px;">
|
|
679
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:1px; color:#9aa0a6; margin-bottom:6px;">What was wrong</div>
|
|
680
|
+
<div id="fixed-what-wrong" style="font-size:14px; color:#3c4043; line-height:1.6;"></div>
|
|
681
|
+
</div>
|
|
682
|
+
<div style="border-top:1px solid #e8eaed; padding-top:16px;">
|
|
683
|
+
<div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:1px; color:#9aa0a6; margin-bottom:6px;">What we fixed</div>
|
|
684
|
+
<div id="fixed-what-fixed" style="font-size:14px; color:#3c4043; line-height:1.6;"></div>
|
|
685
|
+
</div>
|
|
686
|
+
</div>
|
|
687
|
+
|
|
688
|
+
<div style="margin-bottom:16px;">
|
|
689
|
+
<button class="details-toggle" id="btn-fixed-details" onclick="toggleFixedDetails()">
|
|
690
|
+
<span class="toggle-arrow">▶</span> Show technical details
|
|
691
|
+
</button>
|
|
692
|
+
<div class="details-panel" id="fixed-details-panel" style="margin-top:8px;">
|
|
693
|
+
<p id="fixed-explanation" style="font-size:13px; color:#5f6368;"></p>
|
|
694
|
+
</div>
|
|
695
|
+
</div>
|
|
696
|
+
|
|
697
|
+
<button class="btn btn-coffee" onclick="window.open('https://buymeacoffee.com/clawaid','_blank')">
|
|
698
|
+
☕ Buy me a coffee
|
|
699
|
+
</button>
|
|
700
|
+
<div style="margin-top: 8px; text-align: center; font-size: 12px; color: #9aa0a6;">
|
|
701
|
+
ClawAid is free. If it saved your day, a coffee helps keep it alive!
|
|
702
|
+
</div>
|
|
703
|
+
</div>
|
|
704
|
+
|
|
705
|
+
<!-- ===== SECTION: Healthy ===== -->
|
|
706
|
+
<div id="section-healthy" class="section card fade-in">
|
|
707
|
+
<div class="result-icon">💚</div>
|
|
708
|
+
<div class="result-title">OpenClaw is healthy!</div>
|
|
709
|
+
<p class="result-desc" id="healthy-explanation">Your system is running normally. No issues detected.</p>
|
|
710
|
+
|
|
711
|
+
<div id="healthy-reasoning" style="display:none; text-align:left; margin-bottom:12px;">
|
|
712
|
+
<button class="details-toggle" onclick="this.nextElementSibling.classList.toggle('open'); this.querySelector('.toggle-arrow').textContent = this.nextElementSibling.classList.contains('open') ? '▼' : '▶'">
|
|
713
|
+
<span class="toggle-arrow">▶</span> How we diagnosed this
|
|
714
|
+
</button>
|
|
715
|
+
<div class="details-panel" id="healthy-reasoning-list" style="margin-top:8px;"></div>
|
|
716
|
+
</div>
|
|
717
|
+
|
|
718
|
+
<div id="healthy-warnings" style="display:none; text-align:left; margin-bottom:16px;">
|
|
719
|
+
<div style="font-size:13px; font-weight:600; color:#e37400; margin-bottom:8px;">⚠️ Non-critical notes</div>
|
|
720
|
+
<ul id="healthy-warnings-list" style="list-style:none; padding:0; margin:0;"></ul>
|
|
721
|
+
</div>
|
|
722
|
+
|
|
723
|
+
<button class="btn btn-secondary" onclick="location.reload()" style="margin-bottom: 8px;">
|
|
724
|
+
🔄 Scan Again
|
|
725
|
+
</button>
|
|
726
|
+
</div>
|
|
727
|
+
|
|
728
|
+
<!-- ===== SECTION: Not Fixed ===== -->
|
|
729
|
+
<div id="section-notfixed" class="section card fade-in">
|
|
730
|
+
<div class="result-icon">😔</div>
|
|
731
|
+
<div class="result-title">Couldn't fix automatically</div>
|
|
732
|
+
<p class="result-desc" id="notfixed-explanation">
|
|
733
|
+
After multiple attempts, the issue couldn't be resolved automatically.
|
|
734
|
+
Here's the diagnostic report to share with the community.
|
|
735
|
+
</p>
|
|
736
|
+
|
|
737
|
+
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px;">
|
|
738
|
+
<span style="font-size: 13px; font-weight: 500; color: #3c4043;">Diagnostic Report</span>
|
|
739
|
+
<button class="copy-btn" id="btn-copy-report">Copy</button>
|
|
740
|
+
</div>
|
|
741
|
+
<div class="report-area" id="report-area"></div>
|
|
742
|
+
|
|
743
|
+
<button class="btn btn-secondary" onclick="window.open('https://discord.gg/openclaw','_blank')" style="margin-bottom: 8px;">
|
|
744
|
+
💬 Get Help on Discord
|
|
745
|
+
</button>
|
|
746
|
+
<button class="btn btn-secondary" onclick="location.reload()">
|
|
747
|
+
🔄 Try Again
|
|
748
|
+
</button>
|
|
749
|
+
</div>
|
|
750
|
+
|
|
751
|
+
<div class="footer">
|
|
752
|
+
<p>ClawAid v1.0.0 · <a href="https://github.com/openclaw" target="_blank">GitHub</a></p>
|
|
753
|
+
</div>
|
|
754
|
+
|
|
755
|
+
</div>
|
|
756
|
+
|
|
757
|
+
<script>
|
|
758
|
+
(function() {
|
|
759
|
+
'use strict';
|
|
760
|
+
|
|
761
|
+
// State
|
|
762
|
+
let sessionId = null;
|
|
763
|
+
let currentState = 'idle';
|
|
764
|
+
let eventSource = null;
|
|
765
|
+
let diagnosisData = null; // last diagnosis received
|
|
766
|
+
let chosenOption = null; // option selected for fix
|
|
767
|
+
|
|
768
|
+
// Elements
|
|
769
|
+
const $ = id => document.getElementById(id);
|
|
770
|
+
|
|
771
|
+
const sections = {
|
|
772
|
+
privacy: $('section-privacy'),
|
|
773
|
+
scanning: $('section-scanning'),
|
|
774
|
+
apikey: $('section-apikey'),
|
|
775
|
+
diagnosis: $('section-diagnosis'),
|
|
776
|
+
options: $('section-options'),
|
|
777
|
+
autofix: $('section-auto-fix'),
|
|
778
|
+
fixed: $('section-fixed'),
|
|
779
|
+
healthy: $('section-healthy'),
|
|
780
|
+
notfixed: $('section-notfixed'),
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
function showOnly(name) {
|
|
784
|
+
Object.entries(sections).forEach(([key, el]) => {
|
|
785
|
+
el.classList.toggle('visible', key === name);
|
|
786
|
+
});
|
|
787
|
+
currentState = name;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function appendLog(areaId, msg, cls) {
|
|
791
|
+
const area = $(areaId);
|
|
792
|
+
if (!area) return;
|
|
793
|
+
const line = document.createElement('span');
|
|
794
|
+
line.className = 'log-line' + (cls ? ' ' + cls : '');
|
|
795
|
+
line.textContent = msg + '\n';
|
|
796
|
+
area.appendChild(line);
|
|
797
|
+
area.scrollTop = area.scrollHeight;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function classForMessage(msg) {
|
|
801
|
+
if (msg.startsWith('✓') || msg.startsWith('✅') || msg.includes('Success') || msg.includes('fixed')) return 'success';
|
|
802
|
+
if (msg.startsWith('❌') || msg.startsWith('✗') || msg.includes('Error') || msg.includes('failed')) return 'error';
|
|
803
|
+
if (msg.startsWith('⚠️') || msg.startsWith('Warning')) return 'warn';
|
|
804
|
+
if (msg.startsWith('🤖') || msg.startsWith('💭') || msg.startsWith('🔄') || msg.startsWith('📡')) return 'meta';
|
|
805
|
+
return '';
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Details toggle (scan + fix log panels)
|
|
809
|
+
window.toggleDetails = function(panelSuffix) {
|
|
810
|
+
const btnId = 'btn-toggle-' + panelSuffix;
|
|
811
|
+
const panelId = 'details-' + panelSuffix;
|
|
812
|
+
const btn = $(btnId);
|
|
813
|
+
const panel = $(panelId);
|
|
814
|
+
if (!btn || !panel) return;
|
|
815
|
+
const isOpen = panel.classList.toggle('open');
|
|
816
|
+
btn.classList.toggle('open', isOpen);
|
|
817
|
+
btn.querySelector('.toggle-arrow').textContent = isOpen ? '▼' : '▶';
|
|
818
|
+
btn.childNodes[1].textContent = isOpen ? ' Hide details' : ' Show details';
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// Fixed details toggle
|
|
822
|
+
window.toggleFixedDetails = function() {
|
|
823
|
+
const btn = $('btn-fixed-details');
|
|
824
|
+
const panel = $('fixed-details-panel');
|
|
825
|
+
const isOpen = panel.classList.toggle('open');
|
|
826
|
+
btn.querySelector('.toggle-arrow').textContent = isOpen ? '▼' : '▶';
|
|
827
|
+
btn.childNodes[1].textContent = isOpen ? ' Hide technical details' : ' Show technical details';
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// Reasoning toggle
|
|
831
|
+
window.toggleReasoning = function() {
|
|
832
|
+
const btn = $('toggle-reasoning');
|
|
833
|
+
const panel = $('reasoning-panel');
|
|
834
|
+
const isOpen = panel.classList.toggle('open');
|
|
835
|
+
btn.classList.toggle('open', isOpen);
|
|
836
|
+
btn.querySelector('.arrow').textContent = isOpen ? '▼' : '▶';
|
|
837
|
+
btn.childNodes[1].textContent = isOpen ? ' Hide diagnostic details' : ' Diagnostic details';
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
// Start SSE connection
|
|
841
|
+
function startDiagnosis() {
|
|
842
|
+
showOnly('scanning');
|
|
843
|
+
$('log-area').textContent = '';
|
|
844
|
+
$('exec-log').textContent = '';
|
|
845
|
+
|
|
846
|
+
eventSource = new EventSource('/api/diagnose');
|
|
847
|
+
|
|
848
|
+
eventSource.onmessage = function(e) {
|
|
849
|
+
let parsed;
|
|
850
|
+
try { parsed = JSON.parse(e.data); } catch { return; }
|
|
851
|
+
|
|
852
|
+
const { type, data } = parsed;
|
|
853
|
+
sessionId = parsed.sessionId || sessionId;
|
|
854
|
+
|
|
855
|
+
switch(type) {
|
|
856
|
+
case 'session_start':
|
|
857
|
+
sessionId = data.sessionId;
|
|
858
|
+
$('scan-status-text').textContent = 'Checking gateway...';
|
|
859
|
+
break;
|
|
860
|
+
|
|
861
|
+
case 'progress': {
|
|
862
|
+
const msg = data.message || '';
|
|
863
|
+
const cls = classForMessage(msg);
|
|
864
|
+
appendLog('log-area', msg, cls);
|
|
865
|
+
appendLog('exec-log', msg, cls);
|
|
866
|
+
appendLog('reasoning-log', msg, cls);
|
|
867
|
+
|
|
868
|
+
// Update clean status text
|
|
869
|
+
const clean = msg.replace(/^[🔍🤔🔧✅⚠️❌💭🔄→📡🔒 ]+/, '').trim().slice(0, 80);
|
|
870
|
+
if (clean) {
|
|
871
|
+
$('scan-status-text').textContent = clean;
|
|
872
|
+
$('auto-fix-sub').textContent = clean;
|
|
873
|
+
}
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
case 'state_change':
|
|
878
|
+
handleStateChange(data.state);
|
|
879
|
+
break;
|
|
880
|
+
|
|
881
|
+
case 'diagnosis':
|
|
882
|
+
showDiagnosis(data);
|
|
883
|
+
break;
|
|
884
|
+
|
|
885
|
+
case 'action_result':
|
|
886
|
+
break;
|
|
887
|
+
|
|
888
|
+
case 'verify_result':
|
|
889
|
+
appendLog('exec-log', '─────────────────────────────────────', '');
|
|
890
|
+
if (data.fixed) {
|
|
891
|
+
appendLog('exec-log', '✅ Verified — issue resolved!', 'success');
|
|
892
|
+
appendLog('exec-log', ' ' + data.explanation, 'success');
|
|
893
|
+
} else {
|
|
894
|
+
appendLog('exec-log', '⚠️ Not yet fixed: ' + data.explanation, 'warn');
|
|
895
|
+
appendLog('exec-log', ' Re-analyzing...', '');
|
|
896
|
+
}
|
|
897
|
+
break;
|
|
898
|
+
|
|
899
|
+
case 'request_input':
|
|
900
|
+
if (data.field === 'apiKey') showApiKeyInput(data);
|
|
901
|
+
break;
|
|
902
|
+
|
|
903
|
+
case 'complete':
|
|
904
|
+
handleComplete(data);
|
|
905
|
+
break;
|
|
906
|
+
|
|
907
|
+
case 'error':
|
|
908
|
+
appendLog('log-area', '─────────────────────────────────────', '');
|
|
909
|
+
appendLog('log-area', '❌ Error: ' + data.message, 'error');
|
|
910
|
+
appendLog('log-area', ' Check your API key and internet connection, then reload to try again.', 'warn');
|
|
911
|
+
$('scan-status-text').textContent = 'Error — click "Show details"';
|
|
912
|
+
showOnly('scanning');
|
|
913
|
+
// Auto-open details on error
|
|
914
|
+
const detailPanel = $('details-scan-log');
|
|
915
|
+
if (detailPanel && !detailPanel.classList.contains('open')) {
|
|
916
|
+
window.toggleDetails('scan-log');
|
|
917
|
+
}
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
eventSource.onerror = function() {
|
|
923
|
+
if (currentState !== 'fixed' && currentState !== 'notfixed' && currentState !== 'healthy') {
|
|
924
|
+
appendLog('log-area', '⚠️ Connection lost. The server may have stopped.', 'warn');
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function handleStateChange(state) {
|
|
930
|
+
switch(state) {
|
|
931
|
+
case 'observing':
|
|
932
|
+
showOnly('scanning');
|
|
933
|
+
$('scan-status-text').textContent = 'Checking gateway...';
|
|
934
|
+
break;
|
|
935
|
+
case 'diagnosing':
|
|
936
|
+
showOnly('scanning');
|
|
937
|
+
$('scan-status-text').textContent = 'Analyzing your system...';
|
|
938
|
+
$('scan-sub-text').textContent = 'This may take a few seconds';
|
|
939
|
+
appendLog('log-area', '─────────────────────────────────────', '');
|
|
940
|
+
appendLog('log-area', '🤖 Sending data to AI for diagnosis...', 'meta');
|
|
941
|
+
break;
|
|
942
|
+
case 'showing_options':
|
|
943
|
+
// Options will show via 'diagnosis' event + render options
|
|
944
|
+
break;
|
|
945
|
+
case 'auto_executing':
|
|
946
|
+
$('exec-log').textContent = '';
|
|
947
|
+
showOnly('autofix');
|
|
948
|
+
break;
|
|
949
|
+
case 'executing':
|
|
950
|
+
$('exec-log').textContent = '';
|
|
951
|
+
showOnly('autofix');
|
|
952
|
+
break;
|
|
953
|
+
case 'verifying':
|
|
954
|
+
$('auto-fix-sub').textContent = 'Verifying repair...';
|
|
955
|
+
appendLog('exec-log', '─────────────────────────────────────', '');
|
|
956
|
+
appendLog('exec-log', '🔍 Checking if the fix worked...', 'meta');
|
|
957
|
+
break;
|
|
958
|
+
case 'needs_api_key':
|
|
959
|
+
break; // handled by request_input event
|
|
960
|
+
case 'error':
|
|
961
|
+
$('scan-status-text').textContent = 'Error occurred';
|
|
962
|
+
break;
|
|
963
|
+
case 'fixed':
|
|
964
|
+
showOnly('fixed');
|
|
965
|
+
break;
|
|
966
|
+
case 'healthy':
|
|
967
|
+
showOnly('healthy');
|
|
968
|
+
break;
|
|
969
|
+
case 'not_fixed':
|
|
970
|
+
showOnly('notfixed');
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
function showDiagnosis(data) {
|
|
976
|
+
diagnosisData = data;
|
|
977
|
+
const confidence = Math.round((data.confidence || 0.5) * 100);
|
|
978
|
+
const options = data.options || [];
|
|
979
|
+
const round = data.round || 1;
|
|
980
|
+
|
|
981
|
+
// Render reasoning as clean list
|
|
982
|
+
const reasoningLog = $('reasoning-log');
|
|
983
|
+
reasoningLog.innerHTML = '';
|
|
984
|
+
const reasoning = data.reasoning || [];
|
|
985
|
+
if (reasoning.length > 0) {
|
|
986
|
+
reasoning.forEach(function(r, i) {
|
|
987
|
+
const line = document.createElement('div');
|
|
988
|
+
line.style.cssText = 'padding:6px 0; font-size:13px; color:#3c4043; border-bottom:1px solid #f1f3f4;';
|
|
989
|
+
line.textContent = (i+1) + '. ' + r;
|
|
990
|
+
reasoningLog.appendChild(line);
|
|
991
|
+
});
|
|
992
|
+
} else {
|
|
993
|
+
reasoningLog.textContent = 'No reasoning details available.';
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Update diagnosis card
|
|
997
|
+
$('diag-text').textContent = data.diagnosis || '';
|
|
998
|
+
$('root-cause-box').textContent = '🎯 ' + (data.rootCause || 'Unknown root cause');
|
|
999
|
+
$('confidence-fill').style.width = confidence + '%';
|
|
1000
|
+
$('confidence-label').textContent = 'Confidence: ' + confidence + '%';
|
|
1001
|
+
|
|
1002
|
+
// Round badge
|
|
1003
|
+
if (round > 1) {
|
|
1004
|
+
$('round-badge-diag').style.display = 'inline-flex';
|
|
1005
|
+
$('round-badge-text').textContent = 'Round ' + round + ' — new approach';
|
|
1006
|
+
$('round-badge-opts').style.display = 'inline-flex';
|
|
1007
|
+
$('round-opts-text').textContent = 'Round ' + round + ' — new approach';
|
|
1008
|
+
} else {
|
|
1009
|
+
$('round-badge-diag').style.display = 'none';
|
|
1010
|
+
$('round-badge-opts').style.display = 'none';
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Alternatives
|
|
1014
|
+
const alts = data.alternativeHypotheses || [];
|
|
1015
|
+
if (alts.length > 0) {
|
|
1016
|
+
$('alternatives-section').style.display = 'block';
|
|
1017
|
+
const altList = $('alt-list');
|
|
1018
|
+
altList.innerHTML = '';
|
|
1019
|
+
alts.forEach(alt => {
|
|
1020
|
+
const li = document.createElement('li');
|
|
1021
|
+
li.textContent = alt;
|
|
1022
|
+
altList.appendChild(li);
|
|
1023
|
+
});
|
|
1024
|
+
} else {
|
|
1025
|
+
$('alternatives-section').style.display = 'none';
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Show diagnosis card
|
|
1029
|
+
showOnly('diagnosis');
|
|
1030
|
+
|
|
1031
|
+
// Auto-check if we should show options too immediately
|
|
1032
|
+
const recommended = options.filter(o => o.recommended);
|
|
1033
|
+
const canAutoExecute = recommended.length > 0 && recommended.every(o => o.autoExecute);
|
|
1034
|
+
|
|
1035
|
+
if (canAutoExecute) {
|
|
1036
|
+
// Store recommended option for result page
|
|
1037
|
+
chosenOption = recommended[0] || null;
|
|
1038
|
+
// Auto-execute: show diagnosis briefly, then trigger fix
|
|
1039
|
+
setTimeout(function() {
|
|
1040
|
+
fetch('/api/fix', {
|
|
1041
|
+
method: 'POST',
|
|
1042
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1043
|
+
body: JSON.stringify({ sessionId: sessionId }),
|
|
1044
|
+
});
|
|
1045
|
+
}, 1200);
|
|
1046
|
+
} else if (options.length > 0) {
|
|
1047
|
+
// Render option cards and switch to options section
|
|
1048
|
+
renderOptions(options);
|
|
1049
|
+
// Show diagnosis briefly then switch to options after 1s
|
|
1050
|
+
setTimeout(() => showOnly('options'), 3000);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
function renderOptions(options) {
|
|
1055
|
+
const list = $('options-list');
|
|
1056
|
+
list.innerHTML = '';
|
|
1057
|
+
|
|
1058
|
+
options.forEach(opt => {
|
|
1059
|
+
const card = document.createElement('div');
|
|
1060
|
+
card.className = 'option-card' + (opt.recommended ? ' recommended' : '');
|
|
1061
|
+
|
|
1062
|
+
const riskClass = 'risk-' + (opt.risk || 'low');
|
|
1063
|
+
|
|
1064
|
+
card.innerHTML = `
|
|
1065
|
+
<div class="option-card-header">
|
|
1066
|
+
<div class="option-letter">${escHtml(opt.id)}</div>
|
|
1067
|
+
<div class="option-title-row">
|
|
1068
|
+
<span class="option-title">${escHtml(opt.title)}</span>
|
|
1069
|
+
${opt.recommended ? '<span class="recommended-badge">★ Recommended</span>' : ''}
|
|
1070
|
+
<span class="risk-badge ${riskClass}">${escHtml(opt.risk)}</span>
|
|
1071
|
+
</div>
|
|
1072
|
+
</div>
|
|
1073
|
+
<div class="option-description">${escHtml(opt.description)}</div>
|
|
1074
|
+
<button class="option-fix-btn" data-option-id="${escHtml(opt.id)}">
|
|
1075
|
+
🔧 Fix with this option
|
|
1076
|
+
</button>
|
|
1077
|
+
`;
|
|
1078
|
+
|
|
1079
|
+
list.appendChild(card);
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
// Attach click handlers
|
|
1083
|
+
list.querySelectorAll('.option-fix-btn').forEach(btn => {
|
|
1084
|
+
btn.addEventListener('click', async function() {
|
|
1085
|
+
const optionId = this.dataset.optionId;
|
|
1086
|
+
// Store chosen option for result page
|
|
1087
|
+
chosenOption = (diagnosisData && diagnosisData.options) ? diagnosisData.options.find(o => o.id === optionId) || diagnosisData.options.find(o => o.recommended) : null;
|
|
1088
|
+
// Disable all buttons
|
|
1089
|
+
list.querySelectorAll('.option-fix-btn').forEach(b => { b.disabled = true; });
|
|
1090
|
+
|
|
1091
|
+
$('exec-log').textContent = '';
|
|
1092
|
+
appendLog('exec-log', '🔧 Starting repair: Option ' + optionId + '...', 'meta');
|
|
1093
|
+
showOnly('autofix');
|
|
1094
|
+
|
|
1095
|
+
try {
|
|
1096
|
+
await fetch('/api/fix', {
|
|
1097
|
+
method: 'POST',
|
|
1098
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1099
|
+
body: JSON.stringify({ sessionId, optionId }),
|
|
1100
|
+
});
|
|
1101
|
+
} catch(e) {
|
|
1102
|
+
appendLog('exec-log', '❌ Failed to start fix: ' + e.message, 'error');
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function showApiKeyInput(data) {
|
|
1109
|
+
if (data.instructions) $('apikey-instructions').textContent = data.instructions;
|
|
1110
|
+
showOnly('apikey');
|
|
1111
|
+
$('apikey-input').focus();
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
function handleComplete(data) {
|
|
1115
|
+
if (eventSource) {
|
|
1116
|
+
eventSource.close();
|
|
1117
|
+
eventSource = null;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (data.healthy) {
|
|
1121
|
+
$('healthy-explanation').textContent = data.explanation || 'Your system is running normally. No issues detected.';
|
|
1122
|
+
// Show reasoning if any
|
|
1123
|
+
const reasoning = data.reasoning || [];
|
|
1124
|
+
if (reasoning.length > 0) {
|
|
1125
|
+
$('healthy-reasoning').style.display = 'block';
|
|
1126
|
+
const list = $('healthy-reasoning-list');
|
|
1127
|
+
list.innerHTML = '';
|
|
1128
|
+
reasoning.forEach(function(r, i) {
|
|
1129
|
+
const div = document.createElement('div');
|
|
1130
|
+
div.style.cssText = 'padding:4px 0; font-size:13px; color:#5f6368;';
|
|
1131
|
+
div.textContent = (i+1) + '. ' + r;
|
|
1132
|
+
list.appendChild(div);
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
// Show warnings if any
|
|
1136
|
+
const warnings = data.warnings || [];
|
|
1137
|
+
if (warnings.length > 0) {
|
|
1138
|
+
$('healthy-warnings').style.display = 'block';
|
|
1139
|
+
const list = $('healthy-warnings-list');
|
|
1140
|
+
list.innerHTML = '';
|
|
1141
|
+
warnings.forEach(function(w) {
|
|
1142
|
+
const li = document.createElement('li');
|
|
1143
|
+
li.style.cssText = 'font-size:13px; color:#5f6368; padding:6px 10px; background:#fef7e0; border-radius:6px; margin-bottom:6px; line-height:1.4;';
|
|
1144
|
+
li.textContent = w;
|
|
1145
|
+
list.appendChild(li);
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
showOnly('healthy');
|
|
1149
|
+
} else if (data.fixed) {
|
|
1150
|
+
// Populate result summary
|
|
1151
|
+
const wrongEl = $('fixed-what-wrong');
|
|
1152
|
+
const fixedEl = $('fixed-what-fixed');
|
|
1153
|
+
if (wrongEl) wrongEl.textContent = (diagnosisData && diagnosisData.diagnosis) || data.explanation || 'An issue was detected and resolved.';
|
|
1154
|
+
if (fixedEl && chosenOption) {
|
|
1155
|
+
fixedEl.innerHTML = '<strong>' + chosenOption.title + '</strong><br><span style="color:#5f6368">' + (chosenOption.description || '') + '</span>';
|
|
1156
|
+
} else if (fixedEl) {
|
|
1157
|
+
fixedEl.textContent = data.explanation || 'OpenClaw has been repaired!';
|
|
1158
|
+
}
|
|
1159
|
+
$('fixed-explanation').textContent = data.explanation || 'OpenClaw has been repaired!';
|
|
1160
|
+
showOnly('fixed');
|
|
1161
|
+
} else {
|
|
1162
|
+
$('notfixed-explanation').textContent = data.explanation || 'Could not automatically fix the issue.';
|
|
1163
|
+
if (data.diagnosticReport) $('report-area').textContent = data.diagnosticReport;
|
|
1164
|
+
showOnly('notfixed');
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function escHtml(str) {
|
|
1169
|
+
return String(str)
|
|
1170
|
+
.replace(/&/g, '&')
|
|
1171
|
+
.replace(/</g, '<')
|
|
1172
|
+
.replace(/>/g, '>')
|
|
1173
|
+
.replace(/"/g, '"');
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// API key submit
|
|
1177
|
+
$('btn-submit-key').addEventListener('click', async function() {
|
|
1178
|
+
const key = $('apikey-input').value.trim();
|
|
1179
|
+
if (!key) {
|
|
1180
|
+
$('apikey-input').focus();
|
|
1181
|
+
$('apikey-input').style.borderColor = '#c5221f';
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
$('apikey-input').style.borderColor = '';
|
|
1186
|
+
this.disabled = true;
|
|
1187
|
+
this.textContent = 'Starting...';
|
|
1188
|
+
|
|
1189
|
+
showOnly('scanning');
|
|
1190
|
+
$('log-area').textContent = '';
|
|
1191
|
+
$('scan-status-text').textContent = 'Initializing with API key...';
|
|
1192
|
+
|
|
1193
|
+
try {
|
|
1194
|
+
await fetch('/api/input', {
|
|
1195
|
+
method: 'POST',
|
|
1196
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1197
|
+
body: JSON.stringify({ sessionId, field: 'apiKey', value: key }),
|
|
1198
|
+
});
|
|
1199
|
+
} catch(e) {
|
|
1200
|
+
showOnly('apikey');
|
|
1201
|
+
this.disabled = false;
|
|
1202
|
+
this.textContent = 'Start Diagnosis';
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
$('apikey-input').addEventListener('keydown', function(e) {
|
|
1207
|
+
if (e.key === 'Enter') $('btn-submit-key').click();
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
$('btn-copy-report').addEventListener('click', function() {
|
|
1211
|
+
const text = $('report-area').textContent;
|
|
1212
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
1213
|
+
this.textContent = 'Copied!';
|
|
1214
|
+
setTimeout(() => { this.textContent = 'Copy'; }, 2000);
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
// Privacy notice — start scan on button click
|
|
1219
|
+
$('btn-start-scan').addEventListener('click', function() {
|
|
1220
|
+
startDiagnosis();
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
})();
|
|
1224
|
+
</script>
|
|
1225
|
+
</body>
|
|
1226
|
+
</html>
|