shellbell 0.12.0 → 0.13.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 +35 -96
- package/dist/doctor-D2Hd_mqM.js +86 -0
- package/dist/native-controller.js +2 -2
- package/dist/native-service.js +2 -2
- package/dist/service-entry-Dz0BLRLS.js +11 -0
- package/dist/service-lifecycle-CCOIXXFm.js +29 -0
- package/package.json +1 -1
- package/dist/service-entry-BBSp8-ir.js +0 -11
- package/dist/service-lifecycle-De-Hj3Tl.js +0 -29
|
@@ -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-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
|
-
`);return}if(process.argv.length!==2||process.execArgv.length||process.env.NODE_OPTIONS||process.env.NODE_PATH)throw Error();let e=
|
|
2
|
+
import{C as e,F as t,H as n,I as r,L as i,Ot as a,P as o,Pt as s,S as c,U as l,V as u,_ as d,b as f,c as p,dt as m,ft as h,g,h as _,it as v,m as y,o as b,ot as x,x as S}from"./service-lifecycle-CCOIXXFm.js";import{H as C,L as w,U as T,V as E,t as D,z as O}from"./doctor-D2Hd_mqM.js";import{a as k,i as A,o as j,r as M,t as N}from"./service-entry-Dz0BLRLS.js";import{spawn as P}from"node:child_process";import{closeSync as F,constants as I,openSync as L,realpathSync as R}from"node:fs";import{userInfo as z}from"node:os";import{dirname as B,join as V,resolve as H}from"node:path";import{fileURLToPath as U}from"node:url";import{createHash as W,randomUUID as G}from"node:crypto";import{performance as K}from"node:perf_hooks";function q(e,t,n,a){let o=!1,s=!1,c=0,l=!1,u=!1,p=!1,m,h,v,b,x=()=>b||(o=!0,clearTimeout(v),w(),e.off(`data`,E),e.off(`end`,D),e.destroy(),b=Promise.resolve(n.close()).finally(()=>{t.end()}),b.catch(()=>{}),b),S=e=>{if(o)return!1;let n=i(e),r=t.writableLength;if(!n||t.destroyed||!Number.isFinite(r)||r<0||r+n.byteLength>262144)return x(),!1;try{t.write(n)}catch{return x(),!1}return!0},C=(e,t)=>S({v:1,id:e,ok:!1,error:{code:t}}),w=n.onEvent(e=>{let t=d.safeParse(e);if(!t.success){x();return}if(p){m?x():m=t.data;return}if(t.data.flowId!==h){x();return}S(t.data),t.data.event===`pairing.closed`&&(h=void 0)}),T=new r({onError:x,onLine(e){if(o)return;let t;try{t=JSON.parse(e)}catch{x();return}let r=f.safeParse(t);if(!r.success){typeof t==`object`&&t&&`id`in t&&typeof t.id==`number`&&Number.isSafeInteger(t.id)&&t.id>c&&C(t.id,`v`in t&&t.v!==1?`unsupported-version`:`bad-request`),x();return}let d=r.data;if(d.id<=c){x();return}if(c=d.id,!s){if(d.cmd!==`hello`){C(d.id,`handshake-required`),x();return}s=!0,clearTimeout(v),S({v:1,id:d.id,ok:!0,data:_.hello.parse({version:1,agentVersion:a.agentVersion,capabilities:[`status`,`settings`,`lifecycle`,`pairing`,`devices`,`diagnostics`]})});return}if(d.cmd===`hello`){x();return}if(l){C(d.id,`busy`),u||x();return}l=!0,u=!1,p=d.cmd===`pairing.open`;let b=`args`in d;v=setTimeout(()=>{if(b){C(d.id,`delivery-unknown`),x();return}u=!0,C(d.id,`timeout`)},b?6e4:5e3),n.execute(d).then(e=>{if(o||u)return;let t=_[d.cmd].safeParse(e);if(!t.success){if(!b){C(d.id,`operation-failed`);return}C(d.id,`delivery-unknown`),x();return}if(d.cmd===`pairing.open`&&(h=t.data.flowId),!i({v:1,id:d.id,ok:!0,data:t.data})){C(d.id,`response-too-large`),x();return}if(S({v:1,id:d.id,ok:!0,data:t.data}),p=!1,m){if(m.flowId!==h){x();return}S(m),m.event===`pairing.closed`&&(h=void 0),m=void 0}},e=>{if(u)return;let t=e instanceof y&&g.safeParse(e.code).success?e.code:`operation-failed`;C(d.id,t),p=!1,m=void 0}).finally(()=>{clearTimeout(v),l=!1,u=!1})}}),E=e=>T.push(e),D=()=>{T.finish(),x()};return e.on(`data`,E),e.once(`end`,D),e.once(`error`,x),t.once(`error`,x),v=setTimeout(x,5e3),{close:x}}var J=class{options;owned;starting;closed=!1;readiness;clock;constructor(e){this.options=e,this.readiness=e.readiness??new b,this.clock=e.clock??{now:()=>K.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 y(`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 y(`busy`)):!S.safeParse(e).success||e.mode!==`desktop`?Promise.reject(new y(`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??k)(e.bundlePath);if(t.agentVersion!==e.agentVersion||this.closed||(await this.readiness.observe(m(e.stateDir).sock)).kind!==`absent`||this.closed)throw new y(`conflict`);let n=P(t.nodePath,[t.servicePath,`desktop`],{cwd:this.options.homeDir,env:M(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 y(`unavailable`);let i=await this.readiness.observe(m(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 y(`conflict`);await this.clock.sleep(Math.min(25,Math.max(0,t-this.clock.now())))}throw new y(`unavailable`)}catch(e){throw await this.stopOwned(r),e}}async stop(e){let t=this.owned;if(!t){if(e.runtime)throw new y(`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 y(`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(m(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 y(`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 y(`unavailable`);if((await this.readiness.observe(m(e.selection.stateDir).sock)).kind!==`absent`)throw new y(`conflict`);e.pipe.destroy(),this.owned===e&&(this.owned=void 0)}};async function Y(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 X=class{options;desktop;readiness;newId;client;listeners=new Set;observedStateDirs=new WeakMap;closed=!1;constructor(e){this.options=e,this.desktop=e.desktop??new J({uid:e.uid,homeDir:e.homeDir,readiness:e.readiness,admitBundle:e.inspectBundle}),this.readiness=e.readiness??new b,this.newId=e.newId??G}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=N(u,this.options.uid),f=r?.mode===`desktop`?await this.desktop.inspect(r):{registration:`not-registered`,loaded:!1,pid:null,bundlePath:null},h=r?r.mode===`desktop`?f:e(r.mode)===`manual`?a:o:null,g=d?{stateDir:u,computerFp:d.fp,serviceInstance:r?.serviceInstance??n.definition?.serviceInstance??null,...h?.pid?{pid:h.pid}:{}}:void 0,_=await this.readiness.observe(m(u).sock,g);if(_.kind===`verified`&&(!d||r&&(!h?.loaded||!h.pid||d.fp!==r.computerFp))&&(_.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(h)&&(_.kind=`unverified`,_.local=null)}let v=new p({stateDir:u,uid:this.options.uid}).inspect(),y=c.parse({desktopLogin:s,desktop:f,ownership:{revision:v?.revision??null,mode:v?.mode??(r||t?.transition?`legacy-native`:n.installed||n.loaded?`headless`:null),consented:v?.consented??!1,startupEnabled:v?.startupEnabled??null,transition:v?.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&&_.kind===`absent`&&!n.installed&&!n.loaded,legacy:{installed:n.installed,loaded:n.loaded,stateDir:n.definition?.stateDir??null},manual:a,persistent:o,local:{kind:_.kind,status:_.local}});return l&&this.observedStateDirs.set(y,l),y}error(e){return e instanceof y?e:e instanceof v?new y(e.code===`busy`?`busy`:e.code===`invalid`?`invalid-config`:`unsafe-state`):e instanceof o?e.code===`server-error`?new y(e.serverCode===`runtime-mismatch`||e.serverCode===`configuration-mismatch`?`conflict`:e.serverCode===`pairing-busy`?`busy`:`operation-failed`):new y(e.code===`protocol-error`||e.code===`closed`?`unavailable`:e.code):new y(`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 y(`conflict`)}async control(e){let n=e.local.status?.process;if(e.local.kind!==`verified`||!n)throw new y(`unavailable`);if(this.client&&!this.exact(this.client.runtime,n)&&(this.client.close(),this.client=void 0),!this.client){let e=await(this.options.connect??t)(m(n.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 y(`unavailable`);if(!this.exact(e.runtime,n))throw e.close(),new y(`conflict`);this.client=e}return this.client}async settings(e){let t=this.statusStateDirectory(e),n=h(m(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 y(`unavailable`);let t=f.safeParse(e);if(!t.success||t.data.cmd===`hello`)throw new y(`bad-request`);let r=t.data,i;if(r.cmd===`terminals.connect`){let e=await(await this.control(await this.status())).connectTerminal(r.args.name);i=e?{supported:!0,...e}:{supported:!1,started:!1,terminals:[]}}else if(r.cmd===`agents.setup`||r.cmd===`agents.skip`||r.cmd===`agents.remove`){let e=w(this.statusStateDirectory(await this.status()),this.options.homeDir);i={agents:r.cmd===`agents.setup`?C(e,r.args.kinds):r.cmd===`agents.skip`?T(e,r.args.kinds):E(e,r.args.kind)}}else if(`args`in r)i=`ownerRevision`in r.args?await this.ownership(r):await this.guardLegacy(r,e=>this.options.store.mutate(r.args.expect.revision,async t=>this.options.platform.withLegacyGuard(async i=>{let a=await i.inspect(),o=await this.observe(t.current,a);if(r.cmd.startsWith(`service.`)&&(o.ownership?.mode===`desktop`||o.ownership?.transition))throw new y(`conflict`);let s=(r.cmd===`service.start`&&r.args.migrateLegacy||r.cmd===`service.recover`&&r.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,r.args.expect,s),r.cmd.startsWith(`service.`))return this.lifecycle(r,t,i,a,o);if(r.cmd===`settings.set`){let t=this.statusStateDirectory(o);if(t!==e)throw new y(`conflict`);let i=m(t),a=x(i,e=>{if(u(e)!==r.args.configRevision)throw new y(`conflict`);let t=e;for(let i of r.args.changes){if(n(e,i.key)===i.value)continue;let r=l(t,i.key,i.value,!1);if(`error`in r)throw new y(`invalid-config`);t=r.next}return t});if(o.local.kind===`verified`&&r.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(r.cmd===`devices.revoke`)return c.revoke(r.args.phoneFp);if(r.cmd===`pairing.open`)return c.openPairing();if(r.cmd===`pairing.close`)return await c.closePairing(r.args.flowId),{};if(r.cmd===`pairing.confirm`)return await c.confirm(r.args.flowId,r.args.challengeId,r.args.phoneFp,r.args.accept),{};throw new y(`bad-request`)}).catch(e=>{throw this.error(e)})));else{let e=await this.status();if(r.cmd===`status`)i=e;else if(r.cmd===`agents`)i={agents:O(w(this.statusStateDirectory(e),this.options.homeDir))};else if(r.cmd===`settings.get`)i=await this.settings(e);else if(r.cmd===`devices`)i=await(await this.control(e)).devices();else if(r.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=_[r.cmd].safeParse(i);if(!a.success)throw new y(`args`in r?`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&&(N(r,this.options.uid),await this.requireAbsentDestination(r));let i=new p({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 y(`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 y(`conflict`);let r=this.stateDirectory(n,t.legacy.stateDir),i=new p({stateDir:r,uid:this.options.uid});if((e.cmd===`desktop.start`||e.cmd===`desktop.stop`)&&(t.ownership?.mode!==`desktop`||!t.ownership.consented))throw new y(`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 y(`conflict`);if(t.current.transition||n.current?.transition)throw new y(`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 y(`conflict`);if(o.local.kind===`absent`&&!o.desktop?.loaded)return o;if(o.local.kind!==`verified`)throw new y(`conflict`);return await this.desktop.stop(e.args.expect),await this.readiness.waitStopped(m(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 y(`conflict`)}else if(e.cmd===`desktop.start`){if(t.current?.transition||n.current?.transition)throw new y(`recovery-required`);if(t.current?.mode!==`desktop`||!t.current.consented||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded)throw new y(`conflict`);if(o.local.kind===`verified`&&o.selection?.mode===`desktop`&&o.desktop?.loaded)return o;if(o.local.kind!==`absent`)throw new y(`conflict`)}else if(e.cmd===`ownership.recover`){if(!t.current?.transition||t.current.transition.id!==e.args.intentId)throw new y(`conflict`)}else if(t.current?.transition)throw new y(`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 y(`conflict`);let l=N(r,this.options.uid,e.cmd===`desktop.setup`);if(!l)throw new y(`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 y(`conflict`);let h=this.newId(),g=f?.environment??a.definition?.environment,_=d??u?.destination??{mode:`desktop`,stateDir:r,computerFp:l.fp,serviceInstance:h,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:g?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,...g?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:g.HERDR_SOCKET_PATH}:{},...g?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:g.XDG_CONFIG_HOME}:{},SHELLBELL_DIR:r,SHELLBELL_SERVICE_INSTANCE:h}};if(_.mode!==`desktop`||_.computerFp!==l.fp||_.stateDir!==r||_.bundlePath!==p.targetBundlePath||_.agentVersion!==p.targetVersion)throw new y(`conflict`);let v=async()=>{let e=await this.observe(n.current,await i.inspect());return e.selection?.serviceInstance===_.serviceInstance&&e.local.kind===`verified`&&!!e.desktop?.loaded&&!e.manual.loaded&&!e.persistent.loaded&&!e.legacy.installed&&!e.legacy.loaded};return await Y(t,p,{preflight:async()=>{if(!S.safeParse(_).success)throw new y(`unsafe-state`);await this.admitBundle(_.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 y(`recovery-required`);e={id:this.newId(),definitionPath:i.definitionPath,rawBase64:a.raw.toString(`base64`),sha256:W(`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:_,recoveryId:e?.id??null}})}if(await v())return;if(f){if(f.stateDir!==r||f.computerFp!==l.fp)throw new y(`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 y(`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(m(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||W(`sha256`).update(e.raw).digest(`hex`)!==t.sha256)throw new y(`conflict`);e.loaded&&await i.unload(),await this.readiness.waitStopped(m(r).sock);let a=await i.inspect();if(a.loaded||!a.raw?.equals(e.raw))throw new y(`conflict`);await i.restore(null)}},verifyAbsent:async()=>{if(await v())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 y(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{await v()||(this.phase(n,`destination-start-requested`,{selection:_}),await this.desktop.start(_),await this.certify(_),this.phase(n,`destination-ready`))},complete:async()=>{this.publish(n,{selection:_,transition:null})}}),this.observe(n.current,await i.inspect())})))}async convertToHeadless(e,t,n,r,i,o,s){if(!s&&e.current?.mode===`headless`&&!t.current?.selection&&!t.current?.transition)return i;if([`foreign`,`unverified`].includes(i.local.kind))throw new y(`conflict`);await this.admitBundle(this.options.bundlePath);let c=await(this.options.inspectBundle??k)(this.options.bundlePath),l=N(o,this.options.uid);if(!l)throw new y(`unsafe-state`);let u=s&&t.current?.transition?.id===e.current?.transition?.id?t.current.transition:null,d=u?u.source:t.current?.selection??null,f=s?e.current.transition:{id:this.newId(),source:i.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 y(`conflict`);let p=d?.environment??(s&&r.definition?.serviceInstance===f.id?r.definition.environment:void 0),h={nodePath:c.nodePath,cliPath:V(this.options.bundlePath,`Contents/Resources/agent/dist/cli.js`),stateDir:o,serviceInstance:f.id,logPath:m(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}:{}}},g=e=>{let t=e.definition;return e.installed&&!!t&&t.serviceInstance===f.id&&t.stateDir===o&&t.nodePath===h.nodePath&&t.cliPath===h.cliPath&&t.logPath===h.logPath&&JSON.stringify(Object.entries(t.environment).sort())===JSON.stringify(Object.entries(h.environment).sort())},_={stateDir:o,computerFp:l.fp,serviceInstance:f.id},v=async()=>{let e=await n.inspect();if(!g(e)||!e.loaded||(await this.readiness.observe(m(o).sock,_)).kind!==`verified`)return!1;let t=await n.inspect();return g(t)&&t.loaded};return await Y(e,f,{preflight:async()=>{if((r.installed||r.loaded)&&(!s||!g(r))||r.loaded&&(i.manual.loaded||i.persistent.loaded||d?.mode===`desktop`&&(await this.desktop.inspect(d)).loaded)||d&&(d.stateDir!==o||d.computerFp!==l.fp)||i.manual.loaded&&d?.mode!==`manual`||i.persistent.loaded&&d?.mode!==`persistent`)throw new y(`conflict`)},stopSource:async()=>{this.publish(t,{transition:{id:f.id,action:`recover`,phase:`prepared`,source:d,destination:null,recoveryId:t.current?.recovery?.id??null}});let e=await this.options.platform.loginStatus(this.options.bundlePath);if(e===`unknown`)throw new y(`unavailable`);if((e===`enabled`||e===`requires-approval`)&&await this.options.platform.setLogin(this.options.bundlePath,!1),!await v()){if(d?.mode===`desktop`){let e=await this.desktop.inspect(d);if(e.loaded){let n=await this.readiness.observe(m(o).sock,{stateDir:o,computerFp:l.fp,serviceInstance:d.serviceInstance,...e.pid?{pid:e.pid}:{}});if(n.kind!==`verified`)throw new y(`conflict`);await this.desktop.stop({revision:t.current?.revision??null,runtime:n.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(m(o).sock),t||await this.options.platform.remove(d)}}},verifyAbsent:async()=>{if(await v())return;let e=await this.observe(t.current,await n.inspect()),r=await n.inspect();if(e.manual.loaded||e.persistent.loaded||e.desktop?.loaded||r.loaded||r.installed&&!g(r)||e.local.kind!==`absent`)throw new y(`conflict`);this.phase(t,`source-stopped`,{selection:null})},startDestination:async()=>{if(await v())return;if(await this.admitBundle(this.options.bundlePath),N(o,this.options.uid)?.fp!==l.fp)throw new y(`unsafe-state`);a(h.logPath)||F(L(h.logPath,I.O_WRONLY|I.O_CREAT|I.O_EXCL|I.O_NOFOLLOW,384)),this.phase(t,`destination-start-requested`,{selection:null});let r=await n.inspect();if(!g(r)){if(r.installed||r.loaded)throw new y(`conflict`);await n.write(h)}await n.setStartupEnabled(e.current.startupEnabled);let i=await n.load();if(await this.readiness.waitReady(m(o).sock,{..._,pid:i}),!await v())throw new y(`conflict`);this.phase(t,`destination-ready`)},complete:async()=>{this.publish(t,{selection:null,transition:null})}}),this.observe(t.current,await n.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`},D(this.statusStateDirectory(e),this.options.homeDir)]}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 y(`recovery-required`);return this.publish(e,{...n,transition:{...r,phase:t}})}async admitBundle(e,t=this.options.agentVersion){let n=await(this.options.inspectBundle??k)(e);if(n.agentVersion!==t)throw new y(`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 y(`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 y(`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 y(`conflict`);!o&&!i.installed&&(N(n,this.options.uid),await this.requireAbsentDestination(n));let r=N(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 y(`recovery-required`);let e=N(i.definition.stateDir,this.options.uid);if(!e)throw new y(`unsafe-state`);c={id:this.newId(),definitionPath:r.definitionPath,rawBase64:i.raw.toString(`base64`),sha256:W(`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 y(`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(m(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 y(`operation-failed`)}else if(r.installed){r.loaded&&await n.unload(),await this.readiness.waitStopped(m(r.definition.stateDir).sock);let e=await n.inspect();if(e.loaded||!e.raw?.equals(r.raw))throw new y(`conflict`)}else if(i.local.kind!==`absent`)throw new y(`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 y(`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),N(t.stateDir,this.options.uid)?.fp!==t.computerFp)throw new y(`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(m(e).sock)).kind!==`absent`)throw new y(`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 y(`operation-failed`);let r=await this.readiness.waitReady(m(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 y(`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 y(`conflict`);if(t.args.action===`discard-backup`){if(o.transition||!o.recovery||i.installed&&i.raw?.toString(`base64`)!==o.recovery.rawBase64)throw new y(`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||W(`sha256`).update(c).digest(`hex`)!==s.sha256)||s&&(s.definitionPath!==r.definitionPath||N(s.stateDir,this.options.uid)?.fp!==s.computerFp))throw new y(`unsafe-state`);if(s&&i.installed&&!i.raw?.equals(c))throw new y(`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 y(`conflict`);if(await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(`manual`,this.options.bundlePath),N(e.stateDir,this.options.uid)?.fp!==e.computerFp)throw new y(`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 y(`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 y(`recovery-required`);try{if(t.args.action===`restore-legacy`||o.transition?.restoreLegacy){if(!s||!c)throw new y(`conflict`);if(t.args.action===`restore-legacy`){if(i.loaded)throw new y(`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 y(`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 y(`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 y(`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 y(`conflict`);let o=await t.inspect();if(!o.loaded||!o.raw?.equals(i))throw new y(`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 y(`conflict`);await this.readiness.waitStopped(m(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 y(`operation-failed`);if(s.restartPrevious){this.phase(e,`destination-start-requested`);let n=await t.load();await this.readiness.waitReady(m(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 y(`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 Z(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${s}\n`:`Shellbell native controller
|
|
3
|
+
`);return}if(process.argv.length!==2||process.execArgv.length||process.env.NODE_OPTIONS||process.env.NODE_PATH)throw Error();let e=z();if(process.platform!==`darwin`||e.uid<=0)throw Error();let t=H(B(U(import.meta.url)),`../../../..`);if((await k(t)).agentVersion!==s)throw Error();let n=V(e.homedir,`Library/Application Support/Shellbell`),r=new X({store:new A({root:n,uid:e.uid}),platform:j({root:n,uid:e.uid,homeDir:e.homedir}),bundlePath:t,uid:e.uid,homeDir:e.homedir,agentVersion:s,defaultStateDir:V(e.homedir,`.shellbell`)}),i=q(process.stdin,process.stdout,r,{agentVersion:s}),a=()=>{i.close().catch(()=>{process.exitCode=1})};process.once(`SIGTERM`,a),process.once(`SIGINT`,a)}process.argv[1]&&R(process.argv[1])===U(import.meta.url)&&Z().catch(()=>{process.stderr.write(`Shellbell controller unavailable
|
|
4
4
|
`),process.exitCode=1});export{};
|
package/dist/native-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`);return}let
|
|
2
|
+
import{Pt as e,dt as t,nt as n,tt as r,w as i}from"./service-lifecycle-CCOIXXFm.js";import{a,n as o,r as s}from"./service-entry-Dz0BLRLS.js";import{createReadStream as c,fstatSync as l,realpathSync as u}from"node:fs";import{userInfo as d}from"node:os";import{dirname as f,join as p,resolve as m}from"node:path";import{fileURLToPath as h}from"node:url";async function g(){if(process.argv.length===3&&[`--help`,`--version`].includes(process.argv[2])){process.stdout.write(process.argv[2]===`--version`?`${e}\n`:`Shellbell native service
|
|
3
|
+
`);return}let u=i.parse(process.argv[2]);if(process.argv.length!==3||process.execArgv.length||process.env.NODE_OPTIONS||process.env.NODE_PATH)throw Error();let g=d();if(process.platform!==`darwin`||g.uid<=0)throw Error();let _,v=m(f(h(import.meta.url)),`../../../..`),y=await a(v);if(y.agentVersion!==e)throw Error();let b=p(g.homedir,`Library/Application Support/Shellbell`),x=await o(u,{...u===`desktop`?{ownerInput:(()=>{let e=l(3);if(!e.isFIFO()&&!e.isSocket())throw Error(`invalid owner channel`);return c(``,{fd:3,autoClose:!0})})(),onOwnerLost:e=>{_?.warn(e===null?`app connection closed; stopping`:`app connection failed; stopping`),process.exit(e===null?0:1)}}:{},bundlePath:v,root:b,uid:g.uid,async start(e){if(e.agentVersion!==y.agentVersion)throw Error();let i=s(e,g.homedir,process.env);for(let e of Object.keys(process.env))delete process.env[e];Object.assign(process.env,i);let{buildAgent:a,shutdown:o}=await import(new URL(`./cli.js`,import.meta.url).href),c=t(e.stateDir),l=r({file:c.log,stdout:!1}),u=n(l);_=u,u.info(`service starting`);let d=await a(u,void 0,!1,{paths:c,serviceInstance:e.serviceInstance,nativeService:!0});try{await d.control.start(),d.agent.start()}catch(e){throw d.stopBackendDetectors(),d.agent.stop(),await d.control.stop(),e}let f;return{stop(){return f??=o(d.agent,d.control,e=>{e&&process.exit(1)},d.stopBackendDetectors),f}}}}),S=()=>{_?.info(`asked to stop`),x.stop().then(()=>process.exit(0),()=>process.exit(1))};process.once(`SIGTERM`,S),process.once(`SIGINT`,S)}process.argv[1]&&u(process.argv[1])===h(import.meta.url)&&g().catch(()=>{process.stderr.write(`Shellbell service unavailable
|
|
4
4
|
`),process.exitCode=1});export{};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{A as e,At as t,C as n,D as r,E as i,Et as a,O as o,Ot as s,T as c,c as l,dt as u,f as d,ft as f,i as p,k as m,kt as h,m as g,mt as _,p as v,v as y,x as b,y as x}from"./service-lifecycle-CCOIXXFm.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){(!c.safeParse(e).success||e!==j(e))&&F();for(let t=e;;t=A(t)){let e=s(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new g(`unsafe-state`)}function I(e){return(!c.safeParse(e).success||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&F(),e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}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
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0"><dict>
|
|
4
|
+
<key>Label</key><string>${N}</string>
|
|
5
|
+
<key>ProgramArguments</key><array><string>${I(e)}</string><string>--service-run</string><string>manual</string></array>
|
|
6
|
+
<key>RunAtLoad</key><true/>
|
|
7
|
+
<key>KeepAlive</key><true/>
|
|
8
|
+
<key>ThrottleInterval</key><integer>10</integer>
|
|
9
|
+
</dict></plist>
|
|
10
|
+
`)}function R(e,n){return e===null||n===null?e===n:t(e.stat,n.stat)&&e.stat.mode===n.stat.mode&&e.stat.uid===n.stat.uid&&e.stat.size===n.stat.size&&e.stat.mtimeMs===n.stat.mtimeMs&&e.stat.ctimeMs===n.stat.ctimeMs&&e.raw.equals(n.raw)}function z(e,n){let r=j(e,`manual.plist`),i,o=t=>{try{if(P(e),!s(e))return null;h(e,n);let i=s(r);if(!i)return null;let o=a(r,65536,n);return o.equals(L(t))||F(),{stat:i,raw:o}}catch{return F()}},c=e=>{let t=o(e);return i!==void 0&&!R(i,t)&&F(),i=t,t};return{path:r,inspect(e){return c(e)!==null},write(a){let l=L(a),u=c(a);P(e),s(e)||E(e,{recursive:!0,mode:448});let d=h(e,n);_(r,l,()=>{P(e),(!t(d,h(e,n))||!R(u,o(a)))&&F()}),i=o(a),i?.raw.equals(l)||F()},remove(e){let t=c(e);t&&(R(t,o(e))||F(),k(r),i=null)}}}const B=`sh.bilal.shellbell.host.agent`,V=65536;function H(){throw new g(`unsafe-state`)}function U(e){(!c.safeParse(e).success||e!==j(e)||te(e)!==`Shellbell.app`)&&H();let t=j(e,`Contents`,`MacOS`,`Shellbell`);return c.safeParse(t).success||H(),t}async function W(e,t,n,r,i=!1,a=1e4){try{let i=await e(t,n,{input:r,timeoutMs:a,maxOutputBytes:V,captureOutput:!0});if(!Number.isInteger(i.exitCode)||i.exitCode<0||i.exitCode>255||!Buffer.isBuffer(i.stdout)||i.stdout.length>V)throw Error(`invalid command result`);return i}catch{throw new g(i?`delivery-unknown`:`unavailable`)}}function G(e,n){return t(e,n)&&e.mode===n.mode&&e.uid===n.uid&&e.size===n.size&&e.mtimeMs===n.mtimeMs&&e.ctimeMs===n.ctimeMs}async function K(e,t,n=r){let i=U(e),o=j(e,`Contents`,`Info.plist`),c=new Map,l=()=>{P(A(e));for(let n of[e,j(e,`Contents`),j(e,`Contents`,`MacOS`),o,i]){let e=s(n),r=n===o||n===i;(!e||e.isSymbolicLink()||(r?!e.isFile():!e.isDirectory())||e.uid!==t&&e.uid!==0||e.mode&3602||n===i&&!(e.mode&73))&&H();let a=c.get(n);a&&!G(a,e)&&H(),c.set(n,e)}};try{l();let e=await W(n,`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,`-`],a(o,V));e.exitCode!==0&&H();let t=JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(e.stdout));return(t?.CFBundleIdentifier!==`sh.bilal.shellbell.host`||t?.CFBundleExecutable!==`Shellbell`)&&H(),l(),{executable:i,revalidate:l}}catch{return H()}}function q(e,t,n,r){let i;try{i=new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch{return H()}let a=i.trim().split(/\r?\n/).map(e=>e.trim());(a.shift()!==`${t} = {`||a.pop()!==`}`)&&H();let o=1,s,c=null,l=!1,u,d=!1;for(let e of a)if(e){if(e===`}`){o<=1&&H(),d&&o===2&&(d=!1),o--;continue}if(o===1&&e.startsWith(`program = `)){s!==void 0&&H(),s=e.slice(10);continue}if(o===1&&e.startsWith(`pid = `)){(l||!/^pid = [1-9][0-9]*$/.test(e))&&H(),l=!0,c=Number(e.slice(6)),(!Number.isSafeInteger(c)||c>2147483647)&&H();continue}if(o===1&&/^(?:pid|program|arguments)(?:\s|=)/.test(e)&&e!==`arguments = {`&&H(),e.endsWith(`= {`)){o===1&&e===`arguments = {`?(u!==void 0&&H(),u=[],d=!0):d&&H(),o++;continue}d&&o===2?u.push(e):(e.includes(`{`)||e.includes(`}`))&&H()}return(o!==1||s!==n||!u||u.length!==3||u[0]!==(r===`persistent`?`Shellbell`:n)||u[1]!==`--service-run`||u[2]!==r)&&H(),c}function J(e){let{root:t,uid:a,homeDir:l}=e;(!Number.isSafeInteger(a)||a<=0||!c.safeParse(t).success||!c.safeParse(l).success||t!==j(t)||l!==j(l))&&H();let u=j(l,`Library`,`LaunchAgents`);(t===u||t.startsWith(`${u}/`))&&H();let d=e.run??r,f=z(t,a),m=()=>e.legacy??i({run:d,uid:a,homeDir:l}),h=`gui/${a}`,_=e=>`${h}/${e===`manual`?N:B}`,v=e=>{b.safeParse(e).success||H()};async function x(e,t,n,r=`service`){let i=await K(e,a,d);await n?.(),i.revalidate();let o=t!==`status`,s=await W(d,i.executable,[r===`login`?`--login-api`:`--service-api`,t],void 0,o);i.revalidate();let c;try{c=y.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.stdout)))}catch{throw new g(o?`delivery-unknown`:`unavailable`)}if(!c.ok)throw new g(c.error.code===`denied`?`approval-required`:c.error.code===`invalid-bundle`?`unsafe-state`:`operation-failed`);if(s.exitCode!==0)throw new g(o?`delivery-unknown`:`unavailable`);return c.status}async function S(e,t,n=1e4){let r=await W(d,`/bin/launchctl`,[`print`,_(e)],void 0,!1,n);if(r.exitCode===113)return{loaded:!1,pid:null};if(r.exitCode!==0)throw new g(`unavailable`);return{loaded:!0,pid:q(r.stdout,_(e),U(t),e)}}let C={loginStatus:e=>x(e,`status`,void 0,`login`),async setLogin(e,t){let n=await K(e,a,d),r=await W(d,`/usr/bin/codesign`,[`--verify`,`--strict`,e]);if(n.revalidate(),r.exitCode!==0)throw new g(`startup-unavailable`);let i=await x(e,`status`,void 0,`login`);if(i===`not-found`&&!t||i===`unknown`)throw new g(`startup-unavailable`);if(t?i===`enabled`||i===`requires-approval`:i===`not-registered`)return i;try{await x(e,t?`register`:`unregister`,void 0,`login`)}catch(n){if(!(t&&n instanceof g&&n.code===`approval-required`&&await x(e,`status`,void 0,`login`)===`requires-approval`))throw n}let o=await x(e,`status`,void 0,`login`);if(t?o!==`enabled`&&o!==`requires-approval`:o!==`not-registered`)throw new g(`operation-failed`);return o},async preflight(e,t){await o(d,a,l);let n=await K(t,a,d);if(e===`persistent`){let e=await W(d,`/usr/bin/codesign`,[`--verify`,`--strict`,t]);if(n.revalidate(),e.exitCode!==0||await x(t,`status`)===`not-found`)throw new g(`startup-unavailable`)}},async prepareManualRecovery(e){if(await o(d,a,l),v(e),n(e.mode)!==`persistent`&&H(),(await C.inspect(`persistent`,e.bundlePath)).loaded)throw new g(`conflict`);if((await W(d,`/bin/launchctl`,[`disable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);let t=await W(d,`/bin/launchctl`,[`print-disabled`,h]),r=new TextDecoder(`utf-8`,{fatal:!0}).decode(t.stdout).trim().split(/\r?\n/).map(e=>e.trim());if(t.exitCode!==0||r.shift()!==`disabled services = {`||r.pop()!==`}`||r.filter(e=>e.includes(`"${B}"`)).join(`
|
|
11
|
+
`)!==`"${B}" => disabled`)throw new g(`operation-failed`);let i=await C.inspect(`persistent`,e.bundlePath);if(i.loaded)throw new g(`conflict`);i.registration!==`not-registered`&&i.registration!==`not-found`&&await C.stop(e,i)},inspectLegacy:()=>m().inspect(),async inspect(e,t){e!==`manual`&&e!==`persistent`&&H();let n=U(t),r;e===`manual`?r=f.inspect(n)?`enabled`:`not-registered`:(P(A(t)),r=s(t)?await x(t,`status`):`not-found`);let i=await S(e,t);return e===`manual`&&i.loaded&&r!==`enabled`&&H(),{registration:r,...i,bundlePath:t}},async start(e){if(v(e),await C.preflight(n(e.mode),e.bundlePath),(await C.inspect(n(e.mode),e.bundlePath)).loaded)throw new g(`conflict`);if(n(e.mode)===`persistent`){if((await W(d,`/bin/launchctl`,[`enable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);return{registration:await x(e.bundlePath,`register`,async()=>{if((await S(`persistent`,e.bundlePath)).loaded)throw new g(`conflict`)}),...await S(n(e.mode),e.bundlePath),bundlePath:e.bundlePath}}let t=await K(e.bundlePath,a,d);if(f.write(t.executable),(await S(`manual`,e.bundlePath)).loaded)throw new g(`conflict`);if(f.inspect(t.executable),t.revalidate(),(await W(d,`/bin/launchctl`,[`bootstrap`,h,f.path],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);return C.inspect(`manual`,e.bundlePath)},async stop(e,t){v(e),t.bundlePath!==e.bundlePath&&H();let r=await C.inspect(n(e.mode),e.bundlePath);if(r.loaded!==t.loaded||r.pid!==t.pid||r.registration!==t.registration)throw new g(`conflict`);if(n(e.mode)===`persistent`){if(await x(e.bundlePath,`unregister`,async()=>{let t=await S(`persistent`,e.bundlePath);if(t.loaded!==r.loaded||t.pid!==r.pid)throw new g(`conflict`)})!==`not-registered`)throw new g(`operation-failed`)}else if(r.loaded&&(f.inspect(U(e.bundlePath)),(await W(d,`/bin/launchctl`,[`bootout`,_(`manual`)],void 0,!0)).exitCode!==0))throw new g(`operation-failed`);let i=performance.now()+1e4;for(;;){let t=i-performance.now();if(t<=0)throw new g(`operation-failed`);let a=await S(n(e.mode),e.bundlePath,t);if(!a.loaded)break;if(a.pid!==null&&a.pid!==r.pid)throw new g(`conflict`);let o=Math.min(100,i-performance.now());if(o<=0)throw new g(`operation-failed`);await new Promise(e=>setTimeout(e,o))}},async remove(e){v(e);let t=await C.inspect(n(e.mode),e.bundlePath);if(t.loaded||n(e.mode)===`persistent`&&t.registration!==`not-registered`)throw new g(`conflict`);n(e.mode)===`manual`&&f.remove(U(e.bundlePath))},withLegacyGuard(e){return p(m(),!0,e)}};return C}const Y=()=>{throw new g(`unsafe-state`)};async function X(e,t={}){try{(O(e)!==e||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&Y();let n=t.run??r,i=await K(e,process.getuid(),n),o=j(e,`Contents`),c=j(o,`Resources`),l=j(o,`Helpers/node`),u=j(c,`agent/dist/native-controller.js`),d=j(c,`agent/dist/native-service.js`),f=[l,u,d,j(c,`runtime/LICENSE`),j(c,`agent/package.json`),j(c,`agent/dist/cli.js`)],p=()=>{for(let t of f){for(let n=A(t);n!==e;n=A(n)){let e=s(n);(!e?.isDirectory()||e.isSymbolicLink()||e.mode&3602||e.uid!==0&&e.uid!==process.getuid())&&Y()}let n=s(t);(!n?.isFile()||n.isSymbolicLink()||n.mode&3602||n.uid!==0&&n.uid!==process.getuid()||t===l&&!(n.mode&73))&&Y()}let t=0,n=new Set,r=e=>{++t>1e5&&Y();let i=s(e);if(!i)throw new g(`unsafe-state`);let a=O(e);if(a.startsWith(`${c}/`)||Y(),i.isSymbolicLink()){r(a);return}if(!n.has(a)){if(n.add(a),(i.uid!==0&&i.uid!==process.getuid()||i.mode&3602)&&Y(),i.isDirectory())for(let t of D(e))r(j(e,t));else i.isFile()||Y()}};for(let e of[`agent`,`runtime`])r(j(c,e))};p();let m=JSON.parse(a(j(c,`agent/package.json`),65536).toString(`utf8`));(m.name!==`shellbell`||typeof m.version!=`string`||!m.version||m.type!==`module`)&&Y();let h=S(j(c,`agent/package.json`));for(let e of Object.keys(m.dependencies??{}))O(h.resolve(e)).startsWith(`${c}/agent/`)||Y();let _=await n(`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,j(o,`Info.plist`)],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(_.exitCode!==0||JSON.parse(_.stdout.toString(`utf8`)).CFBundleShortVersionString!==m.version)&&Y();let v=await n(l,[`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(v.exitCode!==0||v.stdout.toString(`utf8`).trim()!==`v22.23.1`)&&Y();let y=await n(l,[`-p`,`process.platform + ':' + process.arch`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(y.exitCode!==0||y.stdout.toString(`utf8`).trim()!==`${process.platform}:${process.arch}`)&&Y();for(let e of[j(c,`agent/dist/cli.js`),u,d]){let t=await n(l,[e,`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(t.exitCode!==0||t.stdout.toString(`utf8`).trim()!==m.version)&&Y()}return i.revalidate(),p(),{executable:i.executable,nodePath:l,controllerPath:u,servicePath:d,agentVersion:m.version}}catch(e){if(e instanceof g)throw e;return Y()}}const Z=M.strictObject({v:M.literal(1),instance:M.uuid()});function ne(e,t){let n,r,i=new Promise((e,t)=>{n=e,r=t}),a=!1,o=!1,s=Buffer.alloc(0),c=setTimeout(()=>u(),t.timeoutMs??5e3),l=()=>{clearTimeout(c),e.off(`data`,d),e.off(`end`,u),e.off(`close`,u),e.off(`error`,u)},u=()=>{o||(o=!0,l(),r(new g(`unavailable`)),Promise.resolve().then(()=>t.onLost()).catch(()=>{}))},d=e=>{if(o)return;let r=Buffer.isBuffer(e)?e:Buffer.from(e);if(a||s.length+r.length>1024){u();return}s=Buffer.concat([s,r]);let i=s.indexOf(10);if(!(i<0))try{let e=Z.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.subarray(0,i))));if(i!==s.length-1||e.instance!==t.instance)throw Error();a=!0,s=Buffer.alloc(0),clearTimeout(c),n()}catch{u()}};return e.on(`data`,d),e.once(`end`,u),e.once(`close`,u),e.once(`error`,u),(e.destroyed||e.readableEnded)&&u(),{ready:i,close:u}}var Q=class extends d{constructor(e){super({...e,filename:`controller.json`,maxBytes:v,schema:x})}};function re(e,t,n){if(n.NODE_OPTIONS||n.NODE_PATH||!b.safeParse(e).success||!c.safeParse(t).success)throw new g(`unsafe-state`);return{...e.environment,HOME:t}}function $(t,n,r=!1){try{if(n<=0||!c.safeParse(t).success||[...t].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))throw Error();for(let e=t;;e=A(e)){let t=s(e);if(t&&(!t.isDirectory()||t.isSymbolicLink()))throw Error();if(A(e)===e)break}if(!s(t)){if(!r)return null;E(t,{recursive:!0,mode:448})}if(h(t,n),O(t)!==t)throw Error();let i=u(t);for(let e of[i.identity,i.pairings,i.config,i.pid])s(e)&&a(e,65536,n);ie(i.log,n);let o=s(i.sock);if(o&&(!o.isSocket()||o.uid!==n||(o.mode&4095)!=384))throw Error();return f(i),r?m(i):e(i)}catch{throw new g(`unsafe-state`)}}function ie(e,n){let r=s(e);if(!r)return;let i=e=>{if(!e.isFile()||e.isSymbolicLink()||e.uid!==n||(e.mode&4095)!=384)throw Error()};i(r);let a=ee(e,w.O_RDONLY|w.O_NOFOLLOW|w.O_NONBLOCK);try{let n=T(a);i(n);let o=s(e);if(!o||(i(o),!t(r,n)||!t(n,o)))throw Error()}finally{C(a)}}async function ae(e,t){let n=new Q(t).inspect()?.selection;if(!n||n.mode!==e||n.bundlePath!==t.bundlePath)throw new g(`conflict`);let r=$(n.stateDir,t.uid);if(!r||r.fp!==n.computerFp)throw new g(`unsafe-state`);if(e!==`desktop`)return t.start(n);let i=new l({stateDir:n.stateDir,uid:t.uid}).inspect();if(!t.ownerInput||i?.mode!==`desktop`||!i.consented||i.transition&&(i.transition.target!==`desktop`||![`source-stopped`,`destination-started`].includes(i.transition.phase)))throw new g(`conflict`);let a=!1,o,s,c=()=>s??=(async()=>{o&&await(await o).stop()})(),u=ne(t.ownerInput,{instance:n.serviceInstance,onLost:async()=>{a=!0;try{await c(),t.onOwnerLost?.(null)}catch(e){t.onOwnerLost?.(e)}}});try{if(await u.ready,a)throw new g(`unavailable`);if(o=t.start(n),await o,a)throw await c(),new g(`unavailable`);return{stop:async()=>{await c(),u.close()}}}catch(e){throw u.close(),e}}export{X as a,Q as i,ae as n,J as o,re as r,$ as t};
|