@tradejs/cli 2.0.6 → 2.0.7

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.
@@ -1641,6 +1641,11 @@ __export(aiExport_exports, {
1641
1641
  module.exports = __toCommonJS(aiExport_exports);
1642
1642
  var import_args = __toESM(require("args"));
1643
1643
  var import_chalk2 = __toESM(require("chalk"));
1644
+ var import_promises2 = __toESM(require("fs/promises"));
1645
+ var import_progress = __toESM(require("progress"));
1646
+ var import_ai2 = require("@tradejs/infra/ai");
1647
+
1648
+ // src/lib/aiExport.ts
1644
1649
  var import_promises = __toESM(require("fs/promises"));
1645
1650
  var import_path = __toESM(require("path"));
1646
1651
  var import_ai = require("@tradejs/infra/ai");
@@ -1684,6 +1689,139 @@ var loadBacktestCheckpointResults = async ({
1684
1689
  import_redis.redisKeys.backtestRunResults(userName, runId)
1685
1690
  );
1686
1691
 
1692
+ // src/lib/aiExport.ts
1693
+ var resolveRunScopedAiChunks = async ({
1694
+ outDir,
1695
+ requestedRunId,
1696
+ strategyName,
1697
+ userName
1698
+ }) => {
1699
+ const resolvedRunId = String(requestedRunId || "").trim();
1700
+ const runIds = resolvedRunId ? [resolvedRunId] : await (0, import_ai.listAiChunkRunIds)({ strategyName, outDir });
1701
+ const runId = runIds.at(-1) ?? "";
1702
+ if (!runId) {
1703
+ return null;
1704
+ }
1705
+ const chunkFiles = await (0, import_ai.listAiChunkFiles)({ strategyName, outDir, runId });
1706
+ if (!chunkFiles.length) {
1707
+ return {
1708
+ runId,
1709
+ chunkFiles,
1710
+ completedAttemptKeys: /* @__PURE__ */ new Set()
1711
+ };
1712
+ }
1713
+ const completed = await loadBacktestCheckpointResults({ runId, userName });
1714
+ return {
1715
+ runId,
1716
+ chunkFiles,
1717
+ completedAttemptKeys: buildCompletedBacktestDatasetAttemptKeys(completed)
1718
+ };
1719
+ };
1720
+ var exportAiStrategy = async (params) => {
1721
+ const {
1722
+ outDir,
1723
+ strategyName,
1724
+ keepChunks,
1725
+ requestedRunId,
1726
+ userName,
1727
+ now = Date.now
1728
+ } = params;
1729
+ const partMonths = Math.max(0, Math.trunc(Number(params.partMonths) || 0));
1730
+ const runScopedChunks = await resolveRunScopedAiChunks({
1731
+ outDir,
1732
+ requestedRunId,
1733
+ strategyName,
1734
+ userName
1735
+ });
1736
+ const chunkFiles = runScopedChunks ? runScopedChunks.chunkFiles : await (0, import_ai.listAiChunkFiles)({ strategyName, outDir });
1737
+ if (!chunkFiles.length) {
1738
+ return null;
1739
+ }
1740
+ if (runScopedChunks && runScopedChunks.completedAttemptKeys.size === 0) {
1741
+ throw new Error(
1742
+ `No completed checkpoint attempts found for AI export run "${runScopedChunks.runId}"`
1743
+ );
1744
+ }
1745
+ const completedAttemptCount = runScopedChunks?.completedAttemptKeys.size ?? void 0;
1746
+ const mergedPath = import_path.default.join(
1747
+ outDir,
1748
+ `ai-dataset-${(0, import_ai.toFileToken)(strategyName)}-merged-${now()}.jsonl`
1749
+ );
1750
+ await (0, import_ai.mergeAiJsonlFiles)({
1751
+ filePaths: chunkFiles,
1752
+ outPath: mergedPath,
1753
+ shouldIncludeRow: runScopedChunks ? (row) => isBacktestDatasetRowForCompletedAttempt(
1754
+ row,
1755
+ runScopedChunks.completedAttemptKeys
1756
+ ) : void 0
1757
+ });
1758
+ runScopedChunks?.completedAttemptKeys.clear();
1759
+ const splitResult = partMonths > 0 ? await (0, import_ai.splitAiMergedDatasetFile)({
1760
+ filePath: mergedPath,
1761
+ monthsPerPart: partMonths
1762
+ }) : {
1763
+ partPaths: [mergedPath],
1764
+ partCount: 1,
1765
+ splitApplied: false
1766
+ };
1767
+ const shouldDeleteChunks = !keepChunks;
1768
+ if (shouldDeleteChunks) {
1769
+ for (const filePath of chunkFiles) {
1770
+ await import_promises.default.rm(filePath, { force: true });
1771
+ }
1772
+ }
1773
+ return {
1774
+ strategyName,
1775
+ sourceChunkCount: chunkFiles.length,
1776
+ deleteChunks: shouldDeleteChunks,
1777
+ partMonths,
1778
+ partPaths: splitResult.partPaths,
1779
+ partCount: splitResult.partCount,
1780
+ splitApplied: splitResult.splitApplied,
1781
+ runId: runScopedChunks?.runId,
1782
+ completedAttemptCount
1783
+ };
1784
+ };
1785
+ var exportAiStrategiesSequentially = async (params, dependencies = {}) => {
1786
+ const { strategyNames, onProgress, ...strategyParams } = params;
1787
+ const runExport = dependencies.exportStrategy ?? exportAiStrategy;
1788
+ const results = [];
1789
+ const total = strategyNames.length;
1790
+ for (let index = 0; index < strategyNames.length; index += 1) {
1791
+ const strategyName = strategyNames[index];
1792
+ onProgress?.({
1793
+ strategyName,
1794
+ current: index,
1795
+ total,
1796
+ status: "started"
1797
+ });
1798
+ try {
1799
+ const result = await runExport({
1800
+ ...strategyParams,
1801
+ strategyName
1802
+ });
1803
+ if (result) {
1804
+ results.push(result);
1805
+ }
1806
+ onProgress?.({
1807
+ strategyName,
1808
+ current: index + 1,
1809
+ total,
1810
+ status: result ? "completed" : "skipped"
1811
+ });
1812
+ } catch (error) {
1813
+ onProgress?.({
1814
+ strategyName,
1815
+ current: index,
1816
+ total,
1817
+ status: "failed"
1818
+ });
1819
+ throw error;
1820
+ }
1821
+ }
1822
+ return results;
1823
+ };
1824
+
1687
1825
  // src/scripts/selectStrategy.ts
1688
1826
  var import_readline = __toESM(require("readline"));
1689
1827
  var import_chalk = __toESM(require("chalk"));
@@ -1750,12 +1888,14 @@ var selectStrategy = async (promptLabel = "Select strategy", options) => {
1750
1888
  };
1751
1889
 
1752
1890
  // src/scripts/resolveExportStrategy.ts
1891
+ var ALL_EXPORT_STRATEGIES = "all";
1753
1892
  var resolveExportStrategy = async ({
1754
1893
  explicitStrategy,
1755
1894
  outDir,
1756
1895
  datasetLabel,
1757
1896
  promptLabel,
1758
- listStrategies
1897
+ listStrategies,
1898
+ includeAllOption = false
1759
1899
  }) => {
1760
1900
  const raw = String(explicitStrategy || "").trim();
1761
1901
  if (raw) {
@@ -1773,8 +1913,9 @@ var resolveExportStrategy = async ({
1773
1913
  `Multiple ${datasetLabel} chunk strategies found in ${outDir}: ${availableStrategies.join(", ")}. Pass --strategy.`
1774
1914
  );
1775
1915
  }
1916
+ const promptStrategies = includeAllOption ? [...availableStrategies, ALL_EXPORT_STRATEGIES] : availableStrategies;
1776
1917
  return selectStrategy(promptLabel, {
1777
- strategies: availableStrategies,
1918
+ strategies: promptStrategies,
1778
1919
  defaultStrategy: availableStrategies[0]
1779
1920
  });
1780
1921
  };
@@ -1803,110 +1944,81 @@ import_args.default.option(
1803
1944
  "root"
1804
1945
  );
1805
1946
  var flags = import_args.default.parse(process.argv);
1806
- var resolveRunScopedAiChunks = async ({
1807
- outDir,
1808
- strategyName
1809
- }) => {
1810
- const requestedRunId = typeof flags.runId === "string" && flags.runId.trim() ? flags.runId.trim() : "";
1811
- const runIds = requestedRunId ? [requestedRunId] : await (0, import_ai.listAiChunkRunIds)({ strategyName, outDir });
1812
- const runId = runIds.at(-1) ?? "";
1813
- if (!runId) {
1814
- return null;
1815
- }
1816
- const chunkFiles = await (0, import_ai.listAiChunkFiles)({ strategyName, outDir, runId });
1817
- if (!chunkFiles.length) {
1818
- return {
1819
- runId,
1820
- chunkFiles,
1821
- completedAttemptKeys: /* @__PURE__ */ new Set()
1822
- };
1823
- }
1824
- const userName = String(flags.user || "root");
1825
- const completed = await loadBacktestCheckpointResults({ runId, userName });
1826
- return {
1827
- runId,
1828
- chunkFiles,
1829
- completedAttemptKeys: buildCompletedBacktestDatasetAttemptKeys(completed)
1830
- };
1947
+ var printExportResult = (result) => {
1948
+ console.log(
1949
+ import_chalk2.default.green(
1950
+ result.splitApplied ? `Merged AI dataset for ${result.strategyName} saved as ${result.partCount} part files` : `Merged AI dataset saved: ${result.partPaths[0]}`
1951
+ )
1952
+ );
1953
+ result.partPaths.forEach((filePath, index) => {
1954
+ console.log(import_chalk2.default.gray(`part${index + 1}: ${filePath}`));
1955
+ });
1956
+ console.log(
1957
+ import_chalk2.default.gray(
1958
+ `strategy=${result.strategyName}, source_chunks=${result.sourceChunkCount}, deleteChunks=${Boolean(
1959
+ result.deleteChunks
1960
+ )}, partMonths=${result.partMonths}, partCount=${result.partCount}${result.runId ? `, runId=${result.runId}, completedAttempts=${result.completedAttemptCount}` : ""}`
1961
+ )
1962
+ );
1831
1963
  };
1832
1964
  var main = async () => {
1833
1965
  const outDir = String(flags.outDir || "data/ai/export");
1834
- await import_promises.default.mkdir(outDir, { recursive: true });
1966
+ await import_promises2.default.mkdir(outDir, { recursive: true });
1835
1967
  const strategyName = await resolveExportStrategy({
1836
1968
  explicitStrategy: String(flags.strategy || ""),
1837
1969
  outDir,
1838
1970
  datasetLabel: "AI",
1839
1971
  promptLabel: "Select AI export strategy",
1840
- listStrategies: import_ai.listAiChunkStrategies
1972
+ listStrategies: import_ai2.listAiChunkStrategies,
1973
+ includeAllOption: true
1841
1974
  });
1842
1975
  if (!strategyName) {
1843
1976
  console.log(import_chalk2.default.yellow(`No AI chunk files found in ${outDir}`));
1844
- process.exit(0);
1977
+ return;
1845
1978
  }
1846
- const runScopedChunks = await resolveRunScopedAiChunks({
1847
- strategyName,
1848
- outDir
1849
- });
1850
- const chunkFiles = runScopedChunks ? runScopedChunks.chunkFiles : await (0, import_ai.listAiChunkFiles)({
1851
- strategyName,
1852
- outDir
1979
+ const strategyNames = strategyName === ALL_EXPORT_STRATEGIES ? await (0, import_ai2.listAiChunkStrategies)({ outDir }) : [strategyName];
1980
+ if (!strategyNames.length) {
1981
+ console.log(import_chalk2.default.yellow(`No AI chunk files found in ${outDir}`));
1982
+ return;
1983
+ }
1984
+ const progressBar = strategyNames.length > 1 ? new import_progress.default(":current/:total [:bar] :percent :strategy :status", {
1985
+ total: strategyNames.length,
1986
+ width: 30
1987
+ }) : null;
1988
+ const results = await exportAiStrategiesSequentially({
1989
+ outDir,
1990
+ strategyNames,
1991
+ keepChunks: Boolean(flags.keepChunks),
1992
+ partMonths: Number(flags.partMonths),
1993
+ requestedRunId: typeof flags.runId === "string" ? flags.runId.trim() : void 0,
1994
+ userName: String(flags.user || "root"),
1995
+ onProgress: progressBar ? ({ strategyName: currentStrategy, status }) => {
1996
+ const progressStatus = status === "started" ? "exporting" : status;
1997
+ if (status === "started" || status === "failed") {
1998
+ progressBar.tick(0, {
1999
+ strategy: currentStrategy,
2000
+ status: progressStatus
2001
+ });
2002
+ if (status === "failed") {
2003
+ progressBar.terminate();
2004
+ }
2005
+ return;
2006
+ }
2007
+ progressBar.tick(1, {
2008
+ strategy: currentStrategy,
2009
+ status: progressStatus
2010
+ });
2011
+ } : void 0
1853
2012
  });
1854
- if (!chunkFiles.length) {
2013
+ if (!results.length) {
1855
2014
  console.log(
1856
2015
  import_chalk2.default.yellow(
1857
- `No chunk files found for strategy "${strategyName}" in ${outDir}`
2016
+ strategyNames.length === 1 ? `No chunk files found for strategy "${strategyNames[0]}" in ${outDir}` : `No AI chunk files were exported from ${outDir}`
1858
2017
  )
1859
2018
  );
1860
- process.exit(0);
2019
+ return;
1861
2020
  }
1862
- if (runScopedChunks && runScopedChunks.completedAttemptKeys.size === 0) {
1863
- throw new Error(
1864
- `No completed checkpoint attempts found for AI export run "${runScopedChunks.runId}"`
1865
- );
1866
- }
1867
- const mergedPath = import_path.default.join(
1868
- outDir,
1869
- `ai-dataset-${(0, import_ai.toFileToken)(strategyName)}-merged-${Date.now()}.jsonl`
1870
- );
1871
- await (0, import_ai.mergeAiJsonlFiles)({
1872
- filePaths: chunkFiles,
1873
- outPath: mergedPath,
1874
- shouldIncludeRow: runScopedChunks ? (row) => isBacktestDatasetRowForCompletedAttempt(
1875
- row,
1876
- runScopedChunks.completedAttemptKeys
1877
- ) : void 0
1878
- });
1879
- const partMonths = Math.max(0, Math.trunc(Number(flags.partMonths) || 0));
1880
- const splitResult = partMonths > 0 ? await (0, import_ai.splitAiMergedDatasetFile)({
1881
- filePath: mergedPath,
1882
- monthsPerPart: partMonths
1883
- }) : {
1884
- partPaths: [mergedPath],
1885
- partCount: 1,
1886
- splitApplied: false
1887
- };
1888
- const shouldDeleteChunks = !Boolean(flags.keepChunks);
1889
- if (shouldDeleteChunks) {
1890
- for (const filePath of chunkFiles) {
1891
- await import_promises.default.rm(filePath, { force: true });
1892
- }
1893
- }
1894
- console.log(
1895
- import_chalk2.default.green(
1896
- splitResult.splitApplied ? `Merged AI dataset saved as ${splitResult.partCount} part files` : `Merged AI dataset saved: ${splitResult.partPaths[0]}`
1897
- )
1898
- );
1899
- splitResult.partPaths.forEach((filePath, index) => {
1900
- console.log(import_chalk2.default.gray(`part${index + 1}: ${filePath}`));
1901
- });
1902
- console.log(
1903
- import_chalk2.default.gray(
1904
- `strategy=${strategyName}, source_chunks=${chunkFiles.length}, deleteChunks=${Boolean(
1905
- shouldDeleteChunks
1906
- )}, partMonths=${partMonths}, partCount=${splitResult.partCount}${runScopedChunks ? `, runId=${runScopedChunks.runId}, completedAttempts=${runScopedChunks.completedAttemptKeys.size}` : ""}`
1907
- )
1908
- );
1909
- process.exit(0);
2021
+ results.forEach(printExportResult);
1910
2022
  };
1911
2023
  // Annotate the CommonJS export names for ESM import in node:
1912
2024
  0 && (module.exports = {