Conversation
Pookie can now generate self-contained HTML apps and surface them in Slack as a card with an "Open app" button. The /a/[token] route renders the HTML inside a strict iframe sandbox (allow-scripts only, no allow-same-origin) so model-written code runs in an opaque origin and can't reach Pookie cookies, parent DOM, or top-level navigation. - create_html_app tool with size + document-shape validation - Encrypted Redis store keyed by team, 30-day TTL - HMAC-signed token URLs (so links aren't guessable) - Render route + 404 + CSP / frame-ancestors header config - System prompt entries (tool routing + common workflow) - Tests for sign/verify/expire, store round-trip + encryption, tool schema - Phase 2 PRD + follow-up issue for the bidirectional/MCP-Apps-host upgrade Co-authored-by: Cursor <cursoragent@cursor.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The channel-panel preload type used a forbidden `import()` type
annotation (`Promise<typeof import("emoji-picker-react")>`), which
tripped the typescript-eslint(consistent-type-imports) rule and broke
lint CI. Replace with `import type * as M` so the same module-namespace
type is referenced via a regular type-only import.
Co-authored-by: Cursor <cursoragent@cursor.com>
aidenybai
added a commit
that referenced
this pull request
May 7, 2026
Closes the four actionable findings from the review pass: #1 (medium) -- detection-source mismatch between auto-react and system reminder. The auto-react in handleSlackMessage previously only inspected [currentMessage, ...skippedMessages], so a uwu/owo/meow that arrived as a Redis-drained follow-up mid-turn (round 2+) flipped pet-mode on in the system reminder but never got its cat reaction. Auto-react bookkeeping now lives at the turn scope in handleSlackMessage with a single \`petAutoReacted\` flag and a \`tryPetAutoReact(candidates)\` helper called both on round 0 input AND after each Redis drain. To keep the messageId attached, drainFollowUps now returns the full QueuedFollowUp[] (text + messageId) instead of \`string[]\`; callers that only need text \`.map((f) => f.text)\`. The downstream followUpMessages -> system reminder pipeline is unchanged. #2 (low) -- belt-and-suspenders: findUwuTriggerMessage now filters out candidates with empty \`id\` so a malformed Slack message with text but no ts can't trigger a 400 from reactions.add. #5 (low) -- test coverage: resolveSlackEmojiShortcode now has cases for the bare cat emojis (🐱 → cat, 🐈 → cat2), skin-tone modifiers (👍🏻 / 👍🏿 → +1), and the bare-codepoint heart without its variation selector (\\u2764 → heart). #6 (low) -- tracing observability: stamp \`pookiebot.uwu_mode: true\` when the per-round detection lights up, plus \`pookiebot.uwu_trigger_message_id\` when the auto-react fires. Consistent with existing \`pookiebot.dropped_card\` etc. attributes. #7 (doc nit) -- the \`already_reacted\` comment now reflects Slack's exact-emoji semantics: that branch only fires when the SAME shortcode is already on the message, so reporting success there is genuinely correct (the user-facing reaction state matches what the model wanted). Tests: - thread-lock tests rewritten for the QueuedFollowUp[] return shape - agent-follow-ups mocks updated to mock objects with messageId - four new resolveSlackEmojiShortcode cases for #5 - 281 total tests passing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Pookie can now generate small self-contained HTML apps (calculators, configurators, mini dashboards, embedded viewers, "let me poke at this" tools) and surface them in Slack as a card with an "Open app ↗" button. The button links to
${BASE_URL}/a/<token>on Pookie itself, where the HTML renders inside a strict iframe sandbox.create_html_apptool: takes title / description / a complete HTML document, persists encrypted in Redis (30-day TTL), returns a HMAC-signed URL./a/[token]Next.js route: verifies the token, loads the row, and renders<iframe sandbox="allow-scripts" srcDoc={html} />— noallow-same-origin, noallow-top-navigation, no popups, no forms. The iframe runs in an opaque origin so model-generated code cannot reach Pookie cookies or the parent DOM.frame-ancestors 'self'),X-Frame-Options: SAMEORIGIN, andCache-Control: private, no-storeconfigured for the route.footerAction..scratch/html-apps/for the bidirectional postMessage bridge / MCP-Apps-host upgrade.The lazy Redis state adapter was extracted from
slack-bot.tsintoserver/state.tsso the new render route can share it.Security model
sandbox="allow-scripts"only. Withoutallow-same-originthe iframe is in an opaque origin and cannot read cookies, parent DOM, or storage.srcDoc, never via a public-fetch URL the iframe could navigate to.{ teamId, id, exp }keyed bySLACK_ENCRYPTION_KEY) and time-limited (30 days).frame-ancestors 'self'so other sites can't embed the wrapper.SLACK_ENCRYPTION_KEYpath used by memory.Future hardening called out in the Phase 2 PRD: host
/a/*on a separate origin (e.g.apps.pookie.app) so even a sandbox regression cannot reach Pookie cookies; gate the route via Slack OAuth before the bidirectional bridge ships.Test plan
pnpm testfromapps/api— 20 files / 176 tests pass (3 new files / 14 new tests).pnpm typecheck— no new errors. (One pre-existing missing-vaulerror in unrelated website mock components.)pnpm lint— no new errors. (One pre-existingconsistent-type-importswarning in unrelated website mock components.)pnpm format:checkclean on every touched file./a/<token>shows the friendly 404.Out of scope (tracked in
.scratch/html-apps/)ui://resources from connected MCP servers) — Phase 2.Made with Cursor