shellbell 0.14.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +30 -30
- package/dist/doctor-CTHrssge.js +86 -0
- package/dist/native-controller.js +2 -2
- package/dist/native-service.js +2 -2
- package/dist/{service-entry-BY8SEvyp.js → service-entry-uoRwcU1h.js} +3 -3
- package/dist/service-lifecycle-CSQmtvfk.js +29 -0
- package/package.json +2 -2
- package/dist/doctor-DBq3DNjT.js +0 -86
- package/dist/service-lifecycle-GJqJjIQF.js +0 -29
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{At as e,C as t,F as n,H as r,I as i,It as a,L as o,R as s,S as c,U as l,W as u,_ as d,at as f,c as p,ft as m,g as h,h as g,o as _,pt as v,st as y,v as b,w as x,x as S}from"./service-lifecycle-GJqJjIQF.js";import{B as C,H as w,R as T,U as E,W as D,t as O}from"./doctor-DBq3DNjT.js";import{a as k,i as A,o as j,r as M,t as N}from"./service-entry-BY8SEvyp.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,r){let i=!1,a=!1,c=0,l=!1,u=!1,f=!1,p,m,_,v,y=()=>v||(i=!0,clearTimeout(_),w(),e.off(`data`,E),e.off(`end`,D),e.destroy(),v=Promise.resolve(n.close()).finally(()=>{t.end()}),v.catch(()=>{}),v),x=e=>{if(i)return!1;let n=s(e),r=t.writableLength;if(!n||t.destroyed||!Number.isFinite(r)||r<0||r+n.byteLength>262144)return y(),!1;try{t.write(n)}catch{return y(),!1}return!0},C=(e,t)=>x({v:1,id:e,ok:!1,error:{code:t}}),w=n.onEvent(e=>{let t=b.safeParse(e);if(!t.success){y();return}if(f){p?y():p=t.data;return}if(t.data.flowId!==m){y();return}x(t.data),t.data.event===`pairing.closed`&&(m=void 0)}),T=new o({onError:y,onLine(e){if(i)return;let t;try{t=JSON.parse(e)}catch{y();return}let o=S.safeParse(t);if(!o.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`),y();return}let v=o.data;if(v.id<=c){y();return}if(c=v.id,!a){if(v.cmd!==`hello`){C(v.id,`handshake-required`),y();return}a=!0,clearTimeout(_),x({v:1,id:v.id,ok:!0,data:h.hello.parse({version:1,agentVersion:r.agentVersion,capabilities:[`status`,`settings`,`lifecycle`,`pairing`,`devices`,`diagnostics`]})});return}if(v.cmd===`hello`){y();return}if(l){C(v.id,`busy`),u||y();return}l=!0,u=!1,f=v.cmd===`pairing.open`;let b=`args`in v;_=setTimeout(()=>{if(b){C(v.id,`delivery-unknown`),y();return}u=!0,C(v.id,`timeout`)},b?6e4:5e3),n.execute(v).then(e=>{if(i||u)return;let t=h[v.cmd].safeParse(e);if(!t.success){if(!b){C(v.id,`operation-failed`);return}C(v.id,`delivery-unknown`),y();return}if(v.cmd===`pairing.open`&&(m=t.data.flowId),!s({v:1,id:v.id,ok:!0,data:t.data})){C(v.id,`response-too-large`),y();return}if(x({v:1,id:v.id,ok:!0,data:t.data}),f=!1,p){if(p.flowId!==m){y();return}x(p),p.event===`pairing.closed`&&(m=void 0),p=void 0}},e=>{if(u)return;let t=e instanceof g&&d.safeParse(e.code).success?e.code:`operation-failed`;C(v.id,t),f=!1,p=void 0}).finally(()=>{clearTimeout(_),l=!1,u=!1})}}),E=e=>T.push(e),D=()=>{T.finish(),y()};return e.on(`data`,E),e.once(`end`,D),e.once(`error`,y),t.once(`error`,y),_=setTimeout(y,5e3),{close:y}}var J=class{options;owned;starting;closed=!1;readiness;clock;constructor(e){this.options=e,this.readiness=e.readiness??new _,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 g(`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 g(`busy`)):!c.safeParse(e).success||e.mode!==`desktop`?Promise.reject(new g(`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 g(`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 g(`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 g(`conflict`);await this.clock.sleep(Math.min(25,Math.max(0,t-this.clock.now())))}throw new g(`unavailable`)}catch(e){throw await this.stopOwned(r),e}}async stop(e){let t=this.owned;if(!t){if(e.runtime)throw new g(`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 g(`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 g(`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 g(`unavailable`);if((await this.readiness.observe(m(e.selection.stateDir).sock)).kind!==`absent`)throw new g(`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 _,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(e,n){let r=e?.selection??null,i=r?.bundlePath??e?.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`)]),c=this.recordedStateDirectory(e,n.definition?.stateDir),l=c??this.options.defaultStateDir,u=N(l,this.options.uid),d=r?.mode===`desktop`?await this.desktop.inspect(r):{registration:`not-registered`,loaded:!1,pid:null,bundlePath:null},f=r?r.mode===`desktop`?d:x(r.mode)===`manual`?a:o:null,h=u?{stateDir:l,computerFp:u.fp,serviceInstance:r?.serviceInstance??n.definition?.serviceInstance??null,...f?.pid?{pid:f.pid}:{}}:void 0,g=await this.readiness.observe(m(l).sock,h);if(g.kind===`verified`&&(!u||r&&(!f?.loaded||!f.pid||u.fp!==r.computerFp))&&(g.kind=`foreign`),r){let e=r.mode===`desktop`?await this.desktop.inspect(r):await this.options.platform.inspect(x(r.mode),i);JSON.stringify(e)!==JSON.stringify(f)&&(g.kind=`unverified`,g.local=null)}let _=new p({stateDir:l,uid:this.options.uid}).inspect(),v=t.parse({desktopLogin:s,desktop:d,ownership:{revision:_?.revision??null,mode:_?.mode??(r||e?.transition?`legacy-native`:n.installed||n.loaded?`headless`:null),consented:_?.consented??!1,startupEnabled:_?.startupEnabled??null,transition:_?.transition??null},revision:e?.revision??null,selection:r,transition:e?.transition?{id:e.transition.id,action:e.transition.action,phase:e.transition.phase}:null,recoveryAvailable:!!e?.recovery,manualRecoveryAvailable:(e?.transition?.destination?.mode===`persistent`&&r?.serviceInstance===e.transition.destination.serviceInstance&&[`start`,`restart`].includes(e.transition.action)&&!e.transition.restoreLegacy||this.isManualRecovery(e)&&r?.serviceInstance===e?.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 c&&this.observedStateDirs.set(v,c),v}error(e){return e instanceof g?e:e instanceof f?new g(e.code===`busy`?`busy`:e.code===`invalid`?`invalid-config`:`unsafe-state`):e instanceof n?e.code===`server-error`?new g(e.serverCode===`runtime-mismatch`||e.serverCode===`configuration-mismatch`?`conflict`:e.serverCode===`pairing-busy`?`busy`:`operation-failed`):new g(e.code===`protocol-error`||e.code===`closed`?`unavailable`:e.code):new g(`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 g(`conflict`)}async control(e){let t=e.local.status?.process;if(e.local.kind!==`verified`||!t)throw new g(`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??i)(m(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 g(`unavailable`);if(!this.exact(e.runtime,t))throw e.close(),new g(`conflict`);this.client=e}return this.client}async settings(e){let t=this.statusStateDirectory(e),n=v(m(t)),i=r(n),a=null;if(e.local.kind===`verified`)try{a=await(await this.control(e)).configurationRevision()}catch{}return{saved:n,savedRevision:i,appliedRevision:a,applied:e.local.kind===`absent`?`not-running`:a===null?`unknown`:a===i?`matches`:`restart-required`}}async execute(e){try{if(this.closed)throw new g(`unavailable`);let t=S.safeParse(e);if(!t.success||t.data.cmd===`hello`)throw new g(`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(n.cmd===`agents.setup`||n.cmd===`agents.skip`||n.cmd===`agents.remove`){let e=T(this.statusStateDirectory(await this.status()),this.options.homeDir);i={agents:n.cmd===`agents.setup`?E(e,n.args.kinds):n.cmd===`agents.skip`?D(e,n.args.kinds):w(e,n.args.kind)}}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 g(`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 g(`conflict`);let i=m(t),a=y(i,e=>{if(r(e)!==n.args.configRevision)throw new g(`conflict`);let t=e;for(let r of n.args.changes){if(l(e,r.key)===r.value)continue;let n=u(t,r.key,r.value,!1);if(`error`in n)throw new g(`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(r(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 g(`bad-request`)}).catch(e=>{throw this.error(e)})));else{let e=await this.status();if(n.cmd===`status`)i=e;else if(n.cmd===`agents`)i={agents:C(T(this.statusStateDirectory(e),this.options.homeDir))};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=h[n.cmd].safeParse(i);if(!a.success)throw new g(`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&&(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 g(`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 g(`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 g(`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 g(`conflict`);if(t.current.transition||n.current?.transition)throw new g(`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 g(`conflict`);if(o.local.kind===`absent`&&!o.desktop?.loaded)return o;if(o.local.kind!==`verified`)throw new g(`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 g(`conflict`)}else if(e.cmd===`desktop.start`){if(t.current?.transition||n.current?.transition)throw new g(`recovery-required`);if(t.current?.mode!==`desktop`||!t.current.consented||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded)throw new g(`conflict`);if(o.local.kind===`verified`&&o.selection?.mode===`desktop`&&o.desktop?.loaded)return o;if(o.local.kind!==`absent`)throw new g(`conflict`)}else if(e.cmd===`ownership.recover`){if(!t.current?.transition||t.current.transition.id!==e.args.intentId)throw new g(`conflict`)}else if(t.current?.transition)throw new g(`recovery-required`);let s=e.cmd===`ownership.recover`,l=s?t.current.transition.target:e.cmd===`ownership.convert`?e.args.target:`desktop`;if(l===`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 g(`conflict`);let u=N(r,this.options.uid,e.cmd===`desktop.setup`);if(!u)throw new g(`unsafe-state`);let d=s&&n.current?.transition?.id===t.current?.transition?.id?n.current.transition:null,f=s&&!n.current?.transition&&n.current?.selection?.mode===`desktop`?n.current.selection:null,p=f?null:d?d.source:n.current?.selection??null,h=s?t.current.transition:{id:this.newId(),source:o.ownership?.mode??null,target:l,sourceManager:p?p.mode===`desktop`?`desktop-child`:p.mode===`manual`?`native-manual`:`native-persistent`:a.installed||a.loaded?`launchd`:null,sourceInstance:p?.serviceInstance??a.definition?.serviceInstance??null,stateDir:r,computerFp:u.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(h.stateDir!==r||h.computerFp!==u.fp||h.targetBundlePath!==this.options.bundlePath||h.targetVersion!==this.options.agentVersion)throw new g(`conflict`);let _=this.newId(),v=p?.environment??a.definition?.environment,y=f??d?.destination??{mode:`desktop`,stateDir:r,computerFp:u.fp,serviceInstance:_,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:v?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,...v?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:v.HERDR_SOCKET_PATH}:{},...v?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:v.XDG_CONFIG_HOME}:{},SHELLBELL_DIR:r,SHELLBELL_SERVICE_INSTANCE:_}};if(y.mode!==`desktop`||y.computerFp!==u.fp||y.stateDir!==r||y.bundlePath!==h.targetBundlePath||y.agentVersion!==h.targetVersion)throw new g(`conflict`);let b=async()=>{let e=await this.observe(n.current,await i.inspect());return e.selection?.serviceInstance===y.serviceInstance&&e.local.kind===`verified`&&!!e.desktop?.loaded&&!e.manual.loaded&&!e.persistent.loaded&&!e.legacy.installed&&!e.legacy.loaded};return await Y(t,h,{preflight:async()=>{if(!c.safeParse(y).success)throw new g(`unsafe-state`);await this.admitBundle(y.bundlePath)},stopSource:async()=>{if(h.source===`headless`&&t.current?.startupEnabled&&await this.options.platform.setLogin(this.options.bundlePath,!0),!d){let e=n.current?.recovery??null;if(a.installed){if(!a.raw||!a.definition||e&&s)throw new g(`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:u.fp}}this.publish(n,{recovery:e,transition:{id:h.id,action:`start`,phase:`prepared`,source:p,destination:y,recoveryId:e?.id??null}})}if(await b())return;if(p){if(p.stateDir!==r||p.computerFp!==u.fp)throw new g(`conflict`);if(p.mode===`desktop`){let e=await this.observe(n.current,await i.inspect());if(e.desktop?.loaded){if(e.local.kind!==`verified`)throw new g(`conflict`);await this.desktop.stop({revision:e.revision,runtime:e.local.status.process})}}else{let e=await this.options.platform.inspect(p.mode,p.bundlePath),t=p.mode===`persistent`&&!e.loaded;t?await this.options.platform.prepareManualRecovery(p):(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(p,e),await this.readiness.waitStopped(m(r).sock),t||await this.options.platform.remove(p)}}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 g(`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 g(`conflict`);await i.restore(null)}},verifyAbsent:async()=>{if(await b())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 g(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{await b()||(this.phase(n,`destination-start-requested`,{selection:y}),await this.desktop.start(y),await this.certify(y),this.phase(n,`destination-ready`))},complete:async()=>{this.publish(n,{selection:y,transition:null})}}),this.observe(n.current,await i.inspect())})))}async convertToHeadless(t,n,r,i,a,o,s){if(!s&&t.current?.mode===`headless`&&!n.current?.selection&&!n.current?.transition)return a;if([`foreign`,`unverified`].includes(a.local.kind))throw new g(`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 g(`unsafe-state`);let u=s&&n.current?.transition?.id===t.current?.transition?.id?n.current.transition:null,d=u?u.source:n.current?.selection??null,f=s?t.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 g(`conflict`);let p=d?.environment??(s&&i.definition?.serviceInstance===f.id?i.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}:{}}},_=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())},v={stateDir:o,computerFp:l.fp,serviceInstance:f.id},y=async()=>{let e=await r.inspect();if(!_(e)||!e.loaded||(await this.readiness.observe(m(o).sock,v)).kind!==`verified`)return!1;let t=await r.inspect();return _(t)&&t.loaded};return await Y(t,f,{preflight:async()=>{if((i.installed||i.loaded)&&(!s||!_(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 g(`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 g(`unavailable`);if((e===`enabled`||e===`requires-approval`)&&await this.options.platform.setLogin(this.options.bundlePath,!1),!await y()){if(d?.mode===`desktop`){let e=await this.desktop.inspect(d);if(e.loaded){let t=await this.readiness.observe(m(o).sock,{stateDir:o,computerFp:l.fp,serviceInstance:d.serviceInstance,...e.pid?{pid:e.pid}:{}});if(t.kind!==`verified`)throw new g(`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(m(o).sock),t||await this.options.platform.remove(d)}}},verifyAbsent:async()=>{if(await y())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&&!_(t)||e.local.kind!==`absent`)throw new g(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{if(await y())return;if(await this.admitBundle(this.options.bundlePath),N(o,this.options.uid)?.fp!==l.fp)throw new g(`unsafe-state`);e(h.logPath)||F(L(h.logPath,I.O_WRONLY|I.O_CREAT|I.O_EXCL|I.O_NOFOLLOW,384)),this.phase(n,`destination-start-requested`,{selection:null});let i=await r.inspect();if(!_(i)){if(i.installed||i.loaded)throw new g(`conflict`);await r.write(h)}await r.setStartupEnabled(t.current.startupEnabled);let a=await r.load();if(await this.readiness.waitReady(m(o).sock,{...v,pid:a}),!await y())throw new g(`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`},O(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 g(`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 g(`upgrade-required`);return n}async lifecycle(e,t,n,r,i){if(e.cmd===`service.recover`)return this.recover(e,t,n,r,i);if(t.current?.transition)throw new g(`recovery-required`);let a=t.current?.selection??null;if(i.manual.loaded&&a?.mode!==`manual`||i.persistent.loaded&&a?.mode!==`persistent`||a&&r.loaded||e.cmd!==`service.start`&&!a||e.cmd===`service.start`&&a&&x(a.mode)===e.args.mode&&a.bundlePath===this.options.bundlePath&&i[x(a.mode)].loaded||r.installed&&(e.cmd!==`service.start`||!e.args.migrateLegacy))throw new g(`conflict`);let o=null;if(e.cmd===`service.start`||e.cmd===`service.restart`){await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(e.cmd===`service.start`?e.args.mode:x(a.mode),this.options.bundlePath);let t=a?.stateDir??r.definition?.stateDir??(e.cmd===`service.start`?e.args.stateDir:void 0)??this.options.defaultStateDir;if(e.cmd===`service.start`&&e.args.stateDir&&e.args.stateDir!==t)throw new g(`conflict`);!a&&!r.installed&&(N(t,this.options.uid),await this.requireAbsentDestination(t));let n=N(t,this.options.uid,!0),i=this.newId();o={mode:e.cmd===`service.start`?e.args.mode:a.mode,stateDir:t,computerFp:n.fp,serviceInstance:i,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:t,SHELLBELL_SERVICE_INSTANCE:i}}}let s=t.current?.recovery??null;if(r.installed){if(!r.raw||!r.definition||s)throw new g(`recovery-required`);let e=N(r.definition.stateDir,this.options.uid);if(!e)throw new g(`unsafe-state`);s={id:this.newId(),definitionPath:n.definitionPath,rawBase64:r.raw.toString(`base64`),sha256:W(`sha256`).update(r.raw).digest(`hex`),wasLoaded:r.loaded,stateDir:r.definition.stateDir,computerFp:e.fp}}this.publish(t,{recovery:s,transition:{id:this.newId(),action:e.cmd.slice(8),phase:`prepared`,source:a,destination:o,recoveryId:s?.id??null}});try{return await this.advance(t,n,r,i)}catch(e){throw this.phase(t,`recovery-required`),e}}async stopSource(e,t,n,r){let i=e.current.transition,a=i.source;if(this.phase(e,`source-stop-requested`),a){try{await this.admitBundle(a.bundlePath,a.agentVersion)}catch{throw new g(`recovery-required`)}let e=r[x(a.mode)];(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(a,e),await this.readiness.waitStopped(m(a.stateDir).sock);let t=await this.options.platform.inspect(x(a.mode),a.bundlePath);if(t.loaded||x(a.mode)===`persistent`&&t.registration!==`not-registered`)throw new g(`operation-failed`)}else if(n.installed){n.loaded&&await t.unload(),await this.readiness.waitStopped(m(n.definition.stateDir).sock);let e=await t.inspect();if(e.loaded||!e.raw?.equals(n.raw))throw new g(`conflict`)}else if(r.local.kind!==`absent`)throw new g(`conflict`);if(this.phase(e,`source-stopped`,{selection:i.action===`stop`?a:null}),a&&i.destination&&(x(a.mode)!==x(i.destination.mode)||a.bundlePath!==i.destination.bundlePath)&&await this.options.platform.remove(a),n.installed){await t.restore(null);let e=await t.inspect();if(e.installed||e.loaded)throw new g(`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 g(`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 g(`conflict`)}async certify(e){let t=e.mode===`desktop`?await this.desktop.inspect(e):await this.options.platform.inspect(x(e.mode),e.bundlePath);if(!t.loaded||!t.pid)throw new g(`operation-failed`);let n=await this.readiness.waitReady(m(e.stateDir).sock,{computerFp:e.computerFp,stateDir:e.stateDir,serviceInstance:e.serviceInstance,pid:t.pid}),r=e.mode===`desktop`?await this.desktop.inspect(e):await this.options.platform.inspect(x(e.mode),e.bundlePath);if(JSON.stringify(t)!==JSON.stringify(r)||n.process.agentVersion!==e.agentVersion)throw new g(`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(e,t,n,r,i){let a=t.current;if(!a||i.manual.loaded&&i.persistent.loaded||a.selection&&r.loaded||a.selection&&i[x(a.selection.mode)===`manual`?`persistent`:`manual`].loaded)throw new g(`conflict`);if(e.args.action===`discard-backup`){if(a.transition||!a.recovery||r.installed&&r.raw?.toString(`base64`)!==a.recovery.rawBase64)throw new g(`conflict`);return this.publish(t,{recovery:null}),this.observe(t.current,r)}let o=a.recovery,s=o?Buffer.from(o.rawBase64,`base64`):null;if(o&&(!s||W(`sha256`).update(s).digest(`hex`)!==o.sha256)||o&&(o.definitionPath!==n.definitionPath||N(o.stateDir,this.options.uid)?.fp!==o.computerFp))throw new g(`unsafe-state`);if(o&&r.installed&&!r.raw?.equals(s))throw new g(`conflict`);let c=this.isManualRecovery(a);if(e.args.action===`use-manual`||e.args.action===`continue`&&c){let e=c?a.transition?.source:a.transition?.destination;if(e?.mode!==`persistent`||a.transition?.restoreLegacy||!c&&![`start`,`restart`].includes(a.transition.action)||a.selection?.serviceInstance!==e.serviceInstance||i.manual.loaded||i.persistent.loaded||i.local.kind!==`absent`||r.installed||r.loaded)throw new g(`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 g(`unsafe-state`);let o=this.newId(),s=c?a.transition.destination:{...e,mode:`manual`,bundlePath:this.options.bundlePath,agentVersion:this.options.agentVersion,serviceInstance:o,environment:{...e.environment,SHELLBELL_SERVICE_INSTANCE:o}};c||this.publish(t,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:e,destination:s,recoveryId:a.recovery?.id??null}});try{await this.options.platform.prepareManualRecovery(e),await this.requireAbsentDestination(e.stateDir);let r=await this.observe(t.current,await n.inspect());if(r.manual.loaded||r.persistent.loaded||r.legacy.installed||r.legacy.loaded||r.local.kind!==`absent`)throw new g(`conflict`);return this.publish(t,{selection:null,transition:{id:this.newId(),action:`start`,phase:`source-stopped`,source:null,destination:s,recoveryId:a.recovery?.id??null}}),await this.startDestination(t,s),this.publish(t,{transition:null}),this.observe(t.current,await n.inspect())}catch(e){throw this.phase(t,`recovery-required`),e}}if(e.args.action===`continue`&&a.transition?.action===`recover`&&!a.transition.restoreLegacy)throw new g(`recovery-required`);try{if(e.args.action===`restore-legacy`||a.transition?.restoreLegacy){if(!o||!s)throw new g(`conflict`);if(e.args.action===`restore-legacy`){if(r.loaded)throw new g(`conflict`);this.publish(t,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:a.selection,destination:null,recoveryId:o.id,restoreLegacy:{restartPrevious:e.args.restartPrevious}}})}return await this.restoreLegacy(t,n,r,i,s)}let c=a.transition;if(!c)throw new g(`conflict`);let l=c.destination;if(l&&a.selection?.serviceInstance===l.serviceInstance){let e=i[x(l.mode)];if(r.loaded||i[x(l.mode)===`manual`?`persistent`:`manual`].loaded)throw new g(`conflict`);if(e.registration===`requires-approval`)return this.phase(t,`awaiting-approval`),this.observe(t.current,r);if(e.loaded)await this.certify(l),this.phase(t,`destination-ready`);else{if(i.local.kind!==`absent`)throw new g(`conflict`);await this.startDestination(t,l)}return t.current.transition?.phase!==`awaiting-approval`&&this.publish(t,{transition:null}),this.observe(t.current,await n.inspect())}return await this.advance(t,n,r,i)}catch(e){throw t.current?.transition&&this.phase(t,`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 g(`conflict`);let o=await t.inspect();if(!o.loaded||!o.raw?.equals(i))throw new g(`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 g(`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 g(`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 g(`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`?`${a}\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!==
|
|
2
|
+
import{C as e,F as t,G as n,I as r,K as i,L as a,Nt as o,R as s,S as c,_ as l,c as u,ct as d,g as f,gt as p,h as m,ht as h,o as g,q as _,ut as v,v as y,w as b,x,zt as S}from"./service-lifecycle-CSQmtvfk.js";import{B as C,H as w,R as T,U as E,W as D,t as O}from"./doctor-CTHrssge.js";import{a as k,i as A,o as j,r as M,t as N}from"./service-entry-uoRwcU1h.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,r){let i=!1,o=!1,c=0,u=!1,d=!1,p=!1,h,g,_,v,b=()=>v||(i=!0,clearTimeout(_),w(),e.off(`data`,E),e.off(`end`,D),e.destroy(),v=Promise.resolve(n.close()).finally(()=>{t.end()}),v.catch(()=>{}),v),S=e=>{if(i)return!1;let n=s(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},C=(e,t)=>S({v:1,id:e,ok:!1,error:{code:t}}),w=n.onEvent(e=>{let t=y.safeParse(e);if(!t.success){b();return}if(p){h?b():h=t.data;return}if(t.data.flowId!==g){b();return}S(t.data),t.data.event===`pairing.closed`&&(g=void 0)}),T=new a({onError:b,onLine(e){if(i)return;let t;try{t=JSON.parse(e)}catch{b();return}let a=x.safeParse(t);if(!a.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`),b();return}let v=a.data;if(v.id<=c){b();return}if(c=v.id,!o){if(v.cmd!==`hello`){C(v.id,`handshake-required`),b();return}o=!0,clearTimeout(_),S({v:1,id:v.id,ok:!0,data:f.hello.parse({version:1,agentVersion:r.agentVersion,capabilities:[`status`,`settings`,`lifecycle`,`pairing`,`devices`,`diagnostics`]})});return}if(v.cmd===`hello`){b();return}if(u){C(v.id,`busy`),d||b();return}u=!0,d=!1,p=v.cmd===`pairing.open`;let y=`args`in v;_=setTimeout(()=>{if(y){C(v.id,`delivery-unknown`),b();return}d=!0,C(v.id,`timeout`)},y?6e4:5e3),n.execute(v).then(e=>{if(i||d)return;let t=f[v.cmd].safeParse(e);if(!t.success){if(!y){C(v.id,`operation-failed`);return}C(v.id,`delivery-unknown`),b();return}if(v.cmd===`pairing.open`&&(g=t.data.flowId),!s({v:1,id:v.id,ok:!0,data:t.data})){C(v.id,`response-too-large`),b();return}if(S({v:1,id:v.id,ok:!0,data:t.data}),p=!1,h){if(h.flowId!==g){b();return}S(h),h.event===`pairing.closed`&&(g=void 0),h=void 0}},e=>{if(d)return;let t=e instanceof m&&l.safeParse(e.code).success?e.code:`operation-failed`;C(v.id,t),p=!1,h=void 0}).finally(()=>{clearTimeout(_),u=!1,d=!1})}}),E=e=>T.push(e),D=()=>{T.finish(),b()};return e.on(`data`,E),e.once(`end`,D),e.once(`error`,b),t.once(`error`,b),_=setTimeout(b,5e3),{close:b}}var J=class{options;owned;starting;closed=!1;readiness;clock;constructor(e){this.options=e,this.readiness=e.readiness??new g,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 m(`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 m(`busy`)):!c.safeParse(e).success||e.mode!==`desktop`?Promise.reject(new m(`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(h(e.stateDir).sock)).kind!==`absent`||this.closed)throw new m(`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 m(`unavailable`);let i=await this.readiness.observe(h(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 m(`conflict`);await this.clock.sleep(Math.min(25,Math.max(0,t-this.clock.now())))}throw new m(`unavailable`)}catch(e){throw await this.stopOwned(r),e}}async stop(e){let t=this.owned;if(!t){if(e.runtime)throw new m(`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 m(`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(h(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 m(`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 m(`unavailable`);if((await this.readiness.observe(h(e.selection.stateDir).sock)).kind!==`absent`)throw new m(`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 g,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`)]),c=this.recordedStateDirectory(t,n.definition?.stateDir),l=c??this.options.defaultStateDir,d=N(l,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:b(r.mode)===`manual`?a:o:null,m=d?{stateDir:l,computerFp:d.fp,serviceInstance:r?.serviceInstance??n.definition?.serviceInstance??null,...p?.pid?{pid:p.pid}:{}}:void 0,g=await this.readiness.observe(h(l).sock,m);if(g.kind===`verified`&&(!d||r&&(!p?.loaded||!p.pid||d.fp!==r.computerFp))&&(g.kind=`foreign`),r){let e=r.mode===`desktop`?await this.desktop.inspect(r):await this.options.platform.inspect(b(r.mode),i);JSON.stringify(e)!==JSON.stringify(p)&&(g.kind=`unverified`,g.local=null)}let _=new u({stateDir:l,uid:this.options.uid}).inspect(),v=e.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 c&&this.observedStateDirs.set(v,c),v}error(e){return e instanceof m?e:e instanceof d?new m(e.code===`busy`?`busy`:e.code===`invalid`?`invalid-config`:`unsafe-state`):e instanceof t?e.code===`server-error`?new m(e.serverCode===`runtime-mismatch`||e.serverCode===`configuration-mismatch`?`conflict`:e.serverCode===`pairing-busy`?`busy`:`operation-failed`):new m(e.code===`protocol-error`||e.code===`closed`?`unavailable`:e.code):new m(`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 m(`conflict`)}async control(e){let t=e.local.status?.process;if(e.local.kind!==`verified`||!t)throw new m(`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??r)(h(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 m(`unavailable`);if(!this.exact(e.runtime,t))throw e.close(),new m(`conflict`);this.client=e}return this.client}async settings(e){let t=this.statusStateDirectory(e),r=p(h(t)),i=n(r),a=null;if(e.local.kind===`verified`)try{a=await(await this.control(e)).configurationRevision()}catch{}return{saved:r,savedRevision:i,appliedRevision:a,applied:e.local.kind===`absent`?`not-running`:a===null?`unknown`:a===i?`matches`:`restart-required`}}async execute(e){try{if(this.closed)throw new m(`unavailable`);let t=x.safeParse(e);if(!t.success||t.data.cmd===`hello`)throw new m(`bad-request`);let r=t.data,a;if(r.cmd===`terminals.connect`){let e=await(await this.control(await this.status())).connectTerminal(r.args.name);a=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=T(this.statusStateDirectory(await this.status()),this.options.homeDir);a={agents:r.cmd===`agents.setup`?E(e,r.args.kinds):r.cmd===`agents.skip`?D(e,r.args.kinds):w(e,r.args.kind)}}else if(`args`in r)a=`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 a=>{let o=await a.inspect(),s=await this.observe(t.current,o);if(r.cmd.startsWith(`service.`)&&(s.ownership?.mode===`desktop`||s.ownership?.transition))throw new m(`conflict`);let c=(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)&&o.loaded&&o.definition?.serviceInstance===null&&s.local.kind===`unverified`;if(this.expect(s,r.args.expect,c),r.cmd.startsWith(`service.`))return this.lifecycle(r,t,a,o,s);if(r.cmd===`settings.set`){let t=this.statusStateDirectory(s);if(t!==e)throw new m(`conflict`);let a=h(t),o=v(a,e=>{if(n(e)!==r.args.configRevision)throw new m(`conflict`);let t=e;for(let n of r.args.changes){if(i(e,n.key)===n.value)continue;let r=_(t,n.key,n.value,!1);if(`error`in r)throw new m(`invalid-config`);t=r.next}return t});if(s.local.kind===`verified`&&r.args.changes.some(e=>e.key===`conversations`))try{await(await this.control(s)).applyConversationSetting(n(o))}catch{}return this.settings(s)}let l=await this.control(s);if(r.cmd===`devices.revoke`)return l.revoke(r.args.phoneFp);if(r.cmd===`pairing.open`)return l.openPairing();if(r.cmd===`pairing.close`)return await l.closePairing(r.args.flowId),{};if(r.cmd===`pairing.confirm`)return await l.confirm(r.args.flowId,r.args.challengeId,r.args.phoneFp,r.args.accept),{};throw new m(`bad-request`)}).catch(e=>{throw this.error(e)})));else{let e=await this.status();if(r.cmd===`status`)a=e;else if(r.cmd===`agents`)a={agents:C(T(this.statusStateDirectory(e),this.options.homeDir))};else if(r.cmd===`settings.get`)a=await this.settings(e);else if(r.cmd===`devices`)a=await(await this.control(e)).devices();else if(r.cmd===`terminals`){let t=await(await this.control(e)).terminals();a={supported:t!==null,terminals:t??[]}}else a={checks:await this.diagnose(e)}}let o=f[r.cmd].safeParse(a);if(!o.success)throw new m(`args`in r?`delivery-unknown`:`operation-failed`);return o.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 u({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 m(`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 m(`conflict`);let r=this.stateDirectory(n,t.legacy.stateDir),i=new u({stateDir:r,uid:this.options.uid});if((e.cmd===`desktop.start`||e.cmd===`desktop.stop`)&&(t.ownership?.mode!==`desktop`||!t.ownership.consented))throw new m(`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 m(`conflict`);if(t.current.transition||n.current?.transition)throw new m(`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 m(`conflict`);if(o.local.kind===`absent`&&!o.desktop?.loaded)return o;if(o.local.kind!==`verified`)throw new m(`conflict`);return await this.desktop.stop(e.args.expect),await this.readiness.waitStopped(h(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 m(`conflict`)}else if(e.cmd===`desktop.start`){if(t.current?.transition||n.current?.transition)throw new m(`recovery-required`);if(t.current?.mode!==`desktop`||!t.current.consented||a.installed||a.loaded||o.manual.loaded||o.persistent.loaded)throw new m(`conflict`);if(o.local.kind===`verified`&&o.selection?.mode===`desktop`&&o.desktop?.loaded)return o;if(o.local.kind!==`absent`)throw new m(`conflict`)}else if(e.cmd===`ownership.recover`){if(!t.current?.transition||t.current.transition.id!==e.args.intentId)throw new m(`conflict`)}else if(t.current?.transition)throw new m(`recovery-required`);let s=e.cmd===`ownership.recover`,l=s?t.current.transition.target:e.cmd===`ownership.convert`?e.args.target:`desktop`;if(l===`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 m(`conflict`);let u=N(r,this.options.uid,e.cmd===`desktop.setup`);if(!u)throw new m(`unsafe-state`);let d=s&&n.current?.transition?.id===t.current?.transition?.id?n.current.transition:null,f=s&&!n.current?.transition&&n.current?.selection?.mode===`desktop`?n.current.selection:null,p=f?null:d?d.source:n.current?.selection??null,g=s?t.current.transition:{id:this.newId(),source:o.ownership?.mode??null,target:l,sourceManager:p?p.mode===`desktop`?`desktop-child`:p.mode===`manual`?`native-manual`:`native-persistent`:a.installed||a.loaded?`launchd`:null,sourceInstance:p?.serviceInstance??a.definition?.serviceInstance??null,stateDir:r,computerFp:u.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(g.stateDir!==r||g.computerFp!==u.fp||g.targetBundlePath!==this.options.bundlePath||g.targetVersion!==this.options.agentVersion)throw new m(`conflict`);let _=this.newId(),v=p?.environment??a.definition?.environment,y=f??d?.destination??{mode:`desktop`,stateDir:r,computerFp:u.fp,serviceInstance:_,bundlePath:this.options.bundlePath,bundleId:`sh.bilal.shellbell.host`,agentVersion:this.options.agentVersion,environment:{PATH:v?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,...v?.HERDR_SOCKET_PATH?{HERDR_SOCKET_PATH:v.HERDR_SOCKET_PATH}:{},...v?.XDG_CONFIG_HOME?{XDG_CONFIG_HOME:v.XDG_CONFIG_HOME}:{},SHELLBELL_DIR:r,SHELLBELL_SERVICE_INSTANCE:_}};if(y.mode!==`desktop`||y.computerFp!==u.fp||y.stateDir!==r||y.bundlePath!==g.targetBundlePath||y.agentVersion!==g.targetVersion)throw new m(`conflict`);let b=async()=>{let e=await this.observe(n.current,await i.inspect());return e.selection?.serviceInstance===y.serviceInstance&&e.local.kind===`verified`&&!!e.desktop?.loaded&&!e.manual.loaded&&!e.persistent.loaded&&!e.legacy.installed&&!e.legacy.loaded};return await Y(t,g,{preflight:async()=>{if(!c.safeParse(y).success)throw new m(`unsafe-state`);await this.admitBundle(y.bundlePath)},stopSource:async()=>{if(g.source===`headless`&&t.current?.startupEnabled&&await this.options.platform.setLogin(this.options.bundlePath,!0),!d){let e=n.current?.recovery??null;if(a.installed){if(!a.raw||!a.definition||e&&s)throw new m(`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:u.fp}}this.publish(n,{recovery:e,transition:{id:g.id,action:`start`,phase:`prepared`,source:p,destination:y,recoveryId:e?.id??null}})}if(await b())return;if(p){if(p.stateDir!==r||p.computerFp!==u.fp)throw new m(`conflict`);if(p.mode===`desktop`){let e=await this.observe(n.current,await i.inspect());if(e.desktop?.loaded){if(e.local.kind!==`verified`)throw new m(`conflict`);await this.desktop.stop({revision:e.revision,runtime:e.local.status.process})}}else{let e=await this.options.platform.inspect(p.mode,p.bundlePath),t=p.mode===`persistent`&&!e.loaded;t?await this.options.platform.prepareManualRecovery(p):(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(p,e),await this.readiness.waitStopped(h(r).sock),t||await this.options.platform.remove(p)}}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 m(`conflict`);e.loaded&&await i.unload(),await this.readiness.waitStopped(h(r).sock);let a=await i.inspect();if(a.loaded||!a.raw?.equals(e.raw))throw new m(`conflict`);await i.restore(null)}},verifyAbsent:async()=>{if(await b())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 m(`conflict`);this.phase(n,`source-stopped`,{selection:null})},startDestination:async()=>{await b()||(this.phase(n,`destination-start-requested`,{selection:y}),await this.desktop.start(y),await this.certify(y),this.phase(n,`destination-ready`))},complete:async()=>{this.publish(n,{selection:y,transition:null})}}),this.observe(n.current,await i.inspect())})))}async convertToHeadless(e,t,n,r,i,a,s){if(!s&&e.current?.mode===`headless`&&!t.current?.selection&&!t.current?.transition)return i;if([`foreign`,`unverified`].includes(i.local.kind))throw new m(`conflict`);await this.admitBundle(this.options.bundlePath);let c=await(this.options.inspectBundle??k)(this.options.bundlePath),l=N(a,this.options.uid);if(!l)throw new m(`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:a,computerFp:l.fp,targetBundlePath:this.options.bundlePath,targetVersion:this.options.agentVersion,phase:`prepared`};if(f.target!==`headless`||f.stateDir!==a||f.computerFp!==l.fp||f.targetBundlePath!==this.options.bundlePath||f.targetVersion!==this.options.agentVersion)throw new m(`conflict`);let p=d?.environment??(s&&r.definition?.serviceInstance===f.id?r.definition.environment:void 0),g={nodePath:c.nodePath,cliPath:V(this.options.bundlePath,`Contents/Resources/agent/dist/cli.js`),stateDir:a,serviceInstance:f.id,logPath:h(a).log,environment:{PATH:p?.PATH??`/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin`,SHELLBELL_DIR:a,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}:{}}},_=e=>{let t=e.definition;return e.installed&&!!t&&t.serviceInstance===f.id&&t.stateDir===a&&t.nodePath===g.nodePath&&t.cliPath===g.cliPath&&t.logPath===g.logPath&&JSON.stringify(Object.entries(t.environment).sort())===JSON.stringify(Object.entries(g.environment).sort())},v={stateDir:a,computerFp:l.fp,serviceInstance:f.id},y=async()=>{let e=await n.inspect();if(!_(e)||!e.loaded||(await this.readiness.observe(h(a).sock,v)).kind!==`verified`)return!1;let t=await n.inspect();return _(t)&&t.loaded};return await Y(e,f,{preflight:async()=>{if((r.installed||r.loaded)&&(!s||!_(r))||r.loaded&&(i.manual.loaded||i.persistent.loaded||d?.mode===`desktop`&&(await this.desktop.inspect(d)).loaded)||d&&(d.stateDir!==a||d.computerFp!==l.fp)||i.manual.loaded&&d?.mode!==`manual`||i.persistent.loaded&&d?.mode!==`persistent`)throw new m(`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 m(`unavailable`);if((e===`enabled`||e===`requires-approval`)&&await this.options.platform.setLogin(this.options.bundlePath,!1),!await y()){if(d?.mode===`desktop`){let e=await this.desktop.inspect(d);if(e.loaded){let n=await this.readiness.observe(h(a).sock,{stateDir:a,computerFp:l.fp,serviceInstance:d.serviceInstance,...e.pid?{pid:e.pid}:{}});if(n.kind!==`verified`)throw new m(`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(h(a).sock),t||await this.options.platform.remove(d)}}},verifyAbsent:async()=>{if(await y())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&&!_(r)||e.local.kind!==`absent`)throw new m(`conflict`);this.phase(t,`source-stopped`,{selection:null})},startDestination:async()=>{if(await y())return;if(await this.admitBundle(this.options.bundlePath),N(a,this.options.uid)?.fp!==l.fp)throw new m(`unsafe-state`);o(g.logPath)||F(L(g.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(!_(r)){if(r.installed||r.loaded)throw new m(`conflict`);await n.write(g)}await n.setStartupEnabled(e.current.startupEnabled);let i=await n.load();if(await this.readiness.waitReady(h(a).sock,{...v,pid:i}),!await y())throw new m(`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`},O(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 m(`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 m(`upgrade-required`);return n}async lifecycle(e,t,n,r,i){if(e.cmd===`service.recover`)return this.recover(e,t,n,r,i);if(t.current?.transition)throw new m(`recovery-required`);let a=t.current?.selection??null;if(i.manual.loaded&&a?.mode!==`manual`||i.persistent.loaded&&a?.mode!==`persistent`||a&&r.loaded||e.cmd!==`service.start`&&!a||e.cmd===`service.start`&&a&&b(a.mode)===e.args.mode&&a.bundlePath===this.options.bundlePath&&i[b(a.mode)].loaded||r.installed&&(e.cmd!==`service.start`||!e.args.migrateLegacy))throw new m(`conflict`);let o=null;if(e.cmd===`service.start`||e.cmd===`service.restart`){await this.admitBundle(this.options.bundlePath),await this.options.platform.preflight(e.cmd===`service.start`?e.args.mode:b(a.mode),this.options.bundlePath);let t=a?.stateDir??r.definition?.stateDir??(e.cmd===`service.start`?e.args.stateDir:void 0)??this.options.defaultStateDir;if(e.cmd===`service.start`&&e.args.stateDir&&e.args.stateDir!==t)throw new m(`conflict`);!a&&!r.installed&&(N(t,this.options.uid),await this.requireAbsentDestination(t));let n=N(t,this.options.uid,!0),i=this.newId();o={mode:e.cmd===`service.start`?e.args.mode:a.mode,stateDir:t,computerFp:n.fp,serviceInstance:i,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:t,SHELLBELL_SERVICE_INSTANCE:i}}}let s=t.current?.recovery??null;if(r.installed){if(!r.raw||!r.definition||s)throw new m(`recovery-required`);let e=N(r.definition.stateDir,this.options.uid);if(!e)throw new m(`unsafe-state`);s={id:this.newId(),definitionPath:n.definitionPath,rawBase64:r.raw.toString(`base64`),sha256:W(`sha256`).update(r.raw).digest(`hex`),wasLoaded:r.loaded,stateDir:r.definition.stateDir,computerFp:e.fp}}this.publish(t,{recovery:s,transition:{id:this.newId(),action:e.cmd.slice(8),phase:`prepared`,source:a,destination:o,recoveryId:s?.id??null}});try{return await this.advance(t,n,r,i)}catch(e){throw this.phase(t,`recovery-required`),e}}async stopSource(e,t,n,r){let i=e.current.transition,a=i.source;if(this.phase(e,`source-stop-requested`),a){try{await this.admitBundle(a.bundlePath,a.agentVersion)}catch{throw new m(`recovery-required`)}let e=r[b(a.mode)];(e.loaded||e.registration!==`not-registered`)&&await this.options.platform.stop(a,e),await this.readiness.waitStopped(h(a.stateDir).sock);let t=await this.options.platform.inspect(b(a.mode),a.bundlePath);if(t.loaded||b(a.mode)===`persistent`&&t.registration!==`not-registered`)throw new m(`operation-failed`)}else if(n.installed){n.loaded&&await t.unload(),await this.readiness.waitStopped(h(n.definition.stateDir).sock);let e=await t.inspect();if(e.loaded||!e.raw?.equals(n.raw))throw new m(`conflict`)}else if(r.local.kind!==`absent`)throw new m(`conflict`);if(this.phase(e,`source-stopped`,{selection:i.action===`stop`?a:null}),a&&i.destination&&(b(a.mode)!==b(i.destination.mode)||a.bundlePath!==i.destination.bundlePath)&&await this.options.platform.remove(a),n.installed){await t.restore(null);let e=await t.inspect();if(e.installed||e.loaded)throw new m(`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 m(`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(h(e).sock)).kind!==`absent`)throw new m(`conflict`)}async certify(e){let t=e.mode===`desktop`?await this.desktop.inspect(e):await this.options.platform.inspect(b(e.mode),e.bundlePath);if(!t.loaded||!t.pid)throw new m(`operation-failed`);let n=await this.readiness.waitReady(h(e.stateDir).sock,{computerFp:e.computerFp,stateDir:e.stateDir,serviceInstance:e.serviceInstance,pid:t.pid}),r=e.mode===`desktop`?await this.desktop.inspect(e):await this.options.platform.inspect(b(e.mode),e.bundlePath);if(JSON.stringify(t)!==JSON.stringify(r)||n.process.agentVersion!==e.agentVersion)throw new m(`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(e,t,n,r,i){let a=t.current;if(!a||i.manual.loaded&&i.persistent.loaded||a.selection&&r.loaded||a.selection&&i[b(a.selection.mode)===`manual`?`persistent`:`manual`].loaded)throw new m(`conflict`);if(e.args.action===`discard-backup`){if(a.transition||!a.recovery||r.installed&&r.raw?.toString(`base64`)!==a.recovery.rawBase64)throw new m(`conflict`);return this.publish(t,{recovery:null}),this.observe(t.current,r)}let o=a.recovery,s=o?Buffer.from(o.rawBase64,`base64`):null;if(o&&(!s||W(`sha256`).update(s).digest(`hex`)!==o.sha256)||o&&(o.definitionPath!==n.definitionPath||N(o.stateDir,this.options.uid)?.fp!==o.computerFp))throw new m(`unsafe-state`);if(o&&r.installed&&!r.raw?.equals(s))throw new m(`conflict`);let c=this.isManualRecovery(a);if(e.args.action===`use-manual`||e.args.action===`continue`&&c){let e=c?a.transition?.source:a.transition?.destination;if(e?.mode!==`persistent`||a.transition?.restoreLegacy||!c&&![`start`,`restart`].includes(a.transition.action)||a.selection?.serviceInstance!==e.serviceInstance||i.manual.loaded||i.persistent.loaded||i.local.kind!==`absent`||r.installed||r.loaded)throw new m(`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 m(`unsafe-state`);let o=this.newId(),s=c?a.transition.destination:{...e,mode:`manual`,bundlePath:this.options.bundlePath,agentVersion:this.options.agentVersion,serviceInstance:o,environment:{...e.environment,SHELLBELL_SERVICE_INSTANCE:o}};c||this.publish(t,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:e,destination:s,recoveryId:a.recovery?.id??null}});try{await this.options.platform.prepareManualRecovery(e),await this.requireAbsentDestination(e.stateDir);let r=await this.observe(t.current,await n.inspect());if(r.manual.loaded||r.persistent.loaded||r.legacy.installed||r.legacy.loaded||r.local.kind!==`absent`)throw new m(`conflict`);return this.publish(t,{selection:null,transition:{id:this.newId(),action:`start`,phase:`source-stopped`,source:null,destination:s,recoveryId:a.recovery?.id??null}}),await this.startDestination(t,s),this.publish(t,{transition:null}),this.observe(t.current,await n.inspect())}catch(e){throw this.phase(t,`recovery-required`),e}}if(e.args.action===`continue`&&a.transition?.action===`recover`&&!a.transition.restoreLegacy)throw new m(`recovery-required`);try{if(e.args.action===`restore-legacy`||a.transition?.restoreLegacy){if(!o||!s)throw new m(`conflict`);if(e.args.action===`restore-legacy`){if(r.loaded)throw new m(`conflict`);this.publish(t,{transition:{id:this.newId(),action:`recover`,phase:`prepared`,source:a.selection,destination:null,recoveryId:o.id,restoreLegacy:{restartPrevious:e.args.restartPrevious}}})}return await this.restoreLegacy(t,n,r,i,s)}let c=a.transition;if(!c)throw new m(`conflict`);let l=c.destination;if(l&&a.selection?.serviceInstance===l.serviceInstance){let e=i[b(l.mode)];if(r.loaded||i[b(l.mode)===`manual`?`persistent`:`manual`].loaded)throw new m(`conflict`);if(e.registration===`requires-approval`)return this.phase(t,`awaiting-approval`),this.observe(t.current,r);if(e.loaded)await this.certify(l),this.phase(t,`destination-ready`);else{if(i.local.kind!==`absent`)throw new m(`conflict`);await this.startDestination(t,l)}return t.current.transition?.phase!==`awaiting-approval`&&this.publish(t,{transition:null}),this.observe(t.current,await n.inspect())}return await this.advance(t,n,r,i)}catch(e){throw t.current?.transition&&this.phase(t,`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 m(`conflict`);let o=await t.inspect();if(!o.loaded||!o.raw?.equals(i))throw new m(`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 m(`conflict`);await this.readiness.waitStopped(h(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 m(`operation-failed`);if(s.restartPrevious){this.phase(e,`destination-start-requested`);let n=await t.load();await this.readiness.waitReady(h(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 m(`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 u=
|
|
2
|
+
import{T as e,at as t,ht as n,ot as r,zt as i}from"./service-lifecycle-CSQmtvfk.js";import{a,n as o,r as s}from"./service-entry-uoRwcU1h.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`?`${i}\n`:`Shellbell native service
|
|
3
|
+
`);return}let u=e.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!==i)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=n(e.stateDir),l=t({file:c.log,stdout:!1}),u=r(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{};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{A as e,
|
|
1
|
+
import{A as e,D as t,E as n,Ft as r,Nt as i,O as a,Pt as o,S as s,b as c,c as l,gt as u,h as d,ht as f,i as p,j as m,jt as h,k as g,m as _,p as v,vt as y,w as b,y as x}from"./service-lifecycle-CSQmtvfk.js";import{createRequire as S}from"node:module";import{closeSync as C,constants as w,fstatSync as ee,mkdirSync as T,openSync as E,readdirSync as te,realpathSync as D,unlinkSync as O}from"node:fs";import{basename as k,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){(!n.safeParse(e).success||e!==j(e))&&F();for(let t=e;;t=A(t)){let e=i(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new d(`unsafe-state`)}function I(e){return(!n.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
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>
|
|
@@ -7,5 +7,5 @@ import{A as e,At as t,D as n,E as r,Mt as i,O as a,Ot as o,S as s,b as c,c as l,
|
|
|
7
7
|
<key>KeepAlive</key><true/>
|
|
8
8
|
<key>ThrottleInterval</key><integer>10</integer>
|
|
9
9
|
</dict></plist>
|
|
10
|
-
`)}function R(e,t){return e===null||t===null?e===t:
|
|
11
|
-
`)!==`"${B}" => disabled`)throw new d(`operation-failed`);let r=await C.inspect(`persistent`,e.bundlePath);if(r.loaded)throw new d(`conflict`);r.registration!==`not-registered`&&r.registration!==`not-found`&&await C.stop(e,r)},inspectLegacy:()=>m().inspect(),async inspect(e,
|
|
10
|
+
`)}function R(e,t){return e===null||t===null?e===t:r(e.stat,t.stat)&&e.stat.mode===t.stat.mode&&e.stat.uid===t.stat.uid&&e.stat.size===t.stat.size&&e.stat.mtimeMs===t.stat.mtimeMs&&e.stat.ctimeMs===t.stat.ctimeMs&&e.raw.equals(t.raw)}function z(e,t){let n=j(e,`manual.plist`),a,s=r=>{try{if(P(e),!i(e))return null;o(e,t);let a=i(n);if(!a)return null;let s=h(n,65536,t);return s.equals(L(r))||F(),{stat:a,raw:s}}catch{return F()}},c=e=>{let t=s(e);return a!==void 0&&!R(a,t)&&F(),a=t,t};return{path:n,inspect(e){return c(e)!==null},write(l){let u=L(l),d=c(l);P(e),i(e)||T(e,{recursive:!0,mode:448});let f=o(e,t);y(n,u,()=>{P(e),(!r(f,o(e,t))||!R(d,s(l)))&&F()}),a=s(l),a?.raw.equals(u)||F()},remove(e){let t=c(e);t&&(R(t,s(e))||F(),O(n),a=null)}}}const B=`sh.bilal.shellbell.host.agent`,V=65536;function H(){throw new d(`unsafe-state`)}function U(e){(!n.safeParse(e).success||e!==j(e)||k(e)!==`Shellbell.app`)&&H();let t=j(e,`Contents`,`MacOS`,`Shellbell`);return n.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 d(i?`delivery-unknown`:`unavailable`)}}function G(e,t){return r(e,t)&&e.mode===t.mode&&e.uid===t.uid&&e.size===t.size&&e.mtimeMs===t.mtimeMs&&e.ctimeMs===t.ctimeMs}async function K(e,t,n=a){let r=U(e),o=j(e,`Contents`,`Info.plist`),s=new Map,c=()=>{P(A(e));for(let n of[e,j(e,`Contents`),j(e,`Contents`,`MacOS`),o,r]){let e=i(n),a=n===o||n===r;(!e||e.isSymbolicLink()||(a?!e.isFile():!e.isDirectory())||e.uid!==t&&e.uid!==0||e.mode&3602||n===r&&!(e.mode&73))&&H();let c=s.get(n);c&&!G(c,e)&&H(),s.set(n,e)}};try{c();let e=await W(n,`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,`-`],h(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(),c(),{executable:r,revalidate:c}}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:r,uid:o,homeDir:c}=e;(!Number.isSafeInteger(o)||o<=0||!n.safeParse(r).success||!n.safeParse(c).success||r!==j(r)||c!==j(c))&&H();let l=j(c,`Library`,`LaunchAgents`);(r===l||r.startsWith(`${l}/`))&&H();let u=e.run??a,f=z(r,o),m=()=>e.legacy??t({run:u,uid:o,homeDir:c}),h=`gui/${o}`,_=e=>`${h}/${e===`manual`?N:B}`,v=e=>{s.safeParse(e).success||H()};async function y(e,t,n,r=`service`){let i=await K(e,o,u);await n?.(),i.revalidate();let a=t!==`status`,s=await W(u,i.executable,[r===`login`?`--login-api`:`--service-api`,t],void 0,a);i.revalidate();let c;try{c=x.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.stdout)))}catch{throw new d(a?`delivery-unknown`:`unavailable`)}if(!c.ok)throw new d(c.error.code===`denied`?`approval-required`:c.error.code===`invalid-bundle`?`unsafe-state`:`operation-failed`);if(s.exitCode!==0)throw new d(a?`delivery-unknown`:`unavailable`);return c.status}async function S(e,t,n=1e4){let r=await W(u,`/bin/launchctl`,[`print`,_(e)],void 0,!1,n);if(r.exitCode===113)return{loaded:!1,pid:null};if(r.exitCode!==0)throw new d(`unavailable`);return{loaded:!0,pid:q(r.stdout,_(e),U(t),e)}}let C={loginStatus:e=>y(e,`status`,void 0,`login`),async setLogin(e,t){let n=await K(e,o,u),r=await W(u,`/usr/bin/codesign`,[`--verify`,`--strict`,e]);if(n.revalidate(),r.exitCode!==0)throw new d(`startup-unavailable`);let i=await y(e,`status`,void 0,`login`);if(i===`not-found`&&!t||i===`unknown`)throw new d(`startup-unavailable`);if(t?i===`enabled`||i===`requires-approval`:i===`not-registered`)return i;try{await y(e,t?`register`:`unregister`,void 0,`login`)}catch(n){if(!(t&&n instanceof d&&n.code===`approval-required`&&await y(e,`status`,void 0,`login`)===`requires-approval`))throw n}let a=await y(e,`status`,void 0,`login`);if(t?a!==`enabled`&&a!==`requires-approval`:a!==`not-registered`)throw new d(`operation-failed`);return a},async preflight(e,t){await g(u,o,c);let n=await K(t,o,u);if(e===`persistent`){let e=await W(u,`/usr/bin/codesign`,[`--verify`,`--strict`,t]);if(n.revalidate(),e.exitCode!==0||await y(t,`status`)===`not-found`)throw new d(`startup-unavailable`)}},async prepareManualRecovery(e){if(await g(u,o,c),v(e),b(e.mode)!==`persistent`&&H(),(await C.inspect(`persistent`,e.bundlePath)).loaded)throw new d(`conflict`);if((await W(u,`/bin/launchctl`,[`disable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new d(`operation-failed`);let t=await W(u,`/bin/launchctl`,[`print-disabled`,h]),n=new TextDecoder(`utf-8`,{fatal:!0}).decode(t.stdout).trim().split(/\r?\n/).map(e=>e.trim());if(t.exitCode!==0||n.shift()!==`disabled services = {`||n.pop()!==`}`||n.filter(e=>e.includes(`"${B}"`)).join(`
|
|
11
|
+
`)!==`"${B}" => disabled`)throw new d(`operation-failed`);let r=await C.inspect(`persistent`,e.bundlePath);if(r.loaded)throw new d(`conflict`);r.registration!==`not-registered`&&r.registration!==`not-found`&&await C.stop(e,r)},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=i(t)?await y(t,`status`):`not-found`);let a=await S(e,t);return e===`manual`&&a.loaded&&r!==`enabled`&&H(),{registration:r,...a,bundlePath:t}},async start(e){if(v(e),await C.preflight(b(e.mode),e.bundlePath),(await C.inspect(b(e.mode),e.bundlePath)).loaded)throw new d(`conflict`);if(b(e.mode)===`persistent`){if((await W(u,`/bin/launchctl`,[`enable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new d(`operation-failed`);return{registration:await y(e.bundlePath,`register`,async()=>{if((await S(`persistent`,e.bundlePath)).loaded)throw new d(`conflict`)}),...await S(b(e.mode),e.bundlePath),bundlePath:e.bundlePath}}let t=await K(e.bundlePath,o,u);if(f.write(t.executable),(await S(`manual`,e.bundlePath)).loaded)throw new d(`conflict`);if(f.inspect(t.executable),t.revalidate(),(await W(u,`/bin/launchctl`,[`bootstrap`,h,f.path],void 0,!0)).exitCode!==0)throw new d(`operation-failed`);return C.inspect(`manual`,e.bundlePath)},async stop(e,t){v(e),t.bundlePath!==e.bundlePath&&H();let n=await C.inspect(b(e.mode),e.bundlePath);if(n.loaded!==t.loaded||n.pid!==t.pid||n.registration!==t.registration)throw new d(`conflict`);if(b(e.mode)===`persistent`){if(await y(e.bundlePath,`unregister`,async()=>{let t=await S(`persistent`,e.bundlePath);if(t.loaded!==n.loaded||t.pid!==n.pid)throw new d(`conflict`)})!==`not-registered`)throw new d(`operation-failed`)}else if(n.loaded&&(f.inspect(U(e.bundlePath)),(await W(u,`/bin/launchctl`,[`bootout`,_(`manual`)],void 0,!0)).exitCode!==0))throw new d(`operation-failed`);let r=performance.now()+1e4;for(;;){let t=r-performance.now();if(t<=0)throw new d(`operation-failed`);let i=await S(b(e.mode),e.bundlePath,t);if(!i.loaded)break;if(i.pid!==null&&i.pid!==n.pid)throw new d(`conflict`);let a=Math.min(100,r-performance.now());if(a<=0)throw new d(`operation-failed`);await new Promise(e=>setTimeout(e,a))}},async remove(e){v(e);let t=await C.inspect(b(e.mode),e.bundlePath);if(t.loaded||b(e.mode)===`persistent`&&t.registration!==`not-registered`)throw new d(`conflict`);b(e.mode)===`manual`&&f.remove(U(e.bundlePath))},withLegacyGuard(e){return p(m(),!0,e)}};return C}const Y=()=>{throw new d(`unsafe-state`)};async function X(e,t={}){try{(D(e)!==e||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&Y();let n=t.run??a,r=await K(e,process.getuid(),n),o=j(e,`Contents`),s=j(o,`Resources`),c=j(o,`Helpers/node`),l=j(s,`agent/dist/native-controller.js`),u=j(s,`agent/dist/native-service.js`),f=[c,l,u,j(s,`runtime/LICENSE`),j(s,`agent/package.json`),j(s,`agent/dist/cli.js`)],p=()=>{for(let t of f){for(let n=A(t);n!==e;n=A(n)){let e=i(n);(!e?.isDirectory()||e.isSymbolicLink()||e.mode&3602||e.uid!==0&&e.uid!==process.getuid())&&Y()}let n=i(t);(!n?.isFile()||n.isSymbolicLink()||n.mode&3602||n.uid!==0&&n.uid!==process.getuid()||t===c&&!(n.mode&73))&&Y()}let t=0,n=new Set,r=e=>{++t>1e5&&Y();let a=i(e);if(!a)throw new d(`unsafe-state`);let o=D(e);if(o.startsWith(`${s}/`)||Y(),a.isSymbolicLink()){r(o);return}if(!n.has(o)){if(n.add(o),(a.uid!==0&&a.uid!==process.getuid()||a.mode&3602)&&Y(),a.isDirectory())for(let t of te(e))r(j(e,t));else a.isFile()||Y()}};for(let e of[`agent`,`runtime`])r(j(s,e))};p();let m=JSON.parse(h(j(s,`agent/package.json`),65536).toString(`utf8`));(m.name!==`shellbell`||typeof m.version!=`string`||!m.version||m.type!==`module`)&&Y();let g=S(j(s,`agent/package.json`));for(let e of Object.keys(m.dependencies??{}))D(g.resolve(e)).startsWith(`${s}/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(c,[`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(v.exitCode!==0||v.stdout.toString(`utf8`).trim()!==`v22.23.1`)&&Y();let y=await n(c,[`-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(s,`agent/dist/cli.js`),l,u]){let t=await n(c,[e,`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(t.exitCode!==0||t.stdout.toString(`utf8`).trim()!==m.version)&&Y()}return r.revalidate(),p(),{executable:r.executable,nodePath:c,controllerPath:l,servicePath:u,agentVersion:m.version}}catch(e){if(e instanceof d)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`,f),e.off(`end`,u),e.off(`close`,u),e.off(`error`,u)},u=()=>{o||(o=!0,l(),r(new d(`unavailable`)),Promise.resolve().then(()=>t.onLost()).catch(()=>{}))},f=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`,f),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 v{constructor(e){super({...e,filename:`controller.json`,maxBytes:_,schema:c})}};function re(e,t,r){if(r.NODE_OPTIONS||r.NODE_PATH||!s.safeParse(e).success||!n.safeParse(t).success)throw new d(`unsafe-state`);return{...e.environment,HOME:t}}function $(t,r,a=!1){try{if(r<=0||!n.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=i(e);if(t&&(!t.isDirectory()||t.isSymbolicLink()))throw Error();if(A(e)===e)break}if(!i(t)){if(!a)return null;T(t,{recursive:!0,mode:448})}if(o(t,r),D(t)!==t)throw Error();let s=f(t);for(let e of[s.identity,s.pairings,s.config,s.pid])i(e)&&h(e,65536,r);ie(s.log,r);let c=i(s.sock);if(c&&(!c.isSocket()||c.uid!==r||(c.mode&4095)!=384))throw Error();return u(s),a?e(s):m(s)}catch{throw new d(`unsafe-state`)}}function ie(e,t){let n=i(e);if(!n)return;let a=e=>{if(!e.isFile()||e.isSymbolicLink()||e.uid!==t||(e.mode&4095)!=384)throw Error()};a(n);let o=E(e,w.O_RDONLY|w.O_NOFOLLOW|w.O_NONBLOCK);try{let t=ee(o);a(t);let s=i(e);if(!s||(a(s),!r(n,t)||!r(t,s)))throw Error()}finally{C(o)}}async function ae(e,t){let n=new Q(t).inspect()?.selection;if(!n||n.mode!==e||n.bundlePath!==t.bundlePath)throw new d(`conflict`);let r=$(n.stateDir,t.uid);if(!r||r.fp!==n.computerFp)throw new d(`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 d(`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 d(`unavailable`);if(o=t.start(n),await o,a)throw await c(),new d(`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};
|