UNPKG

hdw2

Version:

鸿蒙 hdc 调试工具

1,431 lines (1,392 loc) 73.6 kB
#!/usr/bin/env node // src/index.ts import { cyan as cyan4 } from "colorette"; import { Command } from "commander"; // package.json var version = "2.3.7"; // src/core/logger.ts import { cyan, dim, green, red, yellow } from "colorette"; import util from "util"; var useColor = process.stdout.isTTY || !!process.env.CI || process.env.JENKINS_URL; var TAG = "[hdw]"; var logger = class _logger { static format(level, args) { return util.format(level, ...args); } static debug(...args) { const msg = _logger.format("D", args); console.log(TAG, useColor ? dim(msg) : msg); } static info(...args) { const msg = _logger.format("I", args); console.log(TAG, useColor ? cyan(msg) : msg); } static warn(...args) { const msg = _logger.format("W", args); console.log(TAG, useColor ? yellow(msg) : msg); } static success(...args) { const msg = _logger.format("S", args); console.log(TAG, useColor ? green(msg) : msg); } static error(...args) { const msg = _logger.format("E", args); console.log(TAG, useColor ? red(msg) : msg); } static line(line = 1) { for (let i = 0; i < line; i++) { console.log(""); } } }; // src/core/device-manager.ts import shell2 from "shelljs"; // src/core/const.ts import os from "os"; import path from "path"; var HOME = process.env.HOME || os.homedir(); var CONFIG_PATH = path.join(HOME, "./.hdwrc"); var CONFIG_KEY_MAP = { useGlobalHdc: "\u5168\u5C40hdc\u5B58\u5728\u65F6,\u662F\u5426\u4F7F\u7528\u5168\u5C40hdc", bundleName: "\u76EE\u6807\u5E94\u7528bundleName", abilityName: "\u76EE\u6807\u5E94\u7528abilityName", sandboxRootPath: "\u76EE\u6807\u5E94\u7528\u6C99\u7BB1\u6839\u76EE\u5F55", defaultDevice: "\u9ED8\u8BA4\u8BBE\u5907ID", devices: "\u8BBE\u5907\u8BB0\u5F55\u5217\u8868" }; var EXIT_CODE_ERROR = 1; var DEFAULT_WEBVIEW_DEBUG_PORT = 9222; var DEFAULT_FTP_PORT = 9200; var HDC_SUCCESS_KEYWORD = "successfully"; var HDC_FINISH_KEYWORD = "finish"; var CONFIG_BUNDLE_MAP = { sirius: { bundle: "com.zybank.siriusdemo", ability: "EntryAbility" }, pmobile: { bundle: "com.zybank.pmobile.hmos", ability: "EntryAbility" }, yuanxin: { bundle: "com.zyb.yuanxin.hmos", ability: "EntryAbility" }, emobile: { bundle: "com.zyebank.emobile.hmos", ability: "EntryAbility" }, ibh: { bundle: "com.zybank.ibh.hmos", ability: "EntryAbility" } }; var REMOTE_PATH_MAP = { temp: "/data/local/tmp", download: "/storage/media/100/local/files/Docs/Download", share: "/storage/media/100/local/files/Docs/Huawei Share" }; var OS_MAP = { win32: "win", darwin: "mac", linux: "linux" }; var ARCH_MAP = { x64: "x86", ia32: "x86", arm64: "arm", arm: "arm" }; // src/core/util.ts import { execSync } from "child_process"; import fs from "fs"; import os2 from "os"; import path2 from "path"; import { fileURLToPath } from "url"; import shell from "shelljs"; var __filename = fileURLToPath(import.meta.url); var __dirname = path2.dirname(__filename); function hasGlobalHdc() { const hasHdcShell = shell.which("hdc"); return hasHdcShell && hasHdcShell.code === 0; } function hasHdc() { if (hasGlobalHdc()) { return true; } const hdc2 = getHdc(); if (!hdc2) { return false; } const hasHdcShell2 = shell.which(hdc2); return hasHdcShell2 ? hasHdcShell2.code === 0 : false; } function getHdc() { if (process.env.NODE_ENV === "development") { return "hdc"; } const useGlobalHdc = getHdwConfig("useGlobalHdc"); const isExitGlobalHdc = hasGlobalHdc(); if (useGlobalHdc && isExitGlobalHdc) { return "hdc"; } const platformArch = getPlatformArch(); if (!process.env.HDW_PLATFORM_LOGGED) { logger.debug("\u5F53\u524D\u5E73\u53F0:", platformArch); process.env.HDW_PLATFORM_LOGGED = "true"; } if (platformArch === "win-x86") { return path2.join(__dirname, "../toolchains/win-x86/hdc"); } if (platformArch === "mac-x86") { return path2.join(__dirname, "../toolchains/mac-x86/hdc"); } if (platformArch === "mac-arm") { return path2.join(__dirname, "../toolchains/mac-arm/hdc"); } if (platformArch === "linux-x86") { return path2.join(__dirname, "../toolchains/linux-x86/hdc"); } if (isExitGlobalHdc) { return "hdc"; } return ""; } function getHdcWithDevice() { const hdc2 = getHdc(); if (hdc2) { const deviceId = deviceManager.getDefaultDevice()?.deviceId; const tmd = deviceId ? ` -t ${deviceId}` : ""; return `${hdc2}${tmd}`; } return hdc2; } function getConfigPath() { return CONFIG_PATH; } function isConfigExist() { const configPath = getConfigPath(); return fs.existsSync(configPath); } function formatValue(value) { if (value === "true" || value === "false") { return value === "true"; } if (/^\d+$/.test(value)) { return Number(value); } return value; } function getHdwConfig(key) { if (!isConfigExist()) { if (key) { return void 0; } return {}; } const configPath = getConfigPath(); const configStr = fs.readFileSync(configPath, "utf-8"); try { const hdwConfig = JSON.parse(configStr); if (key) { const value = hdwConfig[key]; return value; } return hdwConfig; } catch (error) { logger.error(`hdw\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF,\u8BF7\u4FEE\u6539\u672A\u6807\u51C6json\u683C\u5F0F,\u8DEF\u5F84\u4E3A: ${configPath}`); process.exit(EXIT_CODE_ERROR); } } function setHdwConfig(config, force) { if (!config || typeof config !== "object") { logger.error(`hdw\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF,\u8BF7\u4FEE\u6539\u672A\u6807\u51C6json\u683C\u5F0F`); process.exit(EXIT_CODE_ERROR); } const newConfig = {}; Object.entries(config).forEach(([key, value]) => { if (value !== void 0) { newConfig[key] = formatValue(value); } }); let oldConfig = {}; if (!force) { oldConfig = getHdwConfig(); } const hdwConfig = { ...oldConfig, ...newConfig }; const configPath = getConfigPath(); fs.writeFileSync(configPath, JSON.stringify(hdwConfig, null, 2)); } function writeToClipboard(text) { try { const platform = process.platform; let cmd; if (platform === "win32") { cmd = "clip"; execSync(cmd, { input: text }); } else if (platform === "darwin") { cmd = "pbcopy"; execSync(cmd, { input: text }); } else { cmd = "xclip -selection clipboard"; execSync(cmd, { input: text }); } } catch (error) { logger.warn("\u65E0\u6CD5\u590D\u5236\u5230\u526A\u8D34\u677F\uFF0C\u8BF7\u624B\u52A8\u590D\u5236\u8C03\u8BD5\u5730\u5740"); } } function getPlatformArch() { const platform = os2.platform(); const arch = os2.arch(); const osPart = OS_MAP[platform] || platform; const archPart = ARCH_MAP[arch] || arch; return osPart && archPart ? `${osPart}-${archPart}` : ""; } // src/core/device-manager.ts import { intro, isCancel, select } from "@clack/prompts"; import { cyan as cyan2 } from "colorette"; var DeviceManager = class { config = {}; constructor() { this.config = getHdwConfig(); } /** * 检查设备连接 * @returns */ checkDevices() { const devices2 = this.getRawDevices(); if (devices2.length === 0) { logger.error("\u8BF7\u786E\u8BA4\u8BBE\u5907\u5DF2\u901A\u8FC7USB\u8FDE\u63A5,\u5F00\u542F\u5F00\u53D1\u8005\u6A21\u5F0F\u5E76\u6253\u5F00USB\u8C03\u8BD5\u5F00\u5173"); process.exit(EXIT_CODE_ERROR); } return devices2; } /** * 获取原始设备列表 * @returns */ getRawDevices() { const hdc2 = getHdc(); const deviceListCmd = `${hdc2} list targets`; const deviceListExec = shell2.exec(deviceListCmd, { silent: true }); if (deviceListExec.code !== 0 || deviceListExec.stderr) { logger.error("\u67E5\u8BE2\u8BBE\u5907\u5217\u8868\u5931\u8D25", deviceListExec.stdout || deviceListExec.stderr); process.exit(EXIT_CODE_ERROR); } const deviceListStdout = deviceListExec.stdout; if (deviceListStdout.includes("[Empty]")) { return []; } const devices2 = deviceListStdout.split("\n").filter((line) => line.trim()); return devices2; } /** * 获取当前设备列表 * 返回实时连接的设备列表,不更新配置文件 */ getConnectedDevices(rawDevices) { const devices2 = rawDevices || this.getRawDevices(); if (!devices2) { return []; } const connectedDevices = []; for (const device of devices2) { const parts = device.trim().split(/\s+/); const isDefault = device.startsWith("*"); const deviceId = isDefault ? parts[1] : parts[0]; const deviceName = parts.slice(isDefault ? 2 : 1).join(" "); if (!this.config.devices) { this.config.devices = []; } const index = this.config.devices.findIndex((d) => d.deviceId === deviceId); if (index === -1) { logger.line(); logger.info(`\u6B63\u5728\u83B7\u53D6\u65B0\u8BBE\u5907 [${deviceId}] \u7684\u540D\u79F0...`); const modelName = this.getDeviceModel(deviceId); logger.debug(`\u8BBE\u5907 ${deviceId} \u540D\u79F0: ${modelName}`); const newDevice = { deviceId, name: modelName, nickname: deviceName, lastConnected: (/* @__PURE__ */ new Date()).toLocaleString() }; this.config.devices.push(newDevice); connectedDevices.push({ ...newDevice, connected: true }); } else { const existingDevice = this.config.devices[index]; existingDevice.lastConnected = (/* @__PURE__ */ new Date()).toLocaleString(); if (!existingDevice.name || existingDevice.name === existingDevice.deviceId) { logger.debug(`\u6B63\u5728\u66F4\u65B0\u73B0\u6709\u8BBE\u5907 ${deviceId} \u7684\u540D\u79F0...`); const modelName = this.getDeviceModel(deviceId); logger.debug(`\u8BBE\u5907 ${deviceId} \u65B0\u540D\u79F0: ${modelName}`); if (modelName && modelName !== existingDevice.deviceId && modelName !== "null" && modelName !== "undefined") { existingDevice.name = modelName; logger.debug(`\u5DF2\u66F4\u65B0\u8BBE\u5907 ${deviceId} \u7684\u540D\u79F0\u4E3A: ${modelName}`); } } connectedDevices.push({ ...existingDevice, connected: true }); } } return connectedDevices; } /** * 设置设备列表 * @returns 设备列表 */ setDevices(devices2, isOverwrite = false) { if (!this.config.devices) { this.config.devices = []; } if (isOverwrite) { this.config.devices = devices2; } else { for (const device of devices2) { const index = this.config.devices.findIndex((d) => d.deviceId === device.deviceId); delete device.connected; if (index !== -1) { this.config.devices[index] = { ...this.config.devices[index], ...device, lastConnected: device.lastConnected || this.config.devices[index].lastConnected }; } else { this.config.devices.push(device); } } } this.saveConfig(); } /** * 打印设备列表 * @param connectedDevices */ printConnectedDevices(rawDevices) { const connectedDevices = deviceManager.getConnectedDevices(rawDevices); logger.line(); logger.info("=== \u5F53\u524D\u5DF2\u8FDE\u63A5\u8BBE\u5907 ==="); if (connectedDevices.length > 0) { const defaultDevice = deviceManager.getDefaultDevice(); connectedDevices.forEach((device) => { const displayName = device.nickname || device.name || device.deviceId; const isDefault = device.deviceId === defaultDevice?.deviceId; const status = device.connected ? "[\u5728\u7EBF]" : "[\u79BB\u7EBF]"; const mark = isDefault ? "[\u9ED8\u8BA4]" : ""; logger.info(` ${device.deviceId} ${displayName} ${status} ${mark}`); }); } else { logger.warn("\u6CA1\u6709\u5DF2\u8FDE\u63A5\u7684\u8BBE\u5907"); } return connectedDevices; } /** * 获取所有设备记录(包含连接状态) */ getAllDevicesWithStatus(formDevices) { let connectedDevices; if (formDevices) { if (typeof formDevices[0] === "string") { connectedDevices = deviceManager.getConnectedDevices(formDevices); } else { connectedDevices = formDevices; } } else { connectedDevices = deviceManager.getConnectedDevices(); } const connectedDevicesSets = new Set(connectedDevices.map((d) => d.deviceId)); const devices2 = this.config.devices || []; return devices2.map((device) => ({ ...device, connected: connectedDevicesSets.has(device.deviceId) })); } /** * 获取默认设备 */ getDefaultDevice() { const defaultId = this.config.defaultDevice; if (!defaultId) return null; const allDevices = this.getAllDevicesWithStatus(); const device = allDevices.find((d) => d.deviceId === defaultId); if (device && device.connected) { return device; } const firstConnected = allDevices.find((d) => d.connected); return firstConnected || null; } /** * 设置默认设备 */ setDefaultDevice(deviceId) { const devices2 = this.config.devices || []; const device = devices2.find((d) => d.deviceId === deviceId); if (!device) { logger.error(`\u8BBE\u5907\u4E0D\u5B58\u5728: ${deviceId}`); return false; } this.config.defaultDevice = deviceId; const displayName = device.nickname || device.name || device.deviceId; this.saveConfig(); logger.success(`\u5DF2\u8BBE\u7F6E\u9ED8\u8BA4\u8BBE\u5907: ${deviceId}${displayName ? ` (${displayName})` : ""}`); return true; } /** * 清除默认设备 */ clearDefaultDevice() { delete this.config.defaultDevice; this.saveConfig(); logger.success("\u5DF2\u6E05\u9664\u9ED8\u8BA4\u8BBE\u5907"); return true; } /** * 清除默认设备 */ clearDevices() { delete this.config.devices; this.saveConfig(); logger.success("\u5DF2\u6E05\u9664\u8BBE\u5907\u5217\u8868"); return true; } /** * 清除默认设备和设备列表 */ clearDefaultDeviceAndDevices() { delete this.config.defaultDevice; delete this.config.devices; this.saveConfig(); logger.success("\u5DF2\u6E05\u9664\u9ED8\u8BA4\u8BBE\u5907\u548C\u8BBE\u5907\u5217\u8868"); return true; } /** * 设置设备备注 */ setDeviceNickname(deviceId, nickname) { const devices2 = this.config.devices || []; const device = devices2.find((d) => d.deviceId === deviceId); if (!device) { logger.error(`\u8BBE\u5907\u4E0D\u5B58\u5728: ${deviceId}`); return false; } device.nickname = nickname; this.saveConfig(); logger.success(`\u5DF2\u8BBE\u7F6E\u8BBE\u5907\u5907\u6CE8: ${deviceId} -> ${nickname}`); return true; } /** * 获取所有设备记录(包含实时连接状态) */ getAllDevices(formDevices) { return this.getAllDevicesWithStatus(formDevices); } /** * 获取设备显示名称(优先显示备注) */ getDeviceDisplayName(device) { return device.nickname || device.name || device.deviceId; } /** * 移除设备记录 */ removeDevice(deviceId) { const devices2 = this.config.devices || []; if (!devices2 || devices2.length === 0) { logger.error(`\u8BBE\u5907\u4E0D\u5B58\u5728: ${deviceId}`); return false; } const index = devices2.findIndex((d) => d.deviceId === deviceId); if (index === -1) { logger.error(`\u8BBE\u5907\u4E0D\u5B58\u5728: ${deviceId}`); return false; } devices2.splice(index, 1); if (this.config.defaultDevice === deviceId) { delete this.config.defaultDevice; } this.saveConfig(); logger.success(`\u5DF2\u79FB\u9664\u8BBE\u5907\u8BB0\u5F55: ${deviceId}`); return true; } /** * 获取设备名称 */ getDeviceModel(deviceId) { const hdc2 = getHdc(); const cmd = `${hdc2} -t ${deviceId} shell param get const.product.name`; logger.debug(`\u6267\u884C\u547D\u4EE4: ${cmd}`); const exec = shell2.exec(cmd, { silent: true }); logger.debug( `\u83B7\u53D6\u8BBE\u5907\u540D\u79F0\u7ED3\u679C: code=${exec.code}, stdout="${exec.stdout.trim()}", stderr="${exec.stderr.replace(/\n/g, "")}"` ); if (exec.code === 0 && exec.stdout && !exec.stdout.includes("[Fail]") && !exec.stdout.includes("[Fail]ExecuteCommand")) { const name = exec.stdout.trim(); if (name && name !== "" && name !== "null" && name !== "undefined") { logger.debug(`\u6210\u529F\u83B7\u53D6\u8BBE\u5907\u540D\u79F0: ${name}`); return name; } } const cmd2 = `${hdc2} -t ${deviceId} shell param const.product.model`; logger.debug(`\u6267\u884C\u547D\u4EE4\u83B7\u53D6\u8BBE\u5907\u578B\u53F7: ${cmd2}`); const cmd2Exec = shell2.exec(cmd2, { silent: true }); logger.debug(`\u83B7\u53D6\u8BBE\u5907\u578B\u53F7\u7ED3\u679C: code=${cmd2Exec.code}, stdout="${cmd2Exec.stdout}"`); if (cmd2Exec.code === 0 && cmd2Exec.stdout && !cmd2Exec.stdout.includes("[Fail]")) { const model = cmd2Exec.stdout.trim(); if (model && model !== "") { logger.debug(`\u6210\u529F\u83B7\u53D6\u8BBE\u5907\u578B\u53F7: ${model}`); return model; } } logger.debug(`\u4F7F\u7528\u8BBE\u5907ID\u4F5C\u4E3A\u5907\u6CE8: ${deviceId}`); return deviceId; } /** * 保存配置到本地 */ saveConfig() { setHdwConfig(this.config, true); } /** * 设备选择交互界面 */ async createDeviceSelectUI(devices2) { const defaultDevice = this.config.defaultDevice; logger.line(); intro(cyan2("\u9ED8\u8BA4\u8BBE\u5907\u9009\u62E9")); const device = await select({ message: "\u8BF7\u4F7F\u7528\u4E0A\u4E0B\u952E\u9009\u62E9,\u56DE\u8F66\u952E\u786E\u8BA4", options: devices2.map((d) => ({ value: d, label: `${d.deviceId} (${d.nickname || d.name}) ${d.deviceId === defaultDevice ? "(\u5F53\u524D\u9ED8\u8BA4\u8BBE\u5907)" : ""}` })) }); if (isCancel(device)) { logger.info("\u5DF2\u53D6\u6D88\u9009\u62E9"); process.exit(EXIT_CODE_ERROR); } return device; } }; var deviceManager = new DeviceManager(); // src/core/check.ts function check(options = {}) { logger.debug("\u68C0\u67E5\u9E3F\u8499\u8BBE\u5907\u8FDE\u63A5\u72B6\u6001..."); const devices2 = deviceManager.checkDevices(); logger.success("\u8BBE\u5907\u8FDE\u63A5\u6B63\u5E38"); const connectedDevices = deviceManager.printConnectedDevices(devices2); deviceManager.setDevices(connectedDevices); } // src/commands/check.ts function registerCheckCommand(program2) { program2.command("check").description("\u68C0\u67E5\u5F53\u524D\u73AF\u5883\u662F\u5426\u53EF\u8FDB\u884Cwebview\u8C03\u8BD5").action(async (options) => { check(options); }); } // src/core/clear.ts import shell4 from "shelljs"; // src/core/list.ts import shell3 from "shelljs"; function list(options = {}) { const hdc2 = getHdcWithDevice(); if (!options.isGetValue) { logger.debug("\u67E5\u8BE2\u7AEF\u53E3\u6620\u5C04\u5217\u8868..."); } const fportLsCmd = `${hdc2} fport ls`; logger.debug("\u6267\u884C\u547D\u4EE4:", fportLsCmd); const fportLsExec = shell3.exec(fportLsCmd, { silent: true }); if (fportLsExec.code !== 0 || /\[Fail\]/.test(fportLsExec.stdout)) { logger.error("\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u67E5\u8BE2\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } const fportLsStdout = fportLsExec.stdout; const isEmpty = fportLsStdout.includes("[Empty]"); if (isEmpty) { if (options.isGetValue) { return ""; } logger.warn("\u5F53\u524D\u65E0\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04"); process.exit(0); } if (!options.isGetValue) { logger.success(`\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u5217\u8868: ${fportLsStdout}`); } return fportLsStdout; } // src/core/clear.ts function clear(options = {}) { const hdc2 = getHdcWithDevice(); logger.debug("\u6E05\u7A7A\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04..."); const fportLsStdout = list({ isGetValue: true }); if (!fportLsStdout) { logger.success("\u5F53\u524D\u65E0\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04"); process.exit(0); } if (!options.isGetValue) { logger.debug("\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u5217\u8868:", fportLsStdout); } const fportList = Array.from(new Set(fportLsStdout.split(/\n|\r/).filter((item) => item))); const localRemoteArr = fportList.map((item) => { const arr = item.split(/\s+/); const localRemoteArr2 = arr.slice(1, 3); if (localRemoteArr2.length === 2) { return localRemoteArr2; } return null; }).filter((item) => !!item); for (let i = 0; i < localRemoteArr.length; i++) { const localRemote = localRemoteArr[i]; const fportCmd = `${hdc2} fport rm ${localRemote[0]} ${localRemote[1]}`; if (!options.isGetValue) { logger.debug("\u6267\u884C\u547D\u4EE4:", fportCmd); } const pidExec = shell4.exec(fportCmd, { silent: true }); if (pidExec.code !== 0 || !/success/.test(pidExec.stdout)) { logger.error("\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u6E05\u9664\u5931\u8D25", pidExec.stdout); process.exit(EXIT_CODE_ERROR); } } logger.success("\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u6E05\u9664\u6210\u529F"); } // src/commands/clear.ts function registerClearCommand(program2) { program2.command("clear").description("\u6E05\u7A7A\u5F53\u524Dwebview\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04").action(async (options) => { clear(options); }); } // src/core/config/del-handler.ts function registerDelHandler(manager) { manager.register("del", { format: "<key>", desc: "\u5220\u9664\u914D\u7F6E\u9879", handler: delHandler }); } function delHandler(key) { if (!key) { logger.error("\u8BF7\u8F93\u5165\u8981\u5220\u9664\u7684key"); process.exit(EXIT_CODE_ERROR); } const configPath = getConfigPath(); logger.debug("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:", configPath); const config = getHdwConfig(); delete config[key]; setHdwConfig(config, true); logger.success(`\u5220\u9664\u6210\u529F: ${JSON.stringify(config, null, 2)}`); } // src/core/config/get-handler.ts function registerGetHandler(manager) { manager.register("get", { format: "<key>", desc: "\u83B7\u53D6\u914D\u7F6E\u9879", handler: getHandler }); } function getHandler(key) { if (!key) { logger.error("\u8BF7\u8F93\u5165\u8981\u83B7\u53D6\u7684key"); process.exit(EXIT_CODE_ERROR); } const configPath = getConfigPath(); logger.debug("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:", configPath); const configValue = getHdwConfig(key); if (typeof configValue === "undefined") { logger.warn(`${key} \u5BF9\u5E94\u7684\u914D\u7F6E\u9879\u4E0D\u5B58\u5728`); process.exit(0); } logger.success(`${key}\u7684\u503C\u4E3A: ${configValue}`); } // src/core/config/list-handler.ts function registerListHandler(manager) { manager.register("list", { format: "", desc: "\u83B7\u53D6\u5F53\u524D\u914D\u7F6E\u9879\u5217\u8868", handler: listHandler }); } function listHandler() { const configPath = getConfigPath(); logger.debug("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:", configPath); const config = getHdwConfig(); logger.success(`\u914D\u7F6E\u5217\u8868: ${JSON.stringify(config, null, 2)}`); } // src/core/config/set-handler.ts function registerSetHandler(manager) { manager.register("set", { format: "<key> <value>", desc: "\u8BBE\u7F6E\u914D\u7F6E\u9879", handler: setHandler }); } function setHandler(key, value) { if (!key) { logger.error("\u8BF7\u8F93\u5165\u8981\u8BBE\u7F6E\u7684key"); process.exit(EXIT_CODE_ERROR); } if (!value) { logger.error("\u8BF7\u8F93\u5165\u8981\u8BBE\u7F6E\u7684\u503C"); process.exit(EXIT_CODE_ERROR); } const configPath = getConfigPath(); logger.debug("\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84:", configPath); setHdwConfig({ [key]: value }); const config = getHdwConfig(); logger.success(`\u8BBE\u7F6E\u6210\u529F: ${JSON.stringify(config, null, 2)}`); } // src/core/config/index.ts function registerConfigHandlers(manager) { registerListHandler(manager); registerSetHandler(manager); registerGetHandler(manager); registerDelHandler(manager); } // src/core/keyed-manager.ts var KeyedManager = class { defines = /* @__PURE__ */ new Map(); register(key, keyedItem) { this.defines.set(key, keyedItem); } has(key) { return this.defines.has(key); } getKeys() { return Array.from(this.defines.keys()); } getHandler(key) { const item = this.defines.get(key); if (!item) { return null; } return item.handler; } getHelp() { const title = "\n\u652F\u6301\u7684\u547D\u4EE4\u5217\u8868:"; const defines = Array.from(this.defines.entries()); const helpContents = defines.map(([key, item]) => { return `${" ".repeat(2)} ${key} ${item.format} ${item.desc}`; }); return `${title} ${helpContents.join("\n")}`; } }; // src/commands/config.ts function registerConfigCommand(program2) { const manager = new KeyedManager(); registerConfigHandlers(manager); program2.command("config").description("hdw\u914D\u7F6E\u8BBE\u7F6E\u3001\u83B7\u53D6\u3001\u5220\u9664\u7B49\u64CD\u4F5C").argument("<action>", `\u8981\u6267\u884C\u7684\u547D\u4EE4(\u652F\u6301: ${manager.getKeys().join(", ")})`, (action) => { if (!manager.has(action)) { logger.error(`\u8F93\u5165\u7684\u547D\u4EE4: ${action}\u4E0D\u5B58\u5728`); process.exit(1); } return action; }).argument("[values...]", "\u8981\u8BBE\u7F6E\u7684\u503C,\u591A\u4E2A\u4F7F\u7528\u7A7A\u683C\u9694\u5F00").addHelpText("after", () => { const managerHap = manager.getHelp(); const configureHelp = getConfigHelp(); return `${managerHap} ${configureHelp}`; }).action(async (key, values) => { manager.getHandler(key)?.(...values); }); } function getConfigHelp() { const configEntries = Object.entries(CONFIG_KEY_MAP); const helpTitle = "\n\u652F\u6301\u7684\u5B8C\u6574\u914D\u7F6E:\n"; const helpContext = configEntries.map(([key, value]) => { return `${" ".repeat(2)}${key}: ${value}`; }); return `${helpTitle}${helpContext.join("\n")}`; } // src/core/debug.ts import shell5 from "shelljs"; function debug(options = {}) { const hdc2 = getHdcWithDevice(); const fportLsStdout = list({ isGetValue: true }); if (fportLsStdout) { clear({ isGetValue: true }); } logger.debug("\u6620\u5C04\u8C03\u8BD5\u7AEF\u53E3..."); logger.debug("\u67E5\u8BE2\u53EF\u8C03\u8BD5\u5E94\u7528PID\u5217\u8868..."); const catCmd = `${hdc2} shell "cat /proc/net/unix | grep devtools"`; logger.debug("\u6267\u884C\u547D\u4EE4:", catCmd); const pidListExec = shell5.exec(catCmd, { silent: true }); if (pidListExec.code !== 0 || !pidListExec.stdout) { logger.error("\u67E5\u8BE2\u53EF\u8C03\u8BD5\u5E94\u7528PID\u5217\u8868\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } const pidListStdout = pidListExec.stdout; const lines = pidListStdout.split(/\n|\r/).filter((item) => item.includes("webview_devtools_remote_")).map((item) => { return item.split("webview_devtools_remote_")[1]; }); const pidArr = Array.from(new Set(lines)); if (!pidArr.length) { logger.error("\u672A\u67E5\u8BE2\u5230\u53EF\u8C03\u8BD5\u5E94\u7528PID\u5217\u8868"); process.exit(EXIT_CODE_ERROR); } logger.debug("\u5E94\u7528PID\u5217\u8868:", pidArr.join(" ")); logger.debug("\u8FDB\u884C\u7AEF\u53E3\u6620\u5C04..."); const inputPort = parseInt(options.port || ""); let port = inputPort || DEFAULT_WEBVIEW_DEBUG_PORT; logger.debug(`\u6620\u5C04\u8D77\u59CB\u7AEF\u53E3\u53F7: ${port}`); for (let i = 0; i < pidArr.length; i++) { const pid = pidArr[i]; const fportCmd = `${hdc2} fport tcp:${port} localabstract:webview_devtools_remote_${pid}`; logger.debug("\u6267\u884C\u547D\u4EE4:", fportCmd); const pidExec = shell5.exec(fportCmd, { silent: true }); if (pidExec.code !== 0 || /\[Fail\]/.test(pidExec.stdout)) { logger.error(`\u6620\u5C04\u7AEF\u53E3${port}\u5931\u8D25`); process.exit(EXIT_CODE_ERROR); } port++; } logger.debug("\u67E5\u8BE2\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u7ED3\u679C..."); const fportLsCmd = `${hdc2} fport ls`; logger.debug("\u6267\u884C\u547D\u4EE4:", fportLsCmd); const fportLsExec = shell5.exec(fportLsCmd, { silent: true }); if (fportLsExec.code !== 0 || /\[Fail\]/.test(fportLsExec.stdout)) { logger.error("\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u67E5\u8BE2\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } const fportLs = fportLsExec.stdout; logger.debug(`\u8C03\u8BD5\u6620\u5C04\u5217\u8868: ${fportLs}`); logger.success("\u6620\u5C04\u7AEF\u53E3\u6210\u529F"); logger.line(); const edgeUrl = "edge://inspect/#devices"; const chromeUrl = "chrome://inspect/#devices"; const suffix = " ==>\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F"; logger.info("\u8BF7\u6253\u5F00\u6D4F\u89C8\u5668\u8BBF\u95EE\u4EE5\u4E0B\u5730\u5740\u8FDB\u884C\u8C03\u8BD5:"); logger.info("edge: ", edgeUrl, options.chrome ? "" : suffix); logger.info("chrome: ", chromeUrl, options.chrome ? suffix : ""); const curUrl = options.chrome ? chromeUrl : edgeUrl; writeToClipboard(curUrl); } // src/commands/debug.ts function registerDebugCommand(program2) { program2.command("debug").option("-p --port <\u7AEF\u53E3\u53F7>", "\u81EA\u5B9A\u4E49\u8C03\u8BD5\u6620\u5C04\u7AEF\u53E3").option("-c --chrome", "\u4F7F\u7528Chrome\u6D4F\u89C8\u5668\u8C03\u8BD5,\u9ED8\u8BA4\u4F7F\u7528Edge", false).description("\u5F00\u59CBwebview\u8C03\u8BD5").action(async (options) => { debug(options); }); } // src/core/devices.ts function devices(options = {}) { logger.debug("\u68C0\u67E5\u9E3F\u8499\u8BBE\u5907\u8FDE\u63A5\u72B6\u6001..."); const devices2 = deviceManager.checkDevices(); const connectedDevices = deviceManager.printConnectedDevices(devices2); const allDevices = deviceManager.getAllDevices(connectedDevices); if (connectedDevices.length > 1 && !deviceManager.getDefaultDevice()) { logger.info('\u63D0\u793A\uFF1A\u4F7F\u7528 "hdw use" \u9009\u62E9\u9ED8\u8BA4\u8BBE\u5907'); } deviceManager.setDevices(connectedDevices); if (options.all && allDevices.length > connectedDevices.length) { logger.line(); logger.debug("=== \u5386\u53F2\u8BBE\u5907 ==="); allDevices.filter((device) => !device.connected).forEach((device) => { const displayName = device.nickname || device.name || device.deviceId; const lastConnected = new Date(device.lastConnected).toLocaleString(); logger.debug(` ${device.deviceId} ${displayName} - \u6700\u540E\u8FDE\u63A5: ${lastConnected}`); logger.line(); }); } } // src/commands/devices.ts function registerDevicesCommand(program2) { program2.command("devices").option("-a --all", "\u663E\u793A\u6240\u6709\u8BBE\u5907", false).description("\u68C0\u67E5\u5F53\u524D\u73AF\u5883,\u83B7\u53D6\u8BBE\u5907\u5217\u8868").action(async (options) => { devices(options); }); } // src/core/get/api-version-handler.ts import shell6 from "shelljs"; function registerApiVersionHandler(manager) { manager.register("apiVersion", { format: "", desc: "\u83B7\u53D6\u7CFB\u7EDFapi\u7248\u672C", handler: apiVersionHandler }); } function apiVersionHandler() { const hdc2 = getHdcWithDevice(); logger.debug("\u83B7\u53D6\u7CFB\u7EDFAPI\u7248\u672C..."); const apiCmd = `${hdc2} shell param get const.ohos.apiversion`; logger.debug("\u6267\u884C\u547D\u4EE4:", apiCmd); const apiExec = shell6.exec(apiCmd, { silent: true }); if (apiExec.code !== 0) { logger.error("\u83B7\u53D6\u7CFB\u7EDFAPI\u7248\u672C\u5931\u8D25", apiExec.stdout); process.exit(EXIT_CODE_ERROR); } const apiVersion = apiExec.replace(/\s*/g, ""); if (!apiVersion || !/^d+$/.test(apiVersion)) { logger.error("\u83B7\u53D6\u7CFB\u7EDFAPI\u7248\u672C\u5931\u8D25", apiExec.stdout); process.exit(EXIT_CODE_ERROR); } logger.debug("\u83B7\u53D6\u7CFB\u7EDFAPI\u7248\u672C\u6210\u529F"); logger.success(`\u7CFB\u7EDFAPI\u7248\u672C: ${apiVersion}`); } // src/core/get/hdc-handler.ts function registerHdcHandler(manager) { manager.register("hdc", { format: "", desc: "\u83B7\u53D6hdc\u547D\u4EE4\u8DEF\u5F84", handler: hdcHandler }); } function hdcHandler() { const hdc2 = getHdc(); logger.debug("\u83B7\u53D6hdc\u547D\u4EE4\u8DEF\u5F84..."); logger.debug("\u83B7\u53D6hdc\u547D\u4EE4\u8DEF\u5F84\u6210\u529F"); logger.success(`hdc\u547D\u4EE4\u8DEF\u5F84: ${hdc2}`); } // src/core/get/udid-handler.ts import shell7 from "shelljs"; function registerUdidHandler(manager) { manager.register("udid", { format: "", desc: "\u83B7\u53D6\u8BBE\u5907UDID", handler: udidHandler }); } function udidHandler() { const hdc2 = getHdcWithDevice(); logger.debug("\u67E5\u8BE2\u8BBE\u5907udid..."); const udidCmd = `${hdc2} shell bm get --udid`; logger.debug("\u6267\u884C\u547D\u4EE4:", udidCmd); const udidExec = shell7.exec(udidCmd, { silent: true }); if (udidExec.code !== 0) { logger.error("\u83B7\u53D6\u8BBE\u5907udid\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } const udid = udidExec.stdout.split(/[\r\n]/).find((item) => /^[a-zA-z0-9]{64,}$/.test(item)); if (!udid) { logger.error("\u83B7\u53D6\u8BBE\u5907udid\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } logger.debug("\u67E5\u8BE2\u8BBE\u5907udid\u6210\u529F"); logger.success(`UDID: ${udid}`); } // src/core/get/index.ts function registerGetHandlers(manager) { registerHdcHandler(manager); registerUdidHandler(manager); registerApiVersionHandler(manager); } // src/commands/get.ts function registerGetCommand(program2) { const manager = new KeyedManager(); registerGetHandlers(manager); program2.command("get").description("\u83B7\u53D6Hdc\u7684\u5E38\u7528\u6570\u636E").argument("<name>", `\u8981\u83B7\u53D6\u7684\u6570\u636E\u540D\u79F0(\u652F\u6301: ${manager.getKeys().join(", ")})`, (key) => { if (!manager.has(key)) { logger.error(`\u8F93\u5165\u7684\u6570\u636E\u540D\u79F0: ${key}\u4E0D\u5B58\u5728`); process.exit(1); } return key; }).addHelpText("after", manager.getHelp()).action(async (key) => { manager.getHandler(key)?.(); }); } // src/core/hdc.ts import shell8 from "shelljs"; function hdc(options = {}, extArgs = []) { const rawHdc = getHdc(); if (options.V) { extArgs.push("-v"); } else if (options.H) { extArgs.push("-h"); } logger.debug("\u6267\u884Chdc\u547D\u4EE4..."); const hdcCmd = `${rawHdc} ${extArgs.join(" ")}`; logger.debug(`\u6267\u884Chdc\u547D\u4EE4: ${hdcCmd}`); const hdcCmdExec = shell8.exec(hdcCmd, { silent: true, async: true }); let hdcStdout = ""; hdcCmdExec.stdout?.once("data", () => { logger.debug("HDC\u547D\u4EE4\u8F93\u51FA:"); }); hdcCmdExec.stdout?.on("data", (data) => { hdcStdout += data; logger.debug(data); }); hdcCmdExec.stderr?.on("data", (data) => { if (options.H) { logger.debug(data); return; } logger.error(data); }); hdcCmdExec.on("error", (err) => { logger.error("HDC\u547D\u4EE4\u6267\u884C\u5931\u8D25", err); process.exit(EXIT_CODE_ERROR); }); hdcCmdExec.on("close", () => { logger.success("HDC\u547D\u4EE4\u6267\u884C\u5B8C\u6210"); }); } // src/commands/hdc.ts function registerHdcCommand(program2) { program2.command("hdc [extArgs...]").description("\u6267\u884Chdc\u547D\u4EE4").option("-V", "hdc\u7248\u672C\u53F7").option("-H", "hdc\u5E2E\u52A9\u4FE1\u606F").allowUnknownOption(true).action(async (extArgs = [], options) => { hdc(options, extArgs); }); } // src/core/install.ts import AdmZip from "adm-zip"; import fs2 from "fs"; import path3 from "path"; import shell9 from "shelljs"; function cleanupTempDir(tempDirPath) { try { if (fs2.existsSync(tempDirPath)) { shell9.rm("-rf", tempDirPath); logger.debug("\u5DF2\u6E05\u7406\u4E34\u65F6\u76EE\u5F55:", tempDirPath); } } catch (err) { logger.warn("\u6E05\u7406\u4E34\u65F6\u76EE\u5F55\u5931\u8D25:", err); } } function install(_options = {}, extArgs = []) { const hdc2 = getHdcWithDevice(); const installPath = extArgs[0]; if (!installPath) { logger.error("\u8BF7\u63D0\u4F9B\u8981\u5B89\u88C5\u7684\u6587\u4EF6\u8DEF\u5F84"); process.exit(EXIT_CODE_ERROR); } logger.debug("\u5B89\u88C5\u5E94\u7528..."); let installTarget; let bundleName = ""; let tempDirPath = ""; const lowerInstallPath = installPath.toLowerCase(); if (!lowerInstallPath.endsWith(".hap") && !lowerInstallPath.endsWith(".zip")) { logger.error("\u5B89\u88C5\u5305\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u4EC5\u652F\u6301.hap\u6216.zip\u6587\u4EF6"); process.exit(EXIT_CODE_ERROR); } const isZip = lowerInstallPath.endsWith(".zip"); if (isZip) { const zipPath = path3.resolve(installPath); if (!fs2.existsSync(zipPath)) { logger.error("ZIP\u6587\u4EF6\u4E0D\u5B58\u5728"); process.exit(EXIT_CODE_ERROR); } const dirName = path3.dirname(zipPath); const fileNameWithoutExt = path3.basename(zipPath, ".zip"); const tempDirName = `${fileNameWithoutExt.replace(/\s+/g, "")}_temp`; tempDirPath = path3.join(dirName, tempDirName); if (fs2.existsSync(tempDirPath)) { shell9.rm("-rf", tempDirPath); logger.debug(`\u5DF2\u5220\u9664\u5DF2\u5B58\u5728\u7684\u4E34\u65F6\u76EE\u5F55: ${tempDirPath}`); } logger.debug(`\u6B63\u5728\u89E3\u538BZIP\u6587\u4EF6: ${zipPath}`); logger.debug(`\u89E3\u538B\u5230\u4E34\u65F6\u76EE\u5F55: ${tempDirPath}`); try { if (!fs2.existsSync(tempDirPath)) { fs2.mkdirSync(tempDirPath, { recursive: true }); } const zip = new AdmZip(zipPath); const fileList = zip.getEntries(); const fmtList = fileList.map((file, index) => `${index + 1}. ${file.entryName}`); logger.debug(`\u6587\u4EF6\u5217\u8868(\u5171${fmtList.length}\u4E2A): ${fmtList.join("\n")}`); const isApp = fileList.some((file) => file.entryName.endsWith(".app")); if (isApp) { logger.error("app\u6587\u4EF6\u4E0D\u652F\u6301\u5B89\u88C5"); cleanupTempDir(tempDirPath); process.exit(EXIT_CODE_ERROR); } const hapFile = fileList.find((file) => file.entryName.endsWith(".hap")); if (!hapFile) { logger.error("\u672A\u627E\u5230hap\u6587\u4EF6"); cleanupTempDir(tempDirPath); process.exit(EXIT_CODE_ERROR); } zip.extractAllTo(tempDirPath, true); logger.debug("\u89E3\u538B\u5B8C\u6210"); logger.debug(`\u627E\u5230hap\u6587\u4EF6: ${hapFile.entryName}`); bundleName = getBundleName(path3.join(tempDirPath, hapFile.entryName)); } catch (err) { logger.error("\u89E3\u538B\u5931\u8D25", err); cleanupTempDir(tempDirPath); process.exit(EXIT_CODE_ERROR); } installTarget = tempDirPath; } else { const hapPath = path3.resolve(installPath); if (!fs2.existsSync(hapPath)) { logger.error(`HAP\u6587\u4EF6\u4E0D\u5B58\u5728: ${hapPath}`); process.exit(EXIT_CODE_ERROR); } installTarget = hapPath; bundleName = getBundleName(hapPath); } if (bundleName) { uninstall(bundleName); } const hdcCmd = `${hdc2} install ${installTarget}`; logger.debug("\u6267\u884C\u547D\u4EE4:", hdcCmd); const hdcCmdExec = shell9.exec(hdcCmd, { silent: true, async: true }); let hdcStdout = ""; hdcCmdExec.stdout?.once("data", () => { logger.debug("HDC\u547D\u4EE4\u8F93\u51FA:"); }); hdcCmdExec.stdout?.on("data", (data) => { hdcStdout += data; logger.debug(data); }); hdcCmdExec.stderr?.on("data", (data) => { logger.error(data); }); hdcCmdExec.on("error", () => { logger.error("\u5E94\u7528\u5B89\u88C5\u5931\u8D25"); cleanupTempDir(tempDirPath); process.exit(EXIT_CODE_ERROR); }); hdcCmdExec.on("close", () => { const isSuccess = hdcStdout.includes(HDC_SUCCESS_KEYWORD); if (isSuccess) { logger.success("\u5E94\u7528\u5B89\u88C5\u6210\u529F"); cleanupTempDir(tempDirPath); } else { logger.error("\u5E94\u7528\u5B89\u88C5\u5931\u8D25,\u8BF7\u5148\u624B\u52A8\u5378\u8F7D\u5E94\u7528\u540E\u91CD\u8BD5"); cleanupTempDir(tempDirPath); process.exit(EXIT_CODE_ERROR); } }); } function uninstall(bundleName) { const hdc2 = getHdcWithDevice(); const uninstallCmd = `${hdc2} uninstall ${bundleName}`; logger.debug("\u6267\u884C\u547D\u4EE4:", uninstallCmd); const fportLsExec = shell9.exec(uninstallCmd, { silent: true }); if (fportLsExec.code !== 0) { logger.warn("\u5E94\u7528\u5378\u8F7D\u5931\u8D25", fportLsExec.stdout); return; } if (fportLsExec.stdout.includes("code:9568386")) { logger.success("\u5E94\u7528\u672A\u5B89\u88C5,\u65E0\u9700\u5378\u8F7D"); return; } if (!fportLsExec.stdout.includes(HDC_SUCCESS_KEYWORD)) { logger.warn("\u5E94\u7528\u5378\u8F7D\u5931\u8D25", fportLsExec.stdout); return; } logger.success(`\u5E94\u7528\u5378\u8F7D\u6210\u529F,bundleName: ${bundleName}`); } function getBundleName(hapPath) { logger.debug("hap\u6587\u4EF6\u8DEF\u5F84:", hapPath); const hapZip = new AdmZip(hapPath); const packInfoEntry = hapZip.getEntry("pack.info"); if (!packInfoEntry) { logger.error("hap\u4E2D\u672A\u627E\u5230pack.info\u6587\u4EF6"); return ""; } const packInfoContent = hapZip.readAsText(packInfoEntry, "utf8"); const packInfo = JSON.parse(packInfoContent); const bundleName = packInfo.summary?.app?.bundleName; logger.debug("bundleName:", bundleName || ""); if (!bundleName) { logger.warn("\u672A\u627E\u5230bundleName"); return ""; } return bundleName; } // src/commands/install.ts function registerInstallCommand(program2) { program2.command("install [extArgs...]").description("\u5E94\u7528\u5B89\u88C5,\u4F20\u53C2\u540Chdc install,\u652F\u6301zip\u3001hap\u683C\u5F0F").action(async (extArgs = [], options) => { install(options, extArgs); }); } // src/commands/list.ts function registerListCommand(program2) { program2.command("list").description("\u67E5\u8BE2\u5F53\u524Dwebview\u8C03\u8BD5\u7AEF\u53E3\u6620\u5C04\u5217\u8868").action(async (options) => { list(options); }); } // src/core/ls.ts import shell10 from "shelljs"; import { bold, cyan as cyan3, dim as dim2, green as green2, yellow as yellow2 } from "colorette"; // src/core/fs-utils.ts import fs3 from "fs"; import path4 from "path"; function formatFileSize(size) { if (size === 0) return "0 B"; const units = ["B", "KB", "MB", "GB", "TB"]; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${parseFloat(size.toFixed(2))} ${units[unitIndex]}`; } function getFileTypeDesc(name, isDir) { if (isDir) return "\u76EE\u5F55"; const ext = path4.extname(name).toLowerCase(); const typeMap = { ".txt": "\u6587\u672C\u6587\u4EF6", ".log": "\u65E5\u5FD7\u6587\u4EF6", ".hap": "HAP\u5E94\u7528\u5305", ".hsp": "HSP\u5171\u4EAB\u5305", ".zip": "ZIP\u538B\u7F29\u5305", ".rar": "RAR\u538B\u7F29\u5305", ".7z": "7Z\u538B\u7F29\u5305", ".tar": "TAR\u5F52\u6863", ".gz": "GZ\u538B\u7F29\u5305", ".so": "\u52A8\u6001\u5E93", ".apk": "APK\u5B89\u88C5\u5305", ".exe": "\u53EF\u6267\u884C\u6587\u4EF6", ".dll": "DLL\u52A8\u6001\u5E93", ".png": "PNG\u56FE\u7247", ".jpg": "JPG\u56FE\u7247", ".jpeg": "JPEG\u56FE\u7247", ".gif": "GIF\u56FE\u7247", ".svg": "SVG\u56FE\u7247", ".webp": "WebP\u56FE\u7247", ".mp4": "MP4\u89C6\u9891", ".mp3": "MP3\u97F3\u9891", ".wav": "WAV\u97F3\u9891", ".pdf": "PDF\u6587\u6863", ".doc": "Word\u6587\u6863", ".docx": "Word\u6587\u6863", ".xls": "Excel\u8868\u683C", ".xlsx": "Excel\u8868\u683C", ".ppt": "PPT\u6F14\u793A", ".pptx": "PPT\u6F14\u793A", ".html": "HTML\u6587\u4EF6", ".css": "CSS\u6587\u4EF6", ".js": "JS\u6587\u4EF6", ".ts": "TS\u6587\u4EF6", ".json": "JSON\u6587\u4EF6", ".xml": "XML\u6587\u4EF6", ".md": "Markdown\u6587\u4EF6", ".vsix": "VSCode\u6269\u5C55" }; return typeMap[ext] || "\u6587\u4EF6"; } function parseLsOutput(output) { const entries = []; const lines = output.split("\n").filter((line) => line.trim()); for (const line of lines) { const trimmed = line.trim(); if (/^total\s+/i.test(trimmed)) continue; if (!/^[dlcbps-][rwxlsStT-]{9}/.test(trimmed)) continue; const parts = trimmed.split(/\s+/); if (parts.length < 8) continue; const perms = parts[0]; const sizeStr = parts[4]; const rawName = parts.slice(7).join(" "); const name = rawName.split(" -> ")[0]; if (name === "." || name === "..") continue; entries.push({ name, isDir: perms[0] === "d", size: parseInt(sizeStr, 10) || 0 }); } return entries; } // src/core/ls.ts import path5 from "path"; function getDisplayWidth(s) { return [...s].reduce((w, c) => w + (c.charCodeAt(0) > 127 ? 2 : 1), 0); } function printFileList(entries) { const dirs = entries.filter((e) => e.isDir); const files = entries.filter((e) => !e.isDir); const sorted = [...dirs, ...files]; logger.success(`\u6587\u4EF6\u5217\u8868 (\u5171 ${sorted.length} \u9879, ${dirs.length} \u4E2A\u76EE\u5F55, ${files.length} \u4E2A\u6587\u4EF6):`); const maxNameLen = Math.max(...sorted.map((e) => getDisplayWidth(e.name) + (e.isDir ? 1 : 0))); const maxSizeLen = Math.max(8, ...sorted.filter((e) => !e.isDir).map((e) => formatFileSize(e.size).length)); const headerName = "\u540D\u79F0".padEnd(maxNameLen - 2); const headerSize = "\u5927\u5C0F".padEnd(maxSizeLen - 2); const headerType = "\u7C7B\u578B".padEnd(8 - 2); logger.line(); console.log(` ${headerName} ${headerSize} ${headerType}`); console.log(` ${"\u2500".repeat(maxNameLen)} ${"\u2500".repeat(maxSizeLen)} ${"\u2500".repeat(8)}`); for (const entry of sorted) { const namePart = entry.isDir ? `${entry.name}/` : entry.name; const padSpaces = Math.max(0, maxNameLen - getDisplayWidth(namePart)); const displayName = entry.isDir ? bold(cyan3(namePart)) + " ".repeat(padSpaces) : namePart + " ".repeat(padSpaces); const sizeStr = entry.isDir ? "-".padEnd(maxSizeLen) : formatFileSize(entry.size).padEnd(maxSizeLen); const displaySize = entry.isDir ? dim2(sizeStr) : yellow2(sizeStr); const typeStr = entry.isDir ? cyan3(getFileTypeDesc(entry.name, entry.isDir)) : green2(getFileTypeDesc(entry.name, entry.isDir)); console.log(` ${displayName} ${displaySize} ${typeStr}`); } logger.line(); } function ls(options = {}, extArgs = []) { const hdc2 = getHdcWithDevice(); if (!options.remote) { if (options.download) { options.remote = REMOTE_PATH_MAP.download; } else if (options.share) { options.remote = REMOTE_PATH_MAP.share; } else { options.remote = REMOTE_PATH_MAP.temp; } } if (extArgs.length) { const remoteArg = extArgs[0]; options.remote = path5.posix.resolve(options.remote, remoteArg); } logger.debug("\u8FDC\u7AEF\u8DEF\u5F84:", options.remote); logger.debug("\u83B7\u53D6\u6587\u4EF6\u5217\u8868..."); const lsCmd = `${hdc2} shell ls -l "${options.remote}"`; logger.debug("\u6267\u884C\u547D\u4EE4:", lsCmd); const lsExec = shell10.exec(lsCmd, { silent: true }); if (lsExec.code !== 0) { logger.debug("\u8BE6\u7EC6\u5217\u8868\u6A21\u5F0F\u5931\u8D25, \u56DE\u9000\u5230\u7B80\u5355\u5217\u8868\u6A21\u5F0F"); const simpleCmd = `${hdc2} shell ls "${options.remote}"`; logger.debug("\u6267\u884C\u547D\u4EE4:", simpleCmd); const simpleExec = shell10.exec(simpleCmd, { silent: true }); if (simpleExec.code !== 0) { logger.error("\u83B7\u53D6\u6587\u4EF6\u5217\u8868\u5931\u8D25"); process.exit(EXIT_CODE_ERROR); } const stdout = simpleExec.stdout; if (stdout.includes("No such file or directory")) { logger.warn(`\u8DEF\u5F84: ${options.remote} \u4E0D\u5B58\u5728`); process.exit(EXIT_CODE_ERROR); } if (!stdout) { logger.warn(`\u8DEF\u5F84: ${options.remote} \u4E3A\u7A7A`); process.exit(0); } logger.success(`\u6587\u4EF6\u5217\u8868: ${stdout}`); return; } const lsStdout = lsExec.stdout; if (lsStdout.includes("No such file or directory")) { logger.warn(`\u8DEF\u5F84: ${options.remote} \u4E0D\u5B58\u5728`); process.exit(EXIT_CODE_ERROR); } const entries = parseLsOutput(lsStdout); if (entries.length === 0) { const lines = lsStdout.split("\n").filter((l) => l.trim() && !l.trim().startsWith("total")); if (lines.length === 0) { logger.warn(`\u8DEF\u5F84: ${options.remote} \u4E3A\u7A7A`); process.exit(0); } logger.success(`\u6587\u4EF6\u5217\u8868: ${lines.join("\n")}`); return; } printFileList(entries); } // src/commands/ls.ts function registerLsCommand(program2) { program2.command("ls [extArgs...]").description("\u83B7\u53D6\u624B\u673A\u7AEF\u6307\u5B9A\u76EE\u5F55\u6587\u4EF6\u5217\u8868,\u9ED8\u8BA4\u4E3A/data/local/tmp/").option("-r --remote <\u8DEF\u5F84>", "\u6307\u5B9A\u8BBE\u5907\u7AEF\u6587\u4EF6\u8DEF\u5F84").option("-d --download", "\u6307\u5B9A\u8BBE\u5907\u7AEFdownload\u76EE\u5F55", false).option("-s --share", "\u6307\u5B9A\u8BBE\u5907\u7AEF\u5206\u4EAB\u76EE\u5F55", false).action(async (extArgs = [], options) => { ls(options, extArgs); }); } // src/core/pull.ts import path6 from "path"; import shell11 from "shelljs"; function pull(options = {}, extArgs = []) { const hdc2 = getHdcWithDevice(); const remoteFilePathName = extArgs[0]; if (!remoteFilePathName && !options.remote) { logger.error("\u7F3A\u5C11\u8BBE\u5907\u7AEF\u6587\u4EF6\u8DEF\u5F84\u6216\u6587\u4EF6\u540D"); process.exit(EXIT_CODE_ERROR); } logger.debug("\u62C9\u53D6\u6587\u4EF6..."); if (!options.remote) { if (options.download) { options.remote = REMOTE_PATH_MAP.download; } else if (options.share) { options.remote = REMOTE_PATH_MAP.share; } else { options.remote = REMOTE_PATH_MAP.temp; } } if (!options.