@tradejs/cli 3.1.29-beta.289 → 3.1.29-beta.291
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/dist/cli.js +2574 -1236
- package/dist/lib/aiPocketSearch.js +37 -3
- package/dist/lib/aiTrainDataset.js +1 -0
- package/dist/lib/aiTrainEvaluationDump.js +7 -2
- package/dist/lib/aiTrainResearch.js +11 -7
- package/dist/lib/coreResearch.js +12 -4
- package/dist/lib/researchMetricSnapshot.js +74 -0
- package/dist/lib/researchVisuals.js +910 -0
- package/dist/lib/runtimeFeedbackNotification.js +6 -2
- package/dist/lib/runtimeFeedbackReplay.js +44 -29
- package/dist/lib/runtimeParity.js +1 -0
- package/dist/lib/runtimeParityDetails.js +51 -21
- package/dist/lib/strategyRelease.js +8 -2
- package/dist/lib/strategyResearch.js +133 -33
- package/dist/lib/tickerProfiles.js +76 -0
- package/dist/scripts/aiPocketSearch.js +38 -3
- package/dist/scripts/aiTrain.js +29 -17
- package/dist/scripts/coreResearch.js +12 -4
- package/dist/scripts/replay.js +223 -33
- package/dist/scripts/replayRunner.js +223 -33
- package/dist/scripts/researchVisuals.js +955 -0
- package/dist/scripts/runtimeFeedbackNotify.js +11 -3
- package/dist/scripts/runtimeFeedbackReplay.js +44 -29
- package/dist/scripts/runtimeParity.js +1 -0
- package/dist/scripts/signalsSummary.js +5 -6
- package/dist/scripts/strategyRelease.js +59 -7
- package/dist/scripts/strategyResearch.js +136 -36
- package/dist/scripts/tickerProfiles.js +114 -0
- package/package.json +8 -7
|
@@ -39,6 +39,9 @@ var import_node_path = __toESM(require("path"));
|
|
|
39
39
|
var import_args = __toESM(require("args"));
|
|
40
40
|
var import_chalk = __toESM(require("chalk"));
|
|
41
41
|
|
|
42
|
+
// src/lib/runtimeFeedbackNotification.ts
|
|
43
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
44
|
+
|
|
42
45
|
// src/lib/runtimeFeedbackArtifacts.ts
|
|
43
46
|
var runtimeFeedbackArtifacts_exports = {};
|
|
44
47
|
__reExport(runtimeFeedbackArtifacts_exports, require("@tradejs/node/diagnostics"));
|
|
@@ -223,11 +226,14 @@ var notifyRuntimeFeedbackBundle = async ({
|
|
|
223
226
|
}) => {
|
|
224
227
|
const verified = await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplayBundle)(bundleDir);
|
|
225
228
|
const message = buildRuntimeFeedbackTelegramMessage(verified.replayEvidence);
|
|
226
|
-
await
|
|
229
|
+
const settings = await (0, import_userSettings.getUserSettings)(verified.manifest.userName);
|
|
230
|
+
const sent = settings.NOTIFY_RUNTIME_DEBUG !== false;
|
|
231
|
+
if (sent) await send(message, { userName: verified.manifest.userName });
|
|
227
232
|
return {
|
|
228
233
|
artifactId: verified.manifest.artifactId,
|
|
229
234
|
userName: verified.manifest.userName,
|
|
230
|
-
message
|
|
235
|
+
message,
|
|
236
|
+
sent
|
|
231
237
|
};
|
|
232
238
|
};
|
|
233
239
|
|
|
@@ -249,7 +255,9 @@ var runtimeFeedbackNotify = async () => {
|
|
|
249
255
|
}
|
|
250
256
|
const result = await notifyRuntimeFeedbackBundle({ bundleDir });
|
|
251
257
|
console.log(
|
|
252
|
-
import_chalk.default.green(
|
|
258
|
+
import_chalk.default.green(
|
|
259
|
+
`Runtime feedback notification ${result.sent ? "sent" : "disabled"}: ${result.artifactId}`
|
|
260
|
+
)
|
|
253
261
|
);
|
|
254
262
|
};
|
|
255
263
|
var main = runtimeFeedbackNotify;
|
|
@@ -43,6 +43,7 @@ var import_chalk = __toESM(require("chalk"));
|
|
|
43
43
|
var import_node_child_process = require("child_process");
|
|
44
44
|
var import_promises = __toESM(require("fs/promises"));
|
|
45
45
|
var import_node_path = __toESM(require("path"));
|
|
46
|
+
var import_mcp = require("@tradejs/node/mcp");
|
|
46
47
|
|
|
47
48
|
// src/lib/runtimeEvidenceDeployment.ts
|
|
48
49
|
var runtimeEvidenceDeployment_exports = {};
|
|
@@ -190,44 +191,58 @@ var runLoggedCommand = async ({
|
|
|
190
191
|
env,
|
|
191
192
|
logHandle
|
|
192
193
|
}) => {
|
|
193
|
-
await logHandle.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
};
|
|
203
|
-
const child = (0, import_node_child_process.spawn)(executable, command, {
|
|
204
|
-
cwd,
|
|
205
|
-
env,
|
|
206
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
207
|
-
});
|
|
208
|
-
child.stdout.on("data", (chunk) => {
|
|
209
|
-
process.stdout.write(chunk);
|
|
210
|
-
appendLog(chunk);
|
|
211
|
-
});
|
|
212
|
-
child.stderr.on("data", (chunk) => {
|
|
213
|
-
process.stderr.write(chunk);
|
|
214
|
-
appendLog(chunk);
|
|
215
|
-
});
|
|
194
|
+
await logHandle.writeFile(
|
|
195
|
+
"\n" + (0, import_mcp.formatMcpArtifactLogLine)(`$ ${[executable, ...command].join(" ")}`)
|
|
196
|
+
);
|
|
197
|
+
const child = (0, import_node_child_process.spawn)(executable, command, {
|
|
198
|
+
cwd,
|
|
199
|
+
env,
|
|
200
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
201
|
+
});
|
|
202
|
+
const exit = new Promise((resolve, reject) => {
|
|
216
203
|
child.once("error", reject);
|
|
217
204
|
child.once("close", (code, signal) => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
resolve();
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
205
|
+
if (code === 0) resolve();
|
|
206
|
+
else {
|
|
223
207
|
reject(
|
|
224
208
|
new Error(
|
|
225
209
|
`Runtime feedback command failed: exit=${String(code)} signal=${String(signal)}`
|
|
226
210
|
)
|
|
227
211
|
);
|
|
228
|
-
}
|
|
212
|
+
}
|
|
229
213
|
});
|
|
230
214
|
});
|
|
215
|
+
let pendingLogWrite = Promise.resolve();
|
|
216
|
+
const copyLog = async (input, output) => {
|
|
217
|
+
const writeLine = async (line) => {
|
|
218
|
+
const formatted = (0, import_mcp.formatMcpArtifactLogLine)(line);
|
|
219
|
+
pendingLogWrite = pendingLogWrite.then(
|
|
220
|
+
() => logHandle.writeFile(formatted)
|
|
221
|
+
);
|
|
222
|
+
await pendingLogWrite;
|
|
223
|
+
output.write(formatted);
|
|
224
|
+
};
|
|
225
|
+
let pendingLine = "";
|
|
226
|
+
try {
|
|
227
|
+
for await (const chunk of input.setEncoding("utf8")) {
|
|
228
|
+
const lines = (pendingLine + chunk).split("\n");
|
|
229
|
+
pendingLine = lines.pop() ?? "";
|
|
230
|
+
for (const line of lines) await writeLine(line);
|
|
231
|
+
}
|
|
232
|
+
if (pendingLine) await writeLine(pendingLine);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
child.kill();
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const results = await Promise.allSettled([
|
|
239
|
+
copyLog(child.stdout, process.stdout),
|
|
240
|
+
copyLog(child.stderr, process.stderr),
|
|
241
|
+
exit
|
|
242
|
+
]);
|
|
243
|
+
for (const result of results) {
|
|
244
|
+
if (result.status === "rejected") throw result.reason;
|
|
245
|
+
}
|
|
231
246
|
};
|
|
232
247
|
var runRuntimeFeedbackReplay = async ({
|
|
233
248
|
runtimeEvidencePath,
|
|
@@ -159,6 +159,7 @@ var extractRuntimeParityEntries = (trades) => trades.filter(
|
|
|
159
159
|
direction: trade.direction,
|
|
160
160
|
qty: toFiniteNumberOrNull(trade.qty),
|
|
161
161
|
timestamp: trade.entryTimestamp,
|
|
162
|
+
...Number.isFinite(trade.signalTimestamp) ? { signalTimestamp: trade.signalTimestamp } : {},
|
|
162
163
|
price: toFiniteNumberOrNull(trade.entryPrice),
|
|
163
164
|
orderId: trade.orderId,
|
|
164
165
|
signalId: typeof trade.signalId === "string" ? trade.signalId : void 0,
|
|
@@ -35,6 +35,7 @@ __export(signalsSummary_exports, {
|
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(signalsSummary_exports);
|
|
37
37
|
var import_config = require("dotenv/config");
|
|
38
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
38
39
|
var import_args = __toESM(require("args"));
|
|
39
40
|
var import_logger = require("@tradejs/infra/logger");
|
|
40
41
|
var import_connectors = require("@tradejs/node/connectors");
|
|
@@ -1295,6 +1296,7 @@ none`
|
|
|
1295
1296
|
};
|
|
1296
1297
|
};
|
|
1297
1298
|
var signalsSummary = async () => {
|
|
1299
|
+
const includeDebug = flags.printOnly || (await (0, import_userSettings.getUserSettings)(flags.user)).NOTIFY_RUNTIME_DEBUG !== false;
|
|
1298
1300
|
const hours = Math.max(
|
|
1299
1301
|
1,
|
|
1300
1302
|
Number.parseInt(String(flags.hours ?? 24), 10) || 24
|
|
@@ -1415,18 +1417,15 @@ var signalsSummary = async () => {
|
|
|
1415
1417
|
content: signalsMessage,
|
|
1416
1418
|
deploymentId: scope.deploymentId
|
|
1417
1419
|
});
|
|
1418
|
-
const tradesMessageWithAttachmentSummary = appendReportAttachmentSummary({
|
|
1420
|
+
const tradesMessageWithAttachmentSummary = includeDebug ? appendReportAttachmentSummary({
|
|
1419
1421
|
message: tradesMessage,
|
|
1420
1422
|
signalsFilename: signalsAttachment.filename,
|
|
1421
1423
|
filename: debugAttachment?.filename,
|
|
1422
1424
|
tradesCount: debugAttachment ? scopeTrades.length : void 0,
|
|
1423
1425
|
signalsCount: debugAttachment ? debugAttachment.summary?.signals ?? debugSignals.length : void 0,
|
|
1424
1426
|
evaluationsCount: debugAttachment ? debugAttachment.summary?.evaluations ?? 0 : void 0
|
|
1425
|
-
});
|
|
1426
|
-
const attachments = [
|
|
1427
|
-
signalsAttachment,
|
|
1428
|
-
...debugAttachment ? [debugAttachment] : []
|
|
1429
|
-
];
|
|
1427
|
+
}) : tradesMessage;
|
|
1428
|
+
const attachments = includeDebug ? [signalsAttachment, ...debugAttachment ? [debugAttachment] : []] : [];
|
|
1430
1429
|
if (flags.printOnly) {
|
|
1431
1430
|
console.log(tradesMessageWithAttachmentSummary);
|
|
1432
1431
|
console.log("");
|
|
@@ -42,8 +42,40 @@ var import_chalk = __toESM(require("chalk"));
|
|
|
42
42
|
|
|
43
43
|
// src/lib/strategyRelease/researchRetention.ts
|
|
44
44
|
var import_promises = __toESM(require("fs/promises"));
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
// src/lib/researchMetricSnapshot.ts
|
|
46
47
|
var import_node_crypto = require("crypto");
|
|
48
|
+
var import_node_zlib = require("zlib");
|
|
49
|
+
var MAX_BYTES = 256 * 1024 * 1024;
|
|
50
|
+
var hash = (bytes) => (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
|
|
51
|
+
var validatePermanentResearchMetrics = (value) => {
|
|
52
|
+
if (!value || typeof value !== "object") return;
|
|
53
|
+
for (const [key, child] of Object.entries(value)) {
|
|
54
|
+
if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
|
|
55
|
+
throw new Error(`Temporary payload ${key} is not a permanent metric`);
|
|
56
|
+
if (key === "trades" && Array.isArray(child) && child.some(
|
|
57
|
+
(row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
|
|
58
|
+
))
|
|
59
|
+
throw new Error("Temporary trade records are not permanent metrics");
|
|
60
|
+
validatePermanentResearchMetrics(child);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var decodeResearchMetricSnapshot = (snapshot) => {
|
|
64
|
+
if (!snapshot || typeof snapshot !== "object" || !("schema" in snapshot) || snapshot.schema !== "tradejs-metric-snapshot/v1" || !("encoding" in snapshot) || snapshot.encoding !== "gzip+base64" || !("decodedBytes" in snapshot) || typeof snapshot.decodedBytes !== "number" || !Number.isSafeInteger(snapshot.decodedBytes) || snapshot.decodedBytes <= 0 || snapshot.decodedBytes > MAX_BYTES || !("sha256" in snapshot) || typeof snapshot.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(snapshot.sha256) || !("payload" in snapshot) || typeof snapshot.payload !== "string")
|
|
65
|
+
throw new Error("Invalid metric snapshot envelope");
|
|
66
|
+
const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
|
|
67
|
+
maxOutputLength: snapshot.decodedBytes
|
|
68
|
+
});
|
|
69
|
+
if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
|
|
70
|
+
throw new Error("Metric snapshot checksum or size mismatch");
|
|
71
|
+
const metrics = JSON.parse(bytes.toString("utf8"));
|
|
72
|
+
validatePermanentResearchMetrics(metrics);
|
|
73
|
+
return metrics;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/lib/strategyRelease/researchRetention.ts
|
|
77
|
+
var import_node_path2 = __toESM(require("path"));
|
|
78
|
+
var import_node_crypto2 = require("crypto");
|
|
47
79
|
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
48
80
|
|
|
49
81
|
// src/lib/strategyRelease/researchFileConsumers.ts
|
|
@@ -235,7 +267,7 @@ var mapFiles = async (entries, visit) => {
|
|
|
235
267
|
if (worker.status === "rejected") throw worker.reason;
|
|
236
268
|
return results;
|
|
237
269
|
};
|
|
238
|
-
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0,
|
|
270
|
+
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto2.createHash)("sha256").update(await import_promises.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(file);
|
|
239
271
|
var inside = (root, file) => {
|
|
240
272
|
const relative = import_node_path2.default.relative(root, file);
|
|
241
273
|
return relative !== "" && !relative.startsWith(`..${import_node_path2.default.sep}`) && relative !== ".." && !import_node_path2.default.isAbsolute(relative);
|
|
@@ -279,13 +311,27 @@ var applyResearchRetention = async (options) => {
|
|
|
279
311
|
const header = Buffer.alloc(4096);
|
|
280
312
|
const { bytesRead } = await handle.read(header, 0, header.length, 0);
|
|
281
313
|
const frontmatter = header.subarray(0, bytesRead).toString("utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
282
|
-
if (!frontmatter || !/^schema:\s*tradejs-research\/
|
|
314
|
+
if (!frontmatter || !/^schema:\s*tradejs-research\/v[12]\s*$/m.test(frontmatter[1]) || !(retired ? /^reproduction:\s*(?:complete|partial|blocked|legacy-partial)\s*$/m.test(
|
|
283
315
|
frontmatter[1]
|
|
284
316
|
) : /^reproduction:\s*complete\s*$/m.test(frontmatter[1]))) {
|
|
285
317
|
throw new Error(
|
|
286
318
|
`Research note must have reproduction: complete: ${file}`
|
|
287
319
|
);
|
|
288
320
|
}
|
|
321
|
+
if (!retired && /^schema:\s*tradejs-research\/v2\s*$/m.test(frontmatter[1])) {
|
|
322
|
+
if ((await import_promises.default.stat(file)).size > 8 * 1024 * 1024)
|
|
323
|
+
throw new Error("Compact permanent note exceeds 8 MiB");
|
|
324
|
+
const content = await import_promises.default.readFile(file, "utf8");
|
|
325
|
+
const section = content.split("## Metrics snapshot (machine-readable)")[1]?.split("## Reported metrics")[0] ?? "";
|
|
326
|
+
const blocks = [
|
|
327
|
+
...section.matchAll(/```json\r?\n([\s\S]*?)\r?\n```/g)
|
|
328
|
+
];
|
|
329
|
+
if (blocks.length !== 1)
|
|
330
|
+
throw new Error(
|
|
331
|
+
"Complete v2 note needs one verified metric snapshot"
|
|
332
|
+
);
|
|
333
|
+
decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
|
|
334
|
+
}
|
|
289
335
|
} finally {
|
|
290
336
|
await handle.close();
|
|
291
337
|
}
|
|
@@ -369,7 +415,7 @@ var applyResearchRetention = async (options) => {
|
|
|
369
415
|
};
|
|
370
416
|
|
|
371
417
|
// src/lib/strategyRelease.ts
|
|
372
|
-
var
|
|
418
|
+
var import_node_crypto3 = require("crypto");
|
|
373
419
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
374
420
|
var import_node_path3 = __toESM(require("path"));
|
|
375
421
|
var import_types2 = require("@tradejs/types");
|
|
@@ -1539,7 +1585,7 @@ var verifyCompletedCoreResearchBundle = async ({
|
|
|
1539
1585
|
const artifactHashes = manifest.artifactHashes != null && typeof manifest.artifactHashes === "object" && !Array.isArray(manifest.artifactHashes) ? manifest.artifactHashes : null;
|
|
1540
1586
|
const parsedSpec = JSON.parse(specBytes.toString("utf8"));
|
|
1541
1587
|
assert2(
|
|
1542
|
-
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0,
|
|
1588
|
+
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0, import_node_crypto3.createHash)("sha256").update(canonicalStrategyReleaseJson(parsedSpec)).digest("hex") === specSha256,
|
|
1543
1589
|
"core result is not bound by its completed core research manifest"
|
|
1544
1590
|
);
|
|
1545
1591
|
for (const [relativePath, expectedSha256] of Object.entries(
|
|
@@ -1587,12 +1633,18 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
1587
1633
|
}
|
|
1588
1634
|
const nested = (value) => value != null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1589
1635
|
const array = (value) => Array.isArray(value) ? value : [];
|
|
1590
|
-
const semanticallyValid = reference.kind === "core_research" ?
|
|
1636
|
+
const semanticallyValid = reference.kind === "core_research" ? [
|
|
1637
|
+
"tradejs-core-research-result/v1",
|
|
1638
|
+
"tradejs-core-research-result/v2"
|
|
1639
|
+
].includes(String(artifact.schema)) || artifact.schema === "tradejs-core-research-manifest/v1" && artifact.status === "completed" : reference.kind === "ai_gate" ? nested(artifact.run)?.mode === "local-deterministic" && nested(artifact.research)?.lineage != null && nested(artifact.outcome) != null : reference.kind === "runtime_parity" ? artifact.reportType === "replay-runtime-evidence" && nested(nested(artifact.replay)?.runtimeComparison) != null : reference.kind === "execution_calibration" ? artifact.reportType === "execution-calibration" && nested(artifact.summary) != null : reference.kind === "runtime_evidence" ? artifact.reportType === "runtime-evidence" : artifact.reportType === "runtime-scorecard";
|
|
1591
1640
|
assert2(
|
|
1592
1641
|
semanticallyValid,
|
|
1593
1642
|
`evidence ${reference.artifactId} does not match ${reference.kind}`
|
|
1594
1643
|
);
|
|
1595
|
-
if (reference.kind === "core_research" &&
|
|
1644
|
+
if (reference.kind === "core_research" && [
|
|
1645
|
+
"tradejs-core-research-result/v1",
|
|
1646
|
+
"tradejs-core-research-result/v2"
|
|
1647
|
+
].includes(String(artifact.schema))) {
|
|
1596
1648
|
await verifyCompletedCoreResearchBundle({
|
|
1597
1649
|
artifact,
|
|
1598
1650
|
resultPath: reference.path,
|