selftune 0.2.23 → 0.2.25
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/CHANGELOG.md +6 -0
- package/README.md +93 -15
- package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +1 -0
- package/apps/local-dashboard/dist/assets/index-Dhgv5BQO.js +15 -0
- package/apps/local-dashboard/dist/assets/vendor-react-C5oyHiV1.js +11 -0
- package/apps/local-dashboard/dist/assets/{vendor-table-BIiI3YhS.js → vendor-table-Bc_bbKd8.js} +1 -1
- package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +1 -0
- package/apps/local-dashboard/dist/index.html +5 -5
- package/cli/selftune/adapters/codex/install.ts +310 -78
- package/cli/selftune/adapters/opencode/install.ts +3 -4
- package/cli/selftune/alpha-upload/build-payloads.ts +3 -3
- package/cli/selftune/alpha-upload/stage-canonical.ts +17 -11
- package/cli/selftune/auto-update.ts +200 -8
- package/cli/selftune/canonical-export.ts +55 -25
- package/cli/selftune/command-surface.ts +397 -0
- package/cli/selftune/contribute/contribute.ts +64 -13
- package/cli/selftune/contribution-config.ts +57 -3
- package/cli/selftune/contribution-preferences.ts +117 -0
- package/cli/selftune/contribution-signals.ts +8 -4
- package/cli/selftune/contribution-staging.ts +13 -2
- package/cli/selftune/contributions.ts +55 -121
- package/cli/selftune/creator-contributions.ts +29 -10
- package/cli/selftune/cron/setup.ts +7 -3
- package/cli/selftune/dashboard-contract.ts +73 -0
- package/cli/selftune/dashboard-server.ts +168 -17
- package/cli/selftune/dashboard.ts +350 -17
- package/cli/selftune/eval/baseline.ts +21 -5
- package/cli/selftune/eval/execution-eval.ts +170 -0
- package/cli/selftune/eval/family-overlap.ts +2 -2
- package/cli/selftune/eval/hooks-to-evals.ts +228 -82
- package/cli/selftune/eval/import-skillsbench.ts +2 -2
- package/cli/selftune/eval/invocation-classifier.ts +56 -0
- package/cli/selftune/eval/synthetic-evals.ts +5 -3
- package/cli/selftune/eval/unit-test-cli.ts +7 -4
- package/cli/selftune/evolution/apply-proposal.ts +295 -0
- package/cli/selftune/evolution/engines/replay-engine.ts +79 -57
- package/cli/selftune/evolution/evolve-body.ts +100 -39
- package/cli/selftune/evolution/evolve.ts +244 -52
- package/cli/selftune/evolution/rollback.ts +0 -1
- package/cli/selftune/evolution/validate-body.ts +68 -42
- package/cli/selftune/evolution/validate-host-replay.ts +510 -60
- package/cli/selftune/evolution/validate-proposal.ts +11 -150
- package/cli/selftune/evolution/validate-routing.ts +43 -41
- package/cli/selftune/evolution/validation-contract.ts +91 -0
- package/cli/selftune/grading/auto-grade.ts +11 -7
- package/cli/selftune/grading/grade-session.ts +10 -16
- package/cli/selftune/index.ts +35 -10
- package/cli/selftune/ingestors/claude-replay.ts +15 -10
- package/cli/selftune/ingestors/codex-wrapper.ts +3 -3
- package/cli/selftune/ingestors/opencode-ingest.ts +2 -2
- package/cli/selftune/ingestors/pi-ingest.ts +3 -2
- package/cli/selftune/init.ts +27 -3
- package/cli/selftune/localdb/direct-write.ts +35 -1
- package/cli/selftune/localdb/queries/cron.ts +34 -0
- package/cli/selftune/localdb/queries/dashboard.ts +834 -0
- package/cli/selftune/localdb/queries/evolution.ts +158 -0
- package/cli/selftune/localdb/queries/execution.ts +133 -0
- package/cli/selftune/localdb/queries/json.ts +18 -0
- package/cli/selftune/localdb/queries/monitoring.ts +263 -0
- package/cli/selftune/localdb/queries/raw.ts +95 -0
- package/cli/selftune/localdb/queries/staging.ts +270 -0
- package/cli/selftune/localdb/queries/trust.ts +392 -0
- package/cli/selftune/localdb/queries.ts +60 -2288
- package/cli/selftune/localdb/schema.ts +21 -0
- package/cli/selftune/monitoring/watch.ts +96 -29
- package/cli/selftune/normalization.ts +3 -0
- package/cli/selftune/observability.ts +4 -2
- package/cli/selftune/orchestrate/cli.ts +161 -0
- package/cli/selftune/orchestrate/execute.ts +295 -0
- package/cli/selftune/orchestrate/finalize.ts +157 -0
- package/cli/selftune/orchestrate/locks.ts +40 -0
- package/cli/selftune/orchestrate/plan.ts +131 -0
- package/cli/selftune/orchestrate/post-run.ts +59 -0
- package/cli/selftune/orchestrate/prepare.ts +334 -0
- package/cli/selftune/orchestrate/report.ts +182 -0
- package/cli/selftune/orchestrate/runtime.ts +120 -0
- package/cli/selftune/orchestrate/signals.ts +48 -0
- package/cli/selftune/orchestrate.ts +150 -1173
- package/cli/selftune/repair/skill-usage.ts +5 -2
- package/cli/selftune/routes/overview.ts +5 -2
- package/cli/selftune/routes/skill-report.ts +15 -2
- package/cli/selftune/schedule.ts +5 -5
- package/cli/selftune/status.ts +39 -2
- package/cli/selftune/testing-readiness.ts +597 -0
- package/cli/selftune/types.ts +44 -4
- package/cli/selftune/uninstall.ts +2 -1
- package/cli/selftune/utils/canonical-log.ts +1 -9
- package/cli/selftune/utils/cli-error.ts +9 -0
- package/cli/selftune/utils/llm-call.ts +126 -6
- package/cli/selftune/utils/skill-discovery.ts +2 -0
- package/cli/selftune/workflows/proposals.ts +184 -0
- package/cli/selftune/workflows/skill-scaffold.ts +241 -0
- package/cli/selftune/workflows/workflows.ts +100 -26
- package/node_modules/@selftune/telemetry-contract/fixtures/complete-push.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
- package/node_modules/@selftune/telemetry-contract/src/schemas.ts +41 -1
- package/node_modules/@selftune/telemetry-contract/src/types.ts +103 -2
- package/package.json +25 -9
- package/packages/dashboard-core/AGENTS.md +18 -0
- package/packages/dashboard-core/README.md +30 -0
- package/packages/dashboard-core/index.ts +3 -0
- package/packages/dashboard-core/package.json +39 -0
- package/packages/dashboard-core/src/chrome/DashboardChrome.tsx +74 -0
- package/packages/dashboard-core/src/chrome/DashboardHeader.tsx +200 -0
- package/packages/dashboard-core/src/chrome/DashboardSidebar.tsx +219 -0
- package/packages/dashboard-core/src/chrome/RuntimeBadge.tsx +46 -0
- package/packages/dashboard-core/src/chrome/index.ts +14 -0
- package/packages/dashboard-core/src/chrome/types.ts +81 -0
- package/packages/dashboard-core/src/chrome/utils.ts +23 -0
- package/packages/dashboard-core/src/gates/FeatureGate.tsx +11 -0
- package/packages/dashboard-core/src/gates/LockedRoute.tsx +29 -0
- package/packages/dashboard-core/src/gates/UpgradeCard.tsx +89 -0
- package/packages/dashboard-core/src/gates/index.ts +3 -0
- package/packages/dashboard-core/src/host/DashboardHostProvider.tsx +62 -0
- package/packages/dashboard-core/src/host/adapter.ts +47 -0
- package/packages/dashboard-core/src/host/capabilities.ts +55 -0
- package/packages/dashboard-core/src/host/index.ts +3 -0
- package/packages/dashboard-core/src/models/analytics.ts +39 -0
- package/packages/dashboard-core/src/models/index.ts +4 -0
- package/packages/dashboard-core/src/models/overview.ts +98 -0
- package/packages/dashboard-core/src/models/runtime.ts +7 -0
- package/packages/dashboard-core/src/models/skills.ts +34 -0
- package/packages/dashboard-core/src/routes/index.ts +2 -0
- package/packages/dashboard-core/src/routes/manifest.test.ts +70 -0
- package/packages/dashboard-core/src/routes/manifest.ts +451 -0
- package/packages/dashboard-core/src/routes/types.ts +39 -0
- package/packages/dashboard-core/src/screens/analytics/AnalyticsScreen.tsx +278 -0
- package/packages/dashboard-core/src/screens/analytics/index.ts +1 -0
- package/packages/dashboard-core/src/screens/index.ts +37 -0
- package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.test.ts +101 -0
- package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.tsx +393 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.test.tsx +113 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.tsx +72 -0
- package/packages/dashboard-core/src/screens/overview/OverviewCoreSurface.tsx +71 -0
- package/packages/dashboard-core/src/screens/overview/OverviewOnboardingBanner.tsx +90 -0
- package/packages/dashboard-core/src/screens/overview/OverviewRunSummary.tsx +40 -0
- package/packages/dashboard-core/src/screens/overview/index.ts +16 -0
- package/packages/dashboard-core/src/screens/overview/types.ts +13 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +99 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportDataQualityTabContent.tsx +35 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceRail.tsx +71 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceSection.tsx +63 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceTabContent.tsx +25 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportInvocationsSection.tsx +24 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportMissedQueriesSection.tsx +79 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +150 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportSections.test.tsx +224 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.test.tsx +76 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.tsx +88 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTrendSection.tsx +33 -0
- package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +67 -0
- package/packages/dashboard-core/src/screens/skill-report/index.ts +45 -0
- package/packages/dashboard-core/src/screens/skills/SkillsLibraryScreen.tsx +162 -0
- package/packages/dashboard-core/src/screens/skills/index.ts +6 -0
- package/packages/telemetry-contract/fixtures/complete-push.ts +1 -1
- package/packages/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
- package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
- package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
- package/packages/telemetry-contract/src/schemas.ts +41 -1
- package/packages/telemetry-contract/src/types.ts +103 -2
- package/packages/ui/src/components/EvidenceViewer.tsx +80 -25
- package/packages/ui/src/components/OverviewPanels.tsx +67 -26
- package/packages/ui/src/primitives/tabs.tsx +7 -6
- package/packages/ui/src/types.ts +10 -0
- package/skill/SKILL.md +130 -332
- package/skill/agents/diagnosis-analyst.md +3 -3
- package/skill/agents/evolution-reviewer.md +3 -3
- package/skill/agents/integration-guide.md +3 -3
- package/skill/agents/pattern-analyst.md +2 -2
- package/skill/references/cli-quick-reference.md +89 -0
- package/skill/references/creator-playbook.md +131 -0
- package/skill/references/examples.md +48 -0
- package/skill/references/troubleshooting.md +47 -0
- package/skill/references/version-history.md +1 -1
- package/skill/selftune.contribute.json +11 -0
- package/skill/{Workflows → workflows}/Baseline.md +20 -1
- package/skill/{Workflows → workflows}/Contribute.md +23 -10
- package/skill/{Workflows → workflows}/Contributions.md +13 -5
- package/skill/workflows/CreateTestDeploy.md +170 -0
- package/skill/{Workflows → workflows}/CreatorContributions.md +18 -6
- package/skill/{Workflows → workflows}/Cron.md +1 -1
- package/skill/{Workflows → workflows}/Dashboard.md +20 -0
- package/skill/{Workflows → workflows}/Doctor.md +1 -1
- package/skill/{Workflows → workflows}/Evals.md +67 -2
- package/skill/{Workflows → workflows}/Evolve.md +119 -30
- package/skill/{Workflows → workflows}/EvolveBody.md +41 -1
- package/skill/{Workflows → workflows}/Grade.md +1 -1
- package/skill/{Workflows → workflows}/Initialize.md +8 -4
- package/skill/{Workflows → workflows}/Orchestrate.md +13 -3
- package/skill/{Workflows → workflows}/Schedule.md +3 -3
- package/skill/workflows/SignalsDashboard.md +87 -0
- package/skill/{Workflows → workflows}/UnitTest.md +19 -0
- package/skill/{Workflows → workflows}/Watch.md +42 -2
- package/skill/{Workflows → workflows}/Workflows.md +39 -2
- package/apps/local-dashboard/dist/assets/index-CwOtTrUS.css +0 -1
- package/apps/local-dashboard/dist/assets/index-f1HQpbeH.js +0 -59
- package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +0 -11
- package/apps/local-dashboard/dist/assets/vendor-ui-jVSaIZey.js +0 -12
- /package/skill/{Workflows → workflows}/AlphaUpload.md +0 -0
- /package/skill/{Workflows → workflows}/AutoActivation.md +0 -0
- /package/skill/{Workflows → workflows}/Badge.md +0 -0
- /package/skill/{Workflows → workflows}/Composability.md +0 -0
- /package/skill/{Workflows → workflows}/EvolutionMemory.md +0 -0
- /package/skill/{Workflows → workflows}/ExportCanonical.md +0 -0
- /package/skill/{Workflows → workflows}/Hook.md +0 -0
- /package/skill/{Workflows → workflows}/ImportSkillsBench.md +0 -0
- /package/skill/{Workflows → workflows}/Ingest.md +0 -0
- /package/skill/{Workflows → workflows}/PlatformHooks.md +0 -0
- /package/skill/{Workflows → workflows}/Quickstart.md +0 -0
- /package/skill/{Workflows → workflows}/Recover.md +0 -0
- /package/skill/{Workflows → workflows}/Registry.md +0 -0
- /package/skill/{Workflows → workflows}/RepairSkillUsage.md +0 -0
- /package/skill/{Workflows → workflows}/Replay.md +0 -0
- /package/skill/{Workflows → workflows}/Rollback.md +0 -0
- /package/skill/{Workflows → workflows}/Sync.md +0 -0
- /package/skill/{Workflows → workflows}/Telemetry.md +0 -0
- /package/skill/{Workflows → workflows}/Uninstall.md +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { useMemo, useState } from "react";
|
|
5
|
+
import { AlertCircleIcon, RefreshCwIcon } from "lucide-react";
|
|
6
|
+
|
|
7
|
+
import type { AnalyticsResponse } from "@selftune/ui/components";
|
|
8
|
+
import {
|
|
9
|
+
ActivityHeatmap,
|
|
10
|
+
EvolutionROIList,
|
|
11
|
+
PassRateTrendChart,
|
|
12
|
+
SkillRankingsList,
|
|
13
|
+
} from "@selftune/ui/components";
|
|
14
|
+
import {
|
|
15
|
+
Badge,
|
|
16
|
+
Button,
|
|
17
|
+
Card,
|
|
18
|
+
CardContent,
|
|
19
|
+
CardDescription,
|
|
20
|
+
CardHeader,
|
|
21
|
+
CardTitle,
|
|
22
|
+
} from "@selftune/ui/primitives";
|
|
23
|
+
|
|
24
|
+
export interface AnalyticsScreenProps {
|
|
25
|
+
data: AnalyticsResponse | null;
|
|
26
|
+
isLoading: boolean;
|
|
27
|
+
error?: string | null;
|
|
28
|
+
onRefresh(): void;
|
|
29
|
+
onRetry(): void;
|
|
30
|
+
headerActions?: ReactNode;
|
|
31
|
+
insightActions?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseDayBucket(day: string): Date | null {
|
|
35
|
+
const [year, month, date] = day.split("-").map(Number);
|
|
36
|
+
if (!year || !month || !date) return null;
|
|
37
|
+
return new Date(year, month - 1, date);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function AnalyticsScreenSkeleton() {
|
|
41
|
+
return (
|
|
42
|
+
<div className="@container/main flex flex-1 flex-col gap-6 px-4 py-6 lg:px-6">
|
|
43
|
+
<div className="h-12 w-80 animate-pulse rounded-xl bg-card" />
|
|
44
|
+
<div className="grid grid-cols-12 gap-6">
|
|
45
|
+
<div className="col-span-12 h-[380px] animate-pulse rounded-xl bg-card @4xl/main:col-span-8" />
|
|
46
|
+
<div className="col-span-12 h-[380px] animate-pulse rounded-xl bg-card @4xl/main:col-span-4" />
|
|
47
|
+
<div className="col-span-12 h-[320px] animate-pulse rounded-xl bg-card @4xl/main:col-span-7" />
|
|
48
|
+
<div className="col-span-12 h-[320px] animate-pulse rounded-xl bg-card @4xl/main:col-span-5" />
|
|
49
|
+
<div className="col-span-12 h-[140px] animate-pulse rounded-xl bg-card" />
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function AnalyticsScreen({
|
|
56
|
+
data,
|
|
57
|
+
isLoading,
|
|
58
|
+
error,
|
|
59
|
+
onRefresh,
|
|
60
|
+
onRetry,
|
|
61
|
+
headerActions,
|
|
62
|
+
insightActions,
|
|
63
|
+
}: AnalyticsScreenProps) {
|
|
64
|
+
const [chartMode, setChartMode] = useState<"pass_rate" | "volume">("pass_rate");
|
|
65
|
+
|
|
66
|
+
const lastGraded = useMemo(() => {
|
|
67
|
+
if (!data?.pass_rate_trend.length) return null;
|
|
68
|
+
const last = data.pass_rate_trend[data.pass_rate_trend.length - 1];
|
|
69
|
+
if (!last) return null;
|
|
70
|
+
const lastDay = parseDayBucket(last.date);
|
|
71
|
+
if (!lastDay) return null;
|
|
72
|
+
const todayStart = new Date();
|
|
73
|
+
todayStart.setHours(0, 0, 0, 0);
|
|
74
|
+
const diffDays = Math.max(
|
|
75
|
+
0,
|
|
76
|
+
Math.floor((todayStart.getTime() - lastDay.getTime()) / 86_400_000),
|
|
77
|
+
);
|
|
78
|
+
if (diffDays === 0) return "today";
|
|
79
|
+
if (diffDays === 1) return "1d ago";
|
|
80
|
+
return `${diffDays}d ago`;
|
|
81
|
+
}, [data]);
|
|
82
|
+
|
|
83
|
+
const topSkills = useMemo(() => {
|
|
84
|
+
if (!data?.skill_rankings) return [];
|
|
85
|
+
return data.skill_rankings.toSorted((a, b) => b.pass_rate - a.pass_rate).slice(0, 5);
|
|
86
|
+
}, [data]);
|
|
87
|
+
|
|
88
|
+
const avgPassRate = useMemo(() => {
|
|
89
|
+
if (!topSkills.length) return 0;
|
|
90
|
+
return topSkills.reduce((sum, skill) => sum + skill.pass_rate, 0) / topSkills.length;
|
|
91
|
+
}, [topSkills]);
|
|
92
|
+
|
|
93
|
+
const improvedSkills = useMemo(() => {
|
|
94
|
+
if (!data?.evolution_impact) return [];
|
|
95
|
+
return data.evolution_impact.filter((entry) => entry.pass_rate_after > entry.pass_rate_before);
|
|
96
|
+
}, [data]);
|
|
97
|
+
|
|
98
|
+
if (isLoading && !data) {
|
|
99
|
+
return <AnalyticsScreenSkeleton />;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (error && !data) {
|
|
103
|
+
return (
|
|
104
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-4 py-16">
|
|
105
|
+
<AlertCircleIcon className="size-10 text-destructive" />
|
|
106
|
+
<p className="text-sm font-medium text-destructive">{error}</p>
|
|
107
|
+
<Button variant="outline" size="sm" onClick={onRetry}>
|
|
108
|
+
<RefreshCwIcon className="mr-2 size-3.5" />
|
|
109
|
+
Retry
|
|
110
|
+
</Button>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!data) {
|
|
116
|
+
return (
|
|
117
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-2 py-16">
|
|
118
|
+
<p className="text-sm text-muted-foreground">
|
|
119
|
+
No analytics data available yet. Run some sessions and grading first.
|
|
120
|
+
</p>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const { summary } = data;
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div className="@container/main flex flex-1 flex-col gap-8 px-4 py-8 lg:px-6">
|
|
129
|
+
<div className="flex flex-wrap items-start justify-between gap-4">
|
|
130
|
+
<div>
|
|
131
|
+
<div className="flex items-center gap-3">
|
|
132
|
+
<h1 className="font-headline text-4xl font-bold tracking-tight text-foreground">
|
|
133
|
+
Performance Analytics
|
|
134
|
+
</h1>
|
|
135
|
+
<Badge
|
|
136
|
+
variant="outline"
|
|
137
|
+
className="gap-1.5 border-primary/20 bg-primary/10 font-headline text-[10px] uppercase tracking-widest text-primary"
|
|
138
|
+
>
|
|
139
|
+
<span className="size-1.5 animate-pulse rounded-full bg-primary" />
|
|
140
|
+
Live
|
|
141
|
+
</Badge>
|
|
142
|
+
</div>
|
|
143
|
+
<p className="mt-2 text-sm text-muted-foreground">
|
|
144
|
+
{lastGraded ? `Last graded: ${lastGraded}` : "Awaiting first grading run"}
|
|
145
|
+
{summary.active_skills > 0 && ` · ${summary.active_skills} active skills`}
|
|
146
|
+
</p>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<div className="flex items-center gap-2">
|
|
150
|
+
<Button
|
|
151
|
+
variant="secondary"
|
|
152
|
+
size="sm"
|
|
153
|
+
onClick={onRefresh}
|
|
154
|
+
className="gap-1.5 font-headline text-[10px] uppercase tracking-widest"
|
|
155
|
+
>
|
|
156
|
+
<RefreshCwIcon className="size-3" />
|
|
157
|
+
Refresh
|
|
158
|
+
</Button>
|
|
159
|
+
{headerActions}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div className="grid grid-cols-12 gap-6">
|
|
164
|
+
<Card className="col-span-12 border-none bg-muted shadow-none @4xl/main:col-span-8">
|
|
165
|
+
<CardHeader className="pb-2">
|
|
166
|
+
<CardDescription className="font-headline text-[10px] uppercase tracking-widest">
|
|
167
|
+
Evolution Trajectory
|
|
168
|
+
</CardDescription>
|
|
169
|
+
<div className="flex items-center justify-between">
|
|
170
|
+
<CardTitle className="font-headline text-lg">Evolution Impact Curve</CardTitle>
|
|
171
|
+
<div className="flex items-center gap-1 rounded-lg bg-background p-0.5">
|
|
172
|
+
{[
|
|
173
|
+
{ key: "pass_rate" as const, label: "Pass Rate" },
|
|
174
|
+
{ key: "volume" as const, label: "Check Volume" },
|
|
175
|
+
].map((tab) => (
|
|
176
|
+
<button
|
|
177
|
+
key={tab.key}
|
|
178
|
+
type="button"
|
|
179
|
+
onClick={() => setChartMode(tab.key)}
|
|
180
|
+
className={`rounded-md px-3 py-1 text-[10px] font-headline uppercase tracking-widest transition-colors ${
|
|
181
|
+
chartMode === tab.key
|
|
182
|
+
? "bg-secondary text-primary"
|
|
183
|
+
: "text-muted-foreground hover:text-foreground"
|
|
184
|
+
}`}
|
|
185
|
+
>
|
|
186
|
+
{tab.label}
|
|
187
|
+
</button>
|
|
188
|
+
))}
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
</CardHeader>
|
|
192
|
+
<CardContent>
|
|
193
|
+
<PassRateTrendChart data={data.pass_rate_trend} mode={chartMode} />
|
|
194
|
+
</CardContent>
|
|
195
|
+
</Card>
|
|
196
|
+
|
|
197
|
+
<Card className="col-span-12 flex flex-col border-none bg-muted shadow-none @4xl/main:col-span-4">
|
|
198
|
+
<CardHeader className="pb-2">
|
|
199
|
+
<CardDescription className="font-headline text-[10px] uppercase tracking-widest">
|
|
200
|
+
Skill Rankings
|
|
201
|
+
</CardDescription>
|
|
202
|
+
<CardTitle className="font-headline text-lg">Skill Performance</CardTitle>
|
|
203
|
+
</CardHeader>
|
|
204
|
+
<CardContent className="flex flex-1 flex-col">
|
|
205
|
+
<SkillRankingsList skills={topSkills} />
|
|
206
|
+
|
|
207
|
+
<div className="mt-5 border-t border-border/20 pt-4">
|
|
208
|
+
<div className="flex items-center justify-between">
|
|
209
|
+
<span className="font-headline text-[10px] uppercase tracking-widest text-muted-foreground">
|
|
210
|
+
Avg Pass Rate
|
|
211
|
+
</span>
|
|
212
|
+
<span className="font-headline text-2xl font-bold text-primary">
|
|
213
|
+
{topSkills.length > 0 ? `${Math.round(avgPassRate * 100)}%` : "--"}
|
|
214
|
+
</span>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</CardContent>
|
|
218
|
+
</Card>
|
|
219
|
+
|
|
220
|
+
<Card className="col-span-12 border-none bg-muted shadow-none @4xl/main:col-span-7">
|
|
221
|
+
<CardHeader className="pb-2">
|
|
222
|
+
<CardDescription className="font-headline text-[10px] uppercase tracking-widest">
|
|
223
|
+
Grading Activity
|
|
224
|
+
</CardDescription>
|
|
225
|
+
<CardTitle className="font-headline text-lg">Check Activity Over Time</CardTitle>
|
|
226
|
+
</CardHeader>
|
|
227
|
+
<CardContent className="flex flex-1 flex-col">
|
|
228
|
+
<ActivityHeatmap data={data.daily_activity} />
|
|
229
|
+
</CardContent>
|
|
230
|
+
</Card>
|
|
231
|
+
|
|
232
|
+
<Card className="col-span-12 border-none bg-muted shadow-none @4xl/main:col-span-5">
|
|
233
|
+
<CardHeader className="pb-2">
|
|
234
|
+
<CardDescription className="font-headline text-[10px] uppercase tracking-widest">
|
|
235
|
+
Evolution Outcomes
|
|
236
|
+
</CardDescription>
|
|
237
|
+
<CardTitle className="font-headline text-lg">Evolution ROI</CardTitle>
|
|
238
|
+
</CardHeader>
|
|
239
|
+
<CardContent>
|
|
240
|
+
<EvolutionROIList impacts={data.evolution_impact} />
|
|
241
|
+
</CardContent>
|
|
242
|
+
</Card>
|
|
243
|
+
|
|
244
|
+
<Card className="col-span-12 border-none bg-muted/60 shadow-none backdrop-blur-md">
|
|
245
|
+
<CardContent className="pt-6">
|
|
246
|
+
<div className="flex flex-col items-start justify-between gap-4 @3xl/main:flex-row @3xl/main:items-center">
|
|
247
|
+
<div>
|
|
248
|
+
<p className="mb-2 font-headline text-[10px] uppercase tracking-widest text-muted-foreground">
|
|
249
|
+
Data-Driven Insight
|
|
250
|
+
</p>
|
|
251
|
+
<p className="max-w-2xl text-[15px] leading-relaxed text-foreground">
|
|
252
|
+
{improvedSkills.length > 0
|
|
253
|
+
? `${improvedSkills.length} skill${improvedSkills.length !== 1 ? "s" : ""} improved after evolution, averaging ${Math.round(summary.avg_improvement * 100)}% improvement. ${summary.total_checks_30d} checks processed in the last 30 days across ${summary.active_skills} active skills.`
|
|
254
|
+
: summary.total_checks_30d > 0
|
|
255
|
+
? `${summary.total_checks_30d} checks processed in the last 30 days across ${summary.active_skills} active skills. Run an evolution cycle to start improving skill pass rates.`
|
|
256
|
+
: "Start grading sessions to generate performance insights. Run selftune orchestrate to begin the autonomous improvement loop."}
|
|
257
|
+
</p>
|
|
258
|
+
</div>
|
|
259
|
+
{insightActions ? (
|
|
260
|
+
<div className="flex shrink-0 items-center gap-3">{insightActions}</div>
|
|
261
|
+
) : null}
|
|
262
|
+
</div>
|
|
263
|
+
</CardContent>
|
|
264
|
+
</Card>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="flex items-center justify-between px-1 font-headline text-[10px] uppercase tracking-widest text-muted-foreground">
|
|
268
|
+
<span>
|
|
269
|
+
{summary.total_evolutions} evolution{summary.total_evolutions !== 1 ? "s" : ""} deployed
|
|
270
|
+
</span>
|
|
271
|
+
<span>{summary.total_checks_30d} checks (30d)</span>
|
|
272
|
+
<span>
|
|
273
|
+
{summary.active_skills} active skill{summary.active_skills !== 1 ? "s" : ""}
|
|
274
|
+
</span>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AnalyticsScreen, type AnalyticsScreenProps } from "./AnalyticsScreen";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export { AnalyticsScreen, type AnalyticsScreenProps } from "./analytics/index";
|
|
2
|
+
export {
|
|
3
|
+
OverviewComparisonSurface,
|
|
4
|
+
OverviewCompositionSurface,
|
|
5
|
+
OverviewCoreSurface,
|
|
6
|
+
OverviewOnboardingBanner,
|
|
7
|
+
OverviewRunSummary,
|
|
8
|
+
type OverviewComparisonRow,
|
|
9
|
+
type OverviewComparisonSurfaceProps,
|
|
10
|
+
type OverviewComparisonWatchlistConfig,
|
|
11
|
+
type OverviewCompositionSurfaceProps,
|
|
12
|
+
type OverviewCoreSurfaceProps,
|
|
13
|
+
type OverviewOnboardingBannerProps,
|
|
14
|
+
type OverviewRunSummaryProps,
|
|
15
|
+
} from "./overview/index";
|
|
16
|
+
export {
|
|
17
|
+
SkillReportEvidenceSection,
|
|
18
|
+
SkillReportEvidenceRail,
|
|
19
|
+
SkillReportInvocationsSection,
|
|
20
|
+
SkillReportScaffold,
|
|
21
|
+
SkillReportTabs,
|
|
22
|
+
SkillReportTrustBadge,
|
|
23
|
+
getSkillReportTrustBadgeConfig,
|
|
24
|
+
type SkillReportEvidenceSectionProps,
|
|
25
|
+
type SkillReportEvidenceRailProps,
|
|
26
|
+
type SkillReportInvocationsSectionProps,
|
|
27
|
+
type SkillReportNextAction,
|
|
28
|
+
type SkillReportScaffoldProps,
|
|
29
|
+
type SkillReportTabDefinition,
|
|
30
|
+
type SkillReportTabsProps,
|
|
31
|
+
} from "./skill-report/index";
|
|
32
|
+
export {
|
|
33
|
+
SkillsLibraryScreen,
|
|
34
|
+
type SkillsLibraryHero,
|
|
35
|
+
type SkillsLibraryPendingProposal,
|
|
36
|
+
type SkillsLibraryScreenProps,
|
|
37
|
+
} from "./skills/index";
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getOverviewWatchlistSyncKey,
|
|
5
|
+
resolveOverviewWatchlistChange,
|
|
6
|
+
resolveOverviewWatchlistLoad,
|
|
7
|
+
} from "./OverviewComparisonSurface";
|
|
8
|
+
|
|
9
|
+
describe("resolveOverviewWatchlistChange", () => {
|
|
10
|
+
it("prefers an explicit watchlist change handler", () => {
|
|
11
|
+
const explicit = vi.fn();
|
|
12
|
+
const host = {
|
|
13
|
+
actions: {
|
|
14
|
+
updateOverviewWatchlist: vi.fn(),
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
expect(
|
|
19
|
+
resolveOverviewWatchlistChange(
|
|
20
|
+
{
|
|
21
|
+
initialSkills: [],
|
|
22
|
+
onChange: explicit,
|
|
23
|
+
},
|
|
24
|
+
host as never,
|
|
25
|
+
),
|
|
26
|
+
).toBe(explicit);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("falls back to the host adapter watchlist action", () => {
|
|
30
|
+
const hostAction = vi.fn();
|
|
31
|
+
|
|
32
|
+
expect(
|
|
33
|
+
resolveOverviewWatchlistChange(
|
|
34
|
+
{
|
|
35
|
+
initialSkills: ["selftune"],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
actions: {
|
|
39
|
+
openUpgrade: vi.fn(),
|
|
40
|
+
updateOverviewWatchlist: hostAction,
|
|
41
|
+
},
|
|
42
|
+
} as never,
|
|
43
|
+
),
|
|
44
|
+
).toBe(hostAction);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("returns undefined when no mutation handler exists", () => {
|
|
48
|
+
expect(resolveOverviewWatchlistChange(undefined, null)).toBeUndefined();
|
|
49
|
+
expect(
|
|
50
|
+
resolveOverviewWatchlistChange(
|
|
51
|
+
{
|
|
52
|
+
initialSkills: [],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
actions: {
|
|
56
|
+
openUpgrade: vi.fn(),
|
|
57
|
+
},
|
|
58
|
+
} as never,
|
|
59
|
+
),
|
|
60
|
+
).toBeUndefined();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("resolveOverviewWatchlistLoad", () => {
|
|
65
|
+
it("returns the host adapter loader when present", () => {
|
|
66
|
+
const hostLoader = vi.fn();
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
resolveOverviewWatchlistLoad({
|
|
70
|
+
actions: {
|
|
71
|
+
openUpgrade: vi.fn(),
|
|
72
|
+
getOverviewWatchlist: hostLoader,
|
|
73
|
+
},
|
|
74
|
+
} as never),
|
|
75
|
+
).toBe(hostLoader);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("returns undefined when the host does not provide a loader", () => {
|
|
79
|
+
expect(
|
|
80
|
+
resolveOverviewWatchlistLoad({
|
|
81
|
+
actions: {
|
|
82
|
+
openUpgrade: vi.fn(),
|
|
83
|
+
},
|
|
84
|
+
} as never),
|
|
85
|
+
).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("getOverviewWatchlistSyncKey", () => {
|
|
90
|
+
it("stays stable for value-equal arrays across rerenders", () => {
|
|
91
|
+
expect(getOverviewWatchlistSyncKey(["alpha", "beta"])).toBe(
|
|
92
|
+
getOverviewWatchlistSyncKey(["alpha", "beta"]),
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("changes when the actual initial watchlist contents change", () => {
|
|
97
|
+
expect(getOverviewWatchlistSyncKey(["alpha", "beta"])).not.toBe(
|
|
98
|
+
getOverviewWatchlistSyncKey(["alpha", "gamma"]),
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|