shellbell 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +10 -10
- package/dist/{doctor-ChDZpdTd.js → doctor-7CO6h_gI.js} +1 -1
- package/dist/native-controller.js +1 -1
- package/dist/native-service.js +1 -1
- package/dist/{service-entry-CRFCiWGq.js → service-entry-CjiJBFHG.js} +1 -1
- package/dist/{service-lifecycle-Cl7R7c5G.js → service-lifecycle-CLWP08Es.js} +3 -3
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
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-Cl7R7c5G.js";import{B as C,H as w,R as T,U as E,W as D,t as O}from"./doctor-ChDZpdTd.js";import{a as k,i as A,o as j,r as M,t as N}from"./service-entry-CRFCiWGq.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
|
|
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-CLWP08Es.js";import{B as C,H as w,R as T,U as E,W as D,t as O}from"./doctor-7CO6h_gI.js";import{a as k,i as A,o as j,r as M,t as N}from"./service-entry-CjiJBFHG.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
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{T as e,at as t,ht as n,ot as r,zt as i}from"./service-lifecycle-
|
|
2
|
+
import{T as e,at as t,ht as n,ot as r,zt as i}from"./service-lifecycle-CLWP08Es.js";import{a,n as o,r as s}from"./service-entry-CjiJBFHG.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
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,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-
|
|
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-CLWP08Es.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>
|