shellbell 0.7.0 → 0.8.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.7.0",
3
+ "version": "0.8.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,C as t,Ct as n,D as r,Dt as i,E as a,Et as o,O as s,T as c,Tt as l,c as u,ct as d,dt as f,f as p,i as m,k as h,lt as g,m as _,p as v,v as y,x as b,y as x}from"./service-lifecycle-CcyJ7m6L.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=l(t);if(e&&(!e.isDirectory()||e.isSymbolicLink())&&F(),A(t)===t)break}}function F(){throw new _(`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,t){return e===null||t===null?e===t:i(e.stat,t.stat)&&e.stat.mode===t.stat.mode&&e.stat.uid===t.stat.uid&&e.stat.size===t.stat.size&&e.stat.mtimeMs===t.stat.mtimeMs&&e.stat.ctimeMs===t.stat.ctimeMs&&e.raw.equals(t.raw)}function z(e,t){let r=j(e,`manual.plist`),a,s=i=>{try{if(P(e),!l(e))return null;o(e,t);let a=l(r);if(!a)return null;let s=n(r,65536,t);return s.equals(L(i))||F(),{stat:a,raw:s}}catch{return F()}},c=e=>{let t=s(e);return a!==void 0&&!R(a,t)&&F(),a=t,t};return{path:r,inspect(e){return c(e)!==null},write(n){let u=L(n),d=c(n);P(e),l(e)||E(e,{recursive:!0,mode:448});let p=o(e,t);f(r,u,()=>{P(e),(!i(p,o(e,t))||!R(d,s(n)))&&F()}),a=s(n),a?.raw.equals(u)||F()},remove(e){let t=c(e);t&&(R(t,s(e))||F(),k(r),a=null)}}}const B=`sh.bilal.shellbell.host.agent`,V=65536;function H(){throw new _(`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 _(i?`delivery-unknown`:`unavailable`)}}function G(e,t){return i(e,t)&&e.mode===t.mode&&e.uid===t.uid&&e.size===t.size&&e.mtimeMs===t.mtimeMs&&e.ctimeMs===t.ctimeMs}async function K(e,t,i=r){let a=U(e),o=j(e,`Contents`,`Info.plist`),s=new Map,c=()=>{P(A(e));for(let n of[e,j(e,`Contents`),j(e,`Contents`,`MacOS`),o,a]){let e=l(n),r=n===o||n===a;(!e||e.isSymbolicLink()||(r?!e.isFile():!e.isDirectory())||e.uid!==t&&e.uid!==0||e.mode&3602||n===a&&!(e.mode&73))&&H();let i=s.get(n);i&&!G(i,e)&&H(),s.set(n,e)}};try{c();let e=await W(i,`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,`-`],n(o,V));e.exitCode!==0&&H();let t=JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(e.stdout));return(t?.CFBundleIdentifier!==`sh.bilal.shellbell.host`||t?.CFBundleExecutable!==`Shellbell`)&&H(),c(),{executable:a,revalidate:c}}catch{return H()}}function q(e,t,n,r){let i;try{i=new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch{return H()}let a=i.trim().split(/\r?\n/).map(e=>e.trim());(a.shift()!==`${t} = {`||a.pop()!==`}`)&&H();let o=1,s,c=null,l=!1,u,d=!1;for(let e of a)if(e){if(e===`}`){o<=1&&H(),d&&o===2&&(d=!1),o--;continue}if(o===1&&e.startsWith(`program = `)){s!==void 0&&H(),s=e.slice(10);continue}if(o===1&&e.startsWith(`pid = `)){(l||!/^pid = [1-9][0-9]*$/.test(e))&&H(),l=!0,c=Number(e.slice(6)),(!Number.isSafeInteger(c)||c>2147483647)&&H();continue}if(o===1&&/^(?:pid|program|arguments)(?:\s|=)/.test(e)&&e!==`arguments = {`&&H(),e.endsWith(`= {`)){o===1&&e===`arguments = {`?(u!==void 0&&H(),u=[],d=!0):d&&H(),o++;continue}d&&o===2?u.push(e):(e.includes(`{`)||e.includes(`}`))&&H()}return(o!==1||s!==n||!u||u.length!==3||u[0]!==(r===`persistent`?`Shellbell`:n)||u[1]!==`--service-run`||u[2]!==r)&&H(),c}function J(e){let{root:n,uid:i,homeDir:o}=e;(!Number.isSafeInteger(i)||i<=0||!c.safeParse(n).success||!c.safeParse(o).success||n!==j(n)||o!==j(o))&&H();let u=j(o,`Library`,`LaunchAgents`);(n===u||n.startsWith(`${u}/`))&&H();let d=e.run??r,f=z(n,i),p=()=>e.legacy??a({run:d,uid:i,homeDir:o}),h=`gui/${i}`,g=e=>`${h}/${e===`manual`?N:B}`,v=e=>{b.safeParse(e).success||H()};async function x(e,t,n,r=`service`){let a=await K(e,i,d);await n?.(),a.revalidate();let o=t!==`status`,s=await W(d,a.executable,[r===`login`?`--login-api`:`--service-api`,t],void 0,o);a.revalidate();let c;try{c=y.parse(JSON.parse(new TextDecoder(`utf-8`,{fatal:!0}).decode(s.stdout)))}catch{throw new _(o?`delivery-unknown`:`unavailable`)}if(!c.ok)throw new _(c.error.code===`denied`?`approval-required`:c.error.code===`invalid-bundle`?`unsafe-state`:`operation-failed`);if(s.exitCode!==0)throw new _(o?`delivery-unknown`:`unavailable`);return c.status}async function S(e,t,n=1e4){let r=await W(d,`/bin/launchctl`,[`print`,g(e)],void 0,!1,n);if(r.exitCode===113)return{loaded:!1,pid:null};if(r.exitCode!==0)throw new _(`unavailable`);return{loaded:!0,pid:q(r.stdout,g(e),U(t),e)}}let C={loginStatus:e=>x(e,`status`,void 0,`login`),async setLogin(e,t){let n=await K(e,i,d),r=await W(d,`/usr/bin/codesign`,[`--verify`,`--strict`,e]);if(n.revalidate(),r.exitCode!==0)throw new _(`startup-unavailable`);let a=await x(e,`status`,void 0,`login`);if(a===`not-found`&&!t||a===`unknown`)throw new _(`startup-unavailable`);if(t?a===`enabled`||a===`requires-approval`:a===`not-registered`)return a;try{await x(e,t?`register`:`unregister`,void 0,`login`)}catch(n){if(!(t&&n instanceof _&&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 _(`operation-failed`);return o},async preflight(e,t){await s(d,i,o);let n=await K(t,i,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 _(`startup-unavailable`)}},async prepareManualRecovery(e){if(await s(d,i,o),v(e),t(e.mode)!==`persistent`&&H(),(await C.inspect(`persistent`,e.bundlePath)).loaded)throw new _(`conflict`);if((await W(d,`/bin/launchctl`,[`disable`,g(`persistent`)],void 0,!0)).exitCode!==0)throw new _(`operation-failed`);let n=await W(d,`/bin/launchctl`,[`print-disabled`,h]),r=new TextDecoder(`utf-8`,{fatal:!0}).decode(n.stdout).trim().split(/\r?\n/).map(e=>e.trim());if(n.exitCode!==0||r.shift()!==`disabled services = {`||r.pop()!==`}`||r.filter(e=>e.includes(`"${B}"`)).join(`
11
- `)!==`"${B}" => disabled`)throw new _(`operation-failed`);let a=await C.inspect(`persistent`,e.bundlePath);if(a.loaded)throw new _(`conflict`);a.registration!==`not-registered`&&a.registration!==`not-found`&&await C.stop(e,a)},inspectLegacy:()=>p().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=l(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(t(e.mode),e.bundlePath),(await C.inspect(t(e.mode),e.bundlePath)).loaded)throw new _(`conflict`);if(t(e.mode)===`persistent`){if((await W(d,`/bin/launchctl`,[`enable`,g(`persistent`)],void 0,!0)).exitCode!==0)throw new _(`operation-failed`);return{registration:await x(e.bundlePath,`register`,async()=>{if((await S(`persistent`,e.bundlePath)).loaded)throw new _(`conflict`)}),...await S(t(e.mode),e.bundlePath),bundlePath:e.bundlePath}}let n=await K(e.bundlePath,i,d);if(f.write(n.executable),(await S(`manual`,e.bundlePath)).loaded)throw new _(`conflict`);if(f.inspect(n.executable),n.revalidate(),(await W(d,`/bin/launchctl`,[`bootstrap`,h,f.path],void 0,!0)).exitCode!==0)throw new _(`operation-failed`);return C.inspect(`manual`,e.bundlePath)},async stop(e,n){v(e),n.bundlePath!==e.bundlePath&&H();let r=await C.inspect(t(e.mode),e.bundlePath);if(r.loaded!==n.loaded||r.pid!==n.pid||r.registration!==n.registration)throw new _(`conflict`);if(t(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 _(`conflict`)})!==`not-registered`)throw new _(`operation-failed`)}else if(r.loaded&&(f.inspect(U(e.bundlePath)),(await W(d,`/bin/launchctl`,[`bootout`,g(`manual`)],void 0,!0)).exitCode!==0))throw new _(`operation-failed`);let i=performance.now()+1e4;for(;;){let n=i-performance.now();if(n<=0)throw new _(`operation-failed`);let a=await S(t(e.mode),e.bundlePath,n);if(!a.loaded)break;if(a.pid!==null&&a.pid!==r.pid)throw new _(`conflict`);let o=Math.min(100,i-performance.now());if(o<=0)throw new _(`operation-failed`);await new Promise(e=>setTimeout(e,o))}},async remove(e){v(e);let n=await C.inspect(t(e.mode),e.bundlePath);if(n.loaded||t(e.mode)===`persistent`&&n.registration!==`not-registered`)throw new _(`conflict`);t(e.mode)===`manual`&&f.remove(U(e.bundlePath))},withLegacyGuard(e){return m(p(),!0,e)}};return C}const Y=()=>{throw new _(`unsafe-state`)};async function X(e,t={}){try{(O(e)!==e||[...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)===127))&&Y();let i=t.run??r,a=await K(e,process.getuid(),i),o=j(e,`Contents`),s=j(o,`Resources`),c=j(o,`Helpers/node`),u=j(s,`agent/dist/native-controller.js`),d=j(s,`agent/dist/native-service.js`),f=[c,u,d,j(s,`runtime/LICENSE`),j(s,`agent/package.json`),j(s,`agent/dist/cli.js`)],p=()=>{for(let t of f){for(let n=A(t);n!==e;n=A(n)){let e=l(n);(!e?.isDirectory()||e.isSymbolicLink()||e.mode&3602||e.uid!==0&&e.uid!==process.getuid())&&Y()}let n=l(t);(!n?.isFile()||n.isSymbolicLink()||n.mode&3602||n.uid!==0&&n.uid!==process.getuid()||t===c&&!(n.mode&73))&&Y()}let t=0,n=new Set,r=e=>{++t>1e5&&Y();let i=l(e);if(!i)throw new _(`unsafe-state`);let a=O(e);if(a.startsWith(`${s}/`)||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(s,e))};p();let m=JSON.parse(n(j(s,`agent/package.json`),65536).toString(`utf8`));(m.name!==`shellbell`||typeof m.version!=`string`||!m.version||m.type!==`module`)&&Y();let h=S(j(s,`agent/package.json`));for(let e of Object.keys(m.dependencies??{}))O(h.resolve(e)).startsWith(`${s}/agent/`)||Y();let g=await i(`/usr/bin/plutil`,[`-convert`,`json`,`-o`,`-`,j(o,`Info.plist`)],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(g.exitCode!==0||JSON.parse(g.stdout.toString(`utf8`)).CFBundleShortVersionString!==m.version)&&Y();let v=await i(c,[`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(v.exitCode!==0||v.stdout.toString(`utf8`).trim()!==`v22.23.1`)&&Y();let y=await i(c,[`-p`,`process.platform + ':' + process.arch`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(y.exitCode!==0||y.stdout.toString(`utf8`).trim()!==`${process.platform}:${process.arch}`)&&Y();for(let e of[j(s,`agent/dist/cli.js`),u,d]){let t=await i(c,[e,`--version`],{timeoutMs:1e4,maxOutputBytes:65536,captureOutput:!0});(t.exitCode!==0||t.stdout.toString(`utf8`).trim()!==m.version)&&Y()}return a.revalidate(),p(),{executable:a.executable,nodePath:c,controllerPath:u,servicePath:d,agentVersion:m.version}}catch(e){if(e instanceof _)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 _(`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 p{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 _(`unsafe-state`);return{...e.environment,HOME:t}}function $(t,r,i=!1){try{if(r<=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=l(e);if(t&&(!t.isDirectory()||t.isSymbolicLink()))throw Error();if(A(e)===e)break}if(!l(t)){if(!i)return null;E(t,{recursive:!0,mode:448})}if(o(t,r),O(t)!==t)throw Error();let a=d(t);for(let e of[a.identity,a.pairings,a.config,a.pid])l(e)&&n(e,65536,r);ie(a.log,r);let s=l(a.sock);if(s&&(!s.isSocket()||s.uid!==r||(s.mode&4095)!=384))throw Error();return g(a),i?h(a):e(a)}catch{throw new _(`unsafe-state`)}}function ie(e,t){let n=l(e);if(!n)return;let r=e=>{if(!e.isFile()||e.isSymbolicLink()||e.uid!==t||(e.mode&4095)!=384)throw Error()};r(n);let a=ee(e,w.O_RDONLY|w.O_NOFOLLOW|w.O_NONBLOCK);try{let t=T(a);r(t);let o=l(e);if(!o||(r(o),!i(n,t)||!i(t,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 _(`conflict`);let r=$(n.stateDir,t.uid);if(!r||r.fp!==n.computerFp)throw new _(`unsafe-state`);if(e!==`desktop`)return t.start(n);let i=new u({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 _(`conflict`);let a=!1,o,s,c=()=>s??=(async()=>{o&&await(await o).stop()})(),l=ne(t.ownerInput,{instance:n.serviceInstance,onLost:async()=>{a=!0;try{await c(),t.onOwnerLost?.(null)}catch(e){t.onOwnerLost?.(e)}}});try{if(await l.ready,a)throw new _(`unavailable`);if(o=t.start(n),await o,a)throw await c(),new _(`unavailable`);return{stop:async()=>{await c(),l.close()}}}catch(e){throw l.close(),e}}export{X as a,Q as i,ae as n,J as o,re as r,$ as t};