harper-knowledge 0.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +276 -0
  3. package/config.yaml +17 -0
  4. package/dist/core/embeddings.d.ts +29 -0
  5. package/dist/core/embeddings.js +199 -0
  6. package/dist/core/entries.d.ts +85 -0
  7. package/dist/core/entries.js +235 -0
  8. package/dist/core/history.d.ts +30 -0
  9. package/dist/core/history.js +119 -0
  10. package/dist/core/search.d.ts +23 -0
  11. package/dist/core/search.js +306 -0
  12. package/dist/core/tags.d.ts +32 -0
  13. package/dist/core/tags.js +76 -0
  14. package/dist/core/triage.d.ts +55 -0
  15. package/dist/core/triage.js +126 -0
  16. package/dist/http-utils.d.ts +37 -0
  17. package/dist/http-utils.js +132 -0
  18. package/dist/index.d.ts +21 -0
  19. package/dist/index.js +76 -0
  20. package/dist/mcp/server.d.ts +24 -0
  21. package/dist/mcp/server.js +124 -0
  22. package/dist/mcp/tools.d.ts +13 -0
  23. package/dist/mcp/tools.js +497 -0
  24. package/dist/oauth/authorize.d.ts +27 -0
  25. package/dist/oauth/authorize.js +438 -0
  26. package/dist/oauth/github.d.ts +28 -0
  27. package/dist/oauth/github.js +62 -0
  28. package/dist/oauth/keys.d.ts +33 -0
  29. package/dist/oauth/keys.js +100 -0
  30. package/dist/oauth/metadata.d.ts +21 -0
  31. package/dist/oauth/metadata.js +55 -0
  32. package/dist/oauth/middleware.d.ts +22 -0
  33. package/dist/oauth/middleware.js +64 -0
  34. package/dist/oauth/register.d.ts +14 -0
  35. package/dist/oauth/register.js +83 -0
  36. package/dist/oauth/token.d.ts +15 -0
  37. package/dist/oauth/token.js +178 -0
  38. package/dist/oauth/validate.d.ts +30 -0
  39. package/dist/oauth/validate.js +52 -0
  40. package/dist/resources/HistoryResource.d.ts +38 -0
  41. package/dist/resources/HistoryResource.js +38 -0
  42. package/dist/resources/KnowledgeEntryResource.d.ts +64 -0
  43. package/dist/resources/KnowledgeEntryResource.js +157 -0
  44. package/dist/resources/QueryLogResource.d.ts +20 -0
  45. package/dist/resources/QueryLogResource.js +57 -0
  46. package/dist/resources/ServiceKeyResource.d.ts +51 -0
  47. package/dist/resources/ServiceKeyResource.js +132 -0
  48. package/dist/resources/TagResource.d.ts +25 -0
  49. package/dist/resources/TagResource.js +32 -0
  50. package/dist/resources/TriageResource.d.ts +51 -0
  51. package/dist/resources/TriageResource.js +107 -0
  52. package/dist/types.d.ts +317 -0
  53. package/dist/types.js +7 -0
  54. package/dist/webhooks/datadog.d.ts +26 -0
  55. package/dist/webhooks/datadog.js +120 -0
  56. package/dist/webhooks/github.d.ts +24 -0
  57. package/dist/webhooks/github.js +167 -0
  58. package/dist/webhooks/middleware.d.ts +14 -0
  59. package/dist/webhooks/middleware.js +161 -0
  60. package/dist/webhooks/types.d.ts +17 -0
  61. package/dist/webhooks/types.js +4 -0
  62. package/package.json +72 -0
  63. package/schema/knowledge.graphql +134 -0
  64. package/web/index.html +735 -0
  65. package/web/js/app.js +461 -0
  66. package/web/js/detail.js +223 -0
  67. package/web/js/editor.js +303 -0
  68. package/web/js/search.js +238 -0
  69. package/web/js/triage.js +305 -0
package/web/index.html ADDED
@@ -0,0 +1,735 @@
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" />
6
+ <title>Harper Knowledge Base</title>
7
+ <style>
8
+ :root {
9
+ --bg: #1a1a2e;
10
+ --bg-surface: #222240;
11
+ --bg-raised: #2a2a4a;
12
+ --bg-input: #16162b;
13
+ --border: #3a3a5c;
14
+ --border-focus: #6c6ce0;
15
+ --text: #e0e0f0;
16
+ --text-dim: #8888aa;
17
+ --text-link: #8888ff;
18
+ --accent: #6c6ce0;
19
+ --accent-hover: #8484f0;
20
+ --green: #4ade80;
21
+ --green-bg: #1a3a2a;
22
+ --blue: #60a5fa;
23
+ --blue-bg: #1a2a3a;
24
+ --amber: #fbbf24;
25
+ --amber-bg: #3a2e1a;
26
+ --red: #f87171;
27
+ --red-bg: #3a1a1a;
28
+ --tag-bg: #2e2e50;
29
+ --tag-text: #b0b0d0;
30
+ --radius: 4px;
31
+ --radius-lg: 6px;
32
+ --font-mono:
33
+ "SF Mono", "Cascadia Code", "JetBrains Mono", "Fira Code", Menlo,
34
+ Consolas, monospace;
35
+ --font-system:
36
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
37
+ sans-serif;
38
+ }
39
+
40
+ * {
41
+ margin: 0;
42
+ padding: 0;
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ html,
47
+ body {
48
+ height: 100%;
49
+ background: var(--bg);
50
+ color: var(--text);
51
+ font-family: var(--font-system);
52
+ font-size: 14px;
53
+ line-height: 1.6;
54
+ }
55
+
56
+ a {
57
+ color: var(--text-link);
58
+ text-decoration: none;
59
+ }
60
+ a:hover {
61
+ text-decoration: underline;
62
+ }
63
+
64
+ /* Layout */
65
+ #app {
66
+ display: flex;
67
+ flex-direction: column;
68
+ min-height: 100vh;
69
+ }
70
+
71
+ header {
72
+ background: var(--bg-surface);
73
+ border-bottom: 1px solid var(--border);
74
+ padding: 0 24px;
75
+ display: flex;
76
+ align-items: center;
77
+ height: 52px;
78
+ flex-shrink: 0;
79
+ }
80
+
81
+ header .logo {
82
+ font-family: var(--font-mono);
83
+ font-size: 15px;
84
+ font-weight: 600;
85
+ color: var(--text);
86
+ margin-right: 32px;
87
+ letter-spacing: -0.5px;
88
+ }
89
+
90
+ header .logo span {
91
+ color: var(--accent);
92
+ }
93
+
94
+ nav {
95
+ display: flex;
96
+ gap: 4px;
97
+ }
98
+
99
+ nav a {
100
+ padding: 6px 14px;
101
+ border-radius: var(--radius);
102
+ color: var(--text-dim);
103
+ font-size: 13px;
104
+ font-weight: 500;
105
+ transition:
106
+ background 0.15s,
107
+ color 0.15s;
108
+ }
109
+
110
+ nav a:hover {
111
+ background: var(--bg-raised);
112
+ color: var(--text);
113
+ text-decoration: none;
114
+ }
115
+
116
+ nav a.active {
117
+ background: var(--accent);
118
+ color: #fff;
119
+ }
120
+
121
+ .header-right {
122
+ margin-left: auto;
123
+ display: flex;
124
+ align-items: center;
125
+ gap: 12px;
126
+ }
127
+
128
+ .auth-status {
129
+ font-size: 12px;
130
+ color: var(--text-dim);
131
+ font-family: var(--font-mono);
132
+ }
133
+
134
+ main {
135
+ flex: 1;
136
+ padding: 24px;
137
+ max-width: 1100px;
138
+ width: 100%;
139
+ margin: 0 auto;
140
+ }
141
+
142
+ /* Forms */
143
+ input[type="text"],
144
+ input[type="password"],
145
+ input[type="url"],
146
+ textarea,
147
+ select {
148
+ background: var(--bg-input);
149
+ border: 1px solid var(--border);
150
+ color: var(--text);
151
+ padding: 8px 10px;
152
+ border-radius: var(--radius);
153
+ font-size: 13px;
154
+ font-family: var(--font-system);
155
+ width: 100%;
156
+ outline: none;
157
+ transition: border-color 0.15s;
158
+ }
159
+
160
+ input:focus,
161
+ textarea:focus,
162
+ select:focus {
163
+ border-color: var(--border-focus);
164
+ }
165
+
166
+ textarea {
167
+ font-family: var(--font-mono);
168
+ font-size: 13px;
169
+ resize: vertical;
170
+ min-height: 200px;
171
+ }
172
+
173
+ label {
174
+ display: block;
175
+ font-size: 12px;
176
+ font-weight: 600;
177
+ color: var(--text-dim);
178
+ text-transform: uppercase;
179
+ letter-spacing: 0.5px;
180
+ margin-bottom: 4px;
181
+ }
182
+
183
+ .form-group {
184
+ margin-bottom: 16px;
185
+ }
186
+
187
+ .form-row {
188
+ display: grid;
189
+ grid-template-columns: 1fr 1fr;
190
+ gap: 16px;
191
+ }
192
+
193
+ .form-row-3 {
194
+ display: grid;
195
+ grid-template-columns: 1fr 1fr 1fr;
196
+ gap: 16px;
197
+ }
198
+
199
+ /* Buttons */
200
+ button,
201
+ .btn {
202
+ display: inline-flex;
203
+ align-items: center;
204
+ gap: 6px;
205
+ padding: 8px 16px;
206
+ border: 1px solid var(--border);
207
+ border-radius: var(--radius);
208
+ background: var(--bg-raised);
209
+ color: var(--text);
210
+ font-size: 13px;
211
+ font-weight: 500;
212
+ cursor: pointer;
213
+ transition:
214
+ background 0.15s,
215
+ border-color 0.15s;
216
+ }
217
+
218
+ button:hover,
219
+ .btn:hover {
220
+ background: var(--bg-surface);
221
+ border-color: var(--border-focus);
222
+ }
223
+
224
+ button.primary,
225
+ .btn-primary {
226
+ background: var(--accent);
227
+ border-color: var(--accent);
228
+ color: #fff;
229
+ }
230
+
231
+ button.primary:hover,
232
+ .btn-primary:hover {
233
+ background: var(--accent-hover);
234
+ border-color: var(--accent-hover);
235
+ }
236
+
237
+ button.danger {
238
+ color: var(--red);
239
+ border-color: var(--red);
240
+ }
241
+
242
+ button.danger:hover {
243
+ background: var(--red-bg);
244
+ }
245
+
246
+ button.success {
247
+ color: var(--green);
248
+ border-color: var(--green);
249
+ }
250
+
251
+ button.success:hover {
252
+ background: var(--green-bg);
253
+ }
254
+
255
+ button:disabled {
256
+ opacity: 0.5;
257
+ cursor: not-allowed;
258
+ }
259
+
260
+ /* Badges & chips */
261
+ .badge {
262
+ display: inline-block;
263
+ padding: 2px 8px;
264
+ border-radius: 10px;
265
+ font-size: 11px;
266
+ font-weight: 600;
267
+ font-family: var(--font-mono);
268
+ text-transform: uppercase;
269
+ letter-spacing: 0.3px;
270
+ }
271
+
272
+ .badge-verified {
273
+ background: var(--green-bg);
274
+ color: var(--green);
275
+ }
276
+ .badge-reviewed {
277
+ background: var(--blue-bg);
278
+ color: var(--blue);
279
+ }
280
+ .badge-ai-generated {
281
+ background: var(--amber-bg);
282
+ color: var(--amber);
283
+ }
284
+
285
+ .badge-pending {
286
+ background: var(--amber-bg);
287
+ color: var(--amber);
288
+ }
289
+ .badge-processing {
290
+ background: var(--blue-bg);
291
+ color: var(--blue);
292
+ }
293
+ .badge-accepted {
294
+ background: var(--green-bg);
295
+ color: var(--green);
296
+ }
297
+ .badge-dismissed {
298
+ background: var(--red-bg);
299
+ color: var(--red);
300
+ }
301
+
302
+ .tag {
303
+ display: inline-block;
304
+ padding: 2px 8px;
305
+ background: var(--tag-bg);
306
+ color: var(--tag-text);
307
+ border-radius: 10px;
308
+ font-size: 11px;
309
+ font-family: var(--font-mono);
310
+ cursor: pointer;
311
+ transition: background 0.15s;
312
+ }
313
+
314
+ .tag:hover {
315
+ background: var(--accent);
316
+ color: #fff;
317
+ }
318
+
319
+ .tag.active {
320
+ background: var(--accent);
321
+ color: #fff;
322
+ }
323
+
324
+ .tags {
325
+ display: flex;
326
+ flex-wrap: wrap;
327
+ gap: 4px;
328
+ }
329
+
330
+ /* Cards */
331
+ .card {
332
+ background: var(--bg-surface);
333
+ border: 1px solid var(--border);
334
+ border-radius: var(--radius-lg);
335
+ padding: 16px;
336
+ margin-bottom: 12px;
337
+ transition: border-color 0.15s;
338
+ }
339
+
340
+ .card:hover {
341
+ border-color: var(--border-focus);
342
+ }
343
+
344
+ .card-title {
345
+ font-size: 15px;
346
+ font-weight: 600;
347
+ margin-bottom: 6px;
348
+ }
349
+
350
+ .card-title a {
351
+ color: var(--text);
352
+ }
353
+
354
+ .card-title a:hover {
355
+ color: var(--text-link);
356
+ }
357
+
358
+ .card-snippet {
359
+ color: var(--text-dim);
360
+ font-size: 13px;
361
+ margin-bottom: 10px;
362
+ line-height: 1.5;
363
+ }
364
+
365
+ .card-meta {
366
+ display: flex;
367
+ align-items: center;
368
+ gap: 8px;
369
+ flex-wrap: wrap;
370
+ }
371
+
372
+ .card-meta .sep {
373
+ color: var(--border);
374
+ }
375
+
376
+ /* Detail view */
377
+ .detail-header {
378
+ margin-bottom: 20px;
379
+ }
380
+
381
+ .detail-title {
382
+ font-size: 22px;
383
+ font-weight: 700;
384
+ margin-bottom: 8px;
385
+ }
386
+
387
+ .detail-content {
388
+ background: var(--bg-surface);
389
+ border: 1px solid var(--border);
390
+ border-radius: var(--radius-lg);
391
+ padding: 20px;
392
+ margin-bottom: 20px;
393
+ font-family: var(--font-mono);
394
+ font-size: 13px;
395
+ white-space: pre-wrap;
396
+ word-wrap: break-word;
397
+ line-height: 1.7;
398
+ }
399
+
400
+ .detail-section {
401
+ margin-bottom: 20px;
402
+ }
403
+
404
+ .detail-section h3 {
405
+ font-size: 12px;
406
+ text-transform: uppercase;
407
+ letter-spacing: 0.5px;
408
+ color: var(--text-dim);
409
+ margin-bottom: 8px;
410
+ font-weight: 600;
411
+ }
412
+
413
+ .meta-grid {
414
+ display: grid;
415
+ grid-template-columns: 140px 1fr;
416
+ gap: 6px 16px;
417
+ font-size: 13px;
418
+ }
419
+
420
+ .meta-grid dt {
421
+ color: var(--text-dim);
422
+ font-weight: 500;
423
+ }
424
+
425
+ .meta-grid dd {
426
+ color: var(--text);
427
+ }
428
+
429
+ .entry-links {
430
+ display: flex;
431
+ flex-wrap: wrap;
432
+ gap: 6px;
433
+ }
434
+
435
+ .entry-link {
436
+ display: inline-block;
437
+ padding: 4px 10px;
438
+ background: var(--bg-raised);
439
+ border: 1px solid var(--border);
440
+ border-radius: var(--radius);
441
+ font-size: 12px;
442
+ font-family: var(--font-mono);
443
+ }
444
+
445
+ /* Collapsible */
446
+ .collapsible-header {
447
+ display: flex;
448
+ align-items: center;
449
+ gap: 8px;
450
+ cursor: pointer;
451
+ padding: 8px 0;
452
+ user-select: none;
453
+ font-size: 13px;
454
+ font-weight: 500;
455
+ color: var(--text-dim);
456
+ }
457
+
458
+ .collapsible-header:hover {
459
+ color: var(--text);
460
+ }
461
+
462
+ .collapsible-header .arrow {
463
+ transition: transform 0.15s;
464
+ font-size: 10px;
465
+ }
466
+
467
+ .collapsible-header.open .arrow {
468
+ transform: rotate(90deg);
469
+ }
470
+
471
+ .collapsible-body {
472
+ display: none;
473
+ padding: 8px 0;
474
+ }
475
+
476
+ .collapsible-body.open {
477
+ display: block;
478
+ }
479
+
480
+ /* JSON preview */
481
+ .json-preview {
482
+ background: var(--bg-input);
483
+ border: 1px solid var(--border);
484
+ border-radius: var(--radius);
485
+ padding: 12px;
486
+ font-family: var(--font-mono);
487
+ font-size: 12px;
488
+ max-height: 300px;
489
+ overflow: auto;
490
+ white-space: pre-wrap;
491
+ word-break: break-all;
492
+ }
493
+
494
+ /* Loading & empty states */
495
+ .loading {
496
+ text-align: center;
497
+ padding: 40px;
498
+ color: var(--text-dim);
499
+ }
500
+
501
+ .empty-state {
502
+ text-align: center;
503
+ padding: 60px 20px;
504
+ color: var(--text-dim);
505
+ }
506
+
507
+ .empty-state h2 {
508
+ font-size: 16px;
509
+ margin-bottom: 8px;
510
+ color: var(--text);
511
+ }
512
+
513
+ .empty-state p {
514
+ font-size: 13px;
515
+ }
516
+
517
+ /* Status messages */
518
+ .status-message {
519
+ padding: 10px 14px;
520
+ border-radius: var(--radius);
521
+ font-size: 13px;
522
+ margin-bottom: 16px;
523
+ }
524
+
525
+ .status-message.error {
526
+ background: var(--red-bg);
527
+ color: var(--red);
528
+ border: 1px solid var(--red);
529
+ }
530
+
531
+ .status-message.success {
532
+ background: var(--green-bg);
533
+ color: var(--green);
534
+ border: 1px solid var(--green);
535
+ }
536
+
537
+ /* Triage actions */
538
+ .triage-actions {
539
+ display: flex;
540
+ gap: 8px;
541
+ margin-top: 12px;
542
+ }
543
+
544
+ /* Search bar */
545
+ .search-bar {
546
+ display: flex;
547
+ gap: 8px;
548
+ margin-bottom: 16px;
549
+ }
550
+
551
+ .search-bar input {
552
+ flex: 1;
553
+ }
554
+
555
+ /* Inline form for triage link action */
556
+ .inline-form {
557
+ display: flex;
558
+ gap: 8px;
559
+ align-items: center;
560
+ margin-top: 8px;
561
+ }
562
+
563
+ .inline-form input {
564
+ width: 240px;
565
+ }
566
+
567
+ /* Deprecated overlay */
568
+ .deprecated {
569
+ opacity: 0.6;
570
+ position: relative;
571
+ }
572
+
573
+ .deprecated::after {
574
+ content: "DEPRECATED";
575
+ position: absolute;
576
+ top: 8px;
577
+ right: 8px;
578
+ background: var(--red-bg);
579
+ color: var(--red);
580
+ padding: 2px 8px;
581
+ border-radius: 10px;
582
+ font-size: 10px;
583
+ font-weight: 700;
584
+ font-family: var(--font-mono);
585
+ }
586
+
587
+ /* Score indicator */
588
+ .score {
589
+ font-family: var(--font-mono);
590
+ font-size: 11px;
591
+ color: var(--text-dim);
592
+ }
593
+
594
+ /* Login modal */
595
+ .modal-overlay {
596
+ position: fixed;
597
+ inset: 0;
598
+ background: rgba(0, 0, 0, 0.6);
599
+ display: flex;
600
+ align-items: center;
601
+ justify-content: center;
602
+ z-index: 100;
603
+ }
604
+
605
+ .modal {
606
+ background: var(--bg-surface);
607
+ border: 1px solid var(--border);
608
+ border-radius: var(--radius-lg);
609
+ padding: 24px;
610
+ width: 360px;
611
+ max-width: 90vw;
612
+ }
613
+
614
+ .modal h2 {
615
+ font-size: 16px;
616
+ margin-bottom: 16px;
617
+ }
618
+
619
+ .modal .btn-row {
620
+ display: flex;
621
+ gap: 8px;
622
+ justify-content: flex-end;
623
+ margin-top: 16px;
624
+ }
625
+
626
+ .btn-github {
627
+ display: flex;
628
+ align-items: center;
629
+ justify-content: center;
630
+ gap: 8px;
631
+ width: 100%;
632
+ padding: 10px 16px;
633
+ background: #238636;
634
+ color: #fff;
635
+ border: none;
636
+ border-radius: var(--radius);
637
+ font-size: 14px;
638
+ font-weight: 500;
639
+ cursor: pointer;
640
+ text-decoration: none;
641
+ transition: background 0.15s;
642
+ }
643
+
644
+ .btn-github:hover {
645
+ background: #2ea043;
646
+ text-decoration: none;
647
+ color: #fff;
648
+ }
649
+
650
+ .login-divider {
651
+ display: flex;
652
+ align-items: center;
653
+ gap: 12px;
654
+ margin: 16px 0;
655
+ color: var(--text-dim);
656
+ font-size: 12px;
657
+ }
658
+
659
+ .login-divider::before,
660
+ .login-divider::after {
661
+ content: "";
662
+ flex: 1;
663
+ height: 1px;
664
+ background: var(--border);
665
+ }
666
+
667
+ .login-cred-toggle {
668
+ display: block;
669
+ width: 100%;
670
+ text-align: center;
671
+ color: var(--text-dim);
672
+ font-size: 12px;
673
+ background: none;
674
+ border: none;
675
+ cursor: pointer;
676
+ padding: 4px;
677
+ transition: color 0.15s;
678
+ }
679
+
680
+ .login-cred-toggle:hover {
681
+ color: var(--text);
682
+ background: none;
683
+ border: none;
684
+ }
685
+
686
+ .login-cred-form {
687
+ display: none;
688
+ margin-top: 16px;
689
+ }
690
+
691
+ .login-cred-form.visible {
692
+ display: block;
693
+ }
694
+
695
+ /* Responsive */
696
+ @media (max-width: 768px) {
697
+ main {
698
+ padding: 16px;
699
+ }
700
+ .form-row,
701
+ .form-row-3 {
702
+ grid-template-columns: 1fr;
703
+ }
704
+ header {
705
+ padding: 0 12px;
706
+ }
707
+ nav a {
708
+ padding: 6px 10px;
709
+ font-size: 12px;
710
+ }
711
+ .meta-grid {
712
+ grid-template-columns: 1fr;
713
+ }
714
+ }
715
+ </style>
716
+ </head>
717
+ <body>
718
+ <div id="app">
719
+ <header>
720
+ <div class="logo"><span>harper</span> knowledge</div>
721
+ <nav>
722
+ <a href="#search" data-nav="search">Search</a>
723
+ <a href="#browse" data-nav="browse">Browse</a>
724
+ <a href="#add" data-nav="add">Add Entry</a>
725
+ <a href="#triage" data-nav="triage">Triage</a>
726
+ </nav>
727
+ <div class="header-right">
728
+ <span class="auth-status" id="auth-status"></span>
729
+ </div>
730
+ </header>
731
+ <main id="main"></main>
732
+ </div>
733
+ <script type="module" src="js/app.js"></script>
734
+ </body>
735
+ </html>