@nathapp/nax 0.62.0-canary.8 → 0.62.0

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 (2) hide show
  1. package/dist/nax.js +169 -120
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -5404,79 +5404,25 @@ var init_extglob = __esm(() => {
5404
5404
  ];
5405
5405
  });
5406
5406
 
5407
- // src/test-runners/detect/framework-configs.ts
5407
+ // src/test-runners/detect/framework-configs-deps.ts
5408
+ var _frameworkConfigDeps;
5409
+ var init_framework_configs_deps = __esm(() => {
5410
+ _frameworkConfigDeps = {
5411
+ readText: async (path) => {
5412
+ const f = Bun.file(path);
5413
+ if (!await f.exists())
5414
+ return null;
5415
+ return f.text();
5416
+ },
5417
+ parseToml: (text) => Bun.TOML.parse(text),
5418
+ parseYaml: (text) => Bun.YAML.parse(text)
5419
+ };
5420
+ });
5421
+
5422
+ // src/test-runners/detect/framework-configs-python.ts
5408
5423
  function filterExcluded(patterns) {
5409
5424
  return patterns.filter((p) => !EXCLUDE_DIRS.some((d) => p.includes(`/${d}/`) || p.startsWith(`${d}/`)));
5410
5425
  }
5411
- function normalize(patterns) {
5412
- return filterExcluded(expandExtglobAll(patterns));
5413
- }
5414
- async function parseVitestConfig(workdir) {
5415
- const candidates = ["vitest.config.ts", "vitest.config.mts", "vitest.config.js", "vitest.config.mjs"];
5416
- for (const name of candidates) {
5417
- const path = `${workdir}/${name}`;
5418
- const text = await _frameworkConfigDeps.readText(path);
5419
- if (!text)
5420
- continue;
5421
- const includeMatch = text.match(/include\s*:\s*\[([^\]]+)\]/s);
5422
- if (includeMatch) {
5423
- const patterns = extractStringLiterals(includeMatch[1]);
5424
- if (patterns.length > 0) {
5425
- return { type: "framework-config", path, patterns: normalize(patterns) };
5426
- }
5427
- }
5428
- return { type: "framework-config", path, patterns: [] };
5429
- }
5430
- return null;
5431
- }
5432
- async function parseJestConfig(workdir) {
5433
- const candidates = ["jest.config.ts", "jest.config.js", "jest.config.cjs", "jest.config.mjs", "jest.config.json"];
5434
- for (const name of candidates) {
5435
- const path = `${workdir}/${name}`;
5436
- const text = await _frameworkConfigDeps.readText(path);
5437
- if (!text)
5438
- continue;
5439
- if (name.endsWith(".json")) {
5440
- try {
5441
- const config = JSON.parse(text);
5442
- const patterns2 = extractJestPatternsFromObject(config);
5443
- return { type: "framework-config", path, patterns: normalize(patterns2) };
5444
- } catch {}
5445
- }
5446
- const patterns = extractJestPatterns(text);
5447
- return { type: "framework-config", path, patterns: normalize(patterns) };
5448
- }
5449
- const pkgPath = `${workdir}/package.json`;
5450
- const pkgText = await _frameworkConfigDeps.readText(pkgPath);
5451
- if (pkgText) {
5452
- try {
5453
- const pkg = JSON.parse(pkgText);
5454
- const jestConfig = pkg.jest;
5455
- if (jestConfig) {
5456
- const patterns = extractJestPatternsFromObject(jestConfig);
5457
- if (patterns.length > 0) {
5458
- return { type: "framework-config", path: `${pkgPath}#jest`, patterns: normalize(patterns) };
5459
- }
5460
- }
5461
- } catch {}
5462
- }
5463
- return null;
5464
- }
5465
- function extractJestPatterns(text) {
5466
- const matchMatch = text.match(/testMatch\s*:\s*\[([^\]]+)\]/s);
5467
- if (matchMatch) {
5468
- const patterns = extractStringLiterals(matchMatch[1]);
5469
- if (patterns.length > 0)
5470
- return patterns;
5471
- }
5472
- return [];
5473
- }
5474
- function extractJestPatternsFromObject(config) {
5475
- const testMatch = config.testMatch;
5476
- if (Array.isArray(testMatch))
5477
- return testMatch.filter((p) => typeof p === "string");
5478
- return [];
5479
- }
5480
5426
  async function parsePyprojectToml(workdir) {
5481
5427
  const path = `${workdir}/pyproject.toml`;
5482
5428
  const text = await _frameworkConfigDeps.readText(path);
@@ -5510,7 +5456,7 @@ async function parsePyprojectToml(workdir) {
5510
5456
  if (patterns.length === 0) {
5511
5457
  patterns.push("test_*.py", "*_test.py");
5512
5458
  }
5513
- return { type: "framework-config", path, patterns: normalize(patterns) };
5459
+ return { type: "framework-config", framework: "pytest", path, patterns: filterExcluded(patterns) };
5514
5460
  } catch {
5515
5461
  return null;
5516
5462
  }
@@ -5541,10 +5487,94 @@ async function parsePytestIni(workdir) {
5541
5487
  }
5542
5488
  if (patterns.length === 0)
5543
5489
  patterns.push("test_*.py", "*_test.py");
5544
- return { type: "framework-config", path, patterns: normalize(patterns) };
5490
+ return { type: "framework-config", framework: "pytest", path, patterns: filterExcluded(patterns) };
5545
5491
  }
5546
5492
  return null;
5547
5493
  }
5494
+ var EXCLUDE_DIRS;
5495
+ var init_framework_configs_python = __esm(() => {
5496
+ init_framework_configs_deps();
5497
+ EXCLUDE_DIRS = ["node_modules", "dist", "build", ".nax", "coverage", ".git"];
5498
+ });
5499
+
5500
+ // src/test-runners/detect/framework-configs.ts
5501
+ function filterExcluded2(patterns) {
5502
+ return patterns.filter((p) => !EXCLUDE_DIRS2.some((d) => p.includes(`/${d}/`) || p.startsWith(`${d}/`)));
5503
+ }
5504
+ function normalize(patterns) {
5505
+ return filterExcluded2(expandExtglobAll(patterns));
5506
+ }
5507
+ async function parseVitestConfig(workdir) {
5508
+ const candidates = ["vitest.config.ts", "vitest.config.mts", "vitest.config.js", "vitest.config.mjs"];
5509
+ for (const name of candidates) {
5510
+ const path = `${workdir}/${name}`;
5511
+ const text = await _frameworkConfigDeps.readText(path);
5512
+ if (!text)
5513
+ continue;
5514
+ const includeMatch = text.match(/include\s*:\s*\[([^\]]+)\]/s);
5515
+ if (includeMatch) {
5516
+ const patterns = extractStringLiterals(includeMatch[1]);
5517
+ if (patterns.length > 0) {
5518
+ return { type: "framework-config", framework: "vitest", path, patterns: normalize(patterns) };
5519
+ }
5520
+ }
5521
+ return { type: "framework-config", framework: "vitest", path, patterns: [] };
5522
+ }
5523
+ return null;
5524
+ }
5525
+ async function parseJestConfig(workdir) {
5526
+ const candidates = ["jest.config.ts", "jest.config.js", "jest.config.cjs", "jest.config.mjs", "jest.config.json"];
5527
+ for (const name of candidates) {
5528
+ const path = `${workdir}/${name}`;
5529
+ const text = await _frameworkConfigDeps.readText(path);
5530
+ if (!text)
5531
+ continue;
5532
+ if (name.endsWith(".json")) {
5533
+ try {
5534
+ const config = JSON.parse(text);
5535
+ const patterns2 = extractJestPatternsFromObject(config);
5536
+ return { type: "framework-config", framework: "jest", path, patterns: normalize(patterns2) };
5537
+ } catch {}
5538
+ }
5539
+ const patterns = extractJestPatterns(text);
5540
+ return { type: "framework-config", framework: "jest", path, patterns: normalize(patterns) };
5541
+ }
5542
+ const pkgPath = `${workdir}/package.json`;
5543
+ const pkgText = await _frameworkConfigDeps.readText(pkgPath);
5544
+ if (pkgText) {
5545
+ try {
5546
+ const pkg = JSON.parse(pkgText);
5547
+ const jestConfig = pkg.jest;
5548
+ if (jestConfig) {
5549
+ const patterns = extractJestPatternsFromObject(jestConfig);
5550
+ if (patterns.length > 0) {
5551
+ return {
5552
+ type: "framework-config",
5553
+ framework: "jest",
5554
+ path: `${pkgPath}#jest`,
5555
+ patterns: normalize(patterns)
5556
+ };
5557
+ }
5558
+ }
5559
+ } catch {}
5560
+ }
5561
+ return null;
5562
+ }
5563
+ function extractJestPatterns(text) {
5564
+ const matchMatch = text.match(/testMatch\s*:\s*\[([^\]]+)\]/s);
5565
+ if (matchMatch) {
5566
+ const patterns = extractStringLiterals(matchMatch[1]);
5567
+ if (patterns.length > 0)
5568
+ return patterns;
5569
+ }
5570
+ return [];
5571
+ }
5572
+ function extractJestPatternsFromObject(config) {
5573
+ const testMatch = config.testMatch;
5574
+ if (Array.isArray(testMatch))
5575
+ return testMatch.filter((p) => typeof p === "string");
5576
+ return [];
5577
+ }
5548
5578
  async function parseMochaConfig(workdir) {
5549
5579
  const candidates = [".mocharc.js", ".mocharc.cjs", ".mocharc.yaml", ".mocharc.yml", ".mocharc.json"];
5550
5580
  for (const name of candidates) {
@@ -5561,15 +5591,16 @@ async function parseMochaConfig(workdir) {
5561
5591
  } else {
5562
5592
  const specMatch = text.match(/spec\s*:\s*['"]([^'"]+)['"]/);
5563
5593
  if (specMatch) {
5564
- return { type: "framework-config", path, patterns: normalize([specMatch[1]]) };
5594
+ return { type: "framework-config", framework: "mocha", path, patterns: normalize([specMatch[1]]) };
5565
5595
  }
5566
- continue;
5596
+ return { type: "framework-config", framework: "mocha", path, patterns: [] };
5567
5597
  }
5568
5598
  const spec = config.spec;
5569
5599
  const patterns = Array.isArray(spec) ? spec.filter((p) => typeof p === "string") : typeof spec === "string" ? [spec] : [];
5570
5600
  if (patterns.length > 0) {
5571
- return { type: "framework-config", path, patterns: normalize(patterns) };
5601
+ return { type: "framework-config", framework: "mocha", path, patterns: normalize(patterns) };
5572
5602
  }
5603
+ return { type: "framework-config", framework: "mocha", path, patterns: [] };
5573
5604
  } catch {}
5574
5605
  }
5575
5606
  return null;
@@ -5591,9 +5622,9 @@ async function parsePlaywrightConfig(workdir) {
5591
5622
  patterns.push(...extracted);
5592
5623
  }
5593
5624
  if (patterns.length > 0) {
5594
- return { type: "framework-config", path, patterns: normalize(patterns) };
5625
+ return { type: "framework-config", framework: "playwright", path, patterns: normalize(patterns) };
5595
5626
  }
5596
- return { type: "framework-config", path, patterns: ["**/*.spec.ts", "**/*.spec.js"] };
5627
+ return { type: "framework-config", framework: "playwright", path, patterns: [] };
5597
5628
  }
5598
5629
  return null;
5599
5630
  }
@@ -5606,9 +5637,14 @@ async function parseCypressConfig(workdir) {
5606
5637
  continue;
5607
5638
  const specMatch = text.match(/specPattern\s*:\s*['"]([^'"]+)['"]/);
5608
5639
  if (specMatch) {
5609
- return { type: "framework-config", path, patterns: normalize([specMatch[1]]) };
5640
+ return { type: "framework-config", framework: "cypress", path, patterns: normalize([specMatch[1]]) };
5610
5641
  }
5611
- return { type: "framework-config", path, patterns: normalize(["cypress/e2e/**/*.cy.{js,ts}"]) };
5642
+ return {
5643
+ type: "framework-config",
5644
+ framework: "cypress",
5645
+ path,
5646
+ patterns: normalize(["cypress/e2e/**/*.cy.{js,ts}"])
5647
+ };
5612
5648
  }
5613
5649
  return null;
5614
5650
  }
@@ -5638,11 +5674,11 @@ async function parseViteConfig(workdir) {
5638
5674
  if (includeMatch) {
5639
5675
  const patterns = extractStringLiterals(includeMatch[1]);
5640
5676
  if (patterns.length > 0) {
5641
- return { type: "framework-config", path, patterns: normalize(patterns) };
5677
+ return { type: "framework-config", framework: "vitest", path, patterns: normalize(patterns) };
5642
5678
  }
5643
5679
  }
5644
5680
  }
5645
- return { type: "framework-config", path, patterns: [] };
5681
+ return { type: "framework-config", framework: "vitest", path, patterns: [] };
5646
5682
  }
5647
5683
  return null;
5648
5684
  }
@@ -5660,6 +5696,7 @@ async function parseBunfig(workdir) {
5660
5696
  }
5661
5697
  return {
5662
5698
  type: "framework-config",
5699
+ framework: "bun",
5663
5700
  path,
5664
5701
  patterns: normalize([
5665
5702
  "**/*.test.{ts,tsx,js,jsx,mjs,cjs}",
@@ -5703,20 +5740,13 @@ async function detectFromFrameworkConfigs(workdir) {
5703
5740
  ]);
5704
5741
  return results.filter((r) => r !== null);
5705
5742
  }
5706
- var EXCLUDE_DIRS, _frameworkConfigDeps;
5743
+ var EXCLUDE_DIRS2;
5707
5744
  var init_framework_configs = __esm(() => {
5708
5745
  init_extglob();
5709
- EXCLUDE_DIRS = ["node_modules", "dist", "build", ".nax", "coverage", ".git"];
5710
- _frameworkConfigDeps = {
5711
- readText: async (path) => {
5712
- const f = Bun.file(path);
5713
- if (!await f.exists())
5714
- return null;
5715
- return f.text();
5716
- },
5717
- parseToml: (text) => Bun.TOML.parse(text),
5718
- parseYaml: (text) => Bun.YAML.parse(text)
5719
- };
5746
+ init_framework_configs_deps();
5747
+ init_framework_configs_python();
5748
+ init_framework_configs_deps();
5749
+ EXCLUDE_DIRS2 = ["node_modules", "dist", "build", ".nax", "coverage", ".git"];
5720
5750
  });
5721
5751
 
5722
5752
  // src/test-runners/detect/framework-defaults.ts
@@ -5724,58 +5754,71 @@ async function detectFromPackageJson(workdir) {
5724
5754
  const path = `${workdir}/package.json`;
5725
5755
  const text = await _frameworkDefaultsDeps.readText(path);
5726
5756
  if (!text)
5727
- return null;
5757
+ return [];
5728
5758
  let pkg;
5729
5759
  try {
5730
5760
  pkg = JSON.parse(text);
5731
5761
  } catch {
5732
- return null;
5762
+ return [];
5733
5763
  }
5734
5764
  const devDeps = pkg.devDependencies ?? {};
5735
5765
  const deps = pkg.dependencies ?? {};
5736
5766
  const allDeps = { ...deps, ...devDeps };
5737
- for (const [framework, patterns] of Object.entries(JS_FRAMEWORK_DEFAULTS)) {
5738
- if (framework in allDeps) {
5739
- return { type: "manifest", path, patterns: expandExtglobAll(patterns) };
5767
+ const results = [];
5768
+ for (const { depKey, framework, patterns } of JS_FRAMEWORK_DEFAULTS) {
5769
+ if (depKey in allDeps) {
5770
+ results.push({ type: "manifest", framework, path, patterns: expandExtglobAll(patterns) });
5740
5771
  }
5741
5772
  }
5773
+ if (results.length > 0)
5774
+ return results;
5742
5775
  const scripts = pkg.scripts;
5743
5776
  const testScript = typeof scripts?.test === "string" ? scripts.test : "";
5744
5777
  if (testScript.includes("bun test")) {
5745
- return { type: "manifest", path, patterns: expandExtglobAll(BUN_TEST_DEFAULTS) };
5778
+ return [{ type: "manifest", framework: "bun", path, patterns: expandExtglobAll(BUN_TEST_DEFAULTS) }];
5746
5779
  }
5747
- return null;
5780
+ return [];
5748
5781
  }
5749
5782
  async function detectFromGoMod(workdir) {
5750
5783
  const path = `${workdir}/go.mod`;
5751
5784
  if (!await _frameworkDefaultsDeps.fileExists(path))
5752
5785
  return null;
5753
- return { type: "manifest", path, patterns: ["**/*_test.go"] };
5786
+ return { type: "manifest", framework: "go", path, patterns: ["**/*_test.go"] };
5754
5787
  }
5755
5788
  async function detectFromCargoToml(workdir) {
5756
5789
  const path = `${workdir}/Cargo.toml`;
5757
5790
  if (!await _frameworkDefaultsDeps.fileExists(path))
5758
5791
  return null;
5759
- return { type: "manifest", path, patterns: ["tests/**/*.rs", "src/**/*.rs"] };
5792
+ return { type: "manifest", framework: "rust", path, patterns: ["tests/**/*.rs", "src/**/*.rs"] };
5760
5793
  }
5761
5794
  async function detectFromPyprojectDeps(workdir) {
5762
5795
  const path = `${workdir}/pyproject.toml`;
5763
5796
  const text = await _frameworkDefaultsDeps.readText(path);
5764
5797
  if (!text)
5765
5798
  return null;
5766
- if (text.includes("pytest")) {
5767
- return { type: "manifest", path, patterns: ["test_*.py", "*_test.py", "tests/**/*.py"] };
5768
- }
5769
- return null;
5799
+ const PYTEST_DEP_RE = /(?:^[ \t]*["']?pytest(?![-\w]))|(?:["']pytest(?![-\w])(?:[>=~!<][^"']*)?["'])/m;
5800
+ if (!PYTEST_DEP_RE.test(text))
5801
+ return null;
5802
+ return {
5803
+ type: "manifest",
5804
+ framework: "pytest",
5805
+ path,
5806
+ patterns: ["test_*.py", "*_test.py", "tests/**/*.py"]
5807
+ };
5770
5808
  }
5771
5809
  async function detectFromFrameworkDefaults(workdir) {
5772
- const results = await Promise.all([
5810
+ const [pkgJsonSources, goSource, cargoSource, pyprojectSource] = await Promise.all([
5773
5811
  detectFromPackageJson(workdir),
5774
5812
  detectFromGoMod(workdir),
5775
5813
  detectFromCargoToml(workdir),
5776
5814
  detectFromPyprojectDeps(workdir)
5777
5815
  ]);
5778
- return results.filter((r) => r !== null);
5816
+ return [
5817
+ ...pkgJsonSources,
5818
+ ...goSource ? [goSource] : [],
5819
+ ...cargoSource ? [cargoSource] : [],
5820
+ ...pyprojectSource ? [pyprojectSource] : []
5821
+ ];
5779
5822
  }
5780
5823
  var _frameworkDefaultsDeps, JS_FRAMEWORK_DEFAULTS, BUN_TEST_DEFAULTS;
5781
5824
  var init_framework_defaults = __esm(() => {
@@ -5789,14 +5832,18 @@ var init_framework_defaults = __esm(() => {
5789
5832
  },
5790
5833
  fileExists: async (path) => Bun.file(path).exists()
5791
5834
  };
5792
- JS_FRAMEWORK_DEFAULTS = {
5793
- vitest: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
5794
- jest: ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
5795
- mocha: ["test/**/*.{js,mjs,cjs}", "**/*.spec.{js,ts}"],
5796
- jasmine: ["spec/**/*.js"],
5797
- "@playwright/test": ["**/*.spec.ts", "**/*.spec.js"],
5798
- cypress: ["cypress/e2e/**/*.cy.{js,jsx,ts,tsx}"]
5799
- };
5835
+ JS_FRAMEWORK_DEFAULTS = [
5836
+ { depKey: "vitest", framework: "vitest", patterns: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"] },
5837
+ {
5838
+ depKey: "jest",
5839
+ framework: "jest",
5840
+ patterns: ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"]
5841
+ },
5842
+ { depKey: "mocha", framework: "mocha", patterns: ["test/**/*.{js,mjs,cjs}", "**/*.spec.{js,ts}"] },
5843
+ { depKey: "jasmine", framework: "jasmine", patterns: ["spec/**/*.js"] },
5844
+ { depKey: "@playwright/test", framework: "playwright", patterns: ["**/*.spec.ts", "**/*.spec.js"] },
5845
+ { depKey: "cypress", framework: "cypress", patterns: ["cypress/e2e/**/*.cy.{js,jsx,ts,tsx}"] }
5846
+ ];
5800
5847
  BUN_TEST_DEFAULTS = [
5801
5848
  "**/*.test.{ts,tsx,js,jsx,mjs,cjs}",
5802
5849
  "**/*_test.{ts,tsx,js,jsx,mjs,cjs}",
@@ -5848,7 +5895,9 @@ async function detectForDirectory(workdir) {
5848
5895
  const logger = getSafeLogger();
5849
5896
  const tier1Sources = await detectFromFrameworkConfigs(workdir);
5850
5897
  const tier1Patterns = tier1Sources.flatMap((s) => [...s.patterns]);
5851
- const tier2Sources = await detectFromFrameworkDefaults(workdir);
5898
+ const tier1FrameworksWithPatterns = new Set(tier1Sources.filter((s) => s.patterns.length > 0 && s.framework !== undefined).map((s) => s.framework));
5899
+ const tier2SourcesAll = await detectFromFrameworkDefaults(workdir);
5900
+ const tier2Sources = tier2SourcesAll.filter((s) => !s.framework || !tier1FrameworksWithPatterns.has(s.framework));
5852
5901
  const tier2Patterns = tier2Sources.flatMap((s) => [...s.patterns]);
5853
5902
  const tier3Source = await detectFromFileScan(workdir);
5854
5903
  const tier3Patterns = tier3Source ? [...tier3Source.patterns] : [];
@@ -39351,7 +39400,7 @@ var package_default;
39351
39400
  var init_package = __esm(() => {
39352
39401
  package_default = {
39353
39402
  name: "@nathapp/nax",
39354
- version: "0.62.0-canary.8",
39403
+ version: "0.62.0",
39355
39404
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
39356
39405
  type: "module",
39357
39406
  bin: {
@@ -39431,8 +39480,8 @@ var init_version = __esm(() => {
39431
39480
  NAX_VERSION = package_default.version;
39432
39481
  NAX_COMMIT = (() => {
39433
39482
  try {
39434
- if (/^[0-9a-f]{6,10}$/.test("3ae84665"))
39435
- return "3ae84665";
39483
+ if (/^[0-9a-f]{6,10}$/.test("2aa5324d"))
39484
+ return "2aa5324d";
39436
39485
  } catch {}
39437
39486
  try {
39438
39487
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.62.0-canary.8",
3
+ "version": "0.62.0",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {