@deveco-test/deveco-cli 1.2.0-Test.1 → 1.2.0-Test.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
@@ -28,7 +28,7 @@ Available runnable modules:
28
28
  `))}function _a(r,e,t,n,i){let o=[],s=r.collectNonHarDependentModuleList(e);for(let c of s){let d=r.findArtifactPath(c,t,n,i);o.push(d)}let a=r.findArtifactPath(e,t,n,i);return o.push(a),o}async function Wa(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(`
29
29
  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(ki(`
30
30
  Application '${t}': ${s}`))}var Ua=new La("run").description("Build and run the project on a connected device").option("--module <module>","Module 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 Va(r)}catch(e){console.error(Na(e.message)),process.exit(1)}});async function Ba(r,e,t,n,i,o){let s=new _e(e,r.rootDir),a=new Te(e,r.rootDir),d=r.collectNonHarDependentModuleList(t).map(D=>`${D}@${n}`),u=ir(r,d),v={type:"modules",modulesToBuild:d,moduleTasks:u};await pt(r.rootDir,()=>or(s,a,i,o,v),()=>console.log("Another build is already running for this project. Waiting for completion...")),console.log(`
31
- `+ki("Build completed successfully."))}async function Va(r){let e=ke.discover(process.cwd());console.warn(Ha("Ensure the project source is trusted before proceeding."));let t=await O.new(),n=$a(e,r.module),{moduleName:i,targetName:o}=ja(n),s=e.getModuleType(i);if(s!=="entry"&&s!=="feature"&&s!=="shared")throw new Error(`Module '${i}' '${s}' is not runnable. Specify an entry or feature module.`);let a=new Bt(t),c=V.from(t),d=await Fa(c,r.device),u=d.includes("127.0.0.1")||d.includes("localhost"),v=r.product||"default";e.validateProduct(v);let D=r.buildMode||"debug";r.skipBuild||await Ba(e,t,i,o,v,D);let le=_a(e,i,o,u,v),Fe=e.getBundleName(),$e=e.getMainAbility(i,r.ability);await Wa(a,d,Fe,le,$e,!!r.uninstall)}var Ti=Ua;import{Command as za}from"commander";import{green as Mi,red as Ri,cyan as cr}from"colorette";import{execa as xi}from"execa";function qa(){return"@deveco-test/deveco-cli"}function Ya(){return"1.2.0-Test.1"}var Ga=new za("update").description("Update deveco-cli to latest").action(async()=>{let r=qa(),e=Ya();console.log(cr("Checking for updates..."));try{let{stdout:t}=await xi("npm",["view",r,"version"]),n=t.trim();if(n===e){console.log(Mi(`
31
+ `+ki("Build completed successfully."))}async function Va(r){let e=ke.discover(process.cwd());console.warn(Ha("Ensure the project source is trusted before proceeding."));let t=await O.new(),n=$a(e,r.module),{moduleName:i,targetName:o}=ja(n),s=e.getModuleType(i);if(s!=="entry"&&s!=="feature"&&s!=="shared")throw new Error(`Module '${i}' '${s}' is not runnable. Specify an entry or feature module.`);let a=new Bt(t),c=V.from(t),d=await Fa(c,r.device),u=d.includes("127.0.0.1")||d.includes("localhost"),v=r.product||"default";e.validateProduct(v);let D=r.buildMode||"debug";r.skipBuild||await Ba(e,t,i,o,v,D);let le=_a(e,i,o,u,v),Fe=e.getBundleName(),$e=e.getMainAbility(i,r.ability);await Wa(a,d,Fe,le,$e,!!r.uninstall)}var Ti=Ua;import{Command as za}from"commander";import{green as Mi,red as Ri,cyan as cr}from"colorette";import{execa as xi}from"execa";function qa(){return"@deveco-test/deveco-cli"}function Ya(){return"1.2.0-Test.2"}var Ga=new za("update").description("Update deveco-cli to latest").action(async()=>{let r=qa(),e=Ya();console.log(cr("Checking for updates..."));try{let{stdout:t}=await xi("npm",["view",r,"version"]),n=t.trim();if(n===e){console.log(Mi(`
32
32
  ${r} is already up to date (version ${e}.)`));return}console.log(cr(`
33
33
  New version found: ${n} (current: ${e})`)),console.log(cr(`Updating ${r}...`)),await xi("npm",["install","-g",`${r}@latest`],{stdio:"inherit"}),console.log(`
34
34
  `+Mi(`${r} updated successfully to version ${n}.`))}catch(t){let n=t;console.error(Ri(`Failed to update ${r}`)),n.message&&console.error(Ri(n.message)),process.exit(1)}}),Oi=Ga;import{Command as gc}from"commander";import{execa as pr}from"execa";function H(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}import{spawn as Ja}from"child_process";var Ka=2500;function Xa(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 Za(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,Ka);r.once("error",u=>c(u.message)),Xa(r,d,s,a,c,o)}function Li(r,e,t){return w(`Spawning emulator: ${r} ${t.join(" ")}`),new Promise((n,i)=>{let o=[],s=Ja(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)),Za(s,o,n,i)})}import*as Be from"path";function Qa(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 ec(r){let e=r.instancePath?.trim();if(e)return Be.dirname(Be.normalize(e)).replace(/\\/g,"/");let t=r.path?.trim();return t?Be.dirname(Be.normalize(t)).replace(/\\/g,"/"):""}function tc(r){let e=[];return r&&e.push(["-imageRoot",r]),e.push([]),e}function Ni(r,e){return e?[...r,"-bootmode",e]:r}function nc(r,e,t){let n=[Ni(["-start",r],t)],i=ec(e);if(i)for(let o of tc(e.imageRoot))n.push(Ni(["-hvd",r,"-path",i,...o],t));return Qa(n)}async function Hi(r,e,t,n){let i=new Error("No start strategy ran"),o=nc(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 lr(r){return(await V.withHdcPath(r).listDevices()).map(t=>t.serial).filter(ft)}async function dr(r){let e=await lr(r);return e.length===0?[]:(await Promise.all(e.map(n=>Ut(r,n,"ohos.qemu.hvd.name")))).filter(n=>!!n)}async function ji(r,e){return(await dr(r)).includes(e)}import*as ze from"path";import{existsSync as rc,statSync as ic}from"fs";function Ve(r,e){for(let t of e){let n=r[t];if(typeof n=="string"&&n.trim())return n.trim()}return""}function oc(r){let e=Ve(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 sc(r){return Ve(r,["uuid","UUID","Uuid","instanceUuid","instance_uuid","InstanceUuid"])}function ac(r){let e=r.find(n=>n.instancePath?.trim());if(!e?.instancePath?.trim())return;let t=ze.dirname(ze.normalize(e.instancePath));for(let n of r){if(n.instancePath?.trim())continue;let i=ze.join(t,n.name);rc(i)&&ic(i).isDirectory()&&(n.instancePath=i.replace(/\\/g,"/"))}}function cc(r){try{let e=JSON.parse(r);return Array.isArray(e)?e.map(t=>{let n=sc(t),i=Ve(t,["deviceType","DeviceType","devicetype"]),o=Ve(t,["os.osVersion","osVersion","OsVersion","OSVersion"]);return{name:t.name||t.Name||"",isRunning:t.isRunning===!0||String(t.isRunning).toLowerCase()==="true",instancePath:oc(t),path:Ve(t,["path","Path","hvdPath","hvd_path"]),imageRoot:Ve(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 lc(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 Fi(r){let t=cc(r)??lc(r);return ac(t),t}function ur(r,e){for(let t of e){let n=r[t];if(typeof n=="string"&&n.trim())return n.trim()}return""}function dc(r){let e=r.downloaded??r.Downloaded;return e===!0||String(e).toLowerCase()==="true"}function uc(r){if(!dc(r))return null;let e=ur(r,["osVersion","OsVersion","OSVersion"]),t=ur(r,["SoftWareVersion","SoftwareVersion","softwareVersion"]),n=ur(r,["deviceType","DeviceType"]);return!e&&!t?null:{osVersion:e,softwareVersion:t,deviceType:n}}function Vt(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=uc(i);o&&n.push(o)}return n}catch{return[]}}function $i(r){let t=Vt(r).map(n=>n.osVersion).filter(Boolean);return[...new Set(t)]}var _i=/no images are available/i;function re(r){return r.normalize("NFKC").trim().toLowerCase()}function pc(r){let e=r.message||"";return _i.test(e)}var qe=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 pr(this.emulatorPath,e,{stdio:["ignore","pipe","pipe"],env:{...process.env,DEVECO_SDK_HOME:this.sdkPath}})}executeEmulatorDetached(e){return Li(this.emulatorPath,this.sdkPath,e)}async listEmulators(){let{stdout:e}=await this.executeEmulator(["-list","-details"]);return Fi(e)}async getDeviceTypeByName(){let e=new Map;try{let t=await this.listEmulators();for(let n of t)n.name&&n.deviceType&&e.set(H(n.name),n.deviceType)}catch{}return e}async startEmulator(e){let t=await this.listEmulators(),n=H(e),i=t.find(a=>H(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 Hi(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.
@@ -1245,7 +1245,7 @@ Output so far:
1245
1245
  `):"\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=te.isAbsolute(o)?o:te.join(n,o);if(!ve.existsSync(s)){t.push(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${o}`);continue}if(!ve.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 ws(500);try{let o=await this.checkFile(i);n.push(ku(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(`
1246
1246
  `)),t.length>0&&n.push(t.join(`
1247
1247
  `));let i=n.join(`
1248
- `).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(At),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=It(e),n=this.popDiagnosticWaiter(t);if(n)return n;for(let i of Ss(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=te.join(pn(),"ArkTSCheck"),n=te.join(t,"mapping-config.properties"),i=Ps(e,n),o=`${Date.now()}${process.hrtime.bigint()%1000000n}`,s=te.join(t,"lsp-log",String(i),o),a=te.join(t,"lsp-index",String(i));return ve.mkdirSync(s,{recursive:!0}),ve.mkdirSync(a,{recursive:!0}),{logPath:ce(s),indexPath:ce(a)}}catch{return{logPath:"auto",indexPath:"auto"}}}};function ku(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 Tu}from"child_process";import*as k from"fs";import*as L from"path";import{z as ni}from"zod";var Ks=60*1e3,Mu=30*1e3,Ru=new Set(["textDocument/didOpen","textDocument/didChange","textDocument/didClose","textDocument/didSave"]),xu=1e3,ri=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=ce(this.projectPath),i=Le(n),o=L.basename(n)||"workspace",s={processId:null,clientInfo:{name:"devecocli-mcp-server",version:"1.2.0-Test.1"},rootPath:n,rootUri:i,workspaceFolders:[{uri:i,name:o}],capabilities:{}};await this.sendRequestToClangd("initialize",s,Ks),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=Ks,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=k.realpathSync(e)}catch{t=e}let n=Le(t),i=bs(t),o=await k.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}`))},Mu);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}Ru.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
1248
+ `).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(At),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=It(e),n=this.popDiagnosticWaiter(t);if(n)return n;for(let i of Ss(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=te.join(pn(),"ArkTSCheck"),n=te.join(t,"mapping-config.properties"),i=Ps(e,n),o=`${Date.now()}${process.hrtime.bigint()%1000000n}`,s=te.join(t,"lsp-log",String(i),o),a=te.join(t,"lsp-index",String(i));return ve.mkdirSync(s,{recursive:!0}),ve.mkdirSync(a,{recursive:!0}),{logPath:ce(s),indexPath:ce(a)}}catch{return{logPath:"auto",indexPath:"auto"}}}};function ku(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 Tu}from"child_process";import*as k from"fs";import*as L from"path";import{z as ni}from"zod";var Ks=60*1e3,Mu=30*1e3,Ru=new Set(["textDocument/didOpen","textDocument/didChange","textDocument/didClose","textDocument/didSave"]),xu=1e3,ri=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=ce(this.projectPath),i=Le(n),o=L.basename(n)||"workspace",s={processId:null,clientInfo:{name:"devecocli-mcp-server",version:"1.2.0-Test.2"},rootPath:n,rootUri:i,workspaceFolders:[{uri:i,name:o}],capabilities:{}};await this.sendRequestToClangd("initialize",s,Ks),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=Ks,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=k.realpathSync(e)}catch{t=e}let n=Le(t),i=bs(t),o=await k.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}`))},Mu);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}Ru.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
1249
1249
  \r
1250
1250
  `,"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
1251
1251
  \r
@@ -1260,5 +1260,5 @@ Output so far:
1260
1260
  `),a.join(`
1261
1261
  `)].filter(v=>v.trim().length>0).join(`
1262
1262
  `).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 ${na[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>=si?(f.error(`Init retry limit reached (${this.initRetryCount}/${si}), 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}/${si})`),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(`
1263
- `);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 Gu;if(await this.server.connect(e),f.info("devecocli-mcp-server started"),!this.config.debug){let t=Is();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=fe(t);n?(f.info(`Detected project path from client root: ${n}`),this.config.projectPath=n,this.sdkPath=this.computeSdkPath()):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 ct(e,this.config.devecoPath??null),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?fe(this.workspaceRoot):null;return!t&&this.originalProjectPath&&(t=fe(this.originalProjectPath),t&&f.info(`Phase 1 found HarmonyOS project from original config: ${t}`)),t?(this.config.projectPath=t,this.sdkPath=this.computeSdkPath(),this.initRetryCount=0,!0):(this.projectState=0,!1)}async doEnsureProjectReady(){if(this.discoverProject()&&(this.sdkPath||(this.sdkPath=this.computeSdkPath()),!!await this.ensureProjectSynced())){this.projectState=3,this.arktsCheckTool=new at(this.config.projectPath,this.config.devecoPath??null,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=ea(e,this.config.forceSync??!1);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 st.handleSyncProject(e,this.sdkPath);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>=ta?(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 / ${ta/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}}computeSdkPath(){let e=dn(this.config.devecoPath??""),t=ae(e);return ut.join(t,"sdk")}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"),Ds(),Cs()}getToolRouter(){return this.toolRouter}getServer(){return this.server}};function Ju(r){let e=[],t=[],n=[];for(let i of r)ut.extname(i).toLowerCase()===".ets"?e.push(i):un(i)?t.push(i):n.push(i);return{etsFiles:e,cppFiles:t,unsupported:n}}function ai(r={}){return new Xn(r)}async function Xu(){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=process.env.DEVECO_MCP_FORCE_SYNC==="1",o=await O.new(),s=r,a=e??o.devecoStudioPath,c=ai({projectPath:s,devecoPath:a,nodeMaxOldSpaceSize:t,debug:n,forceSync:i}),d=async()=>{await c.shutdown(),process.exit(0)};process.once("SIGINT",d),process.once("SIGTERM",d),process.platform==="win32"&&process.once("SIGBREAK",d);try{await c.start()}catch(u){console.error("Failed to start MCP server:",u),process.exit(1)}}var ra=new Ku("serve").description("Host bundled auxiliary protocol servers");ra.command("mcp").description("Start a local stdio-based MCP server").action(async()=>{await Xu()});var ia=ra;import{Command as sp,InvalidArgumentError as di}from"commander";import{red as $t,dim as ap}from"colorette";import*as J from"path";import*as ne from"fs";import{homedir as Zu}from"os";import{execa as Qu}from"execa";import{rgPath as ep}from"@vscode/ripgrep";import tp from"adm-zip";import{fileURLToPath as np}from"url";import rp from"ora";var jt=["harmonyos-guides","harmonyos-references","best-practices","harmonyos-faqs","harmonyos-releases","harmonyos-roadmap"],Ft={"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 ip="deveco-cli",op="docs",ci=class{docsDir;versionFile;initialized=!1;initPromise=null;constructor(){this.docsDir=J.join(Zu(),".local","share",ip,op),this.versionFile=J.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"1.2.0-Test.1"}async getExistingVersion(){try{return(await ne.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=rp({text:"Extracting documentation\u2026",color:"cyan"}).start();try{let i=J.dirname(this.docsDir);await ne.promises.mkdir(i,{recursive:!0}),await this.cleanOldDocs(),await ne.promises.mkdir(this.docsDir,{recursive:!0}),new tp(t).extractAllTo(this.docsDir,!0),await ne.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=np(e),n=J.dirname(t),i=[J.join(n,"..","docs.zip")];for(let o of i)if(ne.existsSync(o))return o;return null}async cleanOldDocs(){try{await ne.promises.rm(this.docsDir,{recursive:!0,force:!0})}catch{}}async search(e,t){await this.ensureInitialized();let n=t?J.join(this.docsDir,Ft[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 Qu(ep,["--type","md","--json","--no-messages","-i","-e",e,t],{reject:!1});if(i.exitCode===1)return new Map;if(i.exitCode!==0)throw new Error(i.stderr?.trim()||`Search failed with exit code ${i.exitCode}`);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(`
1264
- `),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=>C.isPathContainedWithSymlink(i,this.docsDir).contained).map(i=>J.join(this.docsDir,i));for(let i of n)try{return await ne.promises.readFile(i,"utf-8")}catch{continue}throw new Error(`Document not found: ${e}`)}parseFilePath(e){if(!e.endsWith(".md"))return null;let t=J.relative(this.docsDir,e);if(!t||t.startsWith("..")||J.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 ne.promises.readFile(t,"utf-8");return JSON.parse(n)}catch{return null}}async readContentPreview(e){try{let t=await ne.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""}}},li=new ci;function oa(...r){return e=>{if(!r.includes(e))throw new di(`Allowed values: ${r.join(", ")}`);return e}}function cp(r){let e=Number(r);if(!Number.isInteger(e)||e<=0)throw new di("Must be a positive integer.");return e}var lp=oa("json","default"),dp=oa("json","default"),Zn=new sp("docs").description("Search and read HarmonyOS documentation from local docs directory");Zn.command("search <keywords...>").description("Search documentation by keywords").option("--catalog <name>","Catalog name (all : all catalogs)",up,"all").option("--format <fmt>","Output format (default, json)",lp,"default").option("--limit <n>","Max number of results",cp,20).action(async(r,e)=>{try{let t=r.map(s=>s.trim()).filter(s=>s);t.length===0&&(console.error($t("Keywords cannot be empty.")),process.exit(1)),t.length>10&&(console.error($t("Keywords cannot exceed 10.")),process.exit(1));let n=e.catalog&&e.catalog!=="all"?e.catalog:void 0,o=(await li.search(t,n)).slice(0,e.limit);e.format==="json"?console.log(JSON.stringify(o,null,2)):pp(o)}catch(t){console.error($t(t.message)),process.exit(1)}});Zn.command("read <documentId>").description("Read full content of a document by document ID").action(async r=>{try{let e=r.trim();e||(console.error($t("Document ID cannot be empty.")),process.exit(1));let t=await li.readDocument(e);console.log(t)}catch(e){console.error($t(e.message)),process.exit(1)}});Zn.command("catalog").description("List all available catalogs").option("--format <fmt>","Output format (options: default,json)",dp,"default").action(r=>{if(r.format==="json"){let e=jt.map(t=>({name:t,title:Ft[t]}));console.log(JSON.stringify(e,null,2))}else for(let e of jt)console.log(` ${e.padEnd(20)} ${ap(Ft[e])}`)});function up(r){if(r==="all")return"all";if(!jt.includes(r))throw new di(`Invalid catalog "${r}". Allowed: all, ${jt.join(", ")}`);return r}function pp(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 sa=Zn;process.env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE="";hp();B.name("devecocli").description("HarmonyOS application development command line tool").version("1.2.0-Test.1");B.addCommand(Si);B.addCommand(Ti);B.addCommand(Oi);B.addCommand(zi);B.addCommand(ho);B.addCommand(Wo);B.addCommand(zo);B.addCommand(ts);B.addCommand(ls);B.addCommand(ia);B.addCommand(sa);var ui=process.argv.slice(2);ui.length>=2&&ui[ui.length-1]==="help"&&(process.argv=[...process.argv.slice(0,-1),"--help"]);var mp=new Set(["update"]);B.hook("preAction",async(r,e)=>{if(process.env.DEVECO_CLI_SKIP_VERSION_CHECK)return;let t=e;for(;t.parent&&t.parent!==B;)t=t.parent;mp.has(t.name())||await O.checkVersion()});B.parseAsync(process.argv).catch(r=>{let e=r instanceof Error?r.message:String(r??"Unknown error");console.error(fp(`Error: ${e}`)),process.env.DEVECO_CLI_DEBUG==="1"&&r instanceof Error&&r.stack&&console.error(r.stack),process.exit(1)});
1263
+ `);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 Gu;if(await this.server.connect(e),f.info("devecocli-mcp-server started"),!this.config.debug){let t=Is();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=fe(t);n?(f.info(`Detected project path from client root: ${n}`),this.config.projectPath=n,this.sdkPath=this.computeSdkPath()):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 ct(e,this.config.devecoPath??null),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?fe(this.workspaceRoot):null;return!t&&this.originalProjectPath&&(t=fe(this.originalProjectPath),t&&f.info(`Phase 1 found HarmonyOS project from original config: ${t}`)),t?(this.config.projectPath=t,this.sdkPath=this.computeSdkPath(),this.initRetryCount=0,!0):(this.projectState=0,!1)}async doEnsureProjectReady(){if(this.discoverProject()&&(this.sdkPath||(this.sdkPath=this.computeSdkPath()),!!await this.ensureProjectSynced())){this.projectState=3,this.arktsCheckTool=new at(this.config.projectPath,this.config.devecoPath??null,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=ea(e,this.config.forceSync??!1);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 st.handleSyncProject(e,this.sdkPath);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>=ta?(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 / ${ta/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}}computeSdkPath(){let e=dn(this.config.devecoPath??""),t=ae(e);return ut.join(t,"sdk")}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"),Ds(),Cs()}getToolRouter(){return this.toolRouter}getServer(){return this.server}};function Ju(r){let e=[],t=[],n=[];for(let i of r)ut.extname(i).toLowerCase()===".ets"?e.push(i):un(i)?t.push(i):n.push(i);return{etsFiles:e,cppFiles:t,unsupported:n}}function ai(r={}){return new Xn(r)}async function Xu(){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=process.env.DEVECO_MCP_FORCE_SYNC==="1",o=await O.new(),s=r,a=e??o.devecoStudioPath,c=ai({projectPath:s,devecoPath:a,nodeMaxOldSpaceSize:t,debug:n,forceSync:i}),d=async()=>{await c.shutdown(),process.exit(0)};process.once("SIGINT",d),process.once("SIGTERM",d),process.platform==="win32"&&process.once("SIGBREAK",d);try{await c.start()}catch(u){console.error("Failed to start MCP server:",u),process.exit(1)}}var ra=new Ku("serve").description("Host bundled auxiliary protocol servers");ra.command("mcp").description("Start a local stdio-based MCP server").action(async()=>{await Xu()});var ia=ra;import{Command as sp,InvalidArgumentError as di}from"commander";import{red as $t,dim as ap}from"colorette";import*as J from"path";import*as ne from"fs";import{homedir as Zu}from"os";import{execa as Qu}from"execa";import{rgPath as ep}from"@vscode/ripgrep";import tp from"adm-zip";import{fileURLToPath as np}from"url";import rp from"ora";var jt=["harmonyos-guides","harmonyos-references","best-practices","harmonyos-faqs","harmonyos-releases","harmonyos-roadmap"],Ft={"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 ip="deveco-cli",op="docs",ci=class{docsDir;versionFile;initialized=!1;initPromise=null;constructor(){this.docsDir=J.join(Zu(),".local","share",ip,op),this.versionFile=J.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"1.2.0-Test.2"}async getExistingVersion(){try{return(await ne.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=rp({text:"Extracting documentation\u2026",color:"cyan"}).start();try{let i=J.dirname(this.docsDir);await ne.promises.mkdir(i,{recursive:!0}),await this.cleanOldDocs(),await ne.promises.mkdir(this.docsDir,{recursive:!0}),new tp(t).extractAllTo(this.docsDir,!0),await ne.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=np(e),n=J.dirname(t),i=[J.join(n,"..","docs.zip")];for(let o of i)if(ne.existsSync(o))return o;return null}async cleanOldDocs(){try{await ne.promises.rm(this.docsDir,{recursive:!0,force:!0})}catch{}}async search(e,t){await this.ensureInitialized();let n=t?J.join(this.docsDir,Ft[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 Qu(ep,["--type","md","--json","--no-messages","-i","-e",e,t],{reject:!1});if(i.exitCode===1)return new Map;if(i.exitCode!==0)throw new Error(i.stderr?.trim()||`Search failed with exit code ${i.exitCode}`);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(`
1264
+ `),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=>C.isPathContainedWithSymlink(i,this.docsDir).contained).map(i=>J.join(this.docsDir,i));for(let i of n)try{return await ne.promises.readFile(i,"utf-8")}catch{continue}throw new Error(`Document not found: ${e}`)}parseFilePath(e){if(!e.endsWith(".md"))return null;let t=J.relative(this.docsDir,e);if(!t||t.startsWith("..")||J.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 ne.promises.readFile(t,"utf-8");return JSON.parse(n)}catch{return null}}async readContentPreview(e){try{let t=await ne.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""}}},li=new ci;function oa(...r){return e=>{if(!r.includes(e))throw new di(`Allowed values: ${r.join(", ")}`);return e}}function cp(r){let e=Number(r);if(!Number.isInteger(e)||e<=0)throw new di("Must be a positive integer.");return e}var lp=oa("json","default"),dp=oa("json","default"),Zn=new sp("docs").description("Search and read HarmonyOS documentation from local docs directory");Zn.command("search <keywords...>").description("Search documentation by keywords").option("--catalog <name>","Catalog name (all : all catalogs)",up,"all").option("--format <fmt>","Output format (default, json)",lp,"default").option("--limit <n>","Max number of results",cp,20).action(async(r,e)=>{try{let t=r.map(s=>s.trim()).filter(s=>s);t.length===0&&(console.error($t("Keywords cannot be empty.")),process.exit(1)),t.length>10&&(console.error($t("Keywords cannot exceed 10.")),process.exit(1));let n=e.catalog&&e.catalog!=="all"?e.catalog:void 0,o=(await li.search(t,n)).slice(0,e.limit);e.format==="json"?console.log(JSON.stringify(o,null,2)):pp(o)}catch(t){console.error($t(t.message)),process.exit(1)}});Zn.command("read <documentId>").description("Read full content of a document by document ID").action(async r=>{try{let e=r.trim();e||(console.error($t("Document ID cannot be empty.")),process.exit(1));let t=await li.readDocument(e);console.log(t)}catch(e){console.error($t(e.message)),process.exit(1)}});Zn.command("catalog").description("List all available catalogs").option("--format <fmt>","Output format (options: default,json)",dp,"default").action(r=>{if(r.format==="json"){let e=jt.map(t=>({name:t,title:Ft[t]}));console.log(JSON.stringify(e,null,2))}else for(let e of jt)console.log(` ${e.padEnd(20)} ${ap(Ft[e])}`)});function up(r){if(r==="all")return"all";if(!jt.includes(r))throw new di(`Invalid catalog "${r}". Allowed: all, ${jt.join(", ")}`);return r}function pp(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 sa=Zn;process.env.GLOBAL_AGENT_ENVIRONMENT_VARIABLE_NAMESPACE="";hp();B.name("devecocli").description("HarmonyOS application development command line tool").version("1.2.0-Test.2");B.addCommand(Si);B.addCommand(Ti);B.addCommand(Oi);B.addCommand(zi);B.addCommand(ho);B.addCommand(Wo);B.addCommand(zo);B.addCommand(ts);B.addCommand(ls);B.addCommand(ia);B.addCommand(sa);var ui=process.argv.slice(2);ui.length>=2&&ui[ui.length-1]==="help"&&(process.argv=[...process.argv.slice(0,-1),"--help"]);var mp=new Set(["update"]);B.hook("preAction",async(r,e)=>{if(process.env.DEVECO_CLI_SKIP_VERSION_CHECK)return;let t=e;for(;t.parent&&t.parent!==B;)t=t.parent;mp.has(t.name())||await O.checkVersion()});B.parseAsync(process.argv).catch(r=>{let e=r instanceof Error?r.message:String(r??"Unknown error");console.error(fp(`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/deveco-cli",
3
- "version": "1.2.0-Test.1",
3
+ "version": "1.2.0-Test.2",
4
4
  "description": "HarmonyOS application development command line tool",
5
5
  "license": "MIT",
6
6
  "type": "module",