{
  "interval": {
    "intervalStart": "2026-05-04T00:00:00.000Z",
    "intervalEnd": "2026-05-05T00:00:00.000Z",
    "intervalType": "day"
  },
  "repository": "elizaos/eliza",
  "overview": "From 2026-05-04 to 2026-05-05, elizaos/eliza had 33 new PRs (31 merged), 5 new issues, and 12 active contributors.",
  "topIssues": [
    {
      "id": "I_kwDOMT5cIs8AAAABBPLbLg",
      "title": "📝 Integration Proposal: CAJAL — Scientific Paper Character",
      "author": "Agnuxo1",
      "number": 7366,
      "repository": "elizaos/eliza",
      "body": "## 📝 Integration Proposal: CAJAL — Scientific Paper Character for Eliza\n\n### What is CAJAL?\n**CAJAL is not a general-purpose chat model.** It is a **specialized scientific paper generation tool** — local, 2GB, producing LaTeX-formatted academic output.\n\n### Part of P2PCLAW\nAgent in [P2PCLAW](https://p2pclaw.com) — 14-agent decentralized research network.\n\n### Why Eliza?\nEliza's character-based AI + CAJAL = **\"Professor Eliza\"** — a research character:\n- Character: \"Dr. CAJAL, peer-review scientist\"\n- Action: generate_paper_section\n- Evaluator: review_paper_quality\n- Community-driven scientific characters\n\n### Proposed Integration\n```json\n{\n  \"name\": \"Dr. CAJAL\",\n  \"system\": \"You are a peer-review scientist generating LaTeX papers...\",\n  \"actions\": [\"generate_abstract\", \"review_methodology\"]\n}\n```\n\n### Links\n- 🤗 HF: https://huggingface.co/Agnuxo/CAJAL-4B-P2PCLAW\n- 📁 GH: https://github.com/Agnuxo1/CAJAL\n- 🌐 P2PCLAW: https://p2pclaw.com\n\n— Francisco (@Agnuxo1), P2PCLAW\n",
      "createdAt": "2026-05-04T16:14:24Z",
      "closedAt": "2026-05-04T20:27:54Z",
      "state": "CLOSED",
      "commentCount": 0
    },
    {
      "id": "I_kwDOMT5cIs8AAAABBO8Flg",
      "title": "agent-orchestrator: --dangerously-skip-permissions doesn't actually skip; PTY exits 1 on 'Bypass Permissions confirmation' loop",
      "author": "Sw4pIO",
      "number": 7365,
      "repository": "elizaos/eliza",
      "body": "## Summary\n\nWhen the SwarmCoordinator dispatches a research/coding task, it spawns a `claude` (Claude Code CLI) subprocess in a PTY with `--dangerously-skip-permissions` plus a curated `--tools` list. The subprocess **still** displays a `\"Bypass Permissions confirmation\"` dialog at startup. The orchestrator's idle-watchdog auto-presses `enter`, but the prompt loops — Claude Code expects an actual selection, not a bare enter — and after a few rounds the PTY exits with code 1.\n\nNet effect: every dispatched coding/research task fails before doing any work. From the user side, the agent says \"I'll research X\" then nothing happens; eventually the coordinator surfaces:\n\n```\n[SwarmCoordinator] Idle watchdog: \"<task>-1\" — PTY session no longer exists, marking as stopped\n[SwarmCoordinator] checkAllTasksComplete: sessions are terminal but acceptance failed — thread task-<id> | failed goals: <goal>=failed\n```\n\n## Reproduction\n\n1. Web chat or Telegram → ask Chen to research anything that triggers the orchestrator dispatch path:\n   *\"Search for B2B logistics companies in California with 50–500 employees that haven't adopted AI yet.\"*\n2. Watch logs:\n   ```\n   [PTYService/Worker] Spawning session { type: 'claude', name: 'coding-... ' }\n   [PTYService/Worker] Starting PTY session { command: 'claude', args: '--dangerously-skip-permissions --tools Read,Grep,…' }\n   [PTYService/Worker] PTY session started { pid: ... }\n   [PTYService/Worker] Sent input to session { input: '# Workspace\\n…' }\n   [PTYService/Worker] Sent special key { key: 'enter' }\n   [PTYService/Worker] Blocking prompt requires user intervention {\n     promptType: 'permission',\n     prompt: 'Bypass Permissions confirmation'\n   }\n   [PTYService/Worker] Sent special key { key: 'enter' }    ← repeats 2-3×\n   [PTYService/Worker] PTY session exited { exitCode: 1 }\n   ```\n3. Coordinator marks task failed; user sees no work done.\n\n## Root cause\n\n`--dangerously-skip-permissions` is a Claude Code flag that **promises** to skip the per-tool permission ask, but on first invocation the CLI shows a one-time confirmation gate (\"are you sure you want to bypass permissions?\") that the orchestrator's automated `enter` press doesn't satisfy. The CLI is interpreting `enter` as \"show me the choices again\" rather than \"yes, confirmed.\"\n\nThe orchestrator's blocking-prompt detector sees the prompt, fires `key: enter`, sees the prompt again, fires `enter` again, and gives up after the third round. Then PTY exits.\n\n## Suggested fixes\n\n1. **Pre-confirm the bypass** out-of-band before spawning. Run `claude config set --global dangerouslySkipPermissionsAcknowledged true` once on first orchestrator boot (or detect the missing ack and run it). Then `--dangerously-skip-permissions` won't prompt.\n\n2. **Match the actual prompt's accept key**. `enter` may not be the correct dismiss key — most CLI confirmations want `y` + `enter` or arrow-then-enter. Audit Claude Code's actual prompt and send the right sequence.\n\n3. **Detect this specific failure mode and surface a real error** instead of silent task-failed. Right now the user has no way to know the subprocess is stuck on a permission dialog vs actually running.\n\n4. **Fall back to a non-prompting agent type** (codex, e.g.) when the claude path repeatedly hits this gate.\n\n## Why this matters\n\nThe orchestrator dispatch path is the entire reason `BROWSER_ACTION`, `USE_SKILL`, and the coding-agent flow exist. With this gate blocking every spawn, users with `PARALLAX_DEFAULT_AGENT_TYPE=claude` get **zero** completed tasks — the system looks broken on every \"do X for me\" request.\n\nCombined with #7362 (capability denial), users are double-blocked: even after the agent agrees to dispatch, the dispatch fails.\n\n## Environment\n\n- bun 1.3.13\n- claude-code CLI (current version on `~/.claude` install path)\n- milady on `alice` post-PR-105\n- Discovered when user's \"research B2B logistics companies\" task triggered orchestrator → PTY exit 1 → coordinator failed-goals report",
      "createdAt": "2026-05-04T15:28:16Z",
      "closedAt": null,
      "state": "OPEN",
      "commentCount": 0
    },
    {
      "id": "I_kwDOMT5cIs8AAAABBO5XIw",
      "title": "telegram: milady wrapper bypasses agent runtime — bot has no action/skill/orchestrator dispatch, only LLM-text-in/text-out",
      "author": "Sw4pIO",
      "number": 7364,
      "repository": "elizaos/eliza",
      "body": "## Summary\n\nMilady's standalone Telegram wrapper at `packages/app-core/src/runtime/eliza.ts:665` (function `ensureTelegramBotPolling`) handles inbound Telegram messages by calling \\`runtime.useModel(ModelType.TEXT_LARGE, { prompt: ... })\\` directly with a stitched-together system + history prompt, then sending the model's text reply back via `ctx.reply()`.\n\nThis bypasses the entire agent runtime message-handling pipeline. As a result, the Telegram bot **has no access to**:\n\n- Action dispatch (`BROWSER_ACTION`, `CREATE_TASK`, `CREATE_CRON`, `FILE_ACTION`, `TERMINAL_ACTION`, `USE_COMPUTER`, `USE_SKILL`, etc.)\n- The agent orchestrator / coding-agent subprocess path\n- The skill/provider context that the dashboard chat sees on every turn (recent messages, entity facts, long-term memory hints, capability lists)\n- Per-turn callbacks / streamed updates / progressive responses\n\nEven after patching the character system prompt to declare capabilities (per #7362), the Telegram path **literally cannot invoke any action** because the runtime's action-selection step is never reached. The model can talk about doing things, but nothing happens.\n\nWeb chat (`localhost:2138`) goes through `runtime.processMessage()` → full pipeline → actions actually run. The two paths are wildly out of parity.\n\n## Reproduction\n\n1. Patch Chen's system prompt to mention `BROWSER_ACTION` (so the model is willing to invoke it).\n2. Web chat: *\"Use BROWSER_ACTION to search for X\"* → spawns Claude Code subprocess, runs the action, replies with results.\n3. Telegram DM: *\"Use BROWSER_ACTION to search for X\"* → bot replies with text describing what it would do, but no action is dispatched. Logs show:\n   ```\n   [milady] Telegram message from @user: Use BROWSER_ACTION to search ...\n   [milady] Telegram replied to @user\n   ```\n   No `processActions`, no orchestrator, no PTY — just a text reply.\n\n## Root cause\n\nThe current handler shape:\n\n```ts\nbot.on(\"message\", async (ctx) => {\n  // ... build system + history string ...\n  const response = await modelRuntime.useModel(ModelType.TEXT_LARGE, {\n    prompt: `${systemPrompt}\\n\\nConversation:\\n${conv}\\n\\n${char.name}:`,\n  });\n  await ctx.reply(responseText);\n});\n```\n\nDirect `useModel` skips:\n- `runtime.composeState()` — no providers contribute context\n- Action selection — no tool-use turns\n- `runtime.processActions()` — no dispatch\n- Memory write — `createMemory()` is never called for inbound or outbound\n- Event emission — `EventType.MESSAGE_RECEIVED` and `MESSAGE_SENT` never fire, so any subscriber (analytics, training trajectories, escalation routing) is blind to Telegram traffic\n\n## Why the wrapper exists\n\nA comment at `packages/app-core/src/runtime/eliza.ts:531-533` explains:\n> *\"Ensure Telegram bot is polling. The upstream plugin's `bot.launch()` is not awaited and silently fails on bun/Windows. We create a standalone Telegraf instance with proper lifecycle management.\"*\n\nSo the wrapper was added to work around #7241 (Telegraf launch under Bun) and #7240 (token bridge). But the implementation went further than necessary — instead of just owning the Telegraf instance and forwarding inbound messages into the runtime, it implemented its own simplified \"ask LLM, reply text\" loop.\n\n## Fix\n\nRefactor the wrapper's message handler to forward inbound messages through the agent runtime, mirroring what `@elizaos/plugin-telegram/src/messageManager.ts` does:\n\n1. Build a proper `Memory` object (entityId, roomId, worldId, agentId, content.text, source: \"telegram\", channelType, createdAt).\n2. `await runtime.ensureConnection({ entityId, roomId, source: \"telegram\", ... })` so room/world state exists.\n3. `await runtime.createMemory(memory, \"messages\")` so it lands in the inbound stream.\n4. `runtime.emitEvent(EventType.MESSAGE_RECEIVED, { runtime, message: memory, callback })` where callback dispatches `ctx.reply()` for each response chunk.\n\nEstimated ~200 lines of plumbing — most of it boilerplate Memory/room construction that can be lifted from the upstream `messageManager.ts` directly.\n\n## Why this matters\n\nUsers assume their Telegram bot is the same agent as the web chat. With the current wrapper, Telegram is essentially a watered-down chatbot that can't do work. Anything the user asks Chen to *do* via Telegram will silently fail or just be described as text without execution.\n\nCombined with #7240, #7241, #7245, the Telegram path has been on a long tail of regressions; this is the architectural one that gates feature parity.\n\n## Environment\n\n- bun 1.3.13\n- milady on `alice` post-PR-105\n- Discovered when user asked \"i need my telegram bot to be able to do all of these too\" (browser actions, tasks, memory) and confirmed via log inspection that the wrapper never invokes `processActions`.",
      "createdAt": "2026-05-04T15:21:46Z",
      "closedAt": null,
      "state": "OPEN",
      "commentCount": 0
    },
    {
      "id": "I_kwDOMT5cIs8AAAABBOMOBA",
      "title": "ui: Activity panel flickers under high-volume WS events — useActivityEvents fires setState per event with no coalescing",
      "author": "Sw4pIO",
      "number": 7363,
      "repository": "elizaos/eliza",
      "body": "## Summary\n\n`packages/app-core/src/hooks/useActivityEvents.ts` subscribes to three WebSocket event streams (`pty-session-event`, `proactive-message`, `agent_event`) and calls `setEvents([...bufferRef.current])` on **every** event. When multiple events arrive in the same tick — common during code-task spawns, multi-step actions, or chatty proactive flows — React fires N re-renders, which the user sees as the Activity panel flickering.\n\n## Reproduction\n\n1. Open the dashboard, watch the right-side Activity panel.\n2. Trigger any flow that emits multiple `agent_event`s rapidly (start a code task with sub-steps, or run anything that emits proactive nudges in quick succession).\n3. Activity panel visibly flickers / re-renders rapidly.\n\nFrequency scales with WS event volume — light usage might never trigger it; heavy use makes it constant.\n\n## Root cause\n\n```ts\nconst pushEvent = useCallback((entry) => {\n  const event = { ...entry, id: makeEventId() };\n  const buf = bufferRef.current;\n  buf.unshift(event);\n  if (buf.length > RING_BUFFER_CAP) buf.length = RING_BUFFER_CAP;\n  setEvents([...buf]);  // ← new array reference every event\n}, []);\n```\n\nEach `setEvents([...buf])` allocates a new top-level array reference, so React's bailout doesn't kick in. With 3 active WS subscriptions firing in bursts, you get unboundedly many renders per second. No batching, no rAF coalescing, no debounce.\n\n## Fix (verified locally)\n\nCoalesce bursts into one render via `requestAnimationFrame`:\n\n```ts\nconst flushHandleRef = useRef<number | null>(null);\n\nconst pushEvent = useCallback((entry) => {\n  const event = { ...entry, id: makeEventId() };\n  const buf = bufferRef.current;\n  buf.unshift(event);\n  if (buf.length > RING_BUFFER_CAP) buf.length = RING_BUFFER_CAP;\n  if (flushHandleRef.current !== null) return;       // already scheduled\n  flushHandleRef.current = requestAnimationFrame(() => {\n    flushHandleRef.current = null;\n    setEvents([...bufferRef.current]);\n  });\n}, []);\n\n// cancel pending flush on unmount\nuseEffect(() => () => {\n  if (flushHandleRef.current !== null) {\n    cancelAnimationFrame(flushHandleRef.current);\n  }\n}, []);\n\n// clearEvents also cancels pending flush\nconst clearEvents = useCallback(() => {\n  bufferRef.current = [];\n  if (flushHandleRef.current !== null) {\n    cancelAnimationFrame(flushHandleRef.current);\n    flushHandleRef.current = null;\n  }\n  setEvents([]);\n}, []);\n```\n\nAfter patch: at most one render per animation frame regardless of how many events fire. Visible flicker eliminated. Tested locally during a multi-step agent run.\n\n## Why rAF and not debounce\n\n- `requestAnimationFrame` is the right cadence for visible UI updates — anything finer is wasted work, anything coarser feels laggy.\n- Survives backgrounded tabs (rAF pauses them, which is the correct behavior).\n- No timeout magic numbers to tune.\n\n## Why this matters\n\nSubtle but persistent flicker is a \"the app feels broken\" UX signal even when functionally everything works. With the upcoming hyperscape / agent-orchestrator flows producing more event volume, this gets worse, not better.\n\n## Environment\n\n- bun 1.3.13\n- React 19\n- milady on `alice` (PR #105 sync)",
      "createdAt": "2026-05-04T13:28:32Z",
      "closedAt": null,
      "state": "OPEN",
      "commentCount": 0
    },
    {
      "id": "I_kwDOMT5cIs8AAAABBNvvng",
      "title": "agent hallucinates 'no task manager / no memory' when CREATE_TASK + memory infrastructure are present but not surfaced; Hyperscape app stomps agents.list on install",
      "author": "andex23",
      "number": 7362,
      "repository": "elizaos/eliza",
      "body": "## Two bugs in one report — they hit users together\n\n### Bug A: Agent denies having tools it actually has\n\nA user asks Chen via Telegram (or web chat) to add a task to her task manager. Chen replies:\n\n> *\"just to be clear — i don't have a task manager or memory between sessions, so i can't save it on my end. but you can keep this as your task… copy that somewhere you'll actually see it.\"*\n\nThis is **wrong**:\n\n- `eliza/packages/typescript/src/features/advanced-capabilities/actions/createTask.ts:103` defines a `CREATE_TASK` action: *\"Create an autonomous trigger task (interval, once, or cron)\"*.\n- `eliza/plugins/plugin-cron/typescript/src/actions/` has full `create-cron`, `list-crons`, `delete-cron`, `update-cron`, `run-cron` implementations.\n- `plugin-sql` has a real `tasks` table (we see queries against it on every boot — the `__db_ready_probe__` line in #7222 hits it).\n- Long-term memory is a real capability — `entity_identities`, `fact_candidates`, the trajectories table, `longTermMemoryProvider`. Per CLAUDE.md: *\"Trajectory persistence is on by default. Every turn lands in the `trajectories` table.\"*\n\nThe agent has all of this and still tells the user \"I don't have it.\" That's a worst-case UX failure: capable system, agent unaware of its capabilities, polite-sounding lie surfaced to the user. The user has no way to know the system can actually do the thing.\n\n#### Likely root cause\n\nThe system prompt and `actions` provider don't list these capabilities to the model. The agent picks up `CREATE_TASK` only if (a) the action's plugin is in the auto-enable map, (b) the action gets surfaced in the prompt's `Available actions` block, (c) the character's `system` doesn't actively suppress it. On a default install at least one of those gates is failing.\n\n#### Suggested fix\n\n1. **Auto-enable** the cron / task-creation plugin by default (or include `CREATE_TASK` in the always-on action set).\n2. **Inject capability hints into the system prompt** — something like *\"You have a persistent task manager (CREATE_TASK), long-term memory (trajectories + entity_identities), and can schedule work. Don't claim otherwise.\"*\n3. **Add a fallback**: when the agent emits a refusal that mentions \"no memory\" / \"no task manager\" / \"no persistence\" and the runtime has the corresponding capability, log it (so devs notice) and ideally re-prompt with the capability list.\n\n### Bug B: Hyperscape app overwrites `agents.list` on install\n\nWhen the Hyperscape app/plugin is installed (`@hyperscape/plugin-hyperscape` + `@elizaos/app-hyperscape`), its bootstrap step **replaces** `agents.list` in `~/.milady/milady.json` with a single `\"Hyperscape Explorer\"` entry — wiping out the user's existing character (Chen, in our case). After install, the user opens the chat and the default agent is no longer who they onboarded with.\n\nReproduction:\n\n1. Onboard fresh, pick Chen.\n2. `cat ~/.milady/milady.json` — `agents.list` either absent (preset rebuilds Chen) or contains a Chen entry. `ui.presetId === \"chen\"`.\n3. Install Hyperscape (env vars `HYPERSCAPE_SERVER_URL`, `HYPERSCAPE_API_URL`, `HYPERSCAPE_CLIENT_URL` written; plugins enabled).\n4. `cat ~/.milady/milady.json` — `agents.list` is now `[{ name: \"Hyperscape Explorer\", bio: [...], topics: [\"hyperscape\",\"osrs\",...], ... }]`. **Chen is gone.** `ui.presetId` still says `\"chen\"` but it's ignored when `agents.list` is populated.\n5. Restart milady. Default chat agent is \"Hyperscape Explorer\" — an OSRS adventurer the user never asked for.\n\nWorkaround: delete `agents.list` from `~/.milady/milady.json`, restart. The runtime rebuilds from `presetId` and Chen comes back.\n\n#### Suggested fix\n\nApp / plugin install paths must **not** silently mutate `agents.list`. Two acceptable behaviors:\n\n1. **Append** a new agent entry rather than replace.\n2. **Provide a sample/demo character separately** (e.g., a \"Hyperscape Demo\" preset the user can pick from a gallery) instead of writing it into the live agent list.\n\nEither way, an install step should never destroy user character config without consent.\n\n### Why I bundled them\n\nThese hit the user in the same flow: they install Hyperscape (or another app that does this), their agent silently changes, the new agent doesn't know what it can or can't do, and on the very next user message the agent confidently denies having a task manager. Both bugs stem from the same general pattern — system writes config the user doesn't see, agent doesn't introspect its own runtime state.\n\n## Environment\n\n- bun 1.3.13\n- milady on `alice` post-PR-105 sync\n- `@elizaos/app-hyperscape` + `@hyperscape/plugin-hyperscape` installed\n- Discovered when user said *\"why am i seeing hyperscape explorer as default chat, what happened to chen and other personality?\"* and then *\"i tried to give my agent a task to add to its task manager and it said the above\"*",
      "createdAt": "2026-05-04T12:17:51Z",
      "closedAt": null,
      "state": "OPEN",
      "commentCount": 0
    }
  ],
  "topPRs": [
    {
      "id": "PR_kwDOMT5cIs7X8Akl",
      "title": "Add ilfeops code + analysis mode",
      "author": "lalalune",
      "number": 7356,
      "body": "This adds some code to make things more interesting",
      "repository": "elizaos/eliza",
      "createdAt": "2026-05-04T08:56:25Z",
      "mergedAt": "2026-05-04T10:24:03Z",
      "additions": 28474,
      "deletions": 1876
    },
    {
      "id": "PR_kwDOMT5cIs7YJahe",
      "title": "feat(slack): migrate plugin-slack into the monorepo",
      "author": "2-A-M",
      "number": 7375,
      "body": "## Summary\n\nBrings \\`@elizaos/plugin-slack\\` from [elizaos-plugins/plugin-slack](https://github.com/elizaos-plugins/plugin-slack) into the monorepo at \\`plugins/plugin-slack/\\` alongside the other connector plugins already living here (discord, telegram, signal, whatsapp, wechat, xmtp, instagram, matrix, line, feishu, google-chat, imessage, x, twitch, bluesky, bluebubbles, farcaster, nostr).\n\nSlack was the last major-platform connector still living standalone. The standalone repo is at \\`v2.0.0-alpha\\` with the same \\`typescript/python/rust\\` layout as plugin-elizacloud and friends, so it was already migration-ready — just hadn't been picked up by the migration sweep.\n\nThe source matches the standalone repo's \\`next\\` branch tip plus the multi-message handling fix from [elizaos-plugins/plugin-slack#1](https://github.com/elizaos-plugins/plugin-slack/pull/1) (\\`d50e802\\`), which has been sitting on standalone with an APPROVED review since 2026-02-28. That PR will close as superseded by this one.\n\n## What lands\n\n- \\`src/\\` — service, accounts, formatting, config, index, types, plus:\n  - \\`actions/\\` — sendMessage, editMessage, deleteMessage, listChannels, readChannel, pinMessage, unpinMessage, listPins, reactToMessage, emojiList, getUserInfo (11 actions)\n  - \\`providers/\\` — channelState, memberList, workspaceInfo (3 providers)\n- \\`__tests__/\\` — \\`accounts.test.ts\\` (98 tests), \\`formatting.test.ts\\` (22 tests)\n- \\`package.json\\` — workspace-aware: \\`@elizaos/core: workspace:*\\`, version bumped to \\`2.0.0-alpha.537\\` to match sibling plugins, scripts aligned with monorepo conventions (biome from root \\`node_modules\\`)\n- \\`tsconfig.json\\` (modeled on plugin-discord), \\`build.ts\\` (unchanged from standalone), \\`README.md\\`, \\`LICENSE\\`\n\n## API drift fixes (alpha.3 → alpha.537)\n\nThe standalone \\`peerDependencies\\` pinned \\`@elizaos/core: 2.0.0-alpha.3\\`. The monorepo is at alpha.537, and the core API has moved in two specific ways the slack plugin needed updates for:\n\n- **\\`State.recentMessagesData\\` typing.** Providers in \\`channelState.ts\\`, \\`memberList.ts\\`, \\`workspaceInfo.ts\\` read \\`state?.recentMessagesData\\`, which is now typed as the broader \\`StateValue\\` union (\\`string | number | bigint | true | object\\`) rather than \\`Memory[]\\` directly. Cast the field to \\`Memory[] | undefined\\` at the read site so \\`validateActionKeywords\\` / \\`validateActionRegex\\` get the expected shape. Behavior unchanged.\n- **\\`MentionContext\\` shape.** \\`service.ts\\` was constructing \\`{ isMention: true }\\`; the type now requires \\`isReply\\` and \\`isThread\\` too. Filled with \\`false\\` for the mention-only path. Behavior unchanged for the existing mention handling.\n\n## Verified\n\n- ✅ \\`tsc --noEmit -p plugins/plugin-slack/tsconfig.json\\` clean\n- ✅ 120/120 unit tests pass (\\`bun test plugins/plugin-slack/__tests__/\\`)\n- ✅ \\`bun run build.ts\\` produces \\`dist/index.js\\` + \\`.d.ts\\` cleanly\n\n## Follow-ups (not in this PR)\n\n- Close [elizaos-plugins/plugin-slack#1](https://github.com/elizaos-plugins/plugin-slack/pull/1) as superseded once this lands.\n- The standalone repo itself can be archived or kept as a thin re-export, mirroring how the other migrated plugin repos are handled.\n- The CodeRabbit P2 nitpick on the multi-message handling fix (channel_type undefined edge case) is preserved as-is from the standalone PR — landing the existing fix verbatim, leaving any further hardening to a follow-up.\n\n## Test plan\n- [x] Typecheck clean\n- [x] Unit tests green (120/120)\n- [x] Build artifact produced\n- [ ] Wire-up smoke test against a live Slack workspace — out of scope for this PR; happy to follow up if maintainers want it before merge\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR migrates `@elizaos/plugin-slack` from its standalone repository into the monorepo, adding 11 actions, 3 providers, a Socket Mode service, and 120 passing unit tests. The alpha API drift fixes (`State.recentMessagesData` cast and `MentionContext` shape) are correctly applied.\n\n- **P1 – silent message drops**: `getUser()` in `handleMessage` and `handleAppMention` calls `client.users.info` without a try/catch. A Slack API error (rate-limit, deactivated user, network) will throw through the entire Bolt event handler, causing the message to be lost with no memory stored and no agent reply.\n- **P2 – stale `repository.url`**: `package.json` still points to the old `elizaos-plugins/plugin-slack` standalone repo instead of the monorepo.\n- **P2 – unused `zod` runtime dependency**: `zod` is declared in `dependencies` but never imported in any source file.\n\n<h3>Confidence Score: 3/5</h3>\n\nNot safe to merge without fixing the missing try/catch around getUser() — incoming messages are silently dropped on any Slack API error during user lookup.\n\nOne P1 defect (unguarded getUser throws drop live messages) plus two P2 hygiene issues (stale repo URL, unused zod dependency). The P1 is on the critical incoming-message path so the score is pulled below the ceiling.\n\nplugins/plugin-slack/src/service.ts (handleMessage and handleAppMention event handlers); plugins/plugin-slack/package.json\n\n<h3>Important Files Changed</h3>\n\n| Filename | Overview |\n|----------|----------|\n| plugins/plugin-slack/src/service.ts | Core Slack service with Socket Mode integration — contains a P1 missing try/catch around `getUser()` in event handlers (messages silently dropped on API errors), and a P2 channel-type mapping where both MPIM and public channels collapse to `ChannelType.GROUP`. |\n| plugins/plugin-slack/package.json | Package metadata has two P2 issues: `repository.url` still points to the old standalone repo and `zod` is declared as a runtime dependency but is never imported in source. |\n| plugins/plugin-slack/src/index.ts | Plugin registration and re-exports; token validation and masked logging look correct. Imports/exports are well-organized. |\n| plugins/plugin-slack/src/actions/sendMessage.ts | Action handler with LLM-extracted parameters; the generated `validate` wrapper is verbose but functionally correct; channel resolution and fallback logic are sound. |\n| plugins/plugin-slack/src/providers/channelState.ts | Channel state provider with correct `Memory[] | undefined` cast for `recentMessagesData`; relevance-gating and fallback paths look correct. |\n| plugins/plugin-slack/src/types.ts | Comprehensive Slack type definitions, error classes, and utility functions; looks correct and well-structured. |\n| plugins/plugin-slack/src/accounts.ts | Multi-account resolution helpers with token validation logic; parallel type definitions to `config.ts` but scoped correctly to `accounts.ts` exports only. |\n\n</details>\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant Slack as Slack (Socket Mode)\n    participant Bolt as @slack/bolt App\n    participant SVC as SlackService\n    participant RT as IAgentRuntime\n    participant Agent as MessageService\n\n    Slack->>Bolt: message / app_mention event\n    Bolt->>SVC: handleMessage() / handleAppMention()\n    SVC->>SVC: isChannelAllowed()\n    SVC->>RT: getEntityById(entityId)\n    SVC->>Slack: users.info (getUser) ⚠️ no try/catch\n    SVC->>RT: createEntity()\n    SVC->>RT: createMemory(memory, \"messages\")\n    SVC->>RT: emitEvent(SLACK_MESSAGE_RECEIVED)\n    SVC->>Agent: messageService.handleMessage(memory, callback)\n    Agent-->>SVC: callback(response)\n    SVC->>Slack: chat.postMessage (sendMessage)\n    SVC->>RT: createMemory(responseMemory)\n    SVC->>RT: emitEvent(SLACK_MESSAGE_SENT)\n```\n\n<sub>Reviews (1): Last reviewed commit: [\"feat(slack): migrate plugin-slack into m...\"](https://github.com/elizaos/eliza/commit/32b5ec0448c0943d5ccdbaa1ed00047fb7d94310) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=30739102)</sub>\n\n> Greptile also left **4 inline comments** on this PR.\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-05-04T19:59:56Z",
      "mergedAt": "2026-05-04T20:03:13Z",
      "additions": 7299,
      "deletions": 0
    },
    {
      "id": "PR_kwDOMT5cIs7YL89f",
      "title": "feat(cloud): support monetized container app domains",
      "author": "NubsCarson",
      "number": 7376,
      "body": "# Relates to\n\nCloud app/domain monetization build path.\n\n# Risks\n\nLarge. This touches Cloud app auth, app-scoped chat, Cloudflare domain management, and container deployment status handling. Review should focus on route ownership checks, billing/error behavior, and deployment lifecycle state transitions.\n\n# Background\n\n## What does this PR do?\n\nAdds the production Cloud path needed for agent-built monetized apps:\n\n- App-scoped chat endpoint support at `/api/v1/apps/:appId/chat`, routed through the configured provider/AI Gateway with app monetization metadata.\n- Cloudflare-managed app domain support, including check/buy/status/sync flows and app-domain ownership checks.\n- App auth callback/session handling needed for generated apps to complete OAuth-style sign-in and return to the app.\n- Local container control-plane deployment support and immediate monitor reconciliation so a healthy container is marked `running` instead of staying stuck in `deploying`.\n- Skill docs aligned with the Cloud container/OAuth/monetized-chat/domain lifecycle.\n\n## What kind of change is this?\n\nFeatures and bug fixes.\n\n# Documentation changes needed?\n\nUpdated included skill documentation for Cloud app builds and app domain lifecycle behavior.\n\n# Testing\n\n## Where should a reviewer start?\n\nStart with Cloud app/domain route changes, then the container deployment status monitor, then the skill docs.\n\n## Detailed testing steps\n\n- `bun run --cwd cloud/apps/api typecheck`\n- `bun run --cwd cloud/services/container-control-plane typecheck`\n- `bun test cloud/packages/tests/unit/domains/domain-pricing.test.ts cloud/packages/tests/unit/domains/cloudflare-dns-stub.test.ts cloud/packages/tests/unit/domains/cloudflare-registrar-stub.test.ts`\n- Local Discord e2e with normal app prompts spawned Codex, registered Cloud apps, enabled app-scoped monetized chat, completed OAuth-style app auth, offered Cloudflare domains, and verified unsigned chat returns `401 not_signed_in`.\n- Local custom-domain e2e verified `nubilio.org` against the local Cloud stack and confirmed the app auth entry point returns Cloud HTML.\n\n# Deploy Notes\n\nRequires the Cloud API/frontend/control-plane deploy together. Configure Cloudflare registrar/DNS env vars and the AI Gateway/provider env already expected by Cloud. Container deployment status depends on the container control-plane service being reachable.\n\n## Database changes\n\nIncludes Cloud domain/app-domain state changes from the Cloud codepath. Run the Cloud migrations before enabling the new domain/app routes in prod.\n\n## Deployment instructions\n\nDeploy Cloud API, frontend, and container control-plane from the same revision. Do not enable automatic domain purchase without the existing user confirmation step.\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR adds the production Cloud path for agent-built monetized apps: app-scoped chat at `/api/v1/apps/:id/chat` with credit debit/reconcile, Cloudflare-managed domain buy/check/status/sync/verify flows, an app OAuth-style auth callback, and a new Node container control-plane sidecar with an immediate deploy-monitor reconciliation on container creation.\n\n- **P1 — Auth errors return 500 on the chat endpoint:** `requireAuthOrApiKeyWithOrg` is called inside `Promise.all`. For API-key callers (where the global middleware skips validation), any `AuthenticationError` or `ForbiddenError` is caught by the outer catch and returned as HTTP 500 instead of 401/403.\n- **P1 — Sync never marks a Cloudflare domain as `verified` after zone provisioning:** When a domain is purchased while zone creation is still pending (`verified: false`), calling `/sync` later sets `status: \\\"active\\\"` but omits `verified: true`, leaving `listVerifiedAppOrigins` (used for CORS) permanently empty for that domain.\n\n<h3>Confidence Score: 3/5</h3>\n\nNot safe to merge without addressing the two P1s; auth misclassification and broken CORS sync compound the already-flagged credit/refund issues from the prior review round.\n\nMultiple P1 findings across core paths (auth, CORS, and credit reconciliation from prior round) pull the score below the P1 ceiling.\n\ncloud/apps/api/v1/apps/[id]/chat/route.ts (auth error handling), cloud/apps/api/v1/apps/[id]/domains/sync/route.ts (verified flag), cloud/apps/api/v1/apps/[id]/domains/buy/route.ts (credit refund on DB failure)\n\n<h3>Important Files Changed</h3>\n\n\n\n\n| Filename | Overview |\n|----------|----------|\n| cloud/apps/api/v1/apps/[id]/chat/route.ts | New app-scoped monetized chat endpoint; auth errors from API-key callers are swallowed as 500 inside Promise.all; streaming/non-streaming credit reconciliation edge cases already flagged in previous reviews. |\n| cloud/apps/api/v1/apps/[id]/domains/sync/route.ts | New domain sync endpoint; does not pass verified: true to syncStatus when a pending Cloudflare domain becomes active, leaving CORS origin lists stale. |\n| cloud/apps/api/v1/apps/[id]/domains/buy/route.ts | New atomic domain-buy flow; DB write failure after successful registration leaves credits consumed with no refund (flagged in prior review). |\n| cloud/services/container-control-plane/src/index.ts | New Node container control-plane; requireInternalToken is a no-op when CONTAINER_CONTROL_PLANE_TOKEN env var is absent (flagged in prior review). |\n| cloud/packages/lib/services/managed-domains.ts | New managed-domains service; upsert/insert/syncStatus logic is solid; org-ownership guard correctly rejects cross-org conflicts. |\n\n</details>\n\n\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant CloudAPI as Cloud API\n    participant CF as Cloudflare Registrar\n    participant DB as managed_domains DB\n\n    Note over Client,DB: Domain Sync (BUG)\n    Client->>CloudAPI: POST /apps/:id/domains/sync\n    CloudAPI->>CF: getRegistrationStatus\n    CF-->>CloudAPI: status=active\n    CloudAPI->>DB: syncStatus(status=active, isLive=true)\n    Note right of DB: verified stays false!\n    CloudAPI-->>Client: verified=false (broken CORS)\n```\n\n<!-- greptile_failed_comments -->\n<details><summary><h3>Comments Outside Diff (3)</h3></summary>\n\n1. `cloud/apps/api/v1/apps/[id]/chat/route.ts`, line 498-558 ([link](https://github.com/elizaos/eliza/blob/2692d06ba732110606be388695e1a3d3e659c5f3/cloud/apps/api/v1/apps/[id]/chat/route.ts#L498-L558)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> **Full refund issued after stream content is already delivered**\n\n   `writerClosed` is set to `true` at line 498 and `writer.close()` is called at line 499. If any subsequent await — `calculateCost` or `appCreditsService.reconcileCredits` — throws (e.g., transient DB error), the outer `catch` at line 559 calls `reconcileCredits` with `actualBaseCost: 0`, issuing a full refund for a stream that was already successfully delivered to the user. Users can receive inference for free whenever the reconciliation step fails.\n\n2. `cloud/apps/api/v1/apps/[id]/chat/route.ts`, line 637-669 ([link](https://github.com/elizaos/eliza/blob/7dd117f331e62045f271c441fed1aaa6f2b12ff8/cloud/apps/api/v1/apps/[id]/chat/route.ts#L637-L669)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> **Non-streaming reconciliation failure: user charged, no response returned, no refund**\n\n   If `reconcileCredits` at line 637 throws (transient DB error, network blip), execution falls to the outer `catch` at line 670, which returns a 500 to the user. At that point credits have been deducted at 1.5× the estimate, the provider already delivered a successful response (consumed via `providerResponse.json()` at line 606), and no refund is issued. The user is overcharged by the full reserved amount and receives neither the AI response nor their credits back.\n\n   Add a try/catch around the reconciliation that attempts a full refund and still returns the provider's response to the user.\n\n3. `cloud/apps/api/v1/apps/[id]/chat/route.ts`, line 165-169 ([link](https://github.com/elizaos/eliza/blob/1c07ef5b8264ab48fcafb5f80c9c1e0d80f3f327/cloud/apps/api/v1/apps/[id]/chat/route.ts#L165-L169)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> **Auth errors masked as 500 for API-key callers**\n\n   `requireAuthOrApiKeyWithOrg` is called inside `Promise.all` at line 165. When the global auth middleware bypasses cookie auth for API-key requests (`if (apiKey || elizaBearer) { next(); }`), the per-route key validation runs here. If the key is invalid or expired, `AuthenticationError` or `ForbiddenError` is thrown, falls into the outer `catch` at line 670, and is returned to the caller as `status: 500` with `code: \"internal_server_error\"` instead of 401/403. Clients that retry on 401 will never retry, and the error message gives no hint of the actual cause.\n\n</details>\n\n<!-- /greptile_failed_comments -->\n\n<sub>Reviews (4): Last reviewed commit: [\"fix(cloud): respect noble hashes package...\"](https://github.com/elizaos/eliza/commit/1c07ef5b8264ab48fcafb5f80c9c1e0d80f3f327) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=30759652)</sub>\n\n> Greptile also left **1 inline comment** on this PR.\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-05-04T22:15:44Z",
      "mergedAt": "2026-05-04T23:22:42Z",
      "additions": 5571,
      "deletions": 437
    },
    {
      "id": "PR_kwDOMT5cIs7YIc7d",
      "title": "feat(n8n-workflow): structured ClarificationRequest + name->id prompt rules",
      "author": "2-A-M",
      "number": 7373,
      "body": "## Summary\n\nMirror of [elizaos-plugins/plugin-n8n-workflow#27](https://github.com/elizaos-plugins/plugin-n8n-workflow/pull/27) + [#28](https://github.com/elizaos-plugins/plugin-n8n-workflow/pull/28), combined into a single PR since the plugin source of truth lives here now and the standalone-repo chain pre-dates the monorepo migration.\n\n## What changes\n\n**Structured `ClarificationRequest` (was #27):**\n- New \\`ClarificationRequest\\` interface with a discriminated \\`kind\\` (\\`target_channel\\` | \\`target_server\\` | \\`recipient\\` | \\`value\\` | \\`free_text\\`), optional \\`platform\\` + \\`scope.guildId\\`, the user-facing \\`question\\`, and \\`paramPath\\` pointing at the JSON path the resolved value should land at.\n- \\`WorkflowMeta.requiresClarification\\` widened from \\`string[]\\` to \\`Array<string | ClarificationRequest>\\` — preserves backward compat with legacy free-text emissions while letting the LLM (and post-catalog passes) emit structured items.\n- New \\`src/utils/clarification.ts\\`:\n  - \\`coerceClarificationRequests\\` normalizes a mixed-shape array into structured objects.\n  - \\`isCatalogClarification\\` / \\`CATALOG_CLARIFICATION_SUFFIX\\` distinguishes post-catalog-pass clarifications from LLM-emitted ones (so they don't double-up across passes).\n- \\`validateAndRepair.ts\\` was using inline \\`endsWith(SUFFIX)\\` on each item, which no longer typechecks against the widened union. Switched to \\`isCatalogClarification(c)\\` — same semantics, type-safe.\n- 12 unit tests covering coerce + suffix detection.\n\n**Prompt rules (was #28):**\n- \\`WORKFLOW_GENERATION_SYSTEM_PROMPT\\` instructs the LLM to emit structured clarification objects with explicit \\`kind\\` + \\`paramPath\\`, with worked examples (Discord guild + chained channel-picker; recipient picker).\n- Name→id directive: never invent ids, emails, channel IDs, etc. — emit a structured clarification with the exact \\`paramPath\\` and let the host patch after the user picks.\n- 9 unit tests asserting the prompt contains the structured-shape directives, the name→id rule, and the example payloads.\n\nThe host-side coercion (\\`packages/app-core/src/api/n8n-clarification.ts\\` + \\`client-types-chat.ts\\`) already exists in the monorepo and is fully compatible — it normalizes whatever the plugin emits into \\`N8nClarificationRequest[]\\` before handing to the UI. This PR makes the plugin's emitted shape structured at the source.\n\n## Why mirror\n\nPR #27 / #28 were opened against the standalone repo before the plugin migration into the monorepo. The fix needs to land here to actually ship.\n\n## Test plan\n- [x] \\`tsc --noEmit -p plugins/plugin-n8n-workflow/tsconfig.json\\` clean\n- [x] 21/21 new clarification + workflowGenerationPrompt tests pass\n- [x] 44/44 validateAndRepair + generation regression tests still pass\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR introduces a structured `ClarificationRequest` interface to the `plugin-n8n-workflow` package, replacing bare strings in `WorkflowMeta.requiresClarification` with a discriminated-union object that carries `kind`, `platform`, `scope`, `question`, and `paramPath`. It also updates the LLM system prompt with display-name→id resolution rules and worked examples for chained server/channel pickers. The refactoring is backward-compatible, well-tested (21 new unit tests), and the host-side coercion path in `app-core` is already aligned.\n\n<h3>Confidence Score: 4/5</h3>\n\nSafe to merge; all findings are P2 quality/maintainability items with no current runtime impact.\n\nOnly P2 findings: one partial refactor where CATALOG_CLARIFICATION_SUFFIX is imported for detection but the construction site still inlines the raw string, and minor defensive gaps in coerceClarificationRequests. No P0/P1 bugs identified.\n\nplugins/plugin-n8n-workflow/src/utils/validateAndRepair.ts — message-construction template still inlines the suffix literal instead of using the imported constant.\n\n<h3>Important Files Changed</h3>\n\n\n\n\n| Filename | Overview |\n|----------|----------|\n| plugins/plugin-n8n-workflow/src/utils/clarification.ts | New utility introducing CATALOG_CLARIFICATION_SUFFIX, isCatalogClarification, and coerceClarificationRequests. Logic is correct and well-tested; minor concerns around suffix-based discrimination and silent item drops. |\n| plugins/plugin-n8n-workflow/src/utils/validateAndRepair.ts | Local SUFFIX const removed, isCatalogClarification used for filtering — but the message-construction template on line 442 still inlines the raw suffix string instead of using CATALOG_CLARIFICATION_SUFFIX. |\n| plugins/plugin-n8n-workflow/src/types/index.ts | ClarificationRequest interface added with discriminated kind union; WorkflowMeta.requiresClarification widened to Array<string | ClarificationRequest> with backward-compatible semantics. |\n| plugins/plugin-n8n-workflow/src/services/n8n-workflow-service.ts | injectCatalogClarifications updated to use isCatalogClarification and CATALOG_CLARIFICATION_SUFFIX — correct and consistent with the new abstraction. |\n| plugins/plugin-n8n-workflow/src/actions/createWorkflow.ts | Both clarification callback paths updated to use coerceClarificationRequests().map(c => c.question) — structured data preserved in cached workflow, text-only surface for conversational callback. |\n| plugins/plugin-n8n-workflow/src/prompts/workflowGeneration.ts | System prompt extended with display-name→id resolution rules, structured ClarificationRequest format documentation, and worked examples. |\n\n</details>\n\n\n\n<h3>Flowchart</h3>\n\n```mermaid\n%%{init: {'theme': 'neutral'}}%%\nflowchart TD\n    LLM[\"LLM generates workflow\\n(_meta.requiresClarification:\\nArray<string | ClarificationRequest>)\"]\n    VAR[\"validateAndRepair\\napplyRequiredParameterPreflight\\n→ push catalog strings\"]\n    SVC[\"N8nWorkflowService\\ninjectCatalogClarifications\\n→ isCatalogClarification filter\\n→ append CATALOG_CLARIFICATION_SUFFIX strings\"]\n    CACHE[\"runtime.setCache\\n(full structured array preserved)\"]\n    COERCE[\"coerceClarificationRequests\\n(display only — maps to .question[])\"]\n    CB[\"callback({ text: questions[] })\"]\n    HOST[\"Host reads cached workflow._meta\\n→ full ClarificationRequest[] for picker UI\"]\n\n    LLM --> VAR\n    VAR --> SVC\n    SVC --> CACHE\n    CACHE --> COERCE\n    COERCE --> CB\n    CACHE --> HOST\n```\n\n<!-- greptile_failed_comments -->\n<details><summary><h3>Comments Outside Diff (1)</h3></summary>\n\n1. `plugins/plugin-n8n-workflow/src/utils/validateAndRepair.ts`, line 441-443 ([link](https://github.com/elizaos/eliza/blob/f9e9cb6ed0b7facd3a170d704729e243f6035fcf/plugins/plugin-n8n-workflow/src/utils/validateAndRepair.ts#L441-L443)) \n\n   <a href=\"#\"><img alt=\"P1\" src=\"https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=7\" align=\"top\"></a> The `CATALOG_CLARIFICATION_SUFFIX` constant is imported and used for *detection* (`isCatalogClarification`), but the actual message construction on line 442 still inlines the raw suffix string. If the constant is ever changed, detection and production will silently diverge — the filter will stop finding these strings.\n\n</details>\n\n<!-- /greptile_failed_comments -->\n\n<sub>Reviews (1): Last reviewed commit: [\"feat(n8n-workflow): structured Clarifica...\"](https://github.com/elizaos/eliza/commit/f9e9cb6ed0b7facd3a170d704729e243f6035fcf) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=30731744)</sub>\n\n> Greptile also left **2 inline comments** on this PR.\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-05-04T19:12:11Z",
      "mergedAt": "2026-05-04T20:00:07Z",
      "additions": 359,
      "deletions": 10
    },
    {
      "id": "PR_kwDOMT5cIs7X1JHn",
      "title": "feat(automations): clarification quick-pick UI",
      "author": "2-A-M",
      "number": 7341,
      "body": "## Summary\n\nRenders the `needs_clarification` response from `POST /api/n8n/workflows/generate` (added in #7316) as an inline panel in `AutomationsView`, just below the missing-credentials banner. The user picks from a row of buttons drawn from the `connector-target-catalog` snapshot (#7315), the host calls `POST /api/n8n/workflows/resolve-clarification` with `{paramPath, value}`, and either deploys (clearing the panel and refreshing the workflow list) or chains a follow-up picker (server then channel) by surfacing the next pending clarification.\n\nThis was the planned slice-2 P5 UI surface that #7316 / #7317 made the backend for. Shipping it now closes the loop: the route + UX restoration are already on develop, but the user-facing clarification picker was missing.\n\n## Implementation\n\n`ClarificationPanel` renders `ChoiceWidget` directly. `ChoiceWidget`'s existing `onChoose` callback contract was already a clean direct callback — the chat round-trip via `sendActionMessage` is layered on in `MessageContent.tsx`, not in the widget itself, so the widget did not need an `onChooseDirect` prop. The clarification flow simply instantiates `ChoiceWidget` with its own callback.\n\n`optionsForClarification` narrows the catalog snapshot per clarification kind:\n- `target_server` lists one button per group.\n- `target_channel` narrows to `scope.guildId` when set, then lists each text channel; if no scope is set and multiple guilds returned, the label is prefixed with the guild name to disambiguate same-named channels.\n- `recipient` lists each recipient target.\n- `value` / `free_text` / unmatched-platform fall through to a free-text `Input` bubble (`ClarificationFreeTextInput`) so the user can still answer when no catalog backs the question.\n\nCancel dismisses the panel locally without touching the server. A busy spinner suppresses re-clicks while resolve is in flight; an error string surfaces failed resolves (bad paramPath, validation rejection) without dropping the panel.\n\n`client-n8n.ts` gains `resolveN8nClarification(request)` calling `POST /api/n8n/workflows/resolve-clarification` with the same 120s timeout as `generateN8nWorkflow` (validateAndRepair + deploy can be slow).\n\n## Stacking\n\n**Depends on #7340** (`milady/fix-trigger-delete-name`) — that PR's P1 fix is the first commit in this branch. When #7340 merges, this PR's diff collapses to just the P5 commit.\n\n## Test plan\n\n- [x] `bun run typecheck` clean in `packages/app-core`\n- [ ] Manual: type a Discord-targeting prompt like \"send a Discord message to my announcements channel when a new GitHub issue is opened\" → expect `target_server` clarification card → click an option → expect chained `target_channel` clarification → click a channel → expect deploy success and panel clears\n- [ ] Manual: same flow with `kind: free_text` clarification → expect `ClarificationFreeTextInput` → typing + Apply submits the value\n- [ ] Manual: Cancel dismisses the panel without server call\n\nBackend coverage from #7316 (route + helper tests) covers the `resolve-clarification` endpoint.\n\n<!-- greptile_comment -->\n\n<h3>Greptile Summary</h3>\n\nThis PR adds the clarification quick-pick UI (`ClarificationPanel`, `ClarificationFreeTextInput`, `optionsForClarification`) to `AutomationsView`, replacing the previous static page-notice with an inline picker that chains server → channel → recipient selections driven by the catalog snapshot. `client-n8n.ts` gains `resolveN8nClarification` with the same 120 s timeout as `generateN8nWorkflow`.\n\n<h3>Confidence Score: 4/5</h3>\n\nSafe to merge with minor follow-ups — no runtime blocking bugs; two P2 edge cases around key collisions and dead UI code.\n\nAll three previously-flagged P1s (React key, busy-state leak, stale free-text) are addressed in this version of the code. Remaining findings are P2: `choiceId` can collide for consecutive paramPath-less clarifications, and `currentIndex` is never incremented so the Step X of Y display is unreachable. Neither blocks the happy path.\n\npackages/app-core/src/components/pages/AutomationsView.tsx — `choiceId` generation and `currentIndex` advancement logic.\n\n<h3>Important Files Changed</h3>\n\n| Filename | Overview |\n|----------|----------|\n| packages/app-core/src/api/client-n8n.ts | Adds `resolveN8nClarification` method via declaration merging, mirroring `generateN8nWorkflow` with the same 120 s timeout; straightforward and consistent with existing patterns. |\n| packages/app-core/src/components/pages/AutomationsView.tsx | Adds `ClarificationPanel`, `ClarificationFreeTextInput`, and `optionsForClarification`; wires `resolveClarificationChoice` into `AutomationsLayout`. Two P2s: `choiceId` can collide for consecutive free-text clarifications with absent `paramPath`, and `currentIndex` is never advanced so the \"Step X of Y\" UI is unreachable. |\n\n</details>\n\n<h3>Sequence Diagram</h3>\n\n```mermaid\nsequenceDiagram\n    participant U as User\n    participant AV as AutomationsView\n    participant API as /api/n8n/workflows\n\n    U->>AV: Submit automation prompt\n    AV->>API: POST /generate\n    API-->>AV: needs_clarification {clarifications, catalog, draft}\n    AV->>AV: setClarification({response, currentIndex:0})\n    AV->>U: Render ClarificationPanel (ChoiceWidget or FreeTextInput)\n\n    U->>AV: Pick option / submit text\n    AV->>API: POST /resolve-clarification {draft, resolutions}\n\n    alt Another clarification needed\n        API-->>AV: needs_clarification (chained)\n        AV->>AV: setClarification({response, currentIndex:0})\n        AV->>U: Render next ClarificationPanel\n    else Missing credentials\n        API-->>AV: missing_credentials\n        AV->>AV: setMissingCredentials(...)\n        AV->>U: Show credentials banner\n    else Deploy success\n        API-->>AV: deployed workflow {id}\n        AV->>AV: setClarification(null), refreshAutomations()\n        AV->>U: Select deployed workflow\n    end\n```\n\n<sub>Reviews (3): Last reviewed commit: [\"fix(automations): surface post-deploy re...\"](https://github.com/elizaos/eliza/commit/ad3416cec19be4072196a1e05c5e32844f4a30a2) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=30623960)</sub>\n\n<!-- /greptile_comment -->",
      "repository": "elizaos/eliza",
      "createdAt": "2026-05-03T21:48:23Z",
      "mergedAt": "2026-05-04T02:03:29Z",
      "additions": 307,
      "deletions": 6
    }
  ],
  "codeChanges": {
    "additions": 25133,
    "deletions": 1265,
    "files": 174,
    "commitCount": 156
  },
  "completedItems": [
    {
      "title": "feat(automations): clarification quick-pick UI",
      "prNumber": 7341,
      "type": "feature",
      "body": "## Summary\n\nRenders the `needs_clarification` response from `POST /api/n8n/workflows/generate` (added in #7316) as an inline panel in `AutomationsView`, just below the missing-credentials banner. The user picks from a row of buttons drawn f",
      "files": [
        "packages/app-core/src/api/client-n8n.ts",
        "packages/app-core/src/components/pages/AutomationsView.tsx"
      ]
    },
    {
      "title": "fix(automations): pass triggerName to onDeleteTrigger from detail pane",
      "prNumber": 7340,
      "type": "bugfix",
      "body": "## Summary\n\nGreptile flagged a P1 bug on #7317 that shipped unfixed when the PR merged: `TriggerAutomationDetailPane`'s delete button calls `onDeleteTrigger(trigger.id)`, but the confirmation dialog reads `form.displayName` — which reflects",
      "files": [
        "packages/app-core/src/components/pages/AutomationsView.tsx"
      ]
    },
    {
      "title": "chore(deps): update dependency zod to v4.4.2",
      "prNumber": 7339,
      "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| [zod](https://zod.dev) ([source](https:",
      "files": [
        "cloud/package.json",
        "plugins/plugin-claude-code-workbench/package.json"
      ]
    },
    {
      "title": "chore(deps): update dependency undici to v6.25.0",
      "prNumber": 7338,
      "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| [undici](https://undici.nodejs.org) ([s",
      "files": [
        "cloud/package.json"
      ]
    },
    {
      "title": "chore(deps): update dependency typescript to v5.9.3",
      "prNumber": 7335,
      "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| [typescript](https://www.typescriptlang",
      "files": [
        "plugins/plugin-video/package.json"
      ]
    },
    {
      "title": "chore(deps): update dependency tsx to v4.21.0",
      "prNumber": 7334,
      "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| [tsx](https://tsx.is) ([source](https:/",
      "files": [
        "plugins/plugin-social-alpha/package.json"
      ]
    },
    {
      "title": "fix(cloud-frontend): cli-login active flag race on cleanup",
      "prNumber": 7377,
      "type": "bugfix",
      "body": "## Summary\n\nFollow-up to #7367. That PR fixed the `useEffect` cleanup deadlock by adding the `if (!completionFiredRef.current) abort.abort()` guard, but the `active` flag race was left in place.\n\nIf `authenticated` or `ready` toggles in `us",
      "files": [
        "cloud/apps/frontend/package.json",
        "cloud/apps/frontend/src/pages/auth/cli-login/page.test.tsx",
        "cloud/apps/frontend/src/pages/auth/cli-login/page.tsx",
        "cloud/apps/frontend/vitest.config.ts",
        "cloud/apps/frontend/vitest.setup.ts"
      ]
    },
    {
      "title": "feat(cloud): support monetized container app domains",
      "prNumber": 7376,
      "type": "feature",
      "body": "# Relates to\n\nCloud app/domain monetization build path.\n\n# Risks\n\nLarge. This touches Cloud app auth, app-scoped chat, Cloudflare domain management, and container deployment status handling. Review should focus on route ownership checks, bi",
      "files": [
        "cloud/.env.example",
        "cloud/apps/api/cron/cleanup-stuck-provisioning/route.ts",
        "cloud/apps/api/src/_router.generated.ts",
        "cloud/apps/api/src/middleware/auth.ts",
        "cloud/apps/api/v1/_container-control-plane-forward.ts",
        "cloud/apps/api/v1/admin/docker-nodes/[nodeId]/health-check/route.ts",
        "cloud/apps/api/v1/apps/[id]/chat/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/[domain]/dns/[recordId]/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/[domain]/dns/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/buy/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/check/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/status/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/sync/route.ts",
        "cloud/apps/api/v1/apps/[id]/domains/verify/route.ts",
        "cloud/apps/api/v1/apps/[id]/public/route.ts",
        "cloud/apps/api/v1/containers/[id]/logs/route.ts",
        "cloud/apps/api/v1/containers/[id]/route.ts",
        "cloud/apps/api/v1/containers/route.ts",
        "cloud/apps/api/v1/cron/deployment-monitor/route.ts",
        "cloud/apps/api/v1/cron/node-autoscale/route.ts",
        "cloud/apps/api/v1/domains/resolve/route.ts",
        "cloud/apps/api/v1/domains/route.ts",
        "cloud/apps/api/v1/domains/search/route.ts",
        "cloud/apps/frontend/package.json",
        "cloud/apps/frontend/src/App.tsx",
        "cloud/apps/frontend/src/entry-server.tsx",
        "cloud/apps/frontend/src/lib/steward-session.ts",
        "cloud/apps/frontend/src/pages/auth/callback/email/page.tsx",
        "cloud/apps/frontend/src/pages/login/steward-login-section.tsx",
        "cloud/apps/frontend/vite.config.ts",
        "cloud/docs/proposals/cloudflare-domain-broker.md",
        "cloud/package.json",
        "cloud/packages/agent-skills/eliza-cloud/SKILL.md",
        "cloud/packages/db/migrations/0098_drop_vercel_artifacts.sql",
        "cloud/packages/db/migrations/0105_managed_domains_cloudflare_provider.sql",
        "cloud/packages/db/migrations/meta/_journal.json",
        "cloud/packages/db/schemas/managed-domains.ts",
        "cloud/packages/docs/agent-skill-build-monetized-app.md",
        "cloud/packages/docs/building-a-monetized-app.md",
        "cloud/packages/lib/cache/socket-redis.ts",
        "cloud/packages/lib/config/containers-env.ts",
        "cloud/packages/lib/middleware/rate-limit-hono-cloudflare.ts",
        "cloud/packages/lib/providers/index.ts",
        "cloud/packages/lib/providers/language-model.ts",
        "cloud/packages/lib/providers/provider-env.ts",
        "cloud/packages/lib/providers/vercel-ai-gateway.ts",
        "cloud/packages/lib/services/app-domains-compat.ts",
        "cloud/packages/lib/services/apps.ts",
        "cloud/packages/lib/services/cloudflare-dns.ts"
      ]
    },
    {
      "title": "feat(slack): migrate plugin-slack into the monorepo",
      "prNumber": 7375,
      "type": "feature",
      "body": "## Summary\n\nBrings \\`@elizaos/plugin-slack\\` from [elizaos-plugins/plugin-slack](https://github.com/elizaos-plugins/plugin-slack) into the monorepo at \\`plugins/plugin-slack/\\` alongside the other connector plugins already living here (disc",
      "files": [
        "plugins/plugin-slack/LICENSE",
        "plugins/plugin-slack/README.md",
        "plugins/plugin-slack/__tests__/accounts.test.ts",
        "plugins/plugin-slack/__tests__/formatting.test.ts",
        "plugins/plugin-slack/build.ts",
        "plugins/plugin-slack/package.json",
        "plugins/plugin-slack/src/accounts.ts",
        "plugins/plugin-slack/src/actions/deleteMessage.ts",
        "plugins/plugin-slack/src/actions/editMessage.ts",
        "plugins/plugin-slack/src/actions/emojiList.ts",
        "plugins/plugin-slack/src/actions/getUserInfo.ts",
        "plugins/plugin-slack/src/actions/listChannels.ts",
        "plugins/plugin-slack/src/actions/listPins.ts",
        "plugins/plugin-slack/src/actions/pinMessage.ts",
        "plugins/plugin-slack/src/actions/reactToMessage.ts",
        "plugins/plugin-slack/src/actions/readChannel.ts",
        "plugins/plugin-slack/src/actions/sendMessage.ts",
        "plugins/plugin-slack/src/actions/unpinMessage.ts",
        "plugins/plugin-slack/src/config.ts",
        "plugins/plugin-slack/src/formatting.ts",
        "plugins/plugin-slack/src/index.ts",
        "plugins/plugin-slack/src/providers/channelState.ts",
        "plugins/plugin-slack/src/providers/memberList.ts",
        "plugins/plugin-slack/src/providers/workspaceInfo.ts",
        "plugins/plugin-slack/src/service.ts",
        "plugins/plugin-slack/src/types.ts",
        "plugins/plugin-slack/tsconfig.json"
      ]
    },
    {
      "title": "fix(cloud): stop billing-fetch render-loop in CloudDashboard",
      "prNumber": 7374,
      "type": "bugfix",
      "body": "## Summary\n\nThe \\\"fire on connect\\\" \\`useEffect\\` in \\`CloudDashboard\\` that calls \\`fetchBillingData()\\` listed \\`fetchBillingData\\` itself in its dep array. \\`fetchBillingData\\` is a \\`useCallback\\` whose deps include \\`t\\` (\\`useTranslat",
      "files": [
        "packages/app-core/src/components/pages/ElizaCloudDashboard.tsx"
      ]
    },
    {
      "title": "feat(n8n-workflow): structured ClarificationRequest + name->id prompt rules",
      "prNumber": 7373,
      "type": "feature",
      "body": "## Summary\n\nMirror of [elizaos-plugins/plugin-n8n-workflow#27](https://github.com/elizaos-plugins/plugin-n8n-workflow/pull/27) + [#28](https://github.com/elizaos-plugins/plugin-n8n-workflow/pull/28), combined into a single PR since the plug",
      "files": [
        "plugins/plugin-n8n-workflow/__tests__/unit/clarification.test.ts",
        "plugins/plugin-n8n-workflow/__tests__/unit/workflowGenerationPrompt.test.ts",
        "plugins/plugin-n8n-workflow/src/actions/createWorkflow.ts",
        "plugins/plugin-n8n-workflow/src/prompts/workflowGeneration.ts",
        "plugins/plugin-n8n-workflow/src/services/n8n-workflow-service.ts",
        "plugins/plugin-n8n-workflow/src/types/index.ts",
        "plugins/plugin-n8n-workflow/src/utils/clarification.ts",
        "plugins/plugin-n8n-workflow/src/utils/index.ts",
        "plugins/plugin-n8n-workflow/src/utils/validateAndRepair.ts"
      ]
    },
    {
      "title": "feat(n8n-workflow): render Runtime Facts as fenced JSON block",
      "prNumber": 7372,
      "type": "feature",
      "body": "## Summary\n\nMirror of [elizaos-plugins/plugin-n8n-workflow#26](https://github.com/elizaos-plugins/plugin-n8n-workflow/pull/26)'s nitpick fix into the monorepo. Plugin source of truth lives here now.\n\n`buildRuntimeContextSections` previously",
      "files": [
        "plugins/plugin-n8n-workflow/src/utils/generation.ts"
      ]
    },
    {
      "title": "fix(elizacloud): widen fence-strip and dedupe duplicated responses output",
      "prNumber": 7371,
      "type": "bugfix",
      "body": "## Summary\n\nMirror of [elizaos-plugins/plugin-elizacloud#18](https://github.com/elizaos-plugins/plugin-elizacloud/pull/18) into the monorepo. Same root cause, same fix — the plugin source of truth lives here now, so this is the canonical la",
      "files": [
        "plugins/plugin-elizacloud/__tests__/unit/text-object-models.real.test.ts",
        "plugins/plugin-elizacloud/models/object.ts",
        "plugins/plugin-elizacloud/utils/responses-output.ts"
      ]
    },
    {
      "title": "fix(automations): support free-form clarifications in resolve flow",
      "prNumber": 7370,
      "type": "bugfix",
      "body": "## Summary\n\nThe clarification round-trip assumed every clarification has a non-empty `paramPath` that maps a user-supplied value into a workflow field. In practice the n8n workflow LLM also emits free-form clarifications without a paramPath",
      "files": [
        "packages/app-core/src/api/n8n-clarification.test.ts",
        "packages/app-core/src/api/n8n-clarification.ts",
        "packages/app-core/src/api/n8n-routes.ts"
      ]
    },
    {
      "title": "fix(n8n-workflow): tolerate prose-trailed JSON in parseWorkflowResponse",
      "prNumber": 7369,
      "type": "bugfix",
      "body": "## Summary\n\nEven with `responseFormat: { type: 'json_object' }` set on the `TEXT_LARGE` call, the LLM occasionally appends conversational prose **after** the workflow JSON (real example from a session today: `{...} What's good big man? meow",
      "files": [
        "plugins/plugin-n8n-workflow/src/utils/generation.ts"
      ]
    },
    {
      "title": "fix(agent): skip vault sentinels in applyConfigEnvToProcessEnv",
      "prNumber": 7368,
      "type": "bugfix",
      "body": "## Summary\n\n`loadElizaConfig()` is invoked by ~30 services post-boot (registry-client, escalation, owner-name, custom-actions, plugin-routes, onboarding-routes, api/server, runtime/eliza, …). Every call walks `config.env` and unconditionall",
      "files": [
        "packages/agent/src/config/config.ts"
      ]
    },
    {
      "title": "fix(cloud-frontend): cli-login completion effect deadlock",
      "prNumber": 7367,
      "type": "bugfix",
      "body": "## Summary\n\nThe `/auth/cli-login` page could get stuck on \"Generating API Key\" because the `useEffect` that POSTs `/api/auth/cli-session/:id/complete` listed `completion.status` in its dependency array. Setting status to `completing` re-ran",
      "files": [
        "cloud/apps/frontend/src/pages/auth/cli-login/page.tsx"
      ]
    },
    {
      "title": "fix(cloud): repair steward login session flow",
      "prNumber": 7361,
      "type": "bugfix",
      "body": "## Summary\\n- prefer STEWARD_JWT_SECRET over legacy STEWARD_SESSION_SECRET in workers-hono-auth so CLI completion verifies the same Steward JWT accepted by steward-session\\n- default browser API calls back to same-origin /api proxy so front",
      "files": [
        "cloud/apps/frontend/src/entry-server.tsx",
        "cloud/apps/frontend/src/lib/api-client.ts",
        "cloud/apps/frontend/src/pages/login/steward-login-section.tsx",
        "cloud/packages/lib/auth/workers-hono-auth.ts",
        "cloud/packages/lib/providers/StewardProvider.tsx",
        "cloud/packages/tests/unit/workers-hono-auth.test.ts"
      ]
    },
    {
      "title": "fix(cloud/frontend): StewardProvider syncs steward-session cookie to api.elizacloud.ai",
      "prNumber": 7360,
      "type": "bugfix",
      "body": "## Bug\n\nFollow-up to #7359. The login form's `setSessionCookie` was switched to `apiFetch` in #7359, but `StewardProvider` (`cloud/packages/lib/providers/StewardProvider.tsx`) has its own auto-sync `useEffect` that POSTs the localStorage to",
      "files": [
        "cloud/apps/frontend/src/pages/login/steward-login-section.tsx",
        "cloud/packages/lib/providers/StewardProvider.tsx"
      ]
    },
    {
      "title": "fix(cloud/frontend): apiFetch for /api/auth/steward-session",
      "prNumber": 7359,
      "type": "bugfix",
      "body": "## Bug\n\nFollow-up to #7358. `setSessionCookie` (in `steward-login-section.tsx`) was still calling raw `fetch(\"/api/auth/steward-session\")`, which goes same-origin to `www.elizacloud.ai`. The Worker sets `steward-token` + `steward-authed` co",
      "files": [
        "cloud/apps/frontend/src/pages/login/steward-login-section.tsx"
      ]
    },
    {
      "title": "fix(cloud/frontend): SPA hits api.elizacloud.ai directly for /steward/*",
      "prNumber": 7358,
      "type": "bugfix",
      "body": "## Bug\n\nThe Cloudflare Pages `functions/api/[[path]].ts` + `functions/steward/[[path]].ts` proxy keeps disappearing on manual local deploys. Each time it does, every `www.elizacloud.ai/api/*` and `/steward/*` request falls through to the SP",
      "files": [
        "cloud/apps/frontend/src/entry-server.tsx",
        "cloud/packages/lib/steward-url.ts"
      ]
    },
    {
      "title": "fix(cloud/frontend): consolidate Pages Functions into _middleware.ts",
      "prNumber": 7357,
      "type": "bugfix",
      "body": "## Bug\n\nCloudflare's Pages bundler translates the catch-all directory pattern `[[path]].ts` into the route pattern `/:path*` and registers it with the Pages router on cold start. The Pages runtime path-to-regexp dependency was upgraded to v",
      "files": [
        "cloud/apps/frontend/functions/_middleware.ts",
        "cloud/apps/frontend/functions/api/[[path]].ts",
        "cloud/apps/frontend/functions/steward/[[path]].ts",
        "cloud/packages/tests/unit/cloudflare-pages-functions.test.ts"
      ]
    },
    {
      "title": "Add ilfeops code + analysis mode",
      "prNumber": 7356,
      "type": "other",
      "body": "This adds some code to make things more interesting",
      "files": [
        "apps/app-lifeops/src/actions/activity-report.character-voice.test.ts",
        "apps/app-lifeops/src/actions/activity-report.ts",
        "apps/app-lifeops/src/actions/extractor-pipeline.test.ts",
        "apps/app-lifeops/src/actions/extractor-pipeline.ts",
        "apps/app-lifeops/src/actions/health.character-voice.test.ts",
        "apps/app-lifeops/src/actions/health.ts",
        "apps/app-lifeops/src/actions/inbox.invariant.test.ts",
        "apps/app-lifeops/src/actions/inbox.ts",
        "apps/app-lifeops/src/actions/life-goal-extractor.ts",
        "apps/app-lifeops/src/actions/life-param-extractor.test.ts",
        "apps/app-lifeops/src/actions/life-param-extractor.ts",
        "apps/app-lifeops/src/actions/life-update-extractor.test.ts",
        "apps/app-lifeops/src/actions/life-update-extractor.ts",
        "apps/app-lifeops/src/actions/life.extractor.test.ts",
        "apps/app-lifeops/src/actions/life.extractor.ts",
        "apps/app-lifeops/src/actions/lifeops-grounded-reply.ts",
        "apps/app-lifeops/src/actions/relationships.character-voice.test.ts",
        "apps/app-lifeops/src/actions/relationships.ts",
        "apps/app-lifeops/src/actions/scheduling.character-voice.test.ts",
        "apps/app-lifeops/src/actions/scheduling.ts",
        "apps/app-lifeops/src/actions/screen-time.character-voice.test.ts",
        "apps/app-lifeops/src/actions/screen-time.ts",
        "apps/app-lifeops/src/actions/website-blocker.test.ts",
        "apps/app-lifeops/src/actions/website-blocker.ts",
        "apps/app-lifeops/src/activity-profile/presence-signal-bridge-service.ts",
        "apps/app-lifeops/src/activity-profile/proactive-planner.social-overuse.test.ts",
        "apps/app-lifeops/src/activity-profile/proactive-planner.ts",
        "apps/app-lifeops/src/activity-profile/proactive-worker.ts",
        "apps/app-lifeops/src/activity-profile/types.ts",
        "apps/app-lifeops/src/lifeops/awake-probability.test.ts",
        "apps/app-lifeops/src/lifeops/browser-extension-store.ts",
        "apps/app-lifeops/src/lifeops/bulk-review.test.ts",
        "apps/app-lifeops/src/lifeops/bulk-review.ts",
        "apps/app-lifeops/src/lifeops/checkin/__tests__/checkin-service.test.ts",
        "apps/app-lifeops/src/lifeops/checkin/__tests__/sleep-cycle-dispatch.test.ts",
        "apps/app-lifeops/src/lifeops/checkin/checkin-service.ts",
        "apps/app-lifeops/src/lifeops/checkin/schedule-resolver.ts",
        "apps/app-lifeops/src/lifeops/checkin/sleep-cycle-dispatch.ts",
        "apps/app-lifeops/src/lifeops/checkin/types.ts",
        "apps/app-lifeops/src/lifeops/contact-route-policy.ts",
        "apps/app-lifeops/src/lifeops/context-graph.test.ts",
        "apps/app-lifeops/src/lifeops/context-graph.ts",
        "apps/app-lifeops/src/lifeops/continuity-probe.ts",
        "apps/app-lifeops/src/lifeops/device-identity.test.ts",
        "apps/app-lifeops/src/lifeops/device-identity.ts",
        "apps/app-lifeops/src/lifeops/document-review.test.ts",
        "apps/app-lifeops/src/lifeops/document-review.ts",
        "apps/app-lifeops/src/lifeops/email-curation.test.ts",
        "apps/app-lifeops/src/lifeops/email-curation.ts",
        "apps/app-lifeops/src/lifeops/health-bridge.ts"
      ]
    },
    {
      "title": "chore(deps): update azure/setup-helm action to v5",
      "prNumber": 7355,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Type | Update | Change |\n|---|---|---|---|\n| [azure/setup-helm](https://redirect.github.com/azure/setup-helm) | action | major | `v4` → `v5` |\n\n---\n\n> [!WARNING]\n> Some dependencies could",
      "files": [
        "cloud/.github/workflows/gateway-discord.yml"
      ]
    },
    {
      "title": "chore(deps): update dependency zod to v4.4.3",
      "prNumber": 7354,
      "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| [zod](https://zod.dev) ([source](https:",
      "files": [
        "cloud/package.json",
        "plugins/plugin-claude-code-workbench/package.json"
      ]
    },
    {
      "title": "fix(elizaos): include cloud-sdk workspace in fullstack-app template",
      "prNumber": 7347,
      "type": "bugfix",
      "body": "## Summary\n\n- The fullstack-app template's `requiredSubmodules` clones `plugins/plugin-elizacloud`, which has a `workspace:*` dependency on `@elizaos/cloud-sdk` (at `cloud/packages/sdk`).\n- The generated project's `workspaces` array did not",
      "files": [
        "packages/elizaos/templates/fullstack-app/package.json",
        "packages/templates/fullstack-app/package.json"
      ]
    },
    {
      "title": "fix(plugin-video): revert typescript downgrade that hangs bun resolver",
      "prNumber": 7346,
      "type": "bugfix",
      "body": "PR #7335 (renovate) downgraded plugin-video's typescript devDep from ^6.0.0 to ^5.7.3. Every other plugin in the workspace pins typescript ^6.0.x, so the introduced version split puts bun's resolver into a pathological loop — Build Agent Im",
      "files": [
        "plugins/plugin-video/package.json"
      ]
    },
    {
      "title": "chore(deps): update actions/cache action to v5",
      "prNumber": 7345,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Type | Update | Change |\n|---|---|---|---|\n| [actions/cache](https://redirect.github.com/actions/cache) | action | major | `v4` → `v5` |\n\n---\n\n> [!WARNING]\n> Some dependencies could not b",
      "files": [
        "plugins/plugin-bluesky/.github/workflows/ci.yml",
        "plugins/plugin-groq/.github/workflows/ci.yml",
        "plugins/plugin-groq/.github/workflows/crates-deploy.yml"
      ]
    },
    {
      "title": "chore(deps): update terraform google to v7.30.0",
      "prNumber": 7344,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Type | Update | Change |\n|---|---|---|---|\n| [google](https://registry.terraform.io/providers/hashicorp/google) ([source](https://redirect.github.com/hashicorp/terraform-provider-google))",
      "files": [
        "cloud/packages/infra/terraform/gcp/01-foundation/.terraform.lock.hcl",
        "cloud/packages/infra/terraform/gcp/02-k8s/.terraform.lock.hcl"
      ]
    },
    {
      "title": "chore(deps): update terraform aws to v6.43.0",
      "prNumber": 7343,
      "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 | Type | Update | Change |\n|---|---|---|---|\n| [aws](https://registry.terraform.io/providers/hashicorp/aws) ([source](",
      "files": [
        "cloud/packages/infra/terraform/.terraform.lock.hcl",
        "cloud/services/gateway-discord/terraform/.terraform.lock.hcl"
      ]
    },
    {
      "title": "chore(deps): update gradle to v9.5.0",
      "prNumber": 7342,
      "type": "other",
      "body": "This PR contains the following updates:\n\n| Package | Update | Change |\n|---|---|---|\n| [gradle](https://gradle.org) ([source](https://redirect.github.com/gradle/gradle)) | minor | `9.4.1` → `9.5.0` |\n\n---\n\n> [!WARNING]\n> Some dependencies c",
      "files": [
        "packages/app-core/platforms/android/gradle/wrapper/gradle-wrapper.properties"
      ]
    }
  ],
  "topContributors": [
    {
      "username": "2-A-M",
      "avatarUrl": "https://avatars.githubusercontent.com/u/96268540?u=b7d92c0e2a91af580d09eeae862eef576955ab8a&v=4",
      "totalScore": 331.83194645981956,
      "prScore": 331.3939464598196,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.43799999999999994,
      "summary": null
    },
    {
      "username": "0xSolace",
      "avatarUrl": "https://avatars.githubusercontent.com/u/257989456?u=e0d4e0c6385403319241eb46ba647b49083d4a05&v=4",
      "totalScore": 217.4816532184886,
      "prScore": 217.2816532184886,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.2,
      "summary": null
    },
    {
      "username": "greptile-apps",
      "avatarUrl": "https://avatars.githubusercontent.com/in/867647?v=4",
      "totalScore": 85.5,
      "prScore": 0,
      "issueScore": 0,
      "reviewScore": 85.5,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "lalalune",
      "avatarUrl": "https://avatars.githubusercontent.com/u/18633264?u=e2e906c3712c2506ebfa98df01c2cfdc50050b30&v=4",
      "totalScore": 80.24608004091016,
      "prScore": 80.24608004091016,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "NubsCarson",
      "avatarUrl": "https://avatars.githubusercontent.com/u/192162056?u=d2be9082dbee60fcbad21d32bf6e662ab1af3674&v=4",
      "totalScore": 59.5437738965761,
      "prScore": 59.5437738965761,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "standujar",
      "avatarUrl": "https://avatars.githubusercontent.com/u/16385918?u=718bdcd1585be8447bdfffb8c11ce249baa7532d&v=4",
      "totalScore": 54.763328839830905,
      "prScore": 48.763328839830905,
      "issueScore": 0,
      "reviewScore": 6,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "Dexploarer",
      "avatarUrl": "https://avatars.githubusercontent.com/u/211557447?u=21a243d61cc1f87574328ae07fc64d7d7577b53d&v=4",
      "totalScore": 31.94591014905531,
      "prScore": 31.94591014905531,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "dutchiono",
      "avatarUrl": "https://avatars.githubusercontent.com/u/86275975?u=0d8badaa81aa47682651f87dc2d363837876de98&v=4",
      "totalScore": 31.198947636399186,
      "prScore": 31.198947636399186,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "Sw4pIO",
      "avatarUrl": "https://avatars.githubusercontent.com/u/250003491?u=b9bad2342b9ccdb72ee4d4502d5534b6256e9d5c&v=4",
      "totalScore": 6,
      "prScore": 0,
      "issueScore": 6,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "Agnuxo1",
      "avatarUrl": "https://avatars.githubusercontent.com/u/166046035?u=4654f0706d2f6e9cf6894bd6717003d19f74645c&v=4",
      "totalScore": 4,
      "prScore": 0,
      "issueScore": 4,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "andex23",
      "avatarUrl": "https://avatars.githubusercontent.com/u/49397867?u=760e6ec36b34f3511f24928686d87f912c3eb7ba&v=4",
      "totalScore": 2,
      "prScore": 0,
      "issueScore": 2,
      "reviewScore": 0,
      "commentScore": 0,
      "summary": null
    },
    {
      "username": "bartonguestier1725-collab",
      "avatarUrl": "https://avatars.githubusercontent.com/u/249058300?v=4",
      "totalScore": 0.2,
      "prScore": 0,
      "issueScore": 0,
      "reviewScore": 0,
      "commentScore": 0.2,
      "summary": null
    }
  ],
  "newPRs": 33,
  "mergedPRs": 31,
  "newIssues": 5,
  "closedIssues": 1,
  "activeContributors": 12
}