@agent-native/core 0.161.17 → 0.161.22

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 (176) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/adding-a-feature/SKILL.md +10 -0
  3. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +29 -2
  5. package/corpus/templates/analytics/AGENTS.md +1 -0
  6. package/corpus/templates/analytics/server/plugins/auth.ts +4 -0
  7. package/corpus/templates/assets/.agents/skills/adding-a-feature/SKILL.md +10 -0
  8. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  9. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +29 -2
  10. package/corpus/templates/assets/AGENTS.md +1 -0
  11. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +10 -0
  12. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  13. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +29 -2
  14. package/corpus/templates/brain/AGENTS.md +1 -0
  15. package/corpus/templates/calendar/.agents/skills/adding-a-feature/SKILL.md +10 -0
  16. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  17. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +29 -2
  18. package/corpus/templates/calendar/AGENTS.md +1 -0
  19. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  20. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  21. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  22. package/corpus/templates/chat/AGENTS.md +4 -0
  23. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  24. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +29 -2
  25. package/corpus/templates/clips/AGENTS.md +1 -0
  26. package/corpus/templates/clips/actions/finalize-meeting.ts +57 -21
  27. package/corpus/templates/clips/actions/get-meeting.ts +11 -3
  28. package/corpus/templates/clips/actions/request-transcript.ts +183 -8
  29. package/corpus/templates/clips/actions/update-meeting.ts +66 -14
  30. package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +80 -135
  31. package/corpus/templates/clips/app/components/player/video-player.tsx +4 -0
  32. package/corpus/templates/clips/app/hooks/use-playback-position.ts +10 -2
  33. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  34. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +470 -35
  35. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +1 -0
  36. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +26 -25
  37. package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -0
  38. package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-opens-welcome-window-on-first-launch.md +6 -0
  39. package/corpus/templates/clips/changelog/2026-08-18-meeting-notes-support-rich-editing-for-personal-notes-summar.md +6 -0
  40. package/corpus/templates/clips/changelog/2026-08-18-pending-recording-files-now-use-a-clips-prefixed-name.md +6 -0
  41. package/corpus/templates/clips/desktop/src/main.tsx +0 -3
  42. package/corpus/templates/clips/desktop/src/shared/config.ts +0 -1
  43. package/corpus/templates/clips/desktop/src/styles.css +0 -118
  44. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +0 -1
  45. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +0 -45
  46. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +1 -4
  47. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +0 -10
  48. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +57 -5
  49. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +13 -3
  50. package/corpus/templates/content/.agents/skills/adding-a-feature/SKILL.md +10 -0
  51. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  52. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +29 -2
  53. package/corpus/templates/content/AGENTS.md +1 -0
  54. package/corpus/templates/crm/.agents/skills/adding-a-feature/SKILL.md +10 -0
  55. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  56. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +29 -2
  57. package/corpus/templates/crm/AGENTS.md +1 -0
  58. package/corpus/templates/design/.agents/skills/adding-a-feature/SKILL.md +10 -0
  59. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  60. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +29 -2
  61. package/corpus/templates/design/AGENTS.md +1 -0
  62. package/corpus/templates/design/app/i18n-data.ts +11 -0
  63. package/corpus/templates/design/app/lib/agent-chat.ts +9 -8
  64. package/corpus/templates/dispatch/.agents/skills/adding-a-feature/SKILL.md +10 -0
  65. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  66. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +29 -2
  67. package/corpus/templates/dispatch/AGENTS.md +5 -5
  68. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +10 -0
  69. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  70. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +29 -2
  71. package/corpus/templates/factory/AGENTS.md +1 -0
  72. package/corpus/templates/forms/.agents/skills/adding-a-feature/SKILL.md +10 -0
  73. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  74. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +29 -2
  75. package/corpus/templates/forms/AGENTS.md +1 -0
  76. package/corpus/templates/macros/.agents/skills/adding-a-feature/SKILL.md +10 -0
  77. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  78. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +29 -2
  79. package/corpus/templates/macros/AGENTS.md +1 -0
  80. package/corpus/templates/mail/.agents/skills/adding-a-feature/SKILL.md +10 -0
  81. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  82. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +29 -2
  83. package/corpus/templates/mail/AGENTS.md +1 -0
  84. package/corpus/templates/mail/app/components/email/EmailList.tsx +74 -22
  85. package/corpus/templates/mail/app/components/email/infinite-pagination.ts +82 -0
  86. package/corpus/templates/mail/app/hooks/use-emails.ts +1 -0
  87. package/corpus/templates/mail/app/pages/InboxPage.tsx +15 -10
  88. package/corpus/templates/mail/app/pages/inbox-zero.ts +35 -0
  89. package/corpus/templates/mail/changelog/2026-08-18-pinned-labels-load-matches.md +6 -0
  90. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +10 -0
  91. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  92. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +29 -2
  93. package/corpus/templates/plan/AGENTS.md +1 -0
  94. package/corpus/templates/slides/.agents/skills/adding-a-feature/SKILL.md +10 -0
  95. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  96. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +29 -2
  97. package/corpus/templates/slides/AGENTS.md +2 -1
  98. package/corpus/templates/slides/actions/get-deck.ts +5 -1
  99. package/corpus/templates/slides/actions/list-decks.ts +29 -8
  100. package/corpus/templates/slides/actions/view-screen.ts +7 -3
  101. package/corpus/templates/slides/changelog/2026-08-18-decks-appear-under-mine.md +6 -0
  102. package/corpus/templates/slides/shared/ownership.ts +6 -0
  103. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +10 -0
  104. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  105. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +29 -2
  106. package/corpus/templates/tasks/AGENTS.md +1 -0
  107. package/dist/action.js +43 -1
  108. package/dist/app-config/schema.d.ts +2 -0
  109. package/dist/app-config/workspace.d.ts +2 -0
  110. package/dist/app-config/workspace.js +18 -0
  111. package/dist/catalog.json +23 -23
  112. package/dist/client/analytics.d.ts +1 -0
  113. package/dist/client/api-path.js +7 -3
  114. package/dist/client/chat/run-recovery.js +1 -1
  115. package/dist/client/frame.js +20 -6
  116. package/dist/client/org/workspace-app-links.js +10 -1
  117. package/dist/client/route-state.js +17 -13
  118. package/dist/collab/awareness.d.ts +2 -2
  119. package/dist/collab/routes.d.ts +1 -1
  120. package/dist/collab/struct-routes.d.ts +1 -1
  121. package/dist/deploy/build.js +26 -2
  122. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  123. package/dist/notifications/routes.d.ts +1 -1
  124. package/dist/observability/routes.d.ts +5 -5
  125. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  126. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  127. package/dist/secrets/routes.d.ts +9 -9
  128. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  129. package/dist/server/app-origin-config.d.ts +1 -0
  130. package/dist/server/app-origin-config.js +3 -0
  131. package/dist/server/auth.d.ts +6 -0
  132. package/dist/server/auth.js +25 -7
  133. package/dist/server/cookie-namespace.js +17 -2
  134. package/dist/server/credential-provider.js +5 -2
  135. package/dist/server/derived-secret.js +3 -2
  136. package/dist/server/onboarding-html.js +34 -2
  137. package/dist/server/workspace-oauth.js +11 -6
  138. package/dist/shared/runtime-config.d.ts +2 -0
  139. package/dist/shared/runtime-config.js +12 -3
  140. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  141. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  142. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  143. package/dist/templates/chat/AGENTS.md +4 -0
  144. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
  145. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  146. package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -2
  147. package/dist/templates/default/AGENTS.md +4 -0
  148. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  149. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
  150. package/dist/templates/headless/AGENTS.md +4 -0
  151. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
  152. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  153. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
  154. package/dist/templates/workspace-core/AGENTS.md +4 -0
  155. package/dist/templates/workspace-root/AGENTS.md +9 -0
  156. package/dist/vite/client.js +5 -2
  157. package/docs/content/deployment.mdx +70 -0
  158. package/docs/content/faq.mdx +1 -1
  159. package/package.json +2 -2
  160. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  161. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  162. package/src/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  163. package/src/templates/chat/AGENTS.md +4 -0
  164. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
  165. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  166. package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -2
  167. package/src/templates/default/AGENTS.md +4 -0
  168. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  169. package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
  170. package/src/templates/headless/AGENTS.md +4 -0
  171. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
  172. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  173. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
  174. package/src/templates/workspace-core/AGENTS.md +4 -0
  175. package/src/templates/workspace-root/AGENTS.md +9 -0
  176. package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +0 -314
@@ -1,27 +1,9 @@
1
1
  import { useT } from "@agent-native/core/client/i18n";
2
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
2
+ import { SharedRichEditor } from "@agent-native/toolkit/editor";
3
+ import { useEffect, useRef, useState } from "react";
3
4
 
4
- import { Textarea } from "@/components/ui/textarea";
5
- import {
6
- Tooltip,
7
- TooltipContent,
8
- TooltipProvider,
9
- TooltipTrigger,
10
- } from "@/components/ui/tooltip";
11
5
  import { cn } from "@/lib/utils";
12
6
 
13
- function useAutoGrow(
14
- ref: React.RefObject<HTMLTextAreaElement | null>,
15
- dep: unknown,
16
- ) {
17
- useLayoutEffect(() => {
18
- const el = ref.current;
19
- if (!el) return;
20
- el.style.height = "auto";
21
- el.style.height = `${el.scrollHeight}px`;
22
- }, [ref, dep]);
23
- }
24
-
25
7
  interface CanvasEditorProps {
26
8
  /** Which content this canvas renders. */
27
9
  view: "user" | "ai";
@@ -29,10 +11,9 @@ interface CanvasEditorProps {
29
11
  userNotesMd?: string;
30
12
  /** Save user notes. Called on blur after edit. */
31
13
  onUserNotesChange?: (next: string) => void;
32
- /** AI-generated summary — primary content, so it renders full-strength
33
- * foreground like user notes. For the "ai" view. */
14
+ /** AI-generated summary (renders muted-gray). For the "ai" view. */
34
15
  summaryMd?: string;
35
- /** AI-generated bullets — same weight as the summary. For the "ai" view. */
16
+ /** AI-generated bullets (renders muted-gray). For the "ai" view. */
36
17
  bullets?: string[];
37
18
  /** Save AI summary when the user edits the summary section. */
38
19
  onSummaryChange?: (next: string) => void;
@@ -40,6 +21,8 @@ interface CanvasEditorProps {
40
21
  renderBullet?: (bullet: string, index: number) => React.ReactNode;
41
22
  /** When true, notes render as read-only (viewer-role access). */
42
23
  readOnly?: boolean;
24
+ /** Optional layout classes for embedding the canvas in another panel. */
25
+ className?: string;
43
26
  }
44
27
 
45
28
  export function CanvasEditor({
@@ -51,6 +34,7 @@ export function CanvasEditor({
51
34
  onSummaryChange,
52
35
  renderBullet,
53
36
  readOnly = false,
37
+ className,
54
38
  }: CanvasEditorProps) {
55
39
  const t = useT();
56
40
  const showUser = view === "user";
@@ -58,7 +42,7 @@ export function CanvasEditor({
58
42
  const hasAi = summaryMd || bullets.length > 0;
59
43
 
60
44
  return (
61
- <div className="px-6 py-6 space-y-6 max-w-2xl">
45
+ <div className={cn("px-6 py-6 space-y-6 max-w-2xl", className)}>
62
46
  {/* User notes block */}
63
47
  {showUser && (
64
48
  <UserNotesBlock
@@ -77,7 +61,7 @@ export function CanvasEditor({
77
61
  />
78
62
  )}
79
63
 
80
- {/* AI bullets — with optional BulletLink wrappers */}
64
+ {/* AI bullets — muted gray, with optional BulletLink wrappers */}
81
65
  {showAi && bullets.length > 0 && (
82
66
  <AiBulletsBlock bullets={bullets} renderBullet={renderBullet} />
83
67
  )}
@@ -104,24 +88,9 @@ function UserNotesBlock({
104
88
  readOnly?: boolean;
105
89
  }) {
106
90
  const t = useT();
107
- const ref = useRef<HTMLTextAreaElement>(null);
108
- const [draft, setDraft] = useState(value);
109
- const focusedRef = useRef(false);
110
-
111
- // Sync external updates (live polling, desktop-app sync) into the editor —
112
- // but only while it's not focused, so we never clobber what's being typed.
113
- useEffect(() => {
114
- if (!focusedRef.current) setDraft(value);
115
- }, [value]);
116
-
117
- useAutoGrow(ref, draft);
118
91
 
119
- if (readOnly) {
120
- return value ? (
121
- <p className="text-base leading-relaxed text-foreground font-medium whitespace-pre-wrap">
122
- {value}
123
- </p>
124
- ) : (
92
+ if (readOnly && !value) {
93
+ return (
125
94
  <p className="text-sm leading-relaxed text-muted-foreground/50 italic">
126
95
  {t("meetingCanvas.noNotes")}
127
96
  </p>
@@ -129,19 +98,13 @@ function UserNotesBlock({
129
98
  }
130
99
 
131
100
  return (
132
- <Textarea
133
- ref={ref}
134
- value={draft}
101
+ <RichContentBlock
102
+ value={value}
103
+ onChange={onChange}
104
+ readOnly={readOnly}
135
105
  placeholder={t("meetingCanvas.yourNotes")}
136
- onChange={(e) => setDraft(e.target.value)}
137
- onFocus={() => {
138
- focusedRef.current = true;
139
- }}
140
- onBlur={(e) => {
141
- focusedRef.current = false;
142
- if (e.target.value !== value) onChange(e.target.value);
143
- }}
144
- className="min-h-[80px] resize-none overflow-hidden text-base leading-relaxed text-foreground font-medium border-none shadow-none focus-visible:ring-0 px-0"
106
+ ariaLabel={t("meetingDetail.myNotes")}
107
+ editorClassName="text-base leading-relaxed font-medium"
145
108
  />
146
109
  );
147
110
  }
@@ -158,94 +121,76 @@ function AiSummaryBlock({
158
121
  readOnly?: boolean;
159
122
  }) {
160
123
  const t = useT();
161
- const [editing, setEditing] = useState(false);
162
- const [draft, setDraft] = useState(value);
163
- const ref = useRef<HTMLTextAreaElement>(null);
164
124
 
165
- useEffect(() => {
166
- if (!editing) setDraft(value);
167
- }, [value, editing]);
168
-
169
- useEffect(() => {
170
- if (editing) {
171
- const el = ref.current;
172
- if (el) {
173
- el.focus();
174
- el.setSelectionRange(el.value.length, el.value.length);
175
- }
176
- }
177
- }, [editing]);
125
+ return (
126
+ <div className="space-y-1.5">
127
+ <AiTabIndicator />
128
+ <RichContentBlock
129
+ value={value}
130
+ onChange={onChange}
131
+ readOnly={readOnly}
132
+ placeholder={t("meetingCanvas.clickToEdit")}
133
+ ariaLabel={t("meetingDetail.aiNotes")}
134
+ editorClassName="text-sm leading-relaxed text-muted-foreground"
135
+ />
136
+ </div>
137
+ );
138
+ }
178
139
 
179
- useAutoGrow(ref, editing ? draft : null);
140
+ function RichContentBlock({
141
+ value,
142
+ onChange,
143
+ readOnly,
144
+ placeholder,
145
+ ariaLabel,
146
+ editorClassName,
147
+ }: {
148
+ value: string;
149
+ onChange: (next: string) => void;
150
+ readOnly: boolean;
151
+ placeholder: string;
152
+ ariaLabel: string;
153
+ editorClassName?: string;
154
+ }) {
155
+ const [draft, setDraft] = useState(value);
156
+ const draftRef = useRef(value);
157
+ const focusedRef = useRef(false);
180
158
 
181
- if (readOnly) {
182
- return (
183
- <div className="space-y-1.5">
184
- <AiTabIndicator />
185
- <p className="text-sm leading-relaxed whitespace-pre-wrap text-foreground">
186
- {value}
187
- </p>
188
- </div>
189
- );
190
- }
159
+ // Polling can replace the parent value while a meeting is live. Keep the
160
+ // editor's local draft authoritative while focused, then accept the latest
161
+ // server value once the user leaves it.
162
+ useEffect(() => {
163
+ if (focusedRef.current) return;
164
+ draftRef.current = value;
165
+ setDraft(value);
166
+ }, [value]);
191
167
 
192
168
  const commit = () => {
193
- setEditing(false);
194
- const next = draft;
195
- if (next === value) return;
196
- onChange(next);
169
+ focusedRef.current = false;
170
+ const next = draftRef.current;
171
+ if (next !== value) onChange(next);
197
172
  };
198
173
 
199
- if (editing) {
200
- return (
201
- <div className="space-y-1.5">
202
- <AiTabIndicator />
203
- <Textarea
204
- ref={ref}
205
- value={draft}
206
- onChange={(e) => setDraft(e.target.value)}
207
- onBlur={commit}
208
- onKeyDown={(e) => {
209
- if (e.key === "Escape") {
210
- setDraft(value);
211
- setEditing(false);
212
- }
213
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
214
- e.preventDefault();
215
- commit();
216
- }
217
- }}
218
- // Once the user starts typing, it visually flips to foreground.
219
- className="min-h-[100px] resize-none overflow-hidden text-sm leading-relaxed text-foreground border-none shadow-none focus-visible:ring-0 px-0"
220
- />
221
- </div>
222
- );
223
- }
224
-
225
174
  return (
226
- <TooltipProvider delayDuration={200}>
227
- <div className="group relative space-y-1.5">
228
- <AiTabIndicator />
229
- <Tooltip>
230
- <TooltipTrigger asChild>
231
- <button
232
- type="button"
233
- onClick={() => setEditing(true)}
234
- className="block w-full text-left cursor-text"
235
- >
236
- <p
237
- className={cn(
238
- "text-sm leading-relaxed whitespace-pre-wrap text-foreground rounded -mx-1 px-1 group-hover:bg-accent/30",
239
- )}
240
- >
241
- {value}
242
- </p>
243
- </button>
244
- </TooltipTrigger>
245
- <TooltipContent>{t("meetingCanvas.clickToEdit")}</TooltipContent>
246
- </Tooltip>
247
- </div>
248
- </TooltipProvider>
175
+ <SharedRichEditor
176
+ value={draft}
177
+ onChange={(next) => {
178
+ // Keep Tiptap updates local while typing. The parent only commits the
179
+ // latest markdown on blur, so one editing session cannot enqueue one
180
+ // database write per keystroke.
181
+ focusedRef.current = true;
182
+ draftRef.current = next;
183
+ setDraft(next);
184
+ }}
185
+ onBlur={commit}
186
+ editable={!readOnly}
187
+ dialect="nfm"
188
+ preset="content"
189
+ placeholder={placeholder}
190
+ ariaLabel={ariaLabel}
191
+ className="-mx-1 rounded-md px-1"
192
+ editorClassName={cn("min-h-[2rem]", editorClassName)}
193
+ />
249
194
  );
250
195
  }
251
196
 
@@ -264,7 +209,7 @@ function AiBulletsBlock({
264
209
  <ul className="space-y-1.5">
265
210
  {bullets.map((b, i) => {
266
211
  const content = (
267
- <div className="flex gap-2 text-sm leading-relaxed text-foreground">
212
+ <div className="flex gap-2 text-sm leading-relaxed text-muted-foreground">
268
213
  <span>•</span>
269
214
  <span className="flex-1">{b}</span>
270
215
  </div>
@@ -183,6 +183,8 @@ export interface VideoPlayerProps {
183
183
  defaultSpeed?: number;
184
184
  /** Autoplay on mount. */
185
185
  autoPlay?: boolean;
186
+ /** Persist resume position for an authenticated viewer. */
187
+ persistPlaybackPosition?: boolean;
186
188
  /** Start time in ms. */
187
189
  startMs?: number;
188
190
  /** Comment + chapter overlays for the scrubber. */
@@ -247,6 +249,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
247
249
  thumbnailUrl,
248
250
  defaultSpeed = 1.2,
249
251
  autoPlay,
252
+ persistPlaybackPosition = true,
250
253
  startMs,
251
254
  editsJson,
252
255
  comments,
@@ -520,6 +523,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
520
523
  recordingId,
521
524
  videoEl: playbackVideoEl,
522
525
  durationMs,
526
+ enabled: persistPlaybackPosition,
523
527
  explicitStartMs: startMs,
524
528
  allowRestoreWhilePlaying: autoPlay,
525
529
  onRestore: restorePlaybackPosition,
@@ -13,6 +13,7 @@ export interface UsePlaybackPositionOptions {
13
13
  recordingId: string;
14
14
  videoEl: HTMLVideoElement | null;
15
15
  durationMs: number;
16
+ enabled?: boolean;
16
17
  explicitStartMs?: number;
17
18
  allowRestoreWhilePlaying?: boolean;
18
19
  onRestore?: (positionMs: number) => void;
@@ -27,6 +28,7 @@ export function usePlaybackPosition({
27
28
  recordingId,
28
29
  videoEl,
29
30
  durationMs,
31
+ enabled = true,
30
32
  explicitStartMs,
31
33
  allowRestoreWhilePlaying = false,
32
34
  onRestore,
@@ -38,7 +40,7 @@ export function usePlaybackPosition({
38
40
  onRestoreRef.current = onRestore;
39
41
 
40
42
  useEffect(() => {
41
- if (!videoEl || !recordingId) return;
43
+ if (!enabled || !videoEl || !recordingId) return;
42
44
 
43
45
  const controller = new AbortController();
44
46
  let cancelled = false;
@@ -184,5 +186,11 @@ export function usePlaybackPosition({
184
186
  window.removeEventListener("pagehide", onPageHide);
185
187
  document.removeEventListener("visibilitychange", onVisibilityChange);
186
188
  };
187
- }, [allowRestoreWhilePlaying, explicitStartMs, recordingId, videoEl]);
189
+ }, [
190
+ allowRestoreWhilePlaying,
191
+ enabled,
192
+ explicitStartMs,
193
+ recordingId,
194
+ videoEl,
195
+ ]);
188
196
  }
@@ -384,6 +384,9 @@ const messages = {
384
384
  aiNotes: "AI notes",
385
385
  summary: "Summary",
386
386
  actionItems: "Action items",
387
+ addActionItem: "Add action item",
388
+ removeActionItem: "Remove action item",
389
+ actionItemPlaceholder: "What needs to happen?",
387
390
  working: "Working…",
388
391
  noActionItems:
389
392
  "No action items yet. They appear here after notes are generated from a transcript.",
@@ -1119,6 +1122,7 @@ All notable user-facing changes to Clips are documented here. Open it any time f
1119
1122
  "The live transcript will appear here once notes start.",
1120
1123
  me: "Me",
1121
1124
  them: "Them",
1125
+ unknownSpeaker: "Speaker",
1122
1126
  searchTranscript: "Search transcript",
1123
1127
  searchPlaceholder: "Search transcript…",
1124
1128
  searchMatchCount: "{{current}} of {{total}}",