@zltquant/zlt-mcp 0.6.0-beta.0 → 0.6.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/config.json +10 -9
- package/package.json +1 -1
- package/zlt-mcp-proxy.bundle.cjs +366 -177
package/README.md
CHANGED
|
@@ -25,6 +25,12 @@ npx -y @zltquant/zlt-mcp call zlt-runtime-doctor --args-json '{}'
|
|
|
25
25
|
stderr 保留诊断,失败返回非零退出码。工具执行后若写文件失败,完整结果会输出到 stdout;先核对结果,不要自动重复执行。
|
|
26
26
|
不传该参数时保持原有完整 stdout。
|
|
27
27
|
|
|
28
|
+
回测可按当前工具 schema 传基线路径与覆盖:新建用 `strategyPath`(策略根 localPath),
|
|
29
|
+
重跑用 `codePath`(所选 runId 的运行目录)。MCP 先读配置并校验身份,再合并覆盖、补默认值,
|
|
30
|
+
沿原有 IPC 链提交完整参数。策略根是工作区/调试配置,正式 RUN 不保证更新根目录;运行目录用于该次结果对账。
|
|
31
|
+
无覆盖时省略 runParams,由 ZLTAF 读取库中参数;部分覆盖需合并完整基线。版本管理开启时已执行的正式 RUN 必须新建记录,不自动绕过拒绝。
|
|
32
|
+
`configurationEvidence` 标明基线来源/哈希与 `persistenceVerified=false`;提交回显不代表文件和数据库已回读一致。
|
|
33
|
+
|
|
28
34
|
其他支持原生 MCP 的客户端(Trae / Claude Code / Cursor 等)可以使用下面的配置:
|
|
29
35
|
|
|
30
36
|
```json
|
package/config.json
CHANGED
|
@@ -507,7 +507,7 @@
|
|
|
507
507
|
},
|
|
508
508
|
{
|
|
509
509
|
"name": "mcp-create-and-run-backtest",
|
|
510
|
-
"description": "创建并启动回测。strategyId 必须来自 mcp-create-strategy 返回的策略ID;runType 固定为 2
|
|
510
|
+
"description": "创建并启动回测。strategyId 必须来自 mcp-create-strategy 返回的策略ID;runType 固定为 2;推荐传 strategyPath(策略 localPath)和 runParams 中本次要改的字段;MCP 读取策略根目录当前配置,合并覆盖后形成完整提交参数,再走原有 run/create → run/run 同步链,不由 Agent 直接改文件或写库。策略根目录是工作区/调试配置,正式 RUN 模式不会保证更新它;只有 DEBUG 路径显式双写根目录和运行目录。不要称根目录为最近正式回测参数,运行身份以返回 runId 为准。没有 strategyPath 时保持旧式完整参数调用;仅真正缺失的字段补默认值。run/create 失败直接报错,不要去复用策略里自动生成的 debug runId(建策略时已回显为 debugRunId,跑它等于跑创建那一刻的模板快照)。run/create 生成快照后,MCP 会在真正启动前拒绝 get_current_data().get(...) 这种当前对象不支持的访问。\n\n**返回 runId、codePath 和 attemptFence 后立即调用 mcp-wait(kind=backtest,id=runId)阻塞等待回测结束,不要用 mcp-get-backtest-state 轮询。CLI 创建命令启动的隐藏 guardian 会自行携带 attemptFence;任何后续显式 CLI call 或 MCP 重启后的调用,都必须把 codePath 和 attemptFence 一起传回 mcp-wait,避免把上一轮残留的 result.json 当成本轮错误;同一 MCP 会话内可省略。**\n\n日线类频率只可见到 context.previous_date:要用交易日 T 的收盘,end 必须设成 T 的下一个交易日;end 落在未来不报错但结果为空。展开见返回的 dailyVisibilityNote / endWarning。\n\n返回 Data 的 resolvedStart/resolvedEnd/resolvedCapital、runParams 和 evidence.effectiveRunParams 是 MCP 补全后的提交参数,不是文件/数据库回读确认。configurationEvidence 标明提交证据及基线来源/哈希,persistenceVerified=false;运行目录 tradesetting.json 和库中对应运行记录是落盘对账依据。evidence 同时给出 backtestId、runDir 和代码快照 sourceSha256。**基准不在此列**:回显的 requestedBenchmark 只是请求值,策略 initialize 里的 set_benchmark() 会覆盖它,收益产物里的「基准收益」按策略实际用的基准算。说基准是什么之前先读策略代码里的 set_benchmark,否则会把一只个股的涨跌报成指数的。\n\n**期货回测要同时改三处,少一处引擎就按股票跑**:runParams.marketIds 加上对应期货交易所(zj 中金所、zs 郑商所、ds 大商所、sq 上期所、gq 广期所),account_list 的 account_type 改成 2(实测用 6 直接废单),费率用 ratio_tpl_obj.future。合约代码形如 zjIM2605。基准保持默认 sz399300 即可,它对期货策略只是业绩比较基准。数据前置见 mcp-download-data:除行情外还必须有市场规则 mr。",
|
|
511
511
|
"inputSchema": {
|
|
512
512
|
"type": "object",
|
|
513
513
|
"properties": {
|
|
@@ -529,7 +529,7 @@
|
|
|
529
529
|
},
|
|
530
530
|
"runParams": {
|
|
531
531
|
"type": "object",
|
|
532
|
-
"description": "
|
|
532
|
+
"description": "本次参数覆盖。提供 strategyPath 时先读策略当前配置,再递归合并对象覆盖(数组整体替换),最后补系统默认值;不需要复述整套费率。只改 initial_capital 时同步单账户现金;多账户须明确分配。未提供 strategyPath 时必须自行携带已有配置基线,省略值会使用系统默认值。",
|
|
533
533
|
"properties": {
|
|
534
534
|
"account_list": {
|
|
535
535
|
"type": "array",
|
|
@@ -651,6 +651,10 @@
|
|
|
651
651
|
}
|
|
652
652
|
},
|
|
653
653
|
"additionalProperties": false
|
|
654
|
+
},
|
|
655
|
+
"strategyPath": {
|
|
656
|
+
"type": "string",
|
|
657
|
+
"description": "策略根目录绝对路径,使用策略创建/详情返回的 localPath;不是 backtest 下的运行副本。提供时 MCP 读取该目录 .vscode/tradesetting.json 作为当前配置基线,runParams 只传本次覆盖;路径或 strategy_id 不匹配时在执行前拒绝。不提供时保持完整参数/系统默认值的兼容调用,不自动定位磁盘配置。"
|
|
654
658
|
}
|
|
655
659
|
},
|
|
656
660
|
"required": [
|
|
@@ -742,7 +746,7 @@
|
|
|
742
746
|
},
|
|
743
747
|
{
|
|
744
748
|
"name": "mcp-re-backtest",
|
|
745
|
-
"description": "
|
|
749
|
+
"description": "运行指定 runId 的代码副本,不会把你在策略源工程里刚改过的 main.py 拷进去。ZLTAF 启用回测版本管理时,正式 RUN 记录一旦执行过就不能同 runId 重跑,会返回“请先创建新的回测记录”;这时报告限制,不自动重试、改 DEBUG 或绕过版本管理。需要新一轮实验时按用户授权使用 mcp-create-and-run-backtest。\n\n不改变参数时省略 runParams 或传空对象,MCP 不补旧缓存参数,由 ZLTAF 读取数据库 run_params。改变部分参数时传所选 runId 的 codePath,MCP 校验运行配置并递归合并覆盖,形成完整参数;无路径时只兼容有缓存基线或完整参数的调用。ZLTAF 对非空参数整体采用,不自行合并。返回 configurationEvidence 区分 mcp_submission 与 zltaf_stored_parameters;两者均不证明文件/数据库已回读一致。后者不回显猜测的 effectiveRunParams。\n\n成功启动后按 runId、codePath、attemptFence 调用 mcp-wait,再由收尾读取该次运行文件和终态。根目录不作为历史配置,策略实际基准也不由请求值证明。",
|
|
746
750
|
"inputSchema": {
|
|
747
751
|
"type": "object",
|
|
748
752
|
"properties": {
|
|
@@ -760,7 +764,7 @@
|
|
|
760
764
|
},
|
|
761
765
|
"codePath": {
|
|
762
766
|
"type": "string",
|
|
763
|
-
"description": "
|
|
767
|
+
"description": "所选 runId 的运行目录绝对路径,用于身份校验、部分覆盖的配置基线和后续等待定位,不发送给 IPC。无参数覆盖时不把文件内容作为 runParams 重发;数据库配置由 ZLTAF 读取。"
|
|
764
768
|
},
|
|
765
769
|
"runType": {
|
|
766
770
|
"type": "integer",
|
|
@@ -772,7 +776,7 @@
|
|
|
772
776
|
},
|
|
773
777
|
"runParams": {
|
|
774
778
|
"type": "object",
|
|
775
|
-
"description": "
|
|
779
|
+
"description": "省略或空对象表示使用 ZLTAF 数据库存储参数,不依赖 MCP 缓存。非空对象表示本次覆盖:提供 codePath 时读取所选运行配置并递归合并;数组整体替换,多账户资金须明确分配。无 codePath 时需要缓存基线或完整参数,禁止把部分参数直接发送给会整体替换的后端。",
|
|
776
780
|
"properties": {
|
|
777
781
|
"marketIds": {
|
|
778
782
|
"type": "array",
|
|
@@ -795,10 +799,7 @@
|
|
|
795
799
|
},
|
|
796
800
|
"required": [
|
|
797
801
|
"strategyId",
|
|
798
|
-
"
|
|
799
|
-
"runId",
|
|
800
|
-
"runType",
|
|
801
|
-
"runParams"
|
|
802
|
+
"runId"
|
|
802
803
|
],
|
|
803
804
|
"additionalProperties": false
|
|
804
805
|
},
|
package/package.json
CHANGED
package/zlt-mcp-proxy.bundle.cjs
CHANGED
|
@@ -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
|
|
1151
|
-
var
|
|
1150
|
+
var path16 = require("node:path");
|
|
1151
|
+
var fs15 = 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();
|
|
@@ -2129,7 +2129,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2129
2129
|
* @param {string} subcommandName
|
|
2130
2130
|
*/
|
|
2131
2131
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
2132
|
-
if (
|
|
2132
|
+
if (fs15.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 =
|
|
2151
|
-
if (
|
|
2152
|
-
if (sourceExt.includes(
|
|
2150
|
+
const localBin = path16.resolve(baseDir, baseName);
|
|
2151
|
+
if (fs15.existsSync(localBin)) return localBin;
|
|
2152
|
+
if (sourceExt.includes(path16.extname(baseName))) return void 0;
|
|
2153
2153
|
const foundExt = sourceExt.find(
|
|
2154
|
-
(ext) =>
|
|
2154
|
+
(ext) => fs15.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 =
|
|
2166
|
+
resolvedScriptPath = fs15.realpathSync(this._scriptPath);
|
|
2167
2167
|
} catch {
|
|
2168
2168
|
resolvedScriptPath = this._scriptPath;
|
|
2169
2169
|
}
|
|
2170
|
-
executableDir =
|
|
2171
|
-
|
|
2170
|
+
executableDir = path16.resolve(
|
|
2171
|
+
path16.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 =
|
|
2178
|
+
const legacyName = path16.basename(
|
|
2179
2179
|
this._scriptPath,
|
|
2180
|
-
|
|
2180
|
+
path16.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(
|
|
2191
|
+
launchWithNode = sourceExt.includes(path16.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 =
|
|
3038
|
+
this._name = path16.basename(filename, path16.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(
|
|
3053
|
-
if (
|
|
3054
|
-
this._executableDir =
|
|
3052
|
+
executableDir(path17) {
|
|
3053
|
+
if (path17 === void 0) return this._executableDir;
|
|
3054
|
+
this._executableDir = path17;
|
|
3055
3055
|
return this;
|
|
3056
3056
|
}
|
|
3057
3057
|
/**
|
|
@@ -6516,8 +6516,8 @@ var require_utils = __commonJS({
|
|
|
6516
6516
|
}
|
|
6517
6517
|
return ind;
|
|
6518
6518
|
}
|
|
6519
|
-
function removeDotSegments(
|
|
6520
|
-
let input =
|
|
6519
|
+
function removeDotSegments(path16) {
|
|
6520
|
+
let input = path16;
|
|
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 [
|
|
6720
|
-
wsComponent.path =
|
|
6719
|
+
const [path16, query] = wsComponent.resourceName.split("?");
|
|
6720
|
+
wsComponent.path = path16 && path16 !== "/" ? path16 : 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,
|
|
10082
|
+
function addFormats(ajv, list, fs15, 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,
|
|
10087
|
+
ajv.addFormat(f, fs15[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
|
|
10101
|
-
function checkPathExt(
|
|
10100
|
+
var fs15 = require("fs");
|
|
10101
|
+
function checkPathExt(path16, 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 &&
|
|
10112
|
+
if (p && path16.substr(-p.length).toLowerCase() === p) {
|
|
10113
10113
|
return true;
|
|
10114
10114
|
}
|
|
10115
10115
|
}
|
|
10116
10116
|
return false;
|
|
10117
10117
|
}
|
|
10118
|
-
function checkStat(stat,
|
|
10118
|
+
function checkStat(stat, path16, options) {
|
|
10119
10119
|
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
10120
10120
|
return false;
|
|
10121
10121
|
}
|
|
10122
|
-
return checkPathExt(
|
|
10122
|
+
return checkPathExt(path16, options);
|
|
10123
10123
|
}
|
|
10124
|
-
function isexe(
|
|
10125
|
-
|
|
10126
|
-
cb(er, er ? false : checkStat(stat,
|
|
10124
|
+
function isexe(path16, options, cb) {
|
|
10125
|
+
fs15.stat(path16, function(er, stat) {
|
|
10126
|
+
cb(er, er ? false : checkStat(stat, path16, options));
|
|
10127
10127
|
});
|
|
10128
10128
|
}
|
|
10129
|
-
function sync(
|
|
10130
|
-
return checkStat(
|
|
10129
|
+
function sync(path16, options) {
|
|
10130
|
+
return checkStat(fs15.statSync(path16), path16, 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
|
|
10141
|
-
function isexe(
|
|
10142
|
-
|
|
10140
|
+
var fs15 = require("fs");
|
|
10141
|
+
function isexe(path16, options, cb) {
|
|
10142
|
+
fs15.stat(path16, function(er, stat) {
|
|
10143
10143
|
cb(er, er ? false : checkStat(stat, options));
|
|
10144
10144
|
});
|
|
10145
10145
|
}
|
|
10146
|
-
function sync(
|
|
10147
|
-
return checkStat(
|
|
10146
|
+
function sync(path16, options) {
|
|
10147
|
+
return checkStat(fs15.statSync(path16), 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
|
|
10171
|
+
var fs15 = 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(
|
|
10180
|
+
function isexe(path16, 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(
|
|
10190
|
+
isexe(path16, 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(
|
|
10199
|
+
core(path16, 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(
|
|
10209
|
+
function sync(path16, options) {
|
|
10210
10210
|
try {
|
|
10211
|
-
return core.sync(
|
|
10211
|
+
return core.sync(path16, 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
|
|
10227
|
+
var path16 = 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 =
|
|
10265
|
+
const pCmd = path16.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 =
|
|
10292
|
+
const pCmd = path16.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
|
|
10340
|
+
var path16 = 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 ?
|
|
10358
|
+
pathExt: withoutPathExt ? path16.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 =
|
|
10367
|
+
resolved = path16.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 [
|
|
10422
|
-
const binary =
|
|
10421
|
+
const [path16, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
10422
|
+
const binary = path16.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
|
|
10435
|
+
var fs15 = 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 =
|
|
10443
|
-
|
|
10444
|
-
|
|
10442
|
+
fd = fs15.openSync(command, "r");
|
|
10443
|
+
fs15.readSync(fd, buffer, 0, size, 0);
|
|
10444
|
+
fs15.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
|
|
10457
|
+
var path16 = 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 =
|
|
10482
|
+
parsed.command = path16.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(" ");
|
|
@@ -10607,8 +10607,8 @@ var {
|
|
|
10607
10607
|
} = import_index.default;
|
|
10608
10608
|
|
|
10609
10609
|
// src/index.ts
|
|
10610
|
-
var
|
|
10611
|
-
var
|
|
10610
|
+
var fs14 = __toESM(require("node:fs"), 1);
|
|
10611
|
+
var path15 = __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,
|
|
10816
|
-
if (!
|
|
10815
|
+
function getElementAtPath(obj, path16) {
|
|
10816
|
+
if (!path16)
|
|
10817
10817
|
return obj;
|
|
10818
|
-
return
|
|
10818
|
+
return path16.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(
|
|
11138
|
+
function prefixIssues(path16, issues) {
|
|
11139
11139
|
return issues.map((iss) => {
|
|
11140
11140
|
var _a;
|
|
11141
11141
|
(_a = iss).path ?? (_a.path = []);
|
|
11142
|
-
iss.path.unshift(
|
|
11142
|
+
iss.path.unshift(path16);
|
|
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
|
|
19170
|
-
const
|
|
19171
|
-
const zltFile =
|
|
19172
|
-
return
|
|
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() : "";
|
|
19173
19173
|
}
|
|
19174
19174
|
async function pipeExists2(pipeName) {
|
|
19175
|
-
const
|
|
19175
|
+
const fs15 = await import("fs");
|
|
19176
19176
|
try {
|
|
19177
19177
|
if (process.platform === "win32") {
|
|
19178
|
-
return
|
|
19178
|
+
return fs15.readdirSync("\\\\.\\pipe\\").includes(pipeName);
|
|
19179
19179
|
}
|
|
19180
|
-
return
|
|
19180
|
+
return fs15.existsSync(`/tmp/${pipeName}`);
|
|
19181
19181
|
} catch {
|
|
19182
19182
|
return false;
|
|
19183
19183
|
}
|
|
@@ -19387,8 +19387,8 @@ async function updateRuntimeLeaseActiveJob(handle, runId, active, options = {})
|
|
|
19387
19387
|
async function releaseRuntimeLease(handle, options = {}) {
|
|
19388
19388
|
const deps = options.deps ?? defaultRuntimeLifecycleDeps;
|
|
19389
19389
|
return withLifecycleLock(handle.workRoot, deps, async (stateDir) => {
|
|
19390
|
-
const
|
|
19391
|
-
if (
|
|
19390
|
+
const record3 = readJson(leasePath(stateDir, handle.token));
|
|
19391
|
+
if (record3 && sameIdentity(record3.holder, handle.holder)) {
|
|
19392
19392
|
fs3.rmSync(leasePath(stateDir, handle.token), { force: true });
|
|
19393
19393
|
}
|
|
19394
19394
|
const recordedOwner = readJson(ownerPath(stateDir));
|
|
@@ -19591,13 +19591,13 @@ function readAndPruneStore(stateDir, deps) {
|
|
|
19591
19591
|
if (!entry.isFile() || !entry.name.endsWith(".json"))
|
|
19592
19592
|
continue;
|
|
19593
19593
|
const filePath = path3.join(leasesDir, entry.name);
|
|
19594
|
-
const
|
|
19595
|
-
const current =
|
|
19596
|
-
if (!
|
|
19594
|
+
const record3 = readJson(filePath);
|
|
19595
|
+
const current = record3 ? deps.inspectProcess(record3.holder.pid) : null;
|
|
19596
|
+
if (!record3 || !current || !sameIdentity(current, record3.holder)) {
|
|
19597
19597
|
fs3.rmSync(filePath, { force: true });
|
|
19598
19598
|
continue;
|
|
19599
19599
|
}
|
|
19600
|
-
leases.push(
|
|
19600
|
+
leases.push(record3);
|
|
19601
19601
|
}
|
|
19602
19602
|
let owner = normalizeRuntimeOwnerRecord(readJson(ownerPath(stateDir)));
|
|
19603
19603
|
if (owner) {
|
|
@@ -19609,21 +19609,21 @@ function readAndPruneStore(stateDir, deps) {
|
|
|
19609
19609
|
}
|
|
19610
19610
|
return { owner, leases };
|
|
19611
19611
|
}
|
|
19612
|
-
function normalizeRuntimeOwnerRecord(
|
|
19613
|
-
if (!
|
|
19612
|
+
function normalizeRuntimeOwnerRecord(record3) {
|
|
19613
|
+
if (!record3)
|
|
19614
19614
|
return null;
|
|
19615
|
-
const activeJobIds = new Set(normalizeRunIds(
|
|
19616
|
-
const legacyBoundJobIds = normalizeRunIds(
|
|
19617
|
-
const legacyResolvedJobIds = new Set(normalizeRunIds(
|
|
19615
|
+
const activeJobIds = new Set(normalizeRunIds(record3.activeJobIds));
|
|
19616
|
+
const legacyBoundJobIds = normalizeRunIds(record3.legacyBoundJobIds);
|
|
19617
|
+
const legacyResolvedJobIds = new Set(normalizeRunIds(record3.legacyResolvedJobIds));
|
|
19618
19618
|
for (const runId of legacyBoundJobIds) {
|
|
19619
19619
|
activeJobIds.add(runId);
|
|
19620
19620
|
legacyResolvedJobIds.delete(runId);
|
|
19621
19621
|
}
|
|
19622
19622
|
return {
|
|
19623
|
-
process:
|
|
19624
|
-
startedAt:
|
|
19623
|
+
process: record3.process,
|
|
19624
|
+
startedAt: record3.startedAt,
|
|
19625
19625
|
activeJobIds: [...activeJobIds].sort(),
|
|
19626
|
-
legacyActiveJobs:
|
|
19626
|
+
legacyActiveJobs: record3.legacyActiveJobs === void 0 ? normalizeLegacyActiveJobs(record3.activeJobs) : normalizeLegacyActiveJobs(record3.legacyActiveJobs),
|
|
19627
19627
|
legacyBoundJobIds,
|
|
19628
19628
|
legacyResolvedJobIds: [...legacyResolvedJobIds].sort()
|
|
19629
19629
|
};
|
|
@@ -21715,14 +21715,14 @@ function appendHistory(outputDir, uri, statusCode, contentSize, respFile) {
|
|
|
21715
21715
|
fs9.writeFileSync(historyPath, kept.join("\n") + "\n", "utf-8");
|
|
21716
21716
|
}
|
|
21717
21717
|
}
|
|
21718
|
-
const
|
|
21718
|
+
const record3 = {
|
|
21719
21719
|
time: getTimestampISO(),
|
|
21720
21720
|
uri,
|
|
21721
21721
|
status: statusCode,
|
|
21722
21722
|
size: contentSize
|
|
21723
21723
|
};
|
|
21724
|
-
if (respFile)
|
|
21725
|
-
fs9.appendFileSync(historyPath, JSON.stringify(
|
|
21724
|
+
if (respFile) record3.file = respFile;
|
|
21725
|
+
fs9.appendFileSync(historyPath, JSON.stringify(record3) + "\n", "utf-8");
|
|
21726
21726
|
}
|
|
21727
21727
|
function cleanOutput(clientRootDir, maxDays = 1) {
|
|
21728
21728
|
const outputDir = getOutputDir(clientRootDir);
|
|
@@ -21895,13 +21895,13 @@ function backtestHandoff(result) {
|
|
|
21895
21895
|
const payload = parseMcpResult(result);
|
|
21896
21896
|
const data = payload?.Data;
|
|
21897
21897
|
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
21898
|
-
const
|
|
21899
|
-
const status = Number(
|
|
21898
|
+
const record3 = data;
|
|
21899
|
+
const status = Number(record3.status);
|
|
21900
21900
|
if (Number.isFinite(status) && status !== 0 && status !== 1) return null;
|
|
21901
|
-
const runId = typeof
|
|
21901
|
+
const runId = typeof record3.runId === "string" ? record3.runId.trim() : "";
|
|
21902
21902
|
if (!runId) return null;
|
|
21903
|
-
const evidence =
|
|
21904
|
-
const rawCodePath = typeof
|
|
21903
|
+
const evidence = record3.evidence && typeof record3.evidence === "object" && !Array.isArray(record3.evidence) ? record3.evidence : void 0;
|
|
21904
|
+
const rawCodePath = typeof record3.codePath === "string" ? record3.codePath.trim() : typeof evidence?.runDir === "string" ? evidence.runDir.trim() : "";
|
|
21905
21905
|
return {
|
|
21906
21906
|
runId,
|
|
21907
21907
|
...rawCodePath && path9.isAbsolute(rawCodePath) ? { codePath: rawCodePath } : {}
|
|
@@ -21915,13 +21915,13 @@ function parseKeepaliveLockRecord(raw) {
|
|
|
21915
21915
|
try {
|
|
21916
21916
|
const parsed = JSON.parse(raw.toString("utf-8"));
|
|
21917
21917
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
21918
|
-
const
|
|
21919
|
-
const processIdentity = parseRuntimeProcessIdentity(
|
|
21920
|
-
return typeof
|
|
21921
|
-
token:
|
|
21922
|
-
pid: Number(
|
|
21918
|
+
const record3 = parsed;
|
|
21919
|
+
const processIdentity = parseRuntimeProcessIdentity(record3.processIdentity);
|
|
21920
|
+
return typeof record3.token === "string" && record3.token.length > 0 && Number.isSafeInteger(record3.pid) && Number(record3.pid) > 0 && processIdentity?.pid === Number(record3.pid) && Number.isSafeInteger(record3.heartbeatAt) && Number(record3.heartbeatAt) > 0 ? {
|
|
21921
|
+
token: record3.token,
|
|
21922
|
+
pid: Number(record3.pid),
|
|
21923
21923
|
processIdentity,
|
|
21924
|
-
heartbeatAt: Number(
|
|
21924
|
+
heartbeatAt: Number(record3.heartbeatAt)
|
|
21925
21925
|
} : null;
|
|
21926
21926
|
} catch {
|
|
21927
21927
|
return null;
|
|
@@ -21929,11 +21929,11 @@ function parseKeepaliveLockRecord(raw) {
|
|
|
21929
21929
|
}
|
|
21930
21930
|
function parseRuntimeProcessIdentity(value) {
|
|
21931
21931
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
21932
|
-
const
|
|
21933
|
-
return Number.isSafeInteger(
|
|
21934
|
-
pid: Number(
|
|
21935
|
-
executablePath:
|
|
21936
|
-
creationTime:
|
|
21932
|
+
const record3 = value;
|
|
21933
|
+
return Number.isSafeInteger(record3.pid) && Number(record3.pid) > 0 && typeof record3.executablePath === "string" && record3.executablePath.length > 0 && typeof record3.creationTime === "string" && record3.creationTime.length > 0 ? {
|
|
21934
|
+
pid: Number(record3.pid),
|
|
21935
|
+
executablePath: record3.executablePath,
|
|
21936
|
+
creationTime: record3.creationTime
|
|
21937
21937
|
} : null;
|
|
21938
21938
|
}
|
|
21939
21939
|
function readKeepaliveLock(lockPath) {
|
|
@@ -21975,15 +21975,15 @@ function currentKeepaliveProcessIdentity() {
|
|
|
21975
21975
|
if (!identity) throw new Error(`Unable to identify keepalive process pid=${process.pid}`);
|
|
21976
21976
|
return identity;
|
|
21977
21977
|
}
|
|
21978
|
-
function keepaliveProcessIsCurrent(
|
|
21979
|
-
if (!processIsAlive(
|
|
21980
|
-
const current = inspectRuntimeProcess(
|
|
21981
|
-
return current ? sameProcessIdentity(current,
|
|
21978
|
+
function keepaliveProcessIsCurrent(record3) {
|
|
21979
|
+
if (!processIsAlive(record3.pid)) return false;
|
|
21980
|
+
const current = inspectRuntimeProcess(record3.pid);
|
|
21981
|
+
return current ? sameProcessIdentity(current, record3.processIdentity) : true;
|
|
21982
21982
|
}
|
|
21983
|
-
function writeNewKeepaliveLock(lockPath,
|
|
21983
|
+
function writeNewKeepaliveLock(lockPath, record3) {
|
|
21984
21984
|
const descriptor = fs9.openSync(lockPath, "wx", 384);
|
|
21985
21985
|
try {
|
|
21986
|
-
fs9.writeFileSync(descriptor, JSON.stringify(
|
|
21986
|
+
fs9.writeFileSync(descriptor, JSON.stringify(record3), "utf-8");
|
|
21987
21987
|
} finally {
|
|
21988
21988
|
fs9.closeSync(descriptor);
|
|
21989
21989
|
}
|
|
@@ -22054,8 +22054,8 @@ function releaseKeepaliveLock(ownership) {
|
|
|
22054
22054
|
retireKeepaliveLockIfUnchanged(ownership.lockPath, current.identity);
|
|
22055
22055
|
}
|
|
22056
22056
|
}
|
|
22057
|
-
function keepaliveLeaseIsFresh(
|
|
22058
|
-
return keepaliveTimestampIsFresh(
|
|
22057
|
+
function keepaliveLeaseIsFresh(record3) {
|
|
22058
|
+
return keepaliveTimestampIsFresh(record3.heartbeatAt);
|
|
22059
22059
|
}
|
|
22060
22060
|
function keepaliveTimestampIsFresh(timestamp) {
|
|
22061
22061
|
const age = Date.now() - timestamp;
|
|
@@ -23123,9 +23123,9 @@ var StdioServerTransport = class {
|
|
|
23123
23123
|
};
|
|
23124
23124
|
|
|
23125
23125
|
// src/mcp-server.ts
|
|
23126
|
-
var
|
|
23126
|
+
var fs13 = __toESM(require("node:fs"), 1);
|
|
23127
23127
|
var os5 = __toESM(require("node:os"), 1);
|
|
23128
|
-
var
|
|
23128
|
+
var path14 = __toESM(require("node:path"), 1);
|
|
23129
23129
|
|
|
23130
23130
|
// src/tool-profile-contract.mjs
|
|
23131
23131
|
var UNIVERSAL_AGENT_RUNTIME_TOOL_NAMES = Object.freeze([
|
|
@@ -23188,9 +23188,9 @@ var NPM_PACKAGE_CONFIG_TOOL_NAMES = Object.freeze([
|
|
|
23188
23188
|
]);
|
|
23189
23189
|
|
|
23190
23190
|
// src/tool-pipeline.ts
|
|
23191
|
-
var
|
|
23192
|
-
var
|
|
23193
|
-
var
|
|
23191
|
+
var fs12 = __toESM(require("node:fs"), 1);
|
|
23192
|
+
var path12 = __toESM(require("node:path"), 1);
|
|
23193
|
+
var import_node_crypto3 = require("node:crypto");
|
|
23194
23194
|
|
|
23195
23195
|
// src/feature-set.ts
|
|
23196
23196
|
function resolveFeatureSet() {
|
|
@@ -23199,6 +23199,119 @@ function resolveFeatureSet() {
|
|
|
23199
23199
|
var MASKED_FACTOR_MESSAGE = "\u56E0\u5B50\u7814\u7A76\u529F\u80FD\u5728\u5F53\u524D\u7248\u672C\u672A\u5F00\u653E\u3002";
|
|
23200
23200
|
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
23201
|
|
|
23202
|
+
// src/backtest-config.ts
|
|
23203
|
+
var fs11 = __toESM(require("node:fs"), 1);
|
|
23204
|
+
var path11 = __toESM(require("node:path"), 1);
|
|
23205
|
+
var import_node_crypto2 = require("node:crypto");
|
|
23206
|
+
var BACKTEST_CONFIG_KEYS = [
|
|
23207
|
+
"start",
|
|
23208
|
+
"end",
|
|
23209
|
+
"freq",
|
|
23210
|
+
"kcount",
|
|
23211
|
+
"marketIds",
|
|
23212
|
+
"trade_type",
|
|
23213
|
+
"initial_capital",
|
|
23214
|
+
"account_list",
|
|
23215
|
+
"base_tpl_obj",
|
|
23216
|
+
"ratio_tpl_obj"
|
|
23217
|
+
];
|
|
23218
|
+
var INTERNAL_CONFIG_KEYS = ["btmode", "st_parmas", "mode", "class_type", "base_tpl_id", "ratio_tpl_id"];
|
|
23219
|
+
var BASE_KEYS = [
|
|
23220
|
+
"name",
|
|
23221
|
+
"zhCnName",
|
|
23222
|
+
"benchmark",
|
|
23223
|
+
"matching_mode",
|
|
23224
|
+
"slippage",
|
|
23225
|
+
"avoid_future",
|
|
23226
|
+
"open_cache",
|
|
23227
|
+
"match_with_order_book",
|
|
23228
|
+
"max_trade_ratio",
|
|
23229
|
+
"order_volume_ratio",
|
|
23230
|
+
"take_fee_type",
|
|
23231
|
+
"adjust_aqty_by_avail",
|
|
23232
|
+
"jv_kuan_open_avg_cost_switch"
|
|
23233
|
+
];
|
|
23234
|
+
var FEE_KEYS = [
|
|
23235
|
+
"open_commission",
|
|
23236
|
+
"close_commission",
|
|
23237
|
+
"close_today_commission",
|
|
23238
|
+
"min_commission",
|
|
23239
|
+
"open_tax",
|
|
23240
|
+
"close_tax",
|
|
23241
|
+
"margin_ratio"
|
|
23242
|
+
];
|
|
23243
|
+
var record2 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
23244
|
+
var pick2 = (v, keys) => Object.fromEntries(keys.filter((k) => Object.prototype.hasOwnProperty.call(v, k)).map((k) => [k, v[k]]));
|
|
23245
|
+
function readBacktestBaseline(tool, args) {
|
|
23246
|
+
const create = tool === "mcp-create-and-run-backtest";
|
|
23247
|
+
if (!create && tool !== "mcp-re-backtest") return void 0;
|
|
23248
|
+
const directory = args[create ? "strategyPath" : "codePath"];
|
|
23249
|
+
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") {
|
|
23253
|
+
throw new Error("strategyPath must identify the strategy root, not a historical backtest directory");
|
|
23254
|
+
}
|
|
23255
|
+
const file = path11.join(root, ".vscode", "tradesetting.json");
|
|
23256
|
+
const raw = fs11.readFileSync(file);
|
|
23257
|
+
let config2;
|
|
23258
|
+
try {
|
|
23259
|
+
config2 = JSON.parse(raw.toString("utf8").replace(/^\uFEFF/, ""));
|
|
23260
|
+
} catch {
|
|
23261
|
+
throw new Error("Configuration baseline is not valid JSON");
|
|
23262
|
+
}
|
|
23263
|
+
if (!record2(config2) || config2.strategy_id !== args.strategyId) throw new Error("Configuration baseline strategy_id is missing or mismatched");
|
|
23264
|
+
if (!create && (typeof args.runId !== "string" || config2.backtest_id !== args.runId)) {
|
|
23265
|
+
throw new Error("Configuration baseline backtest_id does not match the requested runId");
|
|
23266
|
+
}
|
|
23267
|
+
const params = pick2(config2, [...BACKTEST_CONFIG_KEYS, ...INTERNAL_CONFIG_KEYS]);
|
|
23268
|
+
for (const key of ["base_tpl_obj", "ratio_tpl_obj"]) {
|
|
23269
|
+
if (params[key] !== void 0 && !record2(params[key])) throw new Error(`Configuration baseline ${key} must be an object`);
|
|
23270
|
+
}
|
|
23271
|
+
if (record2(params.base_tpl_obj)) params.base_tpl_obj = pick2(params.base_tpl_obj, BASE_KEYS);
|
|
23272
|
+
if (record2(params.ratio_tpl_obj)) {
|
|
23273
|
+
const fees = params.ratio_tpl_obj;
|
|
23274
|
+
for (const asset of ["stock", "future", "fund", "bond"]) {
|
|
23275
|
+
if (fees[asset] !== void 0 && !record2(fees[asset])) throw new Error(`Configuration baseline fee section ${asset} must be an object`);
|
|
23276
|
+
}
|
|
23277
|
+
params.ratio_tpl_obj = {
|
|
23278
|
+
...pick2(fees, ["name", "zhCnName"]),
|
|
23279
|
+
...Object.fromEntries(["stock", "future", "fund", "bond"].filter((k) => record2(fees[k])).map((k) => [k, pick2(fees[k], FEE_KEYS)]))
|
|
23280
|
+
};
|
|
23281
|
+
}
|
|
23282
|
+
if (Array.isArray(params.account_list)) {
|
|
23283
|
+
params.account_list = params.account_list.map((account) => {
|
|
23284
|
+
if (!record2(account)) throw new Error("Configuration baseline account_list contains a non-object");
|
|
23285
|
+
const result = pick2(account, ["pindex", "account_id", "cash", "account_type"]);
|
|
23286
|
+
if (create && typeof result.account_id === "string" && /^RN-[A-Za-z0-9-]+_\d+$/.test(result.account_id)) result.account_id = "";
|
|
23287
|
+
return result;
|
|
23288
|
+
});
|
|
23289
|
+
}
|
|
23290
|
+
return { params, evidence: {
|
|
23291
|
+
kind: create ? "strategy_current" : "selected_run",
|
|
23292
|
+
path: file,
|
|
23293
|
+
sha256: (0, import_node_crypto2.createHash)("sha256").update(raw).digest("hex")
|
|
23294
|
+
} };
|
|
23295
|
+
}
|
|
23296
|
+
function reconcileBaselineCapital(params, overrides) {
|
|
23297
|
+
const accounts = params.account_list;
|
|
23298
|
+
if (!Array.isArray(accounts) || !accounts.length || accounts.some((a) => !record2(a) || typeof a.cash !== "number" || !Number.isFinite(a.cash) || a.cash < 0)) {
|
|
23299
|
+
throw new Error("Configuration baseline requires accounts with finite nonnegative cash");
|
|
23300
|
+
}
|
|
23301
|
+
const explicitCapital = Object.prototype.hasOwnProperty.call(overrides, "initial_capital");
|
|
23302
|
+
const explicitAccounts = Object.prototype.hasOwnProperty.call(overrides, "account_list");
|
|
23303
|
+
if (explicitCapital && !explicitAccounts) {
|
|
23304
|
+
if (accounts.length !== 1) throw new Error("Changing capital for multiple accounts requires an explicit account_list allocation");
|
|
23305
|
+
if (typeof params.initial_capital !== "number" || !Number.isFinite(params.initial_capital) || params.initial_capital <= 0) throw new Error("initial_capital must be positive and finite");
|
|
23306
|
+
accounts[0] = { ...accounts[0], cash: params.initial_capital };
|
|
23307
|
+
}
|
|
23308
|
+
const total = accounts.reduce((sum, a) => sum + a.cash, 0);
|
|
23309
|
+
if (explicitAccounts && !explicitCapital || params.initial_capital === void 0) params.initial_capital = total;
|
|
23310
|
+
if (typeof params.initial_capital !== "number" || !Number.isFinite(params.initial_capital) || params.initial_capital <= 0 || Math.abs(params.initial_capital - total) > 5e-3) {
|
|
23311
|
+
throw new Error("initial_capital must match the sum of account cash; supply a consistent allocation");
|
|
23312
|
+
}
|
|
23313
|
+
}
|
|
23314
|
+
|
|
23202
23315
|
// src/tool-pipeline.ts
|
|
23203
23316
|
function finitePositiveNumber(value) {
|
|
23204
23317
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -23228,6 +23341,44 @@ function isFuturesRun(marketIds) {
|
|
|
23228
23341
|
return marketIds.some((id) => FUTURES_MARKET_IDS.has(String(id).trim().toLowerCase()));
|
|
23229
23342
|
}
|
|
23230
23343
|
var identityRepairHint = (data) => data;
|
|
23344
|
+
function prepareToolCallArgs(tool, args, contexts) {
|
|
23345
|
+
const clean = { ...args };
|
|
23346
|
+
delete clean.__configBaseline;
|
|
23347
|
+
delete clean.__storedRunParams;
|
|
23348
|
+
try {
|
|
23349
|
+
if (tool.name === "mcp-re-backtest" && (clean.runParams === void 0 || isRecord2(clean.runParams) && Object.keys(clean.runParams).length === 0)) {
|
|
23350
|
+
readBacktestBaseline(tool.name, clean);
|
|
23351
|
+
const prior = typeof clean.runId === "string" ? contexts.get(clean.runId) : void 0;
|
|
23352
|
+
if (prior && prior.strategyId !== clean.strategyId) throw new Error("Cached run belongs to another strategy");
|
|
23353
|
+
delete clean.runParams;
|
|
23354
|
+
return prepareToolArgs(tool, applyToolArgDefaults(tool, { ...clean, __storedRunParams: true }), contexts);
|
|
23355
|
+
}
|
|
23356
|
+
const baseline = readBacktestBaseline(tool.name, clean);
|
|
23357
|
+
if (!baseline) {
|
|
23358
|
+
if (tool.name === "mcp-re-backtest") {
|
|
23359
|
+
const prior = typeof clean.runId === "string" ? contexts.get(clean.runId) : void 0;
|
|
23360
|
+
if (prior && prior.strategyId !== clean.strategyId) throw new Error("Cached run belongs to another strategy");
|
|
23361
|
+
const supplied = isRecord2(clean.runParams) ? clean.runParams : {};
|
|
23362
|
+
if (!prior?.runParams && BACKTEST_CONFIG_KEYS.some((key) => supplied[key] === void 0 || supplied[key] === null)) {
|
|
23363
|
+
throw new Error("Rerun has no persistent or cached baseline; supply codePath or complete runParams");
|
|
23364
|
+
}
|
|
23365
|
+
}
|
|
23366
|
+
return prepareToolArgs(tool, applyToolArgDefaults(tool, clean), contexts);
|
|
23367
|
+
}
|
|
23368
|
+
if (clean.runParams !== void 0 && !isRecord2(clean.runParams)) throw new Error("runParams overrides must be an object");
|
|
23369
|
+
const overrides = clean.runParams ?? {};
|
|
23370
|
+
const runParams = applyBodyDefaults(baseline.params, overrides);
|
|
23371
|
+
const merged = applyToolArgDefaults(tool, { ...clean, runParams, __configBaseline: baseline.evidence });
|
|
23372
|
+
reconcileBaselineCapital(merged.runParams, overrides);
|
|
23373
|
+
return prepareToolArgs(tool, merged, contexts);
|
|
23374
|
+
} catch (error2) {
|
|
23375
|
+
return jsonToolResult(10063, "\u56DE\u6D4B\u914D\u7F6E\u57FA\u7EBF\u4E0D\u53EF\u7528\u6216\u8986\u76D6\u53C2\u6570\u51B2\u7A81", {
|
|
23376
|
+
reason: error2 instanceof Error ? error2.message : String(error2),
|
|
23377
|
+
toolExecution: "not_started",
|
|
23378
|
+
action: "Check the supplied strategyPath/codePath, configuration identity and account allocation, then retry."
|
|
23379
|
+
}, true);
|
|
23380
|
+
}
|
|
23381
|
+
}
|
|
23231
23382
|
function prepareToolArgs(tool, args, contexts) {
|
|
23232
23383
|
const inherited = inheritReBacktestRunParams(tool, args, contexts);
|
|
23233
23384
|
const dated = applyBacktestDateDefaults(tool, inherited);
|
|
@@ -23362,7 +23513,7 @@ function readSlaveProperties(filePath) {
|
|
|
23362
23513
|
const entries = /* @__PURE__ */ new Map();
|
|
23363
23514
|
let raw;
|
|
23364
23515
|
try {
|
|
23365
|
-
raw =
|
|
23516
|
+
raw = fs12.readFileSync(filePath, "utf-8");
|
|
23366
23517
|
} catch {
|
|
23367
23518
|
return entries;
|
|
23368
23519
|
}
|
|
@@ -23386,18 +23537,18 @@ function resolveFactorProjectRoot(clientRootDir) {
|
|
|
23386
23537
|
if (cached2) return cached2;
|
|
23387
23538
|
const root = clientRootDir.replace(/[\\/]+$/, "");
|
|
23388
23539
|
const configured = expandSlaveValue(
|
|
23389
|
-
readSlaveProperties(
|
|
23540
|
+
readSlaveProperties(path12.join(root, ...ZLTAF_CONFIG_SEGMENTS)),
|
|
23390
23541
|
"slave.factor.project-path",
|
|
23391
23542
|
root
|
|
23392
23543
|
);
|
|
23393
|
-
const resolved = configured ?
|
|
23544
|
+
const resolved = configured ? path12.normalize(configured) : path12.join(root, ...FALLBACK_FACTOR_PROJECT_PATH);
|
|
23394
23545
|
factorProjectRootCache.set(clientRootDir, resolved);
|
|
23395
23546
|
return resolved;
|
|
23396
23547
|
}
|
|
23397
23548
|
function resolveFactorWorkspacePath(clientRootDir, factorId) {
|
|
23398
23549
|
if (!clientRootDir || !factorId) return void 0;
|
|
23399
23550
|
const projectRoot = resolveFactorProjectRoot(clientRootDir);
|
|
23400
|
-
return projectRoot ?
|
|
23551
|
+
return projectRoot ? path12.join(projectRoot, factorId) : void 0;
|
|
23401
23552
|
}
|
|
23402
23553
|
var MODULE_LEVEL_FACTOR_EXPORT = /^(?:(?:async\s+)?def\s+get_factor\s*\(|get_factor\s*=(?!=)|Factor\s*=(?!=))/m;
|
|
23403
23554
|
function checkFactorSourceLoadable(clientRootDir, factorId) {
|
|
@@ -23405,7 +23556,7 @@ function checkFactorSourceLoadable(clientRootDir, factorId) {
|
|
|
23405
23556
|
if (!workspacePath) return null;
|
|
23406
23557
|
let source;
|
|
23407
23558
|
try {
|
|
23408
|
-
source =
|
|
23559
|
+
source = fs12.readFileSync(path12.join(workspacePath, "main.py"), "utf8");
|
|
23409
23560
|
} catch {
|
|
23410
23561
|
return null;
|
|
23411
23562
|
}
|
|
@@ -23504,6 +23655,9 @@ var CONTROL_PARAMS = [
|
|
|
23504
23655
|
"timeout",
|
|
23505
23656
|
"confirm",
|
|
23506
23657
|
"codePath",
|
|
23658
|
+
"strategyPath",
|
|
23659
|
+
"__configBaseline",
|
|
23660
|
+
"__storedRunParams",
|
|
23507
23661
|
"attemptFence",
|
|
23508
23662
|
"__attemptStartedAtMs",
|
|
23509
23663
|
"__resultBaseline"
|
|
@@ -23524,12 +23678,12 @@ function normalizeBacktestRunName(tool, args) {
|
|
|
23524
23678
|
};
|
|
23525
23679
|
}
|
|
23526
23680
|
function inheritReBacktestRunParams(tool, args, contexts) {
|
|
23527
|
-
if (tool.name !== "mcp-re-backtest") return args;
|
|
23681
|
+
if (tool.name !== "mcp-re-backtest" || args.__configBaseline || args.__storedRunParams) return args;
|
|
23528
23682
|
const runId = typeof args.runId === "string" ? args.runId.trim() : "";
|
|
23529
23683
|
const prior = runId ? contexts.get(runId)?.runParams : void 0;
|
|
23530
23684
|
if (!prior) return args;
|
|
23531
23685
|
const runParams = isRecord2(args.runParams) ? args.runParams : {};
|
|
23532
|
-
return { ...args, runParams:
|
|
23686
|
+
return { ...args, runParams: applyBodyDefaults(prior, runParams) };
|
|
23533
23687
|
}
|
|
23534
23688
|
function applyBacktestDateDefaults(tool, args) {
|
|
23535
23689
|
if (tool.name !== "mcp-create-and-run-backtest") return args;
|
|
@@ -23645,18 +23799,18 @@ function backtestWindowPreflightError(tool, reason, message, details) {
|
|
|
23645
23799
|
}, true);
|
|
23646
23800
|
}
|
|
23647
23801
|
function isExistingAbsoluteDirectory(value) {
|
|
23648
|
-
if (!value || !
|
|
23802
|
+
if (!value || !path12.isAbsolute(value)) return false;
|
|
23649
23803
|
try {
|
|
23650
|
-
return
|
|
23804
|
+
return fs12.statSync(value).isDirectory();
|
|
23651
23805
|
} catch {
|
|
23652
23806
|
return false;
|
|
23653
23807
|
}
|
|
23654
23808
|
}
|
|
23655
23809
|
function readBacktestIdFromCodePath(codePath) {
|
|
23656
23810
|
try {
|
|
23657
|
-
const tradesettingPath =
|
|
23658
|
-
if (!
|
|
23659
|
-
const parsed = JSON.parse(
|
|
23811
|
+
const tradesettingPath = path12.join(codePath, ".vscode", "tradesetting.json");
|
|
23812
|
+
if (!fs12.existsSync(tradesettingPath)) return void 0;
|
|
23813
|
+
const parsed = JSON.parse(fs12.readFileSync(tradesettingPath, "utf-8"));
|
|
23660
23814
|
if (!isRecord2(parsed)) return void 0;
|
|
23661
23815
|
const value = parsed.backtest_id ?? parsed.backtestId;
|
|
23662
23816
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -23680,7 +23834,7 @@ function capturePendingBacktestAttempt(tool, args, contexts) {
|
|
|
23680
23834
|
if (tool.name !== "mcp-create-and-run-backtest" && tool.name !== "mcp-re-backtest") return;
|
|
23681
23835
|
const runId = typeof args.runId === "string" ? args.runId.trim() : "";
|
|
23682
23836
|
const suppliedCodePath = typeof args.codePath === "string" ? args.codePath.trim() : "";
|
|
23683
|
-
const codePath = (runId ? contexts.get(runId)?.codePath : void 0) || suppliedCodePath;
|
|
23837
|
+
const codePath = args.__configBaseline ? suppliedCodePath : (runId ? contexts.get(runId)?.codePath : void 0) || suppliedCodePath;
|
|
23684
23838
|
const resultFile = codePath ? readRunResultFile(codePath) : null;
|
|
23685
23839
|
pendingBacktestAttempts.set(args, {
|
|
23686
23840
|
...resultFile ? { resultBaseline: resultFile.identity } : {},
|
|
@@ -24352,9 +24506,9 @@ var FACTOR_FAILURE_SIGNATURES = [
|
|
|
24352
24506
|
function factorFailureMessage(data) {
|
|
24353
24507
|
if (typeof data.errorMessage === "string" && data.errorMessage) return data.errorMessage;
|
|
24354
24508
|
for (const key of ["calculateRecord", "detectRecord"]) {
|
|
24355
|
-
const
|
|
24356
|
-
if (isRecord2(
|
|
24357
|
-
return
|
|
24509
|
+
const record3 = data[key];
|
|
24510
|
+
if (isRecord2(record3) && typeof record3.errorMessage === "string" && record3.errorMessage) {
|
|
24511
|
+
return record3.errorMessage;
|
|
24358
24512
|
}
|
|
24359
24513
|
}
|
|
24360
24514
|
return "";
|
|
@@ -24798,18 +24952,18 @@ function applyBacktestResultGuards(tool, args, result, states, contexts, activeR
|
|
|
24798
24952
|
}
|
|
24799
24953
|
function readRunResultFile(codePath) {
|
|
24800
24954
|
try {
|
|
24801
|
-
const resultPath =
|
|
24802
|
-
if (!
|
|
24803
|
-
const before =
|
|
24804
|
-
const raw =
|
|
24805
|
-
const after =
|
|
24955
|
+
const resultPath = path12.join(codePath, "log", "result.json");
|
|
24956
|
+
if (!fs12.existsSync(resultPath)) return null;
|
|
24957
|
+
const before = fs12.statSync(resultPath);
|
|
24958
|
+
const raw = fs12.readFileSync(resultPath);
|
|
24959
|
+
const after = fs12.statSync(resultPath);
|
|
24806
24960
|
if (before.mtimeMs !== after.mtimeMs || before.size !== after.size) return null;
|
|
24807
24961
|
const parsed = JSON.parse(raw.toString("utf-8"));
|
|
24808
24962
|
if (!isRecord2(parsed)) return null;
|
|
24809
24963
|
return {
|
|
24810
24964
|
data: parsed,
|
|
24811
24965
|
identity: {
|
|
24812
|
-
sha256: (0,
|
|
24966
|
+
sha256: (0, import_node_crypto3.createHash)("sha256").update(raw).digest("hex"),
|
|
24813
24967
|
mtimeMs: after.mtimeMs,
|
|
24814
24968
|
size: after.size
|
|
24815
24969
|
}
|
|
@@ -24918,7 +25072,7 @@ function captureBacktestRunContext(tool, args, result, contexts, activeRunIds) {
|
|
|
24918
25072
|
const strategyId = typeof args.strategyId === "string" ? args.strategyId : "";
|
|
24919
25073
|
const start = typeof runParams.start === "string" ? runParams.start : "";
|
|
24920
25074
|
const end = typeof runParams.end === "string" ? runParams.end : "";
|
|
24921
|
-
if (!strategyId || !start || !end) return;
|
|
25075
|
+
if (!strategyId || (!start || !end) && !args.__storedRunParams) return;
|
|
24922
25076
|
try {
|
|
24923
25077
|
const parsed = JSON.parse(result.content[0].text);
|
|
24924
25078
|
if (!isRecord2(parsed) || !isRecord2(parsed.Data)) return;
|
|
@@ -24926,7 +25080,7 @@ function captureBacktestRunContext(tool, args, result, contexts, activeRunIds) {
|
|
|
24926
25080
|
const runId = echoedRunId || (isRerun && typeof args.runId === "string" ? args.runId.trim() : "");
|
|
24927
25081
|
const prior = runId ? contexts.get(runId) : void 0;
|
|
24928
25082
|
const suppliedCodePath = typeof args.codePath === "string" ? args.codePath.trim() : "";
|
|
24929
|
-
const codePath = typeof parsed.Data.codePath === "string" && parsed.Data.codePath.trim() ? parsed.Data.codePath.trim() : prior?.codePath || suppliedCodePath;
|
|
25083
|
+
const codePath = typeof parsed.Data.codePath === "string" && parsed.Data.codePath.trim() ? parsed.Data.codePath.trim() : args.__configBaseline ? suppliedCodePath : prior?.codePath || suppliedCodePath;
|
|
24930
25084
|
if (runId) {
|
|
24931
25085
|
const marketIds = Array.isArray(runParams.marketIds) ? runParams.marketIds.filter((id) => typeof id === "string") : prior?.marketIds;
|
|
24932
25086
|
const sourceSha256 = hashBacktestSource(codePath) ?? prior?.sourceSha256;
|
|
@@ -24955,6 +25109,11 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
|
|
|
24955
25109
|
const resolvedCapital = resolveBacktestCapital(runParams);
|
|
24956
25110
|
const resolvedBenchmark = resolveBacktestBenchmark(runParams);
|
|
24957
25111
|
const echo = {};
|
|
25112
|
+
echo.configurationEvidence = {
|
|
25113
|
+
source: args.__storedRunParams ? "zltaf_stored_parameters" : "mcp_submission",
|
|
25114
|
+
persistenceVerified: false,
|
|
25115
|
+
...args.__configBaseline ? { baseline: args.__configBaseline } : {}
|
|
25116
|
+
};
|
|
24958
25117
|
if (resolvedStart) echo.resolvedStart = resolvedStart;
|
|
24959
25118
|
if (resolvedEnd) echo.resolvedEnd = resolvedEnd;
|
|
24960
25119
|
if (resolvedCapital !== null) echo.resolvedCapital = resolvedCapital;
|
|
@@ -24976,7 +25135,7 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
|
|
|
24976
25135
|
echo.codePath = context.codePath;
|
|
24977
25136
|
echo.runDir = context.codePath;
|
|
24978
25137
|
}
|
|
24979
|
-
if (context?.runParams) echo.runParams = { ...context.runParams };
|
|
25138
|
+
if (context?.runParams && !args.__storedRunParams) echo.runParams = { ...context.runParams };
|
|
24980
25139
|
if (context?.attemptStartedAtMs) {
|
|
24981
25140
|
echo.attemptFence = {
|
|
24982
25141
|
attemptStartedAtMs: context.attemptStartedAtMs,
|
|
@@ -24989,7 +25148,7 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
|
|
|
24989
25148
|
backtestId: runId,
|
|
24990
25149
|
...context?.codePath ? { runDir: context.codePath } : {},
|
|
24991
25150
|
...context?.strategyId ? { strategyId: context.strategyId } : {},
|
|
24992
|
-
...context?.runParams ? { effectiveRunParams: { ...context.runParams } } : {},
|
|
25151
|
+
...context?.runParams && !args.__storedRunParams ? { effectiveRunParams: { ...context.runParams } } : {},
|
|
24993
25152
|
...context?.sourceSha256 ? { sourceSha256: context.sourceSha256 } : {}
|
|
24994
25153
|
};
|
|
24995
25154
|
}
|
|
@@ -25011,9 +25170,9 @@ function echoResolvedBacktestConfig(tool, args, result, contexts) {
|
|
|
25011
25170
|
function hashBacktestSource(codePath) {
|
|
25012
25171
|
if (!codePath) return void 0;
|
|
25013
25172
|
try {
|
|
25014
|
-
const sourcePath =
|
|
25015
|
-
if (!
|
|
25016
|
-
return (0,
|
|
25173
|
+
const sourcePath = path12.join(codePath, "main.py");
|
|
25174
|
+
if (!fs12.statSync(sourcePath).isFile()) return void 0;
|
|
25175
|
+
return (0, import_node_crypto3.createHash)("sha256").update(fs12.readFileSync(sourcePath)).digest("hex");
|
|
25017
25176
|
} catch {
|
|
25018
25177
|
return void 0;
|
|
25019
25178
|
}
|
|
@@ -25059,7 +25218,7 @@ function resolveBacktestBenchmark(runParams) {
|
|
|
25059
25218
|
var STRATEGY_DOCS_TOOLS = /* @__PURE__ */ new Set(["mcp-create-strategy", "mcp-create-strategy-with-template"]);
|
|
25060
25219
|
function resolveStrategyDocsPath(clientRootDir) {
|
|
25061
25220
|
if (!clientRootDir) return void 0;
|
|
25062
|
-
const docsPath =
|
|
25221
|
+
const docsPath = path12.join(
|
|
25063
25222
|
clientRootDir,
|
|
25064
25223
|
"python",
|
|
25065
25224
|
"Lib",
|
|
@@ -25069,7 +25228,7 @@ function resolveStrategyDocsPath(clientRootDir) {
|
|
|
25069
25228
|
"docs"
|
|
25070
25229
|
);
|
|
25071
25230
|
try {
|
|
25072
|
-
if (!
|
|
25231
|
+
if (!fs12.existsSync(docsPath)) return void 0;
|
|
25073
25232
|
} catch {
|
|
25074
25233
|
return void 0;
|
|
25075
25234
|
}
|
|
@@ -25086,7 +25245,7 @@ function injectDebugRunId(tool, result) {
|
|
|
25086
25245
|
const localPath = typeof parsed.Data.localPath === "string" ? parsed.Data.localPath.trim() : "";
|
|
25087
25246
|
if (!localPath) return result;
|
|
25088
25247
|
const settings = JSON.parse(
|
|
25089
|
-
|
|
25248
|
+
fs12.readFileSync(path12.join(localPath, ".vscode", "tradesetting.json"), "utf8")
|
|
25090
25249
|
);
|
|
25091
25250
|
const debugRunId = isRecord2(settings) && typeof settings.backtest_id === "string" ? settings.backtest_id.trim() : "";
|
|
25092
25251
|
if (!debugRunId) return result;
|
|
@@ -25582,12 +25741,12 @@ function preflightCreatedBacktestSource(toolName, body) {
|
|
|
25582
25741
|
if (toolName !== "mcp-create-and-run-backtest") return null;
|
|
25583
25742
|
const runId = typeof body.runId === "string" ? body.runId.trim() : "";
|
|
25584
25743
|
const codePath = typeof body.codePath === "string" ? body.codePath.trim() : "";
|
|
25585
|
-
if (!codePath || !
|
|
25586
|
-
const sourcePath =
|
|
25587
|
-
if (!
|
|
25744
|
+
if (!codePath || !fs12.existsSync(codePath)) return null;
|
|
25745
|
+
const sourcePath = path12.join(codePath, "main.py");
|
|
25746
|
+
if (!fs12.existsSync(sourcePath)) return null;
|
|
25588
25747
|
let source;
|
|
25589
25748
|
try {
|
|
25590
|
-
source =
|
|
25749
|
+
source = fs12.readFileSync(sourcePath, "utf8");
|
|
25591
25750
|
} catch (error2) {
|
|
25592
25751
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
25593
25752
|
return jsonToolResult(10061, "\u56DE\u6D4B\u4EE3\u7801\u5FEB\u7167\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u672A\u542F\u52A8\u7B56\u7565\u5F15\u64CE\u3002", {
|
|
@@ -25607,7 +25766,7 @@ function preflightCreatedBacktestSource(toolName, body) {
|
|
|
25607
25766
|
codePath,
|
|
25608
25767
|
sourcePath,
|
|
25609
25768
|
sourcePreflight: "blocked",
|
|
25610
|
-
sourceSha256: (0,
|
|
25769
|
+
sourceSha256: (0, import_node_crypto3.createHash)("sha256").update(source).digest("hex"),
|
|
25611
25770
|
violations,
|
|
25612
25771
|
userAction: "\u628A current_data.get(security) \u6539\u4E3A current_data[security]\uFF0C\u5E76\u7528 KeyError \u5904\u7406\u7F3A\u5931\u8BC1\u5238\uFF1B\u7136\u540E\u91CD\u65B0\u521B\u5EFA\u5E76\u8FD0\u884C\u56DE\u6D4B\u3002"
|
|
25613
25772
|
}, true);
|
|
@@ -25827,7 +25986,7 @@ function normalizeDataRoot(raw, clientRootDir) {
|
|
|
25827
25986
|
}
|
|
25828
25987
|
function readJsonFile(filePath) {
|
|
25829
25988
|
try {
|
|
25830
|
-
const parsed = JSON.parse(
|
|
25989
|
+
const parsed = JSON.parse(fs12.readFileSync(filePath, "utf-8"));
|
|
25831
25990
|
return isRecord2(parsed) ? parsed : void 0;
|
|
25832
25991
|
} catch {
|
|
25833
25992
|
return void 0;
|
|
@@ -25841,8 +26000,8 @@ function resolveDataRoots(clientRootDir) {
|
|
|
25841
26000
|
const cached2 = Date.now() - readAt < DATA_ROOTS_TTL_MS ? dataRootsCache.get(clientRootDir) : void 0;
|
|
25842
26001
|
if (cached2) return cached2;
|
|
25843
26002
|
const root = clientRootDir.replace(/[\\/]+$/, "");
|
|
25844
|
-
const dcSdk = readJsonFile(
|
|
25845
|
-
const dcm = readJsonFile(
|
|
26003
|
+
const dcSdk = readJsonFile(path12.join(root, ...DC_SDK_CONFIG_SEGMENTS));
|
|
26004
|
+
const dcm = readJsonFile(path12.join(root, ...DCM_CONFIG_SEGMENTS));
|
|
25846
26005
|
const engineRoot = normalizeDataRoot(isRecord2(dcSdk?.mdf) ? dcSdk.mdf.path : void 0, root);
|
|
25847
26006
|
const downloadRoot = normalizeDataRoot(dcm?.download_home, root);
|
|
25848
26007
|
const resolved = Boolean(engineRoot && downloadRoot);
|
|
@@ -25872,9 +26031,9 @@ function hqSeriesFromResults(resultItems) {
|
|
|
25872
26031
|
function engineHasAnyHqSeries(engineRoot, series) {
|
|
25873
26032
|
if (!engineRoot || series.length === 0) return void 0;
|
|
25874
26033
|
for (const { exchangeId, dataType } of series) {
|
|
25875
|
-
const dir =
|
|
26034
|
+
const dir = path12.join(engineRoot, "hqdata", "his", exchangeId, dataType);
|
|
25876
26035
|
try {
|
|
25877
|
-
if (
|
|
26036
|
+
if (fs12.existsSync(dir) && fs12.readdirSync(dir).length > 0) return true;
|
|
25878
26037
|
} catch {
|
|
25879
26038
|
return void 0;
|
|
25880
26039
|
}
|
|
@@ -26869,8 +27028,7 @@ async function startMcpServer() {
|
|
|
26869
27028
|
isError: true
|
|
26870
27029
|
};
|
|
26871
27030
|
}
|
|
26872
|
-
const
|
|
26873
|
-
const preparedArgs = prepareToolArgs(tool, defaultedToolArgs, backtestRunContexts);
|
|
27031
|
+
const preparedArgs = prepareToolCallArgs(tool, args ?? {}, backtestRunContexts);
|
|
26874
27032
|
if ("content" in preparedArgs) return preparedArgs;
|
|
26875
27033
|
const toolArgs = preparedArgs;
|
|
26876
27034
|
if (tool.localHandler === "currentUser") {
|
|
@@ -27444,13 +27602,13 @@ function syncCredentialsFromEnvAtStartup() {
|
|
|
27444
27602
|
function signalCliKeepaliveReady() {
|
|
27445
27603
|
const raw = process.env.ZLT_MCP_KEEPALIVE_READY_FILE?.trim();
|
|
27446
27604
|
if (process.env.ZLT_MCP_CLI !== "1" || !raw) return;
|
|
27447
|
-
const readyFile =
|
|
27448
|
-
if (
|
|
27605
|
+
const readyFile = path14.resolve(raw);
|
|
27606
|
+
if (path14.dirname(readyFile) !== path14.resolve(os5.tmpdir()) || !path14.basename(readyFile).startsWith("zlt-mcp-keepalive-")) {
|
|
27449
27607
|
return;
|
|
27450
27608
|
}
|
|
27451
27609
|
try {
|
|
27452
|
-
const fd =
|
|
27453
|
-
|
|
27610
|
+
const fd = fs13.openSync(readyFile, "wx", 384);
|
|
27611
|
+
fs13.closeSync(fd);
|
|
27454
27612
|
} catch (error2) {
|
|
27455
27613
|
if (error2.code !== "EEXIST") {
|
|
27456
27614
|
process.stderr.write(`[zlt-mcp-cli] keepalive readiness signal failed: ${error2 instanceof Error ? error2.message : String(error2)}
|
|
@@ -27556,6 +27714,8 @@ if (process.argv.length <= 2) {
|
|
|
27556
27714
|
Input: omitted arguments mean {}; use --args-json for small objects and --args-file
|
|
27557
27715
|
for nested configuration or shell-sensitive text. Follow the selected tool schema
|
|
27558
27716
|
from list --tool <name> --json. Windows paths must be native paths (C:/...), not /c/....
|
|
27717
|
+
Tool schema properties are JSON keys, NOT CLI flags: use --args-json '{"params": [...]}'
|
|
27718
|
+
for a tool's params property, not --params. Pass the complete argument object.
|
|
27559
27719
|
Output: by default stdout contains the complete MCP JSON envelope plus cliProvenance.
|
|
27560
27720
|
JSON business responses are inside content[].text (or structuredContent when present).
|
|
27561
27721
|
Use --output-json for large results or downstream evidence: it saves the complete
|
|
@@ -27566,45 +27726,69 @@ parsing output. Do not discard stderr, merge it into JSON, or pipe calls through
|
|
|
27566
27726
|
head/tail/parsers that can hide the CLI exit code. --no-progress only disables progress.
|
|
27567
27727
|
If saving fails after execution, the complete response is on stdout; preserve it
|
|
27568
27728
|
and inspect the returned state before retrying any operation that may have run.
|
|
27729
|
+
Thrown call failures emit Error: followed by JSON on stderr with stage, message,
|
|
27730
|
+
toolExecution and retry. not_started means the CLI did not call the tool; correct
|
|
27731
|
+
the input/path before retrying. unknown means execution may have occurred (including
|
|
27732
|
+
transport or keepalive failure); inspect state first. response_received means a
|
|
27733
|
+
response was received, not that the business succeeded; inspect that result first.
|
|
27569
27734
|
Credentials belong in the configured local credential store, never in arguments.
|
|
27570
27735
|
`).action(async (tool, options) => {
|
|
27571
27736
|
let outputFd;
|
|
27737
|
+
let stage = "arguments";
|
|
27738
|
+
let toolExecution = "not_started";
|
|
27572
27739
|
try {
|
|
27573
27740
|
const args = parseMcpArgs(options.argsJson, options.argsFile);
|
|
27574
27741
|
const timeoutMs = parseTimeoutOption(options.timeoutMs, "--timeout-ms");
|
|
27575
27742
|
const maxTotalTimeoutMs = parseTimeoutOption(options.maxTotalTimeoutMs, "--max-total-timeout-ms");
|
|
27576
|
-
const resultFile = options.outputJson === void 0 ? void 0 :
|
|
27577
|
-
|
|
27743
|
+
const resultFile = options.outputJson === void 0 ? void 0 : path15.resolve(options.outputJson);
|
|
27744
|
+
stage = "output_prepare";
|
|
27745
|
+
if (resultFile !== void 0) outputFd = fs14.openSync(resultFile, "wx");
|
|
27746
|
+
stage = "tool_call";
|
|
27747
|
+
toolExecution = "unknown";
|
|
27578
27748
|
const result = await callMcpTool(tool, args, {
|
|
27579
27749
|
timeoutMs,
|
|
27580
27750
|
maxTotalTimeoutMs,
|
|
27581
27751
|
showProgress: options.progress !== false
|
|
27582
27752
|
});
|
|
27753
|
+
toolExecution = "response_received";
|
|
27754
|
+
stage = "output_serialize";
|
|
27583
27755
|
const complete = withCliProvenance(result);
|
|
27584
27756
|
const serialized = JSON.stringify(complete) + "\n";
|
|
27585
27757
|
if (outputFd !== void 0 && resultFile !== void 0) {
|
|
27758
|
+
stage = "output_write";
|
|
27586
27759
|
try {
|
|
27587
|
-
|
|
27588
|
-
|
|
27760
|
+
fs14.writeFileSync(outputFd, serialized, "utf-8");
|
|
27761
|
+
fs14.closeSync(outputFd);
|
|
27589
27762
|
outputFd = void 0;
|
|
27590
27763
|
} catch (error2) {
|
|
27591
27764
|
process.stdout.write(serialized);
|
|
27592
27765
|
throw new Error(`Tool returned a result, but saving ${resultFile} failed; complete result is on stdout. Do not repeat the tool automatically. ${String(error2)}`);
|
|
27593
27766
|
}
|
|
27767
|
+
stage = "output_emit";
|
|
27594
27768
|
const receipt = compactCliReceipt(tool, complete, resultFile);
|
|
27595
27769
|
process.stdout.write(JSON.stringify(receipt) + "\n");
|
|
27596
27770
|
if (!receipt.ok) process.exitCode = 1;
|
|
27597
27771
|
} else {
|
|
27772
|
+
stage = "output_emit";
|
|
27598
27773
|
process.stdout.write(serialized);
|
|
27599
27774
|
}
|
|
27600
27775
|
if (result.isError === true) process.exitCode = 1;
|
|
27601
27776
|
} catch (error2) {
|
|
27602
27777
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
27603
|
-
|
|
27778
|
+
const code = error2?.code;
|
|
27779
|
+
const retry = toolExecution === "not_started" ? "fix_input_then_retry" : toolExecution === "response_received" ? "inspect_result_before_retry" : "inspect_state_before_retry";
|
|
27780
|
+
process.stderr.write(`Error: ${JSON.stringify({
|
|
27781
|
+
tool,
|
|
27782
|
+
stage,
|
|
27783
|
+
toolExecution,
|
|
27784
|
+
retry,
|
|
27785
|
+
...typeof code === "string" ? { code } : {},
|
|
27786
|
+
message
|
|
27787
|
+
})}
|
|
27604
27788
|
`);
|
|
27605
27789
|
process.exitCode = 1;
|
|
27606
27790
|
} finally {
|
|
27607
|
-
if (outputFd !== void 0)
|
|
27791
|
+
if (outputFd !== void 0) fs14.closeSync(outputFd);
|
|
27608
27792
|
}
|
|
27609
27793
|
});
|
|
27610
27794
|
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) => {
|
|
@@ -27613,7 +27797,12 @@ Credentials belong in the configured local credential store, never in arguments.
|
|
|
27613
27797
|
if (options.tool !== void 0) {
|
|
27614
27798
|
const tools2 = Array.isArray(result.tools) ? result.tools.filter((tool) => tool.name === options.tool) : [];
|
|
27615
27799
|
if (tools2.length === 0) throw new Error(`Unknown tool: ${options.tool}. Use list to discover available names.`);
|
|
27616
|
-
result = { ...result, tools: tools2
|
|
27800
|
+
result = { ...result, tools: tools2, cliUsage: {
|
|
27801
|
+
command: `call ${options.tool}`,
|
|
27802
|
+
argumentsOption: "--args-json",
|
|
27803
|
+
argumentsAreCliFlags: false,
|
|
27804
|
+
instruction: "Put tool schema properties inside one JSON object passed to --args-json (or use --args-file). Do not turn properties into --flags."
|
|
27805
|
+
} };
|
|
27617
27806
|
}
|
|
27618
27807
|
if (options.json) {
|
|
27619
27808
|
process.stdout.write(JSON.stringify(withCliProvenance(result)) + "\n");
|
|
@@ -27684,17 +27873,17 @@ function resolveCliVersion() {
|
|
|
27684
27873
|
return resolveCliPackageProvenance().packageVersion;
|
|
27685
27874
|
}
|
|
27686
27875
|
function resolveCliPackageProvenance() {
|
|
27687
|
-
let current =
|
|
27876
|
+
let current = path15.dirname(path15.resolve(process.argv[1] || process.cwd()));
|
|
27688
27877
|
for (let depth = 0; depth < 6; depth += 1) {
|
|
27689
|
-
const manifestPath =
|
|
27878
|
+
const manifestPath = path15.join(current, "package.json");
|
|
27690
27879
|
try {
|
|
27691
|
-
const manifest = JSON.parse(
|
|
27880
|
+
const manifest = JSON.parse(fs14.readFileSync(manifestPath, "utf-8"));
|
|
27692
27881
|
if ((manifest.name === "@zltquant/zlt-mcp" || manifest.name === "zlt-mcp-proxy") && typeof manifest.version === "string") {
|
|
27693
27882
|
return { packageName: manifest.name, packageVersion: manifest.version };
|
|
27694
27883
|
}
|
|
27695
27884
|
} catch {
|
|
27696
27885
|
}
|
|
27697
|
-
const parent =
|
|
27886
|
+
const parent = path15.dirname(current);
|
|
27698
27887
|
if (parent === current) break;
|
|
27699
27888
|
current = parent;
|
|
27700
27889
|
}
|