import{d as e,g as t,m as n,t as r,u as i,y as a}from"./paths-B4IRk3wi.js";import{N as o,p as s}from"./subsystem-BQ1073Mu.js";import{C as c,S as l,g as u,y as d}from"./utils-D1PlBTFH.js";import{$a as f,$l as p,A as m,Bo as h,Br as g,Co as _,Ga as v,Hn as y,Ja as b,Oi as x,Vl as S,Yl as C,Zs as w,_ as T,a as ee,ai as E,as as D,da as O,ds as k,fu as A,go as j,h as M,hs as N,ii as te,jt as ne,ls as re,nc as ie,ou as ae,pu as oe,rs as se,sa as ce,so as le,su as ue}from"./model-selection-p21GBPS6.js";import{Dr as de,Nr as fe,Xt as pe,Zt as me,a as he,i as ge,o as _e,ot as ve}from"./reply-SaDCHPDQ.js";import{_ as ye,a as be,d as P,f as F}from"./agent-scope-DW6ZDCxj.js";import{E as xe}from"./session-key-D3P0tf5P.js";import{t as Se}from"./openclaw-root-D_0Q6--h.js";import{a as I,d as Ce}from"./types.secrets-C-5U96pc.js";import{t as L}from"./command-format-BbDT1tlm.js";import{t as we}from"./env-BI_g1HfG.js";import{n as Te}from"./plugins-1aNlpDX7.js";import{n as Ee,t as R}from"./exec-BdtFni8N.js";import{c as De,n as Oe,r as ke,s as Ae}from"./paths-yLEk_25I.js";import{n as je}from"./model-catalog-CH3Up6he.js";import{n as Me,t as Ne}from"./call-_dlYen_W.js";import{f as Pe,m as Fe,p as Ie}from"./send-BKRZJY2a2.js";import{g as Le}from"./read-only-account-inspect-B52H7IXf.js";import{r as Re,t as ze}from"./wsl-Ok7GaSJ6.js";import{h as Be,n as Ve,p as He,s as Ue}from"./onboard-helpers-lK6pmfqQ.js";import{n as z,r as We,t as Ge}from"./prompt-style-DpAh867d.js";import{i as Ke}from"./memory-cli-DgovXr-y.js";import{a as qe,i as Je}from"./manager-DwWffSpi.js";import{g as Ye,m as Xe,p as Ze,u as Qe}from"./arg-split-DE5RqDHq.js";import{t as $e}from"./skills-status-CId4JgRV.js";import{t as B}from"./note-PBjA39mC.js";import{t as et}from"./channels-status-issues-hU0uOU87.js";import{a as tt,o as nt}from"./daemon-install-plan.shared-DOXDMWJk.js";import{n as V,r as rt,t as it}from"./gateway-install-token-CrvWc2P-.js";import{n as at,t as H}from"./daemon-runtime-DHiDbRuC.js";import{i as ot,u as st}from"./systemd-Dp59-Na4.js";import{a as ct,i as lt,n as U,o as ut,s as dt,t as ft}from"./service-BMP0stI7.js";import{c as pt,i as mt,n as ht,o as gt,r as _t,s as vt,t as yt,u as bt}from"./systemd-hints-Cn_aDxkd.js";import{t as xt}from"./diagnostics-DxEtFsuc.js";import{n as St,t as Ct}from"./inspect-B5RjuBmb.js";import{r as wt}from"./health-B8-MyfNZ.js";import{i as Tt,r as Et}from"./control-ui-assets-jM-MvEQE.js";import{t as Dt}from"./channel-account-context-kX_5d8CX.js";import{t as Ot,u as kt}from"./update-runner-fr326LSr.js";import{n as At}from"./logging-DZNwCl5f.js";import{n as jt}from"./oauth-tls-preflight-OT_XKQho.js";import{n as Mt,r as Nt,t as Pt}from"./doctor-config-flow-DljC8-vs.js";import{t as Ft}from"./systemd-linger-Bjq6egQK.js";import{t as It}from"./health-format-BYfab3lP.js";import{n as Lt}from"./doctor-completion-BPaNn7Aj.js";import W from"node:fs";import G from"node:os";import K from"node:path";import{promisify as Rt}from"node:util";import q from"node:fs/promises";import{execFile as zt}from"node:child_process";import{confirm as Bt,intro as Vt,outro as Ht,select as Ut}from"@clack/prompts";async function Wt(e,t){let n=S({cfg:e,store:C(),provider:`anthropic`,legacyProfileId:`anthropic:default`});return!n.migrated||n.changes.length===0||(B(n.changes.map(e=>`- ${e}`).join(`
`),`Auth profiles`),!await t.confirm({message:`Update Anthropic OAuth profile id in config now?`,initialValue:!0}))?e:n.config}function Gt(e,t){if(!e)return{next:e,changed:!1};let n=!1,r={};for(let[i,a]of Object.entries(e)){let e=a.filter(e=>!t.has(e));e.length!==a.length&&(n=!0),e.length>0&&(r[i]=e)}return{next:Object.keys(r).length>0?r:void 0,changed:n}}function Kt(e,t){let n=e.auth?.profiles,r=e.auth?.order,i=n?{...n}:void 0,a=!1;if(i)for(let e of t)e in i&&(delete i[e],a=!0);let o=Gt(r,t);if(o.changed&&(a=!0),!a)return{next:e,changed:!1};let s=i||o.next?{...e.auth,profiles:i&&Object.keys(i).length>0?i:void 0,order:o.next}:void 0;return{next:{...e,auth:s},changed:!0}}async function qt(e,t){let n=C(void 0,{allowKeychainPrompt:!1}),r=new Set;if((n.profiles[`anthropic:claude-cli`]||e.auth?.profiles?.[`anthropic:claude-cli`])&&r.add(ae),(n.profiles[`openai-codex:codex-cli`]||e.auth?.profiles?.[`openai-codex:codex-cli`])&&r.add(ue),r.size===0)return e;let i=[`Deprecated external CLI auth profiles detected (no longer supported):`];if(r.has(`anthropic:claude-cli`)&&i.push(`- ${ae} (Anthropic): use setup-token → ${L(`openclaw models auth setup-token`)}`),r.has(`openai-codex:codex-cli`)&&i.push(`- ${ue} (OpenAI Codex): use OAuth → ${L(`openclaw models auth login --provider openai-codex`)}`),B(i.join(`
`),`Auth profiles`),!await t.confirmRepair({message:`Remove deprecated CLI auth profiles now?`,initialValue:!0}))return e;await p({updater:e=>{let t=!1;for(let n of r)e.profiles[n]&&(delete e.profiles[n],t=!0),e.usageStats?.[n]&&(delete e.usageStats[n],t=!0);if(e.order)for(let[n,i]of Object.entries(e.order)){let a=i.filter(e=>!r.has(e));a.length!==i.length&&(t=!0,a.length>0?e.order[n]=a:delete e.order[n])}if(e.lastGood)for(let[n,i]of Object.entries(e.lastGood))r.has(i)&&(delete e.lastGood[n],t=!0);return t}});let a=Kt(e,r);return a.changed&&B(Array.from(r.values()).map(e=>`- removed ${e} from config`).join(`
`),`Doctor changes`),a.next}function Jt(e){if(e.kind===`disabled`){if(e.reason===`billing`)return`Top up credits (provider billing) or switch provider.`;if(e.reason===`auth_permanent`||e.reason===`auth`)return`Refresh or replace credentials, then retry.`}return`Wait for cooldown or switch provider.`}function Yt(e){return e.reasonCode===`invalid_expires`?`Invalid token expires metadata. Set a future Unix ms timestamp or remove expires.`:e.provider===`anthropic`&&e.profileId===`anthropic:claude-cli`?`Deprecated profile. Use ${L(`openclaw models auth setup-token`)} or ${L(`openclaw configure`)}.`:e.provider===`openai-codex`&&e.profileId===`openai-codex:codex-cli`?`Deprecated profile. Use ${L(`openclaw models auth login --provider openai-codex`)} or ${L(`openclaw configure`)}.`:`Re-auth via \`${L(`openclaw configure`)}\` or \`${L(`openclaw onboard`)}\`.`}function Xt(e){let t=e.remainingMs===void 0?``:` (${_e(e.remainingMs)})`,n=Yt(e),r=e.reasonCode?` [${e.reasonCode}]`:``;return`- ${e.profileId}: ${e.status}${r}${t}${n?` — ${n}`:``}`}async function Zt(e){let t=C(void 0,{allowKeychainPrompt:e.allowKeychainPrompt}),n=(()=>{let e=Date.now(),n=[];for(let r of Object.keys(t.usageStats??{})){let i=ne(t,r);if(!i||e>=i)continue;let a=t.usageStats?.[r],o=_e(i-e),s=typeof a?.disabledUntil==`number`&&e<a.disabledUntil,c=s?`disabled${a.disabledReason?`:${a.disabledReason}`:``}`:`cooldown`,l=Jt({kind:s?`disabled`:`cooldown`,reason:a?.disabledReason});n.push(`- ${r}: ${c} (${o})${l?` — ${l}`:``}`)}return n})();n.length>0&&B(n.join(`
`),`Auth profile cooldowns`);let r=he({store:t,cfg:e.cfg,warnAfterMs:ge}),i=()=>r.profiles.filter(e=>(e.type===`oauth`||e.type===`token`)&&(e.status===`expired`||e.status===`expiring`||e.status===`missing`)),a=i();if(a.length!==0){if(await e.prompter.confirmRepair({message:`Refresh expiring OAuth tokens now? (static tokens need re-auth)`,initialValue:!0})){let n=a.filter(e=>e.type===`oauth`&&[`expired`,`expiring`,`missing`].includes(e.status)),o=[];for(let r of n)try{await N({cfg:e.cfg,store:t,profileId:r.profileId})}catch(e){o.push(`- ${r.profileId}: ${e instanceof Error?e.message:String(e)}`)}o.length>0&&B(o.join(`
`),`OAuth refresh errors`),r=he({store:C(void 0,{allowKeychainPrompt:!1}),cfg:e.cfg,warnAfterMs:ge}),a=i()}a.length>0&&B(a.map(e=>Xt({profileId:e.profileId,provider:e.provider,status:e.status,reasonCode:e.reasonCode,remainingMs:e.remainingMs})).join(`
`),`Model auth`)}}function J(e){return new Intl.NumberFormat(`en-US`).format(Math.max(0,Math.floor(e)))}function Qt(e,t){return!Number.isFinite(t)||t<=0?`0%`:`${Math.min(100,Math.max(0,Math.round(e/t*100)))}%`}function $t(e){return e.length===0?`unknown`:e.map(e=>e===`per-file-limit`?`max/file`:`max/total`).join(`, `)}async function en(e){let t=P(e,F(e)),n=re(e),r=k(e),{bootstrapFiles:i,contextFiles:a}=await fe({workspaceDir:t,config:e}),o=pe({files:me({bootstrapFiles:i,injectedFiles:a}),bootstrapMaxChars:n,bootstrapTotalMaxChars:r});if(!o.hasTruncation&&o.nearLimitFiles.length===0&&!o.totalNearLimit)return o;let s=[];if(o.hasTruncation){s.push(`Workspace bootstrap files exceed limits and will be truncated:`);for(let e of o.truncatedFiles){let t=Math.max(0,e.rawChars-e.injectedChars);s.push(`- ${e.name}: ${J(e.rawChars)} raw / ${J(e.injectedChars)} injected (${Qt(t,e.rawChars)} truncated; ${$t(e.causes)})`)}}else s.push(`Workspace bootstrap files are near configured limits:`);let c=o.nearLimitFiles.filter(e=>!e.truncated);if(c.length>0)for(let e of c)s.push(`- ${e.name}: ${J(e.rawChars)} chars (${Qt(e.rawChars,n)} of max/file ${J(n)})`);s.push(`Total bootstrap injected chars: ${J(o.totals.injectedChars)} (${Qt(o.totals.injectedChars,r)} of max/total ${J(r)}).`),s.push(`Total bootstrap raw chars (before truncation): ${J(o.totals.rawChars)}.`);let l=o.truncatedFiles.some(e=>e.causes.includes(`per-file-limit`))||o.nearLimitFiles.length>0,u=o.truncatedFiles.some(e=>e.causes.includes(`total-limit`))||o.totalNearLimit;return(l||u)&&s.push(``),l&&s.push("- Tip: tune `agents.defaults.bootstrapMaxChars` for per-file limits."),u&&s.push("- Tip: tune `agents.defaults.bootstrapTotalMaxChars` for total-budget limits."),B(s.join(`
`),`Bootstrap file size`),o}function Y(e,t){return`${e} ${t}${e===1?``:`s`}`}function tn(e){let t=[];return e.jobId&&t.push(`- ${Y(e.jobId,`job`)} still uses legacy \`jobId\``),e.legacyScheduleString&&t.push(`- ${Y(e.legacyScheduleString,`job`)} stores schedule as a bare string`),e.legacyScheduleCron&&t.push(`- ${Y(e.legacyScheduleCron,`job`)} still uses \`schedule.cron\``),e.legacyPayloadKind&&t.push(`- ${Y(e.legacyPayloadKind,`job`)} needs payload kind normalization`),e.legacyPayloadProvider&&t.push(`- ${Y(e.legacyPayloadProvider,`job`)} still uses payload \`provider\` as a delivery alias`),e.legacyTopLevelPayloadFields&&t.push(`- ${Y(e.legacyTopLevelPayloadFields,`job`)} still uses top-level payload fields`),e.legacyTopLevelDeliveryFields&&t.push(`- ${Y(e.legacyTopLevelDeliveryFields,`job`)} still uses top-level delivery fields`),e.legacyDeliveryMode&&t.push(`- ${Y(e.legacyDeliveryMode,`job`)} still uses delivery mode \`deliver\``),t}function X(e){return typeof e==`string`&&e.trim()?e.trim():void 0}function nn(e){let t=!1,n=[];for(let r of e.jobs){if(!(`notify`in r))continue;let i=X(r.name)??X(r.id)??`<unnamed>`;if(r.notify!==!0){delete r.notify,t=!0;continue}let a=r.delivery&&typeof r.delivery==`object`&&!Array.isArray(r.delivery)?r.delivery:null,o=X(a?.mode)?.toLowerCase(),s=X(a?.to);if(o===`webhook`&&s){delete r.notify,t=!0;continue}if((o===void 0||o===`none`||o===`webhook`)&&e.legacyWebhook){r.delivery={...a,mode:`webhook`,to:o===`none`?e.legacyWebhook:s??e.legacyWebhook},delete r.notify,t=!0;continue}if(!e.legacyWebhook){n.push(`Cron job "${i}" still uses legacy notify fallback, but cron.webhook is unset so doctor cannot migrate it automatically.`);continue}n.push(`Cron job "${i}" uses legacy notify fallback alongside delivery mode "${o}". Migrate it manually so webhook delivery does not replace existing announce behavior.`)}return{changed:t,warnings:n}}async function rn(e){let t=Ie(e.cfg.cron?.store),n=(await Pe(t)).jobs??[];if(n.length===0)return;let r=kt(n),i=X(e.cfg.cron?.webhook),a=n.filter(e=>e.notify===!0).length,o=tn(r.issues);if(a>0&&o.push(`- ${Y(a,`job`)} still uses legacy \`notify: true\` webhook fallback`),o.length===0||(B([`Legacy cron job storage detected at ${l(t)}.`,...o,`Repair with ${L(`openclaw doctor --fix`)} to normalize the store before the next scheduler run.`].join(`
`),`Cron`),!await e.prompter.confirm({message:`Repair legacy cron jobs now?`,initialValue:!0})))return;let s=nn({jobs:n,legacyWebhook:i}),c=r.mutated||s.changed;!c&&s.warnings.length===0||(c&&(await Fe(t,{version:1,jobs:n}),B(`Cron store normalized at ${l(t)}.`,`Doctor changes`)),s.warnings.length>0&&B(s.warnings.join(`
`),`Doctor warnings`))}function an(e){return bt(e)}function on(e,t={}){let n=[];if(!e)return n;let r=t.platform??process.platform,i=t.env??process.env,a=(()=>{try{return o().file}catch{return null}})();if(r===`linux`&&yt(e.detail))return n.push(...ht({wsl:Re()})),a&&n.push(`File logs: ${a}`),n;if(e.cachedLabel&&r===`darwin`){let e=Qe(i.OPENCLAW_PROFILE);n.push(`LaunchAgent label cached but plist missing. Clear with: launchctl bootout gui/$UID/${e}`),n.push(`Then reinstall: ${L(`openclaw gateway install`,i)}`)}return e.missingUnit?(n.push(`Service not installed. Run: ${L(`openclaw gateway install`,i)}`),a&&n.push(`File logs: ${a}`),n):(e.status===`stopped`&&(n.push(`Service is loaded but not running (likely exited immediately).`),a&&n.push(`File logs: ${a}`),n.push(...pt({platform:r,env:i,systemdServiceName:Ze(i.OPENCLAW_PROFILE),windowsTaskName:Xe(i.OPENCLAW_PROFILE)}))),n)}async function sn(e){if(process.platform!==`darwin`||!await lt({env:e.env})||await ct({env:e.env})||!await ut(e.env)||(B(`LaunchAgent is listed but not loaded in launchd.`,`${e.title} LaunchAgent`),!await e.prompter.confirmSkipInNonInteractive({message:`Repair ${e.title} LaunchAgent bootstrap now?`,initialValue:!0})))return!1;e.runtime.log(`Bootstrapping ${e.title} LaunchAgent...`);let t=await dt({env:e.env});return t.ok?await ct({env:e.env})?(B(`${e.title} LaunchAgent repaired.`,`${e.title} LaunchAgent`),!0):(e.runtime.error(`${e.title} LaunchAgent still not loaded after repair.`),!1):(e.runtime.error(`${e.title} LaunchAgent bootstrap failed: ${t.detail??`unknown error`}`),!1)}async function cn(e){if(e.healthOk)return;let t=U(),n=!1;try{n=await t.isLoaded({env:process.env})}catch{n=!1}let r;if(n&&(r=await t.readRuntime(process.env).catch(()=>void 0)),process.platform===`darwin`&&e.cfg.gateway?.mode!==`remote`){let i=await sn({env:process.env,title:`Gateway`,runtime:e.runtime,prompter:e.prompter});await sn({env:{...process.env,OPENCLAW_LAUNCHD_LABEL:Ye()},title:`Node`,runtime:e.runtime,prompter:e.prompter}),i&&(n=await t.isLoaded({env:process.env}),n&&(r=await t.readRuntime(process.env).catch(()=>void 0)))}if(e.cfg.gateway?.mode!==`remote`){let t=await ce(i(e.cfg,process.env));if(t.status===`busy`)B(O(t).join(`
`),`Gateway port`);else if(n&&r?.status===`running`){let e=await xt(process.env);e&&B(`Last gateway error: ${e}`,`Gateway`)}}if(!n){if(process.platform===`linux`&&!await ot().catch(()=>!1)){B(ht({wsl:await ze()}).join(`
`),`Gateway`);return}if(B(`Gateway service not installed.`,`Gateway`),e.cfg.gateway?.mode!==`remote`&&await e.prompter.confirmSkipInNonInteractive({message:`Install gateway service now?`,initialValue:!0})){let n=await e.prompter.select({message:`Gateway service runtime`,options:at,initialValue:H},H),r=await it({config:e.cfg,env:process.env});for(let e of r.warnings)B(e,`Gateway`);if(r.unavailableReason){B([`Gateway service install aborted.`,r.unavailableReason,`Fix gateway auth config/token input and rerun doctor.`].join(`
`),`Gateway`);return}let a=i(e.cfg,process.env),{programArguments:o,workingDirectory:s,environment:c}=await V({env:process.env,port:a,runtime:n,warn:(e,t)=>B(e,t),config:e.cfg});try{await t.install({env:process.env,stdout:process.stdout,programArguments:o,workingDirectory:s,environment:c})}catch(e){B(`Gateway service install failed: ${String(e)}`,`Gateway`),B(rt(),`Gateway`)}}return}let a=an(r),o=on(r,{platform:process.platform,env:process.env});if(a||o.length>0){let e=[];a&&e.push(`Runtime: ${a}`),e.push(...o),B(e.join(`
`),`Gateway`)}if(r?.status!==`running`&&await e.prompter.confirmSkipInNonInteractive({message:`Start gateway service now?`,initialValue:!0})){let e=ft(`Gateway`,await t.restart({env:process.env,stdout:process.stdout}));e.scheduled?B(e.message,`Gateway`):await c(1500)}if(process.platform===`darwin`){let e=Qe(process.env.OPENCLAW_PROFILE);B(`LaunchAgent loaded; stopping requires "${L(`openclaw gateway stop`)}" or launchctl bootout gui/$UID/${e}.`,`Gateway`)}if(r?.status===`running`&&await e.prompter.confirmSkipInNonInteractive({message:`Restart gateway service now?`,initialValue:!0})){let n=ft(`Gateway`,await t.restart({env:process.env,stdout:process.stdout}));if(n.scheduled){B(n.message,`Gateway`);return}await c(1500);try{await wt({json:!1,timeoutMs:1e4},e.runtime)}catch(t){String(t).includes(`gateway closed`)?(B(`Gateway not running.`,`Gateway`),B(e.gatewayDetailsMessage,`Gateway connection`)):e.runtime.error(It(t))}}}async function ln(e){let t=Ne({config:e.cfg}),n=typeof e.timeoutMs==`number`&&e.timeoutMs>0?e.timeoutMs:1e4,r=!1;try{await wt({json:!1,timeoutMs:n,config:e.cfg},e.runtime),r=!0}catch(n){String(n).includes(`gateway closed`)?(B(`Gateway not running.`,`Gateway`),B(t.message,`Gateway connection`)):e.runtime.error(It(n))}if(r)try{let e=et(await Me({method:`channels.status`,params:{probe:!0,timeoutMs:5e3},timeoutMs:6e3}));e.length>0&&B(e.map(e=>`- ${e.channel} ${e.accountId}: ${e.message}${e.fix?` (${e.fix})`:``}`).join(`
`),`Channel warnings`)}catch{}return{healthOk:r}}async function un(e){let t=typeof e.timeoutMs==`number`&&e.timeoutMs>0?e.timeoutMs:8e3;try{let n=await Me({method:`doctor.memory.status`,timeoutMs:t,config:e.cfg});return{checked:!0,ready:n.embedding.ok,error:n.embedding.error}}catch(e){return{checked:!0,ready:!1,error:`gateway memory probe unavailable: ${e instanceof Error?e.message:String(e)}`}}}async function dn(e,t){let n=await v({config:e,env:t,value:e.gateway?.auth?.token,path:`gateway.auth.token`,unresolvedReasonStyle:`detailed`,readFallback:()=>le(t)});return n.value?{token:n.value}:n.secretRefConfigured?n.unresolvedRefReason?.includes(`resolved to an empty value`)?{unavailableReason:n.unresolvedRefReason}:{unavailableReason:`gateway.auth.token SecretRef is configured but unresolved (${n.unresolvedRefReason??`unknown reason`}).`}:{}}const fn=Rt(zt);function pn(e){let t=e?.[0];if(t){let e=K.basename(t).toLowerCase();if(e===`bun`||e===`bun.exe`)return`bun`;if(e===`node`||e===`node.exe`)return`node`}return H}function mn(e){if(!e||e.length===0)return null;let t=e.indexOf(`gateway`);return t<=0?null:e[t-1]??null}function hn(e){return K.resolve(e)}function gn(e,t){if(!e.startsWith(t))return null;let n=e.slice(t.length).trim();return n.length>0?n:null}async function _n(e){await fn(`launchctl`,[`bootout`,typeof process.getuid==`function`?`gui/${process.getuid()}`:`gui/501`,e.plistPath]).catch(()=>void 0),await fn(`launchctl`,[`unload`,e.plistPath]).catch(()=>void 0);let t=K.join(G.homedir(),`.Trash`);try{await q.mkdir(t,{recursive:!0})}catch{}try{await q.access(e.plistPath)}catch{return null}let n=K.join(t,`${e.label}-${Date.now()}.plist`);try{return await q.rename(e.plistPath,n),n}catch{return null}}function vn(e){let t=[],n=[],r=[];for(let i of e){if(i.platform===`darwin`){i.scope===`user`?t.push(i):r.push(`${i.label} (${i.scope})`);continue}if(i.platform===`linux`){i.scope===`user`?n.push(i):r.push(`${i.label} (${i.scope})`);continue}r.push(`${i.label} (${i.platform})`)}return{darwinUserServices:t,linuxUserServices:n,failed:r}}async function yn(e){let t=[],n=[];for(let r of e){let e=gn(r.detail,`plist:`);if(!e){n.push(`${r.label} (missing plist path)`);continue}let i=await _n({label:r.label,plistPath:e});t.push(i?`${r.label} -> ${i}`:r.label)}return{removed:t,failed:n}}async function bn(e,t){let n=[],r=[];try{let t=await st({env:process.env,stdout:process.stdout}),i=new Map(t.map(e=>[`${e.name}.service`,e]));for(let t of e){let e=i.get(t.label);if(!e){r.push(`${t.label} (legacy unit name not recognized)`);continue}n.push(`${t.label} -> ${e.unitPath}`)}}catch(n){t.error(`Legacy Linux gateway cleanup failed: ${String(n)}`);for(let t of e)r.push(`${t.label} (linux cleanup failed)`)}return{removed:n,failed:r}}async function xn(t,n,r,a){if(e(process.env)){B(`Nix mode detected; skip service updates.`,`Gateway`);return}if(n===`remote`){B(`Gateway mode is remote; skipped local service audit.`,`Gateway`);return}let o=U(),s=null;try{s=await o.readCommand(process.env)}catch{s=null}if(!s)return;let c=!!Ce({value:t.gateway?.auth?.token,defaults:t.secrets?.defaults}).ref,l=await dn(t,process.env);l.unavailableReason&&B(`Unable to verify gateway service token drift: ${l.unavailableReason}`,`Gateway service config`);let u=c?void 0:l.token,d=await mt({env:process.env,command:s,expectedGatewayToken:u}),f=vt(s);c&&f&&d.issues.push({code:_t.gatewayTokenMismatch,message:`Gateway service OPENCLAW_GATEWAY_TOKEN should be unset when gateway.auth.token is SecretRef-managed`,detail:`service token is stale`,level:`recommended`});let p=gt(d.issues),m=p?await nt({env:process.env}):null,h=m?.supported?m.path:null;if(p&&!h){let e=tt(m);e&&B(e,`Gateway runtime`),B(`System Node 22+ not found. Install via Homebrew/apt/choco and rerun doctor to migrate off Bun/version managers.`,`Gateway runtime`)}let g=i(t,process.env),_=pn(s.programArguments),{programArguments:v}=await V({env:process.env,port:g,runtime:p&&h?`node`:_,nodePath:h??void 0,warn:(e,t)=>B(e,t),config:t}),y=mn(v),b=mn(s.programArguments);if(y&&b&&hn(y)!==hn(b)&&d.issues.push({code:_t.gatewayEntrypointMismatch,message:`Gateway service entrypoint does not match the current install.`,detail:`${b} -> ${y}`,level:`recommended`}),d.issues.length===0)return;B(d.issues.map(e=>e.detail?`- ${e.message} (${e.detail})`:`- ${e.message}`).join(`
`),`Gateway service config`);let x=d.issues.filter(e=>e.level===`aggressive`).length>0;if(x&&!a.shouldForce&&B(`Custom or unexpected service edits detected. Rerun with --force to overwrite.`,`Gateway service config`),!(x?await a.confirmAggressive({message:`Overwrite gateway service config with current defaults now?`,initialValue:!!a.shouldForce}):await a.confirmRepair({message:`Update gateway service config to the recommended defaults now?`,initialValue:!0})))return;let S=vt(s),C=u??S,w=typeof t.gateway?.auth?.token==`string`&&t.gateway.auth.token.trim()||void 0,T=t;if(!c&&!w&&C){let e={...t,gateway:{...t.gateway,auth:{...t.gateway?.auth,mode:t.gateway?.auth?.mode??`token`,token:C}}};try{await ie(e),T=e,B(u?`Persisted gateway.auth.token from environment before reinstalling service.`:`Persisted gateway.auth.token from existing service definition before reinstalling service.`,`Gateway`)}catch(e){r.error(`Failed to persist gateway.auth.token before service repair: ${String(e)}`);return}}let ee=i(T,process.env),E=await V({env:process.env,port:ee,runtime:p&&h?`node`:_,nodePath:h??void 0,warn:(e,t)=>B(e,t),config:T});try{await o.install({env:process.env,stdout:process.stdout,programArguments:E.programArguments,workingDirectory:E.workingDirectory,environment:E.environment})}catch(e){r.error(`Gateway service update failed: ${String(e)}`)}}async function Sn(e,t,n){let r=await Ct(process.env,{deep:e.deep});if(r.length===0)return;B(r.map(e=>`- ${e.label} (${e.scope}, ${e.detail})`).join(`
`),`Other gateway-like services detected`);let i=r.filter(e=>e.legacy===!0);if(i.length>0&&await n.confirmSkipInNonInteractive({message:`Remove legacy gateway services (clawdbot/moltbot) now?`,initialValue:!0})){let e=[],{darwinUserServices:n,linuxUserServices:r,failed:a}=vn(i);if(n.length>0){let t=await yn(n);e.push(...t.removed),a.push(...t.failed)}if(r.length>0){let n=await bn(r,t);e.push(...n.removed),a.push(...n.failed)}e.length>0&&B(e.map(e=>`- ${e}`).join(`
`),`Legacy gateway removed`),a.length>0&&B(a.map(e=>`- ${e}`).join(`
`),`Legacy gateway cleanup skipped`),e.length>0&&t.log(`Legacy gateway services removed. Installing OpenClaw gateway next.`)}let a=St();a.length>0&&B(a.map(e=>`- ${e}`).join(`
`),`Cleanup hints`),B([`Recommendation: run a single gateway per machine for most setups.`,`One gateway supports multiple agents.`,`If you need multiple gateways (e.g., a rescue bot on the same host), isolate ports + config/state (see docs: /gateway#multiple-gateways-same-host).`].join(`
`),`Gateway recommendation`)}function Cn(e){if(!e)return;let t=K.join(e,`pnpm-workspace.yaml`);if(!W.existsSync(t))return;let n=[],r=K.join(e,`node_modules`),i=K.join(r,`.pnpm`),a=K.join(r,`.bin`,`tsx`),o=K.join(e,`src`,`entry.ts`);W.existsSync(r)&&!W.existsSync(i)&&n.push(`- node_modules was not installed by pnpm (missing node_modules/.pnpm). Run: pnpm install`),W.existsSync(K.join(e,`package-lock.json`))&&n.push(`- package-lock.json present in a pnpm workspace. If you ran npm install, remove it and reinstall with pnpm.`),W.existsSync(o)&&!W.existsSync(a)&&n.push(`- tsx binary is missing for source runs. Run: pnpm install`),n.length>0&&B(n.join(`
`),`Install`)}async function wn(e,t){let n=F(e),r=be(e,n),i=qe(e,n),a=Je(i?.remote?.apiKey);if(!i){B(`Memory search is explicitly disabled (enabled: false).`,`Memory search`);return}if(Ke({cfg:e,agentId:n}).backend!==`qmd`){if(i.provider!==`auto`){if(i.provider===`local`){if(Tn(i.local,!0)){if(t?.gatewayMemoryProbe?.checked&&!t.gatewayMemoryProbe.ready){let e=t.gatewayMemoryProbe.error?.trim();B([`Memory search provider is set to "local" and a model path is configured,`,`but the gateway reports local embeddings are not ready.`,e?`Gateway probe: ${e}`:null,``,`Verify: ${L(`openclaw memory status --deep`)}`].filter(Boolean).join(`
`),`Memory search`)}return}B([`Memory search provider is set to "local" but no local model file was found.`,``,`Fix (pick one):`,`- Install node-llama-cpp and set a local model path in config`,`- Switch to a remote provider: ${L(`openclaw config set agents.defaults.memorySearch.provider openai`)}`,``,`Verify: ${L(`openclaw memory status --deep`)}`].join(`
`),`Memory search`);return}if(a||await En(i.provider,e,r))return;if(t?.gatewayMemoryProbe?.checked&&t.gatewayMemoryProbe.ready){B([`Memory search provider is set to "${i.provider}" but the API key was not found in the CLI environment.`,`The running gateway reports memory embeddings are ready for the default agent.`,`Verify: ${L(`openclaw memory status --deep`)}`].join(`
`),`Memory search`);return}let n=On(t?.gatewayMemoryProbe),o=Dn(i.provider);B([`Memory search provider is set to "${i.provider}" but no API key was found.`,`Semantic recall will not work without a valid API key.`,n||null,``,`Fix (pick one):`,`- Set ${o} in your environment`,`- Configure credentials: ${L(`openclaw configure --section model`)}`,`- To disable: ${L(`openclaw config set agents.defaults.memorySearch.enabled false`)}`,``,`Verify: ${L(`openclaw memory status --deep`)}`].join(`
`),`Memory search`);return}if(!Tn(i.local)){for(let t of[`openai`,`gemini`,`voyage`,`mistral`])if(a||await En(t,e,r))return;if(t?.gatewayMemoryProbe?.checked&&t.gatewayMemoryProbe.ready){B([`Memory search provider is set to "auto" but the API key was not found in the CLI environment.`,`The running gateway reports memory embeddings are ready for the default agent.`,`Verify: ${L(`openclaw memory status --deep`)}`].join(`
`),`Memory search`);return}B([`Memory search is enabled but no embedding provider is configured.`,`Semantic recall will not work without an embedding provider.`,On(t?.gatewayMemoryProbe)||null,``,`Fix (pick one):`,`- Set OPENAI_API_KEY, GEMINI_API_KEY, VOYAGE_API_KEY, or MISTRAL_API_KEY in your environment`,`- Configure credentials: ${L(`openclaw configure --section model`)}`,`- For local embeddings: configure agents.defaults.memorySearch.provider and local model path`,`- To disable: ${L(`openclaw config set agents.defaults.memorySearch.enabled false`)}`,``,`Verify: ${L(`openclaw memory status --deep`)}`].join(`
`),`Memory search`)}}}function Tn(e,t=!1){let n=e.modelPath?.trim()||(t?`hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf`:void 0);if(!n)return!1;if(/^(hf:|https?:)/i.test(n))return!0;let r=d(n);try{return W.statSync(r).isFile()}catch{return!1}}async function En(e,t,n){let r=e===`gemini`?`google`:e;try{return await m({provider:r,cfg:t,agentDir:n}),!0}catch{return!1}}function Dn(e){switch(e){case`openai`:return`OPENAI_API_KEY`;case`gemini`:return`GEMINI_API_KEY`;case`voyage`:return`VOYAGE_API_KEY`;default:return`${e.toUpperCase()}_API_KEY`}}function On(e){if(!e?.checked||e.ready)return null;let t=e.error?.trim();return t?`Gateway memory probe for default agent is not ready: ${t}`:`Gateway memory probe for default agent is not ready.`}const kn=Rt(zt);async function An(){if(process.platform!==`darwin`)return;let e=u(),t=[K.join(e,`disable-launchagent`)].find(e=>W.existsSync(e));if(!t)return;let n=l(t);B([`- LaunchAgent writes are disabled via ${n}.`,`- To restore default behavior:`,`  rm ${n}`].filter(e=>!!e).join(`
`),`Gateway (macOS)`)}async function jn(e){try{let t=await kn(`/bin/launchctl`,[`getenv`,e],{encoding:`utf8`}),n=String(t.stdout??``).trim();return n.length>0?n:void 0}catch{return}}function Mn(e){let t=e.gateway?.auth?.password,n=e.gateway?.remote?.token,r=e.gateway?.remote?.password;return!!(I(e.gateway?.auth?.token,e.secrets?.defaults)||I(t,e.secrets?.defaults)||I(n,e.secrets?.defaults)||I(r,e.secrets?.defaults))}async function Nn(e,t){if((t?.platform??process.platform)!==`darwin`||!Mn(e))return;let n=t?.getenv??jn,r=[[`CLAWDBOT_GATEWAY_TOKEN`,await n(`CLAWDBOT_GATEWAY_TOKEN`)],[`CLAWDBOT_GATEWAY_PASSWORD`,await n(`CLAWDBOT_GATEWAY_PASSWORD`)]].filter(e=>!!e[1]?.trim());if(r.length>0){let e=[`- Deprecated launchctl environment variables detected (ignored).`,...r.map(([e])=>`- \`${e}\` is set; use \`OPENCLAW_${e.slice(e.indexOf(`_`)+1)}\` instead.`)];(t?.noteFn??B)(e.join(`
`),`Gateway (macOS)`)}let i=[[`OPENCLAW_GATEWAY_TOKEN`,await n(`OPENCLAW_GATEWAY_TOKEN`)]],a=[[`OPENCLAW_GATEWAY_PASSWORD`,await n(`OPENCLAW_GATEWAY_PASSWORD`)]],o=i.find(([,e])=>e?.trim()),s=a.find(([,e])=>e?.trim()),c=o?.[1]?.trim()??``,l=s?.[1]?.trim()??``,u=o?.[0],d=s?.[0];if(!c&&!l)return;let f=[`- launchctl environment overrides detected (can cause confusing unauthorized errors).`,c&&u?`- \`${u}\` is set; it overrides config tokens.`:void 0,l?`- \`${d??`OPENCLAW_GATEWAY_PASSWORD`}\` is set; it overrides config passwords.`:void 0,`- Clear overrides and restart the app/gateway:`,u?`  launchctl unsetenv ${u}`:void 0,d?`  launchctl unsetenv ${d}`:void 0].filter(e=>!!e);(t?.noteFn??B)(f.join(`
`),`Gateway (macOS)`)}function Pn(e=process.env,t){let n=Object.entries(e).filter(([e,t])=>e.startsWith(`CLAWDBOT_`)&&t?.trim()).map(([e])=>e);if(n.length===0)return;let r=[`- Deprecated legacy environment variables detected (ignored).`,`- Use OPENCLAW_* equivalents instead:`,...n.map(e=>`  ${e} -> OPENCLAW_${e.slice(e.indexOf(`_`)+1)}`)];(t?.noteFn??B)(r.join(`
`),`Environment`)}function Fn(e){return typeof e==`string`&&e.trim().length>0}function In(e){let t=e.trim().replace(/\/+$/,``);return t===`/tmp`||t.startsWith(`/tmp/`)||t===`/private/tmp`||t.startsWith(`/private/tmp/`)}function Ln(e=process.env,t){let n=t?.platform??process.platform;if(n===`win32`)return;let r=t?.arch??G.arch(),i=t?.totalMemBytes??G.totalmem();if(!(n===`linux`&&(r===`arm`||r===`arm64`||n===`linux`&&i>0&&i<=8*1024**3)))return;let a=t?.noteFn??B,o=e.NODE_COMPILE_CACHE?.trim()??``,s=e.NODE_DISABLE_COMPILE_CACHE?.trim()??``,c=e.OPENCLAW_NO_RESPAWN?.trim()??``,l=[];if(o?In(o)&&l.push(`- NODE_COMPILE_CACHE points to /tmp; use /var/tmp so cache survives reboots and warms startup reliably.`):l.push(`- NODE_COMPILE_CACHE is not set; repeated CLI runs can be slower on small hosts (Pi/VM).`),Fn(s)&&l.push(`- NODE_DISABLE_COMPILE_CACHE is set; startup compile cache is disabled.`),c!==`1`&&l.push(`- OPENCLAW_NO_RESPAWN is not set to 1; set it to avoid extra startup overhead from self-respawn.`),l.length===0)return;let u=[`- Suggested env for low-power hosts:`,`  export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache`,`  mkdir -p /var/tmp/openclaw-compile-cache`,`  export OPENCLAW_NO_RESPAWN=1`,Fn(s)?`  unset NODE_DISABLE_COMPILE_CACHE`:void 0].filter(e=>!!e);a([...l,...u].join(`
`),`Startup optimization`)}function Rn(e){let t=e.options.yes===!0,n=e.options.nonInteractive===!0,r=e.options.repair===!0||t,i=e.options.force===!0,a=!!process.stdin.isTTY,o=n||!a&&!t,s=a&&!t&&!o,c=async t=>o?!1:r?!0:s?Ue(await Bt({...t,message:z(t.message)}),e.runtime):!!(t.initialValue??!1);return{confirm:c,confirmRepair:async e=>o?!1:c(e),confirmAggressive:async t=>o?!1:r&&i?!0:r&&!i?!1:s?Ue(await Bt({...t,message:z(t.message)}),e.runtime):!!(t.initialValue??!1),confirmSkipInNonInteractive:async e=>o?!1:r?!0:c(e),select:async(t,n)=>!s||r?n:Ue(await Ut({...t,message:z(t.message),options:t.options.map(e=>e.hint===void 0?e:{...e,hint:Ge(e.hint)})}),e.runtime),shouldRepair:r,shouldForce:i}}function zn(e){let t=new Set;t.add(process.cwd());let n=process.argv[1];if(n){let e=K.resolve(n);t.add(K.resolve(K.dirname(e),`..`)),t.add(K.resolve(K.dirname(e)))}for(let n of t){let t=K.join(n,e);if(W.existsSync(t))return{scriptPath:t,cwd:n}}return null}async function Bn(e,t){let n=zn(e);if(!n)return B(`Unable to locate ${e}. Run it from the repo root.`,`Sandbox`),!1;t.log(`Running ${e}...`);let r=await R([`bash`,n.scriptPath],{timeoutMs:1200*1e3,cwd:n.cwd});return r.code===0?(t.log(`Completed ${e}.`),!0):(t.error(`Failed running ${e}: ${r.stderr.trim()||r.stdout.trim()||`unknown error`}`),!1)}async function Vn(){try{return await Ee(`docker`,[`version`,`--format`,`{{.Server.Version}}`],{timeoutMs:5e3}),!0}catch{return!1}}async function Hn(e){try{return await Ee(`docker`,[`image`,`inspect`,e],{timeoutMs:5e3}),!0}catch(e){let t=e?.stderr||e?.message||``;if(String(t).includes(`No such image`))return!1;throw e}}function Un(e){return e.agents?.defaults?.sandbox?.docker?.image?.trim()||D}function Wn(e){return e.agents?.defaults?.sandbox?.browser?.image?.trim()||se}function Gn(e,t){return{...e,agents:{...e.agents,defaults:{...e.agents?.defaults,sandbox:{...e.agents?.defaults?.sandbox,docker:{...e.agents?.defaults?.sandbox?.docker,image:t}}}}}}function Kn(e,t){return{...e,agents:{...e.agents,defaults:{...e.agents?.defaults,sandbox:{...e.agents?.defaults?.sandbox,browser:{...e.agents?.defaults?.sandbox?.browser,image:t}}}}}}async function qn(e,t,n){if(await Hn(e.image))return;let r=e.buildScript?`Build it with ${e.buildScript}.`:`Build or pull it first.`;B(`Sandbox ${e.kind} image missing: ${e.image}. ${r}`,`Sandbox`),e.buildScript&&await n.confirmSkipInNonInteractive({message:`Build ${e.kind} sandbox image now?`,initialValue:!0})&&await Bn(e.buildScript,t)}async function Jn(e,t,n){let r=e.agents?.defaults?.sandbox,i=r?.mode??`off`;if(!r||i===`off`)return e;if(!await Vn())return B([`Sandbox mode is enabled (mode: "${i}") but Docker is not available.`,`Docker is required for sandbox mode to function.`,`Isolated sessions (cron jobs, sub-agents) will fail without Docker.`,``,`Options:`,`- Install Docker and restart the gateway`,`- Disable sandbox mode: openclaw config set agents.defaults.sandbox.mode off`].join(`
`),`Sandbox`),e;let a=e,o=[],s=Un(e);return await qn({kind:`base`,image:s,buildScript:s===`openclaw-sandbox-common:bookworm-slim`?`scripts/sandbox-common-setup.sh`:s===`openclaw-sandbox:bookworm-slim`?`scripts/sandbox-setup.sh`:void 0,updateConfig:e=>{a=Gn(a,e),o.push(`Updated agents.defaults.sandbox.docker.image → ${e}`)}},t,n),r.browser?.enabled&&await qn({kind:`browser`,image:Wn(e),buildScript:`scripts/sandbox-browser-setup.sh`,updateConfig:e=>{a=Kn(a,e),o.push(`Updated agents.defaults.sandbox.browser.image → ${e}`)}},t,n),o.length>0&&B(o.join(`
`),`Doctor changes`),a}function Yn(e){let t=e.agents?.defaults?.sandbox,n=Array.isArray(e.agents?.list)?e.agents.list:[],r=[];for(let e of n){let n=e.id,i=e.sandbox;if(!i||h({scope:i.scope??t?.scope,perSession:i.perSession??t?.perSession})!==`shared`)continue;let a=[];i.docker&&Object.keys(i.docker).length>0&&a.push(`docker`),i.browser&&Object.keys(i.browser).length>0&&a.push(`browser`),i.prune&&Object.keys(i.prune).length>0&&a.push(`prune`),a.length!==0&&r.push([`- agents.list (id "${n}") sandbox ${a.join(`/`)} overrides ignored.`,`  scope resolves to "shared".`].join(`
`))}r.length>0&&B(r.join(`
`),`Sandbox`)}function Xn(e){let t=[],n=e=>{let n=e.heartbeat;!n||n.target===void 0||n.target===`none`||n.directPolicy===void 0&&t.push(`- ${e.label}: heartbeat delivery is configured while ${e.pathHint} is unset.`,`  Heartbeat now allows direct/DM targets by default. Set it explicitly to "allow" or "block" to pin upgrade behavior.`)};n({label:`Heartbeat defaults`,heartbeat:e.agents?.defaults?.heartbeat,pathHint:`agents.defaults.heartbeat.directPolicy`});for(let t of e.agents?.list??[])n({label:`Heartbeat agent "${t.id}"`,heartbeat:t.heartbeat,pathHint:`heartbeat.directPolicy for agent "${t.id}"`});return t}async function Zn(e){let t=[],n=`- Run: ${L(`openclaw security audit --deep`)}`;e.approvals?.exec?.enabled===!1&&t.push(`- Note: approvals.exec.enabled=false disables approval forwarding only.`,`  Host exec gating still comes from ~/.qbotclaw/exec-approvals.json.`,`  Check local policy with: ${L(`openclaw approvals get --gateway`)}`),t.push(...Xn(e));let r=e.gateway?.bind??`loopback`,i=e.gateway?.customBindHost?.trim(),a=[`auto`,`lan`,`loopback`,`custom`,`tailnet`].includes(r)?r:void 0,o=a?await _(a,i):`0.0.0.0`,s=!j(o),c=f({authConfig:e.gateway?.auth,env:process.env,tailscaleMode:e.gateway?.tailscale?.mode??`off`}),l=c.token?.trim()??``,u=c.password?.trim()??``,d=l.length>0||I(e.gateway?.auth?.token,e.secrets?.defaults),p=u.length>0||I(e.gateway?.auth?.password,e.secrets?.defaults),m=c.mode===`token`&&d||c.mode===`password`&&p,h=`"${r}" (${o})`,g=[`  Safer remote access: keep bind loopback and use Tailscale Serve/Funnel or an SSH tunnel.`,`  Example tunnel: ssh -N -L 18789:127.0.0.1:18789 user@gateway-host`,`  Docs: https://docs.openclaw.ai/gateway/remote`];if(s)if(m)t.push(`- WARNING: Gateway bound to ${h} (network-accessible).`,`  Ensure your auth credentials are strong and not exposed.`,...g);else{let e=c.mode===`password`?[`  Fix: ${L(`openclaw configure`)} to set a password`,`  Or switch to token: ${L(`openclaw config set gateway.auth.mode token`)}`]:[`  Fix: ${L(`openclaw doctor --fix`)} to generate a token`,`  Or set token directly: ${L(`openclaw config set gateway.auth.mode token`)}`];t.push(`- CRITICAL: Gateway bound to ${h} without authentication.`,`  Anyone on your network (or internet if port-forwarded) can fully control your agent.`,`  Fix: ${L(`openclaw config set gateway.bind loopback`)}`,...g,...e)}let v=async n=>{let r=n.dmPolicy,i=n.policyPath??`${n.allowFromPath}policy`,{hasWildcard:a,allowCount:o,isMultiUserDm:s}=await Le({provider:n.provider,accountId:n.accountId,allowFrom:n.allowFrom,normalizeEntry:n.normalizeEntry}),c=e.session?.dmScope??`main`;if(r===`open`){let e=`${n.allowFromPath}allowFrom`;t.push(`- ${n.label} DMs: OPEN (${i}="open"). Anyone can DM it.`),a||t.push(`- ${n.label} DMs: config invalid — "open" requires ${e} to include "*".`)}if(r===`disabled`){t.push(`- ${n.label} DMs: disabled (${i}="disabled").`);return}r!==`open`&&o===0&&(t.push(`- ${n.label} DMs: locked (${i}="${r}") with no allowlist; unknown senders will be blocked / get a pairing code.`),t.push(`  ${n.approveHint}`)),c===`main`&&s&&t.push(`- ${n.label} DMs: multiple senders share the main session; run: `+L(`openclaw config set session.dmScope "per-channel-peer"`)+` (or "per-account-channel-peer" for multi-account channels) to isolate sessions.`)};for(let n of Te()){if(!n.security)continue;let{defaultAccountId:r,account:i,enabled:a,configured:o}=await Dt(n,e);if(!a||!o)continue;let s=n.security.resolveDmPolicy?.({cfg:e,accountId:r,account:i});if(s&&await v({label:n.meta.label??n.id,provider:n.id,accountId:r,dmPolicy:s.policy,allowFrom:s.allowFrom,policyPath:s.policyPath,allowFromPath:s.allowFromPath,approveHint:s.approveHint,normalizeEntry:s.normalizeEntry}),n.security.collectWarnings){let a=await n.security.collectWarnings({cfg:e,accountId:r,account:i});a?.length&&t.push(...a)}}let y=t.length>0?t:[`- No channel security warnings detected.`];y.push(n),B(y.join(`
`),`Security`)}function Qn(e){if(e===null)return`unknown`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60),r=t%60;return n<60?`${n}m${r}s`:`${Math.floor(n/60)}h${n%60}m`}function $n(e){let t=e.pid===null?`pid=missing`:`pid=${e.pid} (${e.pidAlive?`alive`:`dead`})`,n=`age=${Qn(e.ageMs)}`,r=e.stale?`stale=yes (${e.staleReasons.join(`, `)||`unknown`})`:`stale=no`,i=e.removed?` [removed]`:``;return`- ${l(e.lockPath)} ${t} ${n} ${r}${i}`}async function er(e){let n=e?.shouldRepair===!0,r=e?.staleMs??18e5,i=[];try{i=await de(t(process.env))}catch(e){B(`- Failed to inspect session lock files: ${String(e)}`,`Session locks`);return}if(i.length===0)return;let a=[];for(let e of i){let t=await x({sessionsDir:e,staleMs:r,removeStale:n});a.push(...t.locks)}if(a.length===0)return;let o=a.filter(e=>e.stale).length,s=a.filter(e=>e.removed).length,c=[`- Found ${a.length} session lock file${a.length===1?``:`s`}.`,...a.toSorted((e,t)=>e.lockPath.localeCompare(t.lockPath)).map($n)];o>0&&!n&&(c.push(`- ${o} lock file${o===1?` is`:`s are`} stale.`),c.push(`- Run "openclaw doctor --fix" to remove stale lock files automatically.`)),n&&s>0&&c.push(`- Removed ${s} stale session lock file${s===1?``:`s`}.`),B(c.join(`
`),`Session locks`)}function Z(e){try{return W.existsSync(e)&&W.statSync(e).isDirectory()}catch{return!1}}function tr(e){try{return W.existsSync(e)&&W.statSync(e).isFile()}catch{return!1}}function nr(e){try{return W.accessSync(e,W.constants.W_OK),!0}catch{return!1}}function rr(e){try{return W.mkdirSync(e,{recursive:!0}),{ok:!0}}catch(e){return{ok:!1,error:String(e)}}}function ir(e){let t=typeof process.getuid==`function`?process.getuid():null,n=typeof process.getgid==`function`?process.getgid():null;try{let r=W.statSync(e);if(t!==null&&r.uid!==t)return`Owner mismatch (uid ${r.uid}). Run: sudo chown -R $USER "${e}"`;if(n!==null&&r.gid!==n)return`Group mismatch (gid ${r.gid}). If access fails, run: sudo chown -R $USER "${e}"`}catch{return null}return null}function ar(e){return e&511|448}function or(e){try{let t=W.readFileSync(e,`utf-8`);if(!t)return 0;let n=0;for(let e=0;e<t.length;e+=1)t[e]===`
`&&(n+=1);return t.endsWith(`
`)||(n+=1),n}catch{return 0}}function sr(e){let t=K.resolve(e),n=process.platform===`darwin`?[`/Users`]:process.platform===`linux`?[`/home`]:[],r=[];for(let e of n){let n=[];try{n=W.readdirSync(e,{withFileTypes:!0})}catch{continue}for(let i of n){if(!i.isDirectory()||i.name.startsWith(`.`))continue;let n=[`.qbotclaw`].map(t=>K.resolve(e,i.name,t));for(let e of n)e!==t&&Z(e)&&r.push(e)}}return r}function cr(e,t){let n=K.resolve(e),r=K.resolve(t),i=K.parse(r).root;return r===i?n.startsWith(i):n===r||n.startsWith(`${r}${K.sep}`)}function lr(e){try{return W.realpathSync(e)}catch{return null}}function ur(e){return e.replace(/\\([0-7]{3})/g,(e,t)=>String.fromCharCode(Number.parseInt(t,8)))}function dr(e){let t=``;for(let n of e){if(n===`\x1B`){t+=`\\x1b`;continue}if(n===`\r`){t+=`\\r`;continue}if(n===`
`){t+=`\\n`;continue}if(n===`	`){t+=`\\t`;continue}let e=n.charCodeAt(0);if(e>=0&&e<=8||e===11||e===12||e>=14&&e<=31){t+=`\\x${e.toString(16).padStart(2,`0`)}`;continue}if(e===127){t+=`\\x7f`;continue}t+=n}return t}function fr(e){let t=[];for(let n of e.split(`
`)){let e=n.trim();if(!e)continue;let r=e.indexOf(` - `);if(r===-1)continue;let i=e.slice(0,r),a=e.slice(r+3),o=i.split(` `),s=a.split(` `);o.length<5||s.length<2||t.push({mountPoint:ur(o[4]),fsType:s[0],source:ur(s[1])})}return t}function pr(e,t,n){let r=n.resolve(e),i=n.resolve(t),a=n.parse(i).root;return i===a?r.startsWith(a):r===i||r.startsWith(`${i}${n.sep}`)}function mr(e,t,n){let r=n.resolve(e),i=null;for(let e of t)pr(r,e.mountPoint,n)&&(!i||n.resolve(e.mountPoint).length>n.resolve(i.mountPoint).length)&&(i=e);return i}function hr(e,t){let n=t.basename(e);return/^mmcblk\d+(?:p\d+)?$/.test(n)}function gr(){try{return W.readFileSync(`/proc/self/mountinfo`,`utf8`)}catch{return null}}function _r(e,t){if((t?.platform??process.platform)!==`linux`)return null;let n=K.posix,r=(t?.resolveRealPath??lr)(e)??n.resolve(e),i=t?.mountInfo??gr();if(!i)return null;let a=mr(r,fr(i),n);if(!a)return null;let o=[a.source];if(a.source.startsWith(`/dev/`)){let e=(t?.resolveDeviceRealPath??lr)(a.source);e&&o.push(n.resolve(e))}return o.some(e=>hr(e,n))?{path:n.resolve(r),mountPoint:n.resolve(a.mountPoint),fsType:a.fsType,source:a.source}:null}function vr(e,t){let n=t.mountPoint===`/`?`/`:l(t.mountPoint);return[`- State directory appears to be on SD/eMMC storage (${e}; device ${dr(t.source)}, fs ${dr(t.fsType)}, mount ${dr(n)}).`,`- SD/eMMC media can be slower for random I/O and wear faster under session/log churn.`,`- For better startup and state durability, prefer SSD/NVMe (or USB SSD on Raspberry Pi) for OPENCLAW_STATE_DIR.`].join(`
`)}function yr(e,t){if((t?.platform??process.platform)!==`darwin`)return null;let n=t?.homedir??G.homedir(),r=[{storage:`iCloud Drive`,root:K.join(n,`Library`,`Mobile Documents`,`com~apple~CloudDocs`)},{storage:`CloudStorage provider`,root:K.join(n,`Library`,`CloudStorage`)}],i=(t?.resolveRealPath??lr)(e),a=i?[K.resolve(i)]:[K.resolve(e)];for(let e of a)for(let{storage:t,root:n}of r)if(cr(e,n))return{path:e,storage:t};return null}function Q(e){return typeof e==`object`&&!!e}function br(e){return typeof e==`string`&&e.trim().toLowerCase()===`pairing`}function xr(e){if(!Q(e))return!1;if(br(e.dmPolicy)||Q(e.dm)&&br(e.dm.policy))return!0;if(!Q(e.accounts))return!1;for(let t of Object.values(e.accounts))if(xr(t))return!0;return!1}function Sr(e){let t=e.trim().toLowerCase();if(!t)return!1;let n=xe(t)?.rest??t;return/^[^:]+:slash:[^:]+(?:$|:)/.test(n)}function Cr(e,t){if(t.OPENCLAW_OAUTH_DIR?.trim())return!0;let n=e.channels;if(!Q(n))return!1;if(Q(n.whatsapp))return!0;for(let[e,t]of Object.entries(n))if(!(e===`defaults`||e===`modelByChannel`)&&xr(t))return!0;return!1}async function wr(e,r,i){let o=[],s=[],c=process.env,u=()=>a(c,G.homedir),d=t(c,u),f=K.join(u(),`.qbotclaw`),p=n(c,d),m=F(e),h=Ae(m,c,u),_=De(e.session?.store,{agentId:m}),v=K.dirname(_),b=K.resolve(_),x=l(d),S=l(p),C=l(h),w=l(v),T=i?l(i):void 0,ee=Cr(e,c),D=yr(d),O=_r(d);D&&o.push([`- State directory is under macOS cloud-synced storage (${x}; ${D.storage}).`,`- This can cause slow I/O and sync/lock races for sessions and credentials.`,`- Prefer a local non-synced state dir (for example: ~/.qbotclaw).`,`  Set locally: OPENCLAW_STATE_DIR=~/.qbotclaw ${L(`openclaw doctor`)}`].join(`
`)),O&&o.push(vr(x,O));let k=Z(d);if(!k&&(o.push(`- CRITICAL: state directory missing (${x}). Sessions, credentials, logs, and config are stored there.`),e.gateway?.mode===`remote`&&o.push(`- Gateway is in remote mode; run doctor on the remote host where the gateway runs.`),await r.confirmSkipInNonInteractive({message:`Create ${x} now?`,initialValue:!1}))){let e=rr(d);e.ok?(s.push(`- Created ${x}`),k=!0):o.push(`- Failed to create ${x}: ${e.error}`)}if(k&&!nr(d)){o.push(`- State directory not writable (${x}).`);let e=ir(d);if(e&&o.push(`  ${e}`),await r.confirmSkipInNonInteractive({message:`Repair permissions on ${x}?`,initialValue:!0}))try{let e=ar(W.statSync(d).mode);W.chmodSync(d,e),s.push(`- Repaired permissions on ${x}`)}catch(e){o.push(`- Failed to repair ${x}: ${String(e)}`)}}if(k&&process.platform!==`win32`)try{let e=W.lstatSync(d),t=e.isSymbolicLink(),n=t?W.statSync(d):e;!(t?W.realpathSync(d):d).startsWith(`/nix/store/`)&&n.mode&63&&(o.push(`- State directory permissions are too open (${x}). Recommend chmod 700.`),await r.confirmSkipInNonInteractive({message:`Tighten permissions on ${x} to 700?`,initialValue:!0})&&(W.chmodSync(d,448),s.push(`- Tightened permissions on ${x} to 700`)))}catch(e){o.push(`- Failed to read ${x} permissions: ${String(e)}`)}if(i&&tr(i)&&process.platform!==`win32`)try{let e=W.lstatSync(i),t=e.isSymbolicLink(),n=t?W.statSync(i):e;!(t?W.realpathSync(i):i).startsWith(`/nix/store/`)&&n.mode&63&&(o.push(`- Config file is group/world readable (${T??i}). Recommend chmod 600.`),await r.confirmSkipInNonInteractive({message:`Tighten permissions on ${T??i} to 600?`,initialValue:!0})&&(W.chmodSync(i,384),s.push(`- Tightened permissions on ${T??i} to 600`)))}catch(e){o.push(`- Failed to read config permissions (${T??i}): ${String(e)}`)}if(k){let e=new Map;e.set(h,`Sessions dir`),e.set(v,`Session store dir`),ee?e.set(p,`OAuth dir`):Z(p)||o.push(`- OAuth dir not present (${S}). Skipping create because no WhatsApp/pairing channel config is active.`);let t=e=>e===h?C:e===v?w:e===p?S:l(e);for(let[n,i]of e){let e=t(n);if(!Z(n)){if(o.push(`- CRITICAL: ${i} missing (${e}).`),await r.confirmSkipInNonInteractive({message:`Create ${i} at ${e}?`,initialValue:!0})){let t=rr(n);t.ok?s.push(`- Created ${i}: ${e}`):o.push(`- Failed to create ${e}: ${t.error}`)}continue}if(!nr(n)){o.push(`- ${i} not writable (${e}).`);let t=ir(n);if(t&&o.push(`  ${t}`),await r.confirmSkipInNonInteractive({message:`Repair permissions on ${i}?`,initialValue:!0}))try{let t=ar(W.statSync(n).mode);W.chmodSync(n,t),s.push(`- Repaired permissions on ${i}: ${e}`)}catch(t){o.push(`- Failed to repair ${e}: ${String(t)}`)}}}}let A=new Set;K.resolve(d)!==K.resolve(f)&&Z(f)&&A.add(f);for(let e of sr(d))A.add(e);A.size>0&&o.push([`- Multiple state directories detected. This can split session history.`,...Array.from(A).map(e=>`  - ${l(e)}`),`  Active state dir: ${x}`].join(`
`));let j=y(_),M=ke({agentId:m,storePath:_}),N=Object.entries(j).filter(([,e])=>e&&typeof e==`object`);if(N.length>0){let t=N.slice().toSorted((e,t)=>{let n=typeof e[1].updatedAt==`number`?e[1].updatedAt:0;return(typeof t[1].updatedAt==`number`?t[1].updatedAt:0)-n}).slice(0,5).filter(([e])=>!Sr(e)),n=t.filter(([,e])=>{let t=e.sessionId;return t?!tr(Oe(t,e,M)):!1});n.length>0&&o.push([`- ${n.length}/${t.length} recent sessions are missing transcripts.`,`  Verify sessions in store: ${L(`openclaw sessions --store "${b}"`)}`,`  Preview cleanup impact: ${L(`openclaw sessions cleanup --store "${b}" --dry-run`)}`,`  Prune missing entries: ${L(`openclaw sessions cleanup --store "${b}" --enforce --fix-missing`)}`].join(`
`));let r=j[g(e)];if(r?.sessionId){let e=Oe(r.sessionId,r,M);if(!tr(e))o.push(`- Main session transcript missing (${l(e)}). History will appear to reset.`);else{let t=or(e);t<=1&&o.push(`- Main session transcript has only ${t} line. Session history may not be appending.`)}}}if(Z(h)){let e=new Set;for(let[,t]of N)if(t?.sessionId)try{e.add(K.resolve(Oe(t.sessionId,t,M)))}catch{}let t=W.readdirSync(h,{withFileTypes:!0}).filter(e=>e.isFile()&&E(e.name)).map(e=>K.resolve(K.join(h,e.name))).filter(t=>!e.has(t));if(t.length>0&&(o.push(`- Found ${t.length} orphan transcript file(s) in ${C}. They are not referenced by sessions.json and can consume disk over time.`),await r.confirmSkipInNonInteractive({message:`Archive ${t.length} orphan transcript file(s) in ${C}?`,initialValue:!1}))){let e=0,n=te();for(let r of t){let t=`${r}.deleted.${n}`;try{W.renameSync(r,t),e+=1}catch(e){o.push(`- Failed to archive orphan transcript ${l(r)}: ${String(e)}`)}}e>0&&s.push(`- Archived ${e} orphan transcript file(s) in ${C}`)}}o.length>0&&B(o.join(`
`),`State integrity`),s.length>0&&B(s.join(`
`),`Doctor changes`)}function Tr(e){if(!Z(e))return;let t=K.join(e,`.git`);W.existsSync(t)||B([`- Tip: back up the workspace in a private git repo (GitHub or GitLab).`,`- Keep ~/.qbotclaw out of git; it contains credentials and session history.`,`- Details: /concepts/agent-workspace#git-backup-recommended`].join(`
`),`Workspace`)}async function Er(e,t){let n=await Se({moduleUrl:import.meta.url,argv1:process.argv[1],cwd:process.cwd()});if(!n)return;let r=K.join(n,`src/gateway/protocol/schema.ts`),i=(await Et({root:n,argv1:process.argv[1]})).indexPath??Tt(n);try{let[e,a]=await Promise.all([q.stat(r).catch(()=>null),q.stat(i).catch(()=>null)]);if(e&&!a){B([`- Control UI assets are missing.`,`- Run: pnpm ui:build`].join(`
`),`UI`);let e=K.join(n,`ui/package.json`);if(!await q.stat(e).catch(()=>null)){B(`Skipping UI build: ui/ sources not present.`,`UI`);return}if(await t.confirmRepair({message:`Build Control UI assets now?`,initialValue:!0})){B(`Building Control UI assets... (this may take a moment)`,`UI`);let e=K.join(n,`scripts/ui.js`),t=await R([process.execPath,e,`build`],{cwd:n,timeoutMs:12e4,env:{...process.env,FORCE_COLOR:`1`}});t.code===0?B(`UI build complete.`,`UI`):B([`UI build failed (exit ${t.code??`unknown`}).`,t.stderr.trim()?t.stderr.trim():null].filter(Boolean).join(`
`),`UI`)}return}if(!e||!a)return;if(e.mtime>a.mtime){let e=await R([`git`,`-C`,n,`log`,`--since=${a.mtime.toISOString()}`,`--format=%h %s`,`src/gateway/protocol/schema.ts`],{timeoutMs:5e3}).catch(()=>null);if(e&&e.code===0&&e.stdout.trim()&&(B(`UI assets are older than the protocol schema.\nFunctional changes since last build:\n${e.stdout.trim().split(`
`).map(e=>`- ${e}`).join(`
`)}`,`UI Freshness`),await t.confirmAggressive({message:`Rebuild UI now? (Detected protocol mismatch requiring update)`,initialValue:!0}))){let e=K.join(n,`ui/package.json`);if(!await q.stat(e).catch(()=>null)){B(`Skipping UI rebuild: ui/ sources not present.`,`UI`);return}B(`Rebuilding stale UI assets... (this may take a moment)`,`UI`);let t=K.join(n,`scripts/ui.js`),r=await R([process.execPath,t,`build`],{cwd:n,timeoutMs:12e4,env:{...process.env,FORCE_COLOR:`1`}});r.code===0?B(`UI rebuild complete.`,`UI`):B([`UI rebuild failed (exit ${r.code??`unknown`}).`,r.stderr.trim()?r.stderr.trim():null].filter(Boolean).join(`
`),`UI`)}}}catch{}}async function Dr(e){let t=await R([`git`,`-C`,e,`rev-parse`,`--show-toplevel`],{timeoutMs:5e3}).catch(()=>null);return t?t.code===0?t.stdout.trim()===e?`git`:`not-git`:t.stderr.toLowerCase().includes(`not a git repository`)?`not-git`:`unknown`:`unknown`}async function Or(e){if(!(!we(process.env.OPENCLAW_UPDATE_IN_PROGRESS)&&e.options.nonInteractive!==!0&&e.options.yes!==!0&&e.options.repair!==!0&&process.stdin.isTTY)||!e.root)return{updated:!1};let t=await Dr(e.root);if(t===`git`){if(!await e.confirm({message:`Update OpenClaw from git before running doctor?`,initialValue:!0}))return{updated:!1};B(`Running update (fetch/rebase/build/ui:build/doctor)…`,`Update`);let t=await Ot({cwd:e.root,argv1:process.argv[1]});return B([`Status: ${t.status}`,`Mode: ${t.mode}`,t.root?`Root: ${t.root}`:null,t.reason?`Reason: ${t.reason}`:null].filter(Boolean).join(`
`),`Update result`),t.status===`ok`?(e.outro(`Update completed (doctor already ran as part of the update).`),{updated:!0,handled:!0}):{updated:!0,handled:!1}}return t===`not-git`&&B([`This install is not a git checkout.`,`Run \`${L(`openclaw update`)}\` to update via your package manager (npm/pnpm), then rerun doctor.`].join(`
`),`Update`),{updated:!1}}const kr=[`Memory system not found in workspace.`,`Paste this into your agent:`,``,`Install the memory system by applying:`,`https://github.com/openclaw/openclaw/commit/9ffea23f31ca1df5183b25668f8f814bee0fb34e`,`https://github.com/openclaw/openclaw/commit/7d1fee70e76f2f634f1b41fca927ee663914183a`].join(`
`);async function Ar(e){let t=[K.join(e,`MEMORY.md`),K.join(e,`memory.md`)];for(let e of t)try{return await W.promises.access(e),!1}catch{}let n=K.join(e,ye);try{let e=await W.promises.readFile(n,`utf-8`);if(/memory\.md/i.test(e))return!1}catch{}return!0}function jr(e){return{activeWorkspace:K.resolve(e.workspaceDir),legacyDirs:[]}}function Mr(e){return[`Extra workspace directories detected (may contain old agent files):`,...e.legacyDirs.map(e=>`- ${l(e)}`),`Active workspace: ${l(e.activeWorkspace)}`,`If unused, archive or move to Trash.`].join(`
`)}function Nr(e){let t=P(e,F(e)),n=jr({workspaceDir:t});n.legacyDirs.length>0&&B(Mr(n),`Extra workspace`);let r=$e(t,{config:e});B([`Eligible: ${r.skills.filter(e=>e.eligible).length}`,`Missing requirements: ${r.skills.filter(e=>!e.eligible&&!e.disabled&&!e.blockedByAllowlist).length}`,`Blocked by allowlist: ${r.skills.filter(e=>e.blockedByAllowlist).length}`].join(`
`),`Skills status`);let i=ve({config:e,workspaceDir:t,logger:{info:()=>{},warn:()=>{},error:()=>{},debug:()=>{}}});if(i.plugins.length>0){let e=i.plugins.filter(e=>e.status===`loaded`),t=i.plugins.filter(e=>e.status===`disabled`),n=i.plugins.filter(e=>e.status===`error`);B([`Loaded: ${e.length}`,`Disabled: ${t.length}`,`Errors: ${n.length}`,n.length>0?`- ${n.slice(0,10).map(e=>e.id).join(`
- `)}${n.length>10?`
- ...`:``}`:null].filter(e=>!!e).join(`
`),`Plugins`)}return i.diagnostics.length>0&&B(i.diagnostics.map(e=>{let t=e.level.toUpperCase(),n=e.pluginId?` ${e.pluginId}`:``,r=e.source?` (${e.source})`:``;return`- ${t}${n}: ${e.message}${r}`}).join(`
`),`Plugin diagnostics`),{workspaceDir:t}}const Pr=e=>Vt(We(e)??e),Fr=e=>Ht(We(e)??e);function $(e){return e.gateway?.mode===`remote`?`remote`:`local`}async function Ir(e=s,t={}){let n=Rn({runtime:e,options:t});He(e),Pr(`OpenClaw doctor`);let i=await Se({moduleUrl:import.meta.url,argv1:process.argv[1],cwd:process.cwd()});if((await Or({runtime:e,options:t,root:i,confirm:e=>n.confirm(e),outro:Fr})).handled)return;await Er(e,n),Cn(i),Pn(),Ln();let a=await Pt({options:t,confirm:e=>n.confirm(e)}),o=a.cfg,c=structuredClone(o),u=a.sourceConfigValid??!0,d=a.path??r;if(!o.gateway?.mode){let e=[`gateway.mode is unset; gateway start will be blocked.`,`Fix: run ${L(`openclaw configure`)} and set Gateway mode (local/remote).`,`Or set directly: ${L(`openclaw config set gateway.mode local`)}`];W.existsSync(d)||e.push(`Missing config: run ${L(`openclaw setup`)} first.`),B(e.join(`
`),`Gateway`)}$(o)===`local`&&b(o)&&B([`gateway.auth.token and gateway.auth.password are both configured while gateway.auth.mode is unset.`,`Set an explicit mode to avoid ambiguous auth selection and startup/runtime failures.`,`Set token mode: ${L(`openclaw config set gateway.auth.mode token`)}`,`Set password mode: ${L(`openclaw config set gateway.auth.mode password`)}`].join(`
`),`Gateway auth`),o=await Wt(o,n),o=await qt(o,n),await Zt({cfg:o,prompter:n,allowKeychainPrompt:t.nonInteractive!==!0&&!!process.stdin.isTTY});let p=Ne({config:o});if(p.remoteFallbackNote&&B(p.remoteFallbackNote,`Gateway`),$(o)===`local`&&u){let e=Ce({value:o.gateway?.auth?.token,defaults:o.secrets?.defaults}).ref,r=f({authConfig:o.gateway?.auth,tailscaleMode:o.gateway?.tailscale?.mode??`off`});if(r.mode!==`password`&&(r.mode!==`token`||!r.token)){if(e)B([`Gateway token is managed via SecretRef and is currently unavailable.`,`Doctor will not overwrite gateway.auth.token with a plaintext value.`,`Resolve/rotate the external secret source, then rerun doctor.`].join(`
`),`Gateway auth`);else if(B(`Gateway auth is off or missing a token. Token auth is now the recommended default (including loopback).`,`Gateway auth`),t.generateGatewayToken===!0||t.nonInteractive!==!0&&await n.confirmRepair({message:`Generate and configure a gateway token now?`,initialValue:!0})){let e=Be();o={...o,gateway:{...o.gateway,auth:{...o.gateway?.auth,mode:`token`,token:e}}},B(`Gateway token configured.`,`Gateway auth`)}}}let m=await Mt({cfg:o});if(m.preview.length>0&&(B(m.preview.join(`
`),`Legacy state detected`),t.nonInteractive===!0||await n.confirm({message:`Migrate legacy state (sessions/agent/WhatsApp auth) now?`,initialValue:!0}))){let e=await Nt({detected:m});e.changes.length>0&&B(e.changes.join(`
`),`Doctor changes`),e.warnings.length>0&&B(e.warnings.join(`
`),`Doctor warnings`)}if(await wr(o,n,a.path??r),await er({shouldRepair:n.shouldRepair}),await rn({cfg:o,options:t,prompter:n}),o=await Jn(o,e,n),Yn(o),await Sn(t,e,n),await xn(o,$(o),e,n),await An(),await Nn(o),await Zn(o),await jt({cfg:o,deep:t.deep===!0}),o.hooks?.gmail?.model?.trim()){let e=T({cfg:o,defaultProvider:oe});if(!e)B(`- hooks.gmail.model "${o.hooks.gmail.model}" could not be resolved`,`Hooks`);else{let{provider:t,model:n}=M({cfg:o,defaultProvider:oe,defaultModel:A}),r=await je({config:o}),i=ee({cfg:o,catalog:r,ref:e,defaultProvider:t,defaultModel:n}),a=[];i.allowed||a.push(`- hooks.gmail.model "${i.key}" not in agents.defaults.models allowlist (will use primary instead)`),i.inCatalog||a.push(`- hooks.gmail.model "${i.key}" not in the model catalog (may fail at runtime)`),a.length>0&&B(a.join(`
`),`Hooks`)}}if(t.nonInteractive!==!0&&process.platform===`linux`&&$(o)===`local`){let t=U(),r=!1;try{r=await t.isLoaded({env:process.env})}catch{r=!1}r&&await Ft({runtime:e,prompter:{confirm:async e=>n.confirm(e),note:B},reason:`Gateway runs as a systemd user service. Without lingering, systemd stops the user session on logout/idle and kills the Gateway.`,requireConfirm:!0})}Nr(o),await en(o),await Lt(e,n,{nonInteractive:t.nonInteractive});let{healthOk:h}=await ln({runtime:e,cfg:o,timeoutMs:t.nonInteractive===!0?3e3:1e4}),g=h?await un({cfg:o,timeoutMs:t.nonInteractive===!0?3e3:1e4}):{checked:!1,ready:!1};if(await wn(o,{gatewayMemoryProbe:g}),await cn({cfg:o,runtime:e,prompter:n,options:t,gatewayDetailsMessage:p.message,healthOk:h}),a.shouldWriteConfig||JSON.stringify(o)!==JSON.stringify(c)){o=Ve(o,{command:`doctor`,mode:$(o)}),await ie(o),At(e);let t=`${r}.bak`;W.existsSync(t)&&e.log(`Backup: ${l(t)}`)}else n.shouldRepair||e.log(`Run "${L(`openclaw doctor --fix`)}" to apply changes.`);if(t.workspaceSuggestions!==!1){let e=P(o,F(o));Tr(e),await Ar(e)&&B(kr,`Workspace`)}let _=await w();if(_.exists&&!_.valid){e.error(`Invalid config:`);for(let t of _.issues){let n=t.path||`<root>`;e.error(`- ${n}: ${t.message}`)}}Fr(`Doctor complete.`)}function Lr(e){return Ut({...e,message:z(e.message),options:e.options.map(e=>e.hint===void 0?e:{...e,hint:Ge(e.hint)})})}export{Ir as n,Lr as t};
