tradeblocks-mcp 3.0.2 → 3.3.1

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 (218) hide show
  1. package/README.md +85 -80
  2. package/dist/{chunk-LDKTV7GW.js → chunk-27S67XW3.js} +24 -52
  3. package/dist/chunk-27S67XW3.js.map +1 -0
  4. package/dist/{chunk-FGZH632F.js → chunk-2E63THNI.js} +13 -11
  5. package/dist/chunk-2E63THNI.js.map +1 -0
  6. package/dist/{chunk-QTTR7AAW.js → chunk-2I3S2ZLT.js} +325 -84
  7. package/dist/chunk-2I3S2ZLT.js.map +1 -0
  8. package/dist/{chunk-4BLCXNQ6.js → chunk-4HZLVUOZ.js} +179 -183
  9. package/dist/chunk-4HZLVUOZ.js.map +1 -0
  10. package/dist/{chunk-XXYOUIZY.js → chunk-NWNSKALN.js} +63 -80
  11. package/dist/chunk-NWNSKALN.js.map +1 -0
  12. package/dist/{chunk-PRAYH3RT.js → chunk-WNTYA7ER.js} +29 -12
  13. package/dist/chunk-WNTYA7ER.js.map +1 -0
  14. package/dist/{chunk-BKQ4PM4Y.js → chunk-YZA4RS76.js} +24 -18
  15. package/dist/chunk-YZA4RS76.js.map +1 -0
  16. package/dist/{chunk-W2PP3LEH.js → chunk-ZTJXC3LS.js} +17 -8
  17. package/dist/chunk-ZTJXC3LS.js.map +1 -0
  18. package/dist/daily-log-processor-MZW2XBZY.js +9 -0
  19. package/dist/{daily-logs-store-D3QC2XPV.js → daily-logs-store-3C3OTGPK.js} +2 -2
  20. package/dist/iv-solver-worker.js +9 -1
  21. package/dist/market-provider-6U33TQUT.js +16 -0
  22. package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
  23. package/dist/{sync-PO4IPCYV.js → sync-3UBC37VW.js} +7 -7
  24. package/dist/test-exports.js +876 -483
  25. package/dist/test-exports.js.map +1 -1
  26. package/dist/trade-processor-DKDCWGKD.js +9 -0
  27. package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
  28. package/package.json +2 -6
  29. package/server/{chunk-CSDVJPBB.js → chunk-536NSFED.js} +29 -12
  30. package/server/chunk-536NSFED.js.map +1 -0
  31. package/server/{chunk-WA5AAPCH.js → chunk-A3UKD64A.js} +17 -8
  32. package/server/chunk-A3UKD64A.js.map +1 -0
  33. package/server/{chunk-PNKG7RY7.js → chunk-OMUDNJBJ.js} +63 -80
  34. package/server/chunk-OMUDNJBJ.js.map +1 -0
  35. package/server/{chunk-72GKJE2U.js → chunk-RJDJHZ5Y.js} +934 -335
  36. package/server/chunk-RJDJHZ5Y.js.map +1 -0
  37. package/server/{chunk-NZO6PT64.js → chunk-RM4B2VKS.js} +167 -177
  38. package/server/chunk-RM4B2VKS.js.map +1 -0
  39. package/server/{chunk-5EBXHT6C.js → chunk-SY6GDNVI.js} +24 -18
  40. package/server/chunk-SY6GDNVI.js.map +1 -0
  41. package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
  42. package/server/chunk-T66KH2XH.js.map +1 -0
  43. package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
  44. package/server/chunk-W5E7FHC4.js.map +1 -0
  45. package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
  46. package/server/config-DK7KOMNL.js.map +1 -0
  47. package/server/daily-log-processor-B2VPU2FQ.js +10 -0
  48. package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
  49. package/server/http-server.js +2 -5
  50. package/server/index.js +2497 -2029
  51. package/server/index.js.map +1 -1
  52. package/server/iv-solver-worker.js +9 -1
  53. package/server/market-provider-L56RFHAC.js +17 -0
  54. package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
  55. package/server/{sync-QFI5L7S7.js → sync-CENKDN53.js} +7 -7
  56. package/server/trade-processor-3PI4LHZI.js +10 -0
  57. package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
  58. package/src/auth/clients-store.ts +4 -4
  59. package/src/auth/code-store.ts +1 -1
  60. package/src/auth/config.ts +11 -12
  61. package/src/auth/login-page.ts +8 -10
  62. package/src/auth/provider.ts +35 -30
  63. package/src/auth/token.ts +17 -15
  64. package/src/db/backtest-schemas.ts +38 -8
  65. package/src/db/connection.ts +107 -40
  66. package/src/db/data-root.ts +22 -0
  67. package/src/db/index.ts +37 -5
  68. package/src/db/json-adapters.ts +22 -31
  69. package/src/db/json-migration.ts +11 -15
  70. package/src/db/json-store.ts +5 -3
  71. package/src/db/market-datasets.ts +48 -15
  72. package/src/db/market-schemas.ts +11 -5
  73. package/src/db/market-views.ts +119 -32
  74. package/src/db/parquet-writer.ts +7 -7
  75. package/src/db/profile-schemas.ts +39 -22
  76. package/src/db/schemas.ts +2 -2
  77. package/src/http-server.ts +7 -12
  78. package/src/index.ts +8 -9
  79. package/src/market/ingestor/index.ts +1 -4
  80. package/src/market/ingestor/market-ingestor.ts +140 -67
  81. package/src/market/ingestor/types.ts +1 -3
  82. package/src/market/stores/chain-sql.ts +2 -8
  83. package/src/market/stores/chain-store.ts +1 -4
  84. package/src/market/stores/duckdb-chain-store.ts +3 -14
  85. package/src/market/stores/duckdb-enriched-store.ts +3 -13
  86. package/src/market/stores/duckdb-quote-store.ts +10 -27
  87. package/src/market/stores/duckdb-spot-store.ts +4 -20
  88. package/src/market/stores/enriched-sql.ts +3 -9
  89. package/src/market/stores/enriched-store.ts +2 -2
  90. package/src/market/stores/parquet-chain-store.ts +5 -22
  91. package/src/market/stores/parquet-enriched-store.ts +4 -16
  92. package/src/market/stores/parquet-oi-daily-store.ts +3 -14
  93. package/src/market/stores/parquet-quote-store.ts +9 -29
  94. package/src/market/stores/parquet-spot-store.ts +14 -33
  95. package/src/market/stores/quote-store.ts +2 -10
  96. package/src/market/stores/spot-sql.ts +3 -15
  97. package/src/market/stores/spot-store.ts +1 -1
  98. package/src/market/tickers/defaults.json +6 -6
  99. package/src/market/tickers/loader.ts +2 -7
  100. package/src/market/tickers/registry.ts +5 -15
  101. package/src/market/tickers/schemas.ts +2 -6
  102. package/src/models/strategy-profile.ts +39 -39
  103. package/src/sync/block-sync.ts +44 -65
  104. package/src/sync/index.ts +1 -4
  105. package/src/sync/metadata.ts +14 -20
  106. package/src/test-exports.ts +139 -123
  107. package/src/tools/analysis.ts +180 -159
  108. package/src/tools/batch-exit-analysis.ts +100 -59
  109. package/src/tools/blocks/analysis.ts +116 -101
  110. package/src/tools/blocks/comparison.ts +281 -364
  111. package/src/tools/blocks/core.ts +208 -253
  112. package/src/tools/blocks/health.ts +571 -563
  113. package/src/tools/blocks/index.ts +2 -0
  114. package/src/tools/blocks/paired-comparison.ts +425 -0
  115. package/src/tools/blocks/similarity.ts +316 -283
  116. package/src/tools/edge-decay.ts +124 -197
  117. package/src/tools/exit-analysis.ts +130 -77
  118. package/src/tools/greeks-attribution.ts +84 -35
  119. package/src/tools/guides.ts +4 -6
  120. package/src/tools/imports.ts +11 -14
  121. package/src/tools/market-data.ts +1067 -757
  122. package/src/tools/market-enrichment.ts +3 -3
  123. package/src/tools/market-fetch.ts +148 -67
  124. package/src/tools/market-imports.ts +12 -12
  125. package/src/tools/middleware/sync-middleware.ts +5 -6
  126. package/src/tools/performance.ts +185 -302
  127. package/src/tools/profile-analysis.ts +52 -66
  128. package/src/tools/profiles.ts +106 -69
  129. package/src/tools/regime-advisor.ts +20 -45
  130. package/src/tools/replay.ts +81 -77
  131. package/src/tools/reports/discrepancies.ts +298 -328
  132. package/src/tools/reports/fields.ts +7 -25
  133. package/src/tools/reports/helpers.ts +18 -49
  134. package/src/tools/reports/predictive.ts +27 -70
  135. package/src/tools/reports/slippage-trends.ts +315 -345
  136. package/src/tools/reports/slippage.ts +1 -4
  137. package/src/tools/reports/strategy-matches.ts +399 -441
  138. package/src/tools/schema.ts +43 -40
  139. package/src/tools/shared/filters.ts +3 -9
  140. package/src/tools/snapshot.ts +9 -30
  141. package/src/tools/sql.ts +15 -14
  142. package/src/tools/tickers.ts +1 -4
  143. package/src/utils/batch-exit-analysis.ts +31 -42
  144. package/src/utils/black-scholes.ts +39 -29
  145. package/src/utils/block-loader.ts +69 -83
  146. package/src/utils/calibration-probe.ts +3 -4
  147. package/src/utils/chain-loader.ts +3 -3
  148. package/src/utils/csv-discovery.ts +16 -22
  149. package/src/utils/data-quality.ts +24 -36
  150. package/src/utils/exit-triggers.ts +91 -96
  151. package/src/utils/field-timing.ts +94 -79
  152. package/src/utils/filter-predicates.ts +13 -9
  153. package/src/utils/flatfile-importer.ts +94 -64
  154. package/src/utils/greeks-decomposition.ts +152 -100
  155. package/src/utils/iv-solver-pool.ts +55 -25
  156. package/src/utils/iv-solver-worker.ts +5 -5
  157. package/src/utils/market-enricher.ts +528 -497
  158. package/src/utils/market-importer.ts +31 -12
  159. package/src/utils/market-provider.ts +21 -23
  160. package/src/utils/massive-tier.ts +5 -7
  161. package/src/utils/migrate-option-data-helpers.ts +2 -8
  162. package/src/utils/option-quote-greeks.ts +25 -31
  163. package/src/utils/option-time.ts +4 -8
  164. package/src/utils/output-formatter.ts +1 -4
  165. package/src/utils/provider-capabilities.ts +1 -4
  166. package/src/utils/providers/massive.ts +59 -93
  167. package/src/utils/providers/thetadata/backfill.ts +14 -23
  168. package/src/utils/providers/thetadata/client.ts +12 -8
  169. package/src/utils/providers/thetadata/decode.ts +2 -20
  170. package/src/utils/providers/thetadata/endpoints.ts +32 -40
  171. package/src/utils/providers/thetadata/join.ts +11 -10
  172. package/src/utils/providers/thetadata/proto.ts +12 -10
  173. package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
  174. package/src/utils/providers/thetadata.ts +11 -10
  175. package/src/utils/quote-enricher.ts +4 -4
  176. package/src/utils/quote-parquet-projection.ts +3 -11
  177. package/src/utils/sample-date-selector.ts +3 -5
  178. package/src/utils/schema-metadata.ts +102 -70
  179. package/src/utils/ticker.ts +5 -9
  180. package/src/utils/trade-replay.ts +77 -68
  181. package/dist/chunk-4BLCXNQ6.js.map +0 -1
  182. package/dist/chunk-BKQ4PM4Y.js.map +0 -1
  183. package/dist/chunk-FGZH632F.js.map +0 -1
  184. package/dist/chunk-LDKTV7GW.js.map +0 -1
  185. package/dist/chunk-PRAYH3RT.js.map +0 -1
  186. package/dist/chunk-QTTR7AAW.js.map +0 -1
  187. package/dist/chunk-W2PP3LEH.js.map +0 -1
  188. package/dist/chunk-XXYOUIZY.js.map +0 -1
  189. package/dist/daily-log-processor-6MWJ23JK.js +0 -9
  190. package/dist/market-provider-VDRJUEF2.js +0 -16
  191. package/dist/trade-processor-NHU4VWRX.js +0 -9
  192. package/manifest.json +0 -141
  193. package/server/chunk-5EBXHT6C.js.map +0 -1
  194. package/server/chunk-72GKJE2U.js.map +0 -1
  195. package/server/chunk-CSDVJPBB.js.map +0 -1
  196. package/server/chunk-FBNDMCT5.js.map +0 -1
  197. package/server/chunk-NRFXAJF7.js.map +0 -1
  198. package/server/chunk-NZO6PT64.js.map +0 -1
  199. package/server/chunk-PNKG7RY7.js.map +0 -1
  200. package/server/chunk-WA5AAPCH.js.map +0 -1
  201. package/server/config-6IZXEFEX.js.map +0 -1
  202. package/server/daily-log-processor-Y3PVSVBM.js +0 -10
  203. package/server/market-provider-VOYYVYWT.js +0 -17
  204. package/server/trade-processor-JWVS37KM.js +0 -10
  205. /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
  206. /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
  207. /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-6U33TQUT.js.map} +0 -0
  208. /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
  209. /package/dist/{sync-PO4IPCYV.js.map → sync-3UBC37VW.js.map} +0 -0
  210. /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
  211. /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
  212. /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
  213. /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
  214. /package/server/{market-provider-VOYYVYWT.js.map → market-provider-L56RFHAC.js.map} +0 -0
  215. /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
  216. /package/server/{sync-QFI5L7S7.js.map → sync-CENKDN53.js.map} +0 -0
  217. /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
  218. /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
@@ -3,19 +3,19 @@ import {
3
3
  REPORTING_TRADE_COLUMN_ALIASES,
4
4
  convertTatRowToReportingTrade,
5
5
  isTatFormat
6
- } from "./chunk-72GKJE2U.js";
6
+ } from "./chunk-RJDJHZ5Y.js";
7
7
 
8
8
  // src/sync/index.ts
9
9
  import { existsSync as existsSync2 } from "fs";
10
10
  import * as fs9 from "fs/promises";
11
- import * as path11 from "path";
11
+ import * as path12 from "path";
12
12
 
13
13
  // src/db/connection.ts
14
14
  import { DuckDBInstance } from "@duckdb/node-api";
15
15
  import { execFile } from "child_process";
16
16
  import * as fs4 from "fs/promises";
17
17
  import * as os from "os";
18
- import * as path7 from "path";
18
+ import * as path8 from "path";
19
19
  import { promisify } from "util";
20
20
 
21
21
  // src/db/schemas.ts
@@ -211,12 +211,13 @@ async function ensureMarketDataTables(conn) {
211
211
 
212
212
  // src/db/parquet-writer.ts
213
213
  import * as fs from "fs/promises";
214
- import * as path2 from "path";
214
+ import * as path3 from "path";
215
215
 
216
216
  // src/db/market-datasets.ts
217
- import * as path from "path";
217
+ import * as path2 from "path";
218
218
 
219
219
  // src/db/data-root.ts
220
+ import path from "path";
220
221
  var KEY = "__tradeblocks_data_root__";
221
222
  function setDataRoot(dir) {
222
223
  globalThis[KEY] = dir;
@@ -236,26 +237,38 @@ var PARTITIONED_DATASETS = {
236
237
  option_quote_minutes: "option_quote_minutes"
237
238
  };
238
239
  function resolveMarketDir(dataDir) {
239
- return path.join(getDataRoot(dataDir), "market");
240
+ return path2.join(getDataRoot(dataDir), "market");
240
241
  }
241
242
  function resolveCanonicalMarketFile(dataDir, dataset) {
242
- return path.join(resolveMarketDir(dataDir), SINGLE_FILE_DATASETS[dataset]);
243
+ return path2.join(resolveMarketDir(dataDir), SINGLE_FILE_DATASETS[dataset]);
243
244
  }
244
245
  function resolveCanonicalMarketPartitionDir(dataDir, dataset) {
245
- return path.join(resolveMarketDir(dataDir), PARTITIONED_DATASETS[dataset]);
246
+ return path2.join(resolveMarketDir(dataDir), PARTITIONED_DATASETS[dataset]);
246
247
  }
247
248
  var DATASETS_V3 = {
248
249
  spot: { subdir: "spot", partitionKeys: ["ticker", "date"], filename: "data.parquet" },
249
250
  enriched: { subdir: "enriched", partitionKeys: ["ticker"], filename: "data.parquet" },
250
251
  enriched_context: { subdir: "enriched/context", partitionKeys: [], filename: "data.parquet" },
251
- option_chain: { subdir: "option_chain", partitionKeys: ["underlying", "date"], filename: "data.parquet" },
252
- option_quote_minutes: { subdir: "option_quote_minutes", partitionKeys: ["underlying", "date"], filename: "data.parquet" },
253
- option_oi_daily: { subdir: "option_oi_daily", partitionKeys: ["underlying", "date"], filename: "data.parquet" }
252
+ option_chain: {
253
+ subdir: "option_chain",
254
+ partitionKeys: ["underlying", "date"],
255
+ filename: "data.parquet"
256
+ },
257
+ option_quote_minutes: {
258
+ subdir: "option_quote_minutes",
259
+ partitionKeys: ["underlying", "date"],
260
+ filename: "data.parquet"
261
+ },
262
+ option_oi_daily: {
263
+ subdir: "option_oi_daily",
264
+ partitionKeys: ["underlying", "date"],
265
+ filename: "data.parquet"
266
+ }
254
267
  };
255
268
  async function writeSpotPartition(conn, args) {
256
269
  const def = DATASETS_V3.spot;
257
270
  return writeParquetPartition(conn, {
258
- baseDir: path.join(resolveMarketDir(args.dataDir), def.subdir),
271
+ baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
259
272
  partitions: { ticker: args.ticker, date: args.date },
260
273
  // order matches def.partitionKeys
261
274
  selectQuery: args.selectQuery,
@@ -266,7 +279,7 @@ async function writeSpotPartition(conn, args) {
266
279
  async function writeChainPartition(conn, args) {
267
280
  const def = DATASETS_V3.option_chain;
268
281
  return writeParquetPartition(conn, {
269
- baseDir: path.join(resolveMarketDir(args.dataDir), def.subdir),
282
+ baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
270
283
  partitions: { underlying: args.underlying, date: args.date },
271
284
  selectQuery: args.selectQuery,
272
285
  compression: args.compression,
@@ -277,7 +290,7 @@ async function writeQuoteMinutesPartition(conn, args) {
277
290
  const def = DATASETS_V3.option_quote_minutes;
278
291
  const sortedSelect = `SELECT * FROM (${args.selectQuery}) AS q ORDER BY q.ticker, q.time`;
279
292
  return writeParquetPartition(conn, {
280
- baseDir: path.join(resolveMarketDir(args.dataDir), def.subdir),
293
+ baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
281
294
  partitions: { underlying: args.underlying, date: args.date },
282
295
  selectQuery: sortedSelect,
283
296
  compression: args.compression,
@@ -288,7 +301,7 @@ async function writeOiDailyPartition(conn, args) {
288
301
  const def = DATASETS_V3.option_oi_daily;
289
302
  const sortedSelect = `SELECT * FROM (${args.selectQuery}) AS q ORDER BY q.ticker`;
290
303
  return writeParquetPartition(conn, {
291
- baseDir: path.join(resolveMarketDir(args.dataDir), def.subdir),
304
+ baseDir: path2.join(resolveMarketDir(args.dataDir), def.subdir),
292
305
  partitions: { underlying: args.underlying, date: args.date },
293
306
  selectQuery: sortedSelect,
294
307
  compression: args.compression,
@@ -310,7 +323,7 @@ async function writeParquetAtomic(conn, opts) {
310
323
  const tempPath = `${targetPath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
311
324
  try {
312
325
  await conn.run(`CREATE TEMP TABLE "${stagingName}" AS ${selectQuery}`);
313
- await fs.mkdir(path2.dirname(targetPath), { recursive: true });
326
+ await fs.mkdir(path3.dirname(targetPath), { recursive: true });
314
327
  await conn.run(
315
328
  `COPY "${stagingName}" TO '${tempPath}' (FORMAT PARQUET, COMPRESSION ${compression})`
316
329
  );
@@ -341,9 +354,7 @@ async function writeParquetPartition(conn, opts) {
341
354
  const filename = isLegacy ? "data.parquet" : opts.filename ?? "data.parquet";
342
355
  for (const [k, v] of Object.entries(partitions)) {
343
356
  if (!PARTITION_KEY_RE.test(k)) {
344
- throw new Error(
345
- `writeParquetPartition: unsafe partition key: ${JSON.stringify(k)}`
346
- );
357
+ throw new Error(`writeParquetPartition: unsafe partition key: ${JSON.stringify(k)}`);
347
358
  }
348
359
  if (!PARTITION_VALUE_RE.test(v)) {
349
360
  throw new Error(
@@ -351,10 +362,8 @@ async function writeParquetPartition(conn, opts) {
351
362
  );
352
363
  }
353
364
  }
354
- const partitionSegments = Object.entries(partitions).map(
355
- ([k, v]) => `${k}=${v}`
356
- );
357
- const targetPath = path2.join(opts.baseDir, ...partitionSegments, filename);
365
+ const partitionSegments = Object.entries(partitions).map(([k, v]) => `${k}=${v}`);
366
+ const targetPath = path3.join(opts.baseDir, ...partitionSegments, filename);
358
367
  return writeParquetAtomic(conn, {
359
368
  targetPath,
360
369
  selectQuery: opts.selectQuery,
@@ -364,18 +373,18 @@ async function writeParquetPartition(conn, opts) {
364
373
 
365
374
  // src/db/json-adapters.ts
366
375
  import * as fs3 from "fs/promises";
367
- import * as path4 from "path";
376
+ import * as path5 from "path";
368
377
  import { z } from "zod";
369
378
 
370
379
  // src/db/json-store.ts
371
380
  import * as fs2 from "fs/promises";
372
- import * as path3 from "path";
381
+ import * as path4 from "path";
373
382
  function isEnoent(err) {
374
383
  return typeof err === "object" && err !== null && err.code === "ENOENT";
375
384
  }
376
385
  async function writeJsonFile(filePath, data) {
377
386
  const tmpPath = filePath + ".tmp";
378
- await fs2.mkdir(path3.dirname(filePath), { recursive: true });
387
+ await fs2.mkdir(path4.dirname(filePath), { recursive: true });
379
388
  await fs2.writeFile(tmpPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
380
389
  await fs2.rename(tmpPath, filePath);
381
390
  }
@@ -404,7 +413,7 @@ async function deleteJsonFile(filePath) {
404
413
  async function listJsonFiles(dirPath, suffix = ".json") {
405
414
  try {
406
415
  const entries = await fs2.readdir(dirPath, { withFileTypes: true });
407
- return entries.filter((e) => e.isFile() && e.name.endsWith(suffix)).map((e) => path3.join(dirPath, e.name)).sort();
416
+ return entries.filter((e) => e.isFile() && e.name.endsWith(suffix)).map((e) => path4.join(dirPath, e.name)).sort();
408
417
  } catch (err) {
409
418
  if (isEnoent(err)) {
410
419
  return [];
@@ -432,7 +441,7 @@ function jsonToProfile(json) {
432
441
  };
433
442
  }
434
443
  function profilePath(blockId, strategyName, blocksDir) {
435
- return path4.join(blocksDir, blockId, "profiles", toFileSlug(strategyName) + ".json");
444
+ return path5.join(blocksDir, blockId, "profiles", toFileSlug(strategyName) + ".json");
436
445
  }
437
446
  async function upsertProfileJson(profile, blocksDir) {
438
447
  const filePath = profilePath(profile.blockId, profile.strategyName, blocksDir);
@@ -454,7 +463,7 @@ async function getProfileJson(blockId, strategyName, blocksDir) {
454
463
  }
455
464
  async function listProfilesJson(blocksDir, blockId) {
456
465
  if (blockId) {
457
- const profileDir = path4.join(blocksDir, blockId, "profiles");
466
+ const profileDir = path5.join(blocksDir, blockId, "profiles");
458
467
  const files = await listJsonFiles(profileDir);
459
468
  const profiles2 = [];
460
469
  for (const file of files) {
@@ -494,7 +503,7 @@ function jsonToSyncMeta(json) {
494
503
  };
495
504
  }
496
505
  function syncMetaPath(blockId, blocksDir) {
497
- return path4.join(blocksDir, blockId, ".sync-meta.json");
506
+ return path5.join(blocksDir, blockId, ".sync-meta.json");
498
507
  }
499
508
  async function getSyncMetadataJson(blockId, blocksDir) {
500
509
  const filePath = syncMetaPath(blockId, blocksDir);
@@ -532,7 +541,7 @@ function marketMetaKey(source, ticker, targetTable) {
532
541
  return `${source}|${ticker}|${targetTable}`;
533
542
  }
534
543
  function marketMetaFilePath(dataDir) {
535
- return path4.join(getDataRoot(dataDir), "market-meta", "sync-metadata.json");
544
+ return path5.join(getDataRoot(dataDir), "market-meta", "sync-metadata.json");
536
545
  }
537
546
  async function upsertMarketImportMetadataJson(metadata, dataDir) {
538
547
  const filePath = marketMetaFilePath(dataDir);
@@ -548,7 +557,7 @@ function flatLogKey(entry) {
548
557
  return `${entry.date}|${entry.asset_class}|${entry.underlying}`;
549
558
  }
550
559
  function flatLogFilePath(dataDir) {
551
- return path4.join(getDataRoot(dataDir), "market-meta", "flat-import-log.json");
560
+ return path5.join(getDataRoot(dataDir), "market-meta", "flat-import-log.json");
552
561
  }
553
562
  async function upsertFlatImportLogJson(entry, dataDir) {
554
563
  const filePath = flatLogFilePath(dataDir);
@@ -574,16 +583,14 @@ var EnrichmentWatermarksSchema = z.object({
574
583
  watermarks: z.record(z.string().regex(/^[A-Z0-9._-]+$/), TickerEntrySchema)
575
584
  });
576
585
  function watermarksFilePath(dataDir) {
577
- return path4.join(getDataRoot(dataDir), "market-meta", "enrichment-watermarks.json");
586
+ return path5.join(getDataRoot(dataDir), "market-meta", "enrichment-watermarks.json");
578
587
  }
579
588
  async function loadEnrichmentWatermarks(dataDir) {
580
589
  const raw = await readJsonFile(watermarksFilePath(dataDir));
581
590
  if (raw === null) return { version: 1, watermarks: {} };
582
591
  const parsed = EnrichmentWatermarksSchema.safeParse(raw);
583
592
  if (!parsed.success) {
584
- throw new Error(
585
- `enrichment-watermarks.json is malformed: ${parsed.error.message}`
586
- );
593
+ throw new Error(`enrichment-watermarks.json is malformed: ${parsed.error.message}`);
587
594
  }
588
595
  return parsed.data;
589
596
  }
@@ -624,13 +631,27 @@ async function ensureProfilesSchema(conn) {
624
631
  await conn.run(`
625
632
  ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS position_sizing JSON
626
633
  `);
627
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS underlying VARCHAR`);
628
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS re_entry BOOLEAN`);
629
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_profits BOOLEAN`);
630
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_losses BOOLEAN`);
631
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS require_two_prices_pt BOOLEAN`);
632
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS close_on_completion BOOLEAN`);
633
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ignore_margin_req BOOLEAN`);
634
+ await conn.run(
635
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS underlying VARCHAR`
636
+ );
637
+ await conn.run(
638
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS re_entry BOOLEAN`
639
+ );
640
+ await conn.run(
641
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_profits BOOLEAN`
642
+ );
643
+ await conn.run(
644
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS cap_losses BOOLEAN`
645
+ );
646
+ await conn.run(
647
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS require_two_prices_pt BOOLEAN`
648
+ );
649
+ await conn.run(
650
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS close_on_completion BOOLEAN`
651
+ );
652
+ await conn.run(
653
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ignore_margin_req BOOLEAN`
654
+ );
634
655
  const strategyCols = [
635
656
  { name: "slippage_entry", type: "DOUBLE" },
636
657
  { name: "slippage_exit", type: "DOUBLE" },
@@ -644,7 +665,9 @@ async function ensureProfilesSchema(conn) {
644
665
  { name: "default_to_date", type: "VARCHAR" }
645
666
  ];
646
667
  for (const col of strategyCols) {
647
- await conn.run(`ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ${col.name} ${col.type}`);
668
+ await conn.run(
669
+ `ALTER TABLE profiles.strategy_profiles ADD COLUMN IF NOT EXISTS ${col.name} ${col.type}`
670
+ );
648
671
  }
649
672
  await migrateExpectedRegimes(conn);
650
673
  }
@@ -867,7 +890,7 @@ async function deleteProfile(conn, blockId, strategyName, baseDir) {
867
890
 
868
891
  // src/db/market-views.ts
869
892
  import { existsSync, readdirSync } from "fs";
870
- import * as path5 from "path";
893
+ import * as path6 from "path";
871
894
 
872
895
  // src/utils/quote-parquet-projection.ts
873
896
  var describeCache = /* @__PURE__ */ new Map();
@@ -976,12 +999,12 @@ function hasParquetPartitions(dir, partitionKey = "date") {
976
999
  const prefix = `${partitionKey}=`;
977
1000
  return readdirSync(dir).some((entry) => {
978
1001
  if (!entry.startsWith(prefix)) return false;
979
- const partDir = path5.join(dir, entry);
1002
+ const partDir = path6.join(dir, entry);
980
1003
  try {
981
1004
  const entries = readdirSync(partDir);
982
1005
  for (const sub of entries) {
983
1006
  if (sub.endsWith(".parquet")) return true;
984
- const nested = path5.join(partDir, sub);
1007
+ const nested = path6.join(partDir, sub);
985
1008
  try {
986
1009
  if (readdirSync(nested).some((f) => f.endsWith(".parquet"))) return true;
987
1010
  } catch {
@@ -1001,20 +1024,24 @@ function hasEnrichedTickerFiles(dir) {
1001
1024
  try {
1002
1025
  return readdirSync(dir).some((entry) => {
1003
1026
  if (!entry.startsWith("ticker=")) return false;
1004
- return existsSync(path5.join(dir, entry, "data.parquet"));
1027
+ return existsSync(path6.join(dir, entry, "data.parquet"));
1005
1028
  });
1006
1029
  } catch {
1007
1030
  return false;
1008
1031
  }
1009
1032
  }
1010
1033
  function hasEnrichedContextFile(dir) {
1011
- return existsSync(path5.join(dir, "context", "data.parquet"));
1034
+ return existsSync(path6.join(dir, "context", "data.parquet"));
1012
1035
  }
1013
1036
  async function createMarketParquetViews(conn, dataDir) {
1014
1037
  const viewsCreated = [];
1015
1038
  const tablesKept = [];
1016
1039
  const hiveViews = [
1017
- { name: "option_chain", subdir: resolveCanonicalMarketPartitionDir(dataDir, "option_chain"), partitionKey: "underlying" }
1040
+ {
1041
+ name: "option_chain",
1042
+ subdir: resolveCanonicalMarketPartitionDir(dataDir, "option_chain"),
1043
+ partitionKey: "underlying"
1044
+ }
1018
1045
  ];
1019
1046
  for (const { name, subdir, partitionKey } of hiveViews) {
1020
1047
  const dirPath = subdir;
@@ -1085,7 +1112,7 @@ async function createMarketParquetViews(conn, dataDir) {
1085
1112
  await conn.run("DROP TABLE IF EXISTS market.option_delta_index");
1086
1113
  } catch {
1087
1114
  }
1088
- const spotDir = path5.join(resolveMarketDir(dataDir), "spot");
1115
+ const spotDir = path6.join(resolveMarketDir(dataDir), "spot");
1089
1116
  if (hasParquetPartitions(spotDir, "ticker")) {
1090
1117
  try {
1091
1118
  await conn.run("DROP VIEW IF EXISTS market.spot");
@@ -1107,7 +1134,7 @@ async function createMarketParquetViews(conn, dataDir) {
1107
1134
  }
1108
1135
  tablesKept.push("spot");
1109
1136
  }
1110
- const enrichedDir = path5.join(resolveMarketDir(dataDir), "enriched");
1137
+ const enrichedDir = path6.join(resolveMarketDir(dataDir), "enriched");
1111
1138
  if (hasEnrichedTickerFiles(enrichedDir)) {
1112
1139
  try {
1113
1140
  await conn.run("DROP VIEW IF EXISTS market.enriched");
@@ -1140,7 +1167,7 @@ async function createMarketParquetViews(conn, dataDir) {
1140
1167
  }
1141
1168
  await conn.run(
1142
1169
  `CREATE OR REPLACE VIEW market.enriched_context AS
1143
- SELECT * FROM read_parquet('${path5.join(enrichedDir, "context", "data.parquet")}')`
1170
+ SELECT * FROM read_parquet('${path6.join(enrichedDir, "context", "data.parquet")}')`
1144
1171
  );
1145
1172
  viewsCreated.push("enriched_context");
1146
1173
  } else {
@@ -1205,7 +1232,7 @@ async function createMarketParquetViews(conn, dataDir) {
1205
1232
  }
1206
1233
 
1207
1234
  // src/db/json-migration.ts
1208
- import * as path6 from "path";
1235
+ import * as path7 from "path";
1209
1236
  function toDate2(value) {
1210
1237
  if (value instanceof Date) return value;
1211
1238
  if (typeof value === "object" && value !== null && "micros" in value) {
@@ -1282,12 +1309,7 @@ async function migrateProfiles(conn, blocksDir) {
1282
1309
  createdAt: createdAt.toISOString(),
1283
1310
  updatedAt: updatedAt.toISOString()
1284
1311
  };
1285
- const filePath = path6.join(
1286
- blocksDir,
1287
- blockId,
1288
- "profiles",
1289
- toFileSlug(strategyName) + ".json"
1290
- );
1312
+ const filePath = path7.join(blocksDir, blockId, "profiles", toFileSlug(strategyName) + ".json");
1291
1313
  await writeJsonFile(filePath, profileJson);
1292
1314
  }
1293
1315
  return rows.length;
@@ -1320,7 +1342,7 @@ async function migrateSyncMetadata(conn, blocksDir) {
1320
1342
  return rows.length;
1321
1343
  }
1322
1344
  async function migrateMarketImportMetadata(conn, dataDir) {
1323
- const existingFile = await readJsonFile(path6.join(dataDir, "market-meta", "sync-metadata.json"));
1345
+ const existingFile = await readJsonFile(path7.join(dataDir, "market-meta", "sync-metadata.json"));
1324
1346
  if (existingFile !== null) return 0;
1325
1347
  let rows;
1326
1348
  try {
@@ -1346,7 +1368,9 @@ async function migrateMarketImportMetadata(conn, dataDir) {
1346
1368
  return rows.length;
1347
1369
  }
1348
1370
  async function migrateFlatImportLog(conn, dataDir) {
1349
- const existingFile = await readJsonFile(path6.join(dataDir, "market-meta", "flat-import-log.json"));
1371
+ const existingFile = await readJsonFile(
1372
+ path7.join(dataDir, "market-meta", "flat-import-log.json")
1373
+ );
1350
1374
  if (existingFile !== null) return 0;
1351
1375
  let rows;
1352
1376
  try {
@@ -1490,7 +1514,7 @@ async function tryRecoverLockByTerminatingStaleProcess(errorMessage, dbPath, for
1490
1514
  return false;
1491
1515
  }
1492
1516
  const normalizedDbPath = dbPath.replace(/\\/g, "/");
1493
- const normalizedDbDir = path7.dirname(normalizedDbPath);
1517
+ const normalizedDbDir = path8.dirname(normalizedDbPath);
1494
1518
  const isTradeblocksProcess = command.includes("tradeblocks-mcp") || command.includes("/mcp-server/server/index.js") || command.includes("packages/mcp-server/server/index.js") || command.includes("\\mcp-server\\server\\index.js") || command.includes("packages\\mcp-server\\server\\index.js");
1495
1519
  const normalizedCommand = command.replace(/\\/g, "/");
1496
1520
  const targetsSameDb = normalizedCommand.includes(normalizedDbPath) || normalizedCommand.includes(normalizedDbDir);
@@ -1524,16 +1548,16 @@ function resolveMarketDbPath(dataDir) {
1524
1548
  const args = process.argv;
1525
1549
  for (let i = 0; i < args.length; i++) {
1526
1550
  if (args[i] === "--market-db" && args[i + 1]) {
1527
- return path7.resolve(args[i + 1]);
1551
+ return path8.resolve(args[i + 1]);
1528
1552
  }
1529
1553
  }
1530
1554
  if (process.env.MARKET_DB_PATH) {
1531
- return path7.resolve(process.env.MARKET_DB_PATH);
1555
+ return path8.resolve(process.env.MARKET_DB_PATH);
1532
1556
  }
1533
- return path7.join(dataDir, "market.duckdb");
1557
+ return path8.join(dataDir, "market.duckdb");
1534
1558
  }
1535
1559
  async function attachMarketDb(conn, marketDbPath, mode) {
1536
- await fs4.mkdir(path7.dirname(marketDbPath), { recursive: true });
1560
+ await fs4.mkdir(path8.dirname(marketDbPath), { recursive: true });
1537
1561
  const readOnlyClause = mode === "read_only" ? " (READ_ONLY)" : "";
1538
1562
  const escapedPath = marketDbPath.replace(/'/g, "''");
1539
1563
  try {
@@ -1580,15 +1604,18 @@ async function openReadWriteConnection(dbPath, threads, memoryLimit) {
1580
1604
  await ensureReportingDataTable(connection);
1581
1605
  await ensureMutableMarketTables(connection);
1582
1606
  await ensureProfilesSchema(connection);
1583
- const dataDir = path7.dirname(dbPath);
1607
+ const dataDir = path8.dirname(dbPath);
1584
1608
  const dataRoot = getDataRoot(dataDir);
1585
1609
  await createMarketParquetViews(connection, dataRoot);
1586
1610
  await ensureMarketDataTables(connection);
1587
1611
  try {
1588
- const blocksDir = (await import("./sync-QFI5L7S7.js")).getBlocksDir(dataRoot);
1612
+ const blocksDir = (await import("./sync-CENKDN53.js")).getBlocksDir(dataRoot);
1589
1613
  await migrateMetadataToJson(connection, dataRoot, blocksDir);
1590
1614
  } catch (err) {
1591
- console.warn("[json-migration] Migration failed (non-fatal):", err instanceof Error ? err.message : err);
1615
+ console.warn(
1616
+ "[json-migration] Migration failed (non-fatal):",
1617
+ err instanceof Error ? err.message : err
1618
+ );
1592
1619
  }
1593
1620
  connectionMode = "read_write";
1594
1621
  return connection;
@@ -1628,7 +1655,7 @@ async function getConnection(dataDir) {
1628
1655
  if (connection) {
1629
1656
  return connection;
1630
1657
  }
1631
- const dbPath = path7.join(dataDir, "analytics.duckdb");
1658
+ const dbPath = path8.join(dataDir, "analytics.duckdb");
1632
1659
  const threads = process.env.DUCKDB_THREADS || defaultThreads();
1633
1660
  const memoryLimit = process.env.DUCKDB_MEMORY_LIMIT || defaultMemoryLimit();
1634
1661
  storedDbPath = dbPath;
@@ -1643,7 +1670,11 @@ async function getConnection(dataDir) {
1643
1670
  } catch (error) {
1644
1671
  const errorMessage = error instanceof Error ? error.message : String(error);
1645
1672
  if (isLockError(errorMessage)) {
1646
- const recovered = await tryRecoverLockByTerminatingStaleProcess(errorMessage, dbPath, forceRecovery);
1673
+ const recovered = await tryRecoverLockByTerminatingStaleProcess(
1674
+ errorMessage,
1675
+ dbPath,
1676
+ forceRecovery
1677
+ );
1647
1678
  if (recovered) {
1648
1679
  for (let attempt = 0; attempt < 3; attempt++) {
1649
1680
  await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
@@ -1701,7 +1732,7 @@ async function closeConnection() {
1701
1732
  async function upgradeToReadWrite(dataDir, options) {
1702
1733
  if (connectionMode === "read_write" && connection) return connection;
1703
1734
  await closeConnection();
1704
- const dbPath = storedDbPath || path7.join(dataDir, "analytics.duckdb");
1735
+ const dbPath = storedDbPath || path8.join(dataDir, "analytics.duckdb");
1705
1736
  const threads = storedThreads || process.env.DUCKDB_THREADS || defaultThreads();
1706
1737
  const memoryLimit = storedMemoryLimit || process.env.DUCKDB_MEMORY_LIMIT || defaultMemoryLimit();
1707
1738
  if (!storedMarketDbPath) {
@@ -1755,7 +1786,7 @@ function getCurrentConnection() {
1755
1786
 
1756
1787
  // src/sync/block-sync.ts
1757
1788
  import * as fs8 from "fs/promises";
1758
- import * as path10 from "path";
1789
+ import * as path11 from "path";
1759
1790
 
1760
1791
  // src/sync/hasher.ts
1761
1792
  import * as crypto from "crypto";
@@ -1813,18 +1844,13 @@ async function deleteSyncMetadata(conn, blockId, blocksDir) {
1813
1844
  await deleteSyncMetadataJson(blockId, blocksDir);
1814
1845
  return;
1815
1846
  }
1816
- await conn.run(
1817
- `DELETE FROM trades._sync_metadata WHERE block_id = $1`,
1818
- [blockId]
1819
- );
1847
+ await conn.run(`DELETE FROM trades._sync_metadata WHERE block_id = $1`, [blockId]);
1820
1848
  }
1821
1849
  async function getAllSyncedBlockIds(conn, blocksDir) {
1822
1850
  if (isParquetMode() && blocksDir) {
1823
1851
  return getAllSyncedBlockIdsJson(blocksDir);
1824
1852
  }
1825
- const reader = await conn.runAndReadAll(
1826
- `SELECT block_id FROM trades._sync_metadata`
1827
- );
1853
+ const reader = await conn.runAndReadAll(`SELECT block_id FROM trades._sync_metadata`);
1828
1854
  const rows = reader.getRows();
1829
1855
  return rows.map((row) => row[0]);
1830
1856
  }
@@ -1876,11 +1902,11 @@ function marketTickerDateKey(ticker, date) {
1876
1902
 
1877
1903
  // src/utils/block-loader.ts
1878
1904
  import * as fs7 from "fs/promises";
1879
- import * as path9 from "path";
1905
+ import * as path10 from "path";
1880
1906
 
1881
1907
  // src/utils/csv-discovery.ts
1882
1908
  import * as fs6 from "fs/promises";
1883
- import * as path8 from "path";
1909
+ import * as path9 from "path";
1884
1910
  function parseCSVLine(line) {
1885
1911
  const result = [];
1886
1912
  let current = "";
@@ -1961,12 +1987,8 @@ async function detectCsvType(filePath) {
1961
1987
  const reportingAliases = Object.keys(REPORTING_TRADE_COLUMN_ALIASES).map(
1962
1988
  (k) => k.toLowerCase()
1963
1989
  );
1964
- const hasReportingColumns = reportingAliases.some(
1965
- (alias) => headers.includes(alias)
1966
- );
1967
- const hasActualPl = headers.some(
1968
- (h) => h.includes("actual") && h.includes("p")
1969
- );
1990
+ const hasReportingColumns = reportingAliases.some((alias) => headers.includes(alias));
1991
+ const hasActualPl = headers.some((h) => h.includes("actual") && h.includes("p"));
1970
1992
  const hasReportedStyle = headers.includes("trade id") || headers.some((h) => h.includes("reported"));
1971
1993
  if (hasActualPl || hasReportingColumns || hasReportedStyle) {
1972
1994
  if (!hasPl || hasActualPl) {
@@ -2009,7 +2031,7 @@ async function discoverCsvFiles(folderPath) {
2009
2031
  if (csvFile === "tradelog.csv" || csvFile === "dailylog.csv" || csvFile === "reportinglog.csv" || csvFile === mappings.reportinglog) {
2010
2032
  continue;
2011
2033
  }
2012
- const csvPath = path8.join(folderPath, csvFile);
2034
+ const csvPath = path9.join(folderPath, csvFile);
2013
2035
  const detectedType = await detectCsvType(csvPath);
2014
2036
  if (detectedType) {
2015
2037
  if (detectedType === "tradelog" && !mappings.tradelog) {
@@ -2198,7 +2220,7 @@ function convertToDailyLogEntry(raw, blockId) {
2198
2220
  }
2199
2221
  }
2200
2222
  async function loadTrades(blockPath, filename = "tradelog.csv", blockId) {
2201
- const tradelogPath = path9.join(blockPath, filename);
2223
+ const tradelogPath = path10.join(blockPath, filename);
2202
2224
  const content = await fs7.readFile(tradelogPath, "utf-8");
2203
2225
  const records = parseCSV(content);
2204
2226
  const trades = [];
@@ -2216,7 +2238,7 @@ async function loadTrades(blockPath, filename = "tradelog.csv", blockId) {
2216
2238
  return trades;
2217
2239
  }
2218
2240
  async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
2219
- const dailylogPath = path9.join(blockPath, filename);
2241
+ const dailylogPath = path10.join(blockPath, filename);
2220
2242
  try {
2221
2243
  await fs7.access(dailylogPath);
2222
2244
  const content = await fs7.readFile(dailylogPath, "utf-8");
@@ -2228,9 +2250,7 @@ async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
2228
2250
  entries.push(entry);
2229
2251
  }
2230
2252
  }
2231
- entries.sort(
2232
- (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
2233
- );
2253
+ entries.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
2234
2254
  return entries.length > 0 ? entries : void 0;
2235
2255
  } catch {
2236
2256
  return void 0;
@@ -2238,10 +2258,10 @@ async function loadDailyLogs(blockPath, blockId, filename = "dailylog.csv") {
2238
2258
  }
2239
2259
  async function loadBlock(baseDir, blockId) {
2240
2260
  const blocksDir = resolveBlocksBaseDir(baseDir);
2241
- const blockPath = path9.join(blocksDir, blockId);
2261
+ const blockPath = path10.join(blocksDir, blockId);
2242
2262
  const { mappings } = await discoverCsvFiles(blockPath);
2243
2263
  const tradelogFilename = mappings.tradelog || "tradelog.csv";
2244
- const tradelogPath = path9.join(blockPath, tradelogFilename);
2264
+ const tradelogPath = path10.join(blockPath, tradelogFilename);
2245
2265
  try {
2246
2266
  await fs7.access(tradelogPath);
2247
2267
  } catch {
@@ -2411,7 +2431,7 @@ async function listBlocks(baseDir) {
2411
2431
  }
2412
2432
  blocks.push(info);
2413
2433
  } else if (!stats) {
2414
- const blockPath = path9.join(blocksDir, blockId);
2434
+ const blockPath = path10.join(blocksDir, blockId);
2415
2435
  try {
2416
2436
  const { mappings } = await discoverCsvFiles(blockPath);
2417
2437
  if (mappings.tradelog) {
@@ -2439,14 +2459,12 @@ async function listBlocks(baseDir) {
2439
2459
  }
2440
2460
  function normalizeRecordHeaders(raw) {
2441
2461
  const normalized = { ...raw };
2442
- Object.entries(REPORTING_TRADE_COLUMN_ALIASES).forEach(
2443
- ([alias, canonical]) => {
2444
- if (normalized[alias] !== void 0) {
2445
- normalized[canonical] = normalized[alias];
2446
- delete normalized[alias];
2447
- }
2462
+ Object.entries(REPORTING_TRADE_COLUMN_ALIASES).forEach(([alias, canonical]) => {
2463
+ if (normalized[alias] !== void 0) {
2464
+ normalized[canonical] = normalized[alias];
2465
+ delete normalized[alias];
2448
2466
  }
2449
- );
2467
+ });
2450
2468
  return normalized;
2451
2469
  }
2452
2470
  function convertToReportingTrade(raw) {
@@ -2481,10 +2499,10 @@ function convertToReportingTrade(raw) {
2481
2499
  }
2482
2500
  async function loadReportingLog(baseDir, blockId) {
2483
2501
  const blocksDir = resolveBlocksBaseDir(baseDir);
2484
- const blockPath = path9.join(blocksDir, blockId);
2502
+ const blockPath = path10.join(blocksDir, blockId);
2485
2503
  const { mappings } = await discoverCsvFiles(blockPath);
2486
2504
  const filename = mappings.reportinglog || "reportinglog.csv";
2487
- const reportingLogPath = path9.join(blockPath, filename);
2505
+ const reportingLogPath = path10.join(blockPath, filename);
2488
2506
  try {
2489
2507
  await fs7.access(reportingLogPath);
2490
2508
  } catch {
@@ -2499,9 +2517,7 @@ async function loadReportingLog(baseDir, blockId) {
2499
2517
  trades.push(trade);
2500
2518
  }
2501
2519
  }
2502
- trades.sort(
2503
- (a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime()
2504
- );
2520
+ trades.sort((a, b) => new Date(a.dateOpened).getTime() - new Date(b.dateOpened).getTime());
2505
2521
  return trades;
2506
2522
  }
2507
2523
  function toKebabCase(str) {
@@ -2541,9 +2557,7 @@ function validateCsvColumns(records, csvType) {
2541
2557
  }
2542
2558
  const dateOpenedAliases = ["Date Opened", "date_opened"];
2543
2559
  const plAliases = ["P/L", "pl"];
2544
- const hasDateOpened = dateOpenedAliases.some(
2545
- (col) => headers.includes(col)
2546
- );
2560
+ const hasDateOpened = dateOpenedAliases.some((col) => headers.includes(col));
2547
2561
  const hasPl = plAliases.some((col) => headers.includes(col));
2548
2562
  const missing = [];
2549
2563
  if (!hasDateOpened) missing.push("Date Opened");
@@ -2583,11 +2597,9 @@ async function importCsv(baseDir, options) {
2583
2597
  const name = blockName;
2584
2598
  const blockId = toKebabCase(name);
2585
2599
  if (!blockId) {
2586
- throw new Error(
2587
- "Could not derive a valid block ID from the filename or provided name"
2588
- );
2600
+ throw new Error("Could not derive a valid block ID from the filename or provided name");
2589
2601
  }
2590
- const blockPath = path9.join(blocksDir, blockId);
2602
+ const blockPath = path10.join(blocksDir, blockId);
2591
2603
  try {
2592
2604
  await fs7.access(blockPath);
2593
2605
  throw new Error(
@@ -2600,7 +2612,7 @@ async function importCsv(baseDir, options) {
2600
2612
  }
2601
2613
  await fs7.mkdir(blockPath, { recursive: true });
2602
2614
  const targetFilename = csvType === "tradelog" ? "tradelog.csv" : csvType === "dailylog" ? "dailylog.csv" : "reportinglog.csv";
2603
- const targetPath = path9.join(blockPath, targetFilename);
2615
+ const targetPath = path10.join(blockPath, targetFilename);
2604
2616
  await fs7.copyFile(csvPath, targetPath);
2605
2617
  let dateRange = {
2606
2618
  start: null,
@@ -2744,10 +2756,7 @@ async function insertTradeBatch(conn, blockId, records, startIdx, batchSize) {
2744
2756
  for (let rowIdx = 0; rowIdx < batch.length; rowIdx++) {
2745
2757
  const record = batch[rowIdx];
2746
2758
  const baseParam = rowIdx * columnsPerRow + 1;
2747
- const rowPlaceholders = Array.from(
2748
- { length: columnsPerRow },
2749
- (_, i) => `$${baseParam + i}`
2750
- );
2759
+ const rowPlaceholders = Array.from({ length: columnsPerRow }, (_, i) => `$${baseParam + i}`);
2751
2760
  placeholders.push(`(${rowPlaceholders.join(", ")})`);
2752
2761
  const premium = parseFloat(record["Premium"]);
2753
2762
  const numContracts = parseInt(record["No. of Contracts"], 10);
@@ -2815,10 +2824,7 @@ async function insertReportingBatch(conn, blockId, trades, tickers, startIdx, ba
2815
2824
  for (let rowIdx = 0; rowIdx < batch.length; rowIdx++) {
2816
2825
  const trade = batch[rowIdx];
2817
2826
  const baseParam = rowIdx * columnsPerRow + 1;
2818
- const rowPlaceholders = Array.from(
2819
- { length: columnsPerRow },
2820
- (_, i) => `$${baseParam + i}`
2821
- );
2827
+ const rowPlaceholders = Array.from({ length: columnsPerRow }, (_, i) => `$${baseParam + i}`);
2822
2828
  placeholders.push(`(${rowPlaceholders.join(", ")})`);
2823
2829
  params.push(
2824
2830
  blockId,
@@ -2852,7 +2858,7 @@ function versionedHash(hash) {
2852
2858
  return `${hash}:${PARSE_VERSION}`;
2853
2859
  }
2854
2860
  async function syncBlockInternal(conn, blockId, blockPath) {
2855
- const blocksDir = path10.dirname(blockPath);
2861
+ const blocksDir = path11.dirname(blockPath);
2856
2862
  try {
2857
2863
  const existingMetadata = await getSyncMetadata(conn, blockId, blocksDir);
2858
2864
  const tradelogFilename = await findTradelogFile(blockPath);
@@ -2860,14 +2866,8 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2860
2866
  if (existingMetadata) {
2861
2867
  await conn.run("BEGIN TRANSACTION");
2862
2868
  try {
2863
- await conn.run(
2864
- "DELETE FROM trades.trade_data WHERE block_id = $1",
2865
- [blockId]
2866
- );
2867
- await conn.run(
2868
- "DELETE FROM trades.reporting_data WHERE block_id = $1",
2869
- [blockId]
2870
- );
2869
+ await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
2870
+ await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
2871
2871
  await deleteSyncMetadata(conn, blockId, blocksDir);
2872
2872
  await conn.run("COMMIT");
2873
2873
  return { blockId, status: "deleted" };
@@ -2882,12 +2882,12 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2882
2882
  error: "No tradelog CSV found in block"
2883
2883
  };
2884
2884
  }
2885
- const tradelogPath = path10.join(blockPath, tradelogFilename);
2885
+ const tradelogPath = path11.join(blockPath, tradelogFilename);
2886
2886
  const tradelogHash = versionedHash(await hashFileContent(tradelogPath));
2887
2887
  if (existingMetadata && existingMetadata.tradelog_hash === tradelogHash) {
2888
2888
  const optionalLogs = await findOptionalLogFiles(blockPath);
2889
2889
  if (optionalLogs.reportinglog) {
2890
- const reportinglogPath = path10.join(blockPath, optionalLogs.reportinglog);
2890
+ const reportinglogPath = path11.join(blockPath, optionalLogs.reportinglog);
2891
2891
  const reportinglogHash = versionedHash(await hashFileContent(reportinglogPath));
2892
2892
  if (existingMetadata.reportinglog_hash !== reportinglogHash) {
2893
2893
  } else {
@@ -2902,10 +2902,7 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2902
2902
  }
2903
2903
  await conn.run("BEGIN TRANSACTION");
2904
2904
  try {
2905
- await conn.run(
2906
- "DELETE FROM trades.trade_data WHERE block_id = $1",
2907
- [blockId]
2908
- );
2905
+ await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
2909
2906
  const csvContent = await fs8.readFile(tradelogPath, "utf-8");
2910
2907
  const records = parseCSV2(csvContent);
2911
2908
  const batchSize = 500;
@@ -2917,26 +2914,23 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2917
2914
  let reportinglogHash = null;
2918
2915
  if (optionalLogs.dailylog) {
2919
2916
  try {
2920
- dailylogHash = versionedHash(await hashFileContent(
2921
- path10.join(blockPath, optionalLogs.dailylog)
2922
- ));
2917
+ dailylogHash = versionedHash(
2918
+ await hashFileContent(path11.join(blockPath, optionalLogs.dailylog))
2919
+ );
2923
2920
  } catch {
2924
2921
  }
2925
2922
  }
2926
2923
  if (optionalLogs.reportinglog) {
2927
2924
  try {
2928
- reportinglogHash = versionedHash(await hashFileContent(
2929
- path10.join(blockPath, optionalLogs.reportinglog)
2930
- ));
2925
+ reportinglogHash = versionedHash(
2926
+ await hashFileContent(path11.join(blockPath, optionalLogs.reportinglog))
2927
+ );
2931
2928
  } catch {
2932
2929
  }
2933
2930
  }
2934
- await conn.run(
2935
- "DELETE FROM trades.reporting_data WHERE block_id = $1",
2936
- [blockId]
2937
- );
2931
+ await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
2938
2932
  if (optionalLogs.reportinglog && reportinglogHash) {
2939
- const reportingPath = path10.join(blockPath, optionalLogs.reportinglog);
2933
+ const reportingPath = path11.join(blockPath, optionalLogs.reportinglog);
2940
2934
  const reportingContent = await fs8.readFile(reportingPath, "utf-8");
2941
2935
  const reportingRecords = parseCSV2(reportingContent);
2942
2936
  const reportingTrades = [];
@@ -2949,7 +2943,14 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2949
2943
  }
2950
2944
  }
2951
2945
  for (let i = 0; i < reportingTrades.length; i += batchSize) {
2952
- await insertReportingBatch(conn, blockId, reportingTrades, reportingTickers, i, batchSize);
2946
+ await insertReportingBatch(
2947
+ conn,
2948
+ blockId,
2949
+ reportingTrades,
2950
+ reportingTickers,
2951
+ i,
2952
+ batchSize
2953
+ );
2953
2954
  }
2954
2955
  }
2955
2956
  const newMetadata = {
@@ -2972,14 +2973,8 @@ async function syncBlockInternal(conn, blockId, blockPath) {
2972
2973
  if (existingMetadata) {
2973
2974
  try {
2974
2975
  await conn.run("BEGIN TRANSACTION");
2975
- await conn.run(
2976
- "DELETE FROM trades.trade_data WHERE block_id = $1",
2977
- [blockId]
2978
- );
2979
- await conn.run(
2980
- "DELETE FROM trades.reporting_data WHERE block_id = $1",
2981
- [blockId]
2982
- );
2976
+ await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
2977
+ await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
2983
2978
  await deleteSyncMetadata(conn, blockId, blocksDir);
2984
2979
  await conn.run("COMMIT");
2985
2980
  } catch {
@@ -3009,10 +3004,11 @@ async function detectBlockChanges(conn, baseDir) {
3009
3004
  for (const entry of entries) {
3010
3005
  if (!entry.isDirectory()) continue;
3011
3006
  if (entry.name.startsWith(".") || entry.name.startsWith("_")) continue;
3012
- if (entry.name.endsWith(".tmp") || entry.name.endsWith(".duckdb") || entry.name.endsWith(".duckdb.tmp")) continue;
3007
+ if (entry.name.endsWith(".tmp") || entry.name.endsWith(".duckdb") || entry.name.endsWith(".duckdb.tmp"))
3008
+ continue;
3013
3009
  const blockId = entry.name;
3014
3010
  folderNames.add(blockId);
3015
- const blockPath = path10.join(baseDir, blockId);
3011
+ const blockPath = path11.join(baseDir, blockId);
3016
3012
  if (!syncedBlockIds.has(blockId)) {
3017
3013
  const tradelog = await findTradelogFile(blockPath);
3018
3014
  if (tradelog) {
@@ -3026,7 +3022,7 @@ async function detectBlockChanges(conn, baseDir) {
3026
3022
  continue;
3027
3023
  }
3028
3024
  try {
3029
- const tradelogPath = path10.join(blockPath, tradelogFilename);
3025
+ const tradelogPath = path11.join(blockPath, tradelogFilename);
3030
3026
  const currentHash = versionedHash(await hashFileContent(tradelogPath));
3031
3027
  const metadata = await getSyncMetadata(conn, blockId, baseDir);
3032
3028
  if (!metadata || metadata.tradelog_hash !== currentHash) {
@@ -3034,7 +3030,7 @@ async function detectBlockChanges(conn, baseDir) {
3034
3030
  } else {
3035
3031
  const optionalLogs = await findOptionalLogFiles(blockPath);
3036
3032
  if (optionalLogs.reportinglog) {
3037
- const reportinglogPath = path10.join(blockPath, optionalLogs.reportinglog);
3033
+ const reportinglogPath = path11.join(blockPath, optionalLogs.reportinglog);
3038
3034
  const reportingHash = versionedHash(await hashFileContent(reportinglogPath));
3039
3035
  if (metadata.reportinglog_hash !== reportingHash) {
3040
3036
  toSync.push(blockId);
@@ -3058,14 +3054,8 @@ async function cleanupDeletedBlocks(conn, deletedBlockIds, blocksDir) {
3058
3054
  for (const blockId of deletedBlockIds) {
3059
3055
  await conn.run("BEGIN TRANSACTION");
3060
3056
  try {
3061
- await conn.run(
3062
- "DELETE FROM trades.trade_data WHERE block_id = $1",
3063
- [blockId]
3064
- );
3065
- await conn.run(
3066
- "DELETE FROM trades.reporting_data WHERE block_id = $1",
3067
- [blockId]
3068
- );
3057
+ await conn.run("DELETE FROM trades.trade_data WHERE block_id = $1", [blockId]);
3058
+ await conn.run("DELETE FROM trades.reporting_data WHERE block_id = $1", [blockId]);
3069
3059
  await deleteSyncMetadata(conn, blockId, blocksDir);
3070
3060
  await conn.run("COMMIT");
3071
3061
  } catch (err) {
@@ -3082,7 +3072,7 @@ function setBlocksDir(dir) {
3082
3072
  }
3083
3073
  function getBlocksDir(baseDir) {
3084
3074
  if (_blocksDir) return _blocksDir;
3085
- const nestedBlocksDir = path11.join(baseDir, "blocks");
3075
+ const nestedBlocksDir = path12.join(baseDir, "blocks");
3086
3076
  return existsSync2(nestedBlocksDir) ? nestedBlocksDir : baseDir;
3087
3077
  }
3088
3078
  async function syncAllBlocks(baseDir) {
@@ -3101,7 +3091,7 @@ async function syncAllBlocks(baseDir) {
3101
3091
  }
3102
3092
  }
3103
3093
  for (const blockId of toSync) {
3104
- const blockPath = path11.join(blocksDir, blockId);
3094
+ const blockPath = path12.join(blocksDir, blockId);
3105
3095
  const result = await syncBlockInternal(conn, blockId, blockPath);
3106
3096
  results.push(result);
3107
3097
  if (result.status === "error" && result.error) {
@@ -3120,7 +3110,7 @@ async function syncAllBlocks(baseDir) {
3120
3110
  async function syncBlock(blockId, baseDir) {
3121
3111
  const conn = await getConnection(baseDir);
3122
3112
  const blocksDir = getBlocksDir(baseDir);
3123
- const blockPath = path11.join(blocksDir, blockId);
3113
+ const blockPath = path12.join(blocksDir, blockId);
3124
3114
  try {
3125
3115
  await fs9.access(blockPath);
3126
3116
  } catch {
@@ -3183,4 +3173,4 @@ export {
3183
3173
  loadReportingLog,
3184
3174
  importCsv
3185
3175
  };
3186
- //# sourceMappingURL=chunk-NZO6PT64.js.map
3176
+ //# sourceMappingURL=chunk-RM4B2VKS.js.map