') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); feat: move permission prompts into composer by Astro-Han · Pull Request #881 · apache/maka · GitHub
Skip to content

feat: move permission prompts into composer - #881

Merged
Astro-Han merged 12 commits into
mainfrom
feat/permission-composer-takeover
Jul 13, 2026
Merged

feat: move permission prompts into composer#881
Astro-Han merged 12 commits into
mainfrom
feat/permission-composer-takeover

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace the blocking permission modal with a compact, non-modal surface that takes over the existing composer slot while preserving the hidden draft.
  • Keep the decision, operation summary, risk context, Stop, deny, and allow actions visible; move long parameters, file contents, and diffs behind a capped disclosure.
  • Consolidate permission card typography, summary geometry, governed Button variants, responsive behavior, and Storybook coverage across permission reasons.

Why

The full-screen modal hid the conversation and live browser, separated Stop from the pending interaction, and spent most of its space repeating transport-level details. PR1 of #825 needs one reusable composer interaction seam before AskUserQuestion can be added without creating a second input surface.

The new surface extends the existing composer slot and permission response path instead of introducing parallel state or lifecycle ownership. It preserves the existing permission FIFO, remember-for-turn behavior, response guards, and stop semantics.

Refs #825

Scope

This is only #825 PR1: permission composer takeover. It does not add or register AskUserQuestion; runtime/TUI and desktop question handling remain in PR2 and PR3.

Verification

  • npm test in packages/ui: 125 passed.
  • npm test in apps/desktop: 2,401 passed.
  • npm run typecheck in apps/desktop: passed.
  • npm run build-storybook in apps/desktop: passed.
  • npm run e2e -- permission-takeover.spec.ts in apps/desktop: 1 representative fake-backend journey passed, including hidden Composer draft preservation across an AppShell rerender.
  • Live Storybook computed-style audit across 13 default permission stories: every summary slot is 37.5 px and every footer is 43 px; ordinary cards are about 137 px, while cards with one necessary risk-context line are about 161 px.

Before

Full-screen modal with repeated metadata and a separate decision footer:

Before: full-screen permission modal

After

Compact composer takeover with one operation summary, adjacent decisions, and details collapsed by default:

After: compact permission composer takeover

Impact

  • Users retain conversation and browser context while a permission is waiting and can stop the active turn from the same surface.
  • Drafts survive allow, deny, and stop because Composer remains mounted while hidden.
  • No persistence, IPC, permission-policy, or migration contract changes.
  • PermissionDialog is replaced by PermissionPrompt; downstream UI imports are updated in the same PR.

Reviewer notes

Review the composer ownership boundary, the hidden-but-mounted draft invariant, response/stop lifecycle guards, disclosure scroll ownership, and whether each remaining visual distinction represents real information rather than duplicated decoration.

Ready for review

  • Verification is complete and the results above are current
  • Impact, compatibility, migration, documentation, and release-note needs are addressed
  • User-visible UI/UX changes include visual evidence, or Verification explains why it is not applicable

@Astro-Han
Astro-Han marked this pull request as ready for review July 13, 2026 14:48
@Astro-Han
Astro-Han merged commit 19fb3d6 into mainJul 13, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/permission-composer-takeover branch July 13, 2026 14:49
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Astro-Han