@wenathlan/extension 1.1.39 → 1.1.40

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../policy.ts", "../tabscommand.ts", "../pageforms.ts", "../datacommand.ts", "../sidepanel.ts"],
4
- "sourcesContent": ["import type { actionkind, agentplan, agentsession, cleanuprule, downloadspec, endpointconfig, fieldkind, formprofile, mimefilter, observationmode, policyevaluation, quarantineentry, runsettings, safetyverdict, toolstep, transformrule } from \"./types.js\";\n\nconst sensitiveactions = new Set<actionkind>([\"click\", \"type\", \"navigate\", \"select\", \"presskey\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"reload\", \"back\", \"forward\", \"writestorage\", \"setattribute\", \"removeattribute\", \"evaluate\", \"tabcreate\", \"tabactivate\", \"tabclose\", \"tabreload\", \"windowcreate\", \"windowclose\", \"windowresize\", \"downloadfile\", \"clickpoint\", \"shiftclick\", \"dismissdialog\", \"enterframe\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"keyhold\", \"keyrelease\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"openlink\", \"openprivate\", \"reloadcache\", \"stopnav\", \"followlink\", \"spanav\", \"rewritequery\", \"setfragment\", \"navlist\", \"navprofile\", \"handleauth\", \"printpdf\", \"prefetch\", \"preconnect\", \"deeplink\", \"reopentab\", \"pausenav\", \"navrate\", \"openclipboard\", \"batchopen\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"restorelayout\", \"reopenrun\", \"badgetab\", \"fillform\", \"filllabel\", \"fillplaceholder\", \"submitform\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcard\", \"fillcode\", \"consentpassword\", \"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"streamdisk\", \"paginateextract\", \"resumeextract\", \"batchdownload\", \"pausedownload\", \"resumedownload\", \"interceptmime\", \"readclipboard\", \"writeclipboard\", \"copyscreen\", \"quarantinedownload\", \"scanvirus\", \"cleanupartifacts\"]);\nconst interactionactions = new Set<actionkind>([\"focus\", \"scroll\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"scrollpage\", \"scrollby\", \"scrollend\", \"scrolltop\", \"fullscreen\", \"zoomset\", \"movepointer\", \"clicktext\", \"clickaria\", \"clickname\", \"expanddetails\", \"pierceshadow\", \"retryaction\"]);\nconst readactions = new Set<actionkind>([\"observe\", \"inspect\", \"extract\", \"wait\", \"waitfor\", \"waittext\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"readlinks\", \"readimages\", \"readmeta\", \"readforms\", \"readstorage\", \"highlight\", \"tablist\", \"windowlist\", \"tabsnapshot\", \"mapclicks\", \"verifyvisible\", \"verifyenabled\", \"resolvexpath\", \"a11ytree\", \"readvisible\", \"readertree\", \"detectlists\", \"detecttables\", \"readjson\", \"watchmutate\", \"waitquiet\", \"watchbanner\", \"detectinfinitescroll\", \"detectvirtual\", \"detectlazy\", \"readscrollpos\", \"readlang\", \"readoutline\", \"countpages\", \"listshadow\", \"listframes\", \"classifypage\", \"fingerprintsection\", \"diffsnapshots\", \"readselection\", \"watchfocus\", \"detectsticky\", \"detectscrolllock\", \"readopengraph\", \"detectlanguage\", \"deriveselector\", \"waitload\", \"waiturl\", \"spawait\", \"detecthttp\", \"readredirects\", \"readfinalurl\", \"trailaudit\", \"navintent\", \"checksafe\", \"querytabs\", \"watchtab\", \"findclones\", \"searchtabs\", \"listaudio\", \"snapshotsession\", \"savelayout\", \"attachmeta\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"readerrors\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\", \"handoffcaptcha\", \"scrapetable\", \"importcsv\", \"looprows\", \"transformvalues\", \"deduperows\", \"mergepages\", \"stamplerows\", \"previewgrid\", \"logprovenance\", \"verifydownload\", \"exportnetlog\", \"namecaptures\"]);\nconst allowedactions = new Set<actionkind>([...sensitiveactions, ...interactionactions, ...readactions]);\nconst watchactions = new Set<actionkind>([\"watchmutate\", \"watchbanner\", \"watchfocus\", \"watchtab\"]);\nconst targetactions = new Set<actionkind>([\"inspect\", \"focus\", \"click\", \"type\", \"scroll\", \"select\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"highlight\", \"setattribute\", \"removeattribute\", \"waitfor\", \"shiftclick\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\", \"verifyvisible\", \"verifyenabled\", \"pierceshadow\", \"deriveselector\", \"fingerprintsection\", \"submitform\", \"retryform\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\", \"scrapetable\", \"paginateextract\"]);\nconst valueactions = new Set<actionkind>([\"presskey\", \"drag\", \"drop\", \"upload\", \"readattribute\", \"removeattribute\", \"waittext\", \"evaluate\", \"zoomset\", \"tabactivate\", \"tabclose\", \"tabreload\", \"windowclose\", \"windowresize\", \"tabcreate\", \"windowcreate\", \"downloadfile\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"keyhold\", \"keyrelease\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"followlink\", \"setfragment\", \"handleauth\", \"navintent\", \"openclipboard\", \"checksafe\", \"reopentab\", \"spanav\", \"duplicatetab\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"focuswindow\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"incognitowindow\", \"asksubmit\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\", \"pausedownload\", \"resumedownload\", \"verifydownload\", \"writeclipboard\", \"quarantinedownload\", \"scanvirus\"]);\nconst tabscommandactions = new Set<actionkind>([\"querytabs\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"watchtab\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"savelayout\", \"restorelayout\", \"findclones\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"listaudio\", \"reopenrun\", \"snapshotsession\"]);\nconst formactions = new Set<actionkind>([\"fillform\", \"filllabel\", \"fillplaceholder\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"submitform\", \"readerrors\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"handoffcaptcha\", \"fillcard\", \"fillcode\", \"consentpassword\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\"]);\n/** Extraction, transform, export and provenance kinds of the forms and data part two family. */\nconst datasetactions = new Set<actionkind>([\"scrapetable\", \"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"importcsv\", \"looprows\", \"transformvalues\", \"deduperows\", \"paginateextract\", \"mergepages\", \"stamplerows\", \"previewgrid\", \"streamdisk\", \"resumeextract\", \"logprovenance\"]);\n/** Export kinds that move extracted data out of local memory to disk, the clipboard or a reviewed sheet endpoint. */\nconst exportactions = new Set<actionkind>([\"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"streamdisk\"]);\n/** Files, clipboard and downloads kinds of the batch queue, interception, clipboard, quarantine, naming and cleanup family. */\nconst filesactions = new Set<actionkind>([\"batchdownload\", \"pausedownload\", \"resumedownload\", \"verifydownload\", \"interceptmime\", \"exportnetlog\", \"readclipboard\", \"writeclipboard\", \"copyscreen\", \"quarantinedownload\", \"scanvirus\", \"namecaptures\", \"cleanupartifacts\"]);\n/** Field kinds the form grammar accepts inside records, profiles and value rules. */\nconst fieldkinds: fieldkind[] = [\"text\", \"email\", \"phone\", \"date\", \"number\", \"select\", \"check\", \"radio\", \"file\", \"password\", \"card\", \"code\"];\nconst layoutmutationactions = new Set<actionkind>([\"grouptabs\", \"colorgroup\", \"collapsegroup\", \"savelayout\", \"restorelayout\"]);\n/** Chromium tab group colors accepted as reviewed group color choices. */\nconst groupcolors = [\"grey\", \"blue\", \"red\", \"yellow\", \"green\", \"pink\", \"purple\", \"cyan\", \"orange\"];\n\n/** Normalizes a user supplied HTTPS endpoint without preserving a provider lock-in. */\nexport function normalizeendpoint(value: string): endpointconfig {\n const endpoint = new URL(value.trim());\n if (endpoint.protocol !== \"https:\") throw new Error(\"Devthink accepts HTTPS endpoints only.\");\n if (endpoint.username || endpoint.password) throw new Error(\"Endpoint credentials are not allowed in the URL.\");\n return { endpoint: endpoint.toString(), origin: endpoint.origin, configuredat: Date.now() };\n}\n\n/** Creates the exact optional host pattern requested from Chromium. */\nexport function hostpattern(origin: string): string {\n const parsed = new URL(origin);\n if (parsed.protocol !== \"https:\") throw new Error(\"Only HTTPS origins can be granted.\");\n return `${parsed.origin}/*`;\n}\n\n/** True when the action kind observes the page over a reviewed lifetime window. */\nexport function iswatchkind(kind: actionkind): boolean {\n return watchactions.has(kind);\n}\n\n/** Grades the observation mode of a kind: passive capture, watched lifetimes or diffing passes. */\nexport function observationmodeof(kind: actionkind): observationmode {\n if (watchactions.has(kind) || kind === \"waitquiet\") return \"watching\";\n if (kind === \"diffsnapshots\") return \"diffing\";\n return \"passive\";\n}\n\n/** Defines action risk from the fixed local allowlist. */\nexport function actionrisk(kind: actionkind): \"read\" | \"interaction\" | \"sensitive\" {\n if (!allowedactions.has(kind)) throw new Error(\"Unsupported browser action.\");\n if (sensitiveactions.has(kind)) return \"sensitive\";\n return interactionactions.has(kind) ? \"interaction\" : \"read\";\n}\n\n/** True when the action kind accepts a css selector target or a reviewed targetref. */\nexport function needstarget(kind: actionkind): boolean {\n return targetactions.has(kind);\n}\n\n/** Parses the reviewed JSON options of a step; malformed payloads are rejected early. */\nexport function parseoptions(step: toolstep): Record<string, unknown> {\n if (step.options === undefined) return {};\n let parsed: unknown;\n try { parsed = JSON.parse(step.options); } catch { throw new Error(\"Step options must be a JSON object.\"); }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) throw new Error(\"Step options must be a JSON object.\");\n return parsed as Record<string, unknown>;\n}\n\n/** Maps an action kind to the optional browser permission it requires, if any. */\nexport function requiredcapability(kind: actionkind): string | undefined {\n if (kind === \"tablist\") return \"tabs\";\n if (kind === \"downloadfile\") return \"downloads\";\n if (kind === \"openclipboard\") return \"clipboardRead\";\n if (kind === \"copytable\") return \"clipboardWrite\";\n if (kind === \"batchdownload\" || kind === \"pausedownload\" || kind === \"resumedownload\" || kind === \"verifydownload\" || kind === \"interceptmime\" || kind === \"quarantinedownload\" || kind === \"scanvirus\") return \"downloads\";\n if (kind === \"readclipboard\") return \"clipboardRead\";\n if (kind === \"writeclipboard\" || kind === \"copyscreen\") return \"clipboardWrite\";\n if (kind === \"openlink\" || kind === \"openprivate\" || kind === \"navlist\" || kind === \"batchopen\" || kind === \"reopentab\" || kind === \"deeplink\") return \"tabs\";\n if (tabscommandactions.has(kind)) return \"tabs\";\n return undefined;\n}\n\n/** True when the kind commands tabs or windows beyond the active tab and needs the optional tabs capability. */\nexport function istabscommandkind(kind: actionkind): boolean {\n return tabscommandactions.has(kind);\n}\n\n/** True when the kind mutates tab groups or layouts and therefore stays inside the active session. */\nexport function islayoutkind(kind: actionkind): boolean {\n return layoutmutationactions.has(kind);\n}\n\n/** True when the kind belongs to the forms and data family. */\nexport function isformkind(kind: actionkind): boolean {\n return formactions.has(kind);\n}\n\n/** True when the kind belongs to the extraction, transform, export and provenance family. */\nexport function isdatasetkind(kind: actionkind): boolean {\n return datasetactions.has(kind);\n}\n\n/** True when the kind exports extracted data out of local memory to disk, the clipboard or a reviewed sheet endpoint. */\nexport function isexportkind(kind: actionkind): boolean {\n return exportactions.has(kind);\n}\n\n/** True when the kind belongs to the files, clipboard and downloads family. */\nexport function isfileskind(kind: actionkind): boolean {\n return filesactions.has(kind);\n}\n\n/** Refuses any export that would leave local memory while the session origin grants do not cover the active origin. */\nexport function exportgranted(session: agentsession | undefined, origin: string): policyevaluation {\n if (!origingranted(session, origin)) return { allowed: false, reason: `The export of extracted data from ${origin} needs the session origin grants before it leaves local memory.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed fieldmatch grammar of one form field entry. */\nexport function validatefieldmatch(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed field match is required in options.\" };\n const match = value as Record<string, unknown>;\n if (match.mode !== \"label\" && match.mode !== \"placeholder\" && match.mode !== \"arialabel\" && match.mode !== \"name\") return { allowed: false, reason: \"The reviewed field match mode must be label, placeholder, arialabel or name.\" };\n const key = match.mode === \"label\" ? \"label\" : match.mode === \"placeholder\" ? \"placeholder\" : match.mode === \"arialabel\" ? \"arialabel\" : \"name\";\n if (!isnonempty(match[key])) return { allowed: false, reason: `The reviewed ${match.mode} field match needs a non-empty ${key}.` };\n return { allowed: true };\n}\n\n/** Validates a reviewed structured form record; password entries are refused because passwords need the explicit consentpassword consent. */\nexport function validateformrecord(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed form record with entries is required in options.\" };\n const record = value as Record<string, unknown>;\n if (record.form !== undefined && !isnonempty(record.form)) return { allowed: false, reason: \"The reviewed form record form selector must be a non-empty string.\" };\n if (!Array.isArray(record.entries) || record.entries.length === 0) return { allowed: false, reason: \"The reviewed form record needs a non-empty list of entries.\" };\n for (const item of record.entries) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed form record entry must be an object.\" };\n const entry = item as Record<string, unknown>;\n const matchcheck = validatefieldmatch(entry.match);\n if (!matchcheck.allowed) return matchcheck;\n if (typeof entry.kind !== \"string\" || !fieldkinds.includes(entry.kind as fieldkind)) return { allowed: false, reason: \"Every reviewed form record entry needs a known field kind.\" };\n if (typeof entry.value !== \"string\") return { allowed: false, reason: \"Every reviewed form record entry needs a string value.\" };\n if (entry.kind === \"password\") return { allowed: false, reason: \"Password entries are refused inside form records; use consentpassword with a reviewed consent ref.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed valuegen grammar of a generatevalues step. */\nexport function validatevaluegen(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed valuegen rule with a field kind is required in options.\" };\n const rule = value as Record<string, unknown>;\n if (typeof rule.kind !== \"string\" || !fieldkinds.includes(rule.kind as fieldkind)) return { allowed: false, reason: \"The reviewed valuegen kind must be a known field kind.\" };\n if (rule.locale !== undefined && !isnonempty(rule.locale)) return { allowed: false, reason: \"The reviewed valuegen locale must be a non-empty string.\" };\n if (rule.seed !== undefined && (typeof rule.seed !== \"number\" || !Number.isFinite(rule.seed))) return { allowed: false, reason: \"The reviewed valuegen seed must be a finite number.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed list of label or placeholder value pairs for filllabel and fillplaceholder steps. */\nfunction validatefieldpairs(options: Record<string, unknown>, mode: \"label\" | \"placeholder\"): policyevaluation {\n const pairs = options.fields;\n if (!Array.isArray(pairs) || pairs.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of field pairs is required in options.\" };\n for (const item of pairs) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed field pair must be an object.\" };\n const pair = item as Record<string, unknown>;\n if (!isnonempty(pair[mode])) return { allowed: false, reason: `Every reviewed field pair needs a non-empty ${mode}.` };\n if (typeof pair.value !== \"string\" || !pair.value.trim()) return { allowed: false, reason: \"Every reviewed field pair needs a non-empty value.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed card segment grammar of a fillcard step. */\nfunction validatecardsegments(value: unknown): policyevaluation {\n if (!Array.isArray(value) || value.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of card segments is required in options.\" };\n for (const item of value) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed card segment must be an object.\" };\n const segment = item as Record<string, unknown>;\n const matchcheck = validatefieldmatch(segment.match);\n if (!matchcheck.allowed) return matchcheck;\n if (typeof segment.value !== \"string\" || !segment.value.trim()) return { allowed: false, reason: \"Every reviewed card segment needs a non-empty value.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed forms and data parameter grammar of the form family. */\nfunction validateformgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"fillform\" || (kind === \"saveprofiles\" && options.formrecord !== undefined)) {\n const recordcheck = validateformrecord(options.formrecord);\n if (!recordcheck.allowed) return recordcheck;\n }\n if (kind === \"filllabel\" || kind === \"fillplaceholder\") {\n const paircheck = validatefieldpairs(options, kind === \"filllabel\" ? \"label\" : \"placeholder\");\n if (!paircheck.allowed) return paircheck;\n }\n if (kind === \"generatevalues\" && options.valuegen !== undefined) {\n const rulecheck = validatevaluegen(options.valuegen);\n if (!rulecheck.allowed) return rulecheck;\n }\n if (kind === \"saveprofiles\" && !isnonempty(options.name)) return { allowed: false, reason: \"A reviewed profile name is required in options.\" };\n if (kind === \"submitform\" && !isnonempty(options.consentref)) return { allowed: false, reason: \"A reviewed consent ref of an approved asksubmit ticket is required in options.\" };\n if (kind === \"retryform\") {\n const backoff = options.backoff;\n if (!backoff || typeof backoff !== \"object\" || Array.isArray(backoff)) return { allowed: false, reason: \"A reviewed backoff rule with wait and factor is required in options.\" };\n const rule = backoff as Record<string, unknown>;\n if (typeof rule.wait !== \"number\" || !Number.isFinite(rule.wait) || rule.wait <= 0) return { allowed: false, reason: \"The reviewed retry backoff wait must be a positive number of milliseconds with no code ceiling.\" };\n if (typeof rule.factor !== \"number\" || !Number.isFinite(rule.factor) || rule.factor < 1) return { allowed: false, reason: \"The reviewed retry backoff factor must be one or greater with no code ceiling.\" };\n if (options.attempts !== undefined && (typeof options.attempts !== \"number\" || !Number.isInteger(options.attempts) || options.attempts < 1)) return { allowed: false, reason: \"The reviewed retry attempts must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"runwizard\" && options.steps !== undefined && (typeof options.steps !== \"number\" || !Number.isInteger(options.steps) || options.steps < 1)) return { allowed: false, reason: \"The reviewed wizard step count must be a positive integer with no code ceiling.\" };\n if (kind === \"selectchain\") {\n if (!isnonempty(options.child)) return { allowed: false, reason: \"A reviewed child selector of the dependent control is required in options.\" };\n if (!nonnegativeoption(options, \"wait\")) return { allowed: false, reason: \"The reviewed dependent wait must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"picktypeahead\") {\n if (!isnonempty(options.pick)) return { allowed: false, reason: \"A reviewed suggestion entry to pick is required in options.\" };\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The reviewed typeahead timeout must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"pickdate\" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed date must use the yyyy-mm-dd form.\" };\n if (kind === \"fillcard\") {\n const segmentcheck = validatecardsegments(options.segments);\n if (!segmentcheck.allowed) return segmentcheck;\n if (!nonnegativeoption(options, \"pause\")) return { allowed: false, reason: \"The reviewed card typing pause must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"fillcode\" && !isnonempty(options.source)) return { allowed: false, reason: \"A reviewed one time code source is required in options.\" };\n if (kind === \"consentpassword\" && !isnonempty(options.consentref)) return { allowed: false, reason: \"A reviewed consent ref is required in options before any password is filled.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed transform rule: a supported expression, source columns and a target column. */\nexport function validatetransformrule(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed transform rule with an expression, sources and a target is required in options.\" };\n const rule = value as Record<string, unknown>;\n const expression = rule.expression;\n if (typeof expression !== \"string\" || !/^(trim|upper|lower|number|prefix|suffix|replace)(?::.+)?$/.test(expression)) return { allowed: false, reason: \"The reviewed transform expression must be trim, upper, lower, number, prefix, suffix or replace with an optional argument.\" };\n if (expression.startsWith(\"replace\") && !expression.slice(\"replace\".length).includes(\"=>\")) return { allowed: false, reason: \"The reviewed replace expression needs the from=>to separator.\" };\n if (expression.startsWith(\"replace\") && expression.slice(\"replace:\".length).split(\"=>\")[0] === \"\") return { allowed: false, reason: \"The reviewed replace expression needs a non-empty from part.\" };\n if (!Array.isArray(rule.sources) || rule.sources.length === 0 || !rule.sources.every(source => isnonempty(source))) return { allowed: false, reason: \"Every reviewed transform rule needs a non-empty list of source columns.\" };\n if (!isnonempty(rule.target)) return { allowed: false, reason: \"Every reviewed transform rule needs a non-empty target column.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed dataset id list in options. */\nfunction validatedatasetids(options: Record<string, unknown>, key: string): policyevaluation {\n const ids = options[key];\n if (!Array.isArray(ids) || ids.length === 0 || !ids.every(id => isnonempty(id))) return { allowed: false, reason: `A reviewed non-empty list of dataset ids is required in options as ${key}.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed extraction, transform, export and provenance parameter grammar of the data family. */\nfunction validatedatagrammar(step: toolstep, options: Record<string, unknown>, origin: string): policyevaluation {\n const kind = step.kind;\n if (kind === \"scrapetable\") {\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed dataset name must be a non-empty string.\" };\n if (options.rowlimit !== undefined && (typeof options.rowlimit !== \"number\" || !Number.isInteger(options.rowlimit) || options.rowlimit < 1)) return { allowed: false, reason: \"The reviewed row limit must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"paginateextract\") {\n if (!isnonempty(options.next)) return { allowed: false, reason: \"A reviewed next control selector is required in options.\" };\n if (options.pages !== undefined && (typeof options.pages !== \"number\" || !Number.isInteger(options.pages) || options.pages < 1)) return { allowed: false, reason: \"The reviewed page count must be a positive integer with no code ceiling.\" };\n if (!nonnegativeoption(options, \"wait\")) return { allowed: false, reason: \"The reviewed row freshness wait must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"exportcsv\" || kind === \"exportjson\" || kind === \"exportexcel\" || kind === \"copytable\" || kind === \"streamdisk\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed artifact name must be a non-empty string.\" };\n }\n if (kind === \"exportcsv\" && options.delimiter !== undefined && (typeof options.delimiter !== \"string\" || options.delimiter.length !== 1)) return { allowed: false, reason: \"The reviewed csv delimiter must be a single character.\" };\n if (kind === \"streamdisk\" && (typeof options.chunk !== \"number\" || !Number.isInteger(options.chunk) || options.chunk < 1)) return { allowed: false, reason: \"The reviewed streaming chunk size must be a positive integer with no code ceiling.\" };\n if (kind === \"pushsheets\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (!isnonempty(options.sheet)) return { allowed: false, reason: \"A reviewed sheet endpoint url is required in options.\" };\n if (!ishttpsurl(options.sheet)) return { allowed: false, reason: \"The reviewed sheet endpoint url must use HTTPS.\" };\n if (options.reviewed !== true) return { allowed: false, reason: \"The sheet push needs the explicit reviewed flag before any data leaves local memory.\" };\n }\n if (kind === \"importcsv\") {\n if (typeof options.csv !== \"string\" || !options.csv.trim()) return { allowed: false, reason: \"Reviewed csv content is required in options.\" };\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed dataset name must be a non-empty string.\" };\n if (options.mapping !== undefined) {\n const mapping = options.mapping;\n if (!mapping || typeof mapping !== \"object\" || Array.isArray(mapping) || !Object.values(mapping).every(item => typeof item === \"string\")) return { allowed: false, reason: \"The reviewed csv column mapping must be an object of string values.\" };\n }\n }\n if (kind === \"looprows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.variable !== undefined && !isnonempty(options.variable)) return { allowed: false, reason: \"The reviewed row variable name must be a non-empty string.\" };\n const inner = validateinnerstep(options, origin);\n if (!inner.allowed) return inner;\n }\n if (kind === \"transformvalues\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n const rules = options.rules;\n if (!Array.isArray(rules) || rules.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of transform rules is required in options.\" };\n for (const item of rules) {\n const rulecheck = validatetransformrule(item);\n if (!rulecheck.allowed) return rulecheck;\n }\n }\n if (kind === \"deduperows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n const keys = options.keys;\n if (!Array.isArray(keys) || keys.length === 0 || !keys.every(key => isnonempty(key))) return { allowed: false, reason: \"A reviewed non-empty list of dedupe column keys is required in options.\" };\n }\n if (kind === \"mergepages\") {\n const listcheck = validatedatasetids(options, \"datasets\");\n if (!listcheck.allowed) return listcheck;\n }\n if (kind === \"stamplerows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.url !== undefined && !ishttpsurl(options.url)) return { allowed: false, reason: \"The reviewed source url must use HTTPS.\" };\n }\n if (kind === \"previewgrid\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.sample !== undefined && (typeof options.sample !== \"number\" || !Number.isInteger(options.sample) || options.sample < 1)) return { allowed: false, reason: \"The reviewed sample row count must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"resumeextract\" && !isnonempty(options.session)) return { allowed: false, reason: \"A reviewed extract session id is required in options.\" };\n if (kind === \"logprovenance\" && !isnonempty(options.artifact)) return { allowed: false, reason: \"A reviewed artifact id or name is required in options.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed batch download specification: a non-empty HTTPS url list, an optional filename rule and an optional completion criterion. */\nexport function validatedownloadspec(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed downloadspec with a url list is required in options.\" };\n const spec = value as Record<string, unknown>;\n if (!Array.isArray(spec.urls) || spec.urls.length === 0 || !spec.urls.every(url => ishttpsurl(url))) return { allowed: false, reason: \"The reviewed downloadspec needs a non-empty list of HTTPS urls.\" };\n if (spec.filename !== undefined && !isnonempty(spec.filename)) return { allowed: false, reason: \"The reviewed downloadspec filename rule must be a non-empty string.\" };\n if (spec.complete !== undefined && spec.complete !== \"size\" && spec.complete !== \"checksum\") return { allowed: false, reason: \"The reviewed downloadspec completion criterion must be size or checksum.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed mime interception filter: include and exclude patterns plus the deny default for unlisted mime types. */\nexport function validatemimefilter(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed mimefilter with include and exclude patterns is required in options.\" };\n const filter = value as Record<string, unknown>;\n if (!Array.isArray(filter.include) || filter.include.length === 0 || !filter.include.every(pattern => isnonempty(pattern))) return { allowed: false, reason: \"The reviewed mimefilter needs a non-empty list of include patterns.\" };\n if (filter.exclude !== undefined && (!Array.isArray(filter.exclude) || !filter.exclude.every(pattern => isnonempty(pattern)))) return { allowed: false, reason: \"The reviewed mimefilter exclude patterns must be a list of non-empty strings.\" };\n if (filter.default !== \"deny\" && filter.default !== \"allow\") return { allowed: false, reason: \"The reviewed mimefilter needs the deny or allow default for unlisted mime types.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed cleanup rule: a positive age window with no code ceiling, an artifact kind and a keep policy. */\nexport function validatecleanuprule(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed cleanuprule with an age, a kind and a keep policy is required.\" };\n const rule = value as Record<string, unknown>;\n if (typeof rule.age !== \"number\" || !Number.isFinite(rule.age) || rule.age <= 0) return { allowed: false, reason: \"The reviewed cleanup age window must be a positive number of milliseconds with no code ceiling.\" };\n if (!isnonempty(rule.kind)) return { allowed: false, reason: \"The reviewed cleanup rule needs a non-empty artifact kind, or any to match every kind.\" };\n if (rule.keep !== \"none\" && rule.keep !== \"latest\" && rule.keep !== \"all\") return { allowed: false, reason: \"The reviewed cleanup keep policy must be none, latest or all.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed files, clipboard and downloads parameter grammar; batch sizes, concurrent windows and cleanup ages stay user configured with no code ceilings. */\nfunction validatefilesgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"batchdownload\") {\n const speccheck = validatedownloadspec(options.downloadspec);\n if (!speccheck.allowed) return speccheck;\n if (options.concurrent !== undefined && (typeof options.concurrent !== \"number\" || !Number.isInteger(options.concurrent) || options.concurrent < 1)) return { allowed: false, reason: \"The reviewed concurrent download window must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"pausedownload\" || kind === \"resumedownload\" || kind === \"verifydownload\" || kind === \"quarantinedownload\" || kind === \"scanvirus\") {\n if (!isnonempty(step.value)) return { allowed: false, reason: \"A reviewed download or quarantine reference is required.\" };\n if (kind === \"verifydownload\") {\n if (options.checksum !== undefined && !isnonempty(options.checksum)) return { allowed: false, reason: \"The reviewed expected checksum must be a non-empty string.\" };\n if (options.bytes !== undefined && (typeof options.bytes !== \"number\" || !Number.isFinite(options.bytes) || options.bytes < 0)) return { allowed: false, reason: \"The reviewed expected size must be zero or a positive number of bytes.\" };\n }\n if (kind === \"scanvirus\" && options.scanner !== undefined && !isnonempty(options.scanner)) return { allowed: false, reason: \"The reviewed scanner name must be a non-empty string.\" };\n if (kind === \"quarantinedownload\" && options.reason !== undefined && !isnonempty(options.reason)) return { allowed: false, reason: \"The reviewed quarantine reason must be a non-empty string.\" };\n }\n if (kind === \"interceptmime\") {\n const filtercheck = validatemimefilter(options.mimefilter);\n if (!filtercheck.allowed) return filtercheck;\n }\n if (kind === \"readclipboard\") {\n if (!isnonempty(options.consentref)) return { allowed: false, reason: \"A clipboard read requires a reviewed consent ref of an approved consent prompt in options.\" };\n if (options.prompt !== undefined && !isnonempty(options.prompt)) return { allowed: false, reason: \"The reviewed clipboard consent prompt must be a non-empty string.\" };\n }\n if (kind === \"exportnetlog\" && options.stepid !== undefined && !isnonempty(options.stepid)) return { allowed: false, reason: \"The reviewed netlog step filter must be a non-empty step id.\" };\n if (kind === \"namecaptures\") {\n if (!isnonempty(options.task)) return { allowed: false, reason: \"A reviewed task id is required in options for capture naming.\" };\n if (options.steps !== undefined && (!Array.isArray(options.steps) || options.steps.length === 0 || !options.steps.every(item => isnonempty(item)))) return { allowed: false, reason: \"The reviewed capture steps must be a non-empty list of step ids when present.\" };\n if (options.extension !== undefined && !isnonempty(options.extension)) return { allowed: false, reason: \"The reviewed capture extension must be a non-empty string.\" };\n }\n if (kind === \"cleanupartifacts\" && options.rules !== undefined) {\n const rules = options.rules;\n if (!Array.isArray(rules) || rules.length === 0) return { allowed: false, reason: \"The reviewed cleanup rules must be a non-empty list when present.\" };\n for (const item of rules) {\n const rulecheck = validatecleanuprule(item);\n if (!rulecheck.allowed) return rulecheck;\n }\n }\n return { allowed: true };\n}\n\n/** Requires an approved consent prompt before any clipboard read; every read consumes its own prompt. */\nexport function clipboardconsentgranted(step: toolstep): policyevaluation {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const consentref = options.consentref;\n if (typeof consentref !== \"string\" || !consentref.trim()) return { allowed: false, reason: \"A clipboard read requires a reviewed consent ref in options.\" };\n return { allowed: true };\n}\n\n/** Refuses to release any quarantined file before a clean scan verdict exists. */\nexport function quarantinereleasegranted(entry: quarantineentry): policyevaluation {\n if (entry.scan !== \"clean\") return { allowed: false, reason: `The quarantined file ${entry.path} cannot leave quarantine with the ${entry.scan} scan verdict; only a clean verdict releases it.` };\n return { allowed: true };\n}\n\n/** Refuses downloads and download interception that fall outside the session origin grants. */\nexport function downloadgranted(session: agentsession | undefined, url: string): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed download URL is invalid.\" }; }\n if (!origingranted(session, origin)) return { allowed: false, reason: `The download from ${origin} leaves the session origin grants and needs a session grant first.` };\n return { allowed: true };\n}\n\n/** Masks a clipboard payload for every log line; the full text never persists anywhere. */\nexport function maskclipboard(payload: string): string {\n return `[clipboard payload of ${payload.length} character${payload.length === 1 ? \"\" : \"s\"}]`;\n}\n\n/** Requires an asksubmit review step before every form submission step. */\nexport function submitreviewgranted(steps: toolstep[], submitid: string): policyevaluation {\n const position = steps.findIndex(candidate => candidate.id === submitid);\n const asked = steps.some((candidate, index) => candidate.kind === \"asksubmit\" && (position === -1 || index < position));\n return asked ? { allowed: true } : { allowed: false, reason: \"Form submission requires an asksubmit review step before it.\" };\n}\n\n/** Requires a reviewed consent ref before any password field is filled. */\nexport function passwordconsentgranted(step: toolstep): policyevaluation {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const consentref = options.consentref;\n if (typeof consentref !== \"string\" || !consentref.trim()) return { allowed: false, reason: \"A password fill requires a reviewed consent ref in options.\" };\n return { allowed: true };\n}\n\n/** True when a numeric value passes the Luhn checksum used by card networks. */\nfunction luhnvalid(digits: string): boolean {\n let sum = 0;\n let double = false;\n for (let index = digits.length - 1; index >= 0; index -= 1) {\n let value = Number.parseInt(digits[index] ?? \"\", 10);\n if (!Number.isFinite(value)) return false;\n if (double) { value *= 2; if (value > 9) value -= 9; }\n sum += value;\n double = !double;\n }\n return sum % 10 === 0;\n}\n\n/** Refuses generated values that look like real card numbers or personal identifiers; test prefixed card values stay allowed. */\nexport function generatedvalueallowed(value: string): policyevaluation {\n const compact = value.replace(/[\\s-]/g, \"\");\n if (/^\\d{13,19}$/.test(compact) && luhnvalid(compact) && !compact.startsWith(\"4111\")) return { allowed: false, reason: \"The generated value looks like a real card number and is refused; generated card values use the 4111 test prefix.\" };\n if (/^\\d{3}-\\d{2}-\\d{4}$/.test(value.trim())) return { allowed: false, reason: \"The generated value looks like a personal identifier and is refused.\" };\n return { allowed: true };\n}\n\n/** Requires the origin grants of a saved profile to cover the origin before its values fill a page. */\nexport function profilegrantgranted(profile: formprofile, origin: string): policyevaluation {\n if (!profile.grants.includes(origin)) return { allowed: false, reason: `The saved profile ${profile.name} is not granted to ${origin}; add the origin to the profile grants first.` };\n return { allowed: true };\n}\n\n/** Restricts group and layout mutations to the active session: they refuse without a live session. */\nexport function layoutmutationgranted(session: agentsession | undefined, now: number): policyevaluation {\n if (!session || session.stoppedat || session.expiresat <= now) return { allowed: false, reason: \"Group and layout mutations stay inside the active session.\" };\n return { allowed: true };\n}\n\n/** Requires explicit review before closing a window that holds more than one task tab. */\nexport function windowclosegate(tasktabcount: number, reviewed: boolean): policyevaluation {\n if (tasktabcount > 1 && !reviewed) return { allowed: false, reason: `The window holds ${tasktabcount} task tabs and needs explicit review before it closes.` };\n return { allowed: true };\n}\n\n/** Reads the user configured concurrent task tab ceiling; an absent value never refuses a tab. */\nexport function tasktabceiling(settings: runsettings | undefined): number | undefined {\n const ceiling = settings?.tasktabceiling;\n return typeof ceiling === \"number\" && Number.isFinite(ceiling) && ceiling >= 0 ? ceiling : undefined;\n}\n\n/** Parses the reviewed wait duration of a wait step with no upper bound. */\nexport function waitduration(step: toolstep): number {\n const requested = step.value ? Number.parseInt(step.value, 10) : 250;\n if (!Number.isFinite(requested) || requested < 0) throw new Error(\"Wait duration must be zero or a positive number of milliseconds.\");\n return requested;\n}\n\nfunction isnumericid(value: unknown): value is string {\n return typeof value === \"string\" && /^\\d+$/.test(value);\n}\n\nfunction numericoption(options: Record<string, unknown>, key: string): boolean {\n return options[key] === undefined || (typeof options[key] === \"number\" && Number.isFinite(options[key] as number));\n}\n\n/** True when an optional numeric option is absent or a finite number of zero or more. */\nfunction nonnegativeoption(options: Record<string, unknown>, key: string): boolean {\n return numericoption(options, key) && !(typeof options[key] === \"number\" && (options[key] as number) < 0);\n}\n\nfunction isnonempty(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction ispoint(value: unknown): boolean {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n const point = value as Record<string, unknown>;\n return typeof point.x === \"number\" && Number.isFinite(point.x) && typeof point.y === \"number\" && Number.isFinite(point.y);\n}\n\n/** Grades a resolution match count: zero is absent, one is resolved and more than one is refused as ambiguous. */\nexport function resolutionverdict(count: number): \"absent\" | \"resolved\" | \"ambiguous\" {\n if (!Number.isFinite(count) || count <= 0) return \"absent\";\n return count === 1 ? \"resolved\" : \"ambiguous\";\n}\n\n/** Validates the reviewed targetref grammar of every resolution mode and rejects empty references. */\nexport function validatetargetref(reference: unknown): policyevaluation {\n if (!reference || typeof reference !== \"object\" || Array.isArray(reference)) return { allowed: false, reason: \"The reviewed target reference must be an object.\" };\n const ref = reference as Record<string, unknown>;\n if (ref.mode === \"selector\") return isnonempty(ref.selector) ? { allowed: true } : { allowed: false, reason: \"The selector target reference needs a non-empty selector.\" };\n if (ref.mode === \"text\") return isnonempty(ref.text) ? { allowed: true } : { allowed: false, reason: \"The text target reference needs non-empty text.\" };\n if (ref.mode === \"aria\") {\n if (!isnonempty(ref.role)) return { allowed: false, reason: \"The aria target reference needs a non-empty role.\" };\n return isnonempty(ref.name) ? { allowed: true } : { allowed: false, reason: \"The aria target reference needs a non-empty name.\" };\n }\n if (ref.mode === \"name\") return isnonempty(ref.name) ? { allowed: true } : { allowed: false, reason: \"The name target reference needs a non-empty name.\" };\n if (ref.mode === \"xpath\") return isnonempty(ref.xpath) ? { allowed: true } : { allowed: false, reason: \"The xpath target reference needs a non-empty expression.\" };\n if (ref.mode === \"index\") {\n const index = ref.index;\n return typeof index === \"number\" && Number.isInteger(index) && index >= 1 ? { allowed: true } : { allowed: false, reason: \"The index target reference needs a positive integer map number.\" };\n }\n if (ref.mode === \"point\") {\n const pointok = typeof ref.x === \"number\" && Number.isFinite(ref.x) && typeof ref.y === \"number\" && Number.isFinite(ref.y);\n return pointok ? { allowed: true } : { allowed: false, reason: \"The point target reference needs numeric x and y coordinates.\" };\n }\n return { allowed: false, reason: \"The target reference mode must be selector, text, aria, name, xpath, index or point.\" };\n}\n\n/** True when the session origin grants cover the given origin; a session without grants only allows its own origin. */\nexport function origingranted(session: agentsession | undefined, origin: string): boolean {\n if (!session) return false;\n const grants = session.grants ?? [session.origin];\n return grants.includes(origin);\n}\n\n/** Decides whether an unreviewed origin may open: the session grants cover it or a safe checksafe verdict vouches for it. */\nexport function originverified(url: string, grants: string[], verdicts: safetyverdict[]): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed navigation URL is invalid.\" }; }\n if (grants.includes(origin)) return { allowed: true };\n const covered = verdicts.find(verdict => verdict.safe && (verdict.url === url || (safeorigin(verdict.url) === origin)));\n if (covered) return { allowed: true };\n return { allowed: false, reason: `The origin ${origin} is outside the session grants and has no safe checksafe verdict; run checksafe and review it first.` };\n}\n\nfunction safeorigin(url: string): string {\n try { return new URL(url).origin; } catch { return \"\"; }\n}\n\n/** Refuses navigation that would move a granted task tab outside the session origin grants until the user consents. */\nexport function navigationgranted(session: agentsession | undefined, url: string): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed navigation URL is invalid.\" }; }\n if (origingranted(session, origin)) return { allowed: true };\n return { allowed: false, reason: `Navigation to ${origin} leaves the task tab origins and needs the user consent of a session grant first.` };\n}\n\n/** Validates the reviewed inner step of a retry or frame wrapper against the same rules as a top-level step. */\nfunction validateinnerstep(options: Record<string, unknown>, origin: string): policyevaluation {\n const stepid = options.stepid;\n const kind = options.kind;\n if (isnonempty(stepid)) {\n if (kind !== undefined) return { allowed: false, reason: \"The reviewed wrapper must reference a step id or an inline step, not both.\" };\n return { allowed: true };\n }\n if (typeof kind !== \"string\" || !kind.trim()) return { allowed: false, reason: \"A reviewed step id or inline step kind is required in options.\" };\n if (kind === \"retryaction\" || kind === \"enterframe\" || kind === \"looprows\") return { allowed: false, reason: \"The reviewed inner step cannot be another wrapper kind.\" };\n if (!allowedactions.has(kind as actionkind)) return { allowed: false, reason: \"The reviewed inner step kind is unsupported.\" };\n const inneroptions = options.options;\n if (inneroptions !== undefined && (!inneroptions || typeof inneroptions !== \"object\" || Array.isArray(inneroptions))) return { allowed: false, reason: \"The reviewed inner step options must be an object.\" };\n const inner: toolstep = {\n id: \"inner\",\n kind: kind as actionkind,\n summary: \"Reviewed inner step.\",\n risk: actionrisk(kind as actionkind),\n ...(isnonempty(options.target) ? { target: options.target } : {}),\n ...(isnonempty(options.value) ? { value: options.value } : {}),\n ...(inneroptions !== undefined ? { options: JSON.stringify(inneroptions) } : {}),\n };\n return validatestep(inner, origin);\n}\n\n/** True when a reviewed https url parses. */\nfunction ishttpsurl(value: unknown): value is string {\n if (typeof value !== \"string\" || !value.trim()) return false;\n try { return new URL(value).protocol === \"https:\"; } catch { return false; }\n}\n\n/** Validates the reviewed navtarget grammar of a navigation step. */\nfunction validatenavtarget(value: unknown, kind: string): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed navtarget with a url is required in options.\" };\n const target = value as Record<string, unknown>;\n if (!ishttpsurl(target.url)) return { allowed: false, reason: \"The reviewed navtarget url must use HTTPS.\" };\n const container = target.container ?? \"tab\";\n if (container !== \"current\" && container !== \"tab\" && container !== \"window\" && container !== \"private\") return { allowed: false, reason: \"The reviewed navtarget container must be current, tab, window or private.\" };\n if (target.position !== undefined && target.position !== \"adjacent\" && target.position !== \"end\") return { allowed: false, reason: \"The reviewed navtarget position must be adjacent or end.\" };\n if (kind === \"openprivate\" && container !== \"private\") return { allowed: false, reason: \"The openprivate step requires the private container.\" };\n if (kind === \"openlink\" && container === \"private\") return { allowed: false, reason: \"The openlink step cannot open the private container; use openprivate.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed waitprofile grammar with its load signals, thresholds and per origin overrides. */\nfunction validatewaitprofile(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed waitprofile with load signals is required in options.\" };\n const profile = value as Record<string, unknown>;\n if (!Array.isArray(profile.signals) || profile.signals.length === 0 || !profile.signals.every(signal => isnonempty(signal))) return { allowed: false, reason: \"The reviewed waitprofile needs a non-empty list of load signals.\" };\n if (!nonnegativeoption(profile, \"idle\")) return { allowed: false, reason: \"The reviewed waitprofile idle threshold must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(profile, \"timeout\")) return { allowed: false, reason: \"The reviewed waitprofile timeout must be zero or a positive number of milliseconds.\" };\n if (profile.overrides !== undefined) {\n if (!Array.isArray(profile.overrides) || profile.overrides.length === 0) return { allowed: false, reason: \"The reviewed waitprofile overrides must be a non-empty list when present.\" };\n for (const entry of profile.overrides) {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return { allowed: false, reason: \"Every reviewed waitprofile override must be an object with an origin.\" };\n const override = entry as Record<string, unknown>;\n if (!ishttpsurl(override.origin)) return { allowed: false, reason: \"Every reviewed waitprofile override origin must use HTTPS.\" };\n if (override.signals !== undefined && (!Array.isArray(override.signals) || !override.signals.every(signal => isnonempty(signal)))) return { allowed: false, reason: \"The reviewed waitprofile override signals must be a list of non-empty strings.\" };\n if (!nonnegativeoption(override, \"idle\") || !nonnegativeoption(override, \"timeout\")) return { allowed: false, reason: \"The reviewed waitprofile override thresholds must be zero or positive numbers.\" };\n }\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed urlpattern grammar with its match mode plus query and fragment parts. */\nexport function validateurlpattern(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed urlpattern is required in options.\" };\n const pattern = value as Record<string, unknown>;\n if (pattern.mode !== \"exact\" && pattern.mode !== \"prefix\" && pattern.mode !== \"host\" && pattern.mode !== \"pattern\") return { allowed: false, reason: \"The reviewed urlpattern mode must be exact, prefix, host or pattern.\" };\n if (!ishttpsurl(pattern.url)) return { allowed: false, reason: \"The reviewed urlpattern url must use HTTPS.\" };\n if (pattern.query !== undefined) {\n if (!pattern.query || typeof pattern.query !== \"object\" || Array.isArray(pattern.query)) return { allowed: false, reason: \"The reviewed urlpattern query part must be an object of parameter names and values.\" };\n for (const item of Object.values(pattern.query)) if (typeof item !== \"string\") return { allowed: false, reason: \"The reviewed urlpattern query values must be strings.\" };\n }\n if (pattern.fragment !== undefined && !isnonempty(pattern.fragment)) return { allowed: false, reason: \"The reviewed urlpattern fragment must be a non-empty string.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed non-empty list of HTTPS urls in options. */\nfunction validateurllist(options: Record<string, unknown>, key: string): policyevaluation {\n const urls = options[key];\n if (!Array.isArray(urls) || urls.length === 0 || !urls.every(url => ishttpsurl(url))) return { allowed: false, reason: `A reviewed non-empty list of HTTPS urls is required in options as ${key}.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed ratelimit grammar of a navrate step; the window and ceiling stay user configured with no hardcoded cap. */\nfunction validateratelimit(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed ratelimit with a window and a ceiling is required in options.\" };\n const limit = value as Record<string, unknown>;\n if (limit.domain !== undefined && !isnonempty(limit.domain)) return { allowed: false, reason: \"The reviewed ratelimit domain must be a non-empty string.\" };\n if (typeof limit.window !== \"number\" || !Number.isFinite(limit.window) || limit.window <= 0) return { allowed: false, reason: \"The reviewed ratelimit window must be a positive number of milliseconds with no code ceiling.\" };\n if (typeof limit.ceiling !== \"number\" || !Number.isInteger(limit.ceiling) || limit.ceiling < 1) return { allowed: false, reason: \"The reviewed ratelimit ceiling must be a positive integer with no code ceiling.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed tabquery grammar with url, title, id and pattern matchers; at least one matcher is required. */\nexport function validatetabquery(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed tabquery with at least one matcher is required in options.\" };\n const query = value as Record<string, unknown>;\n const hasmatcher = query.url !== undefined || query.title !== undefined || query.id !== undefined || query.pattern !== undefined;\n if (!hasmatcher) return { allowed: false, reason: \"The reviewed tabquery needs a url, title, id or pattern matcher.\" };\n if (query.url !== undefined && !isnonempty(query.url)) return { allowed: false, reason: \"The reviewed tabquery url matcher must be a non-empty string.\" };\n if (query.title !== undefined && !isnonempty(query.title)) return { allowed: false, reason: \"The reviewed tabquery title matcher must be a non-empty string.\" };\n if (query.pattern !== undefined && !isnonempty(query.pattern)) return { allowed: false, reason: \"The reviewed tabquery pattern matcher must be a non-empty string.\" };\n if (query.id !== undefined && (typeof query.id !== \"number\" || !Number.isInteger(query.id) || query.id < 0)) return { allowed: false, reason: \"The reviewed tabquery id matcher must be a non-negative integer tab id.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed group color choice against the Chromium tab group palette. */\nfunction validategroupcolor(value: unknown): boolean {\n return typeof value === \"string\" && (groupcolors as string[]).includes(value);\n}\n\n/** Validates a reviewed list of numeric browser ids in options. */\nfunction validateidlist(options: Record<string, unknown>, key: string): boolean {\n const ids = options[key];\n return Array.isArray(ids) && ids.length > 0 && ids.every(id => typeof id === \"number\" && Number.isInteger(id) && id >= 0);\n}\n\n/** Validates the reviewed tab and window parameter grammar of the tabs and windows command family. */\nfunction validatetabsgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"querytabs\" || kind === \"closepattern\") {\n const querycheck = validatetabquery(options.tabquery);\n if (!querycheck.allowed) return querycheck;\n if (kind === \"closepattern\" && options.reviewed !== true) return { allowed: false, reason: \"The close pattern needs the explicit reviewed flag before any tab closes.\" };\n }\n if (kind === \"duplicatetab\" || kind === \"pintab\" || kind === \"mutetab\" || kind === \"movetab\" || kind === \"movetabwindow\" || kind === \"badgetab\" || kind === \"attachmeta\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser tab id is required.\" };\n }\n if (kind === \"focuswindow\" || kind === \"maximizewindow\" || kind === \"minimizewindow\" || kind === \"restorewindow\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser window id is required.\" };\n }\n if (kind === \"pintab\" && typeof options.pinned !== \"boolean\") return { allowed: false, reason: \"A reviewed pinned flag is required in options.\" };\n if (kind === \"mutetab\" && typeof options.muted !== \"boolean\") return { allowed: false, reason: \"A reviewed muted flag is required in options.\" };\n if (kind === \"movetab\") {\n if (typeof options.index !== \"number\" || !Number.isInteger(options.index) || options.index < 0) return { allowed: false, reason: \"A reviewed non-negative target index is required in options.\" };\n }\n if (kind === \"movetabwindow\") {\n if (typeof options.windowid !== \"number\" || !Number.isInteger(options.windowid) || options.windowid < 0) return { allowed: false, reason: \"A reviewed target window id is required in options.\" };\n }\n if (kind === \"grouptabs\") {\n const group = options.group;\n if (!group || typeof group !== \"object\" || Array.isArray(group)) return { allowed: false, reason: \"A reviewed group with a name is required in options.\" };\n const spec = group as Record<string, unknown>;\n if (!isnonempty(spec.name)) return { allowed: false, reason: \"The reviewed group needs a non-empty name.\" };\n if (!validategroupcolor(spec.color)) return { allowed: false, reason: \"The reviewed group color must be a Chromium tab group color.\" };\n if (!validateidlist(spec, \"tabids\")) return { allowed: false, reason: \"The reviewed group needs a non-empty list of member tab ids.\" };\n }\n if (kind === \"colorgroup\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed group name is required in options.\" };\n if (!validategroupcolor(options.color)) return { allowed: false, reason: \"The reviewed group color must be a Chromium tab group color.\" };\n }\n if (kind === \"collapsegroup\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed group name is required in options.\" };\n if (typeof options.collapsed !== \"boolean\") return { allowed: false, reason: \"A reviewed collapsed flag is required in options.\" };\n }\n if (kind === \"discardtab\" || kind === \"reloadtabs\") {\n if (!isnumericid(step.value) && !validateidlist(options, \"tabs\")) return { allowed: false, reason: \"A numeric tab id or a reviewed list of tab ids is required.\" };\n }\n if (kind === \"zoomin\" || kind === \"zoomout\") {\n if (options.step !== undefined && (typeof options.step !== \"number\" || !Number.isFinite(options.step) || options.step <= 0)) return { allowed: false, reason: \"The reviewed zoom step must be a positive number with no code ceiling.\" };\n if (step.value !== undefined && step.value !== \"\" && !isnumericid(step.value)) return { allowed: false, reason: \"The reviewed zoom target must be a numeric tab id.\" };\n }\n if (kind === \"switchtab\") {\n if (options.direction !== \"next\" && options.direction !== \"previous\") return { allowed: false, reason: \"A reviewed switch direction of next or previous is required in options.\" };\n }\n if (kind === \"restorewindow\") {\n const bounds = options.bounds;\n if (bounds !== undefined) {\n if (!bounds || typeof bounds !== \"object\" || Array.isArray(bounds)) return { allowed: false, reason: \"The reviewed window bounds must be an object.\" };\n const shape = bounds as Record<string, unknown>;\n for (const field of [\"left\", \"top\", \"width\", \"height\"]) {\n if (typeof shape[field] !== \"number\" || !Number.isFinite(shape[field])) return { allowed: false, reason: \"The reviewed window bounds need numeric left, top, width and height.\" };\n }\n }\n }\n if (kind === \"scratchwindow\") {\n if (step.value !== undefined && step.value !== \"\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed scratch window url must use HTTPS.\" };\n }\n if (kind === \"incognitowindow\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS url is required to open an incognito window.\" };\n if (kind === \"restoretab\" && step.value !== undefined && step.value !== \"\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed restore url must use HTTPS.\" };\n if (kind === \"savelayout\" || kind === \"restorelayout\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed layout name is required in options.\" };\n }\n if (kind === \"badgetab\") {\n if (!isnonempty(options.label)) return { allowed: false, reason: \"A reviewed badge label is required in options.\" };\n if (options.taskid !== undefined && !isnonempty(options.taskid)) return { allowed: false, reason: \"The reviewed badge task id must be a non-empty string.\" };\n }\n if (kind === \"attachmeta\") {\n const labels = options.labels;\n const taskrefs = options.taskrefs;\n const haslabels = Array.isArray(labels) && labels.length > 0 && labels.every(label => isnonempty(label));\n const hastaskrefs = Array.isArray(taskrefs) && taskrefs.length > 0 && taskrefs.every(ref => isnonempty(ref));\n if (!haslabels && !hastaskrefs) return { allowed: false, reason: \"Reviewed labels or task refs are required in options to attach metadata.\" };\n if (options.provenance !== undefined && !isnonempty(options.provenance)) return { allowed: false, reason: \"The reviewed provenance must be a non-empty string.\" };\n }\n if (kind === \"reopenrun\" && !isnonempty(options.run)) return { allowed: false, reason: \"A reviewed run id is required in options to reopen its tabs.\" };\n return { allowed: true };\n}\n\n/** Validates a single proposal against the active tab origin and local policy. */\nexport function validatestep(step: toolstep, origin: string): policyevaluation {\n if (!allowedactions.has(step.kind)) return { allowed: false, reason: \"Unsupported action kind.\" };\n if (!step.summary.trim()) return { allowed: false, reason: \"A human-readable action summary is required.\" };\n let options: Record<string, unknown>;\n try { options = parseoptions(step); } catch { return { allowed: false, reason: \"Step options must be a JSON object.\" }; }\n const hastargetref = options.targetref !== undefined;\n if (targetactions.has(step.kind) && !step.target?.trim() && !hastargetref) return { allowed: false, reason: \"A page target is required.\" };\n if (valueactions.has(step.kind) && !step.value?.trim()) return { allowed: false, reason: \"A reviewed value is required.\" };\n if (step.kind === \"select\" && !step.value?.trim()) return { allowed: false, reason: \"A reviewed option value is required.\" };\n if (step.kind === \"navigate\" && !step.value) return { allowed: false, reason: \"A navigation URL is required.\" };\n if (hastargetref) {\n const reference = validatetargetref(options.targetref);\n if (!reference.allowed) return reference;\n }\n if (step.kind === \"wait\") {\n try { waitduration(step); } catch { return { allowed: false, reason: \"Wait duration must be zero or a positive number of milliseconds.\" }; }\n }\n if (step.kind === \"navigate\") {\n try {\n if (new URL(step.value ?? \"\").origin !== origin) return { allowed: false, reason: \"Navigation must remain within the approved origin.\" };\n } catch {\n return { allowed: false, reason: \"Navigation URL is invalid.\" };\n }\n }\n if (step.kind === \"tabcreate\" || step.kind === \"windowcreate\" || step.kind === \"downloadfile\") {\n try {\n const url = new URL(step.value ?? \"\");\n if (url.protocol !== \"https:\") return { allowed: false, reason: \"The reviewed URL must use HTTPS.\" };\n } catch {\n return { allowed: false, reason: \"The reviewed URL is invalid.\" };\n }\n }\n if (step.kind === \"tabactivate\" || step.kind === \"tabclose\" || step.kind === \"tabreload\" || step.kind === \"windowclose\" || step.kind === \"windowresize\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser id is required.\" };\n }\n if (step.kind === \"zoomset\") {\n const zoom = Number(step.value);\n if (!Number.isFinite(zoom) || zoom <= 0) return { allowed: false, reason: \"The reviewed zoom must be a positive number.\" };\n }\n if (step.kind === \"setattribute\" || step.kind === \"writestorage\") {\n const keyname = step.kind === \"setattribute\" ? \"name\" : \"key\";\n if (typeof options[keyname] !== \"string\" || !(options[keyname] as string).trim()) return { allowed: false, reason: `A reviewed ${keyname} is required in options.` };\n if (typeof options.value !== \"string\") return { allowed: false, reason: \"A reviewed value is required in options.\" };\n }\n if (step.kind === \"windowresize\") {\n if (typeof options.width !== \"number\" || typeof options.height !== \"number\" || !Number.isFinite(options.width) || !Number.isFinite(options.height)) return { allowed: false, reason: \"Reviewed width and height numbers are required in options.\" };\n }\n if ((step.kind === \"scrollpage\" || step.kind === \"scrollby\") && (!numericoption(options, \"x\") || !numericoption(options, \"y\"))) return { allowed: false, reason: \"Scroll amounts must be numbers in options.\" };\n if (step.kind === \"waitfor\" && options.timeout !== undefined && (typeof options.timeout !== \"number\" || options.timeout < 0)) return { allowed: false, reason: \"The waitfor timeout must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"movepointer\") {\n const path = options.pointpath;\n if (!path || typeof path !== \"object\" || Array.isArray(path)) return { allowed: false, reason: \"A reviewed pointpath with start and end points is required in options.\" };\n const points = path as Record<string, unknown>;\n if (!ispoint(points.start) || !ispoint(points.end)) return { allowed: false, reason: \"The reviewed pointpath needs numeric start and end points.\" };\n if (points.waypoints !== undefined && (!Array.isArray(points.waypoints) || !points.waypoints.every(waypoint => ispoint(waypoint)))) return { allowed: false, reason: \"The reviewed pointpath waypoints must be numeric points.\" };\n if (!nonnegativeoption(points, \"duration\")) return { allowed: false, reason: \"The reviewed pointpath duration must be zero or a positive number of milliseconds.\" };\n const speed = options.speedprofile;\n if (speed !== undefined) {\n if (!speed || typeof speed !== \"object\" || Array.isArray(speed)) return { allowed: false, reason: \"The reviewed speed profile must be an object.\" };\n const profile = speed as Record<string, unknown>;\n if (profile.easing !== undefined && profile.easing !== \"linear\" && profile.easing !== \"easeinout\") return { allowed: false, reason: \"The reviewed easing must be linear or easeinout.\" };\n if (!nonnegativeoption(profile, \"peak\")) return { allowed: false, reason: \"The reviewed peak velocity must be zero or a positive number.\" };\n if (!nonnegativeoption(profile, \"jitter\")) return { allowed: false, reason: \"The reviewed jitter window must be zero or a positive number of milliseconds.\" };\n }\n }\n if (step.kind === \"clickpoint\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"point\")) return { allowed: false, reason: \"A reviewed point target reference is required in options.\" };\n if (step.kind === \"clicktext\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"text\")) return { allowed: false, reason: \"A reviewed text target reference is required in options.\" };\n if (step.kind === \"clickaria\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"aria\")) return { allowed: false, reason: \"A reviewed aria target reference is required in options.\" };\n if (step.kind === \"clickname\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"name\")) return { allowed: false, reason: \"A reviewed name target reference is required in options.\" };\n if (step.kind === \"resolvexpath\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"xpath\")) return { allowed: false, reason: \"A reviewed xpath target reference is required in options.\" };\n if (step.kind === \"typetime\" && options.delay !== undefined && (typeof options.delay !== \"number\" || !Number.isFinite(options.delay) || options.delay < 0)) return { allowed: false, reason: \"The reviewed per keystroke delay must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"submitsearch\") {\n if (!isnonempty(options.results)) return { allowed: false, reason: \"A reviewed results region selector is required in options.\" };\n if (options.timeout !== undefined && (typeof options.timeout !== \"number\" || !Number.isFinite(options.timeout) || options.timeout < 0)) return { allowed: false, reason: \"The submitsearch timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"selectmulti\") {\n const values = options.values;\n if (!Array.isArray(values) || values.length === 0 || !values.every(value => isnonempty(value))) return { allowed: false, reason: \"A reviewed list of option values is required in options.\" };\n }\n if (step.kind === \"setslider\") {\n const slider = Number(step.value);\n if (!Number.isFinite(slider)) return { allowed: false, reason: \"The reviewed slider value must be a number.\" };\n }\n if (step.kind === \"setdate\" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed date must use the yyyy-mm-dd form.\" };\n if (step.kind === \"setcolor\" && !/^#[0-9a-fA-F]{6}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed color must use the #rrggbb form.\" };\n if (step.kind === \"keyhold\" && options.holdid !== undefined && !isnonempty(options.holdid)) return { allowed: false, reason: \"The reviewed hold id must be a non-empty string.\" };\n if (step.kind === \"dismissdialog\") {\n const accept = options.accept;\n const answer = options.answer;\n if (accept === undefined && !isnonempty(answer)) return { allowed: false, reason: \"A reviewed accept flag or prompt answer is required in options.\" };\n if (accept !== undefined && typeof accept !== \"boolean\") return { allowed: false, reason: \"The reviewed dialog accept flag must be a boolean.\" };\n if (answer !== undefined && !isnonempty(answer)) return { allowed: false, reason: \"The reviewed prompt answer must be a non-empty string.\" };\n }\n if (step.kind === \"pierceshadow\" && options.shadow !== undefined) {\n if (!Array.isArray(options.shadow) || !options.shadow.every(item => isnonempty(item))) return { allowed: false, reason: \"The reviewed shadow path must be a list of non-empty selectors.\" };\n }\n if (step.kind === \"enterframe\") {\n const path = options.framepath;\n if (!Array.isArray(path) || path.length === 0 || !path.every(item => typeof item === \"number\" && Number.isInteger(item) && item >= 0)) return { allowed: false, reason: \"A reviewed frame path of frame indexes is required in options.\" };\n return validateinnerstep(options, origin);\n }\n if (step.kind === \"retryaction\") {\n const inner = validateinnerstep(options, origin);\n if (!inner.allowed) return inner;\n const rule = options.retryrule;\n if (!rule || typeof rule !== \"object\" || Array.isArray(rule)) return { allowed: false, reason: \"A reviewed retry rule with attempts is required in options.\" };\n const retry = rule as Record<string, unknown>;\n if (typeof retry.attempts !== \"number\" || !Number.isInteger(retry.attempts) || retry.attempts < 1) return { allowed: false, reason: \"The reviewed retry attempts must be a positive integer with no code ceiling.\" };\n if (!nonnegativeoption(retry, \"settle\")) return { allowed: false, reason: \"The reviewed retry settle window must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(retry, \"tolerance\")) return { allowed: false, reason: \"The reviewed retry movement tolerance must be zero or a positive number of pixels.\" };\n }\n if (watchactions.has(step.kind)) {\n if (typeof options.lifetime !== \"number\" || !Number.isFinite(options.lifetime) || options.lifetime <= 0) return { allowed: false, reason: \"A reviewed watch lifetime window in milliseconds is required in options.\" };\n if (options.scopes !== undefined && (!Array.isArray(options.scopes) || !options.scopes.every(scope => isnonempty(scope)))) return { allowed: false, reason: \"The reviewed watch scopes must be a list of non-empty selectors.\" };\n if (options.events !== undefined && (!Array.isArray(options.events) || !options.events.every(event => isnonempty(event)))) return { allowed: false, reason: \"The reviewed watch event kinds must be a list of non-empty strings.\" };\n if (!nonnegativeoption(options, \"poll\")) return { allowed: false, reason: \"The reviewed watch poll interval must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"waitquiet\") {\n const rule = options.quietrule;\n if (!rule || typeof rule !== \"object\" || Array.isArray(rule)) return { allowed: false, reason: \"A reviewed quietrule with an idle threshold is required in options.\" };\n const quiet = rule as Record<string, unknown>;\n if (typeof quiet.idle !== \"number\" || !Number.isFinite(quiet.idle) || quiet.idle <= 0) return { allowed: false, reason: \"The reviewed quiet idle threshold must be a positive number of milliseconds with no code ceiling.\" };\n if (!nonnegativeoption(quiet, \"poll\")) return { allowed: false, reason: \"The reviewed quiet poll interval must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(quiet, \"timeout\")) return { allowed: false, reason: \"The reviewed quiet timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"diffsnapshots\") {\n const versions = options.versions;\n if (!Array.isArray(versions) || versions.length !== 2 || !versions.every(version => typeof version === \"number\" && Number.isInteger(version) && version >= 1)) return { allowed: false, reason: \"Two reviewed observation version numbers are required in options.\" };\n }\n if (step.kind === \"openlink\" || step.kind === \"openprivate\" || step.kind === \"deeplink\") {\n const targetcheck = validatenavtarget(options.navtarget, step.kind);\n if (!targetcheck.allowed) return targetcheck;\n if (step.kind === \"deeplink\") {\n const app = options.app;\n if (!isnonempty(app)) return { allowed: false, reason: \"A reviewed deep link app pattern is required in options.\" };\n const params = options.params;\n if (params !== undefined && (!params || typeof params !== \"object\" || Array.isArray(params) || !Object.values(params).every(item => typeof item === \"string\"))) return { allowed: false, reason: \"The reviewed deep link params must be an object of string values.\" };\n }\n }\n if (step.kind === \"waitload\" && !nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The waitload timeout must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"waiturl\" || step.kind === \"spawait\") {\n if (step.kind === \"waiturl\") {\n const patterncheck = validateurlpattern(options.urlpattern);\n if (!patterncheck.allowed) return patterncheck;\n }\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The wait timeout must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(options, \"poll\")) return { allowed: false, reason: \"The wait poll interval must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"followlink\") {\n if (options.fragment !== undefined && typeof options.fragment !== \"boolean\") return { allowed: false, reason: \"The reviewed followlink fragment flag must be a boolean.\" };\n }\n if (step.kind === \"spanav\") {\n if (options.routepattern !== undefined) {\n const routecheck = validateurlpattern(options.routepattern);\n if (!routecheck.allowed) return routecheck;\n }\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The spanav route timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"rewritequery\") {\n const set = options.set;\n const remove = options.remove;\n if (set === undefined && remove === undefined) return { allowed: false, reason: \"Reviewed query parameters to set or remove are required in options.\" };\n if (set !== undefined && (!set || typeof set !== \"object\" || Array.isArray(set) || !Object.values(set).every(item => typeof item === \"string\"))) return { allowed: false, reason: \"The reviewed query parameters to set must be an object of string values.\" };\n if (remove !== undefined && (!Array.isArray(remove) || !remove.every(item => isnonempty(item)))) return { allowed: false, reason: \"The reviewed query parameters to remove must be a list of non-empty names.\" };\n }\n if (step.kind === \"navlist\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (step.kind === \"navprofile\") {\n const profilecheck = validatewaitprofile(options.waitprofile);\n if (!profilecheck.allowed) return profilecheck;\n }\n if (step.kind === \"handleauth\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS origin or url is required as the auth target.\" };\n if (step.kind === \"printpdf\" && options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed artifact name must be a non-empty string.\" };\n if (step.kind === \"prefetch\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (step.kind === \"preconnect\") {\n const origins = options.origins;\n if (!Array.isArray(origins) || origins.length === 0 || !origins.every(originurl => ishttpsurl(originurl))) return { allowed: false, reason: \"A reviewed non-empty list of HTTPS origins is required in options.\" };\n }\n if (step.kind === \"reopentab\" && step.value !== undefined && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed reopen url must use HTTPS.\" };\n if (step.kind === \"navrate\") {\n const limitcheck = validateratelimit(options.ratelimit);\n if (!limitcheck.allowed) return limitcheck;\n }\n if (step.kind === \"checksafe\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS url is required for the safety check.\" };\n if (step.kind === \"batchopen\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (istabscommandkind(step.kind)) {\n const tabscheck = validatetabsgrammar(step, options);\n if (!tabscheck.allowed) return tabscheck;\n }\n if (isformkind(step.kind)) {\n const formcheck = validateformgrammar(step, options);\n if (!formcheck.allowed) return formcheck;\n }\n if (isdatasetkind(step.kind)) {\n const datacheck = validatedatagrammar(step, options, origin);\n if (!datacheck.allowed) return datacheck;\n }\n if (isfileskind(step.kind)) {\n const filescheck = validatefilesgrammar(step, options);\n if (!filescheck.allowed) return filescheck;\n }\n if (step.kind === \"tabcreate\") {\n if (options.background !== undefined && typeof options.background !== \"boolean\") return { allowed: false, reason: \"The reviewed background flag must be a boolean.\" };\n if (options.window !== undefined && (typeof options.window !== \"number\" || !Number.isInteger(options.window) || options.window < 0)) return { allowed: false, reason: \"The reviewed target window id must be a non-negative integer.\" };\n }\n if (step.kind === \"windowcreate\") {\n for (const field of [\"left\", \"top\", \"width\", \"height\"]) {\n if (options[field] !== undefined && (typeof options[field] !== \"number\" || !Number.isFinite(options[field]))) return { allowed: false, reason: `The reviewed window ${field} must be a number.` };\n }\n if (options.state !== undefined && ![\"normal\", \"maximized\", \"minimized\", \"fullscreen\"].includes(options.state as string)) return { allowed: false, reason: \"The reviewed window state must be normal, maximized, minimized or fullscreen.\" };\n }\n return { allowed: true };\n}\n\n/** Shared session gate: a live, unpaused session that still matches the active tab. */\nfunction sessiongate(input: { session: agentsession | undefined; tabid: number; origin: string; now: number; action: string }): policyevaluation {\n if (!input.session || input.session.stoppedat) return { allowed: false, reason: \"No active browser session exists.\" };\n if (input.session.expiresat <= input.now) return { allowed: false, reason: \"The browser session has expired.\" };\n if (input.session.pausedat) return { allowed: false, reason: `The browser session is paused and cannot ${input.action}.` };\n if (input.session.tabid !== input.tabid || input.session.origin !== input.origin) return { allowed: false, reason: `The ${input.action} is outside the approved tab or origin.` };\n return { allowed: true };\n}\n\n/** Applies the consent gate immediately before an action reaches the page bridge. */\nexport function canexecute(input: { session: agentsession | undefined; plan: agentplan | undefined; step: toolstep; tabid: number; origin: string; now?: number; verdicts?: safetyverdict[] }): policyevaluation {\n const now = input.now ?? Date.now();\n const gate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now, action: \"execute an action\" });\n if (!gate.allowed) return gate;\n if (!input.plan || input.plan.state !== \"approved\") return { allowed: false, reason: \"The plan has not received explicit approval.\" };\n if (input.plan.expiresat <= now) return { allowed: false, reason: \"The approved plan has expired.\" };\n if ((input.step.kind === \"pierceshadow\" || input.step.kind === \"enterframe\") && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The shadow or frame step is outside the session origin grants.\" };\n if (input.step.kind === \"readjson\" && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The json state read is outside the session origin grants.\" };\n if (isexportkind(input.step.kind)) {\n const exportgate = exportgranted(input.session, input.origin);\n if (!exportgate.allowed) return exportgate;\n }\n if (input.step.kind === \"navlist\") {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n for (const url of Array.isArray(options.urls) ? options.urls : []) {\n if (typeof url !== \"string\") continue;\n const navigation = navigationgranted(input.session, url);\n if (!navigation.allowed) return navigation;\n }\n }\n if (islayoutkind(input.step.kind) && !layoutmutationgranted(input.session, now).allowed) return { allowed: false, reason: \"Group and layout mutations stay inside the active session.\" };\n if (input.step.kind === \"submitform\" || input.step.kind === \"retryform\") {\n if (!input.plan) return { allowed: false, reason: \"Form submission requires an asksubmit review step before it.\" };\n const reviewgate = submitreviewgranted(input.plan.steps, input.step.id);\n if (!reviewgate.allowed) return reviewgate;\n }\n if (input.step.kind === \"consentpassword\") {\n const consentgate = passwordconsentgranted(input.step);\n if (!consentgate.allowed) return consentgate;\n }\n if (input.step.kind === \"readclipboard\") {\n const clipgate = clipboardconsentgranted(input.step);\n if (!clipgate.allowed) return clipgate;\n }\n if (input.step.kind === \"interceptmime\" && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The download interception is outside the session origin grants.\" };\n if (input.step.kind === \"openlink\" || input.step.kind === \"openprivate\" || input.step.kind === \"batchopen\" || input.step.kind === \"prefetch\" || input.step.kind === \"deeplink\" || input.step.kind === \"reopentab\") {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n const grammar = validatestep(input.step, input.origin);\n if (!grammar.allowed) return grammar;\n const grants = input.session?.grants ?? [input.session?.origin ?? input.origin];\n const targets: unknown[] = input.step.kind === \"batchopen\" || input.step.kind === \"prefetch\" ? (Array.isArray(options.urls) ? options.urls : []) : input.step.kind === \"reopentab\" ? [input.step.value] : [(options.navtarget as Record<string, unknown> | undefined)?.url];\n for (const target of targets) {\n if (typeof target !== \"string\" || !target) continue;\n const verified = originverified(target, grants, input.verdicts ?? []);\n if (!verified.allowed) return verified;\n }\n }\n return validatestep(input.step, input.origin);\n}\n\n/** Allows a non-mutating, temporary target preview during plan review. */\nexport function canpreview(input: { session: agentsession | undefined; plan: agentplan | undefined; step: toolstep; tabid: number; origin: string; now?: number }): policyevaluation {\n const now = input.now ?? Date.now();\n const gate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now, action: \"preview a target\" });\n if (!gate.allowed) return gate;\n if (!input.plan || ![\"pending\", \"approved\"].includes(input.plan.state)) return { allowed: false, reason: \"Only a reviewed pending or approved plan can be previewed.\" };\n if (input.plan.expiresat <= now) return { allowed: false, reason: \"The reviewed plan has expired.\" };\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n if (!targetactions.has(input.step.kind) && options.targetref === undefined) return { allowed: false, reason: \"Only a target-based action can be previewed.\" };\n return validatestep(input.step, input.origin);\n}\n", "import type { tabgrouprecord, tablayout, tabquery, tabwatchevent, toolstep } from \"../types.js\";\nimport { parseoptions } from \"../policy.js\";\nimport { assigntasktab, tasktabs } from \"../progress.js\";\nimport type { planprogress } from \"../types.js\";\n\n/**\n * Tabs and windows command logics for reviewed steps.\n * Every correlated rule for tab queries, clone detection, group membership, layouts, snapshots, watchers, badges, discard candidates, switcher order, zoom steps and the task tab budget lives in this file.\n */\n\n/** One serializable live tab shape resolved against the browser tab set. */\nexport interface tabshape {\n tabid: number;\n url: string;\n title: string;\n index: number;\n windowid: number;\n active: boolean;\n pinned: boolean;\n audible: boolean;\n muted: boolean;\n discarded: boolean;\n}\n\n/** One serializable live window shape with bounds, state and profile kind. */\nexport interface windowshape {\n windowid: number;\n left: number;\n top: number;\n width: number;\n height: number;\n state: \"normal\" | \"maximized\" | \"minimized\" | \"fullscreen\";\n incognito: boolean;\n focused: boolean;\n}\n\n/** Reads the reviewed tabquery of a tabs and windows command step; null when the step reviews none. */\nexport function parsetabquery(step: toolstep): tabquery | null {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const value = options.tabquery;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const query = value as Record<string, unknown>;\n return {\n ...(typeof query.url === \"string\" && query.url ? { url: query.url } : {}),\n ...(typeof query.title === \"string\" && query.title ? { title: query.title } : {}),\n ...(typeof query.id === \"number\" && Number.isInteger(query.id) && query.id >= 0 ? { id: query.id } : {}),\n ...(typeof query.pattern === \"string\" && query.pattern ? { pattern: query.pattern } : {}),\n };\n}\n\n/** Matches one reviewed wildcard pattern against a url; `*` spans one path segment and `**` spans any part. */\nexport function tabpatternmatches(pattern: string, url: string): boolean {\n const source = pattern.split(\"**\").map(part => part.split(\"*\").map(piece => piece.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\"[^/]*\")).join(\".*\");\n return new RegExp(`^${source}$`).test(url);\n}\n\n/** Resolves one reviewed tabquery against the live tab set: every matcher that exists must hold. */\nexport function querymatches(query: tabquery, tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => {\n if (query.id !== undefined && tab.tabid !== query.id) return false;\n if (query.url !== undefined && tab.url !== query.url) return false;\n if (query.title !== undefined && !tab.title.toLowerCase().includes(query.title.toLowerCase())) return false;\n if (query.pattern !== undefined && !tabpatternmatches(query.pattern, tab.url)) return false;\n return true;\n });\n}\n\n/** Normalizes one url for clone comparison by dropping the fragment and trailing slashes. */\nexport function normalizedtaburl(url: string): string {\n let normalized = url;\n const hash = normalized.indexOf(\"#\");\n if (hash >= 0) normalized = normalized.slice(0, hash);\n while (normalized.length > 1 && normalized.endsWith(\"/\")) normalized = normalized.slice(0, -1);\n return normalized;\n}\n\n/** One clone warning: a normalized url shared by more than one open tab. */\nexport interface clonewarning {\n url: string;\n tabids: number[];\n}\n\n/** Detects duplicate tabs by normalized url comparison and returns every url held by more than one tab. */\nexport function clonetabs(tabs: tabshape[]): clonewarning[] {\n const groups = new Map<string, number[]>();\n for (const tab of tabs) {\n if (!tab.url) continue;\n const key = normalizedtaburl(tab.url);\n groups.set(key, [...(groups.get(key) ?? []), tab.tabid]);\n }\n return [...groups.entries()].filter(([, tabids]) => tabids.length > 1).map(([url, tabids]) => ({ url, tabids }));\n}\n\n/** Searches across open tabs by title and url, case insensitive, returning matches in live order. */\nexport function searchtabmatches(tabs: tabshape[], text: string): tabshape[] {\n const needle = text.trim().toLowerCase();\n if (!needle) return [];\n return tabs.filter(tab => tab.title.toLowerCase().includes(needle) || tab.url.toLowerCase().includes(needle));\n}\n\n/** Lists the tabs that are playing audio: audible or muted but still playing. */\nexport function audiotabs(tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => tab.audible || (tab.muted && tab.audible));\n}\n\n/** Returns the inactive, unpinned and not yet discarded tabs a discardtab step may release. */\nexport function discardcandidates(tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => !tab.active && !tab.pinned && !tab.discarded && tab.url.length > 0);\n}\n\n/** Restores discarded tabs on demand without losing their urls; every discarded tab keeps its url for reload. */\nexport function restorediscarded(tabs: tabshape[]): Array<{ tabid: number; url: string }> {\n return tabs.filter(tab => tab.discarded && tab.url.length > 0).map(tab => ({ tabid: tab.tabid, url: tab.url }));\n}\n\n/** Captures one tab layout with name, tabs, groups, positions and window bounds from the live browser state. */\nexport function buildlayout(name: string, tabs: tabshape[], windows: windowshape[], groups: tabgrouprecord[], scratchwindowids: number[], at: number): tablayout {\n return {\n name,\n tabs: tabs.map(tab => ({ url: tab.url, title: tab.title, pinned: tab.pinned, index: tab.index, windowid: tab.windowid })),\n groups: groups.map(group => ({ name: group.name, color: group.color, tabids: group.tabids.filter(tabid => tabs.some(tab => tab.tabid === tabid)), collapsed: group.collapsed })),\n windows: windows.map(item => ({ windowid: item.windowid, state: { bounds: { left: item.left, top: item.top, width: item.width, height: item.height }, maximized: item.state === \"maximized\", profile: item.incognito ? \"incognito\" : scratchwindowids.includes(item.windowid) ? \"scratch\" : \"normal\" } })),\n savedat: at,\n };\n}\n\n/** Plans the restore of one saved layout: only urls that are not already open come back, in layout order. */\nexport function layoutrestoreplan(layout: tablayout, openurls: string[]): string[] {\n const open = new Set(openurls.map(url => normalizedtaburl(url)));\n return layout.tabs.map(tab => tab.url).filter(url => url.length > 0 && !open.has(normalizedtaburl(url)));\n}\n\n/** Keeps tabgroup membership through moves: member ids survive, their order follows the live tab order and closed members drop out. */\nexport function regroupaftermoves(groups: tabgrouprecord[], tabs: tabshape[], at: number): tabgrouprecord[] {\n const order = new Map(tabs.map(tab => [tab.tabid, tab.index]));\n return groups.map(group => {\n const members = group.tabids.filter(tabid => order.has(tabid));\n if (members.length === 0) return group;\n const ordered = [...members].sort((left, right) => (order.get(left) ?? 0) - (order.get(right) ?? 0));\n return ordered.length === group.tabids.length && ordered.every((tabid, index) => tabid === group.tabids[index]) ? group : { ...group, tabids: ordered, savedat: at };\n });\n}\n\n/** Renames one stored tab group while keeping its color choice, member tabs and collapse state. */\nexport function renamegroup(groups: tabgrouprecord[], name: string, newname: string, at: number): tabgrouprecord[] {\n return groups.map(group => group.name === name ? { ...group, name: newname, savedat: at } : group);\n}\n\n/** Counts the task tabs that live inside one window so the close gate can demand review. */\nexport function tasktabsinwindow(tabs: tabshape[], windowid: number, tasktabids: number[]): number {\n const tasks = new Set(tasktabids);\n return tabs.filter(tab => tab.windowid === windowid && tasks.has(tab.tabid)).length;\n}\n\n/** Selects the tabs a reviewed closepattern may close; the session tab itself is always refused protection. */\nexport function closeselection(query: tabquery, tabs: tabshape[], sessiontabid: number): { targets: tabshape[]; refused: tabshape[] } {\n const matches = querymatches(query, tabs);\n return {\n targets: matches.filter(tab => tab.tabid !== sessiontabid),\n refused: matches.filter(tab => tab.tabid === sessiontabid),\n };\n}\n\n/** Applies one reviewed zoom step with no code ceiling; a step never crosses zero, so it keeps the current zoom instead. */\nexport function zoomstep(current: number, direction: \"in\" | \"out\", step: number): number {\n const next = direction === \"in\" ? current + step : current - step;\n return next > 0 ? Number(next.toFixed(4)) : current;\n}\n\n/** Resolves the neighbor tab index a switchtab step activates, wrapping at both ends of the window. */\nexport function switchtarget(tabs: tabshape[], direction: \"next\" | \"previous\", currentindex: number): number | undefined {\n if (tabs.length === 0) return undefined;\n const offset = direction === \"next\" ? 1 : -1;\n return (currentindex + offset + tabs.length) % tabs.length;\n}\n\n/** Orders the quick switcher list by recency with filter keys; unseen tabs follow in live index order. */\nexport function switcherlist(tabs: tabshape[], recency: Array<{ tabid: number; at: number }>, filter: string): tabshape[] {\n const needle = filter.trim().toLowerCase();\n const matches = needle ? tabs.filter(tab => tab.title.toLowerCase().includes(needle) || tab.url.toLowerCase().includes(needle)) : [...tabs];\n const lastrun = new Map(recency.map(entry => [entry.tabid, entry.at]));\n return [...matches].sort((left, right) => {\n const leftat = lastrun.get(left.tabid) ?? -1;\n const rightat = lastrun.get(right.tabid) ?? -1;\n if (leftat !== rightat) return rightat - leftat;\n return left.index - right.index;\n });\n}\n\n/** Dispatches the tab events of one watchtab registration into the step result, honoring the reviewed event filters. */\nexport function watchtabdispatch(events: tabwatchevent[], watchid: string, filters: string[]): tabwatchevent[] {\n const allowed = filters.length > 0 ? new Set(filters) : undefined;\n return events.filter(event => event.watchid === watchid && (allowed === undefined || allowed.has(event.event)));\n}\n\n/** Computes the per task badge from the live progress state of the task. */\nexport function badgefromprogress(completed: number, total: number): { label: string; done: boolean } {\n if (total <= 0) return { label: \"idle\", done: false };\n if (completed >= total) return { label: \"done\", done: true };\n return { label: `${completed}/${total}`, done: false };\n}\n\n/** Grades the concurrent task tab budget: a user configured ceiling refuses, an absent ceiling never refuses. */\nexport function tasktabgauge(used: number, ceiling: number | undefined): { used: number; ceiling: number | undefined; over: boolean } {\n return { used, ceiling, over: ceiling !== undefined && used > ceiling };\n}\n\n/** True when a window profile inherits the session origin grants; incognito windows stay separated. */\nexport function windowprofilegrants(profile: \"normal\" | \"incognito\" | \"scratch\"): boolean {\n return profile !== \"incognito\";\n}\n\n/** Assigns every task tab of the plan progress, used when tabmeta routing records a tab for the plan steps. */\nexport function assigntasktabs(progress: planprogress | undefined, planid: string, tabids: number[], now: number): planprogress {\n let next = progress;\n for (const tabid of tabids) next = assigntasktab(next, planid, tabid, now);\n return next ?? { planid, completedsteps: [], tasktabs: [], updatedat: now };\n}\n\n/** Returns the task tabs tracked by one plan progress, used for window close review and badge refresh. */\nexport function trackedtasktabs(progress: planprogress | undefined, planid: string): number[] {\n return tasktabs(progress, planid);\n}\n", "import type { fielderror, fieldkind, fieldmatch, formrecord, formentry, formreport, toolstep } from \"../types.js\";\nimport { parseoptions } from \"../policy.js\";\nimport type { stepresult } from \"./pageactions.js\";\nimport { clean, elementlabel as label, elementselector as selector } from \"./pageresolve.js\";\n\n/**\n * Form field logics for reviewed steps.\n * Every correlated rule for field matching, field kind classification, seeded value generation, native value fills, honeypot detection, login and template detection, error association and form record parsing lives in this file.\n */\n\n/** One serializable form field shape resolved against the page controls. */\nexport interface fieldshape {\n selector: string;\n tag: string;\n type: string;\n name: string;\n label: string;\n placeholder: string;\n arialabel: string;\n autocomplete: string;\n options?: string[];\n}\n\n/** One surveyed field shape carrying the visibility, geometry and timing evidence the honeypot detector reads. */\nexport interface fieldsurvey extends fieldshape {\n hidden: boolean;\n offscreen: boolean;\n createdat?: number;\n}\n\n/** One honeypot field flagged by hidden, offscreen or time trap evidence. */\nexport interface honeypotevidence {\n selector: string;\n reason: \"hidden\" | \"offscreen\" | \"timetrap\";\n}\n\n/** One surveyed field with the aria describedby ref and the sibling message texts the error reader associates. */\nexport interface errorcontext extends fieldshape {\n describedby?: string;\n siblings: string[];\n}\n\n/** Resolves controls by label, placeholder, aria label and name attributes; matches are case insensitive substrings. */\nexport function matchfield(fields: fieldshape[], match: fieldmatch): fieldshape[] {\n const key = match.mode === \"label\" ? \"label\" : match.mode === \"placeholder\" ? \"placeholder\" : match.mode === \"arialabel\" ? \"arialabel\" : \"name\";\n const needle = (match[key] ?? \"\").trim().toLowerCase();\n if (!needle) return [];\n return fields.filter(field => {\n const primary = (field[key] as string).toLowerCase();\n const secondary = match.mode === \"label\" || match.mode === \"name\" ? field.name.toLowerCase() : match.mode === \"placeholder\" ? field.arialabel.toLowerCase() : field.placeholder.toLowerCase();\n return primary.includes(needle) || secondary.includes(needle);\n });\n}\n\n/** Infers the field kind of one control from its input type, autocomplete hint and label text. */\nexport function classifyfield(input: { type: string; autocomplete: string; label: string }): fieldkind {\n const type = input.type.toLowerCase();\n const autocomplete = input.autocomplete.toLowerCase();\n const label = input.label.toLowerCase();\n if (type === \"password\") return \"password\";\n if (autocomplete.startsWith(\"cc-\") || label.includes(\"card number\") || label.includes(\"credit card\") || label.includes(\"cardholder\")) return \"card\";\n if (autocomplete.includes(\"one-time-code\") || autocomplete.includes(\"otp\") || label.includes(\"one time code\") || label.includes(\"verification code\") || label.includes(\"otp\")) return \"code\";\n if (type === \"email\" || autocomplete.includes(\"email\") || label.includes(\"email\")) return \"email\";\n if (type === \"tel\" || autocomplete.includes(\"tel\") || label.includes(\"phone\") || label.includes(\"telephone\")) return \"phone\";\n if (type === \"date\") return \"date\";\n if (type === \"number\") return \"number\";\n if (type === \"checkbox\") return \"check\";\n if (type === \"radio\") return \"radio\";\n if (type === \"file\") return \"file\";\n if (type === \"select\" || type === \"select-one\") return \"select\";\n return \"text\";\n}\n\nconst firstnames: Record<string, string[]> = { en: [\"alex\", \"jordan\", \"taylor\", \"morgan\", \"casey\"], pt: [\"ana\", \"bruno\", \"carla\", \"diego\", \"helena\"] };\nconst lastnames: Record<string, string[]> = { en: [\"brooks\", \"carter\", \"diaz\", \"evans\", \"reyes\"], pt: [\"alves\", \"costa\", \"lima\", \"souza\", \"moraes\"] };\n\nfunction localekey(locale: string): string {\n const normalized = locale.toLowerCase();\n if (normalized.startsWith(\"pt\")) return \"pt\";\n return \"en\";\n}\n\n/** Generates one realistic value for a field kind, deterministically seeded and locale aware for names, emails and phones. */\nexport function generatevalue(kind: fieldkind, rule: { locale?: string; seed?: number }): string {\n const seed = typeof rule.seed === \"number\" && Number.isFinite(rule.seed) ? Math.abs(Math.floor(rule.seed)) : 1;\n const names = firstnames[localekey(rule.locale ?? \"en\")] ?? firstnames.en ?? [\"alex\"];\n const surnames = lastnames[localekey(rule.locale ?? \"en\")] ?? lastnames.en ?? [\"brooks\"];\n let state = seed * 1103515245 + 12345;\n const next = (): number => { state = (state * 1103515245 + 12345) % 2147483648; return state / 2147483648; };\n const pick = <T>(items: T[]): T => items[Math.floor(next() * items.length) % items.length] ?? items[0] as T;\n const digits = (count: number): string => Array.from({ length: count }, () => String(Math.floor(next() * 10))).join(\"\");\n const person = `${pick(names)} ${pick(surnames)}`;\n switch (kind) {\n case \"email\": return `${person.replace(\" \", \".\")}${digits(2)}@example.com`;\n case \"phone\": return localekey(rule.locale ?? \"en\") === \"pt\" ? `+55 (11) 9${digits(4)}-${digits(4)}` : `+1 (555) 010-${digits(4)}`;\n case \"date\": return `${2024 + Math.floor(next() * 2)}-${String(1 + Math.floor(next() * 12)).padStart(2, \"0\")}-${String(1 + Math.floor(next() * 28)).padStart(2, \"0\")}`;\n case \"number\": return String(Math.floor(next() * 1000));\n case \"select\": return `option ${1 + Math.floor(next() * 5)}`;\n case \"check\": return next() > 0.5 ? \"true\" : \"false\";\n case \"radio\": return `choice ${1 + Math.floor(next() * 4)}`;\n case \"file\": return `sample${digits(2)}.pdf`;\n case \"password\": return `pw-${digits(6)}-${pick(names)}`;\n case \"card\": return `4111 ${digits(4)} ${digits(4)} ${digits(4)}`;\n case \"code\": return digits(6);\n default: return person;\n }\n}\n\n/** Builds a deterministic values hash of the reviewed field values a submission ticket records. */\nexport function valueshash(values: Array<{ label: string; value: string }>): string {\n const source = values.map(entry => `${entry.label}=${entry.value}`).join(\"|\");\n let hash = 5381;\n for (let index = 0; index < source.length; index += 1) hash = ((hash * 33) ^ source.charCodeAt(index)) >>> 0;\n return hash.toString(16);\n}\n\n/** Parses the reviewed structured form record of a step; null when the step reviews none or the shape is invalid. */\nexport function parseformrecord(value: unknown): formrecord | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n if (!Array.isArray(record.entries)) return null;\n const entries: formentry[] = [];\n for (const item of record.entries) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const entry = item as Record<string, unknown>;\n const match = entry.match;\n if (!match || typeof match !== \"object\" || Array.isArray(match)) continue;\n const shapes = match as Record<string, unknown>;\n if (typeof shapes.mode !== \"string\") continue;\n const fieldmatch: fieldmatch = {\n mode: shapes.mode as fieldmatch[\"mode\"],\n ...(typeof shapes.label === \"string\" ? { label: shapes.label } : {}),\n ...(typeof shapes.placeholder === \"string\" ? { placeholder: shapes.placeholder } : {}),\n ...(typeof shapes.arialabel === \"string\" ? { arialabel: shapes.arialabel } : {}),\n ...(typeof shapes.name === \"string\" ? { name: shapes.name } : {}),\n };\n if (typeof entry.kind !== \"string\" || typeof entry.value !== \"string\") continue;\n entries.push({ match: fieldmatch, kind: entry.kind as fieldkind, value: entry.value });\n }\n if (entries.length === 0) return null;\n return { ...(typeof record.form === \"string\" && record.form ? { form: record.form } : {}), entries };\n}\n\n/** Builds form record entries from reviewed label or placeholder value pairs. */\nexport function pairentries(pairs: Array<{ label?: string; placeholder?: string; value: string }>, mode: \"label\" | \"placeholder\"): formrecord {\n return { entries: pairs.map(pair => ({ match: mode === \"label\" ? { mode, label: pair.label ?? \"\" } : { mode, placeholder: pair.placeholder ?? \"\" }, kind: \"text\", value: pair.value })) };\n}\n\n/** One fill operation outcome: the entry, the matched control, the honeypot skip flag or the refusal reason. */\nexport interface filloutcome {\n entry: formentry;\n matched?: fieldshape;\n skipped?: boolean;\n reason?: string;\n}\n\n/** Resolves every entry of a form record against the surveyed fields, skipping honeypots and refusing unmatched or ambiguous entries. */\nexport function filloperations(record: formrecord, fields: fieldshape[], skippedselectors: string[] = []): filloutcome[] {\n return record.entries.map(entry => {\n const matches = matchfield(fields, entry.match);\n if (matches.length === 0) return { entry, reason: \"unmatched\" };\n if (matches.length > 1) return { entry, reason: \"ambiguous\" };\n const matched = matches[0] as fieldshape;\n if (skippedselectors.includes(matched.selector)) return { entry, matched, skipped: true };\n return { entry, matched };\n });\n}\n\n/** Masks one card segment so side panels can render card fills without exposing the full value. */\nexport function cardmask(value: string): string {\n const trimmed = value.trim();\n if (/^\\d[\\d\\s-]{11,18}$/.test(trimmed)) {\n const compact = trimmed.replace(/[\\s-]/g, \"\");\n const last = compact.slice(-4);\n return `${\"\u2022\".repeat(Math.max(0, compact.length - 4))}${last}`;\n }\n return \"\u2022\".repeat(trimmed.length);\n}\n\n/** Flags hidden, offscreen and time trap fields so fill steps skip them instead of tripping anti bot defenses. */\nexport function detecthoneypots(surveys: fieldsurvey[], loadedat: number): honeypotevidence[] {\n const traps: honeypotevidence[] = [];\n for (const field of surveys) {\n if (field.hidden) traps.push({ selector: field.selector, reason: \"hidden\" });\n else if (field.offscreen) traps.push({ selector: field.selector, reason: \"offscreen\" });\n else if (field.createdat !== undefined && loadedat > 0 && field.createdat > loadedat) traps.push({ selector: field.selector, reason: \"timetrap\" });\n }\n return traps;\n}\n\n/** Detects a login form: a password field plus an identifier field with session links nearby. */\nexport function detectlogin(fields: fieldshape[], links: string[]): { login: boolean; markers: string[] } {\n const markers: string[] = [];\n const password = fields.find(field => classifyfield(field) === \"password\");\n if (password) markers.push(\"password field\");\n const identifier = fields.find(field => {\n const kind = classifyfield(field);\n return kind === \"email\" || (kind === \"text\" && /user|login|account|identifier/i.test(`${field.name} ${field.label}`));\n });\n if (identifier) markers.push(\"identifier field\");\n const sessionlink = links.some(link => /sign in|log in|log on|forgot|create account|sign up/i.test(link));\n if (sessionlink) markers.push(\"session link\");\n return { login: Boolean(password && identifier && sessionlink), markers };\n}\n\nconst signupmarkers = [\"sign up\", \"create account\", \"register\", \"confirm password\", \"terms\"];\nconst checkoutmarkers = [\"checkout\", \"payment\", \"billing\", \"shipping\", \"card number\", \"place order\", \"cart\"];\n\n/** Detects signup and checkout templates by matching the field labels, autocompletes and page text against known markers. */\nexport function detecttemplate(fields: fieldshape[], text: string): { template: \"signup\" | \"checkout\" | \"unknown\"; markers: string[] } {\n const corpus = [text, ...fields.map(field => `${field.label} ${field.name} ${field.placeholder} ${field.arialabel} ${field.autocomplete}`)].join(\" \").toLowerCase();\n const signup = signupmarkers.filter(marker => corpus.includes(marker));\n const checkout = checkoutmarkers.filter(marker => corpus.includes(marker));\n if (signup.length >= 2 && signup.length >= checkout.length) return { template: \"signup\", markers: signup };\n if (checkout.length >= 2) return { template: \"checkout\", markers: checkout };\n return { template: \"unknown\", markers: [...signup, ...checkout] };\n}\n\n/** Associates validation messages with fields through aria describedby refs and the sibling text next to each field. */\nexport function associateerrors(contexts: errorcontext[], messages: Array<{ id?: string; text: string }>): fielderror[] {\n const errors: fielderror[] = [];\n for (const field of contexts) {\n const byref = field.describedby ? messages.find(message => message.id === field.describedby && message.text.trim()) : undefined;\n if (byref) { errors.push({ field: field.selector, message: byref.text.trim() }); continue; }\n const sibling = field.siblings.map(text => text.trim()).find(text => text.length > 0);\n if (sibling) errors.push({ field: field.selector, message: sibling });\n }\n return errors;\n}\n\n/** Resolves one reviewed artifact name against the run store before a file input is filled. */\nexport function attachplan(name: string, artifacts: Array<{ id: string; name: string; kind: string }>): { artifact?: { id: string; name: string; kind: string }; reason?: string } {\n const artifact = artifacts.find(item => item.name === name || item.id === name);\n if (!artifact) return { reason: \"The reviewed artifact name is not part of the run store.\" };\n return { artifact };\n}\n\n/** Selectors the captcha detector probes; a hit hands control back to the user instead of forcing the page. */\nexport const captchamarkers = ['iframe[src*=\"recaptcha\"]', 'iframe[title*=\"recaptcha\" i]', '.g-recaptcha', '[data-sitekey]', 'iframe[title*=\"captcha\" i]', '.h-captcha'];\n\n/** True when any captcha marker matched, so the plan pauses and hands control to the user. */\nexport function captchadetected(matched: string[]): boolean {\n return matched.length > 0;\n}\n\nfunction events(target: Element): void {\n target.dispatchEvent(new Event(\"input\", { bubbles: true }));\n target.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\n/** Fills one control through the native setter with input and change events; checks, radios and selects use their own grammar. */\nexport function fillcontrol(element: Element, entry: formentry): boolean {\n if (element instanceof HTMLInputElement && (entry.kind === \"check\" || element.type === \"checkbox\")) { element.checked = entry.value === \"true\" || entry.value === \"on\" || entry.value === \"checked\"; events(element); return true; }\n if (element instanceof HTMLInputElement && (entry.kind === \"radio\" || element.type === \"radio\")) { element.checked = true; events(element); return true; }\n if (element instanceof HTMLSelectElement) {\n const option = [...element.options].find(candidate => candidate.value === entry.value || candidate.textContent?.trim() === entry.value);\n if (!option) return false;\n element.value = option.value;\n events(element);\n return true;\n }\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n if (element instanceof HTMLInputElement && element.type === \"file\") return false;\n element.focus();\n const setter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), \"value\")?.set;\n if (setter) setter.call(element, entry.value); else element.value = entry.value;\n events(element);\n return true;\n }\n return false;\n}\n\nfunction controlshape(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): fieldshape {\n return {\n selector: selector(element),\n tag: element.tagName.toLowerCase(),\n type: element instanceof HTMLSelectElement ? \"select\" : element.getAttribute(\"type\") || \"text\",\n name: element.getAttribute(\"name\") || \"\",\n label: label(element),\n placeholder: element.getAttribute(\"placeholder\") || \"\",\n arialabel: element.getAttribute(\"aria-label\") || \"\",\n autocomplete: element.getAttribute(\"autocomplete\") || \"\",\n ...(element instanceof HTMLSelectElement ? { options: [...element.options].map(option => option.value) } : {}),\n };\n}\n\n/** Collects the serializable field shapes of one form scope; absent scopes survey the whole document. */\nfunction collectfields(root: Document, formscope?: string): Array<{ shape: fieldshape; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n const scope = formscope ? root.querySelector(formscope) : root;\n if (!scope) return [];\n const controls = [...scope.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\"input, select, textarea\")];\n return controls.filter(element => element.type !== \"hidden\").map(element => ({ shape: controlshape(element), element }));\n}\n\n/** Surveys the visibility and geometry evidence the honeypot detector reads for one form scope. */\nfunction surveyfields(root: Document, formscope?: string): Array<{ survey: fieldsurvey; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n const viewport = { left: 0, top: 0, right: window.innerWidth || 0, bottom: window.innerHeight || 0 };\n return collectfields(root, formscope).map(({ shape, element }) => {\n const rect = element.getBoundingClientRect();\n const hidden = element.getAttribute(\"aria-hidden\") === \"true\" || element.tabIndex < 0 && (element as HTMLElement).offsetParent === null || (element as HTMLElement).offsetParent === null && rect.width === 0 && rect.height === 0;\n const offscreen = rect.width > 0 && rect.height > 0 && (rect.bottom < viewport.top || rect.top > viewport.bottom || rect.right < viewport.left || rect.left > viewport.right);\n return { survey: { ...shape, hidden, offscreen }, element };\n });\n}\n\n/** Reads the error context of one form scope: describedby refs and the sibling texts after each field. */\nfunction collecterrorcontext(root: Document, formscope?: string): Array<{ context: errorcontext; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n return collectfields(root, formscope).map(({ shape, element }) => {\n const siblings: string[] = [];\n let neighbor = element.nextElementSibling;\n for (let index = 0; neighbor && index < 3; index += 1) {\n const text = clean(neighbor.textContent || \"\");\n if (text && text !== shape.label) siblings.push(text);\n neighbor = neighbor.nextElementSibling;\n }\n const describedby = element.getAttribute(\"aria-describedby\");\n return { context: { ...shape, ...(describedby ? { describedby } : {}), siblings }, element };\n });\n}\n\n/** Runs one reviewed forms and data step inside the page: fills, surveys, detects and reads errors without leaving the form scope. */\nexport function runpageform(step: toolstep, target: Element | null, root: Document = document): stepresult | Promise<stepresult> {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const formscope = typeof options.form === \"string\" && options.form ? options.form : step.target;\n switch (step.kind) {\n case \"fillform\": {\n const record = parseformrecord(options.formrecord);\n if (!record) return { ok: false, summary: \"A reviewed form record with entries is required in options.\" };\n const surveys = surveyfields(root, record.form);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const operations = filloperations(record, surveys.map(entry => entry.survey), honeypots.map(trap => trap.selector));\n let filled = 0;\n const skipped: string[] = [];\n const failures: string[] = [];\n const values: Array<{ label: string; value: string }> = [];\n for (const operation of operations) {\n if (operation.skipped && operation.matched) { skipped.push(operation.matched.selector); continue; }\n if (!operation.matched) { failures.push(`${operation.reason}: ${operation.entry.match.label ?? operation.entry.match.name ?? operation.entry.match.placeholder ?? \"field\"}`); continue; }\n const element = surveys.find(entry => entry.survey.selector === operation.matched?.selector)?.element;\n if (!element || !fillcontrol(element, operation.entry)) { failures.push(`unfillable: ${operation.matched.selector}`); continue; }\n filled += 1;\n values.push({ label: operation.matched.label || operation.matched.name, value: operation.entry.kind === \"password\" ? \"\" : operation.entry.value });\n }\n const report: formreport = { form: record.form ?? \"\", fields: operations.map(operation => ({ selector: operation.matched?.selector ?? \"\", label: operation.matched?.label ?? operation.entry.match.label ?? \"\", kind: operation.entry.kind, matched: Boolean(operation.matched) })) };\n return {\n ok: failures.length === 0,\n summary: failures.length === 0 ? `Filled ${filled} reviewed field${filled === 1 ? \"\" : \"s\"} from the structured record${skipped.length > 0 ? ` and skipped ${skipped.length} honeypot field${skipped.length === 1 ? \"\" : \"s\"}` : \"\"}.` : `Filled ${filled} of ${record.entries.length} reviewed fields; ${failures.length} refusals: ${failures.join(\"; \")}.`,\n details: { filled, skipped, failures, values, report },\n };\n }\n case \"filllabel\":\n case \"fillplaceholder\": {\n const mode = step.kind === \"filllabel\" ? \"label\" : \"placeholder\";\n const pairs = Array.isArray(options.fields) ? (options.fields as Array<Record<string, unknown>>).filter(item => item && typeof item === \"object\") : [];\n const record = pairentries(pairs.map(pair => ({ label: typeof pair.label === \"string\" ? pair.label : \"\", placeholder: typeof pair.placeholder === \"string\" ? pair.placeholder : \"\", value: typeof pair.value === \"string\" ? pair.value : \"\" })), mode);\n if (record.entries.length === 0) return { ok: false, summary: \"A reviewed non-empty list of field pairs is required in options.\" };\n const surveys = surveyfields(root, formscope);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const operations = filloperations(record, surveys.map(entry => entry.survey), honeypots.map(trap => trap.selector));\n let filled = 0;\n const failures: string[] = [];\n for (const operation of operations) {\n if (operation.skipped) continue;\n if (!operation.matched) { failures.push(`${operation.reason}: ${mode === \"label\" ? operation.entry.match.label : operation.entry.match.placeholder}`); continue; }\n const element = surveys.find(entry => entry.survey.selector === operation.matched?.selector)?.element;\n const refined: formentry = { ...operation.entry, kind: classifyfield(operation.matched) };\n if (!element || !fillcontrol(element, refined)) { failures.push(`unfillable: ${operation.matched.selector}`); continue; }\n filled += 1;\n }\n return { ok: failures.length === 0, summary: failures.length === 0 ? `Filled ${filled} field${filled === 1 ? \"\" : \"s\"} matched by ${mode}.` : `Filled ${filled} of ${record.entries.length} fields matched by ${mode}; ${failures.join(\"; \")}.`, details: { filled, failures, mode } };\n }\n case \"detectfields\": {\n const collected = collectfields(root, formscope);\n const report: formreport = { form: formscope ?? \"\", fields: collected.map(entry => ({ selector: entry.shape.selector, label: entry.shape.label || entry.shape.name, kind: classifyfield(entry.shape), matched: Boolean(entry.shape.label || entry.shape.name) })) };\n return { ok: true, summary: `Detected ${collected.length} form field${collected.length === 1 ? \"\" : \"s\"} with their kinds.`, details: { report, count: collected.length } };\n }\n case \"generatevalues\": {\n const rule = options.valuegen && typeof options.valuegen === \"object\" && !Array.isArray(options.valuegen) ? options.valuegen as Record<string, unknown> : {};\n const locale = typeof rule.locale === \"string\" ? rule.locale : \"en\";\n const seed = typeof rule.seed === \"number\" && Number.isFinite(rule.seed) ? rule.seed : 1;\n const surveys = surveyfields(root, formscope);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const skippedselectors = new Set(honeypots.map(trap => trap.selector));\n const candidates = surveys.filter(entry => !skippedselectors.has(entry.survey.selector));\n const values = candidates.map(entry => ({ label: entry.survey.label || entry.survey.name || entry.survey.selector, kind: classifyfield(entry.survey), value: generatevalue(classifyfield(entry.survey), { locale, seed }) }));\n const single = values.length === 0 && typeof rule.kind === \"string\" ? [{ label: rule.kind, kind: rule.kind, value: generatevalue(rule.kind as fieldkind, { locale, seed }) }] : values;\n return { ok: true, summary: `Generated ${single.length} realistic value${single.length === 1 ? \"\" : \"s\"} for the detected field kinds.`, details: { values: single, locale, seed } };\n }\n case \"readerrors\": {\n const contexts = collecterrorcontext(root, formscope);\n const messages = [...root.querySelectorAll<HTMLElement>(\"[id]\")].map(element => ({ id: element.id, text: clean(element.textContent || \"\") })).filter(message => message.text.length > 0);\n const errors = associateerrors(contexts.map(entry => entry.context), messages);\n return { ok: true, summary: errors.length === 0 ? \"No validation error was found next to the reviewed fields.\" : `Collected ${errors.length} inline validation message${errors.length === 1 ? \"\" : \"s\"}.`, details: { errors, form: formscope ?? \"\" } };\n }\n case \"skiphoneypot\": {\n const surveys = surveyfields(root, formscope);\n const traps = detecthoneypots(surveys.map(entry => entry.survey), 0);\n return { ok: true, summary: traps.length === 0 ? \"No honeypot field was detected.\" : `Skipped ${traps.length} honeypot field${traps.length === 1 ? \"\" : \"s\"}: ${traps.map(trap => `${trap.selector} (${trap.reason})`).join(\", \")}.`, details: { skipped: traps } };\n }\n case \"detectlogin\": {\n const collected = collectfields(root, formscope);\n const links = [...(formscope ? root.querySelectorAll(formscope) : [root] as unknown as Element[])].flatMap(scope => [...scope.querySelectorAll(\"a[href], button\")]).map(element => clean(element.textContent || \"\"));\n const detection = detectlogin(collected.map(entry => entry.shape), links);\n return { ok: true, summary: detection.login ? `Login form detected with ${detection.markers.join(\", \")}.` : \"No login form was detected.\", details: { login: detection.login, markers: detection.markers } };\n }\n case \"detecttemplate\": {\n const collected = collectfields(root, formscope);\n const text = clean(root.body?.innerText || \"\");\n const detection = detecttemplate(collected.map(entry => entry.shape), text);\n return { ok: true, summary: detection.template === \"unknown\" ? \"No signup or checkout template was detected.\" : `${detection.template} template detected with markers ${detection.markers.join(\", \")}.`, details: { template: detection.template, markers: detection.markers } };\n }\n case \"handoffcaptcha\": {\n const matched = captchamarkers.filter(marker => root.querySelector(marker) !== null);\n return { ok: true, summary: captchadetected(matched) ? `Captcha presence detected (${matched.join(\", \")}); control hands back to the user.` : \"No captcha was detected.\", details: { captcha: captchadetected(matched), markers: matched } };\n }\n case \"asksubmit\": {\n const collected = collectfields(root, step.value || undefined);\n const values = collected.map(entry => ({ label: entry.shape.label || entry.shape.name || entry.shape.selector, value: entry.element instanceof HTMLSelectElement ? entry.element.value : (entry.element as HTMLInputElement).value }));\n return { ok: true, summary: `Read ${values.length} field value${values.length === 1 ? \"\" : \"s\"} for the submission review.`, details: { values } };\n }\n case \"submitform\": {\n const form = target instanceof HTMLFormElement ? target : target instanceof HTMLElement ? target.closest(\"form\") : null;\n if (!form) return { ok: false, summary: \"No owning form was found for the reviewed submission.\" };\n form.requestSubmit();\n return { ok: true, summary: \"Form submitted programmatically through its owning form.\" };\n }\n case \"consentpassword\": {\n if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) return { ok: false, summary: \"The reviewed password target cannot receive text.\" };\n const entry: formentry = { match: { mode: \"name\", name: target.name || target.getAttribute(\"id\") || \"\" }, kind: \"password\", value: step.value ?? \"\" };\n if (!fillcontrol(target, entry)) return { ok: false, summary: \"The password field refused the native setter fill.\" };\n return { ok: true, summary: \"Password field filled after the reviewed consent; the value never appears in the audit trail.\" };\n }\n case \"attachfile\": {\n if (!(target instanceof HTMLInputElement) || target.type !== \"file\") return { ok: false, summary: \"The reviewed target is not a file input.\" };\n const artifactname = typeof options.artifactname === \"string\" && options.artifactname ? options.artifactname : \"artifact\";\n try {\n const file = new File([new Blob([\"devthink artifact\"], { type: \"application/octet-stream\" })], artifactname);\n const transfer = new DataTransfer();\n transfer.items.add(file);\n target.files = transfer.files;\n events(target);\n return { ok: true, summary: `Artifact ${artifactname} attached to the reviewed file input.`, details: { artifact: options.artifact, artifactname } };\n } catch {\n return { ok: false, summary: \"The reviewed file input refused the artifact attachment.\" };\n }\n }\n default: return { ok: false, summary: \"Unsupported forms and data action.\" };\n }\n}\n", "import type { artifactrecord, columnspec, dataset, datasetrow, exportedartifact, extractsession, provenancerecord, streamstate, toolstep, transformrule } from \"../types.js\";\nimport { tocsv, toexcel, tojson } from \"./pagedata.js\";\n\n/**\n * Dataset command logics for the background executors.\n * Every correlated rule for dataset records, artifact exports with checksums, chunked streaming with backpressure, extraction cursors, loop row variables, provenance records and artifact retention lives in this file.\n */\n\n/** Builds one dataset record from a scraped grid result. */\nexport function builddataset(id: string, name: string, grid: { columns: columnspec[]; rows: datasetrow[]; children?: Array<{ parentrow: number; selector: string; columns: columnspec[]; rows: datasetrow[] }> }, at: number): dataset {\n return { id, name: name || id, columns: grid.columns, rows: grid.rows, sources: [], at };\n}\n\n/** Computes the deterministic checksum of an exported artifact's content. */\nexport function checksum(value: string): string {\n let hash = 5381;\n for (let index = 0; index < value.length; index += 1) hash = ((hash * 33) ^ value.charCodeAt(index)) >>> 0;\n return `fnv1a-${hash.toString(16)}`;\n}\n\n/** Serializes one dataset into the reviewed export format. */\nexport function exportcontent(datasetvalue: dataset, format: \"csv\" | \"json\" | \"excel\", delimiter = \",\"): string {\n if (format === \"json\") return tojson(datasetvalue.columns, datasetvalue.rows);\n if (format === \"excel\") return toexcel(datasetvalue.columns, datasetvalue.rows, datasetvalue.name);\n return tocsv(datasetvalue.columns, datasetvalue.rows, delimiter);\n}\n\n/** Builds one exported artifact record with its content and checksum for the task artifact store. */\nexport function exportartifact(id: string, datasetvalue: dataset, format: \"csv\" | \"json\" | \"excel\", stepid: string, content: string, at: number): exportedartifact {\n const extension = format === \"excel\" ? \"xml\" : format;\n return { id, kind: format, name: `${datasetvalue.name || datasetvalue.id}.${extension}`, stepid, rowcount: datasetvalue.rows.length, content, checksum: checksum(content), at };\n}\n\n/** Converts one exported artifact into the artifact record shape the run store keeps. */\nexport function artifactrecordof(artifact: exportedartifact): artifactrecord {\n return { id: artifact.id, kind: artifact.kind, name: artifact.name, stepid: artifact.stepid, at: artifact.at };\n}\n\n/** Plans the chunk boundaries of a streaming export from a user configured chunk size with no code ceiling. */\nexport function chunkplan(rows: number, chunk: number): Array<{ index: number; from: number; to: number }> {\n const size = Math.max(1, Math.floor(chunk));\n const chunks: Array<{ index: number; from: number; to: number }> = [];\n for (let from = 0; from < rows || chunks.length === 0; from += size) {\n const to = Math.min(rows, from + size);\n chunks.push({ index: chunks.length, from, to });\n if (to >= rows) break;\n }\n return chunks;\n}\n\n/** True when the stream writer must wait for acknowledgements: pending writes reached the in-flight budget of one. */\nexport function backpressure(written: number, acknowledged: number): boolean {\n return written - acknowledged >= 1;\n}\n\n/** Advances one stream state by one acknowledged chunk of rows. */\nexport function advancestream(state: streamstate, chunk: { index: number; to: number }, at: number, done: boolean): streamstate {\n return { datasetid: state.datasetid, name: state.name, chunk: chunk.index + 1, chunks: state.chunks, written: chunk.to, ...(done ? { done: true } : {}), at };\n}\n\n/** Returns the first unwritten row index of a stream, starting a fresh stream at zero. */\nexport function streamfrom(state: streamstate | undefined, rows: number): number {\n if (!state || state.done) return 0;\n return Math.min(state.written, rows);\n}\n\n/** Builds the initial stream state of one dataset. */\nexport function newstream(datasetvalue: dataset, chunks: number, at: number): streamstate {\n return { datasetid: datasetvalue.id, name: datasetvalue.name, chunk: 0, chunks, written: 0, at };\n}\n\n/** Advances one extraction session by one extracted page with its row count. */\nexport function advancecursor(sessionvalue: extractsession, page: string, rows: number, at: number, done: boolean): extractsession {\n return {\n id: sessionvalue.id,\n datasetid: sessionvalue.datasetid,\n name: sessionvalue.name,\n target: sessionvalue.target,\n next: sessionvalue.next,\n planned: sessionvalue.planned,\n pages: [...sessionvalue.pages, page],\n rows: sessionvalue.rows + rows,\n cursor: sessionvalue.cursor + 1,\n ...(done || sessionvalue.cursor + 1 >= sessionvalue.planned ? { done: true } : {}),\n startedat: sessionvalue.startedat,\n updatedat: at,\n };\n}\n\n/** Builds the initial extraction session of one dataset extraction. */\nexport function newextractsession(id: string, datasetid: string, name: string, target: string, next: string, planned: number, at: number): extractsession {\n return { id, datasetid, name, target, next, planned, pages: [], rows: 0, cursor: 0, startedat: at, updatedat: at };\n}\n\n/** Returns the pages an interrupted extraction still owes after its stored cursor. */\nexport function remainingpages(sessionvalue: extractsession, planned: number): number {\n if (sessionvalue.done) return 0;\n return Math.max(0, Math.max(sessionvalue.planned, planned) - sessionvalue.cursor);\n}\n\n/** Builds one provenance record of an exported artifact with its source url, step ref, row range and checksum. */\nexport function provenancefor(artifact: { id: string; name: string; rowcount: number; checksum: string }, url: string, stepid: string, at: number): provenancerecord {\n return { artifact: artifact.id, name: artifact.name, url, stepid, rowstart: artifact.rowcount > 0 ? 1 : 0, rowend: artifact.rowcount, checksum: artifact.checksum, at };\n}\n\n/** Applies the user configured artifact retention to exported artifacts; an absent setting keeps everything. */\nexport function retainedexports<T>(records: T[], retention: number | undefined): T[] {\n return retention === undefined ? records : records.slice(0, retention);\n}\n\n/** Interpolates one text through the {{column}} tokens of a dataset row. */\nexport function interpolate(text: string, row: datasetrow): string {\n return text.replace(/\\{\\{([^}]+)\\}\\}/g, (_, key: string) => row[key.trim()] ?? \"\");\n}\n\n/** Substitutes the row variables of one looprows iteration into the target, value and options of the inner step. */\nexport function loopstep(step: toolstep, row: datasetrow): toolstep {\n return {\n ...step,\n ...(step.target !== undefined ? { target: interpolate(step.target, row) } : {}),\n ...(step.value !== undefined ? { value: interpolate(step.value, row) } : {}),\n ...(step.options !== undefined ? { options: interpolate(step.options, row) } : {}),\n };\n}\n\n/** Exposes one dataset row as the step variables of a looprows iteration. */\nexport function loopvariables(row: datasetrow): datasetrow {\n return { ...row };\n}\n\n/** Builds the grid preview of a dataset with its column order, total rows and sampled rows. */\nexport function gridpreview(datasetvalue: dataset, sample: number): { datasetid: string; columns: string[]; rows: number; sample: datasetrow[] } {\n return { datasetid: datasetvalue.id, columns: datasetvalue.columns.map(column => column.key), rows: datasetvalue.rows.length, sample: datasetvalue.rows.slice(0, Math.max(0, Math.floor(sample))) };\n}\n\n/** Sorts dataset rows by one column key in the reviewed direction with a stable fallback for equal values. */\nexport function sortrows(rows: datasetrow[], key: string, direction: \"asc\" | \"desc\"): datasetrow[] {\n const sign = direction === \"desc\" ? -1 : 1;\n return [...rows].sort((left, right) => {\n const a = left[key] ?? \"\";\n const b = right[key] ?? \"\";\n const numeric = Number(a);\n const numericb = Number(b);\n if (Number.isFinite(numeric) && Number.isFinite(numericb) && a.trim() !== \"\" && b.trim() !== \"\") return (numeric - numericb) * sign;\n return a.localeCompare(b) * sign;\n });\n}\n\n/** Builds the sheet push payload of one dataset for a reviewed sheet endpoint. */\nexport function sheetpayload(datasetvalue: dataset, sheet: string): { sheet: string; columns: string[]; rows: datasetrow[] } {\n return { sheet, columns: datasetvalue.columns.map(column => column.key), rows: datasetvalue.rows };\n}\n\n/** Merges reviewed transform rules and dedupe keys into the task rules record of one task. */\nexport function mergetaskrules(existing: { taskid: string; transforms: transformrule[]; dedupekeys: string[] } | undefined, taskid: string, transforms: transformrule[], dedupekeys: string[], at: number): { taskid: string; transforms: transformrule[]; dedupekeys: string[]; at: number } {\n return {\n taskid,\n transforms: transforms.length > 0 ? transforms : (existing?.transforms ?? []),\n dedupekeys: dedupekeys.length > 0 ? dedupekeys : (existing?.dedupekeys ?? []),\n at,\n };\n}\n", "import type { a11ycapture, a11ynode, agentplan, artifactinventoryentry, artifactrecord, auditevent, bannerreport, capabilityreport, captchahandoff, cleanuprule, cleanuprun, clipboardconsentrecord, clipentry, clickablemap, closedtab, columnspec, controltabstate, curatedlist, dataset, datasetrow, derivedselector, detectionrecord, diagnosticreport, downloadrecord, errorreport, extractsession, fielderror, focusevent, formprofile, listpattern, mimefilter, mutationevent, navcontrol, navrecord, navqueues, netlogrecord, planprogress, provenancerecord, quarantineentry, ratelimitstate, readercapture, resolvedtarget, retryoutcome, safetyverdict, sessionsnapshot, snapshotdiff, stepoutcome, streamstate, submitticket, tabbadge, tabgrouprecord, tablayout, tabmeta, tableshape, taskrules, toolstep, trailentry, transformrule, typeaheadpick, waitprofilerecord, wizardstate } from \"../types.js\";\nimport { switcherlist, type tabshape, type windowshape } from \"./tabscommand.js\";\nimport { cardmask } from \"./pageforms.js\";\nimport { sortrows } from \"./datacommand.js\";\n\nconst objective = document.querySelector<HTMLTextAreaElement>(\"#objective\");\nconst localbutton = document.querySelector<HTMLButtonElement>(\"#localplan\");\nconst remotebutton = document.querySelector<HTMLButtonElement>(\"#remoteplan\");\nconst diagnosticbutton = document.querySelector<HTMLButtonElement>(\"#diagnostic\");\nconst planroot = document.querySelector<HTMLElement>(\"#plan\");\nconst auditroot = document.querySelector<HTMLElement>(\"#audit\");\nconst diagnosticroot = document.querySelector<HTMLElement>(\"#diagnostics\");\nconst maproot = document.querySelector<HTMLElement>(\"#map\");\nconst a11yroot = document.querySelector<HTMLElement>(\"#a11y\");\nconst readerroot = document.querySelector<HTMLElement>(\"#reader\");\nconst detectionsroot = document.querySelector<HTMLElement>(\"#detections\");\nconst streamroot = document.querySelector<HTMLElement>(\"#stream\");\nconst diffsroot = document.querySelector<HTMLElement>(\"#diffs\");\nconst bannersroot = document.querySelector<HTMLElement>(\"#banners\");\nconst selectorsroot = document.querySelector<HTMLElement>(\"#selectors\");\nconst trailroot = document.querySelector<HTMLElement>(\"#trail\");\nconst navigationroot = document.querySelector<HTMLElement>(\"#navigation\");\nconst tabswindowsroot = document.querySelector<HTMLElement>(\"#tabswindows\");\nconst formsroot = document.querySelector<HTMLElement>(\"#forms\");\nconst datasetsroot = document.querySelector<HTMLElement>(\"#datasets\");\nconst filesroot = document.querySelector<HTMLElement>(\"#files\");\nconst statusnode = document.querySelector<HTMLElement>(\"#status\");\nconst progressnode = document.querySelector<HTMLProgressElement>(\"#planprogress\");\nconst capabilitiestext = document.querySelector<HTMLElement>(\"#capabilitiestext\");\n\ntype previewresult = { ok: boolean; summary: string; resolvedtarget?: resolvedtarget; candidates?: string[] };\nconst previews = new Map<string, previewresult>();\n\n/** Safely reads the reviewed options object of one step. */\nfunction options(step: toolstep): Record<string, unknown> {\n if (!step.options) return {};\n try {\n const parsed = JSON.parse(step.options);\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Record<string, unknown>) : {};\n } catch { return {}; }\n}\n\nfunction status(message: string, error = false): void { if (statusnode) { statusnode.textContent = message; statusnode.dataset.state = error ? \"error\" : \"ready\"; } }\nasync function request(message: unknown): Promise<unknown> { const response = await chrome.runtime.sendMessage(message) as { ok: boolean; value?: unknown; error?: string }; if (!response.ok) throw new Error(response.error); return response.value; }\nfunction button(label: string, action: () => Promise<void>, disabled = false): HTMLButtonElement { const element = document.createElement(\"button\"); element.type = \"button\"; element.textContent = label; element.disabled = disabled; element.addEventListener(\"click\", () => action().catch(error => status(error instanceof Error ? error.message : String(error), true))); return element; }\n\n/** Kinds addressable by a css target or a reviewed targetref; only these can be previewed. */\nconst previewkinds = [\"focus\", \"inspect\", \"click\", \"type\", \"scroll\", \"select\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"highlight\", \"setattribute\", \"removeattribute\", \"waitfor\", \"shiftclick\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\", \"verifyvisible\", \"verifyenabled\", \"pierceshadow\", \"clickpoint\", \"clicktext\", \"clickaria\", \"clickname\", \"resolvexpath\", \"deriveselector\", \"fingerprintsection\", \"submitform\", \"retryform\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\"];\n\n/** Topic rows that group the new interaction and observation kinds inside each risk class. */\nconst topictags: Array<{ topic: string; kinds: string[] }> = [\n { topic: \"pointer\", kinds: [\"movepointer\", \"clickpoint\", \"shiftclick\", \"clicktext\", \"clickaria\", \"clickname\", \"pierceshadow\"] },\n { topic: \"typing\", kinds: [\"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\"] },\n { topic: \"keys\", kinds: [\"keyhold\", \"keyrelease\"] },\n { topic: \"controls\", kinds: [\"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\"] },\n { topic: \"dialogs\", kinds: [\"dismissdialog\"] },\n { topic: \"frames\", kinds: [\"enterframe\"] },\n { topic: \"retry\", kinds: [\"retryaction\"] },\n { topic: \"reads\", kinds: [\"mapclicks\", \"verifyvisible\", \"verifyenabled\", \"resolvexpath\"] },\n { topic: \"observation\", kinds: [\"a11ytree\", \"readvisible\", \"readertree\", \"readoutline\", \"readselection\", \"readopengraph\", \"readlang\", \"detectlanguage\", \"listshadow\", \"listframes\", \"readscrollpos\"] },\n { topic: \"detection\", kinds: [\"detectlists\", \"detecttables\", \"detectinfinitescroll\", \"detectvirtual\", \"detectlazy\", \"detectsticky\", \"detectscrolllock\", \"countpages\", \"classifypage\", \"fingerprintsection\"] },\n { topic: \"watch\", kinds: [\"watchmutate\", \"watchbanner\", \"watchfocus\", \"waitquiet\", \"readjson\", \"diffsnapshots\", \"deriveselector\"] },\n { topic: \"navigation\", kinds: [\"openlink\", \"openprivate\", \"reloadcache\", \"stopnav\", \"waitload\", \"waiturl\", \"followlink\", \"spanav\", \"spawait\", \"rewritequery\", \"setfragment\", \"navlist\", \"navprofile\", \"detecthttp\", \"readredirects\", \"readfinalurl\", \"handleauth\", \"printpdf\", \"prefetch\", \"preconnect\", \"deeplink\", \"reopentab\", \"trailaudit\", \"pausenav\", \"navintent\", \"navrate\", \"openclipboard\", \"checksafe\", \"batchopen\"] },\n { topic: \"tabs\", kinds: [\"querytabs\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"watchtab\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"savelayout\", \"restorelayout\", \"findclones\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"listaudio\", \"reopenrun\", \"snapshotsession\"] },\n { topic: \"forms\", kinds: [\"fillform\", \"filllabel\", \"fillplaceholder\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"submitform\", \"readerrors\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"handoffcaptcha\", \"fillcard\", \"fillcode\", \"consentpassword\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\"] },\n];\n\nfunction steptopic(kind: string): string | undefined {\n return topictags.find(tag => tag.kinds.includes(kind))?.topic;\n}\n\n/** Renders plan completion as a live progress ratio. */\nfunction renderprogress(plan: agentplan, completed: string[]): void {\n if (!progressnode) return;\n const total = plan.steps.length || 1;\n progressnode.max = total;\n progressnode.value = completed.length;\n progressnode.textContent = `${completed.length} of ${plan.steps.length} reviewed steps executed`;\n}\n\n/** Renders the latest structured outcome of one step beside its review entry. */\nfunction renderoutcome(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n const outcome = [...outcomes].reverse().find(item => item.stepid === step.id && item.ok) ?? [...outcomes].reverse().find(item => item.stepid === step.id);\n if (!outcome) return null;\n const node = document.createElement(\"details\");\n node.className = \"outcome\";\n const summary = document.createElement(\"summary\");\n summary.textContent = `${outcome.ok ? \"result\" : \"failure\"}: ${outcome.summary}`;\n node.append(summary);\n if (outcome.details && Object.keys(outcome.details).length > 0) {\n const payload = document.createElement(\"pre\");\n payload.textContent = JSON.stringify(outcome.details, null, 2).slice(0, 4000);\n node.append(payload);\n }\n return node;\n}\n\n/** Renders the hold id of a key hold or release step beside its summary. */\nfunction holddetail(step: toolstep): string {\n if (step.kind === \"keyhold\") {\n const holdid = options(step).holdid;\n return typeof holdid === \"string\" && holdid ? ` \u00B7 hold id ${holdid}` : \"\";\n }\n if (step.kind === \"keyrelease\") return step.value ? ` \u00B7 releases hold id ${step.value}` : \"\";\n return \"\";\n}\n\n/** Renders the retry attempts of one retry step on the step timeline. */\nfunction retrydetail(step: toolstep, retries: retryoutcome[]): HTMLElement | null {\n const latest = [...retries].reverse().find(item => item.stepid === step.id);\n if (!latest) return null;\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `retry timeline: ${latest.attempts} attempt${latest.attempts === 1 ? \"\" : \"s\"} \u00B7 ${latest.movement.toFixed(1)} px movement \u00B7 ${latest.ok ? \"succeeded\" : \"failed\"}`;\n return node;\n}\n\n/** Renders the network quiet progress of one waitquiet step from its outcome evidence. */\nfunction quietdetail(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n if (step.kind !== \"waitquiet\") return null;\n const latest = [...outcomes].reverse().find(outcome => outcome.stepid === step.id);\n if (!latest) return null;\n const samples = Array.isArray(latest.details?.samples) ? latest.details?.samples as Array<{ at: number; quietfor: number }> : [];\n const idle = typeof latest.details?.idle === \"number\" ? latest.details?.idle : 0;\n const last = samples[samples.length - 1];\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `network quiet: ${samples.length} sample${samples.length === 1 ? \"\" : \"s\"} \u00B7 quiet for ${Math.round(last?.quietfor ?? 0)} ms \u00B7 idle threshold ${idle} ms \u00B7 ${latest.ok ? \"quiet reached\" : \"still busy\"}`;\n return node;\n}\n\n/** Renders the per iteration row variables of one looprows step on the step timeline. */\nfunction loopdetail(step: toolstep, progress: planprogress | undefined): HTMLElement | null {\n if (step.kind !== \"looprows\") return null;\n const iterations = (progress?.outcomes ?? []).filter(outcome => outcome.stepid === step.id && outcome.details?.iteration !== undefined);\n if (iterations.length === 0) return null;\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n const latest = iterations[iterations.length - 1];\n if (!latest) return null;\n const variables = latest.details?.variables as Record<string, string> | undefined;\n const shown = variables ? Object.entries(variables).slice(0, 4).map(([key, value]) => `${key}=${value}`).join(\", \") : \"\";\n node.textContent = `loop timeline: ${iterations.length} iteration${iterations.length === 1 ? \"\" : \"s\"} \u00B7 ${String(latest.details?.variable ?? \"row\")} variables ${shown}`;\n return node;\n}\n\n/** Renders the navlist progress of one navlist step with the current url and the remaining count. */\nfunction navlistdetail(step: toolstep, progress: planprogress | undefined, outcomes: stepoutcome[]): HTMLElement | null {\n if (step.kind !== \"navlist\") return null;\n const entries = (progress?.outcomes ?? []).filter(outcome => outcome.stepid === step.id && outcome.details?.naventry !== undefined).map(outcome => outcome.details?.naventry as { index: number; url: string; ok: boolean });\n const total = entries.length > 0 ? Math.max(...entries.map(entry => entry.index)) + 1 : 0;\n const latestoutcome = [...outcomes].reverse().find(outcome => outcome.stepid === step.id);\n const remaining = typeof latestoutcome?.details?.remaining === \"number\" ? latestoutcome.details?.remaining : 0;\n const current = entries[entries.length - 1];\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = entries.length === 0\n ? \"navigation list: no entry completed yet\"\n : `navigation list: ${entries.filter(entry => entry.ok).length} of ${total} entries completed \u00B7 current url ${current?.url ?? \"\"} \u00B7 ${remaining} remaining`;\n return node;\n}\n\n/** Renders the redirect chain and final url of one navigation step from its outcome evidence. */\nfunction redirectdetail(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n if (![\"navigate\", \"followlink\", \"spanav\", \"navlist\", \"openlink\", \"reloadcache\"].includes(step.kind)) return null;\n const latest = [...outcomes].reverse().find(outcome => outcome.stepid === step.id && outcome.details?.hops !== undefined);\n if (!latest) return null;\n const hops = typeof latest.details?.hops === \"number\" ? latest.details?.hops : 0;\n const final = typeof latest.details?.finalurl === \"string\" ? latest.details?.finalurl : \"\";\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `redirects: ${Math.max(0, hops - 1)} hop${hops - 1 === 1 ? \"\" : \"s\"} \u00B7 final url ${final || \"unknown\"}`;\n return node;\n}\n\n/** Renders the resolved target details of one previewed interaction step before approval. */\nfunction renderpreview(step: toolstep): HTMLElement | null {\n const preview = previews.get(step.id);\n if (!preview) return null;\n const node = document.createElement(\"details\");\n node.className = \"outcome\";\n const summary = document.createElement(\"summary\");\n summary.textContent = `preview: ${preview.summary}`;\n node.append(summary);\n if (preview.resolvedtarget) {\n const payload = document.createElement(\"pre\");\n payload.textContent = JSON.stringify(preview.resolvedtarget, null, 2);\n node.append(payload);\n }\n if (preview.candidates && preview.candidates.length > 1) {\n const chooser = document.createElement(\"p\");\n chooser.textContent = \"Ambiguous resolution; choose one candidate as the target hint:\";\n node.append(chooser);\n for (const candidate of preview.candidates) {\n node.append(\" \", button(`Choose \"${candidate}\"`, async () => { pickhint(`target hint: ${candidate}`); }));\n }\n }\n return node;\n}\n\nfunction stepitem(plan: agentplan, step: toolstep, completed: string[], outcomes: stepoutcome[], retries: retryoutcome[], progress?: planprogress): HTMLLIElement {\n const item = document.createElement(\"li\");\n const done = completed.includes(step.id);\n item.textContent = `${done ? \"\u2713\" : \"\"} ${step.summary}${holddetail(step)}`;\n const outcome = renderoutcome(step, outcomes);\n if (outcome) item.append(outcome);\n const timeline = step.kind === \"retryaction\" ? retrydetail(step, retries) : quietdetail(step, outcomes);\n if (timeline) item.append(timeline);\n const navlist = navlistdetail(step, progress, outcomes);\n if (navlist) item.append(navlist);\n const loopvars = loopdetail(step, progress);\n if (loopvars) item.append(loopvars);\n const redirects = redirectdetail(step, outcomes);\n if (redirects) item.append(redirects);\n const preview = renderpreview(step);\n if (preview) item.append(preview);\n const hastarget = Boolean(step.target) || options(step).targetref !== undefined;\n if (!done && hastarget && previewkinds.includes(step.kind) && [\"pending\", \"approved\"].includes(plan.state)) item.append(\" \", button(\"Preview current target\", async () => { const result = await request({ kind: \"preview\", stepid: step.id }) as previewresult; previews.set(step.id, result); status(result.summary); await refresh(); }));\n if (!done && plan.state === \"approved\") item.append(\" \", button(\"Run this reviewed step\", async () => { const result = await request({ kind: \"execute\", stepid: step.id }) as { summary: string }; status(result.summary); await refresh(); }));\n return item;\n}\n\nfunction steplist(plan: agentplan, steps: toolstep[], completed: string[], outcomes: stepoutcome[], retries: retryoutcome[], risk: toolstep[\"risk\"], progress?: planprogress): HTMLElement | null {\n const group = steps.filter(step => step.risk === risk);\n if (group.length === 0) return null;\n const section = document.createElement(\"section\");\n const heading = document.createElement(\"h3\");\n heading.textContent = `${risk} steps`;\n section.append(heading);\n const general = group.filter(step => steptopic(step.kind) === undefined);\n if (general.length > 0) {\n const list = document.createElement(\"ol\");\n for (const step of general) list.append(stepitem(plan, step, completed, outcomes, retries, progress));\n section.append(list);\n }\n for (const tag of topictags) {\n const tagged = group.filter(step => steptopic(step.kind) === tag.topic);\n if (tagged.length === 0) continue;\n const row = document.createElement(\"h4\");\n row.textContent = `${tag.topic} steps`;\n section.append(row);\n const list = document.createElement(\"ol\");\n for (const step of tagged) list.append(stepitem(plan, step, completed, outcomes, retries, progress));\n section.append(list);\n }\n return section;\n}\n\nfunction renderplan(plan?: agentplan, progress?: planprogress, outcomes: stepoutcome[] = [], retries: retryoutcome[] = []): void {\n if (!planroot) return;\n planroot.replaceChildren();\n if (!plan) { planroot.textContent = \"Start a session, then request a local or endpoint plan. No task runs before review.\"; if (progressnode) progressnode.value = 0; return; }\n const title = document.createElement(\"h2\"); title.textContent = `${plan.state}: ${plan.objective}`; planroot.append(title);\n const completed = progress?.planid === plan.id ? progress.completedsteps : [];\n renderprogress(plan, completed);\n const sensitive = steplist(plan, plan.steps, completed, outcomes, retries, \"sensitive\", progress);\n const interaction = steplist(plan, plan.steps, completed, outcomes, retries, \"interaction\", progress);\n const read = steplist(plan, plan.steps, completed, outcomes, retries, \"read\", progress);\n for (const group of [sensitive, interaction, read]) if (group) planroot.append(group);\n if (plan.state === \"pending\") { planroot.append(button(\"Approve reviewed plan\", async () => { await request({ kind: \"approve\" }); await refresh(); }), button(\"Reject plan\", async () => { await request({ kind: \"reject\" }); await refresh(); })); }\n if (plan.state === \"completed\" && plan.completedat) { const note = document.createElement(\"p\"); note.textContent = \"Every reviewed step has executed and the plan is closed.\"; planroot.append(note); }\n}\n\n/** Records one clickable map entry or candidate as the target hint for the next plan. */\nfunction pickhint(hint: string): void {\n if (objective) objective.value = objective.value ? `${objective.value}\\n${hint}` : hint;\n status(`${hint} recorded as the target hint for the next plan.`);\n}\n\n/** Renders the clickable map as a numbered list beside the plan and lets the user pick entries. */\nfunction rendermap(map?: clickablemap): void {\n if (!maproot) return;\n maproot.replaceChildren();\n if (!map || map.entries.length === 0) { maproot.textContent = \"Run a mapclicks step to number every clickable element on the page.\"; return; }\n for (const entry of map.entries) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `${entry.number}. ${entry.label || entry.selector} (${entry.role})`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${entry.selector} (map entry ${entry.number}, ${entry.label || entry.role})`));\n item.append(pick);\n maproot.append(item);\n }\n}\n\n/** Renders the latest accessibility tree beside the dom snapshot as indented role lines. */\nfunction rendera11y(capture?: a11ycapture): void {\n if (!a11yroot) return;\n a11yroot.replaceChildren();\n if (!capture) { a11yroot.textContent = \"Run an a11ytree step to capture the accessibility tree beside the dom snapshot.\"; return; }\n const lines: string[] = [];\n const walk = (node: a11ynode, depth: number): void => {\n if (lines.length >= 80) return;\n const states = node.states.length > 0 ? ` [${node.states.join(\", \")}]` : \"\";\n const value = node.value !== undefined ? ` = ${node.value}` : \"\";\n lines.push(`${\"\u00B7 \".repeat(depth)}${node.role}: ${node.name || \"(unnamed)\"}${states}${value}`);\n for (const child of node.children) walk(child, depth + 1);\n };\n walk(capture.tree, 0);\n const payload = document.createElement(\"pre\");\n payload.textContent = lines.join(\"\\n\");\n a11yroot.append(payload);\n}\n\n/** Renders the latest reader view text with heading blocks highlighted. */\nfunction renderreader(capture?: readercapture): void {\n if (!readerroot) return;\n readerroot.replaceChildren();\n if (!capture) { readerroot.textContent = \"Run a readertree step to extract the reader view.\"; return; }\n const title = document.createElement(\"p\");\n title.textContent = `${capture.article.title || \"Untitled\"}${capture.article.byline ? ` \u00B7 ${capture.article.byline}` : \"\"} \u00B7 ${capture.article.words} words \u00B7 ${capture.article.blocks.length} blocks`;\n readerroot.append(title);\n for (const block of capture.article.blocks.slice(0, 40)) {\n const line = document.createElement(\"p\");\n line.className = /^h\\d$/.test(block.kind) ? \"readerblock heading\" : \"readerblock\";\n line.textContent = `${block.kind}: ${block.text.slice(0, 200)}`;\n readerroot.append(line);\n }\n}\n\n/** Shows detected lists, tables and pagination shapes as plan suggestions the user can pick. */\nfunction renderdetections(plan: agentplan | undefined, outcomes: stepoutcome[]): void {\n if (!detectionsroot) return;\n detectionsroot.replaceChildren();\n if (!plan) { detectionsroot.textContent = \"Detection steps list their detected lists, tables and pagination shapes here as suggestions.\"; return; }\n const kindof = (stepid: string): string | undefined => plan.steps.find(step => step.id === stepid)?.kind;\n const latest = (kind: string): stepoutcome | undefined => [...outcomes].reverse().find(outcome => outcome.ok && kindof(outcome.stepid) === kind);\n let shown = 0;\n const listoutcome = latest(\"detectlists\");\n const lists = Array.isArray(listoutcome?.details?.lists) ? listoutcome?.details?.lists as listpattern[] : [];\n for (const pattern of lists.slice(0, 6)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `list of ${pattern.repeat} items \u00B7 ${pattern.itemselector}`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${pattern.itemselector} (repeated list item of ${pattern.container})`));\n item.append(pick);\n detectionsroot.append(item);\n shown += 1;\n }\n const tableoutcome = latest(\"detecttables\");\n const tables = Array.isArray(tableoutcome?.details?.tables) ? tableoutcome?.details?.tables as tableshape[] : [];\n for (const table of tables.slice(0, 6)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `table of ${table.rows} rows \u00B7 ${table.columns.length} columns \u00B7 ${table.selector}`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${table.selector} (detected data table)`));\n item.append(pick);\n detectionsroot.append(item);\n shown += 1;\n }\n const paginationoutcome = latest(\"countpages\");\n if (paginationoutcome) {\n const item = document.createElement(\"li\");\n const current = typeof paginationoutcome.details?.current === \"number\" ? paginationoutcome.details?.current : 0;\n const total = typeof paginationoutcome.details?.total === \"number\" ? paginationoutcome.details?.total : 0;\n const text = document.createElement(\"span\");\n text.textContent = `pagination: current page ${current} \u00B7 estimated total ${total}`;\n item.append(text);\n detectionsroot.append(item);\n shown += 1;\n }\n if (shown === 0) detectionsroot.textContent = \"Detected lists, tables and pagination shapes appear here as plan suggestions.\";\n}\n\n/** Shows the live mutation and focus stream observed during watched steps. */\nfunction renderstream(mutationevents: mutationevent[], focusevents: focusevent[]): void {\n if (!streamroot) return;\n streamroot.replaceChildren();\n if (mutationevents.length === 0 && focusevents.length === 0) { streamroot.textContent = \"Watched steps stream their mutation and focus events here.\"; return; }\n for (const event of mutationevents.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 mutation ${event.event} \u00B7 ${event.targetpath}`;\n streamroot.append(item);\n }\n for (const event of focusevents.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 focus ${event.kind} \u00B7 ${event.targetpath}`;\n streamroot.append(item);\n }\n}\n\n/** Renders the latest snapshot diff with added, removed and changed rows. */\nfunction renderdiffs(diffs: snapshotdiff[]): void {\n if (!diffsroot) return;\n diffsroot.replaceChildren();\n const latest = diffs[0];\n if (!latest) { diffsroot.textContent = \"Diff two captured observation versions with a diffsnapshots step.\"; return; }\n const heading = document.createElement(\"p\");\n heading.textContent = `version ${latest.baseversion} \u2192 ${latest.targetversion}: ${latest.added.length} added \u00B7 ${latest.removed.length} removed \u00B7 ${latest.changed.length} changed`;\n diffsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const entry of [...latest.added, ...latest.removed, ...latest.changed].slice(0, 12)) {\n const item = document.createElement(\"li\");\n item.className = `diffrow ${entry.kind}`;\n item.textContent = `${entry.kind} \u00B7 ${entry.selector} \u00B7 ${entry.summary}`;\n list.append(item);\n }\n diffsroot.append(list);\n}\n\n/** Flags consent banners with a review card before any interaction. */\nfunction renderbanners(banners: bannerreport[]): void {\n if (!bannersroot) return;\n bannersroot.replaceChildren();\n if (banners.length === 0) { bannersroot.textContent = \"No consent banner has been observed yet.\"; return; }\n for (const banner of banners.slice(0, 3)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `${banner.kind} banner detected \u2014 review it before any interaction.`;\n const text = document.createElement(\"p\");\n text.textContent = banner.text.slice(0, 160) || \"(no banner text)\";\n const controls = document.createElement(\"p\");\n controls.textContent = `controls: ${banner.controls.length > 0 ? banner.controls.join(\", \") : \"none\"}`;\n card.append(title, text, controls);\n bannersroot.append(card);\n }\n}\n\n/** Shows derived selector candidates with their stability scores for reuse. */\nfunction renderselectors(selectors: derivedselector[]): void {\n if (!selectorsroot) return;\n selectorsroot.replaceChildren();\n if (selectors.length === 0) { selectorsroot.textContent = \"Run a deriveselector step to rank stable selectors.\"; return; }\n for (const record of selectors.slice(0, 8)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `${record.selector} (${record.strategy} \u00B7 stability ${record.score})`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${record.selector} (derived ${record.strategy} selector)`));\n item.append(pick);\n selectorsroot.append(item);\n }\n}\n\n/** Renders the navigation trail of the session as a timeline of visited urls. */\nfunction rendertrail(trail: trailentry[]): void {\n if (!trailroot) return;\n trailroot.replaceChildren();\n if (trail.length === 0) { trailroot.textContent = \"No page has been visited inside a reviewed navigation step yet.\"; return; }\n for (const entry of [...trail].reverse().slice(0, 12)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(entry.at).toLocaleTimeString()} \u00B7 ${entry.url}${entry.title ? ` \u00B7 ${entry.title}` : \"\"}${entry.stepid ? ` \u00B7 step ${entry.stepid}` : \"\"}`;\n trailroot.append(item);\n }\n}\n\n/** Renders the navigation state: paused navigation, rate limit windows per domain, wait profiles, redirect chains, curated lists, safety verdicts, artifacts and the basic auth prompt behind the consent gate. */\nfunction rendernavigation(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; navcontrol?: navcontrol; ratestates?: ratelimitstate[]; waitprofiles?: waitprofilerecord[]; navrecords?: navrecord[]; curated?: curatedlist[]; safeties?: safetyverdict[]; auths?: Array<{ origin: string; username: string; reviewedat: number }>; navqueues?: navqueues; artifacts?: artifactrecord[] }): void {\n if (!navigationroot) return;\n navigationroot.replaceChildren();\n const paused = document.createElement(\"p\");\n if (context.navcontrol?.pausedat) {\n paused.className = \"bannercard\";\n paused.textContent = `Navigation is paused while ${context.navcontrol.reason ?? \"a consent prompt is open\"}; reviewed navigation steps are blocked until it resumes.`;\n } else {\n paused.textContent = \"Navigation is live; no consent prompt holds it.\";\n }\n navigationroot.append(paused);\n const rates = context.ratestates ?? [];\n if (rates.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"rate limit windows per domain:\";\n navigationroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const state of rates.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${state.domain}: ${state.count} of ${state.limit.ceiling} navigations inside the reviewed window of ${state.limit.window} ms`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const records = context.navrecords ?? [];\n const record = records[0];\n if (record) {\n const chain = document.createElement(\"p\");\n chain.textContent = `latest navigation: ${Math.max(0, record.chain.hops.length - 1)} redirect${record.chain.hops.length - 1 === 1 ? \"\" : \"s\"} \u00B7 final url ${record.finalurl}`;\n navigationroot.append(chain);\n const hops = document.createElement(\"ul\");\n for (const hop of record.chain.hops.slice(0, 6)) {\n const item = document.createElement(\"li\");\n let path = hop.url;\n try { path = new URL(hop.url).pathname; } catch { path = hop.url; }\n item.textContent = `hop ${path} \u00B7 status ${hop.status} \u00B7 ${new Date(hop.at).toLocaleTimeString()}`;\n hops.append(item);\n }\n navigationroot.append(hops);\n }\n const curatedlists = context.curated ?? [];\n if (curatedlists.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"curated link lists with per url safety states:\";\n navigationroot.append(heading);\n for (const list of curatedlists.slice(0, 3)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `${list.links.length} curated url${list.links.length === 1 ? \"\" : \"s\"}${list.reviewedat ? \" \u00B7 opened after review\" : \" \u00B7 waiting for review\"}`;\n card.append(title);\n for (const link of list.links.slice(0, 8)) {\n const line = document.createElement(\"p\");\n line.textContent = `${link.verdict === \"safe\" ? \"\u2713\" : \"\u2717\"} ${link.url}${link.reasons.length > 0 ? ` \u00B7 ${link.reasons.join(\"; \")}` : \"\"}`;\n card.append(line);\n }\n navigationroot.append(card);\n }\n }\n const safeties = context.safeties ?? [];\n const runner = document.createElement(\"p\");\n const checkinput = document.createElement(\"input\");\n checkinput.type = \"url\";\n checkinput.placeholder = \"https://external.example/link\";\n checkinput.setAttribute(\"aria-label\", \"url to verify with checksafe\");\n const checkbutton = button(\"Run checksafe\", async () => {\n const verdict = await request({ kind: \"checksafe\", url: checkinput.value }) as safetyverdict;\n status(verdict.safe ? `${verdict.url} passed every safety check.` : `${verdict.url} is unsafe: ${verdict.reasons.join(\"; \")}.`);\n await refresh();\n });\n runner.append(checkinput, \" \", checkbutton);\n navigationroot.append(runner);\n if (safeties.length > 0) {\n const list = document.createElement(\"ul\");\n for (const verdict of safeties.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${verdict.safe ? \"safe\" : \"unsafe\"} \u00B7 ${verdict.url}${verdict.reasons.length > 0 ? ` \u00B7 ${verdict.reasons.join(\"; \")}` : \"\"}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const authcard = document.createElement(\"div\");\n authcard.className = \"bannercard\";\n const authtitle = document.createElement(\"p\");\n authtitle.textContent = active ? \"basic auth credentials (stored only after your explicit review):\" : \"basic auth credentials need an active session before they can be reviewed.\";\n authcard.append(authtitle);\n if (active) {\n const origininput = document.createElement(\"input\");\n origininput.type = \"url\";\n origininput.placeholder = context.session?.origin ?? \"https://example.com\";\n origininput.setAttribute(\"aria-label\", \"auth origin\");\n const userinput = document.createElement(\"input\");\n userinput.type = \"text\";\n userinput.placeholder = \"username\";\n userinput.setAttribute(\"aria-label\", \"auth username\");\n const passinput = document.createElement(\"input\");\n passinput.type = \"password\";\n passinput.placeholder = \"password\";\n passinput.setAttribute(\"aria-label\", \"auth password\");\n const storebutton = button(\"Store reviewed credentials\", async () => {\n const stored = await request({ kind: \"storeauth\", origin: origininput.value, username: userinput.value, password: passinput.value }) as { origin: string };\n status(`Reviewed basic auth credentials stored for ${stored.origin}.`);\n await refresh();\n });\n authcard.append(origininput, \" \", userinput, \" \", passinput, \" \", storebutton);\n }\n navigationroot.append(authcard);\n const auths = context.auths ?? [];\n if (auths.length > 0) {\n const list = document.createElement(\"ul\");\n for (const record of auths.slice(0, 4)) {\n const item = document.createElement(\"li\");\n item.textContent = `basic auth for ${record.origin} as ${record.username}, reviewed ${new Date(record.reviewedat).toLocaleString()}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const artifacts = context.artifacts ?? [];\n if (artifacts.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"task artifacts:\";\n navigationroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const artifact of artifacts.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${artifact.kind}: ${artifact.name} \u00B7 step ${artifact.stepid}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n}\n\n/** Renders the tabs and windows command surface: quick switcher, groups, badges, audio state, layouts, snapshots, clone warnings, the task tab budget gauge and the pinned control tab feed. */\nfunction rendertabswindows(context: { session?: { stoppedat?: number; expiresat: number }; plan?: agentplan; progress?: planprogress; tabs?: tabshape[]; windows?: windowshape[]; tabgroups?: tabgrouprecord[]; badges?: tabbadge[]; tabmetas?: tabmeta[]; clones?: Array<{ url: string; tabids: number[] }>; layouts?: tablayout[]; snapshots?: sessionsnapshot[]; closedtabs?: closedtab[]; tasktabgauge?: { used: number; ceiling?: number; over: boolean }; controltab?: controltabstate }): void {\n if (!tabswindowsroot) return;\n tabswindowsroot.replaceChildren();\n const tabs = context.tabs ?? [];\n const badges = context.badges ?? [];\n const metas = context.tabmetas ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const gauge = context.tasktabgauge ?? { used: 0, ceiling: undefined, over: false };\n const budget = document.createElement(\"p\");\n budget.className = gauge.over ? \"bannercard\" : \"\";\n budget.textContent = `task tab budget: ${gauge.used} tab${gauge.used === 1 ? \"\" : \"s\"} with active tasks${gauge.ceiling !== undefined ? ` of the user configured ceiling ${gauge.ceiling}` : \" with no user ceiling configured\"}${gauge.over ? \" \u2014 over the reviewed budget\" : \"\"}`;\n tabswindowsroot.append(budget);\n const ceilinginput = document.createElement(\"input\");\n ceilinginput.type = \"number\";\n ceilinginput.min = \"0\";\n ceilinginput.placeholder = gauge.ceiling !== undefined ? String(gauge.ceiling) : \"no ceiling\";\n ceilinginput.setAttribute(\"aria-label\", \"concurrent task tab ceiling\");\n const ceilingbutton = button(\"Save task tab ceiling\", async () => {\n await request({ kind: \"settasktabceiling\", ceiling: ceilinginput.value === \"\" ? undefined : Number(ceilinginput.value) });\n status(`Task tab ceiling saved as ${ceilinginput.value === \"\" ? \"no ceiling\" : ceilinginput.value}; the value stays a user choice.`);\n await refresh();\n });\n tabswindowsroot.append(ceilinginput, \" \", ceilingbutton);\n const switcherheading = document.createElement(\"p\");\n switcherheading.textContent = \"quick switcher (ordered by recency, filter by title or url):\";\n tabswindowsroot.append(switcherheading);\n const filterinput = document.createElement(\"input\");\n filterinput.type = \"search\";\n filterinput.placeholder = \"filter open tabs\";\n filterinput.setAttribute(\"aria-label\", \"quick switcher filter\");\n const switchlist = document.createElement(\"ul\");\n const renderswitchlist = (): void => {\n switchlist.replaceChildren();\n const ordered = switcherlist(tabs, [], filterinput.value).slice(0, 10);\n for (const tab of ordered) {\n const item = document.createElement(\"li\");\n const jump = document.createElement(\"button\");\n jump.type = \"button\";\n const badge = badges.find(entry => entry.tabid === tab.tabid);\n const meta = metas.find(entry => entry.tabid === tab.tabid);\n jump.textContent = `${tab.title || tab.url}${tab.pinned ? \" \uD83D\uDCCC\" : \"\"}${tab.audible || tab.muted ? ` ${tab.muted ? \"\uD83D\uDD07\" : \"\uD83D\uDD0A\"}` : \"\"}${badge ? ` [${badge.label}]` : \"\"}${meta && meta.labels.length > 0 ? ` (${meta.labels.join(\", \")})` : \"\"}`;\n jump.addEventListener(\"click\", () => request({ kind: \"jumptotab\", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch(error => status(error instanceof Error ? error.message : String(error), true)));\n item.append(jump);\n switchlist.append(item);\n }\n if (ordered.length === 0) { const empty = document.createElement(\"li\"); empty.textContent = \"no open tab matches the filter\"; switchlist.append(empty); }\n };\n filterinput.addEventListener(\"input\", renderswitchlist);\n tabswindowsroot.append(filterinput, switchlist);\n renderswitchlist();\n const searchinput = document.createElement(\"input\");\n searchinput.type = \"search\";\n searchinput.placeholder = \"search across open tabs by title and url\";\n searchinput.setAttribute(\"aria-label\", \"searchtabs text\");\n const searchresults = document.createElement(\"ul\");\n const searchbutton = button(\"Run searchtabs\", async () => {\n const result = await request({ kind: \"tabsearch\", text: searchinput.value }) as { matches: tabshape[] };\n searchresults.replaceChildren();\n for (const tab of result.matches.slice(0, 10)) {\n const item = document.createElement(\"li\");\n const jump = document.createElement(\"button\");\n jump.type = \"button\";\n jump.textContent = `${tab.title || tab.url} \u00B7 ${tab.url}`;\n jump.addEventListener(\"click\", () => request({ kind: \"jumptotab\", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch(error => status(error instanceof Error ? error.message : String(error), true)));\n item.append(jump);\n searchresults.append(item);\n }\n status(`searchtabs matched ${result.matches.length} open tab${result.matches.length === 1 ? \"\" : \"s\"}.`);\n });\n tabswindowsroot.append(searchinput, \" \", searchbutton, searchresults);\n const clones = context.clones ?? [];\n for (const clone of clones.slice(0, 3)) {\n const warning = document.createElement(\"p\");\n warning.className = \"bannercard\";\n warning.textContent = `duplicate tab warning: ${clone.tabids.length} open tabs share the url ${clone.url} (tabs ${clone.tabids.join(\", \")})`;\n tabswindowsroot.append(warning);\n }\n const groups = context.tabgroups ?? [];\n if (groups.length > 0) {\n const groupsheading = document.createElement(\"p\");\n groupsheading.textContent = \"tab groups with colors and collapse states:\";\n tabswindowsroot.append(groupsheading);\n const grouplist = document.createElement(\"ul\");\n for (const group of groups.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${group.name} \u00B7 ${group.color} \u00B7 ${group.collapsed ? \"collapsed\" : \"expanded\"} \u00B7 ${group.tabids.length} member tab${group.tabids.length === 1 ? \"\" : \"s\"}`;\n grouplist.append(item);\n }\n tabswindowsroot.append(grouplist);\n }\n const windows = context.windows ?? [];\n if (windows.length > 0) {\n const windowsheading = document.createElement(\"p\");\n windowsheading.textContent = \"windows with layouts and bounds:\";\n tabswindowsroot.append(windowsheading);\n const windowlist = document.createElement(\"ul\");\n for (const item of windows.slice(0, 6)) {\n const entry = document.createElement(\"li\");\n entry.textContent = `window ${item.windowid} \u00B7 ${item.state} \u00B7 bounds ${item.left}\u00D7${item.top} ${item.width}\u00D7${item.height}${item.incognito ? \" \u00B7 incognito, grants not inherited\" : \"\"}${item.focused ? \" \u00B7 focused\" : \"\"}`;\n const closebutton = button(\"Close window\", async () => {\n const tasktabids = (context.progress?.tasktabs ?? []);\n const tabsoftask = (context.tabs ?? []).filter(tab => tab.windowid === item.windowid && tasktabids.includes(tab.tabid));\n const reviewed = tabsoftask.length > 1 ? window.confirm(`This window holds ${tabsoftask.length} task tabs. Close it anyway under explicit review?`) : true;\n await request({ kind: \"closewindow\", windowid: item.windowid, reviewed });\n status(`Closed window ${item.windowid}.`);\n await refresh();\n });\n entry.append(\" \", closebutton);\n windowlist.append(entry);\n }\n tabswindowsroot.append(windowlist);\n }\n const layoutcontrols = document.createElement(\"p\");\n const layoutname = document.createElement(\"input\");\n layoutname.type = \"text\";\n layoutname.placeholder = \"layout name\";\n layoutname.setAttribute(\"aria-label\", \"layout name\");\n const savebutton = button(\"Save layout\", async () => {\n if (!active) { status(\"Layout save stays inside an active session.\", true); return; }\n await request({ kind: \"savelayout\", name: layoutname.value });\n status(`Saved the tab layout ${layoutname.value}.`);\n await refresh();\n });\n const restorebutton = button(\"Restore layout\", async () => {\n if (!active) { status(\"Layout restore stays inside an active session.\", true); return; }\n const result = await request({ kind: \"restorelayout\", name: layoutname.value }) as { reopened: number };\n status(`Restored the tab layout ${layoutname.value}: ${result.reopened} tab${result.reopened === 1 ? \"\" : \"s\"} reopened.`);\n await refresh();\n });\n layoutcontrols.append(layoutname, \" \", savebutton, \" \", restorebutton);\n tabswindowsroot.append(layoutcontrols);\n const layouts = context.layouts ?? [];\n if (layouts.length > 0) {\n const layoutlist = document.createElement(\"ul\");\n for (const layout of layouts.slice(0, 4)) {\n const item = document.createElement(\"li\");\n item.textContent = `${layout.name} \u00B7 ${layout.tabs.length} tab${layout.tabs.length === 1 ? \"\" : \"s\"} \u00B7 ${layout.groups.length} group${layout.groups.length === 1 ? \"\" : \"s\"} \u00B7 ${layout.windows.length} window bound${layout.windows.length === 1 ? \"\" : \"s\"} \u00B7 saved ${new Date(layout.savedat).toLocaleString()}`;\n layoutlist.append(item);\n }\n tabswindowsroot.append(layoutlist);\n }\n const snapshots = context.snapshots ?? [];\n if (snapshots.length > 0) {\n const snapcard = document.createElement(\"div\");\n snapcard.className = \"bannercard\";\n const snaptitle = document.createElement(\"p\");\n snaptitle.textContent = `session snapshot card: ${snapshots.length} snapshot${snapshots.length === 1 ? \"\" : \"s\"} stored`;\n snapcard.append(snaptitle);\n for (const snapshot of snapshots.slice(0, 3)) {\n const row = document.createElement(\"p\");\n row.textContent = `${snapshot.layout.tabs.length} tabs \u00B7 captured ${new Date(snapshot.capturedat).toLocaleString()}`;\n const restore = button(\"Restore snapshot\", async () => {\n const result = await request({ kind: \"restoresnapshot\", id: snapshot.id }) as { reopened: number };\n status(`Restored the session snapshot: ${result.reopened} tab${result.reopened === 1 ? \"\" : \"s\"} reopened.`);\n await refresh();\n });\n row.append(\" \", restore);\n snapcard.append(row);\n }\n tabswindowsroot.append(snapcard);\n }\n const controlcard = document.createElement(\"div\");\n controlcard.className = \"bannercard\";\n const controlstate = context.controltab;\n const completed = context.progress?.completedsteps.length ?? 0;\n const total = context.plan?.steps.length ?? 0;\n controlcard.textContent = `pinned control tab feed: ${controlstate?.enabled ? `open as tab ${controlstate.tabid} with the live task status ${completed} of ${total} reviewed steps executed` : \"disabled\"}${context.plan ? ` \u00B7 ${context.plan.state}` : \" \u00B7 no plan\"}`;\n const controlbutton = button(controlstate?.enabled ? \"Close pinned control tab\" : \"Open pinned control tab\", async () => {\n await request({ kind: \"controltab\", enabled: !controlstate?.enabled });\n status(controlstate?.enabled ? \"The pinned control tab was closed.\" : \"The pinned control tab was opened with the live task feed.\");\n await refresh();\n });\n controlcard.append(\" \", controlbutton);\n tabswindowsroot.append(controlcard);\n}\n\n/** Renders the forms and data surface: the form map, generated values, saved profiles, asksubmit cards with the values diff, wizard progress, inline error reports, honeypot skips, template badges, the consent gated code entry and masked card fills. */\nfunction renderforms(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; plan?: agentplan; outcomes?: stepoutcome[]; profiles?: formprofile[]; tickets?: submitticket[]; wizards?: { wizards: wizardstate[]; picks: typeaheadpick[] }; errorreports?: errorreport[]; captchas?: captchahandoff[]; detections?: detectionrecord[]; codeentry?: boolean }): void {\n if (!formsroot) return;\n formsroot.replaceChildren();\n const outcomes = context.outcomes ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const opencaptcha = (context.captchas ?? []).find(handoff => !handoff.resolved);\n if (opencaptcha) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n card.textContent = `Captcha handoff open on ${opencaptcha.origin}: control is yours and the plan waits until you resolve it.`;\n card.append(\" \", button(\"Captcha resolved\", async () => { await request({ kind: \"resolvecaptcha\" }); status(\"Captcha handoff resolved; the plan continues.\"); await refresh(); }));\n formsroot.append(card);\n }\n const detections = context.detections ?? [];\n if (detections.length > 0) {\n const badges = document.createElement(\"p\");\n badges.textContent = `template badges: ${detections.slice(0, 6).map(record => `${record.kind} on ${record.origin}${record.markers.length > 0 ? ` (${record.markers.join(\", \")})` : \"\"}`).join(\" \u00B7 \")}`;\n formsroot.append(badges);\n }\n const mapoutcome = [...outcomes].reverse().find(outcome => outcome.details?.report !== undefined && outcome.details?.count !== undefined);\n const skippedselectors = new Set(outcomes.flatMap(outcome => Array.isArray(outcome.details?.skipped) ? outcome.details?.skipped as Array<{ selector: string }> : []).map(trap => trap.selector));\n if (mapoutcome) {\n const report = mapoutcome.details?.report as { form: string; fields: Array<{ selector: string; label: string; kind: string; matched: boolean }> };\n const heading = document.createElement(\"p\");\n heading.textContent = `form map${report.form ? ` of ${report.form}` : \"\"}: ${report.fields.length} detected field${report.fields.length === 1 ? \"\" : \"s\"} with their kinds${skippedselectors.size > 0 ? `; ${skippedselectors.size} honeypot field${skippedselectors.size === 1 ? \"\" : \"s\"} highlighted as skipped` : \"\"}`;\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const field of report.fields.slice(0, 10)) {\n const item = document.createElement(\"li\");\n const skipped = skippedselectors.has(field.selector);\n item.textContent = `${field.label || field.selector} \u00B7 ${field.kind}${field.matched ? \"\" : \" \u00B7 unmatched\"}${skipped ? \" \u00B7 honeypot, skipped\" : \"\"}`;\n list.append(item);\n }\n formsroot.append(list);\n }\n const valuesoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.values) && outcome.details?.locale !== undefined);\n if (valuesoutcome) {\n const values = valuesoutcome.details?.values as Array<{ label: string; kind: string; value: string }>;\n const locale = typeof valuesoutcome.details?.locale === \"string\" ? valuesoutcome.details.locale : \"en\";\n const seed = typeof valuesoutcome.details?.seed === \"number\" ? valuesoutcome.details.seed : 1;\n const heading = document.createElement(\"p\");\n heading.textContent = `generated values (locale ${locale}, seed ${seed}) with a regenerate button per field:`;\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const entry of values.slice(0, 10)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.label} \u00B7 ${entry.kind} \u00B7 ${entry.value}`;\n item.append(\" \", button(\"Regenerate\", async () => {\n const regenerated = await request({ kind: \"regeneratevalue\", field: entry.kind, locale, seed: seed + 1 }) as { value: string };\n status(`Regenerated ${entry.label}: ${regenerated.value}.`);\n }));\n list.append(item);\n }\n formsroot.append(list);\n }\n const cardoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.segments));\n if (cardoutcome) {\n const segments = cardoutcome.details?.segments as Array<{ label: string; masked: string }>;\n const cardline = document.createElement(\"p\");\n cardline.textContent = `card fill segments (masked): ${segments.map(segment => `${segment.label} ${cardmask(segment.masked)}`).join(\" \u00B7 \")}`;\n formsroot.append(cardline);\n }\n const profiles = context.profiles ?? [];\n if (profiles.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"saved form profiles with origin grants:\";\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const profile of profiles.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${profile.name} \u00B7 ${profile.fields.length} field${profile.fields.length === 1 ? \"\" : \"s\"} \u00B7 grants ${profile.grants.join(\", \")} \u00B7 saved ${new Date(profile.savedat).toLocaleString()}`;\n item.append(\" \", button(\"Apply\", async () => {\n const applied = await request({ kind: \"applyprofile\", name: profile.name }) as { profile: { fields: unknown[] } };\n pickhint(`profile hint: ${profile.name} with ${applied.profile.fields.length} reviewed field entries`);\n }), \" \", button(\"Remove\", async () => {\n await request({ kind: \"removeprofile\", name: profile.name });\n status(`Form profile ${profile.name} removed.`);\n await refresh();\n }));\n list.append(item);\n }\n formsroot.append(list);\n }\n const pending = (context.tickets ?? []).filter(ticket => ticket.approved === undefined);\n for (const ticket of pending) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `asksubmit for form ${ticket.form || \"the reviewed form\"} \u00B7 values hash ${ticket.valueshash}`;\n card.append(title);\n const askoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.values) && outcome.details?.ticket !== undefined);\n const values = askoutcome?.details?.values as Array<{ label: string; value: string }> | undefined;\n if (values) {\n const diff = document.createElement(\"ul\");\n for (const entry of values.slice(0, 10)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.label}: ${entry.value}`;\n diff.append(item);\n }\n card.append(diff);\n } else {\n const note = document.createElement(\"p\");\n note.textContent = \"The full values diff appears here once the asksubmit step reads the form.\";\n card.append(note);\n }\n card.append(button(\"Approve submission\", async () => { await request({ kind: \"approvesubmit\", id: ticket.id, approved: true }); status(\"Submission approved; the reviewed submitform step may run.\"); await refresh(); }), \" \", button(\"Decline\", async () => { await request({ kind: \"approvesubmit\", id: ticket.id, approved: false }); status(\"Submission declined.\"); await refresh(); }));\n formsroot.append(card);\n }\n const wizards = context.wizards?.wizards ?? [];\n if (wizards.length > 0) {\n const wizard = wizards[0] as wizardstate;\n const heading = document.createElement(\"p\");\n const indicators = Array.from({ length: wizard.steps }, (_, index) => `${index < wizard.index ? (wizard.completed[index] ? \"\u2713\" : \"\u00B7\") : \"\u25CB\"}`).join(\" \");\n heading.textContent = `wizard progress: step ${Math.min(wizard.index + 1, wizard.steps)} of ${wizard.steps} ${indicators}`;\n formsroot.append(heading);\n }\n const picks = context.wizards?.picks ?? [];\n if (picks.length > 0) {\n const pickline = document.createElement(\"p\");\n pickline.textContent = `typeahead picks: ${picks.slice(0, 6).map(pick => `\"${pick.pick}\" for \"${pick.query}\"`).join(\" \u00B7 \")}`;\n formsroot.append(pickline);\n }\n const reports = context.errorreports ?? [];\n if (reports.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"inline error reports with field refs for correction loops:\";\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const report of reports.slice(0, 3)) {\n const item = document.createElement(\"li\");\n item.textContent = `${report.form || \"the reviewed form\"}: ${report.errors.map((error: fielderror) => `${error.field} \u2014 ${error.message}`).join(\"; \") || \"no message\"}`;\n list.append(item);\n }\n formsroot.append(list);\n }\n const codecard = document.createElement(\"div\");\n codecard.className = \"bannercard\";\n const codetitle = document.createElement(\"p\");\n codetitle.textContent = active ? \"one time code entry (stored behind the consent gate of the active session):\" : \"one time code entry needs an active session first.\";\n codecard.append(codetitle);\n if (active) {\n const codeinput = document.createElement(\"input\");\n codeinput.type = \"text\";\n codeinput.inputMode = \"numeric\";\n codeinput.placeholder = context.codeentry ? \"a reviewed code is stored\" : \"one time code\";\n codeinput.setAttribute(\"aria-label\", \"one time code\");\n const storebutton = button(\"Store reviewed code\", async () => {\n await request({ kind: \"storecode\", code: codeinput.value });\n status(\"The reviewed one time code is stored behind the consent gate.\");\n await refresh();\n });\n codecard.append(codeinput, \" \", storebutton);\n }\n formsroot.append(codecard);\n}\n\n/** Renders the dataset surfaces: the preview grid with sortable columns, extraction progress cards with resume prompts, export actions per dataset, transform rule previews, dedupe results, provenance records, import pickers and sheet endpoint grant states. */\nfunction renderdatasets(context: { session?: { stoppedat?: number; expiresat: number }; plan?: agentplan; outcomes?: stepoutcome[]; datasets?: dataset[]; imports?: dataset[]; extractsessions?: extractsession[]; streams?: streamstate[]; exports?: Array<{ id: string; kind: string; name: string; rowcount: number; checksum: string; at: number }>; provenances?: provenancerecord[]; taskrules?: taskrules[]; sheetendpoints?: Array<{ endpoint: string; origin: string; configuredat: number; granted: boolean }> }): void {\n if (!datasetsroot) return;\n datasetsroot.replaceChildren();\n const outcomes = context.outcomes ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const extractsessions = context.extractsessions ?? [];\n for (const extract of extractsessions.slice(0, 4)) {\n const card = document.createElement(\"p\");\n const interrupted = extract.done !== true;\n card.textContent = `extraction ${extract.name}: ${extract.pages.length} page${extract.pages.length === 1 ? \"\" : \"s\"} visited \u00B7 ${extract.rows} row${extract.rows === 1 ? \"\" : \"s\"} collected \u00B7 cursor ${extract.cursor} of ${extract.planned}${extract.done ? \" \u00B7 complete\" : \" \u00B7 interrupted\"}`;\n datasetsroot.append(card);\n }\n const interrupted = extractsessions.find(extract => extract.done !== true);\n if (interrupted && active) {\n const prompt = document.createElement(\"div\");\n prompt.className = \"bannercard\";\n prompt.textContent = `Extraction ${interrupted.name} was interrupted at cursor ${interrupted.cursor}; run its resumeextract reviewed step to continue from the stored cursor.`;\n datasetsroot.append(prompt);\n }\n const streams = context.streams ?? [];\n if (streams.length > 0) {\n const stream = streams[0]!;\n const card = document.createElement(\"p\");\n card.textContent = `stream state: ${stream.name} chunk ${stream.chunk} of ${stream.chunks} \u00B7 ${stream.written} row${stream.written === 1 ? \"\" : \"s\"} written${stream.done ? \" \u00B7 complete\" : \" \u00B7 resumable\"}`;\n datasetsroot.append(card);\n }\n const rules = (context.taskrules ?? [])[0];\n if (rules && rules.transforms.length > 0) {\n const transforms = document.createElement(\"p\");\n transforms.textContent = `transform rules: ${rules.transforms.map(rule => `${rule.sources.join(\"+\")} \u2192 ${rule.target} (${rule.expression})`).join(\" \u00B7 \")}`;\n datasetsroot.append(transforms);\n }\n if (rules && rules.dedupekeys.length > 0) {\n const keys = document.createElement(\"p\");\n keys.textContent = `dedupe keys: ${rules.dedupekeys.join(\", \")}`;\n datasetsroot.append(keys);\n }\n const dedupeoutcome = [...outcomes].reverse().find(outcome => outcome.details?.dedupe !== undefined);\n if (dedupeoutcome) {\n const dedupe = dedupeoutcome.details?.dedupe as { removed: number; kept: number; keys: string[] };\n const card = document.createElement(\"p\");\n card.textContent = `last dedupe: removed ${dedupe.removed} duplicate row${dedupe.removed === 1 ? \"\" : \"s\"}, kept ${dedupe.kept} by ${dedupe.keys.join(\", \")}`;\n datasetsroot.append(card);\n }\n for (const datasetvalue of (context.datasets ?? []).slice(0, 4)) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n head.textContent = `dataset ${datasetvalue.name}: ${datasetvalue.rows.length} row${datasetvalue.rows.length === 1 ? \"\" : \"s\"} \u00B7 ${datasetvalue.columns.length} column${datasetvalue.columns.length === 1 ? \"\" : \"s\"}${(context.imports ?? []).some(item => item.id === datasetvalue.id) ? \" \u00B7 imported csv\" : \"\"}`;\n card.append(head);\n const grid = document.createElement(\"table\");\n const headerrow = document.createElement(\"tr\");\n for (const column of datasetvalue.columns.slice(0, 6)) {\n const cell = document.createElement(\"th\");\n cell.textContent = `${column.label || column.key} ${column.kind === \"number\" ? \"#\" : \"\"}`;\n cell.addEventListener(\"click\", () => {\n const body = grid.querySelector(\"tbody\");\n if (!body) return;\n const sorted = sortrows(datasetvalue.rows.slice(0, 5), column.key, cell.dataset.sorted === \"asc\" ? \"desc\" : \"asc\");\n cell.dataset.sorted = cell.dataset.sorted === \"asc\" ? \"desc\" : \"asc\";\n body.replaceChildren(...sorted.map(row => {\n const line = document.createElement(\"tr\");\n for (const columnspec of datasetvalue.columns.slice(0, 6)) {\n const value = document.createElement(\"td\");\n value.textContent = row[columnspec.key] ?? \"\";\n line.append(value);\n }\n return line;\n }));\n });\n headerrow.append(cell);\n }\n grid.append(headerrow);\n const body = document.createElement(\"tbody\");\n for (const row of datasetvalue.rows.slice(0, 5)) {\n const line = document.createElement(\"tr\");\n for (const column of datasetvalue.columns.slice(0, 6)) {\n const cell = document.createElement(\"td\");\n cell.textContent = row[column.key] ?? \"\";\n line.append(cell);\n }\n body.append(line);\n }\n grid.append(body);\n card.append(grid);\n if (active) {\n const actions = document.createElement(\"p\");\n for (const format of [\"csv\", \"json\", \"excel\"] as const) {\n actions.append(\" \", button(`Export ${format}`, async () => {\n const artifact = await request({ kind: \"exportdataset\", datasetid: datasetvalue.id, format }) as { name: string; checksum: string };\n status(`Exported ${datasetvalue.name} to ${artifact.name} with checksum ${artifact.checksum}.`);\n await refresh();\n }));\n }\n card.append(actions);\n }\n datasetsroot.append(card);\n }\n const provenances = context.provenances ?? [];\n if (provenances.length > 0) {\n const list = document.createElement(\"ul\");\n for (const record of provenances.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.name}: rows ${record.rowstart}\u2013${record.rowend} \u00B7 checksum ${record.checksum} \u00B7 source ${record.url}`;\n list.append(item);\n }\n datasetsroot.append(list);\n }\n const sheetendpoints = context.sheetendpoints ?? [];\n if (sheetendpoints.length > 0) {\n const sheets = document.createElement(\"p\");\n sheets.textContent = `sheet endpoints: ${sheetendpoints.map(config => `${config.origin} ${config.granted ? \"granted\" : \"not granted\"}`).join(\" \u00B7 \")}`;\n datasetsroot.append(sheets);\n }\n if (active) {\n const importer = document.createElement(\"div\");\n importer.className = \"panel\";\n const csvinput = document.createElement(\"textarea\");\n csvinput.rows = 3;\n csvinput.placeholder = \"Paste reviewed csv content for a fill loop (header line first).\";\n const nameinput = document.createElement(\"input\");\n nameinput.placeholder = \"dataset name (optional)\";\n const mappinginput = document.createElement(\"input\");\n mappinginput.placeholder = \"column mapping json (optional, csv header \u2192 target)\";\n importer.append(csvinput, nameinput, mappinginput, \" \", button(\"Import csv\", async () => {\n let mapping: Record<string, string> = {};\n if (mappinginput.value.trim()) {\n try { mapping = JSON.parse(mappinginput.value) as Record<string, string>; } catch { status(\"The column mapping must be a json object.\", true); return; }\n }\n const imported = await request({ kind: \"importcsv\", csv: csvinput.value, name: nameinput.value, mapping }) as { name: string; rows: number };\n status(`Imported ${imported.rows} rows as dataset ${imported.name} for fill loops.`);\n await refresh();\n }));\n datasetsroot.append(importer);\n }\n}\n\n/** Renders the files, clipboard and downloads surface: the batch download queue with per file states and pause, resume and verify actions, mime interception rules with origin grants, clipboard consent prompts with the requesting step, the netlog viewer with step correlation filters and redaction notices, the quarantine list with scan verdicts and release actions, capture naming previews, cleanup policy editing, artifact inventories and copyscreen results. */\nfunction renderfiles(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; plan?: agentplan; downloads?: downloadrecord[]; mimefilters?: mimefilter[]; clipconsents?: clipboardconsentrecord[]; clips?: clipentry[]; netlogs?: netlogrecord[]; quarantines?: quarantineentry[]; capturecounters?: Array<{ taskid: string; counters: Record<string, number>; at: number }>; cleanuprules?: cleanuprule[]; cleanupruns?: cleanuprun[]; inventory?: artifactinventoryentry[]; scanhooks?: Array<{ scanner: string; endpoint: string; origin: string; configuredat: number; granted: boolean }> }): void {\n if (!filesroot) return;\n filesroot.replaceChildren();\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const downloads = context.downloads ?? [];\n if (downloads.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n const states = [\"queued\", \"running\", \"paused\", \"complete\", \"failed\"] as const;\n head.textContent = `batch download queue: ${downloads.length} file${downloads.length === 1 ? \"\" : \"s\"} (${states.map(state => `${downloads.filter(item => item.state === state).length} ${state}`).filter(part => !part.startsWith(\"0 \")).join(\" \u00B7 \") || \"none\"})`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const record of downloads.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.filename} \u00B7 ${record.state}${record.bytes !== undefined ? ` \u00B7 ${record.bytes} bytes` : \"\"}${record.checksum !== undefined ? ` \u00B7 checksum ${record.checksum}` : \"\"}${record.path !== undefined ? ` \u00B7 ${record.path}` : \"\"}`;\n if (active) {\n item.append(\" \", button(\"Pause\", () => request({ kind: \"downloadaction\", id: record.id, action: \"pause\" }).then(() => refresh()).then(() => status(`Paused the download of ${record.filename}.`)), record.state !== \"running\"));\n item.append(\" \", button(\"Resume\", () => request({ kind: \"downloadaction\", id: record.id, action: \"resume\" }).then(() => refresh()).then(() => status(`Resumed the download of ${record.filename}.`)), record.state !== \"paused\"));\n item.append(\" \", button(\"Verify\", () => request({ kind: \"downloadaction\", id: record.id, action: \"verify\" }).then(value => { const output = value as { summary: string }; status(output.summary); return refresh(); })));\n }\n list.append(item);\n }\n card.append(list);\n filesroot.append(card);\n }\n const filters = context.mimefilters ?? [];\n if (filters.length > 0) {\n const filter = filters[0]!;\n const card = document.createElement(\"p\");\n card.textContent = `mime interception: include ${filter.include.join(\", \")} \u00B7 exclude ${filter.exclude.join(\", \") || \"none\"} \u00B7 ${filter.default} default for unlisted mime types${context.session?.origin ? ` \u00B7 armed inside the ${context.session.origin} origin grants` : \"\"}`;\n filesroot.append(card);\n }\n const consents = (context.clipconsents ?? []).filter(record => record.approved === undefined);\n for (const consent of consents.slice(0, 4)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n card.textContent = `Clipboard read consent ${consent.id} waits for your approval: step ${consent.stepid} on ${consent.origin} asked to read the clipboard \u2014 \"${consent.prompt}\".`;\n if (active) {\n card.append(\" \", button(\"Approve read\", async () => { await request({ kind: \"approveclipconsent\", id: consent.id, approved: true }); status(`Clipboard read consent ${consent.id} approved; run the step again to read once.`); await refresh(); }));\n card.append(\" \", button(\"Decline\", async () => { await request({ kind: \"approveclipconsent\", id: consent.id, approved: false }); status(`Clipboard read consent ${consent.id} declined.`); await refresh(); }));\n }\n filesroot.append(card);\n }\n const netlogs = context.netlogs ?? [];\n if (netlogs.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n const steps = [...new Set(netlogs.map(record => record.stepid))];\n head.textContent = `network log: ${netlogs.length} record${netlogs.length === 1 ? \"\" : \"s\"} correlated with ${steps.length} step${steps.length === 1 ? \"\" : \"s\"} (${steps.slice(0, 4).join(\", \")}${steps.length > 4 ? \"\u2026\" : \"\"})`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const record of netlogs.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.method} ${record.url} \u00B7 ${record.status} \u00B7 ${record.timing}ms \u00B7 request ${record.requestid ?? \"?\"} \u00B7 step ${record.stepid}`;\n list.append(item);\n }\n card.append(list);\n if (active) card.append(button(\"Export netlog (header values redacted)\", async () => { const exported = await request({ kind: \"exportnetlog\" }) as { records: unknown[]; redaction: string }; status(`Exported ${exported.records.length} netlog records; ${exported.redaction}.`); }));\n filesroot.append(card);\n }\n const quarantines = context.quarantines ?? [];\n if (quarantines.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n head.textContent = `quarantine: ${quarantines.length} file${quarantines.length === 1 ? \"\" : \"s\"} outside the downloads folder (${quarantines.filter(entry => entry.scan === \"pending\").length} awaiting scan verdicts)`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const entry of quarantines.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.path} \u00B7 scan ${entry.scan}${entry.release !== undefined ? ` \u00B7 released under ${entry.release}` : \"\"} \u00B7 ${entry.reason}`;\n if (active && entry.release === undefined && entry.scan === \"clean\") item.append(\" \", button(\"Release\", async () => { await request({ kind: \"releasequarantine\", id: entry.id }); status(`Released ${entry.path} from quarantine under the clean scan verdict.`); await refresh(); }));\n list.append(item);\n }\n card.append(list);\n filesroot.append(card);\n }\n const planid = context.plan?.id;\n const counters = (context.capturecounters ?? []).find(item => item.taskid === planid);\n if (counters) {\n const card = document.createElement(\"p\");\n card.textContent = `capture naming for task ${counters.taskid}: ${Object.entries(counters.counters).map(([step, sequence]) => `${step} \u2192 ${counters.taskid}-${step}-${sequence}`).join(\" \u00B7 \")}`;\n filesroot.append(card);\n }\n const rules = context.cleanuprules ?? [];\n const rulecard = document.createElement(\"div\");\n rulecard.className = \"panel\";\n const rulehead = document.createElement(\"p\");\n rulehead.textContent = `cleanup policy: ${rules.length > 0 ? rules.map(rule => `older than ${rule.age}ms of kind ${rule.kind} keep ${rule.keep}`).join(\" \u00B7 \") : \"no rule set stored yet\"}`;\n rulecard.append(rulehead);\n const runs = context.cleanupruns ?? [];\n if (runs.length > 0) {\n const lastrun = runs[0]!;\n const runline = document.createElement(\"p\");\n runline.textContent = `last sweep: removed ${lastrun.removed}, kept ${lastrun.kept} under ${lastrun.rules} rule${lastrun.rules === 1 ? \"\" : \"s\"}`;\n rulecard.append(runline);\n }\n if (active) {\n const ageinput = document.createElement(\"input\");\n ageinput.placeholder = \"age window in ms\";\n const kindinput = document.createElement(\"input\");\n kindinput.placeholder = \"artifact kind (any matches all)\";\n const keepinput = document.createElement(\"input\");\n keepinput.placeholder = \"keep policy: none, latest or all\";\n rulecard.append(ageinput, kindinput, keepinput, \" \", button(\"Add cleanup rule\", async () => {\n const age = Number(ageinput.value);\n const rule = { age, kind: kindinput.value.trim() || \"any\", keep: keepinput.value.trim() || \"none\" } as cleanuprule;\n const stored = await request({ kind: \"setcleanuprules\", rules: [...rules, rule] }) as { rules: number };\n status(`Stored ${stored.rules} reviewed cleanup rule${stored.rules === 1 ? \"\" : \"s\"}; ages stay your choice with no code ceiling.`);\n await refresh();\n }));\n }\n filesroot.append(rulecard);\n const inventory = context.inventory ?? [];\n if (inventory.length > 0) {\n const card = document.createElement(\"p\");\n card.textContent = `artifact inventory: ${inventory.slice(0, 5).map(entry => `${entry.name} (${entry.kind}, ${entry.size} characters, ${Math.max(0, Math.round((Date.now() - entry.at) / 60000))} minute${Math.round((Date.now() - entry.at) / 60000) === 1 ? \"\" : \"s\"} old)`).join(\" \u00B7 \")}${inventory.length > 5 ? ` and ${inventory.length - 5} more` : \"\"}`;\n filesroot.append(card);\n }\n const screens = (context.clips ?? []).filter(entry => entry.kind === \"screen\").slice(0, 2);\n for (const screen of screens) {\n const card = document.createElement(\"p\");\n card.textContent = `copyscreen result: ${screen.length} characters of png data with payload hash ${screen.hash} routed to the clipboard destination.`;\n filesroot.append(card);\n }\n const hooks = context.scanhooks ?? [];\n if (active) {\n const hookcard = document.createElement(\"div\");\n hookcard.className = \"panel\";\n const hookhead = document.createElement(\"p\");\n hookhead.textContent = hooks.length > 0 ? `scan hooks: ${hooks.map(hook => `${hook.scanner} at ${hook.origin} ${hook.granted ? \"granted\" : \"not granted\"}`).join(\" \u00B7 \")}` : \"scan hooks: none configured; scan verdicts stay pending without one.\";\n hookcard.append(hookhead);\n const scannerinput = document.createElement(\"input\");\n scannerinput.placeholder = \"scanner name\";\n const endpointinput = document.createElement(\"input\");\n endpointinput.placeholder = \"https://scanner.example/verdict\";\n hookcard.append(scannerinput, endpointinput, \" \", button(\"Configure scan hook\", async () => {\n await request({ kind: \"configurescanhook\", scanner: scannerinput.value, endpoint: endpointinput.value });\n status(`Scan hook ${scannerinput.value} configured; hook failures stay pending verdicts.`);\n await refresh();\n }));\n filesroot.append(hookcard);\n }\n}\n\nfunction rendercapabilities(report?: capabilityreport): void {\n if (!capabilitiestext) return;\n if (!report) { capabilitiestext.textContent = \"Optional capabilities unknown.\"; return; }\n capabilitiestext.textContent = `tabs ${report.tabs ? \"granted\" : \"absent\"} \u00B7 downloads ${report.downloads ? \"granted\" : \"absent\"} \u00B7 clipboard read ${report.clipboardread ? \"granted\" : \"absent\"} \u00B7 clipboard write ${report.clipboardwrite ? \"granted\" : \"absent\"}`;\n}\n\nfunction renderaudit(events: auditevent[]): void { if (!auditroot) return; auditroot.replaceChildren(); for (const event of events.slice(0, 12)) { const item = document.createElement(\"li\"); item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 ${event.kind} \u00B7 ${event.summary}`; auditroot.append(item); } }\nfunction renderdiagnostic(report?: diagnosticreport): void { if (!diagnosticroot) return; diagnosticroot.replaceChildren(); if (!report) { diagnosticroot.textContent = \"Run a local diagnostic after starting a session to record bridge and page-shape health.\"; return; } const values = [`origin: ${report.origin}`, `title: ${report.title || \"untitled\"}`, `interactive elements: ${report.interactivecount}`, `forms: ${report.formcount}`, `page text length: ${report.textlength}`, `bridge available: ${report.bridgeavailable ? \"yes\" : \"no\"}`]; for (const value of values) { const item = document.createElement(\"li\"); item.textContent = value; diagnosticroot.append(item); } }\nasync function refresh(): Promise<void> { const context = await request({ kind: \"context\" }) as { plan?: agentplan; progress?: planprogress; diagnostic?: diagnosticreport; audit: auditevent[]; outcomes?: stepoutcome[]; capabilities?: capabilityreport; session?: { id: string; pausedat?: number; stoppedat?: number; expiresat: number; origin?: string }; map?: clickablemap; retries?: retryoutcome[]; a11y?: a11ycapture; reader?: readercapture; banners?: bannerreport[]; mutationevents?: mutationevent[]; focusevents?: focusevent[]; diffs?: snapshotdiff[]; selectors?: derivedselector[]; trail?: { trail: trailentry[] }; navrecords?: navrecord[]; ratestates?: ratelimitstate[]; safeties?: safetyverdict[]; curated?: curatedlist[]; waitprofiles?: waitprofilerecord[]; auths?: Array<{ origin: string; username: string; reviewedat: number }>; navcontrol?: navcontrol; navqueues?: navqueues; artifacts?: artifactrecord[]; tabs?: tabshape[]; windows?: windowshape[]; tabgroups?: tabgrouprecord[]; badges?: tabbadge[]; tabmetas?: tabmeta[]; clones?: Array<{ url: string; tabids: number[] }>; layouts?: tablayout[]; snapshots?: sessionsnapshot[]; closedtabs?: closedtab[]; tasktabgauge?: { used: number; ceiling?: number; over: boolean }; controltab?: controltabstate; profiles?: formprofile[]; tickets?: submitticket[]; wizards?: { wizards: wizardstate[]; picks: typeaheadpick[] }; picks?: typeaheadpick[]; errorreports?: errorreport[]; captchas?: captchahandoff[]; detections?: detectionrecord[]; codeentry?: boolean; datasets?: dataset[]; imports?: dataset[]; extractsessions?: extractsession[]; streams?: streamstate[]; exports?: Array<{ id: string; kind: string; name: string; rowcount: number; checksum: string; at: number }>; provenances?: provenancerecord[]; taskrules?: taskrules[]; sheetendpoints?: Array<{ endpoint: string; origin: string; configuredat: number; granted: boolean }>; downloads?: downloadrecord[]; mimefilters?: mimefilter[]; clipconsents?: clipboardconsentrecord[]; clips?: clipentry[]; netlogs?: netlogrecord[]; quarantines?: quarantineentry[]; capturecounters?: Array<{ taskid: string; counters: Record<string, number>; at: number }>; cleanuprules?: cleanuprule[]; cleanupruns?: cleanuprun[]; inventory?: artifactinventoryentry[]; scanhooks?: Array<{ scanner: string; endpoint: string; origin: string; configuredat: number; granted: boolean }> }; renderplan(context.plan, context.progress, context.outcomes ?? [], context.retries ?? []); renderdiagnostic(context.diagnostic); rendermap(context.map); rendera11y(context.a11y); renderreader(context.reader); renderdetections(context.plan, context.outcomes ?? []); renderstream(context.mutationevents ?? [], context.focusevents ?? []); renderdiffs(context.diffs ?? []); renderbanners(context.banners ?? []); renderselectors(context.selectors ?? []); rendertrail(context.trail?.trail ?? []); rendernavigation(context); rendertabswindows(context); renderforms(context); renderdatasets(context); renderfiles(context); renderaudit(context.audit); rendercapabilities(context.capabilities); if (context.session?.pausedat) status(\"Session paused. Reviewed actions are blocked until resume.\"); else status(context.session ? \"Active session is visible. The extension is waiting for review.\" : \"No active browser session.\"); }\nasync function create(kind: \"proposelocal\" | \"proposeremote\"): Promise<void> { await request({ kind, objective: objective?.value ?? \"\" }); await refresh(); }\nlocalbutton?.addEventListener(\"click\", () => create(\"proposelocal\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\nremotebutton?.addEventListener(\"click\", () => create(\"proposeremote\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\ndiagnosticbutton?.addEventListener(\"click\", () => request({ kind: \"diagnostic\" }).then(() => refresh()).catch(error => status(error instanceof Error ? error.message : String(error), true)));\nrefresh().catch(error => status(error instanceof Error ? error.message : String(error), true));\n"],
5
- "mappings": ";AAEA,IAAM,mBAAmB,oBAAI,IAAgB,CAAC,SAAS,QAAQ,YAAY,UAAU,YAAY,QAAQ,QAAQ,UAAU,SAAS,SAAS,WAAW,UAAU,UAAU,UAAU,QAAQ,WAAW,gBAAgB,gBAAgB,mBAAmB,YAAY,aAAa,eAAe,YAAY,aAAa,gBAAgB,eAAe,gBAAgB,gBAAgB,cAAc,cAAc,iBAAiB,cAAc,YAAY,cAAc,YAAY,YAAY,WAAW,cAAc,gBAAgB,eAAe,eAAe,aAAa,WAAW,YAAY,YAAY,eAAe,eAAe,WAAW,cAAc,UAAU,gBAAgB,eAAe,WAAW,cAAc,cAAc,YAAY,YAAY,cAAc,YAAY,aAAa,YAAY,WAAW,iBAAiB,aAAa,gBAAgB,gBAAgB,UAAU,WAAW,WAAW,iBAAiB,aAAa,cAAc,iBAAiB,cAAc,cAAc,UAAU,WAAW,aAAa,kBAAkB,kBAAkB,iBAAiB,eAAe,iBAAiB,mBAAmB,cAAc,iBAAiB,aAAa,YAAY,YAAY,aAAa,mBAAmB,cAAc,aAAa,aAAa,eAAe,iBAAiB,YAAY,cAAc,YAAY,YAAY,mBAAmB,aAAa,cAAc,eAAe,aAAa,cAAc,cAAc,mBAAmB,iBAAiB,iBAAiB,iBAAiB,kBAAkB,iBAAiB,iBAAiB,kBAAkB,cAAc,sBAAsB,aAAa,kBAAkB,CAAC;AAClpD,IAAM,qBAAqB,oBAAI,IAAgB,CAAC,SAAS,UAAU,SAAS,aAAa,cAAc,eAAe,cAAc,YAAY,aAAa,aAAa,cAAc,WAAW,eAAe,aAAa,aAAa,aAAa,iBAAiB,gBAAgB,aAAa,CAAC;AACxS,IAAM,cAAc,oBAAI,IAAgB,CAAC,WAAW,WAAW,WAAW,QAAQ,WAAW,YAAY,iBAAiB,aAAa,gBAAgB,aAAa,YAAY,YAAY,iBAAiB,aAAa,aAAa,cAAc,YAAY,aAAa,eAAe,aAAa,WAAW,cAAc,eAAe,aAAa,iBAAiB,iBAAiB,gBAAgB,YAAY,eAAe,cAAc,eAAe,gBAAgB,YAAY,eAAe,aAAa,eAAe,wBAAwB,iBAAiB,cAAc,iBAAiB,YAAY,eAAe,cAAc,cAAc,cAAc,gBAAgB,sBAAsB,iBAAiB,iBAAiB,cAAc,gBAAgB,oBAAoB,iBAAiB,kBAAkB,kBAAkB,YAAY,WAAW,WAAW,cAAc,iBAAiB,gBAAgB,cAAc,aAAa,aAAa,aAAa,YAAY,cAAc,cAAc,aAAa,mBAAmB,cAAc,cAAc,gBAAgB,kBAAkB,gBAAgB,aAAa,cAAc,gBAAgB,eAAe,kBAAkB,kBAAkB,eAAe,aAAa,YAAY,mBAAmB,cAAc,cAAc,eAAe,eAAe,iBAAiB,kBAAkB,gBAAgB,cAAc,CAAC;AAC73C,IAAM,iBAAiB,oBAAI,IAAgB,CAAC,GAAG,kBAAkB,GAAG,oBAAoB,GAAG,WAAW,CAAC;;;AC6KhG,SAAS,aAAa,MAAkB,SAA+C,QAA4B;AACxH,QAAM,SAAS,OAAO,KAAK,EAAE,YAAY;AACzC,QAAM,UAAU,SAAS,KAAK,OAAO,SAAO,IAAI,MAAM,YAAY,EAAE,SAAS,MAAM,KAAK,IAAI,IAAI,YAAY,EAAE,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI;AAC1I,QAAM,UAAU,IAAI,IAAI,QAAQ,IAAI,WAAS,CAAC,MAAM,OAAO,MAAM,EAAE,CAAC,CAAC;AACrE,SAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,UAAU;AACxC,UAAM,SAAS,QAAQ,IAAI,KAAK,KAAK,KAAK;AAC1C,UAAM,UAAU,QAAQ,IAAI,MAAM,KAAK,KAAK;AAC5C,QAAI,WAAW,QAAS,QAAO,UAAU;AACzC,WAAO,KAAK,QAAQ,MAAM;AAAA,EAC5B,CAAC;AACH;;;ACnBO,SAAS,SAAS,OAAuB;AAC9C,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,qBAAqB,KAAK,OAAO,GAAG;AACtC,UAAM,UAAU,QAAQ,QAAQ,UAAU,EAAE;AAC5C,UAAM,OAAO,QAAQ,MAAM,EAAE;AAC7B,WAAO,GAAG,SAAI,OAAO,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;AAAA,EAC9D;AACA,SAAO,SAAI,OAAO,QAAQ,MAAM;AAClC;;;ACzCO,SAAS,SAAS,MAAoB,KAAa,WAAyC;AACjG,QAAM,OAAO,cAAc,SAAS,KAAK;AACzC,SAAO,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,MAAM,UAAU;AACrC,UAAM,IAAI,KAAK,GAAG,KAAK;AACvB,UAAM,IAAI,MAAM,GAAG,KAAK;AACxB,UAAM,UAAU,OAAO,CAAC;AACxB,UAAM,WAAW,OAAO,CAAC;AACzB,QAAI,OAAO,SAAS,OAAO,KAAK,OAAO,SAAS,QAAQ,KAAK,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,GAAI,SAAQ,UAAU,YAAY;AAC/H,WAAO,EAAE,cAAc,CAAC,IAAI;AAAA,EAC9B,CAAC;AACH;;;AC7IA,IAAM,YAAY,SAAS,cAAmC,YAAY;AAC1E,IAAM,cAAc,SAAS,cAAiC,YAAY;AAC1E,IAAM,eAAe,SAAS,cAAiC,aAAa;AAC5E,IAAM,mBAAmB,SAAS,cAAiC,aAAa;AAChF,IAAM,WAAW,SAAS,cAA2B,OAAO;AAC5D,IAAM,YAAY,SAAS,cAA2B,QAAQ;AAC9D,IAAM,iBAAiB,SAAS,cAA2B,cAAc;AACzE,IAAM,UAAU,SAAS,cAA2B,MAAM;AAC1D,IAAM,WAAW,SAAS,cAA2B,OAAO;AAC5D,IAAM,aAAa,SAAS,cAA2B,SAAS;AAChE,IAAM,iBAAiB,SAAS,cAA2B,aAAa;AACxE,IAAM,aAAa,SAAS,cAA2B,SAAS;AAChE,IAAM,YAAY,SAAS,cAA2B,QAAQ;AAC9D,IAAM,cAAc,SAAS,cAA2B,UAAU;AAClE,IAAM,gBAAgB,SAAS,cAA2B,YAAY;AACtE,IAAM,YAAY,SAAS,cAA2B,QAAQ;AAC9D,IAAM,iBAAiB,SAAS,cAA2B,aAAa;AACxE,IAAM,kBAAkB,SAAS,cAA2B,cAAc;AAC1E,IAAM,YAAY,SAAS,cAA2B,QAAQ;AAC9D,IAAM,eAAe,SAAS,cAA2B,WAAW;AACpE,IAAM,YAAY,SAAS,cAA2B,QAAQ;AAC9D,IAAM,aAAa,SAAS,cAA2B,SAAS;AAChE,IAAM,eAAe,SAAS,cAAmC,eAAe;AAChF,IAAM,mBAAmB,SAAS,cAA2B,mBAAmB;AAGhF,IAAM,WAAW,oBAAI,IAA2B;AAGhD,SAAS,QAAQ,MAAyC;AACxD,MAAI,CAAC,KAAK,QAAS,QAAO,CAAC;AAC3B,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK,OAAO;AACtC,WAAO,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,IAAK,SAAqC,CAAC;AAAA,EACjH,QAAQ;AAAE,WAAO,CAAC;AAAA,EAAG;AACvB;AAEA,SAAS,OAAO,SAAiB,QAAQ,OAAa;AAAE,MAAI,YAAY;AAAE,eAAW,cAAc;AAAS,eAAW,QAAQ,QAAQ,QAAQ,UAAU;AAAA,EAAS;AAAE;AACpK,eAAe,QAAQ,SAAoC;AAAE,QAAM,WAAW,MAAM,OAAO,QAAQ,YAAY,OAAO;AAAuD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,SAAS,KAAK;AAAG,SAAO,SAAS;AAAO;AACvP,SAAS,OAAO,OAAe,QAA6B,WAAW,OAA0B;AAAE,QAAM,UAAU,SAAS,cAAc,QAAQ;AAAG,UAAQ,OAAO;AAAU,UAAQ,cAAc;AAAO,UAAQ,WAAW;AAAU,UAAQ,iBAAiB,SAAS,MAAM,OAAO,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AAAG,SAAO;AAAS;AAGhY,IAAM,eAAe,CAAC,SAAS,WAAW,SAAS,QAAQ,UAAU,UAAU,SAAS,aAAa,cAAc,eAAe,QAAQ,QAAQ,UAAU,SAAS,SAAS,WAAW,UAAU,UAAU,iBAAiB,aAAa,gBAAgB,aAAa,YAAY,YAAY,iBAAiB,aAAa,aAAa,gBAAgB,mBAAmB,WAAW,cAAc,YAAY,cAAc,YAAY,YAAY,gBAAgB,eAAe,eAAe,aAAa,WAAW,YAAY,iBAAiB,iBAAiB,iBAAiB,gBAAgB,cAAc,aAAa,aAAa,aAAa,gBAAgB,kBAAkB,sBAAsB,cAAc,aAAa,eAAe,iBAAiB,YAAY,cAAc,YAAY,iBAAiB;AAG7yB,IAAM,YAAuD;AAAA,EAC3D,EAAE,OAAO,WAAW,OAAO,CAAC,eAAe,cAAc,cAAc,aAAa,aAAa,aAAa,cAAc,EAAE;AAAA,EAC9H,EAAE,OAAO,UAAU,OAAO,CAAC,YAAY,cAAc,YAAY,YAAY,cAAc,EAAE;AAAA,EAC7F,EAAE,OAAO,QAAQ,OAAO,CAAC,WAAW,YAAY,EAAE;AAAA,EAClD,EAAE,OAAO,YAAY,OAAO,CAAC,eAAe,eAAe,aAAa,WAAW,YAAY,eAAe,EAAE;AAAA,EAChH,EAAE,OAAO,WAAW,OAAO,CAAC,eAAe,EAAE;AAAA,EAC7C,EAAE,OAAO,UAAU,OAAO,CAAC,YAAY,EAAE;AAAA,EACzC,EAAE,OAAO,SAAS,OAAO,CAAC,aAAa,EAAE;AAAA,EACzC,EAAE,OAAO,SAAS,OAAO,CAAC,aAAa,iBAAiB,iBAAiB,cAAc,EAAE;AAAA,EACzF,EAAE,OAAO,eAAe,OAAO,CAAC,YAAY,eAAe,cAAc,eAAe,iBAAiB,iBAAiB,YAAY,kBAAkB,cAAc,cAAc,eAAe,EAAE;AAAA,EACrM,EAAE,OAAO,aAAa,OAAO,CAAC,eAAe,gBAAgB,wBAAwB,iBAAiB,cAAc,gBAAgB,oBAAoB,cAAc,gBAAgB,oBAAoB,EAAE;AAAA,EAC5M,EAAE,OAAO,SAAS,OAAO,CAAC,eAAe,eAAe,cAAc,aAAa,YAAY,iBAAiB,gBAAgB,EAAE;AAAA,EAClI,EAAE,OAAO,cAAc,OAAO,CAAC,YAAY,eAAe,eAAe,WAAW,YAAY,WAAW,cAAc,UAAU,WAAW,gBAAgB,eAAe,WAAW,cAAc,cAAc,iBAAiB,gBAAgB,cAAc,YAAY,YAAY,cAAc,YAAY,aAAa,cAAc,YAAY,aAAa,WAAW,iBAAiB,aAAa,WAAW,EAAE;AAAA,EAC/Z,EAAE,OAAO,QAAQ,OAAO,CAAC,aAAa,gBAAgB,gBAAgB,UAAU,WAAW,WAAW,iBAAiB,aAAa,cAAc,iBAAiB,cAAc,cAAc,UAAU,WAAW,YAAY,aAAa,kBAAkB,kBAAkB,iBAAiB,eAAe,iBAAiB,mBAAmB,cAAc,cAAc,iBAAiB,cAAc,cAAc,YAAY,cAAc,aAAa,aAAa,iBAAiB,EAAE;AAAA,EACre,EAAE,OAAO,SAAS,OAAO,CAAC,YAAY,aAAa,mBAAmB,gBAAgB,kBAAkB,gBAAgB,aAAa,cAAc,cAAc,aAAa,aAAa,eAAe,iBAAiB,YAAY,cAAc,kBAAkB,YAAY,YAAY,mBAAmB,gBAAgB,eAAe,gBAAgB,EAAE;AACrW;AAEA,SAAS,UAAU,MAAkC;AACnD,SAAO,UAAU,KAAK,SAAO,IAAI,MAAM,SAAS,IAAI,CAAC,GAAG;AAC1D;AAGA,SAAS,eAAe,MAAiB,WAA2B;AAClE,MAAI,CAAC,aAAc;AACnB,QAAM,QAAQ,KAAK,MAAM,UAAU;AACnC,eAAa,MAAM;AACnB,eAAa,QAAQ,UAAU;AAC/B,eAAa,cAAc,GAAG,UAAU,MAAM,OAAO,KAAK,MAAM,MAAM;AACxE;AAGA,SAAS,cAAc,MAAgB,UAA6C;AAClF,QAAM,UAAU,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,UAAQ,KAAK,WAAW,KAAK,MAAM,KAAK,EAAE,KAAK,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,UAAQ,KAAK,WAAW,KAAK,EAAE;AACxJ,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,OAAO,SAAS,cAAc,SAAS;AAC7C,OAAK,YAAY;AACjB,QAAM,UAAU,SAAS,cAAc,SAAS;AAChD,UAAQ,cAAc,GAAG,QAAQ,KAAK,WAAW,SAAS,KAAK,QAAQ,OAAO;AAC9E,OAAK,OAAO,OAAO;AACnB,MAAI,QAAQ,WAAW,OAAO,KAAK,QAAQ,OAAO,EAAE,SAAS,GAAG;AAC9D,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,cAAc,KAAK,UAAU,QAAQ,SAAS,MAAM,CAAC,EAAE,MAAM,GAAG,GAAI;AAC5E,SAAK,OAAO,OAAO;AAAA,EACrB;AACA,SAAO;AACT;AAGA,SAAS,WAAW,MAAwB;AAC1C,MAAI,KAAK,SAAS,WAAW;AAC3B,UAAM,SAAS,QAAQ,IAAI,EAAE;AAC7B,WAAO,OAAO,WAAW,YAAY,SAAS,iBAAc,MAAM,KAAK;AAAA,EACzE;AACA,MAAI,KAAK,SAAS,aAAc,QAAO,KAAK,QAAQ,0BAAuB,KAAK,KAAK,KAAK;AAC1F,SAAO;AACT;AAGA,SAAS,YAAY,MAAgB,SAA6C;AAChF,QAAM,SAAS,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAQ,KAAK,WAAW,KAAK,EAAE;AAC1E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,OAAK,cAAc,mBAAmB,OAAO,QAAQ,WAAW,OAAO,aAAa,IAAI,KAAK,GAAG,SAAM,OAAO,SAAS,QAAQ,CAAC,CAAC,qBAAkB,OAAO,KAAK,cAAc,QAAQ;AACpL,SAAO;AACT;AAGA,SAAS,YAAY,MAAgB,UAA6C;AAChF,MAAI,KAAK,SAAS,YAAa,QAAO;AACtC,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,WAAW,KAAK,EAAE;AACjF,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,UAAU,MAAM,QAAQ,OAAO,SAAS,OAAO,IAAI,OAAO,SAAS,UAAqD,CAAC;AAC/H,QAAM,OAAO,OAAO,OAAO,SAAS,SAAS,WAAW,OAAO,SAAS,OAAO;AAC/E,QAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACvC,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,OAAK,cAAc,kBAAkB,QAAQ,MAAM,UAAU,QAAQ,WAAW,IAAI,KAAK,GAAG,mBAAgB,KAAK,MAAM,MAAM,YAAY,CAAC,CAAC,2BAAwB,IAAI,YAAS,OAAO,KAAK,kBAAkB,YAAY;AAC1N,SAAO;AACT;AAGA,SAAS,WAAW,MAAgB,UAAwD;AAC1F,MAAI,KAAK,SAAS,WAAY,QAAO;AACrC,QAAM,cAAc,UAAU,YAAY,CAAC,GAAG,OAAO,aAAW,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,cAAc,MAAS;AACtI,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,QAAM,SAAS,WAAW,WAAW,SAAS,CAAC;AAC/C,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,YAAY,OAAO,SAAS;AAClC,QAAM,QAAQ,YAAY,OAAO,QAAQ,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,EAAE,KAAK,IAAI,IAAI;AACtH,OAAK,cAAc,kBAAkB,WAAW,MAAM,aAAa,WAAW,WAAW,IAAI,KAAK,GAAG,SAAM,OAAO,OAAO,SAAS,YAAY,KAAK,CAAC,cAAc,KAAK;AACvK,SAAO;AACT;AAGA,SAAS,cAAc,MAAgB,UAAoC,UAA6C;AACtH,MAAI,KAAK,SAAS,UAAW,QAAO;AACpC,QAAM,WAAW,UAAU,YAAY,CAAC,GAAG,OAAO,aAAW,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,aAAa,MAAS,EAAE,IAAI,aAAW,QAAQ,SAAS,QAAuD;AAC3N,QAAM,QAAQ,QAAQ,SAAS,IAAI,KAAK,IAAI,GAAG,QAAQ,IAAI,WAAS,MAAM,KAAK,CAAC,IAAI,IAAI;AACxF,QAAM,gBAAgB,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,WAAW,KAAK,EAAE;AACxF,QAAM,YAAY,OAAO,eAAe,SAAS,cAAc,WAAW,cAAc,SAAS,YAAY;AAC7G,QAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,OAAK,cAAc,QAAQ,WAAW,IAClC,4CACA,oBAAoB,QAAQ,OAAO,WAAS,MAAM,EAAE,EAAE,MAAM,OAAO,KAAK,uCAAoC,SAAS,OAAO,EAAE,SAAM,SAAS;AACjJ,SAAO;AACT;AAGA,SAAS,eAAe,MAAgB,UAA6C;AACnF,MAAI,CAAC,CAAC,YAAY,cAAc,UAAU,WAAW,YAAY,aAAa,EAAE,SAAS,KAAK,IAAI,EAAG,QAAO;AAC5G,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,SAAS,MAAS;AACxH,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,OAAO,SAAS,SAAS,WAAW,OAAO,SAAS,OAAO;AAC/E,QAAM,QAAQ,OAAO,OAAO,SAAS,aAAa,WAAW,OAAO,SAAS,WAAW;AACxF,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,YAAY;AACjB,OAAK,cAAc,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC,OAAO,OAAO,MAAM,IAAI,KAAK,GAAG,mBAAgB,SAAS,SAAS;AACxH,SAAO;AACT;AAGA,SAAS,cAAc,MAAoC;AACzD,QAAM,UAAU,SAAS,IAAI,KAAK,EAAE;AACpC,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,OAAO,SAAS,cAAc,SAAS;AAC7C,OAAK,YAAY;AACjB,QAAM,UAAU,SAAS,cAAc,SAAS;AAChD,UAAQ,cAAc,YAAY,QAAQ,OAAO;AACjD,OAAK,OAAO,OAAO;AACnB,MAAI,QAAQ,gBAAgB;AAC1B,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,cAAc,KAAK,UAAU,QAAQ,gBAAgB,MAAM,CAAC;AACpE,SAAK,OAAO,OAAO;AAAA,EACrB;AACA,MAAI,QAAQ,cAAc,QAAQ,WAAW,SAAS,GAAG;AACvD,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,SAAK,OAAO,OAAO;AACnB,eAAW,aAAa,QAAQ,YAAY;AAC1C,WAAK,OAAO,KAAK,OAAO,WAAW,SAAS,KAAK,YAAY;AAAE,iBAAS,gBAAgB,SAAS,EAAE;AAAA,MAAG,CAAC,CAAC;AAAA,IAC1G;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,SAAS,MAAiB,MAAgB,WAAqB,UAAyB,SAAyB,UAAwC;AAChK,QAAM,OAAO,SAAS,cAAc,IAAI;AACxC,QAAM,OAAO,UAAU,SAAS,KAAK,EAAE;AACvC,OAAK,cAAc,GAAG,OAAO,WAAM,EAAE,IAAI,KAAK,OAAO,GAAG,WAAW,IAAI,CAAC;AACxE,QAAM,UAAU,cAAc,MAAM,QAAQ;AAC5C,MAAI,QAAS,MAAK,OAAO,OAAO;AAChC,QAAM,WAAW,KAAK,SAAS,gBAAgB,YAAY,MAAM,OAAO,IAAI,YAAY,MAAM,QAAQ;AACtG,MAAI,SAAU,MAAK,OAAO,QAAQ;AAClC,QAAM,UAAU,cAAc,MAAM,UAAU,QAAQ;AACtD,MAAI,QAAS,MAAK,OAAO,OAAO;AAChC,QAAM,WAAW,WAAW,MAAM,QAAQ;AAC1C,MAAI,SAAU,MAAK,OAAO,QAAQ;AAClC,QAAM,YAAY,eAAe,MAAM,QAAQ;AAC/C,MAAI,UAAW,MAAK,OAAO,SAAS;AACpC,QAAM,UAAU,cAAc,IAAI;AAClC,MAAI,QAAS,MAAK,OAAO,OAAO;AAChC,QAAM,YAAY,QAAQ,KAAK,MAAM,KAAK,QAAQ,IAAI,EAAE,cAAc;AACtE,MAAI,CAAC,QAAQ,aAAa,aAAa,SAAS,KAAK,IAAI,KAAK,CAAC,WAAW,UAAU,EAAE,SAAS,KAAK,KAAK,EAAG,MAAK,OAAO,KAAK,OAAO,0BAA0B,YAAY;AAAE,UAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,WAAW,QAAQ,KAAK,GAAG,CAAC;AAAoB,aAAS,IAAI,KAAK,IAAI,MAAM;AAAG,WAAO,OAAO,OAAO;AAAG,UAAM,QAAQ;AAAA,EAAG,CAAC,CAAC;AAC3U,MAAI,CAAC,QAAQ,KAAK,UAAU,WAAY,MAAK,OAAO,KAAK,OAAO,0BAA0B,YAAY;AAAE,UAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,WAAW,QAAQ,KAAK,GAAG,CAAC;AAA0B,WAAO,OAAO,OAAO;AAAG,UAAM,QAAQ;AAAA,EAAG,CAAC,CAAC;AAC9O,SAAO;AACT;AAEA,SAAS,SAAS,MAAiB,OAAmB,WAAqB,UAAyB,SAAyB,MAAwB,UAA6C;AAChM,QAAM,QAAQ,MAAM,OAAO,UAAQ,KAAK,SAAS,IAAI;AACrD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,UAAU,SAAS,cAAc,SAAS;AAChD,QAAM,UAAU,SAAS,cAAc,IAAI;AAC3C,UAAQ,cAAc,GAAG,IAAI;AAC7B,UAAQ,OAAO,OAAO;AACtB,QAAM,UAAU,MAAM,OAAO,UAAQ,UAAU,KAAK,IAAI,MAAM,MAAS;AACvE,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,QAAQ,QAAS,MAAK,OAAO,SAAS,MAAM,MAAM,WAAW,UAAU,SAAS,QAAQ,CAAC;AACpG,YAAQ,OAAO,IAAI;AAAA,EACrB;AACA,aAAW,OAAO,WAAW;AAC3B,UAAM,SAAS,MAAM,OAAO,UAAQ,UAAU,KAAK,IAAI,MAAM,IAAI,KAAK;AACtE,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,MAAM,SAAS,cAAc,IAAI;AACvC,QAAI,cAAc,GAAG,IAAI,KAAK;AAC9B,YAAQ,OAAO,GAAG;AAClB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,QAAQ,OAAQ,MAAK,OAAO,SAAS,MAAM,MAAM,WAAW,UAAU,SAAS,QAAQ,CAAC;AACnG,YAAQ,OAAO,IAAI;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAkB,UAAyB,WAA0B,CAAC,GAAG,UAA0B,CAAC,GAAS;AAC/H,MAAI,CAAC,SAAU;AACf,WAAS,gBAAgB;AACzB,MAAI,CAAC,MAAM;AAAE,aAAS,cAAc;AAAuF,QAAI,aAAc,cAAa,QAAQ;AAAG;AAAA,EAAQ;AAC7K,QAAM,QAAQ,SAAS,cAAc,IAAI;AAAG,QAAM,cAAc,GAAG,KAAK,KAAK,KAAK,KAAK,SAAS;AAAI,WAAS,OAAO,KAAK;AACzH,QAAM,YAAY,UAAU,WAAW,KAAK,KAAK,SAAS,iBAAiB,CAAC;AAC5E,iBAAe,MAAM,SAAS;AAC9B,QAAM,YAAY,SAAS,MAAM,KAAK,OAAO,WAAW,UAAU,SAAS,aAAa,QAAQ;AAChG,QAAM,cAAc,SAAS,MAAM,KAAK,OAAO,WAAW,UAAU,SAAS,eAAe,QAAQ;AACpG,QAAM,OAAO,SAAS,MAAM,KAAK,OAAO,WAAW,UAAU,SAAS,QAAQ,QAAQ;AACtF,aAAW,SAAS,CAAC,WAAW,aAAa,IAAI,EAAG,KAAI,MAAO,UAAS,OAAO,KAAK;AACpF,MAAI,KAAK,UAAU,WAAW;AAAE,aAAS,OAAO,OAAO,yBAAyB,YAAY;AAAE,YAAM,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAG,YAAM,QAAQ;AAAA,IAAG,CAAC,GAAG,OAAO,eAAe,YAAY;AAAE,YAAM,QAAQ,EAAE,MAAM,SAAS,CAAC;AAAG,YAAM,QAAQ;AAAA,IAAG,CAAC,CAAC;AAAA,EAAG;AACpP,MAAI,KAAK,UAAU,eAAe,KAAK,aAAa;AAAE,UAAM,OAAO,SAAS,cAAc,GAAG;AAAG,SAAK,cAAc;AAA4D,aAAS,OAAO,IAAI;AAAA,EAAG;AACxM;AAGA,SAAS,SAAS,MAAoB;AACpC,MAAI,UAAW,WAAU,QAAQ,UAAU,QAAQ,GAAG,UAAU,KAAK;AAAA,EAAK,IAAI,KAAK;AACnF,SAAO,GAAG,IAAI,iDAAiD;AACjE;AAGA,SAAS,UAAU,KAA0B;AAC3C,MAAI,CAAC,QAAS;AACd,UAAQ,gBAAgB;AACxB,MAAI,CAAC,OAAO,IAAI,QAAQ,WAAW,GAAG;AAAE,YAAQ,cAAc;AAAuE;AAAA,EAAQ;AAC7I,aAAW,SAAS,IAAI,SAAS;AAC/B,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,SAAK,OAAO;AACZ,SAAK,cAAc,GAAG,MAAM,MAAM,KAAK,MAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,IAAI;AACnF,SAAK,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,MAAM,QAAQ,eAAe,MAAM,MAAM,KAAK,MAAM,SAAS,MAAM,IAAI,GAAG,CAAC;AACzI,SAAK,OAAO,IAAI;AAChB,YAAQ,OAAO,IAAI;AAAA,EACrB;AACF;AAGA,SAAS,WAAW,SAA6B;AAC/C,MAAI,CAAC,SAAU;AACf,WAAS,gBAAgB;AACzB,MAAI,CAAC,SAAS;AAAE,aAAS,cAAc;AAAmF;AAAA,EAAQ;AAClI,QAAM,QAAkB,CAAC;AACzB,QAAM,OAAO,CAAC,MAAgB,UAAwB;AACpD,QAAI,MAAM,UAAU,GAAI;AACxB,UAAM,SAAS,KAAK,OAAO,SAAS,IAAI,KAAK,KAAK,OAAO,KAAK,IAAI,CAAC,MAAM;AACzE,UAAM,QAAQ,KAAK,UAAU,SAAY,MAAM,KAAK,KAAK,KAAK;AAC9D,UAAM,KAAK,GAAG,QAAK,OAAO,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,KAAK,QAAQ,WAAW,GAAG,MAAM,GAAG,KAAK,EAAE;AAC5F,eAAW,SAAS,KAAK,SAAU,MAAK,OAAO,QAAQ,CAAC;AAAA,EAC1D;AACA,OAAK,QAAQ,MAAM,CAAC;AACpB,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,cAAc,MAAM,KAAK,IAAI;AACrC,WAAS,OAAO,OAAO;AACzB;AAGA,SAAS,aAAa,SAA+B;AACnD,MAAI,CAAC,WAAY;AACjB,aAAW,gBAAgB;AAC3B,MAAI,CAAC,SAAS;AAAE,eAAW,cAAc;AAAqD;AAAA,EAAQ;AACtG,QAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,QAAM,cAAc,GAAG,QAAQ,QAAQ,SAAS,UAAU,GAAG,QAAQ,QAAQ,SAAS,SAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE,SAAM,QAAQ,QAAQ,KAAK,eAAY,QAAQ,QAAQ,OAAO,MAAM;AAC7L,aAAW,OAAO,KAAK;AACvB,aAAW,SAAS,QAAQ,QAAQ,OAAO,MAAM,GAAG,EAAE,GAAG;AACvD,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,YAAY,QAAQ,KAAK,MAAM,IAAI,IAAI,wBAAwB;AACpE,SAAK,cAAc,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,MAAM,GAAG,GAAG,CAAC;AAC7D,eAAW,OAAO,IAAI;AAAA,EACxB;AACF;AAGA,SAAS,iBAAiB,MAA6B,UAA+B;AACpF,MAAI,CAAC,eAAgB;AACrB,iBAAe,gBAAgB;AAC/B,MAAI,CAAC,MAAM;AAAE,mBAAe,cAAc;AAAgG;AAAA,EAAQ;AAClJ,QAAM,SAAS,CAAC,WAAuC,KAAK,MAAM,KAAK,UAAQ,KAAK,OAAO,MAAM,GAAG;AACpG,QAAM,SAAS,CAAC,SAA0C,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,MAAM,OAAO,QAAQ,MAAM,MAAM,IAAI;AAC/I,MAAI,QAAQ;AACZ,QAAM,cAAc,OAAO,aAAa;AACxC,QAAM,QAAQ,MAAM,QAAQ,aAAa,SAAS,KAAK,IAAI,aAAa,SAAS,QAAyB,CAAC;AAC3G,aAAW,WAAW,MAAM,MAAM,GAAG,CAAC,GAAG;AACvC,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,SAAK,OAAO;AACZ,SAAK,cAAc,WAAW,QAAQ,MAAM,eAAY,QAAQ,YAAY;AAC5E,SAAK,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,QAAQ,YAAY,2BAA2B,QAAQ,SAAS,GAAG,CAAC;AAClI,SAAK,OAAO,IAAI;AAChB,mBAAe,OAAO,IAAI;AAC1B,aAAS;AAAA,EACX;AACA,QAAM,eAAe,OAAO,cAAc;AAC1C,QAAM,SAAS,MAAM,QAAQ,cAAc,SAAS,MAAM,IAAI,cAAc,SAAS,SAAyB,CAAC;AAC/G,aAAW,SAAS,OAAO,MAAM,GAAG,CAAC,GAAG;AACtC,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,SAAK,OAAO;AACZ,SAAK,cAAc,YAAY,MAAM,IAAI,cAAW,MAAM,QAAQ,MAAM,iBAAc,MAAM,QAAQ;AACpG,SAAK,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,MAAM,QAAQ,wBAAwB,CAAC;AACrG,SAAK,OAAO,IAAI;AAChB,mBAAe,OAAO,IAAI;AAC1B,aAAS;AAAA,EACX;AACA,QAAM,oBAAoB,OAAO,YAAY;AAC7C,MAAI,mBAAmB;AACrB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAM,UAAU,OAAO,kBAAkB,SAAS,YAAY,WAAW,kBAAkB,SAAS,UAAU;AAC9G,UAAM,QAAQ,OAAO,kBAAkB,SAAS,UAAU,WAAW,kBAAkB,SAAS,QAAQ;AACxG,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,cAAc,4BAA4B,OAAO,yBAAsB,KAAK;AACjF,SAAK,OAAO,IAAI;AAChB,mBAAe,OAAO,IAAI;AAC1B,aAAS;AAAA,EACX;AACA,MAAI,UAAU,EAAG,gBAAe,cAAc;AAChD;AAGA,SAAS,aAAa,gBAAiC,aAAiC;AACtF,MAAI,CAAC,WAAY;AACjB,aAAW,gBAAgB;AAC3B,MAAI,eAAe,WAAW,KAAK,YAAY,WAAW,GAAG;AAAE,eAAW,cAAc;AAA8D;AAAA,EAAQ;AAC9J,aAAW,SAAS,eAAe,MAAM,GAAG,CAAC,GAAG;AAC9C,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,SAAK,cAAc,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,mBAAmB,CAAC,kBAAe,MAAM,KAAK,SAAM,MAAM,UAAU;AAC7G,eAAW,OAAO,IAAI;AAAA,EACxB;AACA,aAAW,SAAS,YAAY,MAAM,GAAG,CAAC,GAAG;AAC3C,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,SAAK,cAAc,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,mBAAmB,CAAC,eAAY,MAAM,IAAI,SAAM,MAAM,UAAU;AACzG,eAAW,OAAO,IAAI;AAAA,EACxB;AACF;AAGA,SAAS,YAAY,OAA6B;AAChD,MAAI,CAAC,UAAW;AAChB,YAAU,gBAAgB;AAC1B,QAAM,SAAS,MAAM,CAAC;AACtB,MAAI,CAAC,QAAQ;AAAE,cAAU,cAAc;AAAqE;AAAA,EAAQ;AACpH,QAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,UAAQ,cAAc,WAAW,OAAO,WAAW,WAAM,OAAO,aAAa,KAAK,OAAO,MAAM,MAAM,eAAY,OAAO,QAAQ,MAAM,iBAAc,OAAO,QAAQ,MAAM;AACzK,YAAU,OAAO,OAAO;AACxB,QAAM,OAAO,SAAS,cAAc,IAAI;AACxC,aAAW,SAAS,CAAC,GAAG,OAAO,OAAO,GAAG,OAAO,SAAS,GAAG,OAAO,OAAO,EAAE,MAAM,GAAG,EAAE,GAAG;AACxF,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,SAAK,YAAY,WAAW,MAAM,IAAI;AACtC,SAAK,cAAc,GAAG,MAAM,IAAI,SAAM,MAAM,QAAQ,SAAM,MAAM,OAAO;AACvE,SAAK,OAAO,IAAI;AAAA,EAClB;AACA,YAAU,OAAO,IAAI;AACvB;AAGA,SAAS,cAAc,SAA+B;AACpD,MAAI,CAAC,YAAa;AAClB,cAAY,gBAAgB;AAC5B,MAAI,QAAQ,WAAW,GAAG;AAAE,gBAAY,cAAc;AAA4C;AAAA,EAAQ;AAC1G,aAAW,UAAU,QAAQ,MAAM,GAAG,CAAC,GAAG;AACxC,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,UAAM,cAAc,GAAG,OAAO,IAAI;AAClC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,OAAO,KAAK,MAAM,GAAG,GAAG,KAAK;AAChD,UAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,aAAS,cAAc,aAAa,OAAO,SAAS,SAAS,IAAI,OAAO,SAAS,KAAK,IAAI,IAAI,MAAM;AACpG,SAAK,OAAO,OAAO,MAAM,QAAQ;AACjC,gBAAY,OAAO,IAAI;AAAA,EACzB;AACF;AAGA,SAAS,gBAAgB,WAAoC;AAC3D,MAAI,CAAC,cAAe;AACpB,gBAAc,gBAAgB;AAC9B,MAAI,UAAU,WAAW,GAAG;AAAE,kBAAc,cAAc;AAAuD;AAAA,EAAQ;AACzH,aAAW,UAAU,UAAU,MAAM,GAAG,CAAC,GAAG;AAC1C,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,SAAK,OAAO;AACZ,SAAK,cAAc,GAAG,OAAO,QAAQ,KAAK,OAAO,QAAQ,mBAAgB,OAAO,KAAK;AACrF,SAAK,iBAAiB,SAAS,MAAM,SAAS,gBAAgB,OAAO,QAAQ,aAAa,OAAO,QAAQ,YAAY,CAAC;AACtH,SAAK,OAAO,IAAI;AAChB,kBAAc,OAAO,IAAI;AAAA,EAC3B;AACF;AAGA,SAAS,YAAY,OAA2B;AAC9C,MAAI,CAAC,UAAW;AAChB,YAAU,gBAAgB;AAC1B,MAAI,MAAM,WAAW,GAAG;AAAE,cAAU,cAAc;AAAmE;AAAA,EAAQ;AAC7H,aAAW,SAAS,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,EAAE,GAAG;AACrD,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,SAAK,cAAc,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,mBAAmB,CAAC,SAAM,MAAM,GAAG,GAAG,MAAM,QAAQ,SAAM,MAAM,KAAK,KAAK,EAAE,GAAG,MAAM,SAAS,cAAW,MAAM,MAAM,KAAK,EAAE;AACrK,cAAU,OAAO,IAAI;AAAA,EACvB;AACF;AAGA,SAAS,iBAAiB,SAAkY;AAC1Z,MAAI,CAAC,eAAgB;AACrB,iBAAe,gBAAgB;AAC/B,QAAM,SAAS,SAAS,cAAc,GAAG;AACzC,MAAI,QAAQ,YAAY,UAAU;AAChC,WAAO,YAAY;AACnB,WAAO,cAAc,8BAA8B,QAAQ,WAAW,UAAU,0BAA0B;AAAA,EAC5G,OAAO;AACL,WAAO,cAAc;AAAA,EACvB;AACA,iBAAe,OAAO,MAAM;AAC5B,QAAM,QAAQ,QAAQ,cAAc,CAAC;AACrC,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,mBAAe,OAAO,OAAO;AAC7B,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,SAAS,MAAM,MAAM,GAAG,CAAC,GAAG;AACrC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,MAAM,MAAM,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM,OAAO,8CAA8C,MAAM,MAAM,MAAM;AAC5I,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,mBAAe,OAAO,IAAI;AAAA,EAC5B;AACA,QAAM,UAAU,QAAQ,cAAc,CAAC;AACvC,QAAM,SAAS,QAAQ,CAAC;AACxB,MAAI,QAAQ;AACV,UAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,UAAM,cAAc,sBAAsB,KAAK,IAAI,GAAG,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,YAAY,OAAO,MAAM,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG,mBAAgB,OAAO,QAAQ;AAC3K,mBAAe,OAAO,KAAK;AAC3B,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,OAAO,OAAO,MAAM,KAAK,MAAM,GAAG,CAAC,GAAG;AAC/C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,UAAI,OAAO,IAAI;AACf,UAAI;AAAE,eAAO,IAAI,IAAI,IAAI,GAAG,EAAE;AAAA,MAAU,QAAQ;AAAE,eAAO,IAAI;AAAA,MAAK;AAClE,WAAK,cAAc,OAAO,IAAI,gBAAa,IAAI,MAAM,SAAM,IAAI,KAAK,IAAI,EAAE,EAAE,mBAAmB,CAAC;AAChG,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,mBAAe,OAAO,IAAI;AAAA,EAC5B;AACA,QAAM,eAAe,QAAQ,WAAW,CAAC;AACzC,MAAI,aAAa,SAAS,GAAG;AAC3B,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,mBAAe,OAAO,OAAO;AAC7B,eAAW,QAAQ,aAAa,MAAM,GAAG,CAAC,GAAG;AAC3C,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,YAAY;AACjB,YAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,YAAM,cAAc,GAAG,KAAK,MAAM,MAAM,eAAe,KAAK,MAAM,WAAW,IAAI,KAAK,GAAG,GAAG,KAAK,aAAa,8BAA2B,0BAAuB;AAChK,WAAK,OAAO,KAAK;AACjB,iBAAW,QAAQ,KAAK,MAAM,MAAM,GAAG,CAAC,GAAG;AACzC,cAAM,OAAO,SAAS,cAAc,GAAG;AACvC,aAAK,cAAc,GAAG,KAAK,YAAY,SAAS,WAAM,QAAG,IAAI,KAAK,GAAG,GAAG,KAAK,QAAQ,SAAS,IAAI,SAAM,KAAK,QAAQ,KAAK,IAAI,CAAC,KAAK,EAAE;AACtI,aAAK,OAAO,IAAI;AAAA,MAClB;AACA,qBAAe,OAAO,IAAI;AAAA,IAC5B;AAAA,EACF;AACA,QAAM,WAAW,QAAQ,YAAY,CAAC;AACtC,QAAM,SAAS,SAAS,cAAc,GAAG;AACzC,QAAM,aAAa,SAAS,cAAc,OAAO;AACjD,aAAW,OAAO;AAClB,aAAW,cAAc;AACzB,aAAW,aAAa,cAAc,8BAA8B;AACpE,QAAM,cAAc,OAAO,iBAAiB,YAAY;AACtD,UAAM,UAAU,MAAM,QAAQ,EAAE,MAAM,aAAa,KAAK,WAAW,MAAM,CAAC;AAC1E,WAAO,QAAQ,OAAO,GAAG,QAAQ,GAAG,gCAAgC,GAAG,QAAQ,GAAG,eAAe,QAAQ,QAAQ,KAAK,IAAI,CAAC,GAAG;AAC9H,UAAM,QAAQ;AAAA,EAChB,CAAC;AACD,SAAO,OAAO,YAAY,KAAK,WAAW;AAC1C,iBAAe,OAAO,MAAM;AAC5B,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG;AAC1C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,QAAQ,OAAO,SAAS,QAAQ,SAAM,QAAQ,GAAG,GAAG,QAAQ,QAAQ,SAAS,IAAI,SAAM,QAAQ,QAAQ,KAAK,IAAI,CAAC,KAAK,EAAE;AAC9I,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,mBAAe,OAAO,IAAI;AAAA,EAC5B;AACA,QAAM,SAAS,QAAQ,WAAW,CAAC,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,KAAK,IAAI;AACrG,QAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,WAAS,YAAY;AACrB,QAAM,YAAY,SAAS,cAAc,GAAG;AAC5C,YAAU,cAAc,SAAS,qEAAqE;AACtG,WAAS,OAAO,SAAS;AACzB,MAAI,QAAQ;AACV,UAAM,cAAc,SAAS,cAAc,OAAO;AAClD,gBAAY,OAAO;AACnB,gBAAY,cAAc,QAAQ,SAAS,UAAU;AACrD,gBAAY,aAAa,cAAc,aAAa;AACpD,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,OAAO;AACjB,cAAU,cAAc;AACxB,cAAU,aAAa,cAAc,eAAe;AACpD,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,OAAO;AACjB,cAAU,cAAc;AACxB,cAAU,aAAa,cAAc,eAAe;AACpD,UAAM,cAAc,OAAO,8BAA8B,YAAY;AACnE,YAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,aAAa,QAAQ,YAAY,OAAO,UAAU,UAAU,OAAO,UAAU,UAAU,MAAM,CAAC;AACnI,aAAO,8CAA8C,OAAO,MAAM,GAAG;AACrE,YAAM,QAAQ;AAAA,IAChB,CAAC;AACD,aAAS,OAAO,aAAa,KAAK,WAAW,KAAK,WAAW,KAAK,WAAW;AAAA,EAC/E;AACA,iBAAe,OAAO,QAAQ;AAC9B,QAAM,QAAQ,QAAQ,SAAS,CAAC;AAChC,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAWA,WAAU,MAAM,MAAM,GAAG,CAAC,GAAG;AACtC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,kBAAkBA,QAAO,MAAM,OAAOA,QAAO,QAAQ,cAAc,IAAI,KAAKA,QAAO,UAAU,EAAE,eAAe,CAAC;AAClI,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,mBAAe,OAAO,IAAI;AAAA,EAC5B;AACA,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,mBAAe,OAAO,OAAO;AAC7B,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,YAAY,UAAU,MAAM,GAAG,CAAC,GAAG;AAC5C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,SAAS,IAAI,KAAK,SAAS,IAAI,cAAW,SAAS,MAAM;AAC/E,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,mBAAe,OAAO,IAAI;AAAA,EAC5B;AACF;AAGA,SAAS,kBAAkB,SAA2c;AACpe,MAAI,CAAC,gBAAiB;AACtB,kBAAgB,gBAAgB;AAChC,QAAM,OAAO,QAAQ,QAAQ,CAAC;AAC9B,QAAM,SAAS,QAAQ,UAAU,CAAC;AAClC,QAAM,QAAQ,QAAQ,YAAY,CAAC;AACnC,QAAM,SAAS,QAAQ,WAAW,CAAC,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,KAAK,IAAI;AACrG,QAAM,QAAQ,QAAQ,gBAAgB,EAAE,MAAM,GAAG,SAAS,QAAW,MAAM,MAAM;AACjF,QAAM,SAAS,SAAS,cAAc,GAAG;AACzC,SAAO,YAAY,MAAM,OAAO,eAAe;AAC/C,SAAO,cAAc,oBAAoB,MAAM,IAAI,OAAO,MAAM,SAAS,IAAI,KAAK,GAAG,qBAAqB,MAAM,YAAY,SAAY,mCAAmC,MAAM,OAAO,KAAK,kCAAkC,GAAG,MAAM,OAAO,qCAAgC,EAAE;AACjR,kBAAgB,OAAO,MAAM;AAC7B,QAAM,eAAe,SAAS,cAAc,OAAO;AACnD,eAAa,OAAO;AACpB,eAAa,MAAM;AACnB,eAAa,cAAc,MAAM,YAAY,SAAY,OAAO,MAAM,OAAO,IAAI;AACjF,eAAa,aAAa,cAAc,6BAA6B;AACrE,QAAM,gBAAgB,OAAO,yBAAyB,YAAY;AAChE,UAAM,QAAQ,EAAE,MAAM,qBAAqB,SAAS,aAAa,UAAU,KAAK,SAAY,OAAO,aAAa,KAAK,EAAE,CAAC;AACxH,WAAO,6BAA6B,aAAa,UAAU,KAAK,eAAe,aAAa,KAAK,kCAAkC;AACnI,UAAM,QAAQ;AAAA,EAChB,CAAC;AACD,kBAAgB,OAAO,cAAc,KAAK,aAAa;AACvD,QAAM,kBAAkB,SAAS,cAAc,GAAG;AAClD,kBAAgB,cAAc;AAC9B,kBAAgB,OAAO,eAAe;AACtC,QAAM,cAAc,SAAS,cAAc,OAAO;AAClD,cAAY,OAAO;AACnB,cAAY,cAAc;AAC1B,cAAY,aAAa,cAAc,uBAAuB;AAC9D,QAAM,aAAa,SAAS,cAAc,IAAI;AAC9C,QAAM,mBAAmB,MAAY;AACnC,eAAW,gBAAgB;AAC3B,UAAM,UAAU,aAAa,MAAM,CAAC,GAAG,YAAY,KAAK,EAAE,MAAM,GAAG,EAAE;AACrE,eAAW,OAAO,SAAS;AACzB,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,YAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,WAAK,OAAO;AACZ,YAAM,QAAQ,OAAO,KAAK,WAAS,MAAM,UAAU,IAAI,KAAK;AAC5D,YAAM,OAAO,MAAM,KAAK,WAAS,MAAM,UAAU,IAAI,KAAK;AAC1D,WAAK,cAAc,GAAG,IAAI,SAAS,IAAI,GAAG,GAAG,IAAI,SAAS,eAAQ,EAAE,GAAG,IAAI,WAAW,IAAI,QAAQ,IAAI,IAAI,QAAQ,cAAO,WAAI,KAAK,EAAE,GAAG,QAAQ,KAAK,MAAM,KAAK,MAAM,EAAE,GAAG,QAAQ,KAAK,OAAO,SAAS,IAAI,KAAK,KAAK,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE;AAC9O,WAAK,iBAAiB,SAAS,MAAM,QAAQ,EAAE,MAAM,aAAa,OAAO,IAAI,MAAM,CAAC,EAAE,KAAK,MAAM,OAAO,iBAAiB,IAAI,KAAK,GAAG,CAAC,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AAC5N,WAAK,OAAO,IAAI;AAChB,iBAAW,OAAO,IAAI;AAAA,IACxB;AACA,QAAI,QAAQ,WAAW,GAAG;AAAE,YAAM,QAAQ,SAAS,cAAc,IAAI;AAAG,YAAM,cAAc;AAAkC,iBAAW,OAAO,KAAK;AAAA,IAAG;AAAA,EAC1J;AACA,cAAY,iBAAiB,SAAS,gBAAgB;AACtD,kBAAgB,OAAO,aAAa,UAAU;AAC9C,mBAAiB;AACjB,QAAM,cAAc,SAAS,cAAc,OAAO;AAClD,cAAY,OAAO;AACnB,cAAY,cAAc;AAC1B,cAAY,aAAa,cAAc,iBAAiB;AACxD,QAAM,gBAAgB,SAAS,cAAc,IAAI;AACjD,QAAM,eAAe,OAAO,kBAAkB,YAAY;AACxD,UAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,aAAa,MAAM,YAAY,MAAM,CAAC;AAC3E,kBAAc,gBAAgB;AAC9B,eAAW,OAAO,OAAO,QAAQ,MAAM,GAAG,EAAE,GAAG;AAC7C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,YAAM,OAAO,SAAS,cAAc,QAAQ;AAC5C,WAAK,OAAO;AACZ,WAAK,cAAc,GAAG,IAAI,SAAS,IAAI,GAAG,SAAM,IAAI,GAAG;AACvD,WAAK,iBAAiB,SAAS,MAAM,QAAQ,EAAE,MAAM,aAAa,OAAO,IAAI,MAAM,CAAC,EAAE,KAAK,MAAM,OAAO,iBAAiB,IAAI,KAAK,GAAG,CAAC,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AAC5N,WAAK,OAAO,IAAI;AAChB,oBAAc,OAAO,IAAI;AAAA,IAC3B;AACA,WAAO,sBAAsB,OAAO,QAAQ,MAAM,YAAY,OAAO,QAAQ,WAAW,IAAI,KAAK,GAAG,GAAG;AAAA,EACzG,CAAC;AACD,kBAAgB,OAAO,aAAa,KAAK,cAAc,aAAa;AACpE,QAAM,SAAS,QAAQ,UAAU,CAAC;AAClC,aAAW,SAAS,OAAO,MAAM,GAAG,CAAC,GAAG;AACtC,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,YAAY;AACpB,YAAQ,cAAc,0BAA0B,MAAM,OAAO,MAAM,4BAA4B,MAAM,GAAG,UAAU,MAAM,OAAO,KAAK,IAAI,CAAC;AACzI,oBAAgB,OAAO,OAAO;AAAA,EAChC;AACA,QAAM,SAAS,QAAQ,aAAa,CAAC;AACrC,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,gBAAgB,SAAS,cAAc,GAAG;AAChD,kBAAc,cAAc;AAC5B,oBAAgB,OAAO,aAAa;AACpC,UAAM,YAAY,SAAS,cAAc,IAAI;AAC7C,eAAW,SAAS,OAAO,MAAM,GAAG,CAAC,GAAG;AACtC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,MAAM,IAAI,SAAM,MAAM,KAAK,SAAM,MAAM,YAAY,cAAc,UAAU,SAAM,MAAM,OAAO,MAAM,cAAc,MAAM,OAAO,WAAW,IAAI,KAAK,GAAG;AAC5K,gBAAU,OAAO,IAAI;AAAA,IACvB;AACA,oBAAgB,OAAO,SAAS;AAAA,EAClC;AACA,QAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,iBAAiB,SAAS,cAAc,GAAG;AACjD,mBAAe,cAAc;AAC7B,oBAAgB,OAAO,cAAc;AACrC,UAAM,aAAa,SAAS,cAAc,IAAI;AAC9C,eAAW,QAAQ,QAAQ,MAAM,GAAG,CAAC,GAAG;AACtC,YAAM,QAAQ,SAAS,cAAc,IAAI;AACzC,YAAM,cAAc,UAAU,KAAK,QAAQ,SAAM,KAAK,KAAK,gBAAa,KAAK,IAAI,OAAI,KAAK,GAAG,IAAI,KAAK,KAAK,OAAI,KAAK,MAAM,GAAG,KAAK,YAAY,0CAAuC,EAAE,GAAG,KAAK,UAAU,kBAAe,EAAE;AAC1N,YAAM,cAAc,OAAO,gBAAgB,YAAY;AACrD,cAAM,aAAc,QAAQ,UAAU,YAAY,CAAC;AACnD,cAAM,cAAc,QAAQ,QAAQ,CAAC,GAAG,OAAO,SAAO,IAAI,aAAa,KAAK,YAAY,WAAW,SAAS,IAAI,KAAK,CAAC;AACtH,cAAM,WAAW,WAAW,SAAS,IAAI,OAAO,QAAQ,qBAAqB,WAAW,MAAM,oDAAoD,IAAI;AACtJ,cAAM,QAAQ,EAAE,MAAM,eAAe,UAAU,KAAK,UAAU,SAAS,CAAC;AACxE,eAAO,iBAAiB,KAAK,QAAQ,GAAG;AACxC,cAAM,QAAQ;AAAA,MAChB,CAAC;AACD,YAAM,OAAO,KAAK,WAAW;AAC7B,iBAAW,OAAO,KAAK;AAAA,IACzB;AACA,oBAAgB,OAAO,UAAU;AAAA,EACnC;AACA,QAAM,iBAAiB,SAAS,cAAc,GAAG;AACjD,QAAM,aAAa,SAAS,cAAc,OAAO;AACjD,aAAW,OAAO;AAClB,aAAW,cAAc;AACzB,aAAW,aAAa,cAAc,aAAa;AACnD,QAAM,aAAa,OAAO,eAAe,YAAY;AACnD,QAAI,CAAC,QAAQ;AAAE,aAAO,+CAA+C,IAAI;AAAG;AAAA,IAAQ;AACpF,UAAM,QAAQ,EAAE,MAAM,cAAc,MAAM,WAAW,MAAM,CAAC;AAC5D,WAAO,wBAAwB,WAAW,KAAK,GAAG;AAClD,UAAM,QAAQ;AAAA,EAChB,CAAC;AACD,QAAM,gBAAgB,OAAO,kBAAkB,YAAY;AACzD,QAAI,CAAC,QAAQ;AAAE,aAAO,kDAAkD,IAAI;AAAG;AAAA,IAAQ;AACvF,UAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,iBAAiB,MAAM,WAAW,MAAM,CAAC;AAC9E,WAAO,2BAA2B,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,OAAO,aAAa,IAAI,KAAK,GAAG,YAAY;AACzH,UAAM,QAAQ;AAAA,EAChB,CAAC;AACD,iBAAe,OAAO,YAAY,KAAK,YAAY,KAAK,aAAa;AACrE,kBAAgB,OAAO,cAAc;AACrC,QAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,aAAa,SAAS,cAAc,IAAI;AAC9C,eAAW,UAAU,QAAQ,MAAM,GAAG,CAAC,GAAG;AACxC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,IAAI,SAAM,OAAO,KAAK,MAAM,OAAO,OAAO,KAAK,WAAW,IAAI,KAAK,GAAG,SAAM,OAAO,OAAO,MAAM,SAAS,OAAO,OAAO,WAAW,IAAI,KAAK,GAAG,SAAM,OAAO,QAAQ,MAAM,gBAAgB,OAAO,QAAQ,WAAW,IAAI,KAAK,GAAG,eAAY,IAAI,KAAK,OAAO,OAAO,EAAE,eAAe,CAAC;AACjT,iBAAW,OAAO,IAAI;AAAA,IACxB;AACA,oBAAgB,OAAO,UAAU;AAAA,EACnC;AACA,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,UAAM,YAAY,SAAS,cAAc,GAAG;AAC5C,cAAU,cAAc,0BAA0B,UAAU,MAAM,YAAY,UAAU,WAAW,IAAI,KAAK,GAAG;AAC/G,aAAS,OAAO,SAAS;AACzB,eAAW,YAAY,UAAU,MAAM,GAAG,CAAC,GAAG;AAC5C,YAAM,MAAM,SAAS,cAAc,GAAG;AACtC,UAAI,cAAc,GAAG,SAAS,OAAO,KAAK,MAAM,uBAAoB,IAAI,KAAK,SAAS,UAAU,EAAE,eAAe,CAAC;AAClH,YAAM,UAAU,OAAO,oBAAoB,YAAY;AACrD,cAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,mBAAmB,IAAI,SAAS,GAAG,CAAC;AACzE,eAAO,kCAAkC,OAAO,QAAQ,OAAO,OAAO,aAAa,IAAI,KAAK,GAAG,YAAY;AAC3G,cAAM,QAAQ;AAAA,MAChB,CAAC;AACD,UAAI,OAAO,KAAK,OAAO;AACvB,eAAS,OAAO,GAAG;AAAA,IACrB;AACA,oBAAgB,OAAO,QAAQ;AAAA,EACjC;AACA,QAAM,cAAc,SAAS,cAAc,KAAK;AAChD,cAAY,YAAY;AACxB,QAAM,eAAe,QAAQ;AAC7B,QAAM,YAAY,QAAQ,UAAU,eAAe,UAAU;AAC7D,QAAM,QAAQ,QAAQ,MAAM,MAAM,UAAU;AAC5C,cAAY,cAAc,4BAA4B,cAAc,UAAU,eAAe,aAAa,KAAK,8BAA8B,SAAS,OAAO,KAAK,6BAA6B,UAAU,GAAG,QAAQ,OAAO,SAAM,QAAQ,KAAK,KAAK,KAAK,eAAY;AACpQ,QAAM,gBAAgB,OAAO,cAAc,UAAU,6BAA6B,2BAA2B,YAAY;AACvH,UAAM,QAAQ,EAAE,MAAM,cAAc,SAAS,CAAC,cAAc,QAAQ,CAAC;AACrE,WAAO,cAAc,UAAU,uCAAuC,4DAA4D;AAClI,UAAM,QAAQ;AAAA,EAChB,CAAC;AACD,cAAY,OAAO,KAAK,aAAa;AACrC,kBAAgB,OAAO,WAAW;AACpC;AAGA,SAAS,YAAY,SAAuW;AAC1X,MAAI,CAAC,UAAW;AAChB,YAAU,gBAAgB;AAC1B,QAAM,WAAW,QAAQ,YAAY,CAAC;AACtC,QAAM,SAAS,QAAQ,WAAW,CAAC,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,KAAK,IAAI;AACrG,QAAM,eAAe,QAAQ,YAAY,CAAC,GAAG,KAAK,aAAW,CAAC,QAAQ,QAAQ;AAC9E,MAAI,aAAa;AACf,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,SAAK,cAAc,2BAA2B,YAAY,MAAM;AAChE,SAAK,OAAO,KAAK,OAAO,oBAAoB,YAAY;AAAE,YAAM,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAAG,aAAO,+CAA+C;AAAG,YAAM,QAAQ;AAAA,IAAG,CAAC,CAAC;AACjL,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,aAAa,QAAQ,cAAc,CAAC;AAC1C,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,SAAS,SAAS,cAAc,GAAG;AACzC,WAAO,cAAc,oBAAoB,WAAW,MAAM,GAAG,CAAC,EAAE,IAAI,YAAU,GAAG,OAAO,IAAI,OAAO,OAAO,MAAM,GAAG,OAAO,QAAQ,SAAS,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,QAAK,CAAC;AACpM,cAAU,OAAO,MAAM;AAAA,EACzB;AACA,QAAM,aAAa,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,SAAS,WAAW,UAAa,QAAQ,SAAS,UAAU,MAAS;AACxI,QAAM,mBAAmB,IAAI,IAAI,SAAS,QAAQ,aAAW,MAAM,QAAQ,QAAQ,SAAS,OAAO,IAAI,QAAQ,SAAS,UAAyC,CAAC,CAAC,EAAE,IAAI,UAAQ,KAAK,QAAQ,CAAC;AAC/L,MAAI,YAAY;AACd,UAAM,SAAS,WAAW,SAAS;AACnC,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc,WAAW,OAAO,OAAO,OAAO,OAAO,IAAI,KAAK,EAAE,KAAK,OAAO,OAAO,MAAM,kBAAkB,OAAO,OAAO,WAAW,IAAI,KAAK,GAAG,oBAAoB,iBAAiB,OAAO,IAAI,KAAK,iBAAiB,IAAI,kBAAkB,iBAAiB,SAAS,IAAI,KAAK,GAAG,4BAA4B,EAAE;AACxT,cAAU,OAAO,OAAO;AACxB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,SAAS,OAAO,OAAO,MAAM,GAAG,EAAE,GAAG;AAC9C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,YAAM,UAAU,iBAAiB,IAAI,MAAM,QAAQ;AACnD,WAAK,cAAc,GAAG,MAAM,SAAS,MAAM,QAAQ,SAAM,MAAM,IAAI,GAAG,MAAM,UAAU,KAAK,iBAAc,GAAG,UAAU,4BAAyB,EAAE;AACjJ,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,gBAAgB,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,MAAM,QAAQ,QAAQ,SAAS,MAAM,KAAK,QAAQ,SAAS,WAAW,MAAS;AAC7I,MAAI,eAAe;AACjB,UAAM,SAAS,cAAc,SAAS;AACtC,UAAM,SAAS,OAAO,cAAc,SAAS,WAAW,WAAW,cAAc,QAAQ,SAAS;AAClG,UAAM,OAAO,OAAO,cAAc,SAAS,SAAS,WAAW,cAAc,QAAQ,OAAO;AAC5F,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc,4BAA4B,MAAM,UAAU,IAAI;AACtE,cAAU,OAAO,OAAO;AACxB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,SAAS,OAAO,MAAM,GAAG,EAAE,GAAG;AACvC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,MAAM,KAAK,SAAM,MAAM,IAAI,SAAM,MAAM,KAAK;AAClE,WAAK,OAAO,KAAK,OAAO,cAAc,YAAY;AAChD,cAAM,cAAc,MAAM,QAAQ,EAAE,MAAM,mBAAmB,OAAO,MAAM,MAAM,QAAQ,MAAM,OAAO,EAAE,CAAC;AACxG,eAAO,eAAe,MAAM,KAAK,KAAK,YAAY,KAAK,GAAG;AAAA,MAC5D,CAAC,CAAC;AACF,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,cAAc,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,MAAM,QAAQ,QAAQ,SAAS,QAAQ,CAAC;AACpG,MAAI,aAAa;AACf,UAAM,WAAW,YAAY,SAAS;AACtC,UAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,aAAS,cAAc,gCAAgC,SAAS,IAAI,aAAW,GAAG,QAAQ,KAAK,IAAI,SAAS,QAAQ,MAAM,CAAC,EAAE,EAAE,KAAK,QAAK,CAAC;AAC1I,cAAU,OAAO,QAAQ;AAAA,EAC3B;AACA,QAAM,WAAW,QAAQ,YAAY,CAAC;AACtC,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,cAAU,OAAO,OAAO;AACxB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG;AAC1C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,QAAQ,IAAI,SAAM,QAAQ,OAAO,MAAM,SAAS,QAAQ,OAAO,WAAW,IAAI,KAAK,GAAG,gBAAa,QAAQ,OAAO,KAAK,IAAI,CAAC,eAAY,IAAI,KAAK,QAAQ,OAAO,EAAE,eAAe,CAAC;AACxM,WAAK,OAAO,KAAK,OAAO,SAAS,YAAY;AAC3C,cAAM,UAAU,MAAM,QAAQ,EAAE,MAAM,gBAAgB,MAAM,QAAQ,KAAK,CAAC;AAC1E,iBAAS,iBAAiB,QAAQ,IAAI,SAAS,QAAQ,QAAQ,OAAO,MAAM,yBAAyB;AAAA,MACvG,CAAC,GAAG,KAAK,OAAO,UAAU,YAAY;AACpC,cAAM,QAAQ,EAAE,MAAM,iBAAiB,MAAM,QAAQ,KAAK,CAAC;AAC3D,eAAO,gBAAgB,QAAQ,IAAI,WAAW;AAC9C,cAAM,QAAQ;AAAA,MAChB,CAAC,CAAC;AACF,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,WAAW,QAAQ,WAAW,CAAC,GAAG,OAAO,YAAU,OAAO,aAAa,MAAS;AACtF,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,UAAM,cAAc,sBAAsB,OAAO,QAAQ,mBAAmB,qBAAkB,OAAO,UAAU;AAC/G,SAAK,OAAO,KAAK;AACjB,UAAM,aAAa,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,MAAM,QAAQ,QAAQ,SAAS,MAAM,KAAK,QAAQ,SAAS,WAAW,MAAS;AAC1I,UAAM,SAAS,YAAY,SAAS;AACpC,QAAI,QAAQ;AACV,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,iBAAW,SAAS,OAAO,MAAM,GAAG,EAAE,GAAG;AACvC,cAAM,OAAO,SAAS,cAAc,IAAI;AACxC,aAAK,cAAc,GAAG,MAAM,KAAK,KAAK,MAAM,KAAK;AACjD,aAAK,OAAO,IAAI;AAAA,MAClB;AACA,WAAK,OAAO,IAAI;AAAA,IAClB,OAAO;AACL,YAAM,OAAO,SAAS,cAAc,GAAG;AACvC,WAAK,cAAc;AACnB,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,SAAK,OAAO,OAAO,sBAAsB,YAAY;AAAE,YAAM,QAAQ,EAAE,MAAM,iBAAiB,IAAI,OAAO,IAAI,UAAU,KAAK,CAAC;AAAG,aAAO,4DAA4D;AAAG,YAAM,QAAQ;AAAA,IAAG,CAAC,GAAG,KAAK,OAAO,WAAW,YAAY;AAAE,YAAM,QAAQ,EAAE,MAAM,iBAAiB,IAAI,OAAO,IAAI,UAAU,MAAM,CAAC;AAAG,aAAO,sBAAsB;AAAG,YAAM,QAAQ;AAAA,IAAG,CAAC,CAAC;AAC7X,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,UAAU,QAAQ,SAAS,WAAW,CAAC;AAC7C,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,SAAS,QAAQ,CAAC;AACxB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,UAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,OAAO,MAAM,GAAG,CAAC,GAAG,UAAU,GAAG,QAAQ,OAAO,QAAS,OAAO,UAAU,KAAK,IAAI,WAAM,SAAO,QAAG,EAAE,EAAE,KAAK,GAAG;AACvJ,YAAQ,cAAc,yBAAyB,KAAK,IAAI,OAAO,QAAQ,GAAG,OAAO,KAAK,CAAC,OAAO,OAAO,KAAK,IAAI,UAAU;AACxH,cAAU,OAAO,OAAO;AAAA,EAC1B;AACA,QAAM,QAAQ,QAAQ,SAAS,SAAS,CAAC;AACzC,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,aAAS,cAAc,oBAAoB,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,UAAQ,IAAI,KAAK,IAAI,UAAU,KAAK,KAAK,GAAG,EAAE,KAAK,QAAK,CAAC;AAC1H,cAAU,OAAO,QAAQ;AAAA,EAC3B;AACA,QAAM,UAAU,QAAQ,gBAAgB,CAAC;AACzC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc;AACtB,cAAU,OAAO,OAAO;AACxB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,UAAU,QAAQ,MAAM,GAAG,CAAC,GAAG;AACxC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,QAAQ,mBAAmB,KAAK,OAAO,OAAO,IAAI,CAAC,UAAsB,GAAG,MAAM,KAAK,WAAM,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI,KAAK,YAAY;AACrK,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,WAAS,YAAY;AACrB,QAAM,YAAY,SAAS,cAAc,GAAG;AAC5C,YAAU,cAAc,SAAS,gFAAgF;AACjH,WAAS,OAAO,SAAS;AACzB,MAAI,QAAQ;AACV,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,OAAO;AACjB,cAAU,YAAY;AACtB,cAAU,cAAc,QAAQ,YAAY,8BAA8B;AAC1E,cAAU,aAAa,cAAc,eAAe;AACpD,UAAM,cAAc,OAAO,uBAAuB,YAAY;AAC5D,YAAM,QAAQ,EAAE,MAAM,aAAa,MAAM,UAAU,MAAM,CAAC;AAC1D,aAAO,+DAA+D;AACtE,YAAM,QAAQ;AAAA,IAChB,CAAC;AACD,aAAS,OAAO,WAAW,KAAK,WAAW;AAAA,EAC7C;AACA,YAAU,OAAO,QAAQ;AAC3B;AAGA,SAAS,eAAe,SAA0e;AAChgB,MAAI,CAAC,aAAc;AACnB,eAAa,gBAAgB;AAC7B,QAAM,WAAW,QAAQ,YAAY,CAAC;AACtC,QAAM,SAAS,QAAQ,WAAW,CAAC,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,KAAK,IAAI;AACrG,QAAM,kBAAkB,QAAQ,mBAAmB,CAAC;AACpD,aAAW,WAAW,gBAAgB,MAAM,GAAG,CAAC,GAAG;AACjD,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,UAAMC,eAAc,QAAQ,SAAS;AACrC,SAAK,cAAc,cAAc,QAAQ,IAAI,KAAK,QAAQ,MAAM,MAAM,QAAQ,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG,iBAAc,QAAQ,IAAI,OAAO,QAAQ,SAAS,IAAI,KAAK,GAAG,0BAAuB,QAAQ,MAAM,OAAO,QAAQ,OAAO,GAAG,QAAQ,OAAO,mBAAgB,mBAAgB;AAC9R,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,QAAM,cAAc,gBAAgB,KAAK,aAAW,QAAQ,SAAS,IAAI;AACzE,MAAI,eAAe,QAAQ;AACzB,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,YAAY;AACnB,WAAO,cAAc,cAAc,YAAY,IAAI,8BAA8B,YAAY,MAAM;AACnG,iBAAa,OAAO,MAAM;AAAA,EAC5B;AACA,QAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,SAAS,QAAQ,CAAC;AACxB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,iBAAiB,OAAO,IAAI,UAAU,OAAO,KAAK,OAAO,OAAO,MAAM,SAAM,OAAO,OAAO,OAAO,OAAO,YAAY,IAAI,KAAK,GAAG,WAAW,OAAO,OAAO,mBAAgB,iBAAc;AAC1M,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,QAAM,SAAS,QAAQ,aAAa,CAAC,GAAG,CAAC;AACzC,MAAI,SAAS,MAAM,WAAW,SAAS,GAAG;AACxC,UAAM,aAAa,SAAS,cAAc,GAAG;AAC7C,eAAW,cAAc,oBAAoB,MAAM,WAAW,IAAI,UAAQ,GAAG,KAAK,QAAQ,KAAK,GAAG,CAAC,WAAM,KAAK,MAAM,KAAK,KAAK,UAAU,GAAG,EAAE,KAAK,QAAK,CAAC;AACxJ,iBAAa,OAAO,UAAU;AAAA,EAChC;AACA,MAAI,SAAS,MAAM,WAAW,SAAS,GAAG;AACxC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,gBAAgB,MAAM,WAAW,KAAK,IAAI,CAAC;AAC9D,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,QAAM,gBAAgB,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAW,QAAQ,SAAS,WAAW,MAAS;AACnG,MAAI,eAAe;AACjB,UAAM,SAAS,cAAc,SAAS;AACtC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,wBAAwB,OAAO,OAAO,iBAAiB,OAAO,YAAY,IAAI,KAAK,GAAG,UAAU,OAAO,IAAI,OAAO,OAAO,KAAK,KAAK,IAAI,CAAC;AAC3J,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,aAAW,iBAAiB,QAAQ,YAAY,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG;AAC/D,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,WAAW,aAAa,IAAI,KAAK,aAAa,KAAK,MAAM,OAAO,aAAa,KAAK,WAAW,IAAI,KAAK,GAAG,SAAM,aAAa,QAAQ,MAAM,UAAU,aAAa,QAAQ,WAAW,IAAI,KAAK,GAAG,IAAI,QAAQ,WAAW,CAAC,GAAG,KAAK,UAAQ,KAAK,OAAO,aAAa,EAAE,IAAI,uBAAoB,EAAE;AAChT,SAAK,OAAO,IAAI;AAChB,UAAM,OAAO,SAAS,cAAc,OAAO;AAC3C,UAAM,YAAY,SAAS,cAAc,IAAI;AAC7C,eAAW,UAAU,aAAa,QAAQ,MAAM,GAAG,CAAC,GAAG;AACrD,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,SAAS,OAAO,GAAG,IAAI,OAAO,SAAS,WAAW,MAAM,EAAE;AACvF,WAAK,iBAAiB,SAAS,MAAM;AACnC,cAAMC,QAAO,KAAK,cAAc,OAAO;AACvC,YAAI,CAACA,MAAM;AACX,cAAM,SAAS,SAAS,aAAa,KAAK,MAAM,GAAG,CAAC,GAAG,OAAO,KAAK,KAAK,QAAQ,WAAW,QAAQ,SAAS,KAAK;AACjH,aAAK,QAAQ,SAAS,KAAK,QAAQ,WAAW,QAAQ,SAAS;AAC/D,QAAAA,MAAK,gBAAgB,GAAG,OAAO,IAAI,SAAO;AACxC,gBAAM,OAAO,SAAS,cAAc,IAAI;AACxC,qBAAW,cAAc,aAAa,QAAQ,MAAM,GAAG,CAAC,GAAG;AACzD,kBAAM,QAAQ,SAAS,cAAc,IAAI;AACzC,kBAAM,cAAc,IAAI,WAAW,GAAG,KAAK;AAC3C,iBAAK,OAAO,KAAK;AAAA,UACnB;AACA,iBAAO;AAAA,QACT,CAAC,CAAC;AAAA,MACJ,CAAC;AACD,gBAAU,OAAO,IAAI;AAAA,IACvB;AACA,SAAK,OAAO,SAAS;AACrB,UAAM,OAAO,SAAS,cAAc,OAAO;AAC3C,eAAW,OAAO,aAAa,KAAK,MAAM,GAAG,CAAC,GAAG;AAC/C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,iBAAW,UAAU,aAAa,QAAQ,MAAM,GAAG,CAAC,GAAG;AACrD,cAAM,OAAO,SAAS,cAAc,IAAI;AACxC,aAAK,cAAc,IAAI,OAAO,GAAG,KAAK;AACtC,aAAK,OAAO,IAAI;AAAA,MAClB;AACA,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,SAAK,OAAO,IAAI;AAChB,SAAK,OAAO,IAAI;AAChB,QAAI,QAAQ;AACV,YAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,iBAAW,UAAU,CAAC,OAAO,QAAQ,OAAO,GAAY;AACtD,gBAAQ,OAAO,KAAK,OAAO,UAAU,MAAM,IAAI,YAAY;AACzD,gBAAM,WAAW,MAAM,QAAQ,EAAE,MAAM,iBAAiB,WAAW,aAAa,IAAI,OAAO,CAAC;AAC5F,iBAAO,YAAY,aAAa,IAAI,OAAO,SAAS,IAAI,kBAAkB,SAAS,QAAQ,GAAG;AAC9F,gBAAM,QAAQ;AAAA,QAChB,CAAC,CAAC;AAAA,MACJ;AACA,WAAK,OAAO,OAAO;AAAA,IACrB;AACA,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,QAAM,cAAc,QAAQ,eAAe,CAAC;AAC5C,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,UAAU,YAAY,MAAM,GAAG,CAAC,GAAG;AAC5C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,IAAI,UAAU,OAAO,QAAQ,SAAI,OAAO,MAAM,kBAAe,OAAO,QAAQ,gBAAa,OAAO,GAAG;AAChI,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,iBAAa,OAAO,IAAI;AAAA,EAC1B;AACA,QAAM,iBAAiB,QAAQ,kBAAkB,CAAC;AAClD,MAAI,eAAe,SAAS,GAAG;AAC7B,UAAM,SAAS,SAAS,cAAc,GAAG;AACzC,WAAO,cAAc,oBAAoB,eAAe,IAAI,YAAU,GAAG,OAAO,MAAM,IAAI,OAAO,UAAU,YAAY,aAAa,EAAE,EAAE,KAAK,QAAK,CAAC;AACnJ,iBAAa,OAAO,MAAM;AAAA,EAC5B;AACA,MAAI,QAAQ;AACV,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,UAAM,WAAW,SAAS,cAAc,UAAU;AAClD,aAAS,OAAO;AAChB,aAAS,cAAc;AACvB,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,cAAc;AACxB,UAAM,eAAe,SAAS,cAAc,OAAO;AACnD,iBAAa,cAAc;AAC3B,aAAS,OAAO,UAAU,WAAW,cAAc,KAAK,OAAO,cAAc,YAAY;AACvF,UAAI,UAAkC,CAAC;AACvC,UAAI,aAAa,MAAM,KAAK,GAAG;AAC7B,YAAI;AAAE,oBAAU,KAAK,MAAM,aAAa,KAAK;AAAA,QAA6B,QAAQ;AAAE,iBAAO,6CAA6C,IAAI;AAAG;AAAA,QAAQ;AAAA,MACzJ;AACA,YAAM,WAAW,MAAM,QAAQ,EAAE,MAAM,aAAa,KAAK,SAAS,OAAO,MAAM,UAAU,OAAO,QAAQ,CAAC;AACzG,aAAO,YAAY,SAAS,IAAI,oBAAoB,SAAS,IAAI,kBAAkB;AACnF,YAAM,QAAQ;AAAA,IAChB,CAAC,CAAC;AACF,iBAAa,OAAO,QAAQ;AAAA,EAC9B;AACF;AAGA,SAAS,YAAY,SAA2kB;AAC9lB,MAAI,CAAC,UAAW;AAChB,YAAU,gBAAgB;AAC1B,QAAM,SAAS,QAAQ,WAAW,CAAC,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,KAAK,IAAI;AACrG,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,UAAM,SAAS,CAAC,UAAU,WAAW,UAAU,YAAY,QAAQ;AACnE,SAAK,cAAc,yBAAyB,UAAU,MAAM,QAAQ,UAAU,WAAW,IAAI,KAAK,GAAG,KAAK,OAAO,IAAI,WAAS,GAAG,UAAU,OAAO,UAAQ,KAAK,UAAU,KAAK,EAAE,MAAM,IAAI,KAAK,EAAE,EAAE,OAAO,UAAQ,CAAC,KAAK,WAAW,IAAI,CAAC,EAAE,KAAK,QAAK,KAAK,MAAM;AAC/P,SAAK,OAAO,IAAI;AAChB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,UAAU,UAAU,MAAM,GAAG,CAAC,GAAG;AAC1C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,QAAQ,SAAM,OAAO,KAAK,GAAG,OAAO,UAAU,SAAY,SAAM,OAAO,KAAK,WAAW,EAAE,GAAG,OAAO,aAAa,SAAY,kBAAe,OAAO,QAAQ,KAAK,EAAE,GAAG,OAAO,SAAS,SAAY,SAAM,OAAO,IAAI,KAAK,EAAE;AACrP,UAAI,QAAQ;AACV,aAAK,OAAO,KAAK,OAAO,SAAS,MAAM,QAAQ,EAAE,MAAM,kBAAkB,IAAI,OAAO,IAAI,QAAQ,QAAQ,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAAE,KAAK,MAAM,OAAO,0BAA0B,OAAO,QAAQ,GAAG,CAAC,GAAG,OAAO,UAAU,SAAS,CAAC;AAC9N,aAAK,OAAO,KAAK,OAAO,UAAU,MAAM,QAAQ,EAAE,MAAM,kBAAkB,IAAI,OAAO,IAAI,QAAQ,SAAS,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAAE,KAAK,MAAM,OAAO,2BAA2B,OAAO,QAAQ,GAAG,CAAC,GAAG,OAAO,UAAU,QAAQ,CAAC;AAChO,aAAK,OAAO,KAAK,OAAO,UAAU,MAAM,QAAQ,EAAE,MAAM,kBAAkB,IAAI,OAAO,IAAI,QAAQ,SAAS,CAAC,EAAE,KAAK,WAAS;AAAE,gBAAM,SAAS;AAA8B,iBAAO,OAAO,OAAO;AAAG,iBAAO,QAAQ;AAAA,QAAG,CAAC,CAAC,CAAC;AAAA,MACzN;AACA,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,SAAK,OAAO,IAAI;AAChB,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,UAAU,QAAQ,eAAe,CAAC;AACxC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,SAAS,QAAQ,CAAC;AACxB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,8BAA8B,OAAO,QAAQ,KAAK,IAAI,CAAC,iBAAc,OAAO,QAAQ,KAAK,IAAI,KAAK,MAAM,SAAM,OAAO,OAAO,mCAAmC,QAAQ,SAAS,SAAS,0BAAuB,QAAQ,QAAQ,MAAM,mBAAmB,EAAE;AAC9Q,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,YAAY,QAAQ,gBAAgB,CAAC,GAAG,OAAO,YAAU,OAAO,aAAa,MAAS;AAC5F,aAAW,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG;AAC1C,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,SAAK,cAAc,0BAA0B,QAAQ,EAAE,kCAAkC,QAAQ,MAAM,OAAO,QAAQ,MAAM,wCAAmC,QAAQ,MAAM;AAC7K,QAAI,QAAQ;AACV,WAAK,OAAO,KAAK,OAAO,gBAAgB,YAAY;AAAE,cAAM,QAAQ,EAAE,MAAM,sBAAsB,IAAI,QAAQ,IAAI,UAAU,KAAK,CAAC;AAAG,eAAO,0BAA0B,QAAQ,EAAE,6CAA6C;AAAG,cAAM,QAAQ;AAAA,MAAG,CAAC,CAAC;AACnP,WAAK,OAAO,KAAK,OAAO,WAAW,YAAY;AAAE,cAAM,QAAQ,EAAE,MAAM,sBAAsB,IAAI,QAAQ,IAAI,UAAU,MAAM,CAAC;AAAG,eAAO,0BAA0B,QAAQ,EAAE,YAAY;AAAG,cAAM,QAAQ;AAAA,MAAG,CAAC,CAAC;AAAA,IAChN;AACA,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,UAAU,QAAQ,WAAW,CAAC;AACpC,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,UAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,YAAU,OAAO,MAAM,CAAC,CAAC;AAC/D,SAAK,cAAc,gBAAgB,QAAQ,MAAM,UAAU,QAAQ,WAAW,IAAI,KAAK,GAAG,oBAAoB,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG,KAAK,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,MAAM,SAAS,IAAI,WAAM,EAAE;AAC9N,SAAK,OAAO,IAAI;AAChB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,UAAU,QAAQ,MAAM,GAAG,CAAC,GAAG;AACxC,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,OAAO,MAAM,IAAI,OAAO,GAAG,SAAM,OAAO,MAAM,SAAM,OAAO,MAAM,mBAAgB,OAAO,aAAa,GAAG,cAAW,OAAO,MAAM;AACtJ,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,SAAK,OAAO,IAAI;AAChB,QAAI,OAAQ,MAAK,OAAO,OAAO,0CAA0C,YAAY;AAAE,YAAM,WAAW,MAAM,QAAQ,EAAE,MAAM,eAAe,CAAC;AAAgD,aAAO,YAAY,SAAS,QAAQ,MAAM,oBAAoB,SAAS,SAAS,GAAG;AAAA,IAAG,CAAC,CAAC;AACtR,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,cAAc,QAAQ,eAAe,CAAC;AAC5C,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,eAAe,YAAY,MAAM,QAAQ,YAAY,WAAW,IAAI,KAAK,GAAG,kCAAkC,YAAY,OAAO,WAAS,MAAM,SAAS,SAAS,EAAE,MAAM;AAC7L,SAAK,OAAO,IAAI;AAChB,UAAM,OAAO,SAAS,cAAc,IAAI;AACxC,eAAW,SAAS,YAAY,MAAM,GAAG,CAAC,GAAG;AAC3C,YAAM,OAAO,SAAS,cAAc,IAAI;AACxC,WAAK,cAAc,GAAG,MAAM,IAAI,cAAW,MAAM,IAAI,GAAG,MAAM,YAAY,SAAY,wBAAqB,MAAM,OAAO,KAAK,EAAE,SAAM,MAAM,MAAM;AACjJ,UAAI,UAAU,MAAM,YAAY,UAAa,MAAM,SAAS,QAAS,MAAK,OAAO,KAAK,OAAO,WAAW,YAAY;AAAE,cAAM,QAAQ,EAAE,MAAM,qBAAqB,IAAI,MAAM,GAAG,CAAC;AAAG,eAAO,YAAY,MAAM,IAAI,gDAAgD;AAAG,cAAM,QAAQ;AAAA,MAAG,CAAC,CAAC;AACrR,WAAK,OAAO,IAAI;AAAA,IAClB;AACA,SAAK,OAAO,IAAI;AAChB,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,SAAS,QAAQ,MAAM;AAC7B,QAAM,YAAY,QAAQ,mBAAmB,CAAC,GAAG,KAAK,UAAQ,KAAK,WAAW,MAAM;AACpF,MAAI,UAAU;AACZ,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,2BAA2B,SAAS,MAAM,KAAK,OAAO,QAAQ,SAAS,QAAQ,EAAE,IAAI,CAAC,CAAC,MAAM,QAAQ,MAAM,GAAG,IAAI,WAAM,SAAS,MAAM,IAAI,IAAI,IAAI,QAAQ,EAAE,EAAE,KAAK,QAAK,CAAC;AAC7L,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,QAAQ,QAAQ,gBAAgB,CAAC;AACvC,QAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,WAAS,YAAY;AACrB,QAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,WAAS,cAAc,mBAAmB,MAAM,SAAS,IAAI,MAAM,IAAI,UAAQ,cAAc,KAAK,GAAG,cAAc,KAAK,IAAI,SAAS,KAAK,IAAI,EAAE,EAAE,KAAK,QAAK,IAAI,wBAAwB;AACxL,WAAS,OAAO,QAAQ;AACxB,QAAM,OAAO,QAAQ,eAAe,CAAC;AACrC,MAAI,KAAK,SAAS,GAAG;AACnB,UAAM,UAAU,KAAK,CAAC;AACtB,UAAM,UAAU,SAAS,cAAc,GAAG;AAC1C,YAAQ,cAAc,uBAAuB,QAAQ,OAAO,UAAU,QAAQ,IAAI,UAAU,QAAQ,KAAK,QAAQ,QAAQ,UAAU,IAAI,KAAK,GAAG;AAC/I,aAAS,OAAO,OAAO;AAAA,EACzB;AACA,MAAI,QAAQ;AACV,UAAM,WAAW,SAAS,cAAc,OAAO;AAC/C,aAAS,cAAc;AACvB,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,cAAc;AACxB,UAAM,YAAY,SAAS,cAAc,OAAO;AAChD,cAAU,cAAc;AACxB,aAAS,OAAO,UAAU,WAAW,WAAW,KAAK,OAAO,oBAAoB,YAAY;AAC1F,YAAM,MAAM,OAAO,SAAS,KAAK;AACjC,YAAM,OAAO,EAAE,KAAK,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO;AAClG,YAAM,SAAS,MAAM,QAAQ,EAAE,MAAM,mBAAmB,OAAO,CAAC,GAAG,OAAO,IAAI,EAAE,CAAC;AACjF,aAAO,UAAU,OAAO,KAAK,yBAAyB,OAAO,UAAU,IAAI,KAAK,GAAG,+CAA+C;AAClI,YAAM,QAAQ;AAAA,IAChB,CAAC,CAAC;AAAA,EACJ;AACA,YAAU,OAAO,QAAQ;AACzB,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,uBAAuB,UAAU,MAAM,GAAG,CAAC,EAAE,IAAI,WAAS,GAAG,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,IAAI,gBAAgB,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM,GAAK,CAAC,CAAC,UAAU,KAAK,OAAO,KAAK,IAAI,IAAI,MAAM,MAAM,GAAK,MAAM,IAAI,KAAK,GAAG,OAAO,EAAE,KAAK,QAAK,CAAC,GAAG,UAAU,SAAS,IAAI,QAAQ,UAAU,SAAS,CAAC,UAAU,EAAE;AAC5V,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,WAAW,QAAQ,SAAS,CAAC,GAAG,OAAO,WAAS,MAAM,SAAS,QAAQ,EAAE,MAAM,GAAG,CAAC;AACzF,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,cAAc,sBAAsB,OAAO,MAAM,6CAA6C,OAAO,IAAI;AAC9G,cAAU,OAAO,IAAI;AAAA,EACvB;AACA,QAAM,QAAQ,QAAQ,aAAa,CAAC;AACpC,MAAI,QAAQ;AACV,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,UAAM,WAAW,SAAS,cAAc,GAAG;AAC3C,aAAS,cAAc,MAAM,SAAS,IAAI,eAAe,MAAM,IAAI,UAAQ,GAAG,KAAK,OAAO,OAAO,KAAK,MAAM,IAAI,KAAK,UAAU,YAAY,aAAa,EAAE,EAAE,KAAK,QAAK,CAAC,KAAK;AAC5K,aAAS,OAAO,QAAQ;AACxB,UAAM,eAAe,SAAS,cAAc,OAAO;AACnD,iBAAa,cAAc;AAC3B,UAAM,gBAAgB,SAAS,cAAc,OAAO;AACpD,kBAAc,cAAc;AAC5B,aAAS,OAAO,cAAc,eAAe,KAAK,OAAO,uBAAuB,YAAY;AAC1F,YAAM,QAAQ,EAAE,MAAM,qBAAqB,SAAS,aAAa,OAAO,UAAU,cAAc,MAAM,CAAC;AACvG,aAAO,aAAa,aAAa,KAAK,mDAAmD;AACzF,YAAM,QAAQ;AAAA,IAChB,CAAC,CAAC;AACF,cAAU,OAAO,QAAQ;AAAA,EAC3B;AACF;AAEA,SAAS,mBAAmB,QAAiC;AAC3D,MAAI,CAAC,iBAAkB;AACvB,MAAI,CAAC,QAAQ;AAAE,qBAAiB,cAAc;AAAkC;AAAA,EAAQ;AACxF,mBAAiB,cAAc,QAAQ,OAAO,OAAO,YAAY,QAAQ,mBAAgB,OAAO,YAAY,YAAY,QAAQ,wBAAqB,OAAO,gBAAgB,YAAY,QAAQ,yBAAsB,OAAO,iBAAiB,YAAY,QAAQ;AACpQ;AAEA,SAAS,YAAY,QAA4B;AAAE,MAAI,CAAC,UAAW;AAAQ,YAAU,gBAAgB;AAAG,aAAW,SAAS,OAAO,MAAM,GAAG,EAAE,GAAG;AAAE,UAAM,OAAO,SAAS,cAAc,IAAI;AAAG,SAAK,cAAc,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,mBAAmB,CAAC,SAAM,MAAM,IAAI,SAAM,MAAM,OAAO;AAAI,cAAU,OAAO,IAAI;AAAA,EAAG;AAAE;AAC5T,SAAS,iBAAiB,QAAiC;AAAE,MAAI,CAAC,eAAgB;AAAQ,iBAAe,gBAAgB;AAAG,MAAI,CAAC,QAAQ;AAAE,mBAAe,cAAc;AAA2F;AAAA,EAAQ;AAAE,QAAM,SAAS,CAAC,WAAW,OAAO,MAAM,IAAI,UAAU,OAAO,SAAS,UAAU,IAAI,yBAAyB,OAAO,gBAAgB,IAAI,UAAU,OAAO,SAAS,IAAI,qBAAqB,OAAO,UAAU,IAAI,qBAAqB,OAAO,kBAAkB,QAAQ,IAAI,EAAE;AAAG,aAAW,SAAS,QAAQ;AAAE,UAAM,OAAO,SAAS,cAAc,IAAI;AAAG,SAAK,cAAc;AAAO,mBAAe,OAAO,IAAI;AAAA,EAAG;AAAE;AAC9pB,eAAe,UAAyB;AAAE,QAAM,UAAU,MAAM,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAouE,aAAW,QAAQ,MAAM,QAAQ,UAAU,QAAQ,YAAY,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAC;AAAG,mBAAiB,QAAQ,UAAU;AAAG,YAAU,QAAQ,GAAG;AAAG,aAAW,QAAQ,IAAI;AAAG,eAAa,QAAQ,MAAM;AAAG,mBAAiB,QAAQ,MAAM,QAAQ,YAAY,CAAC,CAAC;AAAG,eAAa,QAAQ,kBAAkB,CAAC,GAAG,QAAQ,eAAe,CAAC,CAAC;AAAG,cAAY,QAAQ,SAAS,CAAC,CAAC;AAAG,gBAAc,QAAQ,WAAW,CAAC,CAAC;AAAG,kBAAgB,QAAQ,aAAa,CAAC,CAAC;AAAG,cAAY,QAAQ,OAAO,SAAS,CAAC,CAAC;AAAG,mBAAiB,OAAO;AAAG,oBAAkB,OAAO;AAAG,cAAY,OAAO;AAAG,iBAAe,OAAO;AAAG,cAAY,OAAO;AAAG,cAAY,QAAQ,KAAK;AAAG,qBAAmB,QAAQ,YAAY;AAAG,MAAI,QAAQ,SAAS,SAAU,QAAO,4DAA4D;AAAA,MAAQ,QAAO,QAAQ,UAAU,oEAAoE,4BAA4B;AAAG;AACltG,eAAe,OAAO,MAAuD;AAAE,QAAM,QAAQ,EAAE,MAAM,WAAW,WAAW,SAAS,GAAG,CAAC;AAAG,QAAM,QAAQ;AAAG;AAC5J,aAAa,iBAAiB,SAAS,MAAM,OAAO,cAAc,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AACxJ,cAAc,iBAAiB,SAAS,MAAM,OAAO,eAAe,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AAC1J,kBAAkB,iBAAiB,SAAS,MAAM,QAAQ,EAAE,MAAM,aAAa,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC;AAC5L,QAAQ,EAAE,MAAM,WAAS,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,IAAI,CAAC;",
4
+ "sourcesContent": ["import type { actionkind, agentplan, agentsession, captureexport, captureformat, capturenaming, captureoptions, cleanuprule, downloadspec, endpointconfig, fieldkind, formprofile, mimefilter, observationmode, policyevaluation, quarantineentry, regionrect, runsettings, safetyverdict, toolstep, transformrule } from \"./types.js\";\n\nconst sensitiveactions = new Set<actionkind>([\"click\", \"type\", \"navigate\", \"select\", \"presskey\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"reload\", \"back\", \"forward\", \"writestorage\", \"setattribute\", \"removeattribute\", \"evaluate\", \"tabcreate\", \"tabactivate\", \"tabclose\", \"tabreload\", \"windowcreate\", \"windowclose\", \"windowresize\", \"downloadfile\", \"clickpoint\", \"shiftclick\", \"dismissdialog\", \"enterframe\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"keyhold\", \"keyrelease\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"openlink\", \"openprivate\", \"reloadcache\", \"stopnav\", \"followlink\", \"spanav\", \"rewritequery\", \"setfragment\", \"navlist\", \"navprofile\", \"handleauth\", \"printpdf\", \"prefetch\", \"preconnect\", \"deeplink\", \"reopentab\", \"pausenav\", \"navrate\", \"openclipboard\", \"batchopen\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"restorelayout\", \"reopenrun\", \"badgetab\", \"fillform\", \"filllabel\", \"fillplaceholder\", \"submitform\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcard\", \"fillcode\", \"consentpassword\", \"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"streamdisk\", \"paginateextract\", \"resumeextract\", \"batchdownload\", \"pausedownload\", \"resumedownload\", \"interceptmime\", \"readclipboard\", \"writeclipboard\", \"copyscreen\", \"quarantinedownload\", \"scanvirus\", \"cleanupartifacts\"]);\nconst interactionactions = new Set<actionkind>([\"focus\", \"scroll\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"scrollpage\", \"scrollby\", \"scrollend\", \"scrolltop\", \"fullscreen\", \"zoomset\", \"movepointer\", \"clicktext\", \"clickaria\", \"clickname\", \"expanddetails\", \"pierceshadow\", \"retryaction\"]);\nconst readactions = new Set<actionkind>([\"observe\", \"inspect\", \"extract\", \"wait\", \"waitfor\", \"waittext\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"readlinks\", \"readimages\", \"readmeta\", \"readforms\", \"readstorage\", \"highlight\", \"tablist\", \"windowlist\", \"tabsnapshot\", \"mapclicks\", \"verifyvisible\", \"verifyenabled\", \"resolvexpath\", \"a11ytree\", \"readvisible\", \"readertree\", \"detectlists\", \"detecttables\", \"readjson\", \"watchmutate\", \"waitquiet\", \"watchbanner\", \"detectinfinitescroll\", \"detectvirtual\", \"detectlazy\", \"readscrollpos\", \"readlang\", \"readoutline\", \"countpages\", \"listshadow\", \"listframes\", \"classifypage\", \"fingerprintsection\", \"diffsnapshots\", \"readselection\", \"watchfocus\", \"detectsticky\", \"detectscrolllock\", \"readopengraph\", \"detectlanguage\", \"deriveselector\", \"waitload\", \"waiturl\", \"spawait\", \"detecthttp\", \"readredirects\", \"readfinalurl\", \"trailaudit\", \"navintent\", \"checksafe\", \"querytabs\", \"watchtab\", \"findclones\", \"searchtabs\", \"listaudio\", \"snapshotsession\", \"savelayout\", \"attachmeta\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"readerrors\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\", \"handoffcaptcha\", \"scrapetable\", \"importcsv\", \"looprows\", \"transformvalues\", \"deduperows\", \"mergepages\", \"stamplerows\", \"previewgrid\", \"logprovenance\", \"verifydownload\", \"exportnetlog\", \"namecaptures\", \"shotview\", \"shotfullpage\", \"shotelement\", \"shotregion\", \"contactsheet\"]);\nconst allowedactions = new Set<actionkind>([...sensitiveactions, ...interactionactions, ...readactions]);\nconst watchactions = new Set<actionkind>([\"watchmutate\", \"watchbanner\", \"watchfocus\", \"watchtab\"]);\nconst targetactions = new Set<actionkind>([\"inspect\", \"focus\", \"click\", \"type\", \"scroll\", \"select\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"highlight\", \"setattribute\", \"removeattribute\", \"waitfor\", \"shiftclick\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\", \"verifyvisible\", \"verifyenabled\", \"pierceshadow\", \"deriveselector\", \"fingerprintsection\", \"submitform\", \"retryform\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\", \"scrapetable\", \"paginateextract\", \"shotelement\"]);\nconst valueactions = new Set<actionkind>([\"presskey\", \"drag\", \"drop\", \"upload\", \"readattribute\", \"removeattribute\", \"waittext\", \"evaluate\", \"zoomset\", \"tabactivate\", \"tabclose\", \"tabreload\", \"windowclose\", \"windowresize\", \"tabcreate\", \"windowcreate\", \"downloadfile\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"keyhold\", \"keyrelease\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"followlink\", \"setfragment\", \"handleauth\", \"navintent\", \"openclipboard\", \"checksafe\", \"reopentab\", \"spanav\", \"duplicatetab\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"focuswindow\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"incognitowindow\", \"asksubmit\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\", \"pausedownload\", \"resumedownload\", \"verifydownload\", \"writeclipboard\", \"quarantinedownload\", \"scanvirus\"]);\nconst tabscommandactions = new Set<actionkind>([\"querytabs\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"watchtab\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"savelayout\", \"restorelayout\", \"findclones\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"listaudio\", \"reopenrun\", \"snapshotsession\"]);\nconst formactions = new Set<actionkind>([\"fillform\", \"filllabel\", \"fillplaceholder\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"submitform\", \"readerrors\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"handoffcaptcha\", \"fillcard\", \"fillcode\", \"consentpassword\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\"]);\n/** Extraction, transform, export and provenance kinds of the forms and data part two family. */\nconst datasetactions = new Set<actionkind>([\"scrapetable\", \"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"importcsv\", \"looprows\", \"transformvalues\", \"deduperows\", \"paginateextract\", \"mergepages\", \"stamplerows\", \"previewgrid\", \"streamdisk\", \"resumeextract\", \"logprovenance\"]);\n/** Export kinds that move extracted data out of local memory to disk, the clipboard or a reviewed sheet endpoint. */\nconst exportactions = new Set<actionkind>([\"exportcsv\", \"exportjson\", \"exportexcel\", \"copytable\", \"pushsheets\", \"streamdisk\"]);\n/** Files, clipboard and downloads kinds of the batch queue, interception, clipboard, quarantine, naming and cleanup family. */\nconst filesactions = new Set<actionkind>([\"batchdownload\", \"pausedownload\", \"resumedownload\", \"verifydownload\", \"interceptmime\", \"exportnetlog\", \"readclipboard\", \"writeclipboard\", \"copyscreen\", \"quarantinedownload\", \"scanvirus\", \"namecaptures\", \"cleanupartifacts\"]);\nconst captureactions = new Set<actionkind>([\"shotview\", \"shotfullpage\", \"shotelement\", \"shotregion\", \"contactsheet\"]);\n/** Field kinds the form grammar accepts inside records, profiles and value rules. */\nconst fieldkinds: fieldkind[] = [\"text\", \"email\", \"phone\", \"date\", \"number\", \"select\", \"check\", \"radio\", \"file\", \"password\", \"card\", \"code\"];\nconst layoutmutationactions = new Set<actionkind>([\"grouptabs\", \"colorgroup\", \"collapsegroup\", \"savelayout\", \"restorelayout\"]);\n/** Chromium tab group colors accepted as reviewed group color choices. */\nconst groupcolors = [\"grey\", \"blue\", \"red\", \"yellow\", \"green\", \"pink\", \"purple\", \"cyan\", \"orange\"];\n\n/** Normalizes a user supplied HTTPS endpoint without preserving a provider lock-in. */\nexport function normalizeendpoint(value: string): endpointconfig {\n const endpoint = new URL(value.trim());\n if (endpoint.protocol !== \"https:\") throw new Error(\"Devthink accepts HTTPS endpoints only.\");\n if (endpoint.username || endpoint.password) throw new Error(\"Endpoint credentials are not allowed in the URL.\");\n return { endpoint: endpoint.toString(), origin: endpoint.origin, configuredat: Date.now() };\n}\n\n/** Creates the exact optional host pattern requested from Chromium. */\nexport function hostpattern(origin: string): string {\n const parsed = new URL(origin);\n if (parsed.protocol !== \"https:\") throw new Error(\"Only HTTPS origins can be granted.\");\n return `${parsed.origin}/*`;\n}\n\n/** True when the action kind observes the page over a reviewed lifetime window. */\nexport function iswatchkind(kind: actionkind): boolean {\n return watchactions.has(kind);\n}\n\n/** Grades the observation mode of a kind: passive capture, watched lifetimes or diffing passes. */\nexport function observationmodeof(kind: actionkind): observationmode {\n if (watchactions.has(kind) || kind === \"waitquiet\") return \"watching\";\n if (kind === \"diffsnapshots\") return \"diffing\";\n return \"passive\";\n}\n\n/** Defines action risk from the fixed local allowlist. */\nexport function actionrisk(kind: actionkind): \"read\" | \"interaction\" | \"sensitive\" {\n if (!allowedactions.has(kind)) throw new Error(\"Unsupported browser action.\");\n if (sensitiveactions.has(kind)) return \"sensitive\";\n return interactionactions.has(kind) ? \"interaction\" : \"read\";\n}\n\n/** True when the action kind accepts a css selector target or a reviewed targetref. */\nexport function needstarget(kind: actionkind): boolean {\n return targetactions.has(kind);\n}\n\n/** Parses the reviewed JSON options of a step; malformed payloads are rejected early. */\nexport function parseoptions(step: toolstep): Record<string, unknown> {\n if (step.options === undefined) return {};\n let parsed: unknown;\n try { parsed = JSON.parse(step.options); } catch { throw new Error(\"Step options must be a JSON object.\"); }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) throw new Error(\"Step options must be a JSON object.\");\n return parsed as Record<string, unknown>;\n}\n\n/** Maps an action kind to the optional browser permission it requires, if any. */\nexport function requiredcapability(kind: actionkind): string | undefined {\n if (kind === \"tablist\") return \"tabs\";\n if (kind === \"downloadfile\") return \"downloads\";\n if (kind === \"openclipboard\") return \"clipboardRead\";\n if (kind === \"copytable\") return \"clipboardWrite\";\n if (kind === \"batchdownload\" || kind === \"pausedownload\" || kind === \"resumedownload\" || kind === \"verifydownload\" || kind === \"interceptmime\" || kind === \"quarantinedownload\" || kind === \"scanvirus\") return \"downloads\";\n if (kind === \"readclipboard\") return \"clipboardRead\";\n if (kind === \"writeclipboard\" || kind === \"copyscreen\") return \"clipboardWrite\";\n if (kind === \"openlink\" || kind === \"openprivate\" || kind === \"navlist\" || kind === \"batchopen\" || kind === \"reopentab\" || kind === \"deeplink\") return \"tabs\";\n if (tabscommandactions.has(kind)) return \"tabs\";\n return undefined;\n}\n\n/** True when the kind commands tabs or windows beyond the active tab and needs the optional tabs capability. */\nexport function istabscommandkind(kind: actionkind): boolean {\n return tabscommandactions.has(kind);\n}\n\n/** True when the kind mutates tab groups or layouts and therefore stays inside the active session. */\nexport function islayoutkind(kind: actionkind): boolean {\n return layoutmutationactions.has(kind);\n}\n\n/** True when the kind belongs to the forms and data family. */\nexport function isformkind(kind: actionkind): boolean {\n return formactions.has(kind);\n}\n\n/** True when the kind belongs to the extraction, transform, export and provenance family. */\nexport function isdatasetkind(kind: actionkind): boolean {\n return datasetactions.has(kind);\n}\n\n/** True when the kind exports extracted data out of local memory to disk, the clipboard or a reviewed sheet endpoint. */\nexport function isexportkind(kind: actionkind): boolean {\n return exportactions.has(kind);\n}\n\n/** True when the kind belongs to the files, clipboard and downloads family. */\nexport function isfileskind(kind: actionkind): boolean {\n return filesactions.has(kind);\n}\n\n/** True when the kind belongs to the media capture family of viewport, full page, element, region and contact sheet shots. */\nexport function iscapturekind(kind: actionkind): boolean {\n return captureactions.has(kind);\n}\n\n/** Requires the active tab grant of the live session before any capture kind runs: the session tab and origin must match and the origin grant must cover the active origin. */\nexport function capturegate(session: agentsession | undefined, tabid: number, origin: string, now: number): policyevaluation {\n if (!session || session.stoppedat) return { allowed: false, reason: \"No active browser session exists for the capture.\" };\n if (session.expiresat <= now) return { allowed: false, reason: \"The browser session has expired and cannot capture.\" };\n if (session.pausedat) return { allowed: false, reason: \"The browser session is paused and cannot capture.\" };\n if (session.tabid !== tabid) return { allowed: false, reason: `The capture needs the active tab grant of session tab ${session.tabid} and refuses tab ${tabid}.` };\n if (!origingranted(session, origin)) return { allowed: false, reason: `The capture of ${origin} needs the session origin grants first.` };\n return { allowed: true };\n}\n\n/** Validates one reviewed capture options payload: format inside the png, jpeg and webp set, quality bounded only by the format range, pixel ratio from one up with no code ceiling, and a known export target. */\nexport function validatecaptureoptions(value: unknown): policyevaluation {\n if (value === undefined) return { allowed: true };\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"The reviewed capture options must be an object in options.capture.\" };\n const options = value as Record<string, unknown>;\n if (options.format !== undefined && options.format !== \"png\" && options.format !== \"jpeg\" && options.format !== \"webp\") return { allowed: false, reason: \"The reviewed capture format must be png, jpeg or webp.\" };\n if (options.quality !== undefined && (typeof options.quality !== \"number\" || !Number.isFinite(options.quality) || options.quality < 0 || options.quality > 100)) return { allowed: false, reason: \"The reviewed capture quality must stay between zero and one hundred; any value in that range is the user choice with no code cap.\" };\n if (options.pixelratio !== undefined && (typeof options.pixelratio !== \"number\" || !Number.isFinite(options.pixelratio) || options.pixelratio < 1)) return { allowed: false, reason: \"The reviewed pixel ratio starts at one and climbs to any user configured ceiling with no code ceiling.\" };\n if (options.annotate !== undefined && typeof options.annotate !== \"boolean\") return { allowed: false, reason: \"The reviewed capture annotation flag must be a boolean.\" };\n if (options.exporttarget !== undefined && options.exporttarget !== \"memory\" && options.exporttarget !== \"download\" && options.exporttarget !== \"clipboard\") return { allowed: false, reason: \"The reviewed capture export target must be memory, download or clipboard.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed region rectangle in css pixels; negative coordinates and non positive sizes are refused. */\nexport function validateregionrect(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed regionrect with x, y, width and height in css pixels is required in options.\" };\n const rect = value as Record<string, unknown>;\n for (const field of [\"x\", \"y\", \"width\", \"height\"]) {\n if (typeof rect[field] !== \"number\" || !Number.isFinite(rect[field] as number)) return { allowed: false, reason: `The reviewed regionrect needs a numeric ${field} in css pixels.` };\n }\n if ((rect.x as number) < 0 || (rect.y as number) < 0) return { allowed: false, reason: \"The reviewed regionrect refuses negative coordinates.\" };\n if ((rect.width as number) <= 0 || (rect.height as number) <= 0) return { allowed: false, reason: \"The reviewed regionrect needs positive width and height values.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed capture naming rule against the allowed segment set: run, step, sequence and kind flags only. */\nexport function validatecapturenaming(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed capturenaming rule with run, step, sequence and kind flags is required.\" };\n const rule = value as Record<string, unknown>;\n const segments = [\"run\", \"step\", \"sequence\", \"kind\"];\n for (const key of Object.keys(rule)) {\n if (!segments.includes(key)) return { allowed: false, reason: `The reviewed capturenaming rule refuses the unknown ${key} segment; only run, step, sequence and kind participate.` };\n }\n for (const segment of segments) {\n if (rule[segment] !== undefined && typeof rule[segment] !== \"boolean\") return { allowed: false, reason: `The reviewed capturenaming ${segment} flag must be a boolean.` };\n }\n if (!segments.some(segment => rule[segment] === true)) return { allowed: false, reason: \"The reviewed capturenaming rule needs at least one enabled segment of run, step, sequence and kind.\" };\n return { allowed: true };\n}\n\n/** Routes the capture export target: memory stays local, clipboard needs the clipboardwrite grant and disk writes only run through the reviewed download flow. */\nexport function captureexportgranted(target: captureexport | undefined): policyevaluation {\n if (target === undefined || target === \"memory\") return { allowed: true };\n if (target === \"clipboard\") return { allowed: true, reason: \"The clipboard capture export runs behind the optional clipboardwrite capability, negotiated through the permissions api before the copy.\" };\n if (target === \"download\") return { allowed: true, reason: \"The download capture export runs only through the reviewed download flow behind the optional downloads capability.\" };\n return { allowed: false, reason: \"The capture export target must be memory, download or clipboard; no other disk route exists.\" };\n}\n\n/** Keeps the stitching scroll budget inside the reviewed wait window: the settle windows of every tile must fit the reviewed wait window with no code ceiling on either side. */\nexport function stitchbudgetallowed(tiles: number, settle: number, wait: number): policyevaluation {\n if (tiles <= 0) return { allowed: false, reason: \"The stitch budget needs at least one tile.\" };\n if (settle < 0 || wait < 0) return { allowed: false, reason: \"The reviewed settle and wait windows must be zero or positive milliseconds.\" };\n if (tiles * settle > wait) return { allowed: false, reason: `The stitching scroll budget of ${tiles} tiles at ${settle} milliseconds exceeds the reviewed wait window of ${wait} milliseconds; review a wider window or a smaller settle.` };\n return { allowed: true };\n}\n\n/** Allows beforeafter state capture to wrap any existing action kind except the capture kinds themselves; pixel evidence around sensitive actions grades as reviewable evidence. */\nexport function beforeafterwrapallowed(kind: actionkind): boolean {\n return allowedactions.has(kind) && !captureactions.has(kind);\n}\n\n/** Exposes the capture retention window as a user configured choice; an absent value keeps every capture byte forever with no code ceiling. */\nexport function captureretentionwindow(settings: runsettings | undefined): number | undefined {\n return settings?.captureretention;\n}\n\n/** Validates the reviewed media capture parameter grammar; pixel ratios, quality values, cell counts and retention windows stay user choices with no code ceilings. */\nfunction validatecapturegrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n const optioncheck = validatecaptureoptions(options.capture);\n if (!optioncheck.allowed) return optioncheck;\n if (options.settle !== undefined && (typeof options.settle !== \"number\" || !Number.isFinite(options.settle) || options.settle < 0)) return { allowed: false, reason: \"The reviewed capture settle window must be zero or a positive number of milliseconds.\" };\n if (options.overlap !== undefined && (typeof options.overlap !== \"number\" || !Number.isInteger(options.overlap) || options.overlap < 0)) return { allowed: false, reason: \"The reviewed stitch overlap must be zero or a positive number of rows.\" };\n if (options.wait !== undefined && (typeof options.wait !== \"number\" || !Number.isFinite(options.wait) || options.wait < 0)) return { allowed: false, reason: \"The reviewed capture wait window must be zero or a positive number of milliseconds.\" };\n if (options.naming !== undefined) {\n const namingcheck = validatecapturenaming(options.naming);\n if (!namingcheck.allowed) return namingcheck;\n }\n if (kind === \"shotregion\") {\n const rectcheck = validateregionrect(options.regionrect);\n if (!rectcheck.allowed) return rectcheck;\n if (options.reviewed !== true) return { allowed: false, reason: \"Every reviewed regionrect needs the explicit reviewed flag before shotregion runs.\" };\n if (options.container !== undefined && !isnonempty(options.container)) return { allowed: false, reason: \"The reviewed scrollable container selector must be a non-empty string.\" };\n if (options.steps !== undefined && (typeof options.steps !== \"number\" || !Number.isInteger(options.steps) || options.steps < 1)) return { allowed: false, reason: \"The reviewed container scroll steps must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"contactsheet\") {\n const elements = options.elements;\n if (!Array.isArray(elements) || elements.length === 0 || !elements.every(item => isnonempty(item))) return { allowed: false, reason: \"A reviewed non-empty list of element selectors is required in options for the contact sheet; the cell count stays the user choice.\" };\n const layout = options.sheet;\n if (layout !== undefined) {\n if (!layout || typeof layout !== \"object\" || Array.isArray(layout)) return { allowed: false, reason: \"The reviewed sheetlayout must be an object with cellsize, columns and label.\" };\n const sheet = layout as Record<string, unknown>;\n if (typeof sheet.cellsize !== \"number\" || !Number.isFinite(sheet.cellsize) || sheet.cellsize <= 0) return { allowed: false, reason: \"The reviewed contact sheet cell size must be a positive number of pixels.\" };\n if (typeof sheet.columns !== \"number\" || !Number.isInteger(sheet.columns) || sheet.columns < 1) return { allowed: false, reason: \"The reviewed contact sheet column count must be a positive integer with no code ceiling.\" };\n if (sheet.label !== undefined && sheet.label !== \"none\" && sheet.label !== \"index\" && sheet.label !== \"selector\" && sheet.label !== \"both\") return { allowed: false, reason: \"The reviewed contact sheet label style must be none, index, selector or both.\" };\n }\n }\n return { allowed: true };\n}\n\n/** Refuses any export that would leave local memory while the session origin grants do not cover the active origin. */\nexport function exportgranted(session: agentsession | undefined, origin: string): policyevaluation {\n if (!origingranted(session, origin)) return { allowed: false, reason: `The export of extracted data from ${origin} needs the session origin grants before it leaves local memory.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed fieldmatch grammar of one form field entry. */\nexport function validatefieldmatch(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed field match is required in options.\" };\n const match = value as Record<string, unknown>;\n if (match.mode !== \"label\" && match.mode !== \"placeholder\" && match.mode !== \"arialabel\" && match.mode !== \"name\") return { allowed: false, reason: \"The reviewed field match mode must be label, placeholder, arialabel or name.\" };\n const key = match.mode === \"label\" ? \"label\" : match.mode === \"placeholder\" ? \"placeholder\" : match.mode === \"arialabel\" ? \"arialabel\" : \"name\";\n if (!isnonempty(match[key])) return { allowed: false, reason: `The reviewed ${match.mode} field match needs a non-empty ${key}.` };\n return { allowed: true };\n}\n\n/** Validates a reviewed structured form record; password entries are refused because passwords need the explicit consentpassword consent. */\nexport function validateformrecord(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed form record with entries is required in options.\" };\n const record = value as Record<string, unknown>;\n if (record.form !== undefined && !isnonempty(record.form)) return { allowed: false, reason: \"The reviewed form record form selector must be a non-empty string.\" };\n if (!Array.isArray(record.entries) || record.entries.length === 0) return { allowed: false, reason: \"The reviewed form record needs a non-empty list of entries.\" };\n for (const item of record.entries) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed form record entry must be an object.\" };\n const entry = item as Record<string, unknown>;\n const matchcheck = validatefieldmatch(entry.match);\n if (!matchcheck.allowed) return matchcheck;\n if (typeof entry.kind !== \"string\" || !fieldkinds.includes(entry.kind as fieldkind)) return { allowed: false, reason: \"Every reviewed form record entry needs a known field kind.\" };\n if (typeof entry.value !== \"string\") return { allowed: false, reason: \"Every reviewed form record entry needs a string value.\" };\n if (entry.kind === \"password\") return { allowed: false, reason: \"Password entries are refused inside form records; use consentpassword with a reviewed consent ref.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed valuegen grammar of a generatevalues step. */\nexport function validatevaluegen(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed valuegen rule with a field kind is required in options.\" };\n const rule = value as Record<string, unknown>;\n if (typeof rule.kind !== \"string\" || !fieldkinds.includes(rule.kind as fieldkind)) return { allowed: false, reason: \"The reviewed valuegen kind must be a known field kind.\" };\n if (rule.locale !== undefined && !isnonempty(rule.locale)) return { allowed: false, reason: \"The reviewed valuegen locale must be a non-empty string.\" };\n if (rule.seed !== undefined && (typeof rule.seed !== \"number\" || !Number.isFinite(rule.seed))) return { allowed: false, reason: \"The reviewed valuegen seed must be a finite number.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed list of label or placeholder value pairs for filllabel and fillplaceholder steps. */\nfunction validatefieldpairs(options: Record<string, unknown>, mode: \"label\" | \"placeholder\"): policyevaluation {\n const pairs = options.fields;\n if (!Array.isArray(pairs) || pairs.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of field pairs is required in options.\" };\n for (const item of pairs) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed field pair must be an object.\" };\n const pair = item as Record<string, unknown>;\n if (!isnonempty(pair[mode])) return { allowed: false, reason: `Every reviewed field pair needs a non-empty ${mode}.` };\n if (typeof pair.value !== \"string\" || !pair.value.trim()) return { allowed: false, reason: \"Every reviewed field pair needs a non-empty value.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed card segment grammar of a fillcard step. */\nfunction validatecardsegments(value: unknown): policyevaluation {\n if (!Array.isArray(value) || value.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of card segments is required in options.\" };\n for (const item of value) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { allowed: false, reason: \"Every reviewed card segment must be an object.\" };\n const segment = item as Record<string, unknown>;\n const matchcheck = validatefieldmatch(segment.match);\n if (!matchcheck.allowed) return matchcheck;\n if (typeof segment.value !== \"string\" || !segment.value.trim()) return { allowed: false, reason: \"Every reviewed card segment needs a non-empty value.\" };\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed forms and data parameter grammar of the form family. */\nfunction validateformgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"fillform\" || (kind === \"saveprofiles\" && options.formrecord !== undefined)) {\n const recordcheck = validateformrecord(options.formrecord);\n if (!recordcheck.allowed) return recordcheck;\n }\n if (kind === \"filllabel\" || kind === \"fillplaceholder\") {\n const paircheck = validatefieldpairs(options, kind === \"filllabel\" ? \"label\" : \"placeholder\");\n if (!paircheck.allowed) return paircheck;\n }\n if (kind === \"generatevalues\" && options.valuegen !== undefined) {\n const rulecheck = validatevaluegen(options.valuegen);\n if (!rulecheck.allowed) return rulecheck;\n }\n if (kind === \"saveprofiles\" && !isnonempty(options.name)) return { allowed: false, reason: \"A reviewed profile name is required in options.\" };\n if (kind === \"submitform\" && !isnonempty(options.consentref)) return { allowed: false, reason: \"A reviewed consent ref of an approved asksubmit ticket is required in options.\" };\n if (kind === \"retryform\") {\n const backoff = options.backoff;\n if (!backoff || typeof backoff !== \"object\" || Array.isArray(backoff)) return { allowed: false, reason: \"A reviewed backoff rule with wait and factor is required in options.\" };\n const rule = backoff as Record<string, unknown>;\n if (typeof rule.wait !== \"number\" || !Number.isFinite(rule.wait) || rule.wait <= 0) return { allowed: false, reason: \"The reviewed retry backoff wait must be a positive number of milliseconds with no code ceiling.\" };\n if (typeof rule.factor !== \"number\" || !Number.isFinite(rule.factor) || rule.factor < 1) return { allowed: false, reason: \"The reviewed retry backoff factor must be one or greater with no code ceiling.\" };\n if (options.attempts !== undefined && (typeof options.attempts !== \"number\" || !Number.isInteger(options.attempts) || options.attempts < 1)) return { allowed: false, reason: \"The reviewed retry attempts must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"runwizard\" && options.steps !== undefined && (typeof options.steps !== \"number\" || !Number.isInteger(options.steps) || options.steps < 1)) return { allowed: false, reason: \"The reviewed wizard step count must be a positive integer with no code ceiling.\" };\n if (kind === \"selectchain\") {\n if (!isnonempty(options.child)) return { allowed: false, reason: \"A reviewed child selector of the dependent control is required in options.\" };\n if (!nonnegativeoption(options, \"wait\")) return { allowed: false, reason: \"The reviewed dependent wait must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"picktypeahead\") {\n if (!isnonempty(options.pick)) return { allowed: false, reason: \"A reviewed suggestion entry to pick is required in options.\" };\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The reviewed typeahead timeout must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"pickdate\" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed date must use the yyyy-mm-dd form.\" };\n if (kind === \"fillcard\") {\n const segmentcheck = validatecardsegments(options.segments);\n if (!segmentcheck.allowed) return segmentcheck;\n if (!nonnegativeoption(options, \"pause\")) return { allowed: false, reason: \"The reviewed card typing pause must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"fillcode\" && !isnonempty(options.source)) return { allowed: false, reason: \"A reviewed one time code source is required in options.\" };\n if (kind === \"consentpassword\" && !isnonempty(options.consentref)) return { allowed: false, reason: \"A reviewed consent ref is required in options before any password is filled.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed transform rule: a supported expression, source columns and a target column. */\nexport function validatetransformrule(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed transform rule with an expression, sources and a target is required in options.\" };\n const rule = value as Record<string, unknown>;\n const expression = rule.expression;\n if (typeof expression !== \"string\" || !/^(trim|upper|lower|number|prefix|suffix|replace)(?::.+)?$/.test(expression)) return { allowed: false, reason: \"The reviewed transform expression must be trim, upper, lower, number, prefix, suffix or replace with an optional argument.\" };\n if (expression.startsWith(\"replace\") && !expression.slice(\"replace\".length).includes(\"=>\")) return { allowed: false, reason: \"The reviewed replace expression needs the from=>to separator.\" };\n if (expression.startsWith(\"replace\") && expression.slice(\"replace:\".length).split(\"=>\")[0] === \"\") return { allowed: false, reason: \"The reviewed replace expression needs a non-empty from part.\" };\n if (!Array.isArray(rule.sources) || rule.sources.length === 0 || !rule.sources.every(source => isnonempty(source))) return { allowed: false, reason: \"Every reviewed transform rule needs a non-empty list of source columns.\" };\n if (!isnonempty(rule.target)) return { allowed: false, reason: \"Every reviewed transform rule needs a non-empty target column.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed dataset id list in options. */\nfunction validatedatasetids(options: Record<string, unknown>, key: string): policyevaluation {\n const ids = options[key];\n if (!Array.isArray(ids) || ids.length === 0 || !ids.every(id => isnonempty(id))) return { allowed: false, reason: `A reviewed non-empty list of dataset ids is required in options as ${key}.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed extraction, transform, export and provenance parameter grammar of the data family. */\nfunction validatedatagrammar(step: toolstep, options: Record<string, unknown>, origin: string): policyevaluation {\n const kind = step.kind;\n if (kind === \"scrapetable\") {\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed dataset name must be a non-empty string.\" };\n if (options.rowlimit !== undefined && (typeof options.rowlimit !== \"number\" || !Number.isInteger(options.rowlimit) || options.rowlimit < 1)) return { allowed: false, reason: \"The reviewed row limit must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"paginateextract\") {\n if (!isnonempty(options.next)) return { allowed: false, reason: \"A reviewed next control selector is required in options.\" };\n if (options.pages !== undefined && (typeof options.pages !== \"number\" || !Number.isInteger(options.pages) || options.pages < 1)) return { allowed: false, reason: \"The reviewed page count must be a positive integer with no code ceiling.\" };\n if (!nonnegativeoption(options, \"wait\")) return { allowed: false, reason: \"The reviewed row freshness wait must be zero or a positive number of milliseconds.\" };\n }\n if (kind === \"exportcsv\" || kind === \"exportjson\" || kind === \"exportexcel\" || kind === \"copytable\" || kind === \"streamdisk\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed artifact name must be a non-empty string.\" };\n }\n if (kind === \"exportcsv\" && options.delimiter !== undefined && (typeof options.delimiter !== \"string\" || options.delimiter.length !== 1)) return { allowed: false, reason: \"The reviewed csv delimiter must be a single character.\" };\n if (kind === \"streamdisk\" && (typeof options.chunk !== \"number\" || !Number.isInteger(options.chunk) || options.chunk < 1)) return { allowed: false, reason: \"The reviewed streaming chunk size must be a positive integer with no code ceiling.\" };\n if (kind === \"pushsheets\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (!isnonempty(options.sheet)) return { allowed: false, reason: \"A reviewed sheet endpoint url is required in options.\" };\n if (!ishttpsurl(options.sheet)) return { allowed: false, reason: \"The reviewed sheet endpoint url must use HTTPS.\" };\n if (options.reviewed !== true) return { allowed: false, reason: \"The sheet push needs the explicit reviewed flag before any data leaves local memory.\" };\n }\n if (kind === \"importcsv\") {\n if (typeof options.csv !== \"string\" || !options.csv.trim()) return { allowed: false, reason: \"Reviewed csv content is required in options.\" };\n if (options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed dataset name must be a non-empty string.\" };\n if (options.mapping !== undefined) {\n const mapping = options.mapping;\n if (!mapping || typeof mapping !== \"object\" || Array.isArray(mapping) || !Object.values(mapping).every(item => typeof item === \"string\")) return { allowed: false, reason: \"The reviewed csv column mapping must be an object of string values.\" };\n }\n }\n if (kind === \"looprows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.variable !== undefined && !isnonempty(options.variable)) return { allowed: false, reason: \"The reviewed row variable name must be a non-empty string.\" };\n const inner = validateinnerstep(options, origin);\n if (!inner.allowed) return inner;\n }\n if (kind === \"transformvalues\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n const rules = options.rules;\n if (!Array.isArray(rules) || rules.length === 0) return { allowed: false, reason: \"A reviewed non-empty list of transform rules is required in options.\" };\n for (const item of rules) {\n const rulecheck = validatetransformrule(item);\n if (!rulecheck.allowed) return rulecheck;\n }\n }\n if (kind === \"deduperows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n const keys = options.keys;\n if (!Array.isArray(keys) || keys.length === 0 || !keys.every(key => isnonempty(key))) return { allowed: false, reason: \"A reviewed non-empty list of dedupe column keys is required in options.\" };\n }\n if (kind === \"mergepages\") {\n const listcheck = validatedatasetids(options, \"datasets\");\n if (!listcheck.allowed) return listcheck;\n }\n if (kind === \"stamplerows\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.url !== undefined && !ishttpsurl(options.url)) return { allowed: false, reason: \"The reviewed source url must use HTTPS.\" };\n }\n if (kind === \"previewgrid\") {\n if (!isnonempty(options.dataset)) return { allowed: false, reason: \"A reviewed dataset id is required in options.\" };\n if (options.sample !== undefined && (typeof options.sample !== \"number\" || !Number.isInteger(options.sample) || options.sample < 1)) return { allowed: false, reason: \"The reviewed sample row count must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"resumeextract\" && !isnonempty(options.session)) return { allowed: false, reason: \"A reviewed extract session id is required in options.\" };\n if (kind === \"logprovenance\" && !isnonempty(options.artifact)) return { allowed: false, reason: \"A reviewed artifact id or name is required in options.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed batch download specification: a non-empty HTTPS url list, an optional filename rule and an optional completion criterion. */\nexport function validatedownloadspec(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed downloadspec with a url list is required in options.\" };\n const spec = value as Record<string, unknown>;\n if (!Array.isArray(spec.urls) || spec.urls.length === 0 || !spec.urls.every(url => ishttpsurl(url))) return { allowed: false, reason: \"The reviewed downloadspec needs a non-empty list of HTTPS urls.\" };\n if (spec.filename !== undefined && !isnonempty(spec.filename)) return { allowed: false, reason: \"The reviewed downloadspec filename rule must be a non-empty string.\" };\n if (spec.complete !== undefined && spec.complete !== \"size\" && spec.complete !== \"checksum\") return { allowed: false, reason: \"The reviewed downloadspec completion criterion must be size or checksum.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed mime interception filter: include and exclude patterns plus the deny default for unlisted mime types. */\nexport function validatemimefilter(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed mimefilter with include and exclude patterns is required in options.\" };\n const filter = value as Record<string, unknown>;\n if (!Array.isArray(filter.include) || filter.include.length === 0 || !filter.include.every(pattern => isnonempty(pattern))) return { allowed: false, reason: \"The reviewed mimefilter needs a non-empty list of include patterns.\" };\n if (filter.exclude !== undefined && (!Array.isArray(filter.exclude) || !filter.exclude.every(pattern => isnonempty(pattern)))) return { allowed: false, reason: \"The reviewed mimefilter exclude patterns must be a list of non-empty strings.\" };\n if (filter.default !== \"deny\" && filter.default !== \"allow\") return { allowed: false, reason: \"The reviewed mimefilter needs the deny or allow default for unlisted mime types.\" };\n return { allowed: true };\n}\n\n/** Validates one reviewed cleanup rule: a positive age window with no code ceiling, an artifact kind and a keep policy. */\nexport function validatecleanuprule(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed cleanuprule with an age, a kind and a keep policy is required.\" };\n const rule = value as Record<string, unknown>;\n if (typeof rule.age !== \"number\" || !Number.isFinite(rule.age) || rule.age <= 0) return { allowed: false, reason: \"The reviewed cleanup age window must be a positive number of milliseconds with no code ceiling.\" };\n if (!isnonempty(rule.kind)) return { allowed: false, reason: \"The reviewed cleanup rule needs a non-empty artifact kind, or any to match every kind.\" };\n if (rule.keep !== \"none\" && rule.keep !== \"latest\" && rule.keep !== \"all\") return { allowed: false, reason: \"The reviewed cleanup keep policy must be none, latest or all.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed files, clipboard and downloads parameter grammar; batch sizes, concurrent windows and cleanup ages stay user configured with no code ceilings. */\nfunction validatefilesgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"batchdownload\") {\n const speccheck = validatedownloadspec(options.downloadspec);\n if (!speccheck.allowed) return speccheck;\n if (options.concurrent !== undefined && (typeof options.concurrent !== \"number\" || !Number.isInteger(options.concurrent) || options.concurrent < 1)) return { allowed: false, reason: \"The reviewed concurrent download window must be a positive integer with no code ceiling.\" };\n }\n if (kind === \"pausedownload\" || kind === \"resumedownload\" || kind === \"verifydownload\" || kind === \"quarantinedownload\" || kind === \"scanvirus\") {\n if (!isnonempty(step.value)) return { allowed: false, reason: \"A reviewed download or quarantine reference is required.\" };\n if (kind === \"verifydownload\") {\n if (options.checksum !== undefined && !isnonempty(options.checksum)) return { allowed: false, reason: \"The reviewed expected checksum must be a non-empty string.\" };\n if (options.bytes !== undefined && (typeof options.bytes !== \"number\" || !Number.isFinite(options.bytes) || options.bytes < 0)) return { allowed: false, reason: \"The reviewed expected size must be zero or a positive number of bytes.\" };\n }\n if (kind === \"scanvirus\" && options.scanner !== undefined && !isnonempty(options.scanner)) return { allowed: false, reason: \"The reviewed scanner name must be a non-empty string.\" };\n if (kind === \"quarantinedownload\" && options.reason !== undefined && !isnonempty(options.reason)) return { allowed: false, reason: \"The reviewed quarantine reason must be a non-empty string.\" };\n }\n if (kind === \"interceptmime\") {\n const filtercheck = validatemimefilter(options.mimefilter);\n if (!filtercheck.allowed) return filtercheck;\n }\n if (kind === \"readclipboard\") {\n if (!isnonempty(options.consentref)) return { allowed: false, reason: \"A clipboard read requires a reviewed consent ref of an approved consent prompt in options.\" };\n if (options.prompt !== undefined && !isnonempty(options.prompt)) return { allowed: false, reason: \"The reviewed clipboard consent prompt must be a non-empty string.\" };\n }\n if (kind === \"exportnetlog\" && options.stepid !== undefined && !isnonempty(options.stepid)) return { allowed: false, reason: \"The reviewed netlog step filter must be a non-empty step id.\" };\n if (kind === \"namecaptures\") {\n if (!isnonempty(options.task)) return { allowed: false, reason: \"A reviewed task id is required in options for capture naming.\" };\n if (options.steps !== undefined && (!Array.isArray(options.steps) || options.steps.length === 0 || !options.steps.every(item => isnonempty(item)))) return { allowed: false, reason: \"The reviewed capture steps must be a non-empty list of step ids when present.\" };\n if (options.extension !== undefined && !isnonempty(options.extension)) return { allowed: false, reason: \"The reviewed capture extension must be a non-empty string.\" };\n }\n if (kind === \"cleanupartifacts\" && options.rules !== undefined) {\n const rules = options.rules;\n if (!Array.isArray(rules) || rules.length === 0) return { allowed: false, reason: \"The reviewed cleanup rules must be a non-empty list when present.\" };\n for (const item of rules) {\n const rulecheck = validatecleanuprule(item);\n if (!rulecheck.allowed) return rulecheck;\n }\n }\n return { allowed: true };\n}\n\n/** Requires an approved consent prompt before any clipboard read; every read consumes its own prompt. */\nexport function clipboardconsentgranted(step: toolstep): policyevaluation {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const consentref = options.consentref;\n if (typeof consentref !== \"string\" || !consentref.trim()) return { allowed: false, reason: \"A clipboard read requires a reviewed consent ref in options.\" };\n return { allowed: true };\n}\n\n/** Refuses to release any quarantined file before a clean scan verdict exists. */\nexport function quarantinereleasegranted(entry: quarantineentry): policyevaluation {\n if (entry.scan !== \"clean\") return { allowed: false, reason: `The quarantined file ${entry.path} cannot leave quarantine with the ${entry.scan} scan verdict; only a clean verdict releases it.` };\n return { allowed: true };\n}\n\n/** Refuses downloads and download interception that fall outside the session origin grants. */\nexport function downloadgranted(session: agentsession | undefined, url: string): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed download URL is invalid.\" }; }\n if (!origingranted(session, origin)) return { allowed: false, reason: `The download from ${origin} leaves the session origin grants and needs a session grant first.` };\n return { allowed: true };\n}\n\n/** Masks a clipboard payload for every log line; the full text never persists anywhere. */\nexport function maskclipboard(payload: string): string {\n return `[clipboard payload of ${payload.length} character${payload.length === 1 ? \"\" : \"s\"}]`;\n}\n\n/** Requires an asksubmit review step before every form submission step. */\nexport function submitreviewgranted(steps: toolstep[], submitid: string): policyevaluation {\n const position = steps.findIndex(candidate => candidate.id === submitid);\n const asked = steps.some((candidate, index) => candidate.kind === \"asksubmit\" && (position === -1 || index < position));\n return asked ? { allowed: true } : { allowed: false, reason: \"Form submission requires an asksubmit review step before it.\" };\n}\n\n/** Requires a reviewed consent ref before any password field is filled. */\nexport function passwordconsentgranted(step: toolstep): policyevaluation {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const consentref = options.consentref;\n if (typeof consentref !== \"string\" || !consentref.trim()) return { allowed: false, reason: \"A password fill requires a reviewed consent ref in options.\" };\n return { allowed: true };\n}\n\n/** True when a numeric value passes the Luhn checksum used by card networks. */\nfunction luhnvalid(digits: string): boolean {\n let sum = 0;\n let double = false;\n for (let index = digits.length - 1; index >= 0; index -= 1) {\n let value = Number.parseInt(digits[index] ?? \"\", 10);\n if (!Number.isFinite(value)) return false;\n if (double) { value *= 2; if (value > 9) value -= 9; }\n sum += value;\n double = !double;\n }\n return sum % 10 === 0;\n}\n\n/** Refuses generated values that look like real card numbers or personal identifiers; test prefixed card values stay allowed. */\nexport function generatedvalueallowed(value: string): policyevaluation {\n const compact = value.replace(/[\\s-]/g, \"\");\n if (/^\\d{13,19}$/.test(compact) && luhnvalid(compact) && !compact.startsWith(\"4111\")) return { allowed: false, reason: \"The generated value looks like a real card number and is refused; generated card values use the 4111 test prefix.\" };\n if (/^\\d{3}-\\d{2}-\\d{4}$/.test(value.trim())) return { allowed: false, reason: \"The generated value looks like a personal identifier and is refused.\" };\n return { allowed: true };\n}\n\n/** Requires the origin grants of a saved profile to cover the origin before its values fill a page. */\nexport function profilegrantgranted(profile: formprofile, origin: string): policyevaluation {\n if (!profile.grants.includes(origin)) return { allowed: false, reason: `The saved profile ${profile.name} is not granted to ${origin}; add the origin to the profile grants first.` };\n return { allowed: true };\n}\n\n/** Restricts group and layout mutations to the active session: they refuse without a live session. */\nexport function layoutmutationgranted(session: agentsession | undefined, now: number): policyevaluation {\n if (!session || session.stoppedat || session.expiresat <= now) return { allowed: false, reason: \"Group and layout mutations stay inside the active session.\" };\n return { allowed: true };\n}\n\n/** Requires explicit review before closing a window that holds more than one task tab. */\nexport function windowclosegate(tasktabcount: number, reviewed: boolean): policyevaluation {\n if (tasktabcount > 1 && !reviewed) return { allowed: false, reason: `The window holds ${tasktabcount} task tabs and needs explicit review before it closes.` };\n return { allowed: true };\n}\n\n/** Reads the user configured concurrent task tab ceiling; an absent value never refuses a tab. */\nexport function tasktabceiling(settings: runsettings | undefined): number | undefined {\n const ceiling = settings?.tasktabceiling;\n return typeof ceiling === \"number\" && Number.isFinite(ceiling) && ceiling >= 0 ? ceiling : undefined;\n}\n\n/** Parses the reviewed wait duration of a wait step with no upper bound. */\nexport function waitduration(step: toolstep): number {\n const requested = step.value ? Number.parseInt(step.value, 10) : 250;\n if (!Number.isFinite(requested) || requested < 0) throw new Error(\"Wait duration must be zero or a positive number of milliseconds.\");\n return requested;\n}\n\nfunction isnumericid(value: unknown): value is string {\n return typeof value === \"string\" && /^\\d+$/.test(value);\n}\n\nfunction numericoption(options: Record<string, unknown>, key: string): boolean {\n return options[key] === undefined || (typeof options[key] === \"number\" && Number.isFinite(options[key] as number));\n}\n\n/** True when an optional numeric option is absent or a finite number of zero or more. */\nfunction nonnegativeoption(options: Record<string, unknown>, key: string): boolean {\n return numericoption(options, key) && !(typeof options[key] === \"number\" && (options[key] as number) < 0);\n}\n\nfunction isnonempty(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction ispoint(value: unknown): boolean {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n const point = value as Record<string, unknown>;\n return typeof point.x === \"number\" && Number.isFinite(point.x) && typeof point.y === \"number\" && Number.isFinite(point.y);\n}\n\n/** Grades a resolution match count: zero is absent, one is resolved and more than one is refused as ambiguous. */\nexport function resolutionverdict(count: number): \"absent\" | \"resolved\" | \"ambiguous\" {\n if (!Number.isFinite(count) || count <= 0) return \"absent\";\n return count === 1 ? \"resolved\" : \"ambiguous\";\n}\n\n/** Validates the reviewed targetref grammar of every resolution mode and rejects empty references. */\nexport function validatetargetref(reference: unknown): policyevaluation {\n if (!reference || typeof reference !== \"object\" || Array.isArray(reference)) return { allowed: false, reason: \"The reviewed target reference must be an object.\" };\n const ref = reference as Record<string, unknown>;\n if (ref.mode === \"selector\") return isnonempty(ref.selector) ? { allowed: true } : { allowed: false, reason: \"The selector target reference needs a non-empty selector.\" };\n if (ref.mode === \"text\") return isnonempty(ref.text) ? { allowed: true } : { allowed: false, reason: \"The text target reference needs non-empty text.\" };\n if (ref.mode === \"aria\") {\n if (!isnonempty(ref.role)) return { allowed: false, reason: \"The aria target reference needs a non-empty role.\" };\n return isnonempty(ref.name) ? { allowed: true } : { allowed: false, reason: \"The aria target reference needs a non-empty name.\" };\n }\n if (ref.mode === \"name\") return isnonempty(ref.name) ? { allowed: true } : { allowed: false, reason: \"The name target reference needs a non-empty name.\" };\n if (ref.mode === \"xpath\") return isnonempty(ref.xpath) ? { allowed: true } : { allowed: false, reason: \"The xpath target reference needs a non-empty expression.\" };\n if (ref.mode === \"index\") {\n const index = ref.index;\n return typeof index === \"number\" && Number.isInteger(index) && index >= 1 ? { allowed: true } : { allowed: false, reason: \"The index target reference needs a positive integer map number.\" };\n }\n if (ref.mode === \"point\") {\n const pointok = typeof ref.x === \"number\" && Number.isFinite(ref.x) && typeof ref.y === \"number\" && Number.isFinite(ref.y);\n return pointok ? { allowed: true } : { allowed: false, reason: \"The point target reference needs numeric x and y coordinates.\" };\n }\n return { allowed: false, reason: \"The target reference mode must be selector, text, aria, name, xpath, index or point.\" };\n}\n\n/** True when the session origin grants cover the given origin; a session without grants only allows its own origin. */\nexport function origingranted(session: agentsession | undefined, origin: string): boolean {\n if (!session) return false;\n const grants = session.grants ?? [session.origin];\n return grants.includes(origin);\n}\n\n/** Decides whether an unreviewed origin may open: the session grants cover it or a safe checksafe verdict vouches for it. */\nexport function originverified(url: string, grants: string[], verdicts: safetyverdict[]): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed navigation URL is invalid.\" }; }\n if (grants.includes(origin)) return { allowed: true };\n const covered = verdicts.find(verdict => verdict.safe && (verdict.url === url || (safeorigin(verdict.url) === origin)));\n if (covered) return { allowed: true };\n return { allowed: false, reason: `The origin ${origin} is outside the session grants and has no safe checksafe verdict; run checksafe and review it first.` };\n}\n\nfunction safeorigin(url: string): string {\n try { return new URL(url).origin; } catch { return \"\"; }\n}\n\n/** Refuses navigation that would move a granted task tab outside the session origin grants until the user consents. */\nexport function navigationgranted(session: agentsession | undefined, url: string): policyevaluation {\n let origin = \"\";\n try { origin = new URL(url).origin; } catch { return { allowed: false, reason: \"The reviewed navigation URL is invalid.\" }; }\n if (origingranted(session, origin)) return { allowed: true };\n return { allowed: false, reason: `Navigation to ${origin} leaves the task tab origins and needs the user consent of a session grant first.` };\n}\n\n/** Validates the reviewed inner step of a retry or frame wrapper against the same rules as a top-level step. */\nfunction validateinnerstep(options: Record<string, unknown>, origin: string): policyevaluation {\n const stepid = options.stepid;\n const kind = options.kind;\n if (isnonempty(stepid)) {\n if (kind !== undefined) return { allowed: false, reason: \"The reviewed wrapper must reference a step id or an inline step, not both.\" };\n return { allowed: true };\n }\n if (typeof kind !== \"string\" || !kind.trim()) return { allowed: false, reason: \"A reviewed step id or inline step kind is required in options.\" };\n if (kind === \"retryaction\" || kind === \"enterframe\" || kind === \"looprows\") return { allowed: false, reason: \"The reviewed inner step cannot be another wrapper kind.\" };\n if (!allowedactions.has(kind as actionkind)) return { allowed: false, reason: \"The reviewed inner step kind is unsupported.\" };\n const inneroptions = options.options;\n if (inneroptions !== undefined && (!inneroptions || typeof inneroptions !== \"object\" || Array.isArray(inneroptions))) return { allowed: false, reason: \"The reviewed inner step options must be an object.\" };\n const inner: toolstep = {\n id: \"inner\",\n kind: kind as actionkind,\n summary: \"Reviewed inner step.\",\n risk: actionrisk(kind as actionkind),\n ...(isnonempty(options.target) ? { target: options.target } : {}),\n ...(isnonempty(options.value) ? { value: options.value } : {}),\n ...(inneroptions !== undefined ? { options: JSON.stringify(inneroptions) } : {}),\n };\n return validatestep(inner, origin);\n}\n\n/** True when a reviewed https url parses. */\nfunction ishttpsurl(value: unknown): value is string {\n if (typeof value !== \"string\" || !value.trim()) return false;\n try { return new URL(value).protocol === \"https:\"; } catch { return false; }\n}\n\n/** Validates the reviewed navtarget grammar of a navigation step. */\nfunction validatenavtarget(value: unknown, kind: string): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed navtarget with a url is required in options.\" };\n const target = value as Record<string, unknown>;\n if (!ishttpsurl(target.url)) return { allowed: false, reason: \"The reviewed navtarget url must use HTTPS.\" };\n const container = target.container ?? \"tab\";\n if (container !== \"current\" && container !== \"tab\" && container !== \"window\" && container !== \"private\") return { allowed: false, reason: \"The reviewed navtarget container must be current, tab, window or private.\" };\n if (target.position !== undefined && target.position !== \"adjacent\" && target.position !== \"end\") return { allowed: false, reason: \"The reviewed navtarget position must be adjacent or end.\" };\n if (kind === \"openprivate\" && container !== \"private\") return { allowed: false, reason: \"The openprivate step requires the private container.\" };\n if (kind === \"openlink\" && container === \"private\") return { allowed: false, reason: \"The openlink step cannot open the private container; use openprivate.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed waitprofile grammar with its load signals, thresholds and per origin overrides. */\nfunction validatewaitprofile(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed waitprofile with load signals is required in options.\" };\n const profile = value as Record<string, unknown>;\n if (!Array.isArray(profile.signals) || profile.signals.length === 0 || !profile.signals.every(signal => isnonempty(signal))) return { allowed: false, reason: \"The reviewed waitprofile needs a non-empty list of load signals.\" };\n if (!nonnegativeoption(profile, \"idle\")) return { allowed: false, reason: \"The reviewed waitprofile idle threshold must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(profile, \"timeout\")) return { allowed: false, reason: \"The reviewed waitprofile timeout must be zero or a positive number of milliseconds.\" };\n if (profile.overrides !== undefined) {\n if (!Array.isArray(profile.overrides) || profile.overrides.length === 0) return { allowed: false, reason: \"The reviewed waitprofile overrides must be a non-empty list when present.\" };\n for (const entry of profile.overrides) {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return { allowed: false, reason: \"Every reviewed waitprofile override must be an object with an origin.\" };\n const override = entry as Record<string, unknown>;\n if (!ishttpsurl(override.origin)) return { allowed: false, reason: \"Every reviewed waitprofile override origin must use HTTPS.\" };\n if (override.signals !== undefined && (!Array.isArray(override.signals) || !override.signals.every(signal => isnonempty(signal)))) return { allowed: false, reason: \"The reviewed waitprofile override signals must be a list of non-empty strings.\" };\n if (!nonnegativeoption(override, \"idle\") || !nonnegativeoption(override, \"timeout\")) return { allowed: false, reason: \"The reviewed waitprofile override thresholds must be zero or positive numbers.\" };\n }\n }\n return { allowed: true };\n}\n\n/** Validates the reviewed urlpattern grammar with its match mode plus query and fragment parts. */\nexport function validateurlpattern(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed urlpattern is required in options.\" };\n const pattern = value as Record<string, unknown>;\n if (pattern.mode !== \"exact\" && pattern.mode !== \"prefix\" && pattern.mode !== \"host\" && pattern.mode !== \"pattern\") return { allowed: false, reason: \"The reviewed urlpattern mode must be exact, prefix, host or pattern.\" };\n if (!ishttpsurl(pattern.url)) return { allowed: false, reason: \"The reviewed urlpattern url must use HTTPS.\" };\n if (pattern.query !== undefined) {\n if (!pattern.query || typeof pattern.query !== \"object\" || Array.isArray(pattern.query)) return { allowed: false, reason: \"The reviewed urlpattern query part must be an object of parameter names and values.\" };\n for (const item of Object.values(pattern.query)) if (typeof item !== \"string\") return { allowed: false, reason: \"The reviewed urlpattern query values must be strings.\" };\n }\n if (pattern.fragment !== undefined && !isnonempty(pattern.fragment)) return { allowed: false, reason: \"The reviewed urlpattern fragment must be a non-empty string.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed non-empty list of HTTPS urls in options. */\nfunction validateurllist(options: Record<string, unknown>, key: string): policyevaluation {\n const urls = options[key];\n if (!Array.isArray(urls) || urls.length === 0 || !urls.every(url => ishttpsurl(url))) return { allowed: false, reason: `A reviewed non-empty list of HTTPS urls is required in options as ${key}.` };\n return { allowed: true };\n}\n\n/** Validates the reviewed ratelimit grammar of a navrate step; the window and ceiling stay user configured with no hardcoded cap. */\nfunction validateratelimit(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed ratelimit with a window and a ceiling is required in options.\" };\n const limit = value as Record<string, unknown>;\n if (limit.domain !== undefined && !isnonempty(limit.domain)) return { allowed: false, reason: \"The reviewed ratelimit domain must be a non-empty string.\" };\n if (typeof limit.window !== \"number\" || !Number.isFinite(limit.window) || limit.window <= 0) return { allowed: false, reason: \"The reviewed ratelimit window must be a positive number of milliseconds with no code ceiling.\" };\n if (typeof limit.ceiling !== \"number\" || !Number.isInteger(limit.ceiling) || limit.ceiling < 1) return { allowed: false, reason: \"The reviewed ratelimit ceiling must be a positive integer with no code ceiling.\" };\n return { allowed: true };\n}\n\n/** Validates the reviewed tabquery grammar with url, title, id and pattern matchers; at least one matcher is required. */\nexport function validatetabquery(value: unknown): policyevaluation {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return { allowed: false, reason: \"A reviewed tabquery with at least one matcher is required in options.\" };\n const query = value as Record<string, unknown>;\n const hasmatcher = query.url !== undefined || query.title !== undefined || query.id !== undefined || query.pattern !== undefined;\n if (!hasmatcher) return { allowed: false, reason: \"The reviewed tabquery needs a url, title, id or pattern matcher.\" };\n if (query.url !== undefined && !isnonempty(query.url)) return { allowed: false, reason: \"The reviewed tabquery url matcher must be a non-empty string.\" };\n if (query.title !== undefined && !isnonempty(query.title)) return { allowed: false, reason: \"The reviewed tabquery title matcher must be a non-empty string.\" };\n if (query.pattern !== undefined && !isnonempty(query.pattern)) return { allowed: false, reason: \"The reviewed tabquery pattern matcher must be a non-empty string.\" };\n if (query.id !== undefined && (typeof query.id !== \"number\" || !Number.isInteger(query.id) || query.id < 0)) return { allowed: false, reason: \"The reviewed tabquery id matcher must be a non-negative integer tab id.\" };\n return { allowed: true };\n}\n\n/** Validates a reviewed group color choice against the Chromium tab group palette. */\nfunction validategroupcolor(value: unknown): boolean {\n return typeof value === \"string\" && (groupcolors as string[]).includes(value);\n}\n\n/** Validates a reviewed list of numeric browser ids in options. */\nfunction validateidlist(options: Record<string, unknown>, key: string): boolean {\n const ids = options[key];\n return Array.isArray(ids) && ids.length > 0 && ids.every(id => typeof id === \"number\" && Number.isInteger(id) && id >= 0);\n}\n\n/** Validates the reviewed tab and window parameter grammar of the tabs and windows command family. */\nfunction validatetabsgrammar(step: toolstep, options: Record<string, unknown>): policyevaluation {\n const kind = step.kind;\n if (kind === \"querytabs\" || kind === \"closepattern\") {\n const querycheck = validatetabquery(options.tabquery);\n if (!querycheck.allowed) return querycheck;\n if (kind === \"closepattern\" && options.reviewed !== true) return { allowed: false, reason: \"The close pattern needs the explicit reviewed flag before any tab closes.\" };\n }\n if (kind === \"duplicatetab\" || kind === \"pintab\" || kind === \"mutetab\" || kind === \"movetab\" || kind === \"movetabwindow\" || kind === \"badgetab\" || kind === \"attachmeta\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser tab id is required.\" };\n }\n if (kind === \"focuswindow\" || kind === \"maximizewindow\" || kind === \"minimizewindow\" || kind === \"restorewindow\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser window id is required.\" };\n }\n if (kind === \"pintab\" && typeof options.pinned !== \"boolean\") return { allowed: false, reason: \"A reviewed pinned flag is required in options.\" };\n if (kind === \"mutetab\" && typeof options.muted !== \"boolean\") return { allowed: false, reason: \"A reviewed muted flag is required in options.\" };\n if (kind === \"movetab\") {\n if (typeof options.index !== \"number\" || !Number.isInteger(options.index) || options.index < 0) return { allowed: false, reason: \"A reviewed non-negative target index is required in options.\" };\n }\n if (kind === \"movetabwindow\") {\n if (typeof options.windowid !== \"number\" || !Number.isInteger(options.windowid) || options.windowid < 0) return { allowed: false, reason: \"A reviewed target window id is required in options.\" };\n }\n if (kind === \"grouptabs\") {\n const group = options.group;\n if (!group || typeof group !== \"object\" || Array.isArray(group)) return { allowed: false, reason: \"A reviewed group with a name is required in options.\" };\n const spec = group as Record<string, unknown>;\n if (!isnonempty(spec.name)) return { allowed: false, reason: \"The reviewed group needs a non-empty name.\" };\n if (!validategroupcolor(spec.color)) return { allowed: false, reason: \"The reviewed group color must be a Chromium tab group color.\" };\n if (!validateidlist(spec, \"tabids\")) return { allowed: false, reason: \"The reviewed group needs a non-empty list of member tab ids.\" };\n }\n if (kind === \"colorgroup\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed group name is required in options.\" };\n if (!validategroupcolor(options.color)) return { allowed: false, reason: \"The reviewed group color must be a Chromium tab group color.\" };\n }\n if (kind === \"collapsegroup\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed group name is required in options.\" };\n if (typeof options.collapsed !== \"boolean\") return { allowed: false, reason: \"A reviewed collapsed flag is required in options.\" };\n }\n if (kind === \"discardtab\" || kind === \"reloadtabs\") {\n if (!isnumericid(step.value) && !validateidlist(options, \"tabs\")) return { allowed: false, reason: \"A numeric tab id or a reviewed list of tab ids is required.\" };\n }\n if (kind === \"zoomin\" || kind === \"zoomout\") {\n if (options.step !== undefined && (typeof options.step !== \"number\" || !Number.isFinite(options.step) || options.step <= 0)) return { allowed: false, reason: \"The reviewed zoom step must be a positive number with no code ceiling.\" };\n if (step.value !== undefined && step.value !== \"\" && !isnumericid(step.value)) return { allowed: false, reason: \"The reviewed zoom target must be a numeric tab id.\" };\n }\n if (kind === \"switchtab\") {\n if (options.direction !== \"next\" && options.direction !== \"previous\") return { allowed: false, reason: \"A reviewed switch direction of next or previous is required in options.\" };\n }\n if (kind === \"restorewindow\") {\n const bounds = options.bounds;\n if (bounds !== undefined) {\n if (!bounds || typeof bounds !== \"object\" || Array.isArray(bounds)) return { allowed: false, reason: \"The reviewed window bounds must be an object.\" };\n const shape = bounds as Record<string, unknown>;\n for (const field of [\"left\", \"top\", \"width\", \"height\"]) {\n if (typeof shape[field] !== \"number\" || !Number.isFinite(shape[field])) return { allowed: false, reason: \"The reviewed window bounds need numeric left, top, width and height.\" };\n }\n }\n }\n if (kind === \"scratchwindow\") {\n if (step.value !== undefined && step.value !== \"\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed scratch window url must use HTTPS.\" };\n }\n if (kind === \"incognitowindow\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS url is required to open an incognito window.\" };\n if (kind === \"restoretab\" && step.value !== undefined && step.value !== \"\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed restore url must use HTTPS.\" };\n if (kind === \"savelayout\" || kind === \"restorelayout\") {\n if (!isnonempty(options.name)) return { allowed: false, reason: \"A reviewed layout name is required in options.\" };\n }\n if (kind === \"badgetab\") {\n if (!isnonempty(options.label)) return { allowed: false, reason: \"A reviewed badge label is required in options.\" };\n if (options.taskid !== undefined && !isnonempty(options.taskid)) return { allowed: false, reason: \"The reviewed badge task id must be a non-empty string.\" };\n }\n if (kind === \"attachmeta\") {\n const labels = options.labels;\n const taskrefs = options.taskrefs;\n const haslabels = Array.isArray(labels) && labels.length > 0 && labels.every(label => isnonempty(label));\n const hastaskrefs = Array.isArray(taskrefs) && taskrefs.length > 0 && taskrefs.every(ref => isnonempty(ref));\n if (!haslabels && !hastaskrefs) return { allowed: false, reason: \"Reviewed labels or task refs are required in options to attach metadata.\" };\n if (options.provenance !== undefined && !isnonempty(options.provenance)) return { allowed: false, reason: \"The reviewed provenance must be a non-empty string.\" };\n }\n if (kind === \"reopenrun\" && !isnonempty(options.run)) return { allowed: false, reason: \"A reviewed run id is required in options to reopen its tabs.\" };\n return { allowed: true };\n}\n\n/** Validates a single proposal against the active tab origin and local policy. */\nexport function validatestep(step: toolstep, origin: string): policyevaluation {\n if (!allowedactions.has(step.kind)) return { allowed: false, reason: \"Unsupported action kind.\" };\n if (!step.summary.trim()) return { allowed: false, reason: \"A human-readable action summary is required.\" };\n let options: Record<string, unknown>;\n try { options = parseoptions(step); } catch { return { allowed: false, reason: \"Step options must be a JSON object.\" }; }\n const hastargetref = options.targetref !== undefined;\n if (targetactions.has(step.kind) && !step.target?.trim() && !hastargetref) return { allowed: false, reason: \"A page target is required.\" };\n if (valueactions.has(step.kind) && !step.value?.trim()) return { allowed: false, reason: \"A reviewed value is required.\" };\n if (step.kind === \"select\" && !step.value?.trim()) return { allowed: false, reason: \"A reviewed option value is required.\" };\n if (step.kind === \"navigate\" && !step.value) return { allowed: false, reason: \"A navigation URL is required.\" };\n if (hastargetref) {\n const reference = validatetargetref(options.targetref);\n if (!reference.allowed) return reference;\n }\n if (step.kind === \"wait\") {\n try { waitduration(step); } catch { return { allowed: false, reason: \"Wait duration must be zero or a positive number of milliseconds.\" }; }\n }\n if (step.kind === \"navigate\") {\n try {\n if (new URL(step.value ?? \"\").origin !== origin) return { allowed: false, reason: \"Navigation must remain within the approved origin.\" };\n } catch {\n return { allowed: false, reason: \"Navigation URL is invalid.\" };\n }\n }\n if (step.kind === \"tabcreate\" || step.kind === \"windowcreate\" || step.kind === \"downloadfile\") {\n try {\n const url = new URL(step.value ?? \"\");\n if (url.protocol !== \"https:\") return { allowed: false, reason: \"The reviewed URL must use HTTPS.\" };\n } catch {\n return { allowed: false, reason: \"The reviewed URL is invalid.\" };\n }\n }\n if (step.kind === \"tabactivate\" || step.kind === \"tabclose\" || step.kind === \"tabreload\" || step.kind === \"windowclose\" || step.kind === \"windowresize\") {\n if (!isnumericid(step.value)) return { allowed: false, reason: \"A numeric browser id is required.\" };\n }\n if (step.kind === \"zoomset\") {\n const zoom = Number(step.value);\n if (!Number.isFinite(zoom) || zoom <= 0) return { allowed: false, reason: \"The reviewed zoom must be a positive number.\" };\n }\n if (step.kind === \"setattribute\" || step.kind === \"writestorage\") {\n const keyname = step.kind === \"setattribute\" ? \"name\" : \"key\";\n if (typeof options[keyname] !== \"string\" || !(options[keyname] as string).trim()) return { allowed: false, reason: `A reviewed ${keyname} is required in options.` };\n if (typeof options.value !== \"string\") return { allowed: false, reason: \"A reviewed value is required in options.\" };\n }\n if (step.kind === \"windowresize\") {\n if (typeof options.width !== \"number\" || typeof options.height !== \"number\" || !Number.isFinite(options.width) || !Number.isFinite(options.height)) return { allowed: false, reason: \"Reviewed width and height numbers are required in options.\" };\n }\n if ((step.kind === \"scrollpage\" || step.kind === \"scrollby\") && (!numericoption(options, \"x\") || !numericoption(options, \"y\"))) return { allowed: false, reason: \"Scroll amounts must be numbers in options.\" };\n if (step.kind === \"waitfor\" && options.timeout !== undefined && (typeof options.timeout !== \"number\" || options.timeout < 0)) return { allowed: false, reason: \"The waitfor timeout must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"movepointer\") {\n const path = options.pointpath;\n if (!path || typeof path !== \"object\" || Array.isArray(path)) return { allowed: false, reason: \"A reviewed pointpath with start and end points is required in options.\" };\n const points = path as Record<string, unknown>;\n if (!ispoint(points.start) || !ispoint(points.end)) return { allowed: false, reason: \"The reviewed pointpath needs numeric start and end points.\" };\n if (points.waypoints !== undefined && (!Array.isArray(points.waypoints) || !points.waypoints.every(waypoint => ispoint(waypoint)))) return { allowed: false, reason: \"The reviewed pointpath waypoints must be numeric points.\" };\n if (!nonnegativeoption(points, \"duration\")) return { allowed: false, reason: \"The reviewed pointpath duration must be zero or a positive number of milliseconds.\" };\n const speed = options.speedprofile;\n if (speed !== undefined) {\n if (!speed || typeof speed !== \"object\" || Array.isArray(speed)) return { allowed: false, reason: \"The reviewed speed profile must be an object.\" };\n const profile = speed as Record<string, unknown>;\n if (profile.easing !== undefined && profile.easing !== \"linear\" && profile.easing !== \"easeinout\") return { allowed: false, reason: \"The reviewed easing must be linear or easeinout.\" };\n if (!nonnegativeoption(profile, \"peak\")) return { allowed: false, reason: \"The reviewed peak velocity must be zero or a positive number.\" };\n if (!nonnegativeoption(profile, \"jitter\")) return { allowed: false, reason: \"The reviewed jitter window must be zero or a positive number of milliseconds.\" };\n }\n }\n if (step.kind === \"clickpoint\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"point\")) return { allowed: false, reason: \"A reviewed point target reference is required in options.\" };\n if (step.kind === \"clicktext\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"text\")) return { allowed: false, reason: \"A reviewed text target reference is required in options.\" };\n if (step.kind === \"clickaria\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"aria\")) return { allowed: false, reason: \"A reviewed aria target reference is required in options.\" };\n if (step.kind === \"clickname\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"name\")) return { allowed: false, reason: \"A reviewed name target reference is required in options.\" };\n if (step.kind === \"resolvexpath\" && (!hastargetref || (options.targetref as Record<string, unknown>).mode !== \"xpath\")) return { allowed: false, reason: \"A reviewed xpath target reference is required in options.\" };\n if (step.kind === \"typetime\" && options.delay !== undefined && (typeof options.delay !== \"number\" || !Number.isFinite(options.delay) || options.delay < 0)) return { allowed: false, reason: \"The reviewed per keystroke delay must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"submitsearch\") {\n if (!isnonempty(options.results)) return { allowed: false, reason: \"A reviewed results region selector is required in options.\" };\n if (options.timeout !== undefined && (typeof options.timeout !== \"number\" || !Number.isFinite(options.timeout) || options.timeout < 0)) return { allowed: false, reason: \"The submitsearch timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"selectmulti\") {\n const values = options.values;\n if (!Array.isArray(values) || values.length === 0 || !values.every(value => isnonempty(value))) return { allowed: false, reason: \"A reviewed list of option values is required in options.\" };\n }\n if (step.kind === \"setslider\") {\n const slider = Number(step.value);\n if (!Number.isFinite(slider)) return { allowed: false, reason: \"The reviewed slider value must be a number.\" };\n }\n if (step.kind === \"setdate\" && !/^\\d{4}-\\d{2}-\\d{2}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed date must use the yyyy-mm-dd form.\" };\n if (step.kind === \"setcolor\" && !/^#[0-9a-fA-F]{6}$/.test(step.value ?? \"\")) return { allowed: false, reason: \"The reviewed color must use the #rrggbb form.\" };\n if (step.kind === \"keyhold\" && options.holdid !== undefined && !isnonempty(options.holdid)) return { allowed: false, reason: \"The reviewed hold id must be a non-empty string.\" };\n if (step.kind === \"dismissdialog\") {\n const accept = options.accept;\n const answer = options.answer;\n if (accept === undefined && !isnonempty(answer)) return { allowed: false, reason: \"A reviewed accept flag or prompt answer is required in options.\" };\n if (accept !== undefined && typeof accept !== \"boolean\") return { allowed: false, reason: \"The reviewed dialog accept flag must be a boolean.\" };\n if (answer !== undefined && !isnonempty(answer)) return { allowed: false, reason: \"The reviewed prompt answer must be a non-empty string.\" };\n }\n if (step.kind === \"pierceshadow\" && options.shadow !== undefined) {\n if (!Array.isArray(options.shadow) || !options.shadow.every(item => isnonempty(item))) return { allowed: false, reason: \"The reviewed shadow path must be a list of non-empty selectors.\" };\n }\n if (step.kind === \"enterframe\") {\n const path = options.framepath;\n if (!Array.isArray(path) || path.length === 0 || !path.every(item => typeof item === \"number\" && Number.isInteger(item) && item >= 0)) return { allowed: false, reason: \"A reviewed frame path of frame indexes is required in options.\" };\n return validateinnerstep(options, origin);\n }\n if (step.kind === \"retryaction\") {\n const inner = validateinnerstep(options, origin);\n if (!inner.allowed) return inner;\n const rule = options.retryrule;\n if (!rule || typeof rule !== \"object\" || Array.isArray(rule)) return { allowed: false, reason: \"A reviewed retry rule with attempts is required in options.\" };\n const retry = rule as Record<string, unknown>;\n if (typeof retry.attempts !== \"number\" || !Number.isInteger(retry.attempts) || retry.attempts < 1) return { allowed: false, reason: \"The reviewed retry attempts must be a positive integer with no code ceiling.\" };\n if (!nonnegativeoption(retry, \"settle\")) return { allowed: false, reason: \"The reviewed retry settle window must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(retry, \"tolerance\")) return { allowed: false, reason: \"The reviewed retry movement tolerance must be zero or a positive number of pixels.\" };\n }\n if (watchactions.has(step.kind)) {\n if (typeof options.lifetime !== \"number\" || !Number.isFinite(options.lifetime) || options.lifetime <= 0) return { allowed: false, reason: \"A reviewed watch lifetime window in milliseconds is required in options.\" };\n if (options.scopes !== undefined && (!Array.isArray(options.scopes) || !options.scopes.every(scope => isnonempty(scope)))) return { allowed: false, reason: \"The reviewed watch scopes must be a list of non-empty selectors.\" };\n if (options.events !== undefined && (!Array.isArray(options.events) || !options.events.every(event => isnonempty(event)))) return { allowed: false, reason: \"The reviewed watch event kinds must be a list of non-empty strings.\" };\n if (!nonnegativeoption(options, \"poll\")) return { allowed: false, reason: \"The reviewed watch poll interval must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"waitquiet\") {\n const rule = options.quietrule;\n if (!rule || typeof rule !== \"object\" || Array.isArray(rule)) return { allowed: false, reason: \"A reviewed quietrule with an idle threshold is required in options.\" };\n const quiet = rule as Record<string, unknown>;\n if (typeof quiet.idle !== \"number\" || !Number.isFinite(quiet.idle) || quiet.idle <= 0) return { allowed: false, reason: \"The reviewed quiet idle threshold must be a positive number of milliseconds with no code ceiling.\" };\n if (!nonnegativeoption(quiet, \"poll\")) return { allowed: false, reason: \"The reviewed quiet poll interval must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(quiet, \"timeout\")) return { allowed: false, reason: \"The reviewed quiet timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"diffsnapshots\") {\n const versions = options.versions;\n if (!Array.isArray(versions) || versions.length !== 2 || !versions.every(version => typeof version === \"number\" && Number.isInteger(version) && version >= 1)) return { allowed: false, reason: \"Two reviewed observation version numbers are required in options.\" };\n }\n if (step.kind === \"openlink\" || step.kind === \"openprivate\" || step.kind === \"deeplink\") {\n const targetcheck = validatenavtarget(options.navtarget, step.kind);\n if (!targetcheck.allowed) return targetcheck;\n if (step.kind === \"deeplink\") {\n const app = options.app;\n if (!isnonempty(app)) return { allowed: false, reason: \"A reviewed deep link app pattern is required in options.\" };\n const params = options.params;\n if (params !== undefined && (!params || typeof params !== \"object\" || Array.isArray(params) || !Object.values(params).every(item => typeof item === \"string\"))) return { allowed: false, reason: \"The reviewed deep link params must be an object of string values.\" };\n }\n }\n if (step.kind === \"waitload\" && !nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The waitload timeout must be zero or a positive number of milliseconds.\" };\n if (step.kind === \"waiturl\" || step.kind === \"spawait\") {\n if (step.kind === \"waiturl\") {\n const patterncheck = validateurlpattern(options.urlpattern);\n if (!patterncheck.allowed) return patterncheck;\n }\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The wait timeout must be zero or a positive number of milliseconds.\" };\n if (!nonnegativeoption(options, \"poll\")) return { allowed: false, reason: \"The wait poll interval must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"followlink\") {\n if (options.fragment !== undefined && typeof options.fragment !== \"boolean\") return { allowed: false, reason: \"The reviewed followlink fragment flag must be a boolean.\" };\n }\n if (step.kind === \"spanav\") {\n if (options.routepattern !== undefined) {\n const routecheck = validateurlpattern(options.routepattern);\n if (!routecheck.allowed) return routecheck;\n }\n if (!nonnegativeoption(options, \"timeout\")) return { allowed: false, reason: \"The spanav route timeout must be zero or a positive number of milliseconds.\" };\n }\n if (step.kind === \"rewritequery\") {\n const set = options.set;\n const remove = options.remove;\n if (set === undefined && remove === undefined) return { allowed: false, reason: \"Reviewed query parameters to set or remove are required in options.\" };\n if (set !== undefined && (!set || typeof set !== \"object\" || Array.isArray(set) || !Object.values(set).every(item => typeof item === \"string\"))) return { allowed: false, reason: \"The reviewed query parameters to set must be an object of string values.\" };\n if (remove !== undefined && (!Array.isArray(remove) || !remove.every(item => isnonempty(item)))) return { allowed: false, reason: \"The reviewed query parameters to remove must be a list of non-empty names.\" };\n }\n if (step.kind === \"navlist\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (step.kind === \"navprofile\") {\n const profilecheck = validatewaitprofile(options.waitprofile);\n if (!profilecheck.allowed) return profilecheck;\n }\n if (step.kind === \"handleauth\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS origin or url is required as the auth target.\" };\n if (step.kind === \"printpdf\" && options.name !== undefined && !isnonempty(options.name)) return { allowed: false, reason: \"The reviewed artifact name must be a non-empty string.\" };\n if (step.kind === \"prefetch\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (step.kind === \"preconnect\") {\n const origins = options.origins;\n if (!Array.isArray(origins) || origins.length === 0 || !origins.every(originurl => ishttpsurl(originurl))) return { allowed: false, reason: \"A reviewed non-empty list of HTTPS origins is required in options.\" };\n }\n if (step.kind === \"reopentab\" && step.value !== undefined && !ishttpsurl(step.value)) return { allowed: false, reason: \"The reviewed reopen url must use HTTPS.\" };\n if (step.kind === \"navrate\") {\n const limitcheck = validateratelimit(options.ratelimit);\n if (!limitcheck.allowed) return limitcheck;\n }\n if (step.kind === \"checksafe\" && !ishttpsurl(step.value)) return { allowed: false, reason: \"A reviewed HTTPS url is required for the safety check.\" };\n if (step.kind === \"batchopen\") {\n const listcheck = validateurllist(options, \"urls\");\n if (!listcheck.allowed) return listcheck;\n }\n if (istabscommandkind(step.kind)) {\n const tabscheck = validatetabsgrammar(step, options);\n if (!tabscheck.allowed) return tabscheck;\n }\n if (isformkind(step.kind)) {\n const formcheck = validateformgrammar(step, options);\n if (!formcheck.allowed) return formcheck;\n }\n if (isdatasetkind(step.kind)) {\n const datacheck = validatedatagrammar(step, options, origin);\n if (!datacheck.allowed) return datacheck;\n }\n if (isfileskind(step.kind)) {\n const filescheck = validatefilesgrammar(step, options);\n if (!filescheck.allowed) return filescheck;\n }\n if (iscapturekind(step.kind)) {\n const capturecheck = validatecapturegrammar(step, options);\n if (!capturecheck.allowed) return capturecheck;\n }\n if (step.kind === \"tabcreate\") {\n if (options.background !== undefined && typeof options.background !== \"boolean\") return { allowed: false, reason: \"The reviewed background flag must be a boolean.\" };\n if (options.window !== undefined && (typeof options.window !== \"number\" || !Number.isInteger(options.window) || options.window < 0)) return { allowed: false, reason: \"The reviewed target window id must be a non-negative integer.\" };\n }\n if (step.kind === \"windowcreate\") {\n for (const field of [\"left\", \"top\", \"width\", \"height\"]) {\n if (options[field] !== undefined && (typeof options[field] !== \"number\" || !Number.isFinite(options[field]))) return { allowed: false, reason: `The reviewed window ${field} must be a number.` };\n }\n if (options.state !== undefined && ![\"normal\", \"maximized\", \"minimized\", \"fullscreen\"].includes(options.state as string)) return { allowed: false, reason: \"The reviewed window state must be normal, maximized, minimized or fullscreen.\" };\n }\n return { allowed: true };\n}\n\n/** Shared session gate: a live, unpaused session that still matches the active tab. */\nfunction sessiongate(input: { session: agentsession | undefined; tabid: number; origin: string; now: number; action: string }): policyevaluation {\n if (!input.session || input.session.stoppedat) return { allowed: false, reason: \"No active browser session exists.\" };\n if (input.session.expiresat <= input.now) return { allowed: false, reason: \"The browser session has expired.\" };\n if (input.session.pausedat) return { allowed: false, reason: `The browser session is paused and cannot ${input.action}.` };\n if (input.session.tabid !== input.tabid || input.session.origin !== input.origin) return { allowed: false, reason: `The ${input.action} is outside the approved tab or origin.` };\n return { allowed: true };\n}\n\n/** Applies the consent gate immediately before an action reaches the page bridge. */\nexport function canexecute(input: { session: agentsession | undefined; plan: agentplan | undefined; step: toolstep; tabid: number; origin: string; now?: number; verdicts?: safetyverdict[] }): policyevaluation {\n const now = input.now ?? Date.now();\n const gate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now, action: \"execute an action\" });\n if (!gate.allowed) return gate;\n if (!input.plan || input.plan.state !== \"approved\") return { allowed: false, reason: \"The plan has not received explicit approval.\" };\n if (input.plan.expiresat <= now) return { allowed: false, reason: \"The approved plan has expired.\" };\n if ((input.step.kind === \"pierceshadow\" || input.step.kind === \"enterframe\") && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The shadow or frame step is outside the session origin grants.\" };\n if (input.step.kind === \"readjson\" && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The json state read is outside the session origin grants.\" };\n if (isexportkind(input.step.kind)) {\n const exportgate = exportgranted(input.session, input.origin);\n if (!exportgate.allowed) return exportgate;\n }\n if (input.step.kind === \"navlist\") {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n for (const url of Array.isArray(options.urls) ? options.urls : []) {\n if (typeof url !== \"string\") continue;\n const navigation = navigationgranted(input.session, url);\n if (!navigation.allowed) return navigation;\n }\n }\n if (islayoutkind(input.step.kind) && !layoutmutationgranted(input.session, now).allowed) return { allowed: false, reason: \"Group and layout mutations stay inside the active session.\" };\n if (input.step.kind === \"submitform\" || input.step.kind === \"retryform\") {\n if (!input.plan) return { allowed: false, reason: \"Form submission requires an asksubmit review step before it.\" };\n const reviewgate = submitreviewgranted(input.plan.steps, input.step.id);\n if (!reviewgate.allowed) return reviewgate;\n }\n if (input.step.kind === \"consentpassword\") {\n const consentgate = passwordconsentgranted(input.step);\n if (!consentgate.allowed) return consentgate;\n }\n if (input.step.kind === \"readclipboard\") {\n const clipgate = clipboardconsentgranted(input.step);\n if (!clipgate.allowed) return clipgate;\n }\n if (input.step.kind === \"interceptmime\" && !origingranted(input.session, input.origin)) return { allowed: false, reason: \"The download interception is outside the session origin grants.\" };\n if (iscapturekind(input.step.kind)) {\n const capturegatecheck = capturegate(input.session, input.tabid, input.origin, now);\n if (!capturegatecheck.allowed) return capturegatecheck;\n let captureoptions: Record<string, unknown> = {};\n try { captureoptions = parseoptions(input.step); } catch { captureoptions = {}; }\n const target = (captureoptions.capture as Record<string, unknown> | undefined)?.exporttarget;\n if (target !== undefined && target !== \"memory\" && target !== \"download\" && target !== \"clipboard\") return { allowed: false, reason: \"The capture export target must be memory, download or clipboard.\" };\n }\n if (input.step.kind === \"openlink\" || input.step.kind === \"openprivate\" || input.step.kind === \"batchopen\" || input.step.kind === \"prefetch\" || input.step.kind === \"deeplink\" || input.step.kind === \"reopentab\") {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n const grammar = validatestep(input.step, input.origin);\n if (!grammar.allowed) return grammar;\n const grants = input.session?.grants ?? [input.session?.origin ?? input.origin];\n const targets: unknown[] = input.step.kind === \"batchopen\" || input.step.kind === \"prefetch\" ? (Array.isArray(options.urls) ? options.urls : []) : input.step.kind === \"reopentab\" ? [input.step.value] : [(options.navtarget as Record<string, unknown> | undefined)?.url];\n for (const target of targets) {\n if (typeof target !== \"string\" || !target) continue;\n const verified = originverified(target, grants, input.verdicts ?? []);\n if (!verified.allowed) return verified;\n }\n }\n return validatestep(input.step, input.origin);\n}\n\n/** Allows a non-mutating, temporary target preview during plan review. */\nexport function canpreview(input: { session: agentsession | undefined; plan: agentplan | undefined; step: toolstep; tabid: number; origin: string; now?: number }): policyevaluation {\n const now = input.now ?? Date.now();\n const gate = sessiongate({ session: input.session, tabid: input.tabid, origin: input.origin, now, action: \"preview a target\" });\n if (!gate.allowed) return gate;\n if (!input.plan || ![\"pending\", \"approved\"].includes(input.plan.state)) return { allowed: false, reason: \"Only a reviewed pending or approved plan can be previewed.\" };\n if (input.plan.expiresat <= now) return { allowed: false, reason: \"The reviewed plan has expired.\" };\n let options: Record<string, unknown> = {};\n try { options = parseoptions(input.step); } catch { options = {}; }\n if (!targetactions.has(input.step.kind) && options.targetref === undefined) return { allowed: false, reason: \"Only a target-based action can be previewed.\" };\n return validatestep(input.step, input.origin);\n}\n", "import type { tabgrouprecord, tablayout, tabquery, tabwatchevent, toolstep } from \"../types.js\";\nimport { parseoptions } from \"../policy.js\";\nimport { assigntasktab, tasktabs } from \"../progress.js\";\nimport type { planprogress } from \"../types.js\";\n\n/**\n * Tabs and windows command logics for reviewed steps.\n * Every correlated rule for tab queries, clone detection, group membership, layouts, snapshots, watchers, badges, discard candidates, switcher order, zoom steps and the task tab budget lives in this file.\n */\n\n/** One serializable live tab shape resolved against the browser tab set. */\nexport interface tabshape {\n tabid: number;\n url: string;\n title: string;\n index: number;\n windowid: number;\n active: boolean;\n pinned: boolean;\n audible: boolean;\n muted: boolean;\n discarded: boolean;\n}\n\n/** One serializable live window shape with bounds, state and profile kind. */\nexport interface windowshape {\n windowid: number;\n left: number;\n top: number;\n width: number;\n height: number;\n state: \"normal\" | \"maximized\" | \"minimized\" | \"fullscreen\";\n incognito: boolean;\n focused: boolean;\n}\n\n/** Reads the reviewed tabquery of a tabs and windows command step; null when the step reviews none. */\nexport function parsetabquery(step: toolstep): tabquery | null {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const value = options.tabquery;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const query = value as Record<string, unknown>;\n return {\n ...(typeof query.url === \"string\" && query.url ? { url: query.url } : {}),\n ...(typeof query.title === \"string\" && query.title ? { title: query.title } : {}),\n ...(typeof query.id === \"number\" && Number.isInteger(query.id) && query.id >= 0 ? { id: query.id } : {}),\n ...(typeof query.pattern === \"string\" && query.pattern ? { pattern: query.pattern } : {}),\n };\n}\n\n/** Matches one reviewed wildcard pattern against a url; `*` spans one path segment and `**` spans any part. */\nexport function tabpatternmatches(pattern: string, url: string): boolean {\n const source = pattern.split(\"**\").map(part => part.split(\"*\").map(piece => piece.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\"[^/]*\")).join(\".*\");\n return new RegExp(`^${source}$`).test(url);\n}\n\n/** Resolves one reviewed tabquery against the live tab set: every matcher that exists must hold. */\nexport function querymatches(query: tabquery, tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => {\n if (query.id !== undefined && tab.tabid !== query.id) return false;\n if (query.url !== undefined && tab.url !== query.url) return false;\n if (query.title !== undefined && !tab.title.toLowerCase().includes(query.title.toLowerCase())) return false;\n if (query.pattern !== undefined && !tabpatternmatches(query.pattern, tab.url)) return false;\n return true;\n });\n}\n\n/** Normalizes one url for clone comparison by dropping the fragment and trailing slashes. */\nexport function normalizedtaburl(url: string): string {\n let normalized = url;\n const hash = normalized.indexOf(\"#\");\n if (hash >= 0) normalized = normalized.slice(0, hash);\n while (normalized.length > 1 && normalized.endsWith(\"/\")) normalized = normalized.slice(0, -1);\n return normalized;\n}\n\n/** One clone warning: a normalized url shared by more than one open tab. */\nexport interface clonewarning {\n url: string;\n tabids: number[];\n}\n\n/** Detects duplicate tabs by normalized url comparison and returns every url held by more than one tab. */\nexport function clonetabs(tabs: tabshape[]): clonewarning[] {\n const groups = new Map<string, number[]>();\n for (const tab of tabs) {\n if (!tab.url) continue;\n const key = normalizedtaburl(tab.url);\n groups.set(key, [...(groups.get(key) ?? []), tab.tabid]);\n }\n return [...groups.entries()].filter(([, tabids]) => tabids.length > 1).map(([url, tabids]) => ({ url, tabids }));\n}\n\n/** Searches across open tabs by title and url, case insensitive, returning matches in live order. */\nexport function searchtabmatches(tabs: tabshape[], text: string): tabshape[] {\n const needle = text.trim().toLowerCase();\n if (!needle) return [];\n return tabs.filter(tab => tab.title.toLowerCase().includes(needle) || tab.url.toLowerCase().includes(needle));\n}\n\n/** Lists the tabs that are playing audio: audible or muted but still playing. */\nexport function audiotabs(tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => tab.audible || (tab.muted && tab.audible));\n}\n\n/** Returns the inactive, unpinned and not yet discarded tabs a discardtab step may release. */\nexport function discardcandidates(tabs: tabshape[]): tabshape[] {\n return tabs.filter(tab => !tab.active && !tab.pinned && !tab.discarded && tab.url.length > 0);\n}\n\n/** Restores discarded tabs on demand without losing their urls; every discarded tab keeps its url for reload. */\nexport function restorediscarded(tabs: tabshape[]): Array<{ tabid: number; url: string }> {\n return tabs.filter(tab => tab.discarded && tab.url.length > 0).map(tab => ({ tabid: tab.tabid, url: tab.url }));\n}\n\n/** Captures one tab layout with name, tabs, groups, positions and window bounds from the live browser state. */\nexport function buildlayout(name: string, tabs: tabshape[], windows: windowshape[], groups: tabgrouprecord[], scratchwindowids: number[], at: number): tablayout {\n return {\n name,\n tabs: tabs.map(tab => ({ url: tab.url, title: tab.title, pinned: tab.pinned, index: tab.index, windowid: tab.windowid })),\n groups: groups.map(group => ({ name: group.name, color: group.color, tabids: group.tabids.filter(tabid => tabs.some(tab => tab.tabid === tabid)), collapsed: group.collapsed })),\n windows: windows.map(item => ({ windowid: item.windowid, state: { bounds: { left: item.left, top: item.top, width: item.width, height: item.height }, maximized: item.state === \"maximized\", profile: item.incognito ? \"incognito\" : scratchwindowids.includes(item.windowid) ? \"scratch\" : \"normal\" } })),\n savedat: at,\n };\n}\n\n/** Plans the restore of one saved layout: only urls that are not already open come back, in layout order. */\nexport function layoutrestoreplan(layout: tablayout, openurls: string[]): string[] {\n const open = new Set(openurls.map(url => normalizedtaburl(url)));\n return layout.tabs.map(tab => tab.url).filter(url => url.length > 0 && !open.has(normalizedtaburl(url)));\n}\n\n/** Keeps tabgroup membership through moves: member ids survive, their order follows the live tab order and closed members drop out. */\nexport function regroupaftermoves(groups: tabgrouprecord[], tabs: tabshape[], at: number): tabgrouprecord[] {\n const order = new Map(tabs.map(tab => [tab.tabid, tab.index]));\n return groups.map(group => {\n const members = group.tabids.filter(tabid => order.has(tabid));\n if (members.length === 0) return group;\n const ordered = [...members].sort((left, right) => (order.get(left) ?? 0) - (order.get(right) ?? 0));\n return ordered.length === group.tabids.length && ordered.every((tabid, index) => tabid === group.tabids[index]) ? group : { ...group, tabids: ordered, savedat: at };\n });\n}\n\n/** Renames one stored tab group while keeping its color choice, member tabs and collapse state. */\nexport function renamegroup(groups: tabgrouprecord[], name: string, newname: string, at: number): tabgrouprecord[] {\n return groups.map(group => group.name === name ? { ...group, name: newname, savedat: at } : group);\n}\n\n/** Counts the task tabs that live inside one window so the close gate can demand review. */\nexport function tasktabsinwindow(tabs: tabshape[], windowid: number, tasktabids: number[]): number {\n const tasks = new Set(tasktabids);\n return tabs.filter(tab => tab.windowid === windowid && tasks.has(tab.tabid)).length;\n}\n\n/** Selects the tabs a reviewed closepattern may close; the session tab itself is always refused protection. */\nexport function closeselection(query: tabquery, tabs: tabshape[], sessiontabid: number): { targets: tabshape[]; refused: tabshape[] } {\n const matches = querymatches(query, tabs);\n return {\n targets: matches.filter(tab => tab.tabid !== sessiontabid),\n refused: matches.filter(tab => tab.tabid === sessiontabid),\n };\n}\n\n/** Applies one reviewed zoom step with no code ceiling; a step never crosses zero, so it keeps the current zoom instead. */\nexport function zoomstep(current: number, direction: \"in\" | \"out\", step: number): number {\n const next = direction === \"in\" ? current + step : current - step;\n return next > 0 ? Number(next.toFixed(4)) : current;\n}\n\n/** Resolves the neighbor tab index a switchtab step activates, wrapping at both ends of the window. */\nexport function switchtarget(tabs: tabshape[], direction: \"next\" | \"previous\", currentindex: number): number | undefined {\n if (tabs.length === 0) return undefined;\n const offset = direction === \"next\" ? 1 : -1;\n return (currentindex + offset + tabs.length) % tabs.length;\n}\n\n/** Orders the quick switcher list by recency with filter keys; unseen tabs follow in live index order. */\nexport function switcherlist(tabs: tabshape[], recency: Array<{ tabid: number; at: number }>, filter: string): tabshape[] {\n const needle = filter.trim().toLowerCase();\n const matches = needle ? tabs.filter(tab => tab.title.toLowerCase().includes(needle) || tab.url.toLowerCase().includes(needle)) : [...tabs];\n const lastrun = new Map(recency.map(entry => [entry.tabid, entry.at]));\n return [...matches].sort((left, right) => {\n const leftat = lastrun.get(left.tabid) ?? -1;\n const rightat = lastrun.get(right.tabid) ?? -1;\n if (leftat !== rightat) return rightat - leftat;\n return left.index - right.index;\n });\n}\n\n/** Dispatches the tab events of one watchtab registration into the step result, honoring the reviewed event filters. */\nexport function watchtabdispatch(events: tabwatchevent[], watchid: string, filters: string[]): tabwatchevent[] {\n const allowed = filters.length > 0 ? new Set(filters) : undefined;\n return events.filter(event => event.watchid === watchid && (allowed === undefined || allowed.has(event.event)));\n}\n\n/** Computes the per task badge from the live progress state of the task. */\nexport function badgefromprogress(completed: number, total: number): { label: string; done: boolean } {\n if (total <= 0) return { label: \"idle\", done: false };\n if (completed >= total) return { label: \"done\", done: true };\n return { label: `${completed}/${total}`, done: false };\n}\n\n/** Grades the concurrent task tab budget: a user configured ceiling refuses, an absent ceiling never refuses. */\nexport function tasktabgauge(used: number, ceiling: number | undefined): { used: number; ceiling: number | undefined; over: boolean } {\n return { used, ceiling, over: ceiling !== undefined && used > ceiling };\n}\n\n/** True when a window profile inherits the session origin grants; incognito windows stay separated. */\nexport function windowprofilegrants(profile: \"normal\" | \"incognito\" | \"scratch\"): boolean {\n return profile !== \"incognito\";\n}\n\n/** Assigns every task tab of the plan progress, used when tabmeta routing records a tab for the plan steps. */\nexport function assigntasktabs(progress: planprogress | undefined, planid: string, tabids: number[], now: number): planprogress {\n let next = progress;\n for (const tabid of tabids) next = assigntasktab(next, planid, tabid, now);\n return next ?? { planid, completedsteps: [], tasktabs: [], updatedat: now };\n}\n\n/** Returns the task tabs tracked by one plan progress, used for window close review and badge refresh. */\nexport function trackedtasktabs(progress: planprogress | undefined, planid: string): number[] {\n return tasktabs(progress, planid);\n}\n", "import type { fielderror, fieldkind, fieldmatch, formrecord, formentry, formreport, toolstep } from \"../types.js\";\nimport { parseoptions } from \"../policy.js\";\nimport type { stepresult } from \"./pageactions.js\";\nimport { clean, elementlabel as label, elementselector as selector } from \"./pageresolve.js\";\n\n/**\n * Form field logics for reviewed steps.\n * Every correlated rule for field matching, field kind classification, seeded value generation, native value fills, honeypot detection, login and template detection, error association and form record parsing lives in this file.\n */\n\n/** One serializable form field shape resolved against the page controls. */\nexport interface fieldshape {\n selector: string;\n tag: string;\n type: string;\n name: string;\n label: string;\n placeholder: string;\n arialabel: string;\n autocomplete: string;\n options?: string[];\n}\n\n/** One surveyed field shape carrying the visibility, geometry and timing evidence the honeypot detector reads. */\nexport interface fieldsurvey extends fieldshape {\n hidden: boolean;\n offscreen: boolean;\n createdat?: number;\n}\n\n/** One honeypot field flagged by hidden, offscreen or time trap evidence. */\nexport interface honeypotevidence {\n selector: string;\n reason: \"hidden\" | \"offscreen\" | \"timetrap\";\n}\n\n/** One surveyed field with the aria describedby ref and the sibling message texts the error reader associates. */\nexport interface errorcontext extends fieldshape {\n describedby?: string;\n siblings: string[];\n}\n\n/** Resolves controls by label, placeholder, aria label and name attributes; matches are case insensitive substrings. */\nexport function matchfield(fields: fieldshape[], match: fieldmatch): fieldshape[] {\n const key = match.mode === \"label\" ? \"label\" : match.mode === \"placeholder\" ? \"placeholder\" : match.mode === \"arialabel\" ? \"arialabel\" : \"name\";\n const needle = (match[key] ?? \"\").trim().toLowerCase();\n if (!needle) return [];\n return fields.filter(field => {\n const primary = (field[key] as string).toLowerCase();\n const secondary = match.mode === \"label\" || match.mode === \"name\" ? field.name.toLowerCase() : match.mode === \"placeholder\" ? field.arialabel.toLowerCase() : field.placeholder.toLowerCase();\n return primary.includes(needle) || secondary.includes(needle);\n });\n}\n\n/** Infers the field kind of one control from its input type, autocomplete hint and label text. */\nexport function classifyfield(input: { type: string; autocomplete: string; label: string }): fieldkind {\n const type = input.type.toLowerCase();\n const autocomplete = input.autocomplete.toLowerCase();\n const label = input.label.toLowerCase();\n if (type === \"password\") return \"password\";\n if (autocomplete.startsWith(\"cc-\") || label.includes(\"card number\") || label.includes(\"credit card\") || label.includes(\"cardholder\")) return \"card\";\n if (autocomplete.includes(\"one-time-code\") || autocomplete.includes(\"otp\") || label.includes(\"one time code\") || label.includes(\"verification code\") || label.includes(\"otp\")) return \"code\";\n if (type === \"email\" || autocomplete.includes(\"email\") || label.includes(\"email\")) return \"email\";\n if (type === \"tel\" || autocomplete.includes(\"tel\") || label.includes(\"phone\") || label.includes(\"telephone\")) return \"phone\";\n if (type === \"date\") return \"date\";\n if (type === \"number\") return \"number\";\n if (type === \"checkbox\") return \"check\";\n if (type === \"radio\") return \"radio\";\n if (type === \"file\") return \"file\";\n if (type === \"select\" || type === \"select-one\") return \"select\";\n return \"text\";\n}\n\nconst firstnames: Record<string, string[]> = { en: [\"alex\", \"jordan\", \"taylor\", \"morgan\", \"casey\"], pt: [\"ana\", \"bruno\", \"carla\", \"diego\", \"helena\"] };\nconst lastnames: Record<string, string[]> = { en: [\"brooks\", \"carter\", \"diaz\", \"evans\", \"reyes\"], pt: [\"alves\", \"costa\", \"lima\", \"souza\", \"moraes\"] };\n\nfunction localekey(locale: string): string {\n const normalized = locale.toLowerCase();\n if (normalized.startsWith(\"pt\")) return \"pt\";\n return \"en\";\n}\n\n/** Generates one realistic value for a field kind, deterministically seeded and locale aware for names, emails and phones. */\nexport function generatevalue(kind: fieldkind, rule: { locale?: string; seed?: number }): string {\n const seed = typeof rule.seed === \"number\" && Number.isFinite(rule.seed) ? Math.abs(Math.floor(rule.seed)) : 1;\n const names = firstnames[localekey(rule.locale ?? \"en\")] ?? firstnames.en ?? [\"alex\"];\n const surnames = lastnames[localekey(rule.locale ?? \"en\")] ?? lastnames.en ?? [\"brooks\"];\n let state = seed * 1103515245 + 12345;\n const next = (): number => { state = (state * 1103515245 + 12345) % 2147483648; return state / 2147483648; };\n const pick = <T>(items: T[]): T => items[Math.floor(next() * items.length) % items.length] ?? items[0] as T;\n const digits = (count: number): string => Array.from({ length: count }, () => String(Math.floor(next() * 10))).join(\"\");\n const person = `${pick(names)} ${pick(surnames)}`;\n switch (kind) {\n case \"email\": return `${person.replace(\" \", \".\")}${digits(2)}@example.com`;\n case \"phone\": return localekey(rule.locale ?? \"en\") === \"pt\" ? `+55 (11) 9${digits(4)}-${digits(4)}` : `+1 (555) 010-${digits(4)}`;\n case \"date\": return `${2024 + Math.floor(next() * 2)}-${String(1 + Math.floor(next() * 12)).padStart(2, \"0\")}-${String(1 + Math.floor(next() * 28)).padStart(2, \"0\")}`;\n case \"number\": return String(Math.floor(next() * 1000));\n case \"select\": return `option ${1 + Math.floor(next() * 5)}`;\n case \"check\": return next() > 0.5 ? \"true\" : \"false\";\n case \"radio\": return `choice ${1 + Math.floor(next() * 4)}`;\n case \"file\": return `sample${digits(2)}.pdf`;\n case \"password\": return `pw-${digits(6)}-${pick(names)}`;\n case \"card\": return `4111 ${digits(4)} ${digits(4)} ${digits(4)}`;\n case \"code\": return digits(6);\n default: return person;\n }\n}\n\n/** Builds a deterministic values hash of the reviewed field values a submission ticket records. */\nexport function valueshash(values: Array<{ label: string; value: string }>): string {\n const source = values.map(entry => `${entry.label}=${entry.value}`).join(\"|\");\n let hash = 5381;\n for (let index = 0; index < source.length; index += 1) hash = ((hash * 33) ^ source.charCodeAt(index)) >>> 0;\n return hash.toString(16);\n}\n\n/** Parses the reviewed structured form record of a step; null when the step reviews none or the shape is invalid. */\nexport function parseformrecord(value: unknown): formrecord | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const record = value as Record<string, unknown>;\n if (!Array.isArray(record.entries)) return null;\n const entries: formentry[] = [];\n for (const item of record.entries) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const entry = item as Record<string, unknown>;\n const match = entry.match;\n if (!match || typeof match !== \"object\" || Array.isArray(match)) continue;\n const shapes = match as Record<string, unknown>;\n if (typeof shapes.mode !== \"string\") continue;\n const fieldmatch: fieldmatch = {\n mode: shapes.mode as fieldmatch[\"mode\"],\n ...(typeof shapes.label === \"string\" ? { label: shapes.label } : {}),\n ...(typeof shapes.placeholder === \"string\" ? { placeholder: shapes.placeholder } : {}),\n ...(typeof shapes.arialabel === \"string\" ? { arialabel: shapes.arialabel } : {}),\n ...(typeof shapes.name === \"string\" ? { name: shapes.name } : {}),\n };\n if (typeof entry.kind !== \"string\" || typeof entry.value !== \"string\") continue;\n entries.push({ match: fieldmatch, kind: entry.kind as fieldkind, value: entry.value });\n }\n if (entries.length === 0) return null;\n return { ...(typeof record.form === \"string\" && record.form ? { form: record.form } : {}), entries };\n}\n\n/** Builds form record entries from reviewed label or placeholder value pairs. */\nexport function pairentries(pairs: Array<{ label?: string; placeholder?: string; value: string }>, mode: \"label\" | \"placeholder\"): formrecord {\n return { entries: pairs.map(pair => ({ match: mode === \"label\" ? { mode, label: pair.label ?? \"\" } : { mode, placeholder: pair.placeholder ?? \"\" }, kind: \"text\", value: pair.value })) };\n}\n\n/** One fill operation outcome: the entry, the matched control, the honeypot skip flag or the refusal reason. */\nexport interface filloutcome {\n entry: formentry;\n matched?: fieldshape;\n skipped?: boolean;\n reason?: string;\n}\n\n/** Resolves every entry of a form record against the surveyed fields, skipping honeypots and refusing unmatched or ambiguous entries. */\nexport function filloperations(record: formrecord, fields: fieldshape[], skippedselectors: string[] = []): filloutcome[] {\n return record.entries.map(entry => {\n const matches = matchfield(fields, entry.match);\n if (matches.length === 0) return { entry, reason: \"unmatched\" };\n if (matches.length > 1) return { entry, reason: \"ambiguous\" };\n const matched = matches[0] as fieldshape;\n if (skippedselectors.includes(matched.selector)) return { entry, matched, skipped: true };\n return { entry, matched };\n });\n}\n\n/** Masks one card segment so side panels can render card fills without exposing the full value. */\nexport function cardmask(value: string): string {\n const trimmed = value.trim();\n if (/^\\d[\\d\\s-]{11,18}$/.test(trimmed)) {\n const compact = trimmed.replace(/[\\s-]/g, \"\");\n const last = compact.slice(-4);\n return `${\"\u2022\".repeat(Math.max(0, compact.length - 4))}${last}`;\n }\n return \"\u2022\".repeat(trimmed.length);\n}\n\n/** Flags hidden, offscreen and time trap fields so fill steps skip them instead of tripping anti bot defenses. */\nexport function detecthoneypots(surveys: fieldsurvey[], loadedat: number): honeypotevidence[] {\n const traps: honeypotevidence[] = [];\n for (const field of surveys) {\n if (field.hidden) traps.push({ selector: field.selector, reason: \"hidden\" });\n else if (field.offscreen) traps.push({ selector: field.selector, reason: \"offscreen\" });\n else if (field.createdat !== undefined && loadedat > 0 && field.createdat > loadedat) traps.push({ selector: field.selector, reason: \"timetrap\" });\n }\n return traps;\n}\n\n/** Detects a login form: a password field plus an identifier field with session links nearby. */\nexport function detectlogin(fields: fieldshape[], links: string[]): { login: boolean; markers: string[] } {\n const markers: string[] = [];\n const password = fields.find(field => classifyfield(field) === \"password\");\n if (password) markers.push(\"password field\");\n const identifier = fields.find(field => {\n const kind = classifyfield(field);\n return kind === \"email\" || (kind === \"text\" && /user|login|account|identifier/i.test(`${field.name} ${field.label}`));\n });\n if (identifier) markers.push(\"identifier field\");\n const sessionlink = links.some(link => /sign in|log in|log on|forgot|create account|sign up/i.test(link));\n if (sessionlink) markers.push(\"session link\");\n return { login: Boolean(password && identifier && sessionlink), markers };\n}\n\nconst signupmarkers = [\"sign up\", \"create account\", \"register\", \"confirm password\", \"terms\"];\nconst checkoutmarkers = [\"checkout\", \"payment\", \"billing\", \"shipping\", \"card number\", \"place order\", \"cart\"];\n\n/** Detects signup and checkout templates by matching the field labels, autocompletes and page text against known markers. */\nexport function detecttemplate(fields: fieldshape[], text: string): { template: \"signup\" | \"checkout\" | \"unknown\"; markers: string[] } {\n const corpus = [text, ...fields.map(field => `${field.label} ${field.name} ${field.placeholder} ${field.arialabel} ${field.autocomplete}`)].join(\" \").toLowerCase();\n const signup = signupmarkers.filter(marker => corpus.includes(marker));\n const checkout = checkoutmarkers.filter(marker => corpus.includes(marker));\n if (signup.length >= 2 && signup.length >= checkout.length) return { template: \"signup\", markers: signup };\n if (checkout.length >= 2) return { template: \"checkout\", markers: checkout };\n return { template: \"unknown\", markers: [...signup, ...checkout] };\n}\n\n/** Associates validation messages with fields through aria describedby refs and the sibling text next to each field. */\nexport function associateerrors(contexts: errorcontext[], messages: Array<{ id?: string; text: string }>): fielderror[] {\n const errors: fielderror[] = [];\n for (const field of contexts) {\n const byref = field.describedby ? messages.find(message => message.id === field.describedby && message.text.trim()) : undefined;\n if (byref) { errors.push({ field: field.selector, message: byref.text.trim() }); continue; }\n const sibling = field.siblings.map(text => text.trim()).find(text => text.length > 0);\n if (sibling) errors.push({ field: field.selector, message: sibling });\n }\n return errors;\n}\n\n/** Resolves one reviewed artifact name against the run store before a file input is filled. */\nexport function attachplan(name: string, artifacts: Array<{ id: string; name: string; kind: string }>): { artifact?: { id: string; name: string; kind: string }; reason?: string } {\n const artifact = artifacts.find(item => item.name === name || item.id === name);\n if (!artifact) return { reason: \"The reviewed artifact name is not part of the run store.\" };\n return { artifact };\n}\n\n/** Selectors the captcha detector probes; a hit hands control back to the user instead of forcing the page. */\nexport const captchamarkers = ['iframe[src*=\"recaptcha\"]', 'iframe[title*=\"recaptcha\" i]', '.g-recaptcha', '[data-sitekey]', 'iframe[title*=\"captcha\" i]', '.h-captcha'];\n\n/** True when any captcha marker matched, so the plan pauses and hands control to the user. */\nexport function captchadetected(matched: string[]): boolean {\n return matched.length > 0;\n}\n\nfunction events(target: Element): void {\n target.dispatchEvent(new Event(\"input\", { bubbles: true }));\n target.dispatchEvent(new Event(\"change\", { bubbles: true }));\n}\n\n/** Fills one control through the native setter with input and change events; checks, radios and selects use their own grammar. */\nexport function fillcontrol(element: Element, entry: formentry): boolean {\n if (element instanceof HTMLInputElement && (entry.kind === \"check\" || element.type === \"checkbox\")) { element.checked = entry.value === \"true\" || entry.value === \"on\" || entry.value === \"checked\"; events(element); return true; }\n if (element instanceof HTMLInputElement && (entry.kind === \"radio\" || element.type === \"radio\")) { element.checked = true; events(element); return true; }\n if (element instanceof HTMLSelectElement) {\n const option = [...element.options].find(candidate => candidate.value === entry.value || candidate.textContent?.trim() === entry.value);\n if (!option) return false;\n element.value = option.value;\n events(element);\n return true;\n }\n if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {\n if (element instanceof HTMLInputElement && element.type === \"file\") return false;\n element.focus();\n const setter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), \"value\")?.set;\n if (setter) setter.call(element, entry.value); else element.value = entry.value;\n events(element);\n return true;\n }\n return false;\n}\n\nfunction controlshape(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): fieldshape {\n return {\n selector: selector(element),\n tag: element.tagName.toLowerCase(),\n type: element instanceof HTMLSelectElement ? \"select\" : element.getAttribute(\"type\") || \"text\",\n name: element.getAttribute(\"name\") || \"\",\n label: label(element),\n placeholder: element.getAttribute(\"placeholder\") || \"\",\n arialabel: element.getAttribute(\"aria-label\") || \"\",\n autocomplete: element.getAttribute(\"autocomplete\") || \"\",\n ...(element instanceof HTMLSelectElement ? { options: [...element.options].map(option => option.value) } : {}),\n };\n}\n\n/** Collects the serializable field shapes of one form scope; absent scopes survey the whole document. */\nfunction collectfields(root: Document, formscope?: string): Array<{ shape: fieldshape; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n const scope = formscope ? root.querySelector(formscope) : root;\n if (!scope) return [];\n const controls = [...scope.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>(\"input, select, textarea\")];\n return controls.filter(element => element.type !== \"hidden\").map(element => ({ shape: controlshape(element), element }));\n}\n\n/** Surveys the visibility and geometry evidence the honeypot detector reads for one form scope. */\nfunction surveyfields(root: Document, formscope?: string): Array<{ survey: fieldsurvey; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n const viewport = { left: 0, top: 0, right: window.innerWidth || 0, bottom: window.innerHeight || 0 };\n return collectfields(root, formscope).map(({ shape, element }) => {\n const rect = element.getBoundingClientRect();\n const hidden = element.getAttribute(\"aria-hidden\") === \"true\" || element.tabIndex < 0 && (element as HTMLElement).offsetParent === null || (element as HTMLElement).offsetParent === null && rect.width === 0 && rect.height === 0;\n const offscreen = rect.width > 0 && rect.height > 0 && (rect.bottom < viewport.top || rect.top > viewport.bottom || rect.right < viewport.left || rect.left > viewport.right);\n return { survey: { ...shape, hidden, offscreen }, element };\n });\n}\n\n/** Reads the error context of one form scope: describedby refs and the sibling texts after each field. */\nfunction collecterrorcontext(root: Document, formscope?: string): Array<{ context: errorcontext; element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }> {\n return collectfields(root, formscope).map(({ shape, element }) => {\n const siblings: string[] = [];\n let neighbor = element.nextElementSibling;\n for (let index = 0; neighbor && index < 3; index += 1) {\n const text = clean(neighbor.textContent || \"\");\n if (text && text !== shape.label) siblings.push(text);\n neighbor = neighbor.nextElementSibling;\n }\n const describedby = element.getAttribute(\"aria-describedby\");\n return { context: { ...shape, ...(describedby ? { describedby } : {}), siblings }, element };\n });\n}\n\n/** Runs one reviewed forms and data step inside the page: fills, surveys, detects and reads errors without leaving the form scope. */\nexport function runpageform(step: toolstep, target: Element | null, root: Document = document): stepresult | Promise<stepresult> {\n let options: Record<string, unknown> = {};\n try { options = parseoptions(step); } catch { options = {}; }\n const formscope = typeof options.form === \"string\" && options.form ? options.form : step.target;\n switch (step.kind) {\n case \"fillform\": {\n const record = parseformrecord(options.formrecord);\n if (!record) return { ok: false, summary: \"A reviewed form record with entries is required in options.\" };\n const surveys = surveyfields(root, record.form);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const operations = filloperations(record, surveys.map(entry => entry.survey), honeypots.map(trap => trap.selector));\n let filled = 0;\n const skipped: string[] = [];\n const failures: string[] = [];\n const values: Array<{ label: string; value: string }> = [];\n for (const operation of operations) {\n if (operation.skipped && operation.matched) { skipped.push(operation.matched.selector); continue; }\n if (!operation.matched) { failures.push(`${operation.reason}: ${operation.entry.match.label ?? operation.entry.match.name ?? operation.entry.match.placeholder ?? \"field\"}`); continue; }\n const element = surveys.find(entry => entry.survey.selector === operation.matched?.selector)?.element;\n if (!element || !fillcontrol(element, operation.entry)) { failures.push(`unfillable: ${operation.matched.selector}`); continue; }\n filled += 1;\n values.push({ label: operation.matched.label || operation.matched.name, value: operation.entry.kind === \"password\" ? \"\" : operation.entry.value });\n }\n const report: formreport = { form: record.form ?? \"\", fields: operations.map(operation => ({ selector: operation.matched?.selector ?? \"\", label: operation.matched?.label ?? operation.entry.match.label ?? \"\", kind: operation.entry.kind, matched: Boolean(operation.matched) })) };\n return {\n ok: failures.length === 0,\n summary: failures.length === 0 ? `Filled ${filled} reviewed field${filled === 1 ? \"\" : \"s\"} from the structured record${skipped.length > 0 ? ` and skipped ${skipped.length} honeypot field${skipped.length === 1 ? \"\" : \"s\"}` : \"\"}.` : `Filled ${filled} of ${record.entries.length} reviewed fields; ${failures.length} refusals: ${failures.join(\"; \")}.`,\n details: { filled, skipped, failures, values, report },\n };\n }\n case \"filllabel\":\n case \"fillplaceholder\": {\n const mode = step.kind === \"filllabel\" ? \"label\" : \"placeholder\";\n const pairs = Array.isArray(options.fields) ? (options.fields as Array<Record<string, unknown>>).filter(item => item && typeof item === \"object\") : [];\n const record = pairentries(pairs.map(pair => ({ label: typeof pair.label === \"string\" ? pair.label : \"\", placeholder: typeof pair.placeholder === \"string\" ? pair.placeholder : \"\", value: typeof pair.value === \"string\" ? pair.value : \"\" })), mode);\n if (record.entries.length === 0) return { ok: false, summary: \"A reviewed non-empty list of field pairs is required in options.\" };\n const surveys = surveyfields(root, formscope);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const operations = filloperations(record, surveys.map(entry => entry.survey), honeypots.map(trap => trap.selector));\n let filled = 0;\n const failures: string[] = [];\n for (const operation of operations) {\n if (operation.skipped) continue;\n if (!operation.matched) { failures.push(`${operation.reason}: ${mode === \"label\" ? operation.entry.match.label : operation.entry.match.placeholder}`); continue; }\n const element = surveys.find(entry => entry.survey.selector === operation.matched?.selector)?.element;\n const refined: formentry = { ...operation.entry, kind: classifyfield(operation.matched) };\n if (!element || !fillcontrol(element, refined)) { failures.push(`unfillable: ${operation.matched.selector}`); continue; }\n filled += 1;\n }\n return { ok: failures.length === 0, summary: failures.length === 0 ? `Filled ${filled} field${filled === 1 ? \"\" : \"s\"} matched by ${mode}.` : `Filled ${filled} of ${record.entries.length} fields matched by ${mode}; ${failures.join(\"; \")}.`, details: { filled, failures, mode } };\n }\n case \"detectfields\": {\n const collected = collectfields(root, formscope);\n const report: formreport = { form: formscope ?? \"\", fields: collected.map(entry => ({ selector: entry.shape.selector, label: entry.shape.label || entry.shape.name, kind: classifyfield(entry.shape), matched: Boolean(entry.shape.label || entry.shape.name) })) };\n return { ok: true, summary: `Detected ${collected.length} form field${collected.length === 1 ? \"\" : \"s\"} with their kinds.`, details: { report, count: collected.length } };\n }\n case \"generatevalues\": {\n const rule = options.valuegen && typeof options.valuegen === \"object\" && !Array.isArray(options.valuegen) ? options.valuegen as Record<string, unknown> : {};\n const locale = typeof rule.locale === \"string\" ? rule.locale : \"en\";\n const seed = typeof rule.seed === \"number\" && Number.isFinite(rule.seed) ? rule.seed : 1;\n const surveys = surveyfields(root, formscope);\n const honeypots = detecthoneypots(surveys.map(entry => entry.survey), 0);\n const skippedselectors = new Set(honeypots.map(trap => trap.selector));\n const candidates = surveys.filter(entry => !skippedselectors.has(entry.survey.selector));\n const values = candidates.map(entry => ({ label: entry.survey.label || entry.survey.name || entry.survey.selector, kind: classifyfield(entry.survey), value: generatevalue(classifyfield(entry.survey), { locale, seed }) }));\n const single = values.length === 0 && typeof rule.kind === \"string\" ? [{ label: rule.kind, kind: rule.kind, value: generatevalue(rule.kind as fieldkind, { locale, seed }) }] : values;\n return { ok: true, summary: `Generated ${single.length} realistic value${single.length === 1 ? \"\" : \"s\"} for the detected field kinds.`, details: { values: single, locale, seed } };\n }\n case \"readerrors\": {\n const contexts = collecterrorcontext(root, formscope);\n const messages = [...root.querySelectorAll<HTMLElement>(\"[id]\")].map(element => ({ id: element.id, text: clean(element.textContent || \"\") })).filter(message => message.text.length > 0);\n const errors = associateerrors(contexts.map(entry => entry.context), messages);\n return { ok: true, summary: errors.length === 0 ? \"No validation error was found next to the reviewed fields.\" : `Collected ${errors.length} inline validation message${errors.length === 1 ? \"\" : \"s\"}.`, details: { errors, form: formscope ?? \"\" } };\n }\n case \"skiphoneypot\": {\n const surveys = surveyfields(root, formscope);\n const traps = detecthoneypots(surveys.map(entry => entry.survey), 0);\n return { ok: true, summary: traps.length === 0 ? \"No honeypot field was detected.\" : `Skipped ${traps.length} honeypot field${traps.length === 1 ? \"\" : \"s\"}: ${traps.map(trap => `${trap.selector} (${trap.reason})`).join(\", \")}.`, details: { skipped: traps } };\n }\n case \"detectlogin\": {\n const collected = collectfields(root, formscope);\n const links = [...(formscope ? root.querySelectorAll(formscope) : [root] as unknown as Element[])].flatMap(scope => [...scope.querySelectorAll(\"a[href], button\")]).map(element => clean(element.textContent || \"\"));\n const detection = detectlogin(collected.map(entry => entry.shape), links);\n return { ok: true, summary: detection.login ? `Login form detected with ${detection.markers.join(\", \")}.` : \"No login form was detected.\", details: { login: detection.login, markers: detection.markers } };\n }\n case \"detecttemplate\": {\n const collected = collectfields(root, formscope);\n const text = clean(root.body?.innerText || \"\");\n const detection = detecttemplate(collected.map(entry => entry.shape), text);\n return { ok: true, summary: detection.template === \"unknown\" ? \"No signup or checkout template was detected.\" : `${detection.template} template detected with markers ${detection.markers.join(\", \")}.`, details: { template: detection.template, markers: detection.markers } };\n }\n case \"handoffcaptcha\": {\n const matched = captchamarkers.filter(marker => root.querySelector(marker) !== null);\n return { ok: true, summary: captchadetected(matched) ? `Captcha presence detected (${matched.join(\", \")}); control hands back to the user.` : \"No captcha was detected.\", details: { captcha: captchadetected(matched), markers: matched } };\n }\n case \"asksubmit\": {\n const collected = collectfields(root, step.value || undefined);\n const values = collected.map(entry => ({ label: entry.shape.label || entry.shape.name || entry.shape.selector, value: entry.element instanceof HTMLSelectElement ? entry.element.value : (entry.element as HTMLInputElement).value }));\n return { ok: true, summary: `Read ${values.length} field value${values.length === 1 ? \"\" : \"s\"} for the submission review.`, details: { values } };\n }\n case \"submitform\": {\n const form = target instanceof HTMLFormElement ? target : target instanceof HTMLElement ? target.closest(\"form\") : null;\n if (!form) return { ok: false, summary: \"No owning form was found for the reviewed submission.\" };\n form.requestSubmit();\n return { ok: true, summary: \"Form submitted programmatically through its owning form.\" };\n }\n case \"consentpassword\": {\n if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) return { ok: false, summary: \"The reviewed password target cannot receive text.\" };\n const entry: formentry = { match: { mode: \"name\", name: target.name || target.getAttribute(\"id\") || \"\" }, kind: \"password\", value: step.value ?? \"\" };\n if (!fillcontrol(target, entry)) return { ok: false, summary: \"The password field refused the native setter fill.\" };\n return { ok: true, summary: \"Password field filled after the reviewed consent; the value never appears in the audit trail.\" };\n }\n case \"attachfile\": {\n if (!(target instanceof HTMLInputElement) || target.type !== \"file\") return { ok: false, summary: \"The reviewed target is not a file input.\" };\n const artifactname = typeof options.artifactname === \"string\" && options.artifactname ? options.artifactname : \"artifact\";\n try {\n const file = new File([new Blob([\"devthink artifact\"], { type: \"application/octet-stream\" })], artifactname);\n const transfer = new DataTransfer();\n transfer.items.add(file);\n target.files = transfer.files;\n events(target);\n return { ok: true, summary: `Artifact ${artifactname} attached to the reviewed file input.`, details: { artifact: options.artifact, artifactname } };\n } catch {\n return { ok: false, summary: \"The reviewed file input refused the artifact attachment.\" };\n }\n }\n default: return { ok: false, summary: \"Unsupported forms and data action.\" };\n }\n}\n", "import type { artifactrecord, columnspec, dataset, datasetrow, exportedartifact, extractsession, provenancerecord, streamstate, toolstep, transformrule } from \"../types.js\";\nimport { tocsv, toexcel, tojson } from \"./pagedata.js\";\n\n/**\n * Dataset command logics for the background executors.\n * Every correlated rule for dataset records, artifact exports with checksums, chunked streaming with backpressure, extraction cursors, loop row variables, provenance records and artifact retention lives in this file.\n */\n\n/** Builds one dataset record from a scraped grid result. */\nexport function builddataset(id: string, name: string, grid: { columns: columnspec[]; rows: datasetrow[]; children?: Array<{ parentrow: number; selector: string; columns: columnspec[]; rows: datasetrow[] }> }, at: number): dataset {\n return { id, name: name || id, columns: grid.columns, rows: grid.rows, sources: [], at };\n}\n\n/** Computes the deterministic checksum of an exported artifact's content. */\nexport function checksum(value: string): string {\n let hash = 5381;\n for (let index = 0; index < value.length; index += 1) hash = ((hash * 33) ^ value.charCodeAt(index)) >>> 0;\n return `fnv1a-${hash.toString(16)}`;\n}\n\n/** Serializes one dataset into the reviewed export format. */\nexport function exportcontent(datasetvalue: dataset, format: \"csv\" | \"json\" | \"excel\", delimiter = \",\"): string {\n if (format === \"json\") return tojson(datasetvalue.columns, datasetvalue.rows);\n if (format === \"excel\") return toexcel(datasetvalue.columns, datasetvalue.rows, datasetvalue.name);\n return tocsv(datasetvalue.columns, datasetvalue.rows, delimiter);\n}\n\n/** Builds one exported artifact record with its content and checksum for the task artifact store. */\nexport function exportartifact(id: string, datasetvalue: dataset, format: \"csv\" | \"json\" | \"excel\", stepid: string, content: string, at: number): exportedartifact {\n const extension = format === \"excel\" ? \"xml\" : format;\n return { id, kind: format, name: `${datasetvalue.name || datasetvalue.id}.${extension}`, stepid, rowcount: datasetvalue.rows.length, content, checksum: checksum(content), at };\n}\n\n/** Converts one exported artifact into the artifact record shape the run store keeps. */\nexport function artifactrecordof(artifact: exportedartifact): artifactrecord {\n return { id: artifact.id, kind: artifact.kind, name: artifact.name, stepid: artifact.stepid, at: artifact.at };\n}\n\n/** Plans the chunk boundaries of a streaming export from a user configured chunk size with no code ceiling. */\nexport function chunkplan(rows: number, chunk: number): Array<{ index: number; from: number; to: number }> {\n const size = Math.max(1, Math.floor(chunk));\n const chunks: Array<{ index: number; from: number; to: number }> = [];\n for (let from = 0; from < rows || chunks.length === 0; from += size) {\n const to = Math.min(rows, from + size);\n chunks.push({ index: chunks.length, from, to });\n if (to >= rows) break;\n }\n return chunks;\n}\n\n/** True when the stream writer must wait for acknowledgements: pending writes reached the in-flight budget of one. */\nexport function backpressure(written: number, acknowledged: number): boolean {\n return written - acknowledged >= 1;\n}\n\n/** Advances one stream state by one acknowledged chunk of rows. */\nexport function advancestream(state: streamstate, chunk: { index: number; to: number }, at: number, done: boolean): streamstate {\n return { datasetid: state.datasetid, name: state.name, chunk: chunk.index + 1, chunks: state.chunks, written: chunk.to, ...(done ? { done: true } : {}), at };\n}\n\n/** Returns the first unwritten row index of a stream, starting a fresh stream at zero. */\nexport function streamfrom(state: streamstate | undefined, rows: number): number {\n if (!state || state.done) return 0;\n return Math.min(state.written, rows);\n}\n\n/** Builds the initial stream state of one dataset. */\nexport function newstream(datasetvalue: dataset, chunks: number, at: number): streamstate {\n return { datasetid: datasetvalue.id, name: datasetvalue.name, chunk: 0, chunks, written: 0, at };\n}\n\n/** Advances one extraction session by one extracted page with its row count. */\nexport function advancecursor(sessionvalue: extractsession, page: string, rows: number, at: number, done: boolean): extractsession {\n return {\n id: sessionvalue.id,\n datasetid: sessionvalue.datasetid,\n name: sessionvalue.name,\n target: sessionvalue.target,\n next: sessionvalue.next,\n planned: sessionvalue.planned,\n pages: [...sessionvalue.pages, page],\n rows: sessionvalue.rows + rows,\n cursor: sessionvalue.cursor + 1,\n ...(done || sessionvalue.cursor + 1 >= sessionvalue.planned ? { done: true } : {}),\n startedat: sessionvalue.startedat,\n updatedat: at,\n };\n}\n\n/** Builds the initial extraction session of one dataset extraction. */\nexport function newextractsession(id: string, datasetid: string, name: string, target: string, next: string, planned: number, at: number): extractsession {\n return { id, datasetid, name, target, next, planned, pages: [], rows: 0, cursor: 0, startedat: at, updatedat: at };\n}\n\n/** Returns the pages an interrupted extraction still owes after its stored cursor. */\nexport function remainingpages(sessionvalue: extractsession, planned: number): number {\n if (sessionvalue.done) return 0;\n return Math.max(0, Math.max(sessionvalue.planned, planned) - sessionvalue.cursor);\n}\n\n/** Builds one provenance record of an exported artifact with its source url, step ref, row range and checksum. */\nexport function provenancefor(artifact: { id: string; name: string; rowcount: number; checksum: string }, url: string, stepid: string, at: number): provenancerecord {\n return { artifact: artifact.id, name: artifact.name, url, stepid, rowstart: artifact.rowcount > 0 ? 1 : 0, rowend: artifact.rowcount, checksum: artifact.checksum, at };\n}\n\n/** Applies the user configured artifact retention to exported artifacts; an absent setting keeps everything. */\nexport function retainedexports<T>(records: T[], retention: number | undefined): T[] {\n return retention === undefined ? records : records.slice(0, retention);\n}\n\n/** Interpolates one text through the {{column}} tokens of a dataset row. */\nexport function interpolate(text: string, row: datasetrow): string {\n return text.replace(/\\{\\{([^}]+)\\}\\}/g, (_, key: string) => row[key.trim()] ?? \"\");\n}\n\n/** Substitutes the row variables of one looprows iteration into the target, value and options of the inner step. */\nexport function loopstep(step: toolstep, row: datasetrow): toolstep {\n return {\n ...step,\n ...(step.target !== undefined ? { target: interpolate(step.target, row) } : {}),\n ...(step.value !== undefined ? { value: interpolate(step.value, row) } : {}),\n ...(step.options !== undefined ? { options: interpolate(step.options, row) } : {}),\n };\n}\n\n/** Exposes one dataset row as the step variables of a looprows iteration. */\nexport function loopvariables(row: datasetrow): datasetrow {\n return { ...row };\n}\n\n/** Builds the grid preview of a dataset with its column order, total rows and sampled rows. */\nexport function gridpreview(datasetvalue: dataset, sample: number): { datasetid: string; columns: string[]; rows: number; sample: datasetrow[] } {\n return { datasetid: datasetvalue.id, columns: datasetvalue.columns.map(column => column.key), rows: datasetvalue.rows.length, sample: datasetvalue.rows.slice(0, Math.max(0, Math.floor(sample))) };\n}\n\n/** Sorts dataset rows by one column key in the reviewed direction with a stable fallback for equal values. */\nexport function sortrows(rows: datasetrow[], key: string, direction: \"asc\" | \"desc\"): datasetrow[] {\n const sign = direction === \"desc\" ? -1 : 1;\n return [...rows].sort((left, right) => {\n const a = left[key] ?? \"\";\n const b = right[key] ?? \"\";\n const numeric = Number(a);\n const numericb = Number(b);\n if (Number.isFinite(numeric) && Number.isFinite(numericb) && a.trim() !== \"\" && b.trim() !== \"\") return (numeric - numericb) * sign;\n return a.localeCompare(b) * sign;\n });\n}\n\n/** Builds the sheet push payload of one dataset for a reviewed sheet endpoint. */\nexport function sheetpayload(datasetvalue: dataset, sheet: string): { sheet: string; columns: string[]; rows: datasetrow[] } {\n return { sheet, columns: datasetvalue.columns.map(column => column.key), rows: datasetvalue.rows };\n}\n\n/** Merges reviewed transform rules and dedupe keys into the task rules record of one task. */\nexport function mergetaskrules(existing: { taskid: string; transforms: transformrule[]; dedupekeys: string[] } | undefined, taskid: string, transforms: transformrule[], dedupekeys: string[], at: number): { taskid: string; transforms: transformrule[]; dedupekeys: string[]; at: number } {\n return {\n taskid,\n transforms: transforms.length > 0 ? transforms : (existing?.transforms ?? []),\n dedupekeys: dedupekeys.length > 0 ? dedupekeys : (existing?.dedupekeys ?? []),\n at,\n };\n}\n", "import type { a11ycapture, a11ynode, agentplan, artifactinventoryentry, artifactrecord, auditevent, bannerreport, capabilityreport, captchahandoff, capturepolicy, cleanuprule, cleanuprun, clipboardconsentrecord, clipentry, clickablemap, closedtab, columnspec, controltabstate, curatedlist, dataset, datasetrow, derivedselector, detectionrecord, diagnosticreport, downloadrecord, errorreport, extractsession, fielderror, focusevent, formprofile, listpattern, mimefilter, mutationevent, navcontrol, navrecord, navqueues, netlogrecord, planprogress, provenancerecord, quarantineentry, ratelimitstate, readercapture, resolvedtarget, retryoutcome, safetyverdict, sessionsnapshot, shotpair, snapshotdiff, stepoutcome, streamstate, submitticket, tabbadge, tabgrouprecord, tablayout, tabmeta, tableshape, taskrules, toolstep, trailentry, transformrule, typeaheadpick, waitprofilerecord, wizardstate } from \"../types.js\";\nimport { switcherlist, type tabshape, type windowshape } from \"./tabscommand.js\";\nimport { cardmask } from \"./pageforms.js\";\nimport { sortrows } from \"./datacommand.js\";\n\nconst objective = document.querySelector<HTMLTextAreaElement>(\"#objective\");\nconst localbutton = document.querySelector<HTMLButtonElement>(\"#localplan\");\nconst remotebutton = document.querySelector<HTMLButtonElement>(\"#remoteplan\");\nconst diagnosticbutton = document.querySelector<HTMLButtonElement>(\"#diagnostic\");\nconst planroot = document.querySelector<HTMLElement>(\"#plan\");\nconst auditroot = document.querySelector<HTMLElement>(\"#audit\");\nconst diagnosticroot = document.querySelector<HTMLElement>(\"#diagnostics\");\nconst maproot = document.querySelector<HTMLElement>(\"#map\");\nconst a11yroot = document.querySelector<HTMLElement>(\"#a11y\");\nconst readerroot = document.querySelector<HTMLElement>(\"#reader\");\nconst detectionsroot = document.querySelector<HTMLElement>(\"#detections\");\nconst streamroot = document.querySelector<HTMLElement>(\"#stream\");\nconst diffsroot = document.querySelector<HTMLElement>(\"#diffs\");\nconst bannersroot = document.querySelector<HTMLElement>(\"#banners\");\nconst selectorsroot = document.querySelector<HTMLElement>(\"#selectors\");\nconst trailroot = document.querySelector<HTMLElement>(\"#trail\");\nconst navigationroot = document.querySelector<HTMLElement>(\"#navigation\");\nconst tabswindowsroot = document.querySelector<HTMLElement>(\"#tabswindows\");\nconst formsroot = document.querySelector<HTMLElement>(\"#forms\");\nconst datasetsroot = document.querySelector<HTMLElement>(\"#datasets\");\nconst filesroot = document.querySelector<HTMLElement>(\"#files\");\nconst capturesroot = document.querySelector<HTMLElement>(\"#captures\");\nconst statusnode = document.querySelector<HTMLElement>(\"#status\");\nconst progressnode = document.querySelector<HTMLProgressElement>(\"#planprogress\");\nconst capabilitiestext = document.querySelector<HTMLElement>(\"#capabilitiestext\");\n\ntype previewresult = { ok: boolean; summary: string; resolvedtarget?: resolvedtarget; candidates?: string[] };\nconst previews = new Map<string, previewresult>();\n\n/** Safely reads the reviewed options object of one step. */\nfunction options(step: toolstep): Record<string, unknown> {\n if (!step.options) return {};\n try {\n const parsed = JSON.parse(step.options);\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as Record<string, unknown>) : {};\n } catch { return {}; }\n}\n\nfunction status(message: string, error = false): void { if (statusnode) { statusnode.textContent = message; statusnode.dataset.state = error ? \"error\" : \"ready\"; } }\nasync function request(message: unknown): Promise<unknown> { const response = await chrome.runtime.sendMessage(message) as { ok: boolean; value?: unknown; error?: string }; if (!response.ok) throw new Error(response.error); return response.value; }\nfunction button(label: string, action: () => Promise<void>, disabled = false): HTMLButtonElement { const element = document.createElement(\"button\"); element.type = \"button\"; element.textContent = label; element.disabled = disabled; element.addEventListener(\"click\", () => action().catch(error => status(error instanceof Error ? error.message : String(error), true))); return element; }\n\n/** Kinds addressable by a css target or a reviewed targetref; only these can be previewed. */\nconst previewkinds = [\"focus\", \"inspect\", \"click\", \"type\", \"scroll\", \"select\", \"hover\", \"clickdeep\", \"rightclick\", \"doubleclick\", \"drag\", \"drop\", \"upload\", \"clear\", \"check\", \"uncheck\", \"toggle\", \"submit\", \"readattribute\", \"readstyle\", \"readgeometry\", \"readvalue\", \"readtext\", \"readhtml\", \"countelements\", \"readtable\", \"highlight\", \"setattribute\", \"removeattribute\", \"waitfor\", \"shiftclick\", \"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\", \"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\", \"verifyvisible\", \"verifyenabled\", \"pierceshadow\", \"clickpoint\", \"clicktext\", \"clickaria\", \"clickname\", \"resolvexpath\", \"deriveselector\", \"fingerprintsection\", \"submitform\", \"retryform\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"fillcode\", \"consentpassword\"];\n\n/** Topic rows that group the new interaction and observation kinds inside each risk class. */\nconst topictags: Array<{ topic: string; kinds: string[] }> = [\n { topic: \"pointer\", kinds: [\"movepointer\", \"clickpoint\", \"shiftclick\", \"clicktext\", \"clickaria\", \"clickname\", \"pierceshadow\"] },\n { topic: \"typing\", kinds: [\"typetime\", \"appendtext\", \"setvalue\", \"typeedit\", \"submitsearch\"] },\n { topic: \"keys\", kinds: [\"keyhold\", \"keyrelease\"] },\n { topic: \"controls\", kinds: [\"selectmulti\", \"chooseradio\", \"setslider\", \"setdate\", \"setcolor\", \"expanddetails\"] },\n { topic: \"dialogs\", kinds: [\"dismissdialog\"] },\n { topic: \"frames\", kinds: [\"enterframe\"] },\n { topic: \"retry\", kinds: [\"retryaction\"] },\n { topic: \"reads\", kinds: [\"mapclicks\", \"verifyvisible\", \"verifyenabled\", \"resolvexpath\"] },\n { topic: \"observation\", kinds: [\"a11ytree\", \"readvisible\", \"readertree\", \"readoutline\", \"readselection\", \"readopengraph\", \"readlang\", \"detectlanguage\", \"listshadow\", \"listframes\", \"readscrollpos\"] },\n { topic: \"detection\", kinds: [\"detectlists\", \"detecttables\", \"detectinfinitescroll\", \"detectvirtual\", \"detectlazy\", \"detectsticky\", \"detectscrolllock\", \"countpages\", \"classifypage\", \"fingerprintsection\"] },\n { topic: \"watch\", kinds: [\"watchmutate\", \"watchbanner\", \"watchfocus\", \"waitquiet\", \"readjson\", \"diffsnapshots\", \"deriveselector\"] },\n { topic: \"navigation\", kinds: [\"openlink\", \"openprivate\", \"reloadcache\", \"stopnav\", \"waitload\", \"waiturl\", \"followlink\", \"spanav\", \"spawait\", \"rewritequery\", \"setfragment\", \"navlist\", \"navprofile\", \"detecthttp\", \"readredirects\", \"readfinalurl\", \"handleauth\", \"printpdf\", \"prefetch\", \"preconnect\", \"deeplink\", \"reopentab\", \"trailaudit\", \"pausenav\", \"navintent\", \"navrate\", \"openclipboard\", \"checksafe\", \"batchopen\"] },\n { topic: \"tabs\", kinds: [\"querytabs\", \"duplicatetab\", \"closepattern\", \"pintab\", \"mutetab\", \"movetab\", \"movetabwindow\", \"grouptabs\", \"colorgroup\", \"collapsegroup\", \"discardtab\", \"reloadtabs\", \"zoomin\", \"zoomout\", \"watchtab\", \"switchtab\", \"maximizewindow\", \"minimizewindow\", \"restorewindow\", \"focuswindow\", \"scratchwindow\", \"incognitowindow\", \"restoretab\", \"savelayout\", \"restorelayout\", \"findclones\", \"searchtabs\", \"badgetab\", \"attachmeta\", \"listaudio\", \"reopenrun\", \"snapshotsession\"] },\n { topic: \"forms\", kinds: [\"fillform\", \"filllabel\", \"fillplaceholder\", \"detectfields\", \"generatevalues\", \"saveprofiles\", \"asksubmit\", \"submitform\", \"readerrors\", \"retryform\", \"runwizard\", \"selectchain\", \"picktypeahead\", \"pickdate\", \"attachfile\", \"handoffcaptcha\", \"fillcard\", \"fillcode\", \"consentpassword\", \"skiphoneypot\", \"detectlogin\", \"detecttemplate\"] },\n];\n\nfunction steptopic(kind: string): string | undefined {\n return topictags.find(tag => tag.kinds.includes(kind))?.topic;\n}\n\n/** Renders plan completion as a live progress ratio. */\nfunction renderprogress(plan: agentplan, completed: string[]): void {\n if (!progressnode) return;\n const total = plan.steps.length || 1;\n progressnode.max = total;\n progressnode.value = completed.length;\n progressnode.textContent = `${completed.length} of ${plan.steps.length} reviewed steps executed`;\n}\n\n/** Renders the latest structured outcome of one step beside its review entry. */\nfunction renderoutcome(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n const outcome = [...outcomes].reverse().find(item => item.stepid === step.id && item.ok) ?? [...outcomes].reverse().find(item => item.stepid === step.id);\n if (!outcome) return null;\n const node = document.createElement(\"details\");\n node.className = \"outcome\";\n const summary = document.createElement(\"summary\");\n summary.textContent = `${outcome.ok ? \"result\" : \"failure\"}: ${outcome.summary}`;\n node.append(summary);\n if (outcome.details && Object.keys(outcome.details).length > 0) {\n const payload = document.createElement(\"pre\");\n payload.textContent = JSON.stringify(outcome.details, null, 2).slice(0, 4000);\n node.append(payload);\n }\n return node;\n}\n\n/** Renders the hold id of a key hold or release step beside its summary. */\nfunction holddetail(step: toolstep): string {\n if (step.kind === \"keyhold\") {\n const holdid = options(step).holdid;\n return typeof holdid === \"string\" && holdid ? ` \u00B7 hold id ${holdid}` : \"\";\n }\n if (step.kind === \"keyrelease\") return step.value ? ` \u00B7 releases hold id ${step.value}` : \"\";\n return \"\";\n}\n\n/** Renders the retry attempts of one retry step on the step timeline. */\nfunction retrydetail(step: toolstep, retries: retryoutcome[]): HTMLElement | null {\n const latest = [...retries].reverse().find(item => item.stepid === step.id);\n if (!latest) return null;\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `retry timeline: ${latest.attempts} attempt${latest.attempts === 1 ? \"\" : \"s\"} \u00B7 ${latest.movement.toFixed(1)} px movement \u00B7 ${latest.ok ? \"succeeded\" : \"failed\"}`;\n return node;\n}\n\n/** Renders the network quiet progress of one waitquiet step from its outcome evidence. */\nfunction quietdetail(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n if (step.kind !== \"waitquiet\") return null;\n const latest = [...outcomes].reverse().find(outcome => outcome.stepid === step.id);\n if (!latest) return null;\n const samples = Array.isArray(latest.details?.samples) ? latest.details?.samples as Array<{ at: number; quietfor: number }> : [];\n const idle = typeof latest.details?.idle === \"number\" ? latest.details?.idle : 0;\n const last = samples[samples.length - 1];\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `network quiet: ${samples.length} sample${samples.length === 1 ? \"\" : \"s\"} \u00B7 quiet for ${Math.round(last?.quietfor ?? 0)} ms \u00B7 idle threshold ${idle} ms \u00B7 ${latest.ok ? \"quiet reached\" : \"still busy\"}`;\n return node;\n}\n\n/** Renders the per iteration row variables of one looprows step on the step timeline. */\nfunction loopdetail(step: toolstep, progress: planprogress | undefined): HTMLElement | null {\n if (step.kind !== \"looprows\") return null;\n const iterations = (progress?.outcomes ?? []).filter(outcome => outcome.stepid === step.id && outcome.details?.iteration !== undefined);\n if (iterations.length === 0) return null;\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n const latest = iterations[iterations.length - 1];\n if (!latest) return null;\n const variables = latest.details?.variables as Record<string, string> | undefined;\n const shown = variables ? Object.entries(variables).slice(0, 4).map(([key, value]) => `${key}=${value}`).join(\", \") : \"\";\n node.textContent = `loop timeline: ${iterations.length} iteration${iterations.length === 1 ? \"\" : \"s\"} \u00B7 ${String(latest.details?.variable ?? \"row\")} variables ${shown}`;\n return node;\n}\n\n/** Renders the navlist progress of one navlist step with the current url and the remaining count. */\nfunction navlistdetail(step: toolstep, progress: planprogress | undefined, outcomes: stepoutcome[]): HTMLElement | null {\n if (step.kind !== \"navlist\") return null;\n const entries = (progress?.outcomes ?? []).filter(outcome => outcome.stepid === step.id && outcome.details?.naventry !== undefined).map(outcome => outcome.details?.naventry as { index: number; url: string; ok: boolean });\n const total = entries.length > 0 ? Math.max(...entries.map(entry => entry.index)) + 1 : 0;\n const latestoutcome = [...outcomes].reverse().find(outcome => outcome.stepid === step.id);\n const remaining = typeof latestoutcome?.details?.remaining === \"number\" ? latestoutcome.details?.remaining : 0;\n const current = entries[entries.length - 1];\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = entries.length === 0\n ? \"navigation list: no entry completed yet\"\n : `navigation list: ${entries.filter(entry => entry.ok).length} of ${total} entries completed \u00B7 current url ${current?.url ?? \"\"} \u00B7 ${remaining} remaining`;\n return node;\n}\n\n/** Renders the redirect chain and final url of one navigation step from its outcome evidence. */\nfunction redirectdetail(step: toolstep, outcomes: stepoutcome[]): HTMLElement | null {\n if (![\"navigate\", \"followlink\", \"spanav\", \"navlist\", \"openlink\", \"reloadcache\"].includes(step.kind)) return null;\n const latest = [...outcomes].reverse().find(outcome => outcome.stepid === step.id && outcome.details?.hops !== undefined);\n if (!latest) return null;\n const hops = typeof latest.details?.hops === \"number\" ? latest.details?.hops : 0;\n const final = typeof latest.details?.finalurl === \"string\" ? latest.details?.finalurl : \"\";\n const node = document.createElement(\"p\");\n node.className = \"timeline\";\n node.textContent = `redirects: ${Math.max(0, hops - 1)} hop${hops - 1 === 1 ? \"\" : \"s\"} \u00B7 final url ${final || \"unknown\"}`;\n return node;\n}\n\n/** Renders the resolved target details of one previewed interaction step before approval. */\nfunction renderpreview(step: toolstep): HTMLElement | null {\n const preview = previews.get(step.id);\n if (!preview) return null;\n const node = document.createElement(\"details\");\n node.className = \"outcome\";\n const summary = document.createElement(\"summary\");\n summary.textContent = `preview: ${preview.summary}`;\n node.append(summary);\n if (preview.resolvedtarget) {\n const payload = document.createElement(\"pre\");\n payload.textContent = JSON.stringify(preview.resolvedtarget, null, 2);\n node.append(payload);\n }\n if (preview.candidates && preview.candidates.length > 1) {\n const chooser = document.createElement(\"p\");\n chooser.textContent = \"Ambiguous resolution; choose one candidate as the target hint:\";\n node.append(chooser);\n for (const candidate of preview.candidates) {\n node.append(\" \", button(`Choose \"${candidate}\"`, async () => { pickhint(`target hint: ${candidate}`); }));\n }\n }\n return node;\n}\n\nfunction stepitem(plan: agentplan, step: toolstep, completed: string[], outcomes: stepoutcome[], retries: retryoutcome[], progress?: planprogress): HTMLLIElement {\n const item = document.createElement(\"li\");\n const done = completed.includes(step.id);\n item.textContent = `${done ? \"\u2713\" : \"\"} ${step.summary}${holddetail(step)}`;\n const outcome = renderoutcome(step, outcomes);\n if (outcome) item.append(outcome);\n const timeline = step.kind === \"retryaction\" ? retrydetail(step, retries) : quietdetail(step, outcomes);\n if (timeline) item.append(timeline);\n const navlist = navlistdetail(step, progress, outcomes);\n if (navlist) item.append(navlist);\n const loopvars = loopdetail(step, progress);\n if (loopvars) item.append(loopvars);\n const redirects = redirectdetail(step, outcomes);\n if (redirects) item.append(redirects);\n const preview = renderpreview(step);\n if (preview) item.append(preview);\n const hastarget = Boolean(step.target) || options(step).targetref !== undefined;\n if (!done && hastarget && previewkinds.includes(step.kind) && [\"pending\", \"approved\"].includes(plan.state)) item.append(\" \", button(\"Preview current target\", async () => { const result = await request({ kind: \"preview\", stepid: step.id }) as previewresult; previews.set(step.id, result); status(result.summary); await refresh(); }));\n if (!done && plan.state === \"approved\") item.append(\" \", button(\"Run this reviewed step\", async () => { const result = await request({ kind: \"execute\", stepid: step.id }) as { summary: string }; status(result.summary); await refresh(); }));\n return item;\n}\n\nfunction steplist(plan: agentplan, steps: toolstep[], completed: string[], outcomes: stepoutcome[], retries: retryoutcome[], risk: toolstep[\"risk\"], progress?: planprogress): HTMLElement | null {\n const group = steps.filter(step => step.risk === risk);\n if (group.length === 0) return null;\n const section = document.createElement(\"section\");\n const heading = document.createElement(\"h3\");\n heading.textContent = `${risk} steps`;\n section.append(heading);\n const general = group.filter(step => steptopic(step.kind) === undefined);\n if (general.length > 0) {\n const list = document.createElement(\"ol\");\n for (const step of general) list.append(stepitem(plan, step, completed, outcomes, retries, progress));\n section.append(list);\n }\n for (const tag of topictags) {\n const tagged = group.filter(step => steptopic(step.kind) === tag.topic);\n if (tagged.length === 0) continue;\n const row = document.createElement(\"h4\");\n row.textContent = `${tag.topic} steps`;\n section.append(row);\n const list = document.createElement(\"ol\");\n for (const step of tagged) list.append(stepitem(plan, step, completed, outcomes, retries, progress));\n section.append(list);\n }\n return section;\n}\n\nfunction renderplan(plan?: agentplan, progress?: planprogress, outcomes: stepoutcome[] = [], retries: retryoutcome[] = []): void {\n if (!planroot) return;\n planroot.replaceChildren();\n if (!plan) { planroot.textContent = \"Start a session, then request a local or endpoint plan. No task runs before review.\"; if (progressnode) progressnode.value = 0; return; }\n const title = document.createElement(\"h2\"); title.textContent = `${plan.state}: ${plan.objective}`; planroot.append(title);\n const completed = progress?.planid === plan.id ? progress.completedsteps : [];\n renderprogress(plan, completed);\n const sensitive = steplist(plan, plan.steps, completed, outcomes, retries, \"sensitive\", progress);\n const interaction = steplist(plan, plan.steps, completed, outcomes, retries, \"interaction\", progress);\n const read = steplist(plan, plan.steps, completed, outcomes, retries, \"read\", progress);\n for (const group of [sensitive, interaction, read]) if (group) planroot.append(group);\n if (plan.state === \"pending\") { planroot.append(button(\"Approve reviewed plan\", async () => { await request({ kind: \"approve\" }); await refresh(); }), button(\"Reject plan\", async () => { await request({ kind: \"reject\" }); await refresh(); })); }\n if (plan.state === \"completed\" && plan.completedat) { const note = document.createElement(\"p\"); note.textContent = \"Every reviewed step has executed and the plan is closed.\"; planroot.append(note); }\n}\n\n/** Records one clickable map entry or candidate as the target hint for the next plan. */\nfunction pickhint(hint: string): void {\n if (objective) objective.value = objective.value ? `${objective.value}\\n${hint}` : hint;\n status(`${hint} recorded as the target hint for the next plan.`);\n}\n\n/** Renders the clickable map as a numbered list beside the plan and lets the user pick entries. */\nfunction rendermap(map?: clickablemap): void {\n if (!maproot) return;\n maproot.replaceChildren();\n if (!map || map.entries.length === 0) { maproot.textContent = \"Run a mapclicks step to number every clickable element on the page.\"; return; }\n for (const entry of map.entries) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `${entry.number}. ${entry.label || entry.selector} (${entry.role})`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${entry.selector} (map entry ${entry.number}, ${entry.label || entry.role})`));\n item.append(pick);\n maproot.append(item);\n }\n}\n\n/** Renders the latest accessibility tree beside the dom snapshot as indented role lines. */\nfunction rendera11y(capture?: a11ycapture): void {\n if (!a11yroot) return;\n a11yroot.replaceChildren();\n if (!capture) { a11yroot.textContent = \"Run an a11ytree step to capture the accessibility tree beside the dom snapshot.\"; return; }\n const lines: string[] = [];\n const walk = (node: a11ynode, depth: number): void => {\n if (lines.length >= 80) return;\n const states = node.states.length > 0 ? ` [${node.states.join(\", \")}]` : \"\";\n const value = node.value !== undefined ? ` = ${node.value}` : \"\";\n lines.push(`${\"\u00B7 \".repeat(depth)}${node.role}: ${node.name || \"(unnamed)\"}${states}${value}`);\n for (const child of node.children) walk(child, depth + 1);\n };\n walk(capture.tree, 0);\n const payload = document.createElement(\"pre\");\n payload.textContent = lines.join(\"\\n\");\n a11yroot.append(payload);\n}\n\n/** Renders the latest reader view text with heading blocks highlighted. */\nfunction renderreader(capture?: readercapture): void {\n if (!readerroot) return;\n readerroot.replaceChildren();\n if (!capture) { readerroot.textContent = \"Run a readertree step to extract the reader view.\"; return; }\n const title = document.createElement(\"p\");\n title.textContent = `${capture.article.title || \"Untitled\"}${capture.article.byline ? ` \u00B7 ${capture.article.byline}` : \"\"} \u00B7 ${capture.article.words} words \u00B7 ${capture.article.blocks.length} blocks`;\n readerroot.append(title);\n for (const block of capture.article.blocks.slice(0, 40)) {\n const line = document.createElement(\"p\");\n line.className = /^h\\d$/.test(block.kind) ? \"readerblock heading\" : \"readerblock\";\n line.textContent = `${block.kind}: ${block.text.slice(0, 200)}`;\n readerroot.append(line);\n }\n}\n\n/** Shows detected lists, tables and pagination shapes as plan suggestions the user can pick. */\nfunction renderdetections(plan: agentplan | undefined, outcomes: stepoutcome[]): void {\n if (!detectionsroot) return;\n detectionsroot.replaceChildren();\n if (!plan) { detectionsroot.textContent = \"Detection steps list their detected lists, tables and pagination shapes here as suggestions.\"; return; }\n const kindof = (stepid: string): string | undefined => plan.steps.find(step => step.id === stepid)?.kind;\n const latest = (kind: string): stepoutcome | undefined => [...outcomes].reverse().find(outcome => outcome.ok && kindof(outcome.stepid) === kind);\n let shown = 0;\n const listoutcome = latest(\"detectlists\");\n const lists = Array.isArray(listoutcome?.details?.lists) ? listoutcome?.details?.lists as listpattern[] : [];\n for (const pattern of lists.slice(0, 6)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `list of ${pattern.repeat} items \u00B7 ${pattern.itemselector}`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${pattern.itemselector} (repeated list item of ${pattern.container})`));\n item.append(pick);\n detectionsroot.append(item);\n shown += 1;\n }\n const tableoutcome = latest(\"detecttables\");\n const tables = Array.isArray(tableoutcome?.details?.tables) ? tableoutcome?.details?.tables as tableshape[] : [];\n for (const table of tables.slice(0, 6)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `table of ${table.rows} rows \u00B7 ${table.columns.length} columns \u00B7 ${table.selector}`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${table.selector} (detected data table)`));\n item.append(pick);\n detectionsroot.append(item);\n shown += 1;\n }\n const paginationoutcome = latest(\"countpages\");\n if (paginationoutcome) {\n const item = document.createElement(\"li\");\n const current = typeof paginationoutcome.details?.current === \"number\" ? paginationoutcome.details?.current : 0;\n const total = typeof paginationoutcome.details?.total === \"number\" ? paginationoutcome.details?.total : 0;\n const text = document.createElement(\"span\");\n text.textContent = `pagination: current page ${current} \u00B7 estimated total ${total}`;\n item.append(text);\n detectionsroot.append(item);\n shown += 1;\n }\n if (shown === 0) detectionsroot.textContent = \"Detected lists, tables and pagination shapes appear here as plan suggestions.\";\n}\n\n/** Shows the live mutation and focus stream observed during watched steps. */\nfunction renderstream(mutationevents: mutationevent[], focusevents: focusevent[]): void {\n if (!streamroot) return;\n streamroot.replaceChildren();\n if (mutationevents.length === 0 && focusevents.length === 0) { streamroot.textContent = \"Watched steps stream their mutation and focus events here.\"; return; }\n for (const event of mutationevents.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 mutation ${event.event} \u00B7 ${event.targetpath}`;\n streamroot.append(item);\n }\n for (const event of focusevents.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 focus ${event.kind} \u00B7 ${event.targetpath}`;\n streamroot.append(item);\n }\n}\n\n/** Renders the latest snapshot diff with added, removed and changed rows. */\nfunction renderdiffs(diffs: snapshotdiff[]): void {\n if (!diffsroot) return;\n diffsroot.replaceChildren();\n const latest = diffs[0];\n if (!latest) { diffsroot.textContent = \"Diff two captured observation versions with a diffsnapshots step.\"; return; }\n const heading = document.createElement(\"p\");\n heading.textContent = `version ${latest.baseversion} \u2192 ${latest.targetversion}: ${latest.added.length} added \u00B7 ${latest.removed.length} removed \u00B7 ${latest.changed.length} changed`;\n diffsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const entry of [...latest.added, ...latest.removed, ...latest.changed].slice(0, 12)) {\n const item = document.createElement(\"li\");\n item.className = `diffrow ${entry.kind}`;\n item.textContent = `${entry.kind} \u00B7 ${entry.selector} \u00B7 ${entry.summary}`;\n list.append(item);\n }\n diffsroot.append(list);\n}\n\n/** Flags consent banners with a review card before any interaction. */\nfunction renderbanners(banners: bannerreport[]): void {\n if (!bannersroot) return;\n bannersroot.replaceChildren();\n if (banners.length === 0) { bannersroot.textContent = \"No consent banner has been observed yet.\"; return; }\n for (const banner of banners.slice(0, 3)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `${banner.kind} banner detected \u2014 review it before any interaction.`;\n const text = document.createElement(\"p\");\n text.textContent = banner.text.slice(0, 160) || \"(no banner text)\";\n const controls = document.createElement(\"p\");\n controls.textContent = `controls: ${banner.controls.length > 0 ? banner.controls.join(\", \") : \"none\"}`;\n card.append(title, text, controls);\n bannersroot.append(card);\n }\n}\n\n/** Shows derived selector candidates with their stability scores for reuse. */\nfunction renderselectors(selectors: derivedselector[]): void {\n if (!selectorsroot) return;\n selectorsroot.replaceChildren();\n if (selectors.length === 0) { selectorsroot.textContent = \"Run a deriveselector step to rank stable selectors.\"; return; }\n for (const record of selectors.slice(0, 8)) {\n const item = document.createElement(\"li\");\n const pick = document.createElement(\"button\");\n pick.type = \"button\";\n pick.textContent = `${record.selector} (${record.strategy} \u00B7 stability ${record.score})`;\n pick.addEventListener(\"click\", () => pickhint(`target hint: ${record.selector} (derived ${record.strategy} selector)`));\n item.append(pick);\n selectorsroot.append(item);\n }\n}\n\n/** Renders the navigation trail of the session as a timeline of visited urls. */\nfunction rendertrail(trail: trailentry[]): void {\n if (!trailroot) return;\n trailroot.replaceChildren();\n if (trail.length === 0) { trailroot.textContent = \"No page has been visited inside a reviewed navigation step yet.\"; return; }\n for (const entry of [...trail].reverse().slice(0, 12)) {\n const item = document.createElement(\"li\");\n item.textContent = `${new Date(entry.at).toLocaleTimeString()} \u00B7 ${entry.url}${entry.title ? ` \u00B7 ${entry.title}` : \"\"}${entry.stepid ? ` \u00B7 step ${entry.stepid}` : \"\"}`;\n trailroot.append(item);\n }\n}\n\n/** Renders the navigation state: paused navigation, rate limit windows per domain, wait profiles, redirect chains, curated lists, safety verdicts, artifacts and the basic auth prompt behind the consent gate. */\nfunction rendernavigation(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; navcontrol?: navcontrol; ratestates?: ratelimitstate[]; waitprofiles?: waitprofilerecord[]; navrecords?: navrecord[]; curated?: curatedlist[]; safeties?: safetyverdict[]; auths?: Array<{ origin: string; username: string; reviewedat: number }>; navqueues?: navqueues; artifacts?: artifactrecord[] }): void {\n if (!navigationroot) return;\n navigationroot.replaceChildren();\n const paused = document.createElement(\"p\");\n if (context.navcontrol?.pausedat) {\n paused.className = \"bannercard\";\n paused.textContent = `Navigation is paused while ${context.navcontrol.reason ?? \"a consent prompt is open\"}; reviewed navigation steps are blocked until it resumes.`;\n } else {\n paused.textContent = \"Navigation is live; no consent prompt holds it.\";\n }\n navigationroot.append(paused);\n const rates = context.ratestates ?? [];\n if (rates.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"rate limit windows per domain:\";\n navigationroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const state of rates.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${state.domain}: ${state.count} of ${state.limit.ceiling} navigations inside the reviewed window of ${state.limit.window} ms`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const records = context.navrecords ?? [];\n const record = records[0];\n if (record) {\n const chain = document.createElement(\"p\");\n chain.textContent = `latest navigation: ${Math.max(0, record.chain.hops.length - 1)} redirect${record.chain.hops.length - 1 === 1 ? \"\" : \"s\"} \u00B7 final url ${record.finalurl}`;\n navigationroot.append(chain);\n const hops = document.createElement(\"ul\");\n for (const hop of record.chain.hops.slice(0, 6)) {\n const item = document.createElement(\"li\");\n let path = hop.url;\n try { path = new URL(hop.url).pathname; } catch { path = hop.url; }\n item.textContent = `hop ${path} \u00B7 status ${hop.status} \u00B7 ${new Date(hop.at).toLocaleTimeString()}`;\n hops.append(item);\n }\n navigationroot.append(hops);\n }\n const curatedlists = context.curated ?? [];\n if (curatedlists.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"curated link lists with per url safety states:\";\n navigationroot.append(heading);\n for (const list of curatedlists.slice(0, 3)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `${list.links.length} curated url${list.links.length === 1 ? \"\" : \"s\"}${list.reviewedat ? \" \u00B7 opened after review\" : \" \u00B7 waiting for review\"}`;\n card.append(title);\n for (const link of list.links.slice(0, 8)) {\n const line = document.createElement(\"p\");\n line.textContent = `${link.verdict === \"safe\" ? \"\u2713\" : \"\u2717\"} ${link.url}${link.reasons.length > 0 ? ` \u00B7 ${link.reasons.join(\"; \")}` : \"\"}`;\n card.append(line);\n }\n navigationroot.append(card);\n }\n }\n const safeties = context.safeties ?? [];\n const runner = document.createElement(\"p\");\n const checkinput = document.createElement(\"input\");\n checkinput.type = \"url\";\n checkinput.placeholder = \"https://external.example/link\";\n checkinput.setAttribute(\"aria-label\", \"url to verify with checksafe\");\n const checkbutton = button(\"Run checksafe\", async () => {\n const verdict = await request({ kind: \"checksafe\", url: checkinput.value }) as safetyverdict;\n status(verdict.safe ? `${verdict.url} passed every safety check.` : `${verdict.url} is unsafe: ${verdict.reasons.join(\"; \")}.`);\n await refresh();\n });\n runner.append(checkinput, \" \", checkbutton);\n navigationroot.append(runner);\n if (safeties.length > 0) {\n const list = document.createElement(\"ul\");\n for (const verdict of safeties.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${verdict.safe ? \"safe\" : \"unsafe\"} \u00B7 ${verdict.url}${verdict.reasons.length > 0 ? ` \u00B7 ${verdict.reasons.join(\"; \")}` : \"\"}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const authcard = document.createElement(\"div\");\n authcard.className = \"bannercard\";\n const authtitle = document.createElement(\"p\");\n authtitle.textContent = active ? \"basic auth credentials (stored only after your explicit review):\" : \"basic auth credentials need an active session before they can be reviewed.\";\n authcard.append(authtitle);\n if (active) {\n const origininput = document.createElement(\"input\");\n origininput.type = \"url\";\n origininput.placeholder = context.session?.origin ?? \"https://example.com\";\n origininput.setAttribute(\"aria-label\", \"auth origin\");\n const userinput = document.createElement(\"input\");\n userinput.type = \"text\";\n userinput.placeholder = \"username\";\n userinput.setAttribute(\"aria-label\", \"auth username\");\n const passinput = document.createElement(\"input\");\n passinput.type = \"password\";\n passinput.placeholder = \"password\";\n passinput.setAttribute(\"aria-label\", \"auth password\");\n const storebutton = button(\"Store reviewed credentials\", async () => {\n const stored = await request({ kind: \"storeauth\", origin: origininput.value, username: userinput.value, password: passinput.value }) as { origin: string };\n status(`Reviewed basic auth credentials stored for ${stored.origin}.`);\n await refresh();\n });\n authcard.append(origininput, \" \", userinput, \" \", passinput, \" \", storebutton);\n }\n navigationroot.append(authcard);\n const auths = context.auths ?? [];\n if (auths.length > 0) {\n const list = document.createElement(\"ul\");\n for (const record of auths.slice(0, 4)) {\n const item = document.createElement(\"li\");\n item.textContent = `basic auth for ${record.origin} as ${record.username}, reviewed ${new Date(record.reviewedat).toLocaleString()}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n const artifacts = context.artifacts ?? [];\n if (artifacts.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"task artifacts:\";\n navigationroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const artifact of artifacts.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${artifact.kind}: ${artifact.name} \u00B7 step ${artifact.stepid}`;\n list.append(item);\n }\n navigationroot.append(list);\n }\n}\n\n/** Renders the tabs and windows command surface: quick switcher, groups, badges, audio state, layouts, snapshots, clone warnings, the task tab budget gauge and the pinned control tab feed. */\nfunction rendertabswindows(context: { session?: { stoppedat?: number; expiresat: number }; plan?: agentplan; progress?: planprogress; tabs?: tabshape[]; windows?: windowshape[]; tabgroups?: tabgrouprecord[]; badges?: tabbadge[]; tabmetas?: tabmeta[]; clones?: Array<{ url: string; tabids: number[] }>; layouts?: tablayout[]; snapshots?: sessionsnapshot[]; closedtabs?: closedtab[]; tasktabgauge?: { used: number; ceiling?: number; over: boolean }; controltab?: controltabstate }): void {\n if (!tabswindowsroot) return;\n tabswindowsroot.replaceChildren();\n const tabs = context.tabs ?? [];\n const badges = context.badges ?? [];\n const metas = context.tabmetas ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const gauge = context.tasktabgauge ?? { used: 0, ceiling: undefined, over: false };\n const budget = document.createElement(\"p\");\n budget.className = gauge.over ? \"bannercard\" : \"\";\n budget.textContent = `task tab budget: ${gauge.used} tab${gauge.used === 1 ? \"\" : \"s\"} with active tasks${gauge.ceiling !== undefined ? ` of the user configured ceiling ${gauge.ceiling}` : \" with no user ceiling configured\"}${gauge.over ? \" \u2014 over the reviewed budget\" : \"\"}`;\n tabswindowsroot.append(budget);\n const ceilinginput = document.createElement(\"input\");\n ceilinginput.type = \"number\";\n ceilinginput.min = \"0\";\n ceilinginput.placeholder = gauge.ceiling !== undefined ? String(gauge.ceiling) : \"no ceiling\";\n ceilinginput.setAttribute(\"aria-label\", \"concurrent task tab ceiling\");\n const ceilingbutton = button(\"Save task tab ceiling\", async () => {\n await request({ kind: \"settasktabceiling\", ceiling: ceilinginput.value === \"\" ? undefined : Number(ceilinginput.value) });\n status(`Task tab ceiling saved as ${ceilinginput.value === \"\" ? \"no ceiling\" : ceilinginput.value}; the value stays a user choice.`);\n await refresh();\n });\n tabswindowsroot.append(ceilinginput, \" \", ceilingbutton);\n const switcherheading = document.createElement(\"p\");\n switcherheading.textContent = \"quick switcher (ordered by recency, filter by title or url):\";\n tabswindowsroot.append(switcherheading);\n const filterinput = document.createElement(\"input\");\n filterinput.type = \"search\";\n filterinput.placeholder = \"filter open tabs\";\n filterinput.setAttribute(\"aria-label\", \"quick switcher filter\");\n const switchlist = document.createElement(\"ul\");\n const renderswitchlist = (): void => {\n switchlist.replaceChildren();\n const ordered = switcherlist(tabs, [], filterinput.value).slice(0, 10);\n for (const tab of ordered) {\n const item = document.createElement(\"li\");\n const jump = document.createElement(\"button\");\n jump.type = \"button\";\n const badge = badges.find(entry => entry.tabid === tab.tabid);\n const meta = metas.find(entry => entry.tabid === tab.tabid);\n jump.textContent = `${tab.title || tab.url}${tab.pinned ? \" \uD83D\uDCCC\" : \"\"}${tab.audible || tab.muted ? ` ${tab.muted ? \"\uD83D\uDD07\" : \"\uD83D\uDD0A\"}` : \"\"}${badge ? ` [${badge.label}]` : \"\"}${meta && meta.labels.length > 0 ? ` (${meta.labels.join(\", \")})` : \"\"}`;\n jump.addEventListener(\"click\", () => request({ kind: \"jumptotab\", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch(error => status(error instanceof Error ? error.message : String(error), true)));\n item.append(jump);\n switchlist.append(item);\n }\n if (ordered.length === 0) { const empty = document.createElement(\"li\"); empty.textContent = \"no open tab matches the filter\"; switchlist.append(empty); }\n };\n filterinput.addEventListener(\"input\", renderswitchlist);\n tabswindowsroot.append(filterinput, switchlist);\n renderswitchlist();\n const searchinput = document.createElement(\"input\");\n searchinput.type = \"search\";\n searchinput.placeholder = \"search across open tabs by title and url\";\n searchinput.setAttribute(\"aria-label\", \"searchtabs text\");\n const searchresults = document.createElement(\"ul\");\n const searchbutton = button(\"Run searchtabs\", async () => {\n const result = await request({ kind: \"tabsearch\", text: searchinput.value }) as { matches: tabshape[] };\n searchresults.replaceChildren();\n for (const tab of result.matches.slice(0, 10)) {\n const item = document.createElement(\"li\");\n const jump = document.createElement(\"button\");\n jump.type = \"button\";\n jump.textContent = `${tab.title || tab.url} \u00B7 ${tab.url}`;\n jump.addEventListener(\"click\", () => request({ kind: \"jumptotab\", tabid: tab.tabid }).then(() => status(`Jumped to tab ${tab.tabid}.`)).catch(error => status(error instanceof Error ? error.message : String(error), true)));\n item.append(jump);\n searchresults.append(item);\n }\n status(`searchtabs matched ${result.matches.length} open tab${result.matches.length === 1 ? \"\" : \"s\"}.`);\n });\n tabswindowsroot.append(searchinput, \" \", searchbutton, searchresults);\n const clones = context.clones ?? [];\n for (const clone of clones.slice(0, 3)) {\n const warning = document.createElement(\"p\");\n warning.className = \"bannercard\";\n warning.textContent = `duplicate tab warning: ${clone.tabids.length} open tabs share the url ${clone.url} (tabs ${clone.tabids.join(\", \")})`;\n tabswindowsroot.append(warning);\n }\n const groups = context.tabgroups ?? [];\n if (groups.length > 0) {\n const groupsheading = document.createElement(\"p\");\n groupsheading.textContent = \"tab groups with colors and collapse states:\";\n tabswindowsroot.append(groupsheading);\n const grouplist = document.createElement(\"ul\");\n for (const group of groups.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${group.name} \u00B7 ${group.color} \u00B7 ${group.collapsed ? \"collapsed\" : \"expanded\"} \u00B7 ${group.tabids.length} member tab${group.tabids.length === 1 ? \"\" : \"s\"}`;\n grouplist.append(item);\n }\n tabswindowsroot.append(grouplist);\n }\n const windows = context.windows ?? [];\n if (windows.length > 0) {\n const windowsheading = document.createElement(\"p\");\n windowsheading.textContent = \"windows with layouts and bounds:\";\n tabswindowsroot.append(windowsheading);\n const windowlist = document.createElement(\"ul\");\n for (const item of windows.slice(0, 6)) {\n const entry = document.createElement(\"li\");\n entry.textContent = `window ${item.windowid} \u00B7 ${item.state} \u00B7 bounds ${item.left}\u00D7${item.top} ${item.width}\u00D7${item.height}${item.incognito ? \" \u00B7 incognito, grants not inherited\" : \"\"}${item.focused ? \" \u00B7 focused\" : \"\"}`;\n const closebutton = button(\"Close window\", async () => {\n const tasktabids = (context.progress?.tasktabs ?? []);\n const tabsoftask = (context.tabs ?? []).filter(tab => tab.windowid === item.windowid && tasktabids.includes(tab.tabid));\n const reviewed = tabsoftask.length > 1 ? window.confirm(`This window holds ${tabsoftask.length} task tabs. Close it anyway under explicit review?`) : true;\n await request({ kind: \"closewindow\", windowid: item.windowid, reviewed });\n status(`Closed window ${item.windowid}.`);\n await refresh();\n });\n entry.append(\" \", closebutton);\n windowlist.append(entry);\n }\n tabswindowsroot.append(windowlist);\n }\n const layoutcontrols = document.createElement(\"p\");\n const layoutname = document.createElement(\"input\");\n layoutname.type = \"text\";\n layoutname.placeholder = \"layout name\";\n layoutname.setAttribute(\"aria-label\", \"layout name\");\n const savebutton = button(\"Save layout\", async () => {\n if (!active) { status(\"Layout save stays inside an active session.\", true); return; }\n await request({ kind: \"savelayout\", name: layoutname.value });\n status(`Saved the tab layout ${layoutname.value}.`);\n await refresh();\n });\n const restorebutton = button(\"Restore layout\", async () => {\n if (!active) { status(\"Layout restore stays inside an active session.\", true); return; }\n const result = await request({ kind: \"restorelayout\", name: layoutname.value }) as { reopened: number };\n status(`Restored the tab layout ${layoutname.value}: ${result.reopened} tab${result.reopened === 1 ? \"\" : \"s\"} reopened.`);\n await refresh();\n });\n layoutcontrols.append(layoutname, \" \", savebutton, \" \", restorebutton);\n tabswindowsroot.append(layoutcontrols);\n const layouts = context.layouts ?? [];\n if (layouts.length > 0) {\n const layoutlist = document.createElement(\"ul\");\n for (const layout of layouts.slice(0, 4)) {\n const item = document.createElement(\"li\");\n item.textContent = `${layout.name} \u00B7 ${layout.tabs.length} tab${layout.tabs.length === 1 ? \"\" : \"s\"} \u00B7 ${layout.groups.length} group${layout.groups.length === 1 ? \"\" : \"s\"} \u00B7 ${layout.windows.length} window bound${layout.windows.length === 1 ? \"\" : \"s\"} \u00B7 saved ${new Date(layout.savedat).toLocaleString()}`;\n layoutlist.append(item);\n }\n tabswindowsroot.append(layoutlist);\n }\n const snapshots = context.snapshots ?? [];\n if (snapshots.length > 0) {\n const snapcard = document.createElement(\"div\");\n snapcard.className = \"bannercard\";\n const snaptitle = document.createElement(\"p\");\n snaptitle.textContent = `session snapshot card: ${snapshots.length} snapshot${snapshots.length === 1 ? \"\" : \"s\"} stored`;\n snapcard.append(snaptitle);\n for (const snapshot of snapshots.slice(0, 3)) {\n const row = document.createElement(\"p\");\n row.textContent = `${snapshot.layout.tabs.length} tabs \u00B7 captured ${new Date(snapshot.capturedat).toLocaleString()}`;\n const restore = button(\"Restore snapshot\", async () => {\n const result = await request({ kind: \"restoresnapshot\", id: snapshot.id }) as { reopened: number };\n status(`Restored the session snapshot: ${result.reopened} tab${result.reopened === 1 ? \"\" : \"s\"} reopened.`);\n await refresh();\n });\n row.append(\" \", restore);\n snapcard.append(row);\n }\n tabswindowsroot.append(snapcard);\n }\n const controlcard = document.createElement(\"div\");\n controlcard.className = \"bannercard\";\n const controlstate = context.controltab;\n const completed = context.progress?.completedsteps.length ?? 0;\n const total = context.plan?.steps.length ?? 0;\n controlcard.textContent = `pinned control tab feed: ${controlstate?.enabled ? `open as tab ${controlstate.tabid} with the live task status ${completed} of ${total} reviewed steps executed` : \"disabled\"}${context.plan ? ` \u00B7 ${context.plan.state}` : \" \u00B7 no plan\"}`;\n const controlbutton = button(controlstate?.enabled ? \"Close pinned control tab\" : \"Open pinned control tab\", async () => {\n await request({ kind: \"controltab\", enabled: !controlstate?.enabled });\n status(controlstate?.enabled ? \"The pinned control tab was closed.\" : \"The pinned control tab was opened with the live task feed.\");\n await refresh();\n });\n controlcard.append(\" \", controlbutton);\n tabswindowsroot.append(controlcard);\n}\n\n/** Renders the forms and data surface: the form map, generated values, saved profiles, asksubmit cards with the values diff, wizard progress, inline error reports, honeypot skips, template badges, the consent gated code entry and masked card fills. */\nfunction renderforms(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; plan?: agentplan; outcomes?: stepoutcome[]; profiles?: formprofile[]; tickets?: submitticket[]; wizards?: { wizards: wizardstate[]; picks: typeaheadpick[] }; errorreports?: errorreport[]; captchas?: captchahandoff[]; detections?: detectionrecord[]; codeentry?: boolean }): void {\n if (!formsroot) return;\n formsroot.replaceChildren();\n const outcomes = context.outcomes ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const opencaptcha = (context.captchas ?? []).find(handoff => !handoff.resolved);\n if (opencaptcha) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n card.textContent = `Captcha handoff open on ${opencaptcha.origin}: control is yours and the plan waits until you resolve it.`;\n card.append(\" \", button(\"Captcha resolved\", async () => { await request({ kind: \"resolvecaptcha\" }); status(\"Captcha handoff resolved; the plan continues.\"); await refresh(); }));\n formsroot.append(card);\n }\n const detections = context.detections ?? [];\n if (detections.length > 0) {\n const badges = document.createElement(\"p\");\n badges.textContent = `template badges: ${detections.slice(0, 6).map(record => `${record.kind} on ${record.origin}${record.markers.length > 0 ? ` (${record.markers.join(\", \")})` : \"\"}`).join(\" \u00B7 \")}`;\n formsroot.append(badges);\n }\n const mapoutcome = [...outcomes].reverse().find(outcome => outcome.details?.report !== undefined && outcome.details?.count !== undefined);\n const skippedselectors = new Set(outcomes.flatMap(outcome => Array.isArray(outcome.details?.skipped) ? outcome.details?.skipped as Array<{ selector: string }> : []).map(trap => trap.selector));\n if (mapoutcome) {\n const report = mapoutcome.details?.report as { form: string; fields: Array<{ selector: string; label: string; kind: string; matched: boolean }> };\n const heading = document.createElement(\"p\");\n heading.textContent = `form map${report.form ? ` of ${report.form}` : \"\"}: ${report.fields.length} detected field${report.fields.length === 1 ? \"\" : \"s\"} with their kinds${skippedselectors.size > 0 ? `; ${skippedselectors.size} honeypot field${skippedselectors.size === 1 ? \"\" : \"s\"} highlighted as skipped` : \"\"}`;\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const field of report.fields.slice(0, 10)) {\n const item = document.createElement(\"li\");\n const skipped = skippedselectors.has(field.selector);\n item.textContent = `${field.label || field.selector} \u00B7 ${field.kind}${field.matched ? \"\" : \" \u00B7 unmatched\"}${skipped ? \" \u00B7 honeypot, skipped\" : \"\"}`;\n list.append(item);\n }\n formsroot.append(list);\n }\n const valuesoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.values) && outcome.details?.locale !== undefined);\n if (valuesoutcome) {\n const values = valuesoutcome.details?.values as Array<{ label: string; kind: string; value: string }>;\n const locale = typeof valuesoutcome.details?.locale === \"string\" ? valuesoutcome.details.locale : \"en\";\n const seed = typeof valuesoutcome.details?.seed === \"number\" ? valuesoutcome.details.seed : 1;\n const heading = document.createElement(\"p\");\n heading.textContent = `generated values (locale ${locale}, seed ${seed}) with a regenerate button per field:`;\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const entry of values.slice(0, 10)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.label} \u00B7 ${entry.kind} \u00B7 ${entry.value}`;\n item.append(\" \", button(\"Regenerate\", async () => {\n const regenerated = await request({ kind: \"regeneratevalue\", field: entry.kind, locale, seed: seed + 1 }) as { value: string };\n status(`Regenerated ${entry.label}: ${regenerated.value}.`);\n }));\n list.append(item);\n }\n formsroot.append(list);\n }\n const cardoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.segments));\n if (cardoutcome) {\n const segments = cardoutcome.details?.segments as Array<{ label: string; masked: string }>;\n const cardline = document.createElement(\"p\");\n cardline.textContent = `card fill segments (masked): ${segments.map(segment => `${segment.label} ${cardmask(segment.masked)}`).join(\" \u00B7 \")}`;\n formsroot.append(cardline);\n }\n const profiles = context.profiles ?? [];\n if (profiles.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"saved form profiles with origin grants:\";\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const profile of profiles.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${profile.name} \u00B7 ${profile.fields.length} field${profile.fields.length === 1 ? \"\" : \"s\"} \u00B7 grants ${profile.grants.join(\", \")} \u00B7 saved ${new Date(profile.savedat).toLocaleString()}`;\n item.append(\" \", button(\"Apply\", async () => {\n const applied = await request({ kind: \"applyprofile\", name: profile.name }) as { profile: { fields: unknown[] } };\n pickhint(`profile hint: ${profile.name} with ${applied.profile.fields.length} reviewed field entries`);\n }), \" \", button(\"Remove\", async () => {\n await request({ kind: \"removeprofile\", name: profile.name });\n status(`Form profile ${profile.name} removed.`);\n await refresh();\n }));\n list.append(item);\n }\n formsroot.append(list);\n }\n const pending = (context.tickets ?? []).filter(ticket => ticket.approved === undefined);\n for (const ticket of pending) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n const title = document.createElement(\"p\");\n title.textContent = `asksubmit for form ${ticket.form || \"the reviewed form\"} \u00B7 values hash ${ticket.valueshash}`;\n card.append(title);\n const askoutcome = [...outcomes].reverse().find(outcome => Array.isArray(outcome.details?.values) && outcome.details?.ticket !== undefined);\n const values = askoutcome?.details?.values as Array<{ label: string; value: string }> | undefined;\n if (values) {\n const diff = document.createElement(\"ul\");\n for (const entry of values.slice(0, 10)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.label}: ${entry.value}`;\n diff.append(item);\n }\n card.append(diff);\n } else {\n const note = document.createElement(\"p\");\n note.textContent = \"The full values diff appears here once the asksubmit step reads the form.\";\n card.append(note);\n }\n card.append(button(\"Approve submission\", async () => { await request({ kind: \"approvesubmit\", id: ticket.id, approved: true }); status(\"Submission approved; the reviewed submitform step may run.\"); await refresh(); }), \" \", button(\"Decline\", async () => { await request({ kind: \"approvesubmit\", id: ticket.id, approved: false }); status(\"Submission declined.\"); await refresh(); }));\n formsroot.append(card);\n }\n const wizards = context.wizards?.wizards ?? [];\n if (wizards.length > 0) {\n const wizard = wizards[0] as wizardstate;\n const heading = document.createElement(\"p\");\n const indicators = Array.from({ length: wizard.steps }, (_, index) => `${index < wizard.index ? (wizard.completed[index] ? \"\u2713\" : \"\u00B7\") : \"\u25CB\"}`).join(\" \");\n heading.textContent = `wizard progress: step ${Math.min(wizard.index + 1, wizard.steps)} of ${wizard.steps} ${indicators}`;\n formsroot.append(heading);\n }\n const picks = context.wizards?.picks ?? [];\n if (picks.length > 0) {\n const pickline = document.createElement(\"p\");\n pickline.textContent = `typeahead picks: ${picks.slice(0, 6).map(pick => `\"${pick.pick}\" for \"${pick.query}\"`).join(\" \u00B7 \")}`;\n formsroot.append(pickline);\n }\n const reports = context.errorreports ?? [];\n if (reports.length > 0) {\n const heading = document.createElement(\"p\");\n heading.textContent = \"inline error reports with field refs for correction loops:\";\n formsroot.append(heading);\n const list = document.createElement(\"ul\");\n for (const report of reports.slice(0, 3)) {\n const item = document.createElement(\"li\");\n item.textContent = `${report.form || \"the reviewed form\"}: ${report.errors.map((error: fielderror) => `${error.field} \u2014 ${error.message}`).join(\"; \") || \"no message\"}`;\n list.append(item);\n }\n formsroot.append(list);\n }\n const codecard = document.createElement(\"div\");\n codecard.className = \"bannercard\";\n const codetitle = document.createElement(\"p\");\n codetitle.textContent = active ? \"one time code entry (stored behind the consent gate of the active session):\" : \"one time code entry needs an active session first.\";\n codecard.append(codetitle);\n if (active) {\n const codeinput = document.createElement(\"input\");\n codeinput.type = \"text\";\n codeinput.inputMode = \"numeric\";\n codeinput.placeholder = context.codeentry ? \"a reviewed code is stored\" : \"one time code\";\n codeinput.setAttribute(\"aria-label\", \"one time code\");\n const storebutton = button(\"Store reviewed code\", async () => {\n await request({ kind: \"storecode\", code: codeinput.value });\n status(\"The reviewed one time code is stored behind the consent gate.\");\n await refresh();\n });\n codecard.append(codeinput, \" \", storebutton);\n }\n formsroot.append(codecard);\n}\n\n/** Renders the dataset surfaces: the preview grid with sortable columns, extraction progress cards with resume prompts, export actions per dataset, transform rule previews, dedupe results, provenance records, import pickers and sheet endpoint grant states. */\nfunction renderdatasets(context: { session?: { stoppedat?: number; expiresat: number }; plan?: agentplan; outcomes?: stepoutcome[]; datasets?: dataset[]; imports?: dataset[]; extractsessions?: extractsession[]; streams?: streamstate[]; exports?: Array<{ id: string; kind: string; name: string; rowcount: number; checksum: string; at: number }>; provenances?: provenancerecord[]; taskrules?: taskrules[]; sheetendpoints?: Array<{ endpoint: string; origin: string; configuredat: number; granted: boolean }> }): void {\n if (!datasetsroot) return;\n datasetsroot.replaceChildren();\n const outcomes = context.outcomes ?? [];\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const extractsessions = context.extractsessions ?? [];\n for (const extract of extractsessions.slice(0, 4)) {\n const card = document.createElement(\"p\");\n const interrupted = extract.done !== true;\n card.textContent = `extraction ${extract.name}: ${extract.pages.length} page${extract.pages.length === 1 ? \"\" : \"s\"} visited \u00B7 ${extract.rows} row${extract.rows === 1 ? \"\" : \"s\"} collected \u00B7 cursor ${extract.cursor} of ${extract.planned}${extract.done ? \" \u00B7 complete\" : \" \u00B7 interrupted\"}`;\n datasetsroot.append(card);\n }\n const interrupted = extractsessions.find(extract => extract.done !== true);\n if (interrupted && active) {\n const prompt = document.createElement(\"div\");\n prompt.className = \"bannercard\";\n prompt.textContent = `Extraction ${interrupted.name} was interrupted at cursor ${interrupted.cursor}; run its resumeextract reviewed step to continue from the stored cursor.`;\n datasetsroot.append(prompt);\n }\n const streams = context.streams ?? [];\n if (streams.length > 0) {\n const stream = streams[0]!;\n const card = document.createElement(\"p\");\n card.textContent = `stream state: ${stream.name} chunk ${stream.chunk} of ${stream.chunks} \u00B7 ${stream.written} row${stream.written === 1 ? \"\" : \"s\"} written${stream.done ? \" \u00B7 complete\" : \" \u00B7 resumable\"}`;\n datasetsroot.append(card);\n }\n const rules = (context.taskrules ?? [])[0];\n if (rules && rules.transforms.length > 0) {\n const transforms = document.createElement(\"p\");\n transforms.textContent = `transform rules: ${rules.transforms.map(rule => `${rule.sources.join(\"+\")} \u2192 ${rule.target} (${rule.expression})`).join(\" \u00B7 \")}`;\n datasetsroot.append(transforms);\n }\n if (rules && rules.dedupekeys.length > 0) {\n const keys = document.createElement(\"p\");\n keys.textContent = `dedupe keys: ${rules.dedupekeys.join(\", \")}`;\n datasetsroot.append(keys);\n }\n const dedupeoutcome = [...outcomes].reverse().find(outcome => outcome.details?.dedupe !== undefined);\n if (dedupeoutcome) {\n const dedupe = dedupeoutcome.details?.dedupe as { removed: number; kept: number; keys: string[] };\n const card = document.createElement(\"p\");\n card.textContent = `last dedupe: removed ${dedupe.removed} duplicate row${dedupe.removed === 1 ? \"\" : \"s\"}, kept ${dedupe.kept} by ${dedupe.keys.join(\", \")}`;\n datasetsroot.append(card);\n }\n for (const datasetvalue of (context.datasets ?? []).slice(0, 4)) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n head.textContent = `dataset ${datasetvalue.name}: ${datasetvalue.rows.length} row${datasetvalue.rows.length === 1 ? \"\" : \"s\"} \u00B7 ${datasetvalue.columns.length} column${datasetvalue.columns.length === 1 ? \"\" : \"s\"}${(context.imports ?? []).some(item => item.id === datasetvalue.id) ? \" \u00B7 imported csv\" : \"\"}`;\n card.append(head);\n const grid = document.createElement(\"table\");\n const headerrow = document.createElement(\"tr\");\n for (const column of datasetvalue.columns.slice(0, 6)) {\n const cell = document.createElement(\"th\");\n cell.textContent = `${column.label || column.key} ${column.kind === \"number\" ? \"#\" : \"\"}`;\n cell.addEventListener(\"click\", () => {\n const body = grid.querySelector(\"tbody\");\n if (!body) return;\n const sorted = sortrows(datasetvalue.rows.slice(0, 5), column.key, cell.dataset.sorted === \"asc\" ? \"desc\" : \"asc\");\n cell.dataset.sorted = cell.dataset.sorted === \"asc\" ? \"desc\" : \"asc\";\n body.replaceChildren(...sorted.map(row => {\n const line = document.createElement(\"tr\");\n for (const columnspec of datasetvalue.columns.slice(0, 6)) {\n const value = document.createElement(\"td\");\n value.textContent = row[columnspec.key] ?? \"\";\n line.append(value);\n }\n return line;\n }));\n });\n headerrow.append(cell);\n }\n grid.append(headerrow);\n const body = document.createElement(\"tbody\");\n for (const row of datasetvalue.rows.slice(0, 5)) {\n const line = document.createElement(\"tr\");\n for (const column of datasetvalue.columns.slice(0, 6)) {\n const cell = document.createElement(\"td\");\n cell.textContent = row[column.key] ?? \"\";\n line.append(cell);\n }\n body.append(line);\n }\n grid.append(body);\n card.append(grid);\n if (active) {\n const actions = document.createElement(\"p\");\n for (const format of [\"csv\", \"json\", \"excel\"] as const) {\n actions.append(\" \", button(`Export ${format}`, async () => {\n const artifact = await request({ kind: \"exportdataset\", datasetid: datasetvalue.id, format }) as { name: string; checksum: string };\n status(`Exported ${datasetvalue.name} to ${artifact.name} with checksum ${artifact.checksum}.`);\n await refresh();\n }));\n }\n card.append(actions);\n }\n datasetsroot.append(card);\n }\n const provenances = context.provenances ?? [];\n if (provenances.length > 0) {\n const list = document.createElement(\"ul\");\n for (const record of provenances.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.name}: rows ${record.rowstart}\u2013${record.rowend} \u00B7 checksum ${record.checksum} \u00B7 source ${record.url}`;\n list.append(item);\n }\n datasetsroot.append(list);\n }\n const sheetendpoints = context.sheetendpoints ?? [];\n if (sheetendpoints.length > 0) {\n const sheets = document.createElement(\"p\");\n sheets.textContent = `sheet endpoints: ${sheetendpoints.map(config => `${config.origin} ${config.granted ? \"granted\" : \"not granted\"}`).join(\" \u00B7 \")}`;\n datasetsroot.append(sheets);\n }\n if (active) {\n const importer = document.createElement(\"div\");\n importer.className = \"panel\";\n const csvinput = document.createElement(\"textarea\");\n csvinput.rows = 3;\n csvinput.placeholder = \"Paste reviewed csv content for a fill loop (header line first).\";\n const nameinput = document.createElement(\"input\");\n nameinput.placeholder = \"dataset name (optional)\";\n const mappinginput = document.createElement(\"input\");\n mappinginput.placeholder = \"column mapping json (optional, csv header \u2192 target)\";\n importer.append(csvinput, nameinput, mappinginput, \" \", button(\"Import csv\", async () => {\n let mapping: Record<string, string> = {};\n if (mappinginput.value.trim()) {\n try { mapping = JSON.parse(mappinginput.value) as Record<string, string>; } catch { status(\"The column mapping must be a json object.\", true); return; }\n }\n const imported = await request({ kind: \"importcsv\", csv: csvinput.value, name: nameinput.value, mapping }) as { name: string; rows: number };\n status(`Imported ${imported.rows} rows as dataset ${imported.name} for fill loops.`);\n await refresh();\n }));\n datasetsroot.append(importer);\n }\n}\n\n/** Renders the files, clipboard and downloads surface: the batch download queue with per file states and pause, resume and verify actions, mime interception rules with origin grants, clipboard consent prompts with the requesting step, the netlog viewer with step correlation filters and redaction notices, the quarantine list with scan verdicts and release actions, capture naming previews, cleanup policy editing, artifact inventories and copyscreen results. */\nfunction renderfiles(context: { session?: { stoppedat?: number; expiresat: number; origin?: string }; plan?: agentplan; downloads?: downloadrecord[]; mimefilters?: mimefilter[]; clipconsents?: clipboardconsentrecord[]; clips?: clipentry[]; netlogs?: netlogrecord[]; quarantines?: quarantineentry[]; capturecounters?: Array<{ taskid: string; counters: Record<string, number>; at: number }>; cleanuprules?: cleanuprule[]; cleanupruns?: cleanuprun[]; inventory?: artifactinventoryentry[]; scanhooks?: Array<{ scanner: string; endpoint: string; origin: string; configuredat: number; granted: boolean }> }): void {\n if (!filesroot) return;\n filesroot.replaceChildren();\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const downloads = context.downloads ?? [];\n if (downloads.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n const states = [\"queued\", \"running\", \"paused\", \"complete\", \"failed\"] as const;\n head.textContent = `batch download queue: ${downloads.length} file${downloads.length === 1 ? \"\" : \"s\"} (${states.map(state => `${downloads.filter(item => item.state === state).length} ${state}`).filter(part => !part.startsWith(\"0 \")).join(\" \u00B7 \") || \"none\"})`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const record of downloads.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.filename} \u00B7 ${record.state}${record.bytes !== undefined ? ` \u00B7 ${record.bytes} bytes` : \"\"}${record.checksum !== undefined ? ` \u00B7 checksum ${record.checksum}` : \"\"}${record.path !== undefined ? ` \u00B7 ${record.path}` : \"\"}`;\n if (active) {\n item.append(\" \", button(\"Pause\", () => request({ kind: \"downloadaction\", id: record.id, action: \"pause\" }).then(() => refresh()).then(() => status(`Paused the download of ${record.filename}.`)), record.state !== \"running\"));\n item.append(\" \", button(\"Resume\", () => request({ kind: \"downloadaction\", id: record.id, action: \"resume\" }).then(() => refresh()).then(() => status(`Resumed the download of ${record.filename}.`)), record.state !== \"paused\"));\n item.append(\" \", button(\"Verify\", () => request({ kind: \"downloadaction\", id: record.id, action: \"verify\" }).then(value => { const output = value as { summary: string }; status(output.summary); return refresh(); })));\n }\n list.append(item);\n }\n card.append(list);\n filesroot.append(card);\n }\n const filters = context.mimefilters ?? [];\n if (filters.length > 0) {\n const filter = filters[0]!;\n const card = document.createElement(\"p\");\n card.textContent = `mime interception: include ${filter.include.join(\", \")} \u00B7 exclude ${filter.exclude.join(\", \") || \"none\"} \u00B7 ${filter.default} default for unlisted mime types${context.session?.origin ? ` \u00B7 armed inside the ${context.session.origin} origin grants` : \"\"}`;\n filesroot.append(card);\n }\n const consents = (context.clipconsents ?? []).filter(record => record.approved === undefined);\n for (const consent of consents.slice(0, 4)) {\n const card = document.createElement(\"div\");\n card.className = \"bannercard\";\n card.textContent = `Clipboard read consent ${consent.id} waits for your approval: step ${consent.stepid} on ${consent.origin} asked to read the clipboard \u2014 \"${consent.prompt}\".`;\n if (active) {\n card.append(\" \", button(\"Approve read\", async () => { await request({ kind: \"approveclipconsent\", id: consent.id, approved: true }); status(`Clipboard read consent ${consent.id} approved; run the step again to read once.`); await refresh(); }));\n card.append(\" \", button(\"Decline\", async () => { await request({ kind: \"approveclipconsent\", id: consent.id, approved: false }); status(`Clipboard read consent ${consent.id} declined.`); await refresh(); }));\n }\n filesroot.append(card);\n }\n const netlogs = context.netlogs ?? [];\n if (netlogs.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n const steps = [...new Set(netlogs.map(record => record.stepid))];\n head.textContent = `network log: ${netlogs.length} record${netlogs.length === 1 ? \"\" : \"s\"} correlated with ${steps.length} step${steps.length === 1 ? \"\" : \"s\"} (${steps.slice(0, 4).join(\", \")}${steps.length > 4 ? \"\u2026\" : \"\"})`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const record of netlogs.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${record.method} ${record.url} \u00B7 ${record.status} \u00B7 ${record.timing}ms \u00B7 request ${record.requestid ?? \"?\"} \u00B7 step ${record.stepid}`;\n list.append(item);\n }\n card.append(list);\n if (active) card.append(button(\"Export netlog (header values redacted)\", async () => { const exported = await request({ kind: \"exportnetlog\" }) as { records: unknown[]; redaction: string }; status(`Exported ${exported.records.length} netlog records; ${exported.redaction}.`); }));\n filesroot.append(card);\n }\n const quarantines = context.quarantines ?? [];\n if (quarantines.length > 0) {\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n head.textContent = `quarantine: ${quarantines.length} file${quarantines.length === 1 ? \"\" : \"s\"} outside the downloads folder (${quarantines.filter(entry => entry.scan === \"pending\").length} awaiting scan verdicts)`;\n card.append(head);\n const list = document.createElement(\"ul\");\n for (const entry of quarantines.slice(0, 6)) {\n const item = document.createElement(\"li\");\n item.textContent = `${entry.path} \u00B7 scan ${entry.scan}${entry.release !== undefined ? ` \u00B7 released under ${entry.release}` : \"\"} \u00B7 ${entry.reason}`;\n if (active && entry.release === undefined && entry.scan === \"clean\") item.append(\" \", button(\"Release\", async () => { await request({ kind: \"releasequarantine\", id: entry.id }); status(`Released ${entry.path} from quarantine under the clean scan verdict.`); await refresh(); }));\n list.append(item);\n }\n card.append(list);\n filesroot.append(card);\n }\n const planid = context.plan?.id;\n const counters = (context.capturecounters ?? []).find(item => item.taskid === planid);\n if (counters) {\n const card = document.createElement(\"p\");\n card.textContent = `capture naming for task ${counters.taskid}: ${Object.entries(counters.counters).map(([step, sequence]) => `${step} \u2192 ${counters.taskid}-${step}-${sequence}`).join(\" \u00B7 \")}`;\n filesroot.append(card);\n }\n const rules = context.cleanuprules ?? [];\n const rulecard = document.createElement(\"div\");\n rulecard.className = \"panel\";\n const rulehead = document.createElement(\"p\");\n rulehead.textContent = `cleanup policy: ${rules.length > 0 ? rules.map(rule => `older than ${rule.age}ms of kind ${rule.kind} keep ${rule.keep}`).join(\" \u00B7 \") : \"no rule set stored yet\"}`;\n rulecard.append(rulehead);\n const runs = context.cleanupruns ?? [];\n if (runs.length > 0) {\n const lastrun = runs[0]!;\n const runline = document.createElement(\"p\");\n runline.textContent = `last sweep: removed ${lastrun.removed}, kept ${lastrun.kept} under ${lastrun.rules} rule${lastrun.rules === 1 ? \"\" : \"s\"}`;\n rulecard.append(runline);\n }\n if (active) {\n const ageinput = document.createElement(\"input\");\n ageinput.placeholder = \"age window in ms\";\n const kindinput = document.createElement(\"input\");\n kindinput.placeholder = \"artifact kind (any matches all)\";\n const keepinput = document.createElement(\"input\");\n keepinput.placeholder = \"keep policy: none, latest or all\";\n rulecard.append(ageinput, kindinput, keepinput, \" \", button(\"Add cleanup rule\", async () => {\n const age = Number(ageinput.value);\n const rule = { age, kind: kindinput.value.trim() || \"any\", keep: keepinput.value.trim() || \"none\" } as cleanuprule;\n const stored = await request({ kind: \"setcleanuprules\", rules: [...rules, rule] }) as { rules: number };\n status(`Stored ${stored.rules} reviewed cleanup rule${stored.rules === 1 ? \"\" : \"s\"}; ages stay your choice with no code ceiling.`);\n await refresh();\n }));\n }\n filesroot.append(rulecard);\n const inventory = context.inventory ?? [];\n if (inventory.length > 0) {\n const card = document.createElement(\"p\");\n card.textContent = `artifact inventory: ${inventory.slice(0, 5).map(entry => `${entry.name} (${entry.kind}, ${entry.size} characters, ${Math.max(0, Math.round((Date.now() - entry.at) / 60000))} minute${Math.round((Date.now() - entry.at) / 60000) === 1 ? \"\" : \"s\"} old)`).join(\" \u00B7 \")}${inventory.length > 5 ? ` and ${inventory.length - 5} more` : \"\"}`;\n filesroot.append(card);\n }\n const screens = (context.clips ?? []).filter(entry => entry.kind === \"screen\").slice(0, 2);\n for (const screen of screens) {\n const card = document.createElement(\"p\");\n card.textContent = `copyscreen result: ${screen.length} characters of png data with payload hash ${screen.hash} routed to the clipboard destination.`;\n filesroot.append(card);\n }\n const hooks = context.scanhooks ?? [];\n if (active) {\n const hookcard = document.createElement(\"div\");\n hookcard.className = \"panel\";\n const hookhead = document.createElement(\"p\");\n hookhead.textContent = hooks.length > 0 ? `scan hooks: ${hooks.map(hook => `${hook.scanner} at ${hook.origin} ${hook.granted ? \"granted\" : \"not granted\"}`).join(\" \u00B7 \")}` : \"scan hooks: none configured; scan verdicts stay pending without one.\";\n hookcard.append(hookhead);\n const scannerinput = document.createElement(\"input\");\n scannerinput.placeholder = \"scanner name\";\n const endpointinput = document.createElement(\"input\");\n endpointinput.placeholder = \"https://scanner.example/verdict\";\n hookcard.append(scannerinput, endpointinput, \" \", button(\"Configure scan hook\", async () => {\n await request({ kind: \"configurescanhook\", scanner: scannerinput.value, endpoint: endpointinput.value });\n status(`Scan hook ${scannerinput.value} configured; hook failures stay pending verdicts.`);\n await refresh();\n }));\n filesroot.append(hookcard);\n }\n}\n\n/** One capture metadata card of the gallery; bytes stay out of the context and load per capture on demand. */\ntype capturemeta = { id: string; runid: string; stepid: string; kind: string; format: string; width: number; height: number; capturedat: number; name?: string; annotated?: boolean; target?: string; bytesexpired?: boolean };\n\n/** Loads the bytes of one stored capture on demand; expired bytes resolve to undefined. */\nasync function capturebytes(id: string): Promise<string | undefined> {\n try {\n const record = await request({ kind: \"capturebytes\", id }) as { bytes: string };\n return record.bytes;\n } catch { return undefined; }\n}\n\n/** Opens any capture full size with its metadata, download and clipboard copy actions. */\nfunction opencapture(record: capturemeta): void {\n if (!capturesroot) return;\n const viewer = document.createElement(\"div\");\n viewer.className = \"panel captureviewer\";\n const head = document.createElement(\"p\");\n head.textContent = `${record.kind} \u00B7 ${record.format} \u00B7 ${record.width}\u00D7${record.height} px \u00B7 step ${record.stepid}${record.annotated ? \" \u00B7 annotated evidence\" : \"\"}${record.name !== undefined ? ` \u00B7 ${record.name}` : \"\"}`;\n viewer.append(head);\n const image = document.createElement(\"img\");\n image.alt = `Capture ${record.id} of kind ${record.kind}`;\n image.src = \"\";\n void capturebytes(record.id).then(bytes => { if (bytes) image.src = bytes; else viewer.append(Object.assign(document.createElement(\"p\"), { textContent: \"The capture bytes expired from the retention window; the metadata stays for the audit trail.\" })); });\n viewer.append(image);\n const actions = document.createElement(\"div\");\n actions.className = \"actions\";\n actions.append(button(\"Download\", () => request({ kind: \"downloadcapture\", id: record.id }).then(() => status(`Downloaded capture ${record.id} through the reviewed download flow.`))));\n actions.append(button(\"Copy to clipboard\", () => request({ kind: \"copycapture\", id: record.id }).then(() => status(`Copied capture ${record.id} to the clipboard.`))));\n actions.append(button(\"Close\", async () => viewer.remove()));\n viewer.append(actions);\n capturesroot.append(viewer);\n}\n\n/** Renders the capture gallery: the policy toggle, stitch progress, thumbnails per run, contact sheet cells and before and after pairs with a divider. */\nfunction rendercaptures(context: { session?: { stoppedat?: number; expiresat: number }; plan?: agentplan; outcomes?: stepoutcome[]; captures?: capturemeta[]; capturepairs?: shotpair[]; capturepolicy?: string; stitchprogress?: Array<{ stepid: string; done: number; total: number }> }): void {\n if (!capturesroot) return;\n capturesroot.replaceChildren();\n const active = context.session && !context.session.stoppedat && context.session.expiresat > Date.now();\n const policy = (context.capturepolicy ?? \"manual\") as capturepolicy;\n const policyrow = document.createElement(\"div\");\n policyrow.className = \"actions\";\n const policylabel = document.createElement(\"p\");\n policylabel.textContent = `capture policy: ${policy}${policy === \"beforeafter\" ? \" \u2014 state pairs wrap every page moving action\" : \"\"}`;\n policyrow.append(policylabel);\n for (const mode of [\"off\", \"manual\", \"annotated\", \"beforeafter\"] as const) {\n policyrow.append(button(mode, async () => { await request({ kind: \"setcapturepolicy\", mode }); status(`Capture policy set to ${mode}.`); await refresh(); }, !active || mode === policy));\n }\n capturesroot.append(policyrow);\n for (const progress of context.stitchprogress ?? []) {\n const bar = document.createElement(\"progress\");\n bar.max = Math.max(1, progress.total);\n bar.value = progress.done;\n const label = document.createElement(\"p\");\n label.textContent = `stitching full page capture of step ${progress.stepid}: tile ${progress.done} of ${progress.total}`;\n capturesroot.append(label, bar);\n }\n const captures = context.captures ?? [];\n if (captures.length === 0 && (context.capturepairs ?? []).length === 0) {\n capturesroot.append(Object.assign(document.createElement(\"p\"), { textContent: \"No captures stored yet; run a shotview, shotfullpage, shotelement, shotregion or contactsheet step.\" }));\n return;\n }\n const runs = [...new Set(captures.map(record => record.runid))];\n for (const run of runs) {\n const runcaptures = captures.filter(record => record.runid === run);\n const card = document.createElement(\"div\");\n card.className = \"panel\";\n const head = document.createElement(\"p\");\n head.textContent = `run ${run}: ${runcaptures.length} capture${runcaptures.length === 1 ? \"\" : \"s\"}`;\n card.append(head);\n const grid = document.createElement(\"div\");\n grid.className = \"capturegrid\";\n for (const record of runcaptures) {\n const cell = document.createElement(\"button\");\n cell.type = \"button\";\n cell.className = record.annotated ? \"capturecard annotated\" : \"capturecard\";\n const label = document.createElement(\"span\");\n label.textContent = `${record.kind} \u00B7 ${record.format} \u00B7 ${record.width}\u00D7${record.height}${record.annotated ? \" \u00B7 annotated\" : \"\"}${record.bytesexpired ? \" \u00B7 bytes expired\" : \"\"}`;\n cell.append(label);\n const image = document.createElement(\"img\");\n image.alt = `Capture ${record.id} of kind ${record.kind}`;\n if (!record.bytesexpired) void capturebytes(record.id).then(bytes => { if (bytes) image.src = bytes; });\n cell.append(image);\n cell.addEventListener(\"click\", () => opencapture(record));\n grid.append(cell);\n if (record.kind === \"contactsheet\") {\n const cells = (context.outcomes ?? []).find(outcome => outcome.stepid === record.stepid && outcome.details?.cells !== undefined)?.details?.cells as Array<{ index: number; selector: string; caption: string }> | undefined;\n for (const sheetcell of cells ?? []) {\n const cellbutton = document.createElement(\"button\");\n cellbutton.type = \"button\";\n cellbutton.className = \"secondary\";\n cellbutton.textContent = sheetcell.caption || sheetcell.selector;\n cellbutton.addEventListener(\"click\", () => opencapture(record));\n grid.append(cellbutton);\n }\n }\n }\n card.append(grid);\n capturesroot.append(card);\n }\n for (const pair of context.capturepairs ?? []) {\n const card = document.createElement(\"div\");\n card.className = \"panel pairview\";\n const head = document.createElement(\"p\");\n head.textContent = `state pair around the ${pair.actionkind} action${pair.target !== undefined ? ` on ${pair.target}` : \"\"}${pair.domsnapshotid !== undefined ? ` \u00B7 dom snapshot ${pair.domsnapshotid}` : \"\"}`;\n card.append(head);\n const row = document.createElement(\"div\");\n row.className = \"pairrow\";\n const before = document.createElement(\"img\");\n before.alt = `Before shot ${pair.beforeid}`;\n const after = document.createElement(\"img\");\n after.alt = `After shot ${pair.afterid}`;\n void capturebytes(pair.beforeid).then(bytes => { if (bytes) before.src = bytes; });\n void capturebytes(pair.afterid).then(bytes => { if (bytes) after.src = bytes; });\n row.append(before, after);\n const divider = document.createElement(\"input\");\n divider.type = \"range\";\n divider.min = \"0\";\n divider.max = \"100\";\n divider.value = \"50\";\n divider.setAttribute(\"aria-label\", \"Before and after divider\");\n divider.addEventListener(\"input\", () => { before.style.width = `${100 - Number(divider.value)}%`; after.style.width = `${Number(divider.value)}%`; });\n card.append(row, divider);\n capturesroot.append(card);\n }\n}\n\nfunction rendercapabilities(report?: capabilityreport): void {\n if (!capabilitiestext) return;\n if (!report) { capabilitiestext.textContent = \"Optional capabilities unknown.\"; return; }\n capabilitiestext.textContent = `tabs ${report.tabs ? \"granted\" : \"absent\"} \u00B7 downloads ${report.downloads ? \"granted\" : \"absent\"} \u00B7 clipboard read ${report.clipboardread ? \"granted\" : \"absent\"} \u00B7 clipboard write ${report.clipboardwrite ? \"granted\" : \"absent\"}`;\n}\n\nfunction renderaudit(events: auditevent[]): void { if (!auditroot) return; auditroot.replaceChildren(); for (const event of events.slice(0, 12)) { const item = document.createElement(\"li\"); item.textContent = `${new Date(event.at).toLocaleTimeString()} \u00B7 ${event.kind} \u00B7 ${event.summary}`; auditroot.append(item); } }\nfunction renderdiagnostic(report?: diagnosticreport): void { if (!diagnosticroot) return; diagnosticroot.replaceChildren(); if (!report) { diagnosticroot.textContent = \"Run a local diagnostic after starting a session to record bridge and page-shape health.\"; return; } const values = [`origin: ${report.origin}`, `title: ${report.title || \"untitled\"}`, `interactive elements: ${report.interactivecount}`, `forms: ${report.formcount}`, `page text length: ${report.textlength}`, `bridge available: ${report.bridgeavailable ? \"yes\" : \"no\"}`]; for (const value of values) { const item = document.createElement(\"li\"); item.textContent = value; diagnosticroot.append(item); } }\nasync function refresh(): Promise<void> { const context = await request({ kind: \"context\" }) as { plan?: agentplan; progress?: planprogress; diagnostic?: diagnosticreport; audit: auditevent[]; outcomes?: stepoutcome[]; capabilities?: capabilityreport; session?: { id: string; pausedat?: number; stoppedat?: number; expiresat: number; origin?: string }; map?: clickablemap; retries?: retryoutcome[]; a11y?: a11ycapture; reader?: readercapture; banners?: bannerreport[]; mutationevents?: mutationevent[]; focusevents?: focusevent[]; diffs?: snapshotdiff[]; selectors?: derivedselector[]; trail?: { trail: trailentry[] }; navrecords?: navrecord[]; ratestates?: ratelimitstate[]; safeties?: safetyverdict[]; curated?: curatedlist[]; waitprofiles?: waitprofilerecord[]; auths?: Array<{ origin: string; username: string; reviewedat: number }>; navcontrol?: navcontrol; navqueues?: navqueues; artifacts?: artifactrecord[]; tabs?: tabshape[]; windows?: windowshape[]; tabgroups?: tabgrouprecord[]; badges?: tabbadge[]; tabmetas?: tabmeta[]; clones?: Array<{ url: string; tabids: number[] }>; layouts?: tablayout[]; snapshots?: sessionsnapshot[]; closedtabs?: closedtab[]; tasktabgauge?: { used: number; ceiling?: number; over: boolean }; controltab?: controltabstate; profiles?: formprofile[]; tickets?: submitticket[]; wizards?: { wizards: wizardstate[]; picks: typeaheadpick[] }; picks?: typeaheadpick[]; errorreports?: errorreport[]; captchas?: captchahandoff[]; detections?: detectionrecord[]; codeentry?: boolean; datasets?: dataset[]; imports?: dataset[]; extractsessions?: extractsession[]; streams?: streamstate[]; exports?: Array<{ id: string; kind: string; name: string; rowcount: number; checksum: string; at: number }>; provenances?: provenancerecord[]; taskrules?: taskrules[]; sheetendpoints?: Array<{ endpoint: string; origin: string; configuredat: number; granted: boolean }>; downloads?: downloadrecord[]; mimefilters?: mimefilter[]; clipconsents?: clipboardconsentrecord[]; clips?: clipentry[]; netlogs?: netlogrecord[]; quarantines?: quarantineentry[]; capturecounters?: Array<{ taskid: string; counters: Record<string, number>; at: number }>; cleanuprules?: cleanuprule[]; cleanupruns?: cleanuprun[]; inventory?: artifactinventoryentry[]; scanhooks?: Array<{ scanner: string; endpoint: string; origin: string; configuredat: number; granted: boolean }>; captures?: Array<{ id: string; runid: string; stepid: string; kind: string; format: string; width: number; height: number; capturedat: number; name?: string; annotated?: boolean; target?: string; bytesexpired?: boolean }>; capturepairs?: shotpair[]; capturepolicy?: string; stitchprogress?: Array<{ stepid: string; done: number; total: number }> }; renderplan(context.plan, context.progress, context.outcomes ?? [], context.retries ?? []); renderdiagnostic(context.diagnostic); rendermap(context.map); rendera11y(context.a11y); renderreader(context.reader); renderdetections(context.plan, context.outcomes ?? []); renderstream(context.mutationevents ?? [], context.focusevents ?? []); renderdiffs(context.diffs ?? []); renderbanners(context.banners ?? []); renderselectors(context.selectors ?? []); rendertrail(context.trail?.trail ?? []); rendernavigation(context); rendertabswindows(context); renderforms(context); renderdatasets(context); renderfiles(context); rendercaptures(context); renderaudit(context.audit); rendercapabilities(context.capabilities); if (context.session?.pausedat) status(\"Session paused. Reviewed actions are blocked until resume.\"); else status(context.session ? \"Active session is visible. The extension is waiting for review.\" : \"No active browser session.\"); }\nasync function create(kind: \"proposelocal\" | \"proposeremote\"): Promise<void> { await request({ kind, objective: objective?.value ?? \"\" }); await refresh(); }\nlocalbutton?.addEventListener(\"click\", () => create(\"proposelocal\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\nremotebutton?.addEventListener(\"click\", () => create(\"proposeremote\").catch(error => status(error instanceof Error ? error.message : String(error), true)));\ndiagnosticbutton?.addEventListener(\"click\", () => request({ kind: \"diagnostic\" }).then(() => refresh()).catch(error => status(error instanceof Error ? error.message : String(error), true)));\nrefresh().catch(error => status(error instanceof Error ? error.message : String(error), true));\n"],
5
+ "mappings": "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",
6
6
  "names": ["record", "interrupted", "body"]
7
7
  }