@microi.net/cli 5.6.1 → 5.6.3

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 (42) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +2 -2
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/README.md +2 -2
  7. package/assets/build-meta.json +7 -6
  8. package/assets/feature-matrix.json +138 -129
  9. package/cordis.patch.yml +2 -2
  10. package/package.json +1 -1
  11. package/scripts/mcp-server.js +2 -2
  12. package/scripts/microi-cli.js +34 -34
  13. package/scripts/microi-skills.meta.json +219 -219
  14. package/skills/.microi-skills-version.json +3 -3
  15. package/skills/.progressive-disclosure-manifest.json +58 -58
  16. package/skills/app-store/SKILL.md +6 -0
  17. package/skills/email-engine/SKILL.md +3 -2
  18. package/skills/job-engine/SKILL.md +10 -3
  19. package/skills/message-notification/SKILL.md +1 -0
  20. package/skills/microi-client-frontend/SKILL.md +5 -2
  21. package/skills/microi-codex/SKILL.md +57 -48
  22. package/skills/microi-codex-installer/SKILL.md +12 -3
  23. package/skills/microi-deployment/SKILL.md +2 -0
  24. package/skills/microi-form-engine/SKILL.md +2 -0
  25. package/skills/microi.v8.js +1 -1
  26. package/skills/playwright-e2e/SKILL.md +8 -8
  27. package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +3 -3
  28. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +2 -2
  29. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +3 -3
  30. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +3 -3
  31. package/skills/system-observability/SKILL.md +62 -8
  32. package/skills/v8-explorer-tree/SKILL.md +228 -226
  33. package/skills/v8-file-upload/SKILL.md +18 -1
  34. package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +1 -1
  35. package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +3 -3
  36. package/skills/v8-sql-query/SKILL.md +141 -133
  37. package/skills/v8-tcp-integration/SKILL.md +2 -2
  38. package/skills/v8-workflow/SKILL.md +12 -4
  39. package/skills/workspace-conventions/SKILL.md +8 -6
  40. package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +6 -6
  41. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +21 -21
  42. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +1 -1
@@ -564,7 +564,7 @@ ${JSON.stringify(g.Data,null,2)}`}]}}catch(g){return{content:[{type:"text",text:
564
564
  `)}]}}catch(c){return{content:[{type:"text",text:`Error: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_save_event_code",`Save (update) form/table V8 event code on Microi server (OsClient: ${r}). This is the MCP tool for submitting \u8868\u5355V8\u4E8B\u4EF6 code. Increments semantic Version in the code header and keeps only the complete function description in code; change history is not written into event source code. Transport timeouts are automatically verified by remote readback. Do not switch to Diy_Table/FormEngine direct writes or SQL after a timeout.`,{formEngineKey:d.string().describe("The table name or FormEngine key the event belongs to"),eventType:d.string().describe("Event type: InFormV8 | SubmitFormV8 | OutFormV8 | SubmitBeforeServerV8 | SubmitAfterServerV8 | DataFilterV8"),code:d.string().describe("The complete JavaScript source code to save"),functionDescription:d.string().optional().describe("Complete function description to keep in the code header. No change history here."),changeSummary:d.string().optional().describe("One-line change summary for audit/future compatible storage.")},async({formEngineKey:a,eventType:s,code:c,functionDescription:l,changeSummary:u})=>{try{let p=await t.saveEventCode(a,s,c,{functionDescription:l,changeSummary:u});return p.Code!==1?{content:[{type:"text",text:`Error: ${p.Msg}`}],isError:!0}:{content:[{type:"text",text:`\u2705 Event "${a}/${s}" code saved successfully.
565
565
 
566
566
  ${JSON.stringify(p.Data||{},null,2)}`}]}}catch(p){return{content:[{type:"text",text:`Error: ${p instanceof Error?p.message:String(p)}`}],isError:!0}}}),i.tool("microi_list_workflow_v8_events",`List workflow node V8 events from WF_Node for OsClient ${r}. WF_Line is returned only in the workflow package snapshot; executable route condition code is WF_Node.LineValueV8.`,{flowDesignId:d.string().optional().describe("Optional WF_FlowDesign.Id to limit results to one workflow")},async({flowDesignId:a})=>{try{let s=await t.getWorkflowV8EventList(a);return s.Code!==1?{content:[{type:"text",text:`Error: ${s.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(s.Data,null,2)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}),i.tool("microi_get_workflow_v8_code",`Get workflow node V8 JavaScript code from WF_Node by nodeId and event type (OsClient: ${r}).`,{nodeId:d.string().describe("WF_Node.Id"),eventType:d.string().describe("WF_Node V8 field: StartV8 | EndV8 | StartV8Server | EndV8Server | LineValueV8 | AllowAddUserV8Code"),flowDesignId:d.string().optional().describe("Optional WF_FlowDesign.Id used as a safety check")},async({nodeId:a,eventType:s,flowDesignId:c})=>{try{let l=await t.getWorkflowV8EventCode(a,s,c);if(l.Code!==1)return{content:[{type:"text",text:`Error: ${l.Msg}`}],isError:!0};let u=l.Data,p=Nt(u,"V8Code","Code");return{content:[{type:"text",text:[`## Workflow V8: ${u?.FlowName||u?.FlowDesignId||c||""} / ${u?.NodeName||a} / ${s}`,u?.EventName?`- **Name**: ${u.EventName}`:"",u?.FlowDesignId?`- **FlowDesignId**: ${u.FlowDesignId}`:"",u?.NodeId?`- **NodeId**: ${u.NodeId}`:"","","```javascript",p||"// No code available","```"].filter(Boolean).join(`
567
- `)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_save_workflow_v8_code",`Save workflow node V8 code into WF_Node for OsClient ${r}. Empty code clears the field without adding a generated header.`,{nodeId:d.string().describe("WF_Node.Id"),eventType:d.string().describe("WF_Node V8 field: StartV8 | EndV8 | StartV8Server | EndV8Server | LineValueV8 | AllowAddUserV8Code"),code:d.string().describe("The complete JavaScript source code to save; pass empty string to clear"),flowDesignId:d.string().optional().describe("Optional WF_FlowDesign.Id used as a safety check"),functionDescription:d.string().optional().describe("Complete function description to keep in the code header. No change history here."),changeSummary:d.string().optional().describe("One-line change summary for audit/future compatible storage.")},async({nodeId:a,eventType:s,code:c,flowDesignId:l,functionDescription:u,changeSummary:p})=>{try{let f=await t.saveWorkflowV8EventCode(a,s,c,{flowDesignId:l,functionDescription:u,changeSummary:p});return f.Code!==1?{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0}:{content:[{type:"text",text:`\u2705 Workflow node V8 "${a}/${s}" saved successfully.`}]}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),i.tool("microi_query_system_observability",`Query the complete Microi \u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7 surface for OsClient ${r}. Start with action=Capabilities. For memory exhaustion/OOM/abnormal allocations: Memory checks current-node pressure, Collector freshness/loss and Evidence storage health; MemoryIncidents returns up to 50 tenant-scoped incident summaries in Data.Items; MemoryIncident reads detail by incidentId from that list. Correlate execution/parent ids, API engine key, V8 table/event/workflow identity, script hash, allocation types/CLR stacks and Trace. Report missing stacks, lost/unattributed samples and storage gaps before assigning a cause. Allocated bytes are NOT retained heap or exclusive RSS; never sum inclusive parent and child allocations. These read actions do not enable V8 limits, create heap dumps, kill processes or write business data. They require a compatible API diagnostic runtime as well as the query engine; updating MCP alone cannot install the backend. Other read actions cover logs/statistics/details, signals, Trace, hot API rank, host/Docker/queues, application logs, security, platform statistics and traffic history. The backend enforces administrator permission, tenant isolation, bounded pagination and redaction. Runtime metrics are current-node only; HTTP-attributed bytes do not equal total NIC/container traffic.`,{action:d.enum(["Capabilities","Snapshot","Logs","LogTypes","LogStats","Signal","Trace","ApiRank","AppLogs","PlatformStats","SecurityData","TrafficHistory","TrafficDetails","HistoricalDashboard","Memory","MemoryIncidents","MemoryIncident","DatabasePools","DatabasePoolRecovery"]).describe("Read action. Use Capabilities first to discover exact scope and boundaries."),keyword:d.string().max(100).optional().describe("Log/signal/security keyword. The backend applies its own bounded search rules."),type:d.string().max(100).optional().describe("System log Type filter."),category:d.string().max(100).optional().describe("System log Category filter."),source:d.string().max(100).optional().describe("System log Source filter."),level:d.number().int().min(0).max(10).optional().describe("Exact log level for Logs."),levelMin:d.number().int().min(0).max(10).optional().describe("Minimum log level for Signal."),searchMonth:d.string().regex(/^\d{6}$/u).optional().describe("Log/Trace month in yyyyMM."),pageIndex:d.number().int().min(1).max(1e5).optional().describe("Page index, default 1."),pageSize:d.number().int().min(1).max(500).optional().describe("Page size. Logs/SecurityData max 200; Trace/TrafficHistory max 500."),windowMinutes:d.number().int().min(1).max(15).optional().describe("Snapshot request window, 1-15 minutes."),windowSeconds:d.number().int().min(60).max(86400).optional().describe("Signal window, 60-86400 seconds."),top:d.number().int().min(1).max(100).optional().describe("Top N for Snapshot or ApiRank. Snapshot backend clamps to 5-50."),includeHost:d.boolean().optional().describe("Snapshot includes host/runtime overview. Default true."),includeDocker:d.boolean().optional().describe("Snapshot includes heavier Docker sampling. Default false."),traceId:d.string().regex(/^[0-9a-fA-F]{32}$/u).optional().describe("W3C 32-hex TraceId for Trace."),incidentId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("Required for MemoryIncident: use an actual 32-lowercase-hex Id from MemoryIncidents Data.Items. Empty Items means not found in the visible tenant/storage scope, not proof of no incident."),serviceName:d.string().max(100).optional().describe("Signal service-name filter."),apiEngineKey:d.string().max(100).optional().describe("ApiRank engine-key filter."),name:d.string().max(100).optional().describe("ApiRank endpoint/name filter."),lines:d.number().int().min(20).max(1e3).optional().describe("AppLogs tail lines, 20-1000."),kind:d.enum(["Access","Attack","Block"]).optional().describe("SecurityData kind."),status:d.string().max(50).optional().describe("SecurityData Block status filter."),dimensionType:d.enum(["Total","Endpoint","Ip","User","Tenant","ContentType"]).optional().describe("TrafficHistory aggregation dimension."),rangeKey:d.enum(["live5","today","yesterday","3d","7d","15d","30d","3m","6m","1y"]).optional().describe("Unified history range for TrafficHistory/HistoricalDashboard. Default today."),hours:d.number().int().min(1).max(168).optional().describe("Legacy TrafficHistory lookback hours. Prefer rangeKey."),observedOsClient:d.string().max(50).optional().describe("TrafficHistory observed tenant filter; caller still remains bound to the authenticated control plane."),transferAction:d.string().max(50).optional().describe("TrafficDetails direction/action filter, for example \u4E0A\u4F20\u3001\u4E0B\u8F7D or SuspiciousTransfer."),ip:d.string().max(100).optional().describe("TrafficDetails client IP filter."),userId:d.string().max(100).optional().describe("TrafficDetails authenticated user-id filter."),endpoint:d.string().max(500).optional().describe("TrafficDetails normalized endpoint or /apiengine/{key} filter."),poolTarget:d.enum(["Both","Write","Read"]).optional().describe("DatabasePools: \u5F53\u524D\u79DF\u6237\u4E3B/\u8BFB\u6C60\uFF0C\u9ED8\u8BA4 Both\uFF1B\u72EC\u7ACB\u5E94\u6025\u9274\u6743\uFF0C\u4E0D\u4F9D\u8D56\u4E1A\u52A1\u6C60\u3002\u9700\u8981\u652F\u6301 database-pools/v1 \u7684 API\u3002"),operationId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("DatabasePoolRecovery: \u6062\u590D\u64CD\u4F5C\u7F16\u53F7\uFF0C\u56DE\u8BFB\u5404\u8282\u70B9\u72B6\u6001\uFF1BPending/Incomplete \u4E0D\u4EE3\u8868\u5DF2\u6062\u590D\u3002")},async({action:a,keyword:s,type:c,category:l,source:u,level:p,levelMin:f,searchMonth:h,pageIndex:m,pageSize:g,windowMinutes:y,windowSeconds:v,top:x,includeHost:b,includeDocker:w,traceId:E,incidentId:S,serviceName:k,apiEngineKey:A,name:R,lines:I,kind:C,status:j,dimensionType:F,rangeKey:V,hours:J,observedOsClient:X,transferAction:Ae,ip:ke,userId:le,endpoint:Mt,poolTarget:tt,operationId:Wt})=>{try{if(a==="DatabasePoolRecovery"&&!Wt)return{content:[{type:"text",text:"\u8FDE\u63A5\u6C60\u6062\u590D\u56DE\u8BFB\u5FC5\u987B\u4F20\u5165\u539F operationId\uFF1B\u8BF7\u6C42\u8D85\u65F6\u4E0D\u80FD\u6362\u7F16\u53F7\u91CD\u8BD5\u3002"}],isError:!0};if(a==="Trace"&&!E)return{content:[{type:"text",text:"Trace \u67E5\u8BE2\u5FC5\u987B\u4F20\u5165 32 \u4F4D\u5341\u516D\u8FDB\u5236 traceId\u3002"}],isError:!0};if(a==="MemoryIncident"&&!S)return{content:[{type:"text",text:"\u8BF7\u5148\u67E5\u8BE2 MemoryIncidents\uFF0C\u5E76\u4F20\u5165 incidentId\u3002"}],isError:!0};let Dt=await t.querySystemObservability({Action:a,...tt?{Target:tt}:{},...Wt?{OperationId:Wt}:{},...s?{Keyword:s,_Keyword:s}:{},...c?{Type:c}:{},...l?{Category:l}:{},...u?{Source:u}:{},...p===void 0?{}:{Level:p},...f===void 0?{}:{LevelMin:f},...h?{SearchMonth:h,_SearchMonth:h}:{},...m===void 0?{}:{PageIndex:m,_PageIndex:m},...g===void 0?{}:{PageSize:g,_PageSize:g},...y===void 0?{}:{WindowMinutes:y},...v===void 0?{}:{WindowSeconds:v},...x===void 0?{}:{Top:x},...b===void 0?{}:{IncludeHost:b},...w===void 0?{}:{IncludeDocker:w},...E?{TraceId:E.toLowerCase()}:{},...S?{IncidentId:S}:{},...k?{ServiceName:k}:{},...A?{ApiEngineKey:A}:{},...R?{Name:R}:{},...I===void 0?{}:{Lines:I},...C?{Kind:C}:{},...j?{Status:j}:{},...F?{DimensionType:F}:{},...V?{RangeKey:V}:{},...J===void 0?{}:{Hours:J},...X?{ObservedOsClient:X}:{},...Ae?{TransferAction:Ae}:{},...ke?{Ip:ke}:{},...le?{UserId:le}:{},...Mt?{Endpoint:Mt}:{}});return{content:[{type:"text",text:JSON.stringify({Code:Dt.Code,Msg:Dt.Msg||"",Data:Dt.Data,DataCount:Dt.DataCount,DataAppend:Dt.DataAppend},null,2)}],...Dt.Code===1?{}:{isError:!0}}}catch(Dt){return{content:[{type:"text",text:`Error: ${Dt instanceof Error?Dt.message:String(Dt)}`}],isError:!0}}}),i.tool("microi_manage_system_observability",`Manage Microi \u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7 for OsClient ${r}. BlockIp/UnblockIp manage IP blocks. ResetDatabasePools \u5728\u7EBF\u8F6E\u6362\u5F53\u524D\u79DF\u6237 MySQL/SQL Server \u4E3B/\u8BFB\u8FDE\u63A5\u6C60\uFF0C\u65E0\u9700\u91CD\u542F\u6570\u636E\u5E93/API\u3002\u5148\u8C03\u7528\u65E0 confirmExecution \u7684\u9884\u89C8\uFF0C\u4F7F\u7528\u8FD4\u56DE\u7684 operationId\u3001poolIds\u3001poolTarget \u548C requiredConfirmation \u6267\u884C\uFF0C\u518D\u901A\u8FC7\u67E5\u8BE2\u5DE5\u5177 action=DatabasePoolRecovery \u56DE\u8BFB\u5404\u8282\u70B9\uFF1B\u8D85\u65F6\u6CBF\u7528\u539F\u7F16\u53F7\u3002\u5E94\u6025\u5165\u53E3\u4ECD\u590D\u6838 DiyToken\u3001\u4E3B\u5E93\u7BA1\u7406\u5458\u53CA mcp:admin\uFF0C\u8981\u6C42\u517C\u5BB9 database-pools/v1 \u7684 API\uFF0CMCP \u66F4\u65B0\u4E0D\u80FD\u5B89\u88C5\u540E\u7AEF\u3002\u5171\u4EAB\u6C60/\u6269\u5C55\u5E93/\u4E0D\u652F\u6301\u9A71\u52A8\u4E0D\u6E05\u7406\u3002\u53EA\u8F6E\u6362\u6307\u5B9A\u6C60\u5E76\u63A2\u6D4B SELECT 1\uFF0C\u4E0D\u6740\u4E8B\u52A1\u3001\u4E0D\u91CD\u653E SQL\u3001\u4E0D\u4FDD\u8BC1\u4FEE\u590D\u6301\u7EED\u6CC4\u6F0F/\u5BB9\u91CF/\u7F51\u7EDC\u6545\u969C\u3002\u968F\u540E\u9A8C\u8BC1\u539F\u6545\u969C\u4E1A\u52A1\u63A5\u53E3\u3002`,{action:d.enum(["BlockIp","UnblockIp","ResetDatabasePools"]).describe("IP \u6CBB\u7406\u6216\u5728\u7EBF\u8FDE\u63A5\u6C60\u6062\u590D\u3002"),ip:d.string().min(3).max(64).optional().describe("IP \u64CD\u4F5C\u5FC5\u586B\uFF0CIPv4/IPv6\uFF1B\u8FDE\u63A5\u6C60\u64CD\u4F5C\u4E0D\u4F20\u3002"),poolTarget:d.enum(["Both","Write","Read"]).optional().describe("\u5F53\u524D\u79DF\u6237\u4E3B/\u8BFB\u6C60\uFF0C\u9ED8\u8BA4 Both\u3002\u4F7F\u7528\u9884\u89C8\u4E2D\u7684 Target\u3002"),operationId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("\u4F7F\u7528\u9884\u89C8\u8FD4\u56DE\u7684 OperationId\uFF0C\u6240\u6709\u91CD\u8BD5\u4FDD\u6301\u76F8\u540C\u7F16\u53F7\u3002"),poolIds:d.array(d.string().regex(/^[0-9a-f]{64}$/u)).min(1).max(2).optional().describe("\u9884\u89C8\u8FD4\u56DE\u7684 PoolIds \u539F\u6570\u7EC4\uFF1B\u914D\u7F6E\u53D8\u5316\u65F6\u540E\u7AEF\u62D2\u7EDD\u6267\u884C\u3002"),blockMinutes:d.number().int().min(1).max(10080).optional().describe("Block duration in minutes, 1-10080. Default 30 for BlockIp."),reason:d.string().max(300).optional().describe("Bounded operator reason. Do not include tokens, passwords or request bodies."),confirmExecution:d.string().optional().describe("\u9884\u89C8\u8FD4\u56DE\u7684\u7CBE\u786E\u786E\u8BA4\u503C\uFF1ABlockIp:<ip>\u3001UnblockIp:<ip> \u6216 ResetDatabasePools:<operationId>\u3002")},async({action:a,ip:s,blockMinutes:c,reason:l,confirmExecution:u,poolTarget:p,operationId:f,poolIds:h})=>{try{if(a==="ResetDatabasePools"){if(!u){let x=await t.querySystemObservability({Action:"DatabasePools",Target:p||"Both"}),b=x.Data;return{content:[{type:"text",text:JSON.stringify({...x,dryRun:!0,requiredConfirmation:b?.OperationId?`ResetDatabasePools:${b.OperationId}`:void 0},null,2)}],...x.Code===1?{}:{isError:!0}}}if(!f||!h||u!==`ResetDatabasePools:${f}`)return{content:[{type:"text",text:"\u5FC5\u987B\u4F7F\u7528\u540C\u4E00\u6B21\u9884\u89C8\u7684 operationId\u3001poolIds \u548C requiredConfirmation\u3002"}],isError:!0};let v=await t.manageSystemObservability({Action:a,Target:p||"Both",OperationId:f,PoolIds:h,Confirm:u});return{content:[{type:"text",text:JSON.stringify(v,null,2)}],...v.Code===1?{}:{isError:!0}}}let m=(s||"").trim();if((0,b2.isIP)(m)===0)return{content:[{type:"text",text:"IP \u5730\u5740\u683C\u5F0F\u65E0\u6548\u3002"}],isError:!0};let g=`${a}:${m}`;if(u!==g)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,action:a,ip:m,blockMinutes:a==="BlockIp"?c||30:void 0,reason:a==="BlockIp"?l||"\u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7\u4E2D\u7531\u7BA1\u7406\u5458\u624B\u52A8\u5C01\u7981\u3002":void 0,requiredConfirmation:g,warning:"\u786E\u8BA4\u540E\u4F1A\u4FEE\u6539\u5F53\u524D\u79DF\u6237\u7684 IP \u5C01\u9501\u72B6\u6001\uFF0C\u5E76\u5199\u5165\u5E73\u53F0\u5BA1\u8BA1\u65E5\u5FD7\u3002"},null,2)}]};await t.writeAuditLog("microi_manage_system_observability",m,JSON.stringify({action:a,blockMinutes:a==="BlockIp"?c||30:void 0}));let y=await t.manageSystemObservability({Action:a,Ip:m,...a==="BlockIp"?{BlockMinutes:c||30,Reason:l||""}:{}});return{content:[{type:"text",text:JSON.stringify({Code:y.Code,Msg:y.Msg||"",Data:y.Data},null,2)}],...y.Code===1?{}:{isError:!0}}}catch(m){return{content:[{type:"text",text:`Error: ${m instanceof Error?m.message:String(m)}`}],isError:!0}}}),i.tool("microi_query_mongodb_logs",`Query Microi MongoDB system logs (sys_log_<osClient>/log_yyyyMM) for OsClient ${r}. Use this after automated tests to inspect V8 errors, slow logs, workflow logs and platform guard logs.`,{keyword:d.string().optional().describe("Keyword searched in log Title and Content"),type:d.string().optional().describe("Log Type, for example MCP, \u8868\u5355V8\u6162\u65E5\u5FD7, \u8868\u5355V8\u9012\u5F52\u4FDD\u62A4, \u5DE5\u4F5C\u6D41\u5408\u5E76\u63D0\u4EA4\u6162\u65E5\u5FD7"),level:d.number().optional().describe("Log level. Common values: 1 info, 2 warning, 3 error"),searchMonth:d.string().optional().describe("Month in yyyyMM. Defaults to current month on server"),pageIndex:d.number().optional().describe("Page index, default 1"),pageSize:d.number().optional().describe("Page size, default 20, backend max 200")},async({keyword:a,type:s,level:c,searchMonth:l,pageIndex:u,pageSize:p})=>{try{let f=await t.queryMongodbLogs({keyword:a,type:s,level:c,searchMonth:l,pageIndex:u,pageSize:p});return f.Code!==1?{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(f.Data,null,2)}]}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),i.tool("microi_write_mongodb_log",`Write a Microi MongoDB system log for OsClient ${r}. Useful for AI automated test milestones, reproduction markers, and repair verification notes.`,{title:d.string().describe("Log title"),content:d.string().describe("Log content"),type:d.string().optional().describe("Log Type, default MCP"),level:d.number().optional().describe("Log level, default 1"),api:d.string().optional().describe("Related API/tool name"),param:d.string().optional().describe("Input or context summary. Avoid secrets."),remark:d.string().optional().describe("Short remark or target identifier"),otherInfo:d.string().optional().describe("Additional diagnostic info. Avoid secrets."),timer:d.number().optional().describe("Elapsed milliseconds, if applicable"),result:d.string().optional().describe("Result summary"),appId:d.string().optional().describe("AppId, default microi.mcp")},async({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:h,timer:m,result:g,appId:y})=>{try{let v=await t.writeMongodbLog({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:h,timer:m,result:g,appId:y});return v.Code!==1?{content:[{type:"text",text:`Error: ${v.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(v.Data||{ok:!0},null,2)}]}}catch(v){return{content:[{type:"text",text:`Error: ${v instanceof Error?v.message:String(v)}`}],isError:!0}}}),i.tool("microi_create_table",`Create or reconcile a custom table for OsClient "${r}". Inserts a record into diy_table. IDEMPOTENT \u2014 calling again with the same name reuses the existing TableId; an explicitly supplied v8Limit value is reconciled and read back by system validation. This is step 2 of system design. After adding fields, call microi_configure_form_banner so the default-visible Banner receives useful field-aware configuration.`,{name:d.string().describe('Table name in English (e.g. "Crm_Customer", "Order_Main"). Convention: Module_Entity format. Will be a real MySQL table.'),description:d.string().optional().describe('Chinese description of the table (e.g. "\u5BA2\u6237\u4FE1\u606F", "\u8BA2\u5355\u4E3B\u8868")'),tabs:d.string().optional().describe(`Form tab layout JSON (e.g. '[{"Id":"basic","Name":"\u57FA\u672C\u4FE1\u606F","Sort":10},{"Id":"business","Name":"\u4E1A\u52A1\u4FE1\u606F","Sort":20}]'). Groups fields into diy_table.Tabs. When using microi_generate_system, many-field tables can be auto-tabbed.`),isTree:d.number().optional().describe("Enable tree structure (1=tree table with ParentId self-referencing, 0=flat). Default: 0"),readPrimary:d.union([d.literal(0),d.literal(1)]).nullable().optional().describe("Trusted table configuration: 1 uses its database writer for native rows/count/sum/tree/export. null/0 uses the existing default; omit preserves existing configuration. Does not change explicit transaction isolation."),column:d.number().optional().describe("Number of form columns (1, 2, or 3). Controls form layout. Default: 2 (\u53CC\u5217\uFF0C\u66F4\u7D27\u51D1\u73B0\u4EE3)"),formOpenType:d.string().optional().describe('How to open form: "Dialog" (\u5F39\u7A97), "Drawer" (\u62BD\u5C49), "Page" (\u65B0\u9875\u9762). Default: Dialog'),formOpenWidth:d.string().optional().describe('Form dialog/drawer width (e.g. "800px", "80%"). Default: 80%'),v8Limit:d.boolean().optional().describe("Default false for new tables; omit to preserve an existing table. true enables Jint per-execution timeout, statement, recursion and allocation budgets for this table's backend V8 events."),v8Unlimited:d.boolean().optional().describe("Deprecated compatibility alias. Prefer v8Limit; true is equivalent to v8Limit=false.")},async({name:a,description:s,tabs:c,isTree:l,readPrimary:u,column:p,formOpenType:f,formOpenWidth:h,v8Limit:m,v8Unlimited:g})=>{try{let y=m??(g===void 0?void 0:!g),v=await t.createTable(a,s,{Tabs:c,IsTree:l,ReadPrimary:u,Column:p??2,FormOpenType:f||"Dialog",FormOpenWidth:h||"80%",V8Limit:y===void 0?void 0:y?1:0});if(v.Code!==1)return{content:[{type:"text",text:`Error: ${v.Msg}`}],isError:!0};let x=v.Data;return{content:[{type:"text",text:`\u2705 Table "${a}" created.
567
+ `)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_save_workflow_v8_code",`Save workflow node V8 code into WF_Node for OsClient ${r}. Empty code clears the field without adding a generated header.`,{nodeId:d.string().describe("WF_Node.Id"),eventType:d.string().describe("WF_Node V8 field: StartV8 | EndV8 | StartV8Server | EndV8Server | LineValueV8 | AllowAddUserV8Code"),code:d.string().describe("The complete JavaScript source code to save; pass empty string to clear"),flowDesignId:d.string().optional().describe("Optional WF_FlowDesign.Id used as a safety check"),functionDescription:d.string().optional().describe("Complete function description to keep in the code header. No change history here."),changeSummary:d.string().optional().describe("One-line change summary for audit/future compatible storage.")},async({nodeId:a,eventType:s,code:c,flowDesignId:l,functionDescription:u,changeSummary:p})=>{try{let f=await t.saveWorkflowV8EventCode(a,s,c,{flowDesignId:l,functionDescription:u,changeSummary:p});return f.Code!==1?{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0}:{content:[{type:"text",text:`\u2705 Workflow node V8 "${a}/${s}" saved successfully.`}]}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),i.tool("microi_query_system_observability",`Query the complete Microi \u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7 surface for OsClient ${r}. Start with action=Capabilities. For memory exhaustion/OOM/abnormal allocations: Memory checks current-node pressure, Collector freshness/loss and Evidence storage health; MemoryIncidents returns up to 50 tenant-scoped incident summaries in Data.Items; MemoryIncident reads detail by incidentId from that list. Correlate execution/parent ids, API engine key, V8 table/event/workflow identity, script hash, allocation types/CLR stacks and Trace. Report missing stacks, lost/unattributed samples and storage gaps before assigning a cause. Allocated bytes are NOT retained heap or exclusive RSS; never sum inclusive parent and child allocations. These read actions do not enable V8 limits, create heap dumps, kill processes or write business data. They require a compatible API diagnostic runtime as well as the query engine; updating MCP alone cannot install the backend. Other read actions cover logs/statistics/details, signals, Trace, hot API rank, host/Docker/queues, application logs, security, platform statistics and traffic history. The backend enforces administrator permission, tenant isolation, bounded pagination and redaction. Runtime metrics are current-node only; HTTP-attributed bytes do not equal total NIC/container traffic.`,{action:d.enum(["Capabilities","Snapshot","Logs","LogTypes","LogStats","Signal","Trace","ApiRank","AppLogs","PlatformStats","SecurityData","TrafficHistory","TrafficDetails","HistoricalDashboard","Memory","MemoryIncidents","MemoryIncident","DatabasePools","DatabasePoolRecovery"]).describe("Read action. Use Capabilities first to discover exact scope and boundaries."),keyword:d.string().max(100).optional().describe("Log/signal/security keyword. The backend applies its own bounded search rules."),type:d.string().max(100).optional().describe("System log Type filter."),category:d.string().max(100).optional().describe("System log Category filter."),source:d.string().max(100).optional().describe("System log Source filter."),level:d.number().int().min(0).max(10).optional().describe("Exact log level for Logs."),levelMin:d.number().int().min(0).max(10).optional().describe("Minimum log level for Signal."),searchMonth:d.string().regex(/^\d{6}$/u).optional().describe("Log/Trace month in yyyyMM."),pageIndex:d.number().int().min(1).max(1e5).optional().describe("Page index, default 1."),pageSize:d.number().int().min(1).max(500).optional().describe("Page size. Logs/SecurityData max 200; Trace/TrafficHistory max 500."),windowMinutes:d.number().int().min(1).max(15).optional().describe("Snapshot request window, 1-15 minutes."),windowSeconds:d.number().int().min(60).max(86400).optional().describe("Signal window, 60-86400 seconds."),top:d.number().int().min(1).max(100).optional().describe("Top N for Snapshot or ApiRank. Snapshot backend clamps to 5-50."),includeHost:d.boolean().optional().describe("Snapshot includes host/runtime overview. Default true. Host.Processes (process-resources/v1) provides 5-second CPU/RSS/Swap/I/O top lists and 12 recent samples; inspect Fresh, Scope, HostProcessesVisible and unavailable counts. CPU 100% means one core. A container PID view is not all NAS processes; host visibility needs a deployment-provided read-only /proc:/host/proc:ro mount. Host.DiskIO.Devices includes numeric device names, IOPS/busy/await; aggregate physical disks only. Requires compatible backend; unavailable metrics remain null."),includeDocker:d.boolean().optional().describe("Snapshot includes heavier Docker sampling. Default false."),traceId:d.string().regex(/^[0-9a-fA-F]{32}$/u).optional().describe("W3C 32-hex TraceId for Trace."),incidentId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("Required for MemoryIncident: use an actual 32-lowercase-hex Id from MemoryIncidents Data.Items. Empty Items means not found in the visible tenant/storage scope, not proof of no incident."),serviceName:d.string().max(100).optional().describe("Signal service-name filter."),apiEngineKey:d.string().max(100).optional().describe("ApiRank engine-key filter."),name:d.string().max(100).optional().describe("ApiRank endpoint/name filter."),lines:d.number().int().min(20).max(1e3).optional().describe("AppLogs tail lines, 20-1000."),kind:d.enum(["Access","Attack","Block"]).optional().describe("SecurityData kind."),status:d.string().max(50).optional().describe("SecurityData Block status filter."),dimensionType:d.enum(["Total","Endpoint","Ip","User","Tenant","ContentType"]).optional().describe("TrafficHistory aggregation dimension."),rangeKey:d.enum(["live5","today","yesterday","3d","7d","15d","30d","3m","6m","1y"]).optional().describe("Unified history range for TrafficHistory/HistoricalDashboard. Default today."),hours:d.number().int().min(1).max(168).optional().describe("Legacy TrafficHistory lookback hours. Prefer rangeKey."),observedOsClient:d.string().max(50).optional().describe("TrafficHistory observed tenant filter; caller still remains bound to the authenticated control plane."),transferAction:d.string().max(50).optional().describe("TrafficDetails direction/action filter, for example \u4E0A\u4F20\u3001\u4E0B\u8F7D or SuspiciousTransfer."),ip:d.string().max(100).optional().describe("TrafficDetails client IP filter."),userId:d.string().max(100).optional().describe("TrafficDetails authenticated user-id filter."),endpoint:d.string().max(500).optional().describe("TrafficDetails normalized endpoint or /apiengine/{key} filter."),poolTarget:d.enum(["Both","Write","Read"]).optional().describe("DatabasePools: \u5F53\u524D\u79DF\u6237\u4E3B/\u8BFB\u6C60\uFF0C\u9ED8\u8BA4 Both\uFF1B\u72EC\u7ACB\u5E94\u6025\u9274\u6743\uFF0C\u4E0D\u4F9D\u8D56\u4E1A\u52A1\u6C60\u3002\u9700\u8981\u652F\u6301 database-pools/v1 \u7684 API\u3002"),operationId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("DatabasePoolRecovery: \u6062\u590D\u64CD\u4F5C\u7F16\u53F7\uFF0C\u56DE\u8BFB\u5404\u8282\u70B9\u72B6\u6001\uFF1BPending/Incomplete \u4E0D\u4EE3\u8868\u5DF2\u6062\u590D\u3002")},async({action:a,keyword:s,type:c,category:l,source:u,level:p,levelMin:f,searchMonth:h,pageIndex:m,pageSize:g,windowMinutes:y,windowSeconds:v,top:x,includeHost:b,includeDocker:w,traceId:E,incidentId:S,serviceName:k,apiEngineKey:A,name:R,lines:I,kind:C,status:j,dimensionType:F,rangeKey:V,hours:J,observedOsClient:X,transferAction:Ae,ip:ke,userId:le,endpoint:Mt,poolTarget:tt,operationId:Wt})=>{try{if(a==="DatabasePoolRecovery"&&!Wt)return{content:[{type:"text",text:"\u8FDE\u63A5\u6C60\u6062\u590D\u56DE\u8BFB\u5FC5\u987B\u4F20\u5165\u539F operationId\uFF1B\u8BF7\u6C42\u8D85\u65F6\u4E0D\u80FD\u6362\u7F16\u53F7\u91CD\u8BD5\u3002"}],isError:!0};if(a==="Trace"&&!E)return{content:[{type:"text",text:"Trace \u67E5\u8BE2\u5FC5\u987B\u4F20\u5165 32 \u4F4D\u5341\u516D\u8FDB\u5236 traceId\u3002"}],isError:!0};if(a==="MemoryIncident"&&!S)return{content:[{type:"text",text:"\u8BF7\u5148\u67E5\u8BE2 MemoryIncidents\uFF0C\u5E76\u4F20\u5165 incidentId\u3002"}],isError:!0};let Dt=await t.querySystemObservability({Action:a,...tt?{Target:tt}:{},...Wt?{OperationId:Wt}:{},...s?{Keyword:s,_Keyword:s}:{},...c?{Type:c}:{},...l?{Category:l}:{},...u?{Source:u}:{},...p===void 0?{}:{Level:p},...f===void 0?{}:{LevelMin:f},...h?{SearchMonth:h,_SearchMonth:h}:{},...m===void 0?{}:{PageIndex:m,_PageIndex:m},...g===void 0?{}:{PageSize:g,_PageSize:g},...y===void 0?{}:{WindowMinutes:y},...v===void 0?{}:{WindowSeconds:v},...x===void 0?{}:{Top:x},...b===void 0?{}:{IncludeHost:b},...w===void 0?{}:{IncludeDocker:w},...E?{TraceId:E.toLowerCase()}:{},...S?{IncidentId:S}:{},...k?{ServiceName:k}:{},...A?{ApiEngineKey:A}:{},...R?{Name:R}:{},...I===void 0?{}:{Lines:I},...C?{Kind:C}:{},...j?{Status:j}:{},...F?{DimensionType:F}:{},...V?{RangeKey:V}:{},...J===void 0?{}:{Hours:J},...X?{ObservedOsClient:X}:{},...Ae?{TransferAction:Ae}:{},...ke?{Ip:ke}:{},...le?{UserId:le}:{},...Mt?{Endpoint:Mt}:{}});return{content:[{type:"text",text:JSON.stringify({Code:Dt.Code,Msg:Dt.Msg||"",Data:Dt.Data,DataCount:Dt.DataCount,DataAppend:Dt.DataAppend},null,2)}],...Dt.Code===1?{}:{isError:!0}}}catch(Dt){return{content:[{type:"text",text:`Error: ${Dt instanceof Error?Dt.message:String(Dt)}`}],isError:!0}}}),i.tool("microi_manage_system_observability",`Manage Microi \u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7 for OsClient ${r}. BlockIp/UnblockIp manage IP blocks. ResetDatabasePools \u5728\u7EBF\u8F6E\u6362\u5F53\u524D\u79DF\u6237 MySQL/SQL Server \u4E3B/\u8BFB\u8FDE\u63A5\u6C60\uFF0C\u65E0\u9700\u91CD\u542F\u6570\u636E\u5E93/API\u3002\u5148\u8C03\u7528\u65E0 confirmExecution \u7684\u9884\u89C8\uFF0C\u4F7F\u7528\u8FD4\u56DE\u7684 operationId\u3001poolIds\u3001poolTarget \u548C requiredConfirmation \u6267\u884C\uFF0C\u518D\u901A\u8FC7\u67E5\u8BE2\u5DE5\u5177 action=DatabasePoolRecovery \u56DE\u8BFB\u5404\u8282\u70B9\uFF1B\u8D85\u65F6\u6CBF\u7528\u539F\u7F16\u53F7\u3002\u5E94\u6025\u5165\u53E3\u4ECD\u590D\u6838 DiyToken\u3001\u4E3B\u5E93\u7BA1\u7406\u5458\u53CA mcp:admin\uFF0C\u8981\u6C42\u517C\u5BB9 database-pools/v1 \u7684 API\uFF0CMCP \u66F4\u65B0\u4E0D\u80FD\u5B89\u88C5\u540E\u7AEF\u3002\u5171\u4EAB\u6C60/\u6269\u5C55\u5E93/\u4E0D\u652F\u6301\u9A71\u52A8\u4E0D\u6E05\u7406\u3002\u53EA\u8F6E\u6362\u6307\u5B9A\u6C60\u5E76\u63A2\u6D4B SELECT 1\uFF0C\u4E0D\u6740\u4E8B\u52A1\u3001\u4E0D\u91CD\u653E SQL\u3001\u4E0D\u4FDD\u8BC1\u4FEE\u590D\u6301\u7EED\u6CC4\u6F0F/\u5BB9\u91CF/\u7F51\u7EDC\u6545\u969C\u3002\u968F\u540E\u9A8C\u8BC1\u539F\u6545\u969C\u4E1A\u52A1\u63A5\u53E3\u3002`,{action:d.enum(["BlockIp","UnblockIp","ResetDatabasePools"]).describe("IP \u6CBB\u7406\u6216\u5728\u7EBF\u8FDE\u63A5\u6C60\u6062\u590D\u3002"),ip:d.string().min(3).max(64).optional().describe("IP \u64CD\u4F5C\u5FC5\u586B\uFF0CIPv4/IPv6\uFF1B\u8FDE\u63A5\u6C60\u64CD\u4F5C\u4E0D\u4F20\u3002"),poolTarget:d.enum(["Both","Write","Read"]).optional().describe("\u5F53\u524D\u79DF\u6237\u4E3B/\u8BFB\u6C60\uFF0C\u9ED8\u8BA4 Both\u3002\u4F7F\u7528\u9884\u89C8\u4E2D\u7684 Target\u3002"),operationId:d.string().regex(/^[0-9a-f]{32}$/u).optional().describe("\u4F7F\u7528\u9884\u89C8\u8FD4\u56DE\u7684 OperationId\uFF0C\u6240\u6709\u91CD\u8BD5\u4FDD\u6301\u76F8\u540C\u7F16\u53F7\u3002"),poolIds:d.array(d.string().regex(/^[0-9a-f]{64}$/u)).min(1).max(2).optional().describe("\u9884\u89C8\u8FD4\u56DE\u7684 PoolIds \u539F\u6570\u7EC4\uFF1B\u914D\u7F6E\u53D8\u5316\u65F6\u540E\u7AEF\u62D2\u7EDD\u6267\u884C\u3002"),blockMinutes:d.number().int().min(1).max(10080).optional().describe("Block duration in minutes, 1-10080. Default 30 for BlockIp."),reason:d.string().max(300).optional().describe("Bounded operator reason. Do not include tokens, passwords or request bodies."),confirmExecution:d.string().optional().describe("\u9884\u89C8\u8FD4\u56DE\u7684\u7CBE\u786E\u786E\u8BA4\u503C\uFF1ABlockIp:<ip>\u3001UnblockIp:<ip> \u6216 ResetDatabasePools:<operationId>\u3002")},async({action:a,ip:s,blockMinutes:c,reason:l,confirmExecution:u,poolTarget:p,operationId:f,poolIds:h})=>{try{if(a==="ResetDatabasePools"){if(!u){let x=await t.querySystemObservability({Action:"DatabasePools",Target:p||"Both"}),b=x.Data;return{content:[{type:"text",text:JSON.stringify({...x,dryRun:!0,requiredConfirmation:b?.OperationId?`ResetDatabasePools:${b.OperationId}`:void 0},null,2)}],...x.Code===1?{}:{isError:!0}}}if(!f||!h||u!==`ResetDatabasePools:${f}`)return{content:[{type:"text",text:"\u5FC5\u987B\u4F7F\u7528\u540C\u4E00\u6B21\u9884\u89C8\u7684 operationId\u3001poolIds \u548C requiredConfirmation\u3002"}],isError:!0};let v=await t.manageSystemObservability({Action:a,Target:p||"Both",OperationId:f,PoolIds:h,Confirm:u});return{content:[{type:"text",text:JSON.stringify(v,null,2)}],...v.Code===1?{}:{isError:!0}}}let m=(s||"").trim();if((0,b2.isIP)(m)===0)return{content:[{type:"text",text:"IP \u5730\u5740\u683C\u5F0F\u65E0\u6548\u3002"}],isError:!0};let g=`${a}:${m}`;if(u!==g)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,action:a,ip:m,blockMinutes:a==="BlockIp"?c||30:void 0,reason:a==="BlockIp"?l||"\u7CFB\u7EDF\u65E5\u5FD7/\u76D1\u63A7\u4E2D\u7531\u7BA1\u7406\u5458\u624B\u52A8\u5C01\u7981\u3002":void 0,requiredConfirmation:g,warning:"\u786E\u8BA4\u540E\u4F1A\u4FEE\u6539\u5F53\u524D\u79DF\u6237\u7684 IP \u5C01\u9501\u72B6\u6001\uFF0C\u5E76\u5199\u5165\u5E73\u53F0\u5BA1\u8BA1\u65E5\u5FD7\u3002"},null,2)}]};await t.writeAuditLog("microi_manage_system_observability",m,JSON.stringify({action:a,blockMinutes:a==="BlockIp"?c||30:void 0}));let y=await t.manageSystemObservability({Action:a,Ip:m,...a==="BlockIp"?{BlockMinutes:c||30,Reason:l||""}:{}});return{content:[{type:"text",text:JSON.stringify({Code:y.Code,Msg:y.Msg||"",Data:y.Data},null,2)}],...y.Code===1?{}:{isError:!0}}}catch(m){return{content:[{type:"text",text:`Error: ${m instanceof Error?m.message:String(m)}`}],isError:!0}}}),i.tool("microi_query_mongodb_logs",`Query Microi MongoDB system logs (sys_log_<osClient>/log_yyyyMM) for OsClient ${r}. Use this after automated tests to inspect V8 errors, slow logs, workflow logs and platform guard logs.`,{keyword:d.string().optional().describe("Keyword searched in log Title and Content"),type:d.string().optional().describe("Log Type, for example MCP, \u8868\u5355V8\u6162\u65E5\u5FD7, \u8868\u5355V8\u9012\u5F52\u4FDD\u62A4, \u5DE5\u4F5C\u6D41\u5408\u5E76\u63D0\u4EA4\u6162\u65E5\u5FD7"),level:d.number().optional().describe("Log level. Common values: 1 info, 2 warning, 3 error"),searchMonth:d.string().optional().describe("Month in yyyyMM. Defaults to current month on server"),pageIndex:d.number().optional().describe("Page index, default 1"),pageSize:d.number().optional().describe("Page size, default 20, backend max 200")},async({keyword:a,type:s,level:c,searchMonth:l,pageIndex:u,pageSize:p})=>{try{let f=await t.queryMongodbLogs({keyword:a,type:s,level:c,searchMonth:l,pageIndex:u,pageSize:p});return f.Code!==1?{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(f.Data,null,2)}]}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),i.tool("microi_write_mongodb_log",`Write a Microi MongoDB system log for OsClient ${r}. Useful for AI automated test milestones, reproduction markers, and repair verification notes.`,{title:d.string().describe("Log title"),content:d.string().describe("Log content"),type:d.string().optional().describe("Log Type, default MCP"),level:d.number().optional().describe("Log level, default 1"),api:d.string().optional().describe("Related API/tool name"),param:d.string().optional().describe("Input or context summary. Avoid secrets."),remark:d.string().optional().describe("Short remark or target identifier"),otherInfo:d.string().optional().describe("Additional diagnostic info. Avoid secrets."),timer:d.number().optional().describe("Elapsed milliseconds, if applicable"),result:d.string().optional().describe("Result summary"),appId:d.string().optional().describe("AppId, default microi.mcp")},async({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:h,timer:m,result:g,appId:y})=>{try{let v=await t.writeMongodbLog({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:h,timer:m,result:g,appId:y});return v.Code!==1?{content:[{type:"text",text:`Error: ${v.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(v.Data||{ok:!0},null,2)}]}}catch(v){return{content:[{type:"text",text:`Error: ${v instanceof Error?v.message:String(v)}`}],isError:!0}}}),i.tool("microi_create_table",`Create or reconcile a custom table for OsClient "${r}". Inserts a record into diy_table. IDEMPOTENT \u2014 calling again with the same name reuses the existing TableId; an explicitly supplied v8Limit value is reconciled and read back by system validation. This is step 2 of system design. After adding fields, call microi_configure_form_banner so the default-visible Banner receives useful field-aware configuration.`,{name:d.string().describe('Table name in English (e.g. "Crm_Customer", "Order_Main"). Convention: Module_Entity format. Will be a real MySQL table.'),description:d.string().optional().describe('Chinese description of the table (e.g. "\u5BA2\u6237\u4FE1\u606F", "\u8BA2\u5355\u4E3B\u8868")'),tabs:d.string().optional().describe(`Form tab layout JSON (e.g. '[{"Id":"basic","Name":"\u57FA\u672C\u4FE1\u606F","Sort":10},{"Id":"business","Name":"\u4E1A\u52A1\u4FE1\u606F","Sort":20}]'). Groups fields into diy_table.Tabs. When using microi_generate_system, many-field tables can be auto-tabbed.`),isTree:d.number().optional().describe("Enable tree structure (1=tree table with ParentId self-referencing, 0=flat). Default: 0"),readPrimary:d.union([d.literal(0),d.literal(1)]).nullable().optional().describe("Trusted table configuration: 1 uses its database writer for native rows/count/sum/tree/export. null/0 uses the existing default; omit preserves existing configuration. Does not change explicit transaction isolation."),column:d.number().optional().describe("Number of form columns (1, 2, or 3). Controls form layout. Default: 2 (\u53CC\u5217\uFF0C\u66F4\u7D27\u51D1\u73B0\u4EE3)"),formOpenType:d.string().optional().describe('How to open form: "Dialog" (\u5F39\u7A97), "Drawer" (\u62BD\u5C49), "Page" (\u65B0\u9875\u9762). Default: Dialog'),formOpenWidth:d.string().optional().describe('Form dialog/drawer width (e.g. "800px", "80%"). Default: 80%'),v8Limit:d.boolean().optional().describe("Default false for new tables; omit to preserve an existing table. true enables Jint per-execution timeout, statement, recursion and allocation budgets for this table's backend V8 events."),v8Unlimited:d.boolean().optional().describe("Deprecated compatibility alias. Prefer v8Limit; true is equivalent to v8Limit=false.")},async({name:a,description:s,tabs:c,isTree:l,readPrimary:u,column:p,formOpenType:f,formOpenWidth:h,v8Limit:m,v8Unlimited:g})=>{try{let y=m??(g===void 0?void 0:!g),v=await t.createTable(a,s,{Tabs:c,IsTree:l,ReadPrimary:u,Column:p??2,FormOpenType:f||"Dialog",FormOpenWidth:h||"80%",V8Limit:y===void 0?void 0:y?1:0});if(v.Code!==1)return{content:[{type:"text",text:`Error: ${v.Msg}`}],isError:!0};let x=v.Data;return{content:[{type:"text",text:`\u2705 Table "${a}" created.
568
568
  - TableId: ${x?.TableId}
569
569
  - Use this TableId when adding fields via microi_add_field`}]}}catch(y){return{content:[{type:"text",text:`Error: ${y instanceof Error?y.message:String(y)}`}],isError:!0}}}),i.tool("microi_repair_audit_fields",`Repair the fixed audit-field metadata for one existing table in OsClient "${r}". The backend reconciles Id, CreateTime, UpdateTime, UserId, UserName and IsDeleted only when the physical columns exist, restores soft-deleted diy_field rows, adds missing diy_field rows without repeating DDL, clears shared metadata caches, and reads the final state back. The fields remain hidden by default when diy_table.DisplayDefaultField is off.`,{tableId:d.string().optional().describe("Exact diy_table.Id. Provide tableId or tableName."),tableName:d.string().optional().describe("Exact physical table/diy_table.Name. Provide tableName or tableId.")},async({tableId:a,tableName:s})=>{if(!a&&!s)return{content:[{type:"text",text:"Error: tableId \u548C tableName \u81F3\u5C11\u4F20\u4E00\u4E2A\u3002"}],isError:!0};try{let c=await t.repairFixedAuditFields({tableId:a,tableName:s});return c.Code!==1?{content:[{type:"text",text:`Error: ${c.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(c.Data||{},null,2)}]}}catch(c){return{content:[{type:"text",text:`Error: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_add_field",`Add a field to a custom table for OsClient "${r}". Inserts a record into diy_field and executes ALTER TABLE to add the column. The "type" parameter MUST be a platform-allowed column type. \u26A0\uFE0F FORBIDDEN: datetime, date, timestamp, time \u2014 all date/time fields MUST use varchar(25) and store 'yyyy-MM-dd HH:mm:ss' strings. Allowed types: varchar(N), mediumtext, longtext, int, bigint, decimal(18,N). This tool is IDEMPOTENT \u2014 calling it again with the same TableId+name returns Skipped:true instead of failing.`,{tableId:d.string().describe("The TableId returned from microi_create_table"),name:d.string().describe('Field name in English (e.g. "CustomerName", "Phone", "Amount")'),label:d.string().describe('Chinese display label (e.g. "\u5BA2\u6237\u540D\u79F0", "\u624B\u673A\u53F7", "\u91D1\u989D")'),type:d.string().optional().describe("Platform column type. Default: varchar(500). Valid: varchar(25/50/200/500/2000), int, bigint, decimal(18,2), mediumtext, longtext. \u26A0\uFE0F FORBIDDEN: datetime, date, timestamp, float, double, boolean \u2014 for dates use varchar(25); for floats use decimal(18,N); for booleans use int."),component:d.string().optional().describe("UI component type. Default: Text. Options: Text, Textarea, NumberText, Select, MultipleSelect, Radio, Checkbox, Switch, DateTime, RichText, ImgUpload, FileUpload, AutoNumber, JoinForm, OpenTable, SelectTree, Cascader, Department, Address, Map, Rate, TableChild"),visible:d.number().optional().describe("Is visible in form (1=yes, 0=no). Default: 1"),appVisible:d.number().optional().describe("Is visible in mobile app (1=yes, 0=no). Default: 1"),tab:d.string().optional().describe("Form tab group name (for organizing fields into tabs)"),tableWidth:d.number().optional().describe("Column width in list view (pixels). When omitted, MCP infers a stable width from field semantics: titles/addresses are wider, dates/codes medium, numbers/statuses compact."),sort:d.number().optional().describe("Field display order (smaller = front). If omitted, MCP auto-increments per table starting at 100, step 10 \u2014 so adding fields in business-meaningful order produces correct list/form ordering automatically. Override only when you need a specific position."),readonly:d.number().optional().describe("Is readonly (1=yes, 0=no). Default: 0"),notEmpty:d.number().optional().describe("Required field validation (1=required, 0=optional). Default: 0"),unique:d.number().optional().describe("Unique constraint (1=unique, 0=allow duplicates). Default: 0"),defaultValue:d.string().optional().describe("Default value for the field"),placeholder:d.string().optional().describe("Placeholder text shown in form input"),formWidth:d.number().nullable().optional().describe("Field width in form grid columns (1-24). Default: null/omitted for normal fields. Use 24 only for full-row controls such as CodeEditor, Textarea, RichText, upload, TableChild, map/layout/custom components."),data:d.string().optional().describe('Options data source for Select/MultipleSelect/Radio/Checkbox components. REQUIRED for these four components. Format: "key1|label1,key2|label2" (KeyValue, recommended \u2014 e.g. "1|\u542F\u7528,0|\u7981\u7528", "male|\u7537,female|\u5973") \u2014 backend stores key, displays label. Or simple "v1,v2,v3" (same value for both). Backend auto-builds the Config JSON. For SQL/ApiEngine/DataSource sources, use the config parameter instead.'),config:d.string().optional().describe(`Component config JSON string. Auto-generated for Select/Radio/Checkbox when "data" is provided. Use this only for advanced cases:
570
570
  - SQL source: '{"DataSource":"Sql","Sql":"select Id,Name from t where Name like \\'%$Keyword$%\\' limit 0,20","SelectLabel":"Name","SelectSaveField":"Id","DataSourceSqlRemote":true}'
@@ -605,7 +605,7 @@ ${JSON.stringify(u,null,2)}
605
605
  `,"| # | Title | Number | Description | Updated |","|---|-------|--------|-------------|---------|"];return c.forEach((u,p)=>{l.push(`| ${p+1} | ${u.Title||""} | ${u.Number||""} | ${u.Desc||""} | ${u.UpdateTime||""} |`)}),{content:[{type:"text",text:l.join(`
606
606
  `)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}),i.tool("microi_get_page",`Get page engine detail including full JSON configuration for OsClient "${r}". The JsonObj field contains the complete page structure with formData, wrapperList, and widgetList.`,{pageId:d.string().describe("The page Id to retrieve")},async({pageId:a})=>{try{let s=await t.getPageEngineDetail(a);if(s.Code!==1)return{content:[{type:"text",text:`Error: ${s.Msg}`}],isError:!0};let c=s.Data;return{content:[{type:"text",text:[`## Page: ${c?.Title||a}`,c?.Number?`- **Number**: ${c.Number}`:"",c?.Desc?`- **Description**: ${c.Desc}`:"","","### JSON Configuration","```json",typeof c?.JsonObj=="string"?c.JsonObj:JSON.stringify(c?.JsonObj,null,2),"```"].filter(Boolean).join(`
607
607
  `)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}),i.tool("microi_save_page",`Create or update a page engine page for OsClient "${r}". Accepts raw JsonObj, {JsonObj}, {JsonStr}, a mic_page row, or {formData:{JsonObj}} and normalizes it to the canonical JsonObj saved in mic_page.JsonObj. Pass pageId to update an existing page, or omit to create a new one.`,{pageId:d.string().optional().describe("Page Id to update. Omit to create a new page."),title:d.string().describe('Page title (e.g. "\u9500\u552E\u4EEA\u8868\u76D8", "\u6570\u636E\u6982\u89C8")'),number:d.string().optional().describe("Page number/code (auto-generated if omitted)"),desc:d.string().optional().describe("Page description"),jsonStr:d.string().optional().describe("Page Engine JsonObj string. Prefer json for object input."),json:d.unknown().optional().describe("Page Engine JSON object/string in any common AI output shape."),routePath:d.string().optional().describe("Optional route path saved to mic_page.RoutePath."),componentPath:d.string().optional().describe("Optional component path saved to mic_page.ComponentPath.")},async({pageId:a,title:s,number:c,desc:l,jsonStr:u,json:p,routePath:f,componentPath:h})=>{try{let m=Kn(p??u);if(!m.ok||!m.json)return{content:[{type:"text",text:JSON.stringify(m,null,2)}],isError:!0};let g=await t.savePageEngine({PageId:a,Title:s,Number:c,Desc:l,JsonStr:m.json,RoutePath:f,ComponentPath:h});if(g.Code!==1)return{content:[{type:"text",text:`Error: ${g.Msg}`}],isError:!0};let y=g.Data;return{content:[{type:"text",text:`\u2705 ${y?.Message||"Page saved successfully."}
608
- - PageId: ${y?.PageId}`}]}}catch(m){return{content:[{type:"text",text:`Error: ${m instanceof Error?m.message:String(m)}`}],isError:!0}}}),i.tool("microi_list_applications",`List every online AI application for OsClient "${r}" across Web, UniApp and MicroService, including each app's complete source-file manifest by default. AI agents should call this at the beginning of application/page work so they understand existing apps before creating duplicates. For complex custom dialogs/pages, prefer extending an existing MicroService or creating one with microi_create_microservice + microi_sync_microservice_source; do not embed large HTML in V8.ConfirmTips.`,{appType:d.enum(["Web","UniApp","MicroService"]).optional().describe("Optional exact application type filter."),keyword:d.string().optional().describe("Optional case-insensitive search across name, AppKey, type and description."),includeFiles:d.boolean().optional().default(!0).describe("Include the complete file manifest for every app. Defaults to true.")},async({appType:a,keyword:s,includeFiles:c})=>{try{let l=await t.listApplications({AppType:a,Keyword:s,IncludeFiles:c!==!1});return l.Code!==1?{content:[{type:"text",text:`Error: ${l.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(l.Data,null,2)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_get_application_context",`Get one Web, UniApp or MicroService application by Id/AppKey for OsClient "${r}". It returns metadata and the full file manifest by default without embedding source bodies; set includeContents=true only when the complete source is actually needed, or use microi_get_application_file for one exact file. MicroService responses also include sys_microiservice runtime/pages.`,{appIdOrKey:d.string().describe("sys_microistore.Id or AppKey."),includeContents:d.boolean().optional().default(!1).describe("Read private HDFS source contents. Defaults to false; prefer microi_get_application_file for targeted reads."),maxFileBytes:d.number().int().positive().optional().describe("Maximum bytes read per source file. Default 2MB."),maxTotalBytes:d.number().int().positive().optional().describe("Maximum total bytes read for this app. Default 50MB.")},async({appIdOrKey:a,includeContents:s,maxFileBytes:c,maxTotalBytes:l})=>{try{let u=await t.getApplicationContext({AppIdOrKey:a,IncludeContents:s===!0,...c?{MaxFileBytes:c}:{},...l?{MaxTotalBytes:l}:{}});if(u.Code!==1)return{content:[{type:"text",text:`Error: ${u.Msg}`}],isError:!0};let p=u.Data,h=(Array.isArray(p?.Files)?p.Files:[]).filter(g=>typeof g?.ContentReadError=="string"&&g.ContentReadError).length,m={...p,McpReadSummary:{RequestedContents:s===!0,ContentsComplete:s!==!0||h===0,ContentErrorCount:h}};return{content:[{type:"text",text:JSON.stringify(m,null,2)}]}}catch(u){return{content:[{type:"text",text:`Error: ${u instanceof Error?u.message:String(u)}`}],isError:!0}}}),i.tool("microi_get_application_file",`Read one exact source file from a Web, UniApp or MicroService online AI application for OsClient "${r}". Text code is returned as UTF-8 Content; binary files are returned as FileByteBase64.`,{appIdOrKey:d.string().describe("sys_microistore.Id or AppKey."),filePath:d.string().describe("Exact relative source path from the application file manifest."),maxFileBytes:d.number().int().positive().optional().describe("Maximum bytes read. Default 10MB.")},async({appIdOrKey:a,filePath:s,maxFileBytes:c})=>{try{let l=await t.getApplicationFile({AppIdOrKey:a,FilePath:s,IncludeContents:!0,...c?{MaxFileBytes:c}:{}});return l.Code!==1?{content:[{type:"text",text:`Error: ${l.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(l.Data,null,2)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_scaffold_vue_microservice",`Create a safe, maintainable MicroService scaffold for OsClient "${r}" using the stable Vue 3.5.40 + Vite 7.3.6 + TypeScript 5.9.3 baseline, @vitejs/plugin-vue 6.0.8, vue-tsc 3.3.9, Composition API and <script setup lang="ts">. The minimal template keeps Microi SDK and host/internal-route integration but does not force Pinia or Vue Router; add either only when application complexity needs it. It writes .microi-micro-app.json, microi.routes.json and exactly one Vue component per declared route inside the local tenant AI\u5E94\u7528 directory. It only accepts a real absolute directory whose basename is AI\u5E94\u7528, never overwrites a different existing project, and performs a dry run until confirmExecution exactly equals appKey. After scaffolding, run npm install and npm run build, then use microi_create_microservice, microi_sync_microservice_source and microi_publish_application_directory_stream (or the legacy publisher for a tiny compatibility payload).`,{appKey:d.string().regex(/^[a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?$/u).describe("Stable lowercase application key and local directory name."),name:d.string().min(1).max(120).describe("Human-readable MicroService name."),description:d.string().optional().describe("Optional application description."),aiApplicationsDirectory:d.string().optional().describe("Absolute tenant AI\u5E94\u7528 directory. Defaults to MICROI_AI_APPLICATIONS_DIR injected by Microi.VSCode."),buildVersion:d.string().regex(/^v\d+\.\d+\.\d+$/u).optional().default("v0.1.0").describe("Initial semantic build version. Default v0.1.0."),routes:d.array(d.object({path:d.string().describe("Internal route path such as /context-test."),name:d.string().describe("Stable route key such as context-test."),title:d.string().describe("Page/menu title."),description:d.string().optional().describe("Optional visible page explanation."),isHome:d.boolean().optional().describe("Mark one route as the default page. The first route is used when omitted.")})).min(1).max(50).describe("Vue pages and MicroService internal routes. One .vue file is generated per item."),confirmExecution:d.string().optional().describe("Required for filesystem writes and must exactly equal appKey. Omit for a local preflight only.")},async({appKey:a,name:s,description:c,aiApplicationsDirectory:l,buildVersion:u,routes:p,confirmExecution:f})=>{try{let h=String(l||process.env.MICROI_AI_APPLICATIONS_DIR||"").trim();if(!h)return{content:[{type:"text",text:"Error: \u7F3A\u5C11 AI \u5E94\u7528\u76EE\u5F55\u3002\u8BF7\u7531 Microi.VSCode \u6CE8\u5165 MICROI_AI_APPLICATIONS_DIR\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 aiApplicationsDirectory\u3002"}],isError:!0};if(f&&f!==a)return{content:[{type:"text",text:`Error: confirmExecution \u5FC5\u987B\u7CBE\u786E\u7B49\u4E8E ${a}`}],isError:!0};let m={aiApplicationsDirectory:h,appKey:a,name:s,description:c,apiBaseUrl:e.apiBaseUrl,osClient:r,buildVersion:u,routes:p,sdkSource:e2(process.env.MICROI_WORKSPACE_ROOT)},g=O0(m);if(f!==a)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,confirmationRequired:a,targetDirectory:g.targetDirectory,appKey:g.appKey,buildVersion:g.buildVersion,routeCount:g.routes.length,routes:g.routes.map(v=>({path:v.path,name:v.name,title:v.title,sourceFile:v.sourceFile,isHome:v.isHome})),fileCount:g.files.length,files:g.files.map(v=>({Path:v.relativePath,Size:v.size,Sha256:v.sha256}))},null,2)}]};let y=t2(m);return{content:[{type:"text",text:JSON.stringify(y,null,2)}]}}catch(h){return{content:[{type:"text",text:`Error: ${h instanceof Error?h.message:String(h)}`}],isError:!0}}}),i.tool("microi_get_microservice",`Get one Microi microservice / micro-app by MsKey for OsClient "${r}". Use this before publishing to inspect current BuildVersion, EntryPath and asset manifest.`,{msKey:d.string().describe("Microservice key, stored in sys_microiservice.MsKey")},async({msKey:a})=>{try{let s=await t.getMicroService(a);return s.Code!==1?{content:[{type:"text",text:`Error: ${s.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(s.Data,null,2)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}),i.tool("microi_create_microservice",`Create or update sys_microiservice metadata for OsClient "${r}". This only writes metadata. For generated app source/dist files, use microi_publish_microservice.`,{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: MsType, Runtime, StorageMode, SourceDirName, EntryPath, BuildVersion."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,confirmExecution:s})=>{if(!s)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,microService:a},null,2)}]};try{let c=await t.createMicroService(a);return c.Code!==1?{content:[{type:"text",text:`Error: ${c.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(c.Data,null,2)}]}}catch(c){return{content:[{type:"text",text:`Error: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_sync_microservice_source",`Sync a local Web, UniApp or MicroService source directory into the online AI Application for OsClient "${r}". Prefer directory: MCP detects SourceStreamPublish, streams each original file into the private staged prefix, then atomically finalizes the complete manifest with CurrentVersion/AppVersion/SourceManifestHash CAS. Transport failures are read back before any exact replay. Old servers use bounded legacy JSON only for at most 256 files and 8MiB. AI agents must never read large files into Base64, create .sync-seg-* files, create sync-source-files.json, or split one source file across tool calls.`,{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: Description and SourceDirName."),directory:d.string().optional().describe("Preferred. Absolute local project directory; MCP reads it directly and excludes node_modules, dist, build, coverage, caches and VCS data."),sourceFiles:d.array(Tt).optional().describe("Legacy compatibility only. Do not construct this array from manually split files when a local directory is available."),replace:d.boolean().optional().describe("Complete directory sync defaults to exact private-source replacement. Explicit false is rejected by the stream protocol; public runtime/build rows are always preserved."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,directory:s,sourceFiles:c,replace:l,confirmExecution:u})=>gQ(t,{microService:a,directory:s,sourceFiles:c,replace:l,confirmExecution:u})),i.tool("microi_clear_application_source",`Remove an AI application's private HDFS source objects, private mci_ai_app_file rows, public SourceZip objects and source-delivery flags while preserving compiled runtime/build assets for OsClient "${r}". This is intentionally destructive and two-phase: first call without confirmExecution to obtain the exact target list and confirmationSha256, then pass that hash unchanged. Keep a verified local source checkout before executing.`,{appIdOrKey:d.string().min(1).describe("Exact AppId or AppKey. No wildcard or bulk deletion is supported."),confirmExecution:d.string().optional().describe("Exact confirmationSha256 returned by the backend dry run.")},async({appIdOrKey:a,confirmExecution:s})=>{try{let c=await t.clearApplicationSource({AppIdOrKey:a,...s?{ConfirmExecution:s}:{}});return{content:[{type:"text",text:JSON.stringify(c,null,2)}],structuredContent:c,...c.Code!==1?{isError:!0}:{}}}catch(c){return{content:[{type:"text",text:`Clear application source failed: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_upload_application_asset_stream",`Stream one local built asset directly to the immutable HDFS version directory for OsClient "${r}". Protocol v3 uses durable HDFS multipart sessions with status readback and reconnect resume for ordinary files through multi-GiB installers; bytes are never encoded as Base64 and never enter Jint. This is a low-level primitive inside a frozen release contract; normally use microi_publish_application_directory_stream to upload and atomically promote a complete directory.`,{appIdOrKey:d.string().min(1).describe("Existing sys_microistore Id or AppKey."),versionNo:d.string().regex(/^v?\d+\.\d+\.\d+$/u).describe("Immutable semantic version, e.g. v1.2.3."),relativePath:d.string().min(1).describe("POSIX-style path inside the compiled output, e.g. assets/index-abcd.js."),localFilePath:d.string().min(1).describe("Absolute or workspace-relative path of one local ordinary file."),sha256:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional expected SHA-256. MCP computes and verifies it when omitted."),routes:d.array(Tt).optional().default([]).describe("Canonical v3 route snapshot input; missing routes are frozen explicitly as []."),routeSnapshotJson:d.string().max(1024*1024).optional().describe("Protocol v3 requires the exact recursive-key-sorted, array-order-preserving UTF-8 canonical JSON for routes."),routeSnapshotHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the lowercase SHA-256 of RouteSnapshotJson."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Protocol v3 source-manifest SHA-256 tying this asset to the release."),runtimeManifestHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 exact runtime-manifest SHA-256 for the frozen release."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Protocol v3 stable delivery batch id."),protocolVersion:d.literal(3).optional().describe("Enable durable v3 multipart/resume. All v3 release identity and CAS fields then become required."),expectedGateEpoch:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 gate epoch as a canonical decimal bigint string."),requestId:d.string().regex(/^[A-Za-z0-9._:-]{8,100}$/u).optional().describe("Protocol v3 stable release RequestId; every asset and stage/finalize replay must reuse it exactly."),requestFingerprint:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 immutable release fingerprint."),expectedCurrentVersion:d.number().int().min(0).optional().describe("Protocol v3 application CurrentVersion baseline."),expectedAppVersion:d.string().nullable().optional().describe("Protocol v3 application AppVersion baseline; explicit null means empty."),expectedPublishFence:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishFence baseline."),expectedPublishRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishRowVersion baseline."),expectedVersionRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).nullable().optional().describe("Protocol v3 target version RowVersion; explicit null means absent."),expectedActivePublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 active version id baseline; explicit null means empty."),expectedCommittedPublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 committed version id baseline; explicit null means empty."),timeoutMs:d.number().int().min(1e3).max(2*60*6e4).optional().describe("Per-file upload timeout. Default 30 minutes; maximum 2 hours."),confirmExecution:d.string().optional().describe("Required for the real upload and must exactly equal appIdOrKey.")},async a=>xQ(t,a)),i.tool("microi_publish_application_directory_stream",`Publish a real Web, UniApp or MicroService build directory for OsClient "${r}" using deterministic RequestId evidence. Protocol v3 automatically switches files above the legacy 128 MiB request boundary to durable HDFS multipart sessions with per-part SHA-256, status readback and reconnect resume; logical files such as 5 GiB installers never enter Base64/Jint or whole-file memory. publishMode=stage uploads immutable version assets only; finalize rebuilds the same local manifest and promotes it without uploading; stage-and-finalize keeps the original one-call flow. Paths, hashes, sizes, request ids, version preconditions and final manifest evidence are verified strictly. Old API nodes without the resumable endpoints fail closed for oversized assets.`,{appIdOrKey:d.string().min(1).describe("Existing sys_microistore Id or AppKey."),versionNo:d.string().regex(/^v?\d+\.\d+\.\d+$/u).describe("Immutable semantic version, e.g. v1.2.3."),directory:d.string().min(1).describe("Local compiled output directory such as dist or unpackage/dist/build/h5."),entryPath:d.string().optional().default("index.html").describe("Entry file relative to directory. Default index.html."),routes:d.array(Tt).optional().default([]).describe("Canonical v3 route snapshot input; missing routes are frozen explicitly as []."),routeSnapshotJson:d.string().max(1024*1024).optional().describe("Protocol v3 requires the exact recursive-key-sorted, array-order-preserving UTF-8 canonical JSON for routes."),routeSnapshotHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the lowercase SHA-256 of RouteSnapshotJson."),changeSummary:d.string().max(2e3).optional().describe("Version change summary stored in mci_ai_app_version on first stage insert. Maximum 2000 characters; retries preserve the original summary."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional source-manifest SHA-256 returned by microi_sync_microservice_source, tying source and runtime to one delivery."),runtimeManifestHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the exact lowercase runtime-manifest SHA-256 computed during the local dry run."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Optional stable delivery batch id (8-50 characters, matching the API and LastBuildTaskId). When omitted MCP derives a deterministic id from app/version/manifest so retries remain stable."),publishMode:d.enum(["stage","finalize","stage-and-finalize"]).optional().default("stage-and-finalize").describe("stage uploads immutable assets only; finalize submits the local manifest only; stage-and-finalize preserves the original one-call behavior."),verificationOnly:d.boolean().optional().default(!1).describe("Protocol v3 stage only: submit/read the same frozen verification task without uploading files again. Pending is not ReleaseVerified and never permits finalize."),protocolVersion:d.literal(3).optional().describe("Explicit protocol v3 gate. When set, publishMode must be explicit stage or finalize and every v3 precondition is required."),expectedGateEpoch:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 gate epoch as a canonical decimal bigint string."),requestId:d.string().regex(/^[A-Za-z0-9._:-]{8,100}$/u).optional().describe("Protocol v3 stable release RequestId; stage/finalize and all Pending replays must reuse it exactly."),requestFingerprint:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 immutable release fingerprint."),expectedCurrentVersion:d.number().int().min(0).optional().describe("Required for finalize/stage-and-finalize and omitted only during stage. Must equal the application CurrentVersion read before staging."),expectedAppVersion:d.string().nullable().optional().describe("Application AppVersion baseline. Protocol v3 requires explicit string or null for both stage and finalize."),expectedPublishFence:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishFence canonical decimal bigint string."),expectedPublishRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishRowVersion canonical decimal bigint string."),expectedVersionRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).nullable().optional().describe("Protocol v3 target mci_ai_app_version.RowVersion; explicit null means the row must not exist."),expectedActivePublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 active version id baseline; explicit null means empty."),expectedCommittedPublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 committed version id baseline; explicit null means empty."),includeSourceMaps:d.boolean().optional().default(!1).describe("Publish *.map source maps. Defaults to false to avoid source disclosure."),maxFiles:d.number().int().min(1).max(2e4).optional().describe("Safety cap checked before upload. Default and hard maximum 20,000."),maxTotalMegabytes:d.number().positive().max(Number.MAX_SAFE_INTEGER/(1024*1024)).optional().describe("Optional caller safety cap checked before upload. Omit for the platform maximum; 5 GiB and larger builds use resumable HDFS multipart."),timeoutMsPerFile:d.number().int().min(1e3).max(2*60*6e4).optional().describe("Per-file upload timeout. Default 30 minutes."),allowLegacyFallback:d.boolean().optional().default(!1).describe("Deprecated compatibility flag. RequestId-capable two-phase publishing fails closed on old API nodes instead of publishing through the legacy payload."),confirmExecution:d.string().optional().describe("Required for real publishing and must exactly equal appIdOrKey. Omit for a local preflight manifest only.")},async({appIdOrKey:a,versionNo:s,directory:c,entryPath:l,routes:u,routeSnapshotJson:p,routeSnapshotHash:f,changeSummary:h,sourceManifestHash:m,runtimeManifestHash:g,deliveryBatchId:y,publishMode:v,verificationOnly:x,protocolVersion:b,expectedGateEpoch:w,requestId:E,requestFingerprint:S,expectedCurrentVersion:k,expectedAppVersion:A,expectedPublishFence:R,expectedPublishRowVersion:I,expectedVersionRowVersion:C,expectedActivePublishVersionId:j,expectedCommittedPublishVersionId:F,includeSourceMaps:V,maxFiles:J,maxTotalMegabytes:X,timeoutMsPerFile:Ae,allowLegacyFallback:ke,confirmExecution:le})=>_Q(t,{appIdOrKey:a,versionNo:s,directory:c,entryPath:l,routes:u,routeSnapshotJson:p,routeSnapshotHash:f,changeSummary:h,sourceManifestHash:m,runtimeManifestHash:g,deliveryBatchId:y,publishMode:v,verificationOnly:x,protocolVersion:b,expectedGateEpoch:w,requestId:E,requestFingerprint:S,expectedCurrentVersion:k,expectedAppVersion:A,expectedPublishFence:R,expectedPublishRowVersion:I,expectedVersionRowVersion:C,expectedActivePublishVersionId:j,expectedCommittedPublishVersionId:F,includeSourceMaps:V,maxFiles:J,maxTotalMegabytes:X,timeoutMsPerFile:Ae,allowLegacyFallback:ke,confirmExecution:le})),i.tool("microi_publish_microservice","Legacy small-payload publisher for generated microservice / micro-app files in Base64. For real compiled directories or large assets, use microi_publish_application_directory_stream so bytes stream directly to HDFS and never enter JSON/Jint.",{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: BuildVersion, EntryPath, SourceDirName."),assets:d.array(Tt).describe("Built asset files. Each item needs Path/RelativePath/FileName and FileByteBase64/ContentBase64. Mark the main HTML/JS entry with IsEntry=true or Entry=true."),routes:d.array(Tt).optional().describe("Optional route/page records for sys_microiservice_page. Fields: PageKey, PageName, PageTitle, RoutePath, EntryPath, SourceDirName, SourceFile, RouteMetaJson, Sort, IsHome."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional source-manifest SHA-256 returned by source sync."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Optional stable delivery batch id (8-50 characters, matching the API and LastBuildTaskId). MCP generates one when omitted."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,assets:s,routes:c,sourceManifestHash:l,deliveryBatchId:u,confirmExecution:p})=>{if(!p)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,microService:a,assetCount:s.length,routes:c||[]},null,2)}]};try{let f=await t.publishMicroService({microService:a,assets:s,routes:c||[],DeliveryBatchId:u||et.default.randomUUID(),SourceManifestHash:l||""});if(f.Code!==1)return{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0};let h=String(a.MsKey||a.MicroServiceKey||a.AppKey||"").trim(),m=h?await t.probeMicroAppEntry(h):{ok:!1,url:"",error:"Cannot probe runtime because MsKey is missing"};for(let y of[250,750,1500]){if(m.ok||!h)break;await new Promise(v=>setTimeout(v,y)),m=await t.probeMicroAppEntry(h)}let g={...f.Data&&typeof f.Data=="object"?f.Data:{},RuntimeProbe:m,PublishedButUnavailable:!m.ok,...m.ok?{}:{Warning:"\u53D1\u5E03\u5143\u6570\u636E\u548C\u8D44\u4EA7\u5199\u5165\u5DF2\u5B8C\u6210\uFF0C\u4F46\u7A33\u5B9A\u5165\u53E3\u4E0D\u53EF\u7528\u3002\u8BF7\u68C0\u67E5 API \u8282\u70B9\u5230\u79DF\u6237 HDFS/MinIO \u516C\u6709\u6876\u7684\u670D\u52A1\u7AEF\u8BFB\u53D6\u94FE\u8DEF\uFF1B\u4E0D\u8981\u65E0\u5224\u65AD\u91CD\u590D\u53D1\u5E03\u3002"}};return{content:[{type:"text",text:JSON.stringify(g,null,2)}],...m.ok?{}:{isError:!0}}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),I$(i,t,e),_$(i,t,e),S$(i,t,e),k$(i,t,e),A$(i,t,e),o.flush(e.codexMode?["microi_codex"]:void 0),i}function DQ(t){let e=t.trim();if(!e||!/^[A-Za-z0-9+/]+={0,2}$/.test(e)||e.length%4!==0)return"";let r=Buffer.from(e,"base64");return r.toString("base64").replace(/=+$/,"")!==e.replace(/=+$/,"")?"":r.toString("utf8")}function A2(t){let e=t.MICROI_LABEL_BASE64||"";if(e){let r=DQ(e);if(r)return r}return t.MICROI_LABEL||""}function I2(t,e,r,n="",i=""){try{let o=JSON.parse(Cl.default.readFileSync(t,"utf-8")),a=String(e||"").replace(/\/+$/,""),s=Up(e,r,n,i),c=r?s.filter(u=>u!==a):s;return Fp(c.map(u=>o[u]))||o[a]}catch{return}}function FQ(t){let e=t.body,r=String(t.headers["content-type"]||"");if(typeof e=="string"){/^application\/json\b/i.test(r)||(t.headers["content-type"]="application/json");try{return JSON.parse(e)}catch{return e}}if(e&&typeof e=="object")return/^application\/json\b/i.test(r)||(t.headers["content-type"]="application/json"),e}async function zQ(){let t={apiBaseUrl:(process.env.MICROI_API_URL||"").replace(/\/+$/,""),username:process.env.MICROI_USERNAME||"",password:process.env.MICROI_PASSWORD||"",osClient:process.env.MICROI_OS_CLIENT||"",osClientType:process.env.MICROI_OS_CLIENT_TYPE||"",osClientNetwork:process.env.MICROI_OS_CLIENT_NETWORK||"",rsaPublicKey:process.env.MICROI_RSA_PUBLIC_KEY||void 0,token:process.env.MICROI_TOKEN||void 0,workspaceCredentialFilePath:process.env.MICROI_WORKSPACE_CREDENTIAL_FILE||void 0,workspaceCredentialUsernameKey:process.env.MICROI_WORKSPACE_USERNAME_KEY||void 0,workspaceCredentialPasswordKey:process.env.MICROI_WORKSPACE_PASSWORD_KEY||void 0};/^https:\/\/(localhost|127\.0\.0\.1)(:\d+)?/i.test(t.apiBaseUrl)&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0",console.error("[microi-mcp] Detected localhost HTTPS, disabled TLS certificate verification"));let e=process.env.MICROI_TOKEN_FILE;if(e){t.tokenFilePath=e,t.authRecoveryRequestDir=process.env.MICROI_AUTH_RECOVERY_DIR||void 0;let n=I2(e,t.apiBaseUrl,t.osClient||"",t.osClientType||"",t.osClientNetwork||"");n&&(t.token=n)}if((process.env.MCP_TRANSPORT||"stdio")==="sse")t.apiBaseUrl||(console.error("Missing required: MICROI_API_URL (Microi backend API URL)"),process.exit(1)),await jQ(parseInt(process.env.MCP_PORT||"3000",10),t);else{t.apiBaseUrl||(console.error("Missing required: MICROI_API_URL"),process.exit(1));let n=!!t.workspaceCredentialFilePath&&!!t.workspaceCredentialUsernameKey&&!!t.workspaceCredentialPasswordKey&&Cl.default.existsSync(t.workspaceCredentialFilePath);!t.token&&(!t.username||!t.password)&&!n&&(console.error("Missing required environment variables:"),console.error(" MICROI_API_URL - Microi backend API URL (e.g. https://api.example.com)"),console.error(" MICROI_TOKEN_FILE - Token file path (preferred, auto-managed by VS Code extension)"),console.error(" MICROI_AUTH_RECOVERY_DIR - Optional credential-free VS Code recovery request directory"),console.error(" MICROI_WORKSPACE_CREDENTIAL_FILE - Optional Windows DPAPI workspace credential vault"),console.error(" MICROI_TOKEN - JWT token (fallback)"),console.error(" MICROI_USERNAME - Login username (fallback if no token)"),console.error(" MICROI_PASSWORD - Login password (fallback if no token)"),console.error("Optional:"),console.error(" MICROI_OS_CLIENT - OsClient identifier"),console.error(" MICROI_OS_CLIENT_TYPE - Optional OsClient type for exact token identity"),console.error(" MICROI_OS_CLIENT_NETWORK - Optional OsClient network for exact token identity"),process.exit(1));let i=new Nc(t);await i.login();let o={osClient:t.osClient||"",osClientType:t.osClientType||"",osClientNetwork:t.osClientNetwork||"",apiBaseUrl:t.apiBaseUrl,label:A2(process.env),codexMode:process.env.MICROI_CODEX_MODE==="1"},a=j0(i,o);await LQ(a),e&&Cl.default.watchFile(e,{interval:5e3},()=>{let c=I2(e,t.apiBaseUrl,t.osClient||"",t.osClientType||"",t.osClientNetwork||"");c&&(i.updateToken(c),console.error("[microi-mcp] Token updated from file"))});let s=()=>{e&&Cl.default.unwatchFile(e),i.destroy(),process.exit(0)};process.on("SIGINT",s),process.on("SIGTERM",s)}}async function LQ(t){let e=new bu;await t.connect(e),console.error("[microi-mcp] Server started (stdio mode)")}async function jQ(t,e){let r=(0,hf.default)();r.use(hf.default.json({type:["application/json","application/*+json"],limit:"4mb"})),r.use(hf.default.text({type:["text/plain","application/json-rpc"],limit:"4mb"}));let n=new Map;r.get("/sse",async(o,a)=>{let s=o.headers["x-microi-username"]||e.username,c=o.headers["x-microi-password"]||e.password,l=o.headers["x-microi-osclient"]||e.osClient||"";if(!s||!c){a.status(401).json({error:"Authentication required",message:"Provide X-Microi-Username and X-Microi-Password in request headers, or set MICROI_USERNAME / MICROI_PASSWORD environment variables."});return}try{let u=new Nc({apiBaseUrl:e.apiBaseUrl,username:s,password:c,osClient:l,osClientType:e.osClientType,osClientNetwork:e.osClientNetwork,rsaPublicKey:e.rsaPublicKey});await u.login();let p={osClient:l||"",osClientType:e.osClientType||"",osClientNetwork:e.osClientNetwork||"",apiBaseUrl:e.apiBaseUrl,label:""},f=j0(u,p),h=new Du("/messages",a);n.set(h.sessionId,{transport:h,client:u}),a.on("close",()=>{let m=n.get(h.sessionId);m&&(m.client.destroy(),n.delete(h.sessionId),console.error(`[microi-mcp] Session ${h.sessionId} disconnected (user: ${s})`))}),console.error(`[microi-mcp] New session ${h.sessionId} (user: ${s}, osClient: ${l||"default"})`),await f.connect(h)}catch(u){let p=u instanceof Error?u.message:String(u);console.error(`[microi-mcp] SSE auth failed (user: ${s}): ${p}`),a.headersSent||a.status(401).json({error:"Authentication failed",message:p})}}),r.post("/messages",async(o,a)=>{let s=o.query.sessionId,c=n.get(s);if(!c){a.status(404).json({error:"Session not found"});return}await c.transport.handlePostMessage(o,a,FQ(o))}),r.get("/health",(o,a)=>{a.json({status:"ok",server:"microi-mcp-server",version:"1.0.0",activeSessions:n.size})});let i=()=>{for(let[o,a]of n)a.client.destroy(),n.delete(o);process.exit(0)};process.on("SIGINT",i),process.on("SIGTERM",i),r.listen(t,()=>{console.error(`[microi-mcp] Server started (SSE mode) on http://localhost:${t}`),console.error(`[microi-mcp] SSE endpoint: http://localhost:${t}/sse`),console.error(`[microi-mcp] Auth: ${e.username?"env defaults available":"headers required"}`)})}zQ().catch(t=>{console.error("[microi-mcp] Fatal error:",t instanceof Error?t.message:t),process.exit(1)});
608
+ - PageId: ${y?.PageId}`}]}}catch(m){return{content:[{type:"text",text:`Error: ${m instanceof Error?m.message:String(m)}`}],isError:!0}}}),i.tool("microi_list_applications",`List every online AI application for OsClient "${r}" across Web, UniApp and MicroService, including each app's complete source-file manifest by default. AI agents should call this at the beginning of application/page work so they understand existing apps before creating duplicates. For complex custom dialogs/pages, prefer extending an existing MicroService or creating one with microi_create_microservice + microi_sync_microservice_source; do not embed large HTML in V8.ConfirmTips.`,{appType:d.enum(["Web","UniApp","MicroService"]).optional().describe("Optional exact application type filter."),keyword:d.string().optional().describe("Optional case-insensitive search across name, AppKey, type and description."),includeFiles:d.boolean().optional().default(!0).describe("Include the complete file manifest for every app. Defaults to true.")},async({appType:a,keyword:s,includeFiles:c})=>{try{let l=await t.listApplications({AppType:a,Keyword:s,IncludeFiles:c!==!1});return l.Code!==1?{content:[{type:"text",text:`Error: ${l.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(l.Data,null,2)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_get_application_context",`Get one Web, UniApp or MicroService application by Id/AppKey for OsClient "${r}". It returns metadata and the full file manifest by default without embedding source bodies; set includeContents=true only when the complete source is actually needed, or use microi_get_application_file for one exact file. MicroService responses also include sys_microiservice runtime/pages.`,{appIdOrKey:d.string().describe("sys_microistore.Id or AppKey."),includeContents:d.boolean().optional().default(!1).describe("Read private HDFS source contents. Defaults to false; prefer microi_get_application_file for targeted reads."),maxFileBytes:d.number().int().positive().optional().describe("Maximum bytes read per source file. Default 2MB."),maxTotalBytes:d.number().int().positive().optional().describe("Maximum total bytes read for this app. Default 50MB.")},async({appIdOrKey:a,includeContents:s,maxFileBytes:c,maxTotalBytes:l})=>{try{let u=await t.getApplicationContext({AppIdOrKey:a,IncludeContents:s===!0,...c?{MaxFileBytes:c}:{},...l?{MaxTotalBytes:l}:{}});if(u.Code!==1)return{content:[{type:"text",text:`Error: ${u.Msg}`}],isError:!0};let p=u.Data,h=(Array.isArray(p?.Files)?p.Files:[]).filter(g=>typeof g?.ContentReadError=="string"&&g.ContentReadError).length,m={...p,McpReadSummary:{RequestedContents:s===!0,ContentsComplete:s!==!0||h===0,ContentErrorCount:h}};return{content:[{type:"text",text:JSON.stringify(m,null,2)}]}}catch(u){return{content:[{type:"text",text:`Error: ${u instanceof Error?u.message:String(u)}`}],isError:!0}}}),i.tool("microi_get_application_file",`Read one exact source file from a Web, UniApp or MicroService online AI application for OsClient "${r}". Text code is returned as UTF-8 Content; binary files are returned as FileByteBase64.`,{appIdOrKey:d.string().describe("sys_microistore.Id or AppKey."),filePath:d.string().describe("Exact relative source path from the application file manifest."),maxFileBytes:d.number().int().positive().optional().describe("Maximum bytes read. Default 10MB.")},async({appIdOrKey:a,filePath:s,maxFileBytes:c})=>{try{let l=await t.getApplicationFile({AppIdOrKey:a,FilePath:s,IncludeContents:!0,...c?{MaxFileBytes:c}:{}});return l.Code!==1?{content:[{type:"text",text:`Error: ${l.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(l.Data,null,2)}]}}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.tool("microi_scaffold_vue_microservice",`Create a safe, maintainable MicroService scaffold for OsClient "${r}" using the stable Vue 3.5.40 + Vite 7.3.6 + TypeScript 5.9.3 baseline, @vitejs/plugin-vue 6.0.8, vue-tsc 3.3.9, Composition API and <script setup lang="ts">. The minimal template keeps Microi SDK and host/internal-route integration but does not force Pinia or Vue Router; add either only when application complexity needs it. It writes .microi-micro-app.json, microi.routes.json and exactly one Vue component per declared route inside the local tenant AI\u5E94\u7528 directory. It only accepts a real absolute directory whose basename is AI\u5E94\u7528, never overwrites a different existing project, and performs a dry run until confirmExecution exactly equals appKey. After scaffolding, run npm install and npm run build, then use microi_create_microservice, microi_sync_microservice_source and microi_publish_application_directory_stream (or the legacy publisher for a tiny compatibility payload).`,{appKey:d.string().regex(/^[a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?$/u).describe("Stable lowercase application key and local directory name."),name:d.string().min(1).max(120).describe("Human-readable MicroService name."),description:d.string().optional().describe("Optional application description."),aiApplicationsDirectory:d.string().optional().describe("Absolute tenant AI\u5E94\u7528 directory. Defaults to MICROI_AI_APPLICATIONS_DIR injected by Microi.Code."),buildVersion:d.string().regex(/^v\d+\.\d+\.\d+$/u).optional().default("v0.1.0").describe("Initial semantic build version. Default v0.1.0."),routes:d.array(d.object({path:d.string().describe("Internal route path such as /context-test."),name:d.string().describe("Stable route key such as context-test."),title:d.string().describe("Page/menu title."),description:d.string().optional().describe("Optional visible page explanation."),isHome:d.boolean().optional().describe("Mark one route as the default page. The first route is used when omitted.")})).min(1).max(50).describe("Vue pages and MicroService internal routes. One .vue file is generated per item."),confirmExecution:d.string().optional().describe("Required for filesystem writes and must exactly equal appKey. Omit for a local preflight only.")},async({appKey:a,name:s,description:c,aiApplicationsDirectory:l,buildVersion:u,routes:p,confirmExecution:f})=>{try{let h=String(l||process.env.MICROI_AI_APPLICATIONS_DIR||"").trim();if(!h)return{content:[{type:"text",text:"Error: \u7F3A\u5C11 AI \u5E94\u7528\u76EE\u5F55\u3002\u8BF7\u7531 Microi.Code \u6CE8\u5165 MICROI_AI_APPLICATIONS_DIR\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 aiApplicationsDirectory\u3002"}],isError:!0};if(f&&f!==a)return{content:[{type:"text",text:`Error: confirmExecution \u5FC5\u987B\u7CBE\u786E\u7B49\u4E8E ${a}`}],isError:!0};let m={aiApplicationsDirectory:h,appKey:a,name:s,description:c,apiBaseUrl:e.apiBaseUrl,osClient:r,buildVersion:u,routes:p,sdkSource:e2(process.env.MICROI_WORKSPACE_ROOT)},g=O0(m);if(f!==a)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,confirmationRequired:a,targetDirectory:g.targetDirectory,appKey:g.appKey,buildVersion:g.buildVersion,routeCount:g.routes.length,routes:g.routes.map(v=>({path:v.path,name:v.name,title:v.title,sourceFile:v.sourceFile,isHome:v.isHome})),fileCount:g.files.length,files:g.files.map(v=>({Path:v.relativePath,Size:v.size,Sha256:v.sha256}))},null,2)}]};let y=t2(m);return{content:[{type:"text",text:JSON.stringify(y,null,2)}]}}catch(h){return{content:[{type:"text",text:`Error: ${h instanceof Error?h.message:String(h)}`}],isError:!0}}}),i.tool("microi_get_microservice",`Get one Microi microservice / micro-app by MsKey for OsClient "${r}". Use this before publishing to inspect current BuildVersion, EntryPath and asset manifest.`,{msKey:d.string().describe("Microservice key, stored in sys_microiservice.MsKey")},async({msKey:a})=>{try{let s=await t.getMicroService(a);return s.Code!==1?{content:[{type:"text",text:`Error: ${s.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(s.Data,null,2)}]}}catch(s){return{content:[{type:"text",text:`Error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}}),i.tool("microi_create_microservice",`Create or update sys_microiservice metadata for OsClient "${r}". This only writes metadata. For generated app source/dist files, use microi_publish_microservice.`,{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: MsType, Runtime, StorageMode, SourceDirName, EntryPath, BuildVersion."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,confirmExecution:s})=>{if(!s)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,microService:a},null,2)}]};try{let c=await t.createMicroService(a);return c.Code!==1?{content:[{type:"text",text:`Error: ${c.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(c.Data,null,2)}]}}catch(c){return{content:[{type:"text",text:`Error: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_sync_microservice_source",`Sync a local Web, UniApp or MicroService source directory into the online AI Application for OsClient "${r}". Prefer directory: MCP detects SourceStreamPublish, streams each original file into the private staged prefix, then atomically finalizes the complete manifest with CurrentVersion/AppVersion/SourceManifestHash CAS. Transport failures are read back before any exact replay. Old servers use bounded legacy JSON only for at most 256 files and 8MiB. AI agents must never read large files into Base64, create .sync-seg-* files, create sync-source-files.json, or split one source file across tool calls.`,{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: Description and SourceDirName."),directory:d.string().optional().describe("Preferred. Absolute local project directory; MCP reads it directly and excludes node_modules, dist, build, coverage, caches and VCS data."),sourceFiles:d.array(Tt).optional().describe("Legacy compatibility only. Do not construct this array from manually split files when a local directory is available."),replace:d.boolean().optional().describe("Complete directory sync defaults to exact private-source replacement. Explicit false is rejected by the stream protocol; public runtime/build rows are always preserved."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,directory:s,sourceFiles:c,replace:l,confirmExecution:u})=>gQ(t,{microService:a,directory:s,sourceFiles:c,replace:l,confirmExecution:u})),i.tool("microi_clear_application_source",`Remove an AI application's private HDFS source objects, private mci_ai_app_file rows, public SourceZip objects and source-delivery flags while preserving compiled runtime/build assets for OsClient "${r}". This is intentionally destructive and two-phase: first call without confirmExecution to obtain the exact target list and confirmationSha256, then pass that hash unchanged. Keep a verified local source checkout before executing.`,{appIdOrKey:d.string().min(1).describe("Exact AppId or AppKey. No wildcard or bulk deletion is supported."),confirmExecution:d.string().optional().describe("Exact confirmationSha256 returned by the backend dry run.")},async({appIdOrKey:a,confirmExecution:s})=>{try{let c=await t.clearApplicationSource({AppIdOrKey:a,...s?{ConfirmExecution:s}:{}});return{content:[{type:"text",text:JSON.stringify(c,null,2)}],structuredContent:c,...c.Code!==1?{isError:!0}:{}}}catch(c){return{content:[{type:"text",text:`Clear application source failed: ${c instanceof Error?c.message:String(c)}`}],isError:!0}}}),i.tool("microi_upload_application_asset_stream",`Stream one local built asset directly to the immutable HDFS version directory for OsClient "${r}". Protocol v3 uses durable HDFS multipart sessions with status readback and reconnect resume for ordinary files through multi-GiB installers; bytes are never encoded as Base64 and never enter Jint. This is a low-level primitive inside a frozen release contract; normally use microi_publish_application_directory_stream to upload and atomically promote a complete directory.`,{appIdOrKey:d.string().min(1).describe("Existing sys_microistore Id or AppKey."),versionNo:d.string().regex(/^v?\d+\.\d+\.\d+$/u).describe("Immutable semantic version, e.g. v1.2.3."),relativePath:d.string().min(1).describe("POSIX-style path inside the compiled output, e.g. assets/index-abcd.js."),localFilePath:d.string().min(1).describe("Absolute or workspace-relative path of one local ordinary file."),sha256:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional expected SHA-256. MCP computes and verifies it when omitted."),routes:d.array(Tt).optional().default([]).describe("Canonical v3 route snapshot input; missing routes are frozen explicitly as []."),routeSnapshotJson:d.string().max(1024*1024).optional().describe("Protocol v3 requires the exact recursive-key-sorted, array-order-preserving UTF-8 canonical JSON for routes."),routeSnapshotHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the lowercase SHA-256 of RouteSnapshotJson."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Protocol v3 source-manifest SHA-256 tying this asset to the release."),runtimeManifestHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 exact runtime-manifest SHA-256 for the frozen release."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Protocol v3 stable delivery batch id."),protocolVersion:d.literal(3).optional().describe("Enable durable v3 multipart/resume. All v3 release identity and CAS fields then become required."),expectedGateEpoch:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 gate epoch as a canonical decimal bigint string."),requestId:d.string().regex(/^[A-Za-z0-9._:-]{8,100}$/u).optional().describe("Protocol v3 stable release RequestId; every asset and stage/finalize replay must reuse it exactly."),requestFingerprint:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 immutable release fingerprint."),expectedCurrentVersion:d.number().int().min(0).optional().describe("Protocol v3 application CurrentVersion baseline."),expectedAppVersion:d.string().nullable().optional().describe("Protocol v3 application AppVersion baseline; explicit null means empty."),expectedPublishFence:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishFence baseline."),expectedPublishRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishRowVersion baseline."),expectedVersionRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).nullable().optional().describe("Protocol v3 target version RowVersion; explicit null means absent."),expectedActivePublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 active version id baseline; explicit null means empty."),expectedCommittedPublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 committed version id baseline; explicit null means empty."),timeoutMs:d.number().int().min(1e3).max(2*60*6e4).optional().describe("Per-file upload timeout. Default 30 minutes; maximum 2 hours."),confirmExecution:d.string().optional().describe("Required for the real upload and must exactly equal appIdOrKey.")},async a=>xQ(t,a)),i.tool("microi_publish_application_directory_stream",`Publish a real Web, UniApp or MicroService build directory for OsClient "${r}" using deterministic RequestId evidence. Protocol v3 automatically switches files above the legacy 128 MiB request boundary to durable HDFS multipart sessions with per-part SHA-256, status readback and reconnect resume; logical files such as 5 GiB installers never enter Base64/Jint or whole-file memory. publishMode=stage uploads immutable version assets only; finalize rebuilds the same local manifest and promotes it without uploading; stage-and-finalize keeps the original one-call flow. Paths, hashes, sizes, request ids, version preconditions and final manifest evidence are verified strictly. Old API nodes without the resumable endpoints fail closed for oversized assets.`,{appIdOrKey:d.string().min(1).describe("Existing sys_microistore Id or AppKey."),versionNo:d.string().regex(/^v?\d+\.\d+\.\d+$/u).describe("Immutable semantic version, e.g. v1.2.3."),directory:d.string().min(1).describe("Local compiled output directory such as dist or unpackage/dist/build/h5."),entryPath:d.string().optional().default("index.html").describe("Entry file relative to directory. Default index.html."),routes:d.array(Tt).optional().default([]).describe("Canonical v3 route snapshot input; missing routes are frozen explicitly as []."),routeSnapshotJson:d.string().max(1024*1024).optional().describe("Protocol v3 requires the exact recursive-key-sorted, array-order-preserving UTF-8 canonical JSON for routes."),routeSnapshotHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the lowercase SHA-256 of RouteSnapshotJson."),changeSummary:d.string().max(2e3).optional().describe("Version change summary stored in mci_ai_app_version on first stage insert. Maximum 2000 characters; retries preserve the original summary."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional source-manifest SHA-256 returned by microi_sync_microservice_source, tying source and runtime to one delivery."),runtimeManifestHash:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 requires the exact lowercase runtime-manifest SHA-256 computed during the local dry run."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Optional stable delivery batch id (8-50 characters, matching the API and LastBuildTaskId). When omitted MCP derives a deterministic id from app/version/manifest so retries remain stable."),publishMode:d.enum(["stage","finalize","stage-and-finalize"]).optional().default("stage-and-finalize").describe("stage uploads immutable assets only; finalize submits the local manifest only; stage-and-finalize preserves the original one-call behavior."),verificationOnly:d.boolean().optional().default(!1).describe("Protocol v3 stage only: submit/read the same frozen verification task without uploading files again. Pending is not ReleaseVerified and never permits finalize."),protocolVersion:d.literal(3).optional().describe("Explicit protocol v3 gate. When set, publishMode must be explicit stage or finalize and every v3 precondition is required."),expectedGateEpoch:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 gate epoch as a canonical decimal bigint string."),requestId:d.string().regex(/^[A-Za-z0-9._:-]{8,100}$/u).optional().describe("Protocol v3 stable release RequestId; stage/finalize and all Pending replays must reuse it exactly."),requestFingerprint:d.string().regex(/^[a-f0-9]{64}$/u).optional().describe("Protocol v3 immutable release fingerprint."),expectedCurrentVersion:d.number().int().min(0).optional().describe("Required for finalize/stage-and-finalize and omitted only during stage. Must equal the application CurrentVersion read before staging."),expectedAppVersion:d.string().nullable().optional().describe("Application AppVersion baseline. Protocol v3 requires explicit string or null for both stage and finalize."),expectedPublishFence:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishFence canonical decimal bigint string."),expectedPublishRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).optional().describe("Protocol v3 sys_microistore.PublishRowVersion canonical decimal bigint string."),expectedVersionRowVersion:d.string().regex(/^(0|[1-9]\d*)$/u).nullable().optional().describe("Protocol v3 target mci_ai_app_version.RowVersion; explicit null means the row must not exist."),expectedActivePublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 active version id baseline; explicit null means empty."),expectedCommittedPublishVersionId:d.string().min(1).nullable().optional().describe("Protocol v3 committed version id baseline; explicit null means empty."),includeSourceMaps:d.boolean().optional().default(!1).describe("Publish *.map source maps. Defaults to false to avoid source disclosure."),maxFiles:d.number().int().min(1).max(2e4).optional().describe("Safety cap checked before upload. Default and hard maximum 20,000."),maxTotalMegabytes:d.number().positive().max(Number.MAX_SAFE_INTEGER/(1024*1024)).optional().describe("Optional caller safety cap checked before upload. Omit for the platform maximum; 5 GiB and larger builds use resumable HDFS multipart."),timeoutMsPerFile:d.number().int().min(1e3).max(2*60*6e4).optional().describe("Per-file upload timeout. Default 30 minutes."),allowLegacyFallback:d.boolean().optional().default(!1).describe("Deprecated compatibility flag. RequestId-capable two-phase publishing fails closed on old API nodes instead of publishing through the legacy payload."),confirmExecution:d.string().optional().describe("Required for real publishing and must exactly equal appIdOrKey. Omit for a local preflight manifest only.")},async({appIdOrKey:a,versionNo:s,directory:c,entryPath:l,routes:u,routeSnapshotJson:p,routeSnapshotHash:f,changeSummary:h,sourceManifestHash:m,runtimeManifestHash:g,deliveryBatchId:y,publishMode:v,verificationOnly:x,protocolVersion:b,expectedGateEpoch:w,requestId:E,requestFingerprint:S,expectedCurrentVersion:k,expectedAppVersion:A,expectedPublishFence:R,expectedPublishRowVersion:I,expectedVersionRowVersion:C,expectedActivePublishVersionId:j,expectedCommittedPublishVersionId:F,includeSourceMaps:V,maxFiles:J,maxTotalMegabytes:X,timeoutMsPerFile:Ae,allowLegacyFallback:ke,confirmExecution:le})=>_Q(t,{appIdOrKey:a,versionNo:s,directory:c,entryPath:l,routes:u,routeSnapshotJson:p,routeSnapshotHash:f,changeSummary:h,sourceManifestHash:m,runtimeManifestHash:g,deliveryBatchId:y,publishMode:v,verificationOnly:x,protocolVersion:b,expectedGateEpoch:w,requestId:E,requestFingerprint:S,expectedCurrentVersion:k,expectedAppVersion:A,expectedPublishFence:R,expectedPublishRowVersion:I,expectedVersionRowVersion:C,expectedActivePublishVersionId:j,expectedCommittedPublishVersionId:F,includeSourceMaps:V,maxFiles:J,maxTotalMegabytes:X,timeoutMsPerFile:Ae,allowLegacyFallback:ke,confirmExecution:le})),i.tool("microi_publish_microservice","Legacy small-payload publisher for generated microservice / micro-app files in Base64. For real compiled directories or large assets, use microi_publish_application_directory_stream so bytes stream directly to HDFS and never enter JSON/Jint.",{microService:Tt.describe("Microservice metadata. Required: MsKey and MsName/Name. Optional: BuildVersion, EntryPath, SourceDirName."),assets:d.array(Tt).describe("Built asset files. Each item needs Path/RelativePath/FileName and FileByteBase64/ContentBase64. Mark the main HTML/JS entry with IsEntry=true or Entry=true."),routes:d.array(Tt).optional().describe("Optional route/page records for sys_microiservice_page. Fields: PageKey, PageName, PageTitle, RoutePath, EntryPath, SourceDirName, SourceFile, RouteMetaJson, Sort, IsHome."),sourceManifestHash:d.string().regex(/^[a-fA-F0-9]{64}$/u).optional().describe("Optional source-manifest SHA-256 returned by source sync."),deliveryBatchId:d.string().min(8).max(50).optional().describe("Optional stable delivery batch id (8-50 characters, matching the API and LastBuildTaskId). MCP generates one when omitted."),confirmExecution:d.string().optional().describe("Required for real writes. Pass any non-empty confirmation string after reviewing the payload.")},async({microService:a,assets:s,routes:c,sourceManifestHash:l,deliveryBatchId:u,confirmExecution:p})=>{if(!p)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,microService:a,assetCount:s.length,routes:c||[]},null,2)}]};try{let f=await t.publishMicroService({microService:a,assets:s,routes:c||[],DeliveryBatchId:u||et.default.randomUUID(),SourceManifestHash:l||""});if(f.Code!==1)return{content:[{type:"text",text:`Error: ${f.Msg}`}],isError:!0};let h=String(a.MsKey||a.MicroServiceKey||a.AppKey||"").trim(),m=h?await t.probeMicroAppEntry(h):{ok:!1,url:"",error:"Cannot probe runtime because MsKey is missing"};for(let y of[250,750,1500]){if(m.ok||!h)break;await new Promise(v=>setTimeout(v,y)),m=await t.probeMicroAppEntry(h)}let g={...f.Data&&typeof f.Data=="object"?f.Data:{},RuntimeProbe:m,PublishedButUnavailable:!m.ok,...m.ok?{}:{Warning:"\u53D1\u5E03\u5143\u6570\u636E\u548C\u8D44\u4EA7\u5199\u5165\u5DF2\u5B8C\u6210\uFF0C\u4F46\u7A33\u5B9A\u5165\u53E3\u4E0D\u53EF\u7528\u3002\u8BF7\u68C0\u67E5 API \u8282\u70B9\u5230\u79DF\u6237 HDFS/MinIO \u516C\u6709\u6876\u7684\u670D\u52A1\u7AEF\u8BFB\u53D6\u94FE\u8DEF\uFF1B\u4E0D\u8981\u65E0\u5224\u65AD\u91CD\u590D\u53D1\u5E03\u3002"}};return{content:[{type:"text",text:JSON.stringify(g,null,2)}],...m.ok?{}:{isError:!0}}}catch(f){return{content:[{type:"text",text:`Error: ${f instanceof Error?f.message:String(f)}`}],isError:!0}}}),I$(i,t,e),_$(i,t,e),S$(i,t,e),k$(i,t,e),A$(i,t,e),o.flush(e.codexMode?["microi_codex"]:void 0),i}function DQ(t){let e=t.trim();if(!e||!/^[A-Za-z0-9+/]+={0,2}$/.test(e)||e.length%4!==0)return"";let r=Buffer.from(e,"base64");return r.toString("base64").replace(/=+$/,"")!==e.replace(/=+$/,"")?"":r.toString("utf8")}function A2(t){let e=t.MICROI_LABEL_BASE64||"";if(e){let r=DQ(e);if(r)return r}return t.MICROI_LABEL||""}function I2(t,e,r,n="",i=""){try{let o=JSON.parse(Cl.default.readFileSync(t,"utf-8")),a=String(e||"").replace(/\/+$/,""),s=Up(e,r,n,i),c=r?s.filter(u=>u!==a):s;return Fp(c.map(u=>o[u]))||o[a]}catch{return}}function FQ(t){let e=t.body,r=String(t.headers["content-type"]||"");if(typeof e=="string"){/^application\/json\b/i.test(r)||(t.headers["content-type"]="application/json");try{return JSON.parse(e)}catch{return e}}if(e&&typeof e=="object")return/^application\/json\b/i.test(r)||(t.headers["content-type"]="application/json"),e}async function zQ(){let t={apiBaseUrl:(process.env.MICROI_API_URL||"").replace(/\/+$/,""),username:process.env.MICROI_USERNAME||"",password:process.env.MICROI_PASSWORD||"",osClient:process.env.MICROI_OS_CLIENT||"",osClientType:process.env.MICROI_OS_CLIENT_TYPE||"",osClientNetwork:process.env.MICROI_OS_CLIENT_NETWORK||"",rsaPublicKey:process.env.MICROI_RSA_PUBLIC_KEY||void 0,token:process.env.MICROI_TOKEN||void 0,workspaceCredentialFilePath:process.env.MICROI_WORKSPACE_CREDENTIAL_FILE||void 0,workspaceCredentialUsernameKey:process.env.MICROI_WORKSPACE_USERNAME_KEY||void 0,workspaceCredentialPasswordKey:process.env.MICROI_WORKSPACE_PASSWORD_KEY||void 0};/^https:\/\/(localhost|127\.0\.0\.1)(:\d+)?/i.test(t.apiBaseUrl)&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0",console.error("[microi-mcp] Detected localhost HTTPS, disabled TLS certificate verification"));let e=process.env.MICROI_TOKEN_FILE;if(e){t.tokenFilePath=e,t.authRecoveryRequestDir=process.env.MICROI_AUTH_RECOVERY_DIR||void 0;let n=I2(e,t.apiBaseUrl,t.osClient||"",t.osClientType||"",t.osClientNetwork||"");n&&(t.token=n)}if((process.env.MCP_TRANSPORT||"stdio")==="sse")t.apiBaseUrl||(console.error("Missing required: MICROI_API_URL (Microi backend API URL)"),process.exit(1)),await jQ(parseInt(process.env.MCP_PORT||"3000",10),t);else{t.apiBaseUrl||(console.error("Missing required: MICROI_API_URL"),process.exit(1));let n=!!t.workspaceCredentialFilePath&&!!t.workspaceCredentialUsernameKey&&!!t.workspaceCredentialPasswordKey&&Cl.default.existsSync(t.workspaceCredentialFilePath);!t.token&&(!t.username||!t.password)&&!n&&(console.error("Missing required environment variables:"),console.error(" MICROI_API_URL - Microi backend API URL (e.g. https://api.example.com)"),console.error(" MICROI_TOKEN_FILE - Token file path (preferred, auto-managed by VS Code extension)"),console.error(" MICROI_AUTH_RECOVERY_DIR - Optional credential-free VS Code recovery request directory"),console.error(" MICROI_WORKSPACE_CREDENTIAL_FILE - Optional Windows DPAPI workspace credential vault"),console.error(" MICROI_TOKEN - JWT token (fallback)"),console.error(" MICROI_USERNAME - Login username (fallback if no token)"),console.error(" MICROI_PASSWORD - Login password (fallback if no token)"),console.error("Optional:"),console.error(" MICROI_OS_CLIENT - OsClient identifier"),console.error(" MICROI_OS_CLIENT_TYPE - Optional OsClient type for exact token identity"),console.error(" MICROI_OS_CLIENT_NETWORK - Optional OsClient network for exact token identity"),process.exit(1));let i=new Nc(t);await i.login();let o={osClient:t.osClient||"",osClientType:t.osClientType||"",osClientNetwork:t.osClientNetwork||"",apiBaseUrl:t.apiBaseUrl,label:A2(process.env),codexMode:process.env.MICROI_CODEX_MODE==="1"},a=j0(i,o);await LQ(a),e&&Cl.default.watchFile(e,{interval:5e3},()=>{let c=I2(e,t.apiBaseUrl,t.osClient||"",t.osClientType||"",t.osClientNetwork||"");c&&(i.updateToken(c),console.error("[microi-mcp] Token updated from file"))});let s=()=>{e&&Cl.default.unwatchFile(e),i.destroy(),process.exit(0)};process.on("SIGINT",s),process.on("SIGTERM",s)}}async function LQ(t){let e=new bu;await t.connect(e),console.error("[microi-mcp] Server started (stdio mode)")}async function jQ(t,e){let r=(0,hf.default)();r.use(hf.default.json({type:["application/json","application/*+json"],limit:"4mb"})),r.use(hf.default.text({type:["text/plain","application/json-rpc"],limit:"4mb"}));let n=new Map;r.get("/sse",async(o,a)=>{let s=o.headers["x-microi-username"]||e.username,c=o.headers["x-microi-password"]||e.password,l=o.headers["x-microi-osclient"]||e.osClient||"";if(!s||!c){a.status(401).json({error:"Authentication required",message:"Provide X-Microi-Username and X-Microi-Password in request headers, or set MICROI_USERNAME / MICROI_PASSWORD environment variables."});return}try{let u=new Nc({apiBaseUrl:e.apiBaseUrl,username:s,password:c,osClient:l,osClientType:e.osClientType,osClientNetwork:e.osClientNetwork,rsaPublicKey:e.rsaPublicKey});await u.login();let p={osClient:l||"",osClientType:e.osClientType||"",osClientNetwork:e.osClientNetwork||"",apiBaseUrl:e.apiBaseUrl,label:""},f=j0(u,p),h=new Du("/messages",a);n.set(h.sessionId,{transport:h,client:u}),a.on("close",()=>{let m=n.get(h.sessionId);m&&(m.client.destroy(),n.delete(h.sessionId),console.error(`[microi-mcp] Session ${h.sessionId} disconnected (user: ${s})`))}),console.error(`[microi-mcp] New session ${h.sessionId} (user: ${s}, osClient: ${l||"default"})`),await f.connect(h)}catch(u){let p=u instanceof Error?u.message:String(u);console.error(`[microi-mcp] SSE auth failed (user: ${s}): ${p}`),a.headersSent||a.status(401).json({error:"Authentication failed",message:p})}}),r.post("/messages",async(o,a)=>{let s=o.query.sessionId,c=n.get(s);if(!c){a.status(404).json({error:"Session not found"});return}await c.transport.handlePostMessage(o,a,FQ(o))}),r.get("/health",(o,a)=>{a.json({status:"ok",server:"microi-mcp-server",version:"1.0.0",activeSessions:n.size})});let i=()=>{for(let[o,a]of n)a.client.destroy(),n.delete(o);process.exit(0)};process.on("SIGINT",i),process.on("SIGTERM",i),r.listen(t,()=>{console.error(`[microi-mcp] Server started (SSE mode) on http://localhost:${t}`),console.error(`[microi-mcp] SSE endpoint: http://localhost:${t}/sse`),console.error(`[microi-mcp] Auth: ${e.username?"env defaults available":"headers required"}`)})}zQ().catch(t=>{console.error("[microi-mcp] Fatal error:",t instanceof Error?t.message:t),process.exit(1)});
609
609
  /*! Bundled license information:
610
610
 
611
611
  bytes/index.js: