shellbell 0.13.1 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shellbell",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "Shellbell agent — mirrors your Mac's terminal sessions to your phone",
5
5
  "type": "module",
6
6
  "imports": {
@@ -1,11 +0,0 @@
1
- import{A as e,At as t,C as n,D as r,E as i,Et as a,O as o,Ot as s,T as c,c as l,dt as u,f as d,ft as f,i as p,k as m,kt as h,m as g,mt as _,p as v,v as y,x as b,y as x}from"./service-lifecycle-CCOIXXFm.js";import{createRequire as S}from"node:module";import{closeSync as C,constants as w,fstatSync as T,mkdirSync as E,openSync as ee,readdirSync as D,realpathSync as O,unlinkSync as k}from"node:fs";import{basename as te,dirname as A,join as j}from"node:path";import{z as M}from"zod";const N=`sh.bilal.shellbell.host.manual`;function P(e){(!c.safeParse(e).success||e!==j(e))&&F();for(let t=e;;t=A(t)){let e=s(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new g(`unsafe-state`)}function I(e){return(!c.safeParse(e).success||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&F(),e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&apos;`)}function L(e){return(e!==j(e)||!e.endsWith(`/Shellbell.app/Contents/MacOS/Shellbell`))&&F(),Buffer.from(`<?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0"><dict>
4
- <key>Label</key><string>${N}</string>
5
- <key>ProgramArguments</key><array><string>${I(e)}</string><string>--service-run</string><string>manual</string></array>
6
- <key>RunAtLoad</key><true/>
7
- <key>KeepAlive</key><true/>
8
- <key>ThrottleInterval</key><integer>10</integer>
9
- </dict></plist>
10
- `)}function R(e,n){return e===null||n===null?e===n:t(e.stat,n.stat)&&e.stat.mode===n.stat.mode&&e.stat.uid===n.stat.uid&&e.stat.size===n.stat.size&&e.stat.mtimeMs===n.stat.mtimeMs&&e.stat.ctimeMs===n.stat.ctimeMs&&e.raw.equals(n.raw)}function z(e,n){let r=j(e,`manual.plist`),i,o=t=>{try{if(P(e),!s(e))return null;h(e,n);let i=s(r);if(!i)return null;let o=a(r,65536,n);return o.equals(L(t))||F(),{stat:i,raw:o}}catch{return F()}},c=e=>{let t=o(e);return i!==void 0&&!R(i,t)&&F(),i=t,t};return{path:r,inspect(e){return c(e)!==null},write(a){let l=L(a),u=c(a);P(e),s(e)||E(e,{recursive:!0,mode:448});let d=h(e,n);_(r,l,()=>{P(e),(!t(d,h(e,n))||!R(u,o(a)))&&F()}),i=o(a),i?.raw.equals(l)||F()},remove(e){let t=c(e);t&&(R(t,o(e))||F(),k(r),i=null)}}}const B=`sh.bilal.shellbell.host.agent`,V=65536;function H(){throw new g(`unsafe-state`)}function U(e){(!c.safeParse(e).success||e!==j(e)||te(e)!==`Shellbell.app`)&&H();let t=j(e,`Contents`,`MacOS`,`Shellbell`);return c.safeParse(t).success||H(),t}async function W(e,t,n,r,i=!1,a=1e4){try{let i=await e(t,n,{input:r,timeoutMs:a,maxOutputBytes:V,captureOutput:!0});if(!Number.isInteger(i.exitCode)||i.exitCode<0||i.exitCode>255||!Buffer.isBuffer(i.stdout)||i.stdout.length>V)throw Error(`invalid command result`);return i}catch{throw new g(i?`delivery-unknown`:`unavailable`)}}function G(e,n){return t(e,n)&&e.mode===n.mode&&e.uid===n.uid&&e.size===n.size&&e.mtimeMs===n.mtimeMs&&e.ctimeMs===n.ctimeMs}async function K(e,t,n=r){let i=U(e),o=j(e,`Contents`,`Info.plist`),c=new Map,l=()=>{P(A(e));for(let n of[e,j(e,`Contents`),j(e,`Contents`,`MacOS`),o,i]){let e=s(n),r=n===o||n===i;(!e||e.isSymbolicLink()||(r?!e.isFile():!e.isDirectory())||e.uid!==t&&e.uid!==0||e.mode&3602||n===i&&!(e.mode&73))&&H();let a=c.get(n);a&&!G(a,e)&&H(),c.set(n,e)}};try{l();let e=await W(n,`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,`-`],a(o,V));e.exitCode!==0&&H();let t=JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(e.stdout));return(t?.CFBundleIdentifier!==`sh.bilal.shellbell.host`||t?.CFBundleExecutable!==`Shellbell`)&&H(),l(),{executable:i,revalidate:l}}catch{return H()}}function q(e,t,n,r){let i;try{i=new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch{return H()}let a=i.trim().split(/\r?\n/).map(e=>e.trim());(a.shift()!==`${t} = {`||a.pop()!==`}`)&&H();let o=1,s,c=null,l=!1,u,d=!1;for(let e of a)if(e){if(e===`}`){o<=1&&H(),d&&o===2&&(d=!1),o--;continue}if(o===1&&e.startsWith(`program = `)){s!==void 0&&H(),s=e.slice(10);continue}if(o===1&&e.startsWith(`pid = `)){(l||!/^pid = [1-9][0-9]*$/.test(e))&&H(),l=!0,c=Number(e.slice(6)),(!Number.isSafeInteger(c)||c>2147483647)&&H();continue}if(o===1&&/^(?:pid|program|arguments)(?:\s|=)/.test(e)&&e!==`arguments = {`&&H(),e.endsWith(`= {`)){o===1&&e===`arguments = {`?(u!==void 0&&H(),u=[],d=!0):d&&H(),o++;continue}d&&o===2?u.push(e):(e.includes(`{`)||e.includes(`}`))&&H()}return(o!==1||s!==n||!u||u.length!==3||u[0]!==(r===`persistent`?`Shellbell`:n)||u[1]!==`--service-run`||u[2]!==r)&&H(),c}function J(e){let{root:t,uid:a,homeDir:l}=e;(!Number.isSafeInteger(a)||a<=0||!c.safeParse(t).success||!c.safeParse(l).success||t!==j(t)||l!==j(l))&&H();let u=j(l,`Library`,`LaunchAgents`);(t===u||t.startsWith(`${u}/`))&&H();let d=e.run??r,f=z(t,a),m=()=>e.legacy??i({run:d,uid:a,homeDir:l}),h=`gui/${a}`,_=e=>`${h}/${e===`manual`?N:B}`,v=e=>{b.safeParse(e).success||H()};async function x(e,t,n,r=`service`){let i=await K(e,a,d);await n?.(),i.revalidate();let o=t!==`status`,s=await W(d,i.executable,[r===`login`?`--login-api`:`--service-api`,t],void 0,o);i.revalidate();let c;try{c=y.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.stdout)))}catch{throw new g(o?`delivery-unknown`:`unavailable`)}if(!c.ok)throw new g(c.error.code===`denied`?`approval-required`:c.error.code===`invalid-bundle`?`unsafe-state`:`operation-failed`);if(s.exitCode!==0)throw new g(o?`delivery-unknown`:`unavailable`);return c.status}async function S(e,t,n=1e4){let r=await W(d,`/bin/launchctl`,[`print`,_(e)],void 0,!1,n);if(r.exitCode===113)return{loaded:!1,pid:null};if(r.exitCode!==0)throw new g(`unavailable`);return{loaded:!0,pid:q(r.stdout,_(e),U(t),e)}}let C={loginStatus:e=>x(e,`status`,void 0,`login`),async setLogin(e,t){let n=await K(e,a,d),r=await W(d,`/usr/bin/codesign`,[`--verify`,`--strict`,e]);if(n.revalidate(),r.exitCode!==0)throw new g(`startup-unavailable`);let i=await x(e,`status`,void 0,`login`);if(i===`not-found`&&!t||i===`unknown`)throw new g(`startup-unavailable`);if(t?i===`enabled`||i===`requires-approval`:i===`not-registered`)return i;try{await x(e,t?`register`:`unregister`,void 0,`login`)}catch(n){if(!(t&&n instanceof g&&n.code===`approval-required`&&await x(e,`status`,void 0,`login`)===`requires-approval`))throw n}let o=await x(e,`status`,void 0,`login`);if(t?o!==`enabled`&&o!==`requires-approval`:o!==`not-registered`)throw new g(`operation-failed`);return o},async preflight(e,t){await o(d,a,l);let n=await K(t,a,d);if(e===`persistent`){let e=await W(d,`/usr/bin/codesign`,[`--verify`,`--strict`,t]);if(n.revalidate(),e.exitCode!==0||await x(t,`status`)===`not-found`)throw new g(`startup-unavailable`)}},async prepareManualRecovery(e){if(await o(d,a,l),v(e),n(e.mode)!==`persistent`&&H(),(await C.inspect(`persistent`,e.bundlePath)).loaded)throw new g(`conflict`);if((await W(d,`/bin/launchctl`,[`disable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);let t=await W(d,`/bin/launchctl`,[`print-disabled`,h]),r=new TextDecoder(`utf-8`,{fatal:!0}).decode(t.stdout).trim().split(/\r?\n/).map(e=>e.trim());if(t.exitCode!==0||r.shift()!==`disabled services = {`||r.pop()!==`}`||r.filter(e=>e.includes(`"${B}"`)).join(`
11
- `)!==`"${B}" => disabled`)throw new g(`operation-failed`);let i=await C.inspect(`persistent`,e.bundlePath);if(i.loaded)throw new g(`conflict`);i.registration!==`not-registered`&&i.registration!==`not-found`&&await C.stop(e,i)},inspectLegacy:()=>m().inspect(),async inspect(e,t){e!==`manual`&&e!==`persistent`&&H();let n=U(t),r;e===`manual`?r=f.inspect(n)?`enabled`:`not-registered`:(P(A(t)),r=s(t)?await x(t,`status`):`not-found`);let i=await S(e,t);return e===`manual`&&i.loaded&&r!==`enabled`&&H(),{registration:r,...i,bundlePath:t}},async start(e){if(v(e),await C.preflight(n(e.mode),e.bundlePath),(await C.inspect(n(e.mode),e.bundlePath)).loaded)throw new g(`conflict`);if(n(e.mode)===`persistent`){if((await W(d,`/bin/launchctl`,[`enable`,_(`persistent`)],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);return{registration:await x(e.bundlePath,`register`,async()=>{if((await S(`persistent`,e.bundlePath)).loaded)throw new g(`conflict`)}),...await S(n(e.mode),e.bundlePath),bundlePath:e.bundlePath}}let t=await K(e.bundlePath,a,d);if(f.write(t.executable),(await S(`manual`,e.bundlePath)).loaded)throw new g(`conflict`);if(f.inspect(t.executable),t.revalidate(),(await W(d,`/bin/launchctl`,[`bootstrap`,h,f.path],void 0,!0)).exitCode!==0)throw new g(`operation-failed`);return C.inspect(`manual`,e.bundlePath)},async stop(e,t){v(e),t.bundlePath!==e.bundlePath&&H();let r=await C.inspect(n(e.mode),e.bundlePath);if(r.loaded!==t.loaded||r.pid!==t.pid||r.registration!==t.registration)throw new g(`conflict`);if(n(e.mode)===`persistent`){if(await x(e.bundlePath,`unregister`,async()=>{let t=await S(`persistent`,e.bundlePath);if(t.loaded!==r.loaded||t.pid!==r.pid)throw new g(`conflict`)})!==`not-registered`)throw new g(`operation-failed`)}else if(r.loaded&&(f.inspect(U(e.bundlePath)),(await W(d,`/bin/launchctl`,[`bootout`,_(`manual`)],void 0,!0)).exitCode!==0))throw new g(`operation-failed`);let i=performance.now()+1e4;for(;;){let t=i-performance.now();if(t<=0)throw new g(`operation-failed`);let a=await S(n(e.mode),e.bundlePath,t);if(!a.loaded)break;if(a.pid!==null&&a.pid!==r.pid)throw new g(`conflict`);let o=Math.min(100,i-performance.now());if(o<=0)throw new g(`operation-failed`);await new Promise(e=>setTimeout(e,o))}},async remove(e){v(e);let t=await C.inspect(n(e.mode),e.bundlePath);if(t.loaded||n(e.mode)===`persistent`&&t.registration!==`not-registered`)throw new g(`conflict`);n(e.mode)===`manual`&&f.remove(U(e.bundlePath))},withLegacyGuard(e){return p(m(),!0,e)}};return C}const Y=()=>{throw new g(`unsafe-state`)};async function X(e,t={}){try{(O(e)!==e||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&Y();let n=t.run??r,i=await K(e,process.getuid(),n),o=j(e,`Contents`),c=j(o,`Resources`),l=j(o,`Helpers/node`),u=j(c,`agent/dist/native-controller.js`),d=j(c,`agent/dist/native-service.js`),f=[l,u,d,j(c,`runtime/LICENSE`),j(c,`agent/package.json`),j(c,`agent/dist/cli.js`)],p=()=>{for(let t of f){for(let n=A(t);n!==e;n=A(n)){let e=s(n);(!e?.isDirectory()||e.isSymbolicLink()||e.mode&3602||e.uid!==0&&e.uid!==process.getuid())&&Y()}let n=s(t);(!n?.isFile()||n.isSymbolicLink()||n.mode&3602||n.uid!==0&&n.uid!==process.getuid()||t===l&&!(n.mode&73))&&Y()}let t=0,n=new Set,r=e=>{++t>1e5&&Y();let i=s(e);if(!i)throw new g(`unsafe-state`);let a=O(e);if(a.startsWith(`${c}/`)||Y(),i.isSymbolicLink()){r(a);return}if(!n.has(a)){if(n.add(a),(i.uid!==0&&i.uid!==process.getuid()||i.mode&3602)&&Y(),i.isDirectory())for(let t of D(e))r(j(e,t));else i.isFile()||Y()}};for(let e of[`agent`,`runtime`])r(j(c,e))};p();let m=JSON.parse(a(j(c,`agent/package.json`),65536).toString(`utf8`));(m.name!==`shellbell`||typeof m.version!=`string`||!m.version||m.type!==`module`)&&Y();let h=S(j(c,`agent/package.json`));for(let e of Object.keys(m.dependencies??{}))O(h.resolve(e)).startsWith(`${c}/agent/`)||Y();let _=await n(`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,j(o,`Info.plist`)],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(_.exitCode!==0||JSON.parse(_.stdout.toString(`utf8`)).CFBundleShortVersionString!==m.version)&&Y();let v=await n(l,[`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(v.exitCode!==0||v.stdout.toString(`utf8`).trim()!==`v22.23.1`)&&Y();let y=await n(l,[`-p`,`process.platform + ':' + process.arch`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(y.exitCode!==0||y.stdout.toString(`utf8`).trim()!==`${process.platform}:${process.arch}`)&&Y();for(let e of[j(c,`agent/dist/cli.js`),u,d]){let t=await n(l,[e,`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(t.exitCode!==0||t.stdout.toString(`utf8`).trim()!==m.version)&&Y()}return i.revalidate(),p(),{executable:i.executable,nodePath:l,controllerPath:u,servicePath:d,agentVersion:m.version}}catch(e){if(e instanceof g)throw e;return Y()}}const Z=M.strictObject({v:M.literal(1),instance:M.uuid()});function ne(e,t){let n,r,i=new Promise((e,t)=>{n=e,r=t}),a=!1,o=!1,s=Buffer.alloc(0),c=setTimeout(()=>u(),t.timeoutMs??5e3),l=()=>{clearTimeout(c),e.off(`data`,d),e.off(`end`,u),e.off(`close`,u),e.off(`error`,u)},u=()=>{o||(o=!0,l(),r(new g(`unavailable`)),Promise.resolve().then(()=>t.onLost()).catch(()=>{}))},d=e=>{if(o)return;let r=Buffer.isBuffer(e)?e:Buffer.from(e);if(a||s.length+r.length>1024){u();return}s=Buffer.concat([s,r]);let i=s.indexOf(10);if(!(i<0))try{let e=Z.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.subarray(0,i))));if(i!==s.length-1||e.instance!==t.instance)throw Error();a=!0,s=Buffer.alloc(0),clearTimeout(c),n()}catch{u()}};return e.on(`data`,d),e.once(`end`,u),e.once(`close`,u),e.once(`error`,u),(e.destroyed||e.readableEnded)&&u(),{ready:i,close:u}}var Q=class extends d{constructor(e){super({...e,filename:`controller.json`,maxBytes:v,schema:x})}};function re(e,t,n){if(n.NODE_OPTIONS||n.NODE_PATH||!b.safeParse(e).success||!c.safeParse(t).success)throw new g(`unsafe-state`);return{...e.environment,HOME:t}}function $(t,n,r=!1){try{if(n<=0||!c.safeParse(t).success||[...t].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))throw Error();for(let e=t;;e=A(e)){let t=s(e);if(t&&(!t.isDirectory()||t.isSymbolicLink()))throw Error();if(A(e)===e)break}if(!s(t)){if(!r)return null;E(t,{recursive:!0,mode:448})}if(h(t,n),O(t)!==t)throw Error();let i=u(t);for(let e of[i.identity,i.pairings,i.config,i.pid])s(e)&&a(e,65536,n);ie(i.log,n);let o=s(i.sock);if(o&&(!o.isSocket()||o.uid!==n||(o.mode&4095)!=384))throw Error();return f(i),r?m(i):e(i)}catch{throw new g(`unsafe-state`)}}function ie(e,n){let r=s(e);if(!r)return;let i=e=>{if(!e.isFile()||e.isSymbolicLink()||e.uid!==n||(e.mode&4095)!=384)throw Error()};i(r);let a=ee(e,w.O_RDONLY|w.O_NOFOLLOW|w.O_NONBLOCK);try{let n=T(a);i(n);let o=s(e);if(!o||(i(o),!t(r,n)||!t(n,o)))throw Error()}finally{C(a)}}async function ae(e,t){let n=new Q(t).inspect()?.selection;if(!n||n.mode!==e||n.bundlePath!==t.bundlePath)throw new g(`conflict`);let r=$(n.stateDir,t.uid);if(!r||r.fp!==n.computerFp)throw new g(`unsafe-state`);if(e!==`desktop`)return t.start(n);let i=new l({stateDir:n.stateDir,uid:t.uid}).inspect();if(!t.ownerInput||i?.mode!==`desktop`||!i.consented||i.transition&&(i.transition.target!==`desktop`||![`source-stopped`,`destination-started`].includes(i.transition.phase)))throw new g(`conflict`);let a=!1,o,s,c=()=>s??=(async()=>{o&&await(await o).stop()})(),u=ne(t.ownerInput,{instance:n.serviceInstance,onLost:async()=>{a=!0;try{await c(),t.onOwnerLost?.(null)}catch(e){t.onOwnerLost?.(e)}}});try{if(await u.ready,a)throw new g(`unavailable`);if(o=t.start(n),await o,a)throw await c(),new g(`unavailable`);return{stop:async()=>{await c(),u.close()}}}catch(e){throw u.close(),e}}export{X as a,Q as i,ae as n,J as o,re as r,$ as t};