selftune 0.2.22 → 0.2.23

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.
Files changed (94) hide show
  1. package/README.md +4 -2
  2. package/apps/local-dashboard/dist/assets/index-CwOtTrUS.css +1 -0
  3. package/apps/local-dashboard/dist/assets/index-f1HQpbeH.js +59 -0
  4. package/apps/local-dashboard/dist/assets/vendor-ui-jVSaIZey.js +12 -0
  5. package/apps/local-dashboard/dist/index.html +3 -3
  6. package/cli/selftune/adapters/pi/hook.ts +273 -0
  7. package/cli/selftune/adapters/pi/install.ts +207 -0
  8. package/cli/selftune/constants.ts +10 -1
  9. package/cli/selftune/dashboard-contract.ts +14 -0
  10. package/cli/selftune/evolution/engines/judge-engine.ts +96 -0
  11. package/cli/selftune/evolution/engines/replay-engine.ts +158 -0
  12. package/cli/selftune/evolution/evidence.ts +2 -6
  13. package/cli/selftune/evolution/evolve-body.ts +73 -20
  14. package/cli/selftune/evolution/validate-body.ts +78 -42
  15. package/cli/selftune/evolution/validate-routing.ts +45 -104
  16. package/cli/selftune/hooks/skill-eval.ts +2 -1
  17. package/cli/selftune/hooks-shared/types.ts +1 -0
  18. package/cli/selftune/index.ts +23 -5
  19. package/cli/selftune/ingestors/pi-ingest.ts +726 -0
  20. package/cli/selftune/init.ts +11 -1
  21. package/cli/selftune/localdb/direct-write.ts +85 -0
  22. package/cli/selftune/localdb/materialize.ts +6 -7
  23. package/cli/selftune/localdb/queries.ts +126 -0
  24. package/cli/selftune/localdb/schema.ts +38 -0
  25. package/cli/selftune/observability.ts +8 -1
  26. package/cli/selftune/orchestrate.ts +43 -0
  27. package/cli/selftune/registry/client.ts +74 -0
  28. package/cli/selftune/registry/history.ts +54 -0
  29. package/cli/selftune/registry/index.ts +90 -0
  30. package/cli/selftune/registry/install.ts +141 -0
  31. package/cli/selftune/registry/list.ts +44 -0
  32. package/cli/selftune/registry/push.ts +171 -0
  33. package/cli/selftune/registry/rollback.ts +49 -0
  34. package/cli/selftune/registry/status.ts +62 -0
  35. package/cli/selftune/registry/sync.ts +125 -0
  36. package/cli/selftune/repair/skill-usage.ts +4 -1
  37. package/cli/selftune/status.ts +31 -0
  38. package/cli/selftune/sync.ts +127 -23
  39. package/cli/selftune/types.ts +2 -1
  40. package/cli/selftune/utils/jsonl.ts +1 -30
  41. package/cli/selftune/utils/skill-discovery.ts +22 -0
  42. package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  43. package/node_modules/@selftune/telemetry-contract/fixtures/golden.test.ts +0 -1
  44. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  45. package/node_modules/@selftune/telemetry-contract/package.json +1 -1
  46. package/node_modules/@selftune/telemetry-contract/src/index.ts +1 -0
  47. package/node_modules/@selftune/telemetry-contract/src/schemas.ts +22 -4
  48. package/node_modules/@selftune/telemetry-contract/src/types.ts +1 -12
  49. package/node_modules/@selftune/telemetry-contract/tests/compatibility.test.ts +0 -1
  50. package/package.json +1 -1
  51. package/packages/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  52. package/packages/telemetry-contract/fixtures/golden.test.ts +0 -1
  53. package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  54. package/packages/telemetry-contract/package.json +1 -1
  55. package/packages/telemetry-contract/src/index.ts +1 -0
  56. package/packages/telemetry-contract/src/schemas.ts +22 -4
  57. package/packages/telemetry-contract/src/types.ts +1 -12
  58. package/packages/telemetry-contract/tests/compatibility.test.ts +0 -1
  59. package/packages/ui/AGENTS.md +16 -0
  60. package/packages/ui/README.md +1 -1
  61. package/packages/ui/package.json +1 -1
  62. package/packages/ui/src/components/ActivityTimeline.tsx +152 -168
  63. package/packages/ui/src/components/AnalyticsCharts.tsx +344 -0
  64. package/packages/ui/src/components/EvidenceViewer.tsx +153 -443
  65. package/packages/ui/src/components/EvolutionTimeline.tsx +34 -87
  66. package/packages/ui/src/components/InfoTip.tsx +1 -2
  67. package/packages/ui/src/components/InvocationsPanel.tsx +413 -0
  68. package/packages/ui/src/components/JobHistoryTimeline.tsx +156 -0
  69. package/packages/ui/src/components/OrchestrateRunsPanel.tsx +18 -36
  70. package/packages/ui/src/components/OverviewPanels.tsx +652 -0
  71. package/packages/ui/src/components/PipelineStatusBar.tsx +65 -0
  72. package/packages/ui/src/components/SkillReportGuide.tsx +215 -0
  73. package/packages/ui/src/components/SkillReportPanels.tsx +919 -0
  74. package/packages/ui/src/components/SkillsLibrary.tsx +437 -0
  75. package/packages/ui/src/components/index.ts +56 -1
  76. package/packages/ui/src/components/section-cards.tsx +18 -35
  77. package/packages/ui/src/components/skill-health-grid.tsx +47 -37
  78. package/packages/ui/src/lib/constants.tsx +0 -1
  79. package/packages/ui/src/primitives/card.tsx +1 -1
  80. package/packages/ui/src/primitives/checkbox.tsx +1 -1
  81. package/packages/ui/src/primitives/dropdown-menu.tsx +2 -2
  82. package/packages/ui/src/primitives/select.tsx +2 -2
  83. package/packages/ui/src/types.ts +172 -4
  84. package/skill/SKILL.md +18 -4
  85. package/skill/Workflows/Ingest.md +60 -2
  86. package/skill/Workflows/Initialize.md +8 -5
  87. package/skill/Workflows/PlatformHooks.md +19 -3
  88. package/skill/Workflows/Registry.md +99 -0
  89. package/skill/Workflows/Sync.md +3 -1
  90. package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +0 -60
  91. package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +0 -1
  92. package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +0 -12
  93. package/cli/selftune/utils/html.ts +0 -27
  94. package/packages/ui/src/components/RecentActivityFeed.tsx +0 -117
@@ -0,0 +1,156 @@
1
+ import { useState } from "react";
2
+ import { Card, CardContent, CardHeader, CardTitle } from "../primitives/card";
3
+ import { Badge } from "../primitives/badge";
4
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../primitives/collapsible";
5
+ import { timeAgo } from "../lib/format";
6
+ import { ActivityIcon, ChevronDownIcon } from "lucide-react";
7
+ import type { JobExecution } from "../types";
8
+
9
+ const JOB_NAMES = [
10
+ "aggregation",
11
+ "alert-checker",
12
+ "badge-cache",
13
+ "retention-cleanup",
14
+ "orchestrate",
15
+ "sync",
16
+ "status",
17
+ ] as const;
18
+
19
+ export interface JobHistoryFilters {
20
+ job: string;
21
+ status: string;
22
+ }
23
+
24
+ function formatDuration(ms: number): string {
25
+ if (ms < 1000) return `${ms}ms`;
26
+ return `${(ms / 1000).toFixed(1)}s`;
27
+ }
28
+
29
+ export function JobHistoryTimeline({
30
+ executions,
31
+ filters,
32
+ onFilterChange,
33
+ }: {
34
+ executions: JobExecution[];
35
+ filters?: JobHistoryFilters;
36
+ onFilterChange?: (filters: JobHistoryFilters) => void;
37
+ }) {
38
+ const currentJob = filters?.job ?? "";
39
+ const currentStatus = filters?.status ?? "";
40
+
41
+ return (
42
+ <Card>
43
+ <CardHeader>
44
+ <CardTitle className="flex items-center gap-2 text-sm">
45
+ <ActivityIcon className="size-4" />
46
+ Execution History
47
+ </CardTitle>
48
+ </CardHeader>
49
+ <CardContent className="space-y-4">
50
+ {/* Filter bar */}
51
+ {onFilterChange && (
52
+ <div className="flex flex-wrap items-center gap-2">
53
+ <select
54
+ value={currentJob}
55
+ onChange={(e) => onFilterChange({ job: e.target.value, status: currentStatus })}
56
+ className="h-7 rounded-md border border-input bg-transparent px-2 text-xs text-foreground outline-none focus:border-ring"
57
+ >
58
+ <option value="">All jobs</option>
59
+ {JOB_NAMES.map((name) => (
60
+ <option key={name} value={name}>
61
+ {name}
62
+ </option>
63
+ ))}
64
+ </select>
65
+ <select
66
+ value={currentStatus}
67
+ onChange={(e) => onFilterChange({ job: currentJob, status: e.target.value })}
68
+ className="h-7 rounded-md border border-input bg-transparent px-2 text-xs text-foreground outline-none focus:border-ring"
69
+ >
70
+ <option value="">All statuses</option>
71
+ <option value="success">Success</option>
72
+ <option value="error">Error</option>
73
+ </select>
74
+ </div>
75
+ )}
76
+
77
+ {/* Timeline */}
78
+ {executions.length === 0 ? (
79
+ <p className="py-8 text-center text-sm text-muted-foreground">No executions yet</p>
80
+ ) : (
81
+ <div className="space-y-2">
82
+ {executions.map((exec) => (
83
+ <ExecutionRow key={exec.id} execution={exec} />
84
+ ))}
85
+ </div>
86
+ )}
87
+ </CardContent>
88
+ </Card>
89
+ );
90
+ }
91
+
92
+ function ExecutionRow({ execution }: { execution: JobExecution }) {
93
+ const [open, setOpen] = useState(false);
94
+ const isError = execution.status === "error";
95
+ const hasDetails = execution.error || Object.keys(execution.metrics).length > 0;
96
+
97
+ return (
98
+ <Collapsible open={open} onOpenChange={setOpen}>
99
+ <div
100
+ className={`rounded-md border p-2 ${
101
+ isError ? "border-red-500/30 bg-red-950/10" : "border-border"
102
+ }`}
103
+ >
104
+ <CollapsibleTrigger
105
+ disabled={!hasDetails}
106
+ className="flex w-full items-center gap-3 text-left disabled:cursor-default"
107
+ >
108
+ <span
109
+ className={`mt-0.5 size-2 shrink-0 rounded-full ${
110
+ isError ? "bg-red-500" : "bg-emerald-500"
111
+ }`}
112
+ />
113
+ <Badge variant={isError ? "destructive" : "secondary"} className="text-[10px]">
114
+ {execution.jobName}
115
+ </Badge>
116
+ <span className="text-xs text-muted-foreground font-mono">
117
+ {timeAgo(execution.startedAt)}
118
+ </span>
119
+ <span className="text-xs text-muted-foreground/60 font-mono">
120
+ took {formatDuration(execution.durationMs)}
121
+ </span>
122
+ {typeof execution.metrics.total_llm_calls === "number" &&
123
+ execution.metrics.total_llm_calls > 0 && (
124
+ <span className="text-xs text-muted-foreground/60 font-mono">
125
+ {execution.metrics.total_llm_calls} LLM calls
126
+ </span>
127
+ )}
128
+ {hasDetails && (
129
+ <ChevronDownIcon
130
+ className={`ml-auto size-3.5 text-muted-foreground transition-transform ${
131
+ open ? "rotate-180" : ""
132
+ }`}
133
+ />
134
+ )}
135
+ </CollapsibleTrigger>
136
+
137
+ {hasDetails && (
138
+ <CollapsibleContent className="mt-2 border-t border-border pt-2">
139
+ {execution.error && (
140
+ <p className="text-xs text-red-400 font-mono mb-1">{execution.error}</p>
141
+ )}
142
+ {Object.keys(execution.metrics).length > 0 && (
143
+ <div className="flex flex-wrap gap-x-4 gap-y-1">
144
+ {Object.entries(execution.metrics).map(([key, value]) => (
145
+ <span key={key} className="text-[11px] text-muted-foreground font-mono">
146
+ {key}: {String(value)}
147
+ </span>
148
+ ))}
149
+ </div>
150
+ )}
151
+ </CollapsibleContent>
152
+ )}
153
+ </div>
154
+ </Collapsible>
155
+ );
156
+ }
@@ -1,14 +1,13 @@
1
- import { BotIcon, ChevronRightIcon, EyeIcon, SkipForwardIcon, ZapIcon } from "lucide-react";
2
1
  import { useState } from "react";
3
-
4
- import { timeAgo } from "../lib/format";
5
2
  import { Badge } from "../primitives/badge";
6
3
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../primitives/card";
7
4
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../primitives/collapsible";
8
5
  import type { OrchestrateRunReport, OrchestrateRunSkillAction } from "../types";
6
+ import { timeAgo } from "../lib/format";
7
+ import { BotIcon, ChevronRightIcon, EyeIcon, SkipForwardIcon, ZapIcon } from "lucide-react";
9
8
 
10
9
  const ACTION_ICON: Record<string, React.ReactNode> = {
11
- evolve: <ZapIcon className="size-3 text-primary-accent" />,
10
+ evolve: <ZapIcon className="size-3 text-amber-500" />,
12
11
  watch: <EyeIcon className="size-3 text-blue-500" />,
13
12
  skip: <SkipForwardIcon className="size-3 text-muted-foreground" />,
14
13
  };
@@ -66,15 +65,17 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
66
65
  <div
67
66
  className={`mt-1.5 size-2 shrink-0 rounded-full ${
68
67
  run.deployed > 0
69
- ? "bg-primary"
68
+ ? "bg-emerald-500"
70
69
  : run.evolved > 0
71
- ? "bg-primary-accent"
70
+ ? "bg-amber-400"
72
71
  : "bg-muted-foreground/40"
73
72
  }`}
74
73
  />
75
74
  <div className="flex-1 min-w-0">
76
75
  <div className="flex items-center gap-2">
77
- <span className="text-[10px] font-mono text-slate-500">{timeAgo(run.timestamp)}</span>
76
+ <span className="text-xs font-mono text-muted-foreground">
77
+ {timeAgo(run.timestamp)}
78
+ </span>
78
79
  {run.dry_run && (
79
80
  <Badge variant="outline" className="text-[10px] h-4 px-1.5">
80
81
  dry-run
@@ -88,7 +89,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
88
89
  </div>
89
90
  <div className="flex items-center gap-3 mt-1 text-xs text-muted-foreground">
90
91
  {run.deployed > 0 && (
91
- <span className="text-primary font-medium">{run.deployed} deployed</span>
92
+ <span className="text-emerald-600 font-medium">{run.deployed} deployed</span>
92
93
  )}
93
94
  {run.evolved > 0 && <span>{run.evolved} evolved</span>}
94
95
  {run.watched > 0 && <span>{run.watched} watched</span>}
@@ -102,7 +103,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
102
103
  </div>
103
104
  </CollapsibleTrigger>
104
105
  <CollapsibleContent>
105
- <div className="ml-5 pl-3 border-l border-border/15 space-y-0.5 pb-2">
106
+ <div className="ml-5 pl-3 border-l border-border space-y-0.5 pb-2">
106
107
  {nonSkipActions.map((action, i) => (
107
108
  <SkillActionRow key={`${action.skill}-${i}`} action={action} />
108
109
  ))}
@@ -124,32 +125,7 @@ function RunCard({ run }: { run: OrchestrateRunReport }) {
124
125
  );
125
126
  }
126
127
 
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
-
128
+ export function OrchestrateRunsPanel({ runs }: { runs: OrchestrateRunReport[] }) {
153
129
  if (runs.length === 0) {
154
130
  return (
155
131
  <Card>
@@ -170,6 +146,8 @@ export function OrchestrateRunsPanel({
170
146
  );
171
147
  }
172
148
 
149
+ const totalDeployed = runs.reduce((sum, r) => sum + r.deployed, 0);
150
+
173
151
  return (
174
152
  <Card>
175
153
  <CardHeader>
@@ -182,7 +160,11 @@ export function OrchestrateRunsPanel({
182
160
  {totalDeployed > 0 && <> &middot; {totalDeployed} total deployments</>}
183
161
  </CardDescription>
184
162
  </CardHeader>
185
- <CardContent>{content}</CardContent>
163
+ <CardContent className="space-y-0">
164
+ {runs.slice(0, 10).map((run) => (
165
+ <RunCard key={run.run_id} run={run} />
166
+ ))}
167
+ </CardContent>
186
168
  </Card>
187
169
  );
188
170
  }