@ai-matrx/context-menu 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +14 -1
  3. package/dist/builder.cjs +1665 -0
  4. package/dist/builder.cjs.map +1 -0
  5. package/dist/builder.d.cts +22 -0
  6. package/dist/builder.d.ts +22 -0
  7. package/dist/builder.js +1650 -0
  8. package/dist/builder.js.map +1 -0
  9. package/dist/design-store.cjs +195 -0
  10. package/dist/design-store.cjs.map +1 -0
  11. package/dist/design-store.d.cts +42 -0
  12. package/dist/design-store.d.ts +42 -0
  13. package/dist/design-store.js +175 -0
  14. package/dist/design-store.js.map +1 -0
  15. package/dist/engine.cjs +3069 -0
  16. package/dist/engine.cjs.map +1 -0
  17. package/dist/engine.d.cts +731 -0
  18. package/dist/engine.d.ts +731 -0
  19. package/dist/engine.js +3250 -0
  20. package/dist/engine.js.map +1 -0
  21. package/dist/grouping-CB3zlD1T.d.ts +623 -0
  22. package/dist/grouping-CGcWsltu.d.cts +623 -0
  23. package/dist/host-types-AOiEYwR8.d.cts +9 -0
  24. package/dist/host-types-AOiEYwR8.d.ts +9 -0
  25. package/dist/index.cjs +486 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +46 -0
  28. package/dist/index.d.ts +46 -0
  29. package/dist/index.js +464 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/menu-content.cjs +3146 -0
  32. package/dist/menu-content.cjs.map +1 -0
  33. package/dist/menu-content.d.cts +30 -0
  34. package/dist/menu-content.d.ts +30 -0
  35. package/dist/menu-content.js +3197 -0
  36. package/dist/menu-content.js.map +1 -0
  37. package/dist/model-BdF0TqZ3.d.cts +107 -0
  38. package/dist/model-BdF0TqZ3.d.ts +107 -0
  39. package/dist/react.cjs +3322 -0
  40. package/dist/react.cjs.map +1 -0
  41. package/dist/react.d.cts +133 -0
  42. package/dist/react.d.ts +133 -0
  43. package/dist/react.js +3345 -0
  44. package/dist/react.js.map +1 -0
  45. package/package.json +170 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/utils/compact.ts","../src/engine/components/AlchemyMenuContent.tsx","../src/engine/utils/field-menu-header.ts","../src/engine/utils/already-here.ts","../src/engine/utils/editor-text-agent.ts","../src/engine/hooks/useContextMenuActions.ts","../src/engine/types.ts","../src/engine/utils/notify.ts","../src/engine/host/port.ts","../src/engine/utils/editor-text-insertion.ts","../src/engine/utils/insert-into-editor.ts","../src/engine/hooks/useUnifiedAgentContextMenu.ts","../src/engine/utils/menu-deadline.ts","../src/engine/model/requirement-gate.ts","../src/engine/value-resolution.ts","../src/engine/utils/selection-tracking.ts","../src/engine/utils/selection-write-back.ts","../src/engine/utils/json-menu-actions.ts","../src/engine/managed-agent-launch.ts","../src/engine/model/menu-model.ts","../src/engine/utils/key-combo.ts","../src/engine/alchemy-provider.ts","../src/engine/regroup/RegroupContext.tsx","../src/engine/regroup/grouping.ts","../src/engine/components/ShortcutKeyRunner.tsx"],"sourcesContent":["/**\n * Drops the keys whose value is `undefined`, so an object assembled from\n * maybe-present values satisfies a target whose optional properties do not\n * accept `undefined` (`exactOptionalPropertyTypes`). Reading any dropped key\n * still yields `undefined` — the only difference is `\"key\" in obj`.\n */\ntype Present<T> = { [K in keyof T as undefined extends T[K] ? never : K]: T[K] };\ntype Maybe<T> = { [K in keyof T as undefined extends T[K] ? K : never]?: Exclude<T[K], undefined> };\nexport type Compact<T> = Present<T> & Maybe<T>;\n\nexport function compact<T extends object>(value: T): Compact<T> {\n const out: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) if (v !== undefined) out[key] = v;\n return out as Compact<T>;\n}\n","\"use client\";\n\n// features/context-menu-v3/components/AlchemyMenuContent.tsx\n//\n// T1 + T1e for the right-click, the floating selection icon, the phone's\n// long-press sheet and the action palette — loaded by the shell through\n// next/dynamic on first open only (static import is still an eslint error).\n//\n// It runs the ONE engine hook (`useContextMenuActions` — every handler, the\n// single deduped agent fetch) and `buildMenuModel`, hands the result to the\n// Alchemy registry as this instance's provider (`alchemy-provider.ts`), and\n// renders the PACKAGE layout for the mode: `ContextMenuPanel` (desktop),\n// `ActionSheet` (phone), `ActionPalette` (palette). The click target is\n// composite, so the rich-document provider contributes the registry rows from\n// the same target — the bar, its ⋯ and this menu show one set of actions.\n\nimport { compact } from \"../utils/compact\";\nimport type { ChatRootState as RootState } from \"@ai-matrx/chat/store/root-state\";\nimport * as React from \"react\";\nimport { createClickTarget } from \"@ai-matrx/alchemy/actions\";\nimport { useAlchemyActions } from \"@ai-matrx/alchemy/react/host\";\nimport { ContextMenuPanel } from \"@ai-matrx/alchemy/react/menu\";\nimport { ActionSheet } from \"@ai-matrx/alchemy/react/sheet\";\nimport { ActionPalette } from \"@ai-matrx/alchemy/react/palette\";\nimport { SOURCE_WRITE_TARGET, richDocumentTargetHost } from \"@ai-matrx/rich-content/rich-document/actions/provider\";\nimport { useRichDocumentProvider } from \"@ai-matrx/rich-content/rich-document/actions/useRichDocumentProvider\";\nimport { useContextMenuActions } from \"../hooks/useContextMenuActions\";\nimport { buildMenuModel } from \"../model/menu-model\";\nimport { chatMessageSubject, namedHeader, contextMenuActionsFromModel, contextMenuProvider, menuEngineRevision, menuHeader, modelRevision } from \"../alchemy-provider\";\nimport { MenuRegroupContext, RegroupBoundary } from \"../regroup/RegroupContext\";\nimport type { MenuContentProps } from \"../types\";\n\nexport type AlchemyMenuMode = \"context\" | \"sheet\" | \"palette\";\n\n/**\n * Registry rows that belong to reading or editing text, not to a record: every\n * listen / read-aloud row (\"Read aloud selection\"), Compare, and Find. A\n * record-actions-only menu (a list row, a folder) leaves them out.\n */\nconst EDITOR_ONLY_RICH_IDS = new Set([\n \"compare-with-clipboard\",\n \"set-compare-base\",\n \"compare-with-base\",\n \"conversation-find\",\n]);\nexport function editorOnlyRichActionIds(actions: ReadonlyArray<{ id: string; category?: string }>): string[] {\n return actions.filter((a) => a.category === \"listen\" || EDITOR_ONLY_RICH_IDS.has(a.id)).map((a) => a.id);\n}\n\nexport interface AlchemyMenuContentProps extends Omit<MenuContentProps, \"variant\"> {\n mode: AlchemyMenuMode;\n /** Viewport point for the desktop menu (pointer, ⋯ button or floating icon). */\n point: { x: number; y: number };\n open: boolean;\n onOpenChange(open: boolean): void;\n}\n\nexport default function AlchemyMenuContent(props: AlchemyMenuContentProps): React.ReactElement {\n const { mode, point, open, onOpenChange, ...menuProps } = props;\n const m = useContextMenuActions(menuProps);\n // No fold under an invented heading (\"More…\" was removed, ALC-15 chair ruling 7): a grid's\n // own sections come first by the primary-section law; every other row keeps its own name.\n const model = buildMenuModel(m, menuProps);\n const { registry } = useAlchemyActions();\n useRichDocumentProvider();\n\n // This menu instance's provider: registered while mounted, reads the latest\n // model through a ref (handlers rebind every render).\n const instanceId = React.useId();\n // A library still loading (the first agent fetch) waits for the NEXT model\n // that changes what the menu draws, instead of vanishing (ALC-15 round 2).\n const waitersRef = React.useRef<((next: typeof model) => void)[]>([]);\n const nextModel = () => new Promise<typeof model>((resolve) => waitersRef.current.push(resolve));\n const actionsRef = React.useRef(contextMenuActionsFromModel(model, instanceId, { nextModel, editable: Boolean(menuProps.isEditable) }));\n const drawnRef = React.useRef(\"\");\n const drawn = modelRevision(model);\n React.useLayoutEffect(() => {\n actionsRef.current = contextMenuActionsFromModel(model, instanceId, { nextModel, editable: Boolean(menuProps.isEditable) });\n if (drawnRef.current !== drawn) {\n drawnRef.current = drawn;\n const waiters = waitersRef.current;\n waitersRef.current = [];\n for (const wake of waiters) wake(model);\n }\n });\n React.useEffect(\n () =>\n registry.register(contextMenuProvider(instanceId, () => actionsRef.current)),\n [registry, instanceId],\n );\n\n // A record-actions-only menu over no record source (a folder: its name is the\n // only text) contributes no document rows — no Copy as, Export, Save to or\n // agent handoff of a folder's name (page-pass /notes, 2026-09-28).\n const hasRichDocument =\n m.registryActions.length > 0 &&\n !(menuProps.recordActionsOnly && m.richDocCtx.source.type === \"raw\");\n // The source can be written back only when its adapter can save, or the\n // menu itself edits the field. A raw source (a table row's words, rendered\n // text) is read-only by definition — marking it writable put \"Open in\n // full-screen editor\" on every table row (live 2026-09-27).\n const sourceWritable =\n hasRichDocument &&\n !m.richDocCtx.source.readOnly &&\n (Boolean(m.richDocCtx.sourceAdapter.edit) || Boolean(menuProps.isEditable));\n const makeTarget = (withRich: boolean) =>\n createClickTarget({\n // The declared item under the pointer (a table row), as itemSources resolved it.\n item: menuProps.item ?? null,\n readOnly: hasRichDocument ? !sourceWritable : !menuProps.isEditable,\n writable: sourceWritable ? [SOURCE_WRITE_TARGET] : [],\n // The strip's Copy IS the registry's one-tap copy here — one row, not two.\n excludedActionIds: [\n ...m.excludedRichActionIds,\n ...(hasRichDocument ? [\"copy\"] : []),\n ...(menuProps.recordActionsOnly ? editorOnlyRichActionIds(m.registryActions) : []),\n ],\n organizationId: m.richDocCtx.organizationId,\n auth: {\n authenticated: m.richDocCtx.isAuthenticated,\n admin: m.richDocCtx.isAdmin,\n creator: m.richDocCtx.isCreator,\n },\n selection: menuProps.selectedText\n ? {\n text: menuProps.selectedText,\n type: menuProps.selectionRange?.type ?? \"non-editable\",\n start: menuProps.selectionRange?.start ?? 0,\n end: menuProps.selectionRange?.end ?? 0,\n handle: menuProps.selectionRange,\n }\n : null,\n payloadKinds: [\"markdown\"],\n host: {\n contextMenu: { kind: \"context-menu\", instanceId },\n ...(hasRichDocument && withRich\n ? {\n richDocument: richDocumentTargetHost(m.richDocCtx, {\n extra: menuProps.extraRichActions ?? [],\n }),\n }\n : {}),\n },\n });\n const [target] = React.useState(() => makeTarget(true));\n // In a field the header names the field (\"Body\"), never its raw text.\n // The message the menu opened on: its role and time, from the transcript store.\n // Either this menu IS the message's, or it is the transcript's and the\n // right-click resolved the message under the pointer — same subject.\n const chatMessage = chatMessageSubject({\n state: m.richDocCtx.getState() as unknown as RootState,\n source: m.richDocCtx.source,\n ...compact({\n extensions: m.richDocCtx.extensions,\n contextData: menuProps.contextData,\n }),\n });\n // A row (or any target) that NAMES itself wins over the generic header —\n // \"Quiz: Unit 2 review\", never \"Content: <agent context>\". A selection\n // still shows itself.\n const { content, contentLabel } =\n namedHeader(menuProps.heading, m.actionText) ?? menuHeader(m.actionText, m.fieldLabel, chatMessage);\n // Re-resolve when what the menu would draw moves (agents finish loading, a\n // toggle flips, the record is renamed) — the target object itself stays one\n // per open.\n const revision = menuEngineRevision(drawn, { content, contentLabel });\n const engine = { revision, content, contentLabel };\n\n // A pass-through everywhere except under a MenuRegroupContext (the regroup\n // demo): there it reports what resolved and may draw a proposed grouping.\n const close = () => onOpenChange(false);\n // Only under a MenuRegroupContext (the proposed-menu demo): its size and header choice.\n const regroup = React.useContext(MenuRegroupContext);\n const panelLook = { size: regroup?.size ?? \"standard\", hideHeader: regroup?.hideHeader ?? false } as const;\n if (mode === \"sheet\") {\n return (\n <RegroupBoundary arrangement={menuProps.menuLayout} close={close}>\n <ActionSheet {...engine} target={target} open={open} onOpenChange={onOpenChange} />\n </RegroupBoundary>\n );\n }\n if (mode === \"palette\") {\n return (\n <RegroupBoundary arrangement={menuProps.menuLayout} close={close}>\n <ActionPalette {...engine} target={target} open={open} onOpenChange={onOpenChange} />\n </RegroupBoundary>\n );\n }\n return (\n <RegroupBoundary arrangement={menuProps.menuLayout} close={close}>\n <ContextMenuPanel\n {...engine}\n target={target}\n point={point}\n open={open}\n onOpenChange={onOpenChange}\n arrangement={menuProps.menuLayout}\n density={menuProps.menuDensity}\n // A control over a container of the thing (a note tab's \"…\"): its own\n // rows first, the rest under one \"<subject> ▸\" (alchemy 0.8.28).\n {...compact({ subjectFold: menuProps.subjectFold })}\n {...panelLook}\n />\n </RegroupBoundary>\n );\n}\n","/**\n * THE MENU OPENED IN A FIELD NAMES THE FIELD (page-pass 2026-09-27,\n * /chat/message-templates/<id>). Right-clicking the Body box headed the menu\n * \"Content: {{reply.body}}\" — the field's raw text. The header is now the\n * field's own name (\"Body\"), with a short plain preview only when it helps:\n * merge fields read as their names (\"Reply body\"), and text that is ONLY merge\n * fields gets no preview (the name already says it). Pure, so it is tested\n * without a DOM menu.\n */\n\n/** A field's name, the way a person reads it on screen. `null` when it has none. */\nexport function fieldLabelOf(element: Element | null | undefined): string | null {\n if (!element) return null;\n const clean = (s: string | null | undefined) => (s ?? \"\").replace(/\\s+/g, \" \").replace(/\\s*\\*$/, \"\").trim() || null;\n const aria = clean(element.getAttribute(\"aria-label\"));\n if (aria) return aria;\n const labelledBy = element.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const text = labelledBy\n .split(/\\s+/)\n .map((id) => element.ownerDocument?.getElementById(id)?.textContent ?? \"\")\n .join(\" \");\n if (clean(text)) return clean(text);\n }\n const labels = (element as HTMLInputElement).labels;\n if (labels && labels.length > 0) {\n const text = clean(labels[0]?.textContent);\n if (text) return text;\n }\n const id = element.getAttribute(\"id\");\n if (id && element.ownerDocument) {\n const label = element.ownerDocument.querySelector(`label[for=\"${CSS.escape(id)}\"]`);\n if (clean(label?.textContent)) return clean(label?.textContent);\n }\n return null;\n}\n\nconst MERGE_FIELD = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** \"reply.body\" / \"reply_body\" → \"Reply body\". */\nexport function mergeFieldName(token: string): string {\n const words = token.replace(/[._-]+/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\").trim().toLowerCase();\n return words ? words[0]!.toUpperCase() + words.slice(1) : token;\n}\n\nexport const FIELD_PREVIEW_MAX = 60;\n\n/**\n * The preview beside the field's name: plain words with merge fields named,\n * clipped; `\"\"` when the text holds nothing but merge fields (or nothing).\n */\nexport function fieldPreview(text: string): string {\n const withoutFields = text.replace(MERGE_FIELD, \"\").replace(/[\\s\\p{P}]+/gu, \"\");\n if (!withoutFields) return \"\";\n const readable = text.replace(MERGE_FIELD, (_, name: string) => mergeFieldName(name)).replace(/\\s+/g, \" \").trim();\n return readable.length > FIELD_PREVIEW_MAX ? `${readable.slice(0, FIELD_PREVIEW_MAX - 1).trimEnd()}…` : readable;\n}\n","// features/context-menu-v3/utils/already-here.ts\n//\n// ACTIONS THAT TARGET THE THING YOU ARE ALREADY IN ARE ABSENT (page-pass\n// 2026-09-27, /notes/<id>): the menu inside a note offered \"Save to Notes\", and\n// the menu inside the editor offered \"Edit content\" and \"Open in full-screen\n// editor\". Each rich-document action id listed here is excluded for the menu\n// instance that is already that place.\n\nexport interface WhereTheMenuIs {\n /** The rich-document source type (`note`, `task`, `chat-message`, `raw`, …). */\n sourceType: string;\n /** The registry surface the menu belongs to. */\n surfaceName?: string | null | undefined;\n /** The menu wraps an editor (EditableContextMenu). */\n isEditable: boolean;\n}\n\n/** \"Save to X\" where the menu already IS an X. */\nconst SAVE_INTO_WHERE_YOU_ARE: ReadonlyArray<{ sourceType: string; surface: string; actionId: string }> = [\n { sourceType: \"note\", surface: \"matrx-user/notes\", actionId: \"save-to-notes\" },\n { sourceType: \"task\", surface: \"matrx-user/tasks\", actionId: \"save-to-task\" },\n];\n\n/** Opening a window from inside that same window (surface-only rules). */\nconst OPEN_WHERE_YOU_ARE: ReadonlyArray<{ surface: string; actionId: string }> = [\n // The Feedback window's menus offered \"Submit feedback\" — reopening itself.\n { surface: \"matrx-user/feedback\", actionId: \"submit-feedback\" },\n];\n\n/** Opening an editor from inside the editor. */\nconst EDITOR_DOORS = [\"edit\", \"open-fullscreen-editor\"] as const;\n\nexport function actionsAlreadyHere(where: WhereTheMenuIs): string[] {\n const out: string[] = [];\n for (const rule of SAVE_INTO_WHERE_YOU_ARE) {\n if (where.sourceType === rule.sourceType || where.surfaceName === rule.surface) out.push(rule.actionId);\n }\n for (const rule of OPEN_WHERE_YOU_ARE) {\n if (where.surfaceName === rule.surface) out.push(rule.actionId);\n }\n // On a record's OWN page (a note's source on the notes surface) the page is\n // its editor — its Write / Read toggle is the door — so the preview offers no\n // second one (live 2026-09-27, /notes/<id> in Read mode). Editor and preview\n // menus now carry the same set.\n // Matched by the SOURCE as well as the surface: live, the Read-mode menu on\n // /notes/<id> carried the note source under a surface name other than the\n // notes one, so a surface-only match missed it.\n const ownPage = SAVE_INTO_WHERE_YOU_ARE.some(\n (rule) => where.sourceType === rule.sourceType || where.surfaceName === rule.surface,\n );\n if (where.isEditable || ownPage) out.push(...EDITOR_DOORS);\n return [...new Set(out)];\n}\n","// features/context-menu-v3/utils/editor-text-agent.ts\n//\n// ONE AI SET FOR A RECORD IN EVERY VIEW (page-pass /notes, 2026-09-28). Clean\n// up / Help with this… / Custom agent are visible only when the action context\n// carries `callbacks.onRequestTextAgentAction` (a host that can review and\n// apply). RichDocument (a note's Read view) supplied it; the editor menus\n// (Write, Plain, Split) did not, so the same note lost its AI rows on switching\n// view. Any menu now offers the shell's review dialog — only where the\n// source can be saved back (a record source with an `edit` adapter, not read\n// only), and never over a host that already supplied its own.\n\nimport type { ContentSource, ContentSourceAdapter, RichDocumentActionContext } from \"@ai-matrx/rich-content/rich-document/types\";\n\ntype Callbacks = RichDocumentActionContext[\"callbacks\"];\ntype Request = NonNullable<NonNullable<Callbacks>[\"onRequestTextAgentAction\"]>;\n\nexport function editorTextAgentCallbacks(\n callbacks: Callbacks,\n source: ContentSource,\n adapter: Pick<ContentSourceAdapter, \"edit\">,\n request: Request | undefined,\n): Callbacks {\n if (callbacks?.onRequestTextAgentAction || !request) return callbacks;\n if (source.type === \"raw\" || source.readOnly || typeof adapter.edit !== \"function\") return callbacks;\n return { ...(callbacks ?? {}), onRequestTextAgentAction: request };\n}\n","\"use client\";\n\n// features/context-menu-v3/hooks/useContextMenuActions.ts\n//\n// THE shared engine behind every menu layout. `components/AlchemyMenuContent`\n// runs it and hands its model to the Alchemy package, whose layouts (right-\n// click, phone sheet, palette, bar ⋯) are pure PRESENTATION (ALC-15 S3) —\n// while every piece of behavior lives here\n// exactly once: placement resolution, the single deduped data fetch, scope +\n// action-text resolution, the rich-document action lists, and every handler\n// (clipboard, history, compare, launch, insert, attach/share, admin).\n//\n// This extraction pays down the long-flagged \"handlers ported 1:1, keep in\n// lockstep\" debt: a launch-path or handler change now lands in ONE place and\n// both renderers inherit it. Do NOT add a handler to a renderer — add it here.\n//\n// Inline agent editing: both launch handlers pass `runtime.widgetHandleId`\n// (registered by the shell for editable surfaces), so any agent/shortcut\n// launched from the menu can stream `widget_text_*` edits into the surface.\n\nimport { compact } from \"../utils/compact\";\nimport { fieldLabelOf } from \"../utils/field-menu-header\";\nimport { actionsAlreadyHere } from \"../utils/already-here\";\nimport { editorTextAgentCallbacks } from \"../utils/editor-text-agent\";\nimport { useEffect, useMemo } from \"react\";\nimport { copyText as kitCopyText, readText as kitReadText } from \"@ai-matrx/kit/clipboard\";\nimport {\n AppWindow,\n Braces,\n Building,\n ClipboardCopy,\n FileText,\n Info,\n Layers,\n Plus,\n Rocket,\n ShieldCheck,\n User,\n} from \"lucide-react\";\nimport { CANONICAL_MENU_VERSION_V3 } from \"../types\";\nimport type { ContextMenuExtraSection, ContextMenuExtraItem } from \"../types\";\nimport { detectActiveSurface } from \"@ai-matrx/chat/surfaces/utils/route-to-surface\";\nimport { getSurfaceDisplayLabel } from \"@ai-matrx/chat/surfaces/utils/surface-display\";\nimport { getRelatedSurfaces } from \"@ai-matrx/chat/surfaces/runtime/fetchRelatedSurfaces\";\nimport { getIconComponent } from \"@ai-matrx/icons\";\nimport { useAppDispatch, useAppSelector, useAppStore } from \"@ai-matrx/chat/store/hooks\";\nimport { selectUserId } from \"@ai-matrx/chat/host/identity\";\nimport { toast } from \"../utils/notify\";\nimport {\n getContextMenuHost,\n useContextMenuHostBindings,\n type ContextMenuQuickActions,\n type ReferencePick,\n} from \"../host/port\";\nimport { selectOrganizationId } from \"@ai-matrx/chat/host/org\";\nimport { useAgentLauncher } from \"@ai-matrx/chat/agents/hooks/useAgentLauncher\";\nimport { useSpeech } from \"@ai-matrx/media/react\";\nimport { primeAudioOutput } from \"@ai-matrx/media/speech\";\nimport { useSurfaceAgentRoles } from \"@ai-matrx/chat/surfaces/hooks/useSurfaceConfig\";\nimport { hasEditorInsertTarget, insertIntoEditor, ownParagraph } from \"../utils/insert-into-editor\";\nimport { resolveActions } from \"@ai-matrx/rich-content/rich-document/actions/provider\";\nimport { registryMenuActions } from \"@ai-matrx/rich-content/rich-document/variants/shared/menuStructure\";\nimport { getSourceAdapter } from \"@ai-matrx/rich-content/rich-document/actions/sources/index\";\nimport { shortHash } from \"@ai-matrx/rich-content/rich-document/actions/sources/raw\";\nimport type {\n ContentSource,\n RichDocumentAction,\n RichDocumentActionContext,\n} from \"@ai-matrx/rich-content/rich-document/types\";\nimport {\n placementGroupKey,\n PLACEMENT_TYPES,\n PLACEMENT_TYPE_META,\n} from \"@ai-matrx/chat/agents/shortcuts/constants\";\nimport type { ResultDisplayMode } from \"@ai-matrx/chat/agents/types/instance.types\";\nimport type { ApplicationScope } from \"@ai-matrx/chat/agents/types/scope.types\";\nimport {\n useUnifiedAgentContextMenu,\n type AgentMenuEntry,\n type AgentMenuCategoryGroup,\n} from \"./useUnifiedAgentContextMenu\";\nimport { buildAvailableKeys } from \"../model/requirement-gate\";\nimport { BASELINE_VALUE_NAMES } from \"@ai-matrx/chat/surfaces/manifests/_baseline.manifest\";\nimport { useSurfaceConfig } from \"@ai-matrx/chat/surfaces/hooks/useSurfaceConfig\";\nimport type { MenuConfig } from \"@ai-matrx/chat/surfaces/config/namespace-registry\";\nimport { useSurfaceBoundAgents } from \"@ai-matrx/chat/surfaces/hooks/useSurfaceBoundAgents\";\nimport type {\n SurfaceBoundAgentEntry,\n SurfaceBoundAgentSection,\n} from \"@ai-matrx/chat/surfaces/services/surface-bound-agents.service\";\nimport {\n resolveApplicationScope,\n resolveActionText,\n reportMenuDiagnostics,\n type ResolvedActionText,\n} from \"../value-resolution\";\nimport { spliceInputValue } from \"../utils/selection-tracking\";\nimport { buildSelectionWriteBack } from \"../utils/selection-write-back\";\nimport { registerLaunchWidgetHandle } from \"@ai-matrx/chat/agents/utils/launch-widget-handles\";\nimport {\n buildJsonMenuSection,\n type JsonMenuSection,\n} from \"../utils/json-menu-actions\";\nimport type {\n MenuContentProps,\n PlacementKey,\n PlacementVisibility,\n} from \"../types\";\nimport { MANAGED_CONTEXT_MENU_AGENT_CONFIG } from \"../managed-agent-launch\";\nimport { AGENT_ICON } from \"@ai-matrx/icons/domain\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared menu-model constants + pure helpers (used by both renderers).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const DEFAULT_PLACEMENT_MODE: Record<PlacementKey, PlacementVisibility> =\n {\n \"ai-action\": \"show\",\n \"bound-agent\": \"show\",\n \"content-block\": \"show\",\n \"organization-tool\": \"show\",\n \"user-tool\": \"show\",\n \"quick-action\": \"show\",\n };\n\nexport const ALL_DB_PLACEMENTS: PlacementKey[] = [\n \"ai-action\",\n \"content-block\",\n \"organization-tool\",\n \"user-tool\",\n];\n\n/** User-facing relabels matching the v3 taxonomy (My Items / Org Items). */\nexport const PLACEMENT_LABEL_OVERRIDE: Partial<Record<string, string>> = {\n [PLACEMENT_TYPES.USER_TOOL]: \"My Items\",\n [PLACEMENT_TYPES.ORGANIZATION_TOOL]: \"Org Items\",\n};\n\nexport const PLACEMENT_COLOR: Record<string, string> = {\n [PLACEMENT_TYPES.AI_ACTION]: \"#0ea5e9\",\n [PLACEMENT_TYPES.CONTENT_BLOCK]: \"#8b5cf6\",\n [PLACEMENT_TYPES.ORGANIZATION_TOOL]: \"#f59e0b\",\n [PLACEMENT_TYPES.USER_TOOL]: \"#10b981\",\n};\n\nexport function getPlacementIcon(placementType: string) {\n switch (placementType) {\n case PLACEMENT_TYPES.AI_ACTION:\n return Rocket;\n case PLACEMENT_TYPES.CONTENT_BLOCK:\n return FileText;\n case PLACEMENT_TYPES.ORGANIZATION_TOOL:\n return Building;\n case PLACEMENT_TYPES.USER_TOOL:\n return User;\n default:\n return FileText;\n }\n}\n\nexport function getPlacementLabel(placementType: string): string {\n return (\n PLACEMENT_LABEL_OVERRIDE[placementType] ??\n PLACEMENT_TYPE_META[placementType as keyof typeof PLACEMENT_TYPE_META]\n ?.label ??\n placementType\n );\n}\n\nexport function resolveIcon(\n iconName: string | null | undefined,\n fallback = \"FileText\",\n) {\n return getIconComponent(iconName ?? fallback, fallback);\n}\n\nexport function groupsByPlacement(\n groups: AgentMenuCategoryGroup[],\n): Record<string, AgentMenuCategoryGroup[]> {\n const map: Record<string, AgentMenuCategoryGroup[]> = {};\n for (const g of groups) {\n // Nullable in storage — key by the shared group key so an unplaced\n // category groups instead of throwing (agent-shortcuts/constants.ts).\n (map[placementGroupKey(g.category.placementType)] ??= []).push(g);\n }\n return map;\n}\n\nexport function hasItemsRecursive(group: AgentMenuCategoryGroup): boolean {\n if (group.items.length > 0) return true;\n return group.children.some(hasItemsRecursive);\n}\n\n/** Resolve a rich-document action's label + disabled state for rendering. */\nexport function resolveRichActionView(\n action: RichDocumentAction,\n ctx: RichDocumentActionContext,\n): { label: string; disabled: boolean } {\n const label =\n typeof action.label === \"function\" ? action.label(ctx) : action.label;\n const disabledResult = action.disabled?.(ctx);\n const disabled =\n typeof disabledResult === \"object\" ? true : Boolean(disabledResult);\n return { label, disabled };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// The engine hook.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ContextMenuActions {\n // Resolved model\n scope: ApplicationScope;\n actionText: ResolvedActionText;\n /** The name of the field the menu opened in (its label), or null. */\n fieldLabel: string | null;\n /** JSON verbs for a JSON-shaped selection/content. `null` = not JSON. */\n jsonSection: JsonMenuSection | null;\n resolvedPlacementMode: Record<PlacementKey, PlacementVisibility>;\n categoryGroups: AgentMenuCategoryGroup[];\n grouped: Record<string, AgentMenuCategoryGroup[]>;\n loading: boolean;\n /** Why the agent libraries (AI Actions, My Items, …) did not load — e.g. past the menu's deadline. */\n librariesError: string | null;\n boundAgentSections: SurfaceBoundAgentSection[];\n boundAgentsLoading: boolean;\n boundAgentsError: string | null;\n /** Re-run the library fetches after a failure or a missed deadline. */\n retryLibraries: () => void;\n /** Rich-document action ids this menu must not draw (surface exclusions + already-here). */\n excludedRichActionIds: string[];\n richDocCtx: RichDocumentActionContext;\n /** The registry actions this menu shows — rendered as the ONE tree. */\n registryActions: RichDocumentAction[];\n copyVariantActions: RichDocumentAction[];\n exportActions: RichDocumentAction[];\n convertActions: RichDocumentAction[];\n // Flags\n hasCompareBase: boolean;\n isAdmin: boolean;\n isDebugMode: boolean;\n isAdminIndicatorOpen: boolean;\n canNativeUndo: boolean;\n // Handlers\n handleCopy: () => Promise<void>;\n handleSpeak: () => void;\n handleSpokenSummary: () => void;\n handleSpokenSummaryLive: () => void;\n spokenSummaryAvailable: boolean;\n handleCut: () => Promise<void>;\n handlePaste: () => Promise<void>;\n handleSelectAll: () => void;\n handleUndo: () => void;\n handleRedo: () => void;\n handleCompareClipboard: () => Promise<void>;\n handleSetCompareBase: () => void;\n handleCompareWithBase: () => Promise<void>;\n handleShortcutExecute: (\n entry: Extract<AgentMenuEntry, { entryType: \"agent_shortcut\" }>,\n ) => Promise<void>;\n handleBoundAgentExecute: (entry: SurfaceBoundAgentEntry) => Promise<void>;\n handleContentBlockInsert: (\n entry: Extract<AgentMenuEntry, { entryType: \"content_block\" }>,\n ) => void;\n handleEntrySelect: (entry: AgentMenuEntry) => void;\n handleDelete: () => Promise<void>;\n handleFind: () => void;\n /** \"Insert reference…\" (editable) / \"Copy reference…\" (read-only). */\n handleInsertReference: () => void;\n handleAttach: () => void;\n /** \"Link a record…\" — the ONE record picker pointed at this menu's entity. */\n handleLinkRecord: () => void;\n handleShare: () => void;\n handleInspectValues: () => void;\n handleInspectState: () => void;\n handleToggleDebugMode: () => void;\n handleToggleAdminIndicator: () => void;\n // Quick actions (pass-through so renderers need no extra hook)\n quickActions: ContextMenuQuickActions;\n /**\n * The page's surface, as ONE nested menu entry titled with the surface's\n * display label (e.g. \"Notes\", \"Marketing Site Workspace\") — the same data\n * and actions the shell-header Agents button offers: location, Surface\n * Context, Surface Context Admin, the bound agents + bind action, related\n * surfaces, and (admins) the menu revision. Shaped as an extra section so\n * BOTH renderers draw it with their existing extra-item code.\n */\n surfaceSection: ContextMenuExtraSection;\n}\n\nexport function useContextMenuActions(\n props: Omit<MenuContentProps, \"variant\">,\n): ContextMenuActions {\n const {\n sourceFeature,\n surfaceName,\n menuVersion,\n getApplicationScope,\n contextData,\n selectedText,\n selectionRange,\n fallbackContent,\n placementMode,\n scope: shortcutScope,\n scopeId,\n extraSections,\n isEditable,\n editorId,\n getTextarea,\n insertAtCaret,\n onContentInserted,\n onTextReplace,\n onTextInsertAfter,\n onDelete,\n onUndo,\n onRedo,\n widgetHandleId,\n } = props;\n\n const dispatch = useAppDispatch();\n const store = useAppStore();\n const host = useContextMenuHostBindings();\n const entity = props.entity;\n\n const resolvedPlacementMode: Record<PlacementKey, PlacementVisibility> = {\n ...DEFAULT_PLACEMENT_MODE,\n ...(placementMode ?? {}),\n };\n const dbPlacementTypes = ALL_DB_PLACEMENTS.filter(\n (p) => resolvedPlacementMode[p] !== \"hide\",\n );\n\n /**\n * THE AMBIENT READS (Phase 1, 2026-08-25). The menu launches agent runs but\n * never asked what was already true around the user: which organization is\n * active and which scopes/context they have selected. Collected here — the\n * engine is the one place with Redux — and landed on a single `ambient`\n * scope key by `resolveApplicationScope`, so an agent launched from a\n * right-click stops asking what the app already knows. ONE key, weakest\n * layer, never overrides a surface (see the baseline manifest's\n * `AMBIENT_VALUES`).\n *\n * NOT here: \"is a run currently streaming\". Every streaming selector in the\n * execution system is conversation-scoped (`selectIsStreaming(conversationId)`)\n * and the menu has no conversation. A global one is worth adding, but it is a\n * new memoized selector over `activeRequests` that runs on every menu open —\n * a deliberate change, not a thing to invent in passing.\n */\n const activeOrganizationId = useAppSelector(selectOrganizationId);\n const activeScopeIds = host.activeScopeIds;\n\n // Assemble the scope the menu acts on. Stable for this open (the shell\n // captured selection before mount), so computing it in render is cheap.\n //\n // 🚨 ORDER MATTERS (Phase 6.7). This runs BEFORE the menu hook because\n // availability is now DERIVED from it: the scope's KEYS are half of what\n // this surface can read, and an item is offered iff every key it consumes\n // is readable here.\n const scope = resolveApplicationScope({\n getApplicationScope,\n contextData,\n selectedText,\n selectionRange,\n fallbackContent,\n surfaceName,\n ambient: {\n active_organization_id: activeOrganizationId ?? null,\n active_scope_ids: activeScopeIds ?? [],\n surface_name: surfaceName ?? null,\n },\n });\n\n /**\n * WHAT THIS SURFACE CAN READ — the derived gate's input (THE-MODEL law 3).\n *\n * Three sources, unioned, all of them KEY-existence and never\n * value-population:\n * 1. the baseline floor — the 5 generic values every menu resolves;\n * 2. the manifest's DECLARED values (inheritance already merged by the\n * registry) — a surface that declares `raw_transcript_text` offers the\n * transcript items before a single word has been recorded;\n * 3. the keys that actually landed in the resolved scope — the honest\n * catch for surfaces emitting values they never declared (\"Undeclared\n * (runtime only)\" in the Surface Context window). A read path is a read\n * path whether or not anyone wrote it down.\n */\n const scopeKeySignature = Object.keys(scope).sort().join(\"|\");\n const availableKeys = useMemo(\n () =>\n buildAvailableKeys(compact({\n baselineValueNames: BASELINE_VALUE_NAMES,\n declaredValueNames: surfaceName\n ? getContextMenuHost().getSurfaceManifest(surfaceName)?.values.map((v) => v.name)\n : undefined,\n // `scope` is rebuilt every render but its KEY SET is stable for an\n // open, so the signature — not the object — is the dependency.\n runtimeScopeKeys: scopeKeySignature.split(\"|\").filter(Boolean),\n })),\n [surfaceName, scopeKeySignature],\n );\n\n /**\n * THE EXCLUSION VALVE (#43) — the surface's `menu` config namespace, the\n * one sanctioned override of derived availability. Resolved through the\n * existing layered surface-config cache (global → org → scope → user), so\n * it costs no extra fetch: the menu already loads this bundle for agent\n * roles.\n */\n const { getNamespace: getSurfaceNamespace } = useSurfaceConfig(\n surfaceName ?? \"matrx-unregistered/context-menu\",\n );\n const menuSurfaceConfig = getSurfaceNamespace<MenuConfig>(\"menu\");\n const excludedItemIds = useMemo(\n () => new Set(menuSurfaceConfig?.excludedItemIds ?? []),\n [menuSurfaceConfig],\n );\n\n const {\n categoryGroups,\n loading,\n error: librariesError,\n refresh,\n } = useUnifiedAgentContextMenu({\n placementTypes: dbPlacementTypes,\n surfaceName,\n availableKeys,\n hasSelection: String(scope.selection ?? \"\").trim().length > 0,\n excludedItemIds,\n enabled: dbPlacementTypes.length > 0,\n scope: shortcutScope,\n scopeId,\n });\n\n const {\n sections: boundAgentSections,\n loading: boundAgentsFetching,\n settled: boundAgentsSettled,\n error: boundAgentsError,\n refresh: refreshBoundAgents,\n } = useSurfaceBoundAgents(surfaceName, { isEditable });\n // Loading until the rows are in hand — an unsettled empty list is never\n // \"no agents\" (round 6: the first open dropped the library).\n const boundAgentsLoading = boundAgentsFetching || !boundAgentsSettled;\n\n const { launchShortcut, launchAgent } = useAgentLauncher();\n const { speak } = useSpeech({ processMarkdown: true, label: \"Selected text\" });\n const { roles: surfaceAgentRoles } = useSurfaceAgentRoles(\n surfaceName ?? \"matrx-unregistered/context-menu\",\n );\n const {\n openListenSummaryWindow,\n quickActions,\n openDiffWindow,\n openFindReplace,\n openReferencePicker,\n openContextAssignment,\n openLinkRecordSheet,\n openShareModalWindow,\n openStateViewer,\n openSurfaceInspector,\n hasCompareBase,\n } = host;\n const currentUserId = useAppSelector(selectUserId);\n // Admin DEBUGGING (every page): the surface key, the menu version and the\n // Admin Tools submenu (debug mode, context values, Redux state, admin\n // indicator) — this browser's own diagnostics, no data. Admin POWER (the\n // Surface Context Admin editor, admin rich-document actions) stays on the\n // lane-gated selector, false outside /administration.\n const isAdmin = host.isAdminDebugger;\n const hasAdminPower = host.hasAdminPower;\n const organizationId = useAppSelector(selectOrganizationId);\n const isDebugMode = host.isDebugMode;\n const isAdminIndicatorOpen = host.isAdminIndicatorOpen;\n\n // The single, deduped fetch — fires on the renderer's mount (= on open).\n // Both the unified-menu thunk and the bound-agents service dedupe, so reopen\n // never refetches. A double fetch is structurally impossible.\n useEffect(() => {\n void refresh();\n // Default-contract agents (matrx-default/*) apply even with no surfaceName,\n // so always fetch — a bare/undeclared surface still gets its default agents.\n void refreshBoundAgents();\n }, []);\n\n const actionText = resolveActionText(scope);\n\n // Rich-document action context — reuses the canonical copy / export / convert\n // handlers (NOT a fork). Only populated when there is content to act on, so\n // the submenus self-hide on an inert menu.\n const richDocSource: ContentSource = props.contentSource ?? { type: \"raw\" };\n const richDocAdapter = getSourceAdapter(richDocSource.type);\n // Raw sources fold a content hash into the instance prefix so two raw\n // documents on one page never share overlay instance IDs (parity with\n // useActionSurfaceProvider's ctx builder).\n const richPrefix =\n richDocSource.type === \"raw\"\n ? `${richDocAdapter.instanceKeyPrefix(richDocSource)}-${shortHash(actionText.text).slice(0, 8)}`\n : richDocAdapter.instanceKeyPrefix(richDocSource);\n const richDocCtx: RichDocumentActionContext = {\n content: actionText.text,\n source: richDocSource,\n metadata: null,\n dispatch,\n getState: store.getState as unknown as () => Record<string, unknown>,\n organizationId,\n isAuthenticated: Boolean(currentUserId),\n isAdmin: hasAdminPower,\n isCreator: false,\n surfaceKey: surfaceName ?? null,\n onClose: () => {},\n instanceKey: (prefix) => `${richPrefix}-${prefix}`,\n sourceAdapter: richDocAdapter,\n applicationScope: scope,\n ...(props.richDocCtxExtras ?? {}),\n };\n // ONE AI SET FOR A RECORD IN EVERY VIEW (page-pass /notes, 2026-09-28): Read\n // (RichDocument) supplied Clean up / Help with this…, the editor views did\n // not. An editor menu over a source that can be saved gets the shell's\n // review-and-apply dialog unless its host already supplied one.\n const textAgentCallbacks = editorTextAgentCallbacks(richDocCtx.callbacks, richDocSource, richDocAdapter, props.requestTextAgentReview);\n if (textAgentCallbacks) richDocCtx.callbacks = textAgentCallbacks;\n // Never an action that targets the place this menu already is (Save to\n // Notes inside a note, Edit inside the editor). The SAME list goes to the\n // click target (AlchemyMenuContent), because the rich-document provider\n // draws its rows from the target, not from this resolve — live on\n // /notes/<id> the preview still showed them while only this list had them.\n const excludedRichActionIds = [\n ...(props.excludedRichActions ?? []),\n ...actionsAlreadyHere({\n sourceType: richDocSource.type,\n surfaceName,\n isEditable: Boolean(isEditable),\n }),\n ];\n const richActions =\n actionText.source !== \"none\"\n ? resolveActions(richDocCtx, compact({\n exclude: excludedRichActionIds,\n extra: props.extraRichActions,\n }))\n : [];\n // The ONE registry tree's actions (the same selector every menu host uses).\n const registryActions = registryMenuActions(richActions);\n const copyVariantActions = richActions.filter((a) => a.category === \"copy\");\n const exportActions = richActions.filter(\n (a) => a.category === \"export\" || a.id === \"save-as-file\",\n );\n const convertActions = richActions.filter(\n (a) => a.category === \"save\" && a.id !== \"save-as-file\",\n );\n\n // Loud guards — dev-only scream for inert menus + value-mapping gaps.\n useEffect(() => {\n reportMenuDiagnostics({\n surfaceName,\n scope,\n isEditable,\n hasExtraSections: Boolean(extraSections && extraSections.length > 0),\n });\n }, []);\n\n // ── Clipboard ─────────────────────────────────────────────────────────────\n const handleCopy = async () => {\n if (!actionText.text) return;\n // Blocked clipboard (embedded browser, permission policy): never a\n // silent swallow — hand the text over for a manual Cmd/Ctrl+C.\n if (!(await kitCopyText(actionText.text))) {\n getContextMenuHost().showManualCopy({ text: actionText.text });\n }\n };\n\n const handleSpeak = () => {\n if (actionText.text.trim()) speak(actionText.text);\n };\n\n // Listening is universal: every menu has content or a selection. A surface\n // that declares its own `spoken_summary` role wins; every other surface\n // falls back to the platform home role (mandate-backed, so it resolves for\n // every user). The home fetch is cached once per session by\n // `ensureSurfaceConfig`'s single-flight.\n const { roles: listenHomeRoles } = useSurfaceAgentRoles(\n getContextMenuHost().listeningHomeSurface,\n );\n const spokenSummaryRole = surfaceAgentRoles.spoken_summary?.effectiveAgentId\n ? surfaceAgentRoles.spoken_summary\n : listenHomeRoles.spoken_summary;\n const spokenSummaryAgentId = spokenSummaryRole?.effectiveAgentId ?? null;\n // Both listening actions open the Listen panel (summary text + audio\n // transport in one place). The only difference is stream-to-stream autoplay.\n const openSpokenSummary = (autoPlay: boolean) => {\n if (!spokenSummaryAgentId || !actionText.text.trim()) return;\n // This click is the ONLY user gesture before speech starts (the audio\n // itself begins from a websocket callback) — unlock iOS/WebKit output now.\n primeAudioOutput();\n openListenSummaryWindow({\n agentId: spokenSummaryAgentId,\n agentName: spokenSummaryRole?.role.label ?? null,\n sourceText: actionText.text,\n style: \"Extremely Concise Summary\",\n autoPlay,\n });\n };\n const handleSpokenSummary = () => openSpokenSummary(false);\n const handleSpokenSummaryLive = () => openSpokenSummary(true);\n\n const handleCut = async () => {\n if (!selectionRange || selectionRange.type !== \"editable\") return;\n const element = selectionRange.element;\n if (\n !(element instanceof HTMLTextAreaElement) &&\n !(element instanceof HTMLInputElement)\n )\n return;\n const { start, end } = selectionRange;\n const cutText = element.value.substring(start, end);\n if (!(await kitCopyText(cutText))) {\n // The text was NOT cut (the splice below never runs) — offer it for a\n // manual copy instead of losing the gesture.\n getContextMenuHost().showManualCopy({ text: cutText, title: \"Copy manually (cut was blocked)\" });\n return;\n }\n if (onTextReplace) {\n onTextReplace(\n element.value.substring(0, start) + element.value.substring(end),\n );\n } else {\n spliceInputValue(element, start, end, \"\");\n }\n };\n\n const handlePaste = async () => {\n if (!isEditable || !selectionRange || selectionRange.type !== \"editable\")\n return;\n const element = selectionRange.element;\n if (\n !(element instanceof HTMLTextAreaElement) &&\n !(element instanceof HTMLInputElement)\n )\n return;\n const text = await kitReadText();\n if (text === null) {\n toast({ title: \"Couldn't read the clipboard\", variant: \"destructive\" });\n return;\n }\n const { start, end } = selectionRange;\n if (onTextReplace) {\n onTextReplace(\n element.value.substring(0, start) + text + element.value.substring(end),\n );\n } else {\n spliceInputValue(element, start, end, text);\n }\n };\n\n // ── JSON ──────────────────────────────────────────────────────────────────\n // Selection-aware: when the text the menu is acting on parses as JSON (with\n // or without a code fence), offer the JSON verbs. Detection + formatting are\n // the shared `lib/json-format` primitive, so this menu and the notes cleanup\n // pass produce byte-identical output. Read-only surfaces get the same verbs\n // as copies.\n const editableTarget =\n isEditable && selectionRange?.type === \"editable\"\n ? selectionRange.element\n : null;\n const canWriteJson =\n editableTarget instanceof HTMLTextAreaElement ||\n editableTarget instanceof HTMLInputElement;\n\n const jsonSection: JsonMenuSection | null = buildJsonMenuSection({\n text: actionText.text,\n canWrite: canWriteJson,\n onReplace: (next) => {\n if (!canWriteJson || !selectionRange || selectionRange.type !== \"editable\")\n return;\n const element = selectionRange.element;\n if (\n !(element instanceof HTMLTextAreaElement) &&\n !(element instanceof HTMLInputElement)\n )\n return;\n // A real selection is rewritten in place; with no selection the menu is\n // acting on the whole field, so the whole value is replaced.\n const { start, end } =\n actionText.source === \"selection\"\n ? selectionRange\n : { start: 0, end: element.value.length };\n if (onTextReplace) {\n onTextReplace(\n element.value.substring(0, start) + next + element.value.substring(end),\n );\n } else {\n spliceInputValue(element, start, end, next);\n }\n },\n onCopy: async (next) => {\n if (await kitCopyText(next)) {\n toast({ title: \"Copied\", description: \"JSON copied to clipboard.\" });\n } else {\n getContextMenuHost().showManualCopy({ text: next });\n }\n },\n });\n\n const handleSelectAll = () => {\n // No captured selection (the common right-click-without-selecting case):\n // an editable surface still knows its field — select all of it. A no-op\n // here is the \"fake menu\" class this feature exists to kill.\n if (!selectionRange) {\n const field = getTextarea?.();\n if (field) {\n requestAnimationFrame(() => {\n field.focus();\n field.select();\n });\n }\n return;\n }\n if (selectionRange.type === \"editable\") {\n const element = selectionRange.element;\n if (\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLInputElement\n ) {\n requestAnimationFrame(() => {\n element.focus();\n element.select();\n });\n }\n } else {\n const container = selectionRange.containerElement;\n if (!container) return;\n requestAnimationFrame(() => {\n try {\n const range = document.createRange();\n range.selectNodeContents(container);\n const selection = window.getSelection();\n if (selection) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n } catch {\n // best-effort\n }\n });\n }\n };\n\n // ── History ───────────────────────────────────────────────────────────────\n // Native per-field Undo/Redo. When the surface provides no richer history\n // (`onUndo`/`onRedo`), an editable field still gets the browser's built-in\n // undo stack — \"offer undo\" without standing up a history system. There is no\n // non-deprecated API to trigger a textarea's native undo, so `execCommand` is\n // the intentional (and only) mechanism here.\n const editableElement: HTMLTextAreaElement | HTMLInputElement | null =\n (() => {\n const fromRange =\n selectionRange?.type === \"editable\" ? selectionRange.element : null;\n const el = fromRange ?? getTextarea?.() ?? null;\n return el instanceof HTMLTextAreaElement || el instanceof HTMLInputElement\n ? el\n : null;\n })();\n const canNativeUndo = Boolean(isEditable && editableElement);\n const runNativeEdit = (command: \"undo\" | \"redo\") => {\n if (!editableElement) return;\n editableElement.focus();\n try {\n document.execCommand(command);\n } catch (err) {\n console.error(`[ContextMenuV3] native ${command} failed`, err);\n }\n };\n const handleUndo = () => (onUndo ? onUndo() : runNativeEdit(\"undo\"));\n const handleRedo = () => (onRedo ? onRedo() : runNativeEdit(\"redo\"));\n\n // ── Compare — reuses the existing diff-viewer window + compare-base slice ──\n const compareContent = (): { content: string; label: string } =>\n actionText.source === \"selection\"\n ? { content: actionText.text, label: \"Selection\" }\n : { content: actionText.text, label: \"Current\" };\n\n const handleCompareClipboard = async () => {\n const { content, label } = compareContent();\n const clip = await kitReadText();\n if (clip === null) {\n toast({ title: \"Couldn't read the clipboard\", variant: \"destructive\" });\n return;\n }\n if (!clip) {\n toast({ title: \"Clipboard is empty\" });\n return;\n }\n // Current content is the baseline (old); the clipboard is the incoming\n // version the user is about to paste (new). Clipboard-only text => addition.\n openDiffWindow({\n original: content,\n modified: clip,\n originalLabel: label,\n modifiedLabel: \"Clipboard\",\n title: \"Compare with clipboard\",\n engine: \"light\",\n });\n };\n\n const handleSetCompareBase = () => {\n const { content, label } = compareContent();\n host.setCompareBase({ content, label, language: null });\n toast({\n title: \"Set as compare base\",\n description: \"Open another item and choose “Compare with base”.\",\n });\n };\n\n const handleCompareWithBase = async () => {\n const { content, label } = compareContent();\n const opened = await host.openCompareWithBase({ current: content, currentLabel: label });\n if (!opened) {\n toast({\n title: \"No compare base set\",\n description: \"Choose “Set as compare base” on another item first.\",\n });\n }\n };\n\n // ── Launch (AI actions / bound agents / content blocks) ──────────────────\n // Per-launch widget handle: the surface's widget_* methods plus a selection\n // write-back, so the result's action bar offers Replace / Insert below in\n // place of the text this run was launched on (any display mode).\n const launchWidgetHandleId = (): string | undefined =>\n registerLaunchWidgetHandle(\n widgetHandleId,\n isEditable\n ? buildSelectionWriteBack({\n originalText: actionText.text,\n textSource: actionText.source,\n selectionRange,\n onTextReplace,\n onTextInsertAfter,\n insertAtCaret,\n })\n : null,\n );\n\n const handleShortcutExecute = async (\n entry: Extract<AgentMenuEntry, { entryType: \"agent_shortcut\" }>,\n ) => {\n if (!entry.agentId) {\n toast({\n title: \"Agent Not Connected\",\n description: `\"${entry.label}\" has no connected agent. Configure it in the admin panel.`,\n variant: \"destructive\",\n });\n return;\n }\n const resultDisplay = (entry.displayMode ??\n \"modal-full\") as ResultDisplayMode;\n try {\n await launchShortcut(entry.id, scope, {\n surfaceKey: `${sourceFeature}:${entry.id}`,\n sourceFeature,\n config: { displayMode: resultDisplay },\n runtime: compact({\n originalText: actionText.text,\n surfaceName,\n // Editable surfaces: let the agent stream widget_text_* edits\n // straight into the surface, and give the person Replace / Insert\n // below on the result (undefined on read-only — no tools).\n widgetHandleId: launchWidgetHandleId(),\n }),\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"An unknown error occurred\";\n toast({\n title: \"Execution Failed\",\n description: `${entry.label}: ${message}`,\n variant: \"destructive\",\n });\n }\n };\n\n const handleBoundAgentExecute = async (entry: SurfaceBoundAgentEntry) => {\n try {\n await launchAgent(entry.agentId, {\n surfaceKey: `${sourceFeature}:bound-agent:${entry.agentId}`,\n sourceFeature,\n // Managed entries share the WindowPanel default. autoRun is deliberately\n // absent so the safe open-and-wait default remains authoritative.\n config: MANAGED_CONTEXT_MENU_AGENT_CONFIG,\n runtime: compact({\n applicationScope: scope,\n originalText: actionText.text,\n surfaceName,\n widgetHandleId: launchWidgetHandleId(),\n }),\n });\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"An unknown error occurred\";\n toast({\n title: \"Execution Failed\",\n description: `${entry.name}: ${message}`,\n variant: \"destructive\",\n });\n }\n };\n\n // Every insert the menu makes goes through ONE function; which target is\n // live (editor id, textarea, rich caret) is decided when the insert runs.\n const insertTargets = { editorId, getTextarea, insertAtCaret, onTextReplace };\n\n const handleContentBlockInsert = (\n entry: Extract<AgentMenuEntry, { entryType: \"content_block\" }>,\n ) => {\n // The template passes through VERBATIM — placeholders like {{variable}}\n // must reach the editor/clipboard unmangled.\n const template = entry.template;\n if (insertIntoEditor(insertTargets, template)) {\n onContentInserted?.();\n return;\n }\n // Read-only surface (or the insert target vanished): never a silent no-op —\n // copy the block so the gesture still yields the text.\n void kitCopyText(template).then((copied) => {\n if (copied) {\n toast({\n title: \"Copied to clipboard\",\n description: `\"${entry.label}\" can't be inserted here — this surface isn't editable.`,\n });\n } else {\n getContextMenuHost().showManualCopy({ text: template });\n }\n });\n };\n\n const handleEntrySelect = (entry: AgentMenuEntry) => {\n if (entry.entryType === \"agent_shortcut\") void handleShortcutExecute(entry);\n else handleContentBlockInsert(entry);\n };\n\n // ── Editable Save / Delete — Delete always via ConfirmDialog ─────────────\n const handleDelete = async () => {\n if (!onDelete) return;\n const ok = await getContextMenuHost().confirm({\n title: \"Delete this item?\",\n description: \"This action cannot be undone.\",\n confirmLabel: \"Delete\",\n variant: \"destructive\",\n });\n if (ok) onDelete();\n };\n\n // ── Overlay-opening actions ───────────────────────────────────────────────\n // Find & Replace carries the live target element + onReplace through the\n // callback registry (never Redux). Suppress the shell's selection-restore so\n // the modal keeps focus after the menu closes (applies on BOTH renderers —\n // the mobile sheet closes into the same overlay).\n const handleFind = () => {\n props.suppressSelectionRestore();\n openFindReplace({\n getTargetElement: () =>\n selectionRange?.type === \"editable\" ? selectionRange.element : null,\n onReplace: onTextReplace,\n });\n };\n\n // Add a reference: the picker returns the canonical minified fence; an\n // editable surface gets it inserted at the caret on its own paragraph, any\n // other surface (or a \"Copy\" choice inside the picker) gets it on the\n // clipboard — never a silent no-op.\n const canInsertReference = isEditable && hasEditorInsertTarget(insertTargets);\n const copyReference = (pick: ReferencePick) => {\n void kitCopyText(pick.fence).then((copied) => {\n if (copied) {\n toast({\n title: \"Reference copied\",\n description: pick.title\n ? `Paste it anywhere to link \"${pick.title}\".`\n : \"Paste it anywhere to render the link.\",\n });\n } else {\n getContextMenuHost().showManualCopy({ text: pick.fence, title: \"Copy the reference\" });\n }\n });\n };\n const insertReference = (pick: ReferencePick) => {\n // Own paragraph everywhere: a fence must start and end on its own line.\n // A block: it lands at the end of the caret's line, never inside a word.\n const inserted = insertIntoEditor(insertTargets, {\n editor: `\\n${pick.fence}\\n`,\n textarea: (field) => ownParagraph(pick.fence, field),\n caret: pick.fence,\n placement: \"block\",\n });\n if (inserted) {\n onContentInserted?.();\n return;\n }\n toast({\n title: \"Copied instead\",\n description: \"Couldn't insert here. Paste it where you want it.\",\n });\n copyReference(pick);\n };\n const handleInsertReference = () => {\n props.suppressSelectionRestore();\n openReferencePicker({\n mode: canInsertReference ? \"insert\" : \"copy\",\n onPicked: (pick) => {\n if (pick.delivery === \"insert\" && canInsertReference) insertReference(pick);\n else copyReference(pick);\n },\n });\n };\n\n const handleAttach = () => {\n if (!entity) return;\n openContextAssignment({\n subject: {\n entityType: entity.type,\n entityId: entity.id,\n title: entity.title,\n },\n });\n };\n\n const handleLinkRecord = () => {\n if (!entity) return;\n openLinkRecordSheet({ target: { token: entity.type, id: entity.id, title: entity.title } });\n };\n\n const handleShare = () => {\n if (!entity?.resourceType) return;\n openShareModalWindow({\n resourceType: entity.resourceType,\n resourceId: entity.id,\n resourceName: entity.title,\n });\n };\n\n // ── Admin ─────────────────────────────────────────────────────────────────\n // ── Surface submenu (mirrors the shell-header Agents panel) ────────────────\n const { openSurfaceContextWindow, openBindAgent } = host;\n const resolvedSurfaceName = surfaceName ?? detectActiveSurface();\n const surfaceLabel = resolvedSurfaceName\n ? getSurfaceDisplayLabel(resolvedSurfaceName)\n : \"This page\";\n const related = getRelatedSurfaces(resolvedSurfaceName);\n const copyText = (text: string) => {\n void kitCopyText(text).then((copied) => {\n if (copied) toast({ title: \"Copied\", description: text });\n else getContextMenuHost().showManualCopy({ text });\n });\n };\n const surfaceAgentItems: ContextMenuExtraItem[] = [];\n boundAgentSections\n .filter((section) => section.agents.length > 0)\n .forEach((section, idx) => {\n if (idx > 0)\n surfaceAgentItems.push({ kind: \"separator\", id: `sa:${section.key}:sep` });\n for (const agent of section.agents) {\n surfaceAgentItems.push({\n kind: \"item\",\n id: `sa:${section.key}:${agent.agentId}`,\n label: agent.name,\n description: agent.organizationName ? `${section.label} · ${agent.organizationName}` : section.label,\n icon: AGENT_ICON,\n onSelect: () => void handleBoundAgentExecute(agent),\n });\n }\n });\n if (surfaceAgentItems.length > 0)\n surfaceAgentItems.push({ kind: \"separator\", id: \"sa:bind-sep\" });\n surfaceAgentItems.push({\n kind: \"item\",\n id: \"sa:bind\",\n label: \"Bind an agent to this page…\",\n icon: Plus,\n disabled: !resolvedSurfaceName,\n onSelect: () => {\n if (resolvedSurfaceName) openBindAgent({ surfaceName: resolvedSurfaceName });\n },\n });\n const relatedItems: ContextMenuExtraItem[] = [\n ...related.ancestry,\n ...related.children,\n ].map((ref) => ({\n kind: \"item\",\n id: `sr:${ref.name}`,\n label: ref.label,\n description: `${ref.kind === \"ancestor\" ? \"Parent\" : \"Child\"} · ${ref.name}`,\n icon: AppWindow,\n onSelect: () =>\n openSurfaceContextWindow({ surfaceName: ref.name, isEditable: false }),\n }));\n const surfaceChildren: ContextMenuExtraItem[] = [\n // The surface key is an engineer's handle — admin-only (cold walk 20),\n // like the Agents panel's sub-line. Everyone else sees the label only.\n ...(isAdmin\n ? ([\n {\n kind: \"item\",\n id: \"surface:location\",\n label: resolvedSurfaceName ?? \"No surface registered for this page\",\n ...(resolvedSurfaceName ? { description: \"Surface location · click to copy\" } : {}),\n icon: ClipboardCopy,\n disabled: !resolvedSurfaceName,\n onSelect: () => resolvedSurfaceName && copyText(resolvedSurfaceName),\n },\n { kind: \"separator\", id: \"surface:sep1\" },\n ] satisfies ContextMenuExtraItem[])\n : []),\n {\n kind: \"item\",\n id: \"surface:context\",\n label: \"Surface Context\",\n description: \"Live page values\",\n icon: Braces,\n disabled: !resolvedSurfaceName,\n onSelect: () => {\n if (!resolvedSurfaceName) return;\n openSurfaceContextWindow({\n surfaceName: resolvedSurfaceName,\n isEditable: Boolean(isEditable),\n });\n },\n },\n ...(hasAdminPower\n ? ([\n {\n kind: \"item\",\n id: \"surface:context-admin\",\n label: \"Surface Context Admin\",\n description: \"Contract, provenance & settings\",\n icon: ShieldCheck,\n onSelect: () =>\n openSurfaceInspector({\n surfaceName: resolvedSurfaceName ?? null,\n scope,\n isEditable: Boolean(isEditable),\n preferRuntime: true,\n }),\n },\n ] satisfies ContextMenuExtraItem[])\n : []),\n { kind: \"separator\", id: \"surface:sep2\" },\n {\n kind: \"submenu\",\n id: \"surface:agents\",\n label: \"Agents on this page\",\n icon: AGENT_ICON,\n children: surfaceAgentItems,\n },\n ...(relatedItems.length > 0\n ? ([\n {\n kind: \"submenu\",\n id: \"surface:related\",\n label: \"Related surfaces\",\n icon: Layers,\n children: relatedItems,\n },\n ] satisfies ContextMenuExtraItem[])\n : []),\n ...(isAdmin\n ? ([\n { kind: \"separator\", id: \"surface:sep3\" },\n {\n kind: \"item\",\n id: \"surface:version\",\n label: `Menu v3.${CANONICAL_MENU_VERSION_V3} · V${menuVersion}`,\n description: \"Menu revision · surface wiring version\",\n icon: Info,\n onSelect: () =>\n copyText(\n `${resolvedSurfaceName ?? \"(no surface)\"} · v3.${CANONICAL_MENU_VERSION_V3} · V${menuVersion}`,\n ),\n },\n ] satisfies ContextMenuExtraItem[])\n : []),\n ];\n const surfaceSection: ContextMenuExtraSection = {\n id: \"surface-info\",\n items: [\n {\n kind: \"submenu\",\n id: \"surface\",\n label: surfaceLabel,\n icon: AppWindow,\n children: surfaceChildren,\n },\n ],\n };\n\n const handleInspectValues = () => {\n openSurfaceInspector({\n surfaceName: surfaceName ?? null,\n scope,\n isEditable: Boolean(isEditable),\n });\n };\n const handleInspectState = () => {\n openStateViewer();\n };\n const handleToggleDebugMode = () => {\n host.toggleDebugMode();\n };\n const handleToggleAdminIndicator = () => {\n host.toggleAdminIndicator();\n };\n\n return {\n scope,\n actionText,\n // A textarea/input, or a contenteditable field (chip / rich editor), names\n // itself in the header — never \"Content: {{reply.body}}\".\n fieldLabel: isEditable && selectionRange ? fieldLabelOf(selectionRange.element) : null,\n jsonSection,\n resolvedPlacementMode,\n categoryGroups,\n grouped: groupsByPlacement(categoryGroups),\n loading,\n librariesError,\n boundAgentSections,\n boundAgentsLoading,\n boundAgentsError,\n excludedRichActionIds,\n retryLibraries: () => {\n void refresh();\n void refreshBoundAgents();\n },\n richDocCtx,\n registryActions,\n copyVariantActions,\n exportActions,\n convertActions,\n hasCompareBase,\n isAdmin,\n isDebugMode,\n isAdminIndicatorOpen,\n canNativeUndo,\n handleCopy,\n handleSpeak,\n handleSpokenSummary,\n handleSpokenSummaryLive,\n spokenSummaryAvailable: Boolean(spokenSummaryAgentId),\n handleCut,\n handlePaste,\n handleSelectAll,\n handleUndo,\n handleRedo,\n handleCompareClipboard,\n handleSetCompareBase,\n handleCompareWithBase,\n handleShortcutExecute,\n handleBoundAgentExecute,\n handleContentBlockInsert,\n handleEntrySelect,\n handleDelete,\n handleFind,\n handleInsertReference,\n handleAttach,\n handleLinkRecord,\n handleShare,\n handleInspectValues,\n handleInspectState,\n handleToggleDebugMode,\n handleToggleAdminIndicator,\n quickActions,\n surfaceSection,\n };\n}\n","import \"./host-types\";\nexport * from \"@ai-matrx/chat/context-menu/types\";\n","/**\n * The menu's `toast({ title, description, variant })` call shape, delivered\n * through the chat package's notify port (`@ai-matrx/chat/host/notify`) —\n * the one notice stack the host already wires for agent runs.\n *\n * `destructive` → error; `success` / `warning` / `info` → the same; anything\n * else → a plain notice. A toast with only a description reads that\n * description as its message.\n */\nimport { toast as notify } from \"@ai-matrx/chat/host/notify\";\n\nexport interface MenuToast {\n title?: string | undefined;\n description?: string | undefined;\n variant?: \"destructive\" | \"success\" | \"warning\" | \"info\" | \"default\" | undefined;\n duration?: number | undefined;\n}\n\nexport function toast(props: MenuToast): void {\n const { title, description, variant, duration } = props;\n const message = title ?? description ?? \"\";\n const options = {\n ...(title !== undefined && description !== undefined ? { description } : {}),\n ...(duration !== undefined ? { duration } : {}),\n };\n if (variant === \"destructive\") notify.error(message, options);\n else if (variant === \"success\") notify.success(message, options);\n else if (variant === \"warning\") notify.warning(message, options);\n else if (variant === \"info\") notify.info(message, options);\n else notify.message(message, options);\n}\n","/**\n * THE CONTEXT MENU HOST PORT — everything the engine needs that only the app\n * running it can answer.\n *\n * The engine (model, layouts, handlers, data fetch, scope resolution) lives\n * in this package. What stays with the host is identity-shaped: which overlay\n * opens for \"Find\", what the app's diff window is, which of its admin lanes\n * is open, its surface-manifest registry, its toast/confirm/manual-copy\n * doors. A host registers them ONCE at boot:\n *\n * configureContextMenuHost({ useBindings, getSurfaceManifest, ... });\n *\n * Organization, user id and toasts are NOT here — they come through the chat\n * package's host (`@ai-matrx/chat/host/*`), which every menu host already\n * configures because the menu launches agents.\n *\n * Every member has a shipped default. A default never pretends: it either\n * does the honest minimum (kit `confirm`) or announces once, by name, that\n * the host did not wire it (`[context-menu] host port \"<name>\" is not wired`).\n *\n * The registration lives on `globalThis` under a `Symbol.for` key so the ESM\n * and CJS builds (and a host that loads both) share one host.\n */\nimport type { ComponentType } from \"react\";\nimport type { ResolvedSurfaceManifest } from \"@ai-matrx/chat/surfaces/types\";\nimport type { SklRenderDefinition } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/skl-types\";\nimport { confirm as kitConfirm, type ConfirmOptions } from \"@ai-matrx/kit/confirm-opener\";\n\n// ── Opener option shapes (what the engine passes; a host's opener accepts a superset) ──\n\nexport interface ListenSummaryWindowOptions {\n agentId: string;\n agentName: string | null;\n sourceText: string;\n style: string;\n autoPlay: boolean;\n}\n\nexport interface DiffWindowOptions {\n original: string;\n modified: string;\n originalLabel: string;\n modifiedLabel: string;\n title: string;\n engine: \"light\";\n}\n\nexport interface FindReplaceOptions {\n getTargetElement: () => HTMLElement | null;\n onReplace: ((nextText: string) => void) | undefined;\n}\n\n/** What the reference picker hands back. */\nexport interface ReferencePick {\n /** The canonical ```matrx fence carrying the minified one-line shell. */\n fence: string;\n /** The bare minified shell (what the fence wraps). */\n shell: string;\n /** Grammar class the fence carries. */\n directiveClass: string;\n /** Reference type token on the wire (`conversation`, `note`, `file`, `url`, …). */\n type: string;\n /** Display title of the picked record, when known. */\n title: string | null;\n delivery: \"insert\" | \"copy\";\n}\n\nexport interface ReferencePickerOptions {\n mode: \"insert\" | \"copy\";\n onPicked: (pick: ReferencePick) => void;\n}\n\nexport interface ContextAssignmentOptions {\n subject: { entityType: string; entityId: string; title: string | undefined };\n}\n\nexport interface LinkRecordSheetOptions {\n target: { token: string; id: string; title: string | undefined };\n}\n\nexport interface ShareModalOptions {\n resourceType: string;\n resourceId: string;\n resourceName: string | undefined;\n}\n\nexport interface SurfaceContextWindowOptions {\n surfaceName: string;\n isEditable: boolean;\n}\n\nexport interface SurfaceAgentBindOptions {\n surfaceName: string;\n}\n\nexport interface SurfaceInspectorOptions {\n surfaceName: string | null;\n scope: unknown;\n isEditable: boolean;\n preferRuntime?: boolean | undefined;\n}\n\nexport interface CompareBaseInput {\n content: string;\n label: string;\n language: string | null;\n}\n\n/** The quick launchers the menu's \"Open\" group offers. */\nexport interface ContextMenuQuickActions {\n openChatWindow: () => void;\n openQuickChat: () => void;\n openQuickData: () => void;\n openQuickFiles: () => void;\n openQuickNotes: () => void;\n openQuickTasks: () => void;\n openVoicePad: () => void;\n}\n\n/** Everything the engine reads or opens per render. Returned by the host's `useBindings` HOOK. */\nexport interface ContextMenuHostBindings {\n /** Admin DEBUGGING power on this page (surface key, menu version, Admin Tools). */\n isAdminDebugger: boolean;\n /** Admin POWER on this page (Surface Context Admin, admin document actions). */\n hasAdminPower: boolean;\n isDebugMode: boolean;\n isAdminIndicatorOpen: boolean;\n hasCompareBase: boolean;\n /** The person's selected scopes/context, landed on the ambient scope key. */\n activeScopeIds: unknown;\n toggleDebugMode: () => void;\n toggleAdminIndicator: () => void;\n setCompareBase: (input: CompareBaseInput) => void;\n /** Resolves false when there was no base to compare with. */\n openCompareWithBase: (input: { current: string; currentLabel: string }) => Promise<boolean>;\n openListenSummaryWindow: (options: ListenSummaryWindowOptions) => void;\n openDiffWindow: (options: DiffWindowOptions) => void;\n openFindReplace: (options: FindReplaceOptions) => void;\n openReferencePicker: (options: ReferencePickerOptions) => void;\n openContextAssignment: (options: ContextAssignmentOptions) => void;\n openLinkRecordSheet: (options: LinkRecordSheetOptions) => void;\n openShareModalWindow: (options: ShareModalOptions) => void;\n openStateViewer: () => void;\n openSurfaceInspector: (options: SurfaceInspectorOptions) => void;\n openSurfaceContextWindow: (options: SurfaceContextWindowOptions) => void;\n openBindAgent: (options: SurfaceAgentBindOptions) => void;\n quickActions: ContextMenuQuickActions;\n}\n\nexport interface ManualCopyOptions {\n text: string;\n title?: string | undefined;\n description?: string | undefined;\n}\n\n/** Props the host's document-review component receives (the \"AI result replaces the selection\" flow). */\nexport type DocumentAgentReviewProps = Record<string, unknown>;\n\nexport interface ContextMenuHost {\n /** A React HOOK, called once per open menu, unconditionally. */\n useBindings: () => ContextMenuHostBindings;\n /** The host's surface-manifest registry. */\n getSurfaceManifest: (surfaceName: string) => ResolvedSurfaceManifest | undefined;\n /** The render-definition (\"content block\") rows already in the host store. */\n selectRenderDefinitions: (state: unknown) => readonly SklRenderDefinition[];\n confirm: (options: ConfirmOptions) => Promise<boolean>;\n /** The last-resort dialog when the clipboard refuses a write. */\n showManualCopy: (options: ManualCopyOptions) => void;\n /** The surface whose `spoken_summary` role every surface falls back to. */\n listeningHomeSurface: string;\n /** The host's document agent review (rendered when an AI result can replace a selection). */\n DocumentAgentReview: ComponentType<DocumentAgentReviewProps> | null;\n}\n\n// ── Defaults ──────────────────────────────────────────────────────────────\n\nfunction unwired(name: string): void {\n const announced = slot().announced;\n if (announced.has(name)) return;\n announced.add(name);\n console.warn(`[context-menu] host port \"${name}\" is not wired — configureContextMenuHost({ ${name} }).`);\n}\nfunction unwiredFn(name: string): () => void {\n return () => unwired(name);\n}\n\nconst DEFAULT_QUICK_ACTIONS: ContextMenuQuickActions = {\n openChatWindow: unwiredFn(\"quickActions.openChatWindow\"),\n openQuickChat: unwiredFn(\"quickActions.openQuickChat\"),\n openQuickData: unwiredFn(\"quickActions.openQuickData\"),\n openQuickFiles: unwiredFn(\"quickActions.openQuickFiles\"),\n openQuickNotes: unwiredFn(\"quickActions.openQuickNotes\"),\n openQuickTasks: unwiredFn(\"quickActions.openQuickTasks\"),\n openVoicePad: unwiredFn(\"quickActions.openVoicePad\"),\n};\n\nconst DEFAULT_BINDINGS: ContextMenuHostBindings = {\n isAdminDebugger: false,\n hasAdminPower: false,\n isDebugMode: false,\n isAdminIndicatorOpen: false,\n hasCompareBase: false,\n activeScopeIds: null,\n toggleDebugMode: unwiredFn(\"useBindings.toggleDebugMode\"),\n toggleAdminIndicator: unwiredFn(\"useBindings.toggleAdminIndicator\"),\n setCompareBase: unwiredFn(\"useBindings.setCompareBase\"),\n openCompareWithBase: async () => {\n unwired(\"useBindings.openCompareWithBase\");\n return false;\n },\n openListenSummaryWindow: unwiredFn(\"useBindings.openListenSummaryWindow\"),\n openDiffWindow: unwiredFn(\"useBindings.openDiffWindow\"),\n openFindReplace: unwiredFn(\"useBindings.openFindReplace\"),\n openReferencePicker: unwiredFn(\"useBindings.openReferencePicker\"),\n openContextAssignment: unwiredFn(\"useBindings.openContextAssignment\"),\n openLinkRecordSheet: unwiredFn(\"useBindings.openLinkRecordSheet\"),\n openShareModalWindow: unwiredFn(\"useBindings.openShareModalWindow\"),\n openStateViewer: unwiredFn(\"useBindings.openStateViewer\"),\n openSurfaceInspector: unwiredFn(\"useBindings.openSurfaceInspector\"),\n openSurfaceContextWindow: unwiredFn(\"useBindings.openSurfaceContextWindow\"),\n openBindAgent: unwiredFn(\"useBindings.openBindAgent\"),\n quickActions: DEFAULT_QUICK_ACTIONS,\n};\n\nconst EMPTY_RENDER_DEFINITIONS: readonly SklRenderDefinition[] = [];\n\nexport const DEFAULT_CONTEXT_MENU_HOST: ContextMenuHost = {\n useBindings: () => DEFAULT_BINDINGS,\n getSurfaceManifest: () => undefined,\n selectRenderDefinitions: () => EMPTY_RENDER_DEFINITIONS,\n confirm: kitConfirm,\n showManualCopy: () => unwired(\"showManualCopy\"),\n listeningHomeSurface: \"matrx-user/assistant-message\",\n DocumentAgentReview: null,\n};\n\n// ── Registration (one slot per realm) ─────────────────────────────────────\n\nconst SLOT = Symbol.for(\"ai-matrx.context-menu.host\");\ntype Slot = { host: ContextMenuHost; announced: Set<string> };\n\nfunction slot(): Slot {\n const g = globalThis as unknown as Record<symbol, Slot | undefined>;\n let s = g[SLOT];\n if (!s) {\n s = { host: DEFAULT_CONTEXT_MENU_HOST, announced: new Set() };\n g[SLOT] = s;\n }\n return s;\n}\n\n/** Register the host's answers. Partial: anything omitted keeps its default. */\nexport function configureContextMenuHost(host: Partial<ContextMenuHost>): void {\n slot().host = { ...slot().host, ...host };\n}\n\n/** The registered host (defaults where the host registered nothing). */\nexport function getContextMenuHost(): ContextMenuHost {\n return slot().host;\n}\n\n/** Tests: back to the shipped defaults. */\nexport function resetContextMenuHost(): void {\n slot().host = DEFAULT_CONTEXT_MENU_HOST;\n slot().announced.clear();\n}\n\n/** The per-render bindings — a hook; call it at the top level of a component or hook. */\nexport function useContextMenuHostBindings(): ContextMenuHostBindings {\n return getContextMenuHost().useBindings();\n}\n","/**\n * Inserts text at the current cursor position in a contenteditable editor\n * identified by `data-editor-id`.\n */\nexport function insertTextAtCursor(editorId: string, text: string): boolean {\n try {\n const editor = document.querySelector(\n `[data-editor-id=\"${editorId}\"]`,\n ) as HTMLDivElement | null;\n if (!editor) {\n console.error(\"[editor-text-insertion] Editor not found:\", editorId);\n return false;\n }\n\n editor.focus();\n\n const selection = window.getSelection();\n if (!selection) {\n console.error(\"[editor-text-insertion] Selection not available\");\n return false;\n }\n\n let range: Range;\n\n if (selection.rangeCount > 0) {\n range = selection.getRangeAt(0);\n } else {\n range = document.createRange();\n const lastNode = editor.lastChild;\n if (lastNode) {\n if (lastNode.nodeType === Node.TEXT_NODE) {\n range.setStart(lastNode, lastNode.textContent?.length ?? 0);\n } else {\n range.setStartAfter(lastNode);\n }\n } else {\n range.setStart(editor, 0);\n }\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n }\n\n if (!range.collapsed) {\n range.deleteContents();\n }\n\n const textNode = document.createTextNode(text);\n range.insertNode(textNode);\n\n range.setStartAfter(textNode);\n range.setEndAfter(textNode);\n selection.removeAllRanges();\n selection.addRange(range);\n\n editor.focus();\n\n return true;\n } catch (error) {\n console.error(\"[editor-text-insertion] Error inserting text:\", error);\n return false;\n }\n}\n","// features/context-menu-v3/utils/insert-into-editor.ts\n//\n// THE one way the menu puts text INTO the editable surface it was opened on.\n//\n// A surface advertises up to three write targets: a contentEditable editor id,\n// a textarea getter, and an `insertAtCaret` callback (rich editors). Which one\n// is live is a CALL-TIME fact, never a prop-presence fact: a host that swaps\n// editors in place (Notes: Split/Plain mount a textarea, Write mounts the rich\n// editor) keeps passing `getTextarea` and simply has it return null while the\n// rich editor is up. Gating the caret path on `!getTextarea` (the 2026-10-02\n// \"Insert reference… → Copied instead, 3/3 in Write mode\" bug) let a dead\n// getter veto the live editor. So each target is tried in order and the first\n// one that is actually there and takes the text wins.\n\nimport { insertTextAtCursor } from \"./editor-text-insertion\";\nimport { blockBoundary, insertTextAtTextareaCursor } from \"@ai-matrx/rich-editor/core/text-insertion\";\n\n/**\n * `inline` goes exactly at the caret; `block` (a reference fence, a section)\n * goes on its own line, never inside a word (G5 review, 2026-10-02: \"of\" became\n * \"o\" + block + \"f\") — BEFORE the caret's line only from its very start,\n * AFTER it otherwise (G11B: a right-click at the start of a line goes above;\n * G15, 2026-10-07: a character \"first half\" rule surprised wrapped\n * paragraphs). The one rule is `blockBoundary(…, \"nearest\")`\n * (@ai-matrx/rich-editor ≥ 0.3.1).\n */\nexport type EditorInsertPlacement = \"inline\" | \"block\";\n\nexport interface EditorInsertTargets {\n /** A contentEditable editor addressed by `data-editor-id`. */\n editorId?: string | undefined;\n /** The surface's textarea — may return null when no textarea is mounted now. */\n getTextarea?: (() => HTMLTextAreaElement | null) | undefined;\n /**\n * A rich editor's insert-at-the-caret. Returns false when it cannot take it.\n * A `block` must land on its own line/paragraph, never inside a word.\n */\n insertAtCaret?: ((text: string, placement?: EditorInsertPlacement) => boolean) | undefined;\n /** Full-value write-back for a controlled textarea. */\n onTextReplace?: ((nextValue: string) => void) | undefined;\n}\n\n/** The text to insert, shaped per target (a textarea knows its neighbours). */\nexport interface EditorInsertText {\n editor: string;\n textarea: (field: HTMLTextAreaElement) => string;\n caret: string;\n /** Default `inline`. */\n placement?: EditorInsertPlacement | undefined;\n}\n\nexport type EditorInsertTarget = \"editor\" | \"textarea\" | \"caret\";\n\n/** True when the surface advertises any write target at all. */\nexport function hasEditorInsertTarget(targets: EditorInsertTargets): boolean {\n return Boolean(targets.editorId) || Boolean(targets.getTextarea) || Boolean(targets.insertAtCaret);\n}\n\n/**\n * Insert into whichever target is live right now. Returns the target that took\n * the text, or null when none could (the caller then copies — never silent).\n */\nexport function insertIntoEditor(\n targets: EditorInsertTargets,\n text: string | EditorInsertText,\n): EditorInsertTarget | null {\n const shaped: EditorInsertText =\n typeof text === \"string\" ? { editor: text, textarea: () => text, caret: text } : text;\n const { editorId, getTextarea, insertAtCaret, onTextReplace } = targets;\n const placement = shaped.placement ?? \"inline\";\n\n if (editorId) {\n const took = attempt(\"editor\", () => {\n if (placement === \"block\") moveEditorCaretToLineEnd(editorId);\n return insertTextAtCursor(editorId, shaped.editor);\n });\n if (took) return \"editor\";\n }\n\n const field = editorId ? null : (getTextarea?.() ?? null);\n if (field) {\n const took = attempt(\"textarea\", () => {\n if (placement === \"block\" && field.selectionStart === field.selectionEnd) {\n const at = blockBoundary(field.value, field.selectionStart, field.selectionEnd, \"nearest\");\n field.setSelectionRange(at, at);\n }\n return insertTextAtTextareaCursor(field, shaped.textarea(field), onTextReplace);\n });\n if (took) return \"textarea\";\n }\n\n if (insertAtCaret && attempt(\"caret\", () => insertAtCaret(shaped.caret, placement))) return \"caret\";\n return null;\n}\n\n/**\n * A target that THROWS is a target that did not take the text — never an\n * exception that escapes into the caller. A rich editor's insert once threw\n * `TransformError` up through the reference picker's pick handler: the dialog\n * stayed open and nothing happened (G8B review, 2026-10-02). Now the next\n * target is tried, and with none left the caller copies and says so.\n */\nfunction attempt(target: EditorInsertTarget, insert: () => boolean): boolean {\n try {\n return insert();\n } catch (error) {\n console.error(`[ContextMenuV3] ${target} insert failed`, error);\n return false;\n }\n}\n\n/**\n * A collapsed caret inside a contentEditable text node moves to an edge of its\n * line (the start only from the very start, else the end), so a block never\n * lands inside a word. A selection is left alone: it is replaced where it is.\n */\nfunction moveEditorCaretToLineEnd(editorId: string): void {\n const editor = document.querySelector(`[data-editor-id=\"${editorId}\"]`);\n const selection = window.getSelection();\n if (!editor || !selection || selection.rangeCount === 0) return;\n const range = selection.getRangeAt(0);\n if (!range.collapsed || !editor.contains(range.startContainer)) return;\n const node = range.startContainer;\n if (node.nodeType !== Node.TEXT_NODE) return;\n const text = node.textContent ?? \"\";\n const at = blockBoundary(text, range.startOffset, range.startOffset, \"nearest\");\n const next = document.createRange();\n next.setStart(node, at);\n next.collapse(true);\n selection.removeAllRanges();\n selection.addRange(next);\n}\n\n/**\n * A block that must sit on its own paragraph inside a textarea: blank lines\n * are added only where the neighbours do not already provide them.\n */\nexport function ownParagraph(block: string, field: HTMLTextAreaElement): string {\n const before = field.value.slice(0, field.selectionStart);\n const after = field.value.slice(field.selectionEnd);\n const lead = before.length === 0 || before.endsWith(\"\\n\\n\") ? \"\" : before.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n const tail = after.length === 0 || after.startsWith(\"\\n\\n\") ? \"\" : after.startsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n return `${lead}${block}${tail}`;\n}\n","\"use client\";\n\nimport { compact } from \"../utils/compact\";\nimport { useMemo, useState, useCallback } from \"react\";\nimport { useAppDispatch, useAppSelector } from \"@ai-matrx/chat/store/hooks\";\nimport { getContextMenuHost } from \"../host/port\";\nimport {\n fetchUnifiedMenu,\n unifiedMenuLoadedKey,\n} from \"@ai-matrx/chat/agents/redux/agent-shortcuts/thunks\";\nimport { withMenuDeadline } from \"../utils/menu-deadline\";\nimport { selectAllShortcutsArray } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/selectors\";\nimport { selectAllCategoriesArray } from \"@ai-matrx/chat/agents/redux/agent-shortcut-categories/selectors\";\nimport type { AgentShortcutRecord } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/types\";\nimport type { AgentShortcutCategoryRecord } from \"@ai-matrx/chat/agents/redux/agent-shortcut-categories/types\";\nimport type { SklRenderDefinition as AgentContentBlockRecord } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/skl-types\";\nimport type { Scope } from \"@ai-matrx/chat/agents/redux/shared/scope\";\nimport { resolveRowScope } from \"@ai-matrx/chat/agents/redux/shared/scope\";\nimport { placementGroupKey } from \"@ai-matrx/chat/agents/shortcuts/constants\";\nimport {\n decideOffer,\n readMenuScope,\n requirementsOf,\n type MenuScopeLevel,\n} from \"../model/requirement-gate\";\n\nexport type AgentMenuEntry =\n | ({ entryType: \"agent_shortcut\"; scopeLevel: Scope } & AgentShortcutRecord)\n | ({ entryType: \"content_block\"; scopeLevel: Scope } & AgentContentBlockRecord);\n\nexport interface AgentMenuCategoryGroup {\n category: AgentShortcutCategoryRecord & { scopeLevel: Scope };\n items: AgentMenuEntry[];\n children: AgentMenuCategoryGroup[];\n}\n\n/**\n * Keys whose POPULATION (not just existence) is checked — the single\n * population-level gate the menu keeps, and the only exception to\n * \"availability is the key existing, not the value\".\n *\n * Kept because the menu is selection-triggered anyway: \"No text selected →\n * nothing to translate → no translate option in the menu\" (Arman, INTERVIEW\n * R8). Everything else gates on key-existence only.\n *\n * The value tested is the RESOLVED scope's `selection`, which already carries\n * the platform's `active_text` convention (`value-resolution.ts`): on a\n * surface that knows the acting text, an unhighlighted right-click still has\n * a selection, so these items stay offered. Only a genuinely empty one hides\n * them.\n */\nconst SELECTION_DEPENDENT_KEYS: ReadonlySet<string> = new Set([\"selection\"]);\n\nexport interface UseUnifiedAgentContextMenuArgs {\n /**\n * Which placement submenus this host renders. LAYOUT ONLY — see\n * `buildCategoryGroups`. It never decides whether an ITEM is available.\n */\n placementTypes: string[];\n /**\n * The Surface Registry `ui_surface.name` (`<client>/<surface>`) this menu is\n * mounted on, or null on a page the platform cannot name. It is the\n * page-level rung of the scope hierarchy and the key to the exclusion valve.\n */\n surfaceName?: string | null | undefined;\n /**\n * Every surface value name that has a READ PATH here: the manifest's\n * declared values + the baseline floor + whatever actually landed in the\n * resolved scope. Built by `buildAvailableKeys` in the engine.\n */\n availableKeys: ReadonlySet<string>;\n /** True when the resolved scope carries a non-empty `selection`. */\n hasSelection: boolean;\n /** The surface's exclusion valve (`menu` surface-config namespace). */\n excludedItemIds?: ReadonlySet<string> | undefined;\n enabled?: boolean | undefined;\n scope?: Scope | undefined;\n scopeId?: string | null | undefined;\n}\n\nexport interface UseUnifiedAgentContextMenuResult {\n categoryGroups: AgentMenuCategoryGroup[];\n loading: boolean;\n error: string | null;\n refresh: () => Promise<void>;\n}\n\nconst SCOPE_PRIORITY: Record<Scope, number> = {\n task: 5,\n project: 4,\n user: 3,\n organization: 2,\n global: 1,\n};\n\n/**\n * Screen specificity of an item's authored scope: a page-pinned version beats\n * a domain-wide one, which beats a global one. Rows without a `surfaceName`\n * (categories, content blocks) are all global, so this never separates them.\n */\nconst SPECIFICITY: Record<MenuScopeLevel, number> = {\n surface: 3,\n domain: 2,\n global: 1,\n};\n\nfunction specificityOf(item: { surfaceName?: string | null }): number {\n return SPECIFICITY[\n readMenuScope({ id: \"\", surfaceName: item.surfaceName ?? null }).level\n ];\n}\n\n/**\n * Does `a` beat `b` for the same dedupe key? Deterministic and independent of\n * row order (the view emits ties in arbitrary order — every sort_order is 0):\n * 1. owner level (task > project > user > organization > global);\n * 2. screen specificity (page > domain > global) — the screen's own version\n * of an action always beats a generic copy at the same owner level;\n * 3. id, ascending — a total order, so equal rows never depend on arrival.\n */\nfunction beats<T extends { scopeLevel: Scope; id: string; surfaceName?: string | null }>(\n a: T,\n b: T,\n): boolean {\n const byOwner = SCOPE_PRIORITY[a.scopeLevel] - SCOPE_PRIORITY[b.scopeLevel];\n if (byOwner !== 0) return byOwner > 0;\n const bySpecificity = specificityOf(a) - specificityOf(b);\n if (bySpecificity !== 0) return bySpecificity > 0;\n return a.id < b.id;\n}\n\nfunction dedupeByPrecedence<\n T extends { scopeLevel: Scope; id: string; surfaceName?: string | null },\n>(items: T[], keyFn: (item: T) => string | null): T[] {\n const winners = new Map<string, T>();\n const passthrough: T[] = [];\n for (const item of items) {\n const key = keyFn(item);\n if (!key) {\n passthrough.push(item);\n continue;\n }\n const existing = winners.get(key);\n if (!existing || beats(item, existing)) winners.set(key, item);\n }\n return [...winners.values(), ...passthrough];\n}\n\nexport interface BuildCategoryGroupsArgs {\n placementTypes: string[];\n surfaceName?: string | null | undefined;\n availableKeys: ReadonlySet<string>;\n hasSelection: boolean;\n excludedItemIds?: ReadonlySet<string> | undefined;\n shortcuts: AgentShortcutRecord[];\n categories: AgentShortcutCategoryRecord[];\n contentBlocks: AgentContentBlockRecord[];\n}\n\n/**\n * THE grouping function — pure and unit-tested\n * (`__tests__/build-category-groups.test.ts`,\n * `../model/__tests__/requirement-gate.test.ts`). Turns the fetched\n * shortcut/category/content-block rows into the nested category tree each\n * placement submenu renders.\n *\n * 🚨 PHASE 6.7 — AVAILABILITY IS DERIVED (THE-MODEL law 3). An item is\n * offered here iff every surface value it consumes has a read path on this\n * surface; then its authored scope (global / domain / page) must reach here;\n * then the surface's exclusion valve gets the last word. The 16 hardcoded\n * `enabled_features` slugs and the RED `legacyMatch` rows they produced are\n * GONE: an item qualifies or is absent, and nothing renders as broken.\n *\n * 🚨 CATEGORIES GROUP, THEY NEVER GATE. A category's `placementType` still\n * decides WHICH placement submenu it renders under — that is layout, and it\n * is the only thing `placementTypes` does here. A category is never dropped\n * for failing a context filter, and an item's availability never consults its\n * category.\n *\n * Guarantees the tests certify:\n * - the derived gate: missing key → absent; key declared-but-empty → present;\n * - the hierarchy: global reaches everywhere, a domain reaches its surfaces,\n * a page-pinned item reaches only its page;\n * - the valve: an excluded id is absent even though it qualified;\n * - placement fidelity: a row renders under exactly its category's\n * placementType;\n * - nested categories nest under their parent, sorted by sortOrder then label;\n * - an EMPTY category still returns (with `items: []`) so the UI can render it\n * greyed — never silently dropped;\n * - an entry with no agent is kept (the renderer disables it as \"Not configured\");\n * - scope precedence dedupe (task > project > user > organization > global),\n * ties broken by screen specificity (page > domain > global), then id —\n * never by row order.\n */\nexport function buildCategoryGroups(\n args: BuildCategoryGroupsArgs,\n): AgentMenuCategoryGroup[] {\n const {\n placementTypes,\n surfaceName = null,\n availableKeys,\n hasSelection,\n excludedItemIds,\n shortcuts,\n categories,\n contentBlocks,\n } = args;\n if (placementTypes.length === 0) return [];\n\n // LAYOUT: which placement submenus this host draws.\n const placementSet = new Set(placementTypes);\n\n const scopedCategories = categories\n .filter(\n (c) =>\n c.isActive !== false &&\n placementSet.has(placementGroupKey(c.placementType)),\n )\n .map((c) => ({ ...c, scopeLevel: resolveRowScope(c) }));\n const scopedShortcuts = shortcuts\n .filter((s) => s.isActive !== false)\n .map((s) => ({\n ...s,\n entryType: \"agent_shortcut\" as const,\n scopeLevel: resolveRowScope(s),\n }));\n const scopedBlocks = contentBlocks\n .filter((b) => b.isActive !== false)\n .map((b) => ({\n ...b,\n entryType: \"content_block\" as const,\n scopeLevel: resolveRowScope(b),\n }));\n\n const offerCtx = compact({\n surfaceName,\n availableKeys,\n excludedItemIds,\n });\n\n const filteredShortcuts = scopedShortcuts.filter((s) => {\n if (!decideOffer(s, offerCtx).offered) return false;\n // The ONE population check (see SELECTION_DEPENDENT_KEYS).\n if (hasSelection) return true;\n return !requirementsOf(s).some((key) => SELECTION_DEPENDENT_KEYS.has(key));\n });\n\n // Content blocks are static insertable text — they consume nothing, so the\n // gate offers them everywhere. They still pass through the valve.\n const filteredBlocks = scopedBlocks.filter(\n (b) => !excludedItemIds?.has(b.id),\n );\n\n const dedupedShortcuts = dedupeByPrecedence(filteredShortcuts, (s) => {\n if (s.keyboardShortcut) return `kbd:${s.keyboardShortcut}`;\n return `label:${s.categoryId}:${s.label}`;\n });\n\n const dedupedBlocks = dedupeByPrecedence(\n filteredBlocks,\n (b) => `block:${b.categoryId ?? \"_none\"}:${b.blockId}`,\n );\n\n const byCategory = new Map<string, AgentMenuEntry[]>();\n for (const s of dedupedShortcuts) {\n if (!byCategory.has(s.categoryId)) byCategory.set(s.categoryId, []);\n byCategory.get(s.categoryId)!.push(s as AgentMenuEntry);\n }\n for (const b of dedupedBlocks) {\n const cid = b.categoryId;\n if (!cid) continue;\n if (!byCategory.has(cid)) byCategory.set(cid, []);\n byCategory.get(cid)!.push(b as AgentMenuEntry);\n }\n\n // CATEGORIES GROUP, NEVER GATE: every active category whose placement this\n // host renders is kept, empty or not. (An empty category still renders\n // greyed — Arman must see where new items will land the moment he creates\n // one.) Nothing here inspects the category's own `enabledFeatures`; the\n // column no longer decides anything.\n const dedupedCategories = dedupeByPrecedence(\n scopedCategories,\n (c) => `${c.placementType}:${c.parentCategoryId ?? \"_root\"}:${c.label}`,\n );\n\n const nodeMap = new Map<string, AgentMenuCategoryGroup>();\n for (const cat of dedupedCategories) {\n nodeMap.set(cat.id, {\n category: cat,\n items: (byCategory.get(cat.id) ?? [])\n .slice()\n .sort((x, y) => (x.sortOrder ?? 0) - (y.sortOrder ?? 0)),\n children: [],\n });\n }\n\n const roots: AgentMenuCategoryGroup[] = [];\n for (const cat of dedupedCategories) {\n const node = nodeMap.get(cat.id)!;\n if (cat.parentCategoryId && nodeMap.has(cat.parentCategoryId)) {\n nodeMap.get(cat.parentCategoryId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n const sortNodes = (nodes: AgentMenuCategoryGroup[]) => {\n nodes.sort(\n (a, b) =>\n (a.category.sortOrder ?? 0) - (b.category.sortOrder ?? 0) ||\n a.category.label.localeCompare(b.category.label),\n );\n for (const n of nodes) sortNodes(n.children);\n };\n sortNodes(roots);\n\n return roots;\n}\n\nexport function useUnifiedAgentContextMenu(\n args: UseUnifiedAgentContextMenuArgs,\n): UseUnifiedAgentContextMenuResult {\n const {\n placementTypes,\n surfaceName = null,\n availableKeys,\n hasSelection,\n excludedItemIds,\n enabled = true,\n scope = \"global\",\n scopeId = null,\n } = args;\n\n const dispatch = useAppDispatch();\n\n const shortcuts = useAppSelector(selectAllShortcutsArray);\n const categories = useAppSelector(selectAllCategoriesArray);\n const contentBlocks = useAppSelector((state) => getContextMenuHost().selectRenderDefinitions(state));\n\n // A load is finished only when its rows are in hand: the menu's own\n // rows-in-hand flag in the store, not this hook's promise. A local\n // \"loading\" boolean read false on the first render (before the effect\n // fires) and false again when a skipped dispatch rejected at once — both\n // read as \"loaded, nothing here\", so My Items / Org Items vanished from the\n // first open and appeared on the next (round 6, 2026-09-27).\n const rowsInHand = useAppSelector(\n (state) =>\n state.agentShortcut.contextLoaded?.[\n unifiedMenuLoadedKey({ scope, scopeId })\n ] ?? false,\n );\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(async () => {\n if (!enabled || placementTypes.length === 0) return;\n try {\n setError(null);\n await withMenuDeadline(\n dispatch(fetchUnifiedMenu({ scope, scopeId })).unwrap(),\n \"Loading the menu's AI actions\",\n );\n } catch (err) {\n // Skipped because the rows are already in hand: not a failure.\n if ((err as { name?: string } | null)?.name === \"ConditionError\") return;\n setError(err instanceof Error ? err.message : \"Failed to load menu\");\n }\n }, [dispatch, enabled, placementTypes.length, scope, scopeId]);\n\n // Intentionally NO mount-time useEffect that fires refresh(). The menu is\n // one of the most expensive fetches in the system — it must only run when\n // the user actually engages. UnifiedAgentContextMenu calls `refresh()`\n // from its `onOpenChange` handler. The fetchUnifiedMenu thunk dedupes\n // internally (module-level inflight map + scope-loaded condition) so\n // rapid opens + multi-mounted menus all resolve to a single HTTP call.\n\n const categoryGroups = useMemo<AgentMenuCategoryGroup[]>(() => {\n if (!enabled) return [];\n return buildCategoryGroups({\n placementTypes,\n surfaceName,\n availableKeys,\n hasSelection,\n excludedItemIds,\n shortcuts,\n categories,\n contentBlocks: [...contentBlocks],\n });\n }, [\n enabled,\n placementTypes,\n categories,\n shortcuts,\n contentBlocks,\n surfaceName,\n availableKeys,\n hasSelection,\n excludedItemIds,\n ]);\n\n return {\n categoryGroups,\n loading:\n enabled && placementTypes.length > 0 && !rowsInHand && error === null,\n // Rows in hand end a failure too: a fetch that landed after the menu's\n // deadline must not leave a \"Couldn't load\" row beside the rows it brought.\n error: rowsInHand ? null : error,\n refresh,\n };\n}\n","export * from \"@ai-matrx/chat/context-menu/utils/menu-deadline\";\n","export * from \"@ai-matrx/chat/context-menu/model/requirement-gate\";\n","// features/context-menu-v3/value-resolution.ts\n//\n// The single most important module in v3: it assembles the `ApplicationScope`\n// the menu acts on, and it makes the two failure classes the user keeps hitting\n// STRUCTURALLY VISIBLE:\n//\n// 1. \"Fake menu\" — a menu that opens but Copy does nothing and the selection\n// bar is empty, because the surface wired neither a selection nor content.\n// Fixed at the root: the DOM-subtree text fallback means read-only content\n// is copyable/actionable with zero surface wiring; `detectInertMenu` then\n// SCREAMS in dev if a menu still opens with nothing resolvable.\n//\n// 2. Broken value mapping — a surface declares a value its shortcuts/agents\n// depend on but forgets to emit it. `auditSurfaceScope` compares the\n// surface's declared `alwaysAvailable` values against what actually landed\n// in the scope and screams about any that are missing.\n//\n// The 5 generic baseline values (selection, text_before, text_after, content,\n// context) are guaranteed present via the platform primitive `withBaselineScope`\n// — we reuse it, never reimplement it.\n\nimport type { ApplicationScope } from \"@ai-matrx/chat/agents/types/scope.types\";\nimport { withBaselineScope } from \"@ai-matrx/chat/surfaces/utils/baseline-scope\";\nimport {\n BASELINE_VALUE_NAMES,\n type BaselineKey,\n} from \"@ai-matrx/chat/surfaces/manifests/_baseline.manifest\";\nimport { getContextMenuHost } from \"./host/port\";\nimport {\n getSurfaceRuntime,\n getSurfaceRuntimeForName,\n} from \"@ai-matrx/chat/surfaces/runtime/SurfaceRuntimeContext\";\nimport type { SelectionRange } from \"./utils/selection-tracking\";\nimport { CONTEXT_MENU_ENTITY_KEY, CONTEXT_MENU_HEADING_KEY } from \"./types\";\n\n/**\n * Keys the menu manages internally and must not leak into the scope as values.\n * `__entity` is the reserved per-row entity (`utils/per-row-entity.ts`) — the\n * shell already strips it; this is the belt for a surface that puts it in\n * static `contextData`.\n */\nconst SKIP_MERGE_KEYS = new Set<string>([CONTEXT_MENU_ENTITY_KEY, CONTEXT_MENU_HEADING_KEY]);\n\nconst isDev = process.env.NODE_ENV !== \"production\";\n\nfunction strOf(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nexport interface ResolveScopeArgs {\n /** Live scope builder from the surface — wins when present. */\n getApplicationScope?: (() => ApplicationScope) | undefined;\n /** Static + per-target-merged value payload from the surface. */\n contextData: Record<string, unknown>;\n /** The text the user has selected (captured by the shell at open). */\n selectedText: string;\n /** The captured selection range (drives text_before / text_after / content). */\n selectionRange: SelectionRange | null;\n /**\n * Plain text of the right-clicked DOM subtree, captured by the shell. Used as\n * `content` ONLY when nothing else resolved it — the net that stops a\n * read-only surface from presenting a dead Copy.\n */\n fallbackContent?: string | undefined;\n /**\n * The surface this menu declared. Used to adopt the LIVE mounted\n * `SurfaceRuntime` for that same surface as an underlay (see\n * `adoptMountedRuntimeScope`).\n */\n surfaceName?: string | undefined;\n /**\n * AMBIENT STATE — what is true around the user right now (active org, active\n * scopes, surface, whether a run is streaming). Collected by the engine from\n * Redux and landed on ONE namespaced `ambient` key, never spread across the\n * scope. The weakest layer there is: a surface that emits its own `ambient`\n * keeps it untouched.\n */\n ambient?: Record<string, unknown> | undefined;\n}\n\n/**\n * Build the complete `ApplicationScope` for this menu invocation.\n *\n * Assembly: the static underlay (`contextData` + the shell-captured selection\n * triad) is built first; when the surface supplies a LIVE builder\n * (`getApplicationScope`) its result is overlaid PER KEY on top. A key the\n * builder emits is authoritative — including an explicit empty (the Vault\n * forces `selection: \"\"` so a highlight over revealed plaintext never enters\n * the scope). A key the builder never mentions falls back to the underlay, so\n * a live-scope surface no longer silently discards `contextData` or the\n * captured selection/text_before/text_after wholesale.\n *\n * Order of precedence for `content`:\n * 1. surface `getApplicationScope().content` / `contextData.content`\n * 2. the full value of an editable field (from the selection range)\n * 3. the DOM-subtree text fallback (`fallbackContent`)\n *\n * The result always carries the 5 baseline keys (empty-floored).\n */\n/**\n * Adopt the LIVE mounted `SurfaceRuntime` as the bottom layer of the scope.\n *\n * 🚨 THE RICH-PAGE / INERT-MENU CLASS (Phase 0, 2026-08-25). `getSurfaceRuntime`\n * holds what the page is actually showing — its filters, its date range, its\n * rows. The launch thunk adopts it. The shell-header Agents panel reads it. The\n * MENU never did: a page with a fully mounted provider still produced an inert\n * menu whenever whoever wired the wrapper did not also hand it values by hand.\n * That made \"make this surface's menu know what is on screen\" per-surface\n * labour, repeated once per surface, done inconsistently — the single biggest\n * driver of shell menus in the census.\n *\n * PRECEDENCE — this is an UNDERLAY, the weakest layer there is. It fills only\n * keys that nothing else provided; `contextData`, the per-row merge, a live\n * `getApplicationScope` and the DOM capture all beat it. A surface that says\n * something is never contradicted by the page it sits on.\n *\n * SYNC ONLY, deliberately. `getScope()` may return a promise, and menu scope is\n * assembled during the render that opens the menu. An async builder is skipped\n * here and still reaches agents at Run time through the launch thunk's own\n * adoption — so the async case degrades to exactly the previous behaviour\n * rather than to something wrong.\n */\nfunction adoptMountedRuntimeScope(\n surfaceName: string | undefined,\n): ApplicationScope | null {\n try {\n const mounted = surfaceName\n ? getSurfaceRuntimeForName(surfaceName)\n : getSurfaceRuntime();\n if (!mounted) return null;\n const payload = mounted.getScope();\n // A promise means this surface builds its scope asynchronously — see above.\n if (payload && typeof (payload as Promise<unknown>).then === \"function\")\n return null;\n return payload as ApplicationScope;\n } catch (err) {\n // Loud, non-fatal: the menu still opens with whatever the surface passed.\n if (isDev)\n console.error(\n \"[ContextMenuV3] mounted SurfaceRuntime threw in getScope() — menu scope falls back to the surface's own values\",\n err,\n );\n return null;\n }\n}\n\n/** True for a value that carries no information — an underlay may fill it. */\nfunction isEmptyValue(value: unknown): boolean {\n if (value === undefined || value === null) return true;\n if (typeof value === \"string\") return value.trim() === \"\";\n if (typeof value === \"object\" && !Array.isArray(value))\n return Object.keys(value as object).length === 0;\n return false;\n}\n\nexport function resolveApplicationScope(\n args: ResolveScopeArgs,\n): ApplicationScope {\n const base: ApplicationScope = buildFromMenuContext(args);\n\n /**\n * Keys the SURFACE itself spoke about — static payload plus live builder.\n * 🚨 An explicit EMPTY is an answer, not a silence: the Vault forces\n * `selection: \"\"` as credential-leak hardening, and the runtime underlay\n * below must never refill it from the page the Vault happens to sit on.\n */\n const surfaceAnswered = new Set<string>(\n Object.keys(args.contextData ?? {}).filter((k) => !SKIP_MERGE_KEYS.has(k)),\n );\n if (args.getApplicationScope) {\n const live = args.getApplicationScope();\n for (const [k, v] of Object.entries(live)) {\n if (SKIP_MERGE_KEYS.has(k) || v === undefined) continue;\n base[k] = v;\n surfaceAnswered.add(k);\n }\n }\n\n // THE RUNTIME UNDERLAY — fills only genuine silences, beaten by everything.\n const runtime = adoptMountedRuntimeScope(args.surfaceName);\n if (runtime) {\n for (const [k, v] of Object.entries(runtime)) {\n if (SKIP_MERGE_KEYS.has(k) || v === undefined) continue;\n if (surfaceAnswered.has(k)) continue;\n if (isEmptyValue(base[k])) base[k] = v;\n }\n }\n\n // THE AMBIENT LAYER — weaker still than the runtime underlay, and confined\n // to ONE key. A surface that speaks about `ambient` is never contradicted.\n if (args.ambient && !surfaceAnswered.has(\"ambient\") && isEmptyValue(base.ambient))\n base.ambient = args.ambient;\n\n // No-fake-menu net: if no usable content resolved but the DOM gave us text,\n // adopt it so Copy / AI actions always have something to act on. A surface\n // with a LIVE builder opted out of this net (documented in FEATURE.md — the\n // Vault relies on it: DOM text there can be revealed plaintext, and an empty\n // live scope must stay empty rather than adopt it).\n const hasContent = strOf(base.content).trim().length > 0;\n if (\n !args.getApplicationScope &&\n !hasContent &&\n args.fallbackContent &&\n args.fallbackContent.trim()\n ) {\n base.content = args.fallbackContent;\n }\n\n return withBaselineScope(base);\n}\n\n/** Assemble scope from static contextData + the captured selection. */\nfunction buildFromMenuContext(args: ResolveScopeArgs): ApplicationScope {\n const { selectedText, selectionRange, contextData: cd } = args;\n\n let textBefore = \"\";\n let textAfter = \"\";\n let fullContent = \"\";\n if (\n selectionRange &&\n selectionRange.type === \"editable\" &&\n selectionRange.element\n ) {\n const value = selectionRange.element.value ?? \"\";\n fullContent = value;\n textBefore = value.substring(0, selectionRange.start ?? 0);\n textAfter = value.substring(selectionRange.end ?? 0);\n }\n\n const scope: ApplicationScope = {};\n\n // Surface payload first — skip undefined so live capture is not clobbered.\n for (const [k, v] of Object.entries(cd)) {\n if (SKIP_MERGE_KEYS.has(k) || v === undefined) continue;\n scope[k] = v;\n }\n\n // Normalize `context` into an object (the resolver flattens it into entries).\n if (typeof cd.context === \"string\") {\n scope.context = { raw: cd.context };\n } else if (cd.context !== undefined && typeof cd.context !== \"string\") {\n scope.context = cd.context as Record<string, unknown>;\n } else if (scope.context === undefined) {\n scope.context = {};\n }\n\n // Live DOM capture wins for the baseline text-editor triad.\n scope.selection = selectedText;\n scope.text_before = textBefore;\n scope.text_after = textAfter;\n\n if (typeof cd.content === \"string\") {\n scope.content = cd.content;\n } else if (fullContent) {\n scope.content = fullContent;\n } else if (scope.content === undefined) {\n scope.content = \"\";\n }\n\n // Convention: `active_text` is selection when highlighted, else the full body.\n // Bindings mapping agent `content` ← surface `selection` keep working when the\n // user didn't highlight but the surface knows the acting text.\n const activeText = scope.active_text;\n if (\n scope.selection === \"\" &&\n typeof activeText === \"string\" &&\n activeText.length > 0\n ) {\n scope.selection = activeText;\n }\n\n return scope;\n}\n\n// ---------------------------------------------------------------------------\n// Source gating — \"never show an action that can't work\".\n// ---------------------------------------------------------------------------\n\n/**\n * The text Copy / AI actions should operate on: the selection if there is one,\n * otherwise the resolved primary content. This is what makes Copy work on a\n * read-only surface where the user merely right-clicked.\n */\nexport interface ResolvedActionText {\n text: string;\n source: \"selection\" | \"content\" | \"none\";\n}\n\nexport function resolveActionText(scope: ApplicationScope): ResolvedActionText {\n const selection = strOf(scope.selection).trim();\n if (selection) return { text: strOf(scope.selection), source: \"selection\" };\n const content = strOf(scope.content).trim();\n if (content) return { text: strOf(scope.content), source: \"content\" };\n return { text: \"\", source: \"none\" };\n}\n\n/** True when there is anything for the content-acting half of the menu to do. */\nexport function hasActionableContent(scope: ApplicationScope): boolean {\n return resolveActionText(scope).source !== \"none\";\n}\n\n// ---------------------------------------------------------------------------\n// Loud guards (dev only) — the second layer that makes the failure visible.\n// ---------------------------------------------------------------------------\n\nexport interface InertMenuDiagnostic {\n /** True when the menu opened with nothing meaningful to do. */\n inert: boolean;\n reasons: string[];\n}\n\n/**\n * A menu is INERT when, on a read-only surface, there is no selection, no\n * resolvable content, and the surface injected no items of its own — i.e. the\n * user sees Copy/AI rows that do nothing. (Editable surfaces are never inert:\n * Paste is always meaningful.)\n */\nexport function detectInertMenu(args: {\n scope: ApplicationScope;\n isEditable: boolean;\n hasExtraSections: boolean;\n}): InertMenuDiagnostic {\n const reasons: string[] = [];\n const selection = strOf(args.scope.selection).trim();\n const content = strOf(args.scope.content).trim();\n // Structured surfaces such as galleries and charts legitimately have no\n // document text, but their live surface values still make Agents and other\n // scope-aware actions meaningful. Treat any informative non-baseline value\n // as an actionable scope instead of falsely reporting an inert menu.\n const baseline = new Set<string>(\n BASELINE_VALUE_NAMES as readonly BaselineKey[],\n );\n const hasApplicationScope = Object.entries(args.scope).some(\n ([key, value]) => !baseline.has(key) && !isEmptyValue(value),\n );\n if (!selection) reasons.push(\"no selection\");\n if (!content) reasons.push(\"no resolvable content (and no DOM-text fallback)\");\n const inert =\n !args.isEditable &&\n !selection &&\n !content &&\n !hasApplicationScope &&\n !args.hasExtraSections;\n return { inert, reasons };\n}\n\n/**\n * Compare a surface's DECLARED `alwaysAvailable` values against what actually\n * landed in the resolved scope. A declared-but-missing value silently breaks\n * the shortcuts/agents that depend on it — the exact \"values not passed\"\n * failure. Baseline values are skipped (they are empty-floored by design, so a\n * missing one is not an error). Returns human-readable warnings.\n */\nexport function auditSurfaceScope(\n surfaceName: string | undefined,\n scope: ApplicationScope,\n): string[] {\n if (!surfaceName) return [];\n const manifest = getContextMenuHost().getSurfaceManifest(surfaceName);\n if (!manifest) {\n return [\n `surface \"${surfaceName}\" has no registered manifest — its declared values cannot be verified`,\n ];\n }\n const baseline = new Set<string>(BASELINE_VALUE_NAMES as readonly BaselineKey[]);\n const warnings: string[] = [];\n for (const value of manifest.values) {\n if (baseline.has(value.name)) continue; // floored — never an error\n if (!value.alwaysAvailable) continue; // optional by declaration\n // EMITTED-vs-EMPTY. A surface that emits the key has wired the value; an\n // empty string is a legal value for a text control nobody has typed into\n // (`crm.manifest.ts` declares exactly that for `search_query`). Screaming\n // at it made a correctly-wired surface look broken every time a search box\n // was empty — a false alarm is how a real scream gets ignored.\n const present = scope[value.name];\n if (!(value.name in scope) || present === undefined || present === null) {\n warnings.push(\n `declared value \"${value.name}\" is alwaysAvailable but was not emitted into the scope`,\n );\n }\n }\n return warnings;\n}\n\n/**\n * Run both loud guards and SCREAM in dev. A recovery/diagnostic layer that fires\n * means a real defect got past the surface wiring — per doctrine it must be\n * impossible to miss, not a silent default. No-op in production.\n */\nexport function reportMenuDiagnostics(args: {\n surfaceName: string | undefined;\n scope: ApplicationScope;\n isEditable: boolean;\n hasExtraSections: boolean;\n}): InertMenuDiagnostic {\n const diag = detectInertMenu(args);\n if (!isDev) return diag;\n\n const label = args.surfaceName ?? \"(no surfaceName)\";\n if (diag.inert) {\n console.error(\n `%c[ContextMenuV3] INERT MENU on \"${label}\"%c — opened with nothing to act on (${diag.reasons.join(\n \", \",\n )}). This is the \"fake menu\" defect: the surface must provide a selection, contextData.content, getApplicationScope(), or render selectable content the DOM fallback can read.`,\n \"color:#ef4444;font-weight:bold\",\n \"color:inherit\",\n { scopeKeys: Object.keys(args.scope) },\n );\n }\n const valueWarnings = auditSurfaceScope(args.surfaceName, args.scope);\n if (valueWarnings.length > 0) {\n console.error(\n `%c[ContextMenuV3] VALUE MAPPING GAP on \"${label}\"%c — ${valueWarnings.join(\n \"; \",\n )}. Shortcuts/agents bound to these values will receive nothing.`,\n \"color:#f59e0b;font-weight:bold\",\n \"color:inherit\",\n );\n }\n return diag;\n}\n","export * from \"@ai-matrx/chat/context-menu/utils/selection-tracking\";\n","// features/context-menu-v3/utils/selection-write-back.ts\n//\n// SELECTION WRITE-BACK — the Replace / Insert below doors for an AI result\n// that was launched from an editable surface's right-click menu.\n//\n// History: the legacy prompts menu (DynamicContextMenu, deleted 2026-06-28 in\n// 3eef0cab17) ran a text action from an editable selection and showed\n// TextActionResultModal with Replace / Insert before / Insert after. The\n// agents-era menus (v2 UnifiedAgentContextMenu, then v3) kept only\n// `runtime.widgetHandleId`, which lets the MODEL call widget_text_* tools.\n// A shortcut whose agent just answers with text (e.g. \"Clean up webpage\n// content\") therefore produced the right text with no way to put it back —\n// reported on /notes 2026-10-01. This restores the human door for EVERY\n// shortcut / bound agent launched from an editable menu, independent of the\n// shortcut's display mode: the per-launch widget handle carries a\n// `selection` write-back, and the result's action bar (rich-document\n// actions `replace-selection` / `insert-below`) reads it from the\n// conversation's widget handle.\n//\n// Contract: the surface's `onTextReplace` takes the WHOLE new value (see\n// buildEditableWidgetHandle). A textarea/input write therefore splices the\n// captured range into the live value and hands over the full text. Editors\n// without a field (rich editors) use their own caret primitives:\n// `insertAtCaret` replaces the live selection, `onTextInsertAfter` inserts a\n// block after it.\n\nimport type { SelectionWriteBack } from \"@ai-matrx/chat/agents/types/widget-handle.types\";\nimport { spliceInputValue, type SelectionRange } from \"./selection-tracking\";\n\nexport interface BuildSelectionWriteBackArgs {\n /** The text the agent was launched on (the selection, or the whole field). */\n originalText: string;\n /** \"selection\" when the person selected text; anything else = whole field. */\n textSource: string;\n selectionRange: SelectionRange | null | undefined;\n onTextReplace?: ((fullValue: string) => void) | undefined;\n onTextInsertAfter?: ((text: string) => void) | undefined;\n insertAtCaret?: ((text: string) => boolean) | undefined;\n}\n\ntype Field = HTMLTextAreaElement | HTMLInputElement;\n\nfunction isField(el: unknown): el is Field {\n return (\n (typeof HTMLTextAreaElement !== \"undefined\" &&\n el instanceof HTMLTextAreaElement) ||\n (typeof HTMLInputElement !== \"undefined\" && el instanceof HTMLInputElement)\n );\n}\n\n/**\n * Build the write-back for one launch, or null when the surface cannot be\n * written (read-only, or nothing captured to write over).\n */\nexport function buildSelectionWriteBack(\n args: BuildSelectionWriteBackArgs,\n): SelectionWriteBack | null {\n const {\n originalText,\n textSource,\n selectionRange,\n onTextReplace,\n onTextInsertAfter,\n insertAtCaret,\n } = args;\n if (!originalText) return null;\n\n const fieldEl =\n selectionRange?.type === \"editable\" && isField(selectionRange.element)\n ? selectionRange.element\n : null;\n\n if (fieldEl) {\n // The anchor moves with every successful write, so Replace twice is a\n // no-op re-apply and Insert below after Replace lands under the new text.\n let anchorText = originalText;\n let anchorStart =\n textSource === \"selection\" ? selectionRange!.start : 0;\n\n const locate = (): { start: number; end: number } | null => {\n if (!fieldEl.isConnected) return null;\n const value = fieldEl.value;\n if (value.slice(anchorStart, anchorStart + anchorText.length) === anchorText) {\n return { start: anchorStart, end: anchorStart + anchorText.length };\n }\n // The text moved (edits above it) — find it again, only if unambiguous.\n const first = value.indexOf(anchorText);\n if (first === -1 || value.indexOf(anchorText, first + 1) !== -1) {\n return null;\n }\n return { start: first, end: first + anchorText.length };\n };\n\n const write = (start: number, end: number, insert: string): void => {\n const value = fieldEl.value;\n const next = value.slice(0, start) + insert + value.slice(end);\n if (onTextReplace) onTextReplace(next);\n else spliceInputValue(fieldEl, start, end, insert);\n };\n\n return {\n originalText,\n replace: (text) => {\n const at = locate();\n if (!at) return false;\n write(at.start, at.end, text);\n anchorStart = at.start;\n anchorText = text;\n return true;\n },\n insertBelow: (text) => {\n const at = locate();\n if (!at) return false;\n const block = \"\\n\\n\" + text;\n write(at.end, at.end, block);\n anchorStart = at.end + 2;\n anchorText = text;\n return true;\n },\n };\n }\n\n // Editors without a field (rich editors) — only a real selection is a\n // target; their caret primitives act on the editor's live selection.\n if (textSource !== \"selection\") return null;\n if (!insertAtCaret && !onTextInsertAfter) return null;\n return {\n originalText,\n replace: (text) => (insertAtCaret ? insertAtCaret(text) : false),\n insertBelow: (text) => {\n if (!onTextInsertAfter) return false;\n onTextInsertAfter(text);\n return true;\n },\n };\n}\n","// features/context-menu-v3/utils/json-menu-actions.ts\n//\n// The JSON section of the universal context menu. Highlight something that\n// looks like JSON — fenced or bare — and the menu offers the things you\n// actually want for JSON: condense it, squeeze it onto one line, open it back\n// up, sort its keys, add or strip the code fence.\n//\n// Design rules:\n// - The menu ASKS the engine, it does not sniff. Detection and formatting\n// both come from `lib/json-format` (the shared primitive), so the notes\n// cleanup pass and this menu can never disagree about what \"condensed\"\n// means.\n// - Every action carries a REAL before/after hint (\"13 lines -> 3 lines\"),\n// computed from the actual formatted output. No action promises a change\n// it will not make: one that would be a no-op is dropped.\n// - On an EDITABLE surface the action rewrites the text in place (the exact\n// selection when there is one, the whole field otherwise). On a read-only\n// surface it copies the formatted text instead — the same intent, the only\n// verb available.\n// - Unparseable-but-JSON-shaped text still produces a section: one disabled\n// row carrying the parse error. Silently showing nothing on a selection\n// the user clearly believes is JSON is the \"fake menu\" failure this\n// codebase kills on sight.\n//\n// Pure except for the two side-effect callbacks handed in by the hook.\n\nimport { detectJson } from \"@ai-matrx/kit/json-format\";\nimport { formatJsonText } from \"@ai-matrx/kit/json-format\";\nimport type {\n JsonDetection,\n JsonFenceMode,\n JsonFormatStyle,\n} from \"@ai-matrx/kit/json-format\";\n\nexport interface JsonMenuAction {\n id: string;\n label: string;\n /** Real before -> after size, e.g. \"13 lines -> 3 lines\". */\n hint?: string | undefined;\n disabled?: boolean | undefined;\n run: () => void | Promise<void>;\n}\n\nexport interface JsonMenuSection {\n /** The detection that produced this section (null when the text isn't JSON-ish). */\n detection: JsonDetection;\n /** True when the surface will rewrite text; false when actions copy instead. */\n writes: boolean;\n actions: JsonMenuAction[];\n}\n\nexport interface BuildJsonMenuActionsParams {\n /** The text the menu is acting on (selection, else resolved content). */\n text: string;\n /** True when the action should REWRITE the text rather than copy it. */\n canWrite: boolean;\n /** Rewrite the acted-on text with `next`. Only called when `canWrite`. */\n onReplace: (next: string) => void;\n /** Copy `next` to the clipboard. Used on read-only surfaces. */\n onCopy: (next: string) => void | Promise<void>;\n}\n\nfunction lineCount(text: string): number {\n let n = text === \"\" ? 0 : 1;\n for (let i = 0; i < text.length; i++) if (text[i] === \"\\n\") n++;\n return n;\n}\n\nfunction sizeHint(before: string, after: string): string {\n const b = lineCount(before);\n const a = lineCount(after);\n if (b !== a) {\n return `${b} line${b !== 1 ? \"s\" : \"\"} -> ${a} line${a !== 1 ? \"s\" : \"\"}`;\n }\n return `${before.length} -> ${after.length} chars`;\n}\n\n/**\n * The style that preserves the user's rough layout — used by actions whose\n * point is NOT re-layout (sort keys, fence toggling). Re-printing a hand-\n * formatted blob as something else because the user asked to sort its keys is\n * a change they did not request.\n */\nfunction shapePreservingStyle(detection: JsonDetection): JsonFormatStyle {\n return detection.payload.includes(\"\\n\") ? \"pretty\" : \"minify\";\n}\n\n/**\n * Build the JSON section for the given text, or `null` when the text is not\n * JSON-shaped at all (the overwhelmingly common case — the section simply\n * does not render).\n */\nexport function buildJsonMenuSection(\n params: BuildJsonMenuActionsParams,\n): JsonMenuSection | null {\n const { text, canWrite, onReplace, onCopy } = params;\n if (!text.trim()) return null;\n\n const detection = detectJson(text);\n if (!detection.looksLikeJson) return null;\n\n // JSON-shaped but broken: one honest, disabled row.\n if (!detection.ok) {\n return {\n detection,\n writes: false,\n actions: [\n {\n id: \"json-invalid\",\n label: \"Invalid JSON\",\n hint: detection.error,\n disabled: true,\n run: () => {},\n },\n ],\n };\n }\n\n const apply = (next: string) => {\n if (canWrite) onReplace(next);\n else void onCopy(next);\n };\n\n const verb = canWrite ? \"\" : \"Copy \";\n const actions: JsonMenuAction[] = [];\n\n const addFormat = (\n id: string,\n label: string,\n style: JsonFormatStyle,\n fence: JsonFenceMode = \"preserve\",\n sortKeys = false,\n ) => {\n const result = formatJsonText(text, { style, fence, sortKeys });\n if (!result.ok) return;\n // Copying an identical string is still useful; rewriting it is not.\n if (canWrite && !result.changed) return;\n actions.push({\n id,\n label,\n hint: result.changed ? sizeHint(text, result.text) : undefined,\n run: () => apply(result.text),\n });\n };\n\n addFormat(\"json-condense\", `${verb}Condense`, \"compact\");\n addFormat(\"json-minify\", `${verb}Minify (one line)`, \"minify\");\n addFormat(\"json-expand\", `${verb}Expand`, \"pretty\");\n addFormat(\n \"json-sort-keys\",\n `${verb}Sort keys A-Z`,\n shapePreservingStyle(detection),\n \"preserve\",\n true,\n );\n\n // Fence toggle — only the direction that applies.\n if (detection.fence) {\n addFormat(\n \"json-strip-fence\",\n `${verb}Remove code fence`,\n shapePreservingStyle(detection),\n \"strip\",\n );\n } else {\n addFormat(\n \"json-add-fence\",\n `${verb}Wrap in json code fence`,\n shapePreservingStyle(detection),\n \"add\",\n );\n }\n\n // An editable surface still benefits from a plain \"give me the one-liner on\n // the clipboard\" that does NOT touch the document.\n if (canWrite) {\n const minified = formatJsonText(text, { style: \"minify\", fence: \"strip\" });\n if (minified.ok) {\n actions.push({\n id: \"json-copy-minified\",\n label: \"Copy minified\",\n hint: sizeHint(text, minified.text),\n run: () => void onCopy(minified.text),\n });\n }\n }\n\n if (actions.length === 0) return null;\n return { detection, writes: canWrite, actions };\n}\n\n/** Short label for the submenu trigger, e.g. \"JSON · 13 lines\". */\nexport function jsonSectionLabel(section: JsonMenuSection): string {\n const { detection } = section;\n if (!detection.ok) return \"JSON (invalid)\";\n const n = detection.lineCount;\n const kind = detection.root === \"array\" ? \"array\" : \"object\";\n return `JSON ${kind} · ${n} line${n !== 1 ? \"s\" : \"\"}`;\n}\n","import type { AgentExecutionConfig } from \"@ai-matrx/chat/agents/types/agent-execution-config.types\";\n\n/**\n * Framework-owned launch defaults for agents listed in the managed \"Agents\"\n * context-menu section. Shortcuts do not use this config: their persisted\n * execution definitions remain authoritative.\n */\nexport const MANAGED_CONTEXT_MENU_AGENT_CONFIG = {\n displayMode: \"flexible-panel\",\n allowChat: true,\n showVariablePanel: true,\n} as const satisfies Pick<\n AgentExecutionConfig,\n \"displayMode\" | \"allowChat\" | \"showVariablePanel\"\n>;\n","// features/context-menu-v3/model/menu-model.ts\n//\n// The MENU MODEL — a declarative tree of everything the desktop menu can show,\n// built ONCE from the shared engine (`useContextMenuActions`) and the props.\n// The renderer never decides what exists; it only decides how the model is\n// ARRANGED (`layouts.ts`) and how dense it is drawn.\n//\n// Why a model: the menu had grown to ~30 top-level rows rendered by hand in\n// JSX. Every \"make it less overwhelming\" idea (fold the tail into submenus,\n// an icon strip for the universal verbs, a type-to-filter box) needs to walk\n// the same set of nodes. A model makes each of those a pure function over\n// one tree instead of a second renderer — and keeps the engine as the ONLY\n// place behavior lives.\n//\n// Nodes are closures over the engine's handlers, so a node is directly\n// actionable wherever a layout puts it (top level, inside a fold, in a\n// filtered flat list).\n\nimport { hasEditInPlaceTarget, openEditInPlaceFromLastInteraction } from \"@ai-matrx/rich-editor/in-place/EditInPlace\";\nimport { parseKeyCombo } from \"../utils/key-combo\";\nimport type React from \"react\";\nimport {\n StickyNote,\n CheckSquare,\n MessageSquare,\n Database,\n FolderOpen,\n Zap,\n Scissors,\n Pencil,\n Copy,\n Clipboard,\n Type,\n Undo2,\n Redo2,\n History,\n GitCompareArrows,\n Pin,\n Shield,\n Eye,\n EyeOff,\n Save,\n Trash2,\n Mic,\n Download,\n Replace,\n Search,\n Share2,\n Link,\n Link2,\n AtSign,\n Bug,\n Braces,\n Volume2,\n Headphones,\n AudioLines,\n RotateCcw,\n} from \"lucide-react\";\nimport type { IconComponentType } from \"@ai-matrx/icons\";\nimport { PLACEMENT_TYPES } from \"@ai-matrx/chat/agents/shortcuts/constants\";\nimport type { RichDocumentAction } from \"@ai-matrx/rich-content/rich-document/types\";\nimport {\n AI_SUBMENU_LABEL,\n buildMenuTree,\n withAiSlot,\n} from \"@ai-matrx/rich-content/rich-document/variants/shared/menuStructure\";\nimport type { AgentMenuCategoryGroup } from \"../hooks/useUnifiedAgentContextMenu\";\nimport { jsonSectionLabel } from \"../utils/json-menu-actions\";\nimport {\n type ContextMenuActions,\n getPlacementIcon,\n getPlacementLabel,\n resolveIcon,\n resolveRichActionView,\n PLACEMENT_COLOR,\n} from \"../hooks/useContextMenuActions\";\nimport type {\n MenuContentProps,\n PlacementKey,\n ExtraSectionAnchor,\n ContextMenuExtraItem,\n ContextMenuExtraSection,\n} from \"../types\";\nimport { AGENT_ICON } from \"@ai-matrx/icons/domain\";\n\n// ---------------------------------------------------------------------------\n// Node types (internal — the public surface contract stays `ContextMenuExtraItem`).\n// ---------------------------------------------------------------------------\n\ninterface MenuNodeBase {\n id: string;\n}\n\n/**\n * \"Edit\" for rendered content that edits in place (Arman, 2026-10-08: never a double-click — the\n * Edit icon or this right-click row opens it; the caret lands where he right-clicked).\n */\nfunction withEditInPlace(sections: MenuSection[]): MenuSection[] {\n if (!hasEditInPlaceTarget()) return sections;\n const edit: MenuItemNode = {\n kind: \"item\",\n id: \"edit-in-place\",\n label: \"Edit\",\n icon: Pencil,\n iconClassName: \"text-muted-foreground\",\n onSelect: () => void openEditInPlaceFromLastInteraction(),\n };\n return [{ id: \"edit-in-place\", group: \"editable\", nodes: [edit] }, ...sections];\n}\n\nexport interface MenuItemNode extends MenuNodeBase {\n kind: \"item\";\n label: string;\n icon?: IconComponentType | undefined;\n /** Tailwind classes for the icon (colour). */\n iconClassName?: string | undefined;\n /** Inline style for the icon (data-driven category colours). */\n iconStyle?: React.CSSProperties | undefined;\n /** Second muted line. */\n description?: string | undefined;\n /** Right-aligned muted hint (shortcut, count, …). */\n hint?: string | undefined;\n /** Native tooltip. */\n title?: string | undefined;\n disabled?: boolean | undefined;\n destructive?: boolean | undefined;\n /** Extra classes on the row (admin amber, …). */\n className?: string | undefined;\n /** Running it reloads this menu's own rows (Retry): the menu stays open (alchemy `keepsMenuOpen`). */\n keepsMenuOpen?: boolean | undefined;\n onSelect: () => void;\n}\n\nexport interface MenuSubmenuNode extends MenuNodeBase {\n kind: \"submenu\";\n label: string;\n icon?: IconComponentType | undefined;\n iconClassName?: string | undefined;\n iconStyle?: React.CSSProperties | undefined;\n disabled?: boolean | undefined;\n /** Spinner in the trigger while the data loads. */\n loading?: boolean | undefined;\n /** Rendered centred when `children` has no actionable node. */\n emptyLabel?: string | undefined;\n /** Tailwind width class for the panel. Default `w-60`. */\n width?: string | undefined;\n /** Layout hint: which placement this submenu is (for re-grouping). */\n placement?: string | undefined;\n children: MenuNode[];\n}\n\nexport interface MenuCheckboxNode extends MenuNodeBase {\n kind: \"checkbox\";\n label: string;\n icon?: IconComponentType | undefined;\n description?: string | undefined;\n hint?: string | undefined;\n checked: boolean;\n disabled?: boolean | undefined;\n onCheckedChange: (next: boolean) => void;\n}\n\nexport interface MenuLinkNode extends MenuNodeBase {\n kind: \"link\";\n label: string;\n icon?: IconComponentType | undefined;\n description?: string | undefined;\n hint?: string | undefined;\n href: string;\n target?: string | undefined;\n disabled?: boolean | undefined;\n}\n\nexport interface MenuLabelNode extends MenuNodeBase {\n kind: \"label\";\n label: string;\n}\n\nexport interface MenuSeparatorNode extends MenuNodeBase {\n kind: \"separator\";\n}\n\nexport type MenuNode =\n | MenuItemNode\n | MenuSubmenuNode\n | MenuCheckboxNode\n | MenuLinkNode\n | MenuLabelNode\n | MenuSeparatorNode;\n\n/** Actionable leaf kinds (what a filter can match and run). */\nexport type MenuLeafNode = MenuItemNode | MenuCheckboxNode | MenuLinkNode;\n\n/**\n * Coarse group a section belongs to. Layouts regroup by this, never by id\n * string-matching, so a surface's `extraSections` (\"surface\") and the\n * data-driven placements (\"ai\") stay distinguishable from the core verbs.\n */\nexport type MenuGroup =\n | \"clipboard\"\n | \"tools\"\n | \"history\"\n | \"share\"\n | \"document\"\n | \"surface\"\n | \"ai\"\n | \"quick\"\n | \"editable\"\n | \"admin\"\n | \"surface-info\";\n\nexport interface MenuSection {\n id: string;\n group: MenuGroup;\n /** Muted heading rendered above the section (surface sections). */\n label?: string | undefined;\n /** Icon for the fold a layout may collapse this section into (any className-drawn icon, like nodes). */\n icon?: IconComponentType | undefined;\n /** Classic rendering: no separator between this and the previous section. */\n joinPrevious?: boolean | undefined;\n /** The clicked target's section — see `ContextMenuExtraSection.primary`. */\n primary?: boolean | undefined;\n nodes: MenuNode[];\n}\n\nexport interface MenuHeader {\n label: \"Selected\" | \"Content\";\n text: string;\n}\n\nexport interface MenuModel {\n header: MenuHeader | null;\n /** Classic order — exactly the historical top-to-bottom arrangement. */\n sections: MenuSection[];\n /** Well-known nodes layouts pull out by role (never by label). */\n roles: MenuRoles;\n}\n\n/** The nodes a layout needs to address individually. */\nexport interface MenuRoles {\n copy: MenuItemNode;\n speak: MenuItemNode;\n /** ONE slot: \"Listen\" submenu — Summarize without playing / Summarize & listen. */\n listen: MenuSubmenuNode | null;\n copyAs: MenuSubmenuNode | null;\n json: MenuSubmenuNode | null;\n cut: MenuItemNode;\n paste: MenuItemNode;\n selectAll: MenuItemNode;\n find: MenuItemNode;\n /** \"Insert reference…\" (editable) / \"Copy reference…\" (read-only) — never absent. */\n insertReference: MenuItemNode;\n chat: MenuItemNode;\n undo: MenuItemNode;\n redo: MenuItemNode;\n viewHistory: MenuItemNode;\n compare: MenuSubmenuNode | null;\n exportMenu: MenuSubmenuNode | null;\n convert: MenuSubmenuNode | null;\n attach: MenuItemNode | null;\n /** \"Link a record…\" — present on EVERY menu that targets a record (guard: every-record-menu-links-a-record). */\n linkRecord: MenuItemNode | null;\n share: MenuItemNode | null;\n placements: MenuSubmenuNode[];\n /**\n * THE ONE REGISTRY TREE (RC-B6): the same tree, in the same order, as the\n * ⋯ menu, ProTextarea's \"…\" and the mobile sheet — with the agent-shortcut\n * libraries folded into its AI submenu. `null` when there is no content.\n */\n registry: MenuNode[] | null;\n quickActions: MenuSubmenuNode | null;\n save: MenuItemNode | null;\n del: MenuItemNode | null;\n admin: MenuSubmenuNode | null;\n /** The engine-built surface submenu section (location / context / agents / related). */\n surfaceInfo: MenuSection;\n /** Surface `extraSections`, by anchor, already converted to model nodes. */\n extras: Record<ExtraSectionAnchor, MenuSection[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Does the subtree contain anything the user can act on? */\nexport function hasActionable(nodes: MenuNode[]): boolean {\n return nodes.some((n) => {\n if (n.kind === \"separator\" || n.kind === \"label\") return false;\n if (n.kind === \"submenu\") return hasActionable(n.children);\n return true;\n });\n}\n\nfunction compactNodes(nodes: Array<MenuNode | null>): MenuNode[] {\n return nodes.filter((node) => node !== null);\n}\n\n// Surface ids are namespaced (`x:`) so they can never collide with a core\n// node id — notes' \"export\" item vs the core \"export\" submenu was a duplicate\n// React key the moment both rendered in one list.\nfunction fromExtraItem(item: ContextMenuExtraItem): MenuNode {\n const id = `x:${item.id}`;\n switch (item.kind) {\n case \"separator\":\n return { kind: \"separator\", id };\n case \"submenu\":\n return {\n kind: \"submenu\",\n id,\n label: item.label,\n icon: item.icon,\n disabled: item.disabled,\n children: item.children.map(fromExtraItem),\n };\n case \"checkbox\":\n return {\n kind: \"checkbox\",\n id,\n label: item.label,\n icon: item.icon,\n description: item.description,\n hint: item.hint,\n checked: item.checked,\n disabled: item.disabled,\n onCheckedChange: item.onCheckedChange,\n };\n case \"link\":\n return {\n kind: \"link\",\n id,\n label: item.label,\n icon: item.icon,\n description: item.description,\n hint: item.hint,\n href: item.href,\n target: item.target,\n disabled: item.disabled,\n };\n case \"item\":\n default:\n return {\n kind: \"item\",\n id,\n label: item.label,\n icon: item.icon,\n description: item.description,\n hint: item.hint,\n disabled: item.disabled,\n destructive: item.destructive,\n onSelect: item.onSelect,\n };\n }\n}\n\nfunction extrasByAnchor(\n extraSections: ContextMenuExtraSection[] | undefined,\n): Record<ExtraSectionAnchor, MenuSection[]> {\n const out: Record<ExtraSectionAnchor, MenuSection[]> = {\n \"after-clipboard\": [],\n \"after-compare\": [],\n \"after-placements\": [],\n };\n for (const s of extraSections ?? []) {\n const anchor = s.anchor ?? \"after-compare\";\n out[anchor].push({\n id: `extra:${s.id}`,\n group: \"surface\",\n label: s.label,\n icon: s.icon,\n primary: s.primary === true ? true : undefined,\n nodes: s.items.map(fromExtraItem),\n });\n }\n return out;\n}\n\n/**\n * Classic order, with the clicked target's section lifted to the very top.\n * Stable: everything else keeps the anchor order it was assembled in.\n */\nexport function liftPrimarySections(sections: MenuSection[]): MenuSection[] {\n const primary = sections.filter((s) => s.primary);\n if (primary.length === 0) return sections;\n return [...primary, ...sections.filter((s) => !s.primary)];\n}\n\nfunction richActionNode(\n action: RichDocumentAction,\n ctx: ContextMenuActions[\"richDocCtx\"],\n): MenuItemNode {\n const { label, disabled } = resolveRichActionView(action, ctx);\n return {\n kind: \"item\",\n id: `rich:${action.id}`,\n label,\n icon: action.icon,\n iconClassName: action.iconColor ?? undefined,\n disabled,\n onSelect: () => void action.run(ctx),\n };\n}\n\n/**\n * The registry tree as model nodes — `buildMenuTree` (the ONE structure every\n * host renders), with `aiExtras` (the agent-shortcut libraries) folded into\n * its AI submenu. Ids are the registry ids behind a `rich:` prefix, which is\n * what the one-tree guard compares against the ⋯ menu.\n */\nexport function registryTreeNodes(\n actions: RichDocumentAction[],\n ctx: ContextMenuActions[\"richDocCtx\"],\n aiExtras: MenuNode[],\n): MenuNode[] {\n const tree = buildMenuTree(actions, { aiSlot: aiExtras.length > 0 });\n const nodes: MenuNode[] = tree.topLevel.map((a) => richActionNode(a, ctx));\n for (const sub of withAiSlot(tree.submenus, aiExtras.length > 0)) {\n const children: MenuNode[] = sub.actions.map((a) => richActionNode(a, ctx));\n const isAi = sub.label === AI_SUBMENU_LABEL;\n if (isAi && aiExtras.length > 0) {\n if (children.length > 0) children.push({ kind: \"separator\", id: \"rich-ai:sep\" });\n children.push(...aiExtras);\n }\n nodes.push({\n kind: \"submenu\",\n id: `rich-sub:${sub.label.toLowerCase().replace(/[^a-z0-9]+/g, \"-\")}`,\n label: sub.label,\n icon: sub.icon,\n width: isAi ? \"w-64\" : undefined,\n children,\n });\n }\n nodes.push(...tree.extras.map((a) => richActionNode(a, ctx)));\n return nodes;\n}\n\nfunction categoryGroupNode(\n group: AgentMenuCategoryGroup,\n m: ContextMenuActions,\n): MenuSubmenuNode {\n const { category, items, children } = group;\n const children_: MenuNode[] = items.map((entry) => {\n const isDisabled = entry.entryType === \"agent_shortcut\" && !entry.agentId;\n const hint =\n // Advertised only when the shell's key listener can run it (key-combo.ts).\n entry.entryType === \"agent_shortcut\" &&\n entry.keyboardShortcut &&\n parseKeyCombo(entry.keyboardShortcut)\n ? entry.keyboardShortcut\n : isDisabled\n ? \"Not configured\"\n : undefined;\n return {\n kind: \"item\",\n id: `entry:${entry.id}`,\n label: entry.label,\n icon: resolveIcon(entry.iconName),\n // Phase 6.7: there is no \"legacy match\" row any more. Availability is\n // derived (requirement-gate.ts) — an item either QUALIFIES here or is\n // absent. Nothing renders red to advertise a backfill backlog.\n hint,\n disabled: isDisabled,\n onSelect: () => m.handleEntrySelect(entry),\n } satisfies MenuItemNode;\n });\n if (children.length > 0) {\n if (items.length > 0) children_.push({ kind: \"separator\", id: `${category.id}:sep` });\n for (const child of children) children_.push(categoryGroupNode(child, m));\n }\n return {\n kind: \"submenu\",\n id: `cat:${category.id}`,\n label: category.label,\n icon: resolveIcon(category.iconName),\n iconStyle: { color: category.color || \"currentColor\" },\n disabled: items.length === 0 && children.length === 0,\n emptyLabel: `No items in ${category.label}`,\n width: \"w-64\",\n children: children_,\n };\n}\n\nfunction placementNode(\n placementType: string,\n m: ContextMenuActions,\n): MenuSubmenuNode | null {\n const mode = m.resolvedPlacementMode[placementType as PlacementKey];\n if (mode === \"hide\") return null;\n const groups = m.grouped[placementType] || [];\n // A category with zero items still RENDERS (as a greyed submenu) — Arman\n // must see where new items will land the moment he creates the category.\n // The placement is only disabled when it has no categories at all.\n const hasCategories = groups.length > 0;\n const label = getPlacementLabel(placementType);\n const color = PLACEMENT_COLOR[placementType];\n if (!hasCategories && m.librariesError && mode !== \"disable\") {\n return failedLibraryNode(`placement:${placementType}`, label, getPlacementIcon(placementType), m, placementType);\n }\n return {\n kind: \"submenu\",\n id: `placement:${placementType}`,\n label,\n icon: getPlacementIcon(placementType),\n iconStyle: color ? { color } : undefined,\n disabled: mode === \"disable\" || !hasCategories,\n loading: m.loading && !hasCategories,\n emptyLabel: `No ${label}`,\n width: \"w-64\",\n placement: placementType,\n children: groups.map((g) => categoryGroupNode(g, m)),\n };\n}\n\n/**\n * A library whose fetch failed or missed the menu's deadline: the row stays\n * (never silently absent, never \"Loading…\" forever) and opens onto one\n * honest row that retries (page-pass 2026-09-27).\n */\nfunction failedLibraryNode(\n id: string,\n label: string,\n icon: MenuSubmenuNode[\"icon\"],\n m: ContextMenuActions,\n placement: string,\n): MenuSubmenuNode {\n return {\n kind: \"submenu\",\n id,\n label,\n icon,\n width: \"w-64\",\n placement,\n children: [\n {\n kind: \"item\",\n id: `${id}:retry`,\n label: \"Couldn't load. Retry\",\n icon: RotateCcw,\n keepsMenuOpen: true,\n onSelect: m.retryLibraries,\n },\n ],\n };\n}\n\nfunction boundAgentsNode(m: ContextMenuActions): MenuSubmenuNode | null {\n const mode = m.resolvedPlacementMode[\"bound-agent\"];\n if (mode === \"hide\") return null;\n const sections = m.boundAgentSections.filter((s) => s.agents.length > 0);\n const hasAgents = sections.length > 0;\n if (!hasAgents && m.boundAgentsError && !m.boundAgentsLoading && mode !== \"disable\") {\n return failedLibraryNode(\"placement:bound-agent\", \"Agents\", AGENT_ICON, m, \"bound-agent\");\n }\n const children: MenuNode[] = [];\n sections.forEach((section, idx) => {\n if (idx > 0) children.push({ kind: \"separator\", id: `agents:${section.key}:sep` });\n children.push({\n kind: \"label\",\n id: `agents:${section.key}:label`,\n label: section.label.toUpperCase(),\n });\n for (const agent of section.agents) {\n children.push({\n kind: \"item\",\n id: `agent:${section.key}:${agent.agentId}`,\n label: agent.name,\n icon: AGENT_ICON,\n iconClassName: \"text-indigo-500/80\",\n onSelect: () => void m.handleBoundAgentExecute(agent),\n });\n }\n });\n return {\n kind: \"submenu\",\n id: \"placement:bound-agent\",\n label: \"Agents\",\n icon: AGENT_ICON,\n iconClassName: \"text-indigo-500\",\n disabled: mode === \"disable\" || (!hasAgents && !m.boundAgentsLoading),\n loading: m.boundAgentsLoading,\n emptyLabel: m.boundAgentsLoading && !hasAgents ? \"Loading…\" : \"No agents available\",\n width: \"w-64\",\n placement: \"bound-agent\",\n children,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The builder\n// ---------------------------------------------------------------------------\n\nexport function buildMenuModel(\n m: ContextMenuActions,\n props: Pick<\n MenuContentProps,\n | \"extraSections\"\n | \"isEditable\"\n | \"onSave\"\n | \"onDelete\"\n | \"onUndo\"\n | \"onRedo\"\n | \"canUndo\"\n | \"canRedo\"\n | \"undoHint\"\n | \"redoHint\"\n | \"onViewHistory\"\n | \"hasHistory\"\n | \"selectedText\"\n | \"entity\"\n | \"getTextarea\"\n > &\n Partial<Pick<MenuContentProps, \"selectionRange\" | \"recordActionsOnly\">>,\n): MenuModel {\n const {\n extraSections,\n isEditable,\n onSave,\n onDelete,\n onUndo,\n onRedo,\n canUndo,\n canRedo,\n undoHint,\n redoHint,\n onViewHistory,\n hasHistory,\n selectedText,\n entity,\n selectionRange,\n getTextarea,\n recordActionsOnly = false,\n } = props;\n const { actionText, quickActions } = m;\n\n const header: MenuHeader | null =\n actionText.source === \"selection\"\n ? { label: \"Selected\", text: actionText.text }\n : actionText.source === \"content\"\n ? { label: \"Content\", text: actionText.text }\n : null;\n\n // ── Clipboard ───────────────────────────────────────────────────────────\n const copy: MenuItemNode = {\n kind: \"item\",\n id: \"copy\",\n label: \"Copy\",\n icon: Copy,\n iconClassName: \"text-emerald-500\",\n disabled: actionText.source === \"none\",\n onSelect: () => void m.handleCopy(),\n };\n const speak: MenuItemNode = {\n kind: \"item\",\n id: \"speak\",\n label: \"Speak\",\n icon: Volume2,\n iconClassName: \"text-sky-500\",\n disabled: actionText.source === \"none\",\n onSelect: m.handleSpeak,\n };\n // The two listening actions live under ONE \"Listen\" slot — every menu has\n // either content or a selection, so this pair is universal; a submenu keeps\n // it to a single row. Disabled (never hidden) when no text or no agent.\n const listenDisabled = actionText.source === \"none\" || !m.spokenSummaryAvailable;\n // With content, the registry owns every content verb (copy formats, listen,\n // compare, save, share & export) — the engine draws its own only without.\n const hasRegistry = m.registryActions.length > 0;\n const spokenSummary: MenuItemNode = {\n kind: \"item\",\n id: \"spoken-summary\",\n label: \"Summarize without playing\",\n icon: Headphones,\n iconClassName: \"text-violet-500\",\n disabled: listenDisabled,\n onSelect: m.handleSpokenSummary,\n };\n const spokenSummaryLive: MenuItemNode = {\n kind: \"item\",\n id: \"spoken-summary-live\",\n label: \"Summarize & listen\",\n icon: AudioLines,\n iconClassName: \"text-violet-500\",\n disabled: listenDisabled,\n onSelect: m.handleSpokenSummaryLive,\n };\n const listen: MenuSubmenuNode | null = hasRegistry ? null : {\n kind: \"submenu\",\n id: \"listen\",\n label: \"Listen\",\n icon: Headphones,\n iconClassName: \"text-violet-500\",\n disabled: listenDisabled,\n children: [spokenSummary, spokenSummaryLive],\n };\n const copyAs: MenuSubmenuNode | null =\n !hasRegistry && m.copyVariantActions.length > 0\n ? {\n kind: \"submenu\",\n id: \"copy-as\",\n label: \"Copy as\",\n icon: Copy,\n iconClassName: \"text-emerald-500\",\n children: m.copyVariantActions.map((a) => richActionNode(a, m.richDocCtx)),\n }\n : null;\n const json: MenuSubmenuNode | null = m.jsonSection\n ? {\n kind: \"submenu\",\n id: \"json\",\n label: jsonSectionLabel(m.jsonSection),\n icon: Braces,\n iconClassName: \"text-amber-500\",\n width: \"w-72\",\n children: m.jsonSection.actions.map((action) => ({\n kind: \"item\",\n id: `json:${action.id}`,\n label: action.label,\n hint: action.hint,\n disabled: action.disabled,\n onSelect: () => void action.run(),\n })),\n }\n : null;\n const cut: MenuItemNode = {\n kind: \"item\",\n id: \"cut\",\n label: \"Cut\",\n icon: Scissors,\n iconClassName: \"text-emerald-500\",\n disabled: !isEditable || !selectedText,\n onSelect: () => void m.handleCut(),\n };\n const paste: MenuItemNode = {\n kind: \"item\",\n id: \"paste\",\n label: \"Paste\",\n icon: Clipboard,\n iconClassName: \"text-emerald-500\",\n disabled: !isEditable,\n onSelect: () => void m.handlePaste(),\n };\n const selectAll: MenuItemNode = {\n kind: \"item\",\n id: \"select-all\",\n label: \"Select All\",\n icon: Type,\n iconClassName: \"text-muted-foreground\",\n // Select All acts on a captured selection's container, or an editable\n // surface's own field. With neither (right-click on a table row or on\n // read-only content without selecting) it would do nothing — a dead row,\n // so it is absent (R1 b), not offered.\n disabled: !selectionRange && !(isEditable && getTextarea),\n onSelect: m.handleSelectAll,\n };\n const find: MenuItemNode = {\n kind: \"item\",\n id: \"find\",\n label: \"Find & Replace\",\n icon: Search,\n iconClassName: \"text-muted-foreground\",\n onSelect: m.handleFind,\n };\n const insertReference: MenuItemNode = {\n kind: \"item\",\n id: \"insert-reference\",\n label: isEditable ? \"Insert reference…\" : \"Copy reference…\",\n icon: AtSign,\n iconClassName: \"text-primary\",\n onSelect: m.handleInsertReference,\n };\n\n // ── Tools ───────────────────────────────────────────────────────────────\n const chat: MenuItemNode = {\n kind: \"item\",\n id: \"chat\",\n label: \"Chat\",\n icon: MessageSquare,\n iconClassName: \"text-primary\",\n onSelect: () => quickActions.openChatWindow(),\n };\n\n // ── History ─────────────────────────────────────────────────────────────\n const undo: MenuItemNode = {\n kind: \"item\",\n id: \"undo\",\n label: \"Undo\",\n icon: Undo2,\n iconClassName: \"text-sky-500\",\n hint: undoHint,\n disabled: onUndo ? !canUndo : !m.canNativeUndo,\n onSelect: m.handleUndo,\n };\n const redo: MenuItemNode = {\n kind: \"item\",\n id: \"redo\",\n label: \"Redo\",\n icon: Redo2,\n iconClassName: \"text-sky-500\",\n hint: redoHint,\n disabled: onRedo ? !canRedo : !m.canNativeUndo,\n onSelect: m.handleRedo,\n };\n const viewHistory: MenuItemNode = {\n kind: \"item\",\n id: \"view-history\",\n label: \"View History\",\n icon: History,\n iconClassName: \"text-violet-500\",\n disabled: !onViewHistory || !hasHistory,\n onSelect: () => onViewHistory?.(),\n };\n const compare: MenuSubmenuNode | null = hasRegistry ? null : {\n kind: \"submenu\",\n id: \"compare\",\n label: \"Compare\",\n icon: GitCompareArrows,\n iconClassName: \"text-amber-500\",\n children: [\n {\n kind: \"item\",\n id: \"compare:clipboard\",\n label: \"Compare with clipboard\",\n icon: Clipboard,\n onSelect: () => void m.handleCompareClipboard(),\n },\n {\n kind: \"item\",\n id: \"compare:set-base\",\n label: \"Set as compare base\",\n icon: Pin,\n description:\n actionText.source === \"selection\" ? \"Use selection\" : \"Use content\",\n onSelect: m.handleSetCompareBase,\n },\n {\n kind: \"item\",\n id: \"compare:with-base\",\n label: \"Compare with base\",\n icon: GitCompareArrows,\n description: m.hasCompareBase ? undefined : \"No base set yet\",\n disabled: !m.hasCompareBase,\n onSelect: () => void m.handleCompareWithBase(),\n },\n ],\n };\n\n // ── Document ────────────────────────────────────────────────────────────\n const exportMenu: MenuSubmenuNode | null =\n !hasRegistry && m.exportActions.length > 0\n ? {\n kind: \"submenu\",\n id: \"export\",\n label: \"Export\",\n icon: Download,\n iconClassName: \"text-amber-500\",\n children: m.exportActions.map((a) => richActionNode(a, m.richDocCtx)),\n }\n : null;\n const convert: MenuSubmenuNode | null =\n !hasRegistry && m.convertActions.length > 0\n ? {\n kind: \"submenu\",\n id: \"convert\",\n label: \"Convert\",\n icon: Replace,\n iconClassName: \"text-violet-500\",\n children: m.convertActions.map((a) => richActionNode(a, m.richDocCtx)),\n }\n : null;\n const attach: MenuItemNode | null = entity\n ? {\n kind: \"item\",\n id: \"attach\",\n label: \"Attach To\",\n icon: Link2,\n iconClassName: \"text-sky-500\",\n onSelect: m.handleAttach,\n }\n : null;\n // THE OBJECT VERB \"Link a record…\" — bound once here, so every menu that targets a record\n // (an `entity` prop, a per-row entity, a `data-entity-*` sniff, or a record-menu-registry row)\n // inherits it; no module adds its own. Opens the ONE picker (LinkRecordOverlay).\n const linkRecord: MenuItemNode | null = entity\n ? {\n kind: \"item\",\n id: \"link-record\",\n label: \"Link a record…\",\n icon: Link,\n iconClassName: \"text-sky-500\",\n onSelect: m.handleLinkRecord,\n }\n : null;\n const share: MenuItemNode | null = entity?.resourceType\n ? {\n kind: \"item\",\n id: \"share\",\n label: \"Share\",\n icon: Share2,\n iconClassName: \"text-emerald-500\",\n onSelect: m.handleShare,\n }\n : null;\n\n // ── Placements (data-driven) ────────────────────────────────────────────\n const libraryNodes = [\n placementNode(PLACEMENT_TYPES.AI_ACTION, m),\n boundAgentsNode(m),\n placementNode(PLACEMENT_TYPES.CONTENT_BLOCK, m),\n placementNode(PLACEMENT_TYPES.USER_TOOL, m),\n placementNode(PLACEMENT_TYPES.ORGANIZATION_TOOL, m),\n ].filter((n): n is MenuSubmenuNode => n !== null);\n // ONE AI family: with a registry, the libraries live INSIDE its AI submenu\n // (every shortcut, agent, block and item kept — only the parallel top-level\n // family is gone). Without content they stay where they always were.\n const registry: MenuNode[] | null = hasRegistry\n ? registryTreeNodes(m.registryActions, m.richDocCtx, libraryNodes)\n : null;\n const placements = hasRegistry ? [] : libraryNodes;\n\n // ── Quick actions ───────────────────────────────────────────────────────\n const quickMode = m.resolvedPlacementMode[\"quick-action\"];\n const quick: MenuSubmenuNode | null =\n quickMode === \"hide\"\n ? null\n : {\n kind: \"submenu\",\n id: \"quick-actions\",\n label: \"Quick Actions\",\n icon: Zap,\n iconClassName: \"text-pink-500\",\n disabled: quickMode === \"disable\",\n width: \"w-56\",\n children: [\n { kind: \"item\", id: \"qa:notes\", label: \"Notes\", icon: StickyNote, onSelect: () => quickActions.openQuickNotes() },\n { kind: \"item\", id: \"qa:tasks\", label: \"Tasks\", icon: CheckSquare, onSelect: () => quickActions.openQuickTasks() },\n { kind: \"item\", id: \"qa:chat\", label: \"Chat\", icon: MessageSquare, onSelect: () => quickActions.openQuickChat() },\n { kind: \"item\", id: \"qa:data\", label: \"Data\", icon: Database, onSelect: () => quickActions.openQuickData() },\n { kind: \"item\", id: \"qa:files\", label: \"Files\", icon: FolderOpen, onSelect: () => quickActions.openQuickFiles() },\n { kind: \"item\", id: \"qa:voice\", label: \"Voice Input\", icon: Mic, onSelect: () => quickActions.openVoicePad() },\n ],\n };\n\n // ── Editable ────────────────────────────────────────────────────────────\n const save: MenuItemNode | null =\n isEditable && onSave\n ? {\n kind: \"item\",\n id: \"save\",\n label: \"Save\",\n icon: Save,\n iconClassName: \"text-emerald-500\",\n onSelect: () => onSave(),\n }\n : null;\n const del: MenuItemNode | null =\n isEditable && onDelete\n ? {\n kind: \"item\",\n id: \"delete\",\n label: \"Delete\",\n icon: Trash2,\n destructive: true,\n onSelect: () => void m.handleDelete(),\n }\n : null;\n\n // ── Admin ───────────────────────────────────────────────────────────────\n const admin: MenuSubmenuNode | null = m.isAdmin\n ? {\n kind: \"submenu\",\n id: \"admin\",\n label: \"Admin Tools\",\n icon: Shield,\n iconClassName: \"text-rose-500\",\n width: \"w-56\",\n children: [\n {\n kind: \"item\",\n id: \"admin:debug\",\n label: `${m.isDebugMode ? \"Disable\" : \"Enable\"} Debug Mode`,\n icon: m.isDebugMode ? EyeOff : Eye,\n iconClassName: m.isDebugMode ? \"text-amber-600 dark:text-amber-400\" : undefined,\n onSelect: m.handleToggleDebugMode,\n },\n {\n kind: \"item\",\n id: \"admin:values\",\n label: \"Context Values\",\n icon: Bug,\n className: \"text-amber-600 dark:text-amber-400\",\n onSelect: m.handleInspectValues,\n },\n ...(m.isDebugMode\n ? ([\n {\n kind: \"item\",\n id: \"admin:state\",\n label: \"Redux State\",\n icon: Database,\n className: \"text-amber-600 dark:text-amber-400\",\n onSelect: m.handleInspectState,\n },\n ] satisfies MenuNode[])\n : []),\n { kind: \"separator\", id: \"admin:sep\" },\n {\n kind: \"item\",\n id: \"admin:indicator\",\n label: `${m.isAdminIndicatorOpen ? \"Hide\" : \"Show\"} Admin Indicator`,\n icon: m.isAdminIndicatorOpen ? Eye : EyeOff,\n iconClassName: m.isAdminIndicatorOpen ? \"text-green-600 dark:text-green-400\" : undefined,\n onSelect: m.handleToggleAdminIndicator,\n },\n ],\n }\n : null;\n\n const extras = extrasByAnchor(extraSections);\n // The surface submenu (engine-built, shared with mobile) — always LAST, where\n // the version footer used to sit.\n const surfaceInfo: MenuSection = {\n id: \"surface-info\",\n group: \"surface-info\",\n nodes: m.surfaceSection.items.map(fromExtraItem),\n };\n\n // ── Record actions only (a list row, a folder) ──────────────────────────\n // A row is a thing you act ON, not text you are in: the editor's items\n // (Select All, Find, Cut/Paste, Undo/Redo/History, Insert/Copy reference,\n // Speak, Listen, Compare, Chat, Quick Actions) are absent. The agent\n // libraries stay only where there is content for them to act on (they ride\n // the registry's AI submenu); a folder has none. (page-pass /notes, 2026-09-28)\n if (recordActionsOnly) {\n const recordSections: MenuSection[] = [];\n // A record with no content source (a folder: only its NAME is on hand) has\n // no document to copy, export or hand an agent — only its own rows.\n const recordHasDocument = hasRegistry && m.richDocCtx?.source?.type !== \"raw\";\n const clipboardRecord = compactNodes([recordHasDocument ? copy : null, recordHasDocument ? copyAs : null, recordHasDocument ? json : null]);\n if (clipboardRecord.length > 0) {\n recordSections.push({ id: \"clipboard\", group: \"clipboard\", nodes: clipboardRecord });\n }\n if (registry && recordHasDocument) recordSections.push({ id: \"registry\", group: \"document\", nodes: registry });\n recordSections.push(...extras[\"after-clipboard\"]);\n if (recordHasDocument && (exportMenu || convert)) {\n recordSections.push({ id: \"document-out\", group: \"document\", nodes: compactNodes([exportMenu, convert]) });\n }\n if (attach || linkRecord || share) {\n recordSections.push({ id: \"share\", group: \"share\", nodes: compactNodes([attach, linkRecord, share]) });\n }\n recordSections.push(...extras[\"after-compare\"]);\n recordSections.push(...extras[\"after-placements\"]);\n if (save || del) recordSections.push({ id: \"editable\", group: \"editable\", nodes: compactNodes([save, del]) });\n if (admin) recordSections.push({ id: \"admin\", group: \"admin\", nodes: [admin] });\n recordSections.push(surfaceInfo);\n return {\n header,\n sections: withEditInPlace(liftPrimarySections(recordSections)),\n roles: {\n copy, speak, listen: null, copyAs, json, cut, paste, selectAll, find, insertReference, chat,\n undo, redo, viewHistory, compare: null, exportMenu, convert, attach, linkRecord, share,\n placements: [], registry, quickActions: null, save, del, admin, extras, surfaceInfo,\n },\n };\n }\n\n // ── Classic order (the historical arrangement, separator for separator) ──\n const sections: MenuSection[] = [];\n sections.push({\n id: \"clipboard\",\n group: \"clipboard\",\n nodes: compactNodes([\n copy,\n speak,\n listen,\n copyAs,\n json,\n cut,\n paste,\n selectAll,\n find,\n insertReference,\n ]),\n });\n if (registry) sections.push({ id: \"registry\", group: \"document\", nodes: registry });\n sections.push(...extras[\"after-clipboard\"]);\n sections.push({ id: \"tools\", group: \"tools\", nodes: [chat] });\n // THE SECTION IS ITS TITLE (page-pass 2026-09-27, /applets/manage/[id]/run):\n // \"History\" held Compare, Export, Convert, Attach To and Share. History keeps\n // what is history; the rest sit in sections of their own kind.\n sections.push({\n id: \"history\",\n group: \"history\",\n nodes: compactNodes([undo, redo, viewHistory]),\n });\n if (compare) sections.push({ id: \"compare\", group: \"tools\", nodes: [compare] });\n if (exportMenu || convert) {\n sections.push({ id: \"document-out\", group: \"document\", nodes: compactNodes([exportMenu, convert]) });\n }\n if (attach || linkRecord || share) {\n sections.push({ id: \"share\", group: \"share\", nodes: compactNodes([attach, linkRecord, share]) });\n }\n sections.push(...extras[\"after-compare\"]);\n if (placements.length > 0) sections.push({ id: \"placements\", group: \"ai\", nodes: placements });\n sections.push(...extras[\"after-placements\"]);\n if (quick) {\n sections.push({\n id: \"quick\",\n group: \"quick\",\n joinPrevious: extras[\"after-placements\"].length === 0,\n nodes: [quick],\n });\n }\n if (save || del) {\n sections.push({\n id: \"editable\",\n group: \"editable\",\n nodes: compactNodes([save, del]),\n });\n }\n if (admin) sections.push({ id: \"admin\", group: \"admin\", nodes: [admin] });\n sections.push(surfaceInfo);\n\n return {\n header,\n sections: withEditInPlace(liftPrimarySections(sections)),\n roles: {\n copy,\n speak,\n listen,\n copyAs,\n json,\n cut,\n paste,\n selectAll,\n find,\n insertReference,\n chat,\n undo,\n redo,\n viewHistory,\n compare,\n exportMenu,\n convert,\n attach,\n linkRecord,\n share,\n placements,\n registry,\n quickActions: quick,\n save,\n del,\n admin,\n extras,\n surfaceInfo,\n },\n };\n}\n","// features/context-menu-v3/utils/key-combo.ts\n//\n// THE ONE READER OF A SHORTCUT'S ADVERTISED KEY COMBO (\"Alt+Shift+S\").\n//\n// The menu prints `keyboard_shortcut` beside an item; the shell's key listener\n// runs it. Both read the combo HERE, so an advertised combo either runs or is\n// not shown (`parseKeyCombo` returns null → the menu draws no hint).\n//\n// MATCH ON `code`, NEVER `key`: on macOS Option rewrites the character —\n// Alt+Shift+S arrives as `key: \"Í\"`, `code: \"KeyS\"` (2026-10-02 → 10-05, the\n// advertised combo did nothing on /notes).\n\nexport interface KeyCombo {\n alt: boolean;\n shift: boolean;\n ctrl: boolean;\n meta: boolean;\n /** `KeyboardEvent.code` for letters/digits (\"KeyS\", \"Digit1\"), else null. */\n code: string | null;\n /** Lowercased `KeyboardEvent.key` for named keys (\"enter\", \"/\"), else null. */\n key: string | null;\n}\n\nconst MOD_ALIASES: Record<string, keyof Pick<KeyCombo, \"alt\" | \"shift\" | \"ctrl\" | \"meta\"> | \"mod\"> = {\n alt: \"alt\",\n option: \"alt\",\n opt: \"alt\",\n \"⌥\": \"alt\",\n shift: \"shift\",\n \"⇧\": \"shift\",\n ctrl: \"ctrl\",\n control: \"ctrl\",\n \"⌃\": \"ctrl\",\n cmd: \"meta\",\n command: \"meta\",\n meta: \"meta\",\n \"⌘\": \"meta\",\n win: \"meta\",\n mod: \"mod\",\n};\n\nfunction isApplePlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent || \"\");\n}\n\n/**\n * Parse an advertised combo. Null when it cannot be a combo this listener can\n * honour: no non-Shift modifier (plain typing), or no key.\n */\nexport function parseKeyCombo(raw: string | null | undefined): KeyCombo | null {\n if (!raw) return null;\n const parts = raw\n .split(/\\s*\\+\\s*/)\n .map((p) => p.trim())\n .filter(Boolean);\n if (parts.length < 2) return null;\n const combo: KeyCombo = { alt: false, shift: false, ctrl: false, meta: false, code: null, key: null };\n const last = parts[parts.length - 1]!;\n for (const part of parts.slice(0, -1)) {\n const mod = MOD_ALIASES[part.toLowerCase()];\n if (!mod) return null;\n if (mod === \"mod\") combo[isApplePlatform() ? \"meta\" : \"ctrl\"] = true;\n else combo[mod] = true;\n }\n if (/^[a-z]$/i.test(last)) combo.code = `Key${last.toUpperCase()}`;\n else if (/^[0-9]$/.test(last)) combo.code = `Digit${last}`;\n else combo.key = last.toLowerCase();\n if (!combo.alt && !combo.ctrl && !combo.meta) return null;\n // ⌘/Ctrl+Shift+K opens the palette on every surface (ContextMenuV3); a\n // shortcut cannot take the platform's key, so it is not advertised either.\n if ((combo.ctrl || combo.meta) && combo.shift && !combo.alt && combo.code === \"KeyK\") return null;\n return combo;\n}\n\ntype KeyEventLike = Pick<KeyboardEvent, \"altKey\" | \"shiftKey\" | \"ctrlKey\" | \"metaKey\" | \"code\" | \"key\">;\n\nexport function eventMatchesCombo(e: KeyEventLike, combo: KeyCombo): boolean {\n if (!!e.altKey !== combo.alt || !!e.shiftKey !== combo.shift) return false;\n if (!!e.ctrlKey !== combo.ctrl || !!e.metaKey !== combo.meta) return false;\n if (combo.code) return e.code === combo.code;\n return !!combo.key && (e.key ?? \"\").toLowerCase() === combo.key;\n}\n\n/** First item whose advertised combo this key event presses. */\nexport function findComboMatch<T>(\n e: KeyEventLike,\n items: readonly T[],\n comboOf: (item: T) => string | null | undefined,\n): T | null {\n if (!e.altKey && !e.ctrlKey && !e.metaKey) return null;\n for (const item of items) {\n const combo = parseKeyCombo(comboOf(item));\n if (combo && eventMatchesCombo(e, combo)) return item;\n }\n return null;\n}\n","// features/context-menu-v3/alchemy-provider.ts\n//\n// The context menu's actions as a provider of the ONE Alchemy action registry\n// (Matrx Alchemy ALC-15 S3, LIST A2). The engine hook (`useContextMenuActions`)\n// still decides WHAT exists — clipboard verbs, selection-aware listening, the\n// agent libraries, history, surface sections, the surface submenu — and\n// `buildMenuModel` still binds every handler. This file turns that model into\n// package `Action`s; the package's model, layouts and renderers draw it (bar,\n// ⋯, right-click, bottom sheet, palette) — the v3 renderers and layouts are\n// gone.\n//\n// • The rich-document registry tree inside the model is NOT re-emitted: the\n// rich-document provider contributes those actions from the same click\n// target (composite host). Only the agent libraries folded into its AI\n// submenu come from here — inline in the \"ai\" group, under no heading,\n// like the rich-document AI rows (the group has no approved name).\n// • A surface section's label (\"Cell\", \"Row · Widget A\") names the clicked\n// thing: it is declared `kind: \"target\"`, never a group heading.\n// • R1: a disabled universal verb (copy, cut, paste, undo, redo, find)\n// greys WITH its sentence; every other unavailable row is absent.\n// • Headings are only names the classic menu already shows (\"History\",\n// a surface section's own label, the surface's display label).\n\nimport { fieldPreview } from \"./utils/field-menu-header\";\nimport type { Action, ActionCategory, ActionProvider, ClickTarget, Eligibility } from \"@ai-matrx/alchemy/actions\";\nimport { registerAlchemyIcon } from \"@ai-matrx/rich-content/utils/alchemy-icon-keys\";\nimport { stripTurnTrust } from \"@ai-matrx/chat/agents/conversation-export/turn-trust-strip\";\nimport { markdownToPlainText } from \"@ai-matrx/content-ir/source\";\nimport type { MenuModel, MenuNode, MenuSection } from \"./model/menu-model\";\n\nexport interface ContextMenuTargetHost {\n kind: \"context-menu\";\n /** The menu instance (one open menu = one provider registration). */\n instanceId: string;\n}\n\n/** Composite host: a right-click target can carry both providers' halves. */\nexport interface CompositeTargetHost {\n contextMenu?: ContextMenuTargetHost | undefined;\n richDocument?: unknown | undefined;\n}\n\nexport function contextMenuHostOf(target: ClickTarget): ContextMenuTargetHost | null {\n const host = target.host as (CompositeTargetHost & Partial<ContextMenuTargetHost>) | undefined;\n if (!host) return null;\n if (host.kind === \"context-menu\" && typeof host.instanceId === \"string\") {\n return host as ContextMenuTargetHost;\n }\n return host.contextMenu ?? null;\n}\n\nconst VERBS: Record<string, { verb: \"copy\" | \"cut\" | \"paste\" | \"undo\" | \"redo\" | \"find\"; sentence: string }> = {\n copy: { verb: \"copy\", sentence: \"Select text, or right-click content, to copy it.\" },\n cut: { verb: \"cut\", sentence: \"Cut works on selected text in an editable field.\" },\n paste: { verb: \"paste\", sentence: \"Paste works in an editable field.\" },\n undo: { verb: \"undo\", sentence: \"Nothing to undo here.\" },\n redo: { verb: \"redo\", sentence: \"Nothing to redo here.\" },\n find: { verb: \"find\", sentence: \"Find works where there is text.\" },\n};\n\n/**\n * Verbs that only mean something where the person can edit: on a read-only\n * target (a table row, rendered content) an unavailable one is ABSENT rather\n * than greyed — Cut / Paste / Undo on a row is noise, and it pushes the row's\n * own section down (page-pass 2026-09-27). Where the target is editable they\n * grey with their sentence as before (R1 c).\n */\nconst EDIT_ONLY_VERBS = new Set([\"cut\", \"paste\", \"undo\", \"redo\"]);\n\n/** v3 section group → the action category that lands in the same package group. */\nconst CATEGORY_OF: Record<MenuSection[\"group\"], ActionCategory> = {\n clipboard: \"clipboard\",\n tools: \"app\",\n history: \"history\",\n share: \"share\",\n document: \"save\",\n surface: \"edit\",\n ai: \"ai\",\n quick: \"feedback\",\n editable: \"edit\",\n admin: \"admin\",\n \"surface-info\": \"surface-info\",\n};\n\n/** Clipboard-section rows that are not universal verbs sit with in-place tools. */\nconst NON_VERB_CLIPBOARD: Record<string, ActionCategory> = {\n \"select-all\": \"edit\",\n \"insert-reference\": \"edit\",\n};\n\nexport interface ProviderOptions {\n /**\n * Resolves with the NEXT model the engine hook builds. A library still\n * loading (the first agent fetch) waits on it instead of vanishing.\n */\n nextModel?: (() => Promise<MenuModel>) | undefined;\n /**\n * Whether THIS menu instance edits its surface (`isEditable`). A read-only\n * wrapper over rich content still gets a writable rich-document target\n * (actions may write back to the SOURCE), so `target.readOnly` alone cannot\n * say \"the person cannot type here\" — this can (live 2026-09-27: a table\n * row's menu still drew Cut / Paste / Undo / Redo).\n */\n editable?: boolean | undefined;\n}\n\n/** Rows that INSERT content into the surface: absent on a read-only source. */\nconst INSERTS_CONTENT = new Set([\"placement:content-block\"]);\n\nfunction findNodeById(nodes: readonly MenuNode[], id: string): MenuNode | null {\n for (const n of nodes) {\n if (n.id === id) return n;\n if (n.kind === \"submenu\") {\n const hit = findNodeById(n.children, id);\n if (hit) return hit;\n }\n }\n return null;\n}\n\ninterface Placement {\n category: ActionCategory;\n section?: Action[\"section\"] | undefined;\n order: number;\n}\n\nconst available: Eligibility = { status: \"available\" };\nconst absent: Eligibility = { status: \"absent\" };\n\nfunction icon(node: { icon?: unknown }): string | undefined {\n return node.icon ? registerAlchemyIcon(node.icon) : undefined;\n}\n\n/** The row starts a new group: the menu draws a divider above it (alchemy `Action.startsGroup`). */\nfunction startGroup(a: Action): void {\n Object.assign(a, { startsGroup: true });\n}\n\n/** One v3 node → one package action (submenus expand to their rows). */\nfunction toAction(node: MenuNode, place: Placement, instanceId: string, opts: ProviderOptions = {}): Action | null {\n if (node.kind === \"separator\" || node.kind === \"label\") return null;\n const id = `cm:${node.id}`;\n const own = (t: ClickTarget) => contextMenuHostOf(t)?.instanceId === instanceId;\n const base = {\n id,\n label: node.label,\n category: place.category,\n order: place.order,\n ...(place.section ? { section: place.section } : {}),\n ...((key) => (key ? { icon: key } : {}))(icon(node)),\n ...(\"iconClassName\" in node && node.iconClassName ? { iconTone: node.iconClassName } : {}),\n ...(\"description\" in node && node.description ? { description: node.description } : {}),\n ...(\"hint\" in node && node.hint ? { hint: node.hint } : {}),\n };\n if (node.kind === \"submenu\") {\n const inserts = INSERTS_CONTENT.has(node.id);\n return {\n ...base,\n // Still loading at the source: every layout shows \"Loading…\" on the row.\n pending: () => Boolean(node.loading),\n eligible: (t) => {\n if (!own(t)) return absent;\n if (inserts && (t.readOnly || opts.editable === false)) return absent;\n // Still loading: SHOWN (as loading), never silently absent (round 2).\n if (node.loading) return available;\n return !node.disabled && hasRows(node.children) ? available : absent;\n },\n expand: async (t) => {\n let current: MenuNode = node;\n // Wait for the library's first load (bounded), then read its rows\n // from the model that has them.\n for (let i = 0; current.kind === \"submenu\" && current.loading && opts.nextModel && i < 20; i++) {\n const next = await opts.nextModel();\n const found = next.sections.map((s) => findNodeById(s.nodes, node.id)).find(Boolean);\n if (!found) return [];\n current = found;\n }\n if (current.kind !== \"submenu\") return [];\n void t;\n // THE SUBMENU KEEPS ITS GROUPS (DATA-V2-BASICS-2): each run of rows between the source's\n // separators is one section, and the menu draws a divider where the section changes\n // (alchemy withGroupDividers) — \"Delete row…\" in its own group, never beside Highlight.\n const rows: Action[] = [];\n let startsNext = false;\n for (const child of current.children) {\n if (child.kind === \"separator\") {\n startsNext = rows.length > 0;\n continue;\n }\n // An empty category (or a row that cannot run) is ABSENT (R1) —\n // never a \"No items in …\" panel, never a dead row.\n if (unusable(child)) continue;\n const a = toAction(child, { ...place, section: undefined, order: rows.length }, instanceId, opts);\n if (!a) continue;\n if (startsNext) startGroup(a);\n startsNext = false;\n rows.push(a);\n }\n return rows;\n },\n run: () => undefined,\n };\n }\n if (node.kind === \"link\") {\n return { ...base, href: node.href, eligible: (t) => (own(t) && !node.disabled ? available : absent), run: () => undefined };\n }\n if (node.kind === \"checkbox\") {\n return {\n ...base,\n toggle: true,\n pressed: () => node.checked,\n eligible: (t) => (own(t) && !node.disabled ? available : absent),\n run: () => node.onCheckedChange(!node.checked),\n };\n }\n const verb = place.category === \"clipboard\" ? VERBS[node.id] : undefined;\n return {\n ...base,\n ...(verb ? { verb: verb.verb } : {}),\n ...(node.destructive ? { destructive: true } : {}),\n ...(node.keepsMenuOpen ? { keepsMenuOpen: true } : {}),\n eligible: (t) => {\n if (!own(t)) return absent;\n if (!node.disabled) return available;\n if (verb && (t.readOnly || opts.editable === false) && EDIT_ONLY_VERBS.has(verb.verb)) return absent;\n // R1 (c): a universal verb greys, and it says why.\n if (verb) return { status: \"unavailable-verb\", verb: verb.verb, sentence: verb.sentence };\n // ABSENT OR HONEST (admin pass 2026-09-27): a row that is off FOR A REASON it states\n // (\"Manifested surfaces are managed in code\") stays, greyed, with the reason. With no\n // reason it is absent.\n const reason = \"description\" in node && typeof node.description === \"string\" ? node.description.trim() : \"\";\n return reason ? { status: \"unavailable\", sentence: reason } : absent;\n },\n run: () => node.onSelect(),\n };\n}\n\n/** A row that can never run here: a disabled leaf, or a submenu with nothing to open. */\nfunction unusable(node: MenuNode): boolean {\n if (node.kind === \"separator\" || node.kind === \"label\") return false;\n if (node.kind === \"submenu\") return !node.loading && (Boolean(node.disabled) || !hasRows(node.children));\n // A disabled row that says why stays (greyed, with its reason); one with no reason cannot run.\n if (!(\"disabled\" in node) || !node.disabled) return false;\n return !(\"description\" in node && typeof node.description === \"string\" && node.description.trim());\n}\n\nfunction hasRows(nodes: MenuNode[]): boolean {\n return nodes.some((n) => (n.kind === \"submenu\" ? n.loading || hasRows(n.children) : n.kind !== \"separator\" && n.kind !== \"label\"));\n}\n\n/**\n * The model → the actions this menu instance contributes. Rich-document rows\n * (`rich:` leaves) are skipped: the rich-document provider supplies them.\n */\nexport function contextMenuActionsFromModel(model: MenuModel, instanceId: string, opts: ProviderOptions = {}): Action[] {\n const out: Action[] = [];\n model.sections.forEach((section, sectionIndex) => {\n const base = sectionIndex * 100;\n if (section.id === \"registry\") {\n // Only the agent libraries folded into the registry's AI submenu are ours.\n section.nodes.forEach((node, i) => {\n if (node.kind !== \"submenu\" || !node.id.startsWith(\"rich-sub:\")) return;\n const libraries = node.children.filter((c) => !c.id.startsWith(\"rich\") && c.kind !== \"separator\");\n libraries.forEach((lib, j) => {\n const a = toAction(\n lib,\n {\n category: \"ai\",\n order: 5_000 + i * 50 + j,\n },\n instanceId,\n opts,\n );\n if (a) out.push(a);\n });\n });\n return;\n }\n // A section with no declared label has no heading — never fabricate one\n // (not even \"\"): the package's own contract is \"no declared name → no\n // heading, rows show inline, never folded\" (`@ai-matrx/alchemy/menu`\n // `buildMenuModel` doc). The empty-string fallback that used to sit here\n // for a labelless `primary` section (e.g. notes'\n // `buildNoteContextSections`'s unlabeled \"note-actions\" section) declared\n // a REAL heading of `\"\"`, which is never an approved heading — every menu\n // carrying one threw `UnapprovedHeadingError` and refused to open\n // (2026-09-28). Ordering for a `primary` section is already handled\n // upstream by `liftPrimarySections` on the v3 `MenuSection[]`, so\n // dropping the heading here costs nothing but the (non-existent) label.\n const named =\n section.group === \"history\"\n ? { id: \"cm-history\", label: \"History\" }\n : section.label\n ? {\n id: `cm-${section.id}`,\n label: section.label,\n ...(section.primary ? { primary: true } : {}),\n // A surface section's label is the clicked thing's own name.\n ...(section.group === \"surface\" ? { kind: \"target\" as const } : {}),\n }\n : undefined;\n // A separator in the source starts a new group: the next row carries `startsGroup` and the\n // menu draws the divider (alchemy buildMenuModel) — \"Delete row…\" in its own group (DATA-V2-BASICS-2).\n let groupStarts = false;\n section.nodes.forEach((node, i) => {\n if (node.kind === \"separator\") {\n groupStarts = true;\n return;\n }\n const category =\n section.group === \"clipboard\" ? (NON_VERB_CLIPBOARD[node.id] ?? \"clipboard\") : CATEGORY_OF[section.group];\n // Undo / Redo are universal verbs: they ride the strip, not the History fold.\n const isHistoryVerb = section.group === \"history\" && (node.id === \"undo\" || node.id === \"redo\");\n const a = toAction(\n node,\n {\n category: isHistoryVerb ? \"clipboard\" : category,\n ...(named && !isHistoryVerb ? { section: named } : {}),\n order: base + i,\n },\n instanceId,\n opts,\n );\n if (a) {\n if (groupStarts) startGroup(a);\n groupStarts = false;\n out.push(a);\n }\n });\n });\n return out;\n}\n\n/**\n * THE provider one open menu registers (AlchemyMenuContent). Every menu\n * instance yields the same baseline ids (`cm:copy`, `cm:find`, …) and the\n * Alchemy registry refuses an id a second provider yields — so an instance\n * answers ONLY a target it opened. Two menus mounted at once (a message's menu\n * nested in the page's, PB-06 2026-10-01: 18 `DuplicateActionError`s per\n * open) each contribute to their own target and nothing to the other's.\n */\nexport function contextMenuProvider(instanceId: string, actions: () => readonly Action[]): ActionProvider {\n return {\n id: `context-menu:${instanceId}`,\n tier: \"T1\",\n actions: (target) => (contextMenuHostOf(target)?.instanceId === instanceId ? actions() : []),\n };\n}\n\n/** A cheap fingerprint of what the menu would draw (re-resolve when it moves). */\nexport function modelRevision(model: MenuModel): string {\n const walk = (nodes: MenuNode[]): string =>\n nodes\n .map((n) =>\n n.kind === \"submenu\"\n ? `${n.id}${n.disabled ? \"!\" : \"\"}${n.loading ? \"~\" : \"\"}[${walk(n.children)}]`\n : `${n.id}${\"disabled\" in n && n.disabled ? \"!\" : \"\"}${n.kind === \"checkbox\" && n.checked ? \"*\" : \"\"}${\"label\" in n ? `:${n.label}` : \"\"}`,\n )\n .join(\",\");\n return model.sections.map((s) => `${s.id}(${walk(s.nodes)})`).join(\"|\");\n}\n\n/**\n * The text the menu's \"Content: …\" header shows for what the menu acts on —\n * without storage plumbing: the tutor's trust comment goes through the ONE\n * strip copies and files use (live 2026-09-26: the header showed\n * `<!--MATRX_TRUST_V1 …-->` on every tutor answer).\n */\nexport function menuHeaderContent(actionText: { source: string; text: string }): string | null {\n if (actionText.source === \"none\") return null;\n return headerPreview(stripTurnTrust(actionText.text));\n}\n\n/** The transcript store slice `chatMessageSubject` reads (RootState[\"messages\"]). */\ninterface TranscriptStoreSlice {\n messages?: {\n byConversationId?: Record<\n string,\n { byId?: Record<string, { role?: unknown; createdAt?: string | null } | undefined> } | undefined\n >;\n };\n}\n\n/**\n * THE MESSAGE A MENU WAS OPENED ON — one answer for every menu over a chat\n * transcript, so the same message gets the same heading everywhere (\"AI answer\n * · Sep 27, 6:50 PM\", \"Your message · …\").\n *\n * Two doors name a message and both land here:\n * 1. the menu's own content source is that message (`chat-message` — the\n * per-answer registry menu);\n * 2. the menu is the transcript-level one and the right-click resolved the\n * message under the pointer (`messageId` in the per-open context —\n * `resolveMarkdownContext` reads the `data-message-id` every message root\n * carries). Run History's user turns and any answer area outside the\n * per-answer menu came through here and were headed \"Content: <the whole\n * text>\" (2026-09-28).\n */\nexport function chatMessageSubject(args: {\n state: TranscriptStoreSlice;\n source: { type: string; conversationId?: string; messageId?: string } | null | undefined;\n extensions?: { type?: string; role?: unknown } | null;\n contextData?: Record<string, unknown> | null | undefined;\n}): { role: string; createdAt: string | null } | null {\n const { state, source, extensions, contextData } = args;\n const read = (conversationId: unknown, messageId: unknown) =>\n typeof conversationId === \"string\" && typeof messageId === \"string\"\n ? state.messages?.byConversationId?.[conversationId]?.byId?.[messageId]\n : undefined;\n if (source?.type === \"chat-message\") {\n const record = read(source.conversationId, source.messageId);\n const role = record?.role ?? (extensions?.type === \"chat-message\" ? extensions.role : null);\n return role ? { role: String(role), createdAt: record?.createdAt ?? null } : null;\n }\n const record = read(contextData?.conversationId, contextData?.messageId);\n return record?.role ? { role: String(record.role), createdAt: record.createdAt ?? null } : null;\n}\n\n/**\n * The header for a menu opened in a FIELD with no selection: the field's name\n * and, when it helps, a short plain preview (`utils/field-menu-header.ts`).\n * Anything else keeps `menuHeaderContent`.\n */\nexport function menuHeader(\n actionText: { source: string; text: string },\n fieldLabel: string | null,\n /** The chat message the menu opened on, when it did (its role and when it was written). */\n message?: { role: string; createdAt?: string | null } | null,\n): { content: string | null; contentLabel: string | null } {\n // A MESSAGE is named, never dumped: \"AI answer\", not \"Content: <the whole answer>\"\n // (page-pass 2026-09-27, applet Run History). A selection still shows itself.\n if (message && actionText.source !== \"selection\" && actionText.source !== \"none\") {\n const who = message.role === \"user\" ? \"Your message\" : message.role === \"assistant\" ? \"AI answer\" : \"Message\";\n const at = message.createdAt ? new Date(message.createdAt) : null;\n const when =\n at && !Number.isNaN(at.getTime())\n ? ` · ${at.toLocaleString(undefined, { month: \"short\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\" })}`\n : \"\";\n return { content: \"\", contentLabel: `${who}${when}` };\n }\n if (fieldLabel && actionText.source !== \"selection\") {\n return { content: fieldPreview(headerPreview(stripTurnTrust(actionText.text))), contentLabel: fieldLabel };\n }\n return { content: menuHeaderContent(actionText), contentLabel: null };\n}\n\n/**\n * The header is a one-line PREVIEW, so it shows words, never markdown syntax:\n * \"Content: # Clinic intake…\" on /notes/<id> (page-pass 2026-09-27). Block\n * markers (headings, quotes, list bullets, task boxes, fences) are dropped per\n * line, inline emphasis goes through THE plain-text helper, and lines join\n * with a space. Only the header changes — the actions still act on the text\n * as written.\n */\nexport function headerPreview(text: string): string {\n const blocks = text\n .replace(/^\\s{0,3}(?:```|~~~).*$/gm, \"\")\n .replace(/^\\s{0,3}#{1,6}\\s+/gm, \"\")\n .replace(/^\\s{0,3}>\\s?/gm, \"\")\n .replace(/^\\s{0,3}(?:[-*+]|\\d+[.)])\\s+(?:\\[[ xX]\\]\\s+)?/gm, \"\");\n return markdownToPlainText(blocks).replace(/\\s*\\n+\\s*/g, \" \").trim();\n}\n\n/**\n * A target that NAMES itself (`CONTEXT_MENU_HEADING_KEY`: a list row's record)\n * heads the menu with that name — \"Quiz: Unit 2 review\" — instead of the\n * generic \"Content: <agent context>\" (page-pass 2026-09-27). A selection still\n * shows itself.\n */\nexport function namedHeader(\n heading: { label: string; text: string } | null | undefined,\n actionText: { source: string },\n): { content: string; contentLabel: string } | null {\n if (!heading || actionText.source === \"selection\") return null;\n return { content: heading.text, contentLabel: heading.label };\n}\n\n/**\n * The revision the alchemy menu engine re-resolves on. The engine\n * (`useMenuEngine` in @ai-matrx/alchemy/react/menu) rebuilds its model — header\n * included — only when its `revision` moves; `content` / `contentLabel` are not\n * in its dependency list. A menu that stays mounted between opens therefore\n * kept the FIRST header: \"Note: New Note\" after the note was renamed\n * (G6B review, 2026-10-02). The header text is part of what the menu draws, so\n * it is part of the revision.\n */\nexport function menuEngineRevision(\n drawn: string,\n header: { content: string | null; contentLabel: string | null },\n): string {\n return `${drawn}\\u0000${header.contentLabel ?? \"\"}\\u0000${header.content ?? \"\"}`;\n}\n","\"use client\";\n\n// features/context-menu-v3/regroup/RegroupContext.tsx\n//\n// Opt-in, per-subtree: a MenuRegroupContext above a menu wrapper makes THAT\n// menu (and only that one) resolve through a registry view that\n// · reports what the real registry resolved (`onResolved`), and\n// · when `grouping` is set, hands the renderer the regrouped actions.\n// With no provider above it — every production menu — `RegroupBoundary`\n// renders its children untouched.\n\nimport * as React from \"react\";\nimport type { ActionRegistry, ClickTarget, ResolvedAction } from \"@ai-matrx/alchemy/actions\";\nimport { AlchemyActionsProvider, useAlchemyActions } from \"@ai-matrx/alchemy/react/host\";\nimport type { ContextMenuLayout } from \"../types\";\nimport { regroupResolved, type MenuGrouping } from \"./grouping\";\n\nexport interface MenuResolutionReport {\n target: ClickTarget;\n /** Exactly what the registry resolved for this open — before any grouping. */\n resolved: readonly ResolvedAction[];\n arrangement: ContextMenuLayout;\n}\n\nexport interface MenuRegroupValue {\n /** null = draw the menu as it is today (report only). */\n grouping: MenuGrouping | null;\n mergeSameName: boolean;\n /**\n * Arrange the resolved rows with a function instead of a grouping (the proposed menu,\n * `../proposed/proposed-arrangement.ts`). Wins over `grouping`.\n */\n transform?: ((target: ClickTarget, resolved: readonly ResolvedAction[]) => ResolvedAction[]) | undefined;\n /** The menu's size and whether it draws its header line (the proposed menu: large, none). */\n size?: \"standard\" | \"large\" | undefined;\n hideHeader?: boolean | undefined;\n /** Called on every resolve of this menu; `close` shuts the open menu. */\n onResolved?: ((report: MenuResolutionReport, close: () => void) => void) | undefined;\n}\n\nexport const MenuRegroupContext = React.createContext<MenuRegroupValue | null>(null);\n\nexport function MenuRegroupProvider({ value, children }: { value: MenuRegroupValue; children: React.ReactNode }) {\n return <MenuRegroupContext.Provider value={value}>{children}</MenuRegroupContext.Provider>;\n}\n\ninterface RegroupInputs {\n value: MenuRegroupValue | null;\n arrangement: ContextMenuLayout;\n close: () => void;\n}\n\n/** A registry view over `inner`; `update` hands it the latest render's inputs. */\nfunction regroupingRegistry(inner: ActionRegistry, first: RegroupInputs): ActionRegistry & { update(next: RegroupInputs): void } {\n let inputs = first;\n const read = () => inputs;\n return {\n update(next) {\n inputs = next;\n },\n register: (provider) => inner.register(provider),\n providers: () => inner.providers(),\n subscribe: (listener) => inner.subscribe(listener),\n // By-id lookup (alchemy 0.12): regrouping changes how a menu is arranged, never which Action an id names.\n get: (id, target) => inner.get(id, target),\n async resolve(target, restrict) {\n const list = await inner.resolve(target, restrict);\n const { value, arrangement, close } = read();\n if (!value) return list;\n value.onResolved?.({ target, resolved: list, arrangement }, close);\n if (value.transform) return value.transform(target, list);\n if (!value.grouping) return list;\n return regroupResolved(target, list, value.grouping, { mergeSameName: value.mergeSameName }).resolved;\n },\n };\n}\n\n/** Wraps the menu renderer; a pass-through unless a MenuRegroupContext is above it. */\nexport function RegroupBoundary({\n arrangement,\n close,\n children,\n}: {\n arrangement: ContextMenuLayout;\n close: () => void;\n children: React.ReactElement;\n}): React.ReactElement {\n const value = React.useContext(MenuRegroupContext);\n const { registry, ports } = useAlchemyActions();\n // One view per menu open: the provider above a menu does not come and go\n // while it is open, and the menu content remounts on every open.\n const [view] = React.useState(() =>\n value ? regroupingRegistry(registry, { value, arrangement, close }) : null,\n );\n // Resolves run after effects, so the view always reads this render's values.\n React.useLayoutEffect(() => {\n view?.update({ value, arrangement, close });\n });\n if (!view) return children;\n return (\n <AlchemyActionsProvider ports={ports} registry={view}>\n {children}\n </AlchemyActionsProvider>\n );\n}\n","// features/context-menu-v3/regroup/grouping.ts\n//\n// A GROUPING is a proposed arrangement of the ONE right-click menu, applied to\n// the resolved registry actions (never a hand-written list): each resolved\n// action goes to the top level, first (the page's own rows), or into one named\n// submenu. It exists so Arman can compare the current menu with a regrouped one\n// side by side before anything changes in production (2026-09-27: \"I'm not\n// happy with what we have but I also don't want things done blindly and I'm\n// not willing to lose important features\").\n//\n// NOTHING IS LOST SILENTLY. `regroupResolved` returns where every input action\n// ended up, and `auditRegroup` recomputes that from the OUTPUT (the actions the\n// regrouped menu actually holds, submenu members included) — so an action the\n// regroup dropped by mistake is reported as having no new home, never hidden.\n//\n// Pure: no React. Applied only where a `MenuRegroupContext` asks for it\n// (`RegroupContext.tsx`); production menus carry no grouping.\n\nimport type { Action, ActionCategory, ClickTarget, ResolvedAction } from \"@ai-matrx/alchemy/actions\";\nimport {\n buildMenuModel,\n context as arrangeContext,\n type ContextArrangement,\n type MenuModel,\n type MenuNode,\n} from \"@ai-matrx/alchemy/menu\";\n\n/** One submenu the grouping creates. The label is a plain, conventional word. */\nexport interface MenuGroupDef {\n key: string;\n label: string;\n /** One line: what the person gets from a row in this submenu. */\n definition: string;\n /** Icon KEY for the Alchemy icon port. */\n icon?: string | undefined;\n /** Decides where the submenu row sits among the other rows (the package's group order). */\n category: ActionCategory;\n order: number;\n}\n\nexport type GroupingDestination =\n /** Top level, lifted to the very top: the page's own actions. */\n | { kind: \"page-first\" }\n /** Top level, where the package places it (verbs stay in the icon strip). */\n | { kind: \"top\" }\n | { kind: \"group\"; key: string };\n\nexport interface GroupingRule {\n /** Matches when ANY listed condition matches. */\n when: {\n ids?: readonly string[] | undefined;\n idPrefixes?: readonly string[] | undefined;\n categories?: readonly ActionCategory[] | undefined;\n /** The clicked thing's own section (a row's or a note's actions). */\n pageOwn?: boolean | undefined;\n /**\n * A page's OWN row whose label matches one of these (case-insensitive\n * regular expressions): a record action that duplicates a category\n * (\"Export as Markdown\", \"Share link…\") moves into that category.\n */\n pageOwnLabels?: readonly string[] | undefined;\n };\n to: GroupingDestination;\n /**\n * Universal rows that do the same thing. When one of them is in the menu,\n * the matched row merges into it (one row, recorded as merged) instead of\n * sitting beside it.\n */\n mergeWithIds?: readonly string[] | undefined;\n}\n\nexport interface MenuGrouping {\n name: string;\n groups: readonly MenuGroupDef[];\n /** First match wins. */\n rules: readonly GroupingRule[];\n /** Where an action no rule names goes. */\n fallback: GroupingDestination;\n /** A group with fewer members than this is not made: its member stays at the top level. */\n minMembers: number;\n}\n\nexport interface RegroupOptions {\n /** Inside one submenu, a second row with the same name as an earlier one is merged into it. */\n mergeSameName: boolean;\n}\n\n/** Why an action sits where it sits in the proposed menu. */\nexport type ProposedHome =\n | { kind: \"page-first\" }\n | { kind: \"top\"; note?: string }\n | { kind: \"group\"; key: string; label: string }\n | {\n kind: \"merged\";\n intoId: string;\n intoLabel: string;\n groupLabel: string;\n /** The merged row runs THIS page's handler under the twin's label and place. */\n pageActionKept?: boolean | undefined;\n };\n\nexport interface RegroupResult {\n /** What the proposed menu resolves: top-level actions plus one submenu action per group. */\n resolved: ResolvedAction[];\n /** The rows inside each submenu, by group key, in order. */\n members: Map<string, ResolvedAction[]>;\n home: Map<string, ProposedHome>;\n}\n\nexport const REGROUP_ID_PREFIX = \"regroup:\";\n\nexport function actionLabel(action: Action, target: ClickTarget): string {\n try {\n return typeof action.label === \"function\" ? action.label(target) : action.label;\n } catch {\n return action.id;\n }\n}\n\nfunction isPageOwn(action: Action): boolean {\n const section = action.section as (Action[\"section\"] & { kind?: string; primary?: boolean }) | undefined;\n return Boolean(section && (section.primary || section.kind === \"target\"));\n}\n\nfunction labelOf(action: Pick<Action, \"id\" | \"label\">, target?: ClickTarget): string {\n if (typeof action.label === \"string\") return action.label;\n return target ? actionLabel(action as Action, target) : \"\";\n}\n\nfunction ruleMatches(rule: GroupingRule, action: Action, target?: ClickTarget): boolean {\n const w = rule.when;\n if (w.pageOwnLabels && isPageOwn(action)) {\n const label = labelOf(action, target);\n if (label && w.pageOwnLabels.some((p) => new RegExp(p, \"i\").test(label))) return true;\n }\n if (w.ids?.includes(action.id)) return true;\n if (w.idPrefixes?.some((p) => action.id.startsWith(p))) return true;\n if (w.categories?.includes(action.category)) return true;\n if (w.pageOwn && isPageOwn(action)) return true;\n return false;\n}\n\n/** The rule that places this action, or null when it falls through to `fallback`. */\nexport function matchRule(\n grouping: MenuGrouping,\n action: Pick<Action, \"id\" | \"category\" | \"section\"> & { label?: Action[\"label\"] },\n target?: ClickTarget,\n): GroupingRule | null {\n return grouping.rules.find((r) => ruleMatches(r, action as Action, target)) ?? null;\n}\n\nexport function destinationFor(grouping: MenuGrouping, action: Action, target?: ClickTarget): GroupingDestination {\n return matchRule(grouping, action, target)?.to ?? grouping.fallback;\n}\n\nconst sameName = (label: string) =>\n label\n .toLowerCase()\n .replace(/[….]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n/** Every node id in a model, in drawn order (for keeping familiar order inside a submenu). */\nfunction drawnOrder(model: MenuModel): Map<string, number> {\n const order = new Map<string, number>();\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) {\n if (!order.has(n.id)) order.set(n.id, order.size);\n if (n.kind === \"submenu\") walk(n.children);\n }\n };\n for (const s of model.sections) walk(s.nodes);\n return order;\n}\n\nexport function currentModel(target: ClickTarget, resolved: readonly ResolvedAction[]): MenuModel {\n return buildMenuModel(target, resolved, { headingPolicy: \"inline\" });\n}\n\n/**\n * Apply a grouping to the resolved actions. Actions greyed with a reason stay\n * at the top level: a submenu row is always drawn runnable, so moving a greyed\n * row into one would make it look usable when it is not.\n */\nexport function regroupResolved(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n grouping: MenuGrouping,\n options: RegroupOptions,\n): RegroupResult {\n const order = drawnOrder(currentModel(target, resolved));\n const pos = (r: ResolvedAction) => order.get(r.action.id) ?? Number.MAX_SAFE_INTEGER;\n const groupDef = new Map(grouping.groups.map((g) => [g.key, g]));\n\n const top: ResolvedAction[] = [];\n const home = new Map<string, ProposedHome>();\n const wanted = new Map<string, ResolvedAction[]>();\n\n // Equivalent rows: a matched row whose universal twin is in this menu merges into it.\n const present = new Map(resolved.map((r) => [r.action.id, r]));\n const twinOf = (r: ResolvedAction): ResolvedAction | null => {\n const rule = matchRule(grouping, r.action, target);\n for (const id of rule?.mergeWithIds ?? []) {\n const twin = present.get(id);\n if (twin && twin !== r) return twin;\n }\n return null;\n };\n // THE PAGE'S VERSION WINS (Arman: \"I'm not willing to lose important\n // features\"): a merged row keeps the twin's label and place, but runs the\n // PAGE's handler; the general one runs only where the page has none. A page\n // row that opens a submenu is never merged (it moves as itself).\n const mergedInto = new Map<string, ResolvedAction>();\n const pageVersionOf = new Map<string, ResolvedAction>();\n for (const r of resolved) {\n if (r.action.expand) continue;\n const twin = twinOf(r);\n if (!twin || pageVersionOf.has(twin.action.id)) continue;\n mergedInto.set(r.action.id, twin);\n pageVersionOf.set(twin.action.id, r);\n }\n const withPageHandler = (r: ResolvedAction): ResolvedAction => {\n const page = pageVersionOf.get(r.action.id);\n if (!page) return r;\n const { href: _generalHref, ...general } = r.action;\n void _generalHref;\n const action: Action = {\n ...general,\n run: page.action.run,\n ...(page.action.href !== undefined ? { href: page.action.href } : {}),\n };\n return { ...r, action };\n };\n\n for (const original of resolved) {\n if (mergedInto.has(original.action.id)) continue;\n const r = withPageHandler(original);\n const to = destinationFor(grouping, r.action, target);\n if (to.kind === \"group\" && groupDef.has(to.key)) {\n if (r.eligibility.status !== \"available\") {\n top.push(r);\n home.set(r.action.id, { kind: \"top\", note: \"greyed here, so it stays visible with its reason\" });\n continue;\n }\n const list = wanted.get(to.key) ?? [];\n list.push(r);\n wanted.set(to.key, list);\n continue;\n }\n if (to.kind === \"page-first\") {\n const section = r.action.section;\n top.push(\n section\n ? { ...r, action: { ...r.action, section: { ...section, primary: true } } as Action }\n : r,\n );\n home.set(r.action.id, { kind: \"page-first\" });\n continue;\n }\n top.push(r);\n home.set(r.action.id, { kind: \"top\" });\n }\n\n const members = new Map<string, ResolvedAction[]>();\n const groupActions: ResolvedAction[] = [];\n for (const def of grouping.groups) {\n const list = (wanted.get(def.key) ?? []).slice().sort((a, b) => pos(a) - pos(b));\n if (list.length === 0) continue;\n if (list.length < grouping.minMembers) {\n for (const r of list) {\n top.push(r);\n home.set(r.action.id, { kind: \"top\", note: `the only row for ${def.label}` });\n }\n continue;\n }\n const kept: ResolvedAction[] = [];\n const byName = new Map<string, ResolvedAction>();\n for (const r of list) {\n const name = sameName(actionLabel(r.action, target));\n const first = options.mergeSameName ? byName.get(name) : undefined;\n if (first) {\n home.set(r.action.id, {\n kind: \"merged\",\n intoId: first.action.id,\n intoLabel: actionLabel(first.action, target),\n groupLabel: def.label,\n });\n continue;\n }\n byName.set(name, r);\n kept.push(r);\n home.set(r.action.id, { kind: \"group\", key: def.key, label: def.label });\n }\n members.set(def.key, kept);\n const children = kept.map((r) => r.action);\n const submenu: Action = {\n id: `${REGROUP_ID_PREFIX}${def.key}`,\n label: def.label,\n category: def.category,\n order: def.order,\n ...(def.icon ? { icon: def.icon } : {}),\n // Still loading at the source when any member is.\n pending: (t) => children.some((c) => Boolean(c.expand && c.pending?.(t))),\n eligible: () => ({ status: \"available\" }),\n expand: async () => children,\n run: () => undefined,\n };\n groupActions.push({ action: submenu, eligibility: { status: \"available\" } });\n }\n\n // Where each twin ended up names where the merged row now lives.\n for (const [id, twin] of mergedInto) {\n const at = home.get(twin.action.id);\n home.set(id, {\n kind: \"merged\",\n intoId: twin.action.id,\n intoLabel: actionLabel(twin.action, target),\n groupLabel: at?.kind === \"group\" ? at.label : at?.kind === \"merged\" ? at.groupLabel : \"\",\n pageActionKept: true,\n });\n }\n\n return { resolved: [...top, ...groupActions], members, home };\n}\n\n// ── Where a row is drawn (for the \"what goes where\" table) ─────────────────\n\n/** Where each top-level action id is drawn in a context arrangement. */\nexport function drawnPlaces(model: MenuModel, arrangement: ContextArrangement): Map<string, string> {\n const arranged = arrangeContext(model, arrangement);\n const places = new Map<string, string>();\n for (const leaf of arranged.strip) places.set(leaf.actionId ?? leaf.id, \"Icon strip\");\n arranged.sections.forEach((section, index) => {\n const heading = section.label ? `\"${section.label}\" section` : \"\";\n for (const node of section.nodes) {\n if (node.kind === \"separator\" || node.kind === \"label\") continue;\n if (node.kind === \"submenu\" && node.id.endsWith(\":fold\")) {\n for (const child of node.children) {\n if (child.kind === \"separator\" || child.kind === \"label\") continue;\n places.set(child.actionId ?? child.id, `${node.label} ▸`);\n }\n continue;\n }\n places.set(node.actionId ?? node.id, heading ? `Top level · ${heading}` : index === 0 && section.primary ? \"Top level · first\" : \"Top level\");\n }\n });\n return places;\n}\n\n/** How many rows a person sees when the menu opens (strip icons count as one row). */\nexport function topLevelRowCount(model: MenuModel, arrangement: ContextArrangement): number {\n const arranged = arrangeContext(model, arrangement);\n let rows = arranged.strip.length > 0 ? 1 : 0;\n for (const section of arranged.sections) {\n rows += section.nodes.filter((n) => n.kind !== \"separator\" && n.kind !== \"label\").length;\n }\n return rows;\n}\n\nexport interface AuditRow {\n id: string;\n label: string;\n category: ActionCategory;\n isSubmenu: boolean;\n /** The clicked thing's own row (surface-specific), not a universal one. */\n pageOwn: boolean;\n current: string;\n proposed: ProposedHome | null;\n proposedPlace: string;\n}\n\nexport interface RegroupAudit {\n rows: AuditRow[];\n /** Current actions the regrouped menu does not hold anywhere and does not explain. */\n lost: AuditRow[];\n currentRows: number;\n proposedRows: number;\n}\n\n/**\n * Recompute, from what the regrouped menu HOLDS, where every current action\n * went. An action counts as placed only if it is a top-level action of the\n * regrouped menu, a member of one of its submenus, or recorded as merged into\n * a row that is itself placed.\n */\nexport function auditRegroup(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n grouping: MenuGrouping,\n options: RegroupOptions,\n arrangement: ContextArrangement,\n /** The regroup under audit (tests hand in a broken one to prove the guard fires). */\n regroup: typeof regroupResolved = regroupResolved,\n): RegroupAudit {\n const result = regroup(target, resolved, grouping, options);\n const current = currentModel(target, resolved);\n const proposed = currentModel(target, result.resolved);\n const currentPlaces = drawnPlaces(current, arrangement);\n const proposedPlaces = drawnPlaces(proposed, arrangement);\n\n const held = new Set<string>();\n for (const r of result.resolved) if (!r.action.id.startsWith(REGROUP_ID_PREFIX)) held.add(r.action.id);\n for (const list of result.members.values()) for (const r of list) held.add(r.action.id);\n\n const rows: AuditRow[] = resolved.map((r) => {\n const home = result.home.get(r.action.id) ?? null;\n let proposedPlace = \"\";\n if (held.has(r.action.id)) {\n proposedPlace =\n home?.kind === \"group\" ? `${home.label} ▸` : (proposedPlaces.get(r.action.id) ?? \"Top level\");\n } else if (home?.kind === \"merged\" && held.has(home.intoId)) {\n proposedPlace = home.groupLabel ? `${home.groupLabel} ▸ ${home.intoLabel}` : `Top level · ${home.intoLabel}`;\n }\n return {\n id: r.action.id,\n label: actionLabel(r.action, target),\n category: r.action.category,\n isSubmenu: Boolean(r.action.expand),\n pageOwn: isPageOwn(r.action),\n current: currentPlaces.get(r.action.id) ?? \"Top level\",\n proposed: proposedPlace ? home : null,\n proposedPlace,\n };\n });\n\n return {\n rows,\n lost: rows.filter((row) => !row.proposedPlace),\n currentRows: topLevelRowCount(current, arrangement),\n proposedRows: topLevelRowCount(proposed, arrangement),\n };\n}\n","\"use client\";\n\n// features/context-menu-v3/components/ShortcutKeyRunner.tsx\n//\n// Runs ONE agent shortcut whose advertised key combo was pressed — through the\n// SAME engine and the same launch handler the menu item uses\n// (`useContextMenuActions().handleShortcutExecute`), so a combo and a click\n// launch identically (scope, selection, widget handle, display mode). Renders\n// nothing; the shell mounts it for one press and drops it when done.\n\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"../utils/notify\";\nimport { useContextMenuActions } from \"../hooks/useContextMenuActions\";\nimport type { AgentMenuCategoryGroup, AgentMenuEntry } from \"../hooks/useUnifiedAgentContextMenu\";\nimport type { MenuContentProps } from \"../types\";\n\ntype ShortcutEntry = Extract<AgentMenuEntry, { entryType: \"agent_shortcut\" }>;\n\nfunction findShortcut(groups: AgentMenuCategoryGroup[], id: string): ShortcutEntry | null {\n for (const group of groups) {\n for (const item of group.items) {\n if (item.entryType === \"agent_shortcut\" && item.id === id) return item;\n }\n const nested = findShortcut(group.children, id);\n if (nested) return nested;\n }\n return null;\n}\n\nexport interface ShortcutKeyRunnerProps extends Omit<MenuContentProps, \"variant\"> {\n shortcutId: string;\n shortcutLabel: string;\n onDone(): void;\n}\n\nexport default function ShortcutKeyRunner(props: ShortcutKeyRunnerProps): null {\n const { shortcutId, shortcutLabel, onDone, ...menuProps } = props;\n const m = useContextMenuActions(menuProps);\n const ran = useRef(false);\n\n useEffect(() => {\n if (ran.current || m.loading) return;\n ran.current = true;\n const entry = findShortcut(m.categoryGroups, shortcutId);\n if (!entry) {\n toast({\n title: m.librariesError\n ? `Couldn't load ${shortcutLabel}`\n : `${shortcutLabel} isn't available here`,\n ...(m.librariesError ? { variant: \"destructive\" as const } : {}),\n });\n onDone();\n return;\n }\n void m.handleShortcutExecute(entry).finally(onDone);\n });\n\n return null;\n}\n"],"mappings":"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","names":["React","useAlchemyActions","id","useMemo","useAppDispatch","useAppSelector","placementGroupKey","BASELINE_VALUE_NAMES","placementGroupKey","useAppDispatch","useAppSelector","useMemo","BASELINE_VALUE_NAMES","Braces","PLACEMENT_TYPES","AGENT_ICON","icon","AGENT_ICON","Braces","PLACEMENT_TYPES","record","buildMenuModel","jsx","useAlchemyActions","useEffect","useRef","useRef","useEffect"]}