@tradejs/cli 1.0.9 → 1.0.10

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.
Files changed (76) hide show
  1. package/dist/cli.js +29497 -13537
  2. package/dist/lib/aiPocketSearch.js +1316 -0
  3. package/dist/lib/aiTrainCharts.js +711 -0
  4. package/dist/lib/aiTrainDataset.js +40 -0
  5. package/dist/lib/aiTrainEvaluationDump.js +76 -0
  6. package/dist/lib/aiTrainMetrics.js +148 -8
  7. package/dist/lib/aiTrainOptions.js +130 -0
  8. package/dist/lib/aiTrainQuarantine.js +199 -0
  9. package/dist/lib/aiTrainResearch.js +467 -0
  10. package/dist/lib/binanceMarketContextBackfill.js +841 -0
  11. package/dist/lib/binanceMarketData.js +392 -0
  12. package/dist/lib/coinMarketCapContextBackfill.js +1088 -0
  13. package/dist/lib/continuity.js +60 -0
  14. package/dist/lib/derivativesContextBackfill.js +490 -77
  15. package/dist/lib/executionCalibration.js +705 -0
  16. package/dist/lib/marketContextPrepare.js +4403 -0
  17. package/dist/lib/paritySummary.js +101 -0
  18. package/dist/lib/runBot.js +1 -0
  19. package/dist/lib/runEnvironment.js +2254 -0
  20. package/dist/lib/runFormatting.js +1657 -0
  21. package/dist/lib/runtimeDebugEvidence.js +526 -0
  22. package/dist/lib/runtimeModeConfig.js +53 -0
  23. package/dist/lib/runtimeParity.js +88 -11
  24. package/dist/lib/runtimeParityDetails.js +751 -0
  25. package/dist/lib/runtimeRedis.js +157 -0
  26. package/dist/lib/runtimeSignalsLoader.js +40 -6
  27. package/dist/lib/runtimeSignalsStorage.js +45 -22
  28. package/dist/lib/runtimeStrategyBacktest.js +134 -0
  29. package/dist/lib/runtimeTradeSync.js +263 -0
  30. package/dist/lib/telegramReports.js +9 -0
  31. package/dist/lib/tickerUniverseCache.js +116 -0
  32. package/dist/lib/timeWindow.js +3 -3
  33. package/dist/scripts/agentRun.js +14 -8
  34. package/dist/scripts/aiExport.js +1721 -7
  35. package/dist/scripts/aiExportSelect.js +16 -4
  36. package/dist/scripts/aiPocketSearch.js +4190 -0
  37. package/dist/scripts/aiTrain.js +1866 -87
  38. package/dist/scripts/backtest.js +4509 -818
  39. package/dist/scripts/binanceMarketIngest.js +565 -0
  40. package/dist/scripts/bot.js +16 -2
  41. package/dist/scripts/candlesMigrateProvider.js +32 -22
  42. package/dist/scripts/cleanDir.js +15 -2
  43. package/dist/scripts/cleanRedis.js +15 -2
  44. package/dist/scripts/cleanTests.js +38 -2
  45. package/dist/scripts/cleanupMarketContext.js +69 -0
  46. package/dist/scripts/continuity.js +148 -67
  47. package/dist/scripts/derivativesIngest.js +14 -4
  48. package/dist/scripts/derivativesIngestCoinalyzeAll.js +14 -4
  49. package/dist/scripts/doctor.js +14 -4
  50. package/dist/scripts/executionCalibration.js +792 -0
  51. package/dist/scripts/infraCommon.js +10 -0
  52. package/dist/scripts/infraDown.js +14 -4
  53. package/dist/scripts/infraInit.js +24 -4
  54. package/dist/scripts/infraUp.js +14 -4
  55. package/dist/scripts/marketWs.js +222 -0
  56. package/dist/scripts/migration.js +15 -2
  57. package/dist/scripts/mlExport.js +1698 -10
  58. package/dist/scripts/mlExportSelect.js +16 -4
  59. package/dist/scripts/mlInspect.js +13 -3
  60. package/dist/scripts/mlTrainLatestSelect.js +14 -4
  61. package/dist/scripts/replay.js +8824 -0
  62. package/dist/scripts/replayRunner.js +8827 -0
  63. package/dist/scripts/replayRuntimeEvidence.js +868 -0
  64. package/dist/scripts/researchAuto.js +286 -59
  65. package/dist/scripts/results.js +3 -3
  66. package/dist/scripts/runtimeEvidence.js +605 -0
  67. package/dist/scripts/runtimeParity.js +6362 -1043
  68. package/dist/scripts/serverHealth.js +588 -0
  69. package/dist/scripts/signals.js +5590 -511
  70. package/dist/scripts/signalsDaemon.js +6167 -0
  71. package/dist/scripts/signalsSummary.js +833 -248
  72. package/dist/scripts/test-ml.js +25 -3
  73. package/dist/scripts/test.js +26 -1
  74. package/dist/scripts/user-add.js +15 -2
  75. package/dist/workers/testerWorker.js +130 -21
  76. package/package.json +18 -12
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/runtimeTradeSync.ts
21
+ var runtimeTradeSync_exports = {};
22
+ __export(runtimeTradeSync_exports, {
23
+ EXCHANGE_HISTORY_MAX_RANGE_MS: () => EXCHANGE_HISTORY_MAX_RANGE_MS,
24
+ consumeClosedPnlMatch: () => consumeClosedPnlMatch,
25
+ formatRuntimeTradeSyncError: () => formatRuntimeTradeSyncError,
26
+ loadClosedPnlRows: () => loadClosedPnlRows,
27
+ splitExchangeHistoryTimeRange: () => splitExchangeHistoryTimeRange,
28
+ syncRuntimeTrades: () => syncRuntimeTrades
29
+ });
30
+ module.exports = __toCommonJS(runtimeTradeSync_exports);
31
+ var import_constants = require("@tradejs/core/constants");
32
+ var import_time = require("@tradejs/core/time");
33
+ var import_redis = require("@tradejs/infra/redis");
34
+ var CLOSED_PNL_LIMIT = 100;
35
+ var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
36
+ var splitExchangeHistoryTimeRange = ({
37
+ startTime,
38
+ endTime,
39
+ maxRangeMs = EXCHANGE_HISTORY_MAX_RANGE_MS
40
+ }) => {
41
+ if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || !Number.isFinite(maxRangeMs) || maxRangeMs <= 0 || endTime <= startTime) {
42
+ return [{ startTime, endTime }];
43
+ }
44
+ const chunks = [];
45
+ let chunkStart = Math.trunc(startTime);
46
+ const finalEnd = Math.trunc(endTime);
47
+ const maxRange = Math.trunc(maxRangeMs);
48
+ while (chunkStart < finalEnd) {
49
+ const chunkEnd = Math.min(finalEnd, chunkStart + maxRange);
50
+ chunks.push({ startTime: chunkStart, endTime: chunkEnd });
51
+ if (chunkEnd >= finalEnd) {
52
+ break;
53
+ }
54
+ chunkStart = chunkEnd + 1;
55
+ }
56
+ return chunks;
57
+ };
58
+ var formatRuntimeTradeSyncError = (error) => {
59
+ if (!error || typeof error !== "object") {
60
+ return String(error || "unknown error");
61
+ }
62
+ const record = error;
63
+ const message = typeof record.message === "string" && record.message.trim() ? record.message.trim() : String(error);
64
+ const code = typeof record.code === "string" && record.code.trim() ? record.code.trim() : null;
65
+ const isAxiosError = record.isAxiosError === true;
66
+ const config = record.config && typeof record.config === "object" ? record.config : null;
67
+ const response = record.response && typeof record.response === "object" ? record.response : null;
68
+ const method = typeof config?.method === "string" && config.method.trim() ? config.method.toUpperCase() : null;
69
+ const url = typeof config?.url === "string" && config.url.trim() ? config.url.trim() : null;
70
+ const timeout = typeof config?.timeout === "number" && Number.isFinite(config.timeout) ? config.timeout : null;
71
+ const status = typeof response?.status === "number" && Number.isFinite(response.status) ? response.status : null;
72
+ const details = [
73
+ isAxiosError ? "axios" : null,
74
+ code,
75
+ status == null ? null : `status=${status}`,
76
+ method && url ? `${method} ${url}` : url,
77
+ timeout == null ? null : `timeout=${timeout}ms`
78
+ ].filter(Boolean);
79
+ return details.length > 0 ? `${message} (${details.join(", ")})` : message;
80
+ };
81
+ var loadClosedPnlRows = async ({
82
+ connector,
83
+ startTime,
84
+ endTime,
85
+ callbacks
86
+ }) => {
87
+ if (typeof connector.getClosedPnl !== "function") {
88
+ callbacks?.onUnsupported?.();
89
+ return [];
90
+ }
91
+ const rows = [];
92
+ const chunks = splitExchangeHistoryTimeRange({ startTime, endTime });
93
+ for (const chunk of chunks) {
94
+ try {
95
+ const chunkRows = await connector.getClosedPnl({
96
+ startTime: chunk.startTime,
97
+ endTime: chunk.endTime,
98
+ limit: CLOSED_PNL_LIMIT
99
+ });
100
+ if (chunkRows.length >= CLOSED_PNL_LIMIT) {
101
+ callbacks?.onCapped?.(chunkRows.length);
102
+ }
103
+ rows.push(...chunkRows);
104
+ } catch (error) {
105
+ callbacks?.onError?.(error);
106
+ }
107
+ }
108
+ return rows.sort((left, right) => left.closedAt - right.closedAt);
109
+ };
110
+ var consumeClosedPnlMatch = (buckets, trade) => {
111
+ const rows = buckets.get(trade.symbol);
112
+ if (!rows?.length) {
113
+ return null;
114
+ }
115
+ const minimumClosedAt = trade.entryTimestamp - 5 * 6e4;
116
+ const matchIndex = rows.findIndex(
117
+ (row2) => Number.isFinite(row2.closedAt) && row2.closedAt >= minimumClosedAt
118
+ );
119
+ if (matchIndex < 0) {
120
+ return null;
121
+ }
122
+ const [row] = rows.splice(matchIndex, 1);
123
+ return row ?? null;
124
+ };
125
+ var syncRuntimeTrades = async ({
126
+ userName,
127
+ connector,
128
+ trades,
129
+ startTime,
130
+ endTime,
131
+ closedPnlCallbacks,
132
+ openPositionCallbacks
133
+ }) => {
134
+ let openPositions = [];
135
+ let openPositionsReliable = true;
136
+ if (typeof connector.getOpenPositionPnl === "function") {
137
+ try {
138
+ openPositions = await connector.getOpenPositionPnl();
139
+ } catch (error) {
140
+ openPositionCallbacks?.onError?.(error);
141
+ openPositionsReliable = false;
142
+ openPositions = [];
143
+ }
144
+ }
145
+ const openPositionsBySymbol = new Map(
146
+ openPositions.map((position) => [position.symbol, position])
147
+ );
148
+ const activeOrderIdBySymbol = /* @__PURE__ */ new Map();
149
+ const symbols = [...new Set(trades.map((trade) => trade.symbol))];
150
+ await Promise.all(
151
+ symbols.map(async (symbol) => {
152
+ const activeRef = await (0, import_redis.getData)(
153
+ import_redis.redisKeys.runtimeActiveTrade(userName, symbol),
154
+ null
155
+ );
156
+ activeOrderIdBySymbol.set(
157
+ symbol,
158
+ typeof activeRef?.orderId === "string" ? activeRef.orderId : null
159
+ );
160
+ })
161
+ );
162
+ const closedPnlRows = await loadClosedPnlRows({
163
+ connector,
164
+ startTime,
165
+ endTime,
166
+ callbacks: closedPnlCallbacks
167
+ });
168
+ const closedPnlBuckets = /* @__PURE__ */ new Map();
169
+ for (const row of closedPnlRows) {
170
+ const bucket = closedPnlBuckets.get(row.symbol) ?? [];
171
+ bucket.push(row);
172
+ closedPnlBuckets.set(row.symbol, bucket);
173
+ }
174
+ const syncedTrades = [];
175
+ for (const trade of trades) {
176
+ if (trade.status !== "active") {
177
+ syncedTrades.push(trade);
178
+ continue;
179
+ }
180
+ const openPosition = openPositionsBySymbol.get(trade.symbol);
181
+ const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
182
+ const isCurrentActiveTrade = activeOrderId === trade.orderId;
183
+ if (!openPositionsReliable) {
184
+ syncedTrades.push({
185
+ ...trade,
186
+ status: "active",
187
+ lastSyncedAt: endTime
188
+ });
189
+ continue;
190
+ }
191
+ if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
192
+ const nextTrade2 = {
193
+ ...trade,
194
+ status: "active",
195
+ currentPrice: openPosition.currentPrice,
196
+ currentPnl: openPosition.unrealizedPnl,
197
+ lastSyncedAt: endTime
198
+ };
199
+ await (0, import_redis.setData)(
200
+ import_redis.redisKeys.runtimeTrade(userName, trade.orderId),
201
+ nextTrade2,
202
+ {
203
+ expire: 0
204
+ }
205
+ );
206
+ await (0, import_redis.setHashJsonField)(
207
+ import_redis.redisKeys.runtimeTradeBucket(
208
+ userName,
209
+ (0, import_time.getRuntimeStorageDayKey)(trade.entryTimestamp)
210
+ ),
211
+ trade.orderId,
212
+ nextTrade2,
213
+ { expire: 0 }
214
+ );
215
+ syncedTrades.push(nextTrade2);
216
+ continue;
217
+ }
218
+ const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
219
+ const nextTrade = {
220
+ ...trade,
221
+ status: "closed",
222
+ currentPrice: matchedClosedPnl?.exitPrice ?? trade.currentPrice ?? null,
223
+ currentPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
224
+ closedPnl: matchedClosedPnl?.closedPnl ?? trade.closedPnl ?? trade.currentPnl ?? null,
225
+ actualEntryPrice: matchedClosedPnl?.entryPrice ?? trade.actualEntryPrice ?? null,
226
+ exitPrice: matchedClosedPnl?.exitPrice ?? trade.exitPrice ?? null,
227
+ actualExitPrice: matchedClosedPnl?.exitPrice ?? trade.actualExitPrice ?? null,
228
+ exitTimestamp: matchedClosedPnl?.closedAt ?? trade.exitTimestamp ?? endTime,
229
+ exitType: trade.exitType ?? null,
230
+ openFee: matchedClosedPnl?.openFee ?? trade.openFee ?? null,
231
+ closeFee: matchedClosedPnl?.closeFee ?? trade.closeFee ?? null,
232
+ fundingFee: matchedClosedPnl?.fundingFee ?? trade.fundingFee ?? null,
233
+ totalFee: matchedClosedPnl?.totalFee ?? trade.totalFee ?? null,
234
+ lastSyncedAt: endTime
235
+ };
236
+ await Promise.all([
237
+ (0, import_redis.setData)(import_redis.redisKeys.runtimeTrade(userName, trade.orderId), nextTrade, {
238
+ expire: import_constants.TTL_1M
239
+ }),
240
+ (0, import_redis.setHashJsonField)(
241
+ import_redis.redisKeys.runtimeTradeBucket(
242
+ userName,
243
+ (0, import_time.getRuntimeStorageDayKey)(trade.entryTimestamp)
244
+ ),
245
+ trade.orderId,
246
+ nextTrade,
247
+ { expire: import_constants.TTL_1M }
248
+ ),
249
+ ...isCurrentActiveTrade ? [(0, import_redis.delKey)(import_redis.redisKeys.runtimeActiveTrade(userName, trade.symbol))] : []
250
+ ]);
251
+ syncedTrades.push(nextTrade);
252
+ }
253
+ return syncedTrades;
254
+ };
255
+ // Annotate the CommonJS export names for ESM import in node:
256
+ 0 && (module.exports = {
257
+ EXCHANGE_HISTORY_MAX_RANGE_MS,
258
+ consumeClosedPnlMatch,
259
+ formatRuntimeTradeSyncError,
260
+ loadClosedPnlRows,
261
+ splitExchangeHistoryTimeRange,
262
+ syncRuntimeTrades
263
+ });
@@ -68,8 +68,16 @@ ${line}` : line;
68
68
  };
69
69
  var sendTelegramReport = async (message, options = {}) => {
70
70
  const chunks = splitTelegramReport(message);
71
+ const sendAttachments = async () => {
72
+ for (const attachment of options.attachments || []) {
73
+ await (0, import_cli.sendDocumentToTG)(attachment, {
74
+ userName: options.userName
75
+ });
76
+ }
77
+ };
71
78
  if (chunks.length === 1) {
72
79
  await (0, import_cli.sendTextToTG)(chunks[0], options);
80
+ await sendAttachments();
73
81
  return chunks.length;
74
82
  }
75
83
  for (const [index, chunk] of chunks.entries()) {
@@ -81,6 +89,7 @@ ${chunk}`, {
81
89
  markup: index === chunks.length - 1 ? options.markup : void 0
82
90
  });
83
91
  }
92
+ await sendAttachments();
84
93
  return chunks.length;
85
94
  };
86
95
  // Annotate the CommonJS export names for ESM import in node:
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/tickerUniverseCache.ts
21
+ var tickerUniverseCache_exports = {};
22
+ __export(tickerUniverseCache_exports, {
23
+ loadRunTickers: () => loadRunTickers
24
+ });
25
+ module.exports = __toCommonJS(tickerUniverseCache_exports);
26
+ var import_tickers = require("@tradejs/core/tickers");
27
+ var import_redis = require("@tradejs/infra/redis");
28
+ var import_cli = require("@tradejs/node/cli");
29
+ var TICKER_CACHE_VERSION = 1;
30
+ var parseSymbolsFromCLI = (symbols = "") => symbols.split(",").map((symbol) => symbol.trim().toUpperCase()).filter(Boolean);
31
+ var isTickerLike = (value) => {
32
+ if (!value || typeof value !== "object") {
33
+ return false;
34
+ }
35
+ const ticker = value;
36
+ return typeof ticker.symbol === "string" && ticker.symbol.trim().length > 0 && typeof ticker.volume24h === "number" && Number.isFinite(ticker.volume24h);
37
+ };
38
+ var readCachedTickerUniverse = async (cacheKey) => {
39
+ const cached = await (0, import_redis.getData)(cacheKey, null);
40
+ if (!cached || !Array.isArray(cached.tickers)) {
41
+ return null;
42
+ }
43
+ const tickers = cached.tickers.filter(isTickerLike);
44
+ return tickers.length ? tickers : null;
45
+ };
46
+ var selectTickerSymbols = ({
47
+ tickers,
48
+ exclude,
49
+ limit
50
+ }) => {
51
+ const excludedTickers = parseSymbolsFromCLI(exclude);
52
+ return (0, import_tickers.getTopTickers)(tickers, limit).map(({ value }) => value).filter((ticker) => !excludedTickers.includes(ticker));
53
+ };
54
+ var loadRunTickers = async ({
55
+ connector,
56
+ connectorName,
57
+ userName,
58
+ include,
59
+ exclude,
60
+ limit,
61
+ cacheOnly,
62
+ universe,
63
+ accountId,
64
+ assetClasses
65
+ }) => {
66
+ if (include?.trim()) {
67
+ return (0, import_cli.getTickers)(connector, include, exclude, limit, void 0, {
68
+ universe,
69
+ assetClasses
70
+ });
71
+ }
72
+ const cacheKey = import_redis.redisKeys.tickerUniverse(
73
+ userName,
74
+ connectorName,
75
+ universe,
76
+ accountId
77
+ );
78
+ if (cacheOnly) {
79
+ const cachedTickers = await readCachedTickerUniverse(cacheKey);
80
+ if (!cachedTickers) {
81
+ throw new Error(
82
+ `No cached ticker universe for ${connectorName}. Run once without --cacheOnly or pass --tickers explicitly.`
83
+ );
84
+ }
85
+ return selectTickerSymbols({
86
+ tickers: cachedTickers,
87
+ exclude,
88
+ limit
89
+ });
90
+ }
91
+ const exchangeTickers = await connector.getTickers({
92
+ universe,
93
+ assetClasses
94
+ });
95
+ if (exchangeTickers.length) {
96
+ await (0, import_redis.setData)(
97
+ cacheKey,
98
+ {
99
+ version: TICKER_CACHE_VERSION,
100
+ connectorName,
101
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
102
+ tickers: exchangeTickers
103
+ },
104
+ { expire: 0 }
105
+ );
106
+ }
107
+ return selectTickerSymbols({
108
+ tickers: exchangeTickers,
109
+ exclude,
110
+ limit
111
+ });
112
+ };
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ loadRunTickers
116
+ });
@@ -54,9 +54,10 @@ var resolveTimeWindow = ({
54
54
  }) => {
55
55
  const explicitStart = toEpochMs(startTime);
56
56
  const explicitEnd = toEpochMs(endTime);
57
+ const resolvedDays = toPositiveNumber(days);
57
58
  if (explicitStart != null || explicitEnd != null) {
58
- const resolvedEnd2 = explicitEnd ?? defaultEndMs ?? nowMs;
59
- const resolvedStart = explicitStart ?? defaultStartMs;
59
+ const resolvedStart = explicitStart ?? (resolvedDays != null && explicitEnd != null ? explicitEnd - resolvedDays * ONE_DAY_MS : defaultStartMs);
60
+ const resolvedEnd2 = explicitEnd ?? (resolvedDays != null && explicitStart != null ? explicitStart + resolvedDays * ONE_DAY_MS : defaultEndMs ?? nowMs);
60
61
  if (resolvedStart >= resolvedEnd2) {
61
62
  throw new Error(
62
63
  `Invalid time window: startTime (${resolvedStart}) must be less than endTime (${resolvedEnd2})`
@@ -68,7 +69,6 @@ var resolveTimeWindow = ({
68
69
  source: "explicit"
69
70
  };
70
71
  }
71
- const resolvedDays = toPositiveNumber(days);
72
72
  if (resolvedDays != null) {
73
73
  const resolvedEnd2 = defaultEndMs ?? nowMs;
74
74
  const resolvedStart = resolvedEnd2 - resolvedDays * ONE_DAY_MS;
@@ -39,6 +39,7 @@ var import_promises = __toESM(require("fs/promises"));
39
39
  var import_node_os = __toESM(require("os"));
40
40
  var import_node_path2 = __toESM(require("path"));
41
41
  var import_node_child_process = require("child_process");
42
+ var import_constants = require("@tradejs/core/constants");
42
43
  var import_redis = require("@tradejs/infra/redis");
43
44
  var import_userSettings = require("@tradejs/infra/userSettings");
44
45
 
@@ -86,8 +87,16 @@ ${line}` : line;
86
87
  };
87
88
  var sendTelegramReport = async (message, options = {}) => {
88
89
  const chunks = splitTelegramReport(message);
90
+ const sendAttachments = async () => {
91
+ for (const attachment of options.attachments || []) {
92
+ await (0, import_cli.sendDocumentToTG)(attachment, {
93
+ userName: options.userName
94
+ });
95
+ }
96
+ };
89
97
  if (chunks.length === 1) {
90
98
  await (0, import_cli.sendTextToTG)(chunks[0], options);
99
+ await sendAttachments();
91
100
  return chunks.length;
92
101
  }
93
102
  for (const [index, chunk] of chunks.entries()) {
@@ -99,6 +108,7 @@ ${chunk}`, {
99
108
  markup: index === chunks.length - 1 ? options.markup : void 0
100
109
  });
101
110
  }
111
+ await sendAttachments();
102
112
  return chunks.length;
103
113
  };
104
114
 
@@ -603,9 +613,11 @@ var saveAgentRun = async (userName, runId, strategy, agentRun) => {
603
613
  ...run.artifacts,
604
614
  agentRun
605
615
  };
606
- await (0, import_redis.setData)(import_redis.redisKeys.researchRun(userName, runId), run, { expire: 0 });
616
+ await (0, import_redis.setData)(import_redis.redisKeys.researchRun(userName, runId), run, {
617
+ expire: import_constants.TTL_1M
618
+ });
607
619
  await (0, import_redis.setData)(import_redis.redisKeys.researchLatestRun(userName, strategy), run, {
608
- expire: 0
620
+ expire: import_constants.TTL_1M
609
621
  });
610
622
  };
611
623
  var resolveGithubRepository = async (worktreePath) => {
@@ -897,12 +909,6 @@ Return a corrected unified diff only. Keep the same allowed paths.`
897
909
  }
898
910
  }
899
911
  };
900
- if (require.main === module) {
901
- main().catch((error) => {
902
- console.error(import_chalk.default.red(error?.message || String(error)));
903
- process.exit(1);
904
- });
905
- }
906
912
  // Annotate the CommonJS export names for ESM import in node:
907
913
  0 && (module.exports = {
908
914
  main