@agent-native/core 0.98.7 → 0.98.9

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 (81) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/docs/content/external-agents.mdx +17 -11
  4. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +6 -2
  5. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +6 -2
  6. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +6 -2
  7. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +6 -2
  8. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +6 -2
  9. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +6 -2
  10. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +6 -2
  11. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +6 -2
  12. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +6 -2
  13. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +6 -2
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/client/session-replay.ts +29 -7
  16. package/corpus/core/src/integrations/adapters/slack.ts +13 -2
  17. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
  18. package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
  19. package/corpus/core/src/integrations/plugin.ts +183 -48
  20. package/corpus/core/src/integrations/types.ts +7 -0
  21. package/corpus/core/src/mcp/build-server.ts +99 -26
  22. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +31 -2
  23. package/corpus/templates/calendar/AGENTS.md +11 -0
  24. package/corpus/templates/calendar/README.md +2 -1
  25. package/corpus/templates/calendar/actions/create-event.ts +7 -6
  26. package/corpus/templates/calendar/actions/event-action-helpers.ts +49 -0
  27. package/corpus/templates/calendar/actions/update-event.ts +225 -14
  28. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +185 -70
  29. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +26 -4
  30. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +112 -69
  31. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +621 -524
  32. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +275 -164
  33. package/corpus/templates/calendar/app/components/calendar/WorkingLocationEditor.tsx +222 -0
  34. package/corpus/templates/calendar/app/hooks/use-events.ts +151 -79
  35. package/corpus/templates/calendar/app/i18n/zh-TW.ts +6 -0
  36. package/corpus/templates/calendar/app/i18n-data.ts +60 -0
  37. package/corpus/templates/calendar/app/lib/all-day-layout.ts +126 -0
  38. package/corpus/templates/calendar/app/lib/event-form-utils.ts +18 -1
  39. package/corpus/templates/calendar/app/lib/event-mutation-inputs.ts +1 -1
  40. package/corpus/templates/calendar/app/lib/working-location.ts +163 -0
  41. package/corpus/templates/calendar/app/pages/CalendarView.tsx +21 -2
  42. package/corpus/templates/calendar/changelog/2026-07-07-working-locations-from-google-calendar-now-appear-as-native-.md +6 -0
  43. package/corpus/templates/calendar/server/lib/calendar-availability.ts +2 -0
  44. package/corpus/templates/calendar/server/lib/google-api.ts +6 -1
  45. package/corpus/templates/calendar/server/lib/google-calendar.ts +49 -19
  46. package/corpus/templates/calendar/shared/api.ts +2 -0
  47. package/dist/client/session-replay.d.ts.map +1 -1
  48. package/dist/client/session-replay.js +24 -7
  49. package/dist/client/session-replay.js.map +1 -1
  50. package/dist/collab/routes.d.ts +2 -2
  51. package/dist/integrations/adapters/slack.js +11 -2
  52. package/dist/integrations/adapters/slack.js.map +1 -1
  53. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  54. package/dist/integrations/pending-tasks-retry-job.js +2 -1
  55. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  56. package/dist/integrations/pending-tasks-store.js +1 -1
  57. package/dist/integrations/pending-tasks-store.js.map +1 -1
  58. package/dist/integrations/plugin.d.ts.map +1 -1
  59. package/dist/integrations/plugin.js +140 -34
  60. package/dist/integrations/plugin.js.map +1 -1
  61. package/dist/integrations/types.d.ts +7 -0
  62. package/dist/integrations/types.d.ts.map +1 -1
  63. package/dist/integrations/types.js.map +1 -1
  64. package/dist/mcp/build-server.d.ts.map +1 -1
  65. package/dist/mcp/build-server.js +82 -28
  66. package/dist/mcp/build-server.js.map +1 -1
  67. package/dist/notifications/routes.d.ts +1 -1
  68. package/dist/observability/routes.d.ts +5 -5
  69. package/dist/secrets/routes.d.ts +9 -9
  70. package/docs/content/external-agents.mdx +17 -11
  71. package/docs/content/locales/ar-SA/external-agents.mdx +6 -2
  72. package/docs/content/locales/de-DE/external-agents.mdx +6 -2
  73. package/docs/content/locales/es-ES/external-agents.mdx +6 -2
  74. package/docs/content/locales/fr-FR/external-agents.mdx +6 -2
  75. package/docs/content/locales/hi-IN/external-agents.mdx +6 -2
  76. package/docs/content/locales/ja-JP/external-agents.mdx +6 -2
  77. package/docs/content/locales/ko-KR/external-agents.mdx +6 -2
  78. package/docs/content/locales/pt-BR/external-agents.mdx +6 -2
  79. package/docs/content/locales/zh-CN/external-agents.mdx +6 -2
  80. package/docs/content/locales/zh-TW/external-agents.mdx +6 -2
  81. package/package.json +1 -1
@@ -74,6 +74,7 @@ import {
74
74
  useUpdateEvent,
75
75
  useDeleteEvent,
76
76
  useRsvpEvent,
77
+ findEventByCurrentOrReplacedId,
77
78
  prefetchEvents,
78
79
  shouldShowEventsSkeleton,
79
80
  } from "@/hooks/use-events";
@@ -778,12 +779,30 @@ export default function CalendarView() {
778
779
  ],
779
780
  );
780
781
 
782
+ useEffect(() => {
783
+ if (sidebarEvent) {
784
+ const rebound = findEventByCurrentOrReplacedId(events, sidebarEvent.id);
785
+ if (rebound && rebound.id !== sidebarEvent.id) setSidebarEvent(rebound);
786
+ }
787
+ if (focusedEvent) {
788
+ const rebound = findEventByCurrentOrReplacedId(events, focusedEvent.id);
789
+ if (rebound && rebound.id !== focusedEvent.id) setFocusedEvent(rebound);
790
+ }
791
+ }, [events, focusedEvent, setFocusedEvent, setSidebarEvent, sidebarEvent]);
792
+
781
793
  const selectedEvent = useMemo(() => {
782
794
  const candidate = sidebarEvent ?? focusedEvent;
783
795
  if (!candidate) return null;
784
- return events.find((event) => event.id === candidate.id) ?? candidate;
796
+ return findEventByCurrentOrReplacedId(events, candidate.id) ?? candidate;
785
797
  }, [events, sidebarEvent, focusedEvent]);
786
798
 
799
+ const refreshedSidebarEvent = useMemo(() => {
800
+ if (!sidebarEvent) return null;
801
+ return (
802
+ findEventByCurrentOrReplacedId(events, sidebarEvent.id) ?? sidebarEvent
803
+ );
804
+ }, [events, sidebarEvent]);
805
+
787
806
  function handleNavigate(direction: "prev" | "next") {
788
807
  const fns =
789
808
  direction === "next"
@@ -1762,7 +1781,7 @@ export default function CalendarView() {
1762
1781
  {/* Event detail sidebar — full height, outside the calendar column */}
1763
1782
  {eventDetailSidebar && (
1764
1783
  <EventDetailPanel
1765
- event={sidebarEvent}
1784
+ event={refreshedSidebarEvent}
1766
1785
  onClose={() => setSidebarEvent(null)}
1767
1786
  onDelete={handleDeleteEvent}
1768
1787
  onTitleSave={handleTitleSave}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-07
4
+ ---
5
+
6
+ Working locations now appear in a dedicated non-blocking lane and can be changed between Home, Office, and Other for one day or an entire recurring series.
@@ -5,6 +5,7 @@ type AvailabilityEvent = Pick<
5
5
  | "accountEmail"
6
6
  | "attendees"
7
7
  | "end"
8
+ | "eventType"
8
9
  | "responseStatus"
9
10
  | "start"
10
11
  | "status"
@@ -25,6 +26,7 @@ function findSelfAttendee(event: AvailabilityEvent) {
25
26
  export function eventBlocksAvailability(event: AvailabilityEvent): boolean {
26
27
  if (!event.start || !event.end) return false;
27
28
  if (event.status === "cancelled") return false;
29
+ if (event.eventType === "workingLocation") return false;
28
30
  if (event.transparency === "transparent") return false;
29
31
 
30
32
  const selfAttendee = findSelfAttendee(event);
@@ -401,9 +401,14 @@ export function calendarUpdateEvent(
401
401
  calendarId: string,
402
402
  eventId: string,
403
403
  body: any,
404
+ params?: {
405
+ sendUpdates?: string;
406
+ conferenceDataVersion?: number;
407
+ supportsAttachments?: boolean;
408
+ },
404
409
  ) {
405
410
  return googleFetch(
406
- `${CALENDAR_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}`,
411
+ `${CALENDAR_BASE}/calendars/${encodeURIComponent(calendarId)}/events/${encodeURIComponent(eventId)}${qs(params ?? {})}`,
407
412
  accessToken,
408
413
  {
409
414
  method: "PUT",
@@ -29,6 +29,7 @@ import {
29
29
  calendarInsertEvent,
30
30
  calendarDeleteEvent,
31
31
  calendarPatchEvent,
32
+ calendarUpdateEvent,
32
33
  peopleGetProfile,
33
34
  } from "./google-api.js";
34
35
  import {
@@ -1122,12 +1123,15 @@ export async function createEvent(
1122
1123
  throw new Error("Out of office and focus time events must be timed.");
1123
1124
  }
1124
1125
 
1125
- const body: any = {
1126
- summary: event.title,
1127
- description: event.description,
1128
- location: event.location,
1129
- ...buildDateRange(event),
1130
- };
1126
+ const body: any =
1127
+ event.eventType === "workingLocation"
1128
+ ? buildDateRange(event)
1129
+ : {
1130
+ summary: event.title,
1131
+ description: event.description,
1132
+ location: event.location,
1133
+ ...buildDateRange(event),
1134
+ };
1131
1135
  applyEventOptions(body, event);
1132
1136
  if (event.attachments !== undefined) {
1133
1137
  body.attachments = event.attachments;
@@ -1218,7 +1222,10 @@ export async function updateEvent(
1218
1222
  if (eventPatch.title !== undefined) requestBody.summary = eventPatch.title;
1219
1223
  if (eventPatch.description !== undefined)
1220
1224
  requestBody.description = eventPatch.description;
1221
- if (eventPatch.location !== undefined)
1225
+ if (
1226
+ eventPatch.location !== undefined &&
1227
+ eventPatch.workingLocationProperties === undefined
1228
+ )
1222
1229
  requestBody.location = eventPatch.location;
1223
1230
  if (eventPatch.start !== undefined) {
1224
1231
  requestBody.start = eventPatch.allDay
@@ -1260,18 +1267,41 @@ export async function updateEvent(
1260
1267
  requestBody.conferenceData = createGoogleMeetRequest();
1261
1268
  }
1262
1269
 
1263
- const response = await calendarPatchEvent(
1264
- client.accessToken,
1265
- "primary",
1266
- targetEventId,
1267
- requestBody,
1268
- {
1269
- sendUpdates: options?.sendUpdates,
1270
- conferenceDataVersion: options?.addGoogleMeet ? 1 : undefined,
1271
- supportsAttachments:
1272
- eventPatch.attachments !== undefined ? true : undefined,
1273
- },
1274
- );
1270
+ // Google validates status events as complete resources during updates. A
1271
+ // partial PATCH can reject otherwise valid working-location changes because
1272
+ // required eventType/start/end fields are absent from the request body.
1273
+ const response = eventPatch.workingLocationProperties
1274
+ ? await calendarUpdateEvent(
1275
+ client.accessToken,
1276
+ "primary",
1277
+ targetEventId,
1278
+ {
1279
+ ...(await calendarGetEvent(
1280
+ client.accessToken,
1281
+ "primary",
1282
+ targetEventId,
1283
+ )),
1284
+ ...requestBody,
1285
+ },
1286
+ {
1287
+ sendUpdates: options?.sendUpdates,
1288
+ conferenceDataVersion: options?.addGoogleMeet ? 1 : undefined,
1289
+ supportsAttachments:
1290
+ eventPatch.attachments !== undefined ? true : undefined,
1291
+ },
1292
+ )
1293
+ : await calendarPatchEvent(
1294
+ client.accessToken,
1295
+ "primary",
1296
+ targetEventId,
1297
+ requestBody,
1298
+ {
1299
+ sendUpdates: options?.sendUpdates,
1300
+ conferenceDataVersion: options?.addGoogleMeet ? 1 : undefined,
1301
+ supportsAttachments:
1302
+ eventPatch.attachments !== undefined ? true : undefined,
1303
+ },
1304
+ );
1275
1305
 
1276
1306
  return {
1277
1307
  htmlLink: response?.htmlLink || undefined,
@@ -122,6 +122,8 @@ export interface CalendarEvent {
122
122
  updatedAt: string;
123
123
  /** Client-only: temp id preserved across optimistic→real swap to keep React keys stable */
124
124
  _tempId?: string;
125
+ /** Client-only: prior provider id retained while open UI state rebinds after replacement */
126
+ _replacedId?: string;
125
127
  }
126
128
 
127
129
  export interface CalendarEventDraft {
@@ -1 +1 @@
1
- {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/client/session-replay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/client/session-replay.ts"],"names":[],"mappings":"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"}
@@ -127,6 +127,7 @@ function getState() {
127
127
  queue: [],
128
128
  queuedBytes: 0,
129
129
  retryBatches: [],
130
+ transientClientErrorFailures: 0,
130
131
  flushTimer: null,
131
132
  maxDurationTimer: null,
132
133
  flushing: false,
@@ -149,6 +150,7 @@ function getState() {
149
150
  const state = g[SESSION_REPLAY_STATE_KEY];
150
151
  // Keep Vite HMR safe when an older recorder state survives a module reload.
151
152
  state.resourceNodes ??= new Map();
153
+ state.transientClientErrorFailures ??= 0;
152
154
  state.restoreIframeBridge ??= null;
153
155
  state.pendingFlushReason ??= null;
154
156
  state.pendingFlushWaiters ??= [];
@@ -658,14 +660,12 @@ const REPLAY_RESOURCE_TAGS = new Set([
658
660
  "audio",
659
661
  "track",
660
662
  "input",
661
- "object",
662
663
  "link",
663
664
  ]);
664
665
  const NO_REPLAY_RESOURCE_ATTRIBUTES = new Set();
665
666
  const REPLAY_SRC_ATTRIBUTES = new Set(["src"]);
666
667
  const REPLAY_SRCSET_ATTRIBUTES = new Set(["src", "srcset"]);
667
668
  const REPLAY_VIDEO_ATTRIBUTES = new Set(["src", "poster"]);
668
- const REPLAY_OBJECT_ATTRIBUTES = new Set(["data"]);
669
669
  const REPLAY_HREF_ATTRIBUTES = new Set(["href"]);
670
670
  function replayAttributeString(attributes, key) {
671
671
  return typeof attributes[key] === "string"
@@ -696,8 +696,6 @@ function replayPreservedResourceAttributes(node) {
696
696
  case "audio":
697
697
  case "track":
698
698
  return REPLAY_SRC_ATTRIBUTES;
699
- case "object":
700
- return REPLAY_OBJECT_ATTRIBUTES;
701
699
  case "input":
702
700
  return node.type === "image"
703
701
  ? REPLAY_SRC_ATTRIBUTES
@@ -991,11 +989,16 @@ class ReplayUploadHttpError extends Error {
991
989
  }
992
990
  /** 4xx statuses where retrying the exact same batch can never succeed.
993
991
  * Keep this deliberately narrow: 401/403/404 can be temporary during auth or
994
- * deploy transitions, and stopping forever on one of those would silently
995
- * black out the rest of a long-lived SPA session. */
992
+ * deploy transitions, so they get a small retry budget before the rejected
993
+ * episode is stopped. The budget prevents a persistent configuration failure
994
+ * from pinning retryBatches while rrweb events grow without bound. */
996
995
  function isDefinitiveReplayUploadClientError(status) {
997
996
  return status === 400 || status === 409 || status === 413 || status === 422;
998
997
  }
998
+ const MAX_TRANSIENT_REPLAY_CLIENT_FAILURES = 3;
999
+ function isTransientReplayUploadClientError(status) {
1000
+ return status === 401 || status === 403 || status === 404;
1001
+ }
999
1002
  async function sendReplayUpload(options, body, callbacks = {}) {
1000
1003
  if (isCrossOriginReplayEndpoint(options.endpoint)) {
1001
1004
  const canUseKeepalive = canUseReplayKeepalive(body);
@@ -1229,6 +1232,7 @@ export async function flushSessionReplay(reason = "manual") {
1229
1232
  if (!reservedSequence)
1230
1233
  advanceReplaySequence(state, payload);
1231
1234
  state.automaticConflictRestartAttempted = false;
1235
+ state.transientClientErrorFailures = 0;
1232
1236
  uploaded = true;
1233
1237
  }
1234
1238
  catch (error) {
@@ -1241,8 +1245,20 @@ export async function flushSessionReplay(reason = "manual") {
1241
1245
  const rejectedStatus = error instanceof ReplayUploadHttpError ? error.status : null;
1242
1246
  const splitBatch = rejectedStatus === 413 ? splitReplayBatch(events) : null;
1243
1247
  const isUnsplittableOversizedBatch = rejectedStatus === 413 && splitBatch === null;
1248
+ const isTransientClientError = rejectedStatus !== null &&
1249
+ isTransientReplayUploadClientError(rejectedStatus);
1250
+ if (isTransientClientError) {
1251
+ state.transientClientErrorFailures += 1;
1252
+ }
1253
+ else {
1254
+ state.transientClientErrorFailures = 0;
1255
+ }
1256
+ const exhaustedTransientClientRetries = isTransientClientError &&
1257
+ state.transientClientErrorFailures >=
1258
+ MAX_TRANSIENT_REPLAY_CLIENT_FAILURES;
1244
1259
  const isDefinitiveClientError = error instanceof ReplayUploadHttpError &&
1245
- isDefinitiveReplayUploadClientError(error.status) &&
1260
+ (isDefinitiveReplayUploadClientError(error.status) ||
1261
+ exhaustedTransientClientRetries) &&
1246
1262
  !splitBatch &&
1247
1263
  !isUnsplittableOversizedBatch;
1248
1264
  if (splitBatch) {
@@ -2202,6 +2218,7 @@ export async function startSessionReplay(options = {}) {
2202
2218
  // This is a new caller-initiated recording episode. A prior episode's
2203
2219
  // conflict-loop guard must not prevent this one from recovering once.
2204
2220
  state.automaticConflictRestartAttempted = false;
2221
+ state.transientClientErrorFailures = 0;
2205
2222
  const startGeneration = ++state.startGeneration;
2206
2223
  let startPromise;
2207
2224
  startPromise = startSessionReplayRecorder(state, normalized, sessionId, sampled, initialProperties, startGeneration).finally(() => {