@microi.net/cli 5.8.6 → 5.8.8

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 (27) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.mcp.json +1 -1
  5. package/.workbuddy-plugin/marketplace.json +2 -2
  6. package/.workbuddy-plugin/plugin.json +1 -1
  7. package/assets/build-meta.json +4 -4
  8. package/cordis.patch.yml +1 -1
  9. package/package.json +1 -1
  10. package/scripts/codex-marketplace.json +20 -20
  11. package/scripts/mcp-codex-stdio-adapter.js +189 -189
  12. package/scripts/mcp-server.js +1 -1
  13. package/scripts/mcp-trae-windows-launcher.cmd +21 -21
  14. package/scripts/microi-cli-mcp.js +7 -7
  15. package/scripts/microi-skills.meta.json +206 -206
  16. package/skills/.microi-skills-version.json +2 -2
  17. package/skills/.progressive-disclosure-manifest.json +3566 -3566
  18. package/skills/dos-orm/SKILL.md +4 -2
  19. package/skills/microi-client-frontend/SKILL.md +10 -7
  20. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +3 -3
  21. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +3 -3
  22. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +3 -3
  23. package/skills/microi-codex/SKILL.md +3 -1
  24. package/skills/microi-deployment/SKILL.md +3 -1
  25. package/skills/microi-microservice/SKILL.md +2 -2
  26. package/skills/microi-sso/SKILL.md +7 -1
  27. package/skills/system-observability/SKILL.md +5 -2
@@ -574,7 +574,7 @@ ${JSON.stringify(g.Data,null,2)}`}]}}catch(g){return{content:[{type:"text",text:
574
574
  `)}]}}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.
575
575
 
576
576
  ${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=Vt(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(`
577
- `)}]}}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. RequestWaits groups pending admission/HTTP by tenant, API, stage and redacted dependency target; samples carry TraceId. Counts are requests/calls, never worker-thread counts. Evidence.CriticalStorage reports acknowledged MySQL writes, pending/dropped snapshots and errors; RelationalStorage in incident reads is independent of Mongo/local files. Only acknowledged critical evidence survives container file loss; MySqlCriticalEvidence omits raw allocation stacks and EvidenceTruncated must be reported. 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:m,pageIndex:h,pageSize:g,windowMinutes:y,windowSeconds:x,top:b,includeHost:v,includeDocker:_,traceId:w,incidentId:C,serviceName:E,apiEngineKey:T,name:A,lines:I,kind:R,status:F,dimensionType:z,rangeKey:j,hours:K,observedOsClient:ee,transferAction:_e,ip:me,userId:Ht,endpoint:Ir,poolTarget:fn,operationId:st})=>{try{if(a==="DatabasePoolRecovery"&&!st)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"&&!w)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"&&!C)return{content:[{type:"text",text:"\u8BF7\u5148\u67E5\u8BE2 MemoryIncidents\uFF0C\u5E76\u4F20\u5165 incidentId\u3002"}],isError:!0};let yt=await t.querySystemObservability({Action:a,...fn?{Target:fn}:{},...st?{OperationId:st}:{},...s?{Keyword:s,_Keyword:s}:{},...c?{Type:c}:{},...l?{Category:l}:{},...u?{Source:u}:{},...p===void 0?{}:{Level:p},...f===void 0?{}:{LevelMin:f},...m?{SearchMonth:m,_SearchMonth:m}:{},...h===void 0?{}:{PageIndex:h,_PageIndex:h},...g===void 0?{}:{PageSize:g,_PageSize:g},...y===void 0?{}:{WindowMinutes:y},...x===void 0?{}:{WindowSeconds:x},...b===void 0?{}:{Top:b},...v===void 0?{}:{IncludeHost:v},..._===void 0?{}:{IncludeDocker:_},...w?{TraceId:w.toLowerCase()}:{},...C?{IncidentId:C}:{},...E?{ServiceName:E}:{},...T?{ApiEngineKey:T}:{},...A?{Name:A}:{},...I===void 0?{}:{Lines:I},...R?{Kind:R}:{},...F?{Status:F}:{},...z?{DimensionType:z}:{},...j?{RangeKey:j}:{},...K===void 0?{}:{Hours:K},...ee?{ObservedOsClient:ee}:{},..._e?{TransferAction:_e}:{},...me?{Ip:me}:{},...Ht?{UserId:Ht}:{},...Ir?{Endpoint:Ir}:{}});return{content:[{type:"text",text:JSON.stringify({Code:yt.Code,Msg:yt.Msg||"",Data:yt.Data,DataCount:yt.DataCount,DataAppend:yt.DataAppend},null,2)}],...yt.Code===1?{}:{isError:!0}}}catch(yt){return{content:[{type:"text",text:`Error: ${yt instanceof Error?yt.message:String(yt)}`}],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:m})=>{try{if(a==="ResetDatabasePools"){if(!u){let b=await t.querySystemObservability({Action:"DatabasePools",Target:p||"Both"}),v=b.Data;return{content:[{type:"text",text:JSON.stringify({...b,dryRun:!0,requiredConfirmation:v?.OperationId?`ResetDatabasePools:${v.OperationId}`:void 0},null,2)}],...b.Code===1?{}:{isError:!0}}}if(!f||!m||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 x=await t.manageSystemObservability({Action:a,Target:p||"Both",OperationId:f,PoolIds:m,Confirm:u});return{content:[{type:"text",text:JSON.stringify(x,null,2)}],...x.Code===1?{}:{isError:!0}}}let h=(s||"").trim();if((0,KO.isIP)(h)===0)return{content:[{type:"text",text:"IP \u5730\u5740\u683C\u5F0F\u65E0\u6548\u3002"}],isError:!0};let g=`${a}:${h}`;if(u!==g)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,action:a,ip:h,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",h,JSON.stringify({action:a,blockMinutes:a==="BlockIp"?c||30:void 0}));let y=await t.manageSystemObservability({Action:a,Ip:h,...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(h){return{content:[{type:"text",text:`Error: ${h instanceof Error?h.message:String(h)}`}],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:m,timer:h,result:g,appId:y})=>{try{let x=await t.writeMongodbLog({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:m,timer:h,result:g,appId:y});return x.Code!==1?{content:[{type:"text",text:`Error: ${x.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(x.Data||{ok:!0},null,2)}]}}catch(x){return{content:[{type:"text",text:`Error: ${x instanceof Error?x.message:String(x)}`}],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:m,v8Limit:h,v8Unlimited:g})=>{try{let y=h??(g===void 0?void 0:!g),x=await t.createTable(a,s,{Tabs:c,IsTree:l,ReadPrimary:u,Column:p??2,FormOpenType:f||"Dialog",FormOpenWidth:m||"80%",V8Limit:y===void 0?void 0:y?1:0});if(x.Code!==1)return{content:[{type:"text",text:`Error: ${x.Msg}`}],isError:!0};let b=x.Data;return{content:[{type:"text",text:`\u2705 Table "${a}" created.
577
+ `)}]}}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. RequestWaits groups pending admission/HTTP by tenant, API, stage and redacted dependency target; samples carry TraceId. Counts are requests/calls, never worker-thread counts. Evidence.CriticalStorage reports acknowledged MySQL writes, pending/dropped snapshots and errors; RelationalStorage in incident reads is independent of Mongo/local files. Only acknowledged critical evidence survives container file loss; MySqlCriticalEvidence omits raw allocation stacks and EvidenceTruncated must be reported. 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\u56DE\u8BFB\u6700\u5927/\u6700\u5C0F\u6C60\u3001\u751F\u547D\u5468\u671F\u53CA CapacityBudget \u7684\u5F53\u524D\u8282\u70B9\u6240\u9009\u53BB\u91CD\u6C60\u914D\u7F6E\u5408\u8BA1\uFF0C\u4E0D\u662F\u5B9E\u9645\u5360\u7528\u6216\u96C6\u7FA4\u5168\u91CF\uFF0CQuartz/\u5176\u5B83\u8282\u70B9/\u6269\u5C55\u5E93/\u5916\u90E8\u5BA2\u6237\u7AEF\u987B\u53E6\u8BA1\u3002\u72EC\u7ACB\u5E94\u6025\u9274\u6743\uFF0C\u9700\u8981 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:m,pageIndex:h,pageSize:g,windowMinutes:y,windowSeconds:x,top:b,includeHost:v,includeDocker:_,traceId:w,incidentId:C,serviceName:E,apiEngineKey:T,name:A,lines:I,kind:R,status:F,dimensionType:z,rangeKey:j,hours:K,observedOsClient:ee,transferAction:_e,ip:me,userId:Ht,endpoint:Ir,poolTarget:fn,operationId:st})=>{try{if(a==="DatabasePoolRecovery"&&!st)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"&&!w)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"&&!C)return{content:[{type:"text",text:"\u8BF7\u5148\u67E5\u8BE2 MemoryIncidents\uFF0C\u5E76\u4F20\u5165 incidentId\u3002"}],isError:!0};let yt=await t.querySystemObservability({Action:a,...fn?{Target:fn}:{},...st?{OperationId:st}:{},...s?{Keyword:s,_Keyword:s}:{},...c?{Type:c}:{},...l?{Category:l}:{},...u?{Source:u}:{},...p===void 0?{}:{Level:p},...f===void 0?{}:{LevelMin:f},...m?{SearchMonth:m,_SearchMonth:m}:{},...h===void 0?{}:{PageIndex:h,_PageIndex:h},...g===void 0?{}:{PageSize:g,_PageSize:g},...y===void 0?{}:{WindowMinutes:y},...x===void 0?{}:{WindowSeconds:x},...b===void 0?{}:{Top:b},...v===void 0?{}:{IncludeHost:v},..._===void 0?{}:{IncludeDocker:_},...w?{TraceId:w.toLowerCase()}:{},...C?{IncidentId:C}:{},...E?{ServiceName:E}:{},...T?{ApiEngineKey:T}:{},...A?{Name:A}:{},...I===void 0?{}:{Lines:I},...R?{Kind:R}:{},...F?{Status:F}:{},...z?{DimensionType:z}:{},...j?{RangeKey:j}:{},...K===void 0?{}:{Hours:K},...ee?{ObservedOsClient:ee}:{},..._e?{TransferAction:_e}:{},...me?{Ip:me}:{},...Ht?{UserId:Ht}:{},...Ir?{Endpoint:Ir}:{}});return{content:[{type:"text",text:JSON.stringify({Code:yt.Code,Msg:yt.Msg||"",Data:yt.Data,DataCount:yt.DataCount,DataAppend:yt.DataAppend},null,2)}],...yt.Code===1?{}:{isError:!0}}}catch(yt){return{content:[{type:"text",text:`Error: ${yt instanceof Error?yt.message:String(yt)}`}],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:m})=>{try{if(a==="ResetDatabasePools"){if(!u){let b=await t.querySystemObservability({Action:"DatabasePools",Target:p||"Both"}),v=b.Data;return{content:[{type:"text",text:JSON.stringify({...b,dryRun:!0,requiredConfirmation:v?.OperationId?`ResetDatabasePools:${v.OperationId}`:void 0},null,2)}],...b.Code===1?{}:{isError:!0}}}if(!f||!m||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 x=await t.manageSystemObservability({Action:a,Target:p||"Both",OperationId:f,PoolIds:m,Confirm:u});return{content:[{type:"text",text:JSON.stringify(x,null,2)}],...x.Code===1?{}:{isError:!0}}}let h=(s||"").trim();if((0,KO.isIP)(h)===0)return{content:[{type:"text",text:"IP \u5730\u5740\u683C\u5F0F\u65E0\u6548\u3002"}],isError:!0};let g=`${a}:${h}`;if(u!==g)return{content:[{type:"text",text:JSON.stringify({dryRun:!0,action:a,ip:h,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",h,JSON.stringify({action:a,blockMinutes:a==="BlockIp"?c||30:void 0}));let y=await t.manageSystemObservability({Action:a,Ip:h,...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(h){return{content:[{type:"text",text:`Error: ${h instanceof Error?h.message:String(h)}`}],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:m,timer:h,result:g,appId:y})=>{try{let x=await t.writeMongodbLog({title:a,content:s,type:c,level:l,api:u,param:p,remark:f,otherInfo:m,timer:h,result:g,appId:y});return x.Code!==1?{content:[{type:"text",text:`Error: ${x.Msg}`}],isError:!0}:{content:[{type:"text",text:JSON.stringify(x.Data||{ok:!0},null,2)}]}}catch(x){return{content:[{type:"text",text:`Error: ${x instanceof Error?x.message:String(x)}`}],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:m,v8Limit:h,v8Unlimited:g})=>{try{let y=h??(g===void 0?void 0:!g),x=await t.createTable(a,s,{Tabs:c,IsTree:l,ReadPrimary:u,Column:p??2,FormOpenType:f||"Dialog",FormOpenWidth:m||"80%",V8Limit:y===void 0?void 0:y?1:0});if(x.Code!==1)return{content:[{type:"text",text:`Error: ${x.Msg}`}],isError:!0};let b=x.Data;return{content:[{type:"text",text:`\u2705 Table "${a}" created.
578
578
  - TableId: ${b?.TableId}
579
579
  - 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:
580
580
  - SQL source: '{"DataSource":"Sql","Sql":"select Id,Name from t where Name like \\'%$Keyword$%\\' limit 0,20","SelectLabel":"Name","SelectSaveField":"Id","DataSourceSqlRemote":true}'
@@ -1,21 +1,21 @@
1
- @echo off
2
- setlocal
3
-
4
- if "%~1"=="" (
5
- >&2 echo [microi-trae-mcp] Missing Node or Electron runtime path.
6
- exit /b 2
7
- )
8
-
9
- if "%~2"=="" (
10
- >&2 echo [microi-trae-mcp] Missing MCP adapter path.
11
- exit /b 2
12
- )
13
-
14
- if "%~3"=="" (
15
- >&2 echo [microi-trae-mcp] Missing MCP server path.
16
- exit /b 2
17
- )
18
-
19
- call "%~1" "%~2" "%~3"
20
- set "MICROI_MCP_EXIT_CODE=%ERRORLEVEL%"
21
- endlocal & exit /b %MICROI_MCP_EXIT_CODE%
1
+ @echo off
2
+ setlocal
3
+
4
+ if "%~1"=="" (
5
+ >&2 echo [microi-trae-mcp] Missing Node or Electron runtime path.
6
+ exit /b 2
7
+ )
8
+
9
+ if "%~2"=="" (
10
+ >&2 echo [microi-trae-mcp] Missing MCP adapter path.
11
+ exit /b 2
12
+ )
13
+
14
+ if "%~3"=="" (
15
+ >&2 echo [microi-trae-mcp] Missing MCP server path.
16
+ exit /b 2
17
+ )
18
+
19
+ call "%~1" "%~2" "%~3"
20
+ set "MICROI_MCP_EXIT_CODE=%ERRORLEVEL%"
21
+ endlocal & exit /b %MICROI_MCP_EXIT_CODE%
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // Keep the configured entry name stable and independent from mcp-server.js.
5
- // Historical VS Code extensions scanned arguments containing that basename
6
- // and rewrote them to their own extension directory during activation.
7
- require('./mcp-server.js');
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Keep the configured entry name stable and independent from mcp-server.js.
5
+ // Historical VS Code extensions scanned arguments containing that basename
6
+ // and rewrote them to their own extension directory during activation.
7
+ require('./mcp-server.js');