@tradejs/cli 3.1.27-beta.248 → 3.1.27-beta.250
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 +603 -207
- package/dist/lib/runtimeEvidenceCompositionSnapshots.js +432 -0
- package/dist/lib/runtimeEvidenceCompositions.js +548 -0
- package/dist/scripts/runtimeEvidence.js +375 -112
- package/dist/scripts/signals.js +396 -18
- package/dist/scripts/signalsDaemon.js +396 -18
- package/package.json +7 -7
|
@@ -49,7 +49,7 @@ var import_constants3 = require("@tradejs/core/constants");
|
|
|
49
49
|
var import_time3 = require("@tradejs/core/time");
|
|
50
50
|
var import_logger4 = require("@tradejs/infra/logger");
|
|
51
51
|
var import_runtimeHeartbeats = require("@tradejs/infra/runtimeHeartbeats");
|
|
52
|
-
var
|
|
52
|
+
var import_runtimeStrategies3 = require("@tradejs/node/runtimeStrategies");
|
|
53
53
|
|
|
54
54
|
// src/lib/marketData/windows.ts
|
|
55
55
|
var import_indicators = require("@tradejs/core/indicators");
|
|
@@ -2148,27 +2148,27 @@ var createCoinMarketCapFetchStats = () => ({
|
|
|
2148
2148
|
totalCredits: 0,
|
|
2149
2149
|
byPath: /* @__PURE__ */ new Map()
|
|
2150
2150
|
});
|
|
2151
|
-
var getCoinMarketCapPathLabel = (
|
|
2152
|
-
if (
|
|
2153
|
-
if (
|
|
2154
|
-
if (
|
|
2155
|
-
if (
|
|
2156
|
-
if (
|
|
2157
|
-
if (
|
|
2158
|
-
return
|
|
2159
|
-
};
|
|
2160
|
-
var recordCoinMarketCapFetchStats = (stats,
|
|
2151
|
+
var getCoinMarketCapPathLabel = (path3) => {
|
|
2152
|
+
if (path3.includes("global-metrics")) return "global";
|
|
2153
|
+
if (path3.includes("cryptocurrency/quotes")) return "reference";
|
|
2154
|
+
if (path3.includes("exchange/quotes")) return "exchangeLiquidity";
|
|
2155
|
+
if (path3.includes("fear-and-greed")) return "fearGreed";
|
|
2156
|
+
if (path3.includes("cmc100")) return "cmc100";
|
|
2157
|
+
if (path3.includes("cmc20")) return "cmc20";
|
|
2158
|
+
return path3;
|
|
2159
|
+
};
|
|
2160
|
+
var recordCoinMarketCapFetchStats = (stats, path3, creditCount) => {
|
|
2161
2161
|
if (!stats) return;
|
|
2162
|
-
const existing = stats.byPath.get(
|
|
2162
|
+
const existing = stats.byPath.get(path3) ?? { requests: 0, credits: 0 };
|
|
2163
2163
|
existing.requests += 1;
|
|
2164
2164
|
existing.credits += creditCount ?? 0;
|
|
2165
2165
|
stats.requests += 1;
|
|
2166
2166
|
stats.totalCredits += creditCount ?? 0;
|
|
2167
|
-
stats.byPath.set(
|
|
2167
|
+
stats.byPath.set(path3, existing);
|
|
2168
2168
|
};
|
|
2169
2169
|
var formatCoinMarketCapFetchStats = (stats) => {
|
|
2170
2170
|
const byPath = [...stats.byPath.entries()].map(
|
|
2171
|
-
([
|
|
2171
|
+
([path3, item]) => `${getCoinMarketCapPathLabel(path3)}=${item.requests}req/${item.credits}cr`
|
|
2172
2172
|
).join(" ");
|
|
2173
2173
|
return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
|
|
2174
2174
|
};
|
|
@@ -4929,6 +4929,368 @@ var buildConfiguredSignalsScopes = ({
|
|
|
4929
4929
|
}));
|
|
4930
4930
|
};
|
|
4931
4931
|
|
|
4932
|
+
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
4933
|
+
var import_node_crypto3 = require("crypto");
|
|
4934
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
4935
|
+
var import_node_path2 = __toESM(require("path"));
|
|
4936
|
+
|
|
4937
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
4938
|
+
var import_runtimeStrategies2 = require("@tradejs/node/runtimeStrategies");
|
|
4939
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
4940
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
4941
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
4942
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
4943
|
+
);
|
|
4944
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
4945
|
+
"1",
|
|
4946
|
+
"3",
|
|
4947
|
+
"5",
|
|
4948
|
+
"15",
|
|
4949
|
+
"30",
|
|
4950
|
+
"60",
|
|
4951
|
+
"120",
|
|
4952
|
+
"240",
|
|
4953
|
+
"360",
|
|
4954
|
+
"720",
|
|
4955
|
+
"D",
|
|
4956
|
+
"W",
|
|
4957
|
+
"M"
|
|
4958
|
+
]);
|
|
4959
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
4960
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
4961
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
4962
|
+
if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
4963
|
+
throw new Error(
|
|
4964
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
4965
|
+
);
|
|
4966
|
+
}
|
|
4967
|
+
const strategies = value.strategies.map((candidate) => {
|
|
4968
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
4969
|
+
throw new Error(
|
|
4970
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
4971
|
+
);
|
|
4972
|
+
}
|
|
4973
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
4974
|
+
throw new Error(
|
|
4975
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
4976
|
+
);
|
|
4977
|
+
}
|
|
4978
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
4979
|
+
throw new Error(
|
|
4980
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
4981
|
+
);
|
|
4982
|
+
}
|
|
4983
|
+
return candidate;
|
|
4984
|
+
});
|
|
4985
|
+
const identities = /* @__PURE__ */ new Set();
|
|
4986
|
+
for (const strategy of strategies) {
|
|
4987
|
+
if (identities.has(strategy.strategyName)) {
|
|
4988
|
+
throw new Error(
|
|
4989
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
4990
|
+
);
|
|
4991
|
+
}
|
|
4992
|
+
identities.add(strategy.strategyName);
|
|
4993
|
+
}
|
|
4994
|
+
return {
|
|
4995
|
+
...value,
|
|
4996
|
+
strategies
|
|
4997
|
+
};
|
|
4998
|
+
};
|
|
4999
|
+
var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
5000
|
+
userName,
|
|
5001
|
+
projectRoot,
|
|
5002
|
+
deploymentId
|
|
5003
|
+
}) => {
|
|
5004
|
+
const [deployment, strategies] = await Promise.all([
|
|
5005
|
+
(0, import_runtimeStrategies2.getRuntimeDeployment)({ userName, projectRoot, deploymentId }),
|
|
5006
|
+
(0, import_runtimeStrategies2.loadResolvedRuntimeStrategies)({ userName, projectRoot, deploymentId })
|
|
5007
|
+
]);
|
|
5008
|
+
if (!deployment) {
|
|
5009
|
+
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
5010
|
+
}
|
|
5011
|
+
return {
|
|
5012
|
+
schemaVersion: 2,
|
|
5013
|
+
id: deployment.id,
|
|
5014
|
+
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
5015
|
+
label: deployment.label,
|
|
5016
|
+
connectorName: deployment.connectorName,
|
|
5017
|
+
provider: deployment.provider,
|
|
5018
|
+
accountId: deployment.accountId,
|
|
5019
|
+
enabled: deployment.enabled,
|
|
5020
|
+
strategies: strategies.map(
|
|
5021
|
+
({
|
|
5022
|
+
strategyName,
|
|
5023
|
+
strategyRevision,
|
|
5024
|
+
enabled,
|
|
5025
|
+
controlState,
|
|
5026
|
+
interval,
|
|
5027
|
+
universe,
|
|
5028
|
+
accountId,
|
|
5029
|
+
strategyPackage,
|
|
5030
|
+
strategyPackageVersion,
|
|
5031
|
+
strategyDependencyVersions,
|
|
5032
|
+
runtimePackageVersion,
|
|
5033
|
+
strategyConfig,
|
|
5034
|
+
selection
|
|
5035
|
+
}) => ({
|
|
5036
|
+
strategyName,
|
|
5037
|
+
strategyRevision,
|
|
5038
|
+
enabled,
|
|
5039
|
+
controlState,
|
|
5040
|
+
interval,
|
|
5041
|
+
universe,
|
|
5042
|
+
...accountId ? { accountId } : {},
|
|
5043
|
+
strategyPackage,
|
|
5044
|
+
strategyPackageVersion,
|
|
5045
|
+
strategyDependencyVersions,
|
|
5046
|
+
runtimePackageVersion,
|
|
5047
|
+
strategyConfig,
|
|
5048
|
+
...selection ? { selection } : {}
|
|
5049
|
+
})
|
|
5050
|
+
),
|
|
5051
|
+
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
|
5052
|
+
...deployment.tickers ? { tickers: [...deployment.tickers] } : {}
|
|
5053
|
+
};
|
|
5054
|
+
};
|
|
5055
|
+
|
|
5056
|
+
// src/lib/runtimeEvidenceProducer.ts
|
|
5057
|
+
var import_node_crypto2 = require("crypto");
|
|
5058
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
5059
|
+
var import_node_path = __toESM(require("path"));
|
|
5060
|
+
var isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
5061
|
+
var sha256 = (value) => (0, import_node_crypto2.createHash)("sha256").update(value).digest("hex");
|
|
5062
|
+
var parseRuntimeEvidenceProducer = (value) => {
|
|
5063
|
+
const producer = isRecord2(value) ? value : null;
|
|
5064
|
+
const runtimePackageManifest = isRecord2(producer?.runtimePackageManifest) ? producer.runtimePackageManifest : null;
|
|
5065
|
+
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)) {
|
|
5066
|
+
throw new Error("Runtime evidence producer image identity is invalid");
|
|
5067
|
+
}
|
|
5068
|
+
return producer;
|
|
5069
|
+
};
|
|
5070
|
+
var resolveRuntimeEvidenceProducer = async ({
|
|
5071
|
+
projectRoot,
|
|
5072
|
+
required
|
|
5073
|
+
}) => {
|
|
5074
|
+
const projectSha = String(process.env.TRADEJS_PROJECT_SHA ?? "").trim();
|
|
5075
|
+
const imageDigest = String(
|
|
5076
|
+
process.env.TRADEJS_PROJECT_IMAGE_DIGEST ?? ""
|
|
5077
|
+
).trim();
|
|
5078
|
+
if (!projectSha && !imageDigest && !required) {
|
|
5079
|
+
return null;
|
|
5080
|
+
}
|
|
5081
|
+
if (!/^[a-f0-9]{40}$/.test(projectSha)) {
|
|
5082
|
+
throw new Error(
|
|
5083
|
+
"TRADEJS_PROJECT_SHA must be a full lowercase Git SHA before publishing runtime evidence"
|
|
5084
|
+
);
|
|
5085
|
+
}
|
|
5086
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(imageDigest)) {
|
|
5087
|
+
throw new Error(
|
|
5088
|
+
"TRADEJS_PROJECT_IMAGE_DIGEST must be an immutable sha256 digest before publishing runtime evidence"
|
|
5089
|
+
);
|
|
5090
|
+
}
|
|
5091
|
+
const manifestPath = import_node_path.default.join(projectRoot, "runtime-package-manifest.json");
|
|
5092
|
+
let manifest;
|
|
5093
|
+
try {
|
|
5094
|
+
manifest = await import_promises.default.readFile(manifestPath);
|
|
5095
|
+
} catch (error) {
|
|
5096
|
+
if (!required && error.code === "ENOENT") {
|
|
5097
|
+
return null;
|
|
5098
|
+
}
|
|
5099
|
+
throw new Error(
|
|
5100
|
+
`Runtime package manifest is required for runtime evidence: ${manifestPath}`,
|
|
5101
|
+
{ cause: error }
|
|
5102
|
+
);
|
|
5103
|
+
}
|
|
5104
|
+
return {
|
|
5105
|
+
schemaVersion: 1,
|
|
5106
|
+
projectSha,
|
|
5107
|
+
imageDigest,
|
|
5108
|
+
runtimePackageManifest: {
|
|
5109
|
+
file: "runtime-package-manifest.json",
|
|
5110
|
+
sha256: sha256(manifest)
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
5113
|
+
};
|
|
5114
|
+
|
|
5115
|
+
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
5116
|
+
var SNAPSHOT_FILE = "snapshot.json";
|
|
5117
|
+
var MANIFEST_FILE = "manifest.json";
|
|
5118
|
+
var COMPLETE_FILE = ".complete";
|
|
5119
|
+
var createRuntimeEvidenceCompositionSnapshotRecorder = ({
|
|
5120
|
+
persist,
|
|
5121
|
+
onError
|
|
5122
|
+
}) => {
|
|
5123
|
+
const completed = /* @__PURE__ */ new Set();
|
|
5124
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
5125
|
+
return {
|
|
5126
|
+
observe(compositionId) {
|
|
5127
|
+
if (completed.has(compositionId) || inFlight.has(compositionId)) return;
|
|
5128
|
+
inFlight.add(compositionId);
|
|
5129
|
+
void Promise.resolve().then(() => persist(compositionId)).then(() => completed.add(compositionId)).catch((error) => onError(compositionId, error)).finally(() => inFlight.delete(compositionId));
|
|
5130
|
+
}
|
|
5131
|
+
};
|
|
5132
|
+
};
|
|
5133
|
+
var isRecord3 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
5134
|
+
var sha2562 = (value) => (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
|
|
5135
|
+
var safeSegment = (value, label) => {
|
|
5136
|
+
const normalized = value.trim();
|
|
5137
|
+
if (!normalized || !/^[a-zA-Z0-9._:-]+$/.test(normalized)) {
|
|
5138
|
+
throw new Error(`Invalid runtime evidence snapshot ${label}`);
|
|
5139
|
+
}
|
|
5140
|
+
return normalized;
|
|
5141
|
+
};
|
|
5142
|
+
var isExistingDestinationError = (error) => {
|
|
5143
|
+
const code = error.code;
|
|
5144
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
5145
|
+
};
|
|
5146
|
+
var parseManifest = (value) => {
|
|
5147
|
+
const manifest = isRecord3(value) ? value : null;
|
|
5148
|
+
const payload = isRecord3(manifest?.payload) ? manifest.payload : null;
|
|
5149
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence-composition-snapshot" || typeof manifest.createdAt !== "number" || typeof manifest.userName !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.deploymentCompositionId !== "string" || payload?.file !== SNAPSHOT_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number") {
|
|
5150
|
+
throw new Error("Invalid runtime evidence composition snapshot manifest");
|
|
5151
|
+
}
|
|
5152
|
+
return manifest;
|
|
5153
|
+
};
|
|
5154
|
+
var verifyRuntimeEvidenceCompositionSnapshot = async (bundleDir) => {
|
|
5155
|
+
const [manifestText, payload, completeText] = await Promise.all([
|
|
5156
|
+
import_promises2.default.readFile(import_node_path2.default.join(bundleDir, MANIFEST_FILE), "utf8"),
|
|
5157
|
+
import_promises2.default.readFile(import_node_path2.default.join(bundleDir, SNAPSHOT_FILE)),
|
|
5158
|
+
import_promises2.default.readFile(import_node_path2.default.join(bundleDir, COMPLETE_FILE), "utf8")
|
|
5159
|
+
]);
|
|
5160
|
+
const manifest = parseManifest(JSON.parse(manifestText));
|
|
5161
|
+
if (completeText.trim() !== manifest.deploymentCompositionId) {
|
|
5162
|
+
throw new Error(`Invalid completion marker in ${bundleDir}`);
|
|
5163
|
+
}
|
|
5164
|
+
if (payload.byteLength !== manifest.payload.bytes || sha2562(payload) !== manifest.payload.sha256) {
|
|
5165
|
+
throw new Error(
|
|
5166
|
+
`Runtime evidence snapshot checksum mismatch in ${bundleDir}`
|
|
5167
|
+
);
|
|
5168
|
+
}
|
|
5169
|
+
const value = JSON.parse(payload.toString("utf8"));
|
|
5170
|
+
const record = isRecord3(value) ? value : null;
|
|
5171
|
+
if (record?.schemaVersion !== 1 || record.reportType !== "runtime-evidence-composition-snapshot" || record.userName !== manifest.userName) {
|
|
5172
|
+
throw new Error(
|
|
5173
|
+
`Invalid runtime evidence snapshot payload in ${bundleDir}`
|
|
5174
|
+
);
|
|
5175
|
+
}
|
|
5176
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(record.deployment);
|
|
5177
|
+
const producer = parseRuntimeEvidenceProducer(record.producer);
|
|
5178
|
+
if (deployment.id !== manifest.deploymentId || deployment.deploymentCompositionId !== manifest.deploymentCompositionId) {
|
|
5179
|
+
throw new Error(
|
|
5180
|
+
`Runtime evidence snapshot identity mismatch in ${bundleDir}`
|
|
5181
|
+
);
|
|
5182
|
+
}
|
|
5183
|
+
return { bundleDir, deployment, producer };
|
|
5184
|
+
};
|
|
5185
|
+
var sameSnapshot = (snapshot, deployment, producer) => JSON.stringify(snapshot.deployment) === JSON.stringify(deployment) && JSON.stringify(snapshot.producer) === JSON.stringify(producer);
|
|
5186
|
+
var publishRuntimeEvidenceCompositionSnapshot = async ({
|
|
5187
|
+
evidenceRoot,
|
|
5188
|
+
userName,
|
|
5189
|
+
deployment,
|
|
5190
|
+
producer
|
|
5191
|
+
}) => {
|
|
5192
|
+
const deploymentId = safeSegment(deployment.id, "deployment id");
|
|
5193
|
+
const compositionId = safeSegment(
|
|
5194
|
+
deployment.deploymentCompositionId,
|
|
5195
|
+
"composition id"
|
|
5196
|
+
);
|
|
5197
|
+
const createdAt = Date.now();
|
|
5198
|
+
const snapshot = {
|
|
5199
|
+
schemaVersion: 1,
|
|
5200
|
+
reportType: "runtime-evidence-composition-snapshot",
|
|
5201
|
+
createdAt,
|
|
5202
|
+
userName,
|
|
5203
|
+
deployment,
|
|
5204
|
+
producer
|
|
5205
|
+
};
|
|
5206
|
+
const payload = `${JSON.stringify(snapshot, null, 2)}
|
|
5207
|
+
`;
|
|
5208
|
+
const manifest = {
|
|
5209
|
+
schemaVersion: 1,
|
|
5210
|
+
reportType: "runtime-evidence-composition-snapshot",
|
|
5211
|
+
createdAt,
|
|
5212
|
+
userName,
|
|
5213
|
+
deploymentId,
|
|
5214
|
+
deploymentCompositionId: compositionId,
|
|
5215
|
+
payload: {
|
|
5216
|
+
file: SNAPSHOT_FILE,
|
|
5217
|
+
sha256: sha2562(payload),
|
|
5218
|
+
bytes: Buffer.byteLength(payload)
|
|
5219
|
+
}
|
|
5220
|
+
};
|
|
5221
|
+
const snapshotsRoot = import_node_path2.default.join(evidenceRoot, "snapshots", deploymentId);
|
|
5222
|
+
const bundleDir = import_node_path2.default.join(snapshotsRoot, compositionId);
|
|
5223
|
+
const temporaryDir = import_node_path2.default.join(
|
|
5224
|
+
evidenceRoot,
|
|
5225
|
+
"incoming",
|
|
5226
|
+
`snapshot-${compositionId}.tmp-${(0, import_node_crypto3.randomUUID)()}`
|
|
5227
|
+
);
|
|
5228
|
+
await import_promises2.default.mkdir(temporaryDir, { recursive: true });
|
|
5229
|
+
try {
|
|
5230
|
+
await Promise.all([
|
|
5231
|
+
import_promises2.default.writeFile(import_node_path2.default.join(temporaryDir, SNAPSHOT_FILE), payload, "utf8"),
|
|
5232
|
+
import_promises2.default.writeFile(
|
|
5233
|
+
import_node_path2.default.join(temporaryDir, MANIFEST_FILE),
|
|
5234
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
5235
|
+
`,
|
|
5236
|
+
"utf8"
|
|
5237
|
+
)
|
|
5238
|
+
]);
|
|
5239
|
+
await import_promises2.default.writeFile(
|
|
5240
|
+
import_node_path2.default.join(temporaryDir, COMPLETE_FILE),
|
|
5241
|
+
`${compositionId}
|
|
5242
|
+
`,
|
|
5243
|
+
"utf8"
|
|
5244
|
+
);
|
|
5245
|
+
await import_promises2.default.mkdir(snapshotsRoot, { recursive: true });
|
|
5246
|
+
try {
|
|
5247
|
+
await import_promises2.default.rename(temporaryDir, bundleDir);
|
|
5248
|
+
} catch (error) {
|
|
5249
|
+
if (!isExistingDestinationError(error)) throw error;
|
|
5250
|
+
await import_promises2.default.rm(temporaryDir, { recursive: true, force: true });
|
|
5251
|
+
}
|
|
5252
|
+
} catch (error) {
|
|
5253
|
+
await import_promises2.default.rm(temporaryDir, { recursive: true, force: true });
|
|
5254
|
+
throw error;
|
|
5255
|
+
}
|
|
5256
|
+
const verified = await verifyRuntimeEvidenceCompositionSnapshot(bundleDir);
|
|
5257
|
+
if (!sameSnapshot(verified, deployment, producer)) {
|
|
5258
|
+
throw new Error(
|
|
5259
|
+
`Conflicting runtime evidence snapshot for composition ${compositionId}`
|
|
5260
|
+
);
|
|
5261
|
+
}
|
|
5262
|
+
return verified;
|
|
5263
|
+
};
|
|
5264
|
+
var captureRuntimeEvidenceCompositionSnapshot = async ({
|
|
5265
|
+
projectRoot,
|
|
5266
|
+
userName,
|
|
5267
|
+
deploymentId,
|
|
5268
|
+
expectedCompositionId
|
|
5269
|
+
}) => {
|
|
5270
|
+
const [deployment, producer] = await Promise.all([
|
|
5271
|
+
resolveRuntimeEvidenceDeploymentSnapshot({
|
|
5272
|
+
userName,
|
|
5273
|
+
projectRoot,
|
|
5274
|
+
deploymentId
|
|
5275
|
+
}),
|
|
5276
|
+
resolveRuntimeEvidenceProducer({ projectRoot, required: true })
|
|
5277
|
+
]);
|
|
5278
|
+
if (!producer) {
|
|
5279
|
+
throw new Error("Runtime evidence producer identity is required");
|
|
5280
|
+
}
|
|
5281
|
+
if (deployment.deploymentCompositionId !== expectedCompositionId) {
|
|
5282
|
+
throw new Error(
|
|
5283
|
+
`Runtime deployment composition changed while capturing snapshot: expected ${expectedCompositionId}, received ${deployment.deploymentCompositionId}`
|
|
5284
|
+
);
|
|
5285
|
+
}
|
|
5286
|
+
await publishRuntimeEvidenceCompositionSnapshot({
|
|
5287
|
+
evidenceRoot: import_node_path2.default.join(projectRoot, "data", "runtime-evidence"),
|
|
5288
|
+
userName,
|
|
5289
|
+
deployment,
|
|
5290
|
+
producer
|
|
5291
|
+
});
|
|
5292
|
+
};
|
|
5293
|
+
|
|
4932
5294
|
// src/lib/signals/runner.ts
|
|
4933
5295
|
var SLOW_SIGNALS_WARNING_MS = 10 * 6e4;
|
|
4934
5296
|
var formatDuration2 = (durationMs) => `${(durationMs / 1e3).toFixed(1)}s`;
|
|
@@ -4950,6 +5312,19 @@ var resolveNonNegativeInteger = (value, fallback) => {
|
|
|
4950
5312
|
var createSignalsRunner = (config2) => {
|
|
4951
5313
|
const interval = config2.interval;
|
|
4952
5314
|
const projectRoot = config2.projectRoot?.trim() || String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
5315
|
+
const compositionSnapshotRecorder = process.env.TRADEJS_PROJECT_SHA && process.env.TRADEJS_PROJECT_IMAGE_DIGEST && config2.deploymentId ? createRuntimeEvidenceCompositionSnapshotRecorder({
|
|
5316
|
+
persist: (compositionId) => captureRuntimeEvidenceCompositionSnapshot({
|
|
5317
|
+
projectRoot,
|
|
5318
|
+
userName: config2.userName,
|
|
5319
|
+
deploymentId: config2.deploymentId,
|
|
5320
|
+
expectedCompositionId: compositionId
|
|
5321
|
+
}),
|
|
5322
|
+
onError: (compositionId, error) => import_logger4.logger.warn(
|
|
5323
|
+
"runtime evidence snapshot unavailable; trading continues and the next cycle will retry (composition=%s): %s",
|
|
5324
|
+
compositionId,
|
|
5325
|
+
error instanceof Error ? error.message : String(error)
|
|
5326
|
+
)
|
|
5327
|
+
}) : null;
|
|
4953
5328
|
const resolveSignalsDaemonMaxLiveBars = (runtimeInterval = interval) => {
|
|
4954
5329
|
const intervalMinutes = Number(runtimeInterval);
|
|
4955
5330
|
const preloadBars = Math.ceil(
|
|
@@ -4991,7 +5366,7 @@ var createSignalsRunner = (config2) => {
|
|
|
4991
5366
|
return connectorName;
|
|
4992
5367
|
};
|
|
4993
5368
|
const createSignalsSession2 = async (lifecycle, scope = {}) => {
|
|
4994
|
-
const deployment = config2.deploymentId ? await (0,
|
|
5369
|
+
const deployment = config2.deploymentId ? await (0, import_runtimeStrategies3.getRuntimeDeployment)({
|
|
4995
5370
|
userName: config2.userName,
|
|
4996
5371
|
projectRoot,
|
|
4997
5372
|
deploymentId: config2.deploymentId
|
|
@@ -5492,7 +5867,7 @@ var createSignalsRunner = (config2) => {
|
|
|
5492
5867
|
if (!config2.deploymentId) {
|
|
5493
5868
|
throw new Error("Runtime deployment id is required");
|
|
5494
5869
|
}
|
|
5495
|
-
const configuredDeployment = await (0,
|
|
5870
|
+
const configuredDeployment = await (0, import_runtimeStrategies3.getRuntimeDeployment)({
|
|
5496
5871
|
userName: config2.userName,
|
|
5497
5872
|
projectRoot,
|
|
5498
5873
|
deploymentId: config2.deploymentId
|
|
@@ -5526,7 +5901,7 @@ var createSignalsRunner = (config2) => {
|
|
|
5526
5901
|
throw new Error("Runtime deployment id is required");
|
|
5527
5902
|
}
|
|
5528
5903
|
const deploymentId = config2.deploymentId;
|
|
5529
|
-
const initialDeployment = await (0,
|
|
5904
|
+
const initialDeployment = await (0, import_runtimeStrategies3.getRuntimeDeployment)({
|
|
5530
5905
|
userName: config2.userName,
|
|
5531
5906
|
projectRoot,
|
|
5532
5907
|
deploymentId
|
|
@@ -5551,7 +5926,7 @@ var createSignalsRunner = (config2) => {
|
|
|
5551
5926
|
settleDelayMs: resolveNonNegativeInteger(config2.settleDelayMs, 5e3),
|
|
5552
5927
|
signal: abortController.signal,
|
|
5553
5928
|
runCycle: async () => {
|
|
5554
|
-
const currentDeployment = await (0,
|
|
5929
|
+
const currentDeployment = await (0, import_runtimeStrategies3.getRuntimeDeployment)({
|
|
5555
5930
|
userName: config2.userName,
|
|
5556
5931
|
projectRoot,
|
|
5557
5932
|
deploymentId
|
|
@@ -5559,6 +5934,9 @@ var createSignalsRunner = (config2) => {
|
|
|
5559
5934
|
if (!currentDeployment) {
|
|
5560
5935
|
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
5561
5936
|
}
|
|
5937
|
+
compositionSnapshotRecorder?.observe(
|
|
5938
|
+
currentDeployment.deploymentCompositionId
|
|
5939
|
+
);
|
|
5562
5940
|
const scopes = await loadConfiguredSignalsScopes(currentDeployment);
|
|
5563
5941
|
for (const [key, staleSession] of sessions) {
|
|
5564
5942
|
if (scopes.has(key)) continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.27-beta.
|
|
3
|
+
"version": "3.1.27-beta.250",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"tradejs": "dist/cli.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@tradejs/connectors": "^3.1.27-beta.
|
|
40
|
-
"@tradejs/core": "^3.1.27-beta.
|
|
41
|
-
"@tradejs/indicators": "^3.1.27-beta.
|
|
42
|
-
"@tradejs/infra": "^3.1.27-beta.
|
|
43
|
-
"@tradejs/node": "^3.1.27-beta.
|
|
39
|
+
"@tradejs/connectors": "^3.1.27-beta.250",
|
|
40
|
+
"@tradejs/core": "^3.1.27-beta.250",
|
|
41
|
+
"@tradejs/indicators": "^3.1.27-beta.250",
|
|
42
|
+
"@tradejs/infra": "^3.1.27-beta.250",
|
|
43
|
+
"@tradejs/node": "^3.1.27-beta.250",
|
|
44
44
|
"@tradejs/strategy-kit": "3.0.4",
|
|
45
|
-
"@tradejs/types": "^3.1.27-beta.
|
|
45
|
+
"@tradejs/types": "^3.1.27-beta.250",
|
|
46
46
|
"args": "^5.0.3",
|
|
47
47
|
"bcryptjs": "^2.4.3",
|
|
48
48
|
"chalk": "4.1.2",
|