@agent-native/core 0.73.0 → 0.75.0

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 (58) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +67 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/durable-background.ts +51 -5
  5. package/corpus/core/src/agent/production-agent.ts +92 -12
  6. package/corpus/core/src/client/ConnectBuilderCard.tsx +7 -7
  7. package/corpus/core/src/client/NewWorkspaceAppFlow.tsx +1 -1
  8. package/corpus/core/src/client/blocks/library/AnnotatedCodeBlock.tsx +33 -18
  9. package/corpus/core/src/client/blocks/library/annotation-rail.tsx +3 -4
  10. package/corpus/core/src/client/components/CodeRequiredDialog.tsx +5 -8
  11. package/corpus/core/src/deploy/build.ts +21 -9
  12. package/corpus/core/src/deploy/workspace-deploy.ts +12 -6
  13. package/corpus/core/src/server/agent-chat-plugin.ts +7 -7
  14. package/corpus/core/src/server/self-dispatch.ts +8 -1
  15. package/corpus/templates/analytics/actions/compose-dashboard.ts +34 -0
  16. package/corpus/templates/analytics/actions/install-dashboard-template.ts +51 -3
  17. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +31 -8
  18. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-filters-now-apply-consistently-to-first-party-traf.md +6 -0
  19. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +97 -28
  20. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +57 -10
  21. package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -0
  22. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +786 -323
  23. package/corpus/templates/clips/changelog/2026-06-24-settings-now-puts-what-s-new-in-a-compact-sidebar-prioritize.md +6 -0
  24. package/corpus/templates/plan/changelog/2026-06-24-annotated-code-callouts-now-use-numbered-gutter-markers-that.md +6 -0
  25. package/dist/agent/durable-background.d.ts +21 -0
  26. package/dist/agent/durable-background.d.ts.map +1 -1
  27. package/dist/agent/durable-background.js +48 -5
  28. package/dist/agent/durable-background.js.map +1 -1
  29. package/dist/agent/production-agent.d.ts.map +1 -1
  30. package/dist/agent/production-agent.js +88 -13
  31. package/dist/agent/production-agent.js.map +1 -1
  32. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  33. package/dist/client/ConnectBuilderCard.js +6 -6
  34. package/dist/client/ConnectBuilderCard.js.map +1 -1
  35. package/dist/client/NewWorkspaceAppFlow.js +1 -1
  36. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  37. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  38. package/dist/client/blocks/library/AnnotatedCodeBlock.js +14 -10
  39. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  40. package/dist/client/blocks/library/annotation-rail.d.ts +3 -4
  41. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  42. package/dist/client/blocks/library/annotation-rail.js +3 -4
  43. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  44. package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
  45. package/dist/client/components/CodeRequiredDialog.js +2 -1
  46. package/dist/client/components/CodeRequiredDialog.js.map +1 -1
  47. package/dist/deploy/build.d.ts +13 -2
  48. package/dist/deploy/build.d.ts.map +1 -1
  49. package/dist/deploy/build.js +21 -9
  50. package/dist/deploy/build.js.map +1 -1
  51. package/dist/deploy/workspace-deploy.js +12 -6
  52. package/dist/deploy/workspace-deploy.js.map +1 -1
  53. package/dist/server/agent-chat-plugin.js +7 -7
  54. package/dist/server/agent-chat-plugin.js.map +1 -1
  55. package/dist/server/self-dispatch.d.ts.map +1 -1
  56. package/dist/server/self-dispatch.js +5 -1
  57. package/dist/server/self-dispatch.js.map +1 -1
  58. package/package.json +1 -1
@@ -45,6 +45,14 @@ export interface FirstPartyMetric {
45
45
  config: Record<string, unknown>;
46
46
  }
47
47
 
48
+ export interface FirstPartyDashboardFilter {
49
+ id: string;
50
+ type: "select";
51
+ label: string;
52
+ default: string;
53
+ options: Array<{ value: string; label: string }>;
54
+ }
55
+
48
56
  const WINDOW_DAYS: Record<Exclude<MetricWindow, "all">, number> = {
49
57
  "30d": 30,
50
58
  "90d": 90,
@@ -94,6 +102,45 @@ const DASHBOARD_TIME_RANGE_FILTER =
94
102
  "('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))";
95
103
  const DASHBOARD_EMAIL_FILTER =
96
104
  "('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))";
105
+ export const FIRST_PARTY_DASHBOARD_FILTERS: FirstPartyDashboardFilter[] = [
106
+ {
107
+ id: "timeRange",
108
+ type: "select",
109
+ label: "Time range",
110
+ default: "90d",
111
+ options: [
112
+ { value: "7d", label: "Last 7 days" },
113
+ { value: "30d", label: "Last 30 days" },
114
+ { value: "90d", label: "Last 90 days" },
115
+ { value: "180d", label: "Last 180 days" },
116
+ { value: "365d", label: "Last 365 days" },
117
+ { value: "all", label: "All time" },
118
+ ],
119
+ },
120
+ {
121
+ id: "emailFilter",
122
+ type: "select",
123
+ label: "Email filter",
124
+ default: "all",
125
+ options: [
126
+ { value: "all", label: "All users" },
127
+ { value: "exclude_builder", label: "Exclude @builder.io" },
128
+ { value: "only_builder", label: "Only @builder.io" },
129
+ ],
130
+ },
131
+ ];
132
+
133
+ export function buildFirstPartyDashboardFilters(): FirstPartyDashboardFilter[] {
134
+ return FIRST_PARTY_DASHBOARD_FILTERS.map((filter) => ({
135
+ ...filter,
136
+ options: filter.options.map((option) => ({ ...option })),
137
+ }));
138
+ }
139
+
140
+ export function usesFirstPartyDashboardFilters(sql: string): boolean {
141
+ return sql.includes("{{timeRange}}") || sql.includes("{{emailFilter}}");
142
+ }
143
+
97
144
  const TOTAL_SIGNUPS_SQL = `SELECT COUNT(*) AS signups FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`;
98
145
  const SIGNUPS_OVER_TIME_SQL = `WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY timestamp) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT substr(timestamp, 1, 10) AS date, ${SIGNUP_TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
99
146
  const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${SIGNUP_TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '1 day', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
@@ -217,7 +264,7 @@ const ENTRIES: FirstPartyMetric[] = [
217
264
  width: 1,
218
265
  windowed: false,
219
266
  buildSql: fixed(
220
- "SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template'",
267
+ `SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`,
221
268
  ),
222
269
  config: {
223
270
  yKey: "count",
@@ -233,7 +280,7 @@ const ENTRIES: FirstPartyMetric[] = [
233
280
  width: 1,
234
281
  windowed: false,
235
282
  buildSql: fixed(
236
- "SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo'",
283
+ `SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`,
237
284
  ),
238
285
  config: {
239
286
  yKey: "count",
@@ -249,7 +296,7 @@ const ENTRIES: FirstPartyMetric[] = [
249
296
  width: 1,
250
297
  windowed: false,
251
298
  buildSql: fixed(
252
- "SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command'",
299
+ `SELECT COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`,
253
300
  ),
254
301
  config: {
255
302
  yKey: "count",
@@ -265,7 +312,7 @@ const ENTRIES: FirstPartyMetric[] = [
265
312
  width: 2,
266
313
  windowed: false,
267
314
  buildSql: fixed(
268
- "SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
315
+ `SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
269
316
  ),
270
317
  config: {
271
318
  xKey: "date",
@@ -287,7 +334,7 @@ const ENTRIES: FirstPartyMetric[] = [
287
334
  width: 2,
288
335
  windowed: false,
289
336
  buildSql: fixed(
290
- "SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
337
+ `SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
291
338
  ),
292
339
  config: {
293
340
  xKey: "date",
@@ -309,7 +356,7 @@ const ENTRIES: FirstPartyMetric[] = [
309
356
  width: 2,
310
357
  windowed: false,
311
358
  buildSql: fixed(
312
- "SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
359
+ `SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
313
360
  ),
314
361
  config: {
315
362
  xKey: "date",
@@ -331,7 +378,7 @@ const ENTRIES: FirstPartyMetric[] = [
331
378
  width: 2,
332
379
  windowed: false,
333
380
  buildSql: fixed(
334
- "SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
381
+ `SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
335
382
  ),
336
383
  config: {
337
384
  xKey: "date",
@@ -353,7 +400,7 @@ const ENTRIES: FirstPartyMetric[] = [
353
400
  width: 2,
354
401
  windowed: false,
355
402
  buildSql: fixed(
356
- "SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template",
403
+ `SELECT substr(timestamp, 1, 10) AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
357
404
  ),
358
405
  config: {
359
406
  xKey: "date",
@@ -402,7 +449,7 @@ const ENTRIES: FirstPartyMetric[] = [
402
449
  width: 2,
403
450
  windowed: false,
404
451
  buildSql: fixed(
405
- `WITH pageviews AS (SELECT COALESCE(CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') END, NULLIF(url, ''), NULLIF(path, ''), 'unknown') AS url, CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN NULLIF(url, '') LIKE 'http%' THEN url ELSE COALESCE(NULLIF(url, ''), NULLIF(path, ''), '') END AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY 1, 2) SELECT url, views, users, last_seen, href FROM pageviews ORDER BY views DESC LIMIT 25`,
452
+ `WITH pageviews AS (SELECT COALESCE(CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') END, NULLIF(url, ''), NULLIF(path, ''), 'unknown') AS url, CASE WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN lower(COALESCE(NULLIF(url, ''), '')) LIKE 'http://%' OR lower(COALESCE(NULLIF(url, ''), '')) LIKE 'https://%' THEN url WHEN NULLIF(path, '') IS NOT NULL AND substr(path, 1, 1) = '/' AND substr(path, 1, 2) != '//' THEN path ELSE '' END AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY 1, 2) SELECT url, views, users, last_seen, href FROM pageviews ORDER BY views DESC LIMIT 25`,
406
453
  ),
407
454
  config: {
408
455
  description:
@@ -426,7 +473,7 @@ const ENTRIES: FirstPartyMetric[] = [
426
473
  width: 2,
427
474
  windowed: false,
428
475
  buildSql: fixed(
429
- `WITH clip_events AS (SELECT COALESCE(NULLIF(properties::jsonb ->> 'recording_id', ''), NULLIF(path, ''), NULLIF(url, ''), 'unknown') AS clip_key, CASE WHEN NULLIF(url, '') LIKE 'http%' THEN url WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN NULLIF(path, '') LIKE '/%' THEN 'https://clips.agent-native.com' || path ELSE COALESCE(NULLIF(url, ''), '') END AS href, user_id, anonymous_id, timestamp FROM analytics_events WHERE event_name = 'share_view' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND COALESCE(NULLIF(properties::jsonb ->> 'surface', ''), 'clip') = 'clip'), clip_views AS (SELECT clip_key, COALESCE(MAX(NULLIF(href, '')), clip_key) AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM clip_events GROUP BY clip_key) SELECT CASE WHEN href LIKE 'http%' THEN href ELSE clip_key END AS clip, views, users, last_seen, href FROM clip_views ORDER BY views DESC LIMIT 25`,
476
+ `WITH clip_events AS (SELECT COALESCE(NULLIF(properties::jsonb ->> 'recording_id', ''), NULLIF(path, ''), NULLIF(url, ''), 'unknown') AS clip_key, CASE WHEN lower(COALESCE(NULLIF(url, ''), '')) LIKE 'http://%' OR lower(COALESCE(NULLIF(url, ''), '')) LIKE 'https://%' THEN url WHEN NULLIF(hostname, '') IS NOT NULL THEN 'https://' || hostname || COALESCE(NULLIF(path, ''), '/') WHEN NULLIF(path, '') LIKE '/%' THEN 'https://clips.agent-native.com' || path ELSE '' END AS href, user_id, anonymous_id, timestamp FROM analytics_events WHERE event_name = 'share_view' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND COALESCE(NULLIF(properties::jsonb ->> 'surface', ''), 'clip') = 'clip'), clip_views AS (SELECT clip_key, COALESCE(MAX(NULLIF(href, '')), clip_key) AS href, COUNT(*) AS views, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users, MAX(substr(timestamp, 1, 10)) AS last_seen FROM clip_events GROUP BY clip_key) SELECT CASE WHEN lower(COALESCE(href, '')) LIKE 'http://%' OR lower(COALESCE(href, '')) LIKE 'https://%' THEN href ELSE clip_key END AS clip, views, users, last_seen, href FROM clip_views ORDER BY views DESC LIMIT 25`,
430
477
  ),
431
478
  config: {
432
479
  description: "Most-viewed shared Clips pages in the selected time range.",
@@ -15,6 +15,7 @@ import {
15
15
  IconLayoutSidebarLeftCollapse,
16
16
  IconLayoutSidebarLeftExpand,
17
17
  IconPlus,
18
+ IconSettings,
18
19
  } from "@tabler/icons-react";
19
20
  import {
20
21
  AgentSidebar,
@@ -212,6 +213,12 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
212
213
  icon: IconTrash,
213
214
  match: (p) => p.startsWith("/trash"),
214
215
  },
216
+ {
217
+ to: "/settings",
218
+ label: "Settings",
219
+ icon: IconSettings,
220
+ match: (p) => p.startsWith("/settings"),
221
+ },
215
222
  ];
216
223
 
217
224
  return (