@bytetrue/byspace 0.14.6 → 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/commands/daemon/index.js +16 -0
- package/dist/commands/daemon/install-service.d.ts +15 -0
- package/dist/commands/daemon/install-service.js +69 -0
- package/dist/commands/daemon/local-daemon.d.ts +1 -0
- package/dist/commands/daemon/local-daemon.js +1 -1
- package/dist/commands/daemon/service/backend.d.ts +16 -0
- package/dist/commands/daemon/service/backend.js +50 -0
- package/dist/commands/daemon/service/launchd.d.ts +15 -0
- package/dist/commands/daemon/service/launchd.js +101 -0
- package/dist/commands/daemon/service/service-spec.d.ts +54 -0
- package/dist/commands/daemon/service/service-spec.js +95 -0
- package/dist/commands/daemon/service/service-status.d.ts +28 -0
- package/dist/commands/daemon/service/service-status.js +32 -0
- package/dist/commands/daemon/service/systemd.d.ts +22 -0
- package/dist/commands/daemon/service/systemd.js +90 -0
- package/dist/commands/daemon/service/windows-task.d.ts +12 -0
- package/dist/commands/daemon/service/windows-task.js +75 -0
- package/dist/commands/daemon/service-status.d.ts +13 -0
- package/dist/commands/daemon/service-status.js +30 -0
- package/dist/commands/daemon/uninstall-service.d.ts +11 -0
- package/dist/commands/daemon/uninstall-service.js +53 -0
- package/node_modules/@bytetrue/client/package.json +3 -3
- package/node_modules/@bytetrue/highlight/package.json +1 -1
- package/node_modules/@bytetrue/protocol/dist/generated/validation/ws-outbound.aot.js +10901 -10861
- package/node_modules/@bytetrue/protocol/dist/messages.d.ts +231 -92
- package/node_modules/@bytetrue/protocol/dist/messages.js +29 -0
- package/node_modules/@bytetrue/protocol/dist/validation/ws-outbound-schema-metadata.d.ts +44 -22
- package/node_modules/@bytetrue/protocol/package.json +1 -1
- package/node_modules/@bytetrue/relay/package.json +1 -1
- package/node_modules/@bytetrue/server/dist/server/server/byspace-env.d.ts +1 -0
- package/node_modules/@bytetrue/server/dist/server/server/byspace-env.js +9 -0
- package/node_modules/@bytetrue/server/dist/server/server/daemon-config-store.d.ts +11 -0
- package/node_modules/@bytetrue/server/dist/server/server/daemon-config-store.js +71 -1
- package/node_modules/@bytetrue/server/dist/server/server/session/daemon/daemon-service-install.d.ts +25 -0
- package/node_modules/@bytetrue/server/dist/server/server/session/daemon/daemon-service-install.js +182 -0
- package/node_modules/@bytetrue/server/dist/server/server/session/daemon/daemon-service-manager.d.ts +21 -0
- package/node_modules/@bytetrue/server/dist/server/server/session/daemon/daemon-service-manager.js +154 -0
- package/node_modules/@bytetrue/server/dist/server/server/websocket-server.js +2 -0
- package/node_modules/@bytetrue/server/dist/server/terminal/agent-hooks/pi/pi-extension.d.ts +1 -1
- package/node_modules/@bytetrue/server/dist/server/terminal/agent-hooks/pi/pi-extension.js +16 -1
- package/node_modules/@bytetrue/server/dist/server/terminal/terminal.js +6 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{index-679e8946b965f52a7a27dc9c54f59a4c.js → index-eade2661e21bbc08a50d56f1c6b0917a.js} +537 -535
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-eade2661e21bbc08a50d56f1c6b0917a.js.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-eade2661e21bbc08a50d56f1c6b0917a.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-d61d5dd974e90216cec99e62c343ffc7.js → indexeddb-attachment-store-a2e8491be0374dc2a52abfe002ecabe9.js} +1 -1
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-d61d5dd974e90216cec99e62c343ffc7.js.br → indexeddb-attachment-store-a2e8491be0374dc2a52abfe002ecabe9.js.br} +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-a2e8491be0374dc2a52abfe002ecabe9.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-df0c0ebe8d233a5a74eddb59a110f00b.js → native-file-attachment-store-6ba28513708667bbad7dd5434a0f8d5b.js} +3 -3
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-6ba28513708667bbad7dd5434a0f8d5b.js.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-6ba28513708667bbad7dd5434a0f8d5b.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/apple-touch-icon.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark-attention.9c2d51faf93468f68840811c0d9a8c6f.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark-running.a52155010955dca55546513b60bb2e2b.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark.ee7787d5c6bd1ad67c31b9949a832f7a.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light-attention.9c2d51faf93468f68840811c0d9a8c6f.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light-running.a52155010955dca55546513b60bb2e2b.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light.ee7787d5c6bd1ad67c31b9949a832f7a.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/notification-icon.ba5a7dce236a7febe5d803b16f027b70.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/favicon.ico +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/index.html +1 -1
- package/node_modules/@bytetrue/server/dist/server/web-ui/index.html.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/index.html.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/manifest.json +14 -2
- package/node_modules/@bytetrue/server/dist/server/web-ui/manifest.json.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/manifest.json.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/pwa-icon-192.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/pwa-icon-512.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/pwa-maskable-192.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/pwa-maskable-512.png +0 -0
- package/node_modules/@bytetrue/server/dist/src/server/byspace-env.js +9 -0
- package/node_modules/@bytetrue/server/dist/src/server/daemon-config-store.js +71 -1
- package/node_modules/@bytetrue/server/dist/src/server/session/daemon/daemon-service-install.js +182 -0
- package/node_modules/@bytetrue/server/dist/src/server/session/daemon/daemon-service-manager.js +154 -0
- package/node_modules/@bytetrue/server/dist/src/server/session/daemon/install-origin.js +64 -0
- package/node_modules/@bytetrue/server/dist/src/server/session/daemon/npm-global-cli.js +98 -0
- package/node_modules/@bytetrue/server/dist/src/terminal/terminal.js +6 -0
- package/node_modules/@bytetrue/server/package.json +15 -5
- package/package.json +7 -7
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-679e8946b965f52a7a27dc9c54f59a4c.js.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-679e8946b965f52a7a27dc9c54f59a4c.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-d61d5dd974e90216cec99e62c343ffc7.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-df0c0ebe8d233a5a74eddb59a110f00b.js.br +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-df0c0ebe8d233a5a74eddb59a110f00b.js.gz +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/node_modules/@bytetrue/server/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createIndexedDbAttachmentStore=function(){return{storageType:"web-indexeddb",async save(n){const o=n.id??(0,t.generateAttachmentId)(),s=Date.now(),{blob:c,mimeType:u}=await b(n),w=n.fileName??null,p=await l();try{await y(p,"readwrite",t=>t.put({id:o,blob:c,createdAt:s,fileName:w}))}finally{p.close()}return{id:o,mimeType:u,storageType:"web-indexeddb",storageKey:o,fileName:w,byteSize:c.size,createdAt:s}},async encodeBase64({attachment:n}){const o=await l();try{const s=await u(o,n.storageKey);return await(0,t.blobToBase64)(s)}finally{o.close()}},async resolvePreviewUrl({attachment:t}){const n=await l();try{const o=await u(n,t.storageKey);return URL.createObjectURL(o)}finally{n.close()}},async releasePreviewUrl({url:t}){URL.revokeObjectURL(t)},async delete({attachment:t}){const n=await l();try{await y(n,"readwrite",n=>n.delete(t.storageKey))}finally{n.close()}},async garbageCollect({referencedIds:t}){const n=await l();try{await new Promise((s,c)=>{const l=n.transaction(o,"readwrite"),y=l.objectStore(o).openCursor();y.addEventListener("error",()=>{c(y.error??new Error("Failed to iterate IndexedDB attachment store."))}),y.addEventListener("success",()=>{const n=y.result;if(!n)return void s();const o=String(n.key);t.has(o)||n.delete(),n.continue()}),l.addEventListener("error",()=>{c(l.error??new Error("Failed to garbage collect IndexedDB attachments."))})})}finally{n.close()}}}};var t=r(d[0]);const n="byspace-attachment-bytes",o="attachments",s=1;function c(){const t=globalThis.indexedDB;if(!t)throw new Error("IndexedDB is unavailable in this runtime.");return t}function l(){return new Promise((t,l)=>{const y=c().open(n,s);y.onupgradeneeded=()=>{const t=y.result;t.objectStoreNames.contains(o)||t.createObjectStore(o,{keyPath:"id"})},y.addEventListener("success",()=>{t(y.result)}),y.addEventListener("error",()=>{l(y.error??new Error("Failed to open attachment IndexedDB."))})})}function y(t,n,s){return new Promise((c,l)=>{const y=t.transaction(o,n),b=y.objectStore(o),u=s(b);u.addEventListener("success",()=>{c(u.result)}),u.addEventListener("error",()=>{l(u.error??new Error("IndexedDB transaction request failed."))}),y.addEventListener("error",()=>{l(y.error??new Error("IndexedDB transaction failed."))})})}async function b(n){const o=n.source;if("bytes"===o.kind){const s=(0,t.normalizeMimeType)(n.mimeType),c=new ArrayBuffer(o.bytes.byteLength);return new Uint8Array(c).set(o.bytes),{blob:new Blob([c],{type:s}),mimeType:s}}if("blob"===o.kind){const s=(0,t.normalizeMimeType)(n.mimeType??o.blob.type);return{blob:o.blob.type===s?o.blob:o.blob.slice(0,o.blob.size,s),mimeType:s}}if("data_url"===o.kind){const s=(0,t.parseDataUrl)(o.dataUrl),c=await fetch(o.dataUrl),l=await c.blob(),y=(0,t.normalizeMimeType)(n.mimeType??s.mimeType??l.type);return{blob:l.type===y?l:l.slice(0,l.size,y),mimeType:y}}const s=await fetch(o.uri),c=await s.blob(),l=(0,t.normalizeMimeType)(n.mimeType??c.type);return{blob:c.type===l?c:c.slice(0,c.size,l),mimeType:l}}async function u(t,n){const o=await y(t,"readonly",t=>t.get(n));if(!o?.blob)throw new Error(`Attachment ${n} was not found in IndexedDB.`);return o.blob}},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createIndexedDbAttachmentStore=function(){return{storageType:"web-indexeddb",async save(n){const o=n.id??(0,t.generateAttachmentId)(),s=Date.now(),{blob:c,mimeType:u}=await b(n),w=n.fileName??null,p=await l();try{await y(p,"readwrite",t=>t.put({id:o,blob:c,createdAt:s,fileName:w}))}finally{p.close()}return{id:o,mimeType:u,storageType:"web-indexeddb",storageKey:o,fileName:w,byteSize:c.size,createdAt:s}},async encodeBase64({attachment:n}){const o=await l();try{const s=await u(o,n.storageKey);return await(0,t.blobToBase64)(s)}finally{o.close()}},async resolvePreviewUrl({attachment:t}){const n=await l();try{const o=await u(n,t.storageKey);return URL.createObjectURL(o)}finally{n.close()}},async releasePreviewUrl({url:t}){URL.revokeObjectURL(t)},async delete({attachment:t}){const n=await l();try{await y(n,"readwrite",n=>n.delete(t.storageKey))}finally{n.close()}},async garbageCollect({referencedIds:t}){const n=await l();try{await new Promise((s,c)=>{const l=n.transaction(o,"readwrite"),y=l.objectStore(o).openCursor();y.addEventListener("error",()=>{c(y.error??new Error("Failed to iterate IndexedDB attachment store."))}),y.addEventListener("success",()=>{const n=y.result;if(!n)return void s();const o=String(n.key);t.has(o)||n.delete(),n.continue()}),l.addEventListener("error",()=>{c(l.error??new Error("Failed to garbage collect IndexedDB attachments."))})})}finally{n.close()}}}};var t=r(d[0]);const n="byspace-attachment-bytes",o="attachments",s=1;function c(){const t=globalThis.indexedDB;if(!t)throw new Error("IndexedDB is unavailable in this runtime.");return t}function l(){return new Promise((t,l)=>{const y=c().open(n,s);y.onupgradeneeded=()=>{const t=y.result;t.objectStoreNames.contains(o)||t.createObjectStore(o,{keyPath:"id"})},y.addEventListener("success",()=>{t(y.result)}),y.addEventListener("error",()=>{l(y.error??new Error("Failed to open attachment IndexedDB."))})})}function y(t,n,s){return new Promise((c,l)=>{const y=t.transaction(o,n),b=y.objectStore(o),u=s(b);u.addEventListener("success",()=>{c(u.result)}),u.addEventListener("error",()=>{l(u.error??new Error("IndexedDB transaction request failed."))}),y.addEventListener("error",()=>{l(y.error??new Error("IndexedDB transaction failed."))})})}async function b(n){const o=n.source;if("bytes"===o.kind){const s=(0,t.normalizeMimeType)(n.mimeType),c=new ArrayBuffer(o.bytes.byteLength);return new Uint8Array(c).set(o.bytes),{blob:new Blob([c],{type:s}),mimeType:s}}if("blob"===o.kind){const s=(0,t.normalizeMimeType)(n.mimeType??o.blob.type);return{blob:o.blob.type===s?o.blob:o.blob.slice(0,o.blob.size,s),mimeType:s}}if("data_url"===o.kind){const s=(0,t.parseDataUrl)(o.dataUrl),c=await fetch(o.dataUrl),l=await c.blob(),y=(0,t.normalizeMimeType)(n.mimeType??s.mimeType??l.type);return{blob:l.type===y?l:l.slice(0,l.size,y),mimeType:y}}const s=await fetch(o.uri),c=await s.blob(),l=(0,t.normalizeMimeType)(n.mimeType??c.type);return{blob:c.type===l?c:c.slice(0,c.size,l),mimeType:l}}async function u(t,n){const o=await y(t,"readonly",t=>t.get(n));if(!o?.blob)throw new Error(`Attachment ${n} was not found in IndexedDB.`);return o.blob}},4902,[4458]);
|
|
Binary file
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createNativeFileAttachmentStore=function(){return(0,s.createLocalFileAttachmentStore)({storageType:"native-file",baseDirectoryName:"byspace-native-attachments",fileSystem:(0,t.createExpoAttachmentFileSystem)(),resolvePreviewUrl:async t=>t.storageKey.startsWith("file://")?t.storageKey:(0,o.isAbsolutePath)(t.storageKey)?t.storageKey.startsWith("/")?`file://${t.storageKey}`:t.storageKey.startsWith("\\\\")?`file:${t.storageKey.replace(/\\/g,"/")}`:`file:///${t.storageKey.replace(/\\/g,"/")}`:t.storageKey})};var t=r(d[0]),s=r(d[1]),o=r(d[2])},
|
|
2
|
-
__d(function(g,r,i,a,m,_e,_d){"use strict";Object.defineProperty(_e,'__esModule',{value:!0}),_e.createExpoAttachmentFileSystem=function(){return{cacheDirectory:t.cacheDirectory,async getInfo(e){const n=await t.getInfoAsync(e);if(!n.exists)return{exists:!1};const c="number"==typeof n.size?n.size:null;return{exists:!0,isDirectory:n.isDirectory??!1,size:c}},async makeDirectory(e,n){await t.makeDirectoryAsync(e,n)},async writeBytes(t,n){new e.File(t).write(n)},async copy(e){await t.copyAsync(e)},readAsBase64:async e=>await t.readAsStringAsync(e,{encoding:t.EncodingType.Base64}),async delete(e,n){await t.deleteAsync(e,n)},listDirectory:async e=>await t.readDirectoryAsync(e)}};var e=r(_d[0]),t=(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach(function(n){var c=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,c.get?c:{enumerable:!0,get:function(){return e[n]}})}),t.default=e,t})(r(_d[1]))},
|
|
3
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createLocalFileAttachmentStore=function(n){const{fileSystem:o}=n,l=o.cacheDirectory?`${o.cacheDirectory}${n.baseDirectoryName}/`:null;async function u(n){if(!l)throw new Error("Attachment file-system cacheDirectory is unavailable.");await c(o,l);const y=n.id??(0,t.generateAttachmentId)();let f;f="data_url"===n.source.kind?(0,t.parseDataUrl)(n.source.dataUrl).mimeType:"blob"===n.source.kind?n.source.blob.type:void 0;const u=(0,t.normalizeMimeType)(n.mimeType??f),p=n.fileName??null,w=s({fileName:p,mimeType:u}),U=Date.now(),b=`${l}${y}${w}`;return{id:y,mimeType:u,fileName:p,createdAt:U,targetUri:b,storageKey:(0,t.fileUriToPath)(b)}}return Object.assign({storageType:n.storageType,async save(t){const s=await u(t);await y({fileSystem:o,source:t.source,targetUri:s.targetUri,mimeType:s.mimeType});const c=await o.getInfo(s.targetUri),l=c.exists?c.size:null;return{id:s.id,mimeType:s.mimeType,storageType:n.storageType,storageKey:s.storageKey,fileName:s.fileName,byteSize:l,createdAt:s.createdAt}},encodeBase64:async({attachment:t})=>await o.readAsBase64(f(t)),resolvePreviewUrl:async({attachment:t})=>await n.resolvePreviewUrl(t)},n.releasePreviewUrl?{async releasePreviewUrl(t){await(n.releasePreviewUrl?.(t))}}:{},{async delete({attachment:t}){await o.delete(f(t),{idempotent:!0})},async garbageCollect({referencedIds:t}){if(!l)return;await c(o,l);const n=await o.listDirectory(l);await Promise.all(n.map(async n=>{const s=n.split(".",1)[0]??"";s&&!t.has(s)&&await o.delete(`${l}${n}`,{idempotent:!0})}))}})};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(s){const c=(0,t.getFileExtensionFromName)(s.fileName);return c||(n[s.mimeType]??".img")}async function c(t,n){const s=await t.getInfo(n);s.exists&&s.isDirectory||await t.makeDirectory(n,{intermediates:!0})}async function o(t){const n=await fetch(t);return new Uint8Array(await n.arrayBuffer())}async function l(t){return new Uint8Array(await t.arrayBuffer())}async function y(n){if("file_uri"===n.source.kind){const s=(0,t.pathToFileUri)(n.source.uri);if(s===n.targetUri)return;return void await n.fileSystem.copy({from:s,to:n.targetUri})}let s;s="data_url"===n.source.kind?await o(n.source.dataUrl):"blob"===n.source.kind?await l(n.source.blob):n.source.bytes,await n.fileSystem.writeBytes(n.targetUri,s)}function f(n){return(0,t.pathToFileUri)(n.storageKey)}},
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createNativeFileAttachmentStore=function(){return(0,s.createLocalFileAttachmentStore)({storageType:"native-file",baseDirectoryName:"byspace-native-attachments",fileSystem:(0,t.createExpoAttachmentFileSystem)(),resolvePreviewUrl:async t=>t.storageKey.startsWith("file://")?t.storageKey:(0,o.isAbsolutePath)(t.storageKey)?t.storageKey.startsWith("/")?`file://${t.storageKey}`:t.storageKey.startsWith("\\\\")?`file:${t.storageKey.replace(/\\/g,"/")}`:`file:///${t.storageKey.replace(/\\/g,"/")}`:t.storageKey})};var t=r(d[0]),s=r(d[1]),o=r(d[2])},4903,[4904,4905,3675]);
|
|
2
|
+
__d(function(g,r,i,a,m,_e,_d){"use strict";Object.defineProperty(_e,'__esModule',{value:!0}),_e.createExpoAttachmentFileSystem=function(){return{cacheDirectory:t.cacheDirectory,async getInfo(e){const n=await t.getInfoAsync(e);if(!n.exists)return{exists:!1};const c="number"==typeof n.size?n.size:null;return{exists:!0,isDirectory:n.isDirectory??!1,size:c}},async makeDirectory(e,n){await t.makeDirectoryAsync(e,n)},async writeBytes(t,n){new e.File(t).write(n)},async copy(e){await t.copyAsync(e)},readAsBase64:async e=>await t.readAsStringAsync(e,{encoding:t.EncodingType.Base64}),async delete(e,n){await t.deleteAsync(e,n)},listDirectory:async e=>await t.readDirectoryAsync(e)}};var e=r(_d[0]),t=(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach(function(n){var c=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,c.get?c:{enumerable:!0,get:function(){return e[n]}})}),t.default=e,t})(r(_d[1]))},4904,[3830,3838]);
|
|
3
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createLocalFileAttachmentStore=function(n){const{fileSystem:o}=n,l=o.cacheDirectory?`${o.cacheDirectory}${n.baseDirectoryName}/`:null;async function u(n){if(!l)throw new Error("Attachment file-system cacheDirectory is unavailable.");await c(o,l);const y=n.id??(0,t.generateAttachmentId)();let f;f="data_url"===n.source.kind?(0,t.parseDataUrl)(n.source.dataUrl).mimeType:"blob"===n.source.kind?n.source.blob.type:void 0;const u=(0,t.normalizeMimeType)(n.mimeType??f),p=n.fileName??null,w=s({fileName:p,mimeType:u}),U=Date.now(),b=`${l}${y}${w}`;return{id:y,mimeType:u,fileName:p,createdAt:U,targetUri:b,storageKey:(0,t.fileUriToPath)(b)}}return Object.assign({storageType:n.storageType,async save(t){const s=await u(t);await y({fileSystem:o,source:t.source,targetUri:s.targetUri,mimeType:s.mimeType});const c=await o.getInfo(s.targetUri),l=c.exists?c.size:null;return{id:s.id,mimeType:s.mimeType,storageType:n.storageType,storageKey:s.storageKey,fileName:s.fileName,byteSize:l,createdAt:s.createdAt}},encodeBase64:async({attachment:t})=>await o.readAsBase64(f(t)),resolvePreviewUrl:async({attachment:t})=>await n.resolvePreviewUrl(t)},n.releasePreviewUrl?{async releasePreviewUrl(t){await(n.releasePreviewUrl?.(t))}}:{},{async delete({attachment:t}){await o.delete(f(t),{idempotent:!0})},async garbageCollect({referencedIds:t}){if(!l)return;await c(o,l);const n=await o.listDirectory(l);await Promise.all(n.map(async n=>{const s=n.split(".",1)[0]??"";s&&!t.has(s)&&await o.delete(`${l}${n}`,{idempotent:!0})}))}})};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(s){const c=(0,t.getFileExtensionFromName)(s.fileName);return c||(n[s.mimeType]??".img")}async function c(t,n){const s=await t.getInfo(n);s.exists&&s.isDirectory||await t.makeDirectory(n,{intermediates:!0})}async function o(t){const n=await fetch(t);return new Uint8Array(await n.arrayBuffer())}async function l(t){return new Uint8Array(await t.arrayBuffer())}async function y(n){if("file_uri"===n.source.kind){const s=(0,t.pathToFileUri)(n.source.uri);if(s===n.targetUri)return;return void await n.fileSystem.copy({from:s,to:n.targetUri})}let s;s="data_url"===n.source.kind?await o(n.source.dataUrl):"blob"===n.source.kind?await l(n.source.blob):n.source.bytes,await n.fileSystem.writeBytes(n.targetUri,s)}function f(n){return(0,t.pathToFileUri)(n.storageKey)}},4905,[4458]);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -86,6 +86,6 @@
|
|
|
86
86
|
<body>
|
|
87
87
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
88
88
|
<div id="root"></div>
|
|
89
|
-
<script src="/_expo/static/js/web/index-
|
|
89
|
+
<script src="/_expo/static/js/web/index-eade2661e21bbc08a50d56f1c6b0917a.js" defer></script>
|
|
90
90
|
</body>
|
|
91
91
|
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -15,13 +15,25 @@
|
|
|
15
15
|
"src": "/pwa-icon-192.png",
|
|
16
16
|
"sizes": "192x192",
|
|
17
17
|
"type": "image/png",
|
|
18
|
-
"purpose": "any
|
|
18
|
+
"purpose": "any"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"src": "/pwa-icon-512.png",
|
|
22
22
|
"sizes": "512x512",
|
|
23
23
|
"type": "image/png",
|
|
24
|
-
"purpose": "any
|
|
24
|
+
"purpose": "any"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"src": "/pwa-maskable-192.png",
|
|
28
|
+
"sizes": "192x192",
|
|
29
|
+
"type": "image/png",
|
|
30
|
+
"purpose": "maskable"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"src": "/pwa-maskable-512.png",
|
|
34
|
+
"sizes": "512x512",
|
|
35
|
+
"type": "image/png",
|
|
36
|
+
"purpose": "maskable"
|
|
25
37
|
}
|
|
26
38
|
]
|
|
27
39
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const BYSPACE_NODE_ENV = "BYSPACE_NODE_ENV";
|
|
2
2
|
const ELECTRON_RUN_AS_NODE = "ELECTRON_RUN_AS_NODE";
|
|
3
|
+
// Shared with the installed Pi extension (which cannot import from here).
|
|
4
|
+
export const PI_TERMINAL_HOOK_OWNER_PID_ENV_KEY = "BYSPACE_PI_TERMINAL_HOOK_OWNER_PID";
|
|
3
5
|
const RUNTIME_CONTROL_ENV_KEYS = [
|
|
4
6
|
BYSPACE_NODE_ENV,
|
|
5
7
|
"BYSPACE_DESKTOP_MANAGED",
|
|
@@ -7,6 +9,13 @@ const RUNTIME_CONTROL_ENV_KEYS = [
|
|
|
7
9
|
ELECTRON_RUN_AS_NODE,
|
|
8
10
|
"ELECTRON_NO_ATTACH_CONSOLE",
|
|
9
11
|
"ESBUILD_BINARY_PATH",
|
|
12
|
+
// Written into `process.env` by the Pi terminal-activity extension so child Pi
|
|
13
|
+
// processes do not register a second reporter for the same terminal. If it
|
|
14
|
+
// survives into a fresh terminal or agent, that Pi process sees a marker whose
|
|
15
|
+
// value is a stale pid, concludes it is an inherited child, and registers no
|
|
16
|
+
// handlers at all — the terminal then never reports running/idle. It is
|
|
17
|
+
// per-process state, never inherited. See docs/terminal-activity.md.
|
|
18
|
+
PI_TERMINAL_HOOK_OWNER_PID_ENV_KEY,
|
|
10
19
|
];
|
|
11
20
|
function buildInternalProcessEnv(baseEnv) {
|
|
12
21
|
return { ...baseEnv };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { loadPersistedConfig, savePersistedConfig, } from "./persisted-config.js";
|
|
2
2
|
import { hashDaemonPassword } from "./auth.js";
|
|
3
|
+
import { DAEMON_SERVICE_LABEL, queryDaemonServiceView, validateServiceOriginSync, } from "./session/daemon/daemon-service-manager.js";
|
|
4
|
+
import { buildServerServiceSpec, installLaunchdServiceServer, installSystemdServiceServer, uninstallLaunchdServiceServer, uninstallSystemdServiceServer, uninstallWindowsTaskServer, } from "./session/daemon/daemon-service-install.js";
|
|
3
5
|
import { isLanListenString } from "./hostnames.js";
|
|
4
6
|
import { ProviderOverrideSchema } from "./agent/provider-launch-config.js";
|
|
5
7
|
import { MutableDaemonConfigSchema, MutableDaemonConfigPatchSchema, TERMINAL_AGENT_HOOK_LEGACY_GLOBAL_PROVIDER_IDS, TERMINAL_AGENT_HOOK_PROVIDER_IDS, } from "@bytetrue/protocol/messages";
|
|
@@ -183,6 +185,7 @@ function pickSupportedPatchFields(patch) {
|
|
|
183
185
|
...(patch.pluginsEnabled !== undefined ? { pluginsEnabled: patch.pluginsEnabled } : {}),
|
|
184
186
|
...(patch.plugins !== undefined ? { plugins: patch.plugins } : {}),
|
|
185
187
|
...pickNetworkAuthPatchFields(patch),
|
|
188
|
+
...(patch.service !== undefined ? { service: patch.service } : {}),
|
|
186
189
|
};
|
|
187
190
|
}
|
|
188
191
|
function pickNetworkAuthPatchFields(patch) {
|
|
@@ -285,6 +288,9 @@ export class DaemonConfigStore {
|
|
|
285
288
|
this.startupPersisted =
|
|
286
289
|
options.startupPersisted ?? loadPersistedConfig(byspaceHome, this.logger);
|
|
287
290
|
this.lastKnownPersisted = this.startupPersisted;
|
|
291
|
+
// Service view is probed, not persisted: refresh it once at construction so the
|
|
292
|
+
// first server_info carries a real state, then again after each service patch.
|
|
293
|
+
this.refreshServiceRuntimeState();
|
|
288
294
|
}
|
|
289
295
|
get() {
|
|
290
296
|
return this.current;
|
|
@@ -303,7 +309,14 @@ export class DaemonConfigStore {
|
|
|
303
309
|
// The network/auth patch never lands in the mutable view verbatim: the
|
|
304
310
|
// plaintext password and listen semantics are translated below, and only
|
|
305
311
|
// the derived view fields (allowLanAccess / passwordSet) surface to clients.
|
|
306
|
-
const { removeProviders = [], network: networkPatch, auth: authPatch, ...rawConfigPatch } = parsedPatch;
|
|
312
|
+
const { removeProviders = [], network: networkPatch, auth: authPatch, service: servicePatch, ...rawConfigPatch } = parsedPatch;
|
|
313
|
+
// Service install is a side effect, not config state: it runs the OS service
|
|
314
|
+
// registration and the resulting view refresh arrives via the service probe.
|
|
315
|
+
if (servicePatch?.install !== undefined) {
|
|
316
|
+
this.applyServicePatch(servicePatch.install);
|
|
317
|
+
// Re-probe after the side effect so the response carries the new state.
|
|
318
|
+
this.refreshServiceRuntimeState();
|
|
319
|
+
}
|
|
307
320
|
let daemonPersistedPatch = null;
|
|
308
321
|
let networkViewPatch = {};
|
|
309
322
|
const resolved = this.resolveDaemonNetworkPatch(networkPatch, authPatch);
|
|
@@ -417,6 +430,63 @@ export class DaemonConfigStore {
|
|
|
417
430
|
});
|
|
418
431
|
this.applyReplacement(next, { removedProviders: [] });
|
|
419
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Re-probe the OS service manager and refresh the derived service view. Never
|
|
435
|
+
* persists: the service state is a property of the host, not of config.json.
|
|
436
|
+
*/
|
|
437
|
+
refreshServiceRuntimeState() {
|
|
438
|
+
let view;
|
|
439
|
+
try {
|
|
440
|
+
view = queryDaemonServiceView();
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
// The service-manager probe is host-dependent (launchctl/systemctl may be
|
|
444
|
+
// absent, e.g. unit tests or containers); leave the view out rather than
|
|
445
|
+
// failing every config operation.
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const next = MutableDaemonConfigSchema.parse({
|
|
449
|
+
...this.current,
|
|
450
|
+
service: view,
|
|
451
|
+
});
|
|
452
|
+
if (JSON.stringify(next) === JSON.stringify(this.current))
|
|
453
|
+
return;
|
|
454
|
+
this.applyReplacement(next, { removedProviders: [] });
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Execute a service install/uninstall (issue 043). Install/uninstall are side
|
|
458
|
+
* effects on the OS service manager, never config state: the mutable view stays
|
|
459
|
+
* untouched and the service view is re-probed on demand.
|
|
460
|
+
*/
|
|
461
|
+
applyServicePatch(install) {
|
|
462
|
+
if (install) {
|
|
463
|
+
// The same npm-global guard the CLI enforces: a service must point at the
|
|
464
|
+
// published install, not a dev checkout or container filesystem. The daemon
|
|
465
|
+
// process runs the check because it owns the install-origin context.
|
|
466
|
+
const originError = validateServiceOriginSync();
|
|
467
|
+
if (originError)
|
|
468
|
+
throw new Error(originError);
|
|
469
|
+
const spec = buildServerServiceSpec(this.byspaceHome);
|
|
470
|
+
if (process.platform === "darwin") {
|
|
471
|
+
installLaunchdServiceServer(spec);
|
|
472
|
+
}
|
|
473
|
+
else if (process.platform === "linux") {
|
|
474
|
+
installSystemdServiceServer(spec);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
throw new Error("Service installation is not supported on this platform (expected macOS or Linux).");
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
else if (process.platform === "darwin") {
|
|
481
|
+
uninstallLaunchdServiceServer(DAEMON_SERVICE_LABEL);
|
|
482
|
+
}
|
|
483
|
+
else if (process.platform === "linux") {
|
|
484
|
+
uninstallSystemdServiceServer(DAEMON_SERVICE_LABEL);
|
|
485
|
+
}
|
|
486
|
+
else if (process.platform === "win32") {
|
|
487
|
+
uninstallWindowsTaskServer(DAEMON_SERVICE_LABEL);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
420
490
|
reload() {
|
|
421
491
|
if (!this.reloadSource) {
|
|
422
492
|
throw new Error("Daemon config reload is unavailable for this daemon instance");
|
package/node_modules/@bytetrue/server/dist/src/server/session/daemon/daemon-service-install.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolveBySpaceHome } from "../../byspace-home.js";
|
|
6
|
+
export function buildServerServiceSpec(home) {
|
|
7
|
+
const env = {};
|
|
8
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
9
|
+
if (key.startsWith("BYSPACE_") && value !== undefined)
|
|
10
|
+
env[key] = value;
|
|
11
|
+
}
|
|
12
|
+
env.PATH = process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
|
13
|
+
return {
|
|
14
|
+
label: "cc.cd.byspace.daemon",
|
|
15
|
+
nodePath: process.execPath,
|
|
16
|
+
// The running daemon knows its own entry: the supervisor entry resolved this
|
|
17
|
+
// process. Use the daemon-worker path via the server package root.
|
|
18
|
+
runnerEntry: resolveSelfRunnerEntry(),
|
|
19
|
+
logPath: path.join(home, "daemon.log"),
|
|
20
|
+
env,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function resolveSelfRunnerEntry() {
|
|
24
|
+
// Walk up from this module to the @bytetrue/server package root (name-checked, so
|
|
25
|
+
// it works under both src/ (tsx) and dist/ (compiled) tree shapes), then locate the
|
|
26
|
+
// supervisor entrypoint the way the CLI's resolveDaemonRunnerEntry does.
|
|
27
|
+
const here = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
let dir = here;
|
|
29
|
+
let packageRoot = null;
|
|
30
|
+
for (let i = 0; i < 12; i += 1) {
|
|
31
|
+
const pkgPath = path.join(dir, "package.json");
|
|
32
|
+
if (existsSync(pkgPath)) {
|
|
33
|
+
const parsed = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
34
|
+
if (parsed.name === "@bytetrue/server") {
|
|
35
|
+
packageRoot = dir;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const parent = path.dirname(dir);
|
|
40
|
+
if (parent === dir)
|
|
41
|
+
break;
|
|
42
|
+
dir = parent;
|
|
43
|
+
}
|
|
44
|
+
if (!packageRoot) {
|
|
45
|
+
throw new Error("Unable to locate the @bytetrue/server package root from the daemon module");
|
|
46
|
+
}
|
|
47
|
+
const distRunner = path.join(packageRoot, "dist", "scripts", "supervisor-entrypoint.js");
|
|
48
|
+
if (existsSync(distRunner))
|
|
49
|
+
return distRunner;
|
|
50
|
+
const srcRunner = path.join(packageRoot, "scripts", "supervisor-entrypoint.ts");
|
|
51
|
+
if (existsSync(srcRunner))
|
|
52
|
+
return srcRunner;
|
|
53
|
+
throw new Error("Unable to locate the supervisor entrypoint in the server package");
|
|
54
|
+
}
|
|
55
|
+
function escapeXml(value) {
|
|
56
|
+
return value
|
|
57
|
+
.replace(/&/g, "&")
|
|
58
|
+
.replace(/</g, "<")
|
|
59
|
+
.replace(/>/g, ">")
|
|
60
|
+
.replace(/"/g, """);
|
|
61
|
+
}
|
|
62
|
+
export function renderLaunchdPlist(spec) {
|
|
63
|
+
const programArgs = [spec.nodePath, spec.runnerEntry];
|
|
64
|
+
const args = programArgs.map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
|
|
65
|
+
const envEntries = Object.entries(spec.env)
|
|
66
|
+
.map(([key, value]) => ` <key>${escapeXml(key)}</key>\n <string>${escapeXml(value)}</string>`)
|
|
67
|
+
.join("\n");
|
|
68
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
69
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
70
|
+
<plist version="1.0">
|
|
71
|
+
<dict>
|
|
72
|
+
<key>Label</key>
|
|
73
|
+
<string>${escapeXml(spec.label)}</string>
|
|
74
|
+
<key>ProgramArguments</key>
|
|
75
|
+
<array>
|
|
76
|
+
${args}
|
|
77
|
+
</array>
|
|
78
|
+
<key>EnvironmentVariables</key>
|
|
79
|
+
<dict>
|
|
80
|
+
${envEntries}
|
|
81
|
+
</dict>
|
|
82
|
+
<key>RunAtLoad</key>
|
|
83
|
+
<true/>
|
|
84
|
+
<key>KeepAlive</key>
|
|
85
|
+
<false/>
|
|
86
|
+
<key>StandardOutPath</key>
|
|
87
|
+
<string>${escapeXml(spec.logPath)}</string>
|
|
88
|
+
<key>StandardErrorPath</key>
|
|
89
|
+
<string>${escapeXml(spec.logPath)}</string>
|
|
90
|
+
<key>ProcessType</key>
|
|
91
|
+
<string>Background</string>
|
|
92
|
+
</dict>
|
|
93
|
+
</plist>
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
function launchctl(args) {
|
|
97
|
+
const result = spawnSync("launchctl", args, { encoding: "utf8", timeout: 15000 });
|
|
98
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
99
|
+
return { ok: result.status === 0, output };
|
|
100
|
+
}
|
|
101
|
+
/** Write the plist and load it. The daemon exits after install; launchd takes over. */
|
|
102
|
+
export function installLaunchdServiceServer(spec) {
|
|
103
|
+
const home = resolveBySpaceHome();
|
|
104
|
+
const plistPath = path.join(home, "Library", "LaunchAgents", `${spec.label}.plist`);
|
|
105
|
+
mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
106
|
+
writeFileSync(plistPath, renderLaunchdPlist(spec), { mode: 0o644 });
|
|
107
|
+
const uid = process.getuid?.();
|
|
108
|
+
if (uid === undefined)
|
|
109
|
+
throw new Error("cannot resolve uid for launchctl bootstrap");
|
|
110
|
+
launchctl(["bootout", `gui/${uid}/${spec.label}`]);
|
|
111
|
+
const boot = launchctl(["bootstrap", `gui/${String(uid)}`, plistPath]);
|
|
112
|
+
if (!boot.ok) {
|
|
113
|
+
throw new Error(`launchctl bootstrap failed: ${boot.output}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Stop and remove the service definition. The daemon keeps running until stopped. */
|
|
117
|
+
export function uninstallLaunchdServiceServer(label) {
|
|
118
|
+
const uid = process.getuid?.();
|
|
119
|
+
if (uid !== undefined) {
|
|
120
|
+
launchctl(["bootout", `gui/${uid}/${label}`]);
|
|
121
|
+
}
|
|
122
|
+
const home = resolveBySpaceHome();
|
|
123
|
+
rmSync(path.join(home, "Library", "LaunchAgents", `${label}.plist`), { force: true });
|
|
124
|
+
}
|
|
125
|
+
export function installSystemdServiceServer(spec) {
|
|
126
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path.join(process.env.HOME ?? "", ".config");
|
|
127
|
+
const unitPath = path.join(configHome, "systemd", "user", `${spec.label}.service`);
|
|
128
|
+
mkdirSync(path.dirname(unitPath), { recursive: true });
|
|
129
|
+
writeFileSync(unitPath, renderSystemdUnit(spec), { mode: 0o644 });
|
|
130
|
+
const run = (args) => {
|
|
131
|
+
const result = spawnSync("systemctl", ["--user", ...args], {
|
|
132
|
+
encoding: "utf8",
|
|
133
|
+
timeout: 20000,
|
|
134
|
+
});
|
|
135
|
+
if (result.status !== 0) {
|
|
136
|
+
throw new Error(`systemctl --user ${args[0]} failed: ${result.stderr ?? result.stdout ?? ""}`);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
run(["daemon-reload"]);
|
|
140
|
+
run(["enable", "--now", `${spec.label}.service`]);
|
|
141
|
+
}
|
|
142
|
+
function renderSystemdUnit(spec) {
|
|
143
|
+
const execStart = [spec.nodePath, spec.runnerEntry]
|
|
144
|
+
.map((part) => part.replace(/([\\"])/g, "\\$1"))
|
|
145
|
+
.join(" ");
|
|
146
|
+
const envLines = Object.entries(spec.env)
|
|
147
|
+
.map(([key, value]) => `Environment="${key}=${value.replace(/([\\"])/g, "\\$1")}"`)
|
|
148
|
+
.join("\n");
|
|
149
|
+
return `# Generated by the BySpace daemon (install-service). Edits are overwritten on reinstall.
|
|
150
|
+
[Unit]
|
|
151
|
+
Description=BySpace daemon
|
|
152
|
+
After=network-online.target
|
|
153
|
+
|
|
154
|
+
[Service]
|
|
155
|
+
Type=exec
|
|
156
|
+
ExecStart=${execStart}
|
|
157
|
+
${envLines}
|
|
158
|
+
Restart=on-failure
|
|
159
|
+
RestartSec=5
|
|
160
|
+
|
|
161
|
+
[Install]
|
|
162
|
+
WantedBy=default.target
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
export function uninstallSystemdServiceServer(label) {
|
|
166
|
+
const run = (args) => {
|
|
167
|
+
spawnSync("systemctl", ["--user", ...args], { encoding: "utf8", timeout: 20000 });
|
|
168
|
+
};
|
|
169
|
+
run(["disable", "--now", `${label}.service`]);
|
|
170
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path.join(process.env.HOME ?? "", ".config");
|
|
171
|
+
rmSync(path.join(configHome, "systemd", "user", `${label}.service`), { force: true });
|
|
172
|
+
run(["daemon-reload"]);
|
|
173
|
+
}
|
|
174
|
+
export function uninstallWindowsTaskServer(label) {
|
|
175
|
+
spawnSync("powershell.exe", [
|
|
176
|
+
"-NoProfile",
|
|
177
|
+
"-NonInteractive",
|
|
178
|
+
"-Command",
|
|
179
|
+
`Unregister-ScheduledTask -TaskPath '\\BySpace\\' -TaskName '${label}' -Confirm:$false -ErrorAction SilentlyContinue`,
|
|
180
|
+
], { encoding: "utf8", timeout: 30000 });
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=daemon-service-install.js.map
|
package/node_modules/@bytetrue/server/dist/src/server/session/daemon/daemon-service-manager.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { BYSPACE_CLI_PACKAGE } from "./npm-global-cli.js";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { validateDaemonInstallOrigin, daemonInstallOriginRuntime } from "./install-origin.js";
|
|
6
|
+
/**
|
|
7
|
+
* Daemon-side OS service management (issue 043). The daemon manages its own service
|
|
8
|
+
* registration because install requires the daemon's install-origin context — the
|
|
9
|
+
* npm-global verification and the runner entry resolution live in this process.
|
|
10
|
+
*
|
|
11
|
+
* KeepAlive/Restart is deliberately not "always": `byspace daemon stop` must stay a
|
|
12
|
+
* real stop. The supervisor's own crash-restart handles worker failures.
|
|
13
|
+
*/
|
|
14
|
+
export const DAEMON_SERVICE_LABEL = "cc.cd.byspace.daemon";
|
|
15
|
+
function launchdProbe(home) {
|
|
16
|
+
const plistPath = path.join(home, "Library", "LaunchAgents", `${DAEMON_SERVICE_LABEL}.plist`);
|
|
17
|
+
return {
|
|
18
|
+
definitionExists: () => existsSync(plistPath),
|
|
19
|
+
servicePid: () => {
|
|
20
|
+
try {
|
|
21
|
+
const uid = process.getuid?.();
|
|
22
|
+
if (uid === undefined)
|
|
23
|
+
return null;
|
|
24
|
+
const output = execFileSync("launchctl", ["print", `gui/${uid}/${DAEMON_SERVICE_LABEL}`], {
|
|
25
|
+
encoding: "utf8",
|
|
26
|
+
timeout: 10000,
|
|
27
|
+
});
|
|
28
|
+
const match = output.match(/^\s*pid\s*=\s*(\d+)/m);
|
|
29
|
+
return match ? Number(match[1]) : null;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
viewFlags: () => ({}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function systemdProbe() {
|
|
39
|
+
const configHome = process.env.XDG_CONFIG_HOME ?? path.join(process.env.HOME ?? "", ".config");
|
|
40
|
+
const unitPath = path.join(configHome, "systemd", "user", `${DAEMON_SERVICE_LABEL}.service`);
|
|
41
|
+
return {
|
|
42
|
+
definitionExists: () => existsSync(unitPath),
|
|
43
|
+
servicePid: () => {
|
|
44
|
+
try {
|
|
45
|
+
const output = execFileSync("systemctl", ["--user", "show", `${DAEMON_SERVICE_LABEL}.service`, "--property", "MainPID"], { encoding: "utf8", timeout: 10000 });
|
|
46
|
+
const match = output.match(/^MainPID=(\d+)$/m);
|
|
47
|
+
const pid = match ? Number(match[1]) : 0;
|
|
48
|
+
return pid > 0 ? pid : null;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
viewFlags: () => {
|
|
55
|
+
try {
|
|
56
|
+
const output = execFileSync("loginctl", ["show-user", process.env.USER ?? "", "--property", "Linger"], { encoding: "utf8", timeout: 10000 });
|
|
57
|
+
return { linger: /Linger=yes/.test(output) };
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function windowsProbe() {
|
|
66
|
+
return {
|
|
67
|
+
definitionExists: () => {
|
|
68
|
+
try {
|
|
69
|
+
const output = execFileSync("powershell.exe", [
|
|
70
|
+
"-NoProfile",
|
|
71
|
+
"-NonInteractive",
|
|
72
|
+
"-Command",
|
|
73
|
+
`(Get-ScheduledTask -TaskPath '\\BySpace\\' -TaskName '${DAEMON_SERVICE_LABEL}' -ErrorAction SilentlyContinue) -ne $null`,
|
|
74
|
+
], { encoding: "utf8", timeout: 15000 });
|
|
75
|
+
return output.trim() === "True";
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
servicePid: () => null,
|
|
82
|
+
viewFlags: () => ({}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function probeForPlatform() {
|
|
86
|
+
switch (process.platform) {
|
|
87
|
+
case "darwin":
|
|
88
|
+
return launchdProbe(resolveBySpaceHomeForService());
|
|
89
|
+
case "linux":
|
|
90
|
+
return systemdProbe();
|
|
91
|
+
case "win32":
|
|
92
|
+
return windowsProbe();
|
|
93
|
+
default:
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function resolveBySpaceHomeForService() {
|
|
98
|
+
return process.env.BYSPACE_HOME ?? path.join(process.env.HOME ?? "", ".byspace");
|
|
99
|
+
}
|
|
100
|
+
/** Guard: only a daemon from the published npm global install may self-register. */
|
|
101
|
+
export function validateServiceOriginSync() {
|
|
102
|
+
if (existsSync("/.dockerenv") || existsSync("/run/.containerenv")) {
|
|
103
|
+
return "Registering a service is not supported inside Docker. Use the container runtime's restart policy instead.";
|
|
104
|
+
}
|
|
105
|
+
// The npm -g listing is the authoritative origin: it proves the published install
|
|
106
|
+
// exists on this host. validateDaemonInstallOrigin then checks that THIS daemon
|
|
107
|
+
// process actually runs from it — a dev checkout parses fine but fails the
|
|
108
|
+
// package-root containment check, which is exactly the guard that matters here.
|
|
109
|
+
try {
|
|
110
|
+
const npmPrefix = execFileSync("npm", ["prefix", "-g"], {
|
|
111
|
+
encoding: "utf8",
|
|
112
|
+
timeout: 15000,
|
|
113
|
+
}).trim();
|
|
114
|
+
const packagePath = path.join(npmPrefix, "lib", "node_modules", "@bytetrue", "byspace");
|
|
115
|
+
const pkgJsonPath = path.join(packagePath, "package.json");
|
|
116
|
+
if (!existsSync(pkgJsonPath)) {
|
|
117
|
+
return `${BYSPACE_CLI_PACKAGE} is not installed with npm -g on this host`;
|
|
118
|
+
}
|
|
119
|
+
const version = JSON.parse(readFileSync(pkgJsonPath, "utf8")).version ?? "";
|
|
120
|
+
const install = {
|
|
121
|
+
version,
|
|
122
|
+
packagePath,
|
|
123
|
+
globalRootPath: npmPrefix,
|
|
124
|
+
isLinked: false,
|
|
125
|
+
};
|
|
126
|
+
return validateDaemonInstallOrigin(install, process.env.npm_package_version ?? version, daemonInstallOriginRuntime);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
return error instanceof Error ? error.message : String(error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Query the current service view. Never caches: each call re-probes the manager. */
|
|
133
|
+
export function queryDaemonServiceView() {
|
|
134
|
+
const probe = probeForPlatform();
|
|
135
|
+
if (!probe) {
|
|
136
|
+
return { state: "unknown", label: DAEMON_SERVICE_LABEL };
|
|
137
|
+
}
|
|
138
|
+
if (!probe.definitionExists()) {
|
|
139
|
+
return { state: "not-installed", label: DAEMON_SERVICE_LABEL, ...probe.viewFlags() };
|
|
140
|
+
}
|
|
141
|
+
const servicePid = probe.servicePid();
|
|
142
|
+
if (servicePid === null) {
|
|
143
|
+
return { state: "installed-stopped", label: DAEMON_SERVICE_LABEL, ...probe.viewFlags() };
|
|
144
|
+
}
|
|
145
|
+
if (servicePid === process.pid) {
|
|
146
|
+
return { state: "managed-by-service", label: DAEMON_SERVICE_LABEL, ...probe.viewFlags() };
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
state: "installed-running-not-this-process",
|
|
150
|
+
label: DAEMON_SERVICE_LABEL,
|
|
151
|
+
...probe.viewFlags(),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=daemon-service-manager.js.map
|