shellbell 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +30 -30
- package/dist/doctor-CTHrssge.js +86 -0
- package/dist/native-controller.js +2 -2
- package/dist/native-service.js +2 -2
- package/dist/{service-entry-BY8SEvyp.js → service-entry-uoRwcU1h.js} +3 -3
- package/dist/service-lifecycle-CSQmtvfk.js +29 -0
- package/package.json +2 -2
- package/dist/doctor-DBq3DNjT.js +0 -86
- package/dist/service-lifecycle-GJqJjIQF.js +0 -29
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import{$ as e,D as t,Dt as n,Et as r,Ft as i,I as a,It as o,Jt as s,Mt as c,Nt as l,P as u,Pt as d,Q as f,Qn as p,Qt as m,St as h,Xt as g,_n as _,a as v,at as y,c as b,f as ee,gn as te,gt as x,ht as ne,it as re,j as ie,jt as S,kt as ae,lr as C,o as w,qt as oe,r as se,rt as T,s as ce,st as le,tt as ue,yt as de,z as fe}from"./service-lifecycle-CSQmtvfk.js";import{execFile as pe,execFileSync as me,spawn as he}from"node:child_process";import{accessSync as ge,chmodSync as _e,closeSync as ve,constants as E,existsSync as D,fsyncSync as ye,linkSync as be,mkdirSync as xe,openSync as Se,readFileSync as O,readSync as Ce,readdirSync as we,readlinkSync as Te,realpathSync as Ee,renameSync as De,rmSync as Oe,statSync as k,statfsSync as ke,symlinkSync as Ae,unlinkSync as je,writeFileSync as Me}from"node:fs";import{homedir as A}from"node:os";import{basename as j,delimiter as Ne,dirname as M,isAbsolute as N,join as P,normalize as Pe,relative as Fe,resolve as Ie,sep as Le}from"node:path";import{z as Re}from"zod";import{createHash as ze,randomUUID as F}from"node:crypto";import{EventEmitter as Be}from"node:events";import{connect as Ve}from"node:net";import He from"ws";import{isDeepStrictEqual as Ue,promisify as We}from"node:util";import{StringDecoder as Ge}from"node:string_decoder";import{create as Ke,fromBinary as qe,toBinary as Je}from"@bufbuild/protobuf";import{fileDesc as Ye,messageDesc as I}from"@bufbuild/protobuf/codegenv2";import{performance as Xe}from"node:perf_hooks";const Ze=[[768,879],[1155,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1552,1562],[1611,1631],[1648,1648],[1750,1756],[1759,1764],[1767,1768],[1770,1773],[1809,1809],[1840,1866],[1958,1968],[2070,2093],[2304,2306],[2362,2362],[2364,2364],[2369,2376],[2381,2381],[2385,2391],[2402,2403],[3633,3633],[3636,3642],[3655,3662],[6832,6911],[7616,7679],[8203,8207],[8232,8238],[8288,8292],[8400,8432],[65024,65039],[65056,65071],[65279,65279],[127995,127999],[917760,917999]],Qe=[[4352,4447],[8986,8987],[9001,9002],[9193,9196],[9200,9200],[9203,9203],[9725,9726],[9748,9749],[9800,9811],[9855,9855],[9875,9875],[9889,9889],[9898,9899],[9917,9918],[9924,9925],[9934,9934],[9940,9940],[9962,9962],[9970,9971],[9973,9973],[9978,9978],[9981,9981],[9989,9989],[9994,9995],[10024,10024],[10060,10060],[10062,10062],[10067,10069],[10071,10071],[10133,10135],[10160,10160],[10175,10175],[11035,11036],[11088,11088],[11093,11093],[11904,12350],[12353,13311],[13312,19903],[19968,40959],[40960,42191],[43360,43391],[44032,55203],[63744,64255],[65040,65049],[65072,65135],[65280,65376],[65504,65510],[94176,94180],[94208,101119],[110592,111359],[126980,126980],[127183,127183],[127374,127374],[127377,127386],[127488,127569],[127744,127776],[127789,127797],[127799,127868],[127870,127891],[127904,127946],[127951,127955],[127968,127984],[127988,127988],[127992,128062],[128064,128064],[128066,128252],[128255,128317],[128331,128334],[128336,128359],[128378,128378],[128405,128406],[128420,128420],[128507,128591],[128640,128709],[128716,128716],[128720,128722],[128725,128727],[128747,128748],[128756,128764],[128992,129003],[129292,129338],[129340,129349],[129351,129535],[129648,129791],[131072,196605],[196608,262141]];function $e(e,t){let n=0,r=t.length-1;for(;n<=r;){let i=n+r>>1,a=t[i];if(e<a[0])r=i-1;else if(e>a[1])n=i+1;else return!0}return!1}function et(e){return e===0||e<32||e>=127&&e<160||$e(e,Ze)?0:$e(e,Qe)?2:1}function tt(e){let t=0,n=!1,r=0;for(let i of e){let e=i.codePointAt(0);if(e===8205){n=!0;continue}let a=et(e);if(a!==0||n){if(n){r=Math.max(r,a),n=!1;continue}t+=r,r=a}}return t+r}function nt(e,t){let n={t:e},r=t.fg,i=t.bg;if(t.inv){let e=r??15;r=i??0,i=e}r!==void 0&&(n.fg=r),i!==void 0&&(n.bg=i),t.b&&(n.b=!0),t.i&&(n.i=!0),t.u&&(n.u=!0),t.s&&(n.s=!0),t.f&&(n.f=!0);let a=tt(e);return a!==oe(e)&&(n.n=a),n}function L(e){return Math.max(0,Math.min(255,e|0))}function rt(e,t){let n=e[t];if(n.length>1){let e=n[1],t=n.slice(2);if(e===5&&t.length>=1)return{color:L(t[0]),consumed:0};if(e===2){let e=t.length>=4?t.slice(1,4):t.slice(0,3);if(e.length===3)return{color:[L(e[0]),L(e[1]),L(e[2])],consumed:0}}return{consumed:0}}let r=e[t+1]?.[0];return r===5&&e[t+2]?{color:L(e[t+2]?.[0]??0),consumed:2}:r===2&&e[t+4]?{color:[L(e[t+2]?.[0]??0),L(e[t+3]?.[0]??0),L(e[t+4]?.[0]??0)],consumed:4}:{consumed:0}}function it(e,t){let n={...e},r=(t===``?[`0`]:t.split(`;`)).map(e=>e.split(`:`).map(e=>e===``?0:Number(e)));for(let e=0;e<r.length;e++){let t=r[e]?.[0]??0;if(t===0)for(let e of Object.keys(n))delete n[e];else if(t===1)n.b=!0;else if(t===2)n.f=!0;else if(t===3)n.i=!0;else if(t===4)n.u=!0;else if(t===7)n.inv=!0;else if(t===9)n.s=!0;else if(t===22)delete n.b,delete n.f;else if(t===23)delete n.i;else if(t===24)delete n.u;else if(t===27)delete n.inv;else if(t===29)delete n.s;else if(t>=30&&t<=37)n.fg=t-30;else if(t===39)delete n.fg;else if(t>=40&&t<=47)n.bg=t-40;else if(t===49)delete n.bg;else if(t>=90&&t<=97)n.fg=t-90+8;else if(t>=100&&t<=107)n.bg=t-100+8;else if(t===38||t===48){let{color:i,consumed:a}=rt(r,e);i!==void 0&&(t===38?n.fg=i:n.bg=i),e+=a}}return n}function at(e){return st(e,{}).line}function ot(e){let t={};return e.map(e=>{let n=st(e,t);return t=n.style,n.line})}function st(e,t){let n=[],r=t,i=``,a=0,o=()=>{i&&n.push(nt(i,r)),i=``},s=0;for(;s<e.length;){let t=e[s];if(t===`\x1B`){let n=e[s+1];if(n===`[`){let n=s+2,a=``;for(;n<e.length&&n-(s+2)<32;){let t=e.charCodeAt(n);if(t>=64&&t<=126)break;a+=e[n],n++}if(n>=e.length||n-(s+2)>=32){i+=t,s++;continue}e[n]===`m`&&(o(),r=it(r,a)),s=n+1;continue}if(n===`]`){let t=s+2;for(;t<e.length&&e[t]!==`\x07`&&(e[t]!==`\x1B`||e[t+1]!==`\\`);)t++;s=e[t]===`\x07`?t+1:t+2;continue}s+=n===void 0?1:2,(n===`(`||n===`)`)&&(s+=1);continue}let n=e.charCodeAt(s);if(t===` `){let e=8-a%8;i+=` `.repeat(e),a+=e,s++;continue}if(n<32||n===127){s++;continue}let c=e.codePointAt(s);i+=String.fromCodePoint(c),a+=et(c),s+=c>65535?2:1}return o(),{line:{r:m(g(n))},style:r}}function ct(e){return e.issue!==void 0&&[`needs-consent`,`automation-denied`,`iterm2-denied`,`timed-out`,`too-old`,`failed`,`limited`].includes(e.issue)}const lt={iterm2:`iTerm2`,tmux:`tmux`,herdr:`Herdr`};function ut(e,t,n={}){let r=lt[e.name]??e.name;if(e.connected&&!e.issue)return{status:`Connected. Ready for your paired phone.`};if(t===`phone`)return ct(e)?{status:`${r} needs one more step on your Mac.`,fix:`Open Shellbell → Settings → Terminals on that Mac, or run shellbell doctor there.`}:{status:`${r} isn't connected right now.`};let i=t===`mac-app`?`Click Connect iTerm2.`:`Run shellbell connect iterm2.`;switch(e.issue){case`not-installed`:return{status:n.noneUsable?`Shellbell couldn't find ${r}.`:`Shellbell couldn't find ${r}. Optional.`,...e.name===`tmux`?{fix:`Install tmux 3.2 or newer, for example: brew install tmux`}:{}};case`not-running`:return e.name===`iterm2`?{status:`iTerm2 isn't open. Open it to see its tabs on your phone.`}:{status:`${r} isn't running.`,fix:`In any terminal, run: ${e.name}`};case`no-session`:return{status:`No tmux session is running.`,fix:`In any terminal, run: tmux`};case`api-off`:return{status:`Turn on iTerm2's Python API to connect.`,fix:`In iTerm2, open Settings → General → Magic and turn on Enable Python API.`};case`needs-consent`:return{status:`Ready to connect.`,fix:`${i} macOS will ask to let Shellbell control iTerm2, and iTerm2 may ask to allow Shellbell. Allow both. Your paired phone can then read and type in your iTerm2 tabs.`};case`connecting`:return{status:`Finish connecting in the macOS or iTerm2 dialog.`};case`automation-denied`:return{status:`macOS is blocking Shellbell from iTerm2.`,fix:`Open System Settings → Privacy & Security → Automation, find Shellbell (or node, for the background service) and turn on iTerm2.`};case`iterm2-denied`:return{status:`iTerm2 is blocking Shellbell.`,fix:`In iTerm2, open Settings → General → Magic and check who may use the Python API. Then ${i.charAt(0).toLowerCase()}${i.slice(1)}`};case`timed-out`:return{status:`Connecting wasn't finished.`,fix:`Check for an open macOS or iTerm2 dialog, then try again. ${i}`};case`too-old`:return e.name===`iterm2`?{status:`Update iTerm2 to connect.`,fix:`Shellbell needs iTerm2 3.3 or newer.`}:e.name===`tmux`?{status:`Shellbell needs tmux 3.2 or newer.`,fix:`Update tmux, for example: brew upgrade tmux`}:{status:`Update ${r} to connect.`};case`limited`:return{status:`Viewing and typing work. Opening new sessions from your phone doesn't.`,...e.detail?{fix:e.detail}:{}};default:return{status:`Shellbell couldn't connect to ${r}.`,fix:e.name===`iterm2`?`Try again. ${i}`:`Shellbell keeps trying.`}}}const dt=[`iterm2`,`tmux`,`herdr`];function ft(e){return!e.some(e=>e.connected)&&dt.every(t=>{let n=e.find(e=>e.name===t);return n!==void 0&&!n.connected&&n.issue===`not-installed`})}function pt(e){let t=`Apple's Terminal only lets other apps see plain text and type whole lines, which isn't enough to use a terminal from your phone, so Shellbell can't use it by itself.`;if(e===`phone`)return{status:`Your Mac needs iTerm2, tmux or Herdr.`,fix:`${t} Install one on your Mac. iTerm2 is the easiest.`};let n=`iTerm2 is the easiest: your phone sees every tab and can open new ones. With tmux or Herdr, sessions you run inside them show on your phone, in Terminal too.`;return{status:`Shellbell needs iTerm2, tmux or Herdr on this Mac.`,fix:e===`command-line`?`${t} ${n} For example: brew install --cask iterm2, or brew install tmux`:`${t} ${n}`}}const mt=`\x1B[?1049l\x1B[!p\x1B[20l\x1B[?12l\x1B[?9l\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B]104\x07\x1B]110\x07\x1B]111\x07\x1B]112\x07\x1B[0m\x1B[2J\x1B[H`,ht=new Set([`sh`,`bash`,`zsh`,`fish`,`dash`,`ksh`,`pwsh`,`powershell`,`cmd`]),gt=new Set([`ssh`,`mosh`,`docker`,`podman`,`kubectl`,`wsl`]);function _t(e){return j(e??``).replace(/^-/,``).replace(/\.exe$/i,``)}function vt(e,t,n){let r=_t(t),i=ht.has(r)?r:void 0,a=r===`claude`?`Claude`:r===`codex`?`Codex`:void 0,o=gt.has(r);return{...e,shell:i,agentName:a,locality:o?`guest`:n===`local-process`&&(i||a)?`local`:`unknown`,revision:JSON.stringify([e.sessionId,e.cwd,e.title,e.sessionLabel,r,n])}}function R(e,t){if(e===void 0)return;let n=e.replace(/[\r\n\t\u2028\u2029]+/gu,` `).replace(/[\p{Cc}\p{Cs}\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/gu,``).replace(/\s+/gu,` `).trim();if(/(?:^|[\s("'=:])(?:\/|~[\\/]|[a-z]:[\\/])|\\\\|[a-z][a-z0-9+.-]*:\/\/|[^\s@]+@[^\s:]+:/iu.test(n))return;let r=``,i=0;for(let e of n){let n=Buffer.byteLength(e,`utf8`);if(i+n>t)break;i+=n,r+=e}return r||void 0}function yt(e,t){return[...[`Desktop`,`Documents`,`Downloads`].map(e=>P(t,e)),P(t,`Library`,`Mobile Documents`),P(t,`Library`,`CloudStorage`),`/Volumes`].some(t=>{let n=Fe(t,e);return n===``||!n.startsWith(`..${Le}`)&&n!==`..`&&!N(n)})}function bt(e={}){let t=e.now??Date.now,n=e.platform??process.platform,r=e.home??A(),i=new Map,a=0,o=new Set;async function s(e){if(e.aborted||o.size>=32)throw Error(`git context unavailable`);if(a>=2?await new Promise((t,n)=>{let r=()=>{o.delete(i),n(Error(`git context unavailable`))},i=()=>{o.delete(i),e.removeEventListener(`abort`,r),a+=1,t()};o.add(i),e.addEventListener(`abort`,r,{once:!0})}):a+=1,e.aborted)throw--a,o.values().next().value?.(),Error(`git context unavailable`);return()=>{--a,o.values().next().value?.()}}let c={NODE_ENV:`production`,PATH:process.env.PATH,SystemRoot:process.env.SystemRoot,GIT_CONFIG_NOSYSTEM:`1`,GIT_CONFIG_GLOBAL:process.platform===`win32`?`NUL`:`/dev/null`,GIT_CONFIG_COUNT:`0`,GIT_TERMINAL_PROMPT:`0`,GIT_OPTIONAL_LOCKS:`0`,GIT_NO_REPLACE_OBJECTS:`1`},l=(e,t,n)=>new Promise((r,i)=>{pe(`git`,[`-c`,`core.fsmonitor=false`,`-C`,e,...t],{env:c,encoding:`utf8`,signal:n,timeout:250,killSignal:`SIGKILL`,maxBuffer:8192,windowsHide:!0},(e,t)=>e?i(e):r(t.trim()))});return async(e,a)=>{if(!N(e)||e.length>1024||a.aborted||n===`darwin`&&yt(e,r))return;let o=t();for(let[e,t]of i)(o<t.observedAt||o-t.observedAt>=5e3)&&i.delete(e);let c=i.get(e);if(c)return c;let u=new AbortController,d=()=>u.abort();a.addEventListener(`abort`,d,{once:!0});let f=setTimeout(d,250),p;try{p=await s(u.signal);let t=await l(e,[`rev-parse`,`--show-toplevel`],u.signal),n;try{n=await l(e,[`symbolic-ref`,`--quiet`,`--short`,`HEAD`],u.signal)}catch(e){!u.signal.aborted&&e.code===1&&(n=`detached HEAD`)}if(u.signal.aborted)return;let r=R(j(t),256);if(!r)return;let a={repository:r,branch:R(n,256),observedAt:o};return i.size>=500&&i.delete(i.keys().next().value),i.set(e,a),a}catch{return}finally{clearTimeout(f),a.removeEventListener(`abort`,d),p?.()}}}async function xt(e,t){let n=t.now(),r=new AbortController,i,a=new Promise(e=>{i=setTimeout(()=>{r.abort(),e(void 0)},250)}),o=async()=>{if(!await Promise.race([Promise.resolve().then(()=>t.stillCurrent(e)),a]))throw Error(`stale notification context`)};try{await o();let i;e.locality===`local`&&e.cwd&&N(e.cwd)&&(i=await Promise.race([Promise.resolve().then(()=>t.git(e.cwd,r.signal)).catch(()=>void 0),a]));let s=t.stillCurrent(e);if(typeof s==`boolean`?!s:!await Promise.race([s,a]))throw Error(`stale notification context`);let c={computerName:R(t.computerName,128)??`Computer`,sessionLabel:R(e.sessionLabel,128)??`Session`,observedAt:Math.min(n,i?.observedAt??n)};for(let[t,n]of[[`customName`,256],[`title`,256],[`shell`,64],[`agentName`,64]]){let r=R(e[t],n);r&&(c[t]=r)}let l=R(i?.repository,256),u=R(i?.branch,256);if(l&&(c.repository=l),l&&u&&(c.branch=u),!l&&e.locality===`local`&&e.cwd&&N(e.cwd)){let t=R(e.cwd===A()?`~`:j(e.cwd),256);t&&(c.title=t)}return c}finally{clearTimeout(i),r.abort()}}function St(e,t){return e===t||!!e&&!!t&&e.agent===t.agent&&e.kind===t.kind&&e.value===t.value}const Ct={claude:[`claude`,`claude-code`,`claude code`],codex:[`codex`,`codex-cli`,`codex cli`],agy:[`agy`,`antigravity`,`antigravity-cli`],gemini:[`gemini`,`gemini-cli`],cursor:[`cursor`,`cursor-agent`],copilot:[`copilot`,`github-copilot`,`ghcs`],opencode:[`opencode`,`opencode2`,`open-code`],pi:[`pi`],omp:[`omp`],devin:[`devin`,`devin-cli`,`devin cli`],cline:[`cline`,`.cline`],mastracode:[`mastracode`,`mastra-code`,`mastra code`],kimi:[`kimi`,`kimi-code`,`kimi code`],kiro:[`kiro`,`kiro-cli`],droid:[`droid`],amp:[`amp`,`amp-local`],grok:[`grok`,`grok-build`],hermes:[`hermes`,`hermes-agent`],kilo:[`kilo`,`kilo-code`,`kilo code`],qodercli:[`qodercli`,`qoderclicn`,`qoder`,`qodercn`],qwen:[`qwen`,`qwen-code`,`qwen code`],letta:[`letta`,`letta-code`,`letta code`],maki:[`maki`],muse:[`muse`,`muse-code`,`muse-cli`]},wt=new Map(Object.entries(Ct).flatMap(([e,t])=>t.map(t=>[t,e])));function Tt(e){let t=(e??``).trim().toLowerCase().split(/[\\/]/).pop().replace(/\.(cmd|exe)$/,``);if(t)return/^muse-bin-\d/.test(t)?`muse`:wt.get(t)}const Et=`\\u2800-\\u28FF\\u25D0-\\u25D3\\u2722\\u2733\\u2736\\u273B\\u273D\\u00B7\\u2022*`,Dt=RegExp(`^[${Et}][${Et}\\uFE0F]*\\s+(?=\\S)`,`u`),Ot=/^[⠀-⣿]/u,kt=/^v?\d+(?:\.\d+)+$/;function At(e){return e.trim().replace(Dt,``)}function jt(e){let t=e?.trim()??``;return Dt.test(t)}function Mt(e){let t=e?.trim().toLowerCase()??``;return Tt(t)??R(t,32)}const Nt=/^\s*(?:Gemini CLI \(.*\)|[\u25C7\u270B\u23F2\u2726] {2}\S.*\(.*\))\s*$/u;function Pt(e,t){let n=_t(e).toLowerCase(),r=Tt(n);if(r)return r;if(n!==``&&n!==`node`&&!kt.test(n))return;if(Nt.test(t??``))return`gemini`;if(!jt(t))return;let i=t?.trim()??``;return Ot.test(i)&&/ \| [^|]+$/.test(i)?`codex`:`claude`}function Ft(e,t=A()){if(!e)return;let n=e=>e.replace(/[\\/]+$/,``);return t&&n(e)===n(t)?`~`:R(n(e).split(/[\\/]/).pop(),128)}const It=new Set([...ht,...Ct.claude,...Ct.codex,...Ct.agy,`node`,`tmux`,`[tmux]`]);function Lt(e,t){let n=e.trim();if(n&&n!==t&&!n.endsWith(`[dead]`)&&!(It.has(n.toLowerCase())||kt.test(n)))return R(n,128)}function Rt(e){let t=_t(e).toLowerCase();return!t||gt.has(t)?!1:ht.has(t)||Tt(t)!==void 0||t===`node`||kt.test(t)}function zt(e,t,n){if(!e)return;let r=At(e.replace(/[\r\n\t]+/g,` `));if(t===`gemini`&&Nt.test(r))return;if(t===`pi`&&/^\s*π\s+-\s+/u.test(r)){r=r.replace(/^\s*π\s+-\s+/u,``);for(let e of[n.folder,n.project])e&&(r===e||r.endsWith(` - ${e}`))&&(r=r.slice(0,r.length-e.length).replace(/\s+-\s*$/,``))}if(n.command){let e=` (${n.command})`;r.endsWith(e)&&(r=r.slice(0,-e.length).trimEnd())}let i=/ \| ([^|]+)$/.exec(r);i&&(t===`codex`||i[1]?.trim()===n.project||i[1]?.trim()===n.folder)&&(r=r.slice(0,i.index).trimEnd());let a=R(r,256);if(!a)return;let o=a.toLowerCase();if(!(o===t.toLowerCase()||Tt(o))&&!(n.ignore??[]).some(e=>e.toLowerCase()===o))return a}function Bt(e,t){return e.project===t.project&&e.agent?.kind===t.agent?.kind&&e.agent?.task===t.agent?.task}function Vt(e,t,n){let r={};return e&&(r.project=e),t&&(r.agent=n?{kind:t,task:n}:{kind:t}),r}function Ht(e){let t=Ft(e.cwd),n=R(e.project,128)??t,r=Pt(e.processName,e.title);if(!r)return Vt(n,void 0);let i=_t(e.processName);return Vt(n,r,zt(e.title,r,{project:n,folder:t,command:i||void 0,ignore:e.ignore}))}function Ut(e,t){let n=Ft(e.foreground_cwd??e.cwd??void 0),r=R(t,128)??n,i=Mt(e.agent||e.display_agent||void 0);return i?Vt(r,i,zt(e.label||e.terminal_title_stripped||e.terminal_title||void 0,i,{project:r,folder:n,ignore:e.display_agent?[e.display_agent]:[]})):Vt(r,void 0)}var Wt=class{git;onChange;now;known=new Map;pending=new Set;constructor(e,t,n=Date.now){this.git=e,this.onChange=t,this.now=n}get size(){return this.known.size}lookup(e){if(!N(e)||e.length>1024)return;let t=this.known.get(e),n=this.now();return(!t||n<t.at||n-t.at>=3e4)&&this.refresh(e,t?.project),t?.project??void 0}refresh(e,t){if(this.pending.has(e)||this.pending.size>=16)return;this.pending.add(e);let n=new AbortController,r;try{r=this.git(e,n.signal)}catch{r=Promise.resolve(void 0)}r.catch(()=>void 0).then(n=>{let r=R(n?.repository,128)??null;for(this.known.delete(e);this.known.size>=256;){let e=this.known.keys().next().value;if(e===void 0)break;this.known.delete(e)}this.known.set(e,{project:r,at:this.now()}),r!==(t??null)&&this.onChange()}).finally(()=>{this.pending.delete(e),n.abort()})}};function Gt(e,t=te){let n=e=>C({type:`sessions`,list:e,complete:!1}).length<=t,r=({agent:e,stateSince:t,activeAt:n,...r})=>e?{...r,agent:{kind:e.kind,...e.reportsState&&{reportsState:!0}}}:r,i=[r,e=>{let{project:t,windowLabel:n,...i}=r(e);return i},e=>{let{project:t,windowLabel:n,cwd:i,title:a,...o}=r(e);return{...o,title:Array.from(a).slice(0,Kt).join(``)}}];if(n(e))return{type:`sessions`,list:e,complete:!0};let a=e;for(let t of i)if(a=e.map(t),n(a))return{type:`sessions`,list:a,complete:!0};let o=0,s=a.length;for(;o<s;){let e=Math.ceil((o+s)/2);n(a.slice(0,e))?o=e:s=e-1}return{type:`sessions`,list:a.slice(0,o),complete:!1}}const Kt=64,qt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,Jt=/^\d{1,12}-\d{1,10}\.rec$/;function Yt(e=ne().dir,t=process.platform){return t===`linux`?`${e}-agents`:e}function Xt(e,t){return P(e,`${t}-sessions`)}function Zt(e,t=ne().dir){return Xt(Yt(t),e)}const Qt=e=>new Map(e.map(e=>[e.slice(0,e.indexOf(`=`)),e.slice(e.indexOf(`=`)+1)]));function $t(e){return!e.startsWith(`/`)||e.length>4096||/[\u0000-\u001f\u007f]/.test(e)||e.split(`/`).some(e=>e===`.`||e===`..`)||e.includes(`//`)?``:e}function en(e,t){let n=t.startsWith(`shellbell-codex-hook 1
|
|
2
|
+
`),r=n?t.indexOf(`
|
|
3
|
+
|
|
4
|
+
`):t.length;if(r<0)return null;let[i,...a]=t.slice(0,r).replace(/\n+$/,``).split(`
|
|
5
|
+
`);if(i!==`shellbell-codex-hook 1`&&i!==`shellbell-agent-hook 2`)return null;let o=Qt(a),s=o.get(`session`);if(n)try{s=JSON.parse(t.slice(r+2))?.session_id}catch{return null}let c=n?`codex`:o.get(`agent`);if(c!==`codex`&&c!==`gemini`)return null;let l=Number(o.get(`time`));if(typeof s!=`string`||!qt.test(s)||!Number.isSafeInteger(l)||!/^\d{1,9}$/.test(o.get(`pid`)??``)||!o.get(`start`)||!o.get(`tty`))return null;let u=o.get(`tmux`)??``;return Object.freeze({name:e,agent:c,transcript:$t(o.get(`transcript`)??``),time:l*1e3,session:s.toLowerCase(),tmuxSocket:u.split(`,`)[0],tmuxPane:o.get(`tmux_pane`)??``,iterm:(o.get(`iterm`)??``).split(`:`).pop().toLowerCase(),herdr:o.get(`herdr_pane`)??``,process:{pid:Number(o.get(`pid`)),start:o.get(`start`),tty:o.get(`tty`)}})}function tn(e,t){return t.tty!==void 0&&e.process.tty!==t.tty?!1:t.tmux?!!e.tmuxPane&&e.tmuxPane===t.tmux.pane&&e.tmuxSocket===t.tmux.socket:t.iterm?!!e.iterm&&e.iterm===t.iterm.toLowerCase():t.herdr?!!e.herdr&&e.herdr===t.herdr:!1}function nn(e){try{return me(`ps`,[`-o`,`lstart=`,`-p`,String(e)],{encoding:`utf8`,timeout:1e3,env:{PATH:`/usr/bin:/bin`,TZ:`UTC`,LC_ALL:`C`}}).trim().replace(/\s+/g,` `)||null}catch{return null}}function rn(e){try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}var an=class{dir;now;startOf;exists;stamp=``;loadedAt=-1/0;records=[];verified=new Map;dead=new Set;retryAt=new Map;constructor(e,t=()=>Date.now(),n=nn,r=rn){this.dir=e,this.now=t,this.startOf=n,this.exists=r}running(e){let{pid:t,start:n}=e.process,r=`${t}:${n}`;if(this.dead.has(r))return!1;if(!this.exists(t))return this.markDead(r),!1;let i=this.verified.get(r);if(i!==void 0&&this.now()-i<6e4)return!0;let a=this.retryAt.get(r);if(a!==void 0&&this.now()<a)return!1;let o=this.startOf(t);return o===null?(this.retryAt.size>256&&this.retryAt.clear(),this.retryAt.set(r,this.now()+1e4),!1):(this.retryAt.delete(r),o===n?(this.verified.size>256&&this.verified.clear(),this.verified.set(r,this.now()),!0):(this.markDead(r),!1))}markDead(e){this.verified.delete(e),this.dead.size>256&&this.dead.clear(),this.dead.add(e)}load(){if(this.now()-this.loadedAt<1e3)return this.records;this.loadedAt=this.now();let e;try{let t=k(this.dir);if(!t.isDirectory()||process.getuid&&t.uid!==process.getuid())return[];e=we(this.dir).filter(e=>Jt.test(e))}catch{return this.records=[],this.records}e.sort((e,t)=>Number(t.split(`-`)[0])-Number(e.split(`-`)[0])||(e<t?1:-1));let t=e.join(`/`);if(t===this.stamp)return this.records;let n=[],r=new Set;for(let[t,i]of e.entries()){let e=P(this.dir,i);try{let a=k(e);if(!a.isFile()||a.size>81920||process.getuid&&a.uid!==process.getuid())continue;let o=en(i,O(e,`utf8`)),s=t>=256||this.now()-a.mtimeMs>2592e6,c=o&&`${o.process.pid}:${o.process.start}`;if(c!==null&&r.has(c)||s&&(!o||!this.exists(o.process.pid))){je(e);continue}c&&r.add(c),o&&n.push(o)}catch{}}return this.stamp=t,this.records=n,n}find(e,t){let n;try{n=this.load()}catch{return null}let r=n.find(n=>tn(n,e)&&(!t||n.process.pid===t.pid&&n.process.start===t.start));return r&&(t||this.running(r))?r:null}};const on=new Map;let sn;function cn(e){e!==sn&&(sn=e,on.clear())}function ln(e){let t=on.get(e)??new an(Zt(e,sn));return on.set(e,t),t}const un={codex:`case "$(ps -o comm= -p "$pid" 2>/dev/null)" in
|
|
6
|
+
codex | */codex) agent=$pid; break ;;
|
|
7
|
+
esac`,gemini:`case "$(ps -o args= -p "$pid" 2>/dev/null)" in
|
|
8
|
+
gemini | "gemini "* | */gemini | */gemini\\ * | */gemini.js | */gemini.js\\ *) agent=$pid; break ;;
|
|
9
|
+
esac`};function dn(e,t){return`#!/bin/sh
|
|
10
|
+
# Installed by Shellbell. Records which terminal pane runs which ${e} session, so your phone
|
|
11
|
+
# can show its full history. Remove it with: shellbell agents remove ${e}
|
|
12
|
+
umask 077
|
|
13
|
+
dir=${`'${t.replaceAll(`'`,`'\\''`)}'`}
|
|
14
|
+
clean() { printf '%s' "$1" | tr -cd 'A-Za-z0-9_.:/%,@=+-' | cut -c1-512; }
|
|
15
|
+
# Only these two values are read from the input; the input itself is never saved.
|
|
16
|
+
input=$(head -c 65536 | tr '\\n' ' ')
|
|
17
|
+
session=$(printf '%s' "$input" | sed -n 's/.*"session_id"[[:space:]]*:[[:space:]]*"\\([0-9A-Fa-f-]\\{36\\}\\)".*/\\1/p')
|
|
18
|
+
transcript=$(printf '%s' "$input" | sed -n 's/.*"transcript_path"[[:space:]]*:[[:space:]]*"\\([^"\\\\]*\\)".*/\\1/p')
|
|
19
|
+
input=
|
|
20
|
+
[ -n "$session" ] || exit 0
|
|
21
|
+
case "$transcript" in /*) ;; *) transcript= ;; esac
|
|
22
|
+
printf '%s' "$transcript" | LC_ALL=C grep -q '[^A-Za-z0-9 _./@+,%=-]' && transcript=
|
|
23
|
+
now=$(date +%s)
|
|
24
|
+
tmp="$dir/.$now-$$.tmp"
|
|
25
|
+
# The agent process that ran this hook and the terminal it runs in. A record counts only while
|
|
26
|
+
# that process runs, and only for an agent with its own terminal: a shared background agent has
|
|
27
|
+
# none, and the pane markers it inherited may name another pane, so it records nothing.
|
|
28
|
+
pid=$PPID
|
|
29
|
+
agent=
|
|
30
|
+
i=0
|
|
31
|
+
while [ "$i" -lt 8 ] && [ "$pid" -gt 1 ] 2>/dev/null; do
|
|
32
|
+
${un[e]}
|
|
33
|
+
pid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ')
|
|
34
|
+
i=$((i + 1))
|
|
35
|
+
done
|
|
36
|
+
[ -n "$agent" ] || exit 0
|
|
37
|
+
tty=$(ps -o tty= -p "$agent" 2>/dev/null | tr -d ' ')
|
|
38
|
+
case "$tty" in '' | '?' | '??') exit 0 ;; esac
|
|
39
|
+
mkdir -p "$dir" 2>/dev/null || exit 0
|
|
40
|
+
{
|
|
41
|
+
echo 'shellbell-agent-hook 2'
|
|
42
|
+
echo "agent=${e}"
|
|
43
|
+
echo "time=$now"
|
|
44
|
+
echo "pid=$agent"
|
|
45
|
+
echo "start=$(TZ=UTC LC_ALL=C ps -o lstart= -p "$agent" 2>/dev/null | tr -s ' ' | sed 's/^ //;s/ $//')"
|
|
46
|
+
echo "tty=$(clean "$tty")"
|
|
47
|
+
echo "tmux=$(clean "\${TMUX:-}")"
|
|
48
|
+
echo "tmux_pane=$(clean "\${TMUX_PANE:-}")"
|
|
49
|
+
echo "iterm=$(clean "\${ITERM_SESSION_ID:-}")"
|
|
50
|
+
echo "herdr_pane=$(clean "\${HERDR_PANE_ID:-}")"
|
|
51
|
+
echo "session=$session"
|
|
52
|
+
echo "transcript=$transcript"
|
|
53
|
+
} >"$tmp" 2>/dev/null && mv -f "$tmp" "$dir/$now-$$.rec" 2>/dev/null
|
|
54
|
+
rm -f "$tmp" 2>/dev/null
|
|
55
|
+
exit 0
|
|
56
|
+
`}function fn(e,t=A(),n=Yt(e)){return{codexHome:process.env.CODEX_HOME||P(t,`.codex`),stateDir:e,helperDir:n}}const pn=e=>P(e.helperDir,`codex-session-hook.sh`),mn=e=>P(e.codexHome,`hooks.json`),z=e=>P(e.codexHome,`config.toml`),hn=e=>`sh '${pn(e).replaceAll(`'`,`'\\''`)}'`;function gn(e){if(!D(mn(e)))return{};let t=JSON.parse(O(mn(e),`utf8`));if(typeof t!=`object`||!t||Array.isArray(t))throw Error(`${mn(e)} isn't a JSON object; Shellbell left it unchanged.`);return t}function B(e,t,n=384){xe(M(e),{recursive:!0});let r=D(e)?Ee(e):e,i=D(r)?k(r).mode&511:n,a=`${r}.shellbell-${process.pid}.tmp`;try{Me(a,t,{mode:i}),De(a,r)}finally{Oe(a,{force:!0})}}const _n=e=>t=>t.hooks?.some(t=>t.command===hn(e))===!0;function vn(e){let t=/^\[\s*(["']?)([^\]"']+)\1\s*\]\s*(?:#.*)?$/.exec(e.trim());return t?t[2].trim():null}function yn(e){if(!D(z(e)))return`unset`;let t=``;for(let n of O(z(e),`utf8`).split(`
|
|
57
|
+
`)){let e=n.trim(),r=vn(e);if(r!==null){if(r.startsWith(`features.`))return`unknown`;t=r;continue}let i=/^["']?hooks["']?\s*=\s*(true|false)\b/.exec(e)?.[1];if(t===`features`&&i)return i===`true`?`on`:`off`;let a=/^["']?features["']?\s*\.\s*["']?hooks["']?\s*=\s*(true|false)\b/.exec(e)?.[1];if(t===``&&a)return a===`true`?`on`:`off`;if(/^\[/.test(e)?/features/.test(e)&&r===null:t===``&&/^["']?features["']?\s*=/.test(e))return`unknown`}return`unset`}function bn(e){return{installed:(gn(e).hooks?.SessionStart??[]).some(_n(e))&&D(pn(e)),hooksFeature:yn(e)}}function xn(e){let t=yn(e);if(t===`off`)throw Error(`Codex hooks are turned off in ${z(e)} (hooks = false). Turn them on, then run this again.`);if(t===`unknown`)throw Error(`${z(e)} sets features in a form Shellbell won't edit. Add hooks = true to Codex's features, then run this again.`);let n=gn(e);B(pn(e),dn(`codex`,Xt(e.helperDir,`codex`)),448),_e(pn(e),448);let r=n.hooks?.SessionStart??[];if(!r.some(_n(e))){let t={...n,hooks:{...n.hooks,SessionStart:[...r,{hooks:[{type:`command`,command:hn(e),timeout:10}]}]}};B(mn(e),`${JSON.stringify(t,null,2)}\n`)}if(t===`unset`){let t=D(z(e))?O(z(e),`utf8`):``,n=t.split(`
|
|
58
|
+
`),r=n.findIndex(e=>vn(e)===`features`);r>=0?n.splice(r+1,0,`hooks = true`):n.push(...t&&!t.endsWith(`
|
|
59
|
+
`)?[``]:[],`[features]`,`hooks = true`,``),B(z(e),n.join(`
|
|
60
|
+
`))}return bn(e)}function Sn(e){let t=gn(e),n=t.hooks?.SessionStart;if(n?.some(_n(e))){let r=n.filter(t=>!_n(e)(t)),i={...t.hooks};r.length?i.SessionStart=r:delete i.SessionStart,B(mn(e),`${JSON.stringify({...t,hooks:i},null,2)}\n`)}return Oe(pn(e),{force:!0}),Oe(Xt(e.helperDir,`codex`),{recursive:!0,force:!0}),bn(e)}const Cn=[`SessionStart`,`BeforeAgent`];function wn(e,t=A(),n=Yt(e)){return{settings:P(process.env.GEMINI_CLI_HOME||t,`.gemini`,`settings.json`),stateDir:e,helperDir:n}}const Tn=e=>P(e.helperDir,`gemini-session-hook.sh`),En=e=>`sh '${Tn(e).replaceAll(`'`,`'\\''`)}'`;function Dn(e){if(!D(e.settings))return{};let t;try{t=JSON.parse(O(e.settings,`utf8`))}catch{return null}if(typeof t!=`object`||!t||Array.isArray(t))return null;let n=t,r=n.hooks;if(r!==void 0&&(typeof r!=`object`||!r||Array.isArray(r)))return null;for(let e of Cn){let t=n.hooks?.[e];if(t!==void 0&&!Array.isArray(t))return null}return n}const On=e=>t=>t?.hooks?.some(t=>t?.name===`shellbell-session`&&t.command===En(e))===!0;function kn(e){let t=Dn(e);if(!t)return{installed:!1,hooks:`unknown`};let n=Cn.every(n=>(t.hooks?.[n]??[]).some(On(e)))&&D(Tn(e)),r=t.hooksConfig?.disabled;return{installed:n,hooks:t.hooksConfig?.enabled===!1||Array.isArray(r)&&r.includes(`shellbell-session`)?`off`:`on`}}function An(e){let t=D(e.settings)?O(e.settings,`utf8`):null,n=Dn(e);if(!n)throw Error(`${e.settings} has comments or settings Shellbell won't rewrite. Remove the comments, then run shellbell agents setup gemini.`);if(kn(e).hooks===`off`)throw Error(`Gemini hooks are turned off in ${e.settings}; Shellbell leaves them off.`);B(Tn(e),dn(`gemini`,Xt(e.helperDir,`gemini`)),448),_e(Tn(e),448);let r={...n.hooks};for(let t of Cn){let n=r[t]??[];n.some(On(e))||(r[t]=[...n,{hooks:[{type:`command`,name:`shellbell-session`,command:En(e),timeout:5e3}]}])}if((D(e.settings)?O(e.settings,`utf8`):null)!==t)throw Error(`${e.settings} changed while Shellbell was editing it. Try again.`);return B(e.settings,`${JSON.stringify({...n,hooks:r},null,2)}\n`),kn(e)}function jn(e){let t=Dn(e);if(t?.hooks&&Cn.some(n=>t.hooks?.[n]?.some(On(e)))){let n={...t.hooks};for(let t of Cn){let r=(n[t]??[]).filter(t=>!On(e)(t));r.length?n[t]=r:delete n[t]}let{hooks:r,...i}=t,a=Object.keys(n).length?{...i,hooks:n}:i;B(e.settings,`${JSON.stringify(a,null,2)}\n`)}return Oe(Tn(e),{force:!0}),Oe(Xt(e.helperDir,`gemini`),{recursive:!0,force:!0}),kn(e)}function Mn(e,t=A(),n=process.platform){let r=Yt(e,n);return{stateDir:e,helperDir:r,home:t,codex:fn(e,t,r),gemini:wn(e,t,r),claudeDir:process.env.CLAUDE_CONFIG_DIR||P(t,`.claude`)}}const Nn=[[`cursor`,`Cursor`,`.cursor/cli-config.json`],[`copilot`,`Copilot`,`.copilot`],[`opencode`,`OpenCode`,`.config/opencode`],[`pi`,`Pi`,`.pi/agent`],[`omp`,`Oh My Pi`,`.omp/agent`],[`devin`,`Devin`,`.config/devin`],[`droid`,`Droid`,`.factory`],[`kimi`,`Kimi`,`.kimi-code`],[`kilo`,`Kilo Code`,`.config/kilo`],[`hermes`,`Hermes`,`.hermes`],[`qodercli`,`Qoder`,`.qoder`],[`qwen`,`Qwen`,`.qwen`],[`mastracode`,`Mastra Code`,`.mastracode`],[`grok`,`Grok`,`.grok`],[`letta`,`Letta`,`.letta`]],Pn=e=>P(e.helperDir,`agent-setup.json`);function Fn(e){try{let t=JSON.parse(O(Pn(e),`utf8`))?.skipped;return new Set(Array.isArray(t)?t.filter(e=>typeof e==`string`):[])}catch{return new Set}}function In(e){xe(e.helperDir,{recursive:!0,mode:448});try{d(e.helperDir,process.getuid?.()??-1)}catch{throw Error(`${e.helperDir} isn't a private folder of yours, so Shellbell won't put agent helpers there.`)}}function Ln(e,t){if(!t.size){Oe(Pn(e),{force:!0});return}In(e);let n=`${Pn(e)}.${process.pid}.tmp`;Me(n,`${JSON.stringify({v:1,skipped:[...t].sort()})}\n`,{mode:384}),De(n,Pn(e))}function Rn(e,t){let n={kind:`codex`,name:`Codex`,skipped:t};try{let t=bn(e.codex);return t.installed?t.hooksFeature===`off`?{...n,state:`hooks-off`,helper:!0}:{...n,state:`ready`,helper:!0}:t.hooksFeature===`off`?{...n,state:`hooks-off`,helper:!1}:t.hooksFeature===`unknown`?{...n,state:`blocked`,helper:!1,detail:`Add hooks = true to the [features] section of ${P(e.codex.codexHome,`config.toml`)}.`}:{...n,state:`needs-setup`,helper:!1}}catch(e){return{...n,state:`blocked`,helper:!1,detail:e instanceof Error?e.message:String(e)}}}function zn(e,t){let n={kind:`gemini`,name:`Gemini`,skipped:t},r=kn(e.gemini);return r.hooks===`unknown`?{...n,state:`blocked`,helper:!1,detail:`${e.gemini.settings} has comments or settings Shellbell won't rewrite. Remove the comments, then run shellbell agents setup gemini.`}:r.hooks===`off`?{...n,state:`hooks-off`,helper:r.installed}:{...n,state:r.installed?`ready`:`needs-setup`,helper:r.installed}}function Bn(e){let t=Fn(e),n=[],r={helper:!1,skipped:!1};D(e.claudeDir)&&n.push({kind:`claude`,name:`Claude Code`,state:`ready`,...r}),D(e.codex.codexHome)&&n.push(Rn(e,t.has(`codex`))),D(P(e.home,`.gemini`,`antigravity-cli`))&&n.push({kind:`agy`,name:`Antigravity`,state:`ready`,...r}),D(P(e.gemini.settings,`..`,`tmp`))&&n.push(zn(e,t.has(`gemini`)));for(let[t,i,a]of Nn)D(P(e.home,a))&&n.push({kind:t,name:i,state:`coming-soon`,...r});return n}function Vn(e){return e.filter(e=>e.state===`needs-setup`&&!e.skipped)}function Hn(e,t){let n=e=>!t||t.includes(e);In(e);let r=Fn(e);for(let t of Bn(e))n(t.kind)&&(r.delete(t.kind),t.state===`needs-setup`&&(t.kind===`codex`&&xn(e.codex),t.kind===`gemini`&&An(e.gemini)));return Ln(e,r),Bn(e)}function Un(e,t){let n=Fn(e);for(let e of t)n.add(e);return Ln(e,n),Bn(e)}function Wn(e,t){return In(e),t===`codex`&&Sn(e.codex),t===`gemini`&&jn(e.gemini),Un(e,[t])}function Gn(e){try{d(e.helperDir,process.getuid?.()??-1)}catch{return}for(let t of[`codex`,`gemini`]){let n=P(e.helperDir,`${t}-session-hook.sh`);try{let r=dn(t,Xt(e.helperDir,t));if(D(n)&&O(n,`utf8`)!==r){let e=`${n}.${process.pid}.tmp`;Me(e,r,{mode:448}),De(e,n)}}catch{}}}function Kn(e){switch(e.state){case`ready`:return e.kind===`codex`?`Ready. Codex sessions started from now on show their full history. If Codex asks, trust Shellbell's helper.`:e.kind===`gemini`?`Ready. Gemini sessions started from now on show their full history.`:`Ready.`;case`needs-setup`:return`Needs a small helper for full history on your phone.`;case`hooks-off`:return e.kind===`gemini`?`Gemini hooks are turned off (in Gemini's settings.json or its /hooks list), so its sessions open as a terminal.`:`Codex hooks are turned off (hooks = false in Codex's config.toml), so its sessions open as a terminal.`;case`blocked`:return e.detail??`Shellbell couldn't change this agent's settings.`;case`coming-soon`:return`Full history coming soon. Opens as a terminal for now.`}}const qn=We(pe),Jn={iTerm:`iTerm2`},Yn=/\/([^/]+)\.app\/Contents\/MacOS\//;function Xn(e){let t=new Map;for(let n of e.split(`
|
|
61
|
+
`)){let e=/^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(n);e&&t.set(Number(e[1]),{ppid:Number(e[2]),args:e[3]})}return t}async function Zn(){if(process.platform===`darwin`)try{let{stdout:e}=await qn(`/bin/ps`,[`-axww`,`-o`,`pid=,ppid=,args=`],{timeout:2e3,maxBuffer:8388608});return Xn(e)}catch{return}}function Qn(e,t){let n=t.get(e)?.ppid;for(let e=0;n!==void 0&&n>1&&e<32;e++){let e=t.get(n);if(!e)return;let r=Yn.exec(e.args)?.[1];if(r)return Jn[r]??r;n=e.ppid}}const $n=[0,7,2],er=`Install Herdr: curl -fsSL https://herdr.dev/install.sh | sh, then start it with "herdr".`,tr=`Upgrade Herdr to 0.7.2 or newer: curl -fsSL https://herdr.dev/install.sh | sh, then restart it.`;var V=class extends Error{code;constructor(e,t){super(`herdr ${e}: ${t}`),this.code=e,this.name=`HerdrError`}};const nr=new Set([`not_found`,`pane_not_found`,`stale_pane_target`]),rr=new Set([`invalid_request`,`unsupported`,`unknown_method`,`method_not_found`]);function ir(e,t){let n=/^\s*v?(\d+)\.(\d+)\.(\d+)/.exec(e);if(!n)return null;let r=[Number(n[1]),Number(n[2]),Number(n[3])];for(let e=0;e<3;e++){let n=r[e],i=t[e];if(n!==i)return n>i}return!0}function ar(e=process.env,t=A()){let n=e.HERDR_SOCKET_PATH;if(n)return n;let r=e.XDG_CONFIG_HOME?P(e.XDG_CONFIG_HOME,`herdr`):P(t,`.config`,`herdr`),i=e.HERDR_SESSION;return i?P(r,`sessions`,i,`herdr.sock`):P(r,`herdr.sock`)}function or(e,t,n){let r=e.code??``;return r===`ENOENT`||r===`ECONNREFUSED`||r===`EACCES`||r===`EPERM`?new V(`unavailable`,`cannot reach the herdr socket at ${n} (${r})`):new V(`socket`,`${t}: ${e.message}`)}function sr(e,t,n,r=1048576){let i=new Ge(`utf8`),a=``;e.on(`data`,e=>{a+=i.write(e);let o=a.indexOf(`
|
|
62
|
+
`);for(;o>=0;){let e=a.slice(0,o);a=a.slice(o+1),e.trim()&&t(e),o=a.indexOf(`
|
|
63
|
+
`)}Buffer.byteLength(a,`utf8`)>r&&(a=``,n())})}var cr=class{opts;log;nextId=1;constructor(e){this.opts=e,this.log=e.log.child({unit:`herdr`})}get socketPath(){return this.opts.socketPath??ar()}request(e,t={},n={}){let r=n.signal;if(r?.aborted)return Promise.reject(new V(`cancelled`,`request cancelled`));let i=`sb${this.nextId++}`,a=this.opts.requestTimeoutMs??5e3,o=this.socketPath;return new Promise((n,s)=>{let c=!1,l=Ve({path:o}),u=(e,t)=>{c||(c=!0,clearTimeout(d),r?.removeEventListener(`abort`,f),l.destroy(),e?s(e):n(t))},d=setTimeout(()=>u(new V(`timeout`,`${e} did not answer within ${a} ms`)),a),f=()=>u(new V(`cancelled`,`request cancelled`));r?.addEventListener(`abort`,f,{once:!0}),l.on(`connect`,()=>{c||l.write(`${JSON.stringify({id:i,method:e,params:t})}\n`)}),sr(l,t=>{let n;try{n=JSON.parse(t)}catch{u(new V(`malformed`,`${e} answered with a non-JSON line`));return}if(n.id!==void 0&&n.id!==i&&this.log.debug(`herdr echoed a different id`,{method:e}),n.error){u(new V(n.error.code||`error`,n.error.message||e));return}if(n.result===void 0||n.result===null){u(new V(`malformed`,`${e} answered without a result`));return}u(null,n.result)},()=>u(new V(`overflow`,`${e} answered with an oversized line`)),8388608),l.on(`error`,t=>u(or(t,e,o))),l.on(`close`,()=>u(new V(`closed`,`herdr closed the connection before answering ${e}`))),r?.aborted&&f()})}subscribe(e,t){let n=`sb${this.nextId++}`,r=this.opts.requestTimeoutMs??5e3,i=this.socketPath;return new Promise((a,o)=>{let s=Ve({path:i}),c=!1,l=!1,u=!1,d={close(){u=!0,s.destroy()}},f=e=>{c||(clearTimeout(m),s.destroy(),o(e))},p=e=>{l||(l=!0,t.onEnd(u?`closed`:e))},m=setTimeout(()=>f(new V(`timeout`,`events.subscribe was not acknowledged`)),r);s.on(`connect`,()=>{s.write(`${JSON.stringify({id:n,method:`events.subscribe`,params:{subscriptions:e}})}\n`)}),sr(s,e=>{let n;try{n=JSON.parse(e)}catch{this.log.warn(`undecodable herdr stream line`,{chars:e.length});return}if(!c){if(n.error){f(new V(n.error.code||`error`,n.error.message||`events.subscribe`));return}let e=n.result?.type;if(e!==`subscription_started`){f(new V(`malformed`,`events.subscribe answered ${e}`));return}c=!0,clearTimeout(m),a(d);return}if(typeof n.event==`string`){let e=n.data&&typeof n.data==`object`?n.data:{};t.onEvent({event:n.event,data:e})}},()=>{c?(s.destroy(),p(`overflow`)):f(new V(`overflow`,`events.subscribe line too long`))}),s.on(`error`,e=>{c?p(`error`):f(or(e,`events.subscribe`,i))}),s.on(`close`,()=>{if(!c){f(new V(`closed`,`herdr closed the connection before acknowledging the stream`));return}p(`eof`)})})}async ping(){let e;try{e=await this.request(`ping`,{})}catch(e){let t=e instanceof Error?e.message:String(e);throw new f(t,er)}let t=typeof e.version==`string`?e.version:``,n=ir(t,$n);if(n===!1)throw new f(`herdr ${t} is older than 0.7.2 (session.snapshot and scroll metrics landed there)`,tr);return n===null&&this.log.warn(`herdr reported an unparseable version; relying on the feature probe`),this.log.debug(`herdr ping ok`,{version:/^\d{1,4}\.\d{1,4}\.\d{1,4}$/.test(t)?t:`unknown`,protocol:typeof e.protocol==`number`&&Number.isSafeInteger(e.protocol)&&e.protocol>=0?e.protocol:`unknown`}),e}};const lr=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,ur=/^[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏] /,dr=/^\[ [!.] \] Action Required \| /;function fr(e){let t=e.trim();if(t.startsWith(`● `))t=t.slice(2);else if(t===`●`)return null;t=t.replace(ur,``).replace(dr,``);let n=t.lastIndexOf(` | `);if(n<=0)return null;let r=t.slice(0,n),i=t.slice(n+3);return i&&!i.includes(` | `)?{name:r,project:i}:null}const pr=new Intl.Segmenter(void 0,{granularity:`grapheme`});function mr(e,t){let n=[...pr.segment(e)].map(e=>e.segment);return n.length<=t?e:`${n.slice(0,t-3).join(``)}...`}function hr(e,t){let n=new Set([mr(j(e),24)]);for(let r=e;r!==M(r);r=M(r))t(P(r,`.git`))&&n.add(mr(j(r),24));return n}function gr(e){let t=Se(e,`r`);try{let e=[],n=0;for(;n<1048576;){let r=Buffer.alloc(65536),i=Ce(t,r,0,r.length,n);if(i===0)break;let a=r.subarray(0,i).indexOf(10);if(e.push(r.subarray(0,a<0?i:a)),n+=i,a>=0)return Buffer.concat(e).toString(`utf8`)}return null}finally{ve(t)}}function _r(e){let t=new Date(e),n=e=>String(e).padStart(2,`0`);return P(String(t.getFullYear()),n(t.getMonth()+1),n(t.getDate()))}var vr=class{home;stamp=``;names=new Map;folders=new Map;now;exists;constructor(e,t={}){this.home=e,this.now=t.now??Date.now,this.exists=t.exists??D}find(e,t){let n=e?fr(e):null;if(!n)return null;try{let e=this.load();if(!e)return null;let r=null;for(let[i,a]of e){if(mr(a,48)!==n.name)continue;let e=this.folder(i);if(!e)return null;if((t===void 0||e===t)&&hr(e,this.exists).has(n.project)){if(r)return null;r=i}}return r}catch{return null}}load(){let e=P(this.home,`session_index.jsonl`),t,n;try{let r=k(e);if(!r.isFile()||process.getuid&&r.uid!==process.getuid()||r.size>4194304)return null;if(t=r.size,n=`${r.mtimeMs}:${t}`,n===this.stamp)return this.names}catch{return this.stamp=``,null}let r=Se(e,`r`),i;try{let e=Buffer.alloc(t);i=e.subarray(0,Ce(r,e,0,t,0)).toString(`utf8`)}finally{ve(r)}let a=i.split(`
|
|
64
|
+
`),o=new Map;for(let e of a)if(e.trim())try{let t=JSON.parse(e);if(typeof t.id!=`string`||!lr.test(t.id))continue;let n=t.id.toLowerCase();o.delete(n),typeof t.thread_name==`string`&&t.thread_name.trim()&&o.set(n,t.thread_name)}catch{}return this.names=o,this.stamp=n,o}folder(e){let t=this.folders.get(e);if(t&&(t.cwd!==null||this.now()-t.at<1e4))return t.cwd;let n=this.readFolder(e);return this.folders.size>=1024&&this.folders.clear(),this.folders.set(e,{cwd:n,at:this.now()}),n}readFolder(e){if(e[14]!==`7`)return null;let t=Number.parseInt(e.slice(0,8)+e.slice(9,13),16),n=P(this.home,`sessions`);for(let r of[0,-1,1]){let i=P(n,_r(t+r*24*60*60*1e3)),a;try{a=we(i)}catch{continue}let o=a.find(t=>t.startsWith(`rollout-`)&&t.endsWith(`-${e}.jsonl`));if(!o)continue;let s=gr(P(i,o));if(!s)return null;let c=JSON.parse(s),l=c.payload?.cwd;return c.type!==`session_meta`||c.payload?.id!==e?null:typeof l==`string`&&N(l)?l:null}return null}};let yr;function br(){return yr??=new vr(process.env.CODEX_HOME||P(A(),`.codex`)),yr}function xr(e){if(typeof e!=`object`||!e||Array.isArray(e))return null;let t=e,n=t.agent===`agy`?`herdr:antigravity_cli`:`herdr:${t.agent}`;return t.agent!==`claude`&&t.agent!==`codex`&&t.agent!==`agy`||t.source!==n||typeof t.value!=`string`||t.agent===`agy`&&t.kind!==`id`?null:t.kind===`id`&&/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,255}$/.test(t.value)?Object.freeze({agent:t.agent,kind:`id`,value:t.value}):t.kind===`path`&&t.value.length<=4096&&N(t.value)&&Pe(t.value)===t.value&&t.value.endsWith(`.jsonl`)&&!Array.from(t.value).some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)>=127&&e.charCodeAt(0)<=159||e.length===1&&e.charCodeAt(0)>=55296&&e.charCodeAt(0)<=57343)?Object.freeze({agent:t.agent,kind:`path`,value:t.value}):null}function Sr(e,t,n){let r=xr(e?.agent_session),i=e?.agent;if(r||i!==`codex`&&i!==`gemini`||typeof e?.pane_id!=`string`)return r;let a=(t??ln(i)).find({herdr:e.pane_id});if(a)return Object.freeze({agent:i,kind:`id`,value:a.session});if(i!==`codex`||typeof e.terminal_title!=`string`)return null;let o=e.foreground_cwd??e.cwd,s=(n??br()).find(e.terminal_title,typeof o==`string`?o:void 0);return s?Object.freeze({agent:i,kind:`id`,value:s}):null}function Cr(e){if(e===``)return[];let t=e.split(`
|
|
65
|
+
`);return t.length>1&&t[t.length-1]===``&&t.pop(),t.map(at)}function wr(e,t){if(e.length>t)return e.slice(e.length-t);let n=e.slice();for(;n.length<t;)n.push(s());return n}function Tr(e){return e.r.reduce((e,t)=>e+(t.n??tt(t.t)),0)}function Er(e,t){let n=Math.max(0,t-1);for(let t=e.length-1;t>=0;t--){let r=e[t];if(r.r.some(e=>e.t.trim().length>0))return{x:Math.min(n,Tr(r)),y:t}}return{x:0,y:0}}function Dr(e){let t=Math.max(1,e.rows),n=Math.max(1,e.cols),r=wr(Cr(e.text),t);return{cols:n,rows:t,cursor:Er(r,n),lines:r,scrollbackTotal:Math.max(0,e.scrollMax)}}function Or(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function kr(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function Ar(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>0}function jr(e,t,n){if(!Or(e)||e.type!==`pane_info`||!Or(e.pane))return null;let r=e.pane;if(typeof r.pane_id!=`string`||r.pane_id.length===0||r.pane_id!==t||typeof r.terminal_id!=`string`||r.terminal_id.length===0||r.terminal_id!==n||!kr(r.revision)||!Or(r.scroll))return null;let i=r.scroll;return!kr(i.offset_from_bottom)||!kr(i.max_offset_from_bottom)||!Ar(i.viewport_rows)||i.offset_from_bottom>i.max_offset_from_bottom||i.max_offset_from_bottom>2**53-1-i.viewport_rows?null:{paneId:r.pane_id,terminalId:r.terminal_id,revision:r.revision,history:i.max_offset_from_bottom,viewportRows:i.viewport_rows,offset:i.offset_from_bottom}}function Mr(e,t){if(!Ar(t.rows)||!Ar(t.cols)||t.minRows!==void 0&&(!kr(t.minRows)||t.minRows>t.rows)||typeof t.paneId!=`string`||t.paneId.length===0||t.source!==`visible`&&t.source!==`recent`||!Or(e)||e.type!==`pane_read`||!Or(e.read))return null;let n=e.read;if(typeof n.pane_id!=`string`||n.pane_id.length===0||n.pane_id!==t.paneId||n.source!==t.source||n.format!==`ansi`||typeof n.text!=`string`||typeof n.truncated!=`boolean`)return null;let r=Cr(n.text);return r.length<(t.minRows??t.rows)||r.length>t.rows||r.some(e=>Tr(e)>t.cols)?null:r}function Nr(e,t){let{visible:n,historyRows:r,viewportRows:i,requestedRows:a}=t;if(n.length===0||n.length>i)return null;let o=i-n.length,s=Mr(e,{paneId:t.paneId,source:`recent`,cols:t.cols,rows:a,minRows:Math.max(n.length,Math.min(a,r+i)-o)});if(!s||!Ue(s.slice(-n.length),n))return null;let c=r+n.length-s.length;return c>=0?{from:c,lines:s}:null}function Pr(e){let[t,...n]=e.trim().split(/\s+/);if(t&&j(t)===`herdr`){if(n.length===0)return``;if(n[0]===`--session`&&n.length===2)return n[1];if(n.length===1&&n[0].startsWith(`--session=`))return n[0].slice(10);if(n[0]===`session`&&n[1]===`attach`&&n.length===3)return n[2]}}function Fr(e,t,n=process.env){let r=new Set;for(let[i,a]of e){let o=Pr(a.args);if(o===void 0||ar({XDG_CONFIG_HOME:n.XDG_CONFIG_HOME,...o?{HERDR_SESSION:o}:{}})!==t)continue;let s=Qn(i,e);s&&r.add(s)}return[...r].sort((e,t)=>e.localeCompare(t)).slice(0,4)}function Ir(e,t){for(let[n,r]of e){let i=r.args.trim().split(/\s+/);if(i.length===4&&j(i[0])===`herdr`&&i[1]===`terminal`&&i[2]===`attach`&&i[3]===t&&Qn(n,e)!==void 0)return!0}return!1}async function Lr(e){let t=await Zn();return t&&Fr(t,e)}const Rr=zr();function zr(){let e={enter:`enter`,tab:`tab`,"shift-tab":`shift+tab`,esc:`esc`,backspace:`backspace`,up:`up`,down:`down`,left:`left`,right:`right`};for(let t of Object.keys(_))/^ctrl-[a-z]$/.test(t)?e[t]=`ctrl+${t.slice(5)}`:/^f([1-9]|1[0-2])$/.test(t)&&(e[t]=t);return e}const Br=Vr();function Vr(){let e=new Map([[`\r`,`enter`],[`
|
|
66
|
+
`,`enter`],[` `,`tab`]]);for(let[t,n]of Object.entries(_)){let r=Rr[t];r&&!e.has(n)&&e.set(n,r)}return e}function Hr(e){return Br.get(e)}const Ur=[`.local/bin`,`.cargo/bin`];function Wr(e,t=process.env,n=e=>{try{return ge(e,E.X_OK),k(e).isFile()}catch{return!1}}){let r=t.HOME||A(),i=N(r)?Ur.map(e=>P(r,e)):[];return[...t.PATH?.split(Ne)??[],...i].map(t=>Ie(t,e)).find(n)}const Gr=We(pe);function Kr(e=process.env,t){return Wr(`herdr`,e,t)}async function qr(e={}){let t=e.platform??process.platform,n;try{if(t===`darwin`)n=await Yr(e);else if(t===`linux`)n=Xr(e);else return}catch{return}let r=[...new Set(n)],i=e.executable??Zr;return r.length===1&&N(r[0])&&i(r[0])?r[0]:void 0}function Jr(e){return e.length===2&&j(e[0])===`herdr`&&e[1]===`server`}async function Yr(e){let t=e.ps??(async e=>(await Gr(`/bin/ps`,e,{timeout:2e3,maxBuffer:8388608})).stdout),n=(await t([`-x`,`-ww`,`-o`,`pid=,args=`])).split(`
|
|
67
|
+
`).flatMap(e=>{let t=/^\s*(\d+)\s+(?:.*\/)?herdr server\s*$/.exec(e);return t?[t[1]]:[]});return n.length===0?[]:(await t([`-ww`,`-o`,`comm=`,`-p`,n.join(`,`)])).split(`
|
|
68
|
+
`).map(e=>e.trim()).filter(e=>j(e)===`herdr`)}function Xr(e){let t=e.procRoot??`/proc`,n=e.uid??process.getuid?.(),r=[];for(let e of we(t))if(/^\d+$/.test(e))try{if(n!==void 0&&k(P(t,e)).uid!==n)continue;let i=O(P(t,e,`cmdline`),`latin1`).split(`\0`);if(i.at(-1)===``&&i.pop(),!Jr(i))continue;let a=Te(P(t,e,`exe`));a.endsWith(` (deleted)`)||r.push(a)}catch{}return r}function Zr(e){try{return ge(e,E.X_OK),k(e).isFile()}catch{return!1}}const Qr=We(pe);var $r=class{opts;executable;issue;env;active=new Map;generation=0;constructor(e){this.opts=e,this.env={...e.env??process.env,HERDR_SOCKET_PATH:e.socketPath}}get available(){return this.executable!==void 0}get verifiedExecutable(){return this.executable===void 0?void 0:Ie(this.executable)}get unavailableReason(){return this.executable===void 0?this.issue:void 0}async configure(e){this.close();let t=this.generation;if(!e||ir(e,[0,9,3])!==!0){this.issue=`Update Herdr to 0.9.3 or newer to open Herdr sessions from your phone${e?` (this computer runs ${e.replace(/^v/,``)})`:``}.`;return}let n=this.opts.executable===void 0&&this.defaultSocket()?await(this.opts.findRunningServer??qr)():void 0;if(t!==this.generation)return;let r=this.opts.executable?[this.opts.executable]:[...new Set([n,Kr(this.env)])].filter(e=>e!==void 0);if(r.length===0){this.issue=`Herdr is running, but Shellbell can't find the herdr program. Install it in ~/.local/bin, /opt/homebrew/bin or /usr/local/bin.`;return}let i=e.replace(/^v/,``),a;for(let e of r){let n;try{let t=this.opts.readVersion?await this.opts.readVersion(e):(await Qr(e,[`--version`],{env:this.env,timeout:3e3,maxBuffer:4096})).stdout;n=/\b(?:herdr\s+)?v?(\d+\.\d+\.\d+(?:-[\w.-]+)?)/.exec(t)?.[1]}catch{if(t!==this.generation)return;a??=`Shellbell couldn't run the herdr program. Reinstall Herdr on this computer.`;continue}if(t!==this.generation)return;if(n===i){this.executable=e;return}a??=n?`The herdr program (${n}) and the running Herdr (${i}) are different versions. Quit Herdr and open it again.`:`Shellbell couldn't read the herdr program's version. Reinstall Herdr on this computer.`}this.issue=a}defaultSocket(){let{HERDR_SOCKET_PATH:e,HERDR_SESSION:t,...n}=this.env;return Ie(this.opts.socketPath)===Ie(ar(n))}close(){this.generation++,this.executable=void 0,this.issue=void 0;for(let e of this.active.values())e();this.active.clear()}async click(e,t,n){let r=this.executable;if(!r||!n()||this.active.has(e)||this.active.size>=4)throw new T(`mouse control unavailable`);if(t.column>=t.cols||t.row>=t.rows)throw new T(`mouse coordinates`);let i=this.generation,a=[`terminal`,`session`,`control`,e,`--cols`,String(t.cols),`--rows`,String(t.rows)],o=this.opts.spawn?this.opts.spawn(r,a,this.env):he(r,a,{env:this.env,stdio:[`pipe`,`pipe`,`pipe`]});await new Promise((r,a)=>{let s=!1,c=!1,l=Buffer.alloc(0),u=t=>{s||(s=!0,clearTimeout(f),this.active.delete(e),o.kill(`SIGKILL`),t?a(t):r())},d=()=>u(c?Error(`mouse delivery unknown`):new T(`mouse control unavailable`)),f=setTimeout(d,this.opts.timeoutMs??3e3);this.active.set(e,d),o.on(`error`,d),o.stdin.on(`error`,d),o.stderr.resume(),o.stdout.on(`data`,e=>{if(s||c)return;if(l=Buffer.concat([l,e]),l.length>1048576)return d();let r=l.indexOf(10);if(r<0)return;let a;try{a=JSON.parse(l.subarray(0,r).toString(`utf8`))}catch{return d()}if(a.type!==`terminal.frame`||a.width!==t.cols||a.height!==t.rows||i!==this.generation||!n())return d();c=!0,l=Buffer.alloc(0);let u={type:`terminal.mouse`,button:t.button,column:t.column,row:t.row,modifiers:t.modifiers};o.stdin.end(`${[{...u,action:`down`},{...u,action:`up`},{type:`terminal.release`}].map(e=>JSON.stringify(e)).join(`
|
|
69
|
+
`)}\n`)}),o.on(`close`,e=>u(e===0&&c?void 0:c?Error(`mouse delivery unknown`):new T(`mouse control unavailable`)))})}},ei=class{options;run;timer;busy=!1;watched=new Set;observations=new Map;watchedMs;backgroundMs;constructor(e){this.options=e,this.watchedMs=Math.max(125,e.watchedMs??125),this.backgroundMs=Math.max(this.watchedMs,e.backgroundMs??1e3)}start(){this.timer&&clearTimeout(this.timer),this.timer=void 0,this.run={};for(let e of this.observations.values())e.due=0;this.schedule()}stop(){this.run=void 0,this.timer&&clearTimeout(this.timer),this.timer=void 0,this.observations.clear()}setWatched(e){let t=new Set(e);for(let e of t)if(!this.watched.has(e)){let t=this.observations.get(e);t&&(t.due=0)}this.watched=t}schedule(){this.run&&!this.timer&&(this.timer=setTimeout(()=>{this.timer=void 0,this.pass().catch(()=>this.reportFailure())},this.watchedMs),this.timer.unref?.())}async pass(){let e=this.run;if(e){if(this.busy){this.schedule();return}this.busy=!0;try{let t=this.options.targets(),n=new Set(t.map(e=>e.id));for(let e of this.observations.keys())n.has(e)||this.observations.delete(e);let r=Date.now(),i=t.map(e=>{let t=this.observations.get(e.id);return(!t||t.identity!==e.identity)&&(t={identity:e.identity,digest:t?.digest,due:0},this.observations.set(e.id,t)),{target:e,observation:t}}).filter(({observation:e})=>e.due<=r).sort((e,t)=>e.observation.due-t.observation.due).slice(0,16),a=0;await Promise.all(Array.from({length:Math.min(4,i.length)},async()=>{for(;this.run===e&&a<i.length;){let t=i[a++];if(!t)return;let{target:n,observation:r}=t;try{let t=await n.read();if(this.run!==e||!n.current())continue;let i=ze(`sha256`).update(JSON.stringify([t.cols,t.rows,t.cursor,t.lines,t.scrollbackTotal])).digest(`hex`);r.digest!==void 0&&r.digest!==i&&this.options.changed(n.id),r.digest=i}catch{this.run===e&&n.current()&&this.reportFailure()}finally{r.due=Date.now()+(this.watched.has(n.id)?this.watchedMs:this.backgroundMs)}}}))}finally{this.busy=!1,this.schedule()}}}reportFailure(){try{this.options.failed()}catch{}}};function ti(e,t){return typeof t==`number`?`${e};5;${t}`:`${e};2;${t[0]};${t[1]};${t[2]}`}function ni(e){let t=[`0`];return e.b&&t.push(`1`),e.f&&t.push(`2`),e.i&&t.push(`3`),e.u&&t.push(`4`),e.s&&t.push(`9`),e.fg!==void 0&&t.push(ti(38,e.fg)),e.bg!==void 0&&t.push(ti(48,e.bg)),`\x1b[${t.join(`;`)}m`}function ri(e){let t=``;for(let n of e.r)t+=ni(n)+n.t.replace(/[\x00-\x1f\x7f]/g,``);return`${t}\x1b[0m`}function ii(e){if(typeof e!=`object`||!e||!(`pane`in e))return;let t=e.pane;if(typeof t!=`object`||!t||!(`agent_status`in t))return;let n=t.agent_status;if(typeof n!=`string`||![`idle`,`working`,`blocked`,`done`,`unknown`].includes(n))return;let r=`agent`in t?t.agent:null,i=`display_agent`in t?t.display_agent:null;if(!(r!=null&&typeof r!=`string`||i!=null&&typeof i!=`string`))return{agent:r||null,displayAgent:i||null,status:n}}var ai=class{options;enabled=!1;closed=!1;busy=!1;evidence=null;constructor(e){this.options=e}enable(){this.enabled=!0}invalidate(){this.evidence=null}close(){this.closed=!0,this.invalidate()}observe(e,t){let n=this.evidence;n&&(!oi(e,n.pane)||!si(t,n.facts))&&this.invalidate()}capture(e,t,n){this.invalidate();let{facts:r,above:i,visible:a}=t;if(!this.enabled||this.closed||!oi(this.options.pane(),e)||e.agent&&(e.agentStatus===`idle`||e.agentStatus===`done`)||!r.source||(r.source.agent!==null||r.source.displayAgent!==null)&&(r.source.status===`idle`||r.source.status===`done`)||r.paneId!==e.paneId||r.terminalId!==e.terminalId||r.offset!==0||r.viewportRows!==e.rows||i.length>r.history||i.length+a.length>1e3||r.history>0&&a.length===0||Buffer.byteLength(n)>p.screenBytes)return;let o=Object.freeze({});return this.evidence={capture:o,pane:{...e},facts:{...r,source:{...r.source}},visible:a},{capture:o,from:r.history-i.length,to:r.history,lines:i,replay:n}}async read(e){if(re(e),e.signal.aborted)return{status:`cancelled`};let t=this.evidence;if(!t||e.capture!==t.capture||e.reported!==t.facts.history)return{status:`unavailable`,reason:`unanchored`};if(!this.owns(t))return{status:`reset`};if(this.busy)return{status:`unavailable`,reason:`busy`};this.busy=!0;let n=()=>e.signal.aborted?{status:`cancelled`}:this.owns(t)?void 0:{status:`reset`};try{if(!await this.confirm(t))return n()??{status:`reset`};let r=n();if(r)return r;let i;if(e.before===0)i={status:`boundary`,reason:`end`,oldestAvailable:0};else{let r=Math.max(0,e.before-e.count),a=Math.max(0,e.reported+t.visible.length-1e3);if(e.before<=a)return{status:`unavailable`,reason:`fetch-window`};let o=Math.min(1e3,t.facts.viewportRows+e.reported-r),s=await this.options.request(`pane.read`,{pane_id:t.pane.paneId,source:`recent`,format:`ansi`,lines:o}),c=n();if(c)return c;let l=Nr(s,{paneId:t.pane.paneId,cols:t.pane.cols,viewportRows:t.facts.viewportRows,historyRows:t.facts.history,requestedRows:o,visible:t.visible});if(!l)return{status:`unavailable`,reason:`changed`};let u=Math.max(r,l.from);if(u>=e.before)return{status:`unavailable`,reason:`fetch-window`};i={status:`page`,from:u,to:e.before,oldestAvailable:0,lines:l.lines.slice(u-l.from,e.before-l.from)}}return await this.confirm(t)?n()??i:n()??{status:`reset`}}catch{return this.evidence===t&&this.invalidate(),n()??{status:`reset`}}finally{this.busy=!1}}owns(e){return!this.closed&&this.evidence===e&&oi(this.options.pane(),e.pane)}async confirm(e){let t=await this.options.request(`pane.get`,{pane_id:e.pane.paneId}),n=jr(t,e.pane.paneId,e.pane.terminalId),r=n?{...n,source:ii(t)}:null;return!r||!si(r,e.facts)?(this.evidence===e&&this.invalidate(),!1):!0}};function oi(e,t){return!!e&&e.paneId===t.paneId&&e.terminalId===t.terminalId&&e.cols===t.cols&&e.rows===t.rows&&e.agent===t.agent&&e.agentStatus===t.agentStatus}function si(e,t){return e.paneId===t.paneId&&e.terminalId===t.terminalId&&e.revision===t.revision&&e.history===t.history&&e.offset===t.offset&&e.viewportRows===t.viewportRows&&e.source?.agent===t.source?.agent&&e.source?.displayAgent===t.source?.displayAgent&&e.source?.status===t.source?.status}const ci=1e3;var H=class extends Error{},li=class extends Be{opts;log;history;generation=0;historyLines=ci;timer=null;busy=!1;seedWanted=!1;ended=!1;failures=0;readFailureSince=null;waitSupported=!0;wakeSeq=0;seedReason=`refresh`;lastSeedReason=`refresh`;probing=null;continuation={cursor:`guessed`,alternate:`unknown`,probe:()=>(this.probing??=this.probe().finally(()=>{this.probing=null}),this.probing)};shown;constructor(e){super(),this.opts=e,this.log=e.log.child({backend:`herdr`,stream:`vt`}),this.history=new ai(e)}async start(e){e!==void 0&&(this.historyLines=e),await this.reseed()}async reseed(e){this.history.invalidate(),e!==void 0&&e<this.historyLines&&(this.seedReason=this.lastSeedReason),e!==void 0&&(this.historyLines=e),this.seedWanted=!0,await this.run()}close(){this.end(void 0)}async run(){if(!(this.ended||this.busy)){++this.wakeSeq,this.busy=!0,this.timer&&clearTimeout(this.timer),this.timer=null;try{this.seedWanted?await this.seed():await this.poll(),this.failures=0,this.readFailureSince=null}catch(e){if(this.readFailureSince??=Date.now(),e instanceof ue||e instanceof V&&nr.has(e.code))this.end(`pane-gone`);else if(Date.now()-this.readFailureSince>=2e3){let t=await this.probeBottomSnapshot();this.ended||this.end(t?e instanceof H?`unsettled`:`failed`:`herdr-unreadable`)}else if(!(e instanceof H)&&++this.failures>=20){this.log.debug(`herdr vt stream failed`,{error:e instanceof Error?e.name:`unknown`});let t=await this.probeBottomSnapshot();this.ended||this.end(t?`failed`:`herdr-unreadable`)}}finally{if(this.busy=!1,!this.ended){if(this.opts.pollMs===void 0&&this.waitSupported&&this.shown&&!this.seedWanted&&this.readFailureSince===null){let e=this.opts.pane();e?this.waitForOutput(this.wakeSeq,e.paneId,this.shown.revision):this.end(`pane-gone`)}else this.schedulePoll(this.opts.pollMs??200)}}}}schedulePoll(e){this.ended||(this.timer=setTimeout(()=>void this.run(),e),this.timer.unref?.())}async waitForOutput(e,t,n){let r=Date.now(),i;try{await Promise.race([this.opts.request(`events.wait`,{match_event:{event:`pane_output_changed`,pane_id:t,min_revision:n+1},timeout_ms:1800}),new Promise(e=>{i=setTimeout(e,2e3),i.unref?.()})])}catch(e){this.waitSupported=!1,e instanceof V&&rr.has(e.code)||this.log.debug(`herdr output wait failed`,{error:e instanceof Error?e.name:`unknown`})}finally{i&&clearTimeout(i)}this.ended||e!==this.wakeSeq||this.schedulePoll(Math.max(0,200-(Date.now()-r)))}current(){let e=this.opts.pane();if(!e)throw this.end(`pane-gone`),new H;return e}async facts(e){let t=await this.opts.request(`pane.get`,{pane_id:e.paneId}),n=jr(t,e.paneId,e.terminalId);if(!n)throw new H;return{...n,source:ii(t)}}async probeBottomSnapshot(){let e=async()=>{try{let e=this.current(),t=await this.opts.request(`pane.read`,{pane_id:e.paneId,source:`detection`,format:`text`});if(t?.type!==`pane_read`||t.read?.pane_id!==e.paneId||t.read.source!==`detection`||t.read.format!==`text`||t.read.truncated||typeof t.read.text!=`string`)return!1;let n=this.current();return n.paneId===e.paneId&&n.terminalId===e.terminalId}catch{return!1}},t;try{return await Promise.race([e(),new Promise(e=>{t=setTimeout(()=>e(!1),1e3)})])}finally{t&&clearTimeout(t)}}async frame(e,t){let n=await this.facts(e);if(n.offset!==0)throw new H;let r=Mr(await this.opts.request(`pane.read`,{pane_id:e.paneId,source:`visible`,format:`ansi`}),{paneId:e.paneId,source:`visible`,rows:n.viewportRows,cols:e.cols,minRows:0});if(!r)throw new H;let i=t(n),a=[];if(i>0&&r.length>0){let t=Math.min(ci,i+r.length),n=Mr(await this.opts.request(`pane.read`,{pane_id:e.paneId,source:`recent`,format:`ansi`,lines:t}),{paneId:e.paneId,source:`recent`,rows:t,cols:e.cols,minRows:r.length});if(!n||!fi(n.slice(-r.length),r))throw new H;a=n.slice(0,-r.length)}let o=await this.facts(e);if(!di(n,o))throw new H;return this.history.observe(e,o),{facts:o,visible:r,above:a}}async seed(){let e=this.current(),t=await this.frame(e,t=>Math.min(e.agent&&ui(e.agentStatus)?this.historyLines:t.history,this.historyLines)),n=pi(t.visible,t.facts.viewportRows),r=mi(t.visible,e.cols),i=[...t.above.map(ri),...n],a=e.agent&&ui(e.agentStatus)&&!this.shown?.idle?`herdr-idle`:this.seedReason;this.lastSeedReason=a,this.seedReason=`refresh`,this.seedWanted=!1,this.generation++,this.shown={cols:e.cols,rows:t.facts.viewportRows,history:t.facts.history,screen:n,cursor:r,idle:ui(e.agentStatus),revision:t.facts.revision};let o=this.history.capture(e,t,`${mt}${i.join(`\r
|
|
70
|
+
`)}${r}`);this.emit(`seed`,{generation:this.generation,cols:e.cols,rows:t.facts.viewportRows,data:`\x1bc${i.join(`\r
|
|
71
|
+
`)}${r}`,...o?{nativeHistory:o}:{},continuation:{data:`${mt}${n.join(`\r
|
|
72
|
+
`)}${r}`,reason:a}})}async poll(){let e=this.shown,t=this.current();if(!e||t.cols!==e.cols){this.seedReason=`resize`,this.seedWanted=!0;return}let n=ui(t.agentStatus);if(t.agent&&n&&!e.idle){this.seedWanted=!0,this.seedReason=`herdr-idle`;return}e.idle=n;let r=!1,i=await this.frame(t,t=>{let n=t.history-e.history;return r=n<0||n+t.viewportRows>1e3,r?0:n});if(r||i.facts.viewportRows!==e.rows||i.above.length!==i.facts.history-e.history){this.seedReason=i.facts.viewportRows===e.rows?`source-gap`:`resize`,this.seedWanted=!0;return}let a=i.above,o=pi(i.visible,i.facts.viewportRows),s=mi(i.visible,t.cols),c=``;if(a.length>0)c=`\x1b[H${[...a.map(ri),...o].map(e=>`\x1b[2K${e}`).join(`\r
|
|
73
|
+
`)}`;else for(let t=0;t<o.length;t++)o[t]!==e.screen[t]&&(c+=`\x1b[${t+1};1H\x1b[2K${o[t]}`);(c||s!==e.cursor)&&(c+=s),e.history=i.facts.history,e.revision=i.facts.revision,e.screen=o,e.cursor=s,c&&this.emit(`bytes`,new TextEncoder().encode(c),this.generation)}end(e){this.ended||(this.ended=!0,this.history.close(),++this.wakeSeq,this.timer&&clearTimeout(this.timer),this.timer=null,e&&this.emit(`end`,e))}async probe(){let e=this.generation,t=await this.frame(this.current(),()=>0);return{generation:e,quiescent:!this.ended&&!this.seedWanted&&e===this.generation&&t.facts.revision===this.shown?.revision&&t.facts.viewportRows===this.shown.rows}}};function ui(e){return e===`idle`||e===`done`}function di(e,t){return e.revision===t.revision&&e.history===t.history&&e.viewportRows===t.viewportRows&&e.offset===t.offset&&e.source?.agent===t.source?.agent&&e.source?.displayAgent===t.source?.displayAgent&&e.source?.status===t.source?.status}function fi(e,t){return e.length===t.length&&e.every((e,n)=>ri(e)===ri(t[n]))}function pi(e,t){return Array.from({length:t},(t,n)=>ri(e[n]??{r:[]}))}function mi(e,t){let{x:n,y:r}=Er(e,t);return`\x1b[${r+1};${n+1}H`}const hi=1e3,gi=1e3;function _i(e){let t=[{type:`pane.created`},{type:`pane.closed`},{type:`pane.exited`},{type:`pane.updated`},{type:`pane.focused`},{type:`pane.moved`},{type:`pane.agent_detected`},{type:`tab.created`},{type:`tab.closed`},{type:`tab.focused`},{type:`tab.renamed`},{type:`tab.moved`},{type:`workspace.created`},{type:`workspace.updated`},{type:`workspace.closed`},{type:`workspace.focused`},{type:`workspace.renamed`},{type:`workspace.moved`},{type:`workspace.reordered`},{type:`layout.updated`}];for(let n of e)t.push({type:`pane.agent_status_changed`,pane_id:n}),t.push({type:`pane.scroll_changed`,pane_id:n});return t}const vi=new Set([`working`,`blocked`,`idle`,`done`,`unknown`]);function yi(e){return typeof e==`string`&&vi.has(e)?e:`unknown`}const bi={working:`running`,blocked:`blocked`,idle:`finished`,done:`finished`,unknown:`unknown`};function xi(e){let t=e.foreground_cwd??e.cwd,n=t?t.split(`/`).filter(Boolean).pop():void 0;return e.display_agent||e.agent||e.title||e.terminal_title_stripped||n||`Pane`}function Si(e){return le(e)}function U(e){return typeof e==`string`?e:void 0}function Ci(e){return e&&typeof e==`object`?e:void 0}function wi(e,t){return e.length===t.size&&e.every(e=>t.has(e))}function Ti(e,t){return e.paneId===t.paneId&&e.terminalId===t.terminalId&&e.revision===t.revision&&e.history===t.history&&e.viewportRows===t.viewportRows&&e.offset===t.offset}var Ei=class{opts;name=`herdr`;get capabilities(){return{subscribe:!0,prompts:!1,createSession:!0,terminalInput:!0,terminalPaste:!0,focus:!0,history:!0,absoluteLines:!1,vtStream:!0,...this.mouse.available?{mouseClick:!0}:{}}}mouse;panes=new Map;historyEpochs=new Map;historyCaptures=new WeakMap;byPaneId=new Map;order=[];workspaces=new Set;focusedWorkspace=null;eventSeq=0;conversationEpoch=F();conversationSupported=!1;conversationPending=!0;conversationHintRevision=0;handlers=new Set;log;client;screenObserver;active=null;subscribedPaneIds=new Set;closed=!0;retryTimer=null;syncTimer=null;syncBusy=!1;wantSnapshot=!1;wantResubscribe=!1;shownIn=[];createdTabs=new Map;hostAppTimer=null;hostAppGeneration=0;constructor(e){this.opts=e,this.client=e.client,this.mouse=e.mouse??new $r({socketPath:this.client.socketPath}),this.log=e.log.child({backend:`herdr`}),this.screenObserver=new ei({watchedMs:e.screenPollMs,backgroundMs:e.backgroundScreenPollMs,targets:()=>{let e=this.active;return this.closed||!e?.live?[]:[...this.panes].map(([t,n])=>({id:t,identity:n.paneId,current:()=>{let r=this.panes.get(t);return!this.closed&&this.active===e&&r?.paneId===n.paneId&&r.rows===n.rows&&r.cols===n.cols},read:()=>this.getScreen(t)}))},changed:e=>{this.historyEpochs.delete(e),this.emit({type:`screen-changed`,sessionId:e})},failed:()=>this.log.warn(`herdr screen observation failed`)})}get isConnected(){return!this.closed&&this.active!==null}async connect(){this.closed=!1,this.conversationSupported=!1;let e=await this.client.ping();this.conversationSupported=typeof e.version==`string`&&/^v?\d+\.\d+\.\d+$/.test(e.version.trim())&&ir(e.version,[0,9,5])===!0,await this.mouse.configure(e.version);let t=[];try{t=Di((await this.client.request(`session.snapshot`,{}))?.snapshot).panes.map(e=>e.pane_id)}catch(e){throw this.unavailable(e)}try{await this.openStream(t)}catch(e){throw e instanceof f?e:this.unavailable(e)}this.hostAppTimer&&clearTimeout(this.hostAppTimer),this.hostAppGeneration++,this.refreshHostApps()}async waitForVisibleAttach(e,{timeoutMs:t=15e3,intervalMs:n=250}={}){let r=Date.now()+t;for(;;){let t=await(this.opts.processTable??Zn)().catch(()=>void 0);if(!t&&(this.opts.platform??process.platform)!==`darwin`||t&&Ir(t,e))return!0;if(this.closed||Date.now()>=r)return!1;await new Promise(e=>setTimeout(e,n))}}async refreshHostApps(){this.hostAppTimer=null;let e=this.hostAppGeneration,t=await(this.opts.hostApps??Lr)(this.client.socketPath).catch(()=>void 0)??[];this.closed||e!==this.hostAppGeneration||(t.join(`
|
|
74
|
+
`)!==this.shownIn.join(`
|
|
75
|
+
`)&&(this.shownIn=t,this.emit({type:`layout-changed`})),this.hostAppTimer=setTimeout(()=>void this.refreshHostApps(),this.opts.hostAppPollMs??1e4),this.hostAppTimer.unref?.())}unavailable(e){if(e instanceof f)return e;let t=e instanceof Error?e.message:String(e);return e instanceof V&&rr.has(e.code)?new f(`herdr does not support session.snapshot (${t})`,tr):e instanceof V&&e.code===`malformed`?new f(`herdr answered session.snapshot with junk (${t})`,tr):new f(t,er)}async close(){this.closed=!0,this.mouse.close(),this.screenObserver.stop(),this.retryTimer&&clearTimeout(this.retryTimer),this.retryTimer=null,this.syncTimer&&clearTimeout(this.syncTimer),this.syncTimer=null,this.hostAppTimer&&clearTimeout(this.hostAppTimer),this.hostAppTimer=null,this.hostAppGeneration++,this.shownIn=[];let e=this.active;this.active=null,e&&(e.cancelled=!0,e.stream?.close()),this.panes.clear(),this.historyEpochs.clear(),this.byPaneId.clear(),this.order=[],this.wantSnapshot=!1,this.wantResubscribe=!1,this.syncBusy=!1,this.subscribedPaneIds.clear(),this.handlers.clear()}on(e){return this.handlers.add(e),()=>this.handlers.delete(e)}async conversationReference(e,t){let n=this.panes.get(e),r=this.active;if(t.aborted||!n||!this.isConnected||!r?.live||this.conversationPending||!this.conversationSupported)return null;let i=n.conversationOwner,a=n.conversationRevision,o=this.conversationEpoch;try{let s=await this.client.request(`pane.get`,{pane_id:n.paneId},{signal:t}),c=this.panes.get(e);if(t.aborted||this.closed||this.active!==r||this.conversationPending||this.conversationEpoch!==o||!c||c.paneId!==n.paneId||c.conversationOwner!==i||s?.pane?.pane_id!==n.paneId||s.pane.terminal_id!==e||!Number.isSafeInteger(s.pane.revision)||s.pane.revision<a)return null;let l=Sr(s.pane);if(this.setConversationReference(c,l,s.pane.revision),c.conversationSeq=++this.eventSeq,t.aborted||this.closed||this.active!==r||this.conversationPending||this.conversationEpoch!==o||this.panes.get(e)!==c||!St(l,c.conversation))return null;let u=yi(s.pane.agent_status);return l?Object.freeze({...l,owner:`${o}:${c.conversationOwner}`,...u!==`unknown`&&{waiting:u===`blocked`}}):null}catch(e){return e instanceof V&&nr.has(e.code)&&(this.invalidateConversations(),this.scheduleSync(`snapshot`)),null}}setConversationReference(e,t,n){n<e.conversationRevision||(n>e.conversationRevision&&(e.conversationRevision=n,e.conversationSeq=++this.eventSeq),!St(e.conversation,t)&&(e.conversation=t,e.conversationOwner=F(),e.conversationSeq=++this.eventSeq,this.emit({type:`conversation-changed`,sessionId:e.terminalId})))}invalidateConversations(){if(this.conversationHintRevision++,!this.conversationPending){this.conversationPending=!0,this.conversationEpoch=F();for(let e of this.panes.values())this.emit({type:`conversation-changed`,sessionId:e.terminalId})}}async notificationFacts(e){let t=this.panes.get(e);if(!t||!this.isConnected)return;let n=t.naming.agent?.kind;return vt({sessionId:e,cwd:t.cwd,title:t.title,sessionLabel:`Herdr`},n,n?`local-process`:`reported`)}async listSessions(){return this.order.map(e=>this.panes.get(e)).filter(e=>e!==void 0).map(e=>this.toInfo(e))}async getScreen(e,t){let n=this.pane(e),r=t?.history?this.captureEpoch(n):void 0;n.scrollStale&&await this.refreshScroll(n);let i=r&&this.ownsHistory(r)?await this.historyFacts(r):void 0,a=!n.scrollStale&&n.scrollOffset===0&&(!i||!(`facts`in i)||i.facts.offset===0)?`visible`:`detection`,o=t=>this.call(e,`pane.read`,{pane_id:n.paneId,source:t,format:t===`visible`?`ansi`:`text`}),s=await o(a);if(a===`visible`&&(n.scrollStale||n.scrollOffset!==0)&&(a=`detection`,s=await o(a)),a===`detection`&&(s?.type!==`pane_read`||s.read?.pane_id!==n.paneId||s.read.source!==`detection`||s.read.format!==`text`||s.read.truncated||typeof s.read.text!=`string`))throw Error(`Herdr live bottom screen unavailable`);let c=Dr({text:s?.read?.text??``,rows:n.rows,cols:n.cols,scrollMax:n.scrollMax});if(a===`detection`||!r||!this.ownsHistory(r)||!i||!(`facts`in i))return c;let l=Mr(s,{paneId:r.paneId,source:`visible`,rows:r.rows,cols:r.cols,minRows:0});if(!l||i.facts.offset!==0)return c;let u=await this.historyFacts(r);if(!this.ownsHistory(r)||!(`facts`in u))return c;if(!Ti(i.facts,u.facts))return this.revokeHistory(r),c;r.certified=u.facts;let d=Object.freeze({});this.historyCaptures.set(d,{epoch:r,facts:u.facts,visible:l}),c.scrollbackTotal=u.facts.history;let f=this.pane(e);return f.scrollMax=u.facts.history,f.scrollOffset=u.facts.offset,f.scrollEventSeq=++this.eventSeq,c.historyCapture=d,c}async getHistoryPage(e,t){if(re(t),t.signal.aborted)return{status:`cancelled`};this.pane(e);let n=this.historyCaptures.get(t.capture);if(!n||n.epoch.sessionId!==e)return{status:`unavailable`,reason:`unanchored`};let{epoch:r,facts:i}=n,a=()=>t.signal.aborted?{status:`cancelled`}:this.ownsHistory(r)?void 0:{status:`reset`},o=a();if(o)return o;if(t.reported<i.history||t.reported>2**53-1-i.viewportRows)return{status:`unavailable`,reason:`unanchored`};let s=await this.historyFacts(r),c=a();if(c)return c;if(!(`facts`in s))return{status:`unavailable`,reason:s.reason};if(!Ti(i,s.facts))return this.revokeHistory(r),{status:`reset`};let l=t.reported-i.history,u;if(t.before<=l)u={status:`boundary`,reason:t.before===l?`end`:`truncated`,oldestAvailable:l};else{let e=Math.max(t.before-t.count,l),o=t.reported+n.visible.length-hi;if(t.before<=o)return{status:`unavailable`,reason:`fetch-window`};let s=Math.min(hi,i.viewportRows+(t.reported-e));if(!Number.isSafeInteger(s)||s<1||s>hi)return{status:`unavailable`,reason:`fetch-window`};let c;try{c=await this.client.request(`pane.read`,{pane_id:r.paneId,source:`recent`,format:`ansi`,lines:s})}catch(e){return a()??{status:`unavailable`,reason:e instanceof V&&e.code===`agent_not_idle`?`busy`:`changed`}}let d=a();if(d)return d;let f=Nr(c,{paneId:r.paneId,cols:r.cols,viewportRows:i.viewportRows,historyRows:i.history,requestedRows:s,visible:n.visible});if(!f)return{status:`unavailable`,reason:`changed`};let p=l+f.from,m=Math.max(e,p);if(m>=t.before)return{status:`unavailable`,reason:`fetch-window`};u={status:`page`,from:m,to:t.before,oldestAvailable:l,lines:f.lines.slice(m-p,t.before-p)}}let d=await this.historyFacts(r);return a()||(`facts`in d?Ti(i,d.facts)?(r.certified=d.facts,u):(this.revokeHistory(r),{status:`reset`}):{status:`unavailable`,reason:d.reason})}captureEpoch(e){if(this.closed||!this.active||this.active.cancelled||e.scrollOffset!==void 0&&e.scrollOffset!==0)return;let t=this.historyEpochs.get(e.terminalId);if(t&&this.ownsHistory(t))return t;let n={sessionId:e.terminalId,paneId:e.paneId,stream:this.active,revision:e.revision,cols:e.cols,rows:e.rows};return this.historyEpochs.set(e.terminalId,n),n}ownsHistory(e){let t=this.panes.get(e.sessionId);return!this.closed&&this.active===e.stream&&!e.stream.cancelled&&this.historyEpochs.get(e.sessionId)===e&&t?.paneId===e.paneId&&t.cols===e.cols&&t.rows===e.rows&&t.revision===e.revision}revokeHistory(e){this.historyEpochs.get(e.sessionId)===e&&this.historyEpochs.delete(e.sessionId)}async historyFacts(e){try{let t=await this.client.request(`pane.get`,{pane_id:e.paneId}),n=jr(t,t?.pane?.pane_id,t?.pane?.terminal_id);return n?(this.ownsHistory(e)&&(n.paneId!==e.paneId||n.terminalId!==e.sessionId||n.viewportRows!==e.rows||e.certified&&!Ti(e.certified,n))&&this.revokeHistory(e),{facts:n}):{reason:`changed`}}catch(e){return{reason:e instanceof V&&e.code===`agent_not_idle`?`busy`:`changed`}}}async getHistory(e,t,n){let r=this.pane(e),i=this.active,{scrollMax:a,rows:o,cols:s}=r,c=Math.max(0,a-t),l=Math.min(hi,c+n+o),u=await this.call(e,`pane.read`,{pane_id:r.paneId,source:`recent`,format:`ansi`,lines:l}),d=()=>new f(`History temporarily unavailable`,`Retry history after output settles.`),p=Mr(await this.call(e,`pane.read`,{pane_id:r.paneId,source:`visible`,format:`ansi`}),{paneId:r.paneId,source:`visible`,rows:o,cols:s,minRows:0});if(!p)throw d();let m=Nr(u,{paneId:r.paneId,cols:s,viewportRows:o,historyRows:a,requestedRows:l,visible:p});if(!m||t>0&&m.from>=t||this.closed||this.active!==i||i?.cancelled||this.panes.get(e)!==r||r.rows!==o||r.cols!==s||r.scrollMax!==a)throw d();let h=Math.max(0,a-c-m.from),g=Math.max(0,h-n),_=m.lines.slice(g,h);return{lines:_,oldestAvailable:m.from===0&&g===0?Math.max(0,t-_.length):0}}async sendText(e,t){let n=this.pane(e),r=Hr(t);if(r){this.log.debug(`herdr key`),await this.call(e,`pane.send_keys`,{pane_id:n.paneId,keys:[r]});return}if(this.log.debug(`herdr text`,{len:t.length}),t.endsWith(`\r`)||t.endsWith(`
|
|
76
|
+
`)){let r=t.slice(0,-1);r&&await this.call(e,`pane.send_text`,{pane_id:n.paneId,text:r}),await this.call(e,`pane.send_keys`,{pane_id:n.paneId,keys:[`enter`]});return}await this.call(e,`pane.send_text`,{pane_id:n.paneId,text:t})}async clickMouse(e,t){let n=this.pane(e),r=this.active,i=()=>{let i=this.panes.get(e);return!this.closed&&this.active===r&&r?.live===!0&&i?.paneId===n.paneId&&i.cols===t.cols&&i.rows===t.rows&&(i.scrollOffset??0)===0};if(!this.mouse.available||!i())throw new T(`mouse input unavailable`);let a=Di((await this.client.request(`session.snapshot`,{}))?.snapshot),o=a.panes.find(t=>t.terminal_id===e),s=a.layouts.flatMap(e=>e.panes).find(e=>e.pane_id===n.paneId)?.rect;if(!i()||o?.pane_id!==n.paneId||o.scroll?.offset_from_bottom!==0||s?.width!==t.cols||s.height!==t.rows)throw new T(`mouse grid changed`);await this.mouse.click(e,t,i)}async sendInput(e,t){let n=this.pane(e);await this.call(e,`pane.send_text`,{pane_id:n.paneId,text:t})}async paste(e,t,n){let r=this.pane(e);await this.call(e,`pane.send_input`,{pane_id:r.paneId,text:t,keys:n?[`Enter`]:[]})}async createSession(t){if(t.kind===`split`){let e=this.pane(t.sessionId),n=U((await this.client.request(`pane.split`,{target_pane_id:e.paneId,direction:t.direction===`vertical`?`right`:`down`,focus:!1}))?.pane?.terminal_id);if(!n)throw Error(`herdr pane.split returned no terminal_id`);return this.scheduleSync(`snapshot`),n}if(t.windowId!==void 0&&!this.workspaces.has(t.windowId))throw new e(t.windowId);let n=t.windowId??this.focusedWorkspace??[...this.workspaces][0];if(!n)return this.createWorkspaceSession();let r=await this.client.request(`tab.create`,{workspace_id:n,focus:!1}),i=U(r?.root_pane?.terminal_id);if(!i)throw Error(`herdr tab.create returned no terminal_id`);let a=U(r?.tab?.tab_id);return a&&(this.createdTabs.set(i,a),this.createdTabs.size>16&&this.createdTabs.delete(this.createdTabs.keys().next().value)),this.scheduleSync(`snapshot`),i}async shownOnComputer(e){if(e.kind===`split`)this.pane(e.sessionId);else if(e.windowId!==void 0&&!this.workspaces.has(e.windowId))throw new ue(e.windowId);let t=await(this.opts.hostApps??Lr)(this.client.socketPath).catch(()=>void 0);return!this.closed&&this.isConnected&&(t?.length??0)>0}async focusedWindow(){let e=this.focusedWorkspace??[...this.workspaces][0];if(e)return await this.shownOnComputer({kind:`tab`,backend:`herdr`,windowId:e})?e:void 0}async discardSession(e){let t=this.createdTabs.get(e);if(!t)throw new ue(e);this.createdTabs.delete(e),await this.client.request(`tab.close`,{tab_id:t}),this.scheduleSync(`snapshot`)}async createWorkspaceSession(){return(await this.createWorkspace()).terminalId}async createWorkspace(){let e=await this.client.request(`workspace.create`,{cwd:A(),focus:!1}),t=U(e?.root_pane?.terminal_id);if(!t)throw Error(`herdr workspace.create returned no terminal_id`);this.scheduleSync(`snapshot`);let n=U(e?.workspace?.workspace_id)??U(e?.root_pane?.workspace_id);return n?{terminalId:t,workspaceId:n}:{terminalId:t}}async closeWorkspace(e){await this.client.request(`workspace.close`,{workspace_id:e}),this.scheduleSync(`snapshot`)}get terminalSocketPath(){return this.client.socketPath}get terminalAttachExecutable(){return this.isConnected?this.mouse.verifiedExecutable:void 0}get terminalAttachIssue(){return this.isConnected&&this.terminalAttachExecutable===void 0?this.mouse.unavailableReason:void 0}async focus(e){let t=this.pane(e);await this.call(e,`pane.focus`,{pane_id:t.paneId})}setWatched(e){this.screenObserver.setWatched(e)}emit(e){for(let t of this.handlers)try{t(e)}catch(e){this.log.warn(`event handler failed`,{error:Si(e)})}}openVtStream(e){return this.pane(e),new li({request:(t,n)=>this.call(e,t,n),pane:()=>{let t=this.closed?void 0:this.panes.get(e);return t&&{paneId:t.paneId,terminalId:t.terminalId,cols:t.cols,rows:t.rows,agentStatus:t.agentStatus,agent:t.naming.agent!==void 0}},log:this.opts.log})}pane(e){let t=this.panes.get(e);if(!t)throw new ue(e);return t}async call(e,t,n){try{return await this.client.request(t,n)}catch(t){throw t instanceof V&&nr.has(t.code)?(this.scheduleSync(`snapshot`),new ue(e)):t}}toInfo(e){return{id:e.terminalId,backend:`herdr`,title:e.title,cwd:e.cwd,...e.naming,...e.windowLabel?{windowLabel:e.windowLabel}:{},cols:Math.max(1,e.cols),rows:Math.max(1,e.rows),windowId:e.workspaceId,windowNumber:e.windowNumber,tabId:e.tabId,tabIndex:e.tabIndex,paneIndex:e.paneIndex,isFocusedOnMac:e.focused,state:bi[e.agentStatus],...this.shownIn.length>0?{shownIn:[...this.shownIn]}:{}}}sortOrder(){this.order=[...this.panes.values()].sort((e,t)=>e.windowNumber-t.windowNumber||e.tabIndex-t.tabIndex||e.paneIndex-t.paneIndex||e.paneId.localeCompare(t.paneId)).map(e=>e.terminalId)}async openStream(e){let t=e??[...this.byPaneId.keys()],n={cancelled:!1,live:!1,buffer:[],stream:null,overflowed:!1},r=await this.client.subscribe(_i(t),{onEvent:e=>{if(!n.cancelled){if(n.live){this.onEvent(e);return}if(n.buffer.length<gi){n.buffer.push(e);return}n.overflowed||(n.overflowed=!0,this.log.warn(`herdr bootstrap event buffer overflowed; dropping events`,{max:gi})),this.active===n&&this.invalidateConversations(),this.scheduleSync(`snapshot`)}},onEnd:e=>{!n.cancelled&&this.active===n&&this.onStreamEnd(e)}});if(n.stream=r,this.closed){n.cancelled=!0,r.close();return}let i=this.active;this.active=n,this.conversationEpoch=F(),this.conversationPending=!0,this.conversationHintRevision++;for(let e of this.panes.values())this.emit({type:`conversation-changed`,sessionId:e.terminalId});this.historyEpochs.clear(),this.subscribedPaneIds=new Set(t),i&&(i.cancelled=!0,i.stream?.close());try{await this.refreshSnapshot()}catch(e){throw n.cancelled=!0,r.close(),this.active===n&&(this.active=null),e}if(n.cancelled||this.closed||this.active!==n)return;n.live=!0;let a=n.buffer;n.buffer=[];for(let e of a)this.onEvent(e);this.screenObserver.start(),this.emit({type:`layout-changed`}),!this.conversationPending&&this.active===n&&this.emit({type:`conversation-settled`})}async refreshSnapshot(){let e=this.eventSeq,t=this.active,n=this.conversationHintRevision;try{let r=await this.client.request(`session.snapshot`,{});if(this.closed||this.active!==t)return;this.applySnapshot(Di(r?.snapshot),e),this.conversationHintRevision===n&&this.conversationPending&&!this.wantResubscribe&&(this.conversationPending=!1,t?.live&&this.emit({type:`conversation-settled`}))}catch(e){if(this.closed||this.active!==t)return;throw e}}scheduleSync(e){this.closed||(e===`resubscribe`?this.wantResubscribe=!0:this.wantSnapshot=!0,!this.syncTimer&&(this.syncTimer=setTimeout(()=>{this.syncTimer=null,this.runSync().catch(e=>{this.log.warn(`herdr sync crashed`,{error:Si(e)})})},this.opts.syncDebounceMs??250),this.syncTimer.unref?.()))}async runSync(){if(!(this.syncBusy||this.closed)){this.syncBusy=!0;try{for(;(this.wantResubscribe||this.wantSnapshot)&&!this.closed&&this.active;){let e=this.wantResubscribe;this.wantResubscribe=!1,this.wantSnapshot=!1,e?await this.openStream():await this.refreshSnapshot()}}catch(e){this.log.warn(`herdr sync failed`,{error:Si(e)}),this.onStreamEnd(`sync-failed`)}finally{this.syncBusy=!1}}}onStreamEnd(e){if(this.closed)return;this.screenObserver.stop(),this.syncTimer&&clearTimeout(this.syncTimer),this.syncTimer=null,this.wantSnapshot=!1,this.wantResubscribe=!1;let t=this.active;this.active=null,this.historyEpochs.clear(),t&&(t.cancelled=!0,t.stream?.close()),this.log.info(`herdr stream ended`,{reason:e});let n=[...this.order];this.panes.clear(),this.byPaneId.clear(),this.order=[],this.subscribedPaneIds.clear();for(let e of n)this.emit({type:`session-removed`,sessionId:e});this.emit({type:`layout-changed`}),this.scheduleReconnect()}scheduleReconnect(){if(this.closed||this.retryTimer)return;let e=this.opts.reconnectMs??2e3;this.retryTimer=setTimeout(()=>{this.retryTimer=null,this.connect().catch(e=>{this.log.debug(`herdr reconnect failed`,{error:Si(e)}),this.scheduleReconnect()})},e),this.retryTimer.unref?.()}applySnapshot(e,t=0){let n=new Map,r=new Map,i=new Set;for(let t of e.workspaces??[]){i.add(t.workspace_id),n.set(t.workspace_id,t.number??0);let e=R(typeof t.label==`string`?t.label:void 0,128);e&&r.set(t.workspace_id,e)}let a=new Map;for(let t of e.tabs??[])a.set(t.tab_id,t.number??0);let o=Oi(e.layouts??[]),s=this.panes,c=new Map,l=new Map,u=[],d=new Set,f=new Set,p=new Set;for(let m of e.panes){let h=m.terminal_id??m.pane_id,g=s.get(h),_=!this.conversationPending&&g?.paneId===m.pane_id?g:void 0,v=_&&(_.conversationSeq>t||m.revision<_.conversationRevision)?_.conversation:Sr(m),y=_&&St(_.conversation,v),b=y?_.conversationOwner:F(),ee=y?_.conversationSeq:++this.eventSeq,te=Math.max(_?.conversationRevision??0,Number.isSafeInteger(m.revision)?m.revision:0);g&&!y&&f.add(h);let x=o.get(m.pane_id),ne=yi(m.agent_status),re=g?.statusSeq??0,ie=re>t,S=g?.paneId===m.pane_id&&g.scrollEventSeq>t,ae=g?.paneId===m.pane_id&&g.layoutEventSeq>t,C=ie?g?.agentStatus??ne:ne,w=m.scroll?.viewport_rows,oe=xi(m),se=m.foreground_cwd??m.cwd,T=r.get(m.workspace_id),ce=Ut(m,T);g&&(g.title!==oe||g.cwd!==se||g.windowLabel!==T||!Bt(g.naming,ce))&&d.add(h);let le=ie?g?.revision??(typeof m.revision==`number`?m.revision:0):typeof m.revision==`number`?m.revision:g?.revision??0;!ie&&g&&typeof m.revision==`number`&&typeof g.revision==`number`&&m.revision!==g.revision&&p.add(h),c.set(h,{conversation:v,conversationOwner:b,conversationSeq:ee,conversationRevision:te,terminalId:h,paneId:m.pane_id,workspaceId:m.workspace_id,tabId:m.tab_id,title:oe,cwd:se,naming:ce,windowLabel:T,cols:ae?g.cols:x?.cols??g?.cols??80,rows:S?g.rows:Math.max(1,w??x?.rows??g?.rows??24),windowNumber:n.get(m.workspace_id)??0,tabIndex:a.get(m.tab_id)??0,paneIndex:ae?g.paneIndex:x?.order??0,focused:m.focused===!0||m.pane_id===e.focused_pane_id,agentStatus:C,scrollMax:S?g.scrollMax:m.scroll?.max_offset_from_bottom??g?.scrollMax??0,scrollOffset:S?g.scrollOffset:m.scroll?.offset_from_bottom??g?.scrollOffset,scrollStale:S?g.scrollStale:(g?.scrollStale??!1)||x!==void 0&&(w===void 0||w!==x.rows),scrollFetchedAt:S?g.scrollFetchedAt:x!==void 0&&(w===void 0||w!==x.rows)?0:g?.scrollFetchedAt??0,scrollEventSeq:g?.scrollEventSeq??0,layoutEventSeq:g?.layoutEventSeq??0,statusSeq:re,revision:le}),l.set(m.pane_id,h),i.add(m.workspace_id),!ie&&g?.agentStatus!==C&&u.push({id:h,state:C,agent:m.display_agent??m.agent})}let m=[...s.keys()].filter(e=>!c.has(e)),h=new Set([...c.keys()].filter(e=>!s.has(e))),g=new Map(u.map(e=>[e.id,e]));for(let[e,t]of this.historyEpochs){let n=s.get(e),r=c.get(e);(!r||r.paneId!==t.paneId||r.cols!==t.cols||r.rows!==t.rows||r.revision!==t.revision||r.scrollMax!==n?.scrollMax||r.scrollOffset!==n?.scrollOffset)&&this.revokeHistory(t)}this.panes=c,this.byPaneId=l,this.workspaces=i,this.focusedWorkspace=e.focused_workspace_id??null,this.sortOrder();for(let e of m)this.emit({type:`session-removed`,sessionId:e});for(let e of this.order)h.has(e)&&this.emit({type:`session-added`,sessionId:e});for(let e of this.order)f.has(e)&&this.emit({type:`conversation-changed`,sessionId:e});let _=Date.now();for(let e of this.order){let t=g.get(e);t&&this.emit({type:`agent-state`,sessionId:t.id,state:t.state,agent:t.agent,at:_})}for(let e of this.order)d.has(e)&&this.emit({type:`title-changed`,sessionId:e});for(let e of this.order)p.has(e)&&this.emit({type:`screen-changed`,sessionId:e});(m.length>0||h.size>0)&&this.emit({type:`layout-changed`}),wi([...l.keys()],this.subscribedPaneIds)||this.scheduleSync(`resubscribe`)}onEvent(e){try{this.handleEvent(e)}catch(e){this.log.warn(`herdr event handling failed`,{error:Si(e)})}}handleEvent(e){let t=e.event.replaceAll(`.`,`_`),n=e.data;switch([`pane_created`,`pane_closed`,`pane_exited`,`pane_moved`,`pane_agent_detected`,`tab_created`,`tab_closed`,`tab_moved`,`workspace_created`,`workspace_closed`].includes(t)&&this.invalidateConversations(),t){case`pane_created`:case`pane_closed`:case`pane_exited`:case`pane_moved`:case`pane_agent_detected`:case`tab_created`:case`tab_closed`:case`tab_renamed`:case`tab_moved`:case`workspace_created`:case`workspace_updated`:case`workspace_closed`:case`workspace_renamed`:case`workspace_moved`:case`workspace_reordered`:this.historyEpochs.clear(),this.scheduleSync(`snapshot`);return;case`pane_updated`:{let e=n.pane,t=U(e?.pane_id);if(!t)return;let r=this.paneByPaneId(t);if(!r){this.scheduleSync(`snapshot`);return}if(typeof e?.revision==`number`&&typeof r.revision==`number`&&e.revision<=r.revision)return;this.historyEpochs.delete(r.terminalId),Number.isSafeInteger(e?.revision)&&e.revision>r.conversationRevision&&this.setConversationReference(r,Sr(e),e.revision),(xi(e)!==r.title||(e?.foreground_cwd??e?.cwd)!==r.cwd||!Bt(Ut(e,r.windowLabel),r.naming))&&this.scheduleSync(`snapshot`);let i=Ci(e?.scroll);typeof i?.offset_from_bottom==`number`&&(r.scrollOffset=i.offset_from_bottom),i&&typeof i.max_offset_from_bottom==`number`&&(r.scrollMax=i.max_offset_from_bottom,typeof i.viewport_rows==`number`&&(r.rows=Math.max(1,i.viewport_rows)),r.scrollStale=!1),r.statusSeq=++this.eventSeq,i&&(r.scrollEventSeq=r.statusSeq);let a=yi(e?.agent_status);r.agentStatus!==a&&(r.agentStatus=a,this.emit({type:`agent-state`,sessionId:r.terminalId,state:a,at:Date.now()})),typeof e?.revision==`number`&&e.revision!==r.revision&&(r.revision=e.revision,this.emit({type:`screen-changed`,sessionId:r.terminalId}));return}case`pane_agent_status_changed`:if(!this.paneByPaneId(U(n.pane_id)))return;this.scheduleSync(`snapshot`);return;case`pane_scroll_changed`:{let e=this.paneByPaneId(U(n.pane_id));if(!e)return;e.scrollEventSeq=++this.eventSeq,this.historyEpochs.delete(e.terminalId);let t=Ci(n.scroll);if(typeof t?.offset_from_bottom==`number`&&(e.scrollOffset=t.offset_from_bottom),t&&typeof t.max_offset_from_bottom==`number`){e.scrollMax=t.max_offset_from_bottom,typeof t.viewport_rows==`number`&&(e.rows=Math.max(1,t.viewport_rows)),e.scrollStale=!1,this.emit({type:`screen-changed`,sessionId:e.terminalId});return}e.scrollStale=!0,this.emit({type:`screen-changed`,sessionId:e.terminalId});return}case`layout_updated`:{this.historyEpochs.clear();let e=n.layout;if(e){for(let[t,n]of Oi([e])){let e=this.paneByPaneId(t);e&&(e.cols=n.cols,e.rows=Math.max(1,n.rows),e.scrollStale=!0,e.scrollFetchedAt=0,e.scrollEventSeq=++this.eventSeq,e.layoutEventSeq=e.scrollEventSeq,e.paneIndex=n.order)}this.sortOrder()}this.emit({type:`layout-changed`});return}case`pane_focused`:{let e=this.paneByPaneId(U(n.pane_id));if(e)for(let t of this.panes.values())t.focused=t===e;else this.scheduleSync(`snapshot`);this.emit({type:`focus-changed`});return}case`tab_focused`:case`workspace_focused`:this.emit({type:`focus-changed`});return;default:this.log.debug(`unhandled herdr event`);return}}paneByPaneId(e){let t=e?this.byPaneId.get(e):void 0;return t?this.panes.get(t):void 0}async refreshScroll(e){let t=Date.now(),n=this.opts.scrollRefreshMs??1e3;if(t-e.scrollFetchedAt<n)return;e.scrollFetchedAt=t;let r=e.scrollEventSeq;try{let t=await this.client.request(`pane.get`,{pane_id:e.paneId});if(this.panes.get(e.terminalId)!==e)return;if(e.scrollEventSeq!==r){e.scrollStale&&(e.scrollFetchedAt=0,this.emit({type:`screen-changed`,sessionId:e.terminalId}));return}let n=t?.pane?.scroll;this.panes.get(e.terminalId)===e&&n&&(n.max_offset_from_bottom!==e.scrollMax||n.viewport_rows!==e.rows||n.offset_from_bottom!==e.scrollOffset)&&this.historyEpochs.delete(e.terminalId),typeof n?.offset_from_bottom==`number`&&(e.scrollOffset=n.offset_from_bottom),n&&typeof n.max_offset_from_bottom==`number`&&(e.scrollMax=n.max_offset_from_bottom,typeof n.viewport_rows==`number`&&(e.rows=Math.max(1,n.viewport_rows))),e.scrollStale=!1}catch(e){this.log.debug(`herdr scroll refresh failed`,{error:Si(e)})}}};function Di(e){let t=e;if(!t||typeof t!=`object`||!Array.isArray(t.panes))throw new V(`malformed`,`session.snapshot returned no panes array`);return t}function Oi(e){let t=new Map;for(let n of e)[...n.panes??[]].sort((e,t)=>(e.rect?.y??0)-(t.rect?.y??0)||(e.rect?.x??0)-(t.rect?.x??0)).forEach((e,n)=>{t.set(e.pane_id,{cols:Math.max(1,e.rect?.width??80),rows:Math.max(1,e.rect?.height??24),order:n})});return t}function ki(e=process.env){return Kr(e)!==void 0}async function Ai(e={}){let t=e.log??y({stdout:!1}),n=e.client??new cr({log:t,socketPath:e.socketPath,requestTimeoutMs:3e3});if(!D(n.socketPath))return{name:`herdr`,ok:!0,detail:(e.herdrOnPath??ki)()?`installed but not running (optional)`:`not installed (optional)`};let r;try{r=await n.ping()}catch(e){return e instanceof f?{name:`herdr`,ok:!1,detail:e.message,fix:e.hint}:{name:`herdr`,ok:!1,detail:String(e),fix:er}}try{Di((await n.request(`session.snapshot`,{}))?.snapshot)}catch(e){return{name:`herdr`,ok:!1,detail:e instanceof V&&rr.has(e.code)?`herdr ${r.version??`?`} has no session.snapshot`:`session.snapshot failed: ${e instanceof Error?e.message:String(e)}`,fix:tr}}return{name:`herdr`,ok:!0,detail:`v${r.version??`?`} protocol ${r.protocol??`?`}`}}function ji(e){let t=e.log.child({unit:`herdr-start`}),n=new Ei({client:e.client??new cr({log:e.log,socketPath:e.socketPath}),log:e.log,...e.backendOptions}),r=null,i=!1,a=!1,o=!1;e.registry.add(n);let s=e.registry.registerSetupReporter(`herdr`,e=>{if(!e)return{issue:ki()?`not-running`:`not-installed`};let t=n.terminalAttachIssue;return t?{issue:`limited`,detail:t}:{}}),c=()=>{i||r||(r=setTimeout(()=>{r=null,l()},e.retryMs??1e4),r.unref?.())},l=async()=>{if(!(i||n.isConnected)){try{await n.connect()}catch(n){t.debug(`herdr not available`,{error:le(n)}),e.onUnavailable&&!o&&n instanceof f&&(o=!0,e.onUnavailable()),c();return}try{if(i)return;if(t.info(`herdr connected`),e.onConnected&&!a){a=!0;let t=await n.listSessions().catch(()=>[]);e.onConnected(t.length)}}catch(e){t.debug(`herdr post-connect setup failed`,{error:le(e)})}}};return l(),{stop(){s(),i=!0,r&&clearTimeout(r),r=null,n.close(),e.registry.remove(`herdr`)}}}const Mi=We(pe);var W=class extends Error{kind;constructor(e,t){super(e),this.kind=t,this.name=`ITerm2AuthError`}};const Ni=12e4;async function Pi(e,t=Ni){let n=Date.now()+t;if((await Fi(`if application "iTerm2" is running then
|
|
77
|
+
return "yes"
|
|
78
|
+
else
|
|
79
|
+
return "no"
|
|
80
|
+
end if`,n)).trim()!==`yes`)throw new W(`iTerm2 is not running`,`not-running`);let r=e.replace(/[\\"]/g,``),i;try{i=await Fi(`tell application "iTerm2" to request cookie and key for app named "${r}"`,n)}catch(e){if(e instanceof W)throw e;let t=String(e.stderr??e);throw/-274[01]/.test(t)?new W(`iTerm2 is too old (need 3.3+)`,`too-old`):/denied|not allowed|user/i.test(t)?new W(t.trim(),`denied`):new W(t.trim(),`unknown`)}let[a,o]=i.trim().split(` `);if(!a||!o)throw new W(`unexpected osascript output (${i.trim().split(` `).length} token(s), ${i.length} chars)`,`unknown`);return{cookie:a,key:o}}async function Fi(e,t){try{let{stdout:n}=await Mi(`/usr/bin/osascript`,[`-e`,e],{timeout:Math.max(1,t-Date.now()),killSignal:`SIGKILL`});return n}catch(e){throw e.killed?new W(`osascript timed out waiting for iTerm2`,`unknown`):e}}const G=Ye(`CgxpdGVybTIucHJvdG8SBml0ZXJtMiLcBQoXQ2xpZW50T3JpZ2luYXRlZE1lc3NhZ2USCgoCaWQYASABKAMSNgoSZ2V0X2J1ZmZlcl9yZXF1ZXN0GGQgASgLMhguaXRlcm0yLkdldEJ1ZmZlclJlcXVlc3RIABI2ChJnZXRfcHJvbXB0X3JlcXVlc3QYZSABKAsyGC5pdGVybTIuR2V0UHJvbXB0UmVxdWVzdEgAEjsKFG5vdGlmaWNhdGlvbl9yZXF1ZXN0GGcgASgLMhsuaXRlcm0yLk5vdGlmaWNhdGlvblJlcXVlc3RIABI8ChVsaXN0X3Nlc3Npb25zX3JlcXVlc3QYaiABKAsyGy5pdGVybTIuTGlzdFNlc3Npb25zUmVxdWVzdEgAEjQKEXNlbmRfdGV4dF9yZXF1ZXN0GGsgASgLMhcuaXRlcm0yLlNlbmRUZXh0UmVxdWVzdEgAEjYKEmNyZWF0ZV90YWJfcmVxdWVzdBhsIAEoCzIYLml0ZXJtMi5DcmVhdGVUYWJSZXF1ZXN0SAASNgoSc3BsaXRfcGFuZV9yZXF1ZXN0GG0gASgLMhguaXRlcm0yLlNwbGl0UGFuZVJlcXVlc3RIABI6ChRnZXRfcHJvcGVydHlfcmVxdWVzdBhwIAEoCzIaLml0ZXJtMi5HZXRQcm9wZXJ0eVJlcXVlc3RIABIzChBhY3RpdmF0ZV9yZXF1ZXN0GHIgASgLMhcuaXRlcm0yLkFjdGl2YXRlUmVxdWVzdEgAEjMKEHZhcmlhYmxlX3JlcXVlc3QYcyABKAsyFy5pdGVybTIuVmFyaWFibGVSZXF1ZXN0SAASLQoNZm9jdXNfcmVxdWVzdBh1IAEoCzIULml0ZXJtMi5Gb2N1c1JlcXVlc3RIABJBChdpbnZva2VfZnVuY3Rpb25fcmVxdWVzdBiEASABKAsyHS5pdGVybTIuSW52b2tlRnVuY3Rpb25SZXF1ZXN0SABCDAoKc3VibWVzc2FnZSK0BgoXU2VydmVyT3JpZ2luYXRlZE1lc3NhZ2USCgoCaWQYASABKAMSDwoFZXJyb3IYAiABKAlIABI4ChNnZXRfYnVmZmVyX3Jlc3BvbnNlGGQgASgLMhkuaXRlcm0yLkdldEJ1ZmZlclJlc3BvbnNlSAASOAoTZ2V0X3Byb21wdF9yZXNwb25zZRhlIAEoCzIZLml0ZXJtMi5HZXRQcm9tcHRSZXNwb25zZUgAEj0KFW5vdGlmaWNhdGlvbl9yZXNwb25zZRhnIAEoCzIcLml0ZXJtMi5Ob3RpZmljYXRpb25SZXNwb25zZUgAEj4KFmxpc3Rfc2Vzc2lvbnNfcmVzcG9uc2UYaiABKAsyHC5pdGVybTIuTGlzdFNlc3Npb25zUmVzcG9uc2VIABI2ChJzZW5kX3RleHRfcmVzcG9uc2UYayABKAsyGC5pdGVybTIuU2VuZFRleHRSZXNwb25zZUgAEjgKE2NyZWF0ZV90YWJfcmVzcG9uc2UYbCABKAsyGS5pdGVybTIuQ3JlYXRlVGFiUmVzcG9uc2VIABI4ChNzcGxpdF9wYW5lX3Jlc3BvbnNlGG0gASgLMhkuaXRlcm0yLlNwbGl0UGFuZVJlc3BvbnNlSAASPAoVZ2V0X3Byb3BlcnR5X3Jlc3BvbnNlGHAgASgLMhsuaXRlcm0yLkdldFByb3BlcnR5UmVzcG9uc2VIABI1ChFhY3RpdmF0ZV9yZXNwb25zZRhyIAEoCzIYLml0ZXJtMi5BY3RpdmF0ZVJlc3BvbnNlSAASNQoRdmFyaWFibGVfcmVzcG9uc2UYcyABKAsyGC5pdGVybTIuVmFyaWFibGVSZXNwb25zZUgAEi8KDmZvY3VzX3Jlc3BvbnNlGHUgASgLMhUuaXRlcm0yLkZvY3VzUmVzcG9uc2VIABJDChhpbnZva2VfZnVuY3Rpb25fcmVzcG9uc2UYhAEgASgLMh4uaXRlcm0yLkludm9rZUZ1bmN0aW9uUmVzcG9uc2VIABItCgxub3RpZmljYXRpb24Y6AcgASgLMhQuaXRlcm0yLk5vdGlmaWNhdGlvbkgAQgwKCnN1Ym1lc3NhZ2UiHQoFQ29vcmQSCQoBeBgBIAEoBRIJCgF5GAIgASgDIkYKCkNvb3JkUmFuZ2USHAoFc3RhcnQYASABKAsyDS5pdGVybTIuQ29vcmQSGgoDZW5kGAIgASgLMg0uaXRlcm0yLkNvb3JkIikKBVJhbmdlEhAKCGxvY2F0aW9uGAEgASgDEg4KBmxlbmd0aBgCIAEoAyJdChJXaW5kb3dlZENvb3JkUmFuZ2USJwoLY29vcmRfcmFuZ2UYASABKAsyEi5pdGVybTIuQ29vcmRSYW5nZRIeCgdjb2x1bW5zGAIgASgLMg0uaXRlcm0yLlJhbmdlIh0KBVBvaW50EgkKAXgYASABKAUSCQoBeRgCIAEoBSIlCgRTaXplEg0KBXdpZHRoGAEgASgFEg4KBmhlaWdodBgCIAEoBSJCCgVGcmFtZRIdCgZvcmlnaW4YASABKAsyDS5pdGVybTIuUG9pbnQSGgoEc2l6ZRgCIAEoCzIMLml0ZXJtMi5TaXplInsKCUxpbmVSYW5nZRIcChRzY3JlZW5fY29udGVudHNfb25seRgBIAEoCBIWCg50cmFpbGluZ19saW5lcxgCIAEoBRI4ChR3aW5kb3dlZF9jb29yZF9yYW5nZRgDIAEoCzIaLml0ZXJtMi5XaW5kb3dlZENvb3JkUmFuZ2UiYgoQR2V0QnVmZmVyUmVxdWVzdBIPCgdzZXNzaW9uGAEgASgJEiUKCmxpbmVfcmFuZ2UYAiABKAsyES5pdGVybTIuTGluZVJhbmdlEhYKDmluY2x1ZGVfc3R5bGVzGAMgASgIIjQKCFJHQkNvbG9yEgsKA3JlZBgBIAEoDRINCgVncmVlbhgCIAEoDRIMCgRibHVlGAMgASgNIowDCglDZWxsU3R5bGUSFAoKZmdTdGFuZGFyZBgBIAEoDUgAEi0KC2ZnQWx0ZXJuYXRlGAIgASgOMhYuaXRlcm0yLkFsdGVybmF0ZUNvbG9ySAASIQoFZmdSZ2IYAyABKAsyEC5pdGVybTIuUkdCQ29sb3JIABIUCgpiZ1N0YW5kYXJkGAUgASgNSAESLQoLYmdBbHRlcm5hdGUYBiABKA4yFi5pdGVybTIuQWx0ZXJuYXRlQ29sb3JIARIhCgViZ1JnYhgHIAEoCzIQLml0ZXJtMi5SR0JDb2xvckgBEgwKBGJvbGQYCSABKAgSDQoFZmFpbnQYCiABKAgSDgoGaXRhbGljGAsgASgIEg0KBWJsaW5rGAwgASgIEhEKCXVuZGVybGluZRgNIAEoCBIVCg1zdHJpa2V0aHJvdWdoGA4gASgIEhEKCWludmlzaWJsZRgPIAEoCBIPCgdpbnZlcnNlGBAgASgIEg8KB3JlcGVhdHMYFiABKA1CCQoHZmdDb2xvckIJCgdiZ0NvbG9yIkAKEUNvZGVQb2ludHNQZXJDZWxsEhoKD251bV9jb2RlX3BvaW50cxgBIAEoBToBMRIPCgdyZXBlYXRzGAIgASgFIo0CCgxMaW5lQ29udGVudHMSDAoEdGV4dBgBIAEoCRI3ChRjb2RlX3BvaW50c19wZXJfY2VsbBgCIAMoCzIZLml0ZXJtMi5Db2RlUG9pbnRzUGVyQ2VsbBJOCgxjb250aW51YXRpb24YAyABKA4yIS5pdGVybTIuTGluZUNvbnRlbnRzLkNvbnRpbnVhdGlvbjoVQ09OVElOVUFUSU9OX0hBUkRfRU9MEiAKBXN0eWxlGAQgAygLMhEuaXRlcm0yLkNlbGxTdHlsZSJECgxDb250aW51YXRpb24SGQoVQ09OVElOVUFUSU9OX0hBUkRfRU9MEAESGQoVQ09OVElOVUFUSU9OX1NPRlRfRU9MEAIiogIKEUdldEJ1ZmZlclJlc3BvbnNlEjQKBnN0YXR1cxgBIAEoDjIgLml0ZXJtMi5HZXRCdWZmZXJSZXNwb25zZS5TdGF0dXM6Ak9LEiYKCGNvbnRlbnRzGAMgAygLMhQuaXRlcm0yLkxpbmVDb250ZW50cxIdCgZjdXJzb3IYBCABKAsyDS5pdGVybTIuQ29vcmQSOAoUd2luZG93ZWRfY29vcmRfcmFuZ2UYBiABKAsyGi5pdGVybTIuV2luZG93ZWRDb29yZFJhbmdlIlYKBlN0YXR1cxIGCgJPSxAAEhUKEVNFU1NJT05fTk9UX0ZPVU5EEAESFgoSSU5WQUxJRF9MSU5FX1JBTkdFEAISFQoRUkVRVUVTVF9NQUxGT1JNRUQQAyIVChNMaXN0U2Vzc2lvbnNSZXF1ZXN0InkKDlNlc3Npb25TdW1tYXJ5EhkKEXVuaXF1ZV9pZGVudGlmaWVyGAEgASgJEhwKBWZyYW1lGAIgASgLMg0uaXRlcm0yLkZyYW1lEh8KCWdyaWRfc2l6ZRgDIAEoCzIMLml0ZXJtMi5TaXplEg0KBXRpdGxlGAQgASgJIsEBCg1TcGxpdFRyZWVOb2RlEhAKCHZlcnRpY2FsGAEgASgIEjIKBWxpbmtzGAIgAygLMiMuaXRlcm0yLlNwbGl0VHJlZU5vZGUuU3BsaXRUcmVlTGluaxpqCg1TcGxpdFRyZWVMaW5rEikKB3Nlc3Npb24YASABKAsyFi5pdGVybTIuU2Vzc2lvblN1bW1hcnlIABIlCgRub2RlGAIgASgLMhUuaXRlcm0yLlNwbGl0VHJlZU5vZGVIAEIHCgVjaGlsZCKbAgoUTGlzdFNlc3Npb25zUmVzcG9uc2USNAoHd2luZG93cxgBIAMoCzIjLml0ZXJtMi5MaXN0U2Vzc2lvbnNSZXNwb25zZS5XaW5kb3caeQoGV2luZG93Ei4KBHRhYnMYASADKAsyIC5pdGVybTIuTGlzdFNlc3Npb25zUmVzcG9uc2UuVGFiEhEKCXdpbmRvd19pZBgCIAEoCRIcCgVmcmFtZRgDIAEoCzINLml0ZXJtMi5GcmFtZRIOCgZudW1iZXIYBCABKAUaUgoDVGFiEiMKBHJvb3QYAyABKAsyFS5pdGVybTIuU3BsaXRUcmVlTm9kZRIOCgZ0YWJfaWQYAiABKAkSFgoOdG11eF93aW5kb3dfaWQYBCABKAkiTAoPU2VuZFRleHRSZXF1ZXN0Eg8KB3Nlc3Npb24YASABKAkSDAoEdGV4dBgCIAEoCRIaChJzdXBwcmVzc19icm9hZGNhc3QYAyABKAgibAoQU2VuZFRleHRSZXNwb25zZRIvCgZzdGF0dXMYASABKA4yHy5pdGVybTIuU2VuZFRleHRSZXNwb25zZS5TdGF0dXMiJwoGU3RhdHVzEgYKAk9LEAASFQoRU0VTU0lPTl9OT1RfRk9VTkQQASJbChJHZXRQcm9wZXJ0eVJlcXVlc3QSEwoJd2luZG93X2lkGAEgASgJSAASFAoKc2Vzc2lvbl9pZBgDIAEoCUgAEgwKBG5hbWUYAiABKAlCDAoKaWRlbnRpZmllciKaAQoTR2V0UHJvcGVydHlSZXNwb25zZRIyCgZzdGF0dXMYASABKA4yIi5pdGVybTIuR2V0UHJvcGVydHlSZXNwb25zZS5TdGF0dXMSEgoKanNvbl92YWx1ZRgCIAEoCSI7CgZTdGF0dXMSBgoCT0sQABIVChFVTlJFQ09HTklaRURfTkFNRRABEhIKDklOVkFMSURfVEFSR0VUEAIiQAoUUHJvbXB0TW9uaXRvclJlcXVlc3QSKAoFbW9kZXMYASADKA4yGS5pdGVybTIuUHJvbXB0TW9uaXRvck1vZGUiYAoWVmFyaWFibGVNb25pdG9yUmVxdWVzdBIMCgRuYW1lGAEgASgJEiQKBXNjb3BlGAIgASgOMhUuaXRlcm0yLlZhcmlhYmxlU2NvcGUSEgoKaWRlbnRpZmllchgDIAEoCSL/AQoTTm90aWZpY2F0aW9uUmVxdWVzdBIPCgdzZXNzaW9uGAEgASgJEhEKCXN1YnNjcmliZRgCIAEoCBIzChFub3RpZmljYXRpb25fdHlwZRgDIAEoDjIYLml0ZXJtMi5Ob3RpZmljYXRpb25UeXBlEkIKGHZhcmlhYmxlX21vbml0b3JfcmVxdWVzdBgGIAEoCzIeLml0ZXJtMi5WYXJpYWJsZU1vbml0b3JSZXF1ZXN0SAASPgoWcHJvbXB0X21vbml0b3JfcmVxdWVzdBgJIAEoCzIcLml0ZXJtMi5Qcm9tcHRNb25pdG9yUmVxdWVzdEgAQgsKCWFyZ3VtZW50cyL1AQoUTm90aWZpY2F0aW9uUmVzcG9uc2USMwoGc3RhdHVzGAEgASgOMiMuaXRlcm0yLk5vdGlmaWNhdGlvblJlc3BvbnNlLlN0YXR1cyKnAQoGU3RhdHVzEgYKAk9LEAASFQoRU0VTU0lPTl9OT1RfRk9VTkQQARIVChFSRVFVRVNUX01BTEZPUk1FRBACEhIKDk5PVF9TVUJTQ1JJQkVEEAMSFgoSQUxSRUFEWV9TVUJTQ1JJQkVEEAQSIwofRFVQTElDQVRFX1NFUlZFUl9PUklHSU5BVEVEX1JQQxAFEhYKEklOVkFMSURfSURFTlRJRklFUhAGIisKGFNjcmVlblVwZGF0ZU5vdGlmaWNhdGlvbhIPCgdzZXNzaW9uGAEgASgJIloKGFByb21wdE5vdGlmaWNhdGlvblByb21wdBITCgtwbGFjZWhvbGRlchgBIAEoCRIpCgZwcm9tcHQYAiABKAsyGS5pdGVybTIuR2V0UHJvbXB0UmVzcG9uc2UiMQoeUHJvbXB0Tm90aWZpY2F0aW9uQ29tbWFuZFN0YXJ0Eg8KB2NvbW1hbmQYASABKAkiLgocUHJvbXB0Tm90aWZpY2F0aW9uQ29tbWFuZEVuZBIOCgZzdGF0dXMYASABKAUi+gEKElByb21wdE5vdGlmaWNhdGlvbhIPCgdzZXNzaW9uGAEgASgJEjIKBnByb21wdBgCIAEoCzIgLml0ZXJtMi5Qcm9tcHROb3RpZmljYXRpb25Qcm9tcHRIABI/Cg1jb21tYW5kX3N0YXJ0GAMgASgLMiYuaXRlcm0yLlByb21wdE5vdGlmaWNhdGlvbkNvbW1hbmRTdGFydEgAEjsKC2NvbW1hbmRfZW5kGAQgASgLMiQuaXRlcm0yLlByb21wdE5vdGlmaWNhdGlvbkNvbW1hbmRFbmRIABIYChB1bmlxdWVfcHJvbXB0X2lkGAUgASgJQgcKBWV2ZW50IiwKFk5ld1Nlc3Npb25Ob3RpZmljYXRpb24SEgoKc2Vzc2lvbl9pZBgBIAEoCSIyChxUZXJtaW5hdGVTZXNzaW9uTm90aWZpY2F0aW9uEhIKCnNlc3Npb25faWQYASABKAkiWQoZTGF5b3V0Q2hhbmdlZE5vdGlmaWNhdGlvbhI8ChZsaXN0X3Nlc3Npb25zX3Jlc3BvbnNlGAEgASgLMhwuaXRlcm0yLkxpc3RTZXNzaW9uc1Jlc3BvbnNlIoQDChhGb2N1c0NoYW5nZWROb3RpZmljYXRpb24SHAoSYXBwbGljYXRpb25fYWN0aXZlGAEgASgISAASOQoGd2luZG93GAIgASgLMicuaXRlcm0yLkZvY3VzQ2hhbmdlZE5vdGlmaWNhdGlvbi5XaW5kb3dIABIWCgxzZWxlY3RlZF90YWIYAyABKAlIABIRCgdzZXNzaW9uGAQgASgJSAAa2gEKBldpbmRvdxJLCg13aW5kb3dfc3RhdHVzGAEgASgOMjQuaXRlcm0yLkZvY3VzQ2hhbmdlZE5vdGlmaWNhdGlvbi5XaW5kb3cuV2luZG93U3RhdHVzEhEKCXdpbmRvd19pZBgCIAEoCSJwCgxXaW5kb3dTdGF0dXMSHgoaVEVSTUlOQUxfV0lORE9XX0JFQ0FNRV9LRVkQABIeChpURVJNSU5BTF9XSU5ET1dfSVNfQ1VSUkVOVBABEiAKHFRFUk1JTkFMX1dJTkRPV19SRVNJR05FRF9LRVkQAkIHCgVldmVudCJ9ChtWYXJpYWJsZUNoYW5nZWROb3RpZmljYXRpb24SJAoFc2NvcGUYASABKA4yFS5pdGVybTIuVmFyaWFibGVTY29wZRISCgppZGVudGlmaWVyGAIgASgJEgwKBG5hbWUYAyABKAkSFgoOanNvbl9uZXdfdmFsdWUYBCABKAki9wMKDE5vdGlmaWNhdGlvbhJEChpzY3JlZW5fdXBkYXRlX25vdGlmaWNhdGlvbhgCIAEoCzIgLml0ZXJtMi5TY3JlZW5VcGRhdGVOb3RpZmljYXRpb24SNwoTcHJvbXB0X25vdGlmaWNhdGlvbhgDIAEoCzIaLml0ZXJtMi5Qcm9tcHROb3RpZmljYXRpb24SQAoYbmV3X3Nlc3Npb25fbm90aWZpY2F0aW9uGAYgASgLMh4uaXRlcm0yLk5ld1Nlc3Npb25Ob3RpZmljYXRpb24STAoedGVybWluYXRlX3Nlc3Npb25fbm90aWZpY2F0aW9uGAcgASgLMiQuaXRlcm0yLlRlcm1pbmF0ZVNlc3Npb25Ob3RpZmljYXRpb24SRgobbGF5b3V0X2NoYW5nZWRfbm90aWZpY2F0aW9uGAggASgLMiEuaXRlcm0yLkxheW91dENoYW5nZWROb3RpZmljYXRpb24SRAoaZm9jdXNfY2hhbmdlZF9ub3RpZmljYXRpb24YCSABKAsyIC5pdGVybTIuRm9jdXNDaGFuZ2VkTm90aWZpY2F0aW9uEkoKHXZhcmlhYmxlX2NoYW5nZWRfbm90aWZpY2F0aW9uGAwgASgLMiMuaXRlcm0yLlZhcmlhYmxlQ2hhbmdlZE5vdGlmaWNhdGlvbiI9ChBHZXRQcm9tcHRSZXF1ZXN0Eg8KB3Nlc3Npb24YASABKAkSGAoQdW5pcXVlX3Byb21wdF9pZBgCIAEoCSLkAgoRR2V0UHJvbXB0UmVzcG9uc2USNAoGc3RhdHVzGAEgASgOMiAuaXRlcm0yLkdldFByb21wdFJlc3BvbnNlLlN0YXR1czoCT0sSGQoRd29ya2luZ19kaXJlY3RvcnkYBSABKAkSDwoHY29tbWFuZBgGIAEoCRI1Cgxwcm9tcHRfc3RhdGUYByABKA4yHy5pdGVybTIuR2V0UHJvbXB0UmVzcG9uc2UuU3RhdGUSEwoLZXhpdF9zdGF0dXMYCSABKA0SGAoQdW5pcXVlX3Byb21wdF9pZBgKIAEoCSJWCgZTdGF0dXMSBgoCT0sQABIVChFTRVNTSU9OX05PVF9GT1VORBABEhUKEVJFUVVFU1RfTUFMRk9STUVEEAISFgoSUFJPTVBUX1VOQVZBSUxBQkxFEAMiLwoFU3RhdGUSCwoHRURJVElORxAAEgsKB1JVTk5JTkcQARIMCghGSU5JU0hFRBACIjIKD1Byb2ZpbGVQcm9wZXJ0eRILCgNrZXkYASABKAkSEgoKanNvbl92YWx1ZRgCIAEoCSKeAQoQQ3JlYXRlVGFiUmVxdWVzdBIUCgxwcm9maWxlX25hbWUYASABKAkSEQoJd2luZG93X2lkGAIgASgJEhEKCXRhYl9pbmRleBgDIAEoDRI6ChljdXN0b21fcHJvZmlsZV9wcm9wZXJ0aWVzGAUgAygLMhcuaXRlcm0yLlByb2ZpbGVQcm9wZXJ0eRISCgpzZWxlY3RfdGFiGAYgASgIIvABChFDcmVhdGVUYWJSZXNwb25zZRIwCgZzdGF0dXMYASABKA4yIC5pdGVybTIuQ3JlYXRlVGFiUmVzcG9uc2UuU3RhdHVzEhEKCXdpbmRvd19pZBgCIAEoCRIOCgZ0YWJfaWQYAyABKAUSEgoKc2Vzc2lvbl9pZBgEIAEoCSJyCgZTdGF0dXMSBgoCT0sQABIYChRJTlZBTElEX1BST0ZJTEVfTkFNRRABEhUKEUlOVkFMSURfV0lORE9XX0lEEAISFQoRSU5WQUxJRF9UQUJfSU5ERVgQAxIYChRNSVNTSU5HX1NVQlNUSVRVVElPThAEIqwBChBTcGxpdFBhbmVSZXF1ZXN0Eg8KB3Nlc3Npb24YASABKAkSQAoPc3BsaXRfZGlyZWN0aW9uGAIgASgOMicuaXRlcm0yLlNwbGl0UGFuZVJlcXVlc3QuU3BsaXREaXJlY3Rpb24SFQoGYmVmb3JlGAMgASgIOgVmYWxzZSIuCg5TcGxpdERpcmVjdGlvbhIMCghWRVJUSUNBTBAAEg4KCkhPUklaT05UQUwQASLVAQoRU3BsaXRQYW5lUmVzcG9uc2USMAoGc3RhdHVzGAEgASgOMiAuaXRlcm0yLlNwbGl0UGFuZVJlc3BvbnNlLlN0YXR1cxISCgpzZXNzaW9uX2lkGAIgAygJInoKBlN0YXR1cxIGCgJPSxAAEhUKEVNFU1NJT05fTk9UX0ZPVU5EEAESGAoUSU5WQUxJRF9QUk9GSUxFX05BTUUQAhIQCgxDQU5OT1RfU1BMSVQQAxIlCiFNQUxGT1JNRURfQ1VTVE9NX1BST0ZJTEVfUFJPUEVSVFkQBCKWAgoPQWN0aXZhdGVSZXF1ZXN0EhMKCXdpbmRvd19pZBgBIAEoCUgAEhAKBnRhYl9pZBgCIAEoCUgAEhQKCnNlc3Npb25faWQYAyABKAlIABIaChJvcmRlcl93aW5kb3dfZnJvbnQYBCABKAgSEgoKc2VsZWN0X3RhYhgFIAEoCBIWCg5zZWxlY3Rfc2Vzc2lvbhgGIAEoCBIxCgxhY3RpdmF0ZV9hcHAYByABKAsyGy5pdGVybTIuQWN0aXZhdGVSZXF1ZXN0LkFwcBo9CgNBcHASGQoRcmFpc2VfYWxsX3dpbmRvd3MYASABKAgSGwoTaWdub3Jpbmdfb3RoZXJfYXBwcxgCIAEoCEIMCgppZGVudGlmaWVyIn0KEEFjdGl2YXRlUmVzcG9uc2USLwoGc3RhdHVzGAEgASgOMh8uaXRlcm0yLkFjdGl2YXRlUmVzcG9uc2UuU3RhdHVzIjgKBlN0YXR1cxIGCgJPSxAAEhIKDkJBRF9JREVOVElGSUVSEAESEgoOSU5WQUxJRF9PUFRJT04QAiKLAQoPVmFyaWFibGVSZXF1ZXN0EhQKCnNlc3Npb25faWQYASABKAlIABIoCgNzZXQYAiADKAsyGy5pdGVybTIuVmFyaWFibGVSZXF1ZXN0LlNldBILCgNnZXQYAyADKAkaIgoDU2V0EgwKBG5hbWUYASABKAkSDQoFdmFsdWUYAiABKAlCBwoFc2NvcGUi5QEKEFZhcmlhYmxlUmVzcG9uc2USLwoGc3RhdHVzGAEgASgOMh8uaXRlcm0yLlZhcmlhYmxlUmVzcG9uc2UuU3RhdHVzEg4KBnZhbHVlcxgCIAMoCSKPAQoGU3RhdHVzEgYKAk9LEAASFQoRU0VTU0lPTl9OT1RfRk9VTkQQARIQCgxJTlZBTElEX05BTUUQAhIRCg1NSVNTSU5HX1NDT1BFEAMSEQoNVEFCX05PVF9GT1VORBAEEhgKFE1VTFRJX0dFVF9ESVNBTExPV0VEEAUSFAoQV0lORE9XX05PVF9GT1VORBAGIp8BChVJbnZva2VGdW5jdGlvblJlcXVlc3QSNgoGbWV0aG9kGAcgASgLMiQuaXRlcm0yLkludm9rZUZ1bmN0aW9uUmVxdWVzdC5NZXRob2RIABISCgppbnZvY2F0aW9uGAUgASgJEhMKB3RpbWVvdXQYBiABKAE6Ai0xGhoKBk1ldGhvZBIQCghyZWNlaXZlchgBIAEoCUIJCgdjb250ZXh0ItkCChZJbnZva2VGdW5jdGlvblJlc3BvbnNlEjUKBWVycm9yGAEgASgLMiQuaXRlcm0yLkludm9rZUZ1bmN0aW9uUmVzcG9uc2UuRXJyb3JIABI5CgdzdWNjZXNzGAIgASgLMiYuaXRlcm0yLkludm9rZUZ1bmN0aW9uUmVzcG9uc2UuU3VjY2Vzc0gAGlQKBUVycm9yEjUKBnN0YXR1cxgBIAEoDjIlLml0ZXJtMi5JbnZva2VGdW5jdGlvblJlc3BvbnNlLlN0YXR1cxIUCgxlcnJvcl9yZWFzb24YAiABKAkaHgoHU3VjY2VzcxITCgtqc29uX3Jlc3VsdBgBIAEoCSJICgZTdGF0dXMSCwoHVElNRU9VVBABEgoKBkZBSUxFRBACEhUKEVJFUVVFU1RfTUFMRk9STUVEEAMSDgoKSU5WQUxJRF9JRBAEQg0KC2Rpc3Bvc2l0aW9uIg4KDEZvY3VzUmVxdWVzdCJICg1Gb2N1c1Jlc3BvbnNlEjcKDW5vdGlmaWNhdGlvbnMYASADKAsyIC5pdGVybTIuRm9jdXNDaGFuZ2VkTm90aWZpY2F0aW9uKkcKDkFsdGVybmF0ZUNvbG9yEgsKB0RFRkFVTFQQABIUChBSRVZFUlNFRF9ERUZBVUxUEAMSEgoOU1lTVEVNX01FU1NBR0UQBCrZAQoQTm90aWZpY2F0aW9uVHlwZRIbChdOT1RJRllfT05fU0NSRUVOX1VQREFURRACEhQKEE5PVElGWV9PTl9QUk9NUFQQAxIZChVOT1RJRllfT05fTkVXX1NFU1NJT04QBhIfChtOT1RJRllfT05fVEVSTUlOQVRFX1NFU1NJT04QBxIbChdOT1RJRllfT05fTEFZT1VUX0NIQU5HRRAIEhoKFk5PVElGWV9PTl9GT0NVU19DSEFOR0UQCRIdChlOT1RJRllfT05fVkFSSUFCTEVfQ0hBTkdFEAwqQwoRUHJvbXB0TW9uaXRvck1vZGUSCgoGUFJPTVBUEAESEQoNQ09NTUFORF9TVEFSVBACEg8KC0NPTU1BTkRfRU5EEAMqOgoNVmFyaWFibGVTY29wZRILCgdTRVNTSU9OEAESBwoDVEFCEAISCgoGV0lORE9XEAMSBwoDQVBQEAQ`),Ii=I(G,0),Li=I(G,1),Ri=I(G,2),zi=I(G,3),Bi=I(G,5),Vi=I(G,9),Hi=I(G,10),Ui=I(G,16),Wi=I(G,20);let Gi=function(e){return e[e.OK=0]=`OK`,e[e.SESSION_NOT_FOUND=1]=`SESSION_NOT_FOUND`,e}({});const Ki=I(G,22),qi=I(G,24),Ji=I(G,25),Yi=I(G,26),Xi=I(G,42),Zi=I(G,44),Qi=I(G,46),$i=I(G,46,0),ea=I(G,48),ta=I(G,52),na=P(A(),`Library`,`Application Support`,`iTerm2`,`private`,`socket`);var ra=class extends Be{opts;ws=null;connecting=null;nextId=1n;pending=new Map;log;constructor(e){super(),this.opts=e,this.log=e.log.child({unit:`iterm2`})}get connected(){return this.ws?.readyState===He.OPEN}connect(){if(this.connecting)return this.connecting;let e=this.open().finally(()=>{this.connecting===e&&(this.connecting=null)});return this.connecting=e,e}async open(){let e=this.opts.appName??`Shellbell`,t=this.opts.socketPath??na,n=this.opts.cookieTimeoutMs??12e4,{cookie:r,key:i}=await ia((this.opts.cookieProvider??(()=>Pi(e,n)))(),n,`iTerm2 did not answer the API cookie request`),a={origin:`ws://localhost/`,"x-iterm2-library-version":`shellbell 0.1.0`,"x-iterm2-disable-auth-ui":`true`,"x-iterm2-advisory-name":e,"x-iterm2-cookie":r,"x-iterm2-key":i},o=this.opts.connectTimeoutMs??1e4,s=this.opts.url?new He(this.opts.url,[`api.iterm2.com`],{headers:a,handshakeTimeout:o}):new He(`ws://localhost/`,[`api.iterm2.com`],{headers:a,handshakeTimeout:o,createConnection:()=>Ve({path:t})});this.ws=s,await new Promise((e,t)=>{let n=()=>{s.off(`open`,i),s.off(`error`,a),s.off(`unexpected-response`,o),s.off(`close`,c)},r=e=>{n(),s.on(`error`,()=>{}),s.terminate(),this.ws===s&&(this.ws=null),t(e)},i=()=>{n(),e()},a=e=>r(e),o=(e,t)=>{t.destroy(),e.destroy(),r(Error(`iTerm2 API responded HTTP ${t.statusCode}`))},c=()=>r(Error(`iTerm2 connection closed before open`));s.once(`open`,i),s.once(`error`,a),s.once(`unexpected-response`,o),s.once(`close`,c)}),s.on(`message`,(e,t)=>{if(!t)return;let n;try{n=qe(Li,new Uint8Array(e))}catch(e){this.log.warn(`undecodable message from iTerm2`,{err:le(e)});return}if(n.submessage.case===`notification`){this.emit(`notification`,n.submessage.value);return}let r=this.pending.get(n.id);r&&(clearTimeout(r.timer),this.pending.delete(n.id),r.resolve(n))}),s.on(`close`,()=>{for(let[e,t]of this.pending)t.ws===s&&(clearTimeout(t.timer),t.reject(Error(`iTerm2 connection closed`)),this.pending.delete(e));this.ws===s&&(this.ws=null),this.emit(`close`)}),s.on(`error`,e=>this.log.warn(`iTerm2 socket error`,{err:le(e)})),this.log.info(`connected to iTerm2 API`)}close(){this.ws?.close(),this.ws=null}request(e){let t=this.ws;if(!t||t.readyState!==He.OPEN)return Promise.reject(Error(`iTerm2 not connected`));let n=this.nextId++,r=Ke(Ii,{id:n,submessage:e});return new Promise((i,a)=>{let o=setTimeout(()=>{this.pending.delete(n),a(Error(`iTerm2 request timeout (${e.case})`))},this.opts.requestTimeoutMs??5e3);this.pending.set(n,{resolve:i,reject:a,timer:o,ws:t}),t.send(Je(Ii,r),{binary:!0})})}};function ia(e,t,n){let r,i=new Promise((e,i)=>{r=setTimeout(()=>i(Error(n)),t)});return Promise.race([e,i]).finally(()=>clearTimeout(r))}async function aa(e,t=fetch){let n;try{let t=new URL(e),r={"ws:":`http:`,"wss:":`https:`,"http:":`http:`,"https:":`https:`}[t.protocol];if(!r||!t.hostname)return!1;t.protocol=r,t.username=``,t.password=``,t.pathname=`/healthz`,t.search=``,t.hash=``,n=t.toString()}catch{return!1}let r=new AbortController,i=null,a=setTimeout(()=>{r.abort(),i?.cancel().catch(()=>{})},5e3);try{let e=await t(n,{redirect:`manual`,signal:r.signal});if(!e.body||(i=e.body.getReader(),e.status!==200))return!1;let a=[],o=0;for(;;){let{done:e,value:t}=await i.read();if(e)break;if(o+=t.byteLength,o>4096)return!1;a.push(t)}return!r.signal.aborted&&Buffer.concat(a,o).toString(`utf8`)===`ok`}catch{return!1}finally{if(clearTimeout(a),r.abort(),i){i.cancel().catch(()=>{});try{i.releaseLock()}catch{}}}}const oa=65536,sa=16384,ca=`# shellbell-systemd-v1 `,la=Re.string().max(sa).refine(e=>{for(let t of e){let e=t.codePointAt(0);if(e<32||e>=127&&e<=159||e>=55296&&e<=57343)return!1}return!0}),ua=la.refine(N),da=Re.strictObject({v:Re.literal(1),machineId:Re.string().regex(/^[0-9a-f]{32}$/).refine(e=>e!==`0`.repeat(32)),nodePath:ua.refine(e=>!/["'\\]/.test(e)),cliPath:ua,stateDir:ua,runtimeRoot:ua,serviceInstance:Re.uuid(),path:la.refine(e=>{let t=e.split(`:`);return t.every(N)&&new Set(t).size===t.length})});function K(){throw Error(`shellbell: invalid or foreign systemd unit`)}function fa(e){return`"${e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`).replaceAll(`%`,`%%`)}"`}function pa(e,t){return`Environment=${fa(`${e}=${t}`)}`}function ma(e){let t=da.safeParse(e);t.success||K();let n=t.data,r=2;for(let[e,t]of Object.entries(n))r+=e.length+3+(r===2?0:1),r+=typeof t==`number`?1:Buffer.byteLength(t)+2+[...t].filter(e=>e===`"`||e===`\\`).length;r>sa&&K();let i=JSON.stringify(n);Buffer.byteLength(i)>sa&&K();let a=Buffer.from([ca+Buffer.from(i).toString(`base64url`),`[Unit]`,`Description=Shellbell terminal host`,`ConditionHost=${n.machineId}`,`StartLimitIntervalSec=60s`,`StartLimitBurst=3`,``,`[Service]`,`Type=exec`,`ExecStart=${[`:${n.nodePath}`,n.cliPath,`start`,`--service`].map(fa).join(` `)}`,pa(`SHELLBELL_DIR`,n.stateDir),pa(`SHELLBELL_SERVICE_INSTANCE`,n.serviceInstance),pa(`XDG_RUNTIME_DIR`,n.runtimeRoot),pa(`PATH`,n.path),`Restart=on-failure`,`RestartSec=5s`,`TimeoutStopSec=15s`,`UMask=0077`,`StandardInput=null`,`StandardOutput=null`,`StandardError=journal`,`KillMode=control-group`,``,`[Install]`,`WantedBy=default.target`,``].join(`
|
|
81
|
+
`));return a.length>oa&&K(),a}function ha(e){try{e.byteLength>oa&&K();let t=Buffer.from(e),n=t.subarray(0,t.indexOf(10)).toString(`utf8`);n.startsWith(ca)||K();let r=n.slice(23);(r.length>21846||!/^[A-Za-z0-9_-]+$/.test(r))&&K();let i=Buffer.from(r,`base64url`);(i.length>sa||i.toString(`base64url`)!==r)&&K();let a=da.parse(JSON.parse(i.toString(`utf8`)));return ma(a).equals(t)||K(),a}catch{return K()}}function ga(e,t){let n=l(e);n&&(!n.isDirectory()||n.isSymbolicLink()||n.uid!==t||n.mode&18)&&K()}function _a(e,t){ua.safeParse(e).success||K();let n=l(e)?Ee(e):c(e);return ga(n,t),n}function va(e){let{uid:t,hostScope:n}=e.identity;(!Number.isSafeInteger(t)||t<=0||!/^[0-9a-f]{32}$/.test(n))&&K();let r=_a(e.home,t),i=_a(e.env.XDG_CONFIG_HOME&&N(e.env.XDG_CONFIG_HOME)?e.env.XDG_CONFIG_HOME:P(r,`.config`),t),a=P(i,`systemd`,`user`);for(let e of[P(i,`systemd`),a])ga(e,t);let o=`shellbell-${n}.service`,s=P(a,o),c=l(s);return c&&(!c.isFile()||c.isSymbolicLink()||c.uid!==t||(c.mode&4095)!=384)&&K(),{uid:t,home:r,configRoot:i,unitName:o,unitDir:a,definitionPath:s,enablementPath:P(a,`default.target.wants`,o),managerRuntimeRoot:`/run/user/${t}`}}function q(){throw Error(`shellbell: unsafe, foreign or concurrently changed systemd files`)}function ya(e,t){return i(e,t)&&e.mode===t.mode&&e.uid===t.uid&&e.size===t.size&&e.mtimeMs===t.mtimeMs&&e.ctimeMs===t.ctimeMs}var ba=class{location;machineId;constructor(e,t){this.location=e,this.machineId=t}directory(e,t=!1){let n=l(e);return!n&&t&&(this.directory(M(e),!0),xe(e,{mode:448}),n=l(e)),n&&(!n.isDirectory()||n.isSymbolicLink()||n.uid!==this.location.uid||n.mode&18)&&q(),n}parents(e=!1){let t=[this.location.home,this.location.configRoot,P(this.location.configRoot,`systemd`),this.location.unitDir,M(this.location.enablementPath)],n=[];for(let r of t){let t=this.directory(r,e&&r!==M(this.location.enablementPath));t&&n.push({path:r,stat:t})}return n}inspect(){let e=this.parents(),t=l(this.location.definitionPath),n=null;if(t){let e=S(this.location.definitionPath,65536,this.location.uid),r=ha(e);(r.machineId!==this.machineId||!ya(t,l(this.location.definitionPath)))&&q(),n={stat:t,raw:e,definition:r}}let r=l(this.location.enablementPath),a=null;if(r){let e=r.isSymbolicLink()?Te(this.location.enablementPath):null;ya(r,l(this.location.enablementPath))||q(),a={stat:r,target:e,owned:r.uid===this.location.uid&&e===this.location.definitionPath}}for(let t of e){let e=this.directory(t.path);(!e||!i(t.stat,e))&&q()}return{unit:n,link:a,parents:e}}assertUnchanged(e){let t=this.inspect();for(let t of e.parents??[]){let e=this.directory(t.path);(!e||!i(t.stat,e))&&q()}(!!t.unit!=!!e.unit||!!t.link!=!!e.link)&&q(),t.unit&&e.unit&&(!ya(t.unit.stat,e.unit.stat)||!t.unit.raw.equals(e.unit.raw))&&q(),t.link&&e.link&&(!ya(t.link.stat,e.link.stat)||t.link.target!==e.link.target)&&q()}matchesFragment(e){try{let t=l(e);return!!t&&t.isFile()&&!t.isSymbolicLink()&&t.uid===this.location.uid&&(t.mode&4095)==384&&P(Ee(M(e)),j(e))===this.location.definitionPath}catch{return!1}}publish(e,t){(t.machineId!==this.machineId||e.link&&!e.link.owned)&&q();let n=ma(t);this.assertUnchanged(e),this.parents(!0);let r=`${this.location.definitionPath}.tmp-${F()}`,a;try{let t=Se(r,E.O_WRONLY|E.O_CREAT|E.O_EXCL|E.O_NOFOLLOW,384);try{a=l(r),Me(t,n),ye(t)}finally{ve(t)}this.assertUnchanged(e),e.unit?De(r,this.location.definitionPath):be(r,this.location.definitionPath)}finally{let e=l(r);a&&e&&i(a,e)&&je(r)}return this.inspect()}setEnabled(e,t){return this.assertUnchanged(e),e.link&&!e.link.owned&&q(),t===!!e.link?e:(t?(e.unit||q(),this.directory(M(this.location.enablementPath),!0),this.assertUnchanged(e),Ae(this.location.definitionPath,this.location.enablementPath)):(this.assertUnchanged(e),je(this.location.enablementPath)),this.inspect())}remove(e){return this.assertUnchanged(e),e.link?.owned&&q(),e.unit&&je(this.location.definitionPath),this.inspect()}restore(e,t){try{this.assertUnchanged(t);let n=t;e.unit&&!n.unit?.raw.equals(e.unit.raw)&&(n=this.publish(n,e.unit.definition)),!!n.link!=!!e.link&&(n=this.setEnabled(n,!!e.link)),e.unit||this.remove(n)}catch{try{this.parents(),e.unit&&Me(`${this.location.definitionPath}.recovery-${F()}`,e.unit.raw,{flag:`wx`,mode:384})}catch{}throw Error(`shellbell: unresolved systemd file recovery; inspect owned artifacts before retrying`)}}};const xa=[`LoadState`,`ActiveState`,`SubState`,`MainPID`,`UnitFileState`,`FragmentPath`,`DropInPaths`,`NeedDaemonReload`,`ConditionResult`],Sa=[`--user`,`--no-pager`,`--no-ask-password`],Ca=new Set([16914836,61267,1481003842,2435016766]),J=()=>Error(`shellbell: systemd command failed`);function wa(e){for(let t of e){let e=t.codePointAt(0);if(e<32||e>=127&&e<=159||e>=55296&&e<=57343)return!1}return!0}const Ta=()=>({available:!1,loadState:`unknown`,activeState:`unknown`,subState:`unknown`,mainPid:null,unitFileState:`unknown`,fragmentPath:``,dropInPaths:``,needDaemonReload:!0,conditionResult:!1,diagnostic:`systemd user manager unavailable or returned unsupported state`});function Ea(e){for(let t of[`/usr/bin`,`/bin`]){let n=P(t,e);try{return ge(n,E.X_OK),n}catch{}}throw J()}const Da=(e,t,n)=>new Promise((r,i)=>{let a=he(e,[...t],{shell:!1,env:n.env,stdio:[`ignore`,`pipe`,`pipe`]}),o=0,s=[],c=!1,l=!1,u,d=setTimeout(p,n.timeoutMs);function f(e){c||(c=!0,clearTimeout(d),clearTimeout(u),a.stdout.destroy(),a.stderr.destroy(),l||e==null?i(J()):r({exitCode:e,stdout:Buffer.concat(s)}))}function p(){c||l||(l=!0,a.kill(`SIGTERM`),u=setTimeout(()=>{a.kill(`SIGKILL`),f()},250))}function m(e,t){if(!(c||l)){if(o+=e.length,o>n.maxOutputBytes){p();return}t&&s.push(Buffer.from(e))}}a.stdout.on(`data`,e=>m(e,!0)),a.stderr.on(`data`,e=>m(e,!1)),a.on(`error`,()=>f()),a.on(`close`,e=>f(e))});function Oa(e){if(e.length>65536)throw J();let t=new TextDecoder(`utf-8`,{fatal:!0}).decode(e),n=t.endsWith(`
|
|
82
|
+
`)?t.slice(0,-1).split(`
|
|
83
|
+
`):t.split(`
|
|
84
|
+
`),r=new Map;for(let e of n){let t=e.indexOf(`=`),n=e.slice(0,t),i=e.slice(t+1);if(t<0||!xa.includes(n)||r.has(n)||!wa(i))throw J();r.set(n,i)}if(r.size!==xa.length)throw J();let i=e=>r.get(e);for(let[e,t]of Object.entries({LoadState:[`stub`,`loaded`,`not-found`,`bad-setting`,`error`,`merged`,`masked`],ActiveState:[`active`,`reloading`,`inactive`,`failed`,`activating`,`deactivating`,`maintenance`],SubState:[`dead`,`condition`,`start-pre`,`start`,`start-post`,`running`,`exited`,`reload`,`stop`,`stop-watchdog`,`stop-sigterm`,`stop-sigkill`,`stop-post`,`final-sigterm`,`final-sigkill`,`failed`,`auto-restart`,`cleaning`],UnitFileState:[``,`enabled`,`enabled-runtime`,`linked`,`linked-runtime`,`alias`,`masked`,`masked-runtime`,`static`,`disabled`,`indirect`,`generated`,`transient`,`bad`]}))if(!t.includes(i(e)))throw J();if(!/^(0|[1-9][0-9]*)$/.test(i(`MainPID`)))throw J();let a=Number(i(`MainPID`));if(!Number.isSafeInteger(a))throw J();for(let e of[`NeedDaemonReload`,`ConditionResult`])if(![`yes`,`no`].includes(i(e)))throw J();let o=i(`FragmentPath`);if(o&&!N(o))throw J();return{available:!0,loadState:i(`LoadState`),activeState:i(`ActiveState`),subState:i(`SubState`),mainPid:a||null,unitFileState:i(`UnitFileState`),fragmentPath:o,dropInPaths:i(`DropInPaths`),needDaemonReload:i(`NeedDaemonReload`)===`yes`,conditionResult:i(`ConditionResult`)===`yes`}}function ka(e){return`unix:path=${[...Buffer.from(e)].map(e=>/[A-Za-z0-9_./-]/.test(String.fromCharCode(e))?String.fromCharCode(e):`%${e.toString(16).padStart(2,`0`)}`).join(``)}`}function Aa(e){let t={...e.location},n=e.run??Da;async function r(r,i){try{let{uid:a}=t;if(!Number.isSafeInteger(a)||a<=0||a!==process.getuid?.()||a!==process.geteuid?.()||!/^shellbell-[0-9a-f]{32}\.service$/.test(t.unitName))throw J();for(let e of[t.home,t.configRoot,t.managerRuntimeRoot])if(!N(e)||!wa(e))throw J();d(t.managerRuntimeRoot,a);let o=e.runtimeFsType?.(t.managerRuntimeRoot)??ke(t.managerRuntimeRoot).type;if(!Ca.has(Number(o)))throw J();let s=await n(e.run?`/usr/bin/${r}`:Ea(r),i,{timeoutMs:3e4,maxOutputBytes:65536,env:{HOME:t.home,XDG_CONFIG_HOME:t.configRoot,XDG_RUNTIME_DIR:t.managerRuntimeRoot,DBUS_SESSION_BUS_ADDRESS:ka(P(t.managerRuntimeRoot,`bus`)),PATH:`/usr/bin:/bin`,LANG:`C`,LC_ALL:`C`}});if(s.exitCode!==0||s.stdout.length>65536)throw J();return s.stdout}catch{throw J()}}return{async observe(){try{return Oa(await r(`systemctl`,[...Sa,`show`,`--property=${xa.join(`,`)}`,t.unitName]))}catch{return Ta()}},async execute(e){if(![`start`,`stop`,`daemon-reload`].includes(e))throw J();await r(`systemctl`,[...Sa,e,...e===`daemon-reload`?[]:[t.unitName]])},async linger(){try{let e=(await r(`loginctl`,[`--no-pager`,`--no-ask-password`,`show-user`,String(t.uid),`--property=Linger`,`--value`])).toString(`utf8`);if(e===`yes
|
|
85
|
+
`||e===`yes`)return`yes`;if(e===`no
|
|
86
|
+
`||e===`no`)return`no`}catch{}return`unknown`}}}const Y=e=>e.activeState===`inactive`||e.activeState===`failed`,ja=e=>[`enabled`,`enabled-runtime`].includes(e.unitFileState);function X(e){throw Error(`shellbell: ${e}`)}var Ma=class extends Error{},Na=class{options;machine;location;files;manager;readiness;clock;constructor(e){this.options=e,this.machine=ae(e.machine),this.location=va({identity:this.machine,env:e.env,home:e.home??A()}),this.files=new ba(this.location,this.machine.machineId),this.manager=e.manager??Aa({location:this.location,runtimeFsType:e.runtimeFsType}),this.readiness=new w(e),this.clock=e.clock??{now:()=>Xe.now(),sleep:e=>new Promise(t=>setTimeout(t,e))}}select(e,t,r=!1){let i=e.unit?.definition;i&&this.options.env.SHELLBELL_DIR!==void 0&&c(this.options.env.SHELLBELL_DIR)!==i.stateDir&&X(`SHELLBELL_DIR conflicts with installed service state; explicit migration is required`);let a;try{let e={...this.options.env,...i?{SHELLBELL_DIR:i.stateDir,...r?{}:{XDG_RUNTIME_DIR:i.runtimeRoot}}:{}};a=(this.options.selectPaths??(e=>n({...this.options.machine,env:e,home:this.options.home,runtimeFsType:this.options.runtimeFsType})))(e),(a.linuxHost.uid!==this.machine.uid||a.linuxHost.hostDigest!==this.machine.hostDigest||i&&a.dir!==i.stateDir)&&X(`selected Linux paths do not match owned service`)}catch{return t&&X(`Linux service runtime/state selection is unsafe or unavailable`),{degraded:!0}}try{let e=h(a);return{paths:a,degraded:!1,expected:{computerFp:e.fp,stateDir:a.dir,...i?{serviceInstance:i.serviceInstance}:{}}}}catch{return t&&X(`Linux host state is not ready; restore initialized credentials before granting service access`),{paths:a,degraded:!0}}}ownedManager(e,t,n=!1){return!t.available||t.dropInPaths!==``||t.needDaemonReload?!1:n&&!e.unit&&[``,`disabled`,`enabled`,`enabled-runtime`].includes(t.unitFileState)&&t.loadState===`not-found`&&t.fragmentPath===``&&Y(t)&&t.mainPid===null?!0:![`disabled`,`enabled`,`enabled-runtime`,`linked`,`linked-runtime`].includes(t.unitFileState)||![`inactive`,`failed`,`active`,`activating`,`deactivating`].includes(t.activeState)?!1:!!e.unit&&t.loadState===`loaded`&&this.files.matchesFragment(t.fragmentPath)}assertManager(e,t,n=!1){if(this.files.assertUnchanged(e),!t.available)throw new Ma(`shellbell: systemd manager ownership is unavailable, foreign or unresolved; inspect exact unit discovery and overrides`);this.ownedManager(e,t,n)||X(`systemd manager ownership is unavailable, foreign or unresolved; inspect exact unit discovery and overrides`)}async local(e,t,n,r=500){if(!t.paths)return{kind:`unverified`,local:null,diagnostic:`Local certification degraded; runtime is unsafe or unavailable`};let i=await this.readiness.observe(t.paths.sock,t.expected?{...t.expected,...n.mainPid?{pid:n.mainPid}:{}}:void 0,r);return i.local&&e.unit&&(i.local.process.pid!==n.mainPid||!ce(i.local,{computerFp:t.expected?.computerFp??i.local.process.computerFp,stateDir:e.unit.definition.stateDir,serviceInstance:e.unit.definition.serviceInstance}))?{kind:`foreign`,local:i.local,diagnostic:`Local endpoint contradicts owned manager job`}:i}async result(e,t,n,r=!1){let i=await this.manager.observe(),a=this.ownedManager(e,i,!0),o=await this.local(e,t,i),s=await this.manager.observe(),c=!0;try{this.files.assertUnchanged(e)}catch{c=!1}let l=c&&a&&this.ownedManager(e,s,!0)&&i.mainPid===s.mainPid&&i.activeState===s.activeState,u=!!e.unit&&l&&!t.degraded&&i.activeState===`active`&&i.mainPid!==null&&i.conditionResult&&s.conditionResult&&o.kind===`verified`;r&&(!l||!Y(s)||s.mainPid!==null||t.paths&&o.kind!==`absent`)&&X(`service stop final confirmation is unresolved; current job or endpoint is not verified stopped`);let d=ja(s)&&!e.link?.owned||e.link&&!e.link.owned;return{manager:`systemd`,unitName:this.location.unitName,definitionPath:this.location.definitionPath,installed:!!e.unit,enabled:ja(s),startupEnabled:s.available?ja(s):null,autostartConfigured:!!e.link?.owned,activeState:s.activeState,managedPid:s.mainPid,ownership:!l||o.kind===`foreign`?`foreign`:t.degraded?`degraded`:e.unit?`verified`:`none`,ready:u,local:o.local,linger:await this.manager.linger(),...n||d||t.degraded||!l||o.diagnostic?{diagnostic:[n,d?`Remaining external enablement is outside Shellbell's owned link`:void 0,t.degraded?`Local identity/runtime certification degraded; credentials were not repaired`:void 0,l?void 0:`Manager ownership is unresolved`,o.diagnostic].filter(Boolean).join(`; `)}:{}}}async installedRuntime(){let e=this.files.inspect().unit?.definition;return e?{nodePath:e.nodePath,cliPath:e.cliPath,stateDir:e.stateDir}:null}async status(){let e=this.files.inspect();return this.result(e,this.select(e,!1))}async serialized(e,t,n){let i=this.files.inspect(),a=this.select(i,e,t),s=async()=>{let t;try{return a.paths&&(r(a.paths),t=o(P(a.paths.runtimeDir,`service`))),this.files.assertUnchanged(i),e&&h(a.paths),await n(i,a,!!t)}finally{t?.()}},c=a.paths?.dir??i.unit?.definition.stateDir;return c?ee({stateDir:c,uid:this.machine.uid,create:t,startupPreference:e=>e.autostartConfigured},s):s()}async execute(e,t){this.files.assertUnchanged(t);try{await this.manager.execute(e)}catch{X(`systemd ${e} failed or timed out; manager effect may be unresolved`)}}async install(){let e=(this.options.resolveRuntime??v)(),t=[`/usr/local/bin`,`/usr/bin`,`/bin`],n=(this.options.env.PATH??``).split(`:`).filter(e=>N(e)&&!t.includes(e));return this.serialized(!0,!0,async(r,i)=>{let a=r.unit?.definition,o={v:1,machineId:this.machine.machineId,nodePath:e.nodePath,cliPath:e.cliPath,stateDir:i.paths.dir,runtimeRoot:M(M(i.paths.runtimeDir)),serviceInstance:a?.serviceInstance??F(),path:[...new Set([M(e.nodePath),...n,...t])].join(`:`)},s=ma(o),c=await this.manager.observe();if(this.assertManager(r,c,!r.unit),r.unit?.raw.equals(s))return this.result(r,i);(!Y(c)||c.mainPid!==null)&&X(`active service definition cannot be updated; stop, install, then start explicitly`),(await this.local(r,i,c)).kind!==`absent`&&X(`local endpoint ownership is foreign or unverified; stop foreground owner before install`);let l=await this.manager.observe();this.assertManager(r,l,!r.unit),(!Y(l)||l.mainPid!==null)&&X(`active service job changed during install admission; stop before updating`),a&&(o.serviceInstance=F());let u;try{return u=this.files.publish(r,o),await this.execute(`daemon-reload`,u),this.assertManager(u,await this.manager.observe()),await this.result(u,i)}catch{if(u){this.files.restore(r,u);try{await this.manager.execute(`daemon-reload`)}catch{X(`systemd install failed; definition restored but manager reload remains unresolved`)}}X(`systemd install failed; owned definition restored where possible, inspect manager discovery`)}})}enable(){return this.link(!0)}disable(){return this.link(!1)}link(e){return this.serialized(e,!1,async(t,n,r)=>{let i=await this.manager.observe();if(this.assertManager(t,i,!t.unit&&!e),!t.unit&&e&&X(`service is not installed; run service install first`),t.link&&!t.link.owned)return e&&X(`foreign autostart leaf prevents service enablement`),this.result(t,n,`Foreign autostart artifact remains; inspect it explicitly`);if(!r)return this.result(t,n,`Owned autostart cleanup remains; restore a safe local runtime before changing files`);if(!!t.link===e)return this.result(t,n);let a=this.files.setEnabled(t,e);try{await this.execute(`daemon-reload`,a),this.assertManager(a,await this.manager.observe(),!a.unit)}catch{e&&this.files.restore(t,a),X(`systemd ${e?`enable`:`disable`} reload failed; inspect remaining manager state`)}return this.result(a,n)})}start(){return this.run(`start`)}restart(){return this.run(`restart`)}stop(){return this.run(`stop`)}uninstall(){return this.run(`uninstall`)}async stopped(e,t,n){let r=this.clock.now()+1e4;for(;this.clock.now()<r;){let i=await this.manager.observe();this.assertManager(e,i),i.mainPid!==null&&i.mainPid!==n&&X(`service stop manager job changed; ownership unresolved`);let a=await this.local(e,t,{...i,mainPid:n},Math.min(500,r-this.clock.now()));a.kind===`foreign`&&X(`service stop ownership changed; endpoint is foreign`);let o=await this.manager.observe();if(this.assertManager(e,o),(o.mainPid!==null&&o.mainPid!==n||Y(i)&&!Y(o))&&X(`service stop manager job changed during local probe; ownership unresolved`),Y(o)&&o.mainPid===null&&(!t.paths||a.kind===`absent`))return;await this.clock.sleep(Math.min(100,Math.max(0,r-this.clock.now())))}X(`service stop timed out; stopped state remains unresolved`)}async stopOwned(e,t){let n=await this.manager.observe();this.assertManager(e,n);let r=await this.local(e,t,n);r.kind===`foreign`&&X(`local endpoint ownership is foreign; refusing service stop`);let i=await this.manager.observe();this.assertManager(e,i),(i.mainPid!==n.mainPid||Y(n)&&!Y(i))&&X(`service stop ownership changed during local probe`),(!Y(i)||i.mainPid!==null||t.paths&&r.kind!==`absent`)&&(await this.execute(`stop`,e),await this.stopped(e,t,n.mainPid))}async ready(e,t,n={}){let r=this.clock.now()+1e4;for(;this.clock.now()<r;){let i=await this.manager.observe();this.assertManager(e,i),n.pid!==void 0&&i.mainPid!==n.pid&&X(`service readiness manager job changed`),i.mainPid!==null&&(n.pid??=i.mainPid);let a=await this.local(e,t,i,Math.min(500,r-this.clock.now()));a.kind===`foreign`&&X(`service readiness ownership is foreign`);let o=await this.manager.observe();if(this.assertManager(e,o),o.mainPid!==i.mainPid&&X(`service readiness manager job changed`),o.activeState===`active`&&o.conditionResult&&o.mainPid!==null&&a.kind===`verified`)return a.local;await this.clock.sleep(Math.min(100,Math.max(0,r-this.clock.now())))}X(`service readiness timed out`)}async cleanupStart(e,t,n){let r=await this.manager.observe();this.assertManager(e,r);let i=await this.local(e,t,r),a=await this.manager.observe();this.assertManager(e,a),(a.mainPid!==r.mainPid||Y(r)&&!Y(a))&&X(`start ownership changed during local probe; cleanup unresolved`),!(Y(a)&&a.mainPid===null&&i.kind===`absent`)&&((r.mainPid===null||n.pid!==void 0&&n.pid!==r.mainPid||![`verified`,`absent`].includes(i.kind))&&X(`start ownership unresolved; no cleanup stop was attempted`),await this.execute(`stop`,e),await this.stopped(e,t,r.mainPid))}run(e){let t=e===`stop`||e===`uninstall`;return this.serialized(!t,!1,async(n,r,i)=>{let a=await this.manager.observe();if(this.assertManager(n,a,!n.unit&&t),!n.unit)return t||X(`service is not installed; run service install first`),this.result(n,r);let o=await this.local(n,r,a);if(o.kind===`foreign`&&X(`local endpoint ownership is foreign`),e!==`start`&&await this.stopOwned(n,r),t){let t=n;e===`uninstall`&&i&&((!t.link||t.link.owned)&&(t=this.files.setEnabled(t,!1)),t=this.files.remove(t),await this.execute(`daemon-reload`,t),this.assertManager(t,await this.manager.observe(),!0));let a=e===`uninstall`?i?`Service uninstalled; credentials remain unchanged`:`Service stopped; owned definition and autostart cleanup remain until runtime is safe`:`Service stopped; if enabled, it may start after a later user-manager restart`;return this.result(t,r,a,!0)}if(e===`start`&&a.activeState===`active`){await this.ready(n,r);let e=await this.result(n,r);return e.ready||X(`service start readiness changed during final confirmation`),e}e===`start`&&(!Y(a)||a.mainPid!==null||o.kind!==`absent`)&&X(`service start ownership is unresolved; stop the foreground or pending owner first`);let s=await this.manager.observe();this.assertManager(n,s),(!Y(s)||s.mainPid!==null)&&X(`service start manager job changed before command; ownership unresolved`);let c={};try{await this.execute(`start`,n),await this.ready(n,r,c);let e=await this.result(n,r);return e.ready||X(`service start readiness changed during final confirmation`),e}catch{try{await this.cleanupStart(n,r,c)}catch{X(`service start failed; ownership or cleanup remains unresolved`)}X(`service start failed; newly started owned job was stopped`)}})}};const Pa=We(pe);function Fa(e){let t=/(\d+)\.(\d+)/.exec(e);return t?Number(t[1])+Number(t[2])/100:null}function Ia(e){return+!!e.some(e=>e.severity===`error`)}function Z(e,t){return{name:e,ok:!0,severity:`pass`,detail:t}}function Q(e,t,n){return{name:e,ok:!0,severity:`warning`,detail:t,...n?{fix:n}:{}}}function $(e,t,n){return{name:e,ok:!1,severity:`error`,detail:t,...n?{fix:n}:{}}}function La(e,t,n,r){return t?{...Z(e,`connected to the local agent`),...n?{required:n}:{}}:n?{...$(e,`required backend is not connected; ${r.detail}`,r.fix),required:!0}:r}function Ra(e,t){for(let n of t.PATH?.split(Ne)??[])if(n)try{return ge(P(n,e),E.X_OK),!0}catch{}return!1}async function za(e){return(await Pa(`tmux`,[`-V`],{env:e,timeout:3e3,maxBuffer:65536})).stdout}async function Ba(e){return Ai({socketPath:ar(e),herdrOnPath:()=>Ra(`herdr`,e)})}function Va(e,t){if(!e.installed||!e.definition)return{env:t,context:`current shell setup`};let n=e.definition.environment;return{env:{PATH:n.PATH,HERDR_SOCKET_PATH:n.HERDR_SOCKET_PATH,XDG_CONFIG_HOME:n.XDG_CONFIG_HOME},context:`installed service setup`}}function Ha(e){try{let t=process.getuid?.();return t!==void 0&&new b({stateDir:c(e),uid:t}).inspect()?.mode===`desktop`}catch{return!1}}function Ua(e,t,n){return e.loaded&&!e.installed?$(`service manager`,`loaded service has no installed definition`):!e.installed&&Ha(n)?Z(`service manager`,`the Shellbell app runs this service`):e.installed?e.definition?e.loaded?e.definition.serviceInstance?t?t.process.serviceInstance===e.definition.serviceInstance?Z(`service manager`,`loaded job matches the local service instance`):$(`service manager`,`loaded job does not match the local service instance`,`stop the foreground owner and restart the service`):Q(`service manager`,`loaded job cannot be matched until local control responds`):Q(`service manager`,`legacy service definition has no verifiable instance marker`,`reinstall the service to record a service instance`):Q(`service manager`,`installed service is stopped`,"run `shellbell start`"):$(`service manager`,`installed service definition is unreadable`,`reinstall the service after checking its definition`):Q(`service manager`,`no service definition installed; foreground agent can still run`,"run `shellbell install` to run Shellbell in the background")}function Wa(e){let t=`installed=${e.installed}; enabled=${e.enabled}; active=${e.activeState}; authenticated ready=${e.ready}; linger=${e.linger}; ownership=${e.ownership}${e.diagnostic?`; ${e.diagnostic}`:``}`;return e.activeState===`unknown`?Q(`service manager`,t,`restore access to the current user's systemd manager; foreground readiness is independent`):e.ownership===`foreign`?$(`service manager`,t,`inspect the exact unit and any drop-ins; Shellbell refuses foreign definitions`):e.ready?Z(`service manager`,t):Q(`service manager`,t,"run `shellbell install` to run Shellbell in the background; foreground readiness is independent")}function Ga(e,t){let n=e=>t.includes(e)?{...$(e,`required backend unavailable until service state is selected`),required:!0}:Q(e,`unavailable until service state is selected`);return[Q(`identity`,e),$(`service manager`,e),Q(`control`,`unavailable until service state is selected`),Q(`relay`,`unavailable until service state is selected`),n(`iterm2`),n(`tmux`),n(`herdr`),Q(`terminal readiness`,`unavailable until service state is selected`)]}async function Ka(e,r={}){let i=(e.platform??process.platform)===`linux`,a=Q(`service manager`,`Linux systemd user-manager inspection unavailable; foreground readiness is independent`,"run `shellbell status` and inspect the current user's systemd manager"),o=e.requiredBackends.filter(e=>e!==`tmux`).map(e=>({...$(e,e===`herdr`?`Shellbell's Herdr backend is not yet qualified for Linux delivery (Herdr itself supports Linux)`:`iTerm2 is not supported on Linux`),required:!0})),s=null,c;if(i){let t,i={...e.env,SHELLBELL_DIR:e.requestedStateDir??e.env.SHELLBELL_DIR},s=e=>(i=e,t=(r.selectLinuxPaths??(e=>n({env:e})))(e),t);try{a=Wa(await(r.inspectLinuxService??(()=>new Na({env:i,selectPaths:s}).status()))(s))}catch{}let l;try{let e=t??s(i);c=e;let n=de(e);l=n.status===`ready`?Z(`host state`,`Linux host state admitted`):$(`host state`,n.reason??`Linux host state is absent`,"absent state: run `shellbell install`; otherwise inspect existing state before recovery")}catch{l=$(`host state`,`Linux state or runtime selection is unsafe or unavailable`,`use a nonroot matching real/effective user, a valid machine ID, and a private 0700 local runtime directory`)}if(l.severity===`error`)return[l,a,Q(`control`,`unavailable until host state is admitted`),Q(`relay`,`unavailable until host state is admitted`),...o,e.requiredBackends.includes(`tmux`)?{...$(`tmux`,`required backend unavailable until host state is admitted`),required:!0}:Q(`tmux`,`unavailable until host state is admitted`)]}else{try{s=await(r.inspectManager??(()=>t().inspect()))()}catch{return Ga(`service manager inspection failed; state unavailable`,e.requiredBackends)}try{c=se(s,e.requestedStateDir,e.defaultStateDir)}catch{return Ga(`state selection unavailable; check SHELLBELL_DIR against installed service`,e.requiredBackends)}}let l,d=null;try{let e=ie(c);e?(d=e.fp,l=Z(`identity`,i?`valid admitted Linux identity`:`valid identity at ${c.identity}`)):l=$(`identity`,`identity missing at ${c.identity}`,`start Shellbell once to create an identity`)}catch{l=$(`identity`,i?`Linux identity invalid or unreadable`:`identity invalid or unreadable at ${c.identity}`,`restore the original identity file; do not replace paired keys`)}let f=null,p;if(!d)p=$(`control`,`cannot verify local process without a valid identity`);else try{let t=await(r.controlStatus??(e=>u(e,`status`,void 0,{timeoutMs:500,maxResponseBytes:65536})))(c.sock),n=fe.safeParse(t);if(!n.success)p=$(`control`,`local endpoint returned malformed or unsupported status`);else if(!ce(n.data,{computerFp:d,stateDir:c.dir}))p=$(`control`,`local endpoint belongs to a different identity or state directory`);else{f=n.data;let t=f.process.agentVersion;p=e.version&&t!==e.version?Q(`control`,`Shellbell ${t} is running, but ${e.version} is installed`,f.process.serviceInstance?`run \`shellbell install\` to switch to ${e.version}`:`stop Shellbell in its terminal window and start it again`):Z(`control`,`Shellbell ${t} answers; identity and state verified`)}}catch{p=$(`control`,`local endpoint is absent or did not return bounded status`,`start Shellbell, or inspect the configured service`)}let m=i?a:Ua(s,f,c.dir),h=null,g=null;try{g=x(c).relayUrl}catch{h=$(`relay`,i?`Linux configuration invalid or unreadable`:`configuration invalid or unreadable at ${c.config}`,`repair the existing config without replacing identity files`)}if(!h){if(f?.relayOnline)h=Z(`relay`,`local agent reports relay connected`);else{let e=`configured relay`,t=!1;try{let n=new URL(g);[`ws:`,`wss:`,`http:`,`https:`].includes(n.protocol)&&(e=`${n.protocol===`ws:`?`http:`:n.protocol===`wss:`?`https:`:n.protocol}//${n.host}/healthz`,t=await(r.relayHealth??aa)(g))}catch{}h=$(`relay`,`local agent is not relay-connected; ${e} ${t?`is reachable`:`is not confirmed reachable`} (HTTP health does not prove WebSocket authorization)`,`check the relay URL, network, and running agent`)}}let{env:_,context:v}=i?{env:e.env,context:`current shell setup`}:Va(s,e.env),y=new Set(e.requiredBackends),b=e=>f?.backends.find(t=>t.name===e)?.connected===!0,ee=Q(`iterm2`,`${v}: iTerm2 API socket unavailable`,`enable iTerm2 Python API, then start Shellbell to authorize access`);if(!i&&!b(`iterm2`))try{(r.itermSocketExists??(()=>D(na)))()&&(ee=Q(`iterm2`,`${v}: API socket exists but agent is disconnected`,`start Shellbell to authorize iTerm2 API access`))}catch{ee=$(`iterm2`,`iTerm2 API socket inspection failed`)}let te=La(`iterm2`,b(`iterm2`),y.has(`iterm2`),ee),ne=Q(`tmux`,`${v}: tmux is unavailable`,`install tmux 3.2 or newer`);if(!b(`tmux`))try{let e=Fa(await(r.tmuxVersion??za)(_));ne=e===null||e<3.02?$(`tmux`,`${v}: tmux version is unsupported or unrecognizable`,`install tmux 3.2 or newer`):Q(`tmux`,`${v}: tmux 3.2+ is installed but not connected`,`start a tmux session and Shellbell`)}catch(e){ne=e.code===`ENOENT`?Q(`tmux`,`${v}: tmux executable not found`,`install tmux 3.2 or newer`):$(`tmux`,`${v}: tmux version probe failed`,`check installed tmux and the saved PATH`)}let re=La(`tmux`,b(`tmux`),y.has(`tmux`),ne),S=Q(`herdr`,`${v}: Herdr is unavailable`,er);if(!i&&!b(`herdr`))try{let e=await(r.checkHerdr??Ba)(_);S=e.ok?e.detail===`not installed (optional)`?Q(`herdr`,`${v}: Herdr not found on PATH`,er):e.detail===`installed but not running (optional)`?Q(`herdr`,`${v}: Herdr is installed but not running`,`start Herdr and Shellbell`):Q(`herdr`,`${v}: Herdr API available but agent is disconnected`,`start Shellbell with Herdr enabled`):$(`herdr`,`${v}: Herdr API is broken or unsupported`,tr)}catch{S=$(`herdr`,`${v}: Herdr API probe failed`,tr)}let ae=La(`herdr`,b(`herdr`),y.has(`herdr`),S),C=f?await(r.terminalSetup??Ya)(c.sock).catch(()=>null):null,w=!i&&!!C&&ft(C),oe=(e,t)=>{let n=C?.find(e=>e.name===t);if(!n?.issue)return e;let{status:r,fix:i}=ut(n,`command-line`,{noneUsable:w});return n.connected?{...Q(t,r,i),...e.required?{required:!0}:{}}:La(t,!1,y.has(t),Q(t,r,i))},T=(i?b(`tmux`):f?.terminalReady)?Z(`terminal readiness`,`at least one backend connected to the verified local agent`):w?$(`terminal readiness`,pt(`command-line`).status,pt(`command-line`).fix):$(`terminal readiness`,`no backend connected to a verified local agent`,`start Shellbell with a supported terminal backend`);return[...i?[Z(`host state`,`Linux host state admitted`)]:[],l,m,p,h,...i?o:[oe(te,`iterm2`)],oe(re,`tmux`),...i?[]:[oe(ae,`herdr`)],T,Ja(c.dir,e.env.HOME),...qa(f)]}function qa(e){return(e?.newerAgents??[]).map(e=>Z(`agent version`,`${e.name} ${e.version} is newer than Shellbell was tested with. Chat still works; tell us if something looks wrong.`))}function Ja(e,t){try{let n=Bn(Mn(e,t||void 0)),r=n.filter(e=>e.state===`needs-setup`);if(r.length)return Q(`coding agents`,`${r.map(e=>e.name).join(`, `)} can't show full history on your phone yet`,`run shellbell agents setup`);let i=n.filter(e=>e.state===`ready`);return Z(`coding agents`,i.length?`full history ready for ${i.map(e=>e.name).join(`, `)}`:`no agents need setup`)}catch{return Q(`coding agents`,`couldn't check coding agents`,`run shellbell agents`)}}async function Ya(e){let t=await a(e);try{return await t.terminals()}finally{t.close()}}export{Tt as $,ji as A,Bn as B,Zi as C,Ni as D,Bi as E,Qn as F,ln as G,Wn as H,Zn as I,Gt as J,cn as K,Kn as L,Kr as M,Wr as N,W as O,br as P,Bt as Q,Mn as R,Gi as S,ea as T,Hn as U,Gn as V,Un as W,Lt as X,Rt as Y,Ht as Z,Vi as _,Na as a,ct as at,qi as b,ra as c,ot as ct,zi as d,St as et,Ri as f,Ki as g,Hi as h,Ka as i,mt as it,Ei as j,Pi as k,Qi as l,ta as m,Ia as n,vt as nt,Ma as o,ut as ot,Xi as p,Wt as q,Fa as r,xt as rt,na as s,at as st,Ja as t,bt as tt,$i as u,Ui as v,Ji as w,Wi as x,Yi as y,Vn as z};
|