handmux 0.29.1 → 0.29.2

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.
@@ -201,7 +201,7 @@ Check the render method of %s.`,vt(ln)||"Unknown"));var J=Oo(U,V);J.payload={ele
201
201
 
202
202
  let root = createRoot(domContainer);
203
203
  root.render(<App />);`),r.unstable_strictMode===!0&&(l=!0),r.identifierPrefix!==void 0&&(E=r.identifierPrefix),r.onRecoverableError!==void 0&&(U=r.onRecoverableError),r.transitionCallbacks!==void 0&&r.transitionCallbacks);var V=JS(t,Vp,null,l,p,E,U);Tp(V.current,t);var H=t.nodeType===Qt?t.parentNode:t;return mm(H),new ow(V)}function Hv(t){this._internalRoot=t}function SO(t){t&&F5(t)}Hv.prototype.unstable_scheduleHydration=SO;function jO(t,r,l){if(!zv(t))throw new Error("hydrateRoot(...): Target container is not a DOM element.");_j(t),r===void 0&&d("Must provide initial children as second argument to hydrateRoot. Example usage: hydrateRoot(domContainer, <App />)");var p=l??null,E=l!=null&&l.hydratedSources||null,U=!1,V=!1,H="",J=bj;l!=null&&(l.unstable_strictMode===!0&&(U=!0),l.identifierPrefix!==void 0&&(H=l.identifierPrefix),l.onRecoverableError!==void 0&&(J=l.onRecoverableError));var le=QS(r,null,t,Vp,p,U,V,H,J);if(Tp(le.current,t),mm(t),E)for(var me=0;me<E.length;me++){var Ae=E[me];RV(le,Ae)}return new Hv(le)}function zv(t){return!!(t&&(t.nodeType===cn||t.nodeType===gr||t.nodeType===Mn))}function oh(t){return!!(t&&(t.nodeType===cn||t.nodeType===gr||t.nodeType===Mn||t.nodeType===Qt&&t.nodeValue===" react-mount-point-unstable "))}function _j(t){t.nodeType===cn&&t.tagName&&t.tagName.toUpperCase()==="BODY"&&d("createRoot(): Creating roots directly with document.body is discouraged, since its children are often manipulated by third-party scripts and browser extensions. This may lead to subtle reconciliation issues. Try using a container element created for your app."),Nm(t)&&(t._reactRootContainer?d("You are calling ReactDOMClient.createRoot() on a container that was previously passed to ReactDOM.render(). This is not supported."):d("You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root.render() on the existing root instead if you want to update it."))}var DO=i.ReactCurrentOwner,yj;yj=function(t){if(t._reactRootContainer&&t.nodeType!==Qt){var r=ej(t._reactRootContainer.current);r&&r.parentNode!==t&&d("render(...): It looks like the React-rendered content of this container was removed without using React. This is not supported and will cause errors. Instead, call ReactDOM.unmountComponentAtNode to empty a container.")}var l=!!t._reactRootContainer,p=lw(t),E=!!(p&&hl(p));E&&!l&&d("render(...): Replacing React-rendered children with a new root component. If you intended to update the children of this node, you should instead have the existing children update their state and render the new components instead of calling ReactDOM.render."),t.nodeType===cn&&t.tagName&&t.tagName.toUpperCase()==="BODY"&&d("render(): Rendering components directly into document.body is discouraged, since its children are often manipulated by third-party scripts and browser extensions. This may lead to subtle reconciliation issues. Try rendering into a container element created for your app.")};function lw(t){return t?t.nodeType===gr?t.documentElement:t.firstChild:null}function xj(){}function kO(t,r,l,p,E){if(E){if(typeof p=="function"){var U=p;p=function(){var Re=Fv(V);U.call(Re)}}var V=QS(r,p,t,pl,null,!1,!1,"",xj);t._reactRootContainer=V,Tp(V.current,t);var H=t.nodeType===Qt?t.parentNode:t;return mm(H),Ho(),V}else{for(var J;J=t.lastChild;)t.removeChild(J);if(typeof p=="function"){var le=p;p=function(){var Re=Fv(me);le.call(Re)}}var me=JS(t,pl,null,!1,!1,"",xj);t._reactRootContainer=me,Tp(me.current,t);var Ae=t.nodeType===Qt?t.parentNode:t;return mm(Ae),Ho(function(){ah(r,me,l,p)}),me}}function TO(t,r){t!==null&&typeof t!="function"&&d("%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.",r,t)}function $v(t,r,l,p,E){yj(l),TO(E===void 0?null:E,"render");var U=l._reactRootContainer,V;if(!U)V=kO(l,r,t,E,p);else{if(V=U,typeof E=="function"){var H=E;E=function(){var J=Fv(V);H.call(J)}}ah(r,V,t,E)}return Fv(V)}var wj=!1;function RO(t){{wj||(wj=!0,d("findDOMNode is deprecated and will be removed in the next major release. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-find-node"));var r=DO.current;if(r!==null&&r.stateNode!==null){var l=r.stateNode._warnedAboutRefsInRender;l||d("%s is accessing findDOMNode inside its render(). render() should be a pure function of props and state. It should never access something that requires stale data from the previous render, such as refs. Move this logic to componentDidMount and componentDidUpdate instead.",oe(r.type)||"A component"),r.stateNode._warnedAboutRefsInRender=!0}}return t==null?null:t.nodeType===cn?t:pO(t,"findDOMNode")}function AO(t,r,l){if(d("ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot"),!oh(r))throw new Error("Target container is not a DOM element.");{var p=Nm(r)&&r._reactRootContainer===void 0;p&&d("You are calling ReactDOM.hydrate() on a container that was previously passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call hydrateRoot(container, element)?")}return $v(null,t,r,!0,l)}function UO(t,r,l){if(d("ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot"),!oh(r))throw new Error("Target container is not a DOM element.");{var p=Nm(r)&&r._reactRootContainer===void 0;p&&d("You are calling ReactDOM.render() on a container that was previously passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.render(element)?")}return $v(null,t,r,!1,l)}function MO(t,r,l,p){if(d("ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported in React 18. Consider using a portal instead. Until you switch to the createRoot API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot"),!oh(l))throw new Error("Target container is not a DOM element.");if(t==null||!Tb(t))throw new Error("parentComponent must be a valid React Component");return $v(t,r,l,!1,p)}var Nj=!1;function LO(t){if(Nj||(Nj=!0,d("unmountComponentAtNode is deprecated and will be removed in the next major release. Switch to the createRoot API. Learn more: https://reactjs.org/link/switch-to-createroot")),!oh(t))throw new Error("unmountComponentAtNode(...): Target container is not a DOM element.");{var r=Nm(t)&&t._reactRootContainer===void 0;r&&d("You are calling ReactDOM.unmountComponentAtNode() on a container that was previously passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?")}if(t._reactRootContainer){{var l=lw(t),p=l&&!hl(l);p&&d("unmountComponentAtNode(): The node you're attempting to unmount was rendered by another copy of React.")}return Ho(function(){$v(null,null,t,!1,function(){t._reactRootContainer=null,bC(t)})}),!0}else{{var E=lw(t),U=!!(E&&hl(E)),V=t.nodeType===cn&&oh(t.parentNode)&&!!t.parentNode._reactRootContainer;U&&d("unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. %s",V?"You may have accidentally passed in a React root node instead of its container.":"Instead, have the parent component update its state and rerender in order to remove this component.")}return!1}}R5(vO),U5(gO),M5(bO),L5(ya),I5(D5),(typeof Map!="function"||Map.prototype==null||typeof Map.prototype.forEach!="function"||typeof Set!="function"||Set.prototype==null||typeof Set.prototype.clear!="function"||typeof Set.prototype.forEach!="function")&&d("React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),Wa(VL),jb(Px,j3,Ho);function IO(t,r){var l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:null;if(!zv(r))throw new Error("Target container is not a DOM element.");return fO(t,r,null,l)}function VO(t,r,l,p){return MO(t,r,l,p)}var cw={usingClientEntryPoint:!1,Events:[hl,yu,Rp,Qc,Zs,Px]};function OO(t,r){return cw.usingClientEntryPoint||d('You are importing createRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client".'),EO(t,r)}function PO(t,r,l){return cw.usingClientEntryPoint||d('You are importing hydrateRoot from "react-dom" which is not supported. You should instead import it from "react-dom/client".'),jO(t,r,l)}function BO(t){return TS()&&d("flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task."),Ho(t)}var FO=CO({findFiberByHostInstance:ic,bundleType:1,version:nw,rendererPackageName:"react-dom"});if(!FO&&we&&window.top===window.self&&(navigator.userAgent.indexOf("Chrome")>-1&&navigator.userAgent.indexOf("Edge")===-1||navigator.userAgent.indexOf("Firefox")>-1)){var Cj=window.location.protocol;/^(https?|file):$/.test(Cj)&&console.info("%cDownload the React DevTools for a better development experience: https://reactjs.org/link/react-devtools"+(Cj==="file:"?`
204
- You might need to use a local HTTP server (instead of file://): https://reactjs.org/link/react-devtools-faq`:""),"font-weight:bold")}Ks.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=cw,Ks.createPortal=IO,Ks.createRoot=OO,Ks.findDOMNode=RO,Ks.flushSync=BO,Ks.hydrate=AO,Ks.hydrateRoot=PO,Ks.render=UO,Ks.unmountComponentAtNode=LO,Ks.unstable_batchedUpdates=Px,Ks.unstable_renderSubtreeIntoContainer=VO,Ks.version=nw,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error)})();zT.exports=Ks;var JN=zT.exports,qT,jj=JN;{var Dj=jj.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;qT=function(e,n){Dj.usingClientEntryPoint=!0;try{return jj.createRoot(e,n)}finally{Dj.usingClientEntryPoint=!1}}}const GT={"auth.welcome":"Connect to your terminal workspace","auth.login":"Sign in","auth.connecting":"Connecting","auth.switchLink":"How do I manage login methods?","auth.switchTitle":"Manage login methods","auth.switchWarning":"Sign in with the Token, then authorize this device.","auth.switchSetup":"To change Public URL, run handmux setup on the server. In Direct mode, open Connection → Direct → Public URL and enter your own reverse-tunnel address.","auth.switchRestart":"For first enrollment or recovery after losing every device, run the command below on the handmux computer.","auth.switchAfter":"The CLI switches device protection and address restrictions; manage devices and addresses here.","auth.copySetup":"Copy view command","auth.copyRestart":"Copy restore command","devices.title":"Authentication & security","devices.protectionEnabled":"Protection on","devices.protectionPartial":"Protection partly on","devices.protectionDisabled":"Protection off","devices.insecureTitle":"Security protections are not fully enabled","devices.insecureHint":"Device protection or trusted-address restrictions are off.","devices.openSecurity":"Open Authentication & security","devices.listTitle":"Authorized devices","devices.historyTitle":"Device history","devices.historyLink":"History ({n})","devices.backToActive":"Back to authorized devices","devices.trusted":"Device protection","devices.deviceProtectionSection":"Device protection","devices.deviceProtectionStatus":"Protection status","devices.originProtectionStatus":"Restriction status","devices.policyEnabled":"On","devices.policyDisabled":"Off","devices.deviceProtectionDisabledHint":"Only the Token is required now; enable this to require a trusted device.","devices.enableProtection":"Enable device protection","devices.enableOriginProtection":"Enable address restrictions","devices.enableConfirmTitle":"Confirm protection","devices.enableDeviceConfirm":"This browser will be registered as a trusted device; other devices must be authorized by a trusted device or the computer CLI. Turning it off is CLI-only: handmux auth device off.","devices.enableOriginConfirm":"Only registered access addresses will be allowed. Turning it off is CLI-only: handmux auth address off.","devices.enableConfirm":"Enable","devices.originProtectionDisabledHint":"Access addresses are not restricted now.","devices.deviceProtectionInfo":"Enable device protection here; turning it off is CLI-only with handmux auth device off. This page only manages devices.","devices.deviceProtectionEnabledHint":"Protects access from unauthorized devices; turning it off is CLI-only: handmux auth device off.","devices.originProtectionInfo":"Toggle trusted-address protection with handmux auth address on/off. This page only manages addresses.","devices.originProtectionEnabledHint":"Protects access from unregistered addresses; turning it off is CLI-only: handmux auth address off.","devices.token":"Token","devices.addSelf":"Add this browser as a trusted device","devices.addSelfTitle":"Add this browser","devices.addSelfAddress":"Address to register: {origin}","devices.cookieRequired":"The browser did not save the trusted-device credential. Allow cookies and retry.","devices.trustedOrigin":"Trusted access address","devices.accessSection":"Trusted address protection","devices.publicUrlLabel":"Primary domain","devices.publicUrlInfo":"Set in setup → Connection → your connection type → Public URL. This page only shows it.","devices.previewDomainLabel":"Preview domain","devices.previewDomainInfo":"Set in setup → Web preview → Web preview proxy domain. handmux automatically allows its dynamic subdomains.","devices.originConfigured":"Configured in setup; cannot be edited here","devices.originBuiltIn":"Allowed automatically by handmux","devices.originUnset":"Not set","devices.originActive":"In effect","devices.originPending":"Not configured; register external addresses with the CLI or authorize a device from them","devices.originHint":"Public URL comes from setup and is read-only here. Leave it blank when you do not use a fixed public entry; local/LAN access remains available, while external hosts must be listed below or use the dynamic preview domain.","devices.originCommands":"Trusted access address commands","devices.originSetupCommandLabel":"Configure","devices.extraOriginsTitle":"Trusted domain","devices.trustedOriginLabel":"Trusted domain {n}","devices.extraOriginsHint":"Addresses are registered by device authorization or managed with the CLI. Wildcards such as https://*.example.com are supported.","devices.extraOriginInput":"Additional trusted domain","devices.extraOriginAdd":"Add domain","devices.removeOriginTitle":"Delete trusted domain","devices.removeOriginImpact":"These active devices will no longer be able to use this address:","devices.removeOriginCurrentImpact":"This includes the current device. It will lose access after deletion and must be authorized again.","devices.removeOriginNoImpact":"No active device is currently using this address. Delete it?","devices.removeOriginConfirm":"Delete","devices.invalidOrigin":"Enter a complete http(s) address such as https://*.example.com. The wildcard must be the left-most subdomain.","devices.originLimit":"You have reached the limit for additional trusted domains. Remove one before adding another.","devices.originMismatch":"This address is not an allowed entry point. Open handmux through the primary URL, dynamic preview domain, or a registered address; to register one, run handmux auth address add <origin>.","devices.addSelfOrigin":"This will add {origin} to the trusted entry points after authorization.","devices.cliOnly":"Change the trusted access address with the handmux CLI on the server.","devices.current":"This device","devices.add":"Add a device","devices.authorizeOther":"Authorize another device","devices.history":"Device history ({n})","devices.activeTab":"Active","devices.historyTab":"History","devices.activeStatus":"Can sign in","devices.detailInfo":"Device information","devices.deviceInfo":"Device","devices.status":"Status","devices.detailActions":"Device actions","devices.noActive":"No active devices.","devices.activeDevices":"‹ Active devices","devices.noHistory":"No past devices.","devices.name":"Device name","devices.expire":"Authorization duration","devices.keep":"Keep current expiry","devices.custom":"Custom","devices.never":"No expiry","devices.customDuration":"Positive number + m / h / d, or never","devices.keepHint":"Keeping the current expiry does not extend authorization.","devices.expireFromSave":"The selected duration starts when these changes are saved.","devices.id":"Device ID","devices.copyId":"Copy ID","devices.browser":"Browser","devices.added":"Added","devices.lastAccess":"Last access","devices.expiresAt":"Expires","devices.revoked":"Unbound","devices.expired":"Expired","devices.daysRemaining":"{n} days left","devices.hoursRemaining":"{n} hours left","devices.minutesRemaining":"{n} minutes left","devices.logout":"Sign out this device","devices.revoke":"Remove device","devices.revokeDescription":"“{name}” will lose access immediately and must pair again. Running terminal tasks will continue.","devices.conflict":"This device changed elsewhere. Refresh its details and reapply your changes.","devices.refreshDetails":"Reload latest details","devices.inactive":"This device has expired or been removed. Pair it again to restore access.","devices.sessionInvalid":"This browser is no longer authorized. Reload handmux and pair again.","devices.invalidName":"Use a device name with 1–80 characters and no control characters.","devices.nameTaken":"That device name is already in use. Choose another name.","devices.saved":"Saved.","devices.invalidExpire":"Use a positive duration such as 1h, 7d, or never.","devices.expiryCliOnly":"Change the authorization duration with the handmux CLI on the server.","devices.invalidCode":"Enter the new browser’s current 6-digit code. Expired or used codes cannot be reused.","devices.pairingGone":"This pairing was canceled or expired. Ask the new browser for another code.","devices.requestError":"Unable to confirm the operation. Check the connection and retry; no successful change has been confirmed.","devices.code":"One-time code","devices.codeHint":"Enter the 6-digit code shown on the new device. Verification starts automatically.","devices.verifyingCode":"Verifying…","devices.configureTitle":"Set up new device","devices.approvalOrigin":"Access address","devices.claim":"Confirm pairing","devices.complete":"Complete adding","devices.newCode":"Enter a new code","auth.methodLabel":"Authorization method","auth.webMethod":"Trusted device","auth.webInstructions":"On a phone or computer already signed in to this same handmux instance, open:","auth.webPath":"Settings → Authentication & security → Add a device with a one-time code","auth.webNext":"Enter the code above and confirm pairing. Set the new device’s name and expiry, then complete adding. This page will sign in automatically.","auth.webFallback":"No trusted device available? Switch to Computer CLI.","auth.title":"Authorize this browser","auth.waiting":"Waiting for authorization","auth.deviceRequired":"Device authorization required","auth.preparingCode":"Preparing a verification code…","auth.deviceAuthorizationHint":"After your Token is checked, authorize this browser once.","auth.verificationCode":"Authorization code","auth.authorizeWithDevice":"On an authorized device, open Authentication & security and enter this code.","auth.authorizeWithCli":"On the computer running handmux, run","auth.cliAfterCode":"then enter this code when prompted.","auth.chooseOneMethod":"Choose one way to authorize this browser","auth.cliMethodTitle":"Computer CLI authorization","auth.deviceMethodTitle":"Authorize from another device","auth.paired":"Paired successfully","auth.pending":"Confirmed. Finishing authorization…","auth.finishCli":"Finish device setup in the terminal.","auth.finishWeb":"Finish device setup on the trusted device.","auth.setupRemaining":"{seconds}s left to complete settings","auth.codeRemaining":"{seconds}s remaining","auth.codeExpired":"Expired. Generate a new code.","auth.expired":"The code expired. Generate a new one.","auth.canceled":"Authorization was canceled. Generate a new code.","auth.request":"Request device authorization","auth.requestNewCode":"Generate new code","auth.refreshCode":"Refresh","auth.cancelPairing":"Cancel pairing","auth.copyCode":"Copy code","auth.copyCommand":"Copy command","auth.copied":"Copied","auth.manualCopy":"Text selected. Long-press or use Ctrl/Cmd+C to copy.","auth.cliMethod":"Computer CLI","auth.cliInstructions":"On the computer running this handmux instance, run the command below as the same OS user, using a direct terminal or independent SSH session. It opens the interactive authorization flow.","auth.cliNext":"Enter the 6-digit code shown on this page, then set the device name and expiry. This page will log in automatically after saving. Automation should use the --code, --name, and --expire flags.","auth.browserScope":"Authorization is saved for this browser and access address. Changing the address requires pairing again.","auth.antiPhishing":"Only authorize a browser you are adding yourself. Never enter a code sent by someone else.","auth.httpWarning":"For better protection of sensitive access, use HTTPS or a trusted encrypted network whenever possible.","auth.tokenWarning":"The Token is always required. Device authorization is also required when device protection is on.","auth.dualRequirement":"The Token is always required. Device authorization is also required when device protection is on.","auth.tokenRequired":"Enter the current Token before requesting device authorization.","auth.tokenInvalid":"The Token is not correct. Enter it again to continue.","auth.connectionError":"Unable to check authorization. Check your network and whether handmux is running, then retry. Your authorization has not been canceled.","auth.originRejected":"This address is not a trusted entry point.","auth.originRejectedTitle":"Untrusted address","auth.originRejectedAddress":"Current address {origin} is not a trusted entry point","auth.originRejectedOpenLabel":"Open a trusted entry point","auth.originRejectedOpenHint":"Use the primary URL, dynamic domain, or an authorized access domain to open this page","auth.originRejectedAuthorizeLabel":"Authorize again","auth.originRejectedAuthorizeHint":"Use another trusted device or the handmux CLI to authorize this access address","auth.originRejectedAuthorizeButton":"Request access","auth.originRejectedRetry":"Check again","auth.retry":"Retry","auth.rateLimit":"Too many authorization attempts. Wait a minute before requesting another code.","auth.logoutTitle":"Unbind and sign out","auth.logoutDescription":"This browser will lose access immediately and must pair again to log in. Running terminal tasks will continue.","auth.logoutError":"Unbinding could not be confirmed. Check the connection and retry; this device may still be authorized.","terminal.disconnected":"Connection lost. Reconnecting…","terminal.paneMissing":"This pane has closed. Switch to another pane.","terminal.transport_live":"Live","terminal.transport_snapshot":"Snapshot","terminal.transport_detail_title":"Terminal delivery","terminal.transport_detail_configured":"Configured","terminal.transport_detail_current":"Current","terminal.transport_detail_connection":"Connection","terminal.transport_detail_manual":"Snapshot pulling was selected manually and will not switch automatically.","terminal.transport_detail_live":"The terminal is receiving live pushes normally.","terminal.transport_detail_fallback":"Live pushing became unstable, so Handmux fell back to snapshot pulling.","terminal.transport_detail_unavailable":"The live channel could not connect. Check whether your proxy supports WebSocket upgrades.","terminal.transport_detail_waiting":"Waiting for the connection to become stable before retrying live pushing.","terminal.transport_detail_retry":"About {seconds}s until Handmux attempts to restore live pushing.","terminal.connection_connecting":"Checking","terminal.connection_good":"Good","terminal.connection_degraded":"Fair","terminal.connection_poor":"Poor","common.save":"Save","common.cancel":"Cancel","common.confirm":"Confirm","common.ok":"OK","common.close":"Close","common.delete":"Delete","common.undo":"Undo","common.copy":"Copy","common.rename":"Rename","common.create":"Create","common.back":"Back","common.open":"Open","common.loading":"Loading…","common.done":"Done","common.retry":"Try Again","common.continue":"Continue","conversationCopy.line":"Line","conversationCopy.paragraph":"Paragraph","app.browser":"Web preview","browser.openTabs":"Open web preview tabs","browser.history":"Recently Visited","browser.closeTab":"Close {title}","browser.newTab":"New tab","browser.minimize":"Minimize","browser.back":"Back","browser.forward":"Forward","browser.address":"Address","browser.addressPlaceholder":"Enter a URL or port","browser.addressOrDirectoryPlaceholder":"Enter a URL, or choose a folder","browser.refresh":"Refresh","browser.stop":"Stop loading","browser.viewMode":"Page width","browser.narrowWidth":"Narrow","browser.wideWidth":"Wide","browser.closeTiming":"Close background tabs","browser.minutes":"{value} minutes","browser.neverClose":"Never close","browser.clearHistory":"Clear","browser.emptyHistory":"No recent visits yet","browser.loadFailed":"This page could not be loaded. Check the address and try again.","browser.retry":"Retry","browser.consentTitle":"Web Preview","browser.consentBody":"Handmux embeds pages in this window. It is not a full browser; use it to preview development servers, localhost, intranet sites, and websites that allow embedding. You can also choose a static folder on the computer from Home.","browser.consentComputer":"Connection: Direct uses your phone network. Computer proxy requests originate from your computer and can reach its intranet and localhost without publishing them.","browser.consentPrivate":"Sign-ins: Direct and proxy use separate Cookies and sign-in state. Proxy sessions are also isolated to this device.","browser.consentLimits":"Compatibility: Direct may be blocked by a site’s iframe or CSP policy, and Handmux may not know why. Computer proxy forwards and rewrites pages but cannot guarantee every site. For full browsing, use Safari, Chrome, or your system browser.","browser.consentIdle":"Background tabs: They close after 10 minutes by default. Direct-site Cookies remain in your phone browser.","browser.about":"About Web Preview","browser.acknowledge":"Got it","browser.directMode":"Direct from phone","browser.proxyMode":"Through computer proxy","browser.directBadge":"Direct","browser.proxyBadge":"Proxy","browser.staticBadge":"Static","browser.chooseDirectory":"Choose directory","browser.staticOpening":"Opening directory…","browser.directoryPickerHint":"Choose the directory containing the web files.","browser.switchMode":"Switch browsing mode","browser.menu":"Web preview menu","browser.connectionMode":"Connection","browser.pageWidth":"Page width","browser.requestSiteVersion":"Ask website for","browser.mobileSite":"Mobile","browser.desktopSite":"Desktop","browser.zoomPage":"Zoom page","browser.resetZoom":"Reset page zoom","browser.proxyLogin":"Proxy sign-in","browser.proxyLoginHelpLabel":"About proxy sign-in","browser.proxyLoginHelp":"Whether to encrypt and store proxy Cookies on the computer running Handmux so sign-ins survive a restart.","browser.siteProxyCookie":"This site’s proxy Cookies","browser.siteCookieHelpLabel":"About this site’s proxy Cookies","browser.siteCookieHelp":"This clears only proxy Cookies on this device that match the site’s real URL. Parent-domain Cookies may sign you out of related internal sites. Direct-site Cookies are unaffected.","browser.openMode":"Choose how to open","browser.historyMore":"More opening options","browser.historyActions":"More actions","browser.proxyLimitHint":"Computer proxy mode forwards and rewrites pages and may not work with every website.","browser.proxyUnavailable":"Run handmux setup on the computer and choose “Web preview” to configure its proxy domain. Until then, only Direct mode is available.","browser.urlInvalid":"Enter a valid HTTP or HTTPS address.","browser.tryProxy":"Try computer proxy","browser.openExternal":"Open in system browser","browser.clearSiteLogin":"Clear this site’s proxy Cookies","browser.clearAllLogin":"Clear all proxy Cookies","browser.clearSiteLoginConfirm":"Clear this site’s proxy login on the current device? Parent-domain Cookies may also affect related internal systems.","browser.clearAllLoginConfirm":"Clear every proxy login on the current device? Direct-site logins are not affected.","browser.deleteHistoryEntry":"Delete this record","browser.profileSaveFailed":"Could not save proxy login settings. Check the server connection and try again.","browser.profileClearFailed":"Cleanup was not fully successful. Check the server connection and storage permissions, then try again.","browser.profileSyncFailed":"Proxy login settings could not be synchronized. Retry or use Direct mode.","browser.profileRecoveryWarning":"Saved proxy login data could not be recovered and was reset on this device.","browser.retention1":"1 day","browser.retention7":"7 days","browser.retention30":"30 days","browser.retentionNotSaved":"Not saved","browser.retentionNever":"Long-term storage","settings.browserPersistLogin":"Persist proxy Cookies on the computer","settings.browserPersistLoginHint":"Stored only for this device. Turning this off keeps current tabs and login state until they are cleared or expire.","settings.browserRetention":"Proxy login retention","settings.browserDisablePersistConfirm":"Stop saving future proxy login changes on the current device? Current tabs and login state stay available.","token.title":"Sign in to handmux","token.placeholder":"Enter Token","settings.language":"Language","settings.browserDefaultMode":"Default web mode","settings.browserDefaultModeHint":"Used for new address-bar tabs and recent visits without a saved mode.","settings.browserEnabled":"Web preview","settings.browserEnabledHint":"Tabs belong to this device. Turning this off closes all tabs but keeps recent visits.","home.empty":"No files opened yet","home.emptyHint":'Switch to "New" to pick one',"home.remove":"Remove","drawer.title":"Sessions","drawer.empty":"No sessions bound yet","drawer.unbind":"Unbind","drawer.bind":"Bind session","drawer.logout":"Log out","windowbar.newWindow":"New window","rename.new_name":"New name","rename.name_rule":"Letters, digits, hyphens only (≤16)","rename.failed":"Rename failed, please retry","rename.saving":"Saving…","newwindow.title":"New window","newwindow.window_name":"Window name (optional)","newwindow.name_placeholder":"Leave blank to auto-name · letters/digits/hyphens ≤16","newwindow.name_rule":"Letters, digits, hyphens only (≤16)","newwindow.start_dir":"Start directory","newwindow.session_dir_named":"{dir} (session dir)","newwindow.session_dir_default":"Session dir (default)","newwindow.choose":"Choose","newwindow.reset_to_session_dir":"Reset to session dir","newwindow.creating":"Creating…","startup.label":"Startup command (optional)","startup.aria":"Startup command","startup.preset_shell":"Plain shell (default)","startup.preset_claude":"claude (launch Claude Code)","startup.preset_claude_continue":"claude -c (resume last session)","startup.preset_codex":"codex (launch Codex CLI)","startup.custom":"Custom…","startup.custom_placeholder":'e.g. claude "fix login bug"',"bind.title":"Bind session","bind.sessionName":"Session name","bind.pickSession":"Choose a session to bind","bind.newSession":"+ New session","bind.modeNew":"New","bind.modeExisting":"Existing","bind.alreadyExists":"Session already exists","bind.bind":"Bind","bind.checking":"Checking…","bind.createAndOpen":"Create & open","bind.creating":"Creating…","bind.createHint":`Session "{name}" doesn't exist — tap "Create & open" to create it`,"bind.alreadyBound":"Session already bound","bind.createFailed":"Create failed, please retry","bind.invalidName":"Only letters, digits, hyphens (≤16)","bind.desktopHint":"On the computer, one command takes any session here back over: handmux open <name>","bind.checkFailed":"Check failed, please retry","bind.startDir":"Start directory","bind.homeDirDefault":"Home directory (default)","bind.choose":"Choose","bind.reset":"Reset","actionsheet.confirmAgain":"Confirm? Tap again","dirpicker.title":"Choose directory","inbox.title":"Inbox","inbox.working":"Working","inbox.done":"Done","inbox.needs":"Needs you","inbox.error":"Error","inbox.clearDone":"Clear results","inbox.empty":"No pane status yet","inbox.reconnecting":"Reconnecting to the inbox…","inbox.enableTitle":"Turn on Claude Code states and notifications","inbox.enableHint":"The Claude Code inbox requires Agent hooks. For Codex CLI, use Handmux managed mode.","inbox.enableBtn":"Enable","inbox.enabling":"Enabling…","inbox.enableFailed":"Could not enable — check the server logs.","drawer.orphans.title":"{n} not taken over","drawer.orphans.hint":"Take over to control remotely","inbox.orphans.takeover":"Take over","inbox.orphans.noSession":"no resumable history","inbox.orphans.busy":"busy","inbox.orphans.idle":"idle","inbox.orphans.working":"Taking over…","inbox.orphans.failed":"Takeover failed","inbox.orphans.targetLabel":"Take over into","inbox.orphans.targetNew":"New session","inbox.orphans.nameLabel":"Session name","inbox.orphans.namePlaceholder":"session name","inbox.orphans.killTitle":"The original process","inbox.orphans.killEnd":"End it","inbox.orphans.killKeep":"Keep it","inbox.orphans.recommended":"Recommended","inbox.orphans.killWhy":"If the same session is written from both your computer and your phone, its history gets scrambled. Ending the original lets this device own it cleanly.","inbox.orphans.reopenPre":"Want to continue on the computer instead? Run in a terminal:","idea.title":"Ideas","idea.editPlaceholder":"Edit idea…","idea.addPlaceholder":"Jot an idea…","idea.add":"Add","idea.empty":"No ideas yet — jot one down","idea.dragSort":"Drag to reorder","idea.fillInput":"Fill into input","idea.send":"Send","doclink.title":"Open file","localurl.title":"Open website","localurl.open":"Open in Browser","localurl.notListening":"Nothing is listening on :{port}.","localurl.badProtocol":"This link is not a proxyable HTTP or HTTPS address.","localurl.network":"Could not reach the handmux service. Check your connection and try again.","localurl.failed":"Could not open this website. Check the address and try again.","changelog.title":"What's new","preview.static":"Static preview","preview.tabs":"Open previews","preview.remainTitle":"Time left — tap to renew / stop","preview.toPcView":"Switch to desktop view","preview.toMobileView":"Switch to mobile view","preview.pcView":"Desktop view","preview.mobileView":"Mobile view","preview.refresh":"Refresh","preview.minimize":"Minimize","preview.ttlDialog":"Preview lifetime","preview.renew":"Renew (reset to 1 hour)","preview.stop":"Stop preview","preview.iframeTitle":"Preview","preview.zoomOut":"Zoom out","preview.zoomIn":"Zoom in","imageviewer.loadFailed":"Failed to load image","imageviewer.saved":"Saved — find it in your album/gallery or Downloads","imageviewer.shareUnsupported":"Image sharing requires Chrome or Safari","imageviewer.zoomOut":"Zoom out","imageviewer.zoomIn":"Zoom in","imageviewer.imageTitle":"Image","imageviewer.saveImage":"Save image","imageviewer.shareImage":"Share image","mic.stop":"Stop voice input","mic.start":"Voice input","mic.recognizing":"Recognizing speech","mic.error.tencentPermission":"Tencent Cloud rejected recognition. Grant the current SecretId the asr:SentenceRecognition permission, then try again.","mic.error.tencentCredentials":"The Tencent Cloud credentials are invalid. Check AppId, SecretId, and SecretKey in handmux setup.","mic.error.browserPermission":"Microphone access is blocked. Allow it in this site's browser settings, then try again.","mic.error.device":"The microphone is unavailable. Check that it exists and is not in use by another app.","mic.error.secureContext":"This address cannot access the microphone. Open Handmux over HTTPS or localhost.","mic.error.tooLong":"The recording is too long. Record a shorter message and try again.","mic.error.notSelected":"The selected voice mode is not active. Restart Handmux and try again.","mic.error.noSpeech":"No speech was recognized. Please try again.","mic.error.network":"Could not reach the speech service. Check the network and try again.","mic.error.provider":"The speech service rejected the request: {reason}","mic.error.generic":"Voice input failed. Please try again.","dock.send":"Send","dock.send.hint":"Tap to send · hold to insert","dock.phrases":"Phrases","dock.attach":"Upload","dock.history":"History","dock.kbdShow":"Keyboard","dock.kbdHide":"Hide keyboard","history.empty":"No history yet","history.scope":"This window only","dock.input.placeholder":"Say something…","dock.input.enterDraft":"Press Shift + Enter to enter draft mode","dock.input.exitDraft":"Press Esc to return to terminal mode · Shift + Enter for a new line","dock.command.placeholder":"Type a command · Enter runs it","dock.mode.agent":"Chat","dock.mode.toggle":"Switch input mode","dock.mode.command":"Command","dock.mode.chat":"Chat","fav.title":"Favorites","fav.add":"Add","fav.addPlaceholder":"Add a favorite…","cmd.editTitle":"Saved commands","cmd.global":"GLOBAL","cmd.window":"THIS WINDOW","cmd.withEnter":"Send directly","cmd.configPresets":"Config presets","cmd.removeDevice":"Remove from this device","cmd.removedDevice":"Removed from this device","cmd.addPlaceholder":"Add a command…","cmd.tabCmd":"Command","cmd.tabKey":"Key","cmd.addTo":"Add to","cmd.addTitle":"Add","cmd.added":"Added","cmd.editItem":"Edit","cmd.sticky":"Modifier","cmd.stickyNone":"None","cmd.baseKey":"Key","cmd.pickKey":"Pick a key","cmd.moveUp":"Move up","cmd.moveDown":"Move down","chat.editTitle":"Saved messages","chat.composer.placeholder":"Message the agent…","chat.historyPulling":"Loading earlier messages…","agentConversation.empty":"Start a conversation with this agent.","agentConversation.unavailable":"Unable to connect to the conversation","agentConversation.reconnecting":"Reconnecting to the live conversation…","agentConversation.reloadRequired":"The Pi conversation integration was updated. Switch to the terminal, run /reload, then return here.","agentConversation.loadOlder":"Load earlier messages","agentConversation.loadOlderFailed":"Earlier messages could not be loaded. Please try again.","agentConversation.reasoning":"Reasoning summary","agentConversation.toolResult":"Tool result","agentConversation.diff":"Changes","agentConversation.attachment":"Attachment","agentConversation.attachmentFailed":"The attachment could not be downloaded. Please try again.","agentConversation.truncated":"Some content was truncated.","agentConversation.interactionTerminal":"Complete this action in the terminal.","agentConversation.interactionUnavailable":"This request is temporarily unavailable in chat.","agentConversation.interactionCommandApproval":"Allow this command?","agentConversation.interactionFileApproval":"Allow file changes?","agentConversation.interactionPermissionApproval":"Allow the requested permissions?","agentConversation.interactionInputRequest":"Additional input is required","agentConversation.interactionReason":"Reason","agentConversation.interactionCommand":"Command","agentConversation.interactionWorkingDirectory":"Working directory","agentConversation.interactionContext":"Context","agentConversation.interactionOther":"Enter another answer","agentConversation.interactionPlaceholder":"Enter an answer","agentConversation.openTerminal":"Open Terminal","chat.stop":"Stop","chat.stopTitle":"Stop the current task?","chat.stopBody":"The turn currently in progress will be interrupted.","chat.config.open":"Configure model, service tier, and reasoning effort","chat.config.title":"Model settings","chat.config.model":"Model","chat.config.effort":"Reasoning effort","chat.config.fast":"Fast","chat.config.fastHint":"Use the faster service offered by this model","chat.config.loading":"Loading available models…","chat.config.empty":"No models are available","chat.config.chooseModel":"Choose an available model first","chat.config.loadFailed":"Could not load the model list","chat.config.refresh":"Refresh model list","chat.config.saveFailed":"The setting could not be saved","chat.config.nextTurn":"The current response stays unchanged; this applies to your next message.","chat.goal.title":"Task goal","chat.goal.objective":"Goal objective","chat.goal.placeholder":"Describe a goal Codex should keep working toward","chat.goal.loading":"Loading the current goal…","chat.goal.loadFailed":"Could not load the current goal","chat.goal.saveFailed":"The goal could not be saved","chat.goal.clearFailed":"The goal could not be cleared","chat.goal.tooLong":"A task goal can contain at most 4,000 characters","chat.goal.created":"Task goal set","chat.goal.updated":"Task goal updated","chat.goal.paused":"Task goal paused","chat.goal.resumed":"Task goal resumed","chat.goal.restarted":"Task goal restarted","chat.goal.cleared":"Task goal cleared","chat.goal.edit":"Edit","chat.goal.pause":"Pause","chat.goal.resume":"Resume","chat.goal.restart":"Restart","chat.goal.clear":"Clear","chat.goal.clearConfirmTitle":"Clear this task goal?","chat.goal.clearConfirmBody":"The current task goal will be deleted and Codex will stop tracking it. Its historical chat card will remain.","chat.goal.statusActive":"Active","chat.goal.statusPaused":"Paused","chat.goal.statusBlocked":"Blocked","chat.goal.statusComplete":"Complete","chat.goal.statusUsageLimited":"Usage limited","chat.goal.statusBudgetLimited":"Budget limited","chat.goal.eventSet":"Goal set","chat.goal.eventRestarted":"Goal restarted","chat.goal.eventComplete":"Goal complete","chat.goal.eventBlocked":"Goal blocked","chat.goal.eventUsageLimited":"Goal ended: usage limited","chat.goal.eventBudgetLimited":"Goal ended: budget limited","chat.goal.tokens":"Tokens {value}","chat.goal.elapsed":"Elapsed {value}s","chat.plan.currentTitle":"Current tasks","chat.plan.historyTitle":"Turn tasks","chat.plan.working":"Working on: {step}","chat.plan.waiting":"Waiting for confirmation: {step}","chat.plan.finalizing":"Preparing the result","chat.plan.complete":"Completed","chat.plan.incomplete":"Incomplete","chat.plan.status.pending":"Pending","chat.plan.status.inProgress":"In progress","chat.plan.status.completed":"Completed","chat.context.aria":"Context usage {percent}%","chat.context.unavailableAria":"Context status, usage temporarily unavailable","chat.context.title":"Context usage","chat.context.percent":"Context window used","chat.context.used":"Current tokens","chat.context.total":"Model total tokens","chat.context.usedTotal":"Used / total","chat.status.aria":"Session status, context usage {percent}%","chat.status.title":"Session status","chat.status.idle":"Idle","chat.status.working":"Working","chat.status.waitingApproval":"Waiting for approval","chat.status.waitingInput":"Waiting for input","chat.status.compacting":"Compacting","chat.compacting.live":"Compacting context","chat.status.directory":"Directory","chat.status.worktree":"Worktree","chat.status.branch":"Branch","chat.status.access":"Access","chat.status.permissionMode":"Permissions","chat.status.sessionId":"Session ID","chat.status.copyDirectory":"Copy directory","chat.status.copyWorktree":"Copy Worktree path","chat.status.copySession":"Copy session ID","chat.status.copied":"Copied","chat.status.sandboxReadOnly":"Read only","chat.status.sandboxWorkspace":"Workspace write","chat.status.sandboxFull":"Full access","chat.permissionMode.default":"Default","chat.permissionMode.autoReview":"Auto-review","chat.permissionMode.fullAccess":"Full Access","chat.permissionMode.custom":"Custom","chat.permissionMode.title":"Permissions","chat.permissionMode.open":"Set permissions, currently {value}","chat.permissionMode.defaultHint":"Read and edit this workspace and run commands; asks before using the internet or other locations.","chat.permissionMode.autoReviewHint":"Same access as Default; Codex automatically approves or denies requests for more access.","chat.permissionMode.fullAccessHint":"Access locations outside the workspace and the internet without asking; use only for trusted tasks.","chat.permissionMode.nextTurn":"Changes apply to your next message","chat.permissionMode.saved":"Permissions updated for your next message","chat.permissionMode.saveFailed":"Permissions could not be saved","chat.interrupted":"You stopped the response","chat.compacted":"Context compacted","chat.compaction.viewDetails":"View details","chat.compaction.title":"Context compaction","chat.compaction.complete":"Complete","chat.compaction.summary":"Summary retained by the agent","chat.compaction.unavailable":"No inspectable summary was provided for this compaction.","chat.compaction.truncated":"This summary was too long, so only the safely retained portion is shown.","chat.scroll.latest":"Jump to latest","chat.scroll.reloadLatest":"↓ Jump to latest","chat.scroll.answer":"↓ View latest answer","chat.scroll.bottom":"↓ Jump to bottom","chat.slash.unsupported":"This command is not supported in chat view yet","chat.session.unboundTitle":"This Codex chat could not be identified","chat.session.unboundHint":"Codex is still starting. The exact chat will appear automatically once it is available.","chat.session.openTerminal":"Open terminal","chat.session.notManaged":"Restart Codex in managed mode from the terminal first","chat.session.unmanagedTitle":"This Codex session is not managed","chat.session.unmanagedHint":"Restart it in managed mode from the terminal before opening chat.","chat.session.connectionHint":"Codex App Server is unavailable. Check that Codex is still running, then try again.","chat.managedGuide.title":"Connect this Codex chat","chat.managedGuide.hint":"Handmux can resume the original session in this pane and switch it to reliable managed chat.","chat.managedGuide.start":"Start managed mode","chat.managedGuide.submitting":"Starting…","chat.managedGuide.confirmTitle":"Start managed mode?","chat.managedGuide.confirmHint":"The current Codex process will end, including any task in progress. Resuming may require you to open the terminal and handle trust or another confirmation manually.","chat.managedGuide.confirmAction":"End and start managed mode","chat.managedGuide.startingTitle":"Starting managed mode","chat.managedGuide.startingHint":"Resuming the original session. Chat opens automatically when it is ready.","chat.managedGuide.terminalHint":"Startup has not finished. Codex may be waiting for trust or another confirmation in the terminal.","chat.managedGuide.timeoutTitle":"Managed mode is not ready","chat.managedGuide.timeoutHint":"Handmux has waited 30 seconds. Codex may need a manual confirmation in the terminal. This page will not switch automatically.","chat.managedGuide.manualTitle":"Continue in the terminal","chat.managedGuide.manualHint":"Codex did not exit normally or return verifiable recovery information. Open the terminal to inspect its current state.","chat.managedGuide.goneTitle":"This Codex has changed","chat.managedGuide.goneHint":"Handmux stopped to avoid ending the wrong process. Open the terminal to check its current state.","chat.managedGuide.unavailableTitle":"Could not verify this Codex session","chat.managedGuide.unavailableHint":"Try again, or open the terminal to continue.","chat.managedGuide.failedHint":"Managed startup could not finish. Try again or open the terminal to check its current state.","chat.managedGuide.recoveryHint":"The original session was verified. If automatic resume failed, run this in the terminal:","chat.managedGuide.copyRecovery":"Copy recovery command","chat.managedGuide.recoveryTitle":"Continue recovering this Codex chat","chat.managedGuide.recoveryReadyHint":"The previous takeover stopped before resume. It is safe to continue in this pane.","chat.managedGuide.recoveryManualHint":"Handmux cannot verify that automatic resume is still safe. Copy the command or open the terminal.","chat.managedGuide.recoveryStaleTitle":"The original pane changed","chat.managedGuide.recoveryStaleHint":"To avoid sending into the wrong pane, only copy is available here.","chat.managedGuide.retryRecovery":"Continue recovery","chat.approval.request":"Codex needs confirmation","chat.approval.file":"Allow these file changes?","chat.approval.command":"Allow this command to run?","chat.approval.permissions":"Allow Codex to use additional permissions?","chat.approval.accept":"Allow once","chat.approval.acceptSession":"Always allow this session","chat.approval.acceptRule":"Allow and remember “{rule}”","chat.approval.allowHost":"Always allow access to {host}","chat.approval.denyHost":"Always deny access to {host}","chat.approval.decline":"Deny","chat.approval.cancel":"Deny and stop","chat.approval.failed":"The approval could not be submitted","chat.input.request":"Codex needs your answer","chat.input.step":"Question {current} of {total}","chat.input.other":"Other answer","chat.input.placeholder":"Enter your answer","chat.input.submit":"Submit answer","chat.input.failed":"The answer could not be submitted","chat.sendFailed":"The message could not be sent","chat.terminalDraftConflict":"The terminal has an unconfirmed draft. Handle it in the terminal, then retry.","chat.queue.terminalDraftConflict":"The terminal has an unconfirmed draft. Handle it there, then edit this message to retry.","chat.sendUnknown":"Delivery could not be confirmed. Check the conversation before trying again.","chat.stopFailed":"Could not stop the turn. Try again.","chat.queue.title":"Queued messages","chat.queue.hint":"Sent one by one after the current turn","chat.queue.steer":"Guide now","chat.queue.edit":"Edit queued message","chat.queue.editTitle":"Edit queued message","chat.queue.editPlaceholder":"Enter queued message","chat.queue.remove":"Delete queued message","chat.queue.removeTitle":"Delete this queued message?","chat.queue.removeBody":"This cannot be undone.","chat.queue.actionFailed":"The queued message could not be updated. Try again.","chat.queue.editExpired":"This edit expired. Close it and edit the message again.","chat.queue.editConflict":"This queued message changed elsewhere. Your draft is preserved; close it and review the latest version.","chat.queue.providerRejected":"Not sent. Edit to retry, or delete it.","chat.queue.unknownDelivery":"Delivery is unconfirmed and will not retry automatically.","chat.controls.actionFailed":"The setting could not be updated. Try again.","chat.config.serviceTier":"Service tier","chat.config.serviceTierDefault":"Default","chat.config.unavailable":"Model settings are temporarily unavailable. Try again.","agentConversation.interactionResponseFailed":"The response could not be sent. Try again or continue in the terminal.","chat.activation.title":"Open Conversation View?","chat.activation.body":"Handmux needs to restart this Agent in managed mode. The current conversation will continue in the same pane.","chat.activation.terminal":"Stay in Terminal","chat.activation.activating":"Preparing the current conversation…","chat.activation.waiting":"Waiting for the managed conversation to reconnect…","chat.activation.working":"Preparing…","chat.activation.stale":"This Agent changed before activation. Return to the terminal or try again.","chat.activation.timeout":"The Agent started, but Conversation View has not connected yet. You can continue in the terminal and try again later.","chat.activation.failed":"Conversation View could not be prepared. Continue in the terminal or try again.","chat.activation.unavailable":"This conversation cannot be switched safely right now. Continue in the terminal.","conversationTool.tool":"Tool","conversationTool.run":"Run command","conversationTool.runValue":"Run {value}","conversationTool.edit":"Edit file","conversationTool.editValue":"Edit {value}","conversationTool.write":"Write file","conversationTool.writeValue":"Write {value}","conversationTool.read":"Read file","conversationTool.readValue":"Read {value}","conversationTool.web":"Browse the web","conversationTool.image":"View image","conversationTool.imageValue":"View image {value}","conversationTool.wait":"Wait for task to finish","conversationTool.waitShort":"Wait for task","conversationTool.continue":"Continue running task","conversationTool.continueShort":"Continue task","conversationTool.search":"Search","conversationTool.searchValue":"Search {value}","conversationTool.find":"Find files","conversationTool.findValue":"Find files {value}","conversationTool.webSearch":"Search the web","conversationTool.webSearchValue":"Search the web {value}","conversationTool.webRead":"Read webpage","conversationTool.webReadValue":"Read webpage {value}","conversationTool.todo":"Update tasks","conversationTool.skill":"Activate skill","conversationTool.skillValue":"Activate skill {value}","conversationTool.agent":"Call Agent","conversationTool.agentValue":"Call Agent {value}","conversationTool.call":"Call tool","conversationTool.callValue":"Call tool {value}","conversationTool.diffStat":"{added} lines added, {removed} removed","conversationTool.declined":"Declined","conversationTool.completed":"Finished","conversationTool.failed":"Failed","conversationTool.success":"Succeeded","conversationTool.running":"Running","conversationTool.runningEllipsis":"Running…","conversationTool.noReturn":"No response","conversationTool.createdFile":"Created file · {added} lines added","conversationTool.noChanges":"No changes to display","conversationTool.mode":"Execution mode","conversationTool.command":"Command","conversationTool.output":"Output","conversationTool.imagePathMissing":"No resolvable image path provided","conversationTool.imageUnavailable":"Unable to read the image. Check the file and read permissions.","conversationTool.noOutput":"No output","conversationTool.truncation.input.sizeLimit":"This input was long, so only the safely retained portion is shown. The tool ran with the complete input.","conversationTool.truncation.output.sizeLimit":"This output was long, so only the safely retained portion is shown. Tool execution was not affected.","conversationTool.truncation.diff.sizeLimit":"These changes were long, so only the safely retained portion is shown. The actual changes were not affected.","conversationTool.truncation.provider_truncated":"The Agent returned this content already truncated, so this record may be incomplete.","conversationTool.truncation.redacted":"Sensitive content was hidden.","conversationTool.truncation.unavailable":"This part of the tool record is temporarily unavailable.","chat.outgoing.sending":"Sending","chat.outgoing.queued":"Queued","chat.outgoing.sent":"Sent","chat.outgoing.steered":"Guided","chat.outgoing.failed":"Failed to send","chat.outgoing.unknown":"Delivery not confirmed","chat.outgoing.retry":"Retry","chat.outgoing.retryUnknown":"Check status","chat.outgoing.resendTitle":"Send this message again?","chat.outgoing.resendBody":"This message may already have been delivered. Continuing sends it as a new message and may run the task twice.","chat.outgoing.resendConfirm":"Send Anyway","chat.favs":"Saved","chat.tabMsg":"Message","chat.addPlaceholder":"Message / slash-command…","dock.upload.aria":"Upload file","dock.upload.title":"Upload file (saved to home upload area, not the project)","dock.upload.progress":"Uploading {name}{tag}","dock.upload.failed":"Upload failed: {names}","dock.upload.rejected":"Unsupported file type: {names}","app.nameExists":"That name already exists","app.renameFailed":"Rename failed, please retry","app.deleteFailed":"Delete failed, please retry","app.moveFailed":"Move failed, please retry","app.sessionGone":'Session "{name}" not found, it may have closed',"app.docNotFound":"File not found","app.docTooLarge":"File too large (over 2MB)","app.docUnsupported":"Unsupported file or path","app.docOpenFailed":"Open failed, please retry","app.preview":"Preview","app.openPreview":"Open preview","app.ideas":"Ideas","app.files":"Files","app.settings":"Settings","usage.title":"Usage","usage.subscriptionTab":"Subscriptions","usage.apiTab":"API","usage.win5h":"5-hour","usage.winWeekly":"Weekly","usage.winMonthly":"Monthly","usage.winGeneric":"{h}h window","usage.winPrimary":"Limit","usage.winSecondary":"Secondary","usage.accountQuota":"Account limits","usage.modelLimits":"Model-specific limits","usage.accountApiKey":"API key account","usage.resetIn":"resets in {t}","usage.resetSoon":"resetting…","usage.resetCredits":"Rate-limit resets","usage.resetCreditsCount":"{n} available","usage.resetCreditExpires":"Expires {time}","usage.claudeOff":"Not wired yet — Claude's 5h/weekly usage needs the handmux statusLine:","usage.claudePending":"No data yet — send a message in a Claude session, then reopen.","usage.codexOff":"Codex not detected on this machine.","usage.codexNoQuota":"Codex has not returned quota data yet.","usage.setupRequired":"Usage collection is not connected yet.","usage.pending":"No quota data yet. Send a message in the Agent, then reopen.","usage.unavailable":"No usage data is currently available on this machine.","usage.loadFailed":"Failed to load usage.","usage.refresh":"Refresh","usage.refreshing":"Refreshing…","usage.refreshFailed":"Subscription usage could not be refreshed. Check the connection and try again.","usage.updatedNow":"updated just now","usage.updatedMin":"updated {n}m ago","usage.updatedHr":"updated {n}h ago","usage.updatedDay":"updated {n}d ago","usage.updatedCompactNow":"now","usage.updatedCompactMin":"{n}m","usage.updatedCompactHr":"{n}h","usage.updatedCompactDay":"{n}d","usage.timeMark":"Time elapsed in this window","usage.menu":"{provider} usage options","usage.show":"Show usage","usage.hide":"Hide usage","apiBalance.title":"API balances","apiBalance.add":"Add API","apiBalance.menu":"Account actions","apiBalance.menuAccount":"{account} ({provider}) account actions","apiBalance.official":"official data","apiBalance.available":"API available","apiBalance.insufficient":"Insufficient balance","apiBalance.notQueried":"Balance not queried yet","apiBalance.noBalanceData":"No balance data","apiBalance.currencyAvailable":"{currency} available balance","apiBalance.toppedUp":"Topped up","apiBalance.granted":"Granted","apiBalance.cash":"Cash balance","apiBalance.voucher":"Voucher balance","apiBalance.refreshing":"Refreshing…","apiBalance.refresh":"Refresh","apiBalance.rename":"Rename","apiBalance.replaceCredential":"Replace credential","apiBalance.deleteConfirm":"Delete this account? Tap again","apiBalance.empty":"No APIs added yet","apiBalance.emptyHint":"Add an API to see official provider balance data.","apiBalance.addAccount":"Add API account","apiBalance.storageNote":"API keys are encrypted on the computer running Handmux. Full keys are never returned to the browser.","apiBalance.account":"Account","apiBalance.provider":"Provider","apiBalance.chooseProvider":"Choose provider","apiBalance.name":"Name","apiBalance.credentialNote":"API keys are encrypted on the computer running Handmux. Full keys are never returned to the browser.","apiBalance.secureRequired":"Open Handmux over HTTPS or on localhost to submit credentials.","apiBalance.verifySave":"Verify & Save","apiBalance.verifying":"Verifying…","apiBalance.form.add":"Add API","apiBalance.form.rename":"Rename API","apiBalance.form.credential":"Replace credential","apiBalance.loadFailed":"API balances could not be loaded. Try again.","apiBalance.refreshFailed":"The balance could not be refreshed. Try again.","apiBalance.saveFailed":"The account could not be saved. Check the connection and try again.","apiBalance.deleteFailed":"The account could not be deleted. Try again.","apiBalance.error.invalid_credential":"Credential invalid, not permitted, or provider verification is required · check the provider account and replace credential if needed","apiBalance.error.rate_limited":"Too many requests · try again later","apiBalance.error.provider_timeout":"Provider did not respond in time · try again","apiBalance.error.provider_unreachable":"Provider is temporarily unreachable · try again","apiBalance.error.unsupported_response":"Provider returned unsupported data · try again","apiBalance.error.storage_unavailable":"Saved API accounts are unavailable · do not clear these files or the accounts cannot be recovered. First back up ~/.handmux/api-accounts.json, api-accounts.key, .corrupt.*, and .unavailable; restore a matching api-accounts.key and api-accounts.json (recover the data file from .corrupt.* if needed), then remove .unavailable last and restart Handmux","apiBalance.error.conflict":"The account changed elsewhere · reopen it and try again","apiBalance.error.account_limit_reached":"Up to 1,000 API accounts can be saved · delete an unused account and try again","apiBalance.error.not_found":"The account was deleted elsewhere · close this window and refresh","app.renameSession":"Rename session","app.renameWindow":"Rename window","app.manageWindow":"Window Management","app.moveLeft":"◀ Move left","app.moveRight":"Move right ▶","app.deleteWindow":"Delete window","pane.splitH":"Split left/right","pane.splitV":"Split top/bottom","pane.manage":"Manage split","pane.manageTitle":"Split Management","pane.close":"Close pane","pane.closeConfirm":"Close? Tap again","pane.splitFailed":"Split failed","pane.closeFailed":"Close failed","resize.windowWidth":"Window width","resize.paneWidth":"Pane width","resize.columns":"{n} columns","resize.restore":"Restore","resize.restoreAutoWidth":"Restore automatic width","resize.restoreRatio":"Restore split ratio","app.deleteLastWindowConfirm":"This is the last window; deleting it closes the whole session! Tap again","app.deleteConfirm":"Delete? Tap again","app.cannotLocate":"Cannot locate","app.pickItsDir":", pick the directory it lives in:","app.noBoundSession":"No bound session yet","app.tapToBind":"Tap here to bind one","app.selectSessionHint":"Tap ☰ at the top-left to pick a session","app.backToExit":"Press Back again to exit","settings.title":"Settings","settings.group_global":"Global settings","settings.group_general":"General","settings.group_voice":"Speech to Text","settings.voice_enabled":"Enabled","settings.voice_on":"On","settings.voice_off":"Off","settings.voice_provider":"Current provider","settings.voice_profile_tencent_streaming":"Tencent Cloud real-time ASR","settings.voice_profile_tencent_sentence":"Tencent Cloud sentence ASR","settings.voice_profile_xfyun":"iFlytek voice dictation","settings.voice_not_configured":"Not configured","settings.voice_filler_filter":"Filler word filtering","settings.voice_filter_low":"Low","settings.voice_filter_medium":"Medium","settings.voice_filter_high":"High","settings.voice_not_supported":"Not supported","settings.voice_setup_hint":"Run handmux setup in your terminal, then open Voice input to configure it.","settings.project_task_beta":"Project Tasks Beta","project.root.projects":"Projects","project.root.sessions":"Sessions","project.add":"Add Project","project.archivedProjects":"Archived Projects ({n})","project.empty":"No projects yet","project.emptyHint":"Choose a local folder to start capturing requirements and tasks.","project.manage":"Project settings","project.tasks":"Tasks","project.drafts":"Drafts","project.noTasks":"No tasks yet","project.noDrafts":"No drafts yet","project.newTask":"New task","project.newDraft":"Capture draft","project.storeUnavailable":"Project data is temporarily unavailable","project.tryAgain":"Try again","project.task.title":"Title","project.task.objective":"Goal","project.task.acceptance":"Acceptance criteria (one per line)","project.task.scope":"Scope and non-goals","project.task.constraints":"Constraints","project.task.references":"References (one URL or path per line)","project.task.priority":"Priority","project.task.priority.none":"None","project.task.priority.high":"High","project.task.priority.medium":"Medium","project.task.priority.low":"Low","project.task.saveDraft":"Save draft","project.task.saveTask":"Save as task","project.task.save":"Save","project.task.edit":"Edit requirements","project.task.promote":"Convert to task","project.task.cancel":"Cancel task","project.task.archive":"Archive","project.task.cancelConfirm":"Canceled tasks become read-only and cannot return to the queue. Continue?","project.task.archiveConfirm":"Archived items leave the normal list but are not deleted. Continue?","project.task.discardConfirm":"Your unsaved changes will be lost. Go back anyway?","project.task.conflict":"This task changed on another page. Refresh it before confirming your edits again.","project.task.actionConflict":"This task changed on another page. The latest version is loaded; review its current state.","project.task.loadLatest":"Load latest","project.task.request":"What should be done?","project.task.requestPlaceholder":"Describe what you need","project.task.requestHint":"The first non-empty line becomes the title. The Agent organizes the remaining details when work starts.","project.task.create":"Create task","project.management.overview":"Overview","project.management.context":"Guidance & memory","project.management.git":"Git","project.management.memoryOff":"Project Memory is not enabled yet","project.management.readOnly":"Read-only","project.management.projectRoot":"Project folder","project.management.repositoryRoot":"Code repository","project.management.defaultAgent":"Default Agent","project.management.notSet":"Not set","project.management.isolation":"Task code location","project.management.execution.project-root":"Project folder","project.management.execution.worktree":"Isolated workspace","project.management.guidance":"Project guidance","project.management.guidanceFailed":"Could not read project guidance. Check folder permissions and retry.","project.management.noGuidance":"No AGENTS.md or CLAUDE.md was found in the project root.","project.management.memoryHint":"Project memory proposals and approvals will appear here later.","project.management.conflict":"This project changed on another page. The latest version is loaded; review it and retry.","project.management.notGit":"This is not a Git repository","project.management.notGitHint":"Tasks still work normally; code changes are simply unavailable here.","project.management.gitFailed":"Could not read Git status. Check the repository and retry.","project.management.gitClean":"The working tree has no uncommitted changes.","project.management.gitChanges":"{n} files have uncommitted changes","project.management.history":"Task history","project.management.canceled":"Canceled ({n})","project.management.archived":"Archived ({n})","project.management.historyEmpty":"Nothing here yet","project.management.historyFailed":"Could not load task history. Try again later.","project.management.archiveProject":"Archive Project","project.management.archiveConfirm":"The Project and its active tasks will leave the normal views, but no data will be deleted. Continue?","settings.group_terminal":"Terminal","settings.group_chat":"Chat","settings.group_notifications":"Notifications","settings.group_about":"About","settings.terminal_font_size":"Terminal font size","settings.terminal_font_decrease":"Decrease terminal font size","settings.terminal_font_increase":"Increase terminal font size","settings.terminal_font_auto":"Auto","settings.terminal_font_auto_title":"Auto-fit to height","settings.conversation_font_size":"Conversation font size","settings.conversation_font_decrease":"Decrease conversation font size","settings.conversation_font_increase":"Increase conversation font size","settings.conversation_font_default":"Reset to default","settings.conversation_font_hint":"Adjust from 10–20px in 1px steps; affects only conversation message text and its Markdown and code.","settings.keyboard_mode":"Keyboard mode","settings.keyboard_mode_auto":"Auto detect","settings.keyboard_mode_mobile":"Mobile","settings.keyboard_mode_desktop":"Desktop","settings.keyboard_mode_hint":"Applies only to this browser; override it if detection is wrong.","settings.terminal_transport":"Terminal delivery mode","settings.terminal_transport_live":"Live pushing","settings.terminal_transport_snapshot":"Snapshot pulling","settings.terminal_transport_hint":"Live pushing uses WebSocket for lower latency, falls back to snapshot pulling on a poor connection, and retries after 30 stable seconds.","settings.snapshot_interval":"Active refresh rate","settings.snapshot_interval_hint":"The terminal refreshes less often while idle to reduce traffic and resource use.","settings.conversation_view_agent":"{agent} Conversation View","settings.experimental":"Experimental","settings.group_agent_integration":"Agent Integration","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"Working…","settings.agent_integration_load_error":"Could not check Agent status.","settings.agent_integration_action_error":"Could not complete setup. Run this on your computer:","settings.agent_integration_conflict_hint":"{agent} has an existing configuration. Diagnose it on your computer:","settings.agent_integration_not_installed_hint":"{agent} is not installed on this computer.","settings.agent_integration_initialize_first_hint":"Run {agent} once on your computer, then come back to enable it.","settings.agent_integration_enable":"Enable","settings.agent_integration_repair":"Repair","settings.agent_integration_loading":"Checking…","settings.agent_integration_status_ready":"Ready","settings.agent_integration_status_not_enabled":"Not enabled","settings.agent_integration_status_needs_repair":"Needs repair","settings.agent_integration_status_conflict":"Needs attention","settings.agent_integration_status_not_installed":"Not installed","boot.loading":"Loading","boot.chat_empty":"Send your first message to start the conversation","settings.chat_tone":"Chat colour","settings.chat_tone_dusk":"Warm Dusk","settings.chat_tone_ink":"Warm Gold","settings.chat_tone_light":"Warm Cream","settings.chat_tone_hint":"The colour tone of the 对话 (chat) view — all warm.","settings.path_highlight":"Highlight file paths","settings.path_highlight_hint":"Tint tappable file paths in the terminal. Paths stay tappable either way.","settings.whats_new":"What's new","settings.view_changelog":"View changelog","settings.reload_app":"Reload app","settings.has_update":"Has update","settings.version":"Version","settings.feedback":"Feedback","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat group","settings.feedback_hint":"Bugs and ideas welcome — issues are tracked and answered.","settings.update_available":"Version {v} available","settings.update_more":"{n} more version updates","settings.update_how":"On your computer, run","settings.push_notifications":"Push notifications","settings.notify_on":"Enabled ✓","settings.notify_enable":"Enable device notifications","settings.notify_enabled":"Enabled, you should receive a welcome notification","settings.notify_disabled":"Disabled","settings.notify_failed":"Operation failed","settings.notify_disable_title":"Turn off push notifications?","settings.notify_disable_hint":"This device will stop receiving “Needs you”, “Done”, and script push notifications. You can turn them back on anytime.","settings.notify_disable_confirm":"Turn Off","settings.processing":"Processing","settings.push_hint":'Listens for "Needs you" and "Done": when a watched session needs your authorization/answer, or a turn just finished, a push is sent to this device.',"settings.push_unsupported":"Push requires Chrome or Safari","settings.preview_site":"Preview site","settings.preview_static_site":"Preview static site","settings.preview_running_static":"Static preview running","settings.preview_remain_title":"Time remaining","settings.preview_remain":"{time} left","settings.preview_renew":"Renew","settings.preview_confirm_stop":"Confirm stop","settings.preview_stop":"Stop","settings.preview_name":"Name: {name}","settings.preview_port":"(port :{port})","settings.preview_type":"Preview type","settings.preview_off":"Off","settings.preview_static":"Static","settings.preview_off_hint":'Preview is off. Choose "Static" to start.',"settings.preview_off_hint_both":'Preview is off. Choose "Static" or "Dynamic" to start.',"settings.preview_pick_dir":"Pick directory & start","settings.preview_static_hint":"Pick a directory containing index.html to preview on your phone.","settings.preview_port_placeholder":"Port, e.g. 3000","settings.preview_port_label":"Port","settings.preview_starting":"Starting…","settings.preview_start":"Start","settings.dir_picker_hint":"Pick the static site directory to preview (containing index.html)","settings.err_port_not_listening":"That port is not listening; make sure the service is running","settings.err_bad_port":"Invalid port (1–65535)","settings.err_start_failed":"Failed to start","filebrowser.openDirFailed":"Cannot open this directory","filebrowser.copiedPath":"Path copied: {abs}","filebrowser.mkdirFailed":"Failed to create folder (invalid name or already exists)","filebrowser.downloading":"Downloading {name}","filebrowser.downloadFailed":"Download failed","filebrowser.uploading":"Uploading {name}{tag}","filebrowser.uploadFailed":"Upload failed","filebrowser.uploadPartialFailed":"These files failed to upload: {names}","filebrowser.uploadRejected":"Unsupported file type: {names}","filebrowser.sessionDir":"Session directory","filebrowser.jumpToSessionDir":"Jump to current session directory","filebrowser.parentDir":"Parent directory","filebrowser.rootSelect":"Switch root (home / temp dirs)","filebrowser.pathPlaceholder":"Enter path (live filter / jump)","filebrowser.newFolder":"New folder","filebrowser.createBtn":"Create","filebrowser.uploadFile":"Upload file","filebrowser.uploadToCurrentDir":"Upload to current directory","filebrowser.enterSubdirToUpload":"Enter a subdirectory to upload","filebrowser.folderNamePlaceholder":"Folder name","filebrowser.uploadPendingTo":"Upload “{name}” to the current directory","filebrowser.enterSubdirFirst":"(enter a subdirectory first)","filebrowser.upload":"Upload","filebrowser.savedToDownloads":"Saved “{name}” to the Downloads folder; view it in the system file manager","filebrowser.noMatches":"No matching files or directories","filebrowser.tooMany":"Showing the first {shown} of {total} — type in the path box to filter","filebrowser.previewUnsupported":"Preview not supported for this file type; tap the button on the right to download","filebrowser.copyAbsPath":"Copy absolute path","filebrowser.download":"Download","filebrowser.pickThisDir":"Select this directory {path}","filebrowser.downloadConfirm":"Download {name}?","filemanager.files":"Files","filemanager.closeTab":"Close tab","filemanager.minimize":"Minimize","filemanager.recent":"Recent","filemanager.directory":"Directory","git.errReadRepo":"Cannot read repository","git.errLoad":"Load failed","git.noRepoInDir":"No git repository here yet — pick another directory, or run git init in this one.","git.outsideRoots":"This folder is outside the area handmux can open — only your home directory and /tmp are reachable. Move the repo under your home directory to browse it here.","git.errReadDir":"Cannot read this directory","git.commitDetail":"Commit details","git.diff":"Diff","git.bindRepo":"Bind repository","git.collapse":"Collapse","git.currentBranch":"Current branch","git.switchViewedBranch":"Switch viewed branch","git.switchBranch":"Switch branch","git.noBranches":"No branches","git.noRepoBound":'No repository bound — tap "+" at the top left to choose a directory.',"git.changes":"Changes","git.commits":"Commits","git.pullToLoadMore":"Pull to load more","git.pickerHint":"Choose a directory to auto-discover git repositories inside it","git.cleanTree":"Working tree clean","git.noCommits":"No commits","git.noDiff":"No diff","git.fontSmaller":"Decrease font size","git.fontLarger":"Increase font size","git.diffTruncated":"Diff too large, truncated","cmd.panel":"Command panel","cmd.title":"Commands","cmd.empty":"No commands yet — send one or save a favorite","cmd.favorites":"Favorites","cmd.scopeGlobal":"Global · all sessions","cmd.recent":"Recent","cmd.scopeSession":"This session only","cmd.favorite":"Favorite","cmd.itemConflict":"That shortcut already exists. Change its content or choose another list.","cmd.unfavorite":"Unfavorite","doc.home":"Recent","doc.read":"Read aloud","doc.pauseRead":"Pause reading","doc.resumeRead":"Resume reading","doc.stopRead":"Stop reading","doc.rate":"Speed","doc.fontSmaller":"Smaller font","doc.fontLarger":"Larger font","inbox.view.working":"Running","inbox.view.done":"Completed","inbox.view.needs":"Needs you","inbox.view.error":"Error","push.unsupported":"Push notifications require Chrome or Safari","push.iosAddToHome":'On iOS, first "Add to Home Screen", then open from the home-screen icon to enable',"a2hs.title":"Add handmux to your Home Screen","a2hs.lead":"Open it like an app — full-screen, no address bar. On iPhone it’s also how push reaches you the moment a pane needs you.","a2hs.install":"Install handmux","a2hs.ios1":"Tap the Share button (the ⬆︎ box) in Safari.","a2hs.ios2":"Tap “More”, or scroll down the list.","a2hs.ios3":"Choose “Add to Home Screen”, then “Add”.","a2hs.iosHint":"In Safari: Share → More → Add to Home Screen.","a2hs.iosOpenSafari":"You’re not in Safari. Open this page in Safari, then add it to your Home Screen — other iOS browsers can’t install it.","a2hs.androidManual":"Open your browser menu (⋮) and choose “Add to Home screen” or “Install app”.","a2hs.later":"Maybe later","push.permissionTimeout":"The system did not return the notification permission result. Check notification access for handmux or your browser in system settings, then try again.","push.permissionDenied":"Notification permission denied","push.swRegisterTimeout":"Registering the notification service timed out. Check your connection and try again.","push.swRegisterFailed":"Could not register the notification service: {reason}. Clear this site’s data, reopen it, and try again.","push.swTimeout":"The notification service was registered but did not activate. Clear this site’s data, reopen it, and try again.","push.unknownReason":"unknown reason","push.configTimeout":"Push configuration timed out. Check the connection to your handmux server and try again.","push.browserTimeout":"The browser push service did not respond. On Android Chrome, make sure Google Play services are available, then try again.","push.noVapid":"Push is not configured on the server (VAPID)","push.reportTimeout":"The subscription was created, but reporting it to the server timed out. Check the connection and try again.","push.subscriptionExpired":"Chrome returned an expired push subscription. It has been reset; tap Enable notifications again.","push.deliveryRejected":"The push service rejected the new subscription. Check the server log and try again.","push.subscribeFailed":"Failed to report subscription","push.sendFailed":"Send failed","api.loadFailed":"Load failed","api.uploadFailed":"Upload failed","upload.title":"Uploading","upload.processing":"Sent — receiving on the server…","api.uploadBadDir":"Cannot upload to this directory","api.uploadDuplicate":"A file with this name already exists","api.uploadTooLarge":"File too large (50MB limit)","api.uploadBadType":"Unsupported file type","time.secAgo":"{n}s ago","time.minAgo":"{n}m ago","time.hourAgo":"{n}h ago","time.dayAgo":"{n}d ago","time.expired":"Expired","time.minutes":"{n} min","settings.script_push":"Script push","settings.script_push_open":"How it works","settings.script_push_hint":"Let a script on your computer push a notification to your phone.","scriptPush.title":"Script push","scriptPush.intro":"Let scripts on your computer reuse handmux’s push channel: on the machine running handmux, one `handmux push` command sends a notification to your phone — handy when a build, CI run, or long task finishes, with no separate push service to wire up.","scriptPush.copied":"Copied","scriptPush.session_placeholder":"<session>","scriptPush.device_placeholder":"<device-key>","scriptPush.scope_all":"All subscribed devices (default)","scriptPush.scope_session":"Only devices in one session","scriptPush.scope_device":"Only this device","scriptPush.device_key_note":"The key above is this device’s — copy and run as-is.","scriptPush.device_need_enable":"Turn on push notifications above first to generate this device’s key.","scriptPush.opts_label":"Optional (append to any of the above)","scriptPush.opt_tag":"--tag <tag> — the same tag replaces the previous push instead of stacking.","scriptPush.opt_url":"--url <path> — opens this path when the notification is tapped.","scriptPush.reliability":"Heads-up: Web Push goes through the phone OS (FCM/APNs) and is best-effort — battery-saver, offline, or vendor policy can delay or drop it. It is not a guaranteed real-time channel. For delivery-critical alerts use a dedicated IM (WeChat / Telegram bot, etc.).","pushInbox.title":"Script Push History","pushInbox.empty":"No notifications yet","pushInbox.delete":"Delete","pushInbox.justNow":"just now","pushInbox.minutesAgo":"{n} min ago","pushInbox.hoursAgo":"{n} h ago","pushInbox.detailTitle":"Script Push","pushInbox.openUrl":"Open link","pushInbox.expired":"This message has expired","pushInbox.back":"Back","pushInbox.markAllRead":"Mark all read","pushInbox.unreadCount":"{n} unread","pushInbox.loadFailed":"Could not load script push history. Check the connection and retry.","pushInbox.deleteFailed":"Could not delete the script push. It was kept; please retry.","pushInbox.retry":"Retry","pushInbox.deliveryPending":"Sending","pushInbox.deliverySuccess":"Success","pushInbox.deliveryFailed":"Failed","pushInbox.deliveryReasonExpired":"subscription expired","pushInbox.deliveryReasonRateLimited":"push service rate limit","pushInbox.deliveryReasonUnavailable":"push service unavailable","pushInbox.deliveryReasonRejected":"push service rejected it","pushInbox.deliveryReasonNetwork":"network error","pushInbox.deliveryReasonNotConfigured":"push is not configured","pushInbox.deliveryReasonUnknown":"unknown reason","workspace.bootDetected":"Computer restart detected","workspace.tmuxDetected":"tmux restart detected","workspace.summary":"Last workspace · {sessions} sessions · saved {time}","workspace.restoreLast":"Restore last workspace","workspace.partialCard":"{failures} sessions still need attention","workspace.unknownTime":"unknown time","workspace.savedAt":"Saved {time}","workspace.topologySummary":"{sessions} sessions · {windows} windows · {panes} panes","workspace.planSummary":"Restore {restore} sessions; {already} already present","workspace.renameRule":"A -restored suffix is added only when a session with the same name already exists.","workspace.nonDestructive":"Current sessions will not be modified, renamed, or stopped.","workspace.progress":"Restoring {completed} / {total}…","workspace.progressDone":"Restored {completed} / {total}","workspace.complete":"Workspace restored.","workspace.completedSummary":"Restored: {sessions} sessions · {windows} windows · {panes} panes","workspace.rebindHint":"Restored sessions stay hidden until you choose which ones to bind to this phone.","workspace.rebind":"Bind restored sessions","workspace.sessionFailure":"{session}: {reason}","workspace.unknownSession":"Unknown session","workspace.restore":"Restore","workspace.ignore":"Ignore this backup","workspace.protectionTitle":"Workspace is not protected","workspace.protection.live-corrupt":"Workspace state copies are damaged. Check disk health and ~/.handmux permissions, then restart handmux.","workspace.protection.live-unavailable":"Workspace state cannot be read or written. Check free disk space and ~/.handmux permissions, then restart handmux.","workspace.protection.unknown":"Background snapshots are unavailable. Check the handmux log on your computer.","workspace.error.restore-interrupted":"restore was interrupted; retry this backup","workspace.error.checkpoint-not-found":"this backup is no longer available; refresh and choose another backup","workspace.error.storage-full":"workspace storage is full; free disk space and retry","workspace.error.permission-denied":"workspace storage is not writable; check permissions and retry","workspace.error.plan-failed":"the restore plan changed; refresh and retry","workspace.error.agent-unavailable":"the agent could not resume; open the restored shell and retry manually","workspace.error.tmux-unavailable":"tmux is unavailable; make sure tmux is running and retry","workspace.error.restore-failed":"the session was not restored; check the handmux log and retry","workspace.error.operation-not-found":"this restore operation is no longer available; retry the backup","workspace.sessionWarning":"{session}: {reason}","workspace.warning.cwd-fallback":"the working directory was unavailable; restored in the home directory","workspace.warning.layout-fallback":"the pane layout could not be fully restored; the default layout was kept","workspace.warning.agent-warning":"the agent did not resume automatically; the restored shell is still available","workspace.warning.live-reconcile-failed":"live workspace reconciliation failed; check the handmux log","workspace.warning.workspace-unavailable":"workspace storage is temporarily unavailable; check disk space and permissions","workspace.warning.restore-warning":"the restore completed with a warning that may need attention"},XO={"auth.welcome":"连接你的终端工作空间","auth.login":"登录","auth.connecting":"正在连接","auth.switchLink":"如何管理登录方式?","auth.switchTitle":"管理登录方式","auth.switchWarning":"登录需要输入Token,并完成设备授权。","auth.switchSetup":"要修改 Public URL,请在服务器上运行 handmux setup。直连模式可在“连接 → 直连 → 公网地址”填写自建反向隧道地址。","auth.switchRestart":"首次授权或丢失全部设备时,请在运行 handmux 的电脑上执行下方 CLI 命令。","auth.switchAfter":"设备保护和访问地址限制只通过 CLI 开关;设备和地址列表可在这里管理。","auth.copySetup":"复制查看命令","auth.copyRestart":"复制恢复命令","devices.title":"认证与安全","devices.protectionEnabled":"已开启保护","devices.protectionPartial":"部分开启保护","devices.protectionDisabled":"未开启保护","devices.insecureTitle":"安全保护未全部开启","devices.insecureHint":"设备保护或可信地址限制未开启。","devices.openSecurity":"去认证与安全","devices.listTitle":"已授权设备","devices.historyTitle":"历史设备","devices.historyLink":"历史设备({n})","devices.backToActive":"返回已授权设备","devices.trusted":"设备保护","devices.deviceProtectionSection":"可信设备保护","devices.deviceProtectionStatus":"保护状态","devices.originProtectionStatus":"限制状态","devices.policyEnabled":"已开启","devices.policyDisabled":"未开启","devices.deviceProtectionDisabledHint":"当前仅使用 Token,设备保护未启用;开启后要求可信设备授权。","devices.enableProtection":"开启设备保护","devices.enableOriginProtection":"开启地址限制","devices.enableConfirmTitle":"确认开启保护","devices.enableDeviceConfirm":"将当前浏览器登记为可信设备;其他设备访问需通过可信设备或电脑 CLI 授权。关闭只能在服务器上运行 handmux auth device off。","devices.enableOriginConfirm":"开启后只允许从已登记的访问地址进入。关闭只能在服务器上运行 handmux auth address off。","devices.enableConfirm":"确认开启","devices.originProtectionDisabledHint":"当前不限制访问地址。","devices.deviceProtectionInfo":"设备保护可在这里一键开启;关闭只能在服务器上运行 handmux auth device off。页面这里只管理设备。","devices.deviceProtectionEnabledHint":"用于限制未授权设备访问;关闭只能在服务器上运行 handmux auth device off。","devices.originProtectionInfo":"访问地址保护只能通过 handmux auth address on/off 切换,页面这里只管理地址。","devices.originProtectionEnabledHint":"用于限制未登记地址访问;关闭只能在服务器上运行 handmux auth address off。","devices.token":"Token","devices.addSelf":"将本机添加为可信设备","devices.addSelfTitle":"添加本机","devices.addSelfAddress":"登记地址:{origin}","devices.cookieRequired":"浏览器未保存可信设备登录凭据,请允许 Cookie 后重试。","devices.trustedOrigin":"可信访问地址","devices.accessSection":"可信地址保护","devices.publicUrlLabel":"主域名","devices.publicUrlInfo":"由 setup → 连接 → 当前连接方式 → 公网地址设置;网页这里只读显示。","devices.previewDomainLabel":"预览域名","devices.previewDomainInfo":"由 setup → Web preview → 网页预览器代理域名设置;系统会自动允许它的动态子域名。","devices.originConfigured":"来自 setup 配置,不能在此修改","devices.originBuiltIn":"系统自动允许","devices.originUnset":"未设置","devices.originActive":"已生效","devices.originPending":"未配置;外部地址请用 CLI 登记,或通过设备授权自动加入","devices.originHint":"Public URL 来自 Setup,网页这里只读。没有固定公网入口时可以留空;本机和局域网直连仍可用,外部地址需加入下方列表或使用动态预览域名。","devices.originCommands":"可信访问地址命令","devices.originSetupCommandLabel":"配置","devices.extraOriginsTitle":"信任域名","devices.trustedOriginLabel":"信任域名 {n}","devices.extraOriginsHint":"由设备授权自动登记,也可用 CLI 管理。支持 https://*.example.com 形式的通配符。","devices.extraOriginInput":"额外信任域名","devices.extraOriginAdd":"添加域名","devices.removeOriginTitle":"删除信任域名","devices.removeOriginImpact":"以下设备将无法通过此地址访问:","devices.removeOriginCurrentImpact":"包含本机:删除后本机也无法访问,需要重新授权。","devices.removeOriginNoImpact":"当前没有已生效设备使用此地址。确定删除吗?","devices.removeOriginConfirm":"删除","devices.invalidOrigin":"请输入完整的 http(s) 地址,例如 https://*.example.com。通配符只能放在最左侧子域名。","devices.originLimit":"额外信任域名已达到上限,请先删除一个。","devices.originMismatch":"当前地址不在允许的访问入口中。请从主访问地址、动态预览域名或已登记地址打开 handmux;需要登记时运行 handmux auth address add <origin>。","devices.addSelfOrigin":"授权完成后会把 {origin} 加入可信访问入口。","devices.cliOnly":"如需修改可信访问地址,请在服务器上使用 handmux CLI。","devices.current":"当前设备","devices.add":"添加设备","devices.authorizeOther":"为其他设备授权","devices.history":"历史设备({n})","devices.activeTab":"有效设备","devices.historyTab":"历史设备","devices.activeStatus":"可访问","devices.detailInfo":"设备信息","devices.deviceInfo":"设备","devices.status":"状态","devices.detailActions":"设备操作","devices.noActive":"暂无有效设备。","devices.activeDevices":"‹ 有效设备","devices.noHistory":"暂无历史设备。","devices.name":"设备名称","devices.expire":"授权有效期","devices.keep":"保持当前期限","devices.custom":"自定义","devices.never":"不限期","devices.customDuration":"正整数加 m / h / d,或 never","devices.keepHint":"保持当前期限不会延长授权。","devices.expireFromSave":"所选时长从本次保存成功时开始计算。","devices.id":"设备 ID","devices.copyId":"复制 ID","devices.browser":"浏览器","devices.added":"添加时间","devices.lastAccess":"最后访问时间","devices.expiresAt":"到期时间","devices.revoked":"已解除绑定","devices.expired":"已过期","devices.daysRemaining":"剩余 {n} 天","devices.hoursRemaining":"剩余 {n} 小时","devices.minutesRemaining":"剩余 {n} 分钟","devices.logout":"退出当前设备","devices.revoke":"踢出设备","devices.revokeDescription":"“{name}”将立即失去访问权限,再次登录需要重新配对。已运行的终端任务继续执行。","devices.conflict":"设备已被其他操作修改。请刷新详情,再重新应用你的修改。","devices.refreshDetails":"重新加载最新信息","devices.inactive":"设备已过期或解除绑定,请重新配对恢复访问。","devices.sessionInvalid":"当前浏览器授权已失效,请刷新 handmux 后重新配对。","devices.invalidName":"设备名称需要 1–80 个字符,不能包含控制字符。","devices.nameTaken":"设备名称已被使用,请换一个名称。","devices.saved":"已保存。","devices.invalidExpire":"请输入正整数时长,例如 1h、7d,或 never。","devices.expiryCliOnly":"授权有效期只能在运行 handmux 的服务器上使用 CLI 修改。","devices.invalidCode":"请输入新浏览器当前显示的 6 位校验码,过期或已使用的校验码不能重复使用。","devices.pairingGone":"配对已取消或过期,请在新浏览器重新申请校验码。","devices.requestError":"无法确认操作结果,请检查网络后重试;尚未确认修改成功。","devices.code":"一次性校验码","devices.codeHint":"输入新设备显示的 6 位验证码,输入完成后会自动验证。","devices.verifyingCode":"正在验证…","devices.configureTitle":"设置新设备","devices.approvalOrigin":"访问地址","devices.claim":"确认配对","devices.complete":"完成添加","devices.newCode":"输入新校验码","auth.methodLabel":"授权方法","auth.webMethod":"已有可信设备","auth.webInstructions":"在已经登录同一个 handmux 实例的手机或电脑上打开:","auth.webPath":"设置 → 认证与安全 → 通过一次性校验码添加设备","auth.webNext":"输入上方校验码并确认配对,再填写新设备的名称和有效期,点击“完成添加”。本页面会自动登录。","auth.webFallback":"没有可用的可信设备?再切换到“电脑 CLI”。","auth.title":"申请设备授权","auth.waiting":"等待授权","auth.deviceRequired":"需要设备授权","auth.preparingCode":"正在准备验证码…","auth.deviceAuthorizationHint":"输入 Token 后,还需要完成一次设备授权。","auth.verificationCode":"授权验证码","auth.authorizeWithDevice":"在已有授权设备的「认证与安全」中输入此验证码。","auth.authorizeWithCli":"在运行 handmux 的电脑上执行","auth.cliAfterCode":"按提示输入这个验证码。","auth.chooseOneMethod":"任选一种方式完成授权","auth.cliMethodTitle":"电脑 CLI 授权","auth.deviceMethodTitle":"其他设备授权","auth.paired":"配对成功","auth.pending":"已确认,正在完成授权…","auth.finishCli":"请在终端完成设备设置。","auth.finishWeb":"请在已授权设备上完成设备设置。","auth.setupRemaining":"剩余 {seconds} 秒完成设置","auth.codeRemaining":"剩余 {seconds} 秒","auth.codeExpired":"已过期,请重新获取","auth.expired":"验证码已过期,请重新生成。","auth.canceled":"授权已取消,请重新生成验证码。","auth.request":"申请设备授权","auth.requestNewCode":"重新生成验证码","auth.refreshCode":"刷新","auth.cancelPairing":"取消配对","auth.copyCode":"复制校验码","auth.copyCommand":"复制命令","auth.copied":"已复制","auth.manualCopy":"已选中文本,请长按或按 Ctrl/Cmd+C 复制。","auth.cliMethod":"电脑 CLI","auth.cliInstructions":"在运行此 handmux 实例的电脑上,使用同一 OS 用户执行下方命令;也可以先通过独立 SSH 连接。命令会进入交互式授权流程。","auth.cliNext":"随后输入本页显示的 6 位校验码,再填写设备名称和有效期;保存完成后本页面会自动登录。自动化脚本请使用 --code、--name 和 --expire flags。","auth.browserScope":"授权保存在当前浏览器和当前访问地址中。更换地址后,需要重新配对。","auth.antiPhishing":"仅授权你本人正在添加的浏览器,不要输入他人发来的校验码。","auth.httpWarning":"为更好地保护敏感访问,尽可能使用 HTTPS 或可信的加密网络。","auth.tokenWarning":"Token 始终需要;开启设备保护后,还需完成设备授权。","auth.dualRequirement":"Token 始终需要;开启设备保护后,还需完成设备授权。","auth.tokenRequired":"请先输入当前 Token,再申请设备授权。","auth.tokenInvalid":"Token 不正确,请重新输入后再继续。","auth.connectionError":"暂时无法确认授权状态,请检查网络和 handmux 是否运行后重试;不会因此取消授权。","auth.originRejected":"当前地址未在可信访问入口中。","auth.originRejectedTitle":"地址未受信任","auth.originRejectedAddress":"当前地址 {origin} 非可信访问入口","auth.originRejectedOpenLabel":"从可信入口打开","auth.originRejectedOpenHint":"使用主访问地址、动态域名或已授权的访问域名打开此页面","auth.originRejectedAuthorizeLabel":"重新授权","auth.originRejectedAuthorizeHint":"使用另一台可信设备或电脑 CLI 授权当前访问地址","auth.originRejectedAuthorizeButton":"申请访问权限","auth.originRejectedRetry":"重新检查","auth.retry":"重试","auth.rateLimit":"授权尝试过于频繁,请稍等一分钟后再申请校验码。","auth.logoutTitle":"解除绑定并退出","auth.logoutDescription":"当前浏览器将立即失去访问权限,再次登录需重新配对。已运行的终端任务会继续。","auth.logoutError":"未能确认解除绑定,请检查连接后重试;当前设备可能仍然有效。","terminal.disconnected":"连接断开,重连中…","terminal.paneMissing":"窗格已关闭,请切换到其他窗格。","terminal.transport_live":"实时","terminal.transport_snapshot":"快照","terminal.transport_detail_title":"终端传输状态","terminal.transport_detail_configured":"设置模式","terminal.transport_detail_current":"当前模式","terminal.transport_detail_connection":"连接状态","terminal.transport_detail_manual":"你已手动选择快照拉取,不会自动切换。","terminal.transport_detail_live":"终端正在正常接收实时推送。","terminal.transport_detail_fallback":"实时推送不稳定,已自动降级为快照拉取。","terminal.transport_detail_unavailable":"实时通道无法建立,请检查反向代理是否支持 WebSocket。","terminal.transport_detail_waiting":"正在等待连接稳定,随后尝试恢复实时推送。","terminal.transport_detail_retry":"预计 {seconds} 秒后尝试恢复实时推送。","terminal.connection_connecting":"检测中","terminal.connection_good":"良好","terminal.connection_degraded":"一般","terminal.connection_poor":"较差","common.save":"保存","common.cancel":"取消","common.confirm":"确认","common.ok":"确定","common.close":"关闭","common.delete":"删除","common.undo":"撤销","common.copy":"复制","common.rename":"重命名","common.create":"新建","common.back":"返回","common.open":"打开","common.loading":"加载中…","common.done":"完成","common.retry":"重试","common.continue":"继续","conversationCopy.line":"整行","conversationCopy.paragraph":"整段","app.browser":"网页预览器","browser.openTabs":"打开的网页预览器标签页","browser.history":"最近访问","browser.closeTab":"关闭 {title}","browser.newTab":"新建标签页","browser.minimize":"收起","browser.back":"后退","browser.forward":"前进","browser.address":"地址","browser.addressPlaceholder":"输入网址或端口","browser.addressOrDirectoryPlaceholder":"输入网址,或选择目录","browser.refresh":"刷新","browser.stop":"停止加载","browser.viewMode":"页面宽度","browser.narrowWidth":"窄屏","browser.wideWidth":"宽屏","browser.closeTiming":"后台页签关闭","browser.minutes":"{value} 分钟","browser.neverClose":"永不关闭","browser.clearHistory":"清除","browser.emptyHistory":"还没有最近访问","browser.loadFailed":"无法加载此网页,请检查地址后重试。","browser.retry":"重试","browser.consentTitle":"网页预览器","browser.consentBody":"Handmux 会把网页嵌入当前窗口。它不是真正的浏览器,适合预览开发服务、localhost、内网和允许嵌入的网站;也可从 Home 选择电脑上的静态目录。","browser.consentComputer":"连接方式:手机直连使用手机网络。经电脑代理时,请求由电脑发起,可以访问电脑所在的内网和 localhost,但不会将它们公开。","browser.consentPrivate":"登录状态:直连与代理不共享 Cookie 和登录状态;代理会话也按当前设备隔离。","browser.consentLimits":"兼容限制:直连可能被网站的 iframe 或 CSP 策略阻止,而且 Handmux 未必能判断原因。电脑代理会转发并改写网页,也不保证兼容所有网站。需要完整浏览能力时,请用 Safari、Chrome 或系统浏览器打开。","browser.consentIdle":"后台标签页:默认在 10 分钟后关闭。直连网站的 Cookie 仍保留在手机浏览器中。","browser.about":"关于网页预览器","browser.acknowledge":"好的","browser.directMode":"手机直连","browser.proxyMode":"经电脑代理","browser.directBadge":"直连","browser.proxyBadge":"代理","browser.staticBadge":"静态","browser.chooseDirectory":"选择目录","browser.staticOpening":"正在打开目录…","browser.directoryPickerHint":"选择包含网页文件的目录。","browser.switchMode":"切换浏览模式","browser.menu":"网页预览器菜单","browser.connectionMode":"连接方式","browser.pageWidth":"页面宽度","browser.requestSiteVersion":"向网站请求","browser.mobileSite":"手机版","browser.desktopSite":"电脑版","browser.zoomPage":"缩放网页","browser.resetZoom":"重置网页缩放","browser.proxyLogin":"代理登录","browser.proxyLoginHelpLabel":"代理登录说明","browser.proxyLoginHelp":"是否将代理 Cookie 加密保存在运行 Handmux 的电脑上,以便重启后保持登录状态。","browser.siteProxyCookie":"本站代理 Cookie","browser.siteCookieHelpLabel":"本站代理 Cookie 说明","browser.siteCookieHelp":"这里只清理当前设备中与本站真实网址匹配的代理 Cookie。父域 Cookie 可能让相关内网站点一起退出,手机直连 Cookie 不受影响。","browser.openMode":"选择打开方式","browser.historyMore":"更多打开方式","browser.historyActions":"更多操作","browser.proxyLimitHint":"电脑代理会转发并改写网页,不保证兼容所有网站。","browser.proxyUnavailable":"请在电脑终端运行 handmux setup,选择“网页预览器”配置代理域名;配置前只能使用手机直连。","browser.urlInvalid":"请输入有效的 HTTP 或 HTTPS 地址。","browser.tryProxy":"改用电脑代理","browser.openExternal":"用系统浏览器打开","browser.clearSiteLogin":"清理本站代理 Cookie","browser.clearAllLogin":"清理全部代理 Cookie","browser.clearSiteLoginConfirm":"清理当前设备的本站代理登录状态?父域 Cookie 也可能影响相关内网系统。","browser.clearAllLoginConfirm":"清理当前设备的全部代理登录状态?手机直连的登录状态不受影响。","browser.deleteHistoryEntry":"删除此记录","browser.profileSaveFailed":"无法保存代理登录设置,请检查服务器连接后重试。","browser.profileClearFailed":"清理未完全成功,请检查服务器连接和存储权限后重试。","browser.profileSyncFailed":"无法同步代理登录设置。请重试,或改用手机直连。","browser.profileRecoveryWarning":"无法恢复已保存的代理登录数据,当前设备的代理登录状态已重置。","browser.retention1":"1 天","browser.retention7":"7 天","browser.retention30":"30 天","browser.retentionNotSaved":"不保存","browser.retentionNever":"长期保存","settings.browserPersistLogin":"在电脑上持久化保存代理 Cookie","settings.browserPersistLoginHint":"只保存在当前设备。关闭后,当前标签页和登录状态仍会保留,直到清理或过期。","settings.browserRetention":"代理登录保留","settings.browserDisablePersistConfirm":"停止保存当前设备后续的代理登录变化?当前标签页和登录状态会继续保留。","token.title":"登录 handmux","token.placeholder":"输入 Token","settings.language":"语言 Language","settings.browserDefaultMode":"网页默认打开方式","settings.browserDefaultModeHint":"用于地址栏新页签,以及没有保存打开方式的历史记录。","settings.browserEnabled":"网页预览器","settings.browserEnabledHint":"标签页仅属于当前设备。关闭后会关闭全部标签页,但保留历史记录。","home.empty":"还没有打开过文件","home.emptyHint":"切到「新增」去挑一个","home.remove":"移除","drawer.title":"会话","drawer.empty":"还没有绑定会话","drawer.unbind":"解绑","drawer.bind":"绑定会话","drawer.logout":"退出登录","windowbar.newWindow":"新建窗口","rename.new_name":"新名称","rename.name_rule":"只能用字母、数字、横线(≤16)","rename.failed":"重命名失败,请重试","rename.saving":"保存中…","newwindow.title":"新建窗口","newwindow.window_name":"窗口名称(可选)","newwindow.name_placeholder":"留空自动命名 · 字母/数字/横线 ≤16","newwindow.name_rule":"只能用字母、数字、横线(≤16)","newwindow.start_dir":"起始目录","newwindow.session_dir_named":"{dir}(会话目录)","newwindow.session_dir_default":"会话目录(默认)","newwindow.choose":"选择","newwindow.reset_to_session_dir":"重置为会话目录","newwindow.creating":"新建中…","startup.label":"启动命令(可选)","startup.aria":"启动命令","startup.preset_shell":"空 shell(默认)","startup.preset_claude":"claude(启动 Claude Code)","startup.preset_claude_continue":"claude -c(接着上次会话)","startup.preset_codex":"codex(启动 Codex CLI)","startup.custom":"自定义…","startup.custom_placeholder":'例如 claude "修复登录bug"',"bind.title":"绑定会话","bind.sessionName":"会话名称","bind.pickSession":"选择要绑定的会话","bind.newSession":"+ 新建会话","bind.modeNew":"新建会话","bind.modeExisting":"已有会话","bind.alreadyExists":"该会话已存在","bind.bind":"绑定","bind.checking":"校验中…","bind.createAndOpen":"新建并打开","bind.creating":"新建中…","bind.createHint":"会话「{name}」不存在,点「新建并打开」创建","bind.alreadyBound":"已绑定该会话","bind.createFailed":"新建失败,请重试","bind.invalidName":"只能用字母、数字、横线(≤16)","bind.desktopHint":"这里的会话(包括手机新建的),电脑上一条命令即可接管:handmux open <会话名>","bind.checkFailed":"校验失败,请重试","bind.startDir":"起始目录","bind.homeDirDefault":"主目录(默认)","bind.choose":"选择","bind.reset":"重置","actionsheet.confirmAgain":"确认?再点一次","dirpicker.title":"选择目录","inbox.title":"收件箱","inbox.working":"进行中","inbox.done":"已完成","inbox.needs":"需要你","inbox.error":"出错","inbox.clearDone":"清除结果","inbox.empty":"暂无面板状态","inbox.reconnecting":"正在重新连接收件箱…","inbox.enableTitle":"开启 Claude Code 状态与通知","inbox.enableHint":"Claude Code 收件箱需要 Agent hooks。Codex CLI 请使用 Handmux 托管模式。","inbox.enableBtn":"开启","inbox.enabling":"开启中…","inbox.enableFailed":"开启失败 —— 看看服务端日志。","drawer.orphans.title":"{n} 个未接管会话","drawer.orphans.hint":"接管即可远程操控","inbox.orphans.takeover":"接管","inbox.orphans.noSession":"无可续接的历史","inbox.orphans.busy":"运行中","inbox.orphans.idle":"空闲","inbox.orphans.working":"接管中…","inbox.orphans.failed":"接管失败","inbox.orphans.targetLabel":"接管到","inbox.orphans.targetNew":"新建会话","inbox.orphans.nameLabel":"会话名称","inbox.orphans.namePlaceholder":"会话名","inbox.orphans.killTitle":"接管后原来的进程","inbox.orphans.killEnd":"结束","inbox.orphans.killKeep":"保留","inbox.orphans.recommended":"推荐","inbox.orphans.killWhy":"同一个会话如果电脑和手机同时在写,历史记录会错乱。结束原进程后由手机这边独占,更稳妥。","inbox.orphans.reopenPre":"想回电脑上继续?在电脑终端运行:","idea.title":"想法","idea.editPlaceholder":"编辑想法…","idea.addPlaceholder":"记一条想法…","idea.add":"添加","idea.empty":"还没有想法,记一条吧","idea.dragSort":"拖动排序","idea.fillInput":"填入输入框","idea.send":"发送","doclink.title":"打开文件","localurl.title":"打开网站","localurl.open":"在浏览器中打开","localurl.notListening":"端口 :{port} 没有服务在监听。","localurl.badProtocol":"该链接不是可代理的 HTTP 或 HTTPS 地址。","localurl.network":"连接 handmux 服务失败,请检查网络后重试。","localurl.failed":"无法打开该网站,请检查地址后重试。","changelog.title":"新功能","preview.static":"静态预览","preview.tabs":"打开的预览","preview.remainTitle":"剩余有效期 — 点击续期 / 停止","preview.toPcView":"切换到电脑视图","preview.toMobileView":"切换到手机视图","preview.pcView":"电脑视图","preview.mobileView":"手机视图","preview.refresh":"刷新","preview.minimize":"收起","preview.ttlDialog":"预览有效期","preview.renew":"续期(重置为 1 小时)","preview.stop":"停止预览","preview.iframeTitle":"预览","preview.zoomOut":"缩小","preview.zoomIn":"放大","imageviewer.loadFailed":"图片加载失败","imageviewer.saved":"已保存,可在相册/图库或「下载」中查看","imageviewer.shareUnsupported":"图片分享需要 Chrome 或 Safari 浏览器","imageviewer.zoomOut":"缩小","imageviewer.zoomIn":"放大","imageviewer.imageTitle":"图片","imageviewer.saveImage":"保存图片","imageviewer.shareImage":"分享图片","mic.stop":"停止语音输入","mic.start":"语音输入","mic.recognizing":"正在识别语音","mic.error.tencentPermission":"腾讯云拒绝了识别:请为当前 SecretId 授予 asr:SentenceRecognition 权限后重试。","mic.error.tencentCredentials":"腾讯云凭据无效,请在 handmux setup 中检查 AppId、SecretId 和 SecretKey。","mic.error.browserPermission":"没有麦克风权限,请在浏览器的网站设置中允许麦克风后重试。","mic.error.device":"无法使用麦克风,请检查设备是否存在或被其他应用占用。","mic.error.secureContext":"当前地址不能使用麦克风,请改用 HTTPS 或 localhost 打开 Handmux。","mic.error.tooLong":"录音过长,请缩短后重试。","mic.error.notSelected":"当前语音模式未生效,请重启 Handmux 后重试。","mic.error.noSpeech":"未识别到语音,请重试。","mic.error.network":"语音服务连接失败,请检查网络后重试。","mic.error.provider":"语音服务拒绝了请求:{reason}","mic.error.generic":"语音输入失败,请重试。","dock.send":"发送","dock.send.hint":"点发送 · 长按填入","dock.phrases":"常用语","dock.attach":"上传","dock.history":"历史","dock.kbdShow":"展开键盘","dock.kbdHide":"收起键盘","history.empty":"还没有发送记录","history.scope":"仅当前窗口的记录","dock.input.placeholder":"说点什么…","dock.input.enterDraft":"按 Shift + Enter 进入草稿模式","dock.input.exitDraft":"按 Esc 回到终端模式 · Shift + Enter 换行","dock.command.placeholder":"输入命令 · 回车执行","dock.mode.agent":"对话","dock.mode.toggle":"切换输入模式","dock.mode.command":"命令模式","dock.mode.chat":"聊天模式","fav.title":"常用","fav.add":"添加","fav.addPlaceholder":"加一条常用…","cmd.editTitle":"常用命令","cmd.global":"全局","cmd.window":"当前窗口","cmd.withEnter":"直接发送","cmd.configPresets":"配置预置","cmd.removeDevice":"从本机移除","cmd.removedDevice":"已从本机移除","cmd.addPlaceholder":"加一条命令…","cmd.tabCmd":"命令","cmd.tabKey":"按键","cmd.addTo":"添加到","cmd.addTitle":"添加","cmd.added":"已添加","cmd.editItem":"编辑","cmd.sticky":"粘滞键","cmd.stickyNone":"无","cmd.baseKey":"基键","cmd.pickKey":"选择按键","cmd.moveUp":"上移","cmd.moveDown":"下移","chat.editTitle":"常用消息","chat.composer.placeholder":"和 Agent 对话…","chat.historyPulling":"拉取中","agentConversation.empty":"开始和这个 Agent 对话吧。","agentConversation.unavailable":"无法连接对话","agentConversation.reconnecting":"正在重新连接实时对话…","agentConversation.reloadRequired":"Pi 对话组件已更新。请切换到终端运行 /reload,然后返回对话。","agentConversation.loadOlder":"加载更早的消息","agentConversation.loadOlderFailed":"更早的消息没有加载成功,请重试。","agentConversation.reasoning":"思考摘要","agentConversation.toolResult":"工具结果","agentConversation.diff":"变更","agentConversation.attachment":"附件","agentConversation.attachmentFailed":"附件下载失败,请重试。","agentConversation.truncated":"部分内容已截断。","agentConversation.interactionTerminal":"这个操作需要在终端中完成。","agentConversation.interactionUnavailable":"暂时无法在对话中处理这个请求","agentConversation.interactionCommandApproval":"允许执行这个命令吗?","agentConversation.interactionFileApproval":"允许修改文件吗?","agentConversation.interactionPermissionApproval":"允许授予所请求的权限吗?","agentConversation.interactionInputRequest":"需要你的补充信息","agentConversation.interactionReason":"原因","agentConversation.interactionCommand":"命令","agentConversation.interactionWorkingDirectory":"工作目录","agentConversation.interactionContext":"上下文","agentConversation.interactionOther":"输入其他回答","agentConversation.interactionPlaceholder":"输入回答","agentConversation.openTerminal":"打开终端","chat.stop":"停止","chat.stopTitle":"停止当前任务?","chat.stopBody":"当前正在执行的回合会被中断。","chat.config.open":"设置模型、服务等级和思考强度","chat.config.title":"模型设置","chat.config.model":"模型","chat.config.effort":"思考强度","chat.config.fast":"Fast","chat.config.fastHint":"使用当前模型提供的快速服务","chat.config.loading":"正在获取可用模型…","chat.config.empty":"没有可用模型","chat.config.chooseModel":"先选择一个可用模型","chat.config.loadFailed":"无法获取模型列表","chat.config.refresh":"刷新模型列表","chat.config.saveFailed":"设置没有保存成功","chat.config.nextTurn":"当前回复不变,下条消息生效","chat.goal.title":"任务目标","chat.goal.objective":"目标内容","chat.goal.placeholder":"描述一个需要持续推进的目标","chat.goal.loading":"正在读取当前目标…","chat.goal.loadFailed":"无法读取当前目标","chat.goal.saveFailed":"目标没有保存成功","chat.goal.clearFailed":"目标没有清除成功","chat.goal.tooLong":"任务目标最多 4,000 个字符","chat.goal.created":"任务目标已设置","chat.goal.updated":"任务目标已更新","chat.goal.paused":"任务目标已暂停","chat.goal.resumed":"任务目标已继续","chat.goal.restarted":"任务目标已重新开始","chat.goal.cleared":"任务目标已清除","chat.goal.edit":"编辑","chat.goal.pause":"暂停","chat.goal.resume":"继续","chat.goal.restart":"重新开始","chat.goal.clear":"清除","chat.goal.clearConfirmTitle":"清除任务目标?","chat.goal.clearConfirmBody":"当前任务目标会被删除,Codex 将停止继续跟踪;对话中的历史卡片仍会保留。","chat.goal.statusActive":"进行中","chat.goal.statusPaused":"已暂停","chat.goal.statusBlocked":"已阻塞","chat.goal.statusComplete":"已完成","chat.goal.statusUsageLimited":"用量受限","chat.goal.statusBudgetLimited":"预算受限","chat.goal.eventSet":"已设置目标","chat.goal.eventRestarted":"已重新开始目标","chat.goal.eventComplete":"目标已完成","chat.goal.eventBlocked":"目标已阻塞","chat.goal.eventUsageLimited":"目标因用量受限结束","chat.goal.eventBudgetLimited":"目标因预算受限结束","chat.goal.tokens":"Token {value}","chat.goal.elapsed":"耗时 {value} 秒","chat.plan.currentTitle":"当前任务","chat.plan.historyTitle":"本轮任务","chat.plan.working":"正在:{step}","chat.plan.waiting":"等待确认:{step}","chat.plan.finalizing":"正在整理结果","chat.plan.complete":"已完成","chat.plan.incomplete":"未完成","chat.plan.status.pending":"待处理","chat.plan.status.inProgress":"进行中","chat.plan.status.completed":"已完成","chat.context.aria":"上下文占用 {percent}%","chat.context.unavailableAria":"上下文状态,用量暂不可用","chat.context.title":"上下文用量","chat.context.percent":"上下文长度用量","chat.context.used":"当前 Token","chat.context.total":"模型总 Token","chat.context.usedTotal":"已用 / 总量","chat.status.aria":"会话状态,上下文占用 {percent}%","chat.status.title":"会话状态","chat.status.idle":"空闲","chat.status.working":"处理中","chat.status.waitingApproval":"等待审批","chat.status.waitingInput":"等待回答","chat.status.compacting":"压缩中","chat.compacting.live":"正在压缩上下文","chat.status.directory":"目录","chat.status.worktree":"Worktree","chat.status.branch":"分支","chat.status.access":"访问权限","chat.status.permissionMode":"权限模式","chat.status.sessionId":"会话 ID","chat.status.copyDirectory":"复制目录","chat.status.copyWorktree":"复制 Worktree 路径","chat.status.copySession":"复制会话 ID","chat.status.copied":"已复制","chat.status.sandboxReadOnly":"只读","chat.status.sandboxWorkspace":"可修改工作区","chat.status.sandboxFull":"完全访问","chat.permissionMode.default":"默认","chat.permissionMode.autoReview":"自动","chat.permissionMode.fullAccess":"完全","chat.permissionMode.custom":"自定义","chat.permissionMode.title":"权限模式","chat.permissionMode.open":"设置权限模式,当前为{value}","chat.permissionMode.defaultHint":"可读写当前工作区并运行命令;联网或访问其他位置时会询问你。","chat.permissionMode.autoReviewHint":"权限与“默认”相同;需要额外权限时,由 Codex 自动判断批准或拒绝。","chat.permissionMode.fullAccessHint":"可访问工作区外和网络且不会询问;仅在完全信任当前任务时使用。","chat.permissionMode.nextTurn":"修改从下一条消息生效","chat.permissionMode.saved":"权限模式已更新,下条消息生效","chat.permissionMode.saveFailed":"权限模式没有保存成功","chat.interrupted":"你终止了这次回复","chat.compacted":"上下文已压缩","chat.compaction.viewDetails":"查看详情","chat.compaction.title":"上下文压缩","chat.compaction.complete":"完成","chat.compaction.summary":"Agent 保留的摘要","chat.compaction.unavailable":"这次压缩没有提供可查看的摘要。","chat.compaction.truncated":"摘要过长,当前只显示已安全保留的部分。","chat.scroll.latest":"回到最新","chat.scroll.reloadLatest":"↓ 回到最新","chat.scroll.answer":"↓ 查看最新回答","chat.scroll.bottom":"↓ 回到底部","chat.slash.unsupported":"这个命令暂不支持在对话视图中使用","chat.session.unboundTitle":"无法确认这个 Codex 对话","chat.session.unboundHint":"Codex 会话仍在启动,确认到准确会话后会自动显示。","chat.session.openTerminal":"前往终端","chat.session.notManaged":"请先在终端以托管模式重新启动 Codex","chat.session.unmanagedTitle":"此 Codex 会话未托管","chat.session.unmanagedHint":"请在终端以托管模式重新启动后再打开对话。","chat.session.connectionHint":"Codex App Server 暂时不可用,请确认 Codex 仍在运行后重试。","chat.managedGuide.title":"接入 Codex 对话","chat.managedGuide.hint":"Handmux 可以在当前窗格恢复原会话,并切换为可靠的托管对话。","chat.managedGuide.start":"开始托管","chat.managedGuide.submitting":"正在启动…","chat.managedGuide.confirmTitle":"开始托管?","chat.managedGuide.confirmHint":"当前 Codex 进程会结束,正在执行的任务也会停止。恢复过程中可能需要你前往终端,人工处理信任或其他确认。","chat.managedGuide.confirmAction":"结束并开始托管","chat.managedGuide.startingTitle":"正在启动托管","chat.managedGuide.startingHint":"正在恢复原会话,成功后会自动进入对话。","chat.managedGuide.terminalHint":"启动尚未完成,Codex 可能正在终端等待信任或其他确认。","chat.managedGuide.timeoutTitle":"托管仍未就绪","chat.managedGuide.timeoutHint":"已经等待 30 秒,Codex 可能需要你前往终端人工确认。当前页面不会自动切换。","chat.managedGuide.manualTitle":"需要从终端继续","chat.managedGuide.manualHint":"Codex 没有正常退出或返回可确认的恢复信息。请前往终端查看当前状态。","chat.managedGuide.goneTitle":"这个 Codex 已经变化","chat.managedGuide.goneHint":"为避免结束错误的进程,Handmux 没有继续操作。请前往终端查看当前状态。","chat.managedGuide.unavailableTitle":"无法安全确认当前 Codex 会话","chat.managedGuide.unavailableHint":"请重试,或前往终端继续。","chat.managedGuide.failedHint":"托管启动未能完成。你可以重试,或前往终端查看当前状态。","chat.managedGuide.recoveryHint":"原会话已经确认;如果自动恢复失败,请在终端运行:","chat.managedGuide.copyRecovery":"复制恢复命令","chat.managedGuide.recoveryTitle":"继续恢复 Codex 对话","chat.managedGuide.recoveryReadyHint":"上次接管在恢复前中断了。可以在当前窗格安全地继续。","chat.managedGuide.recoveryManualHint":"无法确认当前窗格仍可安全自动恢复,请复制命令或前往终端。","chat.managedGuide.recoveryStaleTitle":"原窗格已经变化","chat.managedGuide.recoveryStaleHint":"为避免把命令发送到错误的窗格,这里只提供复制。","chat.managedGuide.retryRecovery":"继续恢复","chat.approval.request":"Codex 请求确认","chat.approval.file":"允许修改文件?","chat.approval.command":"允许运行这条命令?","chat.approval.permissions":"允许 Codex 获取额外权限?","chat.approval.accept":"允许一次","chat.approval.acceptSession":"本次会话始终允许","chat.approval.acceptRule":"允许并记住“{rule}”","chat.approval.allowHost":"始终允许访问 {host}","chat.approval.denyHost":"始终拒绝访问 {host}","chat.approval.decline":"拒绝","chat.approval.cancel":"拒绝并停止","chat.approval.failed":"审批没有提交成功","chat.input.request":"Codex 需要你的回答","chat.input.step":"第 {current}/{total} 题","chat.input.other":"其他回答","chat.input.placeholder":"输入回答","chat.input.submit":"提交回答","chat.input.failed":"回答没有提交成功","chat.sendFailed":"消息没有发送成功","chat.terminalDraftConflict":"终端有未确认的草稿,请先在终端处理后重试","chat.queue.terminalDraftConflict":"终端有未确认的草稿,请先在终端处理,再编辑此消息重试","chat.sendUnknown":"无法确认消息是否送达,请检查对话后再重试","chat.stopFailed":"没有停止成功,请稍后重试","chat.queue.title":"排队消息","chat.queue.hint":"当前回合结束后自动逐条发送","chat.queue.steer":"立刻引导","chat.queue.edit":"编辑排队消息","chat.queue.editTitle":"编辑排队消息","chat.queue.editPlaceholder":"输入排队消息","chat.queue.remove":"删除排队消息","chat.queue.removeTitle":"删除这条排队消息?","chat.queue.removeBody":"删除后无法恢复。","chat.queue.actionFailed":"没有处理成功,请稍后重试","chat.queue.editExpired":"编辑已过期,请关闭后重新编辑。","chat.queue.editConflict":"这条排队消息已在其他页面更新。草稿已保留,请关闭后确认最新内容。","chat.queue.providerRejected":"未发送,可编辑后重试或删除","chat.queue.unknownDelivery":"发送状态待确认,不会自动重发","chat.controls.actionFailed":"设置没有更新成功,请重试。","chat.config.serviceTier":"服务等级","chat.config.serviceTierDefault":"默认","chat.config.unavailable":"模型设置暂时不可用,请重试。","agentConversation.interactionResponseFailed":"没有发送成功,请重试或在终端中继续。","chat.activation.title":"打开对话视图?","chat.activation.body":"Handmux 需要将当前 Agent 重新启动为托管模式。对话会在同一个终端窗格中继续。","chat.activation.terminal":"留在终端","chat.activation.activating":"正在准备当前会话…","chat.activation.waiting":"正在等待托管会话重新连接…","chat.activation.working":"准备中…","chat.activation.stale":"Agent 已发生变化。请返回终端,或重试。","chat.activation.timeout":"Agent 已启动,但对话视图尚未连接。你可以先在终端继续,稍后再试。","chat.activation.failed":"无法准备对话视图。请在终端继续,或重试。","chat.activation.unavailable":"当前无法安全切换此会话,请在终端中继续。","conversationTool.tool":"工具","conversationTool.run":"运行命令","conversationTool.runValue":"运行 {value}","conversationTool.edit":"编辑文件","conversationTool.editValue":"编辑 {value}","conversationTool.write":"写入文件","conversationTool.writeValue":"写入 {value}","conversationTool.read":"读取文件","conversationTool.readValue":"读取 {value}","conversationTool.web":"联网查询","conversationTool.image":"查看图片","conversationTool.imageValue":"查看图片 {value}","conversationTool.wait":"等待任务完成","conversationTool.waitShort":"等待任务","conversationTool.continue":"继续运行任务","conversationTool.continueShort":"继续任务","conversationTool.search":"搜索","conversationTool.searchValue":"搜索 {value}","conversationTool.find":"查找文件","conversationTool.findValue":"查找文件 {value}","conversationTool.webSearch":"联网搜索","conversationTool.webSearchValue":"联网搜索 {value}","conversationTool.webRead":"读取网页","conversationTool.webReadValue":"读取网页 {value}","conversationTool.todo":"更新待办","conversationTool.skill":"激活技能","conversationTool.skillValue":"激活技能 {value}","conversationTool.agent":"调用 Agent","conversationTool.agentValue":"调用 Agent {value}","conversationTool.call":"调用工具","conversationTool.callValue":"调用工具 {value}","conversationTool.diffStat":"新增 {added} 行,删除 {removed} 行","conversationTool.declined":"已拒绝","conversationTool.completed":"已结束","conversationTool.failed":"失败","conversationTool.success":"成功","conversationTool.running":"执行中","conversationTool.runningEllipsis":"执行中…","conversationTool.noReturn":"未返回","conversationTool.createdFile":"新建文件 · 新增 {added} 行","conversationTool.noChanges":"没有可显示的改动","conversationTool.mode":"执行模式","conversationTool.command":"执行的命令","conversationTool.output":"输出结果","conversationTool.imagePathMissing":"未提供可确定的图片路径","conversationTool.imageUnavailable":"图片无法读取,请检查文件和读取权限。","conversationTool.noOutput":"无输出","conversationTool.truncation.input.sizeLimit":"输入较长,仅展示已安全保留的部分;工具执行时使用了完整输入。","conversationTool.truncation.output.sizeLimit":"输出较长,仅展示已安全保留的部分;工具执行不受影响。","conversationTool.truncation.diff.sizeLimit":"变更内容较长,仅展示已安全保留的部分;实际修改不受影响。","conversationTool.truncation.provider_truncated":"Agent 返回的内容本身已截断,当前记录可能不完整。","conversationTool.truncation.redacted":"敏感内容已隐藏。","conversationTool.truncation.unavailable":"这部分工具记录暂不可用。","chat.outgoing.sending":"正在发送","chat.outgoing.queued":"已加入队列","chat.outgoing.sent":"已发送","chat.outgoing.steered":"已引导","chat.outgoing.failed":"发送失败","chat.outgoing.unknown":"未确认是否送达","chat.outgoing.retry":"重试","chat.outgoing.retryUnknown":"查询状态","chat.outgoing.resendTitle":"再次发送这条消息?","chat.outgoing.resendBody":"这条消息可能已经发送。继续会作为一条新消息再次发送,可能导致任务重复执行。","chat.outgoing.resendConfirm":"仍然发送","chat.favs":"常用","chat.tabMsg":"消息","chat.addPlaceholder":"消息 / 斜杠命令…","dock.upload.aria":"上传文件","dock.upload.title":"上传文件(存到家目录上传区,不进项目)","dock.upload.progress":"上传 {name}{tag}","dock.upload.failed":"上传失败:{names}","dock.upload.rejected":"不支持的文件类型:{names}","app.nameExists":"该名已存在","app.renameFailed":"重命名失败,请重试","app.deleteFailed":"删除失败,请重试","app.moveFailed":"移动失败,请重试","app.sessionGone":"会话「{name}」不存在,可能已关闭","app.docNotFound":"文件不存在","app.docTooLarge":"文件过大(超过 2MB)","app.docUnsupported":"不支持的文件或路径","app.docOpenFailed":"打开失败,请重试","app.preview":"预览","app.openPreview":"打开预览","app.ideas":"想法","app.files":"文件","app.settings":"设置","usage.title":"用量","usage.subscriptionTab":"订阅","usage.apiTab":"API","usage.win5h":"5 小时","usage.winWeekly":"本周","usage.winMonthly":"本月","usage.winGeneric":"{h} 小时窗口","usage.winPrimary":"额度","usage.winSecondary":"次级额度","usage.accountQuota":"账号额度","usage.modelLimits":"特定模型","usage.accountApiKey":"API Key 账号","usage.resetIn":"{t}后重置","usage.resetSoon":"即将重置…","usage.resetCredits":"剩余重置次数","usage.resetCreditsCount":"{n} 次","usage.resetCreditExpires":"到期:{time}","usage.claudeOff":"尚未接入 —— Claude 的 5h/周额度需要 handmux statusLine:","usage.claudePending":"暂无数据 —— 在 Claude 会话里发一条消息,再重新打开。","usage.codexOff":"本机未检测到 Codex。","usage.codexNoQuota":"Codex 暂未返回额度数据。","usage.setupRequired":"尚未接入用量采集。","usage.pending":"暂无额度数据,请在 Agent 会话中发一条消息后重新打开。","usage.unavailable":"本机暂未检测到可用的用量数据。","usage.loadFailed":"加载用量失败。","usage.refresh":"刷新","usage.refreshing":"正在刷新…","usage.refreshFailed":"无法刷新订阅用量,请检查连接后重试。","usage.updatedNow":"刚刚更新","usage.updatedMin":"{n} 分钟前更新","usage.updatedHr":"{n} 小时前更新","usage.updatedDay":"{n} 天前更新","usage.updatedCompactNow":"现在","usage.updatedCompactMin":"{n}分","usage.updatedCompactHr":"{n}时","usage.updatedCompactDay":"{n}天","usage.timeMark":"本窗口已过去的时间","usage.menu":"{provider} 用量选项","usage.show":"开启用量显示","usage.hide":"关闭用量显示","apiBalance.title":"API 余额","apiBalance.add":"添加 API","apiBalance.menu":"账户操作","apiBalance.menuAccount":"{account}({provider})账户操作","apiBalance.official":"官方数据","apiBalance.available":"API 可用","apiBalance.insufficient":"余额不足","apiBalance.notQueried":"尚未查询余额","apiBalance.noBalanceData":"暂无余额数据","apiBalance.currencyAvailable":"{currency} 可用余额","apiBalance.toppedUp":"充值余额","apiBalance.granted":"赠送余额","apiBalance.cash":"现金余额","apiBalance.voucher":"代金券余额","apiBalance.refreshing":"正在刷新…","apiBalance.refresh":"刷新","apiBalance.rename":"修改名称","apiBalance.replaceCredential":"替换凭证","apiBalance.deleteConfirm":"确认删除?再点一次","apiBalance.empty":"尚未添加 API","apiBalance.emptyHint":"添加 API 后查看厂家官方余额数据。","apiBalance.addAccount":"添加 API 账户","apiBalance.storageNote":"API Key 加密保存在运行 Handmux 的电脑上,完整 Key 不会返回浏览器。","apiBalance.account":"账户","apiBalance.provider":"厂家","apiBalance.chooseProvider":"选择厂家","apiBalance.name":"名称","apiBalance.credentialNote":"API Key 加密保存在运行 Handmux 的电脑上,完整 Key 不会返回浏览器。","apiBalance.secureRequired":"请通过 HTTPS 或本机 localhost 打开 Handmux 后提交凭证。","apiBalance.verifySave":"验证并保存","apiBalance.verifying":"正在验证…","apiBalance.form.add":"添加 API","apiBalance.form.rename":"修改名称","apiBalance.form.credential":"替换凭证","apiBalance.loadFailed":"无法加载 API 余额,请重试。","apiBalance.refreshFailed":"无法刷新余额,请重试。","apiBalance.saveFailed":"无法保存账户,请检查连接后重试。","apiBalance.deleteFailed":"无法删除账户,请重试。","apiBalance.error.invalid_credential":"凭证无效、无权查询或需完成厂家认证 · 请检查厂家账户,必要时替换凭证","apiBalance.error.rate_limited":"请求过于频繁 · 请稍后重试","apiBalance.error.provider_timeout":"厂家响应超时 · 请重试","apiBalance.error.provider_unreachable":"暂时无法连接厂家 · 请重试","apiBalance.error.unsupported_response":"厂家返回了暂不支持的数据 · 请重试","apiBalance.error.storage_unavailable":"已保存的 API 账户暂不可用 · 请勿直接清空,否则账户无法恢复。请先备份 ~/.handmux/api-accounts.json、api-accounts.key、.corrupt.* 与 .unavailable;恢复匹配的 api-accounts.key 和 api-accounts.json(必要时从 .corrupt.* 还原数据文件),最后移除 .unavailable 并重启 Handmux","apiBalance.error.conflict":"账户已在其他位置更新 · 请重新打开后再试","apiBalance.error.account_limit_reached":"最多可保存 1000 个 API 账户 · 请删除不用的账户后再试","apiBalance.error.not_found":"账户已在其他位置删除 · 请关闭此窗口后刷新","app.renameSession":"重命名会话","app.renameWindow":"重命名窗口","app.manageWindow":"窗口管理","app.moveLeft":"◀ 左移","app.moveRight":"右移 ▶","app.deleteWindow":"删除窗口","pane.splitH":"左右分屏","pane.splitV":"上下分屏","pane.manage":"管理分屏","pane.manageTitle":"分屏管理","pane.close":"关闭此格","pane.closeConfirm":"确认关闭?再点一次","pane.splitFailed":"分屏失败","pane.closeFailed":"关闭失败","resize.windowWidth":"窗口宽度","resize.paneWidth":"窗格宽度","resize.columns":"{n} 列","resize.restore":"恢复","resize.restoreAutoWidth":"恢复自动宽度","resize.restoreRatio":"恢复分屏比例","app.deleteLastWindowConfirm":"这是最后一个窗口,删除将关闭整个会话!再点一次","app.deleteConfirm":"确认删除?再点一次","app.cannotLocate":"无法定位","app.pickItsDir":",请选它所在的目录:","app.noBoundSession":"还没有绑定会话","app.tapToBind":"点此绑定一个","app.selectSessionHint":"点击左上角 ☰ 选择会话","app.backToExit":"再按一次返回键退出","settings.title":"设置","settings.group_global":"全局设置","settings.group_general":"通用","settings.group_voice":"语音转文字","settings.voice_enabled":"是否已开启","settings.voice_on":"已开启","settings.voice_off":"未开启","settings.voice_provider":"当前服务商","settings.voice_profile_tencent_streaming":"腾讯云实时语音识别","settings.voice_profile_tencent_sentence":"腾讯云一句话识别","settings.voice_profile_xfyun":"讯飞语音听写","settings.voice_not_configured":"未配置","settings.voice_filler_filter":"语气词过滤","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"不支持","settings.voice_setup_hint":"请在终端执行 handmux setup,然后进入“语音输入”完成设置。","settings.project_task_beta":"项目任务 Beta","project.root.projects":"项目","project.root.sessions":"会话","project.add":"添加项目","project.archivedProjects":"已归档项目({n})","project.empty":"还没有项目","project.emptyHint":"选择一个本地目录,开始记录需求与任务。","project.manage":"项目管理","project.tasks":"任务","project.drafts":"草稿","project.noTasks":"还没有正式任务","project.noDrafts":"还没有草稿","project.newTask":"新建任务","project.newDraft":"记录草稿","project.storeUnavailable":"项目数据暂时不可用","project.tryAgain":"重试","project.task.title":"标题","project.task.objective":"目标","project.task.acceptance":"验收标准(每行一条)","project.task.scope":"范围与非目标","project.task.constraints":"约束","project.task.references":"引用(每行一个链接或路径)","project.task.priority":"优先级","project.task.priority.none":"无","project.task.priority.high":"高","project.task.priority.medium":"中","project.task.priority.low":"低","project.task.saveDraft":"保存草稿","project.task.saveTask":"保存为任务","project.task.save":"保存","project.task.edit":"编辑要求","project.task.promote":"转为任务","project.task.cancel":"取消任务","project.task.archive":"归档","project.task.cancelConfirm":"取消后任务将只读,且不能恢复为待开始。确定继续吗?","project.task.archiveConfirm":"归档后将从常规列表隐藏,但不会删除数据。确定继续吗?","project.task.discardConfirm":"尚未保存的修改会丢失。确定返回吗?","project.task.conflict":"这项任务已在其他页面更新。请刷新后重新确认你的修改。","project.task.actionConflict":"这项任务已在其他页面更新,已加载最新版本。请确认当前状态。","project.task.loadLatest":"加载最新版本","project.task.request":"想完成什么?","project.task.requestPlaceholder":"直接描述你的需求","project.task.requestHint":"标题会从第一条非空行自动生成,其他信息由 Agent 在处理时整理。","project.task.create":"创建任务","project.management.overview":"概览","project.management.context":"规范记忆","project.management.git":"Git","project.management.memoryOff":"Project Memory 尚未启用","project.management.readOnly":"只读","project.management.projectRoot":"项目目录","project.management.repositoryRoot":"代码仓库","project.management.defaultAgent":"默认 Agent","project.management.notSet":"未设置","project.management.isolation":"任务代码位置","project.management.execution.project-root":"项目目录","project.management.execution.worktree":"独立工作区","project.management.guidance":"项目规范","project.management.guidanceFailed":"暂时无法读取项目规范,请检查目录权限后重试。","project.management.noGuidance":"项目根目录下没有 AGENTS.md 或 CLAUDE.md。","project.management.memoryHint":"以后可在这里查看并确认项目长期记忆。","project.management.conflict":"项目信息已在其他页面更新,已加载最新版本。请确认后重试。","project.management.notGit":"这不是 Git 仓库","project.management.notGitHint":"任务仍可正常管理,只是不显示代码改动。","project.management.gitFailed":"暂时无法读取 Git 状态,请检查仓库后重试。","project.management.gitClean":"工作区没有未提交改动。","project.management.gitChanges":"{n} 个文件有未提交改动","project.management.history":"历史任务","project.management.canceled":"已取消({n})","project.management.archived":"已归档({n})","project.management.historyEmpty":"暂无内容","project.management.historyFailed":"暂时无法读取历史任务,请稍后重试。","project.management.archiveProject":"归档项目","project.management.archiveConfirm":"归档后,项目及其中未归档的任务都会从常规入口隐藏,但数据不会删除。确定继续吗?","settings.group_terminal":"终端","settings.group_chat":"对话","settings.group_notifications":"通知","settings.group_about":"关于","settings.terminal_font_size":"终端字体大小","settings.terminal_font_decrease":"减小终端字体","settings.terminal_font_increase":"增大终端字体","settings.terminal_font_auto":"自适应","settings.terminal_font_auto_title":"按高度自动适配","settings.conversation_font_size":"对话字体大小","settings.conversation_font_decrease":"减小对话字体","settings.conversation_font_increase":"增大对话字体","settings.conversation_font_default":"恢复默认","settings.conversation_font_hint":"可在 10–20px 之间以 1px 为步进调整;仅影响对话消息正文及其中的 Markdown 和代码。","settings.keyboard_mode":"键盘模式","settings.keyboard_mode_auto":"自动识别","settings.keyboard_mode_mobile":"手机","settings.keyboard_mode_desktop":"电脑","settings.keyboard_mode_hint":"仅应用于当前浏览器;识别不准时可手动指定。","settings.terminal_transport":"终端传输模式","settings.terminal_transport_live":"实时推送","settings.terminal_transport_snapshot":"快照拉取","settings.terminal_transport_hint":"实时推送使用 WebSocket;网络较差时会自动降级为快照拉取,持续稳定 30 秒后尝试恢复实时推送。","settings.snapshot_interval":"活跃时刷新频率","settings.snapshot_interval_hint":"终端空闲后会自动降低频率,减少流量和资源占用。","boot.loading":"正在加载","boot.chat_empty":"发送你的第一条消息,对话就开始啦","settings.conversation_view_agent":"{agent} 对话视图","settings.experimental":"实验性","settings.group_agent_integration":"Agent 集成","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"处理中…","settings.agent_integration_load_error":"无法检查 Agent 状态。","settings.agent_integration_action_error":"接入失败,请在电脑上运行:","settings.agent_integration_conflict_hint":"{agent} 已有其他配置,请在电脑上诊断:","settings.agent_integration_not_installed_hint":"这台电脑尚未安装 {agent}。","settings.agent_integration_initialize_first_hint":"请先在电脑上运行一次 {agent},再回来启用。","settings.agent_integration_enable":"启用","settings.agent_integration_repair":"修复","settings.agent_integration_loading":"正在检查…","settings.agent_integration_status_ready":"已接入","settings.agent_integration_status_not_enabled":"未启用","settings.agent_integration_status_needs_repair":"需要修复","settings.agent_integration_status_conflict":"需要处理","settings.agent_integration_status_not_installed":"未安装","settings.chat_tone":"对话配色","settings.chat_tone_dusk":"暖夜","settings.chat_tone_ink":"暖金","settings.chat_tone_light":"暖黄","settings.chat_tone_hint":"对话视图的色调,均为暖色系。暖夜=暖棕暗、暖金=品牌橄榄金、暖黄=奶油亮。","settings.path_highlight":"高亮文件路径","settings.path_highlight_hint":"给终端里可点开的文件路径加底色。无论开关与否,路径都可点开。","settings.whats_new":"新功能","settings.view_changelog":"查看更新日志","settings.reload_app":"重新加载应用","settings.has_update":"有更新","settings.version":"版本","settings.feedback":"反馈与交流","settings.feedback_issues":"GitHub 反馈","settings.feedback_group":"微信用户群","settings.feedback_hint":"bug、想法都欢迎——Issue 会被跟踪处理;微信群反馈直达。","settings.update_available":"有新版本 v{v} 可用","settings.update_more":"另有 {n} 个版本更新","settings.update_how":"在电脑上运行","settings.push_notifications":"推送通知","settings.notify_on":"已开启 ✓","settings.notify_enable":"开启设备通知","settings.notify_enabled":"已开启,应会收到一条欢迎通知","settings.notify_disabled":"已关闭","settings.notify_failed":"操作失败","settings.notify_disable_title":"关闭推送通知?","settings.notify_disable_hint":"关闭后,这台设备将不再收到「需要你」「已完成」或脚本发送的推送。你可以随时重新开启。","settings.notify_disable_confirm":"关闭推送","settings.processing":"处理中","settings.push_hint":"监听「需要你」和「已完成」:所关注会话需要你授权/回答,或一个回合刚做完时,推送到此设备。","settings.push_unsupported":"推送需要 Chrome 或 Safari 浏览器","settings.preview_site":"预览站点","settings.preview_static_site":"预览静态站点","settings.preview_running_static":"静态预览 运行中","settings.preview_remain_title":"剩余有效期","settings.preview_remain":"剩 {time}","settings.preview_renew":"续期","settings.preview_confirm_stop":"确认停止","settings.preview_stop":"停止","settings.preview_name":"名称:{name}","settings.preview_port":"(端口 :{port})","settings.preview_type":"预览类型","settings.preview_off":"不开启","settings.preview_static":"静态","settings.preview_off_hint":"未开启预览。选择「静态」开始。","settings.preview_off_hint_both":"未开启预览。选择「静态」或「动态」开始。","settings.preview_pick_dir":"选择目录启动","settings.preview_static_hint":"选一个含 index.html 的目录,在手机上预览。","settings.preview_port_placeholder":"端口,如 3000","settings.preview_port_label":"端口","settings.preview_starting":"启动中…","settings.preview_start":"启动","settings.dir_picker_hint":"选择要预览的静态站点目录(含 index.html)","settings.err_port_not_listening":"该端口未在监听,请确认服务已启动","settings.err_bad_port":"端口不合法(1–65535)","settings.err_start_failed":"启动失败","filebrowser.openDirFailed":"无法打开该目录","filebrowser.copiedPath":"已复制路径:{abs}","filebrowser.mkdirFailed":"新建目录失败(名称非法或已存在)","filebrowser.downloading":"下载 {name}","filebrowser.downloadFailed":"下载失败","filebrowser.uploading":"上传 {name}{tag}","filebrowser.uploadFailed":"上传失败","filebrowser.uploadPartialFailed":"以下文件上传失败:{names}","filebrowser.uploadRejected":"不支持的文件类型:{names}","filebrowser.sessionDir":"会话目录","filebrowser.jumpToSessionDir":"跳到当前会话目录","filebrowser.parentDir":"上级目录","filebrowser.rootSelect":"切换根目录(家目录 / 临时目录)","filebrowser.pathPlaceholder":"输入路径(实时筛选/跳转)","filebrowser.newFolder":"新建文件夹","filebrowser.createBtn":"创建","filebrowser.uploadFile":"上传文件","filebrowser.uploadToCurrentDir":"上传到当前目录","filebrowser.enterSubdirToUpload":"请进入一个子目录上传","filebrowser.folderNamePlaceholder":"文件夹名称","filebrowser.uploadPendingTo":"把「{name}」上传到当前目录","filebrowser.enterSubdirFirst":"(请先进入一个子目录)","filebrowser.upload":"上传","filebrowser.savedToDownloads":"已保存「{name}」到「下载」文件夹,可在系统文件管理器查看","filebrowser.noMatches":"没有匹配的文件或目录","filebrowser.tooMany":"共 {total} 项,只显示前 {shown} 项——在路径框输入关键词可筛选","filebrowser.previewUnsupported":"暂不支持该类型文件的预览,点右侧按钮可下载","filebrowser.copyAbsPath":"复制绝对路径","filebrowser.download":"下载","filebrowser.pickThisDir":"选定此目录 {path}","filebrowser.downloadConfirm":"下载 {name}?","filemanager.files":"文件","filemanager.closeTab":"关闭标签","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"目录","git.errReadRepo":"无法读取仓库","git.errLoad":"加载失败","git.noRepoInDir":"这个目录还不是 git 仓库 —— 换一个目录,或在这里 git init 一下。","git.outsideRoots":"这个目录在 handmux 可访问范围之外 —— 只开放主目录和 /tmp。把仓库放到主目录下,就能在这里查看了。","git.errReadDir":"无法读取该目录","git.commitDetail":"提交详情","git.diff":"差异","git.bindRepo":"绑定仓库","git.collapse":"收起","git.currentBranch":"当前分支","git.switchViewedBranch":"切换查看的分支","git.switchBranch":"切换分支","git.noBranches":"暂无分支","git.noRepoBound":"未绑定仓库,点左上角「+」选择一个目录。","git.changes":"变更","git.commits":"提交","git.pullToLoadMore":"下拉加载更多","git.pickerHint":"选择一个目录,自动查找其中的 git 仓库","git.cleanTree":"工作区干净","git.noCommits":"暂无提交","git.noDiff":"无差异","git.fontSmaller":"缩小字体","git.fontLarger":"放大字体","git.diffTruncated":"diff 过大,已截断","cmd.panel":"命令面板","cmd.title":"命令","cmd.empty":"还没有命令,发送一条或保存常用","cmd.favorites":"常用","cmd.scopeGlobal":"全局 · 所有会话","cmd.recent":"最近","cmd.scopeSession":"仅本会话","cmd.favorite":"收藏","cmd.itemConflict":"该快捷项已存在,请更换内容或选择其他列表。","cmd.unfavorite":"取消收藏","doc.home":"最近","doc.read":"朗读","doc.pauseRead":"暂停朗读","doc.resumeRead":"继续朗读","doc.stopRead":"停止朗读","doc.rate":"语速","doc.fontSmaller":"缩小字体","doc.fontLarger":"放大字体","inbox.view.working":"进行中","inbox.view.done":"已完成","inbox.view.needs":"需要你","inbox.view.error":"出错","push.unsupported":"推送通知需要 Chrome 或 Safari 浏览器","push.iosAddToHome":'iOS 需先把本站"添加到主屏幕",从主屏图标打开后再开启',"a2hs.title":"把 handmux 添加到主屏","a2hs.lead":"像 App 一样打开——全屏、没有地址栏。在 iPhone 上,pane 需要你时的推送也靠它送达。","a2hs.install":"安装 handmux","a2hs.ios1":"点 Safari 里的分享按钮(⬆︎ 方框)。","a2hs.ios2":"点「更多」,或向下滑动列表。","a2hs.ios3":"选「添加到主屏幕」,再点「添加」。","a2hs.iosHint":"Safari 里:分享 → 更多 → 添加到主屏幕。","a2hs.iosOpenSafari":"当前不是 Safari。请在 Safari 里打开本页再添加到主屏——其他 iOS 浏览器无法安装。","a2hs.androidManual":"打开浏览器菜单(⋮),选「添加到主屏幕」或「安装应用」。","a2hs.later":"以后再说","push.permissionTimeout":"系统未返回通知授权结果,请在系统设置中检查 handmux 或浏览器的通知权限后重试","push.permissionDenied":"通知权限被拒绝","push.swRegisterTimeout":"注册通知服务超时,请检查网络后重试","push.swRegisterFailed":"注册通知服务失败:{reason}。请清除本站数据后重新打开再试","push.swTimeout":"通知服务已注册但未能激活,请清除本站数据后重新打开再试","push.unknownReason":"原因未知","push.configTimeout":"读取推送配置超时,请检查与 handmux 服务的连接后重试","push.browserTimeout":"浏览器推送服务没有响应;Android Chrome 请确认 Google Play 服务可用后重试","push.noVapid":"服务端未配置推送(VAPID)","push.reportTimeout":"订阅已创建,但上报服务器超时,请检查连接后重试","push.subscriptionExpired":"Chrome 返回的推送订阅已经失效,已为你重置;请再次点击开启通知","push.deliveryRejected":"推送服务拒绝了新订阅,请检查服务器日志后重试","push.subscribeFailed":"订阅上报失败","push.sendFailed":"发送失败","api.loadFailed":"加载失败","api.uploadFailed":"上传失败","upload.title":"上传中","upload.processing":"已发送,服务器接收中…","api.uploadBadDir":"无法上传到该目录","api.uploadDuplicate":"已存在同名文件","api.uploadTooLarge":"文件过大(上限 50MB)","api.uploadBadType":"不支持的文件类型","time.secAgo":"{n}秒前","time.minAgo":"{n}分钟前","time.hourAgo":"{n}小时前","time.dayAgo":"{n}天前","time.expired":"已过期","time.minutes":"{n} 分钟","settings.script_push":"脚本推送","settings.script_push_open":"怎么用","settings.script_push_hint":"让电脑上的脚本把一条通知推到手机。","scriptPush.title":"脚本推送","scriptPush.intro":"让电脑上的脚本复用 handmux 的推送通道:在运行 handmux 的电脑上,一条 handmux push 命令就能把通知推到手机——构建、CI 或长任务结束时提醒你,不用另接推送服务。","scriptPush.copied":"已复制","scriptPush.session_placeholder":"<会话名>","scriptPush.device_placeholder":"<本设备key>","scriptPush.scope_all":"推给所有已订阅设备(默认)","scriptPush.scope_session":"只推某个会话里的设备","scriptPush.scope_device":"只推这台设备","scriptPush.device_key_note":"上面这串 key 就是这台设备的,复制即用。","scriptPush.device_need_enable":"先在上方开启推送通知,才会生成这台设备的 key。","scriptPush.opts_label":"可选参数(追加到上面任意一条后面)","scriptPush.opt_tag":"--tag <标签> —— 相同 tag 会覆盖上一条推送,而不是堆叠。","scriptPush.opt_url":"--url <路径> —— 点击通知时打开这个路径。","scriptPush.reliability":"注意:Web 推送经手机系统(FCM/APNs)中转,属尽力而为——省电模式、离线或厂商策略都可能延迟或丢弃它,并不保证实时送达。对送达强依赖的场景,请改用专门的 IM(微信 / Telegram bot 等)。","pushInbox.title":"脚本推送记录","pushInbox.empty":"还没有脚本通知","pushInbox.delete":"删除","pushInbox.justNow":"刚刚","pushInbox.minutesAgo":"{n}分钟前","pushInbox.hoursAgo":"{n}小时前","pushInbox.detailTitle":"脚本推送详情","pushInbox.openUrl":"打开链接","pushInbox.expired":"这条消息已过期","pushInbox.back":"返回","pushInbox.markAllRead":"全部已读","pushInbox.unreadCount":"{n} 未读","pushInbox.loadFailed":"脚本推送记录加载失败,请检查连接后重试","pushInbox.deleteFailed":"脚本推送删除失败,消息已保留,请重试","pushInbox.retry":"重试","pushInbox.deliveryPending":"发送中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失败","pushInbox.deliveryReasonExpired":"订阅已失效","pushInbox.deliveryReasonRateLimited":"推送服务限流","pushInbox.deliveryReasonUnavailable":"推送服务暂不可用","pushInbox.deliveryReasonRejected":"推送服务已拒绝","pushInbox.deliveryReasonNetwork":"网络错误","pushInbox.deliveryReasonNotConfigured":"服务端未配置推送","pushInbox.deliveryReasonUnknown":"未知原因","workspace.bootDetected":"检测到电脑已重启","workspace.tmuxDetected":"检测到 tmux 已重新启动","workspace.summary":"上次工作区 · {sessions} 个会话 · 保存于 {time}","workspace.restoreLast":"恢复上次工作区","workspace.partialCard":"仍有 {failures} 个会话需要处理","workspace.unknownTime":"未知时间","workspace.savedAt":"保存于 {time}","workspace.topologySummary":"{sessions} 个会话 · {windows} 个窗口 · {panes} 个窗格","workspace.planSummary":"将恢复 {restore} 个会话;{already} 个已经存在","workspace.renameRule":"仅当当前已有同名会话时,恢复名称才会添加 -restored 后缀。","workspace.nonDestructive":"当前会话不会被修改、重命名或停止。","workspace.progress":"正在恢复 {completed} / {total}…","workspace.progressDone":"已恢复 {completed} / {total}","workspace.complete":"工作区已恢复。","workspace.completedSummary":"本次恢复:{sessions} 个会话 · {windows} 个窗口 · {panes} 个窗格","workspace.rebindHint":"恢复的会话不会自动显示;可重新选择要绑定到这台手机的会话。","workspace.rebind":"重新绑定会话","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"未知会话","workspace.restore":"恢复","workspace.ignore":"忽略此备份","workspace.protectionTitle":"工作区未受保护","workspace.protection.live-corrupt":"工作区状态副本已损坏;请检查磁盘和 ~/.handmux 权限,然后重启 handmux。","workspace.protection.live-unavailable":"无法读写工作区状态;请检查磁盘空间和 ~/.handmux 权限,然后重启 handmux。","workspace.protection.unknown":"后台快照暂时不可用;请检查电脑上的 handmux 日志。","workspace.error.restore-interrupted":"恢复已中断;请重试此备份","workspace.error.checkpoint-not-found":"此备份已不可用;请刷新后选择其它备份","workspace.error.storage-full":"工作区存储空间不足;请释放磁盘空间后重试","workspace.error.permission-denied":"无法写入工作区存储;请检查权限后重试","workspace.error.plan-failed":"恢复计划已变化;请刷新后重试","workspace.error.agent-unavailable":"Agent 无法续接;请打开已恢复的 shell 后手动重试","workspace.error.tmux-unavailable":"tmux 不可用;请确认 tmux 已运行后重试","workspace.error.restore-failed":"会话未恢复;请检查 handmux 日志后重试","workspace.error.operation-not-found":"此恢复任务已不可用;请重新恢复此备份","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"工作目录不可用;已在主目录中恢复","workspace.warning.layout-fallback":"窗格布局无法完整恢复;已保留默认布局","workspace.warning.agent-warning":"Agent 未能自动续接;已恢复的 shell 仍可使用","workspace.warning.live-reconcile-failed":"实时工作区状态核对失败;请检查 handmux 日志","workspace.warning.workspace-unavailable":"工作区存储暂时不可用;请检查磁盘空间和权限","workspace.warning.restore-warning":"恢复时出现了可继续处理的提醒;请检查恢复结果"},JO={"terminal.transport_live":"即時","terminal.transport_snapshot":"快照","terminal.transport_detail_title":"終端傳輸狀態","terminal.transport_detail_configured":"設定模式","terminal.transport_detail_current":"目前模式","terminal.transport_detail_connection":"連線狀態","terminal.transport_detail_manual":"你已手動選擇快照拉取,不會自動切換。","terminal.transport_detail_live":"終端正在正常接收即時推送。","terminal.transport_detail_fallback":"即時推送不穩定,已自動降級為快照拉取。","terminal.transport_detail_unavailable":"即時通道無法建立,請檢查反向代理是否支援 WebSocket。","terminal.transport_detail_waiting":"正在等待連線穩定,隨後嘗試恢復即時推送。","terminal.transport_detail_retry":"預計 {seconds} 秒後嘗試恢復即時推送。","terminal.connection_connecting":"偵測中","terminal.connection_good":"良好","terminal.connection_degraded":"一般","terminal.connection_poor":"較差","settings.terminal_transport":"終端傳輸模式","settings.terminal_transport_live":"即時推送","settings.terminal_transport_snapshot":"快照拉取","settings.terminal_transport_hint":"即時推送使用 WebSocket;網路較差時會自動降級為快照拉取,持續穩定 30 秒後嘗試恢復即時推送。","settings.snapshot_interval":"活躍時更新頻率","settings.snapshot_interval_hint":"終端閒置後會自動降低頻率,減少流量和資源使用。","terminal.disconnected":"連線中斷,正在重新連線…","terminal.paneMissing":"窗格已關閉,請切換到其他窗格。","common.save":"儲存","common.cancel":"取消","common.confirm":"確認","common.ok":"確定","common.close":"關閉","common.delete":"刪除","common.copy":"複製","conversationCopy.line":"整行","conversationCopy.paragraph":"整段","common.rename":"重新命名","common.create":"新增","common.back":"返回","common.open":"開啟","common.loading":"載入中…","common.done":"完成","common.retry":"重試","app.browser":"網頁預覽器","browser.openTabs":"開啟的網頁預覽器分頁","browser.history":"最近瀏覽","browser.closeTab":"關閉 {title}","browser.newTab":"新增分頁","browser.minimize":"收起","browser.back":"返回","browser.forward":"前進","browser.address":"網址","browser.addressPlaceholder":"輸入網址或連接埠","browser.addressOrDirectoryPlaceholder":"輸入網址,或選擇目錄","browser.refresh":"重新整理","browser.stop":"停止載入","browser.viewMode":"頁面寬度","browser.narrowWidth":"窄螢幕","browser.wideWidth":"寬螢幕","browser.closeTiming":"背景分頁自動關閉","browser.minutes":"{value} 分鐘","browser.neverClose":"永不關閉","browser.clearHistory":"清除","browser.emptyHistory":"尚無最近瀏覽","browser.loadFailed":"無法載入此網頁,請檢查網址後再試。","browser.retry":"重試","browser.consentTitle":"網頁預覽器","browser.consentBody":"Handmux 會將網頁嵌入目前視窗。它不是真正的瀏覽器,適合預覽開發服務、localhost、內網及允許嵌入的網站;也可從 Home 選擇電腦上的靜態目錄。","browser.consentComputer":"連線方式:手機直連使用手機網路。電腦代理的請求由電腦發出,可存取電腦所在的內網與 localhost,但不會將它們公開。","browser.consentPrivate":"登入狀態:直連與代理不共用 Cookie 和登入狀態;代理工作階段也依裝置隔離。","browser.consentLimits":"相容限制:手機直連可能被網站的 iframe 或 CSP 政策阻擋,而且 Handmux 未必能判斷原因。電腦代理會轉送並改寫網頁,也不保證與所有網站相容。需要完整瀏覽功能時,請用 Safari、Chrome 或系統瀏覽器開啟。","browser.consentIdle":"背景分頁:預設在 10 分鐘後關閉。直連網站的 Cookie 仍保留在手機瀏覽器中。","browser.about":"關於網頁預覽器","browser.acknowledge":"好的","browser.directMode":"手機直連","browser.proxyMode":"透過電腦代理","browser.directBadge":"直連","browser.proxyBadge":"代理","browser.staticBadge":"靜態","browser.chooseDirectory":"選擇目錄","browser.staticOpening":"正在開啟目錄…","browser.directoryPickerHint":"選擇包含網頁檔案的目錄。","browser.switchMode":"切換瀏覽模式","browser.menu":"網頁預覽器選單","browser.connectionMode":"連線方式","browser.pageWidth":"頁面寬度","browser.requestSiteVersion":"向網站請求","browser.mobileSite":"手機版","browser.desktopSite":"電腦版","browser.zoomPage":"縮放網頁","browser.resetZoom":"重設網頁縮放","browser.proxyLogin":"代理登入","browser.proxyLoginHelpLabel":"代理登入說明","browser.proxyLoginHelp":"是否將代理 Cookie 加密儲存在執行 Handmux 的電腦上,以便重新啟動後保持登入狀態。","browser.siteProxyCookie":"本站代理 Cookie","browser.siteCookieHelpLabel":"本站代理 Cookie 說明","browser.siteCookieHelp":"這裡只會清理目前裝置中符合本站真實網址的代理 Cookie。父網域 Cookie 可能讓相關內部網站一起登出,手機直接連線 Cookie 不受影響。","browser.openMode":"選擇開啟方式","browser.historyMore":"更多開啟方式","browser.historyActions":"更多操作","browser.proxyLimitHint":"電腦代理會轉送並改寫網頁,不保證與所有網站相容。","browser.proxyUnavailable":"請在電腦終端執行 handmux setup,選擇「網頁預覽器」設定代理網域;設定前只能使用手機直連。","browser.urlInvalid":"請輸入有效的 HTTP 或 HTTPS 位址。","browser.tryProxy":"改用電腦代理","browser.openExternal":"用系統瀏覽器開啟","browser.clearSiteLogin":"清理本站代理 Cookie","browser.clearAllLogin":"清理全部代理 Cookie","browser.clearSiteLoginConfirm":"清理目前裝置的本站代理登入狀態?父網域 Cookie 也可能影響相關內部系統。","browser.clearAllLoginConfirm":"清理目前裝置的全部代理登入狀態?手機直連登入不受影響。","browser.deleteHistoryEntry":"刪除此記錄","browser.profileSaveFailed":"無法儲存代理登入設定,請檢查伺服器連線後重試。","browser.profileClearFailed":"清理未完全成功,請檢查伺服器連線與儲存權限後重試。","browser.profileSyncFailed":"無法同步代理登入設定。請重試,或改用手機直連。","browser.profileRecoveryWarning":"無法復原已儲存的代理登入資料,目前裝置的代理登入狀態已重設。","browser.retention1":"1 天","browser.retention7":"7 天","browser.retention30":"30 天","browser.retentionNotSaved":"不儲存","browser.retentionNever":"長期儲存","settings.browserPersistLogin":"在電腦上持久儲存代理 Cookie","settings.browserPersistLoginHint":"只儲存在目前裝置。關閉後,目前分頁與登入狀態仍會保留,直到清理或到期。","settings.browserRetention":"代理登入保留","settings.browserDisablePersistConfirm":"停止儲存目前裝置後續的代理登入變更?目前分頁與登入狀態仍會保留。","token.title":"需要存取 Token","token.placeholder":"貼上 HANDMUX_TOKEN","settings.language":"語言 Language","settings.browserDefaultMode":"網頁預設開啟方式","settings.browserDefaultModeHint":"用於網址列新分頁,以及未儲存開啟方式的歷史記錄。","settings.browserEnabled":"網頁預覽器","settings.browserEnabledHint":"分頁僅屬於目前裝置。關閉後會關閉全部分頁,但保留歷史記錄。","home.empty":"尚未開啟任何檔案","home.emptyHint":"切換到「新增」挑選一個","home.remove":"移除","drawer.title":"工作階段","drawer.empty":"尚未綁定工作階段","drawer.unbind":"解除綁定","drawer.bind":"綁定工作階段","drawer.logout":"登出","windowbar.newWindow":"新增視窗","rename.new_name":"新名稱","rename.name_rule":"只能使用字母、數字、連字號(≤16)","rename.failed":"重新命名失敗,請重試","rename.saving":"儲存中…","newwindow.title":"新增視窗","newwindow.window_name":"視窗名稱(選填)","newwindow.name_placeholder":"留空自動命名 · 字母/數字/連字號 ≤16","newwindow.name_rule":"只能使用字母、數字、連字號(≤16)","newwindow.start_dir":"起始目錄","newwindow.session_dir_named":"{dir}(工作階段目錄)","newwindow.session_dir_default":"工作階段目錄(預設)","newwindow.choose":"選擇","newwindow.reset_to_session_dir":"重置為工作階段目錄","newwindow.creating":"建立中…","startup.label":"啟動命令(選填)","startup.aria":"啟動命令","startup.preset_shell":"空白 Shell(預設)","startup.preset_claude":"claude(啟動 Claude Code)","startup.preset_claude_continue":"claude -c(繼續上次工作階段)","startup.preset_codex":"codex(啟動 Codex CLI)","startup.custom":"自訂…","startup.custom_placeholder":'例如 claude "修復登入 bug"',"bind.title":"綁定工作階段","bind.sessionName":"工作階段名稱","bind.pickSession":"選擇要綁定的工作階段","bind.newSession":"+ 新增工作階段","bind.modeNew":"新增工作階段","bind.modeExisting":"既有工作階段","bind.alreadyExists":"此工作階段已存在","bind.bind":"綁定","bind.checking":"驗證中…","bind.createAndOpen":"新增並開啟","bind.creating":"建立中…","bind.createHint":"工作階段「{name}」不存在,點「新增並開啟」建立","bind.alreadyBound":"已綁定此工作階段","bind.createFailed":"建立失敗,請重試","bind.invalidName":"只能使用字母、數字、連字號(≤16)","bind.desktopHint":"這裡的工作階段(包括手機新建的),電腦上一條命令即可接管:handmux open <名稱>","bind.checkFailed":"驗證失敗,請重試","bind.startDir":"起始目錄","bind.homeDirDefault":"主目錄(預設)","bind.choose":"選擇","bind.reset":"重置","actionsheet.confirmAgain":"確認?再點一次","dirpicker.title":"選擇目錄","inbox.title":"收件匣","inbox.working":"進行中","inbox.done":"已完成","inbox.needs":"需要你","inbox.error":"出錯","inbox.clearDone":"清除結果","inbox.empty":"目前沒有面板狀態","inbox.enableTitle":"開啟 Claude Code 狀態與通知","inbox.enableHint":"Claude Code 收件匣需要 Agent hooks。Codex CLI 請使用 Handmux 託管模式。","inbox.enableBtn":"開啟","inbox.enabling":"開啟中…","inbox.enableFailed":"開啟失敗——請查看伺服器日誌。","idea.title":"想法","idea.editPlaceholder":"編輯想法…","idea.addPlaceholder":"記錄一條想法…","idea.add":"新增","idea.empty":"還沒有想法,記錄一條吧","idea.dragSort":"拖曳排序","idea.fillInput":"填入輸入框","idea.send":"傳送","doclink.title":"開啟檔案","changelog.title":"新功能","preview.static":"靜態預覽","preview.remainTitle":"剩餘有效期 — 點擊續期 / 停止","preview.toPcView":"切換到電腦檢視","preview.toMobileView":"切換到手機檢視","preview.pcView":"電腦檢視","preview.mobileView":"手機檢視","preview.refresh":"重新整理","preview.minimize":"收起","preview.ttlDialog":"預覽有效期","preview.renew":"續期(重置為 1 小時)","preview.stop":"停止預覽","preview.iframeTitle":"預覽","preview.zoomOut":"縮小","preview.zoomIn":"放大","imageviewer.loadFailed":"圖片載入失敗","imageviewer.saved":"已儲存,可在相簿或「下載」中查看","imageviewer.shareUnsupported":"圖片分享需要 Chrome 或 Safari 瀏覽器","imageviewer.zoomOut":"縮小","imageviewer.zoomIn":"放大","imageviewer.imageTitle":"圖片","imageviewer.saveImage":"儲存圖片","imageviewer.shareImage":"分享圖片","mic.stop":"停止語音輸入","mic.start":"語音輸入","mic.recognizing":"正在識別語音","mic.error.tencentPermission":"騰訊雲拒絕了辨識:請為目前 SecretId 授予 asr:SentenceRecognition 權限後重試。","mic.error.tencentCredentials":"騰訊雲憑證無效,請在 handmux setup 中檢查 AppId、SecretId 和 SecretKey。","mic.error.browserPermission":"沒有麥克風權限,請在瀏覽器網站設定中允許麥克風後重試。","mic.error.device":"無法使用麥克風,請檢查裝置是否存在或被其他程式占用。","mic.error.secureContext":"目前網址不能使用麥克風,請改用 HTTPS 或 localhost 開啟 Handmux。","mic.error.tooLong":"錄音過長,請縮短後重試。","mic.error.notSelected":"目前語音模式尚未生效,請重新啟動 Handmux 後重試。","mic.error.noSpeech":"未辨識到語音,請重試。","mic.error.network":"語音服務連線失敗,請檢查網路後重試。","mic.error.provider":"語音服務拒絕了要求:{reason}","mic.error.generic":"語音輸入失敗,請重試。","dock.send":"傳送","dock.send.hint":"點傳送 · 長按填入","dock.phrases":"常用語","dock.attach":"上傳","dock.history":"歷史","history.empty":"還沒有發送記錄","history.scope":"僅目前視窗的記錄","dock.input.placeholder":"說點什麼…","dock.input.enterDraft":"按 Shift + Enter 進入草稿模式","dock.input.exitDraft":"按 Esc 回到終端模式 · Shift + Enter 換行","dock.command.placeholder":"輸入指令 · Enter 執行","dock.mode.agent":"對話","dock.mode.toggle":"切換輸入模式","dock.mode.command":"命令模式","dock.mode.chat":"聊天模式","fav.title":"常用","fav.add":"新增","fav.addPlaceholder":"新增常用…","dock.upload.aria":"上傳檔案","dock.upload.title":"上傳檔案(存到主目錄上傳區,不進專案)","dock.upload.progress":"上傳 {name}{tag}","dock.upload.failed":"上傳失敗:{names}","app.nameExists":"該名稱已存在","app.renameFailed":"重新命名失敗,請重試","app.deleteFailed":"刪除失敗,請重試","app.moveFailed":"移動失敗,請重試","app.sessionGone":"工作階段「{name}」不存在,可能已關閉","app.docNotFound":"檔案不存在","app.docTooLarge":"檔案過大(超過 2MB)","app.docUnsupported":"不支援的檔案或路徑","app.docOpenFailed":"開啟失敗,請重試","app.preview":"預覽","app.openPreview":"開啟預覽","app.ideas":"想法","app.files":"檔案","app.settings":"設定","app.renameSession":"重新命名工作階段","app.renameWindow":"重新命名視窗","app.moveLeft":"◀ 左移","app.moveRight":"右移 ▶","app.deleteWindow":"刪除視窗","pane.splitH":"左右分割","pane.splitV":"上下分割","pane.manage":"管理分割","pane.close":"關閉此格","pane.closeConfirm":"確認關閉?再點一次","pane.splitFailed":"分割失敗","pane.closeFailed":"關閉失敗","resize.windowWidth":"視窗寬度","resize.paneWidth":"窗格寬度","resize.columns":"{n} 欄","resize.restore":"恢復","resize.restoreAutoWidth":"恢復自動寬度","resize.restoreRatio":"恢復分割比例","app.deleteLastWindowConfirm":"這是最後一個視窗,刪除將關閉整個工作階段!再點一次","app.deleteConfirm":"確認刪除?再點一次","app.cannotLocate":"無法定位","app.pickItsDir":",請選擇所在目錄:","app.noBoundSession":"尚未綁定工作階段","app.tapToBind":"點此綁定一個","app.selectSessionHint":"點擊左上角 ☰ 選擇工作階段","app.backToExit":"再按一次返回鍵結束","settings.title":"設定","settings.group_global":"全域設定","settings.group_general":"一般","settings.group_voice":"語音轉文字","settings.voice_enabled":"是否已開啟","settings.voice_on":"已開啟","settings.voice_off":"未開啟","settings.voice_provider":"目前服務商","settings.voice_profile_tencent_streaming":"騰訊雲即時語音識別","settings.voice_profile_tencent_sentence":"騰訊雲一句話識別","settings.voice_profile_xfyun":"訊飛語音聽寫","settings.voice_not_configured":"未設定","settings.voice_filler_filter":"語氣詞過濾","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"不支援","settings.voice_setup_hint":"請在終端機執行 handmux setup,然後進入「語音輸入」完成設定。","settings.project_task_beta":"專案任務 Beta","settings.group_terminal":"終端機","settings.group_chat":"對話","settings.group_notifications":"通知","settings.group_about":"關於","settings.terminal_font_size":"終端機字型大小","settings.terminal_font_decrease":"縮小終端機字型","settings.terminal_font_increase":"放大終端機字型","settings.terminal_font_auto":"自適應","settings.terminal_font_auto_title":"依高度自動調整","settings.conversation_font_size":"對話字型大小","settings.conversation_font_decrease":"縮小對話字型","settings.conversation_font_increase":"放大對話字型","settings.conversation_font_default":"恢復預設","settings.conversation_font_hint":"可在 10–20px 之間以 1px 為步進調整;僅影響對話訊息內文及其中的 Markdown 與程式碼。","settings.keyboard_mode":"鍵盤模式","settings.keyboard_mode_auto":"自動識別","settings.keyboard_mode_mobile":"手機","settings.keyboard_mode_desktop":"電腦","settings.keyboard_mode_hint":"僅套用於目前瀏覽器;識別不準時可手動指定。","settings.group_agent_integration":"Agent 整合","settings.conversation_view_agent":"{agent} 對話檢視","settings.experimental":"實驗性","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"處理中…","settings.agent_integration_load_error":"無法檢查 Agent 狀態。","settings.agent_integration_action_error":"整合失敗,請在電腦上執行:","settings.agent_integration_conflict_hint":"{agent} 已有其他設定,請在電腦上進行診斷:","settings.agent_integration_not_installed_hint":"這台電腦尚未安裝 {agent}。","settings.agent_integration_initialize_first_hint":"請先在電腦上執行一次 {agent},再回來啟用。","settings.agent_integration_enable":"啟用","settings.agent_integration_repair":"修復","settings.agent_integration_loading":"正在檢查…","settings.agent_integration_status_ready":"已接入","settings.agent_integration_status_not_enabled":"未啟用","settings.agent_integration_status_needs_repair":"需要修復","settings.agent_integration_status_conflict":"需要處理","settings.agent_integration_status_not_installed":"未安裝","settings.chat_lens_claude":"Claude Code 對話視圖(實驗性)","settings.chat_lens_codex":"Codex CLI 對話視圖","settings.chat_lens_claude_hint":"Claude Code 對話仍是實驗性功能;開啟後可在視窗列切換視圖。","settings.chat_lens_codex_hint":"僅控制 Codex CLI 的對話視圖入口。託管工作階段會自動進入收件匣;一般 Codex 仍可使用終端機,但不會同步狀態和通知。","boot.loading":"正在載入","boot.chat_empty":"發送你的第一則訊息,對話就開始啦","settings.chat_lens_need_hooks":"需先安裝 Agent hooks:對話裡的確認提示和狀態都依賴它。","settings.chat_lens_no_claude":"未檢測到 Claude Code;安裝並執行後再開啟。","settings.chat_lens_install_hooks":"一鍵安裝 hooks","settings.chat_lens_installing":"安裝中…","settings.chat_lens_hooks_err":"接入失敗,請到電腦上運行 handmux agent enable claude","settings.agent_hooks_error":"接入失敗,請到電腦上執行 handmux agent enable claude。","settings.path_highlight":"高亮檔案路徑","settings.path_highlight_hint":"為終端機裡可點開的檔案路徑加底色。無論開關與否,路徑都可點開。","settings.whats_new":"新功能","settings.view_changelog":"查看更新日誌","settings.reload_app":"重新載入應用程式","settings.has_update":"有更新","settings.version":"版本","settings.feedback":"意見回饋","settings.feedback_issues":"GitHub 回報","settings.feedback_group":"微信用戶群","settings.feedback_hint":"bug、想法都歡迎——Issue 會被追蹤處理;微信群回饋直達。","settings.update_available":"有新版本 v{v} 可用","settings.update_more":"另有 {n} 個版本更新","settings.update_how":"在電腦上執行","settings.push_notifications":"推播通知","settings.notify_on":"已開啟 ✓","settings.notify_enable":"開啟裝置通知","settings.notify_enabled":"已開啟,應會收到一則歡迎通知","settings.notify_disabled":"已關閉","settings.notify_failed":"操作失敗","settings.notify_disable_title":"關閉推播通知?","settings.notify_disable_hint":"關閉後,這台裝置將不再收到「需要你」「已完成」或指令碼發送的推播。你可以隨時重新開啟。","settings.notify_disable_confirm":"關閉推播","settings.processing":"處理中","settings.push_hint":"監聽「需要你」和「已完成」:所關注工作階段需要授權/回答,或一輪剛完成時,推播到此裝置。","settings.push_unsupported":"推播需要 Chrome 或 Safari 瀏覽器","settings.preview_site":"預覽站台","settings.preview_static_site":"預覽靜態站台","settings.preview_running_static":"靜態預覽 執行中","settings.preview_remain_title":"剩餘有效期","settings.preview_remain":"剩 {time}","settings.preview_renew":"續期","settings.preview_confirm_stop":"確認停止","settings.preview_stop":"停止","settings.preview_name":"名稱:{name}","settings.preview_port":"(連接埠:{port})","settings.preview_type":"預覽類型","settings.preview_off":"不開啟","settings.preview_static":"靜態","settings.preview_off_hint":"未開啟預覽。選擇「靜態」開始。","settings.preview_off_hint_both":"未開啟預覽。選擇「靜態」或「動態」開始。","settings.preview_pick_dir":"選擇目錄啟動","settings.preview_static_hint":"選一個含 index.html 的目錄,在手機上預覽。","settings.preview_port_placeholder":"連接埠,如 3000","settings.preview_port_label":"連接埠","settings.preview_starting":"啟動中…","settings.preview_start":"啟動","settings.dir_picker_hint":"選擇要預覽的靜態站台目錄(含 index.html)","settings.err_port_not_listening":"該連接埠未在監聽,請確認服務已啟動","settings.err_bad_port":"連接埠不合法(1–65535)","settings.err_start_failed":"啟動失敗","localurl.title":"開啟網站","localurl.open":"在瀏覽器中開啟","localurl.notListening":"連接埠 :{port} 沒有服務在監聽。","localurl.badProtocol":"此連結不是可代理的 HTTP 或 HTTPS 位址。","localurl.network":"無法連線 handmux 服務,請檢查網路後重試。","localurl.failed":"無法開啟此網站,請檢查網址後再試。","filebrowser.openDirFailed":"無法開啟該目錄","filebrowser.copiedPath":"已複製路徑:{abs}","filebrowser.mkdirFailed":"建立目錄失敗(名稱不合法或已存在)","filebrowser.downloading":"下載 {name}","filebrowser.downloadFailed":"下載失敗","filebrowser.uploading":"上傳 {name}{tag}","filebrowser.uploadFailed":"上傳失敗","filebrowser.uploadPartialFailed":"以下檔案上傳失敗:{names}","filebrowser.sessionDir":"工作階段目錄","filebrowser.jumpToSessionDir":"跳到目前工作階段目錄","filebrowser.parentDir":"上層目錄","filebrowser.rootSelect":"切換根目錄(主目錄 / 暫存目錄)","filebrowser.pathPlaceholder":"輸入路徑(即時篩選/跳轉)","filebrowser.newFolder":"新增資料夾","filebrowser.createBtn":"建立","filebrowser.uploadFile":"上傳檔案","filebrowser.uploadToCurrentDir":"上傳到目前目錄","filebrowser.enterSubdirToUpload":"請進入一個子目錄上傳","filebrowser.folderNamePlaceholder":"資料夾名稱","filebrowser.uploadPendingTo":"將「{name}」上傳到目前目錄","filebrowser.enterSubdirFirst":"(請先進入一個子目錄)","filebrowser.upload":"上傳","filebrowser.savedToDownloads":"已儲存「{name}」到「下載」資料夾,可在系統檔案管理員查看","filebrowser.noMatches":"沒有符合的檔案或目錄","filebrowser.tooMany":"共 {total} 項,僅顯示前 {shown} 項——在路徑框輸入關鍵字可篩選","filebrowser.previewUnsupported":"暫不支援此類型檔案的預覽,點右側按鈕可下載","filebrowser.copyAbsPath":"複製絕對路徑","filebrowser.download":"下載","filebrowser.pickThisDir":"選定此目錄 {path}","filebrowser.downloadConfirm":"下載 {name}?","filemanager.files":"檔案","filemanager.closeTab":"關閉標籤","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"目錄","git.errReadRepo":"無法讀取儲存庫","git.errLoad":"載入失敗","git.noRepoInDir":"這個目錄還不是 git 儲存庫 —— 換一個目錄,或在這裡 git init 一下。","git.outsideRoots":"這個目錄在 handmux 可存取範圍之外 —— 只開放主目錄和 /tmp。把儲存庫放到主目錄下,就能在這裡檢視了。","git.errReadDir":"無法讀取該目錄","git.commitDetail":"提交詳情","git.diff":"差異","git.bindRepo":"綁定儲存庫","git.collapse":"收起","git.currentBranch":"目前分支","git.switchViewedBranch":"切換查看的分支","git.switchBranch":"切換分支","git.noBranches":"目前沒有分支","git.noRepoBound":"未綁定儲存庫,點左上角「+」選擇一個目錄。","git.changes":"變更","git.commits":"提交","git.pullToLoadMore":"下拉載入更多","git.pickerHint":"選擇一個目錄,自動尋找其中的 git 儲存庫","git.cleanTree":"工作區乾淨","git.noCommits":"目前沒有提交","git.noDiff":"無差異","git.fontSmaller":"縮小字型","git.fontLarger":"放大字型","git.diffTruncated":"diff 過大,已截斷","cmd.panel":"命令面板","cmd.title":"命令","cmd.empty":"還沒有命令,傳送一條或儲存常用","cmd.favorites":"常用","cmd.scopeGlobal":"全域 · 所有工作階段","cmd.recent":"最近","cmd.scopeSession":"僅本工作階段","cmd.favorite":"收藏","cmd.unfavorite":"取消收藏","doc.home":"最近","doc.read":"朗讀","doc.pauseRead":"暫停朗讀","doc.resumeRead":"繼續朗讀","doc.stopRead":"停止朗讀","doc.rate":"語速","doc.fontSmaller":"縮小字型","doc.fontLarger":"放大字型","inbox.view.working":"進行中","inbox.view.done":"已完成","inbox.view.needs":"需要你","inbox.view.error":"出錯","push.unsupported":"推播通知需要 Chrome 或 Safari 瀏覽器","push.iosAddToHome":"iOS 需先將本站「加入主畫面」,從主畫面圖示開啟後再開啟","a2hs.title":"將 handmux 加入主畫面","a2hs.lead":"像 App 一樣開啟——全螢幕、沒有網址列。在 iPhone 上,pane 需要你時的推播也靠它送達。","a2hs.install":"安裝 handmux","a2hs.ios1":"點 Safari 的分享按鈕(⬆︎ 方框)。","a2hs.ios2":"點「更多」,或向下滑動清單。","a2hs.ios3":"選「加入主畫面」,再點「加入」。","a2hs.iosHint":"Safari 裡:分享 → 更多 → 加入主畫面。","a2hs.iosOpenSafari":"目前不是 Safari。請在 Safari 開啟本頁再加入主畫面——其他 iOS 瀏覽器無法安裝。","a2hs.androidManual":"開啟瀏覽器選單(⋮),選「加入主畫面」或「安裝應用程式」。","a2hs.later":"稍後再說","push.permissionTimeout":"系統未回傳通知授權結果,請在系統設定中檢查 handmux 或瀏覽器的通知權限後再試","push.permissionDenied":"通知權限被拒絕","push.swRegisterTimeout":"註冊通知服務逾時,請檢查網路後再試","push.swRegisterFailed":"註冊通知服務失敗:{reason}。請清除本站資料後重新開啟再試","push.swTimeout":"通知服務已註冊但未能啟用,請清除本站資料後重新開啟再試","push.unknownReason":"原因不明","push.configTimeout":"讀取推播設定逾時,請檢查與 handmux 伺服器的連線後再試","push.browserTimeout":"瀏覽器推播服務沒有回應;Android Chrome 請確認 Google Play 服務可用後再試","push.noVapid":"伺服器未設定推播(VAPID)","push.reportTimeout":"訂閱已建立,但回報伺服器逾時,請檢查連線後再試","push.subscriptionExpired":"Chrome 回傳的推播訂閱已失效,已為你重設;請再次點擊開啟通知","push.deliveryRejected":"推播服務拒絕了新訂閱,請檢查伺服器記錄後再試","push.subscribeFailed":"訂閱回報失敗","push.sendFailed":"傳送失敗","api.loadFailed":"載入失敗","api.uploadFailed":"上傳失敗","upload.title":"上傳中","upload.processing":"已傳送,伺服器接收中…","api.uploadBadDir":"無法上傳到該目錄","api.uploadDuplicate":"已存在同名檔案","api.uploadTooLarge":"檔案過大(上限 50MB)","api.uploadBadType":"不支援的檔案類型","time.secAgo":"{n} 秒前","time.minAgo":"{n} 分鐘前","time.hourAgo":"{n} 小時前","time.dayAgo":"{n} 天前","time.expired":"已過期","time.minutes":"{n} 分鐘","settings.script_push":"腳本推送","settings.script_push_open":"怎麼用","settings.script_push_hint":"讓電腦上的腳本把一條通知推到手機。","scriptPush.title":"腳本推送","scriptPush.intro":"讓電腦上的腳本複用 handmux 的推送通道:在執行 handmux 的電腦上,一條 handmux push 命令就能把通知推到手機——建置、CI 或長任務結束時提醒你,不用另接推送服務。","scriptPush.copied":"已複製","scriptPush.session_placeholder":"<會話名>","scriptPush.device_placeholder":"<本裝置key>","scriptPush.scope_all":"推給所有已訂閱裝置(預設)","scriptPush.scope_session":"只推某個會話裡的裝置","scriptPush.scope_device":"只推這台裝置","scriptPush.device_key_note":"上面這串 key 就是這台裝置的,複製即用。","scriptPush.device_need_enable":"先在上方開啟推送通知,才會生成這台裝置的 key。","scriptPush.opts_label":"可選參數(追加到上面任意一條後面)","scriptPush.opt_tag":"--tag <標籤> —— 相同 tag 會覆蓋上一條推送,而不是堆疊。","scriptPush.opt_url":"--url <路徑> —— 點擊通知時開啟這個路徑。","scriptPush.reliability":"注意:Web 推送經手機系統(FCM/APNs)中轉,屬盡力而為——省電模式、離線或廠商策略都可能延遲或丟棄它,並不保證即時送達。對送達強依賴的場景,請改用專門的 IM(WeChat / Telegram bot 等)。","pushInbox.title":"腳本推送記錄","pushInbox.empty":"還沒有腳本通知","pushInbox.delete":"刪除","pushInbox.justNow":"剛剛","pushInbox.minutesAgo":"{n}分鐘前","pushInbox.hoursAgo":"{n}小時前","pushInbox.detailTitle":"腳本推送詳情","pushInbox.openUrl":"打開連結","pushInbox.expired":"這條訊息已過期","pushInbox.back":"返回","pushInbox.markAllRead":"全部已讀","pushInbox.unreadCount":"{n} 未讀","pushInbox.loadFailed":"腳本推送記錄載入失敗,請檢查連線後重試","pushInbox.deleteFailed":"腳本推送刪除失敗,訊息已保留,請重試","pushInbox.retry":"重試","pushInbox.deliveryPending":"傳送中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失敗","pushInbox.deliveryReasonExpired":"訂閱已失效","pushInbox.deliveryReasonRateLimited":"推播服務限流","pushInbox.deliveryReasonUnavailable":"推播服務暫不可用","pushInbox.deliveryReasonRejected":"推播服務已拒絕","pushInbox.deliveryReasonNetwork":"網路錯誤","pushInbox.deliveryReasonNotConfigured":"伺服器未設定推播","pushInbox.deliveryReasonUnknown":"不明原因","workspace.bootDetected":"偵測到電腦已重新啟動","workspace.tmuxDetected":"偵測到 tmux 已重新啟動","workspace.summary":"上次工作區 · {sessions} 個工作階段 · 儲存於 {time}","workspace.restoreLast":"還原上次工作區","workspace.partialCard":"仍有 {failures} 個工作階段需要處理","workspace.unknownTime":"未知時間","workspace.savedAt":"儲存於 {time}","workspace.topologySummary":"{sessions} 個工作階段 · {windows} 個視窗 · {panes} 個窗格","workspace.planSummary":"將還原 {restore} 個工作階段;{already} 個已存在","workspace.renameRule":"僅當目前已有同名工作階段時,還原名稱才會加上 -restored 後綴。","workspace.nonDestructive":"目前的工作階段不會被修改、重新命名或停止。","workspace.progress":"正在還原 {completed} / {total}…","workspace.progressDone":"已還原 {completed} / {total}","workspace.complete":"工作區已還原。","workspace.completedSummary":"本次還原:{sessions} 個工作階段 · {windows} 個視窗 · {panes} 個窗格","workspace.rebindHint":"還原的工作階段不會自動顯示;可重新選擇要綁定到這台手機的工作階段。","workspace.rebind":"重新綁定工作階段","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"未知工作階段","workspace.restore":"還原","workspace.ignore":"忽略此備份","workspace.protectionTitle":"工作區未受保護","workspace.protection.live-corrupt":"工作區狀態副本已損壞;請檢查磁碟與 ~/.handmux 權限,然後重新啟動 handmux。","workspace.protection.live-unavailable":"無法讀寫工作區狀態;請檢查磁碟空間與 ~/.handmux 權限,然後重新啟動 handmux。","workspace.protection.unknown":"背景快照暫時無法使用;請檢查電腦上的 handmux 日誌。","workspace.error.restore-interrupted":"還原已中斷;請重試此備份","workspace.error.checkpoint-not-found":"此備份已無法使用;請重新整理後選擇其他備份","workspace.error.storage-full":"工作區儲存空間不足;請釋放磁碟空間後重試","workspace.error.permission-denied":"無法寫入工作區儲存;請檢查權限後重試","workspace.error.plan-failed":"還原計畫已變更;請重新整理後重試","workspace.error.agent-unavailable":"Agent 無法續接;請開啟已還原的 shell 後手動重試","workspace.error.tmux-unavailable":"tmux 無法使用;請確認 tmux 已執行後重試","workspace.error.restore-failed":"工作階段未還原;請檢查 handmux 日誌後重試","workspace.error.operation-not-found":"此還原任務已無法使用;請重新還原此備份","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"工作目錄無法使用;已在主目錄中還原","workspace.warning.layout-fallback":"窗格配置無法完整還原;已保留預設配置","workspace.warning.agent-warning":"Agent 未能自動續接;已還原的 shell 仍可使用","workspace.warning.live-reconcile-failed":"即時工作區狀態核對失敗;請檢查 handmux 日誌","workspace.warning.workspace-unavailable":"工作區儲存暫時無法使用;請檢查磁碟空間和權限","workspace.warning.restore-warning":"還原時出現可繼續處理的提醒;請檢查還原結果","chat.plan.currentTitle":"目前任務","chat.plan.historyTitle":"本輪任務","chat.plan.working":"正在:{step}","chat.plan.waiting":"等待確認:{step}","chat.plan.finalizing":"正在整理結果","chat.plan.complete":"已完成","chat.plan.incomplete":"未完成","chat.plan.status.pending":"待處理","chat.plan.status.inProgress":"進行中","chat.plan.status.completed":"已完成"},QO={"terminal.transport_live":"リアル","terminal.transport_snapshot":"スナップ","terminal.transport_detail_title":"ターミナル配信状態","terminal.transport_detail_configured":"設定モード","terminal.transport_detail_current":"現在のモード","terminal.transport_detail_connection":"接続状態","terminal.transport_detail_manual":"スナップショット取得が手動で選択されているため、自動では切り替わりません。","terminal.transport_detail_live":"ターミナルはリアルタイム配信を正常に受信しています。","terminal.transport_detail_fallback":"リアルタイム配信が不安定なため、スナップショット取得へ切り替えました。","terminal.transport_detail_unavailable":"リアルタイム接続を確立できません。リバースプロキシが WebSocket に対応しているか確認してください。","terminal.transport_detail_waiting":"接続が安定してからリアルタイム配信への復帰を試みます。","terminal.transport_detail_retry":"約 {seconds} 秒後にリアルタイム配信への復帰を試みます。","terminal.connection_connecting":"確認中","terminal.connection_good":"良好","terminal.connection_degraded":"普通","terminal.connection_poor":"不良","settings.terminal_transport":"ターミナル配信モード","settings.terminal_transport_live":"リアルタイム配信","settings.terminal_transport_snapshot":"スナップショット取得","settings.terminal_transport_hint":"リアルタイム配信は WebSocket を使用し、回線が不安定な場合はスナップショット取得へ切り替わり、30 秒安定すると復帰を試みます。","settings.snapshot_interval":"操作中の更新間隔","settings.snapshot_interval_hint":"ターミナルがアイドル状態になると更新頻度を下げ、通信量とリソースを節約します。","terminal.disconnected":"接続が切れました。再接続しています…","terminal.paneMissing":"このペインは閉じられました。別のペインに切り替えてください。","common.save":"保存","common.cancel":"キャンセル","common.confirm":"確認","common.ok":"OK","common.close":"閉じる","common.delete":"削除","common.copy":"コピー","conversationCopy.line":"行全体","conversationCopy.paragraph":"段落全体","common.rename":"名前を変更","common.create":"新規作成","common.back":"戻る","common.open":"開く","common.loading":"読み込み中…","common.done":"完了","common.retry":"再試行","app.browser":"ウェブプレビュー","browser.openTabs":"開いているウェブプレビュータブ","browser.history":"最近の閲覧","browser.closeTab":"{title} を閉じる","browser.newTab":"新しいタブ","browser.minimize":"最小化","browser.back":"戻る","browser.forward":"進む","browser.address":"アドレス","browser.addressPlaceholder":"URL またはポートを入力","browser.addressOrDirectoryPlaceholder":"URL を入力、またはフォルダを選択","browser.refresh":"更新","browser.stop":"読み込みを停止","browser.viewMode":"ページ幅","browser.narrowWidth":"狭い","browser.wideWidth":"広い","browser.closeTiming":"バックグラウンドタブを閉じる","browser.minutes":"{value} 分","browser.neverClose":"閉じない","browser.clearHistory":"消去","browser.emptyHistory":"最近の閲覧はまだありません","browser.loadFailed":"ページを読み込めません。アドレスを確認して再試行してください。","browser.retry":"再試行","browser.consentTitle":"ウェブプレビュー","browser.consentBody":"Handmux はこのウィンドウ内にページを埋め込みます。完全なブラウザではなく、開発サーバー、localhost、社内ネットワーク、埋め込みを許可するサイトの確認に適しています。Home からパソコン上の静的フォルダも選べます。","browser.consentComputer":"直接接続はスマホの回線を使います。プロキシ接続はパソコンから送信され、公開せずに社内ネットワークや localhost にアクセスできます。","browser.consentPrivate":"直接接続とプロキシでは Cookie とログイン状態が分かれ、プロキシセッションはこのデバイスごとに分離されます。","browser.consentLimits":"直接接続はサイトの iframe または CSP ポリシーでブロックされ、Handmux が原因を判別できない場合があります。PC プロキシはページを転送・書き換えますが、すべてのサイトとの互換性は保証しません。完全な閲覧機能が必要な場合は Safari、Chrome、またはシステムブラウザで開いてください。","browser.consentIdle":"バックグラウンドタブは既定で10分後に閉じます。直接接続したサイトの Cookie はスマホのブラウザに残ります。","browser.about":"ウェブプレビューについて","browser.acknowledge":"了解","browser.directMode":"スマホから直接","browser.proxyMode":"PC プロキシ経由","browser.directBadge":"直接","browser.proxyBadge":"プロキシ","browser.staticBadge":"静的","browser.chooseDirectory":"フォルダを選択","browser.staticOpening":"フォルダを開いています…","browser.directoryPickerHint":"Web ファイルを含むフォルダを選択してください。","browser.switchMode":"閲覧モードを切り替え","browser.menu":"ウェブプレビューメニュー","browser.connectionMode":"接続方法","browser.pageWidth":"ページ幅","browser.requestSiteVersion":"サイトに要求","browser.mobileSite":"モバイル版","browser.desktopSite":"PC 版","browser.zoomPage":"ページを拡大・縮小","browser.resetZoom":"ページのズームをリセット","browser.proxyLogin":"プロキシログイン","browser.proxyLoginHelpLabel":"プロキシログインについて","browser.proxyLoginHelp":"再起動後もログイン状態を維持できるよう、Handmux を実行しているコンピュータにプロキシ Cookie を暗号化して保存するかどうか。","browser.siteProxyCookie":"このサイトのプロキシ Cookie","browser.siteCookieHelpLabel":"このサイトのプロキシ Cookie について","browser.siteCookieHelp":"この端末でサイトの実 URL に一致するプロキシ Cookie のみを消去します。親ドメイン Cookie により関連する社内サイトからもログアウトする場合があります。直接接続の Cookie には影響しません。","browser.openMode":"開き方を選択","browser.historyMore":"その他の開き方","browser.historyActions":"その他の操作","browser.proxyLimitHint":"PC プロキシはページを転送・書き換えるため、すべてのサイトとの互換性は保証しません。","browser.proxyUnavailable":"パソコンのターミナルで handmux setup を実行し、「ウェブプレビュー」でプロキシドメインを設定してください。設定するまではスマホからの直接接続のみ利用できます。","browser.urlInvalid":"有効な HTTP または HTTPS アドレスを入力してください。","browser.tryProxy":"PC プロキシを試す","browser.openExternal":"システムブラウザで開く","browser.clearSiteLogin":"このサイトのプロキシ Cookie を消去","browser.clearAllLogin":"プロキシ Cookie をすべて消去","browser.clearSiteLoginConfirm":"現在の端末でこのサイトのプロキシログインを消去しますか?親ドメインの Cookie により関連する社内システムにも影響する場合があります。","browser.clearAllLoginConfirm":"現在の端末のプロキシログインをすべて消去しますか?スマホ直接接続のログインには影響しません。","browser.deleteHistoryEntry":"この項目を削除","browser.profileSaveFailed":"プロキシログイン設定を保存できません。サーバー接続を確認して再試行してください。","browser.profileClearFailed":"クリーンアップが完全には成功しませんでした。サーバー接続と保存権限を確認して、もう一度お試しください。","browser.profileSyncFailed":"プロキシログイン設定を同期できません。再試行するか、直接接続を使用してください。","browser.profileRecoveryWarning":"保存済みプロキシログインを復元できず、この端末の状態をリセットしました。","browser.retention1":"1 日","browser.retention7":"7 日","browser.retention30":"30 日","browser.retentionNotSaved":"保存しない","browser.retentionNever":"長期保存","settings.browserPersistLogin":"プロキシ Cookie をコンピュータに永続保存","settings.browserPersistLoginHint":"現在の端末だけに保存します。オフにしても、消去または期限切れまで現在のタブとログイン状態は残ります。","settings.browserRetention":"プロキシログイン保持期間","settings.browserDisablePersistConfirm":"現在の端末で今後のプロキシログイン変更の保存を停止しますか?現在のタブとログイン状態は残ります。","token.title":"アクセストークンが必要です","token.placeholder":"HANDMUX_TOKEN を貼り付け","settings.language":"言語 Language","settings.browserDefaultMode":"ウェブの既定モード","settings.browserDefaultModeHint":"アドレスバーから開く新しいタブと、保存済みモードがない履歴に使用します。","settings.browserEnabled":"ウェブプレビュー","settings.browserEnabledHint":"タブはこの端末専用です。オフにすると全タブを閉じますが、履歴は残ります。","home.empty":"ファイルが開かれていません","home.emptyHint":"「新規」タブでファイルを選択してください","home.remove":"削除","drawer.title":"セッション","drawer.empty":"セッションが紐付けられていません","drawer.unbind":"紐付け解除","drawer.bind":"セッションを紐付け","drawer.logout":"ログアウト","windowbar.newWindow":"新規ウィンドウ","rename.new_name":"新しい名前","rename.name_rule":"英数字とハイフンのみ(≤16文字)","rename.failed":"名前の変更に失敗しました。再試行してください","rename.saving":"保存中…","newwindow.title":"新規ウィンドウ","newwindow.window_name":"ウィンドウ名(任意)","newwindow.name_placeholder":"空白で自動命名 · 英数字/ハイフン ≤16","newwindow.name_rule":"英数字とハイフンのみ(≤16文字)","newwindow.start_dir":"開始ディレクトリ","newwindow.session_dir_named":"{dir}(セッションディレクトリ)","newwindow.session_dir_default":"セッションディレクトリ(デフォルト)","newwindow.choose":"選択","newwindow.reset_to_session_dir":"セッションディレクトリにリセット","newwindow.creating":"作成中…","startup.label":"起動コマンド(任意)","startup.aria":"起動コマンド","startup.preset_shell":"空のシェル(デフォルト)","startup.preset_claude":"claude(Claude Code を起動)","startup.preset_claude_continue":"claude -c(前回のセッションを継続)","startup.preset_codex":"codex(Codex CLI を起動)","startup.custom":"カスタム…","startup.custom_placeholder":'例:claude "ログインバグを修正"',"bind.title":"セッションを紐付け","bind.sessionName":"セッション名","bind.pickSession":"紐付けるセッションを選択","bind.newSession":"+ 新規セッション","bind.modeNew":"新規作成","bind.modeExisting":"既存を選択","bind.alreadyExists":"このセッションは既に存在します","bind.bind":"紐付け","bind.checking":"確認中…","bind.createAndOpen":"作成して開く","bind.creating":"作成中…","bind.createHint":"セッション「{name}」が存在しません。「作成して開く」をタップして作成してください","bind.alreadyBound":"このセッションはすでに紐付けられています","bind.createFailed":"作成に失敗しました。再試行してください","bind.invalidName":"英数字とハイフンのみ(≤16文字)","bind.desktopHint":"ここのセッション(スマホで作成したものも)は、PC で 1 コマンドで引き継げます:handmux open <名前>","bind.checkFailed":"確認に失敗しました。再試行してください","bind.startDir":"開始ディレクトリ","bind.homeDirDefault":"ホームディレクトリ(デフォルト)","bind.choose":"選択","bind.reset":"リセット","actionsheet.confirmAgain":"確認しますか?もう一度タップ","dirpicker.title":"ディレクトリを選択","inbox.title":"受信トレイ","inbox.working":"進行中","inbox.done":"完了","inbox.needs":"要対応","inbox.error":"エラー","inbox.clearDone":"結果をクリア","inbox.empty":"パネルの状態なし","inbox.enableTitle":"Claude Code の状態と通知を有効にする","inbox.enableHint":"Claude Code の受信トレイには Agent hooks が必要です。Codex CLI は Handmux の管理モードを使用してください。","inbox.enableBtn":"有効にする","inbox.enabling":"有効化中…","inbox.enableFailed":"有効化に失敗しました——サーバーログを確認してください。","idea.title":"アイデア","idea.editPlaceholder":"アイデアを編集…","idea.addPlaceholder":"アイデアを記録…","idea.add":"追加","idea.empty":"まだアイデアがありません。記録してみましょう","idea.dragSort":"ドラッグで並べ替え","idea.fillInput":"入力欄に挿入","idea.send":"送信","doclink.title":"ファイルを開く","changelog.title":"新機能","preview.static":"静的プレビュー","preview.remainTitle":"残り有効期限 — タップして更新 / 停止","preview.toPcView":"PCビューに切り替え","preview.toMobileView":"モバイルビューに切り替え","preview.pcView":"PCビュー","preview.mobileView":"モバイルビュー","preview.refresh":"更新","preview.minimize":"最小化","preview.ttlDialog":"プレビュー有効期限","preview.renew":"更新(1時間にリセット)","preview.stop":"プレビューを停止","preview.iframeTitle":"プレビュー","preview.zoomOut":"縮小","preview.zoomIn":"拡大","imageviewer.loadFailed":"画像の読み込みに失敗しました","imageviewer.saved":"保存しました。フォトライブラリまたは「ダウンロード」で確認できます","imageviewer.shareUnsupported":"画像の共有には Chrome または Safari が必要です","imageviewer.zoomOut":"縮小","imageviewer.zoomIn":"拡大","imageviewer.imageTitle":"画像","imageviewer.saveImage":"画像を保存","imageviewer.shareImage":"画像を共有","mic.stop":"音声入力を停止","mic.start":"音声入力","mic.recognizing":"音声を認識中","mic.error.tencentPermission":"Tencent Cloud が認識を拒否しました。現在の SecretId に asr:SentenceRecognition 権限を付与して再試行してください。","mic.error.tencentCredentials":"Tencent Cloud の認証情報が無効です。handmux setup で AppId、SecretId、SecretKey を確認してください。","mic.error.browserPermission":"マイクへのアクセスが許可されていません。ブラウザのサイト設定でマイクを許可して再試行してください。","mic.error.device":"マイクを使用できません。接続状態と、他のアプリが使用していないか確認してください。","mic.error.secureContext":"このアドレスではマイクを使用できません。HTTPS または localhost で Handmux を開いてください。","mic.error.tooLong":"録音が長すぎます。短くして再試行してください。","mic.error.notSelected":"選択した音声モードが有効ではありません。Handmux を再起動して再試行してください。","mic.error.noSpeech":"音声を認識できませんでした。もう一度お試しください。","mic.error.network":"音声サービスに接続できません。ネットワークを確認して再試行してください。","mic.error.provider":"音声サービスがリクエストを拒否しました:{reason}","mic.error.generic":"音声入力に失敗しました。再試行してください。","dock.send":"送信","dock.send.hint":"タップで送信 · 長押しで挿入","dock.phrases":"よく使うフレーズ","dock.attach":"添付","dock.history":"履歴","history.empty":"履歴はまだありません","history.scope":"このウィンドウの記録のみ","dock.input.placeholder":"メッセージを入力…","dock.input.enterDraft":"Shift + Enter で下書きモードへ","dock.input.exitDraft":"Esc でターミナルモードへ戻る · Shift + Enter で改行","dock.command.placeholder":"コマンドを入力 · Enterで実行","dock.mode.agent":"会話","dock.mode.toggle":"入力モードを切替","dock.mode.command":"コマンド","dock.mode.chat":"チャット","fav.title":"よく使う","fav.add":"追加","fav.addPlaceholder":"よく使う項目を追加…","dock.upload.aria":"ファイルをアップロード","dock.upload.title":"ファイルをアップロード(ホームのアップロードフォルダに保存、プロジェクトには含まない)","dock.upload.progress":"{name}{tag} をアップロード中","dock.upload.failed":"アップロード失敗:{names}","app.nameExists":"その名前はすでに使われています","app.renameFailed":"名前の変更に失敗しました。再試行してください","app.deleteFailed":"削除に失敗しました。再試行してください","app.moveFailed":"移動に失敗しました。再試行してください","app.sessionGone":"セッション「{name}」が存在しません。閉じられた可能性があります","app.docNotFound":"ファイルが存在しません","app.docTooLarge":"ファイルが大きすぎます(2MB超)","app.docUnsupported":"サポートされていないファイルまたはパス","app.docOpenFailed":"開くのに失敗しました。再試行してください","app.preview":"プレビュー","app.openPreview":"プレビューを開く","app.ideas":"アイデア","app.files":"ファイル","app.settings":"設定","app.renameSession":"セッション名を変更","app.renameWindow":"ウィンドウ名を変更","app.moveLeft":"◀ 左へ移動","app.moveRight":"右へ移動 ▶","app.deleteWindow":"ウィンドウを削除","pane.splitH":"左右に分割","pane.splitV":"上下に分割","pane.manage":"分割を管理","pane.close":"ペインを閉じる","pane.closeConfirm":"閉じますか?もう一度タップ","pane.splitFailed":"分割に失敗しました","pane.closeFailed":"閉じる操作に失敗しました","resize.windowWidth":"ウィンドウ幅","resize.paneWidth":"ペイン幅","resize.columns":"{n} 列","resize.restore":"復元","resize.restoreAutoWidth":"自動幅に戻す","resize.restoreRatio":"分割比率を復元","app.deleteLastWindowConfirm":"これは最後のウィンドウです。削除するとセッション全体が閉じます!もう一度タップ","app.deleteConfirm":"削除しますか?もう一度タップ","app.cannotLocate":"場所を特定できません","app.pickItsDir":"。ディレクトリを選択してください:","app.noBoundSession":"セッションが紐付けられていません","app.tapToBind":"タップして紐付け","app.selectSessionHint":"左上の ☰ をタップしてセッションを選択","app.backToExit":"もう一度戻るで終了します","settings.title":"設定","settings.group_global":"グローバル設定","settings.group_general":"一般","settings.group_voice":"音声文字起こし","settings.voice_enabled":"有効状態","settings.voice_on":"有効","settings.voice_off":"無効","settings.voice_provider":"現在のプロバイダー","settings.voice_profile_tencent_streaming":"Tencent Cloud リアルタイム音声認識","settings.voice_profile_tencent_sentence":"Tencent Cloud 一文音声認識","settings.voice_profile_xfyun":"iFlytek 音声ディクテーション","settings.voice_not_configured":"未設定","settings.voice_filler_filter":"フィラー語の除去","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"未対応","settings.voice_setup_hint":"ターミナルで handmux setup を実行し、「音声入力」で設定してください。","settings.project_task_beta":"プロジェクトタスク Beta","settings.group_terminal":"ターミナル","settings.group_chat":"チャット","settings.group_notifications":"通知","settings.group_about":"情報","settings.terminal_font_size":"ターミナルのフォントサイズ","settings.terminal_font_decrease":"ターミナルのフォントを縮小","settings.terminal_font_increase":"ターミナルのフォントを拡大","settings.terminal_font_auto":"自動調整","settings.terminal_font_auto_title":"高さに合わせて自動調整","settings.conversation_font_size":"会話のフォントサイズ","settings.conversation_font_decrease":"会話のフォントを縮小","settings.conversation_font_increase":"会話のフォントを拡大","settings.conversation_font_default":"デフォルトに戻す","settings.conversation_font_hint":"10〜20px の間を 1px ずつ調整できます。会話メッセージの本文と、その中の Markdown およびコードのみに影響します。","settings.keyboard_mode":"キーボードモード","settings.keyboard_mode_auto":"自動判定","settings.keyboard_mode_mobile":"モバイル","settings.keyboard_mode_desktop":"デスクトップ","settings.keyboard_mode_hint":"このブラウザだけに適用されます。判定が違う場合は手動で選択できます。","settings.group_agent_integration":"Agent 連携","settings.conversation_view_agent":"{agent} 会話ビュー","settings.experimental":"試験機能","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"処理中…","settings.agent_integration_load_error":"Agent の状態を確認できません。","settings.agent_integration_action_error":"設定できませんでした。パソコンで次を実行してください:","settings.agent_integration_conflict_hint":"{agent} に既存の設定があります。パソコンで診断してください:","settings.agent_integration_not_installed_hint":"このパソコンに {agent} がインストールされていません。","settings.agent_integration_initialize_first_hint":"パソコンで {agent} を一度起動してから、ここに戻って有効にしてください。","settings.agent_integration_enable":"有効にする","settings.agent_integration_repair":"修復","settings.agent_integration_loading":"確認中…","settings.agent_integration_status_ready":"準備完了","settings.agent_integration_status_not_enabled":"未有効","settings.agent_integration_status_needs_repair":"修復が必要","settings.agent_integration_status_conflict":"確認が必要","settings.agent_integration_status_not_installed":"未インストール","settings.path_highlight":"ファイルパスをハイライト","settings.path_highlight_hint":"ターミナル内のタップ可能なファイルパスに色を付けます。オフでもパスはタップできます。","settings.whats_new":"新機能","settings.view_changelog":"変更履歴を表示","settings.reload_app":"アプリを再読み込み","settings.has_update":"更新あり","settings.version":"バージョン","settings.feedback":"フィードバック","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat グループ","settings.feedback_hint":"バグ報告や要望は Issue へ — 必ず追跡・返信されます。","settings.update_available":"バージョン {v} が利用可能","settings.update_more":"ほか {n} バージョンの更新","settings.update_how":"パソコンで実行:","settings.push_notifications":"プッシュ通知","settings.notify_on":"有効 ✓","settings.notify_enable":"デバイス通知を有効にする","settings.notify_enabled":"有効にしました。ウェルカム通知が届くはずです","settings.notify_disabled":"無効","settings.notify_failed":"操作に失敗しました","settings.notify_disable_title":"プッシュ通知をオフにしますか?","settings.notify_disable_hint":"このデバイスには「要対応」「完了」およびスクリプトからのプッシュ通知が届かなくなります。いつでも再度オンにできます。","settings.notify_disable_confirm":"オフにする","settings.processing":"処理中","settings.push_hint":"「要対応」と「完了」を監視:注目しているセッションが承認/回答を必要としているとき、またはラウンドが完了したときにこのデバイスへ通知します。","settings.push_unsupported":"プッシュ通知には Chrome または Safari が必要です","settings.preview_site":"プレビューサイト","settings.preview_static_site":"静的サイトをプレビュー","settings.preview_running_static":"静的プレビュー 実行中","settings.preview_remain_title":"残り有効期限","settings.preview_remain":"残り {time}","settings.preview_renew":"更新","settings.preview_confirm_stop":"停止を確認","settings.preview_stop":"停止","settings.preview_name":"名前:{name}","settings.preview_port":"(ポート:{port})","settings.preview_type":"プレビュータイプ","settings.preview_off":"無効","settings.preview_static":"静的","settings.preview_off_hint":"プレビューは無効です。「静的」を選択して開始してください。","settings.preview_off_hint_both":"プレビューは無効です。「静的」または「ダイナミック」を選択して開始してください。","settings.preview_pick_dir":"ディレクトリを選択して開始","settings.preview_static_hint":"index.html を含むディレクトリを選択して、スマートフォンでプレビュー。","settings.preview_port_placeholder":"ポート番号(例:3000)","settings.preview_port_label":"ポート","settings.preview_starting":"起動中…","settings.preview_start":"起動","settings.dir_picker_hint":"プレビューする静的サイトのディレクトリを選択(index.html を含む)","settings.err_port_not_listening":"そのポートはリッスンしていません。サービスが起動しているか確認してください","settings.err_bad_port":"ポート番号が無効です(1〜65535)","settings.err_start_failed":"起動に失敗しました","localurl.title":"Web サイトを開く","localurl.open":"ブラウザで開く","localurl.notListening":"ポート :{port} で待ち受けているサービスがありません。","localurl.badProtocol":"このリンクはプロキシ可能な HTTP または HTTPS アドレスではありません。","localurl.network":"handmux サービスに接続できません。ネットワークを確認して再試行してください。","localurl.failed":"Web サイトを開けません。アドレスを確認して再試行してください。","filebrowser.openDirFailed":"ディレクトリを開けませんでした","filebrowser.copiedPath":"パスをコピーしました:{abs}","filebrowser.mkdirFailed":"ディレクトリの作成に失敗しました(名前が無効または既に存在します)","filebrowser.downloading":"{name} をダウンロード中","filebrowser.downloadFailed":"ダウンロードに失敗しました","filebrowser.uploading":"{name}{tag} をアップロード中","filebrowser.uploadFailed":"アップロードに失敗しました","filebrowser.uploadPartialFailed":"以下のファイルのアップロードに失敗しました:{names}","filebrowser.sessionDir":"セッションディレクトリ","filebrowser.jumpToSessionDir":"現在のセッションディレクトリへ移動","filebrowser.parentDir":"親ディレクトリ","filebrowser.rootSelect":"ルートディレクトリを切り替え(ホーム / 一時)","filebrowser.pathPlaceholder":"パスを入力(リアルタイムフィルタ / ジャンプ)","filebrowser.newFolder":"新規フォルダ","filebrowser.createBtn":"作成","filebrowser.uploadFile":"ファイルをアップロード","filebrowser.uploadToCurrentDir":"現在のディレクトリにアップロード","filebrowser.enterSubdirToUpload":"サブディレクトリに移動してからアップロードしてください","filebrowser.folderNamePlaceholder":"フォルダ名","filebrowser.uploadPendingTo":"「{name}」を現在のディレクトリにアップロード","filebrowser.enterSubdirFirst":"(先にサブディレクトリに移動してください)","filebrowser.upload":"アップロード","filebrowser.savedToDownloads":"「{name}」を「ダウンロード」フォルダに保存しました。ファイルマネージャーで確認できます","filebrowser.noMatches":"一致するファイルまたはディレクトリがありません","filebrowser.tooMany":"合計 {total} 件、最初の {shown} 件のみ表示——パス欄にキーワードを入力してフィルタできます","filebrowser.previewUnsupported":"このファイルタイプのプレビューはサポートされていません。右のボタンでダウンロードできます","filebrowser.copyAbsPath":"絶対パスをコピー","filebrowser.download":"ダウンロード","filebrowser.pickThisDir":"このディレクトリを選択 {path}","filebrowser.downloadConfirm":"{name} をダウンロードしますか?","filemanager.files":"ファイル","filemanager.closeTab":"タブを閉じる","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"ディレクトリ","git.errReadRepo":"リポジトリを読み込めませんでした","git.errLoad":"読み込みに失敗しました","git.noRepoInDir":"このディレクトリにはまだ git リポジトリがありません — 別のディレクトリを選ぶか、ここで git init してください。","git.outsideRoots":"このフォルダは handmux がアクセスできる範囲外です — ホームディレクトリと /tmp のみ開けます。リポジトリをホーム配下に移すとここで閲覧できます。","git.errReadDir":"ディレクトリを読み込めませんでした","git.commitDetail":"コミット詳細","git.diff":"差分","git.bindRepo":"リポジトリを紐付け","git.collapse":"折りたたむ","git.currentBranch":"現在のブランチ","git.switchViewedBranch":"表示するブランチを切り替え","git.switchBranch":"ブランチを切り替え","git.noBranches":"ブランチがありません","git.noRepoBound":"リポジトリが紐付けられていません。左上の「+」をタップしてディレクトリを選択してください。","git.changes":"変更","git.commits":"コミット","git.pullToLoadMore":"引っ張ってさらに読み込む","git.pickerHint":"ディレクトリを選択すると、その中の git リポジトリを自動的に検索します","git.cleanTree":"ワーキングツリーはクリーンです","git.noCommits":"コミットがありません","git.noDiff":"差分なし","git.fontSmaller":"フォントを縮小","git.fontLarger":"フォントを拡大","git.diffTruncated":"差分が大きすぎるため、切り捨てられました","cmd.panel":"コマンドパネル","cmd.title":"コマンド","cmd.empty":"コマンドがありません。送信するか、よく使うものを保存してください","cmd.favorites":"お気に入り","cmd.scopeGlobal":"グローバル · 全セッション","cmd.recent":"最近","cmd.scopeSession":"このセッションのみ","cmd.favorite":"お気に入りに追加","cmd.unfavorite":"お気に入りから削除","doc.home":"最近","doc.read":"読み上げ","doc.pauseRead":"一時停止","doc.resumeRead":"再開","doc.stopRead":"読み上げを停止","doc.rate":"読み上げ速度","doc.fontSmaller":"フォントを縮小","doc.fontLarger":"フォントを拡大","inbox.view.working":"進行中","inbox.view.done":"完了","inbox.view.needs":"要対応","inbox.view.error":"エラー","push.unsupported":"プッシュ通知には Chrome または Safari が必要です","push.iosAddToHome":"iOS では先にこのサイトを「ホーム画面に追加」し、ホーム画面のアイコンから開いてください","a2hs.title":"handmux をホーム画面に追加","a2hs.lead":"アプリのように全画面で開けます。iPhone では、pane があなたを必要とするときの通知もこれで届きます。","a2hs.install":"handmux をインストール","a2hs.ios1":"Safari の共有ボタン(⬆︎ の四角)をタップ。","a2hs.ios2":"「その他」をタップ、または下にスクロール。","a2hs.ios3":"「ホーム画面に追加」を選び、「追加」をタップ。","a2hs.iosHint":"Safari で:共有 → その他 → ホーム画面に追加。","a2hs.iosOpenSafari":"現在 Safari ではありません。Safari でこのページを開いてからホーム画面に追加してください(他の iOS ブラウザではインストールできません)。","a2hs.androidManual":"ブラウザのメニュー(⋮)から「ホーム画面に追加」または「アプリをインストール」を選択。","a2hs.later":"あとで","push.permissionTimeout":"通知権限の結果が返されませんでした。システム設定で handmux またはブラウザの通知権限を確認して再試行してください。","push.permissionDenied":"通知の権限が拒否されました","push.swRegisterTimeout":"通知サービスの登録がタイムアウトしました。接続を確認して再試行してください。","push.swRegisterFailed":"通知サービスを登録できませんでした:{reason}。このサイトのデータを消去し、再度開いてお試しください。","push.swTimeout":"通知サービスは登録されましたが有効化できませんでした。このサイトのデータを消去し、再度開いてお試しください。","push.unknownReason":"原因不明","push.configTimeout":"プッシュ設定の読み込みがタイムアウトしました。handmux サーバーへの接続を確認して再試行してください。","push.browserTimeout":"ブラウザのプッシュサービスが応答しません。Android Chrome では Google Play 開発者サービスが利用可能か確認して再試行してください。","push.noVapid":"サーバーにプッシュ通知(VAPID)が設定されていません","push.reportTimeout":"購読は作成されましたが、サーバーへの登録がタイムアウトしました。接続を確認して再試行してください。","push.subscriptionExpired":"Chrome が期限切れのプッシュ購読を返しました。リセットしたので、もう一度「通知を有効にする」をタップしてください。","push.deliveryRejected":"プッシュサービスが新しい購読を拒否しました。サーバーログを確認して再試行してください。","push.subscribeFailed":"サブスクリプションの登録に失敗しました","push.sendFailed":"送信に失敗しました","pushInbox.loadFailed":"通知を読み込めませんでした。接続を確認して再試行してください。","pushInbox.deleteFailed":"通知を削除できませんでした。メッセージは保持されています。再試行してください。","pushInbox.retry":"再試行","pushInbox.deliveryPending":"送信中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失敗","pushInbox.deliveryReasonExpired":"購読の有効期限切れ","pushInbox.deliveryReasonRateLimited":"プッシュサービスの制限","pushInbox.deliveryReasonUnavailable":"プッシュサービスを利用できません","pushInbox.deliveryReasonRejected":"プッシュサービスが拒否","pushInbox.deliveryReasonNetwork":"ネットワークエラー","pushInbox.deliveryReasonNotConfigured":"プッシュ未設定","pushInbox.deliveryReasonUnknown":"原因不明","api.loadFailed":"読み込みに失敗しました","api.uploadFailed":"アップロードに失敗しました","upload.title":"アップロード中","upload.processing":"送信完了 — サーバーで受信中…","api.uploadBadDir":"そのディレクトリへはアップロードできません","api.uploadDuplicate":"同名のファイルが既に存在します","api.uploadTooLarge":"ファイルが大きすぎます(上限 50MB)","api.uploadBadType":"サポートされていないファイルタイプです","time.secAgo":"{n}秒前","time.minAgo":"{n}分前","time.hourAgo":"{n}時間前","time.dayAgo":"{n}日前","time.expired":"期限切れ","time.minutes":"{n} 分","workspace.bootDetected":"コンピュータの再起動を検出しました","workspace.tmuxDetected":"tmux の再起動を検出しました","workspace.summary":"前回のワークスペース · {sessions} セッション · {time} に保存","workspace.restoreLast":"前回のワークスペースを復元","workspace.partialCard":"残り {failures} セッションの確認が必要です","workspace.unknownTime":"時刻不明","workspace.savedAt":"{time} に保存","workspace.topologySummary":"{sessions} セッション · {windows} ウィンドウ · {panes} ペイン","workspace.planSummary":"{restore} セッションを復元;{already} セッションは既に存在します","workspace.renameRule":"同名のセッションが現在存在する場合にのみ、復元名に -restored が付きます。","workspace.nonDestructive":"現在のセッションは変更、名前変更、停止されません。","workspace.progress":"復元中 {completed} / {total}…","workspace.progressDone":"復元済み {completed} / {total}","workspace.complete":"ワークスペースを復元しました。","workspace.completedSummary":"今回の復元:{sessions} セッション · {windows} ウィンドウ · {panes} ペイン","workspace.rebindHint":"復元したセッションは自動表示されません。この端末にバインドするセッションを選択できます。","workspace.rebind":"セッションを再バインド","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"不明なセッション","workspace.restore":"復元","workspace.ignore":"このバックアップを無視","workspace.protectionTitle":"ワークスペースは保護されていません","workspace.protection.live-corrupt":"ワークスペース状態のコピーが破損しています。ディスクと ~/.handmux の権限を確認し、handmux を再起動してください。","workspace.protection.live-unavailable":"ワークスペース状態を読み書きできません。空き容量と ~/.handmux の権限を確認し、handmux を再起動してください。","workspace.protection.unknown":"バックグラウンドスナップショットを利用できません。コンピュータの handmux ログを確認してください。","workspace.error.restore-interrupted":"復元が中断されました;このバックアップを再試行してください","workspace.error.checkpoint-not-found":"このバックアップは利用できません;更新して別のバックアップを選んでください","workspace.error.storage-full":"ストレージの空きがありません;空き容量を増やして再試行してください","workspace.error.permission-denied":"ワークスペースを書き込めません;権限を確認して再試行してください","workspace.error.plan-failed":"復元計画が変わりました;更新して再試行してください","workspace.error.agent-unavailable":"Agent を再開できません;復元した shell を開いて手動で再試行してください","workspace.error.tmux-unavailable":"tmux を利用できません;tmux が起動中か確認して再試行してください","workspace.error.restore-failed":"セッションを復元できませんでした;handmux ログを確認して再試行してください","workspace.error.operation-not-found":"この復元処理は利用できません。バックアップの復元をやり直してください","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"作業ディレクトリを使用できなかったため、ホームディレクトリに復元しました","workspace.warning.layout-fallback":"ペイン配置を完全に復元できなかったため、既定の配置を維持しました","workspace.warning.agent-warning":"Agent を自動再開できませんでした。復元したシェルは利用できます","workspace.warning.live-reconcile-failed":"現在のワークスペース状態を照合できませんでした。handmux ログを確認してください","workspace.warning.workspace-unavailable":"ワークスペースストレージを一時的に利用できません。空き容量と権限を確認してください","workspace.warning.restore-warning":"復元は完了しましたが、確認が必要な警告があります","chat.plan.currentTitle":"現在のタスク","chat.plan.historyTitle":"このターンのタスク","chat.plan.working":"作業中:{step}","chat.plan.waiting":"確認待ち:{step}","chat.plan.finalizing":"結果をまとめています","chat.plan.complete":"完了","chat.plan.incomplete":"未完了","chat.plan.status.pending":"未着手","chat.plan.status.inProgress":"進行中","chat.plan.status.completed":"完了"},ZO={"terminal.transport_live":"실시간","terminal.transport_snapshot":"스냅샷","terminal.transport_detail_title":"터미널 전송 상태","terminal.transport_detail_configured":"설정 모드","terminal.transport_detail_current":"현재 모드","terminal.transport_detail_connection":"연결 상태","terminal.transport_detail_manual":"스냅샷 가져오기를 직접 선택했으므로 자동으로 전환되지 않습니다.","terminal.transport_detail_live":"터미널이 실시간 푸시를 정상적으로 받고 있습니다.","terminal.transport_detail_fallback":"실시간 푸시가 불안정하여 스냅샷 가져오기로 전환했습니다.","terminal.transport_detail_unavailable":"실시간 연결을 설정할 수 없습니다. 리버스 프록시가 WebSocket을 지원하는지 확인하세요.","terminal.transport_detail_waiting":"연결이 안정되면 실시간 푸시 복귀를 시도합니다.","terminal.transport_detail_retry":"약 {seconds}초 후 실시간 푸시 복귀를 시도합니다.","terminal.connection_connecting":"확인 중","terminal.connection_good":"양호","terminal.connection_degraded":"보통","terminal.connection_poor":"나쁨","settings.terminal_transport":"터미널 전송 모드","settings.terminal_transport_live":"실시간 푸시","settings.terminal_transport_snapshot":"스냅샷 가져오기","settings.terminal_transport_hint":"실시간 푸시는 WebSocket을 사용하며, 네트워크가 불안정하면 스냅샷 가져오기로 전환되고 30초 동안 안정되면 복귀를 시도합니다.","settings.snapshot_interval":"활성 상태 업데이트 간격","settings.snapshot_interval_hint":"터미널이 유휴 상태가 되면 트래픽과 리소스 사용을 줄이기 위해 업데이트 빈도를 낮춥니다.","terminal.disconnected":"연결이 끊겼습니다. 다시 연결하는 중…","terminal.paneMissing":"이 창이 닫혔습니다. 다른 창으로 전환하세요.","common.save":"저장","common.cancel":"취소","common.confirm":"확인","common.ok":"확인","common.close":"닫기","common.delete":"삭제","common.copy":"복사","conversationCopy.line":"전체 줄","conversationCopy.paragraph":"전체 단락","common.rename":"이름 변경","common.create":"새로 만들기","common.back":"뒤로","common.open":"열기","common.loading":"로드 중…","common.done":"완료","common.retry":"다시 시도","app.browser":"웹 미리보기","browser.openTabs":"열린 웹 미리보기 탭","browser.history":"최근 방문","browser.closeTab":"{title} 닫기","browser.newTab":"새 탭","browser.minimize":"최소화","browser.back":"뒤로","browser.forward":"앞으로","browser.address":"주소","browser.addressPlaceholder":"URL 또는 포트 입력","browser.addressOrDirectoryPlaceholder":"URL을 입력하거나 폴더 선택","browser.refresh":"새로고침","browser.stop":"로딩 중지","browser.viewMode":"페이지 너비","browser.narrowWidth":"좁게","browser.wideWidth":"넓게","browser.closeTiming":"백그라운드 탭 자동 닫기","browser.minutes":"{value}분","browser.neverClose":"닫지 않음","browser.clearHistory":"지우기","browser.emptyHistory":"최근 방문이 없습니다","browser.loadFailed":"페이지를 불러올 수 없습니다. 주소를 확인하고 다시 시도하세요.","browser.retry":"다시 시도","browser.consentTitle":"웹 미리보기","browser.consentBody":"Handmux는 이 창 안에 페이지를 삽입합니다. 완전한 브라우저가 아니며 개발 서버, localhost, 내부망 및 삽입을 허용하는 사이트를 확인하는 데 적합합니다. Home에서 컴퓨터의 정적 폴더도 선택할 수 있습니다.","browser.consentComputer":"직접 연결은 휴대폰 네트워크를 사용합니다. 프록시 요청은 컴퓨터에서 전송되어 내부망과 localhost를 공개하지 않고 접근할 수 있습니다.","browser.consentPrivate":"직접 연결과 프록시는 Cookie와 로그인 상태를 공유하지 않으며, 프록시 세션은 이 기기별로 분리됩니다.","browser.consentLimits":"휴대폰 직접 연결은 사이트의 iframe 또는 CSP 정책에 의해 차단될 수 있고 Handmux가 원인을 판단하지 못할 수 있습니다. 컴퓨터 프록시는 페이지를 전달하고 다시 작성하지만 모든 사이트와의 호환성을 보장하지 않습니다. 완전한 탐색 기능이 필요하면 Safari, Chrome 또는 시스템 브라우저에서 여세요.","browser.consentIdle":"백그라운드 탭은 기본 10분 후 닫힙니다. 직접 연결한 사이트의 Cookie는 휴대폰 브라우저에 남습니다.","browser.about":"웹 미리보기 정보","browser.acknowledge":"알겠습니다","browser.directMode":"휴대폰에서 직접","browser.proxyMode":"컴퓨터 프록시 경유","browser.directBadge":"직접","browser.proxyBadge":"프록시","browser.staticBadge":"정적","browser.chooseDirectory":"폴더 선택","browser.staticOpening":"폴더 여는 중…","browser.directoryPickerHint":"웹 파일이 들어 있는 폴더를 선택하세요.","browser.switchMode":"탐색 모드 전환","browser.menu":"웹 미리보기 메뉴","browser.connectionMode":"연결 방식","browser.pageWidth":"페이지 너비","browser.requestSiteVersion":"사이트에 요청","browser.mobileSite":"모바일판","browser.desktopSite":"데스크톱판","browser.zoomPage":"웹페이지 확대/축소","browser.resetZoom":"웹페이지 확대/축소 재설정","browser.proxyLogin":"프록시 로그인","browser.proxyLoginHelpLabel":"프록시 로그인 정보","browser.proxyLoginHelp":"재시작 후에도 로그인 상태를 유지할 수 있도록 Handmux를 실행하는 컴퓨터에 프록시 Cookie를 암호화해 저장할지 여부입니다.","browser.siteProxyCookie":"이 사이트의 프록시 Cookie","browser.siteCookieHelpLabel":"이 사이트의 프록시 Cookie 정보","browser.siteCookieHelp":"현재 기기에서 사이트의 실제 URL과 일치하는 프록시 Cookie만 정리합니다. 상위 도메인 Cookie로 인해 관련 내부 사이트에서도 로그아웃될 수 있습니다. 직접 연결 Cookie는 영향을 받지 않습니다.","browser.openMode":"열기 방식 선택","browser.historyMore":"더 많은 열기 옵션","browser.historyActions":"추가 작업","browser.proxyLimitHint":"컴퓨터 프록시는 페이지를 전달하고 다시 작성하므로 모든 사이트와의 호환성을 보장하지 않습니다.","browser.proxyUnavailable":"컴퓨터 터미널에서 handmux setup을 실행하고 “웹 미리보기”에서 프록시 도메인을 설정하세요. 설정 전에는 휴대폰 직접 연결만 사용할 수 있습니다.","browser.urlInvalid":"유효한 HTTP 또는 HTTPS 주소를 입력하세요.","browser.tryProxy":"컴퓨터 프록시 사용","browser.openExternal":"시스템 브라우저에서 열기","browser.clearSiteLogin":"이 사이트의 프록시 Cookie 정리","browser.clearAllLogin":"모든 프록시 Cookie 정리","browser.clearSiteLoginConfirm":"현재 기기에서 이 사이트의 프록시 로그인을 정리할까요? 상위 도메인 Cookie로 인해 관련 내부 시스템에도 영향을 줄 수 있습니다.","browser.clearAllLoginConfirm":"현재 기기의 프록시 로그인을 모두 정리할까요? 휴대폰 직접 연결 로그인에는 영향이 없습니다.","browser.deleteHistoryEntry":"이 기록 삭제","browser.profileSaveFailed":"프록시 로그인 설정을 저장하지 못했습니다. 서버 연결을 확인하고 다시 시도하세요.","browser.profileClearFailed":"정리가 완전히 완료되지 않았습니다. 서버 연결과 저장 권한을 확인한 후 다시 시도하세요.","browser.profileSyncFailed":"프록시 로그인 설정을 동기화하지 못했습니다. 다시 시도하거나 직접 연결을 사용하세요.","browser.profileRecoveryWarning":"저장된 프록시 로그인을 복구하지 못해 현재 기기의 상태를 초기화했습니다.","browser.retention1":"1일","browser.retention7":"7일","browser.retention30":"30일","browser.retentionNotSaved":"저장 안 함","browser.retentionNever":"장기 저장","settings.browserPersistLogin":"컴퓨터에 프록시 Cookie 영구 저장","settings.browserPersistLoginHint":"현재 기기에만 저장됩니다. 꺼도 정리하거나 만료될 때까지 현재 탭과 로그인 상태는 유지됩니다.","settings.browserRetention":"프록시 로그인 보관 기간","settings.browserDisablePersistConfirm":"현재 기기에서 이후 프록시 로그인 변경 저장을 중지할까요? 현재 탭과 로그인 상태는 유지됩니다.","token.title":"액세스 토큰이 필요합니다","token.placeholder":"HANDMUX_TOKEN 붙여넣기","settings.language":"언어 Language","settings.browserDefaultMode":"기본 웹 모드","settings.browserDefaultModeHint":"주소 표시줄에서 여는 새 탭과 저장된 모드가 없는 방문 기록에 사용됩니다.","settings.browserEnabled":"웹 미리보기","settings.browserEnabledHint":"탭은 이 기기에만 속합니다. 끄면 모든 탭을 닫지만 방문 기록은 유지합니다.","home.empty":"열린 파일이 없습니다","home.emptyHint":"「새로 만들기」 탭에서 파일을 선택하세요","home.remove":"제거","drawer.title":"세션","drawer.empty":"연결된 세션이 없습니다","drawer.unbind":"연결 해제","drawer.bind":"세션 연결","drawer.logout":"로그아웃","windowbar.newWindow":"새 창","rename.new_name":"새 이름","rename.name_rule":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","rename.failed":"이름 변경에 실패했습니다. 다시 시도하세요","rename.saving":"저장 중…","newwindow.title":"새 창","newwindow.window_name":"창 이름(선택 사항)","newwindow.name_placeholder":"비워두면 자동 이름 지정 · 영문/숫자/하이픈 ≤16","newwindow.name_rule":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","newwindow.start_dir":"시작 디렉토리","newwindow.session_dir_named":"{dir}(세션 디렉토리)","newwindow.session_dir_default":"세션 디렉토리(기본값)","newwindow.choose":"선택","newwindow.reset_to_session_dir":"세션 디렉토리로 초기화","newwindow.creating":"생성 중…","startup.label":"시작 명령(선택 사항)","startup.aria":"시작 명령","startup.preset_shell":"빈 셸(기본값)","startup.preset_claude":"claude(Claude Code 시작)","startup.preset_claude_continue":"claude -c(이전 세션 이어서)","startup.preset_codex":"codex(Codex CLI 시작)","startup.custom":"사용자 정의…","startup.custom_placeholder":'예:claude "로그인 버그 수정"',"bind.title":"세션 연결","bind.sessionName":"세션 이름","bind.pickSession":"연결할 세션 선택","bind.newSession":"+ 새 세션","bind.modeNew":"새 세션","bind.modeExisting":"기존 세션","bind.alreadyExists":"이미 존재하는 세션입니다","bind.bind":"연결","bind.checking":"확인 중…","bind.createAndOpen":"생성 후 열기","bind.creating":"생성 중…","bind.createHint":"세션「{name}」이 존재하지 않습니다. 「생성 후 열기」를 탭하여 생성하세요","bind.alreadyBound":"이미 연결된 세션입니다","bind.createFailed":"생성에 실패했습니다. 다시 시도하세요","bind.invalidName":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","bind.desktopHint":"여기의 세션(폰에서 만든 것 포함)은 컴퓨터에서 명령 하나로 이어받을 수 있습니다: handmux open <이름>","bind.checkFailed":"확인에 실패했습니다. 다시 시도하세요","bind.startDir":"시작 디렉토리","bind.homeDirDefault":"홈 디렉토리(기본값)","bind.choose":"선택","bind.reset":"초기화","actionsheet.confirmAgain":"확인하시겠습니까? 한 번 더 탭하세요","dirpicker.title":"디렉토리 선택","inbox.title":"받은 편지함","inbox.working":"진행 중","inbox.done":"완료","inbox.needs":"확인 필요","inbox.error":"오류","inbox.clearDone":"결과 지우기","inbox.empty":"패널 상태 없음","inbox.enableTitle":"Claude Code 상태 및 알림 활성화","inbox.enableHint":"Claude Code 받은편지함에는 Agent hooks가 필요합니다. Codex CLI는 Handmux 관리 모드를 사용하세요.","inbox.enableBtn":"활성화","inbox.enabling":"활성화 중…","inbox.enableFailed":"활성화에 실패했습니다——서버 로그를 확인하세요.","idea.title":"아이디어","idea.editPlaceholder":"아이디어 편집…","idea.addPlaceholder":"아이디어를 기록하세요…","idea.add":"추가","idea.empty":"아직 아이디어가 없습니다. 하나 기록해보세요","idea.dragSort":"드래그하여 정렬","idea.fillInput":"입력창에 삽입","idea.send":"보내기","doclink.title":"파일 열기","changelog.title":"새 기능","preview.static":"정적 미리보기","preview.remainTitle":"남은 유효 기간 — 탭하여 갱신 / 중지","preview.toPcView":"PC 보기로 전환","preview.toMobileView":"모바일 보기로 전환","preview.pcView":"PC 보기","preview.mobileView":"모바일 보기","preview.refresh":"새로 고침","preview.minimize":"최소화","preview.ttlDialog":"미리보기 유효 기간","preview.renew":"갱신(1시간으로 초기화)","preview.stop":"미리보기 중지","preview.iframeTitle":"미리보기","preview.zoomOut":"축소","preview.zoomIn":"확대","imageviewer.loadFailed":"이미지를 불러오지 못했습니다","imageviewer.saved":"저장되었습니다. 사진 앱 또는 「다운로드」에서 확인할 수 있습니다","imageviewer.shareUnsupported":"이미지 공유는 Chrome 또는 Safari가 필요합니다","imageviewer.zoomOut":"축소","imageviewer.zoomIn":"확대","imageviewer.imageTitle":"이미지","imageviewer.saveImage":"이미지 저장","imageviewer.shareImage":"이미지 공유","mic.stop":"음성 입력 중지","mic.start":"음성 입력","mic.recognizing":"음성 인식 중","mic.error.tencentPermission":"Tencent Cloud가 인식을 거부했습니다. 현재 SecretId에 asr:SentenceRecognition 권한을 부여한 뒤 다시 시도하세요.","mic.error.tencentCredentials":"Tencent Cloud 자격 증명이 올바르지 않습니다. handmux setup에서 AppId, SecretId, SecretKey를 확인하세요.","mic.error.browserPermission":"마이크 접근이 차단되었습니다. 브라우저 사이트 설정에서 마이크를 허용한 뒤 다시 시도하세요.","mic.error.device":"마이크를 사용할 수 없습니다. 장치 연결과 다른 앱의 사용 여부를 확인하세요.","mic.error.secureContext":"이 주소에서는 마이크를 사용할 수 없습니다. HTTPS 또는 localhost로 Handmux를 여세요.","mic.error.tooLong":"녹음이 너무 깁니다. 더 짧게 녹음한 뒤 다시 시도하세요.","mic.error.notSelected":"선택한 음성 모드가 활성화되지 않았습니다. Handmux를 재시작한 뒤 다시 시도하세요.","mic.error.noSpeech":"음성을 인식하지 못했습니다. 다시 시도하세요.","mic.error.network":"음성 서비스에 연결할 수 없습니다. 네트워크를 확인한 뒤 다시 시도하세요.","mic.error.provider":"음성 서비스가 요청을 거부했습니다: {reason}","mic.error.generic":"음성 입력에 실패했습니다. 다시 시도하세요.","dock.send":"보내기","dock.send.hint":"탭하여 보내기 · 길게 눌러 삽입","dock.phrases":"자주 쓰는 문구","dock.attach":"첨부","dock.history":"기록","history.empty":"기록이 아직 없습니다","history.scope":"현재 창의 기록만","dock.input.placeholder":"메시지를 입력하세요…","dock.input.enterDraft":"Shift + Enter로 초안 모드 열기","dock.input.exitDraft":"Esc로 터미널 모드 돌아가기 · Shift + Enter로 줄바꿈","dock.command.placeholder":"명령 입력 · Enter로 실행","dock.mode.agent":"대화","dock.mode.toggle":"입력 모드 전환","dock.mode.command":"명령 모드","dock.mode.chat":"채팅 모드","fav.title":"자주 쓰기","fav.add":"추가","fav.addPlaceholder":"자주 쓰는 항목 추가…","dock.upload.aria":"파일 업로드","dock.upload.title":"파일 업로드(홈 업로드 폴더에 저장, 프로젝트에는 포함되지 않음)","dock.upload.progress":"{name}{tag} 업로드 중","dock.upload.failed":"업로드 실패:{names}","app.nameExists":"해당 이름은 이미 사용 중입니다","app.renameFailed":"이름 변경에 실패했습니다. 다시 시도하세요","app.deleteFailed":"삭제에 실패했습니다. 다시 시도하세요","app.moveFailed":"이동에 실패했습니다. 다시 시도하세요","app.sessionGone":"세션「{name}」이 존재하지 않습니다. 이미 닫혔을 수 있습니다","app.docNotFound":"파일이 존재하지 않습니다","app.docTooLarge":"파일이 너무 큽니다(2MB 초과)","app.docUnsupported":"지원되지 않는 파일 또는 경로","app.docOpenFailed":"열기에 실패했습니다. 다시 시도하세요","app.preview":"미리보기","app.openPreview":"미리보기 열기","app.ideas":"아이디어","app.files":"파일","app.settings":"설정","app.renameSession":"세션 이름 변경","app.renameWindow":"창 이름 변경","app.moveLeft":"◀ 왼쪽으로 이동","app.moveRight":"오른쪽으로 이동 ▶","app.deleteWindow":"창 삭제","pane.splitH":"좌우 분할","pane.splitV":"상하 분할","pane.manage":"분할 관리","pane.close":"창 닫기","pane.closeConfirm":"닫을까요? 다시 탭","pane.splitFailed":"분할 실패","pane.closeFailed":"닫기 실패","resize.windowWidth":"창 너비","resize.paneWidth":"패널 너비","resize.columns":"{n}열","resize.restore":"복원","resize.restoreAutoWidth":"자동 너비 복원","resize.restoreRatio":"분할 비율 복원","app.deleteLastWindowConfirm":"마지막 창입니다. 삭제하면 전체 세션이 닫힙니다!한 번 더 탭하세요","app.deleteConfirm":"삭제하시겠습니까? 한 번 더 탭하세요","app.cannotLocate":"위치를 찾을 수 없습니다","app.pickItsDir":",디렉토리를 선택하세요:","app.noBoundSession":"연결된 세션이 없습니다","app.tapToBind":"탭하여 연결","app.selectSessionHint":"왼쪽 상단의 ☰ 를 탭하여 세션 선택","app.backToExit":"한 번 더 뒤로가기를 누르면 종료됩니다","settings.title":"설정","settings.group_global":"전체 설정","settings.group_general":"일반","settings.group_voice":"음성 텍스트 변환","settings.voice_enabled":"사용 여부","settings.voice_on":"사용 중","settings.voice_off":"사용 안 함","settings.voice_provider":"현재 제공업체","settings.voice_profile_tencent_streaming":"Tencent Cloud 실시간 음성 인식","settings.voice_profile_tencent_sentence":"Tencent Cloud 한 문장 인식","settings.voice_profile_xfyun":"iFlytek 음성 받아쓰기","settings.voice_not_configured":"설정 안 됨","settings.voice_filler_filter":"간투사 필터링","settings.voice_filter_low":"낮음","settings.voice_filter_medium":"중간","settings.voice_filter_high":"높음","settings.voice_not_supported":"지원하지 않음","settings.voice_setup_hint":"터미널에서 handmux setup을 실행한 다음, 음성 입력에서 설정하세요.","settings.project_task_beta":"프로젝트 작업 Beta","settings.group_terminal":"터미널","settings.group_chat":"대화","settings.group_notifications":"알림","settings.group_about":"정보","settings.terminal_font_size":"터미널 글꼴 크기","settings.terminal_font_decrease":"터미널 글꼴 축소","settings.terminal_font_increase":"터미널 글꼴 확대","settings.terminal_font_auto":"자동 조정","settings.terminal_font_auto_title":"높이에 맞게 자동 조정","settings.conversation_font_size":"대화 글꼴 크기","settings.conversation_font_decrease":"대화 글꼴 축소","settings.conversation_font_increase":"대화 글꼴 확대","settings.conversation_font_default":"기본값으로 복원","settings.conversation_font_hint":"10–20px 사이를 1px 단위로 조정합니다. 대화 메시지 본문과 그 안의 Markdown 및 코드에만 영향을 줍니다.","settings.keyboard_mode":"키보드 모드","settings.keyboard_mode_auto":"자동 감지","settings.keyboard_mode_mobile":"모바일","settings.keyboard_mode_desktop":"데스크톱","settings.keyboard_mode_hint":"현재 브라우저에만 적용됩니다. 감지가 틀리면 직접 선택하세요.","settings.group_agent_integration":"Agent 연동","settings.conversation_view_agent":"{agent} 대화 보기","settings.experimental":"실험적","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"처리 중…","settings.agent_integration_load_error":"Agent 상태를 확인할 수 없습니다.","settings.agent_integration_action_error":"설정을 완료하지 못했습니다. 컴퓨터에서 다음을 실행하세요:","settings.agent_integration_conflict_hint":"{agent}에 기존 설정이 있습니다. 컴퓨터에서 진단하세요:","settings.agent_integration_not_installed_hint":"이 컴퓨터에 {agent}가 설치되어 있지 않습니다.","settings.agent_integration_initialize_first_hint":"컴퓨터에서 {agent}를 한 번 실행한 뒤 돌아와 활성화하세요.","settings.agent_integration_enable":"활성화","settings.agent_integration_repair":"복구","settings.agent_integration_loading":"확인 중…","settings.agent_integration_status_ready":"준비됨","settings.agent_integration_status_not_enabled":"비활성","settings.agent_integration_status_needs_repair":"복구 필요","settings.agent_integration_status_conflict":"확인 필요","settings.agent_integration_status_not_installed":"설치되지 않음","settings.path_highlight":"파일 경로 강조","settings.path_highlight_hint":"터미널에서 탭 가능한 파일 경로에 색을 입힙니다. 꺼져 있어도 경로는 탭할 수 있습니다.","settings.whats_new":"새 기능","settings.view_changelog":"변경 내역 보기","settings.reload_app":"앱 새로고침","settings.has_update":"업데이트 있음","settings.version":"버전","settings.feedback":"피드백","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat 그룹","settings.feedback_hint":"버그와 아이디어 모두 환영 — Issue는 추적되고 답변됩니다.","settings.update_available":"버전 {v} 사용 가능","settings.update_more":"이전 버전 업데이트 {n}개 더 보기","settings.update_how":"컴퓨터에서 실행:","settings.push_notifications":"푸시 알림","settings.notify_on":"활성화됨 ✓","settings.notify_enable":"기기 알림 활성화","settings.notify_enabled":"활성화되었습니다. 환영 알림이 도착할 것입니다","settings.notify_disabled":"비활성화됨","settings.notify_failed":"작업에 실패했습니다","settings.notify_disable_title":"푸시 알림을 끌까요?","settings.notify_disable_hint":"이 기기에서 더 이상 「확인 필요」, 「완료」 및 스크립트 푸시 알림을 받지 않습니다. 언제든 다시 켤 수 있습니다.","settings.notify_disable_confirm":"푸시 끄기","settings.processing":"처리 중","settings.push_hint":"「확인 필요」및「완료」를 모니터링:관심 세션에서 승인/응답이 필요하거나 한 라운드가 완료되면 이 기기로 알림을 보냅니다.","settings.push_unsupported":"푸시 알림은 Chrome 또는 Safari가 필요합니다","settings.preview_site":"미리보기 사이트","settings.preview_static_site":"정적 사이트 미리보기","settings.preview_running_static":"정적 미리보기 실행 중","settings.preview_remain_title":"남은 유효 기간","settings.preview_remain":"남은 시간 {time}","settings.preview_renew":"갱신","settings.preview_confirm_stop":"중지 확인","settings.preview_stop":"중지","settings.preview_name":"이름:{name}","settings.preview_port":"(포트:{port})","settings.preview_type":"미리보기 유형","settings.preview_off":"비활성화","settings.preview_static":"정적","settings.preview_off_hint":"미리보기가 비활성화되어 있습니다. 「정적」을 선택하여 시작하세요.","settings.preview_off_hint_both":"미리보기가 비활성화되어 있습니다. 「정적」또는「동적」을 선택하여 시작하세요.","settings.preview_pick_dir":"디렉토리를 선택하여 시작","settings.preview_static_hint":"index.html이 포함된 디렉토리를 선택하여 스마트폰에서 미리보기.","settings.preview_port_placeholder":"포트 번호(예:3000)","settings.preview_port_label":"포트","settings.preview_starting":"시작 중…","settings.preview_start":"시작","settings.dir_picker_hint":"미리볼 정적 사이트 디렉토리 선택(index.html 포함)","settings.err_port_not_listening":"해당 포트가 수신 대기 중이지 않습니다. 서비스가 시작되었는지 확인하세요","settings.err_bad_port":"포트 번호가 유효하지 않습니다(1–65535)","settings.err_start_failed":"시작에 실패했습니다","localurl.title":"웹사이트 열기","localurl.open":"브라우저에서 열기","localurl.notListening":"포트 :{port}에서 수신 중인 서비스가 없습니다.","localurl.badProtocol":"이 링크는 프록시할 수 있는 HTTP 또는 HTTPS 주소가 아닙니다.","localurl.network":"handmux 서비스에 연결할 수 없습니다. 네트워크를 확인한 후 다시 시도하세요.","localurl.failed":"웹사이트를 열 수 없습니다. 주소를 확인하고 다시 시도하세요.","filebrowser.openDirFailed":"디렉토리를 열 수 없습니다","filebrowser.copiedPath":"경로가 복사되었습니다:{abs}","filebrowser.mkdirFailed":"디렉토리 생성에 실패했습니다(이름이 유효하지 않거나 이미 존재합니다)","filebrowser.downloading":"{name} 다운로드 중","filebrowser.downloadFailed":"다운로드에 실패했습니다","filebrowser.uploading":"{name}{tag} 업로드 중","filebrowser.uploadFailed":"업로드에 실패했습니다","filebrowser.uploadPartialFailed":"다음 파일 업로드에 실패했습니다:{names}","filebrowser.sessionDir":"세션 디렉토리","filebrowser.jumpToSessionDir":"현재 세션 디렉토리로 이동","filebrowser.parentDir":"상위 디렉토리","filebrowser.rootSelect":"루트 디렉토리 전환(홈 / 임시)","filebrowser.pathPlaceholder":"경로 입력(실시간 필터 / 이동)","filebrowser.newFolder":"새 폴더","filebrowser.createBtn":"생성","filebrowser.uploadFile":"파일 업로드","filebrowser.uploadToCurrentDir":"현재 디렉토리에 업로드","filebrowser.enterSubdirToUpload":"하위 디렉토리로 이동한 후 업로드하세요","filebrowser.folderNamePlaceholder":"폴더 이름","filebrowser.uploadPendingTo":"「{name}」을 현재 디렉토리에 업로드","filebrowser.enterSubdirFirst":"(먼저 하위 디렉토리로 이동하세요)","filebrowser.upload":"업로드","filebrowser.savedToDownloads":"「{name}」이 「다운로드」 폴더에 저장되었습니다. 파일 관리자에서 확인할 수 있습니다","filebrowser.noMatches":"일치하는 파일 또는 디렉토리가 없습니다","filebrowser.tooMany":"총 {total}개, 처음 {shown}개만 표시——경로 입력창에 키워드를 입력하여 필터할 수 있습니다","filebrowser.previewUnsupported":"이 파일 유형의 미리보기는 지원되지 않습니다. 오른쪽 버튼으로 다운로드할 수 있습니다","filebrowser.copyAbsPath":"절대 경로 복사","filebrowser.download":"다운로드","filebrowser.pickThisDir":"이 디렉토리 선택 {path}","filebrowser.downloadConfirm":"{name}을 다운로드하시겠습니까?","filemanager.files":"파일","filemanager.closeTab":"탭 닫기","filemanager.minimize":"최소화","filemanager.recent":"최근","filemanager.directory":"디렉토리","git.errReadRepo":"저장소를 읽을 수 없습니다","git.errLoad":"불러오기에 실패했습니다","git.noRepoInDir":"아직 git 저장소가 없습니다 — 다른 디렉토리를 선택하거나 여기서 git init 하세요.","git.outsideRoots":"이 폴더는 handmux가 열 수 있는 범위 밖입니다 — 홈 디렉토리와 /tmp만 접근할 수 있습니다. 저장소를 홈 디렉토리 아래로 옮기면 여기서 볼 수 있습니다.","git.errReadDir":"디렉토리를 읽을 수 없습니다","git.commitDetail":"커밋 상세","git.diff":"변경 사항","git.bindRepo":"저장소 연결","git.collapse":"접기","git.currentBranch":"현재 브랜치","git.switchViewedBranch":"표시할 브랜치 전환","git.switchBranch":"브랜치 전환","git.noBranches":"브랜치가 없습니다","git.noRepoBound":"저장소가 연결되지 않았습니다. 왼쪽 상단의 「+」를 탭하여 디렉토리를 선택하세요.","git.changes":"변경사항","git.commits":"커밋","git.pullToLoadMore":"당겨서 더 불러오기","git.pickerHint":"디렉토리를 선택하면 그 안의 git 저장소를 자동으로 찾습니다","git.cleanTree":"작업 트리가 깨끗합니다","git.noCommits":"커밋이 없습니다","git.noDiff":"변경 사항 없음","git.fontSmaller":"글꼴 축소","git.fontLarger":"글꼴 확대","git.diffTruncated":"변경 사항이 너무 커서 잘렸습니다","cmd.panel":"명령 패널","cmd.title":"명령","cmd.empty":"명령이 없습니다. 보내거나 자주 쓰는 것을 저장하세요","cmd.favorites":"즐겨찾기","cmd.scopeGlobal":"전체 · 모든 세션","cmd.recent":"최근","cmd.scopeSession":"현재 세션만","cmd.favorite":"즐겨찾기 추가","cmd.unfavorite":"즐겨찾기 해제","doc.home":"최근","doc.read":"읽어주기","doc.pauseRead":"읽기 일시 정지","doc.resumeRead":"읽기 재개","doc.stopRead":"읽기 중지","doc.rate":"읽기 속도","doc.fontSmaller":"글꼴 축소","doc.fontLarger":"글꼴 확대","inbox.view.working":"진행 중","inbox.view.done":"완료","inbox.view.needs":"확인 필요","inbox.view.error":"오류","push.unsupported":"푸시 알림은 Chrome 또는 Safari가 필요합니다","push.iosAddToHome":"iOS에서는 먼저 이 사이트를 「홈 화면에 추가」한 후 홈 화면 아이콘에서 열어주세요","a2hs.title":"handmux를 홈 화면에 추가","a2hs.lead":"앱처럼 전체 화면으로 열 수 있습니다. iPhone에서는 pane이 당신을 필요로 할 때의 푸시도 이 방식으로 전달됩니다.","a2hs.install":"handmux 설치","a2hs.ios1":"Safari의 공유 버튼(⬆︎ 상자)을 탭하세요.","a2hs.ios2":"「더 보기」를 탭하거나 목록을 아래로 스크롤하세요.","a2hs.ios3":"「홈 화면에 추가」를 선택한 뒤 「추가」를 탭하세요.","a2hs.iosHint":"Safari에서: 공유 → 더 보기 → 홈 화면에 추가.","a2hs.iosOpenSafari":"현재 Safari가 아닙니다. Safari에서 이 페이지를 연 뒤 홈 화면에 추가하세요 — 다른 iOS 브라우저는 설치할 수 없습니다.","a2hs.androidManual":"브라우저 메뉴(⋮)에서 「홈 화면에 추가」 또는 「앱 설치」를 선택하세요.","a2hs.later":"나중에","push.permissionTimeout":"알림 권한 결과가 반환되지 않았습니다. 시스템 설정에서 handmux 또는 브라우저의 알림 권한을 확인한 후 다시 시도하세요.","push.permissionDenied":"알림 권한이 거부되었습니다","push.swRegisterTimeout":"알림 서비스 등록 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하세요.","push.swRegisterFailed":"알림 서비스를 등록하지 못했습니다: {reason}. 이 사이트의 데이터를 삭제하고 다시 열어 시도하세요.","push.swTimeout":"알림 서비스가 등록되었지만 활성화되지 않았습니다. 이 사이트의 데이터를 삭제하고 다시 열어 시도하세요.","push.unknownReason":"알 수 없는 원인","push.configTimeout":"푸시 설정을 불러오는 시간이 초과되었습니다. handmux 서버 연결을 확인한 후 다시 시도하세요.","push.browserTimeout":"브라우저 푸시 서비스가 응답하지 않습니다. Android Chrome에서는 Google Play 서비스를 사용할 수 있는지 확인한 후 다시 시도하세요.","push.noVapid":"서버에 푸시 알림(VAPID)이 설정되지 않았습니다","push.reportTimeout":"구독은 생성되었지만 서버 등록 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하세요.","push.subscriptionExpired":"Chrome이 만료된 푸시 구독을 반환했습니다. 구독을 초기화했으니 알림 켜기를 다시 누르세요.","push.deliveryRejected":"푸시 서비스가 새 구독을 거부했습니다. 서버 로그를 확인한 후 다시 시도하세요.","push.subscribeFailed":"구독 등록에 실패했습니다","push.sendFailed":"전송에 실패했습니다","pushInbox.loadFailed":"알림을 불러오지 못했습니다. 연결을 확인한 후 다시 시도하세요.","pushInbox.deleteFailed":"알림을 삭제하지 못했습니다. 메시지는 유지됩니다. 다시 시도하세요.","pushInbox.retry":"다시 시도","pushInbox.deliveryPending":"전송 중","pushInbox.deliverySuccess":"성공","pushInbox.deliveryFailed":"실패","pushInbox.deliveryReasonExpired":"구독 만료","pushInbox.deliveryReasonRateLimited":"푸시 서비스 요청 제한","pushInbox.deliveryReasonUnavailable":"푸시 서비스를 사용할 수 없음","pushInbox.deliveryReasonRejected":"푸시 서비스가 거부함","pushInbox.deliveryReasonNetwork":"네트워크 오류","pushInbox.deliveryReasonNotConfigured":"푸시가 설정되지 않음","pushInbox.deliveryReasonUnknown":"알 수 없는 원인","api.loadFailed":"불러오기에 실패했습니다","api.uploadFailed":"업로드에 실패했습니다","upload.title":"업로드 중","upload.processing":"전송 완료 — 서버에서 수신 중…","api.uploadBadDir":"해당 디렉토리에는 업로드할 수 없습니다","api.uploadDuplicate":"같은 이름의 파일이 이미 존재합니다","api.uploadTooLarge":"파일이 너무 큽니다(최대 50MB)","api.uploadBadType":"지원되지 않는 파일 유형입니다","time.secAgo":"{n}초 전","time.minAgo":"{n}분 전","time.hourAgo":"{n}시간 전","time.dayAgo":"{n}일 전","time.expired":"만료됨","time.minutes":"{n}분","workspace.bootDetected":"컴퓨터 재시작이 감지되었습니다","workspace.tmuxDetected":"tmux 재시작이 감지되었습니다","workspace.summary":"이전 작업 공간 · 세션 {sessions}개 · {time} 저장","workspace.restoreLast":"이전 작업 공간 복원","workspace.partialCard":"세션 {failures}개를 더 확인해야 합니다","workspace.unknownTime":"알 수 없는 시간","workspace.savedAt":"{time} 저장","workspace.topologySummary":"세션 {sessions}개 · 창 {windows}개 · 패널 {panes}개","workspace.planSummary":"세션 {restore}개 복원;{already}개는 이미 존재","workspace.renameRule":"현재 같은 이름의 세션이 있을 때만 복원 이름에 -restored 접미사가 붙습니다.","workspace.nonDestructive":"현재 세션은 수정하거나 이름을 바꾸거나 중지하지 않습니다.","workspace.progress":"복원 중 {completed} / {total}…","workspace.progressDone":"복원됨 {completed} / {total}","workspace.complete":"작업 공간을 복원했습니다.","workspace.completedSummary":"이번 복원: 세션 {sessions}개 · 창 {windows}개 · 패널 {panes}개","workspace.rebindHint":"복원된 세션은 자동으로 표시되지 않습니다. 이 휴대폰에 연결할 세션을 다시 선택할 수 있습니다.","workspace.rebind":"세션 다시 연결","workspace.sessionFailure":"{session}: {reason}","workspace.unknownSession":"알 수 없는 세션","workspace.restore":"복원","workspace.ignore":"이 백업 무시","workspace.protectionTitle":"작업 공간이 보호되지 않음","workspace.protection.live-corrupt":"작업 공간 상태 사본이 손상되었습니다. 디스크와 ~/.handmux 권한을 확인한 뒤 handmux를 재시작하세요.","workspace.protection.live-unavailable":"작업 공간 상태를 읽거나 쓸 수 없습니다. 디스크 여유 공간과 ~/.handmux 권한을 확인한 뒤 handmux를 재시작하세요.","workspace.protection.unknown":"백그라운드 스냅샷을 사용할 수 없습니다. 컴퓨터의 handmux 로그를 확인하세요.","workspace.error.restore-interrupted":"복원이 중단되었습니다. 이 백업을 다시 시도하세요","workspace.error.checkpoint-not-found":"이 백업을 더 이상 사용할 수 없습니다. 새로 고친 뒤 다른 백업을 선택하세요","workspace.error.storage-full":"작업 공간 저장소가 가득 찼습니다. 디스크 공간을 확보한 뒤 다시 시도하세요","workspace.error.permission-denied":"작업 공간 저장소에 쓸 수 없습니다. 권한을 확인한 뒤 다시 시도하세요","workspace.error.plan-failed":"복원 계획이 변경되었습니다. 새로 고친 뒤 다시 시도하세요","workspace.error.agent-unavailable":"Agent를 재개할 수 없습니다. 복원된 shell을 열고 수동으로 다시 시도하세요","workspace.error.tmux-unavailable":"tmux를 사용할 수 없습니다. tmux 실행 여부를 확인한 뒤 다시 시도하세요","workspace.error.restore-failed":"세션을 복원하지 못했습니다. handmux 로그를 확인한 뒤 다시 시도하세요","workspace.error.operation-not-found":"이 복원 작업을 더 이상 사용할 수 없습니다. 백업 복원을 다시 시작하세요","workspace.sessionWarning":"{session}: {reason}","workspace.warning.cwd-fallback":"작업 디렉터리를 사용할 수 없어 홈 디렉터리에 복원했습니다","workspace.warning.layout-fallback":"창 분할 배치를 완전히 복원하지 못해 기본 배치를 유지했습니다","workspace.warning.agent-warning":"Agent를 자동으로 재개하지 못했습니다. 복원된 셸은 계속 사용할 수 있습니다","workspace.warning.live-reconcile-failed":"현재 작업 공간 상태를 대조하지 못했습니다. handmux 로그를 확인하세요","workspace.warning.workspace-unavailable":"작업 공간 저장소를 일시적으로 사용할 수 없습니다. 디스크 공간과 권한을 확인하세요","workspace.warning.restore-warning":"복원 중 확인이 필요한 경고가 발생했습니다","chat.plan.currentTitle":"현재 작업","chat.plan.historyTitle":"이번 턴 작업","chat.plan.working":"진행 중: {step}","chat.plan.waiting":"확인 대기: {step}","chat.plan.finalizing":"결과 정리 중","chat.plan.complete":"완료","chat.plan.incomplete":"미완료","chat.plan.status.pending":"대기","chat.plan.status.inProgress":"진행 중","chat.plan.status.completed":"완료"},QN={zh:XO,"zh-TW":JO,en:GT,ja:QO,ko:ZO},kj=[{code:"zh",label:"简体中文"},{code:"zh-TW",label:"繁體中文"},{code:"en",label:"English"},{code:"ja",label:"日本語"},{code:"ko",label:"한국어"}],KT="tw_lang";function eP(e,n,i=QN){if(typeof e=="string"&&i[e])return e;for(const a of n!=null&&n.length?n:["en"]){const u=String(a).toLowerCase();if(i[u])return u;const g=u.split("-")[0];if(g&&i[g])return g}return"en"}function tP(e,n,i,a){let u=e&&e[i]!=null?e[i]:n&&n[i]!=null?n[i]:i;return a&&(u=u.replace(/\{(\w+)\}/g,(g,d)=>a[d]!=null?String(a[d]):`{${d}}`)),u}const nP=()=>typeof navigator<"u"?navigator.languages||[navigator.language]:null,rP=()=>{try{return localStorage.getItem(KT)}catch{return null}};let jg=eP(rP(),nP());function w(e,n){return tP(QN[jg],GT,e,n)}function mo(){return jg}function iP(e){if(!(typeof e!="string"||!(e in QN)||e===jg)){try{localStorage.setItem(KT,e)}catch{}jg=e,typeof location<"u"&&location.reload()}}const sP=()=>`${Date.now().toString(36)}${Math.random().toString(36).slice(2,6)}`;function YT(e){return Array.isArray(e)?e.flatMap(n=>{const i=n!==null&&typeof n=="object"&&!Array.isArray(n)?n:null;return typeof(i==null?void 0:i.id)=="string"&&i.id&&typeof i.text=="string"&&i.text.trim()?[{id:i.id,text:i.text}]:[]}):[]}function aP(e){const n=typeof e=="string"?e.trim():"";return n?{id:sP(),text:n}:null}function oP(e,n,i){const a=[...e];if(n<0||n>=a.length||i<0||i>=a.length||n===i)return a;const[u]=a.splice(n,1);return u===void 0||a.splice(i,0,u),a}const ZN="tw_token",Tj="hm_browser_device1",rN="hm_browser_access1",e0="tw_font",iN="tw_conversation_font_size",ef="tw_bound",Dg="tw_last_session",t0="tw_win",n0="tw_pane",r0="tw_favs",lP="tw_recent",cP=30,i0="tw_inbox_seen",XT="tw_inbox_read_ts",s0="tw_browse_dir",a0="tw_preview_dir",JT="tw_startup_cmd",sN="tw_chat_draft",QT="tw_chat_tone",ZT="tw_voice_filler_filter",o0="tw_agent_conversation_enabled_v1",eR="tw_agent_usage_enabled_v1",uP="tw_ideas",tR="tw_changelog_seen",nR="tw_version_seen",rR="tw_security_seen",Kg="tw_git_repos",dP="tw_git_dirs",aN="tw_workspace_prompt",iR="tw_workspace_applied_mappings",mP="hm_root_view",oN="hm_last_project",hP=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,uw={sessions:/^\$\d+$/,windows:/^@\d+$/,panes:/^%\d+$/},Ah=(e,n)=>Object.prototype.hasOwnProperty.call(e,n);function md(e){const n=localStorage.getItem(e);if(n===null)return null;try{return JSON.parse(n)}catch{return null}}function ha(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const n=Object.getPrototypeOf(e);return n===Object.prototype||n===null}function hd(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}const sR=()=>localStorage.getItem(ZN),fP=e=>localStorage.setItem(ZN,e),pP=()=>localStorage.removeItem(ZN),dw=e=>localStorage.setItem(mP,e),vP=()=>localStorage.getItem(oN),qv=e=>{e?localStorage.setItem(oN,e):localStorage.removeItem(oN)};function gP(){const e=localStorage.getItem(Tj);if(/^[A-Za-z0-9_-]{32,128}$/.test(e||""))return e;const n=new Uint8Array(24);globalThis.crypto.getRandomValues(n);const i=`device_${[...n].map(a=>a.toString(16).padStart(2,"0")).join("")}`;return localStorage.setItem(Tj,i),i}const bP=()=>localStorage.getItem(rN)==="1",gg=e=>{e?localStorage.setItem(rN,"1"):localStorage.removeItem(rN)};function ho(){try{return hd(md(ef))}catch{return[]}}function lN(e){const n=ho();return n.includes(e)||n.push(e),localStorage.setItem(ef,JSON.stringify(n)),n}function Rj(e){const n=ho().filter(i=>i!==e);return localStorage.setItem(ef,JSON.stringify(n)),n}function _P(e){const n=new Set((Array.isArray(e)?e:[]).flatMap(a=>ha(a)?a.status==="restored"&&typeof a.targetName=="string"&&a.targetName?[a.targetName]:[]:[])),i=ho().filter(a=>!n.has(a));return localStorage.setItem(ef,JSON.stringify(i)),i}function yP(e,n){const i=ho().map(a=>a===e?n:a);return localStorage.setItem(ef,JSON.stringify(i)),l0.renameSession(e,n),Yg.renameSession(e,n),i}function Ms(e){try{const n=md(e);return ha(n)?n:{}}catch{return{}}}function Pl(e,n,i){const a=Ms(e);a[n]=i,localStorage.setItem(e,JSON.stringify(a))}function aR(e,n){if(!e)return{};const i=Ms(aN),a=i[e];return i[e]={...a&&typeof a=="object"&&!Array.isArray(a)?a:{},...n},localStorage.setItem(aN,JSON.stringify(i)),i[e]}const xP=e=>{if(!e)return{};const n=Ms(aN)[e];return ha(n)?{...typeof n.autoShown=="boolean"?{autoShown:n.autoShown}:{},...typeof n.ignored=="boolean"?{ignored:n.ignored}:{}}:{}},Aj=e=>aR(e,{autoShown:!0}),wP=e=>aR(e,{ignored:!0,autoShown:!0});function NP(){try{return hd(md(iR))}catch{return[]}}function CP(e){try{if(!ha(e)||typeof e.id!="string"||!hP.test(e.id)||e.runtime!==void 0&&!ha(e.runtime)||e.names!==void 0&&!ha(e.names))return null;const n=ha(e.runtime)?e.runtime:{};if(Object.keys(n).some(d=>!Ah(uw,d)))return null;const i={sessions:{},windows:{},panes:{}};for(const d of Object.keys(uw)){const o=uw[d],c=n[d];if(c!==void 0){if(!ha(c))return null;for(const[f,v]of Object.entries(c)){if(!o.test(f)||typeof v!="string"||!o.test(v))return null;i[d][f]=v}}}const a={},u=ha(e.names)?e.names:{};for(const[d,o]of Object.entries(u)){if(!d||typeof o!="string"||!o)return null;a[d]=o}return Object.keys(a).length>0||Object.values(i).some(d=>Object.keys(d).length>0)?{id:e.id,runtime:i,names:a}:null}catch{return null}}function EP(e){const n=localStorage.getItem(e);if(n===null)return null;try{const i=JSON.parse(n);return ha(i)?{raw:n,value:i}:null}catch{return null}}function Gv(e,n,i={}){const a=EP(e);if(!a)return;const u=a.value,g=Object.keys(n).filter(c=>Ah(u,c));if(g.length===0)return;const d={};for(const[c,f]of Object.entries(u))Ah(n,c)||(d[c]=f);for(const c of g){const f=n[c];if(f===void 0)continue;const v=u[c];d[f]=typeof v=="string"&&Ah(i,v)?i[v]:v}const o=JSON.stringify(d);o!==a.raw&&localStorage.setItem(e,o)}function SP(e){const{sessions:n,windows:i,panes:a}=e;if(Object.keys(n).length>0){const u=localStorage.getItem(Dg);if(u&&Ah(n,u)){const g=n[u];g!==void 0&&localStorage.setItem(Dg,g)}Gv(t0,n,i)}if(Object.keys(i).length>0){Gv(n0,i,a);for(const u of[Kg,dP,s0,a0])Gv(u,i)}if(Object.keys(a).length>0)for(const u of[d0,i0])Gv(u,a)}function jP(e){const n=CP(e);if(!n)return!1;const i=NP();if(i.includes(n.id))return!1;if(SP(n.runtime),Object.keys(n.names).length>0){const a=ho();for(const[u,g]of Object.entries(n.names))a.includes(u)&&lN(g)}return localStorage.setItem(iR,JSON.stringify([...i,n.id])),!0}function oR(e,n){const i=a=>ha(a)?a:{};return{get(a,u){return!a||!u?[]:n(i(Ms(e)[a])[u])},set(a,u,g){const d=Ms(e),o=i(d[a]);return g&&g.length?o[u]=[...g]:delete o[u],Object.keys(o).length?d[a]=o:delete d[a],localStorage.setItem(e,JSON.stringify(d)),g?[...g]:[]},renameWindow(a,u,g){if(!a||!u||!g||u===g)return;const d=Ms(e),o=i(d[a]);o[u]!=null&&(o[g]=o[u],delete o[u],d[a]=o,localStorage.setItem(e,JSON.stringify(d)))},renameSession(a,u){const g=Ms(e);g[a]!=null&&(g[u]=g[a],delete g[a],localStorage.setItem(e,JSON.stringify(g)))}}}const l0=oR(lP,hd),Yg=oR(uP,YT),cN=()=>{const e={};for(const[n,i]of Object.entries(Ms(i0)))typeof i=="number"&&Number.isFinite(i)&&(e[n]=i);return e};function Uj(e,n){return Pl(i0,e,n),cN()}const DP=()=>{const e=localStorage.getItem(XT);return e==null?null:Number(e)},Mj=e=>localStorage.setItem(XT,String(e)),lR="tw_notif_seen_ts",kP=()=>{const e=localStorage.getItem(lR);return e==null?0:Number(e)},TP=e=>localStorage.setItem(lR,String(e)),c0="tw_notif_read_ids",Uh=()=>{try{return hd(md(c0))}catch{return[]}},Lj=e=>{const n=Uh();n.includes(e)||localStorage.setItem(c0,JSON.stringify([...n,e]))},RP=e=>{const n=Uh().filter(i=>e.includes(i));return localStorage.setItem(c0,JSON.stringify(n)),n},AP=e=>{const n=e?Ms(s0)[e]:null;return typeof n=="string"?n:null},Ij=(e,n)=>{e&&n&&Pl(s0,e,n)},UP=e=>{const n=e?Ms(a0)[e]:null;return typeof n=="string"?n:null},Vj=(e,n)=>{e&&n&&Pl(a0,e,n)},MP=()=>localStorage.getItem(Dg),LP=e=>{const n=Ms(t0)[e];return typeof n=="string"?n:null},Wu=e=>{const n=Ms(n0)[e];return typeof n=="string"?n:null};function kl({sessionId:e,windowId:n,paneId:i}={}){e&&localStorage.setItem(Dg,e),e&&n&&Pl(t0,e,n),n&&i&&Pl(n0,n,i)}function uN(){const e=Number(localStorage.getItem(e0));return Number.isFinite(e)&&e>0?e:null}const Qu=e=>localStorage.setItem(e0,String(e)),cR=()=>localStorage.removeItem(e0),Sh=[10,11,12,13,14,15,16,17,18,19,20],Zu=15,uR=e=>typeof e=="number"&&Sh.includes(e),IP=()=>{const e=localStorage.getItem(iN),n=e===null?NaN:Number(e);return uR(n)?n:Zu},VP=e=>{uR(e)&&(e===Zu?localStorage.removeItem(iN):localStorage.setItem(iN,String(e)))},OP=["dusk","ink","light"],dR=e=>typeof e=="string"&&OP.includes(e),PP=()=>{const e=localStorage.getItem(QT);return dR(e)?e:"dusk"},BP=e=>{dR(e)&&localStorage.setItem(QT,e)},bg=["low","medium","high"],mR=e=>typeof e=="string"&&bg.includes(e),dN=()=>{const e=localStorage.getItem(ZT);return mR(e)?e:"medium"},FP=e=>{mR(e)&&localStorage.setItem(ZT,e)};function hR(){try{const e=JSON.parse(localStorage.getItem(o0)||"{}");return!e||typeof e!="object"||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(n=>/^[a-z][a-z0-9-]{0,63}$/.test(n[0])&&typeof n[1]=="boolean"))}catch{return{}}}function Oj(e){const n=hR();if(Object.hasOwn(n,e))return n[e];const i=localStorage.getItem(`tw_chat_lens_${e}`),a=localStorage.getItem("tw_chat_lens"),u=i!==null?i==="1":a!==null?a==="1":!0;return/^[a-z][a-z0-9-]{0,63}$/.test(e)&&(n[e]=u,localStorage.setItem(o0,JSON.stringify(n))),u}function HP(e,n){if(!/^[a-z][a-z0-9-]{0,63}$/.test(e))return;const i=hR();i[e]=n,localStorage.setItem(o0,JSON.stringify(i))}function fR(){try{const e=JSON.parse(localStorage.getItem(eR)||"{}");return!e||typeof e!="object"||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(n=>/^[a-z][a-z0-9-]{0,63}$/.test(n[0])&&typeof n[1]=="boolean"))}catch{return{}}}function Pj(e){const n=fR();return Object.hasOwn(n,e)?n[e]:!0}function Bj(e,n){if(!/^[a-z][a-z0-9-]{0,63}$/.test(e))return;const i=fR();i[e]=n;try{localStorage.setItem(eR,JSON.stringify(i))}catch{}}const zP=()=>localStorage.getItem(sN)||"",$P=e=>{e?localStorage.setItem(sN,e):localStorage.removeItem(sN)};function kg(){try{return hd(md(r0))}catch{return[]}}function WP(e){const n=e.trim(),i=kg();return n&&!i.includes(n)&&i.push(n),localStorage.setItem(r0,JSON.stringify(i)),i}function qP(e){const n=kg().filter(i=>i!==e);return localStorage.setItem(r0,JSON.stringify(n)),n}const pR=()=>localStorage.getItem(JT)||"",vR=e=>localStorage.setItem(JT,e||""),gR="tw_orphan_kill",GP=()=>localStorage.getItem(gR)!=="0",KP=e=>localStorage.setItem(gR,e?"1":"0"),bR="tw_doc_highlight",_R=()=>localStorage.getItem(bR)==="1",YP=e=>localStorage.setItem(bR,e?"1":"0"),Tg=(e,n)=>l0.get(e,n),yR=(e,n,i)=>l0.set(e,n,i);function XP(e,n,i){const a=(i||"").trim(),u=Tg(e,n);return!a||!e||!n?u:yR(e,n,[a,...u.filter(g=>g!==a)].slice(0,cP))}function JP(e,n,i){return!e||!n?Tg(e,n):yR(e,n,Tg(e,n).filter(a=>a!==i))}const u0="tw_recent_docs",d0="tw_pane_base",QP=30;function m0(){try{const e=md(u0);return Array.isArray(e)?e.flatMap(n=>!ha(n)||typeof n.path!="string"||typeof n.name!="string"||typeof n.type!="string"||typeof n.ts!="number"||!Number.isFinite(n.ts)?[]:[{path:n.path,name:n.name,type:n.type,ts:n.ts}]):[]}catch{return[]}}function Fj({path:e,name:n,type:i,ts:a=Date.now()}){const u=[{path:e,name:n,type:i,ts:a},...m0().filter(g=>g.path!==e)].slice(0,QP);return localStorage.setItem(u0,JSON.stringify(u)),u}function ZP(e){const n=m0().filter(i=>i.path!==e);return localStorage.setItem(u0,JSON.stringify(n)),n}const Hj=e=>{const n=Ms(d0)[e];return typeof n=="string"?n:null},e4=(e,n)=>Pl(d0,e,n),fd=[10,11,12,13,14,16,18,20,22],t4=4,xR="tw_doc_font";function n4(){const e=localStorage.getItem(xR),n=Number(e);return e!==null&&Number.isInteger(n)&&n>=0&&n<fd.length?n:t4}const r4=e=>localStorage.setItem(xR,String(Math.min(fd.length-1,Math.max(0,e)))),i4=2,wR="tw_diff_font";function s4(){const e=localStorage.getItem(wR),n=Number(e);return e!==null&&Number.isInteger(n)&&n>=0&&n<fd.length?n:i4}const a4=e=>localStorage.setItem(wR,String(Math.min(fd.length-1,Math.max(0,e)))),NR=(e,n)=>Yg.get(e,n);function zj(e,n,i){return!e||!n?[]:Yg.set(e,n,i)}const o4=()=>localStorage.getItem(tR),l4=e=>{e&&localStorage.setItem(tR,e)},c4=()=>localStorage.getItem(nR),u4=e=>{e&&localStorage.setItem(nR,e)},d4=()=>localStorage.getItem(rR)==="1",m4=()=>{localStorage.setItem(rR,"1")};function h4(e,n,i){Yg.renameWindow(e,n,i)}function h0(e){if(!e)return[];const n=Ms(Kg)[e];return hd(n)}function $j(e,n){if(!e)return[];const i=[...h0(e)];for(const a of n)a&&!i.includes(a)&&i.push(a);return Pl(Kg,e,i),i}function f4(e,n){if(!e)return[];const i=h0(e).filter(a=>a!==n);return Pl(Kg,e,i),i}const mN=[{version:"0.29.1",date:"2026-09-18",highlight:{zh:"修复 Claude 对话入口丢失 · 长时间运行不再变卡",en:"Fix lost Claude chat entries · no slowdown after long runs"},items:{zh:["修复 WSL2 上 Claude 对话入口反复消失、收件箱状态中断的问题;进程识别不再受系统时间调整影响。","修复 Linux 上 Claude 的活动状态(进行中/空闲/等待)一直显示不出来的问题。","修复 Linux 上 Claude 自动更新删掉旧版本文件后被识别不到的问题。","修复长时间运行或反复重连后变卡、占磁盘的问题:不再可达的内部状态会被回收。",'修复切换会话时短暂显示"无法连接 Codex 会话"的问题;过渡期间改为显示加载中。'],en:["Fixed Claude chat entries and Inbox state repeatedly dropping on WSL2; process identity no longer follows system clock adjustments.","Fixed Claude activity (working / idle / waiting) never showing on Linux.","Fixed Claude not being recognized on Linux after its own auto-update removed the older binary file.","Fixed the service slowing down and growing on disk after long runs or repeated reconnects; unreachable internal state is now reclaimed.",'Fixed a misleading "Could not connect to the Codex session" flash while a conversation switches; it shows the shared loading state instead.']}},{version:"0.29.0",date:"2026-09-16",highlight:{zh:"可信设备与可信地址保护",en:"Trusted device and address protection"},items:{zh:["新增 Token + 可信设备双层认证,以及可信地址保护;支持网页和 CLI 管理设备、授权、有效期与撤销。","新增清晰的认证控制:可查看并开启两层保护,明确授权范围和关闭风险。","修复 DeepSeek 欠费金额显示错误。"],en:["Added layered Token + trusted-device authentication and trusted address protection, with Web and CLI management for devices, authorization, expiry, and revocation.","Added clear authentication controls for viewing and enabling both protection layers, with explicit authorization scope and disable-risk guidance.","Fixed incorrect DeepSeek overdue balances."]}},{version:"0.28.0",date:"2026-09-11",highlight:{zh:"Claude 对话更可靠 · 工具图片预览",en:"More reliable Claude chat · tool image previews"},items:{zh:["对话页新增工具图片预览:图片按实际比例居中显示,支持缩放、保存、分享和失败重试。","修复 Claude 停止、compact、原生命令、选项选择和收件箱状态异常导致消息排队的问题。","修复模型和 Goal 弹窗切换会话后重复打开;队列编辑、Codex /review 和工作区状态更可靠。"],en:["Added tool image previews in chat: images stay centered at their natural size, with zoom, save, share, and retry support.","Fixed Claude stop, compaction, native commands, option selection, and Inbox states leaving messages queued.","Fixed Model and Goal sheets reopening after session switches; queue editing, Codex /review, and workspace state are more reliable."]}},{version:"0.27.2",date:"2026-09-08",highlight:{zh:"修复多标签页偶发鉴权弹窗",en:"Fix intermittent authentication prompts across tabs"},items:{zh:["修复切换浏览器标签页或实时终端连接延迟时,偶发误弹鉴权页面的问题。"],en:["Fixed an intermittent authentication prompt when switching browser tabs or when a live terminal connection was delayed."]}},{version:"0.27.1",date:"2026-09-08",highlight:{zh:"腾讯语音 · 终端光标修复 · Codex 对话恢复",en:"Tencent voice · terminal cursor fixes · Codex chat recovery"},items:{zh:["面向 0.26 升级用户的完整汇总:0.27.0 已公开 GitHub 源码和 Release,但未完成 npm / Homebrew 分发;本版承接这些更新并加入后续修复,保留 0.27.0 历史记录。","语音新增腾讯实时与一句话识别,保留讯飞实时识别;三种方案共享音量波形与录音动效,识别文字插入起录时的光标位置,不清空已有草稿。","handmux setup 会验证语音配置;设置页可调整腾讯语气词过滤级别,关闭语音保留方案和凭据。","修复语音录制、网络或识别失败没有提示,以及终端录音时点击输入框丢失最终文字的问题;终端聊天与对话输入卡片均可点击停止录音并完成识别。","修复实时终端输入后的双光标、光标停在上一字符及文件路径高亮闪烁问题。","工具输入、输出和 Diff 裁剪时在实际位置说明原因;修复 Codex 上下文压缩时内部摘要短暂闪入正文的问题。","终端与对话字体可分别调整,对话字号支持 10–20px;终端字号在两种视图下均可设置,消息正文字号不影响工具详情。","修复原生 Codex 无法进入对话接管页的问题;核实准确会话后接管,中断时提供安全恢复或可复制命令指引;handmux codex resume 默认与原生命令一样只列当前目录会话。","修复服务重启时对话消失并跳回终端,以及 compact 后重发成功仍残留“已发送”的问题;临时反馈离窗即丢弃,成功占位最多保留 10 秒,不影响真实队列和历史。","修复 iOS 对话发送箭头不可见的问题。"],en:["A complete roundup for users upgrading from 0.26: 0.27.0 source and its GitHub Release were public, but npm / Homebrew distribution was not completed. This version carries those updates plus subsequent fixes; the 0.27.0 history is retained.","Voice input adds Tencent real-time and sentence recognition alongside iFlytek real-time recognition. All three share level waveforms and recording animation, inserting text at the recording-start caret without clearing the draft.","handmux setup verifies voice configuration. Settings can adjust Tencent filler-word filtering; turning voice off retains the profile and credentials.","Fixed silent voice capture, network, or recognition failures and lost final text when tapping the terminal input during recording. Both terminal chat and the chat input card can be tapped to stop recording and finish recognition.","Fixed duplicate live-terminal cursors, cursors left on the preceding character after typing, and flickering file-path highlights.","Truncated tool input, output, and diffs explain the limit at the actual cut point. Fixed an internal summary briefly flashing into chat during Codex compaction.","Terminal and chat font sizes can be set independently, with chat supporting 10–20px. Terminal font size remains adjustable in either view; message font size does not affect tool details.","Fixed native Codex sessions missing the chat takeover page. Takeover verifies the exact session and offers safe recovery or a copyable command after interruption. handmux codex resume now defaults to the current directory, matching the native command.","Fixed chat disappearing into terminal during Server restarts and sent placeholders lingering after a compact-time retry. Temporary feedback is discarded on leaving; accepted placeholders last at most 10 seconds without affecting real queues or history.","Fixed the invisible iOS chat send arrow."]}},{version:"0.27.0",date:"2026-09-05",highlight:{zh:"腾讯语音输入 · 终端输入更准确",en:"Tencent voice input · more accurate terminal typing"},items:{zh:["语音输入新增腾讯实时与一句话识别,同时保留讯飞实时识别;三种方案共享实时音量波形与录音动效,识别文字会插入起录时的光标位置,不会清空已有草稿。","语音配置会在首次设置、切换方案或修改字段后直接验证;设置页可调整腾讯语气词过滤级别,关闭语音会保留方案和凭据以便重新开启。","修复语音录制、网络或服务商识别失败时没有提示的问题;未识别出文字时也会明确提示重试。","修复实时终端连续输入英文、中文或使用方向键后偶发双光标或光标停在上一字符的问题;现在文字顺序正确,光标只在正确位置显示一次。","修复 Codex 上下文压缩期间内部摘要短暂闪入正文的问题;工具输入、输出和 Diff 被裁剪时也会在实际位置说明原因。"],en:["Voice input adds Tencent real-time and sentence recognition alongside iFlytek real-time recognition. All three share the live level waveform and recording animation, and insert recognized text at the caret captured when recording started without clearing the draft.","Voice configuration is verified after initial setup, a profile switch, or a field edit. Settings can adjust Tencent filler-word filtering, while turning voice off keeps the selected profile and credentials ready for re-enabling.","Fixed voice capture, network, or provider recognition failures producing no visible feedback; an empty recognition result now clearly asks you to retry.","Fixed live terminal typing occasionally showing two cursors or leaving the cursor on the preceding character. English and Chinese typing now stays in order with arrow-key navigation, and the cursor appears only once at the correct position.","Fixed an internal summary briefly flashing into chat during Codex compaction. Truncated tool input, output, and diffs now also explain the limit at the actual cut point."]}},{version:"0.26.0",date:"2026-09-04",highlight:{zh:"对话精细复制 · Pi 上下文状态",en:"Precise chat copy · Pi context status"},items:{zh:["手机端 Agent 对话支持精细复制:长按消息、工具、Diff 或错误文字选词,拖动首尾手柄调整,并可扩展到屏幕整行或语义整段;流式更新和滚动期间也会保留选区。","Pi 对话的上下文圆环现在显示原生实时用量、运行状态和工作目录;升级会可靠刷新 Connector,已在运行的 Pi 会话执行 /reload 后即可获得新能力。","修复 Codex 历史中的 Diff 使用工作区外绝对临时路径时,更早的消息无法加载的问题。","修复 Codex 只读沙箱配合自动审批时,权限模式被误显示为“自定义”的问题。","修复空收件箱被单个异常 Agent pane 的降级状态长期覆盖为“正在重新连接”的问题。"],en:["Agent chat now supports precise copying on touch devices: long-press message, tool, diff, or error text to select a word, drag either handle to refine it, or expand to the rendered line or semantic paragraph; selections also survive streaming updates and scrolling.","Pi chat’s context ring now shows native live usage, activity, and working directory. Upgrades reliably refresh the Connector; run /reload in an already-open Pi session to expose the new capability.","Fixed older Codex history failing to load when a diff used an absolute temporary path outside the workspace.","Fixed Codex read-only sandbox with automatic approval being mislabeled as a custom permission mode.","Fixed an empty Inbox being indefinitely replaced by “Reconnecting” when a single Agent pane was degraded."]}},{version:"0.25.2",date:"2026-09-02",highlight:{zh:"修复 Agent 对话断流、排队与工具路径",en:"Fixed Agent chat streams, queues, and tool paths"},items:{zh:["修复 Codex 上下文压缩后回复不再实时显示,以及 Pi 历史推进、授权内容更新或 Bridge 启动失败后,对话可能断开、空白或无法重试的问题。","发送状态未知的排队消息会先沿用原消息 ID 安全重试;若仍无法确认,消息会回到对话中,由你决定是否作为新消息再次发送。","工具输入和输出中的本地路径恢复可读;用户主目录缩写为 ~/,密码、Token、Cookie 和私有地址仍会脱敏。","修复订阅用量卡片操作菜单未靠右,以及再次点击三点按钮不能收起菜单的问题。"],en:["Fixed replies no longer streaming after Codex compaction, plus chats disconnecting, going blank, or becoming non-retryable after Pi history advances, authorization updates, or Bridge startup failures.","Queued messages with unknown delivery now retry under their original message ID first; if delivery still cannot be confirmed, the message returns to the conversation so you can choose whether to send it again as new.","Local paths in tool input and output are readable again. User home directories are shortened to ~/, while passwords, tokens, cookies, and private endpoints remain redacted.","Fixed subscription-usage action menus not aligning to the right and not closing when their three-dot button was tapped again."]}},{version:"0.25.1",date:"2026-09-02",highlight:{zh:"修复 Codex 幽灵任务与对话空白",en:"Fixed Codex ghost tasks and blank chats"},items:{zh:["修复 Codex 自动生成标题或回顾摘要的临时线程被误认成当前会话,导致收件箱批量出现无法完成的幽灵“进行中”、对话页报错后空白的问题;服务重启后会重新绑定真实会话并自动撤销旧假状态。"],en:["Fixed Codex title and catch-up helper threads being mistaken for the current conversation, which created ghost “Working” inbox entries and left chat blank after an error. A Server restart now rebinds the real conversation and automatically withdraws stale false states."]}},{version:"0.25.0",date:"2026-09-01",highlight:{zh:"Pi 原生接入 · 多 Agent 对话更可靠",en:"Native Pi support · more reliable agent chat"},items:{zh:["新增 Pi 原生接入:运行 handmux agent enable pi 显式启用接入,以后用 handmux pi 日常启动原生 TUI;Handmux 离线时 Pi 仍可正常使用,结果会在本机等待重放。Pi 对话需在设置中独立开启,当前仍为实验性功能。","Claude Code、Codex 与 Pi 统一接入新的 Agent Runtime:多 pane 状态、完成与出错通知、跨设备已读和实时对话现在由同一套持久数据链提供。","用量页支持单独刷新订阅;Codex 可查看账号、套餐与细分额度,API 分栏可在本机加密保存多个 DeepSeek 和 Moonshot (Kimi) 账户并读取官方余额。","Codex 对话在长会话、切换 pane、Server 重启和弱网重连时更稳定;新会话首条消息、排队与立即引导、发送失败重试、上下文压缩详情都会原位恢复并持续对账。","重写对话滚动与历史分页:上拉阅读不再被新输出抢回底部或推到页首;桌面复制、键盘焦点、前后台重连和统一错误提示也更符合系统习惯。","文件上传支持 ZIP;中文 Markdown 路径、绝对目录和普通句点不再误判或乱码。会话状态还能直接查看当前 Git worktree 根路径与分支。","最低运行环境提高到 Node.js 22.16;低版本会在启动前得到明确升级提示,Homebrew 安装仍会自动提供所需 Node。开机恢复恰遇 npm 替换 Agent 时会短暂等待安装完成,不再误报未安装或丢失恢复的 pane。"],en:["Added native Pi integration. Run handmux agent enable pi once, then use handmux pi for everyday native-TUI launches; Pi remains usable while Handmux is offline, with results queued locally for replay. Pi chat is independently enabled in Settings and remains experimental.","Claude Code, Codex, and Pi now share the new Agent Runtime, with one durable data path for multi-pane state, completion and error notifications, cross-device read state, and live conversations.","Usage subscriptions can now be refreshed individually. Codex shows account, plan, and detailed limits, while the API tab saves multiple DeepSeek and Moonshot (Kimi) accounts encrypted on this computer and reads their official balances.","Codex chat is more reliable across long sessions, pane switches, Server restarts, and weak-network reconnects. First sends, queued and guided messages, safe retries, and context-compaction details now recover and reconcile in place.","Reworked chat scrolling and history pagination so new output no longer steals the reading position or jumps to the top. Desktop copy, keyboard focus, foreground reconnects, and unified error feedback now follow platform conventions more closely.","ZIP uploads are supported. Chinese Markdown paths, absolute directories, and ordinary punctuation no longer become broken links, while session status now shows the current Git worktree root and branch.","The minimum runtime is now Node.js 22.16. Older runtimes receive a clear pre-launch upgrade message, while Homebrew continues to install the required Node automatically. If startup recovery overlaps an npm Agent replacement, Handmux briefly waits for installation instead of falsely reporting the Agent missing or losing restored panes."]}},{version:"0.24.0",date:"2026-08-11",highlight:{zh:"Codex 任务进度与 Goal 原生上线",en:"Native Codex task progress and Goals"},items:{zh:["Codex 对话新增只读回合任务列表:当前运行步骤带动态状态,点按可用 Bottom Sheet 查看完整计划;回合结束后保留可恢复的任务摘要。","Goal 现在完整融入对话:设置或重新开始会立即创建并启动新目标,进行中或暂停的目标常驻在任务列表下方,历史状态留在对应回合;统一详情支持编辑后重新开始、暂停、继续与清除。","终端与对话可预览任意扩展名的文本文件;打开前会按内容区分文本与二进制,普通斜杠文字和未知 Markdown 目标不再误变成可点击路径。","修复了发送消息后回复偶尔排到用户消息上方,以及主屏 App 从其他应用返回后终端或 Codex 对话可能停在旧画面的问题。","Server、Web 与 CLI 底层完成严格 TypeScript 迁移,发布包改为只运行编译产物,并补强了私密状态、会话队列、服务恢复与错误边界。"],en:["Added a read-only turn task list to Codex chat: the active step carries a live indicator, the full plan opens in a Bottom Sheet, and a restorable task summary remains after the turn.","Goals now live naturally in chat: setting or restarting creates and starts a fresh Goal immediately, active or paused Goals stay below the task list, and history stays with its original turn; one shared detail sheet supports edit-and-restart, pause, resume, and clear.","Preview text files with any extension from terminal or chat. A content check separates text from binary files, while slash-separated prose and unknown Markdown targets no longer become misleading file links.","Fixed replies occasionally appearing above the user message that started them, and terminal or Codex chat getting stuck on an old screen after returning to the installed app.","Migrated the Server, Web app, and CLI internals to strict TypeScript, made release packages run compiled output only, and strengthened private state, session queues, service recovery, and API error boundaries."]}},{version:"0.23.0",date:"2026-08-09",highlight:{zh:"Codex 托管对话正式上线",en:"Managed Codex chat is here"},items:{zh:["新增 Codex 托管对话视图:手机与终端保持同一会话,可实时查看 Markdown 回复、完整工具调用、提问与审批,并直接停止任务;断线或重新打开后仍能恢复完整对话。","可用 handmux codex 直接启动托管会话,也可从普通 Codex 窗格原位接管并恢复准确会话;需要终端确认时会明确提示。","Codex 回复期间可继续发送消息:默认按条排队到后续回合,也可编辑、删除或立即引导当前回复。","输入区可直接调整模型、思考强度、Fast 和权限,查看上下文与会话状态,并使用 /goal、/compact、/clear;回复中的文件与网址也可直接在应用内打开。","Codex 与 Claude Code 对话开关现已分开;Codex 正式支持托管对话,Claude Code 对话仍为独立的实验性功能。","修复了应用长时间切到后台后不刷新、多窗格面板受网络阻塞,以及 iPhone 软键盘可能导致终端尺寸异常的问题。"],en:["Added managed Codex chat: the phone and terminal stay on the same session, with live Markdown replies, complete tool calls, questions, approvals and stopping; the full conversation recovers after a disconnect or reopen.","Start a managed session with handmux codex, or take over a plain Codex pane in place and resume its exact session; Handmux clearly asks you to switch to the terminal when confirmation is needed.","Keep sending while Codex is working: messages queue one by one for later turns, or can be edited, deleted, or guided into the current turn immediately.","Change the model, reasoning effort, Fast and permissions from the composer, inspect context and session status, use /goal, /compact and /clear, and open files or URLs from replies directly in the app.","Codex and Claude Code chat now have separate switches: managed Codex chat is fully supported, while Claude Code chat remains an independent experimental feature.","Fixed stale state after a long app switch, network-blocked multi-pane panels, and iPhone soft-keyboard transitions that could leave the terminal at the wrong size."]}},{version:"0.22.1",date:"2026-08-04",highlight:{zh:"网页宽度与网站版本分开控制",en:"Separate page width and site-version controls"},items:{zh:["网页预览器将窄屏 / 宽屏与手机版 / 电脑版分开:宽度切换不重载页面,电脑代理可另外向网站请求所需版本并保留登录状态。","修复了电脑代理临时重启、会话过期或丢失后可能停在错误页的问题,当前标签现在会自动恢复。"],en:["Web Preview now separates narrow/wide page width from mobile/desktop site requests: width changes do not reload, while computer proxy tabs can request a site version and keep their sign-in state.","Fixed proxy tabs getting stuck on an error page after the computer proxy restarted or a browser session expired or disappeared; the current tab now recovers automatically."]}},{version:"0.22.0",date:"2026-08-03",highlight:{zh:"全屏设置 · 窗口与分屏管理更清晰",en:"Full-screen Settings · clearer window and pane management"},items:{zh:["设置改为全屏分组页面:常用选项使用统一的二级页,版本、更新日志、反馈和重新加载应用集中在首层。","列宽调整移到对应的窗口管理或窗格管理中;单窗格调整窗口宽度,多窗格只调整所选窗格,并可恢复自动宽度或原分屏比例。","推送通知、脚本推送和脚本推送记录的入口重新整理;关闭通知前会先确认,同一 App 安装重新开启后仍保留原设备 key。","修复了冷启动时实时终端先显示快照,以及重启后从最近访问打开静态目录产生重复标签的问题。"],en:["Settings is now a full-screen grouped page with consistent detail views, while version, changelog, feedback, and Reload app stay on the first level.","Column sizing now lives in Window or Pane Management: resize a single-pane window or the selected pane in a split, then restore automatic width or the original split ratio.","Push notifications, Script push, and Script Push History are arranged more clearly; turning notifications off requires confirmation, and re-enabling keeps the same device key for that app installation.","Fixed live terminals briefly starting in snapshot mode and static directories opening as duplicate tabs from Recently Visited after a restart."]}},{version:"0.21.0",date:"2026-08-03",highlight:{zh:"网页预览:手机直连、电脑代理与静态目录",en:"Web preview: direct, computer proxy, and static folders"},items:{zh:["新增常驻网页预览器:可由手机直连开发服务、localhost、内网和允许嵌入的网站,也可在配置 previewDomain 后经电脑代理访问;静态目录预览也已融合到同一界面。","网址和静态目录现在使用统一的持久标签与最近访问;切换标签会保留页面、滚动和表单状态,支持手机/电脑视图、网页缩放、刷新、停止及用系统浏览器打开。","电脑代理支持按设备隔离的 Cookie Profile,可在相关企业系统间复用 SSO Cookie,并可选择加密持久化、按网站清理或全部清理。","运行 handmux 的最低 Node.js 版本由 18 提升至 20;网页电脑代理使用的底层依赖要求 Node.js 20。"],en:["Added a persistent Web Preview for direct phone access to development services, localhost, intranet pages, and sites that allow embedding, plus computer proxy access after previewDomain is configured; static folders now share the same interface.","URL and static-folder previews now use unified persistent tabs and recent history; switching tabs preserves page, scroll, and form state, with mobile/desktop views, page zoom, refresh, stop, and Open in system browser.","Computer proxy mode supports a device-isolated Cookie Profile that can reuse SSO cookies across related enterprise systems, with optional encrypted persistence and per-site or full cleanup.","The minimum Node.js version for running handmux increased from 18 to 20 because the computer proxy's underlying dependency requires Node.js 20."]}},{version:"0.20.3",date:"2026-08-01",highlight:{zh:"实时终端显示更稳定流畅",en:"More stable, smoother live terminals"},items:{zh:["修复了实时终端持续输出时偶发缺行,以及内容较短、首次打开或展开键盘时画面位置不稳定的问题;长时间使用和多窗口同时打开也更流畅。"],en:["Fixed occasional missing lines during continuous live output and unstable positioning with short content, first open, or keyboard expansion; long sessions and multiple visible windows also stay smoother."]}},{version:"0.20.2",date:"2026-07-27",highlight:{zh:"实时终端长时间运行更流畅",en:"Smoother long-running live terminals"},items:{zh:["实时终端长时间打开、连续输出大量内容或电脑同时显示多个 PWA 时保持流畅;输出积压时会跳过过期画面并同步最新终端状态,tmux 历史仍可继续查看。"],en:["Live terminals stay responsive during long sessions, heavy output, and multiple visible PWAs; stale intermediate frames are skipped when output falls behind, while the latest tmux state and scrollback remain available."]}},{version:"0.20.1",date:"2026-07-26",highlight:{zh:"聊天发送修复 · 电脑键盘不中断",en:"Reliable chat sending · uninterrupted desktop input"},items:{zh:["电脑端焦点落在 Window 工具栏后,物理键盘输入和 Shift+Enter 仍会作用于当前终端;F5、F12 保留给浏览器。","修复了聊天模式选择文件后没有开始上传、快速连按重复发送同一条内容的问题;空内容发送 Enter 的能力保持不变。"],en:["Physical keyboard input and Shift+Enter keep working after focus lands on the Window toolbar; F5 and F12 remain available to the browser.","Fixed chat uploads not starting after file selection and rapid taps sending the same content more than once; sending Enter with an empty composer remains available."]}},{version:"0.20.0",date:"2026-07-26",highlight:{zh:"终端实时推送 · 弱网自动回退",en:"Live terminal pushing · automatic network fallback"},items:{zh:["手机和电脑的终端输出现在通过 WebSocket 实时推送;首次打开即可上滑浏览最近的 tmux 历史,继续上滑会加载更早内容,回到底部后重新同步最新画面。","实时连接不可用或持续较差时会自动回退到快照拉取,稳定 30 秒后尝试恢复;右上角显示当前模式与延迟,设置中也可固定使用快照拉取并选择刷新频率。","设置中新增「重新加载应用」,服务端更新后无需退出主屏应用即可载入新版客户端;设置二级页面和弹窗现在会按层返回。"],en:["Terminal output now uses WebSocket live pushing on phone and desktop; scroll up immediately for recent tmux history, keep scrolling for older content, and return to the bottom to resynchronize the latest screen.","An unavailable or persistently poor live connection automatically falls back to snapshot pulling and retries after 30 stable seconds; the top-right status shows the current mode and latency, while Settings can pin snapshot pulling and choose its refresh rate.","Settings now includes Reload app, so an updated server can load the new client without quitting the home-screen app; nested Settings pages and dialogs also return one layer at a time."]}},{version:"0.19.0",date:"2026-07-25",highlight:{zh:"电脑物理键盘直输 · Window 切换更流畅",en:"Desktop keyboard input · faster window switching"},items:{zh:["电脑浏览器现在可以用物理键盘直接操作终端,并支持常用终端快捷键、输入法和复制粘贴;Shift+Enter 可进入保留快捷用语、上传、历史和语音的草稿模式,设置中也可手动指定手机或电脑键盘模式。","全站滚动条现在更统一;终端内容超宽时会显示独立横向滚动条,网络较慢时切换 Window 也会立即进入目标终端的加载页面。","Agent 用量现在稳定展示所有设备共享的本机最新状态,Codex 主额度与 CLI /status 保持一致。"],en:["Desktop browsers can now drive the terminal directly from a physical keyboard, with common terminal shortcuts, IME, and copy/paste; Shift+Enter opens draft mode with shortcuts, uploads, history, and voice intact, and Settings can force Mobile or Desktop keyboard mode.","Scrollbars are now consistent across the app; wide terminal content gets its own horizontal scrollbar, and switching Windows on a slow network enters the target terminal loading view immediately.","Agent usage now keeps the latest machine state stable and shared across devices, while the main Codex quota matches CLI /status."]}},{version:"0.18.0",date:"2026-07-22",highlight:{zh:"Tmux 工作区恢复 · 快捷栏自由定制",en:"Tmux workspace recovery · customizable shortcuts"},items:{zh:["新增 Tmux 工作区恢复:电脑或 Tmux 重启后,可从手机或 handmux restore 恢复上次的会话、窗口、分屏、目录和布局;Claude Code / Codex 会话还能继续原对话。","新增 handmux shortcuts:可分别配置命令与聊天模式的共享快捷项;每台手机也能自由混排共享与本机项,或只在本机移除共享项。","handmux setup 现在可以配置动态预览域名;预览不再自动续期,需要延长时由你手动续期或重新打开。"],en:["Added Tmux workspace recovery: after the computer or Tmux restarts, restore the previous sessions, windows, panes, working directories, and layouts from the phone or handmux restore; Claude Code and Codex sessions can also continue their original conversations.","Added handmux shortcuts to configure shared command-mode and chat-mode items; each phone can also freely mix shared and local items or remove a shared item only on that device.","handmux setup can now configure the dynamic-preview domain; previews no longer renew automatically and can be extended manually or reopened when needed."]}},{version:"0.17.8",date:"2026-07-20",highlight:{zh:"分屏地图显示尺寸 · iPhone 交互修复",en:"Pane dimensions in the map · iPhone interaction fixes"},items:{zh:["分屏地图现在会在空间足够的窗格里低调显示真实终端尺寸(列×行),较小窗格仍保持简洁。","修复了分屏地图在 iPhone 上无法显示、长按窗格时触发系统文字选择的问题。","设置分屏列宽时现在会读取当前窗格的实际宽度,不同窗格不再互相沿用调整值。"],en:["The pane map now quietly shows each terminal's real columns × rows when space allows, while smaller tiles stay uncluttered.","Fixed the pane map failing to appear on iPhone and long-pressing a pane triggering the system text-selection UI.","Pane-width settings now read the active pane's actual width, so adjustments no longer carry over between panes."]}},{version:"0.17.7",date:"2026-07-20",highlight:{zh:"单实例启动兜底 · WSL 状态命令修复",en:"Single-instance startup guard · WSL status fix"},items:{zh:["修复安装开机自启后升级、重启可能产生两个后台实例,导致端口占用、URL 不出现或 stop 后仍可访问的问题;启停命令现在统一管理同一个服务,发现重复副本会列出 PID 并全部回收。","handmux status 现在显示实际运行版本,升级后可区分已安装版本;修复了 WSL 中内容显示完毕却不返回命令行的问题。"],en:["Fixed upgrades or restarts creating two background instances after autostart was installed, which could occupy the port, hide the URL, or remain reachable after stop; lifecycle commands now manage one service and list/reap every duplicate PID.","handmux status now shows the actual running version and distinguishes a newly installed version; fixed WSL terminals not returning to the prompt after status output completed."]}},{version:"0.17.6",date:"2026-07-20",highlight:{zh:"推送结果可追踪 · 对话与权限操作更可靠",en:"Traceable push results · safer chats and permissions"},items:{zh:["脚本通知现在会按设备显示成功或失败,失败详情会区分订阅失效、限流、推送服务不可用、拒绝和网络错误;handmux push 也不会再把零送达或部分失败报告为成功。","修复了关闭通知、打开或删除通知记录、查询设备 key 等操作在浏览器或网络无响应时可能一直等待的问题;关闭本地通知开关现在会立即生效。","长对话轮询不再遍历整段会话;历史记录统一每次加载 20 条,首次打开不足一屏时也会自动继续补取更早内容。","权限确认卡调整为左侧取消、右侧确认;取消需要在 2 秒内再次点击,避免误触中断正在等待的请求。"],en:["Script notifications now show success or failure per device, with details for expired subscriptions, rate limits, unavailable push services, rejection, and network errors; handmux push no longer reports zero delivery or partial failure as success.","Fixed notification disabling, inbox loading or deletion, and device-key lookup waiting forever when the browser or network stops responding; the local notification switch now turns off immediately.","Long-chat polling no longer walks the entire session; history loads 20 messages at a time and automatically keeps fetching older messages when the first page does not fill the screen.","Permission cards now place Cancel on the left and Confirm on the right; cancellation requires a second tap within two seconds to prevent accidentally interrupting a pending request."]}},{version:"0.17.5",date:"2026-07-20",highlight:{zh:"通知开启修复 · 长会话与设置可靠性提升",en:"Notification setup fixed · stronger chat and settings reliability"},items:{zh:["修复了安卓 Chrome 开启通知永久转圈、失效订阅假报成功以及更换域名后收不到通知的问题;注册、激活、FCM 与服务器上报现在会分别检查,失效订阅可自动重置。","修复了超长对话反复全量解析、可能拖慢服务并持续占用手机内存的问题;对话记录改为增量读取并限制缓存规模。","恢复设置里的完整版本更新历史;有新版本时的升级提示仍只展示最新一条,更早版本可按需展开。","修复通知记录加载或删除失败时误显示为空、消息短暂消失的问题,现在会保留已有内容并提示重试。","修复 Agent 退出后偶尔残留旧状态、普通 Node 程序被误认成 Codex 的问题;动态预览认证也限制在当前子域,启动失败会显示真实原因。"],en:["Fixed Android Chrome notification setup spinning forever, stale subscriptions being reported as enabled, and notifications not arriving after a domain change; registration, activation, FCM, and server reporting are now checked separately, with expired subscriptions reset automatically.","Fixed very long chats being repeatedly parsed in full, which could slow the service and keep growing phone memory use; transcripts now load incrementally with bounded caches.","Restored the complete version history in Settings; the upgrade prompt still shows only the newest release by default, with older versions expandable on demand.","Fixed notification history appearing empty or briefly losing a message when loading or deletion failed; existing content is now preserved with a retry action.","Fixed stale Agent state after exit and ordinary Node programs occasionally being mistaken for Codex; dynamic-preview authentication is now scoped to the current subdomain and startup failures show their real cause."]}},{version:"0.17.4",date:"2026-07-19",highlight:{zh:"HTTPS 本机预览修复 · 通知链接安全加固",en:"HTTPS localhost previews fixed · safer notification links"},items:{zh:["修复了 HTTPS/WSS 本机服务无法一键预览、带 # 的深链打开失败,以及 Codex pane 偶尔误出现 Claude 对话视图的问题;通知跳转链接也增加了安全校验。"],en:["Fixed one-tap previews for local HTTPS/WSS services, deep links with # fragments, and Claude chat view occasionally appearing on a Codex pane; notification links now receive stricter safety checks too."]}},{version:"0.17.3",date:"2026-07-19",highlight:{zh:"三修官方一键安装的 Claude 识别,真机已验证",en:"Third fix for native-install Claude detection, device-verified"},items:{zh:["修复了官方一键安装器版 Claude Code 仍识别不出的问题(0.17.2 的对账依据在真实环境不成立);本次按真机数据修正,已验证所有官方安装方式都能正确识别(agent 图标、对话视图切换钮正常出现)。"],en:["Fixed native-installer Claude detection still not working (0.17.2 relied on a signal that doesn't hold in the real environment); corrected against real-device data — verified across all official install methods (agent icon and chat-view switch appear)."]}},{version:"0.17.0",date:"2026-07-18",highlight:{zh:"对话视图(实验性)· 通知记录 · 本机地址一键预览",en:"Chat view (experimental) · notification inbox · one-tap localhost preview"},items:{zh:["新增「对话视图」(实验性功能,默认关):到设置里打开「启用对话视图(实验性功能)」后,窗口栏就能把 Claude 会话在终端/对话两个视图间一键切换(需已装 Claude hooks,没装可一键安装)。对话视图把会话读成聊天记录——气泡 + Markdown、工具卡(编辑文件带 +A/−B 和彩色 diff)、Claude 提问时点按即答的问题卡、上下文压缩动画、三套暖色配色;终端视图照旧,完全不受影响。","新增「通知记录」:脚本推送(handmux push)的通知按设备留存(各 100 条),全屏翻看、点开看详情、逐条删除;点手机上的通知直接跳到那条消息的详情。","终端里打印的本机地址(localhost:3000 等)自动变成可点的:点一下就能起代理在手机上预览(带路径),多个端口还能并行切换、自动续期。"],en:["New chat view (experimental, off by default): enable it in Settings → Enable chat view, then flip a Claude pane between terminal and chat from the window bar (requires Claude hooks — one-tap install offered). The chat view reads the session as a conversation — bubbles with Markdown, tool cards (+A/−B and colored diffs for file edits), question cards you answer with a tap, a visible compaction animation, and three warm colour tones. The terminal view is untouched.","New notification inbox: pushes from handmux push are kept per device (latest 100) — browse full-screen, open details, delete one by one; tapping a push lands on that message’s detail.","Localhost URLs printed in the terminal (localhost:3000, …) are now tappable: one tap proxies and previews them on your phone (path preserved), with several ports open in parallel and auto-renewed."]}},{version:"0.16.0",date:"2026-07-15",highlight:{zh:"分屏布局地图 · 手机也能建/删窗格",en:"Split-layout map · create & close panes from the phone"},items:{zh:["有多个窗格的窗口,选择器不再是一条干巴巴的下拉列表,而是照着你屏幕上真实的分屏样子画出来:每一格对应一个窗格,标着序号、正在跑的命令和 Agent 图标,一眼就看出谁在左谁在右、谁在上谁在下,点一下就切过去看那一格。","现在手机上就能直接分屏和关窗格了:长按地图里的某一格,就能把它「左右分屏」或「上下分屏」,也能「关闭」;还没分屏的窗口在它的菜单里也能分,已经分屏的窗口菜单里点「管理分屏」直接进地图。分好之后自动就落在新的那格里,地图也一直开着,随时能接着分或关。","绑定会话的弹窗更清楚了:「新建会话」和「选已有会话」分成两个明确的选项,不会再让人以为点一下「新建」就直接把会话建出来。"],en:["For a window with several panes, the picker is no longer a plain dropdown — it’s drawn to match the way your screen is actually split: each tile is one pane, labelled with its number, the command it’s running, and its agent, so you can tell at a glance which pane is where. Tap a tile to jump to that pane.","You can now split and close panes right from the phone: long-press a tile in the map to Split it left/right or top/bottom, or Close it; a window that isn’t split yet can be split from its menu, and a split window has a “Manage split” entry that opens the map. After a split you’re dropped into the new pane, and the map stays open so you can keep splitting or closing.","The bind-session dialog is clearer: “New session” and “Pick an existing session” are now two distinct choices, so tapping “New” no longer looks like it creates a session on the spot."]}},{version:"0.15.0",date:"2026-07-14",highlight:{zh:"键盘弹起终端自适应 · 全屏程序可上下滚动",en:"Keyboard-aware terminal · scroll inside full-screen apps"},items:{zh:["键盘弹起时终端不再被顶飞:内容自动重排到键盘上方,主屏短内容贴着键盘上沿显示;全屏程序(vim/less/htop 等)可以在里面上下滚动、到顶/底才翻页,默认显示程序的第一行,移动光标时自动跟随。","全屏程序翻页键上方新增「适配高度」和「定位」两个按钮:「适配高度」一键缩字号,收起键盘就能把整屏程序完整塞进手机屏;「定位」点亮后高亮光标所在行并跟随,方便在长内容里盯住光标。键盘弹起的瞬间光标也一直可见,不用再补按一下。","收件箱在一种特定场景下抓不到状态变更:你回应了权限弹窗、但那次回应没产生任何收尾信号时(普通授权、拒绝并反馈、或按 ESC 中断),它会停留在「需要你」。这一版补上识别——授权或拒绝反馈后回到「进行中」,ESC 中断则消掉状态。","光标不用点屏幕也能看到了:一进会话就能看到光标位置,发键/发指令后即使 Claude 正在忙也会亮着。","从设置里启动动态端口预览,现在会像静态预览一样自动弹出预览面板。","会话重命名撞到已有名字时,会明确提示「名称已存在」;修复了终端上滑一点后画面自己往上爬的问题。"],en:["The terminal no longer gets shoved off-screen when the keyboard opens: content reflows to sit just above the keyboard, with short main-screen output resting on its top edge. Full-screen programs (vim/less/htop, etc.) now scroll up/down inside themselves and only page at the edges, default to showing the program’s first line, and follow the cursor as you move it.","Two new buttons above the full-screen pager: “Fit height” shrinks the font in one tap so the whole program fits on the phone with the keyboard down, and “Locate” highlights and follows the cursor’s row so you can keep track of it in long content. The cursor also stays visible the moment the keyboard opens — no extra tap needed.","In one specific case the inbox couldn’t pick up a state change: when you responded to a permission prompt but that response produced no closing signal (a normal approval, a deny-with-feedback, or an ESC interrupt), it would linger on “needs you”. This release adds that detection — approving or denying returns it to “working”, and an ESC interrupt clears it.","The cursor now shows without tapping the screen: you can see where it is the moment you open a session, and it stays lit after you send a key/command even while Claude is busy.","Starting a dynamic-port preview from Settings now auto-opens the preview sheet, just like a static one.","Renaming a session to a name that already exists now says so clearly; and fixed the terminal creeping upward a line at a time after a small scroll up."]}},{version:"0.14.0",date:"2026-07-13",highlight:{zh:"终端文字选中拷贝 · 脚本复用推送通道",en:"Terminal select & copy · scripts reuse the push channel"},items:{zh:["终端可以长按选中文字了:iOS 式首尾手柄精调、跨屏选择,浮条一键拷贝/整行/整段,复制自动去掉行尾空格;选中期间顶部显示「复制模式 · N 行 · M 字」。","你自己的脚本也能复用 handmux 的推送通道:命令行用 handmux push <标题> <正文> 直接给手机发通知(可选 --session/--device 限定范围),脚本跑完主动提醒你。","滚动终端不再收起键盘:滑动时键盘保持、单击才收起;还能用 ⌨ 按钮或底部手柄拖拽显隐键盘,命令/聊天切换也保持键盘不掉。","往上滑看历史更顺了:一次滑到顶只加载一页、不再叠加拉取来回跳,位置稳停在你看的那行,顶部显示「距底 N/M 行」。","全屏程序(vim/less/htop 等)上方不再串出无关的终端历史。","修复了主页误触返回直接退出、以及从通知进入要多按一次返回才能退出的问题。"],en:["You can now long-press to select text in the terminal: iOS-style start/end handles, selection across screens, a callout to copy / whole line / whole paragraph, with trailing spaces trimmed on copy. A “copy mode · N lines · M chars” bar shows while selecting.","Your own scripts can reuse handmux’s push channel: run handmux push <title> <body> to send a notification straight to your phone (optionally scoped with --session/--device) — handy for a script pinging you when it finishes.","Scrolling the terminal no longer dismisses the keyboard: a swipe keeps it up, a single tap puts it away; you can also show/hide it with the ⌨ button or the dock’s grip handle, and it stays up when you switch between command and chat.","Scrolling up through history is smoother: reaching the top loads exactly one page instead of stacking pulls and jumping around, and your place holds steady on the line you were reading, with a “N/M lines from bottom” readout.","A full-screen program (vim/less/htop, etc.) no longer leaks unrelated terminal history above it.","Fixed a stray Back on the home page dropping you straight out, and needing an extra Back to leave after opening the app from a notification."]}},{version:"0.13.0",date:"2026-07-12",highlight:{zh:"终端文件路径高亮可点",en:"Tappable, highlighted file paths"},items:{zh:["终端里的文件路径现在会高亮显示、可以直接点开;这个高亮可以在设置里开关(默认关闭)。","桌面浏览器用鼠标滚轮往上翻,现在能拉出更深的历史了(不再卡在第一屏);桌面和手机都加了一条纤细的滚动条。","设置面板太高时可以整体滚动了,标题和关闭按钮始终可见、够得到。","修复了 agent 图标和底部输入模式偶尔乱跳的问题——现在按 agent 是否真的在运行来判断,分屏里每个窗格也各显各的图标。","handmux setup 新增「令牌」一项:可以手动固定访问令牌,这样每次重启后手机网址不再变化(留空则仍每次自动生成一个)。"],en:["File paths in the terminal are now highlighted and tappable — tap one to open it. You can toggle the highlight in Settings (off by default).","On a desktop browser the mouse wheel now pulls deeper history instead of stalling at the first screen, and a thin scrollbar was added on both desktop and mobile.","The Settings sheet scrolls as a whole when it is taller than the screen, with the title and close button always reachable.","Fixed the agent icon and the bottom input mode occasionally jumping around — both now track whether the agent is actually running, and each pane in a split shows its own icon.","handmux setup has a new “Token” item: you can pin the access token by hand so the phone URL stops changing on every restart (leave it blank to keep auto-generating one each start)."]}},{version:"0.12.3",date:"2026-07-11",highlight:{zh:"接管会话可自定义名称 + Homebrew 一键安装",en:"Name a takeover session · Homebrew install"},items:{zh:["接管电脑上的会话时,可以自己给新会话起名(默认也帮你填好);接管后想回电脑继续的命令,现在直接显示成 handmux open <名称>,照着敲即可。","新增 Homebrew 一键安装:没装 Node 的 Mac 也能用 brew install handmux/tap/handmux 一条命令装好(handmux + Node + tmux)。已有 Node 的话,npm i -g handmux 仍是更轻的选择。"],en:["When taking over a session running on your computer, you can now name the new session yourself (a default is filled in), and the “continue on the computer” hint shows the exact command to run — handmux open <name>.","New Homebrew install: on a Mac without Node, brew install handmux/tap/handmux sets up handmux, Node, and tmux in one command. If you already have Node, npm i -g handmux stays the lighter option."]}},{version:"0.12.2",date:"2026-07-11",highlight:{zh:"修复主屏图标偏大 / 换图标后不刷新",en:"Home-screen icon: right size & always fresh"},items:{zh:["修复了「添加到主屏」的图标在安卓上偏大、以及更换图标后旧图标不刷新的问题——图标更新现在会自动生效(已加到 iPhone 主屏的需删掉重加一次)。"],en:["Fixed the Add-to-Home-Screen icon looking oversized on Android and a changed icon not refreshing for returning users — icon updates now apply automatically (one already on an iOS home screen needs a one-time remove + re-add)."]}},{version:"0.12.1",date:"2026-07-11",highlight:{zh:"全新品牌图标与双色字标",en:"New brand icon & two-tone wordmark"},items:{zh:["焕新品牌:全新的发光终端图标(主屏图标、启动页都换了)+ 圆润的双色「handmux」字标(hand 白、mux 青→绿),官网、分享卡和 README 也一并更新。"],en:['Brand refresh: a new glowing terminal app icon (home-screen icon + boot splash) and a rounded two-tone "handmux" wordmark (hand in white, mux teal→green), with the site, share cards, and README updated to match.']}},{version:"0.12.0",date:"2026-07-11",highlight:{zh:"全屏程序也能滑动滚动 · 反馈入口 · 聊天草稿不丢",en:"Swipe-scroll full-screen apps · feedback channels · chat drafts kept"},items:{zh:["全屏程序(vim / htop / less 等)现在能直接滑动滚动了:开了鼠标的程序像电脑滚轮一样滑着滚,没开鼠标的分页器(less / man / git log)靠滑动逐行滚;每个全屏画面右侧还多了一枚翻页按钮做整页跳。","设置里新增「反馈与交流」:直达 GitHub Issues,中文用户还能扫码进微信交流群;README、官网、文档里也都能找到入口。","聊天框里没发出去的内容现在会自动保存,下次打开自动填回——误划走、切后台被杀、崩溃都不会再丢半截提示词。","修复:从终端链接或「最近」直接打开的文档,点返回会一次收起面板,不再被硬塞进「目录」层、再返一次直接退出 App。"],en:["Full-screen apps (vim / htop / less …) now scroll by swipe: mouse-mode apps scroll like a desktop wheel, and pagers (less / man / git log) scroll line-by-line on a swipe; every full-screen view also gets a page up/down button on the right for whole-page jumps.",'New "Feedback" section in Settings: a direct link to GitHub Issues, plus a WeChat user group for Chinese users — also surfaced in the README, the site, and the docs.',"Whatever you've typed in the chat box is now saved automatically and restored next time you open it — an accidental swipe-away, a background kill, or a crash no longer eats a half-written prompt.","Fixed: a doc opened straight from a terminal link or 最近 now closes the sheet in one Back press, instead of being forced into its folder view and then dropping you out of the app on the next Back."]}},{version:"0.11.1",date:"2026-07-09",highlight:{zh:"修复 Node 18 下无法启动的问题",en:"Fixes startup crash on Node 18"},items:{zh:["修复了电脑用 Node 18 时 handmux 任何命令都启动不了的问题(0.11.0 配置向导引入的依赖要求过新的 Node)。"],en:["Fixed handmux failing to start any command on Node 18 (a dependency introduced by the 0.11.0 setup wizard required a newer Node)."]}},{version:"0.11.0",date:"2026-07-08",highlight:{zh:"国内可用隧道 natapp/cpolar · 配置向导重做",en:"China-usable tunnels · setup redesigned"},items:{zh:["新增两条国内可用的隧道 natapp 和 cpolar:当 Cloudflare 在国内不稳定时,用你自己的免费账号就能把手机连到电脑。只要一个 authtoken;想要固定地址就填公网地址,留空则用免费临时域名;cpolar 的客户端还会自动下载。","`handmux setup` 重做成菜单式向导:每项设置一行、直接显示当前值,想改哪项就点哪项,不用再一路问到底。连接分两级——先选隧道类型,再进去配它的参数;推送、语音也各成小面板。第一次用会一步步带你走,默认落在「直连」并停在「保存并启动」,小白也能顺下来。"],en:["Two China-usable tunnels, natapp and cpolar: when Cloudflare is unreliable inside mainland China, reach your computer from your phone using your own free account. Just an authtoken; add a public URL for a fixed address or leave it blank for a free temporary one — and cpolar's client auto-downloads.",'`handmux setup` is now a menu-style wizard: every setting is a row showing its current value, so you jump straight to what you want to change instead of answering every prompt in order. Connection is two levels — pick the tunnel type, then configure it inside; push and voice are their own mini-panels. A first run walks you through it, defaulting to "Direct" with the cursor on "Save & start".']}},{version:"0.10.0",date:"2026-07-06",highlight:{zh:"升级前预览新功能 · 电脑 handmux open 接管",en:"Preview an update before installing · handmux open"},items:{zh:["更新提示现在会提前告诉你新版有什么:检测到有新版本时,设置里会逐版列出这次升级带来的新功能(一句话说明),让你在电脑上跑 `handmux update` 之前就知道值不值得。","电脑上新增 `handmux open <会话名>`:把你在手机上建的会话直接在电脑终端接回来(没有就新建),不用再记 `tmux new -A -s`。绑定/新建会话的弹窗里也加了这句提示。"],en:["The update notice now tells you what a new version brings before you install it: when an update is detected, Settings lists each newer version's highlight in one line, so you know whether it's worth running `handmux update` on your computer.","New `handmux open <session>` on the computer: reclaim a session you created from your phone straight into your computer's terminal (created if missing) — no need to remember `tmux new -A -s`. The bind/create dialog now hints at it too."]}},{version:"0.9.1",date:"2026-07-06",highlight:{zh:"「添加到主屏」引导",en:'"Add to Home Screen" coach'},items:{zh:["新增「添加到主屏」引导:第一次在浏览器里打开时,提示你把 handmux 装到主屏,像 App 一样全屏打开。安卓可一键安装;iPhone 给出 Safari 的「分享 → 更多 → 添加到主屏幕」三步——iOS 上收推送也需要它。装好后不再打扰。"],en:[`New "Add to Home Screen" coach: the first time you open handmux in a browser, it shows how to install it to your home screen and run it full-screen like an app. Android installs in one tap; iPhone gets the Safari steps (Share → More → Add to Home Screen) — which is also what iOS push needs. It won't nag once you've added it.`]}},{version:"0.9.0",date:"2026-07-05",highlight:{zh:"聊天输入框多行重做",en:"Multi-line chat composer redone"},items:{zh:["聊天输入框多行重做:文字占满整行,麦克风/发送悬到右下角,末行快挤到按钮才让出一行——长消息不再被右侧按钮列挤窄,多行时拖光标也不会误收键盘。"],en:["Chat composer redone for multi-line: text takes the full width, mic/send float in the bottom-right corner, and a row is yielded only when the last line actually reaches them — long messages are no longer squeezed by a right-hand button column, and dragging the caret no longer collapses the keyboard."]}},{version:"0.8.0",date:"2026-07-05",highlight:{zh:"快捷栏可自定义 · 上传体验重做",en:"Customizable quick-bars · upload redone"},items:{zh:["命令模式的常用命令分成「全局」和「当前窗口」两组:快捷栏里全局的(灰)排前、当前窗口的(绿)排后。尾部改成 ⚙ 齿轮,点开更高的编辑器分两区、各自 ▲▼ 排序。新增区一行搞定:顶部「命令/按键」大 Tab 选类型,左侧开关选加到全局还是本窗口。命令可勾「带回车」(点一下直接执行,末尾带 ⏎);按键用 ⌃⇧⌥ + 一个基键拼出组合键(如 Ctrl+C),点一下直接发到终端。","聊天模式的快捷条也能自定义了:末尾同样是 ⚙,点开编辑器,「消息/按键」两个 Tab —— 消息就是一句发给 agent 的话(以 / 开头当斜杠命令),按键用同一套 ⌃⇧⌥ + 基键拼组合键(ESC/Tab/退格默认就在里面)。点任意一条可回到弹窗改,▲▼ 排序。","上传体验重做:进度条不再一冲到 100% 就假装完事——先显示真实发送进度,字节发完后转成「服务器接收中…」,大文件不再像卡死。上传中可随时「取消」,已传完的文件会保留。","重名不再报错:上传一个已存在的文件名会自动改名(如 `报告 (1).pdf`),绝不覆盖原文件。上传失败时也会告诉你具体原因(过大 / 不支持的类型)。","现在可以上传视频了(mp4、mov、webm 等)。","Git 面板现在能打开 `/tmp` 等家目录以外的仓库(比如 agent 在 /tmp 里干活的项目),不再报红。","用量进度条新增「时间竖线」:标出当前重置窗口已过去的时间比例。已用量在竖线左边=烧得比时间慢(稳),越过竖线=烧得偏快,一眼看出自己的节奏。","新增版本更新提示:每次打开检测一次,服务端落后于 npm 最新版时设置齿轮亮红点,进设置能看到当前/最新版本号,按提示在电脑上跑 `handmux update` 升级即可。"],en:[`Command mode's saved commands now split into "Global" and "This window": the quick-bar shows global ones (grey) first, then this window's (green). The trailing + is now a ⚙ opening a taller two-section editor, each reorderable with ▲▼. One add row does it all: a big Command/Key tab picks the type, a left switch picks which list it lands in. Commands can tick "Send Enter" (a tap runs it, marked ⏎); keys are built from ⌃⇧⌥ + a base key into a combo like Ctrl+C that fires straight into the terminal.`,"Chat mode's quick-bar is now customizable too: the same ⚙ at the end opens an editor with a Message/Key tab — a message is a line sent to the agent (starts with / for a slash-command), a key is built from the same ⌃⇧⌥ + base-key picker (ESC/Tab/Backspace ship as defaults). Tap any row to re-open the card and edit it, ▲▼ to reorder.","Upload redone: the bar no longer jumps to 100% and then hangs — it shows real send progress, then flips to “receiving on the server…” once bytes are flushed, so a big file no longer looks stuck. You can Cancel mid-upload; already-uploaded files are kept.","Name clashes no longer fail: uploading an existing name auto-renames (e.g. `report (1).pdf`) and never overwrites. Failures now tell you why (too large / unsupported type).","Video files can now be uploaded (mp4, mov, webm, …).","The git panel can now open repos outside your home directory (e.g. a project an agent is working in under `/tmp`) instead of erroring.",`Usage bars now show a "time marker": a thin vertical line at how far the current reset window has elapsed. Usage left of the line = you're burning slower than the clock; past it = faster — pacing at a glance.`,"New update notice: checked once each time you open the app — when the server is behind the latest npm release, the settings gear lights a dot and Settings shows the current/latest version so you can run `handmux update` on your computer."]}},{version:"0.7.0",date:"2026-07-03",highlight:{zh:"新增「用量」页",en:'New "Usage" page'},items:{zh:["新增「用量」页(顶栏仪表盘图标):一眼看 Claude 的 5 小时 / 本周额度进度条 + 重置倒计时,以及 Codex 的额度环。全部读主机本地文件,不登录账号、不调用 API。Codex 零配置即用;Claude 的实时额度需要在电脑上运行一次 handmux hooks install(会装一个 statusLine 捕获器,已有自定义 statusLine 的绝不覆盖)。"],en:["New \"Usage\" page (gauge icon in the top bar): see Claude's 5-hour / weekly limit bars with reset countdowns, plus Codex's quota ring — at a glance. All read from local files on the host: no account login, no API calls. Codex works with zero setup; Claude's live limits need a one-time `handmux hooks install` on the computer (it adds a statusLine capturer and never clobbers an existing custom statusLine)."]}},{version:"0.6.0",date:"2026-07-02",highlight:{zh:"新增 Codex 支持",en:"Codex support added"},items:{zh:["新增 Codex 支持:收件箱与推送现在同时认得 Claude 和 Codex——Codex 会话的「进行中 / 需要你 / 已完成」都会像 Claude 一样推到手机;tmux 外跑着的 Codex 会话也能一键「接管」进来(codex resume);新建会话的启动命令预设新增 codex。收件箱每一条、以及顶栏当前会话,都带上 Claude / Codex 标记,一眼区分是哪种 agent。","会话抽屉底部新增「未接管会话」:一眼看到在 tmux 外跑着、手机还控制不了的 Claude / Codex(带状态、时间、最后一条消息),点「接管」即可在 tmux 里续接同一会话——自动加进会话列表并跳进去,以后手机随时回来。"],en:["Added Codex support: the inbox and push now recognize both Claude and Codex — a Codex session's working / waiting-on-you / done states reach your phone just like Claude. You can take over Codex sessions running outside tmux (codex resume), and there's a new codex startup-command preset. Every inbox row and the current-session topbar now carry a Claude / Codex mark so you can tell the two apart at a glance.",`The session drawer now has a "not taken over" section at the bottom: Claude / Codex sessions running outside tmux that your phone can't steer yet (with their state, time, and last message). Tap Take over to resume the same conversation inside tmux — it's added to your session list and opened, so you can return to it from your phone anytime.`]}},{version:"0.5.0",date:"2026-06-28",highlight:{zh:"首个公开版 · 多语言界面",en:"First public release · multi-language UI"},items:{zh:["首个公开发布版本(npm 上的 handmux)。","新增繁体中文、日语、韩语界面(设置 → Language 切换)。","想法角标:有未完成想法时,灯泡图标右上角显示数量。","设置面板列数调节:实时显示当前列数,新增 ±1 精细调节按钮。"],en:["First public release (handmux on npm).","Added Traditional Chinese, Japanese, and Korean UI (Settings → Language to switch).","Idea badge: when there are pending ideas, the lightbulb icon shows a count in the corner.","Settings column control: shows the current column count live, with new ±1 fine-adjust buttons."]}},{date:"2026-06",label:{zh:"早期内测",en:"Early builds"},highlight:{zh:"早期内测",en:"Early builds"},items:{zh:["新增「Git」面板(顶栏图标):仿 VS Code,一页同屏看变更 + 提交历史,点文件/提交看全屏彩色 diff;只读,不动你的工作树。可绑多个目录用 tab 切换。","新增「想法」管理器(顶栏灯泡):按窗口记待办,可编辑、拖拽排序、一键填入、语音输入。","网站预览:选目录预览静态站点,或填端口预览本机正在跑的服务(走专属子域名);图片预览:文件/终端里点图片(含 GIF)直接内嵌打开,可捏合缩放、长按保存。","文件:上传/下载(进度条、系统分享上传),浏览器打开即落到当前会话目录,支持 /tmp、$TMPDIR;文档在应用内预览 Markdown/txt/log/sh,可语音朗读(逐句高亮)。","收件箱 + Web Push:汇总各会话「进行中/已完成/需要你」,窗口标签带状态色点,需要你时推送到手机。","命令面板:常用 + 每会话最近命令,斜杠命令快捷键(/clear、/compact、/model…)。","可靠性:断线重连(退避 + 每请求超时 + 断线横幅,后台自动暂停轮询),离线兜底页。","首版:手机浏览器驱动真实 tmux 面板(xterm 终端 + 会话/窗口/pane 导航 + 深链),移动按键区、键盘自动抬升、列宽/字号调节,可添加到主屏(PWA)。"],en:['New "Git" panel (top-bar icon): VS Code style — changes + commit history on one screen, tap a file/commit for a full-screen colored diff; read-only, never touches your working tree. Bind multiple dirs and switch via tabs.','New "Ideas" manager (top-bar lightbulb): per-window to-dos — edit, drag to reorder, one-tap insert, voice input.',"Website preview: pick a directory for a static site, or a port for a service running locally (dedicated subdomain); image preview: tap an image (including GIFs) in Files or the terminal to open inline, pinch to zoom, long-press to save.","Files: upload/download (progress bar, share-to-upload), the browser opens straight to the current session dir, /tmp and $TMPDIR supported; documents preview in-app (Markdown/txt/log/sh) and can be read aloud (sentence-by-sentence highlight).","Inbox + Web Push: summarizes each session's In-progress / Done / Needs-you, window tabs get a status color dot, and Needs-you pushes to your phone.","Command panel: frequent + per-session recent commands, slash-command shortcuts (/clear, /compact, /model, …).","Reliability: reconnect on disconnect (backoff + per-request timeout + connection-lost banner, polling auto-paused in the background) and an offline fallback page.","First release: a phone browser drives real tmux panes (xterm terminal + session/window/pane navigation + deep links), a mobile key bar, keyboard auto-lift, column-width/font-size adjustment, and add-to-home-screen (PWA)."]}}],p4=e=>e.version||e.date,ch=mN[0]?p4(mN[0]):null,v4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Xg(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const n=e;return n.kind!=="codex_resume"||typeof n.sessionId!="string"||!v4.test(n.sessionId)||n.command!==`handmux codex resume ${n.sessionId}`?null:{kind:"codex_resume",sessionId:n.sessionId,command:n.command}}function f0(e){if(!e||typeof e!="object")return null;const n=e;if(typeof n.error!="string"||!n.error)return null;const i=Xg(n.recovery);return{error:n.error,code:typeof n.code=="string"&&n.code?n.code:null,requestId:typeof n.requestId=="string"&&n.requestId?n.requestId:null,...i?{recovery:i}:{}}}class ar extends Error{constructor(){super("unauthorized"),this.name="UnauthorizedError"}}class Er extends Error{constructor(i,a,u,g,d,o){super(i);vr(this,"status");vr(this,"serverError");vr(this,"code");vr(this,"requestId");vr(this,"recovery");this.name="ApiError",this.status=a,this.serverError=u??null,this.code=g??null,this.requestId=d??null,this.recovery=o??null}}class CR extends Er{constructor(){super("Sentence ASR returned no recognized speech",502,"Sentence ASR returned no recognized speech","speech_not_recognized"),this.name="SpeechNotRecognizedError"}}let Wj=Promise.resolve();function g4(e){const n=Wj.then(()=>{var i;return(i=navigator.locks)!=null&&i.request?navigator.locks.request("handmux-auth-cookie",e):e()});return Wj=n.catch(()=>{}),n}let Rg=!1,ER=null,SR=!1,jR=!0,DR=!0;const b4=()=>SR,uh=()=>jR,dh=()=>DR,_4=()=>Rg,qj=()=>Rg&&ER!==null;function Tc(e){if(Rg=e.authenticated,ER=e.currentDeviceId??null,SR=e.tokenEnabled===!0,jR=e.trustedDeviceEnabled!==!1,DR=e.trustedOriginEnabled!==!1,!Rg)try{gg(!1)}catch{}}function y4(){try{return sR()}catch{return null}}function fo(e={}){const n=y4();return{...n?{Authorization:`Bearer ${n}`}:{},...e}}async function so(e="/api/auth/status",n="GET",i){return g4(async()=>{const a=await mw(e,n,i);return a.sessionPending?mw("/api/auth/status","GET"):n==="POST"&&e==="/api/auth/pairing"?mw(e,"GET"):a})}class td extends Error{constructor(n,i){super(`auth -> ${n}`),this.status=n,this.code=i}}async function mw(e,n,i){const a=new AbortController,u=setTimeout(()=>a.abort(),8e3);try{const g=await fetch(e,{method:n,credentials:"same-origin",cache:"no-store",signal:a.signal,headers:{...fo(),...i?{"Content-Type":"application/json"}:{}},...i?{body:JSON.stringify({id:i})}:{}});if(!g.ok){let o=null;try{const c=await g.json(),f=typeof c.code=="string"?c.code:c.error;typeof f=="string"&&(o=f)}catch{}throw new td(g.status,o)}const d=await g.json();if(!d||d.mode!=="trusted-device"&&d.mode!=="token"||typeof d.authenticated!="boolean"||!Number.isFinite(d.serverTime))throw new Error("Invalid authentication response");return d}finally{clearTimeout(u)}}async function po(){return new ar}async function kR(){const e=await so("/api/auth/logout","POST");if(e.authenticated)throw new Error("Device is still authorized");Tc(e)}const x4={jpg:"image/jpeg",jpeg:"image/jpeg",jfif:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",svg:"image/svg+xml",ico:"image/x-icon",heic:"image/heic",heif:"image/heif",avif:"image/avif",tif:"image/tiff",tiff:"image/tiff",pdf:"application/pdf",txt:"text/plain",log:"text/plain",md:"text/markdown",markdown:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",html:"text/html",htm:"text/html",zip:"application/zip",mp4:"video/mp4",m4v:"video/mp4",mov:"video/quicktime",webm:"video/webm",mkv:"video/x-matroska",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",flv:"video/x-flv","3gp":"video/3gpp",ogv:"video/ogg",mpeg:"video/mpeg",mpg:"video/mpeg",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function Jg(e){const n=e||"",i=n.lastIndexOf(".");return i<0?"":x4[n.slice(i+1).toLowerCase()]||""}function w4(e){return Jg(e).startsWith("image/")}async function qt(e,n={}){const{timeoutMs:i,signal:a,...u}=n,g=fo(u.headers);u.body&&!Object.keys(g).some(f=>f.toLowerCase()==="content-type")&&(g["Content-Type"]="application/json");let d=null,o=null;const c=()=>d==null?void 0:d.abort();(i||a)&&(d=new AbortController,a!=null&&a.aborted?d.abort():a==null||a.addEventListener("abort",c,{once:!0}),i&&(o=setTimeout(()=>d==null?void 0:d.abort(),i)));try{let f=await fetch(e,{cache:"no-store",credentials:"same-origin",...u,headers:g,...d?{signal:d.signal}:{}});if(f.status===401&&g.Authorization&&!e.startsWith("/api/auth/")&&(await new Promise(v=>setTimeout(v,500)),f=await fetch(e,{cache:"no-store",credentials:"same-origin",...u,headers:g,...d?{signal:d.signal}:{}})),f.status===401)throw await po();if(!f.ok){let v=null;try{v=f0(await f.json())}catch{}throw new Er((v==null?void 0:v.error)||`${e} -> ${f.status}`,f.status,v==null?void 0:v.error,v==null?void 0:v.code,v==null?void 0:v.requestId,v==null?void 0:v.recovery)}return f.status===204?{unchanged:!0}:await f.json()}catch(f){throw d!=null&&d.signal.aborted&&!(a!=null&&a.aborted)?new Error(`${e} -> timeout`):f}finally{o!==null&&clearTimeout(o),a==null||a.removeEventListener("abort",c)}}const Gj=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null;function N4(){return{slices:new Map}}function C4(e,n){var u;const i=new Map(e.slices),a=Gj((u=Gj(n))==null?void 0:u.result);return typeof(a==null?void 0:a.index)=="number"&&typeof a.voice_text_str=="string"&&i.set(a.index,a.voice_text_str),{slices:i}}function E4(e){return[...e.slices.keys()].sort((n,i)=>n-i).map(n=>e.slices.get(n)).join("")}function TR(e){const n=window.atob(e),i=new Uint8Array(n.length);for(let a=0;a<n.length;a++)i[a]=n.charCodeAt(a);return i}const S4=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,j4={provider:"tencent",protocol:"tencent-asr-v2",parseSession(e){return e.provider==="tencent"&&e.protocol==="tencent-asr-v2"&&typeof e.url=="string"?{provider:"tencent",protocol:"tencent-asr-v2",url:e.url}:null},createDriver(){let e=N4();return{audio:TR,end:()=>JSON.stringify({type:"end"}),consume(n){e=C4(e,n);const i=S4(n),a=i==null?void 0:i.code;return{text:E4(e),final:(i==null?void 0:i.final)===1,...typeof a=="number"&&a!==0?{error:String((i==null?void 0:i.message)||`Tencent ASR ${a}`)}:{}}}}}},D4={language:"zh_cn",domain:"iat",accent:"mandarin",vad_eos:1e4,dwa:"wpgs",ptt:1,nunum:1},p0="audio/L16;rate=16000",mh=e=>e!==null&&typeof e=="object"?e:null;function k4(e,n){return{common:{app_id:e},business:{...D4},data:{status:0,format:p0,encoding:"raw",audio:n}}}function T4(e){return{data:{status:1,format:p0,encoding:"raw",audio:e}}}function R4(){return{data:{status:2,format:p0,encoding:"raw",audio:""}}}function A4(){return{sentences:new Map}}function U4(e,n){var d;const i=mh((d=mh(n))==null?void 0:d.data),a=mh(i==null?void 0:i.result);if(!a||typeof a.sn!="number"||!Array.isArray(a.ws))return e;const u=a.ws.map(o=>{var f;const c=(f=mh(o))==null?void 0:f.cw;return Array.isArray(c)?c.map(v=>{var _;const h=(_=mh(v))==null?void 0:_.w;return typeof h=="string"?h:""}).join(""):""}).join(""),g=new Map(e.sentences);if(a.pgs==="rpl"&&Array.isArray(a.rg)&&typeof a.rg[0]=="number"&&typeof a.rg[1]=="number")for(let o=a.rg[0];o<=a.rg[1];o++)g.delete(o);return g.set(a.sn,u),{sentences:g}}function M4(e){return[...e.sentences.keys()].sort((n,i)=>n-i).map(n=>e.sentences.get(n)).join("")}const Kj=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,L4={provider:"xfyun",protocol:"xfyun-iat-v2",parseSession(e){return e.provider==="xfyun"&&e.protocol==="xfyun-iat-v2"&&typeof e.url=="string"&&typeof e.appId=="string"?{provider:"xfyun",protocol:"xfyun-iat-v2",url:e.url,appId:e.appId}:null},createDriver(e){if(typeof e.appId!="string")throw new Error("XFYUN ASR session is missing appId");const n=e.appId;let i=!0,a=A4();return{audio(u){const g=i?k4(n,u):T4(u);return i=!1,JSON.stringify(g)},end:()=>JSON.stringify(R4()),consume(u){a=U4(a,u);const g=Kj(u),d=Kj(g==null?void 0:g.data),o=g==null?void 0:g.code;return{text:M4(a),final:(d==null?void 0:d.status)===2,...typeof o=="number"&&o!==0?{error:String((g==null?void 0:g.message)||`XFYUN ${o}`)}:{}}}}}},I4=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null;function V4(e){const n=new Map;for(const i of e){if(!i.protocol||n.has(i.protocol))throw new Error(`duplicate voice protocol: ${i.protocol}`);n.set(i.protocol,i)}return{adapters:[...e],parseSession(i){var u;const a=I4(i);return!a||typeof a.protocol!="string"?null:((u=n.get(a.protocol))==null?void 0:u.parseSession(a))??null},createDriver(i){const a=n.get(i.protocol);if(!a||i.provider!==a.provider)throw new Error(`unsupported ASR protocol: ${i.protocol}`);return a.createDriver(i)}}}const RR=V4([L4,j4]),O4=e=>RR.parseSession(e),P4=e=>RR.createDriver(e),B4=["protected","unprotected","degraded"],F4=["create","create-renamed","already-present","unsupported"],AR=["pending","running","succeeded","partial","failed","interrupted"],H4=["restored","already-present","failed"],z4=["plan","topology","agent","restore","reconcile"],ao=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,nd=(e,n)=>typeof n=="string"&&e.includes(n)?n:void 0,Ia=e=>typeof e=="number"&&Number.isFinite(e)?e:void 0,Ii=e=>typeof e=="string"?e:e===null?null:void 0,_g=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):[],In=(e,n)=>n===void 0?{}:{[e]:n};function $4(e){const n=ao(e);return n?{...In("status",nd(B4,n.status)),...In("lastSuccessfulCaptureAt",Ii(n.lastSuccessfulCaptureAt)),...In("errorCode",Ii(n.errorCode))}:null}function W4(e){const n=ao(e);return n?{...In("operationId",typeof n.operationId=="string"?n.operationId:void 0),...In("status",nd(AR,n.status)),...In("reused",typeof n.reused=="boolean"?n.reused:void 0)}:null}const hN=e=>{const n=ao(e);if(n)return{...In("sessions",Ia(n.sessions)),...In("windows",Ia(n.windows)),...In("panes",Ia(n.panes)),...In("agents",Ia(n.agents))}},UR=e=>{const n=ao(e);return n?{...In("logicalId",Ii(n.logicalId)),...In("sourceName",Ii(n.sourceName)),...In("targetName",Ii(n.targetName)),...In("action",n.action===null?null:nd(F4,n.action))}:null};function q4(e){const n=ao(e);if(!n)return null;const i=ao(n.planSummary),a=hN(n.summary),u=i?{...hN(i),...In("create",Ia(i.create)),...In("renamed",Ia(i.renamed)),...In("alreadyPresent",Ia(i.alreadyPresent)),...In("unsupported",Ia(i.unsupported))}:void 0,g=Ia(n.pendingCount)??(n.pendingCount===null?null:void 0);return{...In("checkpointId",Ii(n.checkpointId)),...In("capturedAt",Ii(n.capturedAt)),...In("changeReason",Ii(n.changeReason)),...In("serverNow",Ii(n.serverNow)),...In("expiresAt",Ii(n.expiresAt)),...In("promptEligible",typeof n.promptEligible=="boolean"?n.promptEligible:void 0),...In("resolved",typeof n.resolved=="boolean"?n.resolved:void 0),...In("pendingCount",g),...In("summary",a),...In("planSummary",u),...Array.isArray(n.sessions)?{sessions:n.sessions.flatMap(d=>{const o=UR(d);return o?[o]:[]})}:{},...Array.isArray(n.warningCodes)?{warningCodes:_g(n.warningCodes)}:{},...n.mapping!==void 0?{mapping:n.mapping}:{}}}function G4(e){const n=ao(e);if(!n)return null;const i=ao(n.progress),a=ao(n.request),u=Array.isArray(n.results)?n.results.flatMap(c=>{const f=ao(c),v=UR(c);return!f||!v?[]:[{...v,...In("status",f.status===null?null:nd(H4,f.status)),...In("stage",f.stage===null?null:nd(z4,f.stage)),...In("errorCode",Ii(f.errorCode)),...In("errorMessage",Ii(f.errorMessage)),warningCodes:_g(f.warningCodes)}]}):[],g=i?{...In("completed",Ia(i.completed)),...In("total",Ia(i.total))}:void 0,d=typeof(a==null?void 0:a.checkpointId)=="string"?a.checkpointId:void 0,o=a&&d?{checkpointId:d,...Array.isArray(a.sessions)?{sessions:_g(a.sessions)}:{},...typeof a.historical=="boolean"?{historical:a.historical}:{}}:void 0;return{...typeof n.id=="string"?{id:n.id}:{},...In("status",n.status===null?null:nd(AR,n.status)),...In("request",o),...In("createdAt",Ii(n.createdAt)),...In("updatedAt",Ii(n.updatedAt)),...In("startedAt",Ii(n.startedAt)),...In("completedAt",Ii(n.completedAt)),...In("progress",g),...In("summary",hN(n.summary)),...Array.isArray(n.results)?{results:u}:{},...In("errorCode",Ii(n.errorCode)),...In("errorMessage",Ii(n.errorMessage)),...Array.isArray(n.warningCodes)?{warningCodes:_g(n.warningCodes)}:{},...n.mapping!==void 0?{mapping:n.mapping}:{}}}function K4(e,{ignored:n=!1,autoShown:i=!1,liveSessionCount:a=0}={}){return!e||!e.promptEligible||n===!0||e.resolved||(e.pendingCount??0)<1?"none":a===0&&i!==!0?"auto-dialog":"card"}function MR(e){return(e==null?void 0:e.changeReason)==="boot-changed"?"workspace.bootDetected":"workspace.tmuxDetected"}function ai(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}const fN=/^[a-z][a-z0-9-]{0,63}$/;function Y4(e){const n=ai(e),i=ai(n==null?void 0:n.capabilities),a=(n==null?void 0:n.capabilityMetadata)===void 0?void 0:ai(n.capabilityMetadata),u=(a==null?void 0:a.conversation)===void 0?void 0:ai(a.conversation);if(!n||typeof n.id!="string"||!fN.test(n.id)||typeof n.label!="string"||!n.label.trim()||n.label.length>128||n.iconId!==void 0&&(typeof n.iconId!="string"||!fN.test(n.iconId))||!i||typeof i.inbox!="boolean"||typeof i.conversation!="boolean"||i.conversationActivation!==void 0&&typeof i.conversationActivation!="boolean"||i.conversationGoal!==void 0&&typeof i.conversationGoal!="boolean"||i.conversationPlan!==void 0&&typeof i.conversationPlan!="boolean"||i.conversationContext!==void 0&&typeof i.conversationContext!="boolean"||i.conversationPermission!==void 0&&typeof i.conversationPermission!="boolean"||i.conversationCommands!==void 0&&typeof i.conversationCommands!="boolean"||typeof i.interaction!="boolean"||i.sessionControl!==void 0&&typeof i.sessionControl!="boolean"||typeof i.subscriptionUsage!="boolean"||n.capabilityMetadata!==void 0&&!a||(a==null?void 0:a.conversation)!==void 0&&(!u||typeof u.experimental!="boolean"))return null;const g=u==null?void 0:u.experimental;return{id:n.id,label:n.label,...n.iconId===void 0?{}:{iconId:n.iconId},capabilities:{inbox:i.inbox,conversation:i.conversation,...i.conversationActivation===void 0?{}:{conversationActivation:i.conversationActivation},...i.conversationGoal===void 0?{}:{conversationGoal:i.conversationGoal},...i.conversationPlan===void 0?{}:{conversationPlan:i.conversationPlan},...i.conversationContext===void 0?{}:{conversationContext:i.conversationContext},...i.conversationPermission===void 0?{}:{conversationPermission:i.conversationPermission},...i.conversationCommands===void 0?{}:{conversationCommands:i.conversationCommands},interaction:i.interaction,...i.sessionControl===void 0?{}:{sessionControl:i.sessionControl},subscriptionUsage:i.subscriptionUsage},...g===void 0?{}:{capabilityMetadata:{conversation:{experimental:g}}}}}function X4(e){const n=ai(e);return!n||typeof n.agentId!="string"||!fN.test(n.agentId)||typeof n.paneId!="string"||!n.paneId||n.paneId.length>256||typeof n.runId!="string"||!n.runId||n.runId.length>256||n.sessionId!==void 0&&(typeof n.sessionId!="string"||!n.sessionId||n.sessionId.length>1024)?null:{agentId:n.agentId,paneId:n.paneId,runId:n.runId,...n.sessionId===void 0?{}:{sessionId:n.sessionId}}}const J4=new Set(["starting","ready","degraded","unavailable"]);function Q4(e,n){const i=ai(e);return!i||typeof i.adapterId!="string"||!n.has(i.adapterId)||typeof i.availability!="string"||!J4.has(i.availability)||i.capability!==void 0&&(typeof i.capability!="string"||!i.capability||i.capability.length>64)||i.message!==void 0&&(typeof i.message!="string"||i.message.length>1024)||i.lastSuccessAt!==void 0&&(typeof i.lastSuccessAt!="number"||!Number.isFinite(i.lastSuccessAt))?null:{adapterId:i.adapterId,availability:i.availability,...i.capability===void 0?{}:{capability:i.capability},...i.message===void 0?{}:{message:i.message},...i.lastSuccessAt===void 0?{}:{lastSuccessAt:i.lastSuccessAt}}}async function Kv(){const e=ai(await qt("/api/agents/capabilities",{timeoutMs:4e3}));if(!e||!Array.isArray(e.adapters))return{descriptors:[],runs:[],health:[]};const n=e.adapters.map(Y4).filter(o=>o!==null),i=new Map;for(const o of n)i.set(o.id,(i.get(o.id)??0)+1);const a=n.filter(o=>i.get(o.id)===1),u=new Set(a.map(o=>o.id)),g=Array.isArray(e.runs)?e.runs.map(X4).filter(o=>o!==null&&u.has(o.agentId)):[],d=new Map;for(const o of g)d.set(o.paneId,(d.get(o.paneId)??0)+1);return{descriptors:a,runs:g.filter(o=>d.get(o.paneId)===1),health:Array.isArray(e.health)?e.health.map(o=>Q4(o,u)).filter(o=>o!==null):[]}}async function Z4(e){if(!e.length||e.length>256||e.some(u=>typeof u!="string"||!u||u.length>256))throw new TypeError("Invalid terminal notification ids");const n=ai(await qt("/api/agents/inbox/notifications/read",{method:"POST",body:JSON.stringify({notificationIds:[...e]}),timeoutMs:4e3})),i=Array.isArray(n==null?void 0:n.markedIds)?n.markedIds.filter(u=>typeof u=="string"&&u.length>0):[],a=Go(n==null?void 0:n.readAt);return{markedIds:i,...a===void 0?{}:{readAt:a}}}const Go=e=>typeof e=="number"&&Number.isFinite(e)?e:void 0;function e6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);return typeof(i==null?void 0:i.id)=="string"&&typeof i.name=="string"?[{id:i.id,name:i.name}]:[]}):[]}function t6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.id!="string")return[];const a=Go(i.width);return[{id:i.id,name:typeof i.name=="string"?i.name:i.id,panes:Go(i.panes)??0,...typeof i.active=="boolean"?{active:i.active}:{},...a!==void 0?{width:a}:{},...typeof i.activePaneId=="string"?{activePaneId:i.activePaneId}:{}}]}):[]}function n6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.id!="string")return[];const a=Go(i.left),u=Go(i.top),g=Go(i.width),d=Go(i.height);return[{id:i.id,...typeof i.active=="boolean"?{active:i.active}:{},...typeof i.command=="string"||i.command===null?{command:i.command}:{},...typeof i.agent=="string"||i.agent===null?{agent:i.agent}:{},...a!==void 0?{left:a}:{},...u!==void 0?{top:u}:{},...g!==void 0?{width:g}:{},...d!==void 0?{height:d}:{}}]}):[]}const Ul=async()=>e6(await qt("/api/sessions")),Yj=(e=!1,n)=>qt(`/api/agents/usage${e?`?refresh=true${n?`&target=${encodeURIComponent(n)}`:""}`:""}`,e?{timeoutMs:3e4}:{}),Xj=()=>qt("/api/api-accounts"),r6=(e,n)=>qt("/api/api-accounts",{method:"POST",body:JSON.stringify(e),timeoutMs:15e3,...n?{signal:n}:{}}),i6=(e,n,i)=>qt(`/api/api-accounts/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(n),timeoutMs:15e3,...i?{signal:i}:{}}),s6=e=>qt(`/api/api-accounts/${encodeURIComponent(e)}`,{method:"DELETE"}),a6=e=>qt(`/api/api-accounts/${encodeURIComponent(e)}/query`,{method:"POST",timeoutMs:15e3}),Tl=async e=>t6(await qt(`/api/windows?session=${encodeURIComponent(e)}`)),qs=async e=>n6(await qt(`/api/panes?window=${encodeURIComponent(e)}`,{timeoutMs:8e3})),o6=(e,n=1500,i)=>qt(`/api/history?pane=${encodeURIComponent(e)}&lines=${n}${i?`&since=${i}`:""}`,{timeoutMs:8e3}),Jj=(e,n,i=!0)=>qt("/api/send",{method:"POST",body:JSON.stringify({pane:e,text:n,enter:i})}),v0=(e,n)=>qt("/api/keys",{method:"POST",body:JSON.stringify({pane:e,keys:n})}),l6=(e,n)=>qt("/api/input",{method:"POST",body:JSON.stringify({pane:e,hex:n})}),c6=(e,n,i=1)=>qt("/api/scroll",{method:"POST",body:JSON.stringify({pane:e,dir:n,lines:i})}),u6=(e,n,i)=>qt("/api/resize",{method:"POST",body:JSON.stringify({window:e,cols:n,rows:i})}),d6=(e,n)=>qt("/api/resize",{method:"POST",body:JSON.stringify({pane:e,cols:n})}),m6=e=>qt(`/api/layout?window=${encodeURIComponent(e)}`),h6=(e,n)=>qt("/api/layout",{method:"POST",body:JSON.stringify({window:e,layout:n})}),f6=(e,n)=>qt("/api/resize",{method:"POST",body:JSON.stringify({window:e,auto:!0,layout:n})}),p6=(e,n,i)=>qt("/api/sessions",{method:"POST",body:JSON.stringify({name:e,cwd:n,cmd:i})}),LR=e=>{const n=ai(e);return n?{...typeof n.id=="string"?{id:n.id}:{},...typeof n.session=="string"?{session:n.session}:{},...typeof n.name=="string"?{name:n.name}:{},...typeof n.window=="string"?{window:n.window}:{},...typeof n.pane=="string"?{pane:n.pane}:{}}:{}},v6=async(e,n,i,a,u)=>LR(await qt("/api/windows",{method:"POST",body:JSON.stringify({session:e,pane:n,name:i,cwd:a,cmd:u})})),g6=(e,n)=>qt("/api/sessions",{method:"PATCH",body:JSON.stringify({id:e,name:n})}),b6=(e,n)=>qt("/api/windows",{method:"PATCH",body:JSON.stringify({id:e,name:n})}),_6=e=>qt(`/api/windows?window=${encodeURIComponent(e)}`,{method:"DELETE"}),y6=(e,n)=>qt("/api/windows/swap",{method:"POST",body:JSON.stringify({a:e,b:n})}),Qj=(e,n)=>qt("/api/panes/split",{method:"POST",body:JSON.stringify({pane:e,dir:n})}),x6=e=>qt(`/api/panes?pane=${encodeURIComponent(e)}`,{method:"DELETE"}),w6=(e,n)=>qt("/api/dir",{method:"POST",body:JSON.stringify({dir:e,name:n})}),Zj=async(e,n=null)=>{const i=ai(await qt(`/api/file?path=${encodeURIComponent(e)}${n!=null?`&mtime=${encodeURIComponent(n)}`:""}`,{timeoutMs:8e3}));if((i==null?void 0:i.notModified)===!0)return{notModified:!0};if(!i||typeof i.type!="string"||typeof i.name!="string")throw new Error("file response is invalid");return{type:i.type,name:i.name,content:i.content,...i.mtimeMs===null?{mtimeMs:null}:typeof i.mtimeMs=="number"&&Number.isFinite(i.mtimeMs)?{mtimeMs:i.mtimeMs}:{}}},g0=e=>qt(`/api/dir${e?`?path=${encodeURIComponent(e)}`:""}`,{timeoutMs:8e3}),Uc=e=>qt(`/api/pane-cwd?pane=${encodeURIComponent(e)}`,{timeoutMs:8e3});async function N6(e="medium"){const n=O4(await qt(`/api/asr/session?fillerFilter=${encodeURIComponent(e)}`,{timeoutMs:8e3}));if(n)return n;throw new Error("ASR session returned an unsupported provider")}async function C6(e,n="medium"){const i=new ArrayBuffer(e.byteLength);new Uint8Array(i).set(e);const a=ai(await qt(`/api/asr/sentence?fillerFilter=${encodeURIComponent(n)}`,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:i,timeoutMs:7e4}));if(!a||typeof a.text!="string")throw new Error("Sentence ASR returned an invalid response");if(a.text.trim()==="")throw new CR;return a.text}const E6=()=>qt("/api/config",{timeoutMs:8e3}),S6=async()=>{const e=ai(await qt("/api/version",{timeoutMs:8e3})),n=Array.isArray(e==null?void 0:e.whatsNew)?e.whatsNew.flatMap(i=>{const a=ai(i);return typeof(a==null?void 0:a.version)=="string"?[{version:a.version,...typeof a.zh=="string"?{zh:a.zh}:{},...typeof a.en=="string"?{en:a.en}:{}}]:[]}):void 0;return e?{...typeof e.current=="string"||e.current===null?{current:e.current}:{},...typeof e.latest=="string"||e.latest===null?{latest:e.latest}:{},...typeof e.updateAvailable=="boolean"?{updateAvailable:e.updateAvailable}:{},...n?{whatsNew:n}:{}}:{}},eD=async()=>$4(await qt("/api/workspace/status",{timeoutMs:8e3}))??{},tD=async(e="latest")=>q4(await qt(`/api/workspace/restore-plan?checkpoint=${encodeURIComponent(e)}`,{timeoutMs:8e3})),j6=async(e={checkpointId:"latest"})=>{const n=await qt("/api/workspace/restore",{method:"POST",body:JSON.stringify(e),timeoutMs:8e3});return W4(n)??{}},D6=async e=>G4(await qt(`/api/workspace/restore/${encodeURIComponent(e)}`,{timeoutMs:8e3})),k6=()=>qt("/api/hooks/install",{method:"POST",timeoutMs:15e3}),T6=async(e=[])=>{const n=ai(await qt(`/api/states?sessions=${encodeURIComponent(e.join(","))}`,{timeoutMs:4e3})),i={};for(const[a,u]of Object.entries(n||{})){const g=ai(u);g&&(i[a]={...typeof g.kind=="string"||g.kind===null?{kind:g.kind}:{},...typeof g.session=="string"||g.session===null?{session:g.session}:{},...typeof g.window=="string"||g.window===null?{window:g.window}:{},...typeof g.windowName=="string"||g.windowName===null?{windowName:g.windowName}:{},...typeof g.msg=="string"||g.msg===null?{msg:g.msg}:{},...typeof g.ts=="number"&&Number.isFinite(g.ts)?{ts:g.ts}:{},...typeof g.agent=="string"||g.agent===null?{agent:g.agent}:{},...typeof g.terminalUnread=="boolean"?{terminalUnread:g.terminalUnread}:{},...typeof g.terminalNotificationId=="string"&&g.terminalNotificationId?{terminalNotificationId:g.terminalNotificationId}:{}})}return i},pd=(e,n={})=>qt(e,{timeoutMs:15e3,...n,headers:{...n.headers||{},"X-Handmux-Browser-Device":gP()??""}}),R6=(e,n,i="mobile")=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}`,{method:"PUT",body:JSON.stringify({url:n,siteVersion:i})}),A6=(e,n,i="mobile")=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}/navigate`,{method:"POST",body:JSON.stringify({url:n,siteVersion:i})}),nD=e=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}`,{method:"DELETE"}),rD=()=>pd("/api/browser-proxy/status"),iD=e=>pd("/api/browser-proxy/profile",{method:"PUT",body:JSON.stringify(e)}),U6=(e=null)=>pd("/api/browser-proxy/profile/clear",{method:"POST",body:JSON.stringify({origin:e})}),sD=async()=>{const e=await qt("/api/orphans",{timeoutMs:8e3});return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.pid!="number"||!Number.isFinite(i.pid)||typeof i.cwd!="string")return[];const a=Go(i.startedAt),u=Go(i.lastActivity);return[{pid:i.pid,cwd:i.cwd,...typeof i.cwdLabel=="string"?{cwdLabel:i.cwdLabel}:{},...typeof i.sessionId=="string"||i.sessionId===null?{sessionId:i.sessionId}:{},...typeof i.state=="string"?{state:i.state}:{},...typeof i.snippet=="string"?{snippet:i.snippet}:{},...typeof i.agentLabel=="string"?{agentLabel:i.agentLabel}:{},...typeof i.suggestedName=="string"?{suggestedName:i.suggestedName}:{},...a!==void 0?{startedAt:a}:{},...u!==void 0?{lastActivity:u}:{}}]}):[]},M6=async e=>LR(await qt("/api/orphans/takeover",{method:"POST",body:JSON.stringify(e),timeoutMs:15e3})),L6=async e=>{const n=ai(await qt(`/api/git/worktree?dir=${encodeURIComponent(e)}`,{timeoutMs:8e3})),i=ai(n==null?void 0:n.worktree);return i&&typeof i.path=="string"&&i.path?{path:i.path}:null},aD=e=>qt(`/api/git/repos?dir=${encodeURIComponent(e)}`,{timeoutMs:8e3}),IR=e=>qt(`/api/git/status?repo=${encodeURIComponent(e)}`,{timeoutMs:8e3}),I6=(e,{limit:n=50,ref:i}={})=>{let a=`/api/git/log?repo=${encodeURIComponent(e)}&limit=${n}`;return i&&(a+=`&ref=${encodeURIComponent(i)}`),qt(a,{timeoutMs:8e3})},V6=e=>qt(`/api/git/branches?repo=${encodeURIComponent(e)}`,{timeoutMs:8e3}),O6=(e,{path:n,commit:i,staged:a}={})=>{let u=`/api/git/diff?repo=${encodeURIComponent(e)}&path=${encodeURIComponent(n??"")}`;return i&&(u+=`&commit=${encodeURIComponent(i)}`),a&&(u+="&staged=1"),qt(u,{timeoutMs:8e3})},P6=(e,n)=>qt(`/api/git/commit?repo=${encodeURIComponent(e)}&hash=${encodeURIComponent(n)}`,{timeoutMs:8e3});function B6(e,n){return new Promise((i,a)=>{const u=new XMLHttpRequest;u.open("GET",`/api/download?path=${encodeURIComponent(e)}`);for(const[g,d]of Object.entries(fo()))u.setRequestHeader(g,d);u.responseType="blob",u.onprogress=g=>{n&&g.lengthComputable&&n(g.loaded/g.total)},u.onerror=()=>a(new Error("download failed")),u.onload=()=>{if(u.status===401){po().then(a);return}if(u.status<200||u.status>=300)return a(new Error(`download -> ${u.status}`));const g=e.split("/").pop()||"download";let d=u.response;const o=Jg(g);o&&d&&d.type!==o&&(d=d.slice(0,d.size,o));const c=URL.createObjectURL(d),f=document.createElement("a");f.href=c,f.download=g,document.body.appendChild(f),f.click(),f.remove(),setTimeout(()=>URL.revokeObjectURL(c),1e3),i()},u.send()})}function pN(e,n=null){return new Promise((i,a)=>{const u=new XMLHttpRequest,g=n!=null?`&mtime=${encodeURIComponent(n)}`:"";u.open("GET",`/api/download?path=${encodeURIComponent(e)}${g}`);for(const[d,o]of Object.entries(fo()))u.setRequestHeader(d,o);u.responseType="blob",u.onerror=()=>a(new Error(w("api.loadFailed"))),u.onload=()=>{if(u.status===304)return i({notModified:!0});if(u.status===401){po().then(a);return}if(u.status<200||u.status>=300)return a(new Error(`image -> ${u.status}`));let d=u.response;const o=Jg(e.split("/").pop()||"");o&&d&&d.type!==o&&(d=d.slice(0,d.size,o));const c=Number(u.getResponseHeader("X-Mtime"));i({url:URL.createObjectURL(d),mtimeMs:Number.isFinite(c)?c:null})},u.send()})}const F6=(e,{dir:n}={})=>qt("/api/previews",{method:"POST",body:JSON.stringify({name:e,dir:n})}),hw=e=>qt(`/api/previews/${encodeURIComponent(e)}`,{method:"DELETE"});class Ag extends Error{constructor(){super("upload aborted"),this.name="UploadAbort"}}function VR(e,n,i,a=!1,{signal:u}={}){return new Promise((g,d)=>{if(u!=null&&u.aborted)return d(new Ag);const o=new FormData;o.append("dir",e),a&&o.append("stash","1"),o.append("file",n,n.name);const c=new XMLHttpRequest;c.open("POST","/api/upload");for(const[h,_]of Object.entries(fo()))c.setRequestHeader(h,_);c.upload.onprogress=h=>{i&&h.lengthComputable&&i(h.loaded/h.total,"sending")},c.upload.onload=()=>{i==null||i(1,"processing")};const f=()=>c.abort();u&&u.addEventListener("abort",f,{once:!0});const v=()=>{u&&u.removeEventListener("abort",f)};c.onabort=()=>{v(),d(new Ag)},c.onerror=()=>{v(),d(new Error(w("api.uploadFailed")))},c.onload=()=>{if(v(),c.status===401){po().then(d);return}if(c.status>=200&&c.status<300)try{return g(JSON.parse(c.responseText))}catch{return g({})}const _={400:w("api.uploadBadDir"),409:w("api.uploadDuplicate"),413:w("api.uploadTooLarge"),415:w("api.uploadBadType")}[c.status]||w("api.uploadFailed");d(new Error(_))},c.send(o)})}const H6=e=>{if(e===null||typeof e!="object"||Array.isArray(e))throw new Error("split pane returned an invalid response");const n=e.id;if(typeof n!="string"||!n)throw new Error("split pane returned an invalid response");return n};async function oD({paneId:e,dir:n,windowId:i,api:a,getPanes:u}){const g=H6(await a.splitPane(e,n));return{panes:await u(i),selectPaneId:g}}async function z6({paneId:e,windowId:n,viewedPaneId:i,api:a,getPanes:u,pickId:g}){await a.closePane(e);const d=await u(n),o=e===i&&d.length?g(d,null):null;return{panes:d,selectPaneId:o}}const $6=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Claude"><title>Claude</title><path fill="#d97757" d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
204
+ You might need to use a local HTTP server (instead of file://): https://reactjs.org/link/react-devtools-faq`:""),"font-weight:bold")}Ks.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=cw,Ks.createPortal=IO,Ks.createRoot=OO,Ks.findDOMNode=RO,Ks.flushSync=BO,Ks.hydrate=AO,Ks.hydrateRoot=PO,Ks.render=UO,Ks.unmountComponentAtNode=LO,Ks.unstable_batchedUpdates=Px,Ks.unstable_renderSubtreeIntoContainer=VO,Ks.version=nw,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error)})();zT.exports=Ks;var JN=zT.exports,qT,jj=JN;{var Dj=jj.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;qT=function(e,n){Dj.usingClientEntryPoint=!0;try{return jj.createRoot(e,n)}finally{Dj.usingClientEntryPoint=!1}}}const GT={"auth.welcome":"Connect to your terminal workspace","auth.login":"Sign in","auth.connecting":"Connecting","auth.switchLink":"How do I manage login methods?","auth.switchTitle":"Manage login methods","auth.switchWarning":"Sign in with the Token, then authorize this device.","auth.switchSetup":"To change Public URL, run handmux setup on the server. In Direct mode, open Connection → Direct → Public URL and enter your own reverse-tunnel address.","auth.switchRestart":"For first enrollment or recovery after losing every device, run the command below on the handmux computer.","auth.switchAfter":"The CLI switches device protection and address restrictions; manage devices and addresses here.","auth.copySetup":"Copy view command","auth.copyRestart":"Copy restore command","devices.title":"Authentication & security","devices.protectionEnabled":"Protection on","devices.protectionPartial":"Protection partly on","devices.protectionDisabled":"Protection off","devices.insecureTitle":"Security protections are not fully enabled","devices.insecureHint":"Device protection or trusted-address restrictions are off.","devices.openSecurity":"Open Authentication & security","devices.listTitle":"Authorized devices","devices.historyTitle":"Device history","devices.historyLink":"History ({n})","devices.backToActive":"Back to authorized devices","devices.trusted":"Device protection","devices.deviceProtectionSection":"Device protection","devices.deviceProtectionStatus":"Protection status","devices.originProtectionStatus":"Restriction status","devices.policyEnabled":"On","devices.policyDisabled":"Off","devices.deviceProtectionDisabledHint":"Only the Token is required now; enable this to require a trusted device.","devices.enableProtection":"Enable device protection","devices.enableOriginProtection":"Enable address restrictions","devices.enableConfirmTitle":"Confirm protection","devices.enableDeviceConfirm":"This browser will be registered as a trusted device; other devices must be authorized by a trusted device or the computer CLI. Turning it off is CLI-only: handmux auth device off.","devices.enableOriginConfirm":"Only registered access addresses will be allowed. Turning it off is CLI-only: handmux auth address off.","devices.enableConfirm":"Enable","devices.originProtectionDisabledHint":"Access addresses are not restricted now.","devices.deviceProtectionInfo":"Enable device protection here; turning it off is CLI-only with handmux auth device off. This page only manages devices.","devices.deviceProtectionEnabledHint":"Protects access from unauthorized devices; turning it off is CLI-only: handmux auth device off.","devices.originProtectionInfo":"Toggle trusted-address protection with handmux auth address on/off. This page only manages addresses.","devices.originProtectionEnabledHint":"Protects access from unregistered addresses; turning it off is CLI-only: handmux auth address off.","devices.token":"Token","devices.addSelf":"Add this browser as a trusted device","devices.addSelfTitle":"Add this browser","devices.addSelfAddress":"Address to register: {origin}","devices.cookieRequired":"The browser did not save the trusted-device credential. Allow cookies and retry.","devices.trustedOrigin":"Trusted access address","devices.accessSection":"Trusted address protection","devices.publicUrlLabel":"Primary domain","devices.publicUrlInfo":"Set in setup → Connection → your connection type → Public URL. This page only shows it.","devices.previewDomainLabel":"Preview domain","devices.previewDomainInfo":"Set in setup → Web preview → Web preview proxy domain. handmux automatically allows its dynamic subdomains.","devices.originConfigured":"Configured in setup; cannot be edited here","devices.originBuiltIn":"Allowed automatically by handmux","devices.originUnset":"Not set","devices.originActive":"In effect","devices.originPending":"Not configured; register external addresses with the CLI or authorize a device from them","devices.originHint":"Public URL comes from setup and is read-only here. Leave it blank when you do not use a fixed public entry; local/LAN access remains available, while external hosts must be listed below or use the dynamic preview domain.","devices.originCommands":"Trusted access address commands","devices.originSetupCommandLabel":"Configure","devices.extraOriginsTitle":"Trusted domain","devices.trustedOriginLabel":"Trusted domain {n}","devices.extraOriginsHint":"Addresses are registered by device authorization or managed with the CLI. Wildcards such as https://*.example.com are supported.","devices.extraOriginInput":"Additional trusted domain","devices.extraOriginAdd":"Add domain","devices.removeOriginTitle":"Delete trusted domain","devices.removeOriginImpact":"These active devices will no longer be able to use this address:","devices.removeOriginCurrentImpact":"This includes the current device. It will lose access after deletion and must be authorized again.","devices.removeOriginNoImpact":"No active device is currently using this address. Delete it?","devices.removeOriginConfirm":"Delete","devices.invalidOrigin":"Enter a complete http(s) address such as https://*.example.com. The wildcard must be the left-most subdomain.","devices.originLimit":"You have reached the limit for additional trusted domains. Remove one before adding another.","devices.originMismatch":"This address is not an allowed entry point. Open handmux through the primary URL, dynamic preview domain, or a registered address; to register one, run handmux auth address add <origin>.","devices.addSelfOrigin":"This will add {origin} to the trusted entry points after authorization.","devices.cliOnly":"Change the trusted access address with the handmux CLI on the server.","devices.current":"This device","devices.add":"Add a device","devices.authorizeOther":"Authorize another device","devices.history":"Device history ({n})","devices.activeTab":"Active","devices.historyTab":"History","devices.activeStatus":"Can sign in","devices.detailInfo":"Device information","devices.deviceInfo":"Device","devices.status":"Status","devices.detailActions":"Device actions","devices.noActive":"No active devices.","devices.activeDevices":"‹ Active devices","devices.noHistory":"No past devices.","devices.name":"Device name","devices.expire":"Authorization duration","devices.keep":"Keep current expiry","devices.custom":"Custom","devices.never":"No expiry","devices.customDuration":"Positive number + m / h / d, or never","devices.keepHint":"Keeping the current expiry does not extend authorization.","devices.expireFromSave":"The selected duration starts when these changes are saved.","devices.id":"Device ID","devices.copyId":"Copy ID","devices.browser":"Browser","devices.added":"Added","devices.lastAccess":"Last access","devices.expiresAt":"Expires","devices.revoked":"Unbound","devices.expired":"Expired","devices.daysRemaining":"{n} days left","devices.hoursRemaining":"{n} hours left","devices.minutesRemaining":"{n} minutes left","devices.logout":"Sign out this device","devices.revoke":"Remove device","devices.revokeDescription":"“{name}” will lose access immediately and must pair again. Running terminal tasks will continue.","devices.conflict":"This device changed elsewhere. Refresh its details and reapply your changes.","devices.refreshDetails":"Reload latest details","devices.inactive":"This device has expired or been removed. Pair it again to restore access.","devices.sessionInvalid":"This browser is no longer authorized. Reload handmux and pair again.","devices.invalidName":"Use a device name with 1–80 characters and no control characters.","devices.nameTaken":"That device name is already in use. Choose another name.","devices.saved":"Saved.","devices.invalidExpire":"Use a positive duration such as 1h, 7d, or never.","devices.expiryCliOnly":"Change the authorization duration with the handmux CLI on the server.","devices.invalidCode":"Enter the new browser’s current 6-digit code. Expired or used codes cannot be reused.","devices.pairingGone":"This pairing was canceled or expired. Ask the new browser for another code.","devices.requestError":"Unable to confirm the operation. Check the connection and retry; no successful change has been confirmed.","devices.code":"One-time code","devices.codeHint":"Enter the 6-digit code shown on the new device. Verification starts automatically.","devices.verifyingCode":"Verifying…","devices.configureTitle":"Set up new device","devices.approvalOrigin":"Access address","devices.claim":"Confirm pairing","devices.complete":"Complete adding","devices.newCode":"Enter a new code","auth.methodLabel":"Authorization method","auth.webMethod":"Trusted device","auth.webInstructions":"On a phone or computer already signed in to this same handmux instance, open:","auth.webPath":"Settings → Authentication & security → Add a device with a one-time code","auth.webNext":"Enter the code above and confirm pairing. Set the new device’s name and expiry, then complete adding. This page will sign in automatically.","auth.webFallback":"No trusted device available? Switch to Computer CLI.","auth.title":"Authorize this browser","auth.waiting":"Waiting for authorization","auth.deviceRequired":"Device authorization required","auth.preparingCode":"Preparing a verification code…","auth.deviceAuthorizationHint":"After your Token is checked, authorize this browser once.","auth.verificationCode":"Authorization code","auth.authorizeWithDevice":"On an authorized device, open Authentication & security and enter this code.","auth.authorizeWithCli":"On the computer running handmux, run","auth.cliAfterCode":"then enter this code when prompted.","auth.chooseOneMethod":"Choose one way to authorize this browser","auth.cliMethodTitle":"Computer CLI authorization","auth.deviceMethodTitle":"Authorize from another device","auth.paired":"Paired successfully","auth.pending":"Confirmed. Finishing authorization…","auth.finishCli":"Finish device setup in the terminal.","auth.finishWeb":"Finish device setup on the trusted device.","auth.setupRemaining":"{seconds}s left to complete settings","auth.codeRemaining":"{seconds}s remaining","auth.codeExpired":"Expired. Generate a new code.","auth.expired":"The code expired. Generate a new one.","auth.canceled":"Authorization was canceled. Generate a new code.","auth.request":"Request device authorization","auth.requestNewCode":"Generate new code","auth.refreshCode":"Refresh","auth.cancelPairing":"Cancel pairing","auth.copyCode":"Copy code","auth.copyCommand":"Copy command","auth.copied":"Copied","auth.manualCopy":"Text selected. Long-press or use Ctrl/Cmd+C to copy.","auth.cliMethod":"Computer CLI","auth.cliInstructions":"On the computer running this handmux instance, run the command below as the same OS user, using a direct terminal or independent SSH session. It opens the interactive authorization flow.","auth.cliNext":"Enter the 6-digit code shown on this page, then set the device name and expiry. This page will log in automatically after saving. Automation should use the --code, --name, and --expire flags.","auth.browserScope":"Authorization is saved for this browser and access address. Changing the address requires pairing again.","auth.antiPhishing":"Only authorize a browser you are adding yourself. Never enter a code sent by someone else.","auth.httpWarning":"For better protection of sensitive access, use HTTPS or a trusted encrypted network whenever possible.","auth.tokenWarning":"The Token is always required. Device authorization is also required when device protection is on.","auth.dualRequirement":"The Token is always required. Device authorization is also required when device protection is on.","auth.tokenRequired":"Enter the current Token before requesting device authorization.","auth.tokenInvalid":"The Token is not correct. Enter it again to continue.","auth.connectionError":"Unable to check authorization. Check your network and whether handmux is running, then retry. Your authorization has not been canceled.","auth.originRejected":"This address is not a trusted entry point.","auth.originRejectedTitle":"Untrusted address","auth.originRejectedAddress":"Current address {origin} is not a trusted entry point","auth.originRejectedOpenLabel":"Open a trusted entry point","auth.originRejectedOpenHint":"Use the primary URL, dynamic domain, or an authorized access domain to open this page","auth.originRejectedAuthorizeLabel":"Authorize again","auth.originRejectedAuthorizeHint":"Use another trusted device or the handmux CLI to authorize this access address","auth.originRejectedAuthorizeButton":"Request access","auth.originRejectedRetry":"Check again","auth.retry":"Retry","auth.rateLimit":"Too many authorization attempts. Wait a minute before requesting another code.","auth.logoutTitle":"Unbind and sign out","auth.logoutDescription":"This browser will lose access immediately and must pair again to log in. Running terminal tasks will continue.","auth.logoutError":"Unbinding could not be confirmed. Check the connection and retry; this device may still be authorized.","terminal.disconnected":"Connection lost. Reconnecting…","terminal.paneMissing":"This pane has closed. Switch to another pane.","terminal.transport_live":"Live","terminal.transport_snapshot":"Snapshot","terminal.transport_detail_title":"Terminal delivery","terminal.transport_detail_configured":"Configured","terminal.transport_detail_current":"Current","terminal.transport_detail_connection":"Connection","terminal.transport_detail_manual":"Snapshot pulling was selected manually and will not switch automatically.","terminal.transport_detail_live":"The terminal is receiving live pushes normally.","terminal.transport_detail_fallback":"Live pushing became unstable, so Handmux fell back to snapshot pulling.","terminal.transport_detail_unavailable":"The live channel could not connect. Check whether your proxy supports WebSocket upgrades.","terminal.transport_detail_waiting":"Waiting for the connection to become stable before retrying live pushing.","terminal.transport_detail_retry":"About {seconds}s until Handmux attempts to restore live pushing.","terminal.connection_connecting":"Checking","terminal.connection_good":"Good","terminal.connection_degraded":"Fair","terminal.connection_poor":"Poor","common.save":"Save","common.cancel":"Cancel","common.confirm":"Confirm","common.ok":"OK","common.close":"Close","common.delete":"Delete","common.undo":"Undo","common.copy":"Copy","common.rename":"Rename","common.create":"Create","common.back":"Back","common.open":"Open","common.loading":"Loading…","common.done":"Done","common.retry":"Try Again","common.continue":"Continue","conversationCopy.line":"Line","conversationCopy.paragraph":"Paragraph","app.browser":"Web preview","browser.openTabs":"Open web preview tabs","browser.history":"Recently Visited","browser.closeTab":"Close {title}","browser.newTab":"New tab","browser.minimize":"Minimize","browser.back":"Back","browser.forward":"Forward","browser.address":"Address","browser.addressPlaceholder":"Enter a URL or port","browser.addressOrDirectoryPlaceholder":"Enter a URL, or choose a folder","browser.refresh":"Refresh","browser.stop":"Stop loading","browser.viewMode":"Page width","browser.narrowWidth":"Narrow","browser.wideWidth":"Wide","browser.closeTiming":"Close background tabs","browser.minutes":"{value} minutes","browser.neverClose":"Never close","browser.clearHistory":"Clear","browser.emptyHistory":"No recent visits yet","browser.loadFailed":"This page could not be loaded. Check the address and try again.","browser.retry":"Retry","browser.consentTitle":"Web Preview","browser.consentBody":"Handmux embeds pages in this window. It is not a full browser; use it to preview development servers, localhost, intranet sites, and websites that allow embedding. You can also choose a static folder on the computer from Home.","browser.consentComputer":"Connection: Direct uses your phone network. Computer proxy requests originate from your computer and can reach its intranet and localhost without publishing them.","browser.consentPrivate":"Sign-ins: Direct and proxy use separate Cookies and sign-in state. Proxy sessions are also isolated to this device.","browser.consentLimits":"Compatibility: Direct may be blocked by a site’s iframe or CSP policy, and Handmux may not know why. Computer proxy forwards and rewrites pages but cannot guarantee every site. For full browsing, use Safari, Chrome, or your system browser.","browser.consentIdle":"Background tabs: They close after 10 minutes by default. Direct-site Cookies remain in your phone browser.","browser.about":"About Web Preview","browser.acknowledge":"Got it","browser.directMode":"Direct from phone","browser.proxyMode":"Through computer proxy","browser.directBadge":"Direct","browser.proxyBadge":"Proxy","browser.staticBadge":"Static","browser.chooseDirectory":"Choose directory","browser.staticOpening":"Opening directory…","browser.directoryPickerHint":"Choose the directory containing the web files.","browser.switchMode":"Switch browsing mode","browser.menu":"Web preview menu","browser.connectionMode":"Connection","browser.pageWidth":"Page width","browser.requestSiteVersion":"Ask website for","browser.mobileSite":"Mobile","browser.desktopSite":"Desktop","browser.zoomPage":"Zoom page","browser.resetZoom":"Reset page zoom","browser.proxyLogin":"Proxy sign-in","browser.proxyLoginHelpLabel":"About proxy sign-in","browser.proxyLoginHelp":"Whether to encrypt and store proxy Cookies on the computer running Handmux so sign-ins survive a restart.","browser.siteProxyCookie":"This site’s proxy Cookies","browser.siteCookieHelpLabel":"About this site’s proxy Cookies","browser.siteCookieHelp":"This clears only proxy Cookies on this device that match the site’s real URL. Parent-domain Cookies may sign you out of related internal sites. Direct-site Cookies are unaffected.","browser.openMode":"Choose how to open","browser.historyMore":"More opening options","browser.historyActions":"More actions","browser.proxyLimitHint":"Computer proxy mode forwards and rewrites pages and may not work with every website.","browser.proxyUnavailable":"Run handmux setup on the computer and choose “Web preview” to configure its proxy domain. Until then, only Direct mode is available.","browser.urlInvalid":"Enter a valid HTTP or HTTPS address.","browser.tryProxy":"Try computer proxy","browser.openExternal":"Open in system browser","browser.clearSiteLogin":"Clear this site’s proxy Cookies","browser.clearAllLogin":"Clear all proxy Cookies","browser.clearSiteLoginConfirm":"Clear this site’s proxy login on the current device? Parent-domain Cookies may also affect related internal systems.","browser.clearAllLoginConfirm":"Clear every proxy login on the current device? Direct-site logins are not affected.","browser.deleteHistoryEntry":"Delete this record","browser.profileSaveFailed":"Could not save proxy login settings. Check the server connection and try again.","browser.profileClearFailed":"Cleanup was not fully successful. Check the server connection and storage permissions, then try again.","browser.profileSyncFailed":"Proxy login settings could not be synchronized. Retry or use Direct mode.","browser.profileRecoveryWarning":"Saved proxy login data could not be recovered and was reset on this device.","browser.retention1":"1 day","browser.retention7":"7 days","browser.retention30":"30 days","browser.retentionNotSaved":"Not saved","browser.retentionNever":"Long-term storage","settings.browserPersistLogin":"Persist proxy Cookies on the computer","settings.browserPersistLoginHint":"Stored only for this device. Turning this off keeps current tabs and login state until they are cleared or expire.","settings.browserRetention":"Proxy login retention","settings.browserDisablePersistConfirm":"Stop saving future proxy login changes on the current device? Current tabs and login state stay available.","token.title":"Sign in to handmux","token.placeholder":"Enter Token","settings.language":"Language","settings.browserDefaultMode":"Default web mode","settings.browserDefaultModeHint":"Used for new address-bar tabs and recent visits without a saved mode.","settings.browserEnabled":"Web preview","settings.browserEnabledHint":"Tabs belong to this device. Turning this off closes all tabs but keeps recent visits.","home.empty":"No files opened yet","home.emptyHint":'Switch to "New" to pick one',"home.remove":"Remove","drawer.title":"Sessions","drawer.empty":"No sessions bound yet","drawer.unbind":"Unbind","drawer.bind":"Bind session","drawer.logout":"Log out","windowbar.newWindow":"New window","rename.new_name":"New name","rename.name_rule":"Letters, digits, hyphens only (≤16)","rename.failed":"Rename failed, please retry","rename.saving":"Saving…","newwindow.title":"New window","newwindow.window_name":"Window name (optional)","newwindow.name_placeholder":"Leave blank to auto-name · letters/digits/hyphens ≤16","newwindow.name_rule":"Letters, digits, hyphens only (≤16)","newwindow.start_dir":"Start directory","newwindow.session_dir_named":"{dir} (session dir)","newwindow.session_dir_default":"Session dir (default)","newwindow.choose":"Choose","newwindow.reset_to_session_dir":"Reset to session dir","newwindow.creating":"Creating…","startup.label":"Startup command (optional)","startup.aria":"Startup command","startup.preset_shell":"Plain shell (default)","startup.preset_claude":"claude (launch Claude Code)","startup.preset_claude_continue":"claude -c (resume last session)","startup.preset_codex":"codex (launch Codex CLI)","startup.custom":"Custom…","startup.custom_placeholder":'e.g. claude "fix login bug"',"bind.title":"Bind session","bind.sessionName":"Session name","bind.pickSession":"Choose a session to bind","bind.newSession":"+ New session","bind.modeNew":"New","bind.modeExisting":"Existing","bind.alreadyExists":"Session already exists","bind.bind":"Bind","bind.checking":"Checking…","bind.createAndOpen":"Create & open","bind.creating":"Creating…","bind.createHint":`Session "{name}" doesn't exist — tap "Create & open" to create it`,"bind.alreadyBound":"Session already bound","bind.createFailed":"Create failed, please retry","bind.invalidName":"Only letters, digits, hyphens (≤16)","bind.desktopHint":"On the computer, one command takes any session here back over: handmux open <name>","bind.checkFailed":"Check failed, please retry","bind.startDir":"Start directory","bind.homeDirDefault":"Home directory (default)","bind.choose":"Choose","bind.reset":"Reset","actionsheet.confirmAgain":"Confirm? Tap again","dirpicker.title":"Choose directory","inbox.title":"Inbox","inbox.working":"Working","inbox.done":"Done","inbox.needs":"Needs you","inbox.error":"Error","inbox.clearDone":"Clear results","inbox.empty":"No pane status yet","inbox.reconnecting":"Reconnecting to the inbox…","inbox.enableTitle":"Turn on Claude Code states and notifications","inbox.enableHint":"The Claude Code inbox requires Agent hooks. For Codex CLI, use Handmux managed mode.","inbox.enableBtn":"Enable","inbox.enabling":"Enabling…","inbox.enableFailed":"Could not enable — check the server logs.","drawer.orphans.title":"{n} not taken over","drawer.orphans.hint":"Take over to control remotely","inbox.orphans.takeover":"Take over","inbox.orphans.noSession":"no resumable history","inbox.orphans.busy":"busy","inbox.orphans.idle":"idle","inbox.orphans.working":"Taking over…","inbox.orphans.failed":"Takeover failed","inbox.orphans.targetLabel":"Take over into","inbox.orphans.targetNew":"New session","inbox.orphans.nameLabel":"Session name","inbox.orphans.namePlaceholder":"session name","inbox.orphans.killTitle":"The original process","inbox.orphans.killEnd":"End it","inbox.orphans.killKeep":"Keep it","inbox.orphans.recommended":"Recommended","inbox.orphans.killWhy":"If the same session is written from both your computer and your phone, its history gets scrambled. Ending the original lets this device own it cleanly.","inbox.orphans.reopenPre":"Want to continue on the computer instead? Run in a terminal:","idea.title":"Ideas","idea.editPlaceholder":"Edit idea…","idea.addPlaceholder":"Jot an idea…","idea.add":"Add","idea.empty":"No ideas yet — jot one down","idea.dragSort":"Drag to reorder","idea.fillInput":"Fill into input","idea.send":"Send","doclink.title":"Open file","localurl.title":"Open website","localurl.open":"Open in Browser","localurl.notListening":"Nothing is listening on :{port}.","localurl.badProtocol":"This link is not a proxyable HTTP or HTTPS address.","localurl.network":"Could not reach the handmux service. Check your connection and try again.","localurl.failed":"Could not open this website. Check the address and try again.","changelog.title":"What's new","preview.static":"Static preview","preview.tabs":"Open previews","preview.remainTitle":"Time left — tap to renew / stop","preview.toPcView":"Switch to desktop view","preview.toMobileView":"Switch to mobile view","preview.pcView":"Desktop view","preview.mobileView":"Mobile view","preview.refresh":"Refresh","preview.minimize":"Minimize","preview.ttlDialog":"Preview lifetime","preview.renew":"Renew (reset to 1 hour)","preview.stop":"Stop preview","preview.iframeTitle":"Preview","preview.zoomOut":"Zoom out","preview.zoomIn":"Zoom in","imageviewer.loadFailed":"Failed to load image","imageviewer.saved":"Saved — find it in your album/gallery or Downloads","imageviewer.shareUnsupported":"Image sharing requires Chrome or Safari","imageviewer.zoomOut":"Zoom out","imageviewer.zoomIn":"Zoom in","imageviewer.imageTitle":"Image","imageviewer.saveImage":"Save image","imageviewer.shareImage":"Share image","mic.stop":"Stop voice input","mic.start":"Voice input","mic.recognizing":"Recognizing speech","mic.error.tencentPermission":"Tencent Cloud rejected recognition. Grant the current SecretId the asr:SentenceRecognition permission, then try again.","mic.error.tencentCredentials":"The Tencent Cloud credentials are invalid. Check AppId, SecretId, and SecretKey in handmux setup.","mic.error.browserPermission":"Microphone access is blocked. Allow it in this site's browser settings, then try again.","mic.error.device":"The microphone is unavailable. Check that it exists and is not in use by another app.","mic.error.secureContext":"This address cannot access the microphone. Open Handmux over HTTPS or localhost.","mic.error.tooLong":"The recording is too long. Record a shorter message and try again.","mic.error.notSelected":"The selected voice mode is not active. Restart Handmux and try again.","mic.error.noSpeech":"No speech was recognized. Please try again.","mic.error.network":"Could not reach the speech service. Check the network and try again.","mic.error.provider":"The speech service rejected the request: {reason}","mic.error.generic":"Voice input failed. Please try again.","dock.send":"Send","dock.send.hint":"Tap to send · hold to insert","dock.phrases":"Phrases","dock.attach":"Upload","dock.history":"History","dock.kbdShow":"Keyboard","dock.kbdHide":"Hide keyboard","history.empty":"No history yet","history.scope":"This window only","dock.input.placeholder":"Say something…","dock.input.enterDraft":"Press Shift + Enter to enter draft mode","dock.input.exitDraft":"Press Esc to return to terminal mode · Shift + Enter for a new line","dock.command.placeholder":"Type a command · Enter runs it","dock.mode.agent":"Chat","dock.mode.toggle":"Switch input mode","dock.mode.command":"Command","dock.mode.chat":"Chat","fav.title":"Favorites","fav.add":"Add","fav.addPlaceholder":"Add a favorite…","cmd.editTitle":"Saved commands","cmd.global":"GLOBAL","cmd.window":"THIS WINDOW","cmd.withEnter":"Send directly","cmd.configPresets":"Config presets","cmd.removeDevice":"Remove from this device","cmd.removedDevice":"Removed from this device","cmd.addPlaceholder":"Add a command…","cmd.tabCmd":"Command","cmd.tabKey":"Key","cmd.addTo":"Add to","cmd.addTitle":"Add","cmd.added":"Added","cmd.editItem":"Edit","cmd.sticky":"Modifier","cmd.stickyNone":"None","cmd.baseKey":"Key","cmd.pickKey":"Pick a key","cmd.moveUp":"Move up","cmd.moveDown":"Move down","chat.editTitle":"Saved messages","chat.composer.placeholder":"Message the agent…","chat.historyPulling":"Loading earlier messages…","agentConversation.empty":"Start a conversation with this agent.","agentConversation.unavailable":"Unable to connect to the conversation","agentConversation.reconnecting":"Reconnecting to the live conversation…","agentConversation.reloadRequired":"The Pi conversation integration was updated. Switch to the terminal, run /reload, then return here.","agentConversation.loadOlder":"Load earlier messages","agentConversation.loadOlderFailed":"Earlier messages could not be loaded. Please try again.","agentConversation.reasoning":"Reasoning summary","agentConversation.toolResult":"Tool result","agentConversation.diff":"Changes","agentConversation.attachment":"Attachment","agentConversation.attachmentFailed":"The attachment could not be downloaded. Please try again.","agentConversation.truncated":"Some content was truncated.","agentConversation.interactionTerminal":"Complete this action in the terminal.","agentConversation.interactionUnavailable":"This request is temporarily unavailable in chat.","agentConversation.interactionCommandApproval":"Allow this command?","agentConversation.interactionFileApproval":"Allow file changes?","agentConversation.interactionPermissionApproval":"Allow the requested permissions?","agentConversation.interactionInputRequest":"Additional input is required","agentConversation.interactionReason":"Reason","agentConversation.interactionCommand":"Command","agentConversation.interactionWorkingDirectory":"Working directory","agentConversation.interactionContext":"Context","agentConversation.interactionOther":"Enter another answer","agentConversation.interactionPlaceholder":"Enter an answer","agentConversation.openTerminal":"Open Terminal","chat.stop":"Stop","chat.stopTitle":"Stop the current task?","chat.stopBody":"The turn currently in progress will be interrupted.","chat.config.open":"Configure model, service tier, and reasoning effort","chat.config.title":"Model settings","chat.config.model":"Model","chat.config.effort":"Reasoning effort","chat.config.fast":"Fast","chat.config.fastHint":"Use the faster service offered by this model","chat.config.loading":"Loading available models…","chat.config.empty":"No models are available","chat.config.chooseModel":"Choose an available model first","chat.config.loadFailed":"Could not load the model list","chat.config.refresh":"Refresh model list","chat.config.saveFailed":"The setting could not be saved","chat.config.nextTurn":"The current response stays unchanged; this applies to your next message.","chat.goal.title":"Task goal","chat.goal.objective":"Goal objective","chat.goal.placeholder":"Describe a goal Codex should keep working toward","chat.goal.loading":"Loading the current goal…","chat.goal.loadFailed":"Could not load the current goal","chat.goal.saveFailed":"The goal could not be saved","chat.goal.clearFailed":"The goal could not be cleared","chat.goal.tooLong":"A task goal can contain at most 4,000 characters","chat.goal.created":"Task goal set","chat.goal.updated":"Task goal updated","chat.goal.paused":"Task goal paused","chat.goal.resumed":"Task goal resumed","chat.goal.restarted":"Task goal restarted","chat.goal.cleared":"Task goal cleared","chat.goal.edit":"Edit","chat.goal.pause":"Pause","chat.goal.resume":"Resume","chat.goal.restart":"Restart","chat.goal.clear":"Clear","chat.goal.clearConfirmTitle":"Clear this task goal?","chat.goal.clearConfirmBody":"The current task goal will be deleted and Codex will stop tracking it. Its historical chat card will remain.","chat.goal.statusActive":"Active","chat.goal.statusPaused":"Paused","chat.goal.statusBlocked":"Blocked","chat.goal.statusComplete":"Complete","chat.goal.statusUsageLimited":"Usage limited","chat.goal.statusBudgetLimited":"Budget limited","chat.goal.eventSet":"Goal set","chat.goal.eventRestarted":"Goal restarted","chat.goal.eventComplete":"Goal complete","chat.goal.eventBlocked":"Goal blocked","chat.goal.eventUsageLimited":"Goal ended: usage limited","chat.goal.eventBudgetLimited":"Goal ended: budget limited","chat.goal.tokens":"Tokens {value}","chat.goal.elapsed":"Elapsed {value}s","chat.plan.currentTitle":"Current tasks","chat.plan.historyTitle":"Turn tasks","chat.plan.working":"Working on: {step}","chat.plan.waiting":"Waiting for confirmation: {step}","chat.plan.finalizing":"Preparing the result","chat.plan.complete":"Completed","chat.plan.incomplete":"Incomplete","chat.plan.status.pending":"Pending","chat.plan.status.inProgress":"In progress","chat.plan.status.completed":"Completed","chat.context.aria":"Context usage {percent}%","chat.context.unavailableAria":"Context status, usage temporarily unavailable","chat.context.title":"Context usage","chat.context.percent":"Context window used","chat.context.used":"Current tokens","chat.context.total":"Model total tokens","chat.context.usedTotal":"Used / total","chat.status.aria":"Session status, context usage {percent}%","chat.status.title":"Session status","chat.status.idle":"Idle","chat.status.working":"Working","chat.status.waitingApproval":"Waiting for approval","chat.status.waitingInput":"Waiting for input","chat.status.compacting":"Compacting","chat.compacting.live":"Compacting context","chat.status.directory":"Directory","chat.status.worktree":"Worktree","chat.status.branch":"Branch","chat.status.access":"Access","chat.status.permissionMode":"Permissions","chat.status.sessionId":"Session ID","chat.status.copyDirectory":"Copy directory","chat.status.copyWorktree":"Copy Worktree path","chat.status.copySession":"Copy session ID","chat.status.copied":"Copied","chat.status.sandboxReadOnly":"Read only","chat.status.sandboxWorkspace":"Workspace write","chat.status.sandboxFull":"Full access","chat.permissionMode.default":"Default","chat.permissionMode.autoReview":"Auto-review","chat.permissionMode.fullAccess":"Full Access","chat.permissionMode.custom":"Custom","chat.permissionMode.title":"Permissions","chat.permissionMode.open":"Set permissions, currently {value}","chat.permissionMode.defaultHint":"Read and edit this workspace and run commands; asks before using the internet or other locations.","chat.permissionMode.autoReviewHint":"Same access as Default; Codex automatically approves or denies requests for more access.","chat.permissionMode.fullAccessHint":"Access locations outside the workspace and the internet without asking; use only for trusted tasks.","chat.permissionMode.nextTurn":"Changes apply to your next message","chat.permissionMode.saved":"Permissions updated for your next message","chat.permissionMode.saveFailed":"Permissions could not be saved","chat.interrupted":"You stopped the response","chat.compacted":"Context compacted","chat.compaction.viewDetails":"View details","chat.compaction.title":"Context compaction","chat.compaction.complete":"Complete","chat.compaction.summary":"Summary retained by the agent","chat.compaction.unavailable":"No inspectable summary was provided for this compaction.","chat.compaction.truncated":"This summary was too long, so only the safely retained portion is shown.","chat.scroll.latest":"Jump to latest","chat.scroll.reloadLatest":"↓ Jump to latest","chat.scroll.answer":"↓ View latest answer","chat.scroll.bottom":"↓ Jump to bottom","chat.slash.unsupported":"This command is not supported in chat view yet","chat.session.unboundTitle":"This Codex chat could not be identified","chat.session.unboundHint":"Codex is still starting. The exact chat will appear automatically once it is available.","chat.session.openTerminal":"Open terminal","chat.session.notManaged":"Restart Codex in managed mode from the terminal first","chat.session.unmanagedTitle":"This Codex session is not managed","chat.session.unmanagedHint":"Restart it in managed mode from the terminal before opening chat.","chat.session.connectionHint":"Codex App Server is unavailable. Check that Codex is still running, then try again.","chat.managedGuide.title":"Connect this Codex chat","chat.managedGuide.hint":"Handmux can resume the original session in this pane and switch it to reliable managed chat.","chat.managedGuide.start":"Start managed mode","chat.managedGuide.submitting":"Starting…","chat.managedGuide.confirmTitle":"Start managed mode?","chat.managedGuide.confirmHint":"The current Codex process will end, including any task in progress. Resuming may require you to open the terminal and handle trust or another confirmation manually.","chat.managedGuide.confirmAction":"End and start managed mode","chat.managedGuide.startingTitle":"Starting managed mode","chat.managedGuide.startingHint":"Resuming the original session. Chat opens automatically when it is ready.","chat.managedGuide.terminalHint":"Startup has not finished. Codex may be waiting for trust or another confirmation in the terminal.","chat.managedGuide.timeoutTitle":"Managed mode is not ready","chat.managedGuide.timeoutHint":"Handmux has waited 30 seconds. Codex may need a manual confirmation in the terminal. This page will not switch automatically.","chat.managedGuide.manualTitle":"Continue in the terminal","chat.managedGuide.manualHint":"Codex did not exit normally or return verifiable recovery information. Open the terminal to inspect its current state.","chat.managedGuide.goneTitle":"This Codex has changed","chat.managedGuide.goneHint":"Handmux stopped to avoid ending the wrong process. Open the terminal to check its current state.","chat.managedGuide.unavailableTitle":"Could not verify this Codex session","chat.managedGuide.unavailableHint":"Try again, or open the terminal to continue.","chat.managedGuide.failedHint":"Managed startup could not finish. Try again or open the terminal to check its current state.","chat.managedGuide.recoveryHint":"The original session was verified. If automatic resume failed, run this in the terminal:","chat.managedGuide.copyRecovery":"Copy recovery command","chat.managedGuide.recoveryTitle":"Continue recovering this Codex chat","chat.managedGuide.recoveryReadyHint":"The previous takeover stopped before resume. It is safe to continue in this pane.","chat.managedGuide.recoveryManualHint":"Handmux cannot verify that automatic resume is still safe. Copy the command or open the terminal.","chat.managedGuide.recoveryStaleTitle":"The original pane changed","chat.managedGuide.recoveryStaleHint":"To avoid sending into the wrong pane, only copy is available here.","chat.managedGuide.retryRecovery":"Continue recovery","chat.approval.request":"Codex needs confirmation","chat.approval.file":"Allow these file changes?","chat.approval.command":"Allow this command to run?","chat.approval.permissions":"Allow Codex to use additional permissions?","chat.approval.accept":"Allow once","chat.approval.acceptSession":"Always allow this session","chat.approval.acceptRule":"Allow and remember “{rule}”","chat.approval.allowHost":"Always allow access to {host}","chat.approval.denyHost":"Always deny access to {host}","chat.approval.decline":"Deny","chat.approval.cancel":"Deny and stop","chat.approval.failed":"The approval could not be submitted","chat.input.request":"Codex needs your answer","chat.input.step":"Question {current} of {total}","chat.input.other":"Other answer","chat.input.placeholder":"Enter your answer","chat.input.submit":"Submit answer","chat.input.failed":"The answer could not be submitted","chat.sendFailed":"The message could not be sent","chat.terminalDraftConflict":"The terminal has an unconfirmed draft. Handle it in the terminal, then retry.","chat.queue.terminalDraftConflict":"The terminal has an unconfirmed draft. Handle it there, then edit this message to retry.","chat.sendUnknown":"Delivery could not be confirmed. Check the conversation before trying again.","chat.stopFailed":"Could not stop the turn. Try again.","chat.queue.title":"Queued messages","chat.queue.hint":"Sent one by one after the current turn","chat.queue.steer":"Guide now","chat.queue.edit":"Edit queued message","chat.queue.editTitle":"Edit queued message","chat.queue.editPlaceholder":"Enter queued message","chat.queue.remove":"Delete queued message","chat.queue.removeTitle":"Delete this queued message?","chat.queue.removeBody":"This cannot be undone.","chat.queue.actionFailed":"The queued message could not be updated. Try again.","chat.queue.editExpired":"This edit expired. Close it and edit the message again.","chat.queue.editConflict":"This queued message changed elsewhere. Your draft is preserved; close it and review the latest version.","chat.queue.providerRejected":"Not sent. Edit to retry, or delete it.","chat.queue.unknownDelivery":"Delivery is unconfirmed and will not retry automatically.","chat.controls.actionFailed":"The setting could not be updated. Try again.","chat.config.serviceTier":"Service tier","chat.config.serviceTierDefault":"Default","chat.config.unavailable":"Model settings are temporarily unavailable. Try again.","agentConversation.interactionResponseFailed":"The response could not be sent. Try again or continue in the terminal.","chat.activation.title":"Open Conversation View?","chat.activation.body":"Handmux needs to restart this Agent in managed mode. The current conversation will continue in the same pane.","chat.activation.terminal":"Stay in Terminal","chat.activation.activating":"Preparing the current conversation…","chat.activation.waiting":"Waiting for the managed conversation to reconnect…","chat.activation.working":"Preparing…","chat.activation.stale":"This Agent changed before activation. Return to the terminal or try again.","chat.activation.timeout":"The Agent started, but Conversation View has not connected yet. You can continue in the terminal and try again later.","chat.activation.failed":"Conversation View could not be prepared. Continue in the terminal or try again.","chat.activation.unavailable":"This conversation cannot be switched safely right now. Continue in the terminal.","conversationTool.tool":"Tool","conversationTool.run":"Run command","conversationTool.runValue":"Run {value}","conversationTool.edit":"Edit file","conversationTool.editValue":"Edit {value}","conversationTool.write":"Write file","conversationTool.writeValue":"Write {value}","conversationTool.read":"Read file","conversationTool.readValue":"Read {value}","conversationTool.web":"Browse the web","conversationTool.image":"View image","conversationTool.imageValue":"View image {value}","conversationTool.wait":"Wait for task to finish","conversationTool.waitShort":"Wait for task","conversationTool.continue":"Continue running task","conversationTool.continueShort":"Continue task","conversationTool.search":"Search","conversationTool.searchValue":"Search {value}","conversationTool.find":"Find files","conversationTool.findValue":"Find files {value}","conversationTool.webSearch":"Search the web","conversationTool.webSearchValue":"Search the web {value}","conversationTool.webRead":"Read webpage","conversationTool.webReadValue":"Read webpage {value}","conversationTool.todo":"Update tasks","conversationTool.skill":"Activate skill","conversationTool.skillValue":"Activate skill {value}","conversationTool.agent":"Call Agent","conversationTool.agentValue":"Call Agent {value}","conversationTool.call":"Call tool","conversationTool.callValue":"Call tool {value}","conversationTool.diffStat":"{added} lines added, {removed} removed","conversationTool.declined":"Declined","conversationTool.completed":"Finished","conversationTool.failed":"Failed","conversationTool.success":"Succeeded","conversationTool.running":"Running","conversationTool.runningEllipsis":"Running…","conversationTool.noReturn":"No response","conversationTool.createdFile":"Created file · {added} lines added","conversationTool.noChanges":"No changes to display","conversationTool.mode":"Execution mode","conversationTool.command":"Command","conversationTool.output":"Output","conversationTool.imagePathMissing":"No resolvable image path provided","conversationTool.imageUnavailable":"Unable to read the image. Check the file and read permissions.","conversationTool.noOutput":"No output","conversationTool.truncation.input.sizeLimit":"This input was long, so only the safely retained portion is shown. The tool ran with the complete input.","conversationTool.truncation.output.sizeLimit":"This output was long, so only the safely retained portion is shown. Tool execution was not affected.","conversationTool.truncation.diff.sizeLimit":"These changes were long, so only the safely retained portion is shown. The actual changes were not affected.","conversationTool.truncation.provider_truncated":"The Agent returned this content already truncated, so this record may be incomplete.","conversationTool.truncation.redacted":"Sensitive content was hidden.","conversationTool.truncation.unavailable":"This part of the tool record is temporarily unavailable.","chat.outgoing.sending":"Sending","chat.outgoing.queued":"Queued","chat.outgoing.sent":"Sent","chat.outgoing.steered":"Guided","chat.outgoing.failed":"Failed to send","chat.outgoing.unknown":"Delivery not confirmed","chat.outgoing.retry":"Retry","chat.outgoing.retryUnknown":"Check status","chat.outgoing.resendTitle":"Send this message again?","chat.outgoing.resendBody":"This message may already have been delivered. Continuing sends it as a new message and may run the task twice.","chat.outgoing.resendConfirm":"Send Anyway","chat.favs":"Saved","chat.tabMsg":"Message","chat.addPlaceholder":"Message / slash-command…","dock.upload.aria":"Upload file","dock.upload.title":"Upload file (saved to home upload area, not the project)","dock.upload.progress":"Uploading {name}{tag}","dock.upload.failed":"Upload failed: {names}","dock.upload.rejected":"Unsupported file type: {names}","app.nameExists":"That name already exists","app.renameFailed":"Rename failed, please retry","app.deleteFailed":"Delete failed, please retry","app.moveFailed":"Move failed, please retry","app.sessionGone":'Session "{name}" not found, it may have closed',"app.docNotFound":"File not found","app.docTooLarge":"File too large (over 2MB)","app.docUnsupported":"Unsupported file or path","app.docOpenFailed":"Open failed, please retry","app.preview":"Preview","app.openPreview":"Open preview","app.ideas":"Ideas","app.files":"Files","app.settings":"Settings","usage.title":"Usage","usage.subscriptionTab":"Subscriptions","usage.apiTab":"API","usage.win5h":"5-hour","usage.winWeekly":"Weekly","usage.winMonthly":"Monthly","usage.winGeneric":"{h}h window","usage.winPrimary":"Limit","usage.winSecondary":"Secondary","usage.accountQuota":"Account limits","usage.modelLimits":"Model-specific limits","usage.accountApiKey":"API key account","usage.resetIn":"resets in {t}","usage.resetSoon":"resetting…","usage.resetCredits":"Rate-limit resets","usage.resetCreditsCount":"{n} available","usage.resetCreditExpires":"Expires {time}","usage.claudeOff":"Not wired yet — Claude's 5h/weekly usage needs the handmux statusLine:","usage.claudePending":"No data yet — send a message in a Claude session, then reopen.","usage.codexOff":"Codex not detected on this machine.","usage.codexNoQuota":"Codex has not returned quota data yet.","usage.setupRequired":"Usage collection is not connected yet.","usage.pending":"No quota data yet. Send a message in the Agent, then reopen.","usage.unavailable":"No usage data is currently available on this machine.","usage.loadFailed":"Failed to load usage.","usage.refresh":"Refresh","usage.refreshing":"Refreshing…","usage.refreshFailed":"Subscription usage could not be refreshed. Check the connection and try again.","usage.updatedNow":"updated just now","usage.updatedMin":"updated {n}m ago","usage.updatedHr":"updated {n}h ago","usage.updatedDay":"updated {n}d ago","usage.updatedCompactNow":"now","usage.updatedCompactMin":"{n}m","usage.updatedCompactHr":"{n}h","usage.updatedCompactDay":"{n}d","usage.timeMark":"Time elapsed in this window","usage.menu":"{provider} usage options","usage.show":"Show usage","usage.hide":"Hide usage","apiBalance.title":"API balances","apiBalance.add":"Add API","apiBalance.menu":"Account actions","apiBalance.menuAccount":"{account} ({provider}) account actions","apiBalance.official":"official data","apiBalance.available":"API available","apiBalance.insufficient":"Insufficient balance","apiBalance.notQueried":"Balance not queried yet","apiBalance.noBalanceData":"No balance data","apiBalance.currencyAvailable":"{currency} available balance","apiBalance.toppedUp":"Topped up","apiBalance.granted":"Granted","apiBalance.cash":"Cash balance","apiBalance.voucher":"Voucher balance","apiBalance.refreshing":"Refreshing…","apiBalance.refresh":"Refresh","apiBalance.rename":"Rename","apiBalance.replaceCredential":"Replace credential","apiBalance.deleteConfirm":"Delete this account? Tap again","apiBalance.empty":"No APIs added yet","apiBalance.emptyHint":"Add an API to see official provider balance data.","apiBalance.addAccount":"Add API account","apiBalance.storageNote":"API keys are encrypted on the computer running Handmux. Full keys are never returned to the browser.","apiBalance.account":"Account","apiBalance.provider":"Provider","apiBalance.chooseProvider":"Choose provider","apiBalance.name":"Name","apiBalance.credentialNote":"API keys are encrypted on the computer running Handmux. Full keys are never returned to the browser.","apiBalance.secureRequired":"Open Handmux over HTTPS or on localhost to submit credentials.","apiBalance.verifySave":"Verify & Save","apiBalance.verifying":"Verifying…","apiBalance.form.add":"Add API","apiBalance.form.rename":"Rename API","apiBalance.form.credential":"Replace credential","apiBalance.loadFailed":"API balances could not be loaded. Try again.","apiBalance.refreshFailed":"The balance could not be refreshed. Try again.","apiBalance.saveFailed":"The account could not be saved. Check the connection and try again.","apiBalance.deleteFailed":"The account could not be deleted. Try again.","apiBalance.error.invalid_credential":"Credential invalid, not permitted, or provider verification is required · check the provider account and replace credential if needed","apiBalance.error.rate_limited":"Too many requests · try again later","apiBalance.error.provider_timeout":"Provider did not respond in time · try again","apiBalance.error.provider_unreachable":"Provider is temporarily unreachable · try again","apiBalance.error.unsupported_response":"Provider returned unsupported data · try again","apiBalance.error.storage_unavailable":"Saved API accounts are unavailable · do not clear these files or the accounts cannot be recovered. First back up ~/.handmux/api-accounts.json, api-accounts.key, .corrupt.*, and .unavailable; restore a matching api-accounts.key and api-accounts.json (recover the data file from .corrupt.* if needed), then remove .unavailable last and restart Handmux","apiBalance.error.conflict":"The account changed elsewhere · reopen it and try again","apiBalance.error.account_limit_reached":"Up to 1,000 API accounts can be saved · delete an unused account and try again","apiBalance.error.not_found":"The account was deleted elsewhere · close this window and refresh","app.renameSession":"Rename session","app.renameWindow":"Rename window","app.manageWindow":"Window Management","app.moveLeft":"◀ Move left","app.moveRight":"Move right ▶","app.deleteWindow":"Delete window","pane.splitH":"Split left/right","pane.splitV":"Split top/bottom","pane.manage":"Manage split","pane.manageTitle":"Split Management","pane.close":"Close pane","pane.closeConfirm":"Close? Tap again","pane.splitFailed":"Split failed","pane.closeFailed":"Close failed","resize.windowWidth":"Window width","resize.paneWidth":"Pane width","resize.columns":"{n} columns","resize.restore":"Restore","resize.restoreAutoWidth":"Restore automatic width","resize.restoreRatio":"Restore split ratio","app.deleteLastWindowConfirm":"This is the last window; deleting it closes the whole session! Tap again","app.deleteConfirm":"Delete? Tap again","app.cannotLocate":"Cannot locate","app.pickItsDir":", pick the directory it lives in:","app.noBoundSession":"No bound session yet","app.tapToBind":"Tap here to bind one","app.selectSessionHint":"Tap ☰ at the top-left to pick a session","app.backToExit":"Press Back again to exit","settings.title":"Settings","settings.group_global":"Global settings","settings.group_general":"General","settings.group_voice":"Speech to Text","settings.voice_enabled":"Enabled","settings.voice_on":"On","settings.voice_off":"Off","settings.voice_provider":"Current provider","settings.voice_profile_tencent_streaming":"Tencent Cloud real-time ASR","settings.voice_profile_tencent_sentence":"Tencent Cloud sentence ASR","settings.voice_profile_xfyun":"iFlytek voice dictation","settings.voice_not_configured":"Not configured","settings.voice_filler_filter":"Filler word filtering","settings.voice_filter_low":"Low","settings.voice_filter_medium":"Medium","settings.voice_filter_high":"High","settings.voice_not_supported":"Not supported","settings.voice_setup_hint":"Run handmux setup in your terminal, then open Voice input to configure it.","settings.project_task_beta":"Project Tasks Beta","project.root.projects":"Projects","project.root.sessions":"Sessions","project.add":"Add Project","project.archivedProjects":"Archived Projects ({n})","project.empty":"No projects yet","project.emptyHint":"Choose a local folder to start capturing requirements and tasks.","project.manage":"Project settings","project.tasks":"Tasks","project.drafts":"Drafts","project.noTasks":"No tasks yet","project.noDrafts":"No drafts yet","project.newTask":"New task","project.newDraft":"Capture draft","project.storeUnavailable":"Project data is temporarily unavailable","project.tryAgain":"Try again","project.task.title":"Title","project.task.objective":"Goal","project.task.acceptance":"Acceptance criteria (one per line)","project.task.scope":"Scope and non-goals","project.task.constraints":"Constraints","project.task.references":"References (one URL or path per line)","project.task.priority":"Priority","project.task.priority.none":"None","project.task.priority.high":"High","project.task.priority.medium":"Medium","project.task.priority.low":"Low","project.task.saveDraft":"Save draft","project.task.saveTask":"Save as task","project.task.save":"Save","project.task.edit":"Edit requirements","project.task.promote":"Convert to task","project.task.cancel":"Cancel task","project.task.archive":"Archive","project.task.cancelConfirm":"Canceled tasks become read-only and cannot return to the queue. Continue?","project.task.archiveConfirm":"Archived items leave the normal list but are not deleted. Continue?","project.task.discardConfirm":"Your unsaved changes will be lost. Go back anyway?","project.task.conflict":"This task changed on another page. Refresh it before confirming your edits again.","project.task.actionConflict":"This task changed on another page. The latest version is loaded; review its current state.","project.task.loadLatest":"Load latest","project.task.request":"What should be done?","project.task.requestPlaceholder":"Describe what you need","project.task.requestHint":"The first non-empty line becomes the title. The Agent organizes the remaining details when work starts.","project.task.create":"Create task","project.management.overview":"Overview","project.management.context":"Guidance & memory","project.management.git":"Git","project.management.memoryOff":"Project Memory is not enabled yet","project.management.readOnly":"Read-only","project.management.projectRoot":"Project folder","project.management.repositoryRoot":"Code repository","project.management.defaultAgent":"Default Agent","project.management.notSet":"Not set","project.management.isolation":"Task code location","project.management.execution.project-root":"Project folder","project.management.execution.worktree":"Isolated workspace","project.management.guidance":"Project guidance","project.management.guidanceFailed":"Could not read project guidance. Check folder permissions and retry.","project.management.noGuidance":"No AGENTS.md or CLAUDE.md was found in the project root.","project.management.memoryHint":"Project memory proposals and approvals will appear here later.","project.management.conflict":"This project changed on another page. The latest version is loaded; review it and retry.","project.management.notGit":"This is not a Git repository","project.management.notGitHint":"Tasks still work normally; code changes are simply unavailable here.","project.management.gitFailed":"Could not read Git status. Check the repository and retry.","project.management.gitClean":"The working tree has no uncommitted changes.","project.management.gitChanges":"{n} files have uncommitted changes","project.management.history":"Task history","project.management.canceled":"Canceled ({n})","project.management.archived":"Archived ({n})","project.management.historyEmpty":"Nothing here yet","project.management.historyFailed":"Could not load task history. Try again later.","project.management.archiveProject":"Archive Project","project.management.archiveConfirm":"The Project and its active tasks will leave the normal views, but no data will be deleted. Continue?","settings.group_terminal":"Terminal","settings.group_chat":"Chat","settings.group_notifications":"Notifications","settings.group_about":"About","settings.terminal_font_size":"Terminal font size","settings.terminal_font_decrease":"Decrease terminal font size","settings.terminal_font_increase":"Increase terminal font size","settings.terminal_font_auto":"Auto","settings.terminal_font_auto_title":"Auto-fit to height","settings.conversation_font_size":"Conversation font size","settings.conversation_font_decrease":"Decrease conversation font size","settings.conversation_font_increase":"Increase conversation font size","settings.conversation_font_default":"Reset to default","settings.conversation_font_hint":"Adjust from 10–20px in 1px steps; affects only conversation message text and its Markdown and code.","settings.keyboard_mode":"Keyboard mode","settings.keyboard_mode_auto":"Auto detect","settings.keyboard_mode_mobile":"Mobile","settings.keyboard_mode_desktop":"Desktop","settings.keyboard_mode_hint":"Applies only to this browser; override it if detection is wrong.","settings.terminal_transport":"Terminal delivery mode","settings.terminal_transport_live":"Live pushing","settings.terminal_transport_snapshot":"Snapshot pulling","settings.terminal_transport_hint":"Live pushing uses WebSocket for lower latency, falls back to snapshot pulling on a poor connection, and retries after 30 stable seconds.","settings.snapshot_interval":"Active refresh rate","settings.snapshot_interval_hint":"The terminal refreshes less often while idle to reduce traffic and resource use.","settings.conversation_view_agent":"{agent} Conversation View","settings.experimental":"Experimental","settings.group_agent_integration":"Agent Integration","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"Working…","settings.agent_integration_load_error":"Could not check Agent status.","settings.agent_integration_action_error":"Could not complete setup. Run this on your computer:","settings.agent_integration_conflict_hint":"{agent} has an existing configuration. Diagnose it on your computer:","settings.agent_integration_not_installed_hint":"{agent} is not installed on this computer.","settings.agent_integration_initialize_first_hint":"Run {agent} once on your computer, then come back to enable it.","settings.agent_integration_enable":"Enable","settings.agent_integration_repair":"Repair","settings.agent_integration_loading":"Checking…","settings.agent_integration_status_ready":"Ready","settings.agent_integration_status_not_enabled":"Not enabled","settings.agent_integration_status_needs_repair":"Needs repair","settings.agent_integration_status_conflict":"Needs attention","settings.agent_integration_status_not_installed":"Not installed","boot.loading":"Loading","boot.chat_empty":"Send your first message to start the conversation","settings.chat_tone":"Chat colour","settings.chat_tone_dusk":"Warm Dusk","settings.chat_tone_ink":"Warm Gold","settings.chat_tone_light":"Warm Cream","settings.chat_tone_hint":"The colour tone of the 对话 (chat) view — all warm.","settings.path_highlight":"Highlight file paths","settings.path_highlight_hint":"Tint tappable file paths in the terminal. Paths stay tappable either way.","settings.whats_new":"What's new","settings.view_changelog":"View changelog","settings.reload_app":"Reload app","settings.has_update":"Has update","settings.version":"Version","settings.feedback":"Feedback","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat group","settings.feedback_hint":"Bugs and ideas welcome — issues are tracked and answered.","settings.update_available":"Version {v} available","settings.update_more":"{n} more version updates","settings.update_how":"On your computer, run","settings.push_notifications":"Push notifications","settings.notify_on":"Enabled ✓","settings.notify_enable":"Enable device notifications","settings.notify_enabled":"Enabled, you should receive a welcome notification","settings.notify_disabled":"Disabled","settings.notify_failed":"Operation failed","settings.notify_disable_title":"Turn off push notifications?","settings.notify_disable_hint":"This device will stop receiving “Needs you”, “Done”, and script push notifications. You can turn them back on anytime.","settings.notify_disable_confirm":"Turn Off","settings.processing":"Processing","settings.push_hint":'Listens for "Needs you" and "Done": when a watched session needs your authorization/answer, or a turn just finished, a push is sent to this device.',"settings.push_unsupported":"Push requires Chrome or Safari","settings.preview_site":"Preview site","settings.preview_static_site":"Preview static site","settings.preview_running_static":"Static preview running","settings.preview_remain_title":"Time remaining","settings.preview_remain":"{time} left","settings.preview_renew":"Renew","settings.preview_confirm_stop":"Confirm stop","settings.preview_stop":"Stop","settings.preview_name":"Name: {name}","settings.preview_port":"(port :{port})","settings.preview_type":"Preview type","settings.preview_off":"Off","settings.preview_static":"Static","settings.preview_off_hint":'Preview is off. Choose "Static" to start.',"settings.preview_off_hint_both":'Preview is off. Choose "Static" or "Dynamic" to start.',"settings.preview_pick_dir":"Pick directory & start","settings.preview_static_hint":"Pick a directory containing index.html to preview on your phone.","settings.preview_port_placeholder":"Port, e.g. 3000","settings.preview_port_label":"Port","settings.preview_starting":"Starting…","settings.preview_start":"Start","settings.dir_picker_hint":"Pick the static site directory to preview (containing index.html)","settings.err_port_not_listening":"That port is not listening; make sure the service is running","settings.err_bad_port":"Invalid port (1–65535)","settings.err_start_failed":"Failed to start","filebrowser.openDirFailed":"Cannot open this directory","filebrowser.copiedPath":"Path copied: {abs}","filebrowser.mkdirFailed":"Failed to create folder (invalid name or already exists)","filebrowser.downloading":"Downloading {name}","filebrowser.downloadFailed":"Download failed","filebrowser.uploading":"Uploading {name}{tag}","filebrowser.uploadFailed":"Upload failed","filebrowser.uploadPartialFailed":"These files failed to upload: {names}","filebrowser.uploadRejected":"Unsupported file type: {names}","filebrowser.sessionDir":"Session directory","filebrowser.jumpToSessionDir":"Jump to current session directory","filebrowser.parentDir":"Parent directory","filebrowser.rootSelect":"Switch root (home / temp dirs)","filebrowser.pathPlaceholder":"Enter path (live filter / jump)","filebrowser.newFolder":"New folder","filebrowser.createBtn":"Create","filebrowser.uploadFile":"Upload file","filebrowser.uploadToCurrentDir":"Upload to current directory","filebrowser.enterSubdirToUpload":"Enter a subdirectory to upload","filebrowser.folderNamePlaceholder":"Folder name","filebrowser.uploadPendingTo":"Upload “{name}” to the current directory","filebrowser.enterSubdirFirst":"(enter a subdirectory first)","filebrowser.upload":"Upload","filebrowser.savedToDownloads":"Saved “{name}” to the Downloads folder; view it in the system file manager","filebrowser.noMatches":"No matching files or directories","filebrowser.tooMany":"Showing the first {shown} of {total} — type in the path box to filter","filebrowser.previewUnsupported":"Preview not supported for this file type; tap the button on the right to download","filebrowser.copyAbsPath":"Copy absolute path","filebrowser.download":"Download","filebrowser.pickThisDir":"Select this directory {path}","filebrowser.downloadConfirm":"Download {name}?","filemanager.files":"Files","filemanager.closeTab":"Close tab","filemanager.minimize":"Minimize","filemanager.recent":"Recent","filemanager.directory":"Directory","git.errReadRepo":"Cannot read repository","git.errLoad":"Load failed","git.noRepoInDir":"No git repository here yet — pick another directory, or run git init in this one.","git.outsideRoots":"This folder is outside the area handmux can open — only your home directory and /tmp are reachable. Move the repo under your home directory to browse it here.","git.errReadDir":"Cannot read this directory","git.commitDetail":"Commit details","git.diff":"Diff","git.bindRepo":"Bind repository","git.collapse":"Collapse","git.currentBranch":"Current branch","git.switchViewedBranch":"Switch viewed branch","git.switchBranch":"Switch branch","git.noBranches":"No branches","git.noRepoBound":'No repository bound — tap "+" at the top left to choose a directory.',"git.changes":"Changes","git.commits":"Commits","git.pullToLoadMore":"Pull to load more","git.pickerHint":"Choose a directory to auto-discover git repositories inside it","git.cleanTree":"Working tree clean","git.noCommits":"No commits","git.noDiff":"No diff","git.fontSmaller":"Decrease font size","git.fontLarger":"Increase font size","git.diffTruncated":"Diff too large, truncated","cmd.panel":"Command panel","cmd.title":"Commands","cmd.empty":"No commands yet — send one or save a favorite","cmd.favorites":"Favorites","cmd.scopeGlobal":"Global · all sessions","cmd.recent":"Recent","cmd.scopeSession":"This session only","cmd.favorite":"Favorite","cmd.itemConflict":"That shortcut already exists. Change its content or choose another list.","cmd.unfavorite":"Unfavorite","doc.home":"Recent","doc.read":"Read aloud","doc.pauseRead":"Pause reading","doc.resumeRead":"Resume reading","doc.stopRead":"Stop reading","doc.rate":"Speed","doc.fontSmaller":"Smaller font","doc.fontLarger":"Larger font","inbox.view.working":"Running","inbox.view.done":"Completed","inbox.view.needs":"Needs you","inbox.view.error":"Error","push.unsupported":"Push notifications require Chrome or Safari","push.iosAddToHome":'On iOS, first "Add to Home Screen", then open from the home-screen icon to enable',"a2hs.title":"Add handmux to your Home Screen","a2hs.lead":"Open it like an app — full-screen, no address bar. On iPhone it’s also how push reaches you the moment a pane needs you.","a2hs.install":"Install handmux","a2hs.ios1":"Tap the Share button (the ⬆︎ box) in Safari.","a2hs.ios2":"Tap “More”, or scroll down the list.","a2hs.ios3":"Choose “Add to Home Screen”, then “Add”.","a2hs.iosHint":"In Safari: Share → More → Add to Home Screen.","a2hs.iosOpenSafari":"You’re not in Safari. Open this page in Safari, then add it to your Home Screen — other iOS browsers can’t install it.","a2hs.androidManual":"Open your browser menu (⋮) and choose “Add to Home screen” or “Install app”.","a2hs.later":"Maybe later","push.permissionTimeout":"The system did not return the notification permission result. Check notification access for handmux or your browser in system settings, then try again.","push.permissionDenied":"Notification permission denied","push.swRegisterTimeout":"Registering the notification service timed out. Check your connection and try again.","push.swRegisterFailed":"Could not register the notification service: {reason}. Clear this site’s data, reopen it, and try again.","push.swTimeout":"The notification service was registered but did not activate. Clear this site’s data, reopen it, and try again.","push.unknownReason":"unknown reason","push.configTimeout":"Push configuration timed out. Check the connection to your handmux server and try again.","push.browserTimeout":"The browser push service did not respond. On Android Chrome, make sure Google Play services are available, then try again.","push.noVapid":"Push is not configured on the server (VAPID)","push.reportTimeout":"The subscription was created, but reporting it to the server timed out. Check the connection and try again.","push.subscriptionExpired":"Chrome returned an expired push subscription. It has been reset; tap Enable notifications again.","push.deliveryRejected":"The push service rejected the new subscription. Check the server log and try again.","push.subscribeFailed":"Failed to report subscription","push.sendFailed":"Send failed","api.loadFailed":"Load failed","api.uploadFailed":"Upload failed","upload.title":"Uploading","upload.processing":"Sent — receiving on the server…","api.uploadBadDir":"Cannot upload to this directory","api.uploadDuplicate":"A file with this name already exists","api.uploadTooLarge":"File too large (50MB limit)","api.uploadBadType":"Unsupported file type","time.secAgo":"{n}s ago","time.minAgo":"{n}m ago","time.hourAgo":"{n}h ago","time.dayAgo":"{n}d ago","time.expired":"Expired","time.minutes":"{n} min","settings.script_push":"Script push","settings.script_push_open":"How it works","settings.script_push_hint":"Let a script on your computer push a notification to your phone.","scriptPush.title":"Script push","scriptPush.intro":"Let scripts on your computer reuse handmux’s push channel: on the machine running handmux, one `handmux push` command sends a notification to your phone — handy when a build, CI run, or long task finishes, with no separate push service to wire up.","scriptPush.copied":"Copied","scriptPush.session_placeholder":"<session>","scriptPush.device_placeholder":"<device-key>","scriptPush.scope_all":"All subscribed devices (default)","scriptPush.scope_session":"Only devices in one session","scriptPush.scope_device":"Only this device","scriptPush.device_key_note":"The key above is this device’s — copy and run as-is.","scriptPush.device_need_enable":"Turn on push notifications above first to generate this device’s key.","scriptPush.opts_label":"Optional (append to any of the above)","scriptPush.opt_tag":"--tag <tag> — the same tag replaces the previous push instead of stacking.","scriptPush.opt_url":"--url <path> — opens this path when the notification is tapped.","scriptPush.reliability":"Heads-up: Web Push goes through the phone OS (FCM/APNs) and is best-effort — battery-saver, offline, or vendor policy can delay or drop it. It is not a guaranteed real-time channel. For delivery-critical alerts use a dedicated IM (WeChat / Telegram bot, etc.).","pushInbox.title":"Script Push History","pushInbox.empty":"No notifications yet","pushInbox.delete":"Delete","pushInbox.justNow":"just now","pushInbox.minutesAgo":"{n} min ago","pushInbox.hoursAgo":"{n} h ago","pushInbox.detailTitle":"Script Push","pushInbox.openUrl":"Open link","pushInbox.expired":"This message has expired","pushInbox.back":"Back","pushInbox.markAllRead":"Mark all read","pushInbox.unreadCount":"{n} unread","pushInbox.loadFailed":"Could not load script push history. Check the connection and retry.","pushInbox.deleteFailed":"Could not delete the script push. It was kept; please retry.","pushInbox.retry":"Retry","pushInbox.deliveryPending":"Sending","pushInbox.deliverySuccess":"Success","pushInbox.deliveryFailed":"Failed","pushInbox.deliveryReasonExpired":"subscription expired","pushInbox.deliveryReasonRateLimited":"push service rate limit","pushInbox.deliveryReasonUnavailable":"push service unavailable","pushInbox.deliveryReasonRejected":"push service rejected it","pushInbox.deliveryReasonNetwork":"network error","pushInbox.deliveryReasonNotConfigured":"push is not configured","pushInbox.deliveryReasonUnknown":"unknown reason","workspace.bootDetected":"Computer restart detected","workspace.tmuxDetected":"tmux restart detected","workspace.summary":"Last workspace · {sessions} sessions · saved {time}","workspace.restoreLast":"Restore last workspace","workspace.partialCard":"{failures} sessions still need attention","workspace.unknownTime":"unknown time","workspace.savedAt":"Saved {time}","workspace.topologySummary":"{sessions} sessions · {windows} windows · {panes} panes","workspace.planSummary":"Restore {restore} sessions; {already} already present","workspace.renameRule":"A -restored suffix is added only when a session with the same name already exists.","workspace.nonDestructive":"Current sessions will not be modified, renamed, or stopped.","workspace.progress":"Restoring {completed} / {total}…","workspace.progressDone":"Restored {completed} / {total}","workspace.complete":"Workspace restored.","workspace.completedSummary":"Restored: {sessions} sessions · {windows} windows · {panes} panes","workspace.rebindHint":"Restored sessions stay hidden until you choose which ones to bind to this phone.","workspace.rebind":"Bind restored sessions","workspace.sessionFailure":"{session}: {reason}","workspace.unknownSession":"Unknown session","workspace.restore":"Restore","workspace.ignore":"Ignore this backup","workspace.protectionTitle":"Workspace is not protected","workspace.protection.live-corrupt":"Workspace state copies are damaged. Check disk health and ~/.handmux permissions, then restart handmux.","workspace.protection.live-unavailable":"Workspace state cannot be read or written. Check free disk space and ~/.handmux permissions, then restart handmux.","workspace.protection.unknown":"Background snapshots are unavailable. Check the handmux log on your computer.","workspace.error.restore-interrupted":"restore was interrupted; retry this backup","workspace.error.checkpoint-not-found":"this backup is no longer available; refresh and choose another backup","workspace.error.storage-full":"workspace storage is full; free disk space and retry","workspace.error.permission-denied":"workspace storage is not writable; check permissions and retry","workspace.error.plan-failed":"the restore plan changed; refresh and retry","workspace.error.agent-unavailable":"the agent could not resume; open the restored shell and retry manually","workspace.error.tmux-unavailable":"tmux is unavailable; make sure tmux is running and retry","workspace.error.restore-failed":"the session was not restored; check the handmux log and retry","workspace.error.operation-not-found":"this restore operation is no longer available; retry the backup","workspace.sessionWarning":"{session}: {reason}","workspace.warning.cwd-fallback":"the working directory was unavailable; restored in the home directory","workspace.warning.layout-fallback":"the pane layout could not be fully restored; the default layout was kept","workspace.warning.agent-warning":"the agent did not resume automatically; the restored shell is still available","workspace.warning.live-reconcile-failed":"live workspace reconciliation failed; check the handmux log","workspace.warning.workspace-unavailable":"workspace storage is temporarily unavailable; check disk space and permissions","workspace.warning.restore-warning":"the restore completed with a warning that may need attention"},XO={"auth.welcome":"连接你的终端工作空间","auth.login":"登录","auth.connecting":"正在连接","auth.switchLink":"如何管理登录方式?","auth.switchTitle":"管理登录方式","auth.switchWarning":"登录需要输入Token,并完成设备授权。","auth.switchSetup":"要修改 Public URL,请在服务器上运行 handmux setup。直连模式可在“连接 → 直连 → 公网地址”填写自建反向隧道地址。","auth.switchRestart":"首次授权或丢失全部设备时,请在运行 handmux 的电脑上执行下方 CLI 命令。","auth.switchAfter":"设备保护和访问地址限制只通过 CLI 开关;设备和地址列表可在这里管理。","auth.copySetup":"复制查看命令","auth.copyRestart":"复制恢复命令","devices.title":"认证与安全","devices.protectionEnabled":"已开启保护","devices.protectionPartial":"部分开启保护","devices.protectionDisabled":"未开启保护","devices.insecureTitle":"安全保护未全部开启","devices.insecureHint":"设备保护或可信地址限制未开启。","devices.openSecurity":"去认证与安全","devices.listTitle":"已授权设备","devices.historyTitle":"历史设备","devices.historyLink":"历史设备({n})","devices.backToActive":"返回已授权设备","devices.trusted":"设备保护","devices.deviceProtectionSection":"可信设备保护","devices.deviceProtectionStatus":"保护状态","devices.originProtectionStatus":"限制状态","devices.policyEnabled":"已开启","devices.policyDisabled":"未开启","devices.deviceProtectionDisabledHint":"当前仅使用 Token,设备保护未启用;开启后要求可信设备授权。","devices.enableProtection":"开启设备保护","devices.enableOriginProtection":"开启地址限制","devices.enableConfirmTitle":"确认开启保护","devices.enableDeviceConfirm":"将当前浏览器登记为可信设备;其他设备访问需通过可信设备或电脑 CLI 授权。关闭只能在服务器上运行 handmux auth device off。","devices.enableOriginConfirm":"开启后只允许从已登记的访问地址进入。关闭只能在服务器上运行 handmux auth address off。","devices.enableConfirm":"确认开启","devices.originProtectionDisabledHint":"当前不限制访问地址。","devices.deviceProtectionInfo":"设备保护可在这里一键开启;关闭只能在服务器上运行 handmux auth device off。页面这里只管理设备。","devices.deviceProtectionEnabledHint":"用于限制未授权设备访问;关闭只能在服务器上运行 handmux auth device off。","devices.originProtectionInfo":"访问地址保护只能通过 handmux auth address on/off 切换,页面这里只管理地址。","devices.originProtectionEnabledHint":"用于限制未登记地址访问;关闭只能在服务器上运行 handmux auth address off。","devices.token":"Token","devices.addSelf":"将本机添加为可信设备","devices.addSelfTitle":"添加本机","devices.addSelfAddress":"登记地址:{origin}","devices.cookieRequired":"浏览器未保存可信设备登录凭据,请允许 Cookie 后重试。","devices.trustedOrigin":"可信访问地址","devices.accessSection":"可信地址保护","devices.publicUrlLabel":"主域名","devices.publicUrlInfo":"由 setup → 连接 → 当前连接方式 → 公网地址设置;网页这里只读显示。","devices.previewDomainLabel":"预览域名","devices.previewDomainInfo":"由 setup → Web preview → 网页预览器代理域名设置;系统会自动允许它的动态子域名。","devices.originConfigured":"来自 setup 配置,不能在此修改","devices.originBuiltIn":"系统自动允许","devices.originUnset":"未设置","devices.originActive":"已生效","devices.originPending":"未配置;外部地址请用 CLI 登记,或通过设备授权自动加入","devices.originHint":"Public URL 来自 Setup,网页这里只读。没有固定公网入口时可以留空;本机和局域网直连仍可用,外部地址需加入下方列表或使用动态预览域名。","devices.originCommands":"可信访问地址命令","devices.originSetupCommandLabel":"配置","devices.extraOriginsTitle":"信任域名","devices.trustedOriginLabel":"信任域名 {n}","devices.extraOriginsHint":"由设备授权自动登记,也可用 CLI 管理。支持 https://*.example.com 形式的通配符。","devices.extraOriginInput":"额外信任域名","devices.extraOriginAdd":"添加域名","devices.removeOriginTitle":"删除信任域名","devices.removeOriginImpact":"以下设备将无法通过此地址访问:","devices.removeOriginCurrentImpact":"包含本机:删除后本机也无法访问,需要重新授权。","devices.removeOriginNoImpact":"当前没有已生效设备使用此地址。确定删除吗?","devices.removeOriginConfirm":"删除","devices.invalidOrigin":"请输入完整的 http(s) 地址,例如 https://*.example.com。通配符只能放在最左侧子域名。","devices.originLimit":"额外信任域名已达到上限,请先删除一个。","devices.originMismatch":"当前地址不在允许的访问入口中。请从主访问地址、动态预览域名或已登记地址打开 handmux;需要登记时运行 handmux auth address add <origin>。","devices.addSelfOrigin":"授权完成后会把 {origin} 加入可信访问入口。","devices.cliOnly":"如需修改可信访问地址,请在服务器上使用 handmux CLI。","devices.current":"当前设备","devices.add":"添加设备","devices.authorizeOther":"为其他设备授权","devices.history":"历史设备({n})","devices.activeTab":"有效设备","devices.historyTab":"历史设备","devices.activeStatus":"可访问","devices.detailInfo":"设备信息","devices.deviceInfo":"设备","devices.status":"状态","devices.detailActions":"设备操作","devices.noActive":"暂无有效设备。","devices.activeDevices":"‹ 有效设备","devices.noHistory":"暂无历史设备。","devices.name":"设备名称","devices.expire":"授权有效期","devices.keep":"保持当前期限","devices.custom":"自定义","devices.never":"不限期","devices.customDuration":"正整数加 m / h / d,或 never","devices.keepHint":"保持当前期限不会延长授权。","devices.expireFromSave":"所选时长从本次保存成功时开始计算。","devices.id":"设备 ID","devices.copyId":"复制 ID","devices.browser":"浏览器","devices.added":"添加时间","devices.lastAccess":"最后访问时间","devices.expiresAt":"到期时间","devices.revoked":"已解除绑定","devices.expired":"已过期","devices.daysRemaining":"剩余 {n} 天","devices.hoursRemaining":"剩余 {n} 小时","devices.minutesRemaining":"剩余 {n} 分钟","devices.logout":"退出当前设备","devices.revoke":"踢出设备","devices.revokeDescription":"“{name}”将立即失去访问权限,再次登录需要重新配对。已运行的终端任务继续执行。","devices.conflict":"设备已被其他操作修改。请刷新详情,再重新应用你的修改。","devices.refreshDetails":"重新加载最新信息","devices.inactive":"设备已过期或解除绑定,请重新配对恢复访问。","devices.sessionInvalid":"当前浏览器授权已失效,请刷新 handmux 后重新配对。","devices.invalidName":"设备名称需要 1–80 个字符,不能包含控制字符。","devices.nameTaken":"设备名称已被使用,请换一个名称。","devices.saved":"已保存。","devices.invalidExpire":"请输入正整数时长,例如 1h、7d,或 never。","devices.expiryCliOnly":"授权有效期只能在运行 handmux 的服务器上使用 CLI 修改。","devices.invalidCode":"请输入新浏览器当前显示的 6 位校验码,过期或已使用的校验码不能重复使用。","devices.pairingGone":"配对已取消或过期,请在新浏览器重新申请校验码。","devices.requestError":"无法确认操作结果,请检查网络后重试;尚未确认修改成功。","devices.code":"一次性校验码","devices.codeHint":"输入新设备显示的 6 位验证码,输入完成后会自动验证。","devices.verifyingCode":"正在验证…","devices.configureTitle":"设置新设备","devices.approvalOrigin":"访问地址","devices.claim":"确认配对","devices.complete":"完成添加","devices.newCode":"输入新校验码","auth.methodLabel":"授权方法","auth.webMethod":"已有可信设备","auth.webInstructions":"在已经登录同一个 handmux 实例的手机或电脑上打开:","auth.webPath":"设置 → 认证与安全 → 通过一次性校验码添加设备","auth.webNext":"输入上方校验码并确认配对,再填写新设备的名称和有效期,点击“完成添加”。本页面会自动登录。","auth.webFallback":"没有可用的可信设备?再切换到“电脑 CLI”。","auth.title":"申请设备授权","auth.waiting":"等待授权","auth.deviceRequired":"需要设备授权","auth.preparingCode":"正在准备验证码…","auth.deviceAuthorizationHint":"输入 Token 后,还需要完成一次设备授权。","auth.verificationCode":"授权验证码","auth.authorizeWithDevice":"在已有授权设备的「认证与安全」中输入此验证码。","auth.authorizeWithCli":"在运行 handmux 的电脑上执行","auth.cliAfterCode":"按提示输入这个验证码。","auth.chooseOneMethod":"任选一种方式完成授权","auth.cliMethodTitle":"电脑 CLI 授权","auth.deviceMethodTitle":"其他设备授权","auth.paired":"配对成功","auth.pending":"已确认,正在完成授权…","auth.finishCli":"请在终端完成设备设置。","auth.finishWeb":"请在已授权设备上完成设备设置。","auth.setupRemaining":"剩余 {seconds} 秒完成设置","auth.codeRemaining":"剩余 {seconds} 秒","auth.codeExpired":"已过期,请重新获取","auth.expired":"验证码已过期,请重新生成。","auth.canceled":"授权已取消,请重新生成验证码。","auth.request":"申请设备授权","auth.requestNewCode":"重新生成验证码","auth.refreshCode":"刷新","auth.cancelPairing":"取消配对","auth.copyCode":"复制校验码","auth.copyCommand":"复制命令","auth.copied":"已复制","auth.manualCopy":"已选中文本,请长按或按 Ctrl/Cmd+C 复制。","auth.cliMethod":"电脑 CLI","auth.cliInstructions":"在运行此 handmux 实例的电脑上,使用同一 OS 用户执行下方命令;也可以先通过独立 SSH 连接。命令会进入交互式授权流程。","auth.cliNext":"随后输入本页显示的 6 位校验码,再填写设备名称和有效期;保存完成后本页面会自动登录。自动化脚本请使用 --code、--name 和 --expire flags。","auth.browserScope":"授权保存在当前浏览器和当前访问地址中。更换地址后,需要重新配对。","auth.antiPhishing":"仅授权你本人正在添加的浏览器,不要输入他人发来的校验码。","auth.httpWarning":"为更好地保护敏感访问,尽可能使用 HTTPS 或可信的加密网络。","auth.tokenWarning":"Token 始终需要;开启设备保护后,还需完成设备授权。","auth.dualRequirement":"Token 始终需要;开启设备保护后,还需完成设备授权。","auth.tokenRequired":"请先输入当前 Token,再申请设备授权。","auth.tokenInvalid":"Token 不正确,请重新输入后再继续。","auth.connectionError":"暂时无法确认授权状态,请检查网络和 handmux 是否运行后重试;不会因此取消授权。","auth.originRejected":"当前地址未在可信访问入口中。","auth.originRejectedTitle":"地址未受信任","auth.originRejectedAddress":"当前地址 {origin} 非可信访问入口","auth.originRejectedOpenLabel":"从可信入口打开","auth.originRejectedOpenHint":"使用主访问地址、动态域名或已授权的访问域名打开此页面","auth.originRejectedAuthorizeLabel":"重新授权","auth.originRejectedAuthorizeHint":"使用另一台可信设备或电脑 CLI 授权当前访问地址","auth.originRejectedAuthorizeButton":"申请访问权限","auth.originRejectedRetry":"重新检查","auth.retry":"重试","auth.rateLimit":"授权尝试过于频繁,请稍等一分钟后再申请校验码。","auth.logoutTitle":"解除绑定并退出","auth.logoutDescription":"当前浏览器将立即失去访问权限,再次登录需重新配对。已运行的终端任务会继续。","auth.logoutError":"未能确认解除绑定,请检查连接后重试;当前设备可能仍然有效。","terminal.disconnected":"连接断开,重连中…","terminal.paneMissing":"窗格已关闭,请切换到其他窗格。","terminal.transport_live":"实时","terminal.transport_snapshot":"快照","terminal.transport_detail_title":"终端传输状态","terminal.transport_detail_configured":"设置模式","terminal.transport_detail_current":"当前模式","terminal.transport_detail_connection":"连接状态","terminal.transport_detail_manual":"你已手动选择快照拉取,不会自动切换。","terminal.transport_detail_live":"终端正在正常接收实时推送。","terminal.transport_detail_fallback":"实时推送不稳定,已自动降级为快照拉取。","terminal.transport_detail_unavailable":"实时通道无法建立,请检查反向代理是否支持 WebSocket。","terminal.transport_detail_waiting":"正在等待连接稳定,随后尝试恢复实时推送。","terminal.transport_detail_retry":"预计 {seconds} 秒后尝试恢复实时推送。","terminal.connection_connecting":"检测中","terminal.connection_good":"良好","terminal.connection_degraded":"一般","terminal.connection_poor":"较差","common.save":"保存","common.cancel":"取消","common.confirm":"确认","common.ok":"确定","common.close":"关闭","common.delete":"删除","common.undo":"撤销","common.copy":"复制","common.rename":"重命名","common.create":"新建","common.back":"返回","common.open":"打开","common.loading":"加载中…","common.done":"完成","common.retry":"重试","common.continue":"继续","conversationCopy.line":"整行","conversationCopy.paragraph":"整段","app.browser":"网页预览器","browser.openTabs":"打开的网页预览器标签页","browser.history":"最近访问","browser.closeTab":"关闭 {title}","browser.newTab":"新建标签页","browser.minimize":"收起","browser.back":"后退","browser.forward":"前进","browser.address":"地址","browser.addressPlaceholder":"输入网址或端口","browser.addressOrDirectoryPlaceholder":"输入网址,或选择目录","browser.refresh":"刷新","browser.stop":"停止加载","browser.viewMode":"页面宽度","browser.narrowWidth":"窄屏","browser.wideWidth":"宽屏","browser.closeTiming":"后台页签关闭","browser.minutes":"{value} 分钟","browser.neverClose":"永不关闭","browser.clearHistory":"清除","browser.emptyHistory":"还没有最近访问","browser.loadFailed":"无法加载此网页,请检查地址后重试。","browser.retry":"重试","browser.consentTitle":"网页预览器","browser.consentBody":"Handmux 会把网页嵌入当前窗口。它不是真正的浏览器,适合预览开发服务、localhost、内网和允许嵌入的网站;也可从 Home 选择电脑上的静态目录。","browser.consentComputer":"连接方式:手机直连使用手机网络。经电脑代理时,请求由电脑发起,可以访问电脑所在的内网和 localhost,但不会将它们公开。","browser.consentPrivate":"登录状态:直连与代理不共享 Cookie 和登录状态;代理会话也按当前设备隔离。","browser.consentLimits":"兼容限制:直连可能被网站的 iframe 或 CSP 策略阻止,而且 Handmux 未必能判断原因。电脑代理会转发并改写网页,也不保证兼容所有网站。需要完整浏览能力时,请用 Safari、Chrome 或系统浏览器打开。","browser.consentIdle":"后台标签页:默认在 10 分钟后关闭。直连网站的 Cookie 仍保留在手机浏览器中。","browser.about":"关于网页预览器","browser.acknowledge":"好的","browser.directMode":"手机直连","browser.proxyMode":"经电脑代理","browser.directBadge":"直连","browser.proxyBadge":"代理","browser.staticBadge":"静态","browser.chooseDirectory":"选择目录","browser.staticOpening":"正在打开目录…","browser.directoryPickerHint":"选择包含网页文件的目录。","browser.switchMode":"切换浏览模式","browser.menu":"网页预览器菜单","browser.connectionMode":"连接方式","browser.pageWidth":"页面宽度","browser.requestSiteVersion":"向网站请求","browser.mobileSite":"手机版","browser.desktopSite":"电脑版","browser.zoomPage":"缩放网页","browser.resetZoom":"重置网页缩放","browser.proxyLogin":"代理登录","browser.proxyLoginHelpLabel":"代理登录说明","browser.proxyLoginHelp":"是否将代理 Cookie 加密保存在运行 Handmux 的电脑上,以便重启后保持登录状态。","browser.siteProxyCookie":"本站代理 Cookie","browser.siteCookieHelpLabel":"本站代理 Cookie 说明","browser.siteCookieHelp":"这里只清理当前设备中与本站真实网址匹配的代理 Cookie。父域 Cookie 可能让相关内网站点一起退出,手机直连 Cookie 不受影响。","browser.openMode":"选择打开方式","browser.historyMore":"更多打开方式","browser.historyActions":"更多操作","browser.proxyLimitHint":"电脑代理会转发并改写网页,不保证兼容所有网站。","browser.proxyUnavailable":"请在电脑终端运行 handmux setup,选择“网页预览器”配置代理域名;配置前只能使用手机直连。","browser.urlInvalid":"请输入有效的 HTTP 或 HTTPS 地址。","browser.tryProxy":"改用电脑代理","browser.openExternal":"用系统浏览器打开","browser.clearSiteLogin":"清理本站代理 Cookie","browser.clearAllLogin":"清理全部代理 Cookie","browser.clearSiteLoginConfirm":"清理当前设备的本站代理登录状态?父域 Cookie 也可能影响相关内网系统。","browser.clearAllLoginConfirm":"清理当前设备的全部代理登录状态?手机直连的登录状态不受影响。","browser.deleteHistoryEntry":"删除此记录","browser.profileSaveFailed":"无法保存代理登录设置,请检查服务器连接后重试。","browser.profileClearFailed":"清理未完全成功,请检查服务器连接和存储权限后重试。","browser.profileSyncFailed":"无法同步代理登录设置。请重试,或改用手机直连。","browser.profileRecoveryWarning":"无法恢复已保存的代理登录数据,当前设备的代理登录状态已重置。","browser.retention1":"1 天","browser.retention7":"7 天","browser.retention30":"30 天","browser.retentionNotSaved":"不保存","browser.retentionNever":"长期保存","settings.browserPersistLogin":"在电脑上持久化保存代理 Cookie","settings.browserPersistLoginHint":"只保存在当前设备。关闭后,当前标签页和登录状态仍会保留,直到清理或过期。","settings.browserRetention":"代理登录保留","settings.browserDisablePersistConfirm":"停止保存当前设备后续的代理登录变化?当前标签页和登录状态会继续保留。","token.title":"登录 handmux","token.placeholder":"输入 Token","settings.language":"语言 Language","settings.browserDefaultMode":"网页默认打开方式","settings.browserDefaultModeHint":"用于地址栏新页签,以及没有保存打开方式的历史记录。","settings.browserEnabled":"网页预览器","settings.browserEnabledHint":"标签页仅属于当前设备。关闭后会关闭全部标签页,但保留历史记录。","home.empty":"还没有打开过文件","home.emptyHint":"切到「新增」去挑一个","home.remove":"移除","drawer.title":"会话","drawer.empty":"还没有绑定会话","drawer.unbind":"解绑","drawer.bind":"绑定会话","drawer.logout":"退出登录","windowbar.newWindow":"新建窗口","rename.new_name":"新名称","rename.name_rule":"只能用字母、数字、横线(≤16)","rename.failed":"重命名失败,请重试","rename.saving":"保存中…","newwindow.title":"新建窗口","newwindow.window_name":"窗口名称(可选)","newwindow.name_placeholder":"留空自动命名 · 字母/数字/横线 ≤16","newwindow.name_rule":"只能用字母、数字、横线(≤16)","newwindow.start_dir":"起始目录","newwindow.session_dir_named":"{dir}(会话目录)","newwindow.session_dir_default":"会话目录(默认)","newwindow.choose":"选择","newwindow.reset_to_session_dir":"重置为会话目录","newwindow.creating":"新建中…","startup.label":"启动命令(可选)","startup.aria":"启动命令","startup.preset_shell":"空 shell(默认)","startup.preset_claude":"claude(启动 Claude Code)","startup.preset_claude_continue":"claude -c(接着上次会话)","startup.preset_codex":"codex(启动 Codex CLI)","startup.custom":"自定义…","startup.custom_placeholder":'例如 claude "修复登录bug"',"bind.title":"绑定会话","bind.sessionName":"会话名称","bind.pickSession":"选择要绑定的会话","bind.newSession":"+ 新建会话","bind.modeNew":"新建会话","bind.modeExisting":"已有会话","bind.alreadyExists":"该会话已存在","bind.bind":"绑定","bind.checking":"校验中…","bind.createAndOpen":"新建并打开","bind.creating":"新建中…","bind.createHint":"会话「{name}」不存在,点「新建并打开」创建","bind.alreadyBound":"已绑定该会话","bind.createFailed":"新建失败,请重试","bind.invalidName":"只能用字母、数字、横线(≤16)","bind.desktopHint":"这里的会话(包括手机新建的),电脑上一条命令即可接管:handmux open <会话名>","bind.checkFailed":"校验失败,请重试","bind.startDir":"起始目录","bind.homeDirDefault":"主目录(默认)","bind.choose":"选择","bind.reset":"重置","actionsheet.confirmAgain":"确认?再点一次","dirpicker.title":"选择目录","inbox.title":"收件箱","inbox.working":"进行中","inbox.done":"已完成","inbox.needs":"需要你","inbox.error":"出错","inbox.clearDone":"清除结果","inbox.empty":"暂无面板状态","inbox.reconnecting":"正在重新连接收件箱…","inbox.enableTitle":"开启 Claude Code 状态与通知","inbox.enableHint":"Claude Code 收件箱需要 Agent hooks。Codex CLI 请使用 Handmux 托管模式。","inbox.enableBtn":"开启","inbox.enabling":"开启中…","inbox.enableFailed":"开启失败 —— 看看服务端日志。","drawer.orphans.title":"{n} 个未接管会话","drawer.orphans.hint":"接管即可远程操控","inbox.orphans.takeover":"接管","inbox.orphans.noSession":"无可续接的历史","inbox.orphans.busy":"运行中","inbox.orphans.idle":"空闲","inbox.orphans.working":"接管中…","inbox.orphans.failed":"接管失败","inbox.orphans.targetLabel":"接管到","inbox.orphans.targetNew":"新建会话","inbox.orphans.nameLabel":"会话名称","inbox.orphans.namePlaceholder":"会话名","inbox.orphans.killTitle":"接管后原来的进程","inbox.orphans.killEnd":"结束","inbox.orphans.killKeep":"保留","inbox.orphans.recommended":"推荐","inbox.orphans.killWhy":"同一个会话如果电脑和手机同时在写,历史记录会错乱。结束原进程后由手机这边独占,更稳妥。","inbox.orphans.reopenPre":"想回电脑上继续?在电脑终端运行:","idea.title":"想法","idea.editPlaceholder":"编辑想法…","idea.addPlaceholder":"记一条想法…","idea.add":"添加","idea.empty":"还没有想法,记一条吧","idea.dragSort":"拖动排序","idea.fillInput":"填入输入框","idea.send":"发送","doclink.title":"打开文件","localurl.title":"打开网站","localurl.open":"在浏览器中打开","localurl.notListening":"端口 :{port} 没有服务在监听。","localurl.badProtocol":"该链接不是可代理的 HTTP 或 HTTPS 地址。","localurl.network":"连接 handmux 服务失败,请检查网络后重试。","localurl.failed":"无法打开该网站,请检查地址后重试。","changelog.title":"新功能","preview.static":"静态预览","preview.tabs":"打开的预览","preview.remainTitle":"剩余有效期 — 点击续期 / 停止","preview.toPcView":"切换到电脑视图","preview.toMobileView":"切换到手机视图","preview.pcView":"电脑视图","preview.mobileView":"手机视图","preview.refresh":"刷新","preview.minimize":"收起","preview.ttlDialog":"预览有效期","preview.renew":"续期(重置为 1 小时)","preview.stop":"停止预览","preview.iframeTitle":"预览","preview.zoomOut":"缩小","preview.zoomIn":"放大","imageviewer.loadFailed":"图片加载失败","imageviewer.saved":"已保存,可在相册/图库或「下载」中查看","imageviewer.shareUnsupported":"图片分享需要 Chrome 或 Safari 浏览器","imageviewer.zoomOut":"缩小","imageviewer.zoomIn":"放大","imageviewer.imageTitle":"图片","imageviewer.saveImage":"保存图片","imageviewer.shareImage":"分享图片","mic.stop":"停止语音输入","mic.start":"语音输入","mic.recognizing":"正在识别语音","mic.error.tencentPermission":"腾讯云拒绝了识别:请为当前 SecretId 授予 asr:SentenceRecognition 权限后重试。","mic.error.tencentCredentials":"腾讯云凭据无效,请在 handmux setup 中检查 AppId、SecretId 和 SecretKey。","mic.error.browserPermission":"没有麦克风权限,请在浏览器的网站设置中允许麦克风后重试。","mic.error.device":"无法使用麦克风,请检查设备是否存在或被其他应用占用。","mic.error.secureContext":"当前地址不能使用麦克风,请改用 HTTPS 或 localhost 打开 Handmux。","mic.error.tooLong":"录音过长,请缩短后重试。","mic.error.notSelected":"当前语音模式未生效,请重启 Handmux 后重试。","mic.error.noSpeech":"未识别到语音,请重试。","mic.error.network":"语音服务连接失败,请检查网络后重试。","mic.error.provider":"语音服务拒绝了请求:{reason}","mic.error.generic":"语音输入失败,请重试。","dock.send":"发送","dock.send.hint":"点发送 · 长按填入","dock.phrases":"常用语","dock.attach":"上传","dock.history":"历史","dock.kbdShow":"展开键盘","dock.kbdHide":"收起键盘","history.empty":"还没有发送记录","history.scope":"仅当前窗口的记录","dock.input.placeholder":"说点什么…","dock.input.enterDraft":"按 Shift + Enter 进入草稿模式","dock.input.exitDraft":"按 Esc 回到终端模式 · Shift + Enter 换行","dock.command.placeholder":"输入命令 · 回车执行","dock.mode.agent":"对话","dock.mode.toggle":"切换输入模式","dock.mode.command":"命令模式","dock.mode.chat":"聊天模式","fav.title":"常用","fav.add":"添加","fav.addPlaceholder":"加一条常用…","cmd.editTitle":"常用命令","cmd.global":"全局","cmd.window":"当前窗口","cmd.withEnter":"直接发送","cmd.configPresets":"配置预置","cmd.removeDevice":"从本机移除","cmd.removedDevice":"已从本机移除","cmd.addPlaceholder":"加一条命令…","cmd.tabCmd":"命令","cmd.tabKey":"按键","cmd.addTo":"添加到","cmd.addTitle":"添加","cmd.added":"已添加","cmd.editItem":"编辑","cmd.sticky":"粘滞键","cmd.stickyNone":"无","cmd.baseKey":"基键","cmd.pickKey":"选择按键","cmd.moveUp":"上移","cmd.moveDown":"下移","chat.editTitle":"常用消息","chat.composer.placeholder":"和 Agent 对话…","chat.historyPulling":"拉取中","agentConversation.empty":"开始和这个 Agent 对话吧。","agentConversation.unavailable":"无法连接对话","agentConversation.reconnecting":"正在重新连接实时对话…","agentConversation.reloadRequired":"Pi 对话组件已更新。请切换到终端运行 /reload,然后返回对话。","agentConversation.loadOlder":"加载更早的消息","agentConversation.loadOlderFailed":"更早的消息没有加载成功,请重试。","agentConversation.reasoning":"思考摘要","agentConversation.toolResult":"工具结果","agentConversation.diff":"变更","agentConversation.attachment":"附件","agentConversation.attachmentFailed":"附件下载失败,请重试。","agentConversation.truncated":"部分内容已截断。","agentConversation.interactionTerminal":"这个操作需要在终端中完成。","agentConversation.interactionUnavailable":"暂时无法在对话中处理这个请求","agentConversation.interactionCommandApproval":"允许执行这个命令吗?","agentConversation.interactionFileApproval":"允许修改文件吗?","agentConversation.interactionPermissionApproval":"允许授予所请求的权限吗?","agentConversation.interactionInputRequest":"需要你的补充信息","agentConversation.interactionReason":"原因","agentConversation.interactionCommand":"命令","agentConversation.interactionWorkingDirectory":"工作目录","agentConversation.interactionContext":"上下文","agentConversation.interactionOther":"输入其他回答","agentConversation.interactionPlaceholder":"输入回答","agentConversation.openTerminal":"打开终端","chat.stop":"停止","chat.stopTitle":"停止当前任务?","chat.stopBody":"当前正在执行的回合会被中断。","chat.config.open":"设置模型、服务等级和思考强度","chat.config.title":"模型设置","chat.config.model":"模型","chat.config.effort":"思考强度","chat.config.fast":"Fast","chat.config.fastHint":"使用当前模型提供的快速服务","chat.config.loading":"正在获取可用模型…","chat.config.empty":"没有可用模型","chat.config.chooseModel":"先选择一个可用模型","chat.config.loadFailed":"无法获取模型列表","chat.config.refresh":"刷新模型列表","chat.config.saveFailed":"设置没有保存成功","chat.config.nextTurn":"当前回复不变,下条消息生效","chat.goal.title":"任务目标","chat.goal.objective":"目标内容","chat.goal.placeholder":"描述一个需要持续推进的目标","chat.goal.loading":"正在读取当前目标…","chat.goal.loadFailed":"无法读取当前目标","chat.goal.saveFailed":"目标没有保存成功","chat.goal.clearFailed":"目标没有清除成功","chat.goal.tooLong":"任务目标最多 4,000 个字符","chat.goal.created":"任务目标已设置","chat.goal.updated":"任务目标已更新","chat.goal.paused":"任务目标已暂停","chat.goal.resumed":"任务目标已继续","chat.goal.restarted":"任务目标已重新开始","chat.goal.cleared":"任务目标已清除","chat.goal.edit":"编辑","chat.goal.pause":"暂停","chat.goal.resume":"继续","chat.goal.restart":"重新开始","chat.goal.clear":"清除","chat.goal.clearConfirmTitle":"清除任务目标?","chat.goal.clearConfirmBody":"当前任务目标会被删除,Codex 将停止继续跟踪;对话中的历史卡片仍会保留。","chat.goal.statusActive":"进行中","chat.goal.statusPaused":"已暂停","chat.goal.statusBlocked":"已阻塞","chat.goal.statusComplete":"已完成","chat.goal.statusUsageLimited":"用量受限","chat.goal.statusBudgetLimited":"预算受限","chat.goal.eventSet":"已设置目标","chat.goal.eventRestarted":"已重新开始目标","chat.goal.eventComplete":"目标已完成","chat.goal.eventBlocked":"目标已阻塞","chat.goal.eventUsageLimited":"目标因用量受限结束","chat.goal.eventBudgetLimited":"目标因预算受限结束","chat.goal.tokens":"Token {value}","chat.goal.elapsed":"耗时 {value} 秒","chat.plan.currentTitle":"当前任务","chat.plan.historyTitle":"本轮任务","chat.plan.working":"正在:{step}","chat.plan.waiting":"等待确认:{step}","chat.plan.finalizing":"正在整理结果","chat.plan.complete":"已完成","chat.plan.incomplete":"未完成","chat.plan.status.pending":"待处理","chat.plan.status.inProgress":"进行中","chat.plan.status.completed":"已完成","chat.context.aria":"上下文占用 {percent}%","chat.context.unavailableAria":"上下文状态,用量暂不可用","chat.context.title":"上下文用量","chat.context.percent":"上下文长度用量","chat.context.used":"当前 Token","chat.context.total":"模型总 Token","chat.context.usedTotal":"已用 / 总量","chat.status.aria":"会话状态,上下文占用 {percent}%","chat.status.title":"会话状态","chat.status.idle":"空闲","chat.status.working":"处理中","chat.status.waitingApproval":"等待审批","chat.status.waitingInput":"等待回答","chat.status.compacting":"压缩中","chat.compacting.live":"正在压缩上下文","chat.status.directory":"目录","chat.status.worktree":"Worktree","chat.status.branch":"分支","chat.status.access":"访问权限","chat.status.permissionMode":"权限模式","chat.status.sessionId":"会话 ID","chat.status.copyDirectory":"复制目录","chat.status.copyWorktree":"复制 Worktree 路径","chat.status.copySession":"复制会话 ID","chat.status.copied":"已复制","chat.status.sandboxReadOnly":"只读","chat.status.sandboxWorkspace":"可修改工作区","chat.status.sandboxFull":"完全访问","chat.permissionMode.default":"默认","chat.permissionMode.autoReview":"自动","chat.permissionMode.fullAccess":"完全","chat.permissionMode.custom":"自定义","chat.permissionMode.title":"权限模式","chat.permissionMode.open":"设置权限模式,当前为{value}","chat.permissionMode.defaultHint":"可读写当前工作区并运行命令;联网或访问其他位置时会询问你。","chat.permissionMode.autoReviewHint":"权限与“默认”相同;需要额外权限时,由 Codex 自动判断批准或拒绝。","chat.permissionMode.fullAccessHint":"可访问工作区外和网络且不会询问;仅在完全信任当前任务时使用。","chat.permissionMode.nextTurn":"修改从下一条消息生效","chat.permissionMode.saved":"权限模式已更新,下条消息生效","chat.permissionMode.saveFailed":"权限模式没有保存成功","chat.interrupted":"你终止了这次回复","chat.compacted":"上下文已压缩","chat.compaction.viewDetails":"查看详情","chat.compaction.title":"上下文压缩","chat.compaction.complete":"完成","chat.compaction.summary":"Agent 保留的摘要","chat.compaction.unavailable":"这次压缩没有提供可查看的摘要。","chat.compaction.truncated":"摘要过长,当前只显示已安全保留的部分。","chat.scroll.latest":"回到最新","chat.scroll.reloadLatest":"↓ 回到最新","chat.scroll.answer":"↓ 查看最新回答","chat.scroll.bottom":"↓ 回到底部","chat.slash.unsupported":"这个命令暂不支持在对话视图中使用","chat.session.unboundTitle":"无法确认这个 Codex 对话","chat.session.unboundHint":"Codex 会话仍在启动,确认到准确会话后会自动显示。","chat.session.openTerminal":"前往终端","chat.session.notManaged":"请先在终端以托管模式重新启动 Codex","chat.session.unmanagedTitle":"此 Codex 会话未托管","chat.session.unmanagedHint":"请在终端以托管模式重新启动后再打开对话。","chat.session.connectionHint":"Codex App Server 暂时不可用,请确认 Codex 仍在运行后重试。","chat.managedGuide.title":"接入 Codex 对话","chat.managedGuide.hint":"Handmux 可以在当前窗格恢复原会话,并切换为可靠的托管对话。","chat.managedGuide.start":"开始托管","chat.managedGuide.submitting":"正在启动…","chat.managedGuide.confirmTitle":"开始托管?","chat.managedGuide.confirmHint":"当前 Codex 进程会结束,正在执行的任务也会停止。恢复过程中可能需要你前往终端,人工处理信任或其他确认。","chat.managedGuide.confirmAction":"结束并开始托管","chat.managedGuide.startingTitle":"正在启动托管","chat.managedGuide.startingHint":"正在恢复原会话,成功后会自动进入对话。","chat.managedGuide.terminalHint":"启动尚未完成,Codex 可能正在终端等待信任或其他确认。","chat.managedGuide.timeoutTitle":"托管仍未就绪","chat.managedGuide.timeoutHint":"已经等待 30 秒,Codex 可能需要你前往终端人工确认。当前页面不会自动切换。","chat.managedGuide.manualTitle":"需要从终端继续","chat.managedGuide.manualHint":"Codex 没有正常退出或返回可确认的恢复信息。请前往终端查看当前状态。","chat.managedGuide.goneTitle":"这个 Codex 已经变化","chat.managedGuide.goneHint":"为避免结束错误的进程,Handmux 没有继续操作。请前往终端查看当前状态。","chat.managedGuide.unavailableTitle":"无法安全确认当前 Codex 会话","chat.managedGuide.unavailableHint":"请重试,或前往终端继续。","chat.managedGuide.failedHint":"托管启动未能完成。你可以重试,或前往终端查看当前状态。","chat.managedGuide.recoveryHint":"原会话已经确认;如果自动恢复失败,请在终端运行:","chat.managedGuide.copyRecovery":"复制恢复命令","chat.managedGuide.recoveryTitle":"继续恢复 Codex 对话","chat.managedGuide.recoveryReadyHint":"上次接管在恢复前中断了。可以在当前窗格安全地继续。","chat.managedGuide.recoveryManualHint":"无法确认当前窗格仍可安全自动恢复,请复制命令或前往终端。","chat.managedGuide.recoveryStaleTitle":"原窗格已经变化","chat.managedGuide.recoveryStaleHint":"为避免把命令发送到错误的窗格,这里只提供复制。","chat.managedGuide.retryRecovery":"继续恢复","chat.approval.request":"Codex 请求确认","chat.approval.file":"允许修改文件?","chat.approval.command":"允许运行这条命令?","chat.approval.permissions":"允许 Codex 获取额外权限?","chat.approval.accept":"允许一次","chat.approval.acceptSession":"本次会话始终允许","chat.approval.acceptRule":"允许并记住“{rule}”","chat.approval.allowHost":"始终允许访问 {host}","chat.approval.denyHost":"始终拒绝访问 {host}","chat.approval.decline":"拒绝","chat.approval.cancel":"拒绝并停止","chat.approval.failed":"审批没有提交成功","chat.input.request":"Codex 需要你的回答","chat.input.step":"第 {current}/{total} 题","chat.input.other":"其他回答","chat.input.placeholder":"输入回答","chat.input.submit":"提交回答","chat.input.failed":"回答没有提交成功","chat.sendFailed":"消息没有发送成功","chat.terminalDraftConflict":"终端有未确认的草稿,请先在终端处理后重试","chat.queue.terminalDraftConflict":"终端有未确认的草稿,请先在终端处理,再编辑此消息重试","chat.sendUnknown":"无法确认消息是否送达,请检查对话后再重试","chat.stopFailed":"没有停止成功,请稍后重试","chat.queue.title":"排队消息","chat.queue.hint":"当前回合结束后自动逐条发送","chat.queue.steer":"立刻引导","chat.queue.edit":"编辑排队消息","chat.queue.editTitle":"编辑排队消息","chat.queue.editPlaceholder":"输入排队消息","chat.queue.remove":"删除排队消息","chat.queue.removeTitle":"删除这条排队消息?","chat.queue.removeBody":"删除后无法恢复。","chat.queue.actionFailed":"没有处理成功,请稍后重试","chat.queue.editExpired":"编辑已过期,请关闭后重新编辑。","chat.queue.editConflict":"这条排队消息已在其他页面更新。草稿已保留,请关闭后确认最新内容。","chat.queue.providerRejected":"未发送,可编辑后重试或删除","chat.queue.unknownDelivery":"发送状态待确认,不会自动重发","chat.controls.actionFailed":"设置没有更新成功,请重试。","chat.config.serviceTier":"服务等级","chat.config.serviceTierDefault":"默认","chat.config.unavailable":"模型设置暂时不可用,请重试。","agentConversation.interactionResponseFailed":"没有发送成功,请重试或在终端中继续。","chat.activation.title":"打开对话视图?","chat.activation.body":"Handmux 需要将当前 Agent 重新启动为托管模式。对话会在同一个终端窗格中继续。","chat.activation.terminal":"留在终端","chat.activation.activating":"正在准备当前会话…","chat.activation.waiting":"正在等待托管会话重新连接…","chat.activation.working":"准备中…","chat.activation.stale":"Agent 已发生变化。请返回终端,或重试。","chat.activation.timeout":"Agent 已启动,但对话视图尚未连接。你可以先在终端继续,稍后再试。","chat.activation.failed":"无法准备对话视图。请在终端继续,或重试。","chat.activation.unavailable":"当前无法安全切换此会话,请在终端中继续。","conversationTool.tool":"工具","conversationTool.run":"运行命令","conversationTool.runValue":"运行 {value}","conversationTool.edit":"编辑文件","conversationTool.editValue":"编辑 {value}","conversationTool.write":"写入文件","conversationTool.writeValue":"写入 {value}","conversationTool.read":"读取文件","conversationTool.readValue":"读取 {value}","conversationTool.web":"联网查询","conversationTool.image":"查看图片","conversationTool.imageValue":"查看图片 {value}","conversationTool.wait":"等待任务完成","conversationTool.waitShort":"等待任务","conversationTool.continue":"继续运行任务","conversationTool.continueShort":"继续任务","conversationTool.search":"搜索","conversationTool.searchValue":"搜索 {value}","conversationTool.find":"查找文件","conversationTool.findValue":"查找文件 {value}","conversationTool.webSearch":"联网搜索","conversationTool.webSearchValue":"联网搜索 {value}","conversationTool.webRead":"读取网页","conversationTool.webReadValue":"读取网页 {value}","conversationTool.todo":"更新待办","conversationTool.skill":"激活技能","conversationTool.skillValue":"激活技能 {value}","conversationTool.agent":"调用 Agent","conversationTool.agentValue":"调用 Agent {value}","conversationTool.call":"调用工具","conversationTool.callValue":"调用工具 {value}","conversationTool.diffStat":"新增 {added} 行,删除 {removed} 行","conversationTool.declined":"已拒绝","conversationTool.completed":"已结束","conversationTool.failed":"失败","conversationTool.success":"成功","conversationTool.running":"执行中","conversationTool.runningEllipsis":"执行中…","conversationTool.noReturn":"未返回","conversationTool.createdFile":"新建文件 · 新增 {added} 行","conversationTool.noChanges":"没有可显示的改动","conversationTool.mode":"执行模式","conversationTool.command":"执行的命令","conversationTool.output":"输出结果","conversationTool.imagePathMissing":"未提供可确定的图片路径","conversationTool.imageUnavailable":"图片无法读取,请检查文件和读取权限。","conversationTool.noOutput":"无输出","conversationTool.truncation.input.sizeLimit":"输入较长,仅展示已安全保留的部分;工具执行时使用了完整输入。","conversationTool.truncation.output.sizeLimit":"输出较长,仅展示已安全保留的部分;工具执行不受影响。","conversationTool.truncation.diff.sizeLimit":"变更内容较长,仅展示已安全保留的部分;实际修改不受影响。","conversationTool.truncation.provider_truncated":"Agent 返回的内容本身已截断,当前记录可能不完整。","conversationTool.truncation.redacted":"敏感内容已隐藏。","conversationTool.truncation.unavailable":"这部分工具记录暂不可用。","chat.outgoing.sending":"正在发送","chat.outgoing.queued":"已加入队列","chat.outgoing.sent":"已发送","chat.outgoing.steered":"已引导","chat.outgoing.failed":"发送失败","chat.outgoing.unknown":"未确认是否送达","chat.outgoing.retry":"重试","chat.outgoing.retryUnknown":"查询状态","chat.outgoing.resendTitle":"再次发送这条消息?","chat.outgoing.resendBody":"这条消息可能已经发送。继续会作为一条新消息再次发送,可能导致任务重复执行。","chat.outgoing.resendConfirm":"仍然发送","chat.favs":"常用","chat.tabMsg":"消息","chat.addPlaceholder":"消息 / 斜杠命令…","dock.upload.aria":"上传文件","dock.upload.title":"上传文件(存到家目录上传区,不进项目)","dock.upload.progress":"上传 {name}{tag}","dock.upload.failed":"上传失败:{names}","dock.upload.rejected":"不支持的文件类型:{names}","app.nameExists":"该名已存在","app.renameFailed":"重命名失败,请重试","app.deleteFailed":"删除失败,请重试","app.moveFailed":"移动失败,请重试","app.sessionGone":"会话「{name}」不存在,可能已关闭","app.docNotFound":"文件不存在","app.docTooLarge":"文件过大(超过 2MB)","app.docUnsupported":"不支持的文件或路径","app.docOpenFailed":"打开失败,请重试","app.preview":"预览","app.openPreview":"打开预览","app.ideas":"想法","app.files":"文件","app.settings":"设置","usage.title":"用量","usage.subscriptionTab":"订阅","usage.apiTab":"API","usage.win5h":"5 小时","usage.winWeekly":"本周","usage.winMonthly":"本月","usage.winGeneric":"{h} 小时窗口","usage.winPrimary":"额度","usage.winSecondary":"次级额度","usage.accountQuota":"账号额度","usage.modelLimits":"特定模型","usage.accountApiKey":"API Key 账号","usage.resetIn":"{t}后重置","usage.resetSoon":"即将重置…","usage.resetCredits":"剩余重置次数","usage.resetCreditsCount":"{n} 次","usage.resetCreditExpires":"到期:{time}","usage.claudeOff":"尚未接入 —— Claude 的 5h/周额度需要 handmux statusLine:","usage.claudePending":"暂无数据 —— 在 Claude 会话里发一条消息,再重新打开。","usage.codexOff":"本机未检测到 Codex。","usage.codexNoQuota":"Codex 暂未返回额度数据。","usage.setupRequired":"尚未接入用量采集。","usage.pending":"暂无额度数据,请在 Agent 会话中发一条消息后重新打开。","usage.unavailable":"本机暂未检测到可用的用量数据。","usage.loadFailed":"加载用量失败。","usage.refresh":"刷新","usage.refreshing":"正在刷新…","usage.refreshFailed":"无法刷新订阅用量,请检查连接后重试。","usage.updatedNow":"刚刚更新","usage.updatedMin":"{n} 分钟前更新","usage.updatedHr":"{n} 小时前更新","usage.updatedDay":"{n} 天前更新","usage.updatedCompactNow":"现在","usage.updatedCompactMin":"{n}分","usage.updatedCompactHr":"{n}时","usage.updatedCompactDay":"{n}天","usage.timeMark":"本窗口已过去的时间","usage.menu":"{provider} 用量选项","usage.show":"开启用量显示","usage.hide":"关闭用量显示","apiBalance.title":"API 余额","apiBalance.add":"添加 API","apiBalance.menu":"账户操作","apiBalance.menuAccount":"{account}({provider})账户操作","apiBalance.official":"官方数据","apiBalance.available":"API 可用","apiBalance.insufficient":"余额不足","apiBalance.notQueried":"尚未查询余额","apiBalance.noBalanceData":"暂无余额数据","apiBalance.currencyAvailable":"{currency} 可用余额","apiBalance.toppedUp":"充值余额","apiBalance.granted":"赠送余额","apiBalance.cash":"现金余额","apiBalance.voucher":"代金券余额","apiBalance.refreshing":"正在刷新…","apiBalance.refresh":"刷新","apiBalance.rename":"修改名称","apiBalance.replaceCredential":"替换凭证","apiBalance.deleteConfirm":"确认删除?再点一次","apiBalance.empty":"尚未添加 API","apiBalance.emptyHint":"添加 API 后查看厂家官方余额数据。","apiBalance.addAccount":"添加 API 账户","apiBalance.storageNote":"API Key 加密保存在运行 Handmux 的电脑上,完整 Key 不会返回浏览器。","apiBalance.account":"账户","apiBalance.provider":"厂家","apiBalance.chooseProvider":"选择厂家","apiBalance.name":"名称","apiBalance.credentialNote":"API Key 加密保存在运行 Handmux 的电脑上,完整 Key 不会返回浏览器。","apiBalance.secureRequired":"请通过 HTTPS 或本机 localhost 打开 Handmux 后提交凭证。","apiBalance.verifySave":"验证并保存","apiBalance.verifying":"正在验证…","apiBalance.form.add":"添加 API","apiBalance.form.rename":"修改名称","apiBalance.form.credential":"替换凭证","apiBalance.loadFailed":"无法加载 API 余额,请重试。","apiBalance.refreshFailed":"无法刷新余额,请重试。","apiBalance.saveFailed":"无法保存账户,请检查连接后重试。","apiBalance.deleteFailed":"无法删除账户,请重试。","apiBalance.error.invalid_credential":"凭证无效、无权查询或需完成厂家认证 · 请检查厂家账户,必要时替换凭证","apiBalance.error.rate_limited":"请求过于频繁 · 请稍后重试","apiBalance.error.provider_timeout":"厂家响应超时 · 请重试","apiBalance.error.provider_unreachable":"暂时无法连接厂家 · 请重试","apiBalance.error.unsupported_response":"厂家返回了暂不支持的数据 · 请重试","apiBalance.error.storage_unavailable":"已保存的 API 账户暂不可用 · 请勿直接清空,否则账户无法恢复。请先备份 ~/.handmux/api-accounts.json、api-accounts.key、.corrupt.* 与 .unavailable;恢复匹配的 api-accounts.key 和 api-accounts.json(必要时从 .corrupt.* 还原数据文件),最后移除 .unavailable 并重启 Handmux","apiBalance.error.conflict":"账户已在其他位置更新 · 请重新打开后再试","apiBalance.error.account_limit_reached":"最多可保存 1000 个 API 账户 · 请删除不用的账户后再试","apiBalance.error.not_found":"账户已在其他位置删除 · 请关闭此窗口后刷新","app.renameSession":"重命名会话","app.renameWindow":"重命名窗口","app.manageWindow":"窗口管理","app.moveLeft":"◀ 左移","app.moveRight":"右移 ▶","app.deleteWindow":"删除窗口","pane.splitH":"左右分屏","pane.splitV":"上下分屏","pane.manage":"管理分屏","pane.manageTitle":"分屏管理","pane.close":"关闭此格","pane.closeConfirm":"确认关闭?再点一次","pane.splitFailed":"分屏失败","pane.closeFailed":"关闭失败","resize.windowWidth":"窗口宽度","resize.paneWidth":"窗格宽度","resize.columns":"{n} 列","resize.restore":"恢复","resize.restoreAutoWidth":"恢复自动宽度","resize.restoreRatio":"恢复分屏比例","app.deleteLastWindowConfirm":"这是最后一个窗口,删除将关闭整个会话!再点一次","app.deleteConfirm":"确认删除?再点一次","app.cannotLocate":"无法定位","app.pickItsDir":",请选它所在的目录:","app.noBoundSession":"还没有绑定会话","app.tapToBind":"点此绑定一个","app.selectSessionHint":"点击左上角 ☰ 选择会话","app.backToExit":"再按一次返回键退出","settings.title":"设置","settings.group_global":"全局设置","settings.group_general":"通用","settings.group_voice":"语音转文字","settings.voice_enabled":"是否已开启","settings.voice_on":"已开启","settings.voice_off":"未开启","settings.voice_provider":"当前服务商","settings.voice_profile_tencent_streaming":"腾讯云实时语音识别","settings.voice_profile_tencent_sentence":"腾讯云一句话识别","settings.voice_profile_xfyun":"讯飞语音听写","settings.voice_not_configured":"未配置","settings.voice_filler_filter":"语气词过滤","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"不支持","settings.voice_setup_hint":"请在终端执行 handmux setup,然后进入“语音输入”完成设置。","settings.project_task_beta":"项目任务 Beta","project.root.projects":"项目","project.root.sessions":"会话","project.add":"添加项目","project.archivedProjects":"已归档项目({n})","project.empty":"还没有项目","project.emptyHint":"选择一个本地目录,开始记录需求与任务。","project.manage":"项目管理","project.tasks":"任务","project.drafts":"草稿","project.noTasks":"还没有正式任务","project.noDrafts":"还没有草稿","project.newTask":"新建任务","project.newDraft":"记录草稿","project.storeUnavailable":"项目数据暂时不可用","project.tryAgain":"重试","project.task.title":"标题","project.task.objective":"目标","project.task.acceptance":"验收标准(每行一条)","project.task.scope":"范围与非目标","project.task.constraints":"约束","project.task.references":"引用(每行一个链接或路径)","project.task.priority":"优先级","project.task.priority.none":"无","project.task.priority.high":"高","project.task.priority.medium":"中","project.task.priority.low":"低","project.task.saveDraft":"保存草稿","project.task.saveTask":"保存为任务","project.task.save":"保存","project.task.edit":"编辑要求","project.task.promote":"转为任务","project.task.cancel":"取消任务","project.task.archive":"归档","project.task.cancelConfirm":"取消后任务将只读,且不能恢复为待开始。确定继续吗?","project.task.archiveConfirm":"归档后将从常规列表隐藏,但不会删除数据。确定继续吗?","project.task.discardConfirm":"尚未保存的修改会丢失。确定返回吗?","project.task.conflict":"这项任务已在其他页面更新。请刷新后重新确认你的修改。","project.task.actionConflict":"这项任务已在其他页面更新,已加载最新版本。请确认当前状态。","project.task.loadLatest":"加载最新版本","project.task.request":"想完成什么?","project.task.requestPlaceholder":"直接描述你的需求","project.task.requestHint":"标题会从第一条非空行自动生成,其他信息由 Agent 在处理时整理。","project.task.create":"创建任务","project.management.overview":"概览","project.management.context":"规范记忆","project.management.git":"Git","project.management.memoryOff":"Project Memory 尚未启用","project.management.readOnly":"只读","project.management.projectRoot":"项目目录","project.management.repositoryRoot":"代码仓库","project.management.defaultAgent":"默认 Agent","project.management.notSet":"未设置","project.management.isolation":"任务代码位置","project.management.execution.project-root":"项目目录","project.management.execution.worktree":"独立工作区","project.management.guidance":"项目规范","project.management.guidanceFailed":"暂时无法读取项目规范,请检查目录权限后重试。","project.management.noGuidance":"项目根目录下没有 AGENTS.md 或 CLAUDE.md。","project.management.memoryHint":"以后可在这里查看并确认项目长期记忆。","project.management.conflict":"项目信息已在其他页面更新,已加载最新版本。请确认后重试。","project.management.notGit":"这不是 Git 仓库","project.management.notGitHint":"任务仍可正常管理,只是不显示代码改动。","project.management.gitFailed":"暂时无法读取 Git 状态,请检查仓库后重试。","project.management.gitClean":"工作区没有未提交改动。","project.management.gitChanges":"{n} 个文件有未提交改动","project.management.history":"历史任务","project.management.canceled":"已取消({n})","project.management.archived":"已归档({n})","project.management.historyEmpty":"暂无内容","project.management.historyFailed":"暂时无法读取历史任务,请稍后重试。","project.management.archiveProject":"归档项目","project.management.archiveConfirm":"归档后,项目及其中未归档的任务都会从常规入口隐藏,但数据不会删除。确定继续吗?","settings.group_terminal":"终端","settings.group_chat":"对话","settings.group_notifications":"通知","settings.group_about":"关于","settings.terminal_font_size":"终端字体大小","settings.terminal_font_decrease":"减小终端字体","settings.terminal_font_increase":"增大终端字体","settings.terminal_font_auto":"自适应","settings.terminal_font_auto_title":"按高度自动适配","settings.conversation_font_size":"对话字体大小","settings.conversation_font_decrease":"减小对话字体","settings.conversation_font_increase":"增大对话字体","settings.conversation_font_default":"恢复默认","settings.conversation_font_hint":"可在 10–20px 之间以 1px 为步进调整;仅影响对话消息正文及其中的 Markdown 和代码。","settings.keyboard_mode":"键盘模式","settings.keyboard_mode_auto":"自动识别","settings.keyboard_mode_mobile":"手机","settings.keyboard_mode_desktop":"电脑","settings.keyboard_mode_hint":"仅应用于当前浏览器;识别不准时可手动指定。","settings.terminal_transport":"终端传输模式","settings.terminal_transport_live":"实时推送","settings.terminal_transport_snapshot":"快照拉取","settings.terminal_transport_hint":"实时推送使用 WebSocket;网络较差时会自动降级为快照拉取,持续稳定 30 秒后尝试恢复实时推送。","settings.snapshot_interval":"活跃时刷新频率","settings.snapshot_interval_hint":"终端空闲后会自动降低频率,减少流量和资源占用。","boot.loading":"正在加载","boot.chat_empty":"发送你的第一条消息,对话就开始啦","settings.conversation_view_agent":"{agent} 对话视图","settings.experimental":"实验性","settings.group_agent_integration":"Agent 集成","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"处理中…","settings.agent_integration_load_error":"无法检查 Agent 状态。","settings.agent_integration_action_error":"接入失败,请在电脑上运行:","settings.agent_integration_conflict_hint":"{agent} 已有其他配置,请在电脑上诊断:","settings.agent_integration_not_installed_hint":"这台电脑尚未安装 {agent}。","settings.agent_integration_initialize_first_hint":"请先在电脑上运行一次 {agent},再回来启用。","settings.agent_integration_enable":"启用","settings.agent_integration_repair":"修复","settings.agent_integration_loading":"正在检查…","settings.agent_integration_status_ready":"已接入","settings.agent_integration_status_not_enabled":"未启用","settings.agent_integration_status_needs_repair":"需要修复","settings.agent_integration_status_conflict":"需要处理","settings.agent_integration_status_not_installed":"未安装","settings.chat_tone":"对话配色","settings.chat_tone_dusk":"暖夜","settings.chat_tone_ink":"暖金","settings.chat_tone_light":"暖黄","settings.chat_tone_hint":"对话视图的色调,均为暖色系。暖夜=暖棕暗、暖金=品牌橄榄金、暖黄=奶油亮。","settings.path_highlight":"高亮文件路径","settings.path_highlight_hint":"给终端里可点开的文件路径加底色。无论开关与否,路径都可点开。","settings.whats_new":"新功能","settings.view_changelog":"查看更新日志","settings.reload_app":"重新加载应用","settings.has_update":"有更新","settings.version":"版本","settings.feedback":"反馈与交流","settings.feedback_issues":"GitHub 反馈","settings.feedback_group":"微信用户群","settings.feedback_hint":"bug、想法都欢迎——Issue 会被跟踪处理;微信群反馈直达。","settings.update_available":"有新版本 v{v} 可用","settings.update_more":"另有 {n} 个版本更新","settings.update_how":"在电脑上运行","settings.push_notifications":"推送通知","settings.notify_on":"已开启 ✓","settings.notify_enable":"开启设备通知","settings.notify_enabled":"已开启,应会收到一条欢迎通知","settings.notify_disabled":"已关闭","settings.notify_failed":"操作失败","settings.notify_disable_title":"关闭推送通知?","settings.notify_disable_hint":"关闭后,这台设备将不再收到「需要你」「已完成」或脚本发送的推送。你可以随时重新开启。","settings.notify_disable_confirm":"关闭推送","settings.processing":"处理中","settings.push_hint":"监听「需要你」和「已完成」:所关注会话需要你授权/回答,或一个回合刚做完时,推送到此设备。","settings.push_unsupported":"推送需要 Chrome 或 Safari 浏览器","settings.preview_site":"预览站点","settings.preview_static_site":"预览静态站点","settings.preview_running_static":"静态预览 运行中","settings.preview_remain_title":"剩余有效期","settings.preview_remain":"剩 {time}","settings.preview_renew":"续期","settings.preview_confirm_stop":"确认停止","settings.preview_stop":"停止","settings.preview_name":"名称:{name}","settings.preview_port":"(端口 :{port})","settings.preview_type":"预览类型","settings.preview_off":"不开启","settings.preview_static":"静态","settings.preview_off_hint":"未开启预览。选择「静态」开始。","settings.preview_off_hint_both":"未开启预览。选择「静态」或「动态」开始。","settings.preview_pick_dir":"选择目录启动","settings.preview_static_hint":"选一个含 index.html 的目录,在手机上预览。","settings.preview_port_placeholder":"端口,如 3000","settings.preview_port_label":"端口","settings.preview_starting":"启动中…","settings.preview_start":"启动","settings.dir_picker_hint":"选择要预览的静态站点目录(含 index.html)","settings.err_port_not_listening":"该端口未在监听,请确认服务已启动","settings.err_bad_port":"端口不合法(1–65535)","settings.err_start_failed":"启动失败","filebrowser.openDirFailed":"无法打开该目录","filebrowser.copiedPath":"已复制路径:{abs}","filebrowser.mkdirFailed":"新建目录失败(名称非法或已存在)","filebrowser.downloading":"下载 {name}","filebrowser.downloadFailed":"下载失败","filebrowser.uploading":"上传 {name}{tag}","filebrowser.uploadFailed":"上传失败","filebrowser.uploadPartialFailed":"以下文件上传失败:{names}","filebrowser.uploadRejected":"不支持的文件类型:{names}","filebrowser.sessionDir":"会话目录","filebrowser.jumpToSessionDir":"跳到当前会话目录","filebrowser.parentDir":"上级目录","filebrowser.rootSelect":"切换根目录(家目录 / 临时目录)","filebrowser.pathPlaceholder":"输入路径(实时筛选/跳转)","filebrowser.newFolder":"新建文件夹","filebrowser.createBtn":"创建","filebrowser.uploadFile":"上传文件","filebrowser.uploadToCurrentDir":"上传到当前目录","filebrowser.enterSubdirToUpload":"请进入一个子目录上传","filebrowser.folderNamePlaceholder":"文件夹名称","filebrowser.uploadPendingTo":"把「{name}」上传到当前目录","filebrowser.enterSubdirFirst":"(请先进入一个子目录)","filebrowser.upload":"上传","filebrowser.savedToDownloads":"已保存「{name}」到「下载」文件夹,可在系统文件管理器查看","filebrowser.noMatches":"没有匹配的文件或目录","filebrowser.tooMany":"共 {total} 项,只显示前 {shown} 项——在路径框输入关键词可筛选","filebrowser.previewUnsupported":"暂不支持该类型文件的预览,点右侧按钮可下载","filebrowser.copyAbsPath":"复制绝对路径","filebrowser.download":"下载","filebrowser.pickThisDir":"选定此目录 {path}","filebrowser.downloadConfirm":"下载 {name}?","filemanager.files":"文件","filemanager.closeTab":"关闭标签","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"目录","git.errReadRepo":"无法读取仓库","git.errLoad":"加载失败","git.noRepoInDir":"这个目录还不是 git 仓库 —— 换一个目录,或在这里 git init 一下。","git.outsideRoots":"这个目录在 handmux 可访问范围之外 —— 只开放主目录和 /tmp。把仓库放到主目录下,就能在这里查看了。","git.errReadDir":"无法读取该目录","git.commitDetail":"提交详情","git.diff":"差异","git.bindRepo":"绑定仓库","git.collapse":"收起","git.currentBranch":"当前分支","git.switchViewedBranch":"切换查看的分支","git.switchBranch":"切换分支","git.noBranches":"暂无分支","git.noRepoBound":"未绑定仓库,点左上角「+」选择一个目录。","git.changes":"变更","git.commits":"提交","git.pullToLoadMore":"下拉加载更多","git.pickerHint":"选择一个目录,自动查找其中的 git 仓库","git.cleanTree":"工作区干净","git.noCommits":"暂无提交","git.noDiff":"无差异","git.fontSmaller":"缩小字体","git.fontLarger":"放大字体","git.diffTruncated":"diff 过大,已截断","cmd.panel":"命令面板","cmd.title":"命令","cmd.empty":"还没有命令,发送一条或保存常用","cmd.favorites":"常用","cmd.scopeGlobal":"全局 · 所有会话","cmd.recent":"最近","cmd.scopeSession":"仅本会话","cmd.favorite":"收藏","cmd.itemConflict":"该快捷项已存在,请更换内容或选择其他列表。","cmd.unfavorite":"取消收藏","doc.home":"最近","doc.read":"朗读","doc.pauseRead":"暂停朗读","doc.resumeRead":"继续朗读","doc.stopRead":"停止朗读","doc.rate":"语速","doc.fontSmaller":"缩小字体","doc.fontLarger":"放大字体","inbox.view.working":"进行中","inbox.view.done":"已完成","inbox.view.needs":"需要你","inbox.view.error":"出错","push.unsupported":"推送通知需要 Chrome 或 Safari 浏览器","push.iosAddToHome":'iOS 需先把本站"添加到主屏幕",从主屏图标打开后再开启',"a2hs.title":"把 handmux 添加到主屏","a2hs.lead":"像 App 一样打开——全屏、没有地址栏。在 iPhone 上,pane 需要你时的推送也靠它送达。","a2hs.install":"安装 handmux","a2hs.ios1":"点 Safari 里的分享按钮(⬆︎ 方框)。","a2hs.ios2":"点「更多」,或向下滑动列表。","a2hs.ios3":"选「添加到主屏幕」,再点「添加」。","a2hs.iosHint":"Safari 里:分享 → 更多 → 添加到主屏幕。","a2hs.iosOpenSafari":"当前不是 Safari。请在 Safari 里打开本页再添加到主屏——其他 iOS 浏览器无法安装。","a2hs.androidManual":"打开浏览器菜单(⋮),选「添加到主屏幕」或「安装应用」。","a2hs.later":"以后再说","push.permissionTimeout":"系统未返回通知授权结果,请在系统设置中检查 handmux 或浏览器的通知权限后重试","push.permissionDenied":"通知权限被拒绝","push.swRegisterTimeout":"注册通知服务超时,请检查网络后重试","push.swRegisterFailed":"注册通知服务失败:{reason}。请清除本站数据后重新打开再试","push.swTimeout":"通知服务已注册但未能激活,请清除本站数据后重新打开再试","push.unknownReason":"原因未知","push.configTimeout":"读取推送配置超时,请检查与 handmux 服务的连接后重试","push.browserTimeout":"浏览器推送服务没有响应;Android Chrome 请确认 Google Play 服务可用后重试","push.noVapid":"服务端未配置推送(VAPID)","push.reportTimeout":"订阅已创建,但上报服务器超时,请检查连接后重试","push.subscriptionExpired":"Chrome 返回的推送订阅已经失效,已为你重置;请再次点击开启通知","push.deliveryRejected":"推送服务拒绝了新订阅,请检查服务器日志后重试","push.subscribeFailed":"订阅上报失败","push.sendFailed":"发送失败","api.loadFailed":"加载失败","api.uploadFailed":"上传失败","upload.title":"上传中","upload.processing":"已发送,服务器接收中…","api.uploadBadDir":"无法上传到该目录","api.uploadDuplicate":"已存在同名文件","api.uploadTooLarge":"文件过大(上限 50MB)","api.uploadBadType":"不支持的文件类型","time.secAgo":"{n}秒前","time.minAgo":"{n}分钟前","time.hourAgo":"{n}小时前","time.dayAgo":"{n}天前","time.expired":"已过期","time.minutes":"{n} 分钟","settings.script_push":"脚本推送","settings.script_push_open":"怎么用","settings.script_push_hint":"让电脑上的脚本把一条通知推到手机。","scriptPush.title":"脚本推送","scriptPush.intro":"让电脑上的脚本复用 handmux 的推送通道:在运行 handmux 的电脑上,一条 handmux push 命令就能把通知推到手机——构建、CI 或长任务结束时提醒你,不用另接推送服务。","scriptPush.copied":"已复制","scriptPush.session_placeholder":"<会话名>","scriptPush.device_placeholder":"<本设备key>","scriptPush.scope_all":"推给所有已订阅设备(默认)","scriptPush.scope_session":"只推某个会话里的设备","scriptPush.scope_device":"只推这台设备","scriptPush.device_key_note":"上面这串 key 就是这台设备的,复制即用。","scriptPush.device_need_enable":"先在上方开启推送通知,才会生成这台设备的 key。","scriptPush.opts_label":"可选参数(追加到上面任意一条后面)","scriptPush.opt_tag":"--tag <标签> —— 相同 tag 会覆盖上一条推送,而不是堆叠。","scriptPush.opt_url":"--url <路径> —— 点击通知时打开这个路径。","scriptPush.reliability":"注意:Web 推送经手机系统(FCM/APNs)中转,属尽力而为——省电模式、离线或厂商策略都可能延迟或丢弃它,并不保证实时送达。对送达强依赖的场景,请改用专门的 IM(微信 / Telegram bot 等)。","pushInbox.title":"脚本推送记录","pushInbox.empty":"还没有脚本通知","pushInbox.delete":"删除","pushInbox.justNow":"刚刚","pushInbox.minutesAgo":"{n}分钟前","pushInbox.hoursAgo":"{n}小时前","pushInbox.detailTitle":"脚本推送详情","pushInbox.openUrl":"打开链接","pushInbox.expired":"这条消息已过期","pushInbox.back":"返回","pushInbox.markAllRead":"全部已读","pushInbox.unreadCount":"{n} 未读","pushInbox.loadFailed":"脚本推送记录加载失败,请检查连接后重试","pushInbox.deleteFailed":"脚本推送删除失败,消息已保留,请重试","pushInbox.retry":"重试","pushInbox.deliveryPending":"发送中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失败","pushInbox.deliveryReasonExpired":"订阅已失效","pushInbox.deliveryReasonRateLimited":"推送服务限流","pushInbox.deliveryReasonUnavailable":"推送服务暂不可用","pushInbox.deliveryReasonRejected":"推送服务已拒绝","pushInbox.deliveryReasonNetwork":"网络错误","pushInbox.deliveryReasonNotConfigured":"服务端未配置推送","pushInbox.deliveryReasonUnknown":"未知原因","workspace.bootDetected":"检测到电脑已重启","workspace.tmuxDetected":"检测到 tmux 已重新启动","workspace.summary":"上次工作区 · {sessions} 个会话 · 保存于 {time}","workspace.restoreLast":"恢复上次工作区","workspace.partialCard":"仍有 {failures} 个会话需要处理","workspace.unknownTime":"未知时间","workspace.savedAt":"保存于 {time}","workspace.topologySummary":"{sessions} 个会话 · {windows} 个窗口 · {panes} 个窗格","workspace.planSummary":"将恢复 {restore} 个会话;{already} 个已经存在","workspace.renameRule":"仅当当前已有同名会话时,恢复名称才会添加 -restored 后缀。","workspace.nonDestructive":"当前会话不会被修改、重命名或停止。","workspace.progress":"正在恢复 {completed} / {total}…","workspace.progressDone":"已恢复 {completed} / {total}","workspace.complete":"工作区已恢复。","workspace.completedSummary":"本次恢复:{sessions} 个会话 · {windows} 个窗口 · {panes} 个窗格","workspace.rebindHint":"恢复的会话不会自动显示;可重新选择要绑定到这台手机的会话。","workspace.rebind":"重新绑定会话","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"未知会话","workspace.restore":"恢复","workspace.ignore":"忽略此备份","workspace.protectionTitle":"工作区未受保护","workspace.protection.live-corrupt":"工作区状态副本已损坏;请检查磁盘和 ~/.handmux 权限,然后重启 handmux。","workspace.protection.live-unavailable":"无法读写工作区状态;请检查磁盘空间和 ~/.handmux 权限,然后重启 handmux。","workspace.protection.unknown":"后台快照暂时不可用;请检查电脑上的 handmux 日志。","workspace.error.restore-interrupted":"恢复已中断;请重试此备份","workspace.error.checkpoint-not-found":"此备份已不可用;请刷新后选择其它备份","workspace.error.storage-full":"工作区存储空间不足;请释放磁盘空间后重试","workspace.error.permission-denied":"无法写入工作区存储;请检查权限后重试","workspace.error.plan-failed":"恢复计划已变化;请刷新后重试","workspace.error.agent-unavailable":"Agent 无法续接;请打开已恢复的 shell 后手动重试","workspace.error.tmux-unavailable":"tmux 不可用;请确认 tmux 已运行后重试","workspace.error.restore-failed":"会话未恢复;请检查 handmux 日志后重试","workspace.error.operation-not-found":"此恢复任务已不可用;请重新恢复此备份","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"工作目录不可用;已在主目录中恢复","workspace.warning.layout-fallback":"窗格布局无法完整恢复;已保留默认布局","workspace.warning.agent-warning":"Agent 未能自动续接;已恢复的 shell 仍可使用","workspace.warning.live-reconcile-failed":"实时工作区状态核对失败;请检查 handmux 日志","workspace.warning.workspace-unavailable":"工作区存储暂时不可用;请检查磁盘空间和权限","workspace.warning.restore-warning":"恢复时出现了可继续处理的提醒;请检查恢复结果"},JO={"terminal.transport_live":"即時","terminal.transport_snapshot":"快照","terminal.transport_detail_title":"終端傳輸狀態","terminal.transport_detail_configured":"設定模式","terminal.transport_detail_current":"目前模式","terminal.transport_detail_connection":"連線狀態","terminal.transport_detail_manual":"你已手動選擇快照拉取,不會自動切換。","terminal.transport_detail_live":"終端正在正常接收即時推送。","terminal.transport_detail_fallback":"即時推送不穩定,已自動降級為快照拉取。","terminal.transport_detail_unavailable":"即時通道無法建立,請檢查反向代理是否支援 WebSocket。","terminal.transport_detail_waiting":"正在等待連線穩定,隨後嘗試恢復即時推送。","terminal.transport_detail_retry":"預計 {seconds} 秒後嘗試恢復即時推送。","terminal.connection_connecting":"偵測中","terminal.connection_good":"良好","terminal.connection_degraded":"一般","terminal.connection_poor":"較差","settings.terminal_transport":"終端傳輸模式","settings.terminal_transport_live":"即時推送","settings.terminal_transport_snapshot":"快照拉取","settings.terminal_transport_hint":"即時推送使用 WebSocket;網路較差時會自動降級為快照拉取,持續穩定 30 秒後嘗試恢復即時推送。","settings.snapshot_interval":"活躍時更新頻率","settings.snapshot_interval_hint":"終端閒置後會自動降低頻率,減少流量和資源使用。","terminal.disconnected":"連線中斷,正在重新連線…","terminal.paneMissing":"窗格已關閉,請切換到其他窗格。","common.save":"儲存","common.cancel":"取消","common.confirm":"確認","common.ok":"確定","common.close":"關閉","common.delete":"刪除","common.copy":"複製","conversationCopy.line":"整行","conversationCopy.paragraph":"整段","common.rename":"重新命名","common.create":"新增","common.back":"返回","common.open":"開啟","common.loading":"載入中…","common.done":"完成","common.retry":"重試","app.browser":"網頁預覽器","browser.openTabs":"開啟的網頁預覽器分頁","browser.history":"最近瀏覽","browser.closeTab":"關閉 {title}","browser.newTab":"新增分頁","browser.minimize":"收起","browser.back":"返回","browser.forward":"前進","browser.address":"網址","browser.addressPlaceholder":"輸入網址或連接埠","browser.addressOrDirectoryPlaceholder":"輸入網址,或選擇目錄","browser.refresh":"重新整理","browser.stop":"停止載入","browser.viewMode":"頁面寬度","browser.narrowWidth":"窄螢幕","browser.wideWidth":"寬螢幕","browser.closeTiming":"背景分頁自動關閉","browser.minutes":"{value} 分鐘","browser.neverClose":"永不關閉","browser.clearHistory":"清除","browser.emptyHistory":"尚無最近瀏覽","browser.loadFailed":"無法載入此網頁,請檢查網址後再試。","browser.retry":"重試","browser.consentTitle":"網頁預覽器","browser.consentBody":"Handmux 會將網頁嵌入目前視窗。它不是真正的瀏覽器,適合預覽開發服務、localhost、內網及允許嵌入的網站;也可從 Home 選擇電腦上的靜態目錄。","browser.consentComputer":"連線方式:手機直連使用手機網路。電腦代理的請求由電腦發出,可存取電腦所在的內網與 localhost,但不會將它們公開。","browser.consentPrivate":"登入狀態:直連與代理不共用 Cookie 和登入狀態;代理工作階段也依裝置隔離。","browser.consentLimits":"相容限制:手機直連可能被網站的 iframe 或 CSP 政策阻擋,而且 Handmux 未必能判斷原因。電腦代理會轉送並改寫網頁,也不保證與所有網站相容。需要完整瀏覽功能時,請用 Safari、Chrome 或系統瀏覽器開啟。","browser.consentIdle":"背景分頁:預設在 10 分鐘後關閉。直連網站的 Cookie 仍保留在手機瀏覽器中。","browser.about":"關於網頁預覽器","browser.acknowledge":"好的","browser.directMode":"手機直連","browser.proxyMode":"透過電腦代理","browser.directBadge":"直連","browser.proxyBadge":"代理","browser.staticBadge":"靜態","browser.chooseDirectory":"選擇目錄","browser.staticOpening":"正在開啟目錄…","browser.directoryPickerHint":"選擇包含網頁檔案的目錄。","browser.switchMode":"切換瀏覽模式","browser.menu":"網頁預覽器選單","browser.connectionMode":"連線方式","browser.pageWidth":"頁面寬度","browser.requestSiteVersion":"向網站請求","browser.mobileSite":"手機版","browser.desktopSite":"電腦版","browser.zoomPage":"縮放網頁","browser.resetZoom":"重設網頁縮放","browser.proxyLogin":"代理登入","browser.proxyLoginHelpLabel":"代理登入說明","browser.proxyLoginHelp":"是否將代理 Cookie 加密儲存在執行 Handmux 的電腦上,以便重新啟動後保持登入狀態。","browser.siteProxyCookie":"本站代理 Cookie","browser.siteCookieHelpLabel":"本站代理 Cookie 說明","browser.siteCookieHelp":"這裡只會清理目前裝置中符合本站真實網址的代理 Cookie。父網域 Cookie 可能讓相關內部網站一起登出,手機直接連線 Cookie 不受影響。","browser.openMode":"選擇開啟方式","browser.historyMore":"更多開啟方式","browser.historyActions":"更多操作","browser.proxyLimitHint":"電腦代理會轉送並改寫網頁,不保證與所有網站相容。","browser.proxyUnavailable":"請在電腦終端執行 handmux setup,選擇「網頁預覽器」設定代理網域;設定前只能使用手機直連。","browser.urlInvalid":"請輸入有效的 HTTP 或 HTTPS 位址。","browser.tryProxy":"改用電腦代理","browser.openExternal":"用系統瀏覽器開啟","browser.clearSiteLogin":"清理本站代理 Cookie","browser.clearAllLogin":"清理全部代理 Cookie","browser.clearSiteLoginConfirm":"清理目前裝置的本站代理登入狀態?父網域 Cookie 也可能影響相關內部系統。","browser.clearAllLoginConfirm":"清理目前裝置的全部代理登入狀態?手機直連登入不受影響。","browser.deleteHistoryEntry":"刪除此記錄","browser.profileSaveFailed":"無法儲存代理登入設定,請檢查伺服器連線後重試。","browser.profileClearFailed":"清理未完全成功,請檢查伺服器連線與儲存權限後重試。","browser.profileSyncFailed":"無法同步代理登入設定。請重試,或改用手機直連。","browser.profileRecoveryWarning":"無法復原已儲存的代理登入資料,目前裝置的代理登入狀態已重設。","browser.retention1":"1 天","browser.retention7":"7 天","browser.retention30":"30 天","browser.retentionNotSaved":"不儲存","browser.retentionNever":"長期儲存","settings.browserPersistLogin":"在電腦上持久儲存代理 Cookie","settings.browserPersistLoginHint":"只儲存在目前裝置。關閉後,目前分頁與登入狀態仍會保留,直到清理或到期。","settings.browserRetention":"代理登入保留","settings.browserDisablePersistConfirm":"停止儲存目前裝置後續的代理登入變更?目前分頁與登入狀態仍會保留。","token.title":"需要存取 Token","token.placeholder":"貼上 HANDMUX_TOKEN","settings.language":"語言 Language","settings.browserDefaultMode":"網頁預設開啟方式","settings.browserDefaultModeHint":"用於網址列新分頁,以及未儲存開啟方式的歷史記錄。","settings.browserEnabled":"網頁預覽器","settings.browserEnabledHint":"分頁僅屬於目前裝置。關閉後會關閉全部分頁,但保留歷史記錄。","home.empty":"尚未開啟任何檔案","home.emptyHint":"切換到「新增」挑選一個","home.remove":"移除","drawer.title":"工作階段","drawer.empty":"尚未綁定工作階段","drawer.unbind":"解除綁定","drawer.bind":"綁定工作階段","drawer.logout":"登出","windowbar.newWindow":"新增視窗","rename.new_name":"新名稱","rename.name_rule":"只能使用字母、數字、連字號(≤16)","rename.failed":"重新命名失敗,請重試","rename.saving":"儲存中…","newwindow.title":"新增視窗","newwindow.window_name":"視窗名稱(選填)","newwindow.name_placeholder":"留空自動命名 · 字母/數字/連字號 ≤16","newwindow.name_rule":"只能使用字母、數字、連字號(≤16)","newwindow.start_dir":"起始目錄","newwindow.session_dir_named":"{dir}(工作階段目錄)","newwindow.session_dir_default":"工作階段目錄(預設)","newwindow.choose":"選擇","newwindow.reset_to_session_dir":"重置為工作階段目錄","newwindow.creating":"建立中…","startup.label":"啟動命令(選填)","startup.aria":"啟動命令","startup.preset_shell":"空白 Shell(預設)","startup.preset_claude":"claude(啟動 Claude Code)","startup.preset_claude_continue":"claude -c(繼續上次工作階段)","startup.preset_codex":"codex(啟動 Codex CLI)","startup.custom":"自訂…","startup.custom_placeholder":'例如 claude "修復登入 bug"',"bind.title":"綁定工作階段","bind.sessionName":"工作階段名稱","bind.pickSession":"選擇要綁定的工作階段","bind.newSession":"+ 新增工作階段","bind.modeNew":"新增工作階段","bind.modeExisting":"既有工作階段","bind.alreadyExists":"此工作階段已存在","bind.bind":"綁定","bind.checking":"驗證中…","bind.createAndOpen":"新增並開啟","bind.creating":"建立中…","bind.createHint":"工作階段「{name}」不存在,點「新增並開啟」建立","bind.alreadyBound":"已綁定此工作階段","bind.createFailed":"建立失敗,請重試","bind.invalidName":"只能使用字母、數字、連字號(≤16)","bind.desktopHint":"這裡的工作階段(包括手機新建的),電腦上一條命令即可接管:handmux open <名稱>","bind.checkFailed":"驗證失敗,請重試","bind.startDir":"起始目錄","bind.homeDirDefault":"主目錄(預設)","bind.choose":"選擇","bind.reset":"重置","actionsheet.confirmAgain":"確認?再點一次","dirpicker.title":"選擇目錄","inbox.title":"收件匣","inbox.working":"進行中","inbox.done":"已完成","inbox.needs":"需要你","inbox.error":"出錯","inbox.clearDone":"清除結果","inbox.empty":"目前沒有面板狀態","inbox.enableTitle":"開啟 Claude Code 狀態與通知","inbox.enableHint":"Claude Code 收件匣需要 Agent hooks。Codex CLI 請使用 Handmux 託管模式。","inbox.enableBtn":"開啟","inbox.enabling":"開啟中…","inbox.enableFailed":"開啟失敗——請查看伺服器日誌。","idea.title":"想法","idea.editPlaceholder":"編輯想法…","idea.addPlaceholder":"記錄一條想法…","idea.add":"新增","idea.empty":"還沒有想法,記錄一條吧","idea.dragSort":"拖曳排序","idea.fillInput":"填入輸入框","idea.send":"傳送","doclink.title":"開啟檔案","changelog.title":"新功能","preview.static":"靜態預覽","preview.remainTitle":"剩餘有效期 — 點擊續期 / 停止","preview.toPcView":"切換到電腦檢視","preview.toMobileView":"切換到手機檢視","preview.pcView":"電腦檢視","preview.mobileView":"手機檢視","preview.refresh":"重新整理","preview.minimize":"收起","preview.ttlDialog":"預覽有效期","preview.renew":"續期(重置為 1 小時)","preview.stop":"停止預覽","preview.iframeTitle":"預覽","preview.zoomOut":"縮小","preview.zoomIn":"放大","imageviewer.loadFailed":"圖片載入失敗","imageviewer.saved":"已儲存,可在相簿或「下載」中查看","imageviewer.shareUnsupported":"圖片分享需要 Chrome 或 Safari 瀏覽器","imageviewer.zoomOut":"縮小","imageviewer.zoomIn":"放大","imageviewer.imageTitle":"圖片","imageviewer.saveImage":"儲存圖片","imageviewer.shareImage":"分享圖片","mic.stop":"停止語音輸入","mic.start":"語音輸入","mic.recognizing":"正在識別語音","mic.error.tencentPermission":"騰訊雲拒絕了辨識:請為目前 SecretId 授予 asr:SentenceRecognition 權限後重試。","mic.error.tencentCredentials":"騰訊雲憑證無效,請在 handmux setup 中檢查 AppId、SecretId 和 SecretKey。","mic.error.browserPermission":"沒有麥克風權限,請在瀏覽器網站設定中允許麥克風後重試。","mic.error.device":"無法使用麥克風,請檢查裝置是否存在或被其他程式占用。","mic.error.secureContext":"目前網址不能使用麥克風,請改用 HTTPS 或 localhost 開啟 Handmux。","mic.error.tooLong":"錄音過長,請縮短後重試。","mic.error.notSelected":"目前語音模式尚未生效,請重新啟動 Handmux 後重試。","mic.error.noSpeech":"未辨識到語音,請重試。","mic.error.network":"語音服務連線失敗,請檢查網路後重試。","mic.error.provider":"語音服務拒絕了要求:{reason}","mic.error.generic":"語音輸入失敗,請重試。","dock.send":"傳送","dock.send.hint":"點傳送 · 長按填入","dock.phrases":"常用語","dock.attach":"上傳","dock.history":"歷史","history.empty":"還沒有發送記錄","history.scope":"僅目前視窗的記錄","dock.input.placeholder":"說點什麼…","dock.input.enterDraft":"按 Shift + Enter 進入草稿模式","dock.input.exitDraft":"按 Esc 回到終端模式 · Shift + Enter 換行","dock.command.placeholder":"輸入指令 · Enter 執行","dock.mode.agent":"對話","dock.mode.toggle":"切換輸入模式","dock.mode.command":"命令模式","dock.mode.chat":"聊天模式","fav.title":"常用","fav.add":"新增","fav.addPlaceholder":"新增常用…","dock.upload.aria":"上傳檔案","dock.upload.title":"上傳檔案(存到主目錄上傳區,不進專案)","dock.upload.progress":"上傳 {name}{tag}","dock.upload.failed":"上傳失敗:{names}","app.nameExists":"該名稱已存在","app.renameFailed":"重新命名失敗,請重試","app.deleteFailed":"刪除失敗,請重試","app.moveFailed":"移動失敗,請重試","app.sessionGone":"工作階段「{name}」不存在,可能已關閉","app.docNotFound":"檔案不存在","app.docTooLarge":"檔案過大(超過 2MB)","app.docUnsupported":"不支援的檔案或路徑","app.docOpenFailed":"開啟失敗,請重試","app.preview":"預覽","app.openPreview":"開啟預覽","app.ideas":"想法","app.files":"檔案","app.settings":"設定","app.renameSession":"重新命名工作階段","app.renameWindow":"重新命名視窗","app.moveLeft":"◀ 左移","app.moveRight":"右移 ▶","app.deleteWindow":"刪除視窗","pane.splitH":"左右分割","pane.splitV":"上下分割","pane.manage":"管理分割","pane.close":"關閉此格","pane.closeConfirm":"確認關閉?再點一次","pane.splitFailed":"分割失敗","pane.closeFailed":"關閉失敗","resize.windowWidth":"視窗寬度","resize.paneWidth":"窗格寬度","resize.columns":"{n} 欄","resize.restore":"恢復","resize.restoreAutoWidth":"恢復自動寬度","resize.restoreRatio":"恢復分割比例","app.deleteLastWindowConfirm":"這是最後一個視窗,刪除將關閉整個工作階段!再點一次","app.deleteConfirm":"確認刪除?再點一次","app.cannotLocate":"無法定位","app.pickItsDir":",請選擇所在目錄:","app.noBoundSession":"尚未綁定工作階段","app.tapToBind":"點此綁定一個","app.selectSessionHint":"點擊左上角 ☰ 選擇工作階段","app.backToExit":"再按一次返回鍵結束","settings.title":"設定","settings.group_global":"全域設定","settings.group_general":"一般","settings.group_voice":"語音轉文字","settings.voice_enabled":"是否已開啟","settings.voice_on":"已開啟","settings.voice_off":"未開啟","settings.voice_provider":"目前服務商","settings.voice_profile_tencent_streaming":"騰訊雲即時語音識別","settings.voice_profile_tencent_sentence":"騰訊雲一句話識別","settings.voice_profile_xfyun":"訊飛語音聽寫","settings.voice_not_configured":"未設定","settings.voice_filler_filter":"語氣詞過濾","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"不支援","settings.voice_setup_hint":"請在終端機執行 handmux setup,然後進入「語音輸入」完成設定。","settings.project_task_beta":"專案任務 Beta","settings.group_terminal":"終端機","settings.group_chat":"對話","settings.group_notifications":"通知","settings.group_about":"關於","settings.terminal_font_size":"終端機字型大小","settings.terminal_font_decrease":"縮小終端機字型","settings.terminal_font_increase":"放大終端機字型","settings.terminal_font_auto":"自適應","settings.terminal_font_auto_title":"依高度自動調整","settings.conversation_font_size":"對話字型大小","settings.conversation_font_decrease":"縮小對話字型","settings.conversation_font_increase":"放大對話字型","settings.conversation_font_default":"恢復預設","settings.conversation_font_hint":"可在 10–20px 之間以 1px 為步進調整;僅影響對話訊息內文及其中的 Markdown 與程式碼。","settings.keyboard_mode":"鍵盤模式","settings.keyboard_mode_auto":"自動識別","settings.keyboard_mode_mobile":"手機","settings.keyboard_mode_desktop":"電腦","settings.keyboard_mode_hint":"僅套用於目前瀏覽器;識別不準時可手動指定。","settings.group_agent_integration":"Agent 整合","settings.conversation_view_agent":"{agent} 對話檢視","settings.experimental":"實驗性","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"處理中…","settings.agent_integration_load_error":"無法檢查 Agent 狀態。","settings.agent_integration_action_error":"整合失敗,請在電腦上執行:","settings.agent_integration_conflict_hint":"{agent} 已有其他設定,請在電腦上進行診斷:","settings.agent_integration_not_installed_hint":"這台電腦尚未安裝 {agent}。","settings.agent_integration_initialize_first_hint":"請先在電腦上執行一次 {agent},再回來啟用。","settings.agent_integration_enable":"啟用","settings.agent_integration_repair":"修復","settings.agent_integration_loading":"正在檢查…","settings.agent_integration_status_ready":"已接入","settings.agent_integration_status_not_enabled":"未啟用","settings.agent_integration_status_needs_repair":"需要修復","settings.agent_integration_status_conflict":"需要處理","settings.agent_integration_status_not_installed":"未安裝","settings.chat_lens_claude":"Claude Code 對話視圖(實驗性)","settings.chat_lens_codex":"Codex CLI 對話視圖","settings.chat_lens_claude_hint":"Claude Code 對話仍是實驗性功能;開啟後可在視窗列切換視圖。","settings.chat_lens_codex_hint":"僅控制 Codex CLI 的對話視圖入口。託管工作階段會自動進入收件匣;一般 Codex 仍可使用終端機,但不會同步狀態和通知。","boot.loading":"正在載入","boot.chat_empty":"發送你的第一則訊息,對話就開始啦","settings.chat_lens_need_hooks":"需先安裝 Agent hooks:對話裡的確認提示和狀態都依賴它。","settings.chat_lens_no_claude":"未檢測到 Claude Code;安裝並執行後再開啟。","settings.chat_lens_install_hooks":"一鍵安裝 hooks","settings.chat_lens_installing":"安裝中…","settings.chat_lens_hooks_err":"接入失敗,請到電腦上運行 handmux agent enable claude","settings.agent_hooks_error":"接入失敗,請到電腦上執行 handmux agent enable claude。","settings.path_highlight":"高亮檔案路徑","settings.path_highlight_hint":"為終端機裡可點開的檔案路徑加底色。無論開關與否,路徑都可點開。","settings.whats_new":"新功能","settings.view_changelog":"查看更新日誌","settings.reload_app":"重新載入應用程式","settings.has_update":"有更新","settings.version":"版本","settings.feedback":"意見回饋","settings.feedback_issues":"GitHub 回報","settings.feedback_group":"微信用戶群","settings.feedback_hint":"bug、想法都歡迎——Issue 會被追蹤處理;微信群回饋直達。","settings.update_available":"有新版本 v{v} 可用","settings.update_more":"另有 {n} 個版本更新","settings.update_how":"在電腦上執行","settings.push_notifications":"推播通知","settings.notify_on":"已開啟 ✓","settings.notify_enable":"開啟裝置通知","settings.notify_enabled":"已開啟,應會收到一則歡迎通知","settings.notify_disabled":"已關閉","settings.notify_failed":"操作失敗","settings.notify_disable_title":"關閉推播通知?","settings.notify_disable_hint":"關閉後,這台裝置將不再收到「需要你」「已完成」或指令碼發送的推播。你可以隨時重新開啟。","settings.notify_disable_confirm":"關閉推播","settings.processing":"處理中","settings.push_hint":"監聽「需要你」和「已完成」:所關注工作階段需要授權/回答,或一輪剛完成時,推播到此裝置。","settings.push_unsupported":"推播需要 Chrome 或 Safari 瀏覽器","settings.preview_site":"預覽站台","settings.preview_static_site":"預覽靜態站台","settings.preview_running_static":"靜態預覽 執行中","settings.preview_remain_title":"剩餘有效期","settings.preview_remain":"剩 {time}","settings.preview_renew":"續期","settings.preview_confirm_stop":"確認停止","settings.preview_stop":"停止","settings.preview_name":"名稱:{name}","settings.preview_port":"(連接埠:{port})","settings.preview_type":"預覽類型","settings.preview_off":"不開啟","settings.preview_static":"靜態","settings.preview_off_hint":"未開啟預覽。選擇「靜態」開始。","settings.preview_off_hint_both":"未開啟預覽。選擇「靜態」或「動態」開始。","settings.preview_pick_dir":"選擇目錄啟動","settings.preview_static_hint":"選一個含 index.html 的目錄,在手機上預覽。","settings.preview_port_placeholder":"連接埠,如 3000","settings.preview_port_label":"連接埠","settings.preview_starting":"啟動中…","settings.preview_start":"啟動","settings.dir_picker_hint":"選擇要預覽的靜態站台目錄(含 index.html)","settings.err_port_not_listening":"該連接埠未在監聽,請確認服務已啟動","settings.err_bad_port":"連接埠不合法(1–65535)","settings.err_start_failed":"啟動失敗","localurl.title":"開啟網站","localurl.open":"在瀏覽器中開啟","localurl.notListening":"連接埠 :{port} 沒有服務在監聽。","localurl.badProtocol":"此連結不是可代理的 HTTP 或 HTTPS 位址。","localurl.network":"無法連線 handmux 服務,請檢查網路後重試。","localurl.failed":"無法開啟此網站,請檢查網址後再試。","filebrowser.openDirFailed":"無法開啟該目錄","filebrowser.copiedPath":"已複製路徑:{abs}","filebrowser.mkdirFailed":"建立目錄失敗(名稱不合法或已存在)","filebrowser.downloading":"下載 {name}","filebrowser.downloadFailed":"下載失敗","filebrowser.uploading":"上傳 {name}{tag}","filebrowser.uploadFailed":"上傳失敗","filebrowser.uploadPartialFailed":"以下檔案上傳失敗:{names}","filebrowser.sessionDir":"工作階段目錄","filebrowser.jumpToSessionDir":"跳到目前工作階段目錄","filebrowser.parentDir":"上層目錄","filebrowser.rootSelect":"切換根目錄(主目錄 / 暫存目錄)","filebrowser.pathPlaceholder":"輸入路徑(即時篩選/跳轉)","filebrowser.newFolder":"新增資料夾","filebrowser.createBtn":"建立","filebrowser.uploadFile":"上傳檔案","filebrowser.uploadToCurrentDir":"上傳到目前目錄","filebrowser.enterSubdirToUpload":"請進入一個子目錄上傳","filebrowser.folderNamePlaceholder":"資料夾名稱","filebrowser.uploadPendingTo":"將「{name}」上傳到目前目錄","filebrowser.enterSubdirFirst":"(請先進入一個子目錄)","filebrowser.upload":"上傳","filebrowser.savedToDownloads":"已儲存「{name}」到「下載」資料夾,可在系統檔案管理員查看","filebrowser.noMatches":"沒有符合的檔案或目錄","filebrowser.tooMany":"共 {total} 項,僅顯示前 {shown} 項——在路徑框輸入關鍵字可篩選","filebrowser.previewUnsupported":"暫不支援此類型檔案的預覽,點右側按鈕可下載","filebrowser.copyAbsPath":"複製絕對路徑","filebrowser.download":"下載","filebrowser.pickThisDir":"選定此目錄 {path}","filebrowser.downloadConfirm":"下載 {name}?","filemanager.files":"檔案","filemanager.closeTab":"關閉標籤","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"目錄","git.errReadRepo":"無法讀取儲存庫","git.errLoad":"載入失敗","git.noRepoInDir":"這個目錄還不是 git 儲存庫 —— 換一個目錄,或在這裡 git init 一下。","git.outsideRoots":"這個目錄在 handmux 可存取範圍之外 —— 只開放主目錄和 /tmp。把儲存庫放到主目錄下,就能在這裡檢視了。","git.errReadDir":"無法讀取該目錄","git.commitDetail":"提交詳情","git.diff":"差異","git.bindRepo":"綁定儲存庫","git.collapse":"收起","git.currentBranch":"目前分支","git.switchViewedBranch":"切換查看的分支","git.switchBranch":"切換分支","git.noBranches":"目前沒有分支","git.noRepoBound":"未綁定儲存庫,點左上角「+」選擇一個目錄。","git.changes":"變更","git.commits":"提交","git.pullToLoadMore":"下拉載入更多","git.pickerHint":"選擇一個目錄,自動尋找其中的 git 儲存庫","git.cleanTree":"工作區乾淨","git.noCommits":"目前沒有提交","git.noDiff":"無差異","git.fontSmaller":"縮小字型","git.fontLarger":"放大字型","git.diffTruncated":"diff 過大,已截斷","cmd.panel":"命令面板","cmd.title":"命令","cmd.empty":"還沒有命令,傳送一條或儲存常用","cmd.favorites":"常用","cmd.scopeGlobal":"全域 · 所有工作階段","cmd.recent":"最近","cmd.scopeSession":"僅本工作階段","cmd.favorite":"收藏","cmd.unfavorite":"取消收藏","doc.home":"最近","doc.read":"朗讀","doc.pauseRead":"暫停朗讀","doc.resumeRead":"繼續朗讀","doc.stopRead":"停止朗讀","doc.rate":"語速","doc.fontSmaller":"縮小字型","doc.fontLarger":"放大字型","inbox.view.working":"進行中","inbox.view.done":"已完成","inbox.view.needs":"需要你","inbox.view.error":"出錯","push.unsupported":"推播通知需要 Chrome 或 Safari 瀏覽器","push.iosAddToHome":"iOS 需先將本站「加入主畫面」,從主畫面圖示開啟後再開啟","a2hs.title":"將 handmux 加入主畫面","a2hs.lead":"像 App 一樣開啟——全螢幕、沒有網址列。在 iPhone 上,pane 需要你時的推播也靠它送達。","a2hs.install":"安裝 handmux","a2hs.ios1":"點 Safari 的分享按鈕(⬆︎ 方框)。","a2hs.ios2":"點「更多」,或向下滑動清單。","a2hs.ios3":"選「加入主畫面」,再點「加入」。","a2hs.iosHint":"Safari 裡:分享 → 更多 → 加入主畫面。","a2hs.iosOpenSafari":"目前不是 Safari。請在 Safari 開啟本頁再加入主畫面——其他 iOS 瀏覽器無法安裝。","a2hs.androidManual":"開啟瀏覽器選單(⋮),選「加入主畫面」或「安裝應用程式」。","a2hs.later":"稍後再說","push.permissionTimeout":"系統未回傳通知授權結果,請在系統設定中檢查 handmux 或瀏覽器的通知權限後再試","push.permissionDenied":"通知權限被拒絕","push.swRegisterTimeout":"註冊通知服務逾時,請檢查網路後再試","push.swRegisterFailed":"註冊通知服務失敗:{reason}。請清除本站資料後重新開啟再試","push.swTimeout":"通知服務已註冊但未能啟用,請清除本站資料後重新開啟再試","push.unknownReason":"原因不明","push.configTimeout":"讀取推播設定逾時,請檢查與 handmux 伺服器的連線後再試","push.browserTimeout":"瀏覽器推播服務沒有回應;Android Chrome 請確認 Google Play 服務可用後再試","push.noVapid":"伺服器未設定推播(VAPID)","push.reportTimeout":"訂閱已建立,但回報伺服器逾時,請檢查連線後再試","push.subscriptionExpired":"Chrome 回傳的推播訂閱已失效,已為你重設;請再次點擊開啟通知","push.deliveryRejected":"推播服務拒絕了新訂閱,請檢查伺服器記錄後再試","push.subscribeFailed":"訂閱回報失敗","push.sendFailed":"傳送失敗","api.loadFailed":"載入失敗","api.uploadFailed":"上傳失敗","upload.title":"上傳中","upload.processing":"已傳送,伺服器接收中…","api.uploadBadDir":"無法上傳到該目錄","api.uploadDuplicate":"已存在同名檔案","api.uploadTooLarge":"檔案過大(上限 50MB)","api.uploadBadType":"不支援的檔案類型","time.secAgo":"{n} 秒前","time.minAgo":"{n} 分鐘前","time.hourAgo":"{n} 小時前","time.dayAgo":"{n} 天前","time.expired":"已過期","time.minutes":"{n} 分鐘","settings.script_push":"腳本推送","settings.script_push_open":"怎麼用","settings.script_push_hint":"讓電腦上的腳本把一條通知推到手機。","scriptPush.title":"腳本推送","scriptPush.intro":"讓電腦上的腳本複用 handmux 的推送通道:在執行 handmux 的電腦上,一條 handmux push 命令就能把通知推到手機——建置、CI 或長任務結束時提醒你,不用另接推送服務。","scriptPush.copied":"已複製","scriptPush.session_placeholder":"<會話名>","scriptPush.device_placeholder":"<本裝置key>","scriptPush.scope_all":"推給所有已訂閱裝置(預設)","scriptPush.scope_session":"只推某個會話裡的裝置","scriptPush.scope_device":"只推這台裝置","scriptPush.device_key_note":"上面這串 key 就是這台裝置的,複製即用。","scriptPush.device_need_enable":"先在上方開啟推送通知,才會生成這台裝置的 key。","scriptPush.opts_label":"可選參數(追加到上面任意一條後面)","scriptPush.opt_tag":"--tag <標籤> —— 相同 tag 會覆蓋上一條推送,而不是堆疊。","scriptPush.opt_url":"--url <路徑> —— 點擊通知時開啟這個路徑。","scriptPush.reliability":"注意:Web 推送經手機系統(FCM/APNs)中轉,屬盡力而為——省電模式、離線或廠商策略都可能延遲或丟棄它,並不保證即時送達。對送達強依賴的場景,請改用專門的 IM(WeChat / Telegram bot 等)。","pushInbox.title":"腳本推送記錄","pushInbox.empty":"還沒有腳本通知","pushInbox.delete":"刪除","pushInbox.justNow":"剛剛","pushInbox.minutesAgo":"{n}分鐘前","pushInbox.hoursAgo":"{n}小時前","pushInbox.detailTitle":"腳本推送詳情","pushInbox.openUrl":"打開連結","pushInbox.expired":"這條訊息已過期","pushInbox.back":"返回","pushInbox.markAllRead":"全部已讀","pushInbox.unreadCount":"{n} 未讀","pushInbox.loadFailed":"腳本推送記錄載入失敗,請檢查連線後重試","pushInbox.deleteFailed":"腳本推送刪除失敗,訊息已保留,請重試","pushInbox.retry":"重試","pushInbox.deliveryPending":"傳送中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失敗","pushInbox.deliveryReasonExpired":"訂閱已失效","pushInbox.deliveryReasonRateLimited":"推播服務限流","pushInbox.deliveryReasonUnavailable":"推播服務暫不可用","pushInbox.deliveryReasonRejected":"推播服務已拒絕","pushInbox.deliveryReasonNetwork":"網路錯誤","pushInbox.deliveryReasonNotConfigured":"伺服器未設定推播","pushInbox.deliveryReasonUnknown":"不明原因","workspace.bootDetected":"偵測到電腦已重新啟動","workspace.tmuxDetected":"偵測到 tmux 已重新啟動","workspace.summary":"上次工作區 · {sessions} 個工作階段 · 儲存於 {time}","workspace.restoreLast":"還原上次工作區","workspace.partialCard":"仍有 {failures} 個工作階段需要處理","workspace.unknownTime":"未知時間","workspace.savedAt":"儲存於 {time}","workspace.topologySummary":"{sessions} 個工作階段 · {windows} 個視窗 · {panes} 個窗格","workspace.planSummary":"將還原 {restore} 個工作階段;{already} 個已存在","workspace.renameRule":"僅當目前已有同名工作階段時,還原名稱才會加上 -restored 後綴。","workspace.nonDestructive":"目前的工作階段不會被修改、重新命名或停止。","workspace.progress":"正在還原 {completed} / {total}…","workspace.progressDone":"已還原 {completed} / {total}","workspace.complete":"工作區已還原。","workspace.completedSummary":"本次還原:{sessions} 個工作階段 · {windows} 個視窗 · {panes} 個窗格","workspace.rebindHint":"還原的工作階段不會自動顯示;可重新選擇要綁定到這台手機的工作階段。","workspace.rebind":"重新綁定工作階段","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"未知工作階段","workspace.restore":"還原","workspace.ignore":"忽略此備份","workspace.protectionTitle":"工作區未受保護","workspace.protection.live-corrupt":"工作區狀態副本已損壞;請檢查磁碟與 ~/.handmux 權限,然後重新啟動 handmux。","workspace.protection.live-unavailable":"無法讀寫工作區狀態;請檢查磁碟空間與 ~/.handmux 權限,然後重新啟動 handmux。","workspace.protection.unknown":"背景快照暫時無法使用;請檢查電腦上的 handmux 日誌。","workspace.error.restore-interrupted":"還原已中斷;請重試此備份","workspace.error.checkpoint-not-found":"此備份已無法使用;請重新整理後選擇其他備份","workspace.error.storage-full":"工作區儲存空間不足;請釋放磁碟空間後重試","workspace.error.permission-denied":"無法寫入工作區儲存;請檢查權限後重試","workspace.error.plan-failed":"還原計畫已變更;請重新整理後重試","workspace.error.agent-unavailable":"Agent 無法續接;請開啟已還原的 shell 後手動重試","workspace.error.tmux-unavailable":"tmux 無法使用;請確認 tmux 已執行後重試","workspace.error.restore-failed":"工作階段未還原;請檢查 handmux 日誌後重試","workspace.error.operation-not-found":"此還原任務已無法使用;請重新還原此備份","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"工作目錄無法使用;已在主目錄中還原","workspace.warning.layout-fallback":"窗格配置無法完整還原;已保留預設配置","workspace.warning.agent-warning":"Agent 未能自動續接;已還原的 shell 仍可使用","workspace.warning.live-reconcile-failed":"即時工作區狀態核對失敗;請檢查 handmux 日誌","workspace.warning.workspace-unavailable":"工作區儲存暫時無法使用;請檢查磁碟空間和權限","workspace.warning.restore-warning":"還原時出現可繼續處理的提醒;請檢查還原結果","chat.plan.currentTitle":"目前任務","chat.plan.historyTitle":"本輪任務","chat.plan.working":"正在:{step}","chat.plan.waiting":"等待確認:{step}","chat.plan.finalizing":"正在整理結果","chat.plan.complete":"已完成","chat.plan.incomplete":"未完成","chat.plan.status.pending":"待處理","chat.plan.status.inProgress":"進行中","chat.plan.status.completed":"已完成"},QO={"terminal.transport_live":"リアル","terminal.transport_snapshot":"スナップ","terminal.transport_detail_title":"ターミナル配信状態","terminal.transport_detail_configured":"設定モード","terminal.transport_detail_current":"現在のモード","terminal.transport_detail_connection":"接続状態","terminal.transport_detail_manual":"スナップショット取得が手動で選択されているため、自動では切り替わりません。","terminal.transport_detail_live":"ターミナルはリアルタイム配信を正常に受信しています。","terminal.transport_detail_fallback":"リアルタイム配信が不安定なため、スナップショット取得へ切り替えました。","terminal.transport_detail_unavailable":"リアルタイム接続を確立できません。リバースプロキシが WebSocket に対応しているか確認してください。","terminal.transport_detail_waiting":"接続が安定してからリアルタイム配信への復帰を試みます。","terminal.transport_detail_retry":"約 {seconds} 秒後にリアルタイム配信への復帰を試みます。","terminal.connection_connecting":"確認中","terminal.connection_good":"良好","terminal.connection_degraded":"普通","terminal.connection_poor":"不良","settings.terminal_transport":"ターミナル配信モード","settings.terminal_transport_live":"リアルタイム配信","settings.terminal_transport_snapshot":"スナップショット取得","settings.terminal_transport_hint":"リアルタイム配信は WebSocket を使用し、回線が不安定な場合はスナップショット取得へ切り替わり、30 秒安定すると復帰を試みます。","settings.snapshot_interval":"操作中の更新間隔","settings.snapshot_interval_hint":"ターミナルがアイドル状態になると更新頻度を下げ、通信量とリソースを節約します。","terminal.disconnected":"接続が切れました。再接続しています…","terminal.paneMissing":"このペインは閉じられました。別のペインに切り替えてください。","common.save":"保存","common.cancel":"キャンセル","common.confirm":"確認","common.ok":"OK","common.close":"閉じる","common.delete":"削除","common.copy":"コピー","conversationCopy.line":"行全体","conversationCopy.paragraph":"段落全体","common.rename":"名前を変更","common.create":"新規作成","common.back":"戻る","common.open":"開く","common.loading":"読み込み中…","common.done":"完了","common.retry":"再試行","app.browser":"ウェブプレビュー","browser.openTabs":"開いているウェブプレビュータブ","browser.history":"最近の閲覧","browser.closeTab":"{title} を閉じる","browser.newTab":"新しいタブ","browser.minimize":"最小化","browser.back":"戻る","browser.forward":"進む","browser.address":"アドレス","browser.addressPlaceholder":"URL またはポートを入力","browser.addressOrDirectoryPlaceholder":"URL を入力、またはフォルダを選択","browser.refresh":"更新","browser.stop":"読み込みを停止","browser.viewMode":"ページ幅","browser.narrowWidth":"狭い","browser.wideWidth":"広い","browser.closeTiming":"バックグラウンドタブを閉じる","browser.minutes":"{value} 分","browser.neverClose":"閉じない","browser.clearHistory":"消去","browser.emptyHistory":"最近の閲覧はまだありません","browser.loadFailed":"ページを読み込めません。アドレスを確認して再試行してください。","browser.retry":"再試行","browser.consentTitle":"ウェブプレビュー","browser.consentBody":"Handmux はこのウィンドウ内にページを埋め込みます。完全なブラウザではなく、開発サーバー、localhost、社内ネットワーク、埋め込みを許可するサイトの確認に適しています。Home からパソコン上の静的フォルダも選べます。","browser.consentComputer":"直接接続はスマホの回線を使います。プロキシ接続はパソコンから送信され、公開せずに社内ネットワークや localhost にアクセスできます。","browser.consentPrivate":"直接接続とプロキシでは Cookie とログイン状態が分かれ、プロキシセッションはこのデバイスごとに分離されます。","browser.consentLimits":"直接接続はサイトの iframe または CSP ポリシーでブロックされ、Handmux が原因を判別できない場合があります。PC プロキシはページを転送・書き換えますが、すべてのサイトとの互換性は保証しません。完全な閲覧機能が必要な場合は Safari、Chrome、またはシステムブラウザで開いてください。","browser.consentIdle":"バックグラウンドタブは既定で10分後に閉じます。直接接続したサイトの Cookie はスマホのブラウザに残ります。","browser.about":"ウェブプレビューについて","browser.acknowledge":"了解","browser.directMode":"スマホから直接","browser.proxyMode":"PC プロキシ経由","browser.directBadge":"直接","browser.proxyBadge":"プロキシ","browser.staticBadge":"静的","browser.chooseDirectory":"フォルダを選択","browser.staticOpening":"フォルダを開いています…","browser.directoryPickerHint":"Web ファイルを含むフォルダを選択してください。","browser.switchMode":"閲覧モードを切り替え","browser.menu":"ウェブプレビューメニュー","browser.connectionMode":"接続方法","browser.pageWidth":"ページ幅","browser.requestSiteVersion":"サイトに要求","browser.mobileSite":"モバイル版","browser.desktopSite":"PC 版","browser.zoomPage":"ページを拡大・縮小","browser.resetZoom":"ページのズームをリセット","browser.proxyLogin":"プロキシログイン","browser.proxyLoginHelpLabel":"プロキシログインについて","browser.proxyLoginHelp":"再起動後もログイン状態を維持できるよう、Handmux を実行しているコンピュータにプロキシ Cookie を暗号化して保存するかどうか。","browser.siteProxyCookie":"このサイトのプロキシ Cookie","browser.siteCookieHelpLabel":"このサイトのプロキシ Cookie について","browser.siteCookieHelp":"この端末でサイトの実 URL に一致するプロキシ Cookie のみを消去します。親ドメイン Cookie により関連する社内サイトからもログアウトする場合があります。直接接続の Cookie には影響しません。","browser.openMode":"開き方を選択","browser.historyMore":"その他の開き方","browser.historyActions":"その他の操作","browser.proxyLimitHint":"PC プロキシはページを転送・書き換えるため、すべてのサイトとの互換性は保証しません。","browser.proxyUnavailable":"パソコンのターミナルで handmux setup を実行し、「ウェブプレビュー」でプロキシドメインを設定してください。設定するまではスマホからの直接接続のみ利用できます。","browser.urlInvalid":"有効な HTTP または HTTPS アドレスを入力してください。","browser.tryProxy":"PC プロキシを試す","browser.openExternal":"システムブラウザで開く","browser.clearSiteLogin":"このサイトのプロキシ Cookie を消去","browser.clearAllLogin":"プロキシ Cookie をすべて消去","browser.clearSiteLoginConfirm":"現在の端末でこのサイトのプロキシログインを消去しますか?親ドメインの Cookie により関連する社内システムにも影響する場合があります。","browser.clearAllLoginConfirm":"現在の端末のプロキシログインをすべて消去しますか?スマホ直接接続のログインには影響しません。","browser.deleteHistoryEntry":"この項目を削除","browser.profileSaveFailed":"プロキシログイン設定を保存できません。サーバー接続を確認して再試行してください。","browser.profileClearFailed":"クリーンアップが完全には成功しませんでした。サーバー接続と保存権限を確認して、もう一度お試しください。","browser.profileSyncFailed":"プロキシログイン設定を同期できません。再試行するか、直接接続を使用してください。","browser.profileRecoveryWarning":"保存済みプロキシログインを復元できず、この端末の状態をリセットしました。","browser.retention1":"1 日","browser.retention7":"7 日","browser.retention30":"30 日","browser.retentionNotSaved":"保存しない","browser.retentionNever":"長期保存","settings.browserPersistLogin":"プロキシ Cookie をコンピュータに永続保存","settings.browserPersistLoginHint":"現在の端末だけに保存します。オフにしても、消去または期限切れまで現在のタブとログイン状態は残ります。","settings.browserRetention":"プロキシログイン保持期間","settings.browserDisablePersistConfirm":"現在の端末で今後のプロキシログイン変更の保存を停止しますか?現在のタブとログイン状態は残ります。","token.title":"アクセストークンが必要です","token.placeholder":"HANDMUX_TOKEN を貼り付け","settings.language":"言語 Language","settings.browserDefaultMode":"ウェブの既定モード","settings.browserDefaultModeHint":"アドレスバーから開く新しいタブと、保存済みモードがない履歴に使用します。","settings.browserEnabled":"ウェブプレビュー","settings.browserEnabledHint":"タブはこの端末専用です。オフにすると全タブを閉じますが、履歴は残ります。","home.empty":"ファイルが開かれていません","home.emptyHint":"「新規」タブでファイルを選択してください","home.remove":"削除","drawer.title":"セッション","drawer.empty":"セッションが紐付けられていません","drawer.unbind":"紐付け解除","drawer.bind":"セッションを紐付け","drawer.logout":"ログアウト","windowbar.newWindow":"新規ウィンドウ","rename.new_name":"新しい名前","rename.name_rule":"英数字とハイフンのみ(≤16文字)","rename.failed":"名前の変更に失敗しました。再試行してください","rename.saving":"保存中…","newwindow.title":"新規ウィンドウ","newwindow.window_name":"ウィンドウ名(任意)","newwindow.name_placeholder":"空白で自動命名 · 英数字/ハイフン ≤16","newwindow.name_rule":"英数字とハイフンのみ(≤16文字)","newwindow.start_dir":"開始ディレクトリ","newwindow.session_dir_named":"{dir}(セッションディレクトリ)","newwindow.session_dir_default":"セッションディレクトリ(デフォルト)","newwindow.choose":"選択","newwindow.reset_to_session_dir":"セッションディレクトリにリセット","newwindow.creating":"作成中…","startup.label":"起動コマンド(任意)","startup.aria":"起動コマンド","startup.preset_shell":"空のシェル(デフォルト)","startup.preset_claude":"claude(Claude Code を起動)","startup.preset_claude_continue":"claude -c(前回のセッションを継続)","startup.preset_codex":"codex(Codex CLI を起動)","startup.custom":"カスタム…","startup.custom_placeholder":'例:claude "ログインバグを修正"',"bind.title":"セッションを紐付け","bind.sessionName":"セッション名","bind.pickSession":"紐付けるセッションを選択","bind.newSession":"+ 新規セッション","bind.modeNew":"新規作成","bind.modeExisting":"既存を選択","bind.alreadyExists":"このセッションは既に存在します","bind.bind":"紐付け","bind.checking":"確認中…","bind.createAndOpen":"作成して開く","bind.creating":"作成中…","bind.createHint":"セッション「{name}」が存在しません。「作成して開く」をタップして作成してください","bind.alreadyBound":"このセッションはすでに紐付けられています","bind.createFailed":"作成に失敗しました。再試行してください","bind.invalidName":"英数字とハイフンのみ(≤16文字)","bind.desktopHint":"ここのセッション(スマホで作成したものも)は、PC で 1 コマンドで引き継げます:handmux open <名前>","bind.checkFailed":"確認に失敗しました。再試行してください","bind.startDir":"開始ディレクトリ","bind.homeDirDefault":"ホームディレクトリ(デフォルト)","bind.choose":"選択","bind.reset":"リセット","actionsheet.confirmAgain":"確認しますか?もう一度タップ","dirpicker.title":"ディレクトリを選択","inbox.title":"受信トレイ","inbox.working":"進行中","inbox.done":"完了","inbox.needs":"要対応","inbox.error":"エラー","inbox.clearDone":"結果をクリア","inbox.empty":"パネルの状態なし","inbox.enableTitle":"Claude Code の状態と通知を有効にする","inbox.enableHint":"Claude Code の受信トレイには Agent hooks が必要です。Codex CLI は Handmux の管理モードを使用してください。","inbox.enableBtn":"有効にする","inbox.enabling":"有効化中…","inbox.enableFailed":"有効化に失敗しました——サーバーログを確認してください。","idea.title":"アイデア","idea.editPlaceholder":"アイデアを編集…","idea.addPlaceholder":"アイデアを記録…","idea.add":"追加","idea.empty":"まだアイデアがありません。記録してみましょう","idea.dragSort":"ドラッグで並べ替え","idea.fillInput":"入力欄に挿入","idea.send":"送信","doclink.title":"ファイルを開く","changelog.title":"新機能","preview.static":"静的プレビュー","preview.remainTitle":"残り有効期限 — タップして更新 / 停止","preview.toPcView":"PCビューに切り替え","preview.toMobileView":"モバイルビューに切り替え","preview.pcView":"PCビュー","preview.mobileView":"モバイルビュー","preview.refresh":"更新","preview.minimize":"最小化","preview.ttlDialog":"プレビュー有効期限","preview.renew":"更新(1時間にリセット)","preview.stop":"プレビューを停止","preview.iframeTitle":"プレビュー","preview.zoomOut":"縮小","preview.zoomIn":"拡大","imageviewer.loadFailed":"画像の読み込みに失敗しました","imageviewer.saved":"保存しました。フォトライブラリまたは「ダウンロード」で確認できます","imageviewer.shareUnsupported":"画像の共有には Chrome または Safari が必要です","imageviewer.zoomOut":"縮小","imageviewer.zoomIn":"拡大","imageviewer.imageTitle":"画像","imageviewer.saveImage":"画像を保存","imageviewer.shareImage":"画像を共有","mic.stop":"音声入力を停止","mic.start":"音声入力","mic.recognizing":"音声を認識中","mic.error.tencentPermission":"Tencent Cloud が認識を拒否しました。現在の SecretId に asr:SentenceRecognition 権限を付与して再試行してください。","mic.error.tencentCredentials":"Tencent Cloud の認証情報が無効です。handmux setup で AppId、SecretId、SecretKey を確認してください。","mic.error.browserPermission":"マイクへのアクセスが許可されていません。ブラウザのサイト設定でマイクを許可して再試行してください。","mic.error.device":"マイクを使用できません。接続状態と、他のアプリが使用していないか確認してください。","mic.error.secureContext":"このアドレスではマイクを使用できません。HTTPS または localhost で Handmux を開いてください。","mic.error.tooLong":"録音が長すぎます。短くして再試行してください。","mic.error.notSelected":"選択した音声モードが有効ではありません。Handmux を再起動して再試行してください。","mic.error.noSpeech":"音声を認識できませんでした。もう一度お試しください。","mic.error.network":"音声サービスに接続できません。ネットワークを確認して再試行してください。","mic.error.provider":"音声サービスがリクエストを拒否しました:{reason}","mic.error.generic":"音声入力に失敗しました。再試行してください。","dock.send":"送信","dock.send.hint":"タップで送信 · 長押しで挿入","dock.phrases":"よく使うフレーズ","dock.attach":"添付","dock.history":"履歴","history.empty":"履歴はまだありません","history.scope":"このウィンドウの記録のみ","dock.input.placeholder":"メッセージを入力…","dock.input.enterDraft":"Shift + Enter で下書きモードへ","dock.input.exitDraft":"Esc でターミナルモードへ戻る · Shift + Enter で改行","dock.command.placeholder":"コマンドを入力 · Enterで実行","dock.mode.agent":"会話","dock.mode.toggle":"入力モードを切替","dock.mode.command":"コマンド","dock.mode.chat":"チャット","fav.title":"よく使う","fav.add":"追加","fav.addPlaceholder":"よく使う項目を追加…","dock.upload.aria":"ファイルをアップロード","dock.upload.title":"ファイルをアップロード(ホームのアップロードフォルダに保存、プロジェクトには含まない)","dock.upload.progress":"{name}{tag} をアップロード中","dock.upload.failed":"アップロード失敗:{names}","app.nameExists":"その名前はすでに使われています","app.renameFailed":"名前の変更に失敗しました。再試行してください","app.deleteFailed":"削除に失敗しました。再試行してください","app.moveFailed":"移動に失敗しました。再試行してください","app.sessionGone":"セッション「{name}」が存在しません。閉じられた可能性があります","app.docNotFound":"ファイルが存在しません","app.docTooLarge":"ファイルが大きすぎます(2MB超)","app.docUnsupported":"サポートされていないファイルまたはパス","app.docOpenFailed":"開くのに失敗しました。再試行してください","app.preview":"プレビュー","app.openPreview":"プレビューを開く","app.ideas":"アイデア","app.files":"ファイル","app.settings":"設定","app.renameSession":"セッション名を変更","app.renameWindow":"ウィンドウ名を変更","app.moveLeft":"◀ 左へ移動","app.moveRight":"右へ移動 ▶","app.deleteWindow":"ウィンドウを削除","pane.splitH":"左右に分割","pane.splitV":"上下に分割","pane.manage":"分割を管理","pane.close":"ペインを閉じる","pane.closeConfirm":"閉じますか?もう一度タップ","pane.splitFailed":"分割に失敗しました","pane.closeFailed":"閉じる操作に失敗しました","resize.windowWidth":"ウィンドウ幅","resize.paneWidth":"ペイン幅","resize.columns":"{n} 列","resize.restore":"復元","resize.restoreAutoWidth":"自動幅に戻す","resize.restoreRatio":"分割比率を復元","app.deleteLastWindowConfirm":"これは最後のウィンドウです。削除するとセッション全体が閉じます!もう一度タップ","app.deleteConfirm":"削除しますか?もう一度タップ","app.cannotLocate":"場所を特定できません","app.pickItsDir":"。ディレクトリを選択してください:","app.noBoundSession":"セッションが紐付けられていません","app.tapToBind":"タップして紐付け","app.selectSessionHint":"左上の ☰ をタップしてセッションを選択","app.backToExit":"もう一度戻るで終了します","settings.title":"設定","settings.group_global":"グローバル設定","settings.group_general":"一般","settings.group_voice":"音声文字起こし","settings.voice_enabled":"有効状態","settings.voice_on":"有効","settings.voice_off":"無効","settings.voice_provider":"現在のプロバイダー","settings.voice_profile_tencent_streaming":"Tencent Cloud リアルタイム音声認識","settings.voice_profile_tencent_sentence":"Tencent Cloud 一文音声認識","settings.voice_profile_xfyun":"iFlytek 音声ディクテーション","settings.voice_not_configured":"未設定","settings.voice_filler_filter":"フィラー語の除去","settings.voice_filter_low":"低","settings.voice_filter_medium":"中","settings.voice_filter_high":"高","settings.voice_not_supported":"未対応","settings.voice_setup_hint":"ターミナルで handmux setup を実行し、「音声入力」で設定してください。","settings.project_task_beta":"プロジェクトタスク Beta","settings.group_terminal":"ターミナル","settings.group_chat":"チャット","settings.group_notifications":"通知","settings.group_about":"情報","settings.terminal_font_size":"ターミナルのフォントサイズ","settings.terminal_font_decrease":"ターミナルのフォントを縮小","settings.terminal_font_increase":"ターミナルのフォントを拡大","settings.terminal_font_auto":"自動調整","settings.terminal_font_auto_title":"高さに合わせて自動調整","settings.conversation_font_size":"会話のフォントサイズ","settings.conversation_font_decrease":"会話のフォントを縮小","settings.conversation_font_increase":"会話のフォントを拡大","settings.conversation_font_default":"デフォルトに戻す","settings.conversation_font_hint":"10〜20px の間を 1px ずつ調整できます。会話メッセージの本文と、その中の Markdown およびコードのみに影響します。","settings.keyboard_mode":"キーボードモード","settings.keyboard_mode_auto":"自動判定","settings.keyboard_mode_mobile":"モバイル","settings.keyboard_mode_desktop":"デスクトップ","settings.keyboard_mode_hint":"このブラウザだけに適用されます。判定が違う場合は手動で選択できます。","settings.group_agent_integration":"Agent 連携","settings.conversation_view_agent":"{agent} 会話ビュー","settings.experimental":"試験機能","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"処理中…","settings.agent_integration_load_error":"Agent の状態を確認できません。","settings.agent_integration_action_error":"設定できませんでした。パソコンで次を実行してください:","settings.agent_integration_conflict_hint":"{agent} に既存の設定があります。パソコンで診断してください:","settings.agent_integration_not_installed_hint":"このパソコンに {agent} がインストールされていません。","settings.agent_integration_initialize_first_hint":"パソコンで {agent} を一度起動してから、ここに戻って有効にしてください。","settings.agent_integration_enable":"有効にする","settings.agent_integration_repair":"修復","settings.agent_integration_loading":"確認中…","settings.agent_integration_status_ready":"準備完了","settings.agent_integration_status_not_enabled":"未有効","settings.agent_integration_status_needs_repair":"修復が必要","settings.agent_integration_status_conflict":"確認が必要","settings.agent_integration_status_not_installed":"未インストール","settings.path_highlight":"ファイルパスをハイライト","settings.path_highlight_hint":"ターミナル内のタップ可能なファイルパスに色を付けます。オフでもパスはタップできます。","settings.whats_new":"新機能","settings.view_changelog":"変更履歴を表示","settings.reload_app":"アプリを再読み込み","settings.has_update":"更新あり","settings.version":"バージョン","settings.feedback":"フィードバック","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat グループ","settings.feedback_hint":"バグ報告や要望は Issue へ — 必ず追跡・返信されます。","settings.update_available":"バージョン {v} が利用可能","settings.update_more":"ほか {n} バージョンの更新","settings.update_how":"パソコンで実行:","settings.push_notifications":"プッシュ通知","settings.notify_on":"有効 ✓","settings.notify_enable":"デバイス通知を有効にする","settings.notify_enabled":"有効にしました。ウェルカム通知が届くはずです","settings.notify_disabled":"無効","settings.notify_failed":"操作に失敗しました","settings.notify_disable_title":"プッシュ通知をオフにしますか?","settings.notify_disable_hint":"このデバイスには「要対応」「完了」およびスクリプトからのプッシュ通知が届かなくなります。いつでも再度オンにできます。","settings.notify_disable_confirm":"オフにする","settings.processing":"処理中","settings.push_hint":"「要対応」と「完了」を監視:注目しているセッションが承認/回答を必要としているとき、またはラウンドが完了したときにこのデバイスへ通知します。","settings.push_unsupported":"プッシュ通知には Chrome または Safari が必要です","settings.preview_site":"プレビューサイト","settings.preview_static_site":"静的サイトをプレビュー","settings.preview_running_static":"静的プレビュー 実行中","settings.preview_remain_title":"残り有効期限","settings.preview_remain":"残り {time}","settings.preview_renew":"更新","settings.preview_confirm_stop":"停止を確認","settings.preview_stop":"停止","settings.preview_name":"名前:{name}","settings.preview_port":"(ポート:{port})","settings.preview_type":"プレビュータイプ","settings.preview_off":"無効","settings.preview_static":"静的","settings.preview_off_hint":"プレビューは無効です。「静的」を選択して開始してください。","settings.preview_off_hint_both":"プレビューは無効です。「静的」または「ダイナミック」を選択して開始してください。","settings.preview_pick_dir":"ディレクトリを選択して開始","settings.preview_static_hint":"index.html を含むディレクトリを選択して、スマートフォンでプレビュー。","settings.preview_port_placeholder":"ポート番号(例:3000)","settings.preview_port_label":"ポート","settings.preview_starting":"起動中…","settings.preview_start":"起動","settings.dir_picker_hint":"プレビューする静的サイトのディレクトリを選択(index.html を含む)","settings.err_port_not_listening":"そのポートはリッスンしていません。サービスが起動しているか確認してください","settings.err_bad_port":"ポート番号が無効です(1〜65535)","settings.err_start_failed":"起動に失敗しました","localurl.title":"Web サイトを開く","localurl.open":"ブラウザで開く","localurl.notListening":"ポート :{port} で待ち受けているサービスがありません。","localurl.badProtocol":"このリンクはプロキシ可能な HTTP または HTTPS アドレスではありません。","localurl.network":"handmux サービスに接続できません。ネットワークを確認して再試行してください。","localurl.failed":"Web サイトを開けません。アドレスを確認して再試行してください。","filebrowser.openDirFailed":"ディレクトリを開けませんでした","filebrowser.copiedPath":"パスをコピーしました:{abs}","filebrowser.mkdirFailed":"ディレクトリの作成に失敗しました(名前が無効または既に存在します)","filebrowser.downloading":"{name} をダウンロード中","filebrowser.downloadFailed":"ダウンロードに失敗しました","filebrowser.uploading":"{name}{tag} をアップロード中","filebrowser.uploadFailed":"アップロードに失敗しました","filebrowser.uploadPartialFailed":"以下のファイルのアップロードに失敗しました:{names}","filebrowser.sessionDir":"セッションディレクトリ","filebrowser.jumpToSessionDir":"現在のセッションディレクトリへ移動","filebrowser.parentDir":"親ディレクトリ","filebrowser.rootSelect":"ルートディレクトリを切り替え(ホーム / 一時)","filebrowser.pathPlaceholder":"パスを入力(リアルタイムフィルタ / ジャンプ)","filebrowser.newFolder":"新規フォルダ","filebrowser.createBtn":"作成","filebrowser.uploadFile":"ファイルをアップロード","filebrowser.uploadToCurrentDir":"現在のディレクトリにアップロード","filebrowser.enterSubdirToUpload":"サブディレクトリに移動してからアップロードしてください","filebrowser.folderNamePlaceholder":"フォルダ名","filebrowser.uploadPendingTo":"「{name}」を現在のディレクトリにアップロード","filebrowser.enterSubdirFirst":"(先にサブディレクトリに移動してください)","filebrowser.upload":"アップロード","filebrowser.savedToDownloads":"「{name}」を「ダウンロード」フォルダに保存しました。ファイルマネージャーで確認できます","filebrowser.noMatches":"一致するファイルまたはディレクトリがありません","filebrowser.tooMany":"合計 {total} 件、最初の {shown} 件のみ表示——パス欄にキーワードを入力してフィルタできます","filebrowser.previewUnsupported":"このファイルタイプのプレビューはサポートされていません。右のボタンでダウンロードできます","filebrowser.copyAbsPath":"絶対パスをコピー","filebrowser.download":"ダウンロード","filebrowser.pickThisDir":"このディレクトリを選択 {path}","filebrowser.downloadConfirm":"{name} をダウンロードしますか?","filemanager.files":"ファイル","filemanager.closeTab":"タブを閉じる","filemanager.minimize":"最小化","filemanager.recent":"最近","filemanager.directory":"ディレクトリ","git.errReadRepo":"リポジトリを読み込めませんでした","git.errLoad":"読み込みに失敗しました","git.noRepoInDir":"このディレクトリにはまだ git リポジトリがありません — 別のディレクトリを選ぶか、ここで git init してください。","git.outsideRoots":"このフォルダは handmux がアクセスできる範囲外です — ホームディレクトリと /tmp のみ開けます。リポジトリをホーム配下に移すとここで閲覧できます。","git.errReadDir":"ディレクトリを読み込めませんでした","git.commitDetail":"コミット詳細","git.diff":"差分","git.bindRepo":"リポジトリを紐付け","git.collapse":"折りたたむ","git.currentBranch":"現在のブランチ","git.switchViewedBranch":"表示するブランチを切り替え","git.switchBranch":"ブランチを切り替え","git.noBranches":"ブランチがありません","git.noRepoBound":"リポジトリが紐付けられていません。左上の「+」をタップしてディレクトリを選択してください。","git.changes":"変更","git.commits":"コミット","git.pullToLoadMore":"引っ張ってさらに読み込む","git.pickerHint":"ディレクトリを選択すると、その中の git リポジトリを自動的に検索します","git.cleanTree":"ワーキングツリーはクリーンです","git.noCommits":"コミットがありません","git.noDiff":"差分なし","git.fontSmaller":"フォントを縮小","git.fontLarger":"フォントを拡大","git.diffTruncated":"差分が大きすぎるため、切り捨てられました","cmd.panel":"コマンドパネル","cmd.title":"コマンド","cmd.empty":"コマンドがありません。送信するか、よく使うものを保存してください","cmd.favorites":"お気に入り","cmd.scopeGlobal":"グローバル · 全セッション","cmd.recent":"最近","cmd.scopeSession":"このセッションのみ","cmd.favorite":"お気に入りに追加","cmd.unfavorite":"お気に入りから削除","doc.home":"最近","doc.read":"読み上げ","doc.pauseRead":"一時停止","doc.resumeRead":"再開","doc.stopRead":"読み上げを停止","doc.rate":"読み上げ速度","doc.fontSmaller":"フォントを縮小","doc.fontLarger":"フォントを拡大","inbox.view.working":"進行中","inbox.view.done":"完了","inbox.view.needs":"要対応","inbox.view.error":"エラー","push.unsupported":"プッシュ通知には Chrome または Safari が必要です","push.iosAddToHome":"iOS では先にこのサイトを「ホーム画面に追加」し、ホーム画面のアイコンから開いてください","a2hs.title":"handmux をホーム画面に追加","a2hs.lead":"アプリのように全画面で開けます。iPhone では、pane があなたを必要とするときの通知もこれで届きます。","a2hs.install":"handmux をインストール","a2hs.ios1":"Safari の共有ボタン(⬆︎ の四角)をタップ。","a2hs.ios2":"「その他」をタップ、または下にスクロール。","a2hs.ios3":"「ホーム画面に追加」を選び、「追加」をタップ。","a2hs.iosHint":"Safari で:共有 → その他 → ホーム画面に追加。","a2hs.iosOpenSafari":"現在 Safari ではありません。Safari でこのページを開いてからホーム画面に追加してください(他の iOS ブラウザではインストールできません)。","a2hs.androidManual":"ブラウザのメニュー(⋮)から「ホーム画面に追加」または「アプリをインストール」を選択。","a2hs.later":"あとで","push.permissionTimeout":"通知権限の結果が返されませんでした。システム設定で handmux またはブラウザの通知権限を確認して再試行してください。","push.permissionDenied":"通知の権限が拒否されました","push.swRegisterTimeout":"通知サービスの登録がタイムアウトしました。接続を確認して再試行してください。","push.swRegisterFailed":"通知サービスを登録できませんでした:{reason}。このサイトのデータを消去し、再度開いてお試しください。","push.swTimeout":"通知サービスは登録されましたが有効化できませんでした。このサイトのデータを消去し、再度開いてお試しください。","push.unknownReason":"原因不明","push.configTimeout":"プッシュ設定の読み込みがタイムアウトしました。handmux サーバーへの接続を確認して再試行してください。","push.browserTimeout":"ブラウザのプッシュサービスが応答しません。Android Chrome では Google Play 開発者サービスが利用可能か確認して再試行してください。","push.noVapid":"サーバーにプッシュ通知(VAPID)が設定されていません","push.reportTimeout":"購読は作成されましたが、サーバーへの登録がタイムアウトしました。接続を確認して再試行してください。","push.subscriptionExpired":"Chrome が期限切れのプッシュ購読を返しました。リセットしたので、もう一度「通知を有効にする」をタップしてください。","push.deliveryRejected":"プッシュサービスが新しい購読を拒否しました。サーバーログを確認して再試行してください。","push.subscribeFailed":"サブスクリプションの登録に失敗しました","push.sendFailed":"送信に失敗しました","pushInbox.loadFailed":"通知を読み込めませんでした。接続を確認して再試行してください。","pushInbox.deleteFailed":"通知を削除できませんでした。メッセージは保持されています。再試行してください。","pushInbox.retry":"再試行","pushInbox.deliveryPending":"送信中","pushInbox.deliverySuccess":"成功","pushInbox.deliveryFailed":"失敗","pushInbox.deliveryReasonExpired":"購読の有効期限切れ","pushInbox.deliveryReasonRateLimited":"プッシュサービスの制限","pushInbox.deliveryReasonUnavailable":"プッシュサービスを利用できません","pushInbox.deliveryReasonRejected":"プッシュサービスが拒否","pushInbox.deliveryReasonNetwork":"ネットワークエラー","pushInbox.deliveryReasonNotConfigured":"プッシュ未設定","pushInbox.deliveryReasonUnknown":"原因不明","api.loadFailed":"読み込みに失敗しました","api.uploadFailed":"アップロードに失敗しました","upload.title":"アップロード中","upload.processing":"送信完了 — サーバーで受信中…","api.uploadBadDir":"そのディレクトリへはアップロードできません","api.uploadDuplicate":"同名のファイルが既に存在します","api.uploadTooLarge":"ファイルが大きすぎます(上限 50MB)","api.uploadBadType":"サポートされていないファイルタイプです","time.secAgo":"{n}秒前","time.minAgo":"{n}分前","time.hourAgo":"{n}時間前","time.dayAgo":"{n}日前","time.expired":"期限切れ","time.minutes":"{n} 分","workspace.bootDetected":"コンピュータの再起動を検出しました","workspace.tmuxDetected":"tmux の再起動を検出しました","workspace.summary":"前回のワークスペース · {sessions} セッション · {time} に保存","workspace.restoreLast":"前回のワークスペースを復元","workspace.partialCard":"残り {failures} セッションの確認が必要です","workspace.unknownTime":"時刻不明","workspace.savedAt":"{time} に保存","workspace.topologySummary":"{sessions} セッション · {windows} ウィンドウ · {panes} ペイン","workspace.planSummary":"{restore} セッションを復元;{already} セッションは既に存在します","workspace.renameRule":"同名のセッションが現在存在する場合にのみ、復元名に -restored が付きます。","workspace.nonDestructive":"現在のセッションは変更、名前変更、停止されません。","workspace.progress":"復元中 {completed} / {total}…","workspace.progressDone":"復元済み {completed} / {total}","workspace.complete":"ワークスペースを復元しました。","workspace.completedSummary":"今回の復元:{sessions} セッション · {windows} ウィンドウ · {panes} ペイン","workspace.rebindHint":"復元したセッションは自動表示されません。この端末にバインドするセッションを選択できます。","workspace.rebind":"セッションを再バインド","workspace.sessionFailure":"{session}:{reason}","workspace.unknownSession":"不明なセッション","workspace.restore":"復元","workspace.ignore":"このバックアップを無視","workspace.protectionTitle":"ワークスペースは保護されていません","workspace.protection.live-corrupt":"ワークスペース状態のコピーが破損しています。ディスクと ~/.handmux の権限を確認し、handmux を再起動してください。","workspace.protection.live-unavailable":"ワークスペース状態を読み書きできません。空き容量と ~/.handmux の権限を確認し、handmux を再起動してください。","workspace.protection.unknown":"バックグラウンドスナップショットを利用できません。コンピュータの handmux ログを確認してください。","workspace.error.restore-interrupted":"復元が中断されました;このバックアップを再試行してください","workspace.error.checkpoint-not-found":"このバックアップは利用できません;更新して別のバックアップを選んでください","workspace.error.storage-full":"ストレージの空きがありません;空き容量を増やして再試行してください","workspace.error.permission-denied":"ワークスペースを書き込めません;権限を確認して再試行してください","workspace.error.plan-failed":"復元計画が変わりました;更新して再試行してください","workspace.error.agent-unavailable":"Agent を再開できません;復元した shell を開いて手動で再試行してください","workspace.error.tmux-unavailable":"tmux を利用できません;tmux が起動中か確認して再試行してください","workspace.error.restore-failed":"セッションを復元できませんでした;handmux ログを確認して再試行してください","workspace.error.operation-not-found":"この復元処理は利用できません。バックアップの復元をやり直してください","workspace.sessionWarning":"{session}:{reason}","workspace.warning.cwd-fallback":"作業ディレクトリを使用できなかったため、ホームディレクトリに復元しました","workspace.warning.layout-fallback":"ペイン配置を完全に復元できなかったため、既定の配置を維持しました","workspace.warning.agent-warning":"Agent を自動再開できませんでした。復元したシェルは利用できます","workspace.warning.live-reconcile-failed":"現在のワークスペース状態を照合できませんでした。handmux ログを確認してください","workspace.warning.workspace-unavailable":"ワークスペースストレージを一時的に利用できません。空き容量と権限を確認してください","workspace.warning.restore-warning":"復元は完了しましたが、確認が必要な警告があります","chat.plan.currentTitle":"現在のタスク","chat.plan.historyTitle":"このターンのタスク","chat.plan.working":"作業中:{step}","chat.plan.waiting":"確認待ち:{step}","chat.plan.finalizing":"結果をまとめています","chat.plan.complete":"完了","chat.plan.incomplete":"未完了","chat.plan.status.pending":"未着手","chat.plan.status.inProgress":"進行中","chat.plan.status.completed":"完了"},ZO={"terminal.transport_live":"실시간","terminal.transport_snapshot":"스냅샷","terminal.transport_detail_title":"터미널 전송 상태","terminal.transport_detail_configured":"설정 모드","terminal.transport_detail_current":"현재 모드","terminal.transport_detail_connection":"연결 상태","terminal.transport_detail_manual":"스냅샷 가져오기를 직접 선택했으므로 자동으로 전환되지 않습니다.","terminal.transport_detail_live":"터미널이 실시간 푸시를 정상적으로 받고 있습니다.","terminal.transport_detail_fallback":"실시간 푸시가 불안정하여 스냅샷 가져오기로 전환했습니다.","terminal.transport_detail_unavailable":"실시간 연결을 설정할 수 없습니다. 리버스 프록시가 WebSocket을 지원하는지 확인하세요.","terminal.transport_detail_waiting":"연결이 안정되면 실시간 푸시 복귀를 시도합니다.","terminal.transport_detail_retry":"약 {seconds}초 후 실시간 푸시 복귀를 시도합니다.","terminal.connection_connecting":"확인 중","terminal.connection_good":"양호","terminal.connection_degraded":"보통","terminal.connection_poor":"나쁨","settings.terminal_transport":"터미널 전송 모드","settings.terminal_transport_live":"실시간 푸시","settings.terminal_transport_snapshot":"스냅샷 가져오기","settings.terminal_transport_hint":"실시간 푸시는 WebSocket을 사용하며, 네트워크가 불안정하면 스냅샷 가져오기로 전환되고 30초 동안 안정되면 복귀를 시도합니다.","settings.snapshot_interval":"활성 상태 업데이트 간격","settings.snapshot_interval_hint":"터미널이 유휴 상태가 되면 트래픽과 리소스 사용을 줄이기 위해 업데이트 빈도를 낮춥니다.","terminal.disconnected":"연결이 끊겼습니다. 다시 연결하는 중…","terminal.paneMissing":"이 창이 닫혔습니다. 다른 창으로 전환하세요.","common.save":"저장","common.cancel":"취소","common.confirm":"확인","common.ok":"확인","common.close":"닫기","common.delete":"삭제","common.copy":"복사","conversationCopy.line":"전체 줄","conversationCopy.paragraph":"전체 단락","common.rename":"이름 변경","common.create":"새로 만들기","common.back":"뒤로","common.open":"열기","common.loading":"로드 중…","common.done":"완료","common.retry":"다시 시도","app.browser":"웹 미리보기","browser.openTabs":"열린 웹 미리보기 탭","browser.history":"최근 방문","browser.closeTab":"{title} 닫기","browser.newTab":"새 탭","browser.minimize":"최소화","browser.back":"뒤로","browser.forward":"앞으로","browser.address":"주소","browser.addressPlaceholder":"URL 또는 포트 입력","browser.addressOrDirectoryPlaceholder":"URL을 입력하거나 폴더 선택","browser.refresh":"새로고침","browser.stop":"로딩 중지","browser.viewMode":"페이지 너비","browser.narrowWidth":"좁게","browser.wideWidth":"넓게","browser.closeTiming":"백그라운드 탭 자동 닫기","browser.minutes":"{value}분","browser.neverClose":"닫지 않음","browser.clearHistory":"지우기","browser.emptyHistory":"최근 방문이 없습니다","browser.loadFailed":"페이지를 불러올 수 없습니다. 주소를 확인하고 다시 시도하세요.","browser.retry":"다시 시도","browser.consentTitle":"웹 미리보기","browser.consentBody":"Handmux는 이 창 안에 페이지를 삽입합니다. 완전한 브라우저가 아니며 개발 서버, localhost, 내부망 및 삽입을 허용하는 사이트를 확인하는 데 적합합니다. Home에서 컴퓨터의 정적 폴더도 선택할 수 있습니다.","browser.consentComputer":"직접 연결은 휴대폰 네트워크를 사용합니다. 프록시 요청은 컴퓨터에서 전송되어 내부망과 localhost를 공개하지 않고 접근할 수 있습니다.","browser.consentPrivate":"직접 연결과 프록시는 Cookie와 로그인 상태를 공유하지 않으며, 프록시 세션은 이 기기별로 분리됩니다.","browser.consentLimits":"휴대폰 직접 연결은 사이트의 iframe 또는 CSP 정책에 의해 차단될 수 있고 Handmux가 원인을 판단하지 못할 수 있습니다. 컴퓨터 프록시는 페이지를 전달하고 다시 작성하지만 모든 사이트와의 호환성을 보장하지 않습니다. 완전한 탐색 기능이 필요하면 Safari, Chrome 또는 시스템 브라우저에서 여세요.","browser.consentIdle":"백그라운드 탭은 기본 10분 후 닫힙니다. 직접 연결한 사이트의 Cookie는 휴대폰 브라우저에 남습니다.","browser.about":"웹 미리보기 정보","browser.acknowledge":"알겠습니다","browser.directMode":"휴대폰에서 직접","browser.proxyMode":"컴퓨터 프록시 경유","browser.directBadge":"직접","browser.proxyBadge":"프록시","browser.staticBadge":"정적","browser.chooseDirectory":"폴더 선택","browser.staticOpening":"폴더 여는 중…","browser.directoryPickerHint":"웹 파일이 들어 있는 폴더를 선택하세요.","browser.switchMode":"탐색 모드 전환","browser.menu":"웹 미리보기 메뉴","browser.connectionMode":"연결 방식","browser.pageWidth":"페이지 너비","browser.requestSiteVersion":"사이트에 요청","browser.mobileSite":"모바일판","browser.desktopSite":"데스크톱판","browser.zoomPage":"웹페이지 확대/축소","browser.resetZoom":"웹페이지 확대/축소 재설정","browser.proxyLogin":"프록시 로그인","browser.proxyLoginHelpLabel":"프록시 로그인 정보","browser.proxyLoginHelp":"재시작 후에도 로그인 상태를 유지할 수 있도록 Handmux를 실행하는 컴퓨터에 프록시 Cookie를 암호화해 저장할지 여부입니다.","browser.siteProxyCookie":"이 사이트의 프록시 Cookie","browser.siteCookieHelpLabel":"이 사이트의 프록시 Cookie 정보","browser.siteCookieHelp":"현재 기기에서 사이트의 실제 URL과 일치하는 프록시 Cookie만 정리합니다. 상위 도메인 Cookie로 인해 관련 내부 사이트에서도 로그아웃될 수 있습니다. 직접 연결 Cookie는 영향을 받지 않습니다.","browser.openMode":"열기 방식 선택","browser.historyMore":"더 많은 열기 옵션","browser.historyActions":"추가 작업","browser.proxyLimitHint":"컴퓨터 프록시는 페이지를 전달하고 다시 작성하므로 모든 사이트와의 호환성을 보장하지 않습니다.","browser.proxyUnavailable":"컴퓨터 터미널에서 handmux setup을 실행하고 “웹 미리보기”에서 프록시 도메인을 설정하세요. 설정 전에는 휴대폰 직접 연결만 사용할 수 있습니다.","browser.urlInvalid":"유효한 HTTP 또는 HTTPS 주소를 입력하세요.","browser.tryProxy":"컴퓨터 프록시 사용","browser.openExternal":"시스템 브라우저에서 열기","browser.clearSiteLogin":"이 사이트의 프록시 Cookie 정리","browser.clearAllLogin":"모든 프록시 Cookie 정리","browser.clearSiteLoginConfirm":"현재 기기에서 이 사이트의 프록시 로그인을 정리할까요? 상위 도메인 Cookie로 인해 관련 내부 시스템에도 영향을 줄 수 있습니다.","browser.clearAllLoginConfirm":"현재 기기의 프록시 로그인을 모두 정리할까요? 휴대폰 직접 연결 로그인에는 영향이 없습니다.","browser.deleteHistoryEntry":"이 기록 삭제","browser.profileSaveFailed":"프록시 로그인 설정을 저장하지 못했습니다. 서버 연결을 확인하고 다시 시도하세요.","browser.profileClearFailed":"정리가 완전히 완료되지 않았습니다. 서버 연결과 저장 권한을 확인한 후 다시 시도하세요.","browser.profileSyncFailed":"프록시 로그인 설정을 동기화하지 못했습니다. 다시 시도하거나 직접 연결을 사용하세요.","browser.profileRecoveryWarning":"저장된 프록시 로그인을 복구하지 못해 현재 기기의 상태를 초기화했습니다.","browser.retention1":"1일","browser.retention7":"7일","browser.retention30":"30일","browser.retentionNotSaved":"저장 안 함","browser.retentionNever":"장기 저장","settings.browserPersistLogin":"컴퓨터에 프록시 Cookie 영구 저장","settings.browserPersistLoginHint":"현재 기기에만 저장됩니다. 꺼도 정리하거나 만료될 때까지 현재 탭과 로그인 상태는 유지됩니다.","settings.browserRetention":"프록시 로그인 보관 기간","settings.browserDisablePersistConfirm":"현재 기기에서 이후 프록시 로그인 변경 저장을 중지할까요? 현재 탭과 로그인 상태는 유지됩니다.","token.title":"액세스 토큰이 필요합니다","token.placeholder":"HANDMUX_TOKEN 붙여넣기","settings.language":"언어 Language","settings.browserDefaultMode":"기본 웹 모드","settings.browserDefaultModeHint":"주소 표시줄에서 여는 새 탭과 저장된 모드가 없는 방문 기록에 사용됩니다.","settings.browserEnabled":"웹 미리보기","settings.browserEnabledHint":"탭은 이 기기에만 속합니다. 끄면 모든 탭을 닫지만 방문 기록은 유지합니다.","home.empty":"열린 파일이 없습니다","home.emptyHint":"「새로 만들기」 탭에서 파일을 선택하세요","home.remove":"제거","drawer.title":"세션","drawer.empty":"연결된 세션이 없습니다","drawer.unbind":"연결 해제","drawer.bind":"세션 연결","drawer.logout":"로그아웃","windowbar.newWindow":"새 창","rename.new_name":"새 이름","rename.name_rule":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","rename.failed":"이름 변경에 실패했습니다. 다시 시도하세요","rename.saving":"저장 중…","newwindow.title":"새 창","newwindow.window_name":"창 이름(선택 사항)","newwindow.name_placeholder":"비워두면 자동 이름 지정 · 영문/숫자/하이픈 ≤16","newwindow.name_rule":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","newwindow.start_dir":"시작 디렉토리","newwindow.session_dir_named":"{dir}(세션 디렉토리)","newwindow.session_dir_default":"세션 디렉토리(기본값)","newwindow.choose":"선택","newwindow.reset_to_session_dir":"세션 디렉토리로 초기화","newwindow.creating":"생성 중…","startup.label":"시작 명령(선택 사항)","startup.aria":"시작 명령","startup.preset_shell":"빈 셸(기본값)","startup.preset_claude":"claude(Claude Code 시작)","startup.preset_claude_continue":"claude -c(이전 세션 이어서)","startup.preset_codex":"codex(Codex CLI 시작)","startup.custom":"사용자 정의…","startup.custom_placeholder":'예:claude "로그인 버그 수정"',"bind.title":"세션 연결","bind.sessionName":"세션 이름","bind.pickSession":"연결할 세션 선택","bind.newSession":"+ 새 세션","bind.modeNew":"새 세션","bind.modeExisting":"기존 세션","bind.alreadyExists":"이미 존재하는 세션입니다","bind.bind":"연결","bind.checking":"확인 중…","bind.createAndOpen":"생성 후 열기","bind.creating":"생성 중…","bind.createHint":"세션「{name}」이 존재하지 않습니다. 「생성 후 열기」를 탭하여 생성하세요","bind.alreadyBound":"이미 연결된 세션입니다","bind.createFailed":"생성에 실패했습니다. 다시 시도하세요","bind.invalidName":"영문자, 숫자, 하이픈만 사용 가능(≤16자)","bind.desktopHint":"여기의 세션(폰에서 만든 것 포함)은 컴퓨터에서 명령 하나로 이어받을 수 있습니다: handmux open <이름>","bind.checkFailed":"확인에 실패했습니다. 다시 시도하세요","bind.startDir":"시작 디렉토리","bind.homeDirDefault":"홈 디렉토리(기본값)","bind.choose":"선택","bind.reset":"초기화","actionsheet.confirmAgain":"확인하시겠습니까? 한 번 더 탭하세요","dirpicker.title":"디렉토리 선택","inbox.title":"받은 편지함","inbox.working":"진행 중","inbox.done":"완료","inbox.needs":"확인 필요","inbox.error":"오류","inbox.clearDone":"결과 지우기","inbox.empty":"패널 상태 없음","inbox.enableTitle":"Claude Code 상태 및 알림 활성화","inbox.enableHint":"Claude Code 받은편지함에는 Agent hooks가 필요합니다. Codex CLI는 Handmux 관리 모드를 사용하세요.","inbox.enableBtn":"활성화","inbox.enabling":"활성화 중…","inbox.enableFailed":"활성화에 실패했습니다——서버 로그를 확인하세요.","idea.title":"아이디어","idea.editPlaceholder":"아이디어 편집…","idea.addPlaceholder":"아이디어를 기록하세요…","idea.add":"추가","idea.empty":"아직 아이디어가 없습니다. 하나 기록해보세요","idea.dragSort":"드래그하여 정렬","idea.fillInput":"입력창에 삽입","idea.send":"보내기","doclink.title":"파일 열기","changelog.title":"새 기능","preview.static":"정적 미리보기","preview.remainTitle":"남은 유효 기간 — 탭하여 갱신 / 중지","preview.toPcView":"PC 보기로 전환","preview.toMobileView":"모바일 보기로 전환","preview.pcView":"PC 보기","preview.mobileView":"모바일 보기","preview.refresh":"새로 고침","preview.minimize":"최소화","preview.ttlDialog":"미리보기 유효 기간","preview.renew":"갱신(1시간으로 초기화)","preview.stop":"미리보기 중지","preview.iframeTitle":"미리보기","preview.zoomOut":"축소","preview.zoomIn":"확대","imageviewer.loadFailed":"이미지를 불러오지 못했습니다","imageviewer.saved":"저장되었습니다. 사진 앱 또는 「다운로드」에서 확인할 수 있습니다","imageviewer.shareUnsupported":"이미지 공유는 Chrome 또는 Safari가 필요합니다","imageviewer.zoomOut":"축소","imageviewer.zoomIn":"확대","imageviewer.imageTitle":"이미지","imageviewer.saveImage":"이미지 저장","imageviewer.shareImage":"이미지 공유","mic.stop":"음성 입력 중지","mic.start":"음성 입력","mic.recognizing":"음성 인식 중","mic.error.tencentPermission":"Tencent Cloud가 인식을 거부했습니다. 현재 SecretId에 asr:SentenceRecognition 권한을 부여한 뒤 다시 시도하세요.","mic.error.tencentCredentials":"Tencent Cloud 자격 증명이 올바르지 않습니다. handmux setup에서 AppId, SecretId, SecretKey를 확인하세요.","mic.error.browserPermission":"마이크 접근이 차단되었습니다. 브라우저 사이트 설정에서 마이크를 허용한 뒤 다시 시도하세요.","mic.error.device":"마이크를 사용할 수 없습니다. 장치 연결과 다른 앱의 사용 여부를 확인하세요.","mic.error.secureContext":"이 주소에서는 마이크를 사용할 수 없습니다. HTTPS 또는 localhost로 Handmux를 여세요.","mic.error.tooLong":"녹음이 너무 깁니다. 더 짧게 녹음한 뒤 다시 시도하세요.","mic.error.notSelected":"선택한 음성 모드가 활성화되지 않았습니다. Handmux를 재시작한 뒤 다시 시도하세요.","mic.error.noSpeech":"음성을 인식하지 못했습니다. 다시 시도하세요.","mic.error.network":"음성 서비스에 연결할 수 없습니다. 네트워크를 확인한 뒤 다시 시도하세요.","mic.error.provider":"음성 서비스가 요청을 거부했습니다: {reason}","mic.error.generic":"음성 입력에 실패했습니다. 다시 시도하세요.","dock.send":"보내기","dock.send.hint":"탭하여 보내기 · 길게 눌러 삽입","dock.phrases":"자주 쓰는 문구","dock.attach":"첨부","dock.history":"기록","history.empty":"기록이 아직 없습니다","history.scope":"현재 창의 기록만","dock.input.placeholder":"메시지를 입력하세요…","dock.input.enterDraft":"Shift + Enter로 초안 모드 열기","dock.input.exitDraft":"Esc로 터미널 모드 돌아가기 · Shift + Enter로 줄바꿈","dock.command.placeholder":"명령 입력 · Enter로 실행","dock.mode.agent":"대화","dock.mode.toggle":"입력 모드 전환","dock.mode.command":"명령 모드","dock.mode.chat":"채팅 모드","fav.title":"자주 쓰기","fav.add":"추가","fav.addPlaceholder":"자주 쓰는 항목 추가…","dock.upload.aria":"파일 업로드","dock.upload.title":"파일 업로드(홈 업로드 폴더에 저장, 프로젝트에는 포함되지 않음)","dock.upload.progress":"{name}{tag} 업로드 중","dock.upload.failed":"업로드 실패:{names}","app.nameExists":"해당 이름은 이미 사용 중입니다","app.renameFailed":"이름 변경에 실패했습니다. 다시 시도하세요","app.deleteFailed":"삭제에 실패했습니다. 다시 시도하세요","app.moveFailed":"이동에 실패했습니다. 다시 시도하세요","app.sessionGone":"세션「{name}」이 존재하지 않습니다. 이미 닫혔을 수 있습니다","app.docNotFound":"파일이 존재하지 않습니다","app.docTooLarge":"파일이 너무 큽니다(2MB 초과)","app.docUnsupported":"지원되지 않는 파일 또는 경로","app.docOpenFailed":"열기에 실패했습니다. 다시 시도하세요","app.preview":"미리보기","app.openPreview":"미리보기 열기","app.ideas":"아이디어","app.files":"파일","app.settings":"설정","app.renameSession":"세션 이름 변경","app.renameWindow":"창 이름 변경","app.moveLeft":"◀ 왼쪽으로 이동","app.moveRight":"오른쪽으로 이동 ▶","app.deleteWindow":"창 삭제","pane.splitH":"좌우 분할","pane.splitV":"상하 분할","pane.manage":"분할 관리","pane.close":"창 닫기","pane.closeConfirm":"닫을까요? 다시 탭","pane.splitFailed":"분할 실패","pane.closeFailed":"닫기 실패","resize.windowWidth":"창 너비","resize.paneWidth":"패널 너비","resize.columns":"{n}열","resize.restore":"복원","resize.restoreAutoWidth":"자동 너비 복원","resize.restoreRatio":"분할 비율 복원","app.deleteLastWindowConfirm":"마지막 창입니다. 삭제하면 전체 세션이 닫힙니다!한 번 더 탭하세요","app.deleteConfirm":"삭제하시겠습니까? 한 번 더 탭하세요","app.cannotLocate":"위치를 찾을 수 없습니다","app.pickItsDir":",디렉토리를 선택하세요:","app.noBoundSession":"연결된 세션이 없습니다","app.tapToBind":"탭하여 연결","app.selectSessionHint":"왼쪽 상단의 ☰ 를 탭하여 세션 선택","app.backToExit":"한 번 더 뒤로가기를 누르면 종료됩니다","settings.title":"설정","settings.group_global":"전체 설정","settings.group_general":"일반","settings.group_voice":"음성 텍스트 변환","settings.voice_enabled":"사용 여부","settings.voice_on":"사용 중","settings.voice_off":"사용 안 함","settings.voice_provider":"현재 제공업체","settings.voice_profile_tencent_streaming":"Tencent Cloud 실시간 음성 인식","settings.voice_profile_tencent_sentence":"Tencent Cloud 한 문장 인식","settings.voice_profile_xfyun":"iFlytek 음성 받아쓰기","settings.voice_not_configured":"설정 안 됨","settings.voice_filler_filter":"간투사 필터링","settings.voice_filter_low":"낮음","settings.voice_filter_medium":"중간","settings.voice_filter_high":"높음","settings.voice_not_supported":"지원하지 않음","settings.voice_setup_hint":"터미널에서 handmux setup을 실행한 다음, 음성 입력에서 설정하세요.","settings.project_task_beta":"프로젝트 작업 Beta","settings.group_terminal":"터미널","settings.group_chat":"대화","settings.group_notifications":"알림","settings.group_about":"정보","settings.terminal_font_size":"터미널 글꼴 크기","settings.terminal_font_decrease":"터미널 글꼴 축소","settings.terminal_font_increase":"터미널 글꼴 확대","settings.terminal_font_auto":"자동 조정","settings.terminal_font_auto_title":"높이에 맞게 자동 조정","settings.conversation_font_size":"대화 글꼴 크기","settings.conversation_font_decrease":"대화 글꼴 축소","settings.conversation_font_increase":"대화 글꼴 확대","settings.conversation_font_default":"기본값으로 복원","settings.conversation_font_hint":"10–20px 사이를 1px 단위로 조정합니다. 대화 메시지 본문과 그 안의 Markdown 및 코드에만 영향을 줍니다.","settings.keyboard_mode":"키보드 모드","settings.keyboard_mode_auto":"자동 감지","settings.keyboard_mode_mobile":"모바일","settings.keyboard_mode_desktop":"데스크톱","settings.keyboard_mode_hint":"현재 브라우저에만 적용됩니다. 감지가 틀리면 직접 선택하세요.","settings.group_agent_integration":"Agent 연동","settings.conversation_view_agent":"{agent} 대화 보기","settings.experimental":"실험적","settings.agent_integration_claude":"Claude Code","settings.agent_integration_pi":"Pi","settings.agent_integration_processing":"처리 중…","settings.agent_integration_load_error":"Agent 상태를 확인할 수 없습니다.","settings.agent_integration_action_error":"설정을 완료하지 못했습니다. 컴퓨터에서 다음을 실행하세요:","settings.agent_integration_conflict_hint":"{agent}에 기존 설정이 있습니다. 컴퓨터에서 진단하세요:","settings.agent_integration_not_installed_hint":"이 컴퓨터에 {agent}가 설치되어 있지 않습니다.","settings.agent_integration_initialize_first_hint":"컴퓨터에서 {agent}를 한 번 실행한 뒤 돌아와 활성화하세요.","settings.agent_integration_enable":"활성화","settings.agent_integration_repair":"복구","settings.agent_integration_loading":"확인 중…","settings.agent_integration_status_ready":"준비됨","settings.agent_integration_status_not_enabled":"비활성","settings.agent_integration_status_needs_repair":"복구 필요","settings.agent_integration_status_conflict":"확인 필요","settings.agent_integration_status_not_installed":"설치되지 않음","settings.path_highlight":"파일 경로 강조","settings.path_highlight_hint":"터미널에서 탭 가능한 파일 경로에 색을 입힙니다. 꺼져 있어도 경로는 탭할 수 있습니다.","settings.whats_new":"새 기능","settings.view_changelog":"변경 내역 보기","settings.reload_app":"앱 새로고침","settings.has_update":"업데이트 있음","settings.version":"버전","settings.feedback":"피드백","settings.feedback_issues":"GitHub Issues","settings.feedback_group":"WeChat 그룹","settings.feedback_hint":"버그와 아이디어 모두 환영 — Issue는 추적되고 답변됩니다.","settings.update_available":"버전 {v} 사용 가능","settings.update_more":"이전 버전 업데이트 {n}개 더 보기","settings.update_how":"컴퓨터에서 실행:","settings.push_notifications":"푸시 알림","settings.notify_on":"활성화됨 ✓","settings.notify_enable":"기기 알림 활성화","settings.notify_enabled":"활성화되었습니다. 환영 알림이 도착할 것입니다","settings.notify_disabled":"비활성화됨","settings.notify_failed":"작업에 실패했습니다","settings.notify_disable_title":"푸시 알림을 끌까요?","settings.notify_disable_hint":"이 기기에서 더 이상 「확인 필요」, 「완료」 및 스크립트 푸시 알림을 받지 않습니다. 언제든 다시 켤 수 있습니다.","settings.notify_disable_confirm":"푸시 끄기","settings.processing":"처리 중","settings.push_hint":"「확인 필요」및「완료」를 모니터링:관심 세션에서 승인/응답이 필요하거나 한 라운드가 완료되면 이 기기로 알림을 보냅니다.","settings.push_unsupported":"푸시 알림은 Chrome 또는 Safari가 필요합니다","settings.preview_site":"미리보기 사이트","settings.preview_static_site":"정적 사이트 미리보기","settings.preview_running_static":"정적 미리보기 실행 중","settings.preview_remain_title":"남은 유효 기간","settings.preview_remain":"남은 시간 {time}","settings.preview_renew":"갱신","settings.preview_confirm_stop":"중지 확인","settings.preview_stop":"중지","settings.preview_name":"이름:{name}","settings.preview_port":"(포트:{port})","settings.preview_type":"미리보기 유형","settings.preview_off":"비활성화","settings.preview_static":"정적","settings.preview_off_hint":"미리보기가 비활성화되어 있습니다. 「정적」을 선택하여 시작하세요.","settings.preview_off_hint_both":"미리보기가 비활성화되어 있습니다. 「정적」또는「동적」을 선택하여 시작하세요.","settings.preview_pick_dir":"디렉토리를 선택하여 시작","settings.preview_static_hint":"index.html이 포함된 디렉토리를 선택하여 스마트폰에서 미리보기.","settings.preview_port_placeholder":"포트 번호(예:3000)","settings.preview_port_label":"포트","settings.preview_starting":"시작 중…","settings.preview_start":"시작","settings.dir_picker_hint":"미리볼 정적 사이트 디렉토리 선택(index.html 포함)","settings.err_port_not_listening":"해당 포트가 수신 대기 중이지 않습니다. 서비스가 시작되었는지 확인하세요","settings.err_bad_port":"포트 번호가 유효하지 않습니다(1–65535)","settings.err_start_failed":"시작에 실패했습니다","localurl.title":"웹사이트 열기","localurl.open":"브라우저에서 열기","localurl.notListening":"포트 :{port}에서 수신 중인 서비스가 없습니다.","localurl.badProtocol":"이 링크는 프록시할 수 있는 HTTP 또는 HTTPS 주소가 아닙니다.","localurl.network":"handmux 서비스에 연결할 수 없습니다. 네트워크를 확인한 후 다시 시도하세요.","localurl.failed":"웹사이트를 열 수 없습니다. 주소를 확인하고 다시 시도하세요.","filebrowser.openDirFailed":"디렉토리를 열 수 없습니다","filebrowser.copiedPath":"경로가 복사되었습니다:{abs}","filebrowser.mkdirFailed":"디렉토리 생성에 실패했습니다(이름이 유효하지 않거나 이미 존재합니다)","filebrowser.downloading":"{name} 다운로드 중","filebrowser.downloadFailed":"다운로드에 실패했습니다","filebrowser.uploading":"{name}{tag} 업로드 중","filebrowser.uploadFailed":"업로드에 실패했습니다","filebrowser.uploadPartialFailed":"다음 파일 업로드에 실패했습니다:{names}","filebrowser.sessionDir":"세션 디렉토리","filebrowser.jumpToSessionDir":"현재 세션 디렉토리로 이동","filebrowser.parentDir":"상위 디렉토리","filebrowser.rootSelect":"루트 디렉토리 전환(홈 / 임시)","filebrowser.pathPlaceholder":"경로 입력(실시간 필터 / 이동)","filebrowser.newFolder":"새 폴더","filebrowser.createBtn":"생성","filebrowser.uploadFile":"파일 업로드","filebrowser.uploadToCurrentDir":"현재 디렉토리에 업로드","filebrowser.enterSubdirToUpload":"하위 디렉토리로 이동한 후 업로드하세요","filebrowser.folderNamePlaceholder":"폴더 이름","filebrowser.uploadPendingTo":"「{name}」을 현재 디렉토리에 업로드","filebrowser.enterSubdirFirst":"(먼저 하위 디렉토리로 이동하세요)","filebrowser.upload":"업로드","filebrowser.savedToDownloads":"「{name}」이 「다운로드」 폴더에 저장되었습니다. 파일 관리자에서 확인할 수 있습니다","filebrowser.noMatches":"일치하는 파일 또는 디렉토리가 없습니다","filebrowser.tooMany":"총 {total}개, 처음 {shown}개만 표시——경로 입력창에 키워드를 입력하여 필터할 수 있습니다","filebrowser.previewUnsupported":"이 파일 유형의 미리보기는 지원되지 않습니다. 오른쪽 버튼으로 다운로드할 수 있습니다","filebrowser.copyAbsPath":"절대 경로 복사","filebrowser.download":"다운로드","filebrowser.pickThisDir":"이 디렉토리 선택 {path}","filebrowser.downloadConfirm":"{name}을 다운로드하시겠습니까?","filemanager.files":"파일","filemanager.closeTab":"탭 닫기","filemanager.minimize":"최소화","filemanager.recent":"최근","filemanager.directory":"디렉토리","git.errReadRepo":"저장소를 읽을 수 없습니다","git.errLoad":"불러오기에 실패했습니다","git.noRepoInDir":"아직 git 저장소가 없습니다 — 다른 디렉토리를 선택하거나 여기서 git init 하세요.","git.outsideRoots":"이 폴더는 handmux가 열 수 있는 범위 밖입니다 — 홈 디렉토리와 /tmp만 접근할 수 있습니다. 저장소를 홈 디렉토리 아래로 옮기면 여기서 볼 수 있습니다.","git.errReadDir":"디렉토리를 읽을 수 없습니다","git.commitDetail":"커밋 상세","git.diff":"변경 사항","git.bindRepo":"저장소 연결","git.collapse":"접기","git.currentBranch":"현재 브랜치","git.switchViewedBranch":"표시할 브랜치 전환","git.switchBranch":"브랜치 전환","git.noBranches":"브랜치가 없습니다","git.noRepoBound":"저장소가 연결되지 않았습니다. 왼쪽 상단의 「+」를 탭하여 디렉토리를 선택하세요.","git.changes":"변경사항","git.commits":"커밋","git.pullToLoadMore":"당겨서 더 불러오기","git.pickerHint":"디렉토리를 선택하면 그 안의 git 저장소를 자동으로 찾습니다","git.cleanTree":"작업 트리가 깨끗합니다","git.noCommits":"커밋이 없습니다","git.noDiff":"변경 사항 없음","git.fontSmaller":"글꼴 축소","git.fontLarger":"글꼴 확대","git.diffTruncated":"변경 사항이 너무 커서 잘렸습니다","cmd.panel":"명령 패널","cmd.title":"명령","cmd.empty":"명령이 없습니다. 보내거나 자주 쓰는 것을 저장하세요","cmd.favorites":"즐겨찾기","cmd.scopeGlobal":"전체 · 모든 세션","cmd.recent":"최근","cmd.scopeSession":"현재 세션만","cmd.favorite":"즐겨찾기 추가","cmd.unfavorite":"즐겨찾기 해제","doc.home":"최근","doc.read":"읽어주기","doc.pauseRead":"읽기 일시 정지","doc.resumeRead":"읽기 재개","doc.stopRead":"읽기 중지","doc.rate":"읽기 속도","doc.fontSmaller":"글꼴 축소","doc.fontLarger":"글꼴 확대","inbox.view.working":"진행 중","inbox.view.done":"완료","inbox.view.needs":"확인 필요","inbox.view.error":"오류","push.unsupported":"푸시 알림은 Chrome 또는 Safari가 필요합니다","push.iosAddToHome":"iOS에서는 먼저 이 사이트를 「홈 화면에 추가」한 후 홈 화면 아이콘에서 열어주세요","a2hs.title":"handmux를 홈 화면에 추가","a2hs.lead":"앱처럼 전체 화면으로 열 수 있습니다. iPhone에서는 pane이 당신을 필요로 할 때의 푸시도 이 방식으로 전달됩니다.","a2hs.install":"handmux 설치","a2hs.ios1":"Safari의 공유 버튼(⬆︎ 상자)을 탭하세요.","a2hs.ios2":"「더 보기」를 탭하거나 목록을 아래로 스크롤하세요.","a2hs.ios3":"「홈 화면에 추가」를 선택한 뒤 「추가」를 탭하세요.","a2hs.iosHint":"Safari에서: 공유 → 더 보기 → 홈 화면에 추가.","a2hs.iosOpenSafari":"현재 Safari가 아닙니다. Safari에서 이 페이지를 연 뒤 홈 화면에 추가하세요 — 다른 iOS 브라우저는 설치할 수 없습니다.","a2hs.androidManual":"브라우저 메뉴(⋮)에서 「홈 화면에 추가」 또는 「앱 설치」를 선택하세요.","a2hs.later":"나중에","push.permissionTimeout":"알림 권한 결과가 반환되지 않았습니다. 시스템 설정에서 handmux 또는 브라우저의 알림 권한을 확인한 후 다시 시도하세요.","push.permissionDenied":"알림 권한이 거부되었습니다","push.swRegisterTimeout":"알림 서비스 등록 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하세요.","push.swRegisterFailed":"알림 서비스를 등록하지 못했습니다: {reason}. 이 사이트의 데이터를 삭제하고 다시 열어 시도하세요.","push.swTimeout":"알림 서비스가 등록되었지만 활성화되지 않았습니다. 이 사이트의 데이터를 삭제하고 다시 열어 시도하세요.","push.unknownReason":"알 수 없는 원인","push.configTimeout":"푸시 설정을 불러오는 시간이 초과되었습니다. handmux 서버 연결을 확인한 후 다시 시도하세요.","push.browserTimeout":"브라우저 푸시 서비스가 응답하지 않습니다. Android Chrome에서는 Google Play 서비스를 사용할 수 있는지 확인한 후 다시 시도하세요.","push.noVapid":"서버에 푸시 알림(VAPID)이 설정되지 않았습니다","push.reportTimeout":"구독은 생성되었지만 서버 등록 시간이 초과되었습니다. 연결을 확인한 후 다시 시도하세요.","push.subscriptionExpired":"Chrome이 만료된 푸시 구독을 반환했습니다. 구독을 초기화했으니 알림 켜기를 다시 누르세요.","push.deliveryRejected":"푸시 서비스가 새 구독을 거부했습니다. 서버 로그를 확인한 후 다시 시도하세요.","push.subscribeFailed":"구독 등록에 실패했습니다","push.sendFailed":"전송에 실패했습니다","pushInbox.loadFailed":"알림을 불러오지 못했습니다. 연결을 확인한 후 다시 시도하세요.","pushInbox.deleteFailed":"알림을 삭제하지 못했습니다. 메시지는 유지됩니다. 다시 시도하세요.","pushInbox.retry":"다시 시도","pushInbox.deliveryPending":"전송 중","pushInbox.deliverySuccess":"성공","pushInbox.deliveryFailed":"실패","pushInbox.deliveryReasonExpired":"구독 만료","pushInbox.deliveryReasonRateLimited":"푸시 서비스 요청 제한","pushInbox.deliveryReasonUnavailable":"푸시 서비스를 사용할 수 없음","pushInbox.deliveryReasonRejected":"푸시 서비스가 거부함","pushInbox.deliveryReasonNetwork":"네트워크 오류","pushInbox.deliveryReasonNotConfigured":"푸시가 설정되지 않음","pushInbox.deliveryReasonUnknown":"알 수 없는 원인","api.loadFailed":"불러오기에 실패했습니다","api.uploadFailed":"업로드에 실패했습니다","upload.title":"업로드 중","upload.processing":"전송 완료 — 서버에서 수신 중…","api.uploadBadDir":"해당 디렉토리에는 업로드할 수 없습니다","api.uploadDuplicate":"같은 이름의 파일이 이미 존재합니다","api.uploadTooLarge":"파일이 너무 큽니다(최대 50MB)","api.uploadBadType":"지원되지 않는 파일 유형입니다","time.secAgo":"{n}초 전","time.minAgo":"{n}분 전","time.hourAgo":"{n}시간 전","time.dayAgo":"{n}일 전","time.expired":"만료됨","time.minutes":"{n}분","workspace.bootDetected":"컴퓨터 재시작이 감지되었습니다","workspace.tmuxDetected":"tmux 재시작이 감지되었습니다","workspace.summary":"이전 작업 공간 · 세션 {sessions}개 · {time} 저장","workspace.restoreLast":"이전 작업 공간 복원","workspace.partialCard":"세션 {failures}개를 더 확인해야 합니다","workspace.unknownTime":"알 수 없는 시간","workspace.savedAt":"{time} 저장","workspace.topologySummary":"세션 {sessions}개 · 창 {windows}개 · 패널 {panes}개","workspace.planSummary":"세션 {restore}개 복원;{already}개는 이미 존재","workspace.renameRule":"현재 같은 이름의 세션이 있을 때만 복원 이름에 -restored 접미사가 붙습니다.","workspace.nonDestructive":"현재 세션은 수정하거나 이름을 바꾸거나 중지하지 않습니다.","workspace.progress":"복원 중 {completed} / {total}…","workspace.progressDone":"복원됨 {completed} / {total}","workspace.complete":"작업 공간을 복원했습니다.","workspace.completedSummary":"이번 복원: 세션 {sessions}개 · 창 {windows}개 · 패널 {panes}개","workspace.rebindHint":"복원된 세션은 자동으로 표시되지 않습니다. 이 휴대폰에 연결할 세션을 다시 선택할 수 있습니다.","workspace.rebind":"세션 다시 연결","workspace.sessionFailure":"{session}: {reason}","workspace.unknownSession":"알 수 없는 세션","workspace.restore":"복원","workspace.ignore":"이 백업 무시","workspace.protectionTitle":"작업 공간이 보호되지 않음","workspace.protection.live-corrupt":"작업 공간 상태 사본이 손상되었습니다. 디스크와 ~/.handmux 권한을 확인한 뒤 handmux를 재시작하세요.","workspace.protection.live-unavailable":"작업 공간 상태를 읽거나 쓸 수 없습니다. 디스크 여유 공간과 ~/.handmux 권한을 확인한 뒤 handmux를 재시작하세요.","workspace.protection.unknown":"백그라운드 스냅샷을 사용할 수 없습니다. 컴퓨터의 handmux 로그를 확인하세요.","workspace.error.restore-interrupted":"복원이 중단되었습니다. 이 백업을 다시 시도하세요","workspace.error.checkpoint-not-found":"이 백업을 더 이상 사용할 수 없습니다. 새로 고친 뒤 다른 백업을 선택하세요","workspace.error.storage-full":"작업 공간 저장소가 가득 찼습니다. 디스크 공간을 확보한 뒤 다시 시도하세요","workspace.error.permission-denied":"작업 공간 저장소에 쓸 수 없습니다. 권한을 확인한 뒤 다시 시도하세요","workspace.error.plan-failed":"복원 계획이 변경되었습니다. 새로 고친 뒤 다시 시도하세요","workspace.error.agent-unavailable":"Agent를 재개할 수 없습니다. 복원된 shell을 열고 수동으로 다시 시도하세요","workspace.error.tmux-unavailable":"tmux를 사용할 수 없습니다. tmux 실행 여부를 확인한 뒤 다시 시도하세요","workspace.error.restore-failed":"세션을 복원하지 못했습니다. handmux 로그를 확인한 뒤 다시 시도하세요","workspace.error.operation-not-found":"이 복원 작업을 더 이상 사용할 수 없습니다. 백업 복원을 다시 시작하세요","workspace.sessionWarning":"{session}: {reason}","workspace.warning.cwd-fallback":"작업 디렉터리를 사용할 수 없어 홈 디렉터리에 복원했습니다","workspace.warning.layout-fallback":"창 분할 배치를 완전히 복원하지 못해 기본 배치를 유지했습니다","workspace.warning.agent-warning":"Agent를 자동으로 재개하지 못했습니다. 복원된 셸은 계속 사용할 수 있습니다","workspace.warning.live-reconcile-failed":"현재 작업 공간 상태를 대조하지 못했습니다. handmux 로그를 확인하세요","workspace.warning.workspace-unavailable":"작업 공간 저장소를 일시적으로 사용할 수 없습니다. 디스크 공간과 권한을 확인하세요","workspace.warning.restore-warning":"복원 중 확인이 필요한 경고가 발생했습니다","chat.plan.currentTitle":"현재 작업","chat.plan.historyTitle":"이번 턴 작업","chat.plan.working":"진행 중: {step}","chat.plan.waiting":"확인 대기: {step}","chat.plan.finalizing":"결과 정리 중","chat.plan.complete":"완료","chat.plan.incomplete":"미완료","chat.plan.status.pending":"대기","chat.plan.status.inProgress":"진행 중","chat.plan.status.completed":"완료"},QN={zh:XO,"zh-TW":JO,en:GT,ja:QO,ko:ZO},kj=[{code:"zh",label:"简体中文"},{code:"zh-TW",label:"繁體中文"},{code:"en",label:"English"},{code:"ja",label:"日本語"},{code:"ko",label:"한국어"}],KT="tw_lang";function eP(e,n,i=QN){if(typeof e=="string"&&i[e])return e;for(const a of n!=null&&n.length?n:["en"]){const u=String(a).toLowerCase();if(i[u])return u;const g=u.split("-")[0];if(g&&i[g])return g}return"en"}function tP(e,n,i,a){let u=e&&e[i]!=null?e[i]:n&&n[i]!=null?n[i]:i;return a&&(u=u.replace(/\{(\w+)\}/g,(g,d)=>a[d]!=null?String(a[d]):`{${d}}`)),u}const nP=()=>typeof navigator<"u"?navigator.languages||[navigator.language]:null,rP=()=>{try{return localStorage.getItem(KT)}catch{return null}};let jg=eP(rP(),nP());function w(e,n){return tP(QN[jg],GT,e,n)}function mo(){return jg}function iP(e){if(!(typeof e!="string"||!(e in QN)||e===jg)){try{localStorage.setItem(KT,e)}catch{}jg=e,typeof location<"u"&&location.reload()}}const sP=()=>`${Date.now().toString(36)}${Math.random().toString(36).slice(2,6)}`;function YT(e){return Array.isArray(e)?e.flatMap(n=>{const i=n!==null&&typeof n=="object"&&!Array.isArray(n)?n:null;return typeof(i==null?void 0:i.id)=="string"&&i.id&&typeof i.text=="string"&&i.text.trim()?[{id:i.id,text:i.text}]:[]}):[]}function aP(e){const n=typeof e=="string"?e.trim():"";return n?{id:sP(),text:n}:null}function oP(e,n,i){const a=[...e];if(n<0||n>=a.length||i<0||i>=a.length||n===i)return a;const[u]=a.splice(n,1);return u===void 0||a.splice(i,0,u),a}const ZN="tw_token",Tj="hm_browser_device1",rN="hm_browser_access1",e0="tw_font",iN="tw_conversation_font_size",ef="tw_bound",Dg="tw_last_session",t0="tw_win",n0="tw_pane",r0="tw_favs",lP="tw_recent",cP=30,i0="tw_inbox_seen",XT="tw_inbox_read_ts",s0="tw_browse_dir",a0="tw_preview_dir",JT="tw_startup_cmd",sN="tw_chat_draft",QT="tw_chat_tone",ZT="tw_voice_filler_filter",o0="tw_agent_conversation_enabled_v1",eR="tw_agent_usage_enabled_v1",uP="tw_ideas",tR="tw_changelog_seen",nR="tw_version_seen",rR="tw_security_seen",Kg="tw_git_repos",dP="tw_git_dirs",aN="tw_workspace_prompt",iR="tw_workspace_applied_mappings",mP="hm_root_view",oN="hm_last_project",hP=/^[A-Za-z0-9][A-Za-z0-9._-]*$/,uw={sessions:/^\$\d+$/,windows:/^@\d+$/,panes:/^%\d+$/},Ah=(e,n)=>Object.prototype.hasOwnProperty.call(e,n);function md(e){const n=localStorage.getItem(e);if(n===null)return null;try{return JSON.parse(n)}catch{return null}}function ha(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const n=Object.getPrototypeOf(e);return n===Object.prototype||n===null}function hd(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}const sR=()=>localStorage.getItem(ZN),fP=e=>localStorage.setItem(ZN,e),pP=()=>localStorage.removeItem(ZN),dw=e=>localStorage.setItem(mP,e),vP=()=>localStorage.getItem(oN),qv=e=>{e?localStorage.setItem(oN,e):localStorage.removeItem(oN)};function gP(){const e=localStorage.getItem(Tj);if(/^[A-Za-z0-9_-]{32,128}$/.test(e||""))return e;const n=new Uint8Array(24);globalThis.crypto.getRandomValues(n);const i=`device_${[...n].map(a=>a.toString(16).padStart(2,"0")).join("")}`;return localStorage.setItem(Tj,i),i}const bP=()=>localStorage.getItem(rN)==="1",gg=e=>{e?localStorage.setItem(rN,"1"):localStorage.removeItem(rN)};function ho(){try{return hd(md(ef))}catch{return[]}}function lN(e){const n=ho();return n.includes(e)||n.push(e),localStorage.setItem(ef,JSON.stringify(n)),n}function Rj(e){const n=ho().filter(i=>i!==e);return localStorage.setItem(ef,JSON.stringify(n)),n}function _P(e){const n=new Set((Array.isArray(e)?e:[]).flatMap(a=>ha(a)?a.status==="restored"&&typeof a.targetName=="string"&&a.targetName?[a.targetName]:[]:[])),i=ho().filter(a=>!n.has(a));return localStorage.setItem(ef,JSON.stringify(i)),i}function yP(e,n){const i=ho().map(a=>a===e?n:a);return localStorage.setItem(ef,JSON.stringify(i)),l0.renameSession(e,n),Yg.renameSession(e,n),i}function Ms(e){try{const n=md(e);return ha(n)?n:{}}catch{return{}}}function Pl(e,n,i){const a=Ms(e);a[n]=i,localStorage.setItem(e,JSON.stringify(a))}function aR(e,n){if(!e)return{};const i=Ms(aN),a=i[e];return i[e]={...a&&typeof a=="object"&&!Array.isArray(a)?a:{},...n},localStorage.setItem(aN,JSON.stringify(i)),i[e]}const xP=e=>{if(!e)return{};const n=Ms(aN)[e];return ha(n)?{...typeof n.autoShown=="boolean"?{autoShown:n.autoShown}:{},...typeof n.ignored=="boolean"?{ignored:n.ignored}:{}}:{}},Aj=e=>aR(e,{autoShown:!0}),wP=e=>aR(e,{ignored:!0,autoShown:!0});function NP(){try{return hd(md(iR))}catch{return[]}}function CP(e){try{if(!ha(e)||typeof e.id!="string"||!hP.test(e.id)||e.runtime!==void 0&&!ha(e.runtime)||e.names!==void 0&&!ha(e.names))return null;const n=ha(e.runtime)?e.runtime:{};if(Object.keys(n).some(d=>!Ah(uw,d)))return null;const i={sessions:{},windows:{},panes:{}};for(const d of Object.keys(uw)){const o=uw[d],c=n[d];if(c!==void 0){if(!ha(c))return null;for(const[f,v]of Object.entries(c)){if(!o.test(f)||typeof v!="string"||!o.test(v))return null;i[d][f]=v}}}const a={},u=ha(e.names)?e.names:{};for(const[d,o]of Object.entries(u)){if(!d||typeof o!="string"||!o)return null;a[d]=o}return Object.keys(a).length>0||Object.values(i).some(d=>Object.keys(d).length>0)?{id:e.id,runtime:i,names:a}:null}catch{return null}}function EP(e){const n=localStorage.getItem(e);if(n===null)return null;try{const i=JSON.parse(n);return ha(i)?{raw:n,value:i}:null}catch{return null}}function Gv(e,n,i={}){const a=EP(e);if(!a)return;const u=a.value,g=Object.keys(n).filter(c=>Ah(u,c));if(g.length===0)return;const d={};for(const[c,f]of Object.entries(u))Ah(n,c)||(d[c]=f);for(const c of g){const f=n[c];if(f===void 0)continue;const v=u[c];d[f]=typeof v=="string"&&Ah(i,v)?i[v]:v}const o=JSON.stringify(d);o!==a.raw&&localStorage.setItem(e,o)}function SP(e){const{sessions:n,windows:i,panes:a}=e;if(Object.keys(n).length>0){const u=localStorage.getItem(Dg);if(u&&Ah(n,u)){const g=n[u];g!==void 0&&localStorage.setItem(Dg,g)}Gv(t0,n,i)}if(Object.keys(i).length>0){Gv(n0,i,a);for(const u of[Kg,dP,s0,a0])Gv(u,i)}if(Object.keys(a).length>0)for(const u of[d0,i0])Gv(u,a)}function jP(e){const n=CP(e);if(!n)return!1;const i=NP();if(i.includes(n.id))return!1;if(SP(n.runtime),Object.keys(n.names).length>0){const a=ho();for(const[u,g]of Object.entries(n.names))a.includes(u)&&lN(g)}return localStorage.setItem(iR,JSON.stringify([...i,n.id])),!0}function oR(e,n){const i=a=>ha(a)?a:{};return{get(a,u){return!a||!u?[]:n(i(Ms(e)[a])[u])},set(a,u,g){const d=Ms(e),o=i(d[a]);return g&&g.length?o[u]=[...g]:delete o[u],Object.keys(o).length?d[a]=o:delete d[a],localStorage.setItem(e,JSON.stringify(d)),g?[...g]:[]},renameWindow(a,u,g){if(!a||!u||!g||u===g)return;const d=Ms(e),o=i(d[a]);o[u]!=null&&(o[g]=o[u],delete o[u],d[a]=o,localStorage.setItem(e,JSON.stringify(d)))},renameSession(a,u){const g=Ms(e);g[a]!=null&&(g[u]=g[a],delete g[a],localStorage.setItem(e,JSON.stringify(g)))}}}const l0=oR(lP,hd),Yg=oR(uP,YT),cN=()=>{const e={};for(const[n,i]of Object.entries(Ms(i0)))typeof i=="number"&&Number.isFinite(i)&&(e[n]=i);return e};function Uj(e,n){return Pl(i0,e,n),cN()}const DP=()=>{const e=localStorage.getItem(XT);return e==null?null:Number(e)},Mj=e=>localStorage.setItem(XT,String(e)),lR="tw_notif_seen_ts",kP=()=>{const e=localStorage.getItem(lR);return e==null?0:Number(e)},TP=e=>localStorage.setItem(lR,String(e)),c0="tw_notif_read_ids",Uh=()=>{try{return hd(md(c0))}catch{return[]}},Lj=e=>{const n=Uh();n.includes(e)||localStorage.setItem(c0,JSON.stringify([...n,e]))},RP=e=>{const n=Uh().filter(i=>e.includes(i));return localStorage.setItem(c0,JSON.stringify(n)),n},AP=e=>{const n=e?Ms(s0)[e]:null;return typeof n=="string"?n:null},Ij=(e,n)=>{e&&n&&Pl(s0,e,n)},UP=e=>{const n=e?Ms(a0)[e]:null;return typeof n=="string"?n:null},Vj=(e,n)=>{e&&n&&Pl(a0,e,n)},MP=()=>localStorage.getItem(Dg),LP=e=>{const n=Ms(t0)[e];return typeof n=="string"?n:null},Wu=e=>{const n=Ms(n0)[e];return typeof n=="string"?n:null};function kl({sessionId:e,windowId:n,paneId:i}={}){e&&localStorage.setItem(Dg,e),e&&n&&Pl(t0,e,n),n&&i&&Pl(n0,n,i)}function uN(){const e=Number(localStorage.getItem(e0));return Number.isFinite(e)&&e>0?e:null}const Qu=e=>localStorage.setItem(e0,String(e)),cR=()=>localStorage.removeItem(e0),Sh=[10,11,12,13,14,15,16,17,18,19,20],Zu=15,uR=e=>typeof e=="number"&&Sh.includes(e),IP=()=>{const e=localStorage.getItem(iN),n=e===null?NaN:Number(e);return uR(n)?n:Zu},VP=e=>{uR(e)&&(e===Zu?localStorage.removeItem(iN):localStorage.setItem(iN,String(e)))},OP=["dusk","ink","light"],dR=e=>typeof e=="string"&&OP.includes(e),PP=()=>{const e=localStorage.getItem(QT);return dR(e)?e:"dusk"},BP=e=>{dR(e)&&localStorage.setItem(QT,e)},bg=["low","medium","high"],mR=e=>typeof e=="string"&&bg.includes(e),dN=()=>{const e=localStorage.getItem(ZT);return mR(e)?e:"medium"},FP=e=>{mR(e)&&localStorage.setItem(ZT,e)};function hR(){try{const e=JSON.parse(localStorage.getItem(o0)||"{}");return!e||typeof e!="object"||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(n=>/^[a-z][a-z0-9-]{0,63}$/.test(n[0])&&typeof n[1]=="boolean"))}catch{return{}}}function Oj(e){const n=hR();if(Object.hasOwn(n,e))return n[e];const i=localStorage.getItem(`tw_chat_lens_${e}`),a=localStorage.getItem("tw_chat_lens"),u=i!==null?i==="1":a!==null?a==="1":!0;return/^[a-z][a-z0-9-]{0,63}$/.test(e)&&(n[e]=u,localStorage.setItem(o0,JSON.stringify(n))),u}function HP(e,n){if(!/^[a-z][a-z0-9-]{0,63}$/.test(e))return;const i=hR();i[e]=n,localStorage.setItem(o0,JSON.stringify(i))}function fR(){try{const e=JSON.parse(localStorage.getItem(eR)||"{}");return!e||typeof e!="object"||Array.isArray(e)?{}:Object.fromEntries(Object.entries(e).filter(n=>/^[a-z][a-z0-9-]{0,63}$/.test(n[0])&&typeof n[1]=="boolean"))}catch{return{}}}function Pj(e){const n=fR();return Object.hasOwn(n,e)?n[e]:!0}function Bj(e,n){if(!/^[a-z][a-z0-9-]{0,63}$/.test(e))return;const i=fR();i[e]=n;try{localStorage.setItem(eR,JSON.stringify(i))}catch{}}const zP=()=>localStorage.getItem(sN)||"",$P=e=>{e?localStorage.setItem(sN,e):localStorage.removeItem(sN)};function kg(){try{return hd(md(r0))}catch{return[]}}function WP(e){const n=e.trim(),i=kg();return n&&!i.includes(n)&&i.push(n),localStorage.setItem(r0,JSON.stringify(i)),i}function qP(e){const n=kg().filter(i=>i!==e);return localStorage.setItem(r0,JSON.stringify(n)),n}const pR=()=>localStorage.getItem(JT)||"",vR=e=>localStorage.setItem(JT,e||""),gR="tw_orphan_kill",GP=()=>localStorage.getItem(gR)!=="0",KP=e=>localStorage.setItem(gR,e?"1":"0"),bR="tw_doc_highlight",_R=()=>localStorage.getItem(bR)==="1",YP=e=>localStorage.setItem(bR,e?"1":"0"),Tg=(e,n)=>l0.get(e,n),yR=(e,n,i)=>l0.set(e,n,i);function XP(e,n,i){const a=(i||"").trim(),u=Tg(e,n);return!a||!e||!n?u:yR(e,n,[a,...u.filter(g=>g!==a)].slice(0,cP))}function JP(e,n,i){return!e||!n?Tg(e,n):yR(e,n,Tg(e,n).filter(a=>a!==i))}const u0="tw_recent_docs",d0="tw_pane_base",QP=30;function m0(){try{const e=md(u0);return Array.isArray(e)?e.flatMap(n=>!ha(n)||typeof n.path!="string"||typeof n.name!="string"||typeof n.type!="string"||typeof n.ts!="number"||!Number.isFinite(n.ts)?[]:[{path:n.path,name:n.name,type:n.type,ts:n.ts}]):[]}catch{return[]}}function Fj({path:e,name:n,type:i,ts:a=Date.now()}){const u=[{path:e,name:n,type:i,ts:a},...m0().filter(g=>g.path!==e)].slice(0,QP);return localStorage.setItem(u0,JSON.stringify(u)),u}function ZP(e){const n=m0().filter(i=>i.path!==e);return localStorage.setItem(u0,JSON.stringify(n)),n}const Hj=e=>{const n=Ms(d0)[e];return typeof n=="string"?n:null},e4=(e,n)=>Pl(d0,e,n),fd=[10,11,12,13,14,16,18,20,22],t4=4,xR="tw_doc_font";function n4(){const e=localStorage.getItem(xR),n=Number(e);return e!==null&&Number.isInteger(n)&&n>=0&&n<fd.length?n:t4}const r4=e=>localStorage.setItem(xR,String(Math.min(fd.length-1,Math.max(0,e)))),i4=2,wR="tw_diff_font";function s4(){const e=localStorage.getItem(wR),n=Number(e);return e!==null&&Number.isInteger(n)&&n>=0&&n<fd.length?n:i4}const a4=e=>localStorage.setItem(wR,String(Math.min(fd.length-1,Math.max(0,e)))),NR=(e,n)=>Yg.get(e,n);function zj(e,n,i){return!e||!n?[]:Yg.set(e,n,i)}const o4=()=>localStorage.getItem(tR),l4=e=>{e&&localStorage.setItem(tR,e)},c4=()=>localStorage.getItem(nR),u4=e=>{e&&localStorage.setItem(nR,e)},d4=()=>localStorage.getItem(rR)==="1",m4=()=>{localStorage.setItem(rR,"1")};function h4(e,n,i){Yg.renameWindow(e,n,i)}function h0(e){if(!e)return[];const n=Ms(Kg)[e];return hd(n)}function $j(e,n){if(!e)return[];const i=[...h0(e)];for(const a of n)a&&!i.includes(a)&&i.push(a);return Pl(Kg,e,i),i}function f4(e,n){if(!e)return[];const i=h0(e).filter(a=>a!==n);return Pl(Kg,e,i),i}const mN=[{version:"0.29.2",date:"2026-09-18",highlight:{zh:"修复 Linux 下 Claude 事件上报的兼容问题",en:"Compatibility fix for Claude event reporting on Linux"},items:{zh:["修复个别 Linux 环境下 Hook 读取进程信息失败的问题:进程表不可读时回退到兼容取值,Claude 的收件箱与完成事件不受影响。"],en:["Fixed Hook process lookup failing in some Linux environments: it now falls back to the compatible value when procfs is unreadable, so Claude Inbox and completion events are unaffected."]}},{version:"0.29.1",date:"2026-09-18",highlight:{zh:"修复 Claude 对话入口丢失 · 长时间运行不再变卡",en:"Fix lost Claude chat entries · no slowdown after long runs"},items:{zh:["修复 WSL2 上 Claude 对话入口反复消失、收件箱状态中断的问题;进程识别不再受系统时间调整影响。","修复 Linux 上 Claude 的活动状态(进行中/空闲/等待)一直显示不出来的问题。","修复 Linux 上 Claude 自动更新删掉旧版本文件后被识别不到的问题。","修复长时间运行或反复重连后变卡、占磁盘的问题:不再可达的内部状态会被回收。",'修复切换会话时短暂显示"无法连接 Codex 会话"的问题;过渡期间改为显示加载中。'],en:["Fixed Claude chat entries and Inbox state repeatedly dropping on WSL2; process identity no longer follows system clock adjustments.","Fixed Claude activity (working / idle / waiting) never showing on Linux.","Fixed Claude not being recognized on Linux after its own auto-update removed the older binary file.","Fixed the service slowing down and growing on disk after long runs or repeated reconnects; unreachable internal state is now reclaimed.",'Fixed a misleading "Could not connect to the Codex session" flash while a conversation switches; it shows the shared loading state instead.']}},{version:"0.29.0",date:"2026-09-16",highlight:{zh:"可信设备与可信地址保护",en:"Trusted device and address protection"},items:{zh:["新增 Token + 可信设备双层认证,以及可信地址保护;支持网页和 CLI 管理设备、授权、有效期与撤销。","新增清晰的认证控制:可查看并开启两层保护,明确授权范围和关闭风险。","修复 DeepSeek 欠费金额显示错误。"],en:["Added layered Token + trusted-device authentication and trusted address protection, with Web and CLI management for devices, authorization, expiry, and revocation.","Added clear authentication controls for viewing and enabling both protection layers, with explicit authorization scope and disable-risk guidance.","Fixed incorrect DeepSeek overdue balances."]}},{version:"0.28.0",date:"2026-09-11",highlight:{zh:"Claude 对话更可靠 · 工具图片预览",en:"More reliable Claude chat · tool image previews"},items:{zh:["对话页新增工具图片预览:图片按实际比例居中显示,支持缩放、保存、分享和失败重试。","修复 Claude 停止、compact、原生命令、选项选择和收件箱状态异常导致消息排队的问题。","修复模型和 Goal 弹窗切换会话后重复打开;队列编辑、Codex /review 和工作区状态更可靠。"],en:["Added tool image previews in chat: images stay centered at their natural size, with zoom, save, share, and retry support.","Fixed Claude stop, compaction, native commands, option selection, and Inbox states leaving messages queued.","Fixed Model and Goal sheets reopening after session switches; queue editing, Codex /review, and workspace state are more reliable."]}},{version:"0.27.2",date:"2026-09-08",highlight:{zh:"修复多标签页偶发鉴权弹窗",en:"Fix intermittent authentication prompts across tabs"},items:{zh:["修复切换浏览器标签页或实时终端连接延迟时,偶发误弹鉴权页面的问题。"],en:["Fixed an intermittent authentication prompt when switching browser tabs or when a live terminal connection was delayed."]}},{version:"0.27.1",date:"2026-09-08",highlight:{zh:"腾讯语音 · 终端光标修复 · Codex 对话恢复",en:"Tencent voice · terminal cursor fixes · Codex chat recovery"},items:{zh:["面向 0.26 升级用户的完整汇总:0.27.0 已公开 GitHub 源码和 Release,但未完成 npm / Homebrew 分发;本版承接这些更新并加入后续修复,保留 0.27.0 历史记录。","语音新增腾讯实时与一句话识别,保留讯飞实时识别;三种方案共享音量波形与录音动效,识别文字插入起录时的光标位置,不清空已有草稿。","handmux setup 会验证语音配置;设置页可调整腾讯语气词过滤级别,关闭语音保留方案和凭据。","修复语音录制、网络或识别失败没有提示,以及终端录音时点击输入框丢失最终文字的问题;终端聊天与对话输入卡片均可点击停止录音并完成识别。","修复实时终端输入后的双光标、光标停在上一字符及文件路径高亮闪烁问题。","工具输入、输出和 Diff 裁剪时在实际位置说明原因;修复 Codex 上下文压缩时内部摘要短暂闪入正文的问题。","终端与对话字体可分别调整,对话字号支持 10–20px;终端字号在两种视图下均可设置,消息正文字号不影响工具详情。","修复原生 Codex 无法进入对话接管页的问题;核实准确会话后接管,中断时提供安全恢复或可复制命令指引;handmux codex resume 默认与原生命令一样只列当前目录会话。","修复服务重启时对话消失并跳回终端,以及 compact 后重发成功仍残留“已发送”的问题;临时反馈离窗即丢弃,成功占位最多保留 10 秒,不影响真实队列和历史。","修复 iOS 对话发送箭头不可见的问题。"],en:["A complete roundup for users upgrading from 0.26: 0.27.0 source and its GitHub Release were public, but npm / Homebrew distribution was not completed. This version carries those updates plus subsequent fixes; the 0.27.0 history is retained.","Voice input adds Tencent real-time and sentence recognition alongside iFlytek real-time recognition. All three share level waveforms and recording animation, inserting text at the recording-start caret without clearing the draft.","handmux setup verifies voice configuration. Settings can adjust Tencent filler-word filtering; turning voice off retains the profile and credentials.","Fixed silent voice capture, network, or recognition failures and lost final text when tapping the terminal input during recording. Both terminal chat and the chat input card can be tapped to stop recording and finish recognition.","Fixed duplicate live-terminal cursors, cursors left on the preceding character after typing, and flickering file-path highlights.","Truncated tool input, output, and diffs explain the limit at the actual cut point. Fixed an internal summary briefly flashing into chat during Codex compaction.","Terminal and chat font sizes can be set independently, with chat supporting 10–20px. Terminal font size remains adjustable in either view; message font size does not affect tool details.","Fixed native Codex sessions missing the chat takeover page. Takeover verifies the exact session and offers safe recovery or a copyable command after interruption. handmux codex resume now defaults to the current directory, matching the native command.","Fixed chat disappearing into terminal during Server restarts and sent placeholders lingering after a compact-time retry. Temporary feedback is discarded on leaving; accepted placeholders last at most 10 seconds without affecting real queues or history.","Fixed the invisible iOS chat send arrow."]}},{version:"0.27.0",date:"2026-09-05",highlight:{zh:"腾讯语音输入 · 终端输入更准确",en:"Tencent voice input · more accurate terminal typing"},items:{zh:["语音输入新增腾讯实时与一句话识别,同时保留讯飞实时识别;三种方案共享实时音量波形与录音动效,识别文字会插入起录时的光标位置,不会清空已有草稿。","语音配置会在首次设置、切换方案或修改字段后直接验证;设置页可调整腾讯语气词过滤级别,关闭语音会保留方案和凭据以便重新开启。","修复语音录制、网络或服务商识别失败时没有提示的问题;未识别出文字时也会明确提示重试。","修复实时终端连续输入英文、中文或使用方向键后偶发双光标或光标停在上一字符的问题;现在文字顺序正确,光标只在正确位置显示一次。","修复 Codex 上下文压缩期间内部摘要短暂闪入正文的问题;工具输入、输出和 Diff 被裁剪时也会在实际位置说明原因。"],en:["Voice input adds Tencent real-time and sentence recognition alongside iFlytek real-time recognition. All three share the live level waveform and recording animation, and insert recognized text at the caret captured when recording started without clearing the draft.","Voice configuration is verified after initial setup, a profile switch, or a field edit. Settings can adjust Tencent filler-word filtering, while turning voice off keeps the selected profile and credentials ready for re-enabling.","Fixed voice capture, network, or provider recognition failures producing no visible feedback; an empty recognition result now clearly asks you to retry.","Fixed live terminal typing occasionally showing two cursors or leaving the cursor on the preceding character. English and Chinese typing now stays in order with arrow-key navigation, and the cursor appears only once at the correct position.","Fixed an internal summary briefly flashing into chat during Codex compaction. Truncated tool input, output, and diffs now also explain the limit at the actual cut point."]}},{version:"0.26.0",date:"2026-09-04",highlight:{zh:"对话精细复制 · Pi 上下文状态",en:"Precise chat copy · Pi context status"},items:{zh:["手机端 Agent 对话支持精细复制:长按消息、工具、Diff 或错误文字选词,拖动首尾手柄调整,并可扩展到屏幕整行或语义整段;流式更新和滚动期间也会保留选区。","Pi 对话的上下文圆环现在显示原生实时用量、运行状态和工作目录;升级会可靠刷新 Connector,已在运行的 Pi 会话执行 /reload 后即可获得新能力。","修复 Codex 历史中的 Diff 使用工作区外绝对临时路径时,更早的消息无法加载的问题。","修复 Codex 只读沙箱配合自动审批时,权限模式被误显示为“自定义”的问题。","修复空收件箱被单个异常 Agent pane 的降级状态长期覆盖为“正在重新连接”的问题。"],en:["Agent chat now supports precise copying on touch devices: long-press message, tool, diff, or error text to select a word, drag either handle to refine it, or expand to the rendered line or semantic paragraph; selections also survive streaming updates and scrolling.","Pi chat’s context ring now shows native live usage, activity, and working directory. Upgrades reliably refresh the Connector; run /reload in an already-open Pi session to expose the new capability.","Fixed older Codex history failing to load when a diff used an absolute temporary path outside the workspace.","Fixed Codex read-only sandbox with automatic approval being mislabeled as a custom permission mode.","Fixed an empty Inbox being indefinitely replaced by “Reconnecting” when a single Agent pane was degraded."]}},{version:"0.25.2",date:"2026-09-02",highlight:{zh:"修复 Agent 对话断流、排队与工具路径",en:"Fixed Agent chat streams, queues, and tool paths"},items:{zh:["修复 Codex 上下文压缩后回复不再实时显示,以及 Pi 历史推进、授权内容更新或 Bridge 启动失败后,对话可能断开、空白或无法重试的问题。","发送状态未知的排队消息会先沿用原消息 ID 安全重试;若仍无法确认,消息会回到对话中,由你决定是否作为新消息再次发送。","工具输入和输出中的本地路径恢复可读;用户主目录缩写为 ~/,密码、Token、Cookie 和私有地址仍会脱敏。","修复订阅用量卡片操作菜单未靠右,以及再次点击三点按钮不能收起菜单的问题。"],en:["Fixed replies no longer streaming after Codex compaction, plus chats disconnecting, going blank, or becoming non-retryable after Pi history advances, authorization updates, or Bridge startup failures.","Queued messages with unknown delivery now retry under their original message ID first; if delivery still cannot be confirmed, the message returns to the conversation so you can choose whether to send it again as new.","Local paths in tool input and output are readable again. User home directories are shortened to ~/, while passwords, tokens, cookies, and private endpoints remain redacted.","Fixed subscription-usage action menus not aligning to the right and not closing when their three-dot button was tapped again."]}},{version:"0.25.1",date:"2026-09-02",highlight:{zh:"修复 Codex 幽灵任务与对话空白",en:"Fixed Codex ghost tasks and blank chats"},items:{zh:["修复 Codex 自动生成标题或回顾摘要的临时线程被误认成当前会话,导致收件箱批量出现无法完成的幽灵“进行中”、对话页报错后空白的问题;服务重启后会重新绑定真实会话并自动撤销旧假状态。"],en:["Fixed Codex title and catch-up helper threads being mistaken for the current conversation, which created ghost “Working” inbox entries and left chat blank after an error. A Server restart now rebinds the real conversation and automatically withdraws stale false states."]}},{version:"0.25.0",date:"2026-09-01",highlight:{zh:"Pi 原生接入 · 多 Agent 对话更可靠",en:"Native Pi support · more reliable agent chat"},items:{zh:["新增 Pi 原生接入:运行 handmux agent enable pi 显式启用接入,以后用 handmux pi 日常启动原生 TUI;Handmux 离线时 Pi 仍可正常使用,结果会在本机等待重放。Pi 对话需在设置中独立开启,当前仍为实验性功能。","Claude Code、Codex 与 Pi 统一接入新的 Agent Runtime:多 pane 状态、完成与出错通知、跨设备已读和实时对话现在由同一套持久数据链提供。","用量页支持单独刷新订阅;Codex 可查看账号、套餐与细分额度,API 分栏可在本机加密保存多个 DeepSeek 和 Moonshot (Kimi) 账户并读取官方余额。","Codex 对话在长会话、切换 pane、Server 重启和弱网重连时更稳定;新会话首条消息、排队与立即引导、发送失败重试、上下文压缩详情都会原位恢复并持续对账。","重写对话滚动与历史分页:上拉阅读不再被新输出抢回底部或推到页首;桌面复制、键盘焦点、前后台重连和统一错误提示也更符合系统习惯。","文件上传支持 ZIP;中文 Markdown 路径、绝对目录和普通句点不再误判或乱码。会话状态还能直接查看当前 Git worktree 根路径与分支。","最低运行环境提高到 Node.js 22.16;低版本会在启动前得到明确升级提示,Homebrew 安装仍会自动提供所需 Node。开机恢复恰遇 npm 替换 Agent 时会短暂等待安装完成,不再误报未安装或丢失恢复的 pane。"],en:["Added native Pi integration. Run handmux agent enable pi once, then use handmux pi for everyday native-TUI launches; Pi remains usable while Handmux is offline, with results queued locally for replay. Pi chat is independently enabled in Settings and remains experimental.","Claude Code, Codex, and Pi now share the new Agent Runtime, with one durable data path for multi-pane state, completion and error notifications, cross-device read state, and live conversations.","Usage subscriptions can now be refreshed individually. Codex shows account, plan, and detailed limits, while the API tab saves multiple DeepSeek and Moonshot (Kimi) accounts encrypted on this computer and reads their official balances.","Codex chat is more reliable across long sessions, pane switches, Server restarts, and weak-network reconnects. First sends, queued and guided messages, safe retries, and context-compaction details now recover and reconcile in place.","Reworked chat scrolling and history pagination so new output no longer steals the reading position or jumps to the top. Desktop copy, keyboard focus, foreground reconnects, and unified error feedback now follow platform conventions more closely.","ZIP uploads are supported. Chinese Markdown paths, absolute directories, and ordinary punctuation no longer become broken links, while session status now shows the current Git worktree root and branch.","The minimum runtime is now Node.js 22.16. Older runtimes receive a clear pre-launch upgrade message, while Homebrew continues to install the required Node automatically. If startup recovery overlaps an npm Agent replacement, Handmux briefly waits for installation instead of falsely reporting the Agent missing or losing restored panes."]}},{version:"0.24.0",date:"2026-08-11",highlight:{zh:"Codex 任务进度与 Goal 原生上线",en:"Native Codex task progress and Goals"},items:{zh:["Codex 对话新增只读回合任务列表:当前运行步骤带动态状态,点按可用 Bottom Sheet 查看完整计划;回合结束后保留可恢复的任务摘要。","Goal 现在完整融入对话:设置或重新开始会立即创建并启动新目标,进行中或暂停的目标常驻在任务列表下方,历史状态留在对应回合;统一详情支持编辑后重新开始、暂停、继续与清除。","终端与对话可预览任意扩展名的文本文件;打开前会按内容区分文本与二进制,普通斜杠文字和未知 Markdown 目标不再误变成可点击路径。","修复了发送消息后回复偶尔排到用户消息上方,以及主屏 App 从其他应用返回后终端或 Codex 对话可能停在旧画面的问题。","Server、Web 与 CLI 底层完成严格 TypeScript 迁移,发布包改为只运行编译产物,并补强了私密状态、会话队列、服务恢复与错误边界。"],en:["Added a read-only turn task list to Codex chat: the active step carries a live indicator, the full plan opens in a Bottom Sheet, and a restorable task summary remains after the turn.","Goals now live naturally in chat: setting or restarting creates and starts a fresh Goal immediately, active or paused Goals stay below the task list, and history stays with its original turn; one shared detail sheet supports edit-and-restart, pause, resume, and clear.","Preview text files with any extension from terminal or chat. A content check separates text from binary files, while slash-separated prose and unknown Markdown targets no longer become misleading file links.","Fixed replies occasionally appearing above the user message that started them, and terminal or Codex chat getting stuck on an old screen after returning to the installed app.","Migrated the Server, Web app, and CLI internals to strict TypeScript, made release packages run compiled output only, and strengthened private state, session queues, service recovery, and API error boundaries."]}},{version:"0.23.0",date:"2026-08-09",highlight:{zh:"Codex 托管对话正式上线",en:"Managed Codex chat is here"},items:{zh:["新增 Codex 托管对话视图:手机与终端保持同一会话,可实时查看 Markdown 回复、完整工具调用、提问与审批,并直接停止任务;断线或重新打开后仍能恢复完整对话。","可用 handmux codex 直接启动托管会话,也可从普通 Codex 窗格原位接管并恢复准确会话;需要终端确认时会明确提示。","Codex 回复期间可继续发送消息:默认按条排队到后续回合,也可编辑、删除或立即引导当前回复。","输入区可直接调整模型、思考强度、Fast 和权限,查看上下文与会话状态,并使用 /goal、/compact、/clear;回复中的文件与网址也可直接在应用内打开。","Codex 与 Claude Code 对话开关现已分开;Codex 正式支持托管对话,Claude Code 对话仍为独立的实验性功能。","修复了应用长时间切到后台后不刷新、多窗格面板受网络阻塞,以及 iPhone 软键盘可能导致终端尺寸异常的问题。"],en:["Added managed Codex chat: the phone and terminal stay on the same session, with live Markdown replies, complete tool calls, questions, approvals and stopping; the full conversation recovers after a disconnect or reopen.","Start a managed session with handmux codex, or take over a plain Codex pane in place and resume its exact session; Handmux clearly asks you to switch to the terminal when confirmation is needed.","Keep sending while Codex is working: messages queue one by one for later turns, or can be edited, deleted, or guided into the current turn immediately.","Change the model, reasoning effort, Fast and permissions from the composer, inspect context and session status, use /goal, /compact and /clear, and open files or URLs from replies directly in the app.","Codex and Claude Code chat now have separate switches: managed Codex chat is fully supported, while Claude Code chat remains an independent experimental feature.","Fixed stale state after a long app switch, network-blocked multi-pane panels, and iPhone soft-keyboard transitions that could leave the terminal at the wrong size."]}},{version:"0.22.1",date:"2026-08-04",highlight:{zh:"网页宽度与网站版本分开控制",en:"Separate page width and site-version controls"},items:{zh:["网页预览器将窄屏 / 宽屏与手机版 / 电脑版分开:宽度切换不重载页面,电脑代理可另外向网站请求所需版本并保留登录状态。","修复了电脑代理临时重启、会话过期或丢失后可能停在错误页的问题,当前标签现在会自动恢复。"],en:["Web Preview now separates narrow/wide page width from mobile/desktop site requests: width changes do not reload, while computer proxy tabs can request a site version and keep their sign-in state.","Fixed proxy tabs getting stuck on an error page after the computer proxy restarted or a browser session expired or disappeared; the current tab now recovers automatically."]}},{version:"0.22.0",date:"2026-08-03",highlight:{zh:"全屏设置 · 窗口与分屏管理更清晰",en:"Full-screen Settings · clearer window and pane management"},items:{zh:["设置改为全屏分组页面:常用选项使用统一的二级页,版本、更新日志、反馈和重新加载应用集中在首层。","列宽调整移到对应的窗口管理或窗格管理中;单窗格调整窗口宽度,多窗格只调整所选窗格,并可恢复自动宽度或原分屏比例。","推送通知、脚本推送和脚本推送记录的入口重新整理;关闭通知前会先确认,同一 App 安装重新开启后仍保留原设备 key。","修复了冷启动时实时终端先显示快照,以及重启后从最近访问打开静态目录产生重复标签的问题。"],en:["Settings is now a full-screen grouped page with consistent detail views, while version, changelog, feedback, and Reload app stay on the first level.","Column sizing now lives in Window or Pane Management: resize a single-pane window or the selected pane in a split, then restore automatic width or the original split ratio.","Push notifications, Script push, and Script Push History are arranged more clearly; turning notifications off requires confirmation, and re-enabling keeps the same device key for that app installation.","Fixed live terminals briefly starting in snapshot mode and static directories opening as duplicate tabs from Recently Visited after a restart."]}},{version:"0.21.0",date:"2026-08-03",highlight:{zh:"网页预览:手机直连、电脑代理与静态目录",en:"Web preview: direct, computer proxy, and static folders"},items:{zh:["新增常驻网页预览器:可由手机直连开发服务、localhost、内网和允许嵌入的网站,也可在配置 previewDomain 后经电脑代理访问;静态目录预览也已融合到同一界面。","网址和静态目录现在使用统一的持久标签与最近访问;切换标签会保留页面、滚动和表单状态,支持手机/电脑视图、网页缩放、刷新、停止及用系统浏览器打开。","电脑代理支持按设备隔离的 Cookie Profile,可在相关企业系统间复用 SSO Cookie,并可选择加密持久化、按网站清理或全部清理。","运行 handmux 的最低 Node.js 版本由 18 提升至 20;网页电脑代理使用的底层依赖要求 Node.js 20。"],en:["Added a persistent Web Preview for direct phone access to development services, localhost, intranet pages, and sites that allow embedding, plus computer proxy access after previewDomain is configured; static folders now share the same interface.","URL and static-folder previews now use unified persistent tabs and recent history; switching tabs preserves page, scroll, and form state, with mobile/desktop views, page zoom, refresh, stop, and Open in system browser.","Computer proxy mode supports a device-isolated Cookie Profile that can reuse SSO cookies across related enterprise systems, with optional encrypted persistence and per-site or full cleanup.","The minimum Node.js version for running handmux increased from 18 to 20 because the computer proxy's underlying dependency requires Node.js 20."]}},{version:"0.20.3",date:"2026-08-01",highlight:{zh:"实时终端显示更稳定流畅",en:"More stable, smoother live terminals"},items:{zh:["修复了实时终端持续输出时偶发缺行,以及内容较短、首次打开或展开键盘时画面位置不稳定的问题;长时间使用和多窗口同时打开也更流畅。"],en:["Fixed occasional missing lines during continuous live output and unstable positioning with short content, first open, or keyboard expansion; long sessions and multiple visible windows also stay smoother."]}},{version:"0.20.2",date:"2026-07-27",highlight:{zh:"实时终端长时间运行更流畅",en:"Smoother long-running live terminals"},items:{zh:["实时终端长时间打开、连续输出大量内容或电脑同时显示多个 PWA 时保持流畅;输出积压时会跳过过期画面并同步最新终端状态,tmux 历史仍可继续查看。"],en:["Live terminals stay responsive during long sessions, heavy output, and multiple visible PWAs; stale intermediate frames are skipped when output falls behind, while the latest tmux state and scrollback remain available."]}},{version:"0.20.1",date:"2026-07-26",highlight:{zh:"聊天发送修复 · 电脑键盘不中断",en:"Reliable chat sending · uninterrupted desktop input"},items:{zh:["电脑端焦点落在 Window 工具栏后,物理键盘输入和 Shift+Enter 仍会作用于当前终端;F5、F12 保留给浏览器。","修复了聊天模式选择文件后没有开始上传、快速连按重复发送同一条内容的问题;空内容发送 Enter 的能力保持不变。"],en:["Physical keyboard input and Shift+Enter keep working after focus lands on the Window toolbar; F5 and F12 remain available to the browser.","Fixed chat uploads not starting after file selection and rapid taps sending the same content more than once; sending Enter with an empty composer remains available."]}},{version:"0.20.0",date:"2026-07-26",highlight:{zh:"终端实时推送 · 弱网自动回退",en:"Live terminal pushing · automatic network fallback"},items:{zh:["手机和电脑的终端输出现在通过 WebSocket 实时推送;首次打开即可上滑浏览最近的 tmux 历史,继续上滑会加载更早内容,回到底部后重新同步最新画面。","实时连接不可用或持续较差时会自动回退到快照拉取,稳定 30 秒后尝试恢复;右上角显示当前模式与延迟,设置中也可固定使用快照拉取并选择刷新频率。","设置中新增「重新加载应用」,服务端更新后无需退出主屏应用即可载入新版客户端;设置二级页面和弹窗现在会按层返回。"],en:["Terminal output now uses WebSocket live pushing on phone and desktop; scroll up immediately for recent tmux history, keep scrolling for older content, and return to the bottom to resynchronize the latest screen.","An unavailable or persistently poor live connection automatically falls back to snapshot pulling and retries after 30 stable seconds; the top-right status shows the current mode and latency, while Settings can pin snapshot pulling and choose its refresh rate.","Settings now includes Reload app, so an updated server can load the new client without quitting the home-screen app; nested Settings pages and dialogs also return one layer at a time."]}},{version:"0.19.0",date:"2026-07-25",highlight:{zh:"电脑物理键盘直输 · Window 切换更流畅",en:"Desktop keyboard input · faster window switching"},items:{zh:["电脑浏览器现在可以用物理键盘直接操作终端,并支持常用终端快捷键、输入法和复制粘贴;Shift+Enter 可进入保留快捷用语、上传、历史和语音的草稿模式,设置中也可手动指定手机或电脑键盘模式。","全站滚动条现在更统一;终端内容超宽时会显示独立横向滚动条,网络较慢时切换 Window 也会立即进入目标终端的加载页面。","Agent 用量现在稳定展示所有设备共享的本机最新状态,Codex 主额度与 CLI /status 保持一致。"],en:["Desktop browsers can now drive the terminal directly from a physical keyboard, with common terminal shortcuts, IME, and copy/paste; Shift+Enter opens draft mode with shortcuts, uploads, history, and voice intact, and Settings can force Mobile or Desktop keyboard mode.","Scrollbars are now consistent across the app; wide terminal content gets its own horizontal scrollbar, and switching Windows on a slow network enters the target terminal loading view immediately.","Agent usage now keeps the latest machine state stable and shared across devices, while the main Codex quota matches CLI /status."]}},{version:"0.18.0",date:"2026-07-22",highlight:{zh:"Tmux 工作区恢复 · 快捷栏自由定制",en:"Tmux workspace recovery · customizable shortcuts"},items:{zh:["新增 Tmux 工作区恢复:电脑或 Tmux 重启后,可从手机或 handmux restore 恢复上次的会话、窗口、分屏、目录和布局;Claude Code / Codex 会话还能继续原对话。","新增 handmux shortcuts:可分别配置命令与聊天模式的共享快捷项;每台手机也能自由混排共享与本机项,或只在本机移除共享项。","handmux setup 现在可以配置动态预览域名;预览不再自动续期,需要延长时由你手动续期或重新打开。"],en:["Added Tmux workspace recovery: after the computer or Tmux restarts, restore the previous sessions, windows, panes, working directories, and layouts from the phone or handmux restore; Claude Code and Codex sessions can also continue their original conversations.","Added handmux shortcuts to configure shared command-mode and chat-mode items; each phone can also freely mix shared and local items or remove a shared item only on that device.","handmux setup can now configure the dynamic-preview domain; previews no longer renew automatically and can be extended manually or reopened when needed."]}},{version:"0.17.8",date:"2026-07-20",highlight:{zh:"分屏地图显示尺寸 · iPhone 交互修复",en:"Pane dimensions in the map · iPhone interaction fixes"},items:{zh:["分屏地图现在会在空间足够的窗格里低调显示真实终端尺寸(列×行),较小窗格仍保持简洁。","修复了分屏地图在 iPhone 上无法显示、长按窗格时触发系统文字选择的问题。","设置分屏列宽时现在会读取当前窗格的实际宽度,不同窗格不再互相沿用调整值。"],en:["The pane map now quietly shows each terminal's real columns × rows when space allows, while smaller tiles stay uncluttered.","Fixed the pane map failing to appear on iPhone and long-pressing a pane triggering the system text-selection UI.","Pane-width settings now read the active pane's actual width, so adjustments no longer carry over between panes."]}},{version:"0.17.7",date:"2026-07-20",highlight:{zh:"单实例启动兜底 · WSL 状态命令修复",en:"Single-instance startup guard · WSL status fix"},items:{zh:["修复安装开机自启后升级、重启可能产生两个后台实例,导致端口占用、URL 不出现或 stop 后仍可访问的问题;启停命令现在统一管理同一个服务,发现重复副本会列出 PID 并全部回收。","handmux status 现在显示实际运行版本,升级后可区分已安装版本;修复了 WSL 中内容显示完毕却不返回命令行的问题。"],en:["Fixed upgrades or restarts creating two background instances after autostart was installed, which could occupy the port, hide the URL, or remain reachable after stop; lifecycle commands now manage one service and list/reap every duplicate PID.","handmux status now shows the actual running version and distinguishes a newly installed version; fixed WSL terminals not returning to the prompt after status output completed."]}},{version:"0.17.6",date:"2026-07-20",highlight:{zh:"推送结果可追踪 · 对话与权限操作更可靠",en:"Traceable push results · safer chats and permissions"},items:{zh:["脚本通知现在会按设备显示成功或失败,失败详情会区分订阅失效、限流、推送服务不可用、拒绝和网络错误;handmux push 也不会再把零送达或部分失败报告为成功。","修复了关闭通知、打开或删除通知记录、查询设备 key 等操作在浏览器或网络无响应时可能一直等待的问题;关闭本地通知开关现在会立即生效。","长对话轮询不再遍历整段会话;历史记录统一每次加载 20 条,首次打开不足一屏时也会自动继续补取更早内容。","权限确认卡调整为左侧取消、右侧确认;取消需要在 2 秒内再次点击,避免误触中断正在等待的请求。"],en:["Script notifications now show success or failure per device, with details for expired subscriptions, rate limits, unavailable push services, rejection, and network errors; handmux push no longer reports zero delivery or partial failure as success.","Fixed notification disabling, inbox loading or deletion, and device-key lookup waiting forever when the browser or network stops responding; the local notification switch now turns off immediately.","Long-chat polling no longer walks the entire session; history loads 20 messages at a time and automatically keeps fetching older messages when the first page does not fill the screen.","Permission cards now place Cancel on the left and Confirm on the right; cancellation requires a second tap within two seconds to prevent accidentally interrupting a pending request."]}},{version:"0.17.5",date:"2026-07-20",highlight:{zh:"通知开启修复 · 长会话与设置可靠性提升",en:"Notification setup fixed · stronger chat and settings reliability"},items:{zh:["修复了安卓 Chrome 开启通知永久转圈、失效订阅假报成功以及更换域名后收不到通知的问题;注册、激活、FCM 与服务器上报现在会分别检查,失效订阅可自动重置。","修复了超长对话反复全量解析、可能拖慢服务并持续占用手机内存的问题;对话记录改为增量读取并限制缓存规模。","恢复设置里的完整版本更新历史;有新版本时的升级提示仍只展示最新一条,更早版本可按需展开。","修复通知记录加载或删除失败时误显示为空、消息短暂消失的问题,现在会保留已有内容并提示重试。","修复 Agent 退出后偶尔残留旧状态、普通 Node 程序被误认成 Codex 的问题;动态预览认证也限制在当前子域,启动失败会显示真实原因。"],en:["Fixed Android Chrome notification setup spinning forever, stale subscriptions being reported as enabled, and notifications not arriving after a domain change; registration, activation, FCM, and server reporting are now checked separately, with expired subscriptions reset automatically.","Fixed very long chats being repeatedly parsed in full, which could slow the service and keep growing phone memory use; transcripts now load incrementally with bounded caches.","Restored the complete version history in Settings; the upgrade prompt still shows only the newest release by default, with older versions expandable on demand.","Fixed notification history appearing empty or briefly losing a message when loading or deletion failed; existing content is now preserved with a retry action.","Fixed stale Agent state after exit and ordinary Node programs occasionally being mistaken for Codex; dynamic-preview authentication is now scoped to the current subdomain and startup failures show their real cause."]}},{version:"0.17.4",date:"2026-07-19",highlight:{zh:"HTTPS 本机预览修复 · 通知链接安全加固",en:"HTTPS localhost previews fixed · safer notification links"},items:{zh:["修复了 HTTPS/WSS 本机服务无法一键预览、带 # 的深链打开失败,以及 Codex pane 偶尔误出现 Claude 对话视图的问题;通知跳转链接也增加了安全校验。"],en:["Fixed one-tap previews for local HTTPS/WSS services, deep links with # fragments, and Claude chat view occasionally appearing on a Codex pane; notification links now receive stricter safety checks too."]}},{version:"0.17.3",date:"2026-07-19",highlight:{zh:"三修官方一键安装的 Claude 识别,真机已验证",en:"Third fix for native-install Claude detection, device-verified"},items:{zh:["修复了官方一键安装器版 Claude Code 仍识别不出的问题(0.17.2 的对账依据在真实环境不成立);本次按真机数据修正,已验证所有官方安装方式都能正确识别(agent 图标、对话视图切换钮正常出现)。"],en:["Fixed native-installer Claude detection still not working (0.17.2 relied on a signal that doesn't hold in the real environment); corrected against real-device data — verified across all official install methods (agent icon and chat-view switch appear)."]}},{version:"0.17.0",date:"2026-07-18",highlight:{zh:"对话视图(实验性)· 通知记录 · 本机地址一键预览",en:"Chat view (experimental) · notification inbox · one-tap localhost preview"},items:{zh:["新增「对话视图」(实验性功能,默认关):到设置里打开「启用对话视图(实验性功能)」后,窗口栏就能把 Claude 会话在终端/对话两个视图间一键切换(需已装 Claude hooks,没装可一键安装)。对话视图把会话读成聊天记录——气泡 + Markdown、工具卡(编辑文件带 +A/−B 和彩色 diff)、Claude 提问时点按即答的问题卡、上下文压缩动画、三套暖色配色;终端视图照旧,完全不受影响。","新增「通知记录」:脚本推送(handmux push)的通知按设备留存(各 100 条),全屏翻看、点开看详情、逐条删除;点手机上的通知直接跳到那条消息的详情。","终端里打印的本机地址(localhost:3000 等)自动变成可点的:点一下就能起代理在手机上预览(带路径),多个端口还能并行切换、自动续期。"],en:["New chat view (experimental, off by default): enable it in Settings → Enable chat view, then flip a Claude pane between terminal and chat from the window bar (requires Claude hooks — one-tap install offered). The chat view reads the session as a conversation — bubbles with Markdown, tool cards (+A/−B and colored diffs for file edits), question cards you answer with a tap, a visible compaction animation, and three warm colour tones. The terminal view is untouched.","New notification inbox: pushes from handmux push are kept per device (latest 100) — browse full-screen, open details, delete one by one; tapping a push lands on that message’s detail.","Localhost URLs printed in the terminal (localhost:3000, …) are now tappable: one tap proxies and previews them on your phone (path preserved), with several ports open in parallel and auto-renewed."]}},{version:"0.16.0",date:"2026-07-15",highlight:{zh:"分屏布局地图 · 手机也能建/删窗格",en:"Split-layout map · create & close panes from the phone"},items:{zh:["有多个窗格的窗口,选择器不再是一条干巴巴的下拉列表,而是照着你屏幕上真实的分屏样子画出来:每一格对应一个窗格,标着序号、正在跑的命令和 Agent 图标,一眼就看出谁在左谁在右、谁在上谁在下,点一下就切过去看那一格。","现在手机上就能直接分屏和关窗格了:长按地图里的某一格,就能把它「左右分屏」或「上下分屏」,也能「关闭」;还没分屏的窗口在它的菜单里也能分,已经分屏的窗口菜单里点「管理分屏」直接进地图。分好之后自动就落在新的那格里,地图也一直开着,随时能接着分或关。","绑定会话的弹窗更清楚了:「新建会话」和「选已有会话」分成两个明确的选项,不会再让人以为点一下「新建」就直接把会话建出来。"],en:["For a window with several panes, the picker is no longer a plain dropdown — it’s drawn to match the way your screen is actually split: each tile is one pane, labelled with its number, the command it’s running, and its agent, so you can tell at a glance which pane is where. Tap a tile to jump to that pane.","You can now split and close panes right from the phone: long-press a tile in the map to Split it left/right or top/bottom, or Close it; a window that isn’t split yet can be split from its menu, and a split window has a “Manage split” entry that opens the map. After a split you’re dropped into the new pane, and the map stays open so you can keep splitting or closing.","The bind-session dialog is clearer: “New session” and “Pick an existing session” are now two distinct choices, so tapping “New” no longer looks like it creates a session on the spot."]}},{version:"0.15.0",date:"2026-07-14",highlight:{zh:"键盘弹起终端自适应 · 全屏程序可上下滚动",en:"Keyboard-aware terminal · scroll inside full-screen apps"},items:{zh:["键盘弹起时终端不再被顶飞:内容自动重排到键盘上方,主屏短内容贴着键盘上沿显示;全屏程序(vim/less/htop 等)可以在里面上下滚动、到顶/底才翻页,默认显示程序的第一行,移动光标时自动跟随。","全屏程序翻页键上方新增「适配高度」和「定位」两个按钮:「适配高度」一键缩字号,收起键盘就能把整屏程序完整塞进手机屏;「定位」点亮后高亮光标所在行并跟随,方便在长内容里盯住光标。键盘弹起的瞬间光标也一直可见,不用再补按一下。","收件箱在一种特定场景下抓不到状态变更:你回应了权限弹窗、但那次回应没产生任何收尾信号时(普通授权、拒绝并反馈、或按 ESC 中断),它会停留在「需要你」。这一版补上识别——授权或拒绝反馈后回到「进行中」,ESC 中断则消掉状态。","光标不用点屏幕也能看到了:一进会话就能看到光标位置,发键/发指令后即使 Claude 正在忙也会亮着。","从设置里启动动态端口预览,现在会像静态预览一样自动弹出预览面板。","会话重命名撞到已有名字时,会明确提示「名称已存在」;修复了终端上滑一点后画面自己往上爬的问题。"],en:["The terminal no longer gets shoved off-screen when the keyboard opens: content reflows to sit just above the keyboard, with short main-screen output resting on its top edge. Full-screen programs (vim/less/htop, etc.) now scroll up/down inside themselves and only page at the edges, default to showing the program’s first line, and follow the cursor as you move it.","Two new buttons above the full-screen pager: “Fit height” shrinks the font in one tap so the whole program fits on the phone with the keyboard down, and “Locate” highlights and follows the cursor’s row so you can keep track of it in long content. The cursor also stays visible the moment the keyboard opens — no extra tap needed.","In one specific case the inbox couldn’t pick up a state change: when you responded to a permission prompt but that response produced no closing signal (a normal approval, a deny-with-feedback, or an ESC interrupt), it would linger on “needs you”. This release adds that detection — approving or denying returns it to “working”, and an ESC interrupt clears it.","The cursor now shows without tapping the screen: you can see where it is the moment you open a session, and it stays lit after you send a key/command even while Claude is busy.","Starting a dynamic-port preview from Settings now auto-opens the preview sheet, just like a static one.","Renaming a session to a name that already exists now says so clearly; and fixed the terminal creeping upward a line at a time after a small scroll up."]}},{version:"0.14.0",date:"2026-07-13",highlight:{zh:"终端文字选中拷贝 · 脚本复用推送通道",en:"Terminal select & copy · scripts reuse the push channel"},items:{zh:["终端可以长按选中文字了:iOS 式首尾手柄精调、跨屏选择,浮条一键拷贝/整行/整段,复制自动去掉行尾空格;选中期间顶部显示「复制模式 · N 行 · M 字」。","你自己的脚本也能复用 handmux 的推送通道:命令行用 handmux push <标题> <正文> 直接给手机发通知(可选 --session/--device 限定范围),脚本跑完主动提醒你。","滚动终端不再收起键盘:滑动时键盘保持、单击才收起;还能用 ⌨ 按钮或底部手柄拖拽显隐键盘,命令/聊天切换也保持键盘不掉。","往上滑看历史更顺了:一次滑到顶只加载一页、不再叠加拉取来回跳,位置稳停在你看的那行,顶部显示「距底 N/M 行」。","全屏程序(vim/less/htop 等)上方不再串出无关的终端历史。","修复了主页误触返回直接退出、以及从通知进入要多按一次返回才能退出的问题。"],en:["You can now long-press to select text in the terminal: iOS-style start/end handles, selection across screens, a callout to copy / whole line / whole paragraph, with trailing spaces trimmed on copy. A “copy mode · N lines · M chars” bar shows while selecting.","Your own scripts can reuse handmux’s push channel: run handmux push <title> <body> to send a notification straight to your phone (optionally scoped with --session/--device) — handy for a script pinging you when it finishes.","Scrolling the terminal no longer dismisses the keyboard: a swipe keeps it up, a single tap puts it away; you can also show/hide it with the ⌨ button or the dock’s grip handle, and it stays up when you switch between command and chat.","Scrolling up through history is smoother: reaching the top loads exactly one page instead of stacking pulls and jumping around, and your place holds steady on the line you were reading, with a “N/M lines from bottom” readout.","A full-screen program (vim/less/htop, etc.) no longer leaks unrelated terminal history above it.","Fixed a stray Back on the home page dropping you straight out, and needing an extra Back to leave after opening the app from a notification."]}},{version:"0.13.0",date:"2026-07-12",highlight:{zh:"终端文件路径高亮可点",en:"Tappable, highlighted file paths"},items:{zh:["终端里的文件路径现在会高亮显示、可以直接点开;这个高亮可以在设置里开关(默认关闭)。","桌面浏览器用鼠标滚轮往上翻,现在能拉出更深的历史了(不再卡在第一屏);桌面和手机都加了一条纤细的滚动条。","设置面板太高时可以整体滚动了,标题和关闭按钮始终可见、够得到。","修复了 agent 图标和底部输入模式偶尔乱跳的问题——现在按 agent 是否真的在运行来判断,分屏里每个窗格也各显各的图标。","handmux setup 新增「令牌」一项:可以手动固定访问令牌,这样每次重启后手机网址不再变化(留空则仍每次自动生成一个)。"],en:["File paths in the terminal are now highlighted and tappable — tap one to open it. You can toggle the highlight in Settings (off by default).","On a desktop browser the mouse wheel now pulls deeper history instead of stalling at the first screen, and a thin scrollbar was added on both desktop and mobile.","The Settings sheet scrolls as a whole when it is taller than the screen, with the title and close button always reachable.","Fixed the agent icon and the bottom input mode occasionally jumping around — both now track whether the agent is actually running, and each pane in a split shows its own icon.","handmux setup has a new “Token” item: you can pin the access token by hand so the phone URL stops changing on every restart (leave it blank to keep auto-generating one each start)."]}},{version:"0.12.3",date:"2026-07-11",highlight:{zh:"接管会话可自定义名称 + Homebrew 一键安装",en:"Name a takeover session · Homebrew install"},items:{zh:["接管电脑上的会话时,可以自己给新会话起名(默认也帮你填好);接管后想回电脑继续的命令,现在直接显示成 handmux open <名称>,照着敲即可。","新增 Homebrew 一键安装:没装 Node 的 Mac 也能用 brew install handmux/tap/handmux 一条命令装好(handmux + Node + tmux)。已有 Node 的话,npm i -g handmux 仍是更轻的选择。"],en:["When taking over a session running on your computer, you can now name the new session yourself (a default is filled in), and the “continue on the computer” hint shows the exact command to run — handmux open <name>.","New Homebrew install: on a Mac without Node, brew install handmux/tap/handmux sets up handmux, Node, and tmux in one command. If you already have Node, npm i -g handmux stays the lighter option."]}},{version:"0.12.2",date:"2026-07-11",highlight:{zh:"修复主屏图标偏大 / 换图标后不刷新",en:"Home-screen icon: right size & always fresh"},items:{zh:["修复了「添加到主屏」的图标在安卓上偏大、以及更换图标后旧图标不刷新的问题——图标更新现在会自动生效(已加到 iPhone 主屏的需删掉重加一次)。"],en:["Fixed the Add-to-Home-Screen icon looking oversized on Android and a changed icon not refreshing for returning users — icon updates now apply automatically (one already on an iOS home screen needs a one-time remove + re-add)."]}},{version:"0.12.1",date:"2026-07-11",highlight:{zh:"全新品牌图标与双色字标",en:"New brand icon & two-tone wordmark"},items:{zh:["焕新品牌:全新的发光终端图标(主屏图标、启动页都换了)+ 圆润的双色「handmux」字标(hand 白、mux 青→绿),官网、分享卡和 README 也一并更新。"],en:['Brand refresh: a new glowing terminal app icon (home-screen icon + boot splash) and a rounded two-tone "handmux" wordmark (hand in white, mux teal→green), with the site, share cards, and README updated to match.']}},{version:"0.12.0",date:"2026-07-11",highlight:{zh:"全屏程序也能滑动滚动 · 反馈入口 · 聊天草稿不丢",en:"Swipe-scroll full-screen apps · feedback channels · chat drafts kept"},items:{zh:["全屏程序(vim / htop / less 等)现在能直接滑动滚动了:开了鼠标的程序像电脑滚轮一样滑着滚,没开鼠标的分页器(less / man / git log)靠滑动逐行滚;每个全屏画面右侧还多了一枚翻页按钮做整页跳。","设置里新增「反馈与交流」:直达 GitHub Issues,中文用户还能扫码进微信交流群;README、官网、文档里也都能找到入口。","聊天框里没发出去的内容现在会自动保存,下次打开自动填回——误划走、切后台被杀、崩溃都不会再丢半截提示词。","修复:从终端链接或「最近」直接打开的文档,点返回会一次收起面板,不再被硬塞进「目录」层、再返一次直接退出 App。"],en:["Full-screen apps (vim / htop / less …) now scroll by swipe: mouse-mode apps scroll like a desktop wheel, and pagers (less / man / git log) scroll line-by-line on a swipe; every full-screen view also gets a page up/down button on the right for whole-page jumps.",'New "Feedback" section in Settings: a direct link to GitHub Issues, plus a WeChat user group for Chinese users — also surfaced in the README, the site, and the docs.',"Whatever you've typed in the chat box is now saved automatically and restored next time you open it — an accidental swipe-away, a background kill, or a crash no longer eats a half-written prompt.","Fixed: a doc opened straight from a terminal link or 最近 now closes the sheet in one Back press, instead of being forced into its folder view and then dropping you out of the app on the next Back."]}},{version:"0.11.1",date:"2026-07-09",highlight:{zh:"修复 Node 18 下无法启动的问题",en:"Fixes startup crash on Node 18"},items:{zh:["修复了电脑用 Node 18 时 handmux 任何命令都启动不了的问题(0.11.0 配置向导引入的依赖要求过新的 Node)。"],en:["Fixed handmux failing to start any command on Node 18 (a dependency introduced by the 0.11.0 setup wizard required a newer Node)."]}},{version:"0.11.0",date:"2026-07-08",highlight:{zh:"国内可用隧道 natapp/cpolar · 配置向导重做",en:"China-usable tunnels · setup redesigned"},items:{zh:["新增两条国内可用的隧道 natapp 和 cpolar:当 Cloudflare 在国内不稳定时,用你自己的免费账号就能把手机连到电脑。只要一个 authtoken;想要固定地址就填公网地址,留空则用免费临时域名;cpolar 的客户端还会自动下载。","`handmux setup` 重做成菜单式向导:每项设置一行、直接显示当前值,想改哪项就点哪项,不用再一路问到底。连接分两级——先选隧道类型,再进去配它的参数;推送、语音也各成小面板。第一次用会一步步带你走,默认落在「直连」并停在「保存并启动」,小白也能顺下来。"],en:["Two China-usable tunnels, natapp and cpolar: when Cloudflare is unreliable inside mainland China, reach your computer from your phone using your own free account. Just an authtoken; add a public URL for a fixed address or leave it blank for a free temporary one — and cpolar's client auto-downloads.",'`handmux setup` is now a menu-style wizard: every setting is a row showing its current value, so you jump straight to what you want to change instead of answering every prompt in order. Connection is two levels — pick the tunnel type, then configure it inside; push and voice are their own mini-panels. A first run walks you through it, defaulting to "Direct" with the cursor on "Save & start".']}},{version:"0.10.0",date:"2026-07-06",highlight:{zh:"升级前预览新功能 · 电脑 handmux open 接管",en:"Preview an update before installing · handmux open"},items:{zh:["更新提示现在会提前告诉你新版有什么:检测到有新版本时,设置里会逐版列出这次升级带来的新功能(一句话说明),让你在电脑上跑 `handmux update` 之前就知道值不值得。","电脑上新增 `handmux open <会话名>`:把你在手机上建的会话直接在电脑终端接回来(没有就新建),不用再记 `tmux new -A -s`。绑定/新建会话的弹窗里也加了这句提示。"],en:["The update notice now tells you what a new version brings before you install it: when an update is detected, Settings lists each newer version's highlight in one line, so you know whether it's worth running `handmux update` on your computer.","New `handmux open <session>` on the computer: reclaim a session you created from your phone straight into your computer's terminal (created if missing) — no need to remember `tmux new -A -s`. The bind/create dialog now hints at it too."]}},{version:"0.9.1",date:"2026-07-06",highlight:{zh:"「添加到主屏」引导",en:'"Add to Home Screen" coach'},items:{zh:["新增「添加到主屏」引导:第一次在浏览器里打开时,提示你把 handmux 装到主屏,像 App 一样全屏打开。安卓可一键安装;iPhone 给出 Safari 的「分享 → 更多 → 添加到主屏幕」三步——iOS 上收推送也需要它。装好后不再打扰。"],en:[`New "Add to Home Screen" coach: the first time you open handmux in a browser, it shows how to install it to your home screen and run it full-screen like an app. Android installs in one tap; iPhone gets the Safari steps (Share → More → Add to Home Screen) — which is also what iOS push needs. It won't nag once you've added it.`]}},{version:"0.9.0",date:"2026-07-05",highlight:{zh:"聊天输入框多行重做",en:"Multi-line chat composer redone"},items:{zh:["聊天输入框多行重做:文字占满整行,麦克风/发送悬到右下角,末行快挤到按钮才让出一行——长消息不再被右侧按钮列挤窄,多行时拖光标也不会误收键盘。"],en:["Chat composer redone for multi-line: text takes the full width, mic/send float in the bottom-right corner, and a row is yielded only when the last line actually reaches them — long messages are no longer squeezed by a right-hand button column, and dragging the caret no longer collapses the keyboard."]}},{version:"0.8.0",date:"2026-07-05",highlight:{zh:"快捷栏可自定义 · 上传体验重做",en:"Customizable quick-bars · upload redone"},items:{zh:["命令模式的常用命令分成「全局」和「当前窗口」两组:快捷栏里全局的(灰)排前、当前窗口的(绿)排后。尾部改成 ⚙ 齿轮,点开更高的编辑器分两区、各自 ▲▼ 排序。新增区一行搞定:顶部「命令/按键」大 Tab 选类型,左侧开关选加到全局还是本窗口。命令可勾「带回车」(点一下直接执行,末尾带 ⏎);按键用 ⌃⇧⌥ + 一个基键拼出组合键(如 Ctrl+C),点一下直接发到终端。","聊天模式的快捷条也能自定义了:末尾同样是 ⚙,点开编辑器,「消息/按键」两个 Tab —— 消息就是一句发给 agent 的话(以 / 开头当斜杠命令),按键用同一套 ⌃⇧⌥ + 基键拼组合键(ESC/Tab/退格默认就在里面)。点任意一条可回到弹窗改,▲▼ 排序。","上传体验重做:进度条不再一冲到 100% 就假装完事——先显示真实发送进度,字节发完后转成「服务器接收中…」,大文件不再像卡死。上传中可随时「取消」,已传完的文件会保留。","重名不再报错:上传一个已存在的文件名会自动改名(如 `报告 (1).pdf`),绝不覆盖原文件。上传失败时也会告诉你具体原因(过大 / 不支持的类型)。","现在可以上传视频了(mp4、mov、webm 等)。","Git 面板现在能打开 `/tmp` 等家目录以外的仓库(比如 agent 在 /tmp 里干活的项目),不再报红。","用量进度条新增「时间竖线」:标出当前重置窗口已过去的时间比例。已用量在竖线左边=烧得比时间慢(稳),越过竖线=烧得偏快,一眼看出自己的节奏。","新增版本更新提示:每次打开检测一次,服务端落后于 npm 最新版时设置齿轮亮红点,进设置能看到当前/最新版本号,按提示在电脑上跑 `handmux update` 升级即可。"],en:[`Command mode's saved commands now split into "Global" and "This window": the quick-bar shows global ones (grey) first, then this window's (green). The trailing + is now a ⚙ opening a taller two-section editor, each reorderable with ▲▼. One add row does it all: a big Command/Key tab picks the type, a left switch picks which list it lands in. Commands can tick "Send Enter" (a tap runs it, marked ⏎); keys are built from ⌃⇧⌥ + a base key into a combo like Ctrl+C that fires straight into the terminal.`,"Chat mode's quick-bar is now customizable too: the same ⚙ at the end opens an editor with a Message/Key tab — a message is a line sent to the agent (starts with / for a slash-command), a key is built from the same ⌃⇧⌥ + base-key picker (ESC/Tab/Backspace ship as defaults). Tap any row to re-open the card and edit it, ▲▼ to reorder.","Upload redone: the bar no longer jumps to 100% and then hangs — it shows real send progress, then flips to “receiving on the server…” once bytes are flushed, so a big file no longer looks stuck. You can Cancel mid-upload; already-uploaded files are kept.","Name clashes no longer fail: uploading an existing name auto-renames (e.g. `report (1).pdf`) and never overwrites. Failures now tell you why (too large / unsupported type).","Video files can now be uploaded (mp4, mov, webm, …).","The git panel can now open repos outside your home directory (e.g. a project an agent is working in under `/tmp`) instead of erroring.",`Usage bars now show a "time marker": a thin vertical line at how far the current reset window has elapsed. Usage left of the line = you're burning slower than the clock; past it = faster — pacing at a glance.`,"New update notice: checked once each time you open the app — when the server is behind the latest npm release, the settings gear lights a dot and Settings shows the current/latest version so you can run `handmux update` on your computer."]}},{version:"0.7.0",date:"2026-07-03",highlight:{zh:"新增「用量」页",en:'New "Usage" page'},items:{zh:["新增「用量」页(顶栏仪表盘图标):一眼看 Claude 的 5 小时 / 本周额度进度条 + 重置倒计时,以及 Codex 的额度环。全部读主机本地文件,不登录账号、不调用 API。Codex 零配置即用;Claude 的实时额度需要在电脑上运行一次 handmux hooks install(会装一个 statusLine 捕获器,已有自定义 statusLine 的绝不覆盖)。"],en:["New \"Usage\" page (gauge icon in the top bar): see Claude's 5-hour / weekly limit bars with reset countdowns, plus Codex's quota ring — at a glance. All read from local files on the host: no account login, no API calls. Codex works with zero setup; Claude's live limits need a one-time `handmux hooks install` on the computer (it adds a statusLine capturer and never clobbers an existing custom statusLine)."]}},{version:"0.6.0",date:"2026-07-02",highlight:{zh:"新增 Codex 支持",en:"Codex support added"},items:{zh:["新增 Codex 支持:收件箱与推送现在同时认得 Claude 和 Codex——Codex 会话的「进行中 / 需要你 / 已完成」都会像 Claude 一样推到手机;tmux 外跑着的 Codex 会话也能一键「接管」进来(codex resume);新建会话的启动命令预设新增 codex。收件箱每一条、以及顶栏当前会话,都带上 Claude / Codex 标记,一眼区分是哪种 agent。","会话抽屉底部新增「未接管会话」:一眼看到在 tmux 外跑着、手机还控制不了的 Claude / Codex(带状态、时间、最后一条消息),点「接管」即可在 tmux 里续接同一会话——自动加进会话列表并跳进去,以后手机随时回来。"],en:["Added Codex support: the inbox and push now recognize both Claude and Codex — a Codex session's working / waiting-on-you / done states reach your phone just like Claude. You can take over Codex sessions running outside tmux (codex resume), and there's a new codex startup-command preset. Every inbox row and the current-session topbar now carry a Claude / Codex mark so you can tell the two apart at a glance.",`The session drawer now has a "not taken over" section at the bottom: Claude / Codex sessions running outside tmux that your phone can't steer yet (with their state, time, and last message). Tap Take over to resume the same conversation inside tmux — it's added to your session list and opened, so you can return to it from your phone anytime.`]}},{version:"0.5.0",date:"2026-06-28",highlight:{zh:"首个公开版 · 多语言界面",en:"First public release · multi-language UI"},items:{zh:["首个公开发布版本(npm 上的 handmux)。","新增繁体中文、日语、韩语界面(设置 → Language 切换)。","想法角标:有未完成想法时,灯泡图标右上角显示数量。","设置面板列数调节:实时显示当前列数,新增 ±1 精细调节按钮。"],en:["First public release (handmux on npm).","Added Traditional Chinese, Japanese, and Korean UI (Settings → Language to switch).","Idea badge: when there are pending ideas, the lightbulb icon shows a count in the corner.","Settings column control: shows the current column count live, with new ±1 fine-adjust buttons."]}},{date:"2026-06",label:{zh:"早期内测",en:"Early builds"},highlight:{zh:"早期内测",en:"Early builds"},items:{zh:["新增「Git」面板(顶栏图标):仿 VS Code,一页同屏看变更 + 提交历史,点文件/提交看全屏彩色 diff;只读,不动你的工作树。可绑多个目录用 tab 切换。","新增「想法」管理器(顶栏灯泡):按窗口记待办,可编辑、拖拽排序、一键填入、语音输入。","网站预览:选目录预览静态站点,或填端口预览本机正在跑的服务(走专属子域名);图片预览:文件/终端里点图片(含 GIF)直接内嵌打开,可捏合缩放、长按保存。","文件:上传/下载(进度条、系统分享上传),浏览器打开即落到当前会话目录,支持 /tmp、$TMPDIR;文档在应用内预览 Markdown/txt/log/sh,可语音朗读(逐句高亮)。","收件箱 + Web Push:汇总各会话「进行中/已完成/需要你」,窗口标签带状态色点,需要你时推送到手机。","命令面板:常用 + 每会话最近命令,斜杠命令快捷键(/clear、/compact、/model…)。","可靠性:断线重连(退避 + 每请求超时 + 断线横幅,后台自动暂停轮询),离线兜底页。","首版:手机浏览器驱动真实 tmux 面板(xterm 终端 + 会话/窗口/pane 导航 + 深链),移动按键区、键盘自动抬升、列宽/字号调节,可添加到主屏(PWA)。"],en:['New "Git" panel (top-bar icon): VS Code style — changes + commit history on one screen, tap a file/commit for a full-screen colored diff; read-only, never touches your working tree. Bind multiple dirs and switch via tabs.','New "Ideas" manager (top-bar lightbulb): per-window to-dos — edit, drag to reorder, one-tap insert, voice input.',"Website preview: pick a directory for a static site, or a port for a service running locally (dedicated subdomain); image preview: tap an image (including GIFs) in Files or the terminal to open inline, pinch to zoom, long-press to save.","Files: upload/download (progress bar, share-to-upload), the browser opens straight to the current session dir, /tmp and $TMPDIR supported; documents preview in-app (Markdown/txt/log/sh) and can be read aloud (sentence-by-sentence highlight).","Inbox + Web Push: summarizes each session's In-progress / Done / Needs-you, window tabs get a status color dot, and Needs-you pushes to your phone.","Command panel: frequent + per-session recent commands, slash-command shortcuts (/clear, /compact, /model, …).","Reliability: reconnect on disconnect (backoff + per-request timeout + connection-lost banner, polling auto-paused in the background) and an offline fallback page.","First release: a phone browser drives real tmux panes (xterm terminal + session/window/pane navigation + deep links), a mobile key bar, keyboard auto-lift, column-width/font-size adjustment, and add-to-home-screen (PWA)."]}}],p4=e=>e.version||e.date,ch=mN[0]?p4(mN[0]):null,v4=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Xg(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const n=e;return n.kind!=="codex_resume"||typeof n.sessionId!="string"||!v4.test(n.sessionId)||n.command!==`handmux codex resume ${n.sessionId}`?null:{kind:"codex_resume",sessionId:n.sessionId,command:n.command}}function f0(e){if(!e||typeof e!="object")return null;const n=e;if(typeof n.error!="string"||!n.error)return null;const i=Xg(n.recovery);return{error:n.error,code:typeof n.code=="string"&&n.code?n.code:null,requestId:typeof n.requestId=="string"&&n.requestId?n.requestId:null,...i?{recovery:i}:{}}}class ar extends Error{constructor(){super("unauthorized"),this.name="UnauthorizedError"}}class Er extends Error{constructor(i,a,u,g,d,o){super(i);vr(this,"status");vr(this,"serverError");vr(this,"code");vr(this,"requestId");vr(this,"recovery");this.name="ApiError",this.status=a,this.serverError=u??null,this.code=g??null,this.requestId=d??null,this.recovery=o??null}}class CR extends Er{constructor(){super("Sentence ASR returned no recognized speech",502,"Sentence ASR returned no recognized speech","speech_not_recognized"),this.name="SpeechNotRecognizedError"}}let Wj=Promise.resolve();function g4(e){const n=Wj.then(()=>{var i;return(i=navigator.locks)!=null&&i.request?navigator.locks.request("handmux-auth-cookie",e):e()});return Wj=n.catch(()=>{}),n}let Rg=!1,ER=null,SR=!1,jR=!0,DR=!0;const b4=()=>SR,uh=()=>jR,dh=()=>DR,_4=()=>Rg,qj=()=>Rg&&ER!==null;function Tc(e){if(Rg=e.authenticated,ER=e.currentDeviceId??null,SR=e.tokenEnabled===!0,jR=e.trustedDeviceEnabled!==!1,DR=e.trustedOriginEnabled!==!1,!Rg)try{gg(!1)}catch{}}function y4(){try{return sR()}catch{return null}}function fo(e={}){const n=y4();return{...n?{Authorization:`Bearer ${n}`}:{},...e}}async function so(e="/api/auth/status",n="GET",i){return g4(async()=>{const a=await mw(e,n,i);return a.sessionPending?mw("/api/auth/status","GET"):n==="POST"&&e==="/api/auth/pairing"?mw(e,"GET"):a})}class td extends Error{constructor(n,i){super(`auth -> ${n}`),this.status=n,this.code=i}}async function mw(e,n,i){const a=new AbortController,u=setTimeout(()=>a.abort(),8e3);try{const g=await fetch(e,{method:n,credentials:"same-origin",cache:"no-store",signal:a.signal,headers:{...fo(),...i?{"Content-Type":"application/json"}:{}},...i?{body:JSON.stringify({id:i})}:{}});if(!g.ok){let o=null;try{const c=await g.json(),f=typeof c.code=="string"?c.code:c.error;typeof f=="string"&&(o=f)}catch{}throw new td(g.status,o)}const d=await g.json();if(!d||d.mode!=="trusted-device"&&d.mode!=="token"||typeof d.authenticated!="boolean"||!Number.isFinite(d.serverTime))throw new Error("Invalid authentication response");return d}finally{clearTimeout(u)}}async function po(){return new ar}async function kR(){const e=await so("/api/auth/logout","POST");if(e.authenticated)throw new Error("Device is still authorized");Tc(e)}const x4={jpg:"image/jpeg",jpeg:"image/jpeg",jfif:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",bmp:"image/bmp",svg:"image/svg+xml",ico:"image/x-icon",heic:"image/heic",heif:"image/heif",avif:"image/avif",tif:"image/tiff",tiff:"image/tiff",pdf:"application/pdf",txt:"text/plain",log:"text/plain",md:"text/markdown",markdown:"text/markdown",csv:"text/csv",json:"application/json",xml:"application/xml",html:"text/html",htm:"text/html",zip:"application/zip",mp4:"video/mp4",m4v:"video/mp4",mov:"video/quicktime",webm:"video/webm",mkv:"video/x-matroska",avi:"video/x-msvideo",wmv:"video/x-ms-wmv",flv:"video/x-flv","3gp":"video/3gpp",ogv:"video/ogg",mpeg:"video/mpeg",mpg:"video/mpeg",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation"};function Jg(e){const n=e||"",i=n.lastIndexOf(".");return i<0?"":x4[n.slice(i+1).toLowerCase()]||""}function w4(e){return Jg(e).startsWith("image/")}async function qt(e,n={}){const{timeoutMs:i,signal:a,...u}=n,g=fo(u.headers);u.body&&!Object.keys(g).some(f=>f.toLowerCase()==="content-type")&&(g["Content-Type"]="application/json");let d=null,o=null;const c=()=>d==null?void 0:d.abort();(i||a)&&(d=new AbortController,a!=null&&a.aborted?d.abort():a==null||a.addEventListener("abort",c,{once:!0}),i&&(o=setTimeout(()=>d==null?void 0:d.abort(),i)));try{let f=await fetch(e,{cache:"no-store",credentials:"same-origin",...u,headers:g,...d?{signal:d.signal}:{}});if(f.status===401&&g.Authorization&&!e.startsWith("/api/auth/")&&(await new Promise(v=>setTimeout(v,500)),f=await fetch(e,{cache:"no-store",credentials:"same-origin",...u,headers:g,...d?{signal:d.signal}:{}})),f.status===401)throw await po();if(!f.ok){let v=null;try{v=f0(await f.json())}catch{}throw new Er((v==null?void 0:v.error)||`${e} -> ${f.status}`,f.status,v==null?void 0:v.error,v==null?void 0:v.code,v==null?void 0:v.requestId,v==null?void 0:v.recovery)}return f.status===204?{unchanged:!0}:await f.json()}catch(f){throw d!=null&&d.signal.aborted&&!(a!=null&&a.aborted)?new Error(`${e} -> timeout`):f}finally{o!==null&&clearTimeout(o),a==null||a.removeEventListener("abort",c)}}const Gj=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null;function N4(){return{slices:new Map}}function C4(e,n){var u;const i=new Map(e.slices),a=Gj((u=Gj(n))==null?void 0:u.result);return typeof(a==null?void 0:a.index)=="number"&&typeof a.voice_text_str=="string"&&i.set(a.index,a.voice_text_str),{slices:i}}function E4(e){return[...e.slices.keys()].sort((n,i)=>n-i).map(n=>e.slices.get(n)).join("")}function TR(e){const n=window.atob(e),i=new Uint8Array(n.length);for(let a=0;a<n.length;a++)i[a]=n.charCodeAt(a);return i}const S4=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,j4={provider:"tencent",protocol:"tencent-asr-v2",parseSession(e){return e.provider==="tencent"&&e.protocol==="tencent-asr-v2"&&typeof e.url=="string"?{provider:"tencent",protocol:"tencent-asr-v2",url:e.url}:null},createDriver(){let e=N4();return{audio:TR,end:()=>JSON.stringify({type:"end"}),consume(n){e=C4(e,n);const i=S4(n),a=i==null?void 0:i.code;return{text:E4(e),final:(i==null?void 0:i.final)===1,...typeof a=="number"&&a!==0?{error:String((i==null?void 0:i.message)||`Tencent ASR ${a}`)}:{}}}}}},D4={language:"zh_cn",domain:"iat",accent:"mandarin",vad_eos:1e4,dwa:"wpgs",ptt:1,nunum:1},p0="audio/L16;rate=16000",mh=e=>e!==null&&typeof e=="object"?e:null;function k4(e,n){return{common:{app_id:e},business:{...D4},data:{status:0,format:p0,encoding:"raw",audio:n}}}function T4(e){return{data:{status:1,format:p0,encoding:"raw",audio:e}}}function R4(){return{data:{status:2,format:p0,encoding:"raw",audio:""}}}function A4(){return{sentences:new Map}}function U4(e,n){var d;const i=mh((d=mh(n))==null?void 0:d.data),a=mh(i==null?void 0:i.result);if(!a||typeof a.sn!="number"||!Array.isArray(a.ws))return e;const u=a.ws.map(o=>{var f;const c=(f=mh(o))==null?void 0:f.cw;return Array.isArray(c)?c.map(v=>{var _;const h=(_=mh(v))==null?void 0:_.w;return typeof h=="string"?h:""}).join(""):""}).join(""),g=new Map(e.sentences);if(a.pgs==="rpl"&&Array.isArray(a.rg)&&typeof a.rg[0]=="number"&&typeof a.rg[1]=="number")for(let o=a.rg[0];o<=a.rg[1];o++)g.delete(o);return g.set(a.sn,u),{sentences:g}}function M4(e){return[...e.sentences.keys()].sort((n,i)=>n-i).map(n=>e.sentences.get(n)).join("")}const Kj=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,L4={provider:"xfyun",protocol:"xfyun-iat-v2",parseSession(e){return e.provider==="xfyun"&&e.protocol==="xfyun-iat-v2"&&typeof e.url=="string"&&typeof e.appId=="string"?{provider:"xfyun",protocol:"xfyun-iat-v2",url:e.url,appId:e.appId}:null},createDriver(e){if(typeof e.appId!="string")throw new Error("XFYUN ASR session is missing appId");const n=e.appId;let i=!0,a=A4();return{audio(u){const g=i?k4(n,u):T4(u);return i=!1,JSON.stringify(g)},end:()=>JSON.stringify(R4()),consume(u){a=U4(a,u);const g=Kj(u),d=Kj(g==null?void 0:g.data),o=g==null?void 0:g.code;return{text:M4(a),final:(d==null?void 0:d.status)===2,...typeof o=="number"&&o!==0?{error:String((g==null?void 0:g.message)||`XFYUN ${o}`)}:{}}}}}},I4=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null;function V4(e){const n=new Map;for(const i of e){if(!i.protocol||n.has(i.protocol))throw new Error(`duplicate voice protocol: ${i.protocol}`);n.set(i.protocol,i)}return{adapters:[...e],parseSession(i){var u;const a=I4(i);return!a||typeof a.protocol!="string"?null:((u=n.get(a.protocol))==null?void 0:u.parseSession(a))??null},createDriver(i){const a=n.get(i.protocol);if(!a||i.provider!==a.provider)throw new Error(`unsupported ASR protocol: ${i.protocol}`);return a.createDriver(i)}}}const RR=V4([L4,j4]),O4=e=>RR.parseSession(e),P4=e=>RR.createDriver(e),B4=["protected","unprotected","degraded"],F4=["create","create-renamed","already-present","unsupported"],AR=["pending","running","succeeded","partial","failed","interrupted"],H4=["restored","already-present","failed"],z4=["plan","topology","agent","restore","reconcile"],ao=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,nd=(e,n)=>typeof n=="string"&&e.includes(n)?n:void 0,Ia=e=>typeof e=="number"&&Number.isFinite(e)?e:void 0,Ii=e=>typeof e=="string"?e:e===null?null:void 0,_g=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):[],In=(e,n)=>n===void 0?{}:{[e]:n};function $4(e){const n=ao(e);return n?{...In("status",nd(B4,n.status)),...In("lastSuccessfulCaptureAt",Ii(n.lastSuccessfulCaptureAt)),...In("errorCode",Ii(n.errorCode))}:null}function W4(e){const n=ao(e);return n?{...In("operationId",typeof n.operationId=="string"?n.operationId:void 0),...In("status",nd(AR,n.status)),...In("reused",typeof n.reused=="boolean"?n.reused:void 0)}:null}const hN=e=>{const n=ao(e);if(n)return{...In("sessions",Ia(n.sessions)),...In("windows",Ia(n.windows)),...In("panes",Ia(n.panes)),...In("agents",Ia(n.agents))}},UR=e=>{const n=ao(e);return n?{...In("logicalId",Ii(n.logicalId)),...In("sourceName",Ii(n.sourceName)),...In("targetName",Ii(n.targetName)),...In("action",n.action===null?null:nd(F4,n.action))}:null};function q4(e){const n=ao(e);if(!n)return null;const i=ao(n.planSummary),a=hN(n.summary),u=i?{...hN(i),...In("create",Ia(i.create)),...In("renamed",Ia(i.renamed)),...In("alreadyPresent",Ia(i.alreadyPresent)),...In("unsupported",Ia(i.unsupported))}:void 0,g=Ia(n.pendingCount)??(n.pendingCount===null?null:void 0);return{...In("checkpointId",Ii(n.checkpointId)),...In("capturedAt",Ii(n.capturedAt)),...In("changeReason",Ii(n.changeReason)),...In("serverNow",Ii(n.serverNow)),...In("expiresAt",Ii(n.expiresAt)),...In("promptEligible",typeof n.promptEligible=="boolean"?n.promptEligible:void 0),...In("resolved",typeof n.resolved=="boolean"?n.resolved:void 0),...In("pendingCount",g),...In("summary",a),...In("planSummary",u),...Array.isArray(n.sessions)?{sessions:n.sessions.flatMap(d=>{const o=UR(d);return o?[o]:[]})}:{},...Array.isArray(n.warningCodes)?{warningCodes:_g(n.warningCodes)}:{},...n.mapping!==void 0?{mapping:n.mapping}:{}}}function G4(e){const n=ao(e);if(!n)return null;const i=ao(n.progress),a=ao(n.request),u=Array.isArray(n.results)?n.results.flatMap(c=>{const f=ao(c),v=UR(c);return!f||!v?[]:[{...v,...In("status",f.status===null?null:nd(H4,f.status)),...In("stage",f.stage===null?null:nd(z4,f.stage)),...In("errorCode",Ii(f.errorCode)),...In("errorMessage",Ii(f.errorMessage)),warningCodes:_g(f.warningCodes)}]}):[],g=i?{...In("completed",Ia(i.completed)),...In("total",Ia(i.total))}:void 0,d=typeof(a==null?void 0:a.checkpointId)=="string"?a.checkpointId:void 0,o=a&&d?{checkpointId:d,...Array.isArray(a.sessions)?{sessions:_g(a.sessions)}:{},...typeof a.historical=="boolean"?{historical:a.historical}:{}}:void 0;return{...typeof n.id=="string"?{id:n.id}:{},...In("status",n.status===null?null:nd(AR,n.status)),...In("request",o),...In("createdAt",Ii(n.createdAt)),...In("updatedAt",Ii(n.updatedAt)),...In("startedAt",Ii(n.startedAt)),...In("completedAt",Ii(n.completedAt)),...In("progress",g),...In("summary",hN(n.summary)),...Array.isArray(n.results)?{results:u}:{},...In("errorCode",Ii(n.errorCode)),...In("errorMessage",Ii(n.errorMessage)),...Array.isArray(n.warningCodes)?{warningCodes:_g(n.warningCodes)}:{},...n.mapping!==void 0?{mapping:n.mapping}:{}}}function K4(e,{ignored:n=!1,autoShown:i=!1,liveSessionCount:a=0}={}){return!e||!e.promptEligible||n===!0||e.resolved||(e.pendingCount??0)<1?"none":a===0&&i!==!0?"auto-dialog":"card"}function MR(e){return(e==null?void 0:e.changeReason)==="boot-changed"?"workspace.bootDetected":"workspace.tmuxDetected"}function ai(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}const fN=/^[a-z][a-z0-9-]{0,63}$/;function Y4(e){const n=ai(e),i=ai(n==null?void 0:n.capabilities),a=(n==null?void 0:n.capabilityMetadata)===void 0?void 0:ai(n.capabilityMetadata),u=(a==null?void 0:a.conversation)===void 0?void 0:ai(a.conversation);if(!n||typeof n.id!="string"||!fN.test(n.id)||typeof n.label!="string"||!n.label.trim()||n.label.length>128||n.iconId!==void 0&&(typeof n.iconId!="string"||!fN.test(n.iconId))||!i||typeof i.inbox!="boolean"||typeof i.conversation!="boolean"||i.conversationActivation!==void 0&&typeof i.conversationActivation!="boolean"||i.conversationGoal!==void 0&&typeof i.conversationGoal!="boolean"||i.conversationPlan!==void 0&&typeof i.conversationPlan!="boolean"||i.conversationContext!==void 0&&typeof i.conversationContext!="boolean"||i.conversationPermission!==void 0&&typeof i.conversationPermission!="boolean"||i.conversationCommands!==void 0&&typeof i.conversationCommands!="boolean"||typeof i.interaction!="boolean"||i.sessionControl!==void 0&&typeof i.sessionControl!="boolean"||typeof i.subscriptionUsage!="boolean"||n.capabilityMetadata!==void 0&&!a||(a==null?void 0:a.conversation)!==void 0&&(!u||typeof u.experimental!="boolean"))return null;const g=u==null?void 0:u.experimental;return{id:n.id,label:n.label,...n.iconId===void 0?{}:{iconId:n.iconId},capabilities:{inbox:i.inbox,conversation:i.conversation,...i.conversationActivation===void 0?{}:{conversationActivation:i.conversationActivation},...i.conversationGoal===void 0?{}:{conversationGoal:i.conversationGoal},...i.conversationPlan===void 0?{}:{conversationPlan:i.conversationPlan},...i.conversationContext===void 0?{}:{conversationContext:i.conversationContext},...i.conversationPermission===void 0?{}:{conversationPermission:i.conversationPermission},...i.conversationCommands===void 0?{}:{conversationCommands:i.conversationCommands},interaction:i.interaction,...i.sessionControl===void 0?{}:{sessionControl:i.sessionControl},subscriptionUsage:i.subscriptionUsage},...g===void 0?{}:{capabilityMetadata:{conversation:{experimental:g}}}}}function X4(e){const n=ai(e);return!n||typeof n.agentId!="string"||!fN.test(n.agentId)||typeof n.paneId!="string"||!n.paneId||n.paneId.length>256||typeof n.runId!="string"||!n.runId||n.runId.length>256||n.sessionId!==void 0&&(typeof n.sessionId!="string"||!n.sessionId||n.sessionId.length>1024)?null:{agentId:n.agentId,paneId:n.paneId,runId:n.runId,...n.sessionId===void 0?{}:{sessionId:n.sessionId}}}const J4=new Set(["starting","ready","degraded","unavailable"]);function Q4(e,n){const i=ai(e);return!i||typeof i.adapterId!="string"||!n.has(i.adapterId)||typeof i.availability!="string"||!J4.has(i.availability)||i.capability!==void 0&&(typeof i.capability!="string"||!i.capability||i.capability.length>64)||i.message!==void 0&&(typeof i.message!="string"||i.message.length>1024)||i.lastSuccessAt!==void 0&&(typeof i.lastSuccessAt!="number"||!Number.isFinite(i.lastSuccessAt))?null:{adapterId:i.adapterId,availability:i.availability,...i.capability===void 0?{}:{capability:i.capability},...i.message===void 0?{}:{message:i.message},...i.lastSuccessAt===void 0?{}:{lastSuccessAt:i.lastSuccessAt}}}async function Kv(){const e=ai(await qt("/api/agents/capabilities",{timeoutMs:4e3}));if(!e||!Array.isArray(e.adapters))return{descriptors:[],runs:[],health:[]};const n=e.adapters.map(Y4).filter(o=>o!==null),i=new Map;for(const o of n)i.set(o.id,(i.get(o.id)??0)+1);const a=n.filter(o=>i.get(o.id)===1),u=new Set(a.map(o=>o.id)),g=Array.isArray(e.runs)?e.runs.map(X4).filter(o=>o!==null&&u.has(o.agentId)):[],d=new Map;for(const o of g)d.set(o.paneId,(d.get(o.paneId)??0)+1);return{descriptors:a,runs:g.filter(o=>d.get(o.paneId)===1),health:Array.isArray(e.health)?e.health.map(o=>Q4(o,u)).filter(o=>o!==null):[]}}async function Z4(e){if(!e.length||e.length>256||e.some(u=>typeof u!="string"||!u||u.length>256))throw new TypeError("Invalid terminal notification ids");const n=ai(await qt("/api/agents/inbox/notifications/read",{method:"POST",body:JSON.stringify({notificationIds:[...e]}),timeoutMs:4e3})),i=Array.isArray(n==null?void 0:n.markedIds)?n.markedIds.filter(u=>typeof u=="string"&&u.length>0):[],a=Go(n==null?void 0:n.readAt);return{markedIds:i,...a===void 0?{}:{readAt:a}}}const Go=e=>typeof e=="number"&&Number.isFinite(e)?e:void 0;function e6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);return typeof(i==null?void 0:i.id)=="string"&&typeof i.name=="string"?[{id:i.id,name:i.name}]:[]}):[]}function t6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.id!="string")return[];const a=Go(i.width);return[{id:i.id,name:typeof i.name=="string"?i.name:i.id,panes:Go(i.panes)??0,...typeof i.active=="boolean"?{active:i.active}:{},...a!==void 0?{width:a}:{},...typeof i.activePaneId=="string"?{activePaneId:i.activePaneId}:{}}]}):[]}function n6(e){return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.id!="string")return[];const a=Go(i.left),u=Go(i.top),g=Go(i.width),d=Go(i.height);return[{id:i.id,...typeof i.active=="boolean"?{active:i.active}:{},...typeof i.command=="string"||i.command===null?{command:i.command}:{},...typeof i.agent=="string"||i.agent===null?{agent:i.agent}:{},...a!==void 0?{left:a}:{},...u!==void 0?{top:u}:{},...g!==void 0?{width:g}:{},...d!==void 0?{height:d}:{}}]}):[]}const Ul=async()=>e6(await qt("/api/sessions")),Yj=(e=!1,n)=>qt(`/api/agents/usage${e?`?refresh=true${n?`&target=${encodeURIComponent(n)}`:""}`:""}`,e?{timeoutMs:3e4}:{}),Xj=()=>qt("/api/api-accounts"),r6=(e,n)=>qt("/api/api-accounts",{method:"POST",body:JSON.stringify(e),timeoutMs:15e3,...n?{signal:n}:{}}),i6=(e,n,i)=>qt(`/api/api-accounts/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(n),timeoutMs:15e3,...i?{signal:i}:{}}),s6=e=>qt(`/api/api-accounts/${encodeURIComponent(e)}`,{method:"DELETE"}),a6=e=>qt(`/api/api-accounts/${encodeURIComponent(e)}/query`,{method:"POST",timeoutMs:15e3}),Tl=async e=>t6(await qt(`/api/windows?session=${encodeURIComponent(e)}`)),qs=async e=>n6(await qt(`/api/panes?window=${encodeURIComponent(e)}`,{timeoutMs:8e3})),o6=(e,n=1500,i)=>qt(`/api/history?pane=${encodeURIComponent(e)}&lines=${n}${i?`&since=${i}`:""}`,{timeoutMs:8e3}),Jj=(e,n,i=!0)=>qt("/api/send",{method:"POST",body:JSON.stringify({pane:e,text:n,enter:i})}),v0=(e,n)=>qt("/api/keys",{method:"POST",body:JSON.stringify({pane:e,keys:n})}),l6=(e,n)=>qt("/api/input",{method:"POST",body:JSON.stringify({pane:e,hex:n})}),c6=(e,n,i=1)=>qt("/api/scroll",{method:"POST",body:JSON.stringify({pane:e,dir:n,lines:i})}),u6=(e,n,i)=>qt("/api/resize",{method:"POST",body:JSON.stringify({window:e,cols:n,rows:i})}),d6=(e,n)=>qt("/api/resize",{method:"POST",body:JSON.stringify({pane:e,cols:n})}),m6=e=>qt(`/api/layout?window=${encodeURIComponent(e)}`),h6=(e,n)=>qt("/api/layout",{method:"POST",body:JSON.stringify({window:e,layout:n})}),f6=(e,n)=>qt("/api/resize",{method:"POST",body:JSON.stringify({window:e,auto:!0,layout:n})}),p6=(e,n,i)=>qt("/api/sessions",{method:"POST",body:JSON.stringify({name:e,cwd:n,cmd:i})}),LR=e=>{const n=ai(e);return n?{...typeof n.id=="string"?{id:n.id}:{},...typeof n.session=="string"?{session:n.session}:{},...typeof n.name=="string"?{name:n.name}:{},...typeof n.window=="string"?{window:n.window}:{},...typeof n.pane=="string"?{pane:n.pane}:{}}:{}},v6=async(e,n,i,a,u)=>LR(await qt("/api/windows",{method:"POST",body:JSON.stringify({session:e,pane:n,name:i,cwd:a,cmd:u})})),g6=(e,n)=>qt("/api/sessions",{method:"PATCH",body:JSON.stringify({id:e,name:n})}),b6=(e,n)=>qt("/api/windows",{method:"PATCH",body:JSON.stringify({id:e,name:n})}),_6=e=>qt(`/api/windows?window=${encodeURIComponent(e)}`,{method:"DELETE"}),y6=(e,n)=>qt("/api/windows/swap",{method:"POST",body:JSON.stringify({a:e,b:n})}),Qj=(e,n)=>qt("/api/panes/split",{method:"POST",body:JSON.stringify({pane:e,dir:n})}),x6=e=>qt(`/api/panes?pane=${encodeURIComponent(e)}`,{method:"DELETE"}),w6=(e,n)=>qt("/api/dir",{method:"POST",body:JSON.stringify({dir:e,name:n})}),Zj=async(e,n=null)=>{const i=ai(await qt(`/api/file?path=${encodeURIComponent(e)}${n!=null?`&mtime=${encodeURIComponent(n)}`:""}`,{timeoutMs:8e3}));if((i==null?void 0:i.notModified)===!0)return{notModified:!0};if(!i||typeof i.type!="string"||typeof i.name!="string")throw new Error("file response is invalid");return{type:i.type,name:i.name,content:i.content,...i.mtimeMs===null?{mtimeMs:null}:typeof i.mtimeMs=="number"&&Number.isFinite(i.mtimeMs)?{mtimeMs:i.mtimeMs}:{}}},g0=e=>qt(`/api/dir${e?`?path=${encodeURIComponent(e)}`:""}`,{timeoutMs:8e3}),Uc=e=>qt(`/api/pane-cwd?pane=${encodeURIComponent(e)}`,{timeoutMs:8e3});async function N6(e="medium"){const n=O4(await qt(`/api/asr/session?fillerFilter=${encodeURIComponent(e)}`,{timeoutMs:8e3}));if(n)return n;throw new Error("ASR session returned an unsupported provider")}async function C6(e,n="medium"){const i=new ArrayBuffer(e.byteLength);new Uint8Array(i).set(e);const a=ai(await qt(`/api/asr/sentence?fillerFilter=${encodeURIComponent(n)}`,{method:"POST",headers:{"Content-Type":"application/octet-stream"},body:i,timeoutMs:7e4}));if(!a||typeof a.text!="string")throw new Error("Sentence ASR returned an invalid response");if(a.text.trim()==="")throw new CR;return a.text}const E6=()=>qt("/api/config",{timeoutMs:8e3}),S6=async()=>{const e=ai(await qt("/api/version",{timeoutMs:8e3})),n=Array.isArray(e==null?void 0:e.whatsNew)?e.whatsNew.flatMap(i=>{const a=ai(i);return typeof(a==null?void 0:a.version)=="string"?[{version:a.version,...typeof a.zh=="string"?{zh:a.zh}:{},...typeof a.en=="string"?{en:a.en}:{}}]:[]}):void 0;return e?{...typeof e.current=="string"||e.current===null?{current:e.current}:{},...typeof e.latest=="string"||e.latest===null?{latest:e.latest}:{},...typeof e.updateAvailable=="boolean"?{updateAvailable:e.updateAvailable}:{},...n?{whatsNew:n}:{}}:{}},eD=async()=>$4(await qt("/api/workspace/status",{timeoutMs:8e3}))??{},tD=async(e="latest")=>q4(await qt(`/api/workspace/restore-plan?checkpoint=${encodeURIComponent(e)}`,{timeoutMs:8e3})),j6=async(e={checkpointId:"latest"})=>{const n=await qt("/api/workspace/restore",{method:"POST",body:JSON.stringify(e),timeoutMs:8e3});return W4(n)??{}},D6=async e=>G4(await qt(`/api/workspace/restore/${encodeURIComponent(e)}`,{timeoutMs:8e3})),k6=()=>qt("/api/hooks/install",{method:"POST",timeoutMs:15e3}),T6=async(e=[])=>{const n=ai(await qt(`/api/states?sessions=${encodeURIComponent(e.join(","))}`,{timeoutMs:4e3})),i={};for(const[a,u]of Object.entries(n||{})){const g=ai(u);g&&(i[a]={...typeof g.kind=="string"||g.kind===null?{kind:g.kind}:{},...typeof g.session=="string"||g.session===null?{session:g.session}:{},...typeof g.window=="string"||g.window===null?{window:g.window}:{},...typeof g.windowName=="string"||g.windowName===null?{windowName:g.windowName}:{},...typeof g.msg=="string"||g.msg===null?{msg:g.msg}:{},...typeof g.ts=="number"&&Number.isFinite(g.ts)?{ts:g.ts}:{},...typeof g.agent=="string"||g.agent===null?{agent:g.agent}:{},...typeof g.terminalUnread=="boolean"?{terminalUnread:g.terminalUnread}:{},...typeof g.terminalNotificationId=="string"&&g.terminalNotificationId?{terminalNotificationId:g.terminalNotificationId}:{}})}return i},pd=(e,n={})=>qt(e,{timeoutMs:15e3,...n,headers:{...n.headers||{},"X-Handmux-Browser-Device":gP()??""}}),R6=(e,n,i="mobile")=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}`,{method:"PUT",body:JSON.stringify({url:n,siteVersion:i})}),A6=(e,n,i="mobile")=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}/navigate`,{method:"POST",body:JSON.stringify({url:n,siteVersion:i})}),nD=e=>pd(`/api/browser-proxy/leases/${encodeURIComponent(e)}`,{method:"DELETE"}),rD=()=>pd("/api/browser-proxy/status"),iD=e=>pd("/api/browser-proxy/profile",{method:"PUT",body:JSON.stringify(e)}),U6=(e=null)=>pd("/api/browser-proxy/profile/clear",{method:"POST",body:JSON.stringify({origin:e})}),sD=async()=>{const e=await qt("/api/orphans",{timeoutMs:8e3});return Array.isArray(e)?e.flatMap(n=>{const i=ai(n);if(!i||typeof i.pid!="number"||!Number.isFinite(i.pid)||typeof i.cwd!="string")return[];const a=Go(i.startedAt),u=Go(i.lastActivity);return[{pid:i.pid,cwd:i.cwd,...typeof i.cwdLabel=="string"?{cwdLabel:i.cwdLabel}:{},...typeof i.sessionId=="string"||i.sessionId===null?{sessionId:i.sessionId}:{},...typeof i.state=="string"?{state:i.state}:{},...typeof i.snippet=="string"?{snippet:i.snippet}:{},...typeof i.agentLabel=="string"?{agentLabel:i.agentLabel}:{},...typeof i.suggestedName=="string"?{suggestedName:i.suggestedName}:{},...a!==void 0?{startedAt:a}:{},...u!==void 0?{lastActivity:u}:{}}]}):[]},M6=async e=>LR(await qt("/api/orphans/takeover",{method:"POST",body:JSON.stringify(e),timeoutMs:15e3})),L6=async e=>{const n=ai(await qt(`/api/git/worktree?dir=${encodeURIComponent(e)}`,{timeoutMs:8e3})),i=ai(n==null?void 0:n.worktree);return i&&typeof i.path=="string"&&i.path?{path:i.path}:null},aD=e=>qt(`/api/git/repos?dir=${encodeURIComponent(e)}`,{timeoutMs:8e3}),IR=e=>qt(`/api/git/status?repo=${encodeURIComponent(e)}`,{timeoutMs:8e3}),I6=(e,{limit:n=50,ref:i}={})=>{let a=`/api/git/log?repo=${encodeURIComponent(e)}&limit=${n}`;return i&&(a+=`&ref=${encodeURIComponent(i)}`),qt(a,{timeoutMs:8e3})},V6=e=>qt(`/api/git/branches?repo=${encodeURIComponent(e)}`,{timeoutMs:8e3}),O6=(e,{path:n,commit:i,staged:a}={})=>{let u=`/api/git/diff?repo=${encodeURIComponent(e)}&path=${encodeURIComponent(n??"")}`;return i&&(u+=`&commit=${encodeURIComponent(i)}`),a&&(u+="&staged=1"),qt(u,{timeoutMs:8e3})},P6=(e,n)=>qt(`/api/git/commit?repo=${encodeURIComponent(e)}&hash=${encodeURIComponent(n)}`,{timeoutMs:8e3});function B6(e,n){return new Promise((i,a)=>{const u=new XMLHttpRequest;u.open("GET",`/api/download?path=${encodeURIComponent(e)}`);for(const[g,d]of Object.entries(fo()))u.setRequestHeader(g,d);u.responseType="blob",u.onprogress=g=>{n&&g.lengthComputable&&n(g.loaded/g.total)},u.onerror=()=>a(new Error("download failed")),u.onload=()=>{if(u.status===401){po().then(a);return}if(u.status<200||u.status>=300)return a(new Error(`download -> ${u.status}`));const g=e.split("/").pop()||"download";let d=u.response;const o=Jg(g);o&&d&&d.type!==o&&(d=d.slice(0,d.size,o));const c=URL.createObjectURL(d),f=document.createElement("a");f.href=c,f.download=g,document.body.appendChild(f),f.click(),f.remove(),setTimeout(()=>URL.revokeObjectURL(c),1e3),i()},u.send()})}function pN(e,n=null){return new Promise((i,a)=>{const u=new XMLHttpRequest,g=n!=null?`&mtime=${encodeURIComponent(n)}`:"";u.open("GET",`/api/download?path=${encodeURIComponent(e)}${g}`);for(const[d,o]of Object.entries(fo()))u.setRequestHeader(d,o);u.responseType="blob",u.onerror=()=>a(new Error(w("api.loadFailed"))),u.onload=()=>{if(u.status===304)return i({notModified:!0});if(u.status===401){po().then(a);return}if(u.status<200||u.status>=300)return a(new Error(`image -> ${u.status}`));let d=u.response;const o=Jg(e.split("/").pop()||"");o&&d&&d.type!==o&&(d=d.slice(0,d.size,o));const c=Number(u.getResponseHeader("X-Mtime"));i({url:URL.createObjectURL(d),mtimeMs:Number.isFinite(c)?c:null})},u.send()})}const F6=(e,{dir:n}={})=>qt("/api/previews",{method:"POST",body:JSON.stringify({name:e,dir:n})}),hw=e=>qt(`/api/previews/${encodeURIComponent(e)}`,{method:"DELETE"});class Ag extends Error{constructor(){super("upload aborted"),this.name="UploadAbort"}}function VR(e,n,i,a=!1,{signal:u}={}){return new Promise((g,d)=>{if(u!=null&&u.aborted)return d(new Ag);const o=new FormData;o.append("dir",e),a&&o.append("stash","1"),o.append("file",n,n.name);const c=new XMLHttpRequest;c.open("POST","/api/upload");for(const[h,_]of Object.entries(fo()))c.setRequestHeader(h,_);c.upload.onprogress=h=>{i&&h.lengthComputable&&i(h.loaded/h.total,"sending")},c.upload.onload=()=>{i==null||i(1,"processing")};const f=()=>c.abort();u&&u.addEventListener("abort",f,{once:!0});const v=()=>{u&&u.removeEventListener("abort",f)};c.onabort=()=>{v(),d(new Ag)},c.onerror=()=>{v(),d(new Error(w("api.uploadFailed")))},c.onload=()=>{if(v(),c.status===401){po().then(d);return}if(c.status>=200&&c.status<300)try{return g(JSON.parse(c.responseText))}catch{return g({})}const _={400:w("api.uploadBadDir"),409:w("api.uploadDuplicate"),413:w("api.uploadTooLarge"),415:w("api.uploadBadType")}[c.status]||w("api.uploadFailed");d(new Error(_))},c.send(o)})}const H6=e=>{if(e===null||typeof e!="object"||Array.isArray(e))throw new Error("split pane returned an invalid response");const n=e.id;if(typeof n!="string"||!n)throw new Error("split pane returned an invalid response");return n};async function oD({paneId:e,dir:n,windowId:i,api:a,getPanes:u}){const g=H6(await a.splitPane(e,n));return{panes:await u(i),selectPaneId:g}}async function z6({paneId:e,windowId:n,viewedPaneId:i,api:a,getPanes:u,pickId:g}){await a.closePane(e);const d=await u(n),o=e===i&&d.length?g(d,null):null;return{panes:d,selectPaneId:o}}const $6=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Claude"><title>Claude</title><path fill="#d97757" d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
205
205
  `,W6=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Codex"><title>Codex (OpenAI)</title><path fill="#ededed" d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
206
206
  `,q6=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" fill-rule="evenodd" d="M1 1H17.5V12H12V17.5H6.5V23H1ZM6.5 6.5V12H12V6.5Z"/><path fill="currentColor" d="M17.5 12H23V23H17.5Z"/></svg>
207
207
  `;function G6(e){return(e==null?void 0:e.health.some(n=>n.capability==="inbox"&&e.descriptors.some(i=>i.id===n.adapterId&&i.capabilities.inbox)&&(n.availability==="starting"||n.availability==="unavailable")))??!1}const OR=C.createContext(null);function K6({descriptors:e,runs:n=[],loaded:i,children:a}){const u=C.useMemo(()=>({loaded:i,descriptors:new Map(e.map(g=>[g.id,g])),runsByPane:new Map(n.map(g=>[g.paneId,g]))}),[e,n,i]);return s.jsxDEV(OR.Provider,{value:u,children:a},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/agentCatalog.tsx",lineNumber:87,columnNumber:5},this)}function PR(e){const n=C.useContext(OR);return{loaded:(n==null?void 0:n.loaded)??!1,descriptor:(n==null?void 0:n.descriptors.get(e))??null}}const Vn={viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.75,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0};function sd(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:18,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:17,columnNumber:5},this)}function Y6(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:27,columnNumber:7},this),s.jsxDEV("path",{d:"M12 10v6M9 13h6"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:28,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:26,columnNumber:5},this)}function Ug(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:36,columnNumber:7},this),s.jsxDEV("circle",{cx:"12",cy:"12",r:"3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:37,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:35,columnNumber:5},this)}function BR(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:46,columnNumber:7},this),s.jsxDEV("path",{d:"M14 3v5h5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:47,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:45,columnNumber:5},this)}function X6(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",ry:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:56,columnNumber:7},this),s.jsxDEV("circle",{cx:"9",cy:"9",r:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:57,columnNumber:7},this),s.jsxDEV("path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:58,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:55,columnNumber:5},this)}function Qg(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12 19V5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:67,columnNumber:7},this),s.jsxDEV("path",{d:"m5 12 7-7 7 7"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:68,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:66,columnNumber:5},this)}function J6(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("line",{x1:"2",x2:"5",y1:"12",y2:"12"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:77,columnNumber:7},this),s.jsxDEV("line",{x1:"19",x2:"22",y1:"12",y2:"12"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:78,columnNumber:7},this),s.jsxDEV("line",{x1:"12",x2:"12",y1:"2",y2:"5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:79,columnNumber:7},this),s.jsxDEV("line",{x1:"12",x2:"12",y1:"19",y2:"22"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:80,columnNumber:7},this),s.jsxDEV("circle",{cx:"12",cy:"12",r:"7"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:81,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:76,columnNumber:5},this)}function Mg(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("circle",{cx:"12",cy:"12",r:"9"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:90,columnNumber:7},this),s.jsxDEV("circle",{cx:"12",cy:"12",r:"5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:91,columnNumber:7},this),s.jsxDEV("circle",{cx:"12",cy:"12",r:"1"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:92,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:89,columnNumber:5},this)}function Oa(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"m6 9 6 6 6-6"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:101,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:100,columnNumber:5},this)}function lD(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"m13 2-9 12h8l-1 8 9-12h-8z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:110,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:109,columnNumber:5},this)}function Zg(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M12 5v14M5 12h14"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:119,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:118,columnNumber:5},this)}function Oc(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M20 6 9 17l-5-5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:128,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:127,columnNumber:5},this)}function Q6(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M3 10.5 12 3l9 7.5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:137,columnNumber:7},this),s.jsxDEV("path",{d:"M5 9.5V20a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9.5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:138,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:136,columnNumber:5},this)}function FR(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("circle",{cx:"12",cy:"12",r:"9"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:147,columnNumber:7},this),s.jsxDEV("path",{d:"M12 7v5l3 2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:148,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:146,columnNumber:5},this)}function Z6(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M9 18h6"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:158,columnNumber:7},this),s.jsxDEV("path",{d:"M10 22h4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:159,columnNumber:7},this),s.jsxDEV("path",{d:"M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:160,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:157,columnNumber:5},this)}function eB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M22 12h-6l-2 3h-4l-2-3H2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:169,columnNumber:7},this),s.jsxDEV("path",{d:"M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:170,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:168,columnNumber:5},this)}function tB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12 3v12"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:179,columnNumber:7},this),s.jsxDEV("path",{d:"m7 10 5 5 5-5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:180,columnNumber:7},this),s.jsxDEV("path",{d:"M5 21h14"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:181,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:178,columnNumber:5},this)}function HR(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:191,columnNumber:7},this),s.jsxDEV("path",{d:"M14 2v4a2 2 0 0 0 2 2h4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:192,columnNumber:7},this),s.jsxDEV("path",{d:"M12 18v-6"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:193,columnNumber:7},this),s.jsxDEV("path",{d:"m9 15 3-3 3 3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:194,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:190,columnNumber:5},this)}function eb(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"9",y:"9",width:"11",height:"11",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:203,columnNumber:7},this),s.jsxDEV("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:204,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:202,columnNumber:5},this)}function nB(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M7 5l12 7-12 7z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:213,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:212,columnNumber:5},this)}function rB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("line",{x1:"9",y1:"5",x2:"9",y2:"19"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:222,columnNumber:7},this),s.jsxDEV("line",{x1:"15",y1:"5",x2:"15",y2:"19"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:223,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:221,columnNumber:5},this)}function b0(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:232,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:231,columnNumber:5},this)}function iB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"9",y:"3",width:"6",height:"11",rx:"3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:241,columnNumber:7},this),s.jsxDEV("path",{d:"M5 11a7 7 0 0 0 14 0"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:242,columnNumber:7},this),s.jsxDEV("line",{x1:"12",y1:"18",x2:"12",y2:"21"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:243,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:240,columnNumber:5},this)}function Hh(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12 14l4-4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:262,columnNumber:7},this),s.jsxDEV("path",{d:"M3.34 19a10 10 0 1 1 17.32 0"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:263,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:261,columnNumber:5},this)}function tb(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:282,columnNumber:7},this),s.jsxDEV("path",{d:"M21 3v5h-5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:283,columnNumber:7},this),s.jsxDEV("path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:284,columnNumber:7},this),s.jsxDEV("path",{d:"M3 21v-5h5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:285,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:281,columnNumber:5},this)}function zR(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("line",{x1:"6",y1:"3",x2:"6",y2:"15"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:294,columnNumber:7},this),s.jsxDEV("circle",{cx:"18",cy:"6",r:"3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:295,columnNumber:7},this),s.jsxDEV("circle",{cx:"6",cy:"18",r:"3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:296,columnNumber:7},this),s.jsxDEV("path",{d:"M18 9a9 9 0 0 1-9 9"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:297,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:293,columnNumber:5},this)}function Zi(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M18 6 6 18"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:306,columnNumber:7},this),s.jsxDEV("path",{d:"m6 6 12 12"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:307,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:305,columnNumber:5},this)}function sB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12 20h9"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:316,columnNumber:7},this),s.jsxDEV("path",{d:"M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:317,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:315,columnNumber:5},this)}function aB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"m7 11 2-2-2-2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:335,columnNumber:7},this),s.jsxDEV("path",{d:"M11 13h4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:336,columnNumber:7},this),s.jsxDEV("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:337,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:334,columnNumber:5},this)}function oB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M10 2h4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:346,columnNumber:7},this),s.jsxDEV("path",{d:"M12 14v-4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:347,columnNumber:7},this),s.jsxDEV("path",{d:"M4 13a8 8 0 0 1 8-7 8 8 0 1 1-5.3 14L4 17.6"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:348,columnNumber:7},this),s.jsxDEV("path",{d:"M9 17H4v5"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:349,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:345,columnNumber:5},this)}function lB({down:e=!1}){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"3",y:"9",width:"18",height:"11",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:359,columnNumber:7},this),s.jsxDEV("path",{d:"M7 13h.01M11 13h.01M15 13h.01M8 16.5h8"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:360,columnNumber:7},this),e?s.jsxDEV("path",{d:"M9 4.5l3 3 3-3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:361,columnNumber:15},this):s.jsxDEV("path",{d:"M9 6.5l3-3 3 3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:361,columnNumber:45},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:358,columnNumber:5},this)}function cD(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:370,columnNumber:7},this),s.jsxDEV("path",{d:"M12 4v16"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:371,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:369,columnNumber:5},this)}function uD(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:380,columnNumber:7},this),s.jsxDEV("path",{d:"M3 12h18"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:381,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:379,columnNumber:5},this)}function cB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"3",y:"3",width:"18",height:"18",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:390,columnNumber:7},this),s.jsxDEV("path",{d:"M12 3v18M3 12h18"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:391,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:389,columnNumber:5},this)}function $R(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"m18 5-2.4-2.4A2 2 0 0 0 14.2 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:402,columnNumber:7},this),s.jsxDEV("path",{d:"M21.4 12.6a1 1 0 0 0-3-3l-4 4a2 2 0 0 0-.5.9l-.8 2.9a.5.5 0 0 0 .6.6l2.9-.8a2 2 0 0 0 .8-.5z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:403,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:401,columnNumber:5},this)}function uB(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("circle",{cx:"11",cy:"11",r:"8"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:411,columnNumber:7},this),s.jsxDEV("path",{d:"m21 21-4.3-4.3"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:412,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:410,columnNumber:5},this)}function zh(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("circle",{cx:"12",cy:"12",r:"10"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:420,columnNumber:7},this),s.jsxDEV("path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:421,columnNumber:7},this),s.jsxDEV("path",{d:"M2 12h20"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:422,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:419,columnNumber:5},this)}function nb(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("circle",{cx:"5",cy:"12",r:"1",fill:"currentColor",stroke:"none"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:430,columnNumber:7},this),s.jsxDEV("circle",{cx:"12",cy:"12",r:"1",fill:"currentColor",stroke:"none"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:431,columnNumber:7},this),s.jsxDEV("circle",{cx:"19",cy:"12",r:"1",fill:"currentColor",stroke:"none"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:432,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:429,columnNumber:5},this)}function rb(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"m3 17 2 2 4-4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:440,columnNumber:7},this),s.jsxDEV("path",{d:"m3 7 2 2 4-4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:441,columnNumber:7},this),s.jsxDEV("path",{d:"M13 6h8M13 12h8M13 18h8"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:442,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:439,columnNumber:5},this)}function dB(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M19.439 7.85c-.049.322.059.648.289.878l1.568 1.568c.47.47.706 1.087.706 1.704s-.235 1.233-.706 1.704l-1.611 1.611a.98.98 0 0 1-.837.276c-.47-.07-.802-.48-.968-.925a2.501 2.501 0 1 0-3.214 3.214c.446.166.855.497.925.968a.979.979 0 0 1-.276.837l-1.61 1.61a2.404 2.404 0 0 1-1.705.707 2.402 2.402 0 0 1-1.704-.706l-1.568-1.568a1.026 1.026 0 0 0-.877-.29c-.493.074-.84.504-1.02.968a2.5 2.5 0 1 1-3.237-3.237c.464-.18.894-.527.967-1.02a1.026 1.026 0 0 0-.289-.877l-1.568-1.568A2.402 2.402 0 0 1 1.998 12c0-.617.236-1.234.706-1.704L4.23 8.77c.24-.24.581-.353.917-.303.515.077.877.528 1.073 1.01a2.5 2.5 0 1 0 3.259-3.259c-.482-.196-.933-.558-1.01-1.073-.05-.336.062-.676.303-.917l1.525-1.525A2.402 2.402 0 0 1 12 1.998c.617 0 1.234.236 1.704.706l1.568 1.568c.23.23.556.338.877.29.493-.074.84-.504 1.02-.968a2.5 2.5 0 1 1 3.237 3.237c-.464.18-.894.527-.967 1.02Z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:450,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:449,columnNumber:5},this)}function _0(){return s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("path",{d:"M12 8V4H8"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:458,columnNumber:7},this),s.jsxDEV("rect",{x:"4",y:"8",width:"16",height:"12",rx:"2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:459,columnNumber:7},this),s.jsxDEV("path",{d:"M2 14h2M20 14h2M15 13v2M9 13v2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:460,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:457,columnNumber:5},this)}function mB(){return s.jsxDEV("svg",{...Vn,children:s.jsxDEV("path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:468,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:467,columnNumber:5},this)}const hB={claude:$6,codex:W6,pi:q6};function ad({agent:e}){var d,o;const n=e||"agent",i=PR(n),a=i.loaded?(d=i.descriptor)==null?void 0:d.iconId:n,u=((o=i.descriptor)==null?void 0:o.label)??n,g=a?hB[a]:void 0;return g?s.jsxDEV("span",{className:"agent-mark",role:"img","aria-label":u,"data-agent-icon":a,dangerouslySetInnerHTML:{__html:g}},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:492,columnNumber:12},this):s.jsxDEV("span",{className:"agent-mark",role:"img","aria-label":u,"data-agent-icon":"generic",children:s.jsxDEV("svg",{...Vn,children:[s.jsxDEV("rect",{x:"4",y:"5",width:"16",height:"15",rx:"4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:498,columnNumber:9},this),s.jsxDEV("path",{d:"M9 12h.01M15 12h.01M9 16h6M12 5V2"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:499,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:497,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/icons.tsx",lineNumber:496,columnNumber:5},this)}const WR=[10,30,60,120],fB=[1,7,30,null],vN="hm_browser_close_after1",gN="hm_browser_profile_persist1",bN="hm_browser_profile_retention1",ib="hm_browser_history1",y0="hm_browser_tabs1",qR=200,pB=/^(?:access_token|id_token|refresh_token|token|code|authorization|api_?key)$/i;function $h(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}function GR(e){return WR.some(n=>n===e)}function KR(e){return fB.some(n=>n===e)}function dD(e){const n=Number(e);return Number.isFinite(n)?n:Date.now()}function yg(e){const n=String(e??"").trim();if(!n)return null;let i=n;if(/^\d+$/.test(n)){const a=Number(n);if(!Number.isInteger(a)||a<1||a>65535)return null;i=`http://127.0.0.1:${a}/`}else/^[a-z][a-z\d+.-]*:\/\//i.test(n)||(i=`https://${n}`);try{const a=new URL(i);return a.protocol!=="http:"&&a.protocol!=="https:"||!a.hostname?null:a.toString()}catch{return null}}function fw(){const e=localStorage.getItem(vN),n=localStorage.getItem(gN)==="1",i=localStorage.getItem(bN),a=i==="never"?null:Number(i),u=KR(a)?a:30,g=Number(e);return{closeAfter:GR(g)?g:10,persistProxyLogin:n,proxyLoginRetentionDays:u}}function vB(e){if(!GR(e)){localStorage.removeItem(vN);return}localStorage.setItem(vN,String(e))}function gB(e){e===!0?localStorage.setItem(gN,"1"):localStorage.removeItem(gN)}function bB(e){if(!KR(e)){localStorage.removeItem(bN);return}localStorage.setItem(bN,e===null?"never":String(e))}function x0(e){const n=$h(e);if((n==null?void 0:n.kind)==="static"){const i=String(n.dir||"");return!i.startsWith("/")||i.includes("\0")||i.length>4096?null:{kind:"static",dir:i,title:String(n.title||""),visitedAt:dD(n.visitedAt)}}try{const i=new URL(String((n==null?void 0:n.url)||""));if(i.protocol!=="http:"&&i.protocol!=="https:")return null;i.username="",i.password="";for(const g of[...i.searchParams.keys()])pB.test(g)&&i.searchParams.delete(g);/(?:^|[&#])(?:access_token|id_token|refresh_token|token|code|authorization|api_?key)=/i.test(i.hash)&&(i.hash="");const a=(n==null?void 0:n.lastMode)==="proxy"?"proxy":(n==null?void 0:n.lastMode)==="direct"?"direct":null,u=/^[A-Za-z0-9_-]{1,128}$/.test(String((n==null?void 0:n.sessionId)||""))?String(n==null?void 0:n.sessionId):null;return{url:i.toString(),title:String((n==null?void 0:n.title)||""),visitedAt:dD(n==null?void 0:n.visitedAt),...a?{lastMode:a}:{},...u?{sessionId:u}:{}}}catch{return null}}function Ml(){try{const e=JSON.parse(localStorage.getItem(ib)||"[]");return Array.isArray(e)?e.map(x0).filter(n=>n!==null).slice(0,qR):[]}catch{return[]}}function Yv(e){const n=x0(e);if(!n)return;const i=Ml().filter(a=>n.kind==="static"?a.kind!=="static"||a.dir!==n.dir:a.kind==="static"||a.url!==n.url&&(!n.sessionId||a.sessionId!==n.sessionId));localStorage.setItem(ib,JSON.stringify([n,...i].slice(0,qR)))}function _B(e){const n=x0(e);if(!n)return;const i=Ml().filter(a=>n.kind==="static"?a.kind!=="static"||a.dir!==n.dir||a.visitedAt!==n.visitedAt:a.kind==="static"||a.url!==n.url||a.visitedAt!==n.visitedAt);localStorage.setItem(ib,JSON.stringify(i))}function yB(){localStorage.removeItem(ib)}function YR(e){const n=$h(e),i=yg(n==null?void 0:n.originalUrl);if(!n||!/^[A-Za-z0-9_-]{1,128}$/.test(String(n.id||""))||!i)return null;const a=Number(n.createdAt),u=n.mode==="proxy"?"proxy":"direct";return{id:String(n.id),mode:u,originalUrl:i,title:String(n.title||"").slice(0,1024),deadline:typeof n.deadline=="number"&&Number.isFinite(n.deadline)?n.deadline:null,...u==="proxy"?{siteVersion:n.siteVersion==="desktop"?"desktop":"mobile"}:{},...Number.isFinite(a)&&a>0?{createdAt:a}:{}}}function xB(){try{const e=JSON.parse(localStorage.getItem(y0)||"{}"),n=$h(e);if(!n)throw new Error("invalid browser tabs");const i=(Array.isArray(n.tabs)?n.tabs:[]).map(YR).filter(d=>d!==null),a=typeof n.activeId=="string"?n.activeId:null,u=i.some(d=>d.id===a)?a:null,g=u?n.historyActive===!0:!0;return{tabs:i,activeId:u,open:n.open===!0&&(u!==null||n.historyActive===!0),historyActive:g}}catch{return{tabs:[],activeId:null,open:!1,historyActive:!0}}}function wB({tabs:e=[],activeId:n=null,open:i=!1,historyActive:a=!1}){const u=e.map(YR).filter(d=>d!==null),g=u.some(d=>d.id===n)?n:null;localStorage.setItem(y0,JSON.stringify({tabs:u,activeId:g,open:!!i,historyActive:g?!!a:!0}))}function NB(){localStorage.removeItem(y0)}function CB(e){return!Array.isArray(e)||e.length===0?null:e.some(n=>{var i;return((i=$h(n))==null?void 0:i.mode)==="proxy"})?"proxy":e.some(n=>{const i=$h(n);return(i==null?void 0:i.mode)==="static"||(i==null?void 0:i.kind)==="static"})?"static":"direct"}let EB=1;const Ko=[],_N=new Set;function XR(){for(const e of _N)e()}function w0(e,n,i=EB++){return{id:i,channel:e,invoke:n}}function JR(e){const n=Ko.lastIndexOf(e);n<0||(Ko.splice(n,1),XR())}function N0(e){const n=Ko.lastIndexOf(e);return n>=0&&Ko.splice(n,1),Ko.push(e),XR(),()=>JR(e)}function QR(e){for(let n=Ko.length-1;n>=0;n-=1){const i=Ko[n];if((i==null?void 0:i.channel)===e)return i}return null}function Wh(e){let n=0;for(const i of Ko)i.channel===e&&(n+=1);return n}function mD(){return Ko.length>0}function SB(e){return _N.add(e),()=>_N.delete(e)}const hD=e=>{if(e.key!=="Escape"||e.repeat||e.isComposing)return;const n=QR("escape");n&&(e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),n.invoke())};function sb(e,n,i){const a=C.useRef(n),u=C.useRef(null);a.current=n,u.current||(u.current=w0("escape",()=>a.current(),i)),C.useLayoutEffect(()=>{if(!e)return;const g=u.current;if(!g)return;const d=N0(g);return Wh("escape")===1&&window.addEventListener("keydown",hD,!0),()=>{d(),Wh("escape")===0&&window.removeEventListener("keydown",hD,!0)}},[e])}const jB=["button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","a[href]",'[tabindex]:not([tabindex="-1"])'].join(",");function vd({active:e,dialogRef:n,initialFocusRef:i,returnFocusRef:a,onClose:u}){sb(e,u),C.useEffect(()=>{if(!e)return;const g=a.current,d=requestAnimationFrame(()=>{var c;return(c=i.current)==null?void 0:c.focus()}),o=c=>{if(c.key!=="Tab")return;const f=n.current,v=[...(f==null?void 0:f.querySelectorAll(jB))??[]];if(!v.length){c.preventDefault(),f==null||f.focus();return}const h=v[0],_=v[v.length-1],S=document.activeElement;c.shiftKey&&(!(f!=null&&f.contains(S))||S===h)?(c.preventDefault(),_==null||_.focus()):!c.shiftKey&&(!(f!=null&&f.contains(S))||S===_)&&(c.preventDefault(),h==null||h.focus())};return window.addEventListener("keydown",o),()=>{cancelAnimationFrame(d),window.removeEventListener("keydown",o),g==null||g.focus()}},[e,n,i,a])}const ZR={active:!1,phase:null,pct:0,label:""};let qh=ZR,Mh=null;const yN=new Set,C0=()=>{for(const e of[...yN])e()};function eA(e,n=""){Mh=e,qh={active:!0,phase:"sending",pct:0,label:n},C0()}function Lg(e){qh={...qh,...e},C0()}function xN(){Mh=null,qh=ZR,C0()}function fD(){Mh==null||Mh.abort()}const DB=e=>(yN.add(e),()=>{yN.delete(e)}),kB=()=>qh;function TB(){return C.useSyncExternalStore(DB,kB)}const tA=["jpg","jpeg","png","gif","webp","svg","bmp","heic","heif","avif","ico","tiff","mp4","m4v","mov","webm","mkv","avi","wmv","flv","3gp","ogv","mpeg","mpg","txt","md","markdown","rst","log","csv","tsv","json","yaml","yml","toml","ini","conf","xml","html","htm","css","js","mjs","cjs","ts","tsx","jsx","py","rb","go","rs","java","c","h","cpp","sh","pdf","doc","docx","xls","xlsx","ppt","pptx","odt","ods","odp","rtf","zip"],E0=tA.map(e=>`.${e}`).join(","),RB=new Set(tA);function AB(e){const n=/\.([A-Za-z0-9]+)$/.exec(e||"");return n!=null&&n[1]?RB.has(n[1].toLowerCase()):!1}function nA(e){const n=Array.isArray(e)?e:e&&"length"in e&&typeof e.length=="number"?Array.from(e):e?[e]:[],i=[],a=[];for(const u of n)(AB(u.name)?i:a).push(u);return{allowed:i,rejected:a.map(u=>u.name)}}const rA="\\s'\"`()\\[\\]<>,;,。、;:!?()【】《》「」“”‘’*…:│",iA=["md","markdown","html","htm","txt","log","sh"],sA=["png","jpg","jpeg","jfif","gif","webp","svg","bmp","ico","avif","apng"],pD=new RegExp(`[^${rA}]+`,"g"),UB=new Set([...iA,...sA].map(e=>`.${e}`)),vD=/^(?:readme|license|makefile|dockerfile|gemfile|rakefile|procfile|notice)$/i,MB=new Set([...iA,...sA,"mdx","rst","csv","tsv","json","jsonl","yaml","yml","toml","ini","conf","xml","css","scss","sass","less","js","mjs","cjs","jsx","ts","tsx","vue","svelte","py","pyi","rb","go","rs","java","kt","kts","c","cc","cpp","cxx","h","hpp","cs","swift","php","sql","graphql","gql","proto","properties","gradle","lock"]);function LB(e){var i,a;if(!e||e==="."||e===".."||e.endsWith("/")||UB.has(e.toLowerCase())||/^v?\d+(?:\.\d+)+$/i.test(e)||e.includes("@")&&!e.includes("/"))return!1;if(/^(?:\.\.?\/|~\/)/.test(e))return!0;if(e.includes("/")){const u=e.slice(e.lastIndexOf("/")+1);return e.startsWith("/")&&e.indexOf("/",1)>=0||/^\.[A-Za-z0-9][A-Za-z0-9._-]*$/.test(u)||vD.test(u)||/^[^.][^/]*\.[^.]+$/.test(u)}if(/^\.[A-Za-z0-9][A-Za-z0-9._-]*$/.test(e)||vD.test(e))return!0;const n=(a=(i=/\.([A-Za-z0-9]+)$/.exec(e))==null?void 0:i[1])==null?void 0:a.toLowerCase();return n!==void 0&&MB.has(n)}function IB(e){const n=[];if(!e)return n;pD.lastIndex=0;let i;for(;(i=pD.exec(e))!==null;){let a=i.index,u=i[0].replace(/\.+$/,"");const g=u.lastIndexOf("=");g>=0&&(a+=g+1,u=u.slice(g+1));const d=/^@+/.exec(u);d&&(a+=d[0].length,u=u.slice(d[0].length)),LB(u)&&n.push({start:a,end:a+u.length,path:u})}return n}const aA=e=>typeof e=="string"&&(e.startsWith("/")||e==="~"||e.startsWith("~/"));function Sc(e,n){const i=aA(n)?n:`${e.replace(/\/+$/,"")}/${n}`,a=i.startsWith("/"),u=[];for(const g of i.split("/"))if(!(!g||g===".")){if(g===".."){u.pop();continue}u.push(g)}return(a?"/":"")+u.join("/")}const VB=e=>Array.isArray(e);function Gh({open:e,title:n,subtitle:i="",actions:a=[],onClose:u,children:g=null}){const[d,o]=C.useState(null);if(C.useEffect(()=>{e||o(null)},[e]),!e)return null;const c=v=>{var h;if(!v.disabled){if(v.confirm&&d!==v.key){o(v.key);return}o(null),(h=v.onClick)==null||h.call(v)}},f=v=>s.jsxDEV("button",{className:`sheet-action ${v.danger?"danger":""} ${d===v.key?"armed":""}`,disabled:v.disabled,onClick:()=>c(v),children:[v.icon&&d!==v.key&&s.jsxDEV("span",{className:"sheet-action-icon","aria-hidden":"true",children:v.icon},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:62,columnNumber:47},this),v.confirm&&d===v.key?v.confirmLabel||w("actionsheet.confirmAgain"):v.label]},v.key,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:56,columnNumber:5},this);return s.jsxDEV(s.Fragment,{children:[s.jsxDEV("div",{className:"settings-backdrop",onClick:u},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:69,columnNumber:7},this),s.jsxDEV("div",{className:"settings-card",role:"dialog","aria-label":i?`${n},${i}`:n,"aria-modal":"true",children:[s.jsxDEV("div",{className:"settings-head",children:[s.jsxDEV("span",{className:"settings-heading",children:[s.jsxDEV("span",{className:"settings-title",children:n},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:73,columnNumber:13},this),i&&s.jsxDEV("span",{className:"settings-subtitle",children:i},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:74,columnNumber:26},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:72,columnNumber:11},this),s.jsxDEV("button",{className:"settings-close",onClick:u,"aria-label":w("common.close"),children:"✕"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:76,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:71,columnNumber:9},this),s.jsxDEV("div",{className:"settings-section sheet-actions",children:[g,a.map((v,h)=>VB(v)?s.jsxDEV("div",{className:"sheet-row",children:v.map(f)},`row-${h}`,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:81,columnNumber:15},this):f(v)),s.jsxDEV("button",{className:"fontbtn sheet-cancel",onClick:u,children:w("common.cancel")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:83,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:78,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:70,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/ActionSheet.tsx",lineNumber:68,columnNumber:5},this)}let gD=!1,Kh=0;const OB=()=>{var e;if(Kh>0){Kh-=1;return}(e=QR("history"))==null||e.invoke()},oA=()=>{gD||(window.addEventListener("popstate",OB,!0),gD=!0)},lA=e=>{JR(e),Wh("history")===0&&(Kh=0)};function ab(e,n){const i=C.useRef(n),a=C.useRef(null);i.current=n,a.current||(a.current=w0("history",()=>i.current())),sb(e,()=>window.history.back(),a.current.id),C.useEffect(()=>{if(!e)return;const u=a.current;if(u)return oA(),N0(u),()=>lA(u)},[e])}function ob(e){e<=0||(Wh("history")>0&&(Kh+=1),window.history.go(-e))}function Nn(e,n){const i=C.useRef(n),a=C.useRef(null);i.current=n,a.current||(a.current=w0("history",()=>i.current())),sb(e,()=>window.history.back(),a.current.id),C.useEffect(()=>{if(!e)return;const u=a.current;if(u)return oA(),N0(u),window.history.pushState({overlay:!0,overlayId:u.id},""),()=>{var g;lA(u),((g=window.history.state)==null?void 0:g.overlayId)===u.id&&(Wh("history")>0&&(Kh+=1),window.history.back())}},[e])}const PB=/\.(?:md|markdown|html|htm|txt|log|sh)$/i,bD=300,_D=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,BB=e=>e==="dir"||e==="doc"||e==="image"||e==="file";function FB(e){const n=_D(e);if(!n||typeof n.path!="string"||typeof n.home!="string"||!(n.parent===null||typeof n.parent=="string")||!Array.isArray(n.entries)||!(n.roots===void 0||Array.isArray(n.roots)&&n.roots.every(a=>typeof a=="string")))throw new Error("Directory API returned an invalid listing");const i=n.entries.map(a=>{const u=_D(a);if(!u||typeof u.name!="string"||!BB(u.type)||!(u.size===void 0||typeof u.size=="number"&&Number.isFinite(u.size)))throw new Error("Directory API returned an invalid entry");return{name:u.name,type:u.type,...typeof u.size=="number"?{size:u.size}:{}}});return{path:n.path,home:n.home,...Array.isArray(n.roots)?{roots:n.roots}:{},parent:n.parent,entries:i}}function yD(e){const n=e.lastIndexOf("/");return n<0?{dir:"",frag:e}:{dir:e.slice(0,n+1),frag:e.slice(n+1)}}const HB=e=>e.replace(/\/+$/,"")||"/",pw=(e,n)=>e===n?"":n&&e.startsWith(`${n}/`)?e.slice(n.length+1):e,Xv=(e,n,i)=>{let a=null;for(const u of n||[])(e===u||e!=null&&e.startsWith(`${u}/`))&&(!a||u.length>a.length)&&(a=u);return a||i||null},zB=e=>e==null?"":e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1024/1024).toFixed(1)} MB`;function cA({path:e,onNavigate:n,onOpenDoc:i,onJumpToCwd:a,pendingFile:u,onPendingConsumed:g,pickMode:d=!1,allowMkdir:o=!d,onPick:c,pickDisabled:f=!1,refreshKey:v=0,overlayActive:h=!0}){const[_,S]=C.useState(""),[j,y]=C.useState(null),[m,b]=C.useState(!1),[x,N]=C.useState(""),[k,A]=C.useState(""),[D,T]=C.useState(""),[R,M]=C.useState(null),[L,B]=C.useState(!1),[I,O]=C.useState(!1),[z,G]=C.useState(""),[Y,X]=C.useState(null),$=C.useRef(null),P=C.useRef(!1),F=C.useRef(v),W=C.useRef(null),K=C.useRef(null),ne=C.useRef(null),de=xe=>{xe.current!==null&&clearTimeout(xe.current),xe.current=null},re=async(xe,{sync:Ee=!1,notify:et=!1,fallbackHome:st=!1}={})=>{N("");try{const Le=FB(await g0(xe??void 0));if(P.current=Le.path,y(Le),Ee){const St=pw(Le.path,Xv(Le.path,Le.roots,Le.home));S(St?`${St}/`:"")}et&&(n==null||n(Le.path),O(!1),G(""))}catch{if(st&&xe!=null){await re(null,{sync:!0});return}N(w("filebrowser.openDirFailed"))}};C.useEffect(()=>{const xe=v!==F.current;F.current=v,!(e===P.current&&!xe)&&re(e,{sync:!0,fallbackHome:d})},[e,v]),C.useEffect(()=>()=>{de(W),de(K)},[]),C.useEffect(()=>{if(!m)return;const xe=Ee=>{var et;(!(Ee.target instanceof Node)||!((et=ne.current)!=null&&et.contains(Ee.target)))&&b(!1)};return document.addEventListener("pointerdown",xe,!0),()=>document.removeEventListener("pointerdown",xe,!0)},[m]),Nn(h&&m,()=>b(!1)),Nn(h&&!!R,()=>M(null)),Nn(h&&I,()=>{O(!1),G("")});const fe=xe=>{A(xe),de(K),K.current=setTimeout(()=>A(""),2500)},Q=xe=>{const Ee=j==null?void 0:j.home;if(!Ee){S(xe);return}const et=(j==null?void 0:j.roots)||[Ee];let st=xe;(st==="~"||st.startsWith("~/"))&&(st=Ee+st.slice(1));let Le=Xv(j==null?void 0:j.path,et,Ee)??Ee;st.startsWith("/")&&(Le=Xv(st,et,Ee)??Ee,st=st===Le?"":st.startsWith(`${Le}/`)?st.slice(Le.length+1):st.replace(/^\/+/,"")),S(st);const St=HB(`${Le}/${yD(st).dir}`);St!==P.current&&(de(W),W.current=setTimeout(()=>{St!==P.current&&re(St,{notify:!0})},250))},q=async xe=>{if(!j)return;const Ee=Sc(j.path,xe);try{await navigator.clipboard.writeText(Ee),fe(w("filebrowser.copiedPath",{abs:Ee}))}catch{fe(Ee)}},ie=xe=>{j&&i(Sc(j.path,xe))},ue=xe=>{j&&re(Sc(j.path,xe),{sync:!0,notify:!0})},we=()=>{j!=null&&j.parent&&re(j.parent,{sync:!0,notify:!0})},pe=async()=>{const xe=z.trim();if(!(!xe||!j)){N("");try{await w6(j.path,xe),await re(j.path,{}),O(!1),G("")}catch{N(w("filebrowser.mkdirFailed"))}}},Ie=async xe=>{if(j){N(""),X({label:w("filebrowser.downloading",{name:xe}),pct:0});try{await B6(Sc(j.path,xe),Ee=>X({label:w("filebrowser.downloading",{name:xe}),pct:Ee})),T(xe)}catch{N(w("filebrowser.downloadFailed"))}finally{X(null)}}},je=()=>{const xe=R;M(null),xe&&Ie(xe)},Qe=j==null?void 0:j.home,_e=(j==null?void 0:j.roots)||(Qe?[Qe]:[]),Ue=Xv(j==null?void 0:j.path,_e,Qe),ht=xe=>xe===Qe?"~":xe?/\/tmp$/.test(xe)?"tmp":xe.includes("/var/folders/")?"TMPDIR":xe.split("/").filter(Boolean).pop()||"/":"/",Rt=xe=>{b(!1),xe!==Ue&&re(xe,{sync:!0,notify:!0})},Te=(xe,Ee)=>!xe||!Ee||xe===Ee?!1:(xe.startsWith(`${Ee}/`)?xe.slice(Ee.length+1):xe).split("/").some(st=>st.startsWith(".")),Fe=!!j&&j.path!==Qe&&!Te(j.path,Ue),it=async xe=>{const{allowed:Ee,rejected:et}=nA(xe);if(!Ee.length)return et.length&&N(w("filebrowser.uploadRejected",{names:et.join("、")})),et;if(!j)return[...Ee.map(At=>At.name),...et];const st=Ee[0];if(!st)return et;B(!0),N("");const Le=Ee.length,St=[],Pt=new AbortController;eA(Pt,w("filebrowser.uploading",{name:st.name,tag:Le>1?`(1/${Le})`:""}));try{for(let At=0;At<Le&&!Pt.signal.aborted;At++){const Jt=Ee[At];if(!Jt)continue;const fn=Le>1?`(${At+1}/${Le})`:"";Lg({label:w("filebrowser.uploading",{name:Jt.name,tag:fn}),phase:"sending",pct:0});try{await VR(j.path,Jt,(Ce,ve)=>Lg({pct:Ce,phase:ve}),!1,{signal:Pt.signal})}catch(Ce){if(Ce instanceof Ag)break;St.push({name:Jt.name,reason:Ce instanceof Error&&Ce.message?Ce.message:w("filebrowser.uploadFailed")})}}}finally{xN()}return await re(j.path,{}),B(!1),St.length?N(St.map(At=>`${At.name}:${At.reason}`).join(";")):et.length&&N(w("filebrowser.uploadRejected",{names:et.join("、")})),[...St.map(At=>At.name),...et]},$e=async()=>{u&&(await it(u)).length===0&&(g==null||g())},lt=xe=>{if(d||xe.key!=="Enter")return;const Ee=_.trim();Ee&&PB.test(Ee)&&(j!=null&&j.home)&&i(Sc(j.home,Ee))},ut=yD(_).frag.toLowerCase(),He=((j==null?void 0:j.entries)||[]).filter(xe=>(!d||xe.type==="dir")&&(!ut||xe.name.toLowerCase().includes(ut))),nt=He.length>bD?He.slice(0,bD):He,Be=He.length-nt.length;return s.jsxDEV("div",{className:"browse-view",children:[s.jsxDEV("div",{className:"browse-bar",children:[a&&s.jsxDEV("button",{className:"browse-cwd","aria-label":w("filebrowser.sessionDir"),title:w("filebrowser.jumpToSessionDir"),onClick:a,children:s.jsxDEV(J6,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:409,columnNumber:13},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:408,columnNumber:11},this),s.jsxDEV("button",{className:"browse-up","aria-label":w("filebrowser.parentDir"),disabled:!(j!=null&&j.parent),onClick:we,children:s.jsxDEV(Qg,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:413,columnNumber:11},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:412,columnNumber:9},this),s.jsxDEV("div",{className:"browse-path",children:[_e.length>1?s.jsxDEV("div",{className:"dd browse-root-dd",ref:ne,children:[s.jsxDEV("button",{type:"button",className:"browse-root","aria-haspopup":"listbox","aria-expanded":m,"aria-label":w("filebrowser.rootSelect"),onClick:()=>b(xe=>!xe),children:[s.jsxDEV("span",{children:[ht(Ue),"/"]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:424,columnNumber:17},this),s.jsxDEV("span",{className:`dd-caret${m?" open":""}`,"aria-hidden":"true",children:"▾"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:425,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:420,columnNumber:15},this),m&&s.jsxDEV("div",{className:"dd-menu",role:"listbox",children:_e.map(xe=>s.jsxDEV("button",{type:"button",role:"option","aria-selected":xe===Ue,title:xe,className:`dd-option${xe===Ue?" is-selected":""}`,onClick:()=>Rt(xe),children:[s.jsxDEV("span",{className:"dd-option-label",children:[ht(xe),"/"]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:434,columnNumber:23},this),xe===Ue&&s.jsxDEV("span",{className:"dd-check","aria-hidden":"true",children:"✓"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:435,columnNumber:41},this)]},xe,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:430,columnNumber:21},this))},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:428,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:419,columnNumber:13},this):s.jsxDEV("span",{className:"browse-home","aria-hidden":"true",children:"~/"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:442,columnNumber:13},this),s.jsxDEV("input",{className:"browse-input",value:_,placeholder:w("filebrowser.pathPlaceholder"),autoCapitalize:"off",autoCorrect:"off",spellCheck:!1,onChange:xe=>Q(xe.target.value),onKeyDown:lt},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:444,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:415,columnNumber:9},this),o&&s.jsxDEV("button",{className:"browse-mkdir","aria-label":w("filebrowser.newFolder"),title:w("filebrowser.newFolder"),disabled:!j,onClick:()=>{O(xe=>!xe),G("")},children:s.jsxDEV(Y6,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:456,columnNumber:13},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:451,columnNumber:11},this),!d&&s.jsxDEV("button",{className:"browse-upload","aria-label":w("filebrowser.uploadFile"),title:w(Fe?"filebrowser.uploadToCurrentDir":"filebrowser.enterSubdirToUpload"),disabled:!Fe||L,onClick:()=>{var xe;return(xe=$.current)==null?void 0:xe.click()},children:s.jsxDEV(HR,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:467,columnNumber:13},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:460,columnNumber:11},this),!d&&s.jsxDEV("input",{ref:$,className:"browse-file-input",type:"file",multiple:!0,accept:E0,onChange:xe=>{it(Array.from(xe.target.files||[])),xe.target.value=""}},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:473,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:406,columnNumber:7},this),I&&s.jsxDEV("div",{className:"browse-newfolder",children:[s.jsxDEV("input",{className:"browse-newfolder-input",autoFocus:!0,value:z,placeholder:w("filebrowser.folderNamePlaceholder"),autoCapitalize:"off",autoCorrect:"off",spellCheck:!1,onChange:xe=>G(xe.target.value),onKeyDown:xe=>{xe.key==="Enter"&&pe()}},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:485,columnNumber:11},this),s.jsxDEV("button",{className:"browse-newfolder-ok",onClick:pe,children:w("filebrowser.createBtn")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:491,columnNumber:11},this),s.jsxDEV("button",{className:"browse-newfolder-x","aria-label":w("common.cancel"),onClick:()=>{O(!1),G("")},children:"✕"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:492,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:484,columnNumber:9},this),!d&&u&&s.jsxDEV("div",{className:"browse-pending",children:[s.jsxDEV("span",{className:"browse-pending-text",children:[w("filebrowser.uploadPendingTo",{name:u.name}),!Fe&&s.jsxDEV("em",{className:"browse-pending-hint",children:w("filebrowser.enterSubdirFirst")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:499,columnNumber:28},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:497,columnNumber:11},this),s.jsxDEV("button",{className:"browse-pending-btn",disabled:!Fe||L,onClick:$e,children:w("filebrowser.upload")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:501,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:496,columnNumber:9},this),x&&s.jsxDEV("div",{className:"bind-error browse-err",children:x},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:504,columnNumber:15},this),k&&s.jsxDEV("div",{className:"browse-notice",children:k},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:505,columnNumber:18},this),!d&&D&&s.jsxDEV("div",{className:"browse-saved",children:[s.jsxDEV("span",{className:"browse-saved-text",children:w("filebrowser.savedToDownloads",{name:D})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:508,columnNumber:11},this),s.jsxDEV("button",{className:"browse-saved-close","aria-label":w("common.close"),onClick:()=>T(""),children:"×"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:509,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:507,columnNumber:9},this),!d&&Y&&s.jsxDEV("div",{className:"browse-progress",children:[s.jsxDEV("span",{className:"browse-progress-label",children:[Y.label," ",Math.round(Y.pct*100),"%"]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:514,columnNumber:11},this),s.jsxDEV("span",{className:"browse-progress-track",children:s.jsxDEV("span",{className:"browse-progress-fill",style:{width:`${Math.round(Y.pct*100)}%`}},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:516,columnNumber:13},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:515,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:513,columnNumber:9},this),s.jsxDEV("div",{className:"browse-list",children:[nt.length===0&&!x&&s.jsxDEV("div",{className:"browse-empty",children:w("filebrowser.noMatches")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:521,columnNumber:42},this),nt.map(xe=>s.jsxDEV("div",{className:"browse-entry-row",children:[s.jsxDEV("button",{className:"browse-entry",onClick:()=>xe.type==="dir"?ue(xe.name):xe.type==="doc"||xe.type==="image"?ie(xe.name):fe(w("filebrowser.previewUnsupported")),children:[s.jsxDEV("span",{className:"browse-entry-icon",children:xe.type==="dir"?s.jsxDEV(sd,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:532,columnNumber:71},this):xe.type==="image"?s.jsxDEV(X6,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:532,columnNumber:109},this):s.jsxDEV(BR,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:532,columnNumber:125},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:532,columnNumber:15},this),s.jsxDEV("span",{className:"browse-entry-name",children:xe.name},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:533,columnNumber:15},this),xe.type!=="dir"&&s.jsxDEV("span",{className:"browse-entry-size",children:zB(xe.size)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:534,columnNumber:36},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:524,columnNumber:13},this),xe.type!=="dir"&&s.jsxDEV("button",{className:"browse-copy","aria-label":w("filebrowser.copyAbsPath"),title:w("filebrowser.copyAbsPath"),onClick:()=>q(xe.name),children:s.jsxDEV(eb,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:538,columnNumber:17},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:537,columnNumber:15},this),xe.type!=="dir"&&s.jsxDEV("button",{className:"browse-dl","aria-label":w("filebrowser.download"),onClick:()=>M(xe.name),children:s.jsxDEV(tB,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:543,columnNumber:17},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:542,columnNumber:15},this)]},xe.name,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:523,columnNumber:11},this)),Be>0&&s.jsxDEV("div",{className:"browse-overflow",children:w("filebrowser.tooMany",{shown:nt.length,total:He.length})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:549,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:520,columnNumber:7},this),d&&j&&s.jsxDEV("div",{className:"browse-pick-bar",children:s.jsxDEV("button",{className:"browse-pick-confirm",disabled:f,onClick:()=>c==null?void 0:c(j.path),children:w("filebrowser.pickThisDir",{path:pw(j.path,j.home)?`~/${pw(j.path,j.home)}`:"~"})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:554,columnNumber:11},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:553,columnNumber:9},this),s.jsxDEV(Gh,{open:!!R,title:R?w("filebrowser.downloadConfirm",{name:R}):"",actions:[{key:"dl",label:w("filebrowser.download"),onClick:je}],onClose:()=>M(null)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:560,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/FileBrowser.tsx",lineNumber:405,columnNumber:5},this)}const $B=()=>{};function WB(e){if(e===null||typeof e!="object"||Array.isArray(e))return null;const n=e.cwd;return typeof n=="string"&&n?n:null}function gd({open:e,seedCwd:n=null,hint:i=null,pane:a=null,allowMkdir:u=!1,onPick:g,onClose:d,inset:o=0,busy:c=!1}){const[f,v]=C.useState(n),h=C.useRef(!1);Nn(e,()=>{if(h.current){h.current=!1;return}if(c){h.current=!0,window.history.forward();return}d()});const _=C.useRef(!1);e&&!_.current?(_.current=!0,f!==n&&v(n)):!e&&_.current&&(_.current=!1);const S=a?async()=>{try{const y=WB(await Uc(a));y&&v(y)}catch{}}:null;if(!e)return null;const j={transform:`translate(-50%, calc(-50% + ${o/2}px))`,"--kb-inset":`${o}px`};return s.jsxDEV(s.Fragment,{children:[s.jsxDEV("div",{className:"settings-backdrop dirpick-backdrop",onClick:c?void 0:d},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:76,columnNumber:7},this),s.jsxDEV("div",{className:"settings-card dirpick-card",style:j,role:"dialog","aria-label":w("dirpicker.title"),"aria-modal":"true","aria-busy":c||void 0,children:[s.jsxDEV("div",{className:"settings-head",children:[s.jsxDEV("span",{className:"settings-title",children:w("dirpicker.title")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:80,columnNumber:11},this),s.jsxDEV("button",{className:"settings-close",disabled:c,onClick:d,"aria-label":w("common.close"),children:"✕"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:81,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:79,columnNumber:9},this),i&&s.jsxDEV("div",{className:"dirpick-hint",children:i},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:84,columnNumber:18},this),s.jsxDEV(cA,{path:f,onNavigate:v,onOpenDoc:$B,onJumpToCwd:S,pickMode:!0,allowMkdir:u,onPick:g,pickDisabled:c,overlayActive:e},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:85,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:77,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/DirPicker.tsx",lineNumber:75,columnNumber:5},this)}const qB={host:null,keyboardInset:0,chatTone:"dusk"},uA=C.createContext(qB);function dA(e){return Number.isFinite(e)?Math.max(0,e):0}function GB({children:e,keyboardInset:n=0,chatTone:i="dusk",host:a}){const u=a===void 0&&typeof document<"u"?document.getElementById("overlay-root"):a??null,g=C.useMemo(()=>({host:u,keyboardInset:dA(n),chatTone:i}),[u,n,i]);return s.jsxDEV(uA.Provider,{value:g,children:e},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/overlays/OverlayHost.tsx",lineNumber:56,columnNumber:10},this)}function mi({children:e,keyboardInset:n,chatTone:i,className:a=""}){const u=C.useContext(uA),g=u.host??(typeof document<"u"?document.body:null);if(!g)return null;const d=dA(n??u.keyboardInset),o={"--overlay-keyboard-inset":`${d}px`,"--overlay-keyboard-center-shift":`${d/2}px`},c=`overlay-layer chat-tone-surface${a?` ${a}`:""}`;return JN.createPortal(s.jsxDEV("div",{className:c,"data-chat-tone":i??u.chatTone,style:o,children:e},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/overlays/OverlayHost.tsx",lineNumber:76,columnNumber:5},this),g)}function xD(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}const KB="allow-scripts allow-forms allow-downloads allow-modals allow-popups allow-same-origin",YB="allow-scripts allow-forms allow-downloads allow-modals allow-popups",Jv=[.75,.8,.9,1,1.1,1.25,1.5,1.75,2],XB=15e3;function wD(e){if(e.title)return e.title;try{return new URL(e.originalUrl).hostname}catch{return e.originalUrl}}function ND(e){var n;return((n=e.dir)==null?void 0:n.split("/").filter(Boolean).at(-1))||e.name}function JB(e,n){return[...e.map(a=>({kind:"web",tab:a})),...n.map(a=>({kind:"static",tab:a}))].map((a,u)=>({...a,legacyIndex:u,createdAt:Number(a.tab.createdAt)})).sort((a,u)=>{const g=Number.isFinite(a.createdAt)&&a.createdAt>0,d=Number.isFinite(u.createdAt)&&u.createdAt>0;return g!==d?g?1:-1:g&&a.createdAt!==u.createdAt?a.createdAt-u.createdAt:a.legacyIndex-u.legacyIndex})}function QB({browser:e,staticPreview:n}){var _n;const{open:i,accessEnabled:a,consentOpen:u,tabs:g,activeId:d,historyActive:o,closeAfter:c,history:f,error:v,persistProxyLogin:h,proxyAvailable:_,openUrl:S,switchTab:j,closeTab:y,setOpen:m,setCloseAfter:b,navigateTab:x,ensureBinding:N,recoverBinding:k,markBindingReady:A,updateTabMeta:D,clearHistory:T,setHistoryMode:R,enableAccess:M,cancelAccess:L,setProxyLoginPolicy:B,recordStaticHistory:I,clearProxyLogin:O,deleteHistory:z}=e,G=g.find(ye=>ye.id===d)||null,Y=n!=null&&n.selected?n.shownPreview:null,X=!!Y,$=o&&!X,P=Y||G,F=(G==null?void 0:G.mode)==="proxy"&&!X,[W,K]=C.useState("direct"),ne=X?"static":$||!G?W:G.mode,[de,re]=C.useState((G==null?void 0:G.originalUrl)||""),[fe,Q]=C.useState(!1),[q,ie]=C.useState(!1),[ue,we]=C.useState("narrow"),[pe,Ie]=C.useState({width:0,height:0}),[je,Qe]=C.useState(()=>new Set),[_e,Ue]=C.useState(()=>new Set),[ht,Rt]=C.useState({}),[Te,Fe]=C.useState(null),[it,$e]=C.useState(null),[lt,ut]=C.useState(null),[He,nt]=C.useState(()=>new Set),[Be,xe]=C.useState(()=>new Set),[Ee,et]=C.useState(1),[st,Le]=C.useState(!1),[St,Pt]=C.useState(null),[At,Jt]=C.useState(()=>new Set),[fn,Ce]=C.useState(()=>new Set),[ve,gt]=C.useState({}),dt=C.useRef(new Map),jt=C.useRef(new Map),en=C.useRef(new Map),ze=C.useRef(new Map),We=C.useRef(new Map),yt=C.useRef(d),De=C.useRef(i),bt=C.useRef(null),mt=C.useRef(null),Lt=C.useRef(null),zt=C.useRef(null),Se=C.useRef(null),xt=C.useRef(null);yt.current=d,De.current=i;const ae=C.useCallback(ye=>{const Ct=We.current.get(ye);Ct!=null&&clearTimeout(Ct),We.current.delete(ye)},[]);C.useEffect(()=>{re(X?(Y==null?void 0:Y.dir)||"":$?"":(G==null?void 0:G.originalUrl)||"")},[$,Y==null?void 0:Y.dir,X,G==null?void 0:G.originalUrl]),C.useEffect(()=>{_||K("direct")},[_]),C.useEffect(()=>{Q(!1),ie(!1),$||Fe(null)},[d,$,i,Y==null?void 0:Y.name]),C.useEffect(()=>{et(1)},[d,ue,$,Y==null?void 0:Y.name]),C.useEffect(()=>{!X||!Y||Jt(ye=>new Set(ye).add(Y.name))},[Y==null?void 0:Y.name,X]),C.useEffect(()=>{!X||(Y==null?void 0:Y.status)!=="ready"||I==null||I({dir:Y.dir,title:ND(Y)})},[I,Y==null?void 0:Y.dir,Y==null?void 0:Y.name,Y==null?void 0:Y.status,X]),C.useLayoutEffect(()=>{var ye,Ct;!i||$||!d&&!(Y!=null&&Y.name)||(Ct=(ye=bt.current)==null?void 0:ye.scrollIntoView)==null||Ct.call(ye,{behavior:"smooth",block:"nearest",inline:"nearest"})},[d,$,i,Y==null?void 0:Y.name,(_n=n==null?void 0:n.tabs)==null?void 0:_n.length,g.length]),C.useEffect(()=>{if(!a){nt(new Set);return}!i||o||X||!G||(nt(ye=>new Set(ye).add(G.id)),G.mode==="proxy"&&Be.has(G.id)?(xe(ye=>{const Ct=new Set(ye);return Ct.delete(G.id),Ct}),k(G.id)):G.mode==="proxy"&&!G.url&&N(G.id))},[a,N,o,i,k,X,Be,G==null?void 0:G.id,G==null?void 0:G.mode,G==null?void 0:G.url]),vd({active:!!it,dialogRef:xt,initialFocusRef:Se,returnFocusRef:zt,onClose:()=>$e(null)}),C.useEffect(()=>{const ye=Ct=>{const Et=xD(Ct.data);if((Et==null?void 0:Et.source)!=="handmux-browser")return;const Mt=[...dt.current.entries()].find(([,Sn])=>Sn.contentWindow===Ct.source),Vt=Mt&&g.find(Sn=>Sn.id===Mt[0]);if(!(!Vt||Vt.mode!=="proxy")){if(Et.type==="session-unavailable"){if(Vt.channel!==Et.channel)return;if(!De.current||yt.current!==Vt.id){xe(zr=>new Set(zr).add(Vt.id));return}if(We.current.has(Vt.id))return;const Sn=setTimeout(()=>{We.current.get(Vt.id)===Sn&&We.current.delete(Vt.id)},XB);We.current.set(Vt.id,Sn),k(Vt.id).then(zr=>{zr||ae(Vt.id)});return}Vt.channel===Et.channel&&(Et.type==="ready"&&(ae(Vt.id),typeof Et.channel=="string"&&A(Vt.id,Et.channel),xe(Sn=>{if(!Sn.has(Vt.id))return Sn;const zr=new Set(Sn);return zr.delete(Vt.id),zr})),Et.type==="navigate"&&Ue(Sn=>new Set(Sn).add(Vt.id)),typeof Et.type=="string"&&["ready","load","urlchange","title"].includes(Et.type)&&D(Vt.id,{url:Et.url,title:Et.title}))}};return window.addEventListener("message",ye),()=>window.removeEventListener("message",ye)},[ae,A,k,g,D]),C.useEffect(()=>{const ye=new Set(g.map(Et=>Et.id)),Ct=new Set(g.filter(Et=>Et.mode==="proxy").map(Et=>Et.id));for(const Et of ze.current.keys())ye.has(Et)||ze.current.delete(Et);for(const Et of We.current.keys())Ct.has(Et)||ae(Et);Qe(Et=>{const Mt=new Set;for(const Vt of g)Et.has(Vt.id)&&jt.current.get(Vt.id)===Vt.url&&Mt.add(Vt.id);return jt.current=new Map(g.map(Vt=>[Vt.id,Vt.url])),Mt}),nt(Et=>new Set([...Et].filter(Mt=>ye.has(Mt)))),xe(Et=>new Set([...Et].filter(Mt=>ye.has(Mt))))},[ae,g]),C.useEffect(()=>()=>{for(const ye of We.current.values())clearTimeout(ye);We.current.clear()},[]),C.useEffect(()=>{const ye=(n==null?void 0:n.tabs)||[],Ct=new Set(ye.map(Et=>Et.name));Ce(Et=>{const Mt=new Set;for(const Vt of ye)Et.has(Vt.name)&&en.current.get(Vt.name)===Vt.url&&Mt.add(Vt.name);return en.current=new Map(ye.map(Vt=>[Vt.name,Vt.url])),Mt}),Jt(Et=>new Set([...Et].filter(Mt=>Ct.has(Mt)))),gt(Et=>Object.fromEntries(Object.entries(Et).filter(([Mt])=>Ct.has(Mt))))},[n==null?void 0:n.tabs]),C.useEffect(()=>{const ye=Lt.current;if(!i||!ye)return;const Ct=()=>Ie({width:ye.clientWidth,height:ye.clientHeight});if(Ct(),typeof ResizeObserver>"u")return;const Et=new ResizeObserver(Ct);return Et.observe(ye),()=>Et.disconnect()},[i]);const ke=C.useCallback((ye,Ct)=>{var Et,Mt;!ye||ye.mode!=="proxy"||(Mt=(Et=dt.current.get(ye.id))==null?void 0:Et.contentWindow)==null||Mt.postMessage({source:"handmux-browser-parent",channel:ye.channel,command:Ct},"*")},[]),se=ye=>ke(G,ye),Pe=ye=>{Q(!1),ut(null),n==null||n.deactivate(),j(ye.id)},Ut=ye=>{Q(!1),ut(null),j("history"),n==null||n.switchTab(ye.name)},Je=()=>(Q(!1),ut(null),K("direct"),n==null||n.deactivate(),j("history")),Me=async()=>{if(!P)return;if(X){Y.status==="error"?await n.retryPreview(Y.name):Y.status==="ready"&&(Ce(Mt=>{const Vt=new Set(Mt);return Vt.delete(Y.name),Vt}),gt(Mt=>({...Mt,[Y.name]:(Mt[Y.name]||0)+1})));return}if(!G)return;const ye=G,Ct=(ze.current.get(ye.id)||0)+1;if(ze.current.set(ye.id,Ct),Ue(Mt=>new Set(Mt).add(ye.id)),!F){Rt(Mt=>({...Mt,[ye.id]:(Mt[ye.id]||0)+1}));return}const Et=await x(ye.id,ye.originalUrl,ye.mode);if(ze.current.get(ye.id)===Ct){if((Et==null?void 0:Et.id)===ye.id&&Et.mode==="proxy"&&Et.url){Rt(Mt=>({...Mt,[ye.id]:(Mt[ye.id]||0)+1}));return}Ue(Mt=>{const Vt=new Set(Mt);return Vt.delete(ye.id),Vt})}},Bt=()=>{G&&(ze.current.set(G.id,(ze.current.get(G.id)||0)+1),se("stop"),jt.current.set(G.id,G.url),Qe(ye=>new Set(ye).add(G.id)),Ue(ye=>{const Ct=new Set(ye);return Ct.delete(G.id),Ct}))},Ft=ye=>{jt.current.set(ye.id,ye.url),Qe(Ct=>new Set(Ct).add(ye.id)),Ue(Ct=>{const Et=new Set(Ct);return Et.delete(ye.id),Et})},Wt=ye=>{en.current.set(ye.name,ye.url),Ce(Ct=>new Set(Ct).add(ye.name))},Z=ye=>{ye.preventDefault(),!X&&(ut(null),n==null||n.deactivate(),$||!G?S(de,{mode:W}):x(G.id,de))},Ht=ye=>{if(!(X||ye===ne||ye==="proxy"&&!_)){if(ut(null),$||!G){K(ye);return}x(G.id,G.originalUrl,ye)}},It=async ye=>{if(!F||!G||G.siteVersion===ye)return;Ue(Et=>new Set(Et).add(G.id));const Ct=await x(G.id,G.originalUrl,"proxy",ye);(Ct==null?void 0:Ct.id)===G.id&&Ct.url||Ue(Et=>{const Mt=new Set(Et);return Mt.delete(G.id),Mt})},Ot=(ye,Ct=ye.kind==="static"?"direct":ye.lastMode||"direct",Et=!1)=>{if(Fe(null),ye.kind==="static"){ut(null),n==null||n.startPreview(ye.dir);return}if(Ct==="proxy"&&!_){ut(w("browser.proxyUnavailable"));return}ut(null),Et&&R(ye,Ct),S(ye.url,{mode:Ct})},Dn=()=>{if(!G)return;let ye;try{ye=new URL(G.originalUrl).origin}catch{return}zt.current=document.activeElement instanceof HTMLElement?document.activeElement:null,$e({type:"site",origin:ye})},Mr=()=>{const ye=it;$e(null),(ye==null?void 0:ye.type)==="site"&&O(ye.origin),(ye==null?void 0:ye.type)==="all"&&O(null)},Kn=ye=>{Fe(null),z(ye)},mn=()=>{Je(),re(""),requestAnimationFrame(()=>{var ye;return(ye=mt.current)==null?void 0:ye.focus()})},Dr=async()=>{var Ct;(Ct=mt.current)==null||Ct.blur();let ye=(n==null?void 0:n.lastPreviewDir)||null;if(!ye&&(n!=null&&n.pane))try{const Et=xD(await Uc(n.pane));ye=typeof(Et==null?void 0:Et.cwd)=="string"?Et.cwd:null}catch{}Pt(ye),Le(!0)},dr=async ye=>{Le(!1),await(n==null?void 0:n.startPreview(ye))},kr=ye=>{b(ye),ie(!1)},er=ye=>et(Ct=>ye>0?Jv.find(Et=>Et>Ct)||Ct:[...Jv].reverse().find(Et=>Et<Ct)||Ct),or=ue==="wide"?1280:390,oi=pe.width>0?ue==="wide"?pe.width/or:Math.min(1,pe.width/or):1,Hr=ye=>{const Ct=Math.round(or*oi*ye*1e3)/1e3,Et=Math.round(pe.height*ye*1e3)/1e3,Mt=Math.round(ye*1e3)/10;return{width:`${Ct}px`,height:pe.height>0?`${Et}px`:`${Mt}%`,marginInline:ue==="narrow"&&oi===1?"auto":void 0}},Lr=ye=>({width:`${or}px`,height:pe.height>0?`${pe.height/oi}px`:"100%",transform:`scale(${oi*ye})`,transformOrigin:"0 0"}),mr=X?Y.status==="ensuring"||Y.status==="ready"&&(!fn.has(Y.name)||en.current.get(Y.name)!==Y.url):!!G&&(!je.has(G.id)||jt.current.get(G.id)!==G.url||_e.has(G.id)),hr=lt||($?n==null?void 0:n.error:null)||(X?null:v),lr=JB(g,(n==null?void 0:n.tabs)||[]);return u?s.jsxDEV(mi,{children:s.jsxDEV("div",{className:"file-sheet browser-sheet open browser-consent",role:"dialog","aria-modal":"true","aria-label":w("browser.consentTitle"),children:s.jsxDEV("div",{className:"browser-consent-card",children:[s.jsxDEV(zh,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:585,columnNumber:11},this),s.jsxDEV("h2",{children:w("browser.consentTitle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:586,columnNumber:11},this),s.jsxDEV("p",{children:w("browser.consentBody")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:587,columnNumber:11},this),s.jsxDEV("ul",{children:[s.jsxDEV("li",{children:w("browser.consentComputer")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:589,columnNumber:13},this),s.jsxDEV("li",{children:w("browser.consentPrivate")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:590,columnNumber:13},this),s.jsxDEV("li",{children:w("browser.consentLimits")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:591,columnNumber:13},this),s.jsxDEV("li",{children:w("browser.consentIdle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:592,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:588,columnNumber:11},this),s.jsxDEV("div",{className:"browser-consent-actions",children:[s.jsxDEV("button",{onClick:L,children:w("common.cancel")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:595,columnNumber:13},this),s.jsxDEV("button",{className:"browser-consent-enable",onClick:M,children:w("browser.acknowledge")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:596,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:594,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:584,columnNumber:9},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:583,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:582,columnNumber:5},this):s.jsxDEV(mi,{children:s.jsxDEV("div",{className:`file-sheet browser-sheet ${i?"open":""}`,"aria-hidden":!i,children:[s.jsxDEV("div",{className:"browser-tabs",role:"tablist","aria-label":w("browser.openTabs"),...it?{inert:""}:{},children:[s.jsxDEV("button",{className:`browser-tab browser-history-tab ${$?"active":""}`,role:"tab","aria-selected":$,"aria-label":w("browser.history"),title:w("browser.history"),onClick:Je,children:s.jsxDEV(Q6,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:611,columnNumber:11},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:608,columnNumber:9},this),s.jsxDEV("div",{className:"browser-tabs-scroll",children:lr.map(({kind:ye,tab:Ct})=>{if(ye==="web"){const Vt=!X&&!o&&Ct.id===d,Sn=wD(Ct);return s.jsxDEV("span",{ref:Vt?bt:null,className:`browser-tab-wrap ${Ct.mode} ${Vt?"active":""}`,children:[s.jsxDEV("button",{className:"browser-tab",role:"tab","aria-selected":Vt,title:Ct.originalUrl,onClick:()=>Pe(Ct),children:s.jsxDEV("span",{className:"browser-tab-label",children:Sn},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:623,columnNumber:21},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:621,columnNumber:19},this),Vt&&s.jsxDEV("button",{className:"browser-tab-close","aria-label":w("browser.closeTab",{title:Sn}),onClick:()=>y(Ct.id),children:s.jsxDEV(Zi,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:627,columnNumber:56},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:626,columnNumber:21},this)]},Ct.id,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:619,columnNumber:17},this)}const Et=X&&Ct.name===(Y==null?void 0:Y.name),Mt=ND(Ct);return s.jsxDEV("span",{ref:Et?bt:null,className:`browser-tab-wrap static ${Et?"active":""}`,children:[s.jsxDEV("button",{className:"browser-tab",role:"tab","aria-selected":Et,title:Ct.dir,onClick:()=>Ut(Ct),children:s.jsxDEV("span",{className:"browser-tab-label",children:Mt},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:639,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:637,columnNumber:17},this),Et&&s.jsxDEV("button",{className:"browser-tab-close","aria-label":w("browser.closeTab",{title:Mt}),onClick:()=>{n.closeTab(Ct.name)},children:s.jsxDEV(Zi,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:643,columnNumber:80},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:642,columnNumber:19},this)]},`static:${Ct.name}`,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:635,columnNumber:15},this)})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:613,columnNumber:9},this),s.jsxDEV("button",{className:"browser-head-button","aria-label":w("browser.newTab"),title:w("browser.newTab"),onClick:mn,children:s.jsxDEV(Zg,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:649,columnNumber:127},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:649,columnNumber:9},this),s.jsxDEV("button",{className:"browser-head-button","aria-label":w("browser.minimize"),title:w("browser.minimize"),onClick:()=>{Q(!1),m(!1)},children:s.jsxDEV(Oa,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:651,columnNumber:70},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:650,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:606,columnNumber:7},this),s.jsxDEV("div",{className:"browser-nav",...it?{inert:""}:{},children:[s.jsxDEV("form",{className:"browser-address-form",onSubmit:Z,children:[s.jsxDEV(zh,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:656,columnNumber:11},this),s.jsxDEV("span",{className:`browser-address-mode ${ne}`,children:w(ne==="static"?"browser.staticBadge":ne==="proxy"?"browser.proxyBadge":"browser.directBadge")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:657,columnNumber:11},this),s.jsxDEV("input",{ref:mt,className:"browser-address","aria-label":w("browser.address"),value:de,onChange:ye=>re(ye.target.value),readOnly:X,placeholder:w($?"browser.addressOrDirectoryPlaceholder":"browser.addressPlaceholder"),autoCapitalize:"none",autoCorrect:"off",spellCheck:"false"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:662,columnNumber:11},this),$&&s.jsxDEV("button",{type:"button",className:"browser-address-folder","aria-label":w("browser.chooseDirectory"),title:w("browser.chooseDirectory"),onClick:Dr,children:s.jsxDEV(sd,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:670,columnNumber:39},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:668,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:655,columnNumber:9},this),s.jsxDEV("button",{className:`browser-nav-button browser-refresh ${mr?"loading":""}`,"aria-label":w(mr&&F?"browser.stop":"browser.refresh"),"aria-busy":mr,disabled:!P||$||X&&Y.status==="ensuring",onClick:mr&&F?Bt:Me,children:mr&&F?s.jsxDEV(b0,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:677,columnNumber:39},this):s.jsxDEV(tb,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:677,columnNumber:54},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:673,columnNumber:9},this),s.jsxDEV("button",{className:"browser-nav-button browser-options-trigger","aria-label":w("browser.menu"),"aria-expanded":fe,onClick:()=>Q(ye=>!ye),children:s.jsxDEV(nb,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:680,columnNumber:89},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:679,columnNumber:9},this),fe&&i&&s.jsxDEV(s.Fragment,{children:[s.jsxDEV("div",{className:"browser-options-backdrop",onClick:()=>Q(!1)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:683,columnNumber:13},this),s.jsxDEV("div",{className:"browser-options-card",role:"dialog","aria-label":w("browser.menu"),children:[!X&&s.jsxDEV("div",{className:"browser-options-section browser-current-mode",children:[s.jsxDEV("strong",{children:w("browser.connectionMode")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:687,columnNumber:19},this),s.jsxDEV("div",{className:"browser-mode-segment",role:"group","aria-label":w("browser.switchMode"),children:[s.jsxDEV("button",{"aria-pressed":ne==="direct",onClick:()=>Ht("direct"),children:w("browser.directMode")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:689,columnNumber:21},this),s.jsxDEV("button",{className:"proxy","aria-pressed":ne==="proxy",disabled:!_,"aria-describedby":_?void 0:"browser-options-proxy-unavailable",onClick:()=>Ht("proxy"),children:w("browser.proxyMode")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:691,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:688,columnNumber:19},this),_?s.jsxDEV("p",{className:"browser-options-hint browser-proxy-limit",children:w("browser.proxyLimitHint")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:697,columnNumber:23},this):s.jsxDEV("p",{id:"browser-options-proxy-unavailable",className:"browser-options-hint",children:w("browser.proxyUnavailable")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:698,columnNumber:23},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:686,columnNumber:17},this),s.jsxDEV("div",{className:"browser-options-row browser-width-row",children:[s.jsxDEV("strong",{children:w("browser.pageWidth")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:704,columnNumber:17},this),s.jsxDEV("div",{className:"browser-view-segment",role:"group","aria-label":w("browser.viewMode"),children:[s.jsxDEV("button",{"aria-pressed":ue==="narrow",onClick:()=>we("narrow"),children:w("browser.narrowWidth")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:706,columnNumber:19},this),s.jsxDEV("button",{"aria-pressed":ue==="wide",onClick:()=>we("wide"),children:w("browser.wideWidth")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:708,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:705,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:703,columnNumber:15},this),F&&s.jsxDEV("div",{className:"browser-options-row browser-site-version-row",children:[s.jsxDEV("strong",{children:w("browser.requestSiteVersion")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:715,columnNumber:19},this),s.jsxDEV("div",{className:"browser-view-segment",role:"group","aria-label":w("browser.requestSiteVersion"),children:[s.jsxDEV("button",{"aria-pressed":G.siteVersion!=="desktop",onClick:()=>It("mobile"),children:w("browser.mobileSite")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:718,columnNumber:21},this),s.jsxDEV("button",{"aria-pressed":G.siteVersion==="desktop",onClick:()=>It("desktop"),children:w("browser.desktopSite")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:720,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:716,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:714,columnNumber:17},this),P&&!$&&s.jsxDEV("div",{className:"browser-options-section",children:s.jsxDEV("div",{className:"browser-options-row browser-zoom-row",children:[s.jsxDEV("strong",{children:w("browser.zoomPage")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:729,columnNumber:21},this),s.jsxDEV("div",{className:"browser-zoom-stepper",role:"group","aria-label":w("browser.zoomPage"),children:[s.jsxDEV("button",{onClick:()=>er(-1),disabled:Ee<=(Jv[0]??Ee),"aria-label":w("preview.zoomOut"),children:"−"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:731,columnNumber:23},this),s.jsxDEV("button",{className:"browser-zoom-value",onClick:()=>et(1),"aria-label":w("browser.resetZoom"),children:[Math.round(Ee*100),"%"]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:733,columnNumber:23},this),s.jsxDEV("button",{onClick:()=>er(1),disabled:Ee>=(Jv.at(-1)??Ee),"aria-label":w("preview.zoomIn"),children:"+"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:735,columnNumber:23},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:730,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:728,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:727,columnNumber:17},this),G&&!$&&!X&&s.jsxDEV("div",{className:"browser-options-section",children:s.jsxDEV("a",{className:"browser-options-action browser-open-external",href:G.originalUrl,target:"_blank",rel:"noopener noreferrer",onClick:()=>Q(!1),children:w("browser.openExternal")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:745,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:744,columnNumber:17},this),!X&&s.jsxDEV("div",{className:"browser-options-section",children:[s.jsxDEV("button",{className:"browser-close-trigger","aria-expanded":q,onClick:()=>ie(ye=>!ye),children:[s.jsxDEV("strong",{children:w("browser.closeTiming")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:755,columnNumber:21},this),s.jsxDEV("span",{children:[w("browser.minutes",{value:c})," ▾"]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:756,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:753,columnNumber:19},this),q&&s.jsxDEV("div",{className:"browser-time-options",role:"group","aria-label":w("browser.closeTiming"),children:WR.map(ye=>s.jsxDEV("button",{className:"browser-time-option","aria-pressed":c===ye,onClick:()=>kr(ye),children:w("browser.minutes",{value:ye})},ye,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:761,columnNumber:25},this))},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:759,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:752,columnNumber:17},this),_&&$&&s.jsxDEV("div",{className:"browser-options-section browser-profile-options",children:[s.jsxDEV("div",{className:"browser-options-row browser-profile-persist",children:[s.jsxDEV("span",{className:"browser-options-title",children:[s.jsxDEV("label",{htmlFor:"browser-profile-persist-toggle",children:s.jsxDEV("strong",{children:w("settings.browserPersistLogin")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:774,columnNumber:25},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:773,columnNumber:23},this),s.jsxDEV("button",{type:"button",className:"settings-close browser-title-help","aria-label":w("browser.proxyLoginHelpLabel"),onClick:ye=>{ye.preventDefault(),zt.current=ye.currentTarget,$e({type:"help-profile"})},children:"?"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:776,columnNumber:23},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:772,columnNumber:21},this),s.jsxDEV("span",{className:"browser-options-control",children:s.jsxDEV("span",{className:"cmd-switch",children:[s.jsxDEV("input",{id:"browser-profile-persist-toggle",type:"checkbox",checked:!!h,onChange:ye=>B({persist:ye.target.checked,retentionDays:null})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:786,columnNumber:25},this),s.jsxDEV("span",{className:"cmd-switch-track","aria-hidden":"true"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:791,columnNumber:25},this),s.jsxDEV("span",{className:"cmd-switch-knob","aria-hidden":"true"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:792,columnNumber:25},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:785,columnNumber:23},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:784,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:771,columnNumber:19},this),s.jsxDEV("button",{className:"browser-options-danger",onClick:()=>{zt.current=document.activeElement instanceof HTMLElement?document.activeElement:null,$e({type:"all"})},children:w("browser.clearAllLogin")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:796,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:770,columnNumber:17},this),_&&(G==null?void 0:G.mode)==="proxy"&&!$&&!X&&s.jsxDEV("div",{className:"browser-options-section",children:s.jsxDEV("div",{className:"browser-site-cookie-row",children:[s.jsxDEV("button",{className:"browser-options-danger",onClick:Dn,children:w("browser.clearSiteLogin")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:808,columnNumber:21},this),s.jsxDEV("button",{className:"settings-close browser-title-help","aria-label":w("browser.siteCookieHelpLabel"),onClick:ye=>{zt.current=ye.currentTarget,$e({type:"help-site"})},children:"?"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:811,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:807,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:806,columnNumber:17},this),$&&s.jsxDEV("div",{className:"browser-options-section",children:s.jsxDEV("button",{className:"browser-options-action",onClick:()=>{zt.current=document.activeElement instanceof HTMLElement?document.activeElement:null,$e({type:"help-about"})},children:w("browser.about")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:823,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:822,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:684,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:682,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:654,columnNumber:7},this),s.jsxDEV("div",{ref:Lt,className:`browser-content ${ue}`,...it?{inert:""}:{},children:[s.jsxDEV("section",{className:"browser-history",hidden:!$,children:[s.jsxDEV("div",{className:"browser-history-head",children:[s.jsxDEV("h2",{children:w("browser.history")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:840,columnNumber:13},this),f.length>0&&s.jsxDEV("button",{onClick:T,children:w("browser.clearHistory")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:841,columnNumber:36},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:839,columnNumber:11},this),f.length===0?s.jsxDEV("p",{className:"browser-empty",children:w("browser.emptyHistory")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:843,columnNumber:35},this):s.jsxDEV("div",{className:"browser-history-list",children:f.map((ye,Ct)=>{const Et=ye.kind==="static",Mt=`${ye.visitedAt}-${Et?ye.dir:ye.url}-${Ct}`;return s.jsxDEV("div",{className:"browser-history-row",children:[s.jsxDEV("button",{className:"browser-history-main",onClick:()=>Ot(ye),children:[s.jsxDEV("strong",{children:ye.title||(Et?ye.dir:ye.url)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:851,columnNumber:23},this),s.jsxDEV("span",{className:"browser-history-meta",children:[s.jsxDEV("span",{className:`browser-history-mode ${Et?"static":ye.lastMode||"direct"}`,children:w(Et?"browser.staticBadge":ye.lastMode==="proxy"?"browser.proxyBadge":"browser.directBadge")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:853,columnNumber:25},this),s.jsxDEV("span",{className:"browser-history-url",children:Et?ye.dir:ye.url},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:858,columnNumber:25},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:852,columnNumber:23},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:850,columnNumber:21},this),s.jsxDEV("button",{className:"browser-history-more","aria-label":w(Et?"browser.historyActions":"browser.historyMore"),"aria-expanded":Te===Mt,onClick:()=>Fe(Vt=>Vt===Mt?null:Mt),children:"…"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:861,columnNumber:21},this),Te===Mt&&s.jsxDEV("div",{className:"browser-history-mode-menu",role:"dialog","aria-label":w(Et?"browser.historyActions":"browser.openMode"),children:[!Et&&s.jsxDEV(s.Fragment,{children:[s.jsxDEV("button",{className:"browser-history-mode-option",onClick:()=>Ot(ye,"direct",!0),children:w("browser.directMode")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:870,columnNumber:29},this),s.jsxDEV("button",{className:"browser-history-mode-option proxy",disabled:!_,"aria-describedby":_?void 0:`browser-history-proxy-unavailable-${Ct}`,onClick:()=>Ot(ye,"proxy",!0),children:w("browser.proxyMode")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:871,columnNumber:29},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:869,columnNumber:27},this),s.jsxDEV("button",{className:"browser-history-mode-option danger",onClick:()=>Kn(ye),children:w("browser.deleteHistoryEntry")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:876,columnNumber:25},this),!Et&&!_&&s.jsxDEV("p",{id:`browser-history-proxy-unavailable-${Ct}`,children:w("browser.proxyUnavailable")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:878,columnNumber:61},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:866,columnNumber:23},this)]},Mt,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:849,columnNumber:19},this)})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:844,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:838,columnNumber:9},this),g.filter(ye=>He.has(ye.id)).map(ye=>{const Ct=!X&&!o&&ye.id===d,Et=Ct&&(!je.has(ye.id)||jt.current.get(ye.id)!==ye.url||_e.has(ye.id));return s.jsxDEV("div",{className:`browser-pane ${ye.mode} ${Ct?"active":""}`,"aria-hidden":!Ct,children:s.jsxDEV("div",{className:"browser-frame-scaler",style:Hr(Ct?Ee:1),children:[s.jsxDEV("iframe",{ref:Mt=>{Mt?dt.current.set(ye.id,Mt):dt.current.delete(ye.id)},"data-tab-id":ye.id,className:"browser-frame",title:wD(ye),src:ye.url,sandbox:KB,style:Lr(Ct?Ee:1),onLoad:()=>Ft(ye),onError:()=>{ye.mode==="proxy"&&(De.current&&yt.current===ye.id?k(ye.id):xe(Mt=>new Set(Mt).add(ye.id)))}},`${ye.id}-${ht[ye.id]||0}`,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:894,columnNumber:15},this),Et&&s.jsxDEV("div",{className:"browser-page-loading",role:"status","aria-live":"polite",children:s.jsxDEV("div",{className:"browser-page-progress",role:"progressbar","aria-label":w("common.loading")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:911,columnNumber:19},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:910,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:893,columnNumber:13},this)},ye.id,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:891,columnNumber:11},this)}),((n==null?void 0:n.tabs)||[]).filter(ye=>At.has(ye.name)).map(ye=>{var Mt;const Ct=X&&ye.name===(Y==null?void 0:Y.name),Et=Ct&&ye.status==="ready"&&(!fn.has(ye.name)||en.current.get(ye.name)!==ye.url);return s.jsxDEV("div",{className:`browser-pane static ${Ct?"active":""}`,"aria-hidden":!Ct,children:ye.status==="ready"?s.jsxDEV("div",{className:"browser-frame-scaler",style:Hr(Ct?Ee:1),children:[s.jsxDEV("iframe",{className:"browser-frame","data-static-tab-name":ye.name,title:ye.name,src:ye.url??void 0,sandbox:YB,style:Lr(Ct?Ee:1),onLoad:()=>Wt(ye)},`${ye.name}-${ve[ye.name]||0}`,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:927,columnNumber:17},this),Et&&s.jsxDEV("div",{className:"browser-page-loading",role:"status","aria-live":"polite",children:s.jsxDEV("div",{className:"browser-page-progress static",role:"progressbar","aria-label":w("common.loading")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:938,columnNumber:21},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:937,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:926,columnNumber:15},this):s.jsxDEV("div",{className:"browser-static-state",role:ye.status==="error"?"alert":"status",children:[s.jsxDEV("strong",{children:ye.status==="error"?((Mt=ye.error)==null?void 0:Mt.message)||w("browser.loadFailed"):w("browser.staticOpening")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:944,columnNumber:17},this),s.jsxDEV("span",{children:ye.dir},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:947,columnNumber:17},this),ye.status==="error"&&s.jsxDEV("button",{onClick:()=>n.retryPreview(ye.name),children:w("browser.retry")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:949,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:943,columnNumber:15},this)},`static-pane:${ye.name}`,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:923,columnNumber:11},this)}),hr&&s.jsxDEV("div",{className:"browser-error",role:"alert",children:[s.jsxDEV("span",{children:typeof hr=="string"?hr:hr.message||w("browser.loadFailed")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:960,columnNumber:13},this),!X&&!lt&&G&&G.mode==="direct"&&_?s.jsxDEV("button",{onClick:()=>x(G.id,G.originalUrl,"proxy"),children:w("browser.tryProxy")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:964,columnNumber:17},this):!X&&!lt&&G&&s.jsxDEV("button",{onClick:()=>G.mode==="proxy"?k(G.id):x(G.id,G.originalUrl,G.mode),children:w("browser.retry")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:965,columnNumber:66},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:959,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:836,columnNumber:7},this),s.jsxDEV(gd,{open:st,seedCwd:St,pane:n==null?void 0:n.pane,hint:w("browser.directoryPickerHint"),onPick:dr,onClose:()=>Le(!1)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:973,columnNumber:7},this),it&&s.jsxDEV("div",{className:"browser-profile-confirm-backdrop",children:s.jsxDEV("div",{ref:xt,className:"browser-profile-confirm",role:it.type.startsWith("help-")?"dialog":"alertdialog","aria-modal":"true","aria-label":w(it.type==="help-about"?"browser.about":it.type==="help-profile"?"browser.proxyLogin":it.type==="help-site"?"browser.siteProxyCookie":it.type==="site"?"browser.clearSiteLogin":it.type==="all"?"browser.clearAllLogin":"browser.proxyLogin"),children:[it.type==="help-about"?s.jsxDEV(s.Fragment,{children:[s.jsxDEV("h2",{children:w("browser.consentTitle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:998,columnNumber:17},this),s.jsxDEV("p",{children:w("browser.consentBody")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:999,columnNumber:17},this),s.jsxDEV("ul",{children:[s.jsxDEV("li",{children:w("browser.consentComputer")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1001,columnNumber:19},this),s.jsxDEV("li",{children:w("browser.consentPrivate")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1002,columnNumber:19},this),s.jsxDEV("li",{children:w("browser.consentLimits")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1003,columnNumber:19},this),s.jsxDEV("li",{children:w("browser.consentIdle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1004,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1e3,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:997,columnNumber:15},this):s.jsxDEV("p",{children:w(it.type==="help-profile"?"browser.proxyLoginHelp":it.type==="help-site"?"browser.siteCookieHelp":it.type==="site"?"browser.clearSiteLoginConfirm":it.type==="all"?"browser.clearAllLoginConfirm":"browser.proxyLoginHelp")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1008,columnNumber:15},this),s.jsxDEV("div",{children:it.type.startsWith("help-")?s.jsxDEV("button",{ref:Se,onClick:()=>$e(null),children:w("browser.acknowledge")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1020,columnNumber:17},this):s.jsxDEV(s.Fragment,{children:[s.jsxDEV("button",{ref:Se,onClick:()=>$e(null),children:w("common.cancel")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1023,columnNumber:19},this),s.jsxDEV("button",{className:"danger",onClick:Mr,children:w("common.confirm")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1024,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1022,columnNumber:17},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:1018,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:983,columnNumber:11},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:982,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:605,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/BrowserSheet.tsx",lineNumber:604,columnNumber:5},this)}const ZB={working:"working",compacting:"working",done:"done",idle:"done",permission:"needs",error:"error"},wN={error:4,needs:3,done:2,working:1},e7={working:w("inbox.view.working"),done:w("inbox.view.done"),needs:w("inbox.view.needs"),error:w("inbox.view.error")};function CD(e={},n={},i=0){const a=[];for(const[u,g]of Object.entries(e)){const d=typeof g.kind=="string"?ZB[g.kind]:void 0;if(!d)continue;const o=g.ts||0;(d==="done"||d==="error")&&(g.terminalUnread===!1||g.terminalUnread===void 0&&!(o>Math.max(i||0,n[u]||0)))||a.push({pane:u,session:g.session||"",window:g.window||"",windowName:g.windowName||"",view:d,msg:g.msg||"",ts:o,agent:Object.hasOwn(g,"agent")?g.agent||null:"claude",...g.terminalNotificationId===void 0?{}:{terminalNotificationId:g.terminalNotificationId}})}return a.sort((u,g)=>u.session<g.session?-1:u.session>g.session?1:wN[g.view]-wN[u.view]||g.ts-u.ts),a}function t7(e){const n={working:0,done:0,needs:0,error:0};for(const i of e)n[i.view]+=1;return n}function n7(e){let n=null,i=0;for(const a of e){const u=wN[a.view]||0;u>i&&(i=u,n=a.view)}return n}function ED(e){let n=0;for(const i of Object.values(e)){const a=typeof i.ts=="number"&&Number.isFinite(i.ts)?i.ts:0;a>n&&(n=a)}return n}function r7(e,n){let i=!1;const a=Object.fromEntries(Object.entries(e).map(([u,g])=>!g.terminalUnread||!g.terminalNotificationId||!n.has(g.terminalNotificationId)?[u,g]:(i=!0,[u,{...g,terminalUnread:!1}])));return i?a:e}function i7(e,n,i){return e!=="session"||!n?null:i[n]??null}function mA(e,n){if(!e)return"";const i=Math.max(0,Math.round((n-e)/1e3));if(i<60)return w("time.secAgo",{n:i});const a=Math.round(i/60);if(a<60)return w("time.minAgo",{n:a});const u=Math.round(a/60);return u<24?w("time.hourAgo",{n:u}):w("time.dayAgo",{n:Math.round(u/24)})}function vw(e,n,i){const a=e.findIndex(u=>u.id===n);return a<0?null:e[i==="left"?a-1:a+1]??null}class S0 extends Error{constructor(i,a){super(i);vr(this,"code");this.name="PushError",this.code=a}}class hA extends Error{constructor(i,a){super(i);vr(this,"status");this.name="PushHttpError",this.status=a}}function bd(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}function j0(e){var i;const n=(i=bd(e))==null?void 0:i.pushKey;return typeof n=="string"?n:null}function s7(e){const n=bd(e);return!n||!["pending","success","failed"].includes(String(n.status))?null:{status:n.status,...typeof n.reason=="string"||n.reason===null?{reason:n.reason}:{}}}function a7(e){return Array.isArray(e)?e.flatMap(n=>{const i=bd(n);if(!i||typeof i.id!="string"||typeof i.title!="string"||typeof i.body!="string"||typeof i.ts!="number"||!Number.isFinite(i.ts))return[];const a=s7(i.delivery);return[{id:i.id,title:i.title,body:i.body,ts:i.ts,...typeof i.url=="string"||i.url===null?{url:i.url}:{},...a?{delivery:a}:{}}]}):[]}const fA="tw_notify",pA="tw_push_device_key",vA=/^[A-Za-z0-9_-]{16,128}$/,Yh=1e4,D0=2e4,Lh=()=>localStorage.getItem(fA)==="1",NN=e=>localStorage.setItem(fA,e?"1":"0"),o7=()=>{const e=localStorage.getItem(pA);return vA.test(e||"")?e:null},k0=e=>typeof e!="string"||!vA.test(e)?null:(localStorage.setItem(pA,e),e);function tf(){return typeof navigator<"u"&&"serviceWorker"in navigator&&typeof window<"u"&&"PushManager"in window&&"Notification"in window}function gA(){var n;if(typeof window>"u")return!1;const e=window.navigator;return((n=window.matchMedia)==null?void 0:n.call(window,"(display-mode: standalone)").matches)||e.standalone===!0}const l7=()=>/iP(hone|ad|od)/.test(navigator.userAgent||"");function Mc(e={}){return fo(e)}function CN(e){return new S0(w(e),e)}function gw(e,n){return new S0(w(e,n),e)}function Rc(e,n,i){let a;return Promise.race([Promise.resolve(e),new Promise((u,g)=>{a=setTimeout(()=>g(CN(i)),n)})]).finally(()=>{a!==void 0&&clearTimeout(a)})}async function Lc(e,n,i){const a=new AbortController;let u,g=!1;try{return await Promise.race([fetch(e,{credentials:"same-origin",...n,signal:a.signal}),new Promise((d,o)=>{u=setTimeout(()=>{g=!0,a.abort(),o(CN(i))},Yh)})])}catch(d){throw g?CN(i):d}finally{u!==void 0&&clearTimeout(u)}}const nf=()=>Rc(navigator.serviceWorker.ready,Yh,"push.swTimeout"),lb=e=>Rc(e.pushManager.getSubscription(),D0,"push.browserTimeout");function c7(e){const n="=".repeat((4-e.length%4)%4),i=(e+n).replace(/-/g,"+").replace(/_/g,"/"),a=atob(i),u=new Uint8Array(a.length);for(let g=0;g<a.length;g+=1)u[g]=a.charCodeAt(g);return u.buffer}async function u7(){if(!tf())throw new Error(w("push.unsupported"));if(l7()&&!gA())throw new Error(w("push.iosAddToHome"));if(await Rc(Notification.requestPermission(),Yh,"push.permissionTimeout")!=="granted")throw new Error(w("push.permissionDenied"));try{await Rc(navigator.serviceWorker.register("/sw.js"),Yh,"push.swRegisterTimeout")}catch(f){throw f instanceof S0&&f.code==="push.swRegisterTimeout"?f:gw("push.swRegisterFailed",{reason:f instanceof Error&&f.message?f.message:w("push.unknownReason")})}const n=await nf(),i=await Lc("/api/push/vapid",{headers:Mc(),cache:"no-store"},"push.configTimeout");if(!i.ok)throw new Error(w("push.noVapid"));const a=bd(await i.json()),u=typeof(a==null?void 0:a.key)=="string"?a.key:null;if(!u)throw new Error(w("push.noVapid"));let g=await lb(n);g||(g=await Rc(n.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:c7(u)}),D0,"push.browserTimeout"));const d={subscription:g,boundSessions:ho()},o=o7();o&&(d.pushKey=o);const c=await Lc("/api/push/subscribe",{method:"POST",headers:Mc({"Content-Type":"application/json"}),body:JSON.stringify(d)},"push.reportTimeout");if(!c.ok){if(c.status===410){try{await g.unsubscribe()}catch{}throw NN(!1),gw("push.subscriptionExpired")}throw c.status===502?gw("push.deliveryRejected"):new Error(w("push.subscribeFailed"))}return k0(j0(await c.json())),NN(!0),!0}async function d7(){NN(!1),(async()=>{try{const e=await nf(),n=await lb(e);if(!n)return;const[i]=await Promise.allSettled([Lc("/api/push/unsubscribe",{method:"POST",headers:Mc({"Content-Type":"application/json"}),body:JSON.stringify({endpoint:n.endpoint})},"push.reportTimeout"),Rc(Promise.resolve().then(()=>n.unsubscribe()),D0,"push.browserTimeout")]);i.status==="fulfilled"&&i.value.ok&&k0(j0(await i.value.json()))}catch{}})()}async function qu(){if(!(!Lh()||!tf()))try{const e=await nf(),n=await lb(e);if(!n)return;await Lc("/api/push/bound",{method:"POST",headers:Mc({"Content-Type":"application/json"}),body:JSON.stringify({endpoint:n.endpoint,boundSessions:ho()})},"push.reportTimeout")}catch{}}async function T0(e){if(!tf())return null;try{const n=await nf(),i=await lb(n);if(!i)return null;const a=await Lc("/api/push/key",{method:"POST",headers:Mc({"Content-Type":"application/json"}),body:JSON.stringify({endpoint:i.endpoint})},"push.configTimeout");if(a.status===401)throw await po();if(!a.ok){if(e)throw new hA("push key lookup failed",a.status);return null}return k0(j0(await a.json()))}catch(n){if(e)throw n;return null}}const m7=()=>T0(!1);async function h7(e){if(tf())try{const n=await nf();(await Rc(n.getNotifications({tag:`pane-${e}`}),Yh,"push.swTimeout")).forEach(a=>a.close())}catch{}}async function f7(){var i;if(!Lh())return[];const e=await T0(!0);if(!e)return[];const n=await Lc(`/api/notifications?device=${encodeURIComponent(e)}`,{headers:Mc(),cache:"no-store"},"push.configTimeout");if(n.status===401)throw await po();if(!n.ok)throw new hA("notification inbox load failed",n.status);return a7((i=bd(await n.json()))==null?void 0:i.items)}async function p7(e){var a;const n=await T0(!0);if(!n)throw new Error("notification device unavailable");const i=await Lc(`/api/notifications/${encodeURIComponent(e)}?device=${encodeURIComponent(n)}`,{method:"DELETE",headers:Mc()},"push.reportTimeout");if(i.status===401)throw await po();if(!i.ok||((a=bd(await i.json()))==null?void 0:a.ok)!==!0)throw new Error("notification delete failed");return!0}function v7(e){if(typeof e!="string")return null;const n=e.trim();if(!n)return null;try{const i=new URL(n,window.location.origin);return i.protocol!=="http:"&&i.protocol!=="https:"?null:n}catch{return null}}function SD(e){const n=Math.max(0,Date.now()-e),i=Math.floor(n/6e4);if(i<1)return w("pushInbox.justNow");if(i<60)return w("pushInbox.minutesAgo").replace("{n}",String(i));const a=Math.floor(i/60);return a<24?w("pushInbox.hoursAgo").replace("{n}",String(a)):new Date(e).toLocaleDateString()}const g7={expired:"pushInbox.deliveryReasonExpired",rate_limited:"pushInbox.deliveryReasonRateLimited",service_unavailable:"pushInbox.deliveryReasonUnavailable",rejected:"pushInbox.deliveryReasonRejected",network_error:"pushInbox.deliveryReasonNetwork",not_configured:"pushInbox.deliveryReasonNotConfigured"};function bw(e,n=!1){if((e==null?void 0:e.status)==="pending")return w("pushInbox.deliveryPending");if((e==null?void 0:e.status)==="success")return w("pushInbox.deliverySuccess");if((e==null?void 0:e.status)==="failed"){if(!n)return w("pushInbox.deliveryFailed");const i=typeof e.reason=="string"?g7[e.reason]:void 0,a=w(i||"pushInbox.deliveryReasonUnknown");return`${w("pushInbox.deliveryFailed")} · ${a}`}return""}function b7({open:e,detailId:n,items:i,readIds:a=[],onOpenDetail:u,onCloseDetail:g,onClose:d,onDelete:o,deletingId:c=null,error:f="",onRetry:v,onMarkAllRead:h,unreadCount:_=0}){var N;const S=new Set(a),j=n!=null,y=j?i.find(k=>k.id===n):null,m=v7(y==null?void 0:y.url),b=bw(y==null?void 0:y.delivery,!0),x=i.some(k=>!S.has(k.id));return s.jsxDEV(mi,{children:s.jsxDEV("div",{className:`file-sheet push-inbox-sheet ${e?"open":""}`,"aria-hidden":!e,role:"dialog","aria-label":w("pushInbox.title"),children:[s.jsxDEV("div",{className:"file-tabs push-inbox-head",children:[j?s.jsxDEV("div",{className:"push-inbox-drill-head",children:[s.jsxDEV("button",{className:"push-inbox-back","aria-label":w("pushInbox.back"),title:w("pushInbox.back"),onClick:g,children:"‹"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:77,columnNumber:13},this),s.jsxDEV("span",{className:"push-inbox-head-title",children:w("pushInbox.detailTitle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:78,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:76,columnNumber:11},this):s.jsxDEV("span",{className:"push-inbox-head-title push-inbox-list-title",children:[w("pushInbox.title"),_>0&&s.jsxDEV("span",{className:"push-inbox-unread-count",children:w("pushInbox.unreadCount").replace("{n}",String(_))},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:83,columnNumber:33},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:81,columnNumber:11},this),!j&&x&&s.jsxDEV("button",{className:"push-inbox-markall",onClick:h,children:w("pushInbox.markAllRead")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:89,columnNumber:11},this),s.jsxDEV("button",{className:"file-min","aria-label":w("common.close"),title:w("common.close"),onClick:d,children:s.jsxDEV(Oa,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:91,columnNumber:113},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:91,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:74,columnNumber:7},this),s.jsxDEV("div",{className:"push-inbox-body",children:[f&&s.jsxDEV("div",{className:"push-inbox-error",role:"alert",children:[s.jsxDEV("span",{children:f},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:97,columnNumber:13},this),s.jsxDEV("button",{type:"button",onClick:v,children:w("pushInbox.retry")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:98,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:96,columnNumber:11},this),j?y?s.jsxDEV("div",{className:"push-inbox-detail",children:[s.jsxDEV("div",{className:"push-inbox-detail-title",children:y.title},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:104,columnNumber:15},this),s.jsxDEV("div",{className:"push-inbox-detail-time",children:SD(y.ts)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:105,columnNumber:15},this),b&&s.jsxDEV("div",{className:`push-inbox-delivery detail ${((N=y.delivery)==null?void 0:N.status)||""}`,children:b},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:106,columnNumber:34},this),s.jsxDEV("div",{className:"push-inbox-detail-text",children:y.body},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:107,columnNumber:15},this),m&&s.jsxDEV("a",{className:"fontbtn push-inbox-openurl",href:m,children:w("pushInbox.openUrl")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:108,columnNumber:29},this),s.jsxDEV("button",{className:"fontbtn push-inbox-detail-del",disabled:c!=null,onClick:async()=>{await o(y.id)&&g()},children:w("pushInbox.delete")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:109,columnNumber:15},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:103,columnNumber:13},this):s.jsxDEV("p",{className:"push-inbox-empty",children:w("pushInbox.expired")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:115,columnNumber:13},this):i.length===0&&!f?s.jsxDEV("p",{className:"push-inbox-empty",children:w("pushInbox.empty")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:118,columnNumber:11},this):i.length>0?s.jsxDEV("ul",{className:"push-inbox-list",children:i.map(k=>{var A;return s.jsxDEV("li",{className:`push-inbox-row${S.has(k.id)?"":" push-inbox-unread"}`,children:[s.jsxDEV("button",{className:"push-inbox-main",onClick:()=>u(k.id),children:[s.jsxDEV("div",{className:"push-inbox-row-top",children:[s.jsxDEV("span",{className:"push-inbox-row-title",children:k.title},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:125,columnNumber:21},this),bw(k.delivery)&&s.jsxDEV("span",{className:`push-inbox-delivery ${((A=k.delivery)==null?void 0:A.status)||""}`,children:bw(k.delivery)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:127,columnNumber:23},this),s.jsxDEV("span",{className:"push-inbox-row-time",children:SD(k.ts)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:129,columnNumber:21},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:124,columnNumber:19},this),s.jsxDEV("div",{className:"push-inbox-row-body",children:k.body},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:131,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:123,columnNumber:17},this),s.jsxDEV("button",{className:"push-inbox-del",disabled:c!=null,onClick:()=>void o(k.id),"aria-label":w("pushInbox.delete"),children:"✕"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:133,columnNumber:17},this)]},k.id,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:122,columnNumber:15},this)})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:120,columnNumber:11},this):null]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:94,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:72,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/InboxPage.tsx",lineNumber:71,columnNumber:5},this)}const bA={key:"home",type:"home",name:w("doc.home")},_A=(e,n)=>{const i={...e,type:n.type??e.type,name:n.name??e.name},a=n.content!==void 0?n.content:e.content,u=n.mtime!==void 0?n.mtime:e.mtime;return a!==void 0?i.content=a:delete i.content,u!==void 0?i.mtime=u:delete i.mtime,i};function _7(e,n,i){if(e.tabs.some(u=>u.key===n))return{tabs:e.tabs.map(u=>u.key===n?_A(u,i):u),active:n};const a={key:n,type:i.type,name:i.name,...i.content!==void 0?{content:i.content}:{},...i.mtime!==void 0?{mtime:i.mtime}:{},path:n};return{tabs:[...e.tabs,a],active:n}}function y7(e,n,i){return e.tabs.some(a=>a.key===n)?{...e,tabs:e.tabs.map(a=>a.key===n?_A(a,i):a)}:e}function x7(e,n){var g;const i=e.tabs.findIndex(d=>d.key===n);if(i<=0)return e;const a=e.tabs.filter(d=>d.key!==n),u=e.active===n?((g=e.tabs[i-1])==null?void 0:g.key)??"home":e.active;return{tabs:a,active:u}}function w7(){const[e,n]=C.useState({tabs:[bA],active:"home"}),i=C.useCallback((d,o)=>{n(c=>_7(c,d,o))},[]),a=C.useCallback((d,o)=>{n(c=>y7(c,d,o))},[]),u=C.useCallback(d=>{n(o=>x7(o,d))},[]),g=C.useCallback(d=>{n(o=>({...o,active:d}))},[]);return{tabs:e.tabs,active:e.active,openDoc:i,refreshDoc:a,closeTab:u,activate:g}}function jD(e){return String(e||"").replace(/[^A-Za-z0-9._-]+/g,"-").replace(/-{2,}/g,"-").replace(/^[-.]+|-+$/g,"").toLowerCase()}function N7({session:e,windowName:n,windowId:i}){const a=[e,n].map(jD).filter(Boolean);return a.push(jD(i)||"w"),a.join("-")}function yA(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}function DD(e){const n=yA(e);return n&&typeof n.url=="string"&&n.url?{...n,url:n.url}:null}const xA="hm_static_preview_tabs1";function C7(){try{const e=JSON.parse(localStorage.getItem(xA)||"[]");if(!Array.isArray(e))return{tabs:[],duplicateNames:[]};const n=e.flatMap(g=>{const d=yA(g);if(!d||!/^[A-Za-z0-9._-]+$/.test(String(d.name||""))||typeof d.dir!="string"||!d.dir.startsWith("/"))return[];const o=Number(d.createdAt);return[{name:String(d.name),dir:d.dir,...Number.isFinite(o)&&o>0?{createdAt:o}:{}}]}),i=new Set,a=[],u=[];for(const g of n)i.has(g.dir)?u.push(g.name):(i.add(g.dir),a.push(g));return{tabs:a,duplicateNames:u}}catch{return{tabs:[],duplicateNames:[]}}}function kD(e){try{localStorage.setItem(xA,JSON.stringify(e.map(({name:n,dir:i,createdAt:a})=>({name:n,dir:i,...typeof a=="number"&&Number.isFinite(a)&&a>0?{createdAt:a}:{}}))))}catch{}}function E7(e){var z,G,Y,X,$,P,F;const n=C.useRef(null);n.current||(n.current=C7());const i=n.current,[a,u]=C.useState(i.tabs),[g,d]=C.useState({}),[o,c]=C.useState(null),[f,v]=C.useState(!1),[h,_]=C.useState(null),S=C.useRef(a),j=C.useRef(g),y=C.useRef(new Map);S.current=a,j.current=g;const m=C.useCallback(W=>{const K=typeof W=="function"?W(S.current):W;return S.current=K,u(K),kD(K),K},[]),b=C.useCallback((W,K)=>{d(ne=>{const de={...ne,[W]:K};return j.current=de,de})},[]),x=C.useCallback(W=>{d(K=>{if(!(W in K))return K;const ne={...K};return delete ne[W],j.current=ne,ne})},[]),N=C.useCallback((W,K)=>{const de=(y.current.get(W)||Promise.resolve()).catch(()=>{}).then(K),re=de.catch(()=>{});return y.current.set(W,re),de.finally(()=>{y.current.get(W)===re&&y.current.delete(W)})},[]),k=C.useCallback((W,{quiet:K=!1,allowDetached:ne=!1}={})=>N(W.name,async()=>{const de=j.current[W.name];(!K||(de==null?void 0:de.status)!=="ready")&&b(W.name,{...de,status:"ensuring",error:null});try{const re=DD(await F6(W.name,{dir:W.dir}));if(!re)throw new Error("preview URL unavailable");return!ne&&!S.current.some(fe=>fe.name===W.name)?(await hw(W.name).catch(()=>{}),x(W.name),null):(b(W.name,{status:"ready",url:re.url,error:null}),_(null),re)}catch(re){if(!ne&&!S.current.some(Q=>Q.name===W.name))return x(W.name),null;if(K&&(de==null?void 0:de.status)==="ready")return null;const fe=re instanceof Error?re:new Error(String(re));return b(W.name,{...de,status:"error",error:fe}),_(fe),null}}),[x,N,b]);C.useEffect(()=>{kD(S.current);const W=i.duplicateNames.splice(0);Promise.all(W.map(ne=>hw(ne).catch(()=>{}))),Promise.all(S.current.map(ne=>k(ne)));const K=()=>{document.hidden||Promise.all(S.current.map(ne=>k(ne,{quiet:!0})))};return document.addEventListener("visibilitychange",K),()=>document.removeEventListener("visibilitychange",K)},[k]);const A=e?N7({session:((z=e.session)==null?void 0:z.name)??null,windowName:((G=e.window)==null?void 0:G.name)??null,windowId:((Y=e.window)==null?void 0:Y.id)??null}):null,D=a.map(W=>{var K,ne,de;return{...W,kind:"static",status:((K=g[W.name])==null?void 0:K.status)||"ensuring",url:((ne=g[W.name])==null?void 0:ne.url)||null,error:((de=g[W.name])==null?void 0:de.error)||null}}),T=((X=D.find(W=>W.name===o))==null?void 0:X.name)??(($=D[0])==null?void 0:$.name)??null,R=f&&D.find(W=>W.name===T)||null,M=C.useCallback(async W=>{var fe,Q;if(!A)return null;const K=S.current.find(q=>q.dir===W);if(K){Vj(((fe=e==null?void 0:e.window)==null?void 0:fe.id)??void 0,W),c(K.name),v(!0);const q=j.current[K.name];if((q==null?void 0:q.status)==="ready"&&q.url)return{...K,...q,url:q.url};const ie=y.current.get(K.name),ue=ie?DD(await ie):await k(K);return ue?{...K,...ue}:null}const ne=S.current.find(q=>q.name===A),de={name:A,dir:W,createdAt:(ne==null?void 0:ne.createdAt)||Date.now()},re=await k(de,{allowDetached:!0});return re?(Vj(((Q=e==null?void 0:e.window)==null?void 0:Q.id)??void 0,W),m(q=>[...q.filter(ie=>ie.name!==de.name),de]),c(de.name),v(!0),{...de,...re}):null},[m,A,(P=e==null?void 0:e.window)==null?void 0:P.id,k]),L=C.useCallback((W=T)=>{const K=S.current.find(ne=>ne.name===W);return K?k(K):Promise.resolve(null)},[T,k]),B=C.useCallback(W=>{S.current.some(K=>K.name===W)&&(c(W),v(!0))},[]),I=C.useCallback(()=>v(!1),[]),O=C.useCallback(async W=>{var ne;if(!W)return;_(null);const K=m(de=>de.filter(re=>re.name!==W));x(W),o===W&&(c(((ne=K[0])==null?void 0:ne.name)||null),K.length||v(!1));try{await N(W,()=>hw(W))}catch(de){_(de instanceof Error?de:new Error(String(de)))}},[o,x,m,N]);return{error:h,selected:f,deactivate:I,curPreviewName:A,tabs:D,activeName:T,shownPreview:R,startPreview:M,retryPreview:L,switchTab:B,closeTab:O,pane:(e==null?void 0:e.paneId)||null,lastPreviewDir:UP(((F=e==null?void 0:e.window)==null?void 0:F.id)??void 0)}}function Ec(e){const{url:n,channel:i,generation:a,...u}=e;return u}function S7(e){const{siteVersion:n,...i}=Ec(e);return i}function rf(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null}function xg(e){const n=rf(e);return{...typeof(n==null?void 0:n.status)=="number"?{status:n.status}:{},...typeof(n==null?void 0:n.message)=="string"?{message:n.message}:{},...typeof(n==null?void 0:n.name)=="string"?{name:n.name}:{}}}function TD(e){const n=rf(e),i=typeof(n==null?void 0:n.generation)=="number"||typeof(n==null?void 0:n.generation)=="string"?n.generation:null;return{ready:(n==null?void 0:n.ready)===!0,generation:i}}function RD(e){const n=rf(e);if(!n||typeof n.url!="string"||!n.url)throw new Error(w("browser.loadFailed"));return{url:n.url,...typeof n.channel=="string"?{channel:n.channel}:{},...typeof n.generation=="number"||typeof n.generation=="string"?{generation:n.generation}:{}}}function AD(e){const n=rf(e),i=n==null?void 0:n.retentionDays;if(!n||typeof n.persist!="boolean"||i!==null&&i!==1&&i!==7&&i!==30)throw new Error("Browser proxy returned invalid profile preferences");return{persist:n.persist,retentionDays:i,...typeof n.warning=="string"?{warning:n.warning}:{}}}const UD=e=>({...e,...e.mode==="direct"?{url:e.originalUrl}:{},...e.mode==="proxy"?{siteVersion:e.siteVersion==="desktop"?"desktop":"mobile"}:{}}),_w=[250,500,1e3,2e3,4e3,5e3];function yw(e){const n=xg(e);return[502,503,504].includes(n.status??0)||/(?:timeout|browser unavailable|failed to fetch|networkerror|load failed)/i.test(n.message||"")}const j7=e=>new Promise(n=>setTimeout(n,e));function MD(){const e=new Error("browser open aborted");return e.name="AbortError",e}function LD(e,n){return n?n.aborted?Promise.reject(MD()):new Promise((i,a)=>{const u=()=>a(MD());n.addEventListener("abort",u,{once:!0}),Promise.resolve(e).then(i,a).finally(()=>{n.removeEventListener("abort",u)})}):Promise.resolve(e)}function D7(){const e=new Uint8Array(18);return crypto.getRandomValues(e),[...e].map(n=>n.toString(16).padStart(2,"0")).join("")}function k7({enabled:e=!0,browserProxy:n=!1}={}){const i=C.useRef(bP()).current,a=C.useRef(null);a.current||(a.current=i?xB():{tabs:[],activeId:null,open:!1,historyActive:!0});const[u,g]=C.useState(i),d=a.current,[o,c]=C.useState(()=>d.tabs.map(UD)),[f,v]=C.useState(d.activeId),[h,_]=C.useState(d.open&&i),[S,j]=C.useState(d.historyActive),[y,m]=C.useState(!1),[b,x]=C.useState(null),[N,k]=C.useState(Ml),[A,D]=C.useState(null),T=fw(),[R,M]=C.useState(T.closeAfter),[L,B]=C.useState(T.persistProxyLogin),[I,O]=C.useState(T.proxyLoginRetentionDays),z=C.useRef(o),G=C.useRef(f),Y=C.useRef(h),X=C.useRef(S),$=C.useRef(new Map),P=C.useRef(null),F=C.useRef(0),W=C.useRef(new Map),K=C.useRef(new Map),ne=C.useRef(b),de=C.useRef(null),re=C.useRef(Promise.resolve()),fe=C.useRef(!1),Q=C.useRef({persist:T.persistProxyLogin,retentionDays:T.proxyLoginRetentionDays}),q=C.useRef(new Map);z.current=o,G.current=f,Y.current=h,X.current=S;const ie=C.useCallback(Ce=>{const ve=typeof Ce=="function"?Ce(z.current):Ce;return z.current=ve,c(ve),ve},[]),ue=C.useCallback(Ce=>{G.current=Ce,v(Ce)},[]),we=C.useCallback(Ce=>{Y.current=Ce,_(Ce)},[]),pe=C.useCallback(Ce=>{X.current=Ce,j(Ce)},[]);C.useEffect(()=>{wB({tabs:o,activeId:f,open:h,historyActive:S})},[f,S,h,o]);const Ie=C.useCallback(Ce=>{Ce!=null&&Ce.originalUrl&&(Yv({url:Ce.originalUrl,title:Ce.title,lastMode:Ce.mode,visitedAt:Date.now(),sessionId:Ce.id}),k(Ml()))},[]),je=C.useCallback(Ce=>{(Ce==null?void 0:Ce.mode)==="proxy"&&nD(Ce.id).catch(()=>{})},[]),Qe=C.useCallback((Ce,ve=null)=>{const gt=z.current.findIndex(en=>en.id===Ce);if(gt<0)return;const dt=z.current[gt];je(dt);const jt=ie(en=>en.filter(ze=>ze.id!==Ce));if(G.current===Ce){const ze=(ve!=null&&ve.activeId?jt.find(We=>We.id===ve.activeId):null)||jt[Math.min(gt,jt.length-1)]||null;ze&&!(ve!=null&&ve.historyActive)&&ie(We=>We.map(yt=>yt.id===ze.id?{...yt,deadline:null}:yt)),ue((ze==null?void 0:ze.id)||null),pe((ve==null?void 0:ve.historyActive)??!ze),ve&&we(ve.open)}},[ue,pe,we,ie,je]),_e=C.useCallback(Ce=>{const ve=re.current.catch(()=>{}).then(Ce);return re.current=ve.then(()=>{},()=>{}),ve},[]),Ue=C.useCallback((Ce,ve)=>{ve.generation!=null&&P.current!==ve.generation&&(P.current=ve.generation,ie(dt=>dt.map(jt=>jt.mode==="proxy"&&jt.id!==Ce?Ec(jt):jt)));let gt=null;return ie(dt=>dt.map(jt=>{if(jt.id!==Ce||jt.mode!=="proxy")return jt;const en={...Ec(jt),url:ve.url,...ve.channel!==void 0?{channel:ve.channel}:{},...ve.generation!==void 0?{generation:ve.generation}:{}};return gt=en,en})),gt},[ie]),ht=C.useCallback((Ce,{force:ve=!1}={})=>{const gt=z.current.find(De=>De.id===Ce);if(!gt||gt.mode!=="proxy"||gt.url&&!ve)return Promise.resolve(gt||null);if(!n)return D(new Error(w("browser.proxyUnavailable"))),Promise.resolve(null);const dt=gt.originalUrl,jt=gt.siteVersion==="desktop"?"desktop":"mobile",en=$.current.get(Ce);if((en==null?void 0:en.url)===dt&&en.siteVersion===jt)return en.promise;let ze=!1;const We=()=>{const De=z.current.find(bt=>bt.id===Ce);return(De==null?void 0:De.mode)==="proxy"&&De.originalUrl===dt&&De.siteVersion===jt};let yt;return yt=(async()=>{for(let De=0;De<=_w.length;De+=1){if(!We())return null;let bt=null;try{bt=TD(await rD())}catch(zt){if(!yw(zt))throw zt}if(!We())return null;let mt=!(bt!=null&&bt.ready);if(bt!=null&&bt.ready)try{const zt=await _e(async()=>{if(!We())return null;let Se;try{const xt=fw();Se=AD(await iD({persist:xt.persistProxyLogin,retentionDays:xt.proxyLoginRetentionDays}))}catch(xt){throw yw(xt)?xt:new Error(w("browser.profileSyncFailed"))}return We()?(ze=(Se==null?void 0:Se.warning)==="profile-recovery-failed",ze&&!fe.current&&(fe.current=!0,D(new Error(w("browser.profileRecoveryWarning")))),RD(await R6(Ce,dt,jt))):null});return We()?zt:null}catch(zt){if(!yw(zt))throw zt;mt=!0}if(!mt)return null;if(De===_w.length)throw new Error(w("browser.loadFailed"));const Lt=_w[De];if(Lt===void 0)throw new Error(w("browser.loadFailed"));await j7(Lt)}return null})().then(De=>{if(!De)return null;const bt=z.current.find(Lt=>Lt.id===Ce);if(!bt||bt.mode!=="proxy"||bt.originalUrl!==dt||bt.siteVersion!==jt)return nD(Ce).catch(()=>{}),null;const mt=Ue(Ce,De);return ze||D(null),mt}).catch(De=>{if(We()){const bt=xg(De).message||w("browser.loadFailed");D(De instanceof Error?De:new Error(bt))}return null}).finally(()=>{var De;((De=$.current.get(Ce))==null?void 0:De.promise)===yt&&$.current.delete(Ce)}),$.current.set(Ce,{url:dt,siteVersion:jt,promise:yt}),yt},[Ue,n,_e]),Rt=C.useCallback(Ce=>(ie(ve=>ve.map(gt=>gt.id===Ce&&gt.mode==="proxy"?Ec(gt):gt)),ht(Ce,{force:!0})),[ie,ht]),Te=C.useCallback(async()=>{if(!(!e||!u||!n))try{const Ce=TD(await rD());if(Ce.generation==null)return;const ve=P.current!=null&&P.current!==Ce.generation;P.current=Ce.generation,ve&&ie(gt=>gt.map(dt=>dt.mode==="proxy"?Ec(dt):dt))}catch{}},[u,n,ie,e]),Fe=C.useCallback((Ce,ve=R)=>({...Ce,deadline:ve==null?null:Date.now()+ve*6e4}),[R]),it=C.useCallback(()=>{const Ce=Date.now(),ve=z.current.filter(jt=>jt.deadline!=null&&jt.deadline<=Ce);if(!ve.length)return;const gt=new Set(ve.map(jt=>jt.id));ve.forEach(jt=>{Ie(jt),je(jt)});const dt=ie(jt=>jt.filter(en=>!gt.has(en.id)));if(G.current&&gt.has(G.current)){const jt=dt[0]||null;ue((jt==null?void 0:jt.id)||null),pe(!jt)}},[ue,pe,ie,Ie,je]);C.useEffect(()=>{it(),Te();const Ce=()=>{document.hidden||(it(),Te())};return document.addEventListener("visibilitychange",Ce),()=>document.removeEventListener("visibilitychange",Ce)},[it,Te]),C.useEffect(()=>{const Ce=o.flatMap(gt=>gt.deadline==null?[]:[gt.deadline]);if(!Ce.length)return;const ve=setTimeout(it,Math.max(0,Math.min(...Ce)-Date.now()));return()=>clearTimeout(ve)},[it,o]);const $e=C.useCallback(async(Ce,{mode:ve="direct",force:gt=!1,signal:dt}={})=>{if(dt!=null&&dt.aborted)return null;const jt=++F.current,en=yg(Ce);if(!en)return D(new Error(w("browser.urlInvalid"))),null;if(!u&&!gt){const De={url:en,mode:ve};return ne.current=De,x(De),m(!0),{pending:!0}}if(ve==="proxy"&&!n)return D(new Error(w("browser.proxyUnavailable"))),null;const ze=D7(),We={activeId:G.current,historyActive:X.current,open:Y.current},yt=UD({id:ze,mode:ve,originalUrl:en,title:"",deadline:null,createdAt:Date.now(),...ve==="proxy"?{siteVersion:"mobile"}:{}});ie(De=>[...De.map(bt=>bt.id===G.current&&Y.current&&!X.current?Fe(bt):bt),yt]),ue(ze),pe(!1),we(!0),D(null);try{ve==="proxy"?await LD(ht(ze),dt):await LD(Promise.resolve(),dt)}catch(De){if(Qe(ze,We),xg(De).name==="AbortError")return null;throw De}return dt!=null&&dt.aborted?(Qe(ze,We),null):jt!==F.current?(Qe(ze),null):z.current.find(De=>De.id===ze)||yt},[u,n,ue,pe,we,ie,Qe,ht,Fe]),lt=C.useCallback(()=>{if(de.current)return de.current;const Ce=ne.current;ne.current=null,x(null);const ve=(async()=>(gg(!0),g(!0),m(!1),Ce?$e(Ce.url,{mode:Ce.mode,force:!0}):(we(!0),!0)))().finally(()=>{de.current===ve&&(de.current=null)});return de.current=ve,ve},[we,$e]),ut=C.useCallback(()=>{ne.current=null,x(null),m(!1)},[]),He=C.useCallback(()=>{z.current.forEach(je),ie([]),ue(null),pe(!0),we(!1),NB(),gg(!1),g(!1),m(!1),ne.current=null},[ue,pe,we,ie,je]),nt=C.useCallback(Ce=>Ce?(gg(!0),g(!0),!0):(He(),!1),[He]),Be=C.useCallback(async Ce=>{if(Ce==="history")return D(null),Y.current&&G.current&&!X.current&&ie(gt=>gt.map(dt=>dt.id===G.current?Fe(dt):dt)),pe(!0),!0;const ve=z.current.find(gt=>gt.id===Ce);return ve?(Y.current&&ve.mode==="proxy"&&await Te(),D(null),ie(gt=>gt.map(dt=>dt.id===Ce?{...dt,deadline:null}:dt.id===G.current&&Y.current&&!X.current?Fe(dt):dt)),ue(Ce),pe(!1),Y.current&&await ht(Ce),!0):!1},[ue,pe,ie,ht,Fe,Te]),xe=C.useCallback(async Ce=>{if(Ce&&!u)return m(!0),!1;const ve=z.current.find(gt=>gt.id===G.current);return Ce&&!X.current&&(ve==null?void 0:ve.mode)==="proxy"&&await Te(),G.current&&!X.current&&ie(gt=>gt.map(dt=>dt.id===G.current?Ce?{...dt,deadline:null}:Fe(dt):dt)),we(Ce),Ce&&G.current&&!X.current&&await ht(G.current),!0},[u,we,ie,ht,Fe,Te]),Ee=C.useCallback(Ce=>{const ve=z.current.findIndex(jt=>jt.id===Ce);if(ve<0)return;D(null);const gt=z.current[ve];Ie(gt),je(gt);const dt=ie(jt=>jt.filter(en=>en.id!==Ce));if(G.current===Ce){const jt=dt[Math.min(ve,dt.length-1)]||null;ue((jt==null?void 0:jt.id)||null),pe(!jt),jt&&Y.current&&(ie(en=>en.map(ze=>ze.id===jt.id?{...ze,deadline:null}:ze)),ht(jt.id))}},[ue,pe,ie,ht,Ie,je]),et=C.useCallback(async(Ce,ve,gt,dt)=>{const jt=yg(ve),en=z.current.find(De=>De.id===Ce);if(!en)return null;if(!jt)return D(new Error(w("browser.urlInvalid"))),null;const ze=gt||en.mode,We=dt==="desktop"?"desktop":dt==="mobile"?"mobile":en.mode==="proxy"&&en.siteVersion==="desktop"?"desktop":"mobile";if(ze==="proxy"&&!n)return D(new Error(w("browser.proxyUnavailable"))),null;D(null);const yt=(W.current.get(Ce)||0)+1;if(W.current.set(Ce,yt),q.current.set(Ce,yt),en.mode==="proxy"&&ze==="direct"&&je(en),ie(De=>De.map(bt=>{if(bt.id!==Ce)return bt;const mt={...bt,mode:ze,originalUrl:jt,title:""};return ze==="direct"?{...S7(mt),url:jt}:{...Ec(mt),siteVersion:We}})),ze==="proxy"){const bt=(K.current.get(Ce)||Promise.resolve()).catch(()=>{}).then(async()=>{if(en.mode==="proxy")return RD(await A6(Ce,jt,We));const mt=await ht(Ce,{force:!0});return mt!=null&&mt.url?{url:mt.url,...mt.channel?{channel:mt.channel}:{},...mt.generation!=null?{generation:mt.generation}:{}}:null});K.current.set(Ce,bt);try{const mt=await bt;K.current.get(Ce)===bt&&K.current.delete(Ce);const Lt=z.current.find(zt=>zt.id===Ce);Lt&&W.current.get(Ce)===yt&&Lt.mode===ze&&Lt.originalUrl===jt&&Lt.siteVersion===We&&(mt!=null&&mt.url?(Ue(Ce,mt),D(null)):q.current.delete(Ce))}catch(mt){K.current.get(Ce)===bt&&K.current.delete(Ce);const Lt=z.current.find(zt=>zt.id===Ce);if(Lt&&W.current.get(Ce)===yt&&Lt.mode===ze&&Lt.originalUrl===jt&&Lt.siteVersion===We){ie(Se=>Se.map(xt=>xt.id===Ce?Ec(xt):xt));const zt=xg(mt).message||w("browser.loadFailed");D(mt instanceof Error?mt:new Error(zt)),q.current.delete(Ce)}}}else W.current.get(Ce)===yt&&q.current.delete(Ce);return z.current.find(De=>De.id===Ce)||null},[Ue,n,ie,ht,je]),st=C.useCallback((Ce,ve)=>{if(q.current.has(Ce))return null;const gt=z.current.find(jt=>jt.id===Ce);if(!gt)return;const dt={...gt,originalUrl:yg(ve==null?void 0:ve.url)||gt.originalUrl,title:typeof(ve==null?void 0:ve.title)=="string"?ve.title:gt.title};ie(jt=>jt.map(en=>en.id===Ce?dt:en)),dt.title&&(Yv({url:dt.originalUrl,title:dt.title,lastMode:dt.mode,visitedAt:Date.now(),sessionId:dt.id}),k(Ml()))},[ie]),Le=C.useCallback((Ce,ve)=>{const gt=z.current.find(dt=>dt.id===Ce);(gt==null?void 0:gt.mode)==="proxy"&&gt.channel===ve&&q.current.delete(Ce)},[]),St=C.useCallback(Ce=>{vB(Ce);const ve=fw().closeAfter;return M(ve),ve},[]),Pt=C.useCallback((Ce,ve)=>{if(Ce.kind==="static")return null;Yv({...Ce,lastMode:ve});const gt=Ml();return k(gt),gt.find(dt=>dt.kind!=="static"&&dt.url===Ce.url)||null},[]),At=C.useCallback(Ce=>{const ve=rf(Ce);Yv({kind:"static",dir:ve==null?void 0:ve.dir,title:ve==null?void 0:ve.title,visitedAt:Date.now()}),k(Ml())},[]),Jt=C.useCallback(async Ce=>{const ve={persist:Ce.persist??Q.current.persist,retentionDays:Ce.retentionDays!==void 0?Ce.retentionDays:Q.current.retentionDays};Q.current=ve;try{const gt=await _e(async()=>{const dt=AD(await iD(ve));return gB(dt.persist),bB(dt.retentionDays),dt});return B(gt.persist),O(gt.retentionDays),!0}catch{return D(new Error(w("browser.profileSaveFailed"))),!1}},[_e]),fn=C.useCallback(async(Ce=null)=>{try{return await U6(Ce),!0}catch{return D(new Error(w("browser.profileClearFailed"))),!1}},[]);return{open:h,accessEnabled:u,consentOpen:y,tabs:o,activeId:f,historyActive:S,closeAfter:R,persistProxyLogin:L,proxyLoginRetentionDays:I,proxyAvailable:n,history:N,error:A,openUrl:$e,enableAccess:lt,disableAccess:He,setEnabled:nt,cancelAccess:ut,switchTab:Be,closeTab:Ee,setOpen:xe,setCloseAfter:St,setPersistProxyLogin:Ce=>Jt({persist:!!Ce}),setProxyLoginRetentionDays:Ce=>Jt({retentionDays:Ce}),setProxyLoginPolicy:({persist:Ce,retentionDays:ve})=>Jt({persist:Ce,retentionDays:ve}),clearProxyLogin:fn,setHistoryMode:Pt,recordStaticHistory:At,navigateTab:et,ensureBinding:ht,recoverBinding:Rt,markBindingReady:Le,updateTabMeta:st,deleteHistory:Ce=>{_B(Ce),k(Ml())},clearHistory:()=>{yB(),k([])}}}function hh({fetch:e,apply:n,onError:i,intervalMs:a,enabled:u=!0,deps:g=[],burstKey:d=null,burstIntervalMs:o=a,burstCount:c=0,repeat:f=!0}){const v=C.useRef(e),h=C.useRef(n),_=C.useRef(i);v.current=e,h.current=n,_.current=i,C.useEffect(()=>{if(!u)return;let S=!1,j=null,y=!1,m=!1,b=0,x=document.hidden,N=d==null?0:c;const k=async z=>{var G;if(!document.hidden)try{const Y=await v.current();!S&&z===b&&h.current(Y)}catch(Y){!S&&z===b&&((G=_.current)==null||G.call(_,Y))}},A=()=>{const z=N>0?o:a;return N>0&&(N-=1),z},D=async()=>{if(S||document.hidden)return;if(y){m=!0;return}y=!0;const z=++b;if(await k(z),z!==b||(y=!1,S||document.hidden)||!f)return;const G=m?0:A();m=!1,j=setTimeout(D,G)};D();const T=()=>{y&&(b+=1,y=!1,m=!1)},R=()=>{j!==null&&clearTimeout(j),j=null,T()},M=({abandon:z=!1}={})=>{if(!(S||document.hidden)){if(j!==null&&clearTimeout(j),j=null,y)if(z)T();else{m=!0;return}D()}},L=()=>{if(document.hidden){x=!0,R();return}const z=x;x=!1,M({abandon:z})},B=()=>M({abandon:!0}),I=()=>M({abandon:!0}),O=()=>M({abandon:!0});return document.addEventListener("visibilitychange",L),window.addEventListener("pageshow",B),window.addEventListener("focus",I),window.addEventListener("online",O),()=>{S=!0,j!==null&&clearTimeout(j),document.removeEventListener("visibilitychange",L),window.removeEventListener("pageshow",B),window.removeEventListener("focus",I),window.removeEventListener("online",O)}},[u,a,d,o,c,f,...g])}const ID={type:"key",key:"C-c",label:"Ctrl+C"},Xh={command:[{...ID}],chat:[{...ID},{type:"key",key:"Escape",label:"Esc"},{type:"key",key:"Tab",label:"Tab"},{type:"key",key:"BSpace",label:"⌫"},{type:"text",text:"ok",enter:!0},{type:"text",text:"go on",enter:!0},{type:"text",text:"1",enter:!0},{type:"text",text:"2",enter:!0},{type:"text",text:"3",enter:!0},{type:"text",text:"/compact",enter:!0},{type:"text",text:"/clear",enter:!0},{type:"text",text:"/model",enter:!0}]};function Fn(e){return"type"in e&&e.type==="key"?`key:${e.key}`:"kind"in e&&e.kind==="key"?`key:${e.text}`:`text:${e.text}:${e.enter?"enter":"no-enter"}`}function T7(e,n){return e.type==="key"?{kind:"key",text:e.key,label:e.label||e.key,source:"config"}:{kind:n==="chat"&&!e.text.startsWith("/")?"reply":"cmd",text:e.text,enter:!!e.enter,source:"config"}}function Ac(e,n,i){const a=e.map(d=>T7(d,i)),u=new Set(a.map(Fn)),g=n.filter(d=>!u.has(Fn(d))).map(d=>({...d,source:"local"}));return[...a,...g]}const R0=e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:null,VD=e=>{const n=R0(e);return(n==null?void 0:n.type)==="key"&&typeof n.key=="string"&&n.key?{type:"key",key:n.key,...typeof n.label=="string"&&n.label?{label:n.label}:{}}:(n==null?void 0:n.type)==="text"&&typeof n.text=="string"&&n.text?{type:"text",text:n.text,...typeof n.enter=="boolean"?{enter:n.enter}:{}}:null},R7=e=>{const n=R0(e);return!Array.isArray(n==null?void 0:n.command)||!Array.isArray(n.chat)?null:{command:n.command.map(VD).filter(i=>i!==null),chat:n.chat.map(VD).filter(i=>i!==null)}},A7=new Set(["installed","absent","no-claude"]);function U7(e){const n=R0(e);if(!n)return null;const i=typeof n.claudeHooks=="string"&&A7.has(n.claudeHooks)?n.claudeHooks:void 0;return{shortcuts:R7(n.shortcuts)||Xh,...typeof n.asr=="boolean"?{asr:n.asr}:{},...n.asrProvider===null||typeof n.asrProvider=="string"?{asrProvider:n.asrProvider}:{},...n.asrMode===null||n.asrMode==="streaming"||n.asrMode==="sentence"?{asrMode:n.asrMode}:{},...typeof n.asrFillerFilter=="boolean"?{asrFillerFilter:n.asrFillerFilter}:{},...i?{claudeHooks:i}:{},...typeof n.managedCodex=="boolean"?{managedCodex:n.managedCodex}:{},...typeof n.browserProxy=="boolean"?{browserProxy:n.browserProxy}:{}}}function M7({enabled:e=!0}={}){const[n,i]=C.useState(null),a=C.useRef(!1),u=C.useRef(!1),g=C.useRef(!0),d=C.useRef(e),o=C.useRef(0);C.useLayoutEffect(()=>(g.current=!0,()=>{g.current=!1}),[]),C.useLayoutEffect(()=>{d.current!==e&&(d.current=e,o.current+=1)},[e]);const c=C.useCallback(()=>{if(!g.current||!d.current||u.current)return;u.current=!0;const f=o.current;let v;try{v=E6()}catch{u.current=!1;return}Promise.resolve(v).then(h=>{const _=U7(h);!g.current||!d.current||o.current!==f||!_||i(_)}).catch(()=>{}).finally(()=>{u.current=!1})},[]);return C.useEffect(()=>{!e||a.current||(a.current=!0,c())},[e,c]),C.useEffect(()=>{if(!e)return;const f=()=>{document.hidden||c()};return document.addEventListener("visibilitychange",f),()=>{document.removeEventListener("visibilitychange",f)}},[e,c]),n}function wA(e){return e instanceof Er&&(e.code==="origin_rejected"||e.code==="AUTH_ORIGIN_REJECTED")}function L7(e,n){return e==="device"?e:wA(n)||e==="origin"?"origin":"token"}function I7(e,n){return e instanceof ar||wA(e)?(n==null||n(e),!0):!1}function V7(e,n={},i=null){var g,d;const a=e==null?void 0:e.paneId;if(!a)return null;if((i==null?void 0:i.paneId)===a)return i.agentId;const u=(g=e.panes)==null?void 0:g.find(o=>o.id===a);return u&&Object.hasOwn(u,"agent")?u.agent||null:((d=n[a])==null?void 0:d.agent)||null}function O7(e){var a;const n=e==null?void 0:e.paneId;if(!n)return!1;const i=(a=e.panes)==null?void 0:a.find(u=>u.id===n);return!!i&&Object.hasOwn(i,"agent")}function OD(e,n){const i=`${n}\0`;for(const a of e.keys())a.startsWith(i)&&e.delete(a)}function P7(e,n={}){var o;const i={},a={};for(const[c,f]of Object.entries(n))f!=null&&f.agent&&(a[c]=f.agent,f.window&&(i[f.window]=f.agent));const u=(o=e==null?void 0:e.window)==null?void 0:o.id;let g=!1,d=null;for(const c of(e==null?void 0:e.panes)||[])Object.hasOwn(c,"agent")&&(g=!0,a[c.id]=c.agent||null,c.agent&&(d=c.agent));return u&&g&&(i[u]=d),{windowAgents:i,paneAgents:a}}function B7(){return C.useSyncExternalStore(SB,mD,mD)}function NA(e){if(typeof e!="string")return w("workspace.unknownTime");const n=Date.parse(e);if(!Number.isFinite(n))return w("workspace.unknownTime");try{return new Intl.DateTimeFormat(mo(),{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"}).format(new Date(n))}catch{return new Date(n).toLocaleString()}}function F7({plan:e,operation:n=null,onOpen:i}){var u;if(!e)return null;const a=(n==null?void 0:n.status)==="partial"?(n.results||[]).filter(g=>g.status==="failed").length:0;return s.jsxDEV("button",{type:"button",className:"workspace-recovery-card",onClick:i,children:[s.jsxDEV("strong",{children:w(MR(e))},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WorkspaceRecoveryCard.tsx",lineNumber:35,columnNumber:7},this),s.jsxDEV("span",{children:w("workspace.summary",{sessions:((u=e.summary)==null?void 0:u.sessions)??0,time:NA(e.capturedAt)})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WorkspaceRecoveryCard.tsx",lineNumber:36,columnNumber:7},this),a>0&&s.jsxDEV("span",{className:"workspace-recovery-partial",children:w("workspace.partialCard",{failures:a})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WorkspaceRecoveryCard.tsx",lineNumber:40,columnNumber:24},this),s.jsxDEV("span",{className:"workspace-recovery-action",children:w("workspace.restoreLast")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WorkspaceRecoveryCard.tsx",lineNumber:41,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WorkspaceRecoveryCard.tsx",lineNumber:34,columnNumber:5},this)}function H7({open:e,currentSessionName:n,bound:i,onSelectSession:a,onUnbind:u,onBind:g,onClose:d,onLogout:o,orphans:c=[],onTakeoverRequest:f,recoveryPlan:v=null,recoveryOperation:h=null,onOpenRecovery:_=()=>{},projectTaskBeta:S=!1,onSwitchProject:j=()=>{}}){const[y,m]=C.useState(!1);return s.jsxDEV(s.Fragment,{children:[s.jsxDEV("div",{id:"session-drawer",className:`drawer ${e?"open":""}`,children:[s.jsxDEV("div",{className:"drawer-list",children:[S&&s.jsxDEV("div",{className:"project-root-switch",role:"group",children:[s.jsxDEV("button",{type:"button","aria-pressed":"false",onClick:j,children:w("project.root.projects")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:56,columnNumber:15},this),s.jsxDEV("button",{type:"button","aria-pressed":"true",children:w("project.root.sessions")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:57,columnNumber:15},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:55,columnNumber:13},this),s.jsxDEV("div",{className:"drawer-title",children:w("drawer.title").toUpperCase()},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:60,columnNumber:11},this),i.length===0&&s.jsxDEV("div",{className:"drawer-empty",children:w("drawer.empty")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:61,columnNumber:34},this),i.map(b=>s.jsxDEV("div",{className:`drawer-row drawer-session ${b===n?"active":""}`,children:[s.jsxDEV("span",{className:"drawer-name",onClick:()=>a(b),children:b},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:67,columnNumber:15},this),s.jsxDEV("button",{className:"drawer-unbind",onClick:x=>{x.stopPropagation(),u(b)},"aria-label":w("drawer.unbind"),title:w("drawer.unbind"),children:"✕"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:68,columnNumber:15},this)]},b,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:63,columnNumber:13},this)),s.jsxDEV("button",{className:"drawer-bind",onClick:g,children:["+ ",w("drawer.bind")]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:78,columnNumber:11},this),c.length>0&&s.jsxDEV("div",{className:"drawer-orphans",children:[s.jsxDEV("button",{className:"drawer-orphans-head",onClick:()=>m(b=>!b),children:[s.jsxDEV("span",{children:w("drawer.orphans.title",{n:c.length})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:83,columnNumber:17},this),s.jsxDEV("span",{className:"drawer-orphans-caret","aria-hidden":"true",children:y?"▾":"▸"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:84,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:82,columnNumber:15},this),y&&s.jsxDEV(s.Fragment,{children:[s.jsxDEV("div",{className:"drawer-orphans-hint",children:w("drawer.orphans.hint")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:88,columnNumber:19},this),c.map(b=>{const x=!b.sessionId,N=b.state==="busy"||x;return s.jsxDEV("div",{className:"drawer-orphan-row",children:[s.jsxDEV("div",{className:"drawer-orphan-head",children:[s.jsxDEV("span",{className:"drawer-orphan-cwd",title:b.cwd,children:b.cwdLabel||b.cwd},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:95,columnNumber:27},this),s.jsxDEV("button",{className:"drawer-orphan-btn",disabled:N,title:x?w("inbox.orphans.noSession"):void 0,onClick:()=>f==null?void 0:f(b),children:w("inbox.orphans.takeover")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:96,columnNumber:27},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:94,columnNumber:25},this),s.jsxDEV("div",{className:"drawer-orphan-meta",children:[b.agentLabel&&s.jsxDEV("span",{className:"drawer-orphan-agent",children:b.agentLabel},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:106,columnNumber:44},this),s.jsxDEV("span",{className:`drawer-orphan-state ${b.state==="busy"?"busy":"idle"}`,children:b.state==="busy"?w("inbox.orphans.busy"):w("inbox.orphans.idle")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:107,columnNumber:27},this),s.jsxDEV("span",{className:"drawer-orphan-time",children:mA(b.startedAt||b.lastActivity||0,Date.now())},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:110,columnNumber:27},this),b.snippet&&s.jsxDEV("span",{className:"drawer-orphan-msg",children:b.snippet},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:111,columnNumber:41},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:105,columnNumber:25},this)]},b.pid,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:93,columnNumber:23},this)})]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:87,columnNumber:17},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:81,columnNumber:13},this),v&&s.jsxDEV(F7,{plan:v,operation:h,onOpen:_},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:121,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:53,columnNumber:9},this),s.jsxDEV("button",{className:"drawer-logout",onClick:o,children:w("drawer.logout")},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:124,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:52,columnNumber:7},this),e&&s.jsxDEV("div",{className:"drawer-backdrop",onClick:d},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:126,columnNumber:16},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/Drawer.tsx",lineNumber:51,columnNumber:5},this)}const z7=500,PD=10;function cb(e,{onClick:n}={}){const i=C.useRef(null),a=C.useRef(null),u=C.useRef(!1),g=()=>{i.current!==null&&(clearTimeout(i.current),i.current=null)};return C.useEffect(()=>g,[]),{onPointerDown:d=>{u.current=!1,a.current={x:d.clientX,y:d.clientY},g(),i.current=setTimeout(()=>{i.current=null,u.current=!0,e==null||e()},z7)},onPointerMove:d=>{i.current===null||!a.current||(Math.abs(d.clientX-a.current.x)>PD||Math.abs(d.clientY-a.current.y)>PD)&&g()},onPointerUp:g,onPointerLeave:g,onPointerCancel:g,onClick:d=>{if(u.current){u.current=!1,d.preventDefault(),d.stopPropagation();return}n==null||n(d)}}}const EN=248,SN=158,Ig=6,BD=2,$7=52,W7=34,Qv=e=>typeof e=="number"&&Number.isFinite(e);function A0(e){return Array.isArray(e)&&e.length>0&&e.every(n=>n!==null&&typeof n=="object"&&!Array.isArray(n)&&typeof n.id=="string"&&Qv(n.left)&&Qv(n.top)&&Qv(n.width)&&Qv(n.height))}function FD(e,n){if(!A0(e)||e.length<2)return!1;const i=e.find(g=>g.id===n);if(!i)return!1;const a=i.left+i.width,u=i.top+i.height;return e.some(g=>{if(g.id===n||!(Math.min(u,g.top+g.height)>Math.max(i.top,g.top)))return!1;const o=g.left+g.width;return Math.abs(g.left-a)<=1||Math.abs(i.left-o)<=1})}const HD=e=>[...new Set(e)].sort((n,i)=>n-i);function zD(e,n,i){const a=[];for(let c=0;c<e.length-1;c+=1){const f=e[c],v=e[c+1];if(f===void 0||v===void 0)continue;const h=n.some(([_,S])=>_===f&&S===v);a.push(v-f<=1&&!h)}const u=a.filter(c=>!c).length,g=u>0?(i-a.filter(Boolean).length*BD)/u:i,d=[{at:0}];let o=0;for(let c=0;c<a.length;c+=1)o+=a[c]?BD:g,d.push({at:o});return d}function q7(e){if(!A0(e))return null;const n=Math.max(...e.map(v=>v.left+v.width)),i=Math.max(...e.map(v=>v.top+v.height));if(n<=0||i<=0)return null;const a=HD(e.flatMap(v=>[v.left,v.left+v.width])),u=HD(e.flatMap(v=>[v.top,v.top+v.height])),g=e.map(v=>[v.left,v.left+v.width]),d=e.map(v=>[v.top,v.top+v.height]),o=zD(a,g,EN-Ig*2),c=zD(u,d,SN-Ig*2),f=e.map((v,h)=>{var m,b,x,N;const _=((m=o[a.indexOf(v.left)])==null?void 0:m.at)??0,S=((b=o[a.indexOf(v.left+v.width)])==null?void 0:b.at)??_,j=((x=c[u.indexOf(v.top)])==null?void 0:x.at)??0,y=((N=c[u.indexOf(v.top+v.height)])==null?void 0:N.at)??j;return{id:v.id,active:!!v.active,...v.command!==void 0?{command:v.command}:{},seq:h,left:_,top:j,width:S-_,height:y-j,cols:v.width,rows:v.height}});return{w:EN,h:SN,cells:f}}function G7(e){const n=e.width<$7,i=e.height<W7;return n&&i?"tiny":n?"narrow":i?"flat":""}const xw={terminal:"终端",chat:"对话"};function K7(){return s.jsxDEV("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[s.jsxDEV("path",{d:"M4 8h13M13 4l4 4-4 4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:14,columnNumber:7},this),s.jsxDEV("path",{d:"M20 16H7M11 20l-4-4 4-4"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:15,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:12,columnNumber:5},this)}function Y7({value:e,onChange:n}){const i=e==="chat"?"terminal":"chat";return s.jsxDEV("button",{type:"button",className:"lens-toggle",onClick:()=>n(i),"aria-label":`切换到${xw[i]}视图`,title:`切换到${xw[i]}视图`,children:[s.jsxDEV(K7,{},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:35,columnNumber:7},this),s.jsxDEV("span",{className:"lens-toggle-label",children:xw[i]},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:36,columnNumber:7},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/LensSwitch.tsx",lineNumber:28,columnNumber:5},this)}const X7="①②③④⑤⑥⑦⑧⑨",Ih=e=>X7[e]??String(e+1),J7=(e,n)=>`${Ih(n)} ${(e==null?void 0:e.command)||(e==null?void 0:e.id)||""}`;function Q7({window:e,active:n,agent:i,onSelect:a,onManage:u}){const g=cb(()=>u(e),{onClick:()=>a(e)});return s.jsxDEV("button",{"data-win":e.id,className:`win-tab ${n?"active":""}`,...g,children:[s.jsxDEV("span",{className:"win-title",children:[i&&s.jsxDEV(ad,{agent:i},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:74,columnNumber:19},this),s.jsxDEV("span",{children:e.name||e.id},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:75,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:73,columnNumber:7},this),e.panes>1&&s.jsxDEV("span",{className:"win-panes",children:e.panes},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:77,columnNumber:25},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:72,columnNumber:5},this)}const Z7=200,eF=90;function tF({cell:e,cur:n,releasing:i,picking:a,agent:u,onChoose:g,onManage:d}){const o=G7(e),c=e.command||e.id,v=Number.isFinite(e.cols)&&Number.isFinite(e.rows)?`${e.cols}×${e.rows}`:"",h=o===""&&e.width>=eF&&v,_=cb(()=>d==null?void 0:d(e.id),{onClick:()=>g(e.id)});return s.jsxDEV("button",{type:"button",role:"option","aria-selected":n,"aria-label":v?`${c}, ${v}`:c,className:`pane-map-cell${n?" is-current":""}${i?" is-releasing":""}${o?` is-${o}`:""}${a?" is-picking":""}`,style:{left:`${e.left+Ig}px`,top:`${e.top+Ig}px`,width:`${e.width}px`,height:`${e.height}px`},..._,children:s.jsxDEV("span",{className:"pmc-surf",children:o==="narrow"||o==="tiny"?s.jsxDEV("span",{className:"pmc-seq","aria-hidden":"true",children:Ih(e.seq)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:121,columnNumber:11},this):o==="flat"?s.jsxDEV(s.Fragment,{children:[s.jsxDEV("span",{className:"pmc-seq","aria-hidden":"true",children:Ih(e.seq)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:124,columnNumber:13},this),s.jsxDEV("span",{className:"pmc-cmd",children:c},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:125,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:123,columnNumber:11},this):s.jsxDEV(s.Fragment,{children:[s.jsxDEV("span",{className:"pmc-row",children:[s.jsxDEV("span",{className:"pmc-seq","aria-hidden":"true",children:Ih(e.seq)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:130,columnNumber:15},this),u&&s.jsxDEV(ad,{agent:u},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:131,columnNumber:25},this),h&&s.jsxDEV("span",{className:"pmc-dims","aria-hidden":"true",children:v},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:132,columnNumber:34},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:129,columnNumber:13},this),s.jsxDEV("span",{className:"pmc-cmd",children:c},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:134,columnNumber:13},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:128,columnNumber:11},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:119,columnNumber:7},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:110,columnNumber:5},this)}function nF({window:e,panes:n,paneAgents:i={},currentPaneId:a,agent:u,onManage:g,onManagePane:d,onSelectPane:o,onBeforePaneMapOpen:c,paneSheetOpen:f=!1,openMapFor:v=null,onMapOpened:h,onPaneMapOpenChange:_}){const[S,j]=C.useState(!1);Nn(S,()=>j(!1));const y=C.useRef(S),m=C.useRef(_);y.current=S,m.current=_,C.useEffect(()=>{_==null||_(S)},[S,_]),C.useEffect(()=>()=>{var Y;y.current&&((Y=m.current)==null||Y.call(m,!1))},[]);const[b,x]=C.useState(null),N=C.useRef(null);C.useEffect(()=>()=>{N.current!==null&&clearTimeout(N.current)},[]);const k=Y=>{var $;try{($=navigator.vibrate)==null||$.call(navigator,10)}catch{}if(f&&(d==null||d(Y)),typeof window<"u"&&window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches){o(Y);return}x(Y),N.current!==null&&clearTimeout(N.current),N.current=setTimeout(()=>{x(null),o(Y)},Z7)},[A,D]=C.useState(null),T=C.useRef(null),R=C.useRef(null),M=A0(n)?q7(n):null,L=M?M.w:EN,B=M?M.h:SN,I=()=>{var K;const Y=(K=T.current)==null?void 0:K.getBoundingClientRect();if(!Y)return;const X=8,$=window.innerWidth,P=window.innerHeight,F=Math.max(X,Math.min(Y.left,$-L-X));let W=Y.bottom+6;if(W+B+X>P){const ne=Y.top-6-B;W=ne>=X?ne:Math.max(X,P-B-X)}D({top:W,left:F})};C.useLayoutEffect(()=>{S&&I()},[S,L,B]);const O=cb(()=>g(e),{onClick:()=>{if(S){j(!1);return}if((()=>{I(),j(!0)})(),c)try{Promise.resolve(c(e.id)).catch(()=>{})}catch{}}});C.useEffect(()=>{v&&v===e.id&&(I(),j(!0),h==null||h())},[v,e.id]),C.useEffect(()=>{if(!S)return;const Y=$=>{var P,F;f||(!($.target instanceof Node)||!((P=T.current)!=null&&P.contains($.target))&&!((F=R.current)!=null&&F.contains($.target)))&&j(!1)},X=()=>I();return document.addEventListener("pointerdown",Y,!0),window.addEventListener("scroll",X,!0),window.addEventListener("resize",X),()=>{document.removeEventListener("pointerdown",Y,!0),window.removeEventListener("scroll",X,!0),window.removeEventListener("resize",X)}},[S,f]);const z=Math.max(0,n.findIndex(Y=>Y.id===a)),G=n[z];return s.jsxDEV("div",{className:"wt-dd active","data-win":e.id,ref:T,children:[s.jsxDEV("button",{className:"win-tab active wt-trigger","aria-haspopup":"listbox","aria-expanded":S,...O,children:[s.jsxDEV("span",{className:"win-title",children:[u&&s.jsxDEV(ad,{agent:u},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:303,columnNumber:21},this),s.jsxDEV("span",{className:"wt-name",children:e.name||e.id},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:304,columnNumber:11},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:302,columnNumber:9},this),s.jsxDEV("span",{className:"wt-sep","aria-hidden":"true",children:"│"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:306,columnNumber:9},this),s.jsxDEV("span",{className:"wt-pane",children:J7(G,z)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:307,columnNumber:9},this),s.jsxDEV("span",{className:`wt-caret${S?" open":""}`,"aria-hidden":"true",children:"▾"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:308,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:296,columnNumber:7},this),S&&A&&(M?s.jsxDEV(mi,{children:s.jsxDEV("div",{ref:R,className:"pane-map",role:"listbox",style:{top:A.top,left:A.left,width:L,height:B},children:M.cells.map(Y=>{const X=Y.id===a;return s.jsxDEV(tF,{cell:Y,cur:X,releasing:X&&!!b&&b!==a,picking:b===Y.id,agent:i[Y.id]??null,onChoose:k,...d?{onManage:d}:{}},Y.id,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:317,columnNumber:19},this)})},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:313,columnNumber:13},this)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:312,columnNumber:11},this):s.jsxDEV("div",{className:"dd-menu wt-menu",role:"listbox",style:{top:A.top,left:A.left},children:n.map((Y,X)=>s.jsxDEV("button",{type:"button",role:"option","aria-selected":Y.id===a,className:`dd-option${Y.id===a?" is-selected":""}`,onClick:()=>{o(Y.id),j(!1)},children:[s.jsxDEV("span",{className:"dd-option-label",children:[s.jsxDEV("span",{className:"dd-pane-seq","aria-hidden":"true",children:Ih(X)},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:343,columnNumber:19},this),i[Y.id]&&s.jsxDEV(ad,{agent:i[Y.id]??null},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:344,columnNumber:40},this),s.jsxDEV("span",{className:"dd-pane-cmd",children:Y.command||Y.id},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:345,columnNumber:19},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:342,columnNumber:17},this),Y.id===a&&s.jsxDEV("span",{className:"dd-check","aria-hidden":"true",children:"✓"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:347,columnNumber:44},this)]},Y.id,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:334,columnNumber:15},this))},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:332,columnNumber:11},this))]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:295,columnNumber:5},this)}function rF({windows:e,windowAgents:n={},paneAgents:i={},currentAgent:a,currentWindowId:u,panes:g,currentPaneId:d,onSelectWindow:o,onSelectPane:c,onNewWindow:f,onManageWindow:v,onManagePane:h,onBeforePaneMapOpen:_,paneSheetOpen:S=!1,openMapFor:j=null,onMapOpened:y,onPaneMapOpenChange:m,trackWindowId:b,lens:x="terminal",onLensChange:N=()=>{},chatLensEnabled:k=!1}){const A=C.useRef(null);return C.useLayoutEffect(()=>{var D,T;b&&((T=(D=A.current)==null?void 0:D.querySelector(`[data-win="${b}"]`))==null||T.scrollIntoView({block:"nearest",inline:"nearest"}))},[e,b]),s.jsxDEV("div",{className:"windowbar",children:[s.jsxDEV("div",{className:"windowbar-scroll",ref:A,children:[e.map(D=>{const T=D.id===u;return T&&g.length>1?s.jsxDEV(nF,{window:D,panes:g,paneAgents:i,currentPaneId:d,agent:a??null,onManage:v,...h?{onManagePane:h}:{},onSelectPane:c,..._?{onBeforePaneMapOpen:_}:{},paneSheetOpen:S,openMapFor:j,...y?{onMapOpened:y}:{},...m?{onPaneMapOpenChange:m}:{}},D.id,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:379,columnNumber:15},this):s.jsxDEV(Q7,{window:D,active:T,agent:n[D.id]??null,onSelect:o,onManage:v},D.id,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:398,columnNumber:13},this)}),s.jsxDEV("button",{className:"win-tab win-new",onClick:f,"aria-label":w("windowbar.newWindow"),title:w("windowbar.newWindow"),children:"+"},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:408,columnNumber:9},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:374,columnNumber:7},this),k&&s.jsxDEV(Y7,{value:x,onChange:N},void 0,!1,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:411,columnNumber:27},this)]},void 0,!0,{fileName:"/Users/admin/jly_gh/handmux_private/web/src/components/WindowBar.tsx",lineNumber:373,columnNumber:5},this)}function iF(e){return e.replace(/\r?\n/g,`\r