@tradejs/cli 3.0.1 → 3.1.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.
@@ -32,6 +32,8 @@ __export(aiPocketSearch_exports, {
32
32
  summarizeAiPocketRows: () => summarizeAiPocketRows
33
33
  });
34
34
  module.exports = __toCommonJS(aiPocketSearch_exports);
35
+
36
+ // src/lib/aiPocketSearch/features.ts
35
37
  var DAY_MS = 24 * 60 * 60 * 1e3;
36
38
  var DAYS_PER_WEEK = 7;
37
39
  var DAYS_PER_MONTH = 30.4375;
@@ -674,6 +676,8 @@ var collectAiPocketFeatureSnapshot = ({
674
676
  return { features, featureCoverage };
675
677
  };
676
678
  var collectAiPocketFeatures = (options) => collectAiPocketFeatureSnapshot(options).features;
679
+
680
+ // src/lib/aiPocketSearch/summary.ts
677
681
  var formatNumber = (value) => {
678
682
  if (Number.isInteger(value)) {
679
683
  return String(value);
@@ -970,6 +974,8 @@ var summarizeAiPocketFeatureCoverage = (rows, family) => {
970
974
  maxTimestamp
971
975
  };
972
976
  };
977
+
978
+ // src/lib/aiPocketSearch/predicates.ts
973
979
  var matchesPredicate = (value, predicate) => {
974
980
  if (predicate.kind === "numeric") {
975
981
  if (!isFiniteNumber(value)) {
@@ -1218,6 +1224,8 @@ var buildAiPocketPredicateResult = (rows, options = {}) => {
1218
1224
  return { featureKeys: buckets.size, predicates };
1219
1225
  };
1220
1226
  var buildAiPocketPredicates = (rows, options = {}) => buildAiPocketPredicateResult(rows, options).predicates.map(toPublicPredicate);
1227
+
1228
+ // src/lib/aiPocketSearch/searchEngine.ts
1221
1229
  var scorePositivePocket = (summary) => {
1222
1230
  const profitFactor = summary.profitFactor ?? (summary.grossLoss === 0 ? 8 : 0);
1223
1231
  const winRate = summary.winRate ?? 0;
@@ -1796,6 +1804,8 @@ var searchAiPockets = (rows, options = {}) => {
1796
1804
  }
1797
1805
  };
1798
1806
  };
1807
+
1808
+ // src/lib/aiPocketSearch/markdownReport.ts
1799
1809
  var formatMdNumber = (value, digits = 2) => value == null || !Number.isFinite(value) ? "n/a" : value.toFixed(digits);
1800
1810
  var formatMdPercent = (value) => value == null || !Number.isFinite(value) ? "n/a" : `${(value * 100).toFixed(1)}%`;
1801
1811
  var escapeMarkdownCell = (value) => String(value ?? "n/a").replace(/\|/g, "\\|").replace(/\n/g, "<br>");
@@ -346,28 +346,37 @@ var import_types = require("@tradejs/types");
346
346
 
347
347
  // src/lib/strategyGateFingerprint.ts
348
348
  var import_node_crypto = require("crypto");
349
+ var import_node_module = require("module");
349
350
  var import_promises = __toESM(require("fs/promises"));
350
351
  var import_node_path = __toESM(require("path"));
351
- var gateFingerprintRelativePaths = (strategyName) => [
352
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
353
- `packages/strategies/src/${strategyName}/guardrails.ts`,
354
- `packages/strategies/src/${strategyName}/pockets.ts`,
355
- `packages/strategies/src/${strategyName}/config.ts`,
356
- "packages/strategies/src/shared/localAiGate.ts",
357
- "packages/node/src/ai.ts",
358
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
352
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
353
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
354
+ var gateFingerprintSpecifiers = (strategyName) => [
355
+ getStrategyPackageName(strategyName),
356
+ "@tradejs/strategy-kit/ai-gate",
357
+ "@tradejs/node/ai",
358
+ "@tradejs/core/strategies"
359
359
  ];
360
360
  var resolveStrategyGateFingerprint = async ({
361
361
  projectRoot,
362
362
  strategyName,
363
363
  gitSha
364
364
  }) => {
365
- const candidates = await Promise.all(
366
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
367
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
368
- return content == null ? null : { relativePath, content };
365
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
366
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
367
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
368
+ const candidates = requireFromProject ? await Promise.all(
369
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
370
+ let resolvedPath;
371
+ try {
372
+ resolvedPath = requireFromProject.resolve(specifier);
373
+ } catch {
374
+ return null;
375
+ }
376
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
377
+ return content == null ? null : { specifier, content };
369
378
  })
370
- );
379
+ ) : [];
371
380
  const sourceEntries = candidates.filter(
372
381
  (entry) => entry != null
373
382
  );
@@ -375,7 +384,7 @@ var resolveStrategyGateFingerprint = async ({
375
384
  hash.update(strategyName);
376
385
  if (sourceEntries.length) {
377
386
  for (const entry of sourceEntries) {
378
- hash.update(entry.relativePath);
387
+ hash.update(entry.specifier);
379
388
  hash.update(entry.content);
380
389
  }
381
390
  } else {
@@ -383,7 +392,7 @@ var resolveStrategyGateFingerprint = async ({
383
392
  }
384
393
  return {
385
394
  gateFingerprint: hash.digest("hex").slice(0, 16),
386
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
395
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
387
396
  };
388
397
  };
389
398
 
@@ -46,7 +46,7 @@ module.exports = __toCommonJS(coreResearch_exports);
46
46
 
47
47
  // src/lib/coreResearch/orchestrator.ts
48
48
  var import_promises4 = __toESM(require("fs/promises"));
49
- var import_node_path5 = __toESM(require("path"));
49
+ var import_node_path6 = __toESM(require("path"));
50
50
  var import_node_child_process = require("child_process");
51
51
  var import_node_crypto5 = require("crypto");
52
52
  var import_coreResearch = require("@tradejs/infra/coreResearch");
@@ -2116,6 +2116,10 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
2116
2116
  };
2117
2117
  };
2118
2118
 
2119
+ // src/lib/researchRoots.ts
2120
+ var import_node_path5 = __toESM(require("path"));
2121
+ var SOURCE_REPOSITORY_ROOT_ENV = "TRADEJS_SOURCE_REPOSITORY_ROOT";
2122
+
2119
2123
  // src/lib/coreResearch/orchestrator.ts
2120
2124
  var summarizeSupplementalFiles = async (params) => {
2121
2125
  const loaded = await readCoreResearchVariant({
@@ -2308,7 +2312,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2308
2312
  const primarySourceHashes = Object.fromEntries(
2309
2313
  analyses.flatMap(
2310
2314
  (analysis) => analysis.files.map((file) => [
2311
- import_node_path5.default.relative(paths.researchDir, file.path),
2315
+ import_node_path6.default.relative(paths.researchDir, file.path),
2312
2316
  file.sha256
2313
2317
  ])
2314
2318
  )
@@ -2327,8 +2331,8 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2327
2331
  const supplementalSourceHashes = Object.fromEntries(
2328
2332
  await Promise.all(
2329
2333
  supplementalSourcePaths.map(async (filePath) => [
2330
- import_node_path5.default.relative(paths.researchDir, import_node_path5.default.resolve(filePath)),
2331
- await sha256File(import_node_path5.default.resolve(filePath))
2334
+ import_node_path6.default.relative(paths.researchDir, import_node_path6.default.resolve(filePath)),
2335
+ await sha256File(import_node_path6.default.resolve(filePath))
2332
2336
  ])
2333
2337
  )
2334
2338
  );
@@ -2405,7 +2409,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2405
2409
  "trades.jsonl": await sha256File(paths.tradesPath),
2406
2410
  "report.html": await sha256File(paths.reportPath)
2407
2411
  };
2408
- const resolvedRunsPath = import_node_path5.default.join(paths.researchDir, "resolved-runs.json");
2412
+ const resolvedRunsPath = import_node_path6.default.join(paths.researchDir, "resolved-runs.json");
2409
2413
  try {
2410
2414
  artifactHashes["resolved-runs.json"] = await sha256File(resolvedRunsPath);
2411
2415
  } catch (error) {
@@ -2415,7 +2419,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2415
2419
  for (const name of await import_promises4.default.readdir(paths.runLogDir)) {
2416
2420
  if (!name.endsWith(".log")) continue;
2417
2421
  artifactHashes[`runs/${name}`] = await sha256File(
2418
- import_node_path5.default.join(paths.runLogDir, name)
2422
+ import_node_path6.default.join(paths.runLogDir, name)
2419
2423
  );
2420
2424
  }
2421
2425
  } catch (error) {
@@ -2472,12 +2476,14 @@ var analyzeCoreResearch = async (spec, options = {}) => {
2472
2476
  }
2473
2477
  };
2474
2478
  var createCoreResearchSpecTemplate = (params) => {
2475
- const rootDir = "data/research/core";
2476
- const projectRoot = process.cwd();
2479
+ const rootDir = import_node_path6.default.relative(
2480
+ import_node_path6.default.resolve(params.projectRoot),
2481
+ import_node_path6.default.join(import_node_path6.default.resolve(params.projectRoot), "data", "research", "core")
2482
+ ).replace(/\\/g, "/");
2477
2483
  const lineage = (() => {
2478
2484
  try {
2479
2485
  const gitSha = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
2480
- cwd: projectRoot,
2486
+ cwd: params.sourceRepositoryRoot,
2481
2487
  encoding: "utf8",
2482
2488
  stdio: ["ignore", "pipe", "ignore"]
2483
2489
  }).trim();
@@ -2485,13 +2491,23 @@ var createCoreResearchSpecTemplate = (params) => {
2485
2491
  "git",
2486
2492
  ["diff", "--binary", "--no-ext-diff", "HEAD"],
2487
2493
  {
2488
- cwd: projectRoot,
2494
+ cwd: params.sourceRepositoryRoot,
2489
2495
  encoding: "utf8",
2490
2496
  stdio: ["ignore", "pipe", "ignore"]
2491
2497
  }
2492
2498
  );
2499
+ const sourceRepository = (0, import_node_child_process.execFileSync)(
2500
+ "git",
2501
+ ["remote", "get-url", "origin"],
2502
+ {
2503
+ cwd: params.sourceRepositoryRoot,
2504
+ encoding: "utf8",
2505
+ stdio: ["ignore", "pipe", "ignore"]
2506
+ }
2507
+ ).trim();
2493
2508
  return {
2494
2509
  gitSha,
2510
+ ...sourceRepository ? { sourceRepository } : {},
2495
2511
  ...dirtyDiff ? {
2496
2512
  dirtyDiffSha256: (0, import_node_crypto5.createHash)("sha256").update(dirtyDiff).digest("hex")
2497
2513
  } : {}
@@ -2592,11 +2608,11 @@ var createCoreResearchSpecTemplate = (params) => {
2592
2608
  };
2593
2609
  var runCommand = async (params) => {
2594
2610
  if (!params.command.length) throw new Error("Cannot run an empty command");
2595
- await import_promises4.default.mkdir(import_node_path5.default.dirname(params.logPath), { recursive: true });
2611
+ await import_promises4.default.mkdir(import_node_path6.default.dirname(params.logPath), { recursive: true });
2596
2612
  const chunks = [];
2597
2613
  const child = (0, import_node_child_process.spawn)(params.command[0], params.command.slice(1), {
2598
2614
  cwd: params.cwd,
2599
- env: process.env,
2615
+ env: { ...process.env, ...params.env },
2600
2616
  stdio: ["ignore", "pipe", "pipe"]
2601
2617
  });
2602
2618
  const capture = (chunk) => {
@@ -2664,7 +2680,7 @@ var validateCoreResearchRunCommand = (params) => {
2664
2680
  };
2665
2681
  var runCoreResearch = async (params) => {
2666
2682
  const { spec } = params;
2667
- const cwd = import_node_path5.default.resolve(params.cwd ?? process.cwd());
2683
+ const cwd = import_node_path6.default.resolve(params.cwd ?? process.cwd());
2668
2684
  const prepared = await prepareCoreResearch(spec);
2669
2685
  const resolvedVariants = [];
2670
2686
  for (const variant of spec.variants) {
@@ -2682,7 +2698,7 @@ var runCoreResearch = async (params) => {
2682
2698
  artifactHashes: { variant: sha256Json(variant) }
2683
2699
  });
2684
2700
  let runId = "";
2685
- const backtestLogPath = import_node_path5.default.join(
2701
+ const backtestLogPath = import_node_path6.default.join(
2686
2702
  prepared.paths.runLogDir,
2687
2703
  `${variant.id}-backtest.log`
2688
2704
  );
@@ -2691,6 +2707,14 @@ var runCoreResearch = async (params) => {
2691
2707
  command: variant.command,
2692
2708
  cwd,
2693
2709
  logPath: backtestLogPath,
2710
+ env: {
2711
+ PROJECT_CWD: cwd,
2712
+ ...params.sourceRepositoryRoot ? {
2713
+ [SOURCE_REPOSITORY_ROOT_ENV]: import_node_path6.default.resolve(
2714
+ params.sourceRepositoryRoot
2715
+ )
2716
+ } : {}
2717
+ },
2694
2718
  onLine: (line) => {
2695
2719
  const match = line.match(
2696
2720
  /backtest run id:\s*([0-9]{12}-[a-f0-9]{8})/i
@@ -2701,12 +2725,12 @@ var runCoreResearch = async (params) => {
2701
2725
  if (!runId) {
2702
2726
  throw new Error(`Backtest for ${variant.id} did not report a run id`);
2703
2727
  }
2704
- const exportLogPath = import_node_path5.default.join(
2728
+ const exportLogPath = import_node_path6.default.join(
2705
2729
  prepared.paths.runLogDir,
2706
2730
  `${variant.id}-export.log`
2707
2731
  );
2708
2732
  const exportParts = [];
2709
- const cliPath = import_node_path5.default.resolve(process.argv[1]);
2733
+ const cliPath = import_node_path6.default.resolve(process.argv[1]);
2710
2734
  await runCommand({
2711
2735
  command: [
2712
2736
  process.execPath,
@@ -2723,9 +2747,17 @@ var runCoreResearch = async (params) => {
2723
2747
  ],
2724
2748
  cwd,
2725
2749
  logPath: exportLogPath,
2750
+ env: {
2751
+ PROJECT_CWD: cwd,
2752
+ ...params.sourceRepositoryRoot ? {
2753
+ [SOURCE_REPOSITORY_ROOT_ENV]: import_node_path6.default.resolve(
2754
+ params.sourceRepositoryRoot
2755
+ )
2756
+ } : {}
2757
+ },
2726
2758
  onLine: (line) => {
2727
2759
  const match = line.match(/^part\d+:\s+(.+)$/);
2728
- if (match) exportParts.push(import_node_path5.default.resolve(cwd, match[1].trim()));
2760
+ if (match) exportParts.push(import_node_path6.default.resolve(cwd, match[1].trim()));
2729
2761
  }
2730
2762
  });
2731
2763
  if (!exportParts.length) {
@@ -2736,7 +2768,7 @@ var runCoreResearch = async (params) => {
2736
2768
  const traceFiles = await (0, import_coreResearch.listCoreResearchTraceFiles)({
2737
2769
  strategyName: spec.strategy,
2738
2770
  runId,
2739
- outDir: import_node_path5.default.resolve(cwd, "data/research/core/trace")
2771
+ outDir: import_node_path6.default.resolve(cwd, "data/research/core/trace")
2740
2772
  });
2741
2773
  resolvedVariants.push({
2742
2774
  ...variant,
@@ -2756,7 +2788,7 @@ var runCoreResearch = async (params) => {
2756
2788
  ...Object.fromEntries(
2757
2789
  await Promise.all(
2758
2790
  exportParts.map(async (filePath) => [
2759
- import_node_path5.default.basename(filePath),
2791
+ import_node_path6.default.basename(filePath),
2760
2792
  await sha256File(filePath)
2761
2793
  ])
2762
2794
  )
@@ -2775,7 +2807,7 @@ var runCoreResearch = async (params) => {
2775
2807
  }
2776
2808
  }
2777
2809
  await writeJsonAtomic(
2778
- import_node_path5.default.join(prepared.paths.researchDir, "resolved-runs.json"),
2810
+ import_node_path6.default.join(prepared.paths.researchDir, "resolved-runs.json"),
2779
2811
  {
2780
2812
  schema: "tradejs-core-research-resolved-runs/v1",
2781
2813
  researchId: spec.researchId,
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var researchAgent_exports = {};
22
22
  __export(researchAgent_exports, {
23
23
  RESEARCH_AGENT_BRANCH_PREFIX: () => RESEARCH_AGENT_BRANCH_PREFIX,
24
+ RESEARCH_AGENT_DEFAULT_GITHUB_ORGANIZATION: () => RESEARCH_AGENT_DEFAULT_GITHUB_ORGANIZATION,
24
25
  RESEARCH_AGENT_MODEL: () => RESEARCH_AGENT_MODEL,
25
26
  RESEARCH_AGENT_REASONING_EFFORT: () => RESEARCH_AGENT_REASONING_EFFORT,
26
27
  assertDiffAllowed: () => assertDiffAllowed,
@@ -29,6 +30,8 @@ __export(researchAgent_exports, {
29
30
  buildResearchAgentPrBody: () => buildResearchAgentPrBody,
30
31
  buildResearchAgentPrTitle: () => buildResearchAgentPrTitle,
31
32
  getResearchAgentAllowedPathPrefixes: () => getResearchAgentAllowedPathPrefixes,
33
+ getResearchAgentRepository: () => getResearchAgentRepository,
34
+ getResearchAgentRepositoryName: () => getResearchAgentRepositoryName,
32
35
  normalizeDiffOutput: () => normalizeDiffOutput,
33
36
  parseChangedFilesFromDiff: () => parseChangedFilesFromDiff,
34
37
  parseGithubRepositoryFromRemote: () => parseGithubRepositoryFromRemote
@@ -37,6 +40,7 @@ module.exports = __toCommonJS(researchAgent_exports);
37
40
  var RESEARCH_AGENT_MODEL = "openai/gpt-5.4";
38
41
  var RESEARCH_AGENT_REASONING_EFFORT = "medium";
39
42
  var RESEARCH_AGENT_BRANCH_PREFIX = "codex/research";
43
+ var RESEARCH_AGENT_DEFAULT_GITHUB_ORGANIZATION = "TradeJS-Dev";
40
44
  var buildResearchAgentBranchName = (strategy, runId) => {
41
45
  const normalizedStrategy = strategy.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
42
46
  const normalizedRunId = runId.trim().replace(/[^a-zA-Z0-9-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
@@ -44,8 +48,15 @@ var buildResearchAgentBranchName = (strategy, runId) => {
44
48
  };
45
49
  var buildResearchAgentCommitMessage = (strategy, runId) => `Research agent: ${strategy} follow-up for ${runId}`;
46
50
  var buildResearchAgentPrTitle = (strategy, runId) => `Research agent: ${strategy} follow-up for ${runId}`;
51
+ var getResearchAgentRepositoryName = (strategy) => {
52
+ if (strategy === "TrendLine" || strategy === "ReverseTrendLine") {
53
+ return "TradeJS-Strategy-TrendLine";
54
+ }
55
+ return `TradeJS-Strategy-${strategy}`;
56
+ };
57
+ var getResearchAgentRepository = (strategy, organization = RESEARCH_AGENT_DEFAULT_GITHUB_ORGANIZATION) => `${organization}/${getResearchAgentRepositoryName(strategy)}`;
47
58
  var getResearchAgentAllowedPathPrefixes = (strategy) => [
48
- `packages/strategies/src/${strategy}/`
59
+ `src/${strategy}/`
49
60
  ];
50
61
  var parseGithubRepositoryFromRemote = (value) => {
51
62
  const trimmed = value.trim();
@@ -99,7 +110,7 @@ var buildResearchAgentPrBody = (params) => {
99
110
  lines.push("");
100
111
  lines.push("## Notes");
101
112
  lines.push("- Created automatically by the TradeJS research agent.");
102
- lines.push("- Base branch: `stable`.");
113
+ lines.push("- Base branch: `main`.");
103
114
  return lines.join("\n");
104
115
  };
105
116
  var normalizeDiffOutput = (value) => {
@@ -154,6 +165,7 @@ ${diffText}`)) {
154
165
  // Annotate the CommonJS export names for ESM import in node:
155
166
  0 && (module.exports = {
156
167
  RESEARCH_AGENT_BRANCH_PREFIX,
168
+ RESEARCH_AGENT_DEFAULT_GITHUB_ORGANIZATION,
157
169
  RESEARCH_AGENT_MODEL,
158
170
  RESEARCH_AGENT_REASONING_EFFORT,
159
171
  assertDiffAllowed,
@@ -162,6 +174,8 @@ ${diffText}`)) {
162
174
  buildResearchAgentPrBody,
163
175
  buildResearchAgentPrTitle,
164
176
  getResearchAgentAllowedPathPrefixes,
177
+ getResearchAgentRepository,
178
+ getResearchAgentRepositoryName,
165
179
  normalizeDiffOutput,
166
180
  parseChangedFilesFromDiff,
167
181
  parseGithubRepositoryFromRemote
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/lib/researchRoots.ts
31
+ var researchRoots_exports = {};
32
+ __export(researchRoots_exports, {
33
+ SOURCE_REPOSITORY_ROOT_ENV: () => SOURCE_REPOSITORY_ROOT_ENV,
34
+ resolveResearchRoots: () => resolveResearchRoots
35
+ });
36
+ module.exports = __toCommonJS(researchRoots_exports);
37
+ var import_node_path = __toESM(require("path"));
38
+ var SOURCE_REPOSITORY_ROOT_ENV = "TRADEJS_SOURCE_REPOSITORY_ROOT";
39
+ var firstNonEmpty = (...values) => values.map((value) => String(value || "").trim()).find(Boolean);
40
+ var resolveResearchRoots = (options = {}) => {
41
+ const cwd = import_node_path.default.resolve(options.cwd || process.cwd());
42
+ const env = options.env || process.env;
43
+ const projectRoot = import_node_path.default.resolve(
44
+ firstNonEmpty(options.projectRoot, env.PROJECT_CWD, cwd) || cwd
45
+ );
46
+ const sourceRepositoryRoot = import_node_path.default.resolve(
47
+ firstNonEmpty(
48
+ options.sourceRepositoryRoot,
49
+ env[SOURCE_REPOSITORY_ROOT_ENV],
50
+ cwd
51
+ ) || cwd
52
+ );
53
+ return { projectRoot, sourceRepositoryRoot };
54
+ };
55
+ // Annotate the CommonJS export names for ESM import in node:
56
+ 0 && (module.exports = {
57
+ SOURCE_REPOSITORY_ROOT_ENV,
58
+ resolveResearchRoots
59
+ });
@@ -47,28 +47,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
47
47
 
48
48
  // src/lib/strategyGateFingerprint.ts
49
49
  var import_node_crypto = require("crypto");
50
+ var import_node_module = require("module");
50
51
  var import_promises = __toESM(require("fs/promises"));
51
52
  var import_node_path = __toESM(require("path"));
52
- var gateFingerprintRelativePaths = (strategyName) => [
53
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
54
- `packages/strategies/src/${strategyName}/guardrails.ts`,
55
- `packages/strategies/src/${strategyName}/pockets.ts`,
56
- `packages/strategies/src/${strategyName}/config.ts`,
57
- "packages/strategies/src/shared/localAiGate.ts",
58
- "packages/node/src/ai.ts",
59
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
53
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
54
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
55
+ var gateFingerprintSpecifiers = (strategyName) => [
56
+ getStrategyPackageName(strategyName),
57
+ "@tradejs/strategy-kit/ai-gate",
58
+ "@tradejs/node/ai",
59
+ "@tradejs/core/strategies"
60
60
  ];
61
61
  var resolveStrategyGateFingerprint = async ({
62
62
  projectRoot,
63
63
  strategyName,
64
64
  gitSha
65
65
  }) => {
66
- const candidates = await Promise.all(
67
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
68
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
69
- return content == null ? null : { relativePath, content };
66
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
67
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
68
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
69
+ const candidates = requireFromProject ? await Promise.all(
70
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
71
+ let resolvedPath;
72
+ try {
73
+ resolvedPath = requireFromProject.resolve(specifier);
74
+ } catch {
75
+ return null;
76
+ }
77
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
78
+ return content == null ? null : { specifier, content };
70
79
  })
71
- );
80
+ ) : [];
72
81
  const sourceEntries = candidates.filter(
73
82
  (entry) => entry != null
74
83
  );
@@ -76,7 +85,7 @@ var resolveStrategyGateFingerprint = async ({
76
85
  hash.update(strategyName);
77
86
  if (sourceEntries.length) {
78
87
  for (const entry of sourceEntries) {
79
- hash.update(entry.relativePath);
88
+ hash.update(entry.specifier);
80
89
  hash.update(entry.content);
81
90
  }
82
91
  } else {
@@ -84,7 +93,7 @@ var resolveStrategyGateFingerprint = async ({
84
93
  }
85
94
  return {
86
95
  gateFingerprint: hash.digest("hex").slice(0, 16),
87
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
96
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
88
97
  };
89
98
  };
90
99
 
@@ -263,14 +272,29 @@ var resolveRuntimeGateFingerprint = async ({
263
272
  gateFingerprintCache.set(cacheKey, result);
264
273
  return result;
265
274
  };
266
- var buildRuntimeLineage = async ({
275
+ async function buildRuntimeLineage({
267
276
  projectRoot,
268
277
  strategyName,
269
278
  compositionId,
279
+ releaseVersion,
280
+ strategyPackageVersion,
281
+ runtimePackageVersion,
270
282
  config,
271
283
  runContext,
272
284
  env = process.env
273
- }) => {
285
+ }) {
286
+ if (releaseVersion != null) {
287
+ if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
288
+ throw new Error(`Invalid runtime releaseVersion: ${releaseVersion}`);
289
+ }
290
+ return {
291
+ schemaVersion: 2,
292
+ releaseVersion,
293
+ strategyPackageVersion,
294
+ runtimePackageVersion,
295
+ maxLossValue: resolveRuntimeMaxLossValue(config)
296
+ };
297
+ }
274
298
  const git = resolveGitLineage(projectRoot);
275
299
  const hyperliquidPerpUniverseFingerprint = typeof import_strategies.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
276
300
  projectRoot,
@@ -305,8 +329,8 @@ var buildRuntimeLineage = async ({
305
329
  contextFingerprint: fingerprintRuntimeValue(context),
306
330
  maxLossValue: resolveRuntimeMaxLossValue(config)
307
331
  };
308
- };
309
- var runtimeLineageKey = (lineage) => [
332
+ }
333
+ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
310
334
  lineage.schemaVersion,
311
335
  lineage.compositionId ?? "unbound-composition",
312
336
  lineage.gitSha ?? "unknown",
@@ -41,7 +41,7 @@ var buildRuntimeModeStrategyConfig = ({
41
41
  ...strategyConfig,
42
42
  ENV: env,
43
43
  MAKE_ORDERS: makeOrders,
44
- INTERVAL: interval,
44
+ INTERVAL: strategyConfig.INTERVAL ?? interval,
45
45
  ...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
46
46
  ...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
47
47
  });
@@ -63,7 +63,8 @@ var toRuntimeSignalBucketRef = (signal) => ({
63
63
  symbol: signal.symbol,
64
64
  strategy: signal.strategy,
65
65
  timestamp: signal.timestamp,
66
- ...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {}
66
+ ...signal.runtimeConfigId && signal.runtimeConfigId !== "config" ? { runtimeConfigId: signal.runtimeConfigId } : {},
67
+ ...signal.runtimeReleaseVersion ? { runtimeReleaseVersion: signal.runtimeReleaseVersion } : {}
67
68
  });
68
69
  var shouldStoreRuntimeSignalDiagnostics = (signal) => signal.orderStatus === "completed" || signal.orderStatus === "failed";
69
70
  var toStoredRuntimeSignal = (signal) => {
@@ -30,32 +30,42 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/lib/strategyGateFingerprint.ts
31
31
  var strategyGateFingerprint_exports = {};
32
32
  __export(strategyGateFingerprint_exports, {
33
+ getStrategyPackageName: () => getStrategyPackageName,
33
34
  resolveStrategyGateFingerprint: () => resolveStrategyGateFingerprint
34
35
  });
35
36
  module.exports = __toCommonJS(strategyGateFingerprint_exports);
36
37
  var import_node_crypto = require("crypto");
38
+ var import_node_module = require("module");
37
39
  var import_promises = __toESM(require("fs/promises"));
38
40
  var import_node_path = __toESM(require("path"));
39
- var gateFingerprintRelativePaths = (strategyName) => [
40
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
41
- `packages/strategies/src/${strategyName}/guardrails.ts`,
42
- `packages/strategies/src/${strategyName}/pockets.ts`,
43
- `packages/strategies/src/${strategyName}/config.ts`,
44
- "packages/strategies/src/shared/localAiGate.ts",
45
- "packages/node/src/ai.ts",
46
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
41
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
42
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
43
+ var gateFingerprintSpecifiers = (strategyName) => [
44
+ getStrategyPackageName(strategyName),
45
+ "@tradejs/strategy-kit/ai-gate",
46
+ "@tradejs/node/ai",
47
+ "@tradejs/core/strategies"
47
48
  ];
48
49
  var resolveStrategyGateFingerprint = async ({
49
50
  projectRoot,
50
51
  strategyName,
51
52
  gitSha
52
53
  }) => {
53
- const candidates = await Promise.all(
54
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
55
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
56
- return content == null ? null : { relativePath, content };
54
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
55
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
56
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
57
+ const candidates = requireFromProject ? await Promise.all(
58
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
59
+ let resolvedPath;
60
+ try {
61
+ resolvedPath = requireFromProject.resolve(specifier);
62
+ } catch {
63
+ return null;
64
+ }
65
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
66
+ return content == null ? null : { specifier, content };
57
67
  })
58
- );
68
+ ) : [];
59
69
  const sourceEntries = candidates.filter(
60
70
  (entry) => entry != null
61
71
  );
@@ -63,7 +73,7 @@ var resolveStrategyGateFingerprint = async ({
63
73
  hash.update(strategyName);
64
74
  if (sourceEntries.length) {
65
75
  for (const entry of sourceEntries) {
66
- hash.update(entry.relativePath);
76
+ hash.update(entry.specifier);
67
77
  hash.update(entry.content);
68
78
  }
69
79
  } else {
@@ -71,10 +81,11 @@ var resolveStrategyGateFingerprint = async ({
71
81
  }
72
82
  return {
73
83
  gateFingerprint: hash.digest("hex").slice(0, 16),
74
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
84
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
75
85
  };
76
86
  };
77
87
  // Annotate the CommonJS export names for ESM import in node:
78
88
  0 && (module.exports = {
89
+ getStrategyPackageName,
79
90
  resolveStrategyGateFingerprint
80
91
  });