@agent-native/core 0.114.9 → 0.114.10

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 (130) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +13 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +31 -3
  5. package/corpus/core/src/agent/engine/anthropic-engine.ts +20 -3
  6. package/corpus/core/src/agent/engine/builder-engine.ts +56 -9
  7. package/corpus/core/src/agent/engine/first-event-timeout.ts +64 -0
  8. package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -3
  9. package/corpus/core/src/client/AssistantChat.tsx +7 -3
  10. package/corpus/core/src/client/resources/ResourcesPanel.tsx +1 -1
  11. package/corpus/core/src/integrations/computer-supervision-store.ts +4 -4
  12. package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
  13. package/corpus/core/src/integrations/remote-commands-store.ts +5 -5
  14. package/corpus/core/src/integrations/remote-devices-store.ts +3 -3
  15. package/corpus/core/src/integrations/remote-push-store.ts +3 -3
  16. package/corpus/core/src/observability/traces.ts +38 -1
  17. package/corpus/core/src/server/action-routes.ts +23 -1
  18. package/corpus/core/src/server/http-response-telemetry.ts +6 -1
  19. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  20. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  21. package/corpus/templates/analytics/actions/account-deep-dive.ts +41 -6
  22. package/corpus/templates/analytics/changelog/2026-07-20-account-deep-dives-finish-with-partial-data-when-hubspot-lo.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-07-20-dashboard-email-reports-now-include-an-image-when-a-single-p.md +6 -0
  24. package/corpus/templates/analytics/server/lib/dashboard-report.ts +11 -3
  25. package/corpus/templates/calendar/actions/create-event.ts +5 -0
  26. package/corpus/templates/calendar/app/components/ThemeToggle.tsx +4 -1
  27. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +0 -1
  28. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +309 -421
  29. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +349 -0
  30. package/corpus/templates/calendar/app/i18n-data.ts +110 -0
  31. package/corpus/templates/calendar/app/lib/event-form-utils.ts +6 -0
  32. package/corpus/templates/calendar/app/pages/CalendarView.tsx +3 -0
  33. package/corpus/templates/calendar/app/root.tsx +4 -2
  34. package/corpus/templates/calendar/changelog/2026-07-20-events-can-be-updated-inline-with-date-time-timezone-and-rep.md +6 -0
  35. package/corpus/templates/calendar/changelog/2026-07-20-public-booking-pages-no-longer-hydrate-with-a-theme-mismatch.md +6 -0
  36. package/corpus/templates/calendar/shared/api.ts +1 -0
  37. package/corpus/templates/clips/AGENTS.md +7 -0
  38. package/corpus/templates/clips/actions/create-recording.ts +51 -10
  39. package/corpus/templates/clips/actions/get-recording-player-data.ts +34 -5
  40. package/corpus/templates/clips/actions/lib/transcript-preview.ts +48 -0
  41. package/corpus/templates/clips/actions/list-recordings.ts +15 -4
  42. package/corpus/templates/clips/actions/regenerate-summary.ts +32 -0
  43. package/corpus/templates/clips/actions/search-recordings.ts +28 -6
  44. package/corpus/templates/clips/actions/view-screen.ts +54 -47
  45. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -5
  46. package/corpus/templates/clips/app/components/library/recording-card.tsx +29 -32
  47. package/corpus/templates/clips/app/components/meetings/quick-ask-sidebar.tsx +13 -0
  48. package/corpus/templates/clips/changelog/2026-07-20-agent-summaries-use-bounded-transcript-context.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-07-20-clip-summaries-now-finish-without-sending-a-long-transcript-.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-07-20-clips-agents-only-discover-recordings-you-own-or-have-alread.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-07-20-hosted-recordings-no-longer-start-with-an-impossible-buffered-upload.md +6 -0
  52. package/corpus/templates/clips/changelog/2026-07-20-meeting-recordings-now-offer-a-cleaner-transcript-view-with-.md +6 -0
  53. package/corpus/templates/clips/changelog/2026-07-20-shared-clips-can-be-shared-with-limited-access-and-cards-sho.md +6 -0
  54. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +12 -8
  55. package/corpus/templates/clips/desktop/src/overlays/pill-logo.tsx +2 -15
  56. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +107 -340
  57. package/corpus/templates/clips/desktop/src/styles.css +27 -145
  58. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +6 -7
  59. package/corpus/templates/clips/server/lib/agent-recording-access.ts +73 -0
  60. package/corpus/templates/clips/server/plugins/agent-chat.ts +5 -2
  61. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +18 -0
  62. package/corpus/templates/plan/app/pages/PlansPage.tsx +10 -11
  63. package/corpus/templates/plan/changelog/2026-07-20-bridged-local-plans-now-load-comments-from-the-local-workspace.md +6 -0
  64. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  65. package/dist/agent/engine/ai-sdk-engine.js +27 -4
  66. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  67. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  68. package/dist/agent/engine/anthropic-engine.js +19 -4
  69. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  70. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  71. package/dist/agent/engine/builder-engine.js +40 -7
  72. package/dist/agent/engine/builder-engine.js.map +1 -1
  73. package/dist/agent/engine/first-event-timeout.d.ts +25 -0
  74. package/dist/agent/engine/first-event-timeout.d.ts.map +1 -0
  75. package/dist/agent/engine/first-event-timeout.js +49 -0
  76. package/dist/agent/engine/first-event-timeout.js.map +1 -0
  77. package/dist/cli/pr-visual-recap-workflow.d.ts +2 -2
  78. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  79. package/dist/cli/pr-visual-recap-workflow.js +2 -2
  80. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  81. package/dist/client/AssistantChat.d.ts.map +1 -1
  82. package/dist/client/AssistantChat.js +7 -3
  83. package/dist/client/AssistantChat.js.map +1 -1
  84. package/dist/client/resources/ResourcesPanel.js +1 -1
  85. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  86. package/dist/collab/routes.d.ts +1 -1
  87. package/dist/integrations/computer-supervision-store.js +4 -4
  88. package/dist/integrations/computer-supervision-store.js.map +1 -1
  89. package/dist/integrations/pending-tasks-store.js +1 -1
  90. package/dist/integrations/pending-tasks-store.js.map +1 -1
  91. package/dist/integrations/remote-commands-store.js +5 -5
  92. package/dist/integrations/remote-commands-store.js.map +1 -1
  93. package/dist/integrations/remote-devices-store.js +3 -3
  94. package/dist/integrations/remote-devices-store.js.map +1 -1
  95. package/dist/integrations/remote-push-store.js +3 -3
  96. package/dist/integrations/remote-push-store.js.map +1 -1
  97. package/dist/notifications/routes.d.ts +2 -2
  98. package/dist/observability/routes.d.ts +3 -3
  99. package/dist/observability/traces.d.ts.map +1 -1
  100. package/dist/observability/traces.js +23 -1
  101. package/dist/observability/traces.js.map +1 -1
  102. package/dist/secrets/routes.d.ts +9 -9
  103. package/dist/server/action-routes.d.ts.map +1 -1
  104. package/dist/server/action-routes.js +23 -1
  105. package/dist/server/action-routes.js.map +1 -1
  106. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  107. package/dist/server/http-response-telemetry.d.ts +2 -0
  108. package/dist/server/http-response-telemetry.d.ts.map +1 -1
  109. package/dist/server/http-response-telemetry.js +5 -1
  110. package/dist/server/http-response-telemetry.js.map +1 -1
  111. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  112. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  113. package/package.json +2 -2
  114. package/src/agent/engine/ai-sdk-engine.ts +31 -3
  115. package/src/agent/engine/anthropic-engine.ts +20 -3
  116. package/src/agent/engine/builder-engine.ts +56 -9
  117. package/src/agent/engine/first-event-timeout.ts +64 -0
  118. package/src/cli/pr-visual-recap-workflow.ts +2 -3
  119. package/src/client/AssistantChat.tsx +7 -3
  120. package/src/client/resources/ResourcesPanel.tsx +1 -1
  121. package/src/integrations/computer-supervision-store.ts +4 -4
  122. package/src/integrations/pending-tasks-store.ts +1 -1
  123. package/src/integrations/remote-commands-store.ts +5 -5
  124. package/src/integrations/remote-devices-store.ts +3 -3
  125. package/src/integrations/remote-push-store.ts +3 -3
  126. package/src/observability/traces.ts +38 -1
  127. package/src/server/action-routes.ts +23 -1
  128. package/src/server/http-response-telemetry.ts +6 -1
  129. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +1 -1
  130. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
@@ -0,0 +1,349 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import {
3
+ IconCheck,
4
+ IconClock,
5
+ IconRefresh,
6
+ IconWorld,
7
+ } from "@tabler/icons-react";
8
+ import { format } from "date-fns";
9
+ import { useEffect, useMemo, useRef, useState } from "react";
10
+
11
+ import { TimezoneCombobox } from "@/components/TimezoneCombobox";
12
+ import { Button } from "@/components/ui/button";
13
+ import { Input } from "@/components/ui/input";
14
+ import {
15
+ Popover,
16
+ PopoverContent,
17
+ PopoverTrigger,
18
+ } from "@/components/ui/popover";
19
+ import {
20
+ formatTimezoneLabel,
21
+ type RecurrencePreset,
22
+ } from "@/lib/event-form-utils";
23
+ import { cn } from "@/lib/utils";
24
+
25
+ const TIME_OPTIONS = Array.from({ length: 24 * 4 }, (_, index) => {
26
+ const hour = Math.floor(index / 4);
27
+ const minute = (index % 4) * 15;
28
+ return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
29
+ });
30
+
31
+ function formatTimeValue(value: string) {
32
+ const [hourValue, minuteValue] = value.split(":").map(Number);
33
+ if (!Number.isFinite(hourValue) || !Number.isFinite(minuteValue)) {
34
+ return value;
35
+ }
36
+ const period = hourValue >= 12 ? "PM" : "AM";
37
+ const hour = hourValue % 12 || 12;
38
+ return minuteValue === 0
39
+ ? `${hour} ${period}`
40
+ : `${hour}:${String(minuteValue).padStart(2, "0")} ${period}`;
41
+ }
42
+
43
+ function formatDateValue(value: string) {
44
+ const parsed = new Date(`${value}T12:00:00`);
45
+ return Number.isNaN(parsed.getTime()) ? value : format(parsed, "EEE MMM d");
46
+ }
47
+
48
+ export function TimePickerPopover({
49
+ value,
50
+ onChange,
51
+ label,
52
+ getOptionMeta,
53
+ className,
54
+ }: {
55
+ value: string;
56
+ onChange: (value: string) => void;
57
+ label: string;
58
+ getOptionMeta?: (value: string) => string | undefined;
59
+ className?: string;
60
+ }) {
61
+ const [open, setOpen] = useState(false);
62
+ const selectedRef = useRef<HTMLButtonElement>(null);
63
+ const options = useMemo(
64
+ () =>
65
+ TIME_OPTIONS.includes(value) ? TIME_OPTIONS : [value, ...TIME_OPTIONS],
66
+ [value],
67
+ );
68
+
69
+ useEffect(() => {
70
+ if (open) {
71
+ requestAnimationFrame(() =>
72
+ selectedRef.current?.scrollIntoView({ block: "center" }),
73
+ );
74
+ }
75
+ }, [open]);
76
+
77
+ return (
78
+ <Popover open={open} onOpenChange={setOpen}>
79
+ <PopoverTrigger asChild>
80
+ <Button
81
+ type="button"
82
+ variant="ghost"
83
+ size="sm"
84
+ className={cn(
85
+ "h-auto rounded px-1.5 py-0.5 text-base font-normal text-foreground hover:bg-muted",
86
+ className,
87
+ )}
88
+ aria-label={label}
89
+ >
90
+ {formatTimeValue(value)}
91
+ </Button>
92
+ </PopoverTrigger>
93
+ <PopoverContent
94
+ align="start"
95
+ sideOffset={6}
96
+ className="w-52 p-1"
97
+ data-time-picker-popover
98
+ >
99
+ <div className="flex items-center gap-2 px-2.5 py-2 text-xs font-medium text-muted-foreground">
100
+ <IconClock className="size-3.5" />
101
+ {label}
102
+ </div>
103
+ <div className="max-h-64 overflow-y-auto">
104
+ {options.map((option) => {
105
+ const selected = option === value;
106
+ return (
107
+ <button
108
+ key={option}
109
+ ref={selected ? selectedRef : undefined}
110
+ type="button"
111
+ className={cn(
112
+ "flex w-full items-center justify-between rounded-md px-2.5 py-2 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
113
+ selected && "bg-accent text-accent-foreground",
114
+ )}
115
+ onClick={() => {
116
+ onChange(option);
117
+ setOpen(false);
118
+ }}
119
+ >
120
+ <span>{formatTimeValue(option)}</span>
121
+ {getOptionMeta?.(option) && (
122
+ <span className="text-muted-foreground">
123
+ {getOptionMeta(option)}
124
+ </span>
125
+ )}
126
+ {selected && <IconCheck className="ml-2 size-3.5 shrink-0" />}
127
+ </button>
128
+ );
129
+ })}
130
+ </div>
131
+ </PopoverContent>
132
+ </Popover>
133
+ );
134
+ }
135
+
136
+ export function DatePickerPopover({
137
+ value,
138
+ onChange,
139
+ label,
140
+ className,
141
+ }: {
142
+ value: string;
143
+ onChange: (value: string) => void;
144
+ label: string;
145
+ className?: string;
146
+ }) {
147
+ const [open, setOpen] = useState(false);
148
+
149
+ return (
150
+ <Popover open={open} onOpenChange={setOpen}>
151
+ <PopoverTrigger asChild>
152
+ <Button
153
+ type="button"
154
+ variant="ghost"
155
+ size="sm"
156
+ className={cn(
157
+ "h-auto rounded px-1.5 py-0.5 text-base font-normal text-foreground hover:bg-muted",
158
+ className,
159
+ )}
160
+ aria-label={label}
161
+ >
162
+ {formatDateValue(value)}
163
+ </Button>
164
+ </PopoverTrigger>
165
+ <PopoverContent
166
+ align="start"
167
+ sideOffset={6}
168
+ className="w-auto p-3"
169
+ data-time-picker-popover
170
+ >
171
+ <Input
172
+ type="date"
173
+ value={value}
174
+ aria-label={label}
175
+ autoFocus
176
+ onChange={(event) => {
177
+ if (!event.target.value) return;
178
+ onChange(event.target.value);
179
+ setOpen(false);
180
+ }}
181
+ />
182
+ </PopoverContent>
183
+ </Popover>
184
+ );
185
+ }
186
+
187
+ export function TimezonePickerPopover({
188
+ value,
189
+ onChange,
190
+ label,
191
+ }: {
192
+ value: string;
193
+ onChange: (value: string) => void;
194
+ label: string;
195
+ }) {
196
+ const t = useT();
197
+ const [open, setOpen] = useState(false);
198
+
199
+ return (
200
+ <Popover open={open} onOpenChange={setOpen}>
201
+ <PopoverTrigger asChild>
202
+ <Button
203
+ type="button"
204
+ variant="ghost"
205
+ size="sm"
206
+ className="h-auto justify-start rounded px-1.5 py-0.5 text-sm font-normal text-muted-foreground hover:bg-muted hover:text-foreground"
207
+ aria-label={label}
208
+ >
209
+ <IconWorld className="mr-2 size-4 shrink-0" />
210
+ {formatTimezoneLabel(value)}
211
+ </Button>
212
+ </PopoverTrigger>
213
+ <PopoverContent
214
+ align="start"
215
+ sideOffset={6}
216
+ className="w-[min(20rem,calc(100vw-2rem))] p-3"
217
+ data-time-picker-popover
218
+ >
219
+ <TimezoneCombobox
220
+ id="inline-event-timezone"
221
+ value={value}
222
+ onChange={(nextValue) => {
223
+ onChange(nextValue);
224
+ setOpen(false);
225
+ }}
226
+ />
227
+ <p className="mt-2 text-xs text-muted-foreground">
228
+ {t("eventForm.timezone")}
229
+ </p>
230
+ </PopoverContent>
231
+ </Popover>
232
+ );
233
+ }
234
+
235
+ export function RepeatPicker({
236
+ preset,
237
+ referenceDate,
238
+ onChange,
239
+ }: {
240
+ preset: RecurrencePreset;
241
+ referenceDate: string;
242
+ onChange: (preset: RecurrencePreset) => void;
243
+ }) {
244
+ const t = useT();
245
+ const [open, setOpen] = useState(false);
246
+ const reference = new Date(referenceDate);
247
+ const weekday = Number.isNaN(reference.getTime())
248
+ ? ""
249
+ : format(reference, "EEE");
250
+ const monthDay = Number.isNaN(reference.getTime())
251
+ ? ""
252
+ : format(reference, "do");
253
+ const options: Array<{
254
+ value: RecurrencePreset;
255
+ label: string;
256
+ meta?: string;
257
+ disabled?: boolean;
258
+ }> = [
259
+ { value: "none", label: t("eventForm.doesNotRepeat") },
260
+ { value: "daily", label: t("eventForm.daily") },
261
+ {
262
+ value: "weekdays",
263
+ label: t("eventForm.everyWeekday"),
264
+ meta: t("eventForm.weekdaysShort"),
265
+ },
266
+ {
267
+ value: "weekly",
268
+ label: t("eventForm.weekly"),
269
+ meta: weekday ? t("eventForm.onDay", { day: weekday }) : undefined,
270
+ },
271
+ {
272
+ value: "biweekly",
273
+ label: t("eventForm.everyTwoWeeks"),
274
+ meta: weekday ? t("eventForm.onDay", { day: weekday }) : undefined,
275
+ },
276
+ {
277
+ value: "monthly",
278
+ label: t("eventForm.monthly"),
279
+ meta: monthDay ? t("eventForm.onMonthDay", { day: monthDay }) : undefined,
280
+ },
281
+ {
282
+ value: "yearly",
283
+ label: t("eventForm.yearly"),
284
+ meta: monthDay
285
+ ? t("eventForm.onDate", { date: format(reference, "MMM d") })
286
+ : undefined,
287
+ },
288
+ {
289
+ value: "custom",
290
+ label: t("eventForm.customSchedule"),
291
+ disabled: true,
292
+ },
293
+ ];
294
+
295
+ const selectedOption = options.find((option) => option.value === preset);
296
+ const triggerLabel =
297
+ preset === "none" ? t("eventForm.repeat") : selectedOption?.label;
298
+
299
+ return (
300
+ <Popover open={open} onOpenChange={setOpen}>
301
+ <PopoverTrigger asChild>
302
+ <Button
303
+ type="button"
304
+ variant="ghost"
305
+ size="sm"
306
+ className="h-auto w-full justify-start rounded-md px-1.5 py-1 text-sm font-normal text-muted-foreground hover:bg-muted hover:text-foreground"
307
+ aria-label={t("eventForm.repeat")}
308
+ >
309
+ <IconRefresh className="mr-2 size-4 shrink-0" />
310
+ {triggerLabel}
311
+ </Button>
312
+ </PopoverTrigger>
313
+ <PopoverContent
314
+ align="start"
315
+ sideOffset={6}
316
+ className="w-64 p-1"
317
+ data-time-picker-popover
318
+ >
319
+ {options.map((option) => {
320
+ const selected = option.value === preset;
321
+ return (
322
+ <button
323
+ key={option.value}
324
+ type="button"
325
+ disabled={option.disabled}
326
+ className={cn(
327
+ "flex w-full items-center justify-between rounded-md px-2.5 py-2 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
328
+ selected && "bg-accent text-accent-foreground",
329
+ option.disabled &&
330
+ "cursor-not-allowed opacity-50 hover:bg-transparent",
331
+ )}
332
+ onClick={() => {
333
+ if (option.disabled) return;
334
+ onChange(option.value);
335
+ setOpen(false);
336
+ }}
337
+ >
338
+ <span>{option.label}</span>
339
+ <span className="ml-3 flex items-center gap-2 text-muted-foreground">
340
+ {option.meta}
341
+ {selected && <IconCheck className="size-3.5 shrink-0" />}
342
+ </span>
343
+ </button>
344
+ );
345
+ })}
346
+ </PopoverContent>
347
+ </Popover>
348
+ );
349
+ }
@@ -703,6 +703,7 @@ const enUS = {
703
703
  addCalendar: "Add Calendar",
704
704
  addCalendarFailed: "Failed to add calendar",
705
705
  addCalendarFromUrl: "Add calendar from URL",
706
+ addGuest: "Add guest",
706
707
  addGuests: "Add guests",
707
708
  addNote: "Add note",
708
709
  addLocation: "Add location",
@@ -766,6 +767,7 @@ const enUS = {
766
767
  eventTitlePlaceholder: "Event title",
767
768
  events: "Events",
768
769
  everyWeekday: "Every weekday",
770
+ everyTwoWeeks: "Every 2 weeks",
769
771
  findTime: "Find a time",
770
772
  focusTime: "Focus time",
771
773
  focusTimeTimedOnly:
@@ -821,6 +823,7 @@ const enUS = {
821
823
  quickCreate: "Quick create",
822
824
  recurringResponseScope: "Recurring response scope",
823
825
  repeats: "Repeats",
826
+ repeat: "Repeat",
824
827
  reviewInvite: "Review Invite",
825
828
  responseAwaitingCount: "{{count}} awaiting",
826
829
  responseMaybeCount: "{{count}} maybe",
@@ -872,6 +875,10 @@ const enUS = {
872
875
  viewingOwnerCalendar: "Viewing {{owner}}'s calendar",
873
876
  yourResponse: "Your response: {{status}}",
874
877
  visibility: "Visibility",
878
+ onDate: "on {{date}}",
879
+ onDay: "on {{day}}",
880
+ onMonthDay: "on the {{day}}",
881
+ weekdaysShort: "Mon–Fri",
875
882
  weekly: "Weekly",
876
883
  workingFrom: "Working from",
877
884
  workingLocation: "Working location",
@@ -6122,6 +6129,108 @@ const translatedCalendarDebtTranslations = {
6122
6129
  },
6123
6130
  } satisfies Partial<Record<LocaleCode, PartialMessages>>;
6124
6131
 
6132
+ const translatedCalendarInlineEditorLabels = {
6133
+ "zh-CN": {
6134
+ eventForm: {
6135
+ addGuest: "添加客人",
6136
+ everyTwoWeeks: "每两周",
6137
+ repeat: "重复",
6138
+ onDate: "于 {{date}}",
6139
+ onDay: "于 {{day}}",
6140
+ onMonthDay: "于 {{day}}日",
6141
+ weekdaysShort: "周一至周五",
6142
+ },
6143
+ },
6144
+ "es-ES": {
6145
+ eventForm: {
6146
+ addGuest: "Añadir invitado",
6147
+ everyTwoWeeks: "Cada 2 semanas",
6148
+ repeat: "Repetir",
6149
+ onDate: "el {{date}}",
6150
+ onDay: "el {{day}}",
6151
+ onMonthDay: "el día {{day}}",
6152
+ weekdaysShort: "lun–vie",
6153
+ },
6154
+ },
6155
+ "fr-FR": {
6156
+ eventForm: {
6157
+ addGuest: "Ajouter un invité",
6158
+ everyTwoWeeks: "Toutes les 2 semaines",
6159
+ repeat: "Répéter",
6160
+ onDate: "le {{date}}",
6161
+ onDay: "le {{day}}",
6162
+ onMonthDay: "le {{day}}",
6163
+ weekdaysShort: "lun–ven",
6164
+ },
6165
+ },
6166
+ "de-DE": {
6167
+ eventForm: {
6168
+ addGuest: "Gast hinzufügen",
6169
+ everyTwoWeeks: "Alle 2 Wochen",
6170
+ repeat: "Wiederholen",
6171
+ onDate: "am {{date}}",
6172
+ onDay: "am {{day}}",
6173
+ onMonthDay: "am {{day}}.",
6174
+ weekdaysShort: "Mo–Fr",
6175
+ },
6176
+ },
6177
+ "ja-JP": {
6178
+ eventForm: {
6179
+ addGuest: "ゲストを追加",
6180
+ everyTwoWeeks: "2週間ごと",
6181
+ repeat: "繰り返し",
6182
+ onDate: "{{date}}",
6183
+ onDay: "{{day}}に",
6184
+ onMonthDay: "{{day}}日",
6185
+ weekdaysShort: "月〜金",
6186
+ },
6187
+ },
6188
+ "ko-KR": {
6189
+ eventForm: {
6190
+ addGuest: "게스트 추가",
6191
+ everyTwoWeeks: "2주마다",
6192
+ repeat: "반복",
6193
+ onDate: "{{date}}",
6194
+ onDay: "{{day}}에",
6195
+ onMonthDay: "{{day}}일",
6196
+ weekdaysShort: "월–금",
6197
+ },
6198
+ },
6199
+ "pt-BR": {
6200
+ eventForm: {
6201
+ addGuest: "Adicionar convidado",
6202
+ everyTwoWeeks: "A cada 2 semanas",
6203
+ repeat: "Repetir",
6204
+ onDate: "em {{date}}",
6205
+ onDay: "em {{day}}",
6206
+ onMonthDay: "no dia {{day}}",
6207
+ weekdaysShort: "seg–sex",
6208
+ },
6209
+ },
6210
+ "hi-IN": {
6211
+ eventForm: {
6212
+ addGuest: "अतिथि जोड़ें",
6213
+ everyTwoWeeks: "हर 2 सप्ताह",
6214
+ repeat: "दोहराएं",
6215
+ onDate: "{{date}} को",
6216
+ onDay: "{{day}} को",
6217
+ onMonthDay: "{{day}} को",
6218
+ weekdaysShort: "सोम–शुक्र",
6219
+ },
6220
+ },
6221
+ "ar-SA": {
6222
+ eventForm: {
6223
+ addGuest: "إضافة ضيف",
6224
+ everyTwoWeeks: "كل أسبوعين",
6225
+ repeat: "تكرار",
6226
+ onDate: "في {{date}}",
6227
+ onDay: "في {{day}}",
6228
+ onMonthDay: "في اليوم {{day}}",
6229
+ weekdaysShort: "الإثنين–الجمعة",
6230
+ },
6231
+ },
6232
+ } satisfies Partial<Record<LocaleCode, PartialMessages>>;
6233
+
6125
6234
  const translatedCalendarRemainingRaw = {
6126
6235
  "zh-CN": {
6127
6236
  agentSidebar: {
@@ -9555,6 +9664,7 @@ function applyTranslatedCalendarOverrides(
9555
9664
 
9556
9665
  applyTranslatedCalendarOverrides(translatedCalendarExtras);
9557
9666
  applyTranslatedCalendarOverrides(translatedCalendarDebtTranslations);
9667
+ applyTranslatedCalendarOverrides(translatedCalendarInlineEditorLabels);
9558
9668
  applyTranslatedCalendarOverrides(translatedCalendarRemainingRaw);
9559
9669
  applyTranslatedCalendarOverrides(translatedCalendarRawBurnDown);
9560
9670
  applyTranslatedCalendarOverrides(translatedCalendarExactCleanup);
@@ -7,6 +7,7 @@ export type RecurrencePreset =
7
7
  | "daily"
8
8
  | "weekdays"
9
9
  | "weekly"
10
+ | "biweekly"
10
11
  | "monthly"
11
12
  | "yearly"
12
13
  | "custom";
@@ -334,6 +335,7 @@ export function getRecurrencePreset(recurrence?: string[]): RecurrencePreset {
334
335
  const interval = recurrenceField(rule, "INTERVAL") || "1";
335
336
  const byDay = recurrenceField(rule, "BYDAY");
336
337
 
338
+ if (freq === "WEEKLY" && interval === "2") return "biweekly";
337
339
  if (interval !== "1") return "custom";
338
340
  if (freq === "DAILY" && !byDay) return "daily";
339
341
  if ((freq === "DAILY" || freq === "WEEKLY") && byDay === "MO,TU,WE,TH,FR") {
@@ -361,6 +363,10 @@ export function buildRecurrenceRules(
361
363
  const day = eventWeekdayCode(startIso, timeZone);
362
364
  return [`RRULE:FREQ=WEEKLY;BYDAY=${day}`];
363
365
  }
366
+ case "biweekly": {
367
+ const day = eventWeekdayCode(startIso, timeZone);
368
+ return [`RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=${day}`];
369
+ }
364
370
  case "monthly":
365
371
  return ["RRULE:FREQ=MONTHLY"];
366
372
  case "yearly":
@@ -199,6 +199,7 @@ function draftToCalendarEvent(
199
199
  transparency: draft.transparency,
200
200
  visibility: draft.visibility,
201
201
  eventType: draft.eventType ?? "default",
202
+ recurrence: draft.recurrence,
202
203
  attendees: draft.attendees,
203
204
  reminders: draft.reminders,
204
205
  remindersUseDefault: draft.remindersUseDefault,
@@ -239,6 +240,7 @@ function applyDraftPatch(
239
240
  copy("transparency");
240
241
  copy("visibility");
241
242
  copy("colorId");
243
+ copy("recurrence");
242
244
  copy("reminders");
243
245
  copy("remindersUseDefault");
244
246
  copy("attachments");
@@ -677,6 +679,7 @@ export default function CalendarView() {
677
679
  ? getGoogleEventColorHex(draft.colorId)
678
680
  : undefined,
679
681
  colorId: draft.colorId,
682
+ recurrence: draft.recurrence,
680
683
  attachments: draft.attachments,
681
684
  attendees: draft.attendees,
682
685
  };
@@ -24,7 +24,7 @@ import { resolveLocaleFromRequest } from "@agent-native/core/server";
24
24
  import { IconBrain, IconSun, IconMoon } from "@tabler/icons-react";
25
25
  import { useQueryClient } from "@tanstack/react-query";
26
26
  import { useTheme } from "next-themes";
27
- import { useCallback, useState } from "react";
27
+ import { useCallback, useEffect, useState } from "react";
28
28
  import {
29
29
  Links,
30
30
  Meta,
@@ -174,8 +174,10 @@ function DbSyncSetup() {
174
174
 
175
175
  function ThemeToggleItem() {
176
176
  const { resolvedTheme, setTheme } = useTheme();
177
+ const [mounted, setMounted] = useState(false);
178
+ useEffect(() => setMounted(true), []);
177
179
  const t = useT();
178
- const isDark = resolvedTheme === "dark";
180
+ const isDark = mounted && resolvedTheme === "dark";
179
181
  return (
180
182
  <CommandMenu.Item
181
183
  onSelect={() => setTheme(isDark ? "light" : "dark")}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-20
4
+ ---
5
+
6
+ Events can be updated inline with date, time, timezone, and repeat controls.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-20
4
+ ---
5
+
6
+ Public booking pages no longer show a theme-related hydration error on first load.
@@ -142,6 +142,7 @@ export interface CalendarEventDraft {
142
142
  transparency?: "opaque" | "transparent";
143
143
  visibility?: "default" | "public" | "private" | "confidential";
144
144
  colorId?: string;
145
+ recurrence?: string[];
145
146
  reminders?: CalendarEvent["reminders"];
146
147
  remindersUseDefault?: boolean;
147
148
  attachments?: CalendarEvent["attachments"];
@@ -110,6 +110,13 @@ ladder.
110
110
  - Use `list-recordings --view=shared` for the current user's "Shared with me"
111
111
  collection. It returns recordings admitted by sharing access that are owned
112
112
  by someone else; public-link-only clips remain out of this list.
113
+ - Public recordings are unlisted-by-link for agent purposes: an agent may
114
+ discover only recordings the current user owns or has already viewed. Do not
115
+ use `list-recordings` or `search-recordings` to discover another user's
116
+ public clips, answer a time/date question about the clip already in context,
117
+ or recover from a failed direct lookup. If the user supplies another clip's
118
+ share URL or id, use that explicit reference; otherwise stop and report the
119
+ lookup failure.
113
120
  - Public recordings expose AI-readable URLs for external agents:
114
121
  `/api/agent-context.json?id=<recordingId>` for metadata, transcript, and frame
115
122
  API discovery; `/api/agent-transcript.json?id=<recordingId>` for transcript