@aitty/server 0.1.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.
@@ -0,0 +1,4780 @@
1
+ //#region node_modules/.pnpm/@wterm+core@0.1.9/node_modules/@wterm/core/dist/wasm-inline.js
2
+ const WASM_BASE64 = "AGFzbQEAAAABMAlgAAF/YAAAYAF/AX9gAX8AYAJ/fwBgBH9/f38AYAN/f38AYAJ/fwF/YAN/f38BfwMwLwAAAAAAAQAAAgICAAAAAAAAAAAAAAAAAQAAAwMEBAUFBQYHAQYBAQQIBAQDAAQEBAUBcAEBAQUDAQBYBgkBfwFBgIDAAAsH7wMfBm1lbW9yeQIACmdldE1heENvbHMAAAtnZXRDZWxsU2l6ZQABDmdldERlYnVnTG9nTWF4AAIUZ2V0RGVidWdMb2dFbnRyeVNpemUAARBnZXREZWJ1Z0xvZ0NvdW50AAMOZ2V0RGVidWdMb2dQdHIABA1jbGVhclJlc3BvbnNlAAUOZ2V0UmVzcG9uc2VMZW4ABg5nZXRSZXNwb25zZVB0cgAHFGdldFNjcm9sbGJhY2tMaW5lTGVuAAgRZ2V0U2Nyb2xsYmFja0xpbmUAChJnZXRTY3JvbGxiYWNrQ291bnQACw9nZXRUaXRsZUNoYW5nZWQADAtnZXRUaXRsZUxlbgANC2dldFRpdGxlUHRyAA4RZ2V0VXNpbmdBbHRTY3JlZW4ADxFnZXRCcmFja2V0ZWRQYXN0ZQAQEGdldEN1cnNvcktleXNBcHAAEQdnZXRSb3dzABIHZ2V0Q29scwATEGdldEN1cnNvclZpc2libGUAFAxnZXRDdXJzb3JDb2wAFQxnZXRDdXJzb3JSb3cAFgpjbGVhckRpcnR5ABcLZ2V0RGlydHlQdHIAGApnZXRHcmlkUHRyABkKd3JpdGVCeXRlcwAaDmdldFdyaXRlQnVmZmVyACwOcmVzaXplVGVybWluYWwALQRpbml0AC4K+V8vBQBBgAILBABBDAsEAEEgCwsAQQAoAuSEwIAACwgAQfSG8IAACw0AQQBBADoA2IzwgAALCwBBAC0A2IzwgAALCABBmIzwgAALGgACQCAAEImAgIAAIgANAEEADwsgAC8BgBgLXAECf0EAIQECQCAAQQAoAvyFrIIAIgJPDQACQAJAIAJB6AdPDQAgAiAAQX9zaiEADAELQQAoAoCGrIIAIABrQecHakHoB3AhAAsgAEGEGGxB3KbwgABqIQELIAELFQAgABCJgICAACIAQdyO8IAAIAAbCwsAQQAoAvyFrIIACygBAX9BACEAAkBBAC0Al4zwgABFDQBBAEEAOgCXjPCAAEEBIQALIAALCwBBAC8B/InwgAALCABBlorwgAALCwBBAC0AlYrwgAALCwBBAC0AkIrwgAALCwBBAC0AkYrwgAALCwBBAC8B7obwgAALCwBBAC8B7IbwgAALCwBBAC0A24zwgAALCwBBAC8B8obwgAALCwBBAC8B8IbwgAALNwECf0EALwHqhPCAACEAQQAhAQJAA0AgACABRg0BIAFB7ITwgABqQQA6AAAgAUEBaiEBDAALCwsIAEHshPCAAAsIAEHohMCAAAvVOwMFfwF+Bn8jgICAgABBwABrIgEkgICAgAAgAEGAwAAgAEGAwABJGyECQZyAwIAAQQJqIQNBACEAA0ACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgACACRg0AAkACQAJAAkACQAJAAkACQAJAAkACQCAALQCEhqyCACIEQWhqDgQCAQIAAQtBAC0AwoDAgAAhBEEAQQI6AMKAwIAAIARBB3FBB0YNA0EAQQA7AdiAwIAADCcLAkACQAJAAkACQAJAQQAtAMKAwIAAQQdxDggLAAECAwQFBwsLIATAQb9/Sg0JQQAtAN+EwIAAQQAtAN6EwIAAa0EHcUHahMCAAGogBDoAAEEAQQAtAN6EwIAAQX9qQQdxIgQ6AN6EwIAAIAQNK0H9/wMhBAJAAkACQAJAQQAtAN+EwIAAQQdxQX5qDgMAAQIDC0EALQDahMCAAEEfcUEGdEEALQDbhMCAAEE/cXIhBAwCC0EALQDbhMCAAEE/cUEGdEEALQDahMCAAEEPcUEMdHJBAC0A3ITAgABBP3FyIQQMAQtBAC0A24TAgABBP3FBDHRBAC0A2oTAgABBEnRyQQAtANyEwIAAQT9xQQZ0ckEALQDdhMCAAEE/cXIhBAtBACAEOwGcgMCAACADIARBgID8AHFBEHY6AABBAEEAOgDCgMCAAAwLCwJAAkACQCAEQaV/ag4DAAIBAgtBAEEEOgDCgMCAAEEAQQA7AdiAwIAAQQBBADoAxYDAgABBAEEAOgDEgMCAAEHGgMCAACEFQQghBANAIARBKEYNLSAEQZiAwIAAakEAOwEAIAVBADoAACAEQQJqIQQgBUEBaiEFDAALC0EAQQc6AMKAwIAAQQBBADsBwIDAgAAMKwsCQCAEQfABcUEgRw0AAkBBAC0A2IDAgAAiBUEBSw0AIAUgBDoA1oDAgABBAEEALQDYgMCAAEEBajoA2IDAgAALQQBBAzoAwoDAgAAMKwsgBEFQakH/AXFBzwBJDQ8gBEEgSQ0jDAQLAkAgBEHwAXFBIEcNAEEALQDYgMCAACIFQQFLDSogBSAEOgDWgMCAAEEAQQAtANiAwIAAQQFqOgDYgMCAAAwqCyAEQVBqQf8BcUHPAEkNDiAEQSBJDSIMAwsCQAJAAkACQAJAAkAgBEFQakH/AXEiBUEJSw0AQQAtAMWAwIAADS5BAC0AxIDAgAAiBA0BQQAhBEEAQQE6AMSAwIAADAILIARBRmoOBgICBAQsLAMLIARBf2pB/wFxIQQLIARBAXQiBEF/IAQvAaCAwIAAQRB0rUIKfiIGpyAGQiCIpxtBEHYgBWoiBEH//wMgBEH//wNJGzsBoIDAgAAMKwtBAC0AxIDAgAAiBUEPSw0qQQAgBUEBIAVBAUsbIgVBAWo6AMSAwIAAIARBOkcNKiAFQQE6AMaAwIAADCoLIARBIUYNKAsCQCAEQfABcUEgRw0AAkBBAC0A2IDAgAAiBUEBSw0AIAUgBDoA1oDAgABBAEEALQDYgMCAAEEBajoA2IDAgAALQQBBBToAwoDAgAAMKQsgBEFAakH/AXFBP0kNCSAEQSBJDSEMJgsCQCAEQfABcUEgRw0AQQAtANiAwIAAIgVBAUsNKCAFIAQ6ANaAwIAAQQBBAC0A2IDAgABBAWo6ANiAwIAADCgLIARBQGpB/wFxQT9JDQggBEEgTw0lDCALIARBQGpB/wFxQT5LDSYLQQBBADoAwoDAgAAMJQsgBEEHRw0BQQBBADoAwoDAgAALQQAvAcCAwIAAIgRBAkkNI0EALQDagMCAAEFQag4DByMHIwsgBEFgakH/AXFB3gBLDSJBAC8BwIDAgAAiBUH/A0sNIiAFIAQ6ANqAwIAAQQAgBUEBajsBwIDAgAAMIgtBAEEAOgDCgMCAAAsgBEEgSQ0ZAkAgBEH/AEkNAAJAIARB/wBHDQBBAEH/ADoAw4DAgAAMHAsCQCAEQeABcUHAAUcNAEEAQQI6AN+EwIAAQQAgBDoA2oTAgABBAEEBOgDehMCAAEEAQQE6AMKAwIAADCILAkAgBEHwAXFB4AFHDQBBAEEDOgDfhMCAAEEAIAQ6ANqEwIAAQQBBAjoA3oTAgABBAEEBOgDCgMCAAAwiCyAEQfgBcUHwAUcNIUEAQQQ6AN+EwIAAQQAgBDoA2oTAgABBAEEDOgDehMCAAEEAQQE6AMKAwIAADCELQQAgBDsBnIDAgAAgA0EAOgAAC0EAKAKcgMCAACEEQQAtANmM8IAADQEMFwtBACAEOgDDgMCAAEEAQQA6AMKAwIAAAkBBAC0A2YDAgAAiBUE/Rw0AAkACQAJAIARBmH9qDgUAAgICAQILQQEQm4CAgAAMIQtBABCbgICAAAwgCyAEQT8QnICAgAAMHwsCQCAEQfAARw0AIAVBIUcNAEEAQQE6AJKK8IAAQQBBAToA24zwgABBAEGAgoAINgH+ifCAAEEAQQAvAe6G8IAAOwGGivCAAEEAQQA6AI6K8IAAQQBBADoAkYrwgABBAEEAOgCQivCAAEEAQQA7AYSK8IAAQQBBADoAk4rwgAAMHwsCQCAFQT5HDQAgBEE+EJyAgIAADB8LAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIARBQGoONiQAAQIDBAUGIiEHCAkKISELISEMDSEhIQ4hISEhISEhIw8hIRARIhIhISEhIRMmISEhJRkzGiELQQBBAEEALwHwhvCAACIEQQAvAaCAwIAAIgVBASAFQQFLG0EBQQAtAMSAwIAAG2siBSAFIARLGzsB8IbwgABBAEEAOgDZjPCAAAwyC0EAQQAvAfCG8IAAQQAvAaCAwIAAIgRBASAEQQFLG0EBQQAtAMSAwIAAG2pB//8DcSIEQQAvAe6G8IAAQX9qQf//A3EiBSAEIAVJGzsB8IbwgABBAEEAOgDZjPCAAAwxC0EAQQAvAfKG8IAAQQAvAaCAwIAAIgRBASAEQQFLG0EBQQAtAMSAwIAAG2pB//8DcSIEQQAvAeyG8IAAQX9qQf//A3EiBSAEIAVJGzsB8obwgABBAEEAOgDZjPCAAAwwC0EAQQBBAC8B8obwgAAiBEEALwGggMCAACIFQQEgBUEBSxtBAUEALQDEgMCAABtrIgUgBSAESxs7AfKG8IAAQQBBADoA2YzwgAAMLwtBAEEALwHwhvCAAEEALwGggMCAACIEQQEgBEEBSxtBAUEALQDEgMCAABtqQf//A3EiBEEALwHuhvCAAEF/akH//wNxIgUgBCAFSRs7AfCG8IAAQQBBADoA2YzwgABBAEEAOwHyhvCAAAwuC0EAQQBBAC8B8IbwgAAiBEEALwGggMCAACIFQQEgBUEBSxtBAUEALQDEgMCAABtrIgUgBSAESxs7AfCG8IAAQQBBADoA2YzwgABBAEEAOwHyhvCAAAwtC0EAQQBBAC8BoIDAgAAiBEF/aiIFIAUgBEsbQQBBAC0AxIDAgAAbIgRBAC8B7IbwgAAiBUF/aiAEIAVJGzsB8obwgABBAEEAOgDZjPCAAAwsCwJAQQAtAMSAwIAADQAgAUGAAjsBBCABQSA2AgAgAUEANgIIIAFBAC8BgIrwgAA7AQYMIwtBAC8BoIDAgAAhBSABQQA2AgggAUEALwGAivCAADsBBiABQYACOwEEIAFBIDYCAAJAAkAgBQ4EJAABAS0LQQAhBAJAA0AgBEH//wNxQQAvAfCG8IAAIgVPDQEgBCABEJ2AgIAAIARBAWohBAwACwsgBUEAQQAvAfKG8IAAQQFqIAEQnoCAgAAMLAtBACEEAkADQCAEQf//A3FBAC8B7obwgABPDQEgBCABEJ2AgIAAIARBAWohBAwACwsgBUEDRw0rQQAoAuCEwIAAIgRFDSsgBEIANwKg37sBDCsLQQAtAMSAwIAADQsgAUGAAjsBBCABQSA2AgAgAUEANgIIIAFBAC8BgIrwgAA7AQYMIAtBAC8B8IbwgAAiBEEALwGEivCAAEkNKSAEQQAvAYaK8IAAIgVPDSlBAC8BoIDAgAAhB0EALQDEgMCAACEIIAFBgAI7AQQgAUEgNgIAIAFBADYCCCABQQAvAYCK8IAAOwEGIAQgBSAHQQEgB0EBSxtBASAIGyABEJ+AgIAADCkLQQAvAfCG8IAAIgRBAC8BhIrwgABJDSggBEEALwGGivCAACIFTw0oQQAvAaCAwIAAIQdBAC0AxIDAgAAhCCABQYACOwEEIAFBIDYCACABQQA2AgggAUEALwGAivCAADsBBiAEIAUgB0EBIAdBAUsbQQEgCBsgARCggICAAAwoC0EALwHyhvCAACIEQQxsIghB8ITAgABqIQVBAC8BoIDAgAAiB0EBIAdBAUsbQQFBAC0AxIDAgAAbIglBDGxB6ITAgABqIQpBAC8BgIrwgAAhCwJAA0AgCSAEakEALwHshvCAACIHTw0BIAhBAC8B8IbwgABBgBhsaiIHQeiEwIAAaiAKIAdqIgwpAgA3AgAgB0HwhMCAAGogDEEIaigCADYCACAFQQxqIQUgCEEMaiEIIARBAWohBAwACwsCQANAQQAvAfCG8IAAIQggBCAHQf//A3FPDQEgBSAIQYAYbGoiB0EANgIAIAdBfmogCzsBACAHQXxqQYACOwEAIAdBeGpBIDYCACAFQQxqIQUgBEEBaiEEQQAvAeyG8IAAIQcMAAsLIAhBAToA7ITwgAAMJwtBAC8BoIDAgAAiBEEBIARBAUsbQQFBAC0AxIDAgAAbIQhBAC8BhIrwgAAhBQJAQQAtAJWK8IAADQAgBUH//wNxDQBBACEFQQAoAuCEwIAAIgxFDQBBACEFQQAhBANAIARB//8DcSIHIAhPDQEgB0EALwGGivCAACAFa0H//wNxTw0BIAwgBCAFakH//wNxQYAYbEHohMCAAGpBAC8B7IbwgAAQoYCAgAAgBEEBaiEEQQAvAYSK8IAAIQUMAAsLIAFBgAI7AQQgAUEgNgIAIAFBADYCCCABQQAvAYCK8IAAOwEGIAVBAC8BhorwgAAgCCABEKCAgIAADCYLQQAtAMSAwIAAIQVBAC8BoIDAgAAhBCABQQA2AgggAUEALwGAivCAADsBBiABQYACOwEEIAFBIDYCAEEALwGEivCAAEEALwGGivCAACAEQQEgBEEBSxtBASAFGyABEJ+AgIAADCULQQAtAMSAwIAAIQVBAC8BoIDAgAAhBCABQQA2AgggAUEALwGAivCAADsBBiABQYACOwEEIAFBIDYCAEEALwHwhvCAAEEALwHyhvCAACIHIAcgBEEBIARBAUsbQQEgBRtqQf//A3EiBEEALwHshvCAACIFIAQgBUkbIAEQnoCAgAAMJAtBAEEALwHyhvCAAEEALwGggMCAACIEQQEgBEEBSxtBAUEALQDEgMCAABtqQf//A3EiBEEALwHshvCAAEF/akH//wNxIgUgBCAFSRs7AfKG8IAAQQBBADoA2YzwgAAMIwtBAEEAQQAvAaCAwIAAIgRBf2oiBSAFIARLG0EAQQAtAMSAwIAAGyIEQQAvAe6G8IAAIgVBf2ogBCAFSRs7AfCG8IAAQQBBADoA2YzwgAAMIgtBAEEALwHwhvCAAEEALwGggMCAACIEQQEgBEEBSxtBAUEALQDEgMCAABtqQf//A3EiBEEALwHuhvCAAEF/akH//wNxIgUgBCAFSRs7AfCG8IAAQQBBADoA2YzwgAAMIQsCQAJAQQAtAMSAwIAARQ0AQQAvAaCAwIAADgQAIiIBIgtBAC8B8obwgAAiBEH/AUsNISAEQQA6ANyM8IAADCELQcSMMCEEA0AgBEHEjjBGDSEgBEGYgMCAAGpBADoAACAEQQFqIQQMAAsLQQAhBAJAQQAtAMSAwIAAIgUNAEEAQYCCgAg2Af6J8IAAQQBBADoAk4rwgAAMIAsDQCAEQf8BcSIHIAVB/wFxTw0gAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAHQQF0LwGggMCAACIIDjIAAQIDBAUUBgcIFBQUFBQUFBQUFBQUCQoLDBQNDg8UFBQUFBQUFBARFBQUFBQUFBQSExQLQQBBgIKACDYB/onwgABBAEEAOgCTivCAAAwbC0EAQQAtAJOK8IAAQQFyOgCTivCAAAwaC0EAQQAtAJOK8IAAQQJyOgCTivCAAAwZC0EAQQAtAJOK8IAAQQRyOgCTivCAAAwYCyAEQQFqIghB/wFxIgcgBUH/AXFJDRBBAC0Ak4rwgAAhBQwVC0EAQQAtAJOK8IAAQRByOgCTivCAAAwWC0EAQQAtAJOK8IAAQSByOgCTivCAAAwVC0EAQQAtAJOK8IAAQcAAcjoAk4rwgAAMFAtBAEEALQCTivCAAEGAAXI6AJOK8IAADBMLQQBBAC0Ak4rwgABB/AFxOgCTivCAAAwSC0EAQQAtAJOK8IAAQfsBcToAk4rwgAAMEQtBAEEALQCTivCAAEH3AXE6AJOK8IAADBALQQBBAC0Ak4rwgABB7wFxOgCTivCAAAwPC0EAQQAtAJOK8IAAQd8BcToAk4rwgAAMDgtBAEEALQCTivCAAEG/AXE6AJOK8IAADA0LQQBBAC0Ak4rwgABB/wBxOgCTivCAAAwMCyAEQf6J8IAAEKKAgIAAQf8BcSAEaiEEDAsLQQBBgAI7Af6J8IAADAoLIARBgIrwgAAQooCAgABB/wFxIARqIQQMCQtBAEGAAjsBgIrwgAAMCAsgCEFiaiIMQf//A3FBCEkNBCAIQfj/A3FBKEYNAyAIQaZ/akH//wNxQQhJDQIgCEGcf2pB//8DcUEISQ0BIAVBf2ohBCAFQf8BcUF/aiEIA0AgCCAHRg0IIAdBx4DAgABqIQUgB0EBaiIMIQcgBS0AAEUNBwwACwtBAC0Ak4rwgAAhBSAHLQDGgMCAAEUNBEEAQQhBACAHQQF0LwGggMCAABsgBUH3AXFyOgCTivCAACAIIQQMBgtBACAIQaR/ajsBgIrwgAAMBQtBACAIQa5/ajsB/onwgAAMBAtBACAIQVhqOwGAivCAAAwDC0EAIAw7Af6J8IAADAILQQAgBUEIcjoAk4rwgAAMAQsgDEF/aiEECyAEQQFqIQRBAC0AxIDAgAAhBQwACwtBAC8BoIDAgAAhBCABQQA2AgggAUEALwGAivCAADsBBiABQYACOwEEIAFBIDYCACAEDgMUExIeC0EAQQA7AfKG8IAAEKOAgIAAQQBBADoA2YzwgAAMFQsgAUHAAGokgICAgAAPC0EALQDbgMCAAEE7Rw0bIARBfmoiBEGAAiAEQYACSRshBUEAIQQCQANAIAUgBEYNASAEQZaK8IAAaiAEQdyAwIAAai0AADoAACAEQQFqIQQMAAsLQQBBAToAl4zwgABBACAFOwH8ifCAAAwbC0EAIAQ6AMOAwIAAQQBBADoAwoDAgAACQEEALQDYgMCAAEUNAEEALQDWgMCAAEH/AXFBI0cNAAJAIARBvH9qDgoFBBwcCRwcHBwGAAsCQCAEQUlqDgICAAcLQQAhBQJAA0AgBUH//wNxQQAvAe6G8IAATw0BQQAhBAJAA0AgBEH//wNxQQAvAeyG8IAATw0BIAUgBEGMgMCAABCkgICAACAEQQFqIQQMAAsLIAVBAWohBQwACwtBAEEANgLwhvCAAAwbCwJAIARBvH9qDgoEAxsbCBsbGxsFAAsCQCAEQUlqDgIBAgALIARB4wBGDQYMGgsQpYCAgAAMGQsQpoCAgAAMGAtBAEEAOgDZjPCAAEEAQQA7AfKG8IAACxCjgICAAAwWCwJAQQAvAfCG8IAAIgRBAC8BhIrwgABHDQAgAUGAAjsBBCABQSA2AgAgAUEANgIIIAFBAC8BgIrwgAA7AQYgBEEALwGGivCAAEEBIAEQn4CAgAAMFgsgBEUNFUEAIARBf2o7AfCG8IAADBULIARB4wBHDRQLQQAvAeyG8IAAQQAvAe6G8IAAEKeAgIAADBMLQQAvAfKG8IAAIgRB/wFLDRIgBEEBOgDcjPCAAAwSCyAEQQAQnICAgAAMEQtBAEEAQQAvAaCAwIAAIgRBf2oiBSAFIARLG0EAQQAtAMSAwIAAIgQbIgVBAC8B7obwgAAiB0F/aiAFIAdJGzsB8IbwgABBAEEAQQAvAaKAwIAAIgVBf2oiByAHIAVLG0EAIARBAUsbIgRBAC8B7IbwgAAiBUF/aiAEIAVJGzsB8obwgABBAEEAOgDZjPCAAAwQC0EAQQBBAC8BoIDAgAAiBEF/aiIFIAUgBEsbQQBBAC0AxIDAgAAbIgRBAC8B7IbwgAAiBUF/aiAEIAVJGzsB8obwgABBAEEAOgDZjPCAAAwPC0EALQDEgMCAACEHQQAvAaCAwIAAIQQgAUEANgIIIAFBAC8BgIrwgAA7AQYgAUGAAjsBBCABQSA2AgACQEEALwHyhvCAACIFIARBASAEQQFLG0EBIAcbIgdqQf//A3FBAC8B7IbwgAAiBEkNAEEALwHwhvCAACAFIAQgARCegICAAAwPCwJAA0AgBEF/aiIEQf//A3EgBSAHaiIIQf//A3FJDQFBAC8B8IbwgABBgBhsQeiEwIAAaiIFIAQgB2tB//8DcUEMbGoiCCkCACEGIAUgBEH//wNxQQxsaiIFQQhqIAhBCGooAgA2AgAgBSAGNwIAQQAvAfKG8IAAIQUMAAsLQQAgCEH//wNxIgRBAC8B7IbwgAAiByAEIAdJGyIEIAVB//8DcSIFayIHIAcgBEsbIQQgBUEMbEHohMCAAGohBQJAA0BBAC8B8IbwgAAhByAERQ0BIAUgB0GAGGxqIgcgASkCADcCACAHQQhqIAFBCGooAgA2AgAgBEF/aiEEIAVBDGohBQwACwsgB0EBOgDshPCAAAwOC0EAQQAvAaCAwIAAIgRBf2oiBSAFIARLG0EAQQAtAMSAwIAAIgcbIghBAC8BooDAgAAiBUEALwHuhvCAACIEIAUgBEkbIAQgBRsgBCAHQQFLGyIETw0NQQAgBDsBhorwgABBACAIOwGEivCAAEEAIAhBAEEALQCOivCAABs7AfCG8IAAQQBBADoA2YzwgABBAEEAOwHyhvCAAAwNC0EALQDEgMCAAEUNDEEALwGggMCAAEH//wNxQQZHDQwgAUGbtgE7AABBAC8B8obwgAAhBCABIAFBAkEALwHwhvCAAEEBahCogICAACIFQf8BcWpBOzoAACABIAEgBUEBaiAEQQFqEKiAgIAAIgRB/wFxakHSADoAAAJAQcAARQ0AQZiM8IAAIAFBwAD8CgAAC0EAIARBAWo6ANiM8IAADAwLQQAvAfCG8IAAIAEQnYCAgAAMCwtBAC8B8IbwgABBAEEALwHyhvCAAEEBaiABEJ6AgIAADAoLQQAvAfCG8IAAQQAvAfKG8IAAQQAvAeyG8IAAIAEQnoCAgAAMCQtBAC8B8IbwgABBAC8B8obwgABBAC8B7IbwgAAgARCegICAAEEALwHwhvCAACEEA0AgBEEBaiIEQf//A3FBAC8B7obwgABPDQkgBCABEJ2AgIAADAALCyABQQA6AAsgAUEAOwAJIAFBAC0Ak4rwgAA6AAggAUEAKAH+ifCAADYCBCABIARB////AHE2AgBBAC8B8IbwgABBAC8B8obwgAAgARCkgICAAAJAQQAvAfKG8IAAIgRBAC8B7IbwgABBf2pB//8DcU8NAEEAIARBAWo7AfKG8IAADAgLQQAtAJKK8IAARQ0HQQBBAToA2YzwgAAMBwtBACEFQQAgBDoAw4DAgAAgBEF4ag4GAAECAgIDBgtBAC8B8obwgAAiBEUNBSAEQX9qIQUMAgtBAC8B7IbwgAAiCEEALwHyhvCAACIEQQFqQf//A3EiBSAIIAVLGyEMAkADQCAEQQFqIgUgCE8NASAEQd2M8IAAaiEHIAUhBCAHLQAAQQFHDQALIAUhDAsgDCAIQX9qIAUgCEkbIQUMAQsQo4CAgABBACEFQQAtAI+K8IAARQ0DC0EAIAU7AfKG8IAAQQBBADoA2YzwgAAMAgtBAEEGOgDCgMCAAAwBC0EAIAQ6ANmAwIAACyAAQQFqIQAMAAsLsQIBA39BAC0AxIDAgAAiAUEBIAFBAUsbQQF0IQJBACEBA0ACQAJAAkAgAiABRg0AAkACQAJAAkACQAJAAkACQAJAAkAgAUGggMCAAGovAQAiA0F/ag4HAQwMDAwCAwALAkAgA0Hpd2oOAwYJBwALIANBFEYNAyADQRlGDQQgA0EvRg0FIANB1A9GDQcMCwtBACAAQQFxOgCRivCAAAwKC0EAIABBAXE6AI6K8IAADAkLQQAgAEEBcToAkorwgAAMCAtBACAAQQFxOgCPivCAAAwHC0EAIABBAXE6ANuM8IAADAYLIABBABCpgICAAAwFCyAAQQEQqYCAgAAMBAtBACAAQQFxOgCQivCAAAwDCyAAQQFxDQEQpoCAgAAMAgsPCxClgICAAAsgAUECaiEBDAALC+sBAQJ/I4CAgIAAQRBrIgIkgICAgABBACEDIAJBADoACyACIAE6AAkgAiAAOgAIIAJCADcDACACQQAtAMSAwIAAIgE6AAogAUEEIAFBBEkbQQF0IQECQANAIAEgA0YNASACIANqIANBoIDAgABqLwEAOwEAIANBAmohAwwACwtBAC0A2ozwgABBDGwiA0H8hvCAAGogAkEIaigCADYCACADIAIpAwA3AvSG8IAAQQBBACgC5ITAgABBAWoiA0F/IAMbNgLkhMCAAEEAQQAtANqM8IAAQQFqQR9xOgDajPCAACACQRBqJICAgIAAC3gBAn8CQCAAQf//A3EiAkEALwHqhPCAAE8NACACQYAYbEHohMCAAGohAEEAIQMCQANAIANBAC8B6ITwgABPDQEgACABKQIANwIAIABBCGogAUEIaigCADYCACAAQQxqIQAgA0EBaiEDDAALCyACQQE6AOyE8IAACwujAQEBfwJAIABB//8DcSIEQQAvAeqE8IAATw0AQQAgAkH//wNxIgBBAC8B6ITwgAAiAiAAIAJJGyIAIAFB//8DcSIBayICIAIgAEsbIQIgBEGAGGwgAUEMbGpB6ITAgABqIQACQANAIAJFDQEgACADKQIANwIAIABBCGogA0EIaigCADYCACAAQQxqIQAgAkF/aiECDAALCyAEQQE6AOyE8IAACwvhAQEEfwJAIAJB//8DcUUNACABQf//A3EgAEH//wNxTQ0AIAEgAGsiBCACQf//A3EiAiAEQf//A3EiBCACIARJGyIFa0H//wNxIQZBACECA0ACQCAGIAJHDQAgBSAAakH//wNxIQIDQCAAQf//A3EgAk8NAyAAIAMQnYCAgAAgAEEBaiEADAALCyABIAJBf3NqIgdB//8DcSEEAkBBgBhFDQAgBEGAGGxB6ITAgABqIAcgBWtB//8DcUGAGGxB6ITAgABqQYAY/AoAAAsgBEEBOgDshPCAACACQQFqIQIMAAsLC9gBAQN/AkAgAkH//wNxRQ0AIAFB//8DcSAAQf//A3FNDQAgAkH//wNxIgIgASAAa0H//wNxIgQgAiAESRsiBEGAGGxB6ITAgABqIQUgAUH//wNxIQYgAEH//wNxIgBBgBhsIQIDQAJAIAQgAGogBkkN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";
3
+ //#endregion
4
+ //#region node_modules/.pnpm/@wterm+core@0.1.9/node_modules/@wterm/core/dist/wasm-bridge.js
5
+ function decodeBase64(base64) {
6
+ const binary = atob(base64);
7
+ const bytes = new Uint8Array(binary.length);
8
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
9
+ return bytes.buffer;
10
+ }
11
+ var WasmBridge = class WasmBridge {
12
+ constructor(instance) {
13
+ this.gridPtr = 0;
14
+ this.dirtyPtr = 0;
15
+ this.writeBufferPtr = 0;
16
+ this.cellSize = 12;
17
+ this.maxCols = 256;
18
+ this.encoder = new TextEncoder();
19
+ this.decoder = new TextDecoder();
20
+ this.exports = instance.exports;
21
+ this.memory = this.exports.memory;
22
+ }
23
+ static async load(url) {
24
+ let bytes;
25
+ if (url) {
26
+ const response = await fetch(url);
27
+ if (!response.ok) throw new Error(`[wterm] Failed to load WASM from ${url}: ${response.status} ${response.statusText}`);
28
+ bytes = await response.arrayBuffer();
29
+ } else bytes = decodeBase64(WASM_BASE64);
30
+ const { instance } = await WebAssembly.instantiate(bytes);
31
+ return new WasmBridge(instance);
32
+ }
33
+ init(cols, rows) {
34
+ this.exports.init(cols, rows);
35
+ this._updatePointers();
36
+ }
37
+ _updatePointers() {
38
+ this.gridPtr = this.exports.getGridPtr();
39
+ this.dirtyPtr = this.exports.getDirtyPtr();
40
+ this.writeBufferPtr = this.exports.getWriteBuffer();
41
+ this.cellSize = this.exports.getCellSize();
42
+ this.maxCols = this.exports.getMaxCols();
43
+ this._dv = new DataView(this.memory.buffer);
44
+ }
45
+ writeString(str) {
46
+ const encoded = this.encoder.encode(str);
47
+ this.writeRaw(encoded);
48
+ }
49
+ writeRaw(data) {
50
+ const buf = new Uint8Array(this.memory.buffer, this.writeBufferPtr, 8192);
51
+ let offset = 0;
52
+ while (offset < data.length) {
53
+ const chunk = Math.min(data.length - offset, 8192);
54
+ buf.set(data.subarray(offset, offset + chunk));
55
+ this.exports.writeBytes(chunk);
56
+ offset += chunk;
57
+ }
58
+ }
59
+ getCell(row, col) {
60
+ const offset = this.gridPtr + (row * this.maxCols + col) * this.cellSize;
61
+ const dv = this._dv;
62
+ return {
63
+ char: dv.getUint32(offset, true),
64
+ fg: dv.getUint16(offset + 4, true),
65
+ bg: dv.getUint16(offset + 6, true),
66
+ flags: dv.getUint8(offset + 8)
67
+ };
68
+ }
69
+ isDirtyRow(row) {
70
+ return new Uint8Array(this.memory.buffer, this.dirtyPtr, 256)[row] !== 0;
71
+ }
72
+ clearDirty() {
73
+ this.exports.clearDirty();
74
+ }
75
+ getCursor() {
76
+ return {
77
+ row: this.exports.getCursorRow(),
78
+ col: this.exports.getCursorCol(),
79
+ visible: this.exports.getCursorVisible() !== 0
80
+ };
81
+ }
82
+ getCols() {
83
+ return this.exports.getCols();
84
+ }
85
+ getRows() {
86
+ return this.exports.getRows();
87
+ }
88
+ cursorKeysApp() {
89
+ return this.exports.getCursorKeysApp() !== 0;
90
+ }
91
+ bracketedPaste() {
92
+ return this.exports.getBracketedPaste() !== 0;
93
+ }
94
+ usingAltScreen() {
95
+ return this.exports.getUsingAltScreen() !== 0;
96
+ }
97
+ getTitle() {
98
+ if (this.exports.getTitleChanged() === 0) return null;
99
+ const ptr = this.exports.getTitlePtr();
100
+ const len = this.exports.getTitleLen();
101
+ const bytes = new Uint8Array(this.memory.buffer, ptr, len);
102
+ return this.decoder.decode(bytes);
103
+ }
104
+ getResponse() {
105
+ const len = this.exports.getResponseLen();
106
+ if (len === 0) return null;
107
+ const ptr = this.exports.getResponsePtr();
108
+ const bytes = new Uint8Array(this.memory.buffer, ptr, len);
109
+ const str = this.decoder.decode(bytes);
110
+ this.exports.clearResponse();
111
+ return str;
112
+ }
113
+ getScrollbackCount() {
114
+ return this.exports.getScrollbackCount();
115
+ }
116
+ getScrollbackCell(offset, col) {
117
+ const off = this.exports.getScrollbackLine(offset) + col * this.cellSize;
118
+ const dv = this._dv;
119
+ return {
120
+ char: dv.getUint32(off, true),
121
+ fg: dv.getUint16(off + 4, true),
122
+ bg: dv.getUint16(off + 6, true),
123
+ flags: dv.getUint8(off + 8)
124
+ };
125
+ }
126
+ getScrollbackLineLen(offset) {
127
+ return this.exports.getScrollbackLineLen(offset);
128
+ }
129
+ getUnhandledSequences() {
130
+ const count = this.exports.getDebugLogCount();
131
+ if (count === 0) return [];
132
+ const ptr = this.exports.getDebugLogPtr();
133
+ const entrySize = this.exports.getDebugLogEntrySize();
134
+ const maxEntries = this.exports.getDebugLogMax();
135
+ const total = Math.min(count, maxEntries);
136
+ const dv = new DataView(this.memory.buffer);
137
+ const entries = [];
138
+ const startIdx = count >= maxEntries ? count % maxEntries : 0;
139
+ for (let i = 0; i < total; i++) {
140
+ const off = ptr + (startIdx + i) % maxEntries * entrySize;
141
+ const finalByte = dv.getUint8(off);
142
+ if (finalByte === 0) continue;
143
+ const privateByte = dv.getUint8(off + 1);
144
+ const paramCount = dv.getUint8(off + 2);
145
+ const params = [];
146
+ for (let p = 0; p < Math.min(paramCount, 4); p++) params.push(dv.getUint16(off + 4 + p * 2, true));
147
+ entries.push({
148
+ final: String.fromCharCode(finalByte),
149
+ private: privateByte ? String.fromCharCode(privateByte) : "",
150
+ paramCount,
151
+ params
152
+ });
153
+ }
154
+ return entries;
155
+ }
156
+ resize(cols, rows) {
157
+ this.exports.resizeTerminal(cols, rows);
158
+ this._updatePointers();
159
+ }
160
+ };
161
+ //#endregion
162
+ //#region node_modules/.pnpm/@wterm+dom@0.1.9/node_modules/@wterm/dom/dist/renderer.js
163
+ const DEFAULT_COLOR$1 = 256;
164
+ const FLAG_BOLD$1 = 1;
165
+ const FLAG_DIM$1 = 2;
166
+ const FLAG_ITALIC$1 = 4;
167
+ const FLAG_UNDERLINE$1 = 8;
168
+ const FLAG_REVERSE$1 = 32;
169
+ const FLAG_INVISIBLE$1 = 64;
170
+ const FLAG_STRIKETHROUGH$1 = 128;
171
+ function colorToCSS$1(index) {
172
+ if (index === DEFAULT_COLOR$1) return null;
173
+ if (index < 16) return `var(--term-color-${index})`;
174
+ if (index < 232) {
175
+ const n = index - 16;
176
+ return `rgb(${Math.floor(n / 36) * 51},${Math.floor(n / 6) % 6 * 51},${n % 6 * 51})`;
177
+ }
178
+ const level = (index - 232) * 10 + 8;
179
+ return `rgb(${level},${level},${level})`;
180
+ }
181
+ function buildCellStyle$1(fg, bg, flags) {
182
+ let fgC = fg, bgC = bg;
183
+ if (flags & FLAG_REVERSE$1) {
184
+ const tmp = fgC;
185
+ fgC = bgC;
186
+ bgC = tmp;
187
+ if (fgC === DEFAULT_COLOR$1) fgC = 0;
188
+ if (bgC === DEFAULT_COLOR$1) bgC = 7;
189
+ }
190
+ const fgCSS = colorToCSS$1(fgC);
191
+ const bgCSS = colorToCSS$1(bgC);
192
+ let style = "";
193
+ if (fgCSS) style += `color:${fgCSS};`;
194
+ if (bgCSS) style += `background:${bgCSS};`;
195
+ if (flags & FLAG_BOLD$1) style += "font-weight:bold;";
196
+ if (flags & FLAG_DIM$1) style += "opacity:0.5;";
197
+ if (flags & FLAG_ITALIC$1) style += "font-style:italic;";
198
+ const decorations = [];
199
+ if (flags & FLAG_UNDERLINE$1) decorations.push("underline");
200
+ if (flags & FLAG_STRIKETHROUGH$1) decorations.push("line-through");
201
+ if (decorations.length) style += `text-decoration:${decorations.join(" ")};`;
202
+ if (flags & FLAG_INVISIBLE$1) style += "visibility:hidden;";
203
+ return style;
204
+ }
205
+ function appendRun$1(parent, text, style) {
206
+ const span = document.createElement("span");
207
+ if (style) span.style.cssText = style;
208
+ span.textContent = text;
209
+ parent.appendChild(span);
210
+ }
211
+ function resolveColors$1(fg, bg, flags) {
212
+ let fgC = fg, bgC = bg;
213
+ if (flags & FLAG_REVERSE$1) {
214
+ [fgC, bgC] = [bgC, fgC];
215
+ if (fgC === DEFAULT_COLOR$1) fgC = 0;
216
+ if (bgC === DEFAULT_COLOR$1) bgC = 7;
217
+ }
218
+ return {
219
+ fg: colorToCSS$1(fgC) || "var(--term-fg)",
220
+ bg: colorToCSS$1(bgC) || "var(--term-bg)"
221
+ };
222
+ }
223
+ function getBlockBackground$1(cp, fg, bg) {
224
+ switch (cp) {
225
+ case 9600: return `linear-gradient(${fg} 50%,${bg} 50%)`;
226
+ case 9601: return `linear-gradient(${bg} 87.5%,${fg} 87.5%)`;
227
+ case 9602: return `linear-gradient(${bg} 75%,${fg} 75%)`;
228
+ case 9603: return `linear-gradient(${bg} 62.5%,${fg} 62.5%)`;
229
+ case 9604: return `linear-gradient(${bg} 50%,${fg} 50%)`;
230
+ case 9605: return `linear-gradient(${bg} 37.5%,${fg} 37.5%)`;
231
+ case 9606: return `linear-gradient(${bg} 25%,${fg} 25%)`;
232
+ case 9607: return `linear-gradient(${bg} 12.5%,${fg} 12.5%)`;
233
+ case 9608: return fg;
234
+ case 9609: return `linear-gradient(to right,${fg} 87.5%,${bg} 87.5%)`;
235
+ case 9610: return `linear-gradient(to right,${fg} 75%,${bg} 75%)`;
236
+ case 9611: return `linear-gradient(to right,${fg} 62.5%,${bg} 62.5%)`;
237
+ case 9612: return `linear-gradient(to right,${fg} 50%,${bg} 50%)`;
238
+ case 9613: return `linear-gradient(to right,${fg} 37.5%,${bg} 37.5%)`;
239
+ case 9614: return `linear-gradient(to right,${fg} 25%,${bg} 25%)`;
240
+ case 9615: return `linear-gradient(to right,${fg} 12.5%,${bg} 12.5%)`;
241
+ case 9616: return `linear-gradient(to right,${bg} 50%,${fg} 50%)`;
242
+ case 9617: return `color-mix(in srgb,${fg} 25%,${bg})`;
243
+ case 9618: return `color-mix(in srgb,${fg} 50%,${bg})`;
244
+ case 9619: return `color-mix(in srgb,${fg} 75%,${bg})`;
245
+ case 9620: return `linear-gradient(${fg} 12.5%,${bg} 12.5%)`;
246
+ case 9621: return `linear-gradient(to right,${bg} 87.5%,${fg} 87.5%)`;
247
+ default: {
248
+ const q = {
249
+ 9622: [
250
+ false,
251
+ false,
252
+ true,
253
+ false
254
+ ],
255
+ 9623: [
256
+ false,
257
+ false,
258
+ false,
259
+ true
260
+ ],
261
+ 9624: [
262
+ true,
263
+ false,
264
+ false,
265
+ false
266
+ ],
267
+ 9625: [
268
+ true,
269
+ false,
270
+ true,
271
+ true
272
+ ],
273
+ 9626: [
274
+ true,
275
+ false,
276
+ false,
277
+ true
278
+ ],
279
+ 9627: [
280
+ true,
281
+ true,
282
+ true,
283
+ false
284
+ ],
285
+ 9628: [
286
+ true,
287
+ true,
288
+ false,
289
+ true
290
+ ],
291
+ 9629: [
292
+ false,
293
+ true,
294
+ false,
295
+ false
296
+ ],
297
+ 9630: [
298
+ false,
299
+ true,
300
+ true,
301
+ false
302
+ ],
303
+ 9631: [
304
+ false,
305
+ true,
306
+ true,
307
+ true
308
+ ]
309
+ }[cp];
310
+ if (!q) return fg;
311
+ const [tl, tr, bl, br] = q;
312
+ if (tl && tr && bl && br) return fg;
313
+ const layers = [];
314
+ const POS = [
315
+ "0 0",
316
+ "100% 0",
317
+ "0 100%",
318
+ "100% 100%"
319
+ ];
320
+ q.forEach((filled, i) => {
321
+ if (filled) layers.push(`linear-gradient(${fg},${fg}) ${POS[i]}/50% 50% no-repeat`);
322
+ });
323
+ layers.push(bg);
324
+ return layers.join(",");
325
+ }
326
+ }
327
+ }
328
+ var Renderer = class {
329
+ constructor(container) {
330
+ this.rows = 0;
331
+ this.cols = 0;
332
+ this.rowEls = [];
333
+ this.prevCursorRow = -1;
334
+ this.prevCursorCol = -1;
335
+ this.prevContainerBg = "";
336
+ this.prevRowBg = [];
337
+ this._scrollbackRowEls = [];
338
+ this._renderedScrollbackCount = 0;
339
+ this.container = container;
340
+ }
341
+ setup(cols, rows) {
342
+ this.cols = cols;
343
+ this.rows = rows;
344
+ this.container.innerHTML = "";
345
+ this.rowEls = [];
346
+ this.prevRowBg = [];
347
+ this._scrollbackRowEls = [];
348
+ this._renderedScrollbackCount = 0;
349
+ const fragment = document.createDocumentFragment();
350
+ for (let r = 0; r < rows; r++) {
351
+ const rowEl = document.createElement("div");
352
+ rowEl.className = "term-row";
353
+ fragment.appendChild(rowEl);
354
+ this.rowEls.push(rowEl);
355
+ }
356
+ this.container.appendChild(fragment);
357
+ this.prevCursorRow = -1;
358
+ this.prevCursorCol = -1;
359
+ }
360
+ _buildRowContent(rowEl, getCell, lineLen, cursorCol, rowIndex) {
361
+ rowEl.textContent = "";
362
+ let runStyle = "";
363
+ let runText = "";
364
+ let runStart = 0;
365
+ const flushRun = (endCol) => {
366
+ if (!runText) return;
367
+ if (cursorCol >= runStart && cursorCol < endCol) {
368
+ const offset = cursorCol - runStart;
369
+ const before = runText.slice(0, offset);
370
+ const cursorChar = runText[offset];
371
+ const after = runText.slice(offset + 1);
372
+ if (before) appendRun$1(rowEl, before, runStyle);
373
+ const cursorSpan = document.createElement("span");
374
+ cursorSpan.className = "term-cursor";
375
+ if (runStyle) cursorSpan.style.cssText = runStyle;
376
+ cursorSpan.textContent = cursorChar;
377
+ rowEl.appendChild(cursorSpan);
378
+ if (after) appendRun$1(rowEl, after, runStyle);
379
+ } else appendRun$1(rowEl, runText, runStyle);
380
+ };
381
+ for (let col = 0; col < this.cols; col++) {
382
+ const cell = getCell(col);
383
+ const inBounds = col < lineLen;
384
+ const cp = inBounds ? cell.char : 0;
385
+ if (inBounds && cp >= 9600 && cp <= 9631) {
386
+ flushRun(col);
387
+ const colors = resolveColors$1(cell.fg, cell.bg, cell.flags);
388
+ const span = document.createElement("span");
389
+ span.className = col === cursorCol ? "term-block term-cursor" : "term-block";
390
+ span.style.background = getBlockBackground$1(cp, colors.fg, colors.bg);
391
+ if (cell.flags & FLAG_DIM$1) span.style.opacity = "0.5";
392
+ rowEl.appendChild(span);
393
+ runStyle = "";
394
+ runText = "";
395
+ runStart = col + 1;
396
+ } else {
397
+ const ch = inBounds && cp >= 32 ? String.fromCodePoint(cp) : " ";
398
+ const style = inBounds ? buildCellStyle$1(cell.fg, cell.bg, cell.flags) : "";
399
+ if (style !== runStyle) {
400
+ flushRun(col);
401
+ runStyle = style;
402
+ runText = ch;
403
+ runStart = col;
404
+ } else runText += ch;
405
+ }
406
+ }
407
+ flushRun(this.cols);
408
+ let bgCss = "";
409
+ if (lineLen >= this.cols && this.cols > 0) {
410
+ const lastCell = getCell(this.cols - 1);
411
+ let bgC = lastCell.bg;
412
+ if (lastCell.flags & FLAG_REVERSE$1) {
413
+ bgC = lastCell.fg;
414
+ if (bgC === DEFAULT_COLOR$1) bgC = 7;
415
+ }
416
+ bgCss = colorToCSS$1(bgC) || "";
417
+ }
418
+ const boxShadow = bgCss ? `0 1px 0 ${bgCss}` : "";
419
+ if (rowIndex >= 0) {
420
+ if (bgCss !== (this.prevRowBg[rowIndex] ?? "")) {
421
+ rowEl.style.background = bgCss;
422
+ rowEl.style.boxShadow = boxShadow;
423
+ this.prevRowBg[rowIndex] = bgCss;
424
+ }
425
+ } else {
426
+ rowEl.style.background = bgCss;
427
+ rowEl.style.boxShadow = boxShadow;
428
+ }
429
+ }
430
+ _buildScrollbackRowEl(bridge, sbOffset) {
431
+ const rowEl = document.createElement("div");
432
+ rowEl.className = "term-row term-scrollback-row";
433
+ const lineLen = bridge.getScrollbackLineLen(sbOffset);
434
+ this._buildRowContent(rowEl, (col) => bridge.getScrollbackCell(sbOffset, col), lineLen, -1, -1);
435
+ return rowEl;
436
+ }
437
+ syncScrollback(bridge) {
438
+ const scrollbackCount = bridge.getScrollbackCount();
439
+ if (scrollbackCount === this._renderedScrollbackCount) return;
440
+ if (scrollbackCount > this._renderedScrollbackCount) {
441
+ const newCount = scrollbackCount - this._renderedScrollbackCount;
442
+ const firstGridRow = this.rowEls[0] ?? null;
443
+ const fragment = document.createDocumentFragment();
444
+ for (let i = newCount - 1; i >= 0; i--) {
445
+ const rowEl = this._buildScrollbackRowEl(bridge, i);
446
+ fragment.appendChild(rowEl);
447
+ this._scrollbackRowEls.push(rowEl);
448
+ }
449
+ this.container.insertBefore(fragment, firstGridRow);
450
+ } else {
451
+ const removeCount = this._renderedScrollbackCount - scrollbackCount;
452
+ for (let i = 0; i < removeCount; i++) {
453
+ const el = this._scrollbackRowEls.shift();
454
+ if (el) el.remove();
455
+ }
456
+ }
457
+ this._renderedScrollbackCount = scrollbackCount;
458
+ }
459
+ render(bridge) {
460
+ const rows = bridge.getRows();
461
+ const cols = bridge.getCols();
462
+ let resized = false;
463
+ if (rows !== this.rows || cols !== this.cols) {
464
+ this.setup(cols, rows);
465
+ resized = true;
466
+ }
467
+ this.syncScrollback(bridge);
468
+ const cursor = bridge.getCursor();
469
+ const cursorVisible = cursor.visible;
470
+ const needsCursorUpdate = cursor.row !== this.prevCursorRow || cursor.col !== this.prevCursorCol;
471
+ for (let r = 0; r < this.rows; r++) {
472
+ const isDirty = resized || bridge.isDirtyRow(r);
473
+ const hadCursor = r === this.prevCursorRow && needsCursorUpdate;
474
+ const hasCursor = r === cursor.row;
475
+ if (isDirty || hadCursor || hasCursor && needsCursorUpdate) {
476
+ const cCol = hasCursor && cursorVisible ? cursor.col : -1;
477
+ this._buildRowContent(this.rowEls[r], (col) => bridge.getCell(r, col), this.cols, cCol, r);
478
+ }
479
+ }
480
+ this.prevCursorRow = cursor.row;
481
+ this.prevCursorCol = cursor.col;
482
+ if (resized || bridge.isDirtyRow(this.rows - 1)) {
483
+ const bottomRight = bridge.getCell(this.rows - 1, this.cols - 1);
484
+ let gridBg = bottomRight.bg;
485
+ if (bottomRight.flags & FLAG_REVERSE$1) {
486
+ gridBg = bottomRight.fg;
487
+ if (gridBg === DEFAULT_COLOR$1) gridBg = 7;
488
+ }
489
+ const containerBg = colorToCSS$1(gridBg) || "";
490
+ if (containerBg !== this.prevContainerBg) {
491
+ this.container.style.background = containerBg;
492
+ this.prevContainerBg = containerBg;
493
+ }
494
+ }
495
+ bridge.clearDirty();
496
+ }
497
+ };
498
+ //#endregion
499
+ //#region node_modules/.pnpm/@wterm+dom@0.1.9/node_modules/@wterm/dom/dist/input.js
500
+ const NORMAL_KEYS = {
501
+ ArrowUp: "\x1B[A",
502
+ ArrowDown: "\x1B[B",
503
+ ArrowRight: "\x1B[C",
504
+ ArrowLeft: "\x1B[D",
505
+ Home: "\x1B[H",
506
+ End: "\x1B[F"
507
+ };
508
+ const APP_KEYS = {
509
+ ArrowUp: "\x1BOA",
510
+ ArrowDown: "\x1BOB",
511
+ ArrowRight: "\x1BOC",
512
+ ArrowLeft: "\x1BOD",
513
+ Home: "\x1BOH",
514
+ End: "\x1BOF"
515
+ };
516
+ const FIXED_KEYS = {
517
+ Enter: "\r",
518
+ Backspace: "",
519
+ Tab: " ",
520
+ Escape: "\x1B",
521
+ Insert: "\x1B[2~",
522
+ Delete: "\x1B[3~",
523
+ PageUp: "\x1B[5~",
524
+ PageDown: "\x1B[6~",
525
+ F1: "\x1BOP",
526
+ F2: "\x1BOQ",
527
+ F3: "\x1BOR",
528
+ F4: "\x1BOS",
529
+ F5: "\x1B[15~",
530
+ F6: "\x1B[17~",
531
+ F7: "\x1B[18~",
532
+ F8: "\x1B[19~",
533
+ F9: "\x1B[20~",
534
+ F10: "\x1B[21~",
535
+ F11: "\x1B[23~",
536
+ F12: "\x1B[24~"
537
+ };
538
+ var InputHandler = class {
539
+ constructor(element, onData, getBridge) {
540
+ this.composing = false;
541
+ this.element = element;
542
+ this.onData = onData;
543
+ this.getBridge = getBridge;
544
+ this.textarea = document.createElement("textarea");
545
+ this.textarea.setAttribute("autocapitalize", "off");
546
+ this.textarea.setAttribute("autocomplete", "off");
547
+ this.textarea.setAttribute("autocorrect", "off");
548
+ this.textarea.setAttribute("spellcheck", "false");
549
+ this.textarea.setAttribute("enterkeyhint", "send");
550
+ this.textarea.setAttribute("tabindex", "0");
551
+ this.textarea.setAttribute("aria-hidden", "true");
552
+ const s = this.textarea.style;
553
+ s.position = "absolute";
554
+ s.left = "-9999px";
555
+ s.top = "0";
556
+ s.width = "1px";
557
+ s.height = "1px";
558
+ s.opacity = "0";
559
+ s.overflow = "hidden";
560
+ s.border = "0";
561
+ s.padding = "0";
562
+ s.margin = "0";
563
+ s.outline = "none";
564
+ s.resize = "none";
565
+ s.pointerEvents = "none";
566
+ s.caretColor = "transparent";
567
+ s.color = "transparent";
568
+ s.background = "transparent";
569
+ element.appendChild(this.textarea);
570
+ this._onKeyDown = this.handleKeyDown.bind(this);
571
+ this._onPaste = this.handlePaste.bind(this);
572
+ this._onCompositionStart = this.handleCompositionStart.bind(this);
573
+ this._onCompositionEnd = this.handleCompositionEnd.bind(this);
574
+ this._onInput = this.handleInput.bind(this);
575
+ this._onFocus = () => this.element.classList.add("focused");
576
+ this._onBlur = () => this.element.classList.remove("focused");
577
+ this.textarea.addEventListener("keydown", this._onKeyDown);
578
+ this.textarea.addEventListener("paste", this._onPaste);
579
+ this.textarea.addEventListener("compositionstart", this._onCompositionStart);
580
+ this.textarea.addEventListener("compositionend", this._onCompositionEnd);
581
+ this.textarea.addEventListener("input", this._onInput);
582
+ this.textarea.addEventListener("focus", this._onFocus);
583
+ this.textarea.addEventListener("blur", this._onBlur);
584
+ }
585
+ focus() {
586
+ this.textarea.focus({ preventScroll: true });
587
+ }
588
+ destroy() {
589
+ this.textarea.removeEventListener("keydown", this._onKeyDown);
590
+ this.textarea.removeEventListener("paste", this._onPaste);
591
+ this.textarea.removeEventListener("compositionstart", this._onCompositionStart);
592
+ this.textarea.removeEventListener("compositionend", this._onCompositionEnd);
593
+ this.textarea.removeEventListener("input", this._onInput);
594
+ this.textarea.removeEventListener("focus", this._onFocus);
595
+ this.textarea.removeEventListener("blur", this._onBlur);
596
+ this.element.classList.remove("focused");
597
+ this.textarea.remove();
598
+ }
599
+ handleKeyDown(e) {
600
+ if (this.composing) return;
601
+ if ((e.metaKey || e.ctrlKey) && e.key === "c") {
602
+ const sel = window.getSelection();
603
+ if (sel && sel.toString().length > 0) return;
604
+ }
605
+ if ((e.metaKey || e.ctrlKey) && e.key === "v") {
606
+ this.textarea.focus();
607
+ return;
608
+ }
609
+ if (e.metaKey && !e.ctrlKey) {
610
+ if (e.key === "Backspace") {
611
+ e.preventDefault();
612
+ this.onData("");
613
+ } else if (e.key === "a") {
614
+ e.preventDefault();
615
+ const sel = window.getSelection();
616
+ if (sel) {
617
+ const range = document.createRange();
618
+ range.selectNodeContents(this.element);
619
+ sel.removeAllRanges();
620
+ sel.addRange(range);
621
+ }
622
+ }
623
+ return;
624
+ }
625
+ e.preventDefault();
626
+ const seq = this.keyToSequence(e);
627
+ if (seq) this.onData(seq);
628
+ }
629
+ handlePaste(e) {
630
+ e.preventDefault();
631
+ const text = e.clipboardData?.getData("text");
632
+ if (!text) return;
633
+ const bridge = this.getBridge();
634
+ if (bridge && bridge.bracketedPaste()) {
635
+ const safe = text.replace(/\x1b/g, "");
636
+ this.onData("\x1B[200~" + safe + "\x1B[201~");
637
+ } else this.onData(text);
638
+ }
639
+ handleCompositionStart() {
640
+ this.composing = true;
641
+ }
642
+ handleCompositionEnd(e) {
643
+ this.composing = false;
644
+ if (e.data) this.onData(e.data);
645
+ this.textarea.value = "";
646
+ }
647
+ handleInput() {
648
+ if (this.composing) return;
649
+ const value = this.textarea.value;
650
+ if (value) {
651
+ this.onData(value);
652
+ this.textarea.value = "";
653
+ }
654
+ }
655
+ keyToSequence(e) {
656
+ if (e.ctrlKey && !e.altKey && !e.metaKey) {
657
+ if (e.key.length === 1) {
658
+ const code = e.key.toLowerCase().charCodeAt(0);
659
+ if (code >= 97 && code <= 122) return String.fromCharCode(code - 96);
660
+ }
661
+ if (e.key === "[") return "\x1B";
662
+ if (e.key === "\\") return "";
663
+ if (e.key === "]") return "";
664
+ if (e.key === "^") return "";
665
+ if (e.key === "_") return "";
666
+ }
667
+ if (e.key === "Enter" && e.shiftKey) return "\x1B[13;2u";
668
+ if (e.key === "Tab" && e.shiftKey) return "\x1B[Z";
669
+ const fixed = FIXED_KEYS[e.key];
670
+ if (fixed) return e.altKey ? "\x1B" + fixed : fixed;
671
+ const bridge = this.getBridge();
672
+ const nav = (bridge && bridge.cursorKeysApp() ? APP_KEYS : NORMAL_KEYS)[e.key];
673
+ if (nav) return e.altKey ? "\x1B" + nav : nav;
674
+ if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) return e.altKey ? "\x1B" + e.key : e.key;
675
+ return null;
676
+ }
677
+ };
678
+ //#endregion
679
+ //#region node_modules/.pnpm/@wterm+dom@0.1.9/node_modules/@wterm/dom/dist/debug.js
680
+ const FLAG_NAMES = {
681
+ 1: "bold",
682
+ 2: "dim",
683
+ 4: "italic",
684
+ 8: "underline",
685
+ 16: "blink",
686
+ 32: "reverse",
687
+ 64: "invisible",
688
+ 128: "strikethrough"
689
+ };
690
+ function flagsToNames(flags) {
691
+ const names = [];
692
+ for (const [bit, name] of Object.entries(FLAG_NAMES)) if (flags & Number(bit)) names.push(name);
693
+ return names;
694
+ }
695
+ const ESC$2 = 27;
696
+ function scanSequences(data) {
697
+ const entries = [];
698
+ const ts = Date.now();
699
+ let i = 0;
700
+ let textStart = 0;
701
+ const flushText = () => {
702
+ if (i > textStart) {
703
+ const raw = data.slice(textStart, i);
704
+ if (raw.length > 0 && !/^[\x00-\x1f]+$/.test(raw)) entries.push({
705
+ ts,
706
+ type: "text",
707
+ raw: raw.slice(0, 60)
708
+ });
709
+ }
710
+ };
711
+ while (i < data.length) {
712
+ if (data.charCodeAt(i) !== ESC$2) {
713
+ i++;
714
+ continue;
715
+ }
716
+ flushText();
717
+ const seqStart = i;
718
+ i++;
719
+ if (i >= data.length) break;
720
+ const next = data[i];
721
+ if (next === "[") {
722
+ i++;
723
+ let priv = "";
724
+ if (i < data.length && (data[i] === "?" || data[i] === ">" || data[i] === "!")) {
725
+ priv = data[i];
726
+ i++;
727
+ }
728
+ let paramStr = "";
729
+ while (i < data.length && (data.charCodeAt(i) >= 48 && data.charCodeAt(i) <= 59 || data[i] === ":")) {
730
+ paramStr += data[i];
731
+ i++;
732
+ }
733
+ while (i < data.length && data.charCodeAt(i) >= 32 && data.charCodeAt(i) <= 47) i++;
734
+ let final = "";
735
+ if (i < data.length && data.charCodeAt(i) >= 64 && data.charCodeAt(i) <= 126) {
736
+ final = data[i];
737
+ i++;
738
+ }
739
+ const raw = data.slice(seqStart, i);
740
+ const params = paramStr ? paramStr.split(/[;:]/).map(Number).filter((n) => !isNaN(n)) : [];
741
+ const type = final === "m" ? "sgr" : "csi";
742
+ entries.push({
743
+ ts,
744
+ type,
745
+ raw,
746
+ params: params.length > 0 ? params : void 0,
747
+ private: priv || void 0,
748
+ final
749
+ });
750
+ } else if (next === "]") {
751
+ i++;
752
+ while (i < data.length && data.charCodeAt(i) !== 7 && !(data.charCodeAt(i) === ESC$2 && i + 1 < data.length && data[i + 1] === "\\")) i++;
753
+ if (i < data.length) {
754
+ if (data.charCodeAt(i) === 7) i++;
755
+ else if (data.charCodeAt(i) === ESC$2) i += 2;
756
+ }
757
+ const raw = data.slice(seqStart, i);
758
+ entries.push({
759
+ ts,
760
+ type: "osc",
761
+ raw: raw.slice(0, 80)
762
+ });
763
+ } else if (next >= " " && next <= "~") {
764
+ i++;
765
+ entries.push({
766
+ ts,
767
+ type: "esc",
768
+ raw: data.slice(seqStart, i),
769
+ final: next
770
+ });
771
+ } else i++;
772
+ textStart = i;
773
+ }
774
+ flushText();
775
+ return entries;
776
+ }
777
+ const MAX_TRACES = 500;
778
+ var DebugAdapter = class {
779
+ constructor() {
780
+ this._traces = [];
781
+ this._bridge = null;
782
+ this._perf = {
783
+ frameCount: 0,
784
+ totalRenderMs: 0,
785
+ avgRenderMs: 0,
786
+ maxRenderMs: 0,
787
+ lastDirtyRows: 0
788
+ };
789
+ }
790
+ get traces() {
791
+ return this._traces;
792
+ }
793
+ get perf() {
794
+ return this._perf;
795
+ }
796
+ setBridge(bridge) {
797
+ this._bridge = bridge;
798
+ }
799
+ traceWrite(data) {
800
+ const entries = scanSequences(typeof data === "string" ? data : new TextDecoder().decode(data));
801
+ for (const entry of entries) this._traces.push(entry);
802
+ if (this._traces.length > MAX_TRACES) this._traces = this._traces.slice(-MAX_TRACES);
803
+ }
804
+ recordRender(renderMs, dirtyRows) {
805
+ this._perf.frameCount++;
806
+ this._perf.totalRenderMs += renderMs;
807
+ this._perf.avgRenderMs = this._perf.totalRenderMs / this._perf.frameCount;
808
+ if (renderMs > this._perf.maxRenderMs) this._perf.maxRenderMs = renderMs;
809
+ this._perf.lastDirtyRows = dirtyRows;
810
+ }
811
+ resetPerf() {
812
+ this._perf = {
813
+ frameCount: 0,
814
+ totalRenderMs: 0,
815
+ avgRenderMs: 0,
816
+ maxRenderMs: 0,
817
+ lastDirtyRows: 0
818
+ };
819
+ }
820
+ cell(row, col) {
821
+ if (!this._bridge) return null;
822
+ const c = this._bridge.getCell(row, col);
823
+ return {
824
+ ...c,
825
+ charStr: c.char >= 32 ? String.fromCodePoint(c.char) : "",
826
+ flagNames: flagsToNames(c.flags)
827
+ };
828
+ }
829
+ row(row) {
830
+ if (!this._bridge) return null;
831
+ const cols = this._bridge.getCols();
832
+ const cells = [];
833
+ for (let c = 0; c < cols; c++) cells.push(this.cell(row, c));
834
+ return cells;
835
+ }
836
+ grid() {
837
+ if (!this._bridge) return null;
838
+ const cursor = this._bridge.getCursor();
839
+ return {
840
+ rows: this._bridge.getRows(),
841
+ cols: this._bridge.getCols(),
842
+ cursor,
843
+ altScreen: this._bridge.usingAltScreen(),
844
+ scrollbackCount: this._bridge.getScrollbackCount()
845
+ };
846
+ }
847
+ unhandled() {
848
+ if (!this._bridge) return [];
849
+ return this._bridge.getUnhandledSequences();
850
+ }
851
+ dump(count = 50) {
852
+ const entries = this._traces.slice(-count);
853
+ console.group(`%cwterm debug — last ${entries.length} traces`, "color: #569cd6; font-weight: bold");
854
+ for (const e of entries) {
855
+ const badge = e.type === "sgr" ? "%cSGR" : e.type === "csi" ? "%cCSI" : e.type === "osc" ? "%cOSC" : e.type === "esc" ? "%cESC" : "%cTXT";
856
+ const color = e.type === "sgr" ? "background:#2d5a27;color:#fff;padding:1px 4px;border-radius:2px" : e.type === "csi" ? "background:#1e4a7a;color:#fff;padding:1px 4px;border-radius:2px" : "background:#555;color:#fff;padding:1px 4px;border-radius:2px";
857
+ const detail = [
858
+ e.private ? `private=${e.private}` : "",
859
+ e.params ? `params=[${e.params}]` : "",
860
+ e.final ? `final=${e.final}` : ""
861
+ ].filter(Boolean).join(" ");
862
+ console.log(`${badge} ${e.raw.slice(0, 40)}`, color, detail ? ` ${detail}` : "");
863
+ }
864
+ console.groupEnd();
865
+ }
866
+ dumpUnhandled() {
867
+ const entries = this.unhandled();
868
+ if (entries.length === 0) {
869
+ console.log("%cwterm debug — no unhandled sequences", "color: #6a9955");
870
+ return;
871
+ }
872
+ console.group(`%cwterm debug — ${entries.length} unhandled sequences`, "color: #d7ba7d; font-weight: bold");
873
+ for (const e of entries) console.log(` final=${e.final} private=${e.private || "-"} params=[${e.params.slice(0, e.paramCount)}]`);
874
+ console.groupEnd();
875
+ }
876
+ };
877
+ //#endregion
878
+ //#region node_modules/.pnpm/@wterm+dom@0.1.9/node_modules/@wterm/dom/dist/wterm.js
879
+ var WTerm = class {
880
+ constructor(element, options = {}) {
881
+ this.bridge = null;
882
+ this.debug = null;
883
+ this.renderer = null;
884
+ this.input = null;
885
+ this.rafId = null;
886
+ this.resizeObserver = null;
887
+ this._destroyed = false;
888
+ this._shouldScrollToBottom = false;
889
+ this._rowHeight = 0;
890
+ this.element = element;
891
+ this.wasmUrl = options.wasmUrl;
892
+ this.cols = options.cols || 80;
893
+ this.rows = options.rows || 24;
894
+ this.autoResize = options.autoResize !== false;
895
+ this._debugEnabled = options.debug ?? false;
896
+ this.onData = options.onData || null;
897
+ this.onTitle = options.onTitle || null;
898
+ this.onResize = options.onResize || null;
899
+ this._container = document.createElement("div");
900
+ this._container.className = "term-grid";
901
+ this.element.appendChild(this._container);
902
+ this.element.classList.add("wterm");
903
+ if (options.cursorBlink) this.element.classList.add("cursor-blink");
904
+ this._onClickFocus = () => {
905
+ const sel = window.getSelection();
906
+ if (!sel || sel.isCollapsed) this.input?.focus();
907
+ };
908
+ this.element.addEventListener("click", this._onClickFocus);
909
+ }
910
+ async init() {
911
+ try {
912
+ this.bridge = await WasmBridge.load(this.wasmUrl);
913
+ if (this._destroyed) return this;
914
+ this.bridge.init(this.cols, this.rows);
915
+ if (this._debugEnabled) {
916
+ this.debug = new DebugAdapter();
917
+ this.debug.setBridge(this.bridge);
918
+ globalThis.__wterm = this;
919
+ }
920
+ this._setRowHeight();
921
+ this.renderer = new Renderer(this._container);
922
+ this.renderer.setup(this.cols, this.rows);
923
+ this.input = new InputHandler(this.element, (data) => {
924
+ this._scrollToBottom();
925
+ if (this.onData) this.onData(data);
926
+ else this.write(data);
927
+ }, () => this.bridge);
928
+ if (this.autoResize) this._setupResizeObserver();
929
+ else this._lockHeight();
930
+ this.input.focus();
931
+ this._initialRender();
932
+ } catch (err) {
933
+ this.destroy();
934
+ throw new Error(`wterm: failed to initialize: ${err instanceof Error ? err.message : err}`);
935
+ }
936
+ return this;
937
+ }
938
+ _isScrolledToBottom() {
939
+ const el = this.element;
940
+ return el.scrollHeight - el.scrollTop - el.clientHeight < 5;
941
+ }
942
+ _scrollToBottom() {
943
+ const el = this.element;
944
+ const maxScroll = el.scrollHeight - el.clientHeight;
945
+ if (maxScroll <= 0) {
946
+ el.scrollTop = 0;
947
+ return;
948
+ }
949
+ const rh = this._rowHeight || 17;
950
+ el.scrollTop = Math.floor(maxScroll / rh) * rh;
951
+ }
952
+ write(data) {
953
+ if (!this.bridge) return;
954
+ if (this.debug) this.debug.traceWrite(data);
955
+ this._shouldScrollToBottom = this._isScrolledToBottom();
956
+ if (typeof data === "string") this.bridge.writeString(data);
957
+ else this.bridge.writeRaw(data);
958
+ this._scheduleRender();
959
+ }
960
+ resize(cols, rows) {
961
+ if (!this.bridge) return;
962
+ this._shouldScrollToBottom = this._isScrolledToBottom();
963
+ this.cols = cols;
964
+ this.rows = rows;
965
+ this.bridge.resize(cols, rows);
966
+ this.renderer?.setup(cols, rows);
967
+ this._scheduleRender();
968
+ if (this.onResize) this.onResize(cols, rows);
969
+ }
970
+ focus() {
971
+ if (this.input) this.input.focus();
972
+ else this.element.focus();
973
+ }
974
+ _scheduleRender() {
975
+ if (this.rafId == null) this.rafId = requestAnimationFrame(() => {
976
+ this.rafId = null;
977
+ this._doRender();
978
+ });
979
+ }
980
+ _initialRender() {
981
+ this._doRender();
982
+ }
983
+ _doRender() {
984
+ if (!this.bridge || !this.renderer) return;
985
+ let dirtyCount = 0;
986
+ const t0 = this.debug ? performance.now() : 0;
987
+ if (this.debug) {
988
+ for (let r = 0; r < this.rows; r++) if (this.bridge.isDirtyRow(r)) dirtyCount++;
989
+ }
990
+ this.renderer.render(this.bridge);
991
+ if (this.debug) this.debug.recordRender(performance.now() - t0, dirtyCount);
992
+ const hasScrollback = this.bridge.getScrollbackCount() > 0;
993
+ this.element.classList.toggle("has-scrollback", hasScrollback);
994
+ if (this._shouldScrollToBottom) this._scrollToBottom();
995
+ else if (!hasScrollback && this.element.scrollTop !== 0) this.element.scrollTop = 0;
996
+ const title = this.bridge.getTitle();
997
+ if (title !== null && this.onTitle) this.onTitle(title);
998
+ const response = this.bridge.getResponse();
999
+ if (response !== null && this.onData) this.onData(response);
1000
+ }
1001
+ _lockHeight() {
1002
+ const rh = this._rowHeight || 17;
1003
+ const gridHeight = this.rows * rh;
1004
+ const cs = getComputedStyle(this.element);
1005
+ let extra = (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);
1006
+ if (cs.boxSizing === "border-box") extra += (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);
1007
+ this.element.style.height = `${gridHeight + extra}px`;
1008
+ }
1009
+ _setRowHeight() {
1010
+ const probe = document.createElement("div");
1011
+ probe.className = "term-row";
1012
+ probe.style.visibility = "hidden";
1013
+ probe.style.position = "absolute";
1014
+ probe.textContent = "W";
1015
+ this._container.appendChild(probe);
1016
+ const h = probe.getBoundingClientRect().height;
1017
+ probe.remove();
1018
+ if (h > 0) {
1019
+ const rh = Math.ceil(h);
1020
+ this._rowHeight = rh;
1021
+ this.element.style.setProperty("--term-row-height", `${rh}px`);
1022
+ }
1023
+ }
1024
+ _measureCharSize() {
1025
+ const row = document.createElement("div");
1026
+ row.className = "term-row";
1027
+ row.style.visibility = "hidden";
1028
+ row.style.position = "absolute";
1029
+ const probe = document.createElement("span");
1030
+ probe.textContent = "W";
1031
+ row.appendChild(probe);
1032
+ this._container.appendChild(row);
1033
+ const charWidth = probe.getBoundingClientRect().width;
1034
+ const rowHeight = row.getBoundingClientRect().height;
1035
+ row.remove();
1036
+ if (charWidth === 0 || rowHeight === 0) return null;
1037
+ this._rowHeight = rowHeight;
1038
+ return {
1039
+ charWidth,
1040
+ rowHeight
1041
+ };
1042
+ }
1043
+ _setupResizeObserver() {
1044
+ const initial = this._measureCharSize();
1045
+ if (!initial) return;
1046
+ let { charWidth, rowHeight } = initial;
1047
+ this.resizeObserver = new ResizeObserver((entries) => {
1048
+ const measured = this._measureCharSize();
1049
+ if (measured) {
1050
+ charWidth = measured.charWidth;
1051
+ rowHeight = measured.rowHeight;
1052
+ }
1053
+ for (const entry of entries) {
1054
+ const { width, height } = entry.contentRect;
1055
+ const newCols = Math.max(1, Math.floor(width / charWidth));
1056
+ const newRows = Math.max(1, Math.floor(height / rowHeight));
1057
+ if (newCols !== this.cols || newRows !== this.rows) this.resize(newCols, newRows);
1058
+ }
1059
+ });
1060
+ this.resizeObserver.observe(this.element);
1061
+ }
1062
+ destroy() {
1063
+ this._destroyed = true;
1064
+ if (this.rafId != null) cancelAnimationFrame(this.rafId);
1065
+ if (this.resizeObserver) this.resizeObserver.disconnect();
1066
+ if (this.input) this.input.destroy();
1067
+ this.element.removeEventListener("click", this._onClickFocus);
1068
+ this.element.innerHTML = "";
1069
+ if (this.debug && globalThis.__wterm === this) delete globalThis.__wterm;
1070
+ this.debug = null;
1071
+ }
1072
+ };
1073
+ //#endregion
1074
+ //#region packages/protocol/src/index.ts
1075
+ function createPongControlFrame() {
1076
+ return JSON.stringify({ type: "pong" });
1077
+ }
1078
+ function createResizeControlFrame(cols, rows) {
1079
+ return JSON.stringify({
1080
+ cols,
1081
+ rows,
1082
+ type: "resize"
1083
+ });
1084
+ }
1085
+ function parseAittyControlFrame(data) {
1086
+ try {
1087
+ const parsed = JSON.parse(data);
1088
+ if (!parsed || typeof parsed !== "object" || !("type" in parsed)) return null;
1089
+ if (typeof parsed.type !== "string") return null;
1090
+ return parsed;
1091
+ } catch {
1092
+ return null;
1093
+ }
1094
+ }
1095
+ function normalizeTheme(theme) {
1096
+ if (typeof theme !== "string") return;
1097
+ const normalized = theme.trim();
1098
+ return normalized.length > 0 ? normalized : void 0;
1099
+ }
1100
+ //#endregion
1101
+ //#region src/frontend/ansi-sequences.ts
1102
+ const ALT_SCREEN_PARAMS = new Set([
1103
+ 47,
1104
+ 1047,
1105
+ 1049
1106
+ ]);
1107
+ function parseCsiParams(paramBuffer) {
1108
+ if (!paramBuffer) return [];
1109
+ return paramBuffer.split(/[;:]/).map((value) => Number(value)).filter((value) => !Number.isNaN(value));
1110
+ }
1111
+ function nextAltScreenState(currentState, privateMarker, paramBuffer, finalByte) {
1112
+ if (privateMarker !== "?" || finalByte !== "h" && finalByte !== "l") return currentState;
1113
+ if (!parseCsiParams(paramBuffer).some((value) => ALT_SCREEN_PARAMS.has(value))) return currentState;
1114
+ return finalByte === "h";
1115
+ }
1116
+ //#endregion
1117
+ //#region src/frontend/cell-width.ts
1118
+ function isWideCodePoint(codePoint) {
1119
+ return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 42191 && codePoint !== 12351 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127744 && codePoint <= 128591 || codePoint >= 129280 && codePoint <= 129535 || codePoint >= 131072 && codePoint <= 262141);
1120
+ }
1121
+ function cellWidthForCodePoint(codePoint) {
1122
+ return isWideCodePoint(codePoint) ? 2 : 1;
1123
+ }
1124
+ //#endregion
1125
+ //#region src/frontend/ansi-style-tracker.ts
1126
+ const ESC$1 = "\x1B";
1127
+ function createBlankRow(cols) {
1128
+ return Array.from({ length: cols }, () => null);
1129
+ }
1130
+ function cloneRow(row) {
1131
+ return row.map((cell) => {
1132
+ if (!cell) return null;
1133
+ return {
1134
+ bg: cell.bg ?? null,
1135
+ displayStart: cell.displayStart,
1136
+ fg: cell.fg ?? null,
1137
+ hidden: cell.hidden,
1138
+ width: cell.width
1139
+ };
1140
+ });
1141
+ }
1142
+ function clamp$2(value, min, max) {
1143
+ return Math.min(max, Math.max(min, value));
1144
+ }
1145
+ function createBuffer(cols, rows) {
1146
+ return {
1147
+ cursor: {
1148
+ col: 0,
1149
+ displayCol: 0,
1150
+ row: 0
1151
+ },
1152
+ rows: Array.from({ length: rows }, () => createBlankRow(cols)),
1153
+ savedCursor: {
1154
+ col: 0,
1155
+ displayCol: 0,
1156
+ row: 0
1157
+ },
1158
+ scrollback: []
1159
+ };
1160
+ }
1161
+ function makeRgbCss(red, green, blue) {
1162
+ return `rgb(${clamp$2(red, 0, 255)}, ${clamp$2(green, 0, 255)}, ${clamp$2(blue, 0, 255)})`;
1163
+ }
1164
+ function isPlainCharacter(character) {
1165
+ return character >= " " && character !== "";
1166
+ }
1167
+ function createAnsiStyleTracker(options = {}) {
1168
+ let cols = Math.max(1, options.cols ?? 80);
1169
+ let rows = Math.max(1, options.rows ?? 24);
1170
+ let mainBuffer = createBuffer(cols, rows);
1171
+ let altBuffer = createBuffer(cols, rows);
1172
+ let currentStyle = {
1173
+ bg: null,
1174
+ fg: null
1175
+ };
1176
+ let parserState = "text";
1177
+ let csiPrivate = "";
1178
+ let csiParams = "";
1179
+ let decoder = new TextDecoder();
1180
+ let useAltBuffer = false;
1181
+ let renderHints = {
1182
+ clearScreen: false,
1183
+ styleChanged: false
1184
+ };
1185
+ const activeBuffer = () => useAltBuffer ? altBuffer : mainBuffer;
1186
+ const clampCursor = (cursor) => {
1187
+ cursor.row = clamp$2(cursor.row, 0, rows - 1);
1188
+ cursor.col = clamp$2(cursor.col, 0, cols - 1);
1189
+ cursor.displayCol = clamp$2(cursor.displayCol, 0, cols - 1);
1190
+ };
1191
+ const cellDisplayStart = (row, col) => row[col]?.displayStart ?? col;
1192
+ const cellWidth = (row, col) => row[col]?.width ?? 1;
1193
+ const makeCellState = (style, sourceCol, displayStart, width, hidden = false) => {
1194
+ if (!hidden && style.fg === null && style.bg === null && displayStart === sourceCol && width === 1) return null;
1195
+ return {
1196
+ bg: style.bg,
1197
+ displayStart,
1198
+ fg: style.fg,
1199
+ hidden,
1200
+ width
1201
+ };
1202
+ };
1203
+ const markCellHidden = (row, col) => {
1204
+ const cell = row[col];
1205
+ row[col] = {
1206
+ bg: cell?.bg ?? null,
1207
+ displayStart: cellDisplayStart(row, col),
1208
+ fg: cell?.fg ?? null,
1209
+ hidden: true,
1210
+ width: cellWidth(row, col)
1211
+ };
1212
+ };
1213
+ const hideCellsCoveredByDisplayRange = (row, displayStart, width, sourceCol) => {
1214
+ const displayEnd = displayStart + width;
1215
+ for (let col = 0; col < cols; col += 1) {
1216
+ if (col === sourceCol) continue;
1217
+ const cellStart = cellDisplayStart(row, col);
1218
+ const cellEnd = cellStart + cellWidth(row, col);
1219
+ if (cellStart < displayEnd && cellEnd > displayStart) markCellHidden(row, col);
1220
+ }
1221
+ };
1222
+ const storeCellAtCursor = (width) => {
1223
+ const buffer = activeBuffer();
1224
+ const row = buffer.rows[buffer.cursor.row];
1225
+ if (!row) return;
1226
+ const displayStart = buffer.cursor.displayCol;
1227
+ hideCellsCoveredByDisplayRange(row, displayStart, width, buffer.cursor.col);
1228
+ row[buffer.cursor.col] = makeCellState(currentStyle, buffer.cursor.col, displayStart, width);
1229
+ };
1230
+ const scrollActiveBuffer = () => {
1231
+ const buffer = activeBuffer();
1232
+ const droppedRow = buffer.rows.shift() ?? createBlankRow(cols);
1233
+ buffer.rows.push(createBlankRow(cols));
1234
+ if (!useAltBuffer) mainBuffer.scrollback.unshift(cloneRow(droppedRow));
1235
+ };
1236
+ const moveCursorTo = (buffer, row, col) => {
1237
+ buffer.cursor.row = clamp$2(row, 0, rows - 1);
1238
+ buffer.cursor.col = clamp$2(col, 0, cols - 1);
1239
+ buffer.cursor.displayCol = cellDisplayStart(buffer.rows[buffer.cursor.row] ?? [], buffer.cursor.col);
1240
+ };
1241
+ const advanceCursor = (width) => {
1242
+ const buffer = activeBuffer();
1243
+ if (buffer.cursor.col < cols - 1) {
1244
+ buffer.cursor.col += 1;
1245
+ buffer.cursor.displayCol = clamp$2(buffer.cursor.displayCol + width, 0, cols - 1);
1246
+ return;
1247
+ }
1248
+ buffer.cursor.col = 0;
1249
+ buffer.cursor.displayCol = 0;
1250
+ if (buffer.cursor.row < rows - 1) {
1251
+ buffer.cursor.row += 1;
1252
+ return;
1253
+ }
1254
+ scrollActiveBuffer();
1255
+ };
1256
+ const clearRowRange = (rowIndex, startCol, endCol) => {
1257
+ const row = activeBuffer().rows[rowIndex];
1258
+ if (!row) return;
1259
+ for (let index = startCol; index <= endCol; index += 1) row[index] = null;
1260
+ };
1261
+ const clearScreen = () => {
1262
+ const buffer = activeBuffer();
1263
+ buffer.rows = Array.from({ length: rows }, () => createBlankRow(cols));
1264
+ renderHints.clearScreen = true;
1265
+ };
1266
+ const resetTerminalState = () => {
1267
+ mainBuffer = createBuffer(cols, rows);
1268
+ altBuffer = createBuffer(cols, rows);
1269
+ currentStyle = {
1270
+ bg: null,
1271
+ fg: null
1272
+ };
1273
+ useAltBuffer = false;
1274
+ renderHints.clearScreen = true;
1275
+ };
1276
+ const resizeRows = (buffer, nextRows) => {
1277
+ if (nextRows === buffer.rows.length) return;
1278
+ if (nextRows > buffer.rows.length) {
1279
+ const missing = nextRows - buffer.rows.length;
1280
+ buffer.rows = [...buffer.rows, ...Array.from({ length: missing }, () => createBlankRow(cols))];
1281
+ return;
1282
+ }
1283
+ const removeCount = buffer.rows.length - nextRows;
1284
+ const removedRows = buffer.rows.splice(0, removeCount);
1285
+ if (buffer === mainBuffer) for (const row of removedRows) mainBuffer.scrollback.unshift(cloneRow(row));
1286
+ moveCursorTo(buffer, Math.max(0, buffer.cursor.row - removeCount), buffer.cursor.col);
1287
+ };
1288
+ const resizeCols = (buffer, nextCols) => {
1289
+ buffer.rows = buffer.rows.map((row) => {
1290
+ if (nextCols === row.length) return row;
1291
+ if (nextCols > row.length) return [...row, ...Array.from({ length: nextCols - row.length }, () => null)];
1292
+ return row.slice(0, nextCols);
1293
+ });
1294
+ buffer.cursor.col = clamp$2(buffer.cursor.col, 0, nextCols - 1);
1295
+ buffer.cursor.displayCol = clamp$2(buffer.cursor.displayCol, 0, nextCols - 1);
1296
+ buffer.savedCursor.col = clamp$2(buffer.savedCursor.col, 0, nextCols - 1);
1297
+ buffer.savedCursor.displayCol = clamp$2(buffer.savedCursor.displayCol, 0, nextCols - 1);
1298
+ };
1299
+ const setAltBuffer = (nextState) => {
1300
+ if (nextState === useAltBuffer) return;
1301
+ if (nextState) {
1302
+ mainBuffer.savedCursor = { ...mainBuffer.cursor };
1303
+ altBuffer = createBuffer(cols, rows);
1304
+ useAltBuffer = true;
1305
+ return;
1306
+ }
1307
+ useAltBuffer = false;
1308
+ mainBuffer.cursor = { ...mainBuffer.savedCursor };
1309
+ };
1310
+ const handleSgr = (params) => {
1311
+ const values = params.length === 0 ? [0] : params;
1312
+ renderHints.styleChanged = true;
1313
+ for (let index = 0; index < values.length; index += 1) {
1314
+ const value = values[index] ?? 0;
1315
+ if (value === 0) {
1316
+ currentStyle = {
1317
+ bg: null,
1318
+ fg: null
1319
+ };
1320
+ continue;
1321
+ }
1322
+ if (value === 39 || value >= 30 && value <= 37 || value >= 90 && value <= 97) {
1323
+ currentStyle.fg = null;
1324
+ continue;
1325
+ }
1326
+ if (value === 49 || value >= 40 && value <= 47 || value >= 100 && value <= 107) {
1327
+ currentStyle.bg = null;
1328
+ continue;
1329
+ }
1330
+ if (value === 38 || value === 48) {
1331
+ const target = value === 38 ? "fg" : "bg";
1332
+ const mode = values[index + 1];
1333
+ if (mode === 2 && index + 4 < values.length) {
1334
+ currentStyle[target] = makeRgbCss(values[index + 2], values[index + 3], values[index + 4]);
1335
+ index += 4;
1336
+ continue;
1337
+ }
1338
+ if (mode === 5 && index + 2 < values.length) {
1339
+ currentStyle[target] = null;
1340
+ index += 2;
1341
+ }
1342
+ }
1343
+ }
1344
+ };
1345
+ const handleEraseDisplay = (mode) => {
1346
+ const buffer = activeBuffer();
1347
+ if (mode === 2) {
1348
+ clearScreen();
1349
+ return;
1350
+ }
1351
+ if (mode === 0) {
1352
+ clearRowRange(buffer.cursor.row, buffer.cursor.col, cols - 1);
1353
+ for (let row = buffer.cursor.row + 1; row < rows; row += 1) clearRowRange(row, 0, cols - 1);
1354
+ return;
1355
+ }
1356
+ if (mode === 1) {
1357
+ for (let row = 0; row < buffer.cursor.row; row += 1) clearRowRange(row, 0, cols - 1);
1358
+ clearRowRange(buffer.cursor.row, 0, buffer.cursor.col);
1359
+ }
1360
+ };
1361
+ const handleEraseLine = (mode) => {
1362
+ const cursor = activeBuffer().cursor;
1363
+ if (mode === 2) {
1364
+ clearRowRange(cursor.row, 0, cols - 1);
1365
+ return;
1366
+ }
1367
+ if (mode === 1) {
1368
+ clearRowRange(cursor.row, 0, cursor.col);
1369
+ return;
1370
+ }
1371
+ clearRowRange(cursor.row, cursor.col, cols - 1);
1372
+ };
1373
+ const handleCsi = (finalByte) => {
1374
+ const params = parseCsiParams(csiParams);
1375
+ const buffer = activeBuffer();
1376
+ setAltBuffer(nextAltScreenState(useAltBuffer, csiPrivate, csiParams, finalByte));
1377
+ switch (finalByte) {
1378
+ case "A":
1379
+ moveCursorTo(buffer, buffer.cursor.row - Math.max(1, params[0] ?? 1), buffer.cursor.col);
1380
+ break;
1381
+ case "B":
1382
+ moveCursorTo(buffer, buffer.cursor.row + Math.max(1, params[0] ?? 1), buffer.cursor.col);
1383
+ break;
1384
+ case "C":
1385
+ moveCursorTo(buffer, buffer.cursor.row, buffer.cursor.col + Math.max(1, params[0] ?? 1));
1386
+ break;
1387
+ case "D":
1388
+ moveCursorTo(buffer, buffer.cursor.row, buffer.cursor.col - Math.max(1, params[0] ?? 1));
1389
+ break;
1390
+ case "G":
1391
+ moveCursorTo(buffer, buffer.cursor.row, (params[0] ?? 1) - 1);
1392
+ break;
1393
+ case "H":
1394
+ case "f":
1395
+ moveCursorTo(buffer, (params[0] ?? 1) - 1, (params[1] ?? 1) - 1);
1396
+ break;
1397
+ case "J":
1398
+ handleEraseDisplay(params[0] ?? 0);
1399
+ break;
1400
+ case "K":
1401
+ handleEraseLine(params[0] ?? 0);
1402
+ break;
1403
+ case "m":
1404
+ handleSgr(params);
1405
+ break;
1406
+ case "s":
1407
+ buffer.savedCursor = { ...buffer.cursor };
1408
+ break;
1409
+ case "u":
1410
+ buffer.cursor = { ...buffer.savedCursor };
1411
+ break;
1412
+ default: break;
1413
+ }
1414
+ };
1415
+ const writeCharacter = (character) => {
1416
+ const width = cellWidthForCodePoint(character.codePointAt(0) ?? 32);
1417
+ storeCellAtCursor(width);
1418
+ advanceCursor(width);
1419
+ };
1420
+ const processTextCharacter = (character) => {
1421
+ const buffer = activeBuffer();
1422
+ if (character === ESC$1) {
1423
+ parserState = "escape";
1424
+ return;
1425
+ }
1426
+ if (character === "\b") {
1427
+ moveCursorTo(buffer, buffer.cursor.row, buffer.cursor.col - 1);
1428
+ return;
1429
+ }
1430
+ if (character === "\n") {
1431
+ if (buffer.cursor.row < rows - 1) buffer.cursor.row += 1;
1432
+ else scrollActiveBuffer();
1433
+ return;
1434
+ }
1435
+ if (character === "\r") {
1436
+ buffer.cursor.col = 0;
1437
+ buffer.cursor.displayCol = 0;
1438
+ return;
1439
+ }
1440
+ if (character === " ") {
1441
+ const nextTabStop = (Math.floor(buffer.cursor.displayCol / 8) + 1) * 8;
1442
+ moveCursorTo(buffer, buffer.cursor.row, nextTabStop);
1443
+ return;
1444
+ }
1445
+ if (!isPlainCharacter(character)) return;
1446
+ writeCharacter(character);
1447
+ };
1448
+ const appendText = (text) => {
1449
+ for (const character of text) {
1450
+ if (parserState === "escape") {
1451
+ if (character === "[") {
1452
+ parserState = "csi";
1453
+ csiPrivate = "";
1454
+ csiParams = "";
1455
+ continue;
1456
+ }
1457
+ if (character === "]") {
1458
+ parserState = "osc";
1459
+ continue;
1460
+ }
1461
+ if (character === "7") activeBuffer().savedCursor = { ...activeBuffer().cursor };
1462
+ else if (character === "8") activeBuffer().cursor = { ...activeBuffer().savedCursor };
1463
+ else if (character === "c") resetTerminalState();
1464
+ parserState = "text";
1465
+ continue;
1466
+ }
1467
+ if (parserState === "csi") {
1468
+ if ((character === "?" || character === ">" || character === "!") && csiParams.length === 0) {
1469
+ csiPrivate = character;
1470
+ continue;
1471
+ }
1472
+ if (character >= "0" && character <= "9" || character === ";" || character === ":") {
1473
+ csiParams += character;
1474
+ continue;
1475
+ }
1476
+ if (character >= "@" && character <= "~") {
1477
+ handleCsi(character);
1478
+ parserState = "text";
1479
+ }
1480
+ continue;
1481
+ }
1482
+ if (parserState === "osc") {
1483
+ if (character === "\x07") {
1484
+ parserState = "text";
1485
+ continue;
1486
+ }
1487
+ if (character === ESC$1) parserState = "osc_escape";
1488
+ continue;
1489
+ }
1490
+ if (parserState === "osc_escape") {
1491
+ parserState = character === "\\" ? "text" : "osc";
1492
+ continue;
1493
+ }
1494
+ processTextCharacter(character);
1495
+ }
1496
+ };
1497
+ return {
1498
+ append(chunk) {
1499
+ appendText(decoder.decode(chunk, { stream: true }));
1500
+ },
1501
+ getGridOverride(row, col) {
1502
+ return activeBuffer().rows[row]?.[col] ?? null;
1503
+ },
1504
+ getScrollbackOverride(offset, col) {
1505
+ return mainBuffer.scrollback[offset]?.[col] ?? null;
1506
+ },
1507
+ isAltScreenActive() {
1508
+ return useAltBuffer;
1509
+ },
1510
+ reset(nextCols = cols, nextRows = rows) {
1511
+ cols = Math.max(1, nextCols);
1512
+ rows = Math.max(1, nextRows);
1513
+ mainBuffer = createBuffer(cols, rows);
1514
+ altBuffer = createBuffer(cols, rows);
1515
+ currentStyle = {
1516
+ bg: null,
1517
+ fg: null
1518
+ };
1519
+ parserState = "text";
1520
+ renderHints.clearScreen = false;
1521
+ csiPrivate = "";
1522
+ csiParams = "";
1523
+ decoder = new TextDecoder();
1524
+ useAltBuffer = false;
1525
+ },
1526
+ resize(nextCols, nextRows) {
1527
+ cols = Math.max(1, nextCols);
1528
+ rows = Math.max(1, nextRows);
1529
+ resizeCols(mainBuffer, cols);
1530
+ resizeCols(altBuffer, cols);
1531
+ resizeRows(mainBuffer, rows);
1532
+ resizeRows(altBuffer, rows);
1533
+ clampCursor(mainBuffer.cursor);
1534
+ clampCursor(mainBuffer.savedCursor);
1535
+ clampCursor(altBuffer.cursor);
1536
+ clampCursor(altBuffer.savedCursor);
1537
+ },
1538
+ syncFromBridge(bridge) {
1539
+ if (!bridge) return;
1540
+ useAltBuffer = bridge.usingAltScreen();
1541
+ const cursor = bridge.getCursor();
1542
+ const buffer = activeBuffer();
1543
+ buffer.cursor.row = clamp$2(cursor.row, 0, rows - 1);
1544
+ buffer.cursor.col = clamp$2(cursor.col, 0, cols - 1);
1545
+ },
1546
+ consumeRenderHints() {
1547
+ const nextHints = renderHints;
1548
+ renderHints = {
1549
+ clearScreen: false,
1550
+ styleChanged: false
1551
+ };
1552
+ return nextHints;
1553
+ }
1554
+ };
1555
+ }
1556
+ //#endregion
1557
+ //#region src/frontend/browser-terminal-renderer.ts
1558
+ const DEFAULT_COLOR = 256;
1559
+ const FLAG_BOLD = 1;
1560
+ const FLAG_DIM = 2;
1561
+ const FLAG_ITALIC = 4;
1562
+ const FLAG_UNDERLINE = 8;
1563
+ const FLAG_REVERSE = 32;
1564
+ const FLAG_INVISIBLE = 64;
1565
+ const FLAG_STRIKETHROUGH = 128;
1566
+ function colorToCSS(index) {
1567
+ if (index === DEFAULT_COLOR) return null;
1568
+ if (index < 16) return `var(--term-color-${index})`;
1569
+ if (index < 232) {
1570
+ const value = index - 16;
1571
+ return `rgb(${Math.floor(value / 36) * 51}, ${Math.floor(value / 6) % 6 * 51}, ${value % 6 * 51})`;
1572
+ }
1573
+ const level = (index - 232) * 10 + 8;
1574
+ return `rgb(${level}, ${level}, ${level})`;
1575
+ }
1576
+ function resolveColorChannels(fg, bg, flags, override = null) {
1577
+ let resolvedFg = override?.fg ?? colorToCSS(fg);
1578
+ let resolvedBg = override?.bg ?? colorToCSS(bg);
1579
+ if (flags & FLAG_REVERSE) {
1580
+ [resolvedFg, resolvedBg] = [resolvedBg, resolvedFg];
1581
+ if (resolvedFg === null) resolvedFg = colorToCSS(0);
1582
+ if (resolvedBg === null) resolvedBg = colorToCSS(7);
1583
+ }
1584
+ return {
1585
+ bg: resolvedBg,
1586
+ fg: resolvedFg
1587
+ };
1588
+ }
1589
+ function buildCellStyle(fg, bg, flags, override = null) {
1590
+ const colors = resolveColorChannels(fg, bg, flags, override);
1591
+ let style = "";
1592
+ if (colors.fg) style += `color:${colors.fg};`;
1593
+ if (colors.bg) style += `background:${colors.bg};`;
1594
+ if (flags & FLAG_BOLD) style += "font-weight:bold;";
1595
+ if (flags & FLAG_DIM) style += "opacity:0.5;";
1596
+ if (flags & FLAG_ITALIC) style += "font-style:italic;";
1597
+ const decorations = [];
1598
+ if (flags & FLAG_UNDERLINE) decorations.push("underline");
1599
+ if (flags & FLAG_STRIKETHROUGH) decorations.push("line-through");
1600
+ if (decorations.length > 0) style += `text-decoration:${decorations.join(" ")};`;
1601
+ if (flags & FLAG_INVISIBLE) style += "visibility:hidden;";
1602
+ return style;
1603
+ }
1604
+ function appendRun(parent, text, style, className = "") {
1605
+ const span = document.createElement("span");
1606
+ if (className) span.className = className;
1607
+ if (style) span.style.cssText = style;
1608
+ span.textContent = text;
1609
+ parent.appendChild(span);
1610
+ }
1611
+ function appendWideCell(parent, text, style, cursor = false) {
1612
+ const span = document.createElement("span");
1613
+ span.className = cursor ? "term-wide term-cursor" : "term-wide";
1614
+ if (style) span.style.cssText = style;
1615
+ span.style.width = "2ch";
1616
+ span.style.minWidth = "2ch";
1617
+ span.style.maxWidth = "2ch";
1618
+ span.style.overflow = "hidden";
1619
+ span.textContent = text;
1620
+ parent.appendChild(span);
1621
+ }
1622
+ function isWideContinuationCell(cell) {
1623
+ return (cell?.char ?? 0) === 0;
1624
+ }
1625
+ function serializeRowText(getCell, lineLength) {
1626
+ let text = "";
1627
+ for (let col = 0; col < lineLength; col += 1) {
1628
+ const codePoint = getCell(col)?.char ?? 0;
1629
+ if (isWideCodePoint(codePoint)) {
1630
+ text += String.fromCodePoint(codePoint);
1631
+ if (col + 1 < lineLength && isWideContinuationCell(getCell(col + 1))) col += 1;
1632
+ continue;
1633
+ }
1634
+ text += codePoint >= 32 ? String.fromCodePoint(codePoint) : " ";
1635
+ }
1636
+ return normalizeRowText(text);
1637
+ }
1638
+ function normalizeRowText(text) {
1639
+ return text.trimEnd();
1640
+ }
1641
+ function cloneSnapshotRow(snapshot) {
1642
+ const rowElement = snapshot.element.cloneNode(true);
1643
+ rowElement.className = "term-row term-scrollback-row term-restored-scrollback-row";
1644
+ rowElement.querySelectorAll(".term-cursor").forEach((cursor) => {
1645
+ cursor.classList.remove("term-cursor");
1646
+ });
1647
+ return rowElement;
1648
+ }
1649
+ function resolveSnapshotPrefixMatch(snapshotRows, currentRows) {
1650
+ const meaningfulSnapshotRows = snapshotRows.filter((row) => row.text.length > 0);
1651
+ const meaningfulCurrentRows = currentRows.filter((row) => row.length > 0);
1652
+ if (meaningfulSnapshotRows.length === 0) return {
1653
+ missingPrefixCount: 0,
1654
+ overlapCount: 0
1655
+ };
1656
+ if (meaningfulCurrentRows.length === 0) return {
1657
+ missingPrefixCount: meaningfulSnapshotRows.length,
1658
+ overlapCount: 0
1659
+ };
1660
+ let bestStart = meaningfulSnapshotRows.length;
1661
+ let bestOverlap = 0;
1662
+ for (let start = 0; start < meaningfulSnapshotRows.length; start += 1) {
1663
+ let overlap = 0;
1664
+ while (start + overlap < meaningfulSnapshotRows.length && overlap < meaningfulCurrentRows.length && meaningfulSnapshotRows[start + overlap].text === meaningfulCurrentRows[overlap]) overlap += 1;
1665
+ if (overlap > bestOverlap) {
1666
+ bestOverlap = overlap;
1667
+ bestStart = start;
1668
+ }
1669
+ }
1670
+ if (bestOverlap === 0) return {
1671
+ missingPrefixCount: 0,
1672
+ overlapCount: 0
1673
+ };
1674
+ return {
1675
+ missingPrefixCount: bestStart,
1676
+ overlapCount: bestOverlap
1677
+ };
1678
+ }
1679
+ function findRowSequence(rows, sequence, minStart = 0) {
1680
+ if (sequence.length === 0) return Math.max(0, minStart);
1681
+ outer: for (let start = Math.max(0, minStart); start <= rows.length - sequence.length; start += 1) {
1682
+ for (let index = 0; index < sequence.length; index += 1) if (rows[start + index] !== sequence[index]) continue outer;
1683
+ return start;
1684
+ }
1685
+ return -1;
1686
+ }
1687
+ function resolveColors(fg, bg, flags, override = null) {
1688
+ const colors = resolveColorChannels(fg, bg, flags, override);
1689
+ return {
1690
+ bg: colors.bg ?? "var(--term-bg)",
1691
+ fg: colors.fg ?? "var(--term-fg)"
1692
+ };
1693
+ }
1694
+ function getBlockBackground(codePoint, fg, bg) {
1695
+ switch (codePoint) {
1696
+ case 9600: return `linear-gradient(${fg} 50%,${bg} 50%)`;
1697
+ case 9601: return `linear-gradient(${bg} 87.5%,${fg} 87.5%)`;
1698
+ case 9602: return `linear-gradient(${bg} 75%,${fg} 75%)`;
1699
+ case 9603: return `linear-gradient(${bg} 62.5%,${fg} 62.5%)`;
1700
+ case 9604: return `linear-gradient(${bg} 50%,${fg} 50%)`;
1701
+ case 9605: return `linear-gradient(${bg} 37.5%,${fg} 37.5%)`;
1702
+ case 9606: return `linear-gradient(${bg} 25%,${fg} 25%)`;
1703
+ case 9607: return `linear-gradient(${bg} 12.5%,${fg} 12.5%)`;
1704
+ case 9608: return fg;
1705
+ case 9609: return `linear-gradient(to right,${fg} 87.5%,${bg} 87.5%)`;
1706
+ case 9610: return `linear-gradient(to right,${fg} 75%,${bg} 75%)`;
1707
+ case 9611: return `linear-gradient(to right,${fg} 62.5%,${bg} 62.5%)`;
1708
+ case 9612: return `linear-gradient(to right,${fg} 50%,${bg} 50%)`;
1709
+ case 9613: return `linear-gradient(to right,${fg} 37.5%,${bg} 37.5%)`;
1710
+ case 9614: return `linear-gradient(to right,${fg} 25%,${bg} 25%)`;
1711
+ case 9615: return `linear-gradient(to right,${fg} 12.5%,${bg} 12.5%)`;
1712
+ case 9616: return `linear-gradient(to right,${bg} 50%,${fg} 50%)`;
1713
+ case 9617: return `color-mix(in srgb,${fg} 25%,${bg})`;
1714
+ case 9618: return `color-mix(in srgb,${fg} 50%,${bg})`;
1715
+ case 9619: return `color-mix(in srgb,${fg} 75%,${bg})`;
1716
+ case 9620: return `linear-gradient(${fg} 12.5%,${bg} 12.5%)`;
1717
+ case 9621: return `linear-gradient(to right,${bg} 87.5%,${fg} 87.5%)`;
1718
+ default: {
1719
+ const cells = {
1720
+ 9622: [
1721
+ false,
1722
+ false,
1723
+ true,
1724
+ false
1725
+ ],
1726
+ 9623: [
1727
+ false,
1728
+ false,
1729
+ false,
1730
+ true
1731
+ ],
1732
+ 9624: [
1733
+ true,
1734
+ false,
1735
+ false,
1736
+ false
1737
+ ],
1738
+ 9625: [
1739
+ true,
1740
+ false,
1741
+ true,
1742
+ true
1743
+ ],
1744
+ 9626: [
1745
+ true,
1746
+ false,
1747
+ false,
1748
+ true
1749
+ ],
1750
+ 9627: [
1751
+ true,
1752
+ true,
1753
+ true,
1754
+ false
1755
+ ],
1756
+ 9628: [
1757
+ true,
1758
+ true,
1759
+ false,
1760
+ true
1761
+ ],
1762
+ 9629: [
1763
+ false,
1764
+ true,
1765
+ false,
1766
+ false
1767
+ ],
1768
+ 9630: [
1769
+ false,
1770
+ true,
1771
+ true,
1772
+ false
1773
+ ],
1774
+ 9631: [
1775
+ false,
1776
+ true,
1777
+ true,
1778
+ true
1779
+ ]
1780
+ }[codePoint];
1781
+ if (!cells) return fg;
1782
+ const [topLeft, topRight, bottomLeft, bottomRight] = cells;
1783
+ const layers = [];
1784
+ const positions = [
1785
+ "0 0",
1786
+ "100% 0",
1787
+ "0 100%",
1788
+ "100% 100%"
1789
+ ];
1790
+ [
1791
+ topLeft,
1792
+ topRight,
1793
+ bottomLeft,
1794
+ bottomRight
1795
+ ].forEach((filled, index) => {
1796
+ if (filled) layers.push(`linear-gradient(${fg},${fg}) ${positions[index]}/50% 50% no-repeat`);
1797
+ });
1798
+ layers.push(bg);
1799
+ return layers.join(",");
1800
+ }
1801
+ }
1802
+ }
1803
+ var BrowserTerminalRenderer = class {
1804
+ _altScreenMeaningfulScrollbackCount;
1805
+ _altScreenVisibleRowSnapshot;
1806
+ _lastAltScreenState;
1807
+ _renderedScrollbackCount;
1808
+ _restoreSnapshotCount;
1809
+ _scrollbackRowEls;
1810
+ cols;
1811
+ container;
1812
+ prevContainerBg;
1813
+ prevCursorCol;
1814
+ prevCursorRow;
1815
+ prevCursorVisible;
1816
+ prevRowBg;
1817
+ rowEls;
1818
+ rows;
1819
+ styleTracker;
1820
+ constructor(container, styleTracker) {
1821
+ this._altScreenVisibleRowSnapshot = [];
1822
+ this._altScreenMeaningfulScrollbackCount = 0;
1823
+ this._lastAltScreenState = false;
1824
+ this._restoreSnapshotCount = 0;
1825
+ this.cols = 0;
1826
+ this.container = container;
1827
+ this.prevContainerBg = "";
1828
+ this.prevCursorCol = -1;
1829
+ this.prevCursorRow = -1;
1830
+ this.prevCursorVisible = false;
1831
+ this.prevRowBg = [];
1832
+ this.rowEls = [];
1833
+ this.rows = 0;
1834
+ this.styleTracker = styleTracker;
1835
+ this._renderedScrollbackCount = 0;
1836
+ this._scrollbackRowEls = [];
1837
+ }
1838
+ _resolveFirstLiveGridRow() {
1839
+ return Array.from(this.container.children).find((child) => child instanceof HTMLElement && child.classList.contains("term-row") && !child.classList.contains("term-scrollback-row")) ?? null;
1840
+ }
1841
+ _insertScrollbackFragment(fragment) {
1842
+ const firstGridRow = this._resolveFirstLiveGridRow();
1843
+ if (firstGridRow instanceof HTMLElement) {
1844
+ this.container.insertBefore(fragment, firstGridRow);
1845
+ return;
1846
+ }
1847
+ this.container.appendChild(fragment);
1848
+ }
1849
+ setup(cols, rows) {
1850
+ this.cols = cols;
1851
+ this.rows = rows;
1852
+ this.container.innerHTML = "";
1853
+ this.rowEls = [];
1854
+ this.prevRowBg = [];
1855
+ this._scrollbackRowEls = [];
1856
+ this._renderedScrollbackCount = 0;
1857
+ this.prevCursorVisible = false;
1858
+ this.prevCursorRow = -1;
1859
+ this.prevCursorCol = -1;
1860
+ this._altScreenVisibleRowSnapshot = [];
1861
+ this._altScreenMeaningfulScrollbackCount = 0;
1862
+ this._lastAltScreenState = false;
1863
+ this._restoreSnapshotCount = 0;
1864
+ const fragment = document.createDocumentFragment();
1865
+ for (let row = 0; row < rows; row += 1) {
1866
+ const rowElement = document.createElement("div");
1867
+ rowElement.className = "term-row";
1868
+ fragment.appendChild(rowElement);
1869
+ this.rowEls.push(rowElement);
1870
+ }
1871
+ this.container.appendChild(fragment);
1872
+ }
1873
+ _buildRowContent(rowEl, getCell, getOverride, lineLen, cursorCol, rowIndex) {
1874
+ if (rowIndex >= 0) rowEl.className = "term-row";
1875
+ rowEl.textContent = "";
1876
+ let runStart = 0;
1877
+ let runStyle = "";
1878
+ let runText = "";
1879
+ const flushRun = (endCol) => {
1880
+ if (!runText) return;
1881
+ if (cursorCol >= runStart && cursorCol < endCol) {
1882
+ const offset = cursorCol - runStart;
1883
+ const before = runText.slice(0, offset);
1884
+ const cursorChar = runText[offset];
1885
+ const after = runText.slice(offset + 1);
1886
+ if (before) appendRun(rowEl, before, runStyle);
1887
+ appendRun(rowEl, cursorChar, runStyle, "term-cursor");
1888
+ if (after) appendRun(rowEl, after, runStyle);
1889
+ } else appendRun(rowEl, runText, runStyle);
1890
+ };
1891
+ for (let col = 0; col < this.cols; col += 1) {
1892
+ const cell = getCell(col);
1893
+ const inBounds = col < lineLen;
1894
+ const codePoint = inBounds ? cell.char : 0;
1895
+ const override = getOverride(col);
1896
+ if (override?.hidden === true) {
1897
+ flushRun(col);
1898
+ runStart = col + 1;
1899
+ runStyle = "";
1900
+ runText = "";
1901
+ continue;
1902
+ }
1903
+ if (inBounds && isWideCodePoint(codePoint)) {
1904
+ const consumedColumns = (col + 1 < lineLen && isWideContinuationCell(getCell(col + 1)) ? getCell(col + 1) : null) ? 2 : 1;
1905
+ const style = buildCellStyle(cell.fg, cell.bg, cell.flags, override);
1906
+ const cursorOnWideCell = cursorCol === col || consumedColumns === 2 && cursorCol === col + 1 || cursorCol === col + 1 && getOverride(cursorCol)?.hidden === true;
1907
+ flushRun(col);
1908
+ appendWideCell(rowEl, String.fromCodePoint(codePoint), style, cursorOnWideCell);
1909
+ runStart = col + consumedColumns;
1910
+ runStyle = "";
1911
+ runText = "";
1912
+ col += consumedColumns - 1;
1913
+ continue;
1914
+ }
1915
+ if (inBounds && codePoint >= 9600 && codePoint <= 9631) {
1916
+ flushRun(col);
1917
+ const colors = resolveColors(cell.fg, cell.bg, cell.flags, override);
1918
+ const span = document.createElement("span");
1919
+ span.className = col === cursorCol ? "term-block term-cursor" : "term-block";
1920
+ span.style.background = getBlockBackground(codePoint, colors.fg, colors.bg);
1921
+ if (cell.flags & FLAG_DIM) span.style.opacity = "0.5";
1922
+ rowEl.appendChild(span);
1923
+ runStart = col + 1;
1924
+ runStyle = "";
1925
+ runText = "";
1926
+ continue;
1927
+ }
1928
+ const character = inBounds && codePoint >= 32 ? String.fromCodePoint(codePoint) : " ";
1929
+ const style = inBounds ? buildCellStyle(cell.fg, cell.bg, cell.flags, override) : "";
1930
+ if (style !== runStyle) {
1931
+ flushRun(col);
1932
+ runStart = col;
1933
+ runStyle = style;
1934
+ runText = character;
1935
+ } else runText += character;
1936
+ }
1937
+ flushRun(this.cols);
1938
+ if (rowIndex >= 0) {
1939
+ if (this.prevRowBg[rowIndex] !== "") {
1940
+ rowEl.style.background = "";
1941
+ rowEl.style.boxShadow = "";
1942
+ this.prevRowBg[rowIndex] = "";
1943
+ }
1944
+ return;
1945
+ }
1946
+ rowEl.style.background = "";
1947
+ rowEl.style.boxShadow = "";
1948
+ }
1949
+ _buildScrollbackRowEl(bridge, offset) {
1950
+ const rowElement = document.createElement("div");
1951
+ rowElement.className = "term-row term-scrollback-row";
1952
+ const lineLength = bridge.getScrollbackLineLen(offset);
1953
+ this._buildRowContent(rowElement, (col) => bridge.getScrollbackCell(offset, col), (col) => this.styleTracker.getScrollbackOverride(offset, col), lineLength, -1, -1);
1954
+ return rowElement;
1955
+ }
1956
+ _captureVisibleRowSnapshot() {
1957
+ this._altScreenMeaningfulScrollbackCount = this._scrollbackRowEls.reduce((count, rowElement) => count + (normalizeRowText(rowElement.textContent ?? "").length > 0 ? 1 : 0), 0);
1958
+ this._altScreenVisibleRowSnapshot = this.rowEls.map((rowElement) => ({
1959
+ element: rowElement.cloneNode(true),
1960
+ text: normalizeRowText(rowElement.textContent ?? "")
1961
+ }));
1962
+ }
1963
+ _clearAltScreenRestoreSnapshot() {
1964
+ this._altScreenVisibleRowSnapshot = [];
1965
+ this._altScreenMeaningfulScrollbackCount = 0;
1966
+ }
1967
+ _readGridRowText(bridge, row) {
1968
+ return serializeRowText((col) => bridge.getCell(row, col), this.cols);
1969
+ }
1970
+ getVisibleRowTexts(bridge, { trimPadding = true } = {}) {
1971
+ const rows = [];
1972
+ for (let row = 0; row < this.rows; row += 1) rows.push(this._readGridRowText(bridge, row));
1973
+ if (!trimPadding) return rows;
1974
+ let start = 0;
1975
+ let end = rows.length;
1976
+ while (start < end && rows[start] === "") start += 1;
1977
+ while (end > start && rows[end - 1] === "") end -= 1;
1978
+ return rows.slice(start, end);
1979
+ }
1980
+ _readScrollbackRowText(bridge, offset) {
1981
+ return serializeRowText((col) => bridge.getScrollbackCell(offset, col), bridge.getScrollbackLineLen(offset));
1982
+ }
1983
+ _readLiveTranscriptRows(bridge, currentVisibleRows) {
1984
+ const liveRows = [];
1985
+ for (let offset = bridge.getScrollbackCount() - 1; offset >= 0; offset -= 1) {
1986
+ const rowText = this._readScrollbackRowText(bridge, offset);
1987
+ if (rowText.length > 0) liveRows.push(rowText);
1988
+ }
1989
+ for (const rowText of currentVisibleRows) if (rowText.length > 0) liveRows.push(rowText);
1990
+ return liveRows;
1991
+ }
1992
+ _liveTranscriptContainsSnapshots(bridge, snapshots, currentVisibleRows) {
1993
+ if (snapshots.length === 0) return true;
1994
+ return findRowSequence(this._readLiveTranscriptRows(bridge, currentVisibleRows), snapshots.map((snapshot) => snapshot.text), this._altScreenMeaningfulScrollbackCount) !== -1;
1995
+ }
1996
+ _getRestoredScrollbackSnapshots(bridge) {
1997
+ if (bridge.usingAltScreen() || this._altScreenVisibleRowSnapshot.length === 0) return [];
1998
+ const meaningfulSnapshotRows = this._altScreenVisibleRowSnapshot.filter((row) => row.text.length > 0);
1999
+ if (meaningfulSnapshotRows.length === 0) {
2000
+ this._clearAltScreenRestoreSnapshot();
2001
+ return [];
2002
+ }
2003
+ const currentVisibleRows = [];
2004
+ for (let row = 0; row < this.rows; row += 1) currentVisibleRows.push(this._readGridRowText(bridge, row));
2005
+ let { missingPrefixCount, overlapCount } = resolveSnapshotPrefixMatch(this._altScreenVisibleRowSnapshot, currentVisibleRows);
2006
+ if (missingPrefixCount <= 0) if (overlapCount === 0 && this._lastAltScreenState) missingPrefixCount = meaningfulSnapshotRows.length;
2007
+ else if (overlapCount === 0 && this._restoreSnapshotCount > 0) missingPrefixCount = Math.min(this._restoreSnapshotCount, meaningfulSnapshotRows.length);
2008
+ else {
2009
+ this._clearAltScreenRestoreSnapshot();
2010
+ return [];
2011
+ }
2012
+ const restoredSnapshots = meaningfulSnapshotRows.slice(0, missingPrefixCount);
2013
+ if (this._liveTranscriptContainsSnapshots(bridge, restoredSnapshots, currentVisibleRows)) {
2014
+ this._clearAltScreenRestoreSnapshot();
2015
+ return [];
2016
+ }
2017
+ return restoredSnapshots;
2018
+ }
2019
+ _rebuildScrollback(bridge, restoredSnapshots) {
2020
+ for (const rowElement of this._scrollbackRowEls) rowElement.remove();
2021
+ this._scrollbackRowEls = [];
2022
+ if (bridge.usingAltScreen()) {
2023
+ this._renderedScrollbackCount = 0;
2024
+ this._restoreSnapshotCount = 0;
2025
+ return;
2026
+ }
2027
+ const scrollbackCount = bridge.getScrollbackCount();
2028
+ const rowElements = [];
2029
+ for (let offset = scrollbackCount - 1; offset >= 0; offset -= 1) rowElements.push(this._buildScrollbackRowEl(bridge, offset));
2030
+ if (restoredSnapshots.length > 0) {
2031
+ const restoredRowElements = restoredSnapshots.map((snapshot) => cloneSnapshotRow(snapshot));
2032
+ const preservedRowCount = Math.max(0, rowElements.length - restoredRowElements.length);
2033
+ rowElements.splice(preservedRowCount, rowElements.length - preservedRowCount, ...restoredRowElements);
2034
+ }
2035
+ const fragment = document.createDocumentFragment();
2036
+ for (const rowElement of rowElements) fragment.appendChild(rowElement);
2037
+ this._insertScrollbackFragment(fragment);
2038
+ this._scrollbackRowEls = rowElements;
2039
+ this._renderedScrollbackCount = scrollbackCount;
2040
+ this._restoreSnapshotCount = restoredSnapshots.length;
2041
+ }
2042
+ syncScrollback(bridge, restoredSnapshots = []) {
2043
+ const scrollbackCount = bridge.usingAltScreen() ? 0 : bridge.getScrollbackCount();
2044
+ if (bridge.usingAltScreen() !== this._lastAltScreenState || restoredSnapshots.length > 0 || this._restoreSnapshotCount > 0) {
2045
+ this._rebuildScrollback(bridge, restoredSnapshots);
2046
+ return;
2047
+ }
2048
+ if (scrollbackCount === this._renderedScrollbackCount) return;
2049
+ if (scrollbackCount > this._renderedScrollbackCount) {
2050
+ const newCount = scrollbackCount - this._renderedScrollbackCount;
2051
+ const fragment = document.createDocumentFragment();
2052
+ for (let offset = newCount - 1; offset >= 0; offset -= 1) {
2053
+ const rowElement = this._buildScrollbackRowEl(bridge, offset);
2054
+ fragment.appendChild(rowElement);
2055
+ this._scrollbackRowEls.push(rowElement);
2056
+ }
2057
+ this._insertScrollbackFragment(fragment);
2058
+ } else {
2059
+ const removeCount = this._renderedScrollbackCount - scrollbackCount;
2060
+ for (let index = 0; index < removeCount; index += 1) this._scrollbackRowEls.shift()?.remove();
2061
+ }
2062
+ this._renderedScrollbackCount = scrollbackCount;
2063
+ }
2064
+ render(bridge, options = {}) {
2065
+ const rows = bridge.getRows();
2066
+ const cols = bridge.getCols();
2067
+ const altScreenActive = bridge.usingAltScreen();
2068
+ const forceRender = options.force === true;
2069
+ let resized = false;
2070
+ if (rows !== this.rows || cols !== this.cols) {
2071
+ this.setup(cols, rows);
2072
+ resized = true;
2073
+ }
2074
+ if (altScreenActive && !this._lastAltScreenState) this._captureVisibleRowSnapshot();
2075
+ const restoredSnapshots = this._getRestoredScrollbackSnapshots(bridge);
2076
+ this.syncScrollback(bridge, restoredSnapshots);
2077
+ const cursor = bridge.getCursor();
2078
+ const cursorVisible = cursor.visible;
2079
+ const needsCursorUpdate = cursor.row !== this.prevCursorRow || cursor.col !== this.prevCursorCol || cursorVisible !== this.prevCursorVisible;
2080
+ for (let row = 0; row < this.rows; row += 1) {
2081
+ const isDirty = forceRender || resized || bridge.isDirtyRow(row);
2082
+ const hadCursor = row === this.prevCursorRow && (needsCursorUpdate || this.prevCursorVisible);
2083
+ const hasCursor = row === cursor.row;
2084
+ if (isDirty || hadCursor || hasCursor && needsCursorUpdate) {
2085
+ const cursorCol = hasCursor && cursorVisible ? cursor.col : -1;
2086
+ this._buildRowContent(this.rowEls[row], (col) => bridge.getCell(row, col), (col) => this.styleTracker.getGridOverride(row, col), this.cols, cursorCol, row);
2087
+ }
2088
+ }
2089
+ this.prevCursorRow = cursor.row;
2090
+ this.prevCursorCol = cursor.col;
2091
+ this.prevCursorVisible = cursorVisible;
2092
+ if (this.prevContainerBg !== "") {
2093
+ this.container.style.background = "";
2094
+ this.prevContainerBg = "";
2095
+ }
2096
+ bridge.clearDirty();
2097
+ this._lastAltScreenState = altScreenActive;
2098
+ }
2099
+ };
2100
+ //#endregion
2101
+ //#region src/frontend/terminal-input-policies.ts
2102
+ const RESERVED_BROWSER_SHORTCUT_KEYS = new Set(["r", "w"]);
2103
+ const CONTAINED_TERMINAL_NAVIGATION_KEYS = new Set([
2104
+ "ArrowUp",
2105
+ "ArrowDown",
2106
+ "ArrowLeft",
2107
+ "ArrowRight",
2108
+ "Home",
2109
+ "End",
2110
+ "PageUp",
2111
+ "PageDown"
2112
+ ]);
2113
+ const NORMAL_NAVIGATION_SEQUENCES = Object.freeze({
2114
+ ArrowDown: "\x1B[B",
2115
+ ArrowLeft: "\x1B[D",
2116
+ ArrowRight: "\x1B[C",
2117
+ ArrowUp: "\x1B[A",
2118
+ End: "\x1B[F",
2119
+ Home: "\x1B[H"
2120
+ });
2121
+ const APPLICATION_NAVIGATION_SEQUENCES = Object.freeze({
2122
+ ArrowDown: "\x1BOB",
2123
+ ArrowLeft: "\x1BOD",
2124
+ ArrowRight: "\x1BOC",
2125
+ ArrowUp: "\x1BOA",
2126
+ End: "\x1BOF",
2127
+ Home: "\x1BOH"
2128
+ });
2129
+ const FIXED_KEY_SEQUENCES = Object.freeze({
2130
+ Backspace: "",
2131
+ Delete: "\x1B[3~",
2132
+ Enter: "\r",
2133
+ Escape: "\x1B",
2134
+ F1: "\x1BOP",
2135
+ F10: "\x1B[21~",
2136
+ F11: "\x1B[23~",
2137
+ F12: "\x1B[24~",
2138
+ F2: "\x1BOQ",
2139
+ F3: "\x1BOR",
2140
+ F4: "\x1BOS",
2141
+ F5: "\x1B[15~",
2142
+ F6: "\x1B[17~",
2143
+ F7: "\x1B[18~",
2144
+ F8: "\x1B[19~",
2145
+ F9: "\x1B[20~",
2146
+ Insert: "\x1B[2~",
2147
+ PageDown: "\x1B[6~",
2148
+ PageUp: "\x1B[5~",
2149
+ Tab: " "
2150
+ });
2151
+ const ALT_PRINTABLE_CODE_MAP = Object.freeze({
2152
+ Backquote: "`",
2153
+ BracketLeft: "[",
2154
+ BracketRight: "]",
2155
+ Backslash: "\\",
2156
+ Comma: ",",
2157
+ Digit0: "0",
2158
+ Digit1: "1",
2159
+ Digit2: "2",
2160
+ Digit3: "3",
2161
+ Digit4: "4",
2162
+ Digit5: "5",
2163
+ Digit6: "6",
2164
+ Digit7: "7",
2165
+ Digit8: "8",
2166
+ Digit9: "9",
2167
+ Equal: "=",
2168
+ KeyA: "a",
2169
+ KeyB: "b",
2170
+ KeyC: "c",
2171
+ KeyD: "d",
2172
+ KeyE: "e",
2173
+ KeyF: "f",
2174
+ KeyG: "g",
2175
+ KeyH: "h",
2176
+ KeyI: "i",
2177
+ KeyJ: "j",
2178
+ KeyK: "k",
2179
+ KeyL: "l",
2180
+ KeyM: "m",
2181
+ KeyN: "n",
2182
+ KeyO: "o",
2183
+ KeyP: "p",
2184
+ KeyQ: "q",
2185
+ KeyR: "r",
2186
+ KeyS: "s",
2187
+ KeyT: "t",
2188
+ KeyU: "u",
2189
+ KeyV: "v",
2190
+ KeyW: "w",
2191
+ KeyX: "x",
2192
+ KeyY: "y",
2193
+ KeyZ: "z",
2194
+ Minus: "-",
2195
+ Period: ".",
2196
+ Quote: "'",
2197
+ Semicolon: ";",
2198
+ Slash: "/",
2199
+ Space: " "
2200
+ });
2201
+ function installTerminalInputPolicies(term, callbacks = {}) {
2202
+ const root = term?.element;
2203
+ const textarea = term?.input?.textarea;
2204
+ const ownerDocument = root?.ownerDocument;
2205
+ const onData = callbacks.onData ?? (() => {});
2206
+ const captureDocumentCtrlN = callbacks.captureDocumentCtrlN === true;
2207
+ const resolveKey = callbacks.resolveKey ?? (() => null);
2208
+ const resolveDocumentKeyData = callbacks.resolveDocumentKeyData ?? (() => null);
2209
+ if (!(root instanceof HTMLElement) || !(textarea instanceof HTMLTextAreaElement) || !(ownerDocument instanceof Document)) return () => {};
2210
+ let composing = false;
2211
+ let pendingCompositionCommit = false;
2212
+ let suppressedCompositionValue = "";
2213
+ let latestCompositionValue = "";
2214
+ let speculativePlainInputText = "";
2215
+ let pendingSyntheticPrintableText = "";
2216
+ let syntheticPrintableFlushQueued = false;
2217
+ const clearSpeculativePlainInputText = () => {
2218
+ speculativePlainInputText = "";
2219
+ };
2220
+ const clearPendingSyntheticPrintableText = () => {
2221
+ pendingSyntheticPrintableText = "";
2222
+ };
2223
+ const flushPendingSyntheticPrintableText = () => {
2224
+ if (!pendingSyntheticPrintableText) return;
2225
+ const pendingText = pendingSyntheticPrintableText;
2226
+ pendingSyntheticPrintableText = "";
2227
+ onData(pendingText);
2228
+ };
2229
+ const clearPendingTextState = () => {
2230
+ clearSpeculativePlainInputText();
2231
+ clearPendingSyntheticPrintableText();
2232
+ };
2233
+ const flushPendingTextState = () => {
2234
+ clearSpeculativePlainInputText();
2235
+ flushPendingSyntheticPrintableText();
2236
+ };
2237
+ const deferSyntheticPrintableText = (text) => {
2238
+ pendingSyntheticPrintableText += text;
2239
+ if (syntheticPrintableFlushQueued) return;
2240
+ syntheticPrintableFlushQueued = true;
2241
+ queueMicrotask(() => {
2242
+ syntheticPrintableFlushQueued = false;
2243
+ if (composing || !pendingSyntheticPrintableText) return;
2244
+ const pendingText = pendingSyntheticPrintableText;
2245
+ pendingSyntheticPrintableText = "";
2246
+ onData(pendingText);
2247
+ });
2248
+ };
2249
+ const rollBackSpeculativePlainInputText = (preeditText) => {
2250
+ const rollbackText = resolveSpeculativeRollbackText(speculativePlainInputText, preeditText);
2251
+ if (!rollbackText) return;
2252
+ const rollback = "".repeat([...rollbackText].length);
2253
+ speculativePlainInputText = speculativePlainInputText.slice(0, -rollbackText.length);
2254
+ onData(rollback);
2255
+ };
2256
+ const sendText = (text) => {
2257
+ if (!text) return;
2258
+ onData(text);
2259
+ };
2260
+ const handleDocumentKeyDownCapture = (event) => {
2261
+ if (event.target === textarea) return;
2262
+ const documentKeyData = captureDocumentCtrlN && !event.altKey && !event.metaKey && event.ctrlKey && event.key.toLowerCase() === "n" ? "" : resolveDocumentKeyData(event);
2263
+ if (documentKeyData === null) return;
2264
+ flushPendingTextState();
2265
+ event.preventDefault();
2266
+ stopInputPropagation(event);
2267
+ onData(documentKeyData);
2268
+ };
2269
+ const handleKeyDownCapture = (event) => {
2270
+ if (isBrowserSafeShortcut(event)) {
2271
+ flushPendingTextState();
2272
+ stopInputPropagation(event);
2273
+ return;
2274
+ }
2275
+ if (isCopyShortcutWithTerminalSelection(root, event)) {
2276
+ flushPendingTextState();
2277
+ stopInputPropagation(event);
2278
+ return;
2279
+ }
2280
+ const customKeyData = resolveKey(event);
2281
+ if (customKeyData != null) {
2282
+ flushPendingTextState();
2283
+ event.preventDefault();
2284
+ stopInputPropagation(event);
2285
+ onData(customKeyData);
2286
+ return;
2287
+ }
2288
+ const normalizedAltSequence = resolveAltPrintableSequence(event);
2289
+ if (normalizedAltSequence) {
2290
+ flushPendingTextState();
2291
+ event.preventDefault();
2292
+ stopInputPropagation(event);
2293
+ onData(normalizedAltSequence);
2294
+ return;
2295
+ }
2296
+ if (composing || isCompositionKeyDown(event)) {
2297
+ stopInputPropagation(event);
2298
+ return;
2299
+ }
2300
+ if (isPlainPrintableKey(event)) {
2301
+ pendingCompositionCommit = false;
2302
+ suppressedCompositionValue = "";
2303
+ latestCompositionValue = "";
2304
+ stopInputPropagation(event);
2305
+ if (!event.isTrusted) {
2306
+ event.preventDefault();
2307
+ deferSyntheticPrintableText(event.key);
2308
+ }
2309
+ return;
2310
+ }
2311
+ const terminalSequence = resolveTerminalKeySequence(term, event);
2312
+ if (terminalSequence !== null) {
2313
+ flushPendingTextState();
2314
+ event.preventDefault();
2315
+ stopInputPropagation(event);
2316
+ onData(terminalSequence);
2317
+ return;
2318
+ }
2319
+ if (isContainedTerminalNavigationKey(event)) {
2320
+ flushPendingTextState();
2321
+ event.preventDefault();
2322
+ stopInputPropagation(event);
2323
+ }
2324
+ };
2325
+ const handleCompositionStartCapture = (event) => {
2326
+ clearPendingSyntheticPrintableText();
2327
+ composing = true;
2328
+ pendingCompositionCommit = false;
2329
+ suppressedCompositionValue = "";
2330
+ latestCompositionValue = "";
2331
+ stopInputPropagation(event);
2332
+ };
2333
+ const handleCompositionEndCapture = (event) => {
2334
+ clearPendingTextState();
2335
+ composing = false;
2336
+ stopInputPropagation(event);
2337
+ pendingCompositionCommit = false;
2338
+ const value = normalizeCompositionCommit(event.data);
2339
+ if (!value) {
2340
+ const fallbackValue = textarea.value;
2341
+ if (latestCompositionValue && fallbackValue && fallbackValue !== latestCompositionValue) {
2342
+ latestCompositionValue = "";
2343
+ suppressedCompositionValue = fallbackValue;
2344
+ sendText(fallbackValue);
2345
+ textarea.value = "";
2346
+ return;
2347
+ }
2348
+ pendingCompositionCommit = true;
2349
+ return;
2350
+ }
2351
+ latestCompositionValue = "";
2352
+ suppressedCompositionValue = value;
2353
+ sendText(value);
2354
+ textarea.value = "";
2355
+ };
2356
+ const handleInputCapture = (event) => {
2357
+ if (composing || isComposingInput(event)) {
2358
+ if (isCompositionPreeditInput(event)) {
2359
+ clearPendingSyntheticPrintableText();
2360
+ rollBackSpeculativePlainInputText(textarea.value);
2361
+ } else clearPendingTextState();
2362
+ latestCompositionValue = textarea.value;
2363
+ stopInputPropagation(event);
2364
+ return;
2365
+ }
2366
+ const value = textarea.value;
2367
+ const compositionInput = isCompositionInput(event);
2368
+ const compositionPreeditInput = isCompositionPreeditInput(event);
2369
+ if (pendingCompositionCommit) {
2370
+ clearPendingTextState();
2371
+ stopInputPropagation(event);
2372
+ if (!value) {
2373
+ textarea.value = "";
2374
+ if (!compositionInput) {
2375
+ pendingCompositionCommit = false;
2376
+ latestCompositionValue = "";
2377
+ }
2378
+ return;
2379
+ }
2380
+ if (compositionPreeditInput && value === latestCompositionValue) {
2381
+ textarea.value = "";
2382
+ return;
2383
+ }
2384
+ pendingCompositionCommit = false;
2385
+ latestCompositionValue = "";
2386
+ suppressedCompositionValue = resolveCommittedInputText(event, value);
2387
+ sendText(suppressedCompositionValue);
2388
+ textarea.value = "";
2389
+ return;
2390
+ }
2391
+ if (compositionPreeditInput) {
2392
+ clearPendingSyntheticPrintableText();
2393
+ latestCompositionValue = value;
2394
+ stopInputPropagation(event);
2395
+ return;
2396
+ }
2397
+ if (suppressedCompositionValue) {
2398
+ if (!value || value === suppressedCompositionValue) {
2399
+ suppressedCompositionValue = "";
2400
+ stopInputPropagation(event);
2401
+ textarea.value = "";
2402
+ return;
2403
+ }
2404
+ suppressedCompositionValue = "";
2405
+ }
2406
+ if (!value) return;
2407
+ latestCompositionValue = "";
2408
+ stopInputPropagation(event);
2409
+ textarea.value = "";
2410
+ if (compositionInput) {
2411
+ const committedText = resolveCommittedInputText(event, value);
2412
+ suppressedCompositionValue = committedText;
2413
+ sendText(committedText);
2414
+ return;
2415
+ }
2416
+ const inputText = resolvePlainInputText(event, value);
2417
+ if (isPotentialImeSeedText(inputText)) speculativePlainInputText += inputText;
2418
+ else clearSpeculativePlainInputText();
2419
+ sendText(inputText);
2420
+ };
2421
+ const handleCopy = (event) => {
2422
+ const selectionText = getSelectionText(root);
2423
+ if (!selectionText || !event.clipboardData?.setData) return;
2424
+ event.clipboardData.setData("text/plain", selectionText);
2425
+ event.preventDefault();
2426
+ };
2427
+ const handlePaste = (event) => {
2428
+ flushPendingTextState();
2429
+ const text = event.clipboardData?.getData("text") ?? event.clipboardData?.getData("text/plain") ?? "";
2430
+ if (!text) return;
2431
+ event.preventDefault();
2432
+ stopInputPropagation(event);
2433
+ if (term?.bridge?.bracketedPaste?.() === true) {
2434
+ onData(`\u001b[200~${text.split("\x1B").join("")}\u001b[201~`);
2435
+ return;
2436
+ }
2437
+ onData(text);
2438
+ };
2439
+ ownerDocument.addEventListener("keydown", handleDocumentKeyDownCapture, true);
2440
+ textarea.addEventListener("keydown", handleKeyDownCapture, true);
2441
+ textarea.addEventListener("compositionstart", handleCompositionStartCapture, true);
2442
+ textarea.addEventListener("compositionend", handleCompositionEndCapture, true);
2443
+ textarea.addEventListener("input", handleInputCapture, true);
2444
+ textarea.addEventListener("paste", handlePaste, true);
2445
+ ownerDocument.addEventListener("copy", handleCopy, true);
2446
+ return () => {
2447
+ ownerDocument.removeEventListener("keydown", handleDocumentKeyDownCapture, true);
2448
+ textarea.removeEventListener("keydown", handleKeyDownCapture, true);
2449
+ textarea.removeEventListener("compositionstart", handleCompositionStartCapture, true);
2450
+ textarea.removeEventListener("compositionend", handleCompositionEndCapture, true);
2451
+ textarea.removeEventListener("input", handleInputCapture, true);
2452
+ textarea.removeEventListener("paste", handlePaste, true);
2453
+ ownerDocument.removeEventListener("copy", handleCopy, true);
2454
+ };
2455
+ }
2456
+ function isBrowserSafeShortcut(event) {
2457
+ if (event.altKey) return false;
2458
+ if (!(event.metaKey && !event.ctrlKey || event.ctrlKey && !event.metaKey)) return false;
2459
+ return RESERVED_BROWSER_SHORTCUT_KEYS.has(event.key.toLowerCase());
2460
+ }
2461
+ function isContainedTerminalNavigationKey(event) {
2462
+ if (!CONTAINED_TERMINAL_NAVIGATION_KEYS.has(event.key)) return false;
2463
+ if (event.altKey || event.ctrlKey || event.metaKey) return false;
2464
+ return !(event.shiftKey && (event.key === "PageUp" || event.key === "PageDown"));
2465
+ }
2466
+ function resolveAltPrintableSequence(event) {
2467
+ if (!event.altKey || event.ctrlKey || event.metaKey) return null;
2468
+ const baseKey = ALT_PRINTABLE_CODE_MAP[event.code];
2469
+ if (!baseKey) return null;
2470
+ return `\u001b${baseKey}`;
2471
+ }
2472
+ function isPlainPrintableKey(event) {
2473
+ if (event.altKey || event.ctrlKey || event.metaKey) return false;
2474
+ return event.key.length === 1;
2475
+ }
2476
+ function resolveTerminalKeySequence(term, event) {
2477
+ if (event.metaKey && !event.ctrlKey) {
2478
+ if (event.key === "Backspace") return "";
2479
+ return null;
2480
+ }
2481
+ if (event.ctrlKey) {
2482
+ const controlSequence = resolveControlKeySequence(event);
2483
+ return event.altKey && controlSequence ? `\u001b${controlSequence}` : controlSequence;
2484
+ }
2485
+ if (event.key === "Enter" && event.shiftKey) return "\x1B[13;2u";
2486
+ if (event.key === "Tab" && event.shiftKey) return "\x1B[Z";
2487
+ const fixedSequence = FIXED_KEY_SEQUENCES[event.key];
2488
+ if (fixedSequence) return event.altKey ? `\u001b${fixedSequence}` : fixedSequence;
2489
+ const navigationSequence = (term?.bridge?.cursorKeysApp?.() === true ? APPLICATION_NAVIGATION_SEQUENCES : NORMAL_NAVIGATION_SEQUENCES)[event.key];
2490
+ if (navigationSequence) return event.altKey ? `\u001b${navigationSequence}` : navigationSequence;
2491
+ return null;
2492
+ }
2493
+ function resolveControlKeySequence(event) {
2494
+ if (event.key.length !== 1) return null;
2495
+ const key = event.key.toLowerCase();
2496
+ if (key >= "a" && key <= "z") return String.fromCharCode(key.charCodeAt(0) - 96);
2497
+ return {
2498
+ " ": "\0",
2499
+ "[": "\x1B",
2500
+ "\\": "",
2501
+ "]": "",
2502
+ "^": "",
2503
+ "_": ""
2504
+ }[key] ?? null;
2505
+ }
2506
+ function isCompositionKeyDown(event) {
2507
+ return event.isComposing || event.key === "Process" || event.key === "Dead" || event.keyCode === 229 || event.which === 229;
2508
+ }
2509
+ function isCompositionInput(event) {
2510
+ return typeof event.inputType === "string" && event.inputType.toLowerCase().includes("composition");
2511
+ }
2512
+ function isCompositionPreeditInput(event) {
2513
+ return event.inputType === "insertCompositionText";
2514
+ }
2515
+ function isComposingInput(event) {
2516
+ return event.isComposing || isCompositionPreeditInput(event);
2517
+ }
2518
+ function resolvePlainInputText(event, textareaValue) {
2519
+ if (typeof event.data === "string" && event.data.length > 0) return event.data;
2520
+ if (event.inputType === "insertLineBreak") return "\r";
2521
+ if (event.inputType === "deleteContentBackward") return "";
2522
+ if (event.inputType === "deleteContentForward") return "\x1B[3~";
2523
+ return textareaValue;
2524
+ }
2525
+ function resolveCommittedInputText(event, textareaValue) {
2526
+ if (typeof event.data === "string" && event.data.length > 0) return event.data;
2527
+ return textareaValue;
2528
+ }
2529
+ function isPotentialImeSeedText(text) {
2530
+ return /^[0-9A-Za-z']$/.test(text);
2531
+ }
2532
+ function resolveSpeculativeRollbackText(sentText, preeditText) {
2533
+ if (!sentText || !preeditText || !preeditText.startsWith(sentText)) return "";
2534
+ return sentText;
2535
+ }
2536
+ function normalizeCompositionCommit(data) {
2537
+ if (typeof data === "string" && data.length > 0) return data;
2538
+ return "";
2539
+ }
2540
+ function getSelectionText(root) {
2541
+ const selection = root.ownerDocument?.getSelection?.();
2542
+ if (!selection || selection.isCollapsed) return "";
2543
+ if (!nodeIsInsideRoot(root, selection.anchorNode) || !nodeIsInsideRoot(root, selection.focusNode)) return "";
2544
+ return selection.toString();
2545
+ }
2546
+ function isCopyShortcutWithTerminalSelection(root, event) {
2547
+ if (event.altKey || event.key.toLowerCase() !== "c") return false;
2548
+ if (!(event.metaKey || event.ctrlKey)) return false;
2549
+ return getSelectionText(root).length > 0;
2550
+ }
2551
+ function nodeIsInsideRoot(root, node) {
2552
+ if (!node) return false;
2553
+ if (node === root) return true;
2554
+ if (node instanceof Element) return root.contains(node);
2555
+ return node.parentElement ? root.contains(node.parentElement) : false;
2556
+ }
2557
+ function stopInputPropagation(event) {
2558
+ event.stopPropagation();
2559
+ if (typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
2560
+ }
2561
+ //#endregion
2562
+ //#region src/frontend/terminal-theme-protocol.ts
2563
+ const BEL = "\x07";
2564
+ const ESC = "\x1B";
2565
+ const MAX_OSC_LENGTH = 512;
2566
+ const DEFAULT_DARK_THEME_COLORS = {
2567
+ background: "#0d1117",
2568
+ cursor: "#f6b967",
2569
+ foreground: "#edf2ff"
2570
+ };
2571
+ const DEFAULT_LIGHT_THEME_COLORS = {
2572
+ background: "#f4efe3",
2573
+ cursor: "#b96e1a",
2574
+ foreground: "#24323f"
2575
+ };
2576
+ function createTerminalThemeProtocolParser() {
2577
+ const decoder = new TextDecoder();
2578
+ let parserState = "text";
2579
+ let oscBuffer = "";
2580
+ const reset = () => {
2581
+ parserState = "text";
2582
+ oscBuffer = "";
2583
+ };
2584
+ const appendOscCharacter = (character) => {
2585
+ if (oscBuffer.length < MAX_OSC_LENGTH) oscBuffer += character;
2586
+ };
2587
+ return {
2588
+ append(chunk) {
2589
+ const update = {
2590
+ colors: {},
2591
+ palette: []
2592
+ };
2593
+ const text = decoder.decode(chunk, { stream: true });
2594
+ for (const character of text) {
2595
+ if (parserState === "escape") {
2596
+ if (character === "]") {
2597
+ parserState = "osc";
2598
+ oscBuffer = "";
2599
+ continue;
2600
+ }
2601
+ parserState = "text";
2602
+ continue;
2603
+ }
2604
+ if (parserState === "osc") {
2605
+ if (character === BEL) {
2606
+ mergeThemeUpdate(update, parseOscThemeUpdate(oscBuffer));
2607
+ parserState = "text";
2608
+ oscBuffer = "";
2609
+ continue;
2610
+ }
2611
+ if (character === ESC) {
2612
+ parserState = "osc_escape";
2613
+ continue;
2614
+ }
2615
+ appendOscCharacter(character);
2616
+ continue;
2617
+ }
2618
+ if (parserState === "osc_escape") {
2619
+ if (character === "\\") {
2620
+ mergeThemeUpdate(update, parseOscThemeUpdate(oscBuffer));
2621
+ parserState = "text";
2622
+ oscBuffer = "";
2623
+ continue;
2624
+ }
2625
+ appendOscCharacter(ESC);
2626
+ appendOscCharacter(character);
2627
+ parserState = "osc";
2628
+ continue;
2629
+ }
2630
+ if (character === ESC) parserState = "escape";
2631
+ }
2632
+ return hasThemeUpdate(update) ? update : null;
2633
+ },
2634
+ reset
2635
+ };
2636
+ }
2637
+ function resolveTerminalThemeQueryResponse(chunk, options) {
2638
+ const text = typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk);
2639
+ let response = "";
2640
+ for (const payload of collectOscPayloads(text)) {
2641
+ const parts = payload.split(";");
2642
+ const command = parts[0];
2643
+ if ((command === "10" || command === "11" || command === "12") && parts.slice(1).join(";").trim() === "?") {
2644
+ const slot = resolveColorSlot(command);
2645
+ const color = resolveThemeColor(options.root, slot, options.theme);
2646
+ response += `${ESC}]${command};${toTerminalRgbColor(color)}${ESC}\\`;
2647
+ }
2648
+ }
2649
+ return response.length > 0 ? response : null;
2650
+ }
2651
+ function parseOscThemeUpdate(payload) {
2652
+ const parts = payload.split(";");
2653
+ const command = parts[0];
2654
+ if (!command) return null;
2655
+ if (command === "10" || command === "11" || command === "12") {
2656
+ const color = normalizeTerminalColor(parts.slice(1).join(";"));
2657
+ if (!color) return null;
2658
+ const slot = resolveColorSlot(command);
2659
+ const update = {
2660
+ colors: { [slot]: color },
2661
+ palette: []
2662
+ };
2663
+ if (slot === "background") update.theme = inferThemeFromBackground(color);
2664
+ return update;
2665
+ }
2666
+ if (command === "4") return parsePaletteUpdate(parts.slice(1));
2667
+ return null;
2668
+ }
2669
+ function parsePaletteUpdate(parts) {
2670
+ const palette = [];
2671
+ for (let index = 0; index + 1 < parts.length; index += 2) {
2672
+ const colorIndex = Number.parseInt(parts[index] ?? "", 10);
2673
+ const color = normalizeTerminalColor(parts[index + 1] ?? "");
2674
+ if (!Number.isInteger(colorIndex) || colorIndex < 0 || colorIndex > 15 || !color) continue;
2675
+ palette.push({
2676
+ color,
2677
+ index: colorIndex
2678
+ });
2679
+ }
2680
+ if (palette.length === 0) return null;
2681
+ return {
2682
+ colors: {},
2683
+ palette
2684
+ };
2685
+ }
2686
+ function normalizeTerminalColor(value) {
2687
+ const color = value.trim();
2688
+ if (color.length === 0 || color === "?") return null;
2689
+ const rgb = parseTerminalRgbColor(color);
2690
+ if (rgb) return `rgb(${rgb.red}, ${rgb.green}, ${rgb.blue})`;
2691
+ const cssRgb = parseCssRgbColor(color);
2692
+ if (cssRgb) return `rgb(${cssRgb.red}, ${cssRgb.green}, ${cssRgb.blue})`;
2693
+ if (/^#[0-9a-fA-F]{6}$/.test(color)) return color.toLowerCase();
2694
+ if (/^#[0-9a-fA-F]{3}$/.test(color)) return expandShortHexColor(color);
2695
+ return null;
2696
+ }
2697
+ function collectOscPayloads(text) {
2698
+ const payloads = [];
2699
+ let parserState = "text";
2700
+ let oscBuffer = "";
2701
+ const pushPayload = () => {
2702
+ payloads.push(oscBuffer);
2703
+ oscBuffer = "";
2704
+ };
2705
+ for (const character of text) {
2706
+ if (parserState === "escape") {
2707
+ if (character === "]") {
2708
+ parserState = "osc";
2709
+ oscBuffer = "";
2710
+ continue;
2711
+ }
2712
+ parserState = "text";
2713
+ continue;
2714
+ }
2715
+ if (parserState === "osc") {
2716
+ if (character === BEL) {
2717
+ pushPayload();
2718
+ parserState = "text";
2719
+ continue;
2720
+ }
2721
+ if (character === ESC) {
2722
+ parserState = "osc_escape";
2723
+ continue;
2724
+ }
2725
+ if (oscBuffer.length < MAX_OSC_LENGTH) oscBuffer += character;
2726
+ continue;
2727
+ }
2728
+ if (parserState === "osc_escape") {
2729
+ if (character === "\\") {
2730
+ pushPayload();
2731
+ parserState = "text";
2732
+ continue;
2733
+ }
2734
+ if (oscBuffer.length < MAX_OSC_LENGTH) {
2735
+ oscBuffer += ESC;
2736
+ oscBuffer += character;
2737
+ }
2738
+ parserState = "osc";
2739
+ continue;
2740
+ }
2741
+ if (character === ESC) parserState = "escape";
2742
+ }
2743
+ return payloads;
2744
+ }
2745
+ function resolveThemeColor(root, slot, theme) {
2746
+ const variableName = resolveThemeColorVariable(slot);
2747
+ const computedValue = root.ownerDocument.defaultView?.getComputedStyle(root).getPropertyValue(variableName).trim();
2748
+ const normalizedComputed = computedValue ? normalizeTerminalColor(computedValue) : null;
2749
+ if (normalizedComputed) return normalizedComputed;
2750
+ return (theme === "light" ? DEFAULT_LIGHT_THEME_COLORS : DEFAULT_DARK_THEME_COLORS)[slot];
2751
+ }
2752
+ function resolveThemeColorVariable(slot) {
2753
+ if (slot === "background") return "--theme-term-bg";
2754
+ if (slot === "cursor") return "--theme-term-cursor";
2755
+ return "--theme-term-fg";
2756
+ }
2757
+ function toTerminalRgbColor(color) {
2758
+ const rgb = parseCssRgbColor(color) ?? parseCssHexColor(color) ?? {
2759
+ blue: 255,
2760
+ green: 255,
2761
+ red: 255
2762
+ };
2763
+ return `rgb:${toTerminalRgbChannel(rgb.red)}/${toTerminalRgbChannel(rgb.green)}/${toTerminalRgbChannel(rgb.blue)}`;
2764
+ }
2765
+ function toTerminalRgbChannel(value) {
2766
+ return clamp$1(value, 0, 255).toString(16).padStart(2, "0").repeat(2);
2767
+ }
2768
+ function parseTerminalRgbColor(value) {
2769
+ const match = /^rgb:([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})$/.exec(value);
2770
+ if (!match) return null;
2771
+ return {
2772
+ blue: normalizeHexChannel(match[3] ?? ""),
2773
+ green: normalizeHexChannel(match[2] ?? ""),
2774
+ red: normalizeHexChannel(match[1] ?? "")
2775
+ };
2776
+ }
2777
+ function normalizeHexChannel(value) {
2778
+ if (value.length === 0) return 0;
2779
+ const expanded = value.length === 1 ? `${value}${value}` : value.slice(0, 2);
2780
+ return clamp$1(Number.parseInt(expanded, 16), 0, 255);
2781
+ }
2782
+ function expandShortHexColor(value) {
2783
+ const [, red = "0", green = "0", blue = "0"] = value;
2784
+ return `#${red}${red}${green}${green}${blue}${blue}`.toLowerCase();
2785
+ }
2786
+ function resolveColorSlot(command) {
2787
+ if (command === "11") return "background";
2788
+ if (command === "12") return "cursor";
2789
+ return "foreground";
2790
+ }
2791
+ function inferThemeFromBackground(color) {
2792
+ const rgb = parseCssRgbColor(color) ?? parseCssHexColor(color);
2793
+ if (!rgb) return "dark";
2794
+ return .2126 * toLinearRgb(rgb.red) + .7152 * toLinearRgb(rgb.green) + .0722 * toLinearRgb(rgb.blue) > .45 ? "light" : "dark";
2795
+ }
2796
+ function parseCssRgbColor(color) {
2797
+ const match = /^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/.exec(color);
2798
+ if (!match) return null;
2799
+ return {
2800
+ blue: clamp$1(Number.parseInt(match[3] ?? "", 10), 0, 255),
2801
+ green: clamp$1(Number.parseInt(match[2] ?? "", 10), 0, 255),
2802
+ red: clamp$1(Number.parseInt(match[1] ?? "", 10), 0, 255)
2803
+ };
2804
+ }
2805
+ function parseCssHexColor(color) {
2806
+ const match = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/.exec(color);
2807
+ if (!match) return null;
2808
+ return {
2809
+ blue: Number.parseInt(match[3] ?? "0", 16),
2810
+ green: Number.parseInt(match[2] ?? "0", 16),
2811
+ red: Number.parseInt(match[1] ?? "0", 16)
2812
+ };
2813
+ }
2814
+ function toLinearRgb(value) {
2815
+ const channel = clamp$1(value, 0, 255) / 255;
2816
+ return channel <= .03928 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
2817
+ }
2818
+ function mergeThemeUpdate(target, source) {
2819
+ if (!source) return;
2820
+ Object.assign(target.colors, source.colors);
2821
+ target.palette.push(...source.palette);
2822
+ target.theme = source.theme ?? target.theme;
2823
+ }
2824
+ function hasThemeUpdate(update) {
2825
+ return Object.keys(update.colors).length > 0 || update.palette.length > 0 || Boolean(update.theme);
2826
+ }
2827
+ function clamp$1(value, min, max) {
2828
+ return Math.min(max, Math.max(min, value));
2829
+ }
2830
+ //#endregion
2831
+ //#region src/frontend/terminal-app.ts
2832
+ const SUPERSEDED_CLOSE_CODE = 4001;
2833
+ const DEFAULT_MAX_BYTES_PER_FRAME = 32 * 1024;
2834
+ const DEFAULT_TRANSCRIPT_SCROLLBACK_LIMIT = 1e3;
2835
+ const DEFAULT_RECONNECT_DELAY_MS = 250;
2836
+ const SCREEN_REDRAW_ARCHIVE_SUPPRESS_MS = 500;
2837
+ const TERMINAL_THEME_PROTOCOL_VARIABLES = [
2838
+ "--theme-term-bg",
2839
+ "--theme-term-cursor",
2840
+ "--theme-term-fg",
2841
+ ...Array.from({ length: 16 }, (_, index) => `--theme-term-color-${index}`)
2842
+ ];
2843
+ /**
2844
+ * Batches raw PTY bytes into animation frames without splitting UTF-8 codepoints or
2845
+ * incomplete ANSI sequences. This is the only throttling layer in the browser path.
2846
+ */
2847
+ function createBufferedTerminalWriter(target, scheduler = {}, options = {}) {
2848
+ const requestFrame = scheduler.requestFrame ?? ((callback) => requestBrowserFrame(callback));
2849
+ const cancelFrame = scheduler.cancelFrame ?? ((handle) => cancelBrowserFrame(handle));
2850
+ const maxBytesPerFrame = Math.max(1, options.maxBytesPerFrame ?? DEFAULT_MAX_BYTES_PER_FRAME);
2851
+ let chunks = [];
2852
+ let frameHandle = null;
2853
+ let headOffset = 0;
2854
+ const getPendingBytes = () => {
2855
+ if (chunks.length === 0) return new Uint8Array(0);
2856
+ if (chunks.length === 1) return headOffset === 0 ? chunks[0] : chunks[0].subarray(headOffset);
2857
+ return concatChunks([chunks[0].subarray(headOffset), ...chunks.slice(1)]);
2858
+ };
2859
+ const consumePendingBytes = (byteCount) => {
2860
+ let remainingBytes = byteCount;
2861
+ while (chunks.length > 0 && remainingBytes > 0) {
2862
+ const availableBytes = chunks[0].length - headOffset;
2863
+ if (availableBytes <= remainingBytes) {
2864
+ chunks.shift();
2865
+ headOffset = 0;
2866
+ remainingBytes -= availableBytes;
2867
+ continue;
2868
+ }
2869
+ headOffset += remainingBytes;
2870
+ remainingBytes = 0;
2871
+ }
2872
+ };
2873
+ const isUtf8ContinuationByte = (value) => (value & 192) === 128;
2874
+ const isUtf8LeadByte = (value) => (value & 128) !== 0 && !isUtf8ContinuationByte(value);
2875
+ const resolveUtf8SafeBoundary = (bytes, preferredEnd) => {
2876
+ if (preferredEnd <= 0 || preferredEnd >= bytes.length) return preferredEnd;
2877
+ let index = preferredEnd;
2878
+ while (index > 0 && isUtf8ContinuationByte(bytes[index])) index -= 1;
2879
+ if (index < preferredEnd && isUtf8LeadByte(bytes[index])) return index;
2880
+ return preferredEnd;
2881
+ };
2882
+ const resolveAnsiSafeBoundary = (bytes, preferredEnd) => {
2883
+ if (preferredEnd <= 0 || preferredEnd >= bytes.length) return preferredEnd;
2884
+ let lastEscapeIndex = -1;
2885
+ for (let index = 0; index < preferredEnd; index += 1) if (bytes[index] === 27) lastEscapeIndex = index;
2886
+ if (lastEscapeIndex < 0) return preferredEnd;
2887
+ let index = lastEscapeIndex + 1;
2888
+ if (index >= preferredEnd) return lastEscapeIndex;
2889
+ const nextByte = bytes[index];
2890
+ if (nextByte === 91) {
2891
+ index += 1;
2892
+ while (index < preferredEnd) {
2893
+ const value = bytes[index];
2894
+ if (value >= 64 && value <= 126) return preferredEnd;
2895
+ index += 1;
2896
+ }
2897
+ return lastEscapeIndex;
2898
+ }
2899
+ if (nextByte === 93) {
2900
+ index += 1;
2901
+ while (index < preferredEnd) {
2902
+ const value = bytes[index];
2903
+ if (value === 7) return preferredEnd;
2904
+ if (value === 27 && index + 1 < preferredEnd && bytes[index + 1] === 92) return preferredEnd;
2905
+ index += 1;
2906
+ }
2907
+ return lastEscapeIndex;
2908
+ }
2909
+ return preferredEnd;
2910
+ };
2911
+ const resolveTrailingAnsiCarryLength = (bytes) => {
2912
+ let lastEscapeIndex = -1;
2913
+ for (let index = 0; index < bytes.length; index += 1) if (bytes[index] === 27) lastEscapeIndex = index;
2914
+ if (lastEscapeIndex < 0 || lastEscapeIndex >= bytes.length - 1) return lastEscapeIndex < 0 ? 0 : bytes.length - lastEscapeIndex;
2915
+ const nextByte = bytes[lastEscapeIndex + 1];
2916
+ if (nextByte === 91) {
2917
+ for (let index = lastEscapeIndex + 2; index < bytes.length; index += 1) {
2918
+ const value = bytes[index];
2919
+ if (value >= 64 && value <= 126) return 0;
2920
+ }
2921
+ return bytes.length - lastEscapeIndex;
2922
+ }
2923
+ if (nextByte === 93) {
2924
+ for (let index = lastEscapeIndex + 2; index < bytes.length; index += 1) {
2925
+ const value = bytes[index];
2926
+ if (value === 7) return 0;
2927
+ if (value === 27 && index + 1 < bytes.length && bytes[index + 1] === 92) return 0;
2928
+ }
2929
+ return bytes.length - lastEscapeIndex;
2930
+ }
2931
+ return 0;
2932
+ };
2933
+ const resolveSafeSplitBoundary = (bytes, preferredEnd) => {
2934
+ let boundary = resolveUtf8SafeBoundary(bytes, preferredEnd);
2935
+ boundary = resolveAnsiSafeBoundary(bytes, boundary);
2936
+ return boundary > 0 ? boundary : preferredEnd;
2937
+ };
2938
+ const flush = () => {
2939
+ frameHandle = null;
2940
+ if (chunks.length === 0) return;
2941
+ const pendingBytes = getPendingBytes();
2942
+ if (pendingBytes.length === 0) {
2943
+ chunks = [];
2944
+ headOffset = 0;
2945
+ return;
2946
+ }
2947
+ const preferredEnd = Math.min(maxBytesPerFrame, pendingBytes.length);
2948
+ const safeEnd = resolveSafeSplitBoundary(pendingBytes, preferredEnd);
2949
+ const trailingAnsiCarryLength = preferredEnd === pendingBytes.length ? resolveTrailingAnsiCarryLength(pendingBytes) : 0;
2950
+ const payloadByteCount = trailingAnsiCarryLength > 0 ? Math.max(0, safeEnd - trailingAnsiCarryLength) : safeEnd > 0 ? safeEnd : preferredEnd;
2951
+ if (payloadByteCount <= 0) {
2952
+ frameHandle = requestFrame(() => {
2953
+ flush();
2954
+ });
2955
+ return;
2956
+ }
2957
+ const payload = pendingBytes.subarray(0, payloadByteCount);
2958
+ target.write(payload);
2959
+ consumePendingBytes(payloadByteCount);
2960
+ if (chunks.length > 0) frameHandle = requestFrame(() => {
2961
+ flush();
2962
+ });
2963
+ };
2964
+ return {
2965
+ destroy() {
2966
+ if (frameHandle !== null) {
2967
+ cancelFrame(frameHandle);
2968
+ frameHandle = null;
2969
+ }
2970
+ chunks = [];
2971
+ headOffset = 0;
2972
+ },
2973
+ discardPending() {
2974
+ if (frameHandle !== null) {
2975
+ cancelFrame(frameHandle);
2976
+ frameHandle = null;
2977
+ }
2978
+ chunks = [];
2979
+ headOffset = 0;
2980
+ },
2981
+ enqueue(chunk) {
2982
+ if (chunk.length === 0) return;
2983
+ chunks.push(chunk);
2984
+ if (frameHandle === null) frameHandle = requestFrame(() => {
2985
+ flush();
2986
+ });
2987
+ }
2988
+ };
2989
+ }
2990
+ async function mountTerminalApp(doc = document, dependencies = {}) {
2991
+ const elements = dependencies.elements ?? {};
2992
+ const shell = elements.shell ?? getRequiredElement(doc, "[data-shell]");
2993
+ const status = hasElementOverride(elements, "status") ? elements.status ?? null : getOptionalElement(doc, "[data-terminal-status]");
2994
+ const loading = hasElementOverride(elements, "loading") ? elements.loading ?? null : getOptionalElement(doc, "[data-terminal-loading]");
2995
+ const terminalRoot = elements.terminalRoot ?? getRequiredElement(doc, "[data-terminal-root]");
2996
+ terminalRoot.classList.add("aitty-terminal-root");
2997
+ const windowObject = doc.defaultView ?? window;
2998
+ const sessionUrl = resolveAittySessionUrl(windowObject, dependencies.src);
2999
+ const themeController = createTerminalThemeController(doc, shell, terminalRoot, dependencies.theme);
3000
+ const resolvedRuntimeKind = (dependencies.resolveRuntimeKind ?? ((resolverDoc, resolverShell) => resolveShellRuntimeKind(resolverDoc, resolverShell, sessionUrl)))(doc, shell);
3001
+ const runtimeKind = typeof resolvedRuntimeKind === "string" ? resolvedRuntimeKind : await resolvedRuntimeKind;
3002
+ shell.dataset.runtime = runtimeKind;
3003
+ shell.dataset.terminalPipeline = "raw";
3004
+ terminalRoot.dataset.terminalPipeline = "raw";
3005
+ const frameScheduler = dependencies.frameScheduler ?? {};
3006
+ const requestFrame = frameScheduler.requestFrame ?? ((callback) => windowObject.requestAnimationFrame(callback));
3007
+ const cancelFrame = frameScheduler.cancelFrame ?? ((handle) => windowObject.cancelAnimationFrame(handle));
3008
+ const reconnectDelayMs = Math.max(0, dependencies.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS);
3009
+ const getScrollSurface = () => resolveScrollSurface(doc, terminalRoot, dependencies.scroll);
3010
+ const encoder = new TextEncoder();
3011
+ const ansiStyleTracker = createAnsiStyleTracker();
3012
+ const themeProtocolParser = createTerminalThemeProtocolParser();
3013
+ let transport = null;
3014
+ let term = null;
3015
+ let transcriptArchive = null;
3016
+ let writer = null;
3017
+ let archiveWriter = null;
3018
+ let sessionState = "running";
3019
+ let destroyed = false;
3020
+ let helloReceived = false;
3021
+ let outputReady = false;
3022
+ let reconnecting = false;
3023
+ let termReady = false;
3024
+ let snapScrollbackOnNextWrite = false;
3025
+ let followLiveOutput = false;
3026
+ const pendingFrames = [];
3027
+ const pendingInputFrames = [];
3028
+ let reconnectHandle = null;
3029
+ let scrollbackSnapHandle = null;
3030
+ let scrollbackSnapPassesRemaining = 0;
3031
+ let disposeViewportSizer = null;
3032
+ let disposeScrollMetricsObserver = null;
3033
+ let lastResizeSignature = null;
3034
+ let lastScrollMetrics = null;
3035
+ let suppressTermResizeCallback = false;
3036
+ let statusSnapshot = {
3037
+ connection: normalizeConnectionState(shell.dataset.connection),
3038
+ loading: {
3039
+ message: loading?.textContent ?? "Booting terminal...",
3040
+ visible: loading ? !loading.hidden : false
3041
+ },
3042
+ message: status?.textContent ?? "Connecting to local session...",
3043
+ output: normalizeOutputState(shell.dataset.output),
3044
+ sessionState: normalizeSessionPresentationState(shell.dataset.sessionState)
3045
+ };
3046
+ const getStatusSnapshot = () => cloneTerminalStatusSnapshot(statusSnapshot);
3047
+ const publishScrollMetrics = () => {
3048
+ const onMetricsChange = dependencies.scroll?.onMetricsChange;
3049
+ if (!onMetricsChange) return;
3050
+ const nextMetrics = getScrollMetrics(getScrollSurface());
3051
+ if (lastScrollMetrics && areScrollMetricsEqual(lastScrollMetrics, nextMetrics)) return;
3052
+ lastScrollMetrics = nextMetrics;
3053
+ onMetricsChange({ ...nextMetrics });
3054
+ };
3055
+ const presentStatus = (patch) => {
3056
+ const nextStatus = {
3057
+ ...statusSnapshot,
3058
+ ...patch,
3059
+ loading: {
3060
+ ...statusSnapshot.loading,
3061
+ ...patch.loading
3062
+ }
3063
+ };
3064
+ const changed = !areTerminalStatusSnapshotsEqual(statusSnapshot, nextStatus);
3065
+ statusSnapshot = nextStatus;
3066
+ shell.dataset.connection = nextStatus.connection;
3067
+ shell.dataset.output = nextStatus.output;
3068
+ shell.dataset.sessionState = nextStatus.sessionState;
3069
+ if (status) status.textContent = nextStatus.message;
3070
+ if (loading) {
3071
+ loading.textContent = nextStatus.loading.visible ? nextStatus.loading.message : "";
3072
+ loading.hidden = !nextStatus.loading.visible;
3073
+ }
3074
+ if (changed) dependencies.onStatusChange?.(getStatusSnapshot());
3075
+ };
3076
+ dependencies.onStatusChange?.(getStatusSnapshot());
3077
+ const syncTerminalPresentation = () => {
3078
+ if (!transcriptArchive) return;
3079
+ syncTerminalSurface(terminalRoot, transcriptArchive, term, ansiStyleTracker, { interactive: sessionState === "running" });
3080
+ syncTrailingTerminalBlankRows(terminalRoot);
3081
+ requestScrollUiUpdate(dependencies.scroll);
3082
+ publishScrollMetrics();
3083
+ };
3084
+ const markLiveSession = () => {
3085
+ reconnecting = false;
3086
+ presentStatus({
3087
+ connection: "open",
3088
+ loading: {
3089
+ message: "Booting terminal...",
3090
+ visible: false
3091
+ },
3092
+ message: "Live shell on loopback",
3093
+ output: "ready",
3094
+ sessionState: "live"
3095
+ });
3096
+ };
3097
+ const markWaitingForOutput = () => {
3098
+ presentStatus({
3099
+ connection: "open",
3100
+ loading: {
3101
+ message: "Booting terminal...",
3102
+ visible: !outputReady
3103
+ },
3104
+ message: outputReady ? "Live shell on loopback" : "Connected. Waiting for shell output...",
3105
+ sessionState: outputReady ? "live" : "starting"
3106
+ });
3107
+ };
3108
+ const markOutputReady = () => {
3109
+ if (outputReady) return false;
3110
+ outputReady = true;
3111
+ markLiveSession();
3112
+ return true;
3113
+ };
3114
+ const cancelScrollbackSnap = () => {
3115
+ if (scrollbackSnapHandle === null) {
3116
+ scrollbackSnapPassesRemaining = 0;
3117
+ return;
3118
+ }
3119
+ cancelFrame(scrollbackSnapHandle);
3120
+ scrollbackSnapHandle = null;
3121
+ scrollbackSnapPassesRemaining = 0;
3122
+ };
3123
+ const cancelReconnect = () => {
3124
+ if (reconnectHandle === null) return;
3125
+ clearTimeout(reconnectHandle);
3126
+ reconnectHandle = null;
3127
+ };
3128
+ const getTargetScrollTop = (scrollSurface, { preferTranscriptFollow = false } = {}) => {
3129
+ return getScrollbackMax(scrollSurface);
3130
+ };
3131
+ const scheduleScrollbackSnapToBottom = (passes = 1, options = {}) => {
3132
+ scrollbackSnapPassesRemaining = Math.max(scrollbackSnapPassesRemaining, passes);
3133
+ if (scrollbackSnapHandle !== null) return;
3134
+ const runSnap = () => {
3135
+ scrollbackSnapHandle = requestFrame(() => {
3136
+ scrollbackSnapHandle = null;
3137
+ const scrollSurface = getScrollSurface();
3138
+ scrollSurface.scrollTop = getTargetScrollTop(scrollSurface, options);
3139
+ requestScrollUiUpdate(dependencies.scroll);
3140
+ publishScrollMetrics();
3141
+ scrollbackSnapPassesRemaining = Math.max(0, scrollbackSnapPassesRemaining - 1);
3142
+ if (scrollbackSnapPassesRemaining > 0) runSnap();
3143
+ });
3144
+ };
3145
+ runSnap();
3146
+ };
3147
+ const syncLiveOutputFollowScroll = () => {
3148
+ if (!followLiveOutput) return;
3149
+ scheduleScrollbackSnapToBottom(2, { preferTranscriptFollow: true });
3150
+ };
3151
+ const syncPreservedArchiveVisibility = ({ allowReveal = false, scrollTop = getScrollSurface().scrollTop, maxScrollTop = getScrollbackMax(getScrollSurface()) } = {}) => {
3152
+ if (!transcriptArchive) return;
3153
+ if (isAtScrollbackBottom(scrollTop, maxScrollTop)) {
3154
+ transcriptArchive.concealPreservedArchive();
3155
+ return;
3156
+ }
3157
+ if (allowReveal) transcriptArchive.revealPreservedArchive();
3158
+ };
3159
+ const disposeHotkeys = installScrollbackInteractions(terminalRoot, {
3160
+ getScrollSurface,
3161
+ setScrollTop(scrollSurface, scrollTop) {
3162
+ scrollSurface.scrollTop = scrollTop;
3163
+ requestScrollUiUpdate(dependencies.scroll);
3164
+ publishScrollMetrics();
3165
+ },
3166
+ onInput({ event }) {
3167
+ const preserveVisiblePrompt = shouldPreserveVisiblePromptOnInput(event) && isLiveInputSurfaceVisible(shell, terminalRoot, windowObject);
3168
+ const shouldFollowLiveOutput = shouldFollowLiveOutputOnInput(event);
3169
+ snapScrollbackOnNextWrite = !preserveVisiblePrompt;
3170
+ followLiveOutput = shouldFollowLiveOutput;
3171
+ cancelScrollbackSnap();
3172
+ if (!preserveVisiblePrompt) {
3173
+ const scrollSurface = getScrollSurface();
3174
+ scrollSurface.scrollTop = getTargetScrollTop(scrollSurface);
3175
+ requestScrollUiUpdate(dependencies.scroll);
3176
+ publishScrollMetrics();
3177
+ }
3178
+ syncPreservedArchiveVisibility();
3179
+ },
3180
+ onManualScroll({ scrollTop, maxScrollTop }) {
3181
+ syncPreservedArchiveVisibility({
3182
+ allowReveal: true,
3183
+ scrollTop,
3184
+ maxScrollTop
3185
+ });
3186
+ snapScrollbackOnNextWrite = false;
3187
+ followLiveOutput = false;
3188
+ cancelScrollbackSnap();
3189
+ requestScrollUiUpdate(dependencies.scroll);
3190
+ publishScrollMetrics();
3191
+ }
3192
+ });
3193
+ const resetTerminalBuffer = () => {
3194
+ if (!term) return;
3195
+ writer?.discardPending();
3196
+ archiveWriter?.discardPending();
3197
+ transcriptArchive?.preserveSnapshot([]);
3198
+ ansiStyleTracker.reset(term.cols, term.rows);
3199
+ if (term.bridge && typeof term.bridge.init === "function") {
3200
+ term.bridge.init(term.cols, term.rows);
3201
+ term.renderer?.setup?.(term.cols, term.rows);
3202
+ term.renderer?.render?.(term.bridge);
3203
+ ansiStyleTracker.syncFromBridge(term.bridge);
3204
+ syncTerminalPresentation();
3205
+ return;
3206
+ }
3207
+ term.write?.(encoder.encode("\x1Bc"));
3208
+ syncTerminalPresentation();
3209
+ };
3210
+ const flushPendingInput = () => {
3211
+ if (!helloReceived || sessionState !== "running" || pendingInputFrames.length === 0) return;
3212
+ for (const chunk of pendingInputFrames.splice(0)) transport?.send(chunk);
3213
+ };
3214
+ const processVisiblePayload = (data) => {
3215
+ const firstOutput = markOutputReady();
3216
+ const themeUpdate = themeProtocolParser.append(data);
3217
+ let themeChanged = false;
3218
+ if (themeUpdate) themeChanged = themeController.syncProtocolUpdate(themeUpdate);
3219
+ const themeQueryResponse = resolveTerminalThemeQueryResponse(data, {
3220
+ root: terminalRoot,
3221
+ theme: themeController.getTheme()
3222
+ });
3223
+ if (themeQueryResponse) sendInputToPty(themeQueryResponse);
3224
+ if (!termReady || !writer || !archiveWriter) {
3225
+ pendingFrames.push(data);
3226
+ if (themeChanged) renderTerminalNow(term, { force: true });
3227
+ return;
3228
+ }
3229
+ writer.enqueue(data);
3230
+ archiveWriter.enqueue(data);
3231
+ if (themeChanged) renderTerminalNow(term, { force: true });
3232
+ syncTerminalPresentation();
3233
+ if (followLiveOutput) {
3234
+ snapScrollbackOnNextWrite = false;
3235
+ syncLiveOutputFollowScroll();
3236
+ } else if (snapScrollbackOnNextWrite || firstOutput) {
3237
+ snapScrollbackOnNextWrite = false;
3238
+ scheduleScrollbackSnapToBottom(2);
3239
+ }
3240
+ };
3241
+ const sendInputToPty = (data) => {
3242
+ if (sessionState !== "running") return;
3243
+ if (!helloReceived) {
3244
+ pendingInputFrames.push(data);
3245
+ return;
3246
+ }
3247
+ transport?.send(data);
3248
+ };
3249
+ const sendUserInput = (data) => {
3250
+ sendInputToPty(data);
3251
+ };
3252
+ const emitResize = (cols, rows) => {
3253
+ const normalizedCols = normalizeResizeDimension(cols, term?.cols ?? 80);
3254
+ const normalizedRows = normalizeResizeDimension(rows, term?.rows ?? 24);
3255
+ ansiStyleTracker.resize(normalizedCols, normalizedRows);
3256
+ syncDimensions(terminalRoot, normalizedCols, normalizedRows);
3257
+ transcriptArchive?.refresh();
3258
+ syncTerminalPresentation();
3259
+ const signature = `${normalizedCols}x${normalizedRows}`;
3260
+ if (lastResizeSignature === signature) return;
3261
+ lastResizeSignature = signature;
3262
+ if (sessionState !== "running") return;
3263
+ transport?.sendControl?.(createResizeControlFrame(normalizedCols, normalizedRows));
3264
+ };
3265
+ const syncTermDimensionsFromBridge = (requestedCols = term?.cols ?? 80, requestedRows = term?.rows ?? 24) => {
3266
+ if (!term) return {
3267
+ cols: normalizeResizeDimension(requestedCols, 80),
3268
+ rows: normalizeResizeDimension(requestedRows, 24)
3269
+ };
3270
+ const dimensions = resolveTerminalBridgeDimensions(term, requestedCols, requestedRows);
3271
+ term.cols = dimensions.cols;
3272
+ term.rows = dimensions.rows;
3273
+ if (term.renderer && typeof term.renderer.setup === "function" && (term.renderer.cols !== dimensions.cols || term.renderer.rows !== dimensions.rows)) term.renderer.setup(dimensions.cols, dimensions.rows);
3274
+ return dimensions;
3275
+ };
3276
+ const resizeTerminalTo = (cols, rows) => {
3277
+ if (!term) return;
3278
+ const requestedCols = normalizeResizeDimension(cols, term.cols);
3279
+ const requestedRows = normalizeResizeDimension(rows, term.rows);
3280
+ if (term.cols !== requestedCols || term.rows !== requestedRows) {
3281
+ suppressTermResizeCallback = true;
3282
+ try {
3283
+ term.resize(requestedCols, requestedRows);
3284
+ } finally {
3285
+ suppressTermResizeCallback = false;
3286
+ }
3287
+ }
3288
+ const actual = syncTermDimensionsFromBridge(requestedCols, requestedRows);
3289
+ applyTerminalElementHeight(terminalRoot, actual.rows);
3290
+ emitResize(actual.cols, actual.rows);
3291
+ };
3292
+ const handleTermResize = (cols, rows) => {
3293
+ if (suppressTermResizeCallback) return;
3294
+ const actual = syncTermDimensionsFromBridge(cols, rows);
3295
+ emitResize(actual.cols, actual.rows);
3296
+ };
3297
+ const showReconnectState = (statusText) => {
3298
+ reconnecting = true;
3299
+ helloReceived = false;
3300
+ presentStatus({
3301
+ connection: "reconnecting",
3302
+ loading: {
3303
+ message: "Reconnecting...",
3304
+ visible: true
3305
+ },
3306
+ message: statusText,
3307
+ sessionState: outputReady ? "reconnecting" : "starting"
3308
+ });
3309
+ };
3310
+ const scheduleReconnect = () => {
3311
+ if (destroyed || reconnectHandle !== null || sessionState !== "running") return;
3312
+ showReconnectState("Connection lost. Reconnecting...");
3313
+ reconnectHandle = setTimeout(() => {
3314
+ reconnectHandle = null;
3315
+ if (destroyed || sessionState !== "running") return;
3316
+ transport?.connect();
3317
+ }, reconnectDelayMs);
3318
+ };
3319
+ const handleBrowserOffline = () => {
3320
+ if (destroyed || sessionState !== "running" || reconnecting) return;
3321
+ showReconnectState("Connection interrupted. Reconnecting...");
3322
+ syncTerminalPresentation();
3323
+ transport?.disconnect?.("offline");
3324
+ };
3325
+ const handleBrowserOnline = () => {
3326
+ if (destroyed || sessionState !== "running" || !reconnecting) return;
3327
+ cancelReconnect();
3328
+ transport?.connect();
3329
+ };
3330
+ term = (dependencies.createTerm ?? ((element, options) => new WTerm(element, options)))(terminalRoot, {
3331
+ autoResize: false,
3332
+ cursorBlink: true,
3333
+ onData(data) {
3334
+ sendUserInput(data);
3335
+ },
3336
+ onResize(cols, rows) {
3337
+ handleTermResize(cols, rows);
3338
+ },
3339
+ onTitle(title) {
3340
+ if (title) doc.title = `${title} - aitty`;
3341
+ }
3342
+ });
3343
+ terminalRoot._aittyTerm = term;
3344
+ transcriptArchive = createTranscriptArchive(terminalRoot, frameScheduler, {
3345
+ getCols() {
3346
+ return term?.cols ?? 80;
3347
+ },
3348
+ getVisibleRows() {
3349
+ return term?.rows ?? 24;
3350
+ },
3351
+ scrollbackLimit: dependencies.transcriptArchiveOptions?.scrollbackLimit
3352
+ });
3353
+ archiveWriter = createBufferedTerminalWriter({ write(data) {
3354
+ transcriptArchive?.append(data);
3355
+ } }, frameScheduler);
3356
+ writer = createBufferedTerminalWriter({ write(data) {
3357
+ ansiStyleTracker.append(data);
3358
+ term?.write?.(data);
3359
+ ansiStyleTracker.syncFromBridge(term?.bridge);
3360
+ const renderHints = ansiStyleTracker.consumeRenderHints();
3361
+ renderTerminalNow(term, { force: renderHints.clearScreen || renderHints.styleChanged });
3362
+ syncTerminalPresentation();
3363
+ } }, frameScheduler);
3364
+ transport = (dependencies.createTransport ?? ((handlers) => createBrowserTransport(handlers)))({
3365
+ onBinary(data) {
3366
+ if (!helloReceived) helloReceived = true;
3367
+ processVisiblePayload(data);
3368
+ if (reconnecting && outputReady) markLiveSession();
3369
+ flushPendingInput();
3370
+ },
3371
+ onClose(event) {
3372
+ if (destroyed) return;
3373
+ if (sessionState === "running" && event?.code === SUPERSEDED_CLOSE_CODE) {
3374
+ cancelReconnect();
3375
+ reconnecting = false;
3376
+ sessionState = "superseded";
3377
+ presentStatus({
3378
+ connection: "superseded",
3379
+ loading: {
3380
+ message: "Booting terminal...",
3381
+ visible: false
3382
+ },
3383
+ message: "Session was taken over in another tab",
3384
+ sessionState: "superseded"
3385
+ });
3386
+ syncTerminalPresentation();
3387
+ return;
3388
+ }
3389
+ if (sessionState === "running") {
3390
+ scheduleReconnect();
3391
+ syncTerminalPresentation();
3392
+ return;
3393
+ }
3394
+ presentStatus({ connection: sessionState === "error" ? "error" : "closed" });
3395
+ syncTerminalPresentation();
3396
+ },
3397
+ onControlMessage(data) {
3398
+ const message = parseAittyControlFrame(data);
3399
+ if (!message) return;
3400
+ if (message.type === "hello") {
3401
+ helloReceived = true;
3402
+ const replay = decodeHelloReplay(message.replay);
3403
+ if (reconnecting && replay.length > 0) resetTerminalBuffer();
3404
+ if (replay.length > 0) processVisiblePayload(replay);
3405
+ cancelReconnect();
3406
+ if (reconnecting) if (outputReady) markLiveSession();
3407
+ else {
3408
+ reconnecting = false;
3409
+ markWaitingForOutput();
3410
+ }
3411
+ flushPendingInput();
3412
+ return;
3413
+ }
3414
+ if (message.type === "ping") {
3415
+ transport?.sendControl?.(createPongControlFrame());
3416
+ return;
3417
+ }
3418
+ if (message.type === "theme") {
3419
+ let themeChanged = false;
3420
+ if (message.theme === null) {
3421
+ themeChanged = themeController.setTheme(void 0);
3422
+ if (themeChanged) renderTerminalNow(term, { force: true });
3423
+ return;
3424
+ }
3425
+ const theme = normalizeThemeName(message.theme);
3426
+ if (theme) themeChanged = themeController.setTheme(theme);
3427
+ if (themeChanged) renderTerminalNow(term, { force: true });
3428
+ return;
3429
+ }
3430
+ if (message.type !== "exit") return;
3431
+ cancelReconnect();
3432
+ const exitPresentation = resolveExitPresentation(message);
3433
+ sessionState = exitPresentation.sessionState;
3434
+ reconnecting = false;
3435
+ presentStatus({
3436
+ connection: "closed",
3437
+ loading: {
3438
+ message: "Booting terminal...",
3439
+ visible: false
3440
+ },
3441
+ message: exitPresentation.statusText,
3442
+ sessionState: exitPresentation.sessionState
3443
+ });
3444
+ syncTerminalPresentation();
3445
+ },
3446
+ onError(event) {
3447
+ if (destroyed || sessionState !== "running") return;
3448
+ showReconnectState("Connection interrupted. Reconnecting...");
3449
+ syncTerminalPresentation();
3450
+ if (event instanceof ErrorEvent && event.message) event.message;
3451
+ },
3452
+ onOpen() {
3453
+ cancelReconnect();
3454
+ if (reconnecting) {
3455
+ presentStatus({
3456
+ connection: "open",
3457
+ loading: {
3458
+ message: "Reconnecting...",
3459
+ visible: true
3460
+ },
3461
+ message: outputReady ? "Reconnected. Syncing transcript..." : "Connected. Waiting for shell output...",
3462
+ sessionState: outputReady ? "reconnecting" : "starting"
3463
+ });
3464
+ return;
3465
+ }
3466
+ if (!outputReady) {
3467
+ presentStatus({
3468
+ connection: "open",
3469
+ message: "Connected. Waiting for shell output..."
3470
+ });
3471
+ return;
3472
+ }
3473
+ presentStatus({ connection: "open" });
3474
+ }
3475
+ });
3476
+ await term.init();
3477
+ replaceTerminalInputHandler(term);
3478
+ const disposeInputPolicies = installTerminalInputPolicies(term, {
3479
+ captureDocumentCtrlN: false,
3480
+ onData(data) {
3481
+ sendUserInput(data);
3482
+ },
3483
+ resolveKey: dependencies.input?.resolveKey
3484
+ });
3485
+ installBrowserRenderer(term, ansiStyleTracker);
3486
+ termReady = true;
3487
+ const initialSize = syncTermDimensionsFromBridge(term.cols, term.rows);
3488
+ ansiStyleTracker.reset(initialSize.cols, initialSize.rows);
3489
+ disposeViewportSizer = installTerminalViewportSizer(term, terminalRoot, windowObject, resizeTerminalTo);
3490
+ syncTermDimensionsFromBridge(term.cols, term.rows);
3491
+ emitResize(term.cols, term.rows);
3492
+ syncTerminalPresentation();
3493
+ term.focus();
3494
+ disposeScrollMetricsObserver = installScrollMetricsObserver(getScrollSurface(), publishScrollMetrics);
3495
+ publishScrollMetrics();
3496
+ windowObject.addEventListener("offline", handleBrowserOffline);
3497
+ windowObject.addEventListener("online", handleBrowserOnline);
3498
+ transport.connect(toWebSocketUrl(sessionUrl));
3499
+ for (const frame of pendingFrames.splice(0)) writer.enqueue(frame);
3500
+ return {
3501
+ destroy() {
3502
+ if (destroyed) return;
3503
+ destroyed = true;
3504
+ delete terminalRoot._aittyTerm;
3505
+ cancelScrollbackSnap();
3506
+ cancelReconnect();
3507
+ disposeViewportSizer?.();
3508
+ disposeViewportSizer = null;
3509
+ disposeScrollMetricsObserver?.();
3510
+ disposeScrollMetricsObserver = null;
3511
+ archiveWriter?.destroy();
3512
+ transcriptArchive?.destroy();
3513
+ writer?.destroy();
3514
+ disposeHotkeys();
3515
+ disposeInputPolicies();
3516
+ themeController.destroy();
3517
+ windowObject.removeEventListener("offline", handleBrowserOffline);
3518
+ windowObject.removeEventListener("online", handleBrowserOnline);
3519
+ transport?.close();
3520
+ term?.destroy();
3521
+ },
3522
+ getStatus: getStatusSnapshot,
3523
+ getTheme: themeController.getTheme,
3524
+ setTheme: themeController.setTheme,
3525
+ term,
3526
+ transport
3527
+ };
3528
+ }
3529
+ function mountAitty(containerOrOptions = {}, maybeOptions = {}) {
3530
+ if (typeof containerOrOptions === "string" || isElementLike(containerOrOptions)) return mountAittyInContainer(containerOrOptions, maybeOptions);
3531
+ return mountAittyWithElements(containerOrOptions);
3532
+ }
3533
+ function mountAittyWithElements(options = {}) {
3534
+ const { document: doc = document, loading, shell, status, terminalRoot, ...dependencies } = options;
3535
+ const elements = { ...dependencies.elements };
3536
+ if ("loading" in options) elements.loading = loading;
3537
+ if (shell) elements.shell = shell;
3538
+ if ("status" in options) elements.status = status;
3539
+ if (terminalRoot) elements.terminalRoot = terminalRoot;
3540
+ return mountTerminalApp(doc, {
3541
+ ...dependencies,
3542
+ elements
3543
+ });
3544
+ }
3545
+ const AITTY_TERMINAL_TAG_NAME = "aitty-terminal";
3546
+ function defineAittyTerminalElement(registry = globalThis.customElements) {
3547
+ if (!registry || registry.get(AITTY_TERMINAL_TAG_NAME) || typeof HTMLElement === "undefined") return;
3548
+ registry.define(AITTY_TERMINAL_TAG_NAME, createAittyTerminalElementConstructor());
3549
+ }
3550
+ function createAittyTerminalElementConstructor() {
3551
+ return class AittyTerminalCustomElement extends HTMLElement {
3552
+ static get observedAttributes() {
3553
+ return ["src", "theme"];
3554
+ }
3555
+ #mounted = null;
3556
+ #mountVersion = 0;
3557
+ connectedCallback() {
3558
+ this.#mount();
3559
+ }
3560
+ disconnectedCallback() {
3561
+ this.#destroyMounted();
3562
+ }
3563
+ attributeChangedCallback(name, oldValue, nextValue) {
3564
+ if (oldValue === nextValue || !this.isConnected) return;
3565
+ if (name === "theme" && this.#mounted) {
3566
+ this.#mounted.setTheme(normalizeThemeName(nextValue ?? void 0));
3567
+ return;
3568
+ }
3569
+ this.#mount();
3570
+ }
3571
+ #destroyMounted() {
3572
+ this.#mountVersion += 1;
3573
+ this.#mounted?.destroy();
3574
+ this.#mounted = null;
3575
+ }
3576
+ async #mount() {
3577
+ this.#destroyMounted();
3578
+ const mountVersion = this.#mountVersion;
3579
+ try {
3580
+ const mounted = await mountAitty(this, {
3581
+ document: this.ownerDocument,
3582
+ onStatusChange: (status) => {
3583
+ this.dispatchEvent(new CustomEvent("aitty:status", {
3584
+ bubbles: true,
3585
+ composed: true,
3586
+ detail: status
3587
+ }));
3588
+ },
3589
+ src: this.getAttribute("src") ?? void 0,
3590
+ theme: normalizeThemeName(this.getAttribute("theme") ?? void 0)
3591
+ });
3592
+ if (!this.isConnected || this.#mountVersion !== mountVersion) {
3593
+ mounted.destroy();
3594
+ return;
3595
+ }
3596
+ this.#mounted = mounted;
3597
+ this.dispatchEvent(new CustomEvent("aitty:mount", {
3598
+ bubbles: true,
3599
+ composed: true,
3600
+ detail: mounted
3601
+ }));
3602
+ } catch (error) {
3603
+ this.dispatchEvent(new CustomEvent("aitty:error", {
3604
+ bubbles: true,
3605
+ composed: true,
3606
+ detail: error
3607
+ }));
3608
+ }
3609
+ }
3610
+ };
3611
+ }
3612
+ async function mountAittyInContainer(container, options) {
3613
+ const { scrollAdapter, ...dependencies } = options;
3614
+ const doc = dependencies.document ?? resolveAittyDocument(container);
3615
+ const mount = resolveAittyMountContainer(doc, container);
3616
+ const view = createAittyEmbedView(doc, mount);
3617
+ const scrollOptions = {
3618
+ ...dependencies.scroll,
3619
+ viewport: view.viewport
3620
+ };
3621
+ const adapter = scrollAdapter?.({
3622
+ content: view.content,
3623
+ scrollOptions,
3624
+ target: view.scrollTarget,
3625
+ viewport: view.viewport
3626
+ });
3627
+ Object.assign(scrollOptions, adapter?.scrollOptions);
3628
+ const mounted = await mountTerminalApp(doc, {
3629
+ ...dependencies,
3630
+ scroll: scrollOptions,
3631
+ elements: {
3632
+ shell: view.shell,
3633
+ terminalRoot: view.terminalRoot
3634
+ }
3635
+ });
3636
+ let destroyed = false;
3637
+ return {
3638
+ ...mounted,
3639
+ destroy() {
3640
+ if (destroyed) return;
3641
+ destroyed = true;
3642
+ mounted.destroy();
3643
+ adapter?.destroy?.();
3644
+ view.shell.remove();
3645
+ mount.classList.remove("aitty-embed");
3646
+ }
3647
+ };
3648
+ }
3649
+ function resolveAittyDocument(container) {
3650
+ if (isElementLike(container)) return container.ownerDocument;
3651
+ if (typeof document !== "undefined") return document;
3652
+ throw new Error("mountAitty requires a browser document when mounting by selector");
3653
+ }
3654
+ function resolveAittyMountContainer(doc, container) {
3655
+ if (isDocumentElement(doc, container)) return container;
3656
+ if (isElementLike(container)) throw new Error("aitty mount container belongs to a different document");
3657
+ const element = doc.querySelector(container);
3658
+ if (!(element instanceof HTMLElement)) throw new Error(`Missing aitty mount container: ${container}`);
3659
+ return element;
3660
+ }
3661
+ function isElementLike(value) {
3662
+ return typeof value === "object" && value !== null && "nodeType" in value && "ownerDocument" in value;
3663
+ }
3664
+ function isDocumentElement(doc, value) {
3665
+ const HTMLElementConstructor = doc.defaultView?.HTMLElement;
3666
+ return Boolean(HTMLElementConstructor && value instanceof HTMLElementConstructor);
3667
+ }
3668
+ function createAittyEmbedView(doc, mount) {
3669
+ mount.replaceChildren();
3670
+ mount.classList.add("aitty-embed");
3671
+ const shell = doc.createElement("div");
3672
+ shell.className = "aitty-shell";
3673
+ shell.dataset.shell = "";
3674
+ shell.dataset.runtime = "session";
3675
+ shell.dataset.connection = "connecting";
3676
+ shell.dataset.output = "pending";
3677
+ shell.dataset.sessionState = "starting";
3678
+ const scrollTarget = doc.createElement("div");
3679
+ scrollTarget.className = "aitty-scroll-target";
3680
+ scrollTarget.dataset.aittyScrollTarget = "";
3681
+ const viewport = doc.createElement("div");
3682
+ viewport.className = "aitty-scroll-viewport";
3683
+ viewport.dataset.aittyScrollViewport = "";
3684
+ viewport.tabIndex = -1;
3685
+ const content = doc.createElement("div");
3686
+ content.className = "aitty-scroll-content";
3687
+ content.dataset.aittyScrollContent = "";
3688
+ const terminalRoot = doc.createElement("div");
3689
+ terminalRoot.className = "aitty-terminal-root terminal-root";
3690
+ terminalRoot.dataset.terminalRoot = "";
3691
+ terminalRoot.role = "application";
3692
+ terminalRoot.setAttribute("aria-label", "Terminal");
3693
+ content.append(terminalRoot);
3694
+ viewport.append(content);
3695
+ scrollTarget.append(viewport);
3696
+ shell.append(scrollTarget);
3697
+ mount.append(shell);
3698
+ return {
3699
+ content,
3700
+ scrollTarget,
3701
+ shell,
3702
+ terminalRoot,
3703
+ viewport
3704
+ };
3705
+ }
3706
+ function replaceTerminalInputHandler(term) {
3707
+ const previousInput = term.input;
3708
+ if (typeof previousInput?.destroy !== "function") return;
3709
+ previousInput.destroy();
3710
+ const textarea = term.element.ownerDocument.createElement("textarea");
3711
+ configureTerminalTextarea(textarea);
3712
+ term.element.appendChild(textarea);
3713
+ syncTerminalTextareaPosition(term, textarea);
3714
+ const syncInputPosition = () => {
3715
+ syncTerminalTextareaPosition(term, textarea);
3716
+ };
3717
+ const onFocus = () => {
3718
+ syncInputPosition();
3719
+ term.element.classList.add("focused");
3720
+ };
3721
+ const onBlur = () => {
3722
+ term.element.classList.remove("focused");
3723
+ };
3724
+ textarea.addEventListener("focus", onFocus);
3725
+ textarea.addEventListener("blur", onBlur);
3726
+ textarea.addEventListener("beforeinput", syncInputPosition, true);
3727
+ textarea.addEventListener("compositionstart", syncInputPosition, true);
3728
+ textarea.addEventListener("compositionupdate", syncInputPosition, true);
3729
+ textarea.addEventListener("compositionend", syncInputPosition, true);
3730
+ textarea.addEventListener("input", syncInputPosition, true);
3731
+ textarea.addEventListener("keydown", syncInputPosition, true);
3732
+ term.input = {
3733
+ textarea,
3734
+ focus() {
3735
+ syncInputPosition();
3736
+ textarea.focus({ preventScroll: true });
3737
+ },
3738
+ destroy() {
3739
+ textarea.removeEventListener("focus", onFocus);
3740
+ textarea.removeEventListener("blur", onBlur);
3741
+ textarea.removeEventListener("beforeinput", syncInputPosition, true);
3742
+ textarea.removeEventListener("compositionstart", syncInputPosition, true);
3743
+ textarea.removeEventListener("compositionupdate", syncInputPosition, true);
3744
+ textarea.removeEventListener("compositionend", syncInputPosition, true);
3745
+ textarea.removeEventListener("input", syncInputPosition, true);
3746
+ textarea.removeEventListener("keydown", syncInputPosition, true);
3747
+ term.element.classList.remove("focused");
3748
+ textarea.remove();
3749
+ }
3750
+ };
3751
+ }
3752
+ function configureTerminalTextarea(textarea) {
3753
+ textarea.setAttribute("autocapitalize", "off");
3754
+ textarea.setAttribute("autocomplete", "off");
3755
+ textarea.setAttribute("autocorrect", "off");
3756
+ textarea.setAttribute("spellcheck", "false");
3757
+ textarea.setAttribute("enterkeyhint", "send");
3758
+ textarea.setAttribute("tabindex", "0");
3759
+ textarea.setAttribute("aria-hidden", "true");
3760
+ const style = textarea.style;
3761
+ style.position = "fixed";
3762
+ style.left = "0";
3763
+ style.top = "0";
3764
+ style.width = "1px";
3765
+ style.height = "1px";
3766
+ style.opacity = "0";
3767
+ style.overflow = "hidden";
3768
+ style.border = "0";
3769
+ style.padding = "0";
3770
+ style.margin = "0";
3771
+ style.outline = "none";
3772
+ style.resize = "none";
3773
+ style.pointerEvents = "none";
3774
+ style.caretColor = "transparent";
3775
+ style.color = "transparent";
3776
+ style.background = "transparent";
3777
+ }
3778
+ function syncTerminalTextareaPosition(term, textarea) {
3779
+ const viewport = resolveTextareaViewport(textarea);
3780
+ const anchorRect = (resolveLiveInputSurfaceAnchor(term.element) ?? term.element).getBoundingClientRect?.();
3781
+ const fallbackRect = term.element.getBoundingClientRect?.();
3782
+ const rect = hasUsableClientRect(anchorRect) ? anchorRect : fallbackRect;
3783
+ if (!hasUsableClientRect(rect)) {
3784
+ textarea.style.left = "0";
3785
+ textarea.style.top = "0";
3786
+ return;
3787
+ }
3788
+ const left = clamp(rect.left, 0, Math.max(0, viewport.width - 1));
3789
+ const top = clamp(rect.top, 0, Math.max(0, viewport.height - 1));
3790
+ textarea.style.left = `${left}px`;
3791
+ textarea.style.top = `${top}px`;
3792
+ }
3793
+ function resolveTextareaViewport(textarea) {
3794
+ const view = textarea.ownerDocument.defaultView;
3795
+ const root = textarea.ownerDocument.documentElement;
3796
+ const body = textarea.ownerDocument.body;
3797
+ const width = firstFinitePositiveNumber(view?.innerWidth, root?.clientWidth, body?.clientWidth) ?? 1;
3798
+ return {
3799
+ height: firstFinitePositiveNumber(view?.innerHeight, root?.clientHeight, body?.clientHeight) ?? 1,
3800
+ width
3801
+ };
3802
+ }
3803
+ function installBrowserRenderer(term, styleTracker) {
3804
+ const container = term?._container;
3805
+ if (!(container instanceof HTMLElement)) return;
3806
+ const renderer = new BrowserTerminalRenderer(container, styleTracker);
3807
+ term.renderer = renderer;
3808
+ renderer.setup(term.cols, term.rows);
3809
+ if (term.bridge) renderer.render(term.bridge);
3810
+ }
3811
+ function renderTerminalNow(term, options = {}) {
3812
+ const bridge = term?.bridge;
3813
+ const renderer = term?.renderer;
3814
+ if (!bridge || !renderer || typeof renderer.render !== "function") return;
3815
+ renderer.render(bridge, options);
3816
+ }
3817
+ function installTerminalViewportSizer(term, terminalRoot, windowObject, onResize) {
3818
+ const target = resolveViewportSize(term, terminalRoot, windowObject);
3819
+ applyTerminalElementHeight(terminalRoot, target.rows);
3820
+ onResize(target.cols, target.rows);
3821
+ let frameHandle = null;
3822
+ const scheduleResize = () => {
3823
+ if (frameHandle !== null) return;
3824
+ frameHandle = windowObject.requestAnimationFrame(() => {
3825
+ frameHandle = null;
3826
+ const nextTarget = resolveViewportSize(term, terminalRoot, windowObject);
3827
+ applyTerminalElementHeight(terminalRoot, nextTarget.rows);
3828
+ onResize(nextTarget.cols, nextTarget.rows);
3829
+ });
3830
+ };
3831
+ windowObject.addEventListener("resize", scheduleResize);
3832
+ return () => {
3833
+ if (frameHandle !== null) {
3834
+ windowObject.cancelAnimationFrame(frameHandle);
3835
+ frameHandle = null;
3836
+ }
3837
+ windowObject.removeEventListener("resize", scheduleResize);
3838
+ };
3839
+ }
3840
+ function resolveViewportSize(term, terminalRoot, windowObject) {
3841
+ const metrics = measureTerminalCell(term, terminalRoot);
3842
+ const viewport = resolveAvailableTerminalViewport(terminalRoot, windowObject);
3843
+ if (!viewport) return {
3844
+ cols: normalizeResizeDimension(term?.cols, 80),
3845
+ rows: normalizeResizeDimension(term?.rows, 24)
3846
+ };
3847
+ return {
3848
+ cols: Math.max(1, Math.floor(viewport.width / metrics.charWidth)),
3849
+ rows: Math.max(1, Math.floor(viewport.height / metrics.rowHeight))
3850
+ };
3851
+ }
3852
+ function measureTerminalCell(term, terminalRoot) {
3853
+ const measured = typeof term?._measureCharSize === "function" ? term._measureCharSize() : null;
3854
+ if (measured && Number.isFinite(measured.charWidth) && measured.charWidth > 0 && Number.isFinite(measured.rowHeight) && measured.rowHeight > 0) {
3855
+ terminalRoot.style.setProperty("--term-row-height", `${measured.rowHeight}px`);
3856
+ return measured;
3857
+ }
3858
+ const computedStyle = getComputedStyle(terminalRoot);
3859
+ const rowHeight = parseCssPixelValue(computedStyle.getPropertyValue("--term-row-height")) || parseCssPixelValue(computedStyle.lineHeight) || 17;
3860
+ const fontSize = parseCssPixelValue(computedStyle.fontSize) || 15;
3861
+ return {
3862
+ charWidth: Math.max(1, fontSize * .6),
3863
+ rowHeight: Math.max(1, rowHeight)
3864
+ };
3865
+ }
3866
+ function resolveAvailableTerminalViewport(terminalRoot, windowObject) {
3867
+ const rect = terminalRoot.getBoundingClientRect?.();
3868
+ const width = Number.isFinite(rect?.width) && rect.width > 0 ? rect.width : 0;
3869
+ if (width <= 0 || !Number.isFinite(rect?.top)) return null;
3870
+ const viewportHeight = Math.max(1, windowObject.innerHeight || terminalRoot.ownerDocument?.documentElement?.clientHeight || 24);
3871
+ const top = Math.max(0, rect.top);
3872
+ const paddingBottom = parseCssPixelValue(getComputedStyle(terminalRoot).paddingBottom);
3873
+ const height = viewportHeight - top - paddingBottom;
3874
+ if (!Number.isFinite(height) || height <= 0) return null;
3875
+ return {
3876
+ height,
3877
+ width
3878
+ };
3879
+ }
3880
+ function applyTerminalElementHeight(terminalRoot, rows) {
3881
+ terminalRoot.style.height = `calc(var(--term-row-height, 17px) * ${Math.max(1, rows)})`;
3882
+ }
3883
+ function parseCssPixelValue(value) {
3884
+ const parsed = Number.parseFloat(value);
3885
+ return Number.isFinite(parsed) ? parsed : 0;
3886
+ }
3887
+ function normalizeResizeDimension(value, fallback) {
3888
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : Math.max(1, fallback);
3889
+ }
3890
+ function resolveTerminalBridgeDimensions(term, requestedCols, requestedRows) {
3891
+ const bridge = term?.bridge ?? null;
3892
+ if (!bridge) return {
3893
+ cols: normalizeResizeDimension(requestedCols, 80),
3894
+ rows: normalizeResizeDimension(requestedRows, 24)
3895
+ };
3896
+ const bridgeCols = typeof bridge.getCols === "function" ? bridge.getCols() : requestedCols;
3897
+ const bridgeRows = typeof bridge.getRows === "function" ? bridge.getRows() : requestedRows;
3898
+ return {
3899
+ cols: normalizeResizeDimension(bridgeCols, requestedCols),
3900
+ rows: normalizeResizeDimension(bridgeRows, requestedRows)
3901
+ };
3902
+ }
3903
+ function syncTerminalSurface(element, transcriptArchive, term, styleTracker, options = {}) {
3904
+ const interactive = options.interactive ?? true;
3905
+ syncTerminalInteractivity(element, term, interactive);
3906
+ const bridge = term?.bridge ?? null;
3907
+ const resolvedAltScreenState = (bridge ? bridge.usingAltScreen() : transcriptArchive.isAlternateScreenActive()) || styleTracker.isAltScreenActive();
3908
+ transcriptArchive.setAlternateScreenActive?.(resolvedAltScreenState);
3909
+ element.dataset.altScreen = String(resolvedAltScreenState);
3910
+ element.dataset.renderMode = resolvedAltScreenState ? "screen" : "transcript";
3911
+ transcriptArchive.setScreenModeActive?.(resolvedAltScreenState);
3912
+ syncScreenModeScrollbackRows(element, resolvedAltScreenState);
3913
+ if (!bridge) {
3914
+ delete element.dataset.cursorVisible;
3915
+ delete element.dataset.cursorRow;
3916
+ delete element.dataset.cursorCol;
3917
+ return;
3918
+ }
3919
+ const cursor = bridge.getCursor();
3920
+ if (!interactive) {
3921
+ element.dataset.cursorVisible = "false";
3922
+ element.dataset.cursorRow = String(cursor.row + 1);
3923
+ element.dataset.cursorCol = String(cursor.col + 1);
3924
+ return;
3925
+ }
3926
+ element.dataset.cursorVisible = String(cursor.visible);
3927
+ element.dataset.cursorRow = String(cursor.row + 1);
3928
+ element.dataset.cursorCol = String(cursor.col + 1);
3929
+ }
3930
+ function syncTerminalInteractivity(element, term, interactive) {
3931
+ element.dataset.sessionInteractive = String(interactive);
3932
+ element.setAttribute("aria-disabled", String(!interactive));
3933
+ if (interactive) element.removeAttribute("tabindex");
3934
+ else element.setAttribute("tabindex", "-1");
3935
+ const activeElement = element.ownerDocument?.activeElement;
3936
+ if (!interactive && activeElement instanceof HTMLElement && element.contains(activeElement)) activeElement.blur?.();
3937
+ const textarea = term?.input?.textarea;
3938
+ if (textarea instanceof HTMLTextAreaElement) {
3939
+ textarea.disabled = !interactive;
3940
+ textarea.readOnly = !interactive;
3941
+ textarea.tabIndex = interactive ? 0 : -1;
3942
+ textarea.setAttribute("aria-hidden", String(!interactive));
3943
+ if (!interactive) textarea.blur();
3944
+ }
3945
+ element.querySelectorAll(".term-cursor").forEach((cursor) => {
3946
+ cursor.toggleAttribute("hidden", !interactive);
3947
+ cursor.setAttribute("aria-hidden", String(!interactive));
3948
+ });
3949
+ }
3950
+ function syncScreenModeScrollbackRows(element, screenModeActive) {
3951
+ element.querySelectorAll(".term-scrollback-row").forEach((row) => {
3952
+ row.toggleAttribute("hidden", screenModeActive);
3953
+ row.setAttribute("aria-hidden", String(screenModeActive));
3954
+ });
3955
+ }
3956
+ function containsScreenRedrawControl(text) {
3957
+ const escape = String.fromCharCode(27);
3958
+ return new RegExp(`(?:${escape}\\[[?0-9;:]*[ABCDEFGHJKSTf]|${escape}[78c])`).test(text);
3959
+ }
3960
+ function getMonotonicTime() {
3961
+ return globalThis.performance?.now?.() ?? Date.now();
3962
+ }
3963
+ function requestBrowserFrame(callback, view) {
3964
+ const requestFrame = view?.requestAnimationFrame ?? globalThis.requestAnimationFrame;
3965
+ if (typeof requestFrame === "function") return requestFrame.call(view ?? globalThis, callback);
3966
+ return setTimeout(() => {
3967
+ callback(getMonotonicTime());
3968
+ }, 0);
3969
+ }
3970
+ function cancelBrowserFrame(handle, view) {
3971
+ const cancelFrame = view?.cancelAnimationFrame ?? globalThis.cancelAnimationFrame;
3972
+ if (typeof cancelFrame === "function") {
3973
+ cancelFrame.call(view ?? globalThis, handle);
3974
+ return;
3975
+ }
3976
+ clearTimeout(handle);
3977
+ }
3978
+ function createTranscriptArchive(element, scheduler = {}, options = {}) {
3979
+ const doc = element.ownerDocument ?? document;
3980
+ const view = doc.defaultView;
3981
+ const requestFrame = scheduler.requestFrame ?? ((callback) => requestBrowserFrame(callback, view));
3982
+ const cancelFrame = scheduler.cancelFrame ?? ((handle) => cancelBrowserFrame(handle, view));
3983
+ const getCols = options.getCols ?? (() => 80);
3984
+ const scrollbackLimit = Math.max(0, options.scrollbackLimit ?? DEFAULT_TRANSCRIPT_SCROLLBACK_LIMIT);
3985
+ const getVisibleRows = options.getVisibleRows ?? (() => 24);
3986
+ let decoder = new TextDecoder();
3987
+ const archive = doc.createElement("pre");
3988
+ const archiveText = doc.createTextNode("");
3989
+ archive.setAttribute("data-terminal-transcript-archive", "");
3990
+ archive.className = "term-transcript-archive";
3991
+ archive.append(archiveText);
3992
+ element.insertBefore(archive, element.firstChild);
3993
+ let preservedLines = [];
3994
+ const finalizedLines = [];
3995
+ let currentLine = "";
3996
+ let parserState = "text";
3997
+ let csiParams = "";
3998
+ let csiPrivate = "";
3999
+ let carriageReturnPending = false;
4000
+ let frameHandle = null;
4001
+ let archivedLineCount = 0;
4002
+ let alternateScreenActive = false;
4003
+ let screenModeActive = false;
4004
+ let concealedPreservedArchive = false;
4005
+ let screenRedrawArchiveSuppressedUntil = 0;
4006
+ const setPreservedLines = (lines) => {
4007
+ const normalizedLines = normalizePreservedTranscriptLines(lines);
4008
+ preservedLines = scrollbackLimit > 0 ? normalizedLines.slice(-scrollbackLimit) : [];
4009
+ };
4010
+ const syncArchiveVisibility = () => {
4011
+ const hasArchivedContent = preservedLines.length > 0 || archiveText.data.length > 0;
4012
+ const archiveHidden = alternateScreenActive || screenModeActive;
4013
+ const archiveConcealed = !archiveHidden && concealedPreservedArchive && hasArchivedContent;
4014
+ archive.hidden = archiveHidden;
4015
+ archive.style.visibility = archiveConcealed ? "hidden" : "";
4016
+ archive.setAttribute("aria-hidden", String(archiveHidden || archiveConcealed));
4017
+ element.dataset.archiveConcealed = String(archiveConcealed);
4018
+ };
4019
+ const scheduleSync = () => {
4020
+ if (frameHandle !== null) return;
4021
+ frameHandle = requestFrame(() => {
4022
+ frameHandle = null;
4023
+ syncArchive();
4024
+ });
4025
+ };
4026
+ const reconcilePreservedLines = () => {
4027
+ if (preservedLines.length === 0) return;
4028
+ const nextPreservedLines = trimReconciledPreservedTranscriptLines(preservedLines, [...finalizedLines, currentLine]);
4029
+ if (nextPreservedLines.length === preservedLines.length && nextPreservedLines.every((line, index) => line === preservedLines[index])) return;
4030
+ preservedLines = nextPreservedLines;
4031
+ if (preservedLines.length === 0) concealedPreservedArchive = false;
4032
+ };
4033
+ const syncArchive = () => {
4034
+ reconcilePreservedLines();
4035
+ const liveLineCount = finalizedLines.length + 1;
4036
+ const visibleCapacity = Math.max(1, scrollbackLimit + Math.max(1, getVisibleRows()));
4037
+ const hiddenLineCount = Math.max(0, liveLineCount - visibleCapacity);
4038
+ const archivedStart = Math.max(0, hiddenLineCount - Math.min(hiddenLineCount, scrollbackLimit));
4039
+ const liveArchiveWindow = finalizedLines.slice(archivedStart, hiddenLineCount);
4040
+ const archiveWindow = preservedLines.length > 0 ? [...preservedLines, ...liveArchiveWindow] : liveArchiveWindow;
4041
+ archiveText.data = archiveWindow.length > 0 ? `${archiveWindow.join("\n")}\n` : "";
4042
+ archivedLineCount = archiveWindow.length;
4043
+ syncTranscriptMetadata(element, preservedLines.length + liveLineCount, archivedLineCount);
4044
+ syncArchiveVisibility();
4045
+ };
4046
+ const resetLiveTranscript = () => {
4047
+ finalizedLines.length = 0;
4048
+ currentLine = "";
4049
+ parserState = "text";
4050
+ csiParams = "";
4051
+ csiPrivate = "";
4052
+ carriageReturnPending = false;
4053
+ };
4054
+ const resetParser = () => {
4055
+ resetLiveTranscript();
4056
+ decoder = new TextDecoder();
4057
+ };
4058
+ const setAlternateScreenActive = (nextState) => {
4059
+ if (alternateScreenActive === nextState) return;
4060
+ alternateScreenActive = nextState;
4061
+ syncArchiveVisibility();
4062
+ };
4063
+ const setScreenModeActive = (nextState) => {
4064
+ if (screenModeActive === nextState) return;
4065
+ screenModeActive = nextState;
4066
+ syncArchiveVisibility();
4067
+ };
4068
+ const appendPrintableCharacter = (character) => {
4069
+ const cols = Math.max(1, getCols());
4070
+ if (currentLine.length >= cols) {
4071
+ finalizedLines.push(currentLine);
4072
+ currentLine = "";
4073
+ }
4074
+ currentLine += character;
4075
+ };
4076
+ const handleEraseDisplay = (params) => {
4077
+ if (params.includes(3)) {
4078
+ setPreservedLines([]);
4079
+ concealedPreservedArchive = false;
4080
+ resetParser();
4081
+ return;
4082
+ }
4083
+ if (params.includes(2)) {
4084
+ setPreservedLines([
4085
+ ...preservedLines,
4086
+ ...finalizedLines,
4087
+ currentLine
4088
+ ]);
4089
+ concealedPreservedArchive = preservedLines.length > 0;
4090
+ resetLiveTranscript();
4091
+ }
4092
+ };
4093
+ const processDecodedText = (text, { recordPrintable = true } = {}) => {
4094
+ for (const character of text) {
4095
+ if (parserState === "escape") {
4096
+ if (character === "[") {
4097
+ parserState = "csi";
4098
+ csiParams = "";
4099
+ csiPrivate = "";
4100
+ continue;
4101
+ }
4102
+ if (character === "]") {
4103
+ parserState = "osc";
4104
+ continue;
4105
+ }
4106
+ if (character === "c") resetParser();
4107
+ parserState = "text";
4108
+ continue;
4109
+ }
4110
+ if (parserState === "csi") {
4111
+ if ((character === "?" || character === ">" || character === "!") && csiParams.length === 0) {
4112
+ csiPrivate = character;
4113
+ continue;
4114
+ }
4115
+ if (character >= "0" && character <= "9" || character === ";" || character === ":") {
4116
+ csiParams += character;
4117
+ continue;
4118
+ }
4119
+ if (character >= "@" && character <= "~") {
4120
+ const params = parseCsiParams(csiParams);
4121
+ setAlternateScreenActive(nextAltScreenState(alternateScreenActive, csiPrivate, csiParams, character));
4122
+ if (character === "J") handleEraseDisplay(params);
4123
+ parserState = "text";
4124
+ }
4125
+ continue;
4126
+ }
4127
+ if (parserState === "osc") {
4128
+ if (character === "\x07") {
4129
+ parserState = "text";
4130
+ continue;
4131
+ }
4132
+ if (character === "\x1B") parserState = "osc_escape";
4133
+ continue;
4134
+ }
4135
+ if (parserState === "osc_escape") {
4136
+ parserState = character === "\\" ? "text" : "osc";
4137
+ continue;
4138
+ }
4139
+ if (character === "\x1B") {
4140
+ parserState = "escape";
4141
+ continue;
4142
+ }
4143
+ if (alternateScreenActive) continue;
4144
+ if (!recordPrintable) continue;
4145
+ if (carriageReturnPending) {
4146
+ if (character === "\n") {
4147
+ finalizedLines.push(currentLine);
4148
+ currentLine = "";
4149
+ carriageReturnPending = false;
4150
+ continue;
4151
+ }
4152
+ currentLine = "";
4153
+ carriageReturnPending = false;
4154
+ }
4155
+ if (character === "\r") {
4156
+ carriageReturnPending = true;
4157
+ continue;
4158
+ }
4159
+ if (character === "\n") {
4160
+ finalizedLines.push(currentLine);
4161
+ currentLine = "";
4162
+ continue;
4163
+ }
4164
+ if (character === "\b") {
4165
+ currentLine = currentLine.slice(0, -1);
4166
+ continue;
4167
+ }
4168
+ if (character === " ") {
4169
+ currentLine += character;
4170
+ continue;
4171
+ }
4172
+ if (character >= "\0" && character < " " || character === "") continue;
4173
+ appendPrintableCharacter(character);
4174
+ }
4175
+ };
4176
+ syncArchive();
4177
+ return {
4178
+ append(chunk) {
4179
+ if (screenModeActive) return;
4180
+ const text = decoder.decode(chunk, { stream: true });
4181
+ const now = getMonotonicTime();
4182
+ const hasScreenRedrawControl = containsScreenRedrawControl(text);
4183
+ if (hasScreenRedrawControl) screenRedrawArchiveSuppressedUntil = now + SCREEN_REDRAW_ARCHIVE_SUPPRESS_MS;
4184
+ processDecodedText(text, { recordPrintable: !hasScreenRedrawControl && now >= screenRedrawArchiveSuppressedUntil });
4185
+ scheduleSync();
4186
+ },
4187
+ concealPreservedArchive() {
4188
+ const nextState = preservedLines.length > 0;
4189
+ if (concealedPreservedArchive === nextState) return;
4190
+ concealedPreservedArchive = nextState;
4191
+ syncArchiveVisibility();
4192
+ },
4193
+ destroy() {
4194
+ if (frameHandle !== null) {
4195
+ cancelFrame(frameHandle);
4196
+ frameHandle = null;
4197
+ }
4198
+ archive.remove();
4199
+ },
4200
+ getAllLines() {
4201
+ return normalizePreservedTranscriptLines([
4202
+ ...preservedLines,
4203
+ ...finalizedLines,
4204
+ currentLine
4205
+ ]);
4206
+ },
4207
+ isAlternateScreenActive() {
4208
+ return alternateScreenActive;
4209
+ },
4210
+ preserveSnapshot(lines = []) {
4211
+ setPreservedLines(lines);
4212
+ concealedPreservedArchive = preservedLines.length > 0;
4213
+ resetParser();
4214
+ scheduleSync();
4215
+ },
4216
+ refresh() {
4217
+ scheduleSync();
4218
+ },
4219
+ revealPreservedArchive() {
4220
+ if (!concealedPreservedArchive) return;
4221
+ concealedPreservedArchive = false;
4222
+ syncArchiveVisibility();
4223
+ },
4224
+ setAlternateScreenActive,
4225
+ setScreenModeActive
4226
+ };
4227
+ }
4228
+ function createBrowserTransport(handlers) {
4229
+ const pendingMessages = [];
4230
+ const encoder = new TextEncoder();
4231
+ let socketUrl;
4232
+ let socket = null;
4233
+ let closed = false;
4234
+ const flushPendingMessages = () => {
4235
+ if (!socket || socket.readyState !== WebSocket.OPEN) return;
4236
+ for (const message of pendingMessages.splice(0)) sendMessage(message);
4237
+ };
4238
+ const sendMessage = (message) => {
4239
+ if (closed) return;
4240
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
4241
+ pendingMessages.push(message);
4242
+ return;
4243
+ }
4244
+ if (message.kind === "control") {
4245
+ socket.send(String(message.data));
4246
+ return;
4247
+ }
4248
+ const payload = typeof message.data === "string" ? encoder.encode(message.data) : message.data;
4249
+ socket.send(copyToArrayBuffer(payload));
4250
+ };
4251
+ return {
4252
+ close() {
4253
+ closed = true;
4254
+ pendingMessages.length = 0;
4255
+ socket?.close();
4256
+ },
4257
+ connect(url) {
4258
+ if (closed) return;
4259
+ if (url) socketUrl = url;
4260
+ if (!socketUrl) throw new Error("No WebSocket URL provided");
4261
+ if (socket && socket.readyState !== WebSocket.CLOSED) return;
4262
+ const currentSocket = new WebSocket(socketUrl);
4263
+ socket = currentSocket;
4264
+ currentSocket.binaryType = "arraybuffer";
4265
+ currentSocket.onopen = () => {
4266
+ flushPendingMessages();
4267
+ handlers.onOpen();
4268
+ };
4269
+ currentSocket.onmessage = (event) => {
4270
+ if (event.data instanceof ArrayBuffer) {
4271
+ handlers.onBinary(new Uint8Array(event.data));
4272
+ return;
4273
+ }
4274
+ if (typeof event.data === "string") {
4275
+ handlers.onControlMessage(event.data);
4276
+ return;
4277
+ }
4278
+ if (event.data instanceof Blob) {
4279
+ event.data.arrayBuffer().then((buffer) => {
4280
+ handlers.onBinary(new Uint8Array(buffer));
4281
+ }).catch(() => {
4282
+ handlers.onError(new Event("error"));
4283
+ });
4284
+ return;
4285
+ }
4286
+ handlers.onControlMessage(String(event.data));
4287
+ };
4288
+ currentSocket.onclose = (event) => {
4289
+ if (socket === currentSocket) socket = null;
4290
+ handlers.onClose({
4291
+ code: event.code,
4292
+ reason: event.reason,
4293
+ wasClean: event.wasClean
4294
+ });
4295
+ };
4296
+ currentSocket.onerror = (event) => {
4297
+ handlers.onError(event);
4298
+ if (!closed && currentSocket.readyState < WebSocket.CLOSING) currentSocket.close();
4299
+ };
4300
+ },
4301
+ disconnect(reason = "offline") {
4302
+ if (!socket || socket.readyState >= WebSocket.CLOSING) return;
4303
+ socket.close(1e3, reason);
4304
+ },
4305
+ send(data) {
4306
+ sendMessage({
4307
+ kind: "binary",
4308
+ data
4309
+ });
4310
+ },
4311
+ sendControl(data) {
4312
+ sendMessage({
4313
+ kind: "control",
4314
+ data
4315
+ });
4316
+ }
4317
+ };
4318
+ }
4319
+ function installScrollbackInteractions(element, callbacks = {}) {
4320
+ const getScrollSurface = callbacks.getScrollSurface ?? (() => element);
4321
+ const onInput = callbacks.onInput ?? (() => {});
4322
+ const onManualScroll = callbacks.onManualScroll ?? (() => {});
4323
+ const setScrollTop = callbacks.setScrollTop ?? ((scrollSurface, scrollTop) => {
4324
+ scrollSurface.scrollTop = scrollTop;
4325
+ });
4326
+ const onWheel = (event) => {
4327
+ const scrollSurface = getScrollSurface();
4328
+ const maxScrollTop = getScrollbackMax(scrollSurface);
4329
+ if (maxScrollTop <= 0 || event.deltaY === 0) return;
4330
+ const nextScrollTop = clamp(scrollSurface.scrollTop + event.deltaY, 0, maxScrollTop);
4331
+ if (nextScrollTop === scrollSurface.scrollTop) return;
4332
+ onManualScroll({
4333
+ scrollTop: nextScrollTop,
4334
+ maxScrollTop
4335
+ });
4336
+ event.preventDefault();
4337
+ event.stopPropagation();
4338
+ setScrollTop(scrollSurface, nextScrollTop);
4339
+ };
4340
+ const onKeyDown = (event) => {
4341
+ if (isScrollbackShortcut(event)) {
4342
+ event.preventDefault();
4343
+ event.stopPropagation();
4344
+ const scrollSurface = getScrollSurface();
4345
+ const maxScrollTop = getScrollbackMax(scrollSurface);
4346
+ const nextScrollTop = event.key === "PageUp" ? scrollSurface.scrollTop - Math.max(scrollSurface.clientHeight, 1) : maxScrollTop;
4347
+ onManualScroll({
4348
+ scrollTop: clamp(nextScrollTop, 0, maxScrollTop),
4349
+ maxScrollTop
4350
+ });
4351
+ setScrollTop(scrollSurface, clamp(nextScrollTop, 0, getScrollbackMax(scrollSurface)));
4352
+ return;
4353
+ }
4354
+ if (shouldSnapScrollbackOnKeyDown(event)) onInput({ event });
4355
+ };
4356
+ element.addEventListener("wheel", onWheel, {
4357
+ capture: true,
4358
+ passive: false
4359
+ });
4360
+ element.addEventListener("keydown", onKeyDown, true);
4361
+ return () => {
4362
+ element.removeEventListener("wheel", onWheel, true);
4363
+ element.removeEventListener("keydown", onKeyDown, true);
4364
+ };
4365
+ }
4366
+ function hasVisibleTerminalPaint(element) {
4367
+ const style = getComputedStyle(element);
4368
+ return hasVisibleCssPaint(style.backgroundColor) || hasVisibleCssBoxShadow(style.boxShadow);
4369
+ }
4370
+ function hasVisibleCssBoxShadow(value) {
4371
+ return typeof value === "string" && value.trim().length > 0 && value !== "none";
4372
+ }
4373
+ function hasVisibleCssPaint(value) {
4374
+ if (typeof value !== "string") return false;
4375
+ const normalizedValue = value.trim().replace(/\s+/g, "").toLowerCase();
4376
+ return normalizedValue.length > 0 && normalizedValue !== "transparent" && !/rgba\((?:[^,]+,){3}0(?:\.0+)?\)/.test(normalizedValue);
4377
+ }
4378
+ function getScrollbackMax(element) {
4379
+ return Math.max(0, element.scrollHeight - element.clientHeight);
4380
+ }
4381
+ function resolveScrollSurface(doc, fallbackElement, scrollOptions) {
4382
+ const configuredViewport = scrollOptions?.getViewport?.() ?? scrollOptions?.viewport;
4383
+ if (configuredViewport instanceof HTMLElement) return configuredViewport;
4384
+ const scrollingElement = doc.scrollingElement;
4385
+ if (scrollingElement instanceof HTMLElement) return scrollingElement;
4386
+ if (doc.documentElement instanceof HTMLElement) return doc.documentElement;
4387
+ if (doc.body instanceof HTMLElement) return doc.body;
4388
+ return fallbackElement;
4389
+ }
4390
+ function requestScrollUiUpdate(scrollOptions) {
4391
+ scrollOptions?.requestUiUpdate?.();
4392
+ }
4393
+ function getScrollMetrics(element) {
4394
+ const scrollTop = normalizeScrollMetric(element.scrollTop);
4395
+ const scrollHeight = normalizeScrollMetric(element.scrollHeight);
4396
+ const clientHeight = normalizeScrollMetric(element.clientHeight);
4397
+ const maxScrollTop = getScrollbackMax(element);
4398
+ const atTop = scrollTop <= 1;
4399
+ const atBottom = isAtScrollbackBottom(scrollTop, maxScrollTop);
4400
+ const thumbSizeRatio = scrollHeight <= 0 ? 1 : clamp(clientHeight / scrollHeight, 0, 1);
4401
+ return {
4402
+ atBottom,
4403
+ atTop,
4404
+ clientHeight,
4405
+ maxScrollTop,
4406
+ scrollHeight,
4407
+ scrollTop,
4408
+ thumbOffsetRatio: maxScrollTop <= 0 ? 0 : clamp(scrollTop / maxScrollTop, 0, 1),
4409
+ thumbSizeRatio
4410
+ };
4411
+ }
4412
+ function normalizeScrollMetric(value) {
4413
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
4414
+ }
4415
+ function areScrollMetricsEqual(left, right) {
4416
+ return left.atBottom === right.atBottom && left.atTop === right.atTop && left.clientHeight === right.clientHeight && left.maxScrollTop === right.maxScrollTop && left.scrollHeight === right.scrollHeight && left.scrollTop === right.scrollTop && left.thumbOffsetRatio === right.thumbOffsetRatio && left.thumbSizeRatio === right.thumbSizeRatio;
4417
+ }
4418
+ function installScrollMetricsObserver(element, onScroll) {
4419
+ element.addEventListener("scroll", onScroll, { passive: true });
4420
+ return () => {
4421
+ element.removeEventListener("scroll", onScroll);
4422
+ };
4423
+ }
4424
+ function isAtScrollbackBottom(scrollTop, maxScrollTop) {
4425
+ return maxScrollTop <= 0 || scrollTop >= maxScrollTop - 1;
4426
+ }
4427
+ function clamp(value, min, max) {
4428
+ return Math.min(max, Math.max(min, value));
4429
+ }
4430
+ function isScrollbackShortcut(event) {
4431
+ return event.shiftKey && (event.key === "PageUp" || event.key === "PageDown");
4432
+ }
4433
+ function shouldPreserveVisiblePromptOnInput(event) {
4434
+ if (!(event instanceof KeyboardEvent)) return false;
4435
+ if (event.altKey || event.ctrlKey || event.metaKey) return false;
4436
+ return event.key.length === 1 || event.key === "Backspace" || event.key === "Delete" || isCompositionKeyDown(event);
4437
+ }
4438
+ function shouldFollowLiveOutputOnInput(event) {
4439
+ if (!(event instanceof KeyboardEvent)) return false;
4440
+ return !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && event.key === "Enter";
4441
+ }
4442
+ function isLiveInputSurfaceVisible(shell, terminalRoot, windowObject) {
4443
+ const anchor = resolveLiveInputSurfaceAnchor(terminalRoot);
4444
+ if (!(anchor instanceof HTMLElement)) return false;
4445
+ const rect = anchor.getBoundingClientRect();
4446
+ if (!hasUsableClientRect(rect)) return false;
4447
+ const topBoundary = getViewportTopBoundary(shell);
4448
+ const bottomBoundary = getViewportBottomBoundary(windowObject);
4449
+ return rect.bottom > topBoundary + 1 && rect.top < bottomBoundary - 1;
4450
+ }
4451
+ function resolveLiveInputSurfaceAnchor(terminalRoot) {
4452
+ const visibleCursors = Array.from(terminalRoot.querySelectorAll(".term-grid .term-cursor")).filter((cursor) => cursor instanceof HTMLElement && !cursor.hidden && cursor.getAttribute("aria-hidden") !== "true");
4453
+ if (visibleCursors.length > 0) return visibleCursors[visibleCursors.length - 1];
4454
+ const rows = Array.from(terminalRoot.querySelectorAll(".term-grid .term-row"));
4455
+ let lastNonEmptyRow = null;
4456
+ for (let index = rows.length - 1; index >= 0; index -= 1) {
4457
+ const row = rows[index];
4458
+ if (!(row instanceof HTMLElement)) continue;
4459
+ const text = row.textContent?.trimEnd() ?? "";
4460
+ if (text.length === 0) continue;
4461
+ if (looksLikePromptLine(text)) return row;
4462
+ lastNonEmptyRow = lastNonEmptyRow ?? row;
4463
+ }
4464
+ return lastNonEmptyRow;
4465
+ }
4466
+ function getViewportTopBoundary(shell) {
4467
+ const topBar = shell.querySelector("[data-terminal-viewport-offset]");
4468
+ if (topBar instanceof HTMLElement) {
4469
+ const rect = topBar.getBoundingClientRect();
4470
+ if (hasUsableClientRect(rect)) return rect.bottom;
4471
+ }
4472
+ return 0;
4473
+ }
4474
+ function getViewportBottomBoundary(windowObject) {
4475
+ const candidates = [
4476
+ windowObject?.innerHeight,
4477
+ windowObject?.document?.documentElement?.clientHeight,
4478
+ windowObject?.document?.body?.clientHeight
4479
+ ];
4480
+ for (const candidate of candidates) if (typeof candidate === "number" && Number.isFinite(candidate) && candidate > 0) return candidate;
4481
+ return Number.POSITIVE_INFINITY;
4482
+ }
4483
+ function firstFinitePositiveNumber(...candidates) {
4484
+ for (const candidate of candidates) if (typeof candidate === "number" && Number.isFinite(candidate) && candidate > 0) return candidate;
4485
+ return null;
4486
+ }
4487
+ function hasUsableClientRect(rect) {
4488
+ if (!rect) return false;
4489
+ return Number.isFinite(rect.top) && Number.isFinite(rect.bottom) && Number.isFinite(rect.left) && Number.isFinite(rect.right) && !(rect.top === 0 && rect.bottom === 0 && rect.left === 0 && rect.right === 0);
4490
+ }
4491
+ function shouldSnapScrollbackOnKeyDown(event) {
4492
+ if (event.defaultPrevented || isScrollbackShortcut(event) || isBrowserSafeShortcut(event) || isContainedTerminalNavigationKey(event)) return false;
4493
+ return ![
4494
+ "Alt",
4495
+ "CapsLock",
4496
+ "Control",
4497
+ "Fn",
4498
+ "Meta",
4499
+ "NumLock",
4500
+ "ScrollLock",
4501
+ "Shift"
4502
+ ].includes(event.key);
4503
+ }
4504
+ function decodeHelloReplay(value) {
4505
+ if (typeof value !== "string" || value.length === 0) return new Uint8Array(0);
4506
+ try {
4507
+ const normalizedValue = value.replace(/-/g, "+").replace(/_/g, "/");
4508
+ const missingPadding = normalizedValue.length % 4;
4509
+ const decoded = atob(missingPadding === 0 ? normalizedValue : `${normalizedValue}${"=".repeat(4 - missingPadding)}`);
4510
+ const bytes = new Uint8Array(decoded.length);
4511
+ for (let index = 0; index < decoded.length; index += 1) bytes[index] = decoded.charCodeAt(index);
4512
+ return bytes;
4513
+ } catch {
4514
+ return new Uint8Array(0);
4515
+ }
4516
+ }
4517
+ function formatExitStatus(message) {
4518
+ if (typeof message.signal === "string" && message.signal) return `Session ended (${message.signal})`;
4519
+ if (typeof message.code === "number") return `Session ended (code ${message.code})`;
4520
+ return "Session ended";
4521
+ }
4522
+ function resolveExitPresentation(message) {
4523
+ if (isShutdownSignal(message.signal)) return {
4524
+ sessionState: "shutdown",
4525
+ statusText: `Session shut down (${message.signal})`
4526
+ };
4527
+ return {
4528
+ sessionState: "ended",
4529
+ statusText: formatExitStatus(message)
4530
+ };
4531
+ }
4532
+ function isShutdownSignal(signal) {
4533
+ return signal === "SIGINT" || signal === "SIGTERM";
4534
+ }
4535
+ function getRequiredElement(doc, selector) {
4536
+ const element = doc.querySelector(selector);
4537
+ if (!(element instanceof HTMLElement)) throw new Error(`Missing required element: ${selector}`);
4538
+ return element;
4539
+ }
4540
+ function getOptionalElement(doc, selector) {
4541
+ const element = doc.querySelector(selector);
4542
+ return element instanceof HTMLElement ? element : null;
4543
+ }
4544
+ function hasElementOverride(elements, key) {
4545
+ return Object.prototype.hasOwnProperty.call(elements, key);
4546
+ }
4547
+ function createTerminalThemeController(doc, shell, terminalRoot, theme) {
4548
+ const explicitTheme = normalizeThemeName(theme);
4549
+ let observingTheme = false;
4550
+ const clearProtocolOverrides = () => {
4551
+ clearTerminalThemeProtocolOverrides(doc.documentElement);
4552
+ clearTerminalThemeProtocolOverrides(shell);
4553
+ clearTerminalThemeProtocolOverrides(terminalRoot);
4554
+ };
4555
+ const MutationObserverCtor = doc.defaultView?.MutationObserver ?? globalThis.MutationObserver;
4556
+ const mutationObserver = typeof MutationObserverCtor === "function" ? new MutationObserverCtor(() => {
4557
+ const externalTheme = normalizeThemeName(doc.documentElement.dataset.theme);
4558
+ if (shell.dataset.theme === externalTheme && terminalRoot.dataset.theme === externalTheme) return;
4559
+ clearProtocolOverrides();
4560
+ syncInternalTheme(externalTheme);
4561
+ }) : null;
4562
+ const observeTheme = () => {
4563
+ if (observingTheme) return;
4564
+ mutationObserver?.observe(doc.documentElement, {
4565
+ attributeFilter: ["data-theme"],
4566
+ attributes: true
4567
+ });
4568
+ observingTheme = true;
4569
+ };
4570
+ const pauseThemeObservation = () => {
4571
+ if (!observingTheme) return;
4572
+ mutationObserver?.disconnect();
4573
+ observingTheme = false;
4574
+ };
4575
+ const syncTheme = (nextTheme) => {
4576
+ const configuredTheme = normalizeThemeName(nextTheme);
4577
+ if (!configuredTheme) {
4578
+ if (doc.documentElement.dataset.theme !== void 0) delete doc.documentElement.dataset.theme;
4579
+ doc.documentElement.style.removeProperty("color-scheme");
4580
+ delete shell.dataset.theme;
4581
+ delete terminalRoot.dataset.theme;
4582
+ return;
4583
+ }
4584
+ if (configuredTheme === "light" || configuredTheme === "dark") doc.documentElement.style.setProperty("color-scheme", configuredTheme);
4585
+ else doc.documentElement.style.removeProperty("color-scheme");
4586
+ if (doc.documentElement.dataset.theme !== configuredTheme) doc.documentElement.dataset.theme = configuredTheme;
4587
+ if (shell.dataset.theme !== configuredTheme) shell.dataset.theme = configuredTheme;
4588
+ if (terminalRoot.dataset.theme !== configuredTheme) terminalRoot.dataset.theme = configuredTheme;
4589
+ };
4590
+ const syncInternalTheme = (nextTheme) => {
4591
+ pauseThemeObservation();
4592
+ try {
4593
+ syncTheme(nextTheme);
4594
+ mutationObserver?.takeRecords();
4595
+ } finally {
4596
+ observeTheme();
4597
+ }
4598
+ };
4599
+ syncTheme(explicitTheme ?? doc.documentElement.dataset.theme);
4600
+ observeTheme();
4601
+ return {
4602
+ destroy() {
4603
+ mutationObserver?.disconnect();
4604
+ },
4605
+ getTheme() {
4606
+ return doc.documentElement.dataset.theme;
4607
+ },
4608
+ syncProtocolUpdate(update) {
4609
+ let themeChanged = false;
4610
+ if (update.theme && normalizeThemeName(update.theme) !== this.getTheme()) {
4611
+ clearProtocolOverrides();
4612
+ syncInternalTheme(update.theme);
4613
+ themeChanged = true;
4614
+ }
4615
+ applyTerminalThemeProtocolUpdate(doc.documentElement, update);
4616
+ applyTerminalThemeProtocolUpdate(shell, update);
4617
+ applyTerminalThemeProtocolUpdate(terminalRoot, update);
4618
+ return themeChanged || hasTerminalThemeProtocolUpdate(update);
4619
+ },
4620
+ setTheme(nextTheme) {
4621
+ const previousTheme = this.getTheme();
4622
+ const normalizedTheme = normalizeThemeName(nextTheme);
4623
+ clearProtocolOverrides();
4624
+ syncInternalTheme(nextTheme);
4625
+ return normalizedTheme !== previousTheme;
4626
+ }
4627
+ };
4628
+ }
4629
+ function clearTerminalThemeProtocolOverrides(element) {
4630
+ for (const variableName of TERMINAL_THEME_PROTOCOL_VARIABLES) element.style.removeProperty(variableName);
4631
+ }
4632
+ function applyTerminalThemeProtocolUpdate(element, update) {
4633
+ const { background, cursor, foreground } = update.colors;
4634
+ if (background) element.style.setProperty("--theme-term-bg", background);
4635
+ if (cursor) element.style.setProperty("--theme-term-cursor", cursor);
4636
+ if (foreground) element.style.setProperty("--theme-term-fg", foreground);
4637
+ for (const { color, index } of update.palette) element.style.setProperty(`--theme-term-color-${index}`, color);
4638
+ }
4639
+ function hasTerminalThemeProtocolUpdate(update) {
4640
+ return Object.keys(update.colors).length > 0 || update.palette.length > 0 || Boolean(update.theme);
4641
+ }
4642
+ function normalizeThemeName(theme) {
4643
+ return normalizeTheme(theme);
4644
+ }
4645
+ function normalizeConnectionState(value) {
4646
+ switch (value) {
4647
+ case "open":
4648
+ case "reconnecting":
4649
+ case "superseded":
4650
+ case "closed":
4651
+ case "error": return value;
4652
+ default: return "connecting";
4653
+ }
4654
+ }
4655
+ function normalizeOutputState(value) {
4656
+ return value === "ready" ? "ready" : "pending";
4657
+ }
4658
+ function normalizeSessionPresentationState(value) {
4659
+ switch (value) {
4660
+ case "live":
4661
+ case "reconnecting":
4662
+ case "superseded":
4663
+ case "shutdown":
4664
+ case "ended":
4665
+ case "error": return value;
4666
+ default: return "starting";
4667
+ }
4668
+ }
4669
+ function cloneTerminalStatusSnapshot(status) {
4670
+ return {
4671
+ ...status,
4672
+ loading: { ...status.loading }
4673
+ };
4674
+ }
4675
+ function areTerminalStatusSnapshotsEqual(left, right) {
4676
+ return left.connection === right.connection && left.message === right.message && left.output === right.output && left.sessionState === right.sessionState && left.loading.message === right.loading.message && left.loading.visible === right.loading.visible;
4677
+ }
4678
+ function toWebSocketUrl(sessionUrl) {
4679
+ const url = new URL(sessionUrl.href);
4680
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
4681
+ url.pathname = "/ws";
4682
+ return url.toString();
4683
+ }
4684
+ function resolveAittySessionUrl(windowObject, src) {
4685
+ if (src instanceof URL) return new URL(src.href);
4686
+ if (typeof src === "string" && src.trim()) return new URL(src, windowObject.location.href);
4687
+ return new URL(windowObject.location.href);
4688
+ }
4689
+ function resolveShellRuntimeKind(doc, shell, sessionUrl) {
4690
+ const configuredRuntime = shell.dataset.runtime;
4691
+ if (configuredRuntime === "droid" || configuredRuntime === "pty") return configuredRuntime;
4692
+ if (configuredRuntime !== "session") return "pty";
4693
+ const windowObject = doc.defaultView ?? window;
4694
+ const fetchRuntimeKind = typeof windowObject.fetch === "function" ? windowObject.fetch.bind(windowObject) : null;
4695
+ if (!fetchRuntimeKind) return "pty";
4696
+ return fetchRuntimeKindFromSession(sessionUrl ?? resolveAittySessionUrl(windowObject), fetchRuntimeKind);
4697
+ }
4698
+ async function fetchRuntimeKindFromSession(sessionUrl, fetchRuntimeKind) {
4699
+ try {
4700
+ const url = new URL(sessionUrl.href);
4701
+ url.pathname = "/session-info";
4702
+ url.hash = "";
4703
+ const response = await fetchRuntimeKind(url.toString());
4704
+ if (!response.ok) return "pty";
4705
+ return (await response.json()).runtimeKind === "droid" ? "droid" : "pty";
4706
+ } catch {
4707
+ return "pty";
4708
+ }
4709
+ }
4710
+ function syncDimensions(element, cols, rows) {
4711
+ element.dataset.cols = String(cols);
4712
+ element.dataset.rows = String(rows);
4713
+ }
4714
+ function syncTranscriptMetadata(element, transcriptLineCount, archivedLineCount) {
4715
+ element.dataset.transcriptLines = String(transcriptLineCount);
4716
+ element.dataset.archivedLines = String(archivedLineCount);
4717
+ element.classList.toggle("has-scrollback", archivedLineCount > 0 || element.querySelector(".term-scrollback-row") !== null);
4718
+ }
4719
+ function syncTrailingTerminalBlankRows(element) {
4720
+ const rows = Array.from(element.querySelectorAll(".term-grid .term-row"));
4721
+ let trailingBlank = true;
4722
+ for (let index = rows.length - 1; index >= 0; index -= 1) {
4723
+ const row = rows[index];
4724
+ if (!(row instanceof HTMLElement)) continue;
4725
+ const isBlank = (row.textContent ?? "").trim().length === 0 && !hasVisibleTerminalPaint(row);
4726
+ row.classList.toggle("term-row--trailing-blank", trailingBlank && isBlank);
4727
+ if (!isBlank) trailingBlank = false;
4728
+ }
4729
+ }
4730
+ function trimReconciledPreservedTranscriptLines(preservedLines, liveLines) {
4731
+ if (preservedLines.length === 0 || liveLines.length === 0) return preservedLines;
4732
+ const normalizedLiveLines = normalizePreservedTranscriptLines(liveLines);
4733
+ for (let start = 0; start < preservedLines.length; start += 1) {
4734
+ const candidate = preservedLines.slice(start);
4735
+ if (candidate.length <= normalizedLiveLines.length && candidate.every((line, index) => line === normalizedLiveLines[index])) return preservedLines.slice(0, start);
4736
+ }
4737
+ return preservedLines;
4738
+ }
4739
+ function normalizePreservedTranscriptLines(lines) {
4740
+ return lines.map((line) => line.trimEnd()).filter((line, index, array) => line.length > 0 || index > 0 && index < array.length - 1);
4741
+ }
4742
+ function looksLikePromptLine(text) {
4743
+ return /^\s*(?:[$>#]|[^\s]+[@:][^\s]+[$#])\s?/.test(text);
4744
+ }
4745
+ function copyToArrayBuffer(bytes) {
4746
+ const copy = new Uint8Array(bytes.byteLength);
4747
+ copy.set(bytes);
4748
+ return copy.buffer;
4749
+ }
4750
+ function concatChunks(chunks) {
4751
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
4752
+ const payload = new Uint8Array(totalLength);
4753
+ let offset = 0;
4754
+ for (const chunk of chunks) {
4755
+ payload.set(chunk, offset);
4756
+ offset += chunk.length;
4757
+ }
4758
+ return payload;
4759
+ }
4760
+ if (typeof document !== "undefined") {
4761
+ defineAittyTerminalElement();
4762
+ if (shouldAutoMount(document)) mountTerminalApp().catch((error) => {
4763
+ const shell = document.querySelector("[data-shell]");
4764
+ const status = document.querySelector("[data-terminal-status]");
4765
+ const loading = document.querySelector("[data-terminal-loading]");
4766
+ if (shell instanceof HTMLElement) {
4767
+ shell.dataset.connection = "error";
4768
+ shell.dataset.sessionState = "error";
4769
+ }
4770
+ if (status instanceof HTMLElement) status.textContent = "Failed to start terminal";
4771
+ if (loading instanceof HTMLElement) loading.hidden = true;
4772
+ console.error(error);
4773
+ });
4774
+ }
4775
+ function shouldAutoMount(doc) {
4776
+ const shell = doc.querySelector("[data-shell]");
4777
+ return shell instanceof HTMLElement && !shell.hasAttribute("data-aitty-manual");
4778
+ }
4779
+ //#endregion
4780
+ export { createBufferedTerminalWriter, defineAittyTerminalElement, mountAitty, mountTerminalApp };