selftune 0.2.9 → 0.2.12
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/README.md +35 -35
- package/apps/local-dashboard/dist/assets/index-4_dAY17K.js +16 -0
- package/apps/local-dashboard/dist/assets/index-BxV5WZHc.css +2 -0
- package/apps/local-dashboard/dist/assets/rolldown-runtime-Dw2cE7zH.js +1 -0
- package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +11 -0
- package/apps/local-dashboard/dist/assets/vendor-table-pHbDxq36.js +8 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-7xD7fNEU.js +12 -0
- package/apps/local-dashboard/dist/index.html +16 -15
- package/bin/selftune.cjs +1 -1
- package/cli/selftune/activation-rules.ts +1 -0
- package/cli/selftune/alpha-upload/build-payloads.ts +18 -2
- package/cli/selftune/alpha-upload/stage-canonical.ts +94 -0
- package/cli/selftune/auth/device-code.ts +32 -0
- package/cli/selftune/auto-update.ts +12 -0
- package/cli/selftune/badge/badge.ts +1 -0
- package/cli/selftune/canonical-export.ts +5 -0
- package/cli/selftune/claude-agents.ts +154 -0
- package/cli/selftune/contribute/bundle.ts +1 -0
- package/cli/selftune/contribute/contribute.ts +1 -0
- package/cli/selftune/cron/setup.ts +2 -2
- package/cli/selftune/dashboard-server.ts +1 -0
- package/cli/selftune/eval/hooks-to-evals.ts +1 -0
- package/cli/selftune/eval/import-skillsbench.ts +1 -0
- package/cli/selftune/eval/synthetic-evals.ts +2 -3
- package/cli/selftune/eval/unit-test.ts +1 -0
- package/cli/selftune/evolution/deploy-proposal.ts +9 -238
- package/cli/selftune/evolution/evolve-body.ts +93 -6
- package/cli/selftune/evolution/evolve.ts +3 -7
- package/cli/selftune/evolution/propose-body.ts +3 -2
- package/cli/selftune/evolution/propose-routing.ts +3 -2
- package/cli/selftune/evolution/refine-body.ts +3 -2
- package/cli/selftune/evolution/rollback.ts +1 -1
- package/cli/selftune/export.ts +1 -0
- package/cli/selftune/grading/grade-session.ts +8 -0
- package/cli/selftune/hooks/auto-activate.ts +1 -0
- package/cli/selftune/hooks/evolution-guard.ts +1 -1
- package/cli/selftune/hooks/prompt-log.ts +1 -0
- package/cli/selftune/hooks/session-stop.ts +34 -40
- package/cli/selftune/hooks/skill-change-guard.ts +1 -0
- package/cli/selftune/hooks/skill-eval.ts +1 -1
- package/cli/selftune/index.ts +23 -14
- package/cli/selftune/ingestors/claude-replay.ts +1 -0
- package/cli/selftune/ingestors/codex-rollout.ts +1 -0
- package/cli/selftune/ingestors/codex-wrapper.ts +1 -0
- package/cli/selftune/ingestors/openclaw-ingest.ts +1 -0
- package/cli/selftune/ingestors/opencode-ingest.ts +1 -0
- package/cli/selftune/init.ts +121 -29
- package/cli/selftune/localdb/db.ts +1 -0
- package/cli/selftune/localdb/direct-write.ts +39 -0
- package/cli/selftune/localdb/materialize.ts +2 -0
- package/cli/selftune/localdb/queries.ts +53 -0
- package/cli/selftune/localdb/schema.ts +28 -0
- package/cli/selftune/normalization.ts +1 -0
- package/cli/selftune/observability.ts +1 -0
- package/cli/selftune/repair/skill-usage.ts +1 -0
- package/cli/selftune/routes/orchestrate-runs.ts +1 -0
- package/cli/selftune/routes/overview.ts +1 -0
- package/cli/selftune/routes/report.ts +1 -1
- package/cli/selftune/routes/skill-report.ts +2 -1
- package/cli/selftune/status.ts +1 -1
- package/cli/selftune/sync.ts +30 -1
- package/cli/selftune/uninstall.ts +412 -0
- package/cli/selftune/utils/canonical-log.ts +2 -0
- package/cli/selftune/utils/frontmatter.ts +50 -7
- package/cli/selftune/utils/jsonl.ts +1 -0
- package/cli/selftune/utils/llm-call.ts +131 -3
- package/cli/selftune/utils/skill-log.ts +1 -0
- package/cli/selftune/utils/transcript.ts +1 -0
- package/cli/selftune/utils/trigger-check.ts +1 -1
- package/cli/selftune/workflows/skill-md-writer.ts +5 -5
- package/cli/selftune/workflows/workflows.ts +1 -0
- package/package.json +37 -33
- package/packages/telemetry-contract/fixtures/golden.test.ts +1 -0
- package/packages/telemetry-contract/package.json +1 -1
- package/packages/telemetry-contract/src/schemas.ts +1 -0
- package/packages/telemetry-contract/tests/compatibility.test.ts +1 -0
- package/packages/ui/README.md +35 -34
- package/packages/ui/package.json +3 -3
- package/packages/ui/src/components/ActivityTimeline.tsx +50 -43
- package/packages/ui/src/components/EvidenceViewer.tsx +306 -182
- package/packages/ui/src/components/EvolutionTimeline.tsx +83 -72
- package/packages/ui/src/components/InfoTip.tsx +4 -3
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +60 -53
- package/packages/ui/src/components/section-cards.tsx +20 -25
- package/packages/ui/src/components/skill-health-grid.tsx +213 -193
- package/packages/ui/src/lib/constants.tsx +1 -0
- package/packages/ui/src/primitives/badge.tsx +12 -15
- package/packages/ui/src/primitives/button.tsx +7 -7
- package/packages/ui/src/primitives/card.tsx +15 -26
- package/packages/ui/src/primitives/checkbox.tsx +7 -8
- package/packages/ui/src/primitives/collapsible.tsx +5 -5
- package/packages/ui/src/primitives/dropdown-menu.tsx +45 -55
- package/packages/ui/src/primitives/label.tsx +6 -6
- package/packages/ui/src/primitives/select.tsx +28 -37
- package/packages/ui/src/primitives/table.tsx +17 -44
- package/packages/ui/src/primitives/tabs.tsx +14 -21
- package/packages/ui/src/primitives/tooltip.tsx +10 -22
- package/skill/SKILL.md +70 -57
- package/skill/Workflows/AlphaUpload.md +4 -4
- package/skill/Workflows/AutoActivation.md +11 -6
- package/skill/Workflows/Badge.md +22 -16
- package/skill/Workflows/Baseline.md +34 -36
- package/skill/Workflows/Composability.md +16 -11
- package/skill/Workflows/Contribute.md +26 -21
- package/skill/Workflows/Cron.md +23 -22
- package/skill/Workflows/Dashboard.md +32 -27
- package/skill/Workflows/Doctor.md +33 -27
- package/skill/Workflows/Evals.md +48 -47
- package/skill/Workflows/EvolutionMemory.md +31 -21
- package/skill/Workflows/Evolve.md +84 -82
- package/skill/Workflows/EvolveBody.md +58 -47
- package/skill/Workflows/Grade.md +16 -13
- package/skill/Workflows/ImportSkillsBench.md +9 -6
- package/skill/Workflows/Ingest.md +36 -21
- package/skill/Workflows/Initialize.md +108 -40
- package/skill/Workflows/Orchestrate.md +22 -16
- package/skill/Workflows/Replay.md +12 -7
- package/skill/Workflows/Rollback.md +13 -6
- package/skill/Workflows/Schedule.md +6 -6
- package/skill/Workflows/Sync.md +18 -11
- package/skill/Workflows/UnitTest.md +28 -17
- package/skill/Workflows/Watch.md +28 -21
- package/skill/agents/diagnosis-analyst.md +11 -0
- package/skill/agents/evolution-reviewer.md +15 -1
- package/skill/agents/integration-guide.md +10 -0
- package/skill/agents/pattern-analyst.md +12 -1
- package/skill/references/grading-methodology.md +23 -24
- package/skill/references/interactive-config.md +7 -7
- package/skill/references/invocation-taxonomy.md +22 -20
- package/skill/references/logs.md +14 -6
- package/skill/references/setup-patterns.md +4 -2
- package/.claude/agents/diagnosis-analyst.md +0 -156
- package/.claude/agents/evolution-reviewer.md +0 -180
- package/.claude/agents/integration-guide.md +0 -212
- package/.claude/agents/pattern-analyst.md +0 -160
- package/apps/local-dashboard/dist/assets/index-Bs3Y4ixf.css +0 -1
- package/apps/local-dashboard/dist/assets/index-C4UYGWKr.js +0 -15
- package/apps/local-dashboard/dist/assets/vendor-react-BQH_6WrG.js +0 -60
- package/apps/local-dashboard/dist/assets/vendor-table-dK1QMLq9.js +0 -26
- package/apps/local-dashboard/dist/assets/vendor-ui-CO2mrx6e.js +0 -341
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { useState } from "react"
|
|
2
|
-
import { Badge } from "../primitives/badge"
|
|
3
|
-
import { cn } from "../lib/utils"
|
|
4
|
-
import type { EvalSnapshot, EvolutionEntry } from "../types"
|
|
5
|
-
import { timeAgo } from "../lib/format"
|
|
6
1
|
import {
|
|
7
2
|
CircleDotIcon,
|
|
8
3
|
RocketIcon,
|
|
@@ -13,7 +8,13 @@ import {
|
|
|
13
8
|
TrendingDownIcon,
|
|
14
9
|
ChevronDownIcon,
|
|
15
10
|
ChevronRightIcon,
|
|
16
|
-
} from "lucide-react"
|
|
11
|
+
} from "lucide-react";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
|
|
14
|
+
import { timeAgo } from "../lib/format";
|
|
15
|
+
import { cn } from "../lib/utils";
|
|
16
|
+
import { Badge } from "../primitives/badge";
|
|
17
|
+
import type { EvalSnapshot, EvolutionEntry } from "../types";
|
|
17
18
|
|
|
18
19
|
const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
19
20
|
created: <CircleDotIcon className="size-3.5" />,
|
|
@@ -21,7 +22,7 @@ const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
|
21
22
|
deployed: <RocketIcon className="size-3.5" />,
|
|
22
23
|
rejected: <XCircleIcon className="size-3.5" />,
|
|
23
24
|
rolled_back: <UndoIcon className="size-3.5" />,
|
|
24
|
-
}
|
|
25
|
+
};
|
|
25
26
|
|
|
26
27
|
const ACTION_COLOR: Record<string, string> = {
|
|
27
28
|
created: "bg-blue-500",
|
|
@@ -29,7 +30,7 @@ const ACTION_COLOR: Record<string, string> = {
|
|
|
29
30
|
deployed: "bg-emerald-500",
|
|
30
31
|
rejected: "bg-red-500",
|
|
31
32
|
rolled_back: "bg-red-400",
|
|
32
|
-
}
|
|
33
|
+
};
|
|
33
34
|
|
|
34
35
|
const ACTION_RING: Record<string, string> = {
|
|
35
36
|
created: "ring-blue-500/30",
|
|
@@ -37,7 +38,7 @@ const ACTION_RING: Record<string, string> = {
|
|
|
37
38
|
deployed: "ring-emerald-500/30",
|
|
38
39
|
rejected: "ring-red-500/30",
|
|
39
40
|
rolled_back: "ring-red-400/30",
|
|
40
|
-
}
|
|
41
|
+
};
|
|
41
42
|
|
|
42
43
|
const ACTION_LINE: Record<string, string> = {
|
|
43
44
|
created: "bg-blue-500/30",
|
|
@@ -45,58 +46,65 @@ const ACTION_LINE: Record<string, string> = {
|
|
|
45
46
|
deployed: "bg-emerald-500/30",
|
|
46
47
|
rejected: "bg-red-500/30",
|
|
47
48
|
rolled_back: "bg-red-400/30",
|
|
48
|
-
}
|
|
49
|
+
};
|
|
49
50
|
|
|
50
51
|
interface Props {
|
|
51
|
-
entries: EvolutionEntry[]
|
|
52
|
-
selectedProposalId: string | null
|
|
53
|
-
onSelect: (proposalId: string) => void
|
|
52
|
+
entries: EvolutionEntry[];
|
|
53
|
+
selectedProposalId: string | null;
|
|
54
|
+
onSelect: (proposalId: string) => void;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/** Group evolution entries by proposal_id, ordered newest-first. */
|
|
57
58
|
function groupByProposal(entries: EvolutionEntry[]) {
|
|
58
|
-
const map = new Map<string, EvolutionEntry[]>()
|
|
59
|
+
const map = new Map<string, EvolutionEntry[]>();
|
|
59
60
|
for (const e of entries) {
|
|
60
|
-
const group = map.get(e.proposal_id) ?? []
|
|
61
|
-
group.push(e)
|
|
62
|
-
map.set(e.proposal_id, group)
|
|
61
|
+
const group = map.get(e.proposal_id) ?? [];
|
|
62
|
+
group.push(e);
|
|
63
|
+
map.set(e.proposal_id, group);
|
|
63
64
|
}
|
|
64
65
|
for (const group of map.values()) {
|
|
65
|
-
group.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime())
|
|
66
|
+
group.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
66
67
|
}
|
|
67
68
|
return Array.from(map.entries()).sort((a, b) => {
|
|
68
|
-
const aLast = a[1][a[1].length - 1]
|
|
69
|
-
const bLast = b[1][b[1].length - 1]
|
|
70
|
-
return new Date(bLast.timestamp).getTime() - new Date(aLast.timestamp).getTime()
|
|
71
|
-
})
|
|
69
|
+
const aLast = a[1][a[1].length - 1];
|
|
70
|
+
const bLast = b[1][b[1].length - 1];
|
|
71
|
+
return new Date(bLast.timestamp).getTime() - new Date(aLast.timestamp).getTime();
|
|
72
|
+
});
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
function terminalAction(entries: EvolutionEntry[]): string {
|
|
75
|
-
return entries[entries.length - 1].action
|
|
76
|
+
return entries[entries.length - 1].action;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
/** Find the best eval_snapshot across all steps in a proposal group */
|
|
79
80
|
function findEvalSnapshot(steps: EvolutionEntry[]): EvalSnapshot | null {
|
|
80
81
|
for (let i = steps.length - 1; i >= 0; i--) {
|
|
81
|
-
if (steps[i].eval_snapshot) return steps[i].eval_snapshot
|
|
82
|
+
if (steps[i].eval_snapshot) return steps[i].eval_snapshot!;
|
|
82
83
|
}
|
|
83
|
-
return null
|
|
84
|
+
return null;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
function PassRateDelta({ snapshot }: { snapshot: EvalSnapshot }) {
|
|
87
|
-
const net = snapshot.net_change
|
|
88
|
-
if (net === undefined || net === null) return null
|
|
89
|
-
const pct = Math.round(net * 100)
|
|
90
|
-
const isPositive = pct > 0
|
|
88
|
+
const net = snapshot.net_change;
|
|
89
|
+
if (net === undefined || net === null) return null;
|
|
90
|
+
const pct = Math.round(net * 100);
|
|
91
|
+
const isPositive = pct > 0;
|
|
91
92
|
return (
|
|
92
|
-
<span
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
<span
|
|
94
|
+
className={cn(
|
|
95
|
+
"inline-flex items-center gap-0.5 text-[10px] font-mono font-medium",
|
|
96
|
+
isPositive ? "text-emerald-600 dark:text-emerald-400" : "text-red-500",
|
|
97
|
+
)}
|
|
98
|
+
>
|
|
99
|
+
{isPositive ? (
|
|
100
|
+
<TrendingUpIcon className="size-2.5" />
|
|
101
|
+
) : (
|
|
102
|
+
<TrendingDownIcon className="size-2.5" />
|
|
103
|
+
)}
|
|
104
|
+
{isPositive ? "+" : ""}
|
|
105
|
+
{pct}%
|
|
98
106
|
</span>
|
|
99
|
-
)
|
|
107
|
+
);
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
const LIFECYCLE_STEPS = [
|
|
@@ -105,10 +113,10 @@ const LIFECYCLE_STEPS = [
|
|
|
105
113
|
{ action: "deployed", label: "Deployed", desc: "Accepted and applied to skill file" },
|
|
106
114
|
{ action: "rejected", label: "Rejected", desc: "Failed validation criteria" },
|
|
107
115
|
{ action: "rolled_back", label: "Rolled Back", desc: "Reverted after deployment" },
|
|
108
|
-
]
|
|
116
|
+
];
|
|
109
117
|
|
|
110
118
|
function LifecycleLegend() {
|
|
111
|
-
const [open, setOpen] = useState(false)
|
|
119
|
+
const [open, setOpen] = useState(false);
|
|
112
120
|
|
|
113
121
|
return (
|
|
114
122
|
<div className="px-2 pb-2">
|
|
@@ -124,10 +132,7 @@ function LifecycleLegend() {
|
|
|
124
132
|
<div className="mt-1.5 space-y-1.5 rounded-md border bg-muted/30 p-2">
|
|
125
133
|
{LIFECYCLE_STEPS.map((step) => (
|
|
126
134
|
<div key={step.action} className="flex items-start gap-2">
|
|
127
|
-
<div className={cn(
|
|
128
|
-
"size-2 rounded-full mt-1 shrink-0",
|
|
129
|
-
ACTION_COLOR[step.action],
|
|
130
|
-
)} />
|
|
135
|
+
<div className={cn("size-2 rounded-full mt-1 shrink-0", ACTION_COLOR[step.action])} />
|
|
131
136
|
<div className="min-w-0">
|
|
132
137
|
<span className="text-[10px] font-medium">{step.label}</span>
|
|
133
138
|
<p className="text-[10px] text-muted-foreground/70 leading-tight">{step.desc}</p>
|
|
@@ -137,18 +142,18 @@ function LifecycleLegend() {
|
|
|
137
142
|
</div>
|
|
138
143
|
)}
|
|
139
144
|
</div>
|
|
140
|
-
)
|
|
145
|
+
);
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Props) {
|
|
144
|
-
const groups = groupByProposal(entries)
|
|
149
|
+
const groups = groupByProposal(entries);
|
|
145
150
|
|
|
146
151
|
if (groups.length === 0) {
|
|
147
152
|
return (
|
|
148
153
|
<div className="flex items-center justify-center rounded-lg border border-dashed py-6 px-3">
|
|
149
154
|
<p className="text-xs text-muted-foreground">No evolution history yet</p>
|
|
150
155
|
</div>
|
|
151
|
-
)
|
|
156
|
+
);
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
return (
|
|
@@ -159,29 +164,29 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
159
164
|
<LifecycleLegend />
|
|
160
165
|
<nav className="flex flex-col">
|
|
161
166
|
{groups.map(([proposalId, steps], groupIdx) => {
|
|
162
|
-
const terminal = terminalAction(steps)
|
|
163
|
-
const isSelected = selectedProposalId === proposalId
|
|
164
|
-
const lastStep = steps[steps.length - 1]
|
|
165
|
-
const dotColor = ACTION_COLOR[terminal] ?? "bg-muted-foreground"
|
|
166
|
-
const ringColor = ACTION_RING[terminal] ?? "ring-muted-foreground/30"
|
|
167
|
-
const lineColor = ACTION_LINE[terminal] ?? "bg-border"
|
|
168
|
-
const isLast = groupIdx === groups.length - 1
|
|
169
|
-
const snapshot = findEvalSnapshot(steps)
|
|
167
|
+
const terminal = terminalAction(steps);
|
|
168
|
+
const isSelected = selectedProposalId === proposalId;
|
|
169
|
+
const lastStep = steps[steps.length - 1];
|
|
170
|
+
const dotColor = ACTION_COLOR[terminal] ?? "bg-muted-foreground";
|
|
171
|
+
const ringColor = ACTION_RING[terminal] ?? "ring-muted-foreground/30";
|
|
172
|
+
const lineColor = ACTION_LINE[terminal] ?? "bg-border";
|
|
173
|
+
const isLast = groupIdx === groups.length - 1;
|
|
174
|
+
const snapshot = findEvalSnapshot(steps);
|
|
170
175
|
|
|
171
176
|
return (
|
|
172
177
|
<div key={proposalId} className="relative flex gap-3">
|
|
173
178
|
{/* Vertical connector line */}
|
|
174
179
|
<div className="flex flex-col items-center">
|
|
175
|
-
<div
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
<div
|
|
181
|
+
className={cn(
|
|
182
|
+
"flex items-center justify-center size-7 rounded-full ring-2 text-white shrink-0 z-10",
|
|
183
|
+
dotColor,
|
|
184
|
+
ringColor,
|
|
185
|
+
)}
|
|
186
|
+
>
|
|
180
187
|
{ACTION_ICON[terminal] ?? <CircleDotIcon className="size-3.5" />}
|
|
181
188
|
</div>
|
|
182
|
-
{!isLast && (
|
|
183
|
-
<div className={cn("w-0.5 flex-1 min-h-[16px]", lineColor)} />
|
|
184
|
-
)}
|
|
189
|
+
{!isLast && <div className={cn("w-0.5 flex-1 min-h-[16px]", lineColor)} />}
|
|
185
190
|
</div>
|
|
186
191
|
|
|
187
192
|
{/* Content */}
|
|
@@ -191,14 +196,18 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
191
196
|
className={cn(
|
|
192
197
|
"flex-1 min-w-0 rounded-md px-2.5 py-2 text-left transition-all mb-1",
|
|
193
198
|
"hover:bg-accent/50",
|
|
194
|
-
isSelected
|
|
195
|
-
? "bg-primary/5 ring-1 ring-primary/20"
|
|
196
|
-
: "",
|
|
199
|
+
isSelected ? "bg-primary/5 ring-1 ring-primary/20" : "",
|
|
197
200
|
)}
|
|
198
201
|
>
|
|
199
202
|
<div className="flex items-center gap-1.5">
|
|
200
203
|
<Badge
|
|
201
|
-
variant={
|
|
204
|
+
variant={
|
|
205
|
+
terminal === "deployed"
|
|
206
|
+
? "default"
|
|
207
|
+
: terminal === "rejected" || terminal === "rolled_back"
|
|
208
|
+
? "destructive"
|
|
209
|
+
: "secondary"
|
|
210
|
+
}
|
|
202
211
|
className="text-[10px] capitalize"
|
|
203
212
|
>
|
|
204
213
|
{terminal.replace("_", " ")}
|
|
@@ -211,11 +220,13 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
211
220
|
{snapshot && (
|
|
212
221
|
<div className="flex items-center gap-1.5 mt-1">
|
|
213
222
|
<PassRateDelta snapshot={snapshot} />
|
|
214
|
-
{snapshot.before_pass_rate !== undefined &&
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
{snapshot.before_pass_rate !== undefined &&
|
|
224
|
+
snapshot.after_pass_rate !== undefined && (
|
|
225
|
+
<span className="text-[10px] text-muted-foreground/60 font-mono">
|
|
226
|
+
{Math.round(snapshot.before_pass_rate * 100)}→
|
|
227
|
+
{Math.round(snapshot.after_pass_rate * 100)}%
|
|
228
|
+
</span>
|
|
229
|
+
)}
|
|
219
230
|
</div>
|
|
220
231
|
)}
|
|
221
232
|
<div className="flex items-center gap-1.5 mt-1">
|
|
@@ -244,9 +255,9 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
244
255
|
)}
|
|
245
256
|
</button>
|
|
246
257
|
</div>
|
|
247
|
-
)
|
|
258
|
+
);
|
|
248
259
|
})}
|
|
249
260
|
</nav>
|
|
250
261
|
</div>
|
|
251
|
-
)
|
|
262
|
+
);
|
|
252
263
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { InfoIcon } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../primitives/tooltip";
|
|
3
4
|
|
|
4
5
|
/** Small info icon that shows a tooltip on hover. Used to explain metrics and concepts. */
|
|
5
6
|
export function InfoTip({ text }: { text: string }) {
|
|
@@ -15,5 +16,5 @@ export function InfoTip({ text }: { text: string }) {
|
|
|
15
16
|
{text}
|
|
16
17
|
</TooltipContent>
|
|
17
18
|
</Tooltip>
|
|
18
|
-
)
|
|
19
|
+
);
|
|
19
20
|
}
|
|
@@ -1,33 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "../primitives/card"
|
|
10
|
-
import {
|
|
11
|
-
Collapsible,
|
|
12
|
-
CollapsibleContent,
|
|
13
|
-
CollapsibleTrigger,
|
|
14
|
-
} from "../primitives/collapsible"
|
|
15
|
-
import type { OrchestrateRunReport, OrchestrateRunSkillAction } from "../types"
|
|
16
|
-
import { timeAgo } from "../lib/format"
|
|
17
|
-
import {
|
|
18
|
-
BotIcon,
|
|
19
|
-
CheckCircleIcon,
|
|
20
|
-
ChevronRightIcon,
|
|
21
|
-
EyeIcon,
|
|
22
|
-
SkipForwardIcon,
|
|
23
|
-
ZapIcon,
|
|
24
|
-
} from "lucide-react"
|
|
1
|
+
import { BotIcon, ChevronRightIcon, EyeIcon, SkipForwardIcon, ZapIcon } from "lucide-react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
import { timeAgo } from "../lib/format";
|
|
5
|
+
import { Badge } from "../primitives/badge";
|
|
6
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../primitives/card";
|
|
7
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../primitives/collapsible";
|
|
8
|
+
import type { OrchestrateRunReport, OrchestrateRunSkillAction } from "../types";
|
|
25
9
|
|
|
26
10
|
const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
27
11
|
evolve: <ZapIcon className="size-3 text-amber-500" />,
|
|
28
12
|
watch: <EyeIcon className="size-3 text-blue-500" />,
|
|
29
13
|
skip: <SkipForwardIcon className="size-3 text-muted-foreground" />,
|
|
30
|
-
}
|
|
14
|
+
};
|
|
31
15
|
|
|
32
16
|
function SkillActionRow({ action }: { action: OrchestrateRunSkillAction }) {
|
|
33
17
|
return (
|
|
@@ -38,18 +22,25 @@ function SkillActionRow({ action }: { action: OrchestrateRunSkillAction }) {
|
|
|
38
22
|
<span className="text-xs font-medium truncate">{action.skill}</span>
|
|
39
23
|
<Badge
|
|
40
24
|
variant={
|
|
41
|
-
action.rolledBack
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
action.rolledBack
|
|
26
|
+
? "destructive"
|
|
27
|
+
: action.action === "evolve" && action.deployed
|
|
28
|
+
? "default"
|
|
29
|
+
: action.action === "evolve"
|
|
30
|
+
? "secondary"
|
|
31
|
+
: action.action === "watch"
|
|
32
|
+
? "outline"
|
|
33
|
+
: "secondary"
|
|
46
34
|
}
|
|
47
35
|
className="text-[10px] h-4 px-1.5 shrink-0"
|
|
48
36
|
>
|
|
49
|
-
{action.rolledBack
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
{action.rolledBack
|
|
38
|
+
? "rolled back"
|
|
39
|
+
: action.action === "evolve" && action.deployed
|
|
40
|
+
? "deployed"
|
|
41
|
+
: action.action === "evolve"
|
|
42
|
+
? "evolved"
|
|
43
|
+
: action.action}
|
|
53
44
|
</Badge>
|
|
54
45
|
{action.alert && (
|
|
55
46
|
<Badge variant="destructive" className="text-[10px] h-4 px-1.5 shrink-0">
|
|
@@ -60,42 +51,56 @@ function SkillActionRow({ action }: { action: OrchestrateRunSkillAction }) {
|
|
|
60
51
|
<p className="text-[11px] text-muted-foreground line-clamp-1">{action.reason}</p>
|
|
61
52
|
</div>
|
|
62
53
|
</div>
|
|
63
|
-
)
|
|
54
|
+
);
|
|
64
55
|
}
|
|
65
56
|
|
|
66
57
|
function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
67
|
-
const [open, setOpen] = useState(false)
|
|
68
|
-
const nonSkipActions = run.skill_actions.filter((a) => a.action !== "skip")
|
|
69
|
-
const skipActions = run.skill_actions.filter((a) => a.action === "skip")
|
|
58
|
+
const [open, setOpen] = useState(false);
|
|
59
|
+
const nonSkipActions = run.skill_actions.filter((a) => a.action !== "skip");
|
|
60
|
+
const skipActions = run.skill_actions.filter((a) => a.action === "skip");
|
|
70
61
|
|
|
71
62
|
return (
|
|
72
63
|
<Collapsible open={open} onOpenChange={setOpen}>
|
|
73
64
|
<CollapsibleTrigger className="w-full text-left">
|
|
74
65
|
<div className="flex items-start gap-3 py-2 hover:bg-muted/50 rounded-md px-2 -mx-2 transition-colors">
|
|
75
|
-
<div
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
<div
|
|
67
|
+
className={`mt-1.5 size-2 shrink-0 rounded-full ${
|
|
68
|
+
run.deployed > 0
|
|
69
|
+
? "bg-emerald-500"
|
|
70
|
+
: run.evolved > 0
|
|
71
|
+
? "bg-amber-400"
|
|
72
|
+
: "bg-muted-foreground/40"
|
|
73
|
+
}`}
|
|
74
|
+
/>
|
|
80
75
|
<div className="flex-1 min-w-0">
|
|
81
76
|
<div className="flex items-center gap-2">
|
|
82
|
-
<span className="text-xs font-mono text-muted-foreground">
|
|
77
|
+
<span className="text-xs font-mono text-muted-foreground">
|
|
78
|
+
{timeAgo(run.timestamp)}
|
|
79
|
+
</span>
|
|
83
80
|
{run.dry_run && (
|
|
84
|
-
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
|
81
|
+
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
|
82
|
+
dry-run
|
|
83
|
+
</Badge>
|
|
85
84
|
)}
|
|
86
85
|
{run.approval_mode === "review" && (
|
|
87
|
-
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
|
86
|
+
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
|
87
|
+
review
|
|
88
|
+
</Badge>
|
|
88
89
|
)}
|
|
89
90
|
</div>
|
|
90
91
|
<div className="flex items-center gap-3 mt-1 text-xs text-muted-foreground">
|
|
91
|
-
{run.deployed > 0 &&
|
|
92
|
+
{run.deployed > 0 && (
|
|
93
|
+
<span className="text-emerald-600 font-medium">{run.deployed} deployed</span>
|
|
94
|
+
)}
|
|
92
95
|
{run.evolved > 0 && <span>{run.evolved} evolved</span>}
|
|
93
96
|
{run.watched > 0 && <span>{run.watched} watched</span>}
|
|
94
97
|
{run.skipped > 0 && <span>{run.skipped} skipped</span>}
|
|
95
98
|
<span>{(run.elapsed_ms / 1000).toFixed(1)}s</span>
|
|
96
99
|
</div>
|
|
97
100
|
</div>
|
|
98
|
-
<ChevronRightIcon
|
|
101
|
+
<ChevronRightIcon
|
|
102
|
+
className={`size-4 text-muted-foreground shrink-0 mt-1 transition-transform duration-200 ${open ? "rotate-90" : ""}`}
|
|
103
|
+
/>
|
|
99
104
|
</div>
|
|
100
105
|
</CollapsibleTrigger>
|
|
101
106
|
<CollapsibleContent>
|
|
@@ -118,7 +123,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
|
118
123
|
</div>
|
|
119
124
|
</CollapsibleContent>
|
|
120
125
|
</Collapsible>
|
|
121
|
-
)
|
|
126
|
+
);
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] }) {
|
|
@@ -133,14 +138,16 @@ export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] })
|
|
|
133
138
|
</CardHeader>
|
|
134
139
|
<CardContent>
|
|
135
140
|
<p className="text-sm text-muted-foreground text-center py-4">
|
|
136
|
-
No orchestrate runs yet. Run
|
|
141
|
+
No orchestrate runs yet. Run{" "}
|
|
142
|
+
<code className="text-xs bg-muted px-1 py-0.5 rounded">selftune orchestrate</code> to
|
|
143
|
+
start.
|
|
137
144
|
</p>
|
|
138
145
|
</CardContent>
|
|
139
146
|
</Card>
|
|
140
|
-
)
|
|
147
|
+
);
|
|
141
148
|
}
|
|
142
149
|
|
|
143
|
-
const totalDeployed = runs.reduce((sum, r) => sum + r.deployed, 0)
|
|
150
|
+
const totalDeployed = runs.reduce((sum, r) => sum + r.deployed, 0);
|
|
144
151
|
|
|
145
152
|
return (
|
|
146
153
|
<Card>
|
|
@@ -160,5 +167,5 @@ export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] })
|
|
|
160
167
|
))}
|
|
161
168
|
</CardContent>
|
|
162
169
|
</Card>
|
|
163
|
-
)
|
|
170
|
+
);
|
|
164
171
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import { Badge } from "../primitives/badge"
|
|
2
|
-
import {
|
|
3
|
-
Card,
|
|
4
|
-
CardAction,
|
|
5
|
-
CardDescription,
|
|
6
|
-
CardHeader,
|
|
7
|
-
CardTitle,
|
|
8
|
-
} from "../primitives/card"
|
|
9
|
-
import { InfoTip } from "./InfoTip"
|
|
10
1
|
import {
|
|
11
2
|
TrendingUpIcon,
|
|
12
3
|
TrendingDownIcon,
|
|
@@ -16,16 +7,20 @@ import {
|
|
|
16
7
|
FlaskConicalIcon,
|
|
17
8
|
LayersIcon,
|
|
18
9
|
SearchXIcon,
|
|
19
|
-
} from "lucide-react"
|
|
10
|
+
} from "lucide-react";
|
|
11
|
+
|
|
12
|
+
import { Badge } from "../primitives/badge";
|
|
13
|
+
import { Card, CardAction, CardDescription, CardHeader, CardTitle } from "../primitives/card";
|
|
14
|
+
import { InfoTip } from "./InfoTip";
|
|
20
15
|
|
|
21
16
|
interface SectionCardsProps {
|
|
22
|
-
skillsCount: number
|
|
23
|
-
avgPassRate: number | null
|
|
24
|
-
unmatchedCount: number
|
|
25
|
-
sessionsCount: number
|
|
26
|
-
pendingCount: number
|
|
27
|
-
evidenceCount: number
|
|
28
|
-
hasEvolution?: boolean
|
|
17
|
+
skillsCount: number;
|
|
18
|
+
avgPassRate: number | null;
|
|
19
|
+
unmatchedCount: number;
|
|
20
|
+
sessionsCount: number;
|
|
21
|
+
pendingCount: number;
|
|
22
|
+
evidenceCount: number;
|
|
23
|
+
hasEvolution?: boolean;
|
|
29
24
|
}
|
|
30
25
|
|
|
31
26
|
export function SectionCards({
|
|
@@ -37,8 +32,8 @@ export function SectionCards({
|
|
|
37
32
|
evidenceCount,
|
|
38
33
|
hasEvolution = true,
|
|
39
34
|
}: SectionCardsProps) {
|
|
40
|
-
const passRateStr = avgPassRate !== null ? `${Math.round(avgPassRate * 100)}%` : "--"
|
|
41
|
-
const passRateGood = avgPassRate !== null && avgPassRate >= 0.7
|
|
35
|
+
const passRateStr = avgPassRate !== null ? `${Math.round(avgPassRate * 100)}%` : "--";
|
|
36
|
+
const passRateGood = avgPassRate !== null && avgPassRate >= 0.7;
|
|
42
37
|
|
|
43
38
|
return (
|
|
44
39
|
<div className="grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:shadow-xs lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-3">
|
|
@@ -68,7 +63,9 @@ export function SectionCards({
|
|
|
68
63
|
Avg Trigger Rate
|
|
69
64
|
<InfoTip text="Average percentage of skill checks that resulted in a trigger across all graded skills (5+ checks). Run selftune evolve to improve this." />
|
|
70
65
|
</CardDescription>
|
|
71
|
-
<CardTitle
|
|
66
|
+
<CardTitle
|
|
67
|
+
className={`text-2xl font-semibold tabular-nums @[250px]/card:text-3xl ${!passRateGood && avgPassRate !== null ? "text-red-600" : ""}`}
|
|
68
|
+
>
|
|
72
69
|
{passRateStr}
|
|
73
70
|
</CardTitle>
|
|
74
71
|
<CardAction>
|
|
@@ -128,7 +125,7 @@ export function SectionCards({
|
|
|
128
125
|
<CardHeader>
|
|
129
126
|
<CardDescription className="flex items-center gap-1.5">
|
|
130
127
|
<AlertTriangleIcon className="size-3.5" />
|
|
131
|
-
|
|
128
|
+
Undeployed Proposals
|
|
132
129
|
<InfoTip text="Evolution proposals that have been generated but not yet validated or deployed. Requires running selftune evolve." />
|
|
133
130
|
</CardDescription>
|
|
134
131
|
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
@@ -140,9 +137,7 @@ export function SectionCards({
|
|
|
140
137
|
no evolution runs yet
|
|
141
138
|
</Badge>
|
|
142
139
|
) : pendingCount > 0 ? (
|
|
143
|
-
<Badge variant="secondary">
|
|
144
|
-
awaiting review
|
|
145
|
-
</Badge>
|
|
140
|
+
<Badge variant="secondary">not yet deployed</Badge>
|
|
146
141
|
) : null}
|
|
147
142
|
</CardAction>
|
|
148
143
|
</CardHeader>
|
|
@@ -168,5 +163,5 @@ export function SectionCards({
|
|
|
168
163
|
</CardHeader>
|
|
169
164
|
</Card>
|
|
170
165
|
</div>
|
|
171
|
-
)
|
|
166
|
+
);
|
|
172
167
|
}
|