selftune 0.2.22 → 0.2.24

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 (270) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +95 -15
  3. package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +1 -0
  4. package/apps/local-dashboard/dist/assets/index-Dmx7LPVX.js +15 -0
  5. package/apps/local-dashboard/dist/assets/vendor-react-C5oyHiV1.js +11 -0
  6. package/apps/local-dashboard/dist/assets/{vendor-table-BIiI3YhS.js → vendor-table-Bc_bbKd8.js} +1 -1
  7. package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +1 -0
  8. package/apps/local-dashboard/dist/index.html +5 -5
  9. package/cli/selftune/adapters/codex/install.ts +310 -78
  10. package/cli/selftune/adapters/opencode/install.ts +3 -4
  11. package/cli/selftune/adapters/pi/hook.ts +273 -0
  12. package/cli/selftune/adapters/pi/install.ts +207 -0
  13. package/cli/selftune/alpha-upload/build-payloads.ts +3 -3
  14. package/cli/selftune/alpha-upload/stage-canonical.ts +17 -11
  15. package/cli/selftune/auto-update.ts +200 -8
  16. package/cli/selftune/canonical-export.ts +55 -25
  17. package/cli/selftune/command-surface.ts +397 -0
  18. package/cli/selftune/constants.ts +10 -1
  19. package/cli/selftune/contribute/contribute.ts +64 -13
  20. package/cli/selftune/contribution-config.ts +57 -3
  21. package/cli/selftune/contribution-preferences.ts +117 -0
  22. package/cli/selftune/contribution-signals.ts +8 -4
  23. package/cli/selftune/contribution-staging.ts +13 -2
  24. package/cli/selftune/contributions.ts +55 -121
  25. package/cli/selftune/creator-contributions.ts +29 -10
  26. package/cli/selftune/cron/setup.ts +7 -3
  27. package/cli/selftune/dashboard-contract.ts +87 -0
  28. package/cli/selftune/dashboard-server.ts +168 -17
  29. package/cli/selftune/dashboard.ts +350 -17
  30. package/cli/selftune/eval/baseline.ts +21 -5
  31. package/cli/selftune/eval/execution-eval.ts +170 -0
  32. package/cli/selftune/eval/family-overlap.ts +2 -2
  33. package/cli/selftune/eval/hooks-to-evals.ts +228 -82
  34. package/cli/selftune/eval/import-skillsbench.ts +2 -2
  35. package/cli/selftune/eval/invocation-classifier.ts +56 -0
  36. package/cli/selftune/eval/synthetic-evals.ts +5 -3
  37. package/cli/selftune/eval/unit-test-cli.ts +7 -4
  38. package/cli/selftune/evolution/apply-proposal.ts +295 -0
  39. package/cli/selftune/evolution/engines/judge-engine.ts +96 -0
  40. package/cli/selftune/evolution/engines/replay-engine.ts +180 -0
  41. package/cli/selftune/evolution/evidence.ts +2 -6
  42. package/cli/selftune/evolution/evolve-body.ts +152 -38
  43. package/cli/selftune/evolution/evolve.ts +244 -52
  44. package/cli/selftune/evolution/rollback.ts +0 -1
  45. package/cli/selftune/evolution/validate-body.ts +111 -49
  46. package/cli/selftune/evolution/validate-host-replay.ts +510 -60
  47. package/cli/selftune/evolution/validate-proposal.ts +11 -150
  48. package/cli/selftune/evolution/validate-routing.ts +51 -108
  49. package/cli/selftune/evolution/validation-contract.ts +91 -0
  50. package/cli/selftune/grading/auto-grade.ts +11 -7
  51. package/cli/selftune/grading/grade-session.ts +10 -16
  52. package/cli/selftune/hooks/skill-eval.ts +2 -1
  53. package/cli/selftune/hooks-shared/types.ts +1 -0
  54. package/cli/selftune/index.ts +58 -15
  55. package/cli/selftune/ingestors/claude-replay.ts +15 -10
  56. package/cli/selftune/ingestors/codex-wrapper.ts +3 -3
  57. package/cli/selftune/ingestors/opencode-ingest.ts +2 -2
  58. package/cli/selftune/ingestors/pi-ingest.ts +727 -0
  59. package/cli/selftune/init.ts +38 -4
  60. package/cli/selftune/localdb/direct-write.ts +120 -1
  61. package/cli/selftune/localdb/materialize.ts +6 -7
  62. package/cli/selftune/localdb/queries/cron.ts +34 -0
  63. package/cli/selftune/localdb/queries/dashboard.ts +834 -0
  64. package/cli/selftune/localdb/queries/evolution.ts +158 -0
  65. package/cli/selftune/localdb/queries/execution.ts +133 -0
  66. package/cli/selftune/localdb/queries/json.ts +18 -0
  67. package/cli/selftune/localdb/queries/monitoring.ts +263 -0
  68. package/cli/selftune/localdb/queries/raw.ts +95 -0
  69. package/cli/selftune/localdb/queries/staging.ts +270 -0
  70. package/cli/selftune/localdb/queries/trust.ts +392 -0
  71. package/cli/selftune/localdb/queries.ts +60 -2162
  72. package/cli/selftune/localdb/schema.ts +59 -0
  73. package/cli/selftune/monitoring/watch.ts +96 -29
  74. package/cli/selftune/normalization.ts +3 -0
  75. package/cli/selftune/observability.ts +12 -3
  76. package/cli/selftune/orchestrate/cli.ts +161 -0
  77. package/cli/selftune/orchestrate/execute.ts +295 -0
  78. package/cli/selftune/orchestrate/finalize.ts +157 -0
  79. package/cli/selftune/orchestrate/locks.ts +40 -0
  80. package/cli/selftune/orchestrate/plan.ts +131 -0
  81. package/cli/selftune/orchestrate/post-run.ts +59 -0
  82. package/cli/selftune/orchestrate/prepare.ts +334 -0
  83. package/cli/selftune/orchestrate/report.ts +182 -0
  84. package/cli/selftune/orchestrate/runtime.ts +120 -0
  85. package/cli/selftune/orchestrate/signals.ts +48 -0
  86. package/cli/selftune/orchestrate.ts +162 -1142
  87. package/cli/selftune/registry/client.ts +74 -0
  88. package/cli/selftune/registry/history.ts +54 -0
  89. package/cli/selftune/registry/index.ts +90 -0
  90. package/cli/selftune/registry/install.ts +141 -0
  91. package/cli/selftune/registry/list.ts +44 -0
  92. package/cli/selftune/registry/push.ts +171 -0
  93. package/cli/selftune/registry/rollback.ts +49 -0
  94. package/cli/selftune/registry/status.ts +62 -0
  95. package/cli/selftune/registry/sync.ts +125 -0
  96. package/cli/selftune/repair/skill-usage.ts +9 -3
  97. package/cli/selftune/routes/overview.ts +5 -2
  98. package/cli/selftune/routes/skill-report.ts +15 -2
  99. package/cli/selftune/schedule.ts +5 -5
  100. package/cli/selftune/status.ts +70 -2
  101. package/cli/selftune/sync.ts +127 -23
  102. package/cli/selftune/testing-readiness.ts +597 -0
  103. package/cli/selftune/types.ts +46 -5
  104. package/cli/selftune/uninstall.ts +2 -1
  105. package/cli/selftune/utils/canonical-log.ts +1 -9
  106. package/cli/selftune/utils/cli-error.ts +9 -0
  107. package/cli/selftune/utils/jsonl.ts +1 -30
  108. package/cli/selftune/utils/llm-call.ts +126 -6
  109. package/cli/selftune/utils/skill-discovery.ts +24 -0
  110. package/cli/selftune/workflows/proposals.ts +184 -0
  111. package/cli/selftune/workflows/skill-scaffold.ts +241 -0
  112. package/cli/selftune/workflows/workflows.ts +100 -26
  113. package/node_modules/@selftune/telemetry-contract/fixtures/complete-push.ts +1 -1
  114. package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
  115. package/node_modules/@selftune/telemetry-contract/fixtures/golden.test.ts +0 -1
  116. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  117. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
  118. package/node_modules/@selftune/telemetry-contract/package.json +1 -1
  119. package/node_modules/@selftune/telemetry-contract/src/index.ts +1 -0
  120. package/node_modules/@selftune/telemetry-contract/src/schemas.ts +63 -5
  121. package/node_modules/@selftune/telemetry-contract/src/types.ts +97 -7
  122. package/node_modules/@selftune/telemetry-contract/tests/compatibility.test.ts +0 -1
  123. package/package.json +25 -9
  124. package/packages/dashboard-core/AGENTS.md +18 -0
  125. package/packages/dashboard-core/README.md +30 -0
  126. package/packages/dashboard-core/index.ts +3 -0
  127. package/packages/dashboard-core/package.json +39 -0
  128. package/packages/dashboard-core/src/chrome/DashboardChrome.tsx +74 -0
  129. package/packages/dashboard-core/src/chrome/DashboardHeader.tsx +200 -0
  130. package/packages/dashboard-core/src/chrome/DashboardSidebar.tsx +219 -0
  131. package/packages/dashboard-core/src/chrome/RuntimeBadge.tsx +46 -0
  132. package/packages/dashboard-core/src/chrome/index.ts +14 -0
  133. package/packages/dashboard-core/src/chrome/types.ts +81 -0
  134. package/packages/dashboard-core/src/chrome/utils.ts +23 -0
  135. package/packages/dashboard-core/src/gates/FeatureGate.tsx +11 -0
  136. package/packages/dashboard-core/src/gates/LockedRoute.tsx +29 -0
  137. package/packages/dashboard-core/src/gates/UpgradeCard.tsx +89 -0
  138. package/packages/dashboard-core/src/gates/index.ts +3 -0
  139. package/packages/dashboard-core/src/host/DashboardHostProvider.tsx +62 -0
  140. package/packages/dashboard-core/src/host/adapter.ts +47 -0
  141. package/packages/dashboard-core/src/host/capabilities.ts +55 -0
  142. package/packages/dashboard-core/src/host/index.ts +3 -0
  143. package/packages/dashboard-core/src/models/analytics.ts +39 -0
  144. package/packages/dashboard-core/src/models/index.ts +4 -0
  145. package/packages/dashboard-core/src/models/overview.ts +98 -0
  146. package/packages/dashboard-core/src/models/runtime.ts +7 -0
  147. package/packages/dashboard-core/src/models/skills.ts +34 -0
  148. package/packages/dashboard-core/src/routes/index.ts +2 -0
  149. package/packages/dashboard-core/src/routes/manifest.test.ts +70 -0
  150. package/packages/dashboard-core/src/routes/manifest.ts +451 -0
  151. package/packages/dashboard-core/src/routes/types.ts +39 -0
  152. package/packages/dashboard-core/src/screens/analytics/AnalyticsScreen.tsx +278 -0
  153. package/packages/dashboard-core/src/screens/analytics/index.ts +1 -0
  154. package/packages/dashboard-core/src/screens/index.ts +37 -0
  155. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.test.ts +101 -0
  156. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.tsx +393 -0
  157. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.test.tsx +113 -0
  158. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.tsx +72 -0
  159. package/packages/dashboard-core/src/screens/overview/OverviewCoreSurface.tsx +71 -0
  160. package/packages/dashboard-core/src/screens/overview/OverviewOnboardingBanner.tsx +90 -0
  161. package/packages/dashboard-core/src/screens/overview/OverviewRunSummary.tsx +40 -0
  162. package/packages/dashboard-core/src/screens/overview/index.ts +16 -0
  163. package/packages/dashboard-core/src/screens/overview/types.ts +13 -0
  164. package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +99 -0
  165. package/packages/dashboard-core/src/screens/skill-report/SkillReportDataQualityTabContent.tsx +35 -0
  166. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceRail.tsx +71 -0
  167. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceSection.tsx +63 -0
  168. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceTabContent.tsx +25 -0
  169. package/packages/dashboard-core/src/screens/skill-report/SkillReportInvocationsSection.tsx +24 -0
  170. package/packages/dashboard-core/src/screens/skill-report/SkillReportMissedQueriesSection.tsx +79 -0
  171. package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +150 -0
  172. package/packages/dashboard-core/src/screens/skill-report/SkillReportSections.test.tsx +224 -0
  173. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.test.tsx +76 -0
  174. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.tsx +88 -0
  175. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrendSection.tsx +33 -0
  176. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +67 -0
  177. package/packages/dashboard-core/src/screens/skill-report/index.ts +45 -0
  178. package/packages/dashboard-core/src/screens/skills/SkillsLibraryScreen.tsx +162 -0
  179. package/packages/dashboard-core/src/screens/skills/index.ts +6 -0
  180. package/packages/telemetry-contract/fixtures/complete-push.ts +1 -1
  181. package/packages/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
  182. package/packages/telemetry-contract/fixtures/golden.test.ts +0 -1
  183. package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  184. package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
  185. package/packages/telemetry-contract/package.json +1 -1
  186. package/packages/telemetry-contract/src/index.ts +1 -0
  187. package/packages/telemetry-contract/src/schemas.ts +63 -5
  188. package/packages/telemetry-contract/src/types.ts +97 -7
  189. package/packages/telemetry-contract/tests/compatibility.test.ts +0 -1
  190. package/packages/ui/AGENTS.md +16 -0
  191. package/packages/ui/README.md +1 -1
  192. package/packages/ui/package.json +1 -1
  193. package/packages/ui/src/components/ActivityTimeline.tsx +152 -168
  194. package/packages/ui/src/components/AnalyticsCharts.tsx +344 -0
  195. package/packages/ui/src/components/EvidenceViewer.tsx +229 -464
  196. package/packages/ui/src/components/EvolutionTimeline.tsx +34 -87
  197. package/packages/ui/src/components/InfoTip.tsx +1 -2
  198. package/packages/ui/src/components/InvocationsPanel.tsx +413 -0
  199. package/packages/ui/src/components/JobHistoryTimeline.tsx +156 -0
  200. package/packages/ui/src/components/OrchestrateRunsPanel.tsx +18 -36
  201. package/packages/ui/src/components/OverviewPanels.tsx +693 -0
  202. package/packages/ui/src/components/PipelineStatusBar.tsx +65 -0
  203. package/packages/ui/src/components/SkillReportGuide.tsx +215 -0
  204. package/packages/ui/src/components/SkillReportPanels.tsx +919 -0
  205. package/packages/ui/src/components/SkillsLibrary.tsx +437 -0
  206. package/packages/ui/src/components/index.ts +56 -1
  207. package/packages/ui/src/components/section-cards.tsx +18 -35
  208. package/packages/ui/src/components/skill-health-grid.tsx +47 -37
  209. package/packages/ui/src/lib/constants.tsx +0 -1
  210. package/packages/ui/src/primitives/card.tsx +1 -1
  211. package/packages/ui/src/primitives/checkbox.tsx +1 -1
  212. package/packages/ui/src/primitives/dropdown-menu.tsx +2 -2
  213. package/packages/ui/src/primitives/select.tsx +2 -2
  214. package/packages/ui/src/primitives/tabs.tsx +7 -6
  215. package/packages/ui/src/types.ts +182 -4
  216. package/skill/SKILL.md +130 -318
  217. package/skill/agents/diagnosis-analyst.md +3 -3
  218. package/skill/agents/evolution-reviewer.md +3 -3
  219. package/skill/agents/integration-guide.md +3 -3
  220. package/skill/agents/pattern-analyst.md +2 -2
  221. package/skill/references/cli-quick-reference.md +89 -0
  222. package/skill/references/creator-playbook.md +131 -0
  223. package/skill/references/examples.md +48 -0
  224. package/skill/references/troubleshooting.md +47 -0
  225. package/skill/references/version-history.md +1 -1
  226. package/skill/selftune.contribute.json +11 -0
  227. package/skill/{Workflows → workflows}/Baseline.md +20 -1
  228. package/skill/{Workflows → workflows}/Contribute.md +23 -10
  229. package/skill/{Workflows → workflows}/Contributions.md +13 -5
  230. package/skill/workflows/CreateTestDeploy.md +170 -0
  231. package/skill/{Workflows → workflows}/CreatorContributions.md +18 -6
  232. package/skill/{Workflows → workflows}/Cron.md +1 -1
  233. package/skill/{Workflows → workflows}/Dashboard.md +20 -0
  234. package/skill/{Workflows → workflows}/Doctor.md +1 -1
  235. package/skill/{Workflows → workflows}/Evals.md +67 -2
  236. package/skill/{Workflows → workflows}/Evolve.md +119 -30
  237. package/skill/{Workflows → workflows}/EvolveBody.md +41 -1
  238. package/skill/{Workflows → workflows}/Grade.md +1 -1
  239. package/skill/{Workflows → workflows}/Ingest.md +60 -2
  240. package/skill/{Workflows → workflows}/Initialize.md +16 -9
  241. package/skill/{Workflows → workflows}/Orchestrate.md +13 -3
  242. package/skill/{Workflows → workflows}/PlatformHooks.md +19 -3
  243. package/skill/workflows/Registry.md +99 -0
  244. package/skill/{Workflows → workflows}/Schedule.md +3 -3
  245. package/skill/workflows/SignalsDashboard.md +87 -0
  246. package/skill/{Workflows → workflows}/Sync.md +3 -1
  247. package/skill/{Workflows → workflows}/UnitTest.md +19 -0
  248. package/skill/{Workflows → workflows}/Watch.md +42 -2
  249. package/skill/{Workflows → workflows}/Workflows.md +39 -2
  250. package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +0 -60
  251. package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +0 -1
  252. package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +0 -11
  253. package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +0 -12
  254. package/cli/selftune/utils/html.ts +0 -27
  255. package/packages/ui/src/components/RecentActivityFeed.tsx +0 -117
  256. /package/skill/{Workflows → workflows}/AlphaUpload.md +0 -0
  257. /package/skill/{Workflows → workflows}/AutoActivation.md +0 -0
  258. /package/skill/{Workflows → workflows}/Badge.md +0 -0
  259. /package/skill/{Workflows → workflows}/Composability.md +0 -0
  260. /package/skill/{Workflows → workflows}/EvolutionMemory.md +0 -0
  261. /package/skill/{Workflows → workflows}/ExportCanonical.md +0 -0
  262. /package/skill/{Workflows → workflows}/Hook.md +0 -0
  263. /package/skill/{Workflows → workflows}/ImportSkillsBench.md +0 -0
  264. /package/skill/{Workflows → workflows}/Quickstart.md +0 -0
  265. /package/skill/{Workflows → workflows}/Recover.md +0 -0
  266. /package/skill/{Workflows → workflows}/RepairSkillUsage.md +0 -0
  267. /package/skill/{Workflows → workflows}/Replay.md +0 -0
  268. /package/skill/{Workflows → workflows}/Rollback.md +0 -0
  269. /package/skill/{Workflows → workflows}/Telemetry.md +0 -0
  270. /package/skill/{Workflows → workflows}/Uninstall.md +0 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * selftune registry sync — Check for updates and pull latest versions.
3
+ */
4
+
5
+ import { writeFile, readFile, mkdir, unlink } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+
8
+ import { registryRequest } from "./client.js";
9
+
10
+ interface LocalState {
11
+ entryId: string;
12
+ name: string;
13
+ versionHash: string;
14
+ installPath: string;
15
+ }
16
+
17
+ function getStatePath(): string {
18
+ return join(process.env.HOME || "~", ".selftune", "registry-state.json");
19
+ }
20
+
21
+ async function loadState(): Promise<LocalState[]> {
22
+ try {
23
+ const raw = await readFile(getStatePath(), "utf-8");
24
+ return JSON.parse(raw);
25
+ } catch {
26
+ return [];
27
+ }
28
+ }
29
+
30
+ async function saveState(state: LocalState[]): Promise<void> {
31
+ await mkdir(join(process.env.HOME || "~", ".selftune"), { recursive: true });
32
+ await writeFile(getStatePath(), JSON.stringify(state, null, 2));
33
+ }
34
+
35
+ export async function cliMain() {
36
+ const state = await loadState();
37
+ if (state.length === 0) {
38
+ console.log(
39
+ JSON.stringify({
40
+ message: "No registry installations found. Use 'selftune registry install <name>' first.",
41
+ }),
42
+ );
43
+ return;
44
+ }
45
+
46
+ // Check for updates
47
+ const syncResult = await registryRequest<{
48
+ entries: Array<{
49
+ entry_id: string;
50
+ name: string;
51
+ has_update: boolean;
52
+ latest_version: string;
53
+ latest_content_hash: string;
54
+ download_url?: string;
55
+ }>;
56
+ }>("POST", "/sync", {
57
+ body: {
58
+ installations: state.map((s) => ({
59
+ entry_id: s.entryId,
60
+ current_version_hash: s.versionHash,
61
+ })),
62
+ },
63
+ });
64
+
65
+ if (!syncResult.success) {
66
+ console.error(JSON.stringify({ error: syncResult.error }));
67
+ process.exit(1);
68
+ }
69
+
70
+ const updates = syncResult.data?.entries?.filter((e) => e.has_update) || [];
71
+ if (updates.length === 0) {
72
+ console.log(JSON.stringify({ message: "All installations up to date", count: state.length }));
73
+ return;
74
+ }
75
+
76
+ console.log(`Found ${updates.length} update(s)...`);
77
+ let synced = 0;
78
+ let failed = 0;
79
+
80
+ for (const update of updates) {
81
+ if (!update.download_url) {
82
+ failed++;
83
+ continue;
84
+ }
85
+
86
+ const localEntry = state.find((s) => s.entryId === update.entry_id);
87
+ if (!localEntry) {
88
+ failed++;
89
+ continue;
90
+ }
91
+
92
+ try {
93
+ const response = await fetch(update.download_url, { signal: AbortSignal.timeout(60_000) });
94
+ if (!response.ok) {
95
+ failed++;
96
+ continue;
97
+ }
98
+
99
+ const archiveBuffer = Buffer.from(await response.arrayBuffer());
100
+ const archivePath = `/tmp/selftune-sync-${Date.now()}.tar.gz`;
101
+ await writeFile(archivePath, archiveBuffer);
102
+
103
+ // Extract to existing install path
104
+ const proc = Bun.spawn(["tar", "xzf", archivePath, "-C", localEntry.installPath], {
105
+ stdout: "ignore",
106
+ stderr: "pipe",
107
+ });
108
+ await proc.exited;
109
+ await unlink(archivePath).catch(() => {});
110
+
111
+ if (proc.exitCode === 0) {
112
+ localEntry.versionHash = update.latest_content_hash;
113
+ synced++;
114
+ console.log(` updated: ${update.name} -> v${update.latest_version}`);
115
+ } else {
116
+ failed++;
117
+ }
118
+ } catch {
119
+ failed++;
120
+ }
121
+ }
122
+
123
+ await saveState(state);
124
+ console.log(JSON.stringify({ synced, failed, total: state.length }));
125
+ }
@@ -31,6 +31,7 @@ import {
31
31
  findInstalledSkillPath,
32
32
  findRepositoryClaudeSkillDirs,
33
33
  findRepositorySkillDirs,
34
+ isTestFixturePath,
34
35
  } from "../utils/skill-discovery.js";
35
36
  import { writeRepairedSkillUsageRecords } from "../utils/skill-log.js";
36
37
 
@@ -299,8 +300,11 @@ function extractSessionSkillUsage(
299
300
 
300
301
  const msg = (entry.message as Record<string, unknown>) ?? entry;
301
302
  const role = (msg.role as string) ?? (entry.role as string) ?? "";
302
- const timestamp =
303
- (entry.timestamp as string) ?? (msg.timestamp as string) ?? lastUserMessage?.timestamp ?? "";
303
+ const timestamp: string =
304
+ optionalString(entry.timestamp) ??
305
+ optionalString(msg.timestamp) ??
306
+ lastUserMessage?.timestamp ??
307
+ "";
304
308
  sessionCwd =
305
309
  optionalString(entry.cwd) ??
306
310
  optionalString(msg.cwd) ??
@@ -380,7 +384,7 @@ function extractSessionSkillUsage(
380
384
 
381
385
  if (toolName === "Read") {
382
386
  const filePath = (input.file_path as string) ?? "";
383
- if (filePath.endsWith("SKILL.md")) {
387
+ if (filePath.endsWith("SKILL.md") && !isTestFixturePath(filePath)) {
384
388
  const inferredSkillName = basename(dirname(filePath)).trim();
385
389
  if (inferredSkillName && !skillPathLookup.has(inferredSkillName)) {
386
390
  skillPathLookup.set(inferredSkillName.toLowerCase(), filePath);
@@ -421,6 +425,8 @@ function extractSessionSkillUsage(
421
425
  ? { skillPath: knownSkillPath, resolutionSource: "raw_log" as const }
422
426
  : resolveClaudeSkillPath(skillName, sessionCwd, homeDir, codexHome);
423
427
 
428
+ if (isTestFixturePath(skillPath)) continue;
429
+
424
430
  const recordIndex =
425
431
  repaired.push({
426
432
  timestamp: timestamp || lastUserMessage.timestamp || fallbackTimestamp,
@@ -24,6 +24,7 @@ import {
24
24
  getSkillTrustSummaries,
25
25
  getSkillsList,
26
26
  } from "../localdb/queries.js";
27
+ import { buildCreatorTestingOverview, listSkillTestingReadiness } from "../testing-readiness.js";
27
28
  import { buildTrustWatchlist } from "../trust-model.js";
28
29
  import { loadWatchedSkills } from "../watchlist.js";
29
30
 
@@ -32,15 +33,16 @@ export function handleOverview(
32
33
  version: string,
33
34
  searchParams?: URLSearchParams,
34
35
  ): Response {
35
- const skills = getSkillsList(db);
36
-
37
36
  // -- Autonomy-first enrichment fields ----------------------------------------
38
37
  const attentionQueue = getAttentionQueue(db);
39
38
  const recentDecisions = getRecentDecisions(db);
40
39
  const trustSummaries = getSkillTrustSummaries(db);
40
+ const testingReadiness = listSkillTestingReadiness(db);
41
+ const skills = getSkillsList(db, testingReadiness);
41
42
  const pendingReviews = attentionQueue.filter((a) => a.category === "needs_review").length;
42
43
 
43
44
  const trustWatchlist = buildTrustWatchlist(trustSummaries);
45
+ const creatorTesting = buildCreatorTestingOverview(testingReadiness);
44
46
  const autonomyStatus = buildAutonomyStatus(
45
47
  db,
46
48
  attentionQueue,
@@ -55,6 +57,7 @@ export function handleOverview(
55
57
  attention_queue: attentionQueue,
56
58
  trust_watchlist: trustWatchlist,
57
59
  recent_decisions: recentDecisions,
60
+ creator_testing: creatorTesting,
58
61
  };
59
62
 
60
63
  // -- Standard overview payload -----------------------------------------------
@@ -17,6 +17,7 @@ import {
17
17
  getSkillReportPayload,
18
18
  safeParseJson,
19
19
  } from "../localdb/queries.js";
20
+ import { getSkillTestingReadiness } from "../testing-readiness.js";
20
21
 
21
22
  export function handleSkillReport(
22
23
  db: Database,
@@ -24,6 +25,7 @@ export function handleSkillReport(
24
25
  searchParams?: URLSearchParams,
25
26
  ): Response {
26
27
  const report = getSkillReportPayload(db, skillName);
28
+ const testing_readiness = getSkillTestingReadiness(db, skillName);
27
29
 
28
30
  // 1. Evolution audit with eval_snapshot
29
31
  const evolution = db
@@ -178,7 +180,14 @@ export function handleSkillReport(
178
180
  report.evidence.length > 0 ||
179
181
  evolution.length > 0 ||
180
182
  pending_proposals.length > 0 ||
181
- invPageRows.length > 0;
183
+ invPageRows.length > 0 ||
184
+ Boolean(
185
+ testing_readiness?.skill_path ||
186
+ testing_readiness?.eval_set_entries ||
187
+ testing_readiness?.unit_test_cases ||
188
+ testing_readiness?.replay_check_count ||
189
+ testing_readiness?.baseline_sample_size,
190
+ );
182
191
  if (!hasData) {
183
192
  return Response.json({ error: "Skill not found" }, { status: 404 });
184
193
  }
@@ -784,7 +793,10 @@ export function handleSkillReport(
784
793
 
785
794
  if (coverage.checks < 5) {
786
795
  trustState = "low_sample";
787
- trustSummary = `Too few operational observations to assess trust — only ${coverage.checks} checks recorded.`;
796
+ trustSummary =
797
+ coverage.checks === 0 && testing_readiness
798
+ ? `No runtime observations yet. Use the creator test loop to bootstrap this skill before trusting live routing.`
799
+ : `Too few operational observations to assess trust — only ${coverage.checks} checks recorded.`;
788
800
  } else if (latestAuditRow?.action === "rolled_back") {
789
801
  trustState = "rolled_back";
790
802
  trustSummary = "Recent evolution was rolled back — review evidence before re-deploying.";
@@ -879,5 +891,6 @@ export function handleSkillReport(
879
891
  evolution_state,
880
892
  data_hygiene,
881
893
  examples,
894
+ testing_readiness,
882
895
  });
883
896
  }
@@ -376,7 +376,7 @@ export function buildInstallPlan(
376
376
  }
377
377
 
378
378
  const systemdDir = join(homeDir, ".config", "systemd", "user");
379
- const definitions = SCHEDULE_ENTRIES.map(buildSystemdDefinition);
379
+ const definitions = SCHEDULE_ENTRIES.map((entry) => buildSystemdDefinition(entry));
380
380
  return {
381
381
  artifacts: definitions.flatMap((definition) => [
382
382
  { path: join(systemdDir, `${definition.baseName}.timer`), content: definition.timerContent },
@@ -531,7 +531,7 @@ export function cliMain(): void {
531
531
 
532
532
  if (values["apply-cron-artifact"]) {
533
533
  try {
534
- applyCronArtifact(values["apply-cron-artifact"]);
534
+ applyCronArtifact(values["apply-cron-artifact"] as string);
535
535
  return;
536
536
  } catch (err) {
537
537
  throw new CLIError(
@@ -567,8 +567,8 @@ For OpenClaw-specific scheduling, see: selftune cron`);
567
567
  if (values.install) {
568
568
  try {
569
569
  const result = installSchedule({
570
- format: values.format,
571
- dryRun: values["dry-run"] ?? false,
570
+ format: typeof values.format === "string" ? values.format : undefined,
571
+ dryRun: values["dry-run"] === true,
572
572
  });
573
573
  if (!result.dryRun && !result.activated) {
574
574
  throw new CLIError(
@@ -601,7 +601,7 @@ For OpenClaw-specific scheduling, see: selftune cron`);
601
601
  }
602
602
  }
603
603
 
604
- const result = formatOutput(values.format);
604
+ const result = formatOutput(typeof values.format === "string" ? values.format : undefined);
605
605
  if (!result.ok) {
606
606
  throw new CLIError(
607
607
  result.error ?? "Invalid schedule format",
@@ -16,7 +16,9 @@ import { getAlphaLinkState, readAlphaIdentity } from "./alpha-identity.js";
16
16
  import { getQueueStats } from "./alpha-upload/queue.js";
17
17
  import { getBaseUrl } from "./auth/device-code.js";
18
18
  import { SELFTUNE_CONFIG_PATH } from "./constants.js";
19
+ import type { SkillTestingReadiness } from "./dashboard-contract.js";
19
20
  import { getDb } from "./localdb/db.js";
21
+ import { writeCronRunToDb } from "./localdb/direct-write.js";
20
22
  import {
21
23
  getLastUploadError,
22
24
  getLastUploadSuccess,
@@ -30,6 +32,7 @@ import {
30
32
  import { computeMonitoringSnapshot, MIN_MONITORING_SKILL_CHECKS } from "./monitoring/watch.js";
31
33
  import { doctor } from "./observability.js";
32
34
  import { deriveTrustBucket, deriveTrustBucketReason } from "./trust-model.js";
35
+ import { buildCreatorTestingOverview, listSkillTestingReadiness } from "./testing-readiness.js";
33
36
  import type {
34
37
  AgentCommandGuidance,
35
38
  AlphaLinkState,
@@ -313,7 +316,35 @@ function formatTrustHighlights(trustSummaries: SkillTrustSummary[] | undefined):
313
316
  return lines;
314
317
  }
315
318
 
316
- export function formatStatus(result: StatusResult, trustSummaries?: SkillTrustSummary[]): string {
319
+ function formatCreatorLoopLines(readinessRows: SkillTestingReadiness[] | undefined): string[] {
320
+ if (!readinessRows || readinessRows.length === 0) return [];
321
+
322
+ const overview = buildCreatorTestingOverview(readinessRows);
323
+ const lines = ["Creator loop"];
324
+ lines.push(` ${overview.summary}`);
325
+
326
+ const counts = overview.counts;
327
+ lines.push(
328
+ ` Generate evals: ${counts.generate_evals} | Unit tests: ${counts.run_unit_tests} | Replay dry-run: ${counts.run_replay_dry_run} | Baseline: ${counts.measure_baseline} | Deploy: ${counts.deploy_candidate} | Watching: ${counts.watch_deployment}`,
329
+ );
330
+
331
+ if (overview.priorities.length > 0) {
332
+ lines.push(" Next:");
333
+ for (const priority of overview.priorities.slice(0, 3)) {
334
+ lines.push(
335
+ ` ${priority.skill_name}: ${priority.next_step.replaceAll("_", " ")} — ${priority.recommended_command}`,
336
+ );
337
+ }
338
+ }
339
+
340
+ return lines;
341
+ }
342
+
343
+ export function formatStatus(
344
+ result: StatusResult,
345
+ trustSummaries?: SkillTrustSummary[],
346
+ testingReadiness?: SkillTestingReadiness[],
347
+ ): string {
317
348
  const noColor = !!process.env.NO_COLOR;
318
349
 
319
350
  const green = noColor ? (s: string) => s : (s: string) => colorize(s, "#788c5d");
@@ -333,6 +364,12 @@ export function formatStatus(result: StatusResult, trustSummaries?: SkillTrustSu
333
364
  lines.push("");
334
365
  }
335
366
 
367
+ const creatorLoopLines = formatCreatorLoopLines(testingReadiness);
368
+ if (creatorLoopLines.length > 0) {
369
+ lines.push(...creatorLoopLines);
370
+ lines.push("");
371
+ }
372
+
336
373
  // Skills table
337
374
  const skillCount = result.skills.length;
338
375
  lines.push(
@@ -576,6 +613,8 @@ export function formatAlphaStatus(info: AlphaStatusInfo | null): string {
576
613
 
577
614
  export async function cliMain(): Promise<void> {
578
615
  const db = getDb();
616
+ const statusStartedAt = new Date();
617
+ const statusStart = performance.now();
579
618
  try {
580
619
  const telemetry = querySessionTelemetry(db) as SessionTelemetryRecord[];
581
620
  const skillRecords = querySkillUsageRecords(db) as SkillUsageRecord[];
@@ -585,7 +624,8 @@ export async function cliMain(): Promise<void> {
585
624
 
586
625
  const result = computeStatus(telemetry, skillRecords, queryRecords, auditEntries, doctorResult);
587
626
  const trustSummaries = getSkillTrustSummaries(db);
588
- const output = formatStatus(result, trustSummaries);
627
+ const testingReadiness = listSkillTestingReadiness(db);
628
+ const output = formatStatus(result, trustSummaries, testingReadiness);
589
629
  console.log(output);
590
630
 
591
631
  // Alpha upload status section
@@ -610,9 +650,37 @@ export async function cliMain(): Promise<void> {
610
650
  }
611
651
  console.log(formatAlphaStatus(alphaInfo));
612
652
 
653
+ // Log cron run for unified timeline visibility
654
+ const statusElapsed = Math.round(performance.now() - statusStart);
655
+ writeCronRunToDb(db, {
656
+ jobName: "status",
657
+ startedAt: statusStartedAt.toISOString(),
658
+ elapsedMs: statusElapsed,
659
+ status: "success",
660
+ metrics: {
661
+ total_skills: result.skills.length,
662
+ healthy: result.skills.filter((s) => s.status === "HEALTHY").length,
663
+ warning: result.skills.filter((s) => s.status === "WARNING").length,
664
+ critical: result.skills.filter((s) => s.status === "CRITICAL").length,
665
+ system_healthy: result.system.healthy,
666
+ unmatched_queries: result.unmatchedQueries,
667
+ pending_proposals: result.pendingProposals,
668
+ },
669
+ });
670
+
613
671
  process.exit(0);
614
672
  } catch (err) {
673
+ // Log failed status run
674
+ const statusElapsed = Math.round(performance.now() - statusStart);
615
675
  const message = err instanceof Error ? err.message : String(err);
676
+ writeCronRunToDb(db, {
677
+ jobName: "status",
678
+ startedAt: statusStartedAt.toISOString(),
679
+ elapsedMs: statusElapsed,
680
+ status: "error",
681
+ error: message,
682
+ });
683
+
616
684
  console.error(`selftune status failed: ${message}`);
617
685
  process.exit(1);
618
686
  }