selftune 0.2.2 → 0.2.6
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 +11 -0
- package/apps/local-dashboard/dist/assets/index-C75H1Q3n.css +1 -0
- package/apps/local-dashboard/dist/assets/index-axE4kz3Q.js +15 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-r2k_Ku_V.js +346 -0
- package/apps/local-dashboard/dist/index.html +3 -3
- package/cli/selftune/analytics.ts +354 -0
- package/cli/selftune/badge/badge.ts +2 -2
- package/cli/selftune/dashboard-server.ts +3 -3
- package/cli/selftune/evolution/evolve-body.ts +1 -1
- package/cli/selftune/evolution/evolve.ts +1 -1
- package/cli/selftune/index.ts +15 -1
- package/cli/selftune/init.ts +5 -1
- package/cli/selftune/observability.ts +63 -2
- package/cli/selftune/orchestrate.ts +1 -1
- package/cli/selftune/quickstart.ts +1 -1
- package/cli/selftune/status.ts +2 -2
- package/cli/selftune/types.ts +1 -0
- package/cli/selftune/utils/llm-call.ts +2 -1
- package/package.json +6 -4
- package/packages/ui/README.md +113 -0
- package/packages/ui/index.ts +10 -0
- package/packages/ui/package.json +62 -0
- package/packages/ui/src/components/ActivityTimeline.tsx +171 -0
- package/packages/ui/src/components/EvidenceViewer.tsx +718 -0
- package/packages/ui/src/components/EvolutionTimeline.tsx +252 -0
- package/packages/ui/src/components/InfoTip.tsx +19 -0
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +164 -0
- package/packages/ui/src/components/index.ts +7 -0
- package/packages/ui/src/components/section-cards.tsx +155 -0
- package/packages/ui/src/components/skill-health-grid.tsx +686 -0
- package/packages/ui/src/lib/constants.tsx +43 -0
- package/packages/ui/src/lib/format.ts +37 -0
- package/packages/ui/src/lib/index.ts +3 -0
- package/packages/ui/src/lib/utils.ts +6 -0
- package/packages/ui/src/primitives/badge.tsx +52 -0
- package/packages/ui/src/primitives/button.tsx +58 -0
- package/packages/ui/src/primitives/card.tsx +103 -0
- package/packages/ui/src/primitives/checkbox.tsx +27 -0
- package/packages/ui/src/primitives/collapsible.tsx +7 -0
- package/packages/ui/src/primitives/dropdown-menu.tsx +266 -0
- package/packages/ui/src/primitives/index.ts +55 -0
- package/packages/ui/src/primitives/label.tsx +20 -0
- package/packages/ui/src/primitives/select.tsx +197 -0
- package/packages/ui/src/primitives/table.tsx +114 -0
- package/packages/ui/src/primitives/tabs.tsx +82 -0
- package/packages/ui/src/primitives/tooltip.tsx +64 -0
- package/packages/ui/src/types.ts +87 -0
- package/packages/ui/tsconfig.json +17 -0
- package/skill/SKILL.md +3 -0
- package/skill/Workflows/Telemetry.md +59 -0
- package/apps/local-dashboard/dist/assets/index-C4EOTFZ2.js +0 -15
- package/apps/local-dashboard/dist/assets/index-bl-Webyd.css +0 -1
- package/apps/local-dashboard/dist/assets/vendor-ui-D7_zX_qy.js +0 -346
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Select as SelectPrimitive } from "@base-ui/react/select"
|
|
3
|
+
|
|
4
|
+
import { cn } from "../lib/utils"
|
|
5
|
+
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
const Select = SelectPrimitive.Root
|
|
8
|
+
|
|
9
|
+
function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<SelectPrimitive.Group
|
|
12
|
+
data-slot="select-group"
|
|
13
|
+
className={cn("scroll-my-1 p-1", className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
|
|
20
|
+
return (
|
|
21
|
+
<SelectPrimitive.Value
|
|
22
|
+
data-slot="select-value"
|
|
23
|
+
className={cn("flex flex-1 text-left", className)}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function SelectTrigger({
|
|
30
|
+
className,
|
|
31
|
+
size = "default",
|
|
32
|
+
children,
|
|
33
|
+
...props
|
|
34
|
+
}: SelectPrimitive.Trigger.Props & {
|
|
35
|
+
size?: "sm" | "default"
|
|
36
|
+
}) {
|
|
37
|
+
return (
|
|
38
|
+
<SelectPrimitive.Trigger
|
|
39
|
+
data-slot="select-trigger"
|
|
40
|
+
data-size={size}
|
|
41
|
+
className={cn(
|
|
42
|
+
"flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
<SelectPrimitive.Icon
|
|
49
|
+
render={
|
|
50
|
+
<ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
</SelectPrimitive.Trigger>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function SelectContent({
|
|
58
|
+
className,
|
|
59
|
+
children,
|
|
60
|
+
side = "bottom",
|
|
61
|
+
sideOffset = 4,
|
|
62
|
+
align = "center",
|
|
63
|
+
alignOffset = 0,
|
|
64
|
+
alignItemWithTrigger = true,
|
|
65
|
+
...props
|
|
66
|
+
}: SelectPrimitive.Popup.Props &
|
|
67
|
+
Pick<
|
|
68
|
+
SelectPrimitive.Positioner.Props,
|
|
69
|
+
"align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
|
|
70
|
+
>) {
|
|
71
|
+
return (
|
|
72
|
+
<SelectPrimitive.Portal>
|
|
73
|
+
<SelectPrimitive.Positioner
|
|
74
|
+
side={side}
|
|
75
|
+
sideOffset={sideOffset}
|
|
76
|
+
align={align}
|
|
77
|
+
alignOffset={alignOffset}
|
|
78
|
+
alignItemWithTrigger={alignItemWithTrigger}
|
|
79
|
+
className="isolate z-50"
|
|
80
|
+
>
|
|
81
|
+
<SelectPrimitive.Popup
|
|
82
|
+
data-slot="select-content"
|
|
83
|
+
data-align-trigger={alignItemWithTrigger}
|
|
84
|
+
className={cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
<SelectScrollUpButton />
|
|
88
|
+
<SelectPrimitive.List>{children}</SelectPrimitive.List>
|
|
89
|
+
<SelectScrollDownButton />
|
|
90
|
+
</SelectPrimitive.Popup>
|
|
91
|
+
</SelectPrimitive.Positioner>
|
|
92
|
+
</SelectPrimitive.Portal>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function SelectLabel({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: SelectPrimitive.GroupLabel.Props) {
|
|
100
|
+
return (
|
|
101
|
+
<SelectPrimitive.GroupLabel
|
|
102
|
+
data-slot="select-label"
|
|
103
|
+
className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function SelectItem({
|
|
110
|
+
className,
|
|
111
|
+
children,
|
|
112
|
+
...props
|
|
113
|
+
}: SelectPrimitive.Item.Props) {
|
|
114
|
+
return (
|
|
115
|
+
<SelectPrimitive.Item
|
|
116
|
+
data-slot="select-item"
|
|
117
|
+
className={cn(
|
|
118
|
+
"relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
119
|
+
className
|
|
120
|
+
)}
|
|
121
|
+
{...props}
|
|
122
|
+
>
|
|
123
|
+
<SelectPrimitive.ItemText className="flex flex-1 shrink-0 gap-2 whitespace-nowrap">
|
|
124
|
+
{children}
|
|
125
|
+
</SelectPrimitive.ItemText>
|
|
126
|
+
<SelectPrimitive.ItemIndicator
|
|
127
|
+
render={
|
|
128
|
+
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
<CheckIcon className="pointer-events-none" />
|
|
132
|
+
</SelectPrimitive.ItemIndicator>
|
|
133
|
+
</SelectPrimitive.Item>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function SelectSeparator({
|
|
138
|
+
className,
|
|
139
|
+
...props
|
|
140
|
+
}: SelectPrimitive.Separator.Props) {
|
|
141
|
+
return (
|
|
142
|
+
<SelectPrimitive.Separator
|
|
143
|
+
data-slot="select-separator"
|
|
144
|
+
className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
|
|
145
|
+
{...props}
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function SelectScrollUpButton({
|
|
151
|
+
className,
|
|
152
|
+
...props
|
|
153
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
|
|
154
|
+
return (
|
|
155
|
+
<SelectPrimitive.ScrollUpArrow
|
|
156
|
+
data-slot="select-scroll-up-button"
|
|
157
|
+
className={cn(
|
|
158
|
+
"top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
159
|
+
className
|
|
160
|
+
)}
|
|
161
|
+
{...props}
|
|
162
|
+
>
|
|
163
|
+
<ChevronUpIcon />
|
|
164
|
+
</SelectPrimitive.ScrollUpArrow>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function SelectScrollDownButton({
|
|
169
|
+
className,
|
|
170
|
+
...props
|
|
171
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
|
|
172
|
+
return (
|
|
173
|
+
<SelectPrimitive.ScrollDownArrow
|
|
174
|
+
data-slot="select-scroll-down-button"
|
|
175
|
+
className={cn(
|
|
176
|
+
"bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
177
|
+
className
|
|
178
|
+
)}
|
|
179
|
+
{...props}
|
|
180
|
+
>
|
|
181
|
+
<ChevronDownIcon />
|
|
182
|
+
</SelectPrimitive.ScrollDownArrow>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
Select,
|
|
188
|
+
SelectContent,
|
|
189
|
+
SelectGroup,
|
|
190
|
+
SelectItem,
|
|
191
|
+
SelectLabel,
|
|
192
|
+
SelectScrollDownButton,
|
|
193
|
+
SelectScrollUpButton,
|
|
194
|
+
SelectSeparator,
|
|
195
|
+
SelectTrigger,
|
|
196
|
+
SelectValue,
|
|
197
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils"
|
|
4
|
+
|
|
5
|
+
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="table-container"
|
|
9
|
+
className="relative w-full overflow-x-auto"
|
|
10
|
+
>
|
|
11
|
+
<table
|
|
12
|
+
data-slot="table"
|
|
13
|
+
className={cn("w-full caption-bottom text-sm", className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
</div>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
|
21
|
+
return (
|
|
22
|
+
<thead
|
|
23
|
+
data-slot="table-header"
|
|
24
|
+
className={cn("[&_tr]:border-b", className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
|
31
|
+
return (
|
|
32
|
+
<tbody
|
|
33
|
+
data-slot="table-body"
|
|
34
|
+
className={cn("[&_tr:last-child]:border-0", className)}
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
|
41
|
+
return (
|
|
42
|
+
<tfoot
|
|
43
|
+
data-slot="table-footer"
|
|
44
|
+
className={cn(
|
|
45
|
+
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
|
54
|
+
return (
|
|
55
|
+
<tr
|
|
56
|
+
data-slot="table-row"
|
|
57
|
+
className={cn(
|
|
58
|
+
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
67
|
+
return (
|
|
68
|
+
<th
|
|
69
|
+
data-slot="table-head"
|
|
70
|
+
className={cn(
|
|
71
|
+
"h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0",
|
|
72
|
+
className
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
|
80
|
+
return (
|
|
81
|
+
<td
|
|
82
|
+
data-slot="table-cell"
|
|
83
|
+
className={cn(
|
|
84
|
+
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0",
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function TableCaption({
|
|
93
|
+
className,
|
|
94
|
+
...props
|
|
95
|
+
}: React.ComponentProps<"caption">) {
|
|
96
|
+
return (
|
|
97
|
+
<caption
|
|
98
|
+
data-slot="table-caption"
|
|
99
|
+
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
|
100
|
+
{...props}
|
|
101
|
+
/>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
Table,
|
|
107
|
+
TableHeader,
|
|
108
|
+
TableBody,
|
|
109
|
+
TableFooter,
|
|
110
|
+
TableHead,
|
|
111
|
+
TableRow,
|
|
112
|
+
TableCell,
|
|
113
|
+
TableCaption,
|
|
114
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../lib/utils"
|
|
7
|
+
|
|
8
|
+
function Tabs({
|
|
9
|
+
className,
|
|
10
|
+
orientation = "horizontal",
|
|
11
|
+
...props
|
|
12
|
+
}: TabsPrimitive.Root.Props) {
|
|
13
|
+
return (
|
|
14
|
+
<TabsPrimitive.Root
|
|
15
|
+
data-slot="tabs"
|
|
16
|
+
data-orientation={orientation}
|
|
17
|
+
className={cn(
|
|
18
|
+
"group/tabs flex gap-2 data-horizontal:flex-col",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const tabsListVariants = cva(
|
|
27
|
+
"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
|
|
28
|
+
{
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
default: "bg-muted",
|
|
32
|
+
line: "gap-1 bg-transparent",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
variant: "default",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
function TabsList({
|
|
42
|
+
className,
|
|
43
|
+
variant = "default",
|
|
44
|
+
...props
|
|
45
|
+
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
|
46
|
+
return (
|
|
47
|
+
<TabsPrimitive.List
|
|
48
|
+
data-slot="tabs-list"
|
|
49
|
+
data-variant={variant}
|
|
50
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
|
57
|
+
return (
|
|
58
|
+
<TabsPrimitive.Tab
|
|
59
|
+
data-slot="tabs-trigger"
|
|
60
|
+
className={cn(
|
|
61
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
62
|
+
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
|
63
|
+
"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
|
|
64
|
+
"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
|
65
|
+
className
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
|
73
|
+
return (
|
|
74
|
+
<TabsPrimitive.Panel
|
|
75
|
+
data-slot="tabs-content"
|
|
76
|
+
className={cn("flex-1 text-sm outline-none", className)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils"
|
|
4
|
+
|
|
5
|
+
function TooltipProvider({
|
|
6
|
+
delay = 0,
|
|
7
|
+
...props
|
|
8
|
+
}: TooltipPrimitive.Provider.Props) {
|
|
9
|
+
return (
|
|
10
|
+
<TooltipPrimitive.Provider
|
|
11
|
+
data-slot="tooltip-provider"
|
|
12
|
+
delay={delay}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
|
19
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
|
|
23
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function TooltipContent({
|
|
27
|
+
className,
|
|
28
|
+
side = "top",
|
|
29
|
+
sideOffset = 4,
|
|
30
|
+
align = "center",
|
|
31
|
+
alignOffset = 0,
|
|
32
|
+
children,
|
|
33
|
+
...props
|
|
34
|
+
}: TooltipPrimitive.Popup.Props &
|
|
35
|
+
Pick<
|
|
36
|
+
TooltipPrimitive.Positioner.Props,
|
|
37
|
+
"align" | "alignOffset" | "side" | "sideOffset"
|
|
38
|
+
>) {
|
|
39
|
+
return (
|
|
40
|
+
<TooltipPrimitive.Portal>
|
|
41
|
+
<TooltipPrimitive.Positioner
|
|
42
|
+
align={align}
|
|
43
|
+
alignOffset={alignOffset}
|
|
44
|
+
side={side}
|
|
45
|
+
sideOffset={sideOffset}
|
|
46
|
+
className="isolate z-50"
|
|
47
|
+
>
|
|
48
|
+
<TooltipPrimitive.Popup
|
|
49
|
+
data-slot="tooltip-content"
|
|
50
|
+
className={cn(
|
|
51
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
52
|
+
className
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
|
|
58
|
+
</TooltipPrimitive.Popup>
|
|
59
|
+
</TooltipPrimitive.Positioner>
|
|
60
|
+
</TooltipPrimitive.Portal>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// -- UI-only types -----------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
export type SkillHealthStatus = "HEALTHY" | "WARNING" | "CRITICAL" | "UNGRADED" | "UNKNOWN";
|
|
4
|
+
|
|
5
|
+
export interface SkillCard {
|
|
6
|
+
name: string;
|
|
7
|
+
scope: string | null;
|
|
8
|
+
passRate: number | null;
|
|
9
|
+
checks: number;
|
|
10
|
+
status: SkillHealthStatus;
|
|
11
|
+
hasEvidence: boolean;
|
|
12
|
+
uniqueSessions: number;
|
|
13
|
+
lastSeen: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// -- Dashboard contract types (re-declared for package independence) ----------
|
|
17
|
+
|
|
18
|
+
export interface EvalSnapshot {
|
|
19
|
+
before_pass_rate?: number;
|
|
20
|
+
after_pass_rate?: number;
|
|
21
|
+
net_change?: number;
|
|
22
|
+
improved?: boolean;
|
|
23
|
+
regressions?: Array<Record<string, unknown>>;
|
|
24
|
+
new_passes?: Array<Record<string, unknown>>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface EvolutionEntry {
|
|
28
|
+
timestamp: string;
|
|
29
|
+
proposal_id: string;
|
|
30
|
+
action: string;
|
|
31
|
+
details: string;
|
|
32
|
+
eval_snapshot?: EvalSnapshot | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface UnmatchedQuery {
|
|
36
|
+
timestamp: string;
|
|
37
|
+
session_id: string;
|
|
38
|
+
query: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface PendingProposal {
|
|
42
|
+
proposal_id: string;
|
|
43
|
+
action: string;
|
|
44
|
+
timestamp: string;
|
|
45
|
+
details: string;
|
|
46
|
+
skill_name?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface EvidenceEntry {
|
|
50
|
+
proposal_id: string;
|
|
51
|
+
target: string;
|
|
52
|
+
stage: string;
|
|
53
|
+
timestamp: string;
|
|
54
|
+
rationale: string | null;
|
|
55
|
+
confidence: number | null;
|
|
56
|
+
original_text: string | null;
|
|
57
|
+
proposed_text: string | null;
|
|
58
|
+
validation: Record<string, unknown> | null;
|
|
59
|
+
details: string | null;
|
|
60
|
+
eval_set: Array<Record<string, unknown>>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface OrchestrateRunSkillAction {
|
|
64
|
+
skill: string;
|
|
65
|
+
action: "evolve" | "watch" | "skip";
|
|
66
|
+
reason: string;
|
|
67
|
+
deployed?: boolean;
|
|
68
|
+
rolledBack?: boolean;
|
|
69
|
+
alert?: string | null;
|
|
70
|
+
elapsed_ms?: number;
|
|
71
|
+
llm_calls?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface OrchestrateRunReport {
|
|
75
|
+
run_id: string;
|
|
76
|
+
timestamp: string;
|
|
77
|
+
elapsed_ms: number;
|
|
78
|
+
dry_run: boolean;
|
|
79
|
+
approval_mode: "auto" | "review";
|
|
80
|
+
total_skills: number;
|
|
81
|
+
evaluated: number;
|
|
82
|
+
evolved: number;
|
|
83
|
+
deployed: number;
|
|
84
|
+
watched: number;
|
|
85
|
+
skipped: number;
|
|
86
|
+
skill_actions: OrchestrateRunSkillAction[];
|
|
87
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"declarationMap": true,
|
|
12
|
+
"sourceMap": true,
|
|
13
|
+
"outDir": "dist",
|
|
14
|
+
"rootDir": "."
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "index.ts"]
|
|
17
|
+
}
|
package/skill/SKILL.md
CHANGED
|
@@ -77,6 +77,7 @@ selftune cron setup [--dry-run] # auto-detect platform (
|
|
|
77
77
|
selftune cron setup --platform openclaw [--dry-run] [--tz <timezone>] # OpenClaw-specific
|
|
78
78
|
selftune cron list
|
|
79
79
|
selftune cron remove [--dry-run]
|
|
80
|
+
selftune telemetry [status|enable|disable]
|
|
80
81
|
```
|
|
81
82
|
|
|
82
83
|
## Workflow Routing
|
|
@@ -102,6 +103,7 @@ selftune cron remove [--dry-run]
|
|
|
102
103
|
| eval unit-test, skill test, test skill, generate tests, run tests, assertions | UnitTest | Workflows/UnitTest.md |
|
|
103
104
|
| eval composability, co-occurrence, skill conflicts, skills together, conflict score | Composability | Workflows/Composability.md |
|
|
104
105
|
| eval import, skillsbench, external evals, benchmark tasks, import corpus | ImportSkillsBench | Workflows/ImportSkillsBench.md |
|
|
106
|
+
| telemetry, analytics, disable analytics, opt out, usage data, tracking, privacy | Telemetry | Workflows/Telemetry.md |
|
|
105
107
|
| status, health summary, skill health, pass rates, how are skills, skills working, skills doing, run selftune, start selftune | Status | *(direct command — no workflow file)* |
|
|
106
108
|
| last, last session, recent session, what happened, what changed, what did selftune do | Last | *(direct command — no workflow file)* |
|
|
107
109
|
|
|
@@ -191,6 +193,7 @@ Observe --> Detect --> Diagnose --> Propose --> Validate --> Audit --> Deploy --
|
|
|
191
193
|
| `Workflows/UnitTest.md` | Skill-level unit test runner and generator |
|
|
192
194
|
| `Workflows/Composability.md` | Multi-skill co-occurrence conflict analysis |
|
|
193
195
|
| `Workflows/ImportSkillsBench.md` | SkillsBench task corpus importer |
|
|
196
|
+
| `Workflows/Telemetry.md` | Telemetry status, opt-in/opt-out, and privacy |
|
|
194
197
|
|
|
195
198
|
## Specialized Agents
|
|
196
199
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# selftune Telemetry Workflow
|
|
2
|
+
|
|
3
|
+
## When to Use
|
|
4
|
+
|
|
5
|
+
When the user asks about telemetry, analytics, usage tracking, privacy,
|
|
6
|
+
opting out of data collection, or wants to check/change their telemetry settings.
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
selftune collects anonymous, non-identifying usage analytics to help prioritize
|
|
11
|
+
features. No PII is ever collected — only command names, OS/arch, and selftune
|
|
12
|
+
version. Users can opt out at any time.
|
|
13
|
+
|
|
14
|
+
## Default Commands
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
selftune telemetry # Show current telemetry status
|
|
18
|
+
selftune telemetry status # Same as above
|
|
19
|
+
selftune telemetry enable # Enable anonymous usage analytics
|
|
20
|
+
selftune telemetry disable # Disable anonymous usage analytics
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Environment Override
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
export SELFTUNE_NO_ANALYTICS=1 # Disable via env var (highest priority)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Analytics is also automatically disabled in CI environments (`CI=true`).
|
|
30
|
+
|
|
31
|
+
## What Is Collected
|
|
32
|
+
|
|
33
|
+
- Command name (e.g., "status", "evolve")
|
|
34
|
+
- OS, architecture, selftune version, node version
|
|
35
|
+
- Agent type (claude/codex/opencode)
|
|
36
|
+
- Random anonymous ID (not derived from any user data)
|
|
37
|
+
|
|
38
|
+
## What IS Collected (linkable)
|
|
39
|
+
|
|
40
|
+
- `anonymous_id` — stable random ID (persisted locally, not derived from user data)
|
|
41
|
+
- `sent_at` — ISO timestamp of when the event was sent
|
|
42
|
+
|
|
43
|
+
These fields can correlate events from the same machine. They contain no PII.
|
|
44
|
+
|
|
45
|
+
## What Is NOT Collected
|
|
46
|
+
|
|
47
|
+
- No usernames, emails, IPs, or hostnames
|
|
48
|
+
- No file paths or repo names
|
|
49
|
+
- No session IDs
|
|
50
|
+
- No skill names or content
|
|
51
|
+
|
|
52
|
+
## Common Patterns
|
|
53
|
+
|
|
54
|
+
- "Is selftune tracking me?"
|
|
55
|
+
→ `selftune telemetry status`
|
|
56
|
+
- "Turn off analytics"
|
|
57
|
+
→ `selftune telemetry disable`
|
|
58
|
+
- "I want to help improve selftune"
|
|
59
|
+
→ `selftune telemetry enable`
|