UNPKG

morphbox

Version:

Docker-based AI sandbox for development with Claude integration

487 lines (432 loc) 680 kB
import { c as create_ssr_component, b as subscribe, v as validate_component, d as add_attribute, f as each, e as escape, l as createEventDispatcher, m as missing_component, o as onDestroy, g as get_store_value } from './ssr-Bi8A3Ffq.js'; import { p as page } from './stores-eQz-6iWd.js'; import { s as settings, a as panels, b as activePanel, c as customPanels, d as builtinPanels, e as panelRegistry, t as tick, p as panelStore } from './registry-kTtxA5oL.js'; import { w as writable, d as derived } from './index-6zo8caE3.js'; import { I as Icon } from './Icon-BX2G3WyD.js'; import { D as Download } from './download-RwF-ht7F.js'; import './client-BuRfMCoZ.js'; import './exports-DKuYoYKl.js'; function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function compose() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return function (x) { return fns.reduceRight(function (y, f) { return f(y); }, x); }; } function curry$1(fn) { return function curried() { var _this = this; for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return args.length >= fn.length ? fn.apply(this, args) : function () { for (var _len3 = arguments.length, nextArgs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { nextArgs[_key3] = arguments[_key3]; } return curried.apply(_this, [].concat(args, nextArgs)); }; }; } function isObject(value) { return {}.toString.call(value).includes('Object'); } function isEmpty(obj) { return !Object.keys(obj).length; } function isFunction(value) { return typeof value === 'function'; } function hasOwnProperty(object, property) { return Object.prototype.hasOwnProperty.call(object, property); } function validateChanges(initial, changes) { if (!isObject(changes)) errorHandler('changeType'); if (Object.keys(changes).some(function (field) { return !hasOwnProperty(initial, field); })) errorHandler('changeField'); return changes; } function validateSelector(selector) { if (!isFunction(selector)) errorHandler('selectorType'); } function validateHandler(handler) { if (!(isFunction(handler) || isObject(handler))) errorHandler('handlerType'); if (isObject(handler) && Object.values(handler).some(function (_handler) { return !isFunction(_handler); })) errorHandler('handlersType'); } function validateInitial(initial) { if (!initial) errorHandler('initialIsRequired'); if (!isObject(initial)) errorHandler('initialType'); if (isEmpty(initial)) errorHandler('initialContent'); } function throwError$1(errorMessages, type) { throw new Error(errorMessages[type] || errorMessages["default"]); } var errorMessages$1 = { initialIsRequired: 'initial state is required', initialType: 'initial state should be an object', initialContent: 'initial state shouldn\'t be an empty object', handlerType: 'handler should be an object or a function', handlersType: 'all handlers should be a functions', selectorType: 'selector should be a function', changeType: 'provided value of changes should be an object', changeField: 'it seams you want to change a field in the state which is not specified in the "initial" state', "default": 'an unknown error accured in `state-local` package' }; var errorHandler = curry$1(throwError$1)(errorMessages$1); var validators = { changes: validateChanges, selector: validateSelector, handler: validateHandler, initial: validateInitial }; function create(initial) { var handler = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; validators.initial(initial); validators.handler(handler); var state = { current: initial }; var didUpdate = curry$1(didStateUpdate)(state, handler); var update = curry$1(updateState)(state); var validate = curry$1(validators.changes)(initial); var getChanges = curry$1(extractChanges)(state); function getState() { var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function (state) { return state; }; validators.selector(selector); return selector(state.current); } function setState(causedChanges) { compose(didUpdate, update, validate, getChanges)(causedChanges); } return [getState, setState]; } function extractChanges(state, causedChanges) { return isFunction(causedChanges) ? causedChanges(state.current) : causedChanges; } function updateState(state, changes) { state.current = _objectSpread2(_objectSpread2({}, state.current), changes); return changes; } function didStateUpdate(state, handler, changes) { isFunction(handler) ? handler(state.current) : Object.keys(changes).forEach(function (field) { var _handler$field; return (_handler$field = handler[field]) === null || _handler$field === void 0 ? void 0 : _handler$field.call(handler, state.current[field]); }); return changes; } var index = { create: create }; var config = { paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } }; function curry(fn) { return function curried() { var _this = this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return args.length >= fn.length ? fn.apply(this, args) : function () { for (var _len2 = arguments.length, nextArgs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { nextArgs[_key2] = arguments[_key2]; } return curried.apply(_this, [].concat(args, nextArgs)); }; }; } function throwError(errorMessages, type) { throw new Error(errorMessages[type] || errorMessages["default"]); } var errorMessages = { configIsRequired: 'the configuration object is required', configType: 'the configuration object should be an object', "default": 'an unknown error accured in `@monaco-editor/loader` package', deprecation: "Deprecation warning!\n You are using deprecated way of configuration.\n\n Instead of using\n monaco.config({ urls: { monacoBase: '...' } })\n use\n monaco.config({ paths: { vs: '...' } })\n\n For more please check the link https://github.com/suren-atoyan/monaco-loader#config\n " }; curry(throwError)(errorMessages); /** the local state of the module */ var _state$create = index.create({ config: config, isInitialized: false, resolve: null, reject: null, monaco: null }), _state$create2 = _slicedToArray(_state$create, 2); _state$create2[0]; var setState = _state$create2[1]; new Promise(function (resolve, reject) { return setState({ resolve: resolve, reject: reject }); }); class BrowserLogger { queue = []; batchTimer = null; batchDelay = 1e3; // 1 second maxBatchSize = 50; endpoint = "/api/log/browser"; isEnabled = true; constructor() { this.interceptConsole(); if (typeof window !== "undefined") { window.addEventListener("beforeunload", () => { this.flush(); }); } } interceptConsole() { if (typeof window === "undefined") return; const originalLog = console.log; const originalError = console.error; const originalWarn = console.warn; const originalDebug = console.debug; console.log = (...args) => { this.log("info", args); originalLog.apply(console, args); }; console.error = (...args) => { this.log("error", args); originalError.apply(console, args); }; console.warn = (...args) => { this.log("warn", args); originalWarn.apply(console, args); }; console.debug = (...args) => { this.log("debug", args); originalDebug.apply(console, args); }; } getBrowserInfo() { if (typeof window === "undefined") { return { userAgent: "unknown", url: "unknown", viewport: { width: 0, height: 0 } }; } return { userAgent: navigator.userAgent, url: window.location.href, viewport: { width: window.innerWidth, height: window.innerHeight } }; } formatMessage(args) { return args.map((arg) => { if (typeof arg === "object") { try { return JSON.stringify(arg, null, 2); } catch (e) { return String(arg); } } return String(arg); }).join(" "); } log(level, args) { if (!this.isEnabled) return; const entry = { level, message: this.formatMessage(args), timestamp: (/* @__PURE__ */ new Date()).toISOString(), browserInfo: this.getBrowserInfo() }; if (args.length === 1 && typeof args[0] === "object") { entry.data = args[0]; } this.queue.push(entry); this.scheduleBatch(); } scheduleBatch() { if (this.batchTimer !== null) return; if (this.queue.length >= this.maxBatchSize) { this.sendBatch(); return; } this.batchTimer = window.setTimeout(() => { this.sendBatch(); }, this.batchDelay); } async sendBatch() { if (this.batchTimer !== null) { clearTimeout(this.batchTimer); this.batchTimer = null; } if (this.queue.length === 0) return; const batch = this.queue.splice(0, this.maxBatchSize); try { const response = await fetch(this.endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ logs: batch }) }); if (!response.ok) { throw new Error(`Failed to send logs: ${response.status}`); } } catch (error) { console.error("[BrowserLogger] Failed to send logs to server:", error); batch.forEach((entry) => { const fallbackMsg = `[${entry.level.toUpperCase()}] ${entry.timestamp} - ${entry.message}`; switch (entry.level) { case "error": console.error(fallbackMsg, entry.data); break; case "warn": console.warn(fallbackMsg, entry.data); break; case "debug": console.debug(fallbackMsg, entry.data); break; default: console.log(fallbackMsg, entry.data); } }); } if (this.queue.length > 0) { this.scheduleBatch(); } } // Public methods for direct usage info(...args) { this.log("info", args); } error(...args) { this.log("error", args); } debug(...args) { this.log("debug", args); } warn(...args) { this.log("warn", args); } // Force send all queued logs flush() { if (this.queue.length > 0) { this.sendBatch(); } } // Enable/disable logging enable() { this.isEnabled = true; } disable() { this.isEnabled = false; } // Configuration methods setEndpoint(endpoint) { this.endpoint = endpoint; } setBatchDelay(delay) { this.batchDelay = delay; } setMaxBatchSize(size) { this.maxBatchSize = size; } } const logger = new BrowserLogger(); const css$f = { code: ".terminal-outer-container.svelte-b660cs.svelte-b660cs{width:100%;height:100%;position:relative;overflow:hidden;max-height:100%;box-sizing:border-box}.terminal-container.svelte-b660cs.svelte-b660cs{width:100%;height:100%;background-color:#1e1e1e;position:relative;box-sizing:border-box}.terminal-container.loading.svelte-b660cs.svelte-b660cs{opacity:0.2}.terminal-container.dragging-over.svelte-b660cs.svelte-b660cs{border:2px dashed var(--accent-color, #0e639c);background-color:rgba(14, 99, 156, 0.1)}.terminal-container.dragging-over.svelte-b660cs.svelte-b660cs::after{content:'Drop files here';position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);color:var(--accent-color, #0e639c);font-size:18px;font-weight:bold;pointer-events:none;z-index:10;background:rgba(30, 30, 30, 0.9);padding:10px 20px;border-radius:4px;border:1px solid var(--accent-color, #0e639c)}.upload-modal-backdrop.svelte-b660cs.svelte-b660cs{position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0, 0, 0, 0.7);z-index:1000;display:flex;align-items:center;justify-content:center}.upload-modal.svelte-b660cs.svelte-b660cs{background-color:#2a2a2a;border:1px solid #444;border-radius:8px;padding:24px;max-width:500px;width:90%;max-height:70vh;overflow-y:auto;box-shadow:0 4px 6px rgba(0, 0, 0, 0.3)}.upload-modal.svelte-b660cs h3.svelte-b660cs{margin:0 0 16px 0;color:#fff;font-size:20px}.upload-modal.svelte-b660cs p.svelte-b660cs{color:#ccc;margin:0 0 16px 0;line-height:1.5}.dropped-files.svelte-b660cs.svelte-b660cs{background-color:#1e1e1e;border:1px solid #444;border-radius:4px;padding:12px;margin:16px 0}.dropped-files.svelte-b660cs p.svelte-b660cs{margin:0 0 8px 0;font-weight:bold;color:#aaa;font-size:14px}.dropped-files.svelte-b660cs ul.svelte-b660cs{margin:0;padding-left:20px;color:#ccc}.dropped-files.svelte-b660cs li.svelte-b660cs{margin:4px 0;font-family:monospace;font-size:13px}.close-modal-btn.svelte-b660cs.svelte-b660cs{background-color:var(--accent-color, #0e639c);color:white;border:none;padding:8px 24px;border-radius:4px;cursor:pointer;font-size:14px;margin-top:16px;width:100%}.close-modal-btn.svelte-b660cs.svelte-b660cs:hover{background-color:#1976d2}.loading-overlay.svelte-b660cs.svelte-b660cs{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;background-color:rgba(30, 30, 30, 0.9);z-index:100;pointer-events:none}.loading-content.svelte-b660cs.svelte-b660cs{text-align:center;color:var(--text-primary, #d4d4d4)}.loading-spinner.svelte-b660cs.svelte-b660cs{width:40px;height:40px;margin:0 auto 16px;border:3px solid rgba(255, 255, 255, 0.1);border-top-color:var(--accent-color, #0e639c);border-radius:50%;animation:svelte-b660cs-spin 1s linear infinite}.loading-text.svelte-b660cs.svelte-b660cs{font-size:16px;font-weight:500}.connection-status.svelte-b660cs.svelte-b660cs{position:absolute;top:10px;right:10px;background:rgba(0, 0, 0, 0.8);color:#fff;padding:8px 16px;border-radius:4px;font-size:14px;z-index:100;display:flex;align-items:center;gap:8px}.connection-status.reconnecting.svelte-b660cs.svelte-b660cs{background:rgba(255, 152, 0, 0.9)}.status-icon.svelte-b660cs.svelte-b660cs{display:inline-block;animation:svelte-b660cs-spin 1s linear infinite}@keyframes svelte-b660cs-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.terminal-wrapper .xterm{padding:5px;height:100%;width:100%;display:block;box-sizing:border-box}.xterm-viewport{background-color:#1e1e1e;overflow-y:scroll !important;overflow-x:auto !important}.xterm-screen{margin:0;width:100% !important}.xterm-rows{min-width:0}.xterm{height:100%;width:100%;box-sizing:border-box}.terminal-wrapper{width:100% !important}.xterm .xterm-text-layer,.xterm .xterm-cursor-layer,.xterm .xterm-selection-layer{will-change:transform}.xterm.xterm-cursor-blink{animation-duration:1s}.xterm-helper-textarea{font-size:16px !important}.xterm-helper-textarea{font-size:16px !important}.xterm .xterm-rows{line-height:1.1 !important}.xterm-screen{line-height:1.1 !important}.xterm .xterm-row{line-height:1.1 !important}", map: '{"version":3,"file":"Terminal.svelte","sources":["Terminal.svelte"],"sourcesContent":["<script lang=\\"ts\\">import { onMount, onDestroy, createEventDispatcher, beforeUpdate, afterUpdate } from \\"svelte\\";\\nimport { browser } from \\"$app/environment\\";\\nimport { settings } from \\"$lib/panels/Settings/settings-store\\";\\nimport { fade } from \\"svelte/transition\\";\\nimport logger from \\"$lib/utils/browser-logger\\";\\nconsole.log(\\"\\\\u2705\\\\u2705\\\\u2705 Terminal.svelte loaded - console logging is ENABLED \\\\u2705\\\\u2705\\\\u2705\\");\\nlet Terminal;\\nlet FitAddon;\\nlet WebLinksAddon;\\nif (browser) {\\n import(\\"@xterm/xterm\\").then((module) => {\\n Terminal = module.Terminal;\\n });\\n import(\\"@xterm/addon-fit\\").then((module) => {\\n FitAddon = module.FitAddon;\\n });\\n import(\\"@xterm/addon-web-links\\").then((module) => {\\n WebLinksAddon = module.WebLinksAddon;\\n });\\n import(\\"@xterm/xterm/css/xterm.css\\");\\n}\\nexport let websocketUrl = \\"ws://localhost:3000\\";\\nexport let autoLaunchClaude = false;\\nexport let panelId = \\"\\";\\nexport let backgroundColor = void 0;\\nexport let textColor = void 0;\\nexport let boldTextColor = void 0;\\nlet terminalContainer;\\nlet terminal;\\nlet fitAddon;\\nlet ws = null;\\nlet inputBuffer = \\"\\";\\nlet settingsUnsubscribe = null;\\nlet reconnectAttempts = 0;\\nlet isReconnecting = false;\\nlet connectionStatus = \\"disconnected\\";\\nexport let terminalSessionId = null;\\nlet sessionId = null;\\nlet agentId = null;\\nlet isInitializing = true;\\nlet hideLogoTimeout = null;\\nlet isDraggingOver = false;\\nlet showUploadModal = false;\\nlet draggedFiles = [];\\nlet resizeObserver = null;\\nlet mutationObserver = null;\\nlet windowResizeHandler = null;\\nlet orientationChangeHandler = null;\\nconst dispatch = createEventDispatcher();\\nlet claudeIdleTimeout = null;\\nlet lastDataReceived = 0;\\nlet claudeState = \\"idle\\";\\nlet accumulatedOutput = \\"\\";\\n$: if (terminal && (backgroundColor || textColor || boldTextColor)) {\\n updateTerminalSettings();\\n}\\nfunction isRemoteServer() {\\n if (!browser) return false;\\n const hostname = window.location.hostname;\\n return hostname !== \\"localhost\\" && hostname !== \\"127.0.0.1\\" && hostname !== \\"::1\\";\\n}\\nfunction handleDragOver(event) {\\n event.preventDefault();\\n event.stopPropagation();\\n isDraggingOver = true;\\n if (event.dataTransfer) {\\n event.dataTransfer.dropEffect = \\"copy\\";\\n }\\n}\\nfunction handleDragLeave(event) {\\n event.preventDefault();\\n event.stopPropagation();\\n isDraggingOver = false;\\n}\\nfunction handleDrop(event) {\\n event.preventDefault();\\n event.stopPropagation();\\n isDraggingOver = false;\\n if (!event.dataTransfer || !event.dataTransfer.files.length) {\\n return;\\n }\\n const files = Array.from(event.dataTransfer.files);\\n const items = event.dataTransfer.items ? Array.from(event.dataTransfer.items) : [];\\n if (isRemoteServer()) {\\n draggedFiles = files;\\n showUploadModal = true;\\n return;\\n }\\n processFilesForTerminal(files, items);\\n}\\nasync function processFilesForTerminal(files, items) {\\n const paths = [];\\n for (let i = 0; i < items.length; i++) {\\n const item = items[i];\\n if (item.kind === \\"file\\") {\\n const entry = item.webkitGetAsEntry ? item.webkitGetAsEntry() : null;\\n if (entry) {\\n paths.push(entry.fullPath || files[i].name);\\n } else {\\n paths.push(files[i].name);\\n }\\n }\\n }\\n if (paths.length === 0) {\\n files.forEach((file) => {\\n const path = file.path || file.webkitRelativePath || file.name;\\n paths.push(path);\\n });\\n }\\n if (paths.length > 0 && terminal) {\\n const pathString = paths.map((p) => {\\n if (p.includes(\\" \\") || p.includes(\\"(\\") || p.includes(\\")\\") || p.includes(\\"&\\")) {\\n return `\'${p}\'`;\\n }\\n return p;\\n }).join(\\" \\");\\n sendInput(pathString);\\n }\\n}\\nfunction closeUploadModal() {\\n showUploadModal = false;\\n draggedFiles = [];\\n}\\nonMount(() => {\\n dispatch(\\"ready\\", {\\n sendInput,\\n write,\\n writeln,\\n clear,\\n clearSession\\n });\\n});\\nlet outputBuffer = [];\\nlet flushTimeout = null;\\nlet earlyMessages = [];\\nconst BUFFER_FLUSH_DELAY = 16;\\nfunction flushBuffer() {\\n if (outputBuffer.length > 0 && terminal) {\\n const data = outputBuffer.join(\\"\\");\\n outputBuffer = [];\\n terminal.write(data);\\n }\\n flushTimeout = null;\\n}\\nfunction scheduleFlush() {\\n if (!flushTimeout && browser) {\\n flushTimeout = window.requestAnimationFrame(flushBuffer);\\n }\\n}\\nexport function write(data) {\\n if (terminal) {\\n const viewport = getViewportInfo();\\n if (data.length < 100 || viewport.isSmall) {\\n terminal.write(data);\\n } else {\\n outputBuffer.push(data);\\n scheduleFlush();\\n }\\n } else {\\n console.warn(\\"[Terminal.write] No terminal instance, cannot write data\\");\\n }\\n}\\nexport function writeln(data) {\\n if (terminal) {\\n write(data + \\"\\\\r\\\\n\\");\\n } else {\\n earlyMessages.push(data);\\n console.log(\\"[Terminal] Buffering early message:\\", data);\\n }\\n}\\nexport function clear() {\\n if (terminal) {\\n outputBuffer = [];\\n if (flushTimeout) {\\n cancelAnimationFrame(flushTimeout);\\n flushTimeout = null;\\n }\\n terminal.clear();\\n }\\n}\\nexport function clearSession() {\\n terminalSessionId = null;\\n if (browser) {\\n localStorage.removeItem(\\"morphbox-terminal-session\\");\\n }\\n writeln(\\"\\\\r\\\\n\\\\u{1F504} Session cleared. Next connection will start fresh.\\");\\n}\\nexport function sendInput(input) {\\n console.log(\\"[Terminal.sendInput] Called with:\\", input, \\"WebSocket state:\\", ws?.readyState);\\n if (ws && ws.readyState === WebSocket.OPEN) {\\n const message = JSON.stringify({\\n type: \\"SEND_INPUT\\",\\n payload: { input }\\n });\\n console.log(\\"[Terminal.sendInput] Sending message:\\", message);\\n ws.send(message);\\n } else {\\n console.warn(\\"[Terminal.sendInput] WebSocket not ready:\\", ws?.readyState);\\n }\\n}\\nexport function testLogging() {\\n logger.info(\\"[Terminal] Test log - Info level\\", { test: true, timestamp: Date.now() });\\n logger.error(\\"[Terminal] Test log - Error level\\", { test: true, error: \\"This is a test error\\" });\\n logger.warn(\\"[Terminal] Test log - Warning level\\", { test: true });\\n logger.debug(\\"[Terminal] Test log - Debug level\\", { test: true });\\n console.log(\\"[Terminal] Test logging completed - check logs/browser-logs.jsonl\\");\\n}\\nfunction reconnectWithBackoff() {\\n const maxDelay = 3e4;\\n const baseDelay = 1e3;\\n const delay = Math.min(baseDelay * Math.pow(2, reconnectAttempts), maxDelay);\\n writeln(`\\\\r\\nReconnecting in ${delay / 1e3} seconds... (attempt ${reconnectAttempts + 1})`);\\n setTimeout(() => {\\n if (!ws || ws.readyState === WebSocket.CLOSED) {\\n reconnectAttempts++;\\n connectWebSocket();\\n }\\n }, delay);\\n}\\nfunction connectWebSocket() {\\n if (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN)) {\\n console.warn(\\"[Terminal] WebSocket already connecting or connected, skipping new connection\\");\\n return;\\n }\\n if (ws) {\\n ws.close();\\n }\\n let url = websocketUrl;\\n if (browser) {\\n const urlObj = new URL(websocketUrl);\\n if (terminalSessionId) {\\n urlObj.searchParams.set(\\"terminalSessionId\\", terminalSessionId);\\n }\\n if (sessionId) {\\n urlObj.searchParams.set(\\"sessionId\\", sessionId);\\n } else if (browser) {\\n const storedSessionId = localStorage.getItem(\\"morphbox-websocket-session\\");\\n if (storedSessionId) {\\n sessionId = storedSessionId;\\n urlObj.searchParams.set(\\"sessionId\\", sessionId);\\n }\\n }\\n urlObj.searchParams.set(\\"autoLaunchClaude\\", autoLaunchClaude.toString());\\n url = urlObj.toString();\\n }\\n console.log(\\"[Terminal] Connecting to WebSocket:\\", url);\\n console.log(\\"[Terminal] User agent:\\", navigator.userAgent);\\n console.log(\\"[Terminal] Is mobile:\\", getViewportInfo().isTouchDevice);\\n try {\\n ws = new WebSocket(url);\\n const connectionTimeout = setTimeout(() => {\\n if (ws && ws.readyState !== WebSocket.OPEN) {\\n writeln(`\\\\r\\n\\\\u274C WebSocket connection timeout. Please check if the WebSocket server is running at ${url}.`);\\n console.error(\\"WebSocket connection timeout\\");\\n }\\n }, 5e3);\\n ws.onopen = () => {\\n clearTimeout(connectionTimeout);\\n logger.info(\\"[Terminal] WebSocket connected successfully\\");\\n console.log(\\"WebSocket connected\\");\\n connectionStatus = \\"connected\\";\\n reconnectAttempts = 0;\\n isReconnecting = false;\\n if (terminalSessionId) {\\n writeln(\\"\\\\r\\\\n\\\\u{1F504} Reconnecting to existing session...\\");\\n } else {\\n writeln(\\"\\\\r\\\\n\\\\u2705 Connected to server\\");\\n }\\n dispatch(\\"connection\\", { connected: true });\\n setTimeout(() => {\\n console.log(\\"[Terminal] Hiding loading overlay after connection\\");\\n isInitializing = false;\\n }, 750);\\n };\\n ws.onmessage = (event) => {\\n try {\\n const message = JSON.parse(event.data);\\n if (message.type === \\"OUTPUT\\" && autoLaunchClaude) {\\n } else if (message.type !== \\"OUTPUT\\") {\\n }\\n switch (message.type) {\\n case \\"CONNECTED\\":\\n writeln(`\\\\r\\n${message.payload?.message || \\"Connected\\"}`);\\n if (message.payload?.sessionId) {\\n sessionId = message.payload.sessionId;\\n if (browser && sessionId) {\\n localStorage.setItem(\\"morphbox-websocket-session\\", sessionId);\\n }\\n if (message.payload.isReconnection && sessionId) {\\n writeln(`\\\\r\\n\\\\u{1F504} Reconnected to session: ${sessionId.substring(0, 8)}...`);\\n }\\n }\\n break;\\n case \\"SESSION_CREATED\\":\\n dispatch(\\"session\\", { sessionId: message.payload?.sessionId });\\n break;\\n case \\"AGENT_LAUNCHED\\":\\n agentId = message.payload?.agentId || null;\\n console.log(\\"[Terminal] Agent launched:\\", agentId);\\n isInitializing = false;\\n if (hideLogoTimeout) {\\n clearTimeout(hideLogoTimeout);\\n hideLogoTimeout = null;\\n }\\n dispatch(\\"agent\\", {\\n status: \\"Active\\",\\n agentId: message.payload?.agentId\\n });\\n break;\\n case \\"TERMINAL_SESSION_ID\\":\\n if (message.payload?.sessionId) {\\n const isNewSession = terminalSessionId !== message.payload.sessionId;\\n terminalSessionId = message.payload.sessionId;\\n if (browser && terminalSessionId) {\\n localStorage.setItem(\\"morphbox-terminal-session\\", terminalSessionId);\\n }\\n if (isNewSession && terminalSessionId) {\\n writeln(`\\\\r\\n\\\\u2728 New terminal session created: ${terminalSessionId.substring(0, 8)}...`);\\n } else if (terminalSessionId) {\\n writeln(`\\\\r\\n\\\\u2705 Terminal session restored: ${terminalSessionId.substring(0, 8)}...`);\\n }\\n }\\n break;\\n case \\"RECONNECTED\\":\\n writeln(`\\\\r\\n\\\\u2705 Reconnected to agent: ${message.payload?.agentId}`);\\n dispatch(\\"agent\\", {\\n status: \\"Active\\",\\n agentId: message.payload?.agentId\\n });\\n isInitializing = false;\\n break;\\n case \\"AGENT_EXIT\\":\\n dispatch(\\"agent\\", { status: \\"No agent\\" });\\n break;\\n case \\"OUTPUT\\":\\n if (message.payload?.data && message.payload?.agentId === agentId) {\\n if (isInitializing) {\\n console.log(\\"[Terminal] First output received, hiding loading overlay\\");\\n isInitializing = false;\\n if (hideLogoTimeout) {\\n clearTimeout(hideLogoTimeout);\\n hideLogoTimeout = null;\\n }\\n }\\n write(message.payload.data);\\n if (autoLaunchClaude) {\\n const data = message.payload.data;\\n lastDataReceived = Date.now();\\n claudeState = \\"responding\\";\\n accumulatedOutput += data;\\n if (accumulatedOutput.length > 500) {\\n accumulatedOutput = accumulatedOutput.slice(-500);\\n }\\n const cleanData = data.replace(/\\\\x1b\\\\[[0-9;]*[mGKHJ]/g, \\"\\").trim();\\n if (cleanData && cleanData.length > 5 && !cleanData.match(/^\\\\[\\\\d+[A-Z]$/)) {\\n console.log(\\"\\\\u{1F4DF} Terminal:\\", cleanData.substring(0, 80));\\n }\\n if (claudeIdleTimeout) {\\n clearTimeout(claudeIdleTimeout);\\n }\\n claudeIdleTimeout = setTimeout(() => {\\n const lowerOutput = accumulatedOutput.toLowerCase();\\n const trimmedOutput = accumulatedOutput.trim();\\n const hasClaudeCodePrompt = trimmedOutput.endsWith(\\">\\") || accumulatedOutput.includes(\\"\\\\u2500\\\\u2500\\\\u2500\\") && trimmedOutput.endsWith(\\">\\");\\n const hasRegularClaudePrompt = trimmedOutput.endsWith(\\"human:\\") || trimmedOutput.endsWith(\\"h:\\") || lowerOutput.includes(\\"human:\\") && Date.now() - lastDataReceived > 2e3;\\n const hasEscToInterrupt = accumulatedOutput.toLowerCase().includes(\\"esc to interrupt\\");\\n if (hasEscToInterrupt) {\\n console.log(\'\\\\u23F3 Claude still responding (\\"esc to interrupt\\" present)\');\\n }\\n if (typeof window !== \\"undefined\\") {\\n window.claudeDetectionData = {\\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\\n hasEscToInterrupt,\\n hasClaudeCodePrompt,\\n hasRegularClaudePrompt,\\n last100Chars: accumulatedOutput.slice(-100),\\n fullAccumulatedOutput: accumulatedOutput,\\n claudeState\\n };\\n }\\n if (!hasEscToInterrupt && accumulatedOutput.length > 10) {\\n if (claudeState !== \\"idle\\") {\\n claudeState = \\"idle\\";\\n console.log(\\"\\");\\n console.log(\\"\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\");\\n console.log(\\"\\\\u{1F3AF} CLAUDE IS NOW IDLE - DISPATCHING EVENT! \\\\u{1F3AF}\\");\\n console.log(\\"\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\");\\n console.log(\'\\\\u2705 No \\"esc to interrupt\\" found (Claude finished)\');\\n console.log(\\"\\\\u2705 Claude prompt detected:\\", hasClaudeCodePrompt ? \\">\\" : hasRegularClaudePrompt ? \\"human:\\" : \\"unknown\\");\\n console.log(\\"\\\\u{1F4C4} Last output:\\", accumulatedOutput.slice(-100).replace(/\\\\x1b\\\\[[0-9;]*[mGKHJ]/g, \\"\\"));\\n console.log(\\"\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\\\u{1F3AF}\\");\\n console.log(\\"\\");\\n if (typeof window !== \\"undefined\\") {\\n window.lastClaudeIdleEvent = {\\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\\n output: accumulatedOutput\\n };\\n }\\n dispatch(\\"claude-idle\\");\\n }\\n } else if (Date.now() - lastDataReceived > 3e3) {\\n if (claudeState !== \\"idle\\") {\\n claudeState = \\"idle\\";\\n console.log(\\"[Terminal] \\\\u{1F550} CLAUDE IS IDLE (3s timeout) - DISPATCHING EVENT\\");\\n console.log(\\"[Terminal] Time since last data:\\", Date.now() - lastDataReceived, \\"ms\\");\\n console.log(\\"[Terminal] Last output:\\", accumulatedOutput.slice(-100));\\n if (typeof window !== \\"undefined\\") {\\n window.lastClaudeIdleEvent = {\\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\\n reason: \\"timeout\\",\\n output: accumulatedOutput\\n };\\n }\\n dispatch(\\"claude-idle\\");\\n }\\n }\\n }, 4e3);\\n }\\n }\\n break;\\n case \\"ERROR\\":\\n writeln(`\\\\r\\nError: ${message.payload?.message || \\"Unknown error\\"}`);\\n break;\\n case \\"STATE_UPDATE\\":\\n if (message.payload?.agent) {\\n dispatch(\\"agent\\", {\\n status: message.payload.agent.status || \\"Active\\",\\n agentId: message.payload.agent.id\\n });\\n }\\n break;\\n case \\"CLEAR\\":\\n clear();\\n break;\\n default:\\n console.log(\\"Unknown message type:\\", message.type);\\n }\\n } catch (e) {\\n console.error(\\"Error parsing WebSocket message:\\", e);\\n write(event.data);\\n }\\n };\\n ws.onerror = (error) => {\\n logger.error(\\"[Terminal] WebSocket error:\\", error);\\n console.error(\\"WebSocket error:\\", error);\\n writeln(`\\\\r\\nWebSocket error: ${error}`);\\n };\\n ws.onclose = (event) => {\\n logger.info(\\"[Terminal] WebSocket closed\\", { code: event.code, reason: event.reason });\\n console.error(\\"[Terminal] WebSocket closed:\\", {\\n code: event.code,\\n reason: event.reason,\\n wasClean: event.wasClean,\\n readyState: ws?.readyState,\\n timestamp: (/* @__PURE__ */ new Date()).toISOString(),\\n stackTrace: new Error().stack\\n });\\n connectionStatus = \\"disconnected\\";\\n writeln(`\\\\r\\nDisconnected from server (code: ${event.code})`);\\n dispatch(\\"connection\\", { connected: false });\\n dispatch(\\"agent\\", { status: \\"No agent\\" });\\n if (event.code !== 1e3 && event.code !== 1001 && !isReconnecting) {\\n isReconnecting = true;\\n connectionStatus = \\"reconnecting\\";\\n reconnectWithBackoff();\\n }\\n };\\n } catch (error) {\\n console.error(\\"[Terminal] WebSocket setup error:\\", error);\\n isInitializing = false;\\n writeln(\\"\\\\r\\\\n\\\\u274C Failed to connect to WebSocket\\");\\n return;\\n }\\n}\\nfunction getViewportInfo() {\\n if (!browser) return { width: 1200, height: 800, isSmall: false, isTouchDevice: false };\\n const width = window.innerWidth;\\n const height = window.innerHeight;\\n const isSmall = width < 768;\\n const isTouchDevice = \\"ontouchstart\\" in window || navigator.maxTouchPoints > 0;\\n const info = { width, height, isSmall, isTouchDevice };\\n if (typeof window !== \\"undefined\\" && window.__lastViewportInfo) {\\n const last = window.__lastViewportInfo;\\n if (last.width !== width || last.height !== height || last.isSmall !== isSmall) {\\n console.log(\\"[Terminal.getViewportInfo] Viewport changed:\\", {\\n from: last,\\n to: info,\\n delta: {\\n width: width - last.width,\\n height: height - last.height\\n },\\n devicePixelRatio: window.devicePixelRatio\\n });\\n }\\n }\\n if (typeof window !== \\"undefined\\") {\\n window.__lastViewportInfo = info;\\n }\\n return info;\\n}\\nfunction getTerminalOptions() {\\n const viewport = getViewportInfo();\\n const currentSettings = $settings;\\n console.log(\\"[Terminal.getTerminalOptions] Starting calculation:\\", {\\n viewport,\\n hasContainer: !!terminalContainer,\\n currentSettings: currentSettings?.terminal\\n });\\n let fontSize = currentSettings?.terminal.fontSize || 14;\\n if (viewport.isSmall) {\\n fontSize = Math.max(12, Math.min(fontSize, 14));\\n }\\n let containerWidth = viewport.width;\\n let containerHeight = viewport.height;\\n if (terminalContainer) {\\n const rect = terminalContainer.getBoundingClientRect();\\n containerWidth = rect.width || containerWidth;\\n containerHeight = rect.height || containerHeight;\\n console.log(\\"[Terminal.getTerminalOptions] Container dimensions:\\", {\\n rectWidth: rect.width,\\n rectHeight: rect.height,\\n containerWidth,\\n containerHeight,\\n fallbackToViewport: rect.width === 0 || rect.height === 0\\n });\\n }\\n const charWidth = fontSize * 0.55;\\n const lineHeight = fontSize * (currentSettings?.terminal.lineHeight || 1.1);\\n const padding = viewport.isSmall ? 5 : 10;\\n const cols = Math.max(40, Math.floor((containerWidth - padding * 2) / charWidth));\\n const rows = Math.max(10, Math.floor((containerHeight - padding * 2) / lineHeight));\\n console.log(\\"[Terminal.getTerminalOptions] Calculated dimensions:\\", {\\n fontSize,\\n charWidth,\\n lineHeight,\\n padding,\\n cols,\\n rows,\\n availableWidth: containerWidth - padding * 2,\\n availableHeight: containerHeight - padding * 2\\n });\\n return {\\n fontSize,\\n fontFamily: currentSettings?.terminal.fontFamily || \'\\"Cascadia Code\\", \\"Fira Code\\", monospace\',\\n cols,\\n rows,\\n lineHeight: currentSettings?.terminal.lineHeight || 1.1,\\n cursorStyle: currentSettings?.terminal.cursorStyle || \\"block\\",\\n cursorBlink: currentSettings?.terminal.cursorBlink ?? true,\\n allowProposedApi: true,\\n scrollback: viewport.isSmall ? 1e3 : 5e3,\\n // Reduce scrollback on mobile for performance\\n fastScrollModifier: \\"ctrl\\",\\n smoothScrollDuration: viewport.isSmall ? 0 : 125\\n // Disable smooth scroll on mobile\\n };\\n}\\nfunction measureTerminal() {\\n console.log(\\"[Terminal.measureTerminal] Starting measurement:\\", {\\n hasBrowser: browser,\\n hasContainer: !!terminalContainer,\\n hasTerminal: !!terminal,\\n timestamp: (/* @__PURE__ */ new Date()).toISOString()\\n });\\n if (!browser || !terminalContainer || !terminal) {\\n console.warn(\\"[Terminal.measureTerminal] Missing required components, returning defaults\\");\\n return { cols: 80, rows: 24 };\\n }\\n try {\\n const rect = terminalContainer.getBoundingClientRect();\\n console.log(\\"[Terminal.measureTerminal] Container rect:\\", {\\n width: rect.width,\\n height: rect.height,\\n top: rect.top,\\n left: rect.left,\\n right: rect.right,\\n bottom: rect.bottom,\\n x: rect.x,\\n y: rect.y\\n });\\n if (rect.width === 0 || rect.height === 0) {\\n console.error(\\"[Terminal.measureTerminal] Container has zero dimensions!\\", {\\n rect,\\n containerDisplay: window.getComputedStyle(terminalContainer).display,\\n containerVisibility: window.getComputedStyle(terminalContainer).visibility,\\n containerOpacity: window.getComputedStyle(terminalContainer).opacity,\\n parentElement: terminalContainer.parentElement?.getBoundingClientRect()\\n });\\n return { cols: 80, rows: 24 };\\n }\\n if (terminal._core && terminal._core._renderService && terminal._core._renderService.dimensions) {\\n const dimensions = terminal._core._renderService.dimensions;\\n if (dimensions.actualCellWidth && dimensions.actualCellHeight) {\\n const charWidth2 = dimensions.actualCellWidth;\\n const charHeight2 = dimensions.actualCellHeight;\\n const terminalElement2 = terminalContainer.querySelector(\\".xterm\\");\\n let paddingLeft2 = 0, paddingRight2 = 0, paddingTop2 = 0, paddingBottom2 = 0;\\n if (terminalElement2) {\\n const computedStyle2 = window.getComputedStyle(terminalElement2);\\n paddingLeft2 = parseFloat(computedStyle2.paddingLeft) || 0;\\n paddingRight2 = parseFloat(computedStyle2.paddingRight) || 0;\\n paddingTop2 = parseFloat(computedStyle2.paddingTop) || 0;\\n paddingBottom2 = parseFloat(computedStyle2.paddingBottom) || 0;\\n }\\n const availableWidth2 = rect.width - paddingLeft2 - paddingRight2;\\n const availableHeight2 = rect.height - paddingTop2 - paddingBottom2;\\n const cols2 = Math.max(40, Math.floor(availableWidth2 / charWidth2));\\n const rows2 = Math.max(10, Math.floor(availableHeight2 / charHeight2));\\n console.log(\\"[Terminal] Using renderer dimensions:\\", {\\n actualCellWidth: charWidth2,\\n actualCellHeight: charHeight2,\\n availableWidth: availableWidth2,\\n availableHeight: availableHeight2,\\n cols: cols2,\\n rows: rows2\\n });\\n return { cols: cols2, rows: rows2 };\\n }\\n }\\n if (fitAddon) {\\n try {\\n const proposed = fitAddon.proposeDimensions();\\n if (proposed && proposed.cols && proposed.rows) {\\n const cols2 = Math.max(40, proposed.cols);\\n const rows2 = Math.max(10, proposed.rows);\\n console.log(\\"[Terminal] Using fitAddon.proposeDimensions:\\", {\\n proposedCols: proposed.cols,\\n proposedRows: proposed.rows,\\n cols: cols2,\\n rows: rows2\\n });\\n return { cols: cols2, rows: rows2 };\\n }\\n } catch (e) {\\n console.warn(\\"[Terminal] fitAddon.proposeDimensions failed:\\", e);\\n }\\n }\\n if (terminal._core && terminal._core._charSizeService) {\\n const charSizeService = terminal._core._charSizeService;\\n if (charSizeService.width && charSizeService.height) {\\n const charWidth2 = charSizeService.width;\\n const charHeight2 = charSizeService.height;\\n const terminalElement2 = terminalContainer.querySelector(\\".xterm\\");\\n let paddingLeft2 = 0, paddingRight2 = 0, paddingTop2 = 0, paddingBottom2 = 0;\\n if (terminalElement2) {\\n const computedStyle2 = window.getComputedStyle(terminalElement2);\\n paddingLeft2 = parseFloat(computedStyle2.paddingLeft) || 0;\\n paddingRight2 = parseFloat(computedStyle2.paddingRight) || 0;\\n paddingTop2 = parseFloat(computedStyle2.paddingTop) || 0;\\n paddingBottom2 = parseFloat(computedStyle2.paddingBottom) || 0;\\n }\\n const availableWidth2 = rect.width - paddingLeft2 - paddingRight2;\\n const availableHeight2 = rect.height - paddingTop2 - paddingBottom2;\\n const cols2 = Math.max(40, Math.floor(availableWidth2 / charWidth2));\\n const rows2 = Math.max(10, Math.floor(availableHeight2 / charHeight2));\\n console.log(\\"[Terminal] Using charSizeService dimensions:\\", {\\n charWidth: charWidth2,\\n charHeight: charHeight2,\\n availableWidth: availableWidth2,\\n availableHeight: availableHeight2,\\n cols: cols2,\\n rows: rows2\\n });\\n return { cols: cols2, rows: rows2 };\\n }\\n }\\n console.warn(\\"[Terminal] No xterm dimensions available, using manual measurement\\");\\n const terminalElement = terminalContainer.querySelector(\\".xterm\\");\\n if (!terminalElement) {\\n console.warn(\\"[Terminal] Terminal element not found, using rough estimates\\");\\n const fontSize = terminal.options.fontSize || 14;\\n const charWidth2 = fontSize * 0.55;\\n const lineHeight = fontSize * (terminal.options.lineHeight || 1.1);\\n const padding = 10;\\n const cols2 = Math.max(40, Math.floor((rect.width - padding * 2) / charWidth2));\\n const rows2 = Math.max(10, Math.floor((rect.height - padding * 2) / lineHeight));\\n return { cols: cols2, rows: rows2 };\\n }\\n const computedStyle = window.getComputedStyle(terminalElement);\\n const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;\\n const paddingRight = parseFloat(computedStyle.paddingRight) || 0;\\n const paddingTop = parseFloat(computedStyle.paddingTop) || 0;\\n const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0;\\n const availableWidth = rect.width - paddingLeft - paddingRight;\\n const availableHeight = rect.height - paddingTop - paddingBottom;\\n const testElement = document.createElement(\\"div\\");\\n testElement.style.position = \\"absolute\\";\\n testElement.style.visibility = \\"hidden\\";\\n testElement.style.left = \\"-9999px\\";\\n testElement.style.fontFamily = terminal.options.fontFamily || \'\\"Cascadia Code\\", \\"Fira Code\\", monospace\';\\n testElement.style.fontSize = `${terminal.options.fontSize || 14}px`;\\n testElement.style.lineHeight = `${terminal.options.lineHeight || 1.2}`;\\n testElement.style.whiteSpace = \\"pre\\";\\n testElement.style.padding = \\"0\\";\\n testElement.style.margin = \\"0\\";\\n testElement.style.border = \\"none\\";\\n testElement.textContent = \\"0123456789\\";\\n document.body.appendChild(testElement);\\n const testRect = testElement.getBoundingClientRect();\\n const charWidth = testRect.width / 10;\\n const charHeight = testRect.height;\\n document.body.removeChild(testElement);\\n if (charWidth <= 0 || charHeight <= 0) {\\n console.error(\\"[Terminal] Invalid character measurements:\\", { charWidth, charHeight });\\n return { cols: 80, rows: 24 };\\n }\\n const cols = Math.max(40, Math.floor(availableWidth / charWidth));\\n const rows = Math.max(10, Math.floor(availableHeight / charHeight));\\n const maxCols = 300;\\n const maxRows = 100;\\n const finalCols = Math.min(cols, maxCols);\\n const finalRows = Math.min(rows, maxRows);\\n console.log(\\"[Terminal] Manual measurement dimensions:\\", {\\n containerWidth: rect.width,\\n containerHeight: rect.height,\\n availableWidth,\\n availableHeight,\\n charWidth,\\n charHeight,\\n cols: finalCols,\\n rows: finalRows\\n });\\n return { cols: finalCols, rows: finalRows };\\n } catch (error) {\\n console.error(\\"[Terminal.measureTerminal] Error during measurement:\\", {\\n error,\\n errorMessage: error?.message || \\"Unknown error\\",\\n errorStack: error?.stack || \\"\\",\\n