@tradejs/node 3.1.29-beta.282 → 3.1.29-beta.283

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.
@@ -179,4 +179,57 @@ declare const verifyRuntimeFeedbackReplaySource: ({ bundleDir, runtimeEvidenceBu
179
179
  runtimeEvidence: VerifiedRuntimeEvidenceBundle;
180
180
  }>;
181
181
 
182
- export { RUNTIME_EVIDENCE_COMPLETE_FILE, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_FEEDBACK_COMPLETE_FILE, RUNTIME_FEEDBACK_LOG_FILE, RUNTIME_FEEDBACK_MANIFEST_FILE, RUNTIME_FEEDBACK_REPLAY_FILE, type RuntimeEvidenceArtifactManifest, type RuntimeEvidenceDeploymentSnapshot, type RuntimeEvidenceProducer, type RuntimeEvidenceStrategySnapshot, type RuntimeFeedbackReplayManifest, type VerifiedRuntimeEvidenceBundle, type VerifiedRuntimeFeedbackReplayBundle, activeRuntimeEvidenceStrategies, assertCurrentRuntimeEvidenceArtifact, discoverRuntimeEvidenceBundles, discoverRuntimeFeedbackReplayBundles, parseRuntimeEvidenceDeploymentSnapshot, parseRuntimeEvidenceProducer, publishRuntimeEvidenceBundle, resolveRuntimeEvidenceDeploymentSnapshot, resolveRuntimeEvidenceProducer, resolveRuntimeEvidenceTickerUniverse, runtimeDeploymentFromEvidence, runtimeLineageMatchesStrategySnapshot, sealRuntimeFeedbackReplayBundle, verifyRuntimeEvidenceBundle, verifyRuntimeFeedbackReplayBundle, verifyRuntimeFeedbackReplaySource };
182
+ /** Version of the complete feedback read contract, independent of package versions. */
183
+ declare const MCP_FEEDBACK_CONTRACT: {
184
+ readonly version: 1;
185
+ readonly hostProtocolVersion: 2;
186
+ readonly replayQueue: {
187
+ readonly waitingStates: readonly ["waiting_resources", "waiting_executor"];
188
+ readonly automaticFailedRetries: false;
189
+ };
190
+ readonly artifactEncoding: "base64";
191
+ readonly maximumChunkBytes: 48000;
192
+ readonly artifactFiles: readonly ["payload", "manifest.json", ".complete", "replay.log"];
193
+ readonly requiredTools: readonly ["tradejs_info", "diagnostics_list_reports", "diagnostics_get_report", "artifact_get", "job_get", "job_get_logs"];
194
+ };
195
+ type McpToolDescription = {
196
+ name: string;
197
+ inputSchema: {
198
+ properties?: Record<string, unknown>;
199
+ };
200
+ };
201
+ /** Check the actual client's tools/list, not only what the server advertises. */
202
+ declare const assertMcpFeedbackContract: (version: unknown, tools: McpToolDescription[]) => void;
203
+
204
+ type McpArtifactFile = 'payload' | 'manifest.json' | '.complete' | 'replay.log';
205
+ type McpBundleDescriptor = {
206
+ id: string;
207
+ kind: 'runtime-evidence' | 'runtime-feedback-replay';
208
+ files: {
209
+ file: McpArtifactFile;
210
+ bytes: number;
211
+ sha256: string;
212
+ available: boolean;
213
+ }[];
214
+ };
215
+ declare class McpReadTransportError extends Error {
216
+ readonly retryAfterMs?: number | undefined;
217
+ constructor(message: string, retryAfterMs?: number | undefined);
218
+ }
219
+ type ChunkRequest = {
220
+ artifactId: string;
221
+ file: McpArtifactFile;
222
+ offset: number;
223
+ length: number;
224
+ };
225
+ /** The caller owns the authenticated MCP connection. This function only reads artifacts. */
226
+ declare const downloadMcpBundle: ({ descriptor, root, contractVersion, tools, readChunk, wait, }: {
227
+ descriptor: McpBundleDescriptor;
228
+ root: string;
229
+ contractVersion: unknown;
230
+ tools: McpToolDescription[];
231
+ readChunk: (request: ChunkRequest) => Promise<unknown>;
232
+ wait?: (ms: number) => Promise<unknown>;
233
+ }) => Promise<VerifiedRuntimeEvidenceBundle | VerifiedRuntimeFeedbackReplayBundle>;
234
+
235
+ export { MCP_FEEDBACK_CONTRACT, type McpArtifactFile, type McpBundleDescriptor, McpReadTransportError, type McpToolDescription, RUNTIME_EVIDENCE_COMPLETE_FILE, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_FEEDBACK_COMPLETE_FILE, RUNTIME_FEEDBACK_LOG_FILE, RUNTIME_FEEDBACK_MANIFEST_FILE, RUNTIME_FEEDBACK_REPLAY_FILE, type RuntimeEvidenceArtifactManifest, type RuntimeEvidenceDeploymentSnapshot, type RuntimeEvidenceProducer, type RuntimeEvidenceStrategySnapshot, type RuntimeFeedbackReplayManifest, type VerifiedRuntimeEvidenceBundle, type VerifiedRuntimeFeedbackReplayBundle, activeRuntimeEvidenceStrategies, assertCurrentRuntimeEvidenceArtifact, assertMcpFeedbackContract, discoverRuntimeEvidenceBundles, discoverRuntimeFeedbackReplayBundles, downloadMcpBundle, parseRuntimeEvidenceDeploymentSnapshot, parseRuntimeEvidenceProducer, publishRuntimeEvidenceBundle, resolveRuntimeEvidenceDeploymentSnapshot, resolveRuntimeEvidenceProducer, resolveRuntimeEvidenceTickerUniverse, runtimeDeploymentFromEvidence, runtimeLineageMatchesStrategySnapshot, sealRuntimeFeedbackReplayBundle, verifyRuntimeEvidenceBundle, verifyRuntimeFeedbackReplayBundle, verifyRuntimeFeedbackReplaySource };
@@ -179,4 +179,57 @@ declare const verifyRuntimeFeedbackReplaySource: ({ bundleDir, runtimeEvidenceBu
179
179
  runtimeEvidence: VerifiedRuntimeEvidenceBundle;
180
180
  }>;
181
181
 
182
- export { RUNTIME_EVIDENCE_COMPLETE_FILE, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_FEEDBACK_COMPLETE_FILE, RUNTIME_FEEDBACK_LOG_FILE, RUNTIME_FEEDBACK_MANIFEST_FILE, RUNTIME_FEEDBACK_REPLAY_FILE, type RuntimeEvidenceArtifactManifest, type RuntimeEvidenceDeploymentSnapshot, type RuntimeEvidenceProducer, type RuntimeEvidenceStrategySnapshot, type RuntimeFeedbackReplayManifest, type VerifiedRuntimeEvidenceBundle, type VerifiedRuntimeFeedbackReplayBundle, activeRuntimeEvidenceStrategies, assertCurrentRuntimeEvidenceArtifact, discoverRuntimeEvidenceBundles, discoverRuntimeFeedbackReplayBundles, parseRuntimeEvidenceDeploymentSnapshot, parseRuntimeEvidenceProducer, publishRuntimeEvidenceBundle, resolveRuntimeEvidenceDeploymentSnapshot, resolveRuntimeEvidenceProducer, resolveRuntimeEvidenceTickerUniverse, runtimeDeploymentFromEvidence, runtimeLineageMatchesStrategySnapshot, sealRuntimeFeedbackReplayBundle, verifyRuntimeEvidenceBundle, verifyRuntimeFeedbackReplayBundle, verifyRuntimeFeedbackReplaySource };
182
+ /** Version of the complete feedback read contract, independent of package versions. */
183
+ declare const MCP_FEEDBACK_CONTRACT: {
184
+ readonly version: 1;
185
+ readonly hostProtocolVersion: 2;
186
+ readonly replayQueue: {
187
+ readonly waitingStates: readonly ["waiting_resources", "waiting_executor"];
188
+ readonly automaticFailedRetries: false;
189
+ };
190
+ readonly artifactEncoding: "base64";
191
+ readonly maximumChunkBytes: 48000;
192
+ readonly artifactFiles: readonly ["payload", "manifest.json", ".complete", "replay.log"];
193
+ readonly requiredTools: readonly ["tradejs_info", "diagnostics_list_reports", "diagnostics_get_report", "artifact_get", "job_get", "job_get_logs"];
194
+ };
195
+ type McpToolDescription = {
196
+ name: string;
197
+ inputSchema: {
198
+ properties?: Record<string, unknown>;
199
+ };
200
+ };
201
+ /** Check the actual client's tools/list, not only what the server advertises. */
202
+ declare const assertMcpFeedbackContract: (version: unknown, tools: McpToolDescription[]) => void;
203
+
204
+ type McpArtifactFile = 'payload' | 'manifest.json' | '.complete' | 'replay.log';
205
+ type McpBundleDescriptor = {
206
+ id: string;
207
+ kind: 'runtime-evidence' | 'runtime-feedback-replay';
208
+ files: {
209
+ file: McpArtifactFile;
210
+ bytes: number;
211
+ sha256: string;
212
+ available: boolean;
213
+ }[];
214
+ };
215
+ declare class McpReadTransportError extends Error {
216
+ readonly retryAfterMs?: number | undefined;
217
+ constructor(message: string, retryAfterMs?: number | undefined);
218
+ }
219
+ type ChunkRequest = {
220
+ artifactId: string;
221
+ file: McpArtifactFile;
222
+ offset: number;
223
+ length: number;
224
+ };
225
+ /** The caller owns the authenticated MCP connection. This function only reads artifacts. */
226
+ declare const downloadMcpBundle: ({ descriptor, root, contractVersion, tools, readChunk, wait, }: {
227
+ descriptor: McpBundleDescriptor;
228
+ root: string;
229
+ contractVersion: unknown;
230
+ tools: McpToolDescription[];
231
+ readChunk: (request: ChunkRequest) => Promise<unknown>;
232
+ wait?: (ms: number) => Promise<unknown>;
233
+ }) => Promise<VerifiedRuntimeEvidenceBundle | VerifiedRuntimeFeedbackReplayBundle>;
234
+
235
+ export { MCP_FEEDBACK_CONTRACT, type McpArtifactFile, type McpBundleDescriptor, McpReadTransportError, type McpToolDescription, RUNTIME_EVIDENCE_COMPLETE_FILE, RUNTIME_EVIDENCE_MANIFEST_FILE, RUNTIME_EVIDENCE_PAYLOAD_FILE, RUNTIME_FEEDBACK_COMPLETE_FILE, RUNTIME_FEEDBACK_LOG_FILE, RUNTIME_FEEDBACK_MANIFEST_FILE, RUNTIME_FEEDBACK_REPLAY_FILE, type RuntimeEvidenceArtifactManifest, type RuntimeEvidenceDeploymentSnapshot, type RuntimeEvidenceProducer, type RuntimeEvidenceStrategySnapshot, type RuntimeFeedbackReplayManifest, type VerifiedRuntimeEvidenceBundle, type VerifiedRuntimeFeedbackReplayBundle, activeRuntimeEvidenceStrategies, assertCurrentRuntimeEvidenceArtifact, assertMcpFeedbackContract, discoverRuntimeEvidenceBundles, discoverRuntimeFeedbackReplayBundles, downloadMcpBundle, parseRuntimeEvidenceDeploymentSnapshot, parseRuntimeEvidenceProducer, publishRuntimeEvidenceBundle, resolveRuntimeEvidenceDeploymentSnapshot, resolveRuntimeEvidenceProducer, resolveRuntimeEvidenceTickerUniverse, runtimeDeploymentFromEvidence, runtimeLineageMatchesStrategySnapshot, sealRuntimeFeedbackReplayBundle, verifyRuntimeEvidenceBundle, verifyRuntimeFeedbackReplayBundle, verifyRuntimeFeedbackReplaySource };
@@ -43,7 +43,7 @@ var init_jevInput = __esm({
43
43
  import_data = require("@tradejs/core/data");
44
44
  import_jev = require("@tradejs/core/jev");
45
45
  object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
46
- at = (value, ...path7) => path7.reduce((current, key) => object(current)[key], value);
46
+ at = (value, ...path8) => path8.reduce((current, key) => object(current)[key], value);
47
47
  finite = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
48
48
  fact = (value) => {
49
49
  if (value == null || typeof value === "boolean") return value ?? null;
@@ -453,25 +453,25 @@ var init_jevTraining = __esm({
453
453
  "Jev training is bounded to 20000 rows; select a frozen sample first"
454
454
  );
455
455
  for (const row of rows) {
456
- const record = row?.record;
457
- if (row?.schema !== "tradejs-jev-study/v4" || !row.signalId || record?.schema !== "tradejs-jev-record/v4" || record.input?.schema !== "tradejs-jev-input/v4" || record.input.questionSet !== import_jev2.JEV_QUESTION_SET || !Number.isFinite(record.input.timestamp) || record.inputHash !== (0, import_jev3.jevHash)(record.input) || record.questionsHash !== (0, import_jev3.jevHash)(questionsForJevInput(record.input)) || record.id !== (0, import_jev3.jevHash)({
458
- inputHash: record.inputHash,
459
- questionsHash: record.questionsHash,
460
- provider: record.provider
456
+ const record2 = row?.record;
457
+ if (row?.schema !== "tradejs-jev-study/v4" || !row.signalId || record2?.schema !== "tradejs-jev-record/v4" || record2.input?.schema !== "tradejs-jev-input/v4" || record2.input.questionSet !== import_jev2.JEV_QUESTION_SET || !Number.isFinite(record2.input.timestamp) || record2.inputHash !== (0, import_jev3.jevHash)(record2.input) || record2.questionsHash !== (0, import_jev3.jevHash)(questionsForJevInput(record2.input)) || record2.id !== (0, import_jev3.jevHash)({
458
+ inputHash: record2.inputHash,
459
+ questionsHash: record2.questionsHash,
460
+ provider: record2.provider
461
461
  }))
462
462
  throw new Error("Invalid Jev study provenance");
463
- (0, import_jev3.validateJevResponse)(record.response, record.input.questions);
463
+ (0, import_jev3.validateJevResponse)(record2.response, record2.input.questions);
464
464
  for (const dimension of import_jev2.JEV_DIMENSIONS) {
465
- const expected = record.input.questions.includes(dimension) ? record.response.answers[dimension].score / (0, import_jev3.jevScoreMaximum)(dimension) : null;
466
- if (record.scores[dimension] !== expected)
465
+ const expected = record2.input.questions.includes(dimension) ? record2.response.answers[dimension].score / (0, import_jev3.jevScoreMaximum)(dimension) : null;
466
+ if (record2.scores[dimension] !== expected)
467
467
  throw new Error("Jev study scores do not match the teacher response");
468
468
  }
469
469
  if (row.profit != null && !Number.isFinite(row.profit))
470
470
  throw new Error("Invalid study outcome");
471
- const prior = unique.get(record.inputHash);
472
- if (prior && (prior.record.id !== record.id || prior.profit !== row.profit || (0, import_jev3.jevHash)(prior.record.response) !== (0, import_jev3.jevHash)(record.response)))
471
+ const prior = unique.get(record2.inputHash);
472
+ if (prior && (prior.record.id !== record2.id || prior.profit !== row.profit || (0, import_jev3.jevHash)(prior.record.response) !== (0, import_jev3.jevHash)(record2.response)))
473
473
  throw new Error("Conflicting duplicated Jev sample");
474
- unique.set(record.inputHash, row);
474
+ unique.set(record2.inputHash, row);
475
475
  }
476
476
  const ordered = [...unique.values()].sort(
477
477
  (a, b) => a.record.input.timestamp - b.record.input.timestamp || a.record.id.localeCompare(b.record.id)
@@ -777,6 +777,8 @@ var init_jevTraining = __esm({
777
777
  // src/diagnostics.ts
778
778
  var diagnostics_exports = {};
779
779
  __export(diagnostics_exports, {
780
+ MCP_FEEDBACK_CONTRACT: () => MCP_FEEDBACK_CONTRACT,
781
+ McpReadTransportError: () => McpReadTransportError,
780
782
  RUNTIME_EVIDENCE_COMPLETE_FILE: () => RUNTIME_EVIDENCE_COMPLETE_FILE,
781
783
  RUNTIME_EVIDENCE_MANIFEST_FILE: () => RUNTIME_EVIDENCE_MANIFEST_FILE,
782
784
  RUNTIME_EVIDENCE_PAYLOAD_FILE: () => RUNTIME_EVIDENCE_PAYLOAD_FILE,
@@ -786,8 +788,10 @@ __export(diagnostics_exports, {
786
788
  RUNTIME_FEEDBACK_REPLAY_FILE: () => RUNTIME_FEEDBACK_REPLAY_FILE,
787
789
  activeRuntimeEvidenceStrategies: () => activeRuntimeEvidenceStrategies,
788
790
  assertCurrentRuntimeEvidenceArtifact: () => assertCurrentRuntimeEvidenceArtifact,
791
+ assertMcpFeedbackContract: () => assertMcpFeedbackContract,
789
792
  discoverRuntimeEvidenceBundles: () => discoverRuntimeEvidenceBundles,
790
793
  discoverRuntimeFeedbackReplayBundles: () => discoverRuntimeFeedbackReplayBundles,
794
+ downloadMcpBundle: () => downloadMcpBundle,
791
795
  parseRuntimeEvidenceDeploymentSnapshot: () => parseRuntimeEvidenceDeploymentSnapshot,
792
796
  parseRuntimeEvidenceProducer: () => parseRuntimeEvidenceProducer,
793
797
  publishRuntimeEvidenceBundle: () => publishRuntimeEvidenceBundle,
@@ -982,24 +986,24 @@ var evaluateJevInput = async ({
982
986
  promise = getRecord();
983
987
  pending.set(pendingKey, promise);
984
988
  }
985
- let record;
989
+ let record2;
986
990
  try {
987
- record = await promise;
991
+ record2 = await promise;
988
992
  } finally {
989
993
  pending.delete(pendingKey);
990
994
  }
991
995
  return {
992
- record,
996
+ record: record2,
993
997
  assessment: {
994
998
  ...base,
995
999
  status: "available",
996
1000
  recordId: id,
997
- model: record.response.model,
998
- scores: record.scores,
1001
+ model: record2.response.model,
1002
+ scores: record2.scores,
999
1003
  confidence: Object.fromEntries(
1000
1004
  import_jev4.JEV_DIMENSIONS.map((key) => [
1001
1005
  key,
1002
- record.response.answers[key]?.confidence ?? null
1006
+ record2.response.answers[key]?.confidence ?? null
1003
1007
  ])
1004
1008
  )
1005
1009
  }
@@ -2922,7 +2926,7 @@ var recordRuntimeTradeOpen = async (params) => {
2922
2926
  if (!userName) {
2923
2927
  return null;
2924
2928
  }
2925
- const record = {
2929
+ const record2 = {
2926
2930
  ...params,
2927
2931
  entryCount: 1,
2928
2932
  lastEntryPrice: params.entryPrice,
@@ -2936,33 +2940,33 @@ var recordRuntimeTradeOpen = async (params) => {
2936
2940
  exitTimestamp: null,
2937
2941
  lastSyncedAt: now()
2938
2942
  };
2939
- const dayKey = (0, import_time.getRuntimeStorageDayKey)(record.entryTimestamp);
2940
- const runtimeScopeId = record.deploymentId ?? record.accountId;
2943
+ const dayKey = (0, import_time.getRuntimeStorageDayKey)(record2.entryTimestamp);
2944
+ const runtimeScopeId = record2.deploymentId ?? record2.accountId;
2941
2945
  try {
2942
2946
  await Promise.all([
2943
- (0, import_redis2.setData)(import_redis2.redisKeys.runtimeTrade(userName, record.orderId), record, {
2947
+ (0, import_redis2.setData)(import_redis2.redisKeys.runtimeTrade(userName, record2.orderId), record2, {
2944
2948
  expire: 0
2945
2949
  }),
2946
2950
  (0, import_redis2.setHashJsonField)(
2947
2951
  import_redis2.redisKeys.runtimeTradeBucket(userName, dayKey),
2948
- record.orderId,
2949
- record,
2952
+ record2.orderId,
2953
+ record2,
2950
2954
  { expire: 0 }
2951
2955
  ),
2952
2956
  (0, import_redis2.setData)(
2953
- import_redis2.redisKeys.runtimeActiveTrade(userName, record.symbol, runtimeScopeId),
2954
- { orderId: record.orderId },
2957
+ import_redis2.redisKeys.runtimeActiveTrade(userName, record2.symbol, runtimeScopeId),
2958
+ { orderId: record2.orderId },
2955
2959
  { expire: 0 }
2956
2960
  )
2957
2961
  ]);
2958
2962
  } catch (error) {
2959
2963
  import_logger2.logger.error(
2960
2964
  "runtime trade open journal failed: %s %s",
2961
- record.symbol,
2965
+ record2.symbol,
2962
2966
  error?.message || String(error)
2963
2967
  );
2964
2968
  }
2965
- return record;
2969
+ return record2;
2966
2970
  };
2967
2971
  var recordRuntimeTradeIncrease = async (params) => {
2968
2972
  const {
@@ -8287,10 +8291,10 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
8287
8291
  };
8288
8292
  var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
8289
8293
  var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
8290
- const record = isRecord2(candidate) ? candidate : null;
8291
- const nested = record && isRecord2(record[field]) ? record[field] : null;
8292
- return nested ?? record;
8293
- }).filter((record) => record != null);
8294
+ const record2 = isRecord2(candidate) ? candidate : null;
8295
+ const nested = record2 && isRecord2(record2[field]) ? record2[field] : null;
8296
+ return nested ?? record2;
8297
+ }).filter((record2) => record2 != null);
8294
8298
  var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
8295
8299
  if (!isRecord2(artifact) || artifact.reportType !== "runtime-evidence") {
8296
8300
  throw new Error("Invalid runtime evidence artifact");
@@ -9032,8 +9036,169 @@ var verifyRuntimeFeedbackReplaySource = async ({
9032
9036
  });
9033
9037
  return { feedback, runtimeEvidence };
9034
9038
  };
9039
+
9040
+ // src/diagnostics/mcpFeedbackContract.ts
9041
+ var MCP_FEEDBACK_CONTRACT = {
9042
+ version: 1,
9043
+ hostProtocolVersion: 2,
9044
+ replayQueue: {
9045
+ waitingStates: ["waiting_resources", "waiting_executor"],
9046
+ automaticFailedRetries: false
9047
+ },
9048
+ artifactEncoding: "base64",
9049
+ maximumChunkBytes: 48e3,
9050
+ artifactFiles: ["payload", "manifest.json", ".complete", "replay.log"],
9051
+ requiredTools: [
9052
+ "tradejs_info",
9053
+ "diagnostics_list_reports",
9054
+ "diagnostics_get_report",
9055
+ "artifact_get",
9056
+ "job_get",
9057
+ "job_get_logs"
9058
+ ]
9059
+ };
9060
+ var assertMcpFeedbackContract = (version, tools) => {
9061
+ if (version !== MCP_FEEDBACK_CONTRACT.version)
9062
+ throw new Error("MCP feedback contract version mismatch");
9063
+ for (const name of MCP_FEEDBACK_CONTRACT.requiredTools)
9064
+ if (!tools.some((tool) => tool.name === name))
9065
+ throw new Error(`MCP feedback requires tool ${name}`);
9066
+ const properties = tools.find((tool) => tool.name === "artifact_get")?.inputSchema.properties;
9067
+ if (!properties || !("file" in properties))
9068
+ throw new Error(
9069
+ "MCP feedback requires artifact_get.file; refresh the client tool schema"
9070
+ );
9071
+ };
9072
+
9073
+ // src/diagnostics/mcpBundleDownload.ts
9074
+ var import_node_crypto8 = require("crypto");
9075
+ var import_promises6 = __toESM(require("fs/promises"));
9076
+ var import_node_path6 = __toESM(require("path"));
9077
+ var McpReadTransportError = class extends Error {
9078
+ constructor(message, retryAfterMs) {
9079
+ super(message);
9080
+ this.retryAfterMs = retryAfterMs;
9081
+ }
9082
+ };
9083
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
9084
+ var digest = (bytes) => (0, import_node_crypto8.createHash)("sha256").update(bytes).digest("hex");
9085
+ var exists = async (file) => import_promises6.default.lstat(file).catch((error) => {
9086
+ if (error.code === "ENOENT") return void 0;
9087
+ throw error;
9088
+ });
9089
+ var checkFile = async (file) => {
9090
+ const stat = await exists(file);
9091
+ if (stat && (!stat.isFile() || stat.isSymbolicLink()))
9092
+ throw new Error("Invalid local bundle file");
9093
+ return stat;
9094
+ };
9095
+ var downloadMcpBundle = async ({
9096
+ descriptor,
9097
+ root,
9098
+ contractVersion,
9099
+ tools,
9100
+ readChunk,
9101
+ wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
9102
+ }) => {
9103
+ assertMcpFeedbackContract(contractVersion, tools);
9104
+ if (!/^[a-f0-9]{64}$/.test(descriptor.id))
9105
+ throw new Error("Invalid artifact identity");
9106
+ const required = ["payload", "manifest.json", ".complete"];
9107
+ if (descriptor.kind === "runtime-feedback-replay")
9108
+ required.push("replay.log");
9109
+ for (const name of required) {
9110
+ const matches = descriptor.files.filter((f) => f.file === name);
9111
+ if (matches.length !== 1 || !matches[0].available || !Number.isSafeInteger(matches[0].bytes) || matches[0].bytes < 0 || !/^[a-f0-9]{64}$/.test(matches[0].sha256))
9112
+ throw new Error(`Incomplete bundle descriptor: ${name}`);
9113
+ }
9114
+ const bundleDir = import_node_path6.default.join(root, descriptor.id);
9115
+ await import_promises6.default.mkdir(bundleDir, { recursive: true });
9116
+ const dir = await import_promises6.default.lstat(bundleDir);
9117
+ if (dir.isSymbolicLink()) throw new Error("Invalid bundle directory");
9118
+ const lock = import_node_path6.default.join(bundleDir, ".download-lock");
9119
+ await import_promises6.default.mkdir(lock);
9120
+ try {
9121
+ for (const name of [
9122
+ ...required.filter((f) => f !== ".complete"),
9123
+ ".complete"
9124
+ ]) {
9125
+ const expected = descriptor.files.find((f) => f.file === name);
9126
+ if (!expected) throw new Error("Missing bundle file");
9127
+ const filename = name === "payload" ? descriptor.kind === "runtime-evidence" ? "runtime-evidence.json" : "replay-runtime-evidence.json" : name;
9128
+ const target = import_node_path6.default.join(bundleDir, filename);
9129
+ const verified = await checkFile(target);
9130
+ if (verified) {
9131
+ if (verified.size !== expected.bytes || digest(await import_promises6.default.readFile(target)) !== expected.sha256)
9132
+ throw new Error("Local bundle checksum mismatch");
9133
+ continue;
9134
+ }
9135
+ const partial = target + ".part";
9136
+ const checkpoint = partial + ".json";
9137
+ const identity = JSON.stringify({
9138
+ artifactId: descriptor.id,
9139
+ file: name,
9140
+ bytes: expected.bytes,
9141
+ sha256: expected.sha256
9142
+ });
9143
+ await checkFile(checkpoint);
9144
+ const stat = await checkFile(partial);
9145
+ if (stat) {
9146
+ if (await import_promises6.default.readFile(checkpoint, "utf8") !== identity || stat.size > expected.bytes)
9147
+ throw new Error("Artifact changed during download");
9148
+ } else {
9149
+ if (await checkFile(checkpoint)) {
9150
+ if (await import_promises6.default.readFile(checkpoint, "utf8") !== identity)
9151
+ throw new Error("Artifact changed during download");
9152
+ } else await import_promises6.default.writeFile(checkpoint, identity, { flag: "wx" });
9153
+ }
9154
+ let offset = stat?.size ?? 0;
9155
+ if (!stat) await import_promises6.default.writeFile(partial, Buffer.alloc(0), { flag: "wx" });
9156
+ while (offset < expected.bytes) {
9157
+ const request = {
9158
+ artifactId: descriptor.id,
9159
+ file: name,
9160
+ offset,
9161
+ length: MCP_FEEDBACK_CONTRACT.maximumChunkBytes
9162
+ };
9163
+ let response;
9164
+ for (let attempt = 0; ; attempt++) {
9165
+ try {
9166
+ response = await readChunk(request);
9167
+ break;
9168
+ } catch (error) {
9169
+ if (!(error instanceof McpReadTransportError) || attempt >= 3)
9170
+ throw error;
9171
+ await wait(
9172
+ Math.max([2e3, 5e3, 1e4][attempt], error.retryAfterMs ?? 0)
9173
+ );
9174
+ }
9175
+ }
9176
+ if (!record(response) || response.id !== descriptor.id || response.file !== name || response.offset !== offset || response.bytes !== expected.bytes || response.sha256 !== expected.sha256 || response.encoding !== "base64" || typeof response.data !== "string" || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(
9177
+ response.data
9178
+ ))
9179
+ throw new Error("Invalid artifact chunk identity");
9180
+ const bytes = Buffer.from(response.data, "base64");
9181
+ const next = offset + bytes.length;
9182
+ if (!bytes.length || bytes.length > request.length || next > expected.bytes || response.nextOffset !== (next === expected.bytes ? null : next))
9183
+ throw new Error("Invalid artifact chunk range");
9184
+ await import_promises6.default.appendFile(partial, bytes);
9185
+ offset = next;
9186
+ }
9187
+ if (digest(await import_promises6.default.readFile(partial)) !== expected.sha256)
9188
+ throw new Error("Downloaded bundle checksum mismatch");
9189
+ await import_promises6.default.rename(partial, target);
9190
+ await import_promises6.default.unlink(checkpoint);
9191
+ }
9192
+ const bundle = descriptor.kind === "runtime-evidence" ? await verifyRuntimeEvidenceBundle(bundleDir) : await verifyRuntimeFeedbackReplayBundle(bundleDir);
9193
+ return bundle;
9194
+ } finally {
9195
+ await import_promises6.default.rmdir(lock);
9196
+ }
9197
+ };
9035
9198
  // Annotate the CommonJS export names for ESM import in node:
9036
9199
  0 && (module.exports = {
9200
+ MCP_FEEDBACK_CONTRACT,
9201
+ McpReadTransportError,
9037
9202
  RUNTIME_EVIDENCE_COMPLETE_FILE,
9038
9203
  RUNTIME_EVIDENCE_MANIFEST_FILE,
9039
9204
  RUNTIME_EVIDENCE_PAYLOAD_FILE,
@@ -9043,8 +9208,10 @@ var verifyRuntimeFeedbackReplaySource = async ({
9043
9208
  RUNTIME_FEEDBACK_REPLAY_FILE,
9044
9209
  activeRuntimeEvidenceStrategies,
9045
9210
  assertCurrentRuntimeEvidenceArtifact,
9211
+ assertMcpFeedbackContract,
9046
9212
  discoverRuntimeEvidenceBundles,
9047
9213
  discoverRuntimeFeedbackReplayBundles,
9214
+ downloadMcpBundle,
9048
9215
  parseRuntimeEvidenceDeploymentSnapshot,
9049
9216
  parseRuntimeEvidenceProducer,
9050
9217
  publishRuntimeEvidenceBundle,
@@ -95,10 +95,10 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
95
95
  };
96
96
  var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
97
97
  var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
98
- const record = isRecord(candidate) ? candidate : null;
99
- const nested = record && isRecord(record[field]) ? record[field] : null;
100
- return nested ?? record;
101
- }).filter((record) => record != null);
98
+ const record2 = isRecord(candidate) ? candidate : null;
99
+ const nested = record2 && isRecord(record2[field]) ? record2[field] : null;
100
+ return nested ?? record2;
101
+ }).filter((record2) => record2 != null);
102
102
  var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
103
103
  if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
104
104
  throw new Error("Invalid runtime evidence artifact");
@@ -840,7 +840,168 @@ var verifyRuntimeFeedbackReplaySource = async ({
840
840
  });
841
841
  return { feedback, runtimeEvidence };
842
842
  };
843
+
844
+ // src/diagnostics/mcpFeedbackContract.ts
845
+ var MCP_FEEDBACK_CONTRACT = {
846
+ version: 1,
847
+ hostProtocolVersion: 2,
848
+ replayQueue: {
849
+ waitingStates: ["waiting_resources", "waiting_executor"],
850
+ automaticFailedRetries: false
851
+ },
852
+ artifactEncoding: "base64",
853
+ maximumChunkBytes: 48e3,
854
+ artifactFiles: ["payload", "manifest.json", ".complete", "replay.log"],
855
+ requiredTools: [
856
+ "tradejs_info",
857
+ "diagnostics_list_reports",
858
+ "diagnostics_get_report",
859
+ "artifact_get",
860
+ "job_get",
861
+ "job_get_logs"
862
+ ]
863
+ };
864
+ var assertMcpFeedbackContract = (version, tools) => {
865
+ if (version !== MCP_FEEDBACK_CONTRACT.version)
866
+ throw new Error("MCP feedback contract version mismatch");
867
+ for (const name of MCP_FEEDBACK_CONTRACT.requiredTools)
868
+ if (!tools.some((tool) => tool.name === name))
869
+ throw new Error(`MCP feedback requires tool ${name}`);
870
+ const properties = tools.find((tool) => tool.name === "artifact_get")?.inputSchema.properties;
871
+ if (!properties || !("file" in properties))
872
+ throw new Error(
873
+ "MCP feedback requires artifact_get.file; refresh the client tool schema"
874
+ );
875
+ };
876
+
877
+ // src/diagnostics/mcpBundleDownload.ts
878
+ import { createHash as createHash4 } from "crypto";
879
+ import fs4 from "fs/promises";
880
+ import path4 from "path";
881
+ var McpReadTransportError = class extends Error {
882
+ constructor(message, retryAfterMs) {
883
+ super(message);
884
+ this.retryAfterMs = retryAfterMs;
885
+ }
886
+ };
887
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
888
+ var digest = (bytes) => createHash4("sha256").update(bytes).digest("hex");
889
+ var exists = async (file) => fs4.lstat(file).catch((error) => {
890
+ if (error.code === "ENOENT") return void 0;
891
+ throw error;
892
+ });
893
+ var checkFile = async (file) => {
894
+ const stat = await exists(file);
895
+ if (stat && (!stat.isFile() || stat.isSymbolicLink()))
896
+ throw new Error("Invalid local bundle file");
897
+ return stat;
898
+ };
899
+ var downloadMcpBundle = async ({
900
+ descriptor,
901
+ root,
902
+ contractVersion,
903
+ tools,
904
+ readChunk,
905
+ wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
906
+ }) => {
907
+ assertMcpFeedbackContract(contractVersion, tools);
908
+ if (!/^[a-f0-9]{64}$/.test(descriptor.id))
909
+ throw new Error("Invalid artifact identity");
910
+ const required = ["payload", "manifest.json", ".complete"];
911
+ if (descriptor.kind === "runtime-feedback-replay")
912
+ required.push("replay.log");
913
+ for (const name of required) {
914
+ const matches = descriptor.files.filter((f) => f.file === name);
915
+ if (matches.length !== 1 || !matches[0].available || !Number.isSafeInteger(matches[0].bytes) || matches[0].bytes < 0 || !/^[a-f0-9]{64}$/.test(matches[0].sha256))
916
+ throw new Error(`Incomplete bundle descriptor: ${name}`);
917
+ }
918
+ const bundleDir = path4.join(root, descriptor.id);
919
+ await fs4.mkdir(bundleDir, { recursive: true });
920
+ const dir = await fs4.lstat(bundleDir);
921
+ if (dir.isSymbolicLink()) throw new Error("Invalid bundle directory");
922
+ const lock = path4.join(bundleDir, ".download-lock");
923
+ await fs4.mkdir(lock);
924
+ try {
925
+ for (const name of [
926
+ ...required.filter((f) => f !== ".complete"),
927
+ ".complete"
928
+ ]) {
929
+ const expected = descriptor.files.find((f) => f.file === name);
930
+ if (!expected) throw new Error("Missing bundle file");
931
+ const filename = name === "payload" ? descriptor.kind === "runtime-evidence" ? "runtime-evidence.json" : "replay-runtime-evidence.json" : name;
932
+ const target = path4.join(bundleDir, filename);
933
+ const verified = await checkFile(target);
934
+ if (verified) {
935
+ if (verified.size !== expected.bytes || digest(await fs4.readFile(target)) !== expected.sha256)
936
+ throw new Error("Local bundle checksum mismatch");
937
+ continue;
938
+ }
939
+ const partial = target + ".part";
940
+ const checkpoint = partial + ".json";
941
+ const identity = JSON.stringify({
942
+ artifactId: descriptor.id,
943
+ file: name,
944
+ bytes: expected.bytes,
945
+ sha256: expected.sha256
946
+ });
947
+ await checkFile(checkpoint);
948
+ const stat = await checkFile(partial);
949
+ if (stat) {
950
+ if (await fs4.readFile(checkpoint, "utf8") !== identity || stat.size > expected.bytes)
951
+ throw new Error("Artifact changed during download");
952
+ } else {
953
+ if (await checkFile(checkpoint)) {
954
+ if (await fs4.readFile(checkpoint, "utf8") !== identity)
955
+ throw new Error("Artifact changed during download");
956
+ } else await fs4.writeFile(checkpoint, identity, { flag: "wx" });
957
+ }
958
+ let offset = stat?.size ?? 0;
959
+ if (!stat) await fs4.writeFile(partial, Buffer.alloc(0), { flag: "wx" });
960
+ while (offset < expected.bytes) {
961
+ const request = {
962
+ artifactId: descriptor.id,
963
+ file: name,
964
+ offset,
965
+ length: MCP_FEEDBACK_CONTRACT.maximumChunkBytes
966
+ };
967
+ let response;
968
+ for (let attempt = 0; ; attempt++) {
969
+ try {
970
+ response = await readChunk(request);
971
+ break;
972
+ } catch (error) {
973
+ if (!(error instanceof McpReadTransportError) || attempt >= 3)
974
+ throw error;
975
+ await wait(
976
+ Math.max([2e3, 5e3, 1e4][attempt], error.retryAfterMs ?? 0)
977
+ );
978
+ }
979
+ }
980
+ if (!record(response) || response.id !== descriptor.id || response.file !== name || response.offset !== offset || response.bytes !== expected.bytes || response.sha256 !== expected.sha256 || response.encoding !== "base64" || typeof response.data !== "string" || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(
981
+ response.data
982
+ ))
983
+ throw new Error("Invalid artifact chunk identity");
984
+ const bytes = Buffer.from(response.data, "base64");
985
+ const next = offset + bytes.length;
986
+ if (!bytes.length || bytes.length > request.length || next > expected.bytes || response.nextOffset !== (next === expected.bytes ? null : next))
987
+ throw new Error("Invalid artifact chunk range");
988
+ await fs4.appendFile(partial, bytes);
989
+ offset = next;
990
+ }
991
+ if (digest(await fs4.readFile(partial)) !== expected.sha256)
992
+ throw new Error("Downloaded bundle checksum mismatch");
993
+ await fs4.rename(partial, target);
994
+ await fs4.unlink(checkpoint);
995
+ }
996
+ const bundle = descriptor.kind === "runtime-evidence" ? await verifyRuntimeEvidenceBundle(bundleDir) : await verifyRuntimeFeedbackReplayBundle(bundleDir);
997
+ return bundle;
998
+ } finally {
999
+ await fs4.rmdir(lock);
1000
+ }
1001
+ };
843
1002
  export {
1003
+ MCP_FEEDBACK_CONTRACT,
1004
+ McpReadTransportError,
844
1005
  RUNTIME_EVIDENCE_COMPLETE_FILE,
845
1006
  RUNTIME_EVIDENCE_MANIFEST_FILE,
846
1007
  RUNTIME_EVIDENCE_PAYLOAD_FILE,
@@ -850,8 +1011,10 @@ export {
850
1011
  RUNTIME_FEEDBACK_REPLAY_FILE,
851
1012
  activeRuntimeEvidenceStrategies,
852
1013
  assertCurrentRuntimeEvidenceArtifact,
1014
+ assertMcpFeedbackContract,
853
1015
  discoverRuntimeEvidenceBundles,
854
1016
  discoverRuntimeFeedbackReplayBundles,
1017
+ downloadMcpBundle,
855
1018
  parseRuntimeEvidenceDeploymentSnapshot,
856
1019
  parseRuntimeEvidenceProducer,
857
1020
  publishRuntimeEvidenceBundle,
package/dist/mcp.d.mts CHANGED
@@ -12,7 +12,7 @@ declare const redactMcpJobLog: (line: string) => string;
12
12
  /** Offsets refer to the retained worker tail, which may shift while running. */
13
13
  declare const readMcpJobLogs: (principal: McpPrincipal, id: string, offset?: number, limit?: number) => Promise<{
14
14
  jobId: string;
15
- status: "completed" | "failed" | "running" | "queued" | "cancelled";
15
+ status: "running" | "completed" | "failed" | "queued" | "waiting_resources" | "waiting_executor" | "cancelled";
16
16
  updatedAt: number;
17
17
  offset: number;
18
18
  nextOffset: number | null;
@@ -30,7 +30,7 @@ declare const publicMcpJob: (job: McpJob) => {
30
30
  userName: string;
31
31
  clientId: string;
32
32
  kind: "backtest" | "runtime-evidence" | "runtime-feedback-replay";
33
- status: "queued" | "running" | "completed" | "failed" | "cancelled";
33
+ status: "queued" | "waiting_resources" | "waiting_executor" | "running" | "completed" | "failed" | "cancelled";
34
34
  createdAt: number;
35
35
  updatedAt: number;
36
36
  startedAt?: number;
package/dist/mcp.d.ts CHANGED
@@ -12,7 +12,7 @@ declare const redactMcpJobLog: (line: string) => string;
12
12
  /** Offsets refer to the retained worker tail, which may shift while running. */
13
13
  declare const readMcpJobLogs: (principal: McpPrincipal, id: string, offset?: number, limit?: number) => Promise<{
14
14
  jobId: string;
15
- status: "completed" | "failed" | "running" | "queued" | "cancelled";
15
+ status: "running" | "completed" | "failed" | "queued" | "waiting_resources" | "waiting_executor" | "cancelled";
16
16
  updatedAt: number;
17
17
  offset: number;
18
18
  nextOffset: number | null;
@@ -30,7 +30,7 @@ declare const publicMcpJob: (job: McpJob) => {
30
30
  userName: string;
31
31
  clientId: string;
32
32
  kind: "backtest" | "runtime-evidence" | "runtime-feedback-replay";
33
- status: "queued" | "running" | "completed" | "failed" | "cancelled";
33
+ status: "queued" | "waiting_resources" | "waiting_executor" | "running" | "completed" | "failed" | "cancelled";
34
34
  createdAt: number;
35
35
  updatedAt: number;
36
36
  startedAt?: number;
package/dist/mcp.js CHANGED
@@ -8912,7 +8912,10 @@ var cancelMcpJob = async (principal, id) => {
8912
8912
  const job = await readMcpJob(principal.userName, id);
8913
8913
  if (job.clientId !== principal.clientId)
8914
8914
  throw new Error("Only the submitting client can cancel this job");
8915
- if (!["queued", "running"].includes(job.status)) return job;
8915
+ if (!["queued", "waiting_resources", "waiting_executor", "running"].includes(
8916
+ job.status
8917
+ ))
8918
+ return job;
8916
8919
  const next = {
8917
8920
  ...job,
8918
8921
  cancelRequested: true,
package/dist/mcp.mjs CHANGED
@@ -236,7 +236,10 @@ var cancelMcpJob = async (principal, id) => {
236
236
  const job = await readMcpJob(principal.userName, id);
237
237
  if (job.clientId !== principal.clientId)
238
238
  throw new Error("Only the submitting client can cancel this job");
239
- if (!["queued", "running"].includes(job.status)) return job;
239
+ if (!["queued", "waiting_resources", "waiting_executor", "running"].includes(
240
+ job.status
241
+ ))
242
+ return job;
240
243
  const next = {
241
244
  ...job,
242
245
  cancelRequested: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/node",
3
- "version": "3.1.29-beta.282",
3
+ "version": "3.1.29-beta.283",
4
4
  "description": "Node-only runtime for the TradeJS TypeScript framework: strategies, backtests, Pine strategy loading, and plugin registries.",
5
5
  "keywords": [
6
6
  "tradejs",
@@ -105,9 +105,9 @@
105
105
  "dependencies": {
106
106
  "@langchain/core": "^1.2.3",
107
107
  "@langchain/openai": "^1.5.5",
108
- "@tradejs/core": "^3.1.29-beta.282",
109
- "@tradejs/infra": "^3.1.29-beta.282",
110
- "@tradejs/types": "^3.1.29-beta.282",
108
+ "@tradejs/core": "^3.1.29-beta.283",
109
+ "@tradejs/infra": "^3.1.29-beta.283",
110
+ "@tradejs/types": "^3.1.29-beta.283",
111
111
  "@types/node": "^24",
112
112
  "chalk": "4.1.2",
113
113
  "ioredis": "5.11.1",
@@ -120,7 +120,7 @@
120
120
  "typescript": "^5.9"
121
121
  },
122
122
  "devDependencies": {
123
- "@tradejs/indicators": "^3.1.29-beta.282",
123
+ "@tradejs/indicators": "^3.1.29-beta.283",
124
124
  "@tradejs/strategy-adaptive-momentum-ribbon": "3.0.5",
125
125
  "@tradejs/strategy-hyperliquid-consensus": "3.0.5",
126
126
  "@tradejs/strategy-kit": "3.0.6",