@chatpanel/events 0.127.0 → 0.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/attached-paths.js +19 -0
- package/capability-client.js +1 -0
- package/capability-endpoints.js +1 -0
- package/client-prefs.js +1 -1
- package/composer-chips.js +1 -0
- package/context-attachments.js +7 -7
- package/default-skills.js +6 -0
- package/extract-capability.js +5 -0
- package/fast-path.js +6 -0
- package/index.js +1 -1
- package/mcp-config-import.js +5 -0
- package/model-picker.js +1 -1
- package/model-registry.js +1 -0
- package/model-roles.js +1 -0
- package/monitor-profile.js +1 -0
- package/note-plan.js +6 -6
- package/package.json +51 -3
- package/plan-executor.js +1 -0
- package/plan.js +1 -0
- package/read-document.js +10 -0
- package/redaction-dictionary.js +2 -0
- package/router.js +2 -2
- package/run-details.js +1 -0
- package/sandbox-policy.js +1 -0
- package/search-searxng.js +1 -0
- package/serp-anchors.js +1 -0
- package/settings-registry.js +1 -0
- package/site-policy.js +1 -0
- package/voice-models.js +1 -0
- package/voice-sample.js +1 -0
- package/voice-vad.js +1 -0
- package/web-search.js +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{PREF_SECTIONS as x}from"./client-prefs.js";const A=Object.freeze([{id:"chat",label:"Chat"},{id:"extend",label:"Extend"},{id:"privacy",label:"Privacy"},{id:"workspace",label:"Workspace"},{id:"data",label:"Data"},{id:"account",label:"Account"}]),S=Object.freeze({gateway:{fact:"gateway",reason:"Needs the gateway running on this machine",fix:"Install or start it",page:"gateway"},bridge:{fact:"bridge",reason:"Needs the local runtime (bridge) running",fix:"Install or start it",page:"agent-tools"},pro:{fact:"pro",reason:"A Pro feature",fix:"See plans",page:"plan"},pageActions:{fact:"pageActions",reason:"Only applies once Act on page is on",fix:"Turn on Act on page",page:"chat"},cdp:{fact:"cdp",reason:"Needs High-reliability page control",fix:"Turn it on",page:"chat"},chromium:{fact:"chromium",reason:"Chromium browsers only — elsewhere ChatPanel falls back automatically",fix:"",page:""},drive:{fact:"drive",reason:"Connect Google Drive first",fix:"Connect",page:"backup-sync"},telegram:{fact:"telegram",reason:"Connect a Telegram bot first",fix:"Connect",page:"channels"}}),I=Object.freeze(["removedBuiltinAgents"]),h=Object.freeze([{id:"home",group:null,label:"Home",blurb:"What is set up, what needs attention, and how to get more out of ChatPanel",sections:[]},{id:"general",group:"chat",label:"General",blurb:"How ChatPanel looks and answers",sections:[{id:"appearance",label:"Appearance",rows:[{id:"pref-theme",key:"ui.theme",section:"general",type:"select",label:"Theme",help:"Light, dark or follow the system.",synonyms:["dark mode","light mode","appearance","colour","color"],quick:!0,options:[["system","System"],["light","Light"],["dark","Dark"]]},{id:"pref-language",key:"ui.language",section:"general",type:"select",label:"Response language",help:"Enforced for every model — answers come back in this language whatever you type.",synonyms:["locale","translate","reply language"],quick:!0,options:[["","Auto (match me)"],["English","English"],["Spanish","Spanish"],["French","French"],["German","German"],["Portuguese","Portuguese"],["Italian","Italian"],["Hindi","Hindi"],["Chinese (Simplified)","Chinese (Simplified)"],["Japanese","Japanese"],["Korean","Korean"],["Arabic","Arabic"],["Russian","Russian"]]},{id:"settings-open",key:"ui.settingsOpen",section:"general",type:"select",label:"Open settings",help:"What the gear opens: Settings inside the panel, or the full page. Either can reach the other.",synonyms:["inline","expanded","gear","settings page","full page","in the panel"],options:[["inline","Inline — in the panel"],["expanded","Expanded — the full page"]]}]},{id:"you",label:"You",rows:[{id:"self-name",key:"selfName",section:"identity",type:"text",label:"Your name",help:"How briefs and meeting notes refer to you.",synonyms:["identity","my name","who am I"]}]}]},{id:"chat",group:"chat",label:"Chat",blurb:"The composer, acting on a page, and how far one message may go",sections:[{id:"composer",label:"Composer",rows:[{id:"pref-enter",key:"ui.sendOnEnter",section:"general",type:"toggle",label:"Send on Enter",help:"Enter sends, Shift+Enter makes a newline.",synonyms:["keyboard","return key","newline","submit"],quick:!0,default:!0},{id:"pref-stream",key:"ui.streamResponses",section:"general",type:"toggle",label:"Stream responses",help:"Show the answer as it arrives instead of waiting for the whole reply.",synonyms:["streaming","typing","live"],default:!0},{id:"auto-attach-tab",key:"ui.autoAttachActiveTab",section:"general",type:"toggle",label:"Attach the current page by default",help:"New chats start with the page you are viewing as context. Toggle per chat from the composer.",synonyms:["page context","active tab","use page","attach"],browserOnly:!0,composer:!0,default:!0},{id:"pref-suggestions-enabled",key:"ui.suggestions.enabled",section:"suggestions",type:"toggle",label:"Smart suggestions",help:"Prompt ideas tailored to the page on an empty chat — only the URL, title and description are sent, never the page body.",synonyms:["prompt ideas","starters","suggested prompts"]},{id:"pref-suggestions-target",key:"ui.suggestions.targetId",section:"suggestions",type:"picker",label:"Suggestions model",help:"Which model writes the suggestions. A small, cheap one keeps it fast.",synonyms:["suggestion model","generate with"]},{id:"pref-autocomplete",key:"ui.autocomplete",section:"general",type:"toggle",label:"Autocomplete my prompts",help:"A small, fast model suggests a continuation as you pause; Tab accepts. Set an endpoint’s autocomplete model to use it.",synonyms:["ghost text","prompt completion","tab to accept"],pro:!0}]},{id:"page-actions",label:"Act on page",rows:[{id:"pref-pageact-mode",key:"ui.pageActions",section:"pageActions",type:"select",label:"Act on page",help:"Where the agent may fill forms, click and draw. Ask offers it per site; Every readable tab arms it everywhere.",synonyms:["page actions","automation","fill forms","click","drive the page","browser agent"],browserOnly:!0,quick:!0,options:[["off","Off — never"],["ask","Ask on known apps"],["allowlist","Only sites I allowed"],["always","Every readable tab"]]},{id:"pref-pageact-confirm",key:"ui.pageActionConfirm",section:"pageActions",type:"toggle",label:"Confirm before page actions",help:"Ask before the agent fills, clicks or types, so a page or tool cannot quietly steer it. On by default.",synonyms:["approve","confirmation","safety"],browserOnly:!0,requires:"pageActions",default:!0},{id:"pref-pageact-cdp",key:"ui.pageActionsCdp",section:"pageActions",type:"toggle",label:"High-reliability page control",help:"Trusted browser events instead of synthetic ones — needed for canvas apps and keyboard-driven controls. Shows a debugging banner while acting.",synonyms:["cdp","debugger","trusted events","canvas"],browserOnly:!0,requires:"chromium",default:!0},{id:"pref-pageact-devjs",key:"ui.pageActionsDevJs",section:"pageActions",type:"toggle",label:"Let the agent run JavaScript on the page",help:"For developers. Every call is shown and approved individually; that prompt cannot be waived.",synonyms:["developer","javascript","eval","script"],browserOnly:!0,requires:"cdp"},{id:"pref-pageact-sites",key:"ui.pageSites",section:"pageActions",type:"list",label:"Sites you answered",help:"Where you allowed or declined Act on page. Forget one to be asked again.",synonyms:["allowed sites","per-site","remembered","forget site"],browserOnly:!0}]},{id:"watch",label:"Watch a page",rows:[{id:"watch-interval",key:"ui.watch.intervalMs",section:"watch",type:"number",label:"Check every",help:"How often a watched page is re-read.",synonyms:["poll","interval","monitor page","page changes"],browserOnly:!0,composer:!0},{id:"watch-only-changed",key:"ui.watch.onlyWhenChanged",section:"watch",type:"toggle",label:"Only when the page changed",help:"Skip the model call when nothing on the page moved.",synonyms:["changes only","diff"],browserOnly:!0,composer:!0,default:!0},{id:"watch-instruction",key:"ui.watch.instruction",section:"watch",type:"textarea",label:"What to do on a change",help:"The instruction each check runs with.",synonyms:["watch prompt"],browserOnly:!0,composer:!0}]},{id:"turn-limits",label:"Turn limits",advanced:!0,rows:[{id:"pref-max-tools",key:"ui.maxToolsPerTurn",section:"tools",type:"number",label:"Max tools per turn",help:"Beyond this many, remote tools are dropped by relevance; local tools are always kept. 0 = no limit.",synonyms:["tool cap","narrow tools","too many tools"]},{id:"pref-max-rounds",key:"ui.maxToolRoundsPerTurn",section:"tools",type:"number",label:"Max model requests per turn",help:"How many times one message may go back to the model while it uses tools. Up to 60; an endpoint’s own limit wins.",synonyms:["rounds","tool loop","iterations","requests per turn"]},{id:"mcp-tools-mode",key:"ui.mcpToolsMode",section:"tools",type:"select",label:"MCP tools per turn",help:"Auto offers the servers whose tools match the message; Always offers every enabled server; Off never does.",synonyms:["tools mode","auto tools","mcp policy"],quick:!0,composer:!0,options:[["auto","Auto"],["on","Always"],["off","Off"]]},{id:"history-context-mode",key:"ui.historyContextMode",section:"tools",type:"select",label:"History context",help:"Whether past chats, notes and meetings are pulled into a turn automatically.",synonyms:["rag","history rag","context from history","past chats"],quick:!0,composer:!0,options:[["off","Off"],["chats","Past chats"],["meetings","Meetings"],["all","Chats, meetings & notes"]]},{id:"history-tools",key:"ui.historyTools",section:"tools",type:"toggle",label:"History tools",help:"Let the model search your past chats, notes and meetings when a question depends on them.",synonyms:["history search","find tool"],default:!0},{id:"data-dispatch",key:"ui.dataDispatch",section:"tools",type:"toggle",label:"Group data tools behind one find",help:"One registered tool instead of six schemas on every turn. Turn off only for a model that handles a flat toolset better.",synonyms:["find dispatcher","flat tools"],default:!0},{id:"tool-result-max",key:"ui.toolResultMaxChars",section:"tools",type:"number",label:"Largest tool result",help:"A result over this many characters is stored and previewed; the model pages it. Lower for small local models.",synonyms:["result size","truncate","shield","max chars"]}]}]},{id:"models",group:"chat",label:"Models",blurb:"The API endpoints ChatPanel calls directly, and how a model is chosen",sections:[{id:"model-roles",label:"What runs where",rows:[{id:"model-roles",type:"status",label:"Every model in use, by job",help:"Chat, coding agents, entity detection, transcription, voice, speaker identification, ranking, embeddings, decisions — what is in use, where it runs (this device, your server, cloud), and where to change it.",synonyms:["model roles","what runs where","which model","swap model","cloud model","local model","in use","overview"]}]},{id:"endpoints",label:"Endpoints",rows:[{id:"endpoints",key:"endpoints",section:"endpoints",type:"list",label:"Endpoints",help:"Any OpenAI- or Anthropic-compatible API, local or hosted, with its model, key and system prompt.",synonyms:["api","api key","openai","anthropic","ollama","lm studio","openrouter","base url","model","provider","system prompt"]},{id:"add-endpoint",type:"action",label:"Add endpoint",help:"Connect a new API or local server.",synonyms:["new model","connect api"]},{id:"free-endpoint",key:"freeEndpointId",section:"freeSlots",type:"picker",label:"Free plan endpoint",help:"The one endpoint Free unlocks — your pick.",synonyms:["free slot","free pick"]},{id:"webllm-background",key:"ui.webllmBackground",section:"webllm",type:"toggle",label:"Keep the in-browser model loaded",help:"Stays warm across panel open/close so there is no reload wait; uses memory while idle.",synonyms:["webllm","stay warm","background model","webgpu"],browserOnly:!0},{id:"webllm-custom-models",key:"webllmCustomModels",section:"webllm",type:"list",label:"Custom in-browser models",help:"Extra WebLLM models added by id.",synonyms:["webllm","custom model","mlc"],browserOnly:!0}]},{id:"routing",label:"Routing",advanced:!0,rows:[{id:"routing-mode",key:"ui.routing.mode",section:"routing",type:"select",label:"Observation",help:"Whether the router records what it would have chosen when it is not the one answering. Visible in Activity.",synonyms:["auto route","model routing","observe","router"],options:[["observe","Record what it would choose"],["off","Off"]]},{id:"routing-models",key:"ui.routing.models",section:"routing",type:"list",label:"What each model is",help:"Cost, speed, reach and abilities per model — detected from name and URL, corrected here. Reset puts a row back.",synonyms:["model facts","reach","cost tier","latency","capabilities"]},{id:"routing-latency",type:"select",label:"Try: max wait",help:"A test input for the routing preview — changes nothing.",synonyms:["preview route","what would auto choose"]},{id:"routing-cost",type:"select",label:"Try: max cost",help:"A test input for the routing preview — changes nothing.",synonyms:["preview route"]},{id:"routing-reach",type:"select",label:"Try: request may reach",help:"A test input for the routing preview — changes nothing.",synonyms:["preview route","device only","cloud"]},{id:"routing-tools",type:"toggle",label:"Try: needs tools",help:"A test input for the routing preview — changes nothing.",synonyms:["preview route"]},{id:"routing-prefer",type:"select",label:"Try: prefer",help:"A test input for the routing preview — changes nothing.",synonyms:["preview route","cheapest","fastest"]}]}]},{id:"agent-tools",group:"chat",label:"Agent Tools",blurb:"Claude Code, Codex, Antigravity and the other coding agents on this machine",sections:[{id:"runtime",label:"On this machine",rows:[{id:"local-runtime",type:"status",label:"Local runtime",help:"Whether the gateway and the bridge are installed and running, and which version.",synonyms:["bridge status","gateway status","install","running","version","update"]},{id:"local-recheck",type:"action",label:"Recheck the local runtime",help:"Ask the gateway and bridge again.",synonyms:["refresh status","reconnect"]}]},{id:"agents",label:"Coding agents",rows:[{id:"bridge-agents",key:"agents",section:"agentTools",type:"list",label:"Coding agents",help:"Each CLI the bridge found, with its enabled switch, permission mode, working directory and system prompt.",synonyms:["claude code","codex","antigravity","gemini cli","opencode","pi","aider","harness","cli agent","permission mode","working directory"],requires:"bridge"},{id:"add-agent",type:"action",label:"Add agent",help:"Describe a CLI the bridge did not detect.",synonyms:["custom agent","new harness"]},{id:"free-agent",key:"freeAgentId",section:"freeSlots",type:"picker",label:"Free plan agent",help:"The one coding agent Free unlocks — your pick.",synonyms:["free slot","free pick"]}]},{id:"remote-bridge",label:"Remote bridge",advanced:!0,rows:[{id:"bridge-url",key:"bridgeUrl",store:"local",type:"text",label:"Bridge URL",help:"Where this client reaches the bridge. Leave the default for the bridge on this machine.",synonyms:["bridge address","localhost 4319","port"]},{id:"bridge-token",key:"bridgeToken",store:"local",type:"secret",label:"Bridge token",help:"Only for a bridge on another machine — the local one recognises the extension on sight.",synonyms:["remote bridge","auth token","bridge-token file"]},{id:"bridge-test",type:"action",label:"Test the bridge",help:"Reach the bridge at the URL above and list its agents.",synonyms:["check bridge","connect"]}]}]},{id:"tools-mcp",group:"extend",label:"Tools & MCP",blurb:"External tools your agents can call",sections:[{id:"servers",label:"MCP servers",rows:[{id:"mcp-list",key:"mcpServers",section:"mcpServers",type:"list",label:"MCP servers",help:"Streamable HTTP servers, or stdio servers run on your machine through the bridge, with their auth and env.",synonyms:["mcp","model context protocol","tool server","stdio","auth header","env vars"]},{id:"add-mcp",type:"action",label:"Add server",help:"Add an MCP server by URL or command.",synonyms:["new mcp"]},{id:"import-mcp",type:"action",label:"Import an MCP config",help:"Paste a Claude Desktop / Cursor / Codex mcpServers JSON block.",synonyms:["import json","claude_desktop_config","mcp.json","paste config"]}]},{id:"discover",label:"Discover",rows:[{id:"mcp-registry-search",type:"text",label:"Search the MCP registry",help:"The official registry and curated public servers, one click to add.",synonyms:["registry","catalog","public servers","find mcp"]}]}]},{id:"web-search",group:"extend",label:"Web search",blurb:"Live results as context for any model",sections:[{id:"search",label:"Search",rows:[{id:"pref-websearch-enabled",key:"ui.webSearch.enabled",section:"webSearch",type:"toggle",label:"Web search",help:"Type /search anywhere in a message, or let the model call it when a question needs the web.",synonyms:["internet","google","live results","/search","browse"],default:!0},{id:"websearch-engines",key:"ui.webSearch.engines",section:"webSearch",type:"list",label:"Search engines",help:"Engines use a %s or {q} placeholder and must return server-rendered HTML.",synonyms:["engine","duckduckgo","startpage","brave","bing","searx"]},{id:"add-websearch",type:"action",label:"Add engine",help:"Add a search engine by URL template.",synonyms:["new engine","custom search"]},{id:"pref-websearch-per",key:"ui.webSearch.perEngine",section:"webSearch",type:"number",label:"Results per engine",help:"How many hits each engine contributes.",synonyms:["result count"]},{id:"pref-websearch-pages",key:"ui.webSearch.maxPages",section:"webSearch",type:"number",label:"Pages to read & rank",help:"How many result pages are fetched and ranked before the best are attached.",synonyms:["page count","fetch pages"]}]},{id:"reader",label:"Reader & fallback",advanced:!0,rows:[{id:"pref-websearch-reader",key:"ui.webSearch.reader.enabled",section:"webSearch",type:"toggle",label:"Use a reader service",help:"Fetch each result as LLM-ready Markdown instead of parsing site HTML. Anonymous Jina is blocked, so bring a key.",synonyms:["jina","markdown reader","r.jina.ai"]},{id:"pref-websearch-reader-url",key:"ui.webSearch.reader.url",section:"webSearch",type:"text",label:"Reader URL",help:"The reader service endpoint.",synonyms:["reader endpoint"]},{id:"pref-websearch-reader-key",key:"ui.webSearch.reader.key",section:"webSearch",type:"secret",label:"Reader API key",help:"Sent as a Bearer token; optional.",synonyms:["reader token","jina key"]},{id:"pref-websearch-tabfallback",key:"ui.webSearch.tabFallback",section:"webSearch",type:"toggle",label:"Background-tab render as a last resort",help:"A page that cannot be fetched is opened in a background tab so its JavaScript runs. Off by default.",synonyms:["render tab","javascript pages","serp fallback"],browserOnly:!0}]}]},{id:"skills",group:"extend",label:"Skills",blurb:"Reusable prompts, slash-commands and recipes",sections:[{id:"skills",label:"Skills",rows:[{id:"skills",key:"skills",section:"skills",type:"list",label:"Skills",help:"Prompts you drop into any chat with the button, by /command, or with #Skill in Notes. Editing the built-ins is free; your own are Pro.",synonyms:["slash command","prompt template","custom prompt","skill"]},{id:"skill-filter",type:"text",label:"Filter skills",help:"Narrow the list by name or command.",synonyms:["search skills","find skill"]},{id:"add-skill",type:"action",label:"Add skill",help:"Write a new skill.",synonyms:["new skill","create prompt"],pro:!0},{id:"reset-skills",type:"action",label:"Reset built-in skills",help:"Put every built-in back to its shipped prompt; yours are untouched.",synonyms:["restore defaults","reset prompts"]}]},{id:"recipes",label:"Recipes",rows:[{id:"recipes",key:"recipes",section:"recipes",type:"list",label:"Recipes",help:"Workflows written down once — proposed in chat, approved, run by /name.",synonyms:["workflow","macro","saved steps","recipe"]}]},{id:"machine",label:"On this machine",rows:[{id:"skill-source-search",type:"text",label:"Search skills on this machine",help:"Every skill installed for Claude Code, Codex, Copilot, Antigravity, Hermes and ~/.agents/skills, found by the bridge.",synonyms:["installed skills","local skills","agents skills","found by the bridge"],requires:"bridge"},{id:"skill-dirs-input",key:"ui.skillDirs",section:"skillDirs",type:"textarea",label:"Custom skill folders",help:"Folders the bridge serves alongside the built-in agent locations. Applied on the next rescan.",synonyms:["skill folder","skill directory","skill path"],requires:"bridge"},{id:"skill-sources-refresh",type:"action",label:"Rescan skill folders",help:"Ask the bridge to look again.",synonyms:["rescan","refresh skills"],requires:"bridge"}]}]},{id:"agent-teams",group:"extend",label:"Agent Teams",blurb:"The agents you define and the teams they work in",sections:[{id:"agents",label:"Agents",rows:[{id:"directory",key:"agentPool",section:"agents",type:"list",label:"Agents",help:"Cards with a name, a specialty, an engine and grants — the roster a team is staffed from.",synonyms:["agent pool","roster","directory","specialist","engine","grants"]}]},{id:"teams",label:"Teams",rows:[{id:"teams",key:"teams",section:"teams",type:"list",label:"Teams",help:"A named set of roles with prompts, tiers and grants, run by /team or from a note.",synonyms:["team","swarm","roles","multi-agent"]}]},{id:"dashboard",label:"Live",rows:[{id:"open-teams-dashboard",key:"projects",section:"projects",type:"link",label:"Agent Teams dashboard",help:"Projects, the board and Observe — where each run is, what it asked you, and what it did.",synonyms:["board","projects","observe","kanban","runs","in flight","inbox","trail","approvals","dashboard"]}]}]},{id:"channels",group:"extend",label:"Channels",blurb:"Message your agent from your phone",sections:[{id:"telegram",label:"Telegram",rows:[{id:"ch-token",store:"local",type:"secret",label:"Bot token",help:"From @BotFather. Checked with Telegram before it is stored — on this machine, in a file only you can read.",synonyms:["telegram","botfather","bot","phone","whatsapp"],requires:"bridge"},{id:"ch-connect",type:"action",label:"Connect Telegram",help:"Start polling with the token above. Becomes Connected · Disconnect once it is.",synonyms:["start bot","link telegram"],requires:"bridge"},{id:"ch-agent",store:"gateway",type:"picker",label:"Agent that answers",help:"Which of your agents replies to paired phones.",synonyms:["telegram agent","answering agent"],requires:"telegram"},{id:"ch-privacy",store:"gateway",type:"select",label:"What comes back to Telegram",help:"Telegram is a third party: redact personal details on the way out, and mask credentials on the way back.",synonyms:["telegram redaction","channel privacy","mask secrets"],requires:"telegram"},{id:"ch-disconnect",type:"action",label:"Disconnect Telegram",help:"Stops polling, deletes the stored token and unpairs every phone.",synonyms:["stop bot","remove telegram"],requires:"telegram"}]},{id:"phones",label:"Paired phones",rows:[{id:"ch-pair",type:"action",label:"Pair a phone",help:"A single-use code, scanned once; the phone can read your files and cannot write, run commands or reach the web.",synonyms:["pair","qr code","enroll phone","add phone"],requires:"telegram"}]}]},{id:"connections",group:"extend",label:"Connections",blurb:"The code hosts the bridge holds tokens for",sections:[{id:"hosts",label:"Code hosts",rows:[{id:"connections",key:"connections",section:"connections",type:"list",label:"Connections",help:"GitHub, GitLab and the other SCM hubs — kind and host travel, the token stays in this machine’s keychain.",synonyms:["github","gitlab","bitbucket","scm","source control","personal access token","repo access"],requires:"bridge"}]}]},{id:"redaction",group:"privacy",label:"Redaction",blurb:"PII replaced before it reaches a model, restored in the reply",sections:[{id:"mode",label:"Mode",rows:[{id:"priv-mode",key:"ui.piiRedaction.mode",section:"redaction",type:"select",label:"Redaction",help:"Off, patterns only (emails, phones, cards, keys, IPs + your dictionary), or patterns plus AI detection of names, orgs and locations.",synonyms:["pii","privacy","anonymize","mask","redact","sensitive","placeholder"],quick:!0,options:[["off","Off"],["deterministic","On — patterns + dictionary"],["model","On — + AI detection"]]},{id:"priv-applyto",key:"ui.piiRedaction.applyTo",section:"redaction",type:"select",label:"Redact for",help:"Every model, or remote only — a localhost model keeps data on-device already.",synonyms:["local models","remote only","cloud only","skip local"],options:[["all","All chat models"],["remote","Remote models only"]]}]},{id:"detection",label:"Detection",rows:[{id:"priv-det-backend",key:"ui.piiRedaction.detection.backend",section:"redaction",type:"select",label:"Detector",help:"What finds names, orgs and locations: the gateway’s bundled NER, a NER service by URL, or one of your models. Your text reaches the detector, so keep it local.",synonyms:["ner","entity detection","name detection","detector backend"],pro:!0,options:[["off","Off"],["bundled","Bundled NER (gateway)"],["endpoint","Custom PII service (URL)"],["agent","A configured API / agent"]]},{id:"priv-det-target",key:"ui.piiRedaction.detection.targetId",section:"redaction",type:"picker",label:"Detection model",help:"Which of your APIs or agents runs detection, when the detector is a model.",synonyms:["detector model","api / agent"],pro:!0},{id:"priv-det-tmodel",key:"ui.piiRedaction.detection.model",section:"redaction",type:"text",label:"Detection model name",help:"The model id an agent should use for detection.",synonyms:["detector model id"],pro:!0},{id:"priv-det-url",key:"ui.piiRedaction.detection.url",section:"redaction",type:"text",label:"Detector URL",help:'A NER service: POST {"text"} → {"entities":[{value,type}]}.',synonyms:["ner url","ner endpoint","ner service"],pro:!0},{id:"priv-det-timeout",key:"ui.piiRedaction.detection.timeoutMs",section:"redaction",type:"number",label:"Detector timeout",help:"Milliseconds before a slow detector is skipped for the turn.",synonyms:["ner timeout","detection timeout"],pro:!0},{id:"priv-ner-check",type:"action",label:"Check NER health",help:"Send a test sentence to the detector.",synonyms:["test detector","ner status"]},{id:"priv-det-person",key:"ui.piiRedaction.detection.types.person",section:"redaction",type:"toggle",label:"Redact people (names)",help:"Person names become [[PERSON_n]].",synonyms:["names","person"],pro:!0,default:!0},{id:"priv-det-org",key:"ui.piiRedaction.detection.types.org",section:"redaction",type:"toggle",label:"Redact organizations",help:"Company and org names become [[ORG_n]].",synonyms:["companies","organisations","org"],pro:!0,default:!0},{id:"priv-det-location",key:"ui.piiRedaction.detection.types.location",section:"redaction",type:"toggle",label:"Redact locations",help:"Cities and places become [[LOCATION_n]].",synonyms:["places","cities","addresses","location"],pro:!0,default:!0},{id:"priv-det-number",key:"ui.piiRedaction.detection.types.number",section:"redaction",type:"toggle",label:"Redact numbers & IDs",help:"Account numbers, IDs and other numeric identifiers.",synonyms:["ids","account numbers","numeric"],pro:!0,default:!0}]},{id:"dictionary",label:"Dictionary",rows:[{id:"priv-dictionary",key:"ui.piiRedaction.dictionary",section:"redaction",type:"textarea",label:"Dictionary",help:"One entry per line: term => LABEL redacts reversibly, term -> alias pseudonymizes permanently, /regex/flags also works. Free applies the first 5.",synonyms:["custom terms","pseudonym","alias","regex","always redact","word list"]}]},{id:"scope",label:"Scope",rows:[{id:"priv-scope-chat",key:"ui.piiRedaction.scope.chat",section:"redaction",type:"toggle",label:"Redact chat messages",help:"What you type.",synonyms:["scope chat","messages"],default:!0},{id:"priv-scope-context",key:"ui.piiRedaction.scope.context",section:"redaction",type:"toggle",label:"Redact page & meeting context",help:"Attached pages and live captions.",synonyms:["scope page","scope meeting","context"],pro:!0,default:!0},{id:"priv-scope-history",key:"ui.piiRedaction.scope.history",section:"redaction",type:"toggle",label:"Redact history search results",help:"Past chats, notes and meetings pulled into a turn.",synonyms:["scope history"],pro:!0,default:!0},{id:"priv-scope-tools",key:"ui.piiRedaction.scope.toolResults",section:"redaction",type:"toggle",label:"Redact tool results",help:"What tools return before the model reads it.",synonyms:["scope tools","tool output"],pro:!0,default:!0},{id:"priv-tooldata",key:"ui.piiRedaction.toolData",section:"redaction",type:"select",label:"Tools receive",help:"Real values so lookups work, or the redacted token so PII never reaches a remote MCP server. Local tools always get real values.",synonyms:["tool arguments","mcp sees","real values","redact remote"],options:[["real","Real values"],["redactRemote","Redact for remote (MCP) tools"]]}]},{id:"ner-model",label:"NER model",rows:[{id:"gw-ner-search",store:"gateway",type:"picker",label:"NER model",help:"The on-device model behind Bundled NER — used by the panel’s redaction and the gateway’s. A bigger model is more accurate but a larger download.",synonyms:["ner model","download ner","multilingual ner","deid","hugging face"],requires:"gateway"}]},{id:"try",label:"Try it",advanced:!0,rows:[{id:"priv-flow-input",type:"textarea",label:"Test a prompt end-to-end",help:"See what is detected, what the model sees, what tools receive, and what you get back.",synonyms:["preview redaction","test redaction","what does the model see","pipeline"]},{id:"priv-flow-model",type:"picker",label:"Test with model",help:"Which model answers the test prompt.",synonyms:["test model"]},{id:"priv-flow-run",type:"action",label:"Run the redaction test",help:"Send the test prompt through the whole pipeline.",synonyms:["run test"]},{id:"priv-flow-preview",type:"action",label:"Preview redaction only",help:"Show what would be redacted without calling a model.",synonyms:["dry run","preview"]}]}]},{id:"internal-sites",group:"privacy",label:"Internal sites",blurb:"Content from these never leaves your machine",sections:[{id:"boundary",label:"Data boundary",rows:[{id:"internal-guard",key:"privacy.internalGuard",section:"internalSites",type:"toggle",label:"Keep content from internal sites on this device",help:"When a turn draws on an internal source, only a local model may answer it — whichever model is selected.",synonyms:["intranet","internal","private network","data boundary","on-device only","source gate"],default:!0},{id:"internal-ceiling",key:"privacy.internalCeiling",section:"internalSites",type:"select",label:"Where these may be answered",help:"On this device only, or also by an endpoint you marked trusted.",synonyms:["ceiling","trusted endpoint","allowed models"],options:[["device","This device only"],["trusted","My workspace (gateway or trusted endpoint)"]]}]},{id:"domains",label:"Domains",rows:[{id:"internal-catalog",key:"privacy.internalPatterns",section:"internalSites",type:"list",label:"Addresses treated as internal",help:"Private ranges, .local, .internal and the rest — on by default; untick any that are not internal for you.",synonyms:["localhost",".local",".internal","private ip","defaults"]},{id:"internal-patterns",key:"privacy.internalPatterns",section:"internalSites",type:"textarea",label:"My own internal domains",help:"One per line; a domain covers its subdomains.",synonyms:["custom domain","company domain","add domain"]},{id:"internal-restore",type:"action",label:"Restore all default internal addresses",help:"Tick every built-in pattern again.",synonyms:["reset internal","restore defaults"]}]}]},{id:"gateway",group:"privacy",label:"Gateway",blurb:"An optional local process: on-device models, routing, and redaction for tools outside the panel",sections:[{id:"connection",label:"Connection",rows:[{id:"gw-url",key:"gatewayUrl",store:"local",type:"text",label:"Gateway URL",help:"Where this client reaches the gateway. Leave the default for the gateway on this machine.",synonyms:["gateway address","localhost 4320","port","connect gateway"]},{id:"gw-check",type:"action",label:"Check the gateway",help:"Reach the gateway and read its version. Install → Running · Update once it is.",synonyms:["gateway status","install gateway","is the gateway running","install.sh"]}]},{id:"redaction",label:"Redaction for other clients",rows:[{id:"gw-tier",store:"gateway",type:"select",label:"Gateway redaction tier",help:"What the gateway redacts for traffic that does not go through the panel — OpenCode, Pi, aider.",synonyms:["gateway redaction","proxy redaction","opencode","aider"],requires:"gateway"},{id:"gw-redact-system",store:"gateway",type:"toggle",label:"Redact the system prompt too",help:"Apply redaction to the system message as well as user turns.",synonyms:["system prompt redaction"],requires:"gateway"},{id:"gw-det-backend",store:"gateway",type:"select",label:"Gateway detector",help:"The gateway’s own NER choice. Local options keep the raw text on your machine; a cloud one sends it there.",synonyms:["gateway ner","gateway detector"],requires:"gateway"},{id:"gw-det-url",store:"gateway",type:"text",label:"Gateway detector URL",help:"A NER service or model endpoint the gateway calls.",synonyms:["gateway ner url"],requires:"gateway"},{id:"gw-det-model",store:"gateway",type:"text",label:"Gateway detector model",help:"The model id, when the detector is an LLM.",synonyms:["gateway ner model"],requires:"gateway"},{id:"gw-det-key",store:"gateway",type:"secret",label:"Gateway detector API key",help:"Only for a hosted detector.",synonyms:["gateway ner key"],requires:"gateway"},{id:"gw-det-timeout",store:"gateway",type:"number",label:"Gateway detector timeout",help:"Milliseconds before a slow detector is skipped.",synonyms:["gateway ner timeout"],requires:"gateway"},{id:"gw-ner-check",type:"action",label:"Check the gateway’s NER health",help:"Send a test sentence through the gateway’s detector.",synonyms:["gateway ner test"],requires:"gateway"},{id:"gw-dictionary",store:"gateway",type:"textarea",label:"Gateway dictionary",help:"Separate from the panel’s — applies to traffic the gateway sees. Same grammar.",synonyms:["gateway terms","gateway alias"],requires:"gateway"},{id:"gw-dict-copy",type:"action",label:"Copy the panel’s dictionary to the gateway",help:"One click to keep both the same.",synonyms:["sync dictionary"],requires:"gateway"}]},{id:"routing",label:"Routing",rows:[{id:"gw-dest-trigger",store:"gateway",type:"picker",label:"Destinations",help:"Which of your APIs and agents the gateway routes to; clients pick one by model name via /v1/models.",synonyms:["gateway models","v1/models","route to","destinations"],requires:"gateway"},{id:"gw-tools-data",store:"gateway",type:"select",label:"Gateway tools receive",help:"Real values so a client’s tool works, or the redacted token for remote MCP tools.",synonyms:["gateway tool data","gateway mcp sees"],requires:"gateway"},{id:"gw-tools-narrow",store:"gateway",type:"toggle",label:"Auto-narrow to the most relevant tools",help:"When a client sends many MCP tools, forward only the top-K for this message. Core tools are always kept.",synonyms:["narrow tools","top-k tools"],requires:"gateway"},{id:"gw-tools-cap",store:"gateway",type:"number",label:"Max MCP tools per turn (gateway)",help:"The K in top-K.",synonyms:["gateway tool cap"],requires:"gateway"},{id:"gw-tools-narrowall",store:"gateway",type:"toggle",label:"Also narrow non-MCP tools",help:"Only if your client has no essential core tools.",synonyms:["narrow all tools"],requires:"gateway"}]},{id:"agents",label:"Agents through the gateway",rows:[{id:"gw-agent-perm",store:"gateway",type:"select",label:"Permissions for agents through the gateway",help:"What a CLI agent may do when another client — the desktop, OpenCode — reaches it through the gateway. The panel’s own agents use their card’s setting.",synonyms:["gateway permissions","permission mode","accept edits","bypass"],requires:"gateway"},{id:"gw-agent-workdir",store:"gateway",type:"text",label:"Working directory for agents through the gateway",help:"Where those agents start.",synonyms:["gateway workdir","cwd"],requires:"gateway"}]},{id:"monitoring",label:"Monitoring",rows:[{id:"gw-log",store:"gateway",type:"toggle",label:"Log requests",help:"Counts and per-stage latency, no values.",synonyms:["gateway log","request log","observability"],requires:"gateway"},{id:"gw-log-detail",store:"gateway",type:"toggle",label:"Capture redaction detail",help:"Expand a request to see what was redacted — types and tokens only, or real values kept in memory.",synonyms:["redaction detail","what was redacted","log values"],requires:"gateway"},{id:"gw-logs-refresh",type:"action",label:"Recent gateway requests",help:"The last requests the gateway handled.",synonyms:["recent requests","gateway history"],requires:"gateway"},{id:"gw-test-input",type:"textarea",label:"Test a prompt through the gateway",help:"What is detected, what the destination sees, and the restored reply.",synonyms:["gateway test","try gateway"],requires:"gateway"}]},{id:"advanced",label:"Advanced",advanced:!0,rows:[{id:"gw-origins",store:"gateway",type:"textarea",label:"Allowed browser origins",help:"Only if a web app should call the gateway. Local CLI tools need nothing here.",synonyms:["cors","origins","allow origin","browser app"],requires:"gateway"},{id:"gw-token",key:"gatewayToken",store:"local",type:"secret",label:"Gateway admin token",help:"Only for older gateways — a current one authorizes the extension automatically.",synonyms:["gateway-token","admin token","auth"]},{id:"gw-pro-activate",type:"action",label:"Activate Pro on the gateway",help:"Hands your ChatPanel Pro to the gateway — nothing to paste.",synonyms:["gateway pro","entitlement"],requires:"gateway"},{id:"gw-pro-token",store:"gateway",type:"secret",label:"Entitlement token",help:"Paste a token manually if activation cannot reach the gateway.",synonyms:["entitlement token","license token"],requires:"gateway"},{id:"gw-save",type:"action",label:"Save to gateway",help:"Write the gateway settings above.",synonyms:["save gateway"],requires:"gateway"}]}]},{id:"memory",group:"workspace",label:"Memory",blurb:"What every model already knows about you",sections:[{id:"memory",label:"Memory",rows:[{id:"memory-enabled",key:"ui.memory.enabled",section:"memory",type:"toggle",label:"Memory",help:'Short, durable facts carried into every conversation and offered to any MCP client through the gateway. Say "remember that…" to add one.',synonyms:["remember","facts about me","personalization","long-term memory"],default:!0},{id:"memory-inprompt",key:"ui.memory.inPrompt",section:"memory",type:"select",label:"In the prompt",help:"How much of your memory rides in the system prompt on every turn versus being fetched by the memory tool.",synonyms:["system prompt memory","memory tool","in-prompt"],options:[["preferences","Only how I want answers"],["all","Everything relevant"],["off","Nothing — the model asks the memory tool"]]},{id:"memory-offers",key:"ui.memory.offers",section:"memory",type:"toggle",label:"Offer to remember things I mention in passing",help:"A one-tap Remember chip above the composer; nothing is saved without your tap.",synonyms:["remember chip","suggest memory","offers"],default:!0}]},{id:"stored",label:"Stored memories",rows:[{id:"memory-list",type:"list",label:"Stored memories",help:"Every fact, in full, with where it came from — edit in place or forget.",synonyms:["memories","what does it know","forget","edit memory"]},{id:"memory-add",type:"action",label:"Add a memory",help:"Write a fact yourself.",synonyms:["new memory"]},{id:"memory-clear",type:"action",label:"Forget all memories",help:"Delete every stored memory.",synonyms:["clear memory","delete all","forget everything"]}]}]},{id:"notes",group:"workspace",label:"Notes",blurb:"Your private, on-device writing workspace",sections:[{id:"cowriter",label:"Co-writer",rows:[{id:"notes-cowriter-enabled",store:"local",type:"toggle",label:"Co-writer",help:"An editor fixes typos on a pause, a researcher surfaces related material, a writer drafts ahead on ⌘↵. Off by default — it calls models as you type.",synonyms:["cowriter","writing assistant","grammar","draft ahead","swarm"]}]},{id:"autocomplete",label:"Inline autocomplete",rows:[{id:"notes-ac-enabled",key:"ui.notes.autocomplete.enabled",section:"notes",type:"toggle",label:"Inline autocomplete in notes",help:"Grey ghost text on a pause; Tab accepts. Accepted text is attributed to the model.",synonyms:["ghost text","notes completion","tab to accept"]},{id:"notes-ac-model",key:"ui.notes.autocomplete.agentId",section:"notes",type:"picker",label:"Notes autocomplete model",help:"A small, fast one; uses its autocomplete model when set.",synonyms:["notes model","completion model"]}]},{id:"commands",label:"Note commands",rows:[{id:"notes-tool-websearch",key:"ui.notes.tools.webSearch",section:"notes",type:"toggle",label:"@insert may use web search",help:"Fetch live results for @insert, @table and @list.",synonyms:["@insert","note tools","web in notes"],default:!0},{id:"notes-tool-mcp",key:"ui.notes.tools.mcp",section:"notes",type:"toggle",label:"@insert may use MCP tools",help:"Your connected external tools, from a note.",synonyms:["@insert","mcp in notes"],default:!0},{id:"notes-tool-history",key:"ui.notes.tools.history",section:"notes",type:"toggle",label:"@insert may search history",help:"Your own notes, chats and meetings, from a note.",synonyms:["@insert","history in notes"],default:!0}]},{id:"dashboard",label:"Open",rows:[{id:"open-notes-dashboard",type:"link",label:"Open the notes dashboard",help:"The full-screen notes workspace.",synonyms:["notes page","open notes"]}]}]},{id:"meetings",group:"workspace",label:"Meetings",blurb:"Live scribe for Zoom, Meet, Teams and Webex — captions only, never audio",sections:[{id:"live-notes",label:"Live notes",rows:[{id:"pref-live-notes",key:"ui.liveNotesIntervalMin",section:"meetings",type:"select",label:"Auto-refresh notes",help:"How often new captions are merged into the running summary and saved.",synonyms:["live summary","refresh interval","scribe"],pro:!0,options:[["0","Off — summarize only when I ask"],["1","Every 1 minute"],["2","Every 2 minutes"],["5","Every 5 minutes"],["10","Every 10 minutes"]]},{id:"pref-meeting-window",key:"ui.meetingWindowMin",section:"meetings",type:"select",label:"Transcript sent per question",help:"The full transcript for short calls, a window for long ones — keeps the prompt and cost from growing.",synonyms:["transcript window","context window","minutes"],pro:!0,options:[["0","Full transcript so far"],["5","Last 5 minutes"],["10","Last 10 minutes"],["20","Last 20 minutes"],["30","Last 30 minutes"]]},{id:"pref-meeting-summary-style",key:"ui.meetingSummaryStyle",section:"meetings",type:"select",label:"Live summary style",help:"Concise keeps it short and cheap; Detailed produces full minutes. Either can be regenerated per meeting.",synonyms:["concise","detailed","minutes","summary length"],pro:!0,options:[["concise","Concise"],["detailed","Detailed — full minutes"]]},{id:"pref-alert-sound",key:"ui.alertSound",section:"meetings",type:"toggle",label:"Sound an alert when a timer or reminder fires",help:"A notification is something you look at; a timer needs to reach you when you are not looking.",synonyms:["alert","chime","timer sound","reminder sound","beep"],default:!0}]},{id:"monitors",label:"Live monitors",rows:[{id:"pref-monitor-model",key:"ui.monitors.targetId",section:"monitors",type:"picker",label:"Answer monitors with",help:"A monitor re-answers its question every time the transcript grows — a fast model keeps it live.",synonyms:["monitor model","/monitor","/tldr","live monitor"],pro:!0},{id:"pref-monitor-window",key:"ui.monitors.windowMin",section:"monitors",type:"select",label:"Monitor transcript window",help:"How many minutes of transcript a monitor reads.",synonyms:["monitor window"],pro:!0,options:[["2","Last 2 minutes"],["5","Last 5 minutes"],["10","Last 10 minutes"],["15","Last 15 minutes"],["30","Last 30 minutes"]]},{id:"pref-monitor-summary",key:"ui.monitors.sources.summary",section:"monitors",type:"toggle",label:"Monitors read the running summary",help:"Adds the live summary to each monitor prompt.",synonyms:["monitor sources"],pro:!0,default:!0},{id:"pref-monitor-findings",key:"ui.monitors.sources.findings",section:"monitors",type:"toggle",label:"Monitors read what they already found",help:"Stops a monitor repeating itself.",synonyms:["monitor findings","dedupe"],pro:!0,default:!0},{id:"pref-monitor-web",key:"ui.monitors.sources.web",section:"monitors",type:"toggle",label:"Monitors may search the web",help:"Adds a tool call before it can answer.",synonyms:["monitor web search"],pro:!0},{id:"pref-monitor-history",key:"ui.monitors.sources.history",section:"monitors",type:"toggle",label:"Monitors may read past chats, meetings & notes",help:"Your history as a source for a monitor.",synonyms:["monitor history"],pro:!0},{id:"pref-monitor-mcp",key:"ui.monitors.sources.mcp",section:"monitors",type:"toggle",label:"Monitors may use MCP tools",help:"The slowest option — every server is described in the prompt.",synonyms:["monitor mcp"],pro:!0}]},{id:"spoken",label:"Spoken commands",advanced:!0,rows:[{id:"pref-voice-enabled",key:"ui.voice.enabled",section:"voice",type:"toggle",label:"Spoken commands during a meeting",help:'Say "ChatPanel, keep an eye on the pricing question" to start a monitor. Matched on-device against the captions — no audio, no model call.',synonyms:["wake word","voice commands","hey chatpanel","say"],pro:!0,default:!0},{id:"pref-voice-wake",key:"ui.voice.wakeWord",section:"voice",type:"text",label:"Wake word",help:"Several are fine, separated by commas.",synonyms:["trigger word","hotword"],pro:!0},{id:"pref-voice-from",key:"ui.voice.from",section:"voice",type:"select",label:"Act on commands from",help:"Only you, or anyone on the call.",synonyms:["who can command","speaker"],pro:!0,options:[["me","Only me"],["anyone","Anyone in the meeting"],["off","Nobody — just listen"]]},{id:"pref-voice-names",key:"ui.voice.selfNames",section:"voice",type:"text",label:"My name in captions",help:"Meet labels you by name; put it (and any short form) here so your own commands are recognised.",synonyms:["caption name","my name","you"],pro:!0}]},{id:"dashboard",label:"Open",rows:[{id:"open-meetings-dashboard",type:"link",label:"Open the meetings dashboard",help:"Every recorded meeting: summary, topics, key moments, action items, transcript.",synonyms:["past meetings","transcripts","open meetings"]}]}]},{id:"chat-history",group:"workspace",label:"Chat history",blurb:"Search every conversation",sections:[{id:"topics",label:"Topics",rows:[{id:"pref-topic-extract",key:"ui.topicExtraction.enabled",section:"topics",type:"toggle",label:"Auto-extract topics for history graphs",help:"Runs after chats or transcripts change and saves concise graph topics locally.",synonyms:["topics","graph","tags","topic extraction"],default:!0},{id:"pref-topic-target",key:"ui.topicExtraction.targetId",section:"topics",type:"picker",label:"Topic extraction model",help:"Blank uses the active model or agent.",synonyms:["topic model"]}]},{id:"indexing",label:"Indexing",rows:[{id:"gw-warm-search",key:"ui.warmSearch.enabled",section:"warmSearch",type:"toggle",label:"Index my history to the gateway",help:"Opt-in. Sends decrypted chats and meetings to your local gateway so search scales past what the browser can hold.",synonyms:["warm search","full-corpus search","gateway index","history indexing"],requires:"gateway"},{id:"gw-backup-key",store:"gateway",type:"toggle",label:"Let the gateway decrypt & index my daily backups",help:"Hands your backup password to the local gateway so it can index your encrypted backups too.",synonyms:["backup key","index backups","backup password handoff"],requires:"gateway"}]},{id:"dashboard",label:"Open",rows:[{id:"open-history-dashboard",type:"link",label:"Open the chat history dashboard",help:"Ranked, keyword and by-agent search, threads, related chats and the graph.",synonyms:["history page","search chats","open history"]}]}]},{id:"voice",group:"workspace",label:"Voice",blurb:"Dictation, read-aloud and speaker models — all on this machine",sections:[{id:"dictation",label:"Dictation",rows:[{id:"gw-stt-search",store:"gateway",type:"picker",label:"Speech-to-text model",help:"Local Whisper for the mic button — audio never leaves your machine. Non-Latin languages need Small or Large v3 Turbo.",synonyms:["whisper","stt","dictation model","microphone","speech to text","transcribe"],requires:"gateway"},{id:"gw-stt-dtype",store:"gateway",type:"select",label:"Dictation precision",help:"Quantization — lighter is faster, fuller is more accurate.",synonyms:["quantization","dtype","fp16","q8"],requires:"gateway"},{id:"gw-stt-lang",key:"ui.dictation.lang",section:"speech",type:"picker",label:"Dictation language",help:"Auto-detect works well on Small+. Pin a language if detection guesses wrong on short phrases.",synonyms:["speech language","mic language","auto-detect"]}]},{id:"read-aloud",label:"Read aloud",rows:[{id:"gw-tts-search",store:"gateway",type:"picker",label:"Text-to-speech model",help:"The voice behind Read aloud and voice conversation. Kokoro and VITS/MMS run here; without one the browser voice is used.",synonyms:["tts","speech","kokoro","pocket tts","mms","voice model","read aloud engine"],requires:"gateway"},{id:"gw-tts-voice",store:"gateway",type:"picker",label:"Voice",help:"Which voice reads answers aloud.",synonyms:["speaker voice","tts voice","read aloud voice"],requires:"gateway",quick:!0},{id:"gw-tts-dtype",store:"gateway",type:"select",label:"Read-aloud precision",help:"Quantization for the TTS model.",synonyms:["tts quantization"],requires:"gateway"},{id:"gw-tts-voices",store:"gateway",type:"list",label:"Your voices",help:"Voice prints derived from a few seconds of your speech — the recording is never stored and nothing leaves this machine.",synonyms:["voice clone","my voice","voice print","custom voice"],requires:"gateway"},{id:"gw-tts-record",type:"action",label:"Record a voice",help:"Ten seconds at a normal pace; needs a model that can use a print (Pocket TTS).",synonyms:["record voice","clone voice"],requires:"gateway"}]},{id:"speaker",label:"Meetings",rows:[{id:"gw-diarize-models",store:"gateway",type:"picker",label:"Speaker model",help:"Tells voices apart for meeting transcription — Speaker 1 / Speaker 2 / …, on-device. Needed only for the Transcribe meeting button.",synonyms:["diarization","diarize","who spoke","speaker labels","pyannote"],requires:"gateway"}]}]},{id:"backup-sync",group:"data",label:"Backup & sync",blurb:"Encrypted copies of everything, on a schedule or on demand",sections:[{id:"backups",label:"Encrypted backups",rows:[{id:"autobackup-destination",store:"local",type:"select",label:"Backup destination",help:"Downloads, Google Drive, or both. Compressed and encrypted locally; Drive receives only ciphertext.",synonyms:["where to back up","downloads folder","drive backup","export"],pro:!0},{id:"autobackup-device-name",store:"local",type:"text",label:"This device’s backup name",help:"Each browser profile gets its own seven rotating slots, so one machine never overwrites another.",synonyms:["device name","profile name"],pro:!0},{id:"backup-password",store:"local",type:"secret",label:"Backup encryption password",help:"Stored encrypted in this profile so scheduled backups run unattended. There is no recovery.",synonyms:["passphrase","encryption key","backup password"],pro:!0},{id:"autobackup-now",type:"action",label:"Back up now",help:"An encrypted backup to the destination above, right now.",synonyms:["export now","download backup","manual backup"]}]},{id:"schedule",label:"Schedule",rows:[{id:"autobackup-enabled",store:"local",type:"toggle",label:"Back up my encrypted data every day",help:"At most one completed automatic backup per calendar day; a missed one catches up at the next browser start.",synonyms:["daily backup","automatic backup","scheduled"],pro:!0},{id:"autobackup-hour",store:"local",type:"select",label:"Run the daily backup at",help:"One local time.",synonyms:["backup time","backup hour"],pro:!0}]},{id:"drive",label:"Google Drive",rows:[{id:"drive-connect",type:"action",label:"Connect Google Drive",help:"Your own Google account, connected once; ChatPanel refreshes authorization for scheduled backups.",synonyms:["google","drive","oauth","sign in google"],pro:!0},{id:"drive-disconnect",type:"action",label:"Disconnect Google Drive",help:"Forget the Drive authorization on this browser.",synonyms:["sign out google","remove drive"],requires:"drive"},{id:"drive-backup-list",type:"picker",label:"Encrypted backups in Drive",help:"The backups every device has written.",synonyms:["drive backups","restore from drive"],requires:"drive"},{id:"drive-backup-restore",type:"action",label:"Restore the selected Drive backup",help:"Downloads ciphertext into memory and decrypts it with the password above; always merges chats, meetings and notes.",synonyms:["restore drive"],requires:"drive"},{id:"drive-backup-restore-all",type:"action",label:"Merge latest from all devices",help:"Restore the newest backup of every device at once.",synonyms:["merge devices","restore all"],requires:"drive"}]},{id:"restore",label:"Restore from file",advanced:!0,rows:[{id:"backup-import",type:"action",label:"Restore from file",help:"An encrypted backup or a legacy ZIP export, from disk.",synonyms:["import","restore","upload backup","zip"]},{id:"backup-replace",store:"local",type:"toggle",label:"Replace existing data when restoring from a file",help:"Default is merge.",synonyms:["overwrite on restore","replace data"]}]}]},{id:"storage-access",group:"data",label:"Storage & access",blurb:"Where your data lives, and which agents read it",sections:[{id:"storage",label:"Where your data lives",rows:[{id:"obs-sync",type:"action",label:"Sync now",help:"Mirror chats, meetings and notes to the local gateway so connected agents can search them.",synonyms:["sync gateway","mirror","warm tier"],requires:"gateway"},{id:"obs-clear",type:"action",label:"Clear the gateway copy",help:"Delete the gateway’s mirror; the browser keeps everything.",synonyms:["delete gateway data","clear warm"],requires:"gateway"},{id:"obs-refresh",type:"action",label:"Refresh storage view",help:"Storage per tier and the access log.",synonyms:["storage size","how much data","access log","who read what"]}]}]},{id:"activity-usage",group:"data",label:"Activity & usage",blurb:"Every model call, and what each run actually did",sections:[{id:"totals",label:"Totals",rows:[{id:"usage-groupby",type:"select",label:"Group usage by",help:"Model, agent or day.",synonyms:["usage","tokens","cost","spend","bill"]},{id:"usage-window",type:"select",label:"Usage window",help:"How far back the totals reach.",synonyms:["usage period","last 7 days","this month"]},{id:"usage-clear",type:"action",label:"Clear usage totals",help:"Reset the counters on this device.",synonyms:["reset usage"]}]},{id:"runs",label:"Runs",rows:[{id:"activity-kind",type:"select",label:"Show runs of kind",help:"Chat, monitor, note command, team…",synonyms:["activity filter","run kind"]},{id:"activity-background",type:"toggle",label:"Show background work",help:"Include topic extraction, briefs and the other work that ran without you asking.",synonyms:["background runs","hidden runs"]},{id:"activity-replay",type:"action",label:"Verify replay",help:"Re-derive the log and compare — proves the record is consistent.",synonyms:["replay","verify log","event log"]},{id:"activity-export",type:"action",label:"Export activity (JSONL)",help:"Every run as one JSON line.",synonyms:["export runs","download activity","jsonl"]},{id:"activity-clear",type:"action",label:"Clear activity",help:"Delete the run log on this device.",synonyms:["delete activity","clear runs"]}]}]},{id:"plan",group:"account",label:"Plan",blurb:"Free, Pro or Team, and restoring Pro on this device",sections:[{id:"plan",label:"Your plan",rows:[{id:"btn-subscribe-pro",type:"action",label:"Subscribe to Pro",help:"Opens secure checkout; Pro activates here automatically. Becomes Pro · Manage once you have it.",synonyms:["upgrade","buy","pro","pricing","checkout","license","licence"]},{id:"btn-check-purchase",type:"action",label:"Check for my purchase",help:"Already paid and still seeing Free? No email needed.",synonyms:["already paid","refresh license","activate"]},{id:"license-deactivate",type:"action",label:"Deactivate Pro on this device",help:"Free this device’s seat.",synonyms:["sign out","deactivate","remove license"],requires:"pro"}]},{id:"restore",label:"Already subscribed",rows:[{id:"restore-email",type:"text",label:"Restore Pro by email",help:"A one-tap link that activates Pro on this device.",synonyms:["restore purchase","magic link","email me a link","lost pro"]},{id:"btn-restore",type:"action",label:"Email me a restore link",help:"Send the link to the address above.",synonyms:["send link"]}]}]},{id:"plugins",group:"account",label:"Plugins",blurb:"Everything ChatPanel loads, and what you can switch off",sections:[{id:"plugins",label:"Plugins",rows:[{id:"plugins-list",type:"list",label:"Adapters and tool groups",help:"Adapters drive an app through its own data format; tool groups are the sets offered each turn. A disabled group is never built. Security cannot be turned off.",synonyms:["adapters","tool groups","disable feature","excalidraw","draw.io","tldraw","switch off"]},{id:"plugins-refresh",type:"action",label:"Refresh plugins",help:"Re-read what is loaded.",synonyms:["reload plugins"]}]}]},{id:"about",group:"account",label:"About",blurb:"Version, updates and support",sections:[{id:"about",label:"About",rows:[{id:"check-updates",type:"action",label:"Check for updates",help:"A manual install does not auto-update; this looks for a newer build.",synonyms:["version","update","new version","download latest","changelog","help","support"]}]}]}]),b=new Map(A.map(e=>[e.id,e])),w=new Map(h.map(e=>[e.id,e]));function m(){const e=[];for(const t of h){const a=t.group&&b.get(t.group)||null;for(const s of t.sections)for(const o of s.rows)e.push({row:o,section:s,page:t,group:a})}return e}const f=new Map(m().map(e=>[e.row.id,e]));function L(e){return f.get(e)}function N(e){return w.get(e)}function D(e){return b.get(e)}function W(e){return h.filter(t=>(t.group||null)===(e||null))}function G(){return m().filter(e=>e.row.quick)}function R(e){return[e.group?.label,e.page.label,e.section.label].filter(Boolean).join(" › ")}function C(e,t){return e?t?`#${e}/${t}`:`#${e}`:""}function B(e){const t=f.get(e);return t?C(t.page.id,t.section.id):""}function F(e){const t=String(e||"").replace(/^#/,"");if(!t)return null;const[a,s]=t.split("/"),o=w.get(a);if(!o)return null;const i=s?o.sections.find(r=>r.id===s):void 0;return{page:o,section:i}}function T(e,t){if(!t||!e)return;let a=e;for(const s of t.split(".")){if(!a||typeof a!="object")return;a=a[s]}return a}function j(e,t,a){const s=JSON.parse(JSON.stringify(e||{})),o=String(t||"").split(".");let i=s;for(let r=0;r<o.length-1;r+=1)(!i[o[r]]||typeof i[o[r]]!="object")&&(i[o[r]]={}),i=i[o[r]];return i[o[o.length-1]]=a,s}const z="inline";function H(e){return e?.ui?.settingsOpen==="expanded"?"expanded":"inline"}function O(e,t){const a=t?.key?T(e,t.key):void 0;return a??t?.default}function P(e,t){if(t==null||t==="")return e.type==="secret"?"Not set":"";if(e.type==="secret")return"••••";if(typeof t=="boolean")return t?"On":"Off";if(Array.isArray(t))return`${t.length}`;if(typeof t=="object"){const o=Object.keys(t).length;return o?`${o}`:""}const a=e.options?.find(o=>String(o[0])===String(t)),s=a?a[1]:String(t);return s.length>40?`${s.slice(0,37)}…`:s}const g=e=>String(e||"").toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g,""),q=e=>g(e).split(/[^a-z0-9@/.+-]+/).filter(Boolean);function y(e,t,a,s,o){const i=g(e);if(!i)return 0;let r=0;for(const n of t)i.startsWith(n)?r+=a:new RegExp(`(^|[^a-z0-9])${n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}`).test(i)?r+=s:i.includes(n)&&(r+=o);return r}function U(e,{settings:t,limit:a=12,rows:s}={}){const o=q(e);if(!o.length)return[];const i=s?new Set(s):null,r=[];for(const n of m()){const{row:l}=n;if(i&&!i.has(l.id))continue;const k=[l.label,...l.synonyms||[],n.section.label,n.page.label,n.group?.label||"",l.help||""].map(g).join(" \0 ");if(!o.every(u=>k.includes(u)))continue;let d=y(l.label,o,30,18,8);for(const u of l.synonyms||[])d=Math.max(d,y(u,o,16,12,6))+(y(u,o,1,1,1)?1:0);if(d+=y(n.page.label,o,6,5,2)+y(n.section.label,o,6,5,2),d+=y(l.help,o,2,2,1),l.quick&&(d+=1),d<=0)continue;const v=l.key?P(l,O(t,l)):"";r.push({id:l.id,label:l.label,help:l.help||"",type:l.type,value:v,pro:!!l.pro,requires:l.requires||null,page:n.page.id,pageLabel:n.page.label,section:n.section.id,sectionLabel:n.section.label,group:n.group?.id||null,groupLabel:n.group?.label||"",breadcrumb:R(n),score:d})}return r.sort((n,l)=>l.score-n.score||n.label.length-l.label.length||n.label.localeCompare(l.label)),r.slice(0,a)}const c=e=>Array.isArray(e)?e.length:0,p=(e,t,a=`${t}s`)=>`${e} ${e===1?t:a}`;function E(e,t={},a={}){const s=t.ui||{},o=n=>({state:"ok",text:n}),i=n=>({state:"warn",text:n}),r=n=>({state:"off",text:n});switch(e){case"models":{const n=c(t.endpoints);return n?o(p(n,"endpoint")):i("No endpoints yet")}case"agent-tools":{if(!a.bridge)return i("Local runtime not running");const n=Number.isFinite(a.agentCount)?a.agentCount:c(t.agents);return n?o(p(n,"agent")):i("No agents found")}case"gateway":return a.gateway?o("Running"):r("Not running");case"redaction":{const n=s.piiRedaction?.mode||"off";return n==="off"?i("Off — a model sees what you type"):o(n==="model"?"Patterns + AI detection":"Patterns")}case"internal-sites":return t.privacy?.internalGuard===!1?r("Off"):o("Internal content stays on this device");case"tools-mcp":{const n=c(t.mcpServers);return n?o(p(n,"server")):r("No servers")}case"web-search":return s.webSearch?.enabled===!1?r("Off"):o("On");case"skills":return o(p(c(t.skills),"skill"));case"agent-teams":{const n=c(t.agentPool),l=c(t.teams);return n||l?o(`${p(n,"agent")} · ${p(l,"team")}`):r("None defined")}case"channels":return a.telegram?o("Telegram connected"):r("Not connected");case"connections":return c(t.connections)?o(p(c(t.connections),"host")):r("None");case"memory":return s.memory?.enabled===!1?r("Off"):o("On");case"meetings":return a.pro?o("Ready"):i("Pro");case"chat-history":return s.warmSearch?.enabled?o("Indexed on the gateway"):o("In the browser");case"voice":return a.gateway?o("On-device models available"):i("Needs the gateway for on-device voice");case"backup-sync":return a.backupEnabled?o("Daily backups on"):i("No scheduled backup");case"plan":return a.pro?o("Pro"):r("Free");default:return{state:"none",text:""}}}function _(e={},t={}){const a=e.ui||{};return[{id:"model",label:"Connect a model",why:"A local server or a hosted API — one endpoint is enough to chat.",done:c(e.endpoints)>0,page:"models",section:"endpoints"},{id:"runtime",label:"Install the local runtime",why:"The gateway brings the bridge: coding agents, on-device dictation and PII detection, routing.",done:!!(t.gateway||t.bridge),page:"agent-tools",section:"runtime"},{id:"redaction",label:"Turn redaction on",why:"Sensitive values are replaced before a model sees them and restored in the reply.",done:(a.piiRedaction?.mode||"off")!=="off",page:"redaction",section:"mode"},{id:"name",label:"Tell ChatPanel your name",why:"Briefs and meeting notes refer to you by it.",done:!!String(e.selfName||"").trim(),page:"general",section:"you"},{id:"tools",label:"Connect a tool",why:"An MCP server gives every agent something to do beyond talk.",done:c(e.mcpServers)>0,page:"tools-mcp",section:"servers"},{id:"backup",label:"Set up daily encrypted backups",why:"A reinstall cannot lose your chats, notes and settings.",done:!!t.backupEnabled,page:"backup-sync",section:"schedule",pro:!0},{id:"phone",label:"Message your agent from your phone",why:"A Telegram bot, polled by the bridge on this machine.",done:!!t.telegram,page:"channels",section:"telegram"}]}function $(e,t){const a={};for(const s of h)a[s.id]=E(s.id,e,t);return a}function Y(e,t={}){if(!e?.requires)return{ok:!0};const a=S[e.requires];return a?t[a.fact]?{ok:!0}:{ok:!1,reason:a.reason,fix:a.fix,page:a.page}:{ok:!0}}function K(e){return e?.section?x.find(t=>t.id===e.section):void 0}export{I as BOOKKEEPING_KEYS,S as REQUIREMENTS,A as SETTINGS_GROUPS,z as SETTINGS_OPEN_DEFAULT,h as SETTINGS_PAGES,R as breadcrumb,P as describeValue,O as effectiveValue,L as findRow,Y as gateOf,D as groupById,_ as homeChecklist,C as linkTo,B as linkToRow,m as listRows,N as pageById,W as pagesOf,F as parseLink,G as quickRows,U as searchSettings,K as sectionOfRow,j as setValue,H as settingsOpenMode,$ as statusAll,E as statusOf,T as valueOf};
|
package/site-policy.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const g=Object.freeze({perHost:2,total:4});function p(t,s){if(t==null)return null;const l=String(t).trim();if(!l)return null;if(/^\d+$/.test(l))return Number(l)*1e3;const n=Date.parse(l);return Number.isNaN(n)?null:Math.max(0,n-s)}function y({now:t=()=>Date.now(),perHost:s=g.perHost,total:l=g.total}={}){const n=new Map;let a=0;const r=[],u=new Map,c=e=>a<l&&(n.get(e)||0)<s,d=e=>{n.set(e,(n.get(e)||0)+1),a+=1;let i=!1;return()=>{i||(i=!0,n.set(e,n.get(e)-1),n.get(e)===0&&n.delete(e),a-=1,b())}},b=()=>{for(let e=0;e<r.length;e++)if(c(r[e].host)){const{host:i,resolve:o}=r.splice(e,1)[0];if(o(d(i)),e-=1,a>=l)break}};return{acquire(e){const i=String(e||"").toLowerCase();return c(i)?Promise.resolve(d(i)):new Promise(o=>r.push({host:i,resolve:o}))},noteRetryAfter(e,i){const o=p(i,t());if(o==null||o<=0)return 0;const f=Math.min(o,15*6e4);return u.set(String(e||"").toLowerCase(),t()+f),f},holdFor(e){const i=u.get(String(e||"").toLowerCase());if(!i)return 0;const o=i-t();return o<=0?(u.delete(String(e||"").toLowerCase()),0):o},snapshot(){return{inFlight:Object.fromEntries(n),total:a,waiting:r.length,holds:u.size}}}}const w=200,m=/\b(paywall|subscribe to (continue|read)|subscription required|subscribers? only|become a (member|subscriber)|to continue reading|unlock this (article|story)|premium (article|content))\b/i,h=/(type=["']password["']|\b(sign in|log in|login) to (continue|view|read)\b|\bplease (sign|log) in\b|\byou must be logged in\b)/i;function T({status:t=200,headers:s={},html:l="",words:n=0}={}){const a=r=>{if(!s)return null;if(typeof s.get=="function")return s.get(r);const u=Object.keys(s).find(c=>c.toLowerCase()===r.toLowerCase());return u?s[u]:null};if(t===429||t===503){const r=a("retry-after");return{reason:"rate_limited",detail:r?`HTTP ${t}, Retry-After ${r}`:`HTTP ${t}`}}if(t===401||t===402||t===403)return{reason:t===402?"paywall":"login",detail:`HTTP ${t}`};if(n<w){const r=String(l||"");if(m.test(r))return{reason:"paywall",detail:"a subscription wall with little readable text"};if(h.test(r))return{reason:"login",detail:"a login form with little readable text"}}return null}function x(t){if(!t)return"";switch(t.reason){case"login":return"could not be read: the page is behind a login";case"paywall":return"could not be read: the page is behind a paywall";case"rate_limited":return"could not be read: the site asked us to slow down";case"robots":return"was not read: the site's robots.txt disallows it";case"tdm":return"was not read: the site reserves its content from automated mining";default:return"could not be read"}}export{g as HOST_BUDGET_DEFAULTS,w as THIN_PAGE_WORDS,y as createHostBudget,x as describeRestriction,p as parseRetryAfter,T as restrictionOf};
|
package/voice-models.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const u=Object.freeze({light:"Light",balanced:"Balanced",accurate:"Accurate",max:"Max",custom:"Custom"}),l=e=>e.approxMB?`~${e.approxMB} MB`:"";function p(e,{recommendedFirst:n=!1}={}){const o=e?.active||null,i=e?.progress||null,a=(e?.available||[]).slice();return n&&a.sort((t,r)=>(r.recommended?1:0)-(t.recommended?1:0)),a.map(t=>{const r=t.id===o,s=!!(i&&i.model===t.id),c=[t.tier?u[t.tier]||t.tier:"",t.lang||"",l(t),t.ramMB?`~${(t.ramMB/1024).toFixed(1)} GB RAM`:"",t.installed&&!r?"installed":""].filter(Boolean).join(" · "),d=t.unavailable?"Unavailable":s?`Downloading… ${i.pct||0}%`:r?"In use":t.installed?"Use":`Download${t.approxMB?` (${l(t)})`:""}`;return{id:t.id,title:t.label||t.id,recommended:!!t.recommended,meta:c,note:t.unavailable||t.note||"",downloading:s,progress:s?{pct:i.pct||0,file:i.file||""}:null,action:{label:d,disabled:!!(r||s||t.unavailable),primary:!(r||t.unavailable)}}})}function g(e){return e?.progress?`Downloading ${e.progress.model} — ${e.progress.pct||0}%…`:""}function f(e){const n=e?.dtypes||[{id:"auto",label:"Auto (recommended)"}],o=e?.dtype||"auto",i=e?.runtime==="wasm",a=(n.find(t=>t.id===o)||{}).note||"";return{active:e?.active||null,current:o,options:n.map(t=>{const r=i&&t.id!=="auto"&&t.id!=="fp32";return{id:t.id,label:`${t.label}${r?" — native only":""}`,disabled:r}}),note:a+(e?.loadedDtype?` · currently loaded: ${e.loadedDtype}`:"")}}function w(e){const n=e?.voices||[],o=e?.voice||"",i=e?.customVoiceList||[];if(e?.supportsCustomVoices){const r=[];return n.length&&r.push({label:"Built-in",options:n.map(s=>({value:s.id,label:s.installed===!1?`${s.label||s.id} — downloads on first use`:s.label||s.id}))}),i.length&&r.push({label:"Your voices",options:i.map(s=>({value:`custom:${s.id}`,label:`${s.name} (yours)`}))}),{visible:!0,current:o,groups:r,empty:r.length?"":"No voices yet — record one below",note:i.length?"Your own voices are derived from your recording and never leave this machine.":n.length?"Built-in voices work straight away. Record one below to speak in your own.":"This model speaks in a voice you record — add one under Your voices."}}if(e?.supportsVoices===!1||e?.arch&&e.arch!=="style-tts2")return{visible:!1,current:o,groups:[],empty:"",note:`${e.arch==="vits"?"This model is single-speaker":"This model has no selectable voices"} — one voice, one language. Switch to a Kokoro model to choose a voice.`};const t=n.find(r=>r.id===o);return{visible:!0,current:o,groups:n.length?[{label:"",options:n.map(r=>{const s=[r.grade?`grade ${r.grade}`:"",r.installed?"installed":"downloads on first use"].filter(Boolean).join(" · ");return{value:r.id,label:`${r.label} — ${s}`}})}]:[],empty:n.length?"":"—",note:t?.note||(n.length?"Grades are Kokoro’s own quality ratings. Each voice is a ~500 KB download.":"")}}function h(e){const n=e?.usable!==!1;return(e?.voices||[]).map(o=>{const a=(Array.isArray(o.kinds)?o.kinds:[]).includes("pocket-mimi");return{id:o.id,name:o.name,createdAt:o.createdAt||null,usable:n,note:n?a?"clones your voice":"SpeechT5 only — re-record for Pocket TTS":"needs a cloning model"}})}function m(e){const n=e?.progress||null,o=(e?.available||[])[0];if(!o)return null;const i=!!(n&&n.model===o.id||e?.state==="downloading"||e?.state==="loading"),a=e?.state==="ready"&&!!o.installed;return{id:o.id,title:o.label||o.id,meta:[l(o),o.installed?"installed":""].filter(Boolean).join(" · "),note:o.note||"",ready:a,downloading:i,progress:i?{pct:n?.pct||0,file:n?.file||""}:null,action:{label:i?`Downloading… ${n?.pct||0}%`:a?"Ready":o.installed?"Load":`Download (${l(o)})`,disabled:a||i,primary:!a}}}function b(e,n){return e?e.state==="error"?"error":e.active===n&&e.state==="ready"?"ready":null:null}function y(e,{name:n=""}={}){const o=String(e||"");return/404|unknown_endpoint|upstream fetch failed/.test(o)?"This gateway is too old for recorded voices — update it to 0.6.53+ and restart, then press Save again.":/embedder_not_ready|still downloading/.test(o)?"The speaker model is still loading — your recording was kept, press Save again in a moment.":/failed to load/.test(o)?`The speaker model failed to load. ${o}`:/did not answer within|did not answer in time/.test(o)?`The gateway took too long to answer. If "${n}" appears in the list above it was saved anyway — otherwise your recording was kept, press Save again.`:`Save failed: ${o} — your recording was kept, press Save again.`}function v(e){return/did not answer within|did not answer in time/.test(String(e||""))}function $(e,n){const o=String(n||""),i=/404|unknown_endpoint/.test(o);switch(e){case"stt":return i?"Update the gateway to enable local dictation.":`Models: ${o}`;case"tts":return i?"This gateway has no text-to-speech yet — update it (0.6.50+) and restart to use the local voice.":`Models: ${o}`;case"voices":return i?"Update the gateway (0.6.53+) to record your own voice.":o;case"diarize":return i?"Update the gateway to enable speaker diarization.":`Speaker model: ${o}`;default:return o}}export{u as TIER_LABEL,g as catalogStatus,$ as catalogUnavailable,m as diarizeRow,f as dtypePicker,p as modelRows,v as saveTimedOut,y as saveVoiceFailure,b as switchOutcome,h as voiceListRows,w as voicePicker};
|
package/voice-sample.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const N=16e3,_=3,v=10,D=20,b="The quick brown fox jumps over a lazy dog while five wizards vex him. Each child watched the choir approach the church on a chilly evening. She measured the rough edge, then judged both azure shapes against the light. Please call Stella and ask her to bring these things: a thin blue thread, seven small toys, and the yellow jug from the shed.";function C(e){return(e?.length||0)/16e3}function P(e){const t=C(e);return t>=3?null:`Only ${t.toFixed(1)}s — record at least 3s, or the voice print is mostly room noise.`}function O(e){return`Voice ${e.toLocaleTimeString()}`}function R(e,{where:t="ChatPanel"}={}){const a=e?.message||String(e);return/denied|NotAllowed|Permission/i.test(`${e?.name||""} ${a}`)?`Microphone blocked — allow it for ${t}, then try again.`:`Could not start recording: ${a}`}function w(){const e=globalThis.navigator;return{getUserMedia:e?.mediaDevices?t=>e.mediaDevices.getUserMedia(t):null,AudioContext:globalThis.AudioContext||globalThis.webkitAudioContext||null}}async function $({onLevel:e,onTick:t,onAutoStop:a,targetSeconds:x=10,media:c=w()}={}){const d=Math.min(20,Math.max(3,Number(x)||10));if(!c?.getUserMedia||!c?.AudioContext)throw new Error("no microphone available on this platform");const m=await c.getUserMedia({audio:{channelCount:1,echoCancellation:!0,noiseSuppression:!0}}),r=new c.AudioContext({sampleRate:16e3}),g=r.createMediaStreamSource(m),i=r.createScriptProcessor(4096,1,1),p=[];let l=0,S=!1;const h=r.createAnalyser();h.fftSize=512,g.connect(h);const f=new Uint8Array(h.frequencyBinCount);i.onaudioprocess=n=>{if(S)return;const s=n.inputBuffer.getChannelData(0);if(p.push(new Float32Array(s)),l+=s.length,e){h.getByteFrequencyData(f);let M=0;for(const y of f)M+=y;e(Math.min(1,M/f.length/128))}const o=l/16e3;t?.(o,d),o>=d&&(a?.(o),A.stop())},g.connect(i);const u=r.createGain();u.gain.value=0,i.connect(u),u.connect(r.destination);let E;const T=new Promise(n=>{E=n}),A={target:()=>d,seconds:()=>l/16e3,async stop(){if(S)return T;S=!0;try{i.disconnect(),g.disconnect(),u.disconnect()}catch{}for(const o of m.getTracks())try{o.stop()}catch{}try{await r.close()}catch{}const n=new Float32Array(l);let s=0;for(const o of p)n.set(o,s),s+=o.length;return p.length=0,E(n),n}};return A}export{D as MAX_SECONDS,_ as MIN_SECONDS,b as PROMPT_TEXT,N as SAMPLE_RATE,v as TARGET_SECONDS,O as defaultVoiceName,R as microphoneError,C as sampleSeconds,P as sampleTooShort,$ as startRecording,w as webMedia};
|
package/voice-vad.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const m=Object.freeze({minFrames:12,ratio:3,minEnergy:.06,floorAlpha:.02,cooldownFrames:45});function c(n={}){const t={...m,...n};let o=.02,e=0,r=0;return{get floor(){return o},feed(l,f=!0){const a=Math.max(0,Math.min(1,Number(l)||0));if(r>0)return r--,!1;const u=Math.max(t.minEnergy,o*t.ratio);return a>=u?(e++,e>=t.minFrames?(e=0,r=t.cooldownFrames,!0):!1):(e=0,f&&(o+=(a-o)*t.floorAlpha),!1)},reset(){e=0,r=0}}}function i(n,t=.25){if(!n||!n.length)return 0;const o=Math.max(1,Math.floor(n.length*t));let e=0;for(let r=0;r<o;r++)e+=n[r];return e/o/255}export{m as VAD_DEFAULTS,c as createVad,i as lowBandEnergy};
|
package/web-search.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const g=Object.freeze([Object.freeze({id:"startpage",name:"Startpage",url:"https://www.startpage.com/sp/search?query=%s",enabled:!0}),Object.freeze({id:"duckduckgo",name:"DuckDuckGo",url:"https://html.duckduckgo.com/html/?q=%s",enabled:!0}),Object.freeze({id:"google",name:"Google",url:"https://www.google.com/search?q=%s",enabled:!1}),Object.freeze({id:"bing",name:"Bing",url:"https://www.bing.com/search?q=%s",enabled:!1})]),h=5;function S(n,r,{assertFetchable:e}={}){const t=String(n||"").trim();if(!/^https:\/\//i.test(t))throw new Error("Search engine URL must start with https://");if(!t.includes("%s")&&!t.includes("{q}"))throw new Error("Search engine URL must contain a %s (or {q}) query placeholder");const s=t.replace(/%s|\{q\}/g,encodeURIComponent(String(r||"").trim()));return typeof e=="function"&&e(s),s}function m(n){try{const r=new URL(n,"https://duckduckgo.com"),e=r.searchParams.get("uddg");if(e)return decodeURIComponent(e);const t=r.searchParams.get("url")||r.searchParams.get("u");return t&&/^https?:/i.test(t)?t:r.href}catch{return String(n||"")}}const d=/(^|\.)(startpage\.com|startmail\.com|startpage\.dev|mojeek\.com|buttondown\.(com|email)|ecosia\.org|duckduckgo\.com|search\.brave\.com|qwant\.com)$/i;function w(n,r=""){const e=String(n||"").toLowerCase();if(!e||d.test(e))return!1;const t=String(r||"").split(".").slice(-2).join(".").toLowerCase();return!(t&&(e===t||e.endsWith(`.${t}`)))}function b(n,{engineHost:r="",limit:e=h,fallback:t=!1}={}){const s=[],c=new Map;for(const o of n||[]){const a=m(o?.href||"");let i;try{i=new URL(a)}catch{continue}if(i.protocol!=="https:"&&i.protocol!=="http:"||!w(i.hostname,r)||t&&o.chrome)continue;const u=String(o?.text||"").replace(/\s+/g," ").trim();if(u.length<6)continue;const p=i.origin+i.pathname;if(c.has(p)){const l=c.get(p);l&&!l.snippet&&u.length>l.title.length+10&&(l.snippet=u);continue}const f={url:a,title:u,snippet:String(o?.snippet||"").replace(/\s+/g," ").trim()};if(c.set(p,f),s.push(f),s.length>=e)break}return s}function k(n,r=8){const e=[],t=new Set;for(const s of n||[])for(const c of s||[]){let o;try{const a=new URL(c.url);o=a.origin+a.pathname}catch{o=c.url}if(!t.has(o)&&(t.add(o),e.push(c),e.length>=r))return e}return e}function R(n=g){const r=(Array.isArray(n)?n:[]).filter(e=>e&&e.url&&!e.retired);return[...r.filter(e=>e.enabled!==!1),...r.filter(e=>e.enabled===!1)]}export{h as RESULTS_PER_ENGINE,g as SEARCH_ENGINES,S as buildSearchUrl,R as engineOrder,w as isResultHost,k as mergeEngineResults,b as pickResults,m as unwrapRedirect};
|