selftune 0.2.16 → 0.2.19
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 +32 -22
- package/apps/local-dashboard/dist/assets/index-DnhnXQm6.js +60 -0
- package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +1 -0
- package/apps/local-dashboard/dist/assets/vendor-table-BIiI3YhS.js +1 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +12 -0
- package/apps/local-dashboard/dist/index.html +5 -5
- package/cli/selftune/alpha-upload/build-payloads.ts +14 -1
- package/cli/selftune/alpha-upload/client.ts +51 -1
- package/cli/selftune/alpha-upload/flush.ts +46 -5
- package/cli/selftune/alpha-upload/stage-canonical.ts +32 -10
- package/cli/selftune/alpha-upload-contract.ts +9 -0
- package/cli/selftune/constants.ts +92 -5
- package/cli/selftune/contribute/contribute.ts +30 -2
- package/cli/selftune/contribute/sanitize.ts +52 -5
- package/cli/selftune/contribution-config.ts +249 -0
- package/cli/selftune/contribution-relay.ts +177 -0
- package/cli/selftune/contribution-signals.ts +219 -0
- package/cli/selftune/contribution-staging.ts +147 -0
- package/cli/selftune/contributions.ts +532 -0
- package/cli/selftune/creator-contributions.ts +333 -0
- package/cli/selftune/dashboard-contract.ts +305 -1
- package/cli/selftune/dashboard-server.ts +47 -13
- package/cli/selftune/eval/family-overlap.ts +395 -0
- package/cli/selftune/eval/hooks-to-evals.ts +182 -28
- package/cli/selftune/eval/synthetic-evals.ts +298 -11
- package/cli/selftune/evolution/description-quality.ts +12 -11
- package/cli/selftune/evolution/evolve.ts +214 -51
- package/cli/selftune/evolution/validate-proposal.ts +9 -6
- package/cli/selftune/export.ts +2 -2
- package/cli/selftune/grading/grade-session.ts +20 -0
- package/cli/selftune/hooks/commit-track.ts +188 -0
- package/cli/selftune/hooks/prompt-log.ts +10 -1
- package/cli/selftune/hooks/session-stop.ts +2 -2
- package/cli/selftune/hooks/skill-eval.ts +15 -1
- package/cli/selftune/hooks/stdin-preview.ts +32 -0
- package/cli/selftune/index.ts +41 -5
- package/cli/selftune/ingestors/codex-rollout.ts +31 -35
- package/cli/selftune/ingestors/codex-wrapper.ts +32 -24
- package/cli/selftune/localdb/db.ts +2 -2
- package/cli/selftune/localdb/direct-write.ts +69 -6
- package/cli/selftune/localdb/queries.ts +1253 -37
- package/cli/selftune/localdb/schema.ts +66 -0
- package/cli/selftune/orchestrate.ts +32 -4
- package/cli/selftune/recover.ts +153 -0
- package/cli/selftune/repair/skill-usage.ts +363 -4
- package/cli/selftune/routes/actions.ts +35 -1
- package/cli/selftune/routes/analytics.ts +14 -0
- package/cli/selftune/routes/index.ts +1 -0
- package/cli/selftune/routes/overview.ts +150 -4
- package/cli/selftune/routes/skill-report.ts +648 -18
- package/cli/selftune/status.ts +81 -2
- package/cli/selftune/sync.ts +56 -2
- package/cli/selftune/trust-model.ts +66 -0
- package/cli/selftune/types.ts +80 -0
- package/cli/selftune/utils/skill-detection.ts +43 -0
- package/cli/selftune/utils/transcript.ts +210 -1
- package/cli/selftune/watchlist.ts +65 -0
- package/node_modules/@selftune/telemetry-contract/src/types.ts +11 -0
- package/package.json +1 -1
- package/packages/telemetry-contract/src/types.ts +11 -0
- package/packages/ui/src/components/ActivityTimeline.tsx +165 -150
- package/packages/ui/src/components/EvidenceViewer.tsx +335 -144
- package/packages/ui/src/components/EvolutionTimeline.tsx +58 -28
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +33 -16
- package/packages/ui/src/components/RecentActivityFeed.tsx +72 -41
- package/packages/ui/src/components/section-cards.tsx +12 -9
- package/packages/ui/src/primitives/card.tsx +1 -1
- package/skill/SKILL.md +40 -2
- package/skill/Workflows/AlphaUpload.md +4 -0
- package/skill/Workflows/Composability.md +64 -0
- package/skill/Workflows/Contribute.md +6 -3
- package/skill/Workflows/Contributions.md +97 -0
- package/skill/Workflows/CreatorContributions.md +74 -0
- package/skill/Workflows/Dashboard.md +31 -0
- package/skill/Workflows/Evals.md +57 -8
- package/skill/Workflows/Evolve.md +31 -13
- package/skill/Workflows/ExportCanonical.md +121 -0
- package/skill/Workflows/Hook.md +131 -0
- package/skill/Workflows/Ingest.md +7 -0
- package/skill/Workflows/Initialize.md +29 -9
- package/skill/Workflows/Orchestrate.md +27 -5
- package/skill/Workflows/Quickstart.md +94 -0
- package/skill/Workflows/Recover.md +84 -0
- package/skill/Workflows/RepairSkillUsage.md +95 -0
- package/skill/Workflows/Sync.md +18 -12
- package/skill/Workflows/Uninstall.md +82 -0
- package/skill/settings_snippet.json +11 -0
- package/apps/local-dashboard/dist/assets/index-BMIS6uUh.css +0 -2
- package/apps/local-dashboard/dist/assets/index-DOu3iLD9.js +0 -16
- package/apps/local-dashboard/dist/assets/vendor-table-pHbDxq36.js +0 -8
- package/apps/local-dashboard/dist/assets/vendor-ui-DIwlrGlb.js +0 -12
|
@@ -25,27 +25,43 @@ const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const ACTION_COLOR: Record<string, string> = {
|
|
28
|
-
created: "bg-
|
|
29
|
-
validated: "bg-
|
|
30
|
-
deployed: "bg-
|
|
31
|
-
rejected: "bg-
|
|
32
|
-
rolled_back: "bg-
|
|
28
|
+
created: "bg-primary/15",
|
|
29
|
+
validated: "bg-primary/25",
|
|
30
|
+
deployed: "bg-primary/30",
|
|
31
|
+
rejected: "bg-destructive/20",
|
|
32
|
+
rolled_back: "bg-destructive/15",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const ACTION_ICON_COLOR: Record<string, string> = {
|
|
36
|
+
created: "text-primary/70",
|
|
37
|
+
validated: "text-primary/85",
|
|
38
|
+
deployed: "text-primary",
|
|
39
|
+
rejected: "text-destructive",
|
|
40
|
+
rolled_back: "text-destructive/70",
|
|
33
41
|
};
|
|
34
42
|
|
|
35
43
|
const ACTION_RING: Record<string, string> = {
|
|
36
|
-
created: "ring-
|
|
37
|
-
validated: "ring-
|
|
38
|
-
deployed: "ring-
|
|
39
|
-
rejected: "ring-
|
|
40
|
-
rolled_back: "ring-
|
|
44
|
+
created: "ring-primary/15",
|
|
45
|
+
validated: "ring-primary/25",
|
|
46
|
+
deployed: "ring-primary/30",
|
|
47
|
+
rejected: "ring-destructive/25",
|
|
48
|
+
rolled_back: "ring-destructive/15",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const ACTION_DOT: Record<string, string> = {
|
|
52
|
+
created: "bg-primary/40 ring-primary/30",
|
|
53
|
+
validated: "bg-primary/60 ring-primary/40",
|
|
54
|
+
deployed: "bg-primary ring-primary/50",
|
|
55
|
+
rejected: "bg-destructive/60 ring-destructive/40",
|
|
56
|
+
rolled_back: "bg-destructive/40 ring-destructive/30",
|
|
41
57
|
};
|
|
42
58
|
|
|
43
59
|
const ACTION_LINE: Record<string, string> = {
|
|
44
|
-
created: "bg-
|
|
45
|
-
validated: "bg-
|
|
46
|
-
deployed: "bg-
|
|
47
|
-
rejected: "bg-
|
|
48
|
-
rolled_back: "bg-
|
|
60
|
+
created: "bg-primary/15",
|
|
61
|
+
validated: "bg-primary/20",
|
|
62
|
+
deployed: "bg-primary/25",
|
|
63
|
+
rejected: "bg-destructive/20",
|
|
64
|
+
rolled_back: "bg-destructive/15",
|
|
49
65
|
};
|
|
50
66
|
|
|
51
67
|
interface Props {
|
|
@@ -93,7 +109,7 @@ function PassRateDelta({ snapshot }: { snapshot: EvalSnapshot }) {
|
|
|
93
109
|
<span
|
|
94
110
|
className={cn(
|
|
95
111
|
"inline-flex items-center gap-0.5 text-[10px] font-mono font-medium",
|
|
96
|
-
isPositive ? "text-
|
|
112
|
+
isPositive ? "text-primary" : "text-destructive",
|
|
97
113
|
)}
|
|
98
114
|
>
|
|
99
115
|
{isPositive ? (
|
|
@@ -119,23 +135,35 @@ function LifecycleLegend() {
|
|
|
119
135
|
const [open, setOpen] = useState(false);
|
|
120
136
|
|
|
121
137
|
return (
|
|
122
|
-
<div className="px-2 pb-
|
|
138
|
+
<div className="px-2 pb-3">
|
|
123
139
|
<button
|
|
124
140
|
type="button"
|
|
125
141
|
onClick={() => setOpen(!open)}
|
|
126
|
-
|
|
142
|
+
aria-expanded={open}
|
|
143
|
+
aria-controls="evolution-lifecycle-stages"
|
|
144
|
+
className="flex w-full items-center gap-1 text-[10px] text-muted-foreground/70 transition-colors hover:text-muted-foreground"
|
|
127
145
|
>
|
|
128
146
|
{open ? <ChevronDownIcon className="size-3" /> : <ChevronRightIcon className="size-3" />}
|
|
129
147
|
Lifecycle stages
|
|
130
148
|
</button>
|
|
131
149
|
{open && (
|
|
132
|
-
<div
|
|
150
|
+
<div
|
|
151
|
+
id="evolution-lifecycle-stages"
|
|
152
|
+
className="mt-1.5 space-y-2.5 rounded-md border bg-muted/30 p-2"
|
|
153
|
+
>
|
|
133
154
|
{LIFECYCLE_STEPS.map((step) => (
|
|
134
155
|
<div key={step.action} className="flex items-start gap-2">
|
|
135
|
-
<div
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
<div
|
|
157
|
+
className={cn(
|
|
158
|
+
"size-2 rounded-full shrink-0 ring-1 mt-[3px]",
|
|
159
|
+
ACTION_DOT[step.action],
|
|
160
|
+
)}
|
|
161
|
+
/>
|
|
162
|
+
<div className="min-w-0 flex flex-col gap-0.5">
|
|
163
|
+
<span className="text-[10px] font-medium leading-none">{step.label}</span>
|
|
164
|
+
<span className="text-[10px] text-muted-foreground/70 leading-tight">
|
|
165
|
+
{step.desc}
|
|
166
|
+
</span>
|
|
139
167
|
</div>
|
|
140
168
|
</div>
|
|
141
169
|
))}
|
|
@@ -158,7 +186,7 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
158
186
|
|
|
159
187
|
return (
|
|
160
188
|
<div className="flex flex-col gap-0">
|
|
161
|
-
<h2 className="
|
|
189
|
+
<h2 className="px-2 pb-2 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground/80">
|
|
162
190
|
Evolution
|
|
163
191
|
</h2>
|
|
164
192
|
<LifecycleLegend />
|
|
@@ -167,7 +195,8 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
167
195
|
const terminal = terminalAction(steps);
|
|
168
196
|
const isSelected = selectedProposalId === proposalId;
|
|
169
197
|
const lastStep = steps[steps.length - 1];
|
|
170
|
-
const dotColor = ACTION_COLOR[terminal] ?? "bg-muted-foreground";
|
|
198
|
+
const dotColor = ACTION_COLOR[terminal] ?? "bg-muted-foreground/20";
|
|
199
|
+
const iconColor = ACTION_ICON_COLOR[terminal] ?? "text-muted-foreground";
|
|
171
200
|
const ringColor = ACTION_RING[terminal] ?? "ring-muted-foreground/30";
|
|
172
201
|
const lineColor = ACTION_LINE[terminal] ?? "bg-border";
|
|
173
202
|
const isLast = groupIdx === groups.length - 1;
|
|
@@ -179,14 +208,15 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
179
208
|
<div className="flex flex-col items-center">
|
|
180
209
|
<div
|
|
181
210
|
className={cn(
|
|
182
|
-
"flex items-center justify-center size-7 rounded-full ring-2
|
|
211
|
+
"flex items-center justify-center size-7 rounded-full ring-2 shrink-0 z-10",
|
|
183
212
|
dotColor,
|
|
184
213
|
ringColor,
|
|
214
|
+
iconColor,
|
|
185
215
|
)}
|
|
186
216
|
>
|
|
187
217
|
{ACTION_ICON[terminal] ?? <CircleDotIcon className="size-3.5" />}
|
|
188
218
|
</div>
|
|
189
|
-
{!isLast && <div className={cn("w-0.5 flex-1 min-h-[
|
|
219
|
+
{!isLast && <div className={cn("w-0.5 flex-1 min-h-[8px] my-1", lineColor)} />}
|
|
190
220
|
</div>
|
|
191
221
|
|
|
192
222
|
{/* Content */}
|
|
@@ -241,7 +271,7 @@ export function EvolutionTimeline({ entries, selectedProposalId, onSelect }: Pro
|
|
|
241
271
|
key={`${s.action}-${i}`}
|
|
242
272
|
className={cn(
|
|
243
273
|
"size-1.5 rounded-full",
|
|
244
|
-
|
|
274
|
+
ACTION_DOT[s.action] ?? "bg-muted-foreground/40",
|
|
245
275
|
)}
|
|
246
276
|
/>
|
|
247
277
|
))}
|
|
@@ -8,7 +8,7 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../primitiv
|
|
|
8
8
|
import type { OrchestrateRunReport, OrchestrateRunSkillAction } from "../types";
|
|
9
9
|
|
|
10
10
|
const ACTION_ICON: Record<string, React.ReactNode> = {
|
|
11
|
-
evolve: <ZapIcon className="size-3 text-
|
|
11
|
+
evolve: <ZapIcon className="size-3 text-primary-accent" />,
|
|
12
12
|
watch: <EyeIcon className="size-3 text-blue-500" />,
|
|
13
13
|
skip: <SkipForwardIcon className="size-3 text-muted-foreground" />,
|
|
14
14
|
};
|
|
@@ -66,17 +66,15 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
|
66
66
|
<div
|
|
67
67
|
className={`mt-1.5 size-2 shrink-0 rounded-full ${
|
|
68
68
|
run.deployed > 0
|
|
69
|
-
? "bg-
|
|
69
|
+
? "bg-primary"
|
|
70
70
|
: run.evolved > 0
|
|
71
|
-
? "bg-
|
|
71
|
+
? "bg-primary-accent"
|
|
72
72
|
: "bg-muted-foreground/40"
|
|
73
73
|
}`}
|
|
74
74
|
/>
|
|
75
75
|
<div className="flex-1 min-w-0">
|
|
76
76
|
<div className="flex items-center gap-2">
|
|
77
|
-
<span className="text-
|
|
78
|
-
{timeAgo(run.timestamp)}
|
|
79
|
-
</span>
|
|
77
|
+
<span className="text-[10px] font-mono text-slate-500">{timeAgo(run.timestamp)}</span>
|
|
80
78
|
{run.dry_run && (
|
|
81
79
|
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
|
82
80
|
dry-run
|
|
@@ -90,7 +88,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
|
90
88
|
</div>
|
|
91
89
|
<div className="flex items-center gap-3 mt-1 text-xs text-muted-foreground">
|
|
92
90
|
{run.deployed > 0 && (
|
|
93
|
-
<span className="text-
|
|
91
|
+
<span className="text-primary font-medium">{run.deployed} deployed</span>
|
|
94
92
|
)}
|
|
95
93
|
{run.evolved > 0 && <span>{run.evolved} evolved</span>}
|
|
96
94
|
{run.watched > 0 && <span>{run.watched} watched</span>}
|
|
@@ -104,7 +102,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
|
104
102
|
</div>
|
|
105
103
|
</CollapsibleTrigger>
|
|
106
104
|
<CollapsibleContent>
|
|
107
|
-
<div className="ml-5 pl-3 border-l border-border space-y-0.5 pb-2">
|
|
105
|
+
<div className="ml-5 pl-3 border-l border-border/15 space-y-0.5 pb-2">
|
|
108
106
|
{nonSkipActions.map((action, i) => (
|
|
109
107
|
<SkillActionRow key={`${action.skill}-${i}`} action={action} />
|
|
110
108
|
))}
|
|
@@ -126,7 +124,32 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
|
|
|
126
124
|
);
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
export function OrchestrateRunsPanel({
|
|
127
|
+
export function OrchestrateRunsPanel({
|
|
128
|
+
runs,
|
|
129
|
+
embedded = false,
|
|
130
|
+
}: {
|
|
131
|
+
runs: OrchestrateRunReport[];
|
|
132
|
+
embedded?: boolean;
|
|
133
|
+
}) {
|
|
134
|
+
const totalDeployed = runs.reduce((sum, r) => sum + r.deployed, 0);
|
|
135
|
+
const content =
|
|
136
|
+
runs.length === 0 ? (
|
|
137
|
+
<p className="py-4 text-center text-sm text-muted-foreground">
|
|
138
|
+
No orchestrate runs yet. Run{" "}
|
|
139
|
+
<code className="rounded bg-muted px-1 py-0.5 text-xs">selftune orchestrate</code> to start.
|
|
140
|
+
</p>
|
|
141
|
+
) : (
|
|
142
|
+
<div className="space-y-0">
|
|
143
|
+
{runs.slice(0, 10).map((run) => (
|
|
144
|
+
<RunCard key={run.run_id} run={run} />
|
|
145
|
+
))}
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (embedded) {
|
|
150
|
+
return <div>{content}</div>;
|
|
151
|
+
}
|
|
152
|
+
|
|
130
153
|
if (runs.length === 0) {
|
|
131
154
|
return (
|
|
132
155
|
<Card>
|
|
@@ -147,8 +170,6 @@ export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] })
|
|
|
147
170
|
);
|
|
148
171
|
}
|
|
149
172
|
|
|
150
|
-
const totalDeployed = runs.reduce((sum, r) => sum + r.deployed, 0);
|
|
151
|
-
|
|
152
173
|
return (
|
|
153
174
|
<Card>
|
|
154
175
|
<CardHeader>
|
|
@@ -161,11 +182,7 @@ export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] })
|
|
|
161
182
|
{totalDeployed > 0 && <> · {totalDeployed} total deployments</>}
|
|
162
183
|
</CardDescription>
|
|
163
184
|
</CardHeader>
|
|
164
|
-
<CardContent
|
|
165
|
-
{runs.slice(0, 10).map((run) => (
|
|
166
|
-
<RunCard key={run.run_id} run={run} />
|
|
167
|
-
))}
|
|
168
|
-
</CardContent>
|
|
185
|
+
<CardContent>{content}</CardContent>
|
|
169
186
|
</Card>
|
|
170
187
|
);
|
|
171
188
|
}
|
|
@@ -13,7 +13,77 @@ export interface RecentActivityItem {
|
|
|
13
13
|
is_live: boolean;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export function RecentActivityFeed({
|
|
16
|
+
export function RecentActivityFeed({
|
|
17
|
+
items,
|
|
18
|
+
embedded = false,
|
|
19
|
+
}: {
|
|
20
|
+
items: RecentActivityItem[];
|
|
21
|
+
embedded?: boolean;
|
|
22
|
+
}) {
|
|
23
|
+
const content =
|
|
24
|
+
items.length === 0 ? (
|
|
25
|
+
<p className="py-6 text-center text-sm text-muted-foreground">No recent skill invocations</p>
|
|
26
|
+
) : (
|
|
27
|
+
<div className="space-y-2.5">
|
|
28
|
+
{items.slice(0, 20).map((item, i) => (
|
|
29
|
+
<div
|
|
30
|
+
key={`${item.session_id}-${item.skill_name}-${i}`}
|
|
31
|
+
className="flex gap-3 rounded-md p-1.5"
|
|
32
|
+
>
|
|
33
|
+
<div
|
|
34
|
+
className={`mt-0.5 w-10 h-10 shrink-0 rounded-xl bg-input flex items-center justify-center`}
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
className={`size-2 rounded-full ${
|
|
38
|
+
item.triggered
|
|
39
|
+
? "bg-primary shadow-[0_0_8px_rgba(79,242,255,0.6)]"
|
|
40
|
+
: "bg-muted-foreground/40"
|
|
41
|
+
}`}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div className="flex-1 min-w-0 space-y-0.5">
|
|
45
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
46
|
+
<span className="truncate font-bold text-sm">{item.skill_name}</span>
|
|
47
|
+
{item.is_live && (
|
|
48
|
+
<Badge variant="outline" className="h-4 gap-1 px-1 text-[10px]">
|
|
49
|
+
<CircleDotIcon className="size-2.5 text-primary" />
|
|
50
|
+
live
|
|
51
|
+
</Badge>
|
|
52
|
+
)}
|
|
53
|
+
{item.triggered ? (
|
|
54
|
+
<Badge
|
|
55
|
+
variant="default"
|
|
56
|
+
className="h-4 px-1 text-[10px] font-bold uppercase tracking-tighter bg-primary/10 text-primary"
|
|
57
|
+
>
|
|
58
|
+
triggered
|
|
59
|
+
</Badge>
|
|
60
|
+
) : (
|
|
61
|
+
<Badge
|
|
62
|
+
variant="secondary"
|
|
63
|
+
className="h-4 px-1 text-[10px] font-bold uppercase tracking-tighter"
|
|
64
|
+
>
|
|
65
|
+
checked
|
|
66
|
+
</Badge>
|
|
67
|
+
)}
|
|
68
|
+
<span className="ml-auto shrink-0 font-mono text-[10px] text-slate-500">
|
|
69
|
+
{timeAgo(item.timestamp)}
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
{item.query && (
|
|
73
|
+
<p className="line-clamp-1 text-sm text-card-foreground leading-relaxed">
|
|
74
|
+
{item.query}
|
|
75
|
+
</p>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
))}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (embedded) {
|
|
84
|
+
return <div>{content}</div>;
|
|
85
|
+
}
|
|
86
|
+
|
|
17
87
|
if (items.length === 0) {
|
|
18
88
|
return (
|
|
19
89
|
<Card>
|
|
@@ -41,46 +111,7 @@ export function RecentActivityFeed({ items }: { items: RecentActivityItem[] }) {
|
|
|
41
111
|
</CardTitle>
|
|
42
112
|
<CardDescription>Latest skill invocations across sessions</CardDescription>
|
|
43
113
|
</CardHeader>
|
|
44
|
-
<CardContent
|
|
45
|
-
{items.slice(0, 20).map((item, i) => (
|
|
46
|
-
<div
|
|
47
|
-
key={`${item.session_id}-${item.skill_name}-${i}`}
|
|
48
|
-
className="flex gap-3 rounded-md p-1.5"
|
|
49
|
-
>
|
|
50
|
-
<div
|
|
51
|
-
className={`mt-1 size-2 shrink-0 rounded-full ${
|
|
52
|
-
item.triggered ? "bg-emerald-500" : "bg-muted-foreground/40"
|
|
53
|
-
}`}
|
|
54
|
-
/>
|
|
55
|
-
<div className="flex-1 min-w-0 space-y-0.5">
|
|
56
|
-
<div className="flex items-center gap-2 flex-wrap">
|
|
57
|
-
<span className="text-xs font-medium truncate">{item.skill_name}</span>
|
|
58
|
-
{item.is_live && (
|
|
59
|
-
<Badge variant="outline" className="h-4 px-1 text-[10px] gap-1">
|
|
60
|
-
<CircleDotIcon className="size-2.5 text-emerald-500" />
|
|
61
|
-
live
|
|
62
|
-
</Badge>
|
|
63
|
-
)}
|
|
64
|
-
{item.triggered ? (
|
|
65
|
-
<Badge variant="default" className="h-4 px-1 text-[10px]">
|
|
66
|
-
triggered
|
|
67
|
-
</Badge>
|
|
68
|
-
) : (
|
|
69
|
-
<Badge variant="secondary" className="h-4 px-1 text-[10px]">
|
|
70
|
-
checked
|
|
71
|
-
</Badge>
|
|
72
|
-
)}
|
|
73
|
-
<span className="text-[10px] text-muted-foreground font-mono ml-auto shrink-0">
|
|
74
|
-
{timeAgo(item.timestamp)}
|
|
75
|
-
</span>
|
|
76
|
-
</div>
|
|
77
|
-
{item.query && (
|
|
78
|
-
<p className="text-xs text-muted-foreground line-clamp-1 font-mono">{item.query}</p>
|
|
79
|
-
)}
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
))}
|
|
83
|
-
</CardContent>
|
|
114
|
+
<CardContent>{content}</CardContent>
|
|
84
115
|
</Card>
|
|
85
116
|
);
|
|
86
117
|
}
|
|
@@ -24,6 +24,9 @@ interface SectionCardsProps {
|
|
|
24
24
|
activeSessionsCount?: number;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const CARD_DESCRIPTION_CLASS =
|
|
28
|
+
"flex items-center gap-1.5 text-[10px] uppercase tracking-widest text-slate-500";
|
|
29
|
+
|
|
27
30
|
export function SectionCards({
|
|
28
31
|
skillsCount,
|
|
29
32
|
avgPassRate,
|
|
@@ -38,10 +41,10 @@ export function SectionCards({
|
|
|
38
41
|
const passRateGood = avgPassRate !== null && avgPassRate >= 0.7;
|
|
39
42
|
|
|
40
43
|
return (
|
|
41
|
-
<div className="grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:shadow-
|
|
44
|
+
<div className="grid grid-cols-1 gap-4 px-4 *:data-[slot=card]:shadow-none lg:px-6 @xl/main:grid-cols-2 @5xl/main:grid-cols-3">
|
|
42
45
|
<Card className="@container/card">
|
|
43
46
|
<CardHeader>
|
|
44
|
-
<CardDescription className=
|
|
47
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
45
48
|
<LayersIcon className="size-3.5" />
|
|
46
49
|
Skills Monitored
|
|
47
50
|
<InfoTip text="Total number of skills detected and being tracked by selftune" />
|
|
@@ -60,7 +63,7 @@ export function SectionCards({
|
|
|
60
63
|
|
|
61
64
|
<Card className="@container/card">
|
|
62
65
|
<CardHeader>
|
|
63
|
-
<CardDescription className=
|
|
66
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
64
67
|
<FlaskConicalIcon className="size-3.5" />
|
|
65
68
|
Avg Trigger Rate
|
|
66
69
|
<InfoTip text="Average percentage of skill checks that resulted in a trigger across all graded skills (5+ checks). Run selftune evolve to improve this." />
|
|
@@ -91,7 +94,7 @@ export function SectionCards({
|
|
|
91
94
|
|
|
92
95
|
<Card className="@container/card">
|
|
93
96
|
<CardHeader>
|
|
94
|
-
<CardDescription className=
|
|
97
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
95
98
|
<SearchXIcon className="size-3.5" />
|
|
96
99
|
Unmatched Queries
|
|
97
100
|
<InfoTip text="User prompts that didn't match any skill's trigger criteria — potential gaps in coverage" />
|
|
@@ -112,7 +115,7 @@ export function SectionCards({
|
|
|
112
115
|
|
|
113
116
|
<Card className="@container/card">
|
|
114
117
|
<CardHeader>
|
|
115
|
-
<CardDescription className=
|
|
118
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
116
119
|
<ActivityIcon className="size-3.5" />
|
|
117
120
|
Sessions
|
|
118
121
|
<InfoTip text="Total agent sessions that have been recorded and analyzed" />
|
|
@@ -124,8 +127,8 @@ export function SectionCards({
|
|
|
124
127
|
<CardAction>
|
|
125
128
|
<Badge variant="outline" className="gap-1.5">
|
|
126
129
|
<span className="relative flex size-2">
|
|
127
|
-
<span className="absolute inline-flex size-full animate-ping rounded-full bg-
|
|
128
|
-
<span className="relative inline-flex size-2 rounded-full bg-
|
|
130
|
+
<span className="absolute inline-flex size-full animate-ping rounded-full bg-primary opacity-75" />
|
|
131
|
+
<span className="relative inline-flex size-2 rounded-full bg-primary shadow-[0_0_8px_color-mix(in_srgb,var(--primary)_60%,transparent)]" />
|
|
129
132
|
</span>
|
|
130
133
|
{activeSessionsCount} in progress
|
|
131
134
|
</Badge>
|
|
@@ -136,7 +139,7 @@ export function SectionCards({
|
|
|
136
139
|
|
|
137
140
|
<Card className="@container/card">
|
|
138
141
|
<CardHeader>
|
|
139
|
-
<CardDescription className=
|
|
142
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
140
143
|
<AlertTriangleIcon className="size-3.5" />
|
|
141
144
|
Undeployed Proposals
|
|
142
145
|
<InfoTip text="Evolution proposals that have been generated but not yet validated or deployed. Requires running selftune evolve." />
|
|
@@ -158,7 +161,7 @@ export function SectionCards({
|
|
|
158
161
|
|
|
159
162
|
<Card className="@container/card">
|
|
160
163
|
<CardHeader>
|
|
161
|
-
<CardDescription className=
|
|
164
|
+
<CardDescription className={CARD_DESCRIPTION_CLASS}>
|
|
162
165
|
<EyeIcon className="size-3.5" />
|
|
163
166
|
Total Evidence
|
|
164
167
|
<InfoTip text="Number of evidence entries documenting skill changes with before/after validation results. Requires running selftune evolve." />
|
|
@@ -12,7 +12,7 @@ function Card({
|
|
|
12
12
|
data-slot="card"
|
|
13
13
|
data-size={size}
|
|
14
14
|
className={cn(
|
|
15
|
-
"group/card flex flex-col gap-4 overflow-hidden rounded-
|
|
15
|
+
"group/card flex flex-col gap-4 overflow-hidden rounded-2xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/5 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
|
16
16
|
className,
|
|
17
17
|
)}
|
|
18
18
|
{...props}
|
package/skill/SKILL.md
CHANGED
|
@@ -12,7 +12,7 @@ description: >
|
|
|
12
12
|
even if they don't say "selftune" explicitly.
|
|
13
13
|
metadata:
|
|
14
14
|
author: selftune-dev
|
|
15
|
-
version: 0.2.
|
|
15
|
+
version: 0.2.10
|
|
16
16
|
category: developer-tools
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -89,6 +89,7 @@ selftune eval generate --skill <name> [--list-skills] [--stats] [--max N] [
|
|
|
89
89
|
selftune eval unit-test --skill <name> --tests <path> [--run-agent] [--generate]
|
|
90
90
|
selftune eval import --dir <path> --skill <name> --output <path> [--match-strategy exact|fuzzy]
|
|
91
91
|
selftune eval composability --skill <name> [--window N] [--telemetry-log <path>]
|
|
92
|
+
selftune eval family-overlap --prefix <family-> | --skills <a,b,c> [--parent-skill <name>] [--min-overlap 0.3] [--min-shared 2]
|
|
92
93
|
|
|
93
94
|
# Other commands
|
|
94
95
|
selftune watch --skill <name> --skill-path <path> [--auto-rollback]
|
|
@@ -96,6 +97,8 @@ selftune status
|
|
|
96
97
|
selftune last
|
|
97
98
|
selftune doctor
|
|
98
99
|
selftune dashboard [--port <port>] [--no-open]
|
|
100
|
+
selftune contributions [status|preview <skill>|upload [--dry-run]|approve <skill>|revoke <skill>|default <ask|always|never>|reset]
|
|
101
|
+
selftune creator-contributions [status|enable --skill <name>|enable --all [--prefix <value>]|disable --skill <name>]
|
|
99
102
|
selftune contribute [--skill NAME] [--preview] [--sanitize LEVEL] [--submit]
|
|
100
103
|
selftune cron setup [--dry-run] # auto-detect platform (cron/launchd/systemd)
|
|
101
104
|
selftune cron setup --platform openclaw [--dry-run] [--tz <timezone>] # OpenClaw-specific
|
|
@@ -104,9 +107,28 @@ selftune cron remove [--dry-run]
|
|
|
104
107
|
selftune telemetry [status|enable|disable]
|
|
105
108
|
selftune export [TABLE...] [--output/-o DIR] [--since DATE]
|
|
106
109
|
|
|
110
|
+
# Autonomous loop
|
|
111
|
+
selftune orchestrate [--dry-run] [--review-required] [--auto-approve] [--skill NAME] [--max-skills N] [--recent-window HOURS] [--sync-force] [--max-auto-grade N] [--loop] [--loop-interval SECS]
|
|
112
|
+
selftune sync [--since DATE] [--dry-run] [--force] [--no-claude] [--no-codex] [--no-opencode] [--no-openclaw] [--no-repair] [--json]
|
|
113
|
+
|
|
114
|
+
# Discovery + badges
|
|
115
|
+
selftune workflows [--skill NAME] [--skill-path PATH] [--min-occurrences N] [--window N] [--json] [save --skill NAME --skill-path PATH]
|
|
116
|
+
selftune badge --skill <name> [--format svg|markdown|url] [--output PATH]
|
|
117
|
+
|
|
118
|
+
# Maintenance
|
|
119
|
+
selftune quickstart
|
|
120
|
+
selftune repair-skill-usage [--since DATE] [--dry-run]
|
|
121
|
+
selftune recover [--full] [--force] [--since DATE]
|
|
122
|
+
selftune export-canonical [--out FILE] [--platform NAME] [--record-kind KIND] [--pretty] [--push-payload]
|
|
123
|
+
selftune uninstall [--dry-run] [--keep-logs] [--npm-uninstall]
|
|
124
|
+
|
|
125
|
+
# Hook dispatch (for debugging/manual invocation)
|
|
126
|
+
selftune hook <name> # prompt-log | session-stop | skill-eval | auto-activate | skill-change-guard | evolution-guard
|
|
127
|
+
|
|
107
128
|
# Alpha enrollment (device-code flow — browser opens automatically)
|
|
108
129
|
selftune init --alpha --alpha-email <email>
|
|
109
130
|
selftune alpha upload [--dry-run]
|
|
131
|
+
selftune alpha relink
|
|
110
132
|
selftune status # shows cloud link state + upload readiness
|
|
111
133
|
```
|
|
112
134
|
|
|
@@ -123,6 +145,8 @@ selftune status # shows c
|
|
|
123
145
|
| doctor, health, hooks, broken, diagnose, not working, something wrong | Doctor | Workflows/Doctor.md |
|
|
124
146
|
| ingest, import, codex logs, opencode, openclaw, wrap codex | Ingest | Workflows/Ingest.md |
|
|
125
147
|
| replay, backfill, claude transcripts, historical sessions | Replay | Workflows/Replay.md |
|
|
148
|
+
| contributions, sharing preferences, opt in creator sharing, opt out creator sharing, approve contributions, revoke contributions, preview contributions, upload contributions, relay queue, contribution upload, contribution preview | Contributions | Workflows/Contributions.md |
|
|
149
|
+
| creator contributions, bundle contribution config, selftune.contribute.json, enable creator contribution, disable creator contribution, bulk enable creator contribution, enable all creator contributions, creator prefix config, --all, --prefix | CreatorContributions | Workflows/CreatorContributions.md |
|
|
126
150
|
| contribute, share, community, export data, anonymized, give back | Contribute | Workflows/Contribute.md |
|
|
127
151
|
| init, setup, set up, bootstrap, first time, install, configure selftune, alpha, enroll, alpha enrollment, cloud link, upload credential | Initialize | Workflows/Initialize.md |
|
|
128
152
|
| cron, schedule, automate evolution, run automatically | Cron | Workflows/Cron.md |
|
|
@@ -131,7 +155,7 @@ selftune status # shows c
|
|
|
131
155
|
| evolution memory, session continuity, what happened last | EvolutionMemory | Workflows/EvolutionMemory.md |
|
|
132
156
|
| grade baseline, baseline lift, adds value, skill value, no-skill comparison | Baseline | Workflows/Baseline.md |
|
|
133
157
|
| eval unit-test, skill test, test skill, generate tests, run tests | UnitTest | Workflows/UnitTest.md |
|
|
134
|
-
| eval composability, co-occurrence, skill conflicts, skills together
|
|
158
|
+
| eval composability, co-occurrence, skill conflicts, skills together, family overlap, sibling confusion, consolidate skill family | Composability | Workflows/Composability.md |
|
|
135
159
|
| eval import, skillsbench, external evals, benchmark tasks | ImportSkillsBench | Workflows/ImportSkillsBench.md |
|
|
136
160
|
| telemetry, analytics, disable analytics, opt out, tracking, privacy | Telemetry | Workflows/Telemetry.md |
|
|
137
161
|
| orchestrate, autonomous, full loop, improve all skills, run selftune loop | Orchestrate | Workflows/Orchestrate.md |
|
|
@@ -139,6 +163,12 @@ selftune status # shows c
|
|
|
139
163
|
| badge, readme badge, skill badge, health badge | Badge | Workflows/Badge.md |
|
|
140
164
|
| workflows, discover workflows, list workflows, multi-skill workflows | Workflows | Workflows/Workflows.md |
|
|
141
165
|
| alpha upload, upload data, send alpha data, manual upload, dry run upload | AlphaUpload | Workflows/AlphaUpload.md |
|
|
166
|
+
| recover, rebuild sqlite, recover db, legacy backfill, restore from export snapshot | Recover | Workflows/Recover.md |
|
|
167
|
+
| quickstart, getting started, onboard, first time setup, new user | Quickstart | Workflows/Quickstart.md |
|
|
168
|
+
| uninstall, remove selftune, clean up, teardown | Uninstall | Workflows/Uninstall.md |
|
|
169
|
+
| repair, rebuild usage, fix skill usage, trustworthy usage, repair-skill-usage | RepairSkillUsage | Workflows/RepairSkillUsage.md |
|
|
170
|
+
| export canonical, canonical export, canonical telemetry, push payload | ExportCanonical | Workflows/ExportCanonical.md |
|
|
171
|
+
| hook, run hook, invoke hook, manual hook, debug hook | Hook | Workflows/Hook.md |
|
|
142
172
|
| export, dump, jsonl, export sqlite, debug export | Export | _(direct command — no workflow file)_ |
|
|
143
173
|
| status, health summary, skill health, how are skills, skills doing, run selftune | Status | _(direct command — no workflow file)_ |
|
|
144
174
|
| last, last session, recent session, what happened, what changed | Last | _(direct command — no workflow file)_ |
|
|
@@ -319,6 +349,14 @@ accomplish a task _using_ a skill, route to that skill instead.
|
|
|
319
349
|
| `agents/pattern-analyst.md` | Cross-skill conflict detection | Spawn when composability flags conflicts |
|
|
320
350
|
| `agents/evolution-reviewer.md` | Safety gate for evolution proposals | Spawn before deploying high-stakes evolutions |
|
|
321
351
|
| `agents/integration-guide.md` | Guided setup for complex projects | Spawn for monorepos, multi-skill setups |
|
|
352
|
+
| `Workflows/Quickstart.md` | Guided onboarding: init, ingest, status | First-time setup for new users |
|
|
353
|
+
| `Workflows/Uninstall.md` | Clean removal of selftune data and config | When removing selftune completely |
|
|
354
|
+
| `Workflows/RepairSkillUsage.md` | Rebuild skill usage from source transcripts | When skill usage data seems inaccurate |
|
|
355
|
+
| `Workflows/Recover.md` | Recover SQLite from legacy/exported JSONL | When rebuilding or backfilling SQLite |
|
|
356
|
+
| `Workflows/Contributions.md` | Manage creator-directed sharing preferences | When approving or revoking creator contribution |
|
|
357
|
+
| `Workflows/CreatorContributions.md` | Manage bundled `selftune.contribute.json` configs | When preparing a skill package for creator contributions |
|
|
358
|
+
| `Workflows/ExportCanonical.md` | Export canonical telemetry for downstream use | When exporting data for external consumption |
|
|
359
|
+
| `Workflows/Hook.md` | Manual hook invocation for debugging | When debugging or testing hooks manually |
|
|
322
360
|
| `references/logs.md` | Log file formats (telemetry, usage, queries, audit) | When parsing or debugging log files |
|
|
323
361
|
| `references/grading-methodology.md` | 3-tier grading model, evidence standards | When grading sessions or interpreting grades |
|
|
324
362
|
| `references/invocation-taxonomy.md` | 4 invocation types, coverage analysis | When analyzing trigger coverage |
|
|
@@ -24,6 +24,10 @@ selftune alpha upload [--dry-run]
|
|
|
24
24
|
4. Build V2 push envelopes and flush them to the cloud API
|
|
25
25
|
5. Print a JSON summary with `enrolled`, `prepared`, `sent`, `failed`, `skipped`, and optional `guidance`
|
|
26
26
|
|
|
27
|
+
`selftune sync` already triggers an upload cycle automatically when alpha is
|
|
28
|
+
enrolled. Use this workflow when you want a manual upload now or want to see a
|
|
29
|
+
dry-run summary of what SQLite-backed staging would send.
|
|
30
|
+
|
|
27
31
|
## Examples
|
|
28
32
|
|
|
29
33
|
Preview the upload:
|