@microi.net/cli 4.9.5 → 4.9.7

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 (133) 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/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/README.md +7 -12
  7. package/assets/build-meta.json +6 -5
  8. package/package.json +1 -1
  9. package/scripts/mcp-server.js +83 -83
  10. package/scripts/microi-cli.js +80 -92
  11. package/scripts/microi-codex-broker.js +418 -0
  12. package/scripts/microi-codex-router.js +159 -65
  13. package/scripts/microi-skills.meta.json +349 -190
  14. package/skills/.microi-skills-version.json +2 -2
  15. package/skills/.progressive-disclosure-manifest.json +3566 -0
  16. package/skills/ai-engine/SKILL.md +1 -1
  17. package/skills/ai-platform-governance/SKILL.md +22 -167
  18. package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -0
  19. package/skills/app-store/SKILL.md +1 -1
  20. package/skills/business-blueprint/SKILL.md +1 -1
  21. package/skills/datasource-engine/SKILL.md +1 -1
  22. package/skills/dos-orm/SKILL.md +1 -1
  23. package/skills/job-engine/SKILL.md +1 -1
  24. package/skills/message-notification/SKILL.md +1 -1
  25. package/skills/microi-ai-application/SKILL.md +1 -1
  26. package/skills/microi-client-frontend/SKILL.md +18 -435
  27. 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 +144 -0
  28. 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 +178 -0
  29. 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 +144 -0
  30. package/skills/microi-codex/SKILL.md +4 -4
  31. package/skills/microi-codex-installer/SKILL.md +25 -36
  32. package/skills/microi-datasource-mapping/SKILL.md +1 -1
  33. package/skills/microi-db-schema/SKILL.md +4 -4
  34. package/skills/microi-db-schema/references/schema-overview.md +1 -1
  35. package/skills/microi-db-schema/references/schema.md +1 -1
  36. package/skills/microi-db-schema/references/table-catalog.md +1 -1
  37. package/skills/microi-deployment/SKILL.md +1 -1
  38. package/skills/microi-docs-coverage/SKILL.md +1 -1
  39. package/skills/microi-form-engine/SKILL.md +2 -2
  40. package/skills/microi-form-layout/SKILL.md +20 -226
  41. package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -0
  42. package/skills/microi-frontend-sdk/SKILL.md +18 -152
  43. package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +171 -0
  44. package/skills/microi-left-right-layout/SKILL.md +1 -1
  45. package/skills/microi-microservice/SKILL.md +8 -1
  46. package/skills/microi-microservice/references/runtime-delivery.md +4 -0
  47. package/skills/microi-mobile-app-quality/SKILL.md +23 -289
  48. package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +209 -0
  49. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +117 -0
  50. package/skills/microi-solution-quotation/SKILL.md +1 -1
  51. package/skills/microi-system-delivery/SKILL.md +17 -381
  52. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +186 -0
  53. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +210 -0
  54. package/skills/microi-ui/SKILL.md +20 -170
  55. package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -0
  56. package/skills/microi-uniapp-frontend/SKILL.md +27 -336
  57. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -0
  58. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -0
  59. package/skills/module-engine/SKILL.md +1 -1
  60. package/skills/ocr-engine/SKILL.md +1 -1
  61. package/skills/page-engine/SKILL.md +24 -272
  62. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -0
  63. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -0
  64. package/skills/performance-testing/SKILL.md +1 -1
  65. package/skills/playwright-e2e/SKILL.md +25 -591
  66. 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 +173 -0
  67. 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 +183 -0
  68. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -0
  69. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -0
  70. package/skills/print-engine/SKILL.md +1 -1
  71. package/skills/production-readonly-audit/SKILL.md +1 -1
  72. package/skills/report-engine/SKILL.md +1 -1
  73. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -0
  74. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -0
  75. package/skills/scripts/validate-progressive-disclosure.mjs +52 -0
  76. package/skills/search-engine/SKILL.md +1 -1
  77. package/skills/spider-engine/SKILL.md +1 -1
  78. package/skills/translate-engine/SKILL.md +1 -1
  79. package/skills/ui-design/SKILL.md +27 -1462
  80. package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -0
  81. package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +155 -0
  82. package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -0
  83. package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -0
  84. package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -0
  85. package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -0
  86. package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -0
  87. package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -0
  88. package/skills/uniapp-mall-assets/SKILL.md +1 -1
  89. package/skills/unity-integration/SKILL.md +1 -1
  90. package/skills/v8-api-config/SKILL.md +1 -1
  91. package/skills/v8-cache-pattern/SKILL.md +1 -1
  92. package/skills/v8-crud-api/SKILL.md +21 -246
  93. package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -0
  94. package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -0
  95. package/skills/v8-debugging/SKILL.md +1 -1
  96. package/skills/v8-explorer-tree/SKILL.md +1 -1
  97. package/skills/v8-export-import/SKILL.md +16 -426
  98. package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -0
  99. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -0
  100. package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -0
  101. package/skills/v8-file-upload/SKILL.md +17 -355
  102. 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 +227 -0
  103. 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 +149 -0
  104. package/skills/v8-formengine-http/SKILL.md +1 -1
  105. package/skills/v8-frontend-events/SKILL.md +20 -206
  106. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -0
  107. package/skills/v8-http-integration/SKILL.md +15 -237
  108. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -0
  109. package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -0
  110. package/skills/v8-image-processing/SKILL.md +1 -1
  111. package/skills/v8-menu-buttons/SKILL.md +16 -512
  112. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +221 -0
  113. package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +224 -0
  114. package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -0
  115. package/skills/v8-mongodb/SKILL.md +1 -1
  116. package/skills/v8-mq-mqtt/SKILL.md +12 -176
  117. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -0
  118. package/skills/v8-saas-multi-tenant/SKILL.md +1 -1
  119. package/skills/v8-security/SKILL.md +17 -330
  120. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +199 -0
  121. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -0
  122. package/skills/v8-sql-query/SKILL.md +1 -1
  123. package/skills/v8-table-event/SKILL.md +17 -237
  124. package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -0
  125. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -0
  126. package/skills/v8-template-engine/SKILL.md +1 -1
  127. package/skills/v8-utilities/SKILL.md +1 -1
  128. package/skills/v8-workflow/SKILL.md +20 -161
  129. package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -0
  130. package/skills/workspace-conventions/SKILL.md +36 -369
  131. 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 +208 -0
  132. 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 +196 -0
  133. 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 +27 -0
@@ -10,6 +10,7 @@
10
10
  const childProcess = require('node:child_process');
11
11
  const crypto = require('node:crypto');
12
12
  const fs = require('node:fs');
13
+ const net = require('node:net');
13
14
  const os = require('node:os');
14
15
  const path = require('node:path');
15
16
 
@@ -18,13 +19,14 @@ const CONFIG_FILE = '.microi-config.json';
18
19
  const TOKEN_FILE = '.microi-mcp-tokens.json';
19
20
  const PROTOCOL_VERSION = '2024-11-05';
20
21
  const pluginRoot = path.resolve(__dirname, '..');
21
- const mcpServerPath = path.join(__dirname, 'mcp-server.js');
22
+ const mcpServerPath = path.resolve(process.env.MICROI_MCP_SERVER_PATH || path.join(__dirname, 'mcp-server.js'));
23
+ const brokerScriptPath = path.resolve(process.env.MICROI_CODEX_BROKER_SCRIPT || path.join(__dirname, 'microi-codex-broker.js'));
22
24
  const packagePath = path.join(pluginRoot, 'package.json');
23
- const pluginVersion = readJson(packagePath, {}).version || '0.0.0';
24
- const children = new Map();
25
+ const pluginVersion = process.env.MICROI_TOOL_VERSION || readJson(packagePath, {}).version || '0.0.0';
25
26
  let inputBuffer = '';
26
27
  let requestSequence = 0;
27
28
  let shuttingDown = false;
29
+ let brokerClient = null;
28
30
 
29
31
  function readJson(filePath, fallback) {
30
32
  try {
@@ -109,6 +111,34 @@ function resolveWorkspace() {
109
111
  };
110
112
  }
111
113
 
114
+ function scheduleAutomaticUpdate() {
115
+ if (process.env.MICROI_DISABLE_AUTO_UPDATE === '1') return;
116
+ const cliPath = path.join(__dirname, 'microi-cli.js');
117
+ if (!fs.existsSync(cliPath)) return;
118
+ const workspace = resolveWorkspace();
119
+ try {
120
+ const child = childProcess.spawn(process.execPath, [
121
+ cliPath,
122
+ 'update',
123
+ '--background',
124
+ '--workspace',
125
+ workspace.workspaceRoot,
126
+ '--json',
127
+ ], {
128
+ cwd: pluginRoot,
129
+ detached: true,
130
+ windowsHide: true,
131
+ stdio: 'ignore',
132
+ env: { ...process.env },
133
+ });
134
+ // 不等待更新、不重启当前 Router。新版本仅供后续新进程使用。
135
+ child.on('error', () => { /* 下一次启动自动重试 */ });
136
+ child.unref();
137
+ } catch {
138
+ // 自动更新永远不能成为 MCP 启动门禁。
139
+ }
140
+ }
141
+
112
142
  function loadProfiles() {
113
143
  const workspace = resolveWorkspace();
114
144
  const configured = Array.isArray(workspace.config.profiles)
@@ -203,56 +233,102 @@ function buildApplicationsDir(profile) {
203
233
  return path.join(profile.syncRoot, serverDir, osClientDir, 'AI应用');
204
234
  }
205
235
 
206
- function deviceId() {
207
- const raw = `MCP:${os.hostname() || 'Unknown'}`;
208
- if (/^[\x20-\x7E]{1,128}$/.test(raw)) return raw;
209
- return `MCP-${crypto.createHash('sha256').update(raw).digest('hex').slice(0, 16)}`;
236
+ function brokerCoordinates(workspace) {
237
+ const normalizedRoot = process.platform === 'win32'
238
+ ? workspace.workspaceRoot.toLowerCase()
239
+ : workspace.workspaceRoot;
240
+ const key = crypto.createHash('sha256').update(`${normalizedRoot}\0${pluginVersion}`).digest('hex').slice(0, 24);
241
+ const runtimeRoot = path.resolve(process.env.MICROI_RUNTIME_HOME || path.join(os.homedir(), '.microi', 'runtime'));
242
+ const endpoint = process.env.MICROI_CODEX_BROKER_ENDPOINT || (process.platform === 'win32'
243
+ ? `\\\\.\\pipe\\microi-codex-${key}`
244
+ : path.join(runtimeRoot, 'brokers', `${key}.sock`));
245
+ return {
246
+ endpoint,
247
+ leasePath: path.resolve(process.env.MICROI_CODEX_BROKER_LEASE || path.join(runtimeRoot, 'leases', `microi-codex-${key}.json`)),
248
+ workspaceRoot: workspace.workspaceRoot,
249
+ };
250
+ }
251
+
252
+ function wait(milliseconds) {
253
+ return new Promise(resolve => setTimeout(resolve, milliseconds));
254
+ }
255
+
256
+ function readBrokerToken(leasePath) {
257
+ const lease = readJson(leasePath, {});
258
+ return typeof lease.token === 'string' ? lease.token : '';
210
259
  }
211
260
 
212
- class ChildMcp {
213
- constructor(profile) {
214
- this.profile = profile;
261
+ class SharedBrokerClient {
262
+ constructor(workspace) {
263
+ this.coordinates = brokerCoordinates(workspace);
215
264
  this.pending = new Map();
216
265
  this.buffer = '';
217
- this.ready = this.start();
266
+ this.closed = false;
267
+ this.spawnAttempted = false;
268
+ this.ready = this.connect();
218
269
  }
219
270
 
220
- async start() {
221
- if (!fs.existsSync(mcpServerPath)) {
222
- throw new Error(`Codex Plugin 缺少 MCP bundle:${mcpServerPath}`);
271
+ startBroker() {
272
+ if (!fs.existsSync(brokerScriptPath)) {
273
+ throw new Error(`Codex Plugin 缺少共享 Broker:${brokerScriptPath}`);
223
274
  }
224
- this.child = childProcess.spawn(process.execPath, [mcpServerPath], {
225
- cwd: this.profile.workspaceRoot,
275
+ const child = childProcess.spawn(process.execPath, [brokerScriptPath], {
276
+ cwd: pluginRoot,
277
+ detached: true,
226
278
  windowsHide: true,
227
- stdio: ['pipe', 'pipe', 'pipe'],
279
+ stdio: 'ignore',
228
280
  env: {
229
281
  ...process.env,
230
- MICROI_API_URL: this.profile.apiBaseUrl,
231
- MICROI_TOKEN_FILE: this.profile.tokenPath,
232
- MICROI_AUTH_RECOVERY_DIR: `${this.profile.tokenPath}.recovery`,
233
- MICROI_OS_CLIENT: this.profile.osClient,
234
- MICROI_OS_CLIENT_TYPE: this.profile.osClientType,
235
- MICROI_OS_CLIENT_NETWORK: this.profile.osClientNetwork,
236
- MICROI_WORKSPACE_ROOT: this.profile.workspaceRoot,
237
- MICROI_SYNC_ROOT: this.profile.syncRoot,
238
- MICROI_AI_APPLICATIONS_DIR: buildApplicationsDir(this.profile),
239
- MICROI_LABEL_BASE64: Buffer.from(this.profile.label, 'utf8').toString('base64'),
240
- MICROI_MCP_DID: deviceId(),
241
- MICROI_TOOL_SOURCE: 'codex-plugin',
282
+ MICROI_CODEX_BROKER_ENDPOINT: this.coordinates.endpoint,
283
+ MICROI_CODEX_BROKER_LEASE: this.coordinates.leasePath,
284
+ MICROI_WORKSPACE_ROOT: this.coordinates.workspaceRoot,
285
+ MICROI_MCP_SERVER_PATH: mcpServerPath,
242
286
  MICROI_TOOL_VERSION: pluginVersion,
243
- MICROI_CODEX_MODE: '1',
244
287
  },
245
288
  });
246
- this.child.stdout.on('data', chunk => this.onData(chunk));
247
- this.child.stderr.on('data', chunk => process.stderr.write(`[${this.profile.name}] ${chunk}`));
248
- this.child.on('error', error => this.rejectAll(error));
249
- this.child.on('exit', code => this.rejectAll(new Error(`Microi MCP ${this.profile.name} 已退出(${code ?? 'unknown'})`)));
250
- await this.request('initialize', {
251
- protocolVersion: PROTOCOL_VERSION,
252
- capabilities: {},
253
- clientInfo: { name: 'microi-codex-plugin-router', version: pluginVersion },
254
- }, true);
255
- this.notify('notifications/initialized', {});
289
+ child.on('error', () => { /* connect retry reports the actionable failure */ });
290
+ child.unref();
291
+ }
292
+
293
+ openSocket() {
294
+ return new Promise((resolve, reject) => {
295
+ const socket = net.createConnection(this.coordinates.endpoint);
296
+ const fail = error => {
297
+ socket.destroy();
298
+ reject(error);
299
+ };
300
+ socket.once('error', fail);
301
+ socket.once('connect', () => {
302
+ socket.off('error', fail);
303
+ this.socket = socket;
304
+ socket.setEncoding('utf8');
305
+ socket.on('data', chunk => this.onData(chunk));
306
+ socket.on('error', error => this.rejectAll(error));
307
+ socket.on('close', () => {
308
+ this.closed = true;
309
+ this.rejectAll(new Error('Microi shared broker disconnected'));
310
+ });
311
+ resolve();
312
+ });
313
+ });
314
+ }
315
+
316
+ async connect() {
317
+ let lastError;
318
+ for (let attempt = 0; attempt < 50; attempt += 1) {
319
+ try {
320
+ await this.openSocket();
321
+ return;
322
+ } catch (error) {
323
+ lastError = error;
324
+ if (!this.spawnAttempted || attempt === 15) {
325
+ this.spawnAttempted = true;
326
+ this.startBroker();
327
+ }
328
+ await wait(Math.min(40 + attempt * 12, 250));
329
+ }
330
+ }
331
+ throw new Error(`无法连接 Microi 共享 Broker:${lastError instanceof Error ? lastError.message : String(lastError)}`);
256
332
  }
257
333
 
258
334
  onData(chunk) {
@@ -268,7 +344,7 @@ class ChildMcp {
268
344
  const pending = this.pending.get(String(message.id));
269
345
  if (!pending) continue;
270
346
  this.pending.delete(String(message.id));
271
- if (message.error) pending.reject(new Error(message.error.message || JSON.stringify(message.error)));
347
+ if (message.error) pending.reject(new Error(typeof message.error === 'string' ? message.error : (message.error.message || JSON.stringify(message.error))));
272
348
  else pending.resolve(message.result);
273
349
  }
274
350
  }
@@ -278,37 +354,42 @@ class ChildMcp {
278
354
  this.pending.clear();
279
355
  }
280
356
 
281
- write(message) {
282
- if (!this.child || this.child.stdin.destroyed) throw new Error(`Microi MCP ${this.profile.name} 不可用`);
283
- this.child.stdin.write(`${JSON.stringify(message)}\n`);
284
- }
285
-
286
- request(method, params, skipReady = false) {
357
+ request(profile, method, params) {
287
358
  return (async () => {
288
- if (!skipReady) await this.ready;
359
+ await this.ready;
360
+ if (this.closed || !this.socket || this.socket.destroyed) throw new Error('Microi shared broker is unavailable');
361
+ let auth = '';
362
+ for (let attempt = 0; attempt < 10 && !auth; attempt += 1) {
363
+ auth = readBrokerToken(this.coordinates.leasePath);
364
+ if (!auth) await wait(25);
365
+ }
366
+ if (!auth) throw new Error('Microi shared broker lease is unavailable');
289
367
  const id = `router-${process.pid}-${++requestSequence}`;
290
368
  const response = new Promise((resolve, reject) => this.pending.set(id, { resolve, reject }));
291
- this.write({ jsonrpc: '2.0', id, method, params });
369
+ this.socket.write(`${JSON.stringify({
370
+ id,
371
+ auth,
372
+ type: 'request',
373
+ profile: { ...profile, applicationsDir: buildApplicationsDir(profile) },
374
+ method,
375
+ params,
376
+ })}\n`);
292
377
  return response;
293
378
  })();
294
379
  }
295
380
 
296
- notify(method, params) {
297
- this.write({ jsonrpc: '2.0', method, params });
381
+ close() {
382
+ try { this.socket?.end(); } catch { /* best effort */ }
298
383
  }
384
+ }
299
385
 
300
- stop() {
301
- try { this.child?.stdin.end(); } catch { /* best effort */ }
302
- try { this.child?.kill('SIGTERM'); } catch { /* best effort */ }
303
- }
386
+ function sharedBroker(profile) {
387
+ if (!brokerClient || brokerClient.closed) brokerClient = new SharedBrokerClient({ workspaceRoot: profile.workspaceRoot });
388
+ return brokerClient;
304
389
  }
305
390
 
306
- function childFor(profile) {
307
- const existing = children.get(profile.identity);
308
- if (existing) return existing;
309
- const child = new ChildMcp(profile);
310
- children.set(profile.identity, child);
311
- return child;
391
+ function requestThroughBroker(profile, method, params) {
392
+ return sharedBroker(profile).request(profile, method, params);
312
393
  }
313
394
 
314
395
  function resultText(value, isError = false) {
@@ -350,7 +431,7 @@ async function callRouterTool(args) {
350
431
  }
351
432
  try {
352
433
  const profile = selectProfile(args?.profile);
353
- return await childFor(profile).request('tools/call', {
434
+ return await requestThroughBroker(profile, 'tools/call', {
354
435
  name: 'microi_codex',
355
436
  arguments: { action, params: args?.params || {} },
356
437
  });
@@ -393,7 +474,7 @@ async function readResource(uri) {
393
474
  const raw = decodeURIComponent(match[4] || '');
394
475
  params = raw ? JSON.parse(raw) : {};
395
476
  }
396
- const result = await childFor(profile).request('tools/call', {
477
+ const result = await requestThroughBroker(profile, 'tools/call', {
397
478
  name: 'microi_codex',
398
479
  arguments: { action, params },
399
480
  });
@@ -454,11 +535,13 @@ async function handle(message) {
454
535
  function shutdown() {
455
536
  if (shuttingDown) return;
456
537
  shuttingDown = true;
457
- for (const child of children.values()) child.stop();
458
- children.clear();
538
+ brokerClient?.close();
539
+ brokerClient = null;
459
540
  }
460
541
 
461
542
  process.stdin.setEncoding('utf8');
543
+ const automaticUpdateTimer = setTimeout(scheduleAutomaticUpdate, 1500);
544
+ automaticUpdateTimer.unref();
462
545
  process.stdin.on('data', chunk => {
463
546
  inputBuffer += chunk;
464
547
  let newline;
@@ -476,5 +559,16 @@ process.stdin.on('data', chunk => {
476
559
  });
477
560
  process.stdin.on('end', () => { shutdown(); process.exit(0); });
478
561
  process.stdin.on('error', () => { shutdown(); process.exit(1); });
562
+ process.stdout.on('error', error => { shutdown(); process.exit(error?.code === 'EPIPE' ? 0 : 1); });
563
+ process.on('disconnect', () => { shutdown(); process.exit(0); });
479
564
  for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(signal, () => { shutdown(); process.exit(0); });
480
565
  process.on('exit', shutdown);
566
+
567
+ const parentPid = process.ppid;
568
+ if (parentPid > 1) {
569
+ const parentWatchTimer = setInterval(() => {
570
+ try { process.kill(parentPid, 0); }
571
+ catch (error) { if (error?.code === 'ESRCH') { shutdown(); process.exit(0); } }
572
+ }, 5000);
573
+ parentWatchTimer.unref();
574
+ }