@tradejs/cli 3.1.21-beta.237 → 3.1.22-beta.238
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 +1643 -806
- package/dist/lib/runtimeEvidenceProducer.js +98 -0
- package/dist/lib/runtimeEvidenceSync.js +8 -3
- package/dist/lib/runtimeFeedbackArtifacts.js +566 -0
- package/dist/lib/runtimeFeedbackReplay.js +808 -0
- package/dist/lib/runtimeFeedbackSync.js +350 -0
- package/dist/scripts/replay.js +9 -6
- package/dist/scripts/replayRunner.js +9 -6
- package/dist/scripts/replayRuntimeEvidence.js +4 -0
- package/dist/scripts/runtimeEvidence.js +62 -7
- package/dist/scripts/runtimeFeedbackReplay.js +850 -0
- package/dist/scripts/runtimeFeedbackSync.js +411 -0
- package/dist/scripts/runtimeScorecard.js +217 -39
- package/package.json +9 -7
package/dist/cli.js
CHANGED
|
@@ -255,7 +255,7 @@ var init_researchRoots = __esm({
|
|
|
255
255
|
resolveResearchRoots = (options = {}) => {
|
|
256
256
|
const cwd = import_node_path.default.resolve(options.cwd || process.cwd());
|
|
257
257
|
const env = options.env || process.env;
|
|
258
|
-
const
|
|
258
|
+
const projectRoot17 = import_node_path.default.resolve(
|
|
259
259
|
firstNonEmpty(options.projectRoot, env.PROJECT_CWD, cwd) || cwd
|
|
260
260
|
);
|
|
261
261
|
const sourceRepositoryRoot = firstNonEmpty(
|
|
@@ -263,7 +263,7 @@ var init_researchRoots = __esm({
|
|
|
263
263
|
env[SOURCE_REPOSITORY_ROOT_ENV]
|
|
264
264
|
);
|
|
265
265
|
return {
|
|
266
|
-
projectRoot:
|
|
266
|
+
projectRoot: projectRoot17,
|
|
267
267
|
...sourceRepositoryRoot ? { sourceRepositoryRoot: import_node_path.default.resolve(sourceRepositoryRoot) } : {}
|
|
268
268
|
};
|
|
269
269
|
};
|
|
@@ -1943,32 +1943,32 @@ var init_commandOptions = __esm({
|
|
|
1943
1943
|
(arg) => arg === `--${longName}` || arg.startsWith(`--${longName}=`) || (shortName ? arg === `-${shortName}` : false)
|
|
1944
1944
|
);
|
|
1945
1945
|
resolveAiPocketSearchCommandOptions = ({
|
|
1946
|
-
flags:
|
|
1946
|
+
flags: flags34,
|
|
1947
1947
|
argv: argv2
|
|
1948
1948
|
}) => {
|
|
1949
|
-
const outDir = String(
|
|
1950
|
-
const strategyName = String(
|
|
1951
|
-
const explicitFile = String(
|
|
1952
|
-
const skip = normalizeInt(
|
|
1953
|
-
const minQuality = normalizeInt(
|
|
1954
|
-
const sinceInput = parseTimestampFilter(
|
|
1955
|
-
const untilTimestamp = parseTimestampFilter(
|
|
1956
|
-
const trailingPeriodMs = parseTrailingPeriodMs(
|
|
1957
|
-
const periodLabel = String(
|
|
1949
|
+
const outDir = String(flags34.outDir || "data/ai/export");
|
|
1950
|
+
const strategyName = String(flags34.strategy || "").trim() || void 0;
|
|
1951
|
+
const explicitFile = String(flags34.file || "").trim();
|
|
1952
|
+
const skip = normalizeInt(flags34.skip, 0);
|
|
1953
|
+
const minQuality = normalizeInt(flags34.minQuality, 4);
|
|
1954
|
+
const sinceInput = parseTimestampFilter(flags34.since);
|
|
1955
|
+
const untilTimestamp = parseTimestampFilter(flags34.until);
|
|
1956
|
+
const trailingPeriodMs = parseTrailingPeriodMs(flags34.period);
|
|
1957
|
+
const periodLabel = String(flags34.period || "").trim() || null;
|
|
1958
1958
|
const hasDateFilter = trailingPeriodMs != null || sinceInput != null || untilTimestamp != null;
|
|
1959
1959
|
const recent = resolveAiTrainRecentLimit({
|
|
1960
1960
|
argv: argv2,
|
|
1961
|
-
recentValue:
|
|
1961
|
+
recentValue: flags34.recent,
|
|
1962
1962
|
hasDateFilter
|
|
1963
1963
|
});
|
|
1964
|
-
const qualityThresholds = parseQualityThresholds(
|
|
1965
|
-
const scope = String(
|
|
1964
|
+
const qualityThresholds = parseQualityThresholds(flags34.qualityThresholds);
|
|
1965
|
+
const scope = String(flags34.scope || "all").trim().toLowerCase();
|
|
1966
1966
|
if (!["all", "approved", "rejected", "candidates"].includes(scope)) {
|
|
1967
1967
|
throw new Error(
|
|
1968
1968
|
`Unsupported --scope "${scope}". Use all, approved, rejected, or candidates.`
|
|
1969
1969
|
);
|
|
1970
1970
|
}
|
|
1971
|
-
const direction = String(
|
|
1971
|
+
const direction = String(flags34.direction || "").trim().toUpperCase();
|
|
1972
1972
|
if (direction && !["LONG", "SHORT"].includes(direction)) {
|
|
1973
1973
|
throw new Error(
|
|
1974
1974
|
`Unsupported --direction "${direction}". Use LONG or SHORT.`
|
|
@@ -1979,14 +1979,14 @@ var init_commandOptions = __esm({
|
|
|
1979
1979
|
"maxEventCountShare",
|
|
1980
1980
|
"U"
|
|
1981
1981
|
);
|
|
1982
|
-
const maxDepth = normalizePositiveInt(
|
|
1983
|
-
const explicitMinSupport = hasCliOption2(argv2, "minSupport", "m") ? normalizePositiveInt(
|
|
1982
|
+
const maxDepth = normalizePositiveInt(flags34.maxDepth, 2);
|
|
1983
|
+
const explicitMinSupport = hasCliOption2(argv2, "minSupport", "m") ? normalizePositiveInt(flags34.minSupport, 20) : void 0;
|
|
1984
1984
|
const minProfitFactor = normalizeNonNegativeNumber(
|
|
1985
1985
|
readAiPocketSearchCliOption({
|
|
1986
1986
|
argv: argv2,
|
|
1987
1987
|
longName: "minProfitFactor",
|
|
1988
1988
|
shortName: "F"
|
|
1989
|
-
}) ??
|
|
1989
|
+
}) ?? flags34.minProfitFactor,
|
|
1990
1990
|
1.2
|
|
1991
1991
|
);
|
|
1992
1992
|
const minWinRate = normalizeNonNegativeNumber(
|
|
@@ -1994,21 +1994,21 @@ var init_commandOptions = __esm({
|
|
|
1994
1994
|
argv: argv2,
|
|
1995
1995
|
longName: "minWinRate",
|
|
1996
1996
|
shortName: "W"
|
|
1997
|
-
}) ??
|
|
1997
|
+
}) ?? flags34.minWinRate,
|
|
1998
1998
|
0
|
|
1999
1999
|
);
|
|
2000
2000
|
const minTotalProfitValue = readAiPocketSearchCliOption({
|
|
2001
2001
|
argv: argv2,
|
|
2002
2002
|
longName: "minTotalProfit",
|
|
2003
2003
|
shortName: "R"
|
|
2004
|
-
}) ??
|
|
2004
|
+
}) ?? flags34.minTotalProfit;
|
|
2005
2005
|
const minTotalProfit = Number.isFinite(Number(minTotalProfitValue)) ? Number(minTotalProfitValue) : 0;
|
|
2006
2006
|
const validationSplit = hasCliOption2(argv2, "validationSplit", "V") ? normalizeRatio(
|
|
2007
2007
|
readAiPocketSearchCliOption({
|
|
2008
2008
|
argv: argv2,
|
|
2009
2009
|
longName: "validationSplit",
|
|
2010
2010
|
shortName: "V"
|
|
2011
|
-
}) ??
|
|
2011
|
+
}) ?? flags34.validationSplit,
|
|
2012
2012
|
0.25
|
|
2013
2013
|
) : 0.25;
|
|
2014
2014
|
const testSplit = hasCliOption2(argv2, "testSplit", "T") ? normalizeRatio(
|
|
@@ -2016,10 +2016,10 @@ var init_commandOptions = __esm({
|
|
|
2016
2016
|
argv: argv2,
|
|
2017
2017
|
longName: "testSplit",
|
|
2018
2018
|
shortName: "T"
|
|
2019
|
-
}) ??
|
|
2019
|
+
}) ?? flags34.testSplit,
|
|
2020
2020
|
0
|
|
2021
2021
|
) : 0;
|
|
2022
|
-
const sealTest = Boolean(
|
|
2022
|
+
const sealTest = Boolean(flags34.sealTest);
|
|
2023
2023
|
if (sealTest && testSplit <= 0) {
|
|
2024
2024
|
throw new Error("--sealTest requires a positive --testSplit");
|
|
2025
2025
|
}
|
|
@@ -2028,7 +2028,7 @@ var init_commandOptions = __esm({
|
|
|
2028
2028
|
argv: argv2,
|
|
2029
2029
|
longName: "maxEventCountShare",
|
|
2030
2030
|
shortName: "U"
|
|
2031
|
-
}) ??
|
|
2031
|
+
}) ?? flags34.maxEventCountShare,
|
|
2032
2032
|
0.25
|
|
2033
2033
|
);
|
|
2034
2034
|
const maxSymbolCountShare = normalizeUnitRatio(
|
|
@@ -2036,10 +2036,10 @@ var init_commandOptions = __esm({
|
|
|
2036
2036
|
argv: argv2,
|
|
2037
2037
|
longName: "maxSymbolCountShare",
|
|
2038
2038
|
shortName: "Z"
|
|
2039
|
-
}) ??
|
|
2039
|
+
}) ?? flags34.maxSymbolCountShare,
|
|
2040
2040
|
0.5
|
|
2041
2041
|
);
|
|
2042
|
-
const objective = normalizeObjective(
|
|
2042
|
+
const objective = normalizeObjective(flags34.objective, scope);
|
|
2043
2043
|
return {
|
|
2044
2044
|
outDir,
|
|
2045
2045
|
strategyName,
|
|
@@ -2059,33 +2059,33 @@ var init_commandOptions = __esm({
|
|
|
2059
2059
|
minProfitFactor,
|
|
2060
2060
|
minWinRate,
|
|
2061
2061
|
minTotalProfit,
|
|
2062
|
-
maxAtomicPredicates: normalizePositiveInt(
|
|
2063
|
-
maxCombinations: normalizePositiveInt(
|
|
2062
|
+
maxAtomicPredicates: normalizePositiveInt(flags34.maxAtomicPredicates, 180),
|
|
2063
|
+
maxCombinations: normalizePositiveInt(flags34.maxCombinations, 6e4),
|
|
2064
2064
|
validationSplit,
|
|
2065
2065
|
testSplit,
|
|
2066
2066
|
sealTest,
|
|
2067
|
-
explicitMinValidationSupport: normalizeInt(
|
|
2068
|
-
explicitMinEvents: normalizeInt(
|
|
2069
|
-
explicitMinValidationEvents: normalizeInt(
|
|
2070
|
-
maxBatch: normalizeInt(
|
|
2067
|
+
explicitMinValidationSupport: normalizeInt(flags34.minValidationSupport, 0),
|
|
2068
|
+
explicitMinEvents: normalizeInt(flags34.minEvents, 0),
|
|
2069
|
+
explicitMinValidationEvents: normalizeInt(flags34.minValidationEvents, 0),
|
|
2070
|
+
maxBatch: normalizeInt(flags34.maxBatch, 5),
|
|
2071
2071
|
maxEventCountShare,
|
|
2072
2072
|
explicitMaxEventCountShare,
|
|
2073
2073
|
maxSymbolCountShare,
|
|
2074
2074
|
objective,
|
|
2075
|
-
allowRiskRegression: Boolean(
|
|
2076
|
-
requireValidationEligibility: !Boolean(
|
|
2077
|
-
dedupeEquivalentSelections: Boolean(
|
|
2078
|
-
top: normalizePositiveInt(
|
|
2079
|
-
includeSymbol: Boolean(
|
|
2080
|
-
includeGateContext: Boolean(
|
|
2081
|
-
featureProfile: normalizeFeatureProfile(
|
|
2082
|
-
featurePolicy: normalizeFeaturePolicy(
|
|
2083
|
-
coverageMode: normalizeCoverageMode(
|
|
2084
|
-
cadenceMode: normalizeCadenceMode(
|
|
2085
|
-
jsonOutput: Boolean(
|
|
2086
|
-
outputPath: String(
|
|
2087
|
-
reportDir: String(
|
|
2088
|
-
explicitReportFile: String(
|
|
2075
|
+
allowRiskRegression: Boolean(flags34.allowRiskRegression),
|
|
2076
|
+
requireValidationEligibility: !Boolean(flags34.allowValidationRegression),
|
|
2077
|
+
dedupeEquivalentSelections: Boolean(flags34.dedupeEquivalentSelections),
|
|
2078
|
+
top: normalizePositiveInt(flags34.top, 30),
|
|
2079
|
+
includeSymbol: Boolean(flags34.includeSymbol),
|
|
2080
|
+
includeGateContext: Boolean(flags34.includeGateContext),
|
|
2081
|
+
featureProfile: normalizeFeatureProfile(flags34.featureProfile),
|
|
2082
|
+
featurePolicy: normalizeFeaturePolicy(flags34.featurePolicy),
|
|
2083
|
+
coverageMode: normalizeCoverageMode(flags34.coverageMode),
|
|
2084
|
+
cadenceMode: normalizeCadenceMode(flags34.cadenceMode),
|
|
2085
|
+
jsonOutput: Boolean(flags34.json),
|
|
2086
|
+
outputPath: String(flags34.output || "").trim(),
|
|
2087
|
+
reportDir: String(flags34.reportDir || "data/ai/output").trim(),
|
|
2088
|
+
explicitReportFile: String(flags34.reportFile || "").trim()
|
|
2089
2089
|
};
|
|
2090
2090
|
};
|
|
2091
2091
|
}
|
|
@@ -2185,9 +2185,9 @@ var init_features = __esm({
|
|
|
2185
2185
|
"targetsymbol",
|
|
2186
2186
|
"universe"
|
|
2187
2187
|
]);
|
|
2188
|
-
normalizeFeaturePath = (
|
|
2189
|
-
classifyAiPocketCoverageFeaturePath = (
|
|
2190
|
-
const segments = normalizeFeaturePath(
|
|
2188
|
+
normalizeFeaturePath = (path41) => (Array.isArray(path41) ? path41 : path41.split(".")).filter(Boolean).map((segment) => segment.toLowerCase());
|
|
2189
|
+
classifyAiPocketCoverageFeaturePath = (path41) => {
|
|
2190
|
+
const segments = normalizeFeaturePath(path41);
|
|
2191
2191
|
const normalizedPath = segments.join(".");
|
|
2192
2192
|
if (segments.some(
|
|
2193
2193
|
(segment) => segment.includes("cmc") || segment.includes("coinmarketcap")
|
|
@@ -2361,8 +2361,8 @@ var init_features = __esm({
|
|
|
2361
2361
|
"volumeusd",
|
|
2362
2362
|
"vwap"
|
|
2363
2363
|
]);
|
|
2364
|
-
classifyAiPocketFeaturePath = (
|
|
2365
|
-
const segments = (Array.isArray(
|
|
2364
|
+
classifyAiPocketFeaturePath = (path41) => {
|
|
2365
|
+
const segments = (Array.isArray(path41) ? path41 : path41.split(".")).filter(
|
|
2366
2366
|
Boolean
|
|
2367
2367
|
);
|
|
2368
2368
|
const normalized = segments.map((segment) => segment.toLowerCase());
|
|
@@ -5988,10 +5988,10 @@ var init_command = __esm({
|
|
|
5988
5988
|
init_dataset();
|
|
5989
5989
|
init_research();
|
|
5990
5990
|
runAiPocketSearchCommand = async ({
|
|
5991
|
-
flags:
|
|
5991
|
+
flags: flags34
|
|
5992
5992
|
}) => {
|
|
5993
5993
|
const options = resolveAiPocketSearchCommandOptions({
|
|
5994
|
-
flags:
|
|
5994
|
+
flags: flags34,
|
|
5995
5995
|
argv: process.argv
|
|
5996
5996
|
});
|
|
5997
5997
|
const {
|
|
@@ -6896,11 +6896,11 @@ var init_strategyGateFingerprint = __esm({
|
|
|
6896
6896
|
"@tradejs/core/strategies"
|
|
6897
6897
|
];
|
|
6898
6898
|
resolveStrategyGateFingerprint = async ({
|
|
6899
|
-
projectRoot:
|
|
6899
|
+
projectRoot: projectRoot17,
|
|
6900
6900
|
strategyName,
|
|
6901
6901
|
gitSha
|
|
6902
6902
|
}) => {
|
|
6903
|
-
const projectManifestPath = import_node_path3.default.join(
|
|
6903
|
+
const projectManifestPath = import_node_path3.default.join(projectRoot17, "package.json");
|
|
6904
6904
|
const projectExists = await import_promises6.default.access(projectManifestPath).then(() => true).catch(() => false);
|
|
6905
6905
|
const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
|
|
6906
6906
|
const candidates = requireFromProject ? await Promise.all(
|
|
@@ -7079,10 +7079,10 @@ var init_aiTrainResearch = __esm({
|
|
|
7079
7079
|
};
|
|
7080
7080
|
});
|
|
7081
7081
|
};
|
|
7082
|
-
getGitLineage = (
|
|
7082
|
+
getGitLineage = (projectRoot17) => {
|
|
7083
7083
|
try {
|
|
7084
7084
|
const gitSha = (0, import_node_child_process2.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
7085
|
-
cwd:
|
|
7085
|
+
cwd: projectRoot17,
|
|
7086
7086
|
encoding: "utf8",
|
|
7087
7087
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7088
7088
|
}).trim();
|
|
@@ -7090,7 +7090,7 @@ var init_aiTrainResearch = __esm({
|
|
|
7090
7090
|
"git",
|
|
7091
7091
|
["status", "--porcelain", "--untracked-files=no"],
|
|
7092
7092
|
{
|
|
7093
|
-
cwd:
|
|
7093
|
+
cwd: projectRoot17,
|
|
7094
7094
|
encoding: "utf8",
|
|
7095
7095
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7096
7096
|
}
|
|
@@ -7101,16 +7101,16 @@ var init_aiTrainResearch = __esm({
|
|
|
7101
7101
|
}
|
|
7102
7102
|
};
|
|
7103
7103
|
buildAiTrainLineage = async ({
|
|
7104
|
-
projectRoot:
|
|
7104
|
+
projectRoot: projectRoot17,
|
|
7105
7105
|
strategyName,
|
|
7106
7106
|
configIds,
|
|
7107
7107
|
runContext,
|
|
7108
7108
|
sourceSha256s = [],
|
|
7109
7109
|
env = process.env
|
|
7110
7110
|
}) => {
|
|
7111
|
-
const { gitSha, gitDirty } = getGitLineage(
|
|
7111
|
+
const { gitSha, gitDirty } = getGitLineage(projectRoot17);
|
|
7112
7112
|
const gate = await resolveStrategyGateFingerprint({
|
|
7113
|
-
projectRoot:
|
|
7113
|
+
projectRoot: projectRoot17,
|
|
7114
7114
|
strategyName,
|
|
7115
7115
|
gitSha
|
|
7116
7116
|
});
|
|
@@ -9141,12 +9141,12 @@ var init_binanceMarketContextBackfill = __esm({
|
|
|
9141
9141
|
return rows;
|
|
9142
9142
|
};
|
|
9143
9143
|
getBinanceConnector = async ({
|
|
9144
|
-
projectRoot:
|
|
9144
|
+
projectRoot: projectRoot17,
|
|
9145
9145
|
userName: userName3
|
|
9146
9146
|
}) => {
|
|
9147
9147
|
const creator = await (0, import_connectors2.getConnectorCreatorByName)(
|
|
9148
9148
|
import_connectors.ConnectorNames.Binance,
|
|
9149
|
-
|
|
9149
|
+
projectRoot17
|
|
9150
9150
|
);
|
|
9151
9151
|
if (!creator) {
|
|
9152
9152
|
throw new Error(
|
|
@@ -10693,27 +10693,27 @@ var init_coinMarketCapContextBackfill = __esm({
|
|
|
10693
10693
|
totalCredits: 0,
|
|
10694
10694
|
byPath: /* @__PURE__ */ new Map()
|
|
10695
10695
|
});
|
|
10696
|
-
getCoinMarketCapPathLabel = (
|
|
10697
|
-
if (
|
|
10698
|
-
if (
|
|
10699
|
-
if (
|
|
10700
|
-
if (
|
|
10701
|
-
if (
|
|
10702
|
-
if (
|
|
10703
|
-
return
|
|
10704
|
-
};
|
|
10705
|
-
recordCoinMarketCapFetchStats = (stats,
|
|
10696
|
+
getCoinMarketCapPathLabel = (path41) => {
|
|
10697
|
+
if (path41.includes("global-metrics")) return "global";
|
|
10698
|
+
if (path41.includes("cryptocurrency/quotes")) return "reference";
|
|
10699
|
+
if (path41.includes("exchange/quotes")) return "exchangeLiquidity";
|
|
10700
|
+
if (path41.includes("fear-and-greed")) return "fearGreed";
|
|
10701
|
+
if (path41.includes("cmc100")) return "cmc100";
|
|
10702
|
+
if (path41.includes("cmc20")) return "cmc20";
|
|
10703
|
+
return path41;
|
|
10704
|
+
};
|
|
10705
|
+
recordCoinMarketCapFetchStats = (stats, path41, creditCount) => {
|
|
10706
10706
|
if (!stats) return;
|
|
10707
|
-
const existing = stats.byPath.get(
|
|
10707
|
+
const existing = stats.byPath.get(path41) ?? { requests: 0, credits: 0 };
|
|
10708
10708
|
existing.requests += 1;
|
|
10709
10709
|
existing.credits += creditCount ?? 0;
|
|
10710
10710
|
stats.requests += 1;
|
|
10711
10711
|
stats.totalCredits += creditCount ?? 0;
|
|
10712
|
-
stats.byPath.set(
|
|
10712
|
+
stats.byPath.set(path41, existing);
|
|
10713
10713
|
};
|
|
10714
10714
|
formatCoinMarketCapFetchStats = (stats) => {
|
|
10715
10715
|
const byPath = [...stats.byPath.entries()].map(
|
|
10716
|
-
([
|
|
10716
|
+
([path41, item]) => `${getCoinMarketCapPathLabel(path41)}=${item.requests}req/${item.credits}cr`
|
|
10717
10717
|
).join(" ");
|
|
10718
10718
|
return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
|
|
10719
10719
|
};
|
|
@@ -12471,7 +12471,7 @@ var init_historyPrepare = __esm({
|
|
|
12471
12471
|
connectorName,
|
|
12472
12472
|
marketConnector,
|
|
12473
12473
|
userName: userName3,
|
|
12474
|
-
projectRoot:
|
|
12474
|
+
projectRoot: projectRoot17,
|
|
12475
12475
|
shouldUseDedicatedReferences,
|
|
12476
12476
|
requireDedicatedReferences = false,
|
|
12477
12477
|
warn
|
|
@@ -12483,8 +12483,8 @@ var init_historyPrepare = __esm({
|
|
|
12483
12483
|
};
|
|
12484
12484
|
}
|
|
12485
12485
|
const [binanceFactory, coinbaseFactory] = await Promise.all([
|
|
12486
|
-
(0, import_connectors4.getConnectorCreatorByName)(import_connectors3.ConnectorNames.Binance,
|
|
12487
|
-
(0, import_connectors4.getConnectorCreatorByName)(import_connectors3.ConnectorNames.Coinbase,
|
|
12486
|
+
(0, import_connectors4.getConnectorCreatorByName)(import_connectors3.ConnectorNames.Binance, projectRoot17),
|
|
12487
|
+
(0, import_connectors4.getConnectorCreatorByName)(import_connectors3.ConnectorNames.Coinbase, projectRoot17)
|
|
12488
12488
|
]);
|
|
12489
12489
|
const binance = binanceFactory ? await binanceFactory({ userName: userName3 }) : marketConnector;
|
|
12490
12490
|
if (!binanceFactory) {
|
|
@@ -12742,9 +12742,9 @@ var init_runEnvironment = __esm({
|
|
|
12742
12742
|
};
|
|
12743
12743
|
resolveRunConnectorName = async ({
|
|
12744
12744
|
value,
|
|
12745
|
-
projectRoot:
|
|
12745
|
+
projectRoot: projectRoot17
|
|
12746
12746
|
}) => {
|
|
12747
|
-
const connectorName = await (0, import_connectors5.resolveConnectorName)(value,
|
|
12747
|
+
const connectorName = await (0, import_connectors5.resolveConnectorName)(value, projectRoot17);
|
|
12748
12748
|
if (connectorName) {
|
|
12749
12749
|
return connectorName;
|
|
12750
12750
|
}
|
|
@@ -12769,12 +12769,12 @@ var init_runEnvironment = __esm({
|
|
|
12769
12769
|
};
|
|
12770
12770
|
loadDeploymentReplayStrategies = async ({
|
|
12771
12771
|
userName: userName3,
|
|
12772
|
-
projectRoot:
|
|
12772
|
+
projectRoot: projectRoot17,
|
|
12773
12773
|
deploymentId
|
|
12774
12774
|
}) => {
|
|
12775
12775
|
const [deployment, runtimeStrategies] = await Promise.all([
|
|
12776
|
-
(0, import_runtimeStrategies.getRuntimeDeployment)({ userName: userName3, projectRoot:
|
|
12777
|
-
(0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({ userName: userName3, projectRoot:
|
|
12776
|
+
(0, import_runtimeStrategies.getRuntimeDeployment)({ userName: userName3, projectRoot: projectRoot17, deploymentId }),
|
|
12777
|
+
(0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({ userName: userName3, projectRoot: projectRoot17, deploymentId })
|
|
12778
12778
|
]);
|
|
12779
12779
|
if (!deployment) {
|
|
12780
12780
|
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
@@ -12823,7 +12823,7 @@ var init_runEnvironment = __esm({
|
|
|
12823
12823
|
endTime,
|
|
12824
12824
|
cacheOnly,
|
|
12825
12825
|
interval: interval4,
|
|
12826
|
-
projectRoot:
|
|
12826
|
+
projectRoot: projectRoot17,
|
|
12827
12827
|
universe = "crypto",
|
|
12828
12828
|
accountId,
|
|
12829
12829
|
deploymentId,
|
|
@@ -12833,11 +12833,11 @@ var init_runEnvironment = __esm({
|
|
|
12833
12833
|
}) => {
|
|
12834
12834
|
const connectorName = await resolveRunConnectorName({
|
|
12835
12835
|
value: connector,
|
|
12836
|
-
projectRoot:
|
|
12836
|
+
projectRoot: projectRoot17
|
|
12837
12837
|
});
|
|
12838
12838
|
const connectorFactory = await (0, import_connectors5.getConnectorCreatorByName)(
|
|
12839
12839
|
connectorName,
|
|
12840
|
-
|
|
12840
|
+
projectRoot17
|
|
12841
12841
|
);
|
|
12842
12842
|
if (!connectorFactory) {
|
|
12843
12843
|
throw new Error(`Connector "${connectorName}" is not registered`);
|
|
@@ -12904,7 +12904,7 @@ var init_runEnvironment = __esm({
|
|
|
12904
12904
|
connectorName,
|
|
12905
12905
|
marketConnector,
|
|
12906
12906
|
userName: userName3,
|
|
12907
|
-
projectRoot:
|
|
12907
|
+
projectRoot: projectRoot17,
|
|
12908
12908
|
shouldUseDedicatedReferences: universe === "crypto",
|
|
12909
12909
|
requireDedicatedReferences: universe === "crypto",
|
|
12910
12910
|
warn: (message) => console.log(import_chalk12.default.yellow(message))
|
|
@@ -14578,10 +14578,10 @@ var init_binanceBreadthUniversesUpdate = __esm({
|
|
|
14578
14578
|
flags6 = import_args6.default.parse(process.argv);
|
|
14579
14579
|
BINANCE_BREADTH_UNIVERSES_RELATIVE_PATH = "packages/node/src/config/binanceBreadthUniverses.json";
|
|
14580
14580
|
main6 = async () => {
|
|
14581
|
-
const
|
|
14581
|
+
const projectRoot17 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
14582
14582
|
const connectorCreator = await (0, import_connectors7.getConnectorCreatorByName)(
|
|
14583
14583
|
import_connectors6.ConnectorNames.Binance,
|
|
14584
|
-
|
|
14584
|
+
projectRoot17
|
|
14585
14585
|
);
|
|
14586
14586
|
if (!connectorCreator) {
|
|
14587
14587
|
throw new Error("Binance connector is not registered");
|
|
@@ -14614,7 +14614,7 @@ var init_binanceBreadthUniversesUpdate = __esm({
|
|
|
14614
14614
|
return snapshot;
|
|
14615
14615
|
}
|
|
14616
14616
|
const outputPath = import_node_path5.default.join(
|
|
14617
|
-
|
|
14617
|
+
projectRoot17,
|
|
14618
14618
|
BINANCE_BREADTH_UNIVERSES_RELATIVE_PATH
|
|
14619
14619
|
);
|
|
14620
14620
|
await import_promises9.default.writeFile(outputPath, serialized, "utf8");
|
|
@@ -15448,14 +15448,14 @@ var init_cleanTests = __esm({
|
|
|
15448
15448
|
cleanUserTests = async (userName3) => {
|
|
15449
15449
|
const testsPrefix = `users:${userName3}:tests:`;
|
|
15450
15450
|
const testsCachePrefix = `users:${userName3}:cache:tests:`;
|
|
15451
|
-
const
|
|
15451
|
+
const projectRoot17 = process.env.PROJECT_CWD || process.cwd();
|
|
15452
15452
|
const persistedArtifactsDir = import_path7.default.relative(
|
|
15453
|
-
|
|
15454
|
-
(0, import_backtestArtifacts2.getPersistedBacktestArtifactsDirForUser)(userName3,
|
|
15453
|
+
projectRoot17,
|
|
15454
|
+
(0, import_backtestArtifacts2.getPersistedBacktestArtifactsDirForUser)(userName3, projectRoot17)
|
|
15455
15455
|
);
|
|
15456
15456
|
const cacheArtifactsDir = import_path7.default.relative(
|
|
15457
|
-
|
|
15458
|
-
(0, import_backtestArtifacts2.getBacktestCacheArtifactsDirForUser)(userName3,
|
|
15457
|
+
projectRoot17,
|
|
15458
|
+
(0, import_backtestArtifacts2.getBacktestCacheArtifactsDirForUser)(userName3, projectRoot17)
|
|
15459
15459
|
);
|
|
15460
15460
|
if (flags11.cache) {
|
|
15461
15461
|
console.log(import_chalk19.default.yellow(`clean user cache: ${userName3}`));
|
|
@@ -15468,11 +15468,11 @@ var init_cleanTests = __esm({
|
|
|
15468
15468
|
await (0, import_cli7.cleanRedis)(testsCachePrefix);
|
|
15469
15469
|
await (0, import_cli7.cleanFiles)(persistedArtifactsDir);
|
|
15470
15470
|
await (0, import_cli7.cleanFiles)(cacheArtifactsDir);
|
|
15471
|
-
await import_promises10.default.rm(import_path7.default.join(
|
|
15471
|
+
await import_promises10.default.rm(import_path7.default.join(projectRoot17, persistedArtifactsDir), {
|
|
15472
15472
|
recursive: true,
|
|
15473
15473
|
force: true
|
|
15474
15474
|
});
|
|
15475
|
-
await import_promises10.default.rm(import_path7.default.join(
|
|
15475
|
+
await import_promises10.default.rm(import_path7.default.join(projectRoot17, cacheArtifactsDir), {
|
|
15476
15476
|
recursive: true,
|
|
15477
15477
|
force: true
|
|
15478
15478
|
});
|
|
@@ -17309,8 +17309,8 @@ volumes:
|
|
|
17309
17309
|
`${DEV_COMPOSE_FILE} not found in project root. Run "npx @tradejs/cli infra-init" first.`
|
|
17310
17310
|
);
|
|
17311
17311
|
};
|
|
17312
|
-
runDockerCompose = (composePath,
|
|
17313
|
-
const result = (0, import_node_child_process3.spawnSync)("docker", ["compose", "-f", composePath, ...
|
|
17312
|
+
runDockerCompose = (composePath, args37) => {
|
|
17313
|
+
const result = (0, import_node_child_process3.spawnSync)("docker", ["compose", "-f", composePath, ...args37], {
|
|
17314
17314
|
stdio: "inherit"
|
|
17315
17315
|
});
|
|
17316
17316
|
if (result.error) {
|
|
@@ -23584,11 +23584,11 @@ var init_coreResearch = __esm({
|
|
|
23584
23584
|
if (!Number.isFinite(numeric)) throw new Error(`${name} is invalid: ${text}`);
|
|
23585
23585
|
return numeric;
|
|
23586
23586
|
};
|
|
23587
|
-
readSymbols = async (argv2,
|
|
23587
|
+
readSymbols = async (argv2, projectRoot17) => {
|
|
23588
23588
|
const symbolsFile = valueAfter(argv2, "--symbolsFile");
|
|
23589
23589
|
if (symbolsFile) {
|
|
23590
23590
|
const parsed = JSON.parse(
|
|
23591
|
-
await import_promises20.default.readFile(import_node_path14.default.resolve(
|
|
23591
|
+
await import_promises20.default.readFile(import_node_path14.default.resolve(projectRoot17, symbolsFile), "utf8")
|
|
23592
23592
|
);
|
|
23593
23593
|
if (!Array.isArray(parsed) || parsed.some((symbol) => typeof symbol !== "string")) {
|
|
23594
23594
|
throw new Error("--symbolsFile must contain a JSON string array");
|
|
@@ -24654,12 +24654,15 @@ var init_support = __esm({
|
|
|
24654
24654
|
buildReplayStrategyConfig = ({
|
|
24655
24655
|
strategyConfig,
|
|
24656
24656
|
interval: interval4
|
|
24657
|
-
}) =>
|
|
24658
|
-
|
|
24659
|
-
|
|
24660
|
-
|
|
24661
|
-
|
|
24662
|
-
|
|
24657
|
+
}) => ({
|
|
24658
|
+
...buildRuntimeModeStrategyConfig({
|
|
24659
|
+
strategyConfig,
|
|
24660
|
+
env: "PARITY",
|
|
24661
|
+
interval: interval4,
|
|
24662
|
+
makeOrders: false,
|
|
24663
|
+
recordRuntimeTrades: false
|
|
24664
|
+
}),
|
|
24665
|
+
SIMULATE_ORDERS: true
|
|
24663
24666
|
});
|
|
24664
24667
|
toRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
24665
24668
|
compactReplayAdditionalIndicators = (additionalIndicators) => {
|
|
@@ -24765,13 +24768,13 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
24765
24768
|
const parsed = Date.parse(raw);
|
|
24766
24769
|
return Number.isFinite(parsed) ? parsed : null;
|
|
24767
24770
|
};
|
|
24768
|
-
resolveWindow = (
|
|
24769
|
-
const endTime = toEpochMs2(
|
|
24771
|
+
resolveWindow = (flags34) => {
|
|
24772
|
+
const endTime = toEpochMs2(flags34.endTime) ?? Date.now();
|
|
24770
24773
|
const hours = Math.max(
|
|
24771
24774
|
1,
|
|
24772
|
-
Number.parseInt(String(
|
|
24775
|
+
Number.parseInt(String(flags34.hours ?? 24), 10) || 24
|
|
24773
24776
|
);
|
|
24774
|
-
const startTime = toEpochMs2(
|
|
24777
|
+
const startTime = toEpochMs2(flags34.startTime) ?? endTime - hours * 60 * 60 * 1e3;
|
|
24775
24778
|
if (startTime >= endTime) {
|
|
24776
24779
|
throw new Error(
|
|
24777
24780
|
`Invalid window: startTime (${startTime}) must be less than endTime (${endTime})`
|
|
@@ -24780,7 +24783,7 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
24780
24783
|
return {
|
|
24781
24784
|
startTime,
|
|
24782
24785
|
endTime,
|
|
24783
|
-
source:
|
|
24786
|
+
source: flags34.startTime != null || flags34.endTime != null ? "explicit" : "hours"
|
|
24784
24787
|
};
|
|
24785
24788
|
};
|
|
24786
24789
|
parseStrategyFilter = (value) => String(value ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
@@ -24970,9 +24973,9 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
24970
24973
|
strategies,
|
|
24971
24974
|
userName: userName3,
|
|
24972
24975
|
runtimeEvidenceFile,
|
|
24973
|
-
projectRoot:
|
|
24976
|
+
projectRoot: projectRoot17
|
|
24974
24977
|
}) => {
|
|
24975
|
-
const runtimeEvidencePath = typeof runtimeEvidenceFile === "string" && runtimeEvidenceFile.trim() ? import_node_path15.default.resolve(
|
|
24978
|
+
const runtimeEvidencePath = typeof runtimeEvidenceFile === "string" && runtimeEvidenceFile.trim() ? import_node_path15.default.resolve(projectRoot17, runtimeEvidenceFile.trim()) : null;
|
|
24976
24979
|
if (runtimeEvidencePath) {
|
|
24977
24980
|
const artifact = JSON.parse(
|
|
24978
24981
|
await import_promises21.default.readFile(runtimeEvidencePath, "utf8")
|
|
@@ -25006,23 +25009,23 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
25006
25009
|
};
|
|
25007
25010
|
};
|
|
25008
25011
|
replayRuntimeEvidence = async () => {
|
|
25009
|
-
const
|
|
25010
|
-
const
|
|
25011
|
-
const userName3 = String(
|
|
25012
|
-
const { startTime, endTime, source } = resolveWindow(
|
|
25012
|
+
const flags34 = import_args25.default.parse(process.argv);
|
|
25013
|
+
const projectRoot17 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
25014
|
+
const userName3 = String(flags34.user ?? "root");
|
|
25015
|
+
const { startTime, endTime, source } = resolveWindow(flags34);
|
|
25013
25016
|
const replay = await loadReplayResult({
|
|
25014
25017
|
userName: userName3,
|
|
25015
|
-
replayKey: typeof
|
|
25018
|
+
replayKey: typeof flags34.replayKey === "string" && flags34.replayKey.trim() ? flags34.replayKey.trim() : void 0
|
|
25016
25019
|
});
|
|
25017
|
-
const explicitStrategies = parseStrategyFilter(
|
|
25020
|
+
const explicitStrategies = parseStrategyFilter(flags34.strategy);
|
|
25018
25021
|
const strategies = explicitStrategies.length ? explicitStrategies : getReplayStrategies(replay.value);
|
|
25019
25022
|
const runtime = await loadRuntimePayload({
|
|
25020
25023
|
startTime,
|
|
25021
25024
|
endTime,
|
|
25022
25025
|
strategies,
|
|
25023
25026
|
userName: userName3,
|
|
25024
|
-
runtimeEvidenceFile:
|
|
25025
|
-
projectRoot:
|
|
25027
|
+
runtimeEvidenceFile: flags34.runtimeEvidence,
|
|
25028
|
+
projectRoot: projectRoot17
|
|
25026
25029
|
});
|
|
25027
25030
|
const replayValue = asRecord4(replay.value);
|
|
25028
25031
|
const artifact = {
|
|
@@ -25047,6 +25050,10 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
25047
25050
|
availableKeys: replay.availableKeys,
|
|
25048
25051
|
startedAt: replayValue.startedAt ?? null,
|
|
25049
25052
|
finishedAt: replayValue.finishedAt ?? null,
|
|
25053
|
+
durationSeconds: replayValue.durationSeconds ?? null,
|
|
25054
|
+
cycleCount: replayValue.cycleCount ?? null,
|
|
25055
|
+
abortedCycles: replayValue.abortedCycles ?? null,
|
|
25056
|
+
signalsCount: replayValue.signalsCount ?? null,
|
|
25050
25057
|
resultsByStrategies: asArray2(replayValue.resultsByStrategies).filter(
|
|
25051
25058
|
(row) => !strategies.length || strategies.includes(String(row.strategyName ?? ""))
|
|
25052
25059
|
),
|
|
@@ -25057,7 +25064,7 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
25057
25064
|
},
|
|
25058
25065
|
runtime: runtime.payload
|
|
25059
25066
|
};
|
|
25060
|
-
const outPath = import_node_path15.default.resolve(
|
|
25067
|
+
const outPath = import_node_path15.default.resolve(projectRoot17, String(flags34.out));
|
|
25061
25068
|
await import_promises21.default.mkdir(import_node_path15.default.dirname(outPath), { recursive: true });
|
|
25062
25069
|
await import_promises21.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
|
|
25063
25070
|
`, "utf8");
|
|
@@ -25317,12 +25324,12 @@ var init_runtimeEvidenceDeployment = __esm({
|
|
|
25317
25324
|
});
|
|
25318
25325
|
resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
25319
25326
|
userName: userName3,
|
|
25320
|
-
projectRoot:
|
|
25327
|
+
projectRoot: projectRoot17,
|
|
25321
25328
|
deploymentId
|
|
25322
25329
|
}) => {
|
|
25323
25330
|
const [deployment, strategies] = await Promise.all([
|
|
25324
|
-
(0, import_runtimeStrategies3.getRuntimeDeployment)({ userName: userName3, projectRoot:
|
|
25325
|
-
(0, import_runtimeStrategies3.loadResolvedRuntimeStrategies)({ userName: userName3, projectRoot:
|
|
25331
|
+
(0, import_runtimeStrategies3.getRuntimeDeployment)({ userName: userName3, projectRoot: projectRoot17, deploymentId }),
|
|
25332
|
+
(0, import_runtimeStrategies3.loadResolvedRuntimeStrategies)({ userName: userName3, projectRoot: projectRoot17, deploymentId })
|
|
25326
25333
|
]);
|
|
25327
25334
|
if (!deployment) {
|
|
25328
25335
|
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
@@ -25606,12 +25613,981 @@ var init_runtimeEvidenceArtifacts = __esm({
|
|
|
25606
25613
|
}
|
|
25607
25614
|
});
|
|
25608
25615
|
|
|
25616
|
+
// src/lib/runtimeEvidenceProducer.ts
|
|
25617
|
+
var import_node_crypto11, import_promises23, import_node_path17, isRecord2, sha2562, parseRuntimeEvidenceProducer, resolveRuntimeEvidenceProducer;
|
|
25618
|
+
var init_runtimeEvidenceProducer = __esm({
|
|
25619
|
+
"src/lib/runtimeEvidenceProducer.ts"() {
|
|
25620
|
+
"use strict";
|
|
25621
|
+
import_node_crypto11 = require("crypto");
|
|
25622
|
+
import_promises23 = __toESM(require("fs/promises"));
|
|
25623
|
+
import_node_path17 = __toESM(require("path"));
|
|
25624
|
+
isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
25625
|
+
sha2562 = (value) => (0, import_node_crypto11.createHash)("sha256").update(value).digest("hex");
|
|
25626
|
+
parseRuntimeEvidenceProducer = (value) => {
|
|
25627
|
+
const producer = isRecord2(value) ? value : null;
|
|
25628
|
+
const runtimePackageManifest = isRecord2(producer?.runtimePackageManifest) ? producer.runtimePackageManifest : null;
|
|
25629
|
+
if (producer?.schemaVersion !== 1 || typeof producer.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(producer.projectSha) || typeof producer.imageDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(producer.imageDigest) || runtimePackageManifest?.file !== "runtime-package-manifest.json" || typeof runtimePackageManifest.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(runtimePackageManifest.sha256)) {
|
|
25630
|
+
throw new Error("Runtime evidence producer image identity is invalid");
|
|
25631
|
+
}
|
|
25632
|
+
return producer;
|
|
25633
|
+
};
|
|
25634
|
+
resolveRuntimeEvidenceProducer = async ({
|
|
25635
|
+
projectRoot: projectRoot17,
|
|
25636
|
+
required: required4
|
|
25637
|
+
}) => {
|
|
25638
|
+
const projectSha = String(process.env.TRADEJS_PROJECT_SHA ?? "").trim();
|
|
25639
|
+
const imageDigest = String(
|
|
25640
|
+
process.env.TRADEJS_PROJECT_IMAGE_DIGEST ?? ""
|
|
25641
|
+
).trim();
|
|
25642
|
+
if (!projectSha && !imageDigest && !required4) {
|
|
25643
|
+
return null;
|
|
25644
|
+
}
|
|
25645
|
+
if (!/^[a-f0-9]{40}$/.test(projectSha)) {
|
|
25646
|
+
throw new Error(
|
|
25647
|
+
"TRADEJS_PROJECT_SHA must be a full lowercase Git SHA before publishing runtime evidence"
|
|
25648
|
+
);
|
|
25649
|
+
}
|
|
25650
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(imageDigest)) {
|
|
25651
|
+
throw new Error(
|
|
25652
|
+
"TRADEJS_PROJECT_IMAGE_DIGEST must be an immutable sha256 digest before publishing runtime evidence"
|
|
25653
|
+
);
|
|
25654
|
+
}
|
|
25655
|
+
const manifestPath = import_node_path17.default.join(projectRoot17, "runtime-package-manifest.json");
|
|
25656
|
+
let manifest;
|
|
25657
|
+
try {
|
|
25658
|
+
manifest = await import_promises23.default.readFile(manifestPath);
|
|
25659
|
+
} catch (error) {
|
|
25660
|
+
if (!required4 && error.code === "ENOENT") {
|
|
25661
|
+
return null;
|
|
25662
|
+
}
|
|
25663
|
+
throw new Error(
|
|
25664
|
+
`Runtime package manifest is required for runtime evidence: ${manifestPath}`,
|
|
25665
|
+
{ cause: error }
|
|
25666
|
+
);
|
|
25667
|
+
}
|
|
25668
|
+
return {
|
|
25669
|
+
schemaVersion: 1,
|
|
25670
|
+
projectSha,
|
|
25671
|
+
imageDigest,
|
|
25672
|
+
runtimePackageManifest: {
|
|
25673
|
+
file: "runtime-package-manifest.json",
|
|
25674
|
+
sha256: sha2562(manifest)
|
|
25675
|
+
}
|
|
25676
|
+
};
|
|
25677
|
+
};
|
|
25678
|
+
}
|
|
25679
|
+
});
|
|
25680
|
+
|
|
25681
|
+
// src/lib/runtimeFeedbackArtifacts.ts
|
|
25682
|
+
var import_node_crypto12, import_promises24, import_node_path18, RUNTIME_FEEDBACK_MANIFEST_FILE, RUNTIME_FEEDBACK_REPLAY_FILE, RUNTIME_FEEDBACK_LOG_FILE, RUNTIME_FEEDBACK_COMPLETE_FILE, isRecord3, sha2563, safeSegment2, parsePayload, parseManifest2, assertReplayMatchesRuntimeEvidence, sealRuntimeFeedbackReplayBundle, verifyRuntimeFeedbackReplayBundle, discoverRuntimeFeedbackReplayBundles, verifyRuntimeFeedbackReplaySource;
|
|
25683
|
+
var init_runtimeFeedbackArtifacts = __esm({
|
|
25684
|
+
"src/lib/runtimeFeedbackArtifacts.ts"() {
|
|
25685
|
+
"use strict";
|
|
25686
|
+
import_node_crypto12 = require("crypto");
|
|
25687
|
+
import_promises24 = __toESM(require("fs/promises"));
|
|
25688
|
+
import_node_path18 = __toESM(require("path"));
|
|
25689
|
+
init_runtimeEvidenceDeployment();
|
|
25690
|
+
init_runtimeEvidenceArtifacts();
|
|
25691
|
+
init_runtimeEvidenceProducer();
|
|
25692
|
+
RUNTIME_FEEDBACK_MANIFEST_FILE = "manifest.json";
|
|
25693
|
+
RUNTIME_FEEDBACK_REPLAY_FILE = "replay-runtime-evidence.json";
|
|
25694
|
+
RUNTIME_FEEDBACK_LOG_FILE = "replay.log";
|
|
25695
|
+
RUNTIME_FEEDBACK_COMPLETE_FILE = ".complete";
|
|
25696
|
+
isRecord3 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
25697
|
+
sha2563 = (value) => (0, import_node_crypto12.createHash)("sha256").update(value).digest("hex");
|
|
25698
|
+
safeSegment2 = (value, fallback) => {
|
|
25699
|
+
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
25700
|
+
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
25701
|
+
};
|
|
25702
|
+
parsePayload = (value, expectedFile) => {
|
|
25703
|
+
const payload = isRecord3(value) ? value : null;
|
|
25704
|
+
if (payload?.file !== expectedFile || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number" || !Number.isFinite(payload.bytes) || payload.bytes < 0) {
|
|
25705
|
+
throw new Error(`Invalid runtime feedback payload: ${expectedFile}`);
|
|
25706
|
+
}
|
|
25707
|
+
return payload;
|
|
25708
|
+
};
|
|
25709
|
+
parseManifest2 = (value) => {
|
|
25710
|
+
const manifest = isRecord3(value) ? value : null;
|
|
25711
|
+
const window = isRecord3(manifest?.window) ? manifest.window : null;
|
|
25712
|
+
const runtimeEvidence2 = isRecord3(manifest?.runtimeEvidence) ? manifest.runtimeEvidence : null;
|
|
25713
|
+
const safety = isRecord3(manifest?.safety) ? manifest.safety : null;
|
|
25714
|
+
const payloads = isRecord3(manifest?.payloads) ? manifest.payloads : null;
|
|
25715
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-feedback-replay" || typeof manifest.artifactId !== "string" || !manifest.artifactId.trim() || typeof manifest.runId !== "string" || !manifest.runId.trim() || typeof manifest.deploymentId !== "string" || !manifest.deploymentId.trim() || typeof manifest.deploymentCompositionId !== "string" || !/^dc1:[a-f0-9]{16}$/.test(manifest.deploymentCompositionId) || typeof manifest.userName !== "string" || !manifest.userName.trim() || typeof manifest.createdAt !== "number" || typeof window?.startTime !== "number" || typeof window.endTime !== "number" || typeof runtimeEvidence2?.artifactId !== "string" || typeof runtimeEvidence2.payloadSha256 !== "string" || !/^[a-f0-9]{64}$/.test(runtimeEvidence2.payloadSha256) || !Array.isArray(manifest.activeStrategies) || manifest.activeStrategies.length === 0 || !manifest.activeStrategies.every(
|
|
25716
|
+
(strategy) => typeof strategy === "string" && strategy.trim()
|
|
25717
|
+
) || typeof manifest.cycleCount !== "number" || !Number.isFinite(manifest.cycleCount) || manifest.cycleCount <= 0 || safety?.cacheOnly !== true || safety.externalOrderPlacement !== false || safety.redis !== "isolated" || safety.timescale !== "read_only") {
|
|
25718
|
+
throw new Error("Invalid runtime feedback replay manifest");
|
|
25719
|
+
}
|
|
25720
|
+
const replayEvidence = parsePayload(
|
|
25721
|
+
payloads?.replayEvidence,
|
|
25722
|
+
RUNTIME_FEEDBACK_REPLAY_FILE
|
|
25723
|
+
);
|
|
25724
|
+
const log = parsePayload(payloads?.log, RUNTIME_FEEDBACK_LOG_FILE);
|
|
25725
|
+
return {
|
|
25726
|
+
...manifest,
|
|
25727
|
+
producer: parseRuntimeEvidenceProducer(manifest.producer),
|
|
25728
|
+
payloads: {
|
|
25729
|
+
replayEvidence: {
|
|
25730
|
+
...replayEvidence,
|
|
25731
|
+
file: RUNTIME_FEEDBACK_REPLAY_FILE
|
|
25732
|
+
},
|
|
25733
|
+
log: { ...log, file: RUNTIME_FEEDBACK_LOG_FILE }
|
|
25734
|
+
}
|
|
25735
|
+
};
|
|
25736
|
+
};
|
|
25737
|
+
assertReplayMatchesRuntimeEvidence = ({
|
|
25738
|
+
replayEvidence,
|
|
25739
|
+
runtimeEvidence: runtimeEvidence2
|
|
25740
|
+
}) => {
|
|
25741
|
+
if (replayEvidence.reportType !== "replay-runtime-evidence") {
|
|
25742
|
+
throw new Error("Runtime feedback replay payload has the wrong reportType");
|
|
25743
|
+
}
|
|
25744
|
+
const replayWindow = isRecord3(replayEvidence.window) ? replayEvidence.window : null;
|
|
25745
|
+
if (replayWindow?.startTime !== runtimeEvidence2.manifest.window.startTime || replayWindow.endTime !== runtimeEvidence2.manifest.window.endTime) {
|
|
25746
|
+
throw new Error("Runtime feedback replay window does not match evidence");
|
|
25747
|
+
}
|
|
25748
|
+
const runtimeDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
25749
|
+
runtimeEvidence2.artifact.deployment
|
|
25750
|
+
);
|
|
25751
|
+
const replayDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
25752
|
+
replayEvidence.deployment
|
|
25753
|
+
);
|
|
25754
|
+
if (replayDeployment.id !== runtimeDeployment.id || replayDeployment.deploymentCompositionId !== runtimeDeployment.deploymentCompositionId) {
|
|
25755
|
+
throw new Error(
|
|
25756
|
+
"Runtime feedback replay deployment does not match evidence"
|
|
25757
|
+
);
|
|
25758
|
+
}
|
|
25759
|
+
};
|
|
25760
|
+
sealRuntimeFeedbackReplayBundle = async ({
|
|
25761
|
+
bundleDir,
|
|
25762
|
+
runId,
|
|
25763
|
+
runtimeEvidenceBundle
|
|
25764
|
+
}) => {
|
|
25765
|
+
const replayEvidencePath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_REPLAY_FILE);
|
|
25766
|
+
const logPath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_LOG_FILE);
|
|
25767
|
+
const [replayPayload, logPayload] = await Promise.all([
|
|
25768
|
+
import_promises24.default.readFile(replayEvidencePath),
|
|
25769
|
+
import_promises24.default.readFile(logPath)
|
|
25770
|
+
]);
|
|
25771
|
+
const replayEvidence = JSON.parse(replayPayload.toString("utf8"));
|
|
25772
|
+
assertReplayMatchesRuntimeEvidence({
|
|
25773
|
+
replayEvidence,
|
|
25774
|
+
runtimeEvidence: runtimeEvidenceBundle
|
|
25775
|
+
});
|
|
25776
|
+
const replay = isRecord3(replayEvidence.replay) ? replayEvidence.replay : null;
|
|
25777
|
+
const cycleCount = Number(replay?.cycleCount);
|
|
25778
|
+
if (!Number.isFinite(cycleCount) || cycleCount <= 0) {
|
|
25779
|
+
throw new Error(
|
|
25780
|
+
`Runtime feedback replay produced no comparable cycles: ${String(replay?.cycleCount ?? "missing")}`
|
|
25781
|
+
);
|
|
25782
|
+
}
|
|
25783
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
25784
|
+
runtimeEvidenceBundle.artifact.deployment
|
|
25785
|
+
);
|
|
25786
|
+
const producer = parseRuntimeEvidenceProducer(
|
|
25787
|
+
runtimeEvidenceBundle.artifact.producer
|
|
25788
|
+
);
|
|
25789
|
+
const safeRunId = safeSegment2(runId, "run");
|
|
25790
|
+
const artifactId = `${runtimeEvidenceBundle.manifest.artifactId}_${safeRunId}`;
|
|
25791
|
+
const manifest = {
|
|
25792
|
+
schemaVersion: 1,
|
|
25793
|
+
reportType: "runtime-feedback-replay",
|
|
25794
|
+
artifactId,
|
|
25795
|
+
runId: safeRunId,
|
|
25796
|
+
deploymentId: deployment.id,
|
|
25797
|
+
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
25798
|
+
userName: runtimeEvidenceBundle.manifest.userName,
|
|
25799
|
+
createdAt: Date.now(),
|
|
25800
|
+
window: { ...runtimeEvidenceBundle.manifest.window },
|
|
25801
|
+
runtimeEvidence: {
|
|
25802
|
+
artifactId: runtimeEvidenceBundle.manifest.artifactId,
|
|
25803
|
+
payloadSha256: runtimeEvidenceBundle.manifest.payload.sha256
|
|
25804
|
+
},
|
|
25805
|
+
producer,
|
|
25806
|
+
activeStrategies: activeRuntimeEvidenceStrategies(deployment).map(
|
|
25807
|
+
({ strategyName }) => strategyName
|
|
25808
|
+
),
|
|
25809
|
+
cycleCount,
|
|
25810
|
+
safety: {
|
|
25811
|
+
cacheOnly: true,
|
|
25812
|
+
externalOrderPlacement: false,
|
|
25813
|
+
redis: "isolated",
|
|
25814
|
+
timescale: "read_only"
|
|
25815
|
+
},
|
|
25816
|
+
payloads: {
|
|
25817
|
+
replayEvidence: {
|
|
25818
|
+
file: RUNTIME_FEEDBACK_REPLAY_FILE,
|
|
25819
|
+
sha256: sha2563(replayPayload),
|
|
25820
|
+
bytes: replayPayload.byteLength
|
|
25821
|
+
},
|
|
25822
|
+
log: {
|
|
25823
|
+
file: RUNTIME_FEEDBACK_LOG_FILE,
|
|
25824
|
+
sha256: sha2563(logPayload),
|
|
25825
|
+
bytes: logPayload.byteLength
|
|
25826
|
+
}
|
|
25827
|
+
}
|
|
25828
|
+
};
|
|
25829
|
+
await import_promises24.default.writeFile(
|
|
25830
|
+
import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_MANIFEST_FILE),
|
|
25831
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
25832
|
+
`,
|
|
25833
|
+
"utf8"
|
|
25834
|
+
);
|
|
25835
|
+
await import_promises24.default.writeFile(
|
|
25836
|
+
import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_COMPLETE_FILE),
|
|
25837
|
+
`${artifactId}
|
|
25838
|
+
`,
|
|
25839
|
+
"utf8"
|
|
25840
|
+
);
|
|
25841
|
+
return verifyRuntimeFeedbackReplayBundle(bundleDir);
|
|
25842
|
+
};
|
|
25843
|
+
verifyRuntimeFeedbackReplayBundle = async (bundleDir) => {
|
|
25844
|
+
const manifestPath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_MANIFEST_FILE);
|
|
25845
|
+
const replayEvidencePath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_REPLAY_FILE);
|
|
25846
|
+
const logPath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_LOG_FILE);
|
|
25847
|
+
const completePath = import_node_path18.default.join(bundleDir, RUNTIME_FEEDBACK_COMPLETE_FILE);
|
|
25848
|
+
const [manifestText, replayPayload, logPayload, completeText] = await Promise.all([
|
|
25849
|
+
import_promises24.default.readFile(manifestPath, "utf8"),
|
|
25850
|
+
import_promises24.default.readFile(replayEvidencePath),
|
|
25851
|
+
import_promises24.default.readFile(logPath),
|
|
25852
|
+
import_promises24.default.readFile(completePath, "utf8")
|
|
25853
|
+
]);
|
|
25854
|
+
const manifest = parseManifest2(JSON.parse(manifestText));
|
|
25855
|
+
if (completeText.trim() !== manifest.artifactId) {
|
|
25856
|
+
throw new Error(`Invalid runtime feedback completion marker: ${bundleDir}`);
|
|
25857
|
+
}
|
|
25858
|
+
for (const [payload, descriptor] of [
|
|
25859
|
+
[replayPayload, manifest.payloads.replayEvidence],
|
|
25860
|
+
[logPayload, manifest.payloads.log]
|
|
25861
|
+
]) {
|
|
25862
|
+
if (payload.byteLength !== descriptor.bytes) {
|
|
25863
|
+
throw new Error(
|
|
25864
|
+
`Runtime feedback payload size mismatch: ${descriptor.file}`
|
|
25865
|
+
);
|
|
25866
|
+
}
|
|
25867
|
+
if (sha2563(payload) !== descriptor.sha256) {
|
|
25868
|
+
throw new Error(
|
|
25869
|
+
`Runtime feedback payload checksum mismatch: ${descriptor.file}`
|
|
25870
|
+
);
|
|
25871
|
+
}
|
|
25872
|
+
}
|
|
25873
|
+
const replayEvidence = JSON.parse(replayPayload.toString("utf8"));
|
|
25874
|
+
if (replayEvidence.reportType !== "replay-runtime-evidence") {
|
|
25875
|
+
throw new Error("Invalid runtime feedback replay evidence payload");
|
|
25876
|
+
}
|
|
25877
|
+
const replayWindow = isRecord3(replayEvidence.window) ? replayEvidence.window : null;
|
|
25878
|
+
const replay = isRecord3(replayEvidence.replay) ? replayEvidence.replay : null;
|
|
25879
|
+
const replayDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
25880
|
+
replayEvidence.deployment
|
|
25881
|
+
);
|
|
25882
|
+
const replayStrategies = activeRuntimeEvidenceStrategies(replayDeployment).map(({ strategyName }) => strategyName).sort();
|
|
25883
|
+
if (replayEvidence.userName !== manifest.userName || replayWindow?.startTime !== manifest.window.startTime || replayWindow.endTime !== manifest.window.endTime || replayDeployment.id !== manifest.deploymentId || replayDeployment.deploymentCompositionId !== manifest.deploymentCompositionId || Number(replay?.cycleCount) !== manifest.cycleCount || JSON.stringify(replayStrategies) !== JSON.stringify([...manifest.activeStrategies].sort())) {
|
|
25884
|
+
throw new Error("Runtime feedback replay payload does not match manifest");
|
|
25885
|
+
}
|
|
25886
|
+
return {
|
|
25887
|
+
bundleDir,
|
|
25888
|
+
manifestPath,
|
|
25889
|
+
replayEvidencePath,
|
|
25890
|
+
logPath,
|
|
25891
|
+
manifest,
|
|
25892
|
+
replayEvidence
|
|
25893
|
+
};
|
|
25894
|
+
};
|
|
25895
|
+
discoverRuntimeFeedbackReplayBundles = async (rootDir) => {
|
|
25896
|
+
const bundles = [];
|
|
25897
|
+
const visit = async (directory, depth) => {
|
|
25898
|
+
if (depth > 10) return;
|
|
25899
|
+
let entries;
|
|
25900
|
+
try {
|
|
25901
|
+
entries = await import_promises24.default.readdir(directory, { withFileTypes: true });
|
|
25902
|
+
} catch (error) {
|
|
25903
|
+
if (error.code === "ENOENT") return;
|
|
25904
|
+
throw error;
|
|
25905
|
+
}
|
|
25906
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
25907
|
+
if (names.has(RUNTIME_FEEDBACK_MANIFEST_FILE) && names.has(RUNTIME_FEEDBACK_REPLAY_FILE) && names.has(RUNTIME_FEEDBACK_LOG_FILE) && names.has(RUNTIME_FEEDBACK_COMPLETE_FILE)) {
|
|
25908
|
+
bundles.push(directory);
|
|
25909
|
+
return;
|
|
25910
|
+
}
|
|
25911
|
+
await Promise.all(
|
|
25912
|
+
entries.filter(
|
|
25913
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
|
|
25914
|
+
).map((entry) => visit(import_node_path18.default.join(directory, entry.name), depth + 1))
|
|
25915
|
+
);
|
|
25916
|
+
};
|
|
25917
|
+
await visit(rootDir, 0);
|
|
25918
|
+
return bundles.sort();
|
|
25919
|
+
};
|
|
25920
|
+
verifyRuntimeFeedbackReplaySource = async ({
|
|
25921
|
+
bundleDir,
|
|
25922
|
+
runtimeEvidenceBundleDir
|
|
25923
|
+
}) => {
|
|
25924
|
+
const [feedback, runtimeEvidence2] = await Promise.all([
|
|
25925
|
+
verifyRuntimeFeedbackReplayBundle(bundleDir),
|
|
25926
|
+
verifyRuntimeEvidenceBundle(runtimeEvidenceBundleDir)
|
|
25927
|
+
]);
|
|
25928
|
+
if (feedback.manifest.runtimeEvidence.artifactId !== runtimeEvidence2.manifest.artifactId || feedback.manifest.runtimeEvidence.payloadSha256 !== runtimeEvidence2.manifest.payload.sha256) {
|
|
25929
|
+
throw new Error("Runtime feedback bundle references different evidence");
|
|
25930
|
+
}
|
|
25931
|
+
assertReplayMatchesRuntimeEvidence({
|
|
25932
|
+
replayEvidence: feedback.replayEvidence,
|
|
25933
|
+
runtimeEvidence: runtimeEvidence2
|
|
25934
|
+
});
|
|
25935
|
+
return { feedback, runtimeEvidence: runtimeEvidence2 };
|
|
25936
|
+
};
|
|
25937
|
+
}
|
|
25938
|
+
});
|
|
25939
|
+
|
|
25940
|
+
// src/lib/runtimeFeedbackReplay.ts
|
|
25941
|
+
var import_node_child_process6, import_promises25, import_node_path19, REQUIRED_ENV, FORBIDDEN_SECRET_ENV, unsafeRedisHosts, safeSegment3, assertRuntimeFeedbackReplaySafety, buildRuntimeFeedbackReplayCommands, runLoggedCommand, runRuntimeFeedbackReplay;
|
|
25942
|
+
var init_runtimeFeedbackReplay = __esm({
|
|
25943
|
+
"src/lib/runtimeFeedbackReplay.ts"() {
|
|
25944
|
+
"use strict";
|
|
25945
|
+
import_node_child_process6 = require("child_process");
|
|
25946
|
+
import_promises25 = __toESM(require("fs/promises"));
|
|
25947
|
+
import_node_path19 = __toESM(require("path"));
|
|
25948
|
+
init_runtimeEvidenceDeployment();
|
|
25949
|
+
init_runtimeEvidenceArtifacts();
|
|
25950
|
+
init_runtimeEvidenceProducer();
|
|
25951
|
+
init_runtimeFeedbackArtifacts();
|
|
25952
|
+
REQUIRED_ENV = {
|
|
25953
|
+
RUNTIME_FEEDBACK_ISOLATED_REDIS: "true",
|
|
25954
|
+
MAKE_ORDERS: "false",
|
|
25955
|
+
TRADEJS_EXTERNAL_ORDER_PLACEMENT: "false"
|
|
25956
|
+
};
|
|
25957
|
+
FORBIDDEN_SECRET_ENV = [
|
|
25958
|
+
"AGENT_GITHUB_TOKEN",
|
|
25959
|
+
"AI_API_KEY",
|
|
25960
|
+
"ANTHROPIC_API_KEY",
|
|
25961
|
+
"AUTH_SECRET",
|
|
25962
|
+
"BYBIT_API_KEY",
|
|
25963
|
+
"BYBIT_API_SECRET",
|
|
25964
|
+
"COINALYZE_API_KEY",
|
|
25965
|
+
"COINMARKETCAP_API_KEY",
|
|
25966
|
+
"GITHUB_TOKEN",
|
|
25967
|
+
"GIT_SSH_PRIVATE_KEY",
|
|
25968
|
+
"NEXTAUTH_SECRET",
|
|
25969
|
+
"NPM_TOKEN",
|
|
25970
|
+
"OPENAI_API_KEY",
|
|
25971
|
+
"OPENROUTER_API_KEY",
|
|
25972
|
+
"SSH_PRIVATE_KEY",
|
|
25973
|
+
"TG_BOT_TOKEN"
|
|
25974
|
+
];
|
|
25975
|
+
unsafeRedisHosts = /* @__PURE__ */ new Set([
|
|
25976
|
+
"127.0.0.1",
|
|
25977
|
+
"::1",
|
|
25978
|
+
"inv-redis",
|
|
25979
|
+
"localhost",
|
|
25980
|
+
"redis"
|
|
25981
|
+
]);
|
|
25982
|
+
safeSegment3 = (value, fallback) => {
|
|
25983
|
+
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
25984
|
+
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
25985
|
+
};
|
|
25986
|
+
assertRuntimeFeedbackReplaySafety = (env) => {
|
|
25987
|
+
for (const [name, expected] of Object.entries(REQUIRED_ENV)) {
|
|
25988
|
+
if (env[name] !== expected) {
|
|
25989
|
+
throw new Error(`Runtime feedback replay requires ${name}=${expected}`);
|
|
25990
|
+
}
|
|
25991
|
+
}
|
|
25992
|
+
const redisHost = String(env.REDIS_HOST ?? "").trim().toLowerCase();
|
|
25993
|
+
if (!redisHost || unsafeRedisHosts.has(redisHost)) {
|
|
25994
|
+
throw new Error(
|
|
25995
|
+
`Runtime feedback replay requires a named isolated Redis host, received ${redisHost || "[missing]"}`
|
|
25996
|
+
);
|
|
25997
|
+
}
|
|
25998
|
+
const pgOptions = String(env.PGOPTIONS ?? "");
|
|
25999
|
+
if (!/default_transaction_read_only\s*=\s*on/i.test(pgOptions)) {
|
|
26000
|
+
throw new Error(
|
|
26001
|
+
"Runtime feedback replay requires PGOPTIONS with default_transaction_read_only=on"
|
|
26002
|
+
);
|
|
26003
|
+
}
|
|
26004
|
+
if (env.TRADEJS_TIMESCALE_READ_ONLY !== "true") {
|
|
26005
|
+
throw new Error(
|
|
26006
|
+
"Runtime feedback replay requires TRADEJS_TIMESCALE_READ_ONLY=true"
|
|
26007
|
+
);
|
|
26008
|
+
}
|
|
26009
|
+
const exposedSecrets = FORBIDDEN_SECRET_ENV.filter(
|
|
26010
|
+
(name) => String(env[name] ?? "").trim()
|
|
26011
|
+
);
|
|
26012
|
+
if (exposedSecrets.length) {
|
|
26013
|
+
throw new Error(
|
|
26014
|
+
`Runtime feedback replay received forbidden credentials: ${exposedSecrets.join(", ")}`
|
|
26015
|
+
);
|
|
26016
|
+
}
|
|
26017
|
+
};
|
|
26018
|
+
buildRuntimeFeedbackReplayCommands = ({
|
|
26019
|
+
cliPath,
|
|
26020
|
+
runtimeEvidencePath,
|
|
26021
|
+
replayEvidencePath,
|
|
26022
|
+
userName: userName3,
|
|
26023
|
+
connectorName,
|
|
26024
|
+
deploymentId,
|
|
26025
|
+
interval: interval4,
|
|
26026
|
+
startTime,
|
|
26027
|
+
endTime
|
|
26028
|
+
}) => [
|
|
26029
|
+
[
|
|
26030
|
+
cliPath,
|
|
26031
|
+
"replay",
|
|
26032
|
+
"--user",
|
|
26033
|
+
userName3,
|
|
26034
|
+
"--connector",
|
|
26035
|
+
connectorName,
|
|
26036
|
+
"--deployment",
|
|
26037
|
+
deploymentId,
|
|
26038
|
+
"--timeframe",
|
|
26039
|
+
interval4,
|
|
26040
|
+
"--startTime",
|
|
26041
|
+
String(startTime),
|
|
26042
|
+
"--endTime",
|
|
26043
|
+
String(endTime),
|
|
26044
|
+
"--runtimeEvidence",
|
|
26045
|
+
runtimeEvidencePath,
|
|
26046
|
+
"--cacheOnly"
|
|
26047
|
+
],
|
|
26048
|
+
[
|
|
26049
|
+
cliPath,
|
|
26050
|
+
"replay-runtime-evidence",
|
|
26051
|
+
"--user",
|
|
26052
|
+
userName3,
|
|
26053
|
+
"--runtimeEvidence",
|
|
26054
|
+
runtimeEvidencePath,
|
|
26055
|
+
"--startTime",
|
|
26056
|
+
String(startTime),
|
|
26057
|
+
"--endTime",
|
|
26058
|
+
String(endTime),
|
|
26059
|
+
"--out",
|
|
26060
|
+
replayEvidencePath
|
|
26061
|
+
]
|
|
26062
|
+
];
|
|
26063
|
+
runLoggedCommand = async ({
|
|
26064
|
+
executable,
|
|
26065
|
+
command,
|
|
26066
|
+
cwd,
|
|
26067
|
+
env,
|
|
26068
|
+
logHandle
|
|
26069
|
+
}) => {
|
|
26070
|
+
await logHandle.write(`
|
|
26071
|
+
$ ${[executable, ...command].join(" ")}
|
|
26072
|
+
`);
|
|
26073
|
+
await new Promise((resolve, reject) => {
|
|
26074
|
+
let pendingLogWrite = Promise.resolve();
|
|
26075
|
+
const appendLog = (chunk) => {
|
|
26076
|
+
pendingLogWrite = pendingLogWrite.then(async () => {
|
|
26077
|
+
await logHandle.write(chunk);
|
|
26078
|
+
});
|
|
26079
|
+
};
|
|
26080
|
+
const child = (0, import_node_child_process6.spawn)(executable, command, {
|
|
26081
|
+
cwd,
|
|
26082
|
+
env,
|
|
26083
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
26084
|
+
});
|
|
26085
|
+
child.stdout.on("data", (chunk) => {
|
|
26086
|
+
process.stdout.write(chunk);
|
|
26087
|
+
appendLog(chunk);
|
|
26088
|
+
});
|
|
26089
|
+
child.stderr.on("data", (chunk) => {
|
|
26090
|
+
process.stderr.write(chunk);
|
|
26091
|
+
appendLog(chunk);
|
|
26092
|
+
});
|
|
26093
|
+
child.once("error", reject);
|
|
26094
|
+
child.once("close", (code, signal) => {
|
|
26095
|
+
void pendingLogWrite.then(() => {
|
|
26096
|
+
if (code === 0) {
|
|
26097
|
+
resolve();
|
|
26098
|
+
return;
|
|
26099
|
+
}
|
|
26100
|
+
reject(
|
|
26101
|
+
new Error(
|
|
26102
|
+
`Runtime feedback command failed: exit=${String(code)} signal=${String(signal)}`
|
|
26103
|
+
)
|
|
26104
|
+
);
|
|
26105
|
+
}, reject);
|
|
26106
|
+
});
|
|
26107
|
+
});
|
|
26108
|
+
};
|
|
26109
|
+
runRuntimeFeedbackReplay = async ({
|
|
26110
|
+
runtimeEvidencePath,
|
|
26111
|
+
outDir,
|
|
26112
|
+
runId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${process.pid}`,
|
|
26113
|
+
projectRoot: projectRoot17,
|
|
26114
|
+
env = process.env,
|
|
26115
|
+
executable = process.execPath,
|
|
26116
|
+
cliPath = process.argv[1]
|
|
26117
|
+
}) => {
|
|
26118
|
+
assertRuntimeFeedbackReplaySafety(env);
|
|
26119
|
+
if (!cliPath) {
|
|
26120
|
+
throw new Error("Cannot resolve the TradeJS CLI executable path");
|
|
26121
|
+
}
|
|
26122
|
+
const runtimeEvidenceBundle = await verifyRuntimeEvidenceBundle(
|
|
26123
|
+
import_node_path19.default.dirname(runtimeEvidencePath)
|
|
26124
|
+
);
|
|
26125
|
+
if (import_node_path19.default.resolve(runtimeEvidenceBundle.payloadPath) !== runtimeEvidencePath) {
|
|
26126
|
+
throw new Error(
|
|
26127
|
+
`Runtime evidence must be the verified bundle payload: ${runtimeEvidenceBundle.payloadPath}`
|
|
26128
|
+
);
|
|
26129
|
+
}
|
|
26130
|
+
const deployedProducer = parseRuntimeEvidenceProducer(
|
|
26131
|
+
runtimeEvidenceBundle.artifact.producer
|
|
26132
|
+
);
|
|
26133
|
+
const currentProducer = await resolveRuntimeEvidenceProducer({
|
|
26134
|
+
projectRoot: projectRoot17,
|
|
26135
|
+
required: true
|
|
26136
|
+
});
|
|
26137
|
+
if (!currentProducer || currentProducer.projectSha !== deployedProducer.projectSha || currentProducer.imageDigest !== deployedProducer.imageDigest || currentProducer.runtimePackageManifest.sha256 !== deployedProducer.runtimePackageManifest.sha256) {
|
|
26138
|
+
throw new Error(
|
|
26139
|
+
"Runtime feedback replay image identity does not match runtime evidence"
|
|
26140
|
+
);
|
|
26141
|
+
}
|
|
26142
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
26143
|
+
runtimeEvidenceBundle.artifact.deployment
|
|
26144
|
+
);
|
|
26145
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
26146
|
+
const intervals = new Set(
|
|
26147
|
+
activeStrategies.map(({ interval: interval4 }) => String(interval4))
|
|
26148
|
+
);
|
|
26149
|
+
if (intervals.size !== 1) {
|
|
26150
|
+
throw new Error(
|
|
26151
|
+
`Runtime feedback replay requires one interval, received ${[...intervals].join(",")}`
|
|
26152
|
+
);
|
|
26153
|
+
}
|
|
26154
|
+
await import_promises25.default.mkdir(outDir, { recursive: true });
|
|
26155
|
+
const existing = await import_promises25.default.readdir(outDir);
|
|
26156
|
+
if (existing.length) {
|
|
26157
|
+
throw new Error(
|
|
26158
|
+
`Runtime feedback output directory must be empty: ${outDir}`
|
|
26159
|
+
);
|
|
26160
|
+
}
|
|
26161
|
+
const replayEvidencePath = import_node_path19.default.join(outDir, RUNTIME_FEEDBACK_REPLAY_FILE);
|
|
26162
|
+
const logHandle = await import_promises25.default.open(
|
|
26163
|
+
import_node_path19.default.join(outDir, RUNTIME_FEEDBACK_LOG_FILE),
|
|
26164
|
+
"wx"
|
|
26165
|
+
);
|
|
26166
|
+
const commands = buildRuntimeFeedbackReplayCommands({
|
|
26167
|
+
cliPath,
|
|
26168
|
+
runtimeEvidencePath,
|
|
26169
|
+
replayEvidencePath,
|
|
26170
|
+
userName: runtimeEvidenceBundle.manifest.userName,
|
|
26171
|
+
connectorName: deployment.connectorName,
|
|
26172
|
+
deploymentId: deployment.id,
|
|
26173
|
+
interval: [...intervals][0],
|
|
26174
|
+
startTime: runtimeEvidenceBundle.manifest.window.startTime,
|
|
26175
|
+
endTime: runtimeEvidenceBundle.manifest.window.endTime
|
|
26176
|
+
});
|
|
26177
|
+
try {
|
|
26178
|
+
for (const command of commands) {
|
|
26179
|
+
await runLoggedCommand({
|
|
26180
|
+
executable,
|
|
26181
|
+
command,
|
|
26182
|
+
cwd: projectRoot17,
|
|
26183
|
+
env,
|
|
26184
|
+
logHandle
|
|
26185
|
+
});
|
|
26186
|
+
}
|
|
26187
|
+
} finally {
|
|
26188
|
+
await logHandle.close();
|
|
26189
|
+
}
|
|
26190
|
+
return sealRuntimeFeedbackReplayBundle({
|
|
26191
|
+
bundleDir: outDir,
|
|
26192
|
+
runId: safeSegment3(runId, "run"),
|
|
26193
|
+
runtimeEvidenceBundle
|
|
26194
|
+
});
|
|
26195
|
+
};
|
|
26196
|
+
}
|
|
26197
|
+
});
|
|
26198
|
+
|
|
26199
|
+
// src/scripts/runtimeFeedbackReplay.ts
|
|
26200
|
+
var runtimeFeedbackReplay_exports = {};
|
|
26201
|
+
__export(runtimeFeedbackReplay_exports, {
|
|
26202
|
+
main: () => main34,
|
|
26203
|
+
runtimeFeedbackReplay: () => runtimeFeedbackReplay
|
|
26204
|
+
});
|
|
26205
|
+
var import_node_path20, import_args26, import_chalk39, flags25, projectRoot9, runtimeFeedbackReplay, main34;
|
|
26206
|
+
var init_runtimeFeedbackReplay2 = __esm({
|
|
26207
|
+
"src/scripts/runtimeFeedbackReplay.ts"() {
|
|
26208
|
+
"use strict";
|
|
26209
|
+
import_node_path20 = __toESM(require("path"));
|
|
26210
|
+
import_args26 = __toESM(require("args"));
|
|
26211
|
+
import_chalk39 = __toESM(require("chalk"));
|
|
26212
|
+
init_runtimeFeedbackReplay();
|
|
26213
|
+
import_args26.default.option("runtimeEvidence", "Verified runtime evidence JSON");
|
|
26214
|
+
import_args26.default.option("outDir", "New writable directory for replay output");
|
|
26215
|
+
import_args26.default.option("runId", "Stable identifier for this replay attempt");
|
|
26216
|
+
flags25 = import_args26.default.parse(process.argv);
|
|
26217
|
+
projectRoot9 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
26218
|
+
runtimeFeedbackReplay = async () => {
|
|
26219
|
+
const runtimeEvidence2 = String(flags25.runtimeEvidence ?? "").trim();
|
|
26220
|
+
const outDir = String(flags25.outDir ?? "").trim();
|
|
26221
|
+
if (!runtimeEvidence2 || !outDir) {
|
|
26222
|
+
throw new Error(
|
|
26223
|
+
"Provide --runtimeEvidence and --outDir for runtime feedback replay."
|
|
26224
|
+
);
|
|
26225
|
+
}
|
|
26226
|
+
const verified = await runRuntimeFeedbackReplay({
|
|
26227
|
+
runtimeEvidencePath: import_node_path20.default.resolve(projectRoot9, runtimeEvidence2),
|
|
26228
|
+
outDir: import_node_path20.default.resolve(projectRoot9, outDir),
|
|
26229
|
+
runId: String(flags25.runId ?? "").trim() || void 0,
|
|
26230
|
+
projectRoot: projectRoot9
|
|
26231
|
+
});
|
|
26232
|
+
console.log(
|
|
26233
|
+
import_chalk39.default.green(
|
|
26234
|
+
`Runtime feedback replay sealed: ${verified.manifest.artifactId}`
|
|
26235
|
+
)
|
|
26236
|
+
);
|
|
26237
|
+
console.log(
|
|
26238
|
+
JSON.stringify(
|
|
26239
|
+
{
|
|
26240
|
+
bundleDir: verified.bundleDir,
|
|
26241
|
+
manifestPath: verified.manifestPath,
|
|
26242
|
+
replayEvidencePath: verified.replayEvidencePath
|
|
26243
|
+
},
|
|
26244
|
+
null,
|
|
26245
|
+
2
|
|
26246
|
+
)
|
|
26247
|
+
);
|
|
26248
|
+
};
|
|
26249
|
+
main34 = runtimeFeedbackReplay;
|
|
26250
|
+
}
|
|
26251
|
+
});
|
|
26252
|
+
|
|
26253
|
+
// src/lib/runtimeEvidenceSync.ts
|
|
26254
|
+
var import_node_child_process7, import_promises26, import_node_path21, import_node_util, execFileAsync, isExistingDestinationError2, safeSegment4, withTrailingSlash, dateParts2, buildRuntimeEvidenceRsyncArgs, receiptPath, compareBundles, listPendingRuntimeEvidenceBundles, markRuntimeEvidenceBundleProcessed, syncRuntimeEvidenceBundles;
|
|
26255
|
+
var init_runtimeEvidenceSync = __esm({
|
|
26256
|
+
"src/lib/runtimeEvidenceSync.ts"() {
|
|
26257
|
+
"use strict";
|
|
26258
|
+
import_node_child_process7 = require("child_process");
|
|
26259
|
+
import_promises26 = __toESM(require("fs/promises"));
|
|
26260
|
+
import_node_path21 = __toESM(require("path"));
|
|
26261
|
+
import_node_util = require("util");
|
|
26262
|
+
init_runtimeEvidenceArtifacts();
|
|
26263
|
+
init_runtimeEvidenceDeployment();
|
|
26264
|
+
execFileAsync = (0, import_node_util.promisify)(import_node_child_process7.execFile);
|
|
26265
|
+
isExistingDestinationError2 = (error) => {
|
|
26266
|
+
const code = error.code;
|
|
26267
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
26268
|
+
};
|
|
26269
|
+
safeSegment4 = (value, fallback) => {
|
|
26270
|
+
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
26271
|
+
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
26272
|
+
};
|
|
26273
|
+
withTrailingSlash = (value) => value.endsWith("/") ? value : `${value}/`;
|
|
26274
|
+
dateParts2 = (timestamp) => {
|
|
26275
|
+
const date = new Date(timestamp);
|
|
26276
|
+
return [
|
|
26277
|
+
String(date.getUTCFullYear()),
|
|
26278
|
+
String(date.getUTCMonth() + 1).padStart(2, "0"),
|
|
26279
|
+
String(date.getUTCDate()).padStart(2, "0")
|
|
26280
|
+
];
|
|
26281
|
+
};
|
|
26282
|
+
buildRuntimeEvidenceRsyncArgs = ({
|
|
26283
|
+
source,
|
|
26284
|
+
destination
|
|
26285
|
+
}) => [
|
|
26286
|
+
"--recursive",
|
|
26287
|
+
"--times",
|
|
26288
|
+
"--partial",
|
|
26289
|
+
"--partial-dir=.rsync-partial",
|
|
26290
|
+
"--prune-empty-dirs",
|
|
26291
|
+
withTrailingSlash(source),
|
|
26292
|
+
withTrailingSlash(destination)
|
|
26293
|
+
];
|
|
26294
|
+
receiptPath = (receiptsRoot, artifactId) => import_node_path21.default.join(receiptsRoot, `${safeSegment4(artifactId, "artifact")}.json`);
|
|
26295
|
+
compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
|
|
26296
|
+
listPendingRuntimeEvidenceBundles = async ({
|
|
26297
|
+
evidenceRoot,
|
|
26298
|
+
deploymentId
|
|
26299
|
+
}) => {
|
|
26300
|
+
const safeDeploymentId = safeSegment4(deploymentId, "production");
|
|
26301
|
+
const artifactsRoot = import_node_path21.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
26302
|
+
const receiptsRoot = import_node_path21.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
26303
|
+
const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
|
|
26304
|
+
const pending = [];
|
|
26305
|
+
for (const bundleDir of bundles) {
|
|
26306
|
+
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
26307
|
+
if (verified.manifest.deploymentId !== safeDeploymentId) continue;
|
|
26308
|
+
assertCurrentRuntimeEvidenceArtifact(verified.artifact);
|
|
26309
|
+
try {
|
|
26310
|
+
await import_promises26.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
|
|
26311
|
+
continue;
|
|
26312
|
+
} catch (error) {
|
|
26313
|
+
if (error.code !== "ENOENT") throw error;
|
|
26314
|
+
}
|
|
26315
|
+
pending.push(verified);
|
|
26316
|
+
}
|
|
26317
|
+
return pending.sort(compareBundles);
|
|
26318
|
+
};
|
|
26319
|
+
markRuntimeEvidenceBundleProcessed = async ({
|
|
26320
|
+
evidenceRoot,
|
|
26321
|
+
deploymentId,
|
|
26322
|
+
bundleDir,
|
|
26323
|
+
scorecardPath,
|
|
26324
|
+
runtimeFeedback
|
|
26325
|
+
}) => {
|
|
26326
|
+
const safeDeploymentId = safeSegment4(deploymentId, "production");
|
|
26327
|
+
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
26328
|
+
if (verified.manifest.deploymentId !== safeDeploymentId) {
|
|
26329
|
+
throw new Error(
|
|
26330
|
+
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
26331
|
+
);
|
|
26332
|
+
}
|
|
26333
|
+
const receiptsRoot = import_node_path21.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
26334
|
+
const finalPath = receiptPath(receiptsRoot, verified.manifest.artifactId);
|
|
26335
|
+
const temporaryPath = `${finalPath}.tmp-${process.pid}`;
|
|
26336
|
+
const receipt = {
|
|
26337
|
+
schemaVersion: runtimeFeedback ? 2 : 1,
|
|
26338
|
+
artifactId: verified.manifest.artifactId,
|
|
26339
|
+
payloadSha256: verified.manifest.payload.sha256,
|
|
26340
|
+
processedAt: Date.now(),
|
|
26341
|
+
scorecardPath: scorecardPath ?? null,
|
|
26342
|
+
...runtimeFeedback ? {
|
|
26343
|
+
runtimeFeedbackArtifactId: runtimeFeedback.artifactId,
|
|
26344
|
+
replayEvidenceSha256: runtimeFeedback.replayEvidenceSha256
|
|
26345
|
+
} : {}
|
|
26346
|
+
};
|
|
26347
|
+
await import_promises26.default.mkdir(receiptsRoot, { recursive: true });
|
|
26348
|
+
await import_promises26.default.writeFile(
|
|
26349
|
+
temporaryPath,
|
|
26350
|
+
`${JSON.stringify(receipt, null, 2)}
|
|
26351
|
+
`,
|
|
26352
|
+
"utf8"
|
|
26353
|
+
);
|
|
26354
|
+
await import_promises26.default.rename(temporaryPath, finalPath);
|
|
26355
|
+
return finalPath;
|
|
26356
|
+
};
|
|
26357
|
+
syncRuntimeEvidenceBundles = async ({
|
|
26358
|
+
source,
|
|
26359
|
+
evidenceRoot,
|
|
26360
|
+
deploymentId,
|
|
26361
|
+
runRsync = async (args37) => {
|
|
26362
|
+
const result = await execFileAsync("rsync", args37, {
|
|
26363
|
+
maxBuffer: 10 * 1024 * 1024
|
|
26364
|
+
});
|
|
26365
|
+
return { stdout: result.stdout, stderr: result.stderr };
|
|
26366
|
+
}
|
|
26367
|
+
}) => {
|
|
26368
|
+
const safeDeploymentId = safeSegment4(deploymentId, "production");
|
|
26369
|
+
const inboxRoot = import_node_path21.default.join(evidenceRoot, "inbox", safeDeploymentId);
|
|
26370
|
+
const artifactsRoot = import_node_path21.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
26371
|
+
await Promise.all([
|
|
26372
|
+
import_promises26.default.mkdir(inboxRoot, { recursive: true }),
|
|
26373
|
+
import_promises26.default.mkdir(artifactsRoot, { recursive: true })
|
|
26374
|
+
]);
|
|
26375
|
+
const rsyncArgs = buildRuntimeEvidenceRsyncArgs({
|
|
26376
|
+
source,
|
|
26377
|
+
destination: inboxRoot
|
|
26378
|
+
});
|
|
26379
|
+
const transfer = await runRsync(rsyncArgs);
|
|
26380
|
+
const discovered = await discoverRuntimeEvidenceBundles(inboxRoot);
|
|
26381
|
+
const received = [];
|
|
26382
|
+
for (const bundleDir of discovered) {
|
|
26383
|
+
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
26384
|
+
if (verified.manifest.deploymentId !== safeDeploymentId) {
|
|
26385
|
+
throw new Error(
|
|
26386
|
+
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
26387
|
+
);
|
|
26388
|
+
}
|
|
26389
|
+
assertCurrentRuntimeEvidenceArtifact(verified.artifact);
|
|
26390
|
+
const destinationDir = import_node_path21.default.join(
|
|
26391
|
+
artifactsRoot,
|
|
26392
|
+
...dateParts2(verified.manifest.window.endTime),
|
|
26393
|
+
safeSegment4(verified.manifest.artifactId, "artifact")
|
|
26394
|
+
);
|
|
26395
|
+
await import_promises26.default.mkdir(import_node_path21.default.dirname(destinationDir), { recursive: true });
|
|
26396
|
+
try {
|
|
26397
|
+
await import_promises26.default.rename(bundleDir, destinationDir);
|
|
26398
|
+
} catch (error) {
|
|
26399
|
+
if (!isExistingDestinationError2(error)) throw error;
|
|
26400
|
+
const existing = await verifyRuntimeEvidenceBundle(destinationDir);
|
|
26401
|
+
if (existing.manifest.payload.sha256 !== verified.manifest.payload.sha256) {
|
|
26402
|
+
throw new Error(
|
|
26403
|
+
`Conflicting runtime evidence artifact ${verified.manifest.artifactId}`
|
|
26404
|
+
);
|
|
26405
|
+
}
|
|
26406
|
+
await import_promises26.default.rm(bundleDir, { recursive: true, force: true });
|
|
26407
|
+
}
|
|
26408
|
+
received.push(await verifyRuntimeEvidenceBundle(destinationDir));
|
|
26409
|
+
}
|
|
26410
|
+
const pending = await listPendingRuntimeEvidenceBundles({
|
|
26411
|
+
evidenceRoot,
|
|
26412
|
+
deploymentId: safeDeploymentId
|
|
26413
|
+
});
|
|
26414
|
+
return {
|
|
26415
|
+
rsyncArgs,
|
|
26416
|
+
stdout: String(transfer.stdout ?? ""),
|
|
26417
|
+
stderr: String(transfer.stderr ?? ""),
|
|
26418
|
+
received,
|
|
26419
|
+
pending
|
|
26420
|
+
};
|
|
26421
|
+
};
|
|
26422
|
+
}
|
|
26423
|
+
});
|
|
26424
|
+
|
|
26425
|
+
// src/lib/runtimeFeedbackSync.ts
|
|
26426
|
+
var import_node_child_process8, import_promises27, import_node_path22, import_node_util2, execFileAsync2, isExistingDestinationError3, safeSegment5, dateParts3, syncRuntimeFeedbackReplayBundles;
|
|
26427
|
+
var init_runtimeFeedbackSync = __esm({
|
|
26428
|
+
"src/lib/runtimeFeedbackSync.ts"() {
|
|
26429
|
+
"use strict";
|
|
26430
|
+
import_node_child_process8 = require("child_process");
|
|
26431
|
+
import_promises27 = __toESM(require("fs/promises"));
|
|
26432
|
+
import_node_path22 = __toESM(require("path"));
|
|
26433
|
+
import_node_util2 = require("util");
|
|
26434
|
+
init_runtimeFeedbackArtifacts();
|
|
26435
|
+
init_runtimeEvidenceSync();
|
|
26436
|
+
execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process8.execFile);
|
|
26437
|
+
isExistingDestinationError3 = (error) => {
|
|
26438
|
+
const code = error.code;
|
|
26439
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
26440
|
+
};
|
|
26441
|
+
safeSegment5 = (value, fallback) => {
|
|
26442
|
+
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
26443
|
+
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
26444
|
+
};
|
|
26445
|
+
dateParts3 = (timestamp) => {
|
|
26446
|
+
const date = new Date(timestamp);
|
|
26447
|
+
return [
|
|
26448
|
+
String(date.getUTCFullYear()),
|
|
26449
|
+
String(date.getUTCMonth() + 1).padStart(2, "0"),
|
|
26450
|
+
String(date.getUTCDate()).padStart(2, "0")
|
|
26451
|
+
];
|
|
26452
|
+
};
|
|
26453
|
+
syncRuntimeFeedbackReplayBundles = async ({
|
|
26454
|
+
source,
|
|
26455
|
+
feedbackRoot,
|
|
26456
|
+
deploymentId,
|
|
26457
|
+
runRsync = async (args37) => {
|
|
26458
|
+
const result = await execFileAsync2("rsync", args37, {
|
|
26459
|
+
maxBuffer: 10 * 1024 * 1024
|
|
26460
|
+
});
|
|
26461
|
+
return { stdout: result.stdout, stderr: result.stderr };
|
|
26462
|
+
}
|
|
26463
|
+
}) => {
|
|
26464
|
+
const safeDeploymentId = safeSegment5(deploymentId, "production");
|
|
26465
|
+
const inboxRoot = import_node_path22.default.join(feedbackRoot, "inbox", safeDeploymentId);
|
|
26466
|
+
const artifactsRoot = import_node_path22.default.join(feedbackRoot, "artifacts", safeDeploymentId);
|
|
26467
|
+
await Promise.all([
|
|
26468
|
+
import_promises27.default.mkdir(inboxRoot, { recursive: true }),
|
|
26469
|
+
import_promises27.default.mkdir(artifactsRoot, { recursive: true })
|
|
26470
|
+
]);
|
|
26471
|
+
const rsyncArgs = buildRuntimeEvidenceRsyncArgs({
|
|
26472
|
+
source,
|
|
26473
|
+
destination: inboxRoot
|
|
26474
|
+
});
|
|
26475
|
+
const transfer = await runRsync(rsyncArgs);
|
|
26476
|
+
const discovered = await discoverRuntimeFeedbackReplayBundles(inboxRoot);
|
|
26477
|
+
const received = [];
|
|
26478
|
+
for (const bundleDir of discovered) {
|
|
26479
|
+
const verified = await verifyRuntimeFeedbackReplayBundle(bundleDir);
|
|
26480
|
+
if (verified.manifest.deploymentId !== safeDeploymentId) {
|
|
26481
|
+
throw new Error(
|
|
26482
|
+
`Runtime feedback deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
26483
|
+
);
|
|
26484
|
+
}
|
|
26485
|
+
const destinationDir = import_node_path22.default.join(
|
|
26486
|
+
artifactsRoot,
|
|
26487
|
+
...dateParts3(verified.manifest.window.endTime),
|
|
26488
|
+
safeSegment5(verified.manifest.runtimeEvidence.artifactId, "artifact"),
|
|
26489
|
+
safeSegment5(verified.manifest.runId, "run")
|
|
26490
|
+
);
|
|
26491
|
+
await import_promises27.default.mkdir(import_node_path22.default.dirname(destinationDir), { recursive: true });
|
|
26492
|
+
try {
|
|
26493
|
+
await import_promises27.default.rename(bundleDir, destinationDir);
|
|
26494
|
+
} catch (error) {
|
|
26495
|
+
if (!isExistingDestinationError3(error)) throw error;
|
|
26496
|
+
const existing = await verifyRuntimeFeedbackReplayBundle(destinationDir);
|
|
26497
|
+
if (existing.manifest.payloads.replayEvidence.sha256 !== verified.manifest.payloads.replayEvidence.sha256) {
|
|
26498
|
+
throw new Error(
|
|
26499
|
+
`Conflicting runtime feedback replay ${verified.manifest.artifactId}`
|
|
26500
|
+
);
|
|
26501
|
+
}
|
|
26502
|
+
await import_promises27.default.rm(bundleDir, { recursive: true, force: true });
|
|
26503
|
+
}
|
|
26504
|
+
received.push(await verifyRuntimeFeedbackReplayBundle(destinationDir));
|
|
26505
|
+
}
|
|
26506
|
+
return {
|
|
26507
|
+
rsyncArgs,
|
|
26508
|
+
stdout: String(transfer.stdout ?? ""),
|
|
26509
|
+
stderr: String(transfer.stderr ?? ""),
|
|
26510
|
+
received
|
|
26511
|
+
};
|
|
26512
|
+
};
|
|
26513
|
+
}
|
|
26514
|
+
});
|
|
26515
|
+
|
|
26516
|
+
// src/scripts/runtimeFeedbackSync.ts
|
|
26517
|
+
var runtimeFeedbackSync_exports = {};
|
|
26518
|
+
__export(runtimeFeedbackSync_exports, {
|
|
26519
|
+
main: () => main35,
|
|
26520
|
+
runtimeFeedbackSync: () => runtimeFeedbackSync
|
|
26521
|
+
});
|
|
26522
|
+
var import_node_path23, import_args27, import_chalk40, flags26, projectRoot10, runtimeFeedbackSync, main35;
|
|
26523
|
+
var init_runtimeFeedbackSync2 = __esm({
|
|
26524
|
+
"src/scripts/runtimeFeedbackSync.ts"() {
|
|
26525
|
+
"use strict";
|
|
26526
|
+
import_node_path23 = __toESM(require("path"));
|
|
26527
|
+
import_args27 = __toESM(require("args"));
|
|
26528
|
+
import_chalk40 = __toESM(require("chalk"));
|
|
26529
|
+
init_runtimeFeedbackSync();
|
|
26530
|
+
import_args27.default.option(
|
|
26531
|
+
"source",
|
|
26532
|
+
"Rsync source ending at the runtime feedback ready directory",
|
|
26533
|
+
process.env.RUNTIME_FEEDBACK_RSYNC_SOURCE
|
|
26534
|
+
);
|
|
26535
|
+
import_args27.default.option(
|
|
26536
|
+
"deployment",
|
|
26537
|
+
"Deployment id expected in runtime feedback manifests",
|
|
26538
|
+
process.env.RUNTIME_EVIDENCE_DEPLOYMENT_ID || "production"
|
|
26539
|
+
);
|
|
26540
|
+
import_args27.default.option(
|
|
26541
|
+
"dir",
|
|
26542
|
+
"Local runtime feedback storage root",
|
|
26543
|
+
process.env.RUNTIME_FEEDBACK_LOCAL_DIR || "data/runtime-feedback"
|
|
26544
|
+
);
|
|
26545
|
+
flags26 = import_args27.default.parse(process.argv);
|
|
26546
|
+
projectRoot10 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
26547
|
+
runtimeFeedbackSync = async () => {
|
|
26548
|
+
const source = String(flags26.source ?? "").trim();
|
|
26549
|
+
if (!source) {
|
|
26550
|
+
throw new Error(
|
|
26551
|
+
"Provide --source or RUNTIME_FEEDBACK_RSYNC_SOURCE for runtime feedback sync."
|
|
26552
|
+
);
|
|
26553
|
+
}
|
|
26554
|
+
const feedbackRoot = import_node_path23.default.resolve(projectRoot10, String(flags26.dir));
|
|
26555
|
+
const result = await syncRuntimeFeedbackReplayBundles({
|
|
26556
|
+
source,
|
|
26557
|
+
feedbackRoot,
|
|
26558
|
+
deploymentId: String(flags26.deployment)
|
|
26559
|
+
});
|
|
26560
|
+
console.log(
|
|
26561
|
+
import_chalk40.default.green(
|
|
26562
|
+
`Runtime feedback sync completed: received=${result.received.length}`
|
|
26563
|
+
)
|
|
26564
|
+
);
|
|
26565
|
+
console.log(
|
|
26566
|
+
JSON.stringify(
|
|
26567
|
+
{
|
|
26568
|
+
feedbackRoot,
|
|
26569
|
+
received: result.received.map((bundle) => ({
|
|
26570
|
+
artifactId: bundle.manifest.artifactId,
|
|
26571
|
+
bundleDir: bundle.bundleDir,
|
|
26572
|
+
replayEvidencePath: bundle.replayEvidencePath,
|
|
26573
|
+
runtimeEvidence: bundle.manifest.runtimeEvidence
|
|
26574
|
+
}))
|
|
26575
|
+
},
|
|
26576
|
+
null,
|
|
26577
|
+
2
|
|
26578
|
+
)
|
|
26579
|
+
);
|
|
26580
|
+
};
|
|
26581
|
+
main35 = runtimeFeedbackSync;
|
|
26582
|
+
}
|
|
26583
|
+
});
|
|
26584
|
+
|
|
25609
26585
|
// src/lib/runtimeLineage.ts
|
|
25610
|
-
var
|
|
26586
|
+
var import_node_crypto13, normalizeForStableJson2, resolveRuntimeMaxLossValue, fingerprintRuntimeValue, buildRuntimeLineage, runtimeLineageKey, runtimeLineagesMatch, runtimeLineagesComparable;
|
|
25611
26587
|
var init_runtimeLineage = __esm({
|
|
25612
26588
|
"src/lib/runtimeLineage.ts"() {
|
|
25613
26589
|
"use strict";
|
|
25614
|
-
|
|
26590
|
+
import_node_crypto13 = require("crypto");
|
|
25615
26591
|
normalizeForStableJson2 = (value) => {
|
|
25616
26592
|
if (Array.isArray(value)) {
|
|
25617
26593
|
return value.map(normalizeForStableJson2);
|
|
@@ -25636,7 +26612,7 @@ var init_runtimeLineage = __esm({
|
|
|
25636
26612
|
);
|
|
25637
26613
|
return Number.isFinite(maxLossValue) ? maxLossValue : null;
|
|
25638
26614
|
};
|
|
25639
|
-
fingerprintRuntimeValue = (value) => (0,
|
|
26615
|
+
fingerprintRuntimeValue = (value) => (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify(normalizeForStableJson2(value))).digest("hex").slice(0, 16);
|
|
25640
26616
|
buildRuntimeLineage = async ({
|
|
25641
26617
|
strategyRevision,
|
|
25642
26618
|
deploymentCompositionId,
|
|
@@ -25687,50 +26663,51 @@ var init_runtimeLineage = __esm({
|
|
|
25687
26663
|
// src/scripts/runtimeEvidence.ts
|
|
25688
26664
|
var runtimeEvidence_exports = {};
|
|
25689
26665
|
__export(runtimeEvidence_exports, {
|
|
25690
|
-
main: () =>
|
|
26666
|
+
main: () => main36,
|
|
25691
26667
|
runtimeEvidence: () => runtimeEvidence
|
|
25692
26668
|
});
|
|
25693
|
-
var
|
|
26669
|
+
var import_promises28, import_node_path24, import_args28, import_chalk41, flags27, projectRoot11, toEpochMs3, resolveWindow2, parseStrategyFilter2, runtimeEvidence, main36;
|
|
25694
26670
|
var init_runtimeEvidence = __esm({
|
|
25695
26671
|
"src/scripts/runtimeEvidence.ts"() {
|
|
25696
26672
|
"use strict";
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
26673
|
+
import_promises28 = __toESM(require("fs/promises"));
|
|
26674
|
+
import_node_path24 = __toESM(require("path"));
|
|
26675
|
+
import_args28 = __toESM(require("args"));
|
|
26676
|
+
import_chalk41 = __toESM(require("chalk"));
|
|
25701
26677
|
init_runtimeDebugEvidence();
|
|
25702
26678
|
init_runtimeEvidenceArtifacts();
|
|
25703
26679
|
init_runtimeLineage();
|
|
26680
|
+
init_runtimeEvidenceProducer();
|
|
25704
26681
|
init_runtimeEvidenceDeployment();
|
|
25705
|
-
|
|
25706
|
-
|
|
26682
|
+
import_args28.default.option(["u", "user"], "Use user config", "root");
|
|
26683
|
+
import_args28.default.option(
|
|
25707
26684
|
["S", "startTime"],
|
|
25708
26685
|
"Window start timestamp, seconds/ms, or ISO date"
|
|
25709
26686
|
);
|
|
25710
|
-
|
|
25711
|
-
|
|
26687
|
+
import_args28.default.option(["E", "endTime"], "Window end timestamp, seconds/ms, or ISO date");
|
|
26688
|
+
import_args28.default.option(
|
|
25712
26689
|
["H", "hours"],
|
|
25713
26690
|
"Fallback window in hours when start/end are omitted",
|
|
25714
26691
|
24
|
|
25715
26692
|
);
|
|
25716
|
-
|
|
26693
|
+
import_args28.default.option(
|
|
25717
26694
|
"daily",
|
|
25718
26695
|
"Use the latest complete 21:00 MSK to 21:00 MSK window",
|
|
25719
26696
|
false
|
|
25720
26697
|
);
|
|
25721
|
-
|
|
25722
|
-
|
|
25723
|
-
|
|
26698
|
+
import_args28.default.option(["s", "strategy"], "Strategy filter, comma-separated");
|
|
26699
|
+
import_args28.default.option(["o", "out"], "Output JSON path", "output/runtime-evidence.json");
|
|
26700
|
+
import_args28.default.option(
|
|
25724
26701
|
"publishDir",
|
|
25725
26702
|
"Publish an immutable bundle under <dir>/ready/<deployment>"
|
|
25726
26703
|
);
|
|
25727
|
-
|
|
26704
|
+
import_args28.default.option(
|
|
25728
26705
|
"deployment",
|
|
25729
26706
|
"Deployment id used by immutable evidence bundles",
|
|
25730
26707
|
process.env.RUNTIME_EVIDENCE_DEPLOYMENT_ID || "production"
|
|
25731
26708
|
);
|
|
25732
|
-
|
|
25733
|
-
|
|
26709
|
+
flags27 = import_args28.default.parse(process.argv);
|
|
26710
|
+
projectRoot11 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
25734
26711
|
toEpochMs3 = (value) => {
|
|
25735
26712
|
if (value == null || value === "") {
|
|
25736
26713
|
return null;
|
|
@@ -25744,11 +26721,11 @@ var init_runtimeEvidence = __esm({
|
|
|
25744
26721
|
return Number.isFinite(parsed) ? parsed : null;
|
|
25745
26722
|
};
|
|
25746
26723
|
resolveWindow2 = () => {
|
|
25747
|
-
const explicitStartTime = toEpochMs3(
|
|
25748
|
-
const explicitEndTime = toEpochMs3(
|
|
26724
|
+
const explicitStartTime = toEpochMs3(flags27.startTime);
|
|
26725
|
+
const explicitEndTime = toEpochMs3(flags27.endTime);
|
|
25749
26726
|
const now2 = Date.now();
|
|
25750
26727
|
const dailyEndTime = (() => {
|
|
25751
|
-
if (!
|
|
26728
|
+
if (!flags27.daily || explicitStartTime != null || explicitEndTime != null) {
|
|
25752
26729
|
return null;
|
|
25753
26730
|
}
|
|
25754
26731
|
const date = new Date(now2);
|
|
@@ -25763,7 +26740,7 @@ var init_runtimeEvidence = __esm({
|
|
|
25763
26740
|
const endTime = explicitEndTime ?? dailyEndTime ?? now2;
|
|
25764
26741
|
const hours = Math.max(
|
|
25765
26742
|
1,
|
|
25766
|
-
Number.parseInt(String(
|
|
26743
|
+
Number.parseInt(String(flags27.hours ?? 24), 10) || 24
|
|
25767
26744
|
);
|
|
25768
26745
|
const startTime = explicitStartTime ?? endTime - hours * 60 * 60 * 1e3;
|
|
25769
26746
|
if (startTime >= endTime) {
|
|
@@ -25780,16 +26757,21 @@ var init_runtimeEvidence = __esm({
|
|
|
25780
26757
|
parseStrategyFilter2 = (value) => String(value ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
25781
26758
|
runtimeEvidence = async () => {
|
|
25782
26759
|
const { startTime, endTime, source } = resolveWindow2();
|
|
25783
|
-
const deploymentId = String(
|
|
26760
|
+
const deploymentId = String(flags27.deployment);
|
|
26761
|
+
const publishDir = String(flags27.publishDir ?? "").trim();
|
|
26762
|
+
const producer = await resolveRuntimeEvidenceProducer({
|
|
26763
|
+
projectRoot: projectRoot11,
|
|
26764
|
+
required: Boolean(publishDir)
|
|
26765
|
+
});
|
|
25784
26766
|
const deploymentSnapshot = await resolveRuntimeEvidenceDeploymentSnapshot({
|
|
25785
|
-
userName: String(
|
|
25786
|
-
projectRoot:
|
|
26767
|
+
userName: String(flags27.user),
|
|
26768
|
+
projectRoot: projectRoot11,
|
|
25787
26769
|
deploymentId
|
|
25788
26770
|
});
|
|
25789
26771
|
const activeStrategies = activeRuntimeEvidenceStrategies(
|
|
25790
26772
|
deploymentSnapshot
|
|
25791
26773
|
).map(({ strategyName }) => strategyName);
|
|
25792
|
-
const requestedStrategies = parseStrategyFilter2(
|
|
26774
|
+
const requestedStrategies = parseStrategyFilter2(flags27.strategy);
|
|
25793
26775
|
const strategies = requestedStrategies.length ? requestedStrategies : activeStrategies;
|
|
25794
26776
|
const declaredStrategies = new Set(
|
|
25795
26777
|
deploymentSnapshot.strategies.map(({ strategyName }) => strategyName)
|
|
@@ -25803,7 +26785,7 @@ var init_runtimeEvidence = __esm({
|
|
|
25803
26785
|
);
|
|
25804
26786
|
}
|
|
25805
26787
|
const evidence = await collectRuntimeDebugEvidence({
|
|
25806
|
-
userName:
|
|
26788
|
+
userName: flags27.user,
|
|
25807
26789
|
startTime,
|
|
25808
26790
|
endTime,
|
|
25809
26791
|
strategies,
|
|
@@ -25837,7 +26819,7 @@ var init_runtimeEvidence = __esm({
|
|
|
25837
26819
|
})
|
|
25838
26820
|
);
|
|
25839
26821
|
const runtime = buildRuntimeEvidenceReportPayload({
|
|
25840
|
-
userName:
|
|
26822
|
+
userName: flags27.user,
|
|
25841
26823
|
startTime,
|
|
25842
26824
|
endTime,
|
|
25843
26825
|
signals: currentSignals,
|
|
@@ -25852,7 +26834,8 @@ var init_runtimeEvidence = __esm({
|
|
|
25852
26834
|
const artifact = {
|
|
25853
26835
|
reportType: "runtime-evidence",
|
|
25854
26836
|
generatedAt: Date.now(),
|
|
25855
|
-
|
|
26837
|
+
...producer ? { producer } : {},
|
|
26838
|
+
userName: flags27.user,
|
|
25856
26839
|
window: {
|
|
25857
26840
|
startTime,
|
|
25858
26841
|
endTime,
|
|
@@ -25864,15 +26847,14 @@ var init_runtimeEvidence = __esm({
|
|
|
25864
26847
|
deployment,
|
|
25865
26848
|
runtime
|
|
25866
26849
|
};
|
|
25867
|
-
const outPath =
|
|
25868
|
-
await
|
|
25869
|
-
await
|
|
26850
|
+
const outPath = import_node_path24.default.resolve(projectRoot11, String(flags27.out));
|
|
26851
|
+
await import_promises28.default.mkdir(import_node_path24.default.dirname(outPath), { recursive: true });
|
|
26852
|
+
await import_promises28.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
|
|
25870
26853
|
`, "utf8");
|
|
25871
|
-
const publishDir = String(flags25.publishDir ?? "").trim();
|
|
25872
26854
|
const published = publishDir ? await publishRuntimeEvidenceBundle({
|
|
25873
|
-
publishRoot:
|
|
26855
|
+
publishRoot: import_node_path24.default.resolve(projectRoot11, publishDir),
|
|
25874
26856
|
deploymentId,
|
|
25875
|
-
userName: String(
|
|
26857
|
+
userName: String(flags27.user),
|
|
25876
26858
|
startTime,
|
|
25877
26859
|
endTime,
|
|
25878
26860
|
artifact,
|
|
@@ -25884,9 +26866,9 @@ var init_runtimeEvidence = __esm({
|
|
|
25884
26866
|
...currentLineageScopes.map((scope) => scope.lineage)
|
|
25885
26867
|
].filter((lineage) => lineage != null).map(runtimeLineageKey).filter((key, index, values) => values.indexOf(key) === index)
|
|
25886
26868
|
}) : null;
|
|
25887
|
-
console.log(
|
|
26869
|
+
console.log(import_chalk41.default.green(`Wrote ${outPath}`));
|
|
25888
26870
|
if (published) {
|
|
25889
|
-
console.log(
|
|
26871
|
+
console.log(import_chalk41.default.green(`Published ${published.bundleDir}`));
|
|
25890
26872
|
}
|
|
25891
26873
|
console.log(
|
|
25892
26874
|
JSON.stringify(
|
|
@@ -25899,223 +26881,56 @@ var init_runtimeEvidence = __esm({
|
|
|
25899
26881
|
)
|
|
25900
26882
|
);
|
|
25901
26883
|
};
|
|
25902
|
-
|
|
25903
|
-
}
|
|
25904
|
-
});
|
|
25905
|
-
|
|
25906
|
-
// src/lib/runtimeEvidenceSync.ts
|
|
25907
|
-
var import_node_child_process6, import_promises24, import_node_path18, import_node_util, execFileAsync, isExistingDestinationError2, safeSegment2, withTrailingSlash, dateParts2, buildRuntimeEvidenceRsyncArgs, receiptPath, compareBundles, listPendingRuntimeEvidenceBundles, markRuntimeEvidenceBundleProcessed, syncRuntimeEvidenceBundles;
|
|
25908
|
-
var init_runtimeEvidenceSync = __esm({
|
|
25909
|
-
"src/lib/runtimeEvidenceSync.ts"() {
|
|
25910
|
-
"use strict";
|
|
25911
|
-
import_node_child_process6 = require("child_process");
|
|
25912
|
-
import_promises24 = __toESM(require("fs/promises"));
|
|
25913
|
-
import_node_path18 = __toESM(require("path"));
|
|
25914
|
-
import_node_util = require("util");
|
|
25915
|
-
init_runtimeEvidenceArtifacts();
|
|
25916
|
-
init_runtimeEvidenceDeployment();
|
|
25917
|
-
execFileAsync = (0, import_node_util.promisify)(import_node_child_process6.execFile);
|
|
25918
|
-
isExistingDestinationError2 = (error) => {
|
|
25919
|
-
const code = error.code;
|
|
25920
|
-
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
25921
|
-
};
|
|
25922
|
-
safeSegment2 = (value, fallback) => {
|
|
25923
|
-
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
25924
|
-
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
25925
|
-
};
|
|
25926
|
-
withTrailingSlash = (value) => value.endsWith("/") ? value : `${value}/`;
|
|
25927
|
-
dateParts2 = (timestamp) => {
|
|
25928
|
-
const date = new Date(timestamp);
|
|
25929
|
-
return [
|
|
25930
|
-
String(date.getUTCFullYear()),
|
|
25931
|
-
String(date.getUTCMonth() + 1).padStart(2, "0"),
|
|
25932
|
-
String(date.getUTCDate()).padStart(2, "0")
|
|
25933
|
-
];
|
|
25934
|
-
};
|
|
25935
|
-
buildRuntimeEvidenceRsyncArgs = ({
|
|
25936
|
-
source,
|
|
25937
|
-
destination
|
|
25938
|
-
}) => [
|
|
25939
|
-
"--recursive",
|
|
25940
|
-
"--times",
|
|
25941
|
-
"--partial",
|
|
25942
|
-
"--partial-dir=.rsync-partial",
|
|
25943
|
-
"--prune-empty-dirs",
|
|
25944
|
-
withTrailingSlash(source),
|
|
25945
|
-
withTrailingSlash(destination)
|
|
25946
|
-
];
|
|
25947
|
-
receiptPath = (receiptsRoot, artifactId) => import_node_path18.default.join(receiptsRoot, `${safeSegment2(artifactId, "artifact")}.json`);
|
|
25948
|
-
compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
|
|
25949
|
-
listPendingRuntimeEvidenceBundles = async ({
|
|
25950
|
-
evidenceRoot,
|
|
25951
|
-
deploymentId
|
|
25952
|
-
}) => {
|
|
25953
|
-
const safeDeploymentId = safeSegment2(deploymentId, "production");
|
|
25954
|
-
const artifactsRoot = import_node_path18.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
25955
|
-
const receiptsRoot = import_node_path18.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
25956
|
-
const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
|
|
25957
|
-
const pending = [];
|
|
25958
|
-
for (const bundleDir of bundles) {
|
|
25959
|
-
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
25960
|
-
if (verified.manifest.deploymentId !== safeDeploymentId) continue;
|
|
25961
|
-
assertCurrentRuntimeEvidenceArtifact(verified.artifact);
|
|
25962
|
-
try {
|
|
25963
|
-
await import_promises24.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
|
|
25964
|
-
continue;
|
|
25965
|
-
} catch (error) {
|
|
25966
|
-
if (error.code !== "ENOENT") throw error;
|
|
25967
|
-
}
|
|
25968
|
-
pending.push(verified);
|
|
25969
|
-
}
|
|
25970
|
-
return pending.sort(compareBundles);
|
|
25971
|
-
};
|
|
25972
|
-
markRuntimeEvidenceBundleProcessed = async ({
|
|
25973
|
-
evidenceRoot,
|
|
25974
|
-
deploymentId,
|
|
25975
|
-
bundleDir,
|
|
25976
|
-
scorecardPath
|
|
25977
|
-
}) => {
|
|
25978
|
-
const safeDeploymentId = safeSegment2(deploymentId, "production");
|
|
25979
|
-
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
25980
|
-
if (verified.manifest.deploymentId !== safeDeploymentId) {
|
|
25981
|
-
throw new Error(
|
|
25982
|
-
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
25983
|
-
);
|
|
25984
|
-
}
|
|
25985
|
-
const receiptsRoot = import_node_path18.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
25986
|
-
const finalPath = receiptPath(receiptsRoot, verified.manifest.artifactId);
|
|
25987
|
-
const temporaryPath = `${finalPath}.tmp-${process.pid}`;
|
|
25988
|
-
const receipt = {
|
|
25989
|
-
schemaVersion: 1,
|
|
25990
|
-
artifactId: verified.manifest.artifactId,
|
|
25991
|
-
payloadSha256: verified.manifest.payload.sha256,
|
|
25992
|
-
processedAt: Date.now(),
|
|
25993
|
-
scorecardPath: scorecardPath ?? null
|
|
25994
|
-
};
|
|
25995
|
-
await import_promises24.default.mkdir(receiptsRoot, { recursive: true });
|
|
25996
|
-
await import_promises24.default.writeFile(
|
|
25997
|
-
temporaryPath,
|
|
25998
|
-
`${JSON.stringify(receipt, null, 2)}
|
|
25999
|
-
`,
|
|
26000
|
-
"utf8"
|
|
26001
|
-
);
|
|
26002
|
-
await import_promises24.default.rename(temporaryPath, finalPath);
|
|
26003
|
-
return finalPath;
|
|
26004
|
-
};
|
|
26005
|
-
syncRuntimeEvidenceBundles = async ({
|
|
26006
|
-
source,
|
|
26007
|
-
evidenceRoot,
|
|
26008
|
-
deploymentId,
|
|
26009
|
-
runRsync = async (args35) => {
|
|
26010
|
-
const result = await execFileAsync("rsync", args35, {
|
|
26011
|
-
maxBuffer: 10 * 1024 * 1024
|
|
26012
|
-
});
|
|
26013
|
-
return { stdout: result.stdout, stderr: result.stderr };
|
|
26014
|
-
}
|
|
26015
|
-
}) => {
|
|
26016
|
-
const safeDeploymentId = safeSegment2(deploymentId, "production");
|
|
26017
|
-
const inboxRoot = import_node_path18.default.join(evidenceRoot, "inbox", safeDeploymentId);
|
|
26018
|
-
const artifactsRoot = import_node_path18.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
26019
|
-
await Promise.all([
|
|
26020
|
-
import_promises24.default.mkdir(inboxRoot, { recursive: true }),
|
|
26021
|
-
import_promises24.default.mkdir(artifactsRoot, { recursive: true })
|
|
26022
|
-
]);
|
|
26023
|
-
const rsyncArgs = buildRuntimeEvidenceRsyncArgs({
|
|
26024
|
-
source,
|
|
26025
|
-
destination: inboxRoot
|
|
26026
|
-
});
|
|
26027
|
-
const transfer = await runRsync(rsyncArgs);
|
|
26028
|
-
const discovered = await discoverRuntimeEvidenceBundles(inboxRoot);
|
|
26029
|
-
const received = [];
|
|
26030
|
-
for (const bundleDir of discovered) {
|
|
26031
|
-
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
26032
|
-
if (verified.manifest.deploymentId !== safeDeploymentId) {
|
|
26033
|
-
throw new Error(
|
|
26034
|
-
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
26035
|
-
);
|
|
26036
|
-
}
|
|
26037
|
-
assertCurrentRuntimeEvidenceArtifact(verified.artifact);
|
|
26038
|
-
const destinationDir = import_node_path18.default.join(
|
|
26039
|
-
artifactsRoot,
|
|
26040
|
-
...dateParts2(verified.manifest.window.endTime),
|
|
26041
|
-
safeSegment2(verified.manifest.artifactId, "artifact")
|
|
26042
|
-
);
|
|
26043
|
-
await import_promises24.default.mkdir(import_node_path18.default.dirname(destinationDir), { recursive: true });
|
|
26044
|
-
try {
|
|
26045
|
-
await import_promises24.default.rename(bundleDir, destinationDir);
|
|
26046
|
-
} catch (error) {
|
|
26047
|
-
if (!isExistingDestinationError2(error)) throw error;
|
|
26048
|
-
const existing = await verifyRuntimeEvidenceBundle(destinationDir);
|
|
26049
|
-
if (existing.manifest.payload.sha256 !== verified.manifest.payload.sha256) {
|
|
26050
|
-
throw new Error(
|
|
26051
|
-
`Conflicting runtime evidence artifact ${verified.manifest.artifactId}`
|
|
26052
|
-
);
|
|
26053
|
-
}
|
|
26054
|
-
await import_promises24.default.rm(bundleDir, { recursive: true, force: true });
|
|
26055
|
-
}
|
|
26056
|
-
received.push(await verifyRuntimeEvidenceBundle(destinationDir));
|
|
26057
|
-
}
|
|
26058
|
-
const pending = await listPendingRuntimeEvidenceBundles({
|
|
26059
|
-
evidenceRoot,
|
|
26060
|
-
deploymentId: safeDeploymentId
|
|
26061
|
-
});
|
|
26062
|
-
return {
|
|
26063
|
-
rsyncArgs,
|
|
26064
|
-
stdout: String(transfer.stdout ?? ""),
|
|
26065
|
-
stderr: String(transfer.stderr ?? ""),
|
|
26066
|
-
received,
|
|
26067
|
-
pending
|
|
26068
|
-
};
|
|
26069
|
-
};
|
|
26884
|
+
main36 = runtimeEvidence;
|
|
26070
26885
|
}
|
|
26071
26886
|
});
|
|
26072
26887
|
|
|
26073
26888
|
// src/scripts/runtimeEvidenceSync.ts
|
|
26074
26889
|
var runtimeEvidenceSync_exports = {};
|
|
26075
26890
|
__export(runtimeEvidenceSync_exports, {
|
|
26076
|
-
main: () =>
|
|
26891
|
+
main: () => main37,
|
|
26077
26892
|
runtimeEvidenceSync: () => runtimeEvidenceSync
|
|
26078
26893
|
});
|
|
26079
|
-
var
|
|
26894
|
+
var import_node_path25, import_args29, import_chalk42, flags28, projectRoot12, runtimeEvidenceSync, main37;
|
|
26080
26895
|
var init_runtimeEvidenceSync2 = __esm({
|
|
26081
26896
|
"src/scripts/runtimeEvidenceSync.ts"() {
|
|
26082
26897
|
"use strict";
|
|
26083
|
-
|
|
26084
|
-
|
|
26085
|
-
|
|
26898
|
+
import_node_path25 = __toESM(require("path"));
|
|
26899
|
+
import_args29 = __toESM(require("args"));
|
|
26900
|
+
import_chalk42 = __toESM(require("chalk"));
|
|
26086
26901
|
init_runtimeEvidenceSync();
|
|
26087
|
-
|
|
26902
|
+
import_args29.default.option(
|
|
26088
26903
|
"source",
|
|
26089
26904
|
"Rsync source ending at the deployment ready directory",
|
|
26090
26905
|
process.env.RUNTIME_EVIDENCE_RSYNC_SOURCE
|
|
26091
26906
|
);
|
|
26092
|
-
|
|
26907
|
+
import_args29.default.option(
|
|
26093
26908
|
"deployment",
|
|
26094
26909
|
"Deployment id expected in artifact manifests",
|
|
26095
26910
|
process.env.RUNTIME_EVIDENCE_DEPLOYMENT_ID || "production"
|
|
26096
26911
|
);
|
|
26097
|
-
|
|
26912
|
+
import_args29.default.option(
|
|
26098
26913
|
"dir",
|
|
26099
26914
|
"Local evidence storage root",
|
|
26100
26915
|
process.env.RUNTIME_EVIDENCE_LOCAL_DIR || "data/runtime-evidence"
|
|
26101
26916
|
);
|
|
26102
|
-
|
|
26103
|
-
|
|
26917
|
+
flags28 = import_args29.default.parse(process.argv);
|
|
26918
|
+
projectRoot12 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
26104
26919
|
runtimeEvidenceSync = async () => {
|
|
26105
|
-
const source = String(
|
|
26920
|
+
const source = String(flags28.source ?? "").trim();
|
|
26106
26921
|
if (!source) {
|
|
26107
26922
|
throw new Error(
|
|
26108
26923
|
"Provide --source or RUNTIME_EVIDENCE_RSYNC_SOURCE for runtime evidence sync."
|
|
26109
26924
|
);
|
|
26110
26925
|
}
|
|
26111
|
-
const evidenceRoot =
|
|
26926
|
+
const evidenceRoot = import_node_path25.default.resolve(projectRoot12, String(flags28.dir));
|
|
26112
26927
|
const result = await syncRuntimeEvidenceBundles({
|
|
26113
26928
|
source,
|
|
26114
26929
|
evidenceRoot,
|
|
26115
|
-
deploymentId: String(
|
|
26930
|
+
deploymentId: String(flags28.deployment)
|
|
26116
26931
|
});
|
|
26117
26932
|
console.log(
|
|
26118
|
-
|
|
26933
|
+
import_chalk42.default.green(
|
|
26119
26934
|
`Runtime evidence sync completed: received=${result.received.length} pending=${result.pending.length}`
|
|
26120
26935
|
)
|
|
26121
26936
|
);
|
|
@@ -26140,7 +26955,7 @@ var init_runtimeEvidenceSync2 = __esm({
|
|
|
26140
26955
|
)
|
|
26141
26956
|
);
|
|
26142
26957
|
};
|
|
26143
|
-
|
|
26958
|
+
main37 = runtimeEvidenceSync;
|
|
26144
26959
|
}
|
|
26145
26960
|
});
|
|
26146
26961
|
|
|
@@ -27112,7 +27927,7 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
27112
27927
|
let artifact;
|
|
27113
27928
|
try {
|
|
27114
27929
|
const parsed = JSON.parse(
|
|
27115
|
-
await
|
|
27930
|
+
await import_promises29.default.readFile(reference.path, "utf8")
|
|
27116
27931
|
);
|
|
27117
27932
|
assert3(
|
|
27118
27933
|
parsed != null && typeof parsed === "object" && !Array.isArray(parsed),
|
|
@@ -27259,13 +28074,13 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
27259
28074
|
})
|
|
27260
28075
|
);
|
|
27261
28076
|
}
|
|
27262
|
-
var
|
|
28077
|
+
var import_node_crypto14, import_promises29, import_node_path26, import_types9, import_strategyReleaseEvidence2, SHA256_RE2, LINEAGE_FINGERPRINT_RE, STRATEGY_REVISION_RE, DEPLOYMENT_COMPOSITION_ID_RE, REQUIRED_LONG_WINDOWS, REQUIRED_DIAGNOSTIC_TERMINAL_WINDOWS, MIN_RECENT_DIRECTION_REPAIR_EVENTS, safeSegment6, compactTimestamp2, verifyFullPeriodChartArtifact, readVerifiedJsonArtifact, verifyResearchDecisionLineage, hasExactRuntimeTarget, deriveStrategyReleaseResearchDecision, canonicalStrategyReleaseJson, strategyReleaseSha256, assertFingerprint, assertLineageFingerprint, releaseReasons, deriveReleaseGates, verifyEvidenceComposition, createStrategyReleaseManifest, createStrategyReleaseEnvelope, verifyStrategyReleaseEnvelope, verifyStrategyEvidenceMarkerEnvelope, releaseMarkers, writeJsonAtomic2, publishStrategyRelease, publishStrategyLiveDiagnosis, finiteString3, finiteNumber6, finiteDirectionPolicy, uniqueStrings, incompleteEvidenceLineage, extractEvidenceLineage, verifyCompletedCoreResearchBundle;
|
|
27263
28078
|
var init_strategyRelease = __esm({
|
|
27264
28079
|
"src/lib/strategyRelease.ts"() {
|
|
27265
28080
|
"use strict";
|
|
27266
|
-
|
|
27267
|
-
|
|
27268
|
-
|
|
28081
|
+
import_node_crypto14 = require("crypto");
|
|
28082
|
+
import_promises29 = __toESM(require("fs/promises"));
|
|
28083
|
+
import_node_path26 = __toESM(require("path"));
|
|
27269
28084
|
import_types9 = require("@tradejs/types");
|
|
27270
28085
|
import_strategyReleaseEvidence2 = require("@tradejs/infra/strategyReleaseEvidence");
|
|
27271
28086
|
init_liveDiagnosis();
|
|
@@ -27278,17 +28093,17 @@ var init_strategyRelease = __esm({
|
|
|
27278
28093
|
REQUIRED_LONG_WINDOWS = [1095, 1460, 1825];
|
|
27279
28094
|
REQUIRED_DIAGNOSTIC_TERMINAL_WINDOWS = [365, 180, 90];
|
|
27280
28095
|
MIN_RECENT_DIRECTION_REPAIR_EVENTS = 20;
|
|
27281
|
-
|
|
28096
|
+
safeSegment6 = import_strategyReleaseEvidence2.safeStrategyEvidenceSegment;
|
|
27282
28097
|
compactTimestamp2 = import_strategyReleaseEvidence2.compactStrategyEvidenceTimestamp;
|
|
27283
28098
|
verifyFullPeriodChartArtifact = async (input) => {
|
|
27284
28099
|
const artifact = input.chartArtifact;
|
|
27285
28100
|
if (!artifact?.path || !SHA256_RE2.test(artifact.sha256)) return false;
|
|
27286
28101
|
try {
|
|
27287
|
-
const artifactPath =
|
|
28102
|
+
const artifactPath = import_node_path26.default.resolve(artifact.path);
|
|
27288
28103
|
if (await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
27289
28104
|
return false;
|
|
27290
28105
|
}
|
|
27291
|
-
const report = JSON.parse(await
|
|
28106
|
+
const report = JSON.parse(await import_promises29.default.readFile(artifactPath, "utf8"));
|
|
27292
28107
|
return Boolean(
|
|
27293
28108
|
report.chart?.persisted === true && report.chart.cardIds?.length && report.errors?.failed === 0 && report.run?.strategy === input.strategy && report.run.mode === "local-deterministic" && report.run.recent === 0 && report.run.since == null && report.run.until == null && Number(report.run.sourceRows) > 0
|
|
27294
28109
|
);
|
|
@@ -27299,11 +28114,11 @@ var init_strategyRelease = __esm({
|
|
|
27299
28114
|
readVerifiedJsonArtifact = async (artifact) => {
|
|
27300
28115
|
if (!artifact?.path || !SHA256_RE2.test(artifact.sha256)) return null;
|
|
27301
28116
|
try {
|
|
27302
|
-
const artifactPath =
|
|
28117
|
+
const artifactPath = import_node_path26.default.resolve(artifact.path);
|
|
27303
28118
|
if (await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
27304
28119
|
return null;
|
|
27305
28120
|
}
|
|
27306
|
-
return JSON.parse(await
|
|
28121
|
+
return JSON.parse(await import_promises29.default.readFile(artifactPath, "utf8"));
|
|
27307
28122
|
} catch {
|
|
27308
28123
|
return null;
|
|
27309
28124
|
}
|
|
@@ -27794,7 +28609,7 @@ var init_strategyRelease = __esm({
|
|
|
27794
28609
|
maxLossValue: input.composition.maxLossValue,
|
|
27795
28610
|
...input.composition.directionPolicy == null ? {} : { directionPolicy: input.composition.directionPolicy }
|
|
27796
28611
|
};
|
|
27797
|
-
const compositionId = `${
|
|
28612
|
+
const compositionId = `${safeSegment6(input.strategy, "strategy")}_${strategyReleaseSha256(compositionIdentity).slice(0, 16)}`;
|
|
27798
28613
|
const reasons = releaseReasons({ ...input, gates: evidenceGates });
|
|
27799
28614
|
const economicFailure = reasons.some(
|
|
27800
28615
|
(reason) => [
|
|
@@ -27816,16 +28631,16 @@ var init_strategyRelease = __esm({
|
|
|
27816
28631
|
strategy: input.strategy,
|
|
27817
28632
|
createdAt: input.createdAt,
|
|
27818
28633
|
compositionId,
|
|
27819
|
-
evidence: input.evidence.map(({ kind, artifactId, sha256:
|
|
28634
|
+
evidence: input.evidence.map(({ kind, artifactId, sha256: sha2564 }) => ({
|
|
27820
28635
|
kind,
|
|
27821
28636
|
artifactId,
|
|
27822
|
-
sha256:
|
|
28637
|
+
sha256: sha2564
|
|
27823
28638
|
})),
|
|
27824
28639
|
verdict
|
|
27825
28640
|
};
|
|
27826
28641
|
return {
|
|
27827
28642
|
schema: import_types9.STRATEGY_RELEASE_SCHEMA,
|
|
27828
|
-
releaseId: `${
|
|
28643
|
+
releaseId: `${safeSegment6(input.strategy, "strategy")}_${compactTimestamp2(input.createdAt)}_${strategyReleaseSha256(releaseIdentity).slice(0, 16)}`,
|
|
27829
28644
|
strategy: input.strategy,
|
|
27830
28645
|
createdAt: input.createdAt,
|
|
27831
28646
|
composition: { ...input.composition, compositionId },
|
|
@@ -27849,7 +28664,7 @@ var init_strategyRelease = __esm({
|
|
|
27849
28664
|
manifest
|
|
27850
28665
|
});
|
|
27851
28666
|
verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
27852
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
28667
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises29.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
27853
28668
|
const envelope = value;
|
|
27854
28669
|
assert3(
|
|
27855
28670
|
envelope?.schema === "tradejs-strategy-release-envelope/v1",
|
|
@@ -27900,7 +28715,7 @@ var init_strategyRelease = __esm({
|
|
|
27900
28715
|
return envelope;
|
|
27901
28716
|
};
|
|
27902
28717
|
verifyStrategyEvidenceMarkerEnvelope = async (valueOrPath) => {
|
|
27903
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
28718
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises29.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
27904
28719
|
return (0, import_strategyReleaseEvidence2.verifyStrategyEvidenceMarkerEnvelope)(value);
|
|
27905
28720
|
};
|
|
27906
28721
|
releaseMarkers = (manifest) => {
|
|
@@ -27962,14 +28777,14 @@ var init_strategyRelease = __esm({
|
|
|
27962
28777
|
};
|
|
27963
28778
|
writeJsonAtomic2 = async (filePath, value) => {
|
|
27964
28779
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
27965
|
-
await
|
|
27966
|
-
await
|
|
28780
|
+
await import_promises29.default.mkdir(import_node_path26.default.dirname(filePath), { recursive: true });
|
|
28781
|
+
await import_promises29.default.writeFile(
|
|
27967
28782
|
temporaryPath,
|
|
27968
28783
|
`${canonicalStrategyReleaseJson(value)}
|
|
27969
28784
|
`,
|
|
27970
28785
|
"utf8"
|
|
27971
28786
|
);
|
|
27972
|
-
await
|
|
28787
|
+
await import_promises29.default.rename(temporaryPath, filePath);
|
|
27973
28788
|
};
|
|
27974
28789
|
publishStrategyRelease = async ({
|
|
27975
28790
|
rootDir,
|
|
@@ -27986,16 +28801,16 @@ var init_strategyRelease = __esm({
|
|
|
27986
28801
|
path: entry.path
|
|
27987
28802
|
}))
|
|
27988
28803
|
});
|
|
27989
|
-
const releasePath =
|
|
28804
|
+
const releasePath = import_node_path26.default.join(
|
|
27990
28805
|
rootDir,
|
|
27991
28806
|
"releases",
|
|
27992
|
-
|
|
28807
|
+
safeSegment6(manifest.strategy, "strategy"),
|
|
27993
28808
|
`${manifest.releaseId}.json`
|
|
27994
28809
|
);
|
|
27995
|
-
const markerPath =
|
|
28810
|
+
const markerPath = import_node_path26.default.join(
|
|
27996
28811
|
rootDir,
|
|
27997
28812
|
"markers",
|
|
27998
|
-
|
|
28813
|
+
safeSegment6(manifest.strategy, "strategy"),
|
|
27999
28814
|
`${markerEnvelope.artifactId}.json`
|
|
28000
28815
|
);
|
|
28001
28816
|
await Promise.all([
|
|
@@ -28015,7 +28830,7 @@ var init_strategyRelease = __esm({
|
|
|
28015
28830
|
composition
|
|
28016
28831
|
}) => {
|
|
28017
28832
|
const diagnosisSha256 = strategyReleaseSha256(diagnosis);
|
|
28018
|
-
const diagnosisId = `${
|
|
28833
|
+
const diagnosisId = `${safeSegment6(diagnosis.strategy, "strategy")}_${compactTimestamp2(diagnosis.createdAt)}_${diagnosisSha256.slice(0, 16)}`;
|
|
28019
28834
|
const envelope = {
|
|
28020
28835
|
schema: "tradejs-strategy-live-diagnosis-envelope/v1",
|
|
28021
28836
|
diagnosisId,
|
|
@@ -28072,16 +28887,16 @@ var init_strategyRelease = __esm({
|
|
|
28072
28887
|
markers,
|
|
28073
28888
|
sourceArtifacts
|
|
28074
28889
|
});
|
|
28075
|
-
const diagnosisPath =
|
|
28890
|
+
const diagnosisPath = import_node_path26.default.join(
|
|
28076
28891
|
rootDir,
|
|
28077
28892
|
"diagnoses",
|
|
28078
|
-
|
|
28893
|
+
safeSegment6(diagnosis.strategy, "strategy"),
|
|
28079
28894
|
`${diagnosisId}.json`
|
|
28080
28895
|
);
|
|
28081
|
-
const markerPath =
|
|
28896
|
+
const markerPath = import_node_path26.default.join(
|
|
28082
28897
|
rootDir,
|
|
28083
28898
|
"markers",
|
|
28084
|
-
|
|
28899
|
+
safeSegment6(diagnosis.strategy, "strategy"),
|
|
28085
28900
|
`${markerEnvelope.artifactId}.json`
|
|
28086
28901
|
);
|
|
28087
28902
|
await Promise.all([
|
|
@@ -28268,11 +29083,11 @@ var init_strategyRelease = __esm({
|
|
|
28268
29083
|
const specSha256 = finiteString3(artifact.specSha256);
|
|
28269
29084
|
assert3(researchId != null, "core result researchId is required");
|
|
28270
29085
|
assert3(specSha256 != null, "core result specSha256 is required");
|
|
28271
|
-
const researchDir =
|
|
28272
|
-
const manifestPath =
|
|
28273
|
-
const specPath =
|
|
28274
|
-
const manifestBytes = await
|
|
28275
|
-
const specBytes = await
|
|
29086
|
+
const researchDir = import_node_path26.default.dirname(resultPath);
|
|
29087
|
+
const manifestPath = import_node_path26.default.join(researchDir, "manifest.json");
|
|
29088
|
+
const specPath = import_node_path26.default.join(researchDir, "spec.json");
|
|
29089
|
+
const manifestBytes = await import_promises29.default.readFile(manifestPath).catch(() => null);
|
|
29090
|
+
const specBytes = await import_promises29.default.readFile(specPath).catch(() => null);
|
|
28276
29091
|
assert3(
|
|
28277
29092
|
manifestBytes != null && specBytes != null,
|
|
28278
29093
|
"core result must belong to a completed core research bundle"
|
|
@@ -28281,14 +29096,14 @@ var init_strategyRelease = __esm({
|
|
|
28281
29096
|
const artifactHashes = manifest.artifactHashes != null && typeof manifest.artifactHashes === "object" && !Array.isArray(manifest.artifactHashes) ? manifest.artifactHashes : null;
|
|
28282
29097
|
const parsedSpec = JSON.parse(specBytes.toString("utf8"));
|
|
28283
29098
|
assert3(
|
|
28284
|
-
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0,
|
|
29099
|
+
manifest.schema === "tradejs-core-research-manifest/v1" && manifest.status === "completed" && manifest.researchId === researchId && manifest.specSha256 === specSha256 && artifactHashes?.["result.json"] === resultSha256 && (0, import_node_crypto14.createHash)("sha256").update(canonicalStrategyReleaseJson(parsedSpec)).digest("hex") === specSha256,
|
|
28285
29100
|
"core result is not bound by its completed core research manifest"
|
|
28286
29101
|
);
|
|
28287
29102
|
for (const [relativePath, expectedSha256] of Object.entries(
|
|
28288
29103
|
artifactHashes ?? {}
|
|
28289
29104
|
)) {
|
|
28290
29105
|
assert3(
|
|
28291
|
-
!
|
|
29106
|
+
!import_node_path26.default.isAbsolute(relativePath) && !relativePath.split(/[\\/]/).includes(".."),
|
|
28292
29107
|
`core bundle artifact ${relativePath} escapes its research directory`
|
|
28293
29108
|
);
|
|
28294
29109
|
assert3(
|
|
@@ -28296,7 +29111,7 @@ var init_strategyRelease = __esm({
|
|
|
28296
29111
|
`core bundle artifact ${relativePath} has an invalid checksum`
|
|
28297
29112
|
);
|
|
28298
29113
|
const actualSha256 = await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(
|
|
28299
|
-
|
|
29114
|
+
import_node_path26.default.join(researchDir, relativePath)
|
|
28300
29115
|
);
|
|
28301
29116
|
assert3(
|
|
28302
29117
|
actualSha256 === expectedSha256,
|
|
@@ -28310,88 +29125,89 @@ var init_strategyRelease = __esm({
|
|
|
28310
29125
|
// src/scripts/runtimeScorecard.ts
|
|
28311
29126
|
var runtimeScorecard_exports = {};
|
|
28312
29127
|
__export(runtimeScorecard_exports, {
|
|
28313
|
-
main: () =>
|
|
29128
|
+
main: () => main38,
|
|
28314
29129
|
runtimeScorecard: () => runtimeScorecard
|
|
28315
29130
|
});
|
|
28316
|
-
var
|
|
29131
|
+
var import_promises30, import_node_crypto15, import_node_path27, import_args30, import_chalk43, flags29, projectRoot13, resolveOptionalPath, readJson, assertReportType, sha256File2, loadHistoryArtifacts, runtimeScorecard, main38;
|
|
28317
29132
|
var init_runtimeScorecard2 = __esm({
|
|
28318
29133
|
"src/scripts/runtimeScorecard.ts"() {
|
|
28319
29134
|
"use strict";
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
29135
|
+
import_promises30 = __toESM(require("fs/promises"));
|
|
29136
|
+
import_node_crypto15 = require("crypto");
|
|
29137
|
+
import_node_path27 = __toESM(require("path"));
|
|
29138
|
+
import_args30 = __toESM(require("args"));
|
|
29139
|
+
import_chalk43 = __toESM(require("chalk"));
|
|
28325
29140
|
init_runtimeEvidenceArtifacts();
|
|
29141
|
+
init_runtimeFeedbackArtifacts();
|
|
28326
29142
|
init_runtimeEvidenceSync();
|
|
28327
29143
|
init_runtimeScorecard();
|
|
28328
29144
|
init_strategyRelease();
|
|
28329
|
-
|
|
28330
|
-
|
|
28331
|
-
|
|
28332
|
-
|
|
29145
|
+
import_args30.default.option(["u", "runtimeEvidence"], "Verified runtime evidence JSON");
|
|
29146
|
+
import_args30.default.option(["r", "replayEvidence"], "Replay runtime evidence JSON");
|
|
29147
|
+
import_args30.default.option(["c", "calibration"], "Execution calibration JSON");
|
|
29148
|
+
import_args30.default.option(
|
|
28333
29149
|
["q", "prospectiveEvidence"],
|
|
28334
29150
|
"Verified prospective raw-core/gate/regime summary JSON"
|
|
28335
29151
|
);
|
|
28336
|
-
|
|
28337
|
-
|
|
29152
|
+
import_args30.default.option(["s", "strategy"], "Exact strategy to isolate in the scorecard");
|
|
29153
|
+
import_args30.default.option(
|
|
28338
29154
|
["H", "historyDir"],
|
|
28339
29155
|
"Directory containing verified evidence bundles"
|
|
28340
29156
|
);
|
|
28341
|
-
|
|
29157
|
+
import_args30.default.option(
|
|
28342
29158
|
["E", "evidenceDir"],
|
|
28343
29159
|
"Local evidence storage root used for processing receipts",
|
|
28344
29160
|
process.env.RUNTIME_EVIDENCE_LOCAL_DIR || "data/runtime-evidence"
|
|
28345
29161
|
);
|
|
28346
|
-
|
|
29162
|
+
import_args30.default.option(
|
|
28347
29163
|
["d", "deployment"],
|
|
28348
29164
|
"Deployment id used for processing receipts",
|
|
28349
29165
|
process.env.RUNTIME_EVIDENCE_DEPLOYMENT_ID || "production"
|
|
28350
29166
|
);
|
|
28351
|
-
|
|
29167
|
+
import_args30.default.option(
|
|
28352
29168
|
["M", "markProcessed"],
|
|
28353
29169
|
"Write a processing receipt on success",
|
|
28354
29170
|
false
|
|
28355
29171
|
);
|
|
28356
|
-
|
|
29172
|
+
import_args30.default.option(
|
|
28357
29173
|
["P", "minimumParityRatio"],
|
|
28358
29174
|
"Minimum acceptable replay parity",
|
|
28359
29175
|
0.95
|
|
28360
29176
|
);
|
|
28361
|
-
|
|
29177
|
+
import_args30.default.option(
|
|
28362
29178
|
["S", "maximumSlippageResidualBps"],
|
|
28363
29179
|
"Maximum acceptable execution residual in bps",
|
|
28364
29180
|
3
|
|
28365
29181
|
);
|
|
28366
|
-
|
|
29182
|
+
import_args30.default.option(
|
|
28367
29183
|
["T", "minimumClosedTrades"],
|
|
28368
29184
|
"Minimum 7d closed trades for expectancy reactions",
|
|
28369
29185
|
20
|
|
28370
29186
|
);
|
|
28371
|
-
|
|
28372
|
-
|
|
28373
|
-
|
|
29187
|
+
import_args30.default.option(["X", "minimumExpectancy"], "Minimum acceptable 7d expectancy", 0);
|
|
29188
|
+
import_args30.default.option(["o", "out"], "Output JSON path", "output/runtime-scorecard.json");
|
|
29189
|
+
import_args30.default.option(
|
|
28374
29190
|
["m", "releaseManifest"],
|
|
28375
29191
|
"Verified strategy release envelope JSON"
|
|
28376
29192
|
);
|
|
28377
|
-
|
|
28378
|
-
|
|
29193
|
+
import_args30.default.option(["D", "diagnosisDays"], "Equal-length release drawdown window", 7);
|
|
29194
|
+
import_args30.default.option(
|
|
28379
29195
|
["z", "strategyReleaseRoot"],
|
|
28380
29196
|
"Publish advisory diagnosis and immutable chart markers under this root"
|
|
28381
29197
|
);
|
|
28382
|
-
|
|
28383
|
-
|
|
29198
|
+
flags29 = import_args30.default.parse(process.argv);
|
|
29199
|
+
projectRoot13 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
28384
29200
|
resolveOptionalPath = (value) => {
|
|
28385
29201
|
const raw = String(value ?? "").trim();
|
|
28386
|
-
return raw ?
|
|
29202
|
+
return raw ? import_node_path27.default.resolve(projectRoot13, raw) : null;
|
|
28387
29203
|
};
|
|
28388
|
-
readJson = async (filePath) => filePath ? JSON.parse(await
|
|
29204
|
+
readJson = async (filePath) => filePath ? JSON.parse(await import_promises30.default.readFile(filePath, "utf8")) : void 0;
|
|
28389
29205
|
assertReportType = (artifact, expected, label) => {
|
|
28390
29206
|
if (artifact != null && (!artifact || typeof artifact !== "object" || Array.isArray(artifact) || artifact.reportType !== expected)) {
|
|
28391
29207
|
throw new Error(`${label} must be a ${expected} artifact`);
|
|
28392
29208
|
}
|
|
28393
29209
|
};
|
|
28394
|
-
sha256File2 = async (filePath) => (0,
|
|
29210
|
+
sha256File2 = async (filePath) => (0, import_node_crypto15.createHash)("sha256").update(await import_promises30.default.readFile(filePath)).digest("hex");
|
|
28395
29211
|
loadHistoryArtifacts = async (historyDir) => {
|
|
28396
29212
|
if (!historyDir) return [];
|
|
28397
29213
|
const bundleDirs = await discoverRuntimeEvidenceBundles(historyDir);
|
|
@@ -28402,17 +29218,17 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28402
29218
|
return bundles.map((bundle) => bundle.artifact);
|
|
28403
29219
|
};
|
|
28404
29220
|
runtimeScorecard = async () => {
|
|
28405
|
-
const runtimeEvidencePath = resolveOptionalPath(
|
|
29221
|
+
const runtimeEvidencePath = resolveOptionalPath(flags29.runtimeEvidence);
|
|
28406
29222
|
if (!runtimeEvidencePath) {
|
|
28407
29223
|
throw new Error("Provide --runtimeEvidence for the runtime scorecard.");
|
|
28408
29224
|
}
|
|
28409
|
-
const replayEvidencePath = resolveOptionalPath(
|
|
28410
|
-
const calibrationPath = resolveOptionalPath(
|
|
29225
|
+
const replayEvidencePath = resolveOptionalPath(flags29.replayEvidence);
|
|
29226
|
+
const calibrationPath = resolveOptionalPath(flags29.calibration);
|
|
28411
29227
|
const prospectiveEvidencePath = resolveOptionalPath(
|
|
28412
|
-
|
|
29228
|
+
flags29.prospectiveEvidence
|
|
28413
29229
|
);
|
|
28414
|
-
const historyDir = resolveOptionalPath(
|
|
28415
|
-
const releaseManifestPath = resolveOptionalPath(
|
|
29230
|
+
const historyDir = resolveOptionalPath(flags29.historyDir);
|
|
29231
|
+
const releaseManifestPath = resolveOptionalPath(flags29.releaseManifest);
|
|
28416
29232
|
const [
|
|
28417
29233
|
runtimeArtifact,
|
|
28418
29234
|
replayEvidenceArtifact,
|
|
@@ -28439,7 +29255,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28439
29255
|
"prospectiveEvidence"
|
|
28440
29256
|
);
|
|
28441
29257
|
const verifiedRelease = releaseManifestPath ? await verifyStrategyReleaseEnvelope(releaseManifestPath) : null;
|
|
28442
|
-
const requestedStrategy = String(
|
|
29258
|
+
const requestedStrategy = String(flags29.strategy ?? "").trim() || null;
|
|
28443
29259
|
if (verifiedRelease && requestedStrategy && requestedStrategy !== verifiedRelease.manifest.strategy) {
|
|
28444
29260
|
throw new Error(
|
|
28445
29261
|
`Requested strategy ${requestedStrategy} does not match release ${verifiedRelease.manifest.strategy}`
|
|
@@ -28453,21 +29269,21 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28453
29269
|
prospectiveEvidenceArtifact,
|
|
28454
29270
|
historyRuntimeArtifacts: history,
|
|
28455
29271
|
thresholds: {
|
|
28456
|
-
minimumParityRatio: Number(
|
|
28457
|
-
maximumSlippageResidualBps: Number(
|
|
28458
|
-
minimumClosedTrades: Number(
|
|
28459
|
-
minimumExpectancy: Number(
|
|
29272
|
+
minimumParityRatio: Number(flags29.minimumParityRatio),
|
|
29273
|
+
maximumSlippageResidualBps: Number(flags29.maximumSlippageResidualBps),
|
|
29274
|
+
minimumClosedTrades: Number(flags29.minimumClosedTrades),
|
|
29275
|
+
minimumExpectancy: Number(flags29.minimumExpectancy)
|
|
28460
29276
|
},
|
|
28461
29277
|
strategy: scorecardStrategy,
|
|
28462
29278
|
llmComparatorPolicy: verifiedRelease?.manifest.prospective.llmComparatorPolicy ?? "ai_approved_only"
|
|
28463
29279
|
});
|
|
28464
|
-
const outPath =
|
|
29280
|
+
const outPath = import_node_path27.default.resolve(projectRoot13, String(flags29.out));
|
|
28465
29281
|
const markdownPath = outPath.replace(/\.json$/i, "") + ".md";
|
|
28466
|
-
await
|
|
29282
|
+
await import_promises30.default.mkdir(import_node_path27.default.dirname(outPath), { recursive: true });
|
|
28467
29283
|
await Promise.all([
|
|
28468
|
-
|
|
29284
|
+
import_promises30.default.writeFile(outPath, `${JSON.stringify(scorecard, null, 2)}
|
|
28469
29285
|
`, "utf8"),
|
|
28470
|
-
|
|
29286
|
+
import_promises30.default.writeFile(
|
|
28471
29287
|
markdownPath,
|
|
28472
29288
|
formatRuntimeScorecardMarkdown(scorecard),
|
|
28473
29289
|
"utf8"
|
|
@@ -28476,12 +29292,12 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28476
29292
|
const diagnosis = verifiedRelease ? buildStrategyLiveDiagnosisFromScorecard({
|
|
28477
29293
|
manifest: verifiedRelease.manifest,
|
|
28478
29294
|
scorecard,
|
|
28479
|
-
days: Number(
|
|
29295
|
+
days: Number(flags29.diagnosisDays)
|
|
28480
29296
|
}) : null;
|
|
28481
29297
|
const diagnosisPath = diagnosis ? outPath.replace(/\.json$/i, "") + ".diagnosis.json" : null;
|
|
28482
|
-
const strategyReleaseRoot = resolveOptionalPath(
|
|
29298
|
+
const strategyReleaseRoot = resolveOptionalPath(flags29.strategyReleaseRoot);
|
|
28483
29299
|
if (diagnosis && diagnosisPath) {
|
|
28484
|
-
await
|
|
29300
|
+
await import_promises30.default.writeFile(
|
|
28485
29301
|
diagnosisPath,
|
|
28486
29302
|
`${JSON.stringify(diagnosis, null, 2)}
|
|
28487
29303
|
`,
|
|
@@ -28502,7 +29318,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28502
29318
|
composition: verifiedRelease?.manifest.composition,
|
|
28503
29319
|
sourceArtifacts: await Promise.all(
|
|
28504
29320
|
sourcePaths.map(async (sourcePath) => ({
|
|
28505
|
-
artifactId:
|
|
29321
|
+
artifactId: import_node_path27.default.basename(sourcePath),
|
|
28506
29322
|
path: sourcePath,
|
|
28507
29323
|
sha256: await sha256File2(sourcePath)
|
|
28508
29324
|
}))
|
|
@@ -28511,16 +29327,35 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28511
29327
|
}
|
|
28512
29328
|
}
|
|
28513
29329
|
let receiptPath2 = null;
|
|
28514
|
-
if (
|
|
29330
|
+
if (flags29.markProcessed) {
|
|
29331
|
+
const runtimeEvidenceBundle = await verifyRuntimeEvidenceBundle(
|
|
29332
|
+
import_node_path27.default.dirname(runtimeEvidencePath)
|
|
29333
|
+
);
|
|
29334
|
+
const feedbackSource = replayEvidencePath ? await verifyRuntimeFeedbackReplaySource({
|
|
29335
|
+
bundleDir: import_node_path27.default.dirname(replayEvidencePath),
|
|
29336
|
+
runtimeEvidenceBundleDir: import_node_path27.default.dirname(runtimeEvidencePath)
|
|
29337
|
+
}).catch((error) => {
|
|
29338
|
+
if (runtimeEvidenceBundle.artifact.producer) throw error;
|
|
29339
|
+
return null;
|
|
29340
|
+
}) : null;
|
|
29341
|
+
if (runtimeEvidenceBundle.artifact.producer && !feedbackSource) {
|
|
29342
|
+
throw new Error(
|
|
29343
|
+
"Image-bound runtime evidence requires a verified production replay bundle before it can be marked processed"
|
|
29344
|
+
);
|
|
29345
|
+
}
|
|
28515
29346
|
receiptPath2 = await markRuntimeEvidenceBundleProcessed({
|
|
28516
|
-
evidenceRoot:
|
|
28517
|
-
deploymentId: String(
|
|
28518
|
-
bundleDir:
|
|
28519
|
-
scorecardPath: outPath
|
|
29347
|
+
evidenceRoot: import_node_path27.default.resolve(projectRoot13, String(flags29.evidenceDir)),
|
|
29348
|
+
deploymentId: String(flags29.deployment),
|
|
29349
|
+
bundleDir: import_node_path27.default.dirname(runtimeEvidencePath),
|
|
29350
|
+
scorecardPath: outPath,
|
|
29351
|
+
runtimeFeedback: feedbackSource ? {
|
|
29352
|
+
artifactId: feedbackSource.feedback.manifest.artifactId,
|
|
29353
|
+
replayEvidenceSha256: feedbackSource.feedback.manifest.payloads.replayEvidence.sha256
|
|
29354
|
+
} : null
|
|
28520
29355
|
});
|
|
28521
29356
|
}
|
|
28522
|
-
console.log(
|
|
28523
|
-
console.log(
|
|
29357
|
+
console.log(import_chalk43.default.green(`Wrote ${outPath}`));
|
|
29358
|
+
console.log(import_chalk43.default.green(`Wrote ${markdownPath}`));
|
|
28524
29359
|
console.log(
|
|
28525
29360
|
JSON.stringify(
|
|
28526
29361
|
{
|
|
@@ -28539,7 +29374,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28539
29374
|
)
|
|
28540
29375
|
);
|
|
28541
29376
|
};
|
|
28542
|
-
|
|
29377
|
+
main38 = runtimeScorecard;
|
|
28543
29378
|
}
|
|
28544
29379
|
});
|
|
28545
29380
|
|
|
@@ -28547,10 +29382,10 @@ var init_runtimeScorecard2 = __esm({
|
|
|
28547
29382
|
var runtimeControl_exports = {};
|
|
28548
29383
|
__export(runtimeControl_exports, {
|
|
28549
29384
|
RUNTIME_CONTROL_ACTIONS: () => RUNTIME_CONTROL_ACTIONS,
|
|
28550
|
-
main: () =>
|
|
29385
|
+
main: () => main39,
|
|
28551
29386
|
runtimeControl: () => runtimeControl
|
|
28552
29387
|
});
|
|
28553
|
-
var import_config9, import_runtimeControls, import_runtimeStrategies4, argv, RUNTIME_CONTROL_ACTIONS, action, option, required2,
|
|
29388
|
+
var import_config9, import_runtimeControls, import_runtimeStrategies4, argv, RUNTIME_CONTROL_ACTIONS, action, option, required2, projectRoot14, userName2, verify, inspect, updateControlState, runtimeControl, main39;
|
|
28554
29389
|
var init_runtimeControl = __esm({
|
|
28555
29390
|
"src/scripts/runtimeControl.ts"() {
|
|
28556
29391
|
"use strict";
|
|
@@ -28574,10 +29409,10 @@ var init_runtimeControl = __esm({
|
|
|
28574
29409
|
if (!value) throw new Error(`--${name} is required`);
|
|
28575
29410
|
return value;
|
|
28576
29411
|
};
|
|
28577
|
-
|
|
29412
|
+
projectRoot14 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
28578
29413
|
userName2 = String(option("user") ?? process.env.USER_NAME ?? "root");
|
|
28579
29414
|
verify = async () => {
|
|
28580
|
-
const deployments = await (0, import_runtimeStrategies4.listRuntimeDeployments)({ userName: userName2, projectRoot:
|
|
29415
|
+
const deployments = await (0, import_runtimeStrategies4.listRuntimeDeployments)({ userName: userName2, projectRoot: projectRoot14 });
|
|
28581
29416
|
const requestedDeployment = option("deployment");
|
|
28582
29417
|
const selected = requestedDeployment ? deployments.filter((deployment) => deployment.id === requestedDeployment) : deployments;
|
|
28583
29418
|
if (requestedDeployment && !selected.length) {
|
|
@@ -28588,7 +29423,7 @@ var init_runtimeControl = __esm({
|
|
|
28588
29423
|
try {
|
|
28589
29424
|
const strategies = await (0, import_runtimeStrategies4.loadResolvedRuntimeStrategies)({
|
|
28590
29425
|
userName: userName2,
|
|
28591
|
-
projectRoot:
|
|
29426
|
+
projectRoot: projectRoot14,
|
|
28592
29427
|
deploymentId: deployment.id
|
|
28593
29428
|
});
|
|
28594
29429
|
results2.push({
|
|
@@ -28621,7 +29456,7 @@ var init_runtimeControl = __esm({
|
|
|
28621
29456
|
inspect = async () => {
|
|
28622
29457
|
const requestedDeployment = option("deployment");
|
|
28623
29458
|
const requestedStrategy = option("strategy");
|
|
28624
|
-
const deployments = (await (0, import_runtimeStrategies4.listRuntimeDeployments)({ userName: userName2, projectRoot:
|
|
29459
|
+
const deployments = (await (0, import_runtimeStrategies4.listRuntimeDeployments)({ userName: userName2, projectRoot: projectRoot14 })).filter(
|
|
28625
29460
|
(deployment) => !requestedDeployment || deployment.id === requestedDeployment
|
|
28626
29461
|
).map((deployment) => ({
|
|
28627
29462
|
...deployment,
|
|
@@ -28636,7 +29471,7 @@ var init_runtimeControl = __esm({
|
|
|
28636
29471
|
const strategyName = required2("strategy");
|
|
28637
29472
|
const deployment = await (0, import_runtimeStrategies4.getRuntimeDeployment)({
|
|
28638
29473
|
userName: userName2,
|
|
28639
|
-
projectRoot:
|
|
29474
|
+
projectRoot: projectRoot14,
|
|
28640
29475
|
deploymentId
|
|
28641
29476
|
});
|
|
28642
29477
|
if (!deployment) {
|
|
@@ -28666,7 +29501,7 @@ var init_runtimeControl = __esm({
|
|
|
28666
29501
|
}
|
|
28667
29502
|
const updated = await (0, import_runtimeStrategies4.getRuntimeDeployment)({
|
|
28668
29503
|
userName: userName2,
|
|
28669
|
-
projectRoot:
|
|
29504
|
+
projectRoot: projectRoot14,
|
|
28670
29505
|
deploymentId
|
|
28671
29506
|
});
|
|
28672
29507
|
const updatedReference = updated?.strategies.find(
|
|
@@ -28698,25 +29533,25 @@ var init_runtimeControl = __esm({
|
|
|
28698
29533
|
`Usage: tradejs runtime-control ${RUNTIME_CONTROL_ACTIONS.join("|")}`
|
|
28699
29534
|
);
|
|
28700
29535
|
};
|
|
28701
|
-
|
|
29536
|
+
main39 = runtimeControl;
|
|
28702
29537
|
}
|
|
28703
29538
|
});
|
|
28704
29539
|
|
|
28705
29540
|
// src/scripts/strategyRelease.ts
|
|
28706
29541
|
var strategyRelease_exports = {};
|
|
28707
29542
|
__export(strategyRelease_exports, {
|
|
28708
|
-
main: () =>
|
|
29543
|
+
main: () => main40,
|
|
28709
29544
|
runStrategyReleaseCommand: () => runStrategyReleaseCommand
|
|
28710
29545
|
});
|
|
28711
|
-
var
|
|
29546
|
+
var import_promises31, import_node_fs5, import_node_readline2, import_node_path28, import_chalk44, valueAfter2, required3, writeJsonAtomic3, runStrategyReleaseCommand, printUsage2, main40;
|
|
28712
29547
|
var init_strategyRelease2 = __esm({
|
|
28713
29548
|
"src/scripts/strategyRelease.ts"() {
|
|
28714
29549
|
"use strict";
|
|
28715
|
-
|
|
29550
|
+
import_promises31 = __toESM(require("fs/promises"));
|
|
28716
29551
|
import_node_fs5 = require("fs");
|
|
28717
29552
|
import_node_readline2 = require("readline");
|
|
28718
|
-
|
|
28719
|
-
|
|
29553
|
+
import_node_path28 = __toESM(require("path"));
|
|
29554
|
+
import_chalk44 = __toESM(require("chalk"));
|
|
28720
29555
|
init_strategyRelease();
|
|
28721
29556
|
valueAfter2 = (argv2, name) => {
|
|
28722
29557
|
const index = argv2.indexOf(name);
|
|
@@ -28728,17 +29563,17 @@ var init_strategyRelease2 = __esm({
|
|
|
28728
29563
|
};
|
|
28729
29564
|
writeJsonAtomic3 = async (filePath, value) => {
|
|
28730
29565
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
28731
|
-
await
|
|
28732
|
-
await
|
|
29566
|
+
await import_promises31.default.mkdir(import_node_path28.default.dirname(filePath), { recursive: true });
|
|
29567
|
+
await import_promises31.default.writeFile(
|
|
28733
29568
|
temporaryPath,
|
|
28734
29569
|
`${JSON.stringify(value, null, 2)}
|
|
28735
29570
|
`,
|
|
28736
29571
|
"utf8"
|
|
28737
29572
|
);
|
|
28738
|
-
await
|
|
29573
|
+
await import_promises31.default.rename(temporaryPath, filePath);
|
|
28739
29574
|
};
|
|
28740
29575
|
runStrategyReleaseCommand = async (options) => {
|
|
28741
|
-
const inputPath =
|
|
29576
|
+
const inputPath = import_node_path28.default.resolve(options.inputPath);
|
|
28742
29577
|
if (options.command === "verify") {
|
|
28743
29578
|
const envelope = await verifyStrategyReleaseEnvelope(inputPath);
|
|
28744
29579
|
return {
|
|
@@ -28776,7 +29611,7 @@ var init_strategyRelease2 = __esm({
|
|
|
28776
29611
|
endTime,
|
|
28777
29612
|
days: options.days?.length ? options.days : [7, 30, 90]
|
|
28778
29613
|
});
|
|
28779
|
-
const outputPath =
|
|
29614
|
+
const outputPath = import_node_path28.default.resolve(
|
|
28780
29615
|
options.outputPath ?? "output/strategy-monitoring-profile.json"
|
|
28781
29616
|
);
|
|
28782
29617
|
await writeJsonAtomic3(outputPath, profile);
|
|
@@ -28787,22 +29622,22 @@ var init_strategyRelease2 = __esm({
|
|
|
28787
29622
|
profile
|
|
28788
29623
|
};
|
|
28789
29624
|
}
|
|
28790
|
-
const input = JSON.parse(await
|
|
29625
|
+
const input = JSON.parse(await import_promises31.default.readFile(inputPath, "utf8"));
|
|
28791
29626
|
if (options.command === "decide") {
|
|
28792
29627
|
const decision = await deriveStrategyReleaseResearchDecision(input);
|
|
28793
29628
|
if (options.outputPath) {
|
|
28794
|
-
await writeJsonAtomic3(
|
|
29629
|
+
await writeJsonAtomic3(import_node_path28.default.resolve(options.outputPath), decision);
|
|
28795
29630
|
}
|
|
28796
29631
|
return {
|
|
28797
29632
|
kind: "decided",
|
|
28798
29633
|
...decision,
|
|
28799
|
-
outputPath: options.outputPath ?
|
|
29634
|
+
outputPath: options.outputPath ? import_node_path28.default.resolve(options.outputPath) : null
|
|
28800
29635
|
};
|
|
28801
29636
|
}
|
|
28802
29637
|
if (options.command === "retention") {
|
|
28803
29638
|
const plan = planStrategyEvidenceRetention(input);
|
|
28804
29639
|
if (options.apply) {
|
|
28805
|
-
await Promise.all(plan.delete.map((entry) =>
|
|
29640
|
+
await Promise.all(plan.delete.map((entry) => import_promises31.default.rm(entry.path)));
|
|
28806
29641
|
}
|
|
28807
29642
|
return {
|
|
28808
29643
|
kind: "retention",
|
|
@@ -28815,12 +29650,12 @@ var init_strategyRelease2 = __esm({
|
|
|
28815
29650
|
}
|
|
28816
29651
|
if (options.command === "diagnose") {
|
|
28817
29652
|
const diagnosis = buildStrategyLiveDiagnosis(input);
|
|
28818
|
-
const outputPath =
|
|
29653
|
+
const outputPath = import_node_path28.default.resolve(
|
|
28819
29654
|
options.outputPath ?? "output/strategy-live-diagnosis.json"
|
|
28820
29655
|
);
|
|
28821
29656
|
await writeJsonAtomic3(outputPath, diagnosis);
|
|
28822
29657
|
const published2 = options.rootDir ? await publishStrategyLiveDiagnosis({
|
|
28823
|
-
rootDir:
|
|
29658
|
+
rootDir: import_node_path28.default.resolve(options.rootDir),
|
|
28824
29659
|
diagnosis,
|
|
28825
29660
|
sourceArtifacts: input.sourceArtifacts ?? []
|
|
28826
29661
|
}) : null;
|
|
@@ -28837,7 +29672,7 @@ var init_strategyRelease2 = __esm({
|
|
|
28837
29672
|
evidence: await collectReleaseEvidenceReferences(input.evidence ?? [])
|
|
28838
29673
|
});
|
|
28839
29674
|
const published = await publishStrategyRelease({
|
|
28840
|
-
rootDir:
|
|
29675
|
+
rootDir: import_node_path28.default.resolve(options.rootDir ?? "data/strategy-release"),
|
|
28841
29676
|
manifest
|
|
28842
29677
|
});
|
|
28843
29678
|
return {
|
|
@@ -28855,7 +29690,7 @@ var init_strategyRelease2 = __esm({
|
|
|
28855
29690
|
yarn strategy:release profile --input <trades.jsonl> --variant <id> --startTime <ms> --endTime <ms> [--days 7,30,90] [--out <profile.json>]
|
|
28856
29691
|
yarn strategy:release diagnose --input <diagnosis-input.json> [--out output/diagnosis.json]
|
|
28857
29692
|
yarn strategy:release retention --input <inventory.json> [--apply]`);
|
|
28858
|
-
|
|
29693
|
+
main40 = async () => {
|
|
28859
29694
|
const argv2 = process.argv.slice(2);
|
|
28860
29695
|
const command = argv2[0];
|
|
28861
29696
|
if (!command || ![
|
|
@@ -28881,7 +29716,7 @@ var init_strategyRelease2 = __esm({
|
|
|
28881
29716
|
endTime: Number(valueAfter2(argv2, "--endTime")),
|
|
28882
29717
|
days: valueAfter2(argv2, "--days")?.split(",").map((entry) => Number(entry.trim()))
|
|
28883
29718
|
});
|
|
28884
|
-
console.log(
|
|
29719
|
+
console.log(import_chalk44.default.green(JSON.stringify(result, null, 2)));
|
|
28885
29720
|
};
|
|
28886
29721
|
}
|
|
28887
29722
|
});
|
|
@@ -28894,18 +29729,18 @@ __export(serverHealth_exports, {
|
|
|
28894
29729
|
buildServerHealthDiagnostics: () => buildServerHealthDiagnostics,
|
|
28895
29730
|
collectServerHealthSnapshot: () => collectServerHealthSnapshot,
|
|
28896
29731
|
evaluateServerHealth: () => evaluateServerHealth,
|
|
28897
|
-
main: () =>
|
|
29732
|
+
main: () => main41,
|
|
28898
29733
|
resolveServerHealthThresholds: () => resolveServerHealthThresholds
|
|
28899
29734
|
});
|
|
28900
|
-
var import_config10,
|
|
29735
|
+
var import_config10, import_node_child_process9, import_node_os3, import_node_fs6, import_args31, import_redis16, DEFAULT_STATE, DEFAULT_THRESHOLDS, escapeHtml4, formatPctValue, formatLoadPerCore, formatGiB, formatDuration2, readDiskUsage, parseMeminfoBytes, readMemorySnapshot, runDiagnosticCommand, runDiagnosticCommands, collectServerHealthSnapshot, buildHumanSummaryLines, evaluateServerHealth, shouldRecover, buildAlertMessage, buildRecoveryMessage, buildServerHealthDiagnostics, getStateKey, toFiniteNumber3, resolveServerHealthThresholds, main41;
|
|
28901
29736
|
var init_serverHealth = __esm({
|
|
28902
29737
|
"src/scripts/serverHealth.ts"() {
|
|
28903
29738
|
"use strict";
|
|
28904
29739
|
import_config10 = require("dotenv/config");
|
|
28905
|
-
|
|
29740
|
+
import_node_child_process9 = require("child_process");
|
|
28906
29741
|
import_node_os3 = __toESM(require("os"));
|
|
28907
29742
|
import_node_fs6 = require("fs");
|
|
28908
|
-
|
|
29743
|
+
import_args31 = __toESM(require("args"));
|
|
28909
29744
|
import_redis16 = require("@tradejs/infra/redis");
|
|
28910
29745
|
init_telegramReports();
|
|
28911
29746
|
DEFAULT_STATE = {
|
|
@@ -28939,21 +29774,21 @@ var init_serverHealth = __esm({
|
|
|
28939
29774
|
}
|
|
28940
29775
|
return `${minutes}m`;
|
|
28941
29776
|
};
|
|
28942
|
-
readDiskUsage = (
|
|
29777
|
+
readDiskUsage = (path41) => {
|
|
28943
29778
|
try {
|
|
28944
|
-
const stats = (0, import_node_fs6.statfsSync)(
|
|
29779
|
+
const stats = (0, import_node_fs6.statfsSync)(path41);
|
|
28945
29780
|
const totalBlocks = Number(stats.blocks ?? 0);
|
|
28946
29781
|
const availableBlocks = Number(stats.bavail ?? 0);
|
|
28947
29782
|
if (totalBlocks <= 0) {
|
|
28948
|
-
return { path:
|
|
29783
|
+
return { path: path41, usedPct: null };
|
|
28949
29784
|
}
|
|
28950
29785
|
const usedPct = (totalBlocks - Math.max(0, availableBlocks)) / totalBlocks * 100;
|
|
28951
29786
|
return {
|
|
28952
|
-
path:
|
|
29787
|
+
path: path41,
|
|
28953
29788
|
usedPct: Number.isFinite(usedPct) ? usedPct : null
|
|
28954
29789
|
};
|
|
28955
29790
|
} catch {
|
|
28956
|
-
return { path:
|
|
29791
|
+
return { path: path41, usedPct: null };
|
|
28957
29792
|
}
|
|
28958
29793
|
};
|
|
28959
29794
|
parseMeminfoBytes = (value) => {
|
|
@@ -29017,8 +29852,8 @@ var init_serverHealth = __esm({
|
|
|
29017
29852
|
};
|
|
29018
29853
|
}
|
|
29019
29854
|
};
|
|
29020
|
-
runDiagnosticCommand = (command,
|
|
29021
|
-
const output = (0,
|
|
29855
|
+
runDiagnosticCommand = (command, args37) => {
|
|
29856
|
+
const output = (0, import_node_child_process9.execFileSync)(command, args37, {
|
|
29022
29857
|
encoding: "utf8",
|
|
29023
29858
|
timeout: 5e3,
|
|
29024
29859
|
maxBuffer: 1024 * 1024,
|
|
@@ -29268,57 +30103,57 @@ var init_serverHealth = __esm({
|
|
|
29268
30103
|
diskRecoverPct: diskRecoverPct != null && diskRecoverPct > 0 ? diskRecoverPct : DEFAULT_THRESHOLDS.diskRecoverPct
|
|
29269
30104
|
};
|
|
29270
30105
|
};
|
|
29271
|
-
|
|
29272
|
-
|
|
29273
|
-
|
|
30106
|
+
import_args31.default.option(["u", "user"], "Use user config", "root");
|
|
30107
|
+
import_args31.default.option(["P", "printOnly"], "Print report instead of Telegram", false);
|
|
30108
|
+
import_args31.default.option(
|
|
29274
30109
|
["d", "diskPath"],
|
|
29275
30110
|
"Filesystem path to inspect for disk pressure",
|
|
29276
30111
|
"/"
|
|
29277
30112
|
);
|
|
29278
|
-
|
|
30113
|
+
import_args31.default.option(
|
|
29279
30114
|
["c", "cooldownSec"],
|
|
29280
30115
|
"Minimum seconds between repeated unhealthy reminders",
|
|
29281
30116
|
900
|
|
29282
30117
|
);
|
|
29283
|
-
|
|
30118
|
+
import_args31.default.option(
|
|
29284
30119
|
["l", "loadPerCpuWarn"],
|
|
29285
30120
|
"Alert when 1m load per CPU reaches this value",
|
|
29286
30121
|
String(DEFAULT_THRESHOLDS.loadPerCpuWarn)
|
|
29287
30122
|
);
|
|
29288
|
-
|
|
30123
|
+
import_args31.default.option(
|
|
29289
30124
|
["L", "loadPerCpuRecover"],
|
|
29290
30125
|
"Recovery threshold for 1m load per CPU",
|
|
29291
30126
|
String(DEFAULT_THRESHOLDS.loadPerCpuRecover)
|
|
29292
30127
|
);
|
|
29293
|
-
|
|
30128
|
+
import_args31.default.option(
|
|
29294
30129
|
["m", "memoryWarnPct"],
|
|
29295
30130
|
"Alert when memory used percent reaches this value",
|
|
29296
30131
|
String(DEFAULT_THRESHOLDS.memoryWarnPct)
|
|
29297
30132
|
);
|
|
29298
|
-
|
|
30133
|
+
import_args31.default.option(
|
|
29299
30134
|
["M", "memoryRecoverPct"],
|
|
29300
30135
|
"Recovery threshold for memory used percent",
|
|
29301
30136
|
String(DEFAULT_THRESHOLDS.memoryRecoverPct)
|
|
29302
30137
|
);
|
|
29303
|
-
|
|
30138
|
+
import_args31.default.option(
|
|
29304
30139
|
["D", "diskWarnPct"],
|
|
29305
30140
|
"Alert when disk used percent reaches this value",
|
|
29306
30141
|
String(DEFAULT_THRESHOLDS.diskWarnPct)
|
|
29307
30142
|
);
|
|
29308
|
-
|
|
30143
|
+
import_args31.default.option(
|
|
29309
30144
|
["R", "diskRecoverPct"],
|
|
29310
30145
|
"Recovery threshold for disk used percent",
|
|
29311
30146
|
String(DEFAULT_THRESHOLDS.diskRecoverPct)
|
|
29312
30147
|
);
|
|
29313
|
-
|
|
29314
|
-
const
|
|
29315
|
-
const thresholds = resolveServerHealthThresholds(
|
|
29316
|
-
const diskPath = String(
|
|
30148
|
+
main41 = async () => {
|
|
30149
|
+
const flags34 = import_args31.default.parse(process.argv);
|
|
30150
|
+
const thresholds = resolveServerHealthThresholds(flags34);
|
|
30151
|
+
const diskPath = String(flags34.diskPath || "/");
|
|
29317
30152
|
const snapshot = collectServerHealthSnapshot(diskPath);
|
|
29318
|
-
const stateKey = getStateKey(String(
|
|
30153
|
+
const stateKey = getStateKey(String(flags34.user), snapshot.hostname);
|
|
29319
30154
|
const prevState = await (0, import_redis16.getData)(stateKey, DEFAULT_STATE) ?? DEFAULT_STATE;
|
|
29320
30155
|
const evaluation = evaluateServerHealth(snapshot, thresholds);
|
|
29321
|
-
const cooldownMs = Math.max(60, Number(
|
|
30156
|
+
const cooldownMs = Math.max(60, Number(flags34.cooldownSec)) * 1e3;
|
|
29322
30157
|
const now2 = snapshot.timestamp;
|
|
29323
30158
|
if (!evaluation.isHealthy) {
|
|
29324
30159
|
const reminder = prevState.status === "alerting" && typeof prevState.lastAlertAt === "number" && now2 - prevState.lastAlertAt < cooldownMs ? false : prevState.status === "alerting";
|
|
@@ -29336,7 +30171,7 @@ var init_serverHealth = __esm({
|
|
|
29336
30171
|
prevState,
|
|
29337
30172
|
reminder
|
|
29338
30173
|
});
|
|
29339
|
-
if (
|
|
30174
|
+
if (flags34.printOnly) {
|
|
29340
30175
|
console.log(message);
|
|
29341
30176
|
console.log("");
|
|
29342
30177
|
console.log(
|
|
@@ -29346,7 +30181,7 @@ var init_serverHealth = __esm({
|
|
|
29346
30181
|
})
|
|
29347
30182
|
);
|
|
29348
30183
|
} else {
|
|
29349
|
-
await sendTelegramReport(message, { userName:
|
|
30184
|
+
await sendTelegramReport(message, { userName: flags34.user });
|
|
29350
30185
|
}
|
|
29351
30186
|
}
|
|
29352
30187
|
return;
|
|
@@ -29361,10 +30196,10 @@ var init_serverHealth = __esm({
|
|
|
29361
30196
|
await (0, import_redis16.setData)(stateKey, nextState, { expire: 0 });
|
|
29362
30197
|
if (recovered) {
|
|
29363
30198
|
const message = buildRecoveryMessage({ snapshot, prevState });
|
|
29364
|
-
if (
|
|
30199
|
+
if (flags34.printOnly) {
|
|
29365
30200
|
console.log(message);
|
|
29366
30201
|
} else {
|
|
29367
|
-
await sendTelegramReport(message, { userName:
|
|
30202
|
+
await sendTelegramReport(message, { userName: flags34.user });
|
|
29368
30203
|
}
|
|
29369
30204
|
}
|
|
29370
30205
|
};
|
|
@@ -30767,11 +31602,11 @@ var init_reportingJson = __esm({
|
|
|
30767
31602
|
});
|
|
30768
31603
|
|
|
30769
31604
|
// src/lib/runtimeParity/reportingTerminal.ts
|
|
30770
|
-
var
|
|
31605
|
+
var import_chalk45, import_time8, DETAIL_LIMIT, buildRuntimeParityTerminalReport, writeRuntimeParityTerminalReport, printRuntimeDuplicateDetails, printClassifiedBacktestOnlyDetails, printClassifiedRuntimeOnlyDetails;
|
|
30771
31606
|
var init_reportingTerminal = __esm({
|
|
30772
31607
|
"src/lib/runtimeParity/reportingTerminal.ts"() {
|
|
30773
31608
|
"use strict";
|
|
30774
|
-
|
|
31609
|
+
import_chalk45 = __toESM(require("chalk"));
|
|
30775
31610
|
import_time8 = require("@tradejs/core/time");
|
|
30776
31611
|
init_classification();
|
|
30777
31612
|
init_reportingShared();
|
|
@@ -30780,7 +31615,7 @@ var init_reportingTerminal = __esm({
|
|
|
30780
31615
|
const mismatchRows = buildMismatchSummaryRows(context);
|
|
30781
31616
|
const strategyIssueRows = buildStrategyIssueRows(context.strategyRows);
|
|
30782
31617
|
const lines = [
|
|
30783
|
-
|
|
31618
|
+
import_chalk45.default.cyan("TradeJS runtime parity"),
|
|
30784
31619
|
`Window: ${(0, import_time8.formatUnix)(context.window.start)} -> ${(0, import_time8.formatUnix)(context.window.end)} (${context.window.source})`,
|
|
30785
31620
|
`Connector: ${context.connectorName}`,
|
|
30786
31621
|
`Replay env: ${context.replayEnv}${context.runtimeGatesEnabled ? " (runtime AI/ML gates enabled)" : " (core/backtest gates only)"}`,
|
|
@@ -30809,7 +31644,7 @@ var init_reportingTerminal = __esm({
|
|
|
30809
31644
|
lines.push(`Runtime evaluations: ${context.runtimeSignalEvaluationsCount}`);
|
|
30810
31645
|
}
|
|
30811
31646
|
if (mismatchRows.length) {
|
|
30812
|
-
lines.push("",
|
|
31647
|
+
lines.push("", import_chalk45.default.yellow("Signal mismatches"));
|
|
30813
31648
|
for (const item of mismatchRows.slice(0, context.detailLimit)) {
|
|
30814
31649
|
lines.push(`- ${item.line}`);
|
|
30815
31650
|
}
|
|
@@ -30819,14 +31654,14 @@ var init_reportingTerminal = __esm({
|
|
|
30819
31654
|
}
|
|
30820
31655
|
lines.push("");
|
|
30821
31656
|
if (strategyIssueRows.length) {
|
|
30822
|
-
lines.push(
|
|
31657
|
+
lines.push(import_chalk45.default.cyan("Strategy issues"), ...strategyIssueRows);
|
|
30823
31658
|
} else if (context.strategyRows.length) {
|
|
30824
31659
|
lines.push(
|
|
30825
31660
|
`Strategies: clean ${context.strategyRows.length}/${context.strategyRows.length}`
|
|
30826
31661
|
);
|
|
30827
31662
|
}
|
|
30828
31663
|
if (context.runtimeGateWarningCounts.size && !context.runtimeGatesRequested) {
|
|
30829
|
-
lines.push("",
|
|
31664
|
+
lines.push("", import_chalk45.default.yellow("Warnings"));
|
|
30830
31665
|
for (const [strategy, count] of [
|
|
30831
31666
|
...context.runtimeGateWarningCounts.entries()
|
|
30832
31667
|
].sort(([left], [right]) => left.localeCompare(right))) {
|
|
@@ -30836,7 +31671,7 @@ var init_reportingTerminal = __esm({
|
|
|
30836
31671
|
}
|
|
30837
31672
|
}
|
|
30838
31673
|
if (context.replayErrors.length) {
|
|
30839
|
-
lines.push("",
|
|
31674
|
+
lines.push("", import_chalk45.default.red("Replay errors"));
|
|
30840
31675
|
for (const error of context.replayErrors.slice(0, context.detailLimit)) {
|
|
30841
31676
|
lines.push(`- ${error.strategy} ${error.symbol}: ${error.message}`);
|
|
30842
31677
|
}
|
|
@@ -30854,7 +31689,7 @@ var init_reportingTerminal = __esm({
|
|
|
30854
31689
|
printRuntimeDuplicateDetails = (groups) => {
|
|
30855
31690
|
if (!groups.length) return;
|
|
30856
31691
|
console.log("");
|
|
30857
|
-
console.log(
|
|
31692
|
+
console.log(import_chalk45.default.yellow("Runtime duplicates"));
|
|
30858
31693
|
for (const group of groups.slice(0, DETAIL_LIMIT)) {
|
|
30859
31694
|
const ids = group.entries.map((entry) => entry.orderId ?? entry.id);
|
|
30860
31695
|
console.log(
|
|
@@ -30868,7 +31703,7 @@ var init_reportingTerminal = __esm({
|
|
|
30868
31703
|
printClassifiedBacktestOnlyDetails = (classifiedEntries) => {
|
|
30869
31704
|
if (!classifiedEntries.length) return;
|
|
30870
31705
|
console.log("");
|
|
30871
|
-
console.log(
|
|
31706
|
+
console.log(import_chalk45.default.yellow("Backtest only"));
|
|
30872
31707
|
for (const item of classifiedEntries.slice(0, DETAIL_LIMIT)) {
|
|
30873
31708
|
const evidenceSuffix = item.signal ? ` signalId=${item.signal.signalId} signalDrift=${formatMinutes2(item.signalTimestampDiffMs ?? null)}` : item.evaluation ? ` evaluationId=${item.evaluation.evaluationId} evaluationDrift=${formatMinutes2(item.evaluationTimestampDiffMs ?? null)}` : "";
|
|
30874
31709
|
const price = item.entry.price == null ? "n/a" : item.entry.price.toFixed(6);
|
|
@@ -30883,7 +31718,7 @@ var init_reportingTerminal = __esm({
|
|
|
30883
31718
|
printClassifiedRuntimeOnlyDetails = (classifiedEntries) => {
|
|
30884
31719
|
if (!classifiedEntries.length) return;
|
|
30885
31720
|
console.log("");
|
|
30886
|
-
console.log(
|
|
31721
|
+
console.log(import_chalk45.default.yellow("Runtime only"));
|
|
30887
31722
|
for (const item of classifiedEntries.slice(0, DETAIL_LIMIT)) {
|
|
30888
31723
|
const evidenceSuffix = item.nearestBacktestEntry ? ` nearestBacktestId=${item.nearestBacktestEntry.id} backtestDrift=${formatMinutes2(item.nearestBacktestEntryTimestampDiffMs ?? null)}` : item.evaluation ? ` replayEvaluationId=${item.evaluation.evaluationId} replayDrift=${formatMinutes2(item.evaluationTimestampDiffMs ?? null)} status=${item.evaluation.status}` : "";
|
|
30889
31724
|
const price = item.entry.price == null ? "n/a" : item.entry.price.toFixed(6);
|
|
@@ -31058,17 +31893,17 @@ var init_reporting = __esm({
|
|
|
31058
31893
|
var runtimeParity_exports = {};
|
|
31059
31894
|
__export(runtimeParity_exports, {
|
|
31060
31895
|
buildRuntimeParityMessage: () => buildRuntimeParityMessage,
|
|
31061
|
-
main: () =>
|
|
31896
|
+
main: () => main42,
|
|
31062
31897
|
runtimeParity: () => runtimeParity
|
|
31063
31898
|
});
|
|
31064
|
-
var import_config11,
|
|
31899
|
+
var import_config11, import_node_crypto16, import_args32, import_chalk46, import_constants15, import_time9, import_logger6, import_redis17, import_cli11, import_backtest3, import_connectors14, flags30, interval3, projectRoot15, DEFAULT_LOOKBACK_DAYS, DETAIL_LIMIT2, DEFAULT_REPLAY_ENV, resolveParityConnectorName, createConnector, buildReplayAiAnalyses, formatReplayEnvSummary, buildReplayConfig, warmReplayHistory, runtimeParity, main42;
|
|
31065
31900
|
var init_runtimeParity2 = __esm({
|
|
31066
31901
|
"src/scripts/runtimeParity.ts"() {
|
|
31067
31902
|
"use strict";
|
|
31068
31903
|
import_config11 = require("dotenv/config");
|
|
31069
|
-
|
|
31070
|
-
|
|
31071
|
-
|
|
31904
|
+
import_node_crypto16 = require("crypto");
|
|
31905
|
+
import_args32 = __toESM(require("args"));
|
|
31906
|
+
import_chalk46 = __toESM(require("chalk"));
|
|
31072
31907
|
import_constants15 = require("@tradejs/core/constants");
|
|
31073
31908
|
import_time9 = require("@tradejs/core/time");
|
|
31074
31909
|
import_logger6 = require("@tradejs/infra/logger");
|
|
@@ -31091,45 +31926,45 @@ var init_runtimeParity2 = __esm({
|
|
|
31091
31926
|
init_reporting();
|
|
31092
31927
|
init_reporting();
|
|
31093
31928
|
init_runtimeModeConfig();
|
|
31094
|
-
|
|
31095
|
-
|
|
31929
|
+
import_args32.default.option(["u", "user"], "Use user config", "root");
|
|
31930
|
+
import_args32.default.option(
|
|
31096
31931
|
["o", "connector"],
|
|
31097
31932
|
"Connector provider or name for parity replay (e.g. bybit, binance, coinbase, custom)",
|
|
31098
31933
|
"bybit"
|
|
31099
31934
|
);
|
|
31100
|
-
|
|
31101
|
-
|
|
31935
|
+
import_args32.default.option(["d", "days"], "Replay window in days", 3);
|
|
31936
|
+
import_args32.default.option(
|
|
31102
31937
|
["b", "startTime"],
|
|
31103
31938
|
"Explicit replay start timestamp (ms or seconds)"
|
|
31104
31939
|
);
|
|
31105
|
-
|
|
31106
|
-
|
|
31107
|
-
|
|
31940
|
+
import_args32.default.option(["e", "endTime"], "Explicit replay end timestamp (ms or seconds)");
|
|
31941
|
+
import_args32.default.option(["s", "strategy"], "Only compare one strategy");
|
|
31942
|
+
import_args32.default.option(
|
|
31108
31943
|
["t", "tickers"],
|
|
31109
31944
|
"Replay comma-separated symbols for all configured strategies"
|
|
31110
31945
|
);
|
|
31111
|
-
|
|
31946
|
+
import_args32.default.option(
|
|
31112
31947
|
["C", "cacheOnly"],
|
|
31113
31948
|
"Do not refresh market history before replay",
|
|
31114
31949
|
false
|
|
31115
31950
|
);
|
|
31116
|
-
|
|
31951
|
+
import_args32.default.option(
|
|
31117
31952
|
["a", "toleranceBars"],
|
|
31118
31953
|
"Allowed entry timestamp drift in bars when matching runtime vs backtest",
|
|
31119
31954
|
1
|
|
31120
31955
|
);
|
|
31121
|
-
|
|
31956
|
+
import_args32.default.option(
|
|
31122
31957
|
"fullUniverse",
|
|
31123
31958
|
"Replay every configured strategy across the full connector universe. By default parity replays only runtime-traded and strategy-results symbols unless --tickers is provided.",
|
|
31124
31959
|
false
|
|
31125
31960
|
);
|
|
31126
|
-
|
|
31961
|
+
import_args32.default.option(
|
|
31127
31962
|
"runtimeGates",
|
|
31128
31963
|
"Force runtime AI/ML gates for all replay targets. Runtime-gated configs are replayed with gates by default.",
|
|
31129
31964
|
false
|
|
31130
31965
|
);
|
|
31131
|
-
|
|
31132
|
-
|
|
31966
|
+
import_args32.default.option(["N", "notify"], "Send parity summary to Telegram", false);
|
|
31967
|
+
import_args32.default.option(["D", "details"], "Print unmatched entry details (capped)", false);
|
|
31133
31968
|
process.argv = normalizeCliArgv(process.argv, {
|
|
31134
31969
|
"-C": "--cacheOnly",
|
|
31135
31970
|
"-D": "--details",
|
|
@@ -31138,14 +31973,14 @@ var init_runtimeParity2 = __esm({
|
|
|
31138
31973
|
"-S": "--startTime",
|
|
31139
31974
|
"-T": "--toleranceBars"
|
|
31140
31975
|
});
|
|
31141
|
-
|
|
31976
|
+
flags30 = import_args32.default.parse(process.argv);
|
|
31142
31977
|
interval3 = "15";
|
|
31143
|
-
|
|
31978
|
+
projectRoot15 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
31144
31979
|
DEFAULT_LOOKBACK_DAYS = 3;
|
|
31145
31980
|
DETAIL_LIMIT2 = 10;
|
|
31146
|
-
DEFAULT_REPLAY_ENV =
|
|
31981
|
+
DEFAULT_REPLAY_ENV = flags30.runtimeGates ? "PARITY" : "BACKTEST";
|
|
31147
31982
|
resolveParityConnectorName = async (value) => {
|
|
31148
|
-
const connectorName = await (0, import_connectors14.resolveConnectorName)(value,
|
|
31983
|
+
const connectorName = await (0, import_connectors14.resolveConnectorName)(value, projectRoot15);
|
|
31149
31984
|
if (connectorName) {
|
|
31150
31985
|
return connectorName;
|
|
31151
31986
|
}
|
|
@@ -31162,7 +31997,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31162
31997
|
}) => {
|
|
31163
31998
|
const connectorFactory = await (0, import_connectors14.getConnectorCreatorByName)(
|
|
31164
31999
|
connectorName,
|
|
31165
|
-
|
|
32000
|
+
projectRoot15
|
|
31166
32001
|
);
|
|
31167
32002
|
if (!connectorFactory) {
|
|
31168
32003
|
throw new Error(`Connector "${connectorName}" is not registered`);
|
|
@@ -31254,7 +32089,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31254
32089
|
strategyConfig,
|
|
31255
32090
|
env: resolveReplayStrategyEnv({
|
|
31256
32091
|
strategyConfig,
|
|
31257
|
-
forceRuntimeGates: Boolean(
|
|
32092
|
+
forceRuntimeGates: Boolean(flags30.runtimeGates)
|
|
31258
32093
|
}),
|
|
31259
32094
|
interval: interval3,
|
|
31260
32095
|
makeOrders: true,
|
|
@@ -31273,7 +32108,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31273
32108
|
const symbols = [...new Set(targets.map((target) => target.symbol))];
|
|
31274
32109
|
const warmStartedAt = Date.now();
|
|
31275
32110
|
console.log(
|
|
31276
|
-
|
|
32111
|
+
import_chalk46.default.gray(
|
|
31277
32112
|
`Warm history: ${symbols.length} symbol(s) on ${connectorName}, preload ${(0, import_time9.formatUnix)(preloadStart)} -> ${(0, import_time9.formatUnix)(preloadEnd)}`
|
|
31278
32113
|
)
|
|
31279
32114
|
);
|
|
@@ -31281,7 +32116,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31281
32116
|
connectorName,
|
|
31282
32117
|
marketConnector: connector,
|
|
31283
32118
|
userName: userName3,
|
|
31284
|
-
projectRoot:
|
|
32119
|
+
projectRoot: projectRoot15,
|
|
31285
32120
|
shouldUseDedicatedReferences: true,
|
|
31286
32121
|
warn: (message) => import_logger6.logger.warn(message)
|
|
31287
32122
|
});
|
|
@@ -31293,39 +32128,39 @@ var init_runtimeParity2 = __esm({
|
|
|
31293
32128
|
symbols,
|
|
31294
32129
|
preloadStart,
|
|
31295
32130
|
preloadEnd,
|
|
31296
|
-
log: (message) => console.log(
|
|
32131
|
+
log: (message) => console.log(import_chalk46.default.gray(message))
|
|
31297
32132
|
});
|
|
31298
32133
|
console.log(
|
|
31299
|
-
|
|
32134
|
+
import_chalk46.default.gray(`Warm history: done in ${formatDuration(warmStartedAt)}`)
|
|
31300
32135
|
);
|
|
31301
32136
|
};
|
|
31302
32137
|
runtimeParity = async () => {
|
|
31303
32138
|
const window = resolveTimeWindow({
|
|
31304
|
-
days:
|
|
31305
|
-
startTime:
|
|
31306
|
-
endTime:
|
|
32139
|
+
days: flags30.days ?? DEFAULT_LOOKBACK_DAYS,
|
|
32140
|
+
startTime: flags30.startTime,
|
|
32141
|
+
endTime: flags30.endTime,
|
|
31307
32142
|
defaultStartMs: Date.now() - DEFAULT_LOOKBACK_DAYS * 24 * 60 * 60 * 1e3,
|
|
31308
32143
|
defaultEndMs: Date.now()
|
|
31309
32144
|
});
|
|
31310
32145
|
const toleranceBars = Math.max(
|
|
31311
32146
|
0,
|
|
31312
|
-
Number.parseInt(String(
|
|
32147
|
+
Number.parseInt(String(flags30.toleranceBars ?? 1), 10) || 0
|
|
31313
32148
|
);
|
|
31314
32149
|
const toleranceMs = toleranceBars * 15 * 60 * 1e3;
|
|
31315
|
-
const connectorName = await resolveParityConnectorName(
|
|
31316
|
-
const requestedSymbols = parseSymbolsFromCLI2(String(
|
|
32150
|
+
const connectorName = await resolveParityConnectorName(flags30.connector);
|
|
32151
|
+
const requestedSymbols = parseSymbolsFromCLI2(String(flags30.tickers || ""));
|
|
31317
32152
|
const requestedSymbolSet = requestedSymbols.length ? new Set(requestedSymbols) : null;
|
|
31318
32153
|
let replayErrors = [];
|
|
31319
32154
|
try {
|
|
31320
32155
|
const parityConnector = await createConnector({
|
|
31321
|
-
userName:
|
|
32156
|
+
userName: flags30.user,
|
|
31322
32157
|
connectorName
|
|
31323
32158
|
});
|
|
31324
32159
|
const { runtimeTrades, runtimeSignals, runtimeSignalEvaluations } = await loadRuntimeParityEvidence(
|
|
31325
32160
|
{
|
|
31326
|
-
userName:
|
|
32161
|
+
userName: flags30.user,
|
|
31327
32162
|
window,
|
|
31328
|
-
strategy:
|
|
32163
|
+
strategy: flags30.strategy,
|
|
31329
32164
|
symbols: requestedSymbolSet
|
|
31330
32165
|
},
|
|
31331
32166
|
{
|
|
@@ -31340,29 +32175,29 @@ var init_runtimeParity2 = __esm({
|
|
|
31340
32175
|
runtimeSignalEvaluations
|
|
31341
32176
|
});
|
|
31342
32177
|
const replayTargets = await buildReplayTargets({
|
|
31343
|
-
userName:
|
|
32178
|
+
userName: flags30.user,
|
|
31344
32179
|
runtimeTrades,
|
|
31345
32180
|
connectorSymbols,
|
|
31346
|
-
strategyFilter: String(
|
|
32181
|
+
strategyFilter: String(flags30.strategy || "").trim() || void 0,
|
|
31347
32182
|
explicitSymbols: requestedSymbols,
|
|
31348
|
-
includeConnectorUniverse: Boolean(
|
|
32183
|
+
includeConnectorUniverse: Boolean(flags30.fullUniverse)
|
|
31349
32184
|
});
|
|
31350
32185
|
if (!replayTargets.length) {
|
|
31351
32186
|
console.log(
|
|
31352
|
-
|
|
31353
|
-
`No replay targets found for ${
|
|
32187
|
+
import_chalk46.default.yellow(
|
|
32188
|
+
`No replay targets found for ${flags30.user} in ${(0, import_time9.formatUnix)(window.start)} -> ${(0, import_time9.formatUnix)(window.end)}.`
|
|
31354
32189
|
)
|
|
31355
32190
|
);
|
|
31356
|
-
if (
|
|
32191
|
+
if (flags30.notify) {
|
|
31357
32192
|
await sendTelegramReport(
|
|
31358
32193
|
buildRuntimeParityNoTargetsMessage({
|
|
31359
32194
|
window,
|
|
31360
32195
|
connectorName,
|
|
31361
32196
|
replayEnv: DEFAULT_REPLAY_ENV,
|
|
31362
|
-
runtimeGatesEnabled: Boolean(
|
|
31363
|
-
userName: String(
|
|
32197
|
+
runtimeGatesEnabled: Boolean(flags30.runtimeGates),
|
|
32198
|
+
userName: String(flags30.user)
|
|
31364
32199
|
}),
|
|
31365
|
-
{ userName:
|
|
32200
|
+
{ userName: flags30.user }
|
|
31366
32201
|
);
|
|
31367
32202
|
}
|
|
31368
32203
|
return;
|
|
@@ -31377,14 +32212,14 @@ var init_runtimeParity2 = __esm({
|
|
|
31377
32212
|
replayTargets.map((target) => target.symbol)
|
|
31378
32213
|
).size;
|
|
31379
32214
|
console.log(
|
|
31380
|
-
|
|
31381
|
-
`Replay queue: ${replayTargets.length} target(s), ${replaySymbolsCount} symbol(s), mode=${
|
|
32215
|
+
import_chalk46.default.gray(
|
|
32216
|
+
`Replay queue: ${replayTargets.length} target(s), ${replaySymbolsCount} symbol(s), mode=${flags30.fullUniverse ? "full-universe" : requestedSymbols.length ? "explicit-tickers" : "runtime+results"}`
|
|
31382
32217
|
)
|
|
31383
32218
|
);
|
|
31384
32219
|
const replayConfigs = /* @__PURE__ */ new Map();
|
|
31385
32220
|
for (const target of replayTargets) {
|
|
31386
32221
|
const replayConfig = await buildReplayConfig({
|
|
31387
|
-
userName:
|
|
32222
|
+
userName: flags30.user,
|
|
31388
32223
|
strategy: target.strategy,
|
|
31389
32224
|
symbol: target.symbol,
|
|
31390
32225
|
replayInputsIndex,
|
|
@@ -31401,22 +32236,22 @@ var init_runtimeParity2 = __esm({
|
|
|
31401
32236
|
);
|
|
31402
32237
|
await prepareMarketContextForRun({
|
|
31403
32238
|
mode: "parity",
|
|
31404
|
-
userName:
|
|
31405
|
-
projectRoot:
|
|
32239
|
+
userName: flags30.user,
|
|
32240
|
+
projectRoot: projectRoot15,
|
|
31406
32241
|
symbols: replayTargets.map((target) => target.symbol),
|
|
31407
32242
|
interval: interval3,
|
|
31408
32243
|
startMs: window.start,
|
|
31409
32244
|
endMs: window.end,
|
|
31410
32245
|
preloadStartMs: preloadStart,
|
|
31411
|
-
cacheOnly: Boolean(
|
|
32246
|
+
cacheOnly: Boolean(flags30.cacheOnly),
|
|
31412
32247
|
aiEnabled: hasParityAiTargets,
|
|
31413
32248
|
mlEnabled: hasParityMlTargets,
|
|
31414
32249
|
strategyNames: replayTargets.map((target) => target.strategy),
|
|
31415
|
-
log: (message) => console.log(
|
|
32250
|
+
log: (message) => console.log(import_chalk46.default.gray(message))
|
|
31416
32251
|
});
|
|
31417
|
-
if (!
|
|
32252
|
+
if (!flags30.cacheOnly) {
|
|
31418
32253
|
await warmReplayHistory({
|
|
31419
|
-
userName:
|
|
32254
|
+
userName: flags30.user,
|
|
31420
32255
|
connectorName,
|
|
31421
32256
|
targets: replayTargets,
|
|
31422
32257
|
preloadStart,
|
|
@@ -31443,15 +32278,15 @@ var init_runtimeParity2 = __esm({
|
|
|
31443
32278
|
);
|
|
31444
32279
|
}
|
|
31445
32280
|
const result = await (0, import_backtest3.testing)({
|
|
31446
|
-
userName:
|
|
32281
|
+
userName: flags30.user,
|
|
31447
32282
|
symbol: target.symbol,
|
|
31448
32283
|
options: {
|
|
31449
32284
|
start: window.start,
|
|
31450
32285
|
end: window.end
|
|
31451
32286
|
},
|
|
31452
|
-
name: `${target.symbol}_${target.strategy}_${(0,
|
|
31453
|
-
testId: (0,
|
|
31454
|
-
testSuiteId: (0,
|
|
32287
|
+
name: `${target.symbol}_${target.strategy}_${(0, import_node_crypto16.randomUUID)().slice(0, 8)}`,
|
|
32288
|
+
testId: (0, import_node_crypto16.randomUUID)().slice(0, 8),
|
|
32289
|
+
testSuiteId: (0, import_node_crypto16.randomUUID)().slice(0, 8),
|
|
31455
32290
|
strategyName: target.strategy,
|
|
31456
32291
|
strategyConfig: replayConfig,
|
|
31457
32292
|
connectorName,
|
|
@@ -31472,15 +32307,15 @@ var init_runtimeParity2 = __esm({
|
|
|
31472
32307
|
});
|
|
31473
32308
|
} finally {
|
|
31474
32309
|
(0, import_backtest3.releaseTestingSymbolCache)({
|
|
31475
|
-
cwd:
|
|
31476
|
-
userName:
|
|
32310
|
+
cwd: projectRoot15,
|
|
32311
|
+
userName: flags30.user,
|
|
31477
32312
|
connectorName,
|
|
31478
32313
|
symbol: target.symbol
|
|
31479
32314
|
});
|
|
31480
32315
|
}
|
|
31481
32316
|
if (progressPosition === 1 || progressPosition === replayTargets.length || progressPosition % 25 === 0) {
|
|
31482
32317
|
console.log(
|
|
31483
|
-
|
|
32318
|
+
import_chalk46.default.gray(
|
|
31484
32319
|
`Replay progress: ${progressPosition}/${replayTargets.length}, ok=${successfulTargetKeys.size}, errors=${replayErrors.length}, current=${target.strategy} ${target.symbol}, elapsed=${formatDuration(replayStartedAt)}`
|
|
31485
32320
|
)
|
|
31486
32321
|
);
|
|
@@ -31511,8 +32346,8 @@ var init_runtimeParity2 = __esm({
|
|
|
31511
32346
|
window,
|
|
31512
32347
|
connectorName,
|
|
31513
32348
|
replayEnv: replayEnvSummary,
|
|
31514
|
-
runtimeGatesEnabled: Boolean(
|
|
31515
|
-
runtimeGatesRequested: Boolean(
|
|
32349
|
+
runtimeGatesEnabled: Boolean(flags30.runtimeGates) || replayEnvSummary.includes("PARITY"),
|
|
32350
|
+
runtimeGatesRequested: Boolean(flags30.runtimeGates),
|
|
31516
32351
|
toleranceBars,
|
|
31517
32352
|
toleranceMs,
|
|
31518
32353
|
replayTargetsCount: replayTargets.length,
|
|
@@ -31535,12 +32370,12 @@ var init_runtimeParity2 = __esm({
|
|
|
31535
32370
|
detailLimit: DETAIL_LIMIT2
|
|
31536
32371
|
})
|
|
31537
32372
|
);
|
|
31538
|
-
if (
|
|
32373
|
+
if (flags30.details) {
|
|
31539
32374
|
printRuntimeDuplicateDetails(runtimeDedupe.duplicateGroups);
|
|
31540
32375
|
printClassifiedRuntimeOnlyDetails(classifiedRuntimeOnly);
|
|
31541
32376
|
printClassifiedBacktestOnlyDetails(classifiedBacktestOnly);
|
|
31542
32377
|
}
|
|
31543
|
-
if (
|
|
32378
|
+
if (flags30.notify) {
|
|
31544
32379
|
const mismatchAttachment = buildRuntimeParityMismatchAttachment({
|
|
31545
32380
|
window,
|
|
31546
32381
|
connectorName,
|
|
@@ -31569,7 +32404,7 @@ var init_runtimeParity2 = __esm({
|
|
|
31569
32404
|
window,
|
|
31570
32405
|
connectorName,
|
|
31571
32406
|
replayEnv: replayEnvSummary,
|
|
31572
|
-
runtimeGatesEnabled: Boolean(
|
|
32407
|
+
runtimeGatesEnabled: Boolean(flags30.runtimeGates) || replayEnvSummary.includes("PARITY"),
|
|
31573
32408
|
toleranceBars,
|
|
31574
32409
|
toleranceMs,
|
|
31575
32410
|
replayTargetsCount: replayTargets.length,
|
|
@@ -31591,16 +32426,16 @@ var init_runtimeParity2 = __esm({
|
|
|
31591
32426
|
runtimeGateWarningCounts
|
|
31592
32427
|
}),
|
|
31593
32428
|
{
|
|
31594
|
-
userName:
|
|
32429
|
+
userName: flags30.user,
|
|
31595
32430
|
attachments: mismatchAttachment ? [mismatchAttachment] : void 0
|
|
31596
32431
|
}
|
|
31597
32432
|
);
|
|
31598
32433
|
}
|
|
31599
32434
|
} finally {
|
|
31600
|
-
(0, import_backtest3.resetTestingKlineCache)(
|
|
32435
|
+
(0, import_backtest3.resetTestingKlineCache)(projectRoot15);
|
|
31601
32436
|
}
|
|
31602
32437
|
};
|
|
31603
|
-
|
|
32438
|
+
main42 = runtimeParity;
|
|
31604
32439
|
}
|
|
31605
32440
|
});
|
|
31606
32441
|
|
|
@@ -31679,11 +32514,11 @@ var init_runtimeStrategies = __esm({
|
|
|
31679
32514
|
});
|
|
31680
32515
|
|
|
31681
32516
|
// src/lib/signals/skipStats.ts
|
|
31682
|
-
var
|
|
32517
|
+
var import_chalk47, import_logger7, createStrategySkipStats, recordStrategyReason, logStrategySkipStats;
|
|
31683
32518
|
var init_skipStats = __esm({
|
|
31684
32519
|
"src/lib/signals/skipStats.ts"() {
|
|
31685
32520
|
"use strict";
|
|
31686
|
-
|
|
32521
|
+
import_chalk47 = __toESM(require("chalk"));
|
|
31687
32522
|
import_logger7 = require("@tradejs/infra/logger");
|
|
31688
32523
|
init_runtimeSignalsStorage();
|
|
31689
32524
|
createStrategySkipStats = (runtimeStrategies) => new Map(
|
|
@@ -31709,7 +32544,7 @@ var init_skipStats = __esm({
|
|
|
31709
32544
|
);
|
|
31710
32545
|
};
|
|
31711
32546
|
logStrategySkipStats = (runtimeStrategies, strategyStats) => {
|
|
31712
|
-
import_logger7.logger.info(
|
|
32547
|
+
import_logger7.logger.info(import_chalk47.default.yellow("skip stats:"));
|
|
31713
32548
|
for (const { strategyName } of runtimeStrategies) {
|
|
31714
32549
|
const stats = strategyStats.get(strategyName);
|
|
31715
32550
|
if (!stats) {
|
|
@@ -32654,12 +33489,12 @@ var init_configuredScopes = __esm({
|
|
|
32654
33489
|
});
|
|
32655
33490
|
|
|
32656
33491
|
// src/lib/signals/runner.ts
|
|
32657
|
-
var import_progress11,
|
|
33492
|
+
var import_progress11, import_chalk48, import_connectors16, import_cli12, import_async5, import_strategies11, import_constants16, import_time10, import_logger10, import_runtimeHeartbeats, import_runtimeStrategies6, SLOW_SIGNALS_WARNING_MS, formatDuration3, resolvePositiveInteger2, resolveNonNegativeInteger, createSignalsRunner;
|
|
32658
33493
|
var init_runner = __esm({
|
|
32659
33494
|
"src/lib/signals/runner.ts"() {
|
|
32660
33495
|
"use strict";
|
|
32661
33496
|
import_progress11 = __toESM(require("progress"));
|
|
32662
|
-
|
|
33497
|
+
import_chalk48 = __toESM(require("chalk"));
|
|
32663
33498
|
import_connectors16 = require("@tradejs/node/connectors");
|
|
32664
33499
|
import_cli12 = require("@tradejs/node/cli");
|
|
32665
33500
|
import_async5 = require("@tradejs/core/async");
|
|
@@ -32703,7 +33538,7 @@ var init_runner = __esm({
|
|
|
32703
33538
|
};
|
|
32704
33539
|
createSignalsRunner = (config2) => {
|
|
32705
33540
|
const interval4 = config2.interval;
|
|
32706
|
-
const
|
|
33541
|
+
const projectRoot17 = config2.projectRoot?.trim() || String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
32707
33542
|
const resolveSignalsDaemonMaxLiveBars = (runtimeInterval = interval4) => {
|
|
32708
33543
|
const intervalMinutes = Number(runtimeInterval);
|
|
32709
33544
|
const preloadBars = Math.ceil(
|
|
@@ -32726,7 +33561,7 @@ var init_runner = __esm({
|
|
|
32726
33561
|
const timeOperation3 = (label, operation) => timeOperation(
|
|
32727
33562
|
label,
|
|
32728
33563
|
operation,
|
|
32729
|
-
(message) => import_logger10.logger.info(
|
|
33564
|
+
(message) => import_logger10.logger.info(import_chalk48.default.gray(message))
|
|
32730
33565
|
);
|
|
32731
33566
|
const formatSlowSignalsWarning = (params) => [
|
|
32732
33567
|
"<b>Slow yarn signals run</b>",
|
|
@@ -32736,7 +33571,7 @@ var init_runner = __esm({
|
|
|
32736
33571
|
`Found signals: <b>${params.found}</b>`
|
|
32737
33572
|
].join("\n");
|
|
32738
33573
|
const resolveSignalsConnectorName = async (value) => {
|
|
32739
|
-
const connectorName = await (0, import_connectors16.resolveConnectorName)(value,
|
|
33574
|
+
const connectorName = await (0, import_connectors16.resolveConnectorName)(value, projectRoot17);
|
|
32740
33575
|
if (!connectorName) {
|
|
32741
33576
|
throw new Error(
|
|
32742
33577
|
`Unknown runtime connector: ${String(value || "").trim() || String(value)}`
|
|
@@ -32747,7 +33582,7 @@ var init_runner = __esm({
|
|
|
32747
33582
|
const createSignalsSession2 = async (lifecycle, scope = {}) => {
|
|
32748
33583
|
const deployment = config2.deploymentId ? await (0, import_runtimeStrategies6.getRuntimeDeployment)({
|
|
32749
33584
|
userName: config2.userName,
|
|
32750
|
-
projectRoot:
|
|
33585
|
+
projectRoot: projectRoot17,
|
|
32751
33586
|
deploymentId: config2.deploymentId
|
|
32752
33587
|
}) : null;
|
|
32753
33588
|
if (config2.deploymentId && !deployment) {
|
|
@@ -32766,7 +33601,7 @@ var init_runner = __esm({
|
|
|
32766
33601
|
const requestedAccountId = deployment?.accountId ?? scope.accountId ?? config2.accountId;
|
|
32767
33602
|
const connectorFactory = await (0, import_connectors16.getConnectorCreatorByName)(
|
|
32768
33603
|
connectorName,
|
|
32769
|
-
|
|
33604
|
+
projectRoot17
|
|
32770
33605
|
);
|
|
32771
33606
|
if (!connectorFactory) {
|
|
32772
33607
|
throw new Error(`Connector "${connectorName}" is not registered`);
|
|
@@ -32781,7 +33616,7 @@ var init_runner = __esm({
|
|
|
32781
33616
|
connectorName,
|
|
32782
33617
|
marketConnector,
|
|
32783
33618
|
userName: config2.userName,
|
|
32784
|
-
projectRoot:
|
|
33619
|
+
projectRoot: projectRoot17,
|
|
32785
33620
|
shouldUseDedicatedReferences: universe === "crypto" && connectorName.toLowerCase() === import_connectors16.DEFAULT_CONNECTOR_NAME.toLowerCase(),
|
|
32786
33621
|
warn: (message) => import_logger10.logger.warn(message)
|
|
32787
33622
|
});
|
|
@@ -32841,7 +33676,7 @@ var init_runner = __esm({
|
|
|
32841
33676
|
const selectedTickers = selection?.tickers ? [.../* @__PURE__ */ new Set([...selection.tickers, ...selectedActiveSymbols])] : void 0;
|
|
32842
33677
|
if (selectedActiveSymbols.length) {
|
|
32843
33678
|
import_logger10.logger.info(
|
|
32844
|
-
|
|
33679
|
+
import_chalk48.default.gray(
|
|
32845
33680
|
`strategy selection retained active symbols: ${selectedActiveSymbols.join(", ")}`
|
|
32846
33681
|
)
|
|
32847
33682
|
);
|
|
@@ -32871,10 +33706,10 @@ var init_runner = __esm({
|
|
|
32871
33706
|
instruments.map((instrument) => [instrument.symbol, instrument])
|
|
32872
33707
|
);
|
|
32873
33708
|
if (config2.showTickersList) {
|
|
32874
|
-
console.log(
|
|
33709
|
+
console.log(import_chalk48.default.gray(JSON.stringify(tickers.sort(), null, 2)));
|
|
32875
33710
|
return;
|
|
32876
33711
|
}
|
|
32877
|
-
const projectConfig = await (0, import_cli12.loadTradejsConfig)(
|
|
33712
|
+
const projectConfig = await (0, import_cli12.loadTradejsConfig)(projectRoot17);
|
|
32878
33713
|
projectHooks = projectConfig.hooks;
|
|
32879
33714
|
const currentTimestamp = (0, import_time10.getTimestamp)();
|
|
32880
33715
|
const preloadStart = (0, import_time10.getTimestamp)(import_constants16.SIGNALS_CLI_PRELOAD_DAYS);
|
|
@@ -32892,7 +33727,7 @@ var init_runner = __esm({
|
|
|
32892
33727
|
);
|
|
32893
33728
|
await session.klineFeed.flush();
|
|
32894
33729
|
import_logger10.logger.info(
|
|
32895
|
-
|
|
33730
|
+
import_chalk48.default.gray(
|
|
32896
33731
|
`websocket candles: ready=${expectedSymbols.length - missingSymbols.length}/${expectedSymbols.length} missing=${missingSymbols.length}`
|
|
32897
33732
|
)
|
|
32898
33733
|
);
|
|
@@ -32903,7 +33738,7 @@ var init_runner = __esm({
|
|
|
32903
33738
|
symbols: missingSymbols,
|
|
32904
33739
|
preloadDays: import_constants16.SIGNALS_CLI_PRELOAD_DAYS,
|
|
32905
33740
|
universe,
|
|
32906
|
-
log: (message) => import_logger10.logger.info(
|
|
33741
|
+
log: (message) => import_logger10.logger.info(import_chalk48.default.gray(message))
|
|
32907
33742
|
});
|
|
32908
33743
|
await updateBtcReferenceHistory({
|
|
32909
33744
|
marketConnector,
|
|
@@ -32911,7 +33746,7 @@ var init_runner = __esm({
|
|
|
32911
33746
|
interval: interval5,
|
|
32912
33747
|
preloadDays: import_constants16.SIGNALS_CLI_PRELOAD_DAYS,
|
|
32913
33748
|
universe,
|
|
32914
|
-
log: (message) => import_logger10.logger.info(
|
|
33749
|
+
log: (message) => import_logger10.logger.info(import_chalk48.default.gray(message))
|
|
32915
33750
|
});
|
|
32916
33751
|
} else if (!config2.cacheOnly) {
|
|
32917
33752
|
await updateMarketHistoryWithBtcReferences({
|
|
@@ -32922,13 +33757,13 @@ var init_runner = __esm({
|
|
|
32922
33757
|
symbols: tickers,
|
|
32923
33758
|
preloadDays: import_constants16.SIGNALS_CLI_PRELOAD_DAYS,
|
|
32924
33759
|
universe,
|
|
32925
|
-
log: (message) => import_logger10.logger.info(
|
|
33760
|
+
log: (message) => import_logger10.logger.info(import_chalk48.default.gray(message))
|
|
32926
33761
|
});
|
|
32927
33762
|
}
|
|
32928
33763
|
await prepareMarketContextForRun({
|
|
32929
33764
|
mode: "signals",
|
|
32930
33765
|
userName: config2.userName,
|
|
32931
|
-
projectRoot:
|
|
33766
|
+
projectRoot: projectRoot17,
|
|
32932
33767
|
symbols: tickers,
|
|
32933
33768
|
universe,
|
|
32934
33769
|
interval: interval5,
|
|
@@ -32936,7 +33771,7 @@ var init_runner = __esm({
|
|
|
32936
33771
|
endMs: currentTimestamp,
|
|
32937
33772
|
preloadStartMs: preloadStart,
|
|
32938
33773
|
cacheOnly: config2.cacheOnly,
|
|
32939
|
-
log: (message) => import_logger10.logger.info(
|
|
33774
|
+
log: (message) => import_logger10.logger.info(import_chalk48.default.gray(message))
|
|
32940
33775
|
});
|
|
32941
33776
|
if (config2.updateOnly) {
|
|
32942
33777
|
return;
|
|
@@ -32994,7 +33829,7 @@ var init_runner = __esm({
|
|
|
32994
33829
|
);
|
|
32995
33830
|
const configuredRuntimeStrategies = await (0, import_runtimeStrategies5.loadResolvedRuntimeStrategies)({
|
|
32996
33831
|
userName: config2.userName,
|
|
32997
|
-
projectRoot:
|
|
33832
|
+
projectRoot: projectRoot17,
|
|
32998
33833
|
deploymentId: deployment?.id ?? "",
|
|
32999
33834
|
universe,
|
|
33000
33835
|
accountId,
|
|
@@ -33031,7 +33866,7 @@ var init_runner = __esm({
|
|
|
33031
33866
|
)
|
|
33032
33867
|
);
|
|
33033
33868
|
import_logger10.logger.info(
|
|
33034
|
-
|
|
33869
|
+
import_chalk48.default.yellow(
|
|
33035
33870
|
`loaded strategies (user=${config2.userName}): ${runtimeStrategies.map(formatConfiguredStrategyIdentity).join(", ")}`
|
|
33036
33871
|
)
|
|
33037
33872
|
);
|
|
@@ -33067,9 +33902,9 @@ var init_runner = __esm({
|
|
|
33067
33902
|
width: 30
|
|
33068
33903
|
}
|
|
33069
33904
|
);
|
|
33070
|
-
import_logger10.logger.info(
|
|
33905
|
+
import_logger10.logger.info(import_chalk48.default.yellow(`tickers: ${tickers.length}`));
|
|
33071
33906
|
const signalsParallel = resolvePositiveInteger2(config2.parallel, 4);
|
|
33072
|
-
import_logger10.logger.info(
|
|
33907
|
+
import_logger10.logger.info(import_chalk48.default.yellow(`signal workers: ${signalsParallel}`));
|
|
33073
33908
|
const evaluateTicker = createSignalsTickerEvaluator({
|
|
33074
33909
|
userName: config2.userName,
|
|
33075
33910
|
makeOrders: config2.makeOrders,
|
|
@@ -33108,8 +33943,8 @@ var init_runner = __esm({
|
|
|
33108
33943
|
signals3.push(...strategySignals);
|
|
33109
33944
|
}
|
|
33110
33945
|
bar.tick(1, {
|
|
33111
|
-
found:
|
|
33112
|
-
symbol:
|
|
33946
|
+
found: import_chalk48.default.cyan(signals3.length),
|
|
33947
|
+
symbol: import_chalk48.default.gray(symbol)
|
|
33113
33948
|
});
|
|
33114
33949
|
});
|
|
33115
33950
|
});
|
|
@@ -33213,7 +34048,7 @@ var init_runner = __esm({
|
|
|
33213
34048
|
}
|
|
33214
34049
|
}
|
|
33215
34050
|
import_logger10.logger.info(
|
|
33216
|
-
|
|
34051
|
+
import_chalk48.default.yellow(
|
|
33217
34052
|
`signals ${status} in ${formatDuration3(durationMs)} (found=${signals3.length})`
|
|
33218
34053
|
)
|
|
33219
34054
|
);
|
|
@@ -33225,7 +34060,7 @@ var init_runner = __esm({
|
|
|
33225
34060
|
const loadConfiguredSignalsScopes = async (deployment) => {
|
|
33226
34061
|
const configuredStrategies = await (0, import_runtimeStrategies5.loadResolvedRuntimeStrategies)({
|
|
33227
34062
|
userName: config2.userName,
|
|
33228
|
-
projectRoot:
|
|
34063
|
+
projectRoot: projectRoot17,
|
|
33229
34064
|
deploymentId: deployment.id
|
|
33230
34065
|
});
|
|
33231
34066
|
const connectorName = await resolveSignalsConnectorName(
|
|
@@ -33248,7 +34083,7 @@ var init_runner = __esm({
|
|
|
33248
34083
|
}
|
|
33249
34084
|
const configuredDeployment = await (0, import_runtimeStrategies6.getRuntimeDeployment)({
|
|
33250
34085
|
userName: config2.userName,
|
|
33251
|
-
projectRoot:
|
|
34086
|
+
projectRoot: projectRoot17,
|
|
33252
34087
|
deploymentId: config2.deploymentId
|
|
33253
34088
|
});
|
|
33254
34089
|
if (!configuredDeployment) {
|
|
@@ -33282,7 +34117,7 @@ var init_runner = __esm({
|
|
|
33282
34117
|
const deploymentId = config2.deploymentId;
|
|
33283
34118
|
const initialDeployment = await (0, import_runtimeStrategies6.getRuntimeDeployment)({
|
|
33284
34119
|
userName: config2.userName,
|
|
33285
|
-
projectRoot:
|
|
34120
|
+
projectRoot: projectRoot17,
|
|
33286
34121
|
deploymentId
|
|
33287
34122
|
});
|
|
33288
34123
|
if (!initialDeployment) {
|
|
@@ -33307,7 +34142,7 @@ var init_runner = __esm({
|
|
|
33307
34142
|
runCycle: async () => {
|
|
33308
34143
|
const currentDeployment = await (0, import_runtimeStrategies6.getRuntimeDeployment)({
|
|
33309
34144
|
userName: config2.userName,
|
|
33310
|
-
projectRoot:
|
|
34145
|
+
projectRoot: projectRoot17,
|
|
33311
34146
|
deploymentId
|
|
33312
34147
|
});
|
|
33313
34148
|
if (!currentDeployment) {
|
|
@@ -33414,107 +34249,107 @@ var init_runner = __esm({
|
|
|
33414
34249
|
var signals_exports = {};
|
|
33415
34250
|
__export(signals_exports, {
|
|
33416
34251
|
createSignalsSession: () => createSignalsSession,
|
|
33417
|
-
main: () =>
|
|
34252
|
+
main: () => main43,
|
|
33418
34253
|
signals: () => signals,
|
|
33419
34254
|
signalsConfiguredScopesOnce: () => signalsConfiguredScopesOnce,
|
|
33420
34255
|
signalsDaemon: () => signalsDaemon
|
|
33421
34256
|
});
|
|
33422
|
-
var import_config12,
|
|
34257
|
+
var import_config12, import_args33, flags31, config, runner, createSignalsSession, signals, signalsConfiguredScopesOnce, signalsDaemon, main43;
|
|
33423
34258
|
var init_signals = __esm({
|
|
33424
34259
|
"src/scripts/signals.ts"() {
|
|
33425
34260
|
"use strict";
|
|
33426
34261
|
import_config12 = require("dotenv/config");
|
|
33427
|
-
|
|
34262
|
+
import_args33 = __toESM(require("args"));
|
|
33428
34263
|
init_runner();
|
|
33429
|
-
|
|
33430
|
-
|
|
33431
|
-
|
|
33432
|
-
|
|
33433
|
-
|
|
33434
|
-
|
|
33435
|
-
|
|
33436
|
-
|
|
33437
|
-
|
|
33438
|
-
|
|
33439
|
-
|
|
34264
|
+
import_args33.default.option(["t", "tickers"], "Selected tickers");
|
|
34265
|
+
import_args33.default.option(["e", "exclude"], "Exclude tickers from tests");
|
|
34266
|
+
import_args33.default.option(["l", "tickersLimit"], "Tickers limit");
|
|
34267
|
+
import_args33.default.option(["f", "timeframe"], "Timeframe", 15);
|
|
34268
|
+
import_args33.default.option(["m", "makeOrders"], "Make orders");
|
|
34269
|
+
import_args33.default.option(["N", "notify"], "Send message in Telegram", false);
|
|
34270
|
+
import_args33.default.option(["S", "skipScreenshots"], "Skip screenshot generation", false);
|
|
34271
|
+
import_args33.default.option(["u", "updateOnly"], "Only update tickers history", false);
|
|
34272
|
+
import_args33.default.option(["C", "cacheOnly"], "Do not update tickers history", false);
|
|
34273
|
+
import_args33.default.option(["L", "showTickersList"], "Just show only ticker list", false);
|
|
34274
|
+
import_args33.default.option(
|
|
33440
34275
|
["p", "parallel"],
|
|
33441
34276
|
"Signal evaluation worker count",
|
|
33442
34277
|
Number(process.env.SIGNALS_PARALLEL || 4)
|
|
33443
34278
|
);
|
|
33444
|
-
|
|
34279
|
+
import_args33.default.option(
|
|
33445
34280
|
["R", "showSkipStats"],
|
|
33446
34281
|
"Show aggregated skip stats by strategy",
|
|
33447
34282
|
false
|
|
33448
34283
|
);
|
|
33449
|
-
|
|
33450
|
-
|
|
33451
|
-
|
|
33452
|
-
|
|
34284
|
+
import_args33.default.option(["c", "chunk"], "Split by chunks, ex. 1/3");
|
|
34285
|
+
import_args33.default.option(["U", "user"], "Use user confg", "root");
|
|
34286
|
+
import_args33.default.option(["w", "watch"], "Keep signals running on candle boundaries", false);
|
|
34287
|
+
import_args33.default.option(
|
|
33453
34288
|
["d", "settleDelayMs"],
|
|
33454
34289
|
"Delay after candle close before a daemon cycle",
|
|
33455
34290
|
Number(process.env.SIGNALS_DAEMON_SETTLE_DELAY_MS || 5e3)
|
|
33456
34291
|
);
|
|
33457
|
-
|
|
34292
|
+
import_args33.default.option(
|
|
33458
34293
|
["o", "connector"],
|
|
33459
34294
|
"Connector provider or name for signals (e.g. bybit, binance, coinbase, custom)",
|
|
33460
34295
|
"bybit"
|
|
33461
34296
|
);
|
|
33462
|
-
|
|
33463
|
-
|
|
33464
|
-
|
|
33465
|
-
|
|
34297
|
+
import_args33.default.option(["V", "universe"], "Market universe (crypto or tradfi)", "crypto");
|
|
34298
|
+
import_args33.default.option(["A", "account"], "Trading account id");
|
|
34299
|
+
import_args33.default.option(["D", "deployment"], "Runtime deployment id");
|
|
34300
|
+
flags31 = import_args33.default.parse(process.argv);
|
|
33466
34301
|
config = {
|
|
33467
34302
|
projectRoot: String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd(),
|
|
33468
|
-
userName: String(
|
|
33469
|
-
interval: String(
|
|
33470
|
-
connectorName: String(
|
|
33471
|
-
universe:
|
|
33472
|
-
accountId:
|
|
33473
|
-
deploymentId:
|
|
33474
|
-
tickers:
|
|
33475
|
-
exclude:
|
|
33476
|
-
tickersLimit:
|
|
33477
|
-
chunk:
|
|
33478
|
-
makeOrders: Boolean(
|
|
33479
|
-
notify: Boolean(
|
|
33480
|
-
skipScreenshots: Boolean(
|
|
33481
|
-
updateOnly: Boolean(
|
|
33482
|
-
cacheOnly: Boolean(
|
|
33483
|
-
showTickersList: Boolean(
|
|
33484
|
-
showSkipStats: Boolean(
|
|
33485
|
-
parallel:
|
|
33486
|
-
watch: Boolean(
|
|
33487
|
-
settleDelayMs:
|
|
34303
|
+
userName: String(flags31.user || "root"),
|
|
34304
|
+
interval: String(flags31.timeframe ?? 15),
|
|
34305
|
+
connectorName: String(flags31.connector || "bybit"),
|
|
34306
|
+
universe: flags31.universe,
|
|
34307
|
+
accountId: flags31.account ? String(flags31.account) : void 0,
|
|
34308
|
+
deploymentId: flags31.deployment ? String(flags31.deployment) : void 0,
|
|
34309
|
+
tickers: flags31.tickers,
|
|
34310
|
+
exclude: flags31.exclude,
|
|
34311
|
+
tickersLimit: flags31.tickersLimit,
|
|
34312
|
+
chunk: flags31.chunk,
|
|
34313
|
+
makeOrders: Boolean(flags31.makeOrders),
|
|
34314
|
+
notify: Boolean(flags31.notify),
|
|
34315
|
+
skipScreenshots: Boolean(flags31.skipScreenshots),
|
|
34316
|
+
updateOnly: Boolean(flags31.updateOnly),
|
|
34317
|
+
cacheOnly: Boolean(flags31.cacheOnly),
|
|
34318
|
+
showTickersList: Boolean(flags31.showTickersList),
|
|
34319
|
+
showSkipStats: Boolean(flags31.showSkipStats),
|
|
34320
|
+
parallel: flags31.parallel,
|
|
34321
|
+
watch: Boolean(flags31.watch),
|
|
34322
|
+
settleDelayMs: flags31.settleDelayMs
|
|
33488
34323
|
};
|
|
33489
34324
|
runner = createSignalsRunner(config);
|
|
33490
34325
|
createSignalsSession = runner.createSession;
|
|
33491
34326
|
signals = runner.runCycle;
|
|
33492
34327
|
signalsConfiguredScopesOnce = runner.runConfiguredScopesOnce;
|
|
33493
34328
|
signalsDaemon = runner.runDaemon;
|
|
33494
|
-
|
|
34329
|
+
main43 = () => config.watch ? signalsDaemon() : signalsConfiguredScopesOnce();
|
|
33495
34330
|
}
|
|
33496
34331
|
});
|
|
33497
34332
|
|
|
33498
34333
|
// src/scripts/signalsDaemon.ts
|
|
33499
34334
|
var signalsDaemon_exports = {};
|
|
33500
34335
|
__export(signalsDaemon_exports, {
|
|
33501
|
-
main: () =>
|
|
34336
|
+
main: () => main44
|
|
33502
34337
|
});
|
|
33503
|
-
var
|
|
34338
|
+
var main44;
|
|
33504
34339
|
var init_signalsDaemon = __esm({
|
|
33505
34340
|
"src/scripts/signalsDaemon.ts"() {
|
|
33506
34341
|
"use strict";
|
|
33507
34342
|
init_signals();
|
|
33508
|
-
|
|
34343
|
+
main44 = signalsDaemon;
|
|
33509
34344
|
}
|
|
33510
34345
|
});
|
|
33511
34346
|
|
|
33512
34347
|
// src/lib/replay/cliConfig.ts
|
|
33513
|
-
var
|
|
34348
|
+
var import_args34, REPLAY_UNSUPPORTED_FLAGS, hasCliFlag2, assertNoUnsupportedReplayFlags, replayNormalizedArgv, replayFlags, replayInterval, replayUserName, replayProjectRoot, replayRuntimeEvidencePath, replayDeploymentId, isReplayUpdateOnlyRun;
|
|
33514
34349
|
var init_cliConfig2 = __esm({
|
|
33515
34350
|
"src/lib/replay/cliConfig.ts"() {
|
|
33516
34351
|
"use strict";
|
|
33517
|
-
|
|
34352
|
+
import_args34 = __toESM(require("args"));
|
|
33518
34353
|
init_cliArgs();
|
|
33519
34354
|
REPLAY_UNSUPPORTED_FLAGS = [
|
|
33520
34355
|
["--live", "`yarn replay` is already the replacement for legacy `--live`."],
|
|
@@ -33548,36 +34383,36 @@ var init_cliConfig2 = __esm({
|
|
|
33548
34383
|
}
|
|
33549
34384
|
}
|
|
33550
34385
|
};
|
|
33551
|
-
|
|
34386
|
+
import_args34.default.example(
|
|
33552
34387
|
"yarn replay --days 7 --cacheOnly",
|
|
33553
34388
|
"Replay active runtime strategies on historical data"
|
|
33554
34389
|
);
|
|
33555
|
-
|
|
33556
|
-
|
|
33557
|
-
|
|
33558
|
-
|
|
33559
|
-
|
|
33560
|
-
|
|
33561
|
-
|
|
33562
|
-
|
|
34390
|
+
import_args34.default.option(["t", "tickers"], "Selected tickers");
|
|
34391
|
+
import_args34.default.option(["e", "exclude"], "Exclude tickers from replay");
|
|
34392
|
+
import_args34.default.option(["l", "tickersLimit"], "Tickers limit");
|
|
34393
|
+
import_args34.default.option(["f", "timeframe"], "Timeframe", 15);
|
|
34394
|
+
import_args34.default.option(["d", "days"], "Run replay only for the last N days");
|
|
34395
|
+
import_args34.default.option("startTime", "Explicit replay start timestamp (ms or seconds)");
|
|
34396
|
+
import_args34.default.option("endTime", "Explicit replay end timestamp (ms or seconds)");
|
|
34397
|
+
import_args34.default.option(
|
|
33563
34398
|
"runtimeEvidence",
|
|
33564
34399
|
"Immutable runtime evidence JSON used for offline runtime comparison"
|
|
33565
34400
|
);
|
|
33566
|
-
|
|
34401
|
+
import_args34.default.option(
|
|
33567
34402
|
"deployment",
|
|
33568
34403
|
"Git-owned runtime deployment used when runtime evidence is omitted",
|
|
33569
34404
|
"production"
|
|
33570
34405
|
);
|
|
33571
|
-
|
|
33572
|
-
|
|
33573
|
-
|
|
34406
|
+
import_args34.default.option(["u", "updateOnly"], "Only update tickers history", false);
|
|
34407
|
+
import_args34.default.option(["C", "cacheOnly"], "Do not update tickers history", false);
|
|
34408
|
+
import_args34.default.option(
|
|
33574
34409
|
"chart",
|
|
33575
34410
|
"Save compact replay chart data for the strategies UI",
|
|
33576
34411
|
false
|
|
33577
34412
|
);
|
|
33578
|
-
|
|
33579
|
-
|
|
33580
|
-
|
|
34413
|
+
import_args34.default.option(["L", "showTickersList"], "Just show only ticker list", false);
|
|
34414
|
+
import_args34.default.option(["U", "user"], "Use user config", "root");
|
|
34415
|
+
import_args34.default.option(
|
|
33581
34416
|
["o", "connector"],
|
|
33582
34417
|
"Connector provider or name for replay (e.g. bybit, binance, coinbase, custom)",
|
|
33583
34418
|
"bybit"
|
|
@@ -33589,7 +34424,7 @@ var init_cliConfig2 = __esm({
|
|
|
33589
34424
|
"-U": "--user"
|
|
33590
34425
|
});
|
|
33591
34426
|
assertNoUnsupportedReplayFlags(replayNormalizedArgv);
|
|
33592
|
-
replayFlags =
|
|
34427
|
+
replayFlags = import_args34.default.parse(replayNormalizedArgv);
|
|
33593
34428
|
replayInterval = String(replayFlags.timeframe ?? 15);
|
|
33594
34429
|
replayUserName = String(replayFlags.user ?? "root");
|
|
33595
34430
|
replayProjectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
@@ -33602,12 +34437,12 @@ var init_cliConfig2 = __esm({
|
|
|
33602
34437
|
});
|
|
33603
34438
|
|
|
33604
34439
|
// src/lib/replay/runtimeEvidenceSource.ts
|
|
33605
|
-
var
|
|
34440
|
+
var import_promises32, import_node_path29, asRecord7, asFiniteNumber, unwrapRows2, assertRuntimeRowsMatchDeployment, readRuntimeEvidenceArtifact, loadReplayRuntimeEvidenceMetadata, buildRuntimeEvidenceLineageScopes, loadReplayRuntimeEvidenceSource;
|
|
33606
34441
|
var init_runtimeEvidenceSource = __esm({
|
|
33607
34442
|
"src/lib/replay/runtimeEvidenceSource.ts"() {
|
|
33608
34443
|
"use strict";
|
|
33609
|
-
|
|
33610
|
-
|
|
34444
|
+
import_promises32 = __toESM(require("fs/promises"));
|
|
34445
|
+
import_node_path29 = __toESM(require("path"));
|
|
33611
34446
|
init_runtimeLineage();
|
|
33612
34447
|
init_runtimeEvidenceDeployment();
|
|
33613
34448
|
asRecord7 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -33636,11 +34471,11 @@ var init_runtimeEvidenceSource = __esm({
|
|
|
33636
34471
|
};
|
|
33637
34472
|
readRuntimeEvidenceArtifact = async ({
|
|
33638
34473
|
filePath,
|
|
33639
|
-
projectRoot:
|
|
34474
|
+
projectRoot: projectRoot17
|
|
33640
34475
|
}) => {
|
|
33641
|
-
const resolvedPath =
|
|
34476
|
+
const resolvedPath = import_node_path29.default.resolve(projectRoot17, filePath);
|
|
33642
34477
|
const root = asRecord7(
|
|
33643
|
-
JSON.parse(await
|
|
34478
|
+
JSON.parse(await import_promises32.default.readFile(resolvedPath, "utf8"))
|
|
33644
34479
|
);
|
|
33645
34480
|
const runtime = asRecord7(root?.runtime) ?? root;
|
|
33646
34481
|
if (!root || !runtime) {
|
|
@@ -33737,11 +34572,11 @@ var init_runtimeEvidenceSource = __esm({
|
|
|
33737
34572
|
};
|
|
33738
34573
|
loadReplayRuntimeEvidenceSource = async ({
|
|
33739
34574
|
filePath,
|
|
33740
|
-
projectRoot:
|
|
34575
|
+
projectRoot: projectRoot17,
|
|
33741
34576
|
expectedUserName,
|
|
33742
34577
|
expectedWindow
|
|
33743
34578
|
}) => {
|
|
33744
|
-
const { resolvedPath, runtime, userName: userName3, startTime, endTime, deployment } = await readRuntimeEvidenceArtifact({ filePath, projectRoot:
|
|
34579
|
+
const { resolvedPath, runtime, userName: userName3, startTime, endTime, deployment } = await readRuntimeEvidenceArtifact({ filePath, projectRoot: projectRoot17 });
|
|
33745
34580
|
if (!userName3 || userName3 !== expectedUserName) {
|
|
33746
34581
|
throw new Error(
|
|
33747
34582
|
`Runtime evidence user mismatch: expected=${expectedUserName}, actual=${userName3 || "missing"}`
|
|
@@ -34282,7 +35117,7 @@ var init_historicalSignalsReplayPreparation = __esm({
|
|
|
34282
35117
|
prepareHistoricalReplay = async (context, adapters) => {
|
|
34283
35118
|
const {
|
|
34284
35119
|
userName: userName3,
|
|
34285
|
-
projectRoot:
|
|
35120
|
+
projectRoot: projectRoot17,
|
|
34286
35121
|
preparedRun,
|
|
34287
35122
|
interval: interval4,
|
|
34288
35123
|
connectorName,
|
|
@@ -34335,7 +35170,7 @@ var init_historicalSignalsReplayPreparation = __esm({
|
|
|
34335
35170
|
interval: interval4
|
|
34336
35171
|
});
|
|
34337
35172
|
const runtimeLineage = await adapters.buildLineage({
|
|
34338
|
-
projectRoot:
|
|
35173
|
+
projectRoot: projectRoot17,
|
|
34339
35174
|
strategyName: strategy.strategyName,
|
|
34340
35175
|
strategyRevision: strategy.strategyRevision,
|
|
34341
35176
|
deploymentCompositionId: strategy.deploymentCompositionId,
|
|
@@ -34558,11 +35393,11 @@ var init_historicalSignalsReplayResults = __esm({
|
|
|
34558
35393
|
});
|
|
34559
35394
|
|
|
34560
35395
|
// src/lib/replay/historicalSignalsReplay.ts
|
|
34561
|
-
var
|
|
35396
|
+
var import_chalk49, import_progress12, import_strategies12, import_time11, import_logger11, import_redis19, import_connectors17, import_cli13, import_strategies13, import_runtimeStrategies8, loadRuntimeStrategies, loadReferenceConnector, buildAfterSignalsContext, getConnectorName, runHistoricalSignalsReplay;
|
|
34562
35397
|
var init_historicalSignalsReplay = __esm({
|
|
34563
35398
|
"src/lib/replay/historicalSignalsReplay.ts"() {
|
|
34564
35399
|
"use strict";
|
|
34565
|
-
|
|
35400
|
+
import_chalk49 = __toESM(require("chalk"));
|
|
34566
35401
|
import_progress12 = __toESM(require("progress"));
|
|
34567
35402
|
import_strategies12 = require("@tradejs/core/strategies");
|
|
34568
35403
|
import_time11 = require("@tradejs/core/time");
|
|
@@ -34738,8 +35573,8 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34738
35573
|
tick: (tokens) => prepareBar.tick(1, tokens)
|
|
34739
35574
|
},
|
|
34740
35575
|
display: {
|
|
34741
|
-
skipped: (value) =>
|
|
34742
|
-
symbol: (value) =>
|
|
35576
|
+
skipped: (value) => import_chalk49.default.yellow(value),
|
|
35577
|
+
symbol: (value) => import_chalk49.default.gray(value)
|
|
34743
35578
|
},
|
|
34744
35579
|
buildLineage: buildRuntimeLineage
|
|
34745
35580
|
}
|
|
@@ -34771,9 +35606,9 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34771
35606
|
tick: (tokens) => cycleBar.tick(1, tokens)
|
|
34772
35607
|
},
|
|
34773
35608
|
display: {
|
|
34774
|
-
signals: (value) =>
|
|
34775
|
-
aborted: (value) =>
|
|
34776
|
-
timestamp: (value) =>
|
|
35609
|
+
signals: (value) => import_chalk49.default.cyan(value),
|
|
35610
|
+
aborted: (value) => import_chalk49.default.yellow(value),
|
|
35611
|
+
timestamp: (value) => import_chalk49.default.gray((0, import_time11.formatUnix)(value))
|
|
34777
35612
|
},
|
|
34778
35613
|
invokeBeforeSignals: invokeBeforeSignalsHooks,
|
|
34779
35614
|
invokeAfterSignals: invokeAfterSignalsHooks,
|
|
@@ -34784,7 +35619,7 @@ var init_historicalSignalsReplay = __esm({
|
|
|
34784
35619
|
);
|
|
34785
35620
|
const artifacts = replayConnector.getReplayArtifacts();
|
|
34786
35621
|
import_logger11.logger.info(
|
|
34787
|
-
|
|
35622
|
+
import_chalk49.default.gray(
|
|
34788
35623
|
`signals replay historical cycles: ${plan.orderedTimestamps.length} (aborted=${execution.abortedCycles}) done in ${((Date.now() - startedAt) / 1e3).toFixed(1)}s`
|
|
34789
35624
|
)
|
|
34790
35625
|
);
|
|
@@ -34897,11 +35732,11 @@ var init_chartSnapshot = __esm({
|
|
|
34897
35732
|
});
|
|
34898
35733
|
|
|
34899
35734
|
// src/lib/replay/resultsReporting.ts
|
|
34900
|
-
var
|
|
35735
|
+
var import_chalk50, saveAndPrintReplayResultsByStrategy;
|
|
34901
35736
|
var init_resultsReporting = __esm({
|
|
34902
35737
|
"src/lib/replay/resultsReporting.ts"() {
|
|
34903
35738
|
"use strict";
|
|
34904
|
-
|
|
35739
|
+
import_chalk50 = __toESM(require("chalk"));
|
|
34905
35740
|
init_runtimeParity();
|
|
34906
35741
|
init_runFormatting();
|
|
34907
35742
|
init_support();
|
|
@@ -34940,14 +35775,14 @@ var init_resultsReporting = __esm({
|
|
|
34940
35775
|
const rows = summaries.map((summary) => {
|
|
34941
35776
|
const profit = `${summary.netProfit.toFixed(2)}$`;
|
|
34942
35777
|
const avgTrade = `${summary.avgTradeProfit.toFixed(2)}$`;
|
|
34943
|
-
const profitColor = summary.netProfit > 0 ?
|
|
34944
|
-
const avgTradeColor = summary.avgTradeProfit > 0 ?
|
|
35778
|
+
const profitColor = summary.netProfit > 0 ? import_chalk50.default.green : summary.netProfit < 0 ? import_chalk50.default.red : import_chalk50.default.gray;
|
|
35779
|
+
const avgTradeColor = summary.avgTradeProfit > 0 ? import_chalk50.default.green : summary.avgTradeProfit < 0 ? import_chalk50.default.red : import_chalk50.default.gray;
|
|
34945
35780
|
return [
|
|
34946
|
-
|
|
34947
|
-
|
|
34948
|
-
|
|
34949
|
-
|
|
34950
|
-
|
|
35781
|
+
import_chalk50.default.blue(summary.strategyName),
|
|
35782
|
+
import_chalk50.default.yellow(String(summary.tickers)),
|
|
35783
|
+
import_chalk50.default.yellow(String(summary.tickersWithTrades)),
|
|
35784
|
+
import_chalk50.default.cyan(String(summary.orders)),
|
|
35785
|
+
import_chalk50.default.cyan(
|
|
34951
35786
|
`${summary.wins}/${summary.losses} (${summary.winRate.toFixed(2)}%)`
|
|
34952
35787
|
),
|
|
34953
35788
|
profitColor(profit),
|
|
@@ -36417,29 +37252,29 @@ var init_runtimeComparisonCalculations = __esm({
|
|
|
36417
37252
|
});
|
|
36418
37253
|
|
|
36419
37254
|
// src/lib/replay/runtimeComparisonReporting.ts
|
|
36420
|
-
var
|
|
37255
|
+
var import_chalk51, import_time13, formatDrilldownSummary, colorizeRows, buildReplayComparisonReport, buildNoExchangeEntriesReport, buildNoRuntimeTradesReport, writeReplayComparisonReport;
|
|
36421
37256
|
var init_runtimeComparisonReporting = __esm({
|
|
36422
37257
|
"src/lib/replay/runtimeComparisonReporting.ts"() {
|
|
36423
37258
|
"use strict";
|
|
36424
|
-
|
|
37259
|
+
import_chalk51 = __toESM(require("chalk"));
|
|
36425
37260
|
import_time13 = require("@tradejs/core/time");
|
|
36426
37261
|
init_runFormatting();
|
|
36427
37262
|
init_support();
|
|
36428
37263
|
formatDrilldownSummary = (summary) => Object.entries(summary).filter(([, count]) => count > 0).map(([classification, count]) => `${classification}=${count}`).join(", ");
|
|
36429
37264
|
colorizeRows = (rows) => rows.map((row) => {
|
|
36430
|
-
const btPnlColor = row.backtestNetProfit > 0 ?
|
|
36431
|
-
const rtPnlColor = row.runtimePnl > 0 ?
|
|
37265
|
+
const btPnlColor = row.backtestNetProfit > 0 ? import_chalk51.default.green : row.backtestNetProfit < 0 ? import_chalk51.default.red : import_chalk51.default.gray;
|
|
37266
|
+
const rtPnlColor = row.runtimePnl > 0 ? import_chalk51.default.green : row.runtimePnl < 0 ? import_chalk51.default.red : import_chalk51.default.gray;
|
|
36432
37267
|
return [
|
|
36433
|
-
|
|
36434
|
-
|
|
37268
|
+
import_chalk51.default.blue(row.strategyName),
|
|
37269
|
+
import_chalk51.default.cyan(String(row.backtestEntries)),
|
|
36435
37270
|
btPnlColor(`${row.backtestNetProfit.toFixed(2)}$`),
|
|
36436
|
-
|
|
37271
|
+
import_chalk51.default.yellow(String(row.runtimeTrades)),
|
|
36437
37272
|
rtPnlColor(`${row.runtimePnl.toFixed(2)}$`),
|
|
36438
|
-
|
|
36439
|
-
|
|
36440
|
-
|
|
36441
|
-
|
|
36442
|
-
|
|
37273
|
+
import_chalk51.default.green(String(row.matched)),
|
|
37274
|
+
import_chalk51.default.red(String(row.orderFailed)),
|
|
37275
|
+
import_chalk51.default.yellow(String(row.runtimeOnly)),
|
|
37276
|
+
import_chalk51.default.magenta(String(row.backtestOnly)),
|
|
37277
|
+
import_chalk51.default.red(String(getReplayRuntimeUnmatchedCount(row)))
|
|
36443
37278
|
];
|
|
36444
37279
|
});
|
|
36445
37280
|
buildReplayComparisonReport = (context) => {
|
|
@@ -36459,7 +37294,7 @@ var init_runtimeComparisonReporting = __esm({
|
|
|
36459
37294
|
];
|
|
36460
37295
|
if (runtimeOnlyDrilldownSummary || backtestOnlyDrilldownSummary) {
|
|
36461
37296
|
lines.push(
|
|
36462
|
-
|
|
37297
|
+
import_chalk51.default.gray(
|
|
36463
37298
|
`Mismatch drilldown: ${runtimeOnlyLabel}=[${runtimeOnlyDrilldownSummary || "none"}], backtestOnly=[${backtestOnlyDrilldownSummary || "none"}]`
|
|
36464
37299
|
)
|
|
36465
37300
|
);
|
|
@@ -36472,7 +37307,7 @@ var init_runtimeComparisonReporting = __esm({
|
|
|
36472
37307
|
window
|
|
36473
37308
|
}) => [
|
|
36474
37309
|
"",
|
|
36475
|
-
|
|
37310
|
+
import_chalk51.default.yellow(
|
|
36476
37311
|
`SIGNALS REPLAY VS EXCHANGE: no lineage-linked exchange entry executions found for ${connectorName} in ${(0, import_time13.formatUnix)(
|
|
36477
37312
|
window.start
|
|
36478
37313
|
)} -> ${(0, import_time13.formatUnix)(window.end)}`
|
|
@@ -36484,7 +37319,7 @@ var init_runtimeComparisonReporting = __esm({
|
|
|
36484
37319
|
window
|
|
36485
37320
|
}) => [
|
|
36486
37321
|
"",
|
|
36487
|
-
|
|
37322
|
+
import_chalk51.default.yellow(
|
|
36488
37323
|
`SIGNALS REPLAY VS RUNTIME: no local runtime trades found for ${connectorName} in ${(0, import_time13.formatUnix)(
|
|
36489
37324
|
window.start
|
|
36490
37325
|
)} -> ${(0, import_time13.formatUnix)(window.end)} with matching lineage; checking lineage-linked exchange executions`
|
|
@@ -36500,11 +37335,11 @@ var init_runtimeComparisonReporting = __esm({
|
|
|
36500
37335
|
});
|
|
36501
37336
|
|
|
36502
37337
|
// src/lib/replay/runtimeComparison.ts
|
|
36503
|
-
var
|
|
37338
|
+
var import_chalk52, getReplayEntryTimestampCompareOffsetMs, buildReplaySignalEvaluations, toFiniteNumberOrNull4, sumOptionalNumbers, firstFiniteNumber, firstString, getExchangeExecutionMergeKey, mergeExchangeExecutionGroup, mergeExchangeEntryExecutions, loadExchangeEntryRows, loadExchangeEntriesForComparison, saveAndPrintReplayExchangeComparison, saveAndPrintReplayRuntimeComparison;
|
|
36504
37339
|
var init_runtimeComparison = __esm({
|
|
36505
37340
|
"src/lib/replay/runtimeComparison.ts"() {
|
|
36506
37341
|
"use strict";
|
|
36507
|
-
|
|
37342
|
+
import_chalk52 = __toESM(require("chalk"));
|
|
36508
37343
|
init_runtimeParity();
|
|
36509
37344
|
init_paritySummary();
|
|
36510
37345
|
init_runtimeRedis();
|
|
@@ -36641,7 +37476,7 @@ var init_runtimeComparison = __esm({
|
|
|
36641
37476
|
}) => {
|
|
36642
37477
|
if (typeof connector.getEntryExecutions !== "function") {
|
|
36643
37478
|
console.log(
|
|
36644
|
-
|
|
37479
|
+
import_chalk52.default.yellow(
|
|
36645
37480
|
"runtime compare: connector does not support entry execution history"
|
|
36646
37481
|
)
|
|
36647
37482
|
);
|
|
@@ -36658,7 +37493,7 @@ var init_runtimeComparison = __esm({
|
|
|
36658
37493
|
});
|
|
36659
37494
|
if (chunkRows.length >= 100) {
|
|
36660
37495
|
console.log(
|
|
36661
|
-
|
|
37496
|
+
import_chalk52.default.yellow(
|
|
36662
37497
|
"runtime compare: exchange entry executions returned 100 rows (connector cap); older entry trades in this chunk may be truncated"
|
|
36663
37498
|
)
|
|
36664
37499
|
);
|
|
@@ -36666,7 +37501,7 @@ var init_runtimeComparison = __esm({
|
|
|
36666
37501
|
rows.push(...chunkRows);
|
|
36667
37502
|
} catch (error) {
|
|
36668
37503
|
console.log(
|
|
36669
|
-
|
|
37504
|
+
import_chalk52.default.yellow(
|
|
36670
37505
|
`runtime compare: getEntryExecutions failed: ${formatRuntimeTradeSyncError(error)}`
|
|
36671
37506
|
)
|
|
36672
37507
|
);
|
|
@@ -36691,21 +37526,21 @@ var init_runtimeComparison = __esm({
|
|
|
36691
37526
|
callbacks: {
|
|
36692
37527
|
onUnsupported: () => {
|
|
36693
37528
|
console.log(
|
|
36694
|
-
|
|
37529
|
+
import_chalk52.default.yellow(
|
|
36695
37530
|
"runtime compare: connector does not support getClosedPnl, using runtime trade records as-is"
|
|
36696
37531
|
)
|
|
36697
37532
|
);
|
|
36698
37533
|
},
|
|
36699
37534
|
onCapped: () => {
|
|
36700
37535
|
console.log(
|
|
36701
|
-
|
|
37536
|
+
import_chalk52.default.yellow(
|
|
36702
37537
|
"runtime compare: exchange closed pnl returned 100 rows (connector cap); older closed trades in the window may be truncated"
|
|
36703
37538
|
)
|
|
36704
37539
|
);
|
|
36705
37540
|
},
|
|
36706
37541
|
onError: (error) => {
|
|
36707
37542
|
console.log(
|
|
36708
|
-
|
|
37543
|
+
import_chalk52.default.yellow(
|
|
36709
37544
|
`runtime compare: getClosedPnl failed: ${formatRuntimeTradeSyncError(error)}`
|
|
36710
37545
|
)
|
|
36711
37546
|
);
|
|
@@ -36927,7 +37762,7 @@ var init_runtimeComparison = __esm({
|
|
|
36927
37762
|
]);
|
|
36928
37763
|
if (runtimeEvidence2) {
|
|
36929
37764
|
console.log(
|
|
36930
|
-
|
|
37765
|
+
import_chalk52.default.gray(
|
|
36931
37766
|
`runtime compare: using immutable evidence ${runtimeEvidence2.path}`
|
|
36932
37767
|
)
|
|
36933
37768
|
);
|
|
@@ -36941,7 +37776,7 @@ var init_runtimeComparison = __esm({
|
|
|
36941
37776
|
openPositionCallbacks: {
|
|
36942
37777
|
onError: (error) => {
|
|
36943
37778
|
console.log(
|
|
36944
|
-
|
|
37779
|
+
import_chalk52.default.yellow(
|
|
36945
37780
|
`runtime compare: getOpenPositionPnl failed: ${formatRuntimeTradeSyncError(error)}; continuing without open-position mark prices`
|
|
36946
37781
|
)
|
|
36947
37782
|
);
|
|
@@ -36950,21 +37785,21 @@ var init_runtimeComparison = __esm({
|
|
|
36950
37785
|
closedPnlCallbacks: {
|
|
36951
37786
|
onUnsupported: () => {
|
|
36952
37787
|
console.log(
|
|
36953
|
-
|
|
37788
|
+
import_chalk52.default.yellow(
|
|
36954
37789
|
"runtime compare: connector does not support getClosedPnl, using runtime trade records as-is"
|
|
36955
37790
|
)
|
|
36956
37791
|
);
|
|
36957
37792
|
},
|
|
36958
37793
|
onCapped: () => {
|
|
36959
37794
|
console.log(
|
|
36960
|
-
|
|
37795
|
+
import_chalk52.default.yellow(
|
|
36961
37796
|
"runtime compare: exchange closed pnl returned 100 rows (connector cap); older closed trades in the window may be truncated"
|
|
36962
37797
|
)
|
|
36963
37798
|
);
|
|
36964
37799
|
},
|
|
36965
37800
|
onError: (error) => {
|
|
36966
37801
|
console.log(
|
|
36967
|
-
|
|
37802
|
+
import_chalk52.default.yellow(
|
|
36968
37803
|
`runtime compare: getClosedPnl failed: ${formatRuntimeTradeSyncError(error)}`
|
|
36969
37804
|
)
|
|
36970
37805
|
);
|
|
@@ -37060,12 +37895,12 @@ var init_runtimeComparison = __esm({
|
|
|
37060
37895
|
});
|
|
37061
37896
|
|
|
37062
37897
|
// src/lib/replay/outputReport.ts
|
|
37063
|
-
var
|
|
37898
|
+
var import_promises33, import_node_path30, import_data4, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
|
|
37064
37899
|
var init_outputReport = __esm({
|
|
37065
37900
|
"src/lib/replay/outputReport.ts"() {
|
|
37066
37901
|
"use strict";
|
|
37067
|
-
|
|
37068
|
-
|
|
37902
|
+
import_promises33 = __toESM(require("fs/promises"));
|
|
37903
|
+
import_node_path30 = __toESM(require("path"));
|
|
37069
37904
|
import_data4 = require("@tradejs/core/data");
|
|
37070
37905
|
init_support();
|
|
37071
37906
|
formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
@@ -37357,7 +38192,7 @@ var init_outputReport = __esm({
|
|
|
37357
38192
|
) : "_No replay lineage records._";
|
|
37358
38193
|
};
|
|
37359
38194
|
writeReplayOutputReport = async ({
|
|
37360
|
-
projectRoot:
|
|
38195
|
+
projectRoot: projectRoot17,
|
|
37361
38196
|
timestamp,
|
|
37362
38197
|
replayKey,
|
|
37363
38198
|
userName: userName3,
|
|
@@ -37370,8 +38205,8 @@ var init_outputReport = __esm({
|
|
|
37370
38205
|
strategySnapshot,
|
|
37371
38206
|
runtimeComparison
|
|
37372
38207
|
}) => {
|
|
37373
|
-
const outputDir =
|
|
37374
|
-
await
|
|
38208
|
+
const outputDir = import_node_path30.default.resolve(projectRoot17, "data/replay/output");
|
|
38209
|
+
await import_promises33.default.mkdir(outputDir, { recursive: true });
|
|
37375
38210
|
const perTradeAnalysis = buildPerTradeAnalysis(runtimeComparison);
|
|
37376
38211
|
const report = {
|
|
37377
38212
|
reportType: "replay-output",
|
|
@@ -37406,8 +38241,8 @@ var init_outputReport = __esm({
|
|
|
37406
38241
|
runtimeComparison,
|
|
37407
38242
|
perTradeAnalysis
|
|
37408
38243
|
};
|
|
37409
|
-
const markdownPath =
|
|
37410
|
-
const jsonPath =
|
|
38244
|
+
const markdownPath = import_node_path30.default.join(outputDir, `${timestamp}-replay-report.md`);
|
|
38245
|
+
const jsonPath = import_node_path30.default.join(outputDir, `${timestamp}-replay-report.json`);
|
|
37411
38246
|
const lines = [
|
|
37412
38247
|
"# Replay Report",
|
|
37413
38248
|
"",
|
|
@@ -37473,8 +38308,8 @@ var init_outputReport = __esm({
|
|
|
37473
38308
|
""
|
|
37474
38309
|
];
|
|
37475
38310
|
await Promise.all([
|
|
37476
|
-
|
|
37477
|
-
|
|
38311
|
+
import_promises33.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
38312
|
+
import_promises33.default.writeFile(jsonPath, `${(0, import_data4.toJson)(report, true)}
|
|
37478
38313
|
`, "utf8")
|
|
37479
38314
|
]);
|
|
37480
38315
|
return {
|
|
@@ -37486,11 +38321,11 @@ var init_outputReport = __esm({
|
|
|
37486
38321
|
});
|
|
37487
38322
|
|
|
37488
38323
|
// src/scripts/replayRunner.ts
|
|
37489
|
-
var
|
|
38324
|
+
var import_chalk53, import_constants19, import_data5, import_time14, import_redis21, prepareReplayBinanceMarketContext, finishReplay, replayBacktest;
|
|
37490
38325
|
var init_replayRunner = __esm({
|
|
37491
38326
|
"src/scripts/replayRunner.ts"() {
|
|
37492
38327
|
"use strict";
|
|
37493
|
-
|
|
38328
|
+
import_chalk53 = __toESM(require("chalk"));
|
|
37494
38329
|
import_constants19 = require("@tradejs/core/constants");
|
|
37495
38330
|
import_data5 = require("@tradejs/core/data");
|
|
37496
38331
|
import_time14 = require("@tradejs/core/time");
|
|
@@ -37524,7 +38359,7 @@ var init_replayRunner = __esm({
|
|
|
37524
38359
|
aiEnabled: preparedRun.aiEnabled,
|
|
37525
38360
|
mlEnabled: preparedRun.mlEnabled,
|
|
37526
38361
|
strategyNames: preparedRun.strategyNames,
|
|
37527
|
-
log: (message) => console.log(
|
|
38362
|
+
log: (message) => console.log(import_chalk53.default.gray(message))
|
|
37528
38363
|
});
|
|
37529
38364
|
};
|
|
37530
38365
|
finishReplay = async ({
|
|
@@ -37577,8 +38412,8 @@ var init_replayRunner = __esm({
|
|
|
37577
38412
|
strategySnapshot: replayStrategySnapshot,
|
|
37578
38413
|
runtimeComparison: replayRuntimeComparison
|
|
37579
38414
|
});
|
|
37580
|
-
console.log(
|
|
37581
|
-
console.log(
|
|
38415
|
+
console.log(import_chalk53.default.green(`Replay report: ${outputReport.markdownPath}`));
|
|
38416
|
+
console.log(import_chalk53.default.green(`Replay report JSON: ${outputReport.jsonPath}`));
|
|
37582
38417
|
await (0, import_redis21.setData)(
|
|
37583
38418
|
replayKey,
|
|
37584
38419
|
{
|
|
@@ -37731,9 +38566,9 @@ var init_replayRunner = __esm({
|
|
|
37731
38566
|
),
|
|
37732
38567
|
strategyNames: replayStrategies.map(({ strategyName }) => strategyName)
|
|
37733
38568
|
});
|
|
37734
|
-
console.log(
|
|
38569
|
+
console.log(import_chalk53.default.yellow(`tickers: ${preparedRun.tickers.length}`));
|
|
37735
38570
|
console.log(
|
|
37736
|
-
|
|
38571
|
+
import_chalk53.default.gray(
|
|
37737
38572
|
`mode: replay (${replayStrategies.map(({ strategyName }) => strategyName).join(", ")})`
|
|
37738
38573
|
)
|
|
37739
38574
|
);
|
|
@@ -37761,14 +38596,14 @@ var init_replayRunner = __esm({
|
|
|
37761
38596
|
// src/scripts/replay.ts
|
|
37762
38597
|
var replay_exports = {};
|
|
37763
38598
|
__export(replay_exports, {
|
|
37764
|
-
main: () =>
|
|
38599
|
+
main: () => main45
|
|
37765
38600
|
});
|
|
37766
|
-
var
|
|
38601
|
+
var main45;
|
|
37767
38602
|
var init_replay = __esm({
|
|
37768
38603
|
"src/scripts/replay.ts"() {
|
|
37769
38604
|
"use strict";
|
|
37770
38605
|
init_replayRunner();
|
|
37771
|
-
|
|
38606
|
+
main45 = async () => {
|
|
37772
38607
|
await replayBacktest();
|
|
37773
38608
|
};
|
|
37774
38609
|
}
|
|
@@ -37777,15 +38612,15 @@ var init_replay = __esm({
|
|
|
37777
38612
|
// src/scripts/signalsSummary.ts
|
|
37778
38613
|
var signalsSummary_exports = {};
|
|
37779
38614
|
__export(signalsSummary_exports, {
|
|
37780
|
-
main: () =>
|
|
38615
|
+
main: () => main46,
|
|
37781
38616
|
signalsSummary: () => signalsSummary
|
|
37782
38617
|
});
|
|
37783
|
-
var import_config13,
|
|
38618
|
+
var import_config13, import_args35, import_logger12, import_connectors18, import_runtimeStrategies9, flags32, projectRoot16, SUMMARY_TIMEZONE2, SUMMARY_TIMEZONE_LABEL2, escapeHtml6, formatMskDateTime3, formatSigned3, formatPnlMoneyText, formatWinRateText, resolveSummaryTitle, normalizeStatus, shouldAttachDebugReport, getSummaryDateParts, formatSummaryIsoDayKey, unescapeHtml, stripTelegramHtml, buildSignalsSummaryAttachment, appendReportAttachmentSummary, resolveSummaryConnectorName, groupRuntimeTradesByConnectorScope, syncRuntimeTradeScopes, createRuntimeSignalStats, mergeRuntimeSignalStats, buildSummaryPrelude, resolveTradeStatusEmoji, isTimestampInWindow, isRuntimeTradeClosedInWindow, buildSummaryMessages, signalsSummary, main46;
|
|
37784
38619
|
var init_signalsSummary = __esm({
|
|
37785
38620
|
"src/scripts/signalsSummary.ts"() {
|
|
37786
38621
|
"use strict";
|
|
37787
38622
|
import_config13 = require("dotenv/config");
|
|
37788
|
-
|
|
38623
|
+
import_args35 = __toESM(require("args"));
|
|
37789
38624
|
import_logger12 = require("@tradejs/infra/logger");
|
|
37790
38625
|
import_connectors18 = require("@tradejs/node/connectors");
|
|
37791
38626
|
init_runtimeRedis();
|
|
@@ -37795,21 +38630,21 @@ var init_signalsSummary = __esm({
|
|
|
37795
38630
|
init_runtimeSignalsStorage();
|
|
37796
38631
|
init_runtimeDebugEvidence();
|
|
37797
38632
|
import_runtimeStrategies9 = require("@tradejs/node/runtimeStrategies");
|
|
37798
|
-
|
|
37799
|
-
|
|
38633
|
+
import_args35.default.option(["u", "user"], "Use user config", "root");
|
|
38634
|
+
import_args35.default.option(
|
|
37800
38635
|
"connector",
|
|
37801
38636
|
"Connector provider or name for summary (e.g. bybit, binance, coinbase, custom)",
|
|
37802
38637
|
"bybit"
|
|
37803
38638
|
);
|
|
37804
|
-
|
|
37805
|
-
|
|
37806
|
-
|
|
38639
|
+
import_args35.default.option(["H", "hours"], "Summary window in hours", 24);
|
|
38640
|
+
import_args35.default.option(["P", "printOnly"], "Print summary instead of Telegram", false);
|
|
38641
|
+
import_args35.default.option(
|
|
37807
38642
|
"debugAttachment",
|
|
37808
38643
|
"Attach runtime Redis debug JSON for replay diagnostics",
|
|
37809
38644
|
true
|
|
37810
38645
|
);
|
|
37811
|
-
|
|
37812
|
-
|
|
38646
|
+
flags32 = import_args35.default.parse(process.argv);
|
|
38647
|
+
projectRoot16 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
37813
38648
|
SUMMARY_TIMEZONE2 = "Europe/Moscow";
|
|
37814
38649
|
SUMMARY_TIMEZONE_LABEL2 = "MSK";
|
|
37815
38650
|
escapeHtml6 = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -37896,7 +38731,7 @@ var init_signalsSummary = __esm({
|
|
|
37896
38731
|
return lines.join("\n");
|
|
37897
38732
|
};
|
|
37898
38733
|
resolveSummaryConnectorName = async (value) => {
|
|
37899
|
-
const connectorName = await (0, import_connectors18.resolveConnectorName)(value,
|
|
38734
|
+
const connectorName = await (0, import_connectors18.resolveConnectorName)(value, projectRoot16);
|
|
37900
38735
|
if (connectorName) {
|
|
37901
38736
|
return connectorName;
|
|
37902
38737
|
}
|
|
@@ -37961,7 +38796,7 @@ var init_signalsSummary = __esm({
|
|
|
37961
38796
|
);
|
|
37962
38797
|
const connectorFactory = await (0, import_connectors18.getConnectorCreatorByName)(
|
|
37963
38798
|
connectorName,
|
|
37964
|
-
|
|
38799
|
+
projectRoot16
|
|
37965
38800
|
);
|
|
37966
38801
|
if (!connectorFactory) {
|
|
37967
38802
|
throw new Error(`Connector "${connectorName}" is not registered`);
|
|
@@ -38314,12 +39149,12 @@ none`
|
|
|
38314
39149
|
signalsSummary = async () => {
|
|
38315
39150
|
const hours = Math.max(
|
|
38316
39151
|
1,
|
|
38317
|
-
Number.parseInt(String(
|
|
39152
|
+
Number.parseInt(String(flags32.hours ?? 24), 10) || 24
|
|
38318
39153
|
);
|
|
38319
39154
|
const endTime = Date.now();
|
|
38320
39155
|
const startTime = endTime - hours * 60 * 60 * 1e3;
|
|
38321
39156
|
const fallbackConnectorName = await resolveSummaryConnectorName(
|
|
38322
|
-
|
|
39157
|
+
flags32.connector
|
|
38323
39158
|
);
|
|
38324
39159
|
const [
|
|
38325
39160
|
configuredStrategyNames,
|
|
@@ -38328,25 +39163,25 @@ none`
|
|
|
38328
39163
|
trades,
|
|
38329
39164
|
runtimeDeployments
|
|
38330
39165
|
] = await Promise.all([
|
|
38331
|
-
(0, import_runtimeStrategyConfigs.loadRuntimeStrategyNames)(
|
|
38332
|
-
loadRuntimeSignals(
|
|
38333
|
-
loadRuntimeSignalEvaluationStatsBuckets(
|
|
38334
|
-
loadRuntimeTrades(
|
|
38335
|
-
(0, import_runtimeStrategies9.listRuntimeDeployments)({ userName:
|
|
39166
|
+
(0, import_runtimeStrategyConfigs.loadRuntimeStrategyNames)(flags32.user),
|
|
39167
|
+
loadRuntimeSignals(flags32.user, { startTime, endTime }),
|
|
39168
|
+
loadRuntimeSignalEvaluationStatsBuckets(flags32.user),
|
|
39169
|
+
loadRuntimeTrades(flags32.user),
|
|
39170
|
+
(0, import_runtimeStrategies9.listRuntimeDeployments)({ userName: flags32.user, projectRoot: projectRoot16 })
|
|
38336
39171
|
]);
|
|
38337
39172
|
const {
|
|
38338
39173
|
trades: syncedTrades,
|
|
38339
39174
|
connectorNames,
|
|
38340
39175
|
scopesCount
|
|
38341
39176
|
} = await syncRuntimeTradeScopes({
|
|
38342
|
-
userName:
|
|
39177
|
+
userName: flags32.user,
|
|
38343
39178
|
startTime,
|
|
38344
39179
|
endTime,
|
|
38345
39180
|
fallbackConnectorName,
|
|
38346
39181
|
trades,
|
|
38347
39182
|
deployments: runtimeDeployments
|
|
38348
39183
|
});
|
|
38349
|
-
const activeTradeOrderIds = await loadRuntimeActiveTradeOrderIds(
|
|
39184
|
+
const activeTradeOrderIds = await loadRuntimeActiveTradeOrderIds(flags32.user);
|
|
38350
39185
|
const windowSignals = signals2.filter(
|
|
38351
39186
|
(signal) => signal.timestamp >= startTime && signal.timestamp < endTime
|
|
38352
39187
|
);
|
|
@@ -38394,10 +39229,10 @@ none`
|
|
|
38394
39229
|
windowClosedTrades.length,
|
|
38395
39230
|
connectorNames.join(",") || fallbackConnectorName,
|
|
38396
39231
|
scopesCount,
|
|
38397
|
-
|
|
39232
|
+
flags32.user
|
|
38398
39233
|
);
|
|
38399
|
-
const debugAttachment = shouldAttachDebugReport(
|
|
38400
|
-
userName:
|
|
39234
|
+
const debugAttachment = shouldAttachDebugReport(flags32.debugAttachment) ? await buildRuntimeDebugReportAttachment({
|
|
39235
|
+
userName: flags32.user,
|
|
38401
39236
|
startTime,
|
|
38402
39237
|
endTime,
|
|
38403
39238
|
signals: debugSignals,
|
|
@@ -38405,7 +39240,7 @@ none`
|
|
|
38405
39240
|
trades: windowTrades
|
|
38406
39241
|
}) : null;
|
|
38407
39242
|
const signalsAttachment = buildSignalsSummaryAttachment({
|
|
38408
|
-
userName:
|
|
39243
|
+
userName: flags32.user,
|
|
38409
39244
|
endTime,
|
|
38410
39245
|
content: signalsMessage
|
|
38411
39246
|
});
|
|
@@ -38421,7 +39256,7 @@ none`
|
|
|
38421
39256
|
signalsAttachment,
|
|
38422
39257
|
...debugAttachment ? [debugAttachment] : []
|
|
38423
39258
|
];
|
|
38424
|
-
if (
|
|
39259
|
+
if (flags32.printOnly) {
|
|
38425
39260
|
console.log(tradesMessageWithAttachmentSummary);
|
|
38426
39261
|
console.log("");
|
|
38427
39262
|
console.log(`Signals attachment: ${signalsAttachment.filename}`);
|
|
@@ -38434,20 +39269,20 @@ none`
|
|
|
38434
39269
|
return;
|
|
38435
39270
|
}
|
|
38436
39271
|
await sendTelegramReport(tradesMessageWithAttachmentSummary, {
|
|
38437
|
-
userName:
|
|
39272
|
+
userName: flags32.user,
|
|
38438
39273
|
attachments
|
|
38439
39274
|
});
|
|
38440
39275
|
};
|
|
38441
|
-
|
|
39276
|
+
main46 = signalsSummary;
|
|
38442
39277
|
}
|
|
38443
39278
|
});
|
|
38444
39279
|
|
|
38445
39280
|
// src/scripts/test-ml.ts
|
|
38446
39281
|
var test_ml_exports = {};
|
|
38447
39282
|
__export(test_ml_exports, {
|
|
38448
|
-
main: () =>
|
|
39283
|
+
main: () => main47
|
|
38449
39284
|
});
|
|
38450
|
-
var import_config14, import_constants20, import_ml3, import_registry5, now, INTERVAL_MIN, CANDLES, makeSeries, makeCandles, buildTrendline,
|
|
39285
|
+
var import_config14, import_constants20, import_ml3, import_registry5, now, INTERVAL_MIN, CANDLES, makeSeries, makeCandles, buildTrendline, main47;
|
|
38451
39286
|
var init_test_ml = __esm({
|
|
38452
39287
|
"src/scripts/test-ml.ts"() {
|
|
38453
39288
|
"use strict";
|
|
@@ -38497,7 +39332,7 @@ var init_test_ml = __esm({
|
|
|
38497
39332
|
{ timestamp: entryTs - 2 * INTERVAL_MIN * 6e4, value: price * 0.995 }
|
|
38498
39333
|
]
|
|
38499
39334
|
});
|
|
38500
|
-
|
|
39335
|
+
main47 = async () => {
|
|
38501
39336
|
const defaultConfig = await (0, import_registry5.getStrategyDefaults)("TrendLine", process.cwd());
|
|
38502
39337
|
if (!defaultConfig) {
|
|
38503
39338
|
throw new Error(
|
|
@@ -38590,9 +39425,9 @@ var init_test_ml = __esm({
|
|
|
38590
39425
|
// src/scripts/test.ts
|
|
38591
39426
|
var test_exports = {};
|
|
38592
39427
|
__export(test_exports, {
|
|
38593
|
-
main: () =>
|
|
39428
|
+
main: () => main48
|
|
38594
39429
|
});
|
|
38595
|
-
var import_config15, import_connectors19, getPositions,
|
|
39430
|
+
var import_config15, import_connectors19, getPositions, main48;
|
|
38596
39431
|
var init_test = __esm({
|
|
38597
39432
|
"src/scripts/test.ts"() {
|
|
38598
39433
|
"use strict";
|
|
@@ -38602,7 +39437,7 @@ var init_test = __esm({
|
|
|
38602
39437
|
const res = await connector.getPositions();
|
|
38603
39438
|
console.log("res", res);
|
|
38604
39439
|
};
|
|
38605
|
-
|
|
39440
|
+
main48 = async () => {
|
|
38606
39441
|
const byBitConnector = await import_connectors19.connectors.ByBit({
|
|
38607
39442
|
userName: "root"
|
|
38608
39443
|
});
|
|
@@ -38614,25 +39449,25 @@ var init_test = __esm({
|
|
|
38614
39449
|
// src/scripts/user-add.ts
|
|
38615
39450
|
var user_add_exports = {};
|
|
38616
39451
|
__export(user_add_exports, {
|
|
38617
|
-
main: () =>
|
|
39452
|
+
main: () => main49
|
|
38618
39453
|
});
|
|
38619
|
-
var
|
|
39454
|
+
var import_args36, import_chalk54, import_bcryptjs, import_redis22, flags33, main49;
|
|
38620
39455
|
var init_user_add = __esm({
|
|
38621
39456
|
"src/scripts/user-add.ts"() {
|
|
38622
39457
|
"use strict";
|
|
38623
|
-
|
|
38624
|
-
|
|
39458
|
+
import_args36 = __toESM(require("args"));
|
|
39459
|
+
import_chalk54 = __toESM(require("chalk"));
|
|
38625
39460
|
import_bcryptjs = __toESM(require("bcryptjs"));
|
|
38626
39461
|
import_redis22 = require("@tradejs/infra/redis");
|
|
38627
|
-
|
|
38628
|
-
|
|
38629
|
-
|
|
38630
|
-
|
|
38631
|
-
|
|
38632
|
-
const userName3 = String(
|
|
38633
|
-
const password = String(
|
|
39462
|
+
import_args36.default.example("yarn user-add -u myname -p 123456", "Create or update user");
|
|
39463
|
+
import_args36.default.option(["u", "user"], "Username", "");
|
|
39464
|
+
import_args36.default.option(["p", "password"], "Password (plain text)", "");
|
|
39465
|
+
flags33 = import_args36.default.parse(process.argv);
|
|
39466
|
+
main49 = async () => {
|
|
39467
|
+
const userName3 = String(flags33.user || "").trim();
|
|
39468
|
+
const password = String(flags33.password || "");
|
|
38634
39469
|
if (!userName3 || !password) {
|
|
38635
|
-
console.error(
|
|
39470
|
+
console.error(import_chalk54.default.red("Missing -U <user> or -P <password>"));
|
|
38636
39471
|
process.exit(1);
|
|
38637
39472
|
}
|
|
38638
39473
|
const passwordHash = await import_bcryptjs.default.hash(password, 10);
|
|
@@ -38646,7 +39481,7 @@ var init_user_add = __esm({
|
|
|
38646
39481
|
await (0, import_redis22.setData)(import_redis22.redisKeys.user(userName3), next, {
|
|
38647
39482
|
expire: 0
|
|
38648
39483
|
});
|
|
38649
|
-
console.log(
|
|
39484
|
+
console.log(import_chalk54.default.green(`User ${userName3} updated`));
|
|
38650
39485
|
process.exit(0);
|
|
38651
39486
|
};
|
|
38652
39487
|
}
|
|
@@ -38656,7 +39491,7 @@ var init_user_add = __esm({
|
|
|
38656
39491
|
var cli_exports = {};
|
|
38657
39492
|
__export(cli_exports, {
|
|
38658
39493
|
cleanupCliResources: () => cleanupCliResources,
|
|
38659
|
-
main: () =>
|
|
39494
|
+
main: () => main50,
|
|
38660
39495
|
printUsage: () => printUsage3,
|
|
38661
39496
|
runLoadedModule: () => runLoadedModule
|
|
38662
39497
|
});
|
|
@@ -38698,6 +39533,8 @@ var scriptLoaders = {
|
|
|
38698
39533
|
"research:core": () => Promise.resolve().then(() => (init_coreResearch(), coreResearch_exports)),
|
|
38699
39534
|
results: () => Promise.resolve().then(() => (init_results(), results_exports)),
|
|
38700
39535
|
"replay-runtime-evidence": () => Promise.resolve().then(() => (init_replayRuntimeEvidence(), replayRuntimeEvidence_exports)),
|
|
39536
|
+
"runtime-feedback-replay": () => Promise.resolve().then(() => (init_runtimeFeedbackReplay2(), runtimeFeedbackReplay_exports)),
|
|
39537
|
+
"runtime-feedback-sync": () => Promise.resolve().then(() => (init_runtimeFeedbackSync2(), runtimeFeedbackSync_exports)),
|
|
38701
39538
|
"runtime-evidence": () => Promise.resolve().then(() => (init_runtimeEvidence(), runtimeEvidence_exports)),
|
|
38702
39539
|
"runtime-evidence-sync": () => Promise.resolve().then(() => (init_runtimeEvidenceSync2(), runtimeEvidenceSync_exports)),
|
|
38703
39540
|
"runtime-scorecard": () => Promise.resolve().then(() => (init_runtimeScorecard2(), runtimeScorecard_exports)),
|
|
@@ -38729,14 +39566,14 @@ var runLoadedModule = async (loaded) => {
|
|
|
38729
39566
|
var cleanupCliResources = async () => {
|
|
38730
39567
|
await Promise.allSettled([(0, import_redis23.closeRedisConnection)(), (0, import_client9.closeTimescalePool)()]);
|
|
38731
39568
|
};
|
|
38732
|
-
var
|
|
38733
|
-
const [, scriptPath, command = "", ...
|
|
39569
|
+
var main50 = async () => {
|
|
39570
|
+
const [, scriptPath, command = "", ...args37] = process.argv;
|
|
38734
39571
|
const loader = scriptLoaders[command];
|
|
38735
39572
|
if (!loader) {
|
|
38736
39573
|
printUsage3();
|
|
38737
39574
|
process.exit(command ? 1 : 0);
|
|
38738
39575
|
}
|
|
38739
|
-
const nextArgs = [...
|
|
39576
|
+
const nextArgs = [...args37];
|
|
38740
39577
|
if (command === "spread:ingest") {
|
|
38741
39578
|
nextArgs.push("--provider", "binance_coinbase_spread");
|
|
38742
39579
|
}
|
|
@@ -38749,7 +39586,7 @@ var main48 = async () => {
|
|
|
38749
39586
|
}
|
|
38750
39587
|
};
|
|
38751
39588
|
if (require.main === module) {
|
|
38752
|
-
|
|
39589
|
+
main50().catch((error) => {
|
|
38753
39590
|
console.error(error);
|
|
38754
39591
|
process.exit(1);
|
|
38755
39592
|
});
|