kyd-shared-badge 0.3.39 → 0.3.40

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.3.39",
3
+ "version": "0.3.40",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -583,20 +583,78 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
583
583
  const AiSection = () => (
584
584
  <div className={`${wrapperMaxWidth} mx-auto`}>
585
585
  <div className={'rounded-xl shadow-xl p-6 sm:p-8 mt-6 border'} style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}>
586
+ <Reveal headless={isHeadless} as={'h4'} offsetY={8} className={'text-2xl font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>KYD AI (Beta)</Reveal>
586
587
  {(() => {
587
- const ai_usage_summary = assessmentResult?.ai_usage_summary;
588
- const label = 'AI Transparency';
589
- const topMovers = ai_usage_summary?.key_findings || [];
588
+ const ai = assessmentResult?.ai_usage_summary;
589
+ if (!ai) return null;
590
+ const techGauge = {
591
+ percent: Math.max(0, Math.min(100, Number(ai.originality_score ?? 0))),
592
+ label: 'Originality',
593
+ };
594
+ const riskGauge = {
595
+ percent: Math.max(0, Math.min(100, Number(ai.transparency_score ?? 0))),
596
+ label: ai.transparency_descriptor ? `Transparency — ${ai.transparency_descriptor}` : 'Transparency',
597
+ };
598
+ const stats: Array<{ label: string; value: string }>= [
599
+ { label: 'Files analyzed', value: String(ai.files_analyzed ?? 0) },
600
+ { label: 'Files with AI findings', value: String(ai.files_with_ai_findings ?? 0) },
601
+ { label: 'Files with disclosure', value: String(ai.files_with_disclosure ?? 0) },
602
+ { label: 'Repos analyzed', value: String(ai.repos_analyzed ?? 0) },
603
+ { label: 'Repos with AI findings', value: String(ai.repos_with_ai_findings ?? 0) },
604
+ ];
605
+ const findings = Array.isArray(ai.evidence) ? ai.evidence.slice(0, 5) : [];
606
+ const topMovers = Array.isArray(ai.key_findings) ? ai.key_findings : [];
590
607
  return (
591
- <GaugeCard
592
- key={'ai-card'}
593
- title={'KYD AI (Beta)'}
594
- description={'Indicates the degree to which AI-assisted code is explicitly disclosed across analyzed files.'}
595
- percent={ai_usage_summary?.transparency_score}
596
- label={label}
597
- topMovers={topMovers.map(t => ({ label: t, uid: 'ai-usage' }))}
598
- topMoversTitle={'Key Findings'}
599
- />
608
+ <div className="space-y-8">
609
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 *:min-h-full">
610
+ <GaugeCard
611
+ key={'ai-originality'}
612
+ title={'Originality'}
613
+ description={'Estimated share of human-authored code based on linguistic signals in comments.'}
614
+ percent={techGauge.percent}
615
+ label={techGauge.label}
616
+ topMovers={[]}
617
+ />
618
+ <GaugeCard
619
+ key={'ai-transparency'}
620
+ title={'Transparency'}
621
+ description={'Proportion of AI-influenced files that include an explicit disclosure.'}
622
+ percent={riskGauge.percent}
623
+ label={riskGauge.label}
624
+ topMovers={topMovers.map(t => ({ label: t, uid: 'ai-usage' }))}
625
+ topMoversTitle={'Key Findings'}
626
+ />
627
+ </div>
628
+ <div className="grid grid-cols-2 sm:grid-cols-5 gap-4">
629
+ {stats.map((s, i) => (
630
+ <div key={i} className={'rounded-md p-3 border'} style={{ borderColor: 'var(--icon-button-secondary)', background: 'var(--content-card-background)' }}>
631
+ <div className={'text-xs'} style={{ color: 'var(--text-secondary)' }}>{s.label}</div>
632
+ <div className={'text-lg font-semibold'} style={{ color: 'var(--text-main)' }}>{s.value}</div>
633
+ </div>
634
+ ))}
635
+ </div>
636
+ {findings.length > 0 && (
637
+ <div>
638
+ <div className={'text-sm font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Sample Findings</div>
639
+ <div className="space-y-3">
640
+ {findings.map((f, idx) => (
641
+ <div key={idx} className={'rounded-md p-3 border'} style={{ borderColor: 'var(--icon-button-secondary)', background: 'var(--content-card-background)' }}>
642
+ <div className={'text-xs mb-1'} style={{ color: 'var(--text-secondary)' }}>{f.file_path || 'file'}</div>
643
+ {f.snippet ? (
644
+ <pre className={'text-xs overflow-auto p-2 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{f.snippet}</pre>
645
+ ) : null}
646
+ {f.reason ? (
647
+ <div className={'text-xs mt-2'} style={{ color: 'var(--text-secondary)' }}>{f.reason}</div>
648
+ ) : null}
649
+ </div>
650
+ ))}
651
+ </div>
652
+ </div>
653
+ )}
654
+ {ai.explanation && (
655
+ <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>{ai.explanation}</div>
656
+ )}
657
+ </div>
600
658
  );
601
659
  })()}
602
660
  </div>
@@ -54,8 +54,7 @@ export default function ChatWidget({ api = '/api/chat', title = 'KYD Bot', hintT
54
54
 
55
55
  useEffect(() => {
56
56
  // when sidebar is closed, dismiss hint
57
- if (open) return;
58
- setShowHint(false);
57
+ if (!open) setShowHint(false);
59
58
  }, [open]);
60
59
 
61
60
  // Sidebar width with bounds and persistence
@@ -278,7 +277,7 @@ export default function ChatWidget({ api = '/api/chat', title = 'KYD Bot', hintT
278
277
  )}
279
278
  </div>
280
279
  ) : (
281
- <div style={{ position: 'fixed', right: 0, top: Math.max(headerTop + 16, tabTop), height: 160, width: 44 }}>
280
+ <div style={{ position: 'fixed', right: 0, top: Math.max(headerTop + 16, tabTop), height: 160, width: 44, overflow: 'hidden' }}>
282
281
  <button
283
282
  aria-label={'Open chat sidebar'}
284
283
  aria-expanded={open}
package/src/types.ts CHANGED
@@ -203,10 +203,16 @@ export interface AssessmentResult {
203
203
  ai_usage_summary?: {
204
204
  explanation: string;
205
205
  key_findings: string[];
206
+ originality_score: number;
207
+ transparency_score: number;
208
+ transparency_descriptor?: string;
206
209
  files_with_ai_findings: number;
207
210
  files_analyzed: number;
208
- files_with_disclosure: number;
209
- transparency_score: number;
211
+ files_with_disclosure?: number;
212
+ repos_analyzed?: number;
213
+ repos_with_ai_findings?: number;
214
+ evidence?: Array<{ file_path?: string; snippet?: string; reason?: string }>;
215
+ findings_by_repo?: Record<string, Array<{ file_path?: string; snippet?: string; reason?: string }>>;
210
216
  };
211
217
  key_skills?: string[];
212
218
  summary_scores?: {
@@ -394,13 +400,19 @@ export interface GraphInsightsPayload {
394
400
  top_movers?: Array<{ label?: string; uid?: string }>;
395
401
  };
396
402
  };
397
- ai_usage_summary: {
403
+ ai_usage_summary?: {
398
404
  explanation: string;
399
405
  key_findings: string[];
406
+ originality_score: number;
407
+ transparency_score: number;
408
+ transparency_descriptor?: string;
400
409
  files_with_ai_findings: number;
401
410
  files_analyzed: number;
402
411
  files_with_disclosure?: number;
403
- transparency_score: number;
412
+ repos_analyzed?: number;
413
+ repos_with_ai_findings?: number;
414
+ evidence?: Array<{ file_path?: string; snippet?: string; reason?: string }>;
415
+ findings_by_repo?: Record<string, Array<{ file_path?: string; snippet?: string; reason?: string }>>;
404
416
  }
405
417
  }
406
418