@doubao-dev/cli 0.0.37 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/1272.js +3 -12
- package/dist/2168~0.js +1 -1
- package/dist/4315~0.js +1 -1
- package/dist/@inquirer/confirm.js +1 -0
- package/dist/assets/web-sdk-debugger/assets/framework/doubao-apps-api.template.js +0 -0
- package/dist/assets/web-sdk-debugger/assets/framework/doubao-apps-framework.template.js +0 -0
- package/dist/assets/web-sdk-debugger/index.html +1 -1
- package/dist/assets/web-sdk-debugger/static/js/491.26cad27284.js +1836 -0
- package/dist/assets/web-sdk-debugger/static/js/index.cefeab0b95.js +44 -0
- package/dist/build.js +2 -2
- package/dist/check.js +1 -1
- package/dist/dev-config.js +2 -2
- package/dist/dev.js +7 -7
- package/dist/inquirer.js +1 -1
- package/dist/sdk.js +71 -71
- package/dist/template-starter/package.json +0 -1
- package/package.json +2 -2
- package/skills/doubao-agentic-service-development/SKILL.md +2 -0
- package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/30-/346/227/245/345/216/206.md +141 -0
- package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/groups.md +1 -1
- package/skills/doubao-agentic-service-development/references/frontend/doubao-agentic-service-api/quick-reference.md +2 -1
- package/dist/assets/web-sdk-debugger/static/js/13.6b014d5621.js +0 -1836
- package/dist/assets/web-sdk-debugger/static/js/index.01a86a6f8b.js +0 -44
- package/dist/dist~2.js +0 -2
- /package/dist/assets/web-sdk-debugger/static/js/{13.6b014d5621.js.LICENSE.txt → 491.26cad27284.js.LICENSE.txt} +0 -0
package/dist/dev.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import"node:module";import{__webpack_require__ as e}from"./rslib-runtime~0.js";import"./9652~0.js";import{promises_namespaceObject as t}from"./8663~0.js";import{promises_namespaceObject as n,external_node_child_process_namespaceObject as r}from"./628~0.js";import{devLogger as i,DEV_ACTIONS as o,createDevProviderBinding as a,ensureDevActionSucceeded as s,summarizeData as c,parseJsonData as l,DEV_EVENTS as d,ServiceManager as p,connectDevService as u,startForegroundDevService as f}from"./275~0.js";import"./qrcode.js";import{version as g,getApiBaseUrl as h,getAuthOptions as m,command_Command as w,isRecord as v}from"./4315~0.js";import{getCliPackageRoot as y,createKitDevOptions as I}from"./kit-dev-options.js";import{readJsonIfExists as b}from"./json-file.js";import{TokenExpiredError as S,source as C,withAuth as _,NotLoggedInError as E,AuthError as A}from"./5610~0.js";import{resolveDevSimulatorPaths as D,getAuthErrorMessage as T,prepareDevBusinessTemplates as $,extractDevPermissions as P,prepareDevManifest as N,resolveDevMcpEndpoint as
|
|
2
|
-
`,"utf8")}let eS=e("node:crypto");var eC=e.n(eS);async function e_(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=e.arch??process.arch,i=e.appDir??eg(),o=eh(t),a=t[ec]?.trim();if(a)return{status:"found",appPath:Y().resolve(a),source:"env"};if(!o){let e=eu({...t,[ec]:""},n,i);if(e)return{status:"found",appPath:e,source:"packaged"}}return eE({env:t,platform:n,arch:r,appDir:i,manifest:e.manifest,runner:e.runner})}async function eE(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=e.arch??process.arch,i=e.manifest??eo;if(1!==i.schemaVersion)throw Error(`不支持的豆包开发者工具 Manifest schemaVersion:${i.schemaVersion}`);if(!i.cliVersion.trim())throw Error("豆包开发者工具 Manifest 缺少 cliVersion");if(!i.deviceAppVersion.trim())throw Error("豆包开发者工具 Manifest 缺少 deviceAppVersion");et(i.deviceAppVersion);let o=ee(n,r);if(!o)return{status:"skipped",reasonCode:"UNSUPPORTED_PLATFORM",reason:`当前平台 ${n}/${r} 不支持下载豆包开发者工具`};let a=i.packages[o];if(!a)return{status:"skipped",reason:`CLI ${i.cliVersion} 未配置 ${o} 平台的豆包开发者工具安装包`};let s=ef(t,n),c=en(i,a);if(!eh(t)){let e=function(e,t,n,r,i){var o,a,s,c,l;let d,p=ew(e);if(!p||p.activeDeviceAppVersion!==i||p.cliVersion!==t.cliVersion||p.platform!==n||!ei(p.sha256,r)||p.entry!==r.entry)return;let u=ey(e,i);if(o=u,a=t,s=n,c=r,l=i,!((d=em(o))&&d.cliVersion===a.cliVersion&&d.deviceAppVersion===l&&d.entry===c.entry&&d.platform===s&&ei(d.sha256,c)))return;let f=eI(u,r.entry,"豆包开发者工具入口");return z().existsSync(f)?f:void 0}(s,i,o,a,c);if(e)return ev(s,c),{status:"found",appPath:e,source:"cache"}}let l=await eA(s,i,o,a,n,e.runner);return ev(s,c),{status:"found",appPath:l,source:"downloaded"}}async function eA(e,t,n,r,i,o={}){if(!r.url||!r.entry)throw Error("豆包开发者工具安装包必须配置 url 和 entry");if(void 0!==r.version){if(!r.version.trim())throw Error("豆包开发者工具安装包版本不能为空");et(r.version)}if(r.sha256&&!/^[0-9a-fA-F]{64}$/.test(r.sha256))throw Error(`豆包开发者工具安装包 sha256 必须是 64 位十六进制字符:${r.sha256}`);if(void 0!==r.sizeBytes&&(!Number.isSafeInteger(r.sizeBytes)||r.sizeBytes<=0))throw Error(`豆包开发者工具安装包 sizeBytes 必须是正整数:${r.sizeBytes}`);if(Y().isAbsolute(r.entry)||r.entry.split(/[\\/]+/).includes(".."))throw Error(`豆包开发者工具安装包 entry 必须是 ZIP 内部的相对路径:${r.entry}`);let a=en(t,r),s=o.now?.()??Date.now(),c=Y().join(e,".tmp");z().mkdirSync(c,{recursive:!0}),z().mkdirSync(Y().join(e,ep),{recursive:!0});let l=z().mkdtempSync(Y().join(c,`${a}-`)),d=Y().join(l,"device-app.zip"),p=Y().join(l,"extract"),u=ey(e,a);try{var f;let c,l;if(o.onProgress?.({phase:"download",downloadedBytes:0,...void 0===r.sizeBytes?{}:{totalBytes:r.sizeBytes,percentage:0},elapsedMs:0}),await Z(r.url,d,o.fetch,o.onProgress,o.signal),r.sha256&&(o.onProgress?.({phase:"install",stage:"verify"}),o.signal?.throwIfAborted(),c=await eT(d),o.signal?.throwIfAborted(),c!==er(r.sha256)))throw Error(`豆包开发者工具安装包 SHA-256 校验不匹配:预期 ${r.sha256},实际 ${c}`);z().mkdirSync(p,{recursive:!0}),o.onProgress?.({phase:"install",stage:"extract"}),await eD(d,p,i,o);let g=eI(p,r.entry,"豆包开发者工具安装包入口");!function(e,t){if(!z().existsSync(e))throw Error(`解压后未找到豆包开发者工具入口:${e}`);let n=z().statSync(e);if("darwin"===t){if(!n.isDirectory()||!e.endsWith(".app"))throw Error(`macOS 豆包开发者工具入口必须是 .app 目录:${e}`);return}if("win32"===t&&(!n.isFile()||!e.toLowerCase().endsWith(".exe")))throw Error(`Windows 豆包开发者工具入口必须是 .exe 文件:${e}`)}(g,i);let h=em(p);if(h&&(h.cliVersion!==t.cliVersion||h.deviceAppVersion!==a||h.entry!==r.entry||h.platform!==n||!ei(h.sha256,r)))throw Error(`豆包开发者工具元数据与 CLI Manifest 不匹配,文件位于 ${Y().join(p,el)}`);o.onProgress?.({phase:"install",stage:"install"}),z().rmSync(u,{recursive:!0,force:!0}),z().renameSync(p,u),l={name:"Doubao App V2",cliVersion:t.cliVersion,deviceAppVersion:a,entry:r.entry,platform:n,...r.sha256?{sha256:er(r.sha256)}:{},installedAt:s},eb(Y().join(u,el),l),f={activeDeviceAppVersion:a,cliVersion:t.cliVersion,entry:r.entry,platform:n,...r.sha256?{sha256:er(r.sha256)}:{},installedAt:s},eb(Y().join(e,ed),f);let m=eI(u,r.entry,"豆包开发者工具入口");return o.onProgress?.({phase:"complete",appPath:m}),m}finally{z().rmSync(l,{recursive:!0,force:!0})}}async function eD(e,t,n,r){let i=r.runCommand??((e,t)=>G(e,{rejectOnNonZero:!0,signal:t?.signal}).then(()=>void 0));if("darwin"===n){r.signal?.throwIfAborted(),await i({command:"ditto",args:["-x","-k",e,t]},{signal:r.signal});return}if("win32"===n){r.signal?.throwIfAborted(),await i({command:"powershell.exe",args:["-NoProfile","-ExecutionPolicy","Bypass","-Command",`Expand-Archive -LiteralPath ${e$(e)} -DestinationPath ${e$(t)} -Force`],windowsVerbatimArguments:!0},{signal:r.signal});return}throw Error(`当前平台 ${n} 不支持解压豆包开发者工具 ZIP 安装包`)}async function eT(e){let n=eC().createHash("sha256");return await (0,t.pipeline)(z().createReadStream(e),n),n.digest("hex")}function e$(e){return`'${e.replace(/'/g,"''")}'`}function eP(e){if("complete"===e.phase)return`豆包开发者工具已安装:${e.appPath}`;if("install"===e.phase){let t={verify:"验证",extract:"解压",install:"安装"}[e.stage];return`安装豆包开发者工具:${t}`}let t=[void 0===e.percentage?void 0:`${e.percentage}%`,void 0===e.totalBytes?e.downloadedBytes>0?
|
|
1
|
+
import"node:module";import{__webpack_require__ as e}from"./rslib-runtime~0.js";import"./9652~0.js";import{promises_namespaceObject as t}from"./8663~0.js";import{promises_namespaceObject as n,external_node_child_process_namespaceObject as r}from"./628~0.js";import{devLogger as i,DEV_ACTIONS as o,createDevProviderBinding as a,ensureDevActionSucceeded as s,summarizeData as c,parseJsonData as l,DEV_EVENTS as d,ServiceManager as p,connectDevService as u,startForegroundDevService as f}from"./275~0.js";import"./qrcode.js";import{version as g,getApiBaseUrl as h,getAuthOptions as m,command_Command as w,isRecord as v}from"./4315~0.js";import{getCliPackageRoot as y,createKitDevOptions as I}from"./kit-dev-options.js";import{readJsonIfExists as b}from"./json-file.js";import{TokenExpiredError as S,source as C,withAuth as _,NotLoggedInError as E,AuthError as A}from"./5610~0.js";import{resolveDevSimulatorPaths as D,getAuthErrorMessage as T,prepareDevBusinessTemplates as $,extractDevPermissions as P,prepareDevManifest as N,resolveDevMcpEndpoint as k,formatFinalDevWarnings as x}from"./dev-config.js";import{listMiniAppVersions as O}from"./app.js";import{classifyEventStatus as R,reportCommand as L,runCommand as M,runTrackedDevAction as V,flushEvents as j,setEventTrackingUid as U,reportDevAction as F}from"./2168~0.js";import{openUrlInBrowser as K}from"./browser.js";import{resolveProjectLayout as B}from"./project-layout.js";import{precheckBusinessTemplatesPersonalInformation as q}from"./business-template-personal-information.js";import{extractMCPHeadersFromManifest as H}from"./manifest-headers.js";var W={};function G(e,t){return new Promise((n,i)=>{let o;t.signal?.throwIfAborted();let a=(0,r.spawn)(e.command,e.args,{stdio:"ignore",windowsVerbatimArguments:e.windowsVerbatimArguments}),s=!1,c=()=>{a.kill(),(o=setTimeout(()=>a.kill("SIGKILL"),1e3)).unref()},l=e=>{s||(s=!0,clearTimeout(o),t.signal?.removeEventListener("abort",c),e())};t.signal?.addEventListener("abort",c,{once:!0}),a.once("error",e=>l(()=>i(e))),a.once("close",(r,o)=>{l(()=>{t.signal?.aborted?i(t.signal.reason):null===r?i(Error(`${e.command} 被信号 ${o} 终止`)):0!==r&&t.rejectOnNonZero?i(Error(`${e.command} 已退出,退出码为 ${r}`)):n(r)})})})}e.r(W),e.d(W,{createDeferredDevShellSession:()=>nS,default:()=>ny,isInteractiveTerminal:()=>n_});let Q=e("node:fs");var z=e.n(Q);let J=e("node:stream");async function Z(e,n,r=fetch,i,o){var a,s;let c,l,d,p,u,f,g=new URL(e);if("https:"!==g.protocol&&"http:"!==g.protocol)throw Error(`豆包开发者工具安装包 URL 必须使用 HTTP 或 HTTPS:${e}`);o?.throwIfAborted();let h=await r(e,{signal:o});if(!h.ok)throw Error(`豆包开发者工具安装包下载失败:HTTP ${h.status} ${h.statusText}`);if(!h.body)throw Error("豆包开发者工具安装包下载失败:响应内容为空");let m=h.body;await (0,t.pipeline)(J.Readable.fromWeb(m),(a=h,s=i,c=function(e){if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0?t:void 0}(a.headers.get("content-length")),l=0,d=-1,p=0,u=Date.now(),(f=e=>{if(!s)return;if(c){let t=Math.min(100,Math.floor(l/c*100));if(!e&&100!==t&&t<d+10||t===d)return;d=t;let n=Date.now()-u;s({phase:"download",downloadedBytes:l,totalBytes:c,percentage:t,elapsedMs:n});return}if(!e&&l-p<0x3200000||l===p)return;p=l;let t=Date.now()-u;s({phase:"download",downloadedBytes:l,elapsedMs:t})})(!1),new J.Transform({transform(e,t,n){l+=e.length,f(!1),n(null,e)},flush(e){f(!0),e()}})),z().createWriteStream(n),{signal:o})}let X=e("node:path");var Y=e.n(X);function ee(e,t){if(("darwin"===e||"win32"===e)&&("arm64"===t||"x64"===t))return`${e}-${t}`}function et(e){if(!/^[0-9A-Za-z._+-]+$/.test(e))throw Error(`豆包开发者工具版本包含不支持的路径字符:${e}`)}function en(e,t){let n=t.version??e.deviceAppVersion;if(!n.trim())throw Error("豆包开发者工具安装包版本不能为空");return et(n),n}function er(e){return e.toLowerCase()}function ei(e,t){return!t.sha256||e===er(t.sha256)}let eo={schemaVersion:1,cliVersion:g,deviceAppVersion:"1.0.11",packages:{"darwin-arm64":{url:"https://lf3-cdn-tos.bytegoofy.com/obj/tron-demo/7610358476778248474/512002698/1.0.11/darwin-arm64/DoubaoDeveloperTools-v1.0.11-darwin-arm64.zip",sha256:"7e96be1de104661bd841c11d5236608ee41b3f77d5135567dbcb1ad8f0a24dff",entry:"豆包开发者工具.app",sizeBytes:0x78057a4},"win32-x64":{url:"https://lf3-cdn-tos.bytegoofy.com/obj/tron-demo/7610358476778248474/512002698/1.0.11/win32-x64/DoubaoDeveloperTools-v1.0.11-win32-x64.zip",sha256:"c3d6cf88c8b36515dcaea9548b9df914b588ef8ba2f969080f846c94e5bf9e80",entry:"豆包开发者工具.exe",sizeBytes:0x84cc3e2}}},ea=e("node:os");var es=e.n(ea);let ec="DBX_DEVICE_APP_PATH",el="dbx-device-app.json",ed="state.json",ep="versions";function eu(e=process.env,t=process.platform,n=eg()){let r=e[ec]?.trim();if(r)return Y().resolve(r);if(!z().existsSync(n))return;let i=z().readdirSync(n,{withFileTypes:!0}).find(e=>{var n,r;return n=e,"darwin"===(r=t)?n.isDirectory()&&n.name.endsWith(".app"):"win32"===r?n.isFile()&&n.name.toLowerCase().endsWith(".exe"):n.isFile()&&/\.(appimage|AppImage)$/.test(n.name)});return i?Y().join(n,i.name):void 0}function ef(e=process.env,t=process.platform){let n=e.DBX_DEVICE_APP_CACHE_DIR?.trim();if(n)return Y().resolve(n);if("darwin"===t)return Y().join(es().homedir(),"Library","Application Support","dbx","device-app");if("win32"===t){let t=e.LOCALAPPDATA?.trim()||Y().join(es().homedir(),"AppData","Local");return Y().join(t,"dbx","device-app")}return Y().join(es().homedir(),".local","share","dbx","device-app")}function eg(){return Y().join(y(),"device-app")}function eh(e){let t=e.DBX_DEVICE_APP_FORCE_DOWNLOAD?.trim().toLowerCase();return!!(t&&"0"!==t&&"false"!==t)}function em(e){let t=b(Y().join(e,el));if(!v(t))return;let n=t.cliVersion,r=t.deviceAppVersion,i=t.entry,o=t.platform,a=t.sha256,s=t.installedAt;if("string"==typeof n&&"string"==typeof r&&"string"==typeof i&&"string"==typeof o&&(void 0===a||"string"==typeof a)&&"number"==typeof s)return{name:"string"==typeof t.name?t.name:void 0,cliVersion:n,deviceAppVersion:r,entry:i,platform:o,..."string"==typeof a?{sha256:a}:{},installedAt:s}}function ew(e){let t=b(Y().join(e,ed));if(v(t)&&"string"==typeof t.activeDeviceAppVersion&&"string"==typeof t.cliVersion&&"string"==typeof t.entry&&"string"==typeof t.platform&&(void 0===t.sha256||"string"==typeof t.sha256)&&"number"==typeof t.installedAt)return{activeDeviceAppVersion:t.activeDeviceAppVersion,cliVersion:t.cliVersion,entry:t.entry,platform:t.platform,..."string"==typeof t.sha256?{sha256:t.sha256}:{},installedAt:t.installedAt}}function ev(e,t){let n=Y().join(e,ep);if(z().existsSync(n)){for(let e of z().readdirSync(n,{withFileTypes:!0}))if(e.isDirectory()&&e.name!==t)try{z().rmSync(Y().join(n,e.name),{recursive:!0,force:!0})}catch{}}}function ey(e,t){return et(t),Y().join(e,ep,t)}function eI(e,t,n){if(Y().isAbsolute(t))throw Error(`${n} 必须是相对路径:${t}`);let r=Y().resolve(e),i=Y().resolve(e,t);if(i!==r&&!i.startsWith(`${r}${Y().sep}`))throw Error(`${n} 超出目标目录:${t}`);return i}function eb(e,t){z().mkdirSync(Y().dirname(e),{recursive:!0}),z().writeFileSync(e,`${JSON.stringify(t,null,2)}
|
|
2
|
+
`,"utf8")}let eS=e("node:crypto");var eC=e.n(eS);async function e_(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=e.arch??process.arch,i=e.appDir??eg(),o=eh(t),a=t[ec]?.trim();if(a)return{status:"found",appPath:Y().resolve(a),source:"env"};if(!o){let e=eu({...t,[ec]:""},n,i);if(e)return{status:"found",appPath:e,source:"packaged"}}return eE({env:t,platform:n,arch:r,appDir:i,manifest:e.manifest,runner:e.runner})}async function eE(e={}){let t=e.env??process.env,n=e.platform??process.platform,r=e.arch??process.arch,i=e.manifest??eo;if(1!==i.schemaVersion)throw Error(`不支持的豆包开发者工具 Manifest schemaVersion:${i.schemaVersion}`);if(!i.cliVersion.trim())throw Error("豆包开发者工具 Manifest 缺少 cliVersion");if(!i.deviceAppVersion.trim())throw Error("豆包开发者工具 Manifest 缺少 deviceAppVersion");et(i.deviceAppVersion);let o=ee(n,r);if(!o)return{status:"skipped",reasonCode:"UNSUPPORTED_PLATFORM",reason:`当前平台 ${n}/${r} 不支持下载豆包开发者工具`};let a=i.packages[o];if(!a)return{status:"skipped",reason:`CLI ${i.cliVersion} 未配置 ${o} 平台的豆包开发者工具安装包`};let s=ef(t,n),c=en(i,a);if(!eh(t)){let e=function(e,t,n,r,i){var o,a,s,c,l;let d,p=ew(e);if(!p||p.activeDeviceAppVersion!==i||p.cliVersion!==t.cliVersion||p.platform!==n||!ei(p.sha256,r)||p.entry!==r.entry)return;let u=ey(e,i);if(o=u,a=t,s=n,c=r,l=i,!((d=em(o))&&d.cliVersion===a.cliVersion&&d.deviceAppVersion===l&&d.entry===c.entry&&d.platform===s&&ei(d.sha256,c)))return;let f=eI(u,r.entry,"豆包开发者工具入口");return z().existsSync(f)?f:void 0}(s,i,o,a,c);if(e)return ev(s,c),{status:"found",appPath:e,source:"cache"}}let l=await eA(s,i,o,a,n,e.runner);return ev(s,c),{status:"found",appPath:l,source:"downloaded"}}async function eA(e,t,n,r,i,o={}){if(!r.url||!r.entry)throw Error("豆包开发者工具安装包必须配置 url 和 entry");if(void 0!==r.version){if(!r.version.trim())throw Error("豆包开发者工具安装包版本不能为空");et(r.version)}if(r.sha256&&!/^[0-9a-fA-F]{64}$/.test(r.sha256))throw Error(`豆包开发者工具安装包 sha256 必须是 64 位十六进制字符:${r.sha256}`);if(void 0!==r.sizeBytes&&(!Number.isSafeInteger(r.sizeBytes)||r.sizeBytes<=0))throw Error(`豆包开发者工具安装包 sizeBytes 必须是正整数:${r.sizeBytes}`);if(Y().isAbsolute(r.entry)||r.entry.split(/[\\/]+/).includes(".."))throw Error(`豆包开发者工具安装包 entry 必须是 ZIP 内部的相对路径:${r.entry}`);let a=en(t,r),s=o.now?.()??Date.now(),c=Y().join(e,".tmp");z().mkdirSync(c,{recursive:!0}),z().mkdirSync(Y().join(e,ep),{recursive:!0});let l=z().mkdtempSync(Y().join(c,`${a}-`)),d=Y().join(l,"device-app.zip"),p=Y().join(l,"extract"),u=ey(e,a);try{var f;let c,l;if(o.onProgress?.({phase:"download",downloadedBytes:0,...void 0===r.sizeBytes?{}:{totalBytes:r.sizeBytes,percentage:0},elapsedMs:0}),await Z(r.url,d,o.fetch,o.onProgress,o.signal),r.sha256&&(o.onProgress?.({phase:"install",stage:"verify"}),o.signal?.throwIfAborted(),c=await eT(d),o.signal?.throwIfAborted(),c!==er(r.sha256)))throw Error(`豆包开发者工具安装包 SHA-256 校验不匹配:预期 ${r.sha256},实际 ${c}`);z().mkdirSync(p,{recursive:!0}),o.onProgress?.({phase:"install",stage:"extract"}),await eD(d,p,i,o);let g=eI(p,r.entry,"豆包开发者工具安装包入口");!function(e,t){if(!z().existsSync(e))throw Error(`解压后未找到豆包开发者工具入口:${e}`);let n=z().statSync(e);if("darwin"===t){if(!n.isDirectory()||!e.endsWith(".app"))throw Error(`macOS 豆包开发者工具入口必须是 .app 目录:${e}`);return}if("win32"===t&&(!n.isFile()||!e.toLowerCase().endsWith(".exe")))throw Error(`Windows 豆包开发者工具入口必须是 .exe 文件:${e}`)}(g,i);let h=em(p);if(h&&(h.cliVersion!==t.cliVersion||h.deviceAppVersion!==a||h.entry!==r.entry||h.platform!==n||!ei(h.sha256,r)))throw Error(`豆包开发者工具元数据与 CLI Manifest 不匹配,文件位于 ${Y().join(p,el)}`);o.onProgress?.({phase:"install",stage:"install"}),z().rmSync(u,{recursive:!0,force:!0}),z().renameSync(p,u),l={name:"Doubao App V2",cliVersion:t.cliVersion,deviceAppVersion:a,entry:r.entry,platform:n,...r.sha256?{sha256:er(r.sha256)}:{},installedAt:s},eb(Y().join(u,el),l),f={activeDeviceAppVersion:a,cliVersion:t.cliVersion,entry:r.entry,platform:n,...r.sha256?{sha256:er(r.sha256)}:{},installedAt:s},eb(Y().join(e,ed),f);let m=eI(u,r.entry,"豆包开发者工具入口");return o.onProgress?.({phase:"complete",appPath:m}),m}finally{z().rmSync(l,{recursive:!0,force:!0})}}async function eD(e,t,n,r){let i=r.runCommand??((e,t)=>G(e,{rejectOnNonZero:!0,signal:t?.signal}).then(()=>void 0));if("darwin"===n){r.signal?.throwIfAborted(),await i({command:"ditto",args:["-x","-k",e,t]},{signal:r.signal});return}if("win32"===n){r.signal?.throwIfAborted(),await i({command:"powershell.exe",args:["-NoProfile","-ExecutionPolicy","Bypass","-Command",`Expand-Archive -LiteralPath ${e$(e)} -DestinationPath ${e$(t)} -Force`],windowsVerbatimArguments:!0},{signal:r.signal});return}throw Error(`当前平台 ${n} 不支持解压豆包开发者工具 ZIP 安装包`)}async function eT(e){let n=eC().createHash("sha256");return await (0,t.pipeline)(z().createReadStream(e),n),n.digest("hex")}function e$(e){return`'${e.replace(/'/g,"''")}'`}function eP(e){if("complete"===e.phase)return`豆包开发者工具已安装:${e.appPath}`;if("install"===e.phase){let t={verify:"验证",extract:"解压",install:"安装"}[e.stage];return`安装豆包开发者工具:${t}`}let t=[void 0===e.percentage?void 0:`${e.percentage}%`,void 0===e.totalBytes?e.downloadedBytes>0?ek(e.downloadedBytes):void 0:`${ek(e.downloadedBytes)} / ${ek(e.totalBytes)}`,`${Math.max(0,Math.round(e.elapsedMs/1e3))}s`].filter(e=>!!e);return`下载豆包开发者工具:${t.join(" \xb7 ")}`}function eN(e,t){let n,r=!1;return i=>{if(!i)return void t?.(void 0);if("download"===i.phase){n||(ex(e,"真机调试准备:"),ex(e,`首次或版本更新需要下载豆包开发者工具${i.totalBytes?`(${ek(i.totalBytes)})`:""}。`),ex(e,"下载完成后才会生成二维码;下载耗时取决于网络,进度和实际耗时将持续显示。")),n=i,t?.(i);return}if(n&&!r&&(r=!0,ex(e,`✓ ${eP(n)}`)),"complete"===i.phase){t?.(void 0),ex(e,`✓ ${eP(i)}`);return}t?.(i)}}function ek(e){let t=["B","KB","MB","GB"],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r+=1;return 0===r?`${n} ${t[r]}`:`${n.toFixed(1)} ${t[r]}`}function ex(e,t=""){e.write(`${t}
|
|
3
3
|
`)}async function eO(e=process.stderr,t={}){return e_({runner:{onProgress:t.onProgress??eN(e),signal:t.signal}})}function eR(e){return{namespace:e.namespace,projectPath:e.projectPath,appDir:e.appDir,appKey:e.appId,hostUrl:e.host}}async function eL(e,t){var n,i,o;let a,s=(n=e,i=process.platform,a=(o=t)?[["namespace",o.namespace],["project",o.appDir??o.projectPath],["app-key",o.appKey],["host-url",o.hostUrl]].flatMap(([e,t])=>t?[`--${e}=${t}`]:[]):[],"darwin"===i?{command:"open",args:[n,...a.length?["--args",...a]:[]]}:{command:n,args:a});"darwin"===process.platform?await G(s,{rejectOnNonZero:!0}):await new Promise((e,t)=>{let n=(0,r.spawn)(s.command,s.args,{stdio:"ignore"});n.once("error",t),n.once("spawn",e)})}async function eM(){let e=function(e=process.env,t=process.platform,n=process.arch,r=eg()){let i=e[ec]?.trim();if(i)return Y().resolve(i);let o=eu({...e,[ec]:""},t,r);if(o)return o;let a=ee(t,n);if(!a)return;let s=ef(e,t),c=ew(s);if(!c||c.platform!==a)return;let l=eI(ey(s,c.activeDeviceAppVersion),c.entry,"豆包开发者工具状态中的入口");return z().existsSync(l)?l:void 0}();return e?("darwin"===process.platform?await eV(e):await G(eU(e,process.platform),{rejectOnNonZero:!0}),{status:"closed",appPath:e}):{status:"skipped",reason:`未设置 ${ec},也未找到内置或缓存的豆包开发者工具`}}async function eV(e){let t=function(e){if(!e.endsWith(".app"))return;let t=function(e){let t=Y().join(e,"Contents","Info.plist");if(!z().existsSync(t))return;let n=z().readFileSync(t,"utf8").match(/<key>CFBundleExecutable<\/key>\s*<string>([^<]+)<\/string>/);return n?.[1]}(e)??Y().basename(e,".app");return Y().join(e,"Contents","MacOS",t)}(e);await G(eU(e,"darwin"),{rejectOnNonZero:!1}),!t||await ej(t)&&await G({command:"pkill",args:["-f",eF(t)]},{rejectOnNonZero:!1})}async function ej(e){return 0===await G({command:"pgrep",args:["-f",eF(e)]},{rejectOnNonZero:!1})}function eU(e,t){return"darwin"===t?{command:"osascript",args:["-e",`tell application (POSIX file "${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}" as alias) to quit`]}:"win32"===t?{command:"taskkill",args:["/IM",Y().win32.basename(e),"/T"]}:{command:"pkill",args:["-f",e]}}function eF(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}class eK extends Error{constructor(e){super(`真机调试认证超时,已等待 ${e} 毫秒`),this.name="DeviceDebugAuthTimeoutError"}}class eB extends Error{constructor(){super("真机调试认证已取消"),this.name="DeviceDebugAuthCancelledError"}}let eq=e("../../service-manager/dist/index.js");function eH(e,t,n){let r=new eq.ServiceManager(e,{nodeId:`dev-disconnect-${process.pid}-${Math.random().toString(36).slice(2,8)}`,requestTimeout:2e3}),i=a(r,n);return r.createService({name:`devDisconnectListener${process.pid}`,events:{"connection.clientDisconnected":async e=>{if(await i.ready(),!i.matchesEvent(e.nodeId))return;let{clientId:n}=eQ(e.params);if(void 0!==n&&Number.isSafeInteger(n)&&n>=0)return t(n)}}}),{start:async()=>{try{await r.start()}catch(e){throw i.close(),await r.stop(),e}},stop:()=>(i.close(),r.stop())}}function eW(e){return Math.max(0,e-Date.now())}async function eG(e,t){let r=Date.now()+t;for(;;)try{return await e()}catch(e){if(Date.now()>=r)throw e;await (0,n.setTimeout)(100)}}function eQ(e){return e&&"object"==typeof e?{scope:"string"==typeof e.scope?e.scope:void 0,type:"string"==typeof e.type?e.type:void 0,clientId:"number"==typeof e.clientId?e.clientId:void 0,deviceId:ez(e),app:"string"==typeof e.app?e.app:void 0}:{}}function ez(e){let t=e.client?.device,n=t?.info;return n?.usbDeviceId||t?.xdbId||n?.did||n?.debugRouterId}class eJ extends Error{code;constructor(e,t){super(t),this.code=e,this.name="RealDeviceDebugAuthError"}}async function eZ(e){var t,n,r,i;let s,c,l,d,p,u=e.timeoutMs??6e4;if(!e.hostUrl||!e.appKey)return{ok:!1,status:"skipped",timeoutMs:u,failureStage:"create_qr",error:"无法生成二维码,缺少 hostUrl 或 appKey。"};let f=e.hostUrl,g=e.appKey,w=(t=e.namespace,n=u,l=a(c=new eq.ServiceManager(t,{nodeId:`dev-auth-${process.pid}-${Math.random().toString(36).slice(2,8)}`,requestTimeout:2e3}),void 0),d=!1,p=new Promise(e=>{s=e}),c.createService({name:`devAuthListener${process.pid}`,events:{"connection.newclient"(e){!d&&l.matchesEvent(e.nodeId)&&(d=!0,s(eQ(e.params)))}}}),{start:async()=>{try{await c.start(),await l.ready()}catch(e){throw l.close(),await c.stop(),e}},stop:()=>(l.close(),c.stop()),wait:(e,t=n)=>{var r,i,o;return r=p,i=t,o=e,new Promise((e,t)=>{let n=()=>{clearTimeout(a),t(o?.reason instanceof Error?o.reason:new eB)},a=setTimeout(()=>{o?.removeEventListener("abort",n),t(new eK(i))},i);o?.aborted?n():(o?.addEventListener("abort",n,{once:!0}),r.then(t=>{clearTimeout(a),o?.removeEventListener("abort",n),e(t)},e=>{clearTimeout(a),o?.removeEventListener("abort",n),t(e)}))})},async findExistingClient(){let e=await eG(()=>l.call("devtoolConnection.getConnectedClients"),2e3).catch(()=>[]);return function(e){if(!e||"object"!=typeof e)return;let t=e.device,n=t?.info,r="number"==typeof t?.clientId?t.clientId:void 0;return{scope:"all",type:String(n?.network??"").toLowerCase().includes("wifi")?"wifi":"usb",...void 0===r?{}:{clientId:r},deviceId:ez({client:e}),app:"string"==typeof n?.App?n.App:""}}(Array.isArray(e)?e[0]:void 0)},async awaitDirectDebugReady(e){let t=Math.min(n,2500);try{return await l.call(o.awaitDirectDebugReady,{clientId:e,timeoutMs:t},{timeout:t+1e3})}catch{return!1}},waitForInstallResult:(e,t,n,r)=>{var i,a;return i=l.call(o.awaitDeviceInstallResult,{clientId:e,packageName:t,timeoutMs:n},{timeout:n+1e3}),(a=r)?new Promise((e,t)=>{let n=()=>{t(a.reason instanceof Error?a.reason:new eB)};if(a.aborted){i.catch(()=>void 0),n();return}a.addEventListener("abort",n,{once:!0}),i.then(t=>{a.removeEventListener("abort",n),e(t)},e=>{a.removeEventListener("abort",n),t(e)})}):i}}),v={},y="connection",I="wait_device_connection";await w.start();try{let t;e.signal?.throwIfAborted();let n=await w.findExistingClient(),i=n?.clientId!==void 0&&await w.awaitDirectDebugReady(n.clientId);if(i)await e.onPhaseChange?.("reusing_client");else{let n,i,o;I="create_qr",t=await eX(function(e,t,n={}){let r=e1(n.settings),i=n.authOptions??m();return{hostUrl:e,appKey:t,...void 0===n.versionTag?{}:{versionTag:n.versionTag},isSigned:!1,appletType:0,baseApiUrl:h(),authOptions:i,...!1===r.defaultDebugTagState?{defaultDebugTagState:!1}:{},...!r.usb&&n.wifiConnectUrl?{wifiConnectUrl:n.wifiConnectUrl}:{}}}(f,g,{versionTag:e.versionTag,settings:e.settings,wifiConnectUrl:e.wifiConnectUrl,authOptions:(r=v,{...m(),onResponse(e){var t;let n;t=r,(n=e.headers.get("x-tt-logid"))&&(t.logId=n)}})}),e.signal),await e.onPhaseChange?.("waiting_for_scan"),e5(e.output,""),e5(e.output,"使用豆包 App 扫码连接调试设备."),e5(e.output,`二维码创建成功,请在 ${(n=Math.max(1,Math.round(u/1e3)),i=Math.floor(n/60),o=n%60,i>0?`${i}m ${o}s`:`${o}s`)} 内扫码;超时可在真机模式执行 \`qr\` 创建新二维码。`),e5(e.output,""),await e.onQRCodeReady?.(t.qrCodeValue,t.debugToken),e.signal?.throwIfAborted()}I="wait_device_connection";let o=Date.now()+u;e5(e.output,`等待设备连接(${u/1e3} 秒后超时)……`);let a=(i?n:await w.findExistingClient())??await w.wait(e.signal,eW(o));if(void 0===a.clientId)throw Error("连接的设备缺少 clientId");y="install",I="install_debug_package",await e.onPhaseChange?.("waiting_for_install");let s=await w.waitForInstallResult(a.clientId,g,eW(o),e.signal);if(!s)throw new eK(u);if(!s.success)return{ok:!1,status:"skipped",timeoutMs:u,failureStage:I,waitingFor:y,client:a,error:s.message||"安装 AIPackage 失败,请检查网络环境并关注客户端提示"};return{ok:!0,status:"connected",timeoutMs:u,...t?{qrCodeValue:t.qrCodeValue,debugToken:t.debugToken,encryptedDebugPayload:t.encryptedDebugPayload}:{},client:a}}catch(a){let t=a instanceof eK,n=a instanceof eB||!!e.signal?.aborted,r=function(e){if(e&&"object"==typeof e)return e2(e,"logId")??e2(e,"log_id")}(a)??v.logId,o=e2(a,"code");return{ok:!1,status:n?"cancelled":t?"timeout":"skipped",timeoutMs:u,failureStage:I,waitingFor:y,...r?{logId:r}:{},...o?{errorCode:o}:{},error:T(a)??((i=a)instanceof Error?i.message:String(i))}}finally{await w.stop()}}async function eX(e,t){var n,r,i,o;let a={hostUrl:e0((n=e).hostUrl,"hostUrl is required to request real-device debug ticket"),appKey:e0(n.appKey,"appKey is required to request real-device debug ticket"),isSigned:n.isSigned,isEncrypted:!!n.isEncrypted,signPublicKeyVersion:n.signPublicKeyVersion?.trim(),versionTag:(r=n.versionTag,i="versionTag must not be empty",void 0===r?void 0:e0(r,i)),appletType:n.appletType,baseApiUrl:n.baseApiUrl||"https://hello.doubao-dev.com",authOptions:n.authOptions??m(),...!1===n.defaultDebugTagState?{defaultDebugTagState:!1}:{},...n.wifiConnectUrl?{wifiConnectUrl:n.wifiConnectUrl}:{}},s=await eY(a,t);if(!((o=s)&&"object"==typeof o&&0===o.code&&o.data&&"object"==typeof o.data))throw function(e,t){var n;let r=(n=e)&&"object"==typeof n&&"code"in n&&void 0!==n.code?String(n.code):"unknown";if("50010003"===r)return new eJ("APP_ROLE_PERMISSION_REQUIRED",`真机调试授权失败:当前账号没有工程所配置应用插件的角色权限。
|
|
4
4
|
工程 AppKey:${t.appKey}
|
|
5
5
|
请先检查本地工程的 app_key 是否正确,且不是 mock 或占位值;该 AppKey 应属于你有权限的应用插件。
|
|
@@ -40,12 +40,12 @@ import"node:module";import{__webpack_require__ as e}from"./rslib-runtime~0.js";i
|
|
|
40
40
|
});
|
|
41
41
|
</script>
|
|
42
42
|
</body>
|
|
43
|
-
</html>`));return}if("GET"===e.method&&n===`${h}qr.png`){t.writeHead(200,{"Content-Type":"image/png"}),t.end(l);return}if("GET"===e.method&&n===`${h}qr-modern.png`){if(!d){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("未找到资源");return}t.writeHead(200,{"Content-Type":"image/png"}),t.end(d);return}if("GET"===e.method&&n===`${h}events`){clearTimeout(a),a=void 0,t.writeHead(200,{Connection:"keep-alive","Content-Type":"text/event-stream"}),t.write("retry: 250\nevent: ready\ndata: ready\n\n"),m.add(t),t.once("close",()=>{m.delete(t),w||0!==m.size||(a=setTimeout(y,750))});return}if("POST"===e.method&&n===`${h}closed`){e.resume(),t.writeHead(204).end(),y();return}t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("未找到资源")});await new Promise((e,t)=>{I.once("error",t),I.listen(0,"127.0.0.1",()=>{I.removeListener("error",t),e()})});let b=I.address();if(!b||"string"==typeof b)throw await tt(I),Error("无法启动二维码查看器");f("server-listening",{host:"127.0.0.1",port:b.port});let S=`http://127.0.0.1:${b.port}${h}`,C=e=>c??=(async()=>{w=!0,clearTimeout(a);try{for(let e of m)try{e.destroyed||e.writableEnded||(e.once("error",()=>f("browser-close-event-error")),e.end("event: close\ndata: close\n\n"),f("browser-close-event-written"))}catch{f("browser-close-event-error")}}finally{m.clear(),await tt(I),f("server-closed",e)}})();try{f("browser-open-started"),await t(S),r.write("已在默认浏览器打开二维码。\n")}catch(e){throw await C({status:"browser-open-failed"}),Error(`二维码页面未能自动打开:${e instanceof Error?e.message:String(e)}`)}return{closed:v,close:C}}function tt(e){return e.listening?new Promise(t=>{e.close(()=>t()),e.closeAllConnections()}):Promise.resolve()}let tn=e("node:zlib"),tr=e("../../../node_modules/.pnpm/@byted-doubao-tools+devtool-connection-core@0.1.0_debug@4.4.3_react@19.2.7_winston@3.18.3/node_modules/@byted-doubao-tools/devtool-connection-core/dist/lib/ipc/index.js"),ti=4*Math.ceil(5614250.666666667),to=new Map;class ta extends Error{code;cause;constructor(e,t,n){super(t),this.code=e,this.name="RuntimeInspectionError",n&&"cause"in n&&(this.cause=n.cause)}}async function ts(e){let t,n=new p(e.namespace,{nodeId:`${e.nodeIdPrefix}-${process.pid}-${Math.random().toString(36).slice(2,8)}`,requestTimeout:12e3}),r=a(n,e.providerNodeId),i=new Set,s=new Set,c=0,l=!0;n.createService({name:`runtimeInspection${process.pid}${Math.random().toString(36).slice(2,8)}`,events:{[tr.DEVTOOL_CONNECTION_IPC_EVENTS.messageReceived]:async e=>{if(await r.ready(),!r.matchesEvent(e.nodeId))return;let n=e.params,o=tR(n);for(let e of(o&&Number.isSafeInteger(n.clientId)&&Number.isSafeInteger(n.sessionId)&&(t={clientId:n.clientId,sessionId:n.sessionId,data:o.data}),i))e(n)},[d.runtimeInspectionTargetChanged]:async e=>{if(await r.ready(),!r.matchesEvent(e.nodeId,!1))return;let t=function(e){if(v(e)&&"number"==typeof e.clientId&&"number"==typeof e.sessionId&&"string"==typeof e.url)return{clientId:e.clientId,sessionId:e.sessionId,url:e.url}}(e.params);if(t)for(let e of s)e(t)}}});try{await n.start()}catch(e){throw r.close(),await n.stop().catch(()=>void 0),e}let u=(e,t)=>tO(()=>r.call(`${tr.DEFAULT_DEVTOOL_CONNECTION_IPC_SERVICE_NAME}.${e}`,t),5e3);return{eventSubscriptionWarmupMs:e.eventSubscriptionWarmupMs??5e3,getConnectedClients:()=>u(tr.DEVTOOL_CONNECTION_IPC_ACTIONS.getConnectedClients),getLatestScreencastFrame(e){if(t?.clientId===e.clientId&&t.sessionId===e.sessionId)return{data:t.data}},async getRuntimeInspectionTarget(){if(!l)return null;try{return await r.call(o.getRuntimeInspectionTarget)}catch(e){if(tk(e))return l=!1,null;throw e}},subscribeRuntimeInspectionTarget:e=>(s.add(e),()=>{s.delete(e)}),async sendCdp(e,t,n={},r={}){let i={id:1e9+process.pid%1e5*1e3+c++,clientId:e.clientId,sessionId:e.sessionId,method:t,params:n,messageType:"CDP",timeoutMs:!1===r.expectResponse?100:1e4};try{let e=await u(tr.DEVTOOL_CONNECTION_IPC_ACTIONS.sendMessageToApp,i);var o,a,s=t,l=e;if(!l.success)throw Error([l.reason,l.apps?.length?`apps=${l.apps.join(",")}`:"",l.clients?.length?`clients=${l.clients.map(e=>`${e.clientId}:${e.info.App}`).join(",")}`:""].filter(Boolean).join("; "));if(v(l.data)&&v(l.data.error)){let e=void 0===l.data.error.code?"未知":String(l.data.error.code),t=void 0===l.data.error.message?"未知错误":String(l.data.error.message);throw Error(`${s} 失败:${t}(错误码 ${e})`)}return ty(l.data)}catch(e){if(!1===r.expectResponse&&(o=e,a=t,(o instanceof Error?o.message:String(o)).includes(`send CDP message timeout, method: ${a}`)))return;throw Error(`${t} 失败:${e instanceof Error?e.message:String(e)}`)}},subscribeMessage:e=>(i.add(e),()=>{i.delete(e)}),async stop(){r.close(),i.clear(),s.clear(),t=void 0,await n.stop()}}}async function tc(e,t={}){let n=Date.now()+(t.timeoutMs??3e3);for(;;){tM(t.signal);let r=await e.getConnectedClients(),i=function(e,t={}){let n,r=t.explicitTarget??(t.policy?.kind==="fixed"?t.policy.target:void 0);if(r){let n=e.find(e=>e.device.clientId===r.clientId);if(!n){if(t.activeClientId===r.clientId)throw new ta("TARGET_CLIENT_DISCONNECTED",`调试客户端 ${r.clientId} 已断开连接`);throw new ta("TARGET_STALE",`无法访问会话 ${tl(r)}:对应的调试客户端当前未连接`)}let i=n.sessions.find(e=>e.sessionId===r.sessionId&&th(e));if(!i)throw new ta("TARGET_STALE",`会话 ${tl(r)} 当前不可用,请重新选择可调试的 Lynx 会话`);return{clientId:n.device.clientId,sessionId:i.sessionId,url:i.url}}if(void 0!==t.activeClientId){if(!(n=e.find(e=>e.device.clientId===t.activeClientId)))throw new ta("TARGET_CLIENT_DISCONNECTED",`已认证的调试客户端 ${t.activeClientId} 已断开连接`)}else if(e.length>1)throw new ta("TARGET_AMBIGUOUS",`已连接多个调试设备:${e.map(e=>`${e.device.clientId}:${e.device.info.App||"未知应用"}`).join(", ")}`);else n=e[0];if(!n)return;let i=n.sessions.filter(th).sort((e,t)=>t.sessionId-e.sessionId)[0];if(i)return{clientId:n.device.clientId,sessionId:i.sessionId,url:i.url}}(r,t);if(i)return i;if(Date.now()>=n)throw 0===r.length?new ta("DEVICE_NOT_CONNECTED","未连接调试设备"):new ta("NO_ACTIVE_LYNX_SESSION","已连接的设备没有活跃的 Lynx 会话");await tV(100,t.signal)}}function tl(e){return`@${e.clientId}:${e.sessionId}`}function td(e){let t=/^@([1-9]\d*):([1-9]\d*)$/.exec(e.trim());if(!t)throw new ta("INVALID_TARGET_REF",`目标引用 "${e}" 无效;格式应为 @<clientId>:<sessionId>`);let n={clientId:Number(t[1]),sessionId:Number(t[2])};if(!Number.isSafeInteger(n.clientId)||!Number.isSafeInteger(n.sessionId))throw new ta("INVALID_TARGET_REF",`目标引用 "${e}" 无效;每个 ID 都必须是安全整数`);return n}function tp(e){return`@${e.clientId}:${e.sessionId}:${e.nodeId}`}async function tu(e,t){let n=(await e.getConnectedClients()).find(e=>e.device.clientId===t.clientId),r=n?.sessions.find(e=>e.sessionId===t.sessionId&&th(e));if(!n||!r)throw new ta("STALE_NODE_REF",`节点 ${tp(t)} 所属的会话当前不可用,请重新运行 get-page-tree 获取当前页面的节点`);return{clientId:t.clientId,sessionId:t.sessionId,url:r.url}}async function tf(e,t,n={}){var r,i,o;let a,s,c,l,d,p=n.depth??-1,u=n.maxNodes??5e3;if(!Number.isInteger(p)||p<-1)throw Error("页面树 depth 必须是 -1 或非负整数");if(!Number.isSafeInteger(u)||u<1)throw Error("页面树 maxNodes 必须是正整数");await e.sendCdp(t,"DOM.enable",{useCompression:!1});try{d=await e.sendCdp(t,"DOM.getDocument",{depth:p})}catch{d=await e.sendCdp(t,"DOM.getDocument")}let f=function(e){let t=ty(e);if(!v(t))throw tA("DOM.getDocument","响应不是对象");let n=t.root;if(!0===t.compress&&"string"==typeof n)try{if(n.length>ti)throw Error("压缩根节点超出输入大小限制");n=JSON.parse((0,tn.inflateSync)(Buffer.from(n,"base64"),{maxOutputLength:0x1000000}).toString("utf8"))}catch(e){throw tA("DOM.getDocument","无法解码压缩根节点",e)}else if("string"==typeof n)try{n=JSON.parse(n)}catch(e){throw tA("DOM.getDocument","根节点不是有效的 JSON",e)}if(!v(n))throw tA("DOM.getDocument","缺少根节点");return n}(d),g=await tv(e,t,f,p,u),h=(r=f,i=t,o=u,a=0,s=!1,c=[],{root:(l=e=>{var t;let n=tb(e.nodeId),r="string"==typeof e.nodeName&&e.nodeName?e.nodeName:"unknown";if(void 0===n)throw tA("DOM.getDocument",`节点 ${r} 缺少有效的 nodeId`);a++;let d=[],p={ref:tp({clientId:i.clientId,sessionId:i.sessionId,nodeId:n}),nodeId:n,...void 0===tb(e.backendNodeId)?{}:{backendNodeId:tb(e.backendNodeId)},nodeType:"number"==typeof e.nodeType&&Number.isSafeInteger(e.nodeType)?e.nodeType:0,nodeName:r,..."string"==typeof e.localName?{localName:e.localName}:{},nodeValue:"string"==typeof e.nodeValue?e.nodeValue:"",attributes:function(e){if(!Array.isArray(e))return{};let t={};for(let n=0;n<e.length;n+=2){let r=e[n];if("string"!=typeof r||!r)continue;let i=e[n+1];t[r]="string"==typeof i?i:String(i??"")}return t}(e.attributes),childNodeCount:"number"==typeof e.childNodeCount&&Number.isSafeInteger(e.childNodeCount)?Math.max(0,e.childNodeCount):tI(e).length,children:d};for(let t of(tS(p)&&p.nodeValue&&(p.text=p.nodeValue),tI(e))){if(a>=o){s=!0;break}d.push(l(t))}if("text"===((t=p).localName||t.nodeName).toLowerCase()){let e=function e(t){return t.children.flatMap(t=>tS(t)?[t.nodeValue]:[e(t)]).join("")}(p);e?p.text=e:c.push(p)}return p})(r),nodeCount:a,truncated:s,textCandidates:c});return await tC(e,t,h.textCandidates),{target:t,depth:p,nodeCount:h.nodeCount,truncated:g.truncated||h.truncated,root:h.root}}async function tg(e,t,n,r=[]){let i;await e.sendCdp(t,"DOM.enable",{useCompression:!1});try{i=await e.sendCdp(t,"CSS.getComputedStyleForNode",{nodeId:n.nodeId})}catch(e){var o;if(o=e,/(could not find|cannot find|no such|unknown|invalid|stale).{0,40}node|node.{0,40}(not found|does not exist|invalid|stale)/i.test(o instanceof Error?o.message:String(o)))throw new ta("STALE_NODE_REF",`${tp(n)} 已失效;请重新运行 get-page-tree`,{cause:e});throw e}let a=ty(i);if(!v(a)||!Array.isArray(a.computedStyle))throw tA("CSS.getComputedStyleForNode","缺少 computedStyle 数组");let s=a.computedStyle.filter(v).flatMap(e=>"string"==typeof e.name&&"string"==typeof e.value?[{name:e.name,value:e.value}]:[]),c=0===r.length?s:r.flatMap(e=>{let t=s.find(t=>t.name===e);return t?[t]:[]});return{target:t,nodeRef:tp(n),nodeId:n.nodeId,properties:c}}function th(e){return"lynx"===e.type&&Number.isSafeInteger(e.sessionId)&&e.sessionId>0&&!tw(e.url)}function tm(e){return`${e.clientId}:${e.sessionId}`}function tw(e){return/(?:-main\.js|\.main\.lynx\.js)(?:[?#].*)?$/.test(e)}async function tv(e,t,n,r,i){let o=0,a=!1,s=async(n,c)=>{if(o>=i){a=!0;return}if(o++,r>=0&&c>=r)return;let l=tI(n);if(("number"==typeof n.childNodeCount&&Number.isSafeInteger(n.childNodeCount)?Math.max(0,n.childNodeCount):l.length)>l.length&&"number"==typeof n.nodeId&&Number.isSafeInteger(n.nodeId)){let r=ty(await e.sendCdp(t,"DOM.requestChildNodes",{nodeId:n.nodeId}));if(!v(r)||!Array.isArray(r.nodes))throw tA("DOM.requestChildNodes",`节点 ${n.nodeId} 缺少 nodes 数组`);n.children=l=r.nodes.filter(v)}for(let e of l)if(await s(e,c+1),o>=i){l.indexOf(e)<l.length-1&&(a=!0);break}};return await s(n,0),{truncated:a}}function ty(e){return v(e)&&"id"in e&&"result"in e?e.result:e}function tI(e){return Array.isArray(e.children)?e.children.filter(v):[]}function tb(e){return"number"==typeof e&&Number.isSafeInteger(e)&&e>0?e:void 0}function tS(e){return 3===e.nodeType||"#text"===e.nodeName.toLowerCase()}async function tC(e,t,n){let r=n[0];if(!r)return;let i=await t_(e,t,r);if(i.supported){i.text&&(r.text=i.text);for(let r=1;r<n.length;r+=8){let i=n.slice(r,r+8);await Promise.all(i.map(async n=>{let r=await t_(e,t,n);r.text&&(n.text=r.text)}))}}}async function t_(e,t,n){try{let r=ty(await e.sendCdp(t,"DOM.innerText",{nodeId:n.nodeId}));if(!v(r)||!Array.isArray(r.rawTextValues))return{supported:!1};let i=r.rawTextValues.filter(v).flatMap(e=>"string"==typeof e.text?[e.text]:[]).join("");return{supported:!0,...i?{text:i}:{}}}catch{return{supported:!1}}}function tE(e,t=120){let n=e.replace(/\s+/g," ").trim();return JSON.stringify(n.length>t?`${n.slice(0,Math.max(0,t-1))}…`:n)}function tA(e,t,n){return new ta("INVALID_CDP_RESPONSE",`${e} 返回的响应无效:${t}`,void 0===n?void 0:{cause:n})}async function tD(e,t,n){let r,i,o,a=0,s=!1,c=tm(t),l=new Promise((e,t)=>{i=e,o=t}),d=e=>{s||(s=!0,i({count:a,reason:e}))},p=()=>d("aborted"),u=e.getRuntimeInspectionTarget?.bind(e),f=e=>{if(s||!(Number.isSafeInteger(e.clientId)&&e.clientId>0&&Number.isSafeInteger(e.sessionId)&&e.sessionId>0&&!tw(e.url)))return;let r=tm(e);if(r!==c&&(c=r,r!==tm(t)))try{n.onTargetChange?.(e)}catch{}},g=e.subscribeMessage(e=>{if(s||!t$(e,t))return;let r=function(e){var t;if("Runtime.consoleAPICalled"!==e.method||!v(e.params))return;let n={...t=e.params,...Array.isArray(t.args)?{args:t.args.map(e=>v(e)?{...e}:e)}:{},...v(t.stackTrace)?{stackTrace:{...t.stackTrace,...Array.isArray(t.stackTrace.callFrames)?{callFrames:t.stackTrace.callFrames.map(e=>v(e)?{...e}:e)}:{}}}:{}},r="string"==typeof n.consoleTag?n.consoleTag:void 0;return{type:"string"==typeof n.type?n.type:"log",thread:"Lepus"===r?"main":"background",args:Array.isArray(n.args)?n.args:[],...r?{consoleTag:r}:{},..."number"==typeof n.timestamp?{timestamp:n.timestamp}:{},..."stackTrace"in n?{stackTrace:n.stackTrace}:{},params:n}}(e);if(r){try{n.onMessage(r)}catch(e){s||(s=!0,o(e));return}a++,void 0!==n.limit&&a>=n.limit&&d("limit")}}),h=n.onTargetChange?e.subscribeRuntimeInspectionTarget?.(f):void 0;n.signal?.addEventListener("abort",p,{once:!0}),n.onTargetChange&&u&&u().then(e=>{e&&f(e)}).catch(()=>void 0);try{if(n.signal?.aborted)return d("aborted"),await l;if(await tP(e,t,n.subscriptionWarmupMs??e.eventSubscriptionWarmupMs??5e3,n.signal),s)return await l;for(let i of(void 0!==n.timeoutMs&&(r=setTimeout(()=>d("timeout"),n.timeoutMs)),[{method:"Page.getResourceTree",params:{}},{method:"Debugger.enable",params:{}},{method:"Runtime.enable",params:{}}])){if(s)break;await e.sendCdp(t,i.method,i.params,{expectResponse:!1})}return await l}catch(e){if(n.signal?.aborted)return d("aborted"),await l;throw e}finally{r&&clearTimeout(r),n.signal?.removeEventListener("abort",p),h?.(),g()}}async function tT(e,t,n={}){return tL(t,async()=>{let r,i=new Promise(e=>{r=e}),o=e.subscribeMessage(e=>{let n=t$(e,t)?tR(e):void 0;n&&r(n)}),a=!1;try{var s,c,l;await tP(e,t,e.eventSubscriptionWarmupMs??5e3);let r=n.activeCapture?void 0:e.getLatestScreencastFrame?.(t);!r&&n.activeCapture&&(await e.sendCdp(t,"Page.enable"),a=!0,await e.sendCdp(t,"Page.startScreencast",{format:"jpeg",quality:80},{expectResponse:!1})),r??=await (s=i,c=t,l=n.timeoutMs??1e4,new Promise((e,t)=>{let n=setTimeout(()=>t(new ta("SCREENSHOT_TIMEOUT",`未收到 ${tl(c)} 的 Page.screencastFrame,已等待 ${l} 毫秒;请确认目标会话处于活跃状态且能生成截图帧`)),l);s.then(t=>{clearTimeout(n),e(t)},e=>{clearTimeout(n),t(e)})})),a&&await e.sendCdp(t,"Page.screencastFrameAck",{},{expectResponse:!1}).catch(()=>void 0);let o=function(e){let t=e.replace(/\s+/g,"");if(!t||t.length%4!=0||!/^[A-Za-z0-9+/]+={0,2}$/.test(t))throw new ta("INVALID_SCREENSHOT_DATA","Page.screencastFrame 返回的 Base64 数据无效");let n=Buffer.from(t,"base64");if(n.length<4||255!==n[0]||216!==n[1]||255!==n[n.length-2]||217!==n[n.length-1])throw new ta("INVALID_SCREENSHOT_DATA","Page.screencastFrame 未返回完整的 JPEG 图片");let r=function(e){let t=new Set([192,193,194,195,197,198,199,201,202,203,205,206,207]),n=2;for(;n+3<e.length;){if(255!==e[n]){n++;continue}for(;n<e.length&&255===e[n];)n++;let r=e[n++];if(void 0===r||217===r||218===r)break;if(1===r||r>=208&&r<=215)continue;if(n+1>=e.length)break;let i=e.readUInt16BE(n);if(i<2||n+i>e.length)break;if(t.has(r)){if(i<7)break;let t=e.readUInt16BE(n+3),r=e.readUInt16BE(n+5);if(r>0&&t>0)return{width:r,height:t};break}n+=i}}(n);if(!r)throw new ta("INVALID_SCREENSHOT_DATA","无法读取 Page.screencastFrame 返回的 JPEG 图片尺寸");return{buffer:n,data:t,...r}}(r.data);return{data:o.data,format:"jpeg",source:"Page.screencastFrame",width:o.width,height:o.height,byteLength:o.buffer.length}}finally{a&&await e.sendCdp(t,"Page.stopScreencast",{},{expectResponse:!1}).catch(()=>void 0),o()}})}function t$(e,t){return"CDP"===e.messageType&&e.clientId===t.clientId&&e.sessionId===t.sessionId}async function tP(e,t,n,r){let i;if(n<=0)return;let o=Date.now()+n,a=new Promise(e=>{i=e}),s=e.subscribeMessage(e=>{t$(e,t)&&i()});try{for(;Date.now()<o;){if(tM(r),await e.sendCdp(t,"Page.getResourceTree",{},{expectResponse:!1}).catch(()=>void 0),await function(e,t,n){return new Promise((r,i)=>{let o=new AbortController,a=setTimeout(()=>{o.abort(),r(!1)},t);n?.addEventListener("abort",()=>{clearTimeout(a),o.abort(),i(n?.reason instanceof Error?n.reason:Error("操作已取消"))},{once:!0,signal:o.signal}),e.then(()=>{clearTimeout(a),o.abort(),r(!0)},e=>{clearTimeout(a),o.abort(),i(e)})})}(a,Math.min(250,Math.max(0,o-Date.now())),r))return;await tV(Math.min(50,Math.max(0,o-Date.now())),r)}}finally{s()}}function tN(e){return v(e)?e.objectId?`<${String(e.description||e.className||"Object")} (objectId:${String(e.objectId)})>`:"value"in e?tx(e.value):"string"==typeof e.description?e.description:tx(e):tx(e)}function tx(e){if("string"==typeof e)return e;if(void 0===e)return"undefined";try{let t=JSON.stringify(e);return void 0===t?String(e):t}catch{return String(e)}}function tk(e){return/is not (found|available)/i.test(e instanceof Error?e.message:String(e))}async function tO(e,t){let n=Date.now()+t;for(;;)try{return await e()}catch(e){if(!tk(e)||Date.now()>=n)throw e;await tV(50)}}function tR(e){if("Page.screencastFrame"===e.method&&v(e.params)&&"string"==typeof e.params.data&&e.params.data)return{data:e.params.data}}async function tL(e,t){let n,r=tm(e),i=to.get(r)??Promise.resolve(),o=new Promise(e=>{n=e});to.set(r,o),await i.catch(()=>void 0);try{return await t()}finally{n(),to.get(r)===o&&to.delete(r)}}function tM(e){if(e?.aborted)throw e.reason instanceof Error?e.reason:Error("操作已取消")}async function tV(e,t){try{await (0,n.setTimeout)(e,void 0,{signal:t})}catch(e){throw tM(t),e}}let tj=e("node:util"),tU=[{command:"web",description:"打开 Web 模拟器"},{command:"desktop",description:"进入桌面端工具,可进行真机调试"},{command:"status",description:"查看本地调试服务状态"}],tF=[{command:"qr",description:"重新生成真机调试二维码"},{command:"page [url]",description:"在真机打开页面(省略 url 可选择)"},{command:"pages",description:"列出真机可打开页面"},{command:"widget [id]",description:"向真机推送卡片(省略 id 可选择)"},{command:"widgets",description:"列出真机可推送卡片"},{command:"sessions",description:"列出当前可检查的 Lynx 会话"},{command:"use-session <@client:session|latest>",description:"固定 CLI 会话或恢复跟随最新会话"},{command:"get-console",description:"持续输出当前 Lynx 页面新产生的日志"},{command:"take-screenshot",description:"截取当前 Lynx 页面画面"},{command:"get-page-tree",description:"获取当前 Lynx 页面的 DOM 树"},{command:"get-computed-style [node-ref]",description:"获取 DOM 节点的计算样式"},{command:"back",description:"返回主命令"}];function tK(e,t){if("true"===e)return!0;if("false"===e)return!1;throw Error(`${t} 必须为 "true" 或 "false"`)}async function tB(e){let t,n,r,i,o=e.output??process.stderr,a=e.client??await u({projectPath:e.projectPath,appDir:e.appDir,nodeIdPrefix:"dev-shell"}),s=e.closeDeviceApp??eM,c=new AbortController,l=e.openBrowser??K,d=new Set,p={runtime:e.runtime,client:a,output:o,manageDeviceApp:!0,runtimeInspectionTargetPolicy:{kind:"latest"},openBrowser:l,openQRCodeViewer:e.openQRCodeViewer??((e,t,n)=>te(e,l,t,o,n)),signal:c.signal,closeDeviceApp:s,prepareDeviceApp:e.prepareDeviceApp??(e=>eO(o,e)),...e.onDeviceAppSetupProgress?{onDeviceAppSetupProgress:e.onDeviceAppSetupProgress}:{},openPreparedDeviceApp:e.openPreparedDeviceApp??eL,runDeviceDebugAuth:e.runDeviceDebugAuth??eZ,...e.deviceDebugCoordinator?{deviceDebugCoordinator:e.deviceDebugCoordinator}:{},...e.createRuntimeInspectionSession?{createRuntimeInspectionSession:e.createRuntimeInspectionSession}:{},listAppVersions:e.listAppVersions??(async e=>{let t=await O(e);return t.data?.version_list??[]}),selectItem:e.selectItem,eventTracking:e.eventTracking},f=(e.createRuntimeInspectionSession??ts)({namespace:e.runtime.getState().namespace,nodeIdPrefix:"dev-shell-runtime-inspection"});f.catch(()=>void 0),p.runtimeInspectionSession=f;let g=async()=>r||(r=(async()=>{p.activeDeviceId=void 0,e7(),p.manageDeviceApp&&await tG(p)})().finally(()=>{r=void 0})),h=eH(e.runtime.getState().namespace,async e=>{if(p.activeDeviceId&&!i&&e===p.activeClientId){np(o,"检测到真机连接断开,正在返回主命令并清理真机调试资源..."),await g();for(let e of d)try{e("client-disconnected")}catch{}}});return await h.start(),{stopped:e.runtime.stopped,getState:()=>e.runtime.getState(),execute(e){let r=new AbortController,i=AbortSignal.any([c.signal,r.signal]);n=r,p.signal=i;let o=tq(e,p);return t=o,o.finally(()=>{t===o&&(t=void 0),n===r&&(n=void 0),p.signal===i&&(p.signal=c.signal)})},cancelActiveCommand(){if(!n||n.signal.aborted)return!1;let e=Error("命令已取消");return e.name="AbortError",n.abort(e),!0},returnToRoot:()=>tH(p,"back","execute",g),subscribe:e=>(d.add(e),()=>{d.delete(e)}),close:()=>i??=(async()=>{c.abort(new eB),await t?.catch(()=>void 0),await h.stop().catch(()=>void 0),await g(),await p.runtimeInspectionSession?.then(e=>e.stop()).catch(()=>void 0),await a.stop().catch(()=>void 0),await e.runtime.stop().catch(()=>void 0)})()}}async function tq(e,t){var n;let r;try{r=function(e){let t,n=[],r="",i=!1,o=()=>{r.length>0&&(n.push(r),r="")};for(let n of e.trim()){if(i){r+=n,i=!1;continue}if("\\"===n&&"'"!==t){i=!0;continue}if("'"===n||'"'===n){if(!t){t=n;continue}if(t===n){t=void 0;continue}}if(!t&&/\s/.test(n)){o();continue}r+=n}if(i&&(r+="\\"),t)throw Error(`${t} 引号未闭合`);return o(),n}(e)}catch(e){return np(t.output,e6(nf(e))),"continue"}let i=r[0]?.toLowerCase(),o=r.slice(1);if(!i)return"continue";if((n=o).includes("--help")||n.includes("-h")){let e="desktop"===i&&o[0]&&!o[0].startsWith("-")?`desktop ${o[0].toLowerCase()}`:i;if(function(e,t){switch(t){case"desktop widget":return np(e,"用法:widget [widget-id] [--data <json>] [--bot-id <id>] [--device-id <id>]"),np(e,"推送卡片到已连接真机;省略 widget-id 时从 `widgets` 列表中选择。"),!0;case"desktop page":return np(e,"用法:page [url] [--device-id <id>]"),np(e,"通过完整 URL 打开页面;省略 url 时从 `pages` 列表中选择。页面参数请写入 URL 查询参数。"),!0;case"desktop":np(e,"用法:desktop [--agent] [--ui-only] [--timeout <seconds>] [--qr-file <file.png>] [--usb-connect <true|false>] [--wifi-connect <true|false>] [--defaultDebugTagState <true|false>]"),np(e,"进入真机模式并连接调试设备,默认准备并打开豆包开发者工具。"),np(e,C.bold.green("当前默认使用局域网连接")),np(e,"使用 `desktop --agent` 进入 Agent 模式,不准备、启动或关闭豆包开发者工具。"),np(e,"默认从当前 AppID 的版本列表中选择 versionTag 进行 MCP 端到端调试;没有可选版本时,生成不带 versionTag 的二维码。"),np(e,"兼容旧写法 `desktop --mcp`,行为与 `desktop` 相同。"),np(e,"使用 --ui-only 跳过版本查询和选择,生成不带 versionTag 的二维码;可与 --agent 组合,不能与 --mcp 同时使用。"),np(e,"使用 --usb-connect true 切换为 USB 传输,需要连接 USB 线并开启 USB 调试。");for(let t of(np(e,"真机调试命令"),tF))np(e,` ${t.command.padEnd(22)}${t.description}`);return np(e,"进入真机模式后执行 `<命令> --help` 查看参数。"),np(e,"get-page-tree、get-computed-style、take-screenshot 支持通用的 --json 输出。"),!0;case"desktop qr":return np(e,"用法:qr [--timeout <seconds>] [--qr-file <file.png>] [--usb-connect <true|false>] [--wifi-connect <true|false>] [--defaultDebugTagState <true|false>]"),np(e,"重新生成真机调试二维码,沿用 desktop 的调试模式和 versionTag(未选版本时不携带),不重新查询或选择版本。"),np(e,"使用 --usb-connect true 切换为 USB 传输,需要连接 USB 线并开启 USB 调试。"),!0;case"desktop get-console":return np(e,"用法:get-console [--target <@client:session>] [--limit <count>] [--timeout-seconds <seconds>] [--include-stack-traces]"),np(e,"持续输出当前 Lynx 会话新产生的控制台日志;按 Ctrl+C 停止监听并返回真机命令。"),np(e,"默认仅错误日志显示调用栈;使用 --include-stack-traces 展开所有日志的调用栈。"),!0;case"desktop sessions":return np(e,"用法:sessions"),np(e,"列出当前可检查的 Lynx 会话,并标记最新会话、CLI 固定会话和 Electron 当前会话。"),!0;case"desktop use-session":return np(e,"用法:use-session <@client:session|latest>"),np(e,"固定 CLI 后续检查命令使用的会话,或用 latest 恢复到已认证客户端内最新活跃会话;不会切换 Electron。"),!0;case"desktop take-screenshot":return np(e,"用法:take-screenshot [--target <@client:session>] [-o, --output <file.jpeg>] [--json]"),np(e,"保存 Electron 当前为目标会话输出的最近一帧 JPEG;截图范围跟随 Electron 当前模式。"),!0;case"desktop get-page-tree":return np(e,"用法:get-page-tree [--target <@client:session>] [--depth <-1|n>] [--json]"),np(e,"获取当前 Lynx 会话的 DOM 树(开发者工具元素面板);默认 depth=-1。"),np(e,"终端输出紧凑树;--json 输出节点文本、完整属性和可复用的节点引用 node-ref。"),!0;case"desktop get-computed-style":return np(e,"用法:get-computed-style <node-ref> [--properties <name,...>] [--json]"),np(e,"获取元素节点的计算样式;node-ref 格式为 @<clientId>:<sessionId>:<nodeId>。"),np(e,"省略 --properties 返回全部属性,例如 --properties color,font-size。"),!0;case"web":return np(e,"用法:web"),np(e,"在默认浏览器打开本地 Web 模拟器。"),!0;case"desktop pages":case"desktop widgets":{let n="desktop pages"===t?"打开的页面":"推送的卡片";return np(e,`用法:${t.slice(8)}`),np(e,`列出真机可${n}。`),!0}case"status":return np(e,"用法:status"),np(e,"查看本地调试服务状态。"),!0;default:return!1}}(t.output,e))return"continue"}try{switch(i){case"status":return await tH(t,"status","execute",()=>tQ(t)),"continue";case"web":return await tH(t,"web_open","execute",()=>tz(t)),"continue";case"desktop":return await tW(t,o)?"enter-device":"continue";case"device":return np(t.output,"命令 `device` 已更名为 `desktop`,请改用 `desktop`。"),"continue";default:return np(t.output,`未知命令:${i}`),["qr","pages","page","widgets","widget","sessions","use-session","get-console","take-screenshot","get-page-tree","get-computed-style"].includes(i)&&np(t.output,`\`${i}\` 仅可在桌面模式下使用;请先运行 \`desktop\`。`),"continue"}}catch(e){return np(t.output,e6(nf(e))),"continue"}}async function tH(e,t,n,r){let i=e.eventTracking;return i?V({action:t,actionSequence:++i.actionSequence,appId:i.appId??e.runtime.getState().appId,devSessionId:i.devSessionId,errorStage:n},r):r()}async function tW(e,t){var n;let r=t[0]?.toLowerCase();if(!r||r.startsWith("-"))return void 0!==await tJ(e,t,{reuseDeviceAppMode:!1,reuseVersionTag:!1});let i={args:(n=t.slice(1)).filter(e=>"--json"!==e),json:n.includes("--json")},a=["get-page-tree","get-computed-style","take-screenshot"].includes(r);try{if(i.json&&!a)throw Error(`desktop ${r} 不支持 --json;请搭配 get-page-tree、get-computed-style 或 take-screenshot 使用`);switch(r){case"qr":return await t1(e,i.args)!==void 0;case"pages":return await tH(e,"pages_list","execute",()=>t2(e,"page",o.discoverPages)),!0;case"page":return await tH(e,"page_push","page_push",()=>nr(e,i.args)),!0;case"widgets":return await tH(e,"widgets_list","execute",()=>t2(e,"widget",o.discoverWidgets)),!0;case"widget":return await tH(e,"widget_push","widget_push",()=>ni(e,i.args)),!0;case"sessions":return await tH(e,"sessions_list","execute",()=>t6(e,i.args)),!0;case"use-session":return await tH(e,"session_select","execute",()=>t5(e,i.args)),!0;case"get-console":return await tH(e,"console_stream","execute",()=>t3(e,i.args)),!0;case"take-screenshot":return await tH(e,"screenshot","execute",()=>t4(e,i.args,i.json)),!0;case"get-page-tree":return await tH(e,"page_tree","execute",()=>t8(e,i.args,i.json)),!0;case"get-computed-style":return await tH(e,"computed_style","execute",()=>t7(e,i.args,i.json)),!0;default:return np(e.output,`未知 desktop 子命令:${r}`),!1}}catch(t){if(!i.json||!a)throw t;return nu(e.output,{ok:!1,error:{code:t instanceof ta?t.code:"INSPECTION_FAILED",message:nf(t)}}),!0}}async function tG(e){try{var t,n;let r=await e.closeDeviceApp();t=e.output,n=r,"closed"===n.status?np(t,`豆包开发者工具已关闭:${n.appPath}`):np(t,`关闭豆包开发者工具失败${n.reason?`:${e6(n.reason)}`:""}`)}catch(t){np(e.output,`关闭豆包开发者工具失败:${e6(nf(t))}`)}}async function tQ(e){let t=await e.client.call(o.getInfo);np(e.output,`状态:${{starting:"启动中",running:"运行中",stopping:"停止中",stopped:"已停止",failed:"失败",error:"错误"}[t.status]??t.status}`),np(e.output,`app_id: ${t.appId??"-"}`),np(e.output,`开发服务:${t.host??"-"}`),np(e.output,`Web 模拟器:${t.webDebuggerUrl??"-"}`)}async function tz(e){let t=await e.client.call(o.openWebDebugger);np(e.output,`Web 模拟器已打开:${t}`)}async function tJ(e,t,n){let r=e.eventTracking;if(!r)return tZ(e,t,n);let i=++r.actionSequence,o=performance.now(),a=n.reuseDeviceAppMode?"qr_refresh":"device_connect";try{let s=await tZ(e,t,n),c=s?.status==="connected"?"success":void 0===s||"cancelled"===s.status?"cancelled":s?.status==="timeout"?"timeout":s?.error?"failed":"skipped";return await F({action:a,actionSequence:i,appId:r.appId??e.runtime.getState().appId,devSessionId:r.devSessionId,durationMs:performance.now()-o,...s?.error?{error:s.error,...s.failureStage?{errorStage:s.failureStage}:{},errorType:"device_connection_error"}:{},status:c}),s}catch(t){throw await F({action:a,actionSequence:i,appId:r.appId??e.runtime.getState().appId,devSessionId:r.devSessionId,durationMs:performance.now()-o,error:t,errorStage:"prepare_device_tool",errorType:"device_connection_error",status:R(t)}),t}}async function tZ(e,t,n){var r;let i,o=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{agent:{type:"boolean"},timeout:{type:"string"},"qr-file":{type:"string"},mcp:{type:"boolean"},"ui-only":{type:"boolean"},"usb-connect":{type:"string"},"wifi-connect":{type:"string"},defaultDebugTagState:{type:"string"}}});if(n.reuseVersionTag&&(o.values["ui-only"]||o.values.mcp))throw Error("qr 沿用 desktop 的调试模式,不支持 --mcp 或 --ui-only");if(o.values["ui-only"]&&o.values.mcp)throw Error("--ui-only 与 --mcp 不能同时使用");if(n.reuseDeviceAppMode&&o.values.agent)throw Error("--agent 仅支持在进入桌面模式时使用");let a=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error("--timeout 必须是正数,单位为秒");return Math.round(1e3*t)}(o.values.timeout),s=function(e){if(!e)return;let t=Y().resolve(e);if(".png"!==Y().extname(t).toLowerCase())throw Error("--qr-file 必须指向 .png 文件");return t}(o.values["qr-file"]),c=e1((r={defaultDebugTagState:o.values.defaultDebugTagState,usbConnect:o.values["usb-connect"],wifiConnect:o.values["wifi-connect"]},i={},void 0!==r.defaultDebugTagState&&(i.defaultDebugTagState=tK(r.defaultDebugTagState,"--defaultDebugTagState")),void 0!==r.usbConnect?i.usb=tK(r.usbConnect,"--usb-connect"):void 0!==r.wifiConnect&&(i.usb=!tK(r.wifiConnect,"--wifi-connect")),Object.keys(i).length>0?i:void 0)),l=e.runtime.getState(),d=!!o.values["ui-only"],p=!d&&!n.reuseVersionTag,u=d?void 0:e.activeVersionTag;if(p){let t=await tY(e,l.appId);if("cancelled"===t.status)return;u="selected"===t.status?t.versionTag:void 0}e.signal?.throwIfAborted(),d&&np(e.output,"已启用 --ui-only:跳过版本查询,二维码不携带 versionTag。");let f=()=>tX(e,{state:l,versionTag:u,timeoutMs:a,qrFilePath:s,settings:c,manageDeviceApp:n.reuseDeviceAppMode?e.manageDeviceApp:!o.values.agent,enteringDeviceMode:!n.reuseDeviceAppMode,reuseVersionTag:!p});return e.deviceDebugCoordinator?e.deviceDebugCoordinator.runTerminal(async t=>{let n=e.signal;e.signal=n?AbortSignal.any([n,t]):t;try{return await f()}finally{e.signal=n}}):f()}async function tX(e,t){let n,r,{state:i,versionTag:a,timeoutMs:s,qrFilePath:c,settings:l}=t;e.signal?.throwIfAborted();let d=await e.client.call(o.setConnectionTransport,{type:l.usb?"usb":"wifi",...void 0===a?{}:{versionTag:a}});e.manageDeviceApp=t.manageDeviceApp,e.activeVersionTag=a,a&&t.reuseVersionTag&&np(e.output,`沿用 MCP 端到端调试 versionTag:${a}`),t.enteringDeviceMode&&!l.usb&&np(e.output,C.bold.green("当前默认使用局域网连接")),e.manageDeviceApp||np(e.output,"已启用 --agent:不会准备、启动或关闭豆包开发者工具。");let p=e.manageDeviceApp?await t0(e):void 0;if(p?.status==="skipped"){let t=p.reason??"豆包开发者工具准备失败";return np(e.output,`启动真机调试失败:${e6(t)}`),{ok:!1,status:"skipped",timeoutMs:s??6e4,failureStage:"prepare_device_tool",error:t}}e7();let u=new AbortController,f=e.signal?AbortSignal.any([e.signal,u.signal]):u.signal;try{r=await e.runDeviceDebugAuth({hostUrl:d.host||i.host,appKey:d.appId||i.appId,versionTag:a,namespace:i.namespace,timeoutMs:s,settings:l,wifiConnectUrl:d.wifiConnectUrl,output:e.output,signal:f,onQRCodeReady:async(t,r)=>{(n=await e.openQRCodeViewer(t,c,r)).closed.then(()=>{u.abort(new eB)})}})}finally{await n?.close({status:r?.status??"exception",failureStage:r?.failureStage,waitingFor:r?.waitingFor}).catch(()=>void 0),e7()}if(function(e,t){let n;if(t.ok){let n=t.client?.clientId===void 0?"":`:客户端 ${t.client.clientId}`,r=t.qrCodeValue?"扫码鉴权完成":"复用已连接设备,已跳过二维码鉴权";np(e,`真机调试已连接${n}(${r})。`);return}"cancelled"===t.status?np(e,"install"===t.waitingFor?"二维码页面已关闭,已取消等待设备安装。":"二维码页面已关闭,已取消等待设备连接。"):(n="timeout"===t.status?"install"===t.waitingFor?`设备已连接,但等待安装完成超时(${Math.max(1,Math.ceil(t.timeoutMs/1e3))} 秒)`:`等待设备连接超时(${Math.max(1,Math.ceil(t.timeoutMs/1e3))} 秒)`:e6(t.error??"未知错误"),np(e,`启动真机调试失败:${n}`))}(e.output,r),r.ok&&"connected"===r.status){r.client?.clientId!==void 0&&(void 0!==e.activeClientId&&e.activeClientId!==r.client.clientId&&(e.runtimeInspectionTargetPolicy={kind:"latest"}),e.activeClientId=r.client.clientId);let t=r.client?.deviceId??(r.client?.clientId===void 0?void 0:String(r.client.clientId));t&&(e.activeDeviceId=t)}return p&&r.ok&&"connected"===r.status&&(p.appPath?(await e.openPreparedDeviceApp(p.appPath,eR(i)),np(e.output,`豆包开发者工具已启动:${p.appPath}`)):np(e.output,`启动豆包开发者工具失败${p.reason?`:${e6(p.reason)}`:""}`)),r}async function tY(e,t){if(!t)throw Error("无法查询 versionTag,当前工程缺少 AppID。");let n=(await e.listAppVersions(t)).filter(e=>"string"==typeof e.version_tag&&!!e.version_tag.trim());if(e.signal?.throwIfAborted(),!n.length)return np(e.output,`当前 AppID(${t})没有可选版本,将生成不带 versionTag 的二维码。`),{status:"unversioned"};let r=await e.selectItem("versionTag",n,e.output);return r?(np(e.output,`MCP 端到端调试 versionTag:${r}`),{status:"selected",versionTag:r}):(np(e.output,"已取消 versionTag 选择,未生成二维码。"),{status:"cancelled"})}async function t0(e){e.onDeviceAppSetupProgress?.(void 0);try{return await e.prepareDeviceApp({onProgress:eN(e.output,e.onDeviceAppSetupProgress),signal:e.signal})}catch(t){return e.onDeviceAppSetupProgress?.(void 0),{status:"skipped",reason:nf(t)}}}async function t1(e,t){return tJ(e,t,{reuseDeviceAppMode:!0,reuseVersionTag:!0})}async function t2(e,t,n){let r=await e.client.call(n);if(!r.length)return void np(e.output,`未找到${"page"===t?"页面":"卡片"}`);for(let n of r)np(e.output,`- ${nl(t,n)}`)}async function t6(e,t){if(t.length>0)throw Error("sessions 不接受参数");let n=await nn(e,"sessions"),{session:r}=n;try{let t=await r.getConnectedClients();if(0===t.length)throw new ta("DEVICE_NOT_CONNECTED","未连接调试设备");let n=t.flatMap(e=>e.sessions.filter(th).map(t=>({clientId:e.device.clientId,sessionId:t.sessionId,url:t.url}))).sort((e,t)=>e.clientId-t.clientId||t.sessionId-e.sessionId);if(0===n.length)throw new ta("NO_ACTIVE_LYNX_SESSION","已连接的设备没有活跃的 Lynx 会话");let i=r.getRuntimeInspectionTarget?await r.getRuntimeInspectionTarget().catch(()=>null):null,o=t9(e),a=e.activeClientId??(1===t.length?t[0]?.device.clientId:void 0),s=void 0===a?void 0:n.find(e=>e.clientId===a);for(let t of n){let n=[ne(t,i)?"electron":void 0,"fixed"===o.kind&&ne(t,o.target)?"cli":void 0,ne(t,s)?"latest":void 0].filter(e=>void 0!==e);np(e.output,`${tl(t)}${n.length?` ${n.map(e=>`[${e}]`).join(" ")}`:""} ${t.url||"未知地址"}`)}}finally{n.owned&&await r.stop().catch(()=>void 0)}}async function t5(e,t){if(1!==t.length)throw Error("use-session 需要传入 @<clientId>:<sessionId> 或 latest");if(t[0]?.toLowerCase()==="latest"){e.runtimeInspectionTargetPolicy={kind:"latest"},np(e.output,C.bold.blueBright(`CLI 调试目标已恢复为 latest(跟随最新会话)${void 0===e.activeClientId?"":`(客户端 ${e.activeClientId} 内最新活跃的 Lynx 会话)`};不会切换 Electron。`));return}let n=td(t[0]??""),r=await nn(e,"use-session"),{session:i}=r;try{let t=await tc(i,{activeClientId:e.activeClientId,explicitTarget:n,signal:e.signal});e.runtimeInspectionTargetPolicy={kind:"fixed",target:{clientId:t.clientId,sessionId:t.sessionId}},np(e.output,C.bold.blueBright(`CLI 调试目标已固定为 ${tl(t)}(${t.url||"未知地址"});不会切换 Electron。`))}finally{r.owned&&await i.stop().catch(()=>void 0)}}async function t3(e,t){let n=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{limit:{type:"string"},"timeout-seconds":{type:"string"},"include-stack-traces":{type:"boolean"},target:{type:"string"}}}),r=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isSafeInteger(t)||t<1||t>100)throw Error("--limit 必须是 1 到 100 之间的整数");return t}(n.values.limit),i=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error("--timeout-seconds 必须是正数");return Math.round(1e3*t)}(n.values["timeout-seconds"]),o=await nn(e,"get-console"),{session:a}=o;try{let t=await nt(e,a,n.values.target);np(e.output,C.bold.blueBright(`正在监听客户端 ${t.clientId}、会话 ${t.sessionId}(${t.url||"未知地址"})的新日志;按 Ctrl+C 停止监听。`));let o=await tD(a,t,{...void 0===r?{}:{limit:r},...void 0===i?{}:{timeoutMs:i},signal:e.signal,onTargetChange(n){np(e.output,C.bold.blueBright(`提示:Electron 已切换到客户端 ${n.clientId}、会话 ${n.sessionId}(${n.url||"未知地址"});当前 CLI 仍监听客户端 ${t.clientId}、会话 ${t.sessionId},不会自动跟随 Electron。`))},onMessage(t){np(e.output,function(e,t={}){var n;let r=e.args.map(tN).join(" "),i=t.includeStackTraces||"error"===e.type?(n=e.stackTrace,v(n)&&Array.isArray(n.callFrames)?n.callFrames.filter(v).map(e=>{let t="string"==typeof e.url?e.url:"",n="number"==typeof e.lineNumber?e.lineNumber:"unknown",r="number"==typeof e.columnNumber?e.columnNumber:"unknown";return` at ${t}:${n}:${r}`}).join("\n"):""):"";return`[${e.type}/${e.thread}] ${r}${i?`
|
|
44
|
-
${i}`:""}`}(t,{includeStackTraces:n.values["include-stack-traces"]}))}});
|
|
45
|
-
`)}function nu(e,t){np(e,JSON.stringify(t))}function nf(e){return e instanceof Error?e.message:String(e)}let ng=new Set(["preparing","downloading","installing_tool","reusing_client","waiting_for_scan","waiting_for_install","launching_tool"]),nh=new J.Writable({write(e,t,n){n()}});class nm{options;provider;state={revision:0,phase:"idle",canCancel:!1,canRetry:!1};activeOperation;controlClient;controlClientPromise;disconnectWatcher;qrImages;qrRevision=0;deviceAppOpened=!1;deviceAppClosePromise;disposed=!1;dependencies;constructor(e){this.options=e,this.dependencies={connectClient:u,prepareDeviceApp:eO,runAuth:eZ,renderQRCodes:e8,openDeviceApp:eL,closeDeviceApp:eM,createDisconnectWatcher:eH,...e.dependencies},this.provider={getState:()=>this.getState(),start:()=>this.startWeb(),cancel:e=>this.cancelWeb(e),getQrImage:(e,t)=>this.getQrImage(e,t)}}async runTerminal(e){if(this.disposed)throw Error("DEV_RUNTIME_UNAVAILABLE: 本地调试服务已停止");if(this.activeOperation&&this.isActive())throw Error("REAL_DEVICE_DEBUG_BUSY: Web 或终端已有真机调试流程正在运行。");let t={id:eC().randomUUID(),owner:"terminal",abortController:new AbortController};this.activeOperation=t,this.clearQrImages(),this.replaceState({operationId:t.id,owner:"terminal",phase:"preparing",connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!1});let n=Promise.resolve().then(async()=>(await this.stopDisconnectWatcher(),await this.closeOwnedDeviceApp(),t.abortController.signal.throwIfAborted(),e(t.abortController.signal)));t.promise=n.then(()=>void 0,()=>void 0);try{return await n}finally{this.activeOperation===t&&(this.activeOperation=void 0,this.replaceState({phase:"idle",operationId:void 0,owner:void 0,connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!1}))}}async dispose(){if(this.disposed)return;this.disposed=!0;let e=this.activeOperation;e?.abortController.abort(Error("dev runtime stopped")),await e?.promise?.catch(()=>void 0),this.activeOperation=void 0,this.clearQrImages(),await this.stopDisconnectWatcher(),await this.closeOwnedDeviceApp();let t=await this.controlClientPromise?.catch(()=>void 0);await (t??this.controlClient)?.stop().catch(()=>void 0),this.controlClient=void 0,this.controlClientPromise=void 0}getState(){return{...this.state,...this.state.progress?{progress:{...this.state.progress}}:{},...this.state.qr?{qr:{...this.state.qr}}:{},...this.state.error?{error:{...this.state.error}}:{}}}startWeb(){if(this.disposed)return this.fail("DEV_RUNTIME_UNAVAILABLE","runtime","本地调试服务已停止,请重新运行 dbx dev。"),this.getState();if("connected"===this.state.phase||this.activeOperation&&this.isActive())return this.getState();let e={id:eC().randomUUID(),owner:"web",abortController:new AbortController};return this.activeOperation=e,this.clearQrImages(),this.replaceState({operationId:e.id,owner:"web",phase:"preparing",connectionMode:void 0,deadlineAt:void 0,canCancel:!0,canRetry:!1}),e.promise=this.runWebOperation(e).finally(()=>{this.activeOperation===e&&(this.activeOperation=void 0)}),e.promise.catch(()=>void 0),this.getState()}async cancelWeb(e){let t=this.activeOperation;return t&&t.id===e&&"web"===t.owner&&this.isActive()&&(t.abortController.abort(Error("真机调试已取消")),await t.promise?.catch(()=>void 0)),this.getState()}async getQrImage(e,t){if(this.state.operationId!==e||"waiting_for_scan"!==this.state.phase)return;let n=this.qrImages?.[t];return n?{body:new Uint8Array(n),contentType:"image/png"}:void 0}async runWebOperation(e){let{signal:t}=e.abortController,n=!1;try{await this.deviceAppClosePromise,t.throwIfAborted();let r=await this.options.getRuntime();t.throwIfAborted();let i=r.getState();if("running"!==i.status)throw new nw("DEV_RUNTIME_UNAVAILABLE","runtime","本地调试服务尚未就绪,请稍后重试。");let o=await this.getControlClient();t.throwIfAborted();let a=await o.call("dev.setConnectionTransport",{type:"wifi"});t.throwIfAborted();let s=await this.dependencies.prepareDeviceApp(nh,{signal:t,onProgress:t=>this.handlePreparationProgress(e,t)});if(t.throwIfAborted(),"skipped"===s.status||!s.appPath){let e="UNSUPPORTED_PLATFORM"===s.reasonCode||s.reason?.includes("not supported");throw new nw(e?"UNSUPPORTED_PLATFORM":"TOOL_PREPARE_FAILED","prepare",e?"当前系统暂不支持自动准备豆包开发者工具。":"豆包开发者工具准备失败,请重试或使用终端 desktop 查看详情。")}let c=Date.now()+6e4;this.patchState(e,{deadlineAt:c});let l=await this.dependencies.runAuth({hostUrl:a.host||i.host,appKey:a.appId||i.appId,namespace:i.namespace,timeoutMs:6e4,settings:{usb:!1,defaultDebugTagState:!0},wifiConnectUrl:a.wifiConnectUrl,output:nh,signal:t,onPhaseChange:t=>{if("reusing_client"===t){this.clearQrImages(),this.patchState(e,{phase:t,connectionMode:"existing_client"});return}"waiting_for_scan"===t?this.patchState(e,{phase:t,connectionMode:"qr"}):(this.clearQrImages(),this.patchState(e,{phase:t}))},onQRCodeReady:async(n,r)=>{let i=await this.dependencies.renderQRCodes(n,r);t.throwIfAborted(),this.isCurrent(e)&&(this.qrImages=i,this.qrRevision+=1,this.patchState(e,{phase:"waiting_for_scan",connectionMode:"qr",qr:{revision:this.qrRevision,modernAvailable:!!i.modern,legacyAvailable:!0}}))}});if(t.throwIfAborted(),!l.ok||"connected"!==l.status){if("cancelled"===l.status)return void this.cancelled(e);if("timeout"===l.status){this.clearQrImages(),this.replaceOperationState(e,{phase:"timed_out",canCancel:!1,canRetry:!0,error:{code:"install"===l.waitingFor?"PACKAGE_INSTALL_TIMEOUT":"CONNECTION_TIMEOUT",stage:"install"===l.waitingFor?"package_install":"connection",message:"install"===l.waitingFor?"设备已连接,但安装调试包超时,请重试。":"等待扫码连接超时,请重新生成二维码。"}});return}let t="waiting_for_scan"===this.state.phase||"reusing_client"===this.state.phase;throw new nw("install"===l.waitingFor?"PACKAGE_INSTALL_FAILED":t?"REAL_DEVICE_DEBUG_FAILED":"TICKET_FAILED","install"===l.waitingFor?"package_install":t?"connection":"ticket","install"===l.waitingFor?"调试包安装失败,请检查客户端提示后重试。":t?"设备连接失败,请重新扫码。":T({code:l.errorCode})??"二维码创建失败,请稍后重试。")}if(this.clearQrImages(),this.patchState(e,{phase:"launching_tool",qr:void 0}),await this.dependencies.openDeviceApp(s.appPath,eR(i)),n=!0,this.deviceAppOpened=!0,t.throwIfAborted(),await this.watchForDisconnect(e,i.namespace,l.client?.clientId),t.throwIfAborted(),"failed"===this.state.phase)return;this.replaceOperationState(e,{phase:"connected",deadlineAt:void 0,canCancel:!1,canRetry:!1})}catch(i){if(t.aborted){await this.stopDisconnectWatcher(),n&&this.deviceAppOpened&&await this.closeOwnedDeviceApp(),this.cancelled(e);return}let r=i instanceof nw?i:new nw("launching_tool"===this.state.phase?"TOOL_LAUNCH_FAILED":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"TOOL_PREPARE_FAILED":"REAL_DEVICE_DEBUG_FAILED","launching_tool"===this.state.phase?"launch":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"prepare":"connection","launching_tool"===this.state.phase?"豆包开发者工具启动失败,请重试。":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"豆包开发者工具准备失败,请重试或使用终端 desktop 查看详情。":"真机调试启动失败,请重试。");this.clearQrImages(),this.replaceOperationState(e,{phase:"failed",canCancel:!1,canRetry:!0,error:{code:r.code,stage:r.stage,message:r.message}})}}handlePreparationProgress(e,t){if(t){if("download"===t.phase)return void this.patchState(e,{phase:"downloading",progress:{downloadedBytes:t.downloadedBytes,...void 0===t.totalBytes?{}:{totalBytes:t.totalBytes},...void 0===t.percentage?{}:{percentage:t.percentage}}});"install"===t.phase&&this.patchState(e,{phase:"installing_tool",progress:{installStage:t.stage}})}}async getControlClient(){return this.controlClient?this.controlClient:(this.controlClientPromise||(this.controlClientPromise=this.dependencies.connectClient({projectPath:this.options.projectPath,appDir:this.options.appDir,nodeIdPrefix:"web-real-device"}).then(e=>(this.controlClient=e,e)).catch(e=>{throw this.controlClientPromise=void 0,e})),this.controlClientPromise)}async watchForDisconnect(e,t,n){await this.stopDisconnectWatcher();let r=this.dependencies.createDisconnectWatcher(t,async t=>{t===n&&this.isCurrentState(e)&&("launching_tool"===this.state.phase||"connected"===this.state.phase)&&(this.clearQrImages(),this.replaceState({phase:"failed",canCancel:!1,canRetry:!0,error:{code:"DEVICE_DISCONNECTED",stage:"disconnect",message:"真机连接已断开,请重新扫码。"}}),this.deviceAppOpened&&await this.closeOwnedDeviceApp())});(await r.start(),this.isCurrent(e))?this.disconnectWatcher=r:await r.stop().catch(()=>void 0)}async closeOwnedDeviceApp(){if(this.deviceAppClosePromise)return this.deviceAppClosePromise;if(this.deviceAppOpened){this.deviceAppOpened=!1,this.deviceAppClosePromise=this.dependencies.closeDeviceApp().then(()=>void 0,()=>void 0);try{await this.deviceAppClosePromise}finally{this.deviceAppClosePromise=void 0}}}async stopDisconnectWatcher(){let e=this.disconnectWatcher;this.disconnectWatcher=void 0,await e?.stop().catch(()=>void 0)}cancelled(e){this.clearQrImages(),this.replaceOperationState(e,{phase:"cancelled",connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!0})}fail(e,t,n){this.replaceState({phase:"failed",canCancel:!1,canRetry:!0,error:{code:e,stage:t,message:n}})}patchState(e,t){this.isCurrent(e)&&this.replaceState(t)}replaceOperationState(e,t){this.isCurrentState(e)&&this.replaceState(t)}replaceState(e){this.state={...this.state,...e,revision:this.state.revision+1,...e.phase&&!("error"in e)&&"failed"!==e.phase&&"timed_out"!==e.phase?{error:void 0}:{},...e.phase&&"waiting_for_scan"!==e.phase?{qr:void 0}:{},...e.phase&&"downloading"!==e.phase&&"installing_tool"!==e.phase?{progress:void 0}:{}}}clearQrImages(){this.qrImages=void 0}isCurrent(e){return this.activeOperation===e&&!e.abortController.signal.aborted}isCurrentState(e){return this.state.operationId===e.id}isActive(){return ng.has(this.state.phase)}}class nw extends Error{code;stage;constructor(e,t,n){super(n),this.code=e,this.stage=t}}function nv(){return new w("dev").description("启动 dev 调试控制台(Web 模拟器、真机调试、页面和卡片推送)").option("--project <path>","dbx 项目路径,状态数据会写入该目录下的 node_modules/.doubao-dev",".").option("--mcp-endpoint <endpoint>","HTTP(S) URL,临时覆盖 manifest.mcp_server.end_point;优先级高于环境变量和 manifest").option("--manifest <path>","manifest.yaml 路径;相对路径按 --project 解析,默认按项目布局自动解析").option("--skill <path>","运行态 Skill 目录;显式目录优先,相对路径按 --project 解析;未传默认 skill/,递归加载所有 SKILL.md").option("--host [host]","开发服务器监听的主机名或 IP;不带值时交互选择,不传时自动选址").option("--verbose","输出开发服务生命周期日志",!1).action(async(e,t)=>M(t,t=>ny(t,{...e,verbose:t.verbose})))}async function ny(e,t){let n=(0,eS.randomUUID)(),r=U(),i={devSessionId:n,actionSequence:1,startedAt:performance.now(),runtimeReady:!1,appId:void 0,eventTrackingReady:r};try{return await nI(e,t,i)}catch(e){if(!i.runtimeReady){let t=performance.now()-i.startedAt,r=R(e);await i.eventTrackingReady,await F({action:"start",actionSequence:1,appId:i.appId,devSessionId:n,durationMs:t,error:e,errorStage:"dev_startup",status:r}),await L({appId:i.appId,command:"dev",durationMs:t,error:e,errorStage:"dev_startup",outputMode:"human",status:r})}throw e}}async function nI(e,t,n){let r,i,o,a;e.json&&e.error("dbx dev 会启动交互式控制台,不支持 --json");let s=nC(),c=t.host;if(!0===c){let t=Reflect.get(await import("./dist~1.js"),"selectDevServerHost");t||e.error("当前内置 SDK 不支持交互选择地址,请升级 SDK,或使用 --host <IP>。"),c=await t()}let l=(0,X.resolve)(t.project),{businessTemplatesPath:d,simulatorManifestPath:p,skillsDirectory:u,warnings:g}=D({projectPath:l,manifest:t.manifest,skill:t.skill}),h=[...g],m=p;if(m){let e=await N(m);h.push(...e.warnings),e.usable?(n.appId=r=e.appId,i=e.manifest):m=void 0}if(d){let e=await $(d,i);h.push(...e.warnings.map(e=>({...e,source:"business_templates"})))}else{let e=q(i,void 0);e&&h.push({...e,source:"business_templates"})}let w=await x(process.env,t.mcpEndpoint,m,i),v=H(i),y=P(i),b=B(l).frontendDirectory,S=new J.PassThrough,C=process.stdin,_=new AbortController,E={},A=new nm({projectPath:l,appDir:b,getRuntime:()=>E.promise?E.promise:Promise.reject(Error("Dev runtime is not ready"))}),T=process.env.DBX_WEB_REAL_DEVICE_DEBUG?.trim()!=="0",O=f({projectPath:l,appDir:b,installSignalHandlers:!0,signal:_.signal,verbose:t.verbose,...T?{realDeviceDebug:{provider:A.provider,dispose:()=>A.dispose()}}:{},devOptions:{...I({host:c,appId:r,permissions:y,mcpEndpoint:w,mcpHeaders:v,simulatorBusinessTemplatesPath:d,simulatorManifestPath:m,skillsDirectory:u,printLogs:s?t.verbose:void 0,onLog:s&&!t.verbose?e=>{("error"!==e.level||"build"!==e.scope||"Failed to bundle template"!==e.message&&"模板打包失败"!==e.message)&&("warn"===e.level||"error"===e.level)&&S.write(`${"error"===e.level?"错误:":"⚠"} ${e.message}
|
|
43
|
+
</html>`));return}if("GET"===e.method&&n===`${h}qr.png`){t.writeHead(200,{"Content-Type":"image/png"}),t.end(l);return}if("GET"===e.method&&n===`${h}qr-modern.png`){if(!d){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("未找到资源");return}t.writeHead(200,{"Content-Type":"image/png"}),t.end(d);return}if("GET"===e.method&&n===`${h}events`){clearTimeout(a),a=void 0,t.writeHead(200,{Connection:"keep-alive","Content-Type":"text/event-stream"}),t.write("retry: 250\nevent: ready\ndata: ready\n\n"),m.add(t),t.once("close",()=>{m.delete(t),w||0!==m.size||(a=setTimeout(y,750))});return}if("POST"===e.method&&n===`${h}closed`){e.resume(),t.writeHead(204).end(),y();return}t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("未找到资源")});await new Promise((e,t)=>{I.once("error",t),I.listen(0,"127.0.0.1",()=>{I.removeListener("error",t),e()})});let b=I.address();if(!b||"string"==typeof b)throw await tt(I),Error("无法启动二维码查看器");f("server-listening",{host:"127.0.0.1",port:b.port});let S=`http://127.0.0.1:${b.port}${h}`,C=e=>c??=(async()=>{w=!0,clearTimeout(a);try{for(let e of m)try{e.destroyed||e.writableEnded||(e.once("error",()=>f("browser-close-event-error")),e.end("event: close\ndata: close\n\n"),f("browser-close-event-written"))}catch{f("browser-close-event-error")}}finally{m.clear(),await tt(I),f("server-closed",e)}})();try{f("browser-open-started"),await t(S),r.write("已在默认浏览器打开二维码。\n")}catch(e){throw await C({status:"browser-open-failed"}),Error(`二维码页面未能自动打开:${e instanceof Error?e.message:String(e)}`)}return{closed:v,close:C}}function tt(e){return e.listening?new Promise(t=>{e.close(()=>t()),e.closeAllConnections()}):Promise.resolve()}let tn=e("node:zlib"),tr=e("../../../node_modules/.pnpm/@byted-doubao-tools+devtool-connection-core@0.1.0_debug@4.4.3_react@19.2.7_winston@3.18.3/node_modules/@byted-doubao-tools/devtool-connection-core/dist/lib/ipc/index.js"),ti=4*Math.ceil(5614250.666666667),to=new Map;class ta extends Error{code;cause;constructor(e,t,n){super(t),this.code=e,this.name="RuntimeInspectionError",n&&"cause"in n&&(this.cause=n.cause)}}async function ts(e){let t,n=new p(e.namespace,{nodeId:`${e.nodeIdPrefix}-${process.pid}-${Math.random().toString(36).slice(2,8)}`,requestTimeout:12e3}),r=a(n,e.providerNodeId),i=new Set,s=new Set,c=0,l=!0;n.createService({name:`runtimeInspection${process.pid}${Math.random().toString(36).slice(2,8)}`,events:{[tr.DEVTOOL_CONNECTION_IPC_EVENTS.messageReceived]:async e=>{if(await r.ready(),!r.matchesEvent(e.nodeId))return;let n=e.params,o=tR(n);for(let e of(o&&Number.isSafeInteger(n.clientId)&&Number.isSafeInteger(n.sessionId)&&(t={clientId:n.clientId,sessionId:n.sessionId,data:o.data}),i))e(n)},[d.runtimeInspectionTargetChanged]:async e=>{if(await r.ready(),!r.matchesEvent(e.nodeId,!1))return;let t=function(e){if(v(e)&&"number"==typeof e.clientId&&"number"==typeof e.sessionId&&"string"==typeof e.url)return{clientId:e.clientId,sessionId:e.sessionId,url:e.url}}(e.params);if(t)for(let e of s)e(t)}}});try{await n.start()}catch(e){throw r.close(),await n.stop().catch(()=>void 0),e}let u=(e,t)=>tO(()=>r.call(`${tr.DEFAULT_DEVTOOL_CONNECTION_IPC_SERVICE_NAME}.${e}`,t),5e3);return{eventSubscriptionWarmupMs:e.eventSubscriptionWarmupMs??5e3,getConnectedClients:()=>u(tr.DEVTOOL_CONNECTION_IPC_ACTIONS.getConnectedClients),getLatestScreencastFrame(e){if(t?.clientId===e.clientId&&t.sessionId===e.sessionId)return{data:t.data}},async getRuntimeInspectionTarget(){if(!l)return null;try{return await r.call(o.getRuntimeInspectionTarget)}catch(e){if(tx(e))return l=!1,null;throw e}},subscribeRuntimeInspectionTarget:e=>(s.add(e),()=>{s.delete(e)}),async sendCdp(e,t,n={},r={}){let i={id:1e9+process.pid%1e5*1e3+c++,clientId:e.clientId,sessionId:e.sessionId,method:t,params:n,messageType:"CDP",timeoutMs:!1===r.expectResponse?100:1e4};try{let e=await u(tr.DEVTOOL_CONNECTION_IPC_ACTIONS.sendMessageToApp,i);var o,a,s=t,l=e;if(!l.success)throw Error([l.reason,l.apps?.length?`apps=${l.apps.join(",")}`:"",l.clients?.length?`clients=${l.clients.map(e=>`${e.clientId}:${e.info.App}`).join(",")}`:""].filter(Boolean).join("; "));if(v(l.data)&&v(l.data.error)){let e=void 0===l.data.error.code?"未知":String(l.data.error.code),t=void 0===l.data.error.message?"未知错误":String(l.data.error.message);throw Error(`${s} 失败:${t}(错误码 ${e})`)}return ty(l.data)}catch(e){if(!1===r.expectResponse&&(o=e,a=t,(o instanceof Error?o.message:String(o)).includes(`send CDP message timeout, method: ${a}`)))return;throw Error(`${t} 失败:${e instanceof Error?e.message:String(e)}`)}},subscribeMessage:e=>(i.add(e),()=>{i.delete(e)}),async stop(){r.close(),i.clear(),s.clear(),t=void 0,await n.stop()}}}async function tc(e,t={}){let n=Date.now()+(t.timeoutMs??3e3);for(;;){tM(t.signal);let r=await e.getConnectedClients(),i=function(e,t={}){let n,r=t.explicitTarget??(t.policy?.kind==="fixed"?t.policy.target:void 0);if(r){let n=e.find(e=>e.device.clientId===r.clientId);if(!n){if(t.activeClientId===r.clientId)throw new ta("TARGET_CLIENT_DISCONNECTED",`调试客户端 ${r.clientId} 已断开连接`);throw new ta("TARGET_STALE",`无法访问会话 ${tl(r)}:对应的调试客户端当前未连接`)}let i=n.sessions.find(e=>e.sessionId===r.sessionId&&th(e));if(!i)throw new ta("TARGET_STALE",`会话 ${tl(r)} 当前不可用,请重新选择可调试的 Lynx 会话`);return{clientId:n.device.clientId,sessionId:i.sessionId,url:i.url}}if(void 0!==t.activeClientId){if(!(n=e.find(e=>e.device.clientId===t.activeClientId)))throw new ta("TARGET_CLIENT_DISCONNECTED",`已认证的调试客户端 ${t.activeClientId} 已断开连接`)}else if(e.length>1)throw new ta("TARGET_AMBIGUOUS",`已连接多个调试设备:${e.map(e=>`${e.device.clientId}:${e.device.info.App||"未知应用"}`).join(", ")}`);else n=e[0];if(!n)return;let i=n.sessions.filter(th).sort((e,t)=>t.sessionId-e.sessionId)[0];if(i)return{clientId:n.device.clientId,sessionId:i.sessionId,url:i.url}}(r,t);if(i)return i;if(Date.now()>=n)throw 0===r.length?new ta("DEVICE_NOT_CONNECTED","未连接调试设备"):new ta("NO_ACTIVE_LYNX_SESSION","已连接的设备没有活跃的 Lynx 会话");await tV(100,t.signal)}}function tl(e){return`@${e.clientId}:${e.sessionId}`}function td(e){let t=/^@([1-9]\d*):([1-9]\d*)$/.exec(e.trim());if(!t)throw new ta("INVALID_TARGET_REF",`目标引用 "${e}" 无效;格式应为 @<clientId>:<sessionId>`);let n={clientId:Number(t[1]),sessionId:Number(t[2])};if(!Number.isSafeInteger(n.clientId)||!Number.isSafeInteger(n.sessionId))throw new ta("INVALID_TARGET_REF",`目标引用 "${e}" 无效;每个 ID 都必须是安全整数`);return n}function tp(e){return`@${e.clientId}:${e.sessionId}:${e.nodeId}`}async function tu(e,t){let n=(await e.getConnectedClients()).find(e=>e.device.clientId===t.clientId),r=n?.sessions.find(e=>e.sessionId===t.sessionId&&th(e));if(!n||!r)throw new ta("STALE_NODE_REF",`节点 ${tp(t)} 所属的会话当前不可用,请重新运行 get-page-tree 获取当前页面的节点`);return{clientId:t.clientId,sessionId:t.sessionId,url:r.url}}async function tf(e,t,n={}){var r,i,o;let a,s,c,l,d,p=n.depth??-1,u=n.maxNodes??5e3;if(!Number.isInteger(p)||p<-1)throw Error("页面树 depth 必须是 -1 或非负整数");if(!Number.isSafeInteger(u)||u<1)throw Error("页面树 maxNodes 必须是正整数");await e.sendCdp(t,"DOM.enable",{useCompression:!1});try{d=await e.sendCdp(t,"DOM.getDocument",{depth:p})}catch{d=await e.sendCdp(t,"DOM.getDocument")}let f=function(e){let t=ty(e);if(!v(t))throw tA("DOM.getDocument","响应不是对象");let n=t.root;if(!0===t.compress&&"string"==typeof n)try{if(n.length>ti)throw Error("压缩根节点超出输入大小限制");n=JSON.parse((0,tn.inflateSync)(Buffer.from(n,"base64"),{maxOutputLength:0x1000000}).toString("utf8"))}catch(e){throw tA("DOM.getDocument","无法解码压缩根节点",e)}else if("string"==typeof n)try{n=JSON.parse(n)}catch(e){throw tA("DOM.getDocument","根节点不是有效的 JSON",e)}if(!v(n))throw tA("DOM.getDocument","缺少根节点");return n}(d),g=await tv(e,t,f,p,u),h=(r=f,i=t,o=u,a=0,s=!1,c=[],{root:(l=e=>{var t;let n=tb(e.nodeId),r="string"==typeof e.nodeName&&e.nodeName?e.nodeName:"unknown";if(void 0===n)throw tA("DOM.getDocument",`节点 ${r} 缺少有效的 nodeId`);a++;let d=[],p={ref:tp({clientId:i.clientId,sessionId:i.sessionId,nodeId:n}),nodeId:n,...void 0===tb(e.backendNodeId)?{}:{backendNodeId:tb(e.backendNodeId)},nodeType:"number"==typeof e.nodeType&&Number.isSafeInteger(e.nodeType)?e.nodeType:0,nodeName:r,..."string"==typeof e.localName?{localName:e.localName}:{},nodeValue:"string"==typeof e.nodeValue?e.nodeValue:"",attributes:function(e){if(!Array.isArray(e))return{};let t={};for(let n=0;n<e.length;n+=2){let r=e[n];if("string"!=typeof r||!r)continue;let i=e[n+1];t[r]="string"==typeof i?i:String(i??"")}return t}(e.attributes),childNodeCount:"number"==typeof e.childNodeCount&&Number.isSafeInteger(e.childNodeCount)?Math.max(0,e.childNodeCount):tI(e).length,children:d};for(let t of(tS(p)&&p.nodeValue&&(p.text=p.nodeValue),tI(e))){if(a>=o){s=!0;break}d.push(l(t))}if("text"===((t=p).localName||t.nodeName).toLowerCase()){let e=function e(t){return t.children.flatMap(t=>tS(t)?[t.nodeValue]:[e(t)]).join("")}(p);e?p.text=e:c.push(p)}return p})(r),nodeCount:a,truncated:s,textCandidates:c});return await tC(e,t,h.textCandidates),{target:t,depth:p,nodeCount:h.nodeCount,truncated:g.truncated||h.truncated,root:h.root}}async function tg(e,t,n,r=[]){let i;await e.sendCdp(t,"DOM.enable",{useCompression:!1});try{i=await e.sendCdp(t,"CSS.getComputedStyleForNode",{nodeId:n.nodeId})}catch(e){var o;if(o=e,/(could not find|cannot find|no such|unknown|invalid|stale).{0,40}node|node.{0,40}(not found|does not exist|invalid|stale)/i.test(o instanceof Error?o.message:String(o)))throw new ta("STALE_NODE_REF",`${tp(n)} 已失效;请重新运行 get-page-tree`,{cause:e});throw e}let a=ty(i);if(!v(a)||!Array.isArray(a.computedStyle))throw tA("CSS.getComputedStyleForNode","缺少 computedStyle 数组");let s=a.computedStyle.filter(v).flatMap(e=>"string"==typeof e.name&&"string"==typeof e.value?[{name:e.name,value:e.value}]:[]),c=0===r.length?s:r.flatMap(e=>{let t=s.find(t=>t.name===e);return t?[t]:[]});return{target:t,nodeRef:tp(n),nodeId:n.nodeId,properties:c}}function th(e){return"lynx"===e.type&&Number.isSafeInteger(e.sessionId)&&e.sessionId>0&&!tw(e.url)}function tm(e){return`${e.clientId}:${e.sessionId}`}function tw(e){return/(?:-main\.js|\.main\.lynx\.js)(?:[?#].*)?$/.test(e)}async function tv(e,t,n,r,i){let o=0,a=!1,s=async(n,c)=>{if(o>=i){a=!0;return}if(o++,r>=0&&c>=r)return;let l=tI(n);if(("number"==typeof n.childNodeCount&&Number.isSafeInteger(n.childNodeCount)?Math.max(0,n.childNodeCount):l.length)>l.length&&"number"==typeof n.nodeId&&Number.isSafeInteger(n.nodeId)){let r=ty(await e.sendCdp(t,"DOM.requestChildNodes",{nodeId:n.nodeId}));if(!v(r)||!Array.isArray(r.nodes))throw tA("DOM.requestChildNodes",`节点 ${n.nodeId} 缺少 nodes 数组`);n.children=l=r.nodes.filter(v)}for(let e of l)if(await s(e,c+1),o>=i){l.indexOf(e)<l.length-1&&(a=!0);break}};return await s(n,0),{truncated:a}}function ty(e){return v(e)&&"id"in e&&"result"in e?e.result:e}function tI(e){return Array.isArray(e.children)?e.children.filter(v):[]}function tb(e){return"number"==typeof e&&Number.isSafeInteger(e)&&e>0?e:void 0}function tS(e){return 3===e.nodeType||"#text"===e.nodeName.toLowerCase()}async function tC(e,t,n){let r=n[0];if(!r)return;let i=await t_(e,t,r);if(i.supported){i.text&&(r.text=i.text);for(let r=1;r<n.length;r+=8){let i=n.slice(r,r+8);await Promise.all(i.map(async n=>{let r=await t_(e,t,n);r.text&&(n.text=r.text)}))}}}async function t_(e,t,n){try{let r=ty(await e.sendCdp(t,"DOM.innerText",{nodeId:n.nodeId}));if(!v(r)||!Array.isArray(r.rawTextValues))return{supported:!1};let i=r.rawTextValues.filter(v).flatMap(e=>"string"==typeof e.text?[e.text]:[]).join("");return{supported:!0,...i?{text:i}:{}}}catch{return{supported:!1}}}function tE(e,t=120){let n=e.replace(/\s+/g," ").trim();return JSON.stringify(n.length>t?`${n.slice(0,Math.max(0,t-1))}…`:n)}function tA(e,t,n){return new ta("INVALID_CDP_RESPONSE",`${e} 返回的响应无效:${t}`,void 0===n?void 0:{cause:n})}async function tD(e,t,n){let r,i,o,a=0,s=!1,c=tm(t),l=new Promise((e,t)=>{i=e,o=t}),d=e=>{s||(s=!0,i({count:a,reason:e}))},p=()=>d("aborted"),u=e.getRuntimeInspectionTarget?.bind(e),f=e=>{if(s||!(Number.isSafeInteger(e.clientId)&&e.clientId>0&&Number.isSafeInteger(e.sessionId)&&e.sessionId>0&&!tw(e.url)))return;let r=tm(e);if(r!==c&&(c=r,r!==tm(t)))try{n.onTargetChange?.(e)}catch{}},g=e.subscribeMessage(e=>{if(s||!t$(e,t))return;let r=function(e){var t;if("Runtime.consoleAPICalled"!==e.method||!v(e.params))return;let n={...t=e.params,...Array.isArray(t.args)?{args:t.args.map(e=>v(e)?{...e}:e)}:{},...v(t.stackTrace)?{stackTrace:{...t.stackTrace,...Array.isArray(t.stackTrace.callFrames)?{callFrames:t.stackTrace.callFrames.map(e=>v(e)?{...e}:e)}:{}}}:{}},r="string"==typeof n.consoleTag?n.consoleTag:void 0;return{type:"string"==typeof n.type?n.type:"log",thread:"Lepus"===r?"main":"background",args:Array.isArray(n.args)?n.args:[],...r?{consoleTag:r}:{},..."number"==typeof n.timestamp?{timestamp:n.timestamp}:{},..."stackTrace"in n?{stackTrace:n.stackTrace}:{},params:n}}(e);if(r){try{n.onMessage(r)}catch(e){s||(s=!0,o(e));return}a++,void 0!==n.limit&&a>=n.limit&&d("limit")}}),h=n.onTargetChange?e.subscribeRuntimeInspectionTarget?.(f):void 0;n.signal?.addEventListener("abort",p,{once:!0}),n.onTargetChange&&u&&u().then(e=>{e&&f(e)}).catch(()=>void 0);try{if(n.signal?.aborted)return d("aborted"),await l;if(await tP(e,t,n.subscriptionWarmupMs??e.eventSubscriptionWarmupMs??5e3,n.signal),s)return await l;for(let i of(void 0!==n.timeoutMs&&(r=setTimeout(()=>d("timeout"),n.timeoutMs)),[{method:"Page.getResourceTree",params:{}},{method:"Debugger.enable",params:{}},{method:"Runtime.enable",params:{}}])){if(s)break;await e.sendCdp(t,i.method,i.params,{expectResponse:!1})}return await l}catch(e){if(n.signal?.aborted)return d("aborted"),await l;throw e}finally{r&&clearTimeout(r),n.signal?.removeEventListener("abort",p),h?.(),g()}}async function tT(e,t,n={}){return tL(t,async()=>{let r,i=new Promise(e=>{r=e}),o=e.subscribeMessage(e=>{let n=t$(e,t)?tR(e):void 0;n&&r(n)}),a=!1;try{var s,c,l;await tP(e,t,e.eventSubscriptionWarmupMs??5e3);let r=n.activeCapture?void 0:e.getLatestScreencastFrame?.(t);!r&&n.activeCapture&&(await e.sendCdp(t,"Page.enable"),a=!0,await e.sendCdp(t,"Page.startScreencast",{format:"jpeg",quality:80},{expectResponse:!1})),r??=await (s=i,c=t,l=n.timeoutMs??1e4,new Promise((e,t)=>{let n=setTimeout(()=>t(new ta("SCREENSHOT_TIMEOUT",`未收到 ${tl(c)} 的 Page.screencastFrame,已等待 ${l} 毫秒;请确认目标会话处于活跃状态且能生成截图帧`)),l);s.then(t=>{clearTimeout(n),e(t)},e=>{clearTimeout(n),t(e)})})),a&&await e.sendCdp(t,"Page.screencastFrameAck",{},{expectResponse:!1}).catch(()=>void 0);let o=function(e){let t=e.replace(/\s+/g,"");if(!t||t.length%4!=0||!/^[A-Za-z0-9+/]+={0,2}$/.test(t))throw new ta("INVALID_SCREENSHOT_DATA","Page.screencastFrame 返回的 Base64 数据无效");let n=Buffer.from(t,"base64");if(n.length<4||255!==n[0]||216!==n[1]||255!==n[n.length-2]||217!==n[n.length-1])throw new ta("INVALID_SCREENSHOT_DATA","Page.screencastFrame 未返回完整的 JPEG 图片");let r=function(e){let t=new Set([192,193,194,195,197,198,199,201,202,203,205,206,207]),n=2;for(;n+3<e.length;){if(255!==e[n]){n++;continue}for(;n<e.length&&255===e[n];)n++;let r=e[n++];if(void 0===r||217===r||218===r)break;if(1===r||r>=208&&r<=215)continue;if(n+1>=e.length)break;let i=e.readUInt16BE(n);if(i<2||n+i>e.length)break;if(t.has(r)){if(i<7)break;let t=e.readUInt16BE(n+3),r=e.readUInt16BE(n+5);if(r>0&&t>0)return{width:r,height:t};break}n+=i}}(n);if(!r)throw new ta("INVALID_SCREENSHOT_DATA","无法读取 Page.screencastFrame 返回的 JPEG 图片尺寸");return{buffer:n,data:t,...r}}(r.data);return{data:o.data,format:"jpeg",source:"Page.screencastFrame",width:o.width,height:o.height,byteLength:o.buffer.length}}finally{a&&await e.sendCdp(t,"Page.stopScreencast",{},{expectResponse:!1}).catch(()=>void 0),o()}})}function t$(e,t){return"CDP"===e.messageType&&e.clientId===t.clientId&&e.sessionId===t.sessionId}async function tP(e,t,n,r){let i;if(n<=0)return;let o=Date.now()+n,a=new Promise(e=>{i=e}),s=e.subscribeMessage(e=>{t$(e,t)&&i()});try{for(;Date.now()<o;){if(tM(r),await e.sendCdp(t,"Page.getResourceTree",{},{expectResponse:!1}).catch(()=>void 0),await function(e,t,n){return new Promise((r,i)=>{let o=new AbortController,a=setTimeout(()=>{o.abort(),r(!1)},t);n?.addEventListener("abort",()=>{clearTimeout(a),o.abort(),i(n?.reason instanceof Error?n.reason:Error("操作已取消"))},{once:!0,signal:o.signal}),e.then(()=>{clearTimeout(a),o.abort(),r(!0)},e=>{clearTimeout(a),o.abort(),i(e)})})}(a,Math.min(250,Math.max(0,o-Date.now())),r))return;await tV(Math.min(50,Math.max(0,o-Date.now())),r)}}finally{s()}}function tN(e){return v(e)?e.objectId?`<${String(e.description||e.className||"Object")} (objectId:${String(e.objectId)})>`:"value"in e?tk(e.value):"string"==typeof e.description?e.description:tk(e):tk(e)}function tk(e){if("string"==typeof e)return e;if(void 0===e)return"undefined";try{let t=JSON.stringify(e);return void 0===t?String(e):t}catch{return String(e)}}function tx(e){return/is not (found|available)/i.test(e instanceof Error?e.message:String(e))}async function tO(e,t){let n=Date.now()+t;for(;;)try{return await e()}catch(e){if(!tx(e)||Date.now()>=n)throw e;await tV(50)}}function tR(e){if("Page.screencastFrame"===e.method&&v(e.params)&&"string"==typeof e.params.data&&e.params.data)return{data:e.params.data}}async function tL(e,t){let n,r=tm(e),i=to.get(r)??Promise.resolve(),o=new Promise(e=>{n=e});to.set(r,o),await i.catch(()=>void 0);try{return await t()}finally{n(),to.get(r)===o&&to.delete(r)}}function tM(e){if(e?.aborted)throw e.reason instanceof Error?e.reason:Error("操作已取消")}async function tV(e,t){try{await (0,n.setTimeout)(e,void 0,{signal:t})}catch(e){throw tM(t),e}}let tj=e("node:util"),tU="\0skip-version-tag",tF=[{command:"web",description:"打开 Web 模拟器"},{command:"desktop",description:"进入桌面端工具,可进行真机调试"},{command:"status",description:"查看本地调试服务状态"}],tK=[{command:"qr",description:"重新生成真机调试二维码"},{command:"page [url]",description:"在真机打开页面(省略 url 可选择)"},{command:"pages",description:"列出真机可打开页面"},{command:"widget [id]",description:"向真机推送卡片(省略 id 可选择)"},{command:"widgets",description:"列出真机可推送卡片"},{command:"sessions",description:"列出当前可检查的 Lynx 会话"},{command:"use-session <@client:session|latest>",description:"固定 CLI 会话或恢复跟随最新会话"},{command:"get-console",description:"持续输出当前 Lynx 页面新产生的日志"},{command:"take-screenshot",description:"截取当前 Lynx 页面画面"},{command:"get-page-tree",description:"获取当前 Lynx 页面的 DOM 树"},{command:"get-computed-style [node-ref]",description:"获取 DOM 节点的计算样式"},{command:"back",description:"返回主命令"}];function tB(e,t){if("true"===e)return!0;if("false"===e)return!1;throw Error(`${t} 必须为 "true" 或 "false"`)}async function tq(e){let t,n,r,i,o=e.output??process.stderr,a=e.client??await u({projectPath:e.projectPath,appDir:e.appDir,nodeIdPrefix:"dev-shell"}),s=e.closeDeviceApp??eM,c=new AbortController,l=e.openBrowser??K,d=new Set,p={runtime:e.runtime,client:a,output:o,manageDeviceApp:!0,runtimeInspectionTargetPolicy:{kind:"latest"},openBrowser:l,openQRCodeViewer:e.openQRCodeViewer??((e,t,n)=>te(e,l,t,o,n)),signal:c.signal,closeDeviceApp:s,prepareDeviceApp:e.prepareDeviceApp??(e=>eO(o,e)),...e.onDeviceAppSetupProgress?{onDeviceAppSetupProgress:e.onDeviceAppSetupProgress}:{},openPreparedDeviceApp:e.openPreparedDeviceApp??eL,runDeviceDebugAuth:e.runDeviceDebugAuth??eZ,...e.deviceDebugCoordinator?{deviceDebugCoordinator:e.deviceDebugCoordinator}:{},...e.createRuntimeInspectionSession?{createRuntimeInspectionSession:e.createRuntimeInspectionSession}:{},listAppVersions:e.listAppVersions??(async e=>{let t=await O(e);return t.data?.version_list??[]}),selectItem:e.selectItem,eventTracking:e.eventTracking},f=(e.createRuntimeInspectionSession??ts)({namespace:e.runtime.getState().namespace,nodeIdPrefix:"dev-shell-runtime-inspection"});f.catch(()=>void 0),p.runtimeInspectionSession=f;let g=async()=>r||(r=(async()=>{p.activeDeviceId=void 0,e7(),p.manageDeviceApp&&await tQ(p)})().finally(()=>{r=void 0})),h=eH(e.runtime.getState().namespace,async e=>{if(p.activeDeviceId&&!i&&e===p.activeClientId){nu(o,"检测到真机连接断开,正在返回主命令并清理真机调试资源..."),await g();for(let e of d)try{e("client-disconnected")}catch{}}});return await h.start(),{stopped:e.runtime.stopped,getState:()=>e.runtime.getState(),execute(e){let r=new AbortController,i=AbortSignal.any([c.signal,r.signal]);n=r,p.signal=i;let o=tH(e,p);return t=o,o.finally(()=>{t===o&&(t=void 0),n===r&&(n=void 0),p.signal===i&&(p.signal=c.signal)})},cancelActiveCommand(){if(!n||n.signal.aborted)return!1;let e=Error("命令已取消");return e.name="AbortError",n.abort(e),!0},returnToRoot:()=>tW(p,"back","execute",g),subscribe:e=>(d.add(e),()=>{d.delete(e)}),close:()=>i??=(async()=>{c.abort(new eB),await t?.catch(()=>void 0),await h.stop().catch(()=>void 0),await g(),await p.runtimeInspectionSession?.then(e=>e.stop()).catch(()=>void 0),await a.stop().catch(()=>void 0),await e.runtime.stop().catch(()=>void 0)})()}}async function tH(e,t){var n;let r;try{r=function(e){let t,n=[],r="",i=!1,o=()=>{r.length>0&&(n.push(r),r="")};for(let n of e.trim()){if(i){r+=n,i=!1;continue}if("\\"===n&&"'"!==t){i=!0;continue}if("'"===n||'"'===n){if(!t){t=n;continue}if(t===n){t=void 0;continue}}if(!t&&/\s/.test(n)){o();continue}r+=n}if(i&&(r+="\\"),t)throw Error(`${t} 引号未闭合`);return o(),n}(e)}catch(e){return nu(t.output,e6(ng(e))),"continue"}let i=r[0]?.toLowerCase(),o=r.slice(1);if(!i)return"continue";if((n=o).includes("--help")||n.includes("-h")){let e="desktop"===i&&o[0]&&!o[0].startsWith("-")?`desktop ${o[0].toLowerCase()}`:i;if(function(e,t){switch(t){case"desktop widget":return nu(e,"用法:widget [widget-id] [--data <json>] [--bot-id <id>] [--device-id <id>]"),nu(e,"推送卡片到已连接真机;省略 widget-id 时从 `widgets` 列表中选择。"),!0;case"desktop page":return nu(e,"用法:page [url] [--device-id <id>]"),nu(e,"通过完整 URL 打开页面;省略 url 时从 `pages` 列表中选择。页面参数请写入 URL 查询参数。"),!0;case"desktop":nu(e,"用法:desktop [--agent] [--ui-only] [--timeout <seconds>] [--qr-file <file.png>] [--usb-connect <true|false>] [--wifi-connect <true|false>] [--defaultDebugTagState <true|false>]"),nu(e,"进入真机模式并连接调试设备,默认准备并打开豆包开发者工具。"),nu(e,C.bold.green("当前默认使用局域网连接")),nu(e,"使用 `desktop --agent` 进入 Agent 模式,不准备、启动或关闭豆包开发者工具。"),nu(e,"默认从当前 AppID 的版本列表中选择 versionTag 进行 MCP 端到端调试;没有可选版本时,生成不带 versionTag 的二维码。"),nu(e,"版本列表中可选择 Skip(仅调试 UI),跳过版本选择并继续调试。"),nu(e,"兼容旧写法 `desktop --mcp`,行为与 `desktop` 相同。"),nu(e,"使用 --ui-only 跳过版本查询和选择,生成不带 versionTag 的二维码;可与 --agent 组合,不能与 --mcp 同时使用。"),nu(e,"使用 --usb-connect true 切换为 USB 传输,需要连接 USB 线并开启 USB 调试。");for(let t of(nu(e,"真机调试命令"),tK))nu(e,` ${t.command.padEnd(22)}${t.description}`);return nu(e,"进入真机模式后执行 `<命令> --help` 查看参数。"),nu(e,"get-page-tree、get-computed-style、take-screenshot 支持通用的 --json 输出。"),!0;case"desktop qr":return nu(e,"用法:qr [--timeout <seconds>] [--qr-file <file.png>] [--usb-connect <true|false>] [--wifi-connect <true|false>] [--defaultDebugTagState <true|false>]"),nu(e,"重新生成真机调试二维码,沿用 desktop 的调试模式和 versionTag(未选版本时不携带),不重新查询或选择版本。"),nu(e,"使用 --usb-connect true 切换为 USB 传输,需要连接 USB 线并开启 USB 调试。"),!0;case"desktop get-console":return nu(e,"用法:get-console [--target <@client:session>] [--limit <count>] [--timeout-seconds <seconds>] [--include-stack-traces]"),nu(e,"持续输出当前 Lynx 会话新产生的控制台日志;按 Ctrl+C 停止监听并返回真机命令。"),nu(e,"默认仅错误日志显示调用栈;使用 --include-stack-traces 展开所有日志的调用栈。"),!0;case"desktop sessions":return nu(e,"用法:sessions"),nu(e,"列出当前可检查的 Lynx 会话,并标记最新会话、CLI 固定会话和 Electron 当前会话。"),!0;case"desktop use-session":return nu(e,"用法:use-session <@client:session|latest>"),nu(e,"固定 CLI 后续检查命令使用的会话,或用 latest 恢复到已认证客户端内最新活跃会话;不会切换 Electron。"),!0;case"desktop take-screenshot":return nu(e,"用法:take-screenshot [--target <@client:session>] [-o, --output <file.jpeg>] [--json]"),nu(e,"保存 Electron 当前为目标会话输出的最近一帧 JPEG;截图范围跟随 Electron 当前模式。"),!0;case"desktop get-page-tree":return nu(e,"用法:get-page-tree [--target <@client:session>] [--depth <-1|n>] [--json]"),nu(e,"获取当前 Lynx 会话的 DOM 树(开发者工具元素面板);默认 depth=-1。"),nu(e,"终端输出紧凑树;--json 输出节点文本、完整属性和可复用的节点引用 node-ref。"),!0;case"desktop get-computed-style":return nu(e,"用法:get-computed-style <node-ref> [--properties <name,...>] [--json]"),nu(e,"获取元素节点的计算样式;node-ref 格式为 @<clientId>:<sessionId>:<nodeId>。"),nu(e,"省略 --properties 返回全部属性,例如 --properties color,font-size。"),!0;case"web":return nu(e,"用法:web"),nu(e,"在默认浏览器打开本地 Web 模拟器。"),!0;case"desktop pages":case"desktop widgets":{let n="desktop pages"===t?"打开的页面":"推送的卡片";return nu(e,`用法:${t.slice(8)}`),nu(e,`列出真机可${n}。`),!0}case"status":return nu(e,"用法:status"),nu(e,"查看本地调试服务状态。"),!0;default:return!1}}(t.output,e))return"continue"}try{switch(i){case"status":return await tW(t,"status","execute",()=>tz(t)),"continue";case"web":return await tW(t,"web_open","execute",()=>tJ(t)),"continue";case"desktop":return await tG(t,o)?"enter-device":"continue";case"device":return nu(t.output,"命令 `device` 已更名为 `desktop`,请改用 `desktop`。"),"continue";default:return nu(t.output,`未知命令:${i}`),["qr","pages","page","widgets","widget","sessions","use-session","get-console","take-screenshot","get-page-tree","get-computed-style"].includes(i)&&nu(t.output,`\`${i}\` 仅可在桌面模式下使用;请先运行 \`desktop\`。`),"continue"}}catch(e){return nu(t.output,e6(ng(e))),"continue"}}async function tW(e,t,n,r){let i=e.eventTracking;return i?V({action:t,actionSequence:++i.actionSequence,appId:i.appId??e.runtime.getState().appId,devSessionId:i.devSessionId,errorStage:n},r):r()}async function tG(e,t){var n;let r=t[0]?.toLowerCase();if(!r||r.startsWith("-"))return void 0!==await tZ(e,t,{reuseDeviceAppMode:!1,reuseVersionTag:!1});let i={args:(n=t.slice(1)).filter(e=>"--json"!==e),json:n.includes("--json")},a=["get-page-tree","get-computed-style","take-screenshot"].includes(r);try{if(i.json&&!a)throw Error(`desktop ${r} 不支持 --json;请搭配 get-page-tree、get-computed-style 或 take-screenshot 使用`);switch(r){case"qr":return await t2(e,i.args)!==void 0;case"pages":return await tW(e,"pages_list","execute",()=>t6(e,"page",o.discoverPages)),!0;case"page":return await tW(e,"page_push","page_push",()=>ni(e,i.args)),!0;case"widgets":return await tW(e,"widgets_list","execute",()=>t6(e,"widget",o.discoverWidgets)),!0;case"widget":return await tW(e,"widget_push","widget_push",()=>no(e,i.args)),!0;case"sessions":return await tW(e,"sessions_list","execute",()=>t5(e,i.args)),!0;case"use-session":return await tW(e,"session_select","execute",()=>t3(e,i.args)),!0;case"get-console":return await tW(e,"console_stream","execute",()=>t4(e,i.args)),!0;case"take-screenshot":return await tW(e,"screenshot","execute",()=>t8(e,i.args,i.json)),!0;case"get-page-tree":return await tW(e,"page_tree","execute",()=>t7(e,i.args,i.json)),!0;case"get-computed-style":return await tW(e,"computed_style","execute",()=>t9(e,i.args,i.json)),!0;default:return nu(e.output,`未知 desktop 子命令:${r}`),!1}}catch(t){if(!i.json||!a)throw t;return nf(e.output,{ok:!1,error:{code:t instanceof ta?t.code:"INSPECTION_FAILED",message:ng(t)}}),!0}}async function tQ(e){try{var t,n;let r=await e.closeDeviceApp();t=e.output,n=r,"closed"===n.status?nu(t,`豆包开发者工具已关闭:${n.appPath}`):nu(t,`关闭豆包开发者工具失败${n.reason?`:${e6(n.reason)}`:""}`)}catch(t){nu(e.output,`关闭豆包开发者工具失败:${e6(ng(t))}`)}}async function tz(e){let t=await e.client.call(o.getInfo);nu(e.output,`状态:${{starting:"启动中",running:"运行中",stopping:"停止中",stopped:"已停止",failed:"失败",error:"错误"}[t.status]??t.status}`),nu(e.output,`app_id: ${t.appId??"-"}`),nu(e.output,`开发服务:${t.host??"-"}`),nu(e.output,`Web 模拟器:${t.webDebuggerUrl??"-"}`)}async function tJ(e){let t=await e.client.call(o.openWebDebugger);nu(e.output,`Web 模拟器已打开:${t}`)}async function tZ(e,t,n){let r=e.eventTracking;if(!r)return tX(e,t,n);let i=++r.actionSequence,o=performance.now(),a=n.reuseDeviceAppMode?"qr_refresh":"device_connect";try{let s=await tX(e,t,n),c=s?.status==="connected"?"success":void 0===s||"cancelled"===s.status?"cancelled":s?.status==="timeout"?"timeout":s?.error?"failed":"skipped";return await F({action:a,actionSequence:i,appId:r.appId??e.runtime.getState().appId,devSessionId:r.devSessionId,durationMs:performance.now()-o,...s?.error?{error:s.error,...s.failureStage?{errorStage:s.failureStage}:{},errorType:"device_connection_error"}:{},status:c}),s}catch(t){throw await F({action:a,actionSequence:i,appId:r.appId??e.runtime.getState().appId,devSessionId:r.devSessionId,durationMs:performance.now()-o,error:t,errorStage:"prepare_device_tool",errorType:"device_connection_error",status:R(t)}),t}}async function tX(e,t,n){var r;let i,o=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{agent:{type:"boolean"},timeout:{type:"string"},"qr-file":{type:"string"},mcp:{type:"boolean"},"ui-only":{type:"boolean"},"usb-connect":{type:"string"},"wifi-connect":{type:"string"},defaultDebugTagState:{type:"string"}}});if(n.reuseVersionTag&&(o.values["ui-only"]||o.values.mcp))throw Error("qr 沿用 desktop 的调试模式,不支持 --mcp 或 --ui-only");if(o.values["ui-only"]&&o.values.mcp)throw Error("--ui-only 与 --mcp 不能同时使用");if(n.reuseDeviceAppMode&&o.values.agent)throw Error("--agent 仅支持在进入桌面模式时使用");let a=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error("--timeout 必须是正数,单位为秒");return Math.round(1e3*t)}(o.values.timeout),s=function(e){if(!e)return;let t=Y().resolve(e);if(".png"!==Y().extname(t).toLowerCase())throw Error("--qr-file 必须指向 .png 文件");return t}(o.values["qr-file"]),c=e1((r={defaultDebugTagState:o.values.defaultDebugTagState,usbConnect:o.values["usb-connect"],wifiConnect:o.values["wifi-connect"]},i={},void 0!==r.defaultDebugTagState&&(i.defaultDebugTagState=tB(r.defaultDebugTagState,"--defaultDebugTagState")),void 0!==r.usbConnect?i.usb=tB(r.usbConnect,"--usb-connect"):void 0!==r.wifiConnect&&(i.usb=!tB(r.wifiConnect,"--wifi-connect")),Object.keys(i).length>0?i:void 0)),l=e.runtime.getState(),d=!!o.values["ui-only"],p=!d&&!n.reuseVersionTag,u=d?void 0:e.activeVersionTag;if(p){let t=await t0(e,l.appId);if("cancelled"===t.status)return;u="selected"===t.status?t.versionTag:void 0}e.signal?.throwIfAborted(),d&&nu(e.output,"已启用 --ui-only:跳过版本查询,二维码不携带 versionTag。");let f=()=>tY(e,{state:l,versionTag:u,timeoutMs:a,qrFilePath:s,settings:c,manageDeviceApp:n.reuseDeviceAppMode?e.manageDeviceApp:!o.values.agent,enteringDeviceMode:!n.reuseDeviceAppMode,reuseVersionTag:!p});return e.deviceDebugCoordinator?e.deviceDebugCoordinator.runTerminal(async t=>{let n=e.signal;e.signal=n?AbortSignal.any([n,t]):t;try{return await f()}finally{e.signal=n}}):f()}async function tY(e,t){let n,r,{state:i,versionTag:a,timeoutMs:s,qrFilePath:c,settings:l}=t;e.signal?.throwIfAborted();let d=await e.client.call(o.setConnectionTransport,{type:l.usb?"usb":"wifi",...void 0===a?{}:{versionTag:a}});e.manageDeviceApp=t.manageDeviceApp,e.activeVersionTag=a,a&&t.reuseVersionTag&&nu(e.output,`沿用 MCP 端到端调试 versionTag:${a}`),t.enteringDeviceMode&&!l.usb&&nu(e.output,C.bold.green("当前默认使用局域网连接")),e.manageDeviceApp||nu(e.output,"已启用 --agent:不会准备、启动或关闭豆包开发者工具。");let p=e.manageDeviceApp?await t1(e):void 0;if(p?.status==="skipped"){let t=p.reason??"豆包开发者工具准备失败";return nu(e.output,`启动真机调试失败:${e6(t)}`),{ok:!1,status:"skipped",timeoutMs:s??6e4,failureStage:"prepare_device_tool",error:t}}e7();let u=new AbortController,f=e.signal?AbortSignal.any([e.signal,u.signal]):u.signal;try{r=await e.runDeviceDebugAuth({hostUrl:d.host||i.host,appKey:d.appId||i.appId,versionTag:a,namespace:i.namespace,timeoutMs:s,settings:l,wifiConnectUrl:d.wifiConnectUrl,output:e.output,signal:f,onQRCodeReady:async(t,r)=>{(n=await e.openQRCodeViewer(t,c,r)).closed.then(()=>{u.abort(new eB)})}})}finally{await n?.close({status:r?.status??"exception",failureStage:r?.failureStage,waitingFor:r?.waitingFor}).catch(()=>void 0),e7()}if(function(e,t){let n;if(t.ok){let n=t.client?.clientId===void 0?"":`:客户端 ${t.client.clientId}`,r=t.qrCodeValue?"扫码鉴权完成":"复用已连接设备,已跳过二维码鉴权";nu(e,`真机调试已连接${n}(${r})。`);return}"cancelled"===t.status?nu(e,"install"===t.waitingFor?"二维码页面已关闭,已取消等待设备安装。":"二维码页面已关闭,已取消等待设备连接。"):(n="timeout"===t.status?"install"===t.waitingFor?`设备已连接,但等待安装完成超时(${Math.max(1,Math.ceil(t.timeoutMs/1e3))} 秒)`:`等待设备连接超时(${Math.max(1,Math.ceil(t.timeoutMs/1e3))} 秒)`:e6(t.error??"未知错误"),nu(e,`启动真机调试失败:${n}`))}(e.output,r),r.ok&&"connected"===r.status){r.client?.clientId!==void 0&&(void 0!==e.activeClientId&&e.activeClientId!==r.client.clientId&&(e.runtimeInspectionTargetPolicy={kind:"latest"}),e.activeClientId=r.client.clientId);let t=r.client?.deviceId??(r.client?.clientId===void 0?void 0:String(r.client.clientId));t&&(e.activeDeviceId=t)}return p&&r.ok&&"connected"===r.status&&(p.appPath?(await e.openPreparedDeviceApp(p.appPath,eR(i)),nu(e.output,`豆包开发者工具已启动:${p.appPath}`)):nu(e.output,`启动豆包开发者工具失败${p.reason?`:${e6(p.reason)}`:""}`)),r}async function t0(e,t){if(!t)throw Error("无法查询 versionTag,当前工程缺少 AppID。");let n=(await e.listAppVersions(t)).filter(e=>"string"==typeof e.version_tag&&!!e.version_tag.trim());if(e.signal?.throwIfAborted(),!n.length)return nu(e.output,`当前 AppID(${t})没有可选版本,将生成不带 versionTag 的二维码。`),{status:"unversioned"};let r=await e.selectItem("versionTag",n,e.output);return r===tU?(nu(e.output,"已跳过版本选择,仅调试 UI。"),{status:"unversioned"}):r?(nu(e.output,`MCP 端到端调试 versionTag:${r}`),{status:"selected",versionTag:r}):(nu(e.output,"已取消 versionTag 选择,未生成二维码。"),{status:"cancelled"})}async function t1(e){e.onDeviceAppSetupProgress?.(void 0);try{return await e.prepareDeviceApp({onProgress:eN(e.output,e.onDeviceAppSetupProgress),signal:e.signal})}catch(t){return e.onDeviceAppSetupProgress?.(void 0),{status:"skipped",reason:ng(t)}}}async function t2(e,t){return tZ(e,t,{reuseDeviceAppMode:!0,reuseVersionTag:!0})}async function t6(e,t,n){let r=await e.client.call(n);if(!r.length)return void nu(e.output,`未找到${"page"===t?"页面":"卡片"}`);for(let n of r)nu(e.output,`- ${nd(t,n)}`)}async function t5(e,t){if(t.length>0)throw Error("sessions 不接受参数");let n=await nr(e,"sessions"),{session:r}=n;try{let t=await r.getConnectedClients();if(0===t.length)throw new ta("DEVICE_NOT_CONNECTED","未连接调试设备");let n=t.flatMap(e=>e.sessions.filter(th).map(t=>({clientId:e.device.clientId,sessionId:t.sessionId,url:t.url}))).sort((e,t)=>e.clientId-t.clientId||t.sessionId-e.sessionId);if(0===n.length)throw new ta("NO_ACTIVE_LYNX_SESSION","已连接的设备没有活跃的 Lynx 会话");let i=r.getRuntimeInspectionTarget?await r.getRuntimeInspectionTarget().catch(()=>null):null,o=ne(e),a=e.activeClientId??(1===t.length?t[0]?.device.clientId:void 0),s=void 0===a?void 0:n.find(e=>e.clientId===a);for(let t of n){let n=[nt(t,i)?"electron":void 0,"fixed"===o.kind&&nt(t,o.target)?"cli":void 0,nt(t,s)?"latest":void 0].filter(e=>void 0!==e);nu(e.output,`${tl(t)}${n.length?` ${n.map(e=>`[${e}]`).join(" ")}`:""} ${t.url||"未知地址"}`)}}finally{n.owned&&await r.stop().catch(()=>void 0)}}async function t3(e,t){if(1!==t.length)throw Error("use-session 需要传入 @<clientId>:<sessionId> 或 latest");if(t[0]?.toLowerCase()==="latest"){e.runtimeInspectionTargetPolicy={kind:"latest"},nu(e.output,C.bold.blueBright(`CLI 调试目标已恢复为 latest(跟随最新会话)${void 0===e.activeClientId?"":`(客户端 ${e.activeClientId} 内最新活跃的 Lynx 会话)`};不会切换 Electron。`));return}let n=td(t[0]??""),r=await nr(e,"use-session"),{session:i}=r;try{let t=await tc(i,{activeClientId:e.activeClientId,explicitTarget:n,signal:e.signal});e.runtimeInspectionTargetPolicy={kind:"fixed",target:{clientId:t.clientId,sessionId:t.sessionId}},nu(e.output,C.bold.blueBright(`CLI 调试目标已固定为 ${tl(t)}(${t.url||"未知地址"});不会切换 Electron。`))}finally{r.owned&&await i.stop().catch(()=>void 0)}}async function t4(e,t){let n=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{limit:{type:"string"},"timeout-seconds":{type:"string"},"include-stack-traces":{type:"boolean"},target:{type:"string"}}}),r=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isSafeInteger(t)||t<1||t>100)throw Error("--limit 必须是 1 到 100 之间的整数");return t}(n.values.limit),i=function(e){if(void 0===e)return;let t=Number(e);if(!Number.isFinite(t)||t<=0)throw Error("--timeout-seconds 必须是正数");return Math.round(1e3*t)}(n.values["timeout-seconds"]),o=await nr(e,"get-console"),{session:a}=o;try{let t=await nn(e,a,n.values.target);nu(e.output,C.bold.blueBright(`正在监听客户端 ${t.clientId}、会话 ${t.sessionId}(${t.url||"未知地址"})的新日志;按 Ctrl+C 停止监听。`));let o=await tD(a,t,{...void 0===r?{}:{limit:r},...void 0===i?{}:{timeoutMs:i},signal:e.signal,onTargetChange(n){nu(e.output,C.bold.blueBright(`提示:Electron 已切换到客户端 ${n.clientId}、会话 ${n.sessionId}(${n.url||"未知地址"});当前 CLI 仍监听客户端 ${t.clientId}、会话 ${t.sessionId},不会自动跟随 Electron。`))},onMessage(t){nu(e.output,function(e,t={}){var n;let r=e.args.map(tN).join(" "),i=t.includeStackTraces||"error"===e.type?(n=e.stackTrace,v(n)&&Array.isArray(n.callFrames)?n.callFrames.filter(v).map(e=>{let t="string"==typeof e.url?e.url:"",n="number"==typeof e.lineNumber?e.lineNumber:"unknown",r="number"==typeof e.columnNumber?e.columnNumber:"unknown";return` at ${t}:${n}:${r}`}).join("\n"):""):"";return`[${e.type}/${e.thread}] ${r}${i?`
|
|
44
|
+
${i}`:""}`}(t,{includeStackTraces:n.values["include-stack-traces"]}))}});nu(e.output,`日志监听已停止,共 ${o.count} 条。`)}finally{o.owned&&await a.stop().catch(()=>void 0)}}async function t8(e,t,n=!1){let r=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{output:{type:"string",short:"o"},target:{type:"string"}}}),i=await nr(e,"take-screenshot"),{session:o}=i;try{let t=await nn(e,o,r.values.target),i=await tT(o,t,{activeCapture:!e.manageDeviceApp}),a=Y().resolve(r.values.output??`screenshot-${Date.now()}.jpeg`);await z().promises.writeFile(a,Buffer.from(i.data,"base64")),n?nf(e.output,{ok:!0,command:"take-screenshot",target:t,output:a,format:i.format,source:i.source,width:i.width,height:i.height,byteLength:i.byteLength}):nu(e.output,`截图已保存:${a}(${i.width}\xd7${i.height},客户端 ${t.clientId}、会话 ${t.sessionId},${t.url||"未知地址"};${e.manageDeviceApp?"范围跟随 Electron 当前模式":"由设备按当前截图模式生成"})`)}finally{i.owned&&await o.stop().catch(()=>void 0)}}async function t7(e,t,n=!1){let r=(0,tj.parseArgs)({args:t,allowPositionals:!1,options:{depth:{type:"string"},target:{type:"string"}}}),i=function(e){if(void 0===e)return -1;let t=Number(e);if(!Number.isSafeInteger(t)||t<-1)throw Error("--depth 必须是 -1 或非负整数");return t}(r.values.depth),o=await nr(e,"get-page-tree"),{session:a}=o;try{let t=await nn(e,a,r.values.target),o=await tf(a,t,{depth:i});if(n)nf(e.output,{ok:!0,command:"get-page-tree",...o});else{let n,r;nu(e.output,`DOM 树:客户端 ${t.clientId}、会话 ${t.sessionId}(${t.url||"未知地址"})`),nu(e.output,(n=[],(r=(e,t,i)=>{n.push(`${t}${i}${function(e){if(tS(e))return`${e.ref} #text ${tE(e.nodeValue)}`;let t=(e.localName||e.nodeName).toLowerCase();if(t.startsWith("#"))return`${e.ref} ${t}`;let n=Object.entries(e.attributes).map(([e,t])=>`${e}=${tE(t,80)}`).join(" "),r=e.text||e.children.filter(tS).map(e=>e.nodeValue).join("");return[e.ref,`<${t}${n?` ${n}`:""}>`,r?tE(r,120):""].filter(Boolean).join(" ")}(e)}`);let o=e.children.filter(e=>!tS(e));o.forEach((e,n)=>{r(e,`${t}${i?"└─ "===i?" ":"│ ":""}`,n===o.length-1?"└─ ":"├─ ")})})(o.root,"",""),o.truncated&&n.push(`… tree truncated after ${o.nodeCount} nodes`),n.join("\n"))),nu(e.output,`共 ${o.nodeCount} 个节点${o.truncated?"(已截断)":""}。`)}}finally{o.owned&&await a.stop().catch(()=>void 0)}}async function t9(e,t,n=!1){let r=(0,tj.parseArgs)({args:t,allowPositionals:!0,options:{properties:{type:"string"}}}),i=r.positionals[0];if(!i)throw new ta("INVALID_NODE_REF","缺少 node-ref;请运行 get-page-tree 并传入 @<clientId>:<sessionId>:<nodeId>");if(r.positionals.length>1)throw Error("get-computed-style 只能接受一个 node-ref");let o=function(e){let t=/^@([1-9]\d*):([1-9]\d*):([1-9]\d*)$/.exec(e.trim());if(!t)throw new ta("INVALID_NODE_REF",`节点引用 "${e}" 无效;格式应为 @<clientId>:<sessionId>:<nodeId>`);let n={clientId:Number(t[1]),sessionId:Number(t[2]),nodeId:Number(t[3])};if(!Number.isSafeInteger(n.clientId)||!Number.isSafeInteger(n.sessionId)||!Number.isSafeInteger(n.nodeId))throw new ta("INVALID_NODE_REF",`节点引用 "${e}" 无效;每个 ID 都必须是安全整数`);return n}(i),a=function(e){if(void 0===e)return[];let t=e.split(",").map(e=>e.trim());if(0===t.length||t.some(e=>!/^-{0,2}[a-z][a-z0-9-]*$/i.test(e)))throw Error("--properties 必须是以逗号分隔的 CSS 属性名列表");return[...new Set(t.map(e=>e.toLowerCase()))]}(r.values.properties),s=await nr(e,"get-computed-style"),{session:c}=s;try{let t=await tu(c,o),r=await tg(c,t,o,a);if(n)nf(e.output,{ok:!0,command:"get-computed-style",...r});else if(nu(e.output,`${r.nodeRef} 计算样式(客户端 ${t.clientId}、会话 ${t.sessionId})`),0===r.properties.length)nu(e.output,"没有匹配的 计算样式 属性。");else{let t=Math.max(...r.properties.map(e=>e.name.length));for(let n of r.properties)nu(e.output,` ${n.name.padEnd(t)} ${n.value}`)}}finally{s.owned&&await c.stop().catch(()=>void 0)}}function ne(e){return e.runtimeInspectionTargetPolicy??{kind:"latest"}}function nt(e,t){return null!=e&&null!=t&&e.clientId===t.clientId&&e.sessionId===t.sessionId}function nn(e,t,n){return tc(t,{activeClientId:e.activeClientId,policy:ne(e),...void 0===n?{}:{explicitTarget:td(n)},signal:e.signal})}async function nr(e,t){if(e.runtimeInspectionSession)return{owned:!1,session:await e.runtimeInspectionSession};let n=e.createRuntimeInspectionSession??ts;return{owned:!0,session:await n({namespace:e.runtime.getState().namespace,nodeIdPrefix:`dev-shell-${t}`})}}async function ni(e,t){let n=(0,tj.parseArgs)({args:t,allowPositionals:!0,options:{"device-id":{type:"string"}}}),r=n.positionals[0]??await ns(e,"page",o.discoverPages);if(!r)throw Error("缺少页面 URL");let i=n.values["device-id"]??e.activeDeviceId;nu(e.output,`调试:打开页面请求 ${np({url:r,deviceId:i})}`);let a=s("page",await e.client.call(o.openPageUrl,{url:r,deviceId:i}));nu(e.output,`页面已打开:${r}`),nu(e.output,`状态:${na(a)}`)}async function no(e,t){let n=(0,tj.parseArgs)({args:t,allowPositionals:!0,options:{data:{type:"string"},"bot-id":{type:"string"},"device-id":{type:"string"}}}),r=n.positionals[0]??await ns(e,"widget",o.discoverWidgets);if(!r)throw Error("缺少卡片 ID");let i=l(n.values.data,"--data"),a=n.values["device-id"]??e.activeDeviceId;nu(e.output,`调试:推送卡片请求 ${np({widgetId:r,data:i,botId:n.values["bot-id"],deviceId:a})}`);let c=s("widget",await e.client.call(o.pushWidget,{widgetId:r,widgetData:i,botId:n.values["bot-id"],deviceId:a}));nu(e.output,`卡片已推送:${r}`),nu(e.output,`状态:${na(c)}`)}function na(e){if(!e.ok)return"失败";let t=function(e){if(!e||"object"!=typeof e)return;let t=e.data;if(!t||"object"!=typeof t)return;let n=t.msg;return"string"==typeof n?n:void 0}(e.result);return!t?.trim()||/^(ok|success)$/i.test(t.trim())?"成功":t}async function ns(e,t,n){let r=await e.client.call(n);if(r.length)return e.selectItem(t,r,e.output)}function nc(e,t){let n=t.map(t=>{let n=nl(e,t);return n?{label:nd(e,t),value:n}:void 0}).filter(e=>!!e);return"versionTag"===e?[{label:"Skip(仅调试 UI)",value:tU},...n]:n}function nl(e,t){if("page"!==e){if(!t||"object"!=typeof t)return;for(let e of["id","pageId","page_id","widgetId","widget_id","versionTag","version_tag","name","path"]){let n=t[e];if("string"==typeof n&&n.trim())return n}return}if(!t||"object"!=typeof t)return;let n=t.path;return"string"==typeof n&&n.trim()?n:void 0}function nd(e,t){let n=nl(e,t);if(!t||"object"!=typeof t)return n??String(t);let r="";return"string"==typeof t.title?r=t.title:"string"==typeof t.name&&(r=t.name),[n,r&&r!==n?r:""].filter(Boolean).join(" ")}function np(e){return JSON.stringify(Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).map(([e,t])=>[e,"data"===e?c(t):t])))}function nu(e,t=""){e.write(`${t}
|
|
45
|
+
`)}function nf(e,t){nu(e,JSON.stringify(t))}function ng(e){return e instanceof Error?e.message:String(e)}let nh=new Set(["preparing","downloading","installing_tool","reusing_client","waiting_for_scan","waiting_for_install","launching_tool"]),nm=new J.Writable({write(e,t,n){n()}});class nw{options;provider;state={revision:0,phase:"idle",canCancel:!1,canRetry:!1};activeOperation;controlClient;controlClientPromise;disconnectWatcher;qrImages;qrRevision=0;deviceAppOpened=!1;deviceAppClosePromise;disposed=!1;dependencies;constructor(e){this.options=e,this.dependencies={connectClient:u,prepareDeviceApp:eO,runAuth:eZ,renderQRCodes:e8,openDeviceApp:eL,closeDeviceApp:eM,createDisconnectWatcher:eH,...e.dependencies},this.provider={getState:()=>this.getState(),start:()=>this.startWeb(),cancel:e=>this.cancelWeb(e),getQrImage:(e,t)=>this.getQrImage(e,t)}}async runTerminal(e){if(this.disposed)throw Error("DEV_RUNTIME_UNAVAILABLE: 本地调试服务已停止");if(this.activeOperation&&this.isActive())throw Error("REAL_DEVICE_DEBUG_BUSY: Web 或终端已有真机调试流程正在运行。");let t={id:eC().randomUUID(),owner:"terminal",abortController:new AbortController};this.activeOperation=t,this.clearQrImages(),this.replaceState({operationId:t.id,owner:"terminal",phase:"preparing",connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!1});let n=Promise.resolve().then(async()=>(await this.stopDisconnectWatcher(),await this.closeOwnedDeviceApp(),t.abortController.signal.throwIfAborted(),e(t.abortController.signal)));t.promise=n.then(()=>void 0,()=>void 0);try{return await n}finally{this.activeOperation===t&&(this.activeOperation=void 0,this.replaceState({phase:"idle",operationId:void 0,owner:void 0,connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!1}))}}async dispose(){if(this.disposed)return;this.disposed=!0;let e=this.activeOperation;e?.abortController.abort(Error("dev runtime stopped")),await e?.promise?.catch(()=>void 0),this.activeOperation=void 0,this.clearQrImages(),await this.stopDisconnectWatcher(),await this.closeOwnedDeviceApp();let t=await this.controlClientPromise?.catch(()=>void 0);await (t??this.controlClient)?.stop().catch(()=>void 0),this.controlClient=void 0,this.controlClientPromise=void 0}getState(){return{...this.state,...this.state.progress?{progress:{...this.state.progress}}:{},...this.state.qr?{qr:{...this.state.qr}}:{},...this.state.error?{error:{...this.state.error}}:{}}}startWeb(){if(this.disposed)return this.fail("DEV_RUNTIME_UNAVAILABLE","runtime","本地调试服务已停止,请重新运行 dbx dev。"),this.getState();if("connected"===this.state.phase||this.activeOperation&&this.isActive())return this.getState();let e={id:eC().randomUUID(),owner:"web",abortController:new AbortController};return this.activeOperation=e,this.clearQrImages(),this.replaceState({operationId:e.id,owner:"web",phase:"preparing",connectionMode:void 0,deadlineAt:void 0,canCancel:!0,canRetry:!1}),e.promise=this.runWebOperation(e).finally(()=>{this.activeOperation===e&&(this.activeOperation=void 0)}),e.promise.catch(()=>void 0),this.getState()}async cancelWeb(e){let t=this.activeOperation;return t&&t.id===e&&"web"===t.owner&&this.isActive()&&(t.abortController.abort(Error("真机调试已取消")),await t.promise?.catch(()=>void 0)),this.getState()}async getQrImage(e,t){if(this.state.operationId!==e||"waiting_for_scan"!==this.state.phase)return;let n=this.qrImages?.[t];return n?{body:new Uint8Array(n),contentType:"image/png"}:void 0}async runWebOperation(e){let{signal:t}=e.abortController,n=!1;try{await this.deviceAppClosePromise,t.throwIfAborted();let r=await this.options.getRuntime();t.throwIfAborted();let i=r.getState();if("running"!==i.status)throw new nv("DEV_RUNTIME_UNAVAILABLE","runtime","本地调试服务尚未就绪,请稍后重试。");let o=await this.getControlClient();t.throwIfAborted();let a=await o.call("dev.setConnectionTransport",{type:"wifi"});t.throwIfAborted();let s=await this.dependencies.prepareDeviceApp(nm,{signal:t,onProgress:t=>this.handlePreparationProgress(e,t)});if(t.throwIfAborted(),"skipped"===s.status||!s.appPath){let e="UNSUPPORTED_PLATFORM"===s.reasonCode||s.reason?.includes("not supported");throw new nv(e?"UNSUPPORTED_PLATFORM":"TOOL_PREPARE_FAILED","prepare",e?"当前系统暂不支持自动准备豆包开发者工具。":"豆包开发者工具准备失败,请重试或使用终端 desktop 查看详情。")}let c=Date.now()+6e4;this.patchState(e,{deadlineAt:c});let l=await this.dependencies.runAuth({hostUrl:a.host||i.host,appKey:a.appId||i.appId,namespace:i.namespace,timeoutMs:6e4,settings:{usb:!1,defaultDebugTagState:!0},wifiConnectUrl:a.wifiConnectUrl,output:nm,signal:t,onPhaseChange:t=>{if("reusing_client"===t){this.clearQrImages(),this.patchState(e,{phase:t,connectionMode:"existing_client"});return}"waiting_for_scan"===t?this.patchState(e,{phase:t,connectionMode:"qr"}):(this.clearQrImages(),this.patchState(e,{phase:t}))},onQRCodeReady:async(n,r)=>{let i=await this.dependencies.renderQRCodes(n,r);t.throwIfAborted(),this.isCurrent(e)&&(this.qrImages=i,this.qrRevision+=1,this.patchState(e,{phase:"waiting_for_scan",connectionMode:"qr",qr:{revision:this.qrRevision,modernAvailable:!!i.modern,legacyAvailable:!0}}))}});if(t.throwIfAborted(),!l.ok||"connected"!==l.status){if("cancelled"===l.status)return void this.cancelled(e);if("timeout"===l.status){this.clearQrImages(),this.replaceOperationState(e,{phase:"timed_out",canCancel:!1,canRetry:!0,error:{code:"install"===l.waitingFor?"PACKAGE_INSTALL_TIMEOUT":"CONNECTION_TIMEOUT",stage:"install"===l.waitingFor?"package_install":"connection",message:"install"===l.waitingFor?"设备已连接,但安装调试包超时,请重试。":"等待扫码连接超时,请重新生成二维码。"}});return}let t="waiting_for_scan"===this.state.phase||"reusing_client"===this.state.phase;throw new nv("install"===l.waitingFor?"PACKAGE_INSTALL_FAILED":t?"REAL_DEVICE_DEBUG_FAILED":"TICKET_FAILED","install"===l.waitingFor?"package_install":t?"connection":"ticket","install"===l.waitingFor?"调试包安装失败,请检查客户端提示后重试。":t?"设备连接失败,请重新扫码。":T({code:l.errorCode})??"二维码创建失败,请稍后重试。")}if(this.clearQrImages(),this.patchState(e,{phase:"launching_tool",qr:void 0}),await this.dependencies.openDeviceApp(s.appPath,eR(i)),n=!0,this.deviceAppOpened=!0,t.throwIfAborted(),await this.watchForDisconnect(e,i.namespace,l.client?.clientId),t.throwIfAborted(),"failed"===this.state.phase)return;this.replaceOperationState(e,{phase:"connected",deadlineAt:void 0,canCancel:!1,canRetry:!1})}catch(i){if(t.aborted){await this.stopDisconnectWatcher(),n&&this.deviceAppOpened&&await this.closeOwnedDeviceApp(),this.cancelled(e);return}let r=i instanceof nv?i:new nv("launching_tool"===this.state.phase?"TOOL_LAUNCH_FAILED":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"TOOL_PREPARE_FAILED":"REAL_DEVICE_DEBUG_FAILED","launching_tool"===this.state.phase?"launch":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"prepare":"connection","launching_tool"===this.state.phase?"豆包开发者工具启动失败,请重试。":"preparing"===this.state.phase||"downloading"===this.state.phase||"installing_tool"===this.state.phase?"豆包开发者工具准备失败,请重试或使用终端 desktop 查看详情。":"真机调试启动失败,请重试。");this.clearQrImages(),this.replaceOperationState(e,{phase:"failed",canCancel:!1,canRetry:!0,error:{code:r.code,stage:r.stage,message:r.message}})}}handlePreparationProgress(e,t){if(t){if("download"===t.phase)return void this.patchState(e,{phase:"downloading",progress:{downloadedBytes:t.downloadedBytes,...void 0===t.totalBytes?{}:{totalBytes:t.totalBytes},...void 0===t.percentage?{}:{percentage:t.percentage}}});"install"===t.phase&&this.patchState(e,{phase:"installing_tool",progress:{installStage:t.stage}})}}async getControlClient(){return this.controlClient?this.controlClient:(this.controlClientPromise||(this.controlClientPromise=this.dependencies.connectClient({projectPath:this.options.projectPath,appDir:this.options.appDir,nodeIdPrefix:"web-real-device"}).then(e=>(this.controlClient=e,e)).catch(e=>{throw this.controlClientPromise=void 0,e})),this.controlClientPromise)}async watchForDisconnect(e,t,n){await this.stopDisconnectWatcher();let r=this.dependencies.createDisconnectWatcher(t,async t=>{t===n&&this.isCurrentState(e)&&("launching_tool"===this.state.phase||"connected"===this.state.phase)&&(this.clearQrImages(),this.replaceState({phase:"failed",canCancel:!1,canRetry:!0,error:{code:"DEVICE_DISCONNECTED",stage:"disconnect",message:"真机连接已断开,请重新扫码。"}}),this.deviceAppOpened&&await this.closeOwnedDeviceApp())});(await r.start(),this.isCurrent(e))?this.disconnectWatcher=r:await r.stop().catch(()=>void 0)}async closeOwnedDeviceApp(){if(this.deviceAppClosePromise)return this.deviceAppClosePromise;if(this.deviceAppOpened){this.deviceAppOpened=!1,this.deviceAppClosePromise=this.dependencies.closeDeviceApp().then(()=>void 0,()=>void 0);try{await this.deviceAppClosePromise}finally{this.deviceAppClosePromise=void 0}}}async stopDisconnectWatcher(){let e=this.disconnectWatcher;this.disconnectWatcher=void 0,await e?.stop().catch(()=>void 0)}cancelled(e){this.clearQrImages(),this.replaceOperationState(e,{phase:"cancelled",connectionMode:void 0,deadlineAt:void 0,canCancel:!1,canRetry:!0})}fail(e,t,n){this.replaceState({phase:"failed",canCancel:!1,canRetry:!0,error:{code:e,stage:t,message:n}})}patchState(e,t){this.isCurrent(e)&&this.replaceState(t)}replaceOperationState(e,t){this.isCurrentState(e)&&this.replaceState(t)}replaceState(e){this.state={...this.state,...e,revision:this.state.revision+1,...e.phase&&!("error"in e)&&"failed"!==e.phase&&"timed_out"!==e.phase?{error:void 0}:{},...e.phase&&"waiting_for_scan"!==e.phase?{qr:void 0}:{},...e.phase&&"downloading"!==e.phase&&"installing_tool"!==e.phase?{progress:void 0}:{}}}clearQrImages(){this.qrImages=void 0}isCurrent(e){return this.activeOperation===e&&!e.abortController.signal.aborted}isCurrentState(e){return this.state.operationId===e.id}isActive(){return nh.has(this.state.phase)}}class nv extends Error{code;stage;constructor(e,t,n){super(n),this.code=e,this.stage=t}}function ny(){return new w("dev").description("启动 dev 调试控制台(Web 模拟器、真机调试、页面和卡片推送)").option("--project <path>","dbx 项目路径,状态数据会写入该目录下的 node_modules/.doubao-dev",".").option("--mcp-endpoint <endpoint>","HTTP(S) URL,临时覆盖 manifest.mcp_server.end_point;优先级高于环境变量和 manifest").option("--manifest <path>","manifest.yaml 路径;相对路径按 --project 解析,默认按项目布局自动解析").option("--skill <path>","运行态 Skill 目录;显式目录优先,相对路径按 --project 解析;未传默认 skill/,递归加载所有 SKILL.md").option("--host [host]","开发服务器监听的主机名或 IP;不带值时交互选择,不传时自动选址").option("--verbose","输出开发服务生命周期日志",!1).action(async(e,t)=>M(t,t=>nI(t,{...e,verbose:t.verbose})))}async function nI(e,t){let n=(0,eS.randomUUID)(),r=U(),i={devSessionId:n,actionSequence:1,startedAt:performance.now(),runtimeReady:!1,appId:void 0,eventTrackingReady:r};try{return await nb(e,t,i)}catch(e){if(!i.runtimeReady){let t=performance.now()-i.startedAt,r=R(e);await i.eventTrackingReady,await F({action:"start",actionSequence:1,appId:i.appId,devSessionId:n,durationMs:t,error:e,errorStage:"dev_startup",status:r}),await L({appId:i.appId,command:"dev",durationMs:t,error:e,errorStage:"dev_startup",outputMode:"human",status:r})}throw e}}async function nb(e,t,n){let r,i,o,a;e.json&&e.error("dbx dev 会启动交互式控制台,不支持 --json");let s=n_(),c=t.host;if(!0===c){let t=Reflect.get(await import("./dist~1.js"),"selectDevServerHost");t||e.error("当前内置 SDK 不支持交互选择地址,请升级 SDK,或使用 --host <IP>。"),c=await t()}let l=(0,X.resolve)(t.project),{businessTemplatesPath:d,simulatorManifestPath:p,skillsDirectory:u,warnings:g}=D({projectPath:l,manifest:t.manifest,skill:t.skill}),h=[...g],m=p;if(m){let e=await N(m);h.push(...e.warnings),e.usable?(n.appId=r=e.appId,i=e.manifest):m=void 0}if(d){let e=await $(d,i);h.push(...e.warnings.map(e=>({...e,source:"business_templates"})))}else{let e=q(i,void 0);e&&h.push({...e,source:"business_templates"})}let w=await k(process.env,t.mcpEndpoint,m,i),v=H(i),y=P(i),b=B(l).frontendDirectory,S=new J.PassThrough,C=process.stdin,_=new AbortController,E={},A=new nw({projectPath:l,appDir:b,getRuntime:()=>E.promise?E.promise:Promise.reject(Error("Dev runtime is not ready"))}),T=process.env.DBX_WEB_REAL_DEVICE_DEBUG?.trim()!=="0",O=f({projectPath:l,appDir:b,installSignalHandlers:!0,signal:_.signal,verbose:t.verbose,...T?{realDeviceDebug:{provider:A.provider,dispose:()=>A.dispose()}}:{},devOptions:{...I({host:c,appId:r,permissions:y,mcpEndpoint:w,mcpHeaders:v,simulatorBusinessTemplatesPath:d,simulatorManifestPath:m,skillsDirectory:u,printLogs:s?t.verbose:void 0,onLog:s&&!t.verbose?e=>{("error"!==e.level||"build"!==e.scope||"Failed to bundle template"!==e.message&&"模板打包失败"!==e.message)&&("warn"===e.level||"error"===e.level)&&S.write(`${"error"===e.level?"错误:":"⚠"} ${e.message}
|
|
46
46
|
`)}:void 0,onProgress:s?({percentage:e})=>a?.(e):void 0}),compileHooks:{onAfterDevCompile(e){if(0===e.length)return;let t=new Set(e.map(e=>(0,tj.stripVTControlCharacters)(e.message))),n=`错误:应用编译失败,文件监听仍在运行;修复后将自动重新编译
|
|
47
47
|
${[...t].join("\n")}
|
|
48
48
|
`;s?S.write(n):process.stderr.write(n)},onDevCompileFailed(e){let t=`错误:应用构建失败,文件监听已停止
|
|
49
49
|
${(0,tj.stripVTControlCharacters)(e.stack??e.message)}
|
|
50
|
-
`;s?S.write(t):process.stderr.write(t)}}}}).then(async e=>{o=e,a?.(1),n.appId=e.getState().appId??r,n.runtimeReady=!0;let t=performance.now()-n.startedAt;return await n.eventTrackingReady,await F({action:"start",actionSequence:1,appId:n.appId,devSessionId:n.devSessionId,durationMs:t,status:"success"}),await L({appId:e.getState().appId??r,command:"dev",durationMs:t,outputMode:"human",status:"success"}),e});E.promise=O;let R=
|
|
51
|
-
`);try{let{runInkDevShell:e}=await import("./dev-shell.js");await e({createSession:(e,t,i)=>{S.pipe(e);let a=O.then(r=>{if("running"===r.getState().status)return
|
|
50
|
+
`;s?S.write(t):process.stderr.write(t)}}}}).then(async e=>{o=e,a?.(1),n.appId=e.getState().appId??r,n.runtimeReady=!0;let t=performance.now()-n.startedAt;return await n.eventTrackingReady,await F({action:"start",actionSequence:1,appId:n.appId,devSessionId:n.devSessionId,durationMs:t,status:"success"}),await L({appId:e.getState().appId??r,command:"dev",durationMs:t,outputMode:"human",status:"success"}),e});E.promise=O;let R=x(h);if(!s){let t=await O;R&&e.warn(R,{style:"label"});let n=t.getState();return e.log(`Web 模拟器: ${n.webDebuggerUrl??"-"}`),e.log(`进程 ID:${process.pid}`),e.log("停止服务:按 Ctrl+C 或结束进程"),await t.stopped,nC()}R&&S.write(`⚠ ${R}
|
|
51
|
+
`);try{let{runInkDevShell:e}=await import("./dev-shell.js");await e({createSession:(e,t,i)=>{S.pipe(e);let a=O.then(r=>{if("running"===r.getState().status)return tq({projectPath:l,appDir:b,runtime:{stopped:r.stopped,stop:()=>r.stop(),getState:()=>({...r.getState(),projectPath:l})},output:e,onDeviceAppSetupProgress:i,deviceDebugCoordinator:A,selectItem:t,eventTracking:n})});return Promise.resolve(nS({session:a,stopped:O.then(e=>e.stopped),subscribe:e=>{let t,n=!1;return a.then(r=>{n||(t=r?.subscribe(e))}).catch(()=>void 0),()=>{n=!0,t?.()}},close:async()=>{_.abort(),await o?.stop().catch(()=>void 0)},returnToRoot:async()=>{let e=await a.catch(()=>void 0);await e?.returnToRoot()},getState:()=>o?.getState()??{projectPath:l,appDir:b??l,appId:r,namespace:"",status:"starting",created_at:0,updated_at:0}}))},subscribeCompileProgress:e=>(a=e,()=>{a===e&&(a=void 0)}),stdin:C,toChoices:nc})}finally{_.abort(),await o?.stop().catch(()=>void 0),await A.dispose().catch(()=>void 0),S.destroy()}return nC()}function nS(e){let t,n;return e.session.then(e=>{t=e},()=>void 0),{stopped:e.stopped,cancelActiveCommand:()=>n?.phase!=="waiting"||n.cancelled?t?.cancelActiveCommand()??!1:(n.cancelled=!0,n.resolveCancelled("continue"),!0),close:async()=>{await e.close(),t?await t.close():e.session.then(e=>e?.close()).catch(()=>void 0)},subscribe:e.subscribe,execute(r){let i,o=new Promise(e=>{i=e}),a={cancelled:!1,phase:"waiting",resolveCancelled:i};return n=a,Promise.race([e.session.then(e=>(t=e,a.cancelled)?"continue":(a.phase="running",e?.execute(r)??"continue")),o]).finally(()=>{n===a&&(n=void 0)})},returnToRoot:e.returnToRoot,getState:()=>t?.getState()??e.getState()}}async function nC(){await j(),process.exit(process.exitCode??0)}function n_(e=process.stdin,t=process.stderr){return!!(e.isTTY&&t.isTTY)}export{tK as DEV_SHELL_DEVICE_HELP_ITEMS,tF as DEV_SHELL_HELP_ITEMS,W as dev_namespaceObject,eP as formatDeviceAppSetupStatus};
|