@agent-native/core 0.98.2 → 0.98.4

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 (78) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +23 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +2 -2
  5. package/corpus/core/src/client/analytics.ts +12 -0
  6. package/corpus/core/src/client/index.ts +2 -0
  7. package/corpus/core/src/client/session-replay.ts +612 -26
  8. package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -6
  9. package/corpus/core/src/client/settings/SettingsPanel.tsx +31 -211
  10. package/corpus/core/src/client/settings/agent-settings-search.ts +219 -0
  11. package/corpus/core/src/client/settings/index.ts +4 -0
  12. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
  13. package/corpus/core/src/demo/config.ts +6 -6
  14. package/corpus/core/src/demo/fetch-interceptor.ts +25 -2
  15. package/corpus/core/src/demo/redact.ts +57 -66
  16. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +65 -6
  17. package/corpus/templates/analytics/AGENTS.md +6 -6
  18. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +429 -244
  19. package/corpus/templates/analytics/app/components/layout/command-palette-search.ts +93 -0
  20. package/corpus/templates/analytics/app/global.css +4 -62
  21. package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +2 -1
  22. package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +46 -33
  23. package/corpus/templates/analytics/app/pages/Settings.tsx +8 -45
  24. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +413 -105
  25. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +32 -16
  26. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +126 -0
  27. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-loading-placeholders-now-stay-below-available-r.md +6 -0
  28. package/corpus/templates/analytics/changelog/2026-07-12-command-menu-search-now-prioritizes-the-best-match.md +6 -0
  29. package/corpus/templates/analytics/changelog/2026-07-12-demo-charts-preserve-source-movement.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-07-12-replay-storage-settings-stay-readable-at-narrow-widths.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-preserve-recorded-styling-and-keep-malformed.md +6 -0
  34. package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
  35. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
  36. package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
  37. package/dist/agent/production-agent.js +2 -2
  38. package/dist/agent/production-agent.js.map +1 -1
  39. package/dist/client/analytics.d.ts.map +1 -1
  40. package/dist/client/analytics.js +11 -0
  41. package/dist/client/analytics.js.map +1 -1
  42. package/dist/client/index.d.ts +1 -1
  43. package/dist/client/index.d.ts.map +1 -1
  44. package/dist/client/index.js +1 -1
  45. package/dist/client/index.js.map +1 -1
  46. package/dist/client/session-replay.d.ts +12 -3
  47. package/dist/client/session-replay.d.ts.map +1 -1
  48. package/dist/client/session-replay.js +488 -23
  49. package/dist/client/session-replay.js.map +1 -1
  50. package/dist/client/settings/DemoModeSection.d.ts +3 -3
  51. package/dist/client/settings/DemoModeSection.js +4 -4
  52. package/dist/client/settings/DemoModeSection.js.map +1 -1
  53. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  54. package/dist/client/settings/SettingsPanel.js +41 -191
  55. package/dist/client/settings/SettingsPanel.js.map +1 -1
  56. package/dist/client/settings/agent-settings-search.d.ts +16 -0
  57. package/dist/client/settings/agent-settings-search.d.ts.map +1 -0
  58. package/dist/client/settings/agent-settings-search.js +178 -0
  59. package/dist/client/settings/agent-settings-search.js.map +1 -0
  60. package/dist/client/settings/index.d.ts +1 -0
  61. package/dist/client/settings/index.d.ts.map +1 -1
  62. package/dist/client/settings/index.js +1 -0
  63. package/dist/client/settings/index.js.map +1 -1
  64. package/dist/collab/routes.d.ts +1 -1
  65. package/dist/demo/actions/toggle-demo-mode.js +2 -2
  66. package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
  67. package/dist/demo/config.js +6 -6
  68. package/dist/demo/config.js.map +1 -1
  69. package/dist/demo/fetch-interceptor.d.ts +1 -0
  70. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  71. package/dist/demo/fetch-interceptor.js +19 -2
  72. package/dist/demo/fetch-interceptor.js.map +1 -1
  73. package/dist/demo/redact.d.ts +14 -5
  74. package/dist/demo/redact.d.ts.map +1 -1
  75. package/dist/demo/redact.js +30 -56
  76. package/dist/demo/redact.js.map +1 -1
  77. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  78. package/package.json +2 -2
@@ -26,3 +26,96 @@ export function commandPaletteKeywords(
26
26
 
27
27
  return Array.from(variants);
28
28
  }
29
+
30
+ function normalizeSearchText(value: string): string {
31
+ return value
32
+ .normalize("NFKD")
33
+ .replace(/[\u0300-\u036f]/g, "")
34
+ .toLowerCase()
35
+ .replace(/[^\p{L}\p{N}]+/gu, " ")
36
+ .trim();
37
+ }
38
+
39
+ function fuzzySubsequenceScore(candidate: string, query: string): number {
40
+ const compactCandidate = candidate.replace(/\s/g, "");
41
+ const compactQuery = query.replace(/\s/g, "");
42
+ let queryIndex = 0;
43
+
44
+ for (const character of compactCandidate) {
45
+ if (character === compactQuery[queryIndex]) queryIndex += 1;
46
+ if (queryIndex === compactQuery.length) {
47
+ return 0.2 * (compactQuery.length / compactCandidate.length);
48
+ }
49
+ }
50
+
51
+ return 0;
52
+ }
53
+
54
+ export function commandPaletteFilter(
55
+ value: string,
56
+ search: string,
57
+ keywords: string[] = [],
58
+ ): number {
59
+ const query = normalizeSearchText(search);
60
+ if (!query) return 1;
61
+
62
+ const queryWords = query.split(" ");
63
+ let bestScore = 0;
64
+
65
+ for (const rawCandidate of [...keywords, value]) {
66
+ const candidate = normalizeSearchText(rawCandidate);
67
+ if (!candidate) continue;
68
+
69
+ const words = candidate.split(" ");
70
+ let score = 0;
71
+
72
+ if (candidate === query) score = 1;
73
+ else if (candidate.startsWith(query)) score = 0.96;
74
+ else if (words.includes(query)) score = 0.94;
75
+ else if (words.some((word) => word.startsWith(query))) score = 0.9;
76
+ else if (candidate.includes(query)) score = 0.8;
77
+ else if (
78
+ queryWords.every((queryWord) =>
79
+ words.some((word) => word.startsWith(queryWord)),
80
+ )
81
+ ) {
82
+ score = 0.72;
83
+ } else {
84
+ score = fuzzySubsequenceScore(candidate, query);
85
+ }
86
+
87
+ bestScore = Math.max(bestScore, score);
88
+ }
89
+
90
+ return bestScore;
91
+ }
92
+
93
+ export function rankCommandPaletteEntries<T>(
94
+ entries: T[],
95
+ search: string,
96
+ getSearchData: (entry: T) => { value: string; keywords?: string[] },
97
+ ): Array<{ entry: T; score: number }> {
98
+ return entries
99
+ .map((entry, index) => {
100
+ const { value, keywords } = getSearchData(entry);
101
+ return {
102
+ entry,
103
+ index,
104
+ score: commandPaletteFilter(value, search, keywords),
105
+ };
106
+ })
107
+ .filter(({ score }) => score > 0)
108
+ .sort((a, b) => b.score - a.score || a.index - b.index)
109
+ .map(({ entry, score }) => ({ entry, score }));
110
+ }
111
+
112
+ export function uniqueCommandItems<T extends { id: string; name: string }>(
113
+ items: T[],
114
+ ): T[] {
115
+ const seenIds = new Set<string>();
116
+ return items.filter((item) => {
117
+ if (seenIds.has(item.id)) return false;
118
+ seenIds.add(item.id);
119
+ return true;
120
+ });
121
+ }
@@ -245,72 +245,14 @@
245
245
  transform-origin: top left;
246
246
  }
247
247
 
248
- /* First-party visitor-cursor styles for rrweb playback. These are bundled
249
- statically so the cursor stays visible even if the lazily imported
250
- `@rrweb/replay/dist/style.css` sheet fails to load, and they replace the
251
- default black arrow sprite with an app-styled indicator. The cursor lives
252
- inside `.replayer-wrapper`, so it scales with the fit-to-stage transform. */
253
- .an-replay-stage-root .replayer-mouse {
254
- position: absolute;
255
- z-index: 2;
256
- width: 1.125rem;
257
- height: 1.5rem;
258
- border-radius: 0;
259
- background: transparent;
260
- background-image: none;
261
- box-shadow: none;
262
- transform: none;
263
- transition:
264
- left 80ms linear,
265
- top 80ms linear;
266
- pointer-events: none;
267
- }
268
-
269
- .an-replay-stage-root .replayer-mouse::before {
270
- content: "";
271
- position: absolute;
272
- inset: 0;
273
- background: hsl(0 0% 100%);
274
- clip-path: polygon(0 0, 0 77%, 30% 57%, 48% 100%, 68% 92%, 50% 51%, 92% 51%);
275
- filter: drop-shadow(0 0 1px hsl(0 0% 0% / 0.95))
276
- drop-shadow(0 1px 3px hsl(0 0% 0% / 0.35));
277
- }
278
-
248
+ /* IMPORTANT: Keep rrweb's stock SVG arrow. Only suppress its permanently
249
+ visible purple ::after disc, which can otherwise read as the cursor itself
250
+ when the arrow is small. The stock .active animation still supplies the
251
+ brief click halo. Do not replace the arrow with an app-colored dot. */
279
252
  .an-replay-stage-root .replayer-mouse::after {
280
- content: "";
281
- position: absolute;
282
- left: -0.5rem;
283
- top: -0.5rem;
284
- width: 1rem;
285
- height: 1rem;
286
- border-radius: 9999px;
287
- border: 2px solid hsl(217 91% 60%);
288
- background: transparent;
289
253
  opacity: 0;
290
254
  }
291
255
 
292
- /* rrweb toggles `.active` on mouse interactions; pulse a click ripple. */
293
- .an-replay-stage-root .replayer-mouse.active::after {
294
- animation: an-replay-mouse-click 0.4s ease-out 1;
295
- }
296
-
297
- @keyframes an-replay-mouse-click {
298
- 0% {
299
- opacity: 0.5;
300
- transform: scale(1);
301
- }
302
- 100% {
303
- opacity: 0;
304
- transform: scale(3.5);
305
- }
306
- }
307
-
308
- .an-replay-stage-root .replayer-mouse-tail {
309
- position: absolute;
310
- inset: 0;
311
- pointer-events: none;
312
- }
313
-
314
256
  .analytics-session-snippet .plan-code-surface {
315
257
  border: 0;
316
258
  border-radius: 0;
@@ -46,11 +46,12 @@ export async function fetchReplayStorageStatus(): Promise<ReplayStorageStatus> {
46
46
  };
47
47
  }
48
48
 
49
- export function useReplayStorageStatus() {
49
+ export function useReplayStorageStatus(options?: { enabled?: boolean }) {
50
50
  return useQuery({
51
51
  queryKey: REPLAY_STORAGE_STATUS_KEY,
52
52
  queryFn: fetchReplayStorageStatus,
53
53
  staleTime: 60_000,
54
+ enabled: options?.enabled,
54
55
  });
55
56
  }
56
57
 
@@ -52,49 +52,56 @@ function normalizedVolatility(
52
52
  }
53
53
 
54
54
  function normalizedTrend(
55
- length: number,
55
+ series: number[],
56
+ minimum: number,
57
+ range: number,
56
58
  volatilityScore: number,
57
59
  random: () => number,
58
60
  ): number[] {
61
+ const length = series.length;
59
62
  if (length <= 1) return [0];
60
63
  if (length === 2) return [0, 1];
61
64
 
62
- const volatility = 0.015 + volatilityScore * (0.22 + random() * 0.12);
63
- const noiseMemory = 0.78 - volatilityScore * 0.58;
64
- let noise = 0;
65
- const values = Array.from({ length }, (_, index) => {
66
- if (index === 0) return 0;
67
- if (index === length - 1) return 1;
65
+ const normalized = series.map((value) => (value - minimum) / range);
66
+ const randomization = 0.012 + volatilityScore * 0.08;
67
+ const shape = [normalized[0]];
68
+
69
+ // Preserve the source's actual step pattern (including when and how sharply
70
+ // it spikes), with just enough seeded variation that otherwise-similar demo
71
+ // series do not become identical. Smooth sources receive almost no jitter;
72
+ // volatile sources can vary a little more without moving their events.
73
+ for (let index = 1; index < length; index += 1) {
74
+ const sourceStep = normalized[index] - normalized[index - 1];
75
+ const factor = 1 + (random() * 2 - 1) * randomization;
76
+ shape.push(shape[index - 1] + sourceStep * factor);
77
+ }
68
78
 
79
+ // Add only the linear drift required for the first point to be the global
80
+ // minimum and the last to be the global maximum. A linear term has zero
81
+ // second difference, so the source's local acceleration, spikes, and dips
82
+ // survive instead of being replaced by a synthetic random walk.
83
+ let requiredDrift = 0;
84
+ for (let index = 1; index < length; index += 1) {
85
+ const progress = index / (length - 1);
86
+ requiredDrift = Math.max(
87
+ requiredDrift,
88
+ (shape[0] - shape[index]) / progress,
89
+ );
90
+ }
91
+ for (let index = 0; index < length - 1; index += 1) {
69
92
  const progress = index / (length - 1);
70
- noise = noise * noiseMemory + (random() * 2 - 1) * (1 - noiseMemory);
71
- const taperedNoise = noise * volatility * Math.sin(Math.PI * progress);
72
- return clamp(progress + taperedNoise, 0.025, 0.975);
73
- });
74
-
75
- // Pullback count and depth follow the source's normalized volatility. A
76
- // smooth source remains a gentle rise; a jagged source gets several seeded
77
- // reversals. Spacing the reversals across the series prevents them from
78
- // collapsing into one noisy patch.
79
- if (length >= 5 && volatilityScore >= 0.12) {
80
- const maximumPullbacks = Math.min(3, Math.floor((length - 2) / 2));
81
- const pullbackCount = Math.max(
82
- 1,
83
- Math.round(volatilityScore * maximumPullbacks),
93
+ requiredDrift = Math.max(
94
+ requiredDrift,
95
+ (shape[index] - shape[length - 1]) / (1 - progress),
84
96
  );
85
- for (let pullback = 0; pullback < pullbackCount; pullback += 1) {
86
- const segmentCenter =
87
- ((pullback + 1) * (length - 3)) / (pullbackCount + 1) + 1;
88
- const jitter = (random() - 0.5) * Math.max(1, length / 10);
89
- const dipIndex = Math.round(clamp(segmentCenter + jitter, 2, length - 2));
90
- const center = dipIndex / (length - 1);
91
- const amplitude = 0.025 + volatilityScore * (0.075 + random() * 0.12);
92
- values[dipIndex - 1] = clamp(center + amplitude, 0.075, 0.925);
93
- values[dipIndex] = clamp(center - amplitude, 0.05, 0.9);
94
- }
95
97
  }
96
98
 
97
- return values;
99
+ const drift = requiredDrift + 0.012 + random() * 0.018;
100
+ const candidate = shape.map(
101
+ (value, index) => value + drift * (index / (length - 1)),
102
+ );
103
+ const candidateRange = candidate[length - 1] - candidate[0];
104
+ return candidate.map((value) => (value - candidate[0]) / candidateRange);
98
105
  }
99
106
 
100
107
  /**
@@ -133,7 +140,13 @@ export function createDemoChartTrendRows(
133
140
  minimum,
134
141
  range,
135
142
  );
136
- const trend = normalizedTrend(points.length, volatilityScore, random);
143
+ const trend = normalizedTrend(
144
+ points.map((point) => point.numeric),
145
+ minimum,
146
+ range,
147
+ volatilityScore,
148
+ random,
149
+ );
137
150
  const useStringValues = points.every(
138
151
  (point) => typeof point.original === "string",
139
152
  );
@@ -5,7 +5,6 @@ import {
5
5
  useAgentSettingsTabs,
6
6
  useSession,
7
7
  useT,
8
- type SettingsSearchEntry,
9
8
  type SettingsTabItem,
10
9
  } from "@agent-native/core/client";
11
10
  import { TeamPage } from "@agent-native/core/client/org";
@@ -27,6 +26,7 @@ import changelog from "../../CHANGELOG.md?raw";
27
26
  import { useReplayStorageStatus } from "../hooks/use-replay-storage-status";
28
27
  import { ReplayStorageHint } from "./sessions/SessionsPage";
29
28
  import { AlertRulesSettingsCard } from "./settings/AlertRulesSettingsCard";
29
+ import { buildAnalyticsGeneralSettingsSearchEntries } from "./settings/settings-search";
30
30
 
31
31
  export default function Settings() {
32
32
  // Settings is also reachable directly from the full-page agent surface.
@@ -56,49 +56,12 @@ export default function Settings() {
56
56
  [agentSettingsTabs, t],
57
57
  );
58
58
 
59
- const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
60
- () => [
61
- {
62
- id: "analytics-account",
63
- label: t("settings.account"),
64
- keywords: "profile email signed in identity",
65
- hash: "account",
66
- },
67
- {
68
- id: "analytics-credentials",
69
- label: t("settings.credentials"),
70
- keywords: "data sources api keys manage credentials",
71
- hash: "credentials",
72
- },
73
- {
74
- id: "analytics-dashboard-templates",
75
- label: t("settings.dashboardTemplates"),
76
- keywords: "templates catalog dashboards",
77
- hash: "dashboard-templates",
78
- },
79
- ...(replayStorageStatus.data?.configured
80
- ? [
81
- {
82
- id: "analytics-replay-storage",
83
- label: t("sessions.storageSetupTitle"),
84
- keywords: "session replay recording storage s3 bucket builder",
85
- hash: "replay-storage",
86
- },
87
- ]
88
- : []),
89
- {
90
- id: "analytics-language",
91
- label: t("settings.languageTitle"),
92
- keywords: "language locale translation i18n",
93
- hash: "language",
94
- },
95
- {
96
- id: "analytics-about",
97
- label: t("settings.about"),
98
- keywords: "about version info usage",
99
- hash: "about",
100
- },
101
- ],
59
+ const generalSearchEntries = useMemo(
60
+ () =>
61
+ buildAnalyticsGeneralSettingsSearchEntries(
62
+ t,
63
+ !!replayStorageStatus.data?.configured,
64
+ ),
102
65
  [replayStorageStatus.data?.configured, t],
103
66
  );
104
67
 
@@ -184,7 +147,7 @@ export default function Settings() {
184
147
  </CardDescription>
185
148
  </CardHeader>
186
149
  <CardContent>
187
- <ReplayStorageHint />
150
+ <ReplayStorageHint embedded />
188
151
  </CardContent>
189
152
  </Card>
190
153
  ) : null}