shellbell 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{C as e,Dt as t,F as n,H as r,I as i,L as a,Nt as o,P as s,S as c,U as l,V as u,_ as d,at as f,b as p,c as m,dt as h,g,h as _,m as v,o as y,rt as b,ut as x,x as S}from"./service-lifecycle-BCnZrcYZ.js";import{a as C,i as w,o as T,r as E,t as D}from"./service-entry-CMjd9ogv.js";import{spawn as O}from"node:child_process";import{closeSync as k,constants as A,openSync as j,realpathSync as M}from"node:fs";import{userInfo as N}from"node:os";import{dirname as P,join as F,resolve as I}from"node:path";import{fileURLToPath as L}from"node:url";import{createHash as R,randomUUID as z}from"node:crypto";import{performance as B}from"node:perf_hooks";function V(e,t,n,r){let o=!1,s=!1,c=0,l=!1,u=!1,f,m,h,y,b=()=>y||(o=!0,clearTimeout(h),C(),e.off(`data`,T),e.off(`end`,E),e.destroy(),y=Promise.resolve(n.close()).finally(()=>{t.end()}),y.catch(()=>{}),y),x=e=>{if(o)return!1;let n=a(e),r=t.writableLength;if(!n||t.destroyed||!Number.isFinite(r)||r<0||r+n.byteLength>262144)return b(),!1;try{t.write(n)}catch{return b(),!1}return!0},S=(e,t)=>x({v:1,id:e,ok:!1,error:{code:t}}),C=n.onEvent(e=>{let t=d.safeParse(e);if(!t.success){b();return}if(u){f?b():f=t.data;return}if(t.data.flowId!==m){b();return}x(t.data),t.data.event===`pairing.closed`&&(m=void 0)}),w=new i({onError:b,onLine(e){if(o)return;let t;try{t=JSON.parse(e)}catch{b();return}let i=p.safeParse(t);if(!i.success){typeof t==`object`&&t&&`id`in t&&typeof t.id==`number`&&Number.isSafeInteger(t.id)&&t.id>c&&S(t.id,`v`in t&&t.v!==1?`unsupported-version`:`bad-request`),b();return}let d=i.data;if(d.id<=c){b();return}if(c=d.id,!s){if(d.cmd!==`hello`){S(d.id,`handshake-required`),b();return}s=!0,clearTimeout(h),x({v:1,id:d.id,ok:!0,data:_.hello.parse({version:1,agentVersion:r.agentVersion,capabilities:[`status`,`settings`,`lifecycle`,`pairing`,`devices`,`diagnostics`]})});return}if(d.cmd===`hello`){b();return}if(l){S(d.id,`busy`),b();return}l=!0,u=d.cmd===`pairing.open`;let y=`args`in d;h=setTimeout(()=>{S(d.id,y?`delivery-unknown`:`timeout`),b()},d.cmd.startsWith(`service.`)||d.cmd.startsWith(`desktop.`)||d.cmd.startsWith(`ownership.`)?6e4:5e3),n.execute(d).then(e=>{if(o)return;let t=_[d.cmd].safeParse(e);if(!t.success){S(d.id,y?`delivery-unknown`:`operation-failed`),b();return}if(d.cmd===`pairing.open`&&(m=t.data.flowId),!a({v:1,id:d.id,ok:!0,data:t.data})){S(d.id,`response-too-large`),b();return}if(x({v:1,id:d.id,ok:!0,data:t.data}),u=!1,f){if(f.flowId!==m){b();return}x(f),f.event===`pairing.closed`&&(m=void 0),f=void 0}},e=>{let t=e instanceof v&&g.safeParse(e.code).success?e.code:`operation-failed`;S(d.id,t),u=!1,f=void 0}).finally(()=>{clearTimeout(h),l=!1})}}),T=e=>w.push(e),E=()=>{w.finish(),b()};return e.on(`data`,T),e.once(`end`,E),e.once(`error`,b),t.once(`error`,b),h=setTimeout(b,5e3),{close:b}}var H=class{options;owned;starting;closed=!1;readiness;clock;constructor(e){this.options=e,this.readiness=e.readiness??new y,this.clock=e.clock??{now:()=>B.now(),sleep:e=>new Promise(t=>setTimeout(t,e))}}async inspect(e){let t=this.owned;if(t&&!t.exited&&(t.selection.serviceInstance!==e.serviceInstance||t.selection.bundlePath!==e.bundlePath))throw new v(`conflict`);return{registration:`not-registered`,loaded:!!t&&!t.exited,pid:t&&!t.exited?t.child.pid??null:null,bundlePath:e.bundlePath}}start(e){return this.closed||this.starting||this.owned&&!this.owned.exited?Promise.reject(new v(`busy`)):!S.safeParse(e).success||e.mode!==`desktop`?Promise.reject(new v(`conflict`)):(this.starting=this.launch(structuredClone(e)).finally(()=>{this.starting=void 0}),this.starting)}async launch(e){this.owned&&await this.stopOwned(this.owned);let t=await(this.options.admitBundle??C)(e.bundlePath);if(t.agentVersion!==e.agentVersion||this.closed||(await this.readiness.observe(x(e.stateDir).sock)).kind!==`absent`||this.closed)throw new v(`conflict`);let n=O(t.nodePath,[t.servicePath,`desktop`],{cwd:this.options.homeDir,env:E(e,this.options.homeDir,process.env),stdio:[`ignore`,`pipe`,`pipe`,`pipe`]}),r={child:n,pipe:n.stdio[3],selection:e,exited:!1};this.owned=r,n.once(`exit`,()=>{r.exited=!0}),n.once(`error`,()=>{r.exited=!0}),n.stdout?.resume(),n.stderr?.resume(),r.pipe.on(`error`,()=>{});try{r.pipe.write(`${JSON.stringify({v:1,instance:e.serviceInstance})}\n`);let t=this.clock.now()+1e4;for(;this.clock.now()<t;){if(r.exited||this.closed||!n.pid)throw new v(`unavailable`);let i=await this.readiness.observe(x(e.stateDir).sock,{stateDir:e.stateDir,computerFp:e.computerFp,serviceInstance:e.serviceInstance,pid:n.pid},Math.min(500,t-this.clock.now()));if(i.kind===`verified`&&i.local?.process.agentVersion===e.agentVersion&&!r.exited&&!this.closed)return this.inspect(e);if(i.kind===`foreign`)throw new v(`conflict`);await this.clock.sleep(Math.min(25,Math.max(0,t-this.clock.now())))}throw new v(`unavailable`)}catch(e){throw await this.stopOwned(r),e}}async stop(e){let t=this.owned;if(!t){if(e.runtime)throw new v(`conflict`);return}let n=e.runtime,r=t.selection;if(!n||n.pid!==t.child.pid||n.stateDir!==r.stateDir||n.computerFp!==r.computerFp||n.serviceInstance!==r.serviceInstance||n.agentVersion!==r.agentVersion)throw new v(`conflict`);await this.stopOwned(t)}async close(){this.closed=!0,this.owned&&await this.stopOwned(this.owned),await this.starting?.catch(()=>{}),this.owned&&await this.stopOwned(this.owned)}stopOwned(e){return e.stopping||=this.finishStop(e).finally(()=>{e.stopping=void 0}),e.stopping}async finishStop(e){e.pipe.end();let t=this.options.stopTimeoutMs??1e4,n=this.clock.now()+t,r=n-t/2,i=!1;for(;!e.exited&&this.clock.now()<n;){if(!i&&this.clock.now()>=r){let t=e.selection,r=await this.readiness.observe(x(t.stateDir).sock,{pid:e.child.pid,stateDir:t.stateDir,computerFp:t.computerFp,serviceInstance:t.serviceInstance},Math.min(500,Math.max(1,n-this.clock.now())));if(r.kind===`foreign`)throw new v(`conflict`);r.kind===`verified`&&r.local?.process.agentVersion===t.agentVersion&&this.owned===e&&!e.exited&&(e.child.kill(`SIGTERM`),i=!0)}await this.clock.sleep(Math.min(25,Math.max(0,n-this.clock.now())))}if(!e.exited)throw new v(`unavailable`);if((await this.readiness.observe(x(e.selection.stateDir).sock)).kind!==`absent`)throw new v(`conflict`);e.pipe.destroy(),this.owned===e&&(this.owned=void 0)}};async function U(e,t,n){await n.preflight();let r=n=>e.publish({v:1,mode:n===`prepared`?e.current?.mode??t.target:t.target,consented:!0,startupEnabled:e.current?.startupEnabled??!1,transition:{...t,phase:n}});e.current?.transition||r(`prepared`);try{await n.stopSource(),await n.verifyAbsent(),r(`source-stopped`),await n.startDestination(),r(`destination-started`),await n.complete(),e.publish({v:1,mode:t.target,consented:!0,startupEnabled:e.current.startupEnabled,transition:null})}catch(e){throw r(`recovery-required`),e}}var W=class{options;desktop;readiness;newId;client;listeners=new Set;observedStateDirs=new WeakMap;closed=!1;constructor(e){this.options=e,this.desktop=e.desktop??new H({uid:e.uid,homeDir:e.homeDir,readiness:e.readiness,admitBundle:e.inspectBundle}),this.readiness=e.readiness??new y,this.newId=e.newId??z}async status(){try{return await this.observe(this.options.store.inspect(),await this.options.platform.inspectLegacy())}catch(e){throw this.error(e)}}stateDirectory(e,t){return this.recordedStateDirectory(e,t)??this.options.defaultStateDir}recordedStateDirectory(e,t){return e?.selection?.stateDir??e?.transition?.destination?.stateDir??e?.transition?.source?.stateDir??t??e?.recovery?.stateDir??null}statusStateDirectory(e){return this.observedStateDirs.get(e)??e.selection?.stateDir??e.legacy.stateDir??this.options.defaultStateDir}async observe(t,n){let r=t?.selection??null,i=r?.bundlePath??t?.transition?.source?.bundlePath??this.options.bundlePath,[a,o,s]=await Promise.all([this.options.platform.inspect(`manual`,i),this.options.platform.inspect(`persistent`,i),this.options.platform.loginStatus(this.options.bundlePath).catch(()=>`unknown`)]),l=this.recordedStateDirectory(t,n.definition?.stateDir),u=l??this.options.defaultStateDir,d=D(u,this.options.uid),f=r?.mode===`desktop`?await this.desktop.inspect(r):{registration:`not-registered`,loaded:!1,pid:null,bundlePath:null},p=r?r.mode===`desktop`?f:e(r.mode)===`manual`?a:o:null,h=d?{stateDir:u,computerFp:d.fp,serviceInstance:r?.serviceInstance??n.definition?.serviceInstance??null,...p?.pid?{pid:p.pid}:{}}:void 0,g=await this.readiness.observe(x(u).sock,h);if(g.kind===`verified`&&(!d||r&&(!p?.loaded||!p.pid||d.fp!==r.computerFp))&&(g.kind=`foreign`),r){let t=r.mode===`desktop`?await this.desktop.inspect(r):await this.options.platform.inspect(e(r.mode),i);JSON.stringify(t)!==JSON.stringify(p)&&(g.kind=`unverified`,g.local=null)}let _=new m({stateDir:u,uid:this.options.uid}).inspect(),v=c.parse({desktopLogin:s,desktop:f,ownership:{revision:_?.revision??null,mode:_?.mode??(r||t?.transition?`legacy-native`:n.installed||n.loaded?`headless`:null),consented:_?.consented??!1,startupEnabled:_?.startupEnabled??null,transition:_?.transition??null},revision:t?.revision??null,selection:r,transition:t?.transition?{id:t.transition.id,action:t.transition.action,phase:t.transition.phase}:null,recoveryAvailable:!!t?.recovery,manualRecoveryAvailable:(t?.transition?.destination?.mode===`persistent`&&r?.serviceInstance===t.transition.destination.serviceInstance&&[`start`,`restart`].includes(t.transition.action)&&!t.transition.restoreLegacy||this.isManualRecovery(t)&&r?.serviceInstance===t?.transition?.source?.serviceInstance)&&!a.loaded&&!o.loaded&&g.kind===`absent`&&!n.installed&&!n.loaded,legacy:{installed:n.installed,loaded:n.loaded,stateDir:n.definition?.stateDir??null},manual:a,persistent:o,local:{kind:g.kind,status:g.local}});return l&&this.observedStateDirs.set(v,l),v}error(e){return e instanceof v?e:e instanceof b?new v(e.code===`busy`?`busy`:e.code===`invalid`?`invalid-config`:`unsafe-state`):e instanceof s?e.code===`server-error`?new v(e.serverCode===`runtime-mismatch`||e.serverCode===`configuration-mismatch`?`conflict`:e.serverCode===`pairing-busy`?`busy`:`operation-failed`):new v(e.code===`protocol-error`||e.code===`closed`?`unavailable`:e.code):new v(`operation-failed`)}exact(e,t){return e===null||t===null?e===t:[`pid`,`agentVersion`,`computerFp`,`stateDir`,`serviceInstance`].every(n=>e[n]===t[n])}expect(e,t,n=!1){if(e.revision!==t.revision||!this.exact(e.local.status?.process??null,t.runtime)||e.local.kind===`foreign`||e.local.kind===`unverified`&&!n)throw new v(`conflict`)}async control(e){let t=e.local.status?.process;if(e.local.kind!==`verified`||!t)throw new v(`unavailable`);if(this.client&&!this.exact(this.client.runtime,t)&&(this.client.close(),this.client=void 0),!this.client){let e=await(this.options.connect??n)(x(t.stateDir).sock,{onPairingRequest:e=>this.emit({...e,v:1}),onPairingClosed:e=>this.emit({...e,v:1}),onDisconnect:()=>{this.client=void 0}});if(this.closed)throw e.close(),new v(`unavailable`);if(!this.exact(e.runtime,t))throw e.close(),new v(`conflict`);this.client=e}return this.client}async settings(e){let t=this.statusStateDirectory(e),n=h(x(t)),r=u(n),i=null;if(e.local.kind===`verified`)try{i=await(await this.control(e)).configurationRevision()}catch{}return{saved:n,savedRevision:r,appliedRevision:i,applied:e.local.kind===`absent`?`not-running`:i===null?`unknown`:i===r?`matches`:`restart-required`}}async execute(e){try{if(this.closed)throw new v(`unavailable`);let t=p.safeParse(e);if(!t.success||t.data.cmd===`hello`)throw new v(`bad-request`);let n=t.data,i;if(n.cmd===`terminals.connect`){let e=await(await this.control(await this.status())).connectTerminal(n.args.name);i=e?{supported:!0,...e}:{supported:!1,started:!1,terminals:[]}}else if(`args`in n)i=`ownerRevision`in n.args?await this.ownership(n):await this.guardLegacy(n,e=>this.options.store.mutate(n.args.expect.revision,async t=>this.options.platform.withLegacyGuard(async i=>{let a=await i.inspect(),o=await this.observe(t.current,a);if(n.cmd.startsWith(`service.`)&&(o.ownership?.mode===`desktop`||o.ownership?.transition))throw new v(`conflict`);let s=(n.cmd===`service.start`&&n.args.migrateLegacy||n.cmd===`service.recover`&&n.args.action===`continue`&&t.current?.transition?.source===null&&t.current?.transition?.destination!==null&&!!t.current?.recovery)&&a.loaded&&a.definition?.serviceInstance===null&&o.local.kind===`unverified`;if(this.expect(o,n.args.expect,s),n.cmd.startsWith(`service.`))return this.lifecycle(n,t,i,a,o);if(n.cmd===`settings.set`){let t=this.statusStateDirectory(o);if(t!==e)throw new v(`conflict`);let i=x(t),a=f(i,e=>{if(u(e)!==n.args.configRevision)throw new v(`conflict`);let t=e;for(let i of n.args.changes){if(r(e,i.key)===i.value)continue;let n=l(t,i.key,i.value,!1);if(`error`in n)throw new v(`invalid-config`);t=n.next}return t});if(o.local.kind===`verified`&&n.args.changes.some(e=>e.key===`conversations`))try{await(await this.control(o)).applyConversationSetting(u(a))}catch{}return this.settings(o)}let c=await this.control(o);if(n.cmd===`devices.revoke`)return c.revoke(n.args.phoneFp);if(n.cmd===`pairing.open`)return c.openPairing();if(n.cmd===`pairing.close`)return await c.closePairing(n.args.flowId),{};if(n.cmd===`pairing.confirm`)return await c.confirm(n.args.flowId,n.args.challengeId,n.args.phoneFp,n.args.accept),{};throw new v(`bad-request`)}).catch(e=>{throw this.error(e)})));else{let e=await this.status();if(n.cmd===`status`)i=e;else if(n.cmd===`settings.get`)i=await this.settings(e);else if(n.cmd===`devices`)i=await(await this.control(e)).devices();else if(n.cmd===`terminals`){let t=await(await this.control(e)).terminals();i={supported:t!==null,terminals:t??[]}}else i={checks:await this.diagnose(e)}}let a=_[n.cmd].safeParse(i);if(!a.success)throw new v(`args`in n?`delivery-unknown`:`operation-failed`);return a.data}catch(e){throw this.error(e)}}async guardLegacy(e,t){let n=await this.status(),r=e.cmd===`settings.set`?this.statusStateDirectory(n):n.selection?.stateDir??n.legacy.stateDir??(e.cmd===`service.start`?e.args.stateDir:void 0)??this.options.defaultStateDir;e.cmd===`service.start`&&!n.selection&&!n.legacy.installed&&(D(r,this.options.uid),await this.requireAbsentDestination(r));let i=new m({stateDir:r,uid:this.options.uid});return i.mutate(i.inspect()?.revision??null,async n=>{if(e.cmd.startsWith(`service.`)&&(n.current?.mode===`desktop`||n.current?.transition))throw new v(`conflict`);return t(r)})}async ownership(e){let t=await this.status();this.expect(t,e.args.expect);let n=this.options.store.inspect();if((n?.revision??null)!==t.revision)throw new v(`conflict`);let r=this.stateDirectory(n,t.legacy.stateDir),i=new m({stateDir:r,uid:this.options.uid});if((e.cmd===`desktop.start`||e.cmd===`desktop.stop`)&&(t.ownership?.mode!==`desktop`||!t.ownership.consented))throw new v(`conflict`);return i.mutate(e.args.ownerRevision,async t=>this.options.store.mutate(e.args.expect.revision,async n=>this.options.platform.withLegacyGuard(async i=>{let a=await i.inspect(),o=await this.observe(n.current,a);if(this.expect(o,e.args.expect),e.cmd===`desktop.login.set`){if(t.current?.mode!==`desktop`||!t.current.consented)throw new v(`conflict`);if(t.current.transition||n.current?.transition)throw new v(`recovery-required`);return await this.options.platform.setLogin(this.options.bundlePath,e.args.enabled),t.publish({...t.current,startupEnabled:e.args.enabled}),this.observe(n.current,await i.inspect())}if(e.cmd===`desktop.stop`){if(o.selection?.mode!==`desktop`)throw new v(`conflict`);if(o.local.kind===`absent`&&!o.desktop?.loaded)return o;if(o.local.kind!==`verified`)throw new v(`conflict`);return await this.desktop.stop(e.args.expect),await this.readiness.waitStopped(x(r).sock),this.observe(n.current,await i.inspect())}if(e.cmd===`desktop.setup`){if(t.current||n.current?.selection||n.current?.transition||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded||o.local.kind!==`absent`)throw new v(`conflict`)}else if(e.cmd===`desktop.start`){if(t.current?.transition||n.current?.transition)throw new v(`recovery-required`);if(t.current?.mode!==`desktop`||!t.current.consented||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded)throw new v(`conflict`);if(o.local.kind===`verified`&&o.selection?.mode===`desktop`&&o.desktop?.loaded)return o;if(o.local.kind!==`absent`)throw new v(`conflict`)}else if(e.cmd===`ownership.recover`){if(!t.current?.transition||t.current.transition.id!==e.args.intentId)throw new v(`conflict`)}else if(t.current?.transition)throw new v(`recovery-required`);let s=e.cmd===`ownership.recover`,c=s?t.current.transition.target:e.cmd===`ownership.convert`?e.args.target:`desktop`;if(c===`headless`)return this.convertToHeadless(t,n,i,a,o,r,s);if(await this.admitBundle(this.options.bundlePath),[`foreign`,`unverified`].includes(o.local.kind))throw new v(`conflict`);let l=D(r,this.options.uid,e.cmd===`desktop.setup`);if(!l)throw new v(`unsafe-state`);let u=s&&n.current?.transition?.id===t.current?.transition?.id?n.current.transition:null,d=s&&!n.current?.transition&&n.current?.selection?.mode===`desktop`?n.current.selection:null,f=d?null:u?u.source:n.current?.selection??null,p=s?t.current.transition:{id:this.newId(),source:o.ownership?.mode??null,target:c,sourceManager:f?f.mode===`desktop`?`desktop-child`:f.mode===`manual`?`native-manual`:`native-persistent`:a.installed||a.loaded?`launchd`:null,sourceInstance:f?.serviceInstance??a.definition?.serviceInstance??null,stateDir:r,computerFp:l.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(p.stateDir!==r||p.computerFp!==l.fp||p.targetBundlePath!==this.options.bundlePath||p.targetVersion!==this.options.agentVersion)throw new v(`conflict`);let m=this.newId(),h=f?.environment??a.definition?.environment,g=d??u?.destination??{mode:`desktop`,stateDir:r,computerFp:l.fp,serviceInstance:m,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:h?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,...h?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:h.HERDR_SOCKET_PATH}:{},...h?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:h.XDG_CONFIG_HOME}:{},SHELLBELL_DIR:r,SHELLBELL_SERVICE_INSTANCE:m}};if(g.mode!==`desktop`||g.computerFp!==l.fp||g.stateDir!==r||g.bundlePath!==p.targetBundlePath||g.agentVersion!==p.targetVersion)throw new v(`conflict`);let _=async()=>{let e=await this.observe(n.current,await i.inspect());return e.selection?.serviceInstance===g.serviceInstance&&e.local.kind===`verified`&&!!e.desktop?.loaded&&!e.manual.loaded&&!e.persistent.loaded&&!e.legacy.installed&&!e.legacy.loaded};return await U(t,p,{preflight:async()=>{if(!S.safeParse(g).success)throw new v(`unsafe-state`);await this.admitBundle(g.bundlePath)},stopSource:async()=>{if(p.source===`headless`&&t.current?.startupEnabled&&await this.options.platform.setLogin(this.options.bundlePath,!0),!u){let e=n.current?.recovery??null;if(a.installed){if(!a.raw||!a.definition||e&&s)throw new v(`recovery-required`);e={id:this.newId(),definitionPath:i.definitionPath,rawBase64:a.raw.toString(`base64`),sha256:R(`sha256`).update(a.raw).digest(`hex`),wasLoaded:a.loaded,stateDir:r,computerFp:l.fp}}this.publish(n,{recovery:e,transition:{id:p.id,action:`start`,phase:`prepared`,source:f,destination:g,recoveryId:e?.id??null}})}if(await _())return;if(f){if(f.stateDir!==r||f.computerFp!==l.fp)throw new v(`conflict`);if(f.mode===`desktop`){let e=await this.observe(n.current,await i.inspect());if(e.desktop?.loaded){if(e.local.kind!==`verified`)throw new v(`conflict`);await this.desktop.stop({revision:e.revision,runtime:e.local.status.process})}}else{let e=await this.options.platform.inspect(f.mode,f.bundlePath),t=f.mode===`persistent`&&!e.loaded;t?await this.options.platform.prepareManualRecovery(f):(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(f,e),await this.readiness.waitStopped(x(r).sock),t||await this.options.platform.remove(f)}}let e=await i.inspect();if(e.installed||e.loaded){let t=n.current?.recovery;if(!t||!e.raw||R(`sha256`).update(e.raw).digest(`hex`)!==t.sha256)throw new v(`conflict`);e.loaded&&await i.unload(),await this.readiness.waitStopped(x(r).sock);let a=await i.inspect();if(a.loaded||!a.raw?.equals(e.raw))throw new v(`conflict`);await i.restore(null)}},verifyAbsent:async()=>{if(await _())return;let e=await this.observe(n.current,await i.inspect());if(e.manual.loaded||e.persistent.loaded||e.legacy.installed||e.legacy.loaded||e.desktop?.loaded||e.local.kind!==`absent`)throw new v(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{await _()||(this.phase(n,`destination-start-requested`,{selection:g}),await this.desktop.start(g),await this.certify(g),this.phase(n,`destination-ready`))},complete:async()=>{this.publish(n,{selection:g,transition:null})}}),this.observe(n.current,await i.inspect())})))}async convertToHeadless(e,n,r,i,a,o,s){if(!s&&e.current?.mode===`headless`&&!n.current?.selection&&!n.current?.transition)return a;if([`foreign`,`unverified`].includes(a.local.kind))throw new v(`conflict`);await this.admitBundle(this.options.bundlePath);let c=await(this.options.inspectBundle??C)(this.options.bundlePath),l=D(o,this.options.uid);if(!l)throw new v(`unsafe-state`);let u=s&&n.current?.transition?.id===e.current?.transition?.id?n.current.transition:null,d=u?u.source:n.current?.selection??null,f=s?e.current.transition:{id:this.newId(),source:a.ownership?.mode??null,target:`headless`,sourceManager:d?.mode===`desktop`?`desktop-child`:d?.mode===`manual`?`native-manual`:d?.mode===`persistent`?`native-persistent`:null,sourceInstance:d?.serviceInstance??null,stateDir:o,computerFp:l.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(f.target!==`headless`||f.stateDir!==o||f.computerFp!==l.fp||f.targetBundlePath!==this.options.bundlePath||f.targetVersion!==this.options.agentVersion)throw new v(`conflict`);let p=d?.environment??(s&&i.definition?.serviceInstance===f.id?i.definition.environment:void 0),m={nodePath:c.nodePath,cliPath:F(this.options.bundlePath,`Contents/Resources/agent/dist/cli.js`),stateDir:o,serviceInstance:f.id,logPath:x(o).log,environment:{PATH:p?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,SHELLBELL_DIR:o,SHELLBELL_SERVICE_INSTANCE:f.id,...p?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:p.HERDR_SOCKET_PATH}:{},...p?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:p.XDG_CONFIG_HOME}:{}}},h=e=>{let t=e.definition;return e.installed&&!!t&&t.serviceInstance===f.id&&t.stateDir===o&&t.nodePath===m.nodePath&&t.cliPath===m.cliPath&&t.logPath===m.logPath&&JSON.stringify(Object.entries(t.environment).sort())===JSON.stringify(Object.entries(m.environment).sort())},g={stateDir:o,computerFp:l.fp,serviceInstance:f.id},_=async()=>{let e=await r.inspect();if(!h(e)||!e.loaded||(await this.readiness.observe(x(o).sock,g)).kind!==`verified`)return!1;let t=await r.inspect();return h(t)&&t.loaded};return await U(e,f,{preflight:async()=>{if((i.installed||i.loaded)&&(!s||!h(i))||i.loaded&&(a.manual.loaded||a.persistent.loaded||d?.mode===`desktop`&&(await this.desktop.inspect(d)).loaded)||d&&(d.stateDir!==o||d.computerFp!==l.fp)||a.manual.loaded&&d?.mode!==`manual`||a.persistent.loaded&&d?.mode!==`persistent`)throw new v(`conflict`)},stopSource:async()=>{this.publish(n,{transition:{id:f.id,action:`recover`,phase:`prepared`,source:d,destination:null,recoveryId:n.current?.recovery?.id??null}});let e=await this.options.platform.loginStatus(this.options.bundlePath);if(e===`unknown`)throw new v(`unavailable`);if((e===`enabled`||e===`requires-approval`)&&await this.options.platform.setLogin(this.options.bundlePath,!1),!await _()){if(d?.mode===`desktop`){let e=await this.desktop.inspect(d);if(e.loaded){let t=await this.readiness.observe(x(o).sock,{stateDir:o,computerFp:l.fp,serviceInstance:d.serviceInstance,...e.pid?{pid:e.pid}:{}});if(t.kind!==`verified`)throw new v(`conflict`);await this.desktop.stop({revision:n.current?.revision??null,runtime:t.local.process})}}else if(d){let e=await this.options.platform.inspect(d.mode,d.bundlePath),t=d.mode===`persistent`&&!e.loaded;t&&await this.options.platform.prepareManualRecovery(d),(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(d,e),await this.readiness.waitStopped(x(o).sock),t||await this.options.platform.remove(d)}}},verifyAbsent:async()=>{if(await _())return;let e=await this.observe(n.current,await r.inspect()),t=await r.inspect();if(e.manual.loaded||e.persistent.loaded||e.desktop?.loaded||t.loaded||t.installed&&!h(t)||e.local.kind!==`absent`)throw new v(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{if(await _())return;if(await this.admitBundle(this.options.bundlePath),D(o,this.options.uid)?.fp!==l.fp)throw new v(`unsafe-state`);t(m.logPath)||k(j(m.logPath,A.O_WRONLY|A.O_CREAT|A.O_EXCL|A.O_NOFOLLOW,384)),this.phase(n,`destination-start-requested`,{selection:null});let i=await r.inspect();if(!h(i)){if(i.installed||i.loaded)throw new v(`conflict`);await r.write(m)}await r.setStartupEnabled(e.current.startupEnabled);let a=await r.load();if(await this.readiness.waitReady(x(o).sock,{...g,pid:a}),!await _())throw new v(`conflict`);this.phase(n,`destination-ready`)},complete:async()=>{this.publish(n,{selection:null,transition:null})}}),this.observe(n.current,await r.inspect())}async diagnose(e){return this.options.diagnose?this.options.diagnose(this.statusStateDirectory(e)):[{name:`local-owner`,ok:e.local.kind===`verified`,severity:e.local.kind===`foreign`?`error`:e.local.kind===`verified`?`pass`:`warning`,detail:e.local.kind},{name:`legacy-service`,ok:!e.legacy.loaded,severity:e.legacy.loaded?`warning`:`pass`,detail:e.legacy.loaded?`Legacy service loaded`:`Legacy service stopped`}]}publish(e,t){return e.publish({v:1,selection:null,transition:null,recovery:null,...e.current,...t})}phase(e,t,n={}){let r=e.current?.transition;if(!r)throw new v(`recovery-required`);return this.publish(e,{...n,transition:{...r,phase:t}})}async admitBundle(e,t=this.options.agentVersion){let n=await(this.options.inspectBundle??C)(e);if(n.agentVersion!==t)throw new v(`upgrade-required`);return n}async lifecycle(t,n,r,i,a){if(t.cmd===`service.recover`)return this.recover(t,n,r,i,a);if(n.current?.transition)throw new v(`recovery-required`);let o=n.current?.selection??null;if(a.manual.loaded&&o?.mode!==`manual`||a.persistent.loaded&&o?.mode!==`persistent`||o&&i.loaded||t.cmd!==`service.start`&&!o||t.cmd===`service.start`&&o&&e(o.mode)===t.args.mode&&o.bundlePath===this.options.bundlePath&&a[e(o.mode)].loaded||i.installed&&(t.cmd!==`service.start`||!t.args.migrateLegacy))throw new v(`conflict`);let s=null;if(t.cmd===`service.start`||t.cmd===`service.restart`){await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(t.cmd===`service.start`?t.args.mode:e(o.mode),this.options.bundlePath);let n=o?.stateDir??i.definition?.stateDir??(t.cmd===`service.start`?t.args.stateDir:void 0)??this.options.defaultStateDir;if(t.cmd===`service.start`&&t.args.stateDir&&t.args.stateDir!==n)throw new v(`conflict`);!o&&!i.installed&&(D(n,this.options.uid),await this.requireAbsentDestination(n));let r=D(n,this.options.uid,!0),a=this.newId();s={mode:t.cmd===`service.start`?t.args.mode:o.mode,stateDir:n,computerFp:r.fp,serviceInstance:a,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,SHELLBELL_DIR:n,SHELLBELL_SERVICE_INSTANCE:a}}}let c=n.current?.recovery??null;if(i.installed){if(!i.raw||!i.definition||c)throw new v(`recovery-required`);let e=D(i.definition.stateDir,this.options.uid);if(!e)throw new v(`unsafe-state`);c={id:this.newId(),definitionPath:r.definitionPath,rawBase64:i.raw.toString(`base64`),sha256:R(`sha256`).update(i.raw).digest(`hex`),wasLoaded:i.loaded,stateDir:i.definition.stateDir,computerFp:e.fp}}this.publish(n,{recovery:c,transition:{id:this.newId(),action:t.cmd.slice(8),phase:`prepared`,source:o,destination:s,recoveryId:c?.id??null}});try{return await this.advance(n,r,i,a)}catch(e){throw this.phase(n,`recovery-required`),e}}async stopSource(t,n,r,i){let a=t.current.transition,o=a.source;if(this.phase(t,`source-stop-requested`),o){try{await this.admitBundle(o.bundlePath,o.agentVersion)}catch{throw new v(`recovery-required`)}let t=i[e(o.mode)];(t.loaded||t.registration!==`not-registered`)&&await this.options.platform.stop(o,t),await this.readiness.waitStopped(x(o.stateDir).sock);let n=await this.options.platform.inspect(e(o.mode),o.bundlePath);if(n.loaded||e(o.mode)===`persistent`&&n.registration!==`not-registered`)throw new v(`operation-failed`)}else if(r.installed){r.loaded&&await n.unload(),await this.readiness.waitStopped(x(r.definition.stateDir).sock);let e=await n.inspect();if(e.loaded||!e.raw?.equals(r.raw))throw new v(`conflict`)}else if(i.local.kind!==`absent`)throw new v(`conflict`);if(this.phase(t,`source-stopped`,{selection:a.action===`stop`?o:null}),o&&a.destination&&(e(o.mode)!==e(a.destination.mode)||o.bundlePath!==a.destination.bundlePath)&&await this.options.platform.remove(o),r.installed){await n.restore(null);let e=await n.inspect();if(e.installed||e.loaded)throw new v(`operation-failed`)}}async advance(e,t,n,r){let i=e.current.transition;return await this.stopSource(e,t,n,r),i.destination?await this.startDestination(e,i.destination):i.action===`remove`&&i.source&&(await this.options.platform.remove(i.source),this.publish(e,{selection:null})),e.current.transition?.phase!==`awaiting-approval`&&this.publish(e,{transition:null}),this.observe(e.current,await t.inspect())}async startDestination(e,t){if(await this.admitBundle(t.bundlePath),D(t.stateDir,this.options.uid)?.fp!==t.computerFp)throw new v(`unsafe-state`);if(await this.requireAbsentDestination(t.stateDir),this.phase(e,`destination-start-requested`,{selection:t}),(await this.options.platform.start(t)).registration===`requires-approval`){this.phase(e,`awaiting-approval`);return}await this.certify(t),this.phase(e,`destination-ready`)}async requireAbsentDestination(e){if((await this.readiness.observe(x(e).sock)).kind!==`absent`)throw new v(`conflict`)}async certify(t){let n=t.mode===`desktop`?await this.desktop.inspect(t):await this.options.platform.inspect(e(t.mode),t.bundlePath);if(!n.loaded||!n.pid)throw new v(`operation-failed`);let r=await this.readiness.waitReady(x(t.stateDir).sock,{computerFp:t.computerFp,stateDir:t.stateDir,serviceInstance:t.serviceInstance,pid:n.pid}),i=t.mode===`desktop`?await this.desktop.inspect(t):await this.options.platform.inspect(e(t.mode),t.bundlePath);if(JSON.stringify(n)!==JSON.stringify(i)||r.process.agentVersion!==t.agentVersion)throw new v(`conflict`)}isManualRecovery(e){let t=e?.transition;return t?.action===`recover`&&!t.restoreLegacy&&t.source?.mode===`persistent`&&t.destination?.mode===`manual`&&t.source.stateDir===t.destination.stateDir&&t.source.computerFp===t.destination.computerFp}async recover(t,n,r,i,a){let o=n.current;if(!o||a.manual.loaded&&a.persistent.loaded||o.selection&&i.loaded||o.selection&&a[e(o.selection.mode)===`manual`?`persistent`:`manual`].loaded)throw new v(`conflict`);if(t.args.action===`discard-backup`){if(o.transition||!o.recovery||i.installed&&i.raw?.toString(`base64`)!==o.recovery.rawBase64)throw new v(`conflict`);return this.publish(n,{recovery:null}),this.observe(n.current,i)}let s=o.recovery,c=s?Buffer.from(s.rawBase64,`base64`):null;if(s&&(!c||R(`sha256`).update(c).digest(`hex`)!==s.sha256)||s&&(s.definitionPath!==r.definitionPath||D(s.stateDir,this.options.uid)?.fp!==s.computerFp))throw new v(`unsafe-state`);if(s&&i.installed&&!i.raw?.equals(c))throw new v(`conflict`);let l=this.isManualRecovery(o);if(t.args.action===`use-manual`||t.args.action===`continue`&&l){let e=l?o.transition?.source:o.transition?.destination;if(e?.mode!==`persistent`||o.transition?.restoreLegacy||!l&&![`start`,`restart`].includes(o.transition.action)||o.selection?.serviceInstance!==e.serviceInstance||a.manual.loaded||a.persistent.loaded||a.local.kind!==`absent`||i.installed||i.loaded)throw new v(`conflict`);if(await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(`manual`,this.options.bundlePath),D(e.stateDir,this.options.uid)?.fp!==e.computerFp)throw new v(`unsafe-state`);let t=this.newId(),s=l?o.transition.destination:{...e,mode:`manual`,bundlePath:this.options.bundlePath,agentVersion:this.options.agentVersion,serviceInstance:t,environment:{...e.environment,SHELLBELL_SERVICE_INSTANCE:t}};l||this.publish(n,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:e,destination:s,recoveryId:o.recovery?.id??null}});try{await this.options.platform.prepareManualRecovery(e),await this.requireAbsentDestination(e.stateDir);let t=await this.observe(n.current,await r.inspect());if(t.manual.loaded||t.persistent.loaded||t.legacy.installed||t.legacy.loaded||t.local.kind!==`absent`)throw new v(`conflict`);return this.publish(n,{selection:null,transition:{id:this.newId(),action:`start`,phase:`source-stopped`,source:null,destination:s,recoveryId:o.recovery?.id??null}}),await this.startDestination(n,s),this.publish(n,{transition:null}),this.observe(n.current,await r.inspect())}catch(e){throw this.phase(n,`recovery-required`),e}}if(t.args.action===`continue`&&o.transition?.action===`recover`&&!o.transition.restoreLegacy)throw new v(`recovery-required`);try{if(t.args.action===`restore-legacy`||o.transition?.restoreLegacy){if(!s||!c)throw new v(`conflict`);if(t.args.action===`restore-legacy`){if(i.loaded)throw new v(`conflict`);this.publish(n,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:o.selection,destination:null,recoveryId:s.id,restoreLegacy:{restartPrevious:t.args.restartPrevious}}})}return await this.restoreLegacy(n,r,i,a,c)}let l=o.transition;if(!l)throw new v(`conflict`);let u=l.destination;if(u&&o.selection?.serviceInstance===u.serviceInstance){let t=a[e(u.mode)];if(i.loaded||a[e(u.mode)===`manual`?`persistent`:`manual`].loaded)throw new v(`conflict`);if(t.registration===`requires-approval`)return this.phase(n,`awaiting-approval`),this.observe(n.current,i);if(t.loaded)await this.certify(u),this.phase(n,`destination-ready`);else{if(a.local.kind!==`absent`)throw new v(`conflict`);await this.startDestination(n,u)}return n.current.transition?.phase!==`awaiting-approval`&&this.publish(n,{transition:null}),this.observe(n.current,await r.inspect())}return await this.advance(n,r,i,a)}catch(e){throw n.current?.transition&&this.phase(n,`recovery-required`),e}}async restoreLegacy(e,t,n,r,i){let a=e.current,o=a.recovery,s=a.transition.restoreLegacy;if(n.loaded){if(!s.restartPrevious||a.selection||r.manual.loaded||r.persistent.loaded||r.local.kind!==`verified`||!n.raw?.equals(i))throw new v(`conflict`);let o=await t.inspect();if(!o.loaded||!o.raw?.equals(i))throw new v(`conflict`);return this.publish(e,{selection:null,transition:null}),this.observe(e.current,o)}if(a.selection)await this.stopSource(e,t,{installed:!1,loaded:!1,raw:null,definition:null},r);else if(r.manual.loaded||r.persistent.loaded||r.local.kind!==`absent`)throw new v(`conflict`);await this.readiness.waitStopped(x(o.stateDir).sock),this.phase(e,`source-stopped`,{selection:null}),n.installed||await t.restore(i);let c=await t.inspect();if(!c.raw?.equals(i)||c.loaded)throw new v(`operation-failed`);if(s.restartPrevious){this.phase(e,`destination-start-requested`);let n=await t.load();await this.readiness.waitReady(x(o.stateDir).sock,{computerFp:o.computerFp,stateDir:o.stateDir,serviceInstance:c.definition?.serviceInstance??null,pid:n});let r=await t.inspect();if(!r.loaded||!r.raw?.equals(i))throw new v(`conflict`)}return this.publish(e,{selection:null,transition:null}),this.observe(e.current,await t.inspect())}emit(e){for(let t of this.listeners)t(e)}onEvent(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async close(){this.closed=!0,this.client?.close(),this.client=void 0,this.listeners.clear(),await this.desktop.close()}};async function G(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${o}\n`:`Shellbell native controller
2
+ import{C as e,Dt as t,F as n,H as r,I as i,L as a,Nt as o,P as s,S as c,U as l,V as u,_ as d,at as f,b as p,c as m,dt as h,g,h as _,m as v,o as y,rt as b,ut as x,x as S}from"./service-lifecycle-De-Hj3Tl.js";import{a as C,i as w,o as T,r as E,t as D}from"./service-entry-BBSp8-ir.js";import{spawn as O}from"node:child_process";import{closeSync as k,constants as A,openSync as j,realpathSync as M}from"node:fs";import{userInfo as N}from"node:os";import{dirname as P,join as F,resolve as I}from"node:path";import{fileURLToPath as L}from"node:url";import{createHash as R,randomUUID as z}from"node:crypto";import{performance as B}from"node:perf_hooks";function V(e,t,n,r){let o=!1,s=!1,c=0,l=!1,u=!1,f,m,h,y,b=()=>y||(o=!0,clearTimeout(h),C(),e.off(`data`,T),e.off(`end`,E),e.destroy(),y=Promise.resolve(n.close()).finally(()=>{t.end()}),y.catch(()=>{}),y),x=e=>{if(o)return!1;let n=a(e),r=t.writableLength;if(!n||t.destroyed||!Number.isFinite(r)||r<0||r+n.byteLength>262144)return b(),!1;try{t.write(n)}catch{return b(),!1}return!0},S=(e,t)=>x({v:1,id:e,ok:!1,error:{code:t}}),C=n.onEvent(e=>{let t=d.safeParse(e);if(!t.success){b();return}if(u){f?b():f=t.data;return}if(t.data.flowId!==m){b();return}x(t.data),t.data.event===`pairing.closed`&&(m=void 0)}),w=new i({onError:b,onLine(e){if(o)return;let t;try{t=JSON.parse(e)}catch{b();return}let i=p.safeParse(t);if(!i.success){typeof t==`object`&&t&&`id`in t&&typeof t.id==`number`&&Number.isSafeInteger(t.id)&&t.id>c&&S(t.id,`v`in t&&t.v!==1?`unsupported-version`:`bad-request`),b();return}let d=i.data;if(d.id<=c){b();return}if(c=d.id,!s){if(d.cmd!==`hello`){S(d.id,`handshake-required`),b();return}s=!0,clearTimeout(h),x({v:1,id:d.id,ok:!0,data:_.hello.parse({version:1,agentVersion:r.agentVersion,capabilities:[`status`,`settings`,`lifecycle`,`pairing`,`devices`,`diagnostics`]})});return}if(d.cmd===`hello`){b();return}if(l){S(d.id,`busy`),b();return}l=!0,u=d.cmd===`pairing.open`;let y=`args`in d;h=setTimeout(()=>{S(d.id,y?`delivery-unknown`:`timeout`),b()},d.cmd.startsWith(`service.`)||d.cmd.startsWith(`desktop.`)||d.cmd.startsWith(`ownership.`)?6e4:5e3),n.execute(d).then(e=>{if(o)return;let t=_[d.cmd].safeParse(e);if(!t.success){S(d.id,y?`delivery-unknown`:`operation-failed`),b();return}if(d.cmd===`pairing.open`&&(m=t.data.flowId),!a({v:1,id:d.id,ok:!0,data:t.data})){S(d.id,`response-too-large`),b();return}if(x({v:1,id:d.id,ok:!0,data:t.data}),u=!1,f){if(f.flowId!==m){b();return}x(f),f.event===`pairing.closed`&&(m=void 0),f=void 0}},e=>{let t=e instanceof v&&g.safeParse(e.code).success?e.code:`operation-failed`;S(d.id,t),u=!1,f=void 0}).finally(()=>{clearTimeout(h),l=!1})}}),T=e=>w.push(e),E=()=>{w.finish(),b()};return e.on(`data`,T),e.once(`end`,E),e.once(`error`,b),t.once(`error`,b),h=setTimeout(b,5e3),{close:b}}var H=class{options;owned;starting;closed=!1;readiness;clock;constructor(e){this.options=e,this.readiness=e.readiness??new y,this.clock=e.clock??{now:()=>B.now(),sleep:e=>new Promise(t=>setTimeout(t,e))}}async inspect(e){let t=this.owned;if(t&&!t.exited&&(t.selection.serviceInstance!==e.serviceInstance||t.selection.bundlePath!==e.bundlePath))throw new v(`conflict`);return{registration:`not-registered`,loaded:!!t&&!t.exited,pid:t&&!t.exited?t.child.pid??null:null,bundlePath:e.bundlePath}}start(e){return this.closed||this.starting||this.owned&&!this.owned.exited?Promise.reject(new v(`busy`)):!S.safeParse(e).success||e.mode!==`desktop`?Promise.reject(new v(`conflict`)):(this.starting=this.launch(structuredClone(e)).finally(()=>{this.starting=void 0}),this.starting)}async launch(e){this.owned&&await this.stopOwned(this.owned);let t=await(this.options.admitBundle??C)(e.bundlePath);if(t.agentVersion!==e.agentVersion||this.closed||(await this.readiness.observe(x(e.stateDir).sock)).kind!==`absent`||this.closed)throw new v(`conflict`);let n=O(t.nodePath,[t.servicePath,`desktop`],{cwd:this.options.homeDir,env:E(e,this.options.homeDir,process.env),stdio:[`ignore`,`pipe`,`pipe`,`pipe`]}),r={child:n,pipe:n.stdio[3],selection:e,exited:!1};this.owned=r,n.once(`exit`,()=>{r.exited=!0}),n.once(`error`,()=>{r.exited=!0}),n.stdout?.resume(),n.stderr?.resume(),r.pipe.on(`error`,()=>{});try{r.pipe.write(`${JSON.stringify({v:1,instance:e.serviceInstance})}\n`);let t=this.clock.now()+1e4;for(;this.clock.now()<t;){if(r.exited||this.closed||!n.pid)throw new v(`unavailable`);let i=await this.readiness.observe(x(e.stateDir).sock,{stateDir:e.stateDir,computerFp:e.computerFp,serviceInstance:e.serviceInstance,pid:n.pid},Math.min(500,t-this.clock.now()));if(i.kind===`verified`&&i.local?.process.agentVersion===e.agentVersion&&!r.exited&&!this.closed)return this.inspect(e);if(i.kind===`foreign`)throw new v(`conflict`);await this.clock.sleep(Math.min(25,Math.max(0,t-this.clock.now())))}throw new v(`unavailable`)}catch(e){throw await this.stopOwned(r),e}}async stop(e){let t=this.owned;if(!t){if(e.runtime)throw new v(`conflict`);return}let n=e.runtime,r=t.selection;if(!n||n.pid!==t.child.pid||n.stateDir!==r.stateDir||n.computerFp!==r.computerFp||n.serviceInstance!==r.serviceInstance||n.agentVersion!==r.agentVersion)throw new v(`conflict`);await this.stopOwned(t)}async close(){this.closed=!0,this.owned&&await this.stopOwned(this.owned),await this.starting?.catch(()=>{}),this.owned&&await this.stopOwned(this.owned)}stopOwned(e){return e.stopping||=this.finishStop(e).finally(()=>{e.stopping=void 0}),e.stopping}async finishStop(e){e.pipe.end();let t=this.options.stopTimeoutMs??1e4,n=this.clock.now()+t,r=n-t/2,i=!1;for(;!e.exited&&this.clock.now()<n;){if(!i&&this.clock.now()>=r){let t=e.selection,r=await this.readiness.observe(x(t.stateDir).sock,{pid:e.child.pid,stateDir:t.stateDir,computerFp:t.computerFp,serviceInstance:t.serviceInstance},Math.min(500,Math.max(1,n-this.clock.now())));if(r.kind===`foreign`)throw new v(`conflict`);r.kind===`verified`&&r.local?.process.agentVersion===t.agentVersion&&this.owned===e&&!e.exited&&(e.child.kill(`SIGTERM`),i=!0)}await this.clock.sleep(Math.min(25,Math.max(0,n-this.clock.now())))}if(!e.exited)throw new v(`unavailable`);if((await this.readiness.observe(x(e.selection.stateDir).sock)).kind!==`absent`)throw new v(`conflict`);e.pipe.destroy(),this.owned===e&&(this.owned=void 0)}};async function U(e,t,n){await n.preflight();let r=n=>e.publish({v:1,mode:n===`prepared`?e.current?.mode??t.target:t.target,consented:!0,startupEnabled:e.current?.startupEnabled??!1,transition:{...t,phase:n}});e.current?.transition||r(`prepared`);try{await n.stopSource(),await n.verifyAbsent(),r(`source-stopped`),await n.startDestination(),r(`destination-started`),await n.complete(),e.publish({v:1,mode:t.target,consented:!0,startupEnabled:e.current.startupEnabled,transition:null})}catch(e){throw r(`recovery-required`),e}}var W=class{options;desktop;readiness;newId;client;listeners=new Set;observedStateDirs=new WeakMap;closed=!1;constructor(e){this.options=e,this.desktop=e.desktop??new H({uid:e.uid,homeDir:e.homeDir,readiness:e.readiness,admitBundle:e.inspectBundle}),this.readiness=e.readiness??new y,this.newId=e.newId??z}async status(){try{return await this.observe(this.options.store.inspect(),await this.options.platform.inspectLegacy())}catch(e){throw this.error(e)}}stateDirectory(e,t){return this.recordedStateDirectory(e,t)??this.options.defaultStateDir}recordedStateDirectory(e,t){return e?.selection?.stateDir??e?.transition?.destination?.stateDir??e?.transition?.source?.stateDir??t??e?.recovery?.stateDir??null}statusStateDirectory(e){return this.observedStateDirs.get(e)??e.selection?.stateDir??e.legacy.stateDir??this.options.defaultStateDir}async observe(t,n){let r=t?.selection??null,i=r?.bundlePath??t?.transition?.source?.bundlePath??this.options.bundlePath,[a,o,s]=await Promise.all([this.options.platform.inspect(`manual`,i),this.options.platform.inspect(`persistent`,i),this.options.platform.loginStatus(this.options.bundlePath).catch(()=>`unknown`)]),l=this.recordedStateDirectory(t,n.definition?.stateDir),u=l??this.options.defaultStateDir,d=D(u,this.options.uid),f=r?.mode===`desktop`?await this.desktop.inspect(r):{registration:`not-registered`,loaded:!1,pid:null,bundlePath:null},p=r?r.mode===`desktop`?f:e(r.mode)===`manual`?a:o:null,h=d?{stateDir:u,computerFp:d.fp,serviceInstance:r?.serviceInstance??n.definition?.serviceInstance??null,...p?.pid?{pid:p.pid}:{}}:void 0,g=await this.readiness.observe(x(u).sock,h);if(g.kind===`verified`&&(!d||r&&(!p?.loaded||!p.pid||d.fp!==r.computerFp))&&(g.kind=`foreign`),r){let t=r.mode===`desktop`?await this.desktop.inspect(r):await this.options.platform.inspect(e(r.mode),i);JSON.stringify(t)!==JSON.stringify(p)&&(g.kind=`unverified`,g.local=null)}let _=new m({stateDir:u,uid:this.options.uid}).inspect(),v=c.parse({desktopLogin:s,desktop:f,ownership:{revision:_?.revision??null,mode:_?.mode??(r||t?.transition?`legacy-native`:n.installed||n.loaded?`headless`:null),consented:_?.consented??!1,startupEnabled:_?.startupEnabled??null,transition:_?.transition??null},revision:t?.revision??null,selection:r,transition:t?.transition?{id:t.transition.id,action:t.transition.action,phase:t.transition.phase}:null,recoveryAvailable:!!t?.recovery,manualRecoveryAvailable:(t?.transition?.destination?.mode===`persistent`&&r?.serviceInstance===t.transition.destination.serviceInstance&&[`start`,`restart`].includes(t.transition.action)&&!t.transition.restoreLegacy||this.isManualRecovery(t)&&r?.serviceInstance===t?.transition?.source?.serviceInstance)&&!a.loaded&&!o.loaded&&g.kind===`absent`&&!n.installed&&!n.loaded,legacy:{installed:n.installed,loaded:n.loaded,stateDir:n.definition?.stateDir??null},manual:a,persistent:o,local:{kind:g.kind,status:g.local}});return l&&this.observedStateDirs.set(v,l),v}error(e){return e instanceof v?e:e instanceof b?new v(e.code===`busy`?`busy`:e.code===`invalid`?`invalid-config`:`unsafe-state`):e instanceof s?e.code===`server-error`?new v(e.serverCode===`runtime-mismatch`||e.serverCode===`configuration-mismatch`?`conflict`:e.serverCode===`pairing-busy`?`busy`:`operation-failed`):new v(e.code===`protocol-error`||e.code===`closed`?`unavailable`:e.code):new v(`operation-failed`)}exact(e,t){return e===null||t===null?e===t:[`pid`,`agentVersion`,`computerFp`,`stateDir`,`serviceInstance`].every(n=>e[n]===t[n])}expect(e,t,n=!1){if(e.revision!==t.revision||!this.exact(e.local.status?.process??null,t.runtime)||e.local.kind===`foreign`||e.local.kind===`unverified`&&!n)throw new v(`conflict`)}async control(e){let t=e.local.status?.process;if(e.local.kind!==`verified`||!t)throw new v(`unavailable`);if(this.client&&!this.exact(this.client.runtime,t)&&(this.client.close(),this.client=void 0),!this.client){let e=await(this.options.connect??n)(x(t.stateDir).sock,{onPairingRequest:e=>this.emit({...e,v:1}),onPairingClosed:e=>this.emit({...e,v:1}),onDisconnect:()=>{this.client=void 0}});if(this.closed)throw e.close(),new v(`unavailable`);if(!this.exact(e.runtime,t))throw e.close(),new v(`conflict`);this.client=e}return this.client}async settings(e){let t=this.statusStateDirectory(e),n=h(x(t)),r=u(n),i=null;if(e.local.kind===`verified`)try{i=await(await this.control(e)).configurationRevision()}catch{}return{saved:n,savedRevision:r,appliedRevision:i,applied:e.local.kind===`absent`?`not-running`:i===null?`unknown`:i===r?`matches`:`restart-required`}}async execute(e){try{if(this.closed)throw new v(`unavailable`);let t=p.safeParse(e);if(!t.success||t.data.cmd===`hello`)throw new v(`bad-request`);let n=t.data,i;if(n.cmd===`terminals.connect`){let e=await(await this.control(await this.status())).connectTerminal(n.args.name);i=e?{supported:!0,...e}:{supported:!1,started:!1,terminals:[]}}else if(`args`in n)i=`ownerRevision`in n.args?await this.ownership(n):await this.guardLegacy(n,e=>this.options.store.mutate(n.args.expect.revision,async t=>this.options.platform.withLegacyGuard(async i=>{let a=await i.inspect(),o=await this.observe(t.current,a);if(n.cmd.startsWith(`service.`)&&(o.ownership?.mode===`desktop`||o.ownership?.transition))throw new v(`conflict`);let s=(n.cmd===`service.start`&&n.args.migrateLegacy||n.cmd===`service.recover`&&n.args.action===`continue`&&t.current?.transition?.source===null&&t.current?.transition?.destination!==null&&!!t.current?.recovery)&&a.loaded&&a.definition?.serviceInstance===null&&o.local.kind===`unverified`;if(this.expect(o,n.args.expect,s),n.cmd.startsWith(`service.`))return this.lifecycle(n,t,i,a,o);if(n.cmd===`settings.set`){let t=this.statusStateDirectory(o);if(t!==e)throw new v(`conflict`);let i=x(t),a=f(i,e=>{if(u(e)!==n.args.configRevision)throw new v(`conflict`);let t=e;for(let i of n.args.changes){if(r(e,i.key)===i.value)continue;let n=l(t,i.key,i.value,!1);if(`error`in n)throw new v(`invalid-config`);t=n.next}return t});if(o.local.kind===`verified`&&n.args.changes.some(e=>e.key===`conversations`))try{await(await this.control(o)).applyConversationSetting(u(a))}catch{}return this.settings(o)}let c=await this.control(o);if(n.cmd===`devices.revoke`)return c.revoke(n.args.phoneFp);if(n.cmd===`pairing.open`)return c.openPairing();if(n.cmd===`pairing.close`)return await c.closePairing(n.args.flowId),{};if(n.cmd===`pairing.confirm`)return await c.confirm(n.args.flowId,n.args.challengeId,n.args.phoneFp,n.args.accept),{};throw new v(`bad-request`)}).catch(e=>{throw this.error(e)})));else{let e=await this.status();if(n.cmd===`status`)i=e;else if(n.cmd===`settings.get`)i=await this.settings(e);else if(n.cmd===`devices`)i=await(await this.control(e)).devices();else if(n.cmd===`terminals`){let t=await(await this.control(e)).terminals();i={supported:t!==null,terminals:t??[]}}else i={checks:await this.diagnose(e)}}let a=_[n.cmd].safeParse(i);if(!a.success)throw new v(`args`in n?`delivery-unknown`:`operation-failed`);return a.data}catch(e){throw this.error(e)}}async guardLegacy(e,t){let n=await this.status(),r=e.cmd===`settings.set`?this.statusStateDirectory(n):n.selection?.stateDir??n.legacy.stateDir??(e.cmd===`service.start`?e.args.stateDir:void 0)??this.options.defaultStateDir;e.cmd===`service.start`&&!n.selection&&!n.legacy.installed&&(D(r,this.options.uid),await this.requireAbsentDestination(r));let i=new m({stateDir:r,uid:this.options.uid});return i.mutate(i.inspect()?.revision??null,async n=>{if(e.cmd.startsWith(`service.`)&&(n.current?.mode===`desktop`||n.current?.transition))throw new v(`conflict`);return t(r)})}async ownership(e){let t=await this.status();this.expect(t,e.args.expect);let n=this.options.store.inspect();if((n?.revision??null)!==t.revision)throw new v(`conflict`);let r=this.stateDirectory(n,t.legacy.stateDir),i=new m({stateDir:r,uid:this.options.uid});if((e.cmd===`desktop.start`||e.cmd===`desktop.stop`)&&(t.ownership?.mode!==`desktop`||!t.ownership.consented))throw new v(`conflict`);return i.mutate(e.args.ownerRevision,async t=>this.options.store.mutate(e.args.expect.revision,async n=>this.options.platform.withLegacyGuard(async i=>{let a=await i.inspect(),o=await this.observe(n.current,a);if(this.expect(o,e.args.expect),e.cmd===`desktop.login.set`){if(t.current?.mode!==`desktop`||!t.current.consented)throw new v(`conflict`);if(t.current.transition||n.current?.transition)throw new v(`recovery-required`);return await this.options.platform.setLogin(this.options.bundlePath,e.args.enabled),t.publish({...t.current,startupEnabled:e.args.enabled}),this.observe(n.current,await i.inspect())}if(e.cmd===`desktop.stop`){if(o.selection?.mode!==`desktop`)throw new v(`conflict`);if(o.local.kind===`absent`&&!o.desktop?.loaded)return o;if(o.local.kind!==`verified`)throw new v(`conflict`);return await this.desktop.stop(e.args.expect),await this.readiness.waitStopped(x(r).sock),this.observe(n.current,await i.inspect())}if(e.cmd===`desktop.setup`){if(t.current||n.current?.selection||n.current?.transition||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded||o.local.kind!==`absent`)throw new v(`conflict`)}else if(e.cmd===`desktop.start`){if(t.current?.transition||n.current?.transition)throw new v(`recovery-required`);if(t.current?.mode!==`desktop`||!t.current.consented||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded)throw new v(`conflict`);if(o.local.kind===`verified`&&o.selection?.mode===`desktop`&&o.desktop?.loaded)return o;if(o.local.kind!==`absent`)throw new v(`conflict`)}else if(e.cmd===`ownership.recover`){if(!t.current?.transition||t.current.transition.id!==e.args.intentId)throw new v(`conflict`)}else if(t.current?.transition)throw new v(`recovery-required`);let s=e.cmd===`ownership.recover`,c=s?t.current.transition.target:e.cmd===`ownership.convert`?e.args.target:`desktop`;if(c===`headless`)return this.convertToHeadless(t,n,i,a,o,r,s);if(await this.admitBundle(this.options.bundlePath),[`foreign`,`unverified`].includes(o.local.kind))throw new v(`conflict`);let l=D(r,this.options.uid,e.cmd===`desktop.setup`);if(!l)throw new v(`unsafe-state`);let u=s&&n.current?.transition?.id===t.current?.transition?.id?n.current.transition:null,d=s&&!n.current?.transition&&n.current?.selection?.mode===`desktop`?n.current.selection:null,f=d?null:u?u.source:n.current?.selection??null,p=s?t.current.transition:{id:this.newId(),source:o.ownership?.mode??null,target:c,sourceManager:f?f.mode===`desktop`?`desktop-child`:f.mode===`manual`?`native-manual`:`native-persistent`:a.installed||a.loaded?`launchd`:null,sourceInstance:f?.serviceInstance??a.definition?.serviceInstance??null,stateDir:r,computerFp:l.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(p.stateDir!==r||p.computerFp!==l.fp||p.targetBundlePath!==this.options.bundlePath||p.targetVersion!==this.options.agentVersion)throw new v(`conflict`);let m=this.newId(),h=f?.environment??a.definition?.environment,g=d??u?.destination??{mode:`desktop`,stateDir:r,computerFp:l.fp,serviceInstance:m,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:h?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,...h?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:h.HERDR_SOCKET_PATH}:{},...h?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:h.XDG_CONFIG_HOME}:{},SHELLBELL_DIR:r,SHELLBELL_SERVICE_INSTANCE:m}};if(g.mode!==`desktop`||g.computerFp!==l.fp||g.stateDir!==r||g.bundlePath!==p.targetBundlePath||g.agentVersion!==p.targetVersion)throw new v(`conflict`);let _=async()=>{let e=await this.observe(n.current,await i.inspect());return e.selection?.serviceInstance===g.serviceInstance&&e.local.kind===`verified`&&!!e.desktop?.loaded&&!e.manual.loaded&&!e.persistent.loaded&&!e.legacy.installed&&!e.legacy.loaded};return await U(t,p,{preflight:async()=>{if(!S.safeParse(g).success)throw new v(`unsafe-state`);await this.admitBundle(g.bundlePath)},stopSource:async()=>{if(p.source===`headless`&&t.current?.startupEnabled&&await this.options.platform.setLogin(this.options.bundlePath,!0),!u){let e=n.current?.recovery??null;if(a.installed){if(!a.raw||!a.definition||e&&s)throw new v(`recovery-required`);e={id:this.newId(),definitionPath:i.definitionPath,rawBase64:a.raw.toString(`base64`),sha256:R(`sha256`).update(a.raw).digest(`hex`),wasLoaded:a.loaded,stateDir:r,computerFp:l.fp}}this.publish(n,{recovery:e,transition:{id:p.id,action:`start`,phase:`prepared`,source:f,destination:g,recoveryId:e?.id??null}})}if(await _())return;if(f){if(f.stateDir!==r||f.computerFp!==l.fp)throw new v(`conflict`);if(f.mode===`desktop`){let e=await this.observe(n.current,await i.inspect());if(e.desktop?.loaded){if(e.local.kind!==`verified`)throw new v(`conflict`);await this.desktop.stop({revision:e.revision,runtime:e.local.status.process})}}else{let e=await this.options.platform.inspect(f.mode,f.bundlePath),t=f.mode===`persistent`&&!e.loaded;t?await this.options.platform.prepareManualRecovery(f):(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(f,e),await this.readiness.waitStopped(x(r).sock),t||await this.options.platform.remove(f)}}let e=await i.inspect();if(e.installed||e.loaded){let t=n.current?.recovery;if(!t||!e.raw||R(`sha256`).update(e.raw).digest(`hex`)!==t.sha256)throw new v(`conflict`);e.loaded&&await i.unload(),await this.readiness.waitStopped(x(r).sock);let a=await i.inspect();if(a.loaded||!a.raw?.equals(e.raw))throw new v(`conflict`);await i.restore(null)}},verifyAbsent:async()=>{if(await _())return;let e=await this.observe(n.current,await i.inspect());if(e.manual.loaded||e.persistent.loaded||e.legacy.installed||e.legacy.loaded||e.desktop?.loaded||e.local.kind!==`absent`)throw new v(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{await _()||(this.phase(n,`destination-start-requested`,{selection:g}),await this.desktop.start(g),await this.certify(g),this.phase(n,`destination-ready`))},complete:async()=>{this.publish(n,{selection:g,transition:null})}}),this.observe(n.current,await i.inspect())})))}async convertToHeadless(e,n,r,i,a,o,s){if(!s&&e.current?.mode===`headless`&&!n.current?.selection&&!n.current?.transition)return a;if([`foreign`,`unverified`].includes(a.local.kind))throw new v(`conflict`);await this.admitBundle(this.options.bundlePath);let c=await(this.options.inspectBundle??C)(this.options.bundlePath),l=D(o,this.options.uid);if(!l)throw new v(`unsafe-state`);let u=s&&n.current?.transition?.id===e.current?.transition?.id?n.current.transition:null,d=u?u.source:n.current?.selection??null,f=s?e.current.transition:{id:this.newId(),source:a.ownership?.mode??null,target:`headless`,sourceManager:d?.mode===`desktop`?`desktop-child`:d?.mode===`manual`?`native-manual`:d?.mode===`persistent`?`native-persistent`:null,sourceInstance:d?.serviceInstance??null,stateDir:o,computerFp:l.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(f.target!==`headless`||f.stateDir!==o||f.computerFp!==l.fp||f.targetBundlePath!==this.options.bundlePath||f.targetVersion!==this.options.agentVersion)throw new v(`conflict`);let p=d?.environment??(s&&i.definition?.serviceInstance===f.id?i.definition.environment:void 0),m={nodePath:c.nodePath,cliPath:F(this.options.bundlePath,`Contents/Resources/agent/dist/cli.js`),stateDir:o,serviceInstance:f.id,logPath:x(o).log,environment:{PATH:p?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,SHELLBELL_DIR:o,SHELLBELL_SERVICE_INSTANCE:f.id,...p?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:p.HERDR_SOCKET_PATH}:{},...p?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:p.XDG_CONFIG_HOME}:{}}},h=e=>{let t=e.definition;return e.installed&&!!t&&t.serviceInstance===f.id&&t.stateDir===o&&t.nodePath===m.nodePath&&t.cliPath===m.cliPath&&t.logPath===m.logPath&&JSON.stringify(Object.entries(t.environment).sort())===JSON.stringify(Object.entries(m.environment).sort())},g={stateDir:o,computerFp:l.fp,serviceInstance:f.id},_=async()=>{let e=await r.inspect();if(!h(e)||!e.loaded||(await this.readiness.observe(x(o).sock,g)).kind!==`verified`)return!1;let t=await r.inspect();return h(t)&&t.loaded};return await U(e,f,{preflight:async()=>{if((i.installed||i.loaded)&&(!s||!h(i))||i.loaded&&(a.manual.loaded||a.persistent.loaded||d?.mode===`desktop`&&(await this.desktop.inspect(d)).loaded)||d&&(d.stateDir!==o||d.computerFp!==l.fp)||a.manual.loaded&&d?.mode!==`manual`||a.persistent.loaded&&d?.mode!==`persistent`)throw new v(`conflict`)},stopSource:async()=>{this.publish(n,{transition:{id:f.id,action:`recover`,phase:`prepared`,source:d,destination:null,recoveryId:n.current?.recovery?.id??null}});let e=await this.options.platform.loginStatus(this.options.bundlePath);if(e===`unknown`)throw new v(`unavailable`);if((e===`enabled`||e===`requires-approval`)&&await this.options.platform.setLogin(this.options.bundlePath,!1),!await _()){if(d?.mode===`desktop`){let e=await this.desktop.inspect(d);if(e.loaded){let t=await this.readiness.observe(x(o).sock,{stateDir:o,computerFp:l.fp,serviceInstance:d.serviceInstance,...e.pid?{pid:e.pid}:{}});if(t.kind!==`verified`)throw new v(`conflict`);await this.desktop.stop({revision:n.current?.revision??null,runtime:t.local.process})}}else if(d){let e=await this.options.platform.inspect(d.mode,d.bundlePath),t=d.mode===`persistent`&&!e.loaded;t&&await this.options.platform.prepareManualRecovery(d),(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(d,e),await this.readiness.waitStopped(x(o).sock),t||await this.options.platform.remove(d)}}},verifyAbsent:async()=>{if(await _())return;let e=await this.observe(n.current,await r.inspect()),t=await r.inspect();if(e.manual.loaded||e.persistent.loaded||e.desktop?.loaded||t.loaded||t.installed&&!h(t)||e.local.kind!==`absent`)throw new v(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{if(await _())return;if(await this.admitBundle(this.options.bundlePath),D(o,this.options.uid)?.fp!==l.fp)throw new v(`unsafe-state`);t(m.logPath)||k(j(m.logPath,A.O_WRONLY|A.O_CREAT|A.O_EXCL|A.O_NOFOLLOW,384)),this.phase(n,`destination-start-requested`,{selection:null});let i=await r.inspect();if(!h(i)){if(i.installed||i.loaded)throw new v(`conflict`);await r.write(m)}await r.setStartupEnabled(e.current.startupEnabled);let a=await r.load();if(await this.readiness.waitReady(x(o).sock,{...g,pid:a}),!await _())throw new v(`conflict`);this.phase(n,`destination-ready`)},complete:async()=>{this.publish(n,{selection:null,transition:null})}}),this.observe(n.current,await r.inspect())}async diagnose(e){return this.options.diagnose?this.options.diagnose(this.statusStateDirectory(e)):[{name:`local-owner`,ok:e.local.kind===`verified`,severity:e.local.kind===`foreign`?`error`:e.local.kind===`verified`?`pass`:`warning`,detail:e.local.kind},{name:`legacy-service`,ok:!e.legacy.loaded,severity:e.legacy.loaded?`warning`:`pass`,detail:e.legacy.loaded?`Legacy service loaded`:`Legacy service stopped`}]}publish(e,t){return e.publish({v:1,selection:null,transition:null,recovery:null,...e.current,...t})}phase(e,t,n={}){let r=e.current?.transition;if(!r)throw new v(`recovery-required`);return this.publish(e,{...n,transition:{...r,phase:t}})}async admitBundle(e,t=this.options.agentVersion){let n=await(this.options.inspectBundle??C)(e);if(n.agentVersion!==t)throw new v(`upgrade-required`);return n}async lifecycle(t,n,r,i,a){if(t.cmd===`service.recover`)return this.recover(t,n,r,i,a);if(n.current?.transition)throw new v(`recovery-required`);let o=n.current?.selection??null;if(a.manual.loaded&&o?.mode!==`manual`||a.persistent.loaded&&o?.mode!==`persistent`||o&&i.loaded||t.cmd!==`service.start`&&!o||t.cmd===`service.start`&&o&&e(o.mode)===t.args.mode&&o.bundlePath===this.options.bundlePath&&a[e(o.mode)].loaded||i.installed&&(t.cmd!==`service.start`||!t.args.migrateLegacy))throw new v(`conflict`);let s=null;if(t.cmd===`service.start`||t.cmd===`service.restart`){await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(t.cmd===`service.start`?t.args.mode:e(o.mode),this.options.bundlePath);let n=o?.stateDir??i.definition?.stateDir??(t.cmd===`service.start`?t.args.stateDir:void 0)??this.options.defaultStateDir;if(t.cmd===`service.start`&&t.args.stateDir&&t.args.stateDir!==n)throw new v(`conflict`);!o&&!i.installed&&(D(n,this.options.uid),await this.requireAbsentDestination(n));let r=D(n,this.options.uid,!0),a=this.newId();s={mode:t.cmd===`service.start`?t.args.mode:o.mode,stateDir:n,computerFp:r.fp,serviceInstance:a,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,SHELLBELL_DIR:n,SHELLBELL_SERVICE_INSTANCE:a}}}let c=n.current?.recovery??null;if(i.installed){if(!i.raw||!i.definition||c)throw new v(`recovery-required`);let e=D(i.definition.stateDir,this.options.uid);if(!e)throw new v(`unsafe-state`);c={id:this.newId(),definitionPath:r.definitionPath,rawBase64:i.raw.toString(`base64`),sha256:R(`sha256`).update(i.raw).digest(`hex`),wasLoaded:i.loaded,stateDir:i.definition.stateDir,computerFp:e.fp}}this.publish(n,{recovery:c,transition:{id:this.newId(),action:t.cmd.slice(8),phase:`prepared`,source:o,destination:s,recoveryId:c?.id??null}});try{return await this.advance(n,r,i,a)}catch(e){throw this.phase(n,`recovery-required`),e}}async stopSource(t,n,r,i){let a=t.current.transition,o=a.source;if(this.phase(t,`source-stop-requested`),o){try{await this.admitBundle(o.bundlePath,o.agentVersion)}catch{throw new v(`recovery-required`)}let t=i[e(o.mode)];(t.loaded||t.registration!==`not-registered`)&&await this.options.platform.stop(o,t),await this.readiness.waitStopped(x(o.stateDir).sock);let n=await this.options.platform.inspect(e(o.mode),o.bundlePath);if(n.loaded||e(o.mode)===`persistent`&&n.registration!==`not-registered`)throw new v(`operation-failed`)}else if(r.installed){r.loaded&&await n.unload(),await this.readiness.waitStopped(x(r.definition.stateDir).sock);let e=await n.inspect();if(e.loaded||!e.raw?.equals(r.raw))throw new v(`conflict`)}else if(i.local.kind!==`absent`)throw new v(`conflict`);if(this.phase(t,`source-stopped`,{selection:a.action===`stop`?o:null}),o&&a.destination&&(e(o.mode)!==e(a.destination.mode)||o.bundlePath!==a.destination.bundlePath)&&await this.options.platform.remove(o),r.installed){await n.restore(null);let e=await n.inspect();if(e.installed||e.loaded)throw new v(`operation-failed`)}}async advance(e,t,n,r){let i=e.current.transition;return await this.stopSource(e,t,n,r),i.destination?await this.startDestination(e,i.destination):i.action===`remove`&&i.source&&(await this.options.platform.remove(i.source),this.publish(e,{selection:null})),e.current.transition?.phase!==`awaiting-approval`&&this.publish(e,{transition:null}),this.observe(e.current,await t.inspect())}async startDestination(e,t){if(await this.admitBundle(t.bundlePath),D(t.stateDir,this.options.uid)?.fp!==t.computerFp)throw new v(`unsafe-state`);if(await this.requireAbsentDestination(t.stateDir),this.phase(e,`destination-start-requested`,{selection:t}),(await this.options.platform.start(t)).registration===`requires-approval`){this.phase(e,`awaiting-approval`);return}await this.certify(t),this.phase(e,`destination-ready`)}async requireAbsentDestination(e){if((await this.readiness.observe(x(e).sock)).kind!==`absent`)throw new v(`conflict`)}async certify(t){let n=t.mode===`desktop`?await this.desktop.inspect(t):await this.options.platform.inspect(e(t.mode),t.bundlePath);if(!n.loaded||!n.pid)throw new v(`operation-failed`);let r=await this.readiness.waitReady(x(t.stateDir).sock,{computerFp:t.computerFp,stateDir:t.stateDir,serviceInstance:t.serviceInstance,pid:n.pid}),i=t.mode===`desktop`?await this.desktop.inspect(t):await this.options.platform.inspect(e(t.mode),t.bundlePath);if(JSON.stringify(n)!==JSON.stringify(i)||r.process.agentVersion!==t.agentVersion)throw new v(`conflict`)}isManualRecovery(e){let t=e?.transition;return t?.action===`recover`&&!t.restoreLegacy&&t.source?.mode===`persistent`&&t.destination?.mode===`manual`&&t.source.stateDir===t.destination.stateDir&&t.source.computerFp===t.destination.computerFp}async recover(t,n,r,i,a){let o=n.current;if(!o||a.manual.loaded&&a.persistent.loaded||o.selection&&i.loaded||o.selection&&a[e(o.selection.mode)===`manual`?`persistent`:`manual`].loaded)throw new v(`conflict`);if(t.args.action===`discard-backup`){if(o.transition||!o.recovery||i.installed&&i.raw?.toString(`base64`)!==o.recovery.rawBase64)throw new v(`conflict`);return this.publish(n,{recovery:null}),this.observe(n.current,i)}let s=o.recovery,c=s?Buffer.from(s.rawBase64,`base64`):null;if(s&&(!c||R(`sha256`).update(c).digest(`hex`)!==s.sha256)||s&&(s.definitionPath!==r.definitionPath||D(s.stateDir,this.options.uid)?.fp!==s.computerFp))throw new v(`unsafe-state`);if(s&&i.installed&&!i.raw?.equals(c))throw new v(`conflict`);let l=this.isManualRecovery(o);if(t.args.action===`use-manual`||t.args.action===`continue`&&l){let e=l?o.transition?.source:o.transition?.destination;if(e?.mode!==`persistent`||o.transition?.restoreLegacy||!l&&![`start`,`restart`].includes(o.transition.action)||o.selection?.serviceInstance!==e.serviceInstance||a.manual.loaded||a.persistent.loaded||a.local.kind!==`absent`||i.installed||i.loaded)throw new v(`conflict`);if(await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(`manual`,this.options.bundlePath),D(e.stateDir,this.options.uid)?.fp!==e.computerFp)throw new v(`unsafe-state`);let t=this.newId(),s=l?o.transition.destination:{...e,mode:`manual`,bundlePath:this.options.bundlePath,agentVersion:this.options.agentVersion,serviceInstance:t,environment:{...e.environment,SHELLBELL_SERVICE_INSTANCE:t}};l||this.publish(n,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:e,destination:s,recoveryId:o.recovery?.id??null}});try{await this.options.platform.prepareManualRecovery(e),await this.requireAbsentDestination(e.stateDir);let t=await this.observe(n.current,await r.inspect());if(t.manual.loaded||t.persistent.loaded||t.legacy.installed||t.legacy.loaded||t.local.kind!==`absent`)throw new v(`conflict`);return this.publish(n,{selection:null,transition:{id:this.newId(),action:`start`,phase:`source-stopped`,source:null,destination:s,recoveryId:o.recovery?.id??null}}),await this.startDestination(n,s),this.publish(n,{transition:null}),this.observe(n.current,await r.inspect())}catch(e){throw this.phase(n,`recovery-required`),e}}if(t.args.action===`continue`&&o.transition?.action===`recover`&&!o.transition.restoreLegacy)throw new v(`recovery-required`);try{if(t.args.action===`restore-legacy`||o.transition?.restoreLegacy){if(!s||!c)throw new v(`conflict`);if(t.args.action===`restore-legacy`){if(i.loaded)throw new v(`conflict`);this.publish(n,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:o.selection,destination:null,recoveryId:s.id,restoreLegacy:{restartPrevious:t.args.restartPrevious}}})}return await this.restoreLegacy(n,r,i,a,c)}let l=o.transition;if(!l)throw new v(`conflict`);let u=l.destination;if(u&&o.selection?.serviceInstance===u.serviceInstance){let t=a[e(u.mode)];if(i.loaded||a[e(u.mode)===`manual`?`persistent`:`manual`].loaded)throw new v(`conflict`);if(t.registration===`requires-approval`)return this.phase(n,`awaiting-approval`),this.observe(n.current,i);if(t.loaded)await this.certify(u),this.phase(n,`destination-ready`);else{if(a.local.kind!==`absent`)throw new v(`conflict`);await this.startDestination(n,u)}return n.current.transition?.phase!==`awaiting-approval`&&this.publish(n,{transition:null}),this.observe(n.current,await r.inspect())}return await this.advance(n,r,i,a)}catch(e){throw n.current?.transition&&this.phase(n,`recovery-required`),e}}async restoreLegacy(e,t,n,r,i){let a=e.current,o=a.recovery,s=a.transition.restoreLegacy;if(n.loaded){if(!s.restartPrevious||a.selection||r.manual.loaded||r.persistent.loaded||r.local.kind!==`verified`||!n.raw?.equals(i))throw new v(`conflict`);let o=await t.inspect();if(!o.loaded||!o.raw?.equals(i))throw new v(`conflict`);return this.publish(e,{selection:null,transition:null}),this.observe(e.current,o)}if(a.selection)await this.stopSource(e,t,{installed:!1,loaded:!1,raw:null,definition:null},r);else if(r.manual.loaded||r.persistent.loaded||r.local.kind!==`absent`)throw new v(`conflict`);await this.readiness.waitStopped(x(o.stateDir).sock),this.phase(e,`source-stopped`,{selection:null}),n.installed||await t.restore(i);let c=await t.inspect();if(!c.raw?.equals(i)||c.loaded)throw new v(`operation-failed`);if(s.restartPrevious){this.phase(e,`destination-start-requested`);let n=await t.load();await this.readiness.waitReady(x(o.stateDir).sock,{computerFp:o.computerFp,stateDir:o.stateDir,serviceInstance:c.definition?.serviceInstance??null,pid:n});let r=await t.inspect();if(!r.loaded||!r.raw?.equals(i))throw new v(`conflict`)}return this.publish(e,{selection:null,transition:null}),this.observe(e.current,await t.inspect())}emit(e){for(let t of this.listeners)t(e)}onEvent(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async close(){this.closed=!0,this.client?.close(),this.client=void 0,this.listeners.clear(),await this.desktop.close()}};async function G(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${o}\n`:`Shellbell native controller
3
3
  `);return}if(process.argv.length!==2||process.execArgv.length||process.env.NODE_OPTIONS||process.env.NODE_PATH)throw Error();let e=N();if(process.platform!==`darwin`||e.uid<=0)throw Error();let t=I(P(L(import.meta.url)),`../../../..`);if((await C(t)).agentVersion!==o)throw Error();let n=F(e.homedir,`Library/Application Support/Shellbell`),r=new W({store:new w({root:n,uid:e.uid}),platform:T({root:n,uid:e.uid,homeDir:e.homedir}),bundlePath:t,uid:e.uid,homeDir:e.homedir,agentVersion:o,defaultStateDir:F(e.homedir,`.shellbell`)}),i=V(process.stdin,process.stdout,r,{agentVersion:o}),a=()=>{i.close().catch(()=>{process.exitCode=1})};process.once(`SIGTERM`,a),process.once(`SIGINT`,a)}process.argv[1]&&M(process.argv[1])===L(import.meta.url)&&G().catch(()=>{process.stderr.write(`Shellbell controller unavailable
4
4
  `),process.exitCode=1});export{};
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{Nt as e,tt as t,ut as n,w as r}from"./service-lifecycle-BCnZrcYZ.js";import{a as i,n as a,r as o}from"./service-entry-CMjd9ogv.js";import{createReadStream as s,fstatSync as c,realpathSync as l}from"node:fs";import{userInfo as u}from"node:os";import{dirname as d,join as f,resolve as p}from"node:path";import{fileURLToPath as m}from"node:url";async function h(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${e}\n`:`Shellbell native service
2
+ import{Nt as e,tt as t,ut as n,w as r}from"./service-lifecycle-De-Hj3Tl.js";import{a as i,n as a,r as o}from"./service-entry-BBSp8-ir.js";import{createReadStream as s,fstatSync as c,realpathSync as l}from"node:fs";import{userInfo as u}from"node:os";import{dirname as d,join as f,resolve as p}from"node:path";import{fileURLToPath as m}from"node:url";async function h(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${e}\n`:`Shellbell native service
3
3
  `);return}let l=r.parse(process.argv[2]);if(process.argv.length!==3||process.execArgv.length||process.env.NODE_OPTIONS||process.env.NODE_PATH)throw Error();let h=u();if(process.platform!==`darwin`||h.uid<=0)throw Error();let g=p(d(m(import.meta.url)),`../../../..`),_=await i(g);if(_.agentVersion!==e)throw Error();let v=f(h.homedir,`Library/Application Support/Shellbell`),y=await a(l,{...l===`desktop`?{ownerInput:(()=>{let e=c(3);if(!e.isFIFO()&&!e.isSocket())throw Error(`invalid owner channel`);return s(``,{fd:3,autoClose:!0})})(),onOwnerLost:e=>process.exit(e===null?0:1)}:{},bundlePath:g,root:v,uid:h.uid,async start(e){if(e.agentVersion!==_.agentVersion)throw Error();let r=o(e,h.homedir,process.env);for(let e of Object.keys(process.env))delete process.env[e];Object.assign(process.env,r);let{buildAgent:i,shutdown:a}=await import(new URL(`./cli.js`,import.meta.url).href),s=n(e.stateDir),c=t({file:s.log,stdout:!1}),l={debug:()=>{},info:()=>c.info(`agent-event`),warn:()=>c.warn(`agent-event`),error:()=>c.error(`agent-event`),child:()=>l},u=await i(l,void 0,!1,{paths:s,serviceInstance:e.serviceInstance,nativeService:!0});try{await u.control.start(),u.agent.start()}catch(e){throw u.stopBackendDetectors(),u.agent.stop(),await u.control.stop(),e}let d;return{stop(){return d??=a(u.agent,u.control,e=>{e&&process.exit(1)},u.stopBackendDetectors),d}}}}),b=()=>{y.stop().then(()=>process.exit(0),()=>process.exit(1))};process.once(`SIGTERM`,b),process.once(`SIGINT`,b)}process.argv[1]&&l(process.argv[1])===m(import.meta.url)&&h().catch(()=>{process.stderr.write(`Shellbell service unavailable
4
4
  `),process.exitCode=1});export{};
@@ -1,4 +1,4 @@
1
- import{A as e,C as t,D as n,Dt as r,E as i,O as a,Ot as o,T as s,Tt as c,c as l,dt as u,f as d,i as f,k as p,kt as m,m as h,p as g,pt as _,ut as v,v as y,x as b,y as x}from"./service-lifecycle-BCnZrcYZ.js";import{createRequire as S}from"node:module";import{closeSync as C,constants as w,fstatSync as T,mkdirSync as E,openSync as ee,readdirSync as D,realpathSync as O,unlinkSync as k}from"node:fs";import{basename as te,dirname as A,join as j}from"node:path";import{z as M}from"zod";const N=`sh.bilal.shellbell.host.manual`;function P(e){(!s.safeParse(e).success||e!==j(e))&&F();for(let t=e;;t=A(t)){let e=r(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new h(`unsafe-state`)}function I(e){return(!s.safeParse(e).success||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&F(),e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&apos;`)}function L(e){return(e!==j(e)||!e.endsWith(`/Shellbell.app/Contents/MacOS/Shellbell`))&&F(),Buffer.from(`<?xml version="1.0" encoding="UTF-8"?>
1
+ import{A as e,C as t,D as n,Dt as r,E as i,O as a,Ot as o,T as s,Tt as c,c as l,dt as u,f as d,i as f,k as p,kt as m,m as h,p as g,pt as _,ut as v,v as y,x as b,y as x}from"./service-lifecycle-De-Hj3Tl.js";import{createRequire as S}from"node:module";import{closeSync as C,constants as w,fstatSync as T,mkdirSync as E,openSync as ee,readdirSync as D,realpathSync as O,unlinkSync as k}from"node:fs";import{basename as te,dirname as A,join as j}from"node:path";import{z as M}from"zod";const N=`sh.bilal.shellbell.host.manual`;function P(e){(!s.safeParse(e).success||e!==j(e))&&F();for(let t=e;;t=A(t)){let e=r(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new h(`unsafe-state`)}function I(e){return(!s.safeParse(e).success||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&F(),e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&apos;`)}function L(e){return(e!==j(e)||!e.endsWith(`/Shellbell.app/Contents/MacOS/Shellbell`))&&F(),Buffer.from(`<?xml version="1.0" encoding="UTF-8"?>
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0"><dict>
4
4
  <key>Label</key><string>${N}</string>