codetrap 0.1.5 → 0.1.7

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.
@@ -0,0 +1,528 @@
1
+ import { webClientScript } from "./client-script";
2
+
3
+ export const WEB_INDEX_HTML = `<!doctype html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <title>codetrap review console</title>
9
+ <style>
10
+ :root {
11
+ color-scheme: light;
12
+ --bg: #f3f6f2;
13
+ --panel: #f8faf7;
14
+ --panel-2: #fcfdfb;
15
+ --surface: #ffffff;
16
+ --surface-hover: #edf3ef;
17
+ --line: #d6dfd9;
18
+ --line-soft: #e5ebe6;
19
+ --text: #20231f;
20
+ --muted: #657069;
21
+ --faint: #8b968e;
22
+ --accent: #0f766e;
23
+ --accent-soft: #d9f1eb;
24
+ --accent-strong: #064e46;
25
+ --ink: #1f2937;
26
+ --violet: #4f46e5;
27
+ --violet-soft: #e6e8ff;
28
+ --danger: #b42318;
29
+ --warn: #9a6700;
30
+ --ok: #18794e;
31
+ --shadow: rgba(28, 39, 32, 0.08);
32
+ }
33
+
34
+ * { box-sizing: border-box; }
35
+ html, body { height: 100%; }
36
+ body {
37
+ margin: 0;
38
+ background:
39
+ linear-gradient(120deg, rgba(15, 118, 110, 0.08), transparent 34%),
40
+ linear-gradient(180deg, #fbfcf8 0%, var(--bg) 48%, #eef3ef 100%);
41
+ color: var(--text);
42
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
43
+ letter-spacing: 0;
44
+ -webkit-font-smoothing: antialiased;
45
+ }
46
+
47
+ button, input, select, textarea {
48
+ font: inherit;
49
+ letter-spacing: 0;
50
+ }
51
+
52
+ button {
53
+ border: 1px solid var(--line);
54
+ background: var(--surface);
55
+ color: var(--text);
56
+ min-height: 32px;
57
+ padding: 0 12px;
58
+ border-radius: 8px;
59
+ cursor: pointer;
60
+ box-shadow: 0 1px 2px var(--shadow);
61
+ }
62
+
63
+ button:hover { background: var(--surface-hover); border-color: #c9c1b4; }
64
+ button.primary { background: var(--ink); color: #fffdf8; border-color: var(--ink); }
65
+ button.danger { border-color: color-mix(in srgb, var(--danger), var(--line) 35%); color: var(--danger); }
66
+ button.ghost { background: transparent; }
67
+ button:disabled { color: var(--faint); border-color: var(--line); cursor: not-allowed; opacity: 0.62; }
68
+
69
+ .segmented {
70
+ display: inline-flex;
71
+ align-items: center;
72
+ gap: 2px;
73
+ padding: 3px;
74
+ border: 1px solid var(--line);
75
+ border-radius: 9px;
76
+ background: rgba(255, 255, 255, 0.58);
77
+ box-shadow: 0 1px 2px var(--shadow);
78
+ }
79
+
80
+ .segmented button {
81
+ min-height: 26px;
82
+ padding: 0 9px;
83
+ border: 0;
84
+ border-radius: 6px;
85
+ background: transparent;
86
+ color: var(--muted);
87
+ box-shadow: none;
88
+ font-size: 12px;
89
+ }
90
+
91
+ .segmented button.active {
92
+ background: var(--text);
93
+ color: #fffdf8;
94
+ }
95
+
96
+ input, select, textarea {
97
+ width: 100%;
98
+ border: 1px solid var(--line);
99
+ background: #fffdf8;
100
+ color: var(--text);
101
+ border-radius: 8px;
102
+ padding: 8px 9px;
103
+ outline: none;
104
+ }
105
+
106
+ textarea {
107
+ min-height: 104px;
108
+ resize: vertical;
109
+ line-height: 1.45;
110
+ }
111
+
112
+ input:focus, select:focus, textarea:focus {
113
+ border-color: var(--accent);
114
+ box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
115
+ }
116
+
117
+ .shell {
118
+ height: 100%;
119
+ display: grid;
120
+ grid-template-columns: minmax(250px, 0.82fr) minmax(320px, 1fr) minmax(460px, 1.48fr);
121
+ gap: 0;
122
+ overflow: hidden;
123
+ }
124
+
125
+ .rail, .queue, .detail {
126
+ min-height: 0;
127
+ border-right: 1px solid var(--line-soft);
128
+ background: color-mix(in srgb, var(--panel), transparent 8%);
129
+ display: flex;
130
+ flex-direction: column;
131
+ backdrop-filter: blur(12px);
132
+ }
133
+
134
+ .detail { border-right: 0; background: var(--panel-2); }
135
+
136
+ .bar {
137
+ min-height: 56px;
138
+ padding: 12px 14px;
139
+ border-bottom: 1px solid var(--line-soft);
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: space-between;
143
+ gap: 10px;
144
+ }
145
+
146
+ .rail-actions {
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: flex-end;
150
+ gap: 8px;
151
+ flex-wrap: wrap;
152
+ }
153
+
154
+ .title {
155
+ font-weight: 650;
156
+ text-transform: none;
157
+ font-size: 13px;
158
+ color: var(--text);
159
+ }
160
+
161
+ .subtle { color: var(--muted); font-size: 12px; min-width: 0; overflow-wrap: anywhere; }
162
+ .scroll { overflow: auto; min-height: 0; }
163
+ .stack { display: grid; gap: 10px; padding: 12px; }
164
+
165
+ .project-form {
166
+ display: grid;
167
+ grid-template-columns: 1fr auto;
168
+ gap: 8px;
169
+ padding: 12px;
170
+ border-bottom: 1px solid var(--line-soft);
171
+ }
172
+
173
+ .row {
174
+ width: 100%;
175
+ text-align: left;
176
+ display: grid;
177
+ gap: 5px;
178
+ padding: 10px;
179
+ border: 1px solid var(--line);
180
+ border-radius: 8px;
181
+ background: rgba(255, 255, 255, 0.72);
182
+ overflow: hidden;
183
+ box-shadow: 0 1px 2px var(--shadow);
184
+ }
185
+
186
+ .row:hover { background: #fffdf8; border-color: #cfc7ba; }
187
+ .row.active { border-color: color-mix(in srgb, var(--accent), var(--line) 28%); background: #ffffff; box-shadow: inset 3px 0 0 var(--accent), 0 8px 28px var(--shadow); }
188
+ .row.accepted { border-color: color-mix(in srgb, var(--ok), var(--line) 55%); }
189
+ .row.accepted-missing { border-color: color-mix(in srgb, var(--warn), var(--line) 40%); }
190
+ .row.rejected { border-color: color-mix(in srgb, var(--danger), var(--line) 55%); opacity: 0.72; }
191
+ .row-main {
192
+ width: 100%;
193
+ min-height: 0;
194
+ padding: 0;
195
+ border: 0;
196
+ border-radius: 0;
197
+ background: transparent;
198
+ box-shadow: none;
199
+ text-align: left;
200
+ display: grid;
201
+ gap: 5px;
202
+ color: inherit;
203
+ }
204
+ .row-main:hover { background: transparent; border-color: transparent; }
205
+ .row-action {
206
+ justify-self: start;
207
+ min-height: 28px;
208
+ font-size: 12px;
209
+ box-shadow: none;
210
+ }
211
+ .row-title { overflow-wrap: anywhere; }
212
+ .meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
213
+
214
+ .pill {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ min-height: 22px;
218
+ border: 1px solid var(--line);
219
+ border-radius: 999px;
220
+ padding: 2px 8px;
221
+ color: var(--muted);
222
+ font-size: 11px;
223
+ white-space: nowrap;
224
+ }
225
+
226
+ .pill.proposed { color: var(--accent-strong); background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent), var(--line) 55%); }
227
+ .pill.accepted { color: var(--ok); border-color: color-mix(in srgb, var(--ok), var(--line) 55%); }
228
+ .pill.accepted-missing { color: var(--warn); border-color: color-mix(in srgb, var(--warn), var(--line) 55%); }
229
+ .pill.rejected { color: var(--danger); border-color: color-mix(in srgb, var(--danger), var(--line) 55%); }
230
+ .pill.warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn), var(--line) 55%); }
231
+ .pill.scope { color: var(--violet); background: var(--violet-soft); border-color: color-mix(in srgb, var(--violet), var(--line) 55%); }
232
+ .pill.critical { color: var(--danger); border-color: color-mix(in srgb, var(--danger), var(--line) 42%); }
233
+ .pill.error { color: var(--warn); border-color: color-mix(in srgb, var(--warn), var(--line) 42%); }
234
+
235
+ .detail-body {
236
+ display: grid;
237
+ grid-template-rows: auto 1fr auto;
238
+ min-height: 0;
239
+ height: 100%;
240
+ }
241
+
242
+ .form-grid {
243
+ display: grid;
244
+ grid-template-columns: repeat(2, minmax(0, 1fr));
245
+ gap: 10px;
246
+ }
247
+
248
+ .field { display: grid; gap: 5px; }
249
+ .field.full { grid-column: 1 / -1; }
250
+ label { color: var(--muted); font-size: 11px; text-transform: uppercase; }
251
+
252
+ .library-tools {
253
+ display: grid;
254
+ gap: 10px;
255
+ padding: 12px;
256
+ border-bottom: 1px solid var(--line-soft);
257
+ background: rgba(255, 255, 255, 0.54);
258
+ }
259
+
260
+ .filter-grid {
261
+ display: grid;
262
+ grid-template-columns: repeat(2, minmax(0, 1fr));
263
+ gap: 8px;
264
+ }
265
+
266
+ .filter-grid .wide { grid-column: 1 / -1; }
267
+
268
+ .summary-grid {
269
+ display: grid;
270
+ grid-template-columns: repeat(2, minmax(0, 1fr));
271
+ gap: 8px;
272
+ padding: 12px;
273
+ border-bottom: 1px solid var(--line-soft);
274
+ }
275
+
276
+ .metric {
277
+ border: 1px solid var(--line);
278
+ border-radius: 8px;
279
+ padding: 10px;
280
+ background: rgba(255, 255, 255, 0.72);
281
+ min-height: 74px;
282
+ display: grid;
283
+ align-content: space-between;
284
+ gap: 6px;
285
+ }
286
+
287
+ .metric-value {
288
+ font-size: 21px;
289
+ line-height: 1;
290
+ font-weight: 720;
291
+ color: var(--text);
292
+ overflow-wrap: anywhere;
293
+ }
294
+
295
+ .metric-label {
296
+ color: var(--muted);
297
+ font-size: 11px;
298
+ text-transform: uppercase;
299
+ }
300
+
301
+ .insight-grid {
302
+ display: grid;
303
+ gap: 10px;
304
+ padding: 12px;
305
+ }
306
+
307
+ .insight-block {
308
+ border-top: 1px solid var(--line-soft);
309
+ padding-top: 10px;
310
+ display: grid;
311
+ gap: 8px;
312
+ }
313
+
314
+ .rank-list {
315
+ display: grid;
316
+ gap: 7px;
317
+ }
318
+
319
+ .rank-row {
320
+ display: grid;
321
+ grid-template-columns: minmax(0, 1fr) auto;
322
+ gap: 8px;
323
+ align-items: center;
324
+ font-size: 13px;
325
+ }
326
+
327
+ .rank-label { overflow-wrap: anywhere; }
328
+ .rank-count { color: var(--muted); font-size: 12px; }
329
+
330
+ .bar-track {
331
+ grid-column: 1 / -1;
332
+ height: 5px;
333
+ border-radius: 999px;
334
+ background: var(--line-soft);
335
+ overflow: hidden;
336
+ }
337
+
338
+ .bar-fill {
339
+ height: 100%;
340
+ border-radius: inherit;
341
+ background: var(--accent);
342
+ }
343
+
344
+ .trap-rows {
345
+ display: grid;
346
+ gap: 10px;
347
+ padding: 12px;
348
+ }
349
+
350
+ .text-block {
351
+ display: grid;
352
+ gap: 6px;
353
+ }
354
+
355
+ .text-block .content {
356
+ white-space: pre-wrap;
357
+ line-height: 1.48;
358
+ overflow-wrap: anywhere;
359
+ }
360
+
361
+ .code-block {
362
+ margin: 0;
363
+ border: 1px solid var(--line);
364
+ border-radius: 8px;
365
+ padding: 10px;
366
+ background: #17201d;
367
+ color: #eef6f0;
368
+ overflow: auto;
369
+ line-height: 1.45;
370
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
371
+ font-size: 12px;
372
+ }
373
+
374
+ .detail-kv {
375
+ display: grid;
376
+ grid-template-columns: repeat(2, minmax(0, 1fr));
377
+ gap: 8px;
378
+ }
379
+
380
+ .kv {
381
+ border: 1px solid var(--line);
382
+ border-radius: 8px;
383
+ padding: 9px;
384
+ background: rgba(255, 255, 255, 0.62);
385
+ overflow-wrap: anywhere;
386
+ }
387
+
388
+ .kv-label {
389
+ color: var(--muted);
390
+ font-size: 11px;
391
+ text-transform: uppercase;
392
+ margin-bottom: 4px;
393
+ }
394
+
395
+ .kv-value { font-size: 13px; }
396
+
397
+ .hidden { display: none !important; }
398
+
399
+ .section {
400
+ border-top: 1px solid var(--line-soft);
401
+ padding: 12px;
402
+ display: grid;
403
+ gap: 10px;
404
+ }
405
+
406
+ .evidence, .warning, .conflict {
407
+ border: 1px solid var(--line);
408
+ border-radius: 8px;
409
+ padding: 10px;
410
+ background: rgba(255, 255, 255, 0.68);
411
+ overflow-wrap: anywhere;
412
+ }
413
+
414
+ .warning { border-color: color-mix(in srgb, var(--warn), var(--line) 50%); color: var(--warn); }
415
+ .conflict { border-color: color-mix(in srgb, var(--danger), var(--line) 45%); }
416
+ .review-note { border-color: color-mix(in srgb, var(--accent), var(--line) 55%); }
417
+ .actions {
418
+ padding: 12px;
419
+ border-top: 1px solid var(--line-soft);
420
+ display: flex;
421
+ gap: 8px;
422
+ flex-wrap: wrap;
423
+ background: rgba(255, 255, 255, 0.018);
424
+ }
425
+
426
+ .empty {
427
+ padding: 28px 18px;
428
+ color: var(--muted);
429
+ text-align: center;
430
+ }
431
+
432
+ .status {
433
+ position: fixed;
434
+ right: 14px;
435
+ bottom: 14px;
436
+ max-width: 520px;
437
+ border: 1px solid var(--line);
438
+ background: #fffdf8;
439
+ color: var(--text);
440
+ border-radius: 8px;
441
+ padding: 10px 12px;
442
+ box-shadow: 0 12px 40px var(--shadow);
443
+ display: none;
444
+ z-index: 20;
445
+ }
446
+
447
+ .status.show { display: block; }
448
+ .status.error { border-color: var(--danger); color: var(--danger); }
449
+
450
+ @media (max-width: 1060px) {
451
+ .shell { grid-template-columns: 1fr; overflow: auto; }
452
+ .rail { min-height: auto; border-right: 0; border-bottom: 1px solid var(--line); }
453
+ .queue, .detail { min-height: 520px; border-right: 0; border-bottom: 1px solid var(--line); }
454
+ }
455
+
456
+ @media (max-width: 520px) {
457
+ .bar { align-items: flex-start; flex-direction: column; }
458
+ .rail-actions { justify-content: flex-start; }
459
+ .filter-grid, .summary-grid, .detail-kv { grid-template-columns: 1fr; }
460
+ .project-form { grid-template-columns: 1fr auto; }
461
+ }
462
+ </style>
463
+ </head>
464
+ <body>
465
+ <main class="shell">
466
+ <aside class="rail">
467
+ <div class="bar">
468
+ <div>
469
+ <div class="title">codetrap</div>
470
+ <div class="subtle" id="app-subtitle">review console</div>
471
+ </div>
472
+ <div class="rail-actions">
473
+ <div class="segmented" aria-label="Main view">
474
+ <button type="button" class="active" data-main-view="review">Review</button>
475
+ <button type="button" data-main-view="library">Library</button>
476
+ <button type="button" data-main-view="insights">Insights</button>
477
+ </div>
478
+ <div class="segmented" aria-label="Language">
479
+ <button type="button" data-locale="en">EN</button>
480
+ <button type="button" data-locale="zh">中文</button>
481
+ </div>
482
+ <button class="ghost" id="refresh" title="Refresh">Refresh</button>
483
+ </div>
484
+ </div>
485
+ <form class="project-form" id="project-form">
486
+ <input id="project-path" placeholder="/path/to/project">
487
+ <button type="submit" id="project-add">Add</button>
488
+ </form>
489
+ <div class="scroll">
490
+ <div class="stack" id="projects"></div>
491
+ <div class="section">
492
+ <div class="title" id="sessions-title">sessions</div>
493
+ <div id="sessions" class="stack" style="padding:0"></div>
494
+ </div>
495
+ </div>
496
+ </aside>
497
+
498
+ <section class="queue">
499
+ <div class="bar">
500
+ <div>
501
+ <div class="title" id="queue-title">candidate inbox</div>
502
+ <div class="subtle" id="queue-meta">no project selected</div>
503
+ </div>
504
+ <div class="segmented" id="candidate-tabs" aria-label="Candidate view">
505
+ <button type="button" class="active" data-candidate-view="inbox">Inbox</button>
506
+ <button type="button" data-candidate-view="reviewed">Reviewed</button>
507
+ </div>
508
+ </div>
509
+ <div class="scroll">
510
+ <div class="stack" id="candidates"></div>
511
+ </div>
512
+ </section>
513
+
514
+ <section class="detail">
515
+ <div class="bar">
516
+ <div>
517
+ <div class="title" id="detail-title">candidate detail</div>
518
+ <div class="subtle" id="detail-meta">select a candidate</div>
519
+ </div>
520
+ </div>
521
+ <div class="detail-body" id="detail"></div>
522
+ </section>
523
+ </main>
524
+ <div class="status" id="status"></div>
525
+
526
+ <script>${webClientScript()}</script>
527
+ </body>
528
+ </html>`;