selftune 0.2.18 → 0.2.20

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 (77) hide show
  1. package/README.md +9 -4
  2. package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +60 -0
  3. package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +1 -0
  4. package/apps/local-dashboard/dist/assets/vendor-table-BIiI3YhS.js +1 -0
  5. package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +12 -0
  6. package/apps/local-dashboard/dist/index.html +5 -5
  7. package/cli/selftune/alpha-upload/stage-canonical.ts +7 -6
  8. package/cli/selftune/constants.ts +10 -0
  9. package/cli/selftune/contribute/contribute.ts +30 -2
  10. package/cli/selftune/contribution-config.ts +249 -0
  11. package/cli/selftune/contribution-relay.ts +177 -0
  12. package/cli/selftune/contribution-signals.ts +219 -0
  13. package/cli/selftune/contribution-staging.ts +147 -0
  14. package/cli/selftune/contributions.ts +532 -0
  15. package/cli/selftune/creator-contributions.ts +333 -0
  16. package/cli/selftune/dashboard-contract.ts +209 -1
  17. package/cli/selftune/dashboard-server.ts +45 -11
  18. package/cli/selftune/eval/family-overlap.ts +714 -0
  19. package/cli/selftune/eval/hooks-to-evals.ts +182 -28
  20. package/cli/selftune/eval/synthetic-evals.ts +298 -11
  21. package/cli/selftune/evolution/evidence.ts +5 -0
  22. package/cli/selftune/evolution/evolve-body.ts +62 -2
  23. package/cli/selftune/evolution/evolve.ts +58 -1
  24. package/cli/selftune/evolution/validate-body.ts +10 -0
  25. package/cli/selftune/evolution/validate-host-replay.ts +236 -0
  26. package/cli/selftune/evolution/validate-proposal.ts +10 -0
  27. package/cli/selftune/evolution/validate-routing.ts +112 -5
  28. package/cli/selftune/export.ts +2 -2
  29. package/cli/selftune/index.ts +41 -5
  30. package/cli/selftune/ingestors/codex-rollout.ts +31 -35
  31. package/cli/selftune/ingestors/codex-wrapper.ts +32 -24
  32. package/cli/selftune/localdb/db.ts +2 -2
  33. package/cli/selftune/localdb/direct-write.ts +8 -3
  34. package/cli/selftune/localdb/materialize.ts +7 -2
  35. package/cli/selftune/localdb/queries.ts +712 -31
  36. package/cli/selftune/localdb/schema.ts +30 -1
  37. package/cli/selftune/recover.ts +153 -0
  38. package/cli/selftune/repair/skill-usage.ts +363 -4
  39. package/cli/selftune/routes/actions.ts +35 -1
  40. package/cli/selftune/routes/analytics.ts +14 -0
  41. package/cli/selftune/routes/index.ts +1 -0
  42. package/cli/selftune/routes/overview.ts +112 -4
  43. package/cli/selftune/routes/skill-report.ts +575 -11
  44. package/cli/selftune/status.ts +81 -2
  45. package/cli/selftune/sync.ts +56 -2
  46. package/cli/selftune/trust-model.ts +66 -0
  47. package/cli/selftune/types.ts +103 -0
  48. package/cli/selftune/utils/skill-detection.ts +43 -0
  49. package/cli/selftune/utils/text-similarity.ts +73 -0
  50. package/cli/selftune/watchlist.ts +65 -0
  51. package/package.json +1 -1
  52. package/packages/ui/src/components/ActivityTimeline.tsx +165 -150
  53. package/packages/ui/src/components/EvidenceViewer.tsx +419 -145
  54. package/packages/ui/src/components/EvolutionTimeline.tsx +81 -29
  55. package/packages/ui/src/components/OrchestrateRunsPanel.tsx +33 -16
  56. package/packages/ui/src/components/RecentActivityFeed.tsx +72 -41
  57. package/packages/ui/src/components/section-cards.tsx +12 -9
  58. package/packages/ui/src/primitives/card.tsx +1 -1
  59. package/packages/ui/src/types.ts +4 -0
  60. package/skill/SKILL.md +11 -1
  61. package/skill/Workflows/AlphaUpload.md +4 -0
  62. package/skill/Workflows/Composability.md +78 -0
  63. package/skill/Workflows/Contribute.md +6 -3
  64. package/skill/Workflows/Contributions.md +97 -0
  65. package/skill/Workflows/CreatorContributions.md +74 -0
  66. package/skill/Workflows/Dashboard.md +31 -0
  67. package/skill/Workflows/Evals.md +57 -8
  68. package/skill/Workflows/Evolve.md +23 -0
  69. package/skill/Workflows/Ingest.md +7 -0
  70. package/skill/Workflows/Initialize.md +20 -1
  71. package/skill/Workflows/Recover.md +84 -0
  72. package/skill/Workflows/RepairSkillUsage.md +12 -4
  73. package/skill/Workflows/Sync.md +18 -12
  74. package/apps/local-dashboard/dist/assets/index-BMIS6uUh.css +0 -2
  75. package/apps/local-dashboard/dist/assets/index-DOu3iLD9.js +0 -16
  76. package/apps/local-dashboard/dist/assets/vendor-table-pHbDxq36.js +0 -8
  77. package/apps/local-dashboard/dist/assets/vendor-ui-DIwlrGlb.js +0 -12
@@ -8,10 +8,12 @@
8
8
  * GET /api/health — Dashboard server health probe
9
9
  * GET /api/v2/doctor — System health diagnostics (config, logs, hooks, evolution)
10
10
  * GET /api/v2/overview — SQLite-backed overview payload
11
+ * GET /api/v2/analytics — Performance analytics (trends, rankings, heatmap)
11
12
  * GET /api/v2/skills/:name — SQLite-backed per-skill report
12
13
  * POST /api/actions/watch — Trigger `selftune watch` for a skill
13
14
  * POST /api/actions/evolve — Trigger `selftune evolve` for a skill
14
15
  * POST /api/actions/rollback — Trigger `selftune rollback` for a skill
16
+ * POST /api/actions/watchlist — Persist creator watchlist preferences
15
17
  * GET /badge/:name — Skill health badge
16
18
  * GET /report/:name — Skill health report HTML
17
19
  */
@@ -29,7 +31,6 @@ import type {
29
31
  } from "./dashboard-contract.js";
30
32
  import { readEvidenceTrail } from "./evolution/evidence.js";
31
33
  import { closeSingleton, DB_PATH, getDb } from "./localdb/db.js";
32
- import { materializeIncremental } from "./localdb/materialize.js";
33
34
  import {
34
35
  queryEvolutionAudit,
35
36
  queryQueryLog,
@@ -40,6 +41,7 @@ import { doctor } from "./observability.js";
40
41
  import type { ActionRunner } from "./routes/index.js";
41
42
  import {
42
43
  handleAction,
44
+ handleAnalytics,
43
45
  handleBadge,
44
46
  handleDoctor,
45
47
  handleOrchestrateRuns,
@@ -109,6 +111,16 @@ function decodePathSegment(segment: string): string | null {
109
111
  }
110
112
  }
111
113
 
114
+ function allowedDashboardOrigins(hostname: string, port: number): Set<string> {
115
+ const origins = new Set<string>([`http://${hostname}:${port}`]);
116
+ if (hostname === "localhost") {
117
+ origins.add(`http://127.0.0.1:${port}`);
118
+ } else if (hostname === "127.0.0.1") {
119
+ origins.add(`http://localhost:${port}`);
120
+ }
121
+ return origins;
122
+ }
123
+
112
124
  const MIME_TYPES: Record<string, string> = {
113
125
  ".html": "text/html; charset=utf-8",
114
126
  ".js": "application/javascript; charset=utf-8",
@@ -187,24 +199,21 @@ export async function startDashboardServer(
187
199
  if (needsDb) {
188
200
  try {
189
201
  db = getDb();
190
- // Materializer runs once at startup to backfill any JSONL data not yet in SQLite.
191
- // After startup, hooks write directly to SQLite so re-materialization is unnecessary.
192
- materializeIncremental(db);
193
202
  } catch (error: unknown) {
194
203
  const message = error instanceof Error ? error.message : String(error);
195
204
  console.error(`V2 dashboard data unavailable: ${message}`);
196
205
  }
197
206
  }
198
207
 
199
- // Hooks write directly to SQLite, so periodic re-materialization is not needed.
200
- // These functions are retained as no-ops because they are called from multiple
201
- // places in the request handler and the file-change watcher.
208
+ // Hooks and ingestors write directly to SQLite, so periodic materialization is
209
+ // not part of normal runtime. These remain no-ops because they are invoked
210
+ // from several shared request and watcher paths.
202
211
  function refreshV2Data(): void {
203
- // No-op: materializer runs once at startup only
212
+ // No-op: SQLite is already authoritative at runtime
204
213
  }
205
214
 
206
215
  function refreshV2DataImmediate(): void {
207
- // No-op: materializer runs once at startup only
216
+ // No-op: SQLite is already authoritative at runtime
208
217
  }
209
218
 
210
219
  // -- SSE (Server-Sent Events) live update layer -----------------------------
@@ -259,6 +268,7 @@ export async function startDashboardServer(
259
268
  let lastStatusCacheRefreshAt = 0;
260
269
  let statusRefreshPromise: Promise<void> | null = null;
261
270
  const STATUS_CACHE_TTL_MS = 30_000;
271
+ let boundPort = port;
262
272
 
263
273
  async function refreshStatusCache(force = false): Promise<void> {
264
274
  const cacheIsFresh =
@@ -383,8 +393,20 @@ export async function startDashboardServer(
383
393
  });
384
394
  }
385
395
 
386
- // ---- POST /api/actions/{watch,evolve,rollback} ----
396
+ // ---- POST /api/actions/{watch,evolve,rollback,watchlist} ----
387
397
  if (url.pathname.startsWith("/api/actions/") && req.method === "POST") {
398
+ const trustedActionOrigins = allowedDashboardOrigins(hostname, boundPort);
399
+ const origin = req.headers.get("origin");
400
+ if (!origin || !trustedActionOrigins.has(origin)) {
401
+ return Response.json(
402
+ {
403
+ success: false,
404
+ error:
405
+ "Dashboard actions only accept same-origin requests from the local dashboard UI.",
406
+ },
407
+ { status: 403, headers: corsHeaders() },
408
+ );
409
+ }
388
410
  const action = url.pathname.slice("/api/actions/".length);
389
411
  let body: Record<string, unknown> = {};
390
412
  try {
@@ -469,6 +491,18 @@ export async function startDashboardServer(
469
491
  return withCors(handleOrchestrateRuns(db, limit));
470
492
  }
471
493
 
494
+ // ---- GET /api/v2/analytics ----
495
+ if (url.pathname === "/api/v2/analytics" && req.method === "GET") {
496
+ if (!db) {
497
+ return Response.json(
498
+ { error: "V2 data unavailable" },
499
+ { status: 503, headers: corsHeaders() },
500
+ );
501
+ }
502
+ refreshV2Data();
503
+ return withCors(handleAnalytics(db));
504
+ }
505
+
472
506
  // ---- GET /api/v2/skills/:name ----
473
507
  if (url.pathname.startsWith("/api/v2/skills/") && req.method === "GET") {
474
508
  const skillName = decodePathSegment(url.pathname.slice("/api/v2/skills/".length));
@@ -510,7 +544,7 @@ export async function startDashboardServer(
510
544
  },
511
545
  });
512
546
 
513
- const boundPort = server.port;
547
+ boundPort = server.port;
514
548
 
515
549
  if (openBrowser) {
516
550
  const url = `http://${hostname}:${boundPort}`;