@agent-native/core 0.159.2 → 0.159.5

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/templates/clips/.agents/skills/meetings/SKILL.md +11 -6
  3. package/corpus/templates/clips/AGENTS.md +1 -0
  4. package/corpus/templates/clips/actions/lib/meeting-content.ts +15 -4
  5. package/corpus/templates/clips/actions/list-meetings.ts +179 -42
  6. package/corpus/templates/clips/actions/search-meetings.ts +277 -0
  7. package/corpus/templates/clips/app/components/meetings/agenda-card.tsx +273 -0
  8. package/corpus/templates/clips/app/components/meetings/day-grouped-card.tsx +113 -0
  9. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +117 -0
  10. package/corpus/templates/clips/app/hooks/use-navigation-state.ts +12 -2
  11. package/corpus/templates/clips/app/i18n/en-US.ts +7 -2
  12. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +263 -357
  13. package/corpus/templates/clips/changelog/2026-08-14-meetings-history-is-searchable-again.md +6 -0
  14. package/corpus/templates/clips/desktop/design-refs/granola-ux.md +17 -0
  15. package/corpus/templates/content/actions/_database-source-utils.ts +29 -2
  16. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +11 -11
  17. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +11 -50
  18. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +57 -20
  19. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +30 -0
  20. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +204 -51
  21. package/corpus/templates/content/app/global.css +4 -1
  22. package/corpus/templates/content/app/i18n-data.ts +30 -0
  23. package/corpus/templates/content/changelog/2026-08-12-toggle-blocks-now-follow-notion-style-enter-and-shift-tab-be.md +6 -0
  24. package/corpus/templates/content/docs/solutions/2026-08-12-toggle-summary-focus-persistence-shape.md +733 -0
  25. package/corpus/templates/content/shared/builder-mdx.ts +44 -4
  26. package/corpus/templates/slides/actions/get-layout-overflows.ts +65 -2
  27. package/dist/client/chat-first/app-pane.js +1 -1
  28. package/dist/client/chat-first/copy.js +1 -0
  29. package/dist/collab/awareness.d.ts +2 -2
  30. package/dist/collab/struct-routes.d.ts +1 -1
  31. package/dist/deploy/build.d.ts +6 -4
  32. package/dist/deploy/build.js +27 -11
  33. package/dist/feature-flags/index.d.ts +0 -2
  34. package/dist/feature-flags/index.js +3 -2
  35. package/dist/feature-flags/server.d.ts +2 -0
  36. package/dist/feature-flags/server.js +2 -0
  37. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  38. package/dist/index.d.ts +2 -1
  39. package/dist/index.js +2 -1
  40. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  41. package/dist/notifications/routes.d.ts +6 -6
  42. package/dist/observability/routes.d.ts +5 -5
  43. package/dist/progress/routes.d.ts +1 -1
  44. package/dist/provider-api/actions/custom-provider-registration.d.ts +2 -2
  45. package/dist/secrets/routes.d.ts +9 -9
  46. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  47. package/dist/server/auth.js +10 -0
  48. package/dist/server/index.d.ts +1 -1
  49. package/dist/server/index.js +1 -1
  50. package/dist/server/onboarding-html.js +16 -257
  51. package/dist/shared/auth-copy.d.ts +34 -0
  52. package/dist/shared/auth-copy.js +293 -0
  53. package/dist/shared/index.d.ts +1 -0
  54. package/dist/shared/index.js +1 -0
  55. package/docs/content/actions-advanced.mdx +1 -1
  56. package/docs/content/portal.mdx +21 -8
  57. package/package.json +4 -2
  58. package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +0 -333
@@ -1,333 +0,0 @@
1
- import { useT } from "@agent-native/core/client/i18n";
2
- import {
3
- IconCheck,
4
- IconClock,
5
- IconExternalLink,
6
- IconNotes,
7
- IconVideo,
8
- } from "@tabler/icons-react";
9
- /**
10
- * <MeetingCard /> — Granola-style meeting tile.
11
- *
12
- * Renders title, time, attendee stack, status pills (Live / Transcript ready
13
- * / Notes ready), and a 1-2 line summary preview. Hover lifts the card.
14
- */
15
- import { NavLink } from "react-router";
16
-
17
- import { Badge } from "@/components/ui/badge";
18
- import { Button } from "@/components/ui/button";
19
- import { Card, CardContent } from "@/components/ui/card";
20
- import { cn } from "@/lib/utils";
21
-
22
- import { AttendeeStack, type AttendeeStackParticipant } from "./attendee-stack";
23
-
24
- export interface MeetingCardData {
25
- id: string;
26
- title: string;
27
- scheduledStart: string;
28
- scheduledEnd?: string | null;
29
- actualStart?: string | null;
30
- actualEnd?: string | null;
31
- recordingId?: string | null;
32
- transcriptStatus?:
33
- | "pending"
34
- | "ready"
35
- | "failed"
36
- | "in_progress"
37
- | string
38
- | null;
39
- summaryPreview?: string | null;
40
- summaryMd?: string | null;
41
- participants?: AttendeeStackParticipant[];
42
- }
43
-
44
- type Translate = (key: string, params?: Record<string, unknown>) => string;
45
-
46
- function formatTime(iso?: string | null): string {
47
- if (!iso) return "";
48
- try {
49
- return new Date(iso).toLocaleTimeString([], {
50
- hour: "numeric",
51
- minute: "2-digit",
52
- });
53
- } catch {
54
- return "";
55
- }
56
- }
57
-
58
- function buildPreview(m: MeetingCardData): string | null {
59
- if (m.summaryPreview && m.summaryPreview.trim()) return m.summaryPreview;
60
- if (m.summaryMd && m.summaryMd.trim()) {
61
- // Strip simple markdown markers and collapse whitespace for the preview.
62
- const plain = m.summaryMd
63
- .replace(/[#*`>_~-]+/g, " ")
64
- .replace(/\s+/g, " ")
65
- .trim();
66
- return plain.slice(0, 220);
67
- }
68
- return null;
69
- }
70
-
71
- export function MeetingCard({ meeting }: { meeting: MeetingCardData }) {
72
- const t = useT();
73
- const isLive = !!(
74
- (meeting.actualStart && !meeting.actualEnd) ||
75
- meeting.transcriptStatus === "in_progress"
76
- );
77
- const transcriptReady = meeting.transcriptStatus === "ready";
78
- const hasNotes = !!meeting.summaryMd;
79
- const preview = buildPreview(meeting);
80
- const now = Date.now();
81
- const scheduledEndMs = Date.parse(
82
- meeting.scheduledEnd ?? meeting.scheduledStart,
83
- );
84
- const meetingHasEnded =
85
- !!meeting.actualEnd ||
86
- (!Number.isNaN(scheduledEndMs) && scheduledEndMs < now);
87
- const shouldShowMissingSummary =
88
- !preview &&
89
- (meetingHasEnded || !!meeting.recordingId || transcriptReady || isLive);
90
-
91
- return (
92
- <NavLink
93
- to={`/meetings/${meeting.id}`}
94
- className="group block focus:outline-none"
95
- >
96
- <Card
97
- className={cn(
98
- "cursor-pointer transition-[transform,box-shadow,border-color] duration-150",
99
- "hover:border-foreground/20 hover:shadow-sm hover:-translate-y-px",
100
- "bg-background",
101
- )}
102
- >
103
- <CardContent className="p-4 space-y-2.5">
104
- <div className="flex items-start justify-between gap-2">
105
- <h3 className="text-sm font-medium leading-snug line-clamp-2 flex-1 text-foreground">
106
- {meeting.title || t("meetingDetail.untitledMeeting")}
107
- </h3>
108
- <div className="flex items-center gap-1 shrink-0">
109
- {isLive ? (
110
- <Badge
111
- variant="secondary"
112
- className="bg-red-500/10 text-red-600 border-red-500/20 text-[10px] gap-1 font-medium px-1.5"
113
- >
114
- <span className="relative flex h-1.5 w-1.5">
115
- <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-60" />
116
- <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-red-500" />
117
- </span>
118
- {t("meetingCard.live")}
119
- </Badge>
120
- ) : transcriptReady ? (
121
- <Badge
122
- variant="secondary"
123
- className="bg-emerald-500/10 text-emerald-600 border-emerald-500/20 text-[10px] gap-1 px-1.5"
124
- >
125
- <IconCheck className="h-3 w-3" />
126
- {t("meetingCard.transcript")}
127
- </Badge>
128
- ) : null}
129
- {hasNotes && !isLive && (
130
- <Badge
131
- variant="secondary"
132
- className="bg-amber-500/10 text-amber-700 border-amber-500/20 text-[10px] gap-1 px-1.5"
133
- title={t("meetingCard.aiNotesReady")}
134
- >
135
- <IconNotes className="h-3 w-3" />
136
- </Badge>
137
- )}
138
- </div>
139
- </div>
140
-
141
- <div className="flex items-center gap-1.5 text-xs text-muted-foreground tabular-nums">
142
- <IconClock className="h-3.5 w-3.5" />
143
- <span>{formatTime(meeting.scheduledStart)}</span>
144
- {meeting.scheduledEnd && (
145
- <span>– {formatTime(meeting.scheduledEnd)}</span>
146
- )}
147
- </div>
148
-
149
- {preview ? (
150
- <p className="text-xs text-muted-foreground leading-relaxed line-clamp-2">
151
- {preview}
152
- </p>
153
- ) : shouldShowMissingSummary ? (
154
- <p className="text-xs text-muted-foreground/60 italic leading-relaxed">
155
- {t("meetingCard.noSummary")}
156
- </p>
157
- ) : null}
158
-
159
- <div className="flex items-center justify-between gap-2 pt-1">
160
- <AttendeeStack
161
- participants={meeting.participants ?? []}
162
- size="xs"
163
- />
164
- {meeting.recordingId && (
165
- <span className="flex items-center gap-1 text-[10px] text-muted-foreground">
166
- <IconVideo className="h-3 w-3" />
167
- {t("meetingCard.transcriptSource")}
168
- </span>
169
- )}
170
- </div>
171
- </CardContent>
172
- </Card>
173
- </NavLink>
174
- );
175
- }
176
-
177
- export interface UpcomingMeetingCardData {
178
- id: string;
179
- title: string;
180
- scheduledStart: string;
181
- scheduledEnd?: string | null;
182
- actualStart?: string | null;
183
- actualEnd?: string | null;
184
- joinUrl?: string | null;
185
- platform?: string | null;
186
- participants?: AttendeeStackParticipant[];
187
- }
188
-
189
- /** Human "starts in 5 min" / "now" / "in 2 hrs" label for an upcoming card. */
190
- function relativeStartLabel(
191
- iso: string,
192
- t: Translate,
193
- ): { text: string; soon: boolean } {
194
- const start = Date.parse(iso);
195
- if (Number.isNaN(start)) return { text: "", soon: false };
196
- const diffMin = Math.round((start - Date.now()) / 60000);
197
- if (diffMin <= 0 && diffMin > -120)
198
- return { text: t("meetingCard.now"), soon: true };
199
- if (diffMin <= 0) return { text: t("meetingCard.started"), soon: false };
200
- if (diffMin < 60)
201
- return {
202
- text: t("meetingCard.inMinutes", { count: diffMin }),
203
- soon: diffMin <= 5,
204
- };
205
- const hrs = Math.round(diffMin / 60);
206
- return { text: t("meetingCard.inHours", { count: hrs }), soon: false };
207
- }
208
-
209
- /**
210
- * <UpcomingMeetingCard /> — a not-yet-recorded calendar event (Granola-style).
211
- * Recording is a native Clips desktop-app gesture, so the card just opens the
212
- * meeting's notes ("Open notes") and links out to the call ("Join"). Buttons are
213
- * NavLink/<a> siblings (never nested anchors) so the markup stays valid.
214
- */
215
- export function UpcomingMeetingCard({
216
- meeting,
217
- }: {
218
- meeting: UpcomingMeetingCardData;
219
- }) {
220
- const t = useT();
221
- const isLive = !!(meeting.actualStart && !meeting.actualEnd);
222
- const { text: whenText, soon } = relativeStartLabel(
223
- meeting.scheduledStart,
224
- t,
225
- );
226
- const joinable = soon || isLive;
227
-
228
- return (
229
- <Card
230
- className={cn(
231
- "transition-[transform,box-shadow,border-color] duration-150 hover:border-foreground/20 hover:shadow-sm",
232
- joinable && "border-foreground/25",
233
- )}
234
- >
235
- <CardContent className="p-4 space-y-2.5">
236
- <NavLink
237
- to={`/meetings/${meeting.id}`}
238
- className="block group focus:outline-none"
239
- >
240
- <div className="flex items-start justify-between gap-2">
241
- <h3 className="text-sm font-medium leading-snug line-clamp-2 flex-1 text-foreground group-hover:text-foreground">
242
- {meeting.title || t("meetingDetail.untitledMeeting")}
243
- </h3>
244
- {isLive ? (
245
- <Badge
246
- variant="secondary"
247
- className="bg-red-500/10 text-red-600 border-red-500/20 text-[10px] gap-1 font-medium px-1.5 shrink-0"
248
- >
249
- <span className="relative flex h-1.5 w-1.5">
250
- <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-60" />
251
- <span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-red-500" />
252
- </span>
253
- {t("meetingCard.live")}
254
- </Badge>
255
- ) : (
256
- <span
257
- className={cn(
258
- "shrink-0 text-[11px] tabular-nums",
259
- soon
260
- ? "text-foreground font-medium"
261
- : "text-muted-foreground",
262
- )}
263
- >
264
- {whenText}
265
- </span>
266
- )}
267
- </div>
268
- <div className="mt-1.5 flex items-center gap-1.5 text-xs text-muted-foreground tabular-nums">
269
- <IconClock className="h-3.5 w-3.5" />
270
- <span>{formatTime(meeting.scheduledStart)}</span>
271
- {meeting.scheduledEnd && (
272
- <span>– {formatTime(meeting.scheduledEnd)}</span>
273
- )}
274
- </div>
275
- <p className="mt-1.5 text-[11px] leading-snug text-muted-foreground">
276
- {soon || isLive
277
- ? t("meetingCard.startFromDesktopNow")
278
- : t("meetingCard.startFromDesktopLater")}
279
- </p>
280
- </NavLink>
281
-
282
- <div className="flex items-center justify-between gap-2 pt-1">
283
- <AttendeeStack participants={meeting.participants ?? []} size="xs" />
284
- <div className="flex items-center gap-1.5">
285
- {meeting.joinUrl && (
286
- <a
287
- href={meeting.joinUrl}
288
- target="_blank"
289
- rel="noopener noreferrer"
290
- onClick={(e) => e.stopPropagation()}
291
- >
292
- <Button
293
- size="sm"
294
- variant="outline"
295
- className="h-7 gap-1 px-2 text-xs cursor-pointer"
296
- tabIndex={-1}
297
- >
298
- <IconExternalLink className="h-3.5 w-3.5" />
299
- {t("meetingCard.join")}
300
- </Button>
301
- </a>
302
- )}
303
- <Button
304
- asChild
305
- size="sm"
306
- variant={isLive ? "default" : "secondary"}
307
- className="h-7 gap-1 px-2.5 text-xs cursor-pointer"
308
- >
309
- <NavLink to={`/meetings/${meeting.id}`}>
310
- {t("meetingCard.openNotes")}
311
- </NavLink>
312
- </Button>
313
- </div>
314
- </div>
315
- </CardContent>
316
- </Card>
317
- );
318
- }
319
-
320
- export function MeetingCardSkeleton() {
321
- return (
322
- <div className="rounded-xl border border-border bg-background p-4 space-y-2.5">
323
- <div className="h-4 w-3/4 rounded bg-muted animate-pulse" />
324
- <div className="h-3 w-24 rounded bg-muted animate-pulse" />
325
- <div className="h-3 w-full rounded bg-muted/70 animate-pulse" />
326
- <div className="h-3 w-5/6 rounded bg-muted/70 animate-pulse" />
327
- <div className="flex justify-between pt-1">
328
- <div className="h-5 w-20 rounded-full bg-muted animate-pulse" />
329
- <div className="h-3 w-16 rounded bg-muted animate-pulse" />
330
- </div>
331
- </div>
332
- );
333
- }