@mikedown/core 0.3.0 → 0.4.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.
- package/CHANGELOG.md +12 -1
- package/README.md +1 -1
- package/dist/ai/engines-page.d.ts +11 -4
- package/dist/ai/engines-page.js +5 -4
- package/dist/ai/index.d.ts +1201 -10
- package/dist/ai/index.js +297 -8
- package/dist/{ai-ui-C7ENTWWU.js → ai-ui-QFYFN73D.js} +3165 -138
- package/dist/ai-ui-QFYFN73D.js.map +1 -0
- package/dist/{chunk-QDVY7WW6.js → chunk-APPBNQEY.js} +53 -2
- package/dist/chunk-APPBNQEY.js.map +1 -0
- package/dist/{chunk-7A5HEPLK.js → chunk-DWXGWVA3.js} +850 -12
- package/dist/chunk-DWXGWVA3.js.map +1 -0
- package/dist/{chunk-JZWKEBCI.js → chunk-IWCXWUWW.js} +3260 -201
- package/dist/chunk-IWCXWUWW.js.map +1 -0
- package/dist/{chunk-LXZG7IKN.js → chunk-N4N54LK2.js} +2 -2
- package/dist/chunk-N4N54LK2.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +399 -38
- package/dist/index.js.map +1 -1
- package/dist/schema-DVfssxQX.d.ts +100 -0
- package/dist/styles.css +943 -4
- package/dist/{types-CsVNVSNY.d.ts → types-2TZErbJr.d.ts} +25 -3
- package/dist/{types-CgEeIUhi.d.ts → types-DO8UBybZ.d.ts} +316 -7
- package/package.json +1 -1
- package/dist/ai-ui-C7ENTWWU.js.map +0 -1
- package/dist/chunk-7A5HEPLK.js.map +0 -1
- package/dist/chunk-JZWKEBCI.js.map +0 -1
- package/dist/chunk-LXZG7IKN.js.map +0 -1
- package/dist/chunk-QDVY7WW6.js.map +0 -1
- package/dist/schema-DYzxkuSb.d.ts +0 -46
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai-prefs.ts","../src/ai-settings.ts","../src/ai-toolbar.ts","../src/ai-activity.ts","../src/ai-request.ts","../src/ai-activity-panel.ts","../src/ai-docs-run.ts","../src/ai-ghost.ts","../src/ai-ghost-plugin.ts","../src/ai-ghost-session.ts","../src/ai-markdown-preview.ts","../src/ai-chat-panel.ts","../src/ai-rewrite.ts","../src/ai-insert-guard.ts"],"sourcesContent":["/**\n * Remembered AI choices (D10): the recent translate languages, the last\n * reading level and the thinking level. `localStorage` behind try/catch,\n * like the emoji picker's recents; storage may be missing or throw in a\n * webview sandbox, so every read has a default and every write is best\n * effort. Never a `mikedown.*` setting (D3).\n *\n * The thinking level is one value, set from the AI menu's Thinking row or\n * the popover's dial, and sent with every request until changed (null is\n * \"Default\": MikeDown picks per task, see `resolveThinkingLevel`). A kind that cannot express\n * it gets its nearest level (`thinkingLevelFor`).\n */\n\nimport { getAiAudience, type AiAudience } from './ai/prompts/rewrite';\nimport { nearestThinkingLevel, type AiThinkingLevel } from './ai/thinking';\n\nconst LANGUAGES_KEY = 'mikedown.ai.recentLanguages';\nconst AUDIENCE_KEY = 'mikedown.ai.audience';\nconst THINKING_KEY = 'mikedown.ai.thinking';\n\n/** Recent languages shown above the fixed list. */\nexport const MAX_RECENT_LANGUAGES = 3;\n\n/** Longest language name kept (it is free text from \"Other…\"). */\nconst LANGUAGE_MAX_CHARS = 60;\n\n/** The fixed translate list, in menu order (D17). */\nexport const AI_TRANSLATE_LANGUAGES: readonly string[] = [\n 'English', 'Spanish', 'French', 'German', 'Portuguese', 'Italian',\n 'Dutch', 'Japanese', 'Chinese (Simplified)', 'Korean', 'Arabic', 'Hindi',\n];\n\nconst sameLanguage = (a: string, b: string): boolean => a.toLocaleLowerCase() === b.toLocaleLowerCase();\n\n/** A typed language name, trimmed to one line; empty when there is nothing to keep. */\nfunction cleanLanguage(language: string): string {\n return language.replace(/\\s+/g, ' ').trim().slice(0, LANGUAGE_MAX_CHARS);\n}\n\n/** The recent languages, newest first, at most `MAX_RECENT_LANGUAGES`. */\nexport function loadRecentLanguages(): string[] {\n try {\n const raw = localStorage.getItem(LANGUAGES_KEY);\n if (!raw) {return [];}\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) {return [];}\n const out: string[] = [];\n for (const item of parsed) {\n if (typeof item !== 'string') {continue;}\n const lang = cleanLanguage(item);\n if (lang && !out.some((l) => sameLanguage(l, lang))) {out.push(lang);}\n if (out.length >= MAX_RECENT_LANGUAGES) {break;}\n }\n return out;\n } catch {\n return [];\n }\n}\n\n/** Put a language at the top of the recents, stored as typed. */\nexport function rememberLanguage(language: string): void {\n const lang = cleanLanguage(language);\n if (!lang) {return;}\n try {\n const next = [lang, ...loadRecentLanguages().filter((l) => !sameLanguage(l, lang))].slice(0, MAX_RECENT_LANGUAGES);\n localStorage.setItem(LANGUAGES_KEY, JSON.stringify(next));\n } catch {\n // Storage refused (sandboxed webview, private mode): the choice is not remembered.\n }\n}\n\n/** The language picker's rows: recents first, then the fixed list without them. */\nexport function translateLanguageChoices(recents: string[] = loadRecentLanguages()): { recents: string[]; languages: string[] } {\n return {\n recents,\n languages: AI_TRANSLATE_LANGUAGES.filter((l) => !recents.some((r) => sameLanguage(r, l))),\n };\n}\n\n/** The last reading level chosen, or null. */\nexport function loadAudience(): AiAudience | null {\n try {\n const raw = localStorage.getItem(AUDIENCE_KEY);\n return raw && getAiAudience(raw) ? (raw as AiAudience) : null;\n } catch {\n return null;\n }\n}\n\nexport function rememberAudience(audience: AiAudience): void {\n if (!getAiAudience(audience)) {return;}\n try {\n localStorage.setItem(AUDIENCE_KEY, audience);\n } catch {\n // Storage refused: the choice is not remembered.\n }\n}\n\nconst THINKING_LEVELS: readonly AiThinkingLevel[] = ['off', 'low', 'medium', 'high'];\n\n/** The remembered thinking level, or null for \"Default\" (MikeDown picks per task). */\nexport function loadThinkingLevel(): AiThinkingLevel | null {\n try {\n const raw = localStorage.getItem(THINKING_KEY);\n return raw && (THINKING_LEVELS as readonly string[]).includes(raw) ? (raw as AiThinkingLevel) : null;\n } catch {\n return null;\n }\n}\n\n/** Remember a thinking level; null goes back to \"Default\". */\nexport function rememberThinkingLevel(level: AiThinkingLevel | null): void {\n try {\n if (level) {localStorage.setItem(THINKING_KEY, level);} else {localStorage.removeItem(THINKING_KEY);}\n } catch {\n // Storage refused: the choice is not remembered.\n }\n}\n\n/**\n * The remembered level for a request to this kind: the level itself when\n * the kind has it, else the nearest one (Off on Anthropic is Low, any tier\n * on LM Studio is On). Null for \"Default\" or a kind with no mapping.\n */\nexport function thinkingLevelFor(kind: string): AiThinkingLevel | null {\n return nearestThinkingLevel(kind, loadThinkingLevel());\n}\n","/**\n * The Settings modal's AI tab: a summary. Built only when the host has an\n * `ai` group (see `editor.ts#showSettingsModal`), with the modal's own row\n * builders so it sits flush with the other tabs.\n *\n * Order (U8): the intro, the master switch, the Engines summary, the\n * Documentation bases row (with `host.docs`), Allow cloud with the cloud\n * consents, the toolbar button switch, the AI Activity switch, Features.\n * Tier 1 hosts (`complete` only, they route by themselves) get the master\n * switch, the toolbar and AI Activity switches and the feature toggles. Tier 2 hosts (an\n * engine registry) also get a compact engine list (name, local/cloud pill,\n * status dot, enabled switch), the default model with \"Change…\" (the Tasks\n * section), \"Manage engines…\", Allow cloud, and each feature's task under\n * \"Advanced: task per feature\".\n * Engines, their forms and routing live on the AI Engines page\n * (`ai-engines-page.ts`), which the tab opens over the modal.\n *\n * Edits run in an `AiSettingsSession` (`ai-settings-session.ts`); Save sends\n * only the `ai.*` keys that changed, through the modal's normal\n * `saveSettings` patch. The page starts from the tab's draft and saves on\n * Done; the tab then takes the saved result as its own.\n *\n * Modal UI only: nothing here touches the editor document or its DOM.\n */\n\nimport { AI_FEATURES, AI_NO_CONSENTS_TEXT, AI_TASKS, GHOST_DELAY_MS_DEFAULT, GHOST_DELAY_MS_MAX, GHOST_DELAY_MS_MIN, GHOST_MAX_TOKENS_DEFAULT, GHOST_MAX_TOKENS_MAX, GHOST_MAX_TOKENS_MIN, aiConsentStepNote, aiConsentSummary, aiProviderPolicy, getAiTask, ghostTextOptions, resolveAiFeature, toAiError } from './ai';\nimport type { AiConsentRecord, AiEngineConfig, AiFeatureSetting, AiSettings, AiSettingsPatch } from './ai';\nimport { engineDisplayName, engineKindLabel, parseLocalNetworksText, routeLabel, taskRouteNote } from './ai-settings-model';\nimport { createAiSettingsSession } from './ai-settings-session';\nimport type { AiSettingsSessionOptions } from './ai-settings-session';\nimport type { AiEnginesPageSection } from './ai-engines-page';\nimport { ICONS, button, el, experimentalBadge, experimentalDisclaimer, keepFocus, kindGlyphHtml, localityPills, nextId, note, privacyCard, privacyLine, statusBadge, switchInput } from './ai-settings-dom';\nimport type { MikeDownSettingsSectionBuild, MikeDownSettingsSectionContext } from './types';\n\n/** The tab asks its host to open the AI Engines page over the modal. */\nexport interface AiEnginesPageRequest {\n initial?: { engineId?: string; section?: AiEnginesPageSection };\n /** Session options for the page: it starts from the tab's draft. */\n session: AiSettingsSessionOptions & { keyOverride: Map<string, boolean> };\n /** The page saved (Done) `patch`, ending at `settings`. */\n onDone(patch: AiSettingsPatch, settings: AiSettings): void;\n}\n\nexport interface AiSettingsSectionOptions extends AiSettingsSessionOptions {\n /** The modal saved; the draft is the new settings. */\n onSaved(draft: AiSettings): void;\n /** Open the AI Engines page. Absent: no engine list and no Manage engines… button. */\n openEnginesPage?(request: AiEnginesPageRequest): void;\n /** The host has `host.docs`: a row opens the AI Engines page on its Documentation bases. */\n docsAvailable?: boolean;\n /** Open the AI Activity panel over the modal. Absent: no \"Open\" beside the switch. */\n openActivityPanel?(): void;\n /** A stored consent was forgotten: drop this session's copy of the answer so the next request asks again. */\n onConsentForgotten?(engineId: string): void;\n}\n\n// ── The tab ─────────────────────────────────────────────────────────────────\n\nexport function buildAiSettingsSection(ctx: MikeDownSettingsSectionContext, opts: AiSettingsSectionOptions): MikeDownSettingsSectionBuild {\n const session = createAiSettingsSession(opts);\n const { tier } = session;\n const canManage = tier === 2 && !!opts.openEnginesPage;\n\n // Screen reader announcements (the page saved).\n const live = el('div', 'ai-live');\n live.setAttribute('role', 'status');\n live.setAttribute('aria-live', 'polite');\n let liveTimer: number | undefined;\n function announce(text: string): void {\n window.clearTimeout(liveTimer);\n live.textContent = '';\n liveTimer = window.setTimeout(() => { live.textContent = text; }, 40);\n }\n\n // ── Experimental notice, master switch and Allow cloud ────────────────────\n const rows: HTMLElement[] = [];\n\n const intro = el('div', 'ai-experimental-intro');\n const introHead = el('div', 'ai-experimental-head');\n introHead.append(el('span', 'ai-experimental-title', 'AI features'), experimentalBadge());\n intro.append(introHead, experimentalDisclaimer());\n rows.push(intro);\n\n const masterField = ctx.makeCheckboxRow(\n 'Enable AI features',\n tier === 2\n ? 'Writing help from engines you choose. While this is off, nothing is sent anywhere.'\n : 'Writing help from the AI service this app provides. While this is off, nothing is sent anywhere.',\n session.draft.enabled,\n );\n masterField.row.classList.add('ai-master');\n masterField.input.dataset.fk = 'ai-enabled';\n masterField.input.addEventListener('change', () => {\n session.draft = { ...session.draft, enabled: masterField.input.checked };\n });\n\n const toolbarField = ctx.makeCheckboxRow(\n 'Show AI button on the toolbar',\n 'Opens the AI actions. While AI is off, it offers to turn AI on and set it up.',\n session.draft.showToolbarButton,\n );\n toolbarField.input.dataset.fk = 'ai-toolbar-button';\n toolbarField.input.addEventListener('change', () => {\n session.draft = { ...session.draft, showToolbarButton: toolbarField.input.checked };\n });\n\n const activityField = ctx.makeCheckboxRow(\n 'AI Activity',\n 'Shows exactly what each AI request sent and received. Kept in memory for this window only; turning it off clears it.',\n session.draft.activityPanel,\n );\n activityField.row.classList.add('ai-activity-setting');\n activityField.input.dataset.fk = 'ai-activity-panel';\n // \"Open\" follows the switch at once, before Save. The panel says so if it is not recording yet.\n const activityOpen = button('ai-link-btn ai-activity-open', 'Open', { fk: 'ai-activity:open', ariaLabel: 'Open AI Activity' });\n activityOpen.hidden = !session.draft.activityPanel;\n activityOpen.addEventListener('click', () => opts.openActivityPanel?.());\n if (opts.openActivityPanel) {activityField.row.insertBefore(activityOpen, activityField.input);}\n activityField.input.addEventListener('change', () => {\n session.draft = { ...session.draft, activityPanel: activityField.input.checked };\n activityOpen.hidden = !activityField.input.checked;\n });\n\n const cloudField = ctx.makeCheckboxRow(\n 'Allow cloud engines',\n 'Lets tasks use engines outside this network, such as Anthropic or OpenAI. Local engines never need it.',\n session.draft.allowCloud,\n );\n cloudField.input.dataset.fk = 'ai-allow-cloud';\n // What happens to the text, with the policies of the cloud engines set up\n // so far. Only promise a consent step when the host asks for one (OQ9).\n cloudField.row.append(privacyCard(session.draft.engines.map((e) => ({ policy: aiProviderPolicy(e) })), {\n openLink: ctx.openLink,\n extra: aiConsentStepNote(!!session.ai.requestCloudConsent),\n className: 'ai-row-note',\n }));\n cloudField.input.addEventListener('change', () => {\n session.draft = { ...session.draft, allowCloud: cloudField.input.checked };\n renderEngines();\n });\n\n // ── Cloud consents (only when the host stores answers it can list) ────────\n const listConsents = session.ai.listConsents?.bind(session.ai);\n const forgetConsent = session.ai.forgetConsent?.bind(session.ai);\n const consentsRow = ctx.makeRow('Cloud consents', 'Cloud engines you have allowed or refused here. Forget an answer to be asked again.');\n consentsRow.classList.add('ai-section');\n const consentsBody = el('div', 'ai-consents');\n consentsRow.append(consentsBody);\n\n function engineNameFor(engineId: string): string {\n const engine = session.draft.engines.find((e) => e.id === engineId);\n return engine ? engineDisplayName(engine) : engineId;\n }\n\n function renderConsents(records: AiConsentRecord[], problem?: string): void {\n keepFocus(consentsBody, () => {\n consentsBody.replaceChildren();\n if (problem) {consentsBody.append(note('error', problem));}\n if (records.length === 0) {\n if (!problem) {consentsBody.append(el('div', 'ai-consents-empty', AI_NO_CONSENTS_TEXT));}\n return;\n }\n const list = el('ul', 'ai-consents-list');\n list.setAttribute('aria-label', 'Cloud consents');\n for (const record of records) {\n const name = engineNameFor(record.engineId);\n const item = el('li', 'ai-consent');\n const forget = button('settings-btn settings-btn--secondary ai-consent-forget', 'Forget', { ariaLabel: `Forget the answer for ${name}`, fk: `consent-forget:${record.engineId}` });\n forget.addEventListener('click', () => {\n forget.disabled = true;\n void forgetConsent?.(record.engineId).then(\n () => {\n opts.onConsentForgotten?.(record.engineId);\n announce(`Forgot the answer for ${name}.`);\n return refreshConsents();\n },\n (err: unknown) => refreshConsents(toAiError(err).message),\n );\n });\n item.append(el('span', 'ai-consent-text', aiConsentSummary(record, name)), forget);\n list.append(item);\n }\n consentsBody.append(list);\n });\n }\n\n async function refreshConsents(problem?: string): Promise<void> {\n if (!listConsents) {return;}\n try {\n renderConsents(await listConsents(), problem);\n } catch (err) {\n renderConsents([], toAiError(err).message);\n }\n }\n\n // ── Engines (summary) ─────────────────────────────────────────────────────\n const enginesRow = ctx.makeRow('Engines', 'Servers that run the models. Local engines keep your text on this network.');\n enginesRow.classList.add('ai-section');\n const enginesBody = el('div', 'ai-engines-body');\n enginesRow.append(enginesBody);\n\n function openPage(initial?: AiEnginesPageRequest['initial']): void {\n // \"Enable AI features\" ticked but not saved yet: the page saves it with the engines (Q2).\n const pendingEnable = session.draft.enabled && !session.original.enabled;\n opts.openEnginesPage?.({\n initial,\n session: { ...session.fork(), pendingEnable },\n onDone: (patch, saved) => {\n session.absorb(saved, patch);\n cloudField.input.checked = session.draft.allowCloud;\n masterField.input.checked = session.draft.enabled;\n renderEngines();\n if (Object.keys(patch).length > 0) {announce('Engines and tasks saved.');}\n },\n });\n }\n\n // ── Documentation bases (the page has the list) ───────────────────────────\n const basesRow = ctx.makeRow('Documentation bases', 'Folders of markdown the AI can answer from.', 'inline');\n basesRow.classList.add('ai-section');\n const basesOpen = button('settings-btn settings-btn--secondary', 'Manage bases…', { fk: 'manage-bases' });\n basesOpen.addEventListener('click', () => openPage({ section: 'bases' }));\n basesRow.append(basesOpen);\n\n function renderEngines(): void {\n keepFocus(enginesBody, () => {\n enginesBody.replaceChildren();\n const draft = session.draft;\n if (draft.engines.length === 0) {\n const empty = el('div', 'ai-summary-empty');\n empty.append(\n el('div', 'ai-empty-title', 'No engines yet'),\n el('div', 'ai-empty-text', `Two ways to connect: paste a cloud API key, or run models on your own machine.${draft.enabled ? '' : ' Nothing is sent until AI is on.'}`),\n );\n enginesBody.append(empty);\n } else {\n const list = el('div', 'ai-engines ai-engines--compact');\n list.setAttribute('role', 'list');\n list.setAttribute('aria-label', 'Engines');\n for (const engine of draft.engines) {list.append(buildEngineItem(engine));}\n enginesBody.append(list, buildRouteLine());\n }\n const manage = button('settings-btn settings-btn--secondary ai-manage-btn', draft.engines.length === 0 ? 'Add engine…' : 'Manage engines…', { fk: 'manage-engines' });\n manage.addEventListener('click', () => openPage());\n const actions = el('div', 'ai-summary-actions');\n actions.append(manage);\n enginesBody.append(actions);\n });\n }\n\n function buildEngineItem(engine: AiEngineConfig): HTMLElement {\n const item = el('div', 'ai-engine ai-engine--compact');\n item.setAttribute('role', 'listitem');\n item.dataset.engineId = engine.id;\n item.classList.toggle('is-disabled', !engine.enabled);\n const name = engineDisplayName(engine);\n\n const head = el('div', 'ai-engine-head');\n const glyph = el('span', 'ai-engine-glyph');\n glyph.innerHTML = kindGlyphHtml(engine.kind, 'ai-glyph--sm');\n // The name opens the page on this engine, like a list of services.\n const open = button('ai-engine-main ai-engine-open', '', { ariaLabel: `${name}: open in AI Engines`, fk: `eng:${engine.id}:open` });\n const titleLine = el('span', 'ai-engine-title');\n titleLine.append(el('span', 'ai-engine-name', name), ...localityPills(engine, session.draft));\n open.title = engineKindLabel(engine.kind);\n open.append(titleLine);\n open.addEventListener('click', () => openPage({ engineId: engine.id }));\n\n const enabled = switchInput(engine.enabled, `Enable ${name}`, `eng:${engine.id}:enabled-row`);\n enabled.addEventListener('change', () => {\n session.updateEngine(engine.id, { enabled: enabled.checked });\n renderEngines();\n });\n\n const actions = el('div', 'ai-engine-actions');\n actions.append(statusBadge(session.statuses.get(engine.id), undefined, { compact: true }), enabled);\n head.append(glyph, open, actions);\n item.append(head);\n return item;\n }\n\n /** \"Default model: oMLX (Mac Studio) · Qwen 3.8 Flash Next Change…\" */\n function buildRouteLine(): HTMLElement {\n const draft = session.draft;\n const line = el('div', 'ai-route-line');\n const labelId = nextId('ai-route-line');\n const label = el('span', 'ai-route-line-label', 'Default model');\n label.id = labelId;\n const value = el('span', 'ai-route-line-value', draft.routing.default ? routeLabel(draft, draft.routing.default) : 'None set');\n value.classList.toggle('is-none', !draft.routing.default);\n const change = button('ai-link-btn', 'Change…', { fk: 'route:change', ariaLabel: 'Change the default model' });\n change.setAttribute('aria-describedby', labelId);\n change.addEventListener('click', () => openPage({ section: 'routing' }));\n line.append(label, value, change);\n const n = draft.routing.default\n ? taskRouteNote({ ...draft, routing: { ...draft.routing, tasks: {} } }, session.statusList(), 'chat')\n : { level: 'info' as const, text: 'Tasks have nowhere to go until a default model is set.' };\n if (n) {line.append(note(n.level, n.text, 'ai-row-note'));}\n return line;\n }\n\n // ── Features ──────────────────────────────────────────────────────────────\n // One switch per feature. On tier 2 the task each feature routes through\n // is under \"Advanced: task per feature\" (U8): most people never change it.\n\n const featuresRow = ctx.makeRow('Features', 'Turn each feature on or off. A feature that is off disappears from the menus, and its commands and shortcuts say so instead of running.');\n featuresRow.classList.add('ai-section');\n const featureRows: HTMLElement[] = [];\n const taskRows: HTMLElement[] = [];\n for (const def of AI_FEATURES) {\n const planned = def.status === 'planned';\n const resolved = resolveAiFeature(session.draft.features, def.id);\n const row = el('div', 'settings-row settings-row--inline ai-feature');\n row.classList.toggle('is-planned', planned);\n const text = el('div', 'settings-row-text');\n const labelId = nextId('ai-feature');\n const lbl = el('span', 'settings-label', def.label);\n lbl.id = labelId;\n text.append(lbl, el('span', 'settings-desc', def.description));\n const controls = el('div', 'ai-feature-controls');\n let options: HTMLElement | null = null;\n if (planned) {\n controls.append(el('span', 'ai-pill ai-pill--soon', 'Coming later'));\n row.setAttribute('aria-disabled', 'true');\n } else {\n if (tier === 2) {taskRows.push(buildTaskRow(def));}\n const toggle = switchInput(resolved.enabled, def.label, `feature:${def.id}:enabled`);\n toggle.setAttribute('aria-labelledby', labelId);\n toggle.removeAttribute('aria-label');\n toggle.addEventListener('change', () => {\n const draft = session.draft;\n session.draft = { ...draft, features: { ...draft.features, [def.id]: { ...(draft.features[def.id] ?? {}), enabled: toggle.checked } } };\n });\n controls.append(toggle);\n if (def.id === 'ghostText') {options = buildGhostOptions(toggle, text);}\n }\n row.append(text, controls);\n featureRows.push(row);\n if (options) {featureRows.push(options);}\n }\n featuresRow.append(ctx.makeGroup(...featureRows));\n if (taskRows.length > 0) {featuresRow.append(...buildTaskDisclosure(taskRows));}\n\n /** One feature's task picker: \"Default task (Rewrite)\" or another task's route. */\n function buildTaskRow(def: (typeof AI_FEATURES)[number]): HTMLElement {\n const defaultTask = getAiTask(def.defaultTask);\n const row = el('div', 'settings-row settings-row--inline ai-feature-task');\n const labelId = nextId('ai-feature-task');\n const lbl = el('span', 'settings-label', def.label);\n lbl.id = labelId;\n const select = el('select', 'settings-input settings-input--small');\n select.dataset.fk = `feature:${def.id}:task`;\n select.setAttribute('aria-label', `Task route for ${def.label}`);\n const dflt = el('option', '', `Default task (${defaultTask?.label ?? def.defaultTask})`);\n dflt.value = '';\n select.append(dflt);\n for (const task of AI_TASKS) {\n if (task.hostMethod) {continue;}\n const o = el('option', '', task.label);\n o.value = task.id;\n select.append(o);\n }\n const saved = session.draft.features[def.id]?.task;\n if (saved && !AI_TASKS.some((t) => t.id === saved)) {\n const o = el('option', '', saved);\n o.value = saved;\n select.append(o);\n }\n select.value = saved ?? '';\n select.addEventListener('change', () => {\n const draft = session.draft;\n const entry = { ...(draft.features[def.id] ?? {}) };\n if (select.value) {entry.task = select.value;} else {delete entry.task;}\n session.draft = { ...draft, features: { ...draft.features, [def.id]: entry } };\n });\n row.append(lbl, select);\n return row;\n }\n\n /**\n * Inline suggestions' own knobs, folded under its row while the feature is\n * on, saved into `features.ghostText` like the switch. Tier 1 hosts route by\n * themselves, so \"Local engines only\" could not be honoured there and is\n * left out, with the privacy line that goes with it.\n */\n function buildGhostOptions(enabled: HTMLInputElement, rowText: HTMLElement): HTMLElement {\n const saved = ghostTextOptions(session.draft.features);\n const patch = (change: (entry: AiFeatureSetting) => void): void => {\n const draft = session.draft;\n const entry = { ...(draft.features.ghostText ?? {}) };\n change(entry);\n session.draft = { ...draft, features: { ...draft.features, ghostText: entry } };\n };\n\n const numberRow = (label: string, hint: string, key: 'delayMs' | 'maxTokens', value: number, range: { min: number; max: number; step: number; dflt: number }): HTMLElement => {\n const row = ctx.makeRow(label, hint, 'inline');\n const input = el('input', 'settings-input settings-input--small settings-input--short');\n input.type = 'number';\n input.min = String(range.min);\n input.max = String(range.max);\n input.step = String(range.step);\n input.value = String(value);\n input.dataset.fk = `feature:ghostText:${key}`;\n input.setAttribute('aria-label', label);\n input.addEventListener('change', () => {\n const typed = Number(input.value);\n if (input.value.trim() === '' || !Number.isFinite(typed)) {\n // Blank: back to the default, with the key gone rather than saved.\n patch((entry) => { delete entry[key]; });\n input.value = String(range.dflt);\n return;\n }\n const next = Math.min(range.max, Math.max(range.min, Math.round(typed)));\n patch((entry) => { entry[key] = next; });\n input.value = String(next);\n });\n row.append(input);\n return row;\n };\n const delay = numberRow('Delay (ms)', 'How long you pause before a suggestion is requested.', 'delayMs', saved.delayMs, { min: GHOST_DELAY_MS_MIN, max: GHOST_DELAY_MS_MAX, step: 50, dflt: GHOST_DELAY_MS_DEFAULT });\n const tokens = numberRow('Max tokens', 'The longest suggestion a model may write.', 'maxTokens', saved.maxTokens, { min: GHOST_MAX_TOKENS_MIN, max: GHOST_MAX_TOKENS_MAX, step: 1, dflt: GHOST_MAX_TOKENS_DEFAULT });\n\n const triggerRow = ctx.makeRow('Trigger', 'Automatic suggests as you pause. Manual shortcut suggests only when you press the shortcut.', 'inline');\n const trigger = el('select', 'settings-input settings-input--small');\n trigger.dataset.fk = 'feature:ghostText:trigger';\n trigger.setAttribute('aria-label', 'Trigger');\n for (const [value, label] of [['auto', 'Automatic'], ['manual', 'Manual shortcut']] as const) {\n const o = el('option', '', label);\n o.value = value;\n trigger.append(o);\n }\n trigger.value = saved.trigger;\n trigger.addEventListener('change', () => {\n patch((entry) => { entry.trigger = trigger.value === 'manual' ? 'manual' : 'auto'; });\n });\n triggerRow.append(trigger);\n\n const panelId = nextId('ai-ghost-options');\n const toggle = button('ai-disclosure ai-ghost-options-toggle', 'Options', { html: ICONS.chevron, fk: 'feature:ghostText:options', ariaLabel: 'Inline suggestions options' });\n toggle.setAttribute('aria-expanded', 'false');\n toggle.setAttribute('aria-controls', panelId);\n const panel = el('div', 'ai-advanced ai-ghost-options');\n panel.id = panelId;\n panel.hidden = true;\n toggle.addEventListener('click', () => {\n panel.hidden = !panel.hidden;\n toggle.setAttribute('aria-expanded', String(!panel.hidden));\n });\n const group = ctx.makeGroup(delay, tokens, triggerRow);\n panel.append(group);\n\n let line: HTMLElement | null = null;\n let localOnly: HTMLInputElement | null = null;\n const syncVisible = (): void => {\n box.hidden = !enabled.checked;\n if (line) {line.hidden = !enabled.checked || !!localOnly?.checked;}\n };\n if (tier === 2) {\n const localRow = ctx.makeRow('Local engines only', 'Never sends suggestions to a cloud engine, even when one is set for this task.', 'inline');\n localOnly = switchInput(saved.localOnly, 'Local engines only', 'feature:ghostText:localOnly');\n const onlyLocal = localOnly;\n onlyLocal.addEventListener('change', () => {\n patch((entry) => { entry.localOnly = onlyLocal.checked; });\n syncVisible();\n });\n localRow.append(onlyLocal);\n group.append(localRow);\n\n line = privacyLine(() => openPage());\n // The fuller card is on the AI Engines page; a host without one has only the line.\n if (!canManage) {line.querySelector('button')?.remove();}\n rowText.append(line);\n }\n\n const box = el('div', 'settings-row ai-ghost-options-box');\n box.append(toggle, panel);\n enabled.addEventListener('change', syncVisible);\n syncVisible();\n return box;\n }\n\n /** \"Advanced: task per feature\", closed until opened; a feature can use another task's model. */\n function buildTaskDisclosure(taskRowsIn: HTMLElement[]): HTMLElement[] {\n const panelId = nextId('ai-feature-tasks');\n const toggle = button('ai-disclosure ai-feature-tasks-toggle', 'Advanced: task per feature', { html: ICONS.chevron, fk: 'features:advanced' });\n toggle.setAttribute('aria-expanded', 'false');\n toggle.setAttribute('aria-controls', panelId);\n const panel = el('div', 'ai-advanced ai-feature-tasks');\n panel.id = panelId;\n panel.hidden = true;\n panel.append(el('div', 'settings-desc', 'Each feature uses its own task’s model (see Tasks on the AI Engines page). Pick another task to borrow its model.'), ctx.makeGroup(...taskRowsIn));\n toggle.addEventListener('click', () => {\n panel.hidden = !panel.hidden;\n toggle.setAttribute('aria-expanded', String(!panel.hidden));\n });\n return [toggle, panel];\n }\n\n // ── Local networks ────────────────────────────────────────────────────────\n // A power-user list (tier 2 only): extra ranges and host-name suffixes that\n // count as local, so an engine there needs no Allow cloud. The host saves\n // it to user settings only; a repo cannot widen it.\n\n const localNetsRow = ctx.makeRow('Local networks', 'Networks and host names that count as local, so an engine there never needs Allow cloud.');\n localNetsRow.classList.add('ai-section');\n {\n const panelId = nextId('ai-local-networks');\n const toggle = button('ai-disclosure ai-local-networks-toggle', 'Advanced: local networks', { html: ICONS.chevron, fk: 'local-networks:advanced' });\n toggle.setAttribute('aria-expanded', 'false');\n toggle.setAttribute('aria-controls', panelId);\n const panel = el('div', 'ai-advanced ai-local-networks');\n panel.id = panelId;\n panel.hidden = true;\n\n const area = el('textarea', 'settings-input ai-mono ai-overrides-text');\n area.rows = 4;\n area.spellcheck = false;\n area.dataset.fk = 'ai-local-networks';\n area.placeholder = '10.0.98.0/24\\n.ts.net';\n area.value = session.draft.localNetworks.join('\\n');\n area.setAttribute('aria-label', 'Local networks, one per line');\n const err = el('div', 'ai-field-error');\n err.id = nextId('ai-local-networks-error');\n err.setAttribute('aria-live', 'polite');\n area.setAttribute('aria-describedby', err.id);\n area.addEventListener('input', () => {\n const parsed = parseLocalNetworksText(area.value);\n if (!parsed.ok) {\n err.textContent = parsed.error;\n area.setAttribute('aria-invalid', 'true');\n return;\n }\n err.textContent = '';\n area.removeAttribute('aria-invalid');\n session.draft = { ...session.draft, localNetworks: parsed.value };\n if (canManage) {renderEngines();}\n });\n // Leaving the field shows what was kept: normalized, or the defaults when blank.\n area.addEventListener('blur', () => {\n if (area.getAttribute('aria-invalid') !== 'true') {area.value = session.draft.localNetworks.join('\\n');}\n });\n panel.append(\n el('div', 'settings-desc', 'One per line. An IPv4 range such as 10.0.98.0/24 (a WireGuard network, say) or a host-name suffix such as .ts.net. Loopback, link-local, .local, .lan and .home.arpa always count. Leave it blank for the defaults (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). Saved to your user settings only, never to a folder.'),\n area,\n err,\n );\n toggle.addEventListener('click', () => {\n panel.hidden = !panel.hidden;\n toggle.setAttribute('aria-expanded', String(!panel.hidden));\n });\n localNetsRow.append(toggle, panel);\n }\n\n // ── Assemble ──────────────────────────────────────────────────────────────\n\n // Intro, master switch, Engines (with the default model), Allow cloud and\n // its consents, the toolbar button, AI Activity, Features (U8).\n rows.push(masterField.row);\n if (tier === 2) {\n if (canManage) {\n rows.push(enginesRow);\n renderEngines();\n if (opts.docsAvailable) {rows.push(basesRow);}\n }\n rows.push(cloudField.row);\n if (listConsents && forgetConsent) {\n rows.push(consentsRow);\n void refreshConsents();\n }\n }\n rows.push(toolbarField.row, activityField.row, featuresRow);\n if (tier === 2) {rows.push(localNetsRow);}\n rows.push(live);\n\n // Statuses pushed while the tab is open refresh the dots in place.\n const unsubscribe = canManage ? opts.subscribeStatuses?.((list) => {\n if (!enginesRow.isConnected) {return;}\n for (const s of list) {session.statuses.set(s.engineId, s);}\n renderEngines();\n }) : undefined;\n\n // Fresh statuses as the tab opens: the dots should not be stale.\n if (canManage) {\n void session.refreshStatuses().then((ok) => {\n if (ok && enginesRow.isConnected) {renderEngines();}\n });\n }\n\n const close = () => {\n window.clearTimeout(liveTimer);\n unsubscribe?.();\n };\n\n return {\n rows,\n collect: () => session.collect(),\n onDiscarded: () => {\n close();\n session.discard();\n },\n onSaved: () => {\n close();\n opts.onSaved(session.commit());\n },\n };\n}\n","/**\n * The toolbar's AI button: when it shows, what a click opens, and the small\n * first-run panel it opens while AI is off.\n *\n * The button shows only for a host with an AI adapter (`host.ai` and the\n * `ai` feature) and while `ai.showToolbarButton` is on. With AI off, a click\n * opens the first-run panel: the title, one line of what AI does, the\n * Experimental badge and disclaimer, and Cancel plus one primary button. The disclaimer is one sentence with the full notice behind a link. On\n * a host that can look for local servers (`host.ai.detectLocalServers`) the\n * panel looks while it is open: a running server makes the primary button\n * \"Use LM Studio\" (one click: engine, models, default route, AI on) with\n * \"Set up another way…\" beside it, and one privacy line whose \"Learn more\"\n * opens the AI Engines page too; otherwise the primary is \"Set up\", which\n * opens the AI Engines page (on the setup wizard while there is no engine\n * yet), and AI turns on only at its Done (B3). A tier-1\n * host routes by itself: its button is \"Turn on\" and lands on the AI tab.\n * With AI on, a click opens a menu of every AI action (the same list as the\n * context menu's `AI` submenu, plus Chat…), a Thinking row when the routed model can\n * think, \"AI Activity…\" while `ai.activityPanel` is on, and \"Manage engines…\".\n *\n * Toolbar chrome only: nothing here touches the editor document or its DOM.\n */\n\nimport type { AiSettings, AiThinkingChoice, AiThinkingLevel } from './ai';\nimport type { AiHostTier } from './ai-settings-model';\nimport { AI_EXPERIMENTAL_DISCLAIMER, button, el, experimentalBadge, nextId, privacyLine } from './ai-settings-dom';\nimport { AI_DETECT_LOOKING } from './ai-local-setup';\nimport { getPortal } from './portal';\nimport type { ToolbarDropdownEntry } from './toolbar-dropdown';\n\nexport { aiToolbarButtonMode, type AiToolbarButtonMode } from './ai-lite';\n\n/** The patch \"Turn on\" (tier 1) sends through `host.saveSettings`. Tier 2 turns AI on at the Engines page's Done instead. */\nexport const AI_TURN_ON_PATCH = { 'ai.enabled': true } as const;\n\n/** Where \"Set up\" (or \"Turn on\") lands. */\nexport type AiSetupTarget =\n | { kind: 'page'; engineId: string }\n | { kind: 'wizard' }\n | { kind: 'tab' };\n\n/**\n * \"Set up\": a tier-2 host opens the AI Engines page on the default route's\n * engine (its Express form), else the first engine; with no engine yet, the\n * page opens on the setup wizard (M1b). A tier-1 host routes by itself, so\n * it gets the AI tab and never the wizard.\n */\nexport function aiSetupTarget(tier: AiHostTier, settings: Pick<AiSettings, 'engines' | 'routing'>): AiSetupTarget {\n if (tier !== 2) {return { kind: 'tab' };}\n const byRoute = settings.routing.default?.engineId;\n const engineId = byRoute && settings.engines.some((e) => e.id === byRoute) ? byRoute : settings.engines[0]?.id;\n return engineId ? { kind: 'page', engineId } : { kind: 'wizard' };\n}\n\n// ── The menu (AI on) ────────────────────────────────────────────────────────\n\n/** An AI menu entry: enabled, or disabled with the reason as its hint; null leaves it out. */\nexport type AiToolbarEntryState = { enabled: true; hint?: string } | { enabled: false; hint: string } | null;\n\nexport interface AiToolbarMenuInput {\n /** Rewrite selection: null leaves it out (read-only), otherwise enabled or disabled with a hint. */\n rewrite: AiToolbarEntryState;\n /** \"Explain selection\": absent or null leaves it out. */\n explain?: AiToolbarEntryState;\n /** \"Translate…\" (the selection, or the whole document without one): absent or null leaves it out. */\n translate?: AiToolbarEntryState;\n /** \"Suggest continuation\" (an inline suggestion at the caret): absent or null leaves it out. An enabled hint is why the last one failed. */\n continuation?: AiToolbarEntryState;\n /**\n * The \"Inline suggestions\" switch beside it, with its state: absent or null\n * leaves it out. A click flips it at once and saves; the menu closes.\n */\n inlineSuggestions?: { on: boolean } | null;\n /** \"Summarize document…\": absent or null leaves it out. A disabled hint carries the router's reason (D15). */\n summarize?: AiToolbarEntryState;\n /** \"Suggest titles…\": absent or null leaves it out. */\n titles?: AiToolbarEntryState;\n /** \"Suggest properties\" (the sidebar's Suggest): absent or null leaves it out. */\n properties?: AiToolbarEntryState;\n /** \"Chat…\" (the chat panel): absent or null leaves it out. */\n chat?: AiToolbarEntryState;\n /**\n * The Thinking row near the bottom (it reads as a setting): Default plus\n * the levels the routed model's kind can express. Absent hides it (no\n * model that can think).\n */\n thinking?: AiToolbarThinkingRow;\n /** True for a host with an engine registry (\"Manage engines…\"); otherwise \"AI settings…\". */\n canManageEngines: boolean;\n icons: { rewrite: string; manage: string; explain?: string; translate?: string; continuation?: string; summarize?: string; titles?: string; properties?: string; activity?: string; chat?: string };\n onRewrite(): void;\n onExplain?(): void;\n onTranslate?(): void;\n onSuggestContinuation?(): void;\n /** Flip Inline suggestions to `next`. */\n onToggleInlineSuggestions?(next: boolean): void;\n onSummarize?(): void;\n onSuggestTitles?(): void;\n onSuggestProperties?(): void;\n onChat?(): void;\n onManage(): void;\n /** \"AI Activity…\". Absent (the setting is off): no such entry. The menu is built each time it opens, so it follows the setting. */\n onActivity?(): void;\n /** \"Look again\" under the status row: retest the engine the menu is waiting on. Absent: no such row. */\n onRetest?(): void;\n}\n\nexport interface AiToolbarThinkingRow {\n /** `thinkingChoices(kind)` for the routed model (non-empty). */\n choices: AiThinkingChoice[];\n /** The remembered level; null is Default (the model's own). */\n value(): AiThinkingLevel | null;\n onChange(level: AiThinkingLevel | null): void;\n}\n\nconst THINKING_DEFAULT = 'default';\n\n/** The menu's Thinking row: the popover dial's pill, with Default first. */\nfunction thinkingRowEntry(row: AiToolbarThinkingRow): ToolbarDropdownEntry {\n // The dial's labels: Medium shortened to Med.\n const short = (label: string): string => (label === 'Medium' ? 'Med' : label);\n return {\n type: 'segmented',\n id: 'ai-thinking',\n label: 'Thinking',\n title: 'Thinking level for the next AI requests',\n options: [\n { value: THINKING_DEFAULT, label: 'Default', title: 'Thinking: the model\\'s default', spoken: 'Default' },\n ...row.choices.map((c) => ({ value: c.level, label: short(c.label), title: `Thinking: ${c.label}`, spoken: c.label })),\n ],\n value: () => row.value() ?? THINKING_DEFAULT,\n onChange: (v) => row.onChange(v === THINKING_DEFAULT ? null : v as AiThinkingLevel),\n classes: { group: 'ai-rw-think', label: 'ai-rw-think-label', segment: 'ai-rw-think-seg' },\n };\n}\n\n/** The per-item hint that differs by selection, so it never counts as one shared reason. */\nconst SELECT_TEXT_HINT = 'Select text first';\n\nconst UNREACHABLE_REASON = /could not reach|no answer|timed out|ECONNREFUSED|ENOTFOUND|EHOSTUNREACH|fetch failed|connection refused/i;\n\n/**\n * A short status line for a reason shared by several disabled items: \"oMLX\n * isn't reachable\" with the full reason as its muted second line, or the\n * reason as is when it has no better short form.\n */\nexport function aiMenuStatusLine(reason: string): { label: string; detail?: string } {\n const failed = /^(.+?) failed its last connection test/.exec(reason);\n if (!failed) {return { label: reason };}\n return UNREACHABLE_REASON.test(reason)\n ? { label: `${failed[1]} isn't reachable`, detail: reason }\n : { label: `${failed[1]} failed its last connection test`, detail: reason.slice(failed[0].length).replace(/^[:.\\s]+/, '') || undefined };\n}\n\n/** The reason two or more disabled items share (not \"Select text first\"), or null. */\nfunction sharedDisabledReason(states: readonly (AiToolbarEntryState | undefined)[]): string | null {\n const counts = new Map<string, number>();\n for (const state of states) {\n if (state && !state.enabled && state.hint !== SELECT_TEXT_HINT) {counts.set(state.hint, (counts.get(state.hint) ?? 0) + 1);}\n }\n let best: string | null = null;\n for (const [hint, n] of counts) {\n if (n >= 2 && (best === null || n > counts.get(best)!)) {best = hint;}\n }\n return best;\n}\n\n/**\n * The AI menu: one flat list, the same as the context menu's `AI` submenu\n * and the commands (U1): the selection actions, the document actions, the\n * Thinking row, then AI Activity… and Manage engines…. No submenus (D14).\n */\nexport function aiToolbarMenuEntries(input: AiToolbarMenuInput): ToolbarDropdownEntry[] {\n const entries: ToolbarDropdownEntry[] = [];\n const separate = (): void => {\n if (entries.length > 0 && entries[entries.length - 1].type !== 'separator') {entries.push({ type: 'separator' });}\n };\n // A reason several items share (an engine that cannot be reached) shows once\n // as a status row on top; the items just grey out.\n const shared = sharedDisabledReason([input.rewrite, input.explain, input.translate, input.continuation, input.summarize, input.titles, input.properties, input.chat]);\n if (shared) {\n const { label, detail } = aiMenuStatusLine(shared);\n entries.push({ type: 'status', id: 'ai-status', label, ...(detail ? { detail } : {}) });\n if (input.onRetest) {\n entries.push({ type: 'action', id: 'ai-retest', label: 'Look again', action: () => input.onRetest?.() });\n }\n entries.push({ type: 'separator' });\n }\n const add = (id: string, label: string, icon: string | undefined, state: AiToolbarEntryState | undefined, run: () => void): void => {\n if (!state) {return;}\n entries.push({\n type: 'action',\n id,\n label,\n icon: icon ?? input.icons.rewrite,\n hint: state.hint === shared ? undefined : state.hint,\n isDisabled: () => !state.enabled,\n action: run,\n });\n };\n add('ai-rewrite', 'Rewrite selection', input.icons.rewrite, input.rewrite, () => input.onRewrite());\n add('ai-explain', 'Explain selection', input.icons.explain, input.explain, () => input.onExplain?.());\n add('ai-translate', 'Translate…', input.icons.translate, input.translate, () => input.onTranslate?.());\n add('ai-continuation', 'Suggest continuation', input.icons.continuation, input.continuation, () => input.onSuggestContinuation?.());\n if (input.inlineSuggestions) {\n const { on } = input.inlineSuggestions;\n entries.push({\n type: 'action',\n id: 'ai-inline-suggestions',\n label: 'Inline suggestions',\n icon: input.icons.continuation ?? input.icons.rewrite,\n hint: on ? 'On' : 'Off',\n isActive: () => on,\n action: () => input.onToggleInlineSuggestions?.(!on),\n });\n }\n separate();\n add('ai-summarize', 'Summarize document…', input.icons.summarize, input.summarize, () => input.onSummarize?.());\n add('ai-titles', 'Suggest titles…', input.icons.titles, input.titles, () => input.onSuggestTitles?.());\n add('ai-properties', 'Suggest properties', input.icons.properties, input.properties, () => input.onSuggestProperties?.());\n separate();\n add('ai-chat', 'Chat…', input.icons.chat, input.chat, () => input.onChat?.());\n if (input.thinking && input.thinking.choices.length > 0) {\n separate();\n entries.push(thinkingRowEntry(input.thinking));\n }\n separate();\n if (input.onActivity) {\n entries.push({\n type: 'action',\n id: 'ai-activity',\n label: 'AI Activity…',\n icon: input.icons.activity ?? input.icons.manage,\n action: () => input.onActivity?.(),\n });\n }\n entries.push({\n type: 'action',\n id: 'ai-manage',\n label: input.canManageEngines ? 'Manage engines…' : 'AI settings…',\n icon: input.icons.manage,\n action: () => input.onManage(),\n });\n return entries;\n}\n\n// ── The first-run panel (AI off) ────────────────────────────────────────────\n\n/** What local server detection found, for the panel. */\nexport type AiFirstRunDetection =\n /** A server is running and not set up yet: the primary button offers it. */\n | { kind: 'found'; presetId: string; name: string; models?: number }\n /** Nothing answered: say so, with where to go instead. */\n | { kind: 'none' }\n /** Nothing new to offer (a running server is already set up, or detection failed): say nothing. */\n | { kind: 'quiet' };\n\nexport interface AiFirstRunPanelOptions {\n anchor: HTMLElement;\n /** 1: the host routes by itself, so the button only turns AI on (\"Turn on\"). Default 2 (\"Set up\"). */\n tier?: AiHostTier;\n /** \"Set up\" (or \"Turn on\", or \"Set up another way…\"). The panel is already closed. */\n onTurnOn(): void;\n /** Look for local servers while the panel is open. Aborted when it closes. */\n detect?(signal: AbortSignal): Promise<AiFirstRunDetection>;\n /** \"Use LM Studio\": set it up and turn AI on. Rejects with an Error whose message the panel shows. */\n onUseLocal?(presetId: string): Promise<void>;\n}\n\nexport interface AiFirstRunPanelHandle {\n readonly element: HTMLElement;\n /** Close without turning anything on. */\n close(): void;\n}\n\n/** The one line of verbs under the title (U9). */\nexport const AI_FIRST_RUN_VERBS = 'Rewrite, translate, explain, summarize, suggest titles and tags.';\n\n/** The panel's disclaimer in one sentence; \"Read the full notice\" reveals `AI_EXPERIMENTAL_DISCLAIMER`. */\nexport const AI_FIRST_RUN_NOTICE = 'AI features are experimental, and AI output can be wrong, so review it.';\n\n/** When no local server answered: lead with connecting a provider, local is the advanced option. */\nexport const AI_FIRST_RUN_NONE = 'Connect a provider you already use. Running models on this machine is under Advanced.';\n\n/** \"LM Studio is running on this computer, 3 models.\" */\nexport function aiDetectFoundText(name: string, models?: number): string {\n const count = models === undefined ? '' : `, ${models} ${models === 1 ? 'model' : 'models'}`;\n return `${name} is running on this computer${count}.`;\n}\n\nlet openPanel: { element: HTMLElement; close(restore: boolean): void } | null = null;\n\nexport function isAiFirstRunPanelOpen(): boolean {\n return openPanel !== null;\n}\n\nexport function hideAiFirstRunPanel(): void {\n openPanel?.close(false);\n}\n\n/**\n * Open the panel under `anchor` (one at a time) and focus its primary button.\n * With `detect`, a quiet status line looks for local servers; when one is\n * running, the primary button becomes \"Use <name>\" and \"Set up another way…\"\n * opens setup as before.\n */\nexport function showAiFirstRunPanel(opts: AiFirstRunPanelOptions): AiFirstRunPanelHandle {\n hideAiFirstRunPanel();\n const { anchor } = opts;\n const tier1 = opts.tier === 1;\n const setUpLabel = tier1 ? 'Turn on' : 'Set up';\n\n const panel = el('div', 'ai-first-run');\n panel.setAttribute('role', 'dialog');\n const titleId = nextId('ai-first-run-title');\n const textId = nextId('ai-first-run-text');\n panel.setAttribute('aria-labelledby', titleId);\n panel.setAttribute('aria-describedby', textId);\n\n const head = el('div', 'ai-experimental-head');\n const title = el('span', 'ai-experimental-title', 'AI features');\n title.id = titleId;\n head.append(title, experimentalBadge());\n const verbs = el('p', 'ai-first-run-verbs', AI_FIRST_RUN_VERBS);\n const text = el('p', 'ai-disclaimer ai-first-run-notice', `${AI_FIRST_RUN_NOTICE} `);\n text.id = textId;\n const notice = button('ai-link-btn ai-first-run-notice-toggle', 'Read the full notice', { fk: 'ai-first-run:notice' });\n notice.setAttribute('aria-expanded', 'false');\n text.append(notice);\n const fullNotice = el('p', 'ai-disclaimer ai-first-run-notice-full', AI_EXPERIMENTAL_DISCLAIMER);\n fullNotice.id = nextId('ai-first-run-notice-full');\n fullNotice.hidden = true;\n notice.setAttribute('aria-controls', fullNotice.id);\n\n // Detection and setup progress: one quiet line, read out as it changes.\n const status = el('div', 'ai-first-run-status');\n status.setAttribute('role', 'status');\n status.setAttribute('aria-live', 'polite');\n status.hidden = true;\n\n const actions = el('div', 'ai-first-run-actions');\n const other = button('ai-link-btn ai-first-run-other', 'Set up another way…', { fk: 'ai-first-run:other' });\n other.hidden = true;\n const cancel = button('settings-btn settings-btn--secondary', 'Cancel', { fk: 'ai-first-run:cancel' });\n const primary = button('settings-btn settings-btn--primary', setUpLabel, { fk: 'ai-first-run:turn-on' });\n actions.append(other, cancel, primary);\n // Beside \"Set up another way…\" (which can lead to a cloud engine): local vs cloud in one line.\n const privacy = privacyLine(() => setUp());\n privacy.hidden = true;\n const learnMore = privacy.querySelector<HTMLButtonElement>('button')!;\n panel.append(head, verbs, text, fullNotice, status, privacy, actions);\n\n let found: Extract<AiFirstRunDetection, { kind: 'found' }> | null = null;\n let busy = false;\n const detectAbort = new AbortController();\n\n function setStatus(state: 'looking' | 'found' | 'none' | 'working' | 'error' | 'hidden', line = ''): void {\n status.hidden = state === 'hidden';\n status.dataset.state = state;\n status.replaceChildren();\n if (state === 'hidden') {return;}\n if (state === 'found') {\n const dot = el('span', 'ai-first-run-dot');\n dot.setAttribute('aria-hidden', 'true');\n status.append(dot);\n }\n status.append(el('span', '', line));\n }\n\n let closed = false;\n function close(restore: boolean): void {\n if (closed) {return;}\n closed = true;\n detectAbort.abort();\n document.removeEventListener('mousedown', onOutside, true);\n panel.removeEventListener('keydown', onKeydown);\n panel.remove();\n if (openPanel?.element === panel) {openPanel = null;}\n if (restore && anchor.isConnected) {anchor.focus({ preventScroll: true });}\n }\n\n function onOutside(e: MouseEvent): void {\n const target = e.target as Node;\n // The anchor toggles the panel itself. A setup in progress keeps it open.\n if (!busy && !panel.contains(target) && !anchor.contains(target)) {close(false);}\n }\n\n function onKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n if (!busy) {close(true);}\n } else if (e.key === 'Tab') {\n // Keep Tab on the panel's buttons.\n const order = [notice, learnMore, other, cancel, primary].filter((b) => !b.hidden && !b.closest('[hidden]') && !b.disabled);\n if (order.length === 0) {return;}\n e.preventDefault();\n const at = order.indexOf(document.activeElement as HTMLButtonElement);\n const next = at < 0 ? 0 : (at + (e.shiftKey ? order.length - 1 : 1)) % order.length;\n order[next].focus();\n }\n }\n\n function setUp(): void {\n close(false);\n opts.onTurnOn();\n }\n\n async function useLocal(server: Extract<AiFirstRunDetection, { kind: 'found' }>): Promise<void> {\n if (!opts.onUseLocal) {return;}\n busy = true;\n for (const b of [notice, learnMore, other, cancel, primary]) {b.disabled = true;}\n setStatus('working', `Setting up ${server.name}…`);\n try {\n await opts.onUseLocal(server.presetId);\n busy = false;\n close(true);\n } catch (err) {\n busy = false;\n if (closed) {return;}\n // Back to the plain panel: setup the long way is one click away.\n found = null;\n for (const b of [notice, learnMore, other, cancel, primary]) {b.disabled = false;}\n other.hidden = true;\n privacy.hidden = true;\n primary.textContent = setUpLabel;\n setStatus('error', err instanceof Error && err.message ? err.message : `${server.name} could not be set up.`);\n primary.focus({ preventScroll: true });\n }\n }\n\n notice.addEventListener('click', () => {\n fullNotice.hidden = !fullNotice.hidden;\n notice.setAttribute('aria-expanded', String(!fullNotice.hidden));\n notice.textContent = fullNotice.hidden ? 'Read the full notice' : 'Hide the full notice';\n position(panel, anchor);\n });\n cancel.addEventListener('click', () => close(true));\n other.addEventListener('click', () => setUp());\n primary.addEventListener('click', () => {\n if (found) {void useLocal(found);} else {setUp();}\n });\n panel.addEventListener('keydown', onKeydown);\n document.addEventListener('mousedown', onOutside, true);\n\n if (opts.detect && !tier1) {\n setStatus('looking', AI_DETECT_LOOKING);\n void opts.detect(detectAbort.signal).then(\n (result) => {\n if (closed || busy) {return;}\n if (result.kind === 'found' && opts.onUseLocal) {\n found = result;\n primary.textContent = `Use ${result.name}`;\n other.hidden = false;\n privacy.hidden = false;\n setStatus('found', aiDetectFoundText(result.name, result.models));\n } else if (result.kind === 'none') {\n setStatus('none', AI_FIRST_RUN_NONE);\n } else {\n setStatus('hidden');\n }\n position(panel, anchor);\n },\n () => { if (!closed && !busy) {setStatus('hidden');} },\n );\n }\n\n getPortal().appendChild(panel);\n position(panel, anchor);\n openPanel = { element: panel, close };\n primary.focus({ preventScroll: true });\n\n return { element: panel, close: () => close(true) };\n}\n\n/** Below the anchor (above when there is no room), inside the editor's box and the viewport. */\nfunction position(panel: HTMLElement, anchor: HTMLElement): void {\n const a = anchor.getBoundingClientRect();\n const p = panel.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const bounds = anchor.closest('.mikedown-root')?.getBoundingClientRect();\n const minLeft = Math.max(8, (bounds?.left ?? 0) + 8);\n const maxLeft = Math.min(vw, bounds?.right ?? vw) - p.width - 8;\n const left = Math.max(minLeft, Math.min(a.left + a.width / 2 - p.width / 2, maxLeft));\n const below = vh - a.bottom >= p.height + 6 || vh - a.bottom >= a.top;\n const top = below ? a.bottom + 6 : a.top - p.height - 6;\n panel.style.left = `${left}px`;\n panel.style.top = `${Math.max(8, Math.min(top, vh - p.height - 8))}px`;\n}\n","/**\n * The AI activity recorder: what each completion sent and what came back,\n * kept in memory for this editor instance only (the activity panel reads it).\n *\n * - One `AiActivityLog` per editor instance; `runAiCompletion` writes to it\n * through `AiRunContext.activity`. Nothing is persisted, and the hosts'\n * own request logs stay metadata only.\n * - Off by default (`ai.activityPanel`). While off, `record` retains nothing\n * and `update` on an unknown entry is a no-op, so the setting can flip in\n * the middle of a request. Turning it off clears everything.\n * - A ring of the last `AI_ACTIVITY_LIMIT` entries, oldest first.\n * - Entries are replaced, never mutated, on `update`, so a snapshot a panel\n * holds stays stable.\n *\n * Lives in the lazy AI chunk (`ai-ui.ts`); the editor reaches it through the\n * loaded UI module, and `ai-lite.ts` re-exports only the types.\n */\n\nimport type { AiRunThinking } from './ai-request';\nimport type { AiCompletionRequest, AiCompletionResult, AiDocsActivityDetail, AiError, AiFinishReason, AiServedBy, AiThinkingJob, AiTiming, AiUsage } from './ai';\n\n/** How many requests the log keeps. */\nexport const AI_ACTIVITY_LIMIT = 50;\n\n/** The route a request was sent on (null on the entry for a tier-1 host, which routes by itself). */\nexport interface AiActivityRoute {\n engineId: string;\n modelId: string;\n /** The engine's name as the user sees it (falls back to the id). */\n label: string;\n isLocal: boolean;\n /** The router picked this engine because the preferred one was passed over. */\n viaFallback: boolean;\n}\n\n/** What came back: the text as streamed, then the final result's metadata once it arrives. */\nexport interface AiActivityResponse {\n /** Everything streamed so far; the final text once the request ends well. */\n text: string;\n usage?: AiUsage;\n finishReason?: AiFinishReason;\n timing?: AiTiming;\n served?: AiServedBy;\n}\n\nexport interface AiActivityEntry {\n /** The request's `requestId`. */\n id: string;\n /** `Date.now()` right before the request went to the host. */\n startedAt: number;\n /** Null while streaming. */\n endedAt: number | null;\n feature: string;\n /** What the request was for when that differs from the feature (explain and translate run under `rewrite`); labels only, never routing. */\n job?: AiThinkingJob;\n task: string;\n route: AiActivityRoute | null;\n thinking: AiRunThinking | null;\n /** The exact object handed to `host.ai.complete`. */\n request: AiCompletionRequest;\n response: AiActivityResponse;\n /** Set when the request threw (a cancel is an error with code `cancelled`). */\n error: AiError | null;\n /** 1, or 2 for the retry on another engine after the first was unreachable. */\n attempt: 1 | 2;\n /** On attempt 1 only: the request failed and a fallback attempt follows as its own entry. */\n retried?: true;\n /** A documentation chat request (job `navigate` or `answer`): which pages, and the ids dropped. Ids only, never text. */\n docs?: AiDocsActivityDetail;\n}\n\nexport type AiActivityStatus = 'streaming' | 'ok' | 'error' | 'cancelled' | 'fallback';\n\n/** The one word a list row shows: still streaming, failed, cancelled, answered by a fallback engine, or fine. */\nexport function aiActivityStatus(entry: AiActivityEntry): AiActivityStatus {\n if (entry.error) {return entry.error.code === 'cancelled' ? 'cancelled' : 'error';}\n if (entry.endedAt === null) {return 'streaming';}\n return entry.route?.viaFallback ? 'fallback' : 'ok';\n}\n\nexport type AiActivityPatch = Partial<Omit<AiActivityEntry, 'id'>>;\n\nexport interface AiActivityLog {\n /** Whether requests are recorded (`ai.activityPanel`). */\n readonly enabled: boolean;\n /** Turn recording on or off; going off clears the log. */\n setEnabled(on: boolean): void;\n /** The entries, oldest first (a copy). */\n entries(): AiActivityEntry[];\n get(id: string): AiActivityEntry | undefined;\n /** Append an entry (no-op while off); the oldest drops past the limit. */\n record(entry: AiActivityEntry): void;\n /** Change an entry, by a patch or a function of the current entry (no-op for an unknown id). */\n update(id: string, patch: AiActivityPatch | ((entry: AiActivityEntry) => AiActivityPatch)): void;\n clear(): void;\n /** Called after every change; returns the unsubscribe. */\n subscribe(listener: () => void): () => void;\n}\n\nexport function createAiActivityLog(): AiActivityLog {\n let enabled = false;\n let list: AiActivityEntry[] = [];\n const listeners = new Set<() => void>();\n\n const notify = (): void => {\n for (const fn of [...listeners]) {\n try { fn(); } catch { /* a bad listener never breaks a request */ }\n }\n };\n\n return {\n get enabled() { return enabled; },\n setEnabled(on) {\n if (enabled === on) {return;}\n enabled = on;\n if (!on && list.length > 0) {\n list = [];\n notify();\n }\n },\n entries: () => [...list],\n get: (id) => list.find((e) => e.id === id),\n record(entry) {\n if (!enabled) {return;}\n list = [...list, entry].slice(-AI_ACTIVITY_LIMIT);\n notify();\n },\n update(id, patch) {\n const i = list.findIndex((e) => e.id === id);\n if (i < 0) {return;}\n const current = list[i];\n const next = { ...current, ...(typeof patch === 'function' ? patch(current) : patch), id };\n list = [...list.slice(0, i), next, ...list.slice(i + 1)];\n notify();\n },\n clear() {\n if (list.length === 0) {return;}\n list = [];\n notify();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n },\n };\n}\n\n/** The final result as the entry's response. */\nexport function aiActivityResponse(result: AiCompletionResult): AiActivityResponse {\n return {\n text: result.text,\n ...(result.usage ? { usage: result.usage } : {}),\n ...(result.finishReason ? { finishReason: result.finishReason } : {}),\n ...(result.timing ? { timing: result.timing } : {}),\n served: result.served,\n };\n}\n","/**\n * One AI completion as the editor runs it: resolve the route, ask for cloud\n * consent when the router says so, send, and retry once on another engine\n * when the routed one turns out to be down before it sent a token.\n *\n * - Routing is recomputed on every request (`resolveRoute`, pure) from the\n * current settings, the last engine statuses and this session's consent.\n * - Consent: a grant (\"Allow for this workspace\") is remembered for the\n * session (the host persists it too). \"Allow once\" (`'once'`) covers only\n * the request that asked. A refusal (\"Don't allow\") applies here to that\n * request, so the fallback runs now; the host remembers it for the session\n * and answers the next attempt without a dialog. A stored `'never'` (older\n * versions) is kept for the session as a refusal, so the menu entries\n * disable with the router's reason.\n * - A tier-1 host (no `listEngines`) routes by itself: no route is sent.\n * - Thinking: a per-request level becomes the request's `requestOverrides`\n * (the kind's thinking fields only); the host merges them over the\n * model's own, so the request wins. Only for a routed engine whose kind\n * has a mapping (`thinkingChoices`). With no level (\"Default\") and none\n * set on the model, the job's default applies (`resolveThinkingLevel`:\n * Off for short edits). Such a model counts its reasoning\n * against `maxTokens`, so unless the effective level is Off the answer\n * budget gets reasoning headroom (`thinkingMaxTokens`).\n * - Cancellation is the caller's `AbortSignal`; the host aborts the request.\n * - A pin (`AiRunRequest.pin`, from `resolveAiTurnRoute`) holds a request to\n * one engine and model for a whole turn: never re-routed, never retried\n * elsewhere. If that engine cannot serve it, the request fails with a normal\n * error and the fallback waits for the next turn. Documentation base pages\n * would otherwise follow a fallback past the per-base cloud switch. It also\n * fails if the engine's locality changed since the turn was routed.\n * - A turn: `resolveAiTurnRoute` names the turn (`pin.turnId`) in its consent\n * request and every pinned request carries it (`AiCompletionRequest.turn`).\n * \"Allow once\" then holds for that turn, on the host as well as here: the\n * host keeps the grant, and core's `pin.consented` is not consent to it.\n */\n\nimport {\n CHARS_PER_TOKEN,\n isRouteUsable,\n makeAiError,\n resolveAiFeature,\n resolveRoute,\n resolveThinkingLevel,\n thinkingChoices,\n thinkingLevelFrom,\n thinkingMaxTokens,\n toAiError,\n withThinkingLevel,\n type AiThinkingJob,\n type AiThinkingLevel,\n type AiThinkingOptions,\n} from './ai';\nimport { aiActivityResponse, type AiActivityEntry, type AiActivityLog } from './ai-activity';\nimport type {\n AiCompletionRequest,\n AiCompletionResult,\n AiConsentAbout,\n AiConsentReply,\n AiConsentState,\n AiDocsActivityDetail,\n AiEngineStatus,\n AiError,\n AiErrorCode,\n AiMessage,\n AiRouteOk,\n AiRoutePin,\n AiRouteUnusable,\n AiSendsScope,\n AiSettings,\n MikeDownAiHost,\n} from './ai';\n\nexport interface AiRunContext {\n ai: MikeDownAiHost;\n settings: () => AiSettings;\n statuses: () => readonly AiEngineStatus[];\n /** Session consent answers by engine id (grants only are written back). */\n consent: Record<string, boolean | undefined>;\n /** The editor's activity recorder; every request that is sent is recorded in it (while it is on). */\n activity?: AiActivityLog;\n}\n\nexport interface AiRunRequest {\n feature: string;\n /** What this request sends when it differs from the feature's own scope (whole-document Translate); for the consent dialog. */\n sends?: AiSendsScope;\n /**\n * For `sends: 'docsBase'`: the ids of the documentation bases this request\n * reads from. Forwarded to `requestCloudConsent`; the host maps ids to\n * names from its own settings and drops unknown ids.\n */\n baseIds?: string[];\n task?: string;\n messages: AiMessage[];\n maxTokens?: number;\n temperature?: number;\n format?: 'text' | 'json';\n /**\n * Thinking level for this request; null or absent sends none (the model's\n * configured overrides apply). A function is asked once the route's engine\n * kind is known, so a choice remembered per kind follows a fallback.\n */\n thinking?: AiThinkingLevel | null | ((kind: string) => AiThinkingLevel | null);\n /**\n * What the request is for, for the default thinking level when `thinking`\n * gives none (`taskThinkingDefault`); defaults to `feature`. `explain` and\n * `translate` run under the `rewrite` feature.\n */\n job?: AiThinkingJob;\n /** Use exactly this engine and model (`resolveAiTurnRoute`): no re-routing, no retry elsewhere. Ignored on a tier-1 host, which has no routes. */\n pin?: AiRoutePin;\n /** The documentation chat's ids for this request's Activity entry. */\n docs?: AiDocsActivityDetail;\n /** Only local engines may serve this request (Inline suggestions); a cloud route is `cloudBlocked`. */\n localOnly?: boolean;\n}\n\n/** The thinking dial's state for the route serving a request. */\nexport interface AiRunThinking {\n /** The routed engine's kind (`thinkingChoices(kind)` is non-empty). */\n kind: string;\n /** The level the model's own `requestOverrides` express (null: model default). */\n configured: AiThinkingLevel | null;\n /** The level this request sent (null: none, `configured` applies). */\n sent: AiThinkingLevel | null;\n /** `sent` is the job's default, not the user's choice: the dial still shows Default. */\n auto?: boolean;\n}\n\n/** Whether the model may have been thinking: a routed kind with a mapping whose effective level is not Off. */\nexport function aiRunThinkingOn(thinking: AiRunThinking | null): boolean {\n return !!thinking && (thinking.sent ?? thinking.configured) !== 'off';\n}\n\nexport interface AiRunEvents {\n /**\n * The route about to be used (null for a tier-1 host), before any token.\n * Called again on a retry. `thinking` is null when the route's kind has no\n * thinking mapping (and always for a tier-1 host).\n */\n onRoute?(route: AiRouteOk | null, thinking: AiRunThinking | null): void;\n /** A text delta, and everything received so far for the current attempt. */\n onToken?(delta: string, text: string): void;\n /** The host answered the consent request. Called even when the run was aborted while it asked: the answer still stands. */\n onConsent?(reply: AiConsentReply): void;\n}\n\nexport interface AiRunOutcome {\n result: AiCompletionResult;\n route: AiRouteOk | null;\n viaFallback: boolean;\n thinking: AiRunThinking | null;\n /** The request's id, which is also its Activity entry's. */\n requestId?: string;\n}\n\ntype Json = Record<string, unknown>;\n\nconst isObject = (v: unknown): v is Json => typeof v === 'object' && v !== null && !Array.isArray(v);\n\n/**\n * The per-request `requestOverrides` for one thinking level: the kind's\n * thinking fields only (`withThinkingLevel` on nothing). The host merges\n * them over the model's overrides, and a merge cannot delete, so a thinking\n * field the model sets that this level leaves out is sent at its neutral\n * value: `reasoning_effort: \"none\"`, or `chat_template_kwargs.enable_thinking:\n * true` (a model set to Off on a local engine, asked for a tier). Undefined\n * when the kind cannot express the level.\n */\nexport function thinkingRequestOverrides(\n kind: string,\n modelOverrides: Json | undefined,\n level: AiThinkingLevel,\n opts: AiThinkingOptions = {},\n): Json | undefined {\n const out = withThinkingLevel(kind, undefined, level, opts);\n if (!out || kind === 'anthropic' || !modelOverrides) {return out;}\n if (modelOverrides.reasoning_effort !== undefined && out.reasoning_effort === undefined) {out.reasoning_effort = 'none';}\n const modelKwargs = modelOverrides.chat_template_kwargs;\n const kwargs = isObject(out.chat_template_kwargs) ? out.chat_template_kwargs : {};\n if (isObject(modelKwargs) && modelKwargs.enable_thinking !== undefined && kwargs.enable_thinking === undefined) {\n out.chat_template_kwargs = { ...kwargs, enable_thinking: true };\n }\n return out;\n}\n\n/** The dial state and the overrides to send for `route`, or null when its kind has no mapping. */\nfunction routeThinking(settings: AiSettings, route: AiRouteOk, req: Pick<AiRunRequest, 'thinking' | 'job' | 'feature'>): { info: AiRunThinking; overrides?: Json; contextTokens: number | null } | null {\n const engine = settings.engines.find((e) => e.id === route.engineId);\n if (!engine || thinkingChoices(engine.kind).length === 0) {return null;}\n const model = engine.models.find((m) => m.id === route.modelId);\n const configured = thinkingLevelFrom(engine.kind, model?.requestOverrides);\n const wanted = req.thinking;\n const explicit = typeof wanted === 'function' ? wanted(engine.kind) : wanted ?? null;\n const { level, auto } = resolveThinkingLevel(engine.kind, explicit, configured, req.job ?? req.feature, { modelId: route.modelId });\n const overrides = level ? thinkingRequestOverrides(engine.kind, model?.requestOverrides, level, { local: route.isLocal }) : undefined;\n return {\n info: { kind: engine.kind, configured, sent: overrides ? level : null, ...(overrides && auto ? { auto: true } : {}) },\n ...(overrides ? { overrides } : {}),\n contextTokens: model?.capabilities.contextTokens ?? null,\n };\n}\n\n/** Rough prompt size in tokens (text parts only). */\nfunction promptTokens(messages: readonly AiMessage[]): number {\n let chars = 0;\n for (const m of messages) {\n if (typeof m.content === 'string') {chars += m.content.length;} else {\n for (const part of m.content) {if (part.type === 'text') {chars += part.text.length;}}\n }\n }\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\n\n/**\n * `maxTokens` for the request: the answer budget, plus reasoning headroom\n * when the routed model can think and the effective level (sent, else the\n * model's own, else model default) is not Off.\n */\nfunction requestMaxTokens(req: AiRunRequest, thinking: ReturnType<typeof routeThinking>): number | undefined {\n if (req.maxTokens === undefined || !thinking) {return req.maxTokens;}\n const level = thinking.info.sent ?? thinking.info.configured;\n return thinkingMaxTokens(req.maxTokens, level, { contextTokens: thinking.contextTokens, promptTokens: promptTokens(req.messages) });\n}\n\nlet requestCounter = 0;\n\nfunction nextRequestId(feature: string): string {\n requestCounter += 1;\n return `ai-${feature}-${Date.now().toString(36)}-${requestCounter}`;\n}\n\nlet turnCounter = 0;\n\n/** Tells one turn from another within a panel or window; hosts key their grants by the panel as well. */\nfunction nextTurnId(): string {\n turnCounter += 1;\n return `turn-${Date.now().toString(36)}-${turnCounter}`;\n}\n\n/** Ask about a cloud engine, naming the turn to a host that holds grants per turn. No dialog on a host that decides alone. */\nfunction askConsent(ai: MikeDownAiHost, engineId: string, about: AiConsentAbout, turnId: string | undefined): Promise<AiConsentReply> | boolean {\n if (turnId && ai.requestTurnConsent) {return ai.requestTurnConsent(engineId, { ...about, turnId });}\n return ai.requestCloudConsent ? ai.requestCloudConsent(engineId, about) : true;\n}\n\n/** The turn is over: the host forgets what it held for it. Nothing here may disturb the outcome. */\nexport function endAiTurn(ctx: AiRunContext, turnId: string): void {\n try { ctx.ai.endTurn?.(turnId); } catch { /* ignore */ }\n}\n\n/** The route as the activity log keeps it. */\nfunction activityRoute(settings: AiSettings, route: AiRouteOk): NonNullable<AiActivityEntry['route']> {\n const engine = settings.engines.find((e) => e.id === route.engineId);\n return { engineId: route.engineId, modelId: route.modelId, label: engine?.name ?? route.engineId, isLocal: route.isLocal, viaFallback: route.viaFallback };\n}\n\n/** The recorder is a side channel: a failure in it never reaches the completion. */\nfunction openActivity(ctx: AiRunContext, entry: AiActivityEntry): void {\n try { ctx.activity?.record(entry); } catch { /* ignore */ }\n}\n\nfunction patchActivity(ctx: AiRunContext, id: string, patch: Parameters<AiActivityLog['update']>[1]): void {\n try { ctx.activity?.update(id, patch); } catch { /* ignore */ }\n}\n\n/** An unusable route as the error the popover shows. */\nexport function routeUnusableError(r: AiRouteUnusable): AiError {\n const map: Partial<Record<AiRouteUnusable['unusable'], AiErrorCode>> = {\n cloudBlocked: 'cloudBlocked',\n consentDenied: 'consentDenied',\n probeFailed: 'unreachable',\n modelMissing: 'modelNotFound',\n modelNotListed: 'modelNotFound',\n };\n const e = makeAiError(map[r.unusable] ?? 'unknown', r.reason);\n return r.engineId ? { ...e, engineId: r.engineId } : e;\n}\n\nfunction isTier2(ai: MikeDownAiHost): boolean {\n return typeof ai.listEngines === 'function';\n}\n\n/** Statuses with the engines that failed during this run marked down, so the router passes them over. */\nfunction withFailures(statuses: readonly AiEngineStatus[], failed: ReadonlyMap<string, string>): AiEngineStatus[] {\n if (failed.size === 0) {return [...statuses];}\n const out = statuses.map((s) => (failed.has(s.engineId) ? { ...s, ok: false, error: failed.get(s.engineId) } : s));\n for (const [engineId, error] of failed) {\n if (!out.some((s) => s.engineId === engineId)) {out.push({ engineId, ok: false, isLocal: true, hasKey: false, error, models: [] });}\n }\n return out;\n}\n\n/**\n * The settings a pinned request routes under: the pin as the task's route and\n * no fallback, so every usual check (switches, capabilities, the cloud gate,\n * consent, the last probe) still applies and the only possible answers are the\n * pinned pair or an error.\n */\nfunction pinnedSettings(settings: AiSettings, req: AiRunRequest, pin: AiRoutePin): AiSettings {\n const task = req.task ?? resolveAiFeature(settings.features, req.feature).task;\n return {\n ...settings,\n routing: {\n ...settings.routing,\n fallback: 'none',\n tasks: { ...settings.routing.tasks, [task]: { engineId: pin.engineId, modelId: pin.modelId } },\n },\n };\n}\n\n/** What `resolveAiTurnRoute` needs to know about the turn. */\nexport interface AiTurnRouteRequest {\n feature: string;\n task?: string;\n sends?: AiSendsScope;\n baseIds?: string[];\n /** Asked about each route before any consent dialog; false stops with `blocked`. */\n allowed?(route: AiRouteOk | null): boolean;\n}\n\nexport interface AiTurnRoute {\n /** `allowed` said no. No dialog was shown. */\n blocked: boolean;\n /** Null for a tier-1 host, which routes by itself. */\n route: AiRouteOk | null;\n /** What every request of the turn carries; null when there is no route to hold. */\n pin: AiRoutePin | null;\n}\n\n/**\n * The one route of a turn, asked for before the turn's first request. Checks\n * `allowed`, then asks for consent. A refusal may still move to the fallback\n * here, because nothing has been sent; `allowed` sees that route too. After\n * this the turn does not move. \"Allow once\" lasts for the turn. Throws the\n * router's error when nothing can serve it.\n */\nexport async function resolveAiTurnRoute(ctx: AiRunContext, req: AiTurnRouteRequest, signal: AbortSignal): Promise<AiTurnRoute> {\n if (!isTier2(ctx.ai)) {\n return { blocked: req.allowed ? !req.allowed(null) : false, route: null, pin: null };\n }\n const refused: Record<string, boolean> = {};\n const once: Record<string, boolean> = {};\n const turnId = nextTurnId();\n try {\n for (let pass = 0; pass < 12; pass++) {\n if (signal.aborted) {throw makeAiError('cancelled');}\n const consent: AiConsentState = { ...ctx.consent, ...once, ...refused };\n const resolved = resolveRoute(ctx.settings(), ctx.statuses(), consent, { feature: req.feature, ...(req.task ? { task: req.task } : {}) });\n if (!isRouteUsable(resolved)) {throw routeUnusableError(resolved);}\n if (req.allowed && !req.allowed(resolved)) {\n endAiTurn(ctx, turnId);\n return { blocked: true, route: resolved, pin: null };\n }\n if (!resolved.needsConsent) {\n return {\n blocked: false,\n route: resolved,\n pin: {\n engineId: resolved.engineId,\n modelId: resolved.modelId,\n viaFallback: resolved.viaFallback,\n isLocal: resolved.isLocal,\n turnId,\n ...(resolved.reason ? { reason: resolved.reason } : {}),\n ...(once[resolved.engineId] ? { consented: true } : {}),\n },\n };\n }\n const reply = await askConsent(ctx.ai, resolved.engineId, { feature: req.feature, ...(req.sends ? { sends: req.sends } : {}), ...(req.baseIds && req.baseIds.length > 0 ? { baseIds: req.baseIds } : {}) }, turnId);\n if (signal.aborted) {throw makeAiError('cancelled');}\n if (reply === true) {ctx.consent[resolved.engineId] = true;}\n else if (reply === 'once') {once[resolved.engineId] = true;}\n else {\n refused[resolved.engineId] = false;\n if (reply === 'never') {ctx.consent[resolved.engineId] = false;}\n }\n }\n throw makeAiError('unknown', 'No engine answered.');\n } catch (err) {\n endAiTurn(ctx, turnId);\n throw err;\n }\n}\n\nexport async function runAiCompletion(ctx: AiRunContext, req: AiRunRequest, events: AiRunEvents, signal: AbortSignal): Promise<AiRunOutcome> {\n const tier2 = isTier2(ctx.ai);\n const failed = new Map<string, string>();\n const refused: Record<string, boolean> = {};\n /** \"Allow once\" grants: this run only, never written to the session. */\n const once: Record<string, boolean> = {};\n const pin = tier2 ? req.pin : undefined;\n if (pin?.consented) {once[pin.engineId] = true;}\n let retried = false;\n\n // Bounded: each pass either sends, records a consent answer, or marks one engine failed.\n for (let pass = 0; pass < 12; pass++) {\n if (signal.aborted) {throw makeAiError('cancelled');}\n\n let route: AiRouteOk | null = null;\n if (tier2) {\n const consent: AiConsentState = { ...ctx.consent, ...once, ...refused };\n const settings = pin ? pinnedSettings(ctx.settings(), req, pin) : ctx.settings();\n const resolved = resolveRoute(settings, withFailures(ctx.statuses(), failed), consent, { feature: req.feature, ...(req.task ? { task: req.task } : {}), ...(req.localOnly ? { localOnly: true } : {}) });\n if (!isRouteUsable(resolved)) {throw routeUnusableError(resolved);}\n if (pin && pin.isLocal !== undefined && resolved.isLocal !== pin.isLocal) {\n const name = ctx.settings().engines.find((e) => e.id === pin.engineId)?.name || pin.engineId;\n const moved: AiError = { ...makeAiError('unknown', `${name} moved between local and cloud during this turn. Ask again.`), engineId: pin.engineId };\n throw moved;\n }\n if (resolved.needsConsent) {\n const reply = await askConsent(ctx.ai, resolved.engineId, { feature: req.feature, ...(req.sends ? { sends: req.sends } : {}), ...(req.baseIds && req.baseIds.length > 0 ? { baseIds: req.baseIds } : {}) }, pin?.turnId);\n events.onConsent?.(reply);\n if (signal.aborted) {throw makeAiError('cancelled');}\n if (reply === true) {ctx.consent[resolved.engineId] = true;}\n else if (reply === 'once') {\n once[resolved.engineId] = true;\n // Asked mid-turn (the earlier answer was forgotten): the answer lasts for the rest of the turn too.\n if (pin) {pin.consented = true;}\n } else {\n refused[resolved.engineId] = false;\n // A stored refusal from an older version: the host will not ask again, so the\n // menu entries disable with the router's reason for the rest of the session.\n if (reply === 'never') {ctx.consent[resolved.engineId] = false;}\n }\n continue;\n }\n route = pin\n ? { ...resolved, viaFallback: pin.viaFallback ?? false, ...(pin.reason ? { reason: pin.reason } : {}) }\n : resolved;\n }\n\n const thinking = route ? routeThinking(ctx.settings(), route, req) : null;\n const maxTokens = requestMaxTokens(req, thinking);\n events.onRoute?.(route, thinking?.info ?? null);\n let text = '';\n let gotToken = false;\n const request: AiCompletionRequest = {\n requestId: nextRequestId(req.feature),\n feature: req.feature,\n task: route?.task ?? req.task ?? resolveAiFeature(ctx.settings().features, req.feature).task,\n ...(route ? { route: { engineId: route.engineId, modelId: route.modelId } } : {}),\n messages: req.messages,\n ...(req.format ? { format: req.format } : {}),\n ...(maxTokens !== undefined ? { maxTokens } : {}),\n ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),\n ...(thinking?.overrides ? { requestOverrides: thinking.overrides } : {}),\n ...(pin?.turnId && route ? { turn: { id: pin.turnId, ...(req.sends ? { sends: req.sends } : {}), ...(req.baseIds && req.baseIds.length > 0 ? { baseIds: req.baseIds } : {}), isLocal: route.isLocal } } : {}),\n };\n const entryId = request.requestId;\n openActivity(ctx, {\n id: entryId,\n startedAt: Date.now(),\n endedAt: null,\n feature: request.feature,\n ...(req.job ? { job: req.job } : {}),\n ...(req.docs ? { docs: req.docs } : {}),\n task: request.task,\n route: route ? activityRoute(ctx.settings(), route) : null,\n thinking: thinking?.info ?? null,\n request,\n response: { text: '' },\n error: null,\n attempt: retried ? 2 : 1,\n });\n try {\n const result = await ctx.ai.complete(request, (delta) => {\n if (signal.aborted) {return;}\n gotToken = true;\n text += delta;\n patchActivity(ctx, entryId, { response: { text } });\n events.onToken?.(delta, text);\n }, signal);\n patchActivity(ctx, entryId, { endedAt: Date.now(), response: aiActivityResponse(result) });\n return { result, route, viaFallback: route?.viaFallback ?? false, thinking: thinking?.info ?? null, requestId: entryId };\n } catch (err) {\n const e = signal.aborted ? makeAiError('cancelled') : toAiError(err);\n const retrying = e.code === 'unreachable' && !gotToken && !retried && !!route && !pin;\n patchActivity(ctx, entryId, {\n endedAt: Date.now(),\n error: route && !e.engineId && e.code !== 'cancelled' ? { ...e, engineId: route.engineId } : e,\n ...(retrying ? { retried: true as const } : {}),\n });\n // The routed engine is down and nothing was shown yet: the host has\n // marked it failed; pass it over and try the fallback once.\n if (retrying && route) {\n retried = true;\n failed.set(route.engineId, e.message);\n continue;\n }\n // The popover's \"Open <engine>\" goes to the engine that failed.\n throw route && !e.engineId && e.code !== 'cancelled' ? { ...e, engineId: route.engineId } : e;\n }\n }\n throw makeAiError('unknown', 'No engine answered.');\n}\n\n/**\n * The short notice for a launch (palette command, hotkey) that does nothing\n * because AI or the feature is switched off, so it never fails silently.\n * Null when that is not the reason: no AI host, or the feature is on.\n */\nexport function aiFeatureOffNotice(ai: MikeDownAiHost | undefined, settings: AiSettings, feature: string): string | null {\n if (!ai) {return null;}\n if (!settings.enabled) {return 'AI is turned off. Turn it on in the AI settings.';}\n const resolved = resolveAiFeature(settings.features, feature);\n if (resolved.enabled) {return null;}\n return `${resolved.definition?.label ?? feature} is turned off in the AI settings.`;\n}\n\nexport type AiFeatureAvailability =\n | { state: 'hidden' }\n | { state: 'disabled'; reason: string }\n | { state: 'enabled' };\n\n/**\n * Whether a feature's entry points show: hidden without an AI host, with the\n * master switch or the feature off; disabled (with the router's reason) when\n * AI is on but nothing can serve it; enabled otherwise. A tier-1 host routes\n * by itself, so it is always enabled.\n */\nexport function aiFeatureAvailability(\n ai: MikeDownAiHost | undefined,\n settings: AiSettings,\n statuses: readonly AiEngineStatus[],\n consent: AiConsentState,\n feature: string,\n): AiFeatureAvailability {\n if (!ai || !settings.enabled) {return { state: 'hidden' };}\n if (!resolveAiFeature(settings.features, feature).enabled) {return { state: 'hidden' };}\n if (!isTier2(ai)) {return { state: 'enabled' };}\n // Grants and stored \"never\" answers count here (\"Allow once\" and \"Don't allow\"\n // are never written to the session, so the next attempt goes to the host).\n const answers: Record<string, boolean> = {};\n for (const [id, v] of Object.entries(consent)) {if (typeof v === 'boolean') {answers[id] = v;}}\n const r = resolveRoute(settings, statuses, answers, { feature });\n return isRouteUsable(r) ? { state: 'enabled' } : { state: 'disabled', reason: r.reason };\n}\n","/**\n * The AI Activity panel: every AI request this editor made, with the exact\n * messages sent and the raw response, from the in-memory `AiActivityLog`.\n * Mounted full-window by `editor.ts`, in the same shell as the AI Engines page.\n *\n * Left, the requests, newest first. Right, the selected request: route and\n * thinking, then collapsible Sent and Received. Copy and Save export plain\n * text (`formatActivityExport`). Save is the host's (`saveTextFile`); without\n * it the Save buttons are not there.\n *\n * The log fires on every streamed token, so list work is throttled and\n * incremental: rows update in place, new rows go on top, and the open\n * request's response only ever gets text appended. Scroll positions, text\n * selections and keyboard focus survive streaming.\n *\n * Message and response text goes in as text nodes, never as markup: a message\n * can contain anything. Modal UI only: nothing here touches the editor\n * document or its DOM.\n */\n\nimport { getAiFeature } from './ai';\nimport type { AiMessage } from './ai';\nimport { AI_ACTIVITY_LIMIT, aiActivityStatus } from './ai-activity';\nimport type { AiActivityEntry, AiActivityLog, AiActivityStatus } from './ai-activity';\nimport type { AiRunThinking } from './ai-request';\nimport { ICONS, button, el, experimentalBadge, nextId, note } from './ai-settings-dom';\nimport type { MikeDownSettingsSectionContext } from './types';\n\nexport interface AiActivityPanelOptions {\n /** The editor's one log (the same one `runAiCompletion` records into). */\n log: AiActivityLog;\n /** The host's save dialog and write. Absent: Save this request and Save all are not shown. */\n saveTextFile?(name: string, text: string): Promise<void>;\n /** Open on this request (the chat panel's link to an answer's entry). One no longer in the log is ignored. */\n selectId?: string;\n}\n\nexport interface AiActivityPanelHandle {\n /** Tear down (subscription, timers) and leave the container empty. */\n destroy(): void;\n /** Focus where a keyboard user should land: the selected request, else Back. */\n focus(): void;\n /** Render now, skipping the streaming throttle (the setting changed, or a test wants the DOM). */\n refresh(): void;\n}\n\n/** The one line under the header, always there. */\nexport const AI_ACTIVITY_BANNER = 'This record stays in memory: nothing here is stored or sent anywhere, and turning AI Activity off clears it.';\n\n/** The empty state, while requests are recorded and there are none yet. */\nexport const AI_ACTIVITY_EMPTY = {\n title: 'No AI requests yet',\n text: 'Each request an AI feature makes from this window shows up here, with the exact messages sent and the raw response that came back.',\n};\n\n/** The empty state with the setting off. */\nexport const AI_ACTIVITY_OFF = {\n title: 'AI Activity is off',\n text: 'Requests are not recorded, and earlier ones were cleared. To record them, turn on AI Activity in the AI tab of Settings and save.',\n};\n\n/** Streaming tokens fire far more often than a person can read. */\nconst RENDER_THROTTLE_MS = 100;\n/** How long \"Copied\" stays. */\nconst CONFIRM_MS = 1600;\n/** Narrower than this and the panel is one column (the AI Engines page's width). */\nconst NARROW_PX = 720;\n\nconst STATUS_LABELS: Record<AiActivityStatus, string> = {\n streaming: 'Streaming',\n ok: 'OK',\n error: 'Failed',\n cancelled: 'Cancelled',\n fallback: 'Fallback',\n};\n\n// ── Text helpers ────────────────────────────────────────────────────────────\n\nconst pad = (n: number): string => String(n).padStart(2, '0');\n\n/** `mikedown-ai-activity-<yyyymmdd-hhmm>.txt`, in local time. */\nexport function activityExportFileName(now: Date = new Date()): string {\n const day = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;\n return `mikedown-ai-activity-${day}-${pad(now.getHours())}${pad(now.getMinutes())}.txt`;\n}\n\n/** 24-hour local time: the column stays one width, like a log. */\nfunction clockTime(ms: number): string {\n const d = new Date(ms);\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {return `${Math.round(ms)} ms`;}\n if (ms < 60_000) {return `${(ms / 1000).toFixed(1)} s`;}\n const seconds = Math.round(ms / 1000);\n return `${Math.floor(seconds / 60)} min ${seconds % 60} s`;\n}\n\nfunction entryDuration(entry: AiActivityEntry): number | null {\n return entry.endedAt === null ? null : entry.endedAt - entry.startedAt;\n}\n\n/** Jobs that get their own name, most because they run under another feature (`rewrite`). */\nconst JOB_LABELS: Partial<Record<string, string>> = { explain: 'Explain', translate: 'Translate', navigate: 'Chat: navigate', answer: 'Chat: answer', ghostText: 'Inline suggestions' };\n\nfunction featureLabel(entry: AiActivityEntry): string {\n return (entry.job ? JOB_LABELS[entry.job] : undefined) ?? getAiFeature(entry.feature)?.label ?? entry.feature;\n}\n\n/** Where the request went: the route, or what a tier-1 host reported once it finished. */\nfunction routeOf(entry: AiActivityEntry): { engine: string | null; model: string | null; isLocal: boolean | null } {\n if (entry.route) {return { engine: entry.route.label, model: entry.route.modelId, isLocal: entry.route.isLocal };}\n const served = entry.response.served;\n if (served) {return { engine: served.engineName, model: served.modelId, isLocal: served.isLocal };}\n return { engine: null, model: null, isLocal: null };\n}\n\nconst NO_ROUTE_LABEL = 'Chosen by the app';\n\nfunction routeLabel(entry: AiActivityEntry): string {\n const { engine, model } = routeOf(entry);\n if (!engine) {return NO_ROUTE_LABEL;}\n return model ? `${engine} · ${model}` : engine;\n}\n\nfunction tokensLabel(entry: AiActivityEntry): string {\n const { promptTokens, completionTokens } = entry.response.usage ?? {};\n const parts: string[] = [];\n if (promptTokens !== undefined) {parts.push(`${promptTokens} in`);}\n if (completionTokens !== undefined) {parts.push(`${completionTokens} out`);}\n return parts.join(' · ');\n}\n\nfunction thinkingLabel(thinking: AiRunThinking | null): string | null {\n if (!thinking) {return null;}\n const level = thinking.sent ?? thinking.configured;\n const name = level ? level.charAt(0).toUpperCase() + level.slice(1) : 'Model default';\n return thinking.auto ? `${name} (this task's default)` : name;\n}\n\n/** A message's text, verbatim. An image part is named, not embedded. */\nfunction messageText(message: AiMessage): string {\n if (typeof message.content === 'string') {return message.content;}\n return message.content\n .map((part) => (part.type === 'text' ? part.text : `[image: ${part.mime}, ${part.bytes.length} bytes]`))\n .join('\\n');\n}\n\nconst plural = (n: number, word: string): string => `${n.toLocaleString()} ${word}${n === 1 ? '' : 's'}`;\n\n/** A documentation chat request's ids, as rows. Ids only: nothing a secrets scan left out can get here as text. */\nfunction docsDetailRows(entry: AiActivityEntry): Array<{ label: string; value: string; raw?: boolean }> {\n const { docs } = entry;\n if (!docs) {return [];}\n const ids = (list: readonly string[], count = list.length): string => {\n const more = count - list.length;\n return more > 0 ? `${list.join(', ')}${list.length > 0 ? ', ' : ''}and ${more} more` : list.join(', ');\n };\n const rows: Array<{ label: string; value: string; raw?: boolean }> = [];\n if (docs.hop !== undefined) {rows.push({ label: 'Hop', value: String(docs.hop) });}\n rows.push({ label: 'Pages', value: docs.pages.length > 0 ? ids(docs.pages) : 'None', raw: true });\n if (docs.droppedCount > 0) {rows.push({ label: 'Dropped ids', value: ids(docs.droppedIds, docs.droppedCount), raw: true });}\n if (docs.leftOutIds && docs.leftOutIds.length > 0) {rows.push({ label: 'Left out (key)', value: ids(docs.leftOutIds), raw: true });}\n if (docs.cutIds && docs.cutIds.length > 0) {rows.push({ label: 'Did not fit', value: ids(docs.cutIds), raw: true });}\n return rows;\n}\n\n// ── Plain-text export ───────────────────────────────────────────────────────\n\nfunction exportEntry(entry: AiActivityEntry, index: number, total: number): string {\n const { request, response, error } = entry;\n const { engine, model, isLocal } = routeOf(entry);\n const duration = entryDuration(entry);\n const thinking = thinkingLabel(entry.thinking);\n const head: Array<[string, string | number | null | undefined]> = [\n ['Time', new Date(entry.startedAt).toISOString()],\n ['Feature', entry.feature],\n ['Job', entry.job && JOB_LABELS[entry.job] ? entry.job : null],\n ['Task', entry.task],\n ['Status', aiActivityStatus(entry)],\n ['Engine', engine ? `${engine}${isLocal === null ? '' : isLocal ? ' (local)' : ' (cloud)'}` : 'chosen by the app'],\n ['Model', model],\n ['Via fallback', entry.route?.viaFallback ? 'yes' : null],\n ['Attempt', entry.attempt],\n ...docsDetailRows(entry).map(({ label, value }): [string, string] => [label, value]),\n ['Thinking', thinking],\n ['Duration', duration === null ? null : `${duration} ms`],\n ['Format', request.format],\n ['Max tokens', request.maxTokens],\n ['Temperature', request.temperature],\n ['Request overrides', request.requestOverrides ? JSON.stringify(request.requestOverrides) : null],\n ];\n const result: Array<[string, string | number | null | undefined]> = [\n ['Prompt tokens', response.usage?.promptTokens],\n ['Completion tokens', response.usage?.completionTokens],\n ['Finish reason', response.finishReason],\n ['Total time', response.timing ? `${response.timing.totalMs} ms` : null],\n ['First token', response.timing?.firstTokenMs !== undefined ? `${response.timing.firstTokenMs} ms` : null],\n ['Served by', response.served ? `${response.served.engineName} · ${response.served.modelId} (${response.served.isLocal ? 'local' : 'cloud'})` : null],\n ['Error', error ? `${error.code}: ${error.message}` : null],\n ['Retried', entry.retried ? 'yes, on another engine (the next request)' : null],\n ];\n const lines = (rows: typeof head): string[] => rows.filter(([, v]) => v !== null && v !== undefined).map(([k, v]) => `${k}: ${v}`);\n const metadata = lines(result);\n const blocks = [\n [`=== Request ${index + 1} of ${total} ===`, ...lines(head)].join('\\n'),\n '--- Sent ---',\n ...request.messages.map((m) => `[${m.role}]\\n${messageText(m)}`),\n '--- Received ---',\n response.text,\n ...(metadata.length > 0 ? [['--- Result ---', ...metadata].join('\\n')] : []),\n ];\n return blocks.join('\\n\\n');\n}\n\n/**\n * The plain-text export used by Copy and both Saves: a header per request,\n * then the messages and the response verbatim. Deterministic: times are UTC\n * and nothing depends on when it runs.\n */\nexport function formatActivityExport(entries: readonly AiActivityEntry[]): string {\n if (entries.length === 0) {return '';}\n return `${entries.map((entry, i) => exportEntry(entry, i, entries.length)).join('\\n\\n')}\\n`;\n}\n\n// ── DOM helpers ─────────────────────────────────────────────────────────────\n\nfunction setText(node: Node, text: string): void {\n if (node.textContent !== text) {node.textContent = text;}\n}\n\nfunction setAttr(node: Element, name: string, value: string): void {\n if (node.getAttribute(name) !== value) {node.setAttribute(name, value);}\n}\n\nfunction localityPill(isLocal: boolean, extraClass = ''): HTMLElement {\n const pill = el('span', `ai-pill ai-pill--${isLocal ? 'local' : 'cloud'}${extraClass ? ` ${extraClass}` : ''}`);\n pill.innerHTML = isLocal ? ICONS.local : ICONS.cloud;\n pill.append(el('span', '', isLocal ? 'local' : 'cloud'));\n return pill;\n}\n\nfunction actionButton(action: string, label: string): HTMLButtonElement {\n const b = button('settings-btn ai-activity-action', label, { fk: `activity:${action}` });\n b.dataset.action = action;\n return b;\n}\n\n/** A label and value list (the footers under Sent and Received). */\nfunction metaList(rows: ReadonlyArray<{ label: string; value: string; raw?: boolean }>): HTMLElement {\n const list = el('dl', 'ai-activity-meta');\n for (const row of rows) {\n const value = el('dd', row.raw ? 'is-raw' : '', row.value);\n value.dataset.meta = row.label;\n list.append(el('dt', '', row.label), value);\n }\n return list;\n}\n\n/** One quiet line beside some buttons: read out when it changes, gone after `ms`. */\nfunction inlineStatus(): { element: HTMLElement; show(text: string, level: 'ok' | 'error', ms?: number): void; clear(): void } {\n const element = el('span', 'ai-activity-inline-status');\n element.setAttribute('role', 'status');\n let timer: number | undefined;\n const clear = (): void => {\n window.clearTimeout(timer);\n element.textContent = '';\n delete element.dataset.level;\n };\n return {\n element,\n clear,\n show(text, level, ms) {\n clear();\n element.textContent = text;\n element.dataset.level = level;\n if (ms) {timer = window.setTimeout(clear, ms);}\n },\n };\n}\n\n// ── The panel ───────────────────────────────────────────────────────────────\n\ninterface RowRefs {\n row: HTMLElement;\n dot: HTMLElement;\n feature: HTMLElement;\n statusWord: HTMLElement;\n time: HTMLElement;\n engine: HTMLElement;\n locality: HTMLElement;\n duration: HTMLElement;\n tokens: HTMLElement;\n /** The entry this row shows. Log entries are replaced on update, so identity tells a change. */\n entry: AiActivityEntry | null;\n shownLocal: boolean | null;\n}\n\n/** What changes in an open request, kept so streaming never rebuilds the pane. */\ninterface DetailRefs {\n entry: AiActivityEntry;\n status: HTMLElement;\n statusWord: HTMLElement;\n route: HTMLElement;\n notes: HTMLElement;\n docs: HTMLElement;\n receivedSummary: HTMLElement;\n receivedBlock: HTMLElement;\n receivedText: Text;\n receivedMeta: HTMLElement;\n copyStatus: ReturnType<typeof inlineStatus>;\n}\n\ntype SectionKey = 'sent' | 'received';\n\nexport function mountAiActivityPanel(container: HTMLElement, ctx: MikeDownSettingsSectionContext, opts: AiActivityPanelOptions): AiActivityPanelHandle {\n const { log } = opts;\n const canSave = typeof opts.saveTextFile === 'function';\n\n let selectedId: string | null = opts.selectId !== undefined && log.get(opts.selectId) ? opts.selectId : null;\n let detail: DetailRefs | null = null;\n let mounted = false;\n let destroyed = false;\n let narrow = false;\n /** Narrow layout only: which pane shows. */\n let view: 'list' | 'detail' = selectedId ? 'detail' : 'list';\n let renderTimer: number | undefined;\n let lastRender = 0;\n let savingAll = false;\n /** Closed sections stay closed from request to request while the panel is open. */\n const collapsed: Record<SectionKey, boolean> = { sent: false, received: false };\n\n // ── Shell ─────────────────────────────────────────────────────────────────\n\n const root = el('div', 'ai-page ai-activity');\n // A click on plain text keeps focus here, so Escape still reaches the panel.\n root.tabIndex = -1;\n\n const header = el('div', 'ai-page-header');\n const backBtn = button('ai-page-back', 'Back', { html: ICONS.back, fk: 'activity:back' });\n backBtn.addEventListener('click', () => back());\n const title = el('h2', 'ai-page-title', 'AI Activity');\n title.id = nextId('ai-activity-title');\n const titleLine = el('div', 'ai-page-title-line');\n titleLine.append(title, experimentalBadge());\n const headerActions = el('div', 'ai-activity-header-actions');\n const headerStatus = inlineStatus();\n const saveAllBtn = actionButton('save-all', 'Save all');\n saveAllBtn.hidden = !canSave;\n saveAllBtn.addEventListener('click', () => { void saveAll(); });\n const clearBtn = actionButton('clear', 'Clear all');\n clearBtn.addEventListener('click', () => log.clear());\n headerActions.append(headerStatus.element, saveAllBtn, clearBtn);\n header.append(backBtn, titleLine, headerActions);\n\n const banner = el('p', 'ai-activity-banner', AI_ACTIVITY_BANNER);\n\n const body = el('div', 'ai-activity-body');\n const master = el('div', 'ai-activity-master');\n const listHead = el('div', 'ai-activity-list-head');\n const listId = nextId('ai-activity-list-label');\n const listLabel = el('span', 'ai-activity-list-label', 'Requests');\n listLabel.id = listId;\n const listCount = el('span', 'ai-activity-list-count');\n listHead.append(listLabel, listCount);\n const list = el('div', 'ai-activity-list');\n list.setAttribute('role', 'listbox');\n list.setAttribute('aria-labelledby', listId);\n master.append(listHead, list);\n const detailPane = el('section', 'ai-activity-detail');\n detailPane.tabIndex = 0;\n detailPane.setAttribute('aria-label', 'Selected request');\n body.append(master, detailPane);\n\n const empty = el('div', 'ai-activity-empty');\n const emptyTitle = el('div', 'ai-activity-empty-title');\n const emptyText = el('p', 'ai-activity-empty-text');\n empty.append(emptyTitle, emptyText);\n\n root.append(header, banner, body, empty);\n\n // ── List ──────────────────────────────────────────────────────────────────\n\n const rows = new Map<string, RowRefs>();\n\n function createRow(entry: AiActivityEntry): RowRefs {\n const row = el('div', 'ai-activity-row');\n row.setAttribute('role', 'option');\n row.dataset.entryId = entry.id;\n row.tabIndex = -1;\n const dot = el('span', 'ai-activity-dot');\n dot.setAttribute('aria-hidden', 'true');\n const head = el('span', 'ai-activity-row-head');\n const feature = el('span', 'ai-activity-row-feature');\n const statusWord = el('span', 'ai-activity-row-status');\n head.append(feature, statusWord);\n const when = el('span', 'ai-activity-row-when');\n const duration = el('span', 'ai-activity-row-duration');\n const time = el('span', 'ai-activity-row-time');\n when.append(duration, time);\n const sub = el('span', 'ai-activity-row-sub');\n const engine = el('span', 'ai-activity-row-engine');\n const locality = el('span', 'ai-activity-row-locality');\n sub.append(engine, locality);\n const tokens = el('span', 'ai-activity-row-tokens');\n row.append(dot, head, when, sub, tokens);\n const refs: RowRefs = { row, dot, feature, statusWord, time, engine, locality, duration, tokens, entry: null, shownLocal: null };\n updateRow(refs, entry);\n return refs;\n }\n\n function updateRow(refs: RowRefs, entry: AiActivityEntry): void {\n if (refs.entry === entry) {return;}\n refs.entry = entry;\n const status = aiActivityStatus(entry);\n const statusText = entry.retried ? 'Failed, retried' : STATUS_LABELS[status];\n const route = routeLabel(entry);\n const { isLocal } = routeOf(entry);\n const duration = entryDuration(entry);\n if (refs.row.dataset.status !== status) {refs.row.dataset.status = status;}\n setText(refs.feature, featureLabel(entry));\n // A row that went fine says nothing extra: the dot is enough.\n setText(refs.statusWord, status === 'ok' ? '' : statusText);\n setText(refs.time, clockTime(entry.startedAt));\n setText(refs.engine, route);\n setAttr(refs.engine, 'title', route);\n if (refs.shownLocal !== isLocal) {\n refs.shownLocal = isLocal;\n refs.locality.replaceChildren(...(isLocal === null ? [] : [localityPill(isLocal)]));\n }\n setText(refs.duration, duration === null ? '' : formatDuration(duration));\n setText(refs.tokens, tokensLabel(entry));\n setAttr(refs.row, 'aria-label', `${featureLabel(entry)}, ${statusText}, ${route}, ${clockTime(entry.startedAt)}`);\n }\n\n function renderList(entries: AiActivityEntry[]): void {\n const live = new Set(entries.map((e) => e.id));\n for (const [id, refs] of rows) {\n if (!live.has(id)) {\n refs.row.remove();\n rows.delete(id);\n }\n }\n // Newest first. New rows land on top: keep what the user is looking at\n // where it is (scroll anchoring is off in the CSS, and absent in WebKit).\n const before = list.scrollTop;\n const added: HTMLElement[] = [];\n let cursor = list.firstElementChild;\n for (let i = entries.length - 1; i >= 0; i--) {\n const entry = entries[i];\n let refs = rows.get(entry.id);\n if (!refs) {\n refs = createRow(entry);\n rows.set(entry.id, refs);\n list.insertBefore(refs.row, cursor);\n added.push(refs.row);\n continue;\n }\n updateRow(refs, entry);\n if (refs.row === cursor) {\n cursor = cursor.nextElementSibling;\n } else {\n list.insertBefore(refs.row, cursor);\n }\n }\n if (before > 0 && added.length > 0) {\n list.scrollTop = before + added.reduce((sum, row) => sum + row.offsetHeight, 0);\n }\n setText(listCount, entries.length === 0 ? '' : `${entries.length} of the last ${AI_ACTIVITY_LIMIT}`);\n }\n\n function markSelected(): void {\n for (const [id, refs] of rows) {\n const on = id === selectedId;\n setAttr(refs.row, 'aria-selected', String(on));\n refs.row.tabIndex = on ? 0 : -1;\n }\n }\n\n function selectedRow(): HTMLElement | null {\n return selectedId ? rows.get(selectedId)?.row ?? null : null;\n }\n\n function select(id: string, o: { focus?: boolean } = {}): void {\n flush();\n if (!log.get(id)) {return;}\n selectedId = id;\n markSelected();\n renderDetail(log.get(id) ?? null);\n const row = selectedRow();\n if (row) {\n row.scrollIntoView?.({ block: 'nearest' });\n if (o.focus) {row.focus({ preventScroll: true });}\n }\n }\n\n /** Enter or a click: show the request. One column switches to it; two columns move focus on Enter. */\n function openDetail(o: { focus: boolean }): void {\n if (!selectedId) {return;}\n if (narrow) {\n view = 'detail';\n applyLayout();\n }\n if (o.focus || narrow) {detailPane.focus({ preventScroll: true });}\n }\n\n list.addEventListener('click', (e) => {\n const row = (e.target as Element).closest<HTMLElement>('.ai-activity-row');\n const id = row?.dataset.entryId;\n if (!id) {return;}\n select(id, { focus: true });\n openDetail({ focus: false });\n });\n\n list.addEventListener('keydown', (e) => {\n if (e.altKey || e.ctrlKey || e.metaKey) {return;}\n const ids = Array.from(list.children, (n) => (n as HTMLElement).dataset.entryId ?? '');\n if (ids.length === 0) {return;}\n const at = selectedId ? ids.indexOf(selectedId) : -1;\n let next: string | undefined;\n if (e.key === 'ArrowDown') {next = ids[Math.min(at + 1, ids.length - 1)];}\n else if (e.key === 'ArrowUp') {next = ids[Math.max(at - 1, 0)];}\n else if (e.key === 'Home') {next = ids[0];}\n else if (e.key === 'End') {next = ids[ids.length - 1];}\n else if (e.key === 'Enter') {\n e.preventDefault();\n openDetail({ focus: true });\n return;\n } else {\n return;\n }\n e.preventDefault();\n if (next) {select(next, { focus: true });}\n });\n\n // ── Detail ────────────────────────────────────────────────────────────────\n\n function buildSection(key: SectionKey, label: string): { section: HTMLElement; summary: HTMLElement; content: HTMLElement } {\n const section = el('section', 'ai-activity-section');\n section.dataset.section = key;\n const head = el('div', 'ai-activity-section-head');\n const toggle = button('ai-disclosure ai-activity-section-toggle', label, { html: ICONS.chevron, fk: `activity:section:${key}` });\n const summary = el('span', 'ai-activity-section-summary');\n head.append(toggle, summary);\n const content = el('div', 'ai-activity-section-body');\n content.id = nextId(`ai-activity-${key}`);\n toggle.setAttribute('aria-controls', content.id);\n const apply = (): void => {\n content.hidden = collapsed[key];\n toggle.setAttribute('aria-expanded', String(!collapsed[key]));\n };\n apply();\n toggle.addEventListener('click', () => {\n collapsed[key] = !collapsed[key];\n apply();\n });\n section.append(head, content);\n return { section, summary, content };\n }\n\n function renderRoute(node: HTMLElement, entry: AiActivityEntry): void {\n const { engine, model, isLocal } = routeOf(entry);\n const parts: HTMLElement[] = [el('span', 'ai-activity-route-engine', engine ?? NO_ROUTE_LABEL)];\n if (model) {parts.push(el('span', 'ai-activity-route-model', model));}\n if (isLocal !== null) {parts.push(localityPill(isLocal));}\n node.replaceChildren(...parts);\n }\n\n function detailNotes(entry: AiActivityEntry): HTMLElement[] {\n const out: HTMLElement[] = [];\n if (entry.error) {out.push(note(entry.error.code === 'cancelled' ? 'info' : 'error', entry.error.message));}\n if (entry.retried) {out.push(note('info', 'This engine could not be reached, so the request went to another engine. That attempt is the next request in the list.'));}\n if (!entry.error && entry.route?.viaFallback) {out.push(note('info', 'The preferred engine was passed over, so a fallback engine handled this request.'));}\n return out;\n }\n\n function requestRows(entry: AiActivityEntry): Array<{ label: string; value: string; raw?: boolean }> {\n const { format, maxTokens, temperature, requestOverrides } = entry.request;\n const out: Array<{ label: string; value: string; raw?: boolean }> = [];\n if (format) {out.push({ label: 'Format', value: format });}\n if (maxTokens !== undefined) {out.push({ label: 'Max tokens', value: maxTokens.toLocaleString() });}\n if (temperature !== undefined) {out.push({ label: 'Temperature', value: String(temperature) });}\n if (requestOverrides) {out.push({ label: 'Overrides', value: JSON.stringify(requestOverrides), raw: true });}\n return out;\n }\n\n /** The footer under Received: empty until the request has ended. */\n function resultRows(entry: AiActivityEntry): Array<{ label: string; value: string }> {\n if (entry.endedAt === null) {return [];}\n const { usage, finishReason, timing, served } = entry.response;\n const out: Array<{ label: string; value: string }> = [];\n const usageParts: string[] = [];\n if (usage?.promptTokens !== undefined) {usageParts.push(`${usage.promptTokens.toLocaleString()} prompt`);}\n if (usage?.completionTokens !== undefined) {usageParts.push(`${usage.completionTokens.toLocaleString()} completion`);}\n if (usageParts.length > 0) {out.push({ label: 'Usage', value: `${usageParts.join(' · ')} tokens` });}\n if (finishReason) {out.push({ label: 'Finish reason', value: finishReason });}\n const total = timing?.totalMs ?? entryDuration(entry);\n if (total !== null) {\n const first = timing?.firstTokenMs;\n out.push({ label: 'Timing', value: first === undefined ? formatDuration(total) : `${formatDuration(total)} total · first token at ${formatDuration(first)}` });\n }\n if (served) {out.push({ label: 'Served by', value: `${served.engineName} · ${served.modelId} (${served.isLocal ? 'local' : 'cloud'})` });}\n if (entry.error) {out.push({ label: 'Error code', value: entry.error.code });}\n return out;\n }\n\n function receivedSummaryText(entry: AiActivityEntry): string {\n const size = plural(entry.response.text.length, 'character');\n if (entry.endedAt === null) {return entry.response.text ? `Streaming · ${size}` : 'Waiting for the first token';}\n return entry.response.text ? size : 'Nothing received';\n }\n\n function buildDetail(entry: AiActivityEntry): DetailRefs {\n const head = el('div', 'ai-activity-detail-head');\n const titleRow = el('div', 'ai-activity-detail-title-row');\n const detailTitle = el('h3', 'ai-activity-detail-title', featureLabel(entry));\n const status = el('span', 'ai-activity-status');\n const dot = el('span', 'ai-activity-dot');\n dot.setAttribute('aria-hidden', 'true');\n const statusWord = el('span', 'ai-activity-status-word');\n status.append(dot, statusWord);\n\n const actions = el('div', 'ai-activity-detail-actions');\n const copyStatus = inlineStatus();\n const copyBtn = actionButton('copy', 'Copy');\n copyBtn.addEventListener('click', () => copySelected(copyStatus));\n actions.append(copyStatus.element, copyBtn);\n if (canSave) {\n const saveBtn = actionButton('save', 'Save this request');\n saveBtn.addEventListener('click', () => { void saveSelected(saveBtn, copyStatus); });\n actions.append(saveBtn);\n }\n titleRow.append(detailTitle, status, actions);\n\n const route = el('div', 'ai-activity-route');\n renderRoute(route, entry);\n const facts = [`Task: ${entry.task}`, `Started ${clockTime(entry.startedAt)}`];\n const thinking = thinkingLabel(entry.thinking);\n if (thinking) {facts.unshift(`Thinking: ${thinking}`);}\n if (entry.attempt === 2) {facts.push('Second attempt');}\n head.append(titleRow, route, el('div', 'ai-activity-thinking', facts.join(' · ')));\n\n const notes = el('div', 'ai-activity-notes');\n const docs = el('div', 'ai-activity-docs');\n\n const sent = buildSection('sent', 'Sent');\n const totalChars = entry.request.messages.reduce((sum, m) => sum + messageText(m).length, 0);\n sent.summary.textContent = `${plural(entry.request.messages.length, 'message')} · ${plural(totalChars, 'character')}`;\n for (const message of entry.request.messages) {\n const text = messageText(message);\n const block = el('div', 'ai-activity-block ai-activity-message');\n block.dataset.role = message.role;\n const caption = el('div', 'ai-activity-block-caption');\n caption.append(el('span', 'ai-activity-message-role', message.role), el('span', 'ai-activity-block-size', plural(text.length, 'character')));\n block.append(caption, el('pre', 'ai-activity-text ai-activity-message-text', text));\n sent.content.append(block);\n }\n const requestMeta = requestRows(entry);\n if (requestMeta.length > 0) {sent.content.append(metaList(requestMeta));}\n\n const received = buildSection('received', 'Received');\n const receivedBlock = el('div', 'ai-activity-block ai-activity-received');\n const receivedPre = el('pre', 'ai-activity-text ai-activity-received-text');\n // One text node for the life of the pane: appending to it keeps a text selection.\n const receivedText = document.createTextNode('');\n receivedPre.append(receivedText);\n receivedBlock.append(receivedPre);\n const receivedMeta = el('div', 'ai-activity-received-meta');\n received.content.append(receivedBlock, receivedMeta);\n\n detailPane.replaceChildren();\n const inner = el('div', 'ai-activity-detail-inner');\n inner.append(head, notes, docs, sent.section, received.section);\n detailPane.append(inner);\n detailPane.scrollTop = 0;\n\n const refs: DetailRefs = {\n entry, status, statusWord, route, notes, docs,\n receivedSummary: received.summary, receivedBlock, receivedText, receivedMeta, copyStatus,\n };\n syncDetail(refs, entry, true);\n return refs;\n }\n\n /** Bring the open pane up to `entry`: append response text; rebuild only the small parts that changed. */\n function syncDetail(refs: DetailRefs, entry: AiActivityEntry, first = false): void {\n const previous = refs.entry;\n refs.entry = entry;\n const text = entry.response.text;\n const current = refs.receivedText.data;\n if (text !== current) {\n if (text.startsWith(current)) {refs.receivedText.appendData(text.slice(current.length));}\n else {refs.receivedText.data = text;}\n }\n refs.receivedBlock.hidden = text === '';\n setText(refs.receivedSummary, receivedSummaryText(entry));\n // A hop's page list arrives after its reply was acted on, so after the request ended.\n if (first || previous.docs !== entry.docs) {\n const rows = docsDetailRows(entry);\n refs.docs.replaceChildren(...(rows.length > 0 ? [metaList(rows)] : []));\n }\n const ended = first || previous.endedAt !== entry.endedAt || previous.error !== entry.error || previous.retried !== entry.retried || previous.response.served !== entry.response.served;\n if (!ended) {return;}\n const status = aiActivityStatus(entry);\n refs.status.dataset.status = status;\n setText(refs.statusWord, entry.retried ? 'Failed, retried' : STATUS_LABELS[status]);\n renderRoute(refs.route, entry);\n refs.notes.replaceChildren(...detailNotes(entry));\n const meta = resultRows(entry);\n refs.receivedMeta.replaceChildren(...(meta.length > 0 ? [metaList(meta)] : []));\n }\n\n function renderDetail(entry: AiActivityEntry | null): void {\n if (!entry) {\n detail?.copyStatus.clear();\n detail = null;\n detailPane.replaceChildren();\n return;\n }\n if (detail && detail.entry.id === entry.id) {\n if (detail.entry !== entry) {syncDetail(detail, entry);}\n return;\n }\n detail?.copyStatus.clear();\n detail = buildDetail(entry);\n }\n\n // ── Copy and Save ─────────────────────────────────────────────────────────\n\n function copySelected(status: ReturnType<typeof inlineStatus>): void {\n const entry = selectedId ? log.get(selectedId) : undefined;\n if (!entry) {return;}\n let written: Promise<void>;\n try {\n written = navigator.clipboard.writeText(formatActivityExport([entry]));\n } catch {\n // No clipboard API in this context.\n status.show('Could not copy', 'error', CONFIRM_MS * 2);\n return;\n }\n written.then(\n () => { if (!destroyed) {status.show('Copied', 'ok', CONFIRM_MS);} },\n () => { if (!destroyed) {status.show('Could not copy', 'error', CONFIRM_MS * 2);} },\n );\n }\n\n /** The host's save. It resolves after a cancelled dialog too, so success says nothing. */\n async function saveEntries(entries: AiActivityEntry[], status: ReturnType<typeof inlineStatus>): Promise<void> {\n status.clear();\n try {\n await opts.saveTextFile?.(activityExportFileName(), formatActivityExport(entries));\n } catch (err) {\n if (destroyed) {return;}\n const reason = err instanceof Error && err.message ? `: ${err.message}` : '';\n status.show(`Could not save${reason}`, 'error');\n }\n }\n\n async function saveSelected(btn: HTMLButtonElement, status: ReturnType<typeof inlineStatus>): Promise<void> {\n const entry = selectedId ? log.get(selectedId) : undefined;\n if (!entry) {return;}\n btn.disabled = true;\n await saveEntries([entry], status);\n btn.disabled = false;\n }\n\n async function saveAll(): Promise<void> {\n const entries = log.entries();\n if (entries.length === 0) {return;}\n savingAll = true;\n saveAllBtn.disabled = true;\n await saveEntries(entries, headerStatus);\n savingAll = false;\n if (!destroyed) {saveAllBtn.disabled = log.entries().length === 0;}\n }\n\n // ── Render ────────────────────────────────────────────────────────────────\n\n function flush(): void {\n if (renderTimer !== undefined) {render();}\n }\n\n function render(): void {\n window.clearTimeout(renderTimer);\n renderTimer = undefined;\n lastRender = Date.now();\n const entries = log.entries();\n const isEmpty = entries.length === 0;\n\n root.dataset.recording = log.enabled ? 'on' : 'off';\n body.hidden = isEmpty;\n empty.hidden = !isEmpty;\n if (isEmpty) {\n const copy = log.enabled ? AI_ACTIVITY_EMPTY : AI_ACTIVITY_OFF;\n setText(emptyTitle, copy.title);\n setText(emptyText, copy.text);\n view = 'list';\n applyLayout();\n }\n clearBtn.disabled = isEmpty;\n if (!savingAll) {saveAllBtn.disabled = isEmpty;}\n\n renderList(entries);\n\n // Keep the selection while requests come and go. The first request is\n // selected for you; a request that fell off the ring hands over to the next one.\n if (selectedId && !log.get(selectedId)) {selectedId = isEmpty ? null : entries[0].id;}\n else if (!selectedId && !isEmpty) {selectedId = entries[entries.length - 1].id;}\n markSelected();\n renderDetail(selectedId ? log.get(selectedId) ?? null : null);\n keepFocusInside();\n }\n\n /** A row that left the list or a button that just disabled took focus with it: Escape must still work. */\n function keepFocusInside(): void {\n if (!mounted) {return;}\n const active = document.activeElement;\n if (active === document.body || (active instanceof HTMLButtonElement && active.disabled && root.contains(active))) {focus();}\n }\n\n function onLogChange(): void {\n if (destroyed) {return;}\n // A new request or a cleared log shows at once; tokens wait their turn.\n const entries = log.entries();\n const newest = entries[entries.length - 1];\n const wait = RENDER_THROTTLE_MS - (Date.now() - lastRender);\n if (wait <= 0 || !newest || !rows.has(newest.id)) {\n render();\n } else if (renderTimer === undefined) {\n renderTimer = window.setTimeout(render, wait);\n }\n }\n\n // ── Keyboard, layout, lifetime ────────────────────────────────────────────\n\n function focus(): void {\n (selectedRow() ?? backBtn).focus({ preventScroll: true });\n }\n\n /** Back: from the request to the list in one column, otherwise close. */\n function back(): void {\n if (narrow && view === 'detail') {\n view = 'list';\n applyLayout();\n focus();\n return;\n }\n ctx.close();\n }\n\n root.addEventListener('keydown', (e) => {\n if (e.key !== 'Escape' || e.defaultPrevented) {return;}\n // Escape is Back; nothing else (a modal under the panel) should see it.\n e.preventDefault();\n e.stopPropagation();\n back();\n });\n\n function applyLayout(): void {\n root.classList.toggle('is-narrow', narrow);\n root.dataset.view = narrow ? view : 'both';\n backBtn.setAttribute('aria-label', narrow && view === 'detail' ? 'Back to the list' : 'Back');\n }\n\n function measure(width: number): void {\n // Zero means \"not laid out\" (jsdom, a hidden host): keep two panes.\n const next = width > 0 && width < NARROW_PX;\n if (next === narrow) {return;}\n narrow = next;\n applyLayout();\n }\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver === 'function') {\n resizeObserver = new ResizeObserver((entries) => { measure(entries[0]?.contentRect.width ?? 0); });\n resizeObserver.observe(root);\n }\n\n container.append(root);\n applyLayout();\n render();\n mounted = true;\n measure(root.getBoundingClientRect().width);\n const unsubscribe = log.subscribe(onLogChange);\n\n return {\n destroy() {\n if (destroyed) {return;}\n destroyed = true;\n unsubscribe();\n window.clearTimeout(renderTimer);\n renderTimer = undefined;\n resizeObserver?.disconnect();\n headerStatus.clear();\n detail?.copyStatus.clear();\n root.remove();\n },\n focus,\n refresh() {\n if (!destroyed) {render();}\n },\n };\n}\n","/**\n * The documentation chat's wiring: `ai/docs/loop.ts` is pure, so it is handed\n * the editor's request layer here. Beside `ai-request.ts`, in the lazy AI chunk;\n * the chat panel reaches it through `ai-ui.ts`.\n */\n\nimport { createDocsChat, type AiDocsActivityDetail, type DocsChat, type DocsLoopDeps, type DocsRunRequest } from './ai';\nimport { endAiTurn, resolveAiTurnRoute, runAiCompletion, type AiRunContext } from './ai-request';\n\n/** `format: 'json'` is dropped for a model known not to do it: the prompt still asks, and the parser is lenient. */\nfunction withSupportedFormat(ctx: AiRunContext, req: DocsRunRequest): DocsRunRequest {\n if (req.format !== 'json' || !req.pin) {return req;}\n const { pin } = req;\n const model = ctx.settings().engines.find((e) => e.id === pin.engineId)?.models.find((m) => m.id === pin.modelId);\n if (model?.capabilities.json !== false) {return req;}\n const { format: _format, ...rest } = req;\n return rest;\n}\n\nexport function aiDocsLoopDeps(ctx: AiRunContext): DocsLoopDeps {\n return {\n resolveRoute: (req, signal) => resolveAiTurnRoute(ctx, req, signal),\n run: (req, events, signal) => runAiCompletion(ctx, withSupportedFormat(ctx, req), events, signal),\n contextTokens(route) {\n if (!route) {return null;}\n const engine = ctx.settings().engines.find((e) => e.id === route.engineId);\n return engine?.models.find((m) => m.id === route.modelId)?.capabilities.contextTokens ?? null;\n },\n annotate(requestId: string, detail: AiDocsActivityDetail) {\n // The recorder is a side channel: a failure in it never reaches the turn.\n try { ctx.activity?.update(requestId, { docs: detail }); } catch { /* ignore */ }\n },\n endTurn(pin) {\n if (pin.turnId) {endAiTurn(ctx, pin.turnId);}\n },\n };\n}\n\n/** One per editor instance: it holds the one-request-in-flight rule. */\nexport function createAiDocsChat(ctx: AiRunContext): DocsChat {\n return createDocsChat(aiDocsLoopDeps(ctx));\n}\n","/**\n * Inline suggestions (\"ghost text\"): the surface-agnostic controller\n * (decisions D1 to D13 in ghost-text-plan.md). It knows nothing about\n * ProseMirror or the DOM. The editor plugin feeds it document events and\n * shows whatever it hands to `onSuggestion`.\n *\n * - Timing (D1, D2): every text change aborts the request in flight, clears\n * the suggestion and restarts one idle timer (`delayMs`, `trigger: 'manual'`\n * turns the timer off). A selection move aborts and clears but starts no\n * timer. There is never a queue: one request at a time.\n * - Streaming (D5): each token re-trims the text so far; a stop rule firing\n * aborts the request so the model does not keep generating.\n * - Accept (D6): the whole text, or one word; typing a character that matches\n * the start of the suggestion keeps the rest.\n * - Errors (D9): `cloudBlocked`, `capability`, `featureDisabled` and a refused\n * consent are silent (the suggestion is just cleared) but reported once per\n * session through `onError`; anything else backs off (delay doubles up to\n * 5 s, reset on success).\n * - Activity (D10): only an accepted suggestion or a failed request is\n * recorded, by this controller, through `record`. Callers pass\n * `activity: undefined` in the run context so dismissed ghosts do not flood\n * the recorder.\n *\n * Lives in the lazy AI chunk (`ai-ui.ts`); the editor must not import it\n * statically.\n */\n\nimport {\n buildContinueMessages,\n continueMaxTokens,\n ghostAcceptWord,\n ghostContext,\n ghostPrefixMatch,\n makeAiError,\n trimGhostSuggestionDetailed,\n type AiError,\n type AiErrorCode,\n type AiGhostTextOptions,\n type AiCompletionRequest,\n type AiMessage,\n type AiRouteOk,\n type AiServedBy,\n type GhostBlockKind,\n} from './ai';\nimport type { AiActivityEntry, AiActivityRoute } from './ai-activity';\nimport type { AiRunEvents, AiRunOutcome, AiRunRequest, AiRunThinking } from './ai-request';\n\n/** What the plugin reports on every text change. */\nexport interface GhostChangeInput {\n /** Serialize lazily: called only when a request is about to fire, never per keystroke. */\n read: () => { markdown: string; caretOffset: number };\n atBlockEnd: boolean;\n eligible: boolean; // false: abort, clear, no timer\n blockKind?: GhostBlockKind; // from ai/prompts/continue.ts\n}\n\nexport interface GhostController {\n /** Document text changed: abort, clear, restart the idle timer. */\n noteChange(input: GhostChangeInput): void;\n /** Caret moved without a text change: abort, clear, cancel the timer, do NOT start one (D1). */\n noteSelectionMove(): void;\n /**\n * Manual: fires now from `input` (or the latest `noteChange` input when\n * omitted) if eligible, ignoring the trigger mode. `input` lets the caller\n * hand in a fresh snapshot when the caret moved since the last change.\n */\n triggerNow(input?: GhostChangeInput): void;\n /** The whole visible text to insert (null if none); clears, records one activity entry, calls `onServed`. */\n accept(): string | null;\n /** The next word per `ghostAcceptWord` (null if none); the rest stays visible via `onSuggestion`. */\n acceptWord(): string | null;\n /** Abort, clear, cancel the timer. */\n dismiss(): void;\n /** true: `char` matched (`ghostPrefixMatch`), the stream was aborted, the remainder stays via `onSuggestion`. false: no match, nothing else done. */\n typed(char: string): boolean;\n destroy(): void;\n}\n\n/** Why a ghost request failed; the first four are silent (no toast), the rest are the error codes. */\nexport type GhostErrorReason = AiErrorCode | 'capability' | 'featureDisabled';\n\nexport interface GhostErrorInfo {\n reason: GhostErrorReason;\n /** True for a reason that is shown nowhere but the toolbar menu; reported once per session. */\n silent: boolean;\n /** The router's or the engine's own message, for the menu's tooltip. */\n error: AiError;\n}\n\nexport interface GhostControllerDeps {\n /** The editor's run, built with `activity: undefined` (D10). */\n run(req: AiRunRequest, events: AiRunEvents, signal: AbortSignal): Promise<AiRunOutcome>;\n /** Read on every use, so a settings broadcast needs no rebuild. */\n options(): AiGhostTextOptions;\n /** The routed model's context window in tokens (a guess is fine). */\n contextTokens(): number;\n /** The text to show at the caret, or null for none. Called only when the text changes. */\n onSuggestion(text: string | null): void;\n /** A ghost request is streaming (the toolbar AI button pulses). Called only when the state changes. */\n onBusy?(busy: boolean): void;\n /** An accepted suggestion was served by this engine (the footer chip, D11). */\n onServed?(served: AiServedBy, viaFallback: boolean): void;\n /** See `GhostErrorInfo`. */\n onError?(info: GhostErrorInfo): void;\n /** The activity recorder (D10): one entry per accepted suggestion, one per failed request. */\n record?(entry: AiActivityEntry): void;\n /** The engine's display name for the activity entry and the footer chip (defaults to the engine id). */\n routeLabel?(route: AiRouteOk): string;\n /** Timer seam for tests. */\n setTimer?: (fn: () => void, ms: number) => unknown;\n clearTimer?: (handle: unknown) => void;\n now?: () => number;\n}\n\n/** The longest delay network backoff may reach (D2 note in the milestone). */\nexport const GHOST_BACKOFF_MAX_MS = 5000;\n\nconst SILENT_REASONS: ReadonlySet<GhostErrorReason> = new Set<GhostErrorReason>(['cloudBlocked', 'consentDenied', 'capability', 'featureDisabled']);\n\n/**\n * Which reason an error stands for. `routeUnusableError` (ai-request.ts)\n * keeps `cloudBlocked` and `consentDenied` as codes but turns every other\n * unusable route into `unknown` with the router's sentence, so the two\n * silent ones that matter here are told apart by that sentence.\n */\nexport function classifyGhostError(error: AiError): GhostErrorReason {\n if (error.code !== 'unknown') {return error.code;}\n if (/\\bis turned off\\.?$/i.test(error.message) || /^No engine and model is chosen/i.test(error.message)) {return 'featureDisabled';}\n if (/\\blacks\\b/.test(error.message)) {return 'capability';}\n return 'unknown';\n}\n\n/** What the current (or last) suggestion came from; kept for the activity entry. */\ninterface Origin {\n id: string;\n startedAt: number;\n endedAt: number | null;\n request: AiCompletionRequest;\n route: AiRouteOk | null;\n thinking: AiRunThinking | null;\n served: AiServedBy | null;\n viaFallback: boolean;\n raw: string;\n /** The activity entry and `onServed` were already issued for this suggestion (a word was accepted). */\n recorded: boolean;\n}\n\nlet originCounter = 0;\n\nexport function createGhostController(deps: GhostControllerDeps): GhostController {\n const setTimer = deps.setTimer ?? ((fn: () => void, ms: number): unknown => setTimeout(fn, ms));\n const clearTimer = deps.clearTimer ?? ((h: unknown): void => clearTimeout(h as ReturnType<typeof setTimeout>));\n const now = deps.now ?? ((): number => Date.now());\n\n let destroyed = false;\n let latest: GhostChangeInput | null = null;\n let timer: unknown = null;\n let controller: AbortController | null = null;\n /** Bumped on every abort and every new request; a late reply from an older one is ignored. */\n let seq = 0;\n let busy = false;\n /** The text on screen (what `onSuggestion` last received), or null. */\n let visible: string | null = null;\n let origin: Origin | null = null;\n /** Extra delay after network failures: 0 means none. */\n let backoffMs = 0;\n const reported = new Set<GhostErrorReason>();\n /** The user refused cloud consent: no more requests this session (D9). */\n let silenced = false;\n /** \"Allow once\" covers one request, so a pause stops asking on every stop; the shortcut still can. */\n let idleStopped = false;\n\n function setBusy(next: boolean): void {\n if (busy === next) {return;}\n busy = next;\n try { deps.onBusy?.(next); } catch { /* a UI callback never breaks the controller */ }\n }\n\n function show(text: string | null): void {\n const next = text === null || text === '' ? null : text;\n if (next === visible) {return;}\n visible = next;\n if (destroyed) {return;}\n deps.onSuggestion(next);\n }\n\n function cancelTimer(): void {\n if (timer !== null) {\n clearTimer(timer);\n timer = null;\n }\n }\n\n /** Abort the request in flight (if any) and ignore whatever it still sends. */\n function stopStream(): void {\n seq += 1;\n const c = controller;\n controller = null;\n if (c && !c.signal.aborted) {c.abort();}\n setBusy(false);\n }\n\n /** Stop everything and clear the suggestion. */\n function clearAll(): void {\n cancelTimer();\n stopStream();\n origin = null;\n show(null);\n }\n\n function delay(): number {\n return Math.max(deps.options().delayMs, backoffMs);\n }\n\n function bumpBackoff(): void {\n backoffMs = Math.min(GHOST_BACKOFF_MAX_MS, Math.max(deps.options().delayMs, backoffMs) * 2);\n }\n\n function activityRoute(route: AiRouteOk): AiActivityRoute {\n let label = route.engineId;\n try { label = deps.routeLabel?.(route) ?? label; } catch { /* keep the id */ }\n return { engineId: route.engineId, modelId: route.modelId, label, isLocal: route.isLocal, viaFallback: route.viaFallback };\n }\n\n function servedOf(o: Origin): AiServedBy | null {\n if (o.served) {return o.served;}\n if (!o.route) {return null;}\n return { engineId: o.route.engineId, engineName: activityRoute(o.route).label, modelId: o.route.modelId, isLocal: o.route.isLocal };\n }\n\n function record(entry: AiActivityEntry): void {\n try { deps.record?.(entry); } catch { /* the recorder is a side channel */ }\n }\n\n function entryFor(o: Origin, response: string, error: AiError | null): AiActivityEntry {\n return {\n id: o.id,\n startedAt: o.startedAt,\n endedAt: o.endedAt ?? now(),\n feature: 'ghostText',\n job: 'ghostText',\n task: o.request.task,\n route: o.route ? activityRoute(o.route) : null,\n thinking: o.thinking,\n request: o.request,\n response: { text: response, ...(o.served ? { served: o.served } : {}) },\n error,\n attempt: 1,\n };\n }\n\n /** The first accept of a suggestion: one activity entry (the trimmed text on screen, not the raw stream), and the footer chip. */\n function markAccepted(): void {\n const o = origin;\n if (!o || o.recorded) {return;}\n o.recorded = true;\n record(entryFor(o, visible ?? o.raw, null));\n const served = servedOf(o);\n if (served) {\n try { deps.onServed?.(served, o.viaFallback); } catch { /* ignore */ }\n }\n }\n\n function handleError(err: unknown, o: Origin): void {\n const error = toError(err);\n if (error.code === 'cancelled') {return;}\n const reason = classifyGhostError(error);\n const silent = SILENT_REASONS.has(reason);\n show(null);\n if (reason === 'consentDenied') {silenced = true;}\n if (silent) {\n if (!reported.has(reason)) {\n reported.add(reason);\n report({ reason, silent: true, error });\n }\n return;\n }\n bumpBackoff();\n o.endedAt = now();\n record(entryFor(o, o.raw, error));\n report({ reason, silent: false, error });\n }\n\n function report(info: GhostErrorInfo): void {\n if (destroyed) {return;}\n try { deps.onError?.(info); } catch { /* ignore */ }\n }\n\n function fire(input: GhostChangeInput): void {\n if (destroyed || silenced || !input.eligible) {return;}\n cancelTimer();\n stopStream();\n show(null);\n origin = null;\n\n const options = deps.options();\n let snapshot: { markdown: string; caretOffset: number };\n try { snapshot = input.read(); } catch { return; }\n const maxTokens = continueMaxTokens(options.maxTokens);\n const ctx = ghostContext(snapshot.markdown, snapshot.caretOffset, deps.contextTokens(), { outputTokens: maxTokens });\n // Nothing to continue (empty document, caret in the frontmatter).\n if (ctx.before.trim() === '') {return;}\n\n const messages: AiMessage[] = buildContinueMessages({ before: ctx.before, after: ctx.after, ...(input.blockKind ? { blockKind: input.blockKind } : {}) });\n const req: AiRunRequest = {\n feature: 'ghostText',\n task: 'continue',\n sends: 'cursor',\n messages,\n maxTokens,\n temperature: 0.3,\n thinking: 'off',\n job: 'ghostText',\n localOnly: options.localOnly,\n };\n\n const ac = new AbortController();\n controller = ac;\n const mySeq = ++seq;\n originCounter += 1;\n const o: Origin = {\n id: `ai-ghostText-${now().toString(36)}-g${originCounter}`,\n startedAt: now(),\n endedAt: null,\n request: { requestId: '', feature: req.feature, task: req.task ?? 'continue', messages, maxTokens, temperature: 0.3 },\n route: null,\n thinking: null,\n served: null,\n viaFallback: false,\n raw: '',\n recorded: false,\n };\n o.request.requestId = o.id;\n origin = o;\n setBusy(true);\n\n const events: AiRunEvents = {\n onRoute(route, thinking) {\n if (mySeq !== seq) {return;}\n o.route = route;\n o.thinking = thinking;\n o.viaFallback = route?.viaFallback ?? false;\n },\n onToken(_delta, text) {\n if (mySeq !== seq) {return;}\n o.raw = text;\n const r = trimGhostSuggestionDetailed(text, { atBlockEnd: input.atBlockEnd, before: ctx.before });\n show(r.text);\n if (r.stopped) {\n // A stop rule fired: more tokens cannot change the suggestion, so stop generating.\n o.endedAt = now();\n succeeded();\n stopStream();\n }\n },\n // Not tied to `seq`: an answer given after this request was aborted counts too.\n onConsent(reply) {\n if (reply === 'once') {idleStopped = true;}\n },\n };\n\n let pending: Promise<AiRunOutcome>;\n try {\n pending = deps.run(req, events, ac.signal);\n } catch (err) {\n stopStream();\n handleError(err, o);\n return;\n }\n pending.then(\n (outcome) => {\n if (mySeq !== seq) {return;}\n o.endedAt = now();\n o.served = outcome.result.served ?? null;\n o.viaFallback = outcome.viaFallback;\n if (outcome.route) {o.route = outcome.route;}\n if (outcome.thinking) {o.thinking = outcome.thinking;}\n if (outcome.requestId) {\n o.id = outcome.requestId;\n o.request.requestId = outcome.requestId;\n }\n o.raw = outcome.result.text || o.raw;\n const r = trimGhostSuggestionDetailed(o.raw, { atBlockEnd: input.atBlockEnd, before: ctx.before });\n show(r.text);\n succeeded();\n controller = null;\n setBusy(false);\n },\n (err) => {\n if (mySeq !== seq) {return;}\n controller = null;\n setBusy(false);\n handleError(err, o);\n },\n );\n }\n\n /** A request produced an answer: the delay returns to normal and silent reasons can be reported again. */\n function succeeded(): void {\n backoffMs = 0;\n reported.clear();\n }\n\n function startTimer(input: GhostChangeInput): void {\n timer = setTimer(() => {\n timer = null;\n if (!idleStopped) {fire(input);}\n }, delay());\n }\n\n return {\n noteChange(input) {\n if (destroyed) {return;}\n latest = input;\n clearAll();\n if (!input.eligible || silenced || idleStopped) {return;}\n if (deps.options().trigger === 'manual') {return;}\n startTimer(input);\n },\n\n noteSelectionMove() {\n if (destroyed) {return;}\n clearAll();\n },\n\n triggerNow(input) {\n if (destroyed) {return;}\n if (input) {latest = input;}\n const target = latest;\n clearAll();\n if (!target || !target.eligible) {return;}\n fire(target);\n },\n\n accept() {\n const text = visible;\n if (text === null) {return null;}\n markAccepted();\n cancelTimer();\n stopStream();\n origin = null;\n show(null);\n return text;\n },\n\n acceptWord() {\n const text = visible;\n if (text === null) {return null;}\n const word = ghostAcceptWord(text);\n markAccepted();\n // The rest is what is left of the text as it stands; further tokens would no longer line up with the caret.\n stopStream();\n show(text.slice(word.length));\n return word;\n },\n\n dismiss() {\n if (destroyed) {return;}\n clearAll();\n },\n\n typed(char) {\n const text = visible;\n if (text === null || char === '') {return false;}\n const rest = ghostPrefixMatch(text, char);\n if (rest === null) {return false;}\n stopStream();\n if (rest === '') {origin = null;}\n show(rest);\n return true;\n },\n\n destroy() {\n if (destroyed) {return;}\n cancelTimer();\n stopStream();\n destroyed = true;\n latest = null;\n origin = null;\n visible = null;\n },\n };\n}\n\nfunction toError(err: unknown): AiError {\n if (typeof err === 'object' && err !== null && typeof (err as AiError).code === 'string' && typeof (err as AiError).message === 'string') {\n return err as AiError;\n }\n if (typeof err === 'object' && err !== null && (err as { name?: unknown }).name === 'AbortError') {return makeAiError('cancelled');}\n return makeAiError('unknown', err instanceof Error ? err.message : undefined);\n}\n","/**\n * Inline suggestions (\"ghost text\"): the ProseMirror half (decisions D1, D2,\n * D6 and D7 in ghost-text-plan.md). `ai-ghost.ts` decides when to ask and what\n * to show; this plugin tells it what the document did and draws the answer.\n *\n * - The suggestion is plugin state drawn as a widget decoration, so it is never\n * in the document, the serialized markdown or `getText`.\n * - Keys are taken in `handleDOMEvents.keydown`, not `handleKeyDown`:\n * `view.someProp` asks the editor's own `editorProps.handleKeyDown` before\n * any plugin whatever the plugin order, and that handler owns Tab in lists\n * and tables. DOM event handlers run ahead of it. Nothing is claimed unless a\n * suggestion shows (D7).\n * - Register with a plain `editor.registerPlugin(plugin)`. Appended last, this\n * plugin's `view.update` runs after the autocompletes' have opened or closed\n * their popups, which is what `popupOpen` reads.\n * - `view.update` never dispatches. The controller's `onSuggestion(null)` from\n * inside `noteChange` lands on a state `apply` already cleared, so\n * `setGhostSuggestion` has nothing to do.\n *\n * Lives in the lazy AI chunk (`ai-ui.ts`); only types come from `ai-ghost`.\n */\n\nimport { Plugin, PluginKey, type EditorState, type PluginSpec, type Transaction } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet, type EditorView } from '@tiptap/pm/view';\nimport type { Node as PmNode, ResolvedPos } from '@tiptap/pm/model';\nimport { closeHistory, isHistoryTransaction } from '@tiptap/pm/history';\nimport type { GhostBlockKind } from './ai';\nimport type { GhostChangeInput, GhostController } from './ai-ghost';\n\nexport interface GhostPluginOptions {\n controller: GhostController;\n /** Markdown for a document, without the frontmatter: `(doc) => editor.storage.markdown.serializer.serialize(doc)`. */\n serialize: (doc: PmNode) => string;\n /** An emoji, wikilink, tag or slash popup is open; it wins over a suggestion (D7). */\n popupOpen?: () => boolean;\n /** False stops everything, for example in source mode. */\n enabled?: () => boolean;\n}\n\n/** What the last root transaction was: ours, a keystroke candidate, any other edit, or no edit. */\ntype GhostChange = 'own' | 'typing' | 'other' | null;\n\nexport interface AiGhostState {\n /** The text on screen, or null. */\n text: string | null;\n pos: number;\n /** When this suggestion first showed: streaming redraws the widget, the fade must not restart. */\n shownAt: number;\n change: GhostChange;\n decorations: DecorationSet;\n}\n\ninterface GhostMeta {\n /** Present: show this text (null clears it). */\n text?: string | null;\n /** Our own accept or typed-match edit: keep the suggestion and tell the controller nothing. */\n own?: boolean;\n}\n\ninterface GhostPluginSpec extends PluginSpec<AiGhostState> {\n triggerNow(view: EditorView): void;\n}\n\nexport const aiGhostKey = new PluginKey<AiGhostState>('aiGhost');\n\n/** A document edit counts as a keystroke only this soon after a key (D1). */\nconst GHOST_KEY_WINDOW_MS = 1000;\n\n/** Marks the caret in the markdown; private-use characters no serializer escapes and no document holds. */\nconst CARET_MARK = '';\n\n/** Blocks a suggestion can live in, outermost to innermost. Tables and footnote definitions are left out on purpose (D1). */\nconst ALLOWED_CONTAINERS = new Set(['doc', 'blockquote', 'callout', 'bulletList', 'orderedList', 'listItem', 'taskList', 'taskItem']);\n\nconst EMPTY: AiGhostState = { text: null, pos: 0, shownAt: 0, change: null, decorations: DecorationSet.empty };\n\nfunction classify(tr: Transaction, meta: GhostMeta | undefined): GhostChange {\n if (meta?.own) {return 'own';}\n if (!tr.docChanged) {return null;}\n // Undoing an accept must not bring the same suggestion back, and a paste or a host update is not typing.\n const notTyping = isHistoryTransaction(tr) || !!tr.getMeta('paste') || !!tr.getMeta('uiEvent')\n || !!tr.getMeta('preventUpdate') || tr.getMeta('addToHistory') === false;\n return notTyping ? 'other' : 'typing';\n}\n\nfunction ghostWidget(state: EditorState, text: string, pos: number, shownAt: number): DecorationSet {\n const toDOM = (view: EditorView): Node => {\n const span = view.dom.ownerDocument.createElement('span');\n span.className = 'mikedown-ghost';\n span.setAttribute('aria-hidden', 'true');\n span.setAttribute('spellcheck', 'false');\n // A negative delay resumes the fade where the previous token's widget left off.\n span.style.animationDelay = `${shownAt - Date.now()}ms`;\n span.textContent = text;\n return span;\n };\n // The marks the text will take on accept, so bold stays bold before and after.\n const marks = state.storedMarks ?? state.selection.$head.marks();\n return DecorationSet.create(state.doc, [Decoration.widget(pos, toDOM, { side: 1, marks })]);\n}\n\nfunction applyGhost(tr: Transaction, prev: AiGhostState, oldState: EditorState, newState: EditorState): AiGhostState {\n const meta = tr.getMeta(aiGhostKey) as GhostMeta | undefined;\n const root = tr.getMeta('appendedTransaction') as Transaction | undefined;\n // An appended transaction (autolink, say) belongs to the edit that caused it.\n const change = (root ? prev.change : null) ?? classify(tr, meta);\n\n let text = prev.text;\n if (meta && 'text' in meta) {\n text = meta.text ?? null;\n } else if (change !== 'own' && (tr.docChanged || !oldState.selection.eq(newState.selection))) {\n text = null;\n }\n\n if (text === null) {\n return prev.text === null && prev.change === change ? prev : { ...EMPTY, change };\n }\n const pos = newState.selection.head;\n if (text === prev.text && pos === prev.pos && !tr.docChanged) {\n return prev.change === change ? prev : { ...prev, change };\n }\n const shownAt = prev.text === null ? Date.now() : prev.shownAt;\n return { text, pos, shownAt, change, decorations: ghostWidget(newState, text, pos, shownAt) };\n}\n\n/**\n * What may show of `text`: its first line. The trim keeps a single newline at\n * block end, but inserting it would put a raw line break in the paragraph and\n * flattening it to a space would glue on whatever the next line starts with (a\n * bullet, a heading marker). So a suggestion stops at its newline: what shows\n * is what Tab inserts, and the prefix-match and word rules still line up\n * because this is a prefix of the controller's text.\n */\nfunction visibleLine(text: string | null): string | null {\n if (!text) {return null;}\n const newline = text.indexOf('\\n');\n return (newline < 0 ? text : text.slice(0, newline).replace(/[ \\t]+$/, '')) || null;\n}\n\n/** The markdown and the caret's offset in it, from one serialization, so they cannot disagree. */\nfunction readAtCaret(state: EditorState, serialize: (doc: PmNode) => string): { markdown: string; caretOffset: number } {\n const marked = serialize(state.tr.insertText(CARET_MARK, state.selection.head).doc);\n const caretOffset = marked.indexOf(CARET_MARK);\n if (caretOffset < 0) {\n // The block serialized without its text. Nothing before the caret is known, so nothing fires.\n return { markdown: '', caretOffset: 0 };\n }\n return { markdown: marked.slice(0, caretOffset) + marked.slice(caretOffset + CARET_MARK.length), caretOffset };\n}\n\n/** The kind of block the caret is in, or null when suggestions are not allowed there. */\nfunction blockKindAt($head: ResolvedPos): GhostBlockKind | null {\n const name = $head.parent.type.name;\n if (name !== 'paragraph' && name !== 'heading') {return null;}\n let kind: GhostBlockKind = name === 'heading' ? 'heading' : 'paragraph';\n let inner = kind !== 'paragraph';\n for (let depth = $head.depth - 1; depth >= 0; depth--) {\n const container = $head.node(depth).type.name;\n if (!ALLOWED_CONTAINERS.has(container)) {return null;}\n if (inner) {continue;}\n if (container === 'listItem' || container === 'taskItem') {\n kind = 'listItem';\n inner = true;\n } else if (container === 'blockquote' || container === 'callout') {\n kind = 'blockquote';\n inner = true;\n }\n }\n return kind;\n}\n\n/** The eligibility probe (D1). Only `read` serializes, and only when a request is about to fire. */\nfunction probe(view: EditorView, options: GhostPluginOptions, manual: boolean): GhostChangeInput {\n const { state } = view;\n const { selection } = state;\n const { $head } = selection;\n const input: GhostChangeInput = { read: () => readAtCaret(state, options.serialize), atBlockEnd: false, eligible: false };\n if (!selection.empty || !view.editable || view.composing) {return input;}\n if (options.enabled?.() === false || options.popupOpen?.()) {return input;}\n const blockKind = blockKindAt($head);\n if (!blockKind || (state.storedMarks ?? $head.marks()).some((mark) => mark.type.name === 'code')) {return input;}\n const block = $head.parent;\n // A leaf after the caret (hard break, image) counts as text, so only real trailing whitespace passes.\n if (block.textBetween($head.parentOffset, block.content.size, '\\n', '').trim() !== '') {return input;}\n // An empty block has nothing to continue until someone asks; the toolbar menu has the focus when it does.\n if (!manual && (block.content.size === 0 || !view.hasFocus())) {return input;}\n return { ...input, atBlockEnd: $head.parentOffset === block.content.size, eligible: true, blockKind };\n}\n\nfunction insertOwn(view: EditorView, text: string, keep: boolean): void {\n const meta: GhostMeta = keep ? { own: true } : { own: true, text: null };\n // One step of its own: closed before, so it does not join earlier typing...\n view.dispatch(closeHistory(view.state.tr).insertText(text).setMeta(aiGhostKey, meta).scrollIntoView());\n // ...and after, so typing right away (inside `newGroupDelay`) does not join it. No steps here.\n view.dispatch(closeHistory(view.state.tr).setMeta(aiGhostKey, { own: true } satisfies GhostMeta));\n}\n\n/** A key that matched the suggestion: goes through input rules like any typed character. */\nfunction insertTyped(view: EditorView, char: string): void {\n const { from, to } = view.state.selection;\n const plain = (): Transaction => view.state.tr.insertText(char).setMeta(aiGhostKey, { own: true } satisfies GhostMeta).scrollIntoView();\n if (!view.someProp('handleTextInput', (handle) => handle(view, from, to, char, plain))) {\n view.dispatch(plain());\n }\n}\n\n/** Run the key against a showing suggestion. True means it was used. */\nfunction ghostKey(view: EditorView, event: KeyboardEvent, controller: GhostController): boolean {\n const mod = event.metaKey || event.ctrlKey;\n if (event.key === 'Tab' && !mod && !event.shiftKey && !event.altKey) {\n const text = visibleLine(controller.accept());\n setGhostSuggestion(view, null);\n if (!text) {return false;}\n insertOwn(view, text, false);\n return true;\n }\n if (event.key === 'ArrowRight' && mod && !event.shiftKey && !event.altKey) {\n const word = visibleLine(controller.acceptWord());\n if (!word) {\n setGhostSuggestion(view, null);\n return false;\n }\n insertOwn(view, word, true);\n return true;\n }\n if (event.key === 'Escape' && !mod && !event.shiftKey && !event.altKey) {\n controller.dismiss();\n setGhostSuggestion(view, null);\n return true;\n }\n // Same rule as ProseMirror's keypress: Ctrl alone or Cmd is a chord, Ctrl+Alt is AltGr.\n const printable = [...event.key].length === 1 && !event.metaKey && !(event.ctrlKey && !event.altKey);\n if (printable && controller.typed(event.key)) {\n insertTyped(view, event.key);\n return true;\n }\n return false;\n}\n\n/**\n * The plugin. `editor.registerPlugin(createGhostPlugin(...))` installs it, with\n * no ordering function (see the top of this file). It does not own the\n * controller: registering any later plugin rebuilds plugin views, so the\n * caller destroys the controller on teardown.\n */\nexport function createGhostPlugin(options: GhostPluginOptions): Plugin<AiGhostState> {\n const { controller } = options;\n let lastKeyAt = 0;\n\n const spec: GhostPluginSpec = {\n key: aiGhostKey,\n state: {\n init: () => EMPTY,\n apply: applyGhost,\n },\n view: () => ({\n update(view, prevState) {\n const { change } = aiGhostKey.getState(view.state) ?? EMPTY;\n if (change === 'own') {return;}\n if (change === null) {\n if (!prevState.selection.eq(view.state.selection)) {controller.noteSelectionMove();}\n return;\n }\n const input = probe(view, options, false);\n const keystroke = change === 'typing' && Date.now() - lastKeyAt < GHOST_KEY_WINDOW_MS;\n controller.noteChange(keystroke ? input : { ...input, eligible: false });\n },\n }),\n props: {\n decorations: (state) => aiGhostKey.getState(state)?.decorations,\n handleDOMEvents: {\n keydown(view, event) {\n lastKeyAt = Date.now();\n if (!aiGhostKey.getState(view.state)?.text) {return false;}\n if (event.isComposing || event.keyCode === 229 || view.composing) {return false;}\n // A popup that opened late (candidates still arriving) wins over a suggestion already up.\n if (options.popupOpen?.()) {\n controller.dismiss();\n setGhostSuggestion(view, null);\n return false;\n }\n if (!ghostKey(view, event, controller)) {return false;}\n event.preventDefault();\n return true;\n },\n // Do not sit under an IME's own preview.\n compositionstart() {\n controller.dismiss();\n return false;\n },\n compositionend() {\n lastKeyAt = Date.now();\n return false;\n },\n // Tab would go elsewhere, and nobody is waiting for a request once focus has left.\n blur() {\n controller.dismiss();\n return false;\n },\n },\n },\n triggerNow(view) {\n controller.triggerNow(probe(view, options, true));\n },\n };\n return new Plugin<AiGhostState>(spec);\n}\n\n/**\n * Show `text` at the caret, or clear it with null. This is the controller's\n * `onSuggestion`. Does nothing when the screen already matches.\n */\nexport function setGhostSuggestion(view: EditorView, text: string | null): void {\n if (view.isDestroyed) {return;}\n const ghost = aiGhostKey.getState(view.state);\n if (!ghost) {return;}\n const next = visibleLine(text);\n if (next === ghost.text) {return;}\n if (next !== null && (!view.state.selection.empty || view.composing)) {return;}\n view.dispatch(view.state.tr.setMeta(aiGhostKey, { text: next } satisfies GhostMeta).setMeta('addToHistory', false));\n}\n\n/**\n * The manual trigger (the shortcut and the toolbar entry). Probes now, because\n * the caret may have moved since the last edit, and fires if eligible, whatever\n * the trigger mode. Focus the view first when calling from outside it, or Tab\n * will not reach the suggestion.\n */\nexport function triggerGhostNow(view: EditorView): void {\n (aiGhostKey.get(view.state)?.spec as GhostPluginSpec | undefined)?.triggerNow(view);\n}\n","/**\n * Inline suggestions in one editor: the controller and its plugin, installed\n * together while the feature is on and removed together when it goes off, so\n * `editor.ts` holds one small handle (D13). Options are read on every use, so a\n * settings broadcast changes them without a rebuild, and the controller's \"Don't\n * allow\" latch (D9) lasts as long as the feature stays on.\n *\n * Request errors never toast: a local engine being down must not nag on every\n * pause. The last one is kept for the AI menu (`reason`).\n *\n * Lives in the lazy AI chunk (`ai-ui.ts`); the editor must not import it statically.\n */\n\nimport type { Editor } from '@tiptap/core';\nimport type { Node as PmNode } from '@tiptap/pm/model';\nimport {\n DEFAULT_CONTEXT_TOKENS, ghostTextOptions, isRouteUsable, resolveAiFeature, resolveRoute,\n type AiConsentState, type AiEngineStatus, type AiServedBy, type AiSettings, type MikeDownAiHost,\n} from './ai';\nimport type { AiActivityEntry } from './ai-activity';\nimport { createGhostController, type GhostControllerDeps } from './ai-ghost';\nimport { aiGhostKey, createGhostPlugin, setGhostSuggestion, triggerGhostNow } from './ai-ghost-plugin';\nimport { aiFeatureAvailability, type AiFeatureAvailability } from './ai-request';\nimport { engineDisplayName } from './ai-settings-model';\n\nexport interface GhostSessionDeps {\n editor: Editor;\n /** The editor's run, with `activity: undefined` in its context (D10). */\n run: GhostControllerDeps['run'];\n settings(): AiSettings;\n statuses(): readonly AiEngineStatus[];\n consent: AiConsentState;\n /** A popup that claims Tab or Escape is open; it wins over a suggestion (D7). */\n popupOpen(): boolean;\n /** False stops everything (source mode). */\n enabled(): boolean;\n onBusy(busy: boolean): void;\n onServed(served: AiServedBy, viaFallback: boolean): void;\n record(entry: AiActivityEntry): void;\n}\n\nexport interface GhostSession {\n /** Clear the suggestion and stop any request; the widget is gone when this returns. */\n dismiss(): void;\n /** The manual trigger: focuses the editor, because Tab needs it there and blur dismisses. */\n trigger(): void;\n /** Why the last request failed, until a suggestion shows again. */\n reason(): string | null;\n destroy(): void;\n}\n\n/** The master switch and the feature's own: what decides whether a session exists at all. */\nexport function ghostFeatureOn(settings: AiSettings): boolean {\n return settings.enabled && resolveAiFeature(settings.features, 'ghostText').enabled;\n}\n\n/**\n * The settings with Inline suggestions switched on or off, and the one-key\n * patch that saves it. Everything else under `features` stays as it is (the\n * other features, the delay, trigger, token and `localOnly` options, unknown\n * keys). Only `features` is in the patch; no secret is ever near it.\n */\nexport function withGhostFeature(settings: AiSettings, enabled: boolean): { settings: AiSettings; patch: Record<'ai.features', unknown> } {\n const features = { ...settings.features, ghostText: { ...(settings.features.ghostText ?? {}), enabled } };\n return {\n settings: { ...settings, features },\n patch: { 'ai.features': JSON.parse(JSON.stringify(features)) as unknown },\n };\n}\n\n/** `aiFeatureAvailability` for a request as the controller sends it, which carries `localOnly`. */\nexport function ghostAvailability(\n ai: MikeDownAiHost | undefined,\n settings: AiSettings,\n statuses: readonly AiEngineStatus[],\n consent: AiConsentState,\n): AiFeatureAvailability {\n const plain = aiFeatureAvailability(ai, settings, statuses, consent, 'ghostText');\n // A tier-1 host routes by itself, so there is no route here to hold to local engines.\n if (plain.state === 'hidden' || typeof ai?.listEngines !== 'function' || !ghostTextOptions(settings.features).localOnly) {return plain;}\n const route = resolveRoute(settings, statuses, consent, { feature: 'ghostText', localOnly: true });\n return isRouteUsable(route) ? { state: 'enabled' } : { state: 'disabled', reason: route.reason };\n}\n\nexport function createGhostSession(deps: GhostSessionDeps): GhostSession {\n const { editor } = deps;\n let reason: string | null = null;\n\n const controller = createGhostController({\n run: (req, events, signal) => deps.run(req, events, signal),\n options: () => ghostTextOptions(deps.settings().features),\n contextTokens() {\n const settings = deps.settings();\n const { localOnly } = ghostTextOptions(settings.features);\n const route = resolveRoute(settings, deps.statuses(), deps.consent, { feature: 'ghostText', localOnly });\n if (!isRouteUsable(route)) {return DEFAULT_CONTEXT_TOKENS;}\n const model = settings.engines.find((e) => e.id === route.engineId)?.models.find((m) => m.id === route.modelId);\n return model?.capabilities.contextTokens ?? DEFAULT_CONTEXT_TOKENS;\n },\n onSuggestion(text) {\n if (text) {reason = null;}\n setGhostSuggestion(editor.view, text);\n },\n onBusy: (busy) => deps.onBusy(busy),\n onServed: (served, viaFallback) => deps.onServed(served, viaFallback),\n onError(info) {\n reason = info.error.message;\n },\n record: (entry) => deps.record(entry),\n routeLabel(route) {\n const engine = deps.settings().engines.find((e) => e.id === route.engineId);\n return engine ? engineDisplayName(engine) : route.engineId;\n },\n });\n\n // Appended last, so its `view.update` sees the popups after theirs have run.\n editor.registerPlugin(createGhostPlugin({\n controller,\n serialize: (doc) => (editor.storage as unknown as { markdown: { serializer: { serialize(content: PmNode): string } } }).markdown.serializer.serialize(doc),\n popupOpen: () => deps.popupOpen(),\n enabled: () => deps.enabled(),\n }));\n\n return {\n dismiss() {\n controller.dismiss();\n setGhostSuggestion(editor.view, null);\n },\n trigger() {\n editor.view.focus();\n triggerGhostNow(editor.view);\n },\n reason: () => reason,\n destroy() {\n controller.destroy();\n editor.unregisterPlugin(aiGhostKey);\n },\n };\n}\n","/**\n * A small, safe markdown renderer for the AI result popover's preview.\n *\n * Model output is untrusted text. This builds DOM with `createElement` and\n * `textContent` only: no `innerHTML`, no raw HTML passthrough (a `<script>`\n * stays literal text) and no `href` or `src` is ever set, so a link shows\n * its label and nothing can be followed or fetched from the preview.\n *\n * Covers what models return for summaries, outlines and rewrites:\n * paragraphs, ATX headings, nested bullet and numbered lists, block quotes,\n * fenced code, rules, and inline code, bold, italic, strikethrough, links\n * and images (as their label). Anything else stays literal. Newlines inside\n * a paragraph are kept (the preview is `white-space: pre-wrap`), so plain\n * prose looks as it did when the preview was raw text.\n */\n\nconst FENCE = /^ {0,3}(`{3,}|~{3,})/;\nconst HEADING = /^ {0,3}(#{1,6})[ \\t]+(.*?)(?:[ \\t]+#+)?[ \\t]*$/;\nconst ITEM = /^([ \\t]*)([-*+]|\\d{1,9}[.)])[ \\t]+(.*)$/;\nconst QUOTE = /^ {0,3}>[ \\t]?(.*)$/;\nconst RULE = /^ {0,3}([-*_])(?:[ \\t]*\\1){2,}[ \\t]*$/;\n\nconst isSpace = (c: string | undefined): boolean => c === undefined || /\\s/.test(c);\nconst isWord = (c: string | undefined): boolean => c !== undefined && /[\\p{L}\\p{N}]/u.test(c);\n\nfunction make<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (className) {node.className = className;}\n return node;\n}\n\n/** Index of the closer for a delimiter opened at `from`, or -1. */\nfunction findCloser(s: string, delim: string, from: number): number {\n for (let j = s.indexOf(delim, from); j !== -1; j = s.indexOf(delim, j + 1)) {\n if (s[j - 1] === '\\\\' || isSpace(s[j - 1])) {continue;}\n // A single `*` or `_` is not the first half of a doubled one.\n if (delim.length === 1 && (s[j + 1] === delim || s[j - 1] === delim)) {continue;}\n if (delim === '_' && isWord(s[j + 1])) {continue;}\n return j;\n }\n return -1;\n}\n\n/** Index just past the `)` of a `](url)` that starts at `close`, or -1. */\nfunction linkEnd(s: string, close: number): number {\n if (s[close + 1] !== '(') {return -1;}\n let depth = 0;\n for (let k = close + 1; k < s.length; k++) {\n if (s[k] === '\\n') {return -1;}\n if (s[k] === '(') {depth++;} else if (s[k] === ')' && --depth === 0) {return k + 1;}\n }\n return -1;\n}\n\nfunction matchingBracket(s: string, open: number): number {\n let depth = 0;\n for (let k = open; k < s.length; k++) {\n if (s[k] === '\\\\') {k++;} else if (s[k] === '[') {depth++;} else if (s[k] === ']' && --depth === 0) {return k;}\n }\n return -1;\n}\n\n/** Append `s` to `parent` with its inline markdown as elements. */\nfunction appendInline(parent: Node, s: string): void {\n let buf = '';\n const flush = (): void => {\n if (buf) {parent.appendChild(document.createTextNode(buf)); buf = '';}\n };\n const wrap = (tag: 'strong' | 'em' | 'del' | 'span', inner: string, className?: string): void => {\n flush();\n const node = make(tag, className);\n appendInline(node, inner);\n parent.appendChild(node);\n };\n let i = 0;\n while (i < s.length) {\n const c = s[i];\n if (c === '\\\\' && i + 1 < s.length && /[\\\\`*_{}[\\]()#+\\-.!~>|]/.test(s[i + 1])) {\n buf += s[i + 1];\n i += 2;\n continue;\n }\n if (c === '`') {\n let n = 1;\n while (s[i + n] === '`') {n++;}\n const run = '`'.repeat(n);\n const end = s.indexOf(run, i + n);\n if (end !== -1 && s[end + n] !== '`') {\n flush();\n const code = make('code');\n code.textContent = s.slice(i + n, end).replace(/^ (.*) $/, '$1');\n parent.appendChild(code);\n i = end + n;\n continue;\n }\n buf += run;\n i += n;\n continue;\n }\n if (c === '*' || c === '_') {\n const doubled = s[i + 1] === c;\n const delim = doubled ? c + c : c;\n const after = s[i + delim.length];\n const leftOk = c === '*' || !isWord(s[i - 1]);\n if (leftOk && !isSpace(after) && after !== c) {\n const end = findCloser(s, delim, i + delim.length);\n if (end > i + delim.length) {\n wrap(doubled ? 'strong' : 'em', s.slice(i + delim.length, end));\n i = end + delim.length;\n continue;\n }\n }\n buf += delim;\n i += delim.length;\n continue;\n }\n if (c === '~' && s[i + 1] === '~' && !isSpace(s[i + 2])) {\n const end = findCloser(s, '~~', i + 2);\n if (end > i + 2) {\n wrap('del', s.slice(i + 2, end));\n i = end + 2;\n continue;\n }\n }\n if (c === '[' || (c === '!' && s[i + 1] === '[')) {\n const open = c === '!' ? i + 1 : i;\n const close = matchingBracket(s, open);\n const end = close === -1 ? -1 : linkEnd(s, close);\n if (end !== -1) {\n // The label only: the target is never put on the element.\n wrap('span', s.slice(open + 1, close), c === '!' ? 'ai-rw-md-image' : 'ai-rw-md-link');\n i = end;\n continue;\n }\n }\n buf += c;\n i++;\n }\n flush();\n}\n\ninterface ListFrame {\n indent: number;\n ordered: boolean;\n list: HTMLElement;\n item: HTMLElement | null;\n}\n\nconst indentOf = (ws: string): number => ws.replace(/\\t/g, ' ').length;\n\n/** Replace the children of `into` with `markdown`, rendered. */\nexport function renderPreviewMarkdown(into: HTMLElement, markdown: string): void {\n const out: Node[] = [];\n const lines = markdown.replace(/\\r\\n?/g, '\\n').split('\\n');\n let i = 0;\n\n const startsBlock = (line: string): boolean => FENCE.test(line) || HEADING.test(line) || ITEM.test(line) || QUOTE.test(line) || RULE.test(line);\n\n while (i < lines.length) {\n const line = lines[i];\n if (!line.trim()) {i++; continue;}\n\n const fence = FENCE.exec(line);\n if (fence) {\n const marker = fence[1];\n const body: string[] = [];\n i++;\n // An unclosed fence (a stream still running) shows what it has.\n while (i < lines.length && !new RegExp(`^ {0,3}${marker[0]}{${marker.length},}[ \\\\t]*$`).test(lines[i])) {body.push(lines[i++]);}\n i++;\n const pre = make('pre', 'ai-rw-md-pre');\n const code = make('code');\n code.textContent = body.join('\\n');\n pre.appendChild(code);\n out.push(pre);\n continue;\n }\n\n const heading = HEADING.exec(line);\n if (heading) {\n const node = make('div', 'ai-rw-md-h');\n node.dataset.level = String(heading[1].length);\n appendInline(node, heading[2]);\n out.push(node);\n i++;\n continue;\n }\n\n if (RULE.test(line)) {\n out.push(make('hr', 'ai-rw-md-hr'));\n i++;\n continue;\n }\n\n if (QUOTE.test(line)) {\n const inner: string[] = [];\n while (i < lines.length && QUOTE.test(lines[i])) {inner.push(QUOTE.exec(lines[i++])![1]);}\n const quote = make('blockquote', 'ai-rw-md-quote');\n renderPreviewMarkdown(quote, inner.join('\\n'));\n out.push(quote);\n continue;\n }\n\n if (ITEM.test(line)) {\n const stack: ListFrame[] = [];\n const roots: HTMLElement[] = [];\n while (i < lines.length) {\n const m = ITEM.exec(lines[i]);\n if (!m) {\n // A blank line ends the list unless an item follows it; an indented line continues the item.\n if (lines[i].trim() && /^[ \\t]+\\S/.test(lines[i]) && !startsBlock(lines[i]) && stack.length) {\n const item = stack[stack.length - 1].item!;\n item.appendChild(document.createTextNode(`\\n${lines[i].trim()}`));\n i++;\n continue;\n }\n if (!lines[i].trim() && ITEM.test(lines[i + 1] ?? '')) {i++; continue;}\n break;\n }\n const indent = indentOf(m[1]);\n const ordered = /\\d/.test(m[2]);\n while (stack.length && indent < stack[stack.length - 1].indent) {stack.pop();}\n let top = stack[stack.length - 1];\n if (top && indent === top.indent && ordered !== top.ordered) {stack.pop(); top = stack[stack.length - 1];}\n if (!top || indent > top.indent) {\n const list = make(ordered ? 'ol' : 'ul', 'ai-rw-md-list');\n if (ordered) {\n const start = parseInt(m[2], 10);\n if (start !== 1) {list.setAttribute('start', String(start));}\n }\n if (top?.item) {top.item.appendChild(list);} else {roots.push(list);}\n top = { indent, ordered, list, item: null };\n stack.push(top);\n }\n const li = make('li');\n appendInline(li, m[3]);\n top.list.appendChild(li);\n top.item = li;\n i++;\n }\n out.push(...roots);\n continue;\n }\n\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && (para.length === 0 || !startsBlock(lines[i]))) {para.push(lines[i++]);}\n const p = make('p', 'ai-rw-md-p');\n appendInline(p, para.join('\\n'));\n out.push(p);\n }\n into.replaceChildren(...out);\n}\n","/**\n * The AI chat panel: questions about this document or the documentation bases,\n * answered with citations. Docked inside the editor by `editor.ts`, so the\n * document stays visible and Insert has a cursor to go to. Loaded through\n * `ai-ui.ts` only, never from the editor's main path.\n *\n * Everything from the model, and every base name, path and heading, goes in as\n * text: through `renderPreviewMarkdown` (no href, no src) or `textContent`. A\n * chip is built from a number the turn actually sent, so model text can never\n * name a target. `[n]` in a code span is not a chip (`parseCitations` parts).\n *\n * History lives in this mount: closing the panel clears it and aborts what is in\n * flight. A question that looks like it holds a key is not kept in history.\n *\n * Nothing here touches the editor document or its DOM; Insert goes through\n * `insertAtCursor`, which the editor implements with a transaction.\n */\n\nimport {\n ANSWERED_WITHOUT_SOURCES, NO_SOURCES_CITED, aiErrorCopy, docsActiveBases, docsCitationLabel, docsDocumentLocation, docsFileHref,\n docsSectionFile, docsSectionSlug, parseCitations, prepareInsertMarkdown, rewriteVisibleText, toAiError,\n} from './ai';\nimport type {\n AiDocBaseStatus, AiDocsOptions, AiError, AiRouteOk, DocsChat, DocsSentSection, DocsTurnAnswer, DocsTurnInput, DocsTurnOutcome, DocsTurnProgress,\n InsertUrlPolicy, MikeDownDocsHost,\n} from './ai';\nimport { renderPreviewMarkdown } from './ai-markdown-preview';\nimport { ICONS, button, el, experimentalBadge, nextId, note } from './ai-settings-dom';\n\nexport type AiChatScope = 'document' | 'bases';\n\nexport interface AiChatPanelOptions {\n /** The editor's one chat (`createAiDocsChat`): it holds the one-request-in-flight rule. */\n chat: DocsChat;\n /** Absent: the scope picker is not shown and the scope is This document. */\n docs?: MikeDownDocsHost;\n /** The live text, source mode included. */\n documentText(): string;\n docsOptions?(): Partial<AiDocsOptions>;\n thinking?: DocsTurnInput['thinking'];\n /** An engine's display name. */\n engineName?(engineId: string): string;\n /** The notice while the chat feature is switched off (`aiFeatureOffNotice`), else null. */\n featureOffNotice(): string | null;\n /** False: no Insert (read-only). */\n canInsert(): boolean;\n /** Put markdown at the cursor as one undo step, or return false. `policy` is S8's boundary: the insert enforces it on the parsed result. */\n insertAtCursor(markdown: string, policy: InsertUrlPolicy): boolean;\n /** The current document's absolute folder, null when it has none. */\n documentFolder?(): string | null;\n /** Open a base file. Absent: chips only show. */\n openFile?(href: string, reveal?: { section: string }): void;\n /** Whether AI Activity is recording. */\n activityOn?(): boolean;\n openActivity?(requestId: string): void;\n /** The engines page on routing. Absent (a host that routes by itself): that action is not offered. */\n openRouting?(): void;\n /** The engines page on Documentation bases. */\n openBases?(): void;\n /** The host's save dialog and write. Absent: no Save. */\n saveTextFile?(name: string, text: string): Promise<void>;\n /** Esc with nothing in flight: back to the document. */\n onEscape?(): void;\n /** The close button. The host calls `destroy`. */\n onClose(): void;\n}\n\nexport interface AiChatPanelHandle {\n /** Abort anything in flight, clear the history, leave the container empty. */\n destroy(): void;\n focus(): void;\n /** Settings or bases may have changed: read them again. */\n refresh(): void;\n}\n\nexport const AI_CHAT_SECRET_NOTICE = 'Your question looks like it holds a key, so nothing was sent. Take the key out and ask again.';\nexport const AI_CHAT_BUSY_NOTICE = 'The last request is still finishing. Try again in a moment.';\nexport const AI_CHAT_NO_BASES = 'No documentation base is active. Turn one on or add one, or ask about this document instead.';\n\nconst STREAM_THROTTLE_MS = 80;\nconst CONFIRM_MS = 1600;\n/** Marks a chip's place in the markdown handed to the preview. Private use, stripped from model text first. */\nconst CHIP_OPEN = '';\nconst CHIP_CLOSE = '';\nconst CHIP_RE = /(\\d+)/;\n\nconst ICON_SEND = svgIcon('<path d=\"M8 13V3M3.5 7.5L8 3l4.5 4.5\"/>');\nconst ICON_STOP = svgIcon('<rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\"/>');\nconst ICON_COPY = svgIcon('<rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.5\"/><path d=\"M10.5 5.5v-2a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2\"/>');\nconst ICON_SAVE = svgIcon('<path d=\"M8 2.5v8M4.5 7.5L8 11l3.5-3.5M3 13.5h10\"/>');\n\nfunction svgIcon(body: string): string {\n return `<svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${body}</svg>`;\n}\n\nconst plural = (n: number, word: string): string => `${n} ${word}${n === 1 ? '' : 's'}`;\n\n/** The line under a question while it runs: \"Reading 2 pages... hop 2 of 3\". */\nexport function chatProgressLine(progress: DocsTurnProgress, scope: AiChatScope): string {\n const hop = progress.hop !== undefined ? ` hop ${progress.hop} of ${progress.maxHops}` : '';\n switch (progress.phase) {\n case 'navigate':\n return progress.pages > 0\n ? `Reading ${plural(progress.pages, 'page')}...${hop}`\n : `Looking through the ${scope === 'document' ? 'outline' : 'index'}...${hop}`;\n case 'keyword':\n return 'Searching for matching sections...';\n case 'answer':\n return progress.pages > 0 ? `Answering from ${plural(progress.pages, 'section')}...` : 'Answering...';\n }\n}\n\n/** \"Base X is local-only\", or the same for several. */\nexport function chatLocalOnlyTitle(bases: ReadonlyArray<{ name: string }>): string {\n const names = bases.map((b) => b.name);\n if (names.length === 1) {return `Base ${names[0]} is local-only`;}\n return `Bases ${names.slice(0, -1).join(', ')} and ${names[names.length - 1]} are local-only`;\n}\n\n// ── Plain-text export ───────────────────────────────────────────────────────\n\n/** A finished turn as the export sees it. */\nexport interface AiChatExportTurn {\n startedAt: number;\n scope: AiChatScope;\n status: string;\n /** Null: not kept (it looked like it held a key). */\n question: string | null;\n answer?: string;\n /** Lines under the answer. */\n notes?: readonly string[];\n /** `[n] file › heading`. */\n sources?: readonly string[];\n engine?: string;\n isLocal?: boolean;\n}\n\nconst pad = (n: number): string => String(n).padStart(2, '0');\n\n/** `mikedown-ai-chat-<yyyymmdd-hhmm>.txt`, in local time. */\nexport function chatExportFileName(now: Date = new Date()): string {\n const day = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`;\n return `mikedown-ai-chat-${day}-${pad(now.getHours())}${pad(now.getMinutes())}.txt`;\n}\n\n/** Copy and Save, in the Activity export's shape: a header per turn, then the text verbatim. Times are UTC. */\nexport function formatChatExport(turns: readonly AiChatExportTurn[]): string {\n if (turns.length === 0) {return '';}\n const blocks = turns.map((turn, i) => {\n const head = [\n `=== Turn ${i + 1} of ${turns.length} ===`,\n `Time: ${new Date(turn.startedAt).toISOString()}`,\n `Scope: ${turn.scope === 'bases' ? 'Active bases' : 'This document'}`,\n `Status: ${turn.status}`,\n ...(turn.engine ? [`Engine: ${turn.engine}${turn.isLocal === undefined ? '' : turn.isLocal ? ' (local)' : ' (cloud)'}`] : []),\n ].join('\\n');\n return [\n head,\n '--- Question ---',\n turn.question ?? '(not kept: it looked like it held a key)',\n ...(turn.answer !== undefined ? ['--- Answer ---', turn.answer] : []),\n ...(turn.notes && turn.notes.length > 0 ? ['--- Notes ---', turn.notes.join('\\n')] : []),\n ...(turn.sources && turn.sources.length > 0 ? ['--- Sources ---', turn.sources.join('\\n')] : []),\n ].join('\\n\\n');\n });\n return `${blocks.join('\\n\\n')}\\n`;\n}\n\n// ── The panel ───────────────────────────────────────────────────────────────\n\ninterface Turn {\n scope: AiChatScope;\n startedAt: number;\n question: string | null;\n running: boolean;\n /** The text so far while it streams, kept if it is cancelled. */\n partial: string;\n progress: string;\n route: AiRouteOk | null;\n outcome: DocsTurnOutcome | null;\n node: HTMLElement;\n body: HTMLElement;\n /** The answer's element while it streams. */\n live: HTMLElement | null;\n chips: Array<{ node: HTMLElement; sent: DocsSentSection }>;\n}\n\ntype EngineName = (engineId: string) => string;\n\nfunction errorText(error: AiError, route: AiRouteOk | null, engineName: EngineName): string {\n if (error.code === 'unknown' && error.message) {return error.message;}\n return aiErrorCopy(error.code, route ? { engine: engineName(route.engineId), model: route.modelId } : {}).message;\n}\n\n/** The lines under an answer. */\nfunction answerNotes(turn: Turn, answer: DocsTurnAnswer): string[] {\n const notes: string[] = [];\n if (answer.coverage) {notes.push(answer.coverage);}\n if (answer.withoutSources && !answer.coverage.includes(ANSWERED_WITHOUT_SOURCES)) {notes.push(ANSWERED_WITHOUT_SOURCES);}\n // This document answers have no citations, so there is nothing to miss.\n if (answer.noSources && turn.scope === 'bases') {notes.push(NO_SOURCES_CITED);}\n return notes;\n}\n\n/** The answer as parts: This document answers show no citation markers. */\nfunction answerParts(turn: Turn, answer: DocsTurnAnswer): ReturnType<typeof parseCitations>['parts'] {\n return turn.scope === 'bases' ? answer.citations.parts : parseCitations(answer.answer, []).parts;\n}\n\nfunction exportTurn(turn: Turn, engineName: EngineName): AiChatExportTurn {\n const base = { startedAt: turn.startedAt, scope: turn.scope, question: turn.question };\n const route = turn.route ? { engine: `${engineName(turn.route.engineId)} · ${turn.route.modelId}`, isLocal: turn.route.isLocal } : {};\n const outcome = turn.outcome;\n if (!outcome) {return { ...base, ...route, status: 'running', ...(turn.partial ? { answer: turn.partial } : {}) };}\n switch (outcome.kind) {\n case 'answered':\n return {\n ...base,\n ...route,\n status: 'answered',\n answer: answerParts(turn, outcome).map((p) => (p.type === 'text' ? p.text : `[${p.ns.join(', ')}]`)).join(''),\n notes: answerNotes(turn, outcome),\n sources: turn.scope === 'bases'\n ? outcome.sent.filter((s) => outcome.citations.cited.includes(s.n)).map((s) => `[${s.n}] ${docsCitationLabel(s.section)}`)\n : [],\n };\n case 'cancelled':\n return { ...base, ...route, status: 'cancelled', ...(turn.partial ? { answer: turn.partial } : {}) };\n case 'error':\n return { ...base, ...route, status: 'failed', notes: [errorText(outcome.error, turn.route, engineName)] };\n case 'baseLocalOnly':\n return { ...base, status: 'not sent', notes: [chatLocalOnlyTitle(outcome.bases)] };\n case 'noActiveBases':\n return { ...base, status: 'not sent', notes: [AI_CHAT_NO_BASES] };\n case 'questionHasSecret':\n return { ...base, status: 'not sent', notes: [AI_CHAT_SECRET_NOTICE] };\n case 'busy':\n return { ...base, status: 'not sent', notes: [AI_CHAT_BUSY_NOTICE] };\n }\n}\n\n/** A quiet confirmation beside some buttons, read out when it changes. */\nfunction inlineStatus(): { element: HTMLElement; show(text: string, level?: 'ok' | 'error'): void; dispose(): void } {\n const element = el('span', 'ai-chat-status');\n element.setAttribute('role', 'status');\n let timer: number | undefined;\n return {\n element,\n show(text, level = 'ok') {\n window.clearTimeout(timer);\n element.textContent = text;\n element.dataset.level = level;\n timer = window.setTimeout(() => { element.textContent = ''; }, level === 'ok' ? CONFIRM_MS : CONFIRM_MS * 3);\n },\n dispose() { window.clearTimeout(timer); },\n };\n}\n\nexport function mountAiChatPanel(container: HTMLElement, opts: AiChatPanelOptions): AiChatPanelHandle {\n const engineName: EngineName = (id) => opts.engineName?.(id) ?? id;\n const turns: Turn[] = [];\n let statuses: AiDocBaseStatus[] = [];\n let scope: AiChatScope = 'document';\n /** Once the user has chosen, a late base list does not change it. */\n let scopeChosen = false;\n let current: Turn | null = null;\n let controller: AbortController | null = null;\n let destroyed = false;\n let streamTimer: number | undefined;\n const statusDisposers = new Set<() => void>();\n\n const makeStatus = (): ReturnType<typeof inlineStatus> => {\n const status = inlineStatus();\n statusDisposers.add(() => status.dispose());\n return status;\n };\n\n // ── Shell ─────────────────────────────────────────────────────────────────\n\n const root = el('section', 'ai-chat');\n const titleId = nextId('ai-chat-title');\n root.setAttribute('aria-labelledby', titleId);\n\n const header = el('div', 'ai-chat-header');\n const title = el('h2', 'ai-chat-title', 'Chat');\n title.id = titleId;\n const headerStatus = makeStatus();\n const copyAllBtn = button('ai-chat-icon', '', { html: ICON_COPY, ariaLabel: 'Copy conversation', title: 'Copy conversation', fk: 'chat:copy-all' });\n const saveBtn = button('ai-chat-icon', '', { html: ICON_SAVE, ariaLabel: 'Save conversation', title: 'Save conversation', fk: 'chat:save' });\n const closeBtn = button('ai-chat-icon', '', { html: ICONS.close, ariaLabel: 'Close chat (clears this conversation)', title: 'Close (clears this conversation)', fk: 'chat:close' });\n header.append(title, experimentalBadge(), el('span', 'ai-chat-spacer'), headerStatus.element, copyAllBtn, ...(opts.saveTextFile ? [saveBtn] : []), closeBtn);\n\n const log = el('div', 'ai-chat-log');\n log.setAttribute('role', 'log');\n log.setAttribute('aria-live', 'polite');\n log.tabIndex = 0;\n log.setAttribute('aria-label', 'Conversation');\n\n const empty = el('div', 'ai-chat-empty');\n const emptyTitle = el('div', 'ai-chat-empty-title');\n const emptyText = el('p', 'ai-chat-empty-text');\n empty.append(emptyTitle, emptyText);\n log.append(empty);\n\n const composer = el('div', 'ai-chat-composer');\n const offNote = el('div', 'ai-chat-off');\n const picker = el('div', 'ai-chat-scope');\n picker.setAttribute('role', 'radiogroup');\n picker.setAttribute('aria-label', 'What to ask about');\n const radioName = nextId('ai-chat-scope');\n const radios = new Map<AiChatScope, HTMLInputElement>();\n for (const [value, label] of [['document', 'This document'], ['bases', 'Active bases']] as const) {\n const option = el('label', 'ai-chat-seg');\n const radio = el('input');\n radio.type = 'radio';\n radio.name = radioName;\n radio.value = value;\n radio.addEventListener('change', () => {\n if (!radio.checked) {return;}\n scopeChosen = true;\n setScope(value);\n });\n radios.set(value, radio);\n option.append(radio, el('span', '', label));\n picker.append(option);\n }\n picker.hidden = !opts.docs;\n const basesLine = el('div', 'ai-chat-bases');\n const box = el('div', 'ai-chat-box');\n const input = el('textarea', 'ai-chat-input');\n input.rows = 1;\n input.setAttribute('aria-label', 'Your question');\n const sendBtn = button('ai-chat-send', '', { html: ICON_SEND, ariaLabel: 'Send', title: 'Send (Enter)', fk: 'chat:send' });\n const cancelBtn = button('ai-chat-send ai-chat-send--cancel', '', { html: ICON_STOP, ariaLabel: 'Cancel', title: 'Cancel (Esc)', fk: 'chat:cancel' });\n cancelBtn.hidden = true;\n box.append(input, sendBtn, cancelBtn);\n composer.append(offNote, picker, basesLine, box);\n root.append(header, log, composer);\n\n // ── Scope and availability ────────────────────────────────────────────────\n\n function activeBases(): AiDocBaseStatus[] {\n return docsActiveBases(statuses);\n }\n\n function setScope(next: AiChatScope): void {\n scope = next;\n const radio = radios.get(next);\n if (radio) {radio.checked = true;}\n renderComposerState();\n }\n\n function renderBasesLine(): void {\n basesLine.replaceChildren();\n basesLine.hidden = scope !== 'bases';\n if (scope !== 'bases') {return;}\n const active = activeBases();\n if (active.length > 0) {\n basesLine.textContent = active.map((s) => s.base.name).join(', ');\n basesLine.title = basesLine.textContent;\n return;\n }\n basesLine.title = '';\n basesLine.append(el('span', '', 'No base is active. '));\n if (opts.openBases) {\n const manage = button('ai-chat-link', 'Manage bases…', { fk: 'chat:manage-bases' });\n manage.addEventListener('click', () => opts.openBases?.());\n basesLine.append(manage);\n }\n }\n\n function renderComposerState(): void {\n const off = opts.featureOffNotice();\n offNote.replaceChildren();\n offNote.hidden = !off;\n if (off) {offNote.append(note('info', off));}\n picker.hidden = !opts.docs || !!off;\n renderBasesLine();\n if (off) {basesLine.hidden = true;}\n const busy = current !== null;\n input.disabled = !!off;\n input.placeholder = off ? '' : scope === 'bases' ? 'Ask your documentation…' : 'Ask about this document…';\n sendBtn.hidden = busy;\n cancelBtn.hidden = !busy;\n sendBtn.disabled = !!off || input.value.trim() === '';\n for (const radio of radios.values()) {radio.disabled = busy;}\n emptyTitle.textContent = scope === 'bases' ? 'Ask your documentation' : 'Ask about this document';\n emptyText.textContent = scope === 'bases'\n ? 'Answers come from the active bases, with citations you can open.'\n : 'Answers come from the text in this editor, as it is right now.';\n empty.hidden = turns.length > 0;\n copyAllBtn.hidden = turns.length === 0;\n saveBtn.hidden = turns.length === 0;\n }\n\n async function loadStatuses(): Promise<void> {\n if (!opts.docs) {return;}\n try {\n statuses = await opts.docs.listBases();\n } catch {\n statuses = [];\n }\n if (destroyed) {return;}\n // Defaults to This document when no base is active.\n if (!scopeChosen && current === null) {setScope(activeBases().length > 0 ? 'bases' : 'document');}\n for (const turn of turns) {updateChipTitles(turn);}\n renderComposerState();\n }\n\n // ── Rendering a turn ──────────────────────────────────────────────────────\n\n function nearBottom(): boolean {\n return log.scrollHeight - log.scrollTop - log.clientHeight < 48;\n }\n\n function scrollDown(was: boolean): void {\n if (was) {log.scrollTop = log.scrollHeight;}\n }\n\n function chipTitle(sent: DocsSentSection): string {\n const file = docsSectionFile(sent.section, sent.baseId, statuses);\n if (!file) {return sent.section.relPath;}\n return `${file.baseName}: ${file.root.replace(/[\\\\/]+$/, '')}/${file.relPath}`;\n }\n\n function updateChipTitles(turn: Turn): void {\n for (const { node, sent } of turn.chips) {node.title = chipTitle(sent);}\n }\n\n function makeChip(turn: Turn, sent: DocsSentSection, status: ReturnType<typeof inlineStatus>): HTMLElement {\n const label = docsCitationLabel(sent.section);\n const content = [el('span', 'ai-chat-chip-n', String(sent.n)), el('span', 'ai-chat-chip-label', label)];\n let node: HTMLElement;\n if (opts.openFile) {\n node = button('ai-chat-chip', '', {});\n node.setAttribute('aria-label', `Open source ${sent.n}: ${label}`);\n node.addEventListener('click', () => { void openCitation(sent, status); });\n } else {\n node = el('span', 'ai-chat-chip');\n }\n node.append(...content);\n node.title = chipTitle(sent);\n turn.chips.push({ node, sent });\n return node;\n }\n\n async function openCitation(sent: DocsSentSection, status: ReturnType<typeof inlineStatus>): Promise<void> {\n let file = docsSectionFile(sent.section, sent.baseId, statuses);\n if (!file) {\n await loadStatuses();\n if (destroyed) {return;}\n file = docsSectionFile(sent.section, sent.baseId, statuses);\n }\n if (!file || !opts.openFile) {\n status.show(`Could not open ${sent.section.relPath}: its base is no longer set up.`, 'error');\n return;\n }\n const slug = docsSectionSlug(sent.section);\n opts.openFile(docsFileHref(file.root, file.relPath), slug ? { section: slug } : undefined);\n }\n\n /** The answer through the preview, with each citation's place swapped for a chip. */\n function renderAnswerInto(into: HTMLElement, turn: Turn, answer: DocsTurnAnswer, status: ReturnType<typeof inlineStatus>): void {\n const bySent = new Map(answer.sent.map((s) => [s.n, s]));\n const marks: DocsSentSection[] = [];\n let markdown = '';\n for (const part of answerParts(turn, answer)) {\n if (part.type === 'text') {\n markdown += part.text.replace(/[]/g, '');\n continue;\n }\n part.ns.forEach((n) => {\n const sent = bySent.get(n);\n if (!sent) {return;}\n markdown += `${CHIP_OPEN}${marks.length}${CHIP_CLOSE}`;\n marks.push(sent);\n });\n }\n renderPreviewMarkdown(into, markdown.trim());\n const walker = document.createTreeWalker(into, NodeFilter.SHOW_TEXT);\n const texts: Text[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (CHIP_RE.test((node as Text).data)) {texts.push(node as Text);}\n }\n for (const text of texts) {\n const pieces = text.data.split(CHIP_RE);\n const out: Node[] = [];\n pieces.forEach((piece, i) => {\n if (i % 2 === 1) {out.push(makeChip(turn, marks[Number(piece)], status));}\n else if (piece) {out.push(document.createTextNode(piece));}\n });\n text.replaceWith(...out);\n }\n }\n\n function renderNotice(body: HTMLElement, level: 'warning' | 'info' | 'error', text: string, actions: Array<{ label: string; fk: string; run(): void }> = [], titleText?: string): void {\n const card = el('div', 'ai-chat-notice');\n if (titleText) {card.append(el('div', 'ai-chat-notice-title', titleText));}\n card.append(note(level, text));\n if (actions.length > 0) {\n const row = el('div', 'ai-chat-actions');\n for (const action of actions) {\n const b = button('ai-chat-action', action.label, { fk: action.fk });\n b.addEventListener('click', () => action.run());\n row.append(b);\n }\n card.append(row);\n }\n body.append(card);\n }\n\n function renderAnswered(turn: Turn, answer: DocsTurnAnswer): void {\n const { body } = turn;\n const status = makeStatus();\n const text = el('div', 'ai-chat-answer ai-rw-out');\n renderAnswerInto(text, turn, answer, status);\n body.append(text);\n const notes = answerNotes(turn, answer);\n if (notes.length > 0) {\n const box2 = el('div', 'ai-chat-notes');\n for (const line of notes) {box2.append(el('div', 'ai-chat-note', line));}\n body.append(box2);\n }\n const row = el('div', 'ai-chat-actions');\n if (opts.canInsert()) {\n const insert = button('ai-chat-action', 'Insert at cursor', { fk: 'chat:insert' });\n insert.addEventListener('click', () => {\n const sources = turn.scope === 'bases' ? answer.sent : [];\n const location = docsDocumentLocation(opts.documentFolder?.() ?? null, statuses, answer.sent.map((s) => s.baseId));\n const { markdown, policy } = prepareInsertMarkdown(answer.answer, sources, location);\n if (opts.insertAtCursor(markdown, policy)) {status.show('Inserted');}\n else {status.show('Could not insert here.', 'error');}\n });\n row.append(insert);\n }\n const copy = button('ai-chat-action', 'Copy', { fk: 'chat:copy' });\n copy.addEventListener('click', () => {\n const one = exportTurn(turn, engineName);\n const sources = one.sources && one.sources.length > 0 ? `\\n\\n${one.sources.join('\\n')}` : '';\n void copyText(`${one.answer ?? ''}${sources}`, status);\n });\n row.append(copy);\n const requestId = answer.run.requestId;\n if (requestId && opts.openActivity && opts.activityOn?.()) {\n const activity = button('ai-chat-link', 'Activity', { fk: 'chat:activity', title: 'View this request in AI Activity' });\n activity.addEventListener('click', () => opts.openActivity?.(requestId));\n row.append(activity);\n }\n row.append(status.element, el('span', 'ai-chat-spacer'));\n if (turn.route) {\n const pill = el('span', 'ai-chat-route');\n pill.title = `${engineName(turn.route.engineId)} · ${turn.route.modelId}${turn.route.isLocal ? ' (local)' : ' (cloud)'}`;\n const icon = el('span', 'ai-chat-route-icon');\n icon.innerHTML = turn.route.isLocal ? ICONS.local : ICONS.cloud;\n pill.append(icon, el('span', 'ai-chat-route-name', turn.route.modelId));\n row.append(pill);\n }\n body.append(row);\n }\n\n function renderBody(turn: Turn): void {\n const { body } = turn;\n body.replaceChildren();\n turn.chips = [];\n turn.live = null;\n if (turn.question === null) {turn.node.querySelector('.ai-chat-question')?.remove();}\n if (turn.running) {\n if (turn.partial) {\n turn.live = el('div', 'ai-chat-answer ai-rw-out');\n renderPreviewMarkdown(turn.live, turn.partial);\n body.append(turn.live);\n }\n const line = el('div', 'ai-chat-progress');\n line.append(el('span', 'ai-chat-dot'), el('span', '', turn.progress));\n body.append(line);\n return;\n }\n const outcome = turn.outcome;\n if (!outcome) {return;}\n switch (outcome.kind) {\n case 'answered':\n renderAnswered(turn, outcome);\n return;\n case 'baseLocalOnly': {\n const onCloud = outcome.route ? `${engineName(outcome.route.engineId)} is a cloud engine, so` : 'This route may not stay on this machine, so';\n const actions = [\n ...(opts.openRouting ? [{ label: 'Pick a local engine', fk: 'chat:pick-local', run: () => opts.openRouting?.() }] : []),\n ...(opts.openBases ? [{ label: \"Open the base's switch\", fk: 'chat:base-switch', run: () => opts.openBases?.() }] : []),\n ];\n renderNotice(body, 'warning', `${onCloud} nothing was sent.`, actions, chatLocalOnlyTitle(outcome.bases));\n return;\n }\n case 'noActiveBases':\n renderNotice(body, 'info', AI_CHAT_NO_BASES, opts.openBases ? [{ label: 'Manage bases…', fk: 'chat:manage-bases', run: () => opts.openBases?.() }] : []);\n return;\n case 'questionHasSecret':\n renderNotice(body, 'warning', AI_CHAT_SECRET_NOTICE);\n return;\n case 'busy':\n renderNotice(body, 'info', AI_CHAT_BUSY_NOTICE);\n return;\n case 'cancelled':\n if (turn.partial) {\n const text = el('div', 'ai-chat-answer ai-rw-out is-cancelled');\n renderPreviewMarkdown(text, turn.partial);\n body.append(text);\n }\n body.append(el('div', 'ai-chat-note', 'Cancelled'));\n return;\n case 'error': {\n const actions = opts.openRouting ? [{ label: 'Open engines', fk: 'chat:engines', run: () => opts.openRouting?.() }] : [];\n renderNotice(body, 'error', errorText(outcome.error, turn.route, engineName), actions);\n return;\n }\n }\n }\n\n // ── A turn ────────────────────────────────────────────────────────────────\n\n function addTurn(question: string): Turn {\n const node = el('article', 'ai-chat-turn');\n const body = el('div', 'ai-chat-reply');\n node.append(el('div', 'ai-chat-question', question), body);\n const turn: Turn = {\n scope,\n startedAt: Date.now(),\n question,\n running: true,\n partial: '',\n progress: 'Starting...',\n route: null,\n outcome: null,\n node,\n body,\n live: null,\n chips: [],\n };\n turns.push(turn);\n log.append(node);\n renderBody(turn);\n return turn;\n }\n\n function flushStream(turn: Turn): void {\n window.clearTimeout(streamTimer);\n streamTimer = undefined;\n if (!turn.running || turn !== current) {return;}\n const was = nearBottom();\n if (turn.live) {renderPreviewMarkdown(turn.live, turn.partial);}\n else {renderBody(turn);}\n scrollDown(was);\n }\n\n function finish(turn: Turn, outcome: DocsTurnOutcome): void {\n window.clearTimeout(streamTimer);\n streamTimer = undefined;\n const was = nearBottom();\n turn.running = false;\n turn.outcome = outcome;\n // Don't keep a key in history, or put it in an export. The text goes back in the box to fix.\n if (outcome.kind === 'questionHasSecret') {\n if (input.value === '' && turn.question) {input.value = turn.question;}\n turn.question = null;\n }\n if (outcome.kind === 'busy' && input.value === '' && turn.question) {input.value = turn.question;}\n if (outcome.kind === 'answered') {\n turn.route = outcome.run.route ?? turn.route;\n turn.node.classList.add('ai-chat-turn--arrived');\n }\n renderBody(turn);\n updateChipTitles(turn);\n current = null;\n controller = null;\n if (outcome.kind === 'noActiveBases') {void loadStatuses();}\n // Cancel is about to hide: keep the keyboard in the panel.\n if (document.activeElement === cancelBtn) {input.focus();}\n renderComposerState();\n resizeInput();\n scrollDown(was);\n }\n\n function send(): void {\n const question = input.value.trim();\n if (question === '' || current !== null || opts.featureOffNotice()) {return;}\n const useBases = scope === 'bases' && !!opts.docs;\n const turn = addTurn(question);\n current = turn;\n input.value = '';\n resizeInput();\n const abort = new AbortController();\n controller = abort;\n renderComposerState();\n log.scrollTop = log.scrollHeight;\n if (useBases) {void loadStatuses();}\n\n const options = opts.docsOptions?.();\n const docs = opts.docs;\n const request: DocsTurnInput = {\n question,\n scope: useBases && docs\n ? { kind: 'bases', docs, ...(options ? { options } : {}) }\n : { kind: 'document', text: opts.documentText(), ...(options ? { options } : {}) },\n ...(opts.thinking !== undefined ? { thinking: opts.thinking } : {}),\n };\n const live = (): boolean => !destroyed && current === turn;\n opts.chat.run(request, {\n onRoute(route) {\n if (live()) {turn.route = route;}\n },\n onProgress(progress) {\n if (!live()) {return;}\n turn.progress = chatProgressLine(progress, turn.scope);\n const was = nearBottom();\n renderBody(turn);\n scrollDown(was);\n },\n onToken(_delta, text) {\n if (!live()) {return;}\n turn.partial = rewriteVisibleText(text).trimStart();\n if (streamTimer === undefined) {\n streamTimer = window.setTimeout(() => flushStream(turn), STREAM_THROTTLE_MS);\n }\n },\n }, abort.signal).then(\n (outcome) => { if (live()) {finish(turn, outcome);} },\n (err: unknown) => { if (live()) {finish(turn, { kind: 'error', error: toAiError(err) });} },\n );\n }\n\n /** Back to idle at once; a late result for this turn is ignored. Earlier history stays. */\n function cancel(): void {\n if (!current) {return;}\n controller?.abort();\n finish(current, { kind: 'cancelled' });\n }\n\n // ── Copy and Save ─────────────────────────────────────────────────────────\n\n async function copyText(text: string, status: ReturnType<typeof inlineStatus>): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n status.show('Copied');\n } catch {\n status.show('Could not copy.', 'error');\n }\n }\n\n const exportAll = (): string => formatChatExport(turns.map((turn) => exportTurn(turn, engineName)));\n\n copyAllBtn.addEventListener('click', () => { void copyText(exportAll(), headerStatus); });\n saveBtn.addEventListener('click', () => {\n Promise.resolve(opts.saveTextFile?.(chatExportFileName(), exportAll())).catch(() => {\n if (!destroyed) {headerStatus.show('Could not save.', 'error');}\n });\n });\n\n // ── Input ─────────────────────────────────────────────────────────────────\n\n function resizeInput(): void {\n input.style.height = 'auto';\n if (input.scrollHeight > 0) {input.style.height = `${input.scrollHeight}px`;}\n }\n\n input.addEventListener('input', () => {\n resizeInput();\n sendBtn.disabled = !!opts.featureOffNotice() || input.value.trim() === '';\n });\n input.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' || e.shiftKey || e.isComposing) {return;}\n e.preventDefault();\n send();\n });\n sendBtn.addEventListener('click', () => send());\n cancelBtn.addEventListener('click', () => cancel());\n closeBtn.addEventListener('click', () => opts.onClose());\n root.addEventListener('keydown', (e) => {\n if (e.key !== 'Escape') {return;}\n e.stopPropagation();\n if (current) {cancel();}\n else {opts.onEscape?.();}\n });\n\n container.append(root);\n setScope('document');\n void loadStatuses();\n\n return {\n destroy() {\n if (destroyed) {return;}\n destroyed = true;\n controller?.abort();\n controller = null;\n current = null;\n window.clearTimeout(streamTimer);\n for (const dispose of statusDisposers) {dispose();}\n statusDisposers.clear();\n turns.length = 0;\n container.replaceChildren();\n },\n focus() {\n if (input.disabled) {closeBtn.focus();}\n else {input.focus();}\n },\n refresh() {\n if (destroyed) {return;}\n void loadStatuses();\n for (const turn of turns) {\n if (!turn.running) {renderBody(turn);}\n }\n renderComposerState();\n },\n };\n}\n","/**\n * Selection rewrite (the `rewrite` AI feature): the popover that previews a\n * rewrite before it replaces the selection and the highlight that marks the\n * target while it is open.\n *\n * Transaction discipline (CLAUDE.md, brainstorm constraints 4, 5 and 7):\n *\n * - While the popover is open the target is marked with a decoration (a PM\n * plugin in rich text, a CM state field in source mode). Nothing streams\n * into the document and nothing touches `editor.view.dom`.\n * - Accept is one transaction: `tr.replaceRange` with the slice parsed from\n * the markdown result in rich text, one CM change in source mode. One undo\n * restores the original.\n * - Every new request (Retry, another variant, a new open) aborts the one\n * before it; Esc and click-away abort too.\n *\n * The popover renders model output through `renderPreviewMarkdown`, which\n * builds DOM with `textContent` only: no raw HTML, no link a click can follow.\n * Insert and Accept use the original markdown, not the rendered text.\n *\n * Three output modes, from the variant and the target:\n *\n * - `replace`: Accept replaces the selection (every variant but Explain).\n * - `readOnly`: Explain. Nothing changes unless Insert below is clicked,\n * which inserts the note as a blockquote after the target's block in one\n * transaction.\n * - `replaceDocument`: Translate with \"Whole document\". The target is the\n * body without its frontmatter; Accept replaces the body in one\n * transaction, puts the cursor at its start and scrolls to the top. A body\n * too long for the model's context is cut by `budgetDocument`: the first\n * part is translated, the rest is kept as it is, and a note says so.\n *\n * Two document jobs (the `summary` and `title` features) open the same\n * popover on a cursor target (`cursorInsertTarget`, `sourceCursorTarget`):\n *\n * - `insert` (`/summary`, `/outline`, \"Summarize document…\"): the summary\n * streams into the preview; Insert puts the block at the cursor's block\n * boundary in one transaction that also removes `/query`. TL;DR ⇄ Outline\n * in the header runs again.\n * - `choose` (`/title`, \"Suggest titles…\"): three candidates; a click hands\n * the title to the caller's `apply` (frontmatter `title:`, the H1, or a\n * new H1). One JSON repair round trip when the reply does not parse.\n */\n\nimport { elementFromString, posToDOMRect, type Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\nimport { DOMParser as PmDOMParser, Fragment, type Node as PmNode } from '@tiptap/pm/model';\nimport { closeHistory } from '@tiptap/pm/history';\nimport { EditorView as CmEditorView } from '@codemirror/view';\nimport { isolateHistory } from '@codemirror/commands';\nimport {\n CHARS_PER_TOKEN,\n DEFAULT_CONTEXT_TOKENS,\n aiErrorCopy,\n aiLengthLimitCopy,\n aiResultStats,\n aiResultStatsText,\n aiResultStatsTitle,\n budgetDocument,\n buildSummaryMessages,\n buildTitleMessages,\n coveragePercent,\n finalizeSummary,\n headingsOutline,\n jsonRepairMessages,\n makeAiError,\n parseTitles,\n renderHeadingOutline,\n summaryMaxTokens,\n summaryPreviewText,\n summaryVisibleText,\n thinkingChoices,\n titleMaxTokens,\n toAiError,\n whatIsSent,\n type AiSummaryKind,\n} from './ai';\nimport type { AiError, AiErrorCopy, AiMessage, AiResultStats, AiRouteOk, AiSendsScope, AiServedBy, AiThinkingLevel, InsertUrlPolicy } from './ai';\nimport { guardInsertFragment, guardSourceMarkdown, insertUrlCheck, type InsertGuardParser, type SourceInspector } from './ai-insert-guard';\nimport type { AiServedRequest } from './ai-settings-model';\nimport {\n AI_AUDIENCES,\n AI_REWRITE_VARIANTS,\n REWRITE_CONTEXT_CHARS,\n buildRewriteMessages,\n finalizeRewriteText,\n getAiAudience,\n getAiRewriteVariant,\n rewriteMaxTokens,\n rewriteVisibleText,\n type AiAudience,\n type AiRewriteGroup,\n type AiRewriteParams,\n type AiRewriteVariant,\n type AiRewriteVariantDefinition,\n} from './ai/prompts/rewrite';\nimport { buildExplainMessages, explainMaxTokens } from './ai/prompts/explain';\nimport { checkMarkdownStructure, type StructureDiff, type StructureMismatch } from './ai/prompts/structureCheck';\nimport type { AiRunEvents, AiRunOutcome, AiRunRequest, AiRunThinking } from './ai-request';\nimport { aiRunThinkingOn } from './ai-request';\nimport { renderPreviewMarkdown } from './ai-markdown-preview';\nimport {\n loadAudience,\n rememberAudience,\n rememberLanguage,\n rememberThinkingLevel,\n thinkingLevelFor,\n translateLanguageChoices,\n} from './ai-prefs';\nimport { getPortal } from './portal';\nimport { aiRewriteHighlightKey, cmRewriteRange, setCmRewriteRange, type Range } from './ai-rewrite-highlight';\n\nexport { AiRewriteHighlight, aiRewriteHighlightKey, cmAiRewriteHighlight } from './ai-rewrite-highlight';\n\nlet nextTargetId = 0;\n\n// ── Targets ─────────────────────────────────────────────────────────────────\n\n/** What the popover rewrites: one selection, or the whole body, in one view. */\nexport interface AiRewriteTarget {\n mode: 'rich' | 'source';\n /**\n * `document`: the whole body without its frontmatter (whole-document\n * translate). `cursor`: a caret or a `/query`, where a document job inserts.\n */\n scope: 'selection' | 'document' | 'cursor';\n /** The selection (or the body) as markdown. */\n text: string;\n before: string;\n after: string;\n /** More than one line: the popover shows old and new side by side. */\n multiline: boolean;\n /** False once the target text is gone (deleted, or the view was replaced). */\n alive(): boolean;\n /** Where the target is on screen now (null when it cannot be measured). */\n rect(): DOMRect | null;\n /** Replace the target in one transaction. False when the target is gone. */\n accept(markdown: string): boolean;\n /**\n * Insert `markdown` as a blockquote after the target's block (rich text) or\n * line (source), in one transaction. False when the target is gone or has\n * no block (a document target).\n */\n insertBelow(markdown: string): boolean;\n /** The document title, context for Explain (set by the caller). */\n title?: string;\n /** Drop the highlight. */\n release(): void;\n /** Give the keyboard back to the editor. */\n focus(): void;\n}\n\nfunction serializeFragment(editor: Editor, fragment: Fragment): string {\n const storage = (editor.storage as unknown as Record<string, { serializer?: { serialize(f: Fragment): string } }>).markdown;\n try {\n const md = storage?.serializer?.serialize(fragment);\n if (typeof md === 'string') {return md;}\n } catch { /* fall through to plain text */ }\n return fragment.textBetween(0, fragment.size, '\\n\\n');\n}\n\n/**\n * `doc` from `from` to `to` as markdown. The serializer only writes marks\n * (links, bold, code...) inside a text block, so a range within one block is\n * wrapped in a plain paragraph first: its marks survive and no block syntax\n * (a heading's `#`) is added. Code keeps its text as is.\n */\nfunction serializeRange(editor: Editor, doc: PmNode, from: number, to: number): string {\n const content = doc.slice(from, to).content;\n const parent = doc.resolve(from).parent;\n const paragraph = editor.state.schema.nodes.paragraph;\n if (content.firstChild?.isInline && !parent.type.spec.code && paragraph) {\n return serializeFragment(editor, Fragment.from(paragraph.create(null, content)));\n }\n return serializeFragment(editor, content);\n}\n\ntype MarkdownStorage = {\n // `md` is the markdown-it instance behind `parse`, for the insert guard.\n parser?: { parse(md: string, o?: { inline?: boolean }): string; md?: InsertGuardParser };\n getMarkdown?(): string;\n};\n\nfunction markdownStorage(editor: Editor): MarkdownStorage | undefined {\n return (editor.storage as unknown as Record<string, MarkdownStorage>).markdown;\n}\n\n/** Markdown parsed into block content for the editor's schema. */\nfunction parseBlocks(editor: Editor, markdown: string): Fragment {\n const html = markdownStorage(editor)?.parser?.parse(markdown) ?? markdown;\n return PmDOMParser.fromSchema(editor.state.schema).parse(elementFromString(html)).content;\n}\n\n/** The insert guard's view of source text: the same parse the rich editor would do. */\nfunction sourceInspector(editor: Editor, policy: InsertUrlPolicy): SourceInspector {\n const md = markdownStorage(editor)?.parser?.md;\n return { check: insertUrlCheck(policy, md), fragment: (markdown) => parseBlocks(editor, markdown), md };\n}\n\n/** The text as a Markdown blockquote: every line quoted, blank lines kept as `>`. */\nexport function blockquoteMarkdown(text: string): string {\n return text.trim().split('\\n').map((line) => (line.trim() ? `> ${line}` : '>')).join('\\n');\n}\n\n/** A thin rect along the top of the visible part of `el`: where a document target \"is\". */\nfunction visibleTopRect(el: Element): DOMRect {\n const r = el.getBoundingClientRect();\n const top = Math.max(r.top, 8);\n return new DOMRect(r.left, top, Math.max(1, r.width), 1);\n}\n\nfunction rectUnion(a: { left: number; right: number; top: number; bottom: number }, b: { left: number; right: number; top: number; bottom: number }): DOMRect {\n const left = Math.min(a.left, b.left);\n const top = Math.min(a.top, b.top);\n return new DOMRect(left, top, Math.max(a.right, b.right) - left, Math.max(a.bottom, b.bottom) - top);\n}\n\n/**\n * The rich-text selection as a rewrite target, or null when there is nothing\n * to rewrite. An empty selection takes the text block around the caret.\n */\nexport function richRewriteTarget(editor: Editor): AiRewriteTarget | null {\n const { state } = editor;\n const sel = state.selection;\n // Table cell selections rewrite cell by cell badly; select the text instead.\n if ('$anchorCell' in sel) {return null;}\n let from = sel.from;\n let to = sel.to;\n if (sel.empty) {\n const $f = sel.$from;\n if (!$f.parent.isTextblock || $f.parent.type.spec.code || !$f.parent.textContent.trim()) {return null;}\n from = $f.start();\n to = $f.end();\n }\n const doc = state.doc;\n // Prose only: an image or another atom on its own is not rewritten.\n if (!doc.textBetween(from, to, ' ').trim()) {return null;}\n const text = serializeRange(editor, doc, from, to);\n if (!text.trim()) {return null;}\n\n // Context: the enclosing top-level block plus one on each side.\n const $from = doc.resolve(from);\n const $to = doc.resolve(to);\n const beforeStart = $from.depth > 0 ? $from.posAtIndex(Math.max(0, $from.index(0) - 1), 0) : 0;\n const afterEnd = $to.depth > 0 ? $to.posAtIndex(Math.min(doc.childCount, $to.index(0) + 2), 0) : doc.content.size;\n const before = beforeStart < from ? serializeRange(editor, doc, beforeStart, from) : '';\n const after = afterEnd > to ? serializeRange(editor, doc, to, afterEnd) : '';\n\n const id = ++nextTargetId;\n editor.view.dispatch(state.tr.setMeta(aiRewriteHighlightKey, { range: { from, to, id } }).setMeta('addToHistory', false));\n const range = (): Range | null => {\n if (editor.isDestroyed) {return null;}\n const r = aiRewriteHighlightKey.getState(editor.state);\n return r && r.id === id ? r : null;\n };\n\n return {\n mode: 'rich',\n scope: 'selection',\n text,\n before,\n after,\n multiline: text.trim().includes('\\n'),\n alive: () => !!range(),\n rect() {\n const r = range();\n if (!r) {return null;}\n try { return posToDOMRect(editor.view, r.from, r.to); } catch { return null; }\n },\n accept(markdown) {\n const r = range();\n if (!r || editor.isDestroyed) {return false;}\n const current = editor.state;\n const html = markdownStorage(editor)?.parser?.parse(markdown, { inline: true }) ?? markdown;\n const slice = PmDOMParser.fromSchema(current.schema).parseSlice(elementFromString(html), {\n preserveWhitespace: true,\n context: current.doc.resolve(r.from),\n });\n // Blocks replacing whole text blocks replace the blocks themselves, so\n // no empty paragraph is left behind.\n let { from, to } = r;\n const $a = current.doc.resolve(from);\n const $b = current.doc.resolve(to);\n if (slice.content.firstChild?.isBlock && $a.parent.isTextblock && $b.parent.isTextblock\n && $a.parentOffset === 0 && $b.parentOffset === $b.parent.content.size\n && $a.depth === $b.depth && $a.node($a.depth - 1) === $b.node($b.depth - 1)) {\n from = $a.before();\n to = $b.after();\n }\n // One transaction, its own undo step.\n const tr = closeHistory(current.tr).replaceRange(from, to, slice);\n tr.setMeta(aiRewriteHighlightKey, { range: null });\n const end = tr.mapping.map(to, 1);\n try {\n tr.setSelection(TextSelection.between(tr.doc.resolve(Math.min(from, tr.doc.content.size)), tr.doc.resolve(Math.min(end, tr.doc.content.size))));\n } catch { /* keep the mapped selection */ }\n editor.view.dispatch(tr.scrollIntoView());\n return true;\n },\n insertBelow(markdown) {\n const r = range();\n if (!r || editor.isDestroyed) {return false;}\n const current = editor.state;\n const content = parseBlocks(editor, blockquoteMarkdown(markdown));\n if (!content.size) {return false;}\n // After the top-level block that holds the end of the target, so a\n // selection inside a list or a table gets its note after the whole block.\n const $to = current.doc.resolve(r.to);\n const pos = $to.depth > 0 ? $to.after(1) : r.to;\n editor.view.dispatch(closeHistory(current.tr).insert(pos, content).scrollIntoView());\n return true;\n },\n release() {\n if (!range()) {return;}\n editor.view.dispatch(editor.state.tr.setMeta(aiRewriteHighlightKey, { range: null }).setMeta('addToHistory', false));\n },\n focus() {\n if (!editor.isDestroyed) {editor.view.focus();}\n },\n };\n}\n\n/** The source-mode selection as a rewrite target. An empty selection takes its line. */\nexport function sourceRewriteTarget(view: CmEditorView): AiRewriteTarget | null {\n const { state } = view;\n const sel = state.selection.main;\n let { from, to } = sel;\n if (sel.empty) {\n const line = state.doc.lineAt(from);\n if (!line.text.trim()) {return null;}\n from = line.from;\n to = line.to;\n }\n const text = state.sliceDoc(from, to);\n if (!text.trim()) {return null;}\n const before = state.sliceDoc(Math.max(0, from - REWRITE_CONTEXT_CHARS * 2), from);\n const after = state.sliceDoc(to, Math.min(state.doc.length, to + REWRITE_CONTEXT_CHARS * 2));\n\n const id = ++nextTargetId;\n view.dispatch({ effects: setCmRewriteRange.of({ from, to, id }) });\n const range = (): Range | null => {\n const r = view.state.field(cmRewriteRange, false);\n return r && r.id === id ? r : null;\n };\n\n return {\n mode: 'source',\n scope: 'selection',\n text,\n before,\n after,\n multiline: text.trim().includes('\\n'),\n alive: () => !!range(),\n rect() {\n const r = range();\n if (!r) {return null;}\n const a = view.coordsAtPos(r.from);\n const b = view.coordsAtPos(r.to, -1);\n if (!a || !b) {return a ? rectUnion(a, a) : b ? rectUnion(b, b) : null;}\n // A multi-line range spans the content's width.\n if (b.top > a.top + 1) {\n const content = view.contentDOM.getBoundingClientRect();\n return rectUnion(a, { ...b, left: content.left, right: Math.max(a.right, b.right) });\n }\n return rectUnion(a, b);\n },\n accept(markdown) {\n const r = range();\n if (!r) {return false;}\n // One CM transaction, isolated in history so one undo restores it.\n view.dispatch({\n changes: { from: r.from, to: r.to, insert: markdown },\n selection: { anchor: r.from, head: r.from + markdown.length },\n effects: setCmRewriteRange.of(null),\n annotations: isolateHistory.of('full'),\n userEvent: 'input.ai',\n scrollIntoView: true,\n });\n return true;\n },\n insertBelow(markdown) {\n const r = range();\n if (!r) {return false;}\n const doc = view.state.doc;\n // A selection that ends at the start of a line belongs to the line before.\n const endLine = doc.lineAt(r.to);\n const line = r.to > r.from && endLine.from === r.to ? doc.lineAt(r.to - 1) : endLine;\n const next = line.number < doc.lines ? doc.line(line.number + 1) : null;\n // A blank line before the quote, and one after it when text follows directly.\n const insert = `\\n\\n${blockquoteMarkdown(markdown)}${next && next.text.trim() ? '\\n' : ''}`;\n view.dispatch({\n changes: { from: line.to, insert },\n annotations: isolateHistory.of('full'),\n userEvent: 'input.ai',\n scrollIntoView: true,\n });\n return true;\n },\n release() {\n if (range()) {view.dispatch({ effects: setCmRewriteRange.of(null) });}\n },\n focus() {\n view.focus();\n },\n };\n}\n\n/**\n * The rich-text body as a whole-document target. The frontmatter is not in\n * the ProseMirror document (the editor keeps it apart), so Accept leaves it\n * byte-identical. `scrollToTop` runs after Accept to show the top of the page.\n */\nexport function richDocumentTarget(editor: Editor, opts: { scrollToTop?: () => void } = {}): AiRewriteTarget | null {\n if (editor.isDestroyed) {return null;}\n const text = markdownStorage(editor)?.getMarkdown?.() ?? editor.state.doc.textBetween(0, editor.state.doc.content.size, '\\n\\n');\n if (!text.trim()) {return null;}\n return {\n mode: 'rich',\n scope: 'document',\n text,\n before: '',\n after: '',\n multiline: false,\n alive: () => !editor.isDestroyed,\n rect: () => (editor.isDestroyed ? null : visibleTopRect(editor.view.dom)),\n accept(markdown) {\n if (editor.isDestroyed) {return false;}\n const current = editor.state;\n const content = parseBlocks(editor, markdown);\n if (!content.size) {return false;}\n // One transaction, its own undo step; the caret goes to the start of\n // the body and the view scrolls there (D13).\n const tr = closeHistory(current.tr).replaceWith(0, current.doc.content.size, content);\n tr.setMeta(aiRewriteHighlightKey, { range: null });\n tr.setSelection(TextSelection.atStart(tr.doc));\n editor.view.dispatch(tr.scrollIntoView());\n opts.scrollToTop?.();\n return true;\n },\n insertBelow: () => false,\n release() { /* no highlight */ },\n focus() {\n if (!editor.isDestroyed) {editor.view.focus();}\n },\n };\n}\n\n/**\n * The source-mode body as a whole-document target. `bodyStart` gives where\n * the body starts in the full text (after the frontmatter); only the body is\n * sent and replaced, so the YAML stays byte-identical.\n */\nexport function sourceDocumentTarget(view: CmEditorView, bodyStart: (markdown: string) => number): AiRewriteTarget | null {\n const full = view.state.doc.toString();\n const text = full.slice(bodyStart(full));\n if (!text.trim()) {return null;}\n return {\n mode: 'source',\n scope: 'document',\n text,\n before: '',\n after: '',\n multiline: false,\n alive: () => view.dom.isConnected,\n rect: () => visibleTopRect(view.scrollDOM),\n accept(markdown) {\n const current = view.state.doc.toString();\n const from = bodyStart(current);\n // One CM transaction, isolated in history; caret at the start of the\n // body, view at the top.\n view.dispatch({\n changes: { from, to: current.length, insert: markdown },\n selection: { anchor: from },\n effects: [setCmRewriteRange.of(null), CmEditorView.scrollIntoView(0, { y: 'start' })],\n annotations: isolateHistory.of('full'),\n userEvent: 'input.ai',\n });\n return true;\n },\n insertBelow: () => false,\n release() { /* no highlight */ },\n focus() {\n view.focus();\n },\n };\n}\n\n/** Where a document job inserts: the caret, or the `/query` it replaces. */\nexport interface AiCursorTarget extends AiRewriteTarget {\n /**\n * Insert. With a `policy` (the chat panel's Insert at cursor, S8), the\n * markdown goes through `ai-insert-guard.ts` first; without one (every other\n * caller), it is inserted as given. False when it could not be.\n */\n accept(markdown: string, policy?: InsertUrlPolicy): boolean;\n /** The `/query` (from < to) or the caret (from === to), mapped through edits; null once gone. */\n range(): { from: number; to: number } | null;\n}\n\n/**\n * The rich-text caret, or a slash command's `/query`, as an insert target.\n * The `/query` is marked while the popover is open and stays in the\n * document until Accept, which removes it (with a mid-line trigger space)\n * and inserts the blocks in one transaction: in place of the caret's\n * top-level block when that is left an empty paragraph, else after it.\n * Cancel leaves the document untouched.\n */\nexport function cursorInsertTarget(editor: Editor, slash?: { from: number; to: number }): AiCursorTarget | null {\n if (editor.isDestroyed) {return null;}\n const { state } = editor;\n const id = ++nextTargetId;\n const head = state.selection.head;\n const initial: Range = slash && slash.to > slash.from\n ? { from: slash.from, to: slash.to, id }\n : { from: head, to: head, id, anchor: true };\n editor.view.dispatch(state.tr.setMeta(aiRewriteHighlightKey, { range: initial }).setMeta('addToHistory', false));\n const range = (): Range | null => {\n if (editor.isDestroyed) {return null;}\n const r = aiRewriteHighlightKey.getState(editor.state);\n return r && r.id === id ? r : null;\n };\n\n return {\n mode: 'rich',\n scope: 'cursor',\n text: '',\n before: '',\n after: '',\n multiline: false,\n alive: () => !!range(),\n range() {\n const r = range();\n return r ? { from: r.from, to: r.to } : null;\n },\n rect() {\n const r = range();\n if (!r) {return null;}\n try { return posToDOMRect(editor.view, r.from, r.to); } catch { return null; }\n },\n accept(markdown, policy) {\n const r = range();\n if (!r || editor.isDestroyed) {return false;}\n let content = parseBlocks(editor, markdown);\n if (policy) {\n const guarded = guardInsertFragment(content, insertUrlCheck(policy, markdownStorage(editor)?.parser?.md));\n if (!guarded) {return false;}\n content = guarded.fragment;\n }\n if (!content.size) {return false;}\n const current = editor.state;\n // One transaction, its own undo step: `/query` out, the blocks in.\n const tr = closeHistory(current.tr);\n let at = r.from;\n if (r.to > r.from) {\n const $q = current.doc.resolve(r.from);\n if ($q.parentOffset > 0 && current.doc.textBetween(r.from - 1, r.from) === ' ') {at = r.from - 1;}\n tr.delete(at, r.to);\n }\n tr.setMeta(aiRewriteHighlightKey, { range: null });\n // Text that must stay plain stays plain: the Link extension's autolink\n // plugin would otherwise mark a URL ending a block of this insert.\n if (policy) {tr.setMeta('preventAutolink', true);}\n const $at = tr.doc.resolve(Math.min(at, tr.doc.content.size));\n let from = $at.pos;\n let to = $at.pos;\n if ($at.depth > 0) {\n const block = $at.node(1);\n const empty = block.type.name === 'paragraph' && block.content.size === 0;\n from = empty ? $at.before(1) : $at.after(1);\n to = empty ? $at.after(1) : from;\n }\n tr.replaceWith(from, to, content);\n const end = Math.min(from + content.size, tr.doc.content.size);\n try { tr.setSelection(TextSelection.near(tr.doc.resolve(end), -1)); } catch { /* keep the mapped selection */ }\n editor.view.dispatch(tr.scrollIntoView());\n return true;\n },\n insertBelow: () => false,\n release() {\n if (!range()) {return;}\n editor.view.dispatch(editor.state.tr.setMeta(aiRewriteHighlightKey, { range: null }).setMeta('addToHistory', false));\n },\n focus() {\n if (!editor.isDestroyed) {editor.view.focus();}\n },\n };\n}\n\n/**\n * The source-mode caret as an insert target. Accept puts the markdown at the\n * caret's line in one CM transaction: in place of a blank line, else after\n * the line, with blank lines around it. A caret inside the frontmatter\n * inserts at the start of the body (`bodyStart`). `parserEditor` is the rich\n * editor whose parser judges the text when Accept gets a policy; a policy with\n * no parser to judge by is refused.\n */\nexport function sourceCursorTarget(view: CmEditorView, bodyStart?: (markdown: string) => number, parserEditor?: Editor): AiCursorTarget {\n const id = ++nextTargetId;\n const head = view.state.selection.main.head;\n view.dispatch({ effects: setCmRewriteRange.of({ from: head, to: head, id, anchor: true }) });\n const range = (): Range | null => {\n const r = view.state.field(cmRewriteRange, false);\n return r && r.id === id ? r : null;\n };\n\n return {\n mode: 'source',\n scope: 'cursor',\n text: '',\n before: '',\n after: '',\n multiline: false,\n alive: () => !!range() && view.dom.isConnected,\n range() {\n const r = range();\n return r ? { from: r.from, to: r.to } : null;\n },\n rect() {\n const r = range();\n const c = r ? view.coordsAtPos(r.from) : null;\n return c ? rectUnion(c, c) : null;\n },\n accept(markdown, policy) {\n const r = range();\n let md = markdown.trim();\n if (!r || !md) {return false;}\n const doc = view.state.doc;\n const start = bodyStart ? bodyStart(doc.toString()) : 0;\n const line = doc.lineAt(Math.max(r.from, Math.min(start, doc.length)));\n const prev = line.number > 1 ? doc.line(line.number - 1) : null;\n const next = line.number < doc.lines ? doc.line(line.number + 1) : null;\n const textAfter = !!next && !!next.text.trim();\n const place = (text: string): { changes: { from: number; to?: number; insert: string }; caret: number } => {\n if (!line.text.trim()) {\n const lead = prev && prev.text.trim() && line.from >= start ? '\\n' : '';\n return { changes: { from: line.from, to: line.to, insert: `${lead}${text}${textAfter ? '\\n' : ''}` }, caret: line.from + lead.length + text.length };\n }\n return { changes: { from: line.to, insert: `\\n\\n${text}${textAfter ? '\\n' : ''}` }, caret: line.to + 2 + text.length };\n };\n if (policy) {\n if (!parserEditor || parserEditor.isDestroyed) {return false;}\n const before = doc.toString();\n const guarded = guardSourceMarkdown(md, sourceInspector(parserEditor, policy), (text) => {\n const { changes } = place(text);\n const after = before.slice(0, changes.from) + changes.insert + before.slice(changes.to ?? changes.from);\n return { before: before.slice(start), after: after.slice(bodyStart ? bodyStart(after) : 0) };\n });\n if (guarded === null) {return false;}\n md = guarded;\n }\n const { changes, caret } = place(md);\n // One CM transaction, isolated in history so one undo removes it.\n view.dispatch({\n changes,\n selection: { anchor: caret },\n effects: setCmRewriteRange.of(null),\n annotations: isolateHistory.of('full'),\n userEvent: 'input.ai',\n scrollIntoView: true,\n });\n return true;\n },\n insertBelow: () => false,\n release() {\n if (range()) {view.dispatch({ effects: setCmRewriteRange.of(null) });}\n },\n focus() {\n view.focus();\n },\n };\n}\n\n// ── Titles ──────────────────────────────────────────────────────────────────\n\n/** What a picked title changes (D12): frontmatter `title:` wins, then the first H1, else a new H1. */\nexport type AiTitleEffect = 'frontmatter' | 'h1' | 'insertH1';\n\n/** The one-line hint under the candidates, naming the effect before the click. */\nexport const AI_TITLE_EFFECT_HINTS: Record<AiTitleEffect, string> = {\n frontmatter: 'Sets title: in Properties',\n h1: 'Replaces the H1',\n insertH1: 'Inserts an H1',\n};\n\n/** True when the frontmatter YAML has a top-level `title:` key. */\nexport function yamlHasTitle(yaml: string | null | undefined): boolean {\n return /^title[ \\t]*:/m.test(yaml ?? '');\n}\n\n/**\n * The YAML with its top-level `title:` set to `title` (quoted when YAML\n * needs it). Only the title entry changes, including any indented block\n * scalar lines under it; every other line stays byte-identical. Without a\n * `title:` key the YAML comes back unchanged.\n */\nexport function setYamlTitle(yaml: string, title: string): string {\n const lines = yaml.split('\\n');\n const i = lines.findIndex((l) => /^title[ \\t]*:/.test(l));\n if (i < 0) {return yaml;}\n let end = i + 1;\n while (end < lines.length && /^[ \\t]+\\S/.test(lines[end])) {end++;}\n lines.splice(i, end - i, `title: ${yamlScalar(title)}`);\n return lines.join('\\n');\n}\n\nfunction yamlScalar(s: string): string {\n const plain = !/[:#[\\]{},&*!|>'\"%@`]/.test(s) && !/^\\s|\\s$/.test(s) && !/^(-?\\d+(\\.\\d+)?|true|false|null|yes|no|on|off|~|-.*)$/i.test(s);\n return plain && s ? s : `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Set the title in rich text in one transaction (its own undo step), removing\n * `remove` (a `/query`) in the same transaction: `h1` replaces the first\n * H1's text, `insertH1` puts a new H1 at the top. The frontmatter case is the\n * caller's (the YAML is not in the ProseMirror document).\n */\nexport function applyRichTitle(editor: Editor, effect: 'h1' | 'insertH1', title: string, remove?: { from: number; to: number } | null): boolean {\n if (editor.isDestroyed || !title.trim()) {return false;}\n const { schema } = editor.state;\n const heading = schema.nodes.heading;\n if (!heading) {return false;}\n const tr = closeHistory(editor.state.tr);\n if (remove && remove.to > remove.from) {tr.delete(remove.from, remove.to);}\n tr.setMeta(aiRewriteHighlightKey, { range: null });\n let h1: { pos: number; size: number } | null = null;\n if (effect === 'h1') {\n tr.doc.descendants((node, pos) => {\n if (h1) {return false;}\n if (node.type === heading && node.attrs.level === 1) {\n h1 = { pos, size: node.content.size };\n return false;\n }\n return !node.isTextblock;\n });\n }\n const found = h1 as { pos: number; size: number } | null;\n if (found) {\n tr.replaceWith(found.pos + 1, found.pos + 1 + found.size, schema.text(title));\n } else {\n tr.insert(0, heading.create({ level: 1 }, schema.text(title)));\n }\n editor.view.dispatch(tr.scrollIntoView());\n return true;\n}\n\n/** The first H1 line of `markdown` from `from` on (outside fenced code), or null. */\nfunction sourceH1Line(markdown: string, from: number): { from: number; to: number; prefix: string } | null {\n let pos = from;\n let fence: string | null = null;\n while (pos <= markdown.length) {\n const nl = markdown.indexOf('\\n', pos);\n const end = nl < 0 ? markdown.length : nl;\n const line = markdown.slice(pos, end);\n const f = /^ {0,3}(`{3,}|~{3,})/.exec(line);\n if (fence) {\n if (f && f[1][0] === fence[0] && f[1].length >= fence.length && !line.trim().slice(f[1].length).trim()) {fence = null;}\n } else if (f) {\n fence = f[1];\n } else {\n const m = /^( {0,3}#[ \\t]+)/.exec(line);\n if (m) {return { from: pos, to: end, prefix: m[1] };}\n }\n if (nl < 0) {break;}\n pos = nl + 1;\n }\n return null;\n}\n\n/**\n * Set the title in source mode in one CM transaction: the frontmatter\n * `title:` line, else the first H1's text, else a new H1 at the start of the\n * body (`bodyStart`).\n */\nexport function applySourceTitle(view: CmEditorView, effect: AiTitleEffect, title: string, frontmatter: { yaml: string | null; bodyStart: number }): boolean {\n if (!title.trim()) {return false;}\n const full = view.state.doc.toString();\n let change: { from: number; to: number; insert: string };\n if (effect === 'frontmatter' && frontmatter.yaml !== null && yamlHasTitle(frontmatter.yaml)) {\n // The YAML sits between the opening `---` line and the closing one.\n const yamlFrom = full.indexOf('\\n') + 1;\n change = { from: yamlFrom, to: yamlFrom + frontmatter.yaml.length, insert: setYamlTitle(frontmatter.yaml, title) };\n } else {\n const h1 = effect === 'insertH1' ? null : sourceH1Line(full, frontmatter.bodyStart);\n change = h1\n ? { from: h1.from + h1.prefix.length, to: h1.to, insert: title }\n : { from: frontmatter.bodyStart, to: frontmatter.bodyStart, insert: `# ${title}\\n\\n` };\n }\n view.dispatch({\n changes: change,\n effects: setCmRewriteRange.of(null),\n annotations: isolateHistory.of('full'),\n userEvent: 'input.ai',\n });\n return true;\n}\n\n// ── Icons ───────────────────────────────────────────────────────────────────\n\nconst icon = (body: string, size = 14) => `<svg width=\"${size}\" height=\"${size}\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${body}</svg>`;\nconst SPARK = icon('<path d=\"M8 2.2l1.25 3.3 3.3 1.25-3.3 1.25L8 11.3 6.75 8 3.45 6.75 6.75 5.5z\"/><path d=\"M12.6 10.6l.5 1.3 1.3.5-1.3.5-.5 1.3-.5-1.3-1.3-.5 1.3-.5z\"/>');\nconst CLOSE = icon('<path d=\"M4.5 4.5l7 7M11.5 4.5l-7 7\"/>', 12);\nconst LOCAL = icon('<path d=\"M2.5 7.5L8 3l5.5 4.5M4 6.5V13h8V6.5\"/>', 11);\nconst CLOUD = icon('<path d=\"M4.5 12.5h7a2.75 2.75 0 0 0 .3-5.48A4 4 0 0 0 4.1 7.6 2.5 2.5 0 0 0 4.5 12.5z\"/>', 11);\nconst ALERT = icon('<path d=\"M8 2.5l6 10.5H2z\"/><path d=\"M8 6.5v3M8 11.4v.1\"/>', 16);\nconst WARN = icon('<path d=\"M8 2.5l6 10.5H2z\"/><path d=\"M8 6.5v3M8 11.4v.1\"/>', 12);\nconst BACK = icon('<path d=\"M9.5 4L5.5 8l4 4\"/>', 14);\nconst CHECK = icon('<path d=\"M3.5 8.5l3 3 6-7\"/>', 12);\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string, text?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (className) {node.className = className;}\n if (text !== undefined) {node.textContent = text;}\n return node;\n}\n\nfunction button(className: string, label: string, onClick: () => void): HTMLButtonElement {\n const b = el('button', className, label);\n b.type = 'button';\n // Keep the editor's selection and focus where they are until the action runs.\n b.addEventListener('mousedown', (e) => e.preventDefault());\n b.addEventListener('click', () => { if (b.getAttribute('aria-disabled') !== 'true') {onClick();} });\n return b;\n}\n\nexport function isMacPlatform(): boolean {\n return typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || '');\n}\n\n// ── Grouped variants ────────────────────────────────────────────────────────\n\nconst GROUP_LABELS: Record<AiRewriteGroup, string> = {\n length: 'Length',\n tone: 'Tone',\n audience: 'Audience',\n translate: 'Translate',\n explain: 'Explain',\n custom: 'Custom',\n};\n\nexport interface AiRewriteMenuGroup {\n group: AiRewriteGroup;\n label: string;\n variants: AiRewriteVariantDefinition[];\n}\n\n/** `AI_REWRITE_VARIANTS` in menu order, one entry per group (Length, Tone, …, Custom). */\nexport function aiRewriteMenuGroups(): AiRewriteMenuGroup[] {\n const groups: AiRewriteMenuGroup[] = [];\n for (const v of AI_REWRITE_VARIANTS) {\n let g = groups.find((x) => x.group === v.group);\n if (!g) {\n g = { group: v.group, label: GROUP_LABELS[v.group], variants: [] };\n groups.push(g);\n }\n g.variants.push(v);\n }\n return groups;\n}\n\n/** Variants whose result is checked for dropped links, code, list items and the like. */\nconst STRUCTURE_CHECKED = new Set<AiRewriteVariant>(['translate', 'simpler', 'formal', 'casual', 'expand']);\n\nconst STRUCTURE_NOUNS: Record<StructureMismatch['kind'], [string, string]> = {\n heading: ['heading', 'headings'],\n fencedCodeBlock: ['code block', 'code blocks'],\n inlineCode: ['inline code span', 'inline code spans'],\n link: ['link', 'links'],\n image: ['image', 'images'],\n listItem: ['list item', 'list items'],\n tableRow: ['table row', 'table rows'],\n wikilink: ['wikilink', 'wikilinks'],\n footnote: ['footnote reference', 'footnote references'],\n};\n\n/**\n * The warning line for a structure diff (\"Check: 1 link missing in the\n * result\"), or '' when nothing differs. Headings of every level count as one.\n */\nexport function structureWarningText(diff: StructureDiff): string {\n if (diff.ok) {return '';}\n const byKind = new Map<StructureMismatch['kind'], { original: number; result: number; message: string }>();\n for (const m of diff.mismatches) {\n const seen = byKind.get(m.kind);\n if (seen) {\n seen.original += m.original;\n seen.result += m.result;\n } else {\n byKind.set(m.kind, { original: m.original, result: m.result, message: m.message });\n }\n }\n const parts: string[] = [];\n for (const [kind, m] of byKind) {\n const [one, many] = STRUCTURE_NOUNS[kind];\n const d = m.original - m.result;\n const noun = Math.abs(d) === 1 ? one : many;\n if (d > 0) {parts.push(`${d} ${noun} missing in the result`);}\n else if (d < 0) {parts.push(`${-d} extra ${noun} in the result`);}\n else if (kind === 'link' || kind === 'image') {parts.push(`${many} point somewhere else in the result`);}\n else {parts.push(`${many} differ in the result`);}\n }\n return `Check: ${parts.join('; ')}`;\n}\n\n/**\n * Output budget for a whole-document translation: about the body's length\n * again, more than `rewriteMaxTokens` allows a selection. A host that cannot\n * take it answers `contextOverflow` or stops at the length limit.\n */\nfunction documentMaxTokens(text: string): number {\n return Math.max(1024, Math.min(16384, Math.ceil((text.length / CHARS_PER_TOKEN) * 1.6) + 256));\n}\n\n/** Tokens kept for the system prompt, the instructions and slack around a budgeted document. */\nconst DOCUMENT_RESERVE_TOKENS = 768;\n\n/**\n * Fit a whole-document translation to the model's context. The answer is\n * about as long as what is sent, so when the body does not fit beside its\n * own `documentMaxTokens` the context is split: about 1 part sent to 1.6\n * parts answer. Returns the part to send, the output budget and what is left.\n */\nexport function budgetTranslation(body: string, contextTokens: number): { text: string; rest: string; coverage: number; maxTokens: number } {\n let maxTokens = documentMaxTokens(body);\n let b = budgetDocument(body, { contextTokens, outputTokens: maxTokens, reserveTokens: DOCUMENT_RESERVE_TOKENS });\n if (b.truncated) {\n const room = Math.max(0, contextTokens - DOCUMENT_RESERVE_TOKENS);\n maxTokens = Math.max(1024, Math.min(16384, Math.floor((room * 1.6) / 2.6)));\n b = budgetDocument(body, { contextTokens, outputTokens: maxTokens, reserveTokens: DOCUMENT_RESERVE_TOKENS });\n if (b.truncated) {maxTokens = Math.min(maxTokens, documentMaxTokens(b.text));}\n }\n return b.truncated\n ? { text: b.text, rest: body.slice(b.text.length), coverage: b.coverage, maxTokens }\n : { text: body, rest: '', coverage: 1, maxTokens };\n}\n\n/** The coverage line for a budgeted document job, or '' when all of it was sent. */\nexport function coverageNoteText(job: 'summary' | 'titles' | 'translate', coverage: number): string {\n if (coverage >= 1) {return '';}\n const pct = coveragePercent(coverage);\n if (job === 'translate') {return `Translates the first ${pct}% of the document; the rest did not fit the model's context and stays as it is.`;}\n if (job === 'titles') {return `Based on the first ${pct}% of the document and all of its headings; the rest did not fit the model's context.`;}\n return `Covers the first ${pct}% of the document; the rest did not fit the model's context.`;\n}\n\n// ── Popover ─────────────────────────────────────────────────────────────────\n\nexport interface AiRewriteBadge {\n where: 'local' | 'cloud' | null;\n text: string;\n title: string;\n fallback: boolean;\n}\n\nexport interface AiRewritePopoverDeps {\n run(req: AiRunRequest, events: AiRunEvents, signal: AbortSignal): Promise<AiRunOutcome>;\n /** Footer badge for the route about to serve (before the result) or what served. */\n badge(route: AiRouteOk | null, served: AiServedBy | null, viaFallback: boolean, about?: { feature?: string; sends?: AiSendsScope }): AiRewriteBadge | null;\n onServed(served: AiServedBy, viaFallback: boolean): void;\n /** The AI settings; with `engineId`, that engine's page (an error's \"Open <engine>\"). */\n openSettings(engineId?: string): void;\n /** An engine's display name, so an error can name it (\"Anthropic refused the API key.\"). Absent: errors stay generic. */\n engineName?(engineId: string): string | null;\n /** A request started or stopped running in the popover (the toolbar button's running state). */\n onBusy?(running: boolean): void;\n /** The whole body as a target (Translate's \"Whole document\"); absent hides the toggle. */\n documentTarget?(): AiRewriteTarget | null;\n /**\n * The routed model for `feature`, before sending: its context window (null\n * when unknown, then `DEFAULT_CONTEXT_TOKENS`) and whether it has a JSON\n * mode. Absent: the defaults.\n */\n routeInfo?(feature: string): { contextTokens: number | null; json: boolean };\n}\n\n/** `/summary` and `/outline`: what to summarise. */\nexport interface AiSummaryJob {\n /** The document body as markdown (frontmatter left out). */\n markdown: string;\n kind: AiSummaryKind;\n}\n\n/** `/title`: what to title, and what a pick does. */\nexport interface AiTitleJob {\n /** The document body as markdown (frontmatter left out). */\n markdown: string;\n /** The current title, so the model does not hand it back. */\n existingTitle?: string;\n /** What a pick changes; named in the hint under the list. */\n effect: AiTitleEffect;\n /** Set the picked title (one undo step). False when nothing changed. */\n apply(title: string): boolean;\n}\n\n/** What to run when the popover opens; a parameterised variant without its parameter opens its picker. */\nexport interface AiRewriteChoice {\n variant: AiRewriteVariant;\n instruction?: string;\n params?: AiRewriteParams;\n /** Translate the whole document instead of the selection. */\n wholeDocument?: boolean;\n}\n\nexport interface AiRewritePopover {\n /** Open on a target: with a variant it runs at once (or opens its picker), without one it shows the choices. */\n open(target: AiRewriteTarget, choice?: AiRewriteChoice): void;\n /** Open on a target to say why rewrite cannot run (AI on, no usable route). */\n openUnavailable(target: AiRewriteTarget, reason: string): void;\n /** `insert` mode: summarise the document and insert the block at the target. */\n openSummary(target: AiRewriteTarget, job: AiSummaryJob): void;\n /** `choose` mode: suggest three titles; a click applies one. */\n openTitles(target: AiRewriteTarget, job: AiTitleJob): void;\n close(): void;\n isOpen(): boolean;\n destroy(): void;\n}\n\ntype Phase = 'choose' | 'running' | 'done' | 'error';\ntype Picker = 'language' | 'audience';\ntype OutputMode = 'replace' | 'readOnly' | 'replaceDocument' | 'insert' | 'choose';\n/** What the popover is running: a rewrite variant, a summary, or title suggestions. */\ntype Job = 'rewrite' | 'summary' | 'titles';\n\nconst SUMMARY_KIND_LABELS: Record<AiSummaryKind, string> = { tldr: 'TL;DR', outline: 'Outline' };\nconst REPAIR_NOTE = 'Fixing the answer format…';\n\n/** True when `params` holds what `def` needs. */\nfunction hasParam(def: AiRewriteVariantDefinition | undefined, params: AiRewriteParams): boolean {\n if (def?.param === 'language') {return !!params.language?.trim();}\n if (def?.param === 'audience') {return !!params.audience && !!getAiAudience(params.audience);}\n return true;\n}\n\nconst plainLabel = (label: string): string => label.replace(/…$/, '');\n\n/** The dial's segment label: `thinkingChoices` labels, Medium shortened to fit the header. */\nconst thinkingSegmentLabel = (label: string): string => (label === 'Medium' ? 'Med' : label);\n\n/** The level a route ran with: what the request sent, else the model's own. */\nfunction thinkingInEffect(t: AiRunThinking | null): AiThinkingLevel | null {\n return t ? t.sent ?? t.configured : null;\n}\n\n/** The dial's Default segment: MikeDown picks per task (Off for short edits), else no thinking fields. */\nconst THINKING_DEFAULT = 'default';\n\n/** The remembered preference the dial shows as checked: the level sent, else Default (also when the job's default was sent). */\nconst thinkingSelected = (t: AiRunThinking | null): string => (t && !t.auto ? t.sent : null) ?? THINKING_DEFAULT;\n\n/** \"local · Proxy · model\" reads \"Local · Proxy · model\". */\nconst capitalizeFirst = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);\n\nexport function createAiRewritePopover(deps: AiRewritePopoverDeps): AiRewritePopover {\n let target: AiRewriteTarget | null = null;\n let root: HTMLElement | null = null;\n let phase: Phase = 'choose';\n let variant: AiRewriteVariant = 'shorter';\n let instruction = '';\n let params: AiRewriteParams = {};\n let picker: Picker | null = null;\n let wholeDocument = false;\n /** Opened on the document itself (no selection): only the language picker applies. */\n let docOnly = false;\n let controller: AbortController | null = null;\n let runSeq = 0;\n let raw = '';\n let finalText = '';\n /** The summary stream stopped at the length limit: the preview drops the same fragment Insert does. */\n let summaryCutOff = false;\n let route: AiRouteOk | null = null;\n let served: AiServedBy | null = null;\n /** How long the served result took and how fast it came (null: the host did not measure). */\n let stats: AiResultStats | null = null;\n let viaFallback = false;\n /** The thinking dial for the current route; null hides it (no mapping, tier-1 host, no route yet). */\n let thinking: AiRunThinking | null = null;\n let error: AiError | null = null;\n /** Copy that replaces the error code's own (an answer that never came, out of room). */\n let errorCopy: AiErrorCopy | null = null;\n /** The error is the router's: nothing can serve, so the fix is in settings. */\n let unavailable = false;\n let note = '';\n let warning: { text: string; title: string } | null = null;\n let job: Job = 'rewrite';\n let summaryJob: AiSummaryJob | null = null;\n let titleJob: AiTitleJob | null = null;\n let titles: string[] = [];\n /** Share of the document sent (summary, titles, whole-document translate); 1 when all of it fit. */\n let coverage = 1;\n /** What the rewrite was asked about: the selection, or the part of the body that fit. */\n let sentText = '';\n /** A whole-document translation cut to fit: the rest of the body, kept as it is on Accept. */\n let untranslated = '';\n /** The title job's JSON repair round trip is running (D16). */\n let repairing = false;\n let side: 'below' | 'above' | null = null;\n let frame = 0;\n let copiedTimer: number | undefined;\n let detach: Array<() => void> = [];\n\n // Parts rebuilt per open.\n let titleEl: HTMLElement;\n let badgeEl: HTMLElement;\n let statsEl: HTMLElement;\n let thinkEl: HTMLElement;\n let chooseEl: HTMLElement;\n let menuEl: HTMLElement;\n let formEl: HTMLFormElement;\n let pickerEl: HTMLElement;\n let inputEl: HTMLInputElement;\n let bodyEl: HTMLElement;\n let oldTextEl: HTMLElement;\n let outEl: HTMLElement;\n let caretEl: HTMLElement;\n let newLabelEl: HTMLElement;\n let newPaneEl: HTMLElement;\n let errorEl: HTMLElement;\n let warnEl: HTMLElement;\n let footEl: HTMLElement;\n let acceptBtn: HTMLButtonElement;\n let retryBtn: HTMLButtonElement;\n let copyBtn: HTMLButtonElement;\n let noteEl: HTMLElement;\n let closeBtn: HTMLButtonElement;\n let liveEl: HTMLElement;\n let kindEl: HTMLElement;\n let coverageEl: HTMLElement;\n let titlesBoxEl: HTMLElement;\n let titlesEl: HTMLElement;\n let titleHintEl: HTMLElement;\n\n function abort(): void {\n runSeq += 1;\n controller?.abort();\n controller = null;\n }\n\n function close(opts: { refocus?: boolean } = {}): void {\n if (!target) {return;}\n abort();\n cancelAnimationFrame(frame);\n window.clearTimeout(copiedTimer);\n for (const off of detach) {off();}\n detach = [];\n root?.remove();\n root = null;\n syncBusy();\n const t = target;\n target = null;\n picker = null;\n t.release();\n if (opts.refocus !== false) {t.focus();}\n }\n\n function outputMode(): OutputMode {\n if (job === 'summary') {return 'insert';}\n if (job === 'titles') {return 'choose';}\n if (getAiRewriteVariant(variant)?.output === 'readOnly') {return 'readOnly';}\n return target?.scope === 'document' ? 'replaceDocument' : 'replace';\n }\n\n function build(): HTMLElement {\n const box = el('div', 'mikedown-ai-rewrite');\n box.setAttribute('role', 'dialog');\n box.setAttribute('aria-label', 'Rewrite with AI');\n box.tabIndex = -1;\n\n const head = el('div', 'ai-rw-head');\n const spark = el('span', 'ai-rw-spark');\n spark.innerHTML = SPARK;\n titleEl = el('span', 'ai-rw-title', 'Rewrite');\n thinkEl = el('div', 'ai-rw-think');\n thinkEl.setAttribute('role', 'radiogroup');\n thinkEl.setAttribute('aria-label', 'Thinking');\n thinkEl.hidden = true;\n // Arrow keys move between levels (roving focus); Enter or Space picks, which runs again.\n thinkEl.addEventListener('keydown', onThinkingKey);\n badgeEl = el('span', 'ai-rw-badge');\n badgeEl.hidden = true;\n closeBtn = button('ai-rw-icon-btn', '', () => close());\n closeBtn.innerHTML = CLOSE;\n // TL;DR ⇄ Outline for a summary; picking the other one runs again.\n kindEl = el('div', 'ai-rw-kind');\n kindEl.setAttribute('role', 'group');\n kindEl.setAttribute('aria-label', 'Summary kind');\n kindEl.hidden = true;\n for (const k of ['tldr', 'outline'] as const) {\n const seg = button('ai-rw-kind-seg', SUMMARY_KIND_LABELS[k], () => pickKind(k));\n seg.dataset.kind = k;\n seg.title = k === 'tldr' ? 'A short TL;DR of the document (runs again)' : 'An outline of the document (runs again)';\n kindEl.append(seg);\n }\n // The title and the thinking dial; the engine badge is in the footer, where it has room.\n head.append(spark, titleEl, kindEl, thinkEl, closeBtn);\n\n // First level: one row per group (Length, Tone, Audience, Translate,\n // Explain), then the custom prompt. Second level: the picker.\n chooseEl = el('div', 'ai-rw-choose');\n menuEl = el('div', 'ai-rw-menu');\n menuEl.setAttribute('role', 'menu');\n menuEl.setAttribute('aria-label', 'Rewrite options');\n for (const g of aiRewriteMenuGroups()) {\n if (g.group === 'custom') {continue;}\n const section = el('div', 'ai-rw-group');\n section.dataset.group = g.group;\n section.setAttribute('role', 'group');\n section.setAttribute('aria-label', g.label);\n const heading = el('div', 'ai-rw-group-label', g.label);\n heading.setAttribute('aria-hidden', 'true');\n const chips = el('div', 'ai-rw-chips');\n for (const v of g.variants) {\n const chip = button('ai-rw-chip', v.label, () => choose(v));\n chip.setAttribute('role', 'menuitem');\n if (v.title) {chip.title = v.title;}\n chip.dataset.variant = v.id;\n if (v.param) {chip.setAttribute('aria-haspopup', 'menu');}\n chips.append(chip);\n }\n section.append(heading, chips);\n menuEl.append(section);\n }\n formEl = el('form', 'ai-rw-form');\n inputEl = el('input', 'ai-rw-input');\n inputEl.type = 'text';\n inputEl.placeholder = 'Describe a change, e.g. \"make it friendlier\"';\n inputEl.setAttribute('aria-label', 'Custom rewrite instruction');\n inputEl.maxLength = 1000;\n const go = button('ai-rw-btn ai-rw-btn--primary', 'Rewrite', () => submitCustom());\n formEl.append(inputEl, go);\n formEl.addEventListener('submit', (e) => { e.preventDefault(); submitCustom(); });\n pickerEl = el('div', 'ai-rw-picker');\n chooseEl.append(menuEl, formEl, pickerEl);\n\n bodyEl = el('div', 'ai-rw-body');\n const oldPane = el('div', 'ai-rw-pane ai-rw-pane--old');\n oldTextEl = el('div', 'ai-rw-text');\n oldPane.append(el('div', 'ai-rw-label', 'Original'), oldTextEl);\n newPaneEl = el('div', 'ai-rw-pane ai-rw-pane--new');\n const newText = el('div', 'ai-rw-text');\n outEl = el('div', 'ai-rw-out');\n caretEl = el('span', 'ai-rw-caret');\n newText.append(outEl);\n newLabelEl = el('div', 'ai-rw-label', 'Rewrite');\n newPaneEl.append(newLabelEl, newText);\n bodyEl.append(oldPane, newPaneEl);\n\n // Title candidates, and what a pick changes.\n titlesBoxEl = el('div', 'ai-rw-titles-box');\n titlesEl = el('div', 'ai-rw-titles');\n titlesEl.setAttribute('role', 'menu');\n titlesEl.setAttribute('aria-label', 'Suggested titles');\n titleHintEl = el('div', 'ai-rw-titles-hint');\n titlesBoxEl.append(titlesEl, titleHintEl);\n\n errorEl = el('div', 'ai-rw-error');\n errorEl.setAttribute('role', 'alert');\n\n coverageEl = el('div', 'ai-rw-coverage');\n\n warnEl = el('div', 'ai-rw-warn');\n\n footEl = el('div', 'ai-rw-foot');\n acceptBtn = button('ai-rw-btn ai-rw-btn--primary', 'Accept', () => accept());\n retryBtn = button('ai-rw-btn', 'Retry', () => rerun());\n copyBtn = button('ai-rw-btn', 'Copy', () => copy());\n noteEl = el('span', 'ai-rw-note');\n // \"2.4 s · 38 tok/s\", beside the badge once the answer is in.\n statsEl = el('span', 'ai-rw-stats');\n statsEl.hidden = true;\n footEl.append(acceptBtn, retryBtn, copyBtn, noteEl, statsEl, badgeEl);\n\n liveEl = el('div', 'ai-rw-sr');\n liveEl.setAttribute('aria-live', 'polite');\n\n box.append(head, chooseEl, bodyEl, titlesBoxEl, errorEl, coverageEl, warnEl, footEl, liveEl);\n return box;\n }\n\n function submitCustom(): void {\n const text = inputEl.value.trim();\n if (!text) { inputEl.focus(); return; }\n start('custom', text);\n }\n\n /** A first-level choice: a parameterised variant opens its picker, the rest run. */\n function choose(def: AiRewriteVariantDefinition): void {\n if (def.param) {\n openPicker(def.param === 'language' ? 'language' : 'audience');\n return;\n }\n start(def.id);\n }\n\n // ── Second-level pickers ───────────────────────────────────────────────\n\n function pickerOption(label: string, checked: boolean, onPick: () => void): HTMLButtonElement {\n const b = button('ai-rw-option', '', onPick);\n b.setAttribute('role', 'menuitemradio');\n b.setAttribute('aria-checked', checked ? 'true' : 'false');\n const mark = el('span', 'ai-rw-option-check');\n mark.innerHTML = CHECK;\n b.append(mark, el('span', 'ai-rw-option-label', label));\n return b;\n }\n\n function pickerSeparator(): HTMLElement {\n const sep = el('div', 'ai-rw-option-sep');\n sep.setAttribute('role', 'separator');\n return sep;\n }\n\n function renderPicker(): void {\n if (!picker) { pickerEl.replaceChildren(); return; }\n const head = el('div', 'ai-rw-picker-head');\n const back = button('ai-rw-icon-btn ai-rw-back', '', () => closePicker());\n back.innerHTML = BACK;\n back.setAttribute('aria-label', 'Back (Esc)');\n back.title = 'Back (Esc)';\n back.hidden = docOnly;\n head.append(back, el('span', 'ai-rw-picker-title', picker === 'language' ? 'Translate to' : 'Reading level'));\n\n const list = el('div', 'ai-rw-picker-list');\n list.setAttribute('role', 'menu');\n list.setAttribute('aria-label', picker === 'language' ? 'Language' : 'Audience');\n const parts: HTMLElement[] = [head, list];\n\n if (picker === 'language') {\n const { recents, languages } = translateLanguageChoices();\n // The last language used is the default: checked and focused.\n recents.forEach((lang, i) => list.append(pickerOption(lang, i === 0, () => pickLanguage(lang))));\n if (recents.length) {list.append(pickerSeparator());}\n for (const lang of languages) {list.append(pickerOption(lang, false, () => pickLanguage(lang)));}\n list.append(pickerSeparator());\n const otherForm = el('form', 'ai-rw-form ai-rw-other');\n otherForm.hidden = true;\n const otherInput = el('input', 'ai-rw-input');\n otherInput.type = 'text';\n otherInput.placeholder = 'Language, e.g. Swahili';\n otherInput.setAttribute('aria-label', 'Other language');\n otherInput.maxLength = 60;\n otherForm.append(otherInput, button('ai-rw-btn ai-rw-btn--primary', 'Translate', () => pickLanguage(otherInput.value)));\n otherForm.addEventListener('submit', (e) => { e.preventDefault(); pickLanguage(otherInput.value); });\n const other = button('ai-rw-option ai-rw-option--other', '', () => {\n otherForm.hidden = false;\n other.setAttribute('aria-expanded', 'true');\n otherInput.focus();\n position();\n });\n other.setAttribute('role', 'menuitem');\n other.setAttribute('aria-expanded', 'false');\n other.append(el('span', 'ai-rw-option-check'), el('span', 'ai-rw-option-label', 'Other…'));\n list.append(other);\n parts.push(otherForm);\n\n if (docOnly || deps.documentTarget) {\n const toggle = el('label', 'ai-rw-toggle');\n const box = el('input');\n box.type = 'checkbox';\n box.checked = wholeDocument;\n box.disabled = docOnly;\n box.addEventListener('change', () => { wholeDocument = box.checked; });\n toggle.append(box, el('span', '', 'Whole document'));\n toggle.title = docOnly ? 'Nothing is selected, so the whole document is translated.' : 'Translate the whole document instead of the selection (frontmatter is kept).';\n const foot = el('div', 'ai-rw-picker-foot');\n foot.append(toggle);\n parts.push(foot);\n }\n } else {\n const remembered = loadAudience();\n for (const a of AI_AUDIENCES) {list.append(pickerOption(a.label, a.id === remembered, () => pickAudience(a.id)));}\n }\n pickerEl.replaceChildren(...parts);\n }\n\n function openPicker(kind: Picker): void {\n picker = kind;\n variant = kind === 'language' ? 'translate' : 'readingLevel';\n phase = 'choose';\n renderPicker();\n render();\n position();\n const items = [...pickerEl.querySelectorAll<HTMLButtonElement>('.ai-rw-picker-list > button')];\n (items.find((b) => b.getAttribute('aria-checked') === 'true') ?? items[0])?.focus({ preventScroll: true });\n }\n\n function closePicker(): void {\n if (docOnly) { close(); return; }\n const was = variant;\n picker = null;\n renderPicker();\n render();\n position();\n menuEl.querySelector<HTMLButtonElement>(`.ai-rw-chip[data-variant=\"${was}\"]`)?.focus({ preventScroll: true });\n }\n\n function pickLanguage(language: string): void {\n const lang = language.replace(/\\s+/g, ' ').trim();\n if (!lang) {\n pickerEl.querySelector<HTMLInputElement>('.ai-rw-other .ai-rw-input')?.focus();\n return;\n }\n params = { language: lang };\n if (wholeDocument && !useDocumentTarget()) {return;}\n start('translate');\n }\n\n function pickAudience(audience: AiAudience): void {\n params = { audience };\n start('readingLevel');\n }\n\n /** Swap the selection target for the whole body. False when there is no body to translate. */\n function useDocumentTarget(): boolean {\n if (!target) {return false;}\n if (target.scope === 'document') {return true;}\n const doc = deps.documentTarget?.() ?? null;\n if (!doc) {return false;}\n target.release();\n target = doc;\n side = null;\n return true;\n }\n\n // ── Rendering ──────────────────────────────────────────────────────────\n\n function headTitle(): string {\n if (job === 'summary') {return summaryJob?.kind === 'outline' ? 'Outline' : 'Summary';}\n if (job === 'titles') {return 'Suggest titles';}\n if (unavailable) {return 'Rewrite';}\n if (phase === 'choose') {return picker === 'language' ? 'Translate' : picker === 'audience' ? 'Reading level' : 'Rewrite';}\n if (variant === 'explain') {return 'Explain';}\n if (variant === 'custom') {return 'Rewrite · Custom';}\n if (variant === 'translate') {\n return `Translate · ${params.language ?? ''}${target?.scope === 'document' ? ' · Whole document' : ''}`;\n }\n if (variant === 'readingLevel') {\n return `Reading level · ${(params.audience && getAiAudience(params.audience)?.label) ?? ''}`;\n }\n return `Rewrite · ${plainLabel(getAiRewriteVariant(variant)?.label ?? '')}`;\n }\n\n /**\n * The thinking dial: a radio group with one segment per level the route's\n * kind can express, the level in effect checked. One Tab stop; a redraw\n * keeps the focus on the segment that had it.\n */\n function renderThinking(): void {\n const choices = thinking && phase !== 'choose' ? thinkingChoices(thinking.kind) : [];\n thinkEl.hidden = choices.length === 0;\n if (choices.length === 0) {return;}\n const current = thinkingSelected(thinking);\n const focused = thinkEl.contains(document.activeElement) ? (document.activeElement as HTMLElement).dataset.level : undefined;\n const label = el('span', 'ai-rw-think-label', 'Thinking');\n label.setAttribute('aria-hidden', 'true');\n // The AI menu's Thinking row: Default first (MikeDown picks per task, else the model's own setting), then the kind's levels.\n const options = [\n { level: THINKING_DEFAULT, label: 'Default', title: 'Thinking: picked for the task' },\n ...choices.map((c) => ({ level: c.level as string, label: thinkingSegmentLabel(c.label), title: `Thinking: ${c.label}` })),\n ];\n const stop = focused && options.some((o) => o.level === focused) ? focused : current;\n const segments = options.map((o) => {\n const seg = button('ai-rw-think-seg', o.label, () => pickThinking(o.level === THINKING_DEFAULT ? null : o.level as AiThinkingLevel));\n seg.dataset.level = o.level;\n seg.setAttribute('role', 'radio');\n seg.setAttribute('aria-checked', o.level === current ? 'true' : 'false');\n seg.setAttribute('aria-label', o.level === THINKING_DEFAULT ? 'Default' : choices.find((c) => c.level === o.level)?.label ?? o.label);\n seg.tabIndex = o.level === stop ? 0 : -1;\n seg.title = `${o.title} (runs again)`;\n return seg;\n });\n const effective = thinkingInEffect(thinking);\n thinkEl.title = thinking?.sent && thinking.auto\n ? `Thinking: Default, ${choices.find((c) => c.level === thinking?.sent)?.label ?? thinking.sent} for this task`\n : thinking?.sent\n ? `Thinking: ${choices.find((c) => c.level === thinking?.sent)?.label ?? thinking.sent}`\n : effective\n ? `Thinking: the model's setting (${choices.find((c) => c.level === effective)?.label ?? effective})`\n : 'Thinking: the model\\'s default';\n thinkEl.replaceChildren(label, ...segments);\n if (focused) {segments.find((b) => b.dataset.level === focused)?.focus({ preventScroll: true });}\n }\n\n function onThinkingKey(e: KeyboardEvent): void {\n if (!/^(Arrow(Left|Right|Up|Down)|Home|End)$/.test(e.key)) {return;}\n const segs = [...thinkEl.querySelectorAll<HTMLButtonElement>('.ai-rw-think-seg')];\n const at = segs.indexOf(document.activeElement as HTMLButtonElement);\n if (at < 0) {return;}\n e.preventDefault();\n e.stopPropagation();\n const forward = e.key === 'ArrowRight' || e.key === 'ArrowDown';\n const next = e.key === 'Home' ? 0 : e.key === 'End' ? segs.length - 1 : (at + (forward ? 1 : -1) + segs.length) % segs.length;\n for (const [i, b] of segs.entries()) {b.tabIndex = i === next ? 0 : -1;}\n segs[next].focus({ preventScroll: true });\n }\n\n function renderBadge(): void {\n renderThinking();\n const b = deps.badge(route, served, served ? viaFallback : route?.viaFallback ?? false, jobSends());\n badgeEl.hidden = !b;\n if (!b) {return;}\n badgeEl.dataset.where = b.where ?? '';\n badgeEl.classList.toggle('is-pending', !served);\n // Name the level that served (\"... oMLX · Qwen3 30B, on this network. Thinking: low.\").\n const level = served ? thinkingInEffect(thinking) : null;\n const levelLabel = level && thinking ? thinkingChoices(thinking.kind).find((c) => c.level === level)?.label : undefined;\n let title = b.title;\n if (b.where === 'cloud') {\n // What leaves the machine, unless the host's title already says it.\n const j = jobSends();\n const what = whatIsSent(j.feature, j.sends);\n if (!title.includes(what)) {title = `${title} ${served ? 'Sent' : 'Sends'} ${what}.`;}\n }\n badgeEl.title = levelLabel ? `${title} Thinking: ${levelLabel.toLowerCase()}.` : title;\n const glyph = el('span', 'ai-rw-badge-glyph');\n glyph.innerHTML = b.where === 'cloud' ? CLOUD : LOCAL;\n // \"local · oMLX · Qwen3 30B\": locality and engine never shrink, only the model name ellipsizes.\n const text = el('span', 'ai-rw-badge-text');\n const cut = capitalizeFirst(b.text).split(' · ');\n if (cut.length >= 3) {\n text.append(el('span', 'ai-rw-badge-engine', `${cut.slice(0, 2).join(' · ')} · `), el('span', 'ai-rw-badge-model', cut.slice(2).join(' · ')));\n } else {\n text.append(el('span', 'ai-rw-badge-engine', capitalizeFirst(b.text)));\n }\n const parts: Node[] = [glyph, text];\n if (b.fallback) {parts.push(el('span', 'ai-rw-badge-fallback', '(fallback)'));}\n badgeEl.replaceChildren(...parts);\n }\n\n /** The caret follows the last line of the preview rather than sitting under a block. */\n function placeCaret(): void {\n let host: Element = outEl;\n for (let last = host.lastElementChild; last && /^(UL|OL|LI|BLOCKQUOTE|P|DIV)$/.test(last.tagName); last = host.lastElementChild) {host = last;}\n host.append(caretEl);\n }\n\n function renderOut(): void {\n // Titles stream as JSON: only a placeholder until the list shows.\n const shown = job === 'titles' ? ''\n : job === 'summary' ? (phase === 'done' && summaryJob ? summaryPreviewText(raw, summaryJob.kind, summaryCutOff) : summaryVisibleText(raw)).trim()\n : phase === 'done' ? finalText.trim() : rewriteVisibleText(raw).trimStart();\n renderPreviewMarkdown(outEl, shown);\n placeCaret();\n newPaneEl.classList.toggle('is-waiting', phase === 'running' && !shown);\n if (phase === 'running' && !shown) {\n const name = deps.badge(route, null, false)?.text.split(' · ')[1];\n outEl.replaceChildren();\n placeCaret();\n outEl.dataset.placeholder = repairing ? REPAIR_NOTE\n : job === 'titles' && raw ? 'Suggesting titles…'\n : name ? `Waiting for ${name}…` : 'Waiting for the engine…';\n } else {\n delete outEl.dataset.placeholder;\n }\n // Follow the stream unless the reader scrolled up.\n const scroller = outEl.parentElement;\n if (scroller && phase === 'running' && scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight < 40) {\n scroller.scrollTop = scroller.scrollHeight;\n }\n }\n\n function scheduleOut(): void {\n if (frame) {return;}\n frame = requestAnimationFrame(() => { frame = 0; if (root) {renderOut();} });\n }\n\n /** Tell the host when a request starts or stops running here (once per change). */\n let busyReported = false;\n function syncBusy(): void {\n const running = !!root && phase === 'running';\n if (running === busyReported) {return;}\n busyReported = running;\n deps.onBusy?.(running);\n }\n\n function render(): void {\n syncBusy();\n if (!root || !target) {return;}\n const mode = outputMode();\n root.dataset.phase = phase;\n root.dataset.output = mode;\n // Side by side only for a multi-line selection being replaced: not for\n // Explain (nothing is replaced) nor a whole document (too long).\n root.dataset.layout = mode === 'replace' && target.multiline ? 'split' : 'single';\n root.setAttribute('aria-busy', phase === 'running' ? 'true' : 'false');\n root.setAttribute('aria-label', job === 'summary' ? 'Summarize with AI'\n : job === 'titles' ? 'Suggest titles with AI'\n : variant === 'explain' && phase !== 'choose' ? 'Explain with AI' : 'Rewrite with AI');\n titleEl.textContent = headTitle();\n // The full title on hover: a long one is cut short with an ellipsis.\n if (variant === 'custom' && instruction && phase !== 'choose') {titleEl.title = instruction;} else {titleEl.title = titleEl.textContent;}\n chooseEl.hidden = phase !== 'choose';\n menuEl.hidden = !!picker;\n formEl.hidden = !!picker;\n pickerEl.hidden = !picker;\n bodyEl.hidden = phase === 'choose' || phase === 'error' || (mode === 'choose' && phase === 'done');\n titlesBoxEl.hidden = !(mode === 'choose' && phase === 'done');\n kindEl.hidden = job !== 'summary';\n for (const seg of kindEl.querySelectorAll<HTMLElement>('.ai-rw-kind-seg')) {\n seg.setAttribute('aria-pressed', seg.dataset.kind === summaryJob?.kind ? 'true' : 'false');\n }\n errorEl.hidden = phase !== 'error';\n footEl.hidden = phase === 'choose' || phase === 'error';\n newLabelEl.textContent = mode === 'readOnly' ? 'Explanation' : variant === 'translate' ? 'Translation' : 'Rewrite';\n renderBadge();\n renderOut();\n\n const ready = phase === 'done' && !!finalText.trim();\n acceptBtn.hidden = phase === 'error' || mode === 'choose';\n acceptBtn.setAttribute('aria-disabled', ready ? 'false' : 'true');\n acceptBtn.textContent = mode === 'readOnly' ? 'Insert below'\n : mode === 'insert' ? 'Insert'\n : mode === 'replaceDocument' ? 'Replace document' : 'Accept';\n acceptBtn.title = mode === 'readOnly'\n ? 'Insert the explanation as a quote below the selection'\n : mode === 'insert' ? 'Insert at the cursor (Enter)'\n : mode === 'replaceDocument' ? 'Replace the document body; frontmatter is kept (Enter)' : 'Replace the selection (Enter)';\n copyBtn.hidden = phase === 'error' || mode === 'choose';\n copyBtn.setAttribute('aria-disabled', (phase === 'done' ? finalText : rewriteVisibleText(raw)).trim() ? 'false' : 'true');\n retryBtn.hidden = phase === 'error';\n noteEl.textContent = repairing ? REPAIR_NOTE : note;\n statsEl.hidden = !(phase === 'done' && stats);\n if (phase === 'done' && stats) {\n statsEl.textContent = aiResultStatsText(stats);\n statsEl.title = aiResultStatsTitle(stats);\n }\n\n // What part of the document was sent, when not all of it fit.\n const covered = job === 'rewrite' ? (target.scope === 'document' ? 'translate' : null) : job;\n const covText = covered && (phase === 'running' || phase === 'done') ? coverageNoteText(covered, coverage) : '';\n coverageEl.hidden = !covText;\n coverageEl.textContent = covText;\n // Esc closes; the button names it (there is no visible hint).\n const closeLabel = mode === 'readOnly' ? 'Close (Esc)' : 'Cancel (Esc)';\n closeBtn.setAttribute('aria-label', closeLabel);\n closeBtn.title = closeLabel;\n\n // The structure check, between the preview and the footer. A warning\n // only: Accept stays enabled.\n warnEl.hidden = !(phase === 'done' && warning);\n if (phase === 'done' && warning) {\n const glyph = el('span', 'ai-rw-warn-icon');\n glyph.innerHTML = WARN;\n warnEl.replaceChildren(glyph, el('span', 'ai-rw-warn-text', warning.text));\n warnEl.title = warning.title;\n }\n\n if (phase === 'error' && error) {renderError(error);}\n }\n\n /** The failing engine's name, when the error says which engine it was and the host can name it. */\n function errorEngine(e: AiError): string | null {\n return e.engineId ? deps.engineName?.(e.engineId) ?? null : null;\n }\n\n /** The copy an error shows: an override, the router's \"No engine can rewrite\", or the code's (naming the engine). */\n function copyFor(e: AiError): AiErrorCopy {\n if (unavailable) {return { title: 'No engine can rewrite right now', message: e.message, action: 'openSettings' as const };}\n const engine = errorEngine(e);\n // The model the request went to, for \"LM Studio couldn't load <model>\".\n const model = route && (!e.engineId || route.engineId === e.engineId) ? route.modelId : undefined;\n return errorCopy ?? aiErrorCopy(e.code, { ...(engine ? { engine } : {}), ...(model ? { model } : {}) });\n }\n\n function renderError(e: AiError): void {\n const copyText = copyFor(e);\n const iconEl = el('span', 'ai-rw-error-icon');\n iconEl.innerHTML = ALERT;\n const textBox = el('div', 'ai-rw-error-text');\n textBox.append(el('div', 'ai-rw-error-title', copyText.title));\n // The router's reason or the host's detail, when it says more than the generic copy.\n const detail = e.message && e.message !== copyText.message ? e.message : '';\n textBox.append(el('div', 'ai-rw-error-message', e.code === 'unknown' && detail ? detail : copyText.message));\n if (detail && e.code === 'modelLoadFailed') {\n // The server's own words are long and technical: one click away.\n const more = el('details', 'ai-rw-error-more');\n more.append(el('summary', undefined, 'Details'), el('div', 'ai-rw-error-detail', detail));\n textBox.append(more);\n } else if (detail && e.code !== 'unknown') {\n textBox.append(el('div', 'ai-rw-error-detail', detail));\n }\n if (e.code === 'contextOverflow' && target) {\n const what = target.scope === 'selection' ? 'The selection' : 'The document';\n const size = job === 'summary' ? summaryJob?.markdown.length ?? 0\n : job === 'titles' ? titleJob?.markdown.length ?? 0 : target.text.length;\n textBox.append(el('div', 'ai-rw-error-detail', `${what} is ${size.toLocaleString()} characters.`));\n }\n const actions = el('div', 'ai-rw-error-actions');\n // An engine problem opens that engine's page, by name (F9).\n const onEngine = (copyText.action === 'openEngine' || copyText.action === 'chooseModel') && !!e.engineId;\n const settingsLabel = copyText.action === 'chooseModel' ? 'Choose model' : onEngine ? `Open ${errorEngine(e) ?? 'engine'}` : 'Open AI settings';\n const primary = copyText.action === 'openSettings' || copyText.action === 'chooseModel' || onEngine;\n const settingsBtn = button(`ai-rw-btn${primary ? ' ai-rw-btn--primary' : ''}`, settingsLabel, () => {\n close({ refocus: false });\n if (onEngine) {deps.openSettings(e.engineId);} else {deps.openSettings();}\n });\n actions.append(settingsBtn);\n if (!unavailable && copyText.action !== 'shortenSelection' && e.code !== 'cloudBlocked') {\n actions.append(button(`ai-rw-btn${copyText.action === 'retry' ? ' ai-rw-btn--primary' : ''}`, e.code === 'badOutput' ? 'Try again' : 'Retry', () => rerun()));\n }\n actions.append(button('ai-rw-btn', 'Close', () => close()));\n errorEl.replaceChildren(iconEl, textBox, actions);\n }\n\n function position(): void {\n if (!root || !target) {return;}\n if (!target.alive()) { close({ refocus: false }); return; }\n const rect = target.rect();\n // Not measurable right now (scrolled out of a virtualised view): stay put.\n if (!rect) {return;}\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const gap = 8;\n const w = root.offsetWidth || 440;\n const h = root.offsetHeight || 200;\n // Pick a side once, with room for the tallest state, so streaming never flips it.\n if (!side) {\n const reserve = Math.min(vh * 0.55, 380);\n side = rect.bottom + gap + reserve <= vh - gap || rect.top - gap - reserve < gap ? 'below' : 'above';\n }\n let top = side === 'below' ? rect.bottom + gap : rect.top - gap - h;\n top = Math.max(gap, Math.min(top, vh - h - gap));\n const left = Math.max(gap, Math.min(rect.left, vw - w - gap));\n root.style.top = `${Math.round(top)}px`;\n root.style.left = `${Math.round(left)}px`;\n }\n\n /** Arrow keys, Home and End move between the chips of the first level, the picker's rows or the titles. */\n function moveFocus(e: KeyboardEvent): boolean {\n const inTitles = outputMode() === 'choose' && phase === 'done';\n if (!root || (phase !== 'choose' && !inTitles) || !/^(Arrow(Up|Down|Left|Right)|Home|End)$/.test(e.key)) {return false;}\n const selector = inTitles ? '.ai-rw-titles > button' : picker ? '.ai-rw-picker-list > button' : '.ai-rw-menu .ai-rw-chip';\n const items = [...root.querySelectorAll<HTMLButtonElement>(selector)];\n const i = items.indexOf(e.target as HTMLButtonElement);\n if (i < 0) {return false;}\n const forward = e.key === 'ArrowDown' || e.key === 'ArrowRight';\n const next = e.key === 'Home' ? 0\n : e.key === 'End' ? items.length - 1\n : (i + (forward ? 1 : -1) + items.length) % items.length;\n items[next].focus({ preventScroll: true });\n return true;\n }\n\n function mount(t: AiRewriteTarget): void {\n close({ refocus: false });\n target = t;\n side = null;\n raw = '';\n finalText = '';\n summaryCutOff = false;\n route = null;\n served = null;\n stats = null;\n viaFallback = false;\n thinking = null;\n error = null;\n unavailable = false;\n note = '';\n warning = null;\n picker = null;\n params = {};\n variant = 'shorter';\n instruction = '';\n docOnly = t.scope === 'document';\n wholeDocument = docOnly;\n job = 'rewrite';\n summaryJob = null;\n titleJob = null;\n titles = [];\n coverage = 1;\n sentText = '';\n untranslated = '';\n repairing = false;\n root = build();\n getPortal().appendChild(root);\n\n const onKey = (e: KeyboardEvent): void => {\n if (!root) {return;}\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n // Esc in a picker goes back to the first level.\n if (phase === 'choose' && picker) {closePicker();} else {close();}\n return;\n }\n if (root.contains(e.target as Node) && moveFocus(e)) {\n e.preventDefault();\n return;\n }\n // Enter accepts a replacement or inserts a summary; Explain inserts\n // only on an explicit click, and a title is picked on its own row.\n const mode = outputMode();\n if (e.key === 'Enter' && phase === 'done' && mode !== 'readOnly' && mode !== 'choose' && !e.shiftKey && !e.altKey) {\n const t2 = e.target as HTMLElement | null;\n const inField = !!t2 && (t2.tagName === 'INPUT' || t2.tagName === 'TEXTAREA');\n const onOtherButton = !!t2 && t2.tagName === 'BUTTON' && t2 !== acceptBtn && root.contains(t2);\n if ((!inField && !onOtherButton) || e.metaKey || e.ctrlKey) {\n e.preventDefault();\n e.stopPropagation();\n accept();\n }\n }\n };\n const onDown = (e: MouseEvent): void => {\n if (root && !root.contains(e.target as Node)) {close({ refocus: false });}\n };\n const onMove = (): void => position();\n document.addEventListener('keydown', onKey, true);\n document.addEventListener('mousedown', onDown, true);\n window.addEventListener('resize', onMove);\n document.addEventListener('scroll', onMove, true);\n detach.push(\n () => document.removeEventListener('keydown', onKey, true),\n () => document.removeEventListener('mousedown', onDown, true),\n () => window.removeEventListener('resize', onMove),\n () => document.removeEventListener('scroll', onMove, true),\n );\n }\n\n /** A dial change (null: Default): remembered for every later request (the AI menu's Thinking row too), then the same run again (like Retry). */\n function pickThinking(level: AiThinkingLevel | null): void {\n if (!thinking || phase === 'choose') {return;}\n if ((level ?? THINKING_DEFAULT) === thinkingSelected(thinking)) {return;}\n rememberThinkingLevel(level);\n // Checked at once; the route's answer confirms it.\n thinking = { ...thinking, sent: level, auto: false };\n const label = level ? thinkingChoices(thinking.kind).find((c) => c.level === level)?.label ?? level : 'Default';\n rerun();\n liveEl.textContent = `Thinking: ${label}`;\n }\n\n /** Run the current job again (Retry, Try again, the thinking dial). */\n function rerun(): void {\n if (job === 'summary') {startSummary();}\n else if (job === 'titles') {startTitles();}\n else {start(variant, instruction);}\n }\n\n /** The routed model's context window for `feature` (unknown: `DEFAULT_CONTEXT_TOKENS`). */\n function contextTokensFor(feature: string): number {\n return deps.routeInfo?.(feature).contextTokens ?? DEFAULT_CONTEXT_TOKENS;\n }\n\n /** Abort what runs and reset for a new request; returns its sequence number and signal. */\n function beginRun(): { seq: number; signal: AbortSignal } {\n abort();\n const ac = new AbortController();\n controller = ac;\n phase = 'running';\n raw = '';\n finalText = '';\n summaryCutOff = false;\n served = null;\n stats = null;\n error = null;\n errorCopy = null;\n note = '';\n warning = null;\n repairing = false;\n return { seq: runSeq, signal: ac.signal };\n }\n\n function runEvents(seq: number): AiRunEvents {\n return {\n onRoute: (r, th) => {\n if (seq !== runSeq) {return;}\n route = r;\n thinking = th;\n raw = '';\n renderBadge();\n renderOut();\n },\n onToken: (_delta, text) => {\n if (seq !== runSeq) {return;}\n raw = text;\n scheduleOut();\n },\n };\n }\n\n /** The feature and scope of the current job, for the privacy copy (consent, badge and chip tooltips). */\n function jobSends(): { feature: string; sends: AiSendsScope } {\n if (job === 'summary') {return { feature: 'summary', sends: 'document' };}\n if (job === 'titles') {return { feature: 'title', sends: 'document' };}\n return { feature: 'rewrite', sends: target?.scope === 'document' ? 'document' : 'selection' };\n }\n\n function noteServed(outcome: AiRunOutcome): void {\n // The feature rides along so the sidebar chip can say what the last request sent.\n const by: AiServedRequest = { ...outcome.result.served, ...jobSends() };\n served = by;\n stats = aiResultStats(outcome.result);\n viaFallback = outcome.viaFallback;\n thinking = outcome.thinking;\n deps.onServed(by, outcome.viaFallback);\n }\n\n function finishNote(outcome: AiRunOutcome): string {\n const reason = outcome.result.finishReason;\n if (reason === 'length') {return aiLengthLimitCopy({ thinking: aiRunThinkingOn(outcome.thinking), empty: false }).message;}\n return reason === 'error' ? 'The stream ended early.' : '';\n }\n\n /** An answer with no text that stopped at the length limit: the error says why. */\n function showLengthError(outcome: AiRunOutcome): void {\n const copy = aiLengthLimitCopy({ thinking: aiRunThinkingOn(outcome.thinking), empty: true });\n errorCopy = copy;\n showError(makeAiError('badOutput', copy.message));\n }\n\n function showError(e: AiError): void {\n phase = 'error';\n error = e;\n repairing = false;\n render();\n position();\n liveEl.textContent = `${copyFor(e).title}.`;\n errorEl.querySelector<HTMLButtonElement>('.ai-rw-btn--primary, .ai-rw-btn')?.focus({ preventScroll: true });\n }\n\n function runFailed(seq: number): (err: unknown) => void {\n return (err) => {\n if (seq !== runSeq || !root) {return;}\n controller = null;\n const e = toAiError(err);\n if (e.code === 'cancelled') {return;}\n showError(e);\n };\n }\n\n // ── Document jobs ──────────────────────────────────────────────────────\n\n function pickKind(kind: AiSummaryKind): void {\n if (!summaryJob || summaryJob.kind === kind) {return;}\n summaryJob.kind = kind;\n startSummary();\n }\n\n /** `/summary`, `/outline`: budget the body, stream the summary, Insert when done. Never retried (D16). */\n function startSummary(): void {\n const t = target;\n const sj = summaryJob;\n if (!t || !root || !sj) {return;}\n const { seq, signal } = beginRun();\n const kind = sj.kind;\n const b = budgetDocument(sj.markdown, {\n contextTokens: contextTokensFor('summary'),\n outputTokens: summaryMaxTokens(kind, sj.markdown.length),\n reserveTokens: DOCUMENT_RESERVE_TOKENS,\n });\n coverage = b.coverage;\n render();\n position();\n root.focus({ preventScroll: true });\n deps.run({\n feature: 'summary',\n messages: buildSummaryMessages({ document: b.text, kind, coverage: b.coverage }),\n maxTokens: summaryMaxTokens(kind, b.text.length),\n temperature: 0.3,\n thinking: thinkingLevelFor,\n job: 'summary',\n }, runEvents(seq), signal).then((outcome) => {\n if (seq !== runSeq || !root) {return;}\n controller = null;\n noteServed(outcome);\n raw = outcome.result.text || raw;\n const cutOff = outcome.result.finishReason === 'length';\n summaryCutOff = cutOff;\n finalText = finalizeSummary(raw, kind, coverage, cutOff);\n if (!finalText.trim()) {\n if (cutOff) {showLengthError(outcome);} else {showError(makeAiError('badOutput'));}\n return;\n }\n phase = 'done';\n note = finishNote(outcome);\n render();\n position();\n liveEl.textContent = `${kind === 'outline' ? 'Outline' : 'Summary'} ready. Press Enter to insert or Escape to cancel.`;\n acceptBtn.focus({ preventScroll: true });\n }, runFailed(seq));\n }\n\n /** `/title`: budget the body (plus every heading), ask for three titles, one JSON repair round trip. */\n function startTitles(): void {\n const t = target;\n const tj = titleJob;\n if (!t || !root || !tj) {return;}\n const { seq, signal } = beginRun();\n titles = [];\n const info = deps.routeInfo?.('title');\n const outline = headingsOutline(tj.markdown);\n const b = budgetDocument(tj.markdown, {\n contextTokens: info?.contextTokens ?? DEFAULT_CONTEXT_TOKENS,\n outputTokens: titleMaxTokens(3),\n reserveTokens: DOCUMENT_RESERVE_TOKENS + Math.ceil(renderHeadingOutline(outline).length / CHARS_PER_TOKEN),\n });\n coverage = b.coverage;\n render();\n position();\n root.focus({ preventScroll: true });\n const messages = buildTitleMessages({ document: b.text, outline, existingTitle: tj.existingTitle, count: 3 });\n const request = (msgs: AiMessage[]): Promise<AiRunOutcome> => deps.run({\n feature: 'title',\n messages: msgs,\n maxTokens: titleMaxTokens(3),\n temperature: 0.7,\n thinking: thinkingLevelFor,\n job: 'title',\n ...(info?.json ? { format: 'json' as const } : {}),\n }, runEvents(seq), signal);\n request(messages).then(async (first) => {\n if (seq !== runSeq || !root) {return;}\n noteServed(first);\n const firstText = first.result.text || raw;\n // Nothing to repair: the model ran out of room before it answered.\n if (!rewriteVisibleText(firstText).trim() && first.result.finishReason === 'length') {\n controller = null;\n showLengthError(first);\n return;\n }\n let last = first;\n let parsed = parseTitles(firstText, tj.existingTitle);\n if (!parsed.ok) {\n // D16: one repair round trip, abortable like the first request.\n repairing = true;\n render();\n const second = await request([...messages, ...jsonRepairMessages(firstText, parsed.error)]);\n if (seq !== runSeq || !root) {return;}\n noteServed(second);\n repairing = false;\n last = second;\n parsed = parseTitles(second.result.text || raw, tj.existingTitle);\n if (!parsed.ok) {\n if (second.result.finishReason === 'length') {\n controller = null;\n showLengthError(second);\n return;\n }\n throw makeAiError('badOutput', parsed.error);\n }\n }\n controller = null;\n titles = parsed.titles.slice(0, 3);\n phase = 'done';\n note = finishNote(last);\n renderTitles();\n render();\n position();\n liveEl.textContent = `${titles.length} ${titles.length === 1 ? 'title' : 'titles'} ready. ${AI_TITLE_EFFECT_HINTS[tj.effect]}. Escape cancels.`;\n titlesEl.querySelector<HTMLButtonElement>('button')?.focus({ preventScroll: true });\n }).catch(runFailed(seq));\n }\n\n function renderTitles(): void {\n titlesEl.replaceChildren(...titles.map((title) => {\n const b = button('ai-rw-option ai-rw-title-option', '', () => pickTitle(title));\n b.setAttribute('role', 'menuitem');\n b.append(el('span', 'ai-rw-option-label', title));\n return b;\n }));\n titleHintEl.textContent = titleJob ? AI_TITLE_EFFECT_HINTS[titleJob.effect] : '';\n }\n\n function pickTitle(title: string): void {\n const t = target;\n const tj = titleJob;\n if (!t || !tj || phase !== 'done') {return;}\n const ok = tj.apply(title);\n close({ refocus: true });\n if (!ok) {t.focus();}\n }\n\n function start(v: AiRewriteVariant, custom?: string): void {\n const t = target;\n if (!t || !root) {return;}\n const { seq, signal } = beginRun();\n variant = v;\n instruction = v === 'custom' ? (custom ?? instruction) : '';\n picker = null;\n oldTextEl.textContent = t.scope === 'document' ? '' : t.text.trim();\n const def = getAiRewriteVariant(v);\n if (def?.param === 'language' && params.language) {rememberLanguage(params.language);}\n if (def?.param === 'audience' && params.audience) {rememberAudience(params.audience);}\n const readOnly = def?.output === 'readOnly';\n\n // A whole document is fitted to the routed model's context: the part\n // that fits is translated, the rest is kept as it is (coverage note).\n sentText = t.text;\n untranslated = '';\n coverage = 1;\n let maxTokens = readOnly ? explainMaxTokens() : rewriteMaxTokens(t.text, v);\n if (t.scope === 'document' && !readOnly) {\n const b = budgetTranslation(t.text, contextTokensFor('rewrite'));\n sentText = b.text;\n untranslated = b.rest;\n coverage = b.coverage;\n maxTokens = b.maxTokens;\n }\n render();\n position();\n root.focus({ preventScroll: true });\n\n const messages = readOnly\n ? buildExplainMessages({ selection: t.text, before: t.before, after: t.after, title: t.title })\n : buildRewriteMessages({\n variant: v,\n instruction,\n selection: sentText,\n before: t.before,\n after: t.after,\n params: def?.param ? params : undefined,\n scope: t.scope === 'document' ? 'document' : 'selection',\n });\n deps.run({\n feature: 'rewrite',\n ...(t.scope === 'document' ? { sends: 'document' as const } : {}),\n messages,\n maxTokens,\n temperature: v === 'fixFlow' || v === 'translate' ? 0.2 : 0.5,\n thinking: thinkingLevelFor,\n // Explain keeps the model's own thinking; every other variant is a short edit (Off).\n job: readOnly ? 'explain' : v === 'translate' ? 'translate' : 'rewrite',\n }, runEvents(seq), signal).then((outcome) => {\n if (seq !== runSeq || !root) {return;}\n controller = null;\n noteServed(outcome);\n // Explain is a note, not a version of the selection: no whitespace to carry over.\n finalText = finalizeRewriteText(outcome.result.text || raw, readOnly ? '' : sentText);\n if (!finalText.trim()) {\n phase = 'error';\n if (outcome.result.finishReason === 'length') {\n errorCopy = aiLengthLimitCopy({ thinking: aiRunThinkingOn(outcome.thinking), empty: true });\n error = makeAiError('badOutput', errorCopy.message);\n } else {\n error = { code: 'unknown', message: 'The engine sent back no text.' };\n }\n } else {\n phase = 'done';\n note = finishNote(outcome);\n if (STRUCTURE_CHECKED.has(v)) {\n const diff = checkMarkdownStructure(sentText, finalText);\n const text = structureWarningText(diff);\n warning = text ? { text, title: diff.messages.join('\\n') } : null;\n }\n }\n render();\n position();\n liveEl.textContent = phase !== 'done' ? 'Rewrite failed.'\n : readOnly ? 'Explanation ready. Insert below adds it to the document; Escape closes.'\n : `${variant === 'translate' ? 'Translation' : 'Rewrite'} ready. Press Enter to accept or Escape to cancel.${warning ? ` ${warning.text}.` : ''}`;\n if (phase === 'done') {\n // Explain leaves the keyboard on the popover so Enter cannot insert by accident.\n (readOnly ? root : acceptBtn).focus({ preventScroll: true });\n }\n }, runFailed(seq));\n }\n\n function accept(): void {\n const t = target;\n const mode = outputMode();\n if (!t || phase !== 'done' || !finalText.trim() || mode === 'choose') {return;}\n const ok = mode === 'readOnly' ? t.insertBelow(finalText)\n // A translation cut to fit keeps the untranslated rest after it.\n : mode === 'replaceDocument' && untranslated.trim() ? t.accept(`${finalText.trimEnd()}\\n\\n${untranslated.trimStart()}`)\n : t.accept(finalText);\n close({ refocus: true });\n if (!ok) {t.focus();}\n }\n\n function copy(): void {\n const text = (phase === 'done' ? finalText : rewriteVisibleText(raw)).trim();\n if (!text) {return;}\n void navigator.clipboard?.writeText(text).then(() => {\n if (!root) {return;}\n copyBtn.textContent = 'Copied';\n window.clearTimeout(copiedTimer);\n copiedTimer = window.setTimeout(() => { copyBtn.textContent = 'Copy'; }, 1200);\n }, () => { /* clipboard refused */ });\n }\n\n return {\n open(t, choice) {\n mount(t);\n params = { ...choice?.params };\n wholeDocument = docOnly || !!choice?.wholeDocument;\n const def = choice ? getAiRewriteVariant(choice.variant) : undefined;\n // The document itself (nothing selected) can only be translated.\n if (docOnly && (!def || def.id !== 'translate' || !hasParam(def, params))) {\n openPicker('language');\n return;\n }\n if (def && def.param && !hasParam(def, params)) {\n openPicker(def.param === 'language' ? 'language' : 'audience');\n return;\n }\n if (def && (def.id !== 'custom' || choice?.instruction?.trim())) {\n if (def.id === 'translate' && wholeDocument && !useDocumentTarget()) {\n wholeDocument = false;\n openPicker('language');\n return;\n }\n start(def.id, choice?.instruction);\n return;\n }\n phase = 'choose';\n render();\n position();\n inputEl.focus({ preventScroll: true });\n },\n openSummary(t, sj) {\n mount(t);\n job = 'summary';\n summaryJob = { ...sj };\n startSummary();\n },\n openTitles(t, tj) {\n mount(t);\n job = 'titles';\n titleJob = tj;\n startTitles();\n },\n openUnavailable(t, reason) {\n mount(t);\n phase = 'error';\n error = { code: 'unknown', message: reason };\n unavailable = true;\n render();\n position();\n errorEl.querySelector<HTMLButtonElement>('.ai-rw-btn')?.focus({ preventScroll: true });\n },\n close: () => close(),\n isOpen: () => !!target,\n destroy() {\n close({ refocus: false });\n },\n };\n}\n","/**\n * Insert at cursor's security boundary (S8). Model text is untrusted, and a\n * hostile page can steer it, so a live image or foreign link in the document is\n * a way to send section text to a server. `sanitizeInsertMarkdown` is only a\n * first pass, because a string-level pass approximates CommonMark and every\n * disagreement with markdown-it lets markup through. This module judges what the\n * editor's own parser produced.\n *\n * Rich text: `guardInsertFragment` walks the parsed fragment against an\n * allow-list. A node or mark type not listed here is not live, including one\n * added to the editor later. A link whose URL `InsertUrlPolicy` does not allow\n * keeps its text; such an image becomes its alt text plus the URL.\n *\n * Source mode: nothing structural can be rebuilt, because text goes in as text,\n * so `guardSourceMarkdown` picks the first version of the text that is clean,\n * alone and in the document, with less and less markup left. Null means none\n * was, and the caller refuses the insert.\n *\n * Raw HTML: the editor parses with `html: false`, so a tag is text. The one\n * exception is the `<a id>` anchor rule (`htmlanchor.ts`), whose node is not on\n * the allow-list either.\n */\n\nimport { Fragment, type Mark, type Node as PmNode } from '@tiptap/pm/model';\nimport { insertUrlIsVerbatim, type InsertUrlPolicy } from './ai';\n\n/**\n * Nodes that carry no URL of their own (their children are walked). Math renders\n * with KaTeX's `trust: false` and Mermaid with `securityLevel: 'strict'`, so a\n * code block or formula cannot fetch or link. Not here on purpose: `image`\n * (judged below), `wikilink`, `tableOfContents` (it saves its raw markdown body\n * verbatim) and `htmlAnchor`.\n */\nconst INERT_NODES: ReadonlySet<string> = new Set([\n 'blockquote', 'bulletList', 'callout', 'codeBlock', 'emoji', 'footnoteDef', 'footnoteRef', 'hardBreak', 'heading', 'horizontalRule',\n 'listItem', 'mathBlock', 'mathInline', 'orderedList', 'paragraph', 'table', 'tableCell', 'tableHeader', 'tableRow', 'taskItem', 'taskList', 'text',\n]);\n\n/** Marks that carry no URL. `link` is judged below. */\nconst INERT_MARKS: ReadonlySet<string> = new Set(['bold', 'code', 'highlight', 'italic', 'strike', 'underline']);\n\n/** The part of markdown-it the guard uses. */\nexport interface InsertGuardParser {\n normalizeLink(url: string): string;\n normalizeLinkText(url: string): string;\n parse(src: string, env: { references?: Record<string, { href?: string }> }): MarkdownToken[];\n}\n\ninterface MarkdownToken {\n type: string;\n attrGet(name: string): string | null;\n children: MarkdownToken[] | null;\n}\n\nexport interface InsertUrlCheck {\n link(href: string): boolean;\n image(src: string): boolean;\n}\n\n/**\n * `policy` as predicates on URLs as the parser leaves them. markdown-it\n * normalizes a destination (`é` to `%C3%A9`, a host to punycode), so a citation\n * href is compared normalized and a cited section's text, which has the URL as\n * written, is also tried against the readable form.\n */\nexport function insertUrlCheck(policy: InsertUrlPolicy, md: InsertGuardParser | undefined): InsertUrlCheck {\n const citations = new Set(md ? policy.citationHrefs.map((h) => md.normalizeLink(h)) : policy.citationHrefs);\n const verbatim = (url: string, kind: 'link' | 'image'): boolean =>\n insertUrlIsVerbatim(policy, url, kind) || (!!md && insertUrlIsVerbatim(policy, md.normalizeLinkText(url), kind));\n return {\n link: (href) => citations.has(href) || verbatim(href, 'link'),\n image: (src) => verbatim(src, 'image'),\n };\n}\n\n/** Text standing in for a node that is not live. */\nfunction plainText(node: PmNode): string {\n if (node.type.name === 'image') {return [node.attrs.alt, node.attrs.src].filter(Boolean).join(' ');}\n const attrs = node.attrs as { alias?: unknown; target?: unknown; body?: unknown };\n return (node.textContent || String(attrs.alias ?? attrs.target ?? attrs.body ?? '')).replace(/\\s+/g, ' ').trim();\n}\n\nexport interface GuardedFragment {\n fragment: Fragment;\n /** What did not stay live: URLs, and `node:` or `mark:` entries for types off the allow-list. Empty means `fragment` is the input. */\n dropped: string[];\n}\n\nclass InvalidContent extends Error {}\n\n/** The fragment with everything not allowed made plain. Null when the result would not fit the schema (never expected; refuse rather than guess). */\nexport function guardInsertFragment(fragment: Fragment, check: InsertUrlCheck): GuardedFragment | null {\n const dropped: string[] = [];\n\n const keepMarks = (marks: readonly Mark[]): readonly Mark[] => {\n const kept = marks.filter((mark) => {\n if (INERT_MARKS.has(mark.type.name)) {return true;}\n if (mark.type.name === 'link') {\n const href = String(mark.attrs.href ?? '');\n if (check.link(href)) {return true;}\n dropped.push(href);\n return false;\n }\n dropped.push(`mark:${mark.type.name}`);\n return false;\n });\n return kept.length === marks.length ? marks : kept;\n };\n\n const asPlain = (node: PmNode, marks: readonly Mark[]): PmNode[] => {\n const { schema } = node.type;\n const text = plainText(node);\n if (node.isInline) {return text ? [schema.text(text, marks)] : [];}\n return text ? [schema.nodes.paragraph.create(null, schema.text(text))] : [];\n };\n\n const walkNode = (node: PmNode): PmNode[] => {\n const name = node.type.name;\n const marks = keepMarks(node.marks);\n if (name === 'image') {\n const src = String(node.attrs.src ?? '');\n if (check.image(src)) {return [marks === node.marks ? node : node.mark(marks)];}\n dropped.push(src);\n return asPlain(node, marks);\n }\n if (!INERT_NODES.has(name)) {\n dropped.push(`node:${name}:${JSON.stringify(node.attrs)}`);\n return asPlain(node, marks);\n }\n if (node.isText) {return [marks === node.marks ? node : node.mark(marks)];}\n const kids = walkFragment(node.content);\n if (kids !== node.content && !node.type.validContent(kids)) {throw new InvalidContent();}\n if (kids === node.content && marks === node.marks) {return [node];}\n return [node.type.create(node.attrs, kids, marks)];\n };\n\n const walkFragment = (content: Fragment): Fragment => {\n const out: PmNode[] = [];\n let same = true;\n content.forEach((child) => {\n const next = walkNode(child);\n if (next.length !== 1 || next[0] !== child) {same = false;}\n out.push(...next);\n });\n return same ? content : Fragment.fromArray(out);\n };\n\n try {\n return { fragment: walkFragment(fragment), dropped };\n } catch (err) {\n if (err instanceof InvalidContent) {return null;}\n throw err;\n }\n}\n\n// ── Source mode ─────────────────────────────────────────────────────────────\n\nexport interface SourceInspector {\n check: InsertUrlCheck;\n /** The text parsed as the rich editor would parse it. */\n fragment(markdown: string): Fragment;\n md: InsertGuardParser | undefined;\n}\n\n/** Everything in `markdown` that would not be allowed: nodes and marks, then tokens and reference definitions, which leave no node. Null when there is no parser to ask. */\nfunction offenders(markdown: string, inspector: SourceInspector): Set<string> | null {\n const { check, md } = inspector;\n if (!md) {return null;}\n const guarded = guardInsertFragment(inspector.fragment(markdown), check);\n if (!guarded) {return null;}\n const found = new Set(guarded.dropped);\n const env: { references?: Record<string, { href?: string }> } = {};\n const visit = (tokens: MarkdownToken[]): void => {\n for (const token of tokens) {\n if (token.type === 'link_open') {\n const href = token.attrGet('href') ?? '';\n if (!check.link(href)) {found.add(href);}\n } else if (token.type === 'image') {\n const src = token.attrGet('src') ?? '';\n if (!check.image(src)) {found.add(src);}\n }\n if (token.children) {visit(token.children);}\n }\n };\n visit(md.parse(markdown, env));\n for (const def of Object.values(env.references ?? {})) {\n const href = def.href ?? '';\n if (!check.link(href) && !check.image(href)) {found.add(href);}\n }\n return found;\n}\n\n/** `\\` first in the class, so an escape already in the text cannot cancel the one added here (`\\[` must not become `\\\\[`). */\nfunction escapeLinkSyntax(text: string): string {\n return text.replace(/[\\\\[\\]!<`]/g, '\\\\$&');\n}\n\n/** Every ASCII punctuation character escaped: CommonMark gives each its literal meaning. */\nfunction escapeAllPunctuation(text: string): string {\n return text.replace(/[!-/:-@[-`{-~]/g, '\\\\$&');\n}\n\n/** Escape only the blank-line separated parts that are not clean by themselves. */\nfunction escapeAffectedParts(markdown: string, clean: (text: string) => boolean): string {\n return markdown.split(/(\\n[ \\t]*\\n)/).map((part, i) => (i % 2 === 1 || clean(part) ? part : escapeLinkSyntax(part))).join('');\n}\n\n/**\n * The text to insert: as given when clean, else with only the affected parts\n * escaped, then all of it, then all punctuation. `placed` gives the document\n * body before and after an insert: text can parse differently there (an opening\n * fence closes one the caret sits in, an indented line joins a list item), so\n * every candidate is also judged in place, against what the body already holds.\n */\nexport function guardSourceMarkdown(markdown: string, inspector: SourceInspector, placed?: (text: string) => { before: string; after: string }): string | null {\n const cleanAlone = (text: string): boolean => offenders(text, inspector)?.size === 0;\n let existing: Set<string> | null = null;\n const cleanInPlace = (text: string): boolean => {\n if (!placed) {return true;}\n const { before, after } = placed(text);\n existing ??= offenders(before, inspector);\n const now = offenders(after, inspector);\n if (!existing || !now) {return false;}\n for (const url of now) {if (!existing.has(url)) {return false;}}\n return true;\n };\n const candidates: Array<() => string> = [\n () => markdown,\n () => escapeAffectedParts(markdown, cleanAlone),\n () => escapeLinkSyntax(markdown),\n () => escapeAllPunctuation(markdown),\n ];\n for (const candidate of candidates) {\n const text = candidate();\n if (cleanAlone(text) && cleanInPlace(text)) {return text;}\n }\n return null;\n}\n"],"mappings":"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","names":["icon","routeLabel","promptTokens","rows","activityRoute","CONFIRM_MS","plural","pad","inlineStatus","icon","Fragment","closeHistory","Fragment","el","from","to","closeHistory","$to","changes","button","THINKING_DEFAULT","note","el","button","position","copy"]}
|