glimmervoid 0.46.1 → 0.46.2-next.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/client/assets/{benchmark-panel-DChPUXGA.js → benchmark-panel-xSvlb82T.js} +1 -1
  2. package/dist/client/assets/benchmark-panel-xSvlb82T.js.br +0 -0
  3. package/dist/client/assets/{dialogs-DdT1F2S6.js → dialogs-CsBM709_.js} +1 -1
  4. package/dist/client/assets/dialogs-CsBM709_.js.br +0 -0
  5. package/dist/client/assets/{hooks-panel-BsUFFLp2.js → hooks-panel-B7rgryyG.js} +1 -1
  6. package/dist/client/assets/hooks-panel-B7rgryyG.js.br +0 -0
  7. package/dist/client/assets/{index-BReL4NSr.js → index-In1pKLyK.js} +4 -4
  8. package/dist/client/assets/index-In1pKLyK.js.br +0 -0
  9. package/dist/client/assets/{issues-panel-D28hf84c.js → issues-panel-BvkLz0pA.js} +1 -1
  10. package/dist/client/assets/issues-panel-BvkLz0pA.js.br +0 -0
  11. package/dist/client/assets/{plan-face-CJorgkgV.js → plan-face-B_2vu3O-.js} +1 -1
  12. package/dist/client/assets/plan-face-B_2vu3O-.js.br +0 -0
  13. package/dist/client/assets/{pr-scope-tabs-jELwYeSS.js → pr-scope-tabs-BBY0zxGB.js} +1 -1
  14. package/dist/client/assets/pr-scope-tabs-BBY0zxGB.js.br +0 -0
  15. package/dist/client/assets/{radar-panel-CTcFyxm0.js → radar-panel-9qe7QP0p.js} +1 -1
  16. package/dist/client/assets/radar-panel-9qe7QP0p.js.br +0 -0
  17. package/dist/client/assets/{review-queue-panel-R9p5_F6Q.js → review-queue-panel-D8vwdvPH.js} +1 -1
  18. package/dist/client/assets/review-queue-panel-D8vwdvPH.js.br +0 -0
  19. package/dist/client/assets/{settings-panel-3mnXcihD.js → settings-panel-C0UStpKa.js} +2 -2
  20. package/dist/client/assets/settings-panel-C0UStpKa.js.br +0 -0
  21. package/dist/client/assets/{trace-panel-6p6YymRs.js → trace-panel-CoQywm9H.js} +1 -1
  22. package/dist/client/assets/trace-panel-CoQywm9H.js.br +0 -0
  23. package/dist/client/assets/{usage-panel-DBzi4xwe.js → usage-panel-Y0qy6nIG.js} +1 -1
  24. package/dist/client/assets/usage-panel-Y0qy6nIG.js.br +0 -0
  25. package/dist/client/assets/{visions-panel-BMCIETcz.js → visions-panel-DZcLVbo8.js} +1 -1
  26. package/dist/client/assets/visions-panel-DZcLVbo8.js.br +0 -0
  27. package/dist/client/index.html +1 -1
  28. package/dist/client/index.html.br +0 -0
  29. package/package.json +1 -1
  30. package/dist/client/assets/benchmark-panel-DChPUXGA.js.br +0 -0
  31. package/dist/client/assets/dialogs-DdT1F2S6.js.br +0 -0
  32. package/dist/client/assets/hooks-panel-BsUFFLp2.js.br +0 -0
  33. package/dist/client/assets/index-BReL4NSr.js.br +0 -0
  34. package/dist/client/assets/issues-panel-D28hf84c.js.br +0 -0
  35. package/dist/client/assets/plan-face-CJorgkgV.js.br +0 -0
  36. package/dist/client/assets/pr-scope-tabs-jELwYeSS.js.br +0 -0
  37. package/dist/client/assets/radar-panel-CTcFyxm0.js.br +0 -0
  38. package/dist/client/assets/review-queue-panel-R9p5_F6Q.js.br +0 -0
  39. package/dist/client/assets/settings-panel-3mnXcihD.js.br +0 -0
  40. package/dist/client/assets/trace-panel-6p6YymRs.js.br +0 -0
  41. package/dist/client/assets/usage-panel-DBzi4xwe.js.br +0 -0
  42. package/dist/client/assets/visions-panel-BMCIETcz.js.br +0 -0
@@ -1,4 +1,4 @@
1
- import{A as e,Cn as t,D as n,E as r,Ft as i,Lt as a,M as o,P as s,Sn as c,T as l,_n as u,an as ee,bn as te,cn as ne,dn as d,fn as re,gn as ie,hn as ae,in as oe,k as se,ln as ce,mn as le,nn as ue,o as f,on as de,pn as fe,rn as p,sn as pe,un as me,vn as he,w as ge,xn as _e,y as ve,yn as ye}from"./dom-helpers-B98sy9ep.js";import{u as be}from"./control-ws-C8SS9PPx.js";import{n as xe}from"./poll-ago-DdlzkUaM.js";import{$ as Se,A as Ce,B as we,D as Te,Et as Ee,F as De,H as Oe,I as ke,L as Ae,M as je,N as Me,Ot as Ne,P as Pe,T as Fe,V as Ie,X as Le,b as Re,dt as ze,h as Be,i as Ve,j as He,m as Ue,r as We,s as Ge,st as Ke,tt as qe,ut as Je,w as Ye,x as Xe,y as Ze}from"./ui-prefs-Dvsgw_ZF.js";import{C as Qe,c as $e,d as et,i as tt,s as nt,t as rt}from"./action-status-D9Sf2cZp.js";import{a as it}from"./modal-5t7_5VCF.js";import{$n as at,A as m,Bn as ot,C as st,D as ct,E as lt,Fn as ut,Gn as dt,In as ft,Kn as pt,Ln as mt,M as ht,Mn as gt,Nn as _t,O as vt,Pn as yt,Qn as bt,Rn as xt,S as St,T as Ct,Un as wt,Vn as Tt,Wn as Et,X as Dt,Y as Ot,Zn as kt,_ as At,b as jt,br as Mt,dr as Nt,f as Pt,fr as Ft,g as It,h as Lt,i as Rt,j as zt,jn as Bt,k as h,lr as Vt,m as Ht,n as Ut,p as Wt,pr as Gt,r as Kt,t as qt,ur as Jt,v as Yt,vr as Xt,w as Zt,x as Qt,xr as $t,y as en,zn as tn}from"./index-BReL4NSr.js";import{agentLoginSummary as nn,openAgentConnectDialog as rn,openRemoteSetupDialog as an}from"./dialogs-DdT1F2S6.js";function on(){let e=f(`div`),t=f(`p`,`flying-animals-status`);t.id=`flying-animals-gallery-status`,t.setAttribute(`role`,`status`);let n=f(`div`,`flying-animals-gallery`);n.setAttribute(`aria-label`,`Animal gallery`);let r=[],i=()=>{let e=Ht(),n=Ee(Ve().flyingAnimalsExcludedSprites);t.textContent=[e,n?``:`No animals are included, so automatic flights are paused.`].filter(Boolean).join(` `);for(let t of r)t.disabled=e!==null},a=Ve();for(let e of Ne){let o=f(`article`,`flying-animal-tile`),s=$t(e),c=f(`label`,`flying-animal-include`),l=f(`input`,`settings-view-checkbox`);l.type=`checkbox`,l.checked=!a.flyingAnimalsExcludedSprites.includes(e.sprite),l.setAttribute(`aria-label`,`Include ${e.name}`),l.addEventListener(`change`,()=>{let t=new Set(Ve().flyingAnimalsExcludedSprites);l.checked&&t.delete(e.sprite),l.checked||t.add(e.sprite),He([...t]),Wt(Ze()),i()}),c.append(l,document.createTextNode(`Include`));let u=f(`button`,`btn-dialog btn-dialog-cancel`,`Fly now`);u.type=`button`,u.setAttribute(`aria-describedby`,t.id),u.addEventListener(`click`,()=>Lt(e.sprite)),r.push(u),o.append(s,f(`h2`,`flying-animal-name`,e.name),c,u),n.append(o)}return i(),e.append(t,n),e}var sn=`johncwaters/glimmervoid`,cn=Object.freeze([`auto`,`calculate`,`display`]);Object.freeze([`codex`,`grok`]),Object.freeze([`dailyUsd`,`monthlyUsd`]);var g={scope:`browser`,access:`editable`,takesEffect:`now`},_={scope:`browser`,access:`advanced`,takesEffect:`now`},v={scope:`machine`,access:`editable`,takesEffect:`now`},ln={scope:`machine`,access:`editable`,takesEffect:`new-sessions`},un={scope:`machine`,access:`readout`,takesEffect:`now`},y={scope:`machine`,access:`file-only`},dn=1e3,fn=60,pn=60,mn=dn*fn,hn=mn*pn,gn=hn*24,_n={label:`investigations`,storedPerDisplay:1},vn={label:`sessions`,storedPerDisplay:1},yn={label:`recurrences`,storedPerDisplay:1},bn={label:`actions`,storedPerDisplay:1},b={label:`seconds`,storedPerDisplay:1},xn={label:`minutes`,storedPerDisplay:1},Sn={label:`hours`,storedPerDisplay:1},x={label:`days`,storedPerDisplay:1},Cn={label:`seconds`,storedPerDisplay:dn,storedLabel:`ms`},wn={label:`minutes`,storedPerDisplay:mn,storedLabel:`ms`},Tn={label:`minutes`,storedPerDisplay:fn,storedLabel:`seconds`},En={label:`hours`,storedPerDisplay:hn,storedLabel:`ms`},Dn={label:`hours`,storedPerDisplay:pn,storedLabel:`minutes`},On={label:`days`,storedPerDisplay:gn,storedLabel:`ms`},kn={label:`USD`,storedPerDisplay:1},An={label:`users`,storedPerDisplay:1},jn={label:`reviews per hour`,storedPerDisplay:1},Mn={label:`times`,storedPerDisplay:1},S=`A tuning knob kept out of the Settings view; the default suits almost every install.`,C=`A diagnostic switch kept out of the Settings view; change it in config.json while investigating.`,w=`Changes how the server process or its worktrees behave, so it is set in config.json with a restart or new sessions in mind.`,Nn=`A structured value with no dashboard control; edit it in config.json.`,Pn=`Never editable from the dashboard by rule; edit it in config.json.`;function Fn(e){return e.map(e=>({value:e,label:e[0].toUpperCase()+e.slice(1)}))}var In=Object.freeze({"machine-terminal":{title:`Terminal`,description:`Terminal behavior shared by dashboard clients.`},"machine-detection-sessions":{title:`Detection and sessions`,description:`Config-file-only detection, timing, worktree and process settings.`},"lanes-ingest":{title:`Ingest`,description:`The machine-context sources behind Visions.`}}),Ln=Object.freeze([{id:`browser-appearance`,level:`browser`,title:`Appearance`,description:`How this browser draws the dashboard.`,legacyIds:[`browser-flying-animals`,`animals`,`flying-animals`],settings:[{id:`theme`,path:`pref:themeId`,title:`Theme`,description:`Color scheme for the dashboard.`,control:`select`,optionsFrom:`themes`,keywords:[`color`,`palette`],defaultValue:`phyrexian`,...g},{id:`session-usage-chips`,path:`pref:sessionUsageChips`,title:`Show usage on session cards`,description:`Shows each card's transcript token count and CLI-reported cost when available, otherwise a calculated API list-price estimate.`,control:`toggle`,keywords:[`usage`,`cost`,`tokens`,`card`,`price`],defaultValue:!1,...g},{id:`phone-arrow-pad`,path:`pref:phoneArrowPad`,title:`Swipe arrow pad on phone (experimental)`,description:`Replace the four arrow keys above the phone keyboard with one pad: swipe on it to send arrow keys, one per short drag.`,control:`toggle`,keywords:[`experimental`,`mobile`,`keys`,`arrows`,`swipe`,`gesture`],defaultValue:!1,...g},{id:`flying-animals`,path:`pref:flyingAnimalsEnabled`,title:`Flying animals`,description:`Show animated animals flying across the dashboard.`,control:`toggle`,keywords:[`animation`,`motion`,`animals`],defaultValue:!1,...g},{id:`animals-min-gap`,path:`pref:flyingAnimalsMinGapSeconds`,title:`Time between flights: minimum`,description:`Shortest pause between flights.`,control:`number`,integer:!1,step:.1,range:ee,unit:b,maximumSettingId:`animals-max-gap`,keywords:[`animals`,`frequency`],defaultValue:p.flyingAnimalsMinGapSeconds,..._},{id:`animals-max-gap`,path:`pref:flyingAnimalsMaxGapSeconds`,title:`Time between flights: maximum`,description:`Longest pause between flights.`,control:`number`,integer:!1,step:.1,range:ee,unit:b,keywords:[`animals`,`frequency`],defaultValue:p.flyingAnimalsMaxGapSeconds,..._},{id:`animals-min-duration`,path:`pref:flyingAnimalsMinDurationSeconds`,title:`Flight duration: minimum`,description:`Shortest flight, for faster animals.`,control:`number`,integer:!1,step:.1,range:oe,unit:b,maximumSettingId:`animals-max-duration`,keywords:[`animals`,`speed`],defaultValue:p.flyingAnimalsMinDurationSeconds,..._},{id:`animals-max-duration`,path:`pref:flyingAnimalsMaxDurationSeconds`,title:`Flight duration: maximum`,description:`Longest flight, for slower animals.`,control:`number`,integer:!1,step:.1,range:oe,unit:b,keywords:[`animals`,`speed`],defaultValue:p.flyingAnimalsMaxDurationSeconds,..._},{id:`animals-scale`,path:`pref:flyingAnimalsScale`,title:`Size multiplier`,description:`Scale applied on top of the viewport size.`,control:`number`,integer:!1,step:.1,range:de,unit:Mn,keywords:[`animals`,`size`],defaultValue:p.flyingAnimalsScale,..._},{id:`animals-on-phone`,path:`pref:flyingAnimalsOnPhone`,title:`Show on phone layout`,description:`Allow flights on the phone layout.`,control:`toggle`,keywords:[`animals`,`mobile`],defaultValue:p.flyingAnimalsOnPhone,..._}]},{id:`browser-notifications`,level:`browser`,title:`Notifications`,description:`How this browser, and the Telegram bot shared by every lane, get your attention.`,settings:[{id:`alert-sounds-enabled`,path:`pref:soundEnabled`,title:`Alert sounds`,legacyIds:[{sectionId:`browser-appearance`,settingId:`alert-sounds-enabled`}],description:`Play sounds when a session needs attention and when a merge celebration plays. The same switch as the note button in the desktop header.`,control:`toggle`,keywords:[`audio`,`mute`,`sound`,`notification`],defaultValue:!0,...g},{id:`alert-sound`,path:`pref:soundId`,title:`Alert sound`,legacyIds:[{sectionId:`browser-appearance`,settingId:`alert-sound`}],description:`Sound played when a session needs attention. Your own .ogg, .mp3, .wav, .m4a or .webm files dropped into the sounds folder of the Glimmervoid home (~/.glimmervoid/sounds/, or $GLIMMERVOID_HOME/sounds/) are listed after the built-in sounds. Glimmervoid never creates that folder, so make it yourself; new files show up the next time Settings opens.`,control:`select`,optionsFrom:`sounds`,keywords:[`audio`,`notification`,`custom`],defaultValue:`chime`,...g},{id:`desktop-notifications`,path:`pref:notificationsEnabled`,title:`Desktop notifications`,legacyIds:[{sectionId:`browser-appearance`,settingId:`desktop-notifications`}],description:`Raise a browser notification when a session needs attention while this dashboard is in the background.`,control:`toggle`,keywords:[`browser`,`attention`],defaultValue:!0,...g}]},{id:`machine-telegram`,level:`machine`,parent:`browser-notifications`,title:`Telegram`,description:`One bot shared by session, PR review and PostHog notifications.`,legacyIds:[`telegram`,`notifications`],settings:[{id:`telegram-bot-token`,path:`telegram.botToken`,title:`Bot token`,description:`Credential used by the shared Telegram bot. Create a bot by messaging @BotFather in Telegram and sending /newbot; it replies with this token. When GLIMMERVOID_TELEGRAM_BOT_TOKEN supplies it, this field is read-only.`,control:`password`,keywords:[`credential`,`api`],defaultValue:``,...v},{id:`telegram-chat-id`,path:`telegram.chatId`,title:`Chat id`,description:`Destination chat for enabled Telegram lanes. Send your bot any message, then open https://api.telegram.org/bot<token>/getUpdates in a browser and copy the number under message.chat.id.`,control:`text`,keywords:[`destination`,`channel`],defaultValue:``,...v},{id:`telegram-session-notifications`,path:`telegramNotifications`,title:`Send session notifications`,description:`Send session completion, input and failure alerts when no dashboard is open. Unacknowledged alerts also escalate after the phone escalation delay while a dashboard remains open.`,control:`toggle`,keywords:[`phone`,`off dashboard`,`test`],defaultValue:!1,status:`telegram-delivery`,...v}]},{id:`machine-sessions`,level:`machine`,title:`Sessions`,description:`How sessions start, where projects are found, and what the dashboard shows for them.`,legacyIds:[`machine-general`,`general`,`machine-repositories`,`repos`,`repositories`],settings:[{id:`auto-resume`,path:`autoResume`,title:`Auto-resume sessions on startup`,description:`Resume conversations that were live when Glimmervoid last shut down or crashed, and tell sessions that were mid-turn, or had a background agent, monitor or scheduled wakeup in flight, to continue.`,control:`toggle`,keywords:[`startup`,`conversation`],defaultValue:!0,...v},{id:`conversation-view`,path:`conversationView`,title:`Conversation view (experimental)`,description:`Let each Claude Code and Codex session turn on a Conversation face from its card menu, which renders the transcript as messages, approvals and a composer. Sessions stay on the terminal until you turn it on for them. A Claude Code session started while this is on can answer its permission prompts and questions there. A Codex session connects on its next start, through a local app-server so approvals can be answered from the dashboard; guarded Codex sessions and those that bypass Codex hook trust keep the terminal only.`,control:`toggle`,keywords:[`experimental`,`transcript`,`chat`,`codex`,`claude`],defaultValue:!1,...v},{id:`tab-order`,path:`viewTabOrder`,title:`Tab order`,description:`The order of the dashboard tabs in every browser: the header on desktop and the More menu on a phone. You can also drag a tab in the desktop header.`,control:`tab-order`,keywords:[`tabs`,`order`,`rearrange`,`reorder`,`header`,`more`,`menu`],defaultValue:[],...v},{id:`remote-sessions`,path:`remoteSessions`,title:`Remote Coder sessions (experimental)`,description:`Offer the Coder environments in config.json when adding a session, so the session runs in its own Coder workspace instead of on this machine. Off refuses new remote sessions; ones already running keep working until closed.`,control:`toggle`,keywords:[`experimental`,`coder`,`remote`,`workspace`,`cloud`],defaultValue:!1,...v},{id:`streamer-mode`,path:`streamerMode`,title:`Streamer mode`,description:`Hide sensitive details in the dashboard while screen sharing or streaming.`,control:`toggle`,keywords:[`streaming`,`screen share`,`privacy`],defaultValue:!1,...v},{id:`repository-roots`,path:`repoRoots`,title:`Repository roots`,description:`Directories scanned for projects when adding sessions.`,control:`list`,keywords:[`folders`,`project discovery`],defaultValue:[],listPlaceholder:`Repository root path`,listEmptyText:`No repository roots configured.`,...v},{id:`custom-agents`,path:`status:custom-agents`,title:`Custom agents`,description:`Extra agent CLIs a session can be spawned with, declared under customAgents in config.json.`,control:`readonly`,keywords:[`adapters`,`cli`],status:`custom-agents`,...un},{id:`agent-logins`,path:`status:agent-logins`,title:`Agent logins`,description:`How Claude Code and Codex sign in inside a Coder workspace. Each uses the login already on this machine; Connect signs one in for Glimmervoid alone when there is none.`,control:`readonly`,keywords:[`claude`,`codex`,`sign in`,`login`,`coder`,`remote`],status:`agent-logins`,...un},{id:`remote-setup`,path:`status:remote-setup`,title:`Remote host setup`,description:`Start a session that walks you through running Glimmervoid on another Linux machine you reach by ssh, as a service you open from your laptop and phone.`,control:`readonly`,keywords:[`remote`,`ssh`,`server`,`devbox`,`tailscale`,`pair`,`host`],status:`remote-setup`,...un}]},{id:`machine-guardrails`,level:`machine`,title:`Guardrails and unattended`,description:`What a guarded session may touch, and which unattended actions automated work may take. Claude Code sessions on Linux and macOS write anywhere this account can, except credentials, Glimmervoid's own state and the blocked folders here.`,legacyIds:[`lanes-unattended`,`unattended`],settings:[{id:`skip-permissions-by-default`,path:`skipPermissionsByDefault`,title:`Skip permission prompts by default`,description:`Start sessions whose project sets no permission choice with the agent CLI permission bypass flag.`,control:`toggle`,keywords:[`permissions`,`yolo`,`dangerously`],danger:!0,warning:`Enabling this control lets agents edit files and run shell commands without asking, and restarts running sessions that inherit it.`,defaultValue:!1,...v},{id:`sane-yolo`,path:`saneYolo`,title:`Sane YOLO`,description:`Block catastrophic commands in sessions that skip permission prompts when the cc-safety-net executable is available and trusted hooks are installed. Missing or untrusted hooks leave a session unprotected.`,control:`toggle`,keywords:[`permissions`,`yolo`,`safety`],defaultValue:!0,...ln},{id:`rtk-compression`,path:`rtk`,title:`rtk output compression`,description:`Compress Bash output with the rtk executable.`,control:`toggle`,keywords:[`bash`,`tokens`],danger:!0,status:`rtk-install`,warning:`Enabling this control permits Glimmervoid to install the pinned rtk executable automatically.`,defaultValue:!1,...ln},{id:`branch-gc-delete-unmerged`,path:`branchGc.deleteUnmerged`,title:`Delete unmerged branches`,description:`Also delete stale remote branches with no merge proof. Off keeps every unmerged branch.`,control:`toggle`,keywords:[`git`,`cleanup`,`orphan`],danger:!0,warning:`Enabling this control lets branch cleanup delete stale remote branches without merge proof.`,defaultValue:!1,...v},{id:`guardrails-unguarded-repos`,path:`guardrails.unguardedRepos`,title:`Unguarded repositories`,description:`Folders whose sessions run without guardrails. A session started in one of these folders, or below it, is not guarded.`,control:`list`,keywords:[`guardrails`,`opt out`,`dotfiles`],danger:!0,warning:`A session without guardrails can read credentials and write anywhere this account can.`,defaultValue:[],listPlaceholder:`Folder path`,listEmptyText:`Every repository is guarded.`,...ln},{id:`guardrails-blocked-paths`,path:`guardrails.blockedPaths`,title:`Blocked folders`,description:`Extra folders and files a guarded session cannot write, on top of credentials and Glimmervoid's own state. A leading ~ means the home folder.`,control:`list`,keywords:[`guardrails`,`block`,`protect`],defaultValue:[],listPlaceholder:`~/folder`,listEmptyText:`Only the built-in list is blocked.`,...ln},{id:`guardrails-unreadable-paths`,path:`guardrails.unreadablePaths`,title:`Unreadable folders`,description:`Extra folders and files a guarded session cannot read, on top of the built-in credential list. A leading ~ means the home folder.`,control:`list`,keywords:[`guardrails`,`secrets`,`credentials`],defaultValue:[],listPlaceholder:`~/folder`,listEmptyText:`Only the built-in credential list is unreadable.`,...ln}]},{id:`machine-updates`,level:`machine`,title:`Updates`,description:`See which Glimmervoid version is running, which one is newest, and update in one step.`,legacyIds:[`updates`],settings:[{id:`update-actions`,path:`status:update-actions`,title:`Status and actions`,legacyIds:[`update-summary`,`update-installed`,`update-latest`,`update-last-checked`].map(e=>({sectionId:`machine-updates`,settingId:e})),description:`Whether this install is up to date, the running and newest versions, the last check, and the update and restart actions.`,control:`readonly`,keywords:[`version`,`available`,`current`,`check`,`restart`,`commit`,`installed`,`release`,`failure`],status:`update-actions`,...un},{id:`update-channel`,path:`updateChannel`,title:`Channel`,description:`Track stable releases, or Experimental builds published from every change to main before it reaches a release.`,control:`select`,options:Fn(a),keywords:[`release`,`prerelease`,`next`,`beta`,`early`],defaultValue:`release`,...v},{id:`check-updates`,path:`checkForUpdates`,title:`Check for updates automatically`,description:`Check for a newer Glimmervoid at launch, while a dashboard is connected, and when this page opens.`,control:`toggle`,keywords:[`release`,`github`],defaultValue:!0,...v}]},{id:`machine-usage`,level:`machine`,title:`Usage`,description:`Local transcript accounting and estimated-cost budgets.`,legacyIds:[`usage`],settings:[{id:`usage-enabled`,path:`usage.enabled`,title:`Track token usage`,description:`Read local CLI transcripts and roll them into the Usage view and session chips.`,control:`toggle`,keywords:[`tokens`,`cost`],defaultValue:!0,status:`usage-last-report`,...v},{id:`usage-retain-days`,path:`usage.retainDays`,title:`Retain transcript detail`,description:`How long live transcript detail stays available. A monthly budget keeps detail from the start of the current month when that is longer.`,control:`number`,range:te,unit:x,keywords:[`history`,`retention`],defaultValue:90,...v},{id:`usage-daily-budget`,path:`usage.budget.dailyUsd`,title:`Daily budget`,description:`Estimated daily spend alert threshold. Alerts at 50%, 75% and 100% do not stop spending. Zero or below disables the threshold.`,control:`number`,range:he,unit:kn,keywords:[`spend`,`alert`],defaultValue:null,integer:!1,nullable:!0,zeroIsNull:!0,step:.01,...v},{id:`usage-monthly-budget`,path:`usage.budget.monthlyUsd`,title:`Monthly budget`,description:`Estimated monthly spend alert threshold. Alerts at 50%, 75% and 100% do not stop spending. Zero or below disables the threshold.`,control:`number`,range:he,unit:kn,keywords:[`spend`,`alert`],defaultValue:null,integer:!1,nullable:!0,zeroIsNull:!0,step:.01,...v}]},{id:`lanes-visions`,level:`lanes`,title:`Visions`,description:`Editor-buffer findings, bounded model comments, and the machine-context ingest behind them.`,legacyIds:[`lanes`,`visions`,`lanes-ingest`,`ingest`],settings:[{id:`visions-enabled`,path:`visions.enabled`,title:`Enable Visions`,description:`Set up supported editors detected on this machine, then show their buffer findings in the Visions view.`,control:`toggle`,keywords:[`editor`,`findings`,`lsp`],defaultValue:!1,...v},{id:`visions-dispatch-enabled`,path:`visions.dispatch.enabled`,title:`Enable model comments`,description:`Start bounded review sessions for local editor buffers.`,control:`toggle`,keywords:[`review`,`dispatch`],defaultValue:!1,...v},{id:`visions-max-per-hour`,path:`visions.dispatch.maxPerHour`,title:`Max per hour`,description:`Maximum review sessions dispatched per hour. One slot is reserved for edit reviews; activity-driven reviews take the rest, up to the activity cap set by visions.dispatch.activityMaxPerHour.`,control:`number`,range:d,unit:jn,keywords:[`rate limit`,`reviews`],defaultValue:6,...v},{id:`visions-model`,path:`visions.dispatch.model`,title:`Model override`,description:`Leave blank to use the opus model alias.`,control:`text`,keywords:[`claude`,`override`],defaultValue:``,...v},{id:`visions-projects`,path:`visions.projects`,title:`Projects`,description:`Clear every selection, including unavailable projects, to accept buffers from every configured project.`,control:`projects`,keywords:[`repositories`,`filter`],defaultValue:[],...v},{id:`visions-auto-fix`,path:`visions.autoFix`,title:`Apply tier 1 fixes`,description:`Allow Visions to edit eligible open Markdown buffers, including inactive buffers, without asking.`,control:`toggle`,keywords:[`automatic`,`edits`],danger:!0,warning:`Enabling this control lets Visions edit eligible buffers without a carbon unit present.`,defaultValue:!1,...v},{id:`ingest-enabled`,path:`ingest.enabled`,title:`Enable machine context ingest`,description:`Enable the local activity feed behind Visions. Turning Visions on enables ingest unless ingest.enabled is explicitly false.`,control:`toggle`,keywords:[`events`,`activity`,`ingest`],defaultValue:!1,...v}]},{id:`lanes-posthog`,level:`lanes`,title:`PostHog`,description:`Error monitoring, investigations and traffic-spike alerts.`,legacyIds:[`posthog`],settings:[{id:`posthog-enabled`,path:`posthog.enabled`,title:`Enable PostHog monitoring`,description:`Poll PostHog error tracking and investigate issues that move.`,control:`toggle`,keywords:[`errors`,`monitoring`],defaultValue:!1,...v},{id:`posthog-host`,path:`posthog.host`,title:`Host`,description:`PostHog cloud or self-hosted HTTP URL.`,control:`text`,keywords:[`url`,`server`],defaultValue:`https://us.posthog.com`,...v},{id:`posthog-api-key`,path:`posthog.apiKey`,title:`Personal API key`,description:`Credential with read access to PostHog projects. When GLIMMERVOID_POSTHOG_API_KEY supplies it, this field is read-only.`,control:`password`,keywords:[`credential`,`token`],defaultValue:``,...v},{id:`posthog-projects`,path:`posthog.projects`,title:`Projects`,description:`PostHog project ids to monitor. config.json holds "all" or an array of ids, and an empty array monitors no project. In Settings that empty array shows as none, and an empty list saves "all".`,control:`list`,keywords:[`project ids`,`filter`],defaultValue:`all`,valueKind:`posthog-projects`,listPlaceholder:`Project id`,listEmptyText:`Every project the key can read.`,...v},{id:`posthog-interval`,path:`posthog.intervalMinutes`,title:`Poll interval`,description:`Delay between PostHog polling passes.`,control:`number`,integer:!1,step:`any`,range:d,unit:xn,keywords:[`refresh`,`schedule`],defaultValue:15,...v},{id:`posthog-max-investigations`,path:`posthog.maxConcurrentInvestigations`,title:`Max concurrent investigations`,description:`Maximum investigation sessions running together.`,control:`number`,range:d,unit:_n,keywords:[`parallel`,`workers`],defaultValue:2,...v},{id:`posthog-min-users`,path:`posthog.minUsersToInvestigate`,title:`Min users to investigate`,description:`Minimum affected users for a new issue investigation. Regressions, worsening issues and eligible error spikes bypass this minimum.`,control:`number`,range:d,unit:An,keywords:[`threshold`,`affected`],defaultValue:1,...v},{id:`posthog-traffic-enabled`,path:`posthog.trafficSpikeEnabled`,title:`Traffic spike alerts`,description:`Ping when recent unique users exceed a project baseline.`,control:`toggle`,keywords:[`analytics`,`alert`],defaultValue:!0,...v},{id:`posthog-auto-fix`,path:`posthog.autoFix`,title:`Attempt fixes for major issues`,description:`Allow an isolated agent to fix an issue, push a branch and open a pull request.`,control:`toggle`,keywords:[`automatic`,`pull request`],danger:!0,warning:`Enabling this control lets PostHog fixes commit, push and open pull requests automatically.`,defaultValue:!1,...v}]},{id:`lanes-team-review`,level:`lanes`,title:`Team review`,description:`Draft reviews of teammates' pull requests for you to post from the Reviews tab.`,legacyIds:[`team-review`,`reviews`],settings:[{id:`team-review-enabled`,path:`teamReview.enabled`,title:`Enable team review`,description:`Poll open pull requests from the team and draft a review of each one. Nothing is posted until you choose Approve or Comment.`,control:`toggle`,keywords:[`pull requests`,`github`],defaultValue:!0,...v},{id:`github-teams`,path:`github.teams`,title:`GitHub teams`,description:`Teams to search for review requests and members, one org/slug per entry. Leave empty to fall back to the legacy teamReview.org and teamReview.team keys in config.json.`,control:`list`,keywords:[`github`,`teams`,`review requests`],defaultValue:[],listPlaceholder:`org/team-slug`,listEmptyText:`No GitHub teams configured.`,...v},{id:`team-review-re-review-after-hours`,path:`teamReview.reReviewAfterHours`,title:`Re-review after`,description:`When a reviewed PR has a new head, review it again after this long since its last review. Re-run review runs it at any time.`,control:`number`,range:d,unit:Sn,keywords:[`review`,`delay`],defaultValue:24,integer:!1,step:.5,...v},{id:`team-review-skip-idle-after-days`,path:`teamReview.skipIdleAfterDays`,title:`Skip PRs idle for`,description:`Leave pull requests without GitHub activity for this long out of automatic review.`,control:`number`,range:d,unit:x,keywords:[`idle`,`activity`],defaultValue:14,integer:!1,step:.5,...v},{id:`team-review-skill`,path:`teamReview.skill`,title:`Review skill`,description:`Name of a Claude Code skill installed for the review agent, for example your own PR review skill. Leave empty to let the agent review with whatever skills it has.`,control:`text`,keywords:[`skill`,`claude code`,`pr review`],defaultValue:``,...v},{id:`team-review-auto-rebase-my-prs`,path:`teamReview.autoRebaseMyPrs`,title:`Keep my pull requests rebased`,description:`On each poll, rebase your open, non-draft pull requests that are behind their base branch. A pull request with conflicts or checks still running is left alone, and a failed rebase is not retried until you push again.`,control:`toggle`,keywords:[`rebase`,`update branch`,`behind`,`my prs`],danger:!0,warning:`Enabling this control rewrites your pull request branches on GitHub. Pull before you push from a local checkout of one.`,defaultValue:!1,...v},{id:`team-review-keep-mergeable-enabled`,path:`teamReview.keepMergeableEnabled`,title:`Keep mergeable`,description:`Offer Keep mergeable on your pull requests: a guarded agent repairs conflicts and failing checks and pushes the repair. Off hides the control and starts no repair; the pull requests you chose stay chosen for when you turn it back on.`,control:`toggle`,keywords:[`repair`,`conflicts`,`my prs`],defaultValue:!0,...v},{id:`team-review-keep-mergeable-timeout`,path:`teamReview.keepMergeableTimeoutMinutes`,title:`Keep mergeable deadline`,description:`Longest a Keep mergeable repair session may run before it is stopped and nothing is pushed.`,control:`number`,range:pe,unit:xn,keywords:[`timeout`,`repair`],defaultValue:30,...v},{id:`team-review-merge-queue-enabled`,path:`teamReview.mergeQueueEnabled`,title:`Merge when ready`,description:`Offer Merge when ready on your pull requests: queued pull requests are rebased when behind and merged once ready, one per repository per poll. Off hides the control and merges nothing; the queue is kept for when you turn it back on.`,control:`toggle`,keywords:[`merge queue`,`auto merge`,`my prs`],defaultValue:!0,...v}]},{id:`lanes-workflows`,level:`lanes`,title:`Workflows`,description:`Rules that act on pull request events in the repositories you choose.`,legacyIds:[`workflows`],settings:[{id:`workflows-enabled`,path:`workflows.enabled`,title:`Run workflows`,description:`Poll the repositories your enabled rules watch and run their actions. Off stops polling and every action, whatever each rule says.`,control:`toggle`,keywords:[`pull requests`,`automation`,`master switch`],defaultValue:!0,...v},{id:`workflows-max-concurrent-sessions`,path:`workflows.maxConcurrentSessions`,title:`Concurrent agent sessions`,description:`Most workflow agent sessions running at once. Up to twenty later spawns wait for a free slot; additional spawns are dropped and logged.`,control:`number`,range:t,unit:vn,keywords:[`parallel`,`spawn`],defaultValue:2,...v},{id:`workflows-rules`,path:`status:workflow-rules`,title:`Workflow rules`,description:`Each rule watches repositories for one pull request event (opened, checks-failed, review-requested, approved, commented or merged), narrows it by author, labels, base branch, your own pull requests or a review request to your team, and then notifies you, labels or comments on the pull request, or starts a guarded agent session that pushes nothing. Rules start disabled. Turn each rule on or off here; everything else about a rule is set in config.json under workflows.rules.`,control:`readonly`,keywords:[`pull requests`,`automation`,`github`,`rules`],status:`workflows`,...un}]},{id:`lanes-benchmarks`,level:`lanes`,title:`Benchmarks`,description:`Compare agent setups on frozen cases from the suites in the benchmarks folder of the Glimmervoid home.`,legacyIds:[`benchmarks`],settings:[{id:`benchmarks-enabled`,path:`benchmarks.enabled`,title:`Enable benchmarks`,description:`Show the Bench tab. Nothing runs until you choose Mine or Run there.`,control:`toggle`,keywords:[`eval`,`arms`,`recall`,`compare`],defaultValue:!1,...v}]},{id:`lanes-coherence`,level:`lanes`,title:`Coherence (experimental)`,description:`Per-session Coherence hook status and decision journal for agent sessions.`,settings:[{id:`coherence-enabled`,path:`coherence.enabled`,title:`Show session Coherence`,description:`Shows each session's Coherence hook status and decision journal when the repository installed @posthog/coherence 1.8 or newer. Off by default.`,control:`toggle`,keywords:[`experimental`,`coherence`,`journal`,`decisions`],defaultValue:!1,...v}]},{id:`lanes-issues`,level:`lanes`,title:`Issues (experimental)`,description:`GitHub issues from your projects and teams in their own dashboard tab.`,settings:[{id:`issues-enabled`,path:`issues.enabled`,title:`Show the Issues tab`,description:`Poll GitHub issues for your projects and teams and list them in an Issues tab. Off stops the polling and hides the tab.`,control:`toggle`,keywords:[`experimental`,`issues`,`github`,`tab`],defaultValue:!1,...v}]},{id:`machine-privacy`,level:`machine`,title:`Privacy`,description:`What Glimmervoid sends about itself.`,legacyIds:[`privacy`,`telemetry`],settings:[{id:`telemetry-enabled`,path:`telemetry.enabled`,title:`Send usage data`,description:`Helps us improve Glimmervoid. Sent under a random install id: version, platform, app starts, daily activity, session starts and ends with agent kind, exit kind and duration, errors as their type, error code and scrubbed stack frames, per session token counts, models and estimated costs from the usage scan, and a salted one-way hash of your Claude and Codex account ids so installs of one account count together. Never prompts, project information, error messages, paths, repository or branch names, objectives, terminal output, emails or names. Delete my data asks for everything sent under this install to be erased and starts a new install id. GLIMMERVOID_TELEMETRY=0, DO_NOT_TRACK=1 or CI=true turn it off regardless.`,control:`toggle`,keywords:[`telemetry`,`analytics`,`tracking`,`opt out`],defaultValue:!0,...v}]},{id:`browser-shortcuts`,level:`browser`,title:`Shortcuts`,description:`Keyboard shortcuts and their reference.`,legacyIds:[`shortcuts`],settings:[{id:`next-attention-key`,path:`pref:nextAttentionKeyCode`,title:`Jump to the next session needing you`,description:`The key held with Cmd on a Mac, or Alt elsewhere, that jumps to the next session needing you. Record a new one by pressing the whole shortcut.`,control:`shortcut-key`,keywords:[`shortcut`,`keyboard`,`hotkey`,`jump`,`next`,`attention`],defaultValue:`KeyJ`,...g}]}]),Rn=Object.freeze([{id:`file-debug-mode`,path:`debugMode`,title:`Debug mode`,group:`machine-sessions`,description:`Show session-card diagnostics for state, transitions and detection signals.`,control:`toggle`,keywords:[`diagnostics`,`state`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:C,...y},{id:`file-replay-buffer`,path:`replayBufferKB`,title:`Replay buffer`,group:`machine-terminal`,description:`PTY output retained for clients that reconnect or join late.`,control:`number`,range:ie,unit:{label:`KB`,storedPerDisplay:1},keywords:[`history`,`backfill`],defaultValue:512,takesEffect:`new-sessions`,fileOnlyReason:S,...y},{id:`file-session-memory-reserve`,path:`sessionMemoryReserveMB`,title:`Session memory reserve`,group:`machine-sessions`,description:`Free memory an automatic session start waits for; 0 starts sessions without checking.`,control:`number`,range:ne,unit:{label:`MB`,storedPerDisplay:1},keywords:[`memory`,`headroom`],defaultValue:600,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-cursor-blink`,path:`cursorBlink`,title:`Cursor blink`,group:`machine-terminal`,description:`Blink the cursor in every terminal.`,control:`toggle`,keywords:[`caret`,`terminal`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-detect-background-agents`,path:`detectBackgroundAgents`,title:`Detect background agents`,group:`machine-detection-sessions`,description:`Hold completion while tracked background work is active.`,control:`toggle`,keywords:[`subagents`,`completion`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:C,...y},{id:`file-record-signals`,path:`recordSignals`,title:`Record structural signals`,group:`machine-detection-sessions`,description:`Keep forensic status and hook recordings for each session. Full capture (capture.enabled) records these signals even when this is off.`,control:`toggle`,keywords:[`recordings`,`diagnostics`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:C,...y},{id:`file-trace-enabled`,path:`trace.enabled`,title:`Capture session traces`,group:`machine-detection-sessions`,description:`Keep normalized Claude transcript traces for session debugging.`,control:`toggle`,keywords:[`transcripts`,`diagnostics`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:C,...y},{id:`file-detect-scheduled-wakeups`,path:`detectScheduledWakeups`,title:`Detect scheduled wakeups`,group:`machine-detection-sessions`,description:`Surface advisory wakeup timing for scheduled sessions.`,control:`toggle`,keywords:[`schedule`,`sleep`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:C,...y},{id:`file-worktree-auto-rebase`,path:`worktreeAutoRebase`,title:`Worktree auto-rebase`,group:`machine-detection-sessions`,description:`Rebase eligible session worktrees when the integration branch moves.`,control:`toggle`,keywords:[`git`,`branch`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-sync-on-start`,path:`worktreeSyncOnStart`,title:`Worktree sync on start`,group:`machine-detection-sessions`,description:`Fetch origin and fast-forward the local integration branch before a session starts its worktree.`,control:`toggle`,keywords:[`git`,`fetch`,`fast-forward`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-rerere`,path:`worktreeRerere`,title:`Worktree rerere`,group:`machine-detection-sessions`,description:`Reuse recorded Git conflict resolutions.`,control:`toggle`,keywords:[`git`,`conflicts`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:w,...y},{id:`file-integration-branch`,path:`integrationBranch`,title:`Integration branch`,group:`machine-detection-sessions`,description:`Base branch for session worktrees. Empty = each repo's default branch. Existing sessions are never retargeted.`,control:`text`,nullable:!0,keywords:[`git`,`merge`],defaultValue:null,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-root`,path:`worktreeRoot`,title:`Worktree root`,group:`machine-detection-sessions`,description:`Directory that contains session worktrees. Existing worktrees are never relocated.`,control:`text`,keywords:[`git`,`directory`],defaultValue:``,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-share`,path:`worktreeShare`,title:`Shared worktree paths`,group:`machine-detection-sessions`,description:`Local paths copied or linked during worktree preparation.`,control:`list`,keywords:[`files`,`context`],defaultValue:[`.env`,`.env.local`,`.claude`],takesEffect:`new-sessions`,fileOnlyReason:Pn,...y},{id:`file-port`,path:`port`,title:`Local port`,group:`machine-detection-sessions`,description:`Port used by the local dashboard listener.`,control:`number`,range:me,unit:{label:`port`,storedPerDisplay:1},keywords:[`server`,`listener`],defaultValue:3e3,takesEffect:`restart`,fileOnlyReason:Pn,...y},{id:`file-notify-debounce-ms`,path:`notifyDebounceMs`,title:`Notification debounce`,group:`machine-detection-sessions`,description:`Delay used to coalesce notification state changes.`,control:`number`,integer:!1,step:`any`,range:d,unit:Cn,keywords:[`timer`,`alerts`],defaultValue:3e3,takesEffect:`new-sessions`,fileOnlyReason:S,...y},{id:`file-phone-escalation-ms`,path:`phoneEscalationMs`,title:`Phone escalation delay`,group:`machine-detection-sessions`,description:`Delay before off-dashboard escalation.`,control:`number`,integer:!1,step:`any`,range:d,unit:wn,keywords:[`timer`,`telegram`],defaultValue:3e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-branch-gc-enabled`,path:`branchGc.enabled`,title:`Branch cleanup`,group:`machine-detection-sessions`,description:`Enable cleanup of eligible session branches.`,control:`toggle`,keywords:[`git`,`cleanup`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-worktrees`,path:`branchGc.worktrees`,title:`Local worktree cleanup`,group:`machine-detection-sessions`,description:`Enable cleanup of eligible local worktrees.`,control:`toggle`,keywords:[`git`,`worktree`,`cleanup`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-prefixes`,path:`branchGc.prefixes`,title:`Branch cleanup prefixes`,group:`machine-detection-sessions`,description:`Branch prefixes that filter both remote branch cleanup and local worktree cleanup.`,control:`list`,keywords:[`git`,`branch`],defaultValue:[`glimmervoid/session/`,`worktree-agent-`],takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-dry-run`,path:`branchGc.dryRun`,title:`Branch cleanup dry run`,group:`machine-detection-sessions`,description:`Report planned cleanup without deleting remote branches.`,control:`toggle`,keywords:[`git`,`safety`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-stale-days`,path:`branchGc.staleDays`,title:`Branch stale days`,group:`machine-detection-sessions`,description:`Age threshold for orphan branch cleanup when unmerged deletion is on.`,control:`number`,integer:!1,step:`any`,range:d,unit:x,keywords:[`git`,`retention`],defaultValue:14,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-branch-gc-interval-ms`,path:`branchGc.intervalMs`,title:`Branch cleanup interval`,group:`machine-detection-sessions`,description:`Delay between branch cleanup passes.`,control:`number`,integer:!1,step:`any`,range:d,unit:En,keywords:[`git`,`schedule`],defaultValue:216e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-custom-agents`,path:`customAgents`,title:`Custom agents`,group:`machine-detection-sessions`,description:`Extra agent CLIs a session can be spawned with. The Sessions section lists the declared agents and whether each command resolves.`,control:`json`,keywords:[`adapters`,`cli`],defaultValue:[],takesEffect:`new-sessions`,fileOnlyReason:Pn,...y},{id:`file-task-title-refiner-enabled`,path:`taskTitle.refiner.enabled`,title:`Refine task titles`,group:`machine-detection-sessions`,description:`Keep session card titles useful when prompts change topic by asking a model for a short title.`,control:`toggle`,keywords:[`title`,`refiner`,`card`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-model`,path:`taskTitle.refiner.model`,title:`Task title model`,group:`machine-detection-sessions`,description:`Claude model alias the title refiner asks.`,control:`text`,keywords:[`title`,`refiner`,`model`],defaultValue:`haiku`,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-min-interval`,path:`taskTitle.refiner.minIntervalSeconds`,title:`Task title refresh interval`,group:`machine-detection-sessions`,description:`Shortest pause between two title refinements of one session.`,control:`number`,integer:!1,step:`any`,range:ce,unit:b,keywords:[`title`,`refiner`,`interval`],defaultValue:60,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-timeout`,path:`taskTitle.refiner.timeoutSeconds`,title:`Task title timeout`,group:`machine-detection-sessions`,description:`Maximum time allowed for one title refinement.`,control:`number`,integer:!1,step:`any`,range:u,unit:b,keywords:[`title`,`refiner`,`deadline`],defaultValue:60,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-codex`,path:`usage.vendors.codex`,title:`Track Codex usage`,group:`machine-usage`,description:`Include local Codex CLI transcripts in usage reports.`,control:`toggle`,keywords:[`openai`,`vendor`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-grok`,path:`usage.vendors.grok`,title:`Track Grok usage`,group:`machine-usage`,description:`Include local Grok CLI transcripts in usage reports.`,control:`toggle`,keywords:[`xai`,`vendor`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-fetch-pricing`,path:`usage.fetchPricing`,title:`Fetch current model prices`,group:`machine-usage`,description:`Load public model prices when usage tracking starts, using a cached table for up to one day. Falls back to cached or bundled prices if the fetch fails; no daily refresh runs while tracking continues.`,control:`toggle`,keywords:[`rates`,`models`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:S,...y},{id:`file-usage-plan-limits`,path:`usage.planLimits`,title:`Show plan limits`,group:`machine-usage`,description:`Read the Claude plan limit the CLI reports and show it beside usage.`,control:`toggle`,keywords:[`plan`,`limits`,`quota`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-rtk-savings`,path:`usage.rtkSavings`,title:`Estimate rtk savings`,group:`machine-usage`,description:`Estimate the tokens rtk output compression saved and show it in the Usage view.`,control:`toggle`,keywords:[`rtk`,`savings`,`tokens`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-scan-interval`,path:`usage.scanIntervalMinutes`,title:`Scan interval`,group:`machine-usage`,description:`Periodic transcript polling interval. Session activity can also trigger scans between timer ticks.`,control:`number`,range:_e,unit:xn,keywords:[`poll`,`refresh`],defaultValue:5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-warehouse-retain-days`,path:`usage.warehouseRetainDays`,title:`Retain usage history`,group:`machine-usage`,description:`How long the daily usage warehouse keeps rolled-up totals after transcript detail expires.`,control:`number`,range:ye.warehouseRetainDays,unit:x,keywords:[`history`,`warehouse`,`retention`],defaultValue:365,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-session-block-hours`,path:`usage.sessionBlockHours`,title:`Session block length`,group:`machine-usage`,description:`Length of the rolling block the Usage view groups activity into.`,control:`number`,range:ye.sessionBlockHours,unit:Sn,keywords:[`block`,`window`,`hours`],defaultValue:5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-cost-mode`,path:`usage.costMode`,title:`Cost mode`,group:`machine-usage`,description:`Choose whether recorded costs, calculated costs or both can appear.`,control:`select`,options:Fn(cn),keywords:[`pricing`,`estimate`],defaultValue:`auto`,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-extra-projects-dirs`,path:`usage.extraProjectsDirs`,title:`Extra transcript folders`,group:`machine-usage`,description:`Absolute paths of additional Claude projects folders the usage scan reads.`,control:`list`,keywords:[`transcripts`,`folders`,`scan`],defaultValue:[],takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-quiet-delay`,path:`visions.dispatch.quietMs`,title:`Quiet delay`,group:`lanes-visions`,description:`Editor quiet time before a scheduled review. Saves and blank-line boundaries can dispatch immediately, subject to the other review limits.`,control:`number`,range:d,unit:Cn,keywords:[`debounce`,`idle`],defaultValue:3e4,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-cooldown`,path:`visions.dispatch.cooldownMs`,title:`Cooldown`,group:`lanes-visions`,description:`Minimum delay between reviews of the same document. Initial orientation reviews bypass this delay.`,control:`number`,range:d,unit:wn,keywords:[`rate limit`,`delay`],defaultValue:3e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-activity-max-per-hour`,path:`visions.dispatch.activityMaxPerHour`,title:`Activity max per hour`,group:`lanes-visions`,description:`Maximum activity-driven reviews dispatched per hour, capped at the overall hourly limit minus one to reserve an edit-review slot.`,control:`number`,range:ce,unit:jn,keywords:[`rate limit`,`events`],defaultValue:2,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-dispatch-timeout`,path:`visions.dispatch.dispatchTimeoutSeconds`,title:`Dispatch timeout`,group:`lanes-visions`,description:`Maximum time allowed for one review session.`,control:`number`,range:d,unit:Tn,keywords:[`deadline`,`review`],defaultValue:180,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-intent-thread-ttl`,path:`visions.intent.threadTtlMs`,title:`Intent thread lifetime`,group:`lanes-visions`,description:`How long an intent thread nobody advanced stays live before it retires.`,control:`number`,range:d,unit:On,keywords:[`intent`,`decay`,`thread`],defaultValue:2592e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-terminal`,path:`ingest.sources.terminal.enabled`,title:`Terminal output source`,group:`lanes-ingest`,description:`Include terminal output in the ingest feed.`,control:`toggle`,keywords:[`pty`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-agent-logs`,path:`ingest.sources.agentLogs.enabled`,title:`Agent logs source`,group:`lanes-ingest`,description:`Include local agent logs in the ingest feed.`,control:`toggle`,keywords:[`transcript`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-git`,path:`ingest.sources.git.enabled`,title:`Git activity source`,group:`lanes-ingest`,description:`Include local Git activity in the ingest feed.`,control:`toggle`,keywords:[`commits`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-fs`,path:`ingest.sources.fs.enabled`,title:`File changes source`,group:`lanes-ingest`,description:`Include watched file changes in the ingest feed.`,control:`toggle`,keywords:[`filesystem`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-shell-history`,path:`ingest.sources.shellHistory.enabled`,title:`Shell history source`,group:`lanes-ingest`,description:`Include local shell history in the ingest feed.`,control:`toggle`,keywords:[`commands`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-editor`,path:`ingest.sources.editor.enabled`,title:`Editor events source`,group:`lanes-ingest`,description:`Include local editor events in the ingest feed.`,control:`toggle`,keywords:[`buffers`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-investigation-timeout`,path:`posthog.investigationTimeoutSeconds`,title:`Investigation timeout`,group:`lanes-posthog`,description:`Maximum time allowed for one investigation.`,control:`number`,integer:!1,step:`any`,range:d,unit:Tn,keywords:[`deadline`,`session`],defaultValue:900,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-escalation`,path:`posthog.userEscalationThreshold`,title:`Escalation threshold`,group:`lanes-posthog`,description:`Affected-user count that escalates an issue.`,control:`number`,range:d,unit:An,keywords:[`threshold`,`severity`],defaultValue:25,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-fix-timeout`,path:`posthog.fixTimeoutSeconds`,title:`Fix timeout`,group:`lanes-posthog`,description:`Maximum time allowed for one fix session.`,control:`number`,integer:!1,step:`any`,range:re,unit:Tn,keywords:[`deadline`,`repair`],defaultValue:1800,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-multiplier`,path:`posthog.trafficSpikeMultiplier`,title:`Spike multiplier`,group:`lanes-posthog`,description:`Baseline multiplier required to classify a traffic spike.`,control:`number`,integer:!1,step:`any`,range:ae,unit:Mn,keywords:[`baseline`,`ratio`],defaultValue:3,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-min-users`,path:`posthog.trafficSpikeMinUsers`,title:`Min users to alert`,group:`lanes-posthog`,description:`Minimum recent unique users for an initial traffic-spike alert. Escalation and recovery alerts bypass this minimum.`,control:`number`,range:le,unit:An,keywords:[`threshold`,`analytics`],defaultValue:10,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-cooldown`,path:`posthog.trafficSpikeCooldownMinutes`,title:`Spike cooldown`,group:`lanes-posthog`,description:`Cooldown for new traffic spikes. Escalation and recovery alerts bypass it. Zero removes the time delay; repeated active-spike alerts are still suppressed.`,control:`number`,integer:!1,step:`any`,range:ce,unit:Dn,keywords:[`silence`,`delay`],defaultValue:360,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-baseline`,path:`posthog.trafficSpikeBaselineDays`,title:`Baseline window`,group:`lanes-posthog`,description:`Historical window used to calculate normal hourly traffic.`,control:`number`,range:fe,unit:x,keywords:[`history`,`analytics`],defaultValue:7,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-recurrence-dedupe`,path:`posthog.recurrenceDedupe`,title:`Deduplicate recurring issues`,group:`lanes-posthog`,description:`Treat an issue seen again inside the recurrence window as the same investigation instead of opening a new one.`,control:`toggle`,keywords:[`recurrence`,`dedupe`,`issues`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-recurrence-window-days`,path:`posthog.recurrenceWindowDays`,title:`Recurrence window`,group:`lanes-posthog`,description:`How far back an issue counts as a recurrence of an investigated one.`,control:`number`,integer:!1,step:`any`,range:d,unit:x,keywords:[`recurrence`,`window`],defaultValue:7,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-transient-recurrence-limit`,path:`posthog.transientRecurrenceLimit`,title:`Transient recurrence limit`,group:`lanes-posthog`,description:`How many times a transient issue may recur before it is investigated again.`,control:`number`,integer:!1,step:`any`,range:d,unit:yn,keywords:[`recurrence`,`transient`,`limit`],defaultValue:3,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-repo-path`,path:`posthog.repoPath`,title:`Repository path`,group:`lanes-posthog`,description:`Absolute path of the local checkout investigations read and fixes branch from, for every project the project map does not name.`,control:`text`,keywords:[`repository`,`checkout`,`path`],defaultValue:``,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-project-map`,path:`posthog.projectMap`,title:`Project map`,group:`lanes-posthog`,description:`PostHog project id to a label: the name shown for that project, and, when it is an absolute path to a checkout, the repository its issues are investigated in.`,control:`json`,keywords:[`projects`,`repositories`,`map`],defaultValue:{},takesEffect:`now`,fileOnlyReason:Nn,...y},{id:`file-team-review-org`,path:`teamReview.org`,title:`GitHub organization (legacy)`,group:`lanes-team-review`,description:`Organization login that owns the team, for example PostHog. Read only when github.teams is empty.`,control:`text`,keywords:[`github`,`owner`,`legacy`],defaultValue:``,takesEffect:`now`,fileOnlyReason:`A legacy key: github.teams names teams as org/slug entries and wins whenever it is set.`,...y},{id:`file-team-review-team`,path:`teamReview.team`,title:`GitHub team (legacy)`,group:`lanes-team-review`,description:`Team slug whose members and review requests are polled. Read only when github.teams is empty.`,control:`text`,keywords:[`github`,`slug`,`legacy`],defaultValue:``,takesEffect:`now`,fileOnlyReason:`A legacy key: github.teams names teams as org/slug entries and wins whenever it is set.`,...y},{id:`file-workflows-max-actions-per-poll`,path:`workflows.maxActionsPerPoll`,title:`Actions per poll`,group:`lanes-workflows`,description:`Most actions run in one poll. The rest are dropped and logged.`,control:`number`,range:c,unit:bn,keywords:[`cap`,`rate limit`],defaultValue:20,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-workflows-rules`,path:`workflows.rules`,title:`Workflow rule definitions`,group:`lanes-workflows`,description:`The rules the Workflows section switches on and off: each names its repositories, one pull request event, its filters and its actions.`,control:`json`,keywords:[`pull requests`,`automation`,`rules`],defaultValue:[],takesEffect:`now`,fileOnlyReason:`Rule definitions are written in config.json; the Workflows section only switches each rule on or off.`,...y}]),zn=Object.freeze({sections:Ln,fileOnly:Rn}),Bn=`experimental`;function Vn(e){return e.keywords.includes(Bn)}function Hn(e,t){return t?e:e.flatMap(e=>{let t=e.settings.filter(e=>!Vn(e));return t.length===0&&e.settings.length>0?[]:[{...e,settings:t}]})}var Un=Object.freeze(Object.fromEntries(Ln.flatMap(e=>(e.legacyIds??[]).map(t=>[t,e.id])))),Wn=Object.freeze(Ln.reduce((e,t)=>{for(let n of t.settings)for(let r of n.legacyIds??[])e[r.sectionId]={...e[r.sectionId],[r.settingId]:t.id};return e},{}));function T(e){let t=[],n=e=>{if(!e||typeof e!=`object`)return e;let n=Array.isArray(e)?[]:{};return t.push([e,n]),n},r=n(e);for(let e=t.pop();e;e=t.pop()){let[t,r]=e;for(let[e,i]of Object.entries(t))Object.defineProperty(r,e,{value:n(i),writable:!0,enumerable:!0,configurable:!0})}return r}function Gn(e,t){let n=e;for(let e of t.split(`.`)){if(typeof n!=`object`||!n)return;n=n[e]}return n}function Kn(e,t){let n=t.split(`.`),r=e;for(let e of n.slice(0,-1)){if(!r||typeof r!=`object`)return;r=r[e]}r&&typeof r==`object`&&delete r[n.at(-1)]}function qn(e,t,n){let r=t.split(`.`),i=e;for(let e of r.slice(0,-1))(!i[e]||typeof i[e]!=`object`||Array.isArray(i[e]))&&(i[e]={}),i=i[e];i[r.at(-1)]=T(n)}function E(e){return e.flatMap(e=>e.settings)}function Jn(e){return e.access===`file-only`||e.control===`readonly`}function Yn(e){let t=String(e??``).trim().toLowerCase();if(!t||t===`all`)return`all`;if(t===`none`)return[];let n=t.split(`,`).map(e=>e.trim());return n.every(e=>/^\d+$/.test(e)&&Number.isSafeInteger(Number(e))&&Number(e)>0)?n.map(Number):null}var Xn=6;function D(e,t){return e.control===`number`&&typeof t==`number`?t/(e.unit?.storedPerDisplay??1):e.valueKind===`posthog-projects`?Array.isArray(t)?t.length===0?[`none`]:t.map(String):[]:T(t)}function Zn(e){return e.control===`number`&&(e.unit?.storedPerDisplay??1)!==1}function Qn(e){return String(Number(e.toFixed(Xn)))}function $n(e,t){let n=D(e,t);return e.valueKind===`posthog-projects`&&Array.isArray(n)?n.join(`, `)||`all`:typeof n==`number`&&e.unit?`${Qn(n)} ${e.unit.label}`:JSON.stringify(n??null)}function O(e,t){if(e.control===`number`){if(e.nullable&&(t==null||String(t).trim()===``))return null;let n=Number(t);if(e.zeroIsNull&&n<=0)return null;let r=n*(e.unit?.storedPerDisplay??1);return e.integer===!1?r:Math.round(r)}if(e.valueKind===`posthog-projects`)return Yn(Array.isArray(t)?t.join(`,`):t);if(e.control===`text`||e.control===`password`){let n=String(t??``).trim();return e.nullable&&!n?null:n}return T(t)}function k(e){return String(e||``).toLowerCase().match(/[a-z0-9]+/g)||[]}var er=3,tr=2,nr=1,rr=3,ir=30,ar=16;function or(e,t){return e===t?er:e.startsWith(t)?tr:t.length>=rr&&e.includes(t)?nr:0}function A(e,t,n){let r=0;for(let n of t){let t=Math.max(0,...e.map(e=>or(e,n)));if(t===0)return 0;r+=t}return r*n}function sr(e){return e.options?.map(e=>e.label).join(`, `)??``}function cr(e){return gr(e.group??``)?.title??``}function lr(e,t,n){let r=A(k(e.title),n,1e3),i=A(k(e.keywords.join(` `)),n,100),a=A(t,n,10),o=A(k(e.path),n,10),s=A(k(sr(e)),n,10),c=A(k(e.description),n,1);return r+i+a+o+s+c}function ur(e){return e.section?.title??``}function dr(e,t){return Number(e.section===null)-Number(t.section===null)}function fr(e,t,n){return[[`title`,e.title],[`keywords`,e.keywords.join(` `)],[`section`,t?.title??cr(e)],[`description`,e.description],[`path`,e.path],[`options`,sr(e)]].flatMap(([e,t])=>{let r=[];for(let e of t.matchAll(/[a-z0-9]+/gi)){let t=e[0].toLowerCase();for(let i of n){if(or(t,i)===0)continue;let n=e.index+t.indexOf(i);r.push({start:n,end:n+i.length})}}let i=[];for(let e of r.sort((e,t)=>e.start-t.start||e.end-t.end)){let t=i.at(-1);t&&e.start<=t.end?t.end=Math.max(t.end,e.end):i.push({...e})}return i.length?[{field:e,text:t,spans:i}]:[]})}function pr(e,t,n=[]){let r=k(t).slice(0,ar);if(r.length===0)return[];let i=[];for(let t of e){let e=k(t.title);for(let n of t.settings){let a=lr(n,e,r);a!==0&&i.push({section:t,setting:n,score:a,matches:fr(n,t,r)})}}for(let e of n){let t=lr(e,k(cr(e)),r);t!==0&&i.push({section:null,setting:e,score:t,matches:fr(e,null,r)})}return i.sort((e,t)=>t.score-e.score||dr(e,t)||ur(e).localeCompare(ur(t))||e.setting.title.localeCompare(t.setting.title)).slice(0,ir)}function mr(e,t,n={},r={}){let i=/^#settings\/([^/]+)(?:\/([^/]+))?$/.exec(String(e||``));if(!i)return null;let a,o;try{a=decodeURIComponent(i[1]),o=i[2]?decodeURIComponent(i[2]):null}catch{return null}let s=n[a]||a,c=(o?r[s]?.[o]:void 0)||s,l=t.find(e=>e.id===c);if(!l)return null;let u=o?l.settings.find(e=>e.id===o||e.legacyIds?.some(e=>e.settingId===o&&e.sectionId===s)):null;return o&&!u?null:{sectionId:c,settingId:u?.id||null,hash:`#settings/${c}${u?`/${u.id}`:``}`}}function hr(e){let t=new Map,n=new Map;for(let r of[...E(e.sections),...e.fileOnly])t.set(r.id,r),n.set(r.path,r);return{byId:t,byPath:n}}hr(zn);function gr(e,t=zn){let n=t.sections.find(t=>t.id===e);return n?{title:n.title,description:n.description}:In[e]??null}function _r({checked:e=[],stored:t=[],rendered:n=[]}={}){let r=new Set(n),i=[...e];for(let e of t)typeof e==`string`&&e.trim()&&(r.has(e)||i.includes(e)||i.push(e));return i}function vr(e,t){let n=new Set(e.map(e=>e.id)),r=[...new Set(t)].filter(e=>!n.has(e));return[...e,...r.map(e=>({id:e,name:`Unavailable project (${e})`}))]}var yr=new WeakMap,br=`Configured`,xr=`•`.repeat(12),Sr=`Each line must be a positive whole-number PostHog project id, or the one word none.`,Cr=3,wr=new Set([`customAgents`]),Tr=1e-9,Er=`Lanes`,Dr=Object.freeze({now:`Applies now`,"new-sessions":`New sessions`,restart:`After restart`}),Or=Object.freeze({browser:`This browser`,machine:`This machine`});function kr(e,t){let n=t.secretSources;if(!n||typeof n!=`object`)return null;let r=n[e.path];return typeof r==`string`?r:null}function Ar(e){let t=e.rtkInstall;return t?.status===`installing`?`No rtk binary found. Glimmervoid is installing it into ~/.glimmervoid/bin now.`:e.rtkInstallSupported===!1?`No rtk binary found. Automatic installation is unavailable on this server platform; install a compatible binary manually.`:t?.status===`failed`?`No rtk binary found. The last install attempt failed: ${t.reason||`unknown reason`}. A save can retry after the ten-minute failure cooldown; saves during the cooldown skip installation.`:`No rtk binary found. Saving requests installation into ~/.glimmervoid/bin on supported server platforms, subject to installer eligibility.`}function jr(e){return e.control===`password`}function Mr(e){return`${e.path}${br}`}function Nr(e,t){if(Object.is(e,t))return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>Nr(e,t[n]));if(!e||!t||typeof e!=`object`||typeof t!=`object`)return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.hasOwn(t,n)&&Nr(e[n],t[n]))}function Pr(e){return yr.get(e)||null}function Fr(e){return Array.isArray(e)?e.map(e=>String(e)):[]}function Ir(e){return e.split(`
2
- `).map(e=>e.trim()).filter(e=>e!==``)}function Lr(e){let t=e.range;if(!t)return null;let n={min:Number(D(e,t.min))};return t.max!=null&&(n.max=Number(D(e,t.max))),t.exclusiveMin&&(n.exclusiveMin=!0),n}function Rr(e){let t=`Default ${$n(e,e.defaultValue)}`;return Zn(e)?`${t}, stored as ${JSON.stringify(e.defaultValue)} ${e.unit?.storedLabel??``}`.trimEnd():t}function zr(e,t){let n=Rr(e),r=wr.has(e.path)?void 0:Gn(t,e.path);if(r===void 0)return{currentText:null,defaultText:n,jsonFragment:null};let i={};return qn(i,e.path,r),{currentText:`Current ${$n(e,r)}`,defaultText:n,jsonFragment:JSON.stringify(i,null,2)}}function Br(e,t,n){let r=t??e.find(e=>e.id===n.group);if(!r)return gr(n.group??``)?.title??`config.json`;let i=e.find(e=>e.id===r.parent);return i?`${i.title} / ${r.title}`:r.level===`lanes`?`${Er} / ${r.title}`:r.title}function Vr(e,t){return e.filter(e=>e.parent===t)}function Hr(e,t){let n=e.find(e=>e.id===t);return n?n.parent?e.find(e=>e.id===n.parent)??n:n:null}function Ur(e){return e.filter(e=>!e.parent)}function Wr(e){let t=e.filter(e=>e.level===`lanes`);return[{heading:null,sections:e.filter(e=>e.level!==`lanes`)},{heading:Er,sections:t}].filter(e=>e.sections.length>0)}function Gr(e,t,n,r){return r?`hidden`:n.trim()?`search`:t&&Hr(e,t)?`section`:`list`}function Kr(e,t={}){let n={};for(let r of E(e)){if(Jn(r))continue;if(r.path.startsWith(`pref:`)){let e=r.path.slice(5),i=t.prefs?.[e]??t[r.path];n[r.path]=D(r,i??r.defaultValue);continue}if(jr(r)){let e=Gn(t,Mr(r))===!0;n[r.path]=e?xr:``;continue}let e=Gn(t,r.path);n[r.path]=D(r,e??r.defaultValue)}return yr.set(n,T(t)),n}function qr(e,t,n){let r=E(e).filter(e=>Jn(e)||e.path.startsWith(`pref:`)||kr(e,Pr(t)||{})||jr(e)&&n[e.path]===xr?!1:!Nr(t[e.path],n[e.path]));if(r.length===0)return{};let i=Pr(t)||{},a=(Array.isArray(i.projectChoices)?i.projectChoices:[]).map(e=>e.id).filter(e=>typeof e==`string`),o={},s=new Set;for(let e of r){let[r]=e.path.split(`.`);if(!e.path.includes(`.`)){o[r]=O(e,n[e.path]);continue}if(!s.has(r)){let e=i[r];o[r]=e&&typeof e==`object`&&!Array.isArray(e)?T(e):{},s.add(r)}let c=O(e,n[e.path]);if(e.control===`projects`){let n=t[e.path];c=_r({checked:Array.isArray(c)?c:[],stored:Array.isArray(n)?n:[],rendered:vr(a.map(e=>({id:e,name:e})),Array.isArray(n)?n:[]).map(e=>e.id)})}qn(o,e.path,c)}for(let t of E(e))jr(t)&&Kn(o,Mr(t));return delete o.secretSources,o}function Jr(e,t,n,r){return Ci(qr(e,t,{...t,[n.path]:r}))}function Yr(e){let t=e.unit?.label;return t?` of ${t}`:``}function j(e){let t=Lr(e);if(!t)return`Allowed range is unavailable.`;let n=`${e.integer!==!1&&!Zn(e)?`whole number`:`number`}${Yr(e)}`;return t.exclusiveMin&&t.min===0?`Must be a positive ${n}.`:t.max==null?`Must be a ${n} ${t.exclusiveMin?`above`:`of at least`} ${Qn(t.min)}.`:`Must be a ${n} between ${Qn(t.min)} and ${Qn(t.max)}.`}function Xr(e){return`Must be a multiple of ${$n(e,1)}.`}function Zr(e){return Math.abs(e-Math.round(e))<Tr&&Number.isSafeInteger(Math.round(e))}function Qr(e,t){return Number(O({...e,integer:!1,nullable:!1,zeroIsNull:!1},t))}function $r(e,t){if(e.nullable&&(t==null||String(t).trim()===``))return null;let n=e.range;if(!n)return`Allowed range is unavailable.`;if(t==null||String(t).trim()===``)return j(e);let r=Number(t);if(!Number.isFinite(r))return j(e);if(e.zeroIsNull&&r<=0)return null;let i=Qr(e,r);if(e.integer!==!1&&!Zr(i))return Zn(e)?Xr(e):j(e);let a=Number(O(e,r));return n.exclusiveMin&&a<=n.min||!n.exclusiveMin&&a<n.min||n.max!=null&&a>n.max?j(e):null}function ei(e,t,n=!1){return n?j(e):$r(e,t.trim())}function ti(e,t){let n=t.trim();if(e.nullable&&n===``)return null;let r=Number(n);return e.zeroIsNull&&r<=0?null:r}function ni(e){if(e==null||e===``)return``;let t=Number(e);return Number.isFinite(t)?Qn(t):String(e)}function ri(e,t){return Array.isArray(t)?e.valueKind===`posthog-projects`&&O(e,t)===null?Sr:null:`Must be a list.`}function ii(e,t){let n={};for(let r of E(e)){if(Jn(r))continue;let e=null;r.control===`number`&&(e=$r(r,t[r.path])),r.control===`list`&&(e=ri(r,t[r.path])),r.control===`select`&&r.options&&!r.options.some(e=>e.value===t[r.path])&&(e=`Choose one of the available options.`),e&&(n[r.id]=e)}return ai(E(e),t,n),n}function ai(e,t,n){for(let r of e){let i=e.find(e=>e.id===r.maximumSettingId);if(!i||n[r.id]||n[i.id])continue;let a=t[r.path],o=t[i.path];Number(O(r,a))>Number(O(i,o))&&(n[r.id]=`Minimum must not exceed the maximum (${ni(o)}).`,n[i.id]=`Maximum must not be below the minimum (${ni(a)}).`)}}function oi(e,t){return E(e).find(e=>e.id===t.maximumSettingId||e.maximumSettingId===t.id)}function si(e,t,n){let r=oi(e,t);return ii([{id:`scoped`,level:`machine`,title:``,description:``,settings:r?[t,r]:[t]}],n)[t.id]??null}function ci(e,t){return e.control===`number`?ti(e,t):e.control===`list`?Ir(t):t}function li(e,t){return O(e,e.control===`list`?Fr(t):t)}function ui(e){return e?.isDirty===!0}function di(e,t,n,r,i,a=!1){if(!ui(n))return{kind:`unchanged`};let o=t.control===`number`?ei(t,r,a):null;if(o)return{kind:`invalid`,error:o};let s=ci(t,r);if(Nr(O(t,s),li(t,n.base)))return{kind:`unchanged`};let c=si(e,t,{...i,[t.path]:s});return c?{kind:`invalid`,error:c}:{kind:`changed`,value:s}}function fi(e){return jr(e)?``:D(e,e.defaultValue)}function pi(e,t){return Nr(t,fi(e))}function mi(e){return e.presentation?e.presentation:(e.options?.length??0)<=Cr?`segmented`:`select`}function hi(e){return Array.isArray(e)?e.length>0:typeof e==`string`?e.trim()!==``:e===!0}function gi(e,t){return e.danger===!0&&!!e.warning&&hi(t)}function _i(e,t){return gi(e,t)}function vi(e){return e.title.charAt(0).toLowerCase()+e.title.slice(1)}function yi(e){return jr(e)?`Reset removes the stored ${vi(e)}. Anything that relies on it stops until a new one is saved.`:_i(e,fi(e))?e.warning??``:null}function bi(e){return[e.repos.join(`, `),e.trigger,e.actions.map(e=>e.type).join(`, `)].join(` `)}function xi(e){if(e==null)return[`No rules. Add workflows.rules to config.json.`];let t=ue.safeParse(e);return t.success?t.data.rules.length===0?[`No rules. Add workflows.rules to config.json.`]:t.data.rules.map(e=>[e.name,e.enabled?`enabled`:`disabled`,bi(e)].join(` `)):[`The workflows block is invalid, so no rule runs: ${t.error.issues[0]?.message??`unknown problem`}`]}function Si(e){let t=ue.safeParse(e??{});return t.success?t.data.rules.map(e=>({id:e.id,name:e.name,isEnabled:e.enabled,summary:bi(e)})):[]}function Ci(e){let t=e.workflows;return typeof t!=`object`||!t||Array.isArray(t)?e:{...e,workflows:Object.fromEntries(Object.entries(t).filter(([e])=>e!==`rules`))}}var wi=2200,Ti=1600,Ei=15e3,Di=`https://glimmervoid.dev`,Oi=`browser-appearance`,ki=`flying-animals`,Ai=Object.freeze({ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}),ji=`lanes-features`,Mi=Object.freeze({id:ji,level:`lanes`,title:`Features`,description:`Optional tabs, each hidden until its own toggle is on.`,settings:[]}),Ni=`browser-shortcuts`,Pi=`browser-status-key`,Fi=Object.freeze({id:Pi,level:`browser`,title:`Status key`,description:`What each session status and pull request icon means.`,settings:[]}),Ii=`browser-about`,Li=Object.freeze({id:Ii,level:`browser`,title:`About`,description:`The running build and where the project lives.`,settings:[]}),Ri=Object.freeze({sounds:()=>xt(),themes:yt});function zi(e){if(!e.optionsFrom)return e;let t=Ri[e.optionsFrom]?.()??[];return{...e,options:t.map(e=>({value:e.id,label:e.label}))}}function Bi(e){return e.isExperimentalBuild===!0}function Vi(){return Hn(zn.sections,Bi(h()))}function Hi(){let e=Vi().map(e=>({...e,settings:e.settings.map(zi)})),t=e.findIndex(e=>e.id===Ni)+1,n=[...e.slice(0,t),Fi,...e.slice(t)],r=n.findIndex(e=>e.level===`lanes`);return Object.freeze([...n.slice(0,r),Mi,...n.slice(r),Li])}var M=Hi(),Ui=Bi(h()),N=!1,Wi=null,Gi=null,P=null,F=null,I=null,Ki=null,L=null,R=null,z=M[0],B=h(),V={},qi=new Map,Ji=new Map,H=new Map,U=new WeakMap,Yi=Promise.resolve(),W=new Map,G=``,Xi=!1,Zi=new Set,K=new Map;function Qi(){return{themeId:Be(),flyingAnimalsEnabled:Ze(),...We(),soundEnabled:Fe(),soundId:mt(Ue()),notificationsEnabled:Re(),sessionUsageChips:Ye(),phoneArrowPad:Xe(),nextAttentionKeyCode:Ge()}}function $i(e){V=Kr(M,{...e,prefs:Qi()})}function q(e){return H.has(e.id)?H.get(e.id):V[e.path]}function ea(e){return[e,...Vr(M,e.id)]}function ta(e){return ea(e).flatMap(e=>e.settings)}function na(e){return M.find(t=>t.settings.some(t=>t.id===e.id))??z}function ra(e,t=null){history.replaceState(history.state,``,Yt(e,t))}function ia(e){requestAnimationFrame(()=>{let t=document.getElementById(e),n=t?.closest(`.settings-view-advanced-panel`);n&&(N=!0,n.hidden=!1,R?.querySelector(`.settings-view-advanced-toggle`)?.setAttribute(`aria-expanded`,`true`));let r=t?.closest(`.settings-view-setting`);r&&(r.scrollIntoView({block:`center`}),r.classList.remove(`settings-view-setting-flash`),requestAnimationFrame(()=>r.classList.add(`settings-view-setting-flash`)))})}function aa(e){e.replaceChildren();for(let t of ze(tn,Et())){let n=f(`div`,`shortcut-group`);n.appendChild(f(`h2`,`settings-view-subsection-title`,t.title));let r=f(`dl`,`shortcut-rows`);for(let e of t.items){let t=f(`dd`,`shortcut-keys`);e.combos.forEach((e,n)=>{n>0&&t.appendChild(f(`span`,`shortcut-sep`,`/`)),ot(t,e)}),r.append(f(`dt`,`shortcut-label`,e.label),t)}n.appendChild(r),e.appendChild(n)}}function oa(e){return vt().find(t=>t.gate!==void 0&&`fromSettings`in t.gate&&t.gate.fromSettings===e)?.label}function sa(e){let t=f(`ul`,`settings-view-stack settings-features`);for(let e of Rt){let n=M.find(t=>t.id===e.sectionId),r=da(e.settingId),i=oa(Kt[e.rule]);if(!n||!r||!i)continue;let a=q(r)===!0,o=f(`li`,`settings-feature`),s=f(`div`,`settings-feature-head`);s.append(f(`span`,`settings-feature-name`,i),yo(`feature`,a?`On`:`Off`)),o.append(s,f(`p`,`settings-view-section-description`,n.description),It(e.sectionId,e.settingId,r.title)),t.appendChild(o)}e.appendChild(t)}function ca(e){let t=new URL(e,Di),{telemetryInstallId:n}=B;return typeof n==`string`&&n&&t.searchParams.set(`gv`,n),t.href}function la(e,t){let n=f(`a`,`settings-about-link`,e);return n.href=t,n.target=`_blank`,n.rel=`noopener`,n}function ua(e){let t=f(`div`,`settings-about`),n=f(`span`,`settings-about-version`,`GLIMMERVOID `);n.appendChild(f(`span`,`settings-about-v`,`v0.46.1`));let r=f(`span`,`settings-about-links`);r.append(la(`GitHub`,`https://github.com/${sn}`),la(`Changelog`,`https://github.com/${sn}/blob/main/CHANGELOG.md`),la(`Website`,ca(`/`))),t.append(n,r),e.appendChild(t)}function da(e){return M.flatMap(e=>e.settings).find(t=>t.id===e)??null}function fa(e){if(V[`pref:soundEnabled`]===e)return;V[`pref:soundEnabled`]=e;let t=da(`alert-sounds-enabled`);t&&Z(t)}var pa={"pref:flyingAnimalsMinGapSeconds":e=>De(Number(e)),"pref:flyingAnimalsMaxGapSeconds":e=>Me(Number(e)),"pref:flyingAnimalsMinDurationSeconds":e=>Pe(Number(e)),"pref:flyingAnimalsMaxDurationSeconds":e=>je(Number(e)),"pref:flyingAnimalsScale":e=>Ae(Number(e)),"pref:flyingAnimalsOnPhone":e=>ke(e===!0)};function ma(e,t){if(e.path===`pref:sessionUsageChips`){Le(t===!0),gt(t===!0);return}if(e.path===`pref:phoneArrowPad`){Oe(t===!0),Bt(t===!0);return}if(e.path===`pref:nextAttentionKeyCode`){we(String(t)),Tt(Ge());let e=R?.querySelector(`.settings-view-shortcuts`);e&&aa(e);return}if(e.path===`pref:themeId`){qe(String(t)),_t(String(t));return}if(e.path===`pref:flyingAnimalsEnabled`){Ce(t===!0),Wt(t===!0);return}let n=pa[e.path];n?(n(t),Wt(Ze())):e.path===`pref:soundEnabled`?Ot(t===!0):e.path===`pref:soundId`?(Se(String(t)),ft(String(t))):e.path===`pref:notificationsEnabled`&&(Ie(t===!0),t===!0&&Jt().then(()=>Z(e,{force:!0})))}function J(e,t){let n=Ji.get(e.id);n!==void 0&&clearTimeout(n),Ji.delete(e.id),t&&qi.set(e.id,t),t||qi.delete(e.id),Mo(e)}function ha(e){J(e,{tone:`saved`,text:`Saved`}),Ji.set(e.id,window.setTimeout(()=>J(e,null),wi))}function Y(e,t){W.delete(e.id),e.path.startsWith(`pref:`)?(V[e.path]=t,ma(e,t),Z(e),ha(e)):H.has(e.id)&&JSON.stringify(H.get(e.id))===JSON.stringify(t)||(H.set(e.id,t),J(e,{tone:`saving`,text:`Saving`}),Yi=Yi.then(()=>ga(e,t)))}async function ga(e,t){let n=Jr(M,V,e,t);if(Object.keys(n).length===0)H.delete(e.id),J(e,null),Z(e);else{J(e,{tone:`saving`,text:`Saving`});try{let r=await be(`update-settings`,{settings:n});if(H.get(e.id)===t&&H.delete(e.id),r.type===`settings-error`){J(e,{tone:`error`,text:String(r.message)}),Z(e,{force:!0});return}if(r.type!==`settings-updated`){J(e,{tone:`error`,text:`The server did not confirm the save.`}),Z(e,{force:!0});return}jt(r.settings),ha(e)}catch(n){H.get(e.id)===t&&H.delete(e.id),J(e,{tone:`error`,text:n?.message||`Failed to save the setting.`}),Z(e,{force:!0})}}}function _a(e,t){t&&W.set(e.id,t),t||W.delete(e.id),Mo(e)}function va(e,t){if(!t.exclusiveMin)return t.min;if(e.integer!==!1)return t.min+1}function ya(e){return e?`On`:`Off`}function ba(e){let t=f(`div`,`settings-view-toggle-wrap`),n=f(`label`,`settings-view-toggle`),r=f(`input`,`settings-view-checkbox`);r.type=`checkbox`,r.checked=q(e)===!0,e.id===`desktop-notifications`&&!Nt()&&(r.checked=!1,r.disabled=!0),r.setAttribute(`aria-labelledby`,e.id);let i=f(`span`,`settings-view-toggle-state`,ya(r.checked));return r.addEventListener(`change`,()=>{let t=r.checked;_i(e,t)?(r.checked=!1,i.textContent=ya(!1),it({title:e.title,message:e.warning??``,confirmLabel:`Turn on`,danger:!0,onConfirm:()=>Y(e,!0)})):(i.textContent=ya(t),Y(e,t))}),n.append(r,i),t.appendChild(n),t}function xa(e){let t=f(`div`,`settings-view-shortcut-key`),n=wt(Je(`next-attention`,tn,String(q(e)))),r=f(`button`,`btn-dialog btn-dialog-cancel`,`Record`);r.type=`button`;let i=f(`span`,`settings-view-shortcut-key-prompt`);return i.setAttribute(`role`,`status`),r.addEventListener(`click`,()=>Sa(e,t,r,i)),t.append(n,r,i),t}function Sa(e,t,n,r){let i=()=>{window.removeEventListener(`keydown`,o,!0),window.removeEventListener(`pointerdown`,a,!0),window.removeEventListener(`focusin`,a,!0),n.disabled=!1,r.textContent=``},a=e=>{e.target instanceof Node&&t.contains(e.target)||i()},o=t=>{if(!n.isConnected||!n.checkVisibility()){i();return}t.preventDefault(),t.stopImmediatePropagation();let r=Ke(t,tn);r.kind!==`ignored`&&(r.kind===`refused`?_a(e,r.reason):(i(),_a(e,null),n.focus(),r.kind===`recorded`&&Y(e,r.keyCode)))};_a(e,null),n.disabled=!0,r.textContent=`Press the new shortcut, or Esc to cancel.`,window.addEventListener(`keydown`,o,!0),window.addEventListener(`pointerdown`,a,!0),window.addEventListener(`focusin`,a,!0)}function Ca(e,t,n){e.addEventListener(`blur`,t),e.addEventListener(`keydown`,e=>{e.key===`Enter`?(e.preventDefault(),t()):e.key===`Escape`&&(e.preventDefault(),n())})}function wa(e){return e instanceof HTMLTextAreaElement||e instanceof HTMLInputElement&&[`text`,`number`,`password`].includes(e.type)}function Ta(e,t){U.set(t,{base:q(e),isDirty:!1}),t.addEventListener(`input`,()=>{let e=U.get(t);e&&(e.isDirty=!0)})}function X(e,t,n){t.value!==n&&(t.value=n),U.set(t,{base:q(e),isDirty:!1}),_a(e,null)}function Ea(e,t,n,r=!1){let i=U.get(t);if(!i)return;let a=di(M,e,i,t.value,V,r);a.kind===`invalid`?_a(e,a.error):a.kind===`unchanged`?X(e,t,n):_i(e,a.value)?(X(e,t,n),it({title:e.title,message:e.warning??``,confirmLabel:`Save`,danger:!0,onConfirm:()=>Y(e,a.value)})):(U.set(t,{base:a.value,isDirty:!1}),Y(e,a.value))}function Da(e){let t=f(`input`,`settings-view-input`);t.type=e.control===`password`?`password`:`text`;let n=()=>String(q(e)??``);t.value=n(),e.control===`password`&&(t.value=``,t.placeholder=n()?`Configured`:`Not configured`);let r=kr(e,B);return r&&(t.disabled=!0,t.setAttribute(`aria-description`,`Supplied by ${r}`)),t.autocomplete=`off`,t.spellcheck=!1,t.setAttribute(`aria-labelledby`,e.id),Ta(e,t),Ca(t,()=>{if(e.control===`password`){let n=t.value;if(n===``)return;X(e,t,``),Y(e,n)}else Ea(e,t,n())},()=>X(e,t,e.control===`password`?``:n())),t}function Oa(e){let t=f(`input`,`settings-view-input`),n=Lr(e);t.type=`number`;let r=()=>ni(q(e));t.value=r(),t.step=e.integer===!1?String(e.step??`any`):`1`;let i=n?va(e,n):void 0;i!=null&&(t.min=String(i)),n?.max!=null&&(t.max=String(n.max)),t.autocomplete=`off`,t.setAttribute(`aria-labelledby`,e.id),Ta(e,t),Ca(t,()=>Ea(e,t,r(),t.validity.badInput),()=>X(e,t,r()));let a=e.unit?.label;if(!a)return t;let o=f(`div`,`settings-view-number`),s=f(`span`,`settings-view-unit`,a);return s.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-description`,a),o.append(t,s),o}function ka(e,t){let n=[...e.querySelectorAll(`[role="radio"]`)],r=n.some(e=>e.dataset.value===t);for(let[e,i]of n.entries()){let n=i.dataset.value===t;i.setAttribute(`aria-checked`,String(n)),i.tabIndex=n||!r&&e===0?0:-1}}function Aa(e,t,n){n!==String(q(e))&&(ka(t,n),Y(e,n),ka(t,String(q(e))))}function ja(e){let t=f(`div`,`settings-view-segmented`);t.setAttribute(`role`,`radiogroup`),t.setAttribute(`aria-labelledby`,e.id);let n=e.options??[];for(let r of n){let n=f(`button`,`settings-view-segment`,r.label);n.type=`button`,n.dataset.value=r.value,n.setAttribute(`role`,`radio`),n.addEventListener(`click`,()=>Aa(e,t,r.value)),t.appendChild(n)}return t.addEventListener(`keydown`,r=>{let i=Ai[r.key];if(!i||n.length===0)return;r.preventDefault();let a=Math.max(0,n.findIndex(t=>t.value===String(q(e)))),o=n[(a+i+n.length)%n.length];Aa(e,t,o.value),t.querySelector(`[data-value="${CSS.escape(o.value)}"]`)?.focus()}),ka(t,String(q(e))),t}function Ma(e){let t=f(`select`,`settings-view-input`);t.setAttribute(`aria-labelledby`,e.id);for(let n of e.options??[]){let e=f(`option`,null,n.label);e.value=n.value,t.appendChild(e)}return t.value=String(q(e)),t.addEventListener(`change`,()=>Y(e,t.value)),t}function Na(e,t){let n=e.valueKind===`posthog-projects`?`One project id per line, or none for no project. Shift+Enter adds a line.`:`One entry per line. Shift+Enter adds a line.`;return t.length>0||!e.listEmptyText?n:`${e.listEmptyText} ${n}`}function Pa(e){let t=f(`textarea`,`settings-view-input settings-view-list-input`),n=()=>Fr(q(e)),r=()=>n().join(`
1
+ import{A as e,Cn as t,D as n,E as r,Ft as i,Lt as a,M as o,P as s,Sn as c,T as l,_n as u,an as ee,bn as te,cn as ne,dn as d,fn as re,gn as ie,hn as ae,in as oe,k as se,ln as ce,mn as le,nn as ue,o as f,on as de,pn as fe,rn as p,sn as pe,un as me,vn as he,w as ge,xn as _e,y as ve,yn as ye}from"./dom-helpers-B98sy9ep.js";import{u as be}from"./control-ws-C8SS9PPx.js";import{n as xe}from"./poll-ago-DdlzkUaM.js";import{$ as Se,A as Ce,B as we,D as Te,Et as Ee,F as De,H as Oe,I as ke,L as Ae,M as je,N as Me,Ot as Ne,P as Pe,T as Fe,V as Ie,X as Le,b as Re,dt as ze,h as Be,i as Ve,j as He,m as Ue,r as We,s as Ge,st as Ke,tt as qe,ut as Je,w as Ye,x as Xe,y as Ze}from"./ui-prefs-Dvsgw_ZF.js";import{C as Qe,c as $e,d as et,i as tt,s as nt,t as rt}from"./action-status-D9Sf2cZp.js";import{a as it}from"./modal-5t7_5VCF.js";import{$n as at,A as m,Bn as ot,C as st,D as ct,E as lt,Fn as ut,Gn as dt,In as ft,Kn as pt,Ln as mt,M as ht,Mn as gt,Nn as _t,O as vt,Pn as yt,Qn as bt,Rn as xt,S as St,T as Ct,Un as wt,Vn as Tt,Wn as Et,X as Dt,Y as Ot,Zn as kt,_ as At,b as jt,br as Mt,dr as Nt,f as Pt,fr as Ft,g as It,h as Lt,i as Rt,j as zt,jn as Bt,k as h,lr as Vt,m as Ht,n as Ut,p as Wt,pr as Gt,r as Kt,t as qt,ur as Jt,v as Yt,vr as Xt,w as Zt,x as Qt,xr as $t,y as en,zn as tn}from"./index-In1pKLyK.js";import{agentLoginSummary as nn,openAgentConnectDialog as rn,openRemoteSetupDialog as an}from"./dialogs-CsBM709_.js";function on(){let e=f(`div`),t=f(`p`,`flying-animals-status`);t.id=`flying-animals-gallery-status`,t.setAttribute(`role`,`status`);let n=f(`div`,`flying-animals-gallery`);n.setAttribute(`aria-label`,`Animal gallery`);let r=[],i=()=>{let e=Ht(),n=Ee(Ve().flyingAnimalsExcludedSprites);t.textContent=[e,n?``:`No animals are included, so automatic flights are paused.`].filter(Boolean).join(` `);for(let t of r)t.disabled=e!==null},a=Ve();for(let e of Ne){let o=f(`article`,`flying-animal-tile`),s=$t(e),c=f(`label`,`flying-animal-include`),l=f(`input`,`settings-view-checkbox`);l.type=`checkbox`,l.checked=!a.flyingAnimalsExcludedSprites.includes(e.sprite),l.setAttribute(`aria-label`,`Include ${e.name}`),l.addEventListener(`change`,()=>{let t=new Set(Ve().flyingAnimalsExcludedSprites);l.checked&&t.delete(e.sprite),l.checked||t.add(e.sprite),He([...t]),Wt(Ze()),i()}),c.append(l,document.createTextNode(`Include`));let u=f(`button`,`btn-dialog btn-dialog-cancel`,`Fly now`);u.type=`button`,u.setAttribute(`aria-describedby`,t.id),u.addEventListener(`click`,()=>Lt(e.sprite)),r.push(u),o.append(s,f(`h2`,`flying-animal-name`,e.name),c,u),n.append(o)}return i(),e.append(t,n),e}var sn=`johncwaters/glimmervoid`,cn=Object.freeze([`auto`,`calculate`,`display`]);Object.freeze([`codex`,`grok`]),Object.freeze([`dailyUsd`,`monthlyUsd`]);var g={scope:`browser`,access:`editable`,takesEffect:`now`},_={scope:`browser`,access:`advanced`,takesEffect:`now`},v={scope:`machine`,access:`editable`,takesEffect:`now`},ln={scope:`machine`,access:`editable`,takesEffect:`new-sessions`},un={scope:`machine`,access:`readout`,takesEffect:`now`},y={scope:`machine`,access:`file-only`},dn=1e3,fn=60,pn=60,mn=dn*fn,hn=mn*pn,gn=hn*24,_n={label:`investigations`,storedPerDisplay:1},vn={label:`sessions`,storedPerDisplay:1},yn={label:`recurrences`,storedPerDisplay:1},bn={label:`actions`,storedPerDisplay:1},b={label:`seconds`,storedPerDisplay:1},xn={label:`minutes`,storedPerDisplay:1},Sn={label:`hours`,storedPerDisplay:1},x={label:`days`,storedPerDisplay:1},Cn={label:`seconds`,storedPerDisplay:dn,storedLabel:`ms`},wn={label:`minutes`,storedPerDisplay:mn,storedLabel:`ms`},Tn={label:`minutes`,storedPerDisplay:fn,storedLabel:`seconds`},En={label:`hours`,storedPerDisplay:hn,storedLabel:`ms`},Dn={label:`hours`,storedPerDisplay:pn,storedLabel:`minutes`},On={label:`days`,storedPerDisplay:gn,storedLabel:`ms`},kn={label:`USD`,storedPerDisplay:1},An={label:`users`,storedPerDisplay:1},jn={label:`reviews per hour`,storedPerDisplay:1},Mn={label:`times`,storedPerDisplay:1},S=`A tuning knob kept out of the Settings view; the default suits almost every install.`,C=`A diagnostic switch kept out of the Settings view; change it in config.json while investigating.`,w=`Changes how the server process or its worktrees behave, so it is set in config.json with a restart or new sessions in mind.`,Nn=`A structured value with no dashboard control; edit it in config.json.`,Pn=`Never editable from the dashboard by rule; edit it in config.json.`;function Fn(e){return e.map(e=>({value:e,label:e[0].toUpperCase()+e.slice(1)}))}var In=Object.freeze({"machine-terminal":{title:`Terminal`,description:`Terminal behavior shared by dashboard clients.`},"machine-detection-sessions":{title:`Detection and sessions`,description:`Config-file-only detection, timing, worktree and process settings.`},"lanes-ingest":{title:`Ingest`,description:`The machine-context sources behind Visions.`}}),Ln=Object.freeze([{id:`browser-appearance`,level:`browser`,title:`Appearance`,description:`How this browser draws the dashboard.`,legacyIds:[`browser-flying-animals`,`animals`,`flying-animals`],settings:[{id:`theme`,path:`pref:themeId`,title:`Theme`,description:`Color scheme for the dashboard.`,control:`select`,optionsFrom:`themes`,keywords:[`color`,`palette`],defaultValue:`phyrexian`,...g},{id:`session-usage-chips`,path:`pref:sessionUsageChips`,title:`Show usage on session cards`,description:`Shows each card's transcript token count and CLI-reported cost when available, otherwise a calculated API list-price estimate.`,control:`toggle`,keywords:[`usage`,`cost`,`tokens`,`card`,`price`],defaultValue:!1,...g},{id:`phone-arrow-pad`,path:`pref:phoneArrowPad`,title:`Swipe arrow pad on phone (experimental)`,description:`Replace the four arrow keys above the phone keyboard with one pad: swipe on it to send arrow keys, one per short drag.`,control:`toggle`,keywords:[`experimental`,`mobile`,`keys`,`arrows`,`swipe`,`gesture`],defaultValue:!1,...g},{id:`flying-animals`,path:`pref:flyingAnimalsEnabled`,title:`Flying animals`,description:`Show animated animals flying across the dashboard.`,control:`toggle`,keywords:[`animation`,`motion`,`animals`],defaultValue:!1,...g},{id:`animals-min-gap`,path:`pref:flyingAnimalsMinGapSeconds`,title:`Time between flights: minimum`,description:`Shortest pause between flights.`,control:`number`,integer:!1,step:.1,range:ee,unit:b,maximumSettingId:`animals-max-gap`,keywords:[`animals`,`frequency`],defaultValue:p.flyingAnimalsMinGapSeconds,..._},{id:`animals-max-gap`,path:`pref:flyingAnimalsMaxGapSeconds`,title:`Time between flights: maximum`,description:`Longest pause between flights.`,control:`number`,integer:!1,step:.1,range:ee,unit:b,keywords:[`animals`,`frequency`],defaultValue:p.flyingAnimalsMaxGapSeconds,..._},{id:`animals-min-duration`,path:`pref:flyingAnimalsMinDurationSeconds`,title:`Flight duration: minimum`,description:`Shortest flight, for faster animals.`,control:`number`,integer:!1,step:.1,range:oe,unit:b,maximumSettingId:`animals-max-duration`,keywords:[`animals`,`speed`],defaultValue:p.flyingAnimalsMinDurationSeconds,..._},{id:`animals-max-duration`,path:`pref:flyingAnimalsMaxDurationSeconds`,title:`Flight duration: maximum`,description:`Longest flight, for slower animals.`,control:`number`,integer:!1,step:.1,range:oe,unit:b,keywords:[`animals`,`speed`],defaultValue:p.flyingAnimalsMaxDurationSeconds,..._},{id:`animals-scale`,path:`pref:flyingAnimalsScale`,title:`Size multiplier`,description:`Scale applied on top of the viewport size.`,control:`number`,integer:!1,step:.1,range:de,unit:Mn,keywords:[`animals`,`size`],defaultValue:p.flyingAnimalsScale,..._},{id:`animals-on-phone`,path:`pref:flyingAnimalsOnPhone`,title:`Show on phone layout`,description:`Allow flights on the phone layout.`,control:`toggle`,keywords:[`animals`,`mobile`],defaultValue:p.flyingAnimalsOnPhone,..._}]},{id:`browser-notifications`,level:`browser`,title:`Notifications`,description:`How this browser, and the Telegram bot shared by every lane, get your attention.`,settings:[{id:`alert-sounds-enabled`,path:`pref:soundEnabled`,title:`Alert sounds`,legacyIds:[{sectionId:`browser-appearance`,settingId:`alert-sounds-enabled`}],description:`Play sounds when a session needs attention and when a merge celebration plays. The same switch as the note button in the desktop header.`,control:`toggle`,keywords:[`audio`,`mute`,`sound`,`notification`],defaultValue:!0,...g},{id:`alert-sound`,path:`pref:soundId`,title:`Alert sound`,legacyIds:[{sectionId:`browser-appearance`,settingId:`alert-sound`}],description:`Sound played when a session needs attention. Your own .ogg, .mp3, .wav, .m4a or .webm files dropped into the sounds folder of the Glimmervoid home (~/.glimmervoid/sounds/, or $GLIMMERVOID_HOME/sounds/) are listed after the built-in sounds. Glimmervoid never creates that folder, so make it yourself; new files show up the next time Settings opens.`,control:`select`,optionsFrom:`sounds`,keywords:[`audio`,`notification`,`custom`],defaultValue:`chime`,...g},{id:`desktop-notifications`,path:`pref:notificationsEnabled`,title:`Desktop notifications`,legacyIds:[{sectionId:`browser-appearance`,settingId:`desktop-notifications`}],description:`Raise a browser notification when a session needs attention while this dashboard is in the background.`,control:`toggle`,keywords:[`browser`,`attention`],defaultValue:!0,...g}]},{id:`machine-telegram`,level:`machine`,parent:`browser-notifications`,title:`Telegram`,description:`One bot shared by session, PR review and PostHog notifications.`,legacyIds:[`telegram`,`notifications`],settings:[{id:`telegram-bot-token`,path:`telegram.botToken`,title:`Bot token`,description:`Credential used by the shared Telegram bot. Create a bot by messaging @BotFather in Telegram and sending /newbot; it replies with this token. When GLIMMERVOID_TELEGRAM_BOT_TOKEN supplies it, this field is read-only.`,control:`password`,keywords:[`credential`,`api`],defaultValue:``,...v},{id:`telegram-chat-id`,path:`telegram.chatId`,title:`Chat id`,description:`Destination chat for enabled Telegram lanes. Send your bot any message, then open https://api.telegram.org/bot<token>/getUpdates in a browser and copy the number under message.chat.id.`,control:`text`,keywords:[`destination`,`channel`],defaultValue:``,...v},{id:`telegram-session-notifications`,path:`telegramNotifications`,title:`Send session notifications`,description:`Send session completion, input and failure alerts when no dashboard is open. Unacknowledged alerts also escalate after the phone escalation delay while a dashboard remains open.`,control:`toggle`,keywords:[`phone`,`off dashboard`,`test`],defaultValue:!1,status:`telegram-delivery`,...v}]},{id:`machine-sessions`,level:`machine`,title:`Sessions`,description:`How sessions start, where projects are found, and what the dashboard shows for them.`,legacyIds:[`machine-general`,`general`,`machine-repositories`,`repos`,`repositories`],settings:[{id:`auto-resume`,path:`autoResume`,title:`Auto-resume sessions on startup`,description:`Resume conversations that were live when Glimmervoid last shut down or crashed, and tell sessions that were mid-turn, or had a background agent, monitor or scheduled wakeup in flight, to continue.`,control:`toggle`,keywords:[`startup`,`conversation`],defaultValue:!0,...v},{id:`conversation-view`,path:`conversationView`,title:`Conversation view (experimental)`,description:`Let each Claude Code and Codex session turn on a Conversation face from its card menu, which renders the transcript as messages, approvals and a composer. Sessions stay on the terminal until you turn it on for them. A Claude Code session started while this is on can answer its permission prompts and questions there. A Codex session connects on its next start, through a local app-server so approvals can be answered from the dashboard; guarded Codex sessions and those that bypass Codex hook trust keep the terminal only.`,control:`toggle`,keywords:[`experimental`,`transcript`,`chat`,`codex`,`claude`],defaultValue:!1,...v},{id:`tab-order`,path:`viewTabOrder`,title:`Tab order`,description:`The order of the dashboard tabs in every browser: the header on desktop and the More menu on a phone. You can also drag a tab in the desktop header.`,control:`tab-order`,keywords:[`tabs`,`order`,`rearrange`,`reorder`,`header`,`more`,`menu`],defaultValue:[],...v},{id:`remote-sessions`,path:`remoteSessions`,title:`Remote Coder sessions (experimental)`,description:`Offer the Coder environments in config.json when adding a session, so the session runs in its own Coder workspace instead of on this machine. Off refuses new remote sessions; ones already running keep working until closed.`,control:`toggle`,keywords:[`experimental`,`coder`,`remote`,`workspace`,`cloud`],defaultValue:!1,...v},{id:`streamer-mode`,path:`streamerMode`,title:`Streamer mode`,description:`Hide sensitive details in the dashboard while screen sharing or streaming.`,control:`toggle`,keywords:[`streaming`,`screen share`,`privacy`],defaultValue:!1,...v},{id:`repository-roots`,path:`repoRoots`,title:`Repository roots`,description:`Directories scanned for projects when adding sessions.`,control:`list`,keywords:[`folders`,`project discovery`],defaultValue:[],listPlaceholder:`Repository root path`,listEmptyText:`No repository roots configured.`,...v},{id:`custom-agents`,path:`status:custom-agents`,title:`Custom agents`,description:`Extra agent CLIs a session can be spawned with, declared under customAgents in config.json.`,control:`readonly`,keywords:[`adapters`,`cli`],status:`custom-agents`,...un},{id:`agent-logins`,path:`status:agent-logins`,title:`Agent logins`,description:`How Claude Code and Codex sign in inside a Coder workspace. Each uses the login already on this machine; Connect signs one in for Glimmervoid alone when there is none.`,control:`readonly`,keywords:[`claude`,`codex`,`sign in`,`login`,`coder`,`remote`],status:`agent-logins`,...un},{id:`remote-setup`,path:`status:remote-setup`,title:`Remote host setup`,description:`Start a session that walks you through running Glimmervoid on another Linux machine you reach by ssh, as a service you open from your laptop and phone.`,control:`readonly`,keywords:[`remote`,`ssh`,`server`,`devbox`,`tailscale`,`pair`,`host`],status:`remote-setup`,...un}]},{id:`machine-guardrails`,level:`machine`,title:`Guardrails and unattended`,description:`What a guarded session may touch, and which unattended actions automated work may take. Claude Code sessions on Linux and macOS write anywhere this account can, except credentials, Glimmervoid's own state and the blocked folders here.`,legacyIds:[`lanes-unattended`,`unattended`],settings:[{id:`skip-permissions-by-default`,path:`skipPermissionsByDefault`,title:`Skip permission prompts by default`,description:`Start sessions whose project sets no permission choice with the agent CLI permission bypass flag.`,control:`toggle`,keywords:[`permissions`,`yolo`,`dangerously`],danger:!0,warning:`Enabling this control lets agents edit files and run shell commands without asking, and restarts running sessions that inherit it.`,defaultValue:!1,...v},{id:`sane-yolo`,path:`saneYolo`,title:`Sane YOLO`,description:`Block catastrophic commands in sessions that skip permission prompts when the cc-safety-net executable is available and trusted hooks are installed. Missing or untrusted hooks leave a session unprotected.`,control:`toggle`,keywords:[`permissions`,`yolo`,`safety`],defaultValue:!0,...ln},{id:`rtk-compression`,path:`rtk`,title:`rtk output compression`,description:`Compress Bash output with the rtk executable.`,control:`toggle`,keywords:[`bash`,`tokens`],danger:!0,status:`rtk-install`,warning:`Enabling this control permits Glimmervoid to install the pinned rtk executable automatically.`,defaultValue:!1,...ln},{id:`branch-gc-delete-unmerged`,path:`branchGc.deleteUnmerged`,title:`Delete unmerged branches`,description:`Also delete stale remote branches with no merge proof. Off keeps every unmerged branch.`,control:`toggle`,keywords:[`git`,`cleanup`,`orphan`],danger:!0,warning:`Enabling this control lets branch cleanup delete stale remote branches without merge proof.`,defaultValue:!1,...v},{id:`guardrails-unguarded-repos`,path:`guardrails.unguardedRepos`,title:`Unguarded repositories`,description:`Folders whose sessions run without guardrails. A session started in one of these folders, or below it, is not guarded.`,control:`list`,keywords:[`guardrails`,`opt out`,`dotfiles`],danger:!0,warning:`A session without guardrails can read credentials and write anywhere this account can.`,defaultValue:[],listPlaceholder:`Folder path`,listEmptyText:`Every repository is guarded.`,...ln},{id:`guardrails-blocked-paths`,path:`guardrails.blockedPaths`,title:`Blocked folders`,description:`Extra folders and files a guarded session cannot write, on top of credentials and Glimmervoid's own state. A leading ~ means the home folder.`,control:`list`,keywords:[`guardrails`,`block`,`protect`],defaultValue:[],listPlaceholder:`~/folder`,listEmptyText:`Only the built-in list is blocked.`,...ln},{id:`guardrails-unreadable-paths`,path:`guardrails.unreadablePaths`,title:`Unreadable folders`,description:`Extra folders and files a guarded session cannot read, on top of the built-in credential list. A leading ~ means the home folder.`,control:`list`,keywords:[`guardrails`,`secrets`,`credentials`],defaultValue:[],listPlaceholder:`~/folder`,listEmptyText:`Only the built-in credential list is unreadable.`,...ln}]},{id:`machine-updates`,level:`machine`,title:`Updates`,description:`See which Glimmervoid version is running, which one is newest, and update in one step.`,legacyIds:[`updates`],settings:[{id:`update-actions`,path:`status:update-actions`,title:`Status and actions`,legacyIds:[`update-summary`,`update-installed`,`update-latest`,`update-last-checked`].map(e=>({sectionId:`machine-updates`,settingId:e})),description:`Whether this install is up to date, the running and newest versions, the last check, and the update and restart actions.`,control:`readonly`,keywords:[`version`,`available`,`current`,`check`,`restart`,`commit`,`installed`,`release`,`failure`],status:`update-actions`,...un},{id:`update-channel`,path:`updateChannel`,title:`Channel`,description:`Track stable releases, or Experimental builds published from every change to main before it reaches a release.`,control:`select`,options:Fn(a),keywords:[`release`,`prerelease`,`next`,`beta`,`early`],defaultValue:`release`,...v},{id:`check-updates`,path:`checkForUpdates`,title:`Check for updates automatically`,description:`Check for a newer Glimmervoid at launch, while a dashboard is connected, and when this page opens.`,control:`toggle`,keywords:[`release`,`github`],defaultValue:!0,...v}]},{id:`machine-usage`,level:`machine`,title:`Usage`,description:`Local transcript accounting and estimated-cost budgets.`,legacyIds:[`usage`],settings:[{id:`usage-enabled`,path:`usage.enabled`,title:`Track token usage`,description:`Read local CLI transcripts and roll them into the Usage view and session chips.`,control:`toggle`,keywords:[`tokens`,`cost`],defaultValue:!0,status:`usage-last-report`,...v},{id:`usage-retain-days`,path:`usage.retainDays`,title:`Retain transcript detail`,description:`How long live transcript detail stays available. A monthly budget keeps detail from the start of the current month when that is longer.`,control:`number`,range:te,unit:x,keywords:[`history`,`retention`],defaultValue:90,...v},{id:`usage-daily-budget`,path:`usage.budget.dailyUsd`,title:`Daily budget`,description:`Estimated daily spend alert threshold. Alerts at 50%, 75% and 100% do not stop spending. Zero or below disables the threshold.`,control:`number`,range:he,unit:kn,keywords:[`spend`,`alert`],defaultValue:null,integer:!1,nullable:!0,zeroIsNull:!0,step:.01,...v},{id:`usage-monthly-budget`,path:`usage.budget.monthlyUsd`,title:`Monthly budget`,description:`Estimated monthly spend alert threshold. Alerts at 50%, 75% and 100% do not stop spending. Zero or below disables the threshold.`,control:`number`,range:he,unit:kn,keywords:[`spend`,`alert`],defaultValue:null,integer:!1,nullable:!0,zeroIsNull:!0,step:.01,...v}]},{id:`lanes-visions`,level:`lanes`,title:`Visions`,description:`Editor-buffer findings, bounded model comments, and the machine-context ingest behind them.`,legacyIds:[`lanes`,`visions`,`lanes-ingest`,`ingest`],settings:[{id:`visions-enabled`,path:`visions.enabled`,title:`Enable Visions`,description:`Set up supported editors detected on this machine, then show their buffer findings in the Visions view.`,control:`toggle`,keywords:[`editor`,`findings`,`lsp`],defaultValue:!1,...v},{id:`visions-dispatch-enabled`,path:`visions.dispatch.enabled`,title:`Enable model comments`,description:`Start bounded review sessions for local editor buffers.`,control:`toggle`,keywords:[`review`,`dispatch`],defaultValue:!1,...v},{id:`visions-max-per-hour`,path:`visions.dispatch.maxPerHour`,title:`Max per hour`,description:`Maximum review sessions dispatched per hour. One slot is reserved for edit reviews; activity-driven reviews take the rest, up to the activity cap set by visions.dispatch.activityMaxPerHour.`,control:`number`,range:d,unit:jn,keywords:[`rate limit`,`reviews`],defaultValue:6,...v},{id:`visions-model`,path:`visions.dispatch.model`,title:`Model override`,description:`Leave blank to use the opus model alias.`,control:`text`,keywords:[`claude`,`override`],defaultValue:``,...v},{id:`visions-projects`,path:`visions.projects`,title:`Projects`,description:`Clear every selection, including unavailable projects, to accept buffers from every configured project.`,control:`projects`,keywords:[`repositories`,`filter`],defaultValue:[],...v},{id:`visions-auto-fix`,path:`visions.autoFix`,title:`Apply tier 1 fixes`,description:`Allow Visions to edit eligible open Markdown buffers, including inactive buffers, without asking.`,control:`toggle`,keywords:[`automatic`,`edits`],danger:!0,warning:`Enabling this control lets Visions edit eligible buffers without a carbon unit present.`,defaultValue:!1,...v},{id:`ingest-enabled`,path:`ingest.enabled`,title:`Enable machine context ingest`,description:`Enable the local activity feed behind Visions. Turning Visions on enables ingest unless ingest.enabled is explicitly false.`,control:`toggle`,keywords:[`events`,`activity`,`ingest`],defaultValue:!1,...v}]},{id:`lanes-posthog`,level:`lanes`,title:`PostHog`,description:`Error monitoring, investigations and traffic-spike alerts.`,legacyIds:[`posthog`],settings:[{id:`posthog-enabled`,path:`posthog.enabled`,title:`Enable PostHog monitoring`,description:`Poll PostHog error tracking and investigate issues that move.`,control:`toggle`,keywords:[`errors`,`monitoring`],defaultValue:!1,...v},{id:`posthog-host`,path:`posthog.host`,title:`Host`,description:`PostHog cloud or self-hosted HTTP URL.`,control:`text`,keywords:[`url`,`server`],defaultValue:`https://us.posthog.com`,...v},{id:`posthog-api-key`,path:`posthog.apiKey`,title:`Personal API key`,description:`Credential with read access to PostHog projects. When GLIMMERVOID_POSTHOG_API_KEY supplies it, this field is read-only.`,control:`password`,keywords:[`credential`,`token`],defaultValue:``,...v},{id:`posthog-projects`,path:`posthog.projects`,title:`Projects`,description:`PostHog project ids to monitor. config.json holds "all" or an array of ids, and an empty array monitors no project. In Settings that empty array shows as none, and an empty list saves "all".`,control:`list`,keywords:[`project ids`,`filter`],defaultValue:`all`,valueKind:`posthog-projects`,listPlaceholder:`Project id`,listEmptyText:`Every project the key can read.`,...v},{id:`posthog-interval`,path:`posthog.intervalMinutes`,title:`Poll interval`,description:`Delay between PostHog polling passes.`,control:`number`,integer:!1,step:`any`,range:d,unit:xn,keywords:[`refresh`,`schedule`],defaultValue:15,...v},{id:`posthog-max-investigations`,path:`posthog.maxConcurrentInvestigations`,title:`Max concurrent investigations`,description:`Maximum investigation sessions running together.`,control:`number`,range:d,unit:_n,keywords:[`parallel`,`workers`],defaultValue:2,...v},{id:`posthog-min-users`,path:`posthog.minUsersToInvestigate`,title:`Min users to investigate`,description:`Minimum affected users for a new issue investigation. Regressions, worsening issues and eligible error spikes bypass this minimum.`,control:`number`,range:d,unit:An,keywords:[`threshold`,`affected`],defaultValue:1,...v},{id:`posthog-traffic-enabled`,path:`posthog.trafficSpikeEnabled`,title:`Traffic spike alerts`,description:`Ping when recent unique users exceed a project baseline.`,control:`toggle`,keywords:[`analytics`,`alert`],defaultValue:!0,...v},{id:`posthog-auto-fix`,path:`posthog.autoFix`,title:`Attempt fixes for major issues`,description:`Allow an isolated agent to fix an issue, push a branch and open a pull request.`,control:`toggle`,keywords:[`automatic`,`pull request`],danger:!0,warning:`Enabling this control lets PostHog fixes commit, push and open pull requests automatically.`,defaultValue:!1,...v}]},{id:`lanes-team-review`,level:`lanes`,title:`Team review`,description:`Draft reviews of teammates' pull requests for you to post from the Reviews tab.`,legacyIds:[`team-review`,`reviews`],settings:[{id:`team-review-enabled`,path:`teamReview.enabled`,title:`Enable team review`,description:`Poll open pull requests from the team and draft a review of each one. Nothing is posted until you choose Approve or Comment.`,control:`toggle`,keywords:[`pull requests`,`github`],defaultValue:!0,...v},{id:`github-teams`,path:`github.teams`,title:`GitHub teams`,description:`Teams to search for review requests and members, one org/slug per entry. Leave empty to fall back to the legacy teamReview.org and teamReview.team keys in config.json.`,control:`list`,keywords:[`github`,`teams`,`review requests`],defaultValue:[],listPlaceholder:`org/team-slug`,listEmptyText:`No GitHub teams configured.`,...v},{id:`team-review-re-review-after-hours`,path:`teamReview.reReviewAfterHours`,title:`Re-review after`,description:`When a reviewed PR has a new head, review it again after this long since its last review. Re-run review runs it at any time.`,control:`number`,range:d,unit:Sn,keywords:[`review`,`delay`],defaultValue:24,integer:!1,step:.5,...v},{id:`team-review-skip-idle-after-days`,path:`teamReview.skipIdleAfterDays`,title:`Skip PRs idle for`,description:`Leave pull requests without GitHub activity for this long out of automatic review.`,control:`number`,range:d,unit:x,keywords:[`idle`,`activity`],defaultValue:14,integer:!1,step:.5,...v},{id:`team-review-skill`,path:`teamReview.skill`,title:`Review skill`,description:`Name of a Claude Code skill installed for the review agent, for example your own PR review skill. Leave empty to let the agent review with whatever skills it has.`,control:`text`,keywords:[`skill`,`claude code`,`pr review`],defaultValue:``,...v},{id:`team-review-auto-rebase-my-prs`,path:`teamReview.autoRebaseMyPrs`,title:`Keep my pull requests rebased`,description:`On each poll, rebase your open, non-draft pull requests that are behind their base branch. A pull request with conflicts or checks still running is left alone, and a failed rebase is not retried until you push again.`,control:`toggle`,keywords:[`rebase`,`update branch`,`behind`,`my prs`],danger:!0,warning:`Enabling this control rewrites your pull request branches on GitHub. Pull before you push from a local checkout of one.`,defaultValue:!1,...v},{id:`team-review-keep-mergeable-enabled`,path:`teamReview.keepMergeableEnabled`,title:`Keep mergeable`,description:`Offer Keep mergeable on your pull requests: a guarded agent repairs conflicts and failing checks and pushes the repair. Off hides the control and starts no repair; the pull requests you chose stay chosen for when you turn it back on.`,control:`toggle`,keywords:[`repair`,`conflicts`,`my prs`],defaultValue:!0,...v},{id:`team-review-keep-mergeable-timeout`,path:`teamReview.keepMergeableTimeoutMinutes`,title:`Keep mergeable deadline`,description:`Longest a Keep mergeable repair session may run before it is stopped and nothing is pushed.`,control:`number`,range:pe,unit:xn,keywords:[`timeout`,`repair`],defaultValue:30,...v},{id:`team-review-merge-queue-enabled`,path:`teamReview.mergeQueueEnabled`,title:`Merge when ready`,description:`Offer Merge when ready on your pull requests: queued pull requests are rebased when behind and merged once ready, one per repository per poll. Off hides the control and merges nothing; the queue is kept for when you turn it back on.`,control:`toggle`,keywords:[`merge queue`,`auto merge`,`my prs`],defaultValue:!0,...v}]},{id:`lanes-workflows`,level:`lanes`,title:`Workflows`,description:`Rules that act on pull request events in the repositories you choose.`,legacyIds:[`workflows`],settings:[{id:`workflows-enabled`,path:`workflows.enabled`,title:`Run workflows`,description:`Poll the repositories your enabled rules watch and run their actions. Off stops polling and every action, whatever each rule says.`,control:`toggle`,keywords:[`pull requests`,`automation`,`master switch`],defaultValue:!0,...v},{id:`workflows-max-concurrent-sessions`,path:`workflows.maxConcurrentSessions`,title:`Concurrent agent sessions`,description:`Most workflow agent sessions running at once. Up to twenty later spawns wait for a free slot; additional spawns are dropped and logged.`,control:`number`,range:t,unit:vn,keywords:[`parallel`,`spawn`],defaultValue:2,...v},{id:`workflows-rules`,path:`status:workflow-rules`,title:`Workflow rules`,description:`Each rule watches repositories for one pull request event (opened, checks-failed, review-requested, approved, commented or merged), narrows it by author, labels, base branch, your own pull requests or a review request to your team, and then notifies you, labels or comments on the pull request, or starts a guarded agent session that pushes nothing. Rules start disabled. Turn each rule on or off here; everything else about a rule is set in config.json under workflows.rules.`,control:`readonly`,keywords:[`pull requests`,`automation`,`github`,`rules`],status:`workflows`,...un}]},{id:`lanes-benchmarks`,level:`lanes`,title:`Benchmarks`,description:`Compare agent setups on frozen cases from the suites in the benchmarks folder of the Glimmervoid home.`,legacyIds:[`benchmarks`],settings:[{id:`benchmarks-enabled`,path:`benchmarks.enabled`,title:`Enable benchmarks`,description:`Show the Bench tab. Nothing runs until you choose Mine or Run there.`,control:`toggle`,keywords:[`eval`,`arms`,`recall`,`compare`],defaultValue:!1,...v}]},{id:`lanes-coherence`,level:`lanes`,title:`Coherence (experimental)`,description:`Per-session Coherence hook status and decision journal for agent sessions.`,settings:[{id:`coherence-enabled`,path:`coherence.enabled`,title:`Show session Coherence`,description:`Shows each session's Coherence hook status and decision journal when the repository installed @posthog/coherence 1.8 or newer. Off by default.`,control:`toggle`,keywords:[`experimental`,`coherence`,`journal`,`decisions`],defaultValue:!1,...v}]},{id:`lanes-issues`,level:`lanes`,title:`Issues (experimental)`,description:`GitHub issues from your projects and teams in their own dashboard tab.`,settings:[{id:`issues-enabled`,path:`issues.enabled`,title:`Show the Issues tab`,description:`Poll GitHub issues for your projects and teams and list them in an Issues tab. Off stops the polling and hides the tab.`,control:`toggle`,keywords:[`experimental`,`issues`,`github`,`tab`],defaultValue:!1,...v}]},{id:`machine-privacy`,level:`machine`,title:`Privacy`,description:`What Glimmervoid sends about itself.`,legacyIds:[`privacy`,`telemetry`],settings:[{id:`telemetry-enabled`,path:`telemetry.enabled`,title:`Send usage data`,description:`Helps us improve Glimmervoid. Sent under a random install id: version, platform, app starts, daily activity, session starts and ends with agent kind, exit kind and duration, errors as their type, error code and scrubbed stack frames, per session token counts, models and estimated costs from the usage scan, and a salted one-way hash of your Claude and Codex account ids so installs of one account count together. Never prompts, project information, error messages, paths, repository or branch names, objectives, terminal output, emails or names. Delete my data asks for everything sent under this install to be erased and starts a new install id. GLIMMERVOID_TELEMETRY=0, DO_NOT_TRACK=1 or CI=true turn it off regardless.`,control:`toggle`,keywords:[`telemetry`,`analytics`,`tracking`,`opt out`],defaultValue:!0,...v}]},{id:`browser-shortcuts`,level:`browser`,title:`Shortcuts`,description:`Keyboard shortcuts and their reference.`,legacyIds:[`shortcuts`],settings:[{id:`next-attention-key`,path:`pref:nextAttentionKeyCode`,title:`Jump to the next session needing you`,description:`The key held with Cmd on a Mac, or Alt elsewhere, that jumps to the next session needing you. Record a new one by pressing the whole shortcut.`,control:`shortcut-key`,keywords:[`shortcut`,`keyboard`,`hotkey`,`jump`,`next`,`attention`],defaultValue:`KeyJ`,...g}]}]),Rn=Object.freeze([{id:`file-debug-mode`,path:`debugMode`,title:`Debug mode`,group:`machine-sessions`,description:`Show session-card diagnostics for state, transitions and detection signals.`,control:`toggle`,keywords:[`diagnostics`,`state`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:C,...y},{id:`file-replay-buffer`,path:`replayBufferKB`,title:`Replay buffer`,group:`machine-terminal`,description:`PTY output retained for clients that reconnect or join late.`,control:`number`,range:ie,unit:{label:`KB`,storedPerDisplay:1},keywords:[`history`,`backfill`],defaultValue:512,takesEffect:`new-sessions`,fileOnlyReason:S,...y},{id:`file-session-memory-reserve`,path:`sessionMemoryReserveMB`,title:`Session memory reserve`,group:`machine-sessions`,description:`Free memory an automatic session start waits for; 0 starts sessions without checking.`,control:`number`,range:ne,unit:{label:`MB`,storedPerDisplay:1},keywords:[`memory`,`headroom`],defaultValue:600,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-cursor-blink`,path:`cursorBlink`,title:`Cursor blink`,group:`machine-terminal`,description:`Blink the cursor in every terminal.`,control:`toggle`,keywords:[`caret`,`terminal`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-detect-background-agents`,path:`detectBackgroundAgents`,title:`Detect background agents`,group:`machine-detection-sessions`,description:`Hold completion while tracked background work is active.`,control:`toggle`,keywords:[`subagents`,`completion`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:C,...y},{id:`file-record-signals`,path:`recordSignals`,title:`Record structural signals`,group:`machine-detection-sessions`,description:`Keep forensic status and hook recordings for each session. Full capture (capture.enabled) records these signals even when this is off.`,control:`toggle`,keywords:[`recordings`,`diagnostics`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:C,...y},{id:`file-trace-enabled`,path:`trace.enabled`,title:`Capture session traces`,group:`machine-detection-sessions`,description:`Keep normalized Claude transcript traces for session debugging.`,control:`toggle`,keywords:[`transcripts`,`diagnostics`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:C,...y},{id:`file-detect-scheduled-wakeups`,path:`detectScheduledWakeups`,title:`Detect scheduled wakeups`,group:`machine-detection-sessions`,description:`Surface advisory wakeup timing for scheduled sessions.`,control:`toggle`,keywords:[`schedule`,`sleep`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:C,...y},{id:`file-worktree-auto-rebase`,path:`worktreeAutoRebase`,title:`Worktree auto-rebase`,group:`machine-detection-sessions`,description:`Rebase eligible session worktrees when the integration branch moves.`,control:`toggle`,keywords:[`git`,`branch`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-sync-on-start`,path:`worktreeSyncOnStart`,title:`Worktree sync on start`,group:`machine-detection-sessions`,description:`Fetch origin and fast-forward the local integration branch before a session starts its worktree.`,control:`toggle`,keywords:[`git`,`fetch`,`fast-forward`],defaultValue:!0,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-rerere`,path:`worktreeRerere`,title:`Worktree rerere`,group:`machine-detection-sessions`,description:`Reuse recorded Git conflict resolutions.`,control:`toggle`,keywords:[`git`,`conflicts`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:w,...y},{id:`file-integration-branch`,path:`integrationBranch`,title:`Integration branch`,group:`machine-detection-sessions`,description:`Base branch for session worktrees. Empty = each repo's default branch. Existing sessions are never retargeted.`,control:`text`,nullable:!0,keywords:[`git`,`merge`],defaultValue:null,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-root`,path:`worktreeRoot`,title:`Worktree root`,group:`machine-detection-sessions`,description:`Directory that contains session worktrees. Existing worktrees are never relocated.`,control:`text`,keywords:[`git`,`directory`],defaultValue:``,takesEffect:`new-sessions`,fileOnlyReason:w,...y},{id:`file-worktree-share`,path:`worktreeShare`,title:`Shared worktree paths`,group:`machine-detection-sessions`,description:`Local paths copied or linked during worktree preparation.`,control:`list`,keywords:[`files`,`context`],defaultValue:[`.env`,`.env.local`,`.claude`],takesEffect:`new-sessions`,fileOnlyReason:Pn,...y},{id:`file-port`,path:`port`,title:`Local port`,group:`machine-detection-sessions`,description:`Port used by the local dashboard listener.`,control:`number`,range:me,unit:{label:`port`,storedPerDisplay:1},keywords:[`server`,`listener`],defaultValue:3e3,takesEffect:`restart`,fileOnlyReason:Pn,...y},{id:`file-notify-debounce-ms`,path:`notifyDebounceMs`,title:`Notification debounce`,group:`machine-detection-sessions`,description:`Delay used to coalesce notification state changes.`,control:`number`,integer:!1,step:`any`,range:d,unit:Cn,keywords:[`timer`,`alerts`],defaultValue:3e3,takesEffect:`new-sessions`,fileOnlyReason:S,...y},{id:`file-phone-escalation-ms`,path:`phoneEscalationMs`,title:`Phone escalation delay`,group:`machine-detection-sessions`,description:`Delay before off-dashboard escalation.`,control:`number`,integer:!1,step:`any`,range:d,unit:wn,keywords:[`timer`,`telegram`],defaultValue:3e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-branch-gc-enabled`,path:`branchGc.enabled`,title:`Branch cleanup`,group:`machine-detection-sessions`,description:`Enable cleanup of eligible session branches.`,control:`toggle`,keywords:[`git`,`cleanup`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-worktrees`,path:`branchGc.worktrees`,title:`Local worktree cleanup`,group:`machine-detection-sessions`,description:`Enable cleanup of eligible local worktrees.`,control:`toggle`,keywords:[`git`,`worktree`,`cleanup`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-prefixes`,path:`branchGc.prefixes`,title:`Branch cleanup prefixes`,group:`machine-detection-sessions`,description:`Branch prefixes that filter both remote branch cleanup and local worktree cleanup.`,control:`list`,keywords:[`git`,`branch`],defaultValue:[`glimmervoid/session/`,`worktree-agent-`],takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-dry-run`,path:`branchGc.dryRun`,title:`Branch cleanup dry run`,group:`machine-detection-sessions`,description:`Report planned cleanup without deleting remote branches.`,control:`toggle`,keywords:[`git`,`safety`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:w,...y},{id:`file-branch-gc-stale-days`,path:`branchGc.staleDays`,title:`Branch stale days`,group:`machine-detection-sessions`,description:`Age threshold for orphan branch cleanup when unmerged deletion is on.`,control:`number`,integer:!1,step:`any`,range:d,unit:x,keywords:[`git`,`retention`],defaultValue:14,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-branch-gc-interval-ms`,path:`branchGc.intervalMs`,title:`Branch cleanup interval`,group:`machine-detection-sessions`,description:`Delay between branch cleanup passes.`,control:`number`,integer:!1,step:`any`,range:d,unit:En,keywords:[`git`,`schedule`],defaultValue:216e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-custom-agents`,path:`customAgents`,title:`Custom agents`,group:`machine-detection-sessions`,description:`Extra agent CLIs a session can be spawned with. The Sessions section lists the declared agents and whether each command resolves.`,control:`json`,keywords:[`adapters`,`cli`],defaultValue:[],takesEffect:`new-sessions`,fileOnlyReason:Pn,...y},{id:`file-task-title-refiner-enabled`,path:`taskTitle.refiner.enabled`,title:`Refine task titles`,group:`machine-detection-sessions`,description:`Keep session card titles useful when prompts change topic by asking a model for a short title.`,control:`toggle`,keywords:[`title`,`refiner`,`card`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-model`,path:`taskTitle.refiner.model`,title:`Task title model`,group:`machine-detection-sessions`,description:`Claude model alias the title refiner asks.`,control:`text`,keywords:[`title`,`refiner`,`model`],defaultValue:`haiku`,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-min-interval`,path:`taskTitle.refiner.minIntervalSeconds`,title:`Task title refresh interval`,group:`machine-detection-sessions`,description:`Shortest pause between two title refinements of one session.`,control:`number`,integer:!1,step:`any`,range:ce,unit:b,keywords:[`title`,`refiner`,`interval`],defaultValue:60,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-task-title-refiner-timeout`,path:`taskTitle.refiner.timeoutSeconds`,title:`Task title timeout`,group:`machine-detection-sessions`,description:`Maximum time allowed for one title refinement.`,control:`number`,integer:!1,step:`any`,range:u,unit:b,keywords:[`title`,`refiner`,`deadline`],defaultValue:60,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-codex`,path:`usage.vendors.codex`,title:`Track Codex usage`,group:`machine-usage`,description:`Include local Codex CLI transcripts in usage reports.`,control:`toggle`,keywords:[`openai`,`vendor`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-grok`,path:`usage.vendors.grok`,title:`Track Grok usage`,group:`machine-usage`,description:`Include local Grok CLI transcripts in usage reports.`,control:`toggle`,keywords:[`xai`,`vendor`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-fetch-pricing`,path:`usage.fetchPricing`,title:`Fetch current model prices`,group:`machine-usage`,description:`Load public model prices when usage tracking starts, using a cached table for up to one day. Falls back to cached or bundled prices if the fetch fails; no daily refresh runs while tracking continues.`,control:`toggle`,keywords:[`rates`,`models`],defaultValue:!0,takesEffect:`restart`,fileOnlyReason:S,...y},{id:`file-usage-plan-limits`,path:`usage.planLimits`,title:`Show plan limits`,group:`machine-usage`,description:`Read the Claude plan limit the CLI reports and show it beside usage.`,control:`toggle`,keywords:[`plan`,`limits`,`quota`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-rtk-savings`,path:`usage.rtkSavings`,title:`Estimate rtk savings`,group:`machine-usage`,description:`Estimate the tokens rtk output compression saved and show it in the Usage view.`,control:`toggle`,keywords:[`rtk`,`savings`,`tokens`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-scan-interval`,path:`usage.scanIntervalMinutes`,title:`Scan interval`,group:`machine-usage`,description:`Periodic transcript polling interval. Session activity can also trigger scans between timer ticks.`,control:`number`,range:_e,unit:xn,keywords:[`poll`,`refresh`],defaultValue:5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-warehouse-retain-days`,path:`usage.warehouseRetainDays`,title:`Retain usage history`,group:`machine-usage`,description:`How long the daily usage warehouse keeps rolled-up totals after transcript detail expires.`,control:`number`,range:ye.warehouseRetainDays,unit:x,keywords:[`history`,`warehouse`,`retention`],defaultValue:365,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-session-block-hours`,path:`usage.sessionBlockHours`,title:`Session block length`,group:`machine-usage`,description:`Length of the rolling block the Usage view groups activity into.`,control:`number`,range:ye.sessionBlockHours,unit:Sn,keywords:[`block`,`window`,`hours`],defaultValue:5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-cost-mode`,path:`usage.costMode`,title:`Cost mode`,group:`machine-usage`,description:`Choose whether recorded costs, calculated costs or both can appear.`,control:`select`,options:Fn(cn),keywords:[`pricing`,`estimate`],defaultValue:`auto`,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-usage-extra-projects-dirs`,path:`usage.extraProjectsDirs`,title:`Extra transcript folders`,group:`machine-usage`,description:`Absolute paths of additional Claude projects folders the usage scan reads.`,control:`list`,keywords:[`transcripts`,`folders`,`scan`],defaultValue:[],takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-quiet-delay`,path:`visions.dispatch.quietMs`,title:`Quiet delay`,group:`lanes-visions`,description:`Editor quiet time before a scheduled review. Saves and blank-line boundaries can dispatch immediately, subject to the other review limits.`,control:`number`,range:d,unit:Cn,keywords:[`debounce`,`idle`],defaultValue:3e4,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-cooldown`,path:`visions.dispatch.cooldownMs`,title:`Cooldown`,group:`lanes-visions`,description:`Minimum delay between reviews of the same document. Initial orientation reviews bypass this delay.`,control:`number`,range:d,unit:wn,keywords:[`rate limit`,`delay`],defaultValue:3e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-activity-max-per-hour`,path:`visions.dispatch.activityMaxPerHour`,title:`Activity max per hour`,group:`lanes-visions`,description:`Maximum activity-driven reviews dispatched per hour, capped at the overall hourly limit minus one to reserve an edit-review slot.`,control:`number`,range:ce,unit:jn,keywords:[`rate limit`,`events`],defaultValue:2,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-dispatch-timeout`,path:`visions.dispatch.dispatchTimeoutSeconds`,title:`Dispatch timeout`,group:`lanes-visions`,description:`Maximum time allowed for one review session.`,control:`number`,range:d,unit:Tn,keywords:[`deadline`,`review`],defaultValue:180,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-visions-intent-thread-ttl`,path:`visions.intent.threadTtlMs`,title:`Intent thread lifetime`,group:`lanes-visions`,description:`How long an intent thread nobody advanced stays live before it retires.`,control:`number`,range:d,unit:On,keywords:[`intent`,`decay`,`thread`],defaultValue:2592e5,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-terminal`,path:`ingest.sources.terminal.enabled`,title:`Terminal output source`,group:`lanes-ingest`,description:`Include terminal output in the ingest feed.`,control:`toggle`,keywords:[`pty`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-agent-logs`,path:`ingest.sources.agentLogs.enabled`,title:`Agent logs source`,group:`lanes-ingest`,description:`Include local agent logs in the ingest feed.`,control:`toggle`,keywords:[`transcript`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-git`,path:`ingest.sources.git.enabled`,title:`Git activity source`,group:`lanes-ingest`,description:`Include local Git activity in the ingest feed.`,control:`toggle`,keywords:[`commits`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-fs`,path:`ingest.sources.fs.enabled`,title:`File changes source`,group:`lanes-ingest`,description:`Include watched file changes in the ingest feed.`,control:`toggle`,keywords:[`filesystem`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-shell-history`,path:`ingest.sources.shellHistory.enabled`,title:`Shell history source`,group:`lanes-ingest`,description:`Include local shell history in the ingest feed.`,control:`toggle`,keywords:[`commands`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-ingest-editor`,path:`ingest.sources.editor.enabled`,title:`Editor events source`,group:`lanes-ingest`,description:`Include local editor events in the ingest feed.`,control:`toggle`,keywords:[`buffers`,`source`],defaultValue:!1,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-investigation-timeout`,path:`posthog.investigationTimeoutSeconds`,title:`Investigation timeout`,group:`lanes-posthog`,description:`Maximum time allowed for one investigation.`,control:`number`,integer:!1,step:`any`,range:d,unit:Tn,keywords:[`deadline`,`session`],defaultValue:900,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-escalation`,path:`posthog.userEscalationThreshold`,title:`Escalation threshold`,group:`lanes-posthog`,description:`Affected-user count that escalates an issue.`,control:`number`,range:d,unit:An,keywords:[`threshold`,`severity`],defaultValue:25,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-fix-timeout`,path:`posthog.fixTimeoutSeconds`,title:`Fix timeout`,group:`lanes-posthog`,description:`Maximum time allowed for one fix session.`,control:`number`,integer:!1,step:`any`,range:re,unit:Tn,keywords:[`deadline`,`repair`],defaultValue:1800,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-multiplier`,path:`posthog.trafficSpikeMultiplier`,title:`Spike multiplier`,group:`lanes-posthog`,description:`Baseline multiplier required to classify a traffic spike.`,control:`number`,integer:!1,step:`any`,range:ae,unit:Mn,keywords:[`baseline`,`ratio`],defaultValue:3,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-min-users`,path:`posthog.trafficSpikeMinUsers`,title:`Min users to alert`,group:`lanes-posthog`,description:`Minimum recent unique users for an initial traffic-spike alert. Escalation and recovery alerts bypass this minimum.`,control:`number`,range:le,unit:An,keywords:[`threshold`,`analytics`],defaultValue:10,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-cooldown`,path:`posthog.trafficSpikeCooldownMinutes`,title:`Spike cooldown`,group:`lanes-posthog`,description:`Cooldown for new traffic spikes. Escalation and recovery alerts bypass it. Zero removes the time delay; repeated active-spike alerts are still suppressed.`,control:`number`,integer:!1,step:`any`,range:ce,unit:Dn,keywords:[`silence`,`delay`],defaultValue:360,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-traffic-baseline`,path:`posthog.trafficSpikeBaselineDays`,title:`Baseline window`,group:`lanes-posthog`,description:`Historical window used to calculate normal hourly traffic.`,control:`number`,range:fe,unit:x,keywords:[`history`,`analytics`],defaultValue:7,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-recurrence-dedupe`,path:`posthog.recurrenceDedupe`,title:`Deduplicate recurring issues`,group:`lanes-posthog`,description:`Treat an issue seen again inside the recurrence window as the same investigation instead of opening a new one.`,control:`toggle`,keywords:[`recurrence`,`dedupe`,`issues`],defaultValue:!0,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-recurrence-window-days`,path:`posthog.recurrenceWindowDays`,title:`Recurrence window`,group:`lanes-posthog`,description:`How far back an issue counts as a recurrence of an investigated one.`,control:`number`,integer:!1,step:`any`,range:d,unit:x,keywords:[`recurrence`,`window`],defaultValue:7,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-transient-recurrence-limit`,path:`posthog.transientRecurrenceLimit`,title:`Transient recurrence limit`,group:`lanes-posthog`,description:`How many times a transient issue may recur before it is investigated again.`,control:`number`,integer:!1,step:`any`,range:d,unit:yn,keywords:[`recurrence`,`transient`,`limit`],defaultValue:3,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-repo-path`,path:`posthog.repoPath`,title:`Repository path`,group:`lanes-posthog`,description:`Absolute path of the local checkout investigations read and fixes branch from, for every project the project map does not name.`,control:`text`,keywords:[`repository`,`checkout`,`path`],defaultValue:``,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-posthog-project-map`,path:`posthog.projectMap`,title:`Project map`,group:`lanes-posthog`,description:`PostHog project id to a label: the name shown for that project, and, when it is an absolute path to a checkout, the repository its issues are investigated in.`,control:`json`,keywords:[`projects`,`repositories`,`map`],defaultValue:{},takesEffect:`now`,fileOnlyReason:Nn,...y},{id:`file-team-review-org`,path:`teamReview.org`,title:`GitHub organization (legacy)`,group:`lanes-team-review`,description:`Organization login that owns the team, for example PostHog. Read only when github.teams is empty.`,control:`text`,keywords:[`github`,`owner`,`legacy`],defaultValue:``,takesEffect:`now`,fileOnlyReason:`A legacy key: github.teams names teams as org/slug entries and wins whenever it is set.`,...y},{id:`file-team-review-team`,path:`teamReview.team`,title:`GitHub team (legacy)`,group:`lanes-team-review`,description:`Team slug whose members and review requests are polled. Read only when github.teams is empty.`,control:`text`,keywords:[`github`,`slug`,`legacy`],defaultValue:``,takesEffect:`now`,fileOnlyReason:`A legacy key: github.teams names teams as org/slug entries and wins whenever it is set.`,...y},{id:`file-workflows-max-actions-per-poll`,path:`workflows.maxActionsPerPoll`,title:`Actions per poll`,group:`lanes-workflows`,description:`Most actions run in one poll. The rest are dropped and logged.`,control:`number`,range:c,unit:bn,keywords:[`cap`,`rate limit`],defaultValue:20,takesEffect:`now`,fileOnlyReason:S,...y},{id:`file-workflows-rules`,path:`workflows.rules`,title:`Workflow rule definitions`,group:`lanes-workflows`,description:`The rules the Workflows section switches on and off: each names its repositories, one pull request event, its filters and its actions.`,control:`json`,keywords:[`pull requests`,`automation`,`rules`],defaultValue:[],takesEffect:`now`,fileOnlyReason:`Rule definitions are written in config.json; the Workflows section only switches each rule on or off.`,...y}]),zn=Object.freeze({sections:Ln,fileOnly:Rn}),Bn=`experimental`;function Vn(e){return e.keywords.includes(Bn)}function Hn(e,t){return t?e:e.flatMap(e=>{let t=e.settings.filter(e=>!Vn(e));return t.length===0&&e.settings.length>0?[]:[{...e,settings:t}]})}var Un=Object.freeze(Object.fromEntries(Ln.flatMap(e=>(e.legacyIds??[]).map(t=>[t,e.id])))),Wn=Object.freeze(Ln.reduce((e,t)=>{for(let n of t.settings)for(let r of n.legacyIds??[])e[r.sectionId]={...e[r.sectionId],[r.settingId]:t.id};return e},{}));function T(e){let t=[],n=e=>{if(!e||typeof e!=`object`)return e;let n=Array.isArray(e)?[]:{};return t.push([e,n]),n},r=n(e);for(let e=t.pop();e;e=t.pop()){let[t,r]=e;for(let[e,i]of Object.entries(t))Object.defineProperty(r,e,{value:n(i),writable:!0,enumerable:!0,configurable:!0})}return r}function Gn(e,t){let n=e;for(let e of t.split(`.`)){if(typeof n!=`object`||!n)return;n=n[e]}return n}function Kn(e,t){let n=t.split(`.`),r=e;for(let e of n.slice(0,-1)){if(!r||typeof r!=`object`)return;r=r[e]}r&&typeof r==`object`&&delete r[n.at(-1)]}function qn(e,t,n){let r=t.split(`.`),i=e;for(let e of r.slice(0,-1))(!i[e]||typeof i[e]!=`object`||Array.isArray(i[e]))&&(i[e]={}),i=i[e];i[r.at(-1)]=T(n)}function E(e){return e.flatMap(e=>e.settings)}function Jn(e){return e.access===`file-only`||e.control===`readonly`}function Yn(e){let t=String(e??``).trim().toLowerCase();if(!t||t===`all`)return`all`;if(t===`none`)return[];let n=t.split(`,`).map(e=>e.trim());return n.every(e=>/^\d+$/.test(e)&&Number.isSafeInteger(Number(e))&&Number(e)>0)?n.map(Number):null}var Xn=6;function D(e,t){return e.control===`number`&&typeof t==`number`?t/(e.unit?.storedPerDisplay??1):e.valueKind===`posthog-projects`?Array.isArray(t)?t.length===0?[`none`]:t.map(String):[]:T(t)}function Zn(e){return e.control===`number`&&(e.unit?.storedPerDisplay??1)!==1}function Qn(e){return String(Number(e.toFixed(Xn)))}function $n(e,t){let n=D(e,t);return e.valueKind===`posthog-projects`&&Array.isArray(n)?n.join(`, `)||`all`:typeof n==`number`&&e.unit?`${Qn(n)} ${e.unit.label}`:JSON.stringify(n??null)}function O(e,t){if(e.control===`number`){if(e.nullable&&(t==null||String(t).trim()===``))return null;let n=Number(t);if(e.zeroIsNull&&n<=0)return null;let r=n*(e.unit?.storedPerDisplay??1);return e.integer===!1?r:Math.round(r)}if(e.valueKind===`posthog-projects`)return Yn(Array.isArray(t)?t.join(`,`):t);if(e.control===`text`||e.control===`password`){let n=String(t??``).trim();return e.nullable&&!n?null:n}return T(t)}function k(e){return String(e||``).toLowerCase().match(/[a-z0-9]+/g)||[]}var er=3,tr=2,nr=1,rr=3,ir=30,ar=16;function or(e,t){return e===t?er:e.startsWith(t)?tr:t.length>=rr&&e.includes(t)?nr:0}function A(e,t,n){let r=0;for(let n of t){let t=Math.max(0,...e.map(e=>or(e,n)));if(t===0)return 0;r+=t}return r*n}function sr(e){return e.options?.map(e=>e.label).join(`, `)??``}function cr(e){return gr(e.group??``)?.title??``}function lr(e,t,n){let r=A(k(e.title),n,1e3),i=A(k(e.keywords.join(` `)),n,100),a=A(t,n,10),o=A(k(e.path),n,10),s=A(k(sr(e)),n,10),c=A(k(e.description),n,1);return r+i+a+o+s+c}function ur(e){return e.section?.title??``}function dr(e,t){return Number(e.section===null)-Number(t.section===null)}function fr(e,t,n){return[[`title`,e.title],[`keywords`,e.keywords.join(` `)],[`section`,t?.title??cr(e)],[`description`,e.description],[`path`,e.path],[`options`,sr(e)]].flatMap(([e,t])=>{let r=[];for(let e of t.matchAll(/[a-z0-9]+/gi)){let t=e[0].toLowerCase();for(let i of n){if(or(t,i)===0)continue;let n=e.index+t.indexOf(i);r.push({start:n,end:n+i.length})}}let i=[];for(let e of r.sort((e,t)=>e.start-t.start||e.end-t.end)){let t=i.at(-1);t&&e.start<=t.end?t.end=Math.max(t.end,e.end):i.push({...e})}return i.length?[{field:e,text:t,spans:i}]:[]})}function pr(e,t,n=[]){let r=k(t).slice(0,ar);if(r.length===0)return[];let i=[];for(let t of e){let e=k(t.title);for(let n of t.settings){let a=lr(n,e,r);a!==0&&i.push({section:t,setting:n,score:a,matches:fr(n,t,r)})}}for(let e of n){let t=lr(e,k(cr(e)),r);t!==0&&i.push({section:null,setting:e,score:t,matches:fr(e,null,r)})}return i.sort((e,t)=>t.score-e.score||dr(e,t)||ur(e).localeCompare(ur(t))||e.setting.title.localeCompare(t.setting.title)).slice(0,ir)}function mr(e,t,n={},r={}){let i=/^#settings\/([^/]+)(?:\/([^/]+))?$/.exec(String(e||``));if(!i)return null;let a,o;try{a=decodeURIComponent(i[1]),o=i[2]?decodeURIComponent(i[2]):null}catch{return null}let s=n[a]||a,c=(o?r[s]?.[o]:void 0)||s,l=t.find(e=>e.id===c);if(!l)return null;let u=o?l.settings.find(e=>e.id===o||e.legacyIds?.some(e=>e.settingId===o&&e.sectionId===s)):null;return o&&!u?null:{sectionId:c,settingId:u?.id||null,hash:`#settings/${c}${u?`/${u.id}`:``}`}}function hr(e){let t=new Map,n=new Map;for(let r of[...E(e.sections),...e.fileOnly])t.set(r.id,r),n.set(r.path,r);return{byId:t,byPath:n}}hr(zn);function gr(e,t=zn){let n=t.sections.find(t=>t.id===e);return n?{title:n.title,description:n.description}:In[e]??null}function _r({checked:e=[],stored:t=[],rendered:n=[]}={}){let r=new Set(n),i=[...e];for(let e of t)typeof e==`string`&&e.trim()&&(r.has(e)||i.includes(e)||i.push(e));return i}function vr(e,t){let n=new Set(e.map(e=>e.id)),r=[...new Set(t)].filter(e=>!n.has(e));return[...e,...r.map(e=>({id:e,name:`Unavailable project (${e})`}))]}var yr=new WeakMap,br=`Configured`,xr=`•`.repeat(12),Sr=`Each line must be a positive whole-number PostHog project id, or the one word none.`,Cr=3,wr=new Set([`customAgents`]),Tr=1e-9,Er=`Lanes`,Dr=Object.freeze({now:`Applies now`,"new-sessions":`New sessions`,restart:`After restart`}),Or=Object.freeze({browser:`This browser`,machine:`This machine`});function kr(e,t){let n=t.secretSources;if(!n||typeof n!=`object`)return null;let r=n[e.path];return typeof r==`string`?r:null}function Ar(e){let t=e.rtkInstall;return t?.status===`installing`?`No rtk binary found. Glimmervoid is installing it into ~/.glimmervoid/bin now.`:e.rtkInstallSupported===!1?`No rtk binary found. Automatic installation is unavailable on this server platform; install a compatible binary manually.`:t?.status===`failed`?`No rtk binary found. The last install attempt failed: ${t.reason||`unknown reason`}. A save can retry after the ten-minute failure cooldown; saves during the cooldown skip installation.`:`No rtk binary found. Saving requests installation into ~/.glimmervoid/bin on supported server platforms, subject to installer eligibility.`}function jr(e){return e.control===`password`}function Mr(e){return`${e.path}${br}`}function Nr(e,t){if(Object.is(e,t))return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>Nr(e,t[n]));if(!e||!t||typeof e!=`object`||typeof t!=`object`)return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length&&n.every(n=>Object.hasOwn(t,n)&&Nr(e[n],t[n]))}function Pr(e){return yr.get(e)||null}function Fr(e){return Array.isArray(e)?e.map(e=>String(e)):[]}function Ir(e){return e.split(`
2
+ `).map(e=>e.trim()).filter(e=>e!==``)}function Lr(e){let t=e.range;if(!t)return null;let n={min:Number(D(e,t.min))};return t.max!=null&&(n.max=Number(D(e,t.max))),t.exclusiveMin&&(n.exclusiveMin=!0),n}function Rr(e){let t=`Default ${$n(e,e.defaultValue)}`;return Zn(e)?`${t}, stored as ${JSON.stringify(e.defaultValue)} ${e.unit?.storedLabel??``}`.trimEnd():t}function zr(e,t){let n=Rr(e),r=wr.has(e.path)?void 0:Gn(t,e.path);if(r===void 0)return{currentText:null,defaultText:n,jsonFragment:null};let i={};return qn(i,e.path,r),{currentText:`Current ${$n(e,r)}`,defaultText:n,jsonFragment:JSON.stringify(i,null,2)}}function Br(e,t,n){let r=t??e.find(e=>e.id===n.group);if(!r)return gr(n.group??``)?.title??`config.json`;let i=e.find(e=>e.id===r.parent);return i?`${i.title} / ${r.title}`:r.level===`lanes`?`${Er} / ${r.title}`:r.title}function Vr(e,t){return e.filter(e=>e.parent===t)}function Hr(e,t){let n=e.find(e=>e.id===t);return n?n.parent?e.find(e=>e.id===n.parent)??n:n:null}function Ur(e){return e.filter(e=>!e.parent)}function Wr(e){let t=e.filter(e=>e.level===`lanes`);return[{heading:null,sections:e.filter(e=>e.level!==`lanes`)},{heading:Er,sections:t}].filter(e=>e.sections.length>0)}function Gr(e,t,n,r){return r?`hidden`:n.trim()?`search`:t&&Hr(e,t)?`section`:`list`}function Kr(e,t={}){let n={};for(let r of E(e)){if(Jn(r))continue;if(r.path.startsWith(`pref:`)){let e=r.path.slice(5),i=t.prefs?.[e]??t[r.path];n[r.path]=D(r,i??r.defaultValue);continue}if(jr(r)){let e=Gn(t,Mr(r))===!0;n[r.path]=e?xr:``;continue}let e=Gn(t,r.path);n[r.path]=D(r,e??r.defaultValue)}return yr.set(n,T(t)),n}function qr(e,t,n){let r=E(e).filter(e=>Jn(e)||e.path.startsWith(`pref:`)||kr(e,Pr(t)||{})||jr(e)&&n[e.path]===xr?!1:!Nr(t[e.path],n[e.path]));if(r.length===0)return{};let i=Pr(t)||{},a=(Array.isArray(i.projectChoices)?i.projectChoices:[]).map(e=>e.id).filter(e=>typeof e==`string`),o={},s=new Set;for(let e of r){let[r]=e.path.split(`.`);if(!e.path.includes(`.`)){o[r]=O(e,n[e.path]);continue}if(!s.has(r)){let e=i[r];o[r]=e&&typeof e==`object`&&!Array.isArray(e)?T(e):{},s.add(r)}let c=O(e,n[e.path]);if(e.control===`projects`){let n=t[e.path];c=_r({checked:Array.isArray(c)?c:[],stored:Array.isArray(n)?n:[],rendered:vr(a.map(e=>({id:e,name:e})),Array.isArray(n)?n:[]).map(e=>e.id)})}qn(o,e.path,c)}for(let t of E(e))jr(t)&&Kn(o,Mr(t));return delete o.secretSources,o}function Jr(e,t,n,r){return Ci(qr(e,t,{...t,[n.path]:r}))}function Yr(e){let t=e.unit?.label;return t?` of ${t}`:``}function j(e){let t=Lr(e);if(!t)return`Allowed range is unavailable.`;let n=`${e.integer!==!1&&!Zn(e)?`whole number`:`number`}${Yr(e)}`;return t.exclusiveMin&&t.min===0?`Must be a positive ${n}.`:t.max==null?`Must be a ${n} ${t.exclusiveMin?`above`:`of at least`} ${Qn(t.min)}.`:`Must be a ${n} between ${Qn(t.min)} and ${Qn(t.max)}.`}function Xr(e){return`Must be a multiple of ${$n(e,1)}.`}function Zr(e){return Math.abs(e-Math.round(e))<Tr&&Number.isSafeInteger(Math.round(e))}function Qr(e,t){return Number(O({...e,integer:!1,nullable:!1,zeroIsNull:!1},t))}function $r(e,t){if(e.nullable&&(t==null||String(t).trim()===``))return null;let n=e.range;if(!n)return`Allowed range is unavailable.`;if(t==null||String(t).trim()===``)return j(e);let r=Number(t);if(!Number.isFinite(r))return j(e);if(e.zeroIsNull&&r<=0)return null;let i=Qr(e,r);if(e.integer!==!1&&!Zr(i))return Zn(e)?Xr(e):j(e);let a=Number(O(e,r));return n.exclusiveMin&&a<=n.min||!n.exclusiveMin&&a<n.min||n.max!=null&&a>n.max?j(e):null}function ei(e,t,n=!1){return n?j(e):$r(e,t.trim())}function ti(e,t){let n=t.trim();if(e.nullable&&n===``)return null;let r=Number(n);return e.zeroIsNull&&r<=0?null:r}function ni(e){if(e==null||e===``)return``;let t=Number(e);return Number.isFinite(t)?Qn(t):String(e)}function ri(e,t){return Array.isArray(t)?e.valueKind===`posthog-projects`&&O(e,t)===null?Sr:null:`Must be a list.`}function ii(e,t){let n={};for(let r of E(e)){if(Jn(r))continue;let e=null;r.control===`number`&&(e=$r(r,t[r.path])),r.control===`list`&&(e=ri(r,t[r.path])),r.control===`select`&&r.options&&!r.options.some(e=>e.value===t[r.path])&&(e=`Choose one of the available options.`),e&&(n[r.id]=e)}return ai(E(e),t,n),n}function ai(e,t,n){for(let r of e){let i=e.find(e=>e.id===r.maximumSettingId);if(!i||n[r.id]||n[i.id])continue;let a=t[r.path],o=t[i.path];Number(O(r,a))>Number(O(i,o))&&(n[r.id]=`Minimum must not exceed the maximum (${ni(o)}).`,n[i.id]=`Maximum must not be below the minimum (${ni(a)}).`)}}function oi(e,t){return E(e).find(e=>e.id===t.maximumSettingId||e.maximumSettingId===t.id)}function si(e,t,n){let r=oi(e,t);return ii([{id:`scoped`,level:`machine`,title:``,description:``,settings:r?[t,r]:[t]}],n)[t.id]??null}function ci(e,t){return e.control===`number`?ti(e,t):e.control===`list`?Ir(t):t}function li(e,t){return O(e,e.control===`list`?Fr(t):t)}function ui(e){return e?.isDirty===!0}function di(e,t,n,r,i,a=!1){if(!ui(n))return{kind:`unchanged`};let o=t.control===`number`?ei(t,r,a):null;if(o)return{kind:`invalid`,error:o};let s=ci(t,r);if(Nr(O(t,s),li(t,n.base)))return{kind:`unchanged`};let c=si(e,t,{...i,[t.path]:s});return c?{kind:`invalid`,error:c}:{kind:`changed`,value:s}}function fi(e){return jr(e)?``:D(e,e.defaultValue)}function pi(e,t){return Nr(t,fi(e))}function mi(e){return e.presentation?e.presentation:(e.options?.length??0)<=Cr?`segmented`:`select`}function hi(e){return Array.isArray(e)?e.length>0:typeof e==`string`?e.trim()!==``:e===!0}function gi(e,t){return e.danger===!0&&!!e.warning&&hi(t)}function _i(e,t){return gi(e,t)}function vi(e){return e.title.charAt(0).toLowerCase()+e.title.slice(1)}function yi(e){return jr(e)?`Reset removes the stored ${vi(e)}. Anything that relies on it stops until a new one is saved.`:_i(e,fi(e))?e.warning??``:null}function bi(e){return[e.repos.join(`, `),e.trigger,e.actions.map(e=>e.type).join(`, `)].join(` `)}function xi(e){if(e==null)return[`No rules. Add workflows.rules to config.json.`];let t=ue.safeParse(e);return t.success?t.data.rules.length===0?[`No rules. Add workflows.rules to config.json.`]:t.data.rules.map(e=>[e.name,e.enabled?`enabled`:`disabled`,bi(e)].join(` `)):[`The workflows block is invalid, so no rule runs: ${t.error.issues[0]?.message??`unknown problem`}`]}function Si(e){let t=ue.safeParse(e??{});return t.success?t.data.rules.map(e=>({id:e.id,name:e.name,isEnabled:e.enabled,summary:bi(e)})):[]}function Ci(e){let t=e.workflows;return typeof t!=`object`||!t||Array.isArray(t)?e:{...e,workflows:Object.fromEntries(Object.entries(t).filter(([e])=>e!==`rules`))}}var wi=2200,Ti=1600,Ei=15e3,Di=`https://glimmervoid.dev`,Oi=`browser-appearance`,ki=`flying-animals`,Ai=Object.freeze({ArrowRight:1,ArrowDown:1,ArrowLeft:-1,ArrowUp:-1}),ji=`lanes-features`,Mi=Object.freeze({id:ji,level:`lanes`,title:`Features`,description:`Optional tabs, each hidden until its own toggle is on.`,settings:[]}),Ni=`browser-shortcuts`,Pi=`browser-status-key`,Fi=Object.freeze({id:Pi,level:`browser`,title:`Status key`,description:`What each session status and pull request icon means.`,settings:[]}),Ii=`browser-about`,Li=Object.freeze({id:Ii,level:`browser`,title:`About`,description:`The running build and where the project lives.`,settings:[]}),Ri=Object.freeze({sounds:()=>xt(),themes:yt});function zi(e){if(!e.optionsFrom)return e;let t=Ri[e.optionsFrom]?.()??[];return{...e,options:t.map(e=>({value:e.id,label:e.label}))}}function Bi(e){return e.isExperimentalBuild===!0}function Vi(){return Hn(zn.sections,Bi(h()))}function Hi(){let e=Vi().map(e=>({...e,settings:e.settings.map(zi)})),t=e.findIndex(e=>e.id===Ni)+1,n=[...e.slice(0,t),Fi,...e.slice(t)],r=n.findIndex(e=>e.level===`lanes`);return Object.freeze([...n.slice(0,r),Mi,...n.slice(r),Li])}var M=Hi(),Ui=Bi(h()),N=!1,Wi=null,Gi=null,P=null,F=null,I=null,Ki=null,L=null,R=null,z=M[0],B=h(),V={},qi=new Map,Ji=new Map,H=new Map,U=new WeakMap,Yi=Promise.resolve(),W=new Map,G=``,Xi=!1,Zi=new Set,K=new Map;function Qi(){return{themeId:Be(),flyingAnimalsEnabled:Ze(),...We(),soundEnabled:Fe(),soundId:mt(Ue()),notificationsEnabled:Re(),sessionUsageChips:Ye(),phoneArrowPad:Xe(),nextAttentionKeyCode:Ge()}}function $i(e){V=Kr(M,{...e,prefs:Qi()})}function q(e){return H.has(e.id)?H.get(e.id):V[e.path]}function ea(e){return[e,...Vr(M,e.id)]}function ta(e){return ea(e).flatMap(e=>e.settings)}function na(e){return M.find(t=>t.settings.some(t=>t.id===e.id))??z}function ra(e,t=null){history.replaceState(history.state,``,Yt(e,t))}function ia(e){requestAnimationFrame(()=>{let t=document.getElementById(e),n=t?.closest(`.settings-view-advanced-panel`);n&&(N=!0,n.hidden=!1,R?.querySelector(`.settings-view-advanced-toggle`)?.setAttribute(`aria-expanded`,`true`));let r=t?.closest(`.settings-view-setting`);r&&(r.scrollIntoView({block:`center`}),r.classList.remove(`settings-view-setting-flash`),requestAnimationFrame(()=>r.classList.add(`settings-view-setting-flash`)))})}function aa(e){e.replaceChildren();for(let t of ze(tn,Et())){let n=f(`div`,`shortcut-group`);n.appendChild(f(`h2`,`settings-view-subsection-title`,t.title));let r=f(`dl`,`shortcut-rows`);for(let e of t.items){let t=f(`dd`,`shortcut-keys`);e.combos.forEach((e,n)=>{n>0&&t.appendChild(f(`span`,`shortcut-sep`,`/`)),ot(t,e)}),r.append(f(`dt`,`shortcut-label`,e.label),t)}n.appendChild(r),e.appendChild(n)}}function oa(e){return vt().find(t=>t.gate!==void 0&&`fromSettings`in t.gate&&t.gate.fromSettings===e)?.label}function sa(e){let t=f(`ul`,`settings-view-stack settings-features`);for(let e of Rt){let n=M.find(t=>t.id===e.sectionId),r=da(e.settingId),i=oa(Kt[e.rule]);if(!n||!r||!i)continue;let a=q(r)===!0,o=f(`li`,`settings-feature`),s=f(`div`,`settings-feature-head`);s.append(f(`span`,`settings-feature-name`,i),yo(`feature`,a?`On`:`Off`)),o.append(s,f(`p`,`settings-view-section-description`,n.description),It(e.sectionId,e.settingId,r.title)),t.appendChild(o)}e.appendChild(t)}function ca(e){let t=new URL(e,Di),{telemetryInstallId:n}=B;return typeof n==`string`&&n&&t.searchParams.set(`gv`,n),t.href}function la(e,t){let n=f(`a`,`settings-about-link`,e);return n.href=t,n.target=`_blank`,n.rel=`noopener`,n}function ua(e){let t=f(`div`,`settings-about`),n=f(`span`,`settings-about-version`,`GLIMMERVOID `);n.appendChild(f(`span`,`settings-about-v`,`v0.46.2-next.104`));let r=f(`span`,`settings-about-links`);r.append(la(`GitHub`,`https://github.com/${sn}`),la(`Changelog`,`https://github.com/${sn}/blob/main/CHANGELOG.md`),la(`Website`,ca(`/`))),t.append(n,r),e.appendChild(t)}function da(e){return M.flatMap(e=>e.settings).find(t=>t.id===e)??null}function fa(e){if(V[`pref:soundEnabled`]===e)return;V[`pref:soundEnabled`]=e;let t=da(`alert-sounds-enabled`);t&&Z(t)}var pa={"pref:flyingAnimalsMinGapSeconds":e=>De(Number(e)),"pref:flyingAnimalsMaxGapSeconds":e=>Me(Number(e)),"pref:flyingAnimalsMinDurationSeconds":e=>Pe(Number(e)),"pref:flyingAnimalsMaxDurationSeconds":e=>je(Number(e)),"pref:flyingAnimalsScale":e=>Ae(Number(e)),"pref:flyingAnimalsOnPhone":e=>ke(e===!0)};function ma(e,t){if(e.path===`pref:sessionUsageChips`){Le(t===!0),gt(t===!0);return}if(e.path===`pref:phoneArrowPad`){Oe(t===!0),Bt(t===!0);return}if(e.path===`pref:nextAttentionKeyCode`){we(String(t)),Tt(Ge());let e=R?.querySelector(`.settings-view-shortcuts`);e&&aa(e);return}if(e.path===`pref:themeId`){qe(String(t)),_t(String(t));return}if(e.path===`pref:flyingAnimalsEnabled`){Ce(t===!0),Wt(t===!0);return}let n=pa[e.path];n?(n(t),Wt(Ze())):e.path===`pref:soundEnabled`?Ot(t===!0):e.path===`pref:soundId`?(Se(String(t)),ft(String(t))):e.path===`pref:notificationsEnabled`&&(Ie(t===!0),t===!0&&Jt().then(()=>Z(e,{force:!0})))}function J(e,t){let n=Ji.get(e.id);n!==void 0&&clearTimeout(n),Ji.delete(e.id),t&&qi.set(e.id,t),t||qi.delete(e.id),Mo(e)}function ha(e){J(e,{tone:`saved`,text:`Saved`}),Ji.set(e.id,window.setTimeout(()=>J(e,null),wi))}function Y(e,t){W.delete(e.id),e.path.startsWith(`pref:`)?(V[e.path]=t,ma(e,t),Z(e),ha(e)):H.has(e.id)&&JSON.stringify(H.get(e.id))===JSON.stringify(t)||(H.set(e.id,t),J(e,{tone:`saving`,text:`Saving`}),Yi=Yi.then(()=>ga(e,t)))}async function ga(e,t){let n=Jr(M,V,e,t);if(Object.keys(n).length===0)H.delete(e.id),J(e,null),Z(e);else{J(e,{tone:`saving`,text:`Saving`});try{let r=await be(`update-settings`,{settings:n});if(H.get(e.id)===t&&H.delete(e.id),r.type===`settings-error`){J(e,{tone:`error`,text:String(r.message)}),Z(e,{force:!0});return}if(r.type!==`settings-updated`){J(e,{tone:`error`,text:`The server did not confirm the save.`}),Z(e,{force:!0});return}jt(r.settings),ha(e)}catch(n){H.get(e.id)===t&&H.delete(e.id),J(e,{tone:`error`,text:n?.message||`Failed to save the setting.`}),Z(e,{force:!0})}}}function _a(e,t){t&&W.set(e.id,t),t||W.delete(e.id),Mo(e)}function va(e,t){if(!t.exclusiveMin)return t.min;if(e.integer!==!1)return t.min+1}function ya(e){return e?`On`:`Off`}function ba(e){let t=f(`div`,`settings-view-toggle-wrap`),n=f(`label`,`settings-view-toggle`),r=f(`input`,`settings-view-checkbox`);r.type=`checkbox`,r.checked=q(e)===!0,e.id===`desktop-notifications`&&!Nt()&&(r.checked=!1,r.disabled=!0),r.setAttribute(`aria-labelledby`,e.id);let i=f(`span`,`settings-view-toggle-state`,ya(r.checked));return r.addEventListener(`change`,()=>{let t=r.checked;_i(e,t)?(r.checked=!1,i.textContent=ya(!1),it({title:e.title,message:e.warning??``,confirmLabel:`Turn on`,danger:!0,onConfirm:()=>Y(e,!0)})):(i.textContent=ya(t),Y(e,t))}),n.append(r,i),t.appendChild(n),t}function xa(e){let t=f(`div`,`settings-view-shortcut-key`),n=wt(Je(`next-attention`,tn,String(q(e)))),r=f(`button`,`btn-dialog btn-dialog-cancel`,`Record`);r.type=`button`;let i=f(`span`,`settings-view-shortcut-key-prompt`);return i.setAttribute(`role`,`status`),r.addEventListener(`click`,()=>Sa(e,t,r,i)),t.append(n,r,i),t}function Sa(e,t,n,r){let i=()=>{window.removeEventListener(`keydown`,o,!0),window.removeEventListener(`pointerdown`,a,!0),window.removeEventListener(`focusin`,a,!0),n.disabled=!1,r.textContent=``},a=e=>{e.target instanceof Node&&t.contains(e.target)||i()},o=t=>{if(!n.isConnected||!n.checkVisibility()){i();return}t.preventDefault(),t.stopImmediatePropagation();let r=Ke(t,tn);r.kind!==`ignored`&&(r.kind===`refused`?_a(e,r.reason):(i(),_a(e,null),n.focus(),r.kind===`recorded`&&Y(e,r.keyCode)))};_a(e,null),n.disabled=!0,r.textContent=`Press the new shortcut, or Esc to cancel.`,window.addEventListener(`keydown`,o,!0),window.addEventListener(`pointerdown`,a,!0),window.addEventListener(`focusin`,a,!0)}function Ca(e,t,n){e.addEventListener(`blur`,t),e.addEventListener(`keydown`,e=>{e.key===`Enter`?(e.preventDefault(),t()):e.key===`Escape`&&(e.preventDefault(),n())})}function wa(e){return e instanceof HTMLTextAreaElement||e instanceof HTMLInputElement&&[`text`,`number`,`password`].includes(e.type)}function Ta(e,t){U.set(t,{base:q(e),isDirty:!1}),t.addEventListener(`input`,()=>{let e=U.get(t);e&&(e.isDirty=!0)})}function X(e,t,n){t.value!==n&&(t.value=n),U.set(t,{base:q(e),isDirty:!1}),_a(e,null)}function Ea(e,t,n,r=!1){let i=U.get(t);if(!i)return;let a=di(M,e,i,t.value,V,r);a.kind===`invalid`?_a(e,a.error):a.kind===`unchanged`?X(e,t,n):_i(e,a.value)?(X(e,t,n),it({title:e.title,message:e.warning??``,confirmLabel:`Save`,danger:!0,onConfirm:()=>Y(e,a.value)})):(U.set(t,{base:a.value,isDirty:!1}),Y(e,a.value))}function Da(e){let t=f(`input`,`settings-view-input`);t.type=e.control===`password`?`password`:`text`;let n=()=>String(q(e)??``);t.value=n(),e.control===`password`&&(t.value=``,t.placeholder=n()?`Configured`:`Not configured`);let r=kr(e,B);return r&&(t.disabled=!0,t.setAttribute(`aria-description`,`Supplied by ${r}`)),t.autocomplete=`off`,t.spellcheck=!1,t.setAttribute(`aria-labelledby`,e.id),Ta(e,t),Ca(t,()=>{if(e.control===`password`){let n=t.value;if(n===``)return;X(e,t,``),Y(e,n)}else Ea(e,t,n())},()=>X(e,t,e.control===`password`?``:n())),t}function Oa(e){let t=f(`input`,`settings-view-input`),n=Lr(e);t.type=`number`;let r=()=>ni(q(e));t.value=r(),t.step=e.integer===!1?String(e.step??`any`):`1`;let i=n?va(e,n):void 0;i!=null&&(t.min=String(i)),n?.max!=null&&(t.max=String(n.max)),t.autocomplete=`off`,t.setAttribute(`aria-labelledby`,e.id),Ta(e,t),Ca(t,()=>Ea(e,t,r(),t.validity.badInput),()=>X(e,t,r()));let a=e.unit?.label;if(!a)return t;let o=f(`div`,`settings-view-number`),s=f(`span`,`settings-view-unit`,a);return s.setAttribute(`aria-hidden`,`true`),t.setAttribute(`aria-description`,a),o.append(t,s),o}function ka(e,t){let n=[...e.querySelectorAll(`[role="radio"]`)],r=n.some(e=>e.dataset.value===t);for(let[e,i]of n.entries()){let n=i.dataset.value===t;i.setAttribute(`aria-checked`,String(n)),i.tabIndex=n||!r&&e===0?0:-1}}function Aa(e,t,n){n!==String(q(e))&&(ka(t,n),Y(e,n),ka(t,String(q(e))))}function ja(e){let t=f(`div`,`settings-view-segmented`);t.setAttribute(`role`,`radiogroup`),t.setAttribute(`aria-labelledby`,e.id);let n=e.options??[];for(let r of n){let n=f(`button`,`settings-view-segment`,r.label);n.type=`button`,n.dataset.value=r.value,n.setAttribute(`role`,`radio`),n.addEventListener(`click`,()=>Aa(e,t,r.value)),t.appendChild(n)}return t.addEventListener(`keydown`,r=>{let i=Ai[r.key];if(!i||n.length===0)return;r.preventDefault();let a=Math.max(0,n.findIndex(t=>t.value===String(q(e)))),o=n[(a+i+n.length)%n.length];Aa(e,t,o.value),t.querySelector(`[data-value="${CSS.escape(o.value)}"]`)?.focus()}),ka(t,String(q(e))),t}function Ma(e){let t=f(`select`,`settings-view-input`);t.setAttribute(`aria-labelledby`,e.id);for(let n of e.options??[]){let e=f(`option`,null,n.label);e.value=n.value,t.appendChild(e)}return t.value=String(q(e)),t.addEventListener(`change`,()=>Y(e,t.value)),t}function Na(e,t){let n=e.valueKind===`posthog-projects`?`One project id per line, or none for no project. Shift+Enter adds a line.`:`One entry per line. Shift+Enter adds a line.`;return t.length>0||!e.listEmptyText?n:`${e.listEmptyText} ${n}`}function Pa(e){let t=f(`textarea`,`settings-view-input settings-view-list-input`),n=()=>Fr(q(e)),r=()=>n().join(`
3
3
  `);t.rows=3,t.value=r(),t.autocomplete=`off`,t.spellcheck=!1,t.placeholder=e.listPlaceholder??``,t.setAttribute(`aria-labelledby`,e.id),Ta(e,t),t.addEventListener(`blur`,()=>Ea(e,t,r())),t.addEventListener(`keydown`,n=>{n.key===`Escape`?(n.preventDefault(),X(e,t,r())):n.key!==`Enter`||n.shiftKey||(n.preventDefault(),Ea(e,t,r()))});let i=f(`div`,`settings-view-list`);return i.append(t,f(`span`,`settings-view-list-hint`,Na(e,n()))),i}var Fa=null;function Ia(e){let t=Ut(vt().map(e=>e.view),Fr(q(e))),n=f(`ol`,`settings-view-tab-order`);n.setAttribute(`aria-labelledby`,e.id);for(let[r,i]of t.entries()){let a=vt().find(e=>e.view===i)?.label??i,o=f(`li`,`settings-view-tab-order-item`);o.append(f(`span`,`settings-view-tab-order-label`,a),La(e,t,i,r-1,`Move up`,`Move ${a} up`),La(e,t,i,r+1,`Move down`,`Move ${a} down`)),n.append(o)}return n}function La(e,t,n,r,i,a){let o=`${n}:${i}`,s=f(`button`,`btn-dialog btn-dialog-cancel`,i);return s.type=`button`,s.setAttribute(`aria-label`,a),s.disabled=r<0||r>=t.length,o===Fa&&(s.dataset.restoresFocus=`true`),s.addEventListener(`click`,()=>{Fa=o,Y(e,qt(t,n,r))}),s}function Ra(e){let t=f(`div`,`settings-view-projects`),n=q(e),r=new Set(Array.isArray(n)?n:[]),i=Array.isArray(B.projectChoices)?B.projectChoices:[];i.length===0&&t.appendChild(f(`div`,`settings-empty`,`No configured projects are available.`));for(let n of vr(i,[...r])){let i=f(`label`,`settings-view-project-choice`),a=f(`input`,`settings-view-checkbox`);a.type=`checkbox`,a.checked=r.has(n.id),a.addEventListener(`change`,()=>{let t=q(e),r=new Set(Array.isArray(t)?t:[]);a.checked&&r.add(n.id),a.checked||r.delete(n.id),Y(e,[...r])}),i.append(a,document.createTextNode(n.name)),t.appendChild(i)}return t}function za(e,t,{isPrimary:n=!1,isEnabled:r=!0}={}){let i=f(`button`,`btn-dialog ${n?`btn-dialog-confirm`:`btn-dialog-cancel`} settings-update-button`,e);return i.type=`button`,i.disabled=!r,i.addEventListener(`click`,t),i}function Ba(e){let t=f(`span`,`settings-update-action-status`,e??``);return t.setAttribute(`role`,`status`),t}function Va(){let{isCheckInFlight:e,checkSendFailure:t}=m();return e?`Checking for updates.`:t}function Ha(){let{status:e,lastAutoCheckAt:t}=m();e?(Xi=!1,se({status:e,checkForUpdates:B.checkForUpdates,now:Date.now(),lastAutoCheckAt:t})&&Zt()):Xi=!0}function Ua(e){return e===`update`?za(`Update`,st,{isPrimary:!0}):e===`restart`?za(`Restart`,Ct,{isPrimary:!0}):za(`Check for updates`,Zt,{isEnabled:!m().isCheckInFlight})}function Wa(){let{status:e,journal:t,request:n}=m(),r=o({status:e,journal:t,request:n}),i=f(`div`,`settings-update-actions`);if(r.actions.length>0){let e=f(`div`,`settings-update-buttons`);e.append(...r.actions.map(Ua)),i.appendChild(e)}let a=Va();return a&&i.appendChild(Ba(a)),r.note&&i.appendChild(Ba(r.note)),r.command&&i.appendChild(f(`code`,`settings-update-command`,r.command)),i}function Ga(e,...t){let n=f(`div`,`settings-update-fact`);return n.append(f(`span`,`settings-update-fact-label`,e),...t),n}function Ka(){let e=n(m().journal);if(!e)return null;let t=f(`div`,`settings-update-progress`);t.dataset.state=e.state,t.setAttribute(`role`,`status`),e.terminalLine&&t.appendChild(f(`div`,`settings-update-terminal`,e.terminalLine));let r=f(`ol`,`settings-update-steps`);for(let t of e.steps){let e=f(`li`,`settings-update-step`);e.dataset.status=t.status,e.append(f(`span`,`settings-update-step-state`,t.status),f(`span`,`settings-update-step-label`,t.label)),r.appendChild(e)}if(t.appendChild(r),e.outputTail.length===0)return t;let i=f(`pre`,`settings-update-output`,e.outputTail.join(`
4
4
  `));if(e.outputStepId&&(i.dataset.step=e.outputStepId),!e.outputStepLabel)return t.appendChild(i),t;let a=`Output from ${e.outputStepLabel}`;return i.setAttribute(`aria-label`,a),t.append(f(`div`,`settings-update-output-label`,a),i),t}function qa(){let e=r(m().status),t=[e.label];if(e.releaseUrl){let n=f(`a`,`settings-link`,`View release`);n.href=e.releaseUrl,n.target=`_blank`,n.rel=`noopener noreferrer`,t.push(n)}return Ga(`Latest`,...t)}function Ja(){let t=f(`div`,`settings-view-status-block settings-update-status`),{status:n,journal:r}=m(),i=s(n,r),a=f(`div`,`settings-update-summary`,i.headline);a.dataset.tone=i.tone,t.appendChild(a),t.appendChild(Ga(`Running`,ge(n))),e(n)&&t.appendChild(qa());let o=typeof n?.lastCheckAt==`number`?n.lastCheckAt:null,c=Ga(`Last checked`,l({status:n,checkForUpdates:B.checkForUpdates,relativeTime:xe(o)}));o&&(c.title=new Date(o).toLocaleString()),t.appendChild(c),t.appendChild(Wa());let u=Ka();return u&&t.appendChild(u),t}function Ya(e){return e===null?`not probed yet`:e?`resolved`:`not found on PATH`}function Xa(){let e=Array.isArray(B.customAgents)?B.customAgents:[];return e.length===0?[`None declared. Add customAgents to config.json.`]:e.map(e=>{let t=e.args.length>0?`${e.command} ${e.args.join(` `)}`:e.command;return`${e.id} ${e.label} ${t} ${Ya(e.resolvable)}`})}function Za(){let e=f(`div`,`settings-view-status-block`);e.appendChild(f(`div`,`settings-section-title`,`Declared agents`));for(let t of Xa())e.appendChild(f(`div`,`settings-readonly`,t));return e}function Qa(e){K.set(e,{tone:`ok`,text:`Saved`}),window.setTimeout(()=>{K.get(e)?.tone===`ok`&&(K.delete(e),$())},wi)}async function $a(e,t){Zi.add(e.id),K.delete(e.id),$();try{let n=await be(`update-settings`,{settings:{workflows:{rules:[{id:e.id,enabled:t}]}}},{timeoutMs:rt});if(Zi.delete(e.id),n.type===`settings-error`&&K.set(e.id,{tone:`error`,text:String(n.message)}),n.type===`settings-updated`){Qa(e.id),jt(n.settings);return}}catch(t){K.set(e.id,{tone:`error`,text:nt(t,rt)})}Zi.delete(e.id),$()}function eo(e){let t=tt(`settings-workflow-rule-status`);if(Zi.has(e.id))return t.show(`busy`,`Saving`),t.element;let n=K.get(e.id);return n&&t.show(n.tone,n.text),t.element}function to(e){let t=f(`div`,`settings-view-toggle-wrap`),n=f(`label`,`settings-view-toggle`),r=f(`input`,`settings-view-checkbox`);return r.type=`checkbox`,r.checked=e.isEnabled,r.disabled=Zi.has(e.id),r.setAttribute(`aria-label`,`Run rule ${e.name}`),r.addEventListener(`change`,()=>{$a(e,r.checked)}),n.append(r,f(`span`,`settings-view-toggle-state`,ya(e.isEnabled)),f(`span`,`settings-readonly`,`${e.name} ${e.summary}`)),t.append(n,eo(e)),t}function no(){let e=f(`div`,`settings-view-status-block`);e.appendChild(f(`div`,`settings-section-title`,`Rules`));let t=Si(B.workflows);if(t.length>0){for(let n of t)e.appendChild(to(n));return e}for(let t of xi(B.workflows))e.appendChild(f(`div`,`settings-readonly`,t));return e}function ro(){let e=f(`div`,`settings-view-status-block`);e.appendChild(f(`div`,`settings-section-title`,`Last report`));for(let t of Pt())e.appendChild(f(`div`,`settings-readonly`,t));return e}function io(){let e=f(`div`,`settings-view-status-block`);if((H.get(`remote-sessions`)??V.remoteSessions)!==!0)return e.appendChild(f(`div`,`settings-readonly`,`Turn on Remote Coder sessions (experimental) to connect agent logins for them.`)),e;for(let t of[`claude-code`,`codex`]){let n=f(`div`,`settings-telegram-test`),r=f(`button`,`btn-dialog btn-dialog-cancel`,`Connect`);r.type=`button`,r.addEventListener(`click`,()=>rn(t)),n.append(f(`div`,`settings-readonly`,nn(Xt(t),t)),r),e.appendChild(n)}return e}function ao(){let e=f(`div`,`settings-view-status-block`),t=f(`button`,`btn-dialog btn-dialog-cancel`,`Set up remote host`);return t.type=`button`,t.addEventListener(`click`,an),e.appendChild(t),e}function oo(e){return e.status===`agent-logins`?io():e.status===`remote-setup`?ao():e.status===`update-actions`?Ja():e.status===`custom-agents`?Za():e.status===`workflows`?no():f(`div`,`settings-readonly`,`Not available`)}function so(e){return e.control===`readonly`?oo(e):e.control===`toggle`?ba(e):e.control===`number`?Oa(e):e.control===`select`?mi(e)===`segmented`?ja(e):Ma(e):e.control===`list`?Pa(e):e.control===`projects`?Ra(e):e.control===`shortcut-key`?xa(e):e.control===`tab-order`?Ia(e):Da(e)}function co(e){let t=kr(e,B);return t?`Supplied by ${t}. Change the server environment and restart to replace this credential.`:e.status!==`rtk-install`||q(e)!==!0||B.rtkAvailable?``:Ar(B)}function lo(e){if(e.control===`readonly`)return null;if(e.status===`usage-last-report`){let e=ro();return e.classList.add(`settings-view-status-slot`),e}if(e.id===`desktop-notifications`)return vo(e);if(e.id===`telemetry-enabled`)return _o();if(e.status===`telegram-delivery`)return po();let t=co(e);return t?f(`div`,`settings-view-warning settings-view-status-slot`,t):null}function uo(){let e=i.safeParse(B.telegramDelivery);if(!e.success)return[];let{setupWarning:t,lastFailure:n}=e.data,r=t?[t]:[];return n&&r.push(`The last Telegram send failed at ${new Date(n.failedAt).toLocaleString()}: ${n.message}`),r}function fo(e){e.replaceChildren(...uo().map(e=>f(`p`,`settings-view-warning`,e)))}function po(){let e=f(`div`,`settings-view-status-slot settings-telegram-delivery`),t=f(`div`,`settings-telegram-delivery-lines`);fo(t);let n=f(`button`,`btn-dialog btn-dialog-cancel`,`Send test message`);n.type=`button`;let r=tt(`settings-telegram-test-status`);n.addEventListener(`click`,async()=>{n.disabled=!0;let e=await $e(`telegram-test`,{},r,{busyText:`Sending a test message to Telegram.`});n.disabled=!1,e?.type===`telegram-test-result`&&(B=Qt({telegramDelivery:e.telegramDelivery}),fo(t),e.ok?r.show(`ok`,`Sent. Check the Telegram chat for the test message.`):r.show(`error`,`Not sent: ${e.error??`Telegram refused the message.`}`))});let i=f(`div`,`settings-telegram-test`);return i.append(n,r.element),e.append(t,i),e}async function mo(){ho.disabled=!0;let e=await $e(`request-telemetry-deletion`,{},go,{busyText:`Sending the deletion request.`,timeoutMs:Ei});ho.disabled=!1,e?.type===`telemetry-deletion-result`&&(e.ok?go.show(`ok`,`Deletion requested. New usage starts under a new id.`):go.show(`error`,`Not sent: PostHog did not take the request. Try again later.`))}var ho=f(`button`,`btn-dialog btn-dialog-cancel`,`Delete my data`);ho.type=`button`,ho.addEventListener(`click`,()=>{it({title:`Delete your usage data?`,message:`We delete everything collected under this install. New usage starts under a new id.`,confirmLabel:`Delete my data`,danger:!0,onConfirm:()=>{mo()}})});var go=tt(`settings-telemetry-deletion-status`);function _o(){let e=f(`div`,`settings-view-status-slot settings-telemetry-data`);return e.append(la(`Privacy details`,ca(`/privacy`)),ho,go.element),e}function vo(e){let t=Vt(()=>Z(e,{force:!0}));return t.element.hidden?null:(t.element.classList.add(`settings-view-status-slot`),t.element)}function yo(e,t){let n=f(`span`,`settings-view-chip`,t);return n.dataset.chip=e,n}function bo(e,t){let n=ve(e);return n?n.then(()=>t,()=>`Copy failed`):Promise.resolve(`Copy failed`)}function xo(e,t,{copiedText:n,textToCopy:r}){let i=f(`span`,`settings-view-copy-status`);i.setAttribute(`role`,`status`),t.type=`button`,t.addEventListener(`click`,async()=>{i.textContent=await bo(r(),n),setTimeout(()=>{i.textContent=``},Ti)}),e.append(t,i)}function So(e){let t=f(`div`,`settings-view-setting-heading`),n=na(e),r=f(`h2`,`settings-view-setting-title`,e.title);r.id=e.id,r.addEventListener(`click`,()=>ra(n.id,e.id));let i=f(`button`,`settings-view-copy-link`,`#`);return i.setAttribute(`aria-label`,`Copy link`),t.appendChild(r),xo(t,i,{copiedText:`Link copied`,textToCopy:()=>new URL(Yt(n.id,e.id),location.href).href}),t}function Co(e){let t=f(`div`,`settings-view-chips`);return t.append(yo(`scope`,Or[e.scope]),yo(`effect`,Dr[e.takesEffect])),t}function wo(e){return e.control===`readonly`||kr(e,B)?!1:!pi(e,q(e))}function To(e){let t=f(`div`,`settings-view-control-foot`),n=f(`span`,`settings-view-save-status`);n.setAttribute(`role`,`status`);let r=f(`button`,`settings-view-reset`,`Reset`);return r.type=`button`,r.title=`Reset to the default value`,r.addEventListener(`click`,()=>{let t=fi(e),n=yi(e);n===null?Y(e,t):it({title:e.title,message:n,confirmLabel:`Reset`,danger:!0,onConfirm:()=>Y(e,t)})}),t.append(n,r),t}function Eo(e,t){let n=e.querySelector(`.settings-view-save-status`),r=qi.get(t.id);n&&(n.textContent=r?.text??``,r&&(n.dataset.tone=r.tone),r||delete n.dataset.tone);let i=e.querySelector(`.settings-view-reset`);i&&(i.disabled=!wo(t));let a=e.querySelector(`.settings-view-field-error`),o=W.get(t.id);a&&!o&&a.remove(),a&&o&&(a.textContent=o),!a&&o&&e.querySelector(`.settings-view-setting-control`)?.appendChild(f(`div`,`settings-view-field-error`,o))}function Do(e){let t=f(`article`,`settings-view-setting`);t.dataset.settingId=e.id,e.control===`readonly`&&(t.dataset.readout=`true`);let n=f(`div`,`settings-view-setting-text`);n.append(So(e),f(`p`,`settings-view-setting-description`,e.description),Co(e));let r=f(`div`,`settings-view-setting-control`);r.appendChild(so(e)),e.control!==`readonly`&&r.appendChild(To(e)),t.append(n,r),gi(e,q(e))&&t.appendChild(f(`div`,`settings-view-warning settings-warning`,e.warning));let i=lo(e);return i&&t.appendChild(i),Eo(t,e),t}function Oo(e){return R?.querySelector(`[data-setting-id="${e.id}"]`)??null}function ko(e){let t=e.querySelector(`.settings-view-setting-control`);t&&(t.querySelector(`[data-restores-focus="true"]:not([disabled])`)??t.querySelector(`[role="radio"][aria-checked="true"]`)??t.querySelector(`input:not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled])`))?.focus()}function Ao(e,t){if(!wa(e)||!wa(t))return;e.disabled=t.disabled,e.placeholder=t.placeholder;let n=U.get(t);n&&!ui(U.get(e))&&(U.set(e,{base:n.base,isDirty:!1}),e.value!==t.value&&(e.value=t.value))}function jo(e,t,n){if(e===n){Ao(e,t);return}let r=[...e.children],i=[...t.children];for(let[t,a]of i.entries()){let i=r[t];i?i.contains(n)?jo(i,a,n):i.replaceWith(a):e.appendChild(a)}for(let e of r.slice(i.length))e.remove()}function Z(e,{force:t=!1}={}){let n=Oo(e);if(!n)return;let r=document.activeElement,i=n.contains(r),a=i&&!t&&wa(r)?r:null;(!a||!ui(U.get(a)))&&W.delete(e.id);let o=Do(e);a?jo(n,o,a):(n.replaceWith(o),i&&ko(o))}function Mo(e){let t=Oo(e);t&&Eo(t,e)}function No(e){Oo(e)?.querySelector(`.settings-view-setting-control`)?.replaceChildren(oo(e))}function Po(){for(let e of ta(z))e.control===`readonly`?No(e):Z(e)}function Fo(){let e=f(`button`,`btn-dialog btn-dialog-cancel`,`Reset all to defaults`);return e.type=`button`,e.addEventListener(`click`,()=>{Te(),$i(B),Wt(Ze()),Q()}),e}function Io(e){let t=f(`div`,`settings-view-advanced`),n=f(`button`,`dialog-advanced-toggle settings-view-advanced-toggle`,`Advanced`);n.type=`button`,n.setAttribute(`aria-expanded`,String(N)),n.setAttribute(`aria-controls`,`settings-view-advanced-panel`);let r=f(`div`,`dialog-advanced-panel settings-view-advanced-panel`);r.id=`settings-view-advanced-panel`,r.hidden=!N,n.addEventListener(`click`,()=>{N=!N,r.hidden=!N,n.setAttribute(`aria-expanded`,String(N))});for(let t of e)r.append(Do(t));return z.id===Oi&&r.append(Fo()),t.append(n,r),t}function Lo(e){let t=f(`div`,`settings-view-streamer-placeholder`),n=f(`button`,`btn-dialog btn-dialog-confirm`,`Turn off streamer mode`);n.type=`button`;let r=f(`span`,`settings-view-copy-status`,``);r.setAttribute(`role`,`status`),n.addEventListener(`click`,async()=>{n.disabled=!0,r.textContent=``;let e=await at(!1);n.disabled=!1,r.textContent=e}),t.append(f(`p`,`settings-view-section-description`,`Settings are hidden in streamer mode.`),n,r),e.appendChild(t)}bt(()=>Q());function Ro(e){let t=f(`header`,`settings-view-subsection`),n=f(`h2`,`settings-view-subsection-title`,e.title);return n.addEventListener(`click`,()=>ra(e.id)),t.append(n,f(`p`,`settings-view-section-description`,e.description)),t}function zo(e,t){for(let n of t.settings.filter(e=>e.access!==`advanced`))e.appendChild(Do(n)),n.id===ki&&e.appendChild(on());let n=t.settings.filter(e=>e.access===`advanced`);n.length>0&&e.append(Io(n))}function Q(){if(Yo(),G){qo();return}if(!R)return;if(R.textContent=``,kt()){Lo(R);return}let e=f(`header`,`settings-view-section-header`),t=f(`h1`,`settings-view-section-title`,z.title);if(t.tabIndex=-1,t.addEventListener(`click`,()=>ra(z.id)),e.append(t,f(`p`,`settings-view-section-description`,z.description)),R.appendChild(e),z.id===Ni){let e=f(`div`,`settings-view-stack`);zo(e,z),R.appendChild(e);let t=f(`div`,`shortcut-groups settings-view-shortcuts`);aa(t),R.appendChild(t);return}if(z.id===Ii){ua(R);return}if(z.id===Pi){R.appendChild(pt()),R.appendChild(dt());return}if(z.id===ji){sa(R);return}let n=f(`div`,`settings-view-stack`);for(let e of ea(z))e.id!==z.id&&n.appendChild(Ro(e)),zo(n,e);R.appendChild(n)}function Bo(e,{focusContent:t=!1,settingId:n=null,updateHash:r=!0,openPhoneSection:i=!0}={}){r&&G&&(G=``,I&&(I.value=``));let a=Hr(M,e)??z;z.id!==a.id&&(N=!1),z=a;let o=M.find(t=>t.id===e)??a;Vo(F),i&&Ft()&&(Ki=o.id),Q(),ns(z)&&ts(),z.id===`machine-updates`&&Ha(),r&&ra(o.id,n),n&&ia(n),t&&R?.querySelector(`h1`)?.focus()}function Vo(e){for(let t of e?.querySelectorAll(`[data-settings-section]`)||[]){let e=t.dataset.settingsSection===z.id;t.setAttribute(`aria-current`,e?`page`:`false`)}}function Ho(e){return e.section!==null}function Uo(e){I&&(I.value=``,G=``,Zo(),Bo(e.section.id,{settingId:e.setting.id}))}function Wo(e){return pr(Vi(),e,zn.fileOnly)}function Go(e,t,n,r,i){let a=f(e,t),o=r.matches.find(e=>e.field===i),s=o?n.indexOf(o.text):-1;if(!o||s<0)return a.textContent=n,a;let c=0;for(let e of o.spans)a.append(n.slice(c,s+e.start),f(`mark`,`settings-view-search-highlight`,n.slice(s+e.start,s+e.end))),c=s+e.end;return a.append(n.slice(c)),a}function Ko(e,t){let{currentText:n,defaultText:r,jsonFragment:i}=zr(t.setting,B);if(n!==null&&e.appendChild(f(`span`,`settings-view-search-current`,n)),e.append(f(`span`,`settings-view-search-default`,r),Co(t.setting),f(`p`,`settings-view-list-hint`,`Edit in config.json or with glimmervoid settings set.`)),i===null)return;let a=f(`div`,`settings-view-control-foot`);xo(a,f(`button`,`settings-view-copy-json`,`Copy as JSON`),{copiedText:`JSON copied`,textToCopy:()=>i}),e.appendChild(a)}function qo(){if(!R)return;if(R.textContent=``,kt()){Lo(R);return}let e=Wo(G),t=f(`div`,`settings-view-section-header`);if(t.append(f(`h1`,`settings-view-section-title`,`Settings search`),f(`p`,`settings-view-section-description`,`${e.length} ${e.length===1?`result`:`results`} for "${G}"`)),R.appendChild(t),e.length===0){R.appendChild(f(`p`,`settings-empty settings-view-search-empty`,`No settings found.`));return}let n=f(`ol`,`settings-view-search-results`);n.setAttribute(`aria-label`,`Settings search results`);for(let t of e){let e=f(`li`,`settings-view-search-result`);e.tabIndex=-1;let r=Br(M,t.section,t.setting);e.appendChild(Go(`p`,`settings-view-search-breadcrumb`,r,t,`section`));let i=Go(`span`,`settings-view-setting-title`,t.setting.title,t,`title`);if(Ho(t)){let n=f(`button`,`settings-view-search-open`);n.type=`button`,n.appendChild(i),n.addEventListener(`click`,()=>Uo(t)),e.appendChild(n)}Ho(t)||(e.classList.add(`settings-view-search-file-only`),e.appendChild(i)),e.append(Go(`p`,`settings-view-setting-description`,t.setting.description,t,`description`),Go(`code`,`settings-view-key-path`,t.setting.path,t,`path`));let a=new Set([`title`,`description`,`path`,`section`]);if(!t.matches.some(e=>a.has(e.field))){let n=t.matches.find(e=>e.field===`options`)??t.matches.find(e=>e.field===`keywords`);n&&e.appendChild(Go(`p`,`settings-view-list-hint`,n.text,t,n.field))}Ho(t)||Ko(e,t),n.appendChild(e)}R.appendChild(n)}function Jo(){return Gr(M,Ki,G,kt())}function Yo(){if(!P)return;let e=Jo(),t=P.dataset.settingsScreen!==e;P.dataset.settingsScreen=e,L&&(L.hidden=e!==`section`),t&&St()}function Xo(){let e=z.id;Qo(``),F?.querySelector(`[data-settings-section="${e}"]`)?.focus()}function Zo(){if(F&&P){F.textContent=``;for(let e of Wr(Ur(M))){let t=f(`div`,`settings-view-nav-group`);e.heading&&t.appendChild(f(`div`,`settings-view-nav-heading`,e.heading));for(let n of e.sections){let e=f(`button`,`settings-view-nav-item`,n.title);e.type=`button`,e.dataset.settingsSection=n.id,e.addEventListener(`click`,()=>Bo(n.id,{focusContent:Ft()})),t.appendChild(e)}F.appendChild(t)}G?(Yo(),qo()):Bo(z.id,{updateHash:!1,openPhoneSection:!1})}}function Qo(e,{updateHash:t=!0}={}){G=e.trim(),I&&(I.value=e),Ki=null,t&&history.replaceState(history.state,``,en(G)),Zo()}function $o(e){if(G&&e.key===`Enter`&&e.target===I){let t=Wo(G).find(Ho);if(!t)return;e.preventDefault(),Uo(t);return}if(e.key===`Escape`&&G){if(!I)return;e.preventDefault(),Qo(``),I.focus();return}if(e.key!==`ArrowUp`&&e.key!==`ArrowDown`||!F)return;let t=[...F.querySelectorAll(`[data-settings-section]`)].filter(e=>e instanceof HTMLElement),n=document.activeElement;if(!(n instanceof HTMLElement))return;let r=t.indexOf(n);r<0||(e.preventDefault(),t[(r+(e.key===`ArrowDown`?1:-1)+t.length)%t.length].focus())}function es(e){Dt(fa),Wi=e,Wi.textContent=``,P=f(`div`,`settings-view-shell`);let t=f(`div`,`settings-view-sidebar`);I=f(`input`,`settings-view-search`),I.type=`search`,I.placeholder=`Search settings`,I.setAttribute(`aria-label`,`Search settings`),F=f(`nav`,`settings-view-nav`),F.setAttribute(`role`,`navigation`),F.setAttribute(`aria-label`,`Settings sections`),L=f(`button`,`settings-view-back`,`Settings`),L.prepend(Qe(et)),L.type=`button`,L.hidden=!0,L.setAttribute(`aria-label`,`Back to settings sections`),L.addEventListener(`click`,lt),R=f(`div`,`settings-view-content`),R.setAttribute(`aria-live`,`polite`),I.addEventListener(`input`,()=>{let e=I;e&&Qo(e.value)}),I.addEventListener(`keydown`,$o),F.addEventListener(`keydown`,$o),t.append(I,L,F),P.append(t,R),Wi.appendChild(P),B=h(),is(),$i(B),ct(Jo),zt(fs),Zo(),ts(),Gi?.disconnect(),Gi=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&ts()}),Gi.observe(Wi),cs()}function ts(){ut().then(as)}function ns(e){return ta(e).some(e=>e.path===`pref:soundId`)}function rs(){M=Hi(),Ui=Bi(h()),z=Hr(M,z.id)??M[0]}function is(){return Bi(B)!==Ui&&(rs(),!0)}function as(){if(rs(),V[`pref:soundId`]=mt(Ue()),G){qo();return}let e=da(`alert-sound`);e&&ns(z)&&Z(e)}function os(e,t,n){let r=At(e??n);r?Qo(r.query):(Qo(``,{updateHash:!1}),Ft()&&!e?history.replaceState(history.state,``,en(``)):Bo(e||z.id,{settingId:t}))}function ss(e){let t=mr(e,M,Un,Wn);os(t?.sectionId??null,t?.settingId??null,e)}function cs(){let e=ht();e&&(e.isLink?ss(e.hashAtRequest):os(e.sectionId,e.settingId,e.hashAtRequest))}function ls(){B=h();let e=is();$i(B),G?qo():e?(Zo(),Q()):Po()}function us(e,t){let n=t.querySelector(`.settings-view-status-slot`),r=lo(e);n&&r&&n.replaceWith(r),n&&!r&&n.remove(),!n&&r&&t.appendChild(r)}function $(){for(let e of ta(z)){if(!e.status)continue;let t=Oo(e);t&&(e.control===`readonly`?No(e):us(e,t))}}function ds(){if(z.id!==`machine-updates`)return;let e=da(`update-actions`);e&&No(e)}function fs(e){switch(e.kind){case`broadcast`:ls();return;case`status`:$();return;case`update`:ds(),e.frame===`status`&&Xi&&z.id===`machine-updates`&&Ha();return;case`activate`:cs();return;case`return-to-list`:Xo()}}function ps(){z.id===Oi&&Q()}window.matchMedia(`(prefers-reduced-motion: reduce)`).addEventListener(`change`,ps),Gt(()=>{Ki=null,Yo(),ps()}),Mt($);var ms={mount:es};export{ms as view};
@@ -1,2 +1,2 @@
1
- import{H as e,V as t,_t as n,m as r,n as i,o as a,u as o,y as s}from"./dom-helpers-B98sy9ep.js";import{g as c,nt as l}from"./ui-prefs-Dvsgw_ZF.js";import{i as u}from"./action-status-D9Sf2cZp.js";import{Sn as d,_n as ee,bn as f,gn as p,hn as m,vn as h,xn as g,yn as _}from"./index-BReL4NSr.js";function v(e){return e.kind===`prompt`||e.kind===`expansion`||e.kind===`thinking`||e.kind===`assistant`||e.kind===`notice`?e.text:e.kind===`tool_result`?e.content:e.kind===`raw`?e.line:e.kind===`tool_call`?JSON.stringify(e.input,null,2)??String(e.input??``):[`${e.vendor} ${e.vendorSessionId}`,e.transcriptPath,e.reason??``].filter(Boolean).join(`
1
+ import{H as e,V as t,_t as n,m as r,n as i,o as a,u as o,y as s}from"./dom-helpers-B98sy9ep.js";import{g as c,nt as l}from"./ui-prefs-Dvsgw_ZF.js";import{i as u}from"./action-status-D9Sf2cZp.js";import{Sn as d,_n as ee,bn as f,gn as p,hn as m,vn as h,xn as g,yn as _}from"./index-In1pKLyK.js";function v(e){return e.kind===`prompt`||e.kind===`expansion`||e.kind===`thinking`||e.kind===`assistant`||e.kind===`notice`?e.text:e.kind===`tool_result`?e.content:e.kind===`raw`?e.line:e.kind===`tool_call`?JSON.stringify(e.input,null,2)??String(e.input??``):[`${e.vendor} ${e.vendorSessionId}`,e.transcriptPath,e.reason??``].filter(Boolean).join(`
2
2
  `)}var te=[{kind:`thinking`,label:`Thinking`},{kind:`tool_result`,label:`Tool result`},{kind:`raw`,label:`Raw`}];function ne(e){if(e.startedAt===null)return 0;let t=e.head?.record.ts??e.startedAt;for(let n of e.rows)t=Math.max(t,n.record.ts);return Math.max(0,t-e.startedAt)}function y(e){let{rowCount:r,toolCallCount:i,errorCount:a,resultBytes:o}=e.metrics;return`${`${r} ${r===1?`row`:`rows`}`}, ${`${i} ${i===1?`tool`:`tools`}`}, ${`${a} ${a===1?`error`:`errors`}`}, ${n(o,`KB`)}, ${t(ne(e))}`}function b(e){return e.hasSelectionChanged||e.isRenderedTraceStale||!e.hasRenderedOnce}function x(e,t,n){return e!==0||t?null:n?.startedAt??null}function S(e,t){return C(e,t)?e.filter(e=>e!==t):[...e,t]}function C(e,t){return e.includes(t)}function w(e){return e?`No trace has been recorded for ${e.label}.`:`No sessions are available.`}var T=null,E=null,D=null,O=null,k=[],A=!1,j=c(),M=!1,N=null;function P(){return!!T&&!o(T)}function re(){let{sessionOptions:e,selectedSessionId:t}=g();return e.find(e=>e.id===t)??null}function ie(){let e=a(`label`,`trace-session-field`),t=a(`span`,`trace-session-label`,`Session`),n=a(`select`,`trace-session-select`),{sessionOptions:r,selectedSessionId:i}=g();n.disabled=r.length===0;for(let e of r){let t=a(`option`,null,e.label);t.value=e.id,t.selected=e.id===i,n.append(t)}return n.addEventListener(`change`,()=>ee(n.value)),e.append(t,n),e}function F(e){e.toggleAttribute(`data-hidden`,C(j,e.dataset.kind??``))}function I(){if(D)for(let e of D.querySelectorAll(`.trace-row`))F(e)}function L(e){if(D)for(let t of D.querySelectorAll(`details`))t.open=e}function R(){let e=a(`div`,`trace-filters`);for(let t of te){let n=a(`button`,`trace-filter`,t.label);n.type=`button`;let r=()=>{n.setAttribute(`aria-pressed`,String(!C(j,t.kind)))};r(),n.addEventListener(`click`,()=>{j=S(j,t.kind),l(j),r(),I()}),e.append(n)}for(let[t,n]of[[`Expand all`,!0],[`Collapse all`,!1]]){let r=a(`button`,`trace-expand-control`,t);r.type=`button`,r.addEventListener(`click`,()=>{L(n)}),e.append(r)}return e}function z(){let e=i(`trace`,`Session trace`,`Bodies load from the local trace file only when requested.`),t=a(`div`,`trace-controls`),{selectedTrace:n,traceFailureText:r}=g();t.append(ie());let o=n?.filePath??``,s=a(`code`,`trace-path`,o);s.title=o,t.append(s);let c=n?x(n.firstOffset,n.hasDroppedEarliestRows,n.grouping.turns[0]):null;if(c!==null&&t.append(a(`span`,`trace-session-start`,`Started ${new Date(c).toLocaleString()}`)),e.append(t,R()),!r)return e;let l=u(`trace-status`);return l.show(`error`,r),e.append(l.element),e}function B(e){let t=a(`div`,`trace-copy-wrap`),n=a(`button`,`trace-copy`,`Copy`);n.type=`button`;let r=a(`span`,`trace-copy-status`);return r.setAttribute(`role`,`status`),n.addEventListener(`click`,()=>{let t=s(e);t?(t.then(()=>{r.textContent=`Copied`}).catch(()=>{r.textContent=`Copy failed`}),setTimeout(()=>{r.textContent=``},1600)):r.textContent=`Copy failed`}),t.append(n,r),t}function V(){let e=a(`div`,`trace-earlier-wrap`),t=a(`button`,`trace-load-earlier`,`Load earlier`);return t.type=`button`,t.addEventListener(`click`,()=>{p()}),e.append(t),e}function H(t,n,r=``){let i=a(`details`,`trace-row${r?` ${r}`:``}`);i.dataset.kind=t.kind,i.dataset.tone=t.tone,F(i);let o=a(`summary`,`trace-row-summary`);o.append(a(`span`,`trace-offset`,e(n,t.record.ts)),a(`span`,`trace-kind`,t.tag),a(`span`,`trace-row-label`,t.text));for(let e of t.badges){let t=a(`span`,`trace-badge`,e);t.dataset.badge=e,o.append(t)}let s=a(`div`,`trace-row-body`);i.append(o,s);let c=!1;return i.addEventListener(`toggle`,()=>{if(!i.open||c)return;c=!0;let e=v(t.record);s.append(B(e),a(`pre`,`trace-row-pre`,e))}),i}function U(e){return a(`span`,`trace-turn-metrics`,y(e))}function W(e,t){e&&t&&(t.textContent=y(e))}function G(t,n){let r=t.children,i=Math.min(n.rows.length,r.length);for(let t=0;t<i;t+=1){let i=r[t]?.querySelector(`.trace-offset`);i&&(i.textContent=e(n.startedAt,n.rows[t].record.ts))}}function K(e,t,n){let i=H(t,e.startedAt,`trace-turn-head`);return r(i,`.trace-row-summary`).append(n),i}function q(e){let t=a(`section`,`trace-turn`),n=U(e);if(e.head&&t.append(K(e,e.head,n)),!e.head){let e=a(`h2`,`trace-leading-title`);e.append(a(`span`,`trace-leading-label`,`Before first prompt`),n),t.append(e)}let r=a(`div`,`trace-rows`);for(let t of e.rows)r.append(H(t,e.startedAt));return e.hasTrimmedRows&&t.append(a(`p`,`trace-trimmed`,`Earlier rows trimmed`)),t.append(r),{section:t,rowsElement:r,metricsElement:n}}function J(e){if(!e)return w(null);let{pendingSessionId:t,selectedTrace:n}=g();return t===e.id&&!n?.hasLoadedOnce?`Loading trace.`:w(e)}function Y(){if(!T)return;let e=a(`div`,`trace-content`);E=z(),e.append(E),D=null,O=null,k=[];let t=re(),n=g().selectedTrace?.grouping.turns??[];if(!t||n.length===0){e.append(a(`p`,`trace-empty`,J(t))),T.replaceChildren(e),A=!1;return}d(f())&&(O=V(),e.append(O));let r=a(`div`,`trace-turns`);for(let e of n){let t=q(e);k.push(t),r.append(t.section)}D=r,I(),e.append(r),T.replaceChildren(e),A=!1}function X(){T&&(P()?Y():A=!0)}function Z(){if(!E||!P())return;let e=z();E.replaceWith(e),E=e}function Q(e){if(!D)return;let t=g().selectedTrace?.grouping.turns[e.turnIndex];if(!t)return;if(e.isNewTurn){let e=q(t);k.push(e),D.append(e.section);return}let n=k[e.turnIndex];if(n){for(let r of e.rows)n.rowsElement.append(H(r,t.startedAt));W(t,n.metricsElement)}}function ae(e){let t=e.parentElement;t&&!t.querySelector(`.trace-trimmed`)&&t.insertBefore(a(`p`,`trace-trimmed`,`Earlier rows trimmed`),e)}function $(){d(f())?!O&&D?.parentElement&&(O=V(),D.parentElement.insertBefore(O,D)):(O?.remove(),O=null)}function oe(e){if(!(e.droppedTurnCount>0||e.droppedRowCount>0)){$();return}if(k=k.slice(e.droppedTurnCount),D)for(let t=0;t<e.droppedTurnCount;t+=1)D.firstElementChild?.remove();let t=k[0];if(t&&e.droppedRowCount>0){for(let n=0;n<e.droppedRowCount;n+=1)t.rowsElement.firstElementChild?.remove();ae(t.rowsElement),W(g().selectedTrace?.grouping.turns[0],t.metricsElement)}e.hasJustDroppedEarliestRows&&Z(),$()}function se(e){if(P()&&!A&&D)for(let t of e)Q(t);else D=null,M=!0}function ce(e){if(!D)return;let t=k[0]??null,n=t?.rowsElement.parentElement??null,r=g().selectedTrace?.grouping.turns[e.newTurns.length]??null;if((e.mergedHead||e.mergedRows.length>0)&&t&&n&&r){let i=t.rowsElement;if(e.mergedHead){n.querySelector(`.trace-leading-title`)?.remove();let a=U(r),o=K(r,e.mergedHead,a);n.insertBefore(o,i),t.metricsElement=a}e.mergedHead||W(r,t.metricsElement);let a=document.createDocumentFragment();for(let t of e.mergedRows)a.append(H(t,r.startedAt));i.prepend(a),G(i,r)}let i=document.createDocumentFragment(),a=[];for(let t of e.newTurns){let e=q(t);a.push(e),i.append(e.section)}D.prepend(i),k.unshift(...a)}function le(e){let t=P()&&!A&&!!D&&!e.needsRerender,n=T?.parentElement??null;N={canPrependInPlace:t,scrollElement:n,previousScrollHeight:n?.scrollHeight??0,previousScrollTop:n?.scrollTop??0},t&&ce(e)}function ue(e){oe(e),M&&(M=!1,X());let t=N;N=null,t&&(t.canPrependInPlace||X(),t.canPrependInPlace&&Z(),t.scrollElement&&(t.scrollElement.scrollTop=t.previousScrollTop+t.scrollElement.scrollHeight-t.previousScrollHeight))}function de(e){switch(e.kind){case`selection-reset`:A=!0;return;case`rebuild`:X();return;case`header`:Z();return;case`sessions`:(e.hasSelectionChanged||!E)&&X(),!e.hasSelectionChanged&&E&&Z();return;case`records-appended`:se(e.appends);return;case`records-prepended`:le(e.prepend);return;case`trimmed`:ue(e.trim);return}}function fe(e){T||(T=a(`div`,`trace-panel`),e.append(T),h(P),_(de),Y())}function pe(){T&&b({hasSelectionChanged:m(),isRenderedTraceStale:A,hasRenderedOnce:!!E})&&Y()}var me={mount:fe,refresh:pe};export{me as view};