{
  "interval": {
    "intervalStart": "2026-04-24T00:00:00.000Z",
    "intervalEnd": "2026-04-25T00:00:00.000Z",
    "intervalType": "day"
  },
  "repository": "elizaos/eliza",
  "overview": "From 2026-04-24 to 2026-04-25, elizaos/eliza had 25 new PRs (24 merged), 0 new issues, and 8 active contributors.",
  "topIssues": [
    {
      "id": "I_kwDOMT5cIs8AAAABAW0dtw",
      "title": "Trustless Agent-to-Agent Deals via Local ZK Proofs",
      "author": "jvonb",
      "number": 7073,
      "repository": "elizaos/eliza",
      "body": "**Is your feature request related to a problem? Please describe.**\n\nEliza agents are getting insanely smart, but when Agent A interacts with Agent B, there is no decentralized, private way to verify state without leaking the underlying data of the prompt/decision engine to a centralized server\n\n**Describe the solution you'd like**\n\nA sidecar integration where Eliza agents compute ZK-proofs locally before talking to other agents. I've built a universal Trust Layer for this called **[Project Rohan](https://github.com/rohan-protocol/sdk)**. It uses the Midnight Blockchain to settle agent-deals trustlessly via a Gasless Relayer.\n\nInstead of raw API handshakes, the Eliza agent simply routes the payload through the local prover:\n`await agent.handshake(contractRef, mySecretLogic)`\n\n\n**Additional context**\n\nWe'd love to build an official Eliza-Plugin for this. Are there specific plugin architecture guidelines we should follow for cryptographic sidecars? We've already tested the node.js bindings and the relayer architecture works flawlessly.\n",
      "createdAt": "2026-04-23T21:08:42Z",
      "closedAt": "2026-04-24T04:21:42Z",
      "state": "CLOSED",
      "commentCount": 0
    }
  ],
  "topPRs": [
    {
      "id": "PR_kwDOMT5cIs7VOn2b",
      "title": "Shaw/wallet runtime fix",
      "author": "lalalune",
      "number": 7089,
      "body": "<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR bundles several related improvements: wrapping Discord message metadata enrichment in try-catch for resilience, a new `parseActivityInteger` helper that enforces proper pagination validation on the relationships activity endpoint, paginated load-more in the activity feed UI, a mobile chat surface redesign (drawer → inline panel switcher), popup-blocker avoidance in `GameView`, and a policy change that keeps `workspace:*` as the committed source state for monorepo deps (materializing exact npm versions only at the Docker deploy boundary).\n\n<h3>Confidence Score: 5/5</h3>\n\nSafe to merge; all remaining findings are P2 quality/style issues that do not block production behavior.\n\nThe core runtime fixes (try-catch around Discord enrichment, pagination validation) are correct and defensive. The workspace:* policy change and Dockerfile refactor appear intentional and internally consistent. The two remaining P2 findings (missing cancellation guard in loadMore, implicit @elizaos/core transitive resolution in Docker) are worth a follow-up but do not block the PR.\n\npackages/app-core/deploy/Dockerfile.cloud (verify @elizaos/core resolves transitively after pruning) and packages/app-core/src/components/pages/relationships/RelationshipsActivityFeed.tsx (loadMore unmount guard)\n\n<h3>Important Files Changed</h3>\n\n\n\n\n| Filename | Overview |\n|----------|----------|\n| packages/agent/src/api/conversation-routes.ts | Discord message metadata enrichment wrapped in try-catch for resilience; `cacheDiscordAvatarForRuntime` is now a best-effort operation only |\n| packages/agent/src/api/relationships-routes.ts | New `parseActivityInteger` helper validates pagination params and returns 400 for invalid/negative values — clean improvement over the old loose parseInt calls |\n| packages/app-core/deploy/Dockerfile.cloud | Refactored inline one-liner to readable heredoc script; materializes workspace:* deps for cloud-agent-template at build time; `@elizaos/core` removed from ALLOW set — agent's workspace:* reference will be pruned, relying on transitive resolution |\n| packages/app-core/deploy/cloud-agent-template/package.json | Dependencies changed from pinned registry versions to workspace:* — materialized to exact versions at Docker deploy boundary via Dockerfile.cloud script |\n| packages/app-core/src/components/pages/relationships/RelationshipsActivityFeed.tsx | Pagination and icon improvements; initial load uses cancellation guard but `loadMore` does not — state updates can fire on unmounted component |\n| packages/app-core/src/App.tsx | Mobile chat surface navigation redesigned from a drawer-based to inline panel switching (left/center/right surfaces); simplifies state from two booleans to one enum |\n| packages/app-core/src/components/apps/GameView.tsx | Added `preOpenWindow`/`navigatePreOpenedWindow` to avoid popup-blocker for external URLs; new diagnostics panel and improved game status labeling |\n| packages/app-core/src/api/client-agent.ts | Added `offset` param to `getRelationshipsActivity` and `scope` param to graph/people queries; explicit return type added to activity fetch |\n| packages/app-core/src/api/client-types-relationships.ts | Added pagination metadata (total, offset, limit, hasMore) to RelationshipsActivityResponse and typed merge candidate evidence |\n| packages/app-core/src/components/workspace/AppWorkspaceChrome.tsx | Added `chatDisabled` prop, mobile pane switcher component, and workspace sidebar control registration — enables game views to own their chat surface |\n\n</details>\n\n\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Server as relationships-routes\n    participant DB\n\n    Client->>Server: GET /api/relationships/activity?limit=25&offset=0\n    Server->>Server: parseActivityInteger(limit, 50, {min:1, max:100})\n    Server->>Server: parseActivityInteger(offset, 0, {min:0})\n    alt invalid params\n        Server-->>Client: 400 Invalid pagination\n    else valid params\n        Server->>DB: query activity (limit, offset)\n        DB-->>Server: rows + total count\n        Server-->>Client: {activity[], total, count, offset, limit, hasMore}\n    end\n    Client->>Client: render page 1\n    Client->>Server: GET /api/relationships/activity?limit=25&offset=25\n    Server->>DB: query activity (limit=25, offset=25)\n    DB-->>Server: rows + total count\n    Server-->>Client: {activity[], hasMore}\n    Client->>Client: append to activity list\n```\n\n<!-- greptile_failed_comments -->\n<details><summary><h3>Comments Outside Diff (1)</h3></summary>\n\n1. `packages/agent/src/api/conversation-routes.ts`, line 977-1048 ([link](https://github.com/elizaos/eliza/blob/f46104cc5378ba2d142f0ffdeb5c6c7ef6953900/packages/agent/src/api/conversation-routes.ts#L977-L1048)) \n\n   <a href=\"#\"><img alt=\"P2\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=7\" align=\"top\"></a> **`cacheDiscordAvatarForRuntime` silently skipped on profile errors**\n\n   Previously `cacheDiscordAvatarForRuntime` was called unconditionally after profile enrichment. Now it only runs if the entire try-block succeeds. If `resolveStoredDiscordEntityProfile` or `resolveDiscordMessageAuthorProfile` throws, `message.avatarUrl` is never updated — the message ships with a raw CDN URL rather than a cached one. This is intentional as a resilience fix, but worth documenting explicitly so future callers know avatar caching is best-effort.\n\n</details>\n\n<!-- /greptile_failed_comments -->\n\n<sub>Reviews (1): Last reviewed commit: [\"refactor: remove wallet market status ta...\"](https://github.com/elizaos/eliza/commit/f46104cc5378ba2d142f0ffdeb5c6c7ef6953900) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=29565457)</sub>\n\n> Greptile also left **2 inline comments** on this PR.\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-04-24T06:08:33Z",
      "mergedAt": null,
      "additions": 7114,
      "deletions": 2814
    },
    {
      "id": "PR_kwDOMT5cIs7VSiXK",
      "title": "feat: open app surfaces in managed desktop windows",
      "author": "Dexploarer",
      "number": 7092,
      "body": "## Plan\n- Open app catalog selections in managed Electrobun windows using the existing native toolbar-backed surfaces.\n- Keep detached windows connected to page-scoped chat/control context.\n- Add targeted coverage for always-on-top controls and the duplicate launch guard.\n\n## Patch summary\n- Electrobun: add managed app window RPCs, always-on-top toggles, and explicit webview load handling for detached windows.\n- Apps: add App Windows controls, hash-safe detached app routes, and prevent manual launches from being replayed by slug auto-launch.\n- Agent chat: add Connectors, Plugins, and Settings page scopes so detached surfaces retain scoped chat context.\n\n## Validation\n- `bunx @biomejs/biome check <touched files>`\n- `bunx vitest run eliza/packages/app-core/src/components/pages/AppsView.test.tsx eliza/packages/app-core/src/components/pages/page-scoped-conversations.test.ts eliza/packages/app-core/src/components/workspace/AppWorkspaceChrome.test.tsx eliza/packages/agent/src/api/conversation-metadata.test.ts --passWithNoTests`\n- `(cd packages/app-core/platforms/electrobun && bun run test -- src/surface-windows.test.ts src/native/canvas.test.ts)`\n- `(cd packages/app-core && bun run typecheck)`\n- `bun run dev:desktop -- --force-renderer`\n- Live smoke: clicked Apps -> Plugin Viewer; one elizaOS Plugins window opened, loaded the existing Plugins surface, and showed the Plugins chat panel.\n\n## Notes\n- Direct upstream push was denied for Dexploarer, so this PR is opened from the fork branch.\n- Desktop dev still reports existing whisper.cpp and n8n sidecar warnings; they are unrelated to this patch.\n\n<!-- greptile_comment -->\n\n<details><summary><h3>Greptile Summary</h3></summary>\n\nThis PR wires up app catalog selections to open in managed Electrobun desktop windows, adds always-on-top controls for both managed surface windows and canvas/game windows, introduces concurrent-open coalescing for detached surfaces, and extends chat scope to cover Connectors, Plugins, and Settings views in detached windows. The previously flagged issues — silent no-op on `setAlwaysOnTop`, stale pin state on canvas window failure, and the `shouldUseHashNavigation` duplication — are all resolved in this patch.\n</details>\n\n<h3>Confidence Score: 5/5</h3>\n\nSafe to merge — all previously flagged issues are addressed and no new P0/P1 defects found.\n\nThe patch resolves every issue from the prior review thread: setAlwaysOnTop now returns {success:boolean} instead of silently no-opping, the alwaysOnTop state on canvasListWindows failure is handled in a try/catch, shouldUseHashNavigation duplication is eliminated by extracting shared utilities to navigation/index.ts, and the duplicate-surface-window guard is implemented via openSurfaceWindowOnce. New tests cover the concurrent-open coalescing, singleton guard, explicit webview loadURL, and the always-on-top toggle contract. No P1 or P0 issues found in the new code paths.\n\nNo files require special attention.\n\n<details><summary><h3>Important Files Changed</h3></summary>\n\n| Filename | Overview |\n|----------|----------|\n| packages/app-core/platforms/electrobun/src/surface-windows.ts | Adds openAppWindow, concurrent-open coalescing via pendingSurfaceWindows, setWindowAlwaysOnTop, and explicit webview loadURL. Singleton guard for detached surfaces is now present; loadURL deferred via setTimeout(0) to allow webview to initialize. |\n| packages/app-core/src/components/pages/AppsView.tsx | Adds AppWindowRecord tracking, heartbeat loop, desktop window event subscriptions, and the App Windows control strip. slugAutoLaunchDone.current is now set before the slug lookup to prevent re-launch after a manual catalog open updates the URL — intentional guard. |\n| packages/app-core/platforms/electrobun/src/rpc-handlers.ts | Adds desktopOpenAppWindow, desktopSetManagedWindowAlwaysOnTop, and canvasSetAlwaysOnTop RPC handlers. normalizeRendererRoutePath validates the incoming path is a renderer route before it reaches the URL builder. |\n| packages/app-core/platforms/electrobun/src/native/canvas.ts | Adds setAlwaysOnTop (returns {success: boolean}), exposes alwaysOnTop in listWindows output, and accepts alwaysOnTop in openGameWindow. Addresses the previously flagged silent no-op issue. |\n| packages/app-core/platforms/electrobun/src/native/desktop.ts | Adds openAppWindowCallback and managedWindowAlwaysOnTopCallback wiring. openSurfaceWindow now returns a ManagedWindowSnapshot rather than void, enabling callers to receive the created window ID. |\n| packages/app-core/platforms/electrobun/src/rpc-schema.ts | Schema-level additions: DesktopManagedWindowSnapshot, desktopOpenAppWindow, desktopSetManagedWindowAlwaysOnTop, canvasSetAlwaysOnTop, desktopManagedWindowsChanged push event, and alwaysOnTop on canvas/game types. |\n| packages/app-core/src/navigation/index.ts | Extracts shouldUseHashNavigation, getWindowNavigationPath, and isAppWindowRoute into shared utilities, eliminating the previously flagged duplication across AppsView, AppsPageView, AppContext, and useNavigationState. |\n| packages/agent/src/api/conversation-metadata.ts | Adds page-connectors, page-plugins, and page-settings to VALID_SCOPES. page-settings was already in the ConversationScope type union but was missing from the runtime validation set — this is a correct sync fix. |\n| packages/app-core/src/shell/DetachedShellRoot.tsx | Wraps connectors, plugins, triggers, and settings detached views in DetachedWorkspaceView to provide scoped chat context. Settings section gains overflow-y-auto for scroll. |\n| packages/app-core/src/components/apps/GameView.tsx | Adds always-on-top toggle button for game windows with try/catch guard on canvasListWindows fetch (addressing previous stale-state comment) and success-response check before updating local state. |\n| packages/app-core/platforms/electrobun/src/surface-windows.test.ts | New test file covering surface URL building, singleton guard, concurrent-open coalescing, and explicit webview loadURL. Good coverage of the new deduplication logic. |\n| packages/app-core/platforms/electrobun/src/native/canvas.test.ts | New test file covering openGameWindow with alwaysOnTop, setAlwaysOnTop toggle, and failure path for missing window IDs. Validates the { success: boolean } return contract. |\n\n</details>\n\n</details>\n\n<details><summary><h3>Sequence Diagram</h3></summary>\n\n```mermaid\nsequenceDiagram\n    participant UI as AppsView (Renderer)\n    participant Bridge as Desktop Bridge (RPC)\n    participant SM as SurfaceWindowManager\n    participant DM as DesktopManager\n    participant CM as CanvasManager\n\n    Note over UI: User clicks catalog app\n\n    alt Internal tool app (plugins/connectors/browser/triggers)\n        UI->>Bridge: desktopOpenSurfaceWindow(surface, alwaysOnTop)\n        Bridge->>DM: openSurfaceWindow()\n        DM->>SM: openSurfaceWindow(surface, browse, alwaysOnTop)\n        SM->>SM: Check pendingSurfaceWindows (coalesce)\n        SM->>SM: Check existing window (singleton guard)\n        SM-->>UI: ManagedWindowSnapshot {id, alwaysOnTop}\n        SM->>UI: desktopManagedWindowsChanged push event\n    else External viewer app (game/canvas)\n        UI->>Bridge: gameOpenWindow(url, title, alwaysOnTop)\n        Bridge->>CM: openGameWindow(url, alwaysOnTop)\n        CM-->>UI: {id}\n        Note over UI: Heartbeat loop started\n    else Generic app route\n        UI->>Bridge: desktopOpenAppWindow(title, path, alwaysOnTop)\n        Bridge->>SM: openAppWindow(title, path, alwaysOnTop)\n        SM->>SM: buildAppWindowRendererUrl(rendererUrl, path)\n        Note over SM: URL: host/?appWindow=1#/route\n        SM-->>UI: ManagedWindowSnapshot {id, alwaysOnTop}\n        SM->>UI: desktopManagedWindowsChanged push event\n    end\n\n    Note over UI: Toggle pin on open window\n    alt Managed window\n        UI->>Bridge: desktopSetManagedWindowAlwaysOnTop(id, flag)\n        Bridge->>SM: setWindowAlwaysOnTop(id, flag)\n        SM-->>UI: {success: boolean}\n    else Canvas/game window\n        UI->>Bridge: canvasSetAlwaysOnTop(id, flag)\n        Bridge->>CM: setAlwaysOnTop(id, flag)\n        CM-->>UI: {success: boolean}\n    end\n```\n</details>\n\n<sub>Reviews (2): Last reviewed commit: [\"fix: address managed app window review c...\"](https://github.com/elizaos/eliza/commit/58831fa8e73bc48c4ab8586b9ac1d7780717b2fc) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=29583462)</sub>\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-04-24T09:51:57Z",
      "mergedAt": "2026-04-25T05:31:04Z",
      "additions": 1545,
      "deletions": 114
    },
    {
      "id": "PR_kwDOMT5cIs7VG9uE",
      "title": "feat(lifeops): support multi-calendar Google feeds",
      "author": "dutchiono",
      "number": 7072,
      "body": "This completes the LifeOps multi-calendar stack on the app/runtime side and adds the last safety fallback for hosted cloud lag.\n\n## Included\n- list and persist available calendars in LifeOps settings\n- merge included calendar feeds across calendars/accounts\n- surface calendar origin in merged feeds\n- support cloud-managed secondary calendars\n- fall back to primary aggregation when managed calendar discovery is temporarily unavailable\n\n## Dependency\n- hosted connector route is tracked separately in [cloud#472](https://github.com/elizaOS/cloud/pull/472)\n- this PR intentionally leaves the `cloud` submodule pointer alone until that cloud change lands upstream\n\n## Why\nHosted users were getting blank or incorrect calendar views when the connector only exposed `primary` or when the new managed calendar-list route was not yet deployed. This keeps the UI and agent behavior stable while the cloud route lands.\n\n## Validation\n- `bun run --cwd C:\\Users\\epj33\\Documents\\Playground\\milady\\eliza\\apps\\app-lifeops test -- service-mixin-calendar.test.ts`\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR completes the LifeOps multi-calendar stack: it adds `listCalendars` / `setCalendarIncluded` service methods, a `getCalendarFeed` path that aggregates across all user-enabled calendars (with a fallback to primary when managed calendar discovery is unavailable), per-calendar `includeInFeed` preferences stored in the scheduler task metadata, and UI for toggling calendar visibility in Settings.\n\n- **P1 — multi-account preference key collision**: `calendarFeedIncludes` is keyed only by `calendarId`. Users with two connected Google accounts both have a calendar with `calendarId: \\\"primary\\\"`, so toggling one will silently override the other's preference. The UI already uses a `${grantId}:${calendarId}` composite key for React rendering — the backend persistence and lookup should do the same.\n\n<h3>Confidence Score: 4/5</h3>\n\nSafe to merge for single-account users; multi-account users will see incorrect calendar visibility preferences until the key collision is fixed.\n\nOne P1 correctness issue: calendarFeedIncludes keyed by calendarId alone causes a data collision for any user with two Google accounts sharing a 'primary' calendarId. All other findings are P2 (fragile error string match, unnecessary API call on toggle). The fallback, merge, and UI logic are otherwise well-structured and the new tests give good coverage of the happy paths.\n\napps/app-lifeops/src/lifeops/service-mixin-calendar.ts (preference lookup) and apps/app-lifeops/src/lifeops/owner-profile.ts (preference storage key)\n\n<h3>Important Files Changed</h3>\n\n\n\n\n| Filename | Overview |\n|----------|----------|\n| apps/app-lifeops/src/lifeops/service-mixin-calendar.ts | Core multi-calendar logic: adds listCalendars, setCalendarIncluded, aggregateCalendarFeedsAcrossCalendars, and getCalendarFeed path selection. Has a P1 preference-key collision bug (calendarId-only key breaks multi-account users who both have \"primary\") and a fragile 503 fallback. |\n| apps/app-lifeops/src/lifeops/owner-profile.ts | Adds LifeOpsCalendarFeedPreferences storage: ensureLifeOpsCalendarFeedIncludes and setLifeOpsCalendarFeedIncluded. Logic is clean but the key type (calendarId only) propagates the P1 multi-account collision described in service-mixin-calendar.ts. |\n| apps/app-lifeops/src/lifeops/google-calendar.ts | Adds listGoogleCalendars function fetching calendarList with minAccessRole=reader. Passes showHidden=false in query params and also filters hidden items in the loop (harmless redundancy). Parsing and normalization look correct. |\n| apps/app-lifeops/src/components/LifeOpsSettingsSection.tsx | Adds calendar list + toggle UI in GoogleConnectorSideCard. Correctly uses cancelled-flag cleanup in useEffect. Local state update after toggle correctly matches on both grantId and calendarId, though the backend ignores grantId when persisting. |\n| apps/app-lifeops/src/routes/lifeops-routes.ts | Adds GET /api/lifeops/calendar/calendars and PUT /api/lifeops/calendar/calendars/:id/include routes. Body/path calendarId consistency check is a good defensive guard. |\n| packages/shared/src/contracts/lifeops.ts | Adds LifeOpsCalendarSummary, ListLifeOpsCalendarsRequest/Response, SetLifeOpsCalendarIncludedRequest/Response types, and extends GetLifeOpsCalendarFeedRequest and LifeOpsCalendarEvent. Type design looks correct. |\n| apps/app-lifeops/src/lifeops/service-mixin-calendar.test.ts | New test file covering mergeAggregatedCalendarFeedEvents deduplication and fallback to primary aggregation on empty or unavailable calendar list. Good coverage of the happy path and the 503 fallback. |\n| apps/app-lifeops/src/lifeops/owner-profile.test.ts | Tests for ensureLifeOpsCalendarFeedIncludes (default-true for new, preserve false for existing) and setLifeOpsCalendarFeedIncluded explicit toggle. Tests verify the calendarId-only key behavior — which means they pass even with the multi-account collision issue. |\n| apps/app-lifeops/src/lifeops/google-managed-client.ts | Adds ManagedGoogleCalendarSummaryResponse interface and listCalendars method on GoogleManagedClient. Straightforward delegation to the managed API. |\n| apps/app-lifeops/src/components/LifeOpsWorkspaceView.tsx | Adds eventOriginLabel helper combining calendarSummary and accountEmail; replaces raw accountEmail with it in AccountBadge. Clean change. |\n| apps/app-lifeops/src/components/chat/widgets/plugins/lifeops-channels.tsx | Adds empty-state label and sub-line calendarSummary display to the calendar widget. Structural change from items-center to items-start is appropriate for multi-line event rows. |\n| packages/app-core/src/api/client-lifeops.ts | Adds getLifeOpsCalendars and setLifeOpsCalendarIncluded client methods using appendOptionalParam; mirrors the app-lifeops client implementation. |\n\n</details>\n\n\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant UI as Settings UI\n    participant Client as ElizaClient\n    participant Route as lifeops-routes\n    participant Svc as LifeOpsService\n    participant GMC as GoogleManagedClient\n    participant GCal as Google CalendarList API\n    participant Profile as owner-profile (Task)\n\n    UI->>Client: getLifeOpsCalendars({side, mode})\n    Client->>Route: GET /api/lifeops/calendar/calendars\n    Route->>Svc: listCalendars(url, request)\n    alt cloud_managed grant\n        Svc->>GMC: listCalendars({side, grantId})\n        GMC-->>Svc: ManagedGoogleCalendarSummaryResponse[]\n    else browser/local grant\n        Svc->>GCal: GET calendarList (Bearer token)\n        GCal-->>Svc: GoogleCalendarListEntry[]\n    end\n    Svc->>Profile: ensureLifeOpsCalendarFeedIncludes(calendarIds)\n    Profile-->>Svc: LifeOpsCalendarFeedPreferences\n    Svc-->>Route: LifeOpsCalendarSummary[] (includeInFeed merged)\n    Route-->>Client: { calendars }\n    Client-->>UI: render toggle list\n\n    UI->>Client: setLifeOpsCalendarIncluded({calendarId, includeInFeed, grantId})\n    Client->>Route: PUT /api/lifeops/calendar/calendars/:id/include\n    Route->>Svc: setCalendarIncluded(url, request)\n    Svc->>Svc: listCalendars() — verify existence\n    Svc->>Profile: setLifeOpsCalendarFeedIncluded(calendarId, included)\n    Profile-->>Svc: updated LifeOpsCalendarFeedPreferences\n    Svc-->>Route: updated LifeOpsCalendarSummary\n    Route-->>Client: { calendar }\n    Client-->>UI: optimistic local state update\n```\n\n<!-- greptile_failed_comments -->\n<details><summary><h3>Comments Outside Diff (3)</h3></summary>\n\n1. `apps/app-lifeops/src/lifeops/service-mixin-calendar.ts`, line 1350-1358 ([link](https://github.com/elizaos/eliza/blob/08fdc406cdcb575815fa342c4392a23246aa70e5/apps/app-lifeops/src/lifeops/service-mixin-calendar.ts#L1350-L1358)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> **Calendar preference key collision for multi-account users**\n\n   `calendarFeedIncludes` is stored as `Record<string, boolean>` keyed only by `calendarId`. Google's calendarList API returns `\"primary\"` as the `calendarId` for every account's primary calendar — so two connected Google accounts will share the same key in the preferences store. Toggling the primary calendar on account A will silently affect account B's primary calendar visibility as well.\n\n   The UI already uses the composite key `${calendar.grantId}:${calendar.calendarId}` for React's `key` prop and for local-state matching after a toggle, but the backend drops `grantId` before persisting. The preference lookup here also ignores `grantId`:\n\n   ```ts\n   preferences.calendarFeedIncludes[summary.calendarId] !== false\n   ```\n\n   The fix is to key preferences by `${grantId}:${calendarId}` throughout (`ensureLifeOpsCalendarFeedIncludes`, `setLifeOpsCalendarFeedIncluded`, and the lookup in `listCalendars`).\n\n\n2. `apps/app-lifeops/src/lifeops/service-mixin-calendar.ts`, line 1432-1458 ([link](https://github.com/elizaos/eliza/blob/08fdc406cdcb575815fa342c4392a23246aa70e5/apps/app-lifeops/src/lifeops/service-mixin-calendar.ts#L1432-L1458)) \n\n   <a href=\"#\"><img alt=\"P2\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=7\" align=\"top\"></a> **Fragile error-message substring match for 503 fallback**\n\n   The fallback to primary aggregation is gated on `error.message.includes(\"managed calendar-list route\")`. This is a coupling between the error-throw site in `listCalendars` (same file) and this catch site; if the message is ever rephrased or if a different 503 from the managed client triggers `listCalendars`, the fallback silently does not fire.\n\n   Consider using a dedicated error subclass or a typed error code (`error.code === \"MANAGED_CALENDAR_LIST_UNAVAILABLE\"`) that is stable across refactors and locale-agnostic.\n\n\n3. `apps/app-lifeops/src/lifeops/service-mixin-calendar.ts`, line 1380-1401 ([link](https://github.com/elizaos/eliza/blob/08fdc406cdcb575815fa342c4392a23246aa70e5/apps/app-lifeops/src/lifeops/service-mixin-calendar.ts#L1380-L1401)) \n\n   <a href=\"#\"><img alt=\"P2\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=7\" align=\"top\"></a> **`setCalendarIncluded` issues a full Google API round-trip to validate the calendar**\n\n   `setCalendarIncluded` calls `this.listCalendars(...)` — which hits either the managed cloud API or Google's calendarList endpoint for every grant — purely to confirm the target `calendarId` exists before writing the preference. For users with several connected accounts this means multiple external calls on every toggle.\n\n   Consider persisting a local snapshot of known calendars (already returned to the UI) so this validation can be done from cache, or skip the existence check if it's acceptable to trust the client-supplied `calendarId`.\n\n</details>\n\n<!-- /greptile_failed_comments -->\n\n<sub>Reviews (1): Last reviewed commit: [\"fix(lifeops): fall back when managed cal...\"](https://github.com/elizaos/eliza/commit/08fdc406cdcb575815fa342c4392a23246aa70e5) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=29510472)</sub>\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-04-23T20:08:10Z",
      "mergedAt": "2026-04-24T03:23:53Z",
      "additions": 1315,
      "deletions": 35
    },
    {
      "id": "PR_kwDOMT5cIs7VWcWM",
      "title": "fix(character): tokenize name occurrences on save so renames propagate",
      "author": "dutchiono",
      "number": 7093,
      "body": "## Problem\n\nThe character editor already resolves `{{name}}` / `{{agentName}}` tokens on **load** (`replaceNameTokens` in `packages/app-core/src/utils/name-tokens.ts`, seeded by the onboarding presets in `packages/shared/src/onboarding-presets.characters.ts`).\n\nBut `prepareDraftForSave` in `packages/app-core/src/character/character-draft-helpers.ts` never ran the reverse pass. The moment a user saved via the editor, expanded literals got persisted and the tokens were lost forever. From that point on, renaming the agent in Identity settings stopped propagating — bio, system, message examples, post examples, style, and topics all kept the old name as dead text.\n\nUser-visible symptom: renaming the agent requires find-and-replacing the name across ~20 lines of bio, every time.\n\n## Fix\n\nMake save the mirror of load.\n\n- Add `tokenizeNameOccurrences(text, name)` next to `replaceNameTokens`. Whole-word, case-sensitive, idempotent; refuses single-character names to avoid eating prose.\n- `prepareDraftForSave(draft, previousName?)` now runs the tokenizer over every free-text field: `bio`, `system`, `topics`, `postExamples`, `style.{all,chat,post}`, and `messageExamples[].examples[].content.text`. Speaker-label tokenization via `normalizeSpeakerName` is unchanged.\n- Both the current draft name and (optionally) the previous saved name are tokenized so a rename within the same save pass also catches stale old-name literals that the user didn't hand-edit.\n- `useCharacterState.handleSaveCharacter` threads `characterData?.name` through as the previous name.\n\nRuntime prompt composition already resolves `{{name}}` / `{{agentName}}` tokens via `@elizaos/prompts`, so no backend or runtime changes are needed — the fix is purely at the UI persistence boundary.\n\n## Migration\n\nNo explicit one-shot migration needed. The first save after this change tokenizes the character in place, and the load path already renders tokens back to literals for display. Because tokenization is idempotent and case-sensitive/whole-word, re-running it is safe.\n\n## Tests\n\n15 new cases in `packages/app-core/src/utils/name-tokens.test.ts` covering:\n\n- Whole-word boundary behavior (e.g. name \"Kai\" does not match inside \"Kaizen\")\n- Case sensitivity (lowercase \"momo\" is not tokenized when name is \"Momo\")\n- Idempotency (`tokenize(tokenize(x)) === tokenize(x)`)\n- Guardrails (single-character names, empty inputs, regex special chars)\n- `prepareDraftForSave` field coverage: bio / system / topics / postExamples / style / messageExamples bodies\n- Previous-name tokenization during rename\n- Round-trip through `replaceNameTokens` after a rename\n\n```\n Test Files  1 passed (1)\n      Tests  15 passed (15)\n```\n\n## Verified\n\n- `bun run typecheck` — clean\n- `bunx @biomejs/biome check` on all four changed files — clean\n- Unit test suite — 15/15 passing\n\n## Not claimed\n\n- Knowledge / Experience / Relationships tabs may also store the name literally; they're on different API surfaces. If they do, a follow-up PR extends the tokenizer to those endpoints. No change to them here.\n- Nickname / alternate-form support (`{{nickname}}`) is not added. Schema leaves space for it; not needed for the core rename-propagation fix.\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR adds `tokenizeNameOccurrences` and wires it into `prepareDraftForSave` so that literal name text is re-tokenized to `{{name}}` on every save, making agent renames propagate without manual find-and-replace. The approach is sound, but there is a critical asymmetry between the save and load paths.\n\n- **Save path** now tokenizes `bio`, `system`, `topics`, `postExamples`, `style.all/chat/post`, and `messageExamples[].content.text`.\n- **Load path** (`loadCharacter` in `useCharacterState.ts`) applies `replaceNameTokens` only to `bio` and `system` — the four additional field groups are passed through raw. After the first save with this fix, users will see literal `{{name}}` tokens in the Topics, Style, Post Examples, and Message Examples editor fields.\n\n<h3>Confidence Score: 3/5</h3>\n\nNot safe to merge — the save/load asymmetry will surface raw `{{name}}` tokens in the editor UI immediately after first save.\n\nA single clear P1 defect: the save path tokenizes six field groups but the load path only un-tokenizes two, creating an immediate and reproducible UX regression for every user who saves after this change ships.\n\n`packages/app-core/src/state/useCharacterState.ts` — `loadCharacter` must apply `replaceNameTokens` to `topics`, `style.*`, `postExamples`, and `messageExamples[].content.text` to match the expanded save-side coverage.\n\n<h3>Important Files Changed</h3>\n\n\n\n\n| Filename | Overview |\n|----------|----------|\n| packages/app-core/src/state/useCharacterState.ts | Threads `characterData?.name` as `previousName` into `prepareDraftForSave`, but the `loadCharacter` callback only applies `replaceNameTokens` to `bio` and `system` — not to the six field groups now tokenized on save — causing raw `{{name}}` tokens to appear in the editor UI after first save. |\n| packages/app-core/src/character/character-draft-helpers.ts | Adds `previousName` param and applies tokenization across all free-text fields on save; logic is sound, but correctness depends on the load path being symmetrically updated (which it isn't for several field groups). |\n| packages/app-core/src/utils/name-tokens.ts | Adds `tokenizeNameOccurrences` — case-sensitive, whole-word, idempotent, with guardrails for short/empty names and regex-special chars. Word boundary behaviour is limited to ASCII names; non-ASCII names may not tokenize reliably. |\n| packages/app-core/src/utils/name-tokens.test.ts | Good unit coverage of `tokenizeNameOccurrences` and `prepareDraftForSave` field tokenization; missing round-trip tests verifying load-side expansion for `topics`, `style`, `postExamples`, and `messageExamples`. |\n\n</details>\n\n\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant UI as Editor UI\n    participant State as useCharacterState\n    participant Helpers as character-draft-helpers\n    participant API as Backend API\n\n    Note over UI,API: Save flow (this PR)\n    UI->>State: handleSaveCharacter()\n    State->>Helpers: prepareDraftForSave(draft, previousName)\n    Note over Helpers: tokenizes bio, system, topics,<br/>postExamples, style.*, messageExamples\n    Helpers-->>State: tokenized draft\n    State->>API: updateCharacter(tokenizedDraft)\n    API-->>State: success\n    State->>State: loadCharacter()\n\n    Note over UI,API: Load flow (this PR — unchanged)\n    State->>API: getCharacter()\n    API-->>State: character data (with {{name}} tokens)\n    Note over State: clean() applied to bio + system only\n    Note over State: topics / style / postExamples /<br/>messageExamples NOT cleaned ⚠️\n    State->>UI: setCharacterDraft (raw {{name}} tokens visible in editor)\n```\n\n<!-- greptile_failed_comments -->\n<details><summary><h3>Comments Outside Diff (1)</h3></summary>\n\n1. `packages/app-core/src/state/useCharacterState.ts`, line 86-101 ([link](https://github.com/elizaos/eliza/blob/7cb0d48b06af3b7ab64803113994ac619151d18b/packages/app-core/src/state/useCharacterState.ts#L86-L101)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> **Load path doesn't un-tokenize `topics`, `style`, `postExamples`, `messageExamples`**\n\n   `loadCharacter` applies `clean` (i.e. `replaceNameTokens`) to `bio` and `system` only, but `prepareDraftForSave` now tokenizes six additional field groups — `topics`, `postExamples`, `style.all/chat/post`, and `messageExamples[].content.text`. After the first save with this fix, those fields will be persisted with `{{name}}` tokens. On reload, the draft will contain raw token strings such as `\"how {{name}} thinks\"`, which the editor will display verbatim to the user.\n\n   ```ts\n   // before setting the draft, add:\n   const cleanArr = (arr: string[]) => arr.map(clean);\n\n   setCharacterDraft({\n     name: savedName,\n     username: character.username ?? \"\",\n     bio: Array.isArray(character.bio)\n       ? character.bio.map(clean).join(\"\\n\")\n       : clean(character.bio ?? \"\"),\n     system: clean(character.system ?? \"\"),\n     adjectives: character.adjectives ?? [],\n     topics: cleanArr(character.topics ?? []),\n     style: {\n       all: cleanArr(character.style?.all ?? []),\n       chat: cleanArr(character.style?.chat ?? []),\n       post: cleanArr(character.style?.post ?? []),\n     },\n     messageExamples: (character.messageExamples ?? []).map((group) => ({\n       ...group,\n       examples: group.examples.map((ex) => ({\n         ...ex,\n         content: { ...ex.content, text: clean(ex.content.text) },\n       })),\n     })),\n     postExamples: cleanArr(character.postExamples ?? []),\n   });\n   ```\n\n</details>\n\n<!-- /greptile_failed_comments -->\n\n<sub>Reviews (1): Last reviewed commit: [\"fix(character): tokenize name occurrence...\"](https://github.com/elizaos/eliza/commit/7cb0d48b06af3b7ab64803113994ac619151d18b) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=29603728)</sub>\n\n> Greptile also left **1 inline comment** on this PR.\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-04-24T13:37:34Z",
      "mergedAt": null,
      "additions": 389,
      "deletions": 27
    },
    {
      "id": "PR_kwDOMT5cIs7VOtvB",
      "title": "fix(agent): deliver swarm synthesis to the triggering room",
      "author": "NubsCarson",
      "number": 7090,
      "body": "## Summary\n\nThe swarm synthesis path was broken in three stacked ways. When a task agent finished its work (opens a PR, builds a page, fetches data, etc.), nothing was posted back to the triggering room — the agent silently dropped its final result on the floor.\n\n### 1. `setSwarmCompleteCallback` was a no-op\n\n`wireCodingAgentSwarmSynthesis` installed a deliberate no-op with a comment claiming *\"synthesis happens via the streamer instead.\"* In practice `handleSwarmSynthesis` (defined in the same file) is never called anywhere in the repo. Task agents completed, `swarm_complete` fired, the callback ran, returned — no user-facing message was ever emitted.\n\n**Fix:** wire the callback to `await handleSwarmSynthesis(st, payload)`.\n\n### 2. `routeSynthesisToConnector` gated on a field that's never assigned\n\nThe connector-routing path early-returns when `coordinator.sourceRoomId` is null. That field is declared on the coordinator interface but **never assigned anywhere in the orchestrator**, so the path was always dead.\n\n**Fix:** thread a `fallbackRoomId` parameter through `routeSynthesisToConnector`. Derive it from the most recently terminal task in the payload — the task whose completion fired `swarm_complete`, and whose room is waiting for an answer. Naively taking *\"first task with a roomId\"* leaked results into stale rooms when the coordinator carried tasks across rooms. `coordinator.sourceRoomId` is still preferred when set, so any future direct assignment still wins.\n\n### 3. Synthesis rendered a meta-summary instead of the actual result\n\n`buildTaskResultLine` used the coordinator's `completionSummary` as the user-facing output. That's a meta-judgment about *whether* the task finished (\"The agent delivered a complete evening news brief with 7 headlines...\"), not the content the agent produced. The real deliverable — the brief itself, the PR URL line, the built page URL — was sitting unread in the task agent's `claude-code` session transcript.\n\n**Fix:** read the newest `.jsonl` at `~/.claude/projects/<sanitized-workdir>/` and return the last assistant message as the primary synthesis content. Only fall through to `completionSummary` (and then to port-heuristic text) when the jsonl can't be read. The workdir sanitizer replaces both `/` and `.` with `-` so hidden paths like `/home/u/.milady/workspaces/<id>` resolve to their matching project directory.\n\n## Changes\n\nOne file: `packages/agent/src/api/server-helpers-swarm.ts` (+107, -6).\n\n- `wireCodingAgentSwarmSynthesis` now invokes `handleSwarmSynthesis`\n- `handleSwarmSynthesis` payload carries per-task `roomId` and `workdir`\n- `routeSynthesisToConnector` accepts an optional `fallbackRoomId`\n- New `readAgentFinalAssistantMessage(workdir)` helper reads the agent's final message from its claude-code transcript\n- `buildTaskResultLine` prefers the agent's real output over the coordinator's meta-summary\n\n## Test plan\n\n- [x] Verified end-to-end on a real Discord-triggered delegation: user prompt → planner picks SPAWN_AGENT → task agent completes → synthesis posts the actual deliverable into the originating Discord room. Log shows:\n  ```\n  [swarm-synthesis] Generating synthesis for 1 tasks (1 completed, 0 stopped, 0 errored)\n  [swarm-synthesis] Synthesis generated, routing to user\n  [swarm-synthesis] Routed result to discord room <uuid>\n  ```\n- [x] Multi-task swarm where some tasks span different rooms: synthesis lands in the correct (most recently terminal) room, not in a stale room from a sibling task.\n- [x] `tsc --noEmit` clean in `packages/agent`.\n\n## Compatibility notes\n\n- Behavior for turns where `coordinator.sourceRoomId` is actually set (any downstream consumer that populates it): unchanged — still preferred over the fallback.\n- Behavior when the jsonl isn't readable (non-claude task agents, race at early-kill time, etc.): falls back to existing `completionSummary` / port-heuristic path, so no regression vs. pre-patch rendering.\n- Net effect for users relying on the synthesis NOT running (none observed, but noting it): they now get a post-task message where they previously got silence. If that's desired behavior for some deployment, it should be guarded explicitly rather than left to a silent-drop bug.\n",
      "repository": "elizaos/eliza",
      "createdAt": "2026-04-24T06:14:55Z",
      "mergedAt": "2026-04-25T05:30:41Z",
      "additions": 107,
      "deletions": 6
    }
  ],
  "codeChanges": {
    "additions": 1439,
    "deletions": 80,
    "files": 41,
    "commitCount": 99
  },
  "completedItems": [
    {
      "title": "feat(lifeops): support multi-calendar Google feeds",
      "prNumber": 7072,
      "type": "feature",
      "body": "This completes the LifeOps multi-calendar stack on the app/runtime side and adds the last safety fallback for hosted cloud lag.\n\n## Included\n- list and persist available calendars in LifeOps settings\n- merge included calendar feeds across c",
      "files": [
        "apps/app-lifeops/src/actions/calendar.ts",
        "apps/app-lifeops/src/actions/life.ts",
        "apps/app-lifeops/src/actions/owner-calendar.ts",
        "apps/app-lifeops/src/actions/scheduling.ts",
        "apps/app-lifeops/src/api/client-lifeops.ts",
        "apps/app-lifeops/src/components/LifeOpsCalendarSection.tsx",
        "apps/app-lifeops/src/components/LifeOpsSettingsSection.tsx",
        "apps/app-lifeops/src/components/LifeOpsWorkspaceView.tsx",
        "apps/app-lifeops/src/components/chat/widgets/plugins/lifeops-channels.tsx",
        "apps/app-lifeops/src/lifeops/google-calendar.ts",
        "apps/app-lifeops/src/lifeops/google-managed-client.ts",
        "apps/app-lifeops/src/lifeops/owner-profile.test.ts",
        "apps/app-lifeops/src/lifeops/owner-profile.ts",
        "apps/app-lifeops/src/lifeops/service-mixin-calendar.test.ts",
        "apps/app-lifeops/src/lifeops/service-mixin-calendar.ts",
        "apps/app-lifeops/src/routes/lifeops-routes.ts",
        "apps/app-lifeops/src/routes/plugin.ts",
        "packages/app-core/src/api/client-lifeops.ts",
        "packages/shared/src/contracts/lifeops.ts"
      ]
    },
    {
      "title": "chore(deps): update dependency jsdom to v29",
      "prNumber": 7070,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [jsdom](https://redirect.github.com/jsd",
      "files": [
        "apps/app/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency telegram to v2.26.22",
      "prNumber": 7069,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [telegram](https://redirect.github.com/",
      "files": [
        "apps/app-lifeops/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency @elizaos/core to v2.0.0-alpha.335",
      "prNumber": 7068,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| @&#8203;elizaos/core | [`2.0.0-alpha.22",
      "files": [
        "packages/app-core/deploy/cloud-agent-template/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency org.jetbrains.kotlin:kotlin-gradle-plugin to v2.3.21",
      "prNumber": 7067,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [org.jetbrains.kotlin:kotlin-gradle-plu",
      "files": [
        "packages/app-core/platforms/android/build.gradle"
      ]
    },
    {
      "title": "chore(deps): update supabase/postgres docker tag to v17.6.1.110",
      "prNumber": 7066,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Update | Change |\n|---|---|---|\n| supabase/postgres | patch | `17.6.1.109` → `17.6.1.110` |\n\n---\n\n> [!WARNING]\n> Some dependencies could not be looked up. Check the [Dependency Dashboard]",
      "files": [
        "packages/app-core/deploy/docker-compose.supabase-db.yml"
      ]
    },
    {
      "title": "fix(deps): update dependency recharts to v3",
      "prNumber": 7065,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [recharts](https://redirect.github.com/",
      "files": [
        "packages/benchmarks/solana/solana-gym-env/docs/trajectory-viewer/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency react-router-dom to v7",
      "prNumber": 7064,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [react-router-dom](https://redirect.git",
      "files": [
        "packages/benchmarks/solana/solana-gym-env/docs/trajectory-viewer/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency react-markdown to v10",
      "prNumber": 7063,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [react-markdown](https://redirect.githu",
      "files": [
        "packages/benchmarks/solana/solana-gym-env/docs/trajectory-viewer/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency pytz to v2026",
      "prNumber": 7062,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [pytz](http://pythonhosted.org/pytz) | ",
      "files": [
        "packages/benchmarks/OSWorld/pyproject.toml",
        "packages/benchmarks/OSWorld/requirements.txt",
        "packages/benchmarks/OSWorld/uv.lock"
      ]
    },
    {
      "title": "fix(deps): update dependency pytest to v9",
      "prNumber": 7061,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [pytest](https://redirect.github.com/py",
      "files": [
        "packages/benchmarks/adhdbench/pyproject.toml"
      ]
    },
    {
      "title": "fix(deps): update dependency psutil to v7 - autoclosed",
      "prNumber": 7060,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [psutil](https://redirect.github.com/gi",
      "files": [
        "packages/benchmarks/OSWorld/pyproject.toml",
        "packages/benchmarks/OSWorld/requirements.txt",
        "packages/benchmarks/OSWorld/uv.lock"
      ]
    },
    {
      "title": "chore(deps): update dependency vitest to v4",
      "prNumber": 7088,
      "type": "tests",
      "body": "> ℹ️ **Note**\n> \n> This PR body was truncated due to platform limits.\n\nThis PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-con",
      "files": [
        "apps/app/package.json"
      ]
    },
    {
      "title": "chore(deps): update dependency vite to v8",
      "prNumber": 7087,
      "type": "other",
      "body": "> ℹ️ **Note**\n> \n> This PR body was truncated due to platform limits.\n\nThis PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-con",
      "files": [
        "apps/app/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency three to ^0.184.0",
      "prNumber": 7086,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [three](https://threejs.org/) ([source]",
      "files": [
        "apps/app/package.json"
      ]
    },
    {
      "title": "docs: fix typo in deploy-a-project.mdx",
      "prNumber": 7085,
      "type": "bugfix",
      "body": "Fix typo: threshholds -> thresholds in packages/docs/guides/deploy-a-project.mdx.\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR fixes a single spelling typo in `packages/docs/guides/deploy-a-project.mdx`, correcting `thresh",
      "files": [
        "packages/docs/guides/deploy-a-project.mdx"
      ]
    },
    {
      "title": "fix(deps): update dependency com.google.code.gson:gson to v2.14.0",
      "prNumber": 7084,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [com.google.code.gson:gson](https://red",
      "files": [
        "packages/app-core/platforms/android/app/build.gradle"
      ]
    },
    {
      "title": "fix(deps): update dependency @anthropic-ai/sdk to ^0.91.0",
      "prNumber": 7082,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| [@anthropic-ai/sdk](https://redirect.gi",
      "files": [
        "packages/typescript/package.json"
      ]
    },
    {
      "title": "fix(deps): update dependency @elizaos/core to v2.0.0-alpha.339",
      "prNumber": 7081,
      "type": "bugfix",
      "body": "This PR contains the following updates:\n\n| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |\n|---|---|---|---|\n| @&#8203;elizaos/core | [`2.0.0-alpha.33",
      "files": [
        "packages/app-core/deploy/cloud-agent-template/package.json"
      ]
    },
    {
      "title": "docs: fix typo in README",
      "prNumber": 7080,
      "type": "bugfix",
      "body": "Fix a small typo found in documentation.\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR fixes a single-character typo in `packages/docs/README.md`, correcting the GitHub link from `github.com/elizaos/elizaos` to `github.com/",
      "files": [
        "packages/docs/README.md"
      ]
    },
    {
      "title": "fix: correct malformed Anthropic Haiku model ID",
      "prNumber": 7078,
      "type": "bugfix",
      "body": "The default small model ID had typos causing 404 errors from the Anthropic API:\r\n\r\n- plugin-anthropic config/package.json: duplicated suffix \"claude-haiku-4-5-20251001-5-20251001\"\r\n- provider-switch-config: trailing \"-5\" \"claude-haiku-4-5-2",
      "files": [
        "packages/agent/src/api/provider-switch-config.ts",
        "plugins/plugin-anthropic"
      ]
    },
    {
      "title": "fix: reduce excessive frontend polling",
      "prNumber": 7077,
      "type": "bugfix",
      "body": "## Summary\n\nThe frontend makes hundreds of redundant polling requests per minute with no coordination between components and no visibility-based pausing.\n\n### Changes\n\n- **MusicPlayerGlobal**: slowed polling from 2s to 5s\n- **ChatView inbox",
      "files": [
        "packages/app-core/src/components/conversations/ConversationsSidebar.tsx",
        "packages/app-core/src/components/music/MusicPlayerGlobal.tsx",
        "packages/app-core/src/components/pages/BrowserWorkspaceView.tsx",
        "packages/app-core/src/components/pages/ChatView.tsx"
      ]
    },
    {
      "title": "docs: fix typo in readme",
      "prNumber": 7076,
      "type": "bugfix",
      "body": "fixes a small typo\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR fixes a single-character typo in `packages/docs/guides/deploy-a-project.mdx`, correcting \"commited\" to \"committed\" in the Render deployment instructions.\n\n<h3",
      "files": [
        "packages/docs/guides/deploy-a-project.mdx"
      ]
    },
    {
      "title": "fix(message): preserve SPAWN_AGENT against metadata action correction",
      "prNumber": 7075,
      "type": "bugfix",
      "body": "## Summary\n\n`findOwnedActionCorrectionFromMetadata` is a metadata-based safety net that keyword-scores the planner's chosen action against the user message, and upgrades it if any other registered action scores meaningfully higher. This is ",
      "files": [
        "packages/typescript/src/__tests__/owned-action-correction.test.ts",
        "packages/typescript/src/services/message.ts"
      ]
    }
  ],
  "topContributors": [
    {
      "username": "2-A-M",
      "avatarUrl": "https://avatars.githubusercontent.com/u/96268540?u=b7d92c0e2a91af580d09eeae862eef576955ab8a&v=4",
      "totalScore": 148.6450370306403,
      "prScore": 148.6450370306403,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": "2-A-M: Focused on enhancing system stability and resource efficiency, successfully merging four bug fixes that addressed critical authentication credential handling in elizaos/eliza (#7094) and optimized frontend polling performance (#7077). Their work was entirely dedicated to bugfix efforts, including correcting model ID configurations across the elizaos ecosystem."
    },
    {
      "username": "RemilioNubilio",
      "avatarUrl": "https://avatars.githubusercontent.com/u/275382225?u=b1501ee01bb54e5b31ca64895f2a07c69f554a37&v=4",
      "totalScore": 115.05027584517076,
      "prScore": 114.85027584517076,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.2,
      "summary": "RemilioNubilio: Focused on maintaining project stability and documentation quality, notably resolving a critical message handling issue in elizaos/eliza (#7075) to ensure proper metadata preservation. Their work primarily centered on bugfixes and documentation refinements across the codebase."
    },
    {
      "username": "NubsCarson",
      "avatarUrl": "https://avatars.githubusercontent.com/u/192162056?u=d2be9082dbee60fcbad21d32bf6e662ab1af3674&v=4",
      "totalScore": 86.12775824052848,
      "prScore": 86.12775824052848,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": "NubsCarson: Focused on enhancing system security and message handling within the elizaos/eliza repository, successfully merging four bug fixes that prevented internal data leakage and improved swarm synthesis delivery via PR #7090. Their work was dedicated entirely to bugfix efforts, ensuring cleaner runtime scheduling and more precise action result rendering across the codebase."
    },
    {
      "username": "greptile-apps",
      "avatarUrl": "https://avatars.githubusercontent.com/in/867647?v=4",
      "totalScore": 58.5,
      "prScore": 0,
      "issueScore": 0,
      "reviewScore": 58.5,
      "commentScore": 0,
      "summary": "greptile-apps: No activity today."
    },
    {
      "username": "lalalune",
      "avatarUrl": "https://avatars.githubusercontent.com/u/18633264?u=e2e906c3712c2506ebfa98df01c2cfdc50050b30&v=4",
      "totalScore": 43.7437738965761,
      "prScore": 43.5437738965761,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.2,
      "summary": "lalalune: Focused on extensive codebase maintenance and bug resolution, contributing 71 commits and managing a significant refactor across 9,662 files while opening PR #7089 to address a wallet runtime fix in elizaos/eliza. Their work was primarily concentrated on general project improvements and bugfix efforts, with code and test files comprising the majority of the modifications."
    },
    {
      "username": "Dexploarer",
      "avatarUrl": "https://avatars.githubusercontent.com/u/211557447?u=21a243d61cc1f87574328ae07fc64d7d7577b53d&v=4",
      "totalScore": 43.7437738965761,
      "prScore": 43.5437738965761,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.2,
      "summary": "Dexploarer: Drove significant feature development by merging PR #7092 in elizaos/eliza, which introduced managed desktop windows through a substantial 1,809-line modification across 32 files. This work balanced feature implementation with bug fixes, maintaining a focus on both core code and testing infrastructure."
    },
    {
      "username": "dutchiono",
      "avatarUrl": "https://avatars.githubusercontent.com/u/86275975?u=0d8badaa81aa47682651f87dc2d363837876de98&v=4",
      "totalScore": 30.151898206292632,
      "prScore": 30.151898206292632,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": "dutchiono: Focused on improving character data integrity by opening PR #7093 in elizaos/eliza, which addresses tokenization issues during name saves. This effort involved a significant refactor across 4 files with 263 total lines of code changes, centering entirely on bugfix work."
    },
    {
      "username": "odilitime",
      "avatarUrl": "https://avatars.githubusercontent.com/u/16395496?u=c9bac48e632aae594a0d85aaf9e9c9c69b674d8b&v=4",
      "totalScore": 10,
      "prScore": 0,
      "issueScore": 0,
      "reviewScore": 10,
      "commentScore": 0,
      "summary": "odilitime: Focused on maintaining code quality and stability by providing 2 approvals on peer reviews and executing a targeted bugfix across 3 files. This work reflects a commitment to codebase health through precise, high-impact code modifications."
    }
  ],
  "newPRs": 25,
  "mergedPRs": 24,
  "newIssues": 0,
  "closedIssues": 1,
  "activeContributors": 8
}