selftune 0.2.28 → 0.2.29
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/apps/local-dashboard/dist/assets/index-BcvtYmmL.js +15 -0
- package/apps/local-dashboard/dist/assets/index-BpRIxnpS.css +1 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-DqH_uxum.js +1 -0
- package/apps/local-dashboard/dist/index.html +3 -3
- package/package.json +1 -1
- package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +1 -1
- package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +1 -5
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +10 -18
- package/packages/ui/src/components/EvidenceViewer.tsx +15 -142
- package/packages/ui/src/components/EvolutionTimeline.tsx +20 -44
- package/packages/ui/src/components/SkillReportPanels.tsx +1 -4
- package/skill/SKILL.md +1 -1
- package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +0 -1
- package/apps/local-dashboard/dist/assets/index-MMLFlnVn.js +0 -15
- package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +0 -1
|
@@ -4,40 +4,14 @@ import { Card, CardContent, CardHeader, CardTitle } from "../primitives/card";
|
|
|
4
4
|
import type { EvidenceEntry, EvolutionEntry } from "../types";
|
|
5
5
|
import { formatRate, timeAgo } from "../lib/format";
|
|
6
6
|
import {
|
|
7
|
-
CheckCircleIcon,
|
|
8
7
|
ChevronDownIcon,
|
|
9
8
|
ChevronRightIcon,
|
|
10
|
-
CircleDotIcon,
|
|
11
9
|
FileTextIcon,
|
|
12
|
-
InfoIcon,
|
|
13
|
-
RocketIcon,
|
|
14
|
-
ShieldCheckIcon,
|
|
15
10
|
ShieldAlertIcon,
|
|
16
|
-
XCircleIcon,
|
|
17
|
-
UndoIcon,
|
|
18
|
-
ArrowRightIcon,
|
|
19
|
-
TrendingUpIcon,
|
|
20
|
-
TrendingDownIcon,
|
|
21
11
|
ListChecksIcon,
|
|
22
12
|
} from "lucide-react";
|
|
23
13
|
import Markdown from "react-markdown";
|
|
24
14
|
|
|
25
|
-
const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
26
|
-
created: <CircleDotIcon className="size-3.5" />,
|
|
27
|
-
validated: <ShieldCheckIcon className="size-3.5" />,
|
|
28
|
-
deployed: <RocketIcon className="size-3.5" />,
|
|
29
|
-
rejected: <XCircleIcon className="size-3.5" />,
|
|
30
|
-
rolled_back: <UndoIcon className="size-3.5" />,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const ACTION_VARIANT: Record<string, "default" | "secondary" | "destructive" | "outline"> = {
|
|
34
|
-
created: "outline",
|
|
35
|
-
validated: "secondary",
|
|
36
|
-
deployed: "default",
|
|
37
|
-
rejected: "destructive",
|
|
38
|
-
rolled_back: "destructive",
|
|
39
|
-
};
|
|
40
|
-
|
|
41
15
|
interface Props {
|
|
42
16
|
proposalId: string;
|
|
43
17
|
evolution: EvolutionEntry[];
|
|
@@ -123,9 +97,9 @@ function formatValidationValue(key: string, val: unknown): React.ReactNode {
|
|
|
123
97
|
// Booleans
|
|
124
98
|
if (typeof val === "boolean") {
|
|
125
99
|
return val ? (
|
|
126
|
-
<
|
|
100
|
+
<span className="inline-block size-2 rounded-full bg-primary align-middle" />
|
|
127
101
|
) : (
|
|
128
|
-
<
|
|
102
|
+
<span className="inline-block size-2 rounded-full bg-destructive align-middle" />
|
|
129
103
|
);
|
|
130
104
|
}
|
|
131
105
|
// Numbers that look like rates (0-1 range, or key contains "rate"/"change")
|
|
@@ -212,12 +186,12 @@ function PerEntryResult({ entry }: { entry: Record<string, unknown> }) {
|
|
|
212
186
|
<div className="flex items-start gap-2 text-xs py-1.5 border-b border-border/50 last:border-0">
|
|
213
187
|
{isPass !== null ? (
|
|
214
188
|
isPass ? (
|
|
215
|
-
<
|
|
189
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-primary" />
|
|
216
190
|
) : (
|
|
217
|
-
<
|
|
191
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-destructive" />
|
|
218
192
|
)
|
|
219
193
|
) : (
|
|
220
|
-
<
|
|
194
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-muted-foreground/60" />
|
|
221
195
|
)}
|
|
222
196
|
<span className="flex-1 min-w-0 line-clamp-2">
|
|
223
197
|
{query ? String(query) : JSON.stringify(entry)}
|
|
@@ -307,7 +281,7 @@ function ValidationResults({ validation }: { validation: Record<string, unknown>
|
|
|
307
281
|
)}
|
|
308
282
|
{typeof net_change === "number" && (
|
|
309
283
|
<span
|
|
310
|
-
className={`text-xs font-mono font-semibold ${net_change > 0 ? "text-
|
|
284
|
+
className={`text-xs font-mono font-semibold ${net_change > 0 ? "text-primary" : "text-destructive"}`}
|
|
311
285
|
>
|
|
312
286
|
{net_change > 0 ? "+" : ""}
|
|
313
287
|
{(net_change * 100).toFixed(1)}%
|
|
@@ -324,7 +298,7 @@ function ValidationResults({ validation }: { validation: Record<string, unknown>
|
|
|
324
298
|
{/* New passes */}
|
|
325
299
|
{newPassesArr.length > 0 && (
|
|
326
300
|
<div>
|
|
327
|
-
<p className="text-[11px] font-medium text-
|
|
301
|
+
<p className="mb-1 text-[11px] font-medium text-primary">
|
|
328
302
|
New Passes ({newPassesArr.length})
|
|
329
303
|
</p>
|
|
330
304
|
<div className="rounded border bg-card p-2">
|
|
@@ -345,10 +319,10 @@ function ValidationResults({ validation }: { validation: Record<string, unknown>
|
|
|
345
319
|
{/* Regressions */}
|
|
346
320
|
{regressionsArr.length > 0 && (
|
|
347
321
|
<div>
|
|
348
|
-
<p className="text-[11px] font-medium text-
|
|
322
|
+
<p className="text-[11px] font-medium text-destructive mb-1">
|
|
349
323
|
Regressions ({regressionsArr.length})
|
|
350
324
|
</p>
|
|
351
|
-
<div className="rounded border border-
|
|
325
|
+
<div className="rounded border border-destructive/20 bg-card p-2">
|
|
352
326
|
{regressionsArr.map((entry) => (
|
|
353
327
|
<PerEntryResult
|
|
354
328
|
key={getEvidenceListKey("regression", entry)}
|
|
@@ -406,7 +380,7 @@ function PerEntryResultsSection({ entries }: { entries: unknown[] }) {
|
|
|
406
380
|
{/* Pass rate bar */}
|
|
407
381
|
<div className="h-1.5 rounded-full bg-muted overflow-hidden mb-2">
|
|
408
382
|
<div
|
|
409
|
-
className="h-full rounded-full bg-
|
|
383
|
+
className="h-full rounded-full bg-primary transition-all"
|
|
410
384
|
style={{ width: `${entries.length > 0 ? (passCount / entries.length) * 100 : 0}%` }}
|
|
411
385
|
/>
|
|
412
386
|
</div>
|
|
@@ -442,7 +416,7 @@ function DeltaBadge({ prev, curr }: { prev: number | null; curr: number | null }
|
|
|
442
416
|
const positive = delta > 0;
|
|
443
417
|
return (
|
|
444
418
|
<span
|
|
445
|
-
className={`text-[10px] font-mono font-semibold ${positive ? "text-
|
|
419
|
+
className={`text-[10px] font-mono font-semibold ${positive ? "text-primary" : "text-destructive"}`}
|
|
446
420
|
>
|
|
447
421
|
{positive ? "+" : ""}
|
|
448
422
|
{pct}% vs previous
|
|
@@ -487,12 +461,12 @@ function EvalSetSection({ evalSet }: { evalSet: Array<Record<string, unknown>> }
|
|
|
487
461
|
>
|
|
488
462
|
{typeof passed === "boolean" ? (
|
|
489
463
|
passed ? (
|
|
490
|
-
<
|
|
464
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-primary" />
|
|
491
465
|
) : (
|
|
492
|
-
<
|
|
466
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-destructive" />
|
|
493
467
|
)
|
|
494
468
|
) : (
|
|
495
|
-
<
|
|
469
|
+
<span className="mt-1 size-2 shrink-0 rounded-full bg-muted-foreground/60" />
|
|
496
470
|
)}
|
|
497
471
|
<span className="flex-1 min-w-0 line-clamp-2">
|
|
498
472
|
{String(query ?? JSON.stringify(evalEntry))}
|
|
@@ -648,15 +622,7 @@ function CollapsedEvidenceCard({
|
|
|
648
622
|
);
|
|
649
623
|
}
|
|
650
624
|
|
|
651
|
-
export function EvidenceViewer({ proposalId,
|
|
652
|
-
const steps = useMemo(
|
|
653
|
-
() =>
|
|
654
|
-
evolution
|
|
655
|
-
.filter((e) => e.proposal_id === proposalId)
|
|
656
|
-
.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()),
|
|
657
|
-
[evolution, proposalId],
|
|
658
|
-
);
|
|
659
|
-
|
|
625
|
+
export function EvidenceViewer({ proposalId, evidence }: Props) {
|
|
660
626
|
const entries = useMemo(
|
|
661
627
|
() =>
|
|
662
628
|
evidence
|
|
@@ -677,13 +643,6 @@ export function EvidenceViewer({ proposalId, evolution, evidence }: Props) {
|
|
|
677
643
|
});
|
|
678
644
|
};
|
|
679
645
|
|
|
680
|
-
const snapshot = useMemo(() => {
|
|
681
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
682
|
-
if (steps[i].eval_snapshot) return steps[i].eval_snapshot as Record<string, unknown>;
|
|
683
|
-
}
|
|
684
|
-
return null;
|
|
685
|
-
}, [steps]);
|
|
686
|
-
|
|
687
646
|
// Separate proposal-stage entries from validation-stage entries, then group validations by target
|
|
688
647
|
const { proposalEntries, validationsByTarget } = useMemo(() => {
|
|
689
648
|
const proposals: EvidenceEntry[] = [];
|
|
@@ -702,92 +661,6 @@ export function EvidenceViewer({ proposalId, evolution, evidence }: Props) {
|
|
|
702
661
|
|
|
703
662
|
return (
|
|
704
663
|
<div className="space-y-4">
|
|
705
|
-
{/* Context banner */}
|
|
706
|
-
<div className="flex items-start gap-2.5 rounded-lg border border-primary/20 bg-primary/5 px-3.5 py-2.5">
|
|
707
|
-
<InfoIcon className="size-4 text-primary/60 shrink-0 mt-0.5" />
|
|
708
|
-
<p className="text-xs text-muted-foreground leading-relaxed">
|
|
709
|
-
This view shows the complete evidence trail for a skill evolution proposal — how the
|
|
710
|
-
skill was changed, the eval test results before and after, and whether the change improved
|
|
711
|
-
performance.
|
|
712
|
-
</p>
|
|
713
|
-
</div>
|
|
714
|
-
|
|
715
|
-
{/* Proposal journey */}
|
|
716
|
-
<Card>
|
|
717
|
-
<CardHeader className="pb-3">
|
|
718
|
-
<CardTitle className="text-sm flex items-center gap-2">
|
|
719
|
-
<span>Proposal Journey</span>
|
|
720
|
-
<span className="font-mono text-xs text-muted-foreground">
|
|
721
|
-
#{proposalId.slice(0, 12)}
|
|
722
|
-
</span>
|
|
723
|
-
</CardTitle>
|
|
724
|
-
</CardHeader>
|
|
725
|
-
<CardContent className="space-y-3">
|
|
726
|
-
<div className="flex items-center gap-2 flex-wrap">
|
|
727
|
-
{steps.map((step, i) => (
|
|
728
|
-
<div key={`${step.action}-${step.timestamp}`} className="contents">
|
|
729
|
-
{i > 0 && <ArrowRightIcon className="size-3 text-muted-foreground/50 shrink-0" />}
|
|
730
|
-
<div className="flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 bg-card">
|
|
731
|
-
{ACTION_ICON[step.action]}
|
|
732
|
-
<Badge
|
|
733
|
-
variant={ACTION_VARIANT[step.action] ?? "secondary"}
|
|
734
|
-
className="text-[10px] capitalize"
|
|
735
|
-
>
|
|
736
|
-
{step.action.replace("_", " ")}
|
|
737
|
-
</Badge>
|
|
738
|
-
<span className="text-[10px] text-muted-foreground">
|
|
739
|
-
{timeAgo(step.timestamp)}
|
|
740
|
-
</span>
|
|
741
|
-
</div>
|
|
742
|
-
</div>
|
|
743
|
-
))}
|
|
744
|
-
</div>
|
|
745
|
-
|
|
746
|
-
{/* Eval snapshot — pass rate change */}
|
|
747
|
-
{snapshot && (
|
|
748
|
-
<div className="flex items-center gap-3 rounded-md border bg-muted/20 px-3 py-2">
|
|
749
|
-
{typeof snapshot.net_change === "number" && (
|
|
750
|
-
<div className="flex items-center gap-1">
|
|
751
|
-
{(snapshot.net_change as number) > 0 ? (
|
|
752
|
-
<TrendingUpIcon className="size-3.5 text-emerald-500" />
|
|
753
|
-
) : (
|
|
754
|
-
<TrendingDownIcon className="size-3.5 text-red-500" />
|
|
755
|
-
)}
|
|
756
|
-
<span
|
|
757
|
-
className={`text-sm font-semibold font-mono ${(snapshot.net_change as number) > 0 ? "text-emerald-600 dark:text-emerald-400" : "text-red-500"}`}
|
|
758
|
-
>
|
|
759
|
-
{(snapshot.net_change as number) > 0 ? "+" : ""}
|
|
760
|
-
{Math.round((snapshot.net_change as number) * 100)}%
|
|
761
|
-
</span>
|
|
762
|
-
</div>
|
|
763
|
-
)}
|
|
764
|
-
{typeof snapshot.before_pass_rate === "number" &&
|
|
765
|
-
typeof snapshot.after_pass_rate === "number" && (
|
|
766
|
-
<span className="text-xs text-muted-foreground font-mono">
|
|
767
|
-
{Math.round((snapshot.before_pass_rate as number) * 100)}% →{" "}
|
|
768
|
-
{Math.round((snapshot.after_pass_rate as number) * 100)}%
|
|
769
|
-
</span>
|
|
770
|
-
)}
|
|
771
|
-
{snapshot.improved !== undefined && (
|
|
772
|
-
<Badge
|
|
773
|
-
variant={snapshot.improved ? "default" : "destructive"}
|
|
774
|
-
className="text-[10px]"
|
|
775
|
-
>
|
|
776
|
-
{snapshot.improved ? "Improved" : "Regressed"}
|
|
777
|
-
</Badge>
|
|
778
|
-
)}
|
|
779
|
-
</div>
|
|
780
|
-
)}
|
|
781
|
-
|
|
782
|
-
{/* Details from last step */}
|
|
783
|
-
{steps.length > 0 && steps[steps.length - 1].details && (
|
|
784
|
-
<p className="text-xs text-muted-foreground leading-relaxed">
|
|
785
|
-
{steps[steps.length - 1].details}
|
|
786
|
-
</p>
|
|
787
|
-
)}
|
|
788
|
-
</CardContent>
|
|
789
|
-
</Card>
|
|
790
|
-
|
|
791
664
|
{/* Proposal-stage evidence — standalone cards showing original/proposed text */}
|
|
792
665
|
{proposalEntries.map((entry) => (
|
|
793
666
|
<EvidenceCard
|
|
@@ -3,48 +3,30 @@ import { Badge } from "../primitives/badge";
|
|
|
3
3
|
import { cn } from "../lib/utils";
|
|
4
4
|
import type { EvalSnapshot, EvolutionEntry } from "../types";
|
|
5
5
|
import { timeAgo } from "../lib/format";
|
|
6
|
-
import {
|
|
7
|
-
CircleDotIcon,
|
|
8
|
-
RocketIcon,
|
|
9
|
-
ShieldCheckIcon,
|
|
10
|
-
XCircleIcon,
|
|
11
|
-
UndoIcon,
|
|
12
|
-
TrendingUpIcon,
|
|
13
|
-
TrendingDownIcon,
|
|
14
|
-
ChevronDownIcon,
|
|
15
|
-
ChevronRightIcon,
|
|
16
|
-
} from "lucide-react";
|
|
17
|
-
|
|
18
|
-
const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
19
|
-
created: <CircleDotIcon className="size-3.5" />,
|
|
20
|
-
validated: <ShieldCheckIcon className="size-3.5" />,
|
|
21
|
-
deployed: <RocketIcon className="size-3.5" />,
|
|
22
|
-
rejected: <XCircleIcon className="size-3.5" />,
|
|
23
|
-
rolled_back: <UndoIcon className="size-3.5" />,
|
|
24
|
-
};
|
|
6
|
+
import { TrendingUpIcon, TrendingDownIcon, ChevronDownIcon, ChevronRightIcon } from "lucide-react";
|
|
25
7
|
|
|
26
8
|
const ACTION_COLOR: Record<string, string> = {
|
|
27
|
-
created: "bg-
|
|
28
|
-
validated: "bg-
|
|
29
|
-
deployed: "bg-
|
|
30
|
-
rejected: "bg-
|
|
31
|
-
rolled_back: "bg-
|
|
9
|
+
created: "bg-primary/35",
|
|
10
|
+
validated: "bg-primary/65",
|
|
11
|
+
deployed: "bg-primary",
|
|
12
|
+
rejected: "bg-destructive/85",
|
|
13
|
+
rolled_back: "bg-destructive/45",
|
|
32
14
|
};
|
|
33
15
|
|
|
34
16
|
const ACTION_RING: Record<string, string> = {
|
|
35
|
-
created: "ring-
|
|
36
|
-
validated: "ring-
|
|
37
|
-
deployed: "ring-
|
|
38
|
-
rejected: "ring-
|
|
39
|
-
rolled_back: "ring-
|
|
17
|
+
created: "ring-primary/15",
|
|
18
|
+
validated: "ring-primary/20",
|
|
19
|
+
deployed: "ring-primary/30",
|
|
20
|
+
rejected: "ring-destructive/20",
|
|
21
|
+
rolled_back: "ring-destructive/15",
|
|
40
22
|
};
|
|
41
23
|
|
|
42
24
|
const ACTION_LINE: Record<string, string> = {
|
|
43
|
-
created: "bg-
|
|
44
|
-
validated: "bg-
|
|
45
|
-
deployed: "bg-
|
|
46
|
-
rejected: "bg-
|
|
47
|
-
rolled_back: "bg-
|
|
25
|
+
created: "bg-primary/12",
|
|
26
|
+
validated: "bg-primary/18",
|
|
27
|
+
deployed: "bg-primary/30",
|
|
28
|
+
rejected: "bg-destructive/18",
|
|
29
|
+
rolled_back: "bg-destructive/12",
|
|
48
30
|
};
|
|
49
31
|
|
|
50
32
|
interface Props {
|
|
@@ -92,7 +74,7 @@ function PassRateDelta({ snapshot }: { snapshot: EvalSnapshot }) {
|
|
|
92
74
|
<span
|
|
93
75
|
className={cn(
|
|
94
76
|
"inline-flex items-center gap-0.5 text-[10px] font-mono font-medium",
|
|
95
|
-
isPositive ? "text-
|
|
77
|
+
isPositive ? "text-primary" : "text-destructive",
|
|
96
78
|
)}
|
|
97
79
|
>
|
|
98
80
|
{isPositive ? (
|
|
@@ -157,7 +139,7 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
157
139
|
|
|
158
140
|
return (
|
|
159
141
|
<div className="flex flex-col gap-0">
|
|
160
|
-
<h2 className="
|
|
142
|
+
<h2 className="sticky top-0 z-10 bg-background px-2 pb-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
|
161
143
|
Evolution
|
|
162
144
|
</h2>
|
|
163
145
|
<LifecycleLegend />
|
|
@@ -177,14 +159,8 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
177
159
|
{/* Vertical connector line */}
|
|
178
160
|
<div className="flex flex-col items-center">
|
|
179
161
|
<div
|
|
180
|
-
className={cn(
|
|
181
|
-
|
|
182
|
-
dotColor,
|
|
183
|
-
ringColor,
|
|
184
|
-
)}
|
|
185
|
-
>
|
|
186
|
-
{ACTION_ICON[terminal] ?? <CircleDotIcon className="size-3.5" />}
|
|
187
|
-
</div>
|
|
162
|
+
className={cn("size-3 shrink-0 rounded-full ring-2 z-10", dotColor, ringColor)}
|
|
163
|
+
/>
|
|
188
164
|
{!isLast && <div className={cn("w-0.5 flex-1 min-h-[16px]", lineColor)} />}
|
|
189
165
|
</div>
|
|
190
166
|
|
|
@@ -84,10 +84,7 @@ function ExampleRowItem({ row }: { row: ExampleRow }) {
|
|
|
84
84
|
<TableCell className="py-2">
|
|
85
85
|
<div className="flex items-center gap-1.5">
|
|
86
86
|
{row.triggered ? (
|
|
87
|
-
<Badge
|
|
88
|
-
variant="outline"
|
|
89
|
-
className="border-green-600/30 text-[10px] font-normal text-green-600"
|
|
90
|
-
>
|
|
87
|
+
<Badge variant="outline" className="text-[10px] font-normal">
|
|
91
88
|
triggered
|
|
92
89
|
</Badge>
|
|
93
90
|
) : (
|