@tradejs/cli 3.0.1 → 3.1.1
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 +2 -0
- package/dist/cli.js +3707 -2983
- package/dist/lib/aiPocketSearch.js +10 -0
- package/dist/lib/aiTrainResearch.js +24 -15
- package/dist/lib/coreResearch.js +52 -20
- package/dist/lib/researchAgent.js +16 -2
- package/dist/lib/researchRoots.js +59 -0
- package/dist/lib/runtimeLineage.js +43 -19
- package/dist/lib/runtimeModeConfig.js +1 -1
- package/dist/lib/runtimeSignalsStorage.js +2 -1
- package/dist/lib/strategyGateFingerprint.js +26 -15
- package/dist/lib/strategyRelease.js +266 -253
- package/dist/scripts/agentRun.js +83 -52
- package/dist/scripts/aiPocketSearch.js +2269 -1972
- package/dist/scripts/aiTrain.js +24 -15
- package/dist/scripts/coreResearch.js +91 -30
- package/dist/scripts/replay.js +69 -27
- package/dist/scripts/replayRunner.js +69 -27
- package/dist/scripts/researchAuto.js +34 -13
- package/dist/scripts/runtimeConfig.js +290 -0
- package/dist/scripts/runtimeEvidence.js +2 -1
- package/dist/scripts/runtimeParity.js +1 -1
- package/dist/scripts/runtimeScorecard.js +108 -103
- package/dist/scripts/signals.js +162 -224
- package/dist/scripts/signalsDaemon.js +162 -224
- package/dist/scripts/strategyRelease.js +222 -209
- package/dist/scripts/test-ml.js +8 -2
- package/package.json +13 -10
|
@@ -4350,7 +4350,7 @@ var buildRuntimeModeStrategyConfig = ({
|
|
|
4350
4350
|
...strategyConfig,
|
|
4351
4351
|
ENV: env,
|
|
4352
4352
|
MAKE_ORDERS: makeOrders,
|
|
4353
|
-
INTERVAL: interval,
|
|
4353
|
+
INTERVAL: strategyConfig.INTERVAL ?? interval,
|
|
4354
4354
|
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
4355
4355
|
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
4356
4356
|
});
|
|
@@ -4913,28 +4913,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
|
|
|
4913
4913
|
|
|
4914
4914
|
// src/lib/strategyGateFingerprint.ts
|
|
4915
4915
|
var import_node_crypto = require("crypto");
|
|
4916
|
+
var import_node_module = require("module");
|
|
4916
4917
|
var import_promises = __toESM(require("fs/promises"));
|
|
4917
4918
|
var import_node_path = __toESM(require("path"));
|
|
4918
|
-
var
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
"
|
|
4924
|
-
"
|
|
4925
|
-
"packages/core/src/utils/strategyHelpers/signalBuilders.ts"
|
|
4919
|
+
var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
4920
|
+
var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
|
|
4921
|
+
var gateFingerprintSpecifiers = (strategyName) => [
|
|
4922
|
+
getStrategyPackageName(strategyName),
|
|
4923
|
+
"@tradejs/strategy-kit/ai-gate",
|
|
4924
|
+
"@tradejs/node/ai",
|
|
4925
|
+
"@tradejs/core/strategies"
|
|
4926
4926
|
];
|
|
4927
4927
|
var resolveStrategyGateFingerprint = async ({
|
|
4928
4928
|
projectRoot,
|
|
4929
4929
|
strategyName,
|
|
4930
4930
|
gitSha
|
|
4931
4931
|
}) => {
|
|
4932
|
-
const
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4932
|
+
const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
|
|
4933
|
+
const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
|
|
4934
|
+
const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
|
|
4935
|
+
const candidates = requireFromProject ? await Promise.all(
|
|
4936
|
+
gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
|
|
4937
|
+
let resolvedPath;
|
|
4938
|
+
try {
|
|
4939
|
+
resolvedPath = requireFromProject.resolve(specifier);
|
|
4940
|
+
} catch {
|
|
4941
|
+
return null;
|
|
4942
|
+
}
|
|
4943
|
+
const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
|
|
4944
|
+
return content == null ? null : { specifier, content };
|
|
4936
4945
|
})
|
|
4937
|
-
);
|
|
4946
|
+
) : [];
|
|
4938
4947
|
const sourceEntries = candidates.filter(
|
|
4939
4948
|
(entry) => entry != null
|
|
4940
4949
|
);
|
|
@@ -4942,7 +4951,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
4942
4951
|
hash.update(strategyName);
|
|
4943
4952
|
if (sourceEntries.length) {
|
|
4944
4953
|
for (const entry of sourceEntries) {
|
|
4945
|
-
hash.update(entry.
|
|
4954
|
+
hash.update(entry.specifier);
|
|
4946
4955
|
hash.update(entry.content);
|
|
4947
4956
|
}
|
|
4948
4957
|
} else {
|
|
@@ -4950,7 +4959,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
4950
4959
|
}
|
|
4951
4960
|
return {
|
|
4952
4961
|
gateFingerprint: hash.digest("hex").slice(0, 16),
|
|
4953
|
-
gateFingerprintFiles: sourceEntries.map((entry) => entry.
|
|
4962
|
+
gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
|
|
4954
4963
|
};
|
|
4955
4964
|
};
|
|
4956
4965
|
|
|
@@ -5129,14 +5138,29 @@ var resolveRuntimeGateFingerprint = async ({
|
|
|
5129
5138
|
gateFingerprintCache.set(cacheKey, result);
|
|
5130
5139
|
return result;
|
|
5131
5140
|
};
|
|
5132
|
-
|
|
5141
|
+
async function buildRuntimeLineage({
|
|
5133
5142
|
projectRoot,
|
|
5134
5143
|
strategyName,
|
|
5135
5144
|
compositionId,
|
|
5145
|
+
releaseVersion,
|
|
5146
|
+
strategyPackageVersion,
|
|
5147
|
+
runtimePackageVersion,
|
|
5136
5148
|
config,
|
|
5137
5149
|
runContext,
|
|
5138
5150
|
env = process.env
|
|
5139
|
-
})
|
|
5151
|
+
}) {
|
|
5152
|
+
if (releaseVersion != null) {
|
|
5153
|
+
if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
|
|
5154
|
+
throw new Error(`Invalid runtime releaseVersion: ${releaseVersion}`);
|
|
5155
|
+
}
|
|
5156
|
+
return {
|
|
5157
|
+
schemaVersion: 2,
|
|
5158
|
+
releaseVersion,
|
|
5159
|
+
strategyPackageVersion,
|
|
5160
|
+
runtimePackageVersion,
|
|
5161
|
+
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5162
|
+
};
|
|
5163
|
+
}
|
|
5140
5164
|
const git = resolveGitLineage(projectRoot);
|
|
5141
5165
|
const hyperliquidPerpUniverseFingerprint = typeof import_strategies3.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies3.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
|
|
5142
5166
|
projectRoot,
|
|
@@ -5171,8 +5195,8 @@ var buildRuntimeLineage = async ({
|
|
|
5171
5195
|
contextFingerprint: fingerprintRuntimeValue(context),
|
|
5172
5196
|
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5173
5197
|
};
|
|
5174
|
-
}
|
|
5175
|
-
var runtimeLineageKey = (lineage) => [
|
|
5198
|
+
}
|
|
5199
|
+
var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
|
|
5176
5200
|
lineage.schemaVersion,
|
|
5177
5201
|
lineage.compositionId ?? "unbound-composition",
|
|
5178
5202
|
lineage.gitSha ?? "unknown",
|
|
@@ -5424,6 +5448,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5424
5448
|
userName: replayUserName,
|
|
5425
5449
|
connectorName,
|
|
5426
5450
|
runtimeConfigId: "config",
|
|
5451
|
+
runtimeLineage,
|
|
5427
5452
|
config: buildReplayStrategyConfig({
|
|
5428
5453
|
strategyConfig,
|
|
5429
5454
|
interval
|
|
@@ -7204,6 +7229,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7204
7229
|
strategy,
|
|
7205
7230
|
symbol,
|
|
7206
7231
|
runtimeConfigId,
|
|
7232
|
+
runtimeReleaseVersion,
|
|
7207
7233
|
timestamp,
|
|
7208
7234
|
lineage
|
|
7209
7235
|
}) => {
|
|
@@ -7216,6 +7242,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7216
7242
|
strategy,
|
|
7217
7243
|
symbol,
|
|
7218
7244
|
...runtimeConfigId ? { runtimeConfigId } : {},
|
|
7245
|
+
...runtimeReleaseVersion ? { runtimeReleaseVersion } : {},
|
|
7219
7246
|
lineage,
|
|
7220
7247
|
firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
|
|
7221
7248
|
lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
|
|
@@ -7226,6 +7253,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7226
7253
|
strategy: signal.strategy,
|
|
7227
7254
|
symbol: signal.symbol,
|
|
7228
7255
|
runtimeConfigId: signal.runtimeConfigId,
|
|
7256
|
+
runtimeReleaseVersion: signal.runtimeReleaseVersion,
|
|
7229
7257
|
timestamp: signal.timestamp,
|
|
7230
7258
|
lineage: signal.runtimeLineage
|
|
7231
7259
|
});
|
|
@@ -7235,6 +7263,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7235
7263
|
strategy: evaluation.strategy,
|
|
7236
7264
|
symbol: evaluation.symbol,
|
|
7237
7265
|
runtimeConfigId: evaluation.runtimeConfigId,
|
|
7266
|
+
runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
|
|
7238
7267
|
timestamp: evaluation.timestamp,
|
|
7239
7268
|
lineage: evaluation.runtimeLineage
|
|
7240
7269
|
});
|
|
@@ -8545,13 +8574,26 @@ var renderLineageRows = (runtimeComparison) => {
|
|
|
8545
8574
|
contexts: /* @__PURE__ */ new Set()
|
|
8546
8575
|
};
|
|
8547
8576
|
existing.scopes += 1;
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8577
|
+
if (record.lineage.schemaVersion === 2) {
|
|
8578
|
+
existing.gitShas.add("release-versioned");
|
|
8579
|
+
existing.dirty.add("n/a");
|
|
8580
|
+
existing.gates.add("release-versioned");
|
|
8581
|
+
existing.configs.add(`v${record.lineage.releaseVersion}`);
|
|
8582
|
+
existing.contexts.add(
|
|
8583
|
+
[
|
|
8584
|
+
record.lineage.strategyPackageVersion ?? "strategy:unknown",
|
|
8585
|
+
record.lineage.runtimePackageVersion ?? "runtime:unknown"
|
|
8586
|
+
].join("/")
|
|
8587
|
+
);
|
|
8588
|
+
} else {
|
|
8589
|
+
existing.gitShas.add(record.lineage.gitSha ?? "unknown");
|
|
8590
|
+
existing.dirty.add(
|
|
8591
|
+
record.lineage.gitDirty == null ? "unknown" : String(record.lineage.gitDirty)
|
|
8592
|
+
);
|
|
8593
|
+
existing.gates.add(record.lineage.gateFingerprint);
|
|
8594
|
+
existing.configs.add(record.lineage.configFingerprint);
|
|
8595
|
+
existing.contexts.add(record.lineage.contextFingerprint);
|
|
8596
|
+
}
|
|
8555
8597
|
grouped.set(record.strategy, existing);
|
|
8556
8598
|
}
|
|
8557
8599
|
const formatSet = (values) => {
|
|
@@ -57,12 +57,12 @@ var import_chalk2 = __toESM(require("chalk"));
|
|
|
57
57
|
var import_node_child_process = require("child_process");
|
|
58
58
|
var import_promises = __toESM(require("fs/promises"));
|
|
59
59
|
var import_node_os = __toESM(require("os"));
|
|
60
|
-
var
|
|
60
|
+
var import_node_path2 = __toESM(require("path"));
|
|
61
61
|
var import_constants = require("@tradejs/core/constants");
|
|
62
62
|
var import_ai = require("@tradejs/infra/ai");
|
|
63
63
|
var import_logger = require("@tradejs/infra/logger");
|
|
64
64
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
65
|
-
var
|
|
65
|
+
var import_registry = require("@tradejs/node/registry");
|
|
66
66
|
|
|
67
67
|
// src/lib/runtimeRedis.ts
|
|
68
68
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -84,6 +84,26 @@ var BACKTEST_CLI_RUNTIME_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
84
84
|
"BACKTEST_ENTRY_DELAY_BARS"
|
|
85
85
|
]);
|
|
86
86
|
|
|
87
|
+
// src/lib/researchRoots.ts
|
|
88
|
+
var import_node_path = __toESM(require("path"));
|
|
89
|
+
var SOURCE_REPOSITORY_ROOT_ENV = "TRADEJS_SOURCE_REPOSITORY_ROOT";
|
|
90
|
+
var firstNonEmpty = (...values) => values.map((value) => String(value || "").trim()).find(Boolean);
|
|
91
|
+
var resolveResearchRoots = (options = {}) => {
|
|
92
|
+
const cwd = import_node_path.default.resolve(options.cwd || process.cwd());
|
|
93
|
+
const env = options.env || process.env;
|
|
94
|
+
const projectRoot2 = import_node_path.default.resolve(
|
|
95
|
+
firstNonEmpty(options.projectRoot, env.PROJECT_CWD, cwd) || cwd
|
|
96
|
+
);
|
|
97
|
+
const sourceRepositoryRoot2 = import_node_path.default.resolve(
|
|
98
|
+
firstNonEmpty(
|
|
99
|
+
options.sourceRepositoryRoot,
|
|
100
|
+
env[SOURCE_REPOSITORY_ROOT_ENV],
|
|
101
|
+
cwd
|
|
102
|
+
) || cwd
|
|
103
|
+
);
|
|
104
|
+
return { projectRoot: projectRoot2, sourceRepositoryRoot: sourceRepositoryRoot2 };
|
|
105
|
+
};
|
|
106
|
+
|
|
87
107
|
// src/lib/telegramReports.ts
|
|
88
108
|
var import_cli = require("@tradejs/node/cli");
|
|
89
109
|
var TELEGRAM_REPORT_CHUNK_LIMIT = 3900;
|
|
@@ -175,11 +195,11 @@ import_args.default.option(["O", "outDir"], "AI export output directory", "data/
|
|
|
175
195
|
import_args.default.option(["A", "skipAgent"], "Skip direct research agent invocation", false);
|
|
176
196
|
import_args.default.option(["j", "json"], "Print structured JSON summary", false);
|
|
177
197
|
var flags = import_args.default.parse(process.argv);
|
|
178
|
-
var projectRoot
|
|
198
|
+
var { projectRoot, sourceRepositoryRoot } = resolveResearchRoots();
|
|
179
199
|
var dotenvPath = String(
|
|
180
|
-
process.env.DOTENV_CONFIG_PATH ||
|
|
181
|
-
).trim() ||
|
|
182
|
-
var getResearchAutoLockPath = (userName) =>
|
|
200
|
+
process.env.DOTENV_CONFIG_PATH || import_node_path2.default.join(projectRoot, ".env")
|
|
201
|
+
).trim() || import_node_path2.default.join(projectRoot, ".env");
|
|
202
|
+
var getResearchAutoLockPath = (userName) => import_node_path2.default.join(
|
|
183
203
|
projectRoot,
|
|
184
204
|
"data",
|
|
185
205
|
"cache",
|
|
@@ -223,7 +243,7 @@ var acquireResearchAutoLock = async ({
|
|
|
223
243
|
startedAt,
|
|
224
244
|
argv: [...process.argv]
|
|
225
245
|
};
|
|
226
|
-
await import_promises.default.mkdir(
|
|
246
|
+
await import_promises.default.mkdir(import_node_path2.default.dirname(lockPath), { recursive: true });
|
|
227
247
|
const writeLock = async () => {
|
|
228
248
|
await import_promises.default.writeFile(lockPath, JSON.stringify(nextLock, null, 2), {
|
|
229
249
|
flag: "wx"
|
|
@@ -360,7 +380,7 @@ var listMergedFiles = async (outDir, strategyName) => {
|
|
|
360
380
|
try {
|
|
361
381
|
const entries = await import_promises.default.readdir(outDir);
|
|
362
382
|
const prefix = `ai-dataset-${(0, import_ai.toFileToken)(strategyName)}-merged-`;
|
|
363
|
-
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) =>
|
|
383
|
+
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) => import_node_path2.default.join(outDir, name));
|
|
364
384
|
} catch {
|
|
365
385
|
return [];
|
|
366
386
|
}
|
|
@@ -480,6 +500,7 @@ var runCliCommand = async (params) => {
|
|
|
480
500
|
const env = {
|
|
481
501
|
...process.env,
|
|
482
502
|
PROJECT_CWD: projectRoot,
|
|
503
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: sourceRepositoryRoot,
|
|
483
504
|
DOTENV_CONFIG_PATH: dotenvPath,
|
|
484
505
|
...params.nodeHeapMb ? {
|
|
485
506
|
NODE_OPTIONS: buildNodeOptions({
|
|
@@ -489,8 +510,8 @@ var runCliCommand = async (params) => {
|
|
|
489
510
|
};
|
|
490
511
|
return new Promise((resolve, reject) => {
|
|
491
512
|
const child = (0, import_node_child_process.spawn)(
|
|
492
|
-
|
|
493
|
-
[
|
|
513
|
+
process.execPath,
|
|
514
|
+
[import_node_path2.default.resolve(process.argv[1]), params.command, ...params.args],
|
|
494
515
|
{
|
|
495
516
|
cwd: projectRoot,
|
|
496
517
|
env,
|
|
@@ -672,8 +693,8 @@ var main = async () => {
|
|
|
672
693
|
const jsonOutput = Boolean(flags.json);
|
|
673
694
|
const skipAgent = Boolean(flags.skipAgent);
|
|
674
695
|
const outDirArg = String(flags.outDir || "data/ai/export").trim() || "data/ai/export";
|
|
675
|
-
const outDir =
|
|
676
|
-
const cleanDirArg =
|
|
696
|
+
const outDir = import_node_path2.default.resolve(projectRoot, outDirArg);
|
|
697
|
+
const cleanDirArg = import_node_path2.default.relative(import_node_path2.default.join(projectRoot, "data"), outDir).replace(/\\/g, "/");
|
|
677
698
|
const target = await resolveTarget();
|
|
678
699
|
const runId = `${Date.now()}-${(0, import_ai.toFileToken)(target.strategy)}`;
|
|
679
700
|
const run = {
|
|
@@ -762,7 +783,7 @@ var main = async () => {
|
|
|
762
783
|
target.strategy
|
|
763
784
|
);
|
|
764
785
|
const backtestConfigKey = import_redis2.redisKeys.backtestConfig(userName, target.config);
|
|
765
|
-
const defaults = (0,
|
|
786
|
+
const defaults = await (0, import_registry.getStrategyDefaults)(target.strategy, projectRoot) || {};
|
|
766
787
|
const userStrategyConfig = await (0, import_redis2.getData)(
|
|
767
788
|
strategyConfigKey,
|
|
768
789
|
{}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/scripts/runtimeConfig.ts
|
|
31
|
+
var runtimeConfig_exports = {};
|
|
32
|
+
__export(runtimeConfig_exports, {
|
|
33
|
+
main: () => main,
|
|
34
|
+
runtimeConfig: () => runtimeConfig
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(runtimeConfig_exports);
|
|
37
|
+
var import_config = require("dotenv/config");
|
|
38
|
+
var import_promises = require("fs/promises");
|
|
39
|
+
var import_node_path = __toESM(require("path"));
|
|
40
|
+
var import_runtimeDeployments = require("@tradejs/infra/runtimeDeployments");
|
|
41
|
+
var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
|
|
42
|
+
var import_runtimeStrategyReleases = require("@tradejs/infra/runtimeStrategyReleases");
|
|
43
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
44
|
+
var import_strategies = require("@tradejs/node/strategies");
|
|
45
|
+
var argv = process.argv.slice(2);
|
|
46
|
+
var action = argv[0] ?? "inspect";
|
|
47
|
+
var option = (name) => {
|
|
48
|
+
const index = argv.indexOf(`--${name}`);
|
|
49
|
+
return index >= 0 ? argv[index + 1] : void 0;
|
|
50
|
+
};
|
|
51
|
+
var hasFlag = (name) => argv.includes(`--${name}`);
|
|
52
|
+
var required = (name) => {
|
|
53
|
+
const value = String(option(name) ?? "").trim();
|
|
54
|
+
if (!value) throw new Error(`--${name} is required`);
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
57
|
+
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
58
|
+
var userName = String(option("user") ?? process.env.USER_NAME ?? "root");
|
|
59
|
+
var OPERATIONAL_CONFIG_KEYS = [
|
|
60
|
+
"ACCOUNT_ID",
|
|
61
|
+
"AI_REPLAY_ANALYSES",
|
|
62
|
+
"DEPLOYMENT_ID",
|
|
63
|
+
"ENABLE",
|
|
64
|
+
"ENV",
|
|
65
|
+
"MAKE_ORDERS",
|
|
66
|
+
"RECORD_RUNTIME_TRADES",
|
|
67
|
+
"configId"
|
|
68
|
+
];
|
|
69
|
+
var toReleaseConfig = async (strategyName, sourceConfig) => {
|
|
70
|
+
const defaults = await (0, import_strategies.getStrategyDefaults)(strategyName, projectRoot) ?? {};
|
|
71
|
+
const config = { ...defaults, ...sourceConfig };
|
|
72
|
+
for (const key of OPERATIONAL_CONFIG_KEYS) delete config[key];
|
|
73
|
+
return config;
|
|
74
|
+
};
|
|
75
|
+
var writeMigrationBackup = async (payload) => {
|
|
76
|
+
const directory = import_node_path.default.join(projectRoot, "data", "runtime-config-backups");
|
|
77
|
+
await (0, import_promises.mkdir)(directory, { recursive: true });
|
|
78
|
+
const backupPath = import_node_path.default.join(
|
|
79
|
+
directory,
|
|
80
|
+
`${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`
|
|
81
|
+
);
|
|
82
|
+
await (0, import_promises.writeFile)(backupPath, `${JSON.stringify(payload, null, 2)}
|
|
83
|
+
`, {
|
|
84
|
+
flag: "wx"
|
|
85
|
+
});
|
|
86
|
+
return backupPath;
|
|
87
|
+
};
|
|
88
|
+
var publish = async ({
|
|
89
|
+
strategyName,
|
|
90
|
+
sourceConfig
|
|
91
|
+
}) => {
|
|
92
|
+
const config = await toReleaseConfig(strategyName, sourceConfig);
|
|
93
|
+
const metadata = await (0, import_runtimeStrategies.getRuntimeStrategyPackageMetadata)({
|
|
94
|
+
strategyName,
|
|
95
|
+
projectRoot
|
|
96
|
+
});
|
|
97
|
+
return (0, import_runtimeStrategyReleases.publishRuntimeStrategyRelease)({
|
|
98
|
+
userName,
|
|
99
|
+
strategyName,
|
|
100
|
+
config,
|
|
101
|
+
...metadata,
|
|
102
|
+
createdBy: `cli:${userName}`
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
var migrate = async () => {
|
|
106
|
+
const strategyName = required("strategy");
|
|
107
|
+
const configId = option("config") ?? "config";
|
|
108
|
+
const deploymentId = required("deployment");
|
|
109
|
+
const [sourceConfig, deployment] = await Promise.all([
|
|
110
|
+
(0, import_runtimeStrategyConfigs.getRuntimeStrategyConfig)(userName, strategyName, configId),
|
|
111
|
+
(0, import_runtimeDeployments.getRuntimeDeployment)(userName, deploymentId)
|
|
112
|
+
]);
|
|
113
|
+
if (!sourceConfig) {
|
|
114
|
+
throw new Error(`Legacy config not found: ${strategyName}:${configId}`);
|
|
115
|
+
}
|
|
116
|
+
if (!deployment) throw new Error(`Deployment not found: ${deploymentId}`);
|
|
117
|
+
const reference = deployment.strategies.find(
|
|
118
|
+
(strategy) => strategy.strategyName === strategyName
|
|
119
|
+
);
|
|
120
|
+
if (!reference) {
|
|
121
|
+
throw new Error(`${strategyName} is not bound to ${deploymentId}`);
|
|
122
|
+
}
|
|
123
|
+
const preview = {
|
|
124
|
+
source: { configId, config: sourceConfig },
|
|
125
|
+
releaseConfig: await toReleaseConfig(strategyName, sourceConfig),
|
|
126
|
+
deployment: {
|
|
127
|
+
id: deployment.id,
|
|
128
|
+
accountId: deployment.accountId,
|
|
129
|
+
strategy: {
|
|
130
|
+
strategyName,
|
|
131
|
+
releaseVersion: "<allocated on write>",
|
|
132
|
+
controlState: "entries_paused"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
if (!hasFlag("write")) {
|
|
137
|
+
console.log(JSON.stringify({ dryRun: true, ...preview }, null, 2));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const backupPath = await writeMigrationBackup({
|
|
141
|
+
userName,
|
|
142
|
+
capturedAt: Date.now(),
|
|
143
|
+
deployment,
|
|
144
|
+
legacyConfig: sourceConfig
|
|
145
|
+
});
|
|
146
|
+
const release = await publish({ strategyName, sourceConfig });
|
|
147
|
+
const updatedDeployment = {
|
|
148
|
+
...deployment,
|
|
149
|
+
strategies: deployment.strategies.map(
|
|
150
|
+
(strategy) => strategy.strategyName === strategyName ? {
|
|
151
|
+
strategyName,
|
|
152
|
+
releaseVersion: release.releaseVersion,
|
|
153
|
+
controlState: "entries_paused"
|
|
154
|
+
} : strategy
|
|
155
|
+
)
|
|
156
|
+
};
|
|
157
|
+
await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, updatedDeployment);
|
|
158
|
+
console.log(
|
|
159
|
+
JSON.stringify(
|
|
160
|
+
{ migrated: true, backupPath, release, deployment: updatedDeployment },
|
|
161
|
+
null,
|
|
162
|
+
2
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
var publishDraft = async () => {
|
|
167
|
+
const strategyName = required("strategy");
|
|
168
|
+
const draft = await (0, import_runtimeStrategyReleases.getRuntimeStrategyDraft)(userName, strategyName);
|
|
169
|
+
if (!draft) throw new Error(`Draft not found: ${strategyName}`);
|
|
170
|
+
const release = await publish({ strategyName, sourceConfig: draft.config });
|
|
171
|
+
console.log(JSON.stringify({ release }, null, 2));
|
|
172
|
+
};
|
|
173
|
+
var updateControlState = async (nextState) => {
|
|
174
|
+
const strategyName = required("strategy");
|
|
175
|
+
const deploymentId = required("deployment");
|
|
176
|
+
const deployment = await (0, import_runtimeDeployments.getRuntimeDeployment)(userName, deploymentId);
|
|
177
|
+
if (!deployment) throw new Error(`Deployment not found: ${deploymentId}`);
|
|
178
|
+
const reference = deployment.strategies.find(
|
|
179
|
+
(strategy) => strategy.strategyName === strategyName
|
|
180
|
+
);
|
|
181
|
+
if (!reference?.releaseVersion) {
|
|
182
|
+
throw new Error(`${strategyName} is not a versioned deployment reference`);
|
|
183
|
+
}
|
|
184
|
+
const previousState = reference.controlState ?? "active";
|
|
185
|
+
const updated = await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, {
|
|
186
|
+
...deployment,
|
|
187
|
+
strategies: deployment.strategies.map(
|
|
188
|
+
(strategy) => strategy.strategyName === strategyName ? { ...strategy, controlState: nextState } : strategy
|
|
189
|
+
)
|
|
190
|
+
});
|
|
191
|
+
const event = previousState === nextState ? null : await (0, import_runtimeStrategyReleases.recordRuntimeStrategyControlEvent)({
|
|
192
|
+
userName,
|
|
193
|
+
deploymentId,
|
|
194
|
+
strategyName,
|
|
195
|
+
releaseVersion: reference.releaseVersion,
|
|
196
|
+
previousState,
|
|
197
|
+
nextState,
|
|
198
|
+
createdBy: `cli:${userName}`
|
|
199
|
+
});
|
|
200
|
+
console.log(JSON.stringify({ deployment: updated, event }, null, 2));
|
|
201
|
+
};
|
|
202
|
+
var rollback = async () => {
|
|
203
|
+
const strategyName = required("strategy");
|
|
204
|
+
const deploymentId = required("deployment");
|
|
205
|
+
const releaseVersion = Number(required("release"));
|
|
206
|
+
if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
|
|
207
|
+
throw new Error("--release must be a positive integer");
|
|
208
|
+
}
|
|
209
|
+
const deployment = await (0, import_runtimeDeployments.getRuntimeDeployment)(userName, deploymentId);
|
|
210
|
+
if (!deployment) throw new Error(`Deployment not found: ${deploymentId}`);
|
|
211
|
+
const release = (await (0, import_runtimeStrategyReleases.listRuntimeStrategyReleases)(userName, strategyName)).find((candidate) => candidate.releaseVersion === releaseVersion);
|
|
212
|
+
if (!release)
|
|
213
|
+
throw new Error(`Release not found: ${strategyName} v${releaseVersion}`);
|
|
214
|
+
const backupPath = await writeMigrationBackup({
|
|
215
|
+
userName,
|
|
216
|
+
capturedAt: Date.now(),
|
|
217
|
+
deployment,
|
|
218
|
+
reason: "rollback"
|
|
219
|
+
});
|
|
220
|
+
const updated = await (0, import_runtimeDeployments.saveRuntimeDeployment)(userName, {
|
|
221
|
+
...deployment,
|
|
222
|
+
strategies: deployment.strategies.map(
|
|
223
|
+
(strategy) => strategy.strategyName === strategyName ? {
|
|
224
|
+
strategyName,
|
|
225
|
+
releaseVersion,
|
|
226
|
+
controlState: "entries_paused"
|
|
227
|
+
} : strategy
|
|
228
|
+
)
|
|
229
|
+
});
|
|
230
|
+
console.log(JSON.stringify({ backupPath, deployment: updated }, null, 2));
|
|
231
|
+
};
|
|
232
|
+
var verify = async () => {
|
|
233
|
+
const deployments = await (0, import_runtimeDeployments.listRuntimeDeployments)(userName);
|
|
234
|
+
const selected = option("deployment") ? deployments.filter((deployment) => deployment.id === option("deployment")) : deployments;
|
|
235
|
+
const results = [];
|
|
236
|
+
for (const deployment of selected) {
|
|
237
|
+
try {
|
|
238
|
+
const strategies = await (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({
|
|
239
|
+
userName,
|
|
240
|
+
projectRoot,
|
|
241
|
+
deployment,
|
|
242
|
+
connectorName: deployment.connectorName
|
|
243
|
+
});
|
|
244
|
+
results.push({
|
|
245
|
+
deploymentId: deployment.id,
|
|
246
|
+
ok: true,
|
|
247
|
+
strategies: strategies.map((strategy) => ({
|
|
248
|
+
strategyName: strategy.strategyName,
|
|
249
|
+
releaseVersion: strategy.releaseVersion,
|
|
250
|
+
controlState: strategy.controlState,
|
|
251
|
+
interval: strategy.interval,
|
|
252
|
+
universe: strategy.universe,
|
|
253
|
+
accountId: strategy.accountId
|
|
254
|
+
}))
|
|
255
|
+
});
|
|
256
|
+
} catch (error) {
|
|
257
|
+
results.push({
|
|
258
|
+
deploymentId: deployment.id,
|
|
259
|
+
ok: false,
|
|
260
|
+
error: error instanceof Error ? error.message : String(error)
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
console.log(JSON.stringify({ userName, results }, null, 2));
|
|
265
|
+
if (results.some((result) => !result.ok)) process.exitCode = 1;
|
|
266
|
+
};
|
|
267
|
+
var inspect = async () => {
|
|
268
|
+
const strategyName = option("strategy");
|
|
269
|
+
const deployments = await (0, import_runtimeDeployments.listRuntimeDeployments)(userName);
|
|
270
|
+
const releases = strategyName ? await (0, import_runtimeStrategyReleases.listRuntimeStrategyReleases)(userName, strategyName) : void 0;
|
|
271
|
+
console.log(JSON.stringify({ userName, deployments, releases }, null, 2));
|
|
272
|
+
};
|
|
273
|
+
var runtimeConfig = async () => {
|
|
274
|
+
if (action === "migrate") return migrate();
|
|
275
|
+
if (action === "publish-draft") return publishDraft();
|
|
276
|
+
if (action === "verify") return verify();
|
|
277
|
+
if (action === "pause") return updateControlState("entries_paused");
|
|
278
|
+
if (action === "resume") return updateControlState("active");
|
|
279
|
+
if (action === "rollback") return rollback();
|
|
280
|
+
if (action === "inspect") return inspect();
|
|
281
|
+
throw new Error(
|
|
282
|
+
"Usage: tradejs runtime-config inspect|verify|migrate|publish-draft|pause|resume|rollback"
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
var main = runtimeConfig;
|
|
286
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
287
|
+
0 && (module.exports = {
|
|
288
|
+
main,
|
|
289
|
+
runtimeConfig
|
|
290
|
+
});
|
|
@@ -568,11 +568,12 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
|
|
|
568
568
|
|
|
569
569
|
// src/lib/strategyGateFingerprint.ts
|
|
570
570
|
var import_node_crypto2 = require("crypto");
|
|
571
|
+
var import_node_module = require("module");
|
|
571
572
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
572
573
|
var import_node_path2 = __toESM(require("path"));
|
|
573
574
|
|
|
574
575
|
// src/lib/runtimeLineage.ts
|
|
575
|
-
var runtimeLineageKey = (lineage) => [
|
|
576
|
+
var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
|
|
576
577
|
lineage.schemaVersion,
|
|
577
578
|
lineage.compositionId ?? "unbound-composition",
|
|
578
579
|
lineage.gitSha ?? "unknown",
|
|
@@ -4808,7 +4808,7 @@ var buildRuntimeModeStrategyConfig = ({
|
|
|
4808
4808
|
...strategyConfig,
|
|
4809
4809
|
ENV: env,
|
|
4810
4810
|
MAKE_ORDERS: makeOrders,
|
|
4811
|
-
INTERVAL: interval2,
|
|
4811
|
+
INTERVAL: strategyConfig.INTERVAL ?? interval2,
|
|
4812
4812
|
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
4813
4813
|
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
4814
4814
|
});
|