@agent-native/core 0.154.5 → 0.155.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 (185) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
  3. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
  4. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
  6. package/corpus/templates/analytics/AGENTS.md +3 -0
  7. package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
  8. package/corpus/templates/analytics/actions/bigquery.ts +1 -1
  9. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
  10. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  11. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
  12. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
  13. package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
  14. package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
  15. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
  16. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
  17. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  18. package/corpus/templates/calendar/AGENTS.md +2 -0
  19. package/corpus/templates/calendar/DEVELOPING.md +4 -4
  20. package/corpus/templates/calendar/actions/get-settings.ts +4 -11
  21. package/corpus/templates/calendar/actions/update-availability.ts +15 -4
  22. package/corpus/templates/calendar/actions/update-settings.ts +15 -4
  23. package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
  24. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
  25. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
  26. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
  27. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
  28. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
  29. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
  30. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
  31. package/corpus/templates/calendar/app/i18n-data.ts +30 -0
  32. package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
  33. package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
  34. package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
  35. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
  36. package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
  37. package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
  38. package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
  39. package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
  40. package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
  41. package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
  42. package/corpus/templates/calendar/shared/api.ts +1 -0
  43. package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
  44. package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
  45. package/corpus/templates/calendar/shared/settings.ts +44 -0
  46. package/corpus/templates/clips/AGENTS.md +2 -0
  47. package/corpus/templates/clips/actions/add-comment.ts +5 -2
  48. package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
  49. package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
  50. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
  51. package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
  52. package/corpus/templates/clips/actions/update-comment.ts +9 -2
  53. package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
  54. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
  55. package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
  56. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
  57. package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
  58. package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
  59. package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
  60. package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
  61. package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
  62. package/corpus/templates/clips/app/root.tsx +2 -1
  63. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
  64. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
  65. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
  66. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +14 -7
  67. package/corpus/templates/clips/app/routes/share.$shareId.tsx +8 -4
  68. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
  69. package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
  70. package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
  71. package/corpus/templates/clips/desktop/src/app.tsx +116 -19
  72. package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
  73. package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
  74. package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
  75. package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
  76. package/corpus/templates/clips/desktop/src/styles.css +117 -0
  77. package/corpus/templates/clips/server/db/index.ts +10 -0
  78. package/corpus/templates/clips/server/db/schema.ts +1 -0
  79. package/corpus/templates/clips/server/lib/recordings.ts +3 -1
  80. package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
  81. package/corpus/templates/clips/server/plugins/db.ts +5 -0
  82. package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
  83. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
  84. package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
  85. package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
  86. package/corpus/templates/content/actions/add-comment.ts +2 -1
  87. package/corpus/templates/content/actions/update-comment.ts +1 -1
  88. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
  89. package/corpus/templates/design/actions/generate-design.ts +10 -7
  90. package/corpus/templates/design/actions/present-design-variants.ts +35 -6
  91. package/corpus/templates/design/actions/run-design-audit.ts +33 -0
  92. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
  93. package/corpus/templates/design/shared/design-review.ts +1 -0
  94. package/corpus/templates/design/shared/html-integrity.ts +66 -0
  95. package/corpus/templates/dispatch/.env.example +5 -0
  96. package/corpus/templates/dispatch/AGENTS.md +24 -19
  97. package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
  98. package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
  99. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
  100. package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
  101. package/corpus/templates/factory/AGENTS.md +5 -1
  102. package/corpus/templates/factory/README.md +23 -0
  103. package/corpus/templates/factory/actions/view-screen.ts +17 -0
  104. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
  105. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
  106. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
  107. package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
  108. package/corpus/templates/factory/app/routes/factory.tsx +41 -0
  109. package/corpus/templates/factory/package.json +1 -0
  110. package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
  111. package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
  112. package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
  113. package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
  114. package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
  115. package/corpus/templates/mail/vite.config.ts +7 -0
  116. package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
  117. package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
  118. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  119. package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
  120. package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
  121. package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
  122. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
  123. package/dist/agent/production-agent.js +5 -1
  124. package/dist/agent/thread-data-builder.js +17 -1
  125. package/dist/cli/skills-content/help.js +6 -4
  126. package/dist/cli/skills.js +17 -2
  127. package/dist/cli/workspacify.d.ts +5 -0
  128. package/dist/cli/workspacify.js +65 -8
  129. package/dist/client/AgentPanel.d.ts +5 -0
  130. package/dist/client/AgentPanel.js +20 -4
  131. package/dist/client/AssistantChat.d.ts +21 -0
  132. package/dist/client/AssistantChat.js +66 -68
  133. package/dist/client/active-run-state.d.ts +14 -1
  134. package/dist/client/active-run-state.js +0 -0
  135. package/dist/client/agent-chat-adapter.js +107 -5
  136. package/dist/client/analytics.js +9 -2
  137. package/dist/client/chat/tool-call-display.js +4 -4
  138. package/dist/client/chat-first/apps-rail.js +9 -4
  139. package/dist/client/chat-first/primary-nav.d.ts +2 -1
  140. package/dist/client/chat-first/primary-nav.js +3 -3
  141. package/dist/client/chat-first/types.d.ts +5 -1
  142. package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
  143. package/dist/client/markdown/InlineMarkdown.js +65 -0
  144. package/dist/client/markdown/index.d.ts +1 -0
  145. package/dist/client/markdown/index.js +1 -0
  146. package/dist/client/review/ReviewThreadPanel.js +2 -1
  147. package/dist/client/run-stream-ownership.d.ts +39 -0
  148. package/dist/client/run-stream-ownership.js +65 -0
  149. package/dist/collab/awareness.d.ts +2 -2
  150. package/dist/collab/struct-routes.d.ts +1 -1
  151. package/dist/feature-flags/index.d.ts +1 -1
  152. package/dist/feature-flags/index.js +1 -1
  153. package/dist/feature-flags/store.d.ts +10 -0
  154. package/dist/feature-flags/store.js +112 -1
  155. package/dist/guards/no-env-credentials.js +4 -0
  156. package/dist/index.d.ts +1 -1
  157. package/dist/index.js +1 -1
  158. package/dist/integrations/adapters/slack.js +5 -1
  159. package/dist/localization/default-messages.d.ts +1 -0
  160. package/dist/localization/default-messages.js +1 -0
  161. package/dist/observability/routes.d.ts +6 -6
  162. package/dist/progress/routes.d.ts +1 -1
  163. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  164. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  165. package/dist/resources/agents.js +40 -5
  166. package/dist/resources/handlers.d.ts +1 -1
  167. package/dist/resources/metadata.d.ts +10 -0
  168. package/dist/resources/metadata.js +7 -3
  169. package/dist/review/actions/create-review-comment.js +1 -1
  170. package/dist/review/actions/reply-review-comment.js +1 -1
  171. package/dist/review/actions/resolve-review-thread.js +1 -1
  172. package/dist/secrets/routes.d.ts +3 -3
  173. package/dist/server/action-routes.js +32 -6
  174. package/dist/server/agent-discovery.js +14 -3
  175. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  176. package/dist/server/core-routes-plugin.js +1 -1
  177. package/dist/server/identity-sso-migrations.d.ts +7 -0
  178. package/dist/server/identity-sso-migrations.js +36 -0
  179. package/dist/server/identity-sso-store.d.ts +3 -2
  180. package/dist/server/identity-sso-store.js +8 -3
  181. package/dist/server/realtime-token.d.ts +1 -1
  182. package/dist/server/release-migrations.js +4 -0
  183. package/dist/tracking/providers.js +13 -3
  184. package/dist/workspace-files/tool.js +1 -1
  185. package/package.json +3 -2
@@ -12,6 +12,7 @@ import {
12
12
  IconNotes,
13
13
  IconPlugConnected,
14
14
  IconPlugOff,
15
+ IconPlus,
15
16
  IconSearch,
16
17
  IconSettings,
17
18
  IconX,
@@ -530,17 +531,11 @@ function CalendarAccountMenu({
530
531
  const [disconnectTarget, setDisconnectTarget] =
531
532
  useState<CalendarAccount | null>(null);
532
533
 
533
- const primaryAccount = accounts[0] ?? null;
534
- const statusText =
535
- primaryAccount?.status === "disconnected"
536
- ? "Disconnected"
537
- : primaryAccount?.status === "needs-reauth"
538
- ? "Needs reconnect"
539
- : primaryAccount
540
- ? "Connected"
541
- : "Not connected";
534
+ const hasNeedsReconnect = accounts.some(
535
+ (account) => account.status === "needs-reauth",
536
+ );
542
537
 
543
- const handleReconnect = () => {
538
+ const handleConnect = () => {
544
539
  setConnectPending(true);
545
540
  startCalendarOAuth()
546
541
  .then(() => onConnected?.())
@@ -586,48 +581,121 @@ function CalendarAccountMenu({
586
581
  aria-label={t("meetingsRoute.calendarSettings")}
587
582
  >
588
583
  <IconSettings className="h-4 w-4" />
589
- Calendar
584
+ {t("meetingsRoute.calendarAccountsButton", {
585
+ defaultValue: "Calendars",
586
+ })}
590
587
  </Button>
591
588
  </DropdownMenuTrigger>
592
589
  <DropdownMenuContent align="end" className="w-72">
593
590
  <DropdownMenuLabel className="flex items-center gap-2">
594
- {primaryAccount ? (
591
+ {accounts.length > 0 ? (
595
592
  <IconPlugConnected className="h-4 w-4 text-muted-foreground" />
596
593
  ) : (
597
594
  <IconPlugOff className="h-4 w-4 text-muted-foreground" />
598
595
  )}
599
596
  Google Calendar
600
597
  </DropdownMenuLabel>
601
- <div className="px-2 pb-1 text-xs text-muted-foreground">
602
- {primaryAccount ? (
603
- <>
604
- <div className="truncate">
605
- {calendarAccountLabel(primaryAccount)}
598
+ {accounts.length > 0 ? (
599
+ <div className="space-y-1.5 px-2 pb-1">
600
+ <div className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
601
+ {t("meetingsRoute.connectedAccounts", {
602
+ defaultValue: "Connected accounts",
603
+ })}
604
+ </div>
605
+ {accounts.map((account) => (
606
+ <div
607
+ key={account.id}
608
+ className="flex min-w-0 items-center gap-2 text-xs"
609
+ >
610
+ {account.status === "needs-reauth" ? (
611
+ <IconAlertTriangle className="h-3.5 w-3.5 shrink-0 text-destructive" />
612
+ ) : account.status === "disconnected" ? (
613
+ <IconPlugOff className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
614
+ ) : (
615
+ <IconPlugConnected className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
616
+ )}
617
+ <span className="min-w-0 flex-1 truncate">
618
+ {calendarAccountLabel(account)}
619
+ </span>
620
+ <span
621
+ className={
622
+ account.status === "needs-reauth" ||
623
+ account.status === "disconnected"
624
+ ? "shrink-0 text-[11px] text-destructive"
625
+ : "shrink-0 text-[11px] text-muted-foreground"
626
+ }
627
+ >
628
+ {account.status === "needs-reauth"
629
+ ? t("meetingsRoute.calendarNeedsReconnectLabel", {
630
+ defaultValue: "Needs reconnect",
631
+ })
632
+ : account.status === "disconnected"
633
+ ? t("meetingsRoute.calendarDisconnectedLabel", {
634
+ defaultValue: "Disconnected",
635
+ })
636
+ : account.status && account.status !== "connected"
637
+ ? t("meetingsRoute.calendarStatusUnavailable", {
638
+ defaultValue: "Status unavailable",
639
+ })
640
+ : t("meetingsRoute.calendarConnectedLabel", {
641
+ defaultValue: "Connected",
642
+ })}
643
+ </span>
606
644
  </div>
607
- <div>{statusText}</div>
608
- </>
609
- ) : (
610
- t("meetingsRoute.connectCalendarReminder")
611
- )}
612
- </div>
645
+ ))}
646
+ </div>
647
+ ) : (
648
+ <div className="px-2 pb-1 text-xs text-muted-foreground">
649
+ {t("meetingsRoute.connectCalendarReminder")}
650
+ </div>
651
+ )}
613
652
  <DropdownMenuSeparator />
653
+ {hasNeedsReconnect && (
654
+ <DropdownMenuItem
655
+ onSelect={(event) => {
656
+ event.preventDefault();
657
+ handleConnect();
658
+ }}
659
+ disabled={connectPending}
660
+ >
661
+ {connectPending ? (
662
+ <IconLoader2 className="me-2 h-4 w-4 animate-spin" />
663
+ ) : (
664
+ <IconExternalLink className="me-2 h-4 w-4" />
665
+ )}
666
+ {t("meetingsRoute.reconnectCalendar", {
667
+ defaultValue: "Reconnect calendar",
668
+ })}
669
+ </DropdownMenuItem>
670
+ )}
614
671
  <DropdownMenuItem
615
672
  onSelect={(event) => {
616
673
  event.preventDefault();
617
- handleReconnect();
674
+ handleConnect();
618
675
  }}
619
676
  disabled={connectPending}
620
677
  >
621
678
  {connectPending ? (
622
679
  <IconLoader2 className="me-2 h-4 w-4 animate-spin" />
623
680
  ) : (
624
- <IconExternalLink className="me-2 h-4 w-4" />
681
+ <IconPlus className="me-2 h-4 w-4" />
625
682
  )}
626
- {primaryAccount ? "Reconnect calendar" : "Connect calendar"}
683
+ {accounts.length > 0
684
+ ? t("meetingsRoute.addAnotherCalendarAccount", {
685
+ defaultValue: "Add another account",
686
+ })
687
+ : t("meetingsRoute.connectCalendar", {
688
+ defaultValue: "Connect calendar",
689
+ })}
627
690
  </DropdownMenuItem>
628
691
  {accounts.length > 0 && (
629
692
  <>
630
693
  <DropdownMenuSeparator />
694
+ <DropdownMenuLabel className="text-[11px] text-muted-foreground">
695
+ {t("meetingsRoute.disconnectCalendarAccount", {
696
+ defaultValue: "Disconnect an account",
697
+ })}
698
+ </DropdownMenuLabel>
631
699
  {accounts.map((account) => (
632
700
  <DropdownMenuItem
633
701
  key={account.id}
@@ -12,8 +12,11 @@ import {
12
12
  useBuilderStatus,
13
13
  type SettingsSearchEntry,
14
14
  } from "@agent-native/core/client/settings";
15
- import type { ClipsDefaultVisibility } from "@shared/clips-ai-prefs";
16
- import { useEffect, useMemo, useState } from "react";
15
+ import {
16
+ DEFAULT_CLIPS_RECORDING_VISIBILITY,
17
+ type ClipsDefaultVisibility,
18
+ } from "@shared/clips-ai-prefs";
19
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
17
20
  import { toast } from "sonner";
18
21
 
19
22
  import { PageHeader } from "@/components/library/page-header";
@@ -101,22 +104,34 @@ export default function SettingsIndexRoute() {
101
104
  const storageStatus = useVideoStorageStatus();
102
105
  const secrets = useSecretStatus();
103
106
  const builderStatus = useBuilderStatus();
107
+ const connectRequestedRef = useRef(false);
104
108
  const builderConnect = useBuilderConnectFlow({
105
109
  popupUrl:
106
110
  builderStatus.status?.cliAuthUrl ?? builderStatus.status?.connectUrl,
107
111
  trackingSource: "clips_settings",
108
112
  trackingFlow: "clips_setup",
109
113
  onConnected: async () => {
114
+ const shouldShowConnectedToast = connectRequestedRef.current;
115
+ connectRequestedRef.current = false;
110
116
  await Promise.all([storageStatus.refetch(), builderStatus.refetch()]);
111
- toast.success(t("settings.builderConnectedToast"));
117
+ if (shouldShowConnectedToast) {
118
+ toast.success(t("settings.builderConnectedToast"));
119
+ }
112
120
  },
113
121
  });
122
+ const startBuilderConnect = useCallback(
123
+ (options?: Parameters<typeof builderConnect.start>[0]) => {
124
+ connectRequestedRef.current = true;
125
+ builderConnect.start(options);
126
+ },
127
+ [builderConnect.start],
128
+ );
114
129
  const [loading, setLoading] = useState(true);
115
130
  const [saving, setSaving] = useState(false);
116
131
  const [defaultSpeed, setDefaultSpeed] = useState("1.2");
117
132
  const [emailNotifications, setEmailNotifications] = useState(true);
118
133
  const [defaultVisibility, setDefaultVisibility] =
119
- useState<ClipsDefaultVisibility>("private");
134
+ useState<ClipsDefaultVisibility>(DEFAULT_CLIPS_RECORDING_VISIBILITY);
120
135
  const [transcriptCleanupEnabled, setTranscriptCleanupEnabled] =
121
136
  useState(true);
122
137
 
@@ -126,7 +141,9 @@ export default function SettingsIndexRoute() {
126
141
  if (cancelled) return;
127
142
  setDefaultSpeed(v.defaultPlaybackSpeed ?? "1.2");
128
143
  setEmailNotifications(v.emailNotifications ?? true);
129
- setDefaultVisibility(v.defaultRecordingVisibility ?? "private");
144
+ setDefaultVisibility(
145
+ v.defaultRecordingVisibility ?? DEFAULT_CLIPS_RECORDING_VISIBILITY,
146
+ );
130
147
  setTranscriptCleanupEnabled(v.transcriptCleanupEnabled !== false);
131
148
  setLoading(false);
132
149
  });
@@ -151,9 +168,9 @@ export default function SettingsIndexRoute() {
151
168
  !builderConnect.hasFetchedStatus,
152
169
  connecting: builderConnect.connecting,
153
170
  orgName: builderConnect.orgName ?? builderStatus.status?.orgName ?? null,
154
- start: builderConnect.start,
171
+ start: startBuilderConnect,
155
172
  }),
156
- [builderConnect, builderStatus, storageStatus],
173
+ [builderConnect, builderStatus, startBuilderConnect, storageStatus],
157
174
  );
158
175
 
159
176
  async function handleUploadWorkspaceChange(organizationId: string) {
@@ -132,11 +132,16 @@ export default function EmbedRoute() {
132
132
  readyMediaPollRef.current = null;
133
133
  return 2000;
134
134
  }
135
+ if (rec.seekableRepairPending === true) {
136
+ readyMediaPollRef.current = null;
137
+ return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
138
+ }
135
139
  const mediaKey = [
136
140
  rec.id,
137
141
  rec.durationMs ?? "",
138
142
  rec.videoSizeBytes ?? "",
139
143
  rec.videoFormat ?? "",
144
+ rec.updatedAt ?? "",
140
145
  ].join(":");
141
146
  const now = Date.now();
142
147
  if (readyMediaPollRef.current?.key !== mediaKey) {
@@ -225,10 +230,9 @@ export default function EmbedRoute() {
225
230
  onVideoElementChange={setTrackedVideoEl}
226
231
  recordingId={recording.id}
227
232
  videoUrl={recording.videoUrl}
228
- mediaVersion={[
229
- recording.videoSizeBytes ?? "",
230
- recording.updatedAt ?? "",
231
- ].join(":")}
233
+ mediaVersion={
234
+ recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
235
+ }
232
236
  videoFormat={recording.videoFormat}
233
237
  embedProvider={isLoomEmbedBacked ? "loom" : null}
234
238
  durationMs={recording.durationMs}
@@ -310,6 +310,10 @@ export default function RecordingPage() {
310
310
  readyMediaPollRef.current = null;
311
311
  return 1000;
312
312
  }
313
+ if (rec.seekableRepairPending === true) {
314
+ readyMediaPollRef.current = null;
315
+ return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
316
+ }
313
317
  // Fresh streaming uploads can become `ready` before the background
314
318
  // seekable/faststart repair swaps in the final player URL. Keep polling
315
319
  // briefly so the first post-recording page catches that URL update
@@ -319,6 +323,7 @@ export default function RecordingPage() {
319
323
  rec.durationMs ?? "",
320
324
  rec.videoSizeBytes ?? "",
321
325
  rec.videoFormat ?? "",
326
+ rec.updatedAt ?? "",
322
327
  ].join(":");
323
328
  const now = Date.now();
324
329
  if (readyMediaPollRef.current?.key !== mediaKey) {
@@ -962,7 +967,7 @@ export default function RecordingPage() {
962
967
  variant="ghost"
963
968
  size="icon"
964
969
  className="shrink-0"
965
- aria-label={t("recordingPage.back")}
970
+ aria-label={t("recordingPage.backToLibrary")}
966
971
  >
967
972
  <Link to="/library" replace>
968
973
  <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
@@ -1305,11 +1310,14 @@ export default function RecordingPage() {
1305
1310
  asChild
1306
1311
  variant="ghost"
1307
1312
  size="icon"
1308
- className="shrink-0"
1309
- aria-label={t("recordingPage.back")}
1313
+ className="shrink-0 sm:w-auto sm:px-2"
1314
+ aria-label={t("recordingPage.backToLibrary")}
1310
1315
  >
1311
1316
  <Link to="/library" replace>
1312
1317
  <IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
1318
+ <span className="hidden sm:inline">
1319
+ {t("recordingPage.backToLibrary")}
1320
+ </span>
1313
1321
  </Link>
1314
1322
  </Button>
1315
1323
  <div className="flex-1 min-w-0">
@@ -1592,10 +1600,9 @@ export default function RecordingPage() {
1592
1600
  onVideoElementChange={setTrackedVideoEl}
1593
1601
  recordingId={recording.id}
1594
1602
  videoUrl={recording.videoUrl}
1595
- mediaVersion={[
1596
- recording.videoSizeBytes ?? "",
1597
- recording.updatedAt ?? "",
1598
- ].join(":")}
1603
+ mediaVersion={
1604
+ recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
1605
+ }
1599
1606
  videoFormat={recording.videoFormat}
1600
1607
  embedProvider={isLoomEmbedBacked ? "loom" : null}
1601
1608
  durationMs={recording.durationMs}
@@ -470,11 +470,16 @@ export default function ShareRoute() {
470
470
  readyMediaPollRef.current = null;
471
471
  return 2000;
472
472
  }
473
+ if (rec.seekableRepairPending === true) {
474
+ readyMediaPollRef.current = null;
475
+ return READY_MEDIA_SETTLE_POLL_INTERVAL_MS;
476
+ }
473
477
  const mediaKey = [
474
478
  rec.id,
475
479
  rec.durationMs ?? "",
476
480
  rec.videoSizeBytes ?? "",
477
481
  rec.videoFormat ?? "",
482
+ rec.updatedAt ?? "",
478
483
  ].join(":");
479
484
  const now = Date.now();
480
485
  if (readyMediaPollRef.current?.key !== mediaKey) {
@@ -1020,10 +1025,9 @@ export default function ShareRoute() {
1020
1025
  onVideoElementChange={setTrackedVideoEl}
1021
1026
  recordingId={recording.id}
1022
1027
  videoUrl={recording.videoUrl}
1023
- mediaVersion={[
1024
- recording.videoSizeBytes ?? "",
1025
- recording.updatedAt ?? "",
1026
- ].join(":")}
1028
+ mediaVersion={
1029
+ recording.mediaUpdatedAt ?? recording.videoSizeBytes ?? null
1030
+ }
1027
1031
  videoFormat={recording.videoFormat}
1028
1032
  embedProvider={isLoomEmbedBacked ? "loom" : null}
1029
1033
  durationMs={recording.durationMs}
@@ -2,7 +2,10 @@ import { appPath } from "@agent-native/core/client/api-path";
2
2
  import { useSession } from "@agent-native/core/client/hooks";
3
3
  import { useT } from "@agent-native/core/client/i18n";
4
4
  import { PoweredByBadge } from "@agent-native/core/client/ui";
5
- import { normalizeDocumentTitle } from "@agent-native/core/shared";
5
+ import {
6
+ AGENT_ACCESS_PARAM,
7
+ normalizeDocumentTitle,
8
+ } from "@agent-native/core/shared";
6
9
  import {
7
10
  IconCalendar,
8
11
  IconCheck,
@@ -16,8 +19,12 @@ import {
16
19
  import { useQuery } from "@tanstack/react-query";
17
20
  import { and, eq, isNull } from "drizzle-orm";
18
21
  import { useEffect, useRef, useState } from "react";
19
- import type { LoaderFunctionArgs, MetaFunction } from "react-router";
20
- import { useLoaderData, useParams } from "react-router";
22
+ import type {
23
+ HeadersArgs,
24
+ LoaderFunctionArgs,
25
+ MetaFunction,
26
+ } from "react-router";
27
+ import { useLoaderData, useParams, useSearchParams } from "react-router";
21
28
  import { toast } from "sonner";
22
29
 
23
30
  import {
@@ -36,15 +43,37 @@ import {
36
43
  } from "@/lib/public-meeting";
37
44
 
38
45
  import { getDb, schema } from "../../server/db";
46
+ import { CLIPS_MEETING_AGENT_RESOURCE_KIND } from "../../shared/meeting-agent-access";
47
+ import { privateShareLoaderData } from "../../shared/share-loader-response";
39
48
 
40
49
  type LoaderData = { meeting: PublicMeeting | null };
41
50
 
42
- export async function loader({
43
- params,
44
- }: LoaderFunctionArgs): Promise<LoaderData> {
51
+ function shareMeetingLoaderData(
52
+ payload: LoaderData,
53
+ privateAgentAccess = false,
54
+ ) {
55
+ return privateAgentAccess ? privateShareLoaderData(payload) : payload;
56
+ }
57
+
58
+ export function headers({ loaderHeaders }: HeadersArgs) {
59
+ return loaderHeaders;
60
+ }
61
+
62
+ export async function loader({ params, url }: LoaderFunctionArgs) {
45
63
  const meetingId = params.meetingId;
46
64
  if (!meetingId) return { meeting: null };
47
65
 
66
+ const { verifyScopedAgentAccessToken } =
67
+ await import("@agent-native/core/server");
68
+ const agentAccessToken = url.searchParams.get(AGENT_ACCESS_PARAM) ?? "";
69
+ const hasAgentAccessToken = Boolean(agentAccessToken);
70
+ const tokenGrantsAgentAccess = agentAccessToken
71
+ ? verifyScopedAgentAccessToken(agentAccessToken, {
72
+ resourceKind: CLIPS_MEETING_AGENT_RESOURCE_KIND,
73
+ resourceId: meetingId,
74
+ }).ok
75
+ : false;
76
+
48
77
  const [meeting] = await getDb()
49
78
  .select({
50
79
  id: schema.meetings.id,
@@ -59,14 +88,21 @@ export async function loader({
59
88
  })
60
89
  .from(schema.meetings)
61
90
  .where(
62
- and(
63
- eq(schema.meetings.id, meetingId),
64
- eq(schema.meetings.visibility, "public"),
65
- isNull(schema.meetings.trashedAt),
66
- ),
91
+ tokenGrantsAgentAccess
92
+ ? and(
93
+ eq(schema.meetings.id, meetingId),
94
+ isNull(schema.meetings.trashedAt),
95
+ )
96
+ : and(
97
+ eq(schema.meetings.id, meetingId),
98
+ eq(schema.meetings.visibility, "public"),
99
+ isNull(schema.meetings.trashedAt),
100
+ ),
67
101
  )
68
102
  .limit(1);
69
- if (!meeting) return { meeting: null };
103
+ if (!meeting) {
104
+ return shareMeetingLoaderData({ meeting: null }, hasAgentAccessToken);
105
+ }
70
106
 
71
107
  const [participants, actionItems] = await Promise.all([
72
108
  getDb()
@@ -101,20 +137,23 @@ export async function loader({
101
137
  }
102
138
  } catch {}
103
139
 
104
- return {
105
- meeting: {
106
- id: meeting.id,
107
- title: meeting.title,
108
- scheduledStart: meeting.scheduledStart,
109
- summaryMd: meeting.summaryMd,
110
- bullets,
111
- participants,
112
- actionItems,
113
- actualStart: meeting.actualStart,
114
- actualEnd: meeting.actualEnd,
115
- transcriptStatus: meeting.transcriptStatus,
140
+ return shareMeetingLoaderData(
141
+ {
142
+ meeting: {
143
+ id: meeting.id,
144
+ title: meeting.title,
145
+ scheduledStart: meeting.scheduledStart,
146
+ summaryMd: meeting.summaryMd,
147
+ bullets,
148
+ participants,
149
+ actionItems,
150
+ actualStart: meeting.actualStart,
151
+ actualEnd: meeting.actualEnd,
152
+ transcriptStatus: meeting.transcriptStatus,
153
+ },
116
154
  },
117
- };
155
+ hasAgentAccessToken,
156
+ );
118
157
  }
119
158
 
120
159
  export const meta: MetaFunction<typeof loader> = ({ loaderData }) => {
@@ -197,7 +236,9 @@ export default function ShareMeetingRoute() {
197
236
  const t = useT();
198
237
  const loaderData = useLoaderData<LoaderData>();
199
238
  const { meetingId } = useParams<{ meetingId: string }>();
239
+ const [searchParams] = useSearchParams();
200
240
  const { session, isLoading: sessionLoading } = useSession();
241
+ const agentAccessToken = searchParams.get(AGENT_ACCESS_PARAM) ?? "";
201
242
  const pollingStartedAtRef = useRef<number | null>(null);
202
243
  const [transcriptCopied, setTranscriptCopied] = useState(false);
203
244
  const initialMeetingResult: PublicMeetingResult | undefined =
@@ -215,8 +256,13 @@ export default function ShareMeetingRoute() {
215
256
  meetingId,
216
257
  session?.email ?? null,
217
258
  session?.orgId ?? null,
259
+ agentAccessToken,
218
260
  ],
219
- queryFn: ({ signal }) => fetchPublicMeeting(meetingId ?? "", { signal }),
261
+ queryFn: ({ signal }) =>
262
+ fetchPublicMeeting(meetingId ?? "", {
263
+ signal,
264
+ agentAccessToken,
265
+ }),
220
266
  enabled: !!meetingId && !sessionLoading,
221
267
  initialData: initialMeetingResult,
222
268
  refetchInterval: (query) => {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ Comments now render inline Markdown for emphasis, inline code, links, and line breaks while keeping headings out of compact comment surfaces.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-08-13
4
+ ---
5
+
6
+ Private meeting notes can be shared with an external agent through a temporary link.