@zltquant/zlt-mcp 0.6.0 → 0.6.1-beta.0

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.
package/config.json CHANGED
@@ -1143,21 +1143,22 @@
1143
1143
  },
1144
1144
  {
1145
1145
  "name": "mcp-wait",
1146
- "description": "阻塞等待一个异步任务结束,直到需要 agent 行动的状态才返回。kind=backtest 等回测,id 传 mcp-create-and-run-backtest / mcp-re-backtest 返回的 runId;kind=download 等数据下载,id 传 mcp-download-data 返回的 uuid(传 \"0\" 等本机当前最新下载任务)。拿到任务 id 后应立即调用本工具,等待期间不要做任何其他事、不要轮询状态。\n\nkind=backtest 返回与 mcp-get-backtest-state 相同的终态结果(status 2 失败/3 取消/4 终止/5 完成;status=5 才能查收益)。\n\nkind=download 返回与 mcp-get-download-progress 相同的结果,按其中 nextAction 行动。除下载中以外的任何状态都会立即返回:resume-required / await-credential / report-stopped 表示任务不会自己结束,需要用户决定。\n\n任一 kind 带 waitStopped=no-progress 表示约 3 分钟毫无进展、先交回现状(回测可能仍在准备数据);可用对应状态工具复查一次,再调用本工具继续等。",
1146
+ "description": "阻塞等待一个异步任务结束,直到需要 agent 行动的状态才返回。kind=install 等 runtime 安装,id 传 zlt-runtime-install 返回的 taskId;kind=backtest 等回测,id 传 mcp-create-and-run-backtest / mcp-re-backtest 返回的 runId;kind=download 等数据下载,id 传 mcp-download-data 返回的 uuid(传 \"0\" 等本机当前最新下载任务)。拿到任务 id 后应立即调用本工具,等待期间不要做任何其他事、不要轮询状态。\n\nkind=install 返回安装阶段和终态;completed 后再调用 zlt-runtime-doctor。\n\nkind=backtest 返回与 mcp-get-backtest-state 相同的终态结果(status 2 失败/3 取消/4 终止/5 完成;status=5 才能查收益)。\n\nkind=download 返回与 mcp-get-download-progress 相同的结果,按其中 nextAction 行动。除下载中以外的任何状态都会立即返回:resume-required / await-credential / report-stopped 表示任务不会自己结束,需要用户决定。\n\n任一 kind 带 waitStopped=no-progress 表示约 3 分钟毫无进展、先交回现状(回测可能仍在准备数据);可用对应状态工具复查一次,再调用本工具继续等。",
1147
1147
  "inputSchema": {
1148
1148
  "type": "object",
1149
1149
  "properties": {
1150
1150
  "kind": {
1151
1151
  "type": "string",
1152
1152
  "enum": [
1153
+ "install",
1153
1154
  "backtest",
1154
1155
  "download"
1155
1156
  ],
1156
- "description": "任务类别:backtest 回测,download 数据下载。"
1157
+ "description": "任务类别:install runtime 安装,backtest 回测,download 数据下载。"
1157
1158
  },
1158
1159
  "id": {
1159
1160
  "type": "string",
1160
- "description": "任务标识:kind=backtest 传 runId;kind=download 传 uuid(\"0\" 表示本机当前最新下载任务)。"
1161
+ "description": "任务标识:kind=install 传 zlt-runtime-install 返回的 taskId;kind=backtest 传 runId;kind=download 传 uuid(\"0\" 表示本机当前最新下载任务)。"
1161
1162
  },
1162
1163
  "codePath": {
1163
1164
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zltquant/zlt-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.1-beta.0",
4
4
  "description": "智量通 ZLT Quant MCP server(Windows x64;量化策略创建与本地回测)",
5
5
  "bin": {
6
6
  "zlt-mcp": "./zlt-mcp-proxy.bundle.cjs"
@@ -1147,8 +1147,8 @@ var require_command = __commonJS({
1147
1147
  "../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/lib/command.js"(exports2) {
1148
1148
  var EventEmitter = require("node:events").EventEmitter;
1149
1149
  var childProcess = require("node:child_process");
1150
- var path16 = require("node:path");
1151
- var fs15 = require("node:fs");
1150
+ var path17 = require("node:path");
1151
+ var fs16 = require("node:fs");
1152
1152
  var process4 = require("node:process");
1153
1153
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1154
1154
  var { CommanderError: CommanderError2 } = require_error();
@@ -1198,7 +1198,7 @@ var require_command = __commonJS({
1198
1198
  this._outputConfiguration = {
1199
1199
  writeOut: (str) => process4.stdout.write(str),
1200
1200
  writeErr: (str) => process4.stderr.write(str),
1201
- outputError: (str, write) => write(str),
1201
+ outputError: (str, write2) => write2(str),
1202
1202
  getOutHelpWidth: () => process4.stdout.isTTY ? process4.stdout.columns : void 0,
1203
1203
  getErrHelpWidth: () => process4.stderr.isTTY ? process4.stderr.columns : void 0,
1204
1204
  getOutHasColors: () => useColor() ?? (process4.stdout.isTTY && process4.stdout.hasColors?.()),
@@ -2129,7 +2129,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2129
2129
  * @param {string} subcommandName
2130
2130
  */
2131
2131
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2132
- if (fs15.existsSync(executableFile)) return;
2132
+ if (fs16.existsSync(executableFile)) return;
2133
2133
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2134
2134
  const executableMissing = `'${executableFile}' does not exist
2135
2135
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -2147,11 +2147,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
2147
2147
  let launchWithNode = false;
2148
2148
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2149
2149
  function findFile(baseDir, baseName) {
2150
- const localBin = path16.resolve(baseDir, baseName);
2151
- if (fs15.existsSync(localBin)) return localBin;
2152
- if (sourceExt.includes(path16.extname(baseName))) return void 0;
2150
+ const localBin = path17.resolve(baseDir, baseName);
2151
+ if (fs16.existsSync(localBin)) return localBin;
2152
+ if (sourceExt.includes(path17.extname(baseName))) return void 0;
2153
2153
  const foundExt = sourceExt.find(
2154
- (ext) => fs15.existsSync(`${localBin}${ext}`)
2154
+ (ext) => fs16.existsSync(`${localBin}${ext}`)
2155
2155
  );
2156
2156
  if (foundExt) return `${localBin}${foundExt}`;
2157
2157
  return void 0;
@@ -2163,21 +2163,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
2163
2163
  if (this._scriptPath) {
2164
2164
  let resolvedScriptPath;
2165
2165
  try {
2166
- resolvedScriptPath = fs15.realpathSync(this._scriptPath);
2166
+ resolvedScriptPath = fs16.realpathSync(this._scriptPath);
2167
2167
  } catch {
2168
2168
  resolvedScriptPath = this._scriptPath;
2169
2169
  }
2170
- executableDir = path16.resolve(
2171
- path16.dirname(resolvedScriptPath),
2170
+ executableDir = path17.resolve(
2171
+ path17.dirname(resolvedScriptPath),
2172
2172
  executableDir
2173
2173
  );
2174
2174
  }
2175
2175
  if (executableDir) {
2176
2176
  let localFile = findFile(executableDir, executableFile);
2177
2177
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2178
- const legacyName = path16.basename(
2178
+ const legacyName = path17.basename(
2179
2179
  this._scriptPath,
2180
- path16.extname(this._scriptPath)
2180
+ path17.extname(this._scriptPath)
2181
2181
  );
2182
2182
  if (legacyName !== this._name) {
2183
2183
  localFile = findFile(
@@ -2188,7 +2188,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2188
2188
  }
2189
2189
  executableFile = localFile || executableFile;
2190
2190
  }
2191
- launchWithNode = sourceExt.includes(path16.extname(executableFile));
2191
+ launchWithNode = sourceExt.includes(path17.extname(executableFile));
2192
2192
  let proc;
2193
2193
  if (process4.platform !== "win32") {
2194
2194
  if (launchWithNode) {
@@ -3035,7 +3035,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3035
3035
  * @return {Command}
3036
3036
  */
3037
3037
  nameFromFilename(filename) {
3038
- this._name = path16.basename(filename, path16.extname(filename));
3038
+ this._name = path17.basename(filename, path17.extname(filename));
3039
3039
  return this;
3040
3040
  }
3041
3041
  /**
@@ -3049,9 +3049,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3049
3049
  * @param {string} [path]
3050
3050
  * @return {(string|null|Command)}
3051
3051
  */
3052
- executableDir(path17) {
3053
- if (path17 === void 0) return this._executableDir;
3054
- this._executableDir = path17;
3052
+ executableDir(path18) {
3053
+ if (path18 === void 0) return this._executableDir;
3054
+ this._executableDir = path18;
3055
3055
  return this;
3056
3056
  }
3057
3057
  /**
@@ -3098,11 +3098,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
3098
3098
  hasColors = this._outputConfiguration.getOutHasColors();
3099
3099
  helpWidth = this._outputConfiguration.getOutHelpWidth();
3100
3100
  }
3101
- const write = (str) => {
3101
+ const write2 = (str) => {
3102
3102
  if (!hasColors) str = this._outputConfiguration.stripColor(str);
3103
3103
  return baseWrite(str);
3104
3104
  };
3105
- return { error: error2, write, hasColors, helpWidth };
3105
+ return { error: error2, write: write2, hasColors, helpWidth };
3106
3106
  }
3107
3107
  /**
3108
3108
  * Output help information for this command.
@@ -6516,8 +6516,8 @@ var require_utils = __commonJS({
6516
6516
  }
6517
6517
  return ind;
6518
6518
  }
6519
- function removeDotSegments(path16) {
6520
- let input = path16;
6519
+ function removeDotSegments(path17) {
6520
+ let input = path17;
6521
6521
  const output = [];
6522
6522
  let nextSlash = -1;
6523
6523
  let len = 0;
@@ -6716,8 +6716,8 @@ var require_schemes = __commonJS({
6716
6716
  wsComponent.secure = void 0;
6717
6717
  }
6718
6718
  if (wsComponent.resourceName) {
6719
- const [path16, query] = wsComponent.resourceName.split("?");
6720
- wsComponent.path = path16 && path16 !== "/" ? path16 : void 0;
6719
+ const [path17, query] = wsComponent.resourceName.split("?");
6720
+ wsComponent.path = path17 && path17 !== "/" ? path17 : void 0;
6721
6721
  wsComponent.query = query;
6722
6722
  wsComponent.resourceName = void 0;
6723
6723
  }
@@ -10079,12 +10079,12 @@ var require_dist = __commonJS({
10079
10079
  throw new Error(`Unknown format "${name}"`);
10080
10080
  return f;
10081
10081
  };
10082
- function addFormats(ajv, list, fs15, exportName) {
10082
+ function addFormats(ajv, list, fs16, exportName) {
10083
10083
  var _a;
10084
10084
  var _b;
10085
10085
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
10086
10086
  for (const f of list)
10087
- ajv.addFormat(f, fs15[f]);
10087
+ ajv.addFormat(f, fs16[f]);
10088
10088
  }
10089
10089
  module2.exports = exports2 = formatsPlugin;
10090
10090
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -10097,8 +10097,8 @@ var require_windows = __commonJS({
10097
10097
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports2, module2) {
10098
10098
  module2.exports = isexe;
10099
10099
  isexe.sync = sync;
10100
- var fs15 = require("fs");
10101
- function checkPathExt(path16, options) {
10100
+ var fs16 = require("fs");
10101
+ function checkPathExt(path17, options) {
10102
10102
  var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
10103
10103
  if (!pathext) {
10104
10104
  return true;
@@ -10109,25 +10109,25 @@ var require_windows = __commonJS({
10109
10109
  }
10110
10110
  for (var i = 0; i < pathext.length; i++) {
10111
10111
  var p = pathext[i].toLowerCase();
10112
- if (p && path16.substr(-p.length).toLowerCase() === p) {
10112
+ if (p && path17.substr(-p.length).toLowerCase() === p) {
10113
10113
  return true;
10114
10114
  }
10115
10115
  }
10116
10116
  return false;
10117
10117
  }
10118
- function checkStat(stat, path16, options) {
10118
+ function checkStat(stat, path17, options) {
10119
10119
  if (!stat.isSymbolicLink() && !stat.isFile()) {
10120
10120
  return false;
10121
10121
  }
10122
- return checkPathExt(path16, options);
10122
+ return checkPathExt(path17, options);
10123
10123
  }
10124
- function isexe(path16, options, cb) {
10125
- fs15.stat(path16, function(er, stat) {
10126
- cb(er, er ? false : checkStat(stat, path16, options));
10124
+ function isexe(path17, options, cb) {
10125
+ fs16.stat(path17, function(er, stat) {
10126
+ cb(er, er ? false : checkStat(stat, path17, options));
10127
10127
  });
10128
10128
  }
10129
- function sync(path16, options) {
10130
- return checkStat(fs15.statSync(path16), path16, options);
10129
+ function sync(path17, options) {
10130
+ return checkStat(fs16.statSync(path17), path17, options);
10131
10131
  }
10132
10132
  }
10133
10133
  });
@@ -10137,14 +10137,14 @@ var require_mode = __commonJS({
10137
10137
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports2, module2) {
10138
10138
  module2.exports = isexe;
10139
10139
  isexe.sync = sync;
10140
- var fs15 = require("fs");
10141
- function isexe(path16, options, cb) {
10142
- fs15.stat(path16, function(er, stat) {
10140
+ var fs16 = require("fs");
10141
+ function isexe(path17, options, cb) {
10142
+ fs16.stat(path17, function(er, stat) {
10143
10143
  cb(er, er ? false : checkStat(stat, options));
10144
10144
  });
10145
10145
  }
10146
- function sync(path16, options) {
10147
- return checkStat(fs15.statSync(path16), options);
10146
+ function sync(path17, options) {
10147
+ return checkStat(fs16.statSync(path17), options);
10148
10148
  }
10149
10149
  function checkStat(stat, options) {
10150
10150
  return stat.isFile() && checkMode(stat, options);
@@ -10168,7 +10168,7 @@ var require_mode = __commonJS({
10168
10168
  // ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
10169
10169
  var require_isexe = __commonJS({
10170
10170
  "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports2, module2) {
10171
- var fs15 = require("fs");
10171
+ var fs16 = require("fs");
10172
10172
  var core;
10173
10173
  if (process.platform === "win32" || global.TESTING_WINDOWS) {
10174
10174
  core = require_windows();
@@ -10177,7 +10177,7 @@ var require_isexe = __commonJS({
10177
10177
  }
10178
10178
  module2.exports = isexe;
10179
10179
  isexe.sync = sync;
10180
- function isexe(path16, options, cb) {
10180
+ function isexe(path17, options, cb) {
10181
10181
  if (typeof options === "function") {
10182
10182
  cb = options;
10183
10183
  options = {};
@@ -10187,7 +10187,7 @@ var require_isexe = __commonJS({
10187
10187
  throw new TypeError("callback not provided");
10188
10188
  }
10189
10189
  return new Promise(function(resolve8, reject) {
10190
- isexe(path16, options || {}, function(er, is) {
10190
+ isexe(path17, options || {}, function(er, is) {
10191
10191
  if (er) {
10192
10192
  reject(er);
10193
10193
  } else {
@@ -10196,7 +10196,7 @@ var require_isexe = __commonJS({
10196
10196
  });
10197
10197
  });
10198
10198
  }
10199
- core(path16, options || {}, function(er, is) {
10199
+ core(path17, options || {}, function(er, is) {
10200
10200
  if (er) {
10201
10201
  if (er.code === "EACCES" || options && options.ignoreErrors) {
10202
10202
  er = null;
@@ -10206,9 +10206,9 @@ var require_isexe = __commonJS({
10206
10206
  cb(er, is);
10207
10207
  });
10208
10208
  }
10209
- function sync(path16, options) {
10209
+ function sync(path17, options) {
10210
10210
  try {
10211
- return core.sync(path16, options || {});
10211
+ return core.sync(path17, options || {});
10212
10212
  } catch (er) {
10213
10213
  if (options && options.ignoreErrors || er.code === "EACCES") {
10214
10214
  return false;
@@ -10224,7 +10224,7 @@ var require_isexe = __commonJS({
10224
10224
  var require_which = __commonJS({
10225
10225
  "../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js"(exports2, module2) {
10226
10226
  var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
10227
- var path16 = require("path");
10227
+ var path17 = require("path");
10228
10228
  var COLON = isWindows ? ";" : ":";
10229
10229
  var isexe = require_isexe();
10230
10230
  var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
@@ -10262,7 +10262,7 @@ var require_which = __commonJS({
10262
10262
  return opt.all && found.length ? resolve8(found) : reject(getNotFoundError(cmd));
10263
10263
  const ppRaw = pathEnv[i];
10264
10264
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
10265
- const pCmd = path16.join(pathPart, cmd);
10265
+ const pCmd = path17.join(pathPart, cmd);
10266
10266
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
10267
10267
  resolve8(subStep(p, i, 0));
10268
10268
  });
@@ -10289,7 +10289,7 @@ var require_which = __commonJS({
10289
10289
  for (let i = 0; i < pathEnv.length; i++) {
10290
10290
  const ppRaw = pathEnv[i];
10291
10291
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
10292
- const pCmd = path16.join(pathPart, cmd);
10292
+ const pCmd = path17.join(pathPart, cmd);
10293
10293
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
10294
10294
  for (let j = 0; j < pathExt.length; j++) {
10295
10295
  const cur = p + pathExt[j];
@@ -10337,7 +10337,7 @@ var require_path_key = __commonJS({
10337
10337
  var require_resolveCommand = __commonJS({
10338
10338
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
10339
10339
  "use strict";
10340
- var path16 = require("path");
10340
+ var path17 = require("path");
10341
10341
  var which = require_which();
10342
10342
  var getPathKey = require_path_key();
10343
10343
  function resolveCommandAttempt(parsed, withoutPathExt) {
@@ -10355,7 +10355,7 @@ var require_resolveCommand = __commonJS({
10355
10355
  try {
10356
10356
  resolved = which.sync(parsed.command, {
10357
10357
  path: env[getPathKey({ env })],
10358
- pathExt: withoutPathExt ? path16.delimiter : void 0
10358
+ pathExt: withoutPathExt ? path17.delimiter : void 0
10359
10359
  });
10360
10360
  } catch (e) {
10361
10361
  } finally {
@@ -10364,7 +10364,7 @@ var require_resolveCommand = __commonJS({
10364
10364
  }
10365
10365
  }
10366
10366
  if (resolved) {
10367
- resolved = path16.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
10367
+ resolved = path17.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
10368
10368
  }
10369
10369
  return resolved;
10370
10370
  }
@@ -10418,8 +10418,8 @@ var require_shebang_command = __commonJS({
10418
10418
  if (!match) {
10419
10419
  return null;
10420
10420
  }
10421
- const [path16, argument] = match[0].replace(/#! ?/, "").split(" ");
10422
- const binary = path16.split("/").pop();
10421
+ const [path17, argument] = match[0].replace(/#! ?/, "").split(" ");
10422
+ const binary = path17.split("/").pop();
10423
10423
  if (binary === "env") {
10424
10424
  return argument;
10425
10425
  }
@@ -10432,16 +10432,16 @@ var require_shebang_command = __commonJS({
10432
10432
  var require_readShebang = __commonJS({
10433
10433
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) {
10434
10434
  "use strict";
10435
- var fs15 = require("fs");
10435
+ var fs16 = require("fs");
10436
10436
  var shebangCommand = require_shebang_command();
10437
10437
  function readShebang(command) {
10438
10438
  const size = 150;
10439
10439
  const buffer = Buffer.alloc(size);
10440
10440
  let fd;
10441
10441
  try {
10442
- fd = fs15.openSync(command, "r");
10443
- fs15.readSync(fd, buffer, 0, size, 0);
10444
- fs15.closeSync(fd);
10442
+ fd = fs16.openSync(command, "r");
10443
+ fs16.readSync(fd, buffer, 0, size, 0);
10444
+ fs16.closeSync(fd);
10445
10445
  } catch (e) {
10446
10446
  }
10447
10447
  return shebangCommand(buffer.toString());
@@ -10454,7 +10454,7 @@ var require_readShebang = __commonJS({
10454
10454
  var require_parse = __commonJS({
10455
10455
  "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
10456
10456
  "use strict";
10457
- var path16 = require("path");
10457
+ var path17 = require("path");
10458
10458
  var resolveCommand = require_resolveCommand();
10459
10459
  var escape2 = require_escape();
10460
10460
  var readShebang = require_readShebang();
@@ -10479,7 +10479,7 @@ var require_parse = __commonJS({
10479
10479
  const needsShell = !isExecutableRegExp.test(commandFile);
10480
10480
  if (parsed.options.forceShell || needsShell) {
10481
10481
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
10482
- parsed.command = path16.normalize(parsed.command);
10482
+ parsed.command = path17.normalize(parsed.command);
10483
10483
  parsed.command = escape2.command(parsed.command);
10484
10484
  parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
10485
10485
  const shellCommand = [parsed.command].concat(parsed.args).join(" ");
@@ -10569,7 +10569,7 @@ var require_cross_spawn = __commonJS({
10569
10569
  var cp = require("child_process");
10570
10570
  var parse3 = require_parse();
10571
10571
  var enoent = require_enoent();
10572
- function spawn4(command, args, options) {
10572
+ function spawn5(command, args, options) {
10573
10573
  const parsed = parse3(command, args, options);
10574
10574
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
10575
10575
  enoent.hookChildProcess(spawned, parsed);
@@ -10581,8 +10581,8 @@ var require_cross_spawn = __commonJS({
10581
10581
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
10582
10582
  return result;
10583
10583
  }
10584
- module2.exports = spawn4;
10585
- module2.exports.spawn = spawn4;
10584
+ module2.exports = spawn5;
10585
+ module2.exports.spawn = spawn5;
10586
10586
  module2.exports.sync = spawnSync3;
10587
10587
  module2.exports._parse = parse3;
10588
10588
  module2.exports._enoent = enoent;
@@ -10607,8 +10607,8 @@ var {
10607
10607
  } = import_index.default;
10608
10608
 
10609
10609
  // src/index.ts
10610
- var fs14 = __toESM(require("node:fs"), 1);
10611
- var path15 = __toESM(require("node:path"), 1);
10610
+ var fs15 = __toESM(require("node:fs"), 1);
10611
+ var path16 = __toESM(require("node:path"), 1);
10612
10612
 
10613
10613
  // src/cli.ts
10614
10614
  var fs9 = __toESM(require("fs"), 1);
@@ -10812,10 +10812,10 @@ function assignProp(target, prop, value) {
10812
10812
  configurable: true
10813
10813
  });
10814
10814
  }
10815
- function getElementAtPath(obj, path16) {
10816
- if (!path16)
10815
+ function getElementAtPath(obj, path17) {
10816
+ if (!path17)
10817
10817
  return obj;
10818
- return path16.reduce((acc, key) => acc?.[key], obj);
10818
+ return path17.reduce((acc, key) => acc?.[key], obj);
10819
10819
  }
10820
10820
  function promiseAllObject(promisesObj) {
10821
10821
  const keys = Object.keys(promisesObj);
@@ -11135,11 +11135,11 @@ function aborted(x, startIndex = 0) {
11135
11135
  }
11136
11136
  return false;
11137
11137
  }
11138
- function prefixIssues(path16, issues) {
11138
+ function prefixIssues(path17, issues) {
11139
11139
  return issues.map((iss) => {
11140
11140
  var _a;
11141
11141
  (_a = iss).path ?? (_a.path = []);
11142
- iss.path.unshift(path16);
11142
+ iss.path.unshift(path17);
11143
11143
  return iss;
11144
11144
  });
11145
11145
  }
@@ -19166,18 +19166,18 @@ async function waitForPipe(workRoot, pipePrefix, timeout) {
19166
19166
  throw new Error(`\u7B49\u5F85 ${pipePrefix} \u7BA1\u9053\u8D85\u65F6`);
19167
19167
  }
19168
19168
  async function readZltContent(workRoot, temporaryZltFile) {
19169
- const fs15 = await import("fs");
19170
- const path16 = await import("path");
19171
- const zltFile = path16.join(workRoot, temporaryZltFile || "Temporary/zlt");
19172
- return fs15.existsSync(zltFile) ? fs15.readFileSync(zltFile, "utf-8").trim() : "";
19169
+ const fs16 = await import("fs");
19170
+ const path17 = await import("path");
19171
+ const zltFile = path17.join(workRoot, temporaryZltFile || "Temporary/zlt");
19172
+ return fs16.existsSync(zltFile) ? fs16.readFileSync(zltFile, "utf-8").trim() : "";
19173
19173
  }
19174
19174
  async function pipeExists2(pipeName) {
19175
- const fs15 = await import("fs");
19175
+ const fs16 = await import("fs");
19176
19176
  try {
19177
19177
  if (process.platform === "win32") {
19178
- return fs15.readdirSync("\\\\.\\pipe\\").includes(pipeName);
19178
+ return fs16.readdirSync("\\\\.\\pipe\\").includes(pipeName);
19179
19179
  }
19180
- return fs15.existsSync(`/tmp/${pipeName}`);
19180
+ return fs16.existsSync(`/tmp/${pipeName}`);
19181
19181
  } catch {
19182
19182
  return false;
19183
19183
  }
@@ -23123,9 +23123,82 @@ var StdioServerTransport = class {
23123
23123
  };
23124
23124
 
23125
23125
  // src/mcp-server.ts
23126
- var fs13 = __toESM(require("node:fs"), 1);
23126
+ var fs14 = __toESM(require("node:fs"), 1);
23127
+ var os6 = __toESM(require("node:os"), 1);
23128
+ var path15 = __toESM(require("node:path"), 1);
23129
+
23130
+ // src/install-task.ts
23131
+ var fs11 = __toESM(require("node:fs"), 1);
23127
23132
  var os5 = __toESM(require("node:os"), 1);
23128
- var path14 = __toESM(require("node:path"), 1);
23133
+ var path11 = __toESM(require("node:path"), 1);
23134
+ var import_node_child_process = require("node:child_process");
23135
+ var TASK_ROOT = path11.join(os5.tmpdir(), "zlt-mcp-install-tasks");
23136
+ function taskPath(taskId) {
23137
+ return path11.join(TASK_ROOT, `${taskId}.json`);
23138
+ }
23139
+ function write(record3) {
23140
+ fs11.mkdirSync(TASK_ROOT, { recursive: true });
23141
+ const target = taskPath(record3.taskId);
23142
+ const temporary = `${target}.${process.pid}.tmp`;
23143
+ fs11.writeFileSync(temporary, `${JSON.stringify(record3)}
23144
+ `, "utf8");
23145
+ fs11.renameSync(temporary, target);
23146
+ }
23147
+ function readInstallTask(taskId) {
23148
+ if (!/^[A-Za-z0-9_-]+$/.test(taskId)) return void 0;
23149
+ try {
23150
+ return JSON.parse(fs11.readFileSync(taskPath(taskId), "utf8"));
23151
+ } catch {
23152
+ return void 0;
23153
+ }
23154
+ }
23155
+ function startInstallTask(entrypoint, argsJson, spawnProcess = import_node_child_process.spawn) {
23156
+ try {
23157
+ for (const file of fs11.readdirSync(TASK_ROOT)) {
23158
+ if (!file.endsWith(".json")) continue;
23159
+ const existing = readInstallTask(file.slice(0, -5));
23160
+ if (existing && (existing.status === "queued" || existing.status === "running")) return existing;
23161
+ }
23162
+ } catch {
23163
+ }
23164
+ const taskId = `install-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
23165
+ const record3 = { taskId, status: "queued", createdAt: (/* @__PURE__ */ new Date()).toISOString() };
23166
+ write(record3);
23167
+ const child = spawnProcess(process.execPath, [entrypoint, "__install-worker", taskId, argsJson], {
23168
+ detached: true,
23169
+ stdio: "ignore",
23170
+ windowsHide: true,
23171
+ env: process.env
23172
+ });
23173
+ child.unref();
23174
+ return record3;
23175
+ }
23176
+ function runInstallWorker(taskId, argsJson, install) {
23177
+ const current = readInstallTask(taskId);
23178
+ if (!current || current.status !== "queued") return Promise.resolve();
23179
+ write({ ...current, status: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
23180
+ let args;
23181
+ try {
23182
+ const parsed = JSON.parse(argsJson);
23183
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("\u5B89\u88C5\u4EFB\u52A1\u53C2\u6570\u4E0D\u662F\u5BF9\u8C61");
23184
+ args = parsed;
23185
+ } catch (error2) {
23186
+ write({ ...current, status: "failed", startedAt: (/* @__PURE__ */ new Date()).toISOString(), endedAt: (/* @__PURE__ */ new Date()).toISOString(), error: String(error2) });
23187
+ return Promise.resolve();
23188
+ }
23189
+ return install(args, (message) => updateInstallTask(taskId, { message })).then((workRoot) => {
23190
+ const latest = readInstallTask(taskId) ?? current;
23191
+ write({ ...latest, status: "completed", endedAt: (/* @__PURE__ */ new Date()).toISOString(), workRoot });
23192
+ }).catch((error2) => {
23193
+ const latest = readInstallTask(taskId) ?? current;
23194
+ write({ ...latest, status: "failed", endedAt: (/* @__PURE__ */ new Date()).toISOString(), error: error2 instanceof Error ? error2.message : String(error2) });
23195
+ });
23196
+ }
23197
+ function updateInstallTask(taskId, update) {
23198
+ const current = readInstallTask(taskId);
23199
+ if (!current || current.status === "completed" || current.status === "failed") return;
23200
+ write({ ...current, ...update, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
23201
+ }
23129
23202
 
23130
23203
  // src/tool-profile-contract.mjs
23131
23204
  var UNIVERSAL_AGENT_RUNTIME_TOOL_NAMES = Object.freeze([
@@ -23188,8 +23261,8 @@ var NPM_PACKAGE_CONFIG_TOOL_NAMES = Object.freeze([
23188
23261
  ]);
23189
23262
 
23190
23263
  // src/tool-pipeline.ts
23191
- var fs12 = __toESM(require("node:fs"), 1);
23192
- var path12 = __toESM(require("node:path"), 1);
23264
+ var fs13 = __toESM(require("node:fs"), 1);
23265
+ var path13 = __toESM(require("node:path"), 1);
23193
23266
  var import_node_crypto3 = require("node:crypto");
23194
23267
 
23195
23268
  // src/feature-set.ts
@@ -23200,8 +23273,8 @@ var MASKED_FACTOR_MESSAGE = "\u56E0\u5B50\u7814\u7A76\u529F\u80FD\u5728\u5F53\u5
23200
23273
  var MASKED_FUTURES_MESSAGE = "\u671F\u8D27\u56DE\u6D4B\u5728\u5F53\u524D\u7248\u672C\u672A\u5F00\u653E\uFF1ArunParams.marketIds \u542B\u671F\u8D27\u4EA4\u6613\u6240\uFF08zj/zs/ds/sq/gq\uFF09\u6216 account_list \u7684 account_type \u4E3A\u671F\u8D27\u3002\u8BF7\u4F7F\u7528\u80A1\u7968\u5E02\u573A\uFF08sh/sz\uFF09\u4E0E account_type=1\u3002";
23201
23274
 
23202
23275
  // src/backtest-config.ts
23203
- var fs11 = __toESM(require("node:fs"), 1);
23204
- var path11 = __toESM(require("node:path"), 1);
23276
+ var fs12 = __toESM(require("node:fs"), 1);
23277
+ var path12 = __toESM(require("node:path"), 1);
23205
23278
  var import_node_crypto2 = require("node:crypto");
23206
23279
  var BACKTEST_CONFIG_KEYS = [
23207
23280
  "start",
@@ -23247,13 +23320,13 @@ function readBacktestBaseline(tool, args) {
23247
23320
  if (!create && tool !== "mcp-re-backtest") return void 0;
23248
23321
  const directory = args[create ? "strategyPath" : "codePath"];
23249
23322
  if (directory === void 0) return void 0;
23250
- if (typeof directory !== "string" || !path11.isAbsolute(directory)) throw new Error("Configuration baseline requires an absolute directory path");
23251
- const root = fs11.realpathSync(directory);
23252
- if (create && path11.basename(path11.dirname(root)).toLowerCase() === "backtest") {
23323
+ if (typeof directory !== "string" || !path12.isAbsolute(directory)) throw new Error("Configuration baseline requires an absolute directory path");
23324
+ const root = fs12.realpathSync(directory);
23325
+ if (create && path12.basename(path12.dirname(root)).toLowerCase() === "backtest") {
23253
23326
  throw new Error("strategyPath must identify the strategy root, not a historical backtest directory");
23254
23327
  }
23255
- const file = path11.join(root, ".vscode", "tradesetting.json");
23256
- const raw = fs11.readFileSync(file);
23328
+ const file = path12.join(root, ".vscode", "tradesetting.json");
23329
+ const raw = fs12.readFileSync(file);
23257
23330
  let config2;
23258
23331
  try {
23259
23332
  config2 = JSON.parse(raw.toString("utf8").replace(/^\uFEFF/, ""));
@@ -23385,7 +23458,7 @@ function prepareToolCallArgs(tool, args, contexts) {
23385
23458
  }
23386
23459
  function validateDataRangeArguments(args) {
23387
23460
  const errors = [];
23388
- const error2 = (path16, message) => errors.push({ path: path16, message });
23461
+ const error2 = (path17, message) => errors.push({ path: path17, message });
23389
23462
  const input = stripControlParams(args);
23390
23463
  for (const key of Object.keys(input)) {
23391
23464
  if (key !== "params") error2(`$.${key}`, "Unsupported top-level field; query combinations belong in params[]. Date filters are not accepted.");
@@ -23547,7 +23620,7 @@ function readSlaveProperties(filePath) {
23547
23620
  const entries = /* @__PURE__ */ new Map();
23548
23621
  let raw;
23549
23622
  try {
23550
- raw = fs12.readFileSync(filePath, "utf-8");
23623
+ raw = fs13.readFileSync(filePath, "utf-8");
23551
23624
  } catch {
23552
23625
  return entries;
23553
23626
  }
@@ -23571,18 +23644,18 @@ function resolveFactorProjectRoot(clientRootDir) {
23571
23644
  if (cached2) return cached2;
23572
23645
  const root = clientRootDir.replace(/[\\/]+$/, "");
23573
23646
  const configured = expandSlaveValue(
23574
- readSlaveProperties(path12.join(root, ...ZLTAF_CONFIG_SEGMENTS)),
23647
+ readSlaveProperties(path13.join(root, ...ZLTAF_CONFIG_SEGMENTS)),
23575
23648
  "slave.factor.project-path",
23576
23649
  root
23577
23650
  );
23578
- const resolved = configured ? path12.normalize(configured) : path12.join(root, ...FALLBACK_FACTOR_PROJECT_PATH);
23651
+ const resolved = configured ? path13.normalize(configured) : path13.join(root, ...FALLBACK_FACTOR_PROJECT_PATH);
23579
23652
  factorProjectRootCache.set(clientRootDir, resolved);
23580
23653
  return resolved;
23581
23654
  }
23582
23655
  function resolveFactorWorkspacePath(clientRootDir, factorId) {
23583
23656
  if (!clientRootDir || !factorId) return void 0;
23584
23657
  const projectRoot = resolveFactorProjectRoot(clientRootDir);
23585
- return projectRoot ? path12.join(projectRoot, factorId) : void 0;
23658
+ return projectRoot ? path13.join(projectRoot, factorId) : void 0;
23586
23659
  }
23587
23660
  var MODULE_LEVEL_FACTOR_EXPORT = /^(?:(?:async\s+)?def\s+get_factor\s*\(|get_factor\s*=(?!=)|Factor\s*=(?!=))/m;
23588
23661
  function checkFactorSourceLoadable(clientRootDir, factorId) {
@@ -23590,7 +23663,7 @@ function checkFactorSourceLoadable(clientRootDir, factorId) {
23590
23663
  if (!workspacePath) return null;
23591
23664
  let source;
23592
23665
  try {
23593
- source = fs12.readFileSync(path12.join(workspacePath, "main.py"), "utf8");
23666
+ source = fs13.readFileSync(path13.join(workspacePath, "main.py"), "utf8");
23594
23667
  } catch {
23595
23668
  return null;
23596
23669
  }
@@ -23833,18 +23906,18 @@ function backtestWindowPreflightError(tool, reason, message, details) {
23833
23906
  }, true);
23834
23907
  }
23835
23908
  function isExistingAbsoluteDirectory(value) {
23836
- if (!value || !path12.isAbsolute(value)) return false;
23909
+ if (!value || !path13.isAbsolute(value)) return false;
23837
23910
  try {
23838
- return fs12.statSync(value).isDirectory();
23911
+ return fs13.statSync(value).isDirectory();
23839
23912
  } catch {
23840
23913
  return false;
23841
23914
  }
23842
23915
  }
23843
23916
  function readBacktestIdFromCodePath(codePath) {
23844
23917
  try {
23845
- const tradesettingPath = path12.join(codePath, ".vscode", "tradesetting.json");
23846
- if (!fs12.existsSync(tradesettingPath)) return void 0;
23847
- const parsed = JSON.parse(fs12.readFileSync(tradesettingPath, "utf-8"));
23918
+ const tradesettingPath = path13.join(codePath, ".vscode", "tradesetting.json");
23919
+ if (!fs13.existsSync(tradesettingPath)) return void 0;
23920
+ const parsed = JSON.parse(fs13.readFileSync(tradesettingPath, "utf-8"));
23848
23921
  if (!isRecord2(parsed)) return void 0;
23849
23922
  const value = parsed.backtest_id ?? parsed.backtestId;
23850
23923
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -24986,11 +25059,11 @@ function applyBacktestResultGuards(tool, args, result, states, contexts, activeR
24986
25059
  }
24987
25060
  function readRunResultFile(codePath) {
24988
25061
  try {
24989
- const resultPath = path12.join(codePath, "log", "result.json");
24990
- if (!fs12.existsSync(resultPath)) return null;
24991
- const before = fs12.statSync(resultPath);
24992
- const raw = fs12.readFileSync(resultPath);
24993
- const after = fs12.statSync(resultPath);
25062
+ const resultPath = path13.join(codePath, "log", "result.json");
25063
+ if (!fs13.existsSync(resultPath)) return null;
25064
+ const before = fs13.statSync(resultPath);
25065
+ const raw = fs13.readFileSync(resultPath);
25066
+ const after = fs13.statSync(resultPath);
24994
25067
  if (before.mtimeMs !== after.mtimeMs || before.size !== after.size) return null;
24995
25068
  const parsed = JSON.parse(raw.toString("utf-8"));
24996
25069
  if (!isRecord2(parsed)) return null;
@@ -25204,9 +25277,9 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
25204
25277
  function hashBacktestSource(codePath) {
25205
25278
  if (!codePath) return void 0;
25206
25279
  try {
25207
- const sourcePath = path12.join(codePath, "main.py");
25208
- if (!fs12.statSync(sourcePath).isFile()) return void 0;
25209
- return (0, import_node_crypto3.createHash)("sha256").update(fs12.readFileSync(sourcePath)).digest("hex");
25280
+ const sourcePath = path13.join(codePath, "main.py");
25281
+ if (!fs13.statSync(sourcePath).isFile()) return void 0;
25282
+ return (0, import_node_crypto3.createHash)("sha256").update(fs13.readFileSync(sourcePath)).digest("hex");
25210
25283
  } catch {
25211
25284
  return void 0;
25212
25285
  }
@@ -25252,7 +25325,7 @@ function resolveBacktestBenchmark(runParams) {
25252
25325
  var STRATEGY_DOCS_TOOLS = /* @__PURE__ */ new Set(["mcp-create-strategy", "mcp-create-strategy-with-template"]);
25253
25326
  function resolveStrategyDocsPath(clientRootDir) {
25254
25327
  if (!clientRootDir) return void 0;
25255
- const docsPath = path12.join(
25328
+ const docsPath = path13.join(
25256
25329
  clientRootDir,
25257
25330
  "python",
25258
25331
  "Lib",
@@ -25262,7 +25335,7 @@ function resolveStrategyDocsPath(clientRootDir) {
25262
25335
  "docs"
25263
25336
  );
25264
25337
  try {
25265
- if (!fs12.existsSync(docsPath)) return void 0;
25338
+ if (!fs13.existsSync(docsPath)) return void 0;
25266
25339
  } catch {
25267
25340
  return void 0;
25268
25341
  }
@@ -25279,7 +25352,7 @@ function injectDebugRunId(tool, result) {
25279
25352
  const localPath = typeof parsed.Data.localPath === "string" ? parsed.Data.localPath.trim() : "";
25280
25353
  if (!localPath) return result;
25281
25354
  const settings = JSON.parse(
25282
- fs12.readFileSync(path12.join(localPath, ".vscode", "tradesetting.json"), "utf8")
25355
+ fs13.readFileSync(path13.join(localPath, ".vscode", "tradesetting.json"), "utf8")
25283
25356
  );
25284
25357
  const debugRunId = isRecord2(settings) && typeof settings.backtest_id === "string" ? settings.backtest_id.trim() : "";
25285
25358
  if (!debugRunId) return result;
@@ -25775,12 +25848,12 @@ function preflightCreatedBacktestSource(toolName, body) {
25775
25848
  if (toolName !== "mcp-create-and-run-backtest") return null;
25776
25849
  const runId = typeof body.runId === "string" ? body.runId.trim() : "";
25777
25850
  const codePath = typeof body.codePath === "string" ? body.codePath.trim() : "";
25778
- if (!codePath || !fs12.existsSync(codePath)) return null;
25779
- const sourcePath = path12.join(codePath, "main.py");
25780
- if (!fs12.existsSync(sourcePath)) return null;
25851
+ if (!codePath || !fs13.existsSync(codePath)) return null;
25852
+ const sourcePath = path13.join(codePath, "main.py");
25853
+ if (!fs13.existsSync(sourcePath)) return null;
25781
25854
  let source;
25782
25855
  try {
25783
- source = fs12.readFileSync(sourcePath, "utf8");
25856
+ source = fs13.readFileSync(sourcePath, "utf8");
25784
25857
  } catch (error2) {
25785
25858
  const message = error2 instanceof Error ? error2.message : String(error2);
25786
25859
  return jsonToolResult(10061, "\u56DE\u6D4B\u4EE3\u7801\u5FEB\u7167\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u672A\u542F\u52A8\u7B56\u7565\u5F15\u64CE\u3002", {
@@ -26020,7 +26093,7 @@ function normalizeDataRoot(raw, clientRootDir) {
26020
26093
  }
26021
26094
  function readJsonFile(filePath) {
26022
26095
  try {
26023
- const parsed = JSON.parse(fs12.readFileSync(filePath, "utf-8"));
26096
+ const parsed = JSON.parse(fs13.readFileSync(filePath, "utf-8"));
26024
26097
  return isRecord2(parsed) ? parsed : void 0;
26025
26098
  } catch {
26026
26099
  return void 0;
@@ -26034,8 +26107,8 @@ function resolveDataRoots(clientRootDir) {
26034
26107
  const cached2 = Date.now() - readAt < DATA_ROOTS_TTL_MS ? dataRootsCache.get(clientRootDir) : void 0;
26035
26108
  if (cached2) return cached2;
26036
26109
  const root = clientRootDir.replace(/[\\/]+$/, "");
26037
- const dcSdk = readJsonFile(path12.join(root, ...DC_SDK_CONFIG_SEGMENTS));
26038
- const dcm = readJsonFile(path12.join(root, ...DCM_CONFIG_SEGMENTS));
26110
+ const dcSdk = readJsonFile(path13.join(root, ...DC_SDK_CONFIG_SEGMENTS));
26111
+ const dcm = readJsonFile(path13.join(root, ...DCM_CONFIG_SEGMENTS));
26039
26112
  const engineRoot = normalizeDataRoot(isRecord2(dcSdk?.mdf) ? dcSdk.mdf.path : void 0, root);
26040
26113
  const downloadRoot = normalizeDataRoot(dcm?.download_home, root);
26041
26114
  const resolved = Boolean(engineRoot && downloadRoot);
@@ -26065,9 +26138,9 @@ function hqSeriesFromResults(resultItems) {
26065
26138
  function engineHasAnyHqSeries(engineRoot, series) {
26066
26139
  if (!engineRoot || series.length === 0) return void 0;
26067
26140
  for (const { exchangeId, dataType } of series) {
26068
- const dir = path12.join(engineRoot, "hqdata", "his", exchangeId, dataType);
26141
+ const dir = path13.join(engineRoot, "hqdata", "his", exchangeId, dataType);
26069
26142
  try {
26070
- if (fs12.existsSync(dir) && fs12.readdirSync(dir).length > 0) return true;
26143
+ if (fs13.existsSync(dir) && fs13.readdirSync(dir).length > 0) return true;
26071
26144
  } catch {
26072
26145
  return void 0;
26073
26146
  }
@@ -27065,6 +27138,12 @@ async function startMcpServer() {
27065
27138
  const preparedArgs = prepareToolCallArgs(tool, args ?? {}, backtestRunContexts);
27066
27139
  if ("content" in preparedArgs) return preparedArgs;
27067
27140
  const toolArgs = preparedArgs;
27141
+ if (name === "mcp-wait" && typeof toolArgs.kind === "string" && toolArgs.kind === "install") {
27142
+ return await waitForInstallTask(String(toolArgs.id ?? ""), waitControl, async (workRoot) => {
27143
+ if (workRoot) await ensureRuntimeLease(workRoot);
27144
+ return runRuntimeDoctor();
27145
+ });
27146
+ }
27068
27147
  if (tool.localHandler === "currentUser") {
27069
27148
  return handleCurrentUserTool();
27070
27149
  }
@@ -27400,17 +27479,13 @@ async function handleRuntimeTool(handler, args, runtimeConfig, acquireRuntime, i
27400
27479
  true
27401
27480
  );
27402
27481
  }
27403
- const workRoot = await installRuntime({
27404
- config: runtimeConfig,
27405
- installType: "mini",
27406
- installDir: typeof args.installDir === "string" && args.installDir ? args.installDir : void 0,
27407
- onProgress: (message) => process.stderr.write(`[zlt-runtime-install] ${message}
27408
- `),
27409
- startRuntime: false
27482
+ const task = startInstallTask(process.argv[1], JSON.stringify(args));
27483
+ return jsonToolResult(0, "", {
27484
+ ...task,
27485
+ isTerminal: false,
27486
+ nextAction: "wait",
27487
+ action: `call mcp-wait with kind="install" and id="${task.taskId}"`
27410
27488
  });
27411
- await acquireRuntime(workRoot);
27412
- const doctorResult = await inspectDoctor();
27413
- return jsonToolResult(0, "", { workRoot, doctor: sanitizeRuntimeDoctor(doctorResult) });
27414
27489
  }
27415
27490
  return jsonToolResult(10011, `Unsupported local handler: ${handler}`, {}, true);
27416
27491
  } catch (error2) {
@@ -27432,6 +27507,34 @@ async function handleRuntimeTool(handler, args, runtimeConfig, acquireRuntime, i
27432
27507
  return jsonToolResult(10012, message, { handler }, true);
27433
27508
  }
27434
27509
  }
27510
+ async function waitForInstallTask(taskId, control, doctor) {
27511
+ if (!taskId) return jsonToolResult(10046, "\u6CA1\u6709 installTaskId \u5C31\u6CA1\u6709\u53EF\u7B49\u5F85\u7684\u5B89\u88C5\u4EFB\u52A1\u3002", {}, true);
27512
+ for (; ; ) {
27513
+ if (control.abortSignal?.aborted) return jsonToolResult(10047, "\u5DF2\u53D6\u6D88\u7B49\u5F85\u5B89\u88C5\u3002", { taskId }, true);
27514
+ const task = readInstallTask(taskId);
27515
+ if (!task) return jsonToolResult(10046, "\u5B89\u88C5\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F\u3002", { taskId }, true);
27516
+ const progress = task.status === "completed" ? 100 : task.status === "failed" ? 100 : task.status === "running" ? 50 : 0;
27517
+ control.heartbeat?.(progress);
27518
+ if (task.status === "completed") {
27519
+ const doctorResult = await doctor(task.workRoot);
27520
+ const ready = doctorResult.runtimeFilesComplete === true && doctorResult.backtestDependenciesComplete === true && doctorResult.ipcReachable === true;
27521
+ return jsonToolResult(ready ? 0 : 10012, ready ? "" : "\u5B89\u88C5\u4EFB\u52A1\u5B8C\u6210\uFF0C\u4F46 runtime \u672A\u901A\u8FC7\u5C31\u7EEA\u68C0\u67E5\u3002", {
27522
+ ...task,
27523
+ isTerminal: true,
27524
+ nextAction: ready ? "run-backtest" : "repair-runtime",
27525
+ doctor: sanitizeRuntimeDoctor(doctorResult)
27526
+ }, !ready);
27527
+ }
27528
+ if (task.status === "failed") return jsonToolResult(10012, task.error || "runtime \u5B89\u88C5\u5931\u8D25\u3002", { ...task, isTerminal: true, nextAction: "inspect-error" }, true);
27529
+ await new Promise((resolve8, reject) => {
27530
+ const timer = setTimeout(resolve8, 2e3);
27531
+ control.abortSignal?.addEventListener("abort", () => {
27532
+ clearTimeout(timer);
27533
+ reject(new Error("aborted"));
27534
+ }, { once: true });
27535
+ }).catch(() => void 0);
27536
+ }
27537
+ }
27435
27538
  async function prepareRuntimeForIpc(options) {
27436
27539
  syncCredentialsFromEnvAtStartup();
27437
27540
  const explicitPipeName = process.env.ZLT_PIPE_NAME?.trim();
@@ -27636,13 +27739,13 @@ function syncCredentialsFromEnvAtStartup() {
27636
27739
  function signalCliKeepaliveReady() {
27637
27740
  const raw = process.env.ZLT_MCP_KEEPALIVE_READY_FILE?.trim();
27638
27741
  if (process.env.ZLT_MCP_CLI !== "1" || !raw) return;
27639
- const readyFile = path14.resolve(raw);
27640
- if (path14.dirname(readyFile) !== path14.resolve(os5.tmpdir()) || !path14.basename(readyFile).startsWith("zlt-mcp-keepalive-")) {
27742
+ const readyFile = path15.resolve(raw);
27743
+ if (path15.dirname(readyFile) !== path15.resolve(os6.tmpdir()) || !path15.basename(readyFile).startsWith("zlt-mcp-keepalive-")) {
27641
27744
  return;
27642
27745
  }
27643
27746
  try {
27644
- const fd = fs13.openSync(readyFile, "wx", 384);
27645
- fs13.closeSync(fd);
27747
+ const fd = fs14.openSync(readyFile, "wx", 384);
27748
+ fs14.closeSync(fd);
27646
27749
  } catch (error2) {
27647
27750
  if (error2.code !== "EEXIST") {
27648
27751
  process.stderr.write(`[zlt-mcp-cli] keepalive readiness signal failed: ${error2 instanceof Error ? error2.message : String(error2)}
@@ -27739,16 +27842,30 @@ if (process.argv.length <= 2) {
27739
27842
  startMcpServer();
27740
27843
  } else {
27741
27844
  const program2 = new Command();
27845
+ program2.command("__install-worker <taskId> <argsJson>", { hidden: true }).action(async (taskId, argsJson) => {
27846
+ const config2 = loadAssistantRuntimeConfig(resolveDefaultRuntimeConfigPath());
27847
+ await runInstallWorker(taskId, argsJson, async (args, onProgress) => installRuntime({
27848
+ config: config2,
27849
+ installType: "mini",
27850
+ installDir: typeof args.installDir === "string" && args.installDir ? args.installDir : void 0,
27851
+ onProgress: (message) => {
27852
+ onProgress(message);
27853
+ process.stderr.write(`[zlt-runtime-install] ${message}
27854
+ `);
27855
+ },
27856
+ startRuntime: false
27857
+ }));
27858
+ });
27742
27859
  program2.name(CLI_NAME).description("MCP proxy for ZLTHost IPC service").version(resolveCliVersion()).addHelpText("after", "\nDiscovery: list for names; list --tool <name> --json for one complete input schema.\nUse call --help for input, output and diagnostic handling.");
27743
27860
  program2.command("__keepalive <kind> <id> [codePath]", { hidden: true }).action(async (kind, id, codePath) => {
27744
27861
  if (kind !== "backtest") throw new Error(`Unsupported keepalive kind: ${kind}`);
27745
27862
  await keepMcpBacktestAlive(id, codePath);
27746
27863
  });
27747
27864
  program2.command("call <tool>").description("Call any MCP tool through the bundled MCP server").configureOutput({
27748
- outputError: (message, write) => {
27749
- write(message);
27865
+ outputError: (message, write2) => {
27866
+ write2(message);
27750
27867
  if (message.includes("unknown option")) {
27751
- write("CLI argument error: toolExecution=not_started; no tool was called. Tool fields belong inside one JSON object passed to --args-json (or --args-file), not --flags or key=value arguments. Use call --help and list --tool <tool-name> --json, correct the arguments, then retry.\n");
27868
+ write2("CLI argument error: toolExecution=not_started; no tool was called. Tool fields belong inside one JSON object passed to --args-json (or --args-file), not --flags or key=value arguments. Use call --help and list --tool <tool-name> --json, correct the arguments, then retry.\n");
27752
27869
  }
27753
27870
  }
27754
27871
  }).option("--args-json <json>", "JSON object containing tool arguments").option("--args-file <path>", "Read the JSON argument object from a file").option("--output-json <path>", "Save the complete result to a new JSON file and print a compact receipt").option("--timeout-ms <ms>", "MCP request inactivity timeout in milliseconds").option("--max-total-timeout-ms <ms>", "Optional hard upper bound for the request").option("--no-progress", "Suppress progress diagnostics on stderr").addHelpText("after", `
@@ -27781,9 +27898,9 @@ Credentials belong in the configured local credential store, never in arguments.
27781
27898
  const args = parseMcpArgs(options.argsJson, options.argsFile);
27782
27899
  const timeoutMs = parseTimeoutOption(options.timeoutMs, "--timeout-ms");
27783
27900
  const maxTotalTimeoutMs = parseTimeoutOption(options.maxTotalTimeoutMs, "--max-total-timeout-ms");
27784
- const resultFile = options.outputJson === void 0 ? void 0 : path15.resolve(options.outputJson);
27901
+ const resultFile = options.outputJson === void 0 ? void 0 : path16.resolve(options.outputJson);
27785
27902
  stage = "output_prepare";
27786
- if (resultFile !== void 0) outputFd = fs14.openSync(resultFile, "wx");
27903
+ if (resultFile !== void 0) outputFd = fs15.openSync(resultFile, "wx");
27787
27904
  stage = "tool_call";
27788
27905
  toolExecution = "unknown";
27789
27906
  const result = await callMcpTool(tool, args, {
@@ -27798,8 +27915,8 @@ Credentials belong in the configured local credential store, never in arguments.
27798
27915
  if (outputFd !== void 0 && resultFile !== void 0) {
27799
27916
  stage = "output_write";
27800
27917
  try {
27801
- fs14.writeFileSync(outputFd, serialized, "utf-8");
27802
- fs14.closeSync(outputFd);
27918
+ fs15.writeFileSync(outputFd, serialized, "utf-8");
27919
+ fs15.closeSync(outputFd);
27803
27920
  outputFd = void 0;
27804
27921
  } catch (error2) {
27805
27922
  process.stdout.write(serialized);
@@ -27829,7 +27946,7 @@ Credentials belong in the configured local credential store, never in arguments.
27829
27946
  `);
27830
27947
  process.exitCode = 1;
27831
27948
  } finally {
27832
- if (outputFd !== void 0) fs14.closeSync(outputFd);
27949
+ if (outputFd !== void 0) fs15.closeSync(outputFd);
27833
27950
  }
27834
27951
  });
27835
27952
  program2.command("list").description("List MCP tools exposed by the bundled server").option("--json", "Emit the complete tools/list response as JSON").option("--tool <name>", "Select one exact tool name; combine with --json for its complete schema").addHelpText("after", "\nReuse discovery within a task. Query one schema with list --tool <name> --json.\nUnknown names fail with exit code 1. Preserve stderr separately from JSON stdout.").action(async (options) => {
@@ -27914,17 +28031,17 @@ function resolveCliVersion() {
27914
28031
  return resolveCliPackageProvenance().packageVersion;
27915
28032
  }
27916
28033
  function resolveCliPackageProvenance() {
27917
- let current = path15.dirname(path15.resolve(process.argv[1] || process.cwd()));
28034
+ let current = path16.dirname(path16.resolve(process.argv[1] || process.cwd()));
27918
28035
  for (let depth = 0; depth < 6; depth += 1) {
27919
- const manifestPath = path15.join(current, "package.json");
28036
+ const manifestPath = path16.join(current, "package.json");
27920
28037
  try {
27921
- const manifest = JSON.parse(fs14.readFileSync(manifestPath, "utf-8"));
28038
+ const manifest = JSON.parse(fs15.readFileSync(manifestPath, "utf-8"));
27922
28039
  if ((manifest.name === "@zltquant/zlt-mcp" || manifest.name === "zlt-mcp-proxy") && typeof manifest.version === "string") {
27923
28040
  return { packageName: manifest.name, packageVersion: manifest.version };
27924
28041
  }
27925
28042
  } catch {
27926
28043
  }
27927
- const parent = path15.dirname(current);
28044
+ const parent = path16.dirname(current);
27928
28045
  if (parent === current) break;
27929
28046
  current = parent;
27930
28047
  }
@@ -27942,6 +28059,7 @@ function compactCliReceipt(tool, result, resultFile) {
27942
28059
  if (source && typeof source === "object" && !Array.isArray(source)) {
27943
28060
  const fields = source;
27944
28061
  for (const key of [
28062
+ "taskId",
27945
28063
  "runId",
27946
28064
  "backtestId",
27947
28065
  "strategyId",