@tradejs/cli 1.0.5 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/cli.js +13791 -7652
- package/dist/lib/aiTrainMetrics.js +173 -0
- package/dist/lib/candlesProviderMigration.js +266 -0
- package/dist/lib/cliArgs.js +40 -0
- package/dist/lib/derivativesContextBackfill.js +487 -0
- package/dist/lib/researchAgent.js +195 -0
- package/dist/lib/runtimeParity.js +234 -0
- package/dist/lib/telegramReports.js +91 -0
- package/dist/lib/timeWindow.js +101 -0
- package/dist/scripts/agentRun.js +895 -0
- package/dist/scripts/aiExport.js +192 -0
- package/dist/scripts/aiExportSelect.js +135 -0
- package/dist/scripts/aiTrain.js +2321 -0
- package/dist/scripts/backtest.js +998 -111
- package/dist/scripts/candlesMigrateProvider.js +5302 -0
- package/dist/scripts/continuity.js +1 -1
- package/dist/scripts/derivativesIngest.js +5 -0
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +21 -12
- package/dist/scripts/migration.js +1 -1
- package/dist/scripts/mlExport.js +112 -13
- package/dist/scripts/mlExportSelect.js +43 -9
- package/dist/scripts/mlTrainLatestSelect.js +4 -3
- package/dist/scripts/researchAuto.js +845 -0
- package/dist/scripts/resolveExportStrategy.js +133 -0
- package/dist/scripts/results.js +46 -22
- package/dist/scripts/runtimeParity.js +1651 -0
- package/dist/scripts/selectStrategy.js +4 -3
- package/dist/scripts/signals.js +799 -62
- package/dist/scripts/signalsSummary.js +655 -0
- package/dist/scripts/spawnSiblingScript.js +71 -0
- package/dist/scripts/user-add.js +0 -9
- package/dist/workers/testerWorker.js +13 -2
- package/package.json +18 -12
|
@@ -160,7 +160,7 @@ var continuity = async () => {
|
|
|
160
160
|
(0, import_time.formatUnix)(gap.ts),
|
|
161
161
|
gap.diffSeconds
|
|
162
162
|
);
|
|
163
|
-
await (0, import_timescale.deleteCandles)(symbol, interval);
|
|
163
|
+
await (0, import_timescale.deleteCandles)(provider.id, symbol, interval);
|
|
164
164
|
const reloaded = await connector.kline({
|
|
165
165
|
symbol,
|
|
166
166
|
interval: intervalKey,
|
|
@@ -28,6 +28,7 @@ var import_args = __toESM(require("args"));
|
|
|
28
28
|
var import_chalk = __toESM(require("chalk"));
|
|
29
29
|
var import_indicators = require("@tradejs/core/indicators");
|
|
30
30
|
var import_timescale = require("@tradejs/infra/timescale");
|
|
31
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
31
32
|
var import_connectors = require("@tradejs/connectors");
|
|
32
33
|
import_args.default.example(
|
|
33
34
|
"yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m,1h --days 120",
|
|
@@ -41,6 +42,7 @@ import_args.default.option(
|
|
|
41
42
|
"Provider name: coinalyze | binance_coinbase_spread",
|
|
42
43
|
"coinalyze"
|
|
43
44
|
);
|
|
45
|
+
import_args.default.option(["U", "user"], "User settings profile name from Redis", "root");
|
|
44
46
|
import_args.default.option(["b", "batchDays"], "Request chunk size in days", 7);
|
|
45
47
|
var flags = import_args.default.parse(process.argv);
|
|
46
48
|
var asInt = (value, fallback) => {
|
|
@@ -59,6 +61,8 @@ var run = async () => {
|
|
|
59
61
|
);
|
|
60
62
|
const days = asInt(flags.days, 120);
|
|
61
63
|
const batchDays = asInt(flags.batchDays, 7);
|
|
64
|
+
const userName = String(flags.user || "root").trim() || "root";
|
|
65
|
+
const coinalyzeApiKey = providerName === "coinalyze" ? (await (0, import_userSettings.getUserSettings)(userName)).COINALYZE_API_KEY : void 0;
|
|
62
66
|
if (!symbols.length) throw new Error("No symbols provided");
|
|
63
67
|
if (!intervals.length) throw new Error("No intervals provided");
|
|
64
68
|
await (0, import_timescale.waitForDbReady)();
|
|
@@ -76,6 +80,7 @@ var run = async () => {
|
|
|
76
80
|
);
|
|
77
81
|
const window = await provider.fetchWindow({
|
|
78
82
|
symbol,
|
|
83
|
+
apiKey: coinalyzeApiKey,
|
|
79
84
|
interval,
|
|
80
85
|
fromMs: cursor,
|
|
81
86
|
toMs
|
|
@@ -31,6 +31,7 @@ var import_lodash = __toESM(require("lodash"));
|
|
|
31
31
|
var import_connectors = require("@tradejs/connectors");
|
|
32
32
|
var import_indicators = require("@tradejs/core/indicators");
|
|
33
33
|
var import_async = require("@tradejs/core/async");
|
|
34
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
34
35
|
var import_cli = require("@tradejs/node/cli");
|
|
35
36
|
var import_timescale = require("@tradejs/infra/timescale");
|
|
36
37
|
var coinalyzeIntervalMap = {
|
|
@@ -41,7 +42,7 @@ import_args.default.example(
|
|
|
41
42
|
"yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m,1h",
|
|
42
43
|
"Fetch derivatives for all getTickers symbols matched to Coinalyze markets"
|
|
43
44
|
);
|
|
44
|
-
import_args.default.option(["U", "user"], "
|
|
45
|
+
import_args.default.option(["U", "user"], "User settings profile name from Redis", "root");
|
|
45
46
|
import_args.default.option(["t", "tickers"], "Comma-separated include symbols");
|
|
46
47
|
import_args.default.option(["e", "exclude"], "Comma-separated exclude symbols");
|
|
47
48
|
import_args.default.option(["l", "tickersLimit"], "Tickers limit");
|
|
@@ -76,14 +77,10 @@ var asInt = (value, fallback) => {
|
|
|
76
77
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
77
78
|
};
|
|
78
79
|
var parseList = (value) => String(value ?? "").split(",").map((item) => item.trim().toUpperCase()).filter(Boolean);
|
|
79
|
-
var apiKey = process.env.COINALYZE_API_KEY?.trim();
|
|
80
|
-
if (!apiKey) {
|
|
81
|
-
throw new Error("Missing COINALYZE_API_KEY");
|
|
82
|
-
}
|
|
83
80
|
var coinalyzeBaseUrl = process.env.COINALYZE_BASE_URL?.trim() || "https://api.coinalyze.net/v1";
|
|
84
81
|
var coinalyzeMaxRetries = asInt(process.env.COINALYZE_MAX_RETRIES, 4);
|
|
85
82
|
var lastRequestTs = 0;
|
|
86
|
-
var fetchJsonWithRateLimit = async (url) => {
|
|
83
|
+
var fetchJsonWithRateLimit = async (url, apiKey) => {
|
|
87
84
|
const requestDelayMs = Math.max(100, asInt(flags.requestDelayMs, 200));
|
|
88
85
|
const requestTimeoutMs = Math.max(
|
|
89
86
|
5e3,
|
|
@@ -135,9 +132,10 @@ var fetchJsonWithRateLimit = async (url) => {
|
|
|
135
132
|
}
|
|
136
133
|
throw new Error("Coinalyze request failed after retries");
|
|
137
134
|
};
|
|
138
|
-
var fetchCoinalyzeMarkets = async () => {
|
|
135
|
+
var fetchCoinalyzeMarkets = async (apiKey) => {
|
|
139
136
|
const raw = await fetchJsonWithRateLimit(
|
|
140
|
-
`${coinalyzeBaseUrl}/future-markets
|
|
137
|
+
`${coinalyzeBaseUrl}/future-markets`,
|
|
138
|
+
apiKey
|
|
141
139
|
);
|
|
142
140
|
return Array.isArray(raw) ? raw : [];
|
|
143
141
|
};
|
|
@@ -220,16 +218,17 @@ var toSeriesMap = (raw, metric) => {
|
|
|
220
218
|
return out;
|
|
221
219
|
};
|
|
222
220
|
var fetchMetricBatch = async (params) => {
|
|
223
|
-
const { endpoint, metric, marketSymbols, interval, fromMs, toMs } = params;
|
|
221
|
+
const { endpoint, metric, marketSymbols, apiKey, interval, fromMs, toMs } = params;
|
|
224
222
|
const url = new URL(`${coinalyzeBaseUrl}${endpoint}`);
|
|
225
223
|
url.searchParams.set("symbols", marketSymbols.join(","));
|
|
226
224
|
url.searchParams.set("interval", coinalyzeIntervalMap[interval] || interval);
|
|
227
225
|
url.searchParams.set("from", String(Math.floor(fromMs / 1e3)));
|
|
228
226
|
url.searchParams.set("to", String(Math.floor(toMs / 1e3)));
|
|
229
|
-
const raw = await fetchJsonWithRateLimit(url.toString());
|
|
227
|
+
const raw = await fetchJsonWithRateLimit(url.toString(), apiKey);
|
|
230
228
|
return toSeriesMap(raw, metric);
|
|
231
229
|
};
|
|
232
230
|
var run = async () => {
|
|
231
|
+
const userName = String(flags.user || "root").trim() || "root";
|
|
233
232
|
const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
|
|
234
233
|
flags.intervals
|
|
235
234
|
);
|
|
@@ -239,9 +238,16 @@ var run = async () => {
|
|
|
239
238
|
const tickersLimit = flags.tickersLimit !== void 0 ? asInt(flags.tickersLimit, 0) || void 0 : void 0;
|
|
240
239
|
const exchangePriority = parseList(flags.exchangePriority || "A,6,0");
|
|
241
240
|
if (!intervals.length) throw new Error("No intervals provided");
|
|
241
|
+
const settings = await (0, import_userSettings.getUserSettings)(userName);
|
|
242
|
+
const coinalyzeApiKey = settings.COINALYZE_API_KEY.trim();
|
|
243
|
+
if (!coinalyzeApiKey) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Missing COINALYZE_API_KEY in user settings for user ${userName}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
242
248
|
const connectorFactory = import_connectors.connectors[import_connectors.ConnectorNames.ByBit];
|
|
243
249
|
const bybit = await connectorFactory({
|
|
244
|
-
userName
|
|
250
|
+
userName
|
|
245
251
|
});
|
|
246
252
|
const tickers = await (0, import_cli.getTickers)(
|
|
247
253
|
bybit,
|
|
@@ -253,7 +259,7 @@ var run = async () => {
|
|
|
253
259
|
if (!tickers.length) {
|
|
254
260
|
throw new Error("No tickers loaded via getTickers");
|
|
255
261
|
}
|
|
256
|
-
const markets = await fetchCoinalyzeMarkets();
|
|
262
|
+
const markets = await fetchCoinalyzeMarkets(coinalyzeApiKey);
|
|
257
263
|
if (!markets.length) {
|
|
258
264
|
throw new Error("No markets returned by Coinalyze /future-markets");
|
|
259
265
|
}
|
|
@@ -321,6 +327,7 @@ var run = async () => {
|
|
|
321
327
|
endpoint: oiPath,
|
|
322
328
|
metric: "oi",
|
|
323
329
|
marketSymbols,
|
|
330
|
+
apiKey: coinalyzeApiKey,
|
|
324
331
|
interval,
|
|
325
332
|
fromMs: cursor,
|
|
326
333
|
toMs
|
|
@@ -329,6 +336,7 @@ var run = async () => {
|
|
|
329
336
|
endpoint: fundingPath,
|
|
330
337
|
metric: "funding",
|
|
331
338
|
marketSymbols,
|
|
339
|
+
apiKey: coinalyzeApiKey,
|
|
332
340
|
interval,
|
|
333
341
|
fromMs: cursor,
|
|
334
342
|
toMs
|
|
@@ -337,6 +345,7 @@ var run = async () => {
|
|
|
337
345
|
endpoint: liqPath,
|
|
338
346
|
metric: "liq",
|
|
339
347
|
marketSymbols,
|
|
348
|
+
apiKey: coinalyzeApiKey,
|
|
340
349
|
interval,
|
|
341
350
|
fromMs: cursor,
|
|
342
351
|
toMs
|
|
@@ -43,7 +43,7 @@ var migrateFile = async (file) => {
|
|
|
43
43
|
[],
|
|
44
44
|
projectRoot
|
|
45
45
|
);
|
|
46
|
-
const rows = (0, import_timescale.toRows)(symbol, interval, data);
|
|
46
|
+
const rows = (0, import_timescale.toRows)("bybit", symbol, interval, data);
|
|
47
47
|
for (let i = 0; i < rows.length; i += BATCH) {
|
|
48
48
|
await (0, import_timescale.upsertCandles)(rows.slice(i, i + BATCH));
|
|
49
49
|
}
|
package/dist/scripts/mlExport.js
CHANGED
|
@@ -24,10 +24,106 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
|
|
25
25
|
// src/scripts/mlExport.ts
|
|
26
26
|
var import_args = __toESM(require("args"));
|
|
27
|
-
var
|
|
27
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
28
28
|
var import_promises = __toESM(require("fs/promises"));
|
|
29
29
|
var import_path = __toESM(require("path"));
|
|
30
30
|
var import_ml = require("@tradejs/infra/ml");
|
|
31
|
+
|
|
32
|
+
// src/scripts/selectStrategy.ts
|
|
33
|
+
var import_readline = __toESM(require("readline"));
|
|
34
|
+
var import_chalk = __toESM(require("chalk"));
|
|
35
|
+
var import_strategies = require("@tradejs/node/strategies");
|
|
36
|
+
var defaultStrategy = "TrendLine";
|
|
37
|
+
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
38
|
+
var getStrategyChoices = async () => {
|
|
39
|
+
try {
|
|
40
|
+
const loaded = await (0, import_strategies.getAvailableStrategyNames)(projectRoot);
|
|
41
|
+
if (loaded.length) {
|
|
42
|
+
return loaded;
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.warn(`Failed to load strategy list: ${String(error)}`);
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
"Breakout",
|
|
49
|
+
"MaStrategy",
|
|
50
|
+
"AdaptiveMomentumRibbon",
|
|
51
|
+
"TrendLine",
|
|
52
|
+
"VolumeDivergence"
|
|
53
|
+
];
|
|
54
|
+
};
|
|
55
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
56
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
57
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
58
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
59
|
+
if (!process.stdin.isTTY) {
|
|
60
|
+
return fallbackStrategy;
|
|
61
|
+
}
|
|
62
|
+
console.log(import_chalk.default.cyan("Available strategies:"));
|
|
63
|
+
strategies.forEach((name, index) => {
|
|
64
|
+
const isDefault = name === defaultStrategy;
|
|
65
|
+
const label = isDefault ? import_chalk.default.green(name) : name;
|
|
66
|
+
const suffix = isDefault ? import_chalk.default.gray(" (default)") : "";
|
|
67
|
+
console.log(` ${import_chalk.default.yellow(String(index + 1))}) ${label}${suffix}`);
|
|
68
|
+
});
|
|
69
|
+
const rl = import_readline.default.createInterface({
|
|
70
|
+
input: process.stdin,
|
|
71
|
+
output: process.stdout
|
|
72
|
+
});
|
|
73
|
+
const question = (text) => new Promise((resolve) => rl.question(text, resolve));
|
|
74
|
+
const answer = await question(
|
|
75
|
+
`${promptLabel} [${import_chalk.default.green(fallbackStrategy)}]: `
|
|
76
|
+
);
|
|
77
|
+
rl.close();
|
|
78
|
+
const trimmed = answer.trim();
|
|
79
|
+
if (!trimmed) {
|
|
80
|
+
return fallbackStrategy;
|
|
81
|
+
}
|
|
82
|
+
const asNumber = Number(trimmed);
|
|
83
|
+
if (Number.isFinite(asNumber) && asNumber >= 1 && asNumber <= strategies.length) {
|
|
84
|
+
return strategies[asNumber - 1];
|
|
85
|
+
}
|
|
86
|
+
const byName = strategies.find(
|
|
87
|
+
(name) => name.toLowerCase() === trimmed.toLowerCase()
|
|
88
|
+
);
|
|
89
|
+
if (byName) {
|
|
90
|
+
return byName;
|
|
91
|
+
}
|
|
92
|
+
console.warn(`Unknown strategy "${trimmed}", using ${fallbackStrategy}.`);
|
|
93
|
+
return fallbackStrategy;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/scripts/resolveExportStrategy.ts
|
|
97
|
+
var resolveExportStrategy = async ({
|
|
98
|
+
explicitStrategy,
|
|
99
|
+
outDir,
|
|
100
|
+
datasetLabel,
|
|
101
|
+
promptLabel,
|
|
102
|
+
listStrategies
|
|
103
|
+
}) => {
|
|
104
|
+
const raw = String(explicitStrategy || "").trim();
|
|
105
|
+
if (raw) {
|
|
106
|
+
return raw;
|
|
107
|
+
}
|
|
108
|
+
const availableStrategies = await listStrategies({ outDir });
|
|
109
|
+
if (!availableStrategies.length) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
if (availableStrategies.length === 1) {
|
|
113
|
+
return availableStrategies[0];
|
|
114
|
+
}
|
|
115
|
+
if (!process.stdin.isTTY) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Multiple ${datasetLabel} chunk strategies found in ${outDir}: ${availableStrategies.join(", ")}. Pass --strategy.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return selectStrategy(promptLabel, {
|
|
121
|
+
strategies: availableStrategies,
|
|
122
|
+
defaultStrategy: availableStrategies[0]
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/scripts/mlExport.ts
|
|
31
127
|
import_args.default.example(
|
|
32
128
|
"yarn ts-node ./src/scripts/mlExport --strategy trendline",
|
|
33
129
|
"Merge per-worker ML chunks into one dataset JSONL"
|
|
@@ -45,21 +141,24 @@ var listChunkFiles = async (outDir, strategyName) => {
|
|
|
45
141
|
const entries = await import_promises.default.readdir(outDir, { withFileTypes: true });
|
|
46
142
|
return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).map((name) => import_path.default.join(outDir, name)).sort();
|
|
47
143
|
};
|
|
48
|
-
var resolveStrategyName = async () => {
|
|
49
|
-
const raw = String(flags.strategy || "").trim();
|
|
50
|
-
if (raw) {
|
|
51
|
-
return raw;
|
|
52
|
-
}
|
|
53
|
-
throw new Error("Missing --strategy. Use mlExportSelect or pass --strategy.");
|
|
54
|
-
};
|
|
55
144
|
var main = async () => {
|
|
56
145
|
const outDir = String(flags.outDir || "data/ml/export");
|
|
57
|
-
const strategyName = await resolveStrategyName();
|
|
58
146
|
await import_promises.default.mkdir(outDir, { recursive: true });
|
|
147
|
+
const strategyName = await resolveExportStrategy({
|
|
148
|
+
explicitStrategy: String(flags.strategy || ""),
|
|
149
|
+
outDir,
|
|
150
|
+
datasetLabel: "ML",
|
|
151
|
+
promptLabel: "Select ML export strategy",
|
|
152
|
+
listStrategies: import_ml.listMlChunkStrategies
|
|
153
|
+
});
|
|
154
|
+
if (!strategyName) {
|
|
155
|
+
console.log(import_chalk2.default.yellow(`No ML chunk files found in ${outDir}`));
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
59
158
|
const chunkFiles = await listChunkFiles(outDir, strategyName);
|
|
60
159
|
if (!chunkFiles.length) {
|
|
61
160
|
console.log(
|
|
62
|
-
|
|
161
|
+
import_chalk2.default.yellow(
|
|
63
162
|
`No chunk files found for strategy "${strategyName}" in ${outDir}`
|
|
64
163
|
)
|
|
65
164
|
);
|
|
@@ -79,9 +178,9 @@ var main = async () => {
|
|
|
79
178
|
await import_promises.default.rm(filePath, { force: true });
|
|
80
179
|
}
|
|
81
180
|
}
|
|
82
|
-
console.log(
|
|
181
|
+
console.log(import_chalk2.default.green(`Merged dataset saved: ${mergedPath}`));
|
|
83
182
|
console.log(
|
|
84
|
-
|
|
183
|
+
import_chalk2.default.gray(
|
|
85
184
|
`strategy=${strategyName}, source_chunks=${chunkFiles.length}, deleteChunks=${Boolean(
|
|
86
185
|
shouldDeleteChunks
|
|
87
186
|
)}`
|
|
@@ -90,6 +189,6 @@ var main = async () => {
|
|
|
90
189
|
process.exit(0);
|
|
91
190
|
};
|
|
92
191
|
main().catch((error) => {
|
|
93
|
-
console.error(
|
|
192
|
+
console.error(import_chalk2.default.red(error?.message || String(error)));
|
|
94
193
|
process.exit(1);
|
|
95
194
|
});
|
|
@@ -22,9 +22,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
mod
|
|
23
23
|
));
|
|
24
24
|
|
|
25
|
-
// src/scripts/mlExportSelect.ts
|
|
26
|
-
var import_child_process = require("child_process");
|
|
27
|
-
|
|
28
25
|
// src/scripts/selectStrategy.ts
|
|
29
26
|
var import_readline = __toESM(require("readline"));
|
|
30
27
|
var import_chalk = __toESM(require("chalk"));
|
|
@@ -48,9 +45,10 @@ var getStrategyChoices = async () => {
|
|
|
48
45
|
"VolumeDivergence"
|
|
49
46
|
];
|
|
50
47
|
};
|
|
51
|
-
var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
52
|
-
const strategies = await getStrategyChoices();
|
|
53
|
-
const
|
|
48
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
49
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
50
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
51
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
54
52
|
if (!process.stdin.isTTY) {
|
|
55
53
|
return fallbackStrategy;
|
|
56
54
|
}
|
|
@@ -88,12 +86,48 @@ var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
|
88
86
|
return fallbackStrategy;
|
|
89
87
|
};
|
|
90
88
|
|
|
89
|
+
// src/scripts/spawnSiblingScript.ts
|
|
90
|
+
var import_fs = __toESM(require("fs"));
|
|
91
|
+
var import_path = __toESM(require("path"));
|
|
92
|
+
var import_child_process = require("child_process");
|
|
93
|
+
var spawnSiblingScript = (currentDir, scriptBaseName, extraArgs) => {
|
|
94
|
+
const searchDirs = [currentDir, import_path.default.resolve(currentDir, "scripts")];
|
|
95
|
+
const candidates = searchDirs.flatMap((dir) => [
|
|
96
|
+
import_path.default.resolve(dir, `${scriptBaseName}.js`),
|
|
97
|
+
import_path.default.resolve(dir, `${scriptBaseName}.ts`)
|
|
98
|
+
]);
|
|
99
|
+
const scriptPath = candidates.find((candidate) => import_fs.default.existsSync(candidate));
|
|
100
|
+
if (!scriptPath) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Script "${scriptBaseName}" not found. Checked: ${candidates.join(", ")}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const commandArgs = scriptPath.endsWith(".ts") ? [
|
|
106
|
+
"-r",
|
|
107
|
+
"ts-node/register",
|
|
108
|
+
"-r",
|
|
109
|
+
"tsconfig-paths/register",
|
|
110
|
+
scriptPath,
|
|
111
|
+
...extraArgs
|
|
112
|
+
] : [scriptPath, ...extraArgs];
|
|
113
|
+
const result = (0, import_child_process.spawnSync)(process.execPath, commandArgs, {
|
|
114
|
+
env: process.env,
|
|
115
|
+
stdio: "inherit"
|
|
116
|
+
});
|
|
117
|
+
if (result.error) {
|
|
118
|
+
throw result.error;
|
|
119
|
+
}
|
|
120
|
+
return result.status ?? 1;
|
|
121
|
+
};
|
|
122
|
+
|
|
91
123
|
// src/scripts/mlExportSelect.ts
|
|
92
124
|
var run = async () => {
|
|
93
125
|
const selected = await selectStrategy();
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
126
|
+
const status = spawnSiblingScript(__dirname, "mlExport", [
|
|
127
|
+
"--strategy",
|
|
128
|
+
selected
|
|
129
|
+
]);
|
|
130
|
+
process.exit(status);
|
|
97
131
|
};
|
|
98
132
|
run().catch((err) => {
|
|
99
133
|
console.error("Failed to select strategy:", err);
|
|
@@ -56,9 +56,10 @@ var getStrategyChoices = async () => {
|
|
|
56
56
|
"VolumeDivergence"
|
|
57
57
|
];
|
|
58
58
|
};
|
|
59
|
-
var selectStrategy = async (promptLabel = "Select strategy") => {
|
|
60
|
-
const strategies = await getStrategyChoices();
|
|
61
|
-
const
|
|
59
|
+
var selectStrategy = async (promptLabel = "Select strategy", options) => {
|
|
60
|
+
const strategies = options?.strategies && options.strategies.length ? options.strategies : await getStrategyChoices();
|
|
61
|
+
const preferredDefault = options?.defaultStrategy || defaultStrategy;
|
|
62
|
+
const fallbackStrategy = strategies.includes(preferredDefault) ? preferredDefault : strategies[0];
|
|
62
63
|
if (!process.stdin.isTTY) {
|
|
63
64
|
return fallbackStrategy;
|
|
64
65
|
}
|