@deveco-test/hmos-deveco-cli 0.1.0-TD.3.1 → 0.1.0-TD.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +4 -4
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -30,7 +30,7 @@ Available runnable modules:
30
30
  `))}async function ec(r,e,t,n,i,o){o&&(console.log(`Uninstalling ${t}...`),await r.uninstallApp(e,t)||console.log(`App ${t} not installed; skipping uninstallation.`)),console.log(`
31
31
  Installing artifacts to device ${e}...`),await r.installApp(e,n),console.log(`Launching ${t}/${i}...`);let s=await r.launchApp(e,t,i);console.log(Hi(`
32
32
  Application '${t}': ${s}`))}var tc=new Ga("run").description("Build and run the project on a connected device").option("--module <modules...>","Module(s) to run (format: module or module@target)").option("--device <device>","Target device name or serial").option("--product <product>","Product name (default: default)").option("--build-mode <mode>","Build mode (options: debug, release; default: debug)").option("--ability <ability>","Ability name to launch").option("--uninstall","Uninstall existing app before installation").option("--skip-build","Skip build step and deploy existing artifacts").action(async r=>{try{await rc(r)}catch(e){console.error(Ja(e.message)),process.exit(1)}});async function nc(r,e,t,n,i){let o=new ze(e,r.rootDir),s=new He(e,r.rootDir),a=new Set;for(let{moduleName:y,targetName:k}of t)for(let W of r.collectNonHarDependentModuleList(y))a.add(`${W}@${k}`);let c=[...a],d=dr(r,c),u={type:"modules",modulesToBuild:c,moduleTasks:d};await ft(r.rootDir,()=>ur(o,s,n,i,u,r.rootDir),()=>console.log("Another build is already running for this project. Waiting for completion...")),console.log(`
33
- `+Hi("Build completed successfully."))}async function rc(r){let e=Le.discover(process.cwd());console.warn(Ka("Ensure the project source is trusted before proceeding."));let t=await O.new(),i=Qa(e,r.module).map(Xa);for(let{moduleName:X}of i){let Oe=e.getModuleType(X);if(Oe!=="entry"&&Oe!=="feature"&&Oe!=="shared")throw new Error(`Module '${X}' '${Oe}' is not runnable. Specify an entry or feature module.`)}let o=new Xt(t),s=z.from(t),a=await Za(s,r.device),c=a.includes("127.0.0.1")||a.includes("localhost"),d=r.product||"default";e.validateProduct(d);let u=r.buildMode||"debug";r.skipBuild||await nc(e,t,i,d,u);let y=new Set;for(let{moduleName:X,targetName:Oe}of i){let ha=e.collectNonHarDependentModuleList(X);for(let fa of ha)y.add(e.findArtifactPath(fa,Oe,c,d));y.add(e.findArtifactPath(X,Oe,c,d))}let k=[...y],W=e.getBundleName(),te=e.getMainAbility(i[0].moduleName,r.ability);await ec(o,a,W,k,te,!!r.uninstall)}var ji=tc;import{Command as ic}from"commander";import{green as Fi,red as $i,cyan as fr}from"colorette";import{execa as _i}from"execa";function oc(){return"@deveco-test/hmos-deveco-cli"}function sc(){return"0.1.0-TD.3.1"}var ac=new ic("update").description("Update deveco-cli to latest").action(async()=>{let r=oc(),e=sc();console.log(fr("Checking for updates..."));try{let{stdout:t}=await _i("npm",["view",r,"version"]),n=t.trim();if(n===e){console.log(Fi(`
33
+ `+Hi("Build completed successfully."))}async function rc(r){let e=Le.discover(process.cwd());console.warn(Ka("Ensure the project source is trusted before proceeding."));let t=await O.new(),i=Qa(e,r.module).map(Xa);for(let{moduleName:X}of i){let Oe=e.getModuleType(X);if(Oe!=="entry"&&Oe!=="feature"&&Oe!=="shared")throw new Error(`Module '${X}' '${Oe}' is not runnable. Specify an entry or feature module.`)}let o=new Xt(t),s=z.from(t),a=await Za(s,r.device),c=a.includes("127.0.0.1")||a.includes("localhost"),d=r.product||"default";e.validateProduct(d);let u=r.buildMode||"debug";r.skipBuild||await nc(e,t,i,d,u);let y=new Set;for(let{moduleName:X,targetName:Oe}of i){let ha=e.collectNonHarDependentModuleList(X);for(let fa of ha)y.add(e.findArtifactPath(fa,Oe,c,d));y.add(e.findArtifactPath(X,Oe,c,d))}let k=[...y],W=e.getBundleName(),te=e.getMainAbility(i[0].moduleName,r.ability);await ec(o,a,W,k,te,!!r.uninstall)}var ji=tc;import{Command as ic}from"commander";import{green as Fi,red as $i,cyan as fr}from"colorette";import{execa as _i}from"execa";function oc(){return"@deveco-test/hmos-deveco-cli"}function sc(){return"0.1.0-TD.3.2"}var ac=new ic("update").description("Update deveco-cli to latest").action(async()=>{let r=oc(),e=sc();console.log(fr("Checking for updates..."));try{let{stdout:t}=await _i("npm",["view",r,"version"]),n=t.trim();if(n===e){console.log(Fi(`
34
34
  ${r} is already up to date (version ${e}.)`));return}console.log(fr(`
35
35
  New version found: ${n} (current: ${e})`)),console.log(fr(`Updating ${r}...`)),await _i("npm",["install","-g",`${r}@latest`],{stdio:"inherit"}),console.log(`
36
36
  `+Fi(`${r} updated successfully to version ${n}.`))}catch(t){let n=t;console.error($i(`Failed to update ${r}`)),n.message&&console.error($i(n.message)),process.exit(1)}}),Wi=ac;import{Command as Tc}from"commander";import{execa as vr}from"execa";function $(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}import{spawn as cc}from"child_process";var lc=2500;function dc(r,e,t,n,i,o){r.once("exit",s=>{if(o())return;clearTimeout(e);let a=t();s===0||s===null?n():i(a||`Emulator process exited with code ${s}`)})}function uc(r,e,t,n){let i=!1,o=()=>i,s=()=>Buffer.concat(e).toString("utf8").trim(),a=()=>{i||(i=!0,clearTimeout(d),r.removeAllListeners(),r.stderr?.removeAllListeners(),r.stderr?.destroy(),r.unref(),t())},c=u=>{if(!i){i=!0,clearTimeout(d),r.removeAllListeners(),r.stderr?.removeAllListeners();try{r.kill()}catch{}n(new Error(u))}},d=setTimeout(a,lc);r.once("error",u=>c(u.message)),dc(r,d,s,a,c,o)}function Ui(r,e,t){return m(`Spawning emulator: ${r} ${t.join(" ")}`),new Promise((n,i)=>{let o=[],s=cc(r,t,{detached:!0,stdio:["ignore","ignore","pipe"],env:{...process.env,DEVECO_SDK_HOME:e},windowsHide:!0});s.stderr?.on("data",a=>o.push(a)),uc(s,o,n,i)})}import*as Ge from"path";function pc(r){let e=new Set,t=[];for(let n of r){let i=JSON.stringify(n);e.has(i)||(e.add(i),t.push(n))}return t}function hc(r){let e=r.instancePath?.trim();if(e)return Ge.dirname(Ge.normalize(e)).replace(/\\/g,"/");let t=r.path?.trim();return t?Ge.dirname(Ge.normalize(t)).replace(/\\/g,"/"):""}function fc(r){let e=[];return r&&e.push(["-imageRoot",r]),e.push([]),e}function Bi(r,e){return e?[...r,"-bootmode",e]:r}function mc(r,e,t){let n=[Bi(["-start",r],t)],i=hc(e);if(i)for(let o of fc(e.imageRoot))n.push(Bi(["-hvd",r,"-path",i,...o],t));return pc(n)}async function Vi(r,e,t,n){let i=new Error("No start strategy ran"),o=mc(r,e,n);for(let s of o)try{return await t(s),{ok:!0}}catch(a){i=a}return{ok:!1,lastError:i}}async function mr(r){return(await z.withHdcPath(r).listDevices()).map(t=>t.serial).filter(yt)}async function gr(r){let e=await mr(r);return e.length===0?[]:(await Promise.all(e.map(n=>Kt(r,n,"ohos.qemu.hvd.name")))).filter(n=>!!n)}async function zi(r,e){return(await gr(r)).includes(e)}import*as Ke from"path";import{existsSync as gc,statSync as yc}from"fs";function Je(r,e){for(let t of e){let n=r[t];if(typeof n=="string"&&n.trim())return n.trim()}return""}function vc(r){let e=Je(r,["instancePath","instance_path","InstancePath","instancepath","instanceDir","instance_dir","InstanceDir","deployPath","deploy_path","deployedPath","deployed_path","workPath","work_path","dataPath","data_path"]);if(e)return e;for(let[t,n]of Object.entries(r)){if(typeof n!="string"||!n.trim())continue;let i=t.toLowerCase();if(i.includes("instance")&&(i.includes("path")||i.includes("dir"))||i==="deployedpath")return n.trim()}return""}function wc(r){return Je(r,["uuid","UUID","Uuid","instanceUuid","instance_uuid","InstanceUuid"])}function bc(r){let e=r.find(n=>n.instancePath?.trim());if(!e?.instancePath?.trim())return;let t=Ke.dirname(Ke.normalize(e.instancePath));for(let n of r){if(n.instancePath?.trim())continue;let i=Ke.join(t,n.name);gc(i)&&yc(i).isDirectory()&&(n.instancePath=i.replace(/\\/g,"/"))}}function Sc(r){try{let e=JSON.parse(r);return Array.isArray(e)?e.map(t=>{let n=wc(t),i=Je(t,["deviceType","DeviceType","devicetype"]),o=Je(t,["os.osVersion","osVersion","OsVersion","OSVersion"]);return{name:t.name||t.Name||"",isRunning:t.isRunning===!0||String(t.isRunning).toLowerCase()==="true",instancePath:vc(t),path:Je(t,["path","Path","hvdPath","hvd_path"]),imageRoot:Je(t,["imageRoot","image_root","ImageRoot"]),uuid:n||void 0,deviceType:i||void 0,osVersion:o||void 0}}).filter(t=>t.name):null}catch{return null}}function Pc(r){let e=[],t=/^(name|isrunning|instancepath|path|imageroot|devicetype|os\.osversion)\s*:\s*(.+)/gim,n=null,i;for(;(i=t.exec(r))!==null;){let[,o,s]=i;if(o.toLowerCase()==="name")n&&e.push(n),n={name:s.trim()};else if(n){let a=o.toLowerCase();a==="isrunning"?n.isRunning=s.trim().toLowerCase()==="true":a==="instancepath"?n.instancePath=s.trim():a==="path"?n.path=s.trim():a==="imageroot"?n.imageRoot=s.trim():a==="devicetype"?n.deviceType=s.trim():a==="os.osversion"&&(n.osVersion=s.trim())}}return n&&e.push(n),e}function qi(r){let t=Sc(r)??Pc(r);return bc(t),t}function yr(r,e){for(let t of e){let n=r[t];if(typeof n=="string"&&n.trim())return n.trim()}return""}function Ec(r){let e=r.downloaded??r.Downloaded;return e===!0||String(e).toLowerCase()==="true"}function Cc(r){if(!Ec(r))return null;let e=yr(r,["osVersion","OsVersion","OSVersion"]),t=yr(r,["SoftWareVersion","SoftwareVersion","softwareVersion"]),n=yr(r,["deviceType","DeviceType"]);return!e&&!t?null:{osVersion:e,softwareVersion:t,deviceType:n}}function Zt(r){let e=r.trim();if(!e)return[];try{let t=JSON.parse(e);if(!Array.isArray(t))return[];let n=[];for(let i of t){if(!i||typeof i!="object")continue;let o=Cc(i);o&&n.push(o)}return n}catch{return[]}}function Yi(r){let t=Zt(r).map(n=>n.osVersion).filter(Boolean);return[...new Set(t)]}var Gi=/no images are available/i;function ce(r){return r.normalize("NFKC").trim().toLowerCase()}function Dc(r){let e=r.message||"";return Gi.test(e)}var Xe=class r{emulatorPath;sdkPath;hdcPath;constructor(e,t,n){this.emulatorPath=e,this.sdkPath=t,this.hdcPath=n}static from(e){return new r(e.emulatorPath,e.sdkPath,e.hdcPath)}async executeEmulator(e){return vr(this.emulatorPath,e,{stdio:["ignore","pipe","pipe"],env:{...process.env,DEVECO_SDK_HOME:this.sdkPath}})}executeEmulatorDetached(e){return Ui(this.emulatorPath,this.sdkPath,e)}async listEmulators(){let{stdout:e}=await this.executeEmulator(["-list","-details"]);return qi(e)}async getDeviceTypeByName(){let e=new Map;try{let t=await this.listEmulators();for(let n of t)n.name&&n.deviceType&&e.set($(n.name),n.deviceType)}catch{}return e}async startEmulator(e){let t=await this.listEmulators(),n=$(e),i=t.find(a=>$(a.name)===n);if(!i)throw new Error(`Emulator "${e}" not found.`);let o=i.name;if(await this.isAlreadyRunning(o,i))return"already-running";await this.assertSystemImageAvailable(i);let s=await Vi(o,i,a=>this.executeEmulatorDetached(a),"snapshot");if(s.ok)return"started";if(await this.isAlreadyRunning(o))return"already-running";throw new Error(`Unable to start emulator "${e}". All methods failed.
@@ -1247,7 +1247,7 @@ Output so far:
1247
1247
  `):"\u6CA1\u6709\u6709\u6548\u7684 .ets \u6587\u4EF6"}],isError:!0}:(await this.runDiagnosticsForFiles(i,t,n),this.formatCallResult(t,n))}buildNotReadyResponse(){return{content:[{type:"text",text:this.initializing?"LSP \u6B63\u5728\u521D\u59CB\u5316\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5":this.projectPath?"LSP\u672A\u521D\u59CB\u5316":"\u6CA1\u6709\u914D\u7F6E\u5DE5\u7A0B\u8DEF\u5F84\uFF0C\u8BF7\u914D\u7F6EPROJECT_PATH\u53C2\u6570"}],isError:!0}}collectValidFiles(e,t){let n=this.projectPath,i=[];for(let o of e){let s=pe.isAbsolute(o)?o:pe.join(n,o);if(!Se.existsSync(s)){t.push(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${o}`);continue}if(!Se.statSync(s).isFile()){t.push(`\u4E0D\u662F\u666E\u901A\u6587\u4EF6: ${o}`);continue}if(!s.endsWith(".ets")){t.push(`\u4E0D\u662F .ets \u6587\u4EF6: ${o}`);continue}i.push(s)}return i}async runDiagnosticsForFiles(e,t,n){for(let i of e){await bs(500);try{let o=await this.checkFile(i);n.push(Mu(i,o))}catch(o){t.push(`${i} => wait for diagnostics failed: ${o.message}`)}}}formatCallResult(e,t){let n=[];e.length>0&&n.push(e.join(`
1248
1248
  `)),t.length>0&&n.push(t.join(`
1249
1249
  `));let i=n.join(`
1250
- `).trim(),o=e.length>0;return!o&&t.length===0&&(i="\u672A\u6536\u96C6\u5230\u8BCA\u65AD\u4FE1\u606F"),{content:[{type:"text",text:i}],isError:o}}async shutdown(){if(this.failAllPending(new Error("LSP shutting down")),this.manager){try{await this.manager.dispose()}catch(e){f.warn(`Failed to dispose ArktsLspManager: ${e}`)}this.manager=null}this.initialized=!1,this.initializing=!1,this.initPromise=null,this.clearInitHandlers()}sendNotification(e,t){if(!this.manager)throw new Error("ArktsLspManager not initialized");this.manager.sendNotification({jsonrpc:"2.0",method:e,params:t})}handleLspMessage(e){let t=e,n=t.method;if(n)switch(n){case"textDocument/publishDiagnostics":case"textDocument/didOpen":this.handleDiagnosticsNotification(t.params);break;case"arkts/indexingProgress":this.initResolve&&(this.armInitTimer(Rt),f.debug("Received arkts/indexingProgress, reset init timeout"));break;case"arkts/initialized":{f.info("Received arkts/initialized");let i=this.initResolve;this.clearInitHandlers(),i?.();break}case"arkts/initializationFailed":{let o=t.params?.message??"unknown";f.error(`LSP initialization failed: ${o}`);let s=this.initReject;this.clearInitHandlers(),s?.(new Error(`LSP initialize failed: ${o}`));break}case"workspace/didChangeConfiguration":f.info("Received workspace/didChangeConfiguration, sync deferred to next check");break;default:break}}handleDiagnosticsNotification(e){if(!e)return;let t=e.uri;if(!t)return;let n=this.resolveDiagnosticWaiter(t);if(!n)return;if(typeof e.errorMessage=="string"){f.warn(`diagnostics error uri=${t} message=${e.errorMessage}`),n.resolve({errorMessage:e.errorMessage});return}let i=e.diagnostics,o=Array.isArray(i)?i.length:0;f.debug(`diagnostics received uri=${t} count=${o}`),n.resolve(Array.isArray(i)?i:[])}resolveDiagnosticWaiter(e){let t=Tt(e),n=this.popDiagnosticWaiter(t);if(n)return n;for(let i of Ps(e)){let o=this.popDiagnosticWaiter(i);if(o)return o}}popDiagnosticWaiter(e){let t=this.diagnosticWaiters.get(e);if(t)return this.diagnosticWaiters.delete(e),clearTimeout(t.timer),t}failAllPending(e){for(let[,n]of this.diagnosticWaiters)clearTimeout(n.timer),n.reject(e);this.diagnosticWaiters.clear();let t=this.initReject;this.clearInitHandlers(),t?.(e)}getLogAndIndexPath(e){try{let t=pe.join(gn(),"ArkTSCheck"),n=pe.join(t,"mapping-config.properties"),i=Es(e,n),o=`${Date.now()}${process.hrtime.bigint()%1000000n}`,s=pe.join(t,"lsp-log",String(i),o),a=pe.join(t,"lsp-index",String(i));return Se.mkdirSync(s,{recursive:!0}),Se.mkdirSync(a,{recursive:!0}),{logPath:ue(s),indexPath:ue(a)}}catch{return{logPath:"auto",indexPath:"auto"}}}};function Mu(r,e){if(Array.isArray(e))return e.length===0?`${r} => no diagnostics`:`${r} => Diagnostic: ${JSON.stringify(e)}`;if(e&&typeof e=="object"&&typeof e.errorMessage=="string"){let t=e.errorMessage;return`${r} diagnostic failed, error_message: ${t}`}return`${r} => diagnostic failed, result: ${JSON.stringify(e)}`}import{spawn as Ru}from"child_process";import*as C from"fs";import*as B from"path";import{z as ii}from"zod";var ea=60*1e3,xu=30*1e3,Ou=new Set(["textDocument/didOpen","textDocument/didChange","textDocument/didClose","textDocument/didSave"]),Nu=1e3,si=class{nextRequestId=1;pendingRequests=new Map;diagnosticWaiters=new Map;fileCheckLock=Promise.resolve();closed=!1;wrapperState="preInitialize";queuedDocumentNotifications=[];backendReady=!1;projectPath=null;clangdStdin=null;clangdStdout=null;clangdBuffer=Buffer.alloc(0);constructor(){}isClosed(){return this.closed}async initialize(e){this.projectPath=e,this.wrapperState="waitingForDatabase"}async connectClangdProcess(e,t){if(this.closed)throw new Error("Client is already closed");this.clangdStdin=e,this.clangdStdout=t,this.wrapperState="startingBackend",this.clangdStdout.on("data",a=>this.handleClangdData(a)),this.clangdStdout.on("error",a=>{f.warn(`[CppCheck] clangd stdout error: ${a}`),this.failAll(new Error(`clangd stdout error: ${a}`))}),this.clangdStdout.on("end",()=>{this.failAll(new Error("C++ language server connection closed"))});let n=ue(this.projectPath),i=We(n),o=B.basename(n)||"workspace",s={processId:null,clientInfo:{name:"devecocli-mcp-server",version:"0.1.0-TD.3.1"},rootPath:n,rootUri:i,workspaceFolders:[{uri:i,name:o}],capabilities:{}};await this.sendRequestToClangd("initialize",s,ea),await this.sendNotificationToClangd("initialized",{}),this.backendReady=!0,this.wrapperState="proxying";for(let a of this.queuedDocumentNotifications)await this.writeToClangd(a);this.queuedDocumentNotifications.length=0,f.info("[CppCheck] clangd backend ready, switched to proxying mode")}async waitForBackendReady(){if(this.backendReady)return;let e=ea,t=Date.now();for(;!this.backendReady&&!this.closed&&Date.now()-t<e;)await new Promise(n=>setTimeout(n,500));if(!this.backendReady)throw new Error("Timed out waiting for clangd backend to be ready")}async checkFile(e){await this.waitForBackendReady();let t=await this.acquireFileCheckLock();try{return await this.doCheckFile(e)}finally{t()}}async doCheckFile(e){let t;try{t=C.realpathSync(e)}catch{t=e}let n=We(t),i=Ss(t),o=await C.promises.readFile(t,"utf8"),s=new Promise((a,c)=>{let d=setTimeout(()=>{this.diagnosticWaiters.delete(n)&&c(new Error(`Timed out waiting for diagnostics: ${e}`))},xu);this.diagnosticWaiters.set(n,{resolve:a,reject:c,timer:d})});try{await this.sendNotification("textDocument/didOpen",{textDocument:{uri:n,languageId:i,version:1,text:o}})}catch(a){let c=this.diagnosticWaiters.get(n);throw c&&(clearTimeout(c.timer),this.diagnosticWaiters.delete(n)),a}try{return await s}finally{await this.closeFile(n).catch(a=>{f.warn(`[CppCheck] didClose failed for ${n}: ${a}`)})}}async close(){if(!this.closed&&(this.closed=!0,this.wrapperState="shuttingDown",this.backendReady&&this.clangdStdin)){try{await this.sendRequestToClangd("shutdown",null,3e3)}catch(e){f.warn(`[CppCheck] shutdown request failed: ${e}`)}try{await this.sendNotificationToClangd("exit",null)}catch(e){f.warn(`[CppCheck] exit notification failed: ${e}`)}try{this.clangdStdin.end()}catch(e){f.warn(`[CppCheck] stdin.end() failed: ${e}`)}}}async sendNotification(e,t){let n={jsonrpc:"2.0",method:e,params:t??void 0};if(this.backendReady&&this.clangdStdin){await this.writeToClangd(n);return}Ou.has(e)&&this.queuedDocumentNotifications.push(n)}async closeFile(e){await this.sendNotification("textDocument/didClose",{textDocument:{uri:e}})}async sendRequestToClangd(e,t,n){let i=this.nextRequestId++;return new Promise((o,s)=>{let a=setTimeout(()=>{this.pendingRequests.delete(i)&&s(new Error(`Timed out waiting for ${e} response`))},n);this.pendingRequests.set(i,{resolve:o,reject:s,timer:a}),this.writeToClangd({jsonrpc:"2.0",id:i,method:e,params:t??void 0}).catch(c=>{this.pendingRequests.delete(i)&&(clearTimeout(a),s(c))})})}async sendNotificationToClangd(e,t){await this.writeToClangd({jsonrpc:"2.0",method:e,params:t??void 0})}async writeToClangd(e){if(!this.clangdStdin)throw new Error("clangd stdin not available");return new Promise((t,n)=>{let i;try{i=JSON.stringify(e)}catch(u){n(new Error(`Failed to encode LSP message: ${u}`));return}let o=Buffer.from(i,"utf8"),s=Buffer.from(`Content-Length: ${o.length}\r
1250
+ `).trim(),o=e.length>0;return!o&&t.length===0&&(i="\u672A\u6536\u96C6\u5230\u8BCA\u65AD\u4FE1\u606F"),{content:[{type:"text",text:i}],isError:o}}async shutdown(){if(this.failAllPending(new Error("LSP shutting down")),this.manager){try{await this.manager.dispose()}catch(e){f.warn(`Failed to dispose ArktsLspManager: ${e}`)}this.manager=null}this.initialized=!1,this.initializing=!1,this.initPromise=null,this.clearInitHandlers()}sendNotification(e,t){if(!this.manager)throw new Error("ArktsLspManager not initialized");this.manager.sendNotification({jsonrpc:"2.0",method:e,params:t})}handleLspMessage(e){let t=e,n=t.method;if(n)switch(n){case"textDocument/publishDiagnostics":case"textDocument/didOpen":this.handleDiagnosticsNotification(t.params);break;case"arkts/indexingProgress":this.initResolve&&(this.armInitTimer(Rt),f.debug("Received arkts/indexingProgress, reset init timeout"));break;case"arkts/initialized":{f.info("Received arkts/initialized");let i=this.initResolve;this.clearInitHandlers(),i?.();break}case"arkts/initializationFailed":{let o=t.params?.message??"unknown";f.error(`LSP initialization failed: ${o}`);let s=this.initReject;this.clearInitHandlers(),s?.(new Error(`LSP initialize failed: ${o}`));break}case"workspace/didChangeConfiguration":f.info("Received workspace/didChangeConfiguration, sync deferred to next check");break;default:break}}handleDiagnosticsNotification(e){if(!e)return;let t=e.uri;if(!t)return;let n=this.resolveDiagnosticWaiter(t);if(!n)return;if(typeof e.errorMessage=="string"){f.warn(`diagnostics error uri=${t} message=${e.errorMessage}`),n.resolve({errorMessage:e.errorMessage});return}let i=e.diagnostics,o=Array.isArray(i)?i.length:0;f.debug(`diagnostics received uri=${t} count=${o}`),n.resolve(Array.isArray(i)?i:[])}resolveDiagnosticWaiter(e){let t=Tt(e),n=this.popDiagnosticWaiter(t);if(n)return n;for(let i of Ps(e)){let o=this.popDiagnosticWaiter(i);if(o)return o}}popDiagnosticWaiter(e){let t=this.diagnosticWaiters.get(e);if(t)return this.diagnosticWaiters.delete(e),clearTimeout(t.timer),t}failAllPending(e){for(let[,n]of this.diagnosticWaiters)clearTimeout(n.timer),n.reject(e);this.diagnosticWaiters.clear();let t=this.initReject;this.clearInitHandlers(),t?.(e)}getLogAndIndexPath(e){try{let t=pe.join(gn(),"ArkTSCheck"),n=pe.join(t,"mapping-config.properties"),i=Es(e,n),o=`${Date.now()}${process.hrtime.bigint()%1000000n}`,s=pe.join(t,"lsp-log",String(i),o),a=pe.join(t,"lsp-index",String(i));return Se.mkdirSync(s,{recursive:!0}),Se.mkdirSync(a,{recursive:!0}),{logPath:ue(s),indexPath:ue(a)}}catch{return{logPath:"auto",indexPath:"auto"}}}};function Mu(r,e){if(Array.isArray(e))return e.length===0?`${r} => no diagnostics`:`${r} => Diagnostic: ${JSON.stringify(e)}`;if(e&&typeof e=="object"&&typeof e.errorMessage=="string"){let t=e.errorMessage;return`${r} diagnostic failed, error_message: ${t}`}return`${r} => diagnostic failed, result: ${JSON.stringify(e)}`}import{spawn as Ru}from"child_process";import*as C from"fs";import*as B from"path";import{z as ii}from"zod";var ea=60*1e3,xu=30*1e3,Ou=new Set(["textDocument/didOpen","textDocument/didChange","textDocument/didClose","textDocument/didSave"]),Nu=1e3,si=class{nextRequestId=1;pendingRequests=new Map;diagnosticWaiters=new Map;fileCheckLock=Promise.resolve();closed=!1;wrapperState="preInitialize";queuedDocumentNotifications=[];backendReady=!1;projectPath=null;clangdStdin=null;clangdStdout=null;clangdBuffer=Buffer.alloc(0);constructor(){}isClosed(){return this.closed}async initialize(e){this.projectPath=e,this.wrapperState="waitingForDatabase"}async connectClangdProcess(e,t){if(this.closed)throw new Error("Client is already closed");this.clangdStdin=e,this.clangdStdout=t,this.wrapperState="startingBackend",this.clangdStdout.on("data",a=>this.handleClangdData(a)),this.clangdStdout.on("error",a=>{f.warn(`[CppCheck] clangd stdout error: ${a}`),this.failAll(new Error(`clangd stdout error: ${a}`))}),this.clangdStdout.on("end",()=>{this.failAll(new Error("C++ language server connection closed"))});let n=ue(this.projectPath),i=We(n),o=B.basename(n)||"workspace",s={processId:null,clientInfo:{name:"devecocli-mcp-server",version:"0.1.0-TD.3.2"},rootPath:n,rootUri:i,workspaceFolders:[{uri:i,name:o}],capabilities:{}};await this.sendRequestToClangd("initialize",s,ea),await this.sendNotificationToClangd("initialized",{}),this.backendReady=!0,this.wrapperState="proxying";for(let a of this.queuedDocumentNotifications)await this.writeToClangd(a);this.queuedDocumentNotifications.length=0,f.info("[CppCheck] clangd backend ready, switched to proxying mode")}async waitForBackendReady(){if(this.backendReady)return;let e=ea,t=Date.now();for(;!this.backendReady&&!this.closed&&Date.now()-t<e;)await new Promise(n=>setTimeout(n,500));if(!this.backendReady)throw new Error("Timed out waiting for clangd backend to be ready")}async checkFile(e){await this.waitForBackendReady();let t=await this.acquireFileCheckLock();try{return await this.doCheckFile(e)}finally{t()}}async doCheckFile(e){let t;try{t=C.realpathSync(e)}catch{t=e}let n=We(t),i=Ss(t),o=await C.promises.readFile(t,"utf8"),s=new Promise((a,c)=>{let d=setTimeout(()=>{this.diagnosticWaiters.delete(n)&&c(new Error(`Timed out waiting for diagnostics: ${e}`))},xu);this.diagnosticWaiters.set(n,{resolve:a,reject:c,timer:d})});try{await this.sendNotification("textDocument/didOpen",{textDocument:{uri:n,languageId:i,version:1,text:o}})}catch(a){let c=this.diagnosticWaiters.get(n);throw c&&(clearTimeout(c.timer),this.diagnosticWaiters.delete(n)),a}try{return await s}finally{await this.closeFile(n).catch(a=>{f.warn(`[CppCheck] didClose failed for ${n}: ${a}`)})}}async close(){if(!this.closed&&(this.closed=!0,this.wrapperState="shuttingDown",this.backendReady&&this.clangdStdin)){try{await this.sendRequestToClangd("shutdown",null,3e3)}catch(e){f.warn(`[CppCheck] shutdown request failed: ${e}`)}try{await this.sendNotificationToClangd("exit",null)}catch(e){f.warn(`[CppCheck] exit notification failed: ${e}`)}try{this.clangdStdin.end()}catch(e){f.warn(`[CppCheck] stdin.end() failed: ${e}`)}}}async sendNotification(e,t){let n={jsonrpc:"2.0",method:e,params:t??void 0};if(this.backendReady&&this.clangdStdin){await this.writeToClangd(n);return}Ou.has(e)&&this.queuedDocumentNotifications.push(n)}async closeFile(e){await this.sendNotification("textDocument/didClose",{textDocument:{uri:e}})}async sendRequestToClangd(e,t,n){let i=this.nextRequestId++;return new Promise((o,s)=>{let a=setTimeout(()=>{this.pendingRequests.delete(i)&&s(new Error(`Timed out waiting for ${e} response`))},n);this.pendingRequests.set(i,{resolve:o,reject:s,timer:a}),this.writeToClangd({jsonrpc:"2.0",id:i,method:e,params:t??void 0}).catch(c=>{this.pendingRequests.delete(i)&&(clearTimeout(a),s(c))})})}async sendNotificationToClangd(e,t){await this.writeToClangd({jsonrpc:"2.0",method:e,params:t??void 0})}async writeToClangd(e){if(!this.clangdStdin)throw new Error("clangd stdin not available");return new Promise((t,n)=>{let i;try{i=JSON.stringify(e)}catch(u){n(new Error(`Failed to encode LSP message: ${u}`));return}let o=Buffer.from(i,"utf8"),s=Buffer.from(`Content-Length: ${o.length}\r
1251
1251
  \r
1252
1252
  `,"ascii"),a=!1,c=u=>{a||(a=!0,u?n(u):t())};if(this.clangdStdin.write(Buffer.concat([s,o]),u=>{u?c(u):a||c()}))c();else{let u=()=>c();this.clangdStdin.once("drain",u)}})}handleClangdData(e){for(this.clangdBuffer=this.clangdBuffer.length===0?e:Buffer.concat([this.clangdBuffer,e]);;){let t=this.clangdBuffer.indexOf(`\r
1253
1253
  \r
@@ -1262,5 +1262,5 @@ Output so far:
1262
1262
  `),a.join(`
1263
1263
  `)].filter(y=>y.trim().length>0).join(`
1264
1264
  `).trim()||"No diagnostics collected"}],isError:d}}async callArktsCheck(e){switch(this.projectState){case 0:return this.handleIdleCheck();case 1:case 2:return f.warn(`ArkTS check rejected: project is ${aa[this.projectState]}, files: ${e.join(", ")}`),{content:[{type:"text",text:"Project is syncing, please retry in 10 seconds"}],isError:!0};case 3:return f.warn(`ArkTS check rejected: LSP is initializing, files: ${e.join(", ")}`),{content:[{type:"text",text:"ArkTS LSP is initializing, please retry in 10 seconds"}],isError:!0};case 5:return this.handleErrorCheck();case 4:return this.arktsCheckTool.handleCall({files:e})}}async handleIdleCheck(){if(this.ensureProjectReady(),this.config.projectPath){let e,t;return this.syncSkippedDueToLock?(e=`Another build process is running, sync deferred (waiting ${this.syncSkipStartedAt>0?Math.round((Date.now()-this.syncSkipStartedAt)/1e3):0}s), please retry in 25 seconds`,t="lock contention",this.syncSkippedDueToLock=!1):this.configChangedTriggeredResync?(e="Config file changed, resyncing project, please retry in 10 seconds",t="config changed",this.configChangedTriggeredResync=!1):(e="HarmonyOS project detected, syncing, please retry in 10 seconds",t="initial"),f.info(`Idle check: project '${this.config.projectPath}' already known, triggering init (${t})`),{content:[{type:"text",text:e}],isError:!0}}return this.workspaceRoot||this.originalProjectPath?(f.info(`Idle check: no project path yet, will try from '${this.workspaceRoot}' or '${this.originalProjectPath}'`),{content:[{type:"text",text:"Initializing, please retry in 10 seconds"}],isError:!0}):(f.warn("Idle check: no search candidates available"),{content:[{type:"text",text:"No HarmonyOS project detected. Please verify the project directory or create a project first."}],isError:!0})}async handleErrorCheck(){return this.initRetryCount>=ci?(f.error(`Init retry limit reached (${this.initRetryCount}/${ci}), will not auto-retry`),{content:[{type:"text",text:"Project initialization failed multiple times. Please check project configuration and restart the MCP Server."}],isError:!0}):(f.info(`Error check: auto-retrying (${this.initRetryCount}/${ci})`),this.ensureProjectReady(),{content:[{type:"text",text:"Project initialization failed, auto-retrying, please retry in 10 seconds"}],isError:!0})}async callCppCheck(e){if(!this.cppCheckTool){let t=this.config.projectPath?"C++ LSP is not ready, please retry later":"Project path is not configured. Set the PROJECT_PATH parameter or open a project in DevEco Studio.";return f.warn(`C++ check rejected: ${t}, files: ${e.join(", ")}`),{content:[{type:"text",text:t}],isError:!0}}return this.cppCheckTool.handleCall({files:e})}mergeCheckResult(e,t,n){let i=e.content.map(o=>o.text).filter(o=>o&&o.trim().length>0).join(`
1265
- `);i&&(e.isError?t.push(i):n.push(i))}setProjectPath(e){this.config.projectPath=e,this.arktsCheckTool&&(this.arktsCheckTool.shutdown().catch(t=>{f.warn("Failed to shutdown ArktsCheckTool during setProjectPath:",t)}),this.arktsCheckTool=null),this.cppCheckTool&&(this.cppCheckTool.shutdown().catch(t=>{f.warn("Failed to shutdown CppCheckTool during setProjectPath:",t)}),this.cppCheckTool=null),this.initPromise?(this.needsReinit=!0,f.info("Project path changed while init is running, will reinit after current init completes")):(this.projectState=0,this.ensureProjectReady().catch(t=>{f.warn("Failed to re-init project after setProjectPath:",t)}))}async start(){this.toolRouter.registerToServer(this.server);let e=new Xu;if(await this.server.connect(e),f.info("devecocli-mcp-server started"),!this.config.debug){let t=As();t&&f.info(`Log file: ${t}`)}if(this.setupStdinCloseHandler(),this.config.projectPath)this.workspaceRoot=this.config.projectPath;else{let t=await this.getProjectRootFromClient();if(t){this.workspaceRoot=t;let n=ye(t);n?(f.info(`Detected project path from client root: ${n}`),this.config.projectPath=n):f.warn(`Client root '${t}' is not a HarmonyOS project`)}else this.originalProjectPath?f.warn(`PROJECT_PATH '${this.originalProjectPath}' was provided but no HarmonyOS project was found in it`):f.info("project path is empty (no PROJECT_PATH env and client did not provide roots)")}this.ensureProjectReady().catch(t=>{f.warn("Background project init failed:",t)}),this.initializeCppCheck()}async getProjectRootFromClient(){try{let t=(await this.server.server.listRoots()).roots?.[0];if(!t)return f.warn("Client did not provide any roots"),null;let n=t.uri;return this.resolveFileUri(n)}catch(e){return f.warn("Failed to list roots from client:",e),null}}resolveFileUri(e){try{let t=new URL(e);if(t.protocol==="file:"){let n=t.pathname;return process.platform==="win32"&&/^\/[A-Za-z]:/.test(n)?n.substring(1):n}}catch(t){f.warn("Failed to parse URI with URL API, falling back to manual parsing:",t)}if(e.startsWith("file://")){let t=e.substring(7);return t=decodeURIComponent(t),process.platform==="win32"&&t.startsWith("/")&&/^[A-Za-z]:/.test(t.substring(1))&&(t=t.substring(1)),t}return e}setupStdinCloseHandler(){let e=!1,t=()=>{e||(e=!0,f.info("stdin closed (MCP client disconnected), shutting down..."),this.shutdown().then(()=>{f.info("shutdown completed, exiting process"),process.exit(0)}).catch(n=>{f.error("shutdown failed:",n),process.exit(1)}))};process.stdin.on("end",t),process.stdin.on("close",t)}initializeCppCheck(){let e=this.config.projectPath;if(!e){f.warn("C++ LSP initialization skipped: project path is not configured");return}this.cppCheckTool=new ht(e,this.toolProvider),f.info("CppCheckTool created (lazy initialization)")}async ensureProjectReady(){if(!this.initPromise){this.initPromise=this.doEnsureProjectReady();try{await this.initPromise}finally{this.initPromise=null}this.needsReinit&&(this.needsReinit=!1,this.projectState=0,this.ensureProjectReady().catch(e=>{f.warn("Failed to re-init project after needsReinit:",e)}))}}discoverProject(){if(!((this.projectState===0||this.projectState===5)&&!this.config.projectPath))return!0;this.projectState=1;let t=this.workspaceRoot?ye(this.workspaceRoot):null;return!t&&this.originalProjectPath&&(t=ye(this.originalProjectPath),t&&f.info(`Phase 1 found HarmonyOS project from original config: ${t}`)),t?(this.config.projectPath=t,this.initRetryCount=0,!0):(this.projectState=0,!1)}async doEnsureProjectReady(){if(this.discoverProject()&&await this.ensureProjectSynced()){this.projectState=3,this.arktsCheckTool=new pt(this.config.projectPath,this.toolProvider,this.config.nodeMaxOldSpaceSize),this.arktsCheckTool.setOnConfigChanged(()=>{f.info("Config files changed, resetting to IDLE state for reinit"),this.configChangedTriggeredResync=!0,this.needsReinit=!0,this.projectState=0});try{await this.arktsCheckTool.initialize(),this.projectState=4,this.initRetryCount=0,f.info("Project fully initialized, check tool is available")}catch(e){f.error("LSP initialization failed:",e),this.arktsCheckTool=null,this.initRetryCount++,this.projectState=5}}}async ensureProjectSynced(){let e=this.config.projectPath,t=oa(e);return t.required?(f.info(`Sync required: ${t.reason}`),this.runSync(e)):(f.info(`Sync skipped: ${t.reason}`),!0)}async runSync(e){this.projectState=2,f.info("Starting project sync...");let t=await ut.handleSyncProject(e,this.toolProvider);switch(t.status){case"success":return this.syncSkippedDueToLock=!1,this.syncSkipStartedAt=0,!0;case"skipped":{this.syncSkippedDueToLock=!0,this.syncSkipStartedAt===0&&(this.syncSkipStartedAt=Date.now());let n=Date.now()-this.syncSkipStartedAt,i=Math.round(n/1e3);return n>=sa?(f.error(`Sync skipped for ${i}s due to lock contention, giving up`),this.initRetryCount++,this.syncSkipStartedAt=0,this.projectState=5,!1):(f.warn(`Sync skipped: ${t.reason}, resetting to IDLE for retry (elapsed ${i}s / ${sa/1e3}s)`),this.projectState=0,!1)}case"failed":return f.error(`Project sync failed: ${t.reason}`),this.syncSkippedDueToLock=!1,this.syncSkipStartedAt=0,this.initRetryCount++,this.projectState=5,!1}}async shutdown(){this.arktsCheckTool&&await this.arktsCheckTool.shutdown(),this.cppCheckTool&&await this.cppCheckTool.shutdown();try{await this.server.close()}catch(e){f.warn("Failed to close MCP server connection:",e)}f.info("devecocli-mcp-server stopped"),Is(),Ds()}getToolRouter(){return this.toolRouter}getServer(){return this.server}};function Zu(r){let e=[],t=[],n=[];for(let i of r)er.extname(i).toLowerCase()===".ets"?e.push(i):mn(i)?t.push(i):n.push(i);return{etsFiles:e,cppFiles:t,unsupported:n}}function li(r){return new Qn(r)}async function ep(){let r=process.env.PROJECT_PATH||"",e=process.env.DEVECO_PATH,t=process.env.NODE_MAX_OLD_SPACE_SIZE,n=process.env.DEBUG==="true"||process.env.DEBUG==="1",i=await O.new(e),s=li({toolProvider:i,projectPath:r,nodeMaxOldSpaceSize:t,debug:n}),a=async()=>{await s.shutdown(),process.exit(0)};process.once("SIGINT",a),process.once("SIGTERM",a),process.platform==="win32"&&process.once("SIGBREAK",a);try{await s.start()}catch(c){console.error("Failed to start MCP server:",c),process.exit(1)}}var ca=new Qu("serve").description("Host bundled auxiliary protocol servers");ca.command("mcp").description("Start a local stdio-based MCP server").action(async()=>{await ep()});var la=ca;import{Command as dp,InvalidArgumentError as pi}from"commander";import{red as Bt,dim as up}from"colorette";import*as K from"path";import*as se from"fs";import{homedir as ip}from"os";import{ripgrep as tp}from"ripgrep";import{execa as np}from"execa";var tr=null;async function rp(){if(tr!==null)return tr;let{rgPath:r}=await import("@vscode/ripgrep");return tr=r,tr}async function da(r){if(P())return tp(r,{buffer:!0});let e=await rp(),t=await np(e,r,{reject:!1});return{code:t.exitCode??1,stdout:t.stdout,stderr:t.stderr}}import op from"adm-zip";import{fileURLToPath as sp}from"url";import ap from"ora";var Wt=["harmonyos-guides","harmonyos-references","best-practices","harmonyos-faqs","harmonyos-releases","harmonyos-roadmap"],Ut={"harmonyos-guides":"\u5F00\u53D1\u6307\u5357","harmonyos-references":"API\u53C2\u8003","best-practices":"\u6700\u4F73\u5B9E\u8DF5","harmonyos-faqs":"FAQ","harmonyos-releases":"\u7248\u672C\u8BF4\u660E","harmonyos-roadmap":"\u53D8\u66F4\u9884\u544A"};var cp="deveco-cli",lp="docs",di=class{docsDir;versionFile;initialized=!1;initPromise=null;constructor(){this.docsDir=K.join(ip(),".local","share",cp,lp),this.versionFile=K.join(this.docsDir,".version")}getDocsDir(){return this.docsDir}async ensureInitialized(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.extractDocsIfNeeded(),await this.initPromise,this.initialized=!0}}async extractDocsIfNeeded(){let e=this.getCurrentVersion();await this.getExistingVersion()!==e&&await this.extractDocs(e)}getCurrentVersion(){return"0.1.0-TD.3.1"}async getExistingVersion(){try{return(await se.promises.readFile(this.versionFile,"utf-8")).trim()}catch{return null}}async extractDocs(e){let t=this.findDocsZip();if(!t)throw new Error("docs.zip not found.");let n=ap({text:"Extracting documentation\u2026",color:"cyan"}).start();try{let i=K.dirname(this.docsDir);await se.promises.mkdir(i,{recursive:!0}),await this.cleanOldDocs(),await se.promises.mkdir(this.docsDir,{recursive:!0}),new op(t).extractAllTo(this.docsDir,!0),await se.promises.writeFile(this.versionFile,e,"utf-8"),n.succeed("Documentation extracted successfully.")}catch(i){throw n.fail("Failed to extract documentation."),i}}findDocsZip(){let e=import.meta.url,t=sp(e),n=K.dirname(t),i=[K.join(n,"..","docs.zip")];for(let o of i)if(se.existsSync(o))return o;return null}async cleanOldDocs(){try{await se.promises.rm(this.docsDir,{recursive:!0,force:!0})}catch{}}async search(e,t){await this.ensureInitialized();let n=t?K.join(this.docsDir,Ut[t]):this.docsDir,i=await this.searchFiles(e,n),o=await this.enrichWithTitleRelevance(i,e),s=this.selectByTiers(o,e.length);return(await Promise.all(s.map(async c=>{let d=this.parseFilePath(c.filePath);if(!d||!c.metadata)return null;let u=await this.readContentPreview(c.filePath);return{title:c.metadata.title,documentId:d,content:u}}))).filter(c=>c!==null)}selectByTiers(e,t){let n=(a,c)=>c.totalMatches-a.totalMatches,i=e.filter(a=>a.titleKeywordCount===t).sort(n),o=e.filter(a=>a.keywordCount===t&&a.titleKeywordCount<t).sort(n),s=e.filter(a=>a.keywordCount<t&&a.titleKeywordCount<t).sort(n);return[...i,...o,...s]}async enrichWithTitleRelevance(e,t){return Promise.all(Array.from(e.entries()).map(async([n,i])=>{let o=await this.readMetadata(n),s=o?t.filter(a=>o.title.toLowerCase().includes(a.toLowerCase())).length:0;return{filePath:n,keywordCount:i.keywordCount,totalMatches:i.totalMatches,titleKeywordCount:s,metadata:o}}))}async searchSingleKeyword(e,t){let i=await da(["--type","md","--json","--no-messages","-i","-e",e,t]);if(i.code===1)return new Map;if(i.code!==0)throw new Error(i.stderr?.trim()||`Search failed with exit code ${i.code}`);return this.parseSearchResults(i.stdout)}async searchFiles(e,t){let n=await Promise.all(e.map(o=>this.searchSingleKeyword(o,t))),i=new Map;for(let o of n)for(let[s,a]of o){let c=i.get(s);c?(c.keywordCount+=1,c.totalMatches+=a):i.set(s,{keywordCount:1,totalMatches:a})}return i}parseSearchResults(e){let t=e.split(`
1266
- `),n=new Map;for(let i of t){if(!i)continue;let o=this.parseSearchResultLine(i);o&&n.set(o.filePath,o.count)}return n}parseSearchResultLine(e){try{let t=JSON.parse(e);if(t.type==="end"&&t.data?.path?.text){let n=t.data.stats?.matches??0;if(n>0)return{filePath:t.data.path.text,count:n}}}catch{}return null}async readDocument(e){await this.ensureInitialized();let n=[e,`${e}.md`].filter(i=>S.isPathContainedWithSymlink(i,this.docsDir).contained).map(i=>K.join(this.docsDir,i));for(let i of n)try{return await se.promises.readFile(i,"utf-8")}catch{continue}throw new Error(`Document not found: ${e}`)}parseFilePath(e){if(!e.endsWith(".md"))return null;let t=K.relative(this.docsDir,e);if(!t||t.startsWith("..")||K.isAbsolute(t))return null;let n=t.split(/[/\\]/);if(n.length<2)return null;let i=n[n.length-1];return n[n.length-1]=i.replace(/\.md$/,""),n.join("/")}async readMetadata(e){let t=e.replace(/\.md$/,".json");try{let n=await se.promises.readFile(t,"utf-8");return JSON.parse(n)}catch{return null}}async readContentPreview(e){try{let t=await se.promises.readFile(e,"utf-8"),n=t.replace(/\n/g," ").trim().slice(0,200);return n.length<t.replace(/\n/g," ").trim().length?n+"...":n}catch{return""}}},ui=new di;function ua(...r){return e=>{if(!r.includes(e))throw new pi(`Allowed values: ${r.join(", ")}`);return e}}function pp(r){let e=Number(r);if(!Number.isInteger(e)||e<=0)throw new pi("Must be a positive integer.");return e}var hp=ua("json","default"),fp=ua("json","default"),nr=new dp("docs").description("Search and read HarmonyOS documentation from local docs directory");nr.command("search <keywords...>").description("Search documentation by keywords").option("--catalog <name>","Catalog name (all : all catalogs)",mp,"all").option("--format <fmt>","Output format (default, json)",hp,"default").option("--limit <n>","Max number of results",pp,20).action(async(r,e)=>{try{let t=r.map(s=>s.trim()).filter(s=>s);t.length===0&&(console.error(Bt("Keywords cannot be empty.")),process.exit(1)),t.length>10&&(console.error(Bt("Keywords cannot exceed 10.")),process.exit(1));let n=e.catalog&&e.catalog!=="all"?e.catalog:void 0,o=(await ui.search(t,n)).slice(0,e.limit);e.format==="json"?console.log(JSON.stringify(o,null,2)):gp(o)}catch(t){console.error(Bt(t.message)),process.exit(1)}});nr.command("read <documentId>").description("Read full content of a document by document ID").action(async r=>{try{let e=r.trim();e||(console.error(Bt("Document ID cannot be empty.")),process.exit(1));let t=await ui.readDocument(e);console.log(t)}catch(e){console.error(Bt(e.message)),process.exit(1)}});nr.command("catalog").description("List all available catalogs").option("--format <fmt>","Output format (options: default,json)",fp,"default").action(r=>{if(r.format==="json"){let e=Wt.map(t=>({name:t,title:Ut[t]}));console.log(JSON.stringify(e,null,2))}else for(let e of Wt)console.log(` ${e.padEnd(20)} ${up(Ut[e])}`)});function mp(r){if(r==="all")return"all";if(!Wt.includes(r))throw new pi(`Invalid catalog "${r}". Allowed: all, ${Wt.join(", ")}`);return r}function gp(r){for(let e=0;e<r.length;e++){let t=r[e];console.log(t.documentId),console.log(` Title: ${t.title}`),t.content&&console.log(` Content: ${t.content}`),e<r.length-1&&console.log()}}var pa=nr;process.env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE="";yp();V.name("devecocli").description("HarmonyOS application development command line tool").version("0.1.0-TD.3.1");V.addCommand(Ti);V.addCommand(ji);V.addCommand(Wi);V.addCommand(Qi);P()||V.addCommand(So);V.addCommand(qo);V.addCommand(Xo);V.addCommand(ss);V.addCommand(fs);V.addCommand(la);V.addCommand(pa);var hi=process.argv.slice(2);hi.length>=2&&hi[hi.length-1]==="help"&&(process.argv=[...process.argv.slice(0,-1),"--help"]);var wp=new Set(["update"]);V.hook("preAction",async(r,e)=>{if(process.env.DEVECO_CLI_SKIP_VERSION_CHECK)return;let t=e;for(;t.parent&&t.parent!==V;)t=t.parent;wp.has(t.name())||await O.checkVersion()});V.parseAsync(process.argv).catch(r=>{let e=r instanceof Error?r.message:String(r??"Unknown error");console.error(vp(`Error: ${e}`)),process.env.DEVECO_CLI_DEBUG==="1"&&r instanceof Error&&r.stack&&console.error(r.stack),process.exit(1)});
1265
+ `);i&&(e.isError?t.push(i):n.push(i))}setProjectPath(e){this.config.projectPath=e,this.arktsCheckTool&&(this.arktsCheckTool.shutdown().catch(t=>{f.warn("Failed to shutdown ArktsCheckTool during setProjectPath:",t)}),this.arktsCheckTool=null),this.cppCheckTool&&(this.cppCheckTool.shutdown().catch(t=>{f.warn("Failed to shutdown CppCheckTool during setProjectPath:",t)}),this.cppCheckTool=null),this.initPromise?(this.needsReinit=!0,f.info("Project path changed while init is running, will reinit after current init completes")):(this.projectState=0,this.ensureProjectReady().catch(t=>{f.warn("Failed to re-init project after setProjectPath:",t)}))}async start(){this.toolRouter.registerToServer(this.server);let e=new Xu;if(await this.server.connect(e),f.info("devecocli-mcp-server started"),!this.config.debug){let t=As();t&&f.info(`Log file: ${t}`)}if(this.setupStdinCloseHandler(),this.config.projectPath)this.workspaceRoot=this.config.projectPath;else{let t=await this.getProjectRootFromClient();if(t){this.workspaceRoot=t;let n=ye(t);n?(f.info(`Detected project path from client root: ${n}`),this.config.projectPath=n):f.warn(`Client root '${t}' is not a HarmonyOS project`)}else this.originalProjectPath?f.warn(`PROJECT_PATH '${this.originalProjectPath}' was provided but no HarmonyOS project was found in it`):f.info("project path is empty (no PROJECT_PATH env and client did not provide roots)")}this.ensureProjectReady().catch(t=>{f.warn("Background project init failed:",t)}),this.initializeCppCheck()}async getProjectRootFromClient(){try{let t=(await this.server.server.listRoots()).roots?.[0];if(!t)return f.warn("Client did not provide any roots"),null;let n=t.uri;return this.resolveFileUri(n)}catch(e){return f.warn("Failed to list roots from client:",e),null}}resolveFileUri(e){try{let t=new URL(e);if(t.protocol==="file:"){let n=t.pathname;return process.platform==="win32"&&/^\/[A-Za-z]:/.test(n)?n.substring(1):n}}catch(t){f.warn("Failed to parse URI with URL API, falling back to manual parsing:",t)}if(e.startsWith("file://")){let t=e.substring(7);return t=decodeURIComponent(t),process.platform==="win32"&&t.startsWith("/")&&/^[A-Za-z]:/.test(t.substring(1))&&(t=t.substring(1)),t}return e}setupStdinCloseHandler(){let e=!1,t=()=>{e||(e=!0,f.info("stdin closed (MCP client disconnected), shutting down..."),this.shutdown().then(()=>{f.info("shutdown completed, exiting process"),process.exit(0)}).catch(n=>{f.error("shutdown failed:",n),process.exit(1)}))};process.stdin.on("end",t),process.stdin.on("close",t)}initializeCppCheck(){let e=this.config.projectPath;if(!e){f.warn("C++ LSP initialization skipped: project path is not configured");return}this.cppCheckTool=new ht(e,this.toolProvider),f.info("CppCheckTool created (lazy initialization)")}async ensureProjectReady(){if(!this.initPromise){this.initPromise=this.doEnsureProjectReady();try{await this.initPromise}finally{this.initPromise=null}this.needsReinit&&(this.needsReinit=!1,this.projectState=0,this.ensureProjectReady().catch(e=>{f.warn("Failed to re-init project after needsReinit:",e)}))}}discoverProject(){if(!((this.projectState===0||this.projectState===5)&&!this.config.projectPath))return!0;this.projectState=1;let t=this.workspaceRoot?ye(this.workspaceRoot):null;return!t&&this.originalProjectPath&&(t=ye(this.originalProjectPath),t&&f.info(`Phase 1 found HarmonyOS project from original config: ${t}`)),t?(this.config.projectPath=t,this.initRetryCount=0,!0):(this.projectState=0,!1)}async doEnsureProjectReady(){if(this.discoverProject()&&await this.ensureProjectSynced()){this.projectState=3,this.arktsCheckTool=new pt(this.config.projectPath,this.toolProvider,this.config.nodeMaxOldSpaceSize),this.arktsCheckTool.setOnConfigChanged(()=>{f.info("Config files changed, resetting to IDLE state for reinit"),this.configChangedTriggeredResync=!0,this.needsReinit=!0,this.projectState=0});try{await this.arktsCheckTool.initialize(),this.projectState=4,this.initRetryCount=0,f.info("Project fully initialized, check tool is available")}catch(e){f.error("LSP initialization failed:",e),this.arktsCheckTool=null,this.initRetryCount++,this.projectState=5}}}async ensureProjectSynced(){let e=this.config.projectPath,t=oa(e);return t.required?(f.info(`Sync required: ${t.reason}`),this.runSync(e)):(f.info(`Sync skipped: ${t.reason}`),!0)}async runSync(e){this.projectState=2,f.info("Starting project sync...");let t=await ut.handleSyncProject(e,this.toolProvider);switch(t.status){case"success":return this.syncSkippedDueToLock=!1,this.syncSkipStartedAt=0,!0;case"skipped":{this.syncSkippedDueToLock=!0,this.syncSkipStartedAt===0&&(this.syncSkipStartedAt=Date.now());let n=Date.now()-this.syncSkipStartedAt,i=Math.round(n/1e3);return n>=sa?(f.error(`Sync skipped for ${i}s due to lock contention, giving up`),this.initRetryCount++,this.syncSkipStartedAt=0,this.projectState=5,!1):(f.warn(`Sync skipped: ${t.reason}, resetting to IDLE for retry (elapsed ${i}s / ${sa/1e3}s)`),this.projectState=0,!1)}case"failed":return f.error(`Project sync failed: ${t.reason}`),this.syncSkippedDueToLock=!1,this.syncSkipStartedAt=0,this.initRetryCount++,this.projectState=5,!1}}async shutdown(){this.arktsCheckTool&&await this.arktsCheckTool.shutdown(),this.cppCheckTool&&await this.cppCheckTool.shutdown();try{await this.server.close()}catch(e){f.warn("Failed to close MCP server connection:",e)}f.info("devecocli-mcp-server stopped"),Is(),Ds()}getToolRouter(){return this.toolRouter}getServer(){return this.server}};function Zu(r){let e=[],t=[],n=[];for(let i of r)er.extname(i).toLowerCase()===".ets"?e.push(i):mn(i)?t.push(i):n.push(i);return{etsFiles:e,cppFiles:t,unsupported:n}}function li(r){return new Qn(r)}async function ep(){let r=process.env.PROJECT_PATH||"",e=process.env.DEVECO_PATH,t=process.env.NODE_MAX_OLD_SPACE_SIZE,n=process.env.DEBUG==="true"||process.env.DEBUG==="1",i=await O.new(e),s=li({toolProvider:i,projectPath:r,nodeMaxOldSpaceSize:t,debug:n}),a=async()=>{await s.shutdown(),process.exit(0)};process.once("SIGINT",a),process.once("SIGTERM",a),process.platform==="win32"&&process.once("SIGBREAK",a);try{await s.start()}catch(c){console.error("Failed to start MCP server:",c),process.exit(1)}}var ca=new Qu("serve").description("Host bundled auxiliary protocol servers");ca.command("mcp").description("Start a local stdio-based MCP server").action(async()=>{await ep()});var la=ca;import{Command as dp,InvalidArgumentError as pi}from"commander";import{red as Bt,dim as up}from"colorette";import*as K from"path";import*as se from"fs";import{homedir as ip}from"os";import{ripgrep as tp}from"ripgrep";import{execa as np}from"execa";var tr=null;async function rp(){if(tr!==null)return tr;let{rgPath:r}=await import("@vscode/ripgrep");return tr=r,tr}async function da(r){if(P())return tp(r,{buffer:!0});let e=await rp(),t=await np(e,r,{reject:!1});return{code:t.exitCode??1,stdout:t.stdout,stderr:t.stderr}}import op from"adm-zip";import{fileURLToPath as sp}from"url";import ap from"ora";var Wt=["harmonyos-guides","harmonyos-references","best-practices","harmonyos-faqs","harmonyos-releases","harmonyos-roadmap"],Ut={"harmonyos-guides":"\u5F00\u53D1\u6307\u5357","harmonyos-references":"API\u53C2\u8003","best-practices":"\u6700\u4F73\u5B9E\u8DF5","harmonyos-faqs":"FAQ","harmonyos-releases":"\u7248\u672C\u8BF4\u660E","harmonyos-roadmap":"\u53D8\u66F4\u9884\u544A"};var cp="deveco-cli",lp="docs",di=class{docsDir;versionFile;initialized=!1;initPromise=null;constructor(){this.docsDir=K.join(ip(),".local","share",cp,lp),this.versionFile=K.join(this.docsDir,".version")}getDocsDir(){return this.docsDir}async ensureInitialized(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.extractDocsIfNeeded(),await this.initPromise,this.initialized=!0}}async extractDocsIfNeeded(){let e=this.getCurrentVersion();await this.getExistingVersion()!==e&&await this.extractDocs(e)}getCurrentVersion(){return"0.1.0-TD.3.2"}async getExistingVersion(){try{return(await se.promises.readFile(this.versionFile,"utf-8")).trim()}catch{return null}}async extractDocs(e){let t=this.findDocsZip();if(!t)throw new Error("docs.zip not found.");let n=ap({text:"Extracting documentation\u2026",color:"cyan"}).start();try{let i=K.dirname(this.docsDir);await se.promises.mkdir(i,{recursive:!0}),await this.cleanOldDocs(),await se.promises.mkdir(this.docsDir,{recursive:!0}),new op(t).extractAllTo(this.docsDir,!0),await se.promises.writeFile(this.versionFile,e,"utf-8"),n.succeed("Documentation extracted successfully.")}catch(i){throw n.fail("Failed to extract documentation."),i}}findDocsZip(){let e=import.meta.url,t=sp(e),n=K.dirname(t),i=[K.join(n,"..","docs.zip")];for(let o of i)if(se.existsSync(o))return o;return null}async cleanOldDocs(){try{await se.promises.rm(this.docsDir,{recursive:!0,force:!0})}catch{}}async search(e,t){await this.ensureInitialized();let n=t?K.join(this.docsDir,Ut[t]):this.docsDir,i=await this.searchFiles(e,n),o=await this.enrichWithTitleRelevance(i,e),s=this.selectByTiers(o,e.length);return(await Promise.all(s.map(async c=>{let d=this.parseFilePath(c.filePath);if(!d||!c.metadata)return null;let u=await this.readContentPreview(c.filePath);return{title:c.metadata.title,documentId:d,content:u}}))).filter(c=>c!==null)}selectByTiers(e,t){let n=(a,c)=>c.totalMatches-a.totalMatches,i=e.filter(a=>a.titleKeywordCount===t).sort(n),o=e.filter(a=>a.keywordCount===t&&a.titleKeywordCount<t).sort(n),s=e.filter(a=>a.keywordCount<t&&a.titleKeywordCount<t).sort(n);return[...i,...o,...s]}async enrichWithTitleRelevance(e,t){return Promise.all(Array.from(e.entries()).map(async([n,i])=>{let o=await this.readMetadata(n),s=o?t.filter(a=>o.title.toLowerCase().includes(a.toLowerCase())).length:0;return{filePath:n,keywordCount:i.keywordCount,totalMatches:i.totalMatches,titleKeywordCount:s,metadata:o}}))}async searchSingleKeyword(e,t){let i=await da(["--type","md","--json","--no-messages","-i","-e",e,t]);if(i.code===1)return new Map;if(i.code!==0)throw new Error(i.stderr?.trim()||`Search failed with exit code ${i.code}`);return this.parseSearchResults(i.stdout)}async searchFiles(e,t){let n=await Promise.all(e.map(o=>this.searchSingleKeyword(o,t))),i=new Map;for(let o of n)for(let[s,a]of o){let c=i.get(s);c?(c.keywordCount+=1,c.totalMatches+=a):i.set(s,{keywordCount:1,totalMatches:a})}return i}parseSearchResults(e){let t=e.split(`
1266
+ `),n=new Map;for(let i of t){if(!i)continue;let o=this.parseSearchResultLine(i);o&&n.set(o.filePath,o.count)}return n}parseSearchResultLine(e){try{let t=JSON.parse(e);if(t.type==="end"&&t.data?.path?.text){let n=t.data.stats?.matches??0;if(n>0)return{filePath:t.data.path.text,count:n}}}catch{}return null}async readDocument(e){await this.ensureInitialized();let n=[e,`${e}.md`].filter(i=>S.isPathContainedWithSymlink(i,this.docsDir).contained).map(i=>K.join(this.docsDir,i));for(let i of n)try{return await se.promises.readFile(i,"utf-8")}catch{continue}throw new Error(`Document not found: ${e}`)}parseFilePath(e){if(!e.endsWith(".md"))return null;let t=K.relative(this.docsDir,e);if(!t||t.startsWith("..")||K.isAbsolute(t))return null;let n=t.split(/[/\\]/);if(n.length<2)return null;let i=n[n.length-1];return n[n.length-1]=i.replace(/\.md$/,""),n.join("/")}async readMetadata(e){let t=e.replace(/\.md$/,".json");try{let n=await se.promises.readFile(t,"utf-8");return JSON.parse(n)}catch{return null}}async readContentPreview(e){try{let t=await se.promises.readFile(e,"utf-8"),n=t.replace(/\n/g," ").trim().slice(0,200);return n.length<t.replace(/\n/g," ").trim().length?n+"...":n}catch{return""}}},ui=new di;function ua(...r){return e=>{if(!r.includes(e))throw new pi(`Allowed values: ${r.join(", ")}`);return e}}function pp(r){let e=Number(r);if(!Number.isInteger(e)||e<=0)throw new pi("Must be a positive integer.");return e}var hp=ua("json","default"),fp=ua("json","default"),nr=new dp("docs").description("Search and read HarmonyOS documentation from local docs directory");nr.command("search <keywords...>").description("Search documentation by keywords").option("--catalog <name>","Catalog name (all : all catalogs)",mp,"all").option("--format <fmt>","Output format (default, json)",hp,"default").option("--limit <n>","Max number of results",pp,20).action(async(r,e)=>{try{let t=r.map(s=>s.trim()).filter(s=>s);t.length===0&&(console.error(Bt("Keywords cannot be empty.")),process.exit(1)),t.length>10&&(console.error(Bt("Keywords cannot exceed 10.")),process.exit(1));let n=e.catalog&&e.catalog!=="all"?e.catalog:void 0,o=(await ui.search(t,n)).slice(0,e.limit);e.format==="json"?console.log(JSON.stringify(o,null,2)):gp(o)}catch(t){console.error(Bt(t.message)),process.exit(1)}});nr.command("read <documentId>").description("Read full content of a document by document ID").action(async r=>{try{let e=r.trim();e||(console.error(Bt("Document ID cannot be empty.")),process.exit(1));let t=await ui.readDocument(e);console.log(t)}catch(e){console.error(Bt(e.message)),process.exit(1)}});nr.command("catalog").description("List all available catalogs").option("--format <fmt>","Output format (options: default,json)",fp,"default").action(r=>{if(r.format==="json"){let e=Wt.map(t=>({name:t,title:Ut[t]}));console.log(JSON.stringify(e,null,2))}else for(let e of Wt)console.log(` ${e.padEnd(20)} ${up(Ut[e])}`)});function mp(r){if(r==="all")return"all";if(!Wt.includes(r))throw new pi(`Invalid catalog "${r}". Allowed: all, ${Wt.join(", ")}`);return r}function gp(r){for(let e=0;e<r.length;e++){let t=r[e];console.log(t.documentId),console.log(` Title: ${t.title}`),t.content&&console.log(` Content: ${t.content}`),e<r.length-1&&console.log()}}var pa=nr;process.env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE="";yp();V.name("devecocli").description("HarmonyOS application development command line tool").version("0.1.0-TD.3.2");V.addCommand(Ti);V.addCommand(ji);V.addCommand(Wi);V.addCommand(Qi);P()||V.addCommand(So);V.addCommand(qo);V.addCommand(Xo);V.addCommand(ss);V.addCommand(fs);V.addCommand(la);V.addCommand(pa);var hi=process.argv.slice(2);hi.length>=2&&hi[hi.length-1]==="help"&&(process.argv=[...process.argv.slice(0,-1),"--help"]);var wp=new Set(["update"]);V.hook("preAction",async(r,e)=>{if(process.env.DEVECO_CLI_SKIP_VERSION_CHECK)return;let t=e;for(;t.parent&&t.parent!==V;)t=t.parent;wp.has(t.name())||await O.checkVersion()});V.parseAsync(process.argv).catch(r=>{let e=r instanceof Error?r.message:String(r??"Unknown error");console.error(vp(`Error: ${e}`)),process.env.DEVECO_CLI_DEBUG==="1"&&r instanceof Error&&r.stack&&console.error(r.stack),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deveco-test/hmos-deveco-cli",
3
- "version": "0.1.0-TD.3.1",
3
+ "version": "0.1.0-TD.3.2",
4
4
  "description": "HarmonyOS application development command line tool",
5
5
  "license": "MIT",
6
6
  "type": "module",