@agent-native/core 0.157.5 → 0.157.6
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.
- package/corpus/README.md +1 -1
- package/corpus/templates/clips/actions/create-meeting.ts +19 -1
- package/corpus/templates/clips/app/components/meetings/bullet-link.tsx +48 -25
- package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +7 -6
- package/corpus/templates/clips/app/components/meetings/transcript-bubbles.tsx +388 -178
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +7 -13
- package/corpus/templates/clips/app/components/transcript/transcript-segment-row.tsx +98 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +4 -0
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +49 -31
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +15 -1
- package/corpus/templates/clips/netlify.toml +4 -4
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +10 -0
- package/corpus/templates/clips/shared/transcript-segments.ts +20 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +28 -11
- package/dist/notifications/routes.d.ts +1 -1
- package/package.json +3 -3
package/corpus/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { defineAction } from "@agent-native/core";
|
|
11
11
|
import { writeAppState } from "@agent-native/core/application-state";
|
|
12
|
+
import { getRequestUserName } from "@agent-native/core/server/request-context";
|
|
12
13
|
import { resolveAccess } from "@agent-native/core/sharing";
|
|
13
14
|
import { and, eq, isNull } from "drizzle-orm";
|
|
14
15
|
import { z } from "zod";
|
|
@@ -93,7 +94,7 @@ export default defineAction({
|
|
|
93
94
|
email: string;
|
|
94
95
|
name?: string;
|
|
95
96
|
isOrganizer?: boolean;
|
|
96
|
-
}> = args.participants ?? [];
|
|
97
|
+
}> = [...(args.participants ?? [])];
|
|
97
98
|
let calendarEventIdLink: string | null = null;
|
|
98
99
|
let source: "calendar" | "adhoc" | "manual" =
|
|
99
100
|
args.source ?? (args.title ? "manual" : "adhoc");
|
|
@@ -190,6 +191,23 @@ export default defineAction({
|
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
|
|
194
|
+
// Backfill a missing display name onto the owner's own attendee row —
|
|
195
|
+
// but only when they're already a genuine calendar attendee. Inserting
|
|
196
|
+
// a synthetic row for a non-attendee owner would put their email in
|
|
197
|
+
// meeting_participants indistinguishably from a real attendee, and that
|
|
198
|
+
// table is what the public share payload returns; a meeting made public
|
|
199
|
+
// later would leak an email the owner never actually disclosed. When the
|
|
200
|
+
// owner isn't an attendee, speaker resolution already has a safe
|
|
201
|
+
// fallback (the generic "Me" label) — no snapshot needed for that case.
|
|
202
|
+
const ownerName = getRequestUserName()?.trim() || undefined;
|
|
203
|
+
const ownerParticipant = participantsToInsert.find(
|
|
204
|
+
(participant) =>
|
|
205
|
+
participant.email.trim().toLowerCase() === ownerEmail.toLowerCase(),
|
|
206
|
+
);
|
|
207
|
+
if (ownerParticipant && !ownerParticipant.name?.trim() && ownerName) {
|
|
208
|
+
ownerParticipant.name = ownerName;
|
|
209
|
+
}
|
|
210
|
+
|
|
193
211
|
const visibility =
|
|
194
212
|
args.visibility ??
|
|
195
213
|
(await getDefaultRecordingVisibility(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@/components/ui/tooltip";
|
|
10
10
|
import { cn } from "@/lib/utils";
|
|
11
11
|
|
|
12
|
+
import { formatTranscriptTimestamp } from "../transcript/transcript-segment-row";
|
|
12
13
|
import type { TranscriptSegment } from "./transcript-bubbles";
|
|
13
14
|
|
|
14
15
|
const STOPWORDS = new Set<string>([
|
|
@@ -129,39 +130,61 @@ export function BulletLink({
|
|
|
129
130
|
onJumpTo,
|
|
130
131
|
children,
|
|
131
132
|
}: BulletLinkProps) {
|
|
133
|
+
const t = useT();
|
|
132
134
|
const matchIndex = useMemo(
|
|
133
135
|
() => findBestSegmentMatch(bullet, segments),
|
|
134
136
|
[bullet, segments],
|
|
135
137
|
);
|
|
136
138
|
const hasMatch = matchIndex >= 0;
|
|
139
|
+
const timestamp = hasMatch
|
|
140
|
+
? formatTranscriptTimestamp(segments[matchIndex]!.startMs)
|
|
141
|
+
: null;
|
|
137
142
|
|
|
138
143
|
return (
|
|
139
144
|
<TooltipProvider delayDuration={200}>
|
|
140
145
|
<div className="group flex items-start gap-1.5">
|
|
141
|
-
<div className="flex
|
|
142
|
-
|
|
143
|
-
<
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
</
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
</
|
|
164
|
-
|
|
146
|
+
<div className="flex min-w-0 flex-1">{children}</div>
|
|
147
|
+
{timestamp ? (
|
|
148
|
+
<Tooltip>
|
|
149
|
+
<TooltipTrigger asChild>
|
|
150
|
+
<button
|
|
151
|
+
type="button"
|
|
152
|
+
onClick={() => onJumpTo(matchIndex)}
|
|
153
|
+
aria-label={t("bulletLink.jumpToTranscript", {
|
|
154
|
+
time: timestamp,
|
|
155
|
+
})}
|
|
156
|
+
className={cn(
|
|
157
|
+
"mt-0.5 inline-flex h-5 shrink-0 items-center rounded px-1 font-mono text-[10px] tabular-nums text-muted-foreground/80 opacity-0 transition-opacity",
|
|
158
|
+
"group-hover:opacity-100 [@media(hover:none)]:opacity-100",
|
|
159
|
+
"cursor-pointer hover:bg-accent hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
160
|
+
)}
|
|
161
|
+
>
|
|
162
|
+
{timestamp}
|
|
163
|
+
</button>
|
|
164
|
+
</TooltipTrigger>
|
|
165
|
+
<TooltipContent side="top">
|
|
166
|
+
{t("bulletLink.jumpToTranscript", { time: timestamp })}
|
|
167
|
+
</TooltipContent>
|
|
168
|
+
</Tooltip>
|
|
169
|
+
) : (
|
|
170
|
+
<Tooltip>
|
|
171
|
+
<TooltipTrigger asChild>
|
|
172
|
+
{/* A span, not a button — there's no action to disable, just
|
|
173
|
+
a status to announce, and tabIndex keeps it keyboard- and
|
|
174
|
+
screen-reader-reachable (a disabled button wouldn't be). */}
|
|
175
|
+
<span
|
|
176
|
+
tabIndex={0}
|
|
177
|
+
aria-label={t("bulletLink.noMatchingMoment")}
|
|
178
|
+
className="mt-0.5 inline-flex h-5 shrink-0 cursor-default items-center rounded px-1 font-mono text-[10px] tabular-nums text-muted-foreground/40 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 [@media(hover:none)]:opacity-100"
|
|
179
|
+
>
|
|
180
|
+
--:--
|
|
181
|
+
</span>
|
|
182
|
+
</TooltipTrigger>
|
|
183
|
+
<TooltipContent side="top">
|
|
184
|
+
{t("bulletLink.noMatchingMoment")}
|
|
185
|
+
</TooltipContent>
|
|
186
|
+
</Tooltip>
|
|
187
|
+
)}
|
|
165
188
|
</div>
|
|
166
189
|
</TooltipProvider>
|
|
167
190
|
);
|
|
@@ -29,9 +29,10 @@ interface CanvasEditorProps {
|
|
|
29
29
|
userNotesMd?: string;
|
|
30
30
|
/** Save user notes. Called on blur after edit. */
|
|
31
31
|
onUserNotesChange?: (next: string) => void;
|
|
32
|
-
/** AI-generated summary
|
|
32
|
+
/** AI-generated summary — primary content, so it renders full-strength
|
|
33
|
+
* foreground like user notes. For the "ai" view. */
|
|
33
34
|
summaryMd?: string;
|
|
34
|
-
/** AI-generated bullets
|
|
35
|
+
/** AI-generated bullets — same weight as the summary. For the "ai" view. */
|
|
35
36
|
bullets?: string[];
|
|
36
37
|
/** Save AI summary when the user edits the summary section. */
|
|
37
38
|
onSummaryChange?: (next: string) => void;
|
|
@@ -76,7 +77,7 @@ export function CanvasEditor({
|
|
|
76
77
|
/>
|
|
77
78
|
)}
|
|
78
79
|
|
|
79
|
-
{/* AI bullets —
|
|
80
|
+
{/* AI bullets — with optional BulletLink wrappers */}
|
|
80
81
|
{showAi && bullets.length > 0 && (
|
|
81
82
|
<AiBulletsBlock bullets={bullets} renderBullet={renderBullet} />
|
|
82
83
|
)}
|
|
@@ -181,7 +182,7 @@ function AiSummaryBlock({
|
|
|
181
182
|
return (
|
|
182
183
|
<div className="space-y-1.5">
|
|
183
184
|
<AiTabIndicator />
|
|
184
|
-
<p className="text-sm leading-relaxed whitespace-pre-wrap text-
|
|
185
|
+
<p className="text-sm leading-relaxed whitespace-pre-wrap text-foreground">
|
|
185
186
|
{value}
|
|
186
187
|
</p>
|
|
187
188
|
</div>
|
|
@@ -234,7 +235,7 @@ function AiSummaryBlock({
|
|
|
234
235
|
>
|
|
235
236
|
<p
|
|
236
237
|
className={cn(
|
|
237
|
-
"text-sm leading-relaxed whitespace-pre-wrap text-
|
|
238
|
+
"text-sm leading-relaxed whitespace-pre-wrap text-foreground rounded -mx-1 px-1 group-hover:bg-accent/30",
|
|
238
239
|
)}
|
|
239
240
|
>
|
|
240
241
|
{value}
|
|
@@ -263,7 +264,7 @@ function AiBulletsBlock({
|
|
|
263
264
|
<ul className="space-y-1.5">
|
|
264
265
|
{bullets.map((b, i) => {
|
|
265
266
|
const content = (
|
|
266
|
-
<div className="flex gap-2 text-sm leading-relaxed text-
|
|
267
|
+
<div className="flex gap-2 text-sm leading-relaxed text-foreground">
|
|
267
268
|
<span>•</span>
|
|
268
269
|
<span className="flex-1">{b}</span>
|
|
269
270
|
</div>
|