@wayai/cli 0.3.164 → 0.3.165

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.
package/dist/index.js CHANGED
@@ -17455,40 +17455,214 @@ var init_expected = __esm({
17455
17455
  }
17456
17456
  });
17457
17457
 
17458
- // src/lib/layout.ts
17458
+ // src/lib/fs-safety.ts
17459
17459
  import * as fs from "fs";
17460
17460
  import * as path from "path";
17461
+ function fileHasBytes(abs, data) {
17462
+ let st;
17463
+ try {
17464
+ st = fs.lstatSync(abs);
17465
+ } catch {
17466
+ return false;
17467
+ }
17468
+ if (!st.isFile() || st.isSymbolicLink()) return false;
17469
+ try {
17470
+ return fs.readFileSync(abs).equals(data);
17471
+ } catch {
17472
+ return false;
17473
+ }
17474
+ }
17475
+ function realpathContained(root, abs) {
17476
+ let realRoot;
17477
+ let realAbs;
17478
+ try {
17479
+ realRoot = fs.realpathSync(root);
17480
+ realAbs = fs.realpathSync(abs);
17481
+ } catch {
17482
+ return false;
17483
+ }
17484
+ return realAbs === realRoot || realAbs.startsWith(realRoot + path.sep);
17485
+ }
17486
+ function mkdirTolerateRace(dir) {
17487
+ try {
17488
+ fs.mkdirSync(dir);
17489
+ return true;
17490
+ } catch (err) {
17491
+ if (err.code !== "EEXIST") throw err;
17492
+ let st;
17493
+ try {
17494
+ st = fs.lstatSync(dir);
17495
+ } catch {
17496
+ st = void 0;
17497
+ }
17498
+ return !!st?.isDirectory();
17499
+ }
17500
+ }
17501
+ function ensureRealSubdirNoSymlink(root, target, create) {
17502
+ const rootResolved = path.resolve(root);
17503
+ const targetResolved = path.resolve(target);
17504
+ if (targetResolved !== rootResolved && !targetResolved.startsWith(rootResolved + path.sep)) return false;
17505
+ try {
17506
+ if (!fs.lstatSync(rootResolved).isDirectory()) return false;
17507
+ } catch {
17508
+ return false;
17509
+ }
17510
+ const rel = path.relative(rootResolved, targetResolved);
17511
+ if (rel === "") return true;
17512
+ let cur = rootResolved;
17513
+ for (const segment of rel.split(path.sep)) {
17514
+ cur = path.join(cur, segment);
17515
+ let st;
17516
+ try {
17517
+ st = fs.lstatSync(cur);
17518
+ } catch {
17519
+ st = void 0;
17520
+ }
17521
+ if (st) {
17522
+ if (!st.isDirectory()) return false;
17523
+ } else if (create) {
17524
+ if (!mkdirTolerateRace(cur)) return false;
17525
+ } else {
17526
+ return true;
17527
+ }
17528
+ }
17529
+ return true;
17530
+ }
17531
+ function requireRealSubdirNoSymlink(root, target, create) {
17532
+ if (ensureRealSubdirNoSymlink(root, target, create)) return;
17533
+ throw expected(
17534
+ `${path.relative(path.dirname(root), target)} is reached through a symlink (or a file is in the way). The CLI never reads or writes workspace config through a symlink \u2014 make it a real directory.`
17535
+ );
17536
+ }
17537
+ function requireRealHubFolder(hubFolder, create) {
17538
+ if (!create) {
17539
+ try {
17540
+ fs.lstatSync(hubFolder);
17541
+ } catch {
17542
+ return;
17543
+ }
17544
+ }
17545
+ requireRealSubdirNoSymlink(path.dirname(hubFolder), hubFolder, create);
17546
+ for (const sub of HUB_MANAGED_SUBDIRS) {
17547
+ requireRealSubdirNoSymlink(hubFolder, path.join(hubFolder, sub), false);
17548
+ }
17549
+ for (const name of HUB_CONFIG_FILES) {
17550
+ let st;
17551
+ try {
17552
+ st = fs.lstatSync(path.join(hubFolder, name));
17553
+ } catch {
17554
+ continue;
17555
+ }
17556
+ if (!st.isFile()) {
17557
+ throw expected(
17558
+ `${path.join(path.basename(hubFolder), name)} is a symlink (or not a file). The CLI never reads or writes workspace config through a symlink \u2014 make it a real file.`
17559
+ );
17560
+ }
17561
+ }
17562
+ }
17563
+ function readRealFileOrThrow(root, abs) {
17564
+ let st;
17565
+ try {
17566
+ st = fs.lstatSync(abs);
17567
+ } catch {
17568
+ return null;
17569
+ }
17570
+ const bytes = st.isFile() ? readFileNoFollow(root, abs) : null;
17571
+ if (!bytes) {
17572
+ throw expected(
17573
+ `${path.relative(path.dirname(root), abs)} is a symlink (or reached through one). The CLI never reads or writes workspace config through a symlink \u2014 make it a real file.`
17574
+ );
17575
+ }
17576
+ return bytes.toString("utf-8");
17577
+ }
17578
+ function readFileNoFollow(root, abs) {
17579
+ if (!ensureRealSubdirNoSymlink(root, path.dirname(abs), false)) return null;
17580
+ try {
17581
+ if (!fs.lstatSync(abs).isFile()) return null;
17582
+ return fs.readFileSync(abs);
17583
+ } catch {
17584
+ return null;
17585
+ }
17586
+ }
17587
+ function writeFileNoFollow(root, abs, data) {
17588
+ const parent = path.dirname(abs);
17589
+ if (!ensureRealSubdirNoSymlink(root, parent, true)) return false;
17590
+ let st;
17591
+ try {
17592
+ st = fs.lstatSync(abs);
17593
+ } catch {
17594
+ }
17595
+ if (st?.isSymbolicLink()) fs.rmSync(abs);
17596
+ fs.writeFileSync(abs, data);
17597
+ return true;
17598
+ }
17599
+ function createFileNoFollow(root, abs, data) {
17600
+ if (!ensureRealSubdirNoSymlink(root, path.dirname(abs), true)) return "refused";
17601
+ try {
17602
+ fs.writeFileSync(abs, data, { flag: "wx" });
17603
+ } catch (err) {
17604
+ if (err.code === "EEXIST") return "exists";
17605
+ throw err;
17606
+ }
17607
+ return "created";
17608
+ }
17609
+ var HUB_MANAGED_SUBDIRS, HUB_CONFIG_FILES;
17610
+ var init_fs_safety = __esm({
17611
+ "src/lib/fs-safety.ts"() {
17612
+ "use strict";
17613
+ init_expected();
17614
+ HUB_MANAGED_SUBDIRS = ["agents", "evals", "journeys", "resources", "attachments"];
17615
+ HUB_CONFIG_FILES = ["hub.yaml", "wayai.yaml"];
17616
+ }
17617
+ });
17618
+
17619
+ // src/lib/layout.ts
17620
+ import * as fs2 from "fs";
17621
+ import * as path2 from "path";
17461
17622
  function isDirectory(p) {
17462
17623
  try {
17463
- return fs.statSync(p).isDirectory();
17624
+ return fs2.statSync(p).isDirectory();
17625
+ } catch {
17626
+ return false;
17627
+ }
17628
+ }
17629
+ function isRealDirectory(p) {
17630
+ try {
17631
+ return fs2.lstatSync(p).isDirectory();
17464
17632
  } catch {
17465
17633
  return false;
17466
17634
  }
17467
17635
  }
17468
17636
  function resolveLayout(gitRoot, layout = WAYAI_LAYOUT) {
17469
- const newWs = path.join(gitRoot, layout.wsDir);
17470
- const legacyWs = path.join(gitRoot, layout.legacy.wsDir);
17471
- const legacyOrg = path.join(gitRoot, layout.legacy.orgAtRoot);
17472
- const legacyExists = isDirectory(legacyWs) || isDirectory(legacyOrg);
17473
- const basesDir = path.join(newWs, layout.basesSubdir);
17474
- const hubsDir = path.join(newWs, layout.hubsSubdir);
17475
- const orgDir = path.join(newWs, layout.orgSubdir);
17637
+ const newWs = path2.join(gitRoot, layout.wsDir);
17638
+ const legacyWs = path2.join(gitRoot, layout.legacy.wsDir);
17639
+ const legacyOrg = path2.join(gitRoot, layout.legacy.orgAtRoot);
17640
+ const legacyExists = isRealDirectory(legacyWs) || isRealDirectory(legacyOrg);
17641
+ const basesDir = path2.join(newWs, layout.basesSubdir);
17642
+ const hubsDir = path2.join(newWs, layout.hubsSubdir);
17643
+ const orgDir = path2.join(newWs, layout.orgSubdir);
17476
17644
  const newDisplacesLegacy = () => isDirectory(hubsDir) || isDirectory(orgDir) || isDirectory(basesDir);
17645
+ let resolved;
17477
17646
  if (legacyExists && !newDisplacesLegacy()) {
17478
- return { hubsDir: legacyWs, orgDir: legacyOrg, basesDir, isLegacy: true, legacyAlsoPresent: false };
17647
+ resolved = { hubsDir: legacyWs, orgDir: legacyOrg, basesDir, isLegacy: true, legacyAlsoPresent: false };
17648
+ } else {
17649
+ resolved = { hubsDir, orgDir, basesDir, isLegacy: false, legacyAlsoPresent: legacyExists };
17479
17650
  }
17480
- return { hubsDir, orgDir, basesDir, isLegacy: false, legacyAlsoPresent: legacyExists };
17651
+ for (const dir of [resolved.hubsDir, resolved.orgDir, resolved.basesDir]) {
17652
+ requireRealSubdirNoSymlink(gitRoot, dir, false);
17653
+ }
17654
+ return resolved;
17481
17655
  }
17482
17656
  function resolveBasesDir(gitRoot) {
17483
17657
  return resolveLayout(gitRoot).basesDir;
17484
17658
  }
17485
17659
  function hubsDirLabel(gitRoot) {
17486
- if (!gitRoot) return path.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.hubsSubdir);
17487
- return path.relative(gitRoot, resolveLayout(gitRoot).hubsDir);
17660
+ if (!gitRoot) return path2.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.hubsSubdir);
17661
+ return path2.relative(gitRoot, resolveLayout(gitRoot).hubsDir);
17488
17662
  }
17489
17663
  function basesDirLabel(gitRoot) {
17490
- if (!gitRoot) return path.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.basesSubdir);
17491
- return path.relative(gitRoot, resolveLayout(gitRoot).basesDir);
17664
+ if (!gitRoot) return path2.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.basesSubdir);
17665
+ return path2.relative(gitRoot, resolveLayout(gitRoot).basesDir);
17492
17666
  }
17493
17667
  function warnLayoutOnce(gitRoot) {
17494
17668
  const r = resolveLayout(gitRoot);
@@ -17516,6 +17690,7 @@ var init_layout = __esm({
17516
17690
  "src/lib/layout.ts"() {
17517
17691
  "use strict";
17518
17692
  init_dist();
17693
+ init_fs_safety();
17519
17694
  WAYAI_LAYOUT = {
17520
17695
  ...WAYAI_WORKSPACE_LAYOUT,
17521
17696
  legacy: { wsDir: "workspace", orgAtRoot: "org" }
@@ -17550,8 +17725,8 @@ __export(workspace_exports, {
17550
17725
  scanWorkspaceHubs: () => scanWorkspaceHubs
17551
17726
  });
17552
17727
  import { execFileSync } from "child_process";
17553
- import * as fs2 from "fs";
17554
- import * as path2 from "path";
17728
+ import * as fs3 from "fs";
17729
+ import * as path3 from "path";
17555
17730
  import * as yaml from "js-yaml";
17556
17731
  function findGitRoot() {
17557
17732
  try {
@@ -17566,8 +17741,8 @@ function findGitRoot() {
17566
17741
  function findRepoRootSync() {
17567
17742
  let current = process.cwd();
17568
17743
  while (true) {
17569
- if (fs2.existsSync(path2.join(current, ".git"))) return current;
17570
- const parent = path2.dirname(current);
17744
+ if (fs3.existsSync(path3.join(current, ".git"))) return current;
17745
+ const parent = path3.dirname(current);
17571
17746
  if (parent === current) return null;
17572
17747
  current = parent;
17573
17748
  }
@@ -17576,7 +17751,7 @@ function detectWorkspace() {
17576
17751
  const gitRoot = findGitRoot();
17577
17752
  if (!gitRoot) return null;
17578
17753
  const { hubsDir } = resolveLayout(gitRoot);
17579
- if (!fs2.existsSync(hubsDir) || !fs2.statSync(hubsDir).isDirectory()) {
17754
+ if (!fs3.existsSync(hubsDir) || !fs3.statSync(hubsDir).isDirectory()) {
17580
17755
  return null;
17581
17756
  }
17582
17757
  return { gitRoot, workspaceDir: hubsDir };
@@ -17592,9 +17767,9 @@ function resolveWorkspaceDir() {
17592
17767
  return resolveLayout(gitRoot).hubsDir;
17593
17768
  }
17594
17769
  function readHubYaml(yamlPath) {
17595
- if (!fs2.existsSync(yamlPath)) return null;
17770
+ if (!fs3.existsSync(yamlPath)) return null;
17596
17771
  try {
17597
- const content = fs2.readFileSync(yamlPath, "utf-8");
17772
+ const content = fs3.readFileSync(yamlPath, "utf-8");
17598
17773
  const config = yaml.load(content);
17599
17774
  if (!config?.hub_id || !config.hub_environment) return null;
17600
17775
  return { hubId: config.hub_id, hubEnvironment: config.hub_environment };
@@ -17605,9 +17780,9 @@ function readHubYaml(yamlPath) {
17605
17780
  function scanWorkspaceHubs(workspaceDir) {
17606
17781
  const hubs = [];
17607
17782
  for (const top of safeReaddir(workspaceDir)) {
17608
- const topDir = path2.join(workspaceDir, top);
17609
- if (!isDirectory(topDir)) continue;
17610
- const meta = readHubYaml(path2.join(topDir, "hub.yaml")) || readHubYaml(path2.join(topDir, "wayai.yaml"));
17783
+ const topDir = path3.join(workspaceDir, top);
17784
+ if (!isRealDirectory(topDir)) continue;
17785
+ const meta = readHubYaml(path3.join(topDir, "hub.yaml")) || readHubYaml(path3.join(topDir, "wayai.yaml"));
17611
17786
  if (meta) {
17612
17787
  hubs.push({ hubFolder: topDir, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
17613
17788
  }
@@ -17621,9 +17796,9 @@ function filterPreviewHubs(hubs) {
17621
17796
  return hubs.filter(isPreviewHub);
17622
17797
  }
17623
17798
  function readNewHubYaml(yamlPath) {
17624
- if (!fs2.existsSync(yamlPath)) return null;
17799
+ if (!fs3.existsSync(yamlPath)) return null;
17625
17800
  try {
17626
- const content = fs2.readFileSync(yamlPath, "utf-8");
17801
+ const content = fs3.readFileSync(yamlPath, "utf-8");
17627
17802
  const config = yaml.load(content);
17628
17803
  if (config?.hub_id) return null;
17629
17804
  if (!config?.hub?.name) return null;
@@ -17635,9 +17810,9 @@ function readNewHubYaml(yamlPath) {
17635
17810
  function scanNewHubs(workspaceDir) {
17636
17811
  const hubs = [];
17637
17812
  for (const top of safeReaddir(workspaceDir)) {
17638
- const topDir = path2.join(workspaceDir, top);
17639
- if (!isDirectory(topDir)) continue;
17640
- const meta = readNewHubYaml(path2.join(topDir, "hub.yaml")) || readNewHubYaml(path2.join(topDir, "wayai.yaml"));
17813
+ const topDir = path3.join(workspaceDir, top);
17814
+ if (!isRealDirectory(topDir)) continue;
17815
+ const meta = readNewHubYaml(path3.join(topDir, "hub.yaml")) || readNewHubYaml(path3.join(topDir, "wayai.yaml"));
17641
17816
  if (meta) {
17642
17817
  hubs.push({ hubFolder: topDir, hubName: meta.hubName, hubType: meta.hubType });
17643
17818
  }
@@ -17657,22 +17832,22 @@ function resolveHubFolder(workspaceDir, hubId, hubName, hubEnvironment, previewL
17657
17832
  if (match) return match.hubFolder;
17658
17833
  }
17659
17834
  const hubFolderSlug = getHubFolderSlug(hubName, hubEnvironment, hubId || "", previewLabel, branchName);
17660
- return path2.join(workspaceDir, hubFolderSlug);
17835
+ return path3.join(workspaceDir, hubFolderSlug);
17661
17836
  }
17662
17837
  function findLocalHubFolder(hubId) {
17663
17838
  const workspace = detectWorkspace();
17664
17839
  const gitRoot = findGitRoot();
17665
17840
  const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
17666
- if (!workspaceDir || !fs2.existsSync(workspaceDir)) return null;
17841
+ if (!workspaceDir || !fs3.existsSync(workspaceDir)) return null;
17667
17842
  const match = scanWorkspaceHubs(workspaceDir).find((h) => h.hubId === hubId);
17668
17843
  return match ? match.hubFolder : null;
17669
17844
  }
17670
17845
  function getChangedHubs(workspaceDir) {
17671
17846
  const gitRoot = findGitRoot();
17672
17847
  if (!gitRoot) return [];
17673
- const relWorkspace = path2.relative(gitRoot, workspaceDir);
17674
- const normalizedRel = path2.normalize(relWorkspace);
17675
- if (normalizedRel.startsWith("..") || path2.isAbsolute(normalizedRel)) {
17848
+ const relWorkspace = path3.relative(gitRoot, workspaceDir);
17849
+ const normalizedRel = path3.normalize(relWorkspace);
17850
+ if (normalizedRel.startsWith("..") || path3.isAbsolute(normalizedRel)) {
17676
17851
  return [];
17677
17852
  }
17678
17853
  let statusOutput;
@@ -17697,9 +17872,9 @@ function getChangedHubs(workspaceDir) {
17697
17872
  if (hubFiles.length === 0) return [];
17698
17873
  const hubFolders = /* @__PURE__ */ new Set();
17699
17874
  for (const file of hubFiles) {
17700
- const absFile = path2.resolve(gitRoot, file);
17875
+ const absFile = path3.resolve(gitRoot, file);
17701
17876
  if (file.endsWith("hub.yaml") || file.endsWith("wayai.yaml")) {
17702
- hubFolders.add(path2.dirname(absFile));
17877
+ hubFolders.add(path3.dirname(absFile));
17703
17878
  } else if (file.includes("/agents/")) {
17704
17879
  const agentsIndex = absFile.lastIndexOf("/agents/");
17705
17880
  hubFolders.add(absFile.substring(0, agentsIndex));
@@ -17707,7 +17882,7 @@ function getChangedHubs(workspaceDir) {
17707
17882
  }
17708
17883
  const hubs = [];
17709
17884
  for (const hubFolder of hubFolders) {
17710
- const meta = readHubYaml(path2.join(hubFolder, "hub.yaml")) || readHubYaml(path2.join(hubFolder, "wayai.yaml"));
17885
+ const meta = readHubYaml(path3.join(hubFolder, "hub.yaml")) || readHubYaml(path3.join(hubFolder, "wayai.yaml"));
17711
17886
  if (meta) {
17712
17887
  hubs.push({ hubFolder, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
17713
17888
  }
@@ -17742,19 +17917,19 @@ function resolveExplicitHubPath(hubPath) {
17742
17917
  }
17743
17918
  function findHubByFolderName(workspaceDir, hubFolderName) {
17744
17919
  const all = scanWorkspaceHubs(workspaceDir);
17745
- return all.find((h) => path2.basename(h.hubFolder) === hubFolderName) ?? null;
17920
+ return all.find((h) => path3.basename(h.hubFolder) === hubFolderName) ?? null;
17746
17921
  }
17747
17922
  function autoRenameHubFolder(currentFolder, hubName, hubEnvironment, hubId, previewLabel, branchName) {
17748
17923
  const expectedSlug = getHubFolderSlug(hubName, hubEnvironment, hubId, previewLabel, branchName);
17749
- const currentSlug = path2.basename(currentFolder);
17924
+ const currentSlug = path3.basename(currentFolder);
17750
17925
  if (currentSlug === expectedSlug) return currentFolder;
17751
- const targetFolder = path2.join(path2.dirname(currentFolder), expectedSlug);
17752
- if (fs2.existsSync(targetFolder)) {
17926
+ const targetFolder = path3.join(path3.dirname(currentFolder), expectedSlug);
17927
+ if (fs3.existsSync(targetFolder)) {
17753
17928
  console.warn(` Warning: skipping hub folder rename ${currentSlug} \u2192 ${expectedSlug} (target already exists)`);
17754
17929
  return currentFolder;
17755
17930
  }
17756
17931
  try {
17757
- fs2.renameSync(currentFolder, targetFolder);
17932
+ fs3.renameSync(currentFolder, targetFolder);
17758
17933
  } catch (err) {
17759
17934
  console.warn(` Warning: could not rename ${currentSlug} \u2192 ${expectedSlug}: ${err instanceof Error ? err.message : String(err)}`);
17760
17935
  return currentFolder;
@@ -17765,28 +17940,28 @@ function autoRenameHubFolder(currentFolder, hubName, hubEnvironment, hubId, prev
17765
17940
  }
17766
17941
  function findEnclosingHubFolder(workspaceDir) {
17767
17942
  let current = process.cwd();
17768
- const stop = path2.resolve(workspaceDir);
17943
+ const stop = path3.resolve(workspaceDir);
17769
17944
  while (true) {
17770
- const meta = readHubYaml(path2.join(current, "hub.yaml")) || readHubYaml(path2.join(current, "wayai.yaml"));
17945
+ const meta = readHubYaml(path3.join(current, "hub.yaml")) || readHubYaml(path3.join(current, "wayai.yaml"));
17771
17946
  if (meta) {
17772
17947
  return { hubFolder: current, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment };
17773
17948
  }
17774
17949
  if (current === stop) return null;
17775
- const parent = path2.dirname(current);
17950
+ const parent = path3.dirname(current);
17776
17951
  if (parent === current) return null;
17777
17952
  current = parent;
17778
17953
  }
17779
17954
  }
17780
17955
  function findEnclosingNewHubFolder(workspaceDir) {
17781
17956
  let current = process.cwd();
17782
- const stop = path2.resolve(workspaceDir);
17957
+ const stop = path3.resolve(workspaceDir);
17783
17958
  while (true) {
17784
- const meta = readNewHubYaml(path2.join(current, "hub.yaml")) || readNewHubYaml(path2.join(current, "wayai.yaml"));
17959
+ const meta = readNewHubYaml(path3.join(current, "hub.yaml")) || readNewHubYaml(path3.join(current, "wayai.yaml"));
17785
17960
  if (meta) {
17786
17961
  return { hubFolder: current, hubName: meta.hubName, hubType: meta.hubType };
17787
17962
  }
17788
17963
  if (current === stop) return null;
17789
- const parent = path2.dirname(current);
17964
+ const parent = path3.dirname(current);
17790
17965
  if (parent === current) return null;
17791
17966
  current = parent;
17792
17967
  }
@@ -17794,10 +17969,10 @@ function findEnclosingNewHubFolder(workspaceDir) {
17794
17969
  function resolvePushTarget(workspaceDir, existingHubs, newHubs, selector) {
17795
17970
  if (selector) {
17796
17971
  const existingMatch = existingHubs.find(
17797
- (h) => h.hubId === selector || path2.basename(h.hubFolder) === selector
17972
+ (h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
17798
17973
  );
17799
17974
  if (existingMatch) return { ok: true, target: { kind: "existing", hub: existingMatch } };
17800
- const newMatch = newHubs.find((h) => path2.basename(h.hubFolder) === selector);
17975
+ const newMatch = newHubs.find((h) => path3.basename(h.hubFolder) === selector);
17801
17976
  if (newMatch) return { ok: true, target: { kind: "new", hub: newMatch } };
17802
17977
  return { ok: false, reason: "selector_miss" };
17803
17978
  }
@@ -17813,10 +17988,10 @@ function resolvePushTarget(workspaceDir, existingHubs, newHubs, selector) {
17813
17988
  }
17814
17989
  function resolveNewHubForCreate(workspaceDir, existingHubs, newHubs, selector) {
17815
17990
  if (selector) {
17816
- const newMatch = newHubs.find((h) => path2.basename(h.hubFolder) === selector);
17991
+ const newMatch = newHubs.find((h) => path3.basename(h.hubFolder) === selector);
17817
17992
  if (newMatch) return { ok: true, hub: newMatch };
17818
17993
  const existingMatch = existingHubs.find(
17819
- (h) => h.hubId === selector || path2.basename(h.hubFolder) === selector
17994
+ (h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
17820
17995
  );
17821
17996
  if (existingMatch) return { ok: false, reason: "exists", existing: existingMatch };
17822
17997
  return { ok: false, reason: "selector_miss" };
@@ -17843,7 +18018,7 @@ function resolveActiveHubId(args2) {
17843
18018
  const gitRoot = findGitRoot();
17844
18019
  const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
17845
18020
  const wsLabel = hubsDirLabel(gitRoot);
17846
- if (!workspaceDir || !fs2.existsSync(workspaceDir)) {
18021
+ if (!workspaceDir || !fs3.existsSync(workspaceDir)) {
17847
18022
  if (selector && UUID_RE2.test(selector)) return selector;
17848
18023
  console.error(`No ${wsLabel}/ directory found. Run \`wayai pull --hub <uuid>\` to fetch a hub, or pass --hub <uuid>.`);
17849
18024
  process.exit(1);
@@ -17851,7 +18026,7 @@ function resolveActiveHubId(args2) {
17851
18026
  const allHubs = scanWorkspaceHubs(workspaceDir);
17852
18027
  if (selector) {
17853
18028
  const match = allHubs.find(
17854
- (h) => h.hubId === selector || path2.basename(h.hubFolder) === selector
18029
+ (h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
17855
18030
  );
17856
18031
  if (match) return match.hubId;
17857
18032
  if (UUID_RE2.test(selector)) return selector;
@@ -17868,7 +18043,7 @@ function resolveActiveHubId(args2) {
17868
18043
  }
17869
18044
  console.error(`Multiple hubs in ${wsLabel}/. Pass --hub <uuid|folder-name> or run from inside a hub folder:`);
17870
18045
  for (const h of previewHubs) {
17871
- console.error(` ${path2.basename(h.hubFolder)} (${h.hubId})`);
18046
+ console.error(` ${path3.basename(h.hubFolder)} (${h.hubId})`);
17872
18047
  }
17873
18048
  process.exit(1);
17874
18049
  }
@@ -17876,12 +18051,12 @@ function localHubEnvironment(hubId) {
17876
18051
  const workspace = detectWorkspace();
17877
18052
  const gitRoot = findGitRoot();
17878
18053
  const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
17879
- if (!workspaceDir || !fs2.existsSync(workspaceDir)) return null;
18054
+ if (!workspaceDir || !fs3.existsSync(workspaceDir)) return null;
17880
18055
  return scanWorkspaceHubs(workspaceDir).find((h) => h.hubId === hubId)?.hubEnvironment ?? null;
17881
18056
  }
17882
18057
  function safeReaddir(dir) {
17883
18058
  try {
17884
- return fs2.readdirSync(dir).filter((entry) => !entry.startsWith("."));
18059
+ return fs3.readdirSync(dir).filter((entry) => !entry.startsWith("."));
17885
18060
  } catch {
17886
18061
  return [];
17887
18062
  }
@@ -17895,19 +18070,19 @@ var init_workspace = __esm({
17895
18070
  });
17896
18071
 
17897
18072
  // src/lib/workspace-manifest.ts
17898
- import * as fs3 from "fs";
17899
- import * as path3 from "path";
18073
+ import * as fs4 from "fs";
18074
+ import * as path4 from "path";
17900
18075
  import * as yaml2 from "js-yaml";
17901
18076
  function workspaceManifestPath(gitRoot) {
17902
- return path3.join(gitRoot, WAYAI_LAYOUT.wsDir, WORKSPACE_MANIFEST_FILE);
18077
+ return path4.join(gitRoot, WAYAI_LAYOUT.wsDir, WORKSPACE_MANIFEST_FILE);
17903
18078
  }
17904
18079
  function rootConfigPath(gitRoot) {
17905
- return path3.join(gitRoot, ROOT_CONFIG_FILE);
18080
+ return path4.join(gitRoot, ROOT_CONFIG_FILE);
17906
18081
  }
17907
18082
  function loadYamlMapping(file) {
17908
18083
  let raw;
17909
18084
  try {
17910
- raw = fs3.readFileSync(file, "utf-8");
18085
+ raw = fs4.readFileSync(file, "utf-8");
17911
18086
  } catch (err) {
17912
18087
  if (err.code === "ENOENT") return { kind: "absent" };
17913
18088
  return { kind: "malformed", reason: err instanceof Error ? err.message : String(err) };
@@ -17950,8 +18125,7 @@ __export(repo_config_exports, {
17950
18125
  resolveRepoConfig: () => resolveRepoConfig,
17951
18126
  writeRepoConfig: () => writeRepoConfig
17952
18127
  });
17953
- import * as fs4 from "fs";
17954
- import * as path4 from "path";
18128
+ import * as path5 from "path";
17955
18129
  import * as yaml3 from "js-yaml";
17956
18130
  function noticeOnce(key, emit) {
17957
18131
  if (noticed.has(key)) return;
@@ -17989,7 +18163,7 @@ function legacyFieldsIn(load11) {
17989
18163
  if (load11.kind !== "ok") return [];
17990
18164
  return LEGACY_FIELDS.filter((f) => load11.doc[f] !== void 0);
17991
18165
  }
17992
- function resolve2(gitRoot) {
18166
+ function resolve3(gitRoot) {
17993
18167
  const manifestFile = workspaceManifestPath(gitRoot);
17994
18168
  const manifest = declarationFrom(loadWorkspaceManifest(gitRoot));
17995
18169
  if (manifest.kind === "invalid") {
@@ -18098,7 +18272,7 @@ function report(r, posture) {
18098
18272
  function resolveRepoConfig(root) {
18099
18273
  const gitRoot = root ?? findGitRoot();
18100
18274
  if (!gitRoot) return null;
18101
- const r = resolve2(gitRoot);
18275
+ const r = resolve3(gitRoot);
18102
18276
  report(r, "soft");
18103
18277
  return r.kind === "ok" ? r.resolved : null;
18104
18278
  }
@@ -18108,7 +18282,7 @@ function readRepoConfig(root) {
18108
18282
  function readRepoConfigUnlessBlocked(root) {
18109
18283
  const gitRoot = root ?? findGitRoot();
18110
18284
  if (!gitRoot) return null;
18111
- const r = resolve2(gitRoot);
18285
+ const r = resolve3(gitRoot);
18112
18286
  switch (r.kind) {
18113
18287
  case "ok":
18114
18288
  report(r, "soft");
@@ -18123,7 +18297,7 @@ function readRepoConfigUnlessBlocked(root) {
18123
18297
  }
18124
18298
  function requireRepoConfig(root) {
18125
18299
  const gitRoot = root ?? findGitRoot();
18126
- const r = gitRoot ? resolve2(gitRoot) : { kind: "none" };
18300
+ const r = gitRoot ? resolve3(gitRoot) : { kind: "none" };
18127
18301
  report(r, "hard");
18128
18302
  if (r.kind === "ok") return r.resolved.config;
18129
18303
  return process.exit(1);
@@ -18131,7 +18305,7 @@ function requireRepoConfig(root) {
18131
18305
  function readRepoScopeBlocker(root) {
18132
18306
  const gitRoot = root ?? findGitRoot();
18133
18307
  if (!gitRoot) return null;
18134
- const r = resolve2(gitRoot);
18308
+ const r = resolve3(gitRoot);
18135
18309
  if (r.kind === "conflict") {
18136
18310
  return {
18137
18311
  kind: "conflict",
@@ -18168,6 +18342,7 @@ function writeRepoConfig(config, root) {
18168
18342
  if (!gitRoot) {
18169
18343
  throw expected("Not inside a git repository. Run `git init` first.");
18170
18344
  }
18345
+ readRealFileOrThrow(gitRoot, workspaceManifestPath(gitRoot));
18171
18346
  const stale = declarationFrom(loadYamlMapping(rootConfigPath(gitRoot)));
18172
18347
  if (stale.kind === "declared" && stale.config.organization_id !== config.organization_id) {
18173
18348
  throw expected(rebindRefusal(config.organization_id, stale.config.organization_id));
@@ -18183,12 +18358,8 @@ function writeRepoConfig(config, root) {
18183
18358
  if (config.organization_name?.trim()) doc.organization_name = config.organization_name.trim();
18184
18359
  Object.assign(doc, rest);
18185
18360
  const file = workspaceManifestPath(gitRoot);
18186
- fs4.mkdirSync(path4.dirname(file), { recursive: true });
18187
- fs4.writeFileSync(
18188
- file,
18189
- yaml3.dump(doc, { lineWidth: -1, quotingType: '"', forceQuotes: false }),
18190
- "utf-8"
18191
- );
18361
+ requireRealSubdirNoSymlink(gitRoot, path5.dirname(file), true);
18362
+ writeFileNoFollow(gitRoot, file, Buffer.from(yaml3.dump(doc, { lineWidth: -1, quotingType: '"', forceQuotes: false }), "utf-8"));
18192
18363
  return file;
18193
18364
  }
18194
18365
  var LEGACY_FIELDS, noticed, RECONCILE_REMEDY;
@@ -18196,6 +18367,7 @@ var init_repo_config = __esm({
18196
18367
  "src/lib/repo-config.ts"() {
18197
18368
  "use strict";
18198
18369
  init_expected();
18370
+ init_fs_safety();
18199
18371
  init_workspace();
18200
18372
  init_utils();
18201
18373
  init_workspace_manifest();
@@ -18210,7 +18382,7 @@ var init_repo_config = __esm({
18210
18382
 
18211
18383
  // src/lib/utils.ts
18212
18384
  import * as fs5 from "fs";
18213
- import * as path5 from "path";
18385
+ import * as path6 from "path";
18214
18386
  import * as readline from "readline";
18215
18387
  function prompt(question) {
18216
18388
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -18264,7 +18436,7 @@ function readStdin() {
18264
18436
  }
18265
18437
  function resolveHubYamlPath(hubFolder) {
18266
18438
  for (const filename of ["hub.yaml", "wayai.yaml"]) {
18267
- const yamlPath = path5.join(hubFolder, filename);
18439
+ const yamlPath = path6.join(hubFolder, filename);
18268
18440
  if (fs5.existsSync(yamlPath)) return yamlPath;
18269
18441
  }
18270
18442
  return null;
@@ -18730,17 +18902,17 @@ var init_registry = __esm({
18730
18902
  });
18731
18903
 
18732
18904
  // src/lib/version-cache.ts
18733
- import { existsSync as existsSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
18734
- import { dirname as dirname4, join as join6 } from "path";
18905
+ import { existsSync as existsSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
18906
+ import { dirname as dirname5, join as join7 } from "path";
18735
18907
  import { homedir as homedir2 } from "os";
18736
18908
  function getVersionCachePath(filename = CLI_CACHE_FILE) {
18737
- return join6(homedir2(), ".wayai", filename);
18909
+ return join7(homedir2(), ".wayai", filename);
18738
18910
  }
18739
18911
  function readVersionCache(filename = CLI_CACHE_FILE) {
18740
18912
  try {
18741
18913
  const path35 = getVersionCachePath(filename);
18742
18914
  if (!existsSync3(path35)) return null;
18743
- const parsed = JSON.parse(readFileSync5(path35, "utf-8"));
18915
+ const parsed = JSON.parse(readFileSync6(path35, "utf-8"));
18744
18916
  if (typeof parsed.lastCheck !== "number") return null;
18745
18917
  if (parsed.latest !== null && typeof parsed.latest !== "string") return null;
18746
18918
  return parsed;
@@ -18761,7 +18933,7 @@ function isVersionCacheStale(filename = CLI_CACHE_FILE, maxAgeMs = MAX_AGE_24H_M
18761
18933
  }
18762
18934
  function writeVersionCache(filename, cache) {
18763
18935
  const path35 = getVersionCachePath(filename);
18764
- const dir = dirname4(path35);
18936
+ const dir = dirname5(path35);
18765
18937
  if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
18766
18938
  writeFileSync2(path35, JSON.stringify(cache));
18767
18939
  }
@@ -18780,8 +18952,8 @@ var init_version_cache = __esm({
18780
18952
  });
18781
18953
 
18782
18954
  // src/lib/skill-version.ts
18783
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
18784
- import { join as join7 } from "path";
18955
+ import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
18956
+ import { join as join8 } from "path";
18785
18957
  import * as yaml4 from "js-yaml";
18786
18958
  function skillInstallPaths(skillName) {
18787
18959
  return HARNESS_SKILL_DIRS.map((dir) => `${dir}/skills/${skillName}/${SKILL_FILENAME}`);
@@ -18802,11 +18974,11 @@ function parseFrontmatterVersion(content) {
18802
18974
  function findInstalledSkills(projectRoot, paths = SKILL_INSTALL_PATHS) {
18803
18975
  const found = [];
18804
18976
  for (const rel of paths) {
18805
- const path35 = join7(projectRoot, rel);
18977
+ const path35 = join8(projectRoot, rel);
18806
18978
  if (!existsSync4(path35)) continue;
18807
18979
  let version = null;
18808
18980
  try {
18809
- version = parseFrontmatterVersion(readFileSync6(path35, "utf-8"));
18981
+ version = parseFrontmatterVersion(readFileSync7(path35, "utf-8"));
18810
18982
  } catch {
18811
18983
  }
18812
18984
  found.push({ path: path35, version });
@@ -18841,13 +19013,13 @@ __export(config_exports, {
18841
19013
  writeConfig: () => writeConfig
18842
19014
  });
18843
19015
  import * as fs6 from "fs";
18844
- import * as path6 from "path";
19016
+ import * as path7 from "path";
18845
19017
  import * as os from "os";
18846
19018
  function configDir() {
18847
- return path6.join(os.homedir(), ".wayai");
19019
+ return path7.join(os.homedir(), ".wayai");
18848
19020
  }
18849
19021
  function configPath() {
18850
- return path6.join(configDir(), "config.json");
19022
+ return path7.join(configDir(), "config.json");
18851
19023
  }
18852
19024
  function getConfigPath() {
18853
19025
  return configPath();
@@ -18900,13 +19072,13 @@ var init_config = __esm({
18900
19072
 
18901
19073
  // src/lib/token-store.ts
18902
19074
  import * as fs7 from "fs";
18903
- import * as path7 from "path";
19075
+ import * as path8 from "path";
18904
19076
  import * as os2 from "os";
18905
19077
  function configDir2() {
18906
- return path7.join(os2.homedir(), ".wayai");
19078
+ return path8.join(os2.homedir(), ".wayai");
18907
19079
  }
18908
19080
  function configPath2() {
18909
- return path7.join(configDir2(), "config.json");
19081
+ return path8.join(configDir2(), "config.json");
18910
19082
  }
18911
19083
  function manualCleanupCommand(account) {
18912
19084
  if (process.platform === "darwin") {
@@ -19406,26 +19578,26 @@ __export(skill_symlink_exports, {
19406
19578
  healClaudeSkillLink: () => healClaudeSkillLink,
19407
19579
  healSkillLinkForCommand: () => healSkillLinkForCommand
19408
19580
  });
19409
- import { existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync5, rmSync, symlinkSync } from "fs";
19410
- import { join as join10 } from "path";
19581
+ import { existsSync as existsSync7, lstatSync as lstatSync3, mkdirSync as mkdirSync5, rmSync as rmSync2, symlinkSync } from "fs";
19582
+ import { join as join11 } from "path";
19411
19583
  function healClaudeSkillLink(root) {
19412
19584
  try {
19413
- const source = join10(root, ".agents", "skills", SKILL_NAME);
19414
- if (!existsSync7(join10(source, SKILL_FILENAME))) return false;
19415
- const link = join10(root, ".claude", "skills", SKILL_NAME);
19416
- if (existsSync7(join10(link, SKILL_FILENAME))) return false;
19585
+ const source = join11(root, ".agents", "skills", SKILL_NAME);
19586
+ if (!existsSync7(join11(source, SKILL_FILENAME))) return false;
19587
+ const link = join11(root, ".claude", "skills", SKILL_NAME);
19588
+ if (existsSync7(join11(link, SKILL_FILENAME))) return false;
19417
19589
  let entry = null;
19418
19590
  try {
19419
- entry = lstatSync(link);
19591
+ entry = lstatSync3(link);
19420
19592
  } catch {
19421
19593
  entry = null;
19422
19594
  }
19423
19595
  if (entry) {
19424
19596
  if (!entry.isSymbolicLink()) return false;
19425
- rmSync(link, { force: true });
19597
+ rmSync2(link, { force: true });
19426
19598
  }
19427
- mkdirSync5(join10(root, ".claude", "skills"), { recursive: true });
19428
- symlinkSync(join10("..", "..", ".agents", "skills", SKILL_NAME), link, "dir");
19599
+ mkdirSync5(join11(root, ".claude", "skills"), { recursive: true });
19600
+ symlinkSync(join11("..", "..", ".agents", "skills", SKILL_NAME), link, "dir");
19429
19601
  return true;
19430
19602
  } catch {
19431
19603
  return false;
@@ -19709,7 +19881,7 @@ var init_base_id = __esm({
19709
19881
  // src/lib/worktree-scope.ts
19710
19882
  import { execFileSync as execFileSync2 } from "child_process";
19711
19883
  import * as fs8 from "fs";
19712
- import * as path8 from "path";
19884
+ import * as path9 from "path";
19713
19885
  import * as yaml5 from "js-yaml";
19714
19886
  function axisNoun(axis) {
19715
19887
  return AXES[axis].noun;
@@ -19724,7 +19896,7 @@ function resolveGitDir() {
19724
19896
  encoding: "utf-8",
19725
19897
  stdio: ["pipe", "pipe", "pipe"]
19726
19898
  }).trim();
19727
- gitDir = raw ? path8.resolve(cwd, raw) : null;
19899
+ gitDir = raw ? path9.resolve(cwd, raw) : null;
19728
19900
  } catch {
19729
19901
  gitDir = null;
19730
19902
  }
@@ -19733,12 +19905,12 @@ function resolveGitDir() {
19733
19905
  }
19734
19906
  function getScopePath() {
19735
19907
  const gitDir = resolveGitDir();
19736
- return gitDir ? path8.join(gitDir, SCOPE_FILE) : null;
19908
+ return gitDir ? path9.join(gitDir, SCOPE_FILE) : null;
19737
19909
  }
19738
19910
  function legacyPaths() {
19739
19911
  const gitDir = resolveGitDir();
19740
19912
  if (!gitDir) return [];
19741
- return AXIS_ORDER.flatMap((axis) => AXES[axis].legacyFiles).map((f) => path8.join(gitDir, f));
19913
+ return AXIS_ORDER.flatMap((axis) => AXES[axis].legacyFiles).map((f) => path9.join(gitDir, f));
19742
19914
  }
19743
19915
  function emptyScope() {
19744
19916
  return { hubs: [], bases: [] };
@@ -19762,7 +19934,7 @@ function readLegacyAxis(axis) {
19762
19934
  for (const filename of legacyFiles) {
19763
19935
  let raw;
19764
19936
  try {
19765
- raw = fs8.readFileSync(path8.join(gitDir, filename), "utf-8");
19937
+ raw = fs8.readFileSync(path9.join(gitDir, filename), "utf-8");
19766
19938
  } catch (err) {
19767
19939
  if (err.code === "ENOENT") continue;
19768
19940
  throw err;
@@ -19982,8 +20154,13 @@ function buildSkillState() {
19982
20154
  }
19983
20155
  function buildWorkspaceState(resolved) {
19984
20156
  if (!resolved) return { scoped: false, path: null, hub_count: 0 };
19985
- const ws = detectWorkspace();
19986
- const hubCount = ws ? scanWorkspaceHubs(ws.workspaceDir).length : 0;
20157
+ let hubCount = 0;
20158
+ try {
20159
+ const ws = detectWorkspace();
20160
+ hubCount = ws ? scanWorkspaceHubs(ws.workspaceDir).length : 0;
20161
+ } catch {
20162
+ hubCount = 0;
20163
+ }
19987
20164
  return { scoped: true, path: resolved.path, hub_count: hubCount };
19988
20165
  }
19989
20166
  async function statusCommand(args2, pkg2) {
@@ -20221,12 +20398,12 @@ __export(init_exports, {
20221
20398
  parseArgs: () => parseArgs3
20222
20399
  });
20223
20400
  import { mkdirSync as mkdirSync6 } from "fs";
20224
- import path9 from "path";
20401
+ import path10 from "path";
20225
20402
  function ensureHubsDir(gitRoot) {
20226
20403
  const hubsDir = resolveLayout(gitRoot).hubsDir;
20227
20404
  if (isDirectory(hubsDir)) return null;
20228
20405
  mkdirSync6(hubsDir, { recursive: true });
20229
- return `${path9.relative(gitRoot, hubsDir)}/`;
20406
+ return `${path10.relative(gitRoot, hubsDir)}/`;
20230
20407
  }
20231
20408
  function parseArgs3(args2) {
20232
20409
  let orgId;
@@ -20355,118 +20532,8 @@ var init_init = __esm({
20355
20532
  }
20356
20533
  });
20357
20534
 
20358
- // src/lib/fs-safety.ts
20359
- import * as fs9 from "fs";
20360
- import * as path10 from "path";
20361
- function fileHasBytes(abs, data) {
20362
- let st;
20363
- try {
20364
- st = fs9.lstatSync(abs);
20365
- } catch {
20366
- return false;
20367
- }
20368
- if (!st.isFile() || st.isSymbolicLink()) return false;
20369
- try {
20370
- return fs9.readFileSync(abs).equals(data);
20371
- } catch {
20372
- return false;
20373
- }
20374
- }
20375
- function realpathContained(root, abs) {
20376
- let realRoot;
20377
- let realAbs;
20378
- try {
20379
- realRoot = fs9.realpathSync(root);
20380
- realAbs = fs9.realpathSync(abs);
20381
- } catch {
20382
- return false;
20383
- }
20384
- return realAbs === realRoot || realAbs.startsWith(realRoot + path10.sep);
20385
- }
20386
- function mkdirTolerateRace(dir) {
20387
- try {
20388
- fs9.mkdirSync(dir);
20389
- return true;
20390
- } catch (err) {
20391
- if (err.code !== "EEXIST") throw err;
20392
- let st;
20393
- try {
20394
- st = fs9.lstatSync(dir);
20395
- } catch {
20396
- st = void 0;
20397
- }
20398
- return !!st?.isDirectory();
20399
- }
20400
- }
20401
- function ensureRealSubdirNoSymlink(root, target, create) {
20402
- const rootResolved = path10.resolve(root);
20403
- const targetResolved = path10.resolve(target);
20404
- if (targetResolved !== rootResolved && !targetResolved.startsWith(rootResolved + path10.sep)) return false;
20405
- try {
20406
- if (!fs9.lstatSync(rootResolved).isDirectory()) return false;
20407
- } catch {
20408
- return false;
20409
- }
20410
- const rel = path10.relative(rootResolved, targetResolved);
20411
- if (rel === "") return true;
20412
- let cur = rootResolved;
20413
- for (const segment of rel.split(path10.sep)) {
20414
- cur = path10.join(cur, segment);
20415
- let st;
20416
- try {
20417
- st = fs9.lstatSync(cur);
20418
- } catch {
20419
- st = void 0;
20420
- }
20421
- if (st) {
20422
- if (!st.isDirectory()) return false;
20423
- } else if (create) {
20424
- if (!mkdirTolerateRace(cur)) return false;
20425
- } else {
20426
- return true;
20427
- }
20428
- }
20429
- return true;
20430
- }
20431
- function readFileNoFollow(root, abs) {
20432
- if (!ensureRealSubdirNoSymlink(root, path10.dirname(abs), false)) return null;
20433
- try {
20434
- if (!fs9.lstatSync(abs).isFile()) return null;
20435
- return fs9.readFileSync(abs);
20436
- } catch {
20437
- return null;
20438
- }
20439
- }
20440
- function writeFileNoFollow(root, abs, data) {
20441
- const parent = path10.dirname(abs);
20442
- if (!ensureRealSubdirNoSymlink(root, parent, true)) return false;
20443
- let st;
20444
- try {
20445
- st = fs9.lstatSync(abs);
20446
- } catch {
20447
- }
20448
- if (st?.isSymbolicLink()) fs9.rmSync(abs);
20449
- fs9.writeFileSync(abs, data);
20450
- return true;
20451
- }
20452
- function createFileNoFollow(root, abs, data) {
20453
- if (!ensureRealSubdirNoSymlink(root, path10.dirname(abs), true)) return "refused";
20454
- try {
20455
- fs9.writeFileSync(abs, data, { flag: "wx" });
20456
- } catch (err) {
20457
- if (err.code === "EEXIST") return "exists";
20458
- throw err;
20459
- }
20460
- return "created";
20461
- }
20462
- var init_fs_safety = __esm({
20463
- "src/lib/fs-safety.ts"() {
20464
- "use strict";
20465
- }
20466
- });
20467
-
20468
20535
  // src/lib/resource-files.ts
20469
- import * as fs10 from "fs";
20536
+ import * as fs9 from "fs";
20470
20537
  import * as path11 from "path";
20471
20538
  import * as crypto3 from "crypto";
20472
20539
  function isBinaryFile(filename) {
@@ -20513,14 +20580,14 @@ function computeHash(data) {
20513
20580
  }
20514
20581
  function scanResourceFiles(dir, prefix = "") {
20515
20582
  const files = [];
20516
- const entries = fs10.readdirSync(dir, { withFileTypes: true });
20583
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
20517
20584
  for (const entry of entries) {
20518
20585
  const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
20519
20586
  if (entry.isDirectory()) {
20520
20587
  files.push(...scanResourceFiles(path11.join(dir, entry.name), relPath));
20521
20588
  } else if (entry.isFile()) {
20522
20589
  const fullPath = path11.join(dir, entry.name);
20523
- const stat2 = fs10.statSync(fullPath);
20590
+ const stat2 = fs9.statSync(fullPath);
20524
20591
  if (stat2.size > MAX_RESOURCE_FILE_SIZE3) {
20525
20592
  console.warn(` Warning: skipping ${relPath} (${(stat2.size / 1024 / 1024).toFixed(1)}MB exceeds 10MB limit)`);
20526
20593
  continue;
@@ -20530,7 +20597,7 @@ function scanResourceFiles(dir, prefix = "") {
20530
20597
  mime_type: guessMimeType(entry.name),
20531
20598
  file_size: stat2.size
20532
20599
  };
20533
- const data = fs10.readFileSync(fullPath);
20600
+ const data = fs9.readFileSync(fullPath);
20534
20601
  fileEntry.hash = computeHash(data);
20535
20602
  if (isBinaryFile(entry.name)) {
20536
20603
  fileEntry.content_base64 = data.toString("base64");
@@ -20590,7 +20657,7 @@ function writeResourceFileTree(resDir, files, root, log) {
20590
20657
  return;
20591
20658
  }
20592
20659
  if (files.length === 0) {
20593
- if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", /* @__PURE__ */ new Set(), root, log);
20660
+ if (fs9.existsSync(resDir)) cleanOrphanFiles(resDir, "", /* @__PURE__ */ new Set(), root, log);
20594
20661
  return;
20595
20662
  }
20596
20663
  const writtenPaths = /* @__PURE__ */ new Set();
@@ -20611,18 +20678,18 @@ function writeResourceFileTree(resDir, files, root, log) {
20611
20678
  writtenPaths.delete(file.path);
20612
20679
  }
20613
20680
  }
20614
- if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", writtenPaths, root, log);
20681
+ if (fs9.existsSync(resDir)) cleanOrphanFiles(resDir, "", writtenPaths, root, log);
20615
20682
  }
20616
20683
  function cleanOrphanFiles(dir, prefix, writtenPaths, root, log) {
20617
- const entries = fs10.readdirSync(dir, { withFileTypes: true });
20684
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
20618
20685
  for (const entry of entries) {
20619
20686
  const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
20620
20687
  const fullPath = path11.join(dir, entry.name);
20621
20688
  if (entry.isDirectory()) {
20622
20689
  cleanOrphanFiles(fullPath, relPath, writtenPaths, root, log);
20623
- if (fs10.readdirSync(fullPath).length === 0) fs10.rmdirSync(fullPath);
20690
+ if (fs9.readdirSync(fullPath).length === 0) fs9.rmdirSync(fullPath);
20624
20691
  } else if (!writtenPaths.has(relPath)) {
20625
- fs10.unlinkSync(fullPath);
20692
+ fs9.unlinkSync(fullPath);
20626
20693
  if (log && root) log.removed.push(path11.relative(root, fullPath));
20627
20694
  }
20628
20695
  }
@@ -20643,8 +20710,8 @@ async function downloadBinaryFiles(resDir, files, root, log) {
20643
20710
  }
20644
20711
  if (file.hash) {
20645
20712
  try {
20646
- const st = fs10.lstatSync(filePath);
20647
- if (st.isFile() && !st.isSymbolicLink() && computeHash(fs10.readFileSync(filePath)) === file.hash) continue;
20713
+ const st = fs9.lstatSync(filePath);
20714
+ if (st.isFile() && !st.isSymbolicLink() && computeHash(fs9.readFileSync(filePath)) === file.hash) continue;
20648
20715
  } catch {
20649
20716
  }
20650
20717
  }
@@ -20698,7 +20765,7 @@ var init_resource_files = __esm({
20698
20765
  });
20699
20766
 
20700
20767
  // src/lib/eval-attachments.ts
20701
- import * as fs11 from "fs";
20768
+ import * as fs10 from "fs";
20702
20769
  import * as path12 from "path";
20703
20770
  function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
20704
20771
  const raw = turn.attachments;
@@ -20722,7 +20789,7 @@ function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
20722
20789
  }
20723
20790
  let stat2;
20724
20791
  try {
20725
- stat2 = fs11.statSync(abs);
20792
+ stat2 = fs10.statSync(abs);
20726
20793
  } catch {
20727
20794
  }
20728
20795
  if (!stat2?.isFile()) {
@@ -20736,7 +20803,7 @@ function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
20736
20803
  `${label}: attachment "${entry}" is ${(stat2.size / 1024 / 1024).toFixed(1)}MB, over the 10MB limit.`
20737
20804
  );
20738
20805
  }
20739
- const data = fs11.readFileSync(abs);
20806
+ const data = fs10.readFileSync(abs);
20740
20807
  const hash = computeHash(data);
20741
20808
  const fileName = path12.basename(abs);
20742
20809
  const mimeType = guessMimeType(fileName) ?? "application/octet-stream";
@@ -20844,16 +20911,16 @@ async function downloadEvalAttachments(hubFolder, downloads) {
20844
20911
  console.warn(` Warning: ${ATTACHMENTS_DIR}/ is not reachable inside the hub folder without a symlink; skipping attachment sync.`);
20845
20912
  return result;
20846
20913
  }
20847
- if (!fs11.existsSync(attachDir)) return result;
20914
+ if (!fs10.existsSync(attachDir)) return result;
20848
20915
  for (const dl of downloads) {
20849
20916
  const abs = path12.resolve(hubFolder, dl.relPath);
20850
20917
  if (abs !== attachDir && !abs.startsWith(attachDir + path12.sep)) continue;
20851
20918
  let existing;
20852
20919
  try {
20853
- existing = fs11.lstatSync(abs);
20920
+ existing = fs10.lstatSync(abs);
20854
20921
  } catch {
20855
20922
  }
20856
- if (existing?.isFile() && !existing.isSymbolicLink() && computeHash(fs11.readFileSync(abs)) === dl.hash) {
20923
+ if (existing?.isFile() && !existing.isSymbolicLink() && computeHash(fs10.readFileSync(abs)) === dl.hash) {
20857
20924
  continue;
20858
20925
  }
20859
20926
  try {
@@ -20871,11 +20938,11 @@ async function downloadEvalAttachments(hubFolder, downloads) {
20871
20938
  }
20872
20939
  }
20873
20940
  const keep = new Set(downloads.map((d) => path12.resolve(hubFolder, d.relPath)));
20874
- for (const name of fs11.readdirSync(attachDir)) {
20941
+ for (const name of fs10.readdirSync(attachDir)) {
20875
20942
  const abs = path12.join(attachDir, name);
20876
- const st = fs11.lstatSync(abs);
20943
+ const st = fs10.lstatSync(abs);
20877
20944
  if ((st.isFile() || st.isSymbolicLink()) && !keep.has(abs)) {
20878
- fs11.rmSync(abs);
20945
+ fs10.rmSync(abs);
20879
20946
  result.removed.push(path12.relative(hubFolder, abs));
20880
20947
  }
20881
20948
  }
@@ -20893,15 +20960,16 @@ var init_eval_attachments = __esm({
20893
20960
  });
20894
20961
 
20895
20962
  // src/lib/parser.ts
20896
- import * as fs12 from "fs";
20963
+ import * as fs11 from "fs";
20897
20964
  import * as path13 from "path";
20898
20965
  import * as yaml6 from "js-yaml";
20899
20966
  function parseHubFolder(hubFolder, opts) {
20967
+ requireRealHubFolder(hubFolder, false);
20900
20968
  const yamlPath = resolveHubYamlPath(hubFolder);
20901
20969
  if (!yamlPath) {
20902
20970
  throw expected(`hub.yaml not found in ${hubFolder}`);
20903
20971
  }
20904
- const yamlContent = fs12.readFileSync(yamlPath, "utf-8");
20972
+ const yamlContent = readRealFileOrThrow(hubFolder, yamlPath) ?? "";
20905
20973
  let config;
20906
20974
  try {
20907
20975
  config = yaml6.load(yamlContent);
@@ -20929,8 +20997,8 @@ function parseHubFolder(hubFolder, opts) {
20929
20997
  if (typeof resolved.instructions === "string" && resolved.instructions.endsWith(".md")) {
20930
20998
  const instrValue = resolved.instructions;
20931
20999
  const instructionsPath = instrValue.startsWith("agents/") ? path13.join(hubFolder, instrValue) : path13.join(hubFolder, "agents", instrValue);
20932
- if (fs12.existsSync(instructionsPath)) {
20933
- resolved.instructions = fs12.readFileSync(instructionsPath, "utf-8");
21000
+ if (fs11.existsSync(instructionsPath)) {
21001
+ resolved.instructions = fs11.readFileSync(instructionsPath, "utf-8");
20934
21002
  } else {
20935
21003
  throw expected(
20936
21004
  `Agent instructions file not found: ${instructionsPath} (referenced by agent "${agent.name}")`
@@ -20938,8 +21006,8 @@ function parseHubFolder(hubFolder, opts) {
20938
21006
  }
20939
21007
  } else if (resolved.instructions === void 0 && typeof agent.name === "string") {
20940
21008
  const conventionPath = path13.join(hubFolder, "agents", `${slugify(agent.name)}.md`);
20941
- if (fs12.existsSync(conventionPath)) {
20942
- resolved.instructions = fs12.readFileSync(conventionPath, "utf-8");
21009
+ if (fs11.existsSync(conventionPath)) {
21010
+ resolved.instructions = fs11.readFileSync(conventionPath, "utf-8");
20943
21011
  }
20944
21012
  }
20945
21013
  return resolved;
@@ -20994,17 +21062,17 @@ function parseHubFolder(hubFolder, opts) {
20994
21062
  }
20995
21063
  function scanEvalYamlFiles(hubFolder, bytesByHash) {
20996
21064
  const evalsDir = path13.join(hubFolder, "evals");
20997
- if (!fs12.existsSync(evalsDir)) return [];
21065
+ if (!fs11.existsSync(evalsDir)) return [];
20998
21066
  const evals = [];
20999
21067
  const seen = /* @__PURE__ */ new Set();
21000
- const topEntries = fs12.readdirSync(evalsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21068
+ const topEntries = fs11.readdirSync(evalsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21001
21069
  for (const entry of topEntries) {
21002
21070
  if (entry.isFile() && entry.name.endsWith(".yaml")) {
21003
21071
  collectEval(evals, seen, path13.join(evalsDir, entry.name), `evals/${entry.name}`, null, hubFolder, bytesByHash);
21004
21072
  } else if (entry.isDirectory()) {
21005
21073
  const setName = entry.name;
21006
21074
  const setDir = path13.join(evalsDir, setName);
21007
- const setEntries = fs12.readdirSync(setDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21075
+ const setEntries = fs11.readdirSync(setDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21008
21076
  for (const sub of setEntries) {
21009
21077
  if (sub.isDirectory()) {
21010
21078
  throw expected(
@@ -21033,7 +21101,7 @@ function collectEval(evals, seen, filePath, relPath, setName, hubFolder, bytesBy
21033
21101
  evals.push(evalEntry);
21034
21102
  }
21035
21103
  function parseEvalYaml(filePath, relPath, setName, hubFolder, bytesByHash) {
21036
- const content = fs12.readFileSync(filePath, "utf-8");
21104
+ const content = fs11.readFileSync(filePath, "utf-8");
21037
21105
  let raw;
21038
21106
  try {
21039
21107
  raw = yaml6.load(content);
@@ -21136,10 +21204,10 @@ function parseFixtureField(raw, label, key) {
21136
21204
  }
21137
21205
  function scanJourneyYamlFiles(hubFolder, bytesByHash) {
21138
21206
  const journeysDir = path13.join(hubFolder, "journeys");
21139
- if (!fs12.existsSync(journeysDir)) return [];
21207
+ if (!fs11.existsSync(journeysDir)) return [];
21140
21208
  const journeys = [];
21141
21209
  const seen = /* @__PURE__ */ new Set();
21142
- const entries = fs12.readdirSync(journeysDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21210
+ const entries = fs11.readdirSync(journeysDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
21143
21211
  for (const entry of entries) {
21144
21212
  if (entry.isDirectory()) {
21145
21213
  throw expected(
@@ -21160,7 +21228,7 @@ function scanJourneyYamlFiles(hubFolder, bytesByHash) {
21160
21228
  return journeys;
21161
21229
  }
21162
21230
  function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
21163
- const content = fs12.readFileSync(filePath, "utf-8");
21231
+ const content = fs11.readFileSync(filePath, "utf-8");
21164
21232
  let raw;
21165
21233
  try {
21166
21234
  raw = yaml6.load(content);
@@ -21216,13 +21284,13 @@ function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
21216
21284
  }
21217
21285
  function scanAgentYamlFiles(hubFolder) {
21218
21286
  const agentsDir = path13.join(hubFolder, "agents");
21219
- if (!fs12.existsSync(agentsDir)) return [];
21220
- const yamlFiles = fs12.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml")).sort();
21287
+ if (!fs11.existsSync(agentsDir)) return [];
21288
+ const yamlFiles = fs11.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml")).sort();
21221
21289
  if (yamlFiles.length === 0) return [];
21222
21290
  const agents = [];
21223
21291
  for (const file of yamlFiles) {
21224
21292
  const filePath = path13.join(agentsDir, file);
21225
- const content = fs12.readFileSync(filePath, "utf-8");
21293
+ const content = fs11.readFileSync(filePath, "utf-8");
21226
21294
  let agent;
21227
21295
  try {
21228
21296
  agent = yaml6.load(content);
@@ -21257,7 +21325,7 @@ function parseResources(hubFolder, configResources) {
21257
21325
  if (res.skill_name) resource.skill_name = res.skill_name;
21258
21326
  const resSlug = slugify(resource.name);
21259
21327
  const resDir = path13.join(resourcesDir, resSlug);
21260
- if (fs12.existsSync(resDir)) {
21328
+ if (fs11.existsSync(resDir)) {
21261
21329
  const files = scanResourceFiles(resDir, "");
21262
21330
  if (files.length > 0) {
21263
21331
  resource.files = files;
@@ -21274,6 +21342,7 @@ var init_parser = __esm({
21274
21342
  init_resource_files();
21275
21343
  init_eval_attachments();
21276
21344
  init_expected();
21345
+ init_fs_safety();
21277
21346
  }
21278
21347
  });
21279
21348
 
@@ -21331,7 +21400,7 @@ var init_workspace_files = __esm({
21331
21400
  });
21332
21401
 
21333
21402
  // src/lib/yaml-writer.ts
21334
- import * as fs13 from "fs";
21403
+ import * as fs12 from "fs";
21335
21404
  import * as path15 from "path";
21336
21405
  import * as yaml7 from "js-yaml";
21337
21406
  function writeFileIfChanged(hubFolder, absPath, content, log) {
@@ -21382,11 +21451,11 @@ function buildEvalYamlObject(evalEntry, slug) {
21382
21451
  function writeHubFolder(hubFolder, payload, options = {}) {
21383
21452
  const log = { changed: [], removed: [] };
21384
21453
  const agentsDir = path15.join(hubFolder, "agents");
21385
- if (!fs13.existsSync(hubFolder)) {
21386
- fs13.mkdirSync(hubFolder, { recursive: true });
21454
+ if (!fs12.existsSync(hubFolder)) {
21455
+ fs12.mkdirSync(hubFolder, { recursive: true });
21387
21456
  }
21388
- if (!fs13.existsSync(agentsDir)) {
21389
- fs13.mkdirSync(agentsDir, { recursive: true });
21457
+ if (!fs12.existsSync(agentsDir)) {
21458
+ fs12.mkdirSync(agentsDir, { recursive: true });
21390
21459
  }
21391
21460
  const yamlPayload = buildYamlPayload(payload);
21392
21461
  const agentFiles = extractAgentFiles(payload);
@@ -21401,8 +21470,8 @@ function writeHubFolder(hubFolder, payload, options = {}) {
21401
21470
  if (seeded) log.changed.push(seeded);
21402
21471
  }
21403
21472
  const oldYamlPath = path15.join(hubFolder, "wayai.yaml");
21404
- if (fs13.existsSync(oldYamlPath)) {
21405
- fs13.unlinkSync(oldYamlPath);
21473
+ if (fs12.existsSync(oldYamlPath)) {
21474
+ fs12.unlinkSync(oldYamlPath);
21406
21475
  log.removed.push(path15.relative(hubFolder, oldYamlPath));
21407
21476
  }
21408
21477
  const yamlSlugs = writeAgentYamlFiles(hubFolder, agentsDir, payload.agents || [], log);
@@ -21411,20 +21480,20 @@ function writeHubFolder(hubFolder, payload, options = {}) {
21411
21480
  mdSlugs.add(slug);
21412
21481
  writeFileIfChanged(hubFolder, path15.join(agentsDir, `${slug}.md`), content, log);
21413
21482
  }
21414
- const existingFiles = fs13.readdirSync(agentsDir);
21483
+ const existingFiles = fs12.readdirSync(agentsDir);
21415
21484
  for (const file of existingFiles) {
21416
21485
  if (file.endsWith(".yaml")) {
21417
21486
  const slug = file.slice(0, -5);
21418
21487
  if (!yamlSlugs.has(slug)) {
21419
21488
  const orphan = path15.join(agentsDir, file);
21420
- fs13.unlinkSync(orphan);
21489
+ fs12.unlinkSync(orphan);
21421
21490
  log.removed.push(path15.relative(hubFolder, orphan));
21422
21491
  }
21423
21492
  } else if (file.endsWith(".md")) {
21424
21493
  const slug = file.slice(0, -3);
21425
21494
  if (!mdSlugs.has(slug)) {
21426
21495
  const orphan = path15.join(agentsDir, file);
21427
- fs13.unlinkSync(orphan);
21496
+ fs12.unlinkSync(orphan);
21428
21497
  log.removed.push(path15.relative(hubFolder, orphan));
21429
21498
  }
21430
21499
  }
@@ -21435,12 +21504,13 @@ function writeHubFolder(hubFolder, payload, options = {}) {
21435
21504
  return log;
21436
21505
  }
21437
21506
  function setPreviewLabelInHubYaml(hubFolder, label) {
21507
+ requireRealHubFolder(hubFolder, false);
21438
21508
  const yamlPath = resolveHubYamlPath(hubFolder);
21439
21509
  if (!yamlPath) return;
21440
- const obj = yaml7.load(fs13.readFileSync(yamlPath, "utf-8")) ?? {};
21510
+ const obj = yaml7.load(readRealFileOrThrow(hubFolder, yamlPath) ?? "") ?? {};
21441
21511
  if (label) obj.preview_label = label;
21442
21512
  else delete obj.preview_label;
21443
- fs13.writeFileSync(yamlPath, yaml7.dump(obj, YAML_DUMP_OPTIONS), "utf-8");
21513
+ writeFileNoFollow(hubFolder, yamlPath, Buffer.from(yaml7.dump(obj, YAML_DUMP_OPTIONS), "utf-8"));
21444
21514
  }
21445
21515
  function buildYamlPayload(payload) {
21446
21516
  const result = {
@@ -21505,17 +21575,17 @@ function extractAgentFiles(payload) {
21505
21575
  function writeEvalYamlFiles(hubFolder, evals, log) {
21506
21576
  const evalsDir = path15.join(hubFolder, "evals");
21507
21577
  if (evals.length === 0) {
21508
- if (fs13.existsSync(evalsDir)) {
21578
+ if (fs12.existsSync(evalsDir)) {
21509
21579
  cleanEvalOrphans(hubFolder, evalsDir, /* @__PURE__ */ new Set(), log);
21510
21580
  try {
21511
- if (fs13.readdirSync(evalsDir).length === 0) fs13.rmdirSync(evalsDir);
21581
+ if (fs12.readdirSync(evalsDir).length === 0) fs12.rmdirSync(evalsDir);
21512
21582
  } catch {
21513
21583
  }
21514
21584
  }
21515
21585
  return;
21516
21586
  }
21517
- if (!fs13.existsSync(evalsDir)) {
21518
- fs13.mkdirSync(evalsDir, { recursive: true });
21587
+ if (!fs12.existsSync(evalsDir)) {
21588
+ fs12.mkdirSync(evalsDir, { recursive: true });
21519
21589
  }
21520
21590
  const writtenRelPaths = /* @__PURE__ */ new Set();
21521
21591
  for (const evalEntry of evals) {
@@ -21527,12 +21597,6 @@ function writeEvalYamlFiles(hubFolder, evals, log) {
21527
21597
  console.warn(` Warning: skipping eval "${evalEntry.name}" (scenario set "${setName}" escapes evals/ \u2014 possible bad backend data)`);
21528
21598
  continue;
21529
21599
  }
21530
- if (setName) {
21531
- const setDir = path15.join(evalsDir, setName);
21532
- if (!fs13.existsSync(setDir)) {
21533
- fs13.mkdirSync(setDir, { recursive: true });
21534
- }
21535
- }
21536
21600
  const yamlContent = yaml7.dump(buildEvalYamlObject(evalEntry, slug), YAML_DUMP_OPTIONS);
21537
21601
  writeFileIfChanged(hubFolder, targetPath, yamlContent, log);
21538
21602
  writtenRelPaths.add(relPath);
@@ -21540,31 +21604,31 @@ function writeEvalYamlFiles(hubFolder, evals, log) {
21540
21604
  cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log);
21541
21605
  }
21542
21606
  function cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log) {
21543
- const entries = fs13.readdirSync(evalsDir, { withFileTypes: true });
21607
+ const entries = fs12.readdirSync(evalsDir, { withFileTypes: true });
21544
21608
  for (const entry of entries) {
21545
21609
  const fullPath = path15.join(evalsDir, entry.name);
21546
21610
  if (entry.isFile()) {
21547
21611
  if (entry.name.endsWith(".yaml") && !writtenRelPaths.has(entry.name)) {
21548
- fs13.unlinkSync(fullPath);
21612
+ fs12.unlinkSync(fullPath);
21549
21613
  log.removed.push(path15.relative(hubFolder, fullPath));
21550
21614
  }
21551
21615
  continue;
21552
21616
  }
21553
21617
  if (entry.isDirectory()) {
21554
21618
  const setName = entry.name;
21555
- const subEntries = fs13.readdirSync(fullPath, { withFileTypes: true });
21619
+ const subEntries = fs12.readdirSync(fullPath, { withFileTypes: true });
21556
21620
  for (const sub of subEntries) {
21557
21621
  if (sub.isFile() && sub.name.endsWith(".yaml")) {
21558
21622
  const relPath = `${setName}/${sub.name}`;
21559
21623
  if (!writtenRelPaths.has(relPath)) {
21560
21624
  const orphan = path15.join(fullPath, sub.name);
21561
- fs13.unlinkSync(orphan);
21625
+ fs12.unlinkSync(orphan);
21562
21626
  log.removed.push(path15.relative(hubFolder, orphan));
21563
21627
  }
21564
21628
  }
21565
21629
  }
21566
21630
  try {
21567
- if (fs13.readdirSync(fullPath).length === 0) fs13.rmdirSync(fullPath);
21631
+ if (fs12.readdirSync(fullPath).length === 0) fs12.rmdirSync(fullPath);
21568
21632
  } catch {
21569
21633
  }
21570
21634
  }
@@ -21603,17 +21667,17 @@ function buildJourneyYamlObject(journeyEntry, slug) {
21603
21667
  function writeJourneyYamlFiles(hubFolder, journeys, log) {
21604
21668
  const journeysDir = path15.join(hubFolder, "journeys");
21605
21669
  if (journeys.length === 0) {
21606
- if (fs13.existsSync(journeysDir)) {
21670
+ if (fs12.existsSync(journeysDir)) {
21607
21671
  cleanJourneyOrphans(hubFolder, journeysDir, /* @__PURE__ */ new Set(), log);
21608
21672
  try {
21609
- if (fs13.readdirSync(journeysDir).length === 0) fs13.rmdirSync(journeysDir);
21673
+ if (fs12.readdirSync(journeysDir).length === 0) fs12.rmdirSync(journeysDir);
21610
21674
  } catch {
21611
21675
  }
21612
21676
  }
21613
21677
  return;
21614
21678
  }
21615
- if (!fs13.existsSync(journeysDir)) {
21616
- fs13.mkdirSync(journeysDir, { recursive: true });
21679
+ if (!fs12.existsSync(journeysDir)) {
21680
+ fs12.mkdirSync(journeysDir, { recursive: true });
21617
21681
  }
21618
21682
  const writtenFiles = /* @__PURE__ */ new Set();
21619
21683
  const usedSlugs = /* @__PURE__ */ new Set();
@@ -21627,11 +21691,11 @@ function writeJourneyYamlFiles(hubFolder, journeys, log) {
21627
21691
  cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log);
21628
21692
  }
21629
21693
  function cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log) {
21630
- const entries = fs13.readdirSync(journeysDir, { withFileTypes: true });
21694
+ const entries = fs12.readdirSync(journeysDir, { withFileTypes: true });
21631
21695
  for (const entry of entries) {
21632
21696
  if (entry.isFile() && entry.name.endsWith(".yaml") && !writtenFiles.has(entry.name)) {
21633
21697
  const orphan = path15.join(journeysDir, entry.name);
21634
- fs13.unlinkSync(orphan);
21698
+ fs12.unlinkSync(orphan);
21635
21699
  log.removed.push(path15.relative(hubFolder, orphan));
21636
21700
  }
21637
21701
  }
@@ -21645,12 +21709,12 @@ function writeResourceFiles(hubFolder, resources, log) {
21645
21709
  const resDir = path15.join(resourcesDir, resSlug);
21646
21710
  writeResourceFileTree(resDir, resource.files || [], hubFolder, log);
21647
21711
  }
21648
- if (fs13.existsSync(resourcesDir)) {
21649
- const existingDirs = fs13.readdirSync(resourcesDir, { withFileTypes: true });
21712
+ if (fs12.existsSync(resourcesDir)) {
21713
+ const existingDirs = fs12.readdirSync(resourcesDir, { withFileTypes: true });
21650
21714
  for (const entry of existingDirs) {
21651
21715
  if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
21652
21716
  const orphanDir = path15.join(resourcesDir, entry.name);
21653
- fs13.rmSync(orphanDir, { recursive: true, force: true });
21717
+ fs12.rmSync(orphanDir, { recursive: true, force: true });
21654
21718
  log.removed.push(`${path15.relative(hubFolder, orphanDir)}/`);
21655
21719
  }
21656
21720
  }
@@ -21687,6 +21751,7 @@ async function materializeHubFolder(hubFolder, payload, options = {}) {
21687
21751
  );
21688
21752
  }
21689
21753
  materialized.add(payload);
21754
+ requireRealHubFolder(hubFolder, true);
21690
21755
  const attachmentDownloads = rewriteEvalAttachmentsToLocalPaths(payload);
21691
21756
  const writeLog = writeHubFolder(hubFolder, payload, options);
21692
21757
  const resourceDownloads = await downloadBinaryResourceFiles(hubFolder, payload);
@@ -21718,6 +21783,7 @@ var init_hub_materializer = __esm({
21718
21783
  init_yaml_writer();
21719
21784
  init_eval_attachments();
21720
21785
  init_resource_files();
21786
+ init_fs_safety();
21721
21787
  init_utils();
21722
21788
  materialized = /* @__PURE__ */ new WeakSet();
21723
21789
  }
@@ -21739,7 +21805,7 @@ var init_terminal_output = __esm({
21739
21805
  });
21740
21806
 
21741
21807
  // src/lib/base-workspace.ts
21742
- import * as fs14 from "fs";
21808
+ import * as fs13 from "fs";
21743
21809
  import * as path17 from "path";
21744
21810
  import * as yaml8 from "js-yaml";
21745
21811
  function readBaseMeta(folder) {
@@ -21757,7 +21823,7 @@ function readBaseMeta(folder) {
21757
21823
  function listBaseFolders(basesDir) {
21758
21824
  let entries;
21759
21825
  try {
21760
- entries = fs14.readdirSync(basesDir).filter((entry) => !entry.startsWith("."));
21826
+ entries = fs13.readdirSync(basesDir).filter((entry) => !entry.startsWith("."));
21761
21827
  } catch {
21762
21828
  return [];
21763
21829
  }
@@ -21844,7 +21910,7 @@ function resolveBaseSelectorToId(gitRoot, selector) {
21844
21910
  }
21845
21911
  function hasBaseMetaFile(folder) {
21846
21912
  try {
21847
- return fs14.lstatSync(path17.join(folder, BASE_META_FILE)).isFile();
21913
+ return fs13.lstatSync(path17.join(folder, BASE_META_FILE)).isFile();
21848
21914
  } catch {
21849
21915
  return false;
21850
21916
  }
@@ -22157,7 +22223,7 @@ var init_client = __esm({
22157
22223
  });
22158
22224
 
22159
22225
  // src/data/helpers.ts
22160
- import { readFileSync as readFileSync15 } from "fs";
22226
+ import { readFileSync as readFileSync14 } from "fs";
22161
22227
  function pathSegment(id, label = "id") {
22162
22228
  if (!isPathSafeId(id)) {
22163
22229
  throw expected(`Invalid ${label}: ${JSON.stringify(id)}. An id may use ${PATH_SAFE_ID_RULE}.`);
@@ -22185,7 +22251,7 @@ function parseData(data, flag) {
22185
22251
  let text = data;
22186
22252
  if (source !== void 0) {
22187
22253
  try {
22188
- text = readFileSync15(source, "utf-8");
22254
+ text = readFileSync14(source, "utf-8");
22189
22255
  } catch (e) {
22190
22256
  throw expected(`${prefix}${source}: ${e instanceof Error ? e.message : "could not be read"}`);
22191
22257
  }
@@ -22310,7 +22376,7 @@ var init_types2 = __esm({
22310
22376
  });
22311
22377
 
22312
22378
  // src/data/config-as-code/config-writer.ts
22313
- import * as fs15 from "fs";
22379
+ import * as fs14 from "fs";
22314
22380
  import * as path19 from "path";
22315
22381
  import * as yaml9 from "js-yaml";
22316
22382
  function dump5(value) {
@@ -22345,14 +22411,14 @@ function pruneOrphans(folder, dir, keep, log) {
22345
22411
  if (!ensureRealSubdirNoSymlink(folder, dir, false)) return;
22346
22412
  let entries;
22347
22413
  try {
22348
- entries = fs15.readdirSync(dir);
22414
+ entries = fs14.readdirSync(dir);
22349
22415
  } catch {
22350
22416
  return;
22351
22417
  }
22352
22418
  for (const file of entries) {
22353
22419
  if (!file.endsWith(".yaml") || keep.has(file)) continue;
22354
22420
  const abs = path19.join(dir, file);
22355
- fs15.rmSync(abs);
22421
+ fs14.rmSync(abs);
22356
22422
  log.removed.push(path19.relative(folder, abs));
22357
22423
  }
22358
22424
  }
@@ -22366,7 +22432,7 @@ function metaFileObject(meta) {
22366
22432
  function writeBaseFolder(folder, meta, config) {
22367
22433
  const delta = { changed: [], removed: [] };
22368
22434
  const parent = path19.dirname(folder);
22369
- fs15.mkdirSync(parent, { recursive: true });
22435
+ fs14.mkdirSync(parent, { recursive: true });
22370
22436
  if (!ensureRealSubdirNoSymlink(parent, folder, true)) {
22371
22437
  throw expected(
22372
22438
  `Refusing to write ${folder}: the path crosses a symlink. Remove it and pull again.`
@@ -22393,7 +22459,7 @@ function writeBaseFolder(folder, meta, config) {
22393
22459
  for (const deprecated of DEPRECATED_ENTITY_DIRS) {
22394
22460
  const dir = path19.join(folder, deprecated);
22395
22461
  if (ensureRealSubdirNoSymlink(folder, dir, false)) {
22396
- fs15.rmSync(dir, { recursive: true, force: true });
22462
+ fs14.rmSync(dir, { recursive: true, force: true });
22397
22463
  }
22398
22464
  }
22399
22465
  return delta;
@@ -22545,7 +22611,7 @@ var init_api = __esm({
22545
22611
  });
22546
22612
 
22547
22613
  // src/data/config-as-code/config-parser.ts
22548
- import * as fs16 from "fs";
22614
+ import * as fs15 from "fs";
22549
22615
  import * as path20 from "path";
22550
22616
  import * as yaml10 from "js-yaml";
22551
22617
  function readEntityDir(folder, dir) {
@@ -22554,7 +22620,7 @@ function readEntityDir(folder, dir) {
22554
22620
  }
22555
22621
  if (!isDirectory(dir)) return [];
22556
22622
  const out = [];
22557
- for (const file of fs16.readdirSync(dir).sort()) {
22623
+ for (const file of fs15.readdirSync(dir).sort()) {
22558
22624
  if (!file.endsWith(".yaml")) continue;
22559
22625
  const abs = path20.join(dir, file);
22560
22626
  const bytes = readFileNoFollow(folder, abs);
@@ -22941,7 +23007,7 @@ __export(push_exports, {
22941
23007
  shouldWarnIgnoredPreviewLabel: () => shouldWarnIgnoredPreviewLabel,
22942
23008
  syncAfterPush: () => syncAfterPush
22943
23009
  });
22944
- import * as fs17 from "fs";
23010
+ import * as fs16 from "fs";
22945
23011
  import * as path22 from "path";
22946
23012
  import * as yaml11 from "js-yaml";
22947
23013
  function parseArgs5(args2) {
@@ -23050,13 +23116,14 @@ function printLocalFileChanges(delta) {
23050
23116
  emit(delta.changed, "~");
23051
23117
  }
23052
23118
  async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, remoteConfig) {
23119
+ requireRealHubFolder(hubFolder, false);
23053
23120
  const agentsDir = path22.join(hubFolder, "agents");
23054
23121
  let agentsWithIds = [];
23055
- if (fs17.existsSync(agentsDir)) {
23056
- const yamlFiles = fs17.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
23122
+ if (fs16.existsSync(agentsDir)) {
23123
+ const yamlFiles = fs16.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
23057
23124
  for (const file of yamlFiles) {
23058
23125
  try {
23059
- const content = fs17.readFileSync(path22.join(agentsDir, file), "utf-8");
23126
+ const content = fs16.readFileSync(path22.join(agentsDir, file), "utf-8");
23060
23127
  const agent = yaml11.load(content);
23061
23128
  if (agent?.id && agent.name) {
23062
23129
  agentsWithIds.push({ id: agent.id, name: agent.name });
@@ -23069,7 +23136,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
23069
23136
  if (agentsWithIds.length === 0) {
23070
23137
  const yamlPath = resolveHubYamlPath(hubFolder);
23071
23138
  if (!yamlPath) return;
23072
- const yamlContent = fs17.readFileSync(yamlPath, "utf-8");
23139
+ const yamlContent = readRealFileOrThrow(hubFolder, yamlPath) ?? "";
23073
23140
  const config = yaml11.load(yamlContent);
23074
23141
  agentsWithIds = (config.agents || []).filter((a) => !!a.id && !!a.name);
23075
23142
  }
@@ -23101,18 +23168,18 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
23101
23168
  }
23102
23169
  }
23103
23170
  if (renames.length === 0) return;
23104
- if (!fs17.existsSync(agentsDir)) return;
23105
- for (const file of fs17.readdirSync(agentsDir)) {
23171
+ if (!fs16.existsSync(agentsDir)) return;
23172
+ for (const file of fs16.readdirSync(agentsDir)) {
23106
23173
  if (file.startsWith("__rename_temp_") && (file.endsWith(".md") || file.endsWith(".yaml"))) {
23107
23174
  console.warn(` Warning: removing orphaned temp file agents/${file}`);
23108
- fs17.unlinkSync(path22.join(agentsDir, file));
23175
+ fs16.unlinkSync(path22.join(agentsDir, file));
23109
23176
  }
23110
23177
  }
23111
23178
  const renameFileIfExists = (dir, oldName, newName) => {
23112
23179
  const oldPath = path22.join(dir, oldName);
23113
23180
  const newPath = path22.join(dir, newName);
23114
- if (!fs17.existsSync(oldPath)) return false;
23115
- fs17.renameSync(oldPath, newPath);
23181
+ if (!fs16.existsSync(oldPath)) return false;
23182
+ fs16.renameSync(oldPath, newPath);
23116
23183
  return true;
23117
23184
  };
23118
23185
  const oldSlugs = new Set(renames.map((r) => r.oldSlug));
@@ -23145,9 +23212,9 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
23145
23212
  }
23146
23213
  } else {
23147
23214
  for (const { oldSlug, newSlug } of renames) {
23148
- const hasOldFile = extensions.some((ext) => fs17.existsSync(path22.join(agentsDir, `${oldSlug}${ext}`)));
23215
+ const hasOldFile = extensions.some((ext) => fs16.existsSync(path22.join(agentsDir, `${oldSlug}${ext}`)));
23149
23216
  if (!hasOldFile) continue;
23150
- const hasNewFile = extensions.some((ext) => fs17.existsSync(path22.join(agentsDir, `${newSlug}${ext}`)));
23217
+ const hasNewFile = extensions.some((ext) => fs16.existsSync(path22.join(agentsDir, `${newSlug}${ext}`)));
23151
23218
  if (hasNewFile) {
23152
23219
  console.warn(` Warning: skipping rename agents/${oldSlug}.* \u2192 agents/${newSlug}.* (target already exists)`);
23153
23220
  continue;
@@ -23162,7 +23229,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
23162
23229
  if (completedRenames.length === 0) return;
23163
23230
  const mainYamlPath = resolveHubYamlPath(hubFolder);
23164
23231
  if (mainYamlPath) {
23165
- const mainYamlContent = fs17.readFileSync(mainYamlPath, "utf-8");
23232
+ const mainYamlContent = readRealFileOrThrow(hubFolder, mainYamlPath) ?? "";
23166
23233
  const substitutionMap = /* @__PURE__ */ new Map();
23167
23234
  for (const { oldSlug, newSlug } of completedRenames) {
23168
23235
  substitutionMap.set(`agents/${oldSlug}.md`, `agents/${newSlug}.md`);
@@ -23173,7 +23240,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
23173
23240
  (_match, prefix, pathMatch) => `${prefix}${substitutionMap.get(pathMatch) ?? pathMatch}`
23174
23241
  );
23175
23242
  if (updatedYaml !== mainYamlContent) {
23176
- fs17.writeFileSync(mainYamlPath, updatedYaml, "utf-8");
23243
+ writeFileNoFollow(hubFolder, mainYamlPath, Buffer.from(updatedYaml, "utf-8"));
23177
23244
  console.log(` Updated instructions paths in ${path22.basename(mainYamlPath)}`);
23178
23245
  }
23179
23246
  }
@@ -23267,11 +23334,13 @@ New hub: "${newHub.hubName}" (${hubType})`);
23267
23334
  return;
23268
23335
  }
23269
23336
  }
23337
+ requireRealHubFolder(newHub.hubFolder, false);
23270
23338
  const hubYamlPath = resolveHubYamlPath(newHub.hubFolder);
23271
23339
  if (!hubYamlPath) {
23272
23340
  console.error(`hub.yaml not found in ${newHub.hubFolder}. Cannot proceed with hub creation.`);
23273
23341
  process.exit(1);
23274
23342
  }
23343
+ const content = readRealFileOrThrow(newHub.hubFolder, hubYamlPath) ?? "";
23275
23344
  console.log("Creating hub...");
23276
23345
  const createResult = await client.createHub(opts.organizationId, {
23277
23346
  hubName: newHub.hubName,
@@ -23285,7 +23354,6 @@ New hub: "${newHub.hubName}" (${hubType})`);
23285
23354
  process.exit(1);
23286
23355
  }
23287
23356
  console.log(`Hub created: ${createdHub.hub_name} (${hubId})`);
23288
- const content = fs17.readFileSync(hubYamlPath, "utf-8");
23289
23357
  const hasVersion = content.match(/^version:\s/m);
23290
23358
  let updated;
23291
23359
  if (hasVersion) {
@@ -23301,7 +23369,7 @@ hub_id: "${hubId}"
23301
23369
  hub_environment: preview
23302
23370
  ${content}`;
23303
23371
  }
23304
- fs17.writeFileSync(hubYamlPath, updated, "utf-8");
23372
+ writeFileNoFollow(newHub.hubFolder, hubYamlPath, Buffer.from(updated, "utf-8"));
23305
23373
  seedScopeIfEmpty("hubs", hubId);
23306
23374
  await pushSingleHub(client, hubId, newHub.hubFolder, opts.autoConfirm, opts.organizationId, { skipAgentRename: true });
23307
23375
  }
@@ -23347,7 +23415,7 @@ async function pushCommand(args2) {
23347
23415
  const client = new ApiClient({ apiUrl: config.api_url, accessToken });
23348
23416
  const workspaceDir = resolveWorkspaceDir();
23349
23417
  const wsLabel = hubsDirLabel(gitRoot);
23350
- if (!fs17.existsSync(workspaceDir)) {
23418
+ if (!fs16.existsSync(workspaceDir)) {
23351
23419
  console.error(`No ${wsLabel}/ directory found. Run \`wayai pull\` first or create hub files in ${wsLabel}/<hub>/hub.yaml.`);
23352
23420
  process.exit(1);
23353
23421
  }
@@ -23391,6 +23459,7 @@ var init_push = __esm({
23391
23459
  init_repo_config();
23392
23460
  init_worktree_scope();
23393
23461
  init_subtree_routing();
23462
+ init_fs_safety();
23394
23463
  LOCAL_CHANGE_LIST_CAP = 20;
23395
23464
  }
23396
23465
  });
@@ -23403,7 +23472,7 @@ __export(pull_exports, {
23403
23472
  resolveHubTarget: () => resolveHubTarget,
23404
23473
  writeProductionMirror: () => writeProductionMirror2
23405
23474
  });
23406
- import * as fs18 from "fs";
23475
+ import * as fs17 from "fs";
23407
23476
  import * as path23 from "path";
23408
23477
  function parseArgs6(args2) {
23409
23478
  return { autoConfirm: args2.includes("--yes") || args2.includes("-y") };
@@ -23470,7 +23539,7 @@ async function pullCommand(args2) {
23470
23539
  payload.preview_label,
23471
23540
  payload.branch_name
23472
23541
  );
23473
- fs18.mkdirSync(path23.dirname(hubFolder), { recursive: true });
23542
+ fs17.mkdirSync(path23.dirname(hubFolder), { recursive: true });
23474
23543
  console.log("Writing hub configuration...");
23475
23544
  await materializeHubFolder(hubFolder, payload);
23476
23545
  const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
@@ -23524,7 +23593,7 @@ async function pullCommand(args2) {
23524
23593
  }
23525
23594
  async function writeProductionMirror2(workspaceDir, prodPayload) {
23526
23595
  const folder = resolveHubFolder(workspaceDir, prodPayload.hub_id, prodPayload.hub.name, "production", null, null);
23527
- fs18.mkdirSync(path23.dirname(folder), { recursive: true });
23596
+ fs17.mkdirSync(path23.dirname(folder), { recursive: true });
23528
23597
  await materializeHubFolder(folder, prodPayload, { seedAgentContext: false });
23529
23598
  const finalFolder = autoRenameHubFolder(folder, prodPayload.hub.name, "production", prodPayload.hub_id, null, null);
23530
23599
  prependMirrorMarker(finalFolder, prodPayload.hub_id);
@@ -23542,11 +23611,11 @@ async function mirrorLinkedProduction2(client, workspaceDir, productionHubId, or
23542
23611
  function prependMirrorMarker(hubFolder, productionHubId) {
23543
23612
  const hubYaml = path23.join(hubFolder, "hub.yaml");
23544
23613
  try {
23545
- const content = fs18.readFileSync(hubYaml, "utf-8");
23614
+ const content = fs17.readFileSync(hubYaml, "utf-8");
23546
23615
  if (content.startsWith(MIRROR_MARKER_PREFIX2)) return;
23547
23616
  const marker = `${MIRROR_MARKER_PREFIX2} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
23548
23617
  `;
23549
- fs18.writeFileSync(hubYaml, marker + content, "utf-8");
23618
+ fs17.writeFileSync(hubYaml, marker + content, "utf-8");
23550
23619
  } catch {
23551
23620
  }
23552
23621
  }
@@ -23590,7 +23659,7 @@ __export(create_exports, {
23590
23659
  createCommand: () => createCommand
23591
23660
  });
23592
23661
  import * as path24 from "path";
23593
- import * as fs19 from "fs";
23662
+ import * as fs18 from "fs";
23594
23663
  function parseArgs7(args2) {
23595
23664
  let autoConfirm = false;
23596
23665
  let folderSelector;
@@ -23617,7 +23686,7 @@ async function createCommand(args2) {
23617
23686
  const gitRoot = findGitRoot();
23618
23687
  const wsLabel = hubsDirLabel(gitRoot);
23619
23688
  if (gitRoot) warnLayoutOnce(gitRoot);
23620
- if (!fs19.existsSync(workspaceDir)) {
23689
+ if (!fs18.existsSync(workspaceDir)) {
23621
23690
  console.error(`No ${wsLabel}/ directory found. Create hub files in ${wsLabel}/<hub>/hub.yaml with \`hub: { name: ... }\` first.`);
23622
23691
  process.exit(1);
23623
23692
  }
@@ -23751,7 +23820,7 @@ var replicate_exports = {};
23751
23820
  __export(replicate_exports, {
23752
23821
  replicateCommand: () => replicateCommand
23753
23822
  });
23754
- import * as fs20 from "fs";
23823
+ import * as fs19 from "fs";
23755
23824
  import * as path25 from "path";
23756
23825
  function parseArgs9(args2) {
23757
23826
  let label;
@@ -23798,8 +23867,8 @@ async function replicateCommand(args2) {
23798
23867
  payload.preview_label,
23799
23868
  payload.branch_name
23800
23869
  );
23801
- const folderPreExisted = fs20.existsSync(hubFolder);
23802
- fs20.mkdirSync(path25.dirname(hubFolder), { recursive: true });
23870
+ const folderPreExisted = fs19.existsSync(hubFolder);
23871
+ fs19.mkdirSync(path25.dirname(hubFolder), { recursive: true });
23803
23872
  const delta = await materializeHubFolder(hubFolder, payload);
23804
23873
  hubFolder = autoRenameHubFolder(
23805
23874
  hubFolder,
@@ -24226,7 +24295,7 @@ __export(migrate_exports, {
24226
24295
  migrateCommand: () => migrateCommand
24227
24296
  });
24228
24297
  import { execFileSync as execFileSync3 } from "child_process";
24229
- import * as fs21 from "fs";
24298
+ import * as fs20 from "fs";
24230
24299
  import * as path29 from "path";
24231
24300
  function isTracked(gitRoot, p) {
24232
24301
  try {
@@ -24240,7 +24309,7 @@ function isTracked(gitRoot, p) {
24240
24309
  }
24241
24310
  }
24242
24311
  function moveDir(gitRoot, from, to) {
24243
- fs21.mkdirSync(path29.dirname(to), { recursive: true });
24312
+ fs20.mkdirSync(path29.dirname(to), { recursive: true });
24244
24313
  if (isTracked(gitRoot, from)) {
24245
24314
  try {
24246
24315
  execFileSync3("git", ["mv", path29.relative(gitRoot, from), path29.relative(gitRoot, to)], {
@@ -24251,7 +24320,7 @@ function moveDir(gitRoot, from, to) {
24251
24320
  } catch {
24252
24321
  }
24253
24322
  }
24254
- fs21.renameSync(from, to);
24323
+ fs20.renameSync(from, to);
24255
24324
  return "fs";
24256
24325
  }
24257
24326
  async function migrateCommand(_args) {
@@ -24266,8 +24335,11 @@ async function migrateCommand(_args) {
24266
24335
  const legacyOrg = path29.join(gitRoot, WAYAI_LAYOUT.legacy.orgAtRoot);
24267
24336
  const newHubs = path29.join(newWs, WAYAI_LAYOUT.hubsSubdir);
24268
24337
  const newOrg = path29.join(newWs, WAYAI_LAYOUT.orgSubdir);
24269
- const hasLegacyWs = isDirectory(legacyWs);
24270
- const hasLegacyOrg = isDirectory(legacyOrg);
24338
+ requireRealSubdirNoSymlink(gitRoot, newHubs, false);
24339
+ requireRealSubdirNoSymlink(gitRoot, newOrg, false);
24340
+ readRealFileOrThrow(gitRoot, workspaceManifestPath(gitRoot));
24341
+ const hasLegacyWs = isRealDirectory(legacyWs);
24342
+ const hasLegacyOrg = isRealDirectory(legacyOrg);
24271
24343
  const orgPlan = planOrgMigration(gitRoot);
24272
24344
  if (orgPlan.kind === "refuse") {
24273
24345
  console.error(orgPlan.message);
@@ -24331,6 +24403,7 @@ var init_migrate = __esm({
24331
24403
  "use strict";
24332
24404
  init_workspace();
24333
24405
  init_layout();
24406
+ init_fs_safety();
24334
24407
  init_repo_config();
24335
24408
  init_workspace_manifest();
24336
24409
  }
@@ -24414,12 +24487,12 @@ var send_message_exports = {};
24414
24487
  __export(send_message_exports, {
24415
24488
  sendMessageCommand: () => sendMessageCommand
24416
24489
  });
24417
- import * as fs22 from "fs";
24490
+ import * as fs21 from "fs";
24418
24491
  import * as path30 from "path";
24419
24492
  function statAttachment(filePath) {
24420
24493
  let stat2;
24421
24494
  try {
24422
- stat2 = fs22.statSync(filePath);
24495
+ stat2 = fs21.statSync(filePath);
24423
24496
  } catch {
24424
24497
  console.error(`Error: file not found: ${filePath}`);
24425
24498
  process.exit(1);
@@ -24435,7 +24508,7 @@ function readAttachment(filePath, size) {
24435
24508
  const ext = path30.extname(fileName).replace(/^\./, "");
24436
24509
  return {
24437
24510
  file_name: fileName,
24438
- file_binary: fs22.readFileSync(filePath).toString("base64"),
24511
+ file_binary: fs21.readFileSync(filePath).toString("base64"),
24439
24512
  file_size: size,
24440
24513
  ...ext && { file_extension: ext }
24441
24514
  };
@@ -26634,7 +26707,7 @@ var eval_capture_exports = {};
26634
26707
  __export(eval_capture_exports, {
26635
26708
  evalCaptureCommand: () => evalCaptureCommand
26636
26709
  });
26637
- import * as fs23 from "fs";
26710
+ import * as fs22 from "fs";
26638
26711
  import * as path31 from "path";
26639
26712
  import * as yaml12 from "js-yaml";
26640
26713
  function isValidSetName(name) {
@@ -26708,7 +26781,17 @@ async function evalCaptureCommand(args2) {
26708
26781
  console.error(`Resolved path "${path31.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
26709
26782
  process.exit(1);
26710
26783
  }
26711
- if (fs23.existsSync(targetPath)) {
26784
+ if (!ensureRealSubdirNoSymlink(hubFolder, targetDir, false)) {
26785
+ console.error(`${path31.relative(hubFolder, targetDir)} is reached through a symlink. Aborting.`);
26786
+ process.exit(1);
26787
+ }
26788
+ let targetTaken = true;
26789
+ try {
26790
+ fs22.lstatSync(targetPath);
26791
+ } catch {
26792
+ targetTaken = false;
26793
+ }
26794
+ if (targetTaken) {
26712
26795
  console.error(`File already exists: ${path31.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
26713
26796
  process.exit(1);
26714
26797
  }
@@ -26741,8 +26824,13 @@ async function evalCaptureCommand(args2) {
26741
26824
  ...captured.evaluator_instructions ? { evaluator_instructions: captured.evaluator_instructions } : {}
26742
26825
  };
26743
26826
  const yamlObj = buildEvalYamlObject(evalEntry, slug);
26744
- fs23.mkdirSync(targetDir, { recursive: true });
26745
- fs23.writeFileSync(targetPath, yaml12.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8");
26827
+ const outcome = createFileNoFollow(hubFolder, targetPath, Buffer.from(yaml12.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8"));
26828
+ if (outcome !== "created") {
26829
+ console.error(
26830
+ `Could not write ${path31.relative(hubFolder, targetPath)} (${outcome === "exists" ? "it appeared meanwhile" : "its folder is reached through a symlink"}). The scenario was created on the platform as ${captured.eval_id} \u2014 run \`wayai pull\` to fetch it.`
26831
+ );
26832
+ process.exit(1);
26833
+ }
26746
26834
  const relPath = path31.relative(process.cwd(), targetPath);
26747
26835
  console.log(`
26748
26836
  Wrote ${relPath}`);
@@ -26757,6 +26845,7 @@ var init_eval_capture = __esm({
26757
26845
  init_workspace();
26758
26846
  init_utils();
26759
26847
  init_yaml_writer();
26848
+ init_fs_safety();
26760
26849
  }
26761
26850
  });
26762
26851
 
@@ -28114,23 +28203,21 @@ var init_set_connection_credential = __esm({
28114
28203
  });
28115
28204
 
28116
28205
  // src/lib/org-workspace.ts
28117
- import * as fs24 from "fs";
28206
+ import * as fs23 from "fs";
28118
28207
  import * as path32 from "path";
28119
28208
  import * as yaml13 from "js-yaml";
28120
28209
  function getOrgDir(gitRoot) {
28121
28210
  return resolveLayout(gitRoot).orgDir;
28122
28211
  }
28123
28212
  function orgManifestExists(orgDir) {
28124
- return fs24.existsSync(path32.join(orgDir, ORG_MANIFEST_NAME));
28213
+ return fs23.existsSync(path32.join(orgDir, ORG_MANIFEST_NAME));
28125
28214
  }
28126
28215
  function parseOrgResources(orgDir) {
28127
- const manifestPath = path32.join(orgDir, ORG_MANIFEST_NAME);
28128
- let manifest = {};
28129
- if (fs24.existsSync(manifestPath)) {
28130
- manifest = yaml13.load(fs24.readFileSync(manifestPath, "utf-8")) ?? {};
28131
- }
28132
- const rawResources = Array.isArray(manifest.resources) ? manifest.resources : [];
28133
28216
  const resourcesDir = path32.join(orgDir, "resources");
28217
+ requireRealSubdirNoSymlink(orgDir, resourcesDir, false);
28218
+ const manifestText = readRealFileOrThrow(orgDir, path32.join(orgDir, ORG_MANIFEST_NAME));
28219
+ const manifest = (manifestText !== null ? yaml13.load(manifestText) : null) ?? {};
28220
+ const rawResources = Array.isArray(manifest.resources) ? manifest.resources : [];
28134
28221
  const resources = rawResources.map((res) => {
28135
28222
  const resource = { name: res.name };
28136
28223
  if (res.id) resource.id = res.id;
@@ -28143,7 +28230,7 @@ function parseOrgResources(orgDir) {
28143
28230
  if (Array.isArray(res.tags)) resource.tags = res.tags;
28144
28231
  if (Array.isArray(res.folders)) resource.folders = res.folders;
28145
28232
  const resDir = path32.join(resourcesDir, slugify(resource.name));
28146
- if (fs24.existsSync(resDir)) {
28233
+ if (fs23.existsSync(resDir)) {
28147
28234
  const files = scanResourceFiles(resDir, "");
28148
28235
  if (files.length > 0) resource.files = files;
28149
28236
  }
@@ -28152,28 +28239,29 @@ function parseOrgResources(orgDir) {
28152
28239
  return { version: 1, resources };
28153
28240
  }
28154
28241
  function writeOrgResources(orgDir, payload) {
28155
- fs24.mkdirSync(orgDir, { recursive: true });
28242
+ fs23.mkdirSync(orgDir, { recursive: true });
28243
+ const resourcesDir = path32.join(orgDir, "resources");
28244
+ requireRealSubdirNoSymlink(orgDir, resourcesDir, false);
28156
28245
  const resources = payload.resources ?? [];
28157
28246
  const manifestResources = resources.map((r) => {
28158
28247
  const { files: _files, ...rest } = r;
28159
28248
  return rest;
28160
28249
  });
28161
- fs24.writeFileSync(
28250
+ writeFileNoFollow(
28251
+ orgDir,
28162
28252
  path32.join(orgDir, ORG_MANIFEST_NAME),
28163
- yaml13.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS),
28164
- "utf-8"
28253
+ Buffer.from(yaml13.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS), "utf-8")
28165
28254
  );
28166
- const resourcesDir = path32.join(orgDir, "resources");
28167
28255
  const currentSlugs = /* @__PURE__ */ new Set();
28168
28256
  for (const resource of resources) {
28169
28257
  const resSlug = slugify(resource.name);
28170
28258
  currentSlugs.add(resSlug);
28171
28259
  writeResourceFileTree(path32.join(resourcesDir, resSlug), resource.files || [], orgDir);
28172
28260
  }
28173
- if (fs24.existsSync(resourcesDir)) {
28174
- for (const entry of fs24.readdirSync(resourcesDir, { withFileTypes: true })) {
28261
+ if (fs23.existsSync(resourcesDir)) {
28262
+ for (const entry of fs23.readdirSync(resourcesDir, { withFileTypes: true })) {
28175
28263
  if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
28176
- fs24.rmSync(path32.join(resourcesDir, entry.name), { recursive: true, force: true });
28264
+ fs23.rmSync(path32.join(resourcesDir, entry.name), { recursive: true, force: true });
28177
28265
  }
28178
28266
  }
28179
28267
  }
@@ -28193,6 +28281,7 @@ var init_org_workspace = __esm({
28193
28281
  "use strict";
28194
28282
  init_utils();
28195
28283
  init_layout();
28284
+ init_fs_safety();
28196
28285
  init_resource_files();
28197
28286
  init_yaml_writer();
28198
28287
  ORG_MANIFEST_NAME = "resources.yaml";
@@ -28478,7 +28567,7 @@ var init_report_edit_args = __esm({
28478
28567
  });
28479
28568
 
28480
28569
  // src/lib/file-map.ts
28481
- import * as fs25 from "fs";
28570
+ import * as fs24 from "fs";
28482
28571
  import * as path33 from "path";
28483
28572
  function isSafeRelPath(rel) {
28484
28573
  if (rel.length === 0 || rel.length > 300) return false;
@@ -28495,8 +28584,8 @@ function writeFileMap(targetDir, files) {
28495
28584
  throw new Error(`Refusing to write unsafe path: ${rel}`);
28496
28585
  }
28497
28586
  const abs = path33.join(targetDir, rel);
28498
- fs25.mkdirSync(path33.dirname(abs), { recursive: true });
28499
- fs25.writeFileSync(abs, body, "utf-8");
28587
+ fs24.mkdirSync(path33.dirname(abs), { recursive: true });
28588
+ fs24.writeFileSync(abs, body, "utf-8");
28500
28589
  written.push(rel);
28501
28590
  }
28502
28591
  return written;
@@ -28512,7 +28601,7 @@ var admin_exports = {};
28512
28601
  __export(admin_exports, {
28513
28602
  adminCommand: () => adminCommand
28514
28603
  });
28515
- import * as fs26 from "fs";
28604
+ import * as fs25 from "fs";
28516
28605
  import * as path34 from "path";
28517
28606
  async function adminCommand(args2) {
28518
28607
  const [group, ...afterGroup] = args2;
@@ -28828,7 +28917,7 @@ async function runArchiveRead(positional, flagArgs) {
28828
28917
  exitOnApiError(err);
28829
28918
  throw err;
28830
28919
  }
28831
- fs26.writeFileSync(outPath, zip);
28920
+ fs25.writeFileSync(outPath, zip);
28832
28921
  console.log(`Wrote ${zip.byteLength} bytes to ${outPath}`);
28833
28922
  return;
28834
28923
  }
@@ -28970,7 +29059,7 @@ async function runSkillInstall(positional) {
28970
29059
  throw err;
28971
29060
  }
28972
29061
  const root = findGitRoot() ?? process.cwd();
28973
- const present = HARNESS_SKILL_DIRS.filter((dir) => fs26.existsSync(path34.join(root, dir)));
29062
+ const present = HARNESS_SKILL_DIRS.filter((dir) => fs25.existsSync(path34.join(root, dir)));
28974
29063
  const targets = present.length > 0 ? present : HARNESS_SKILL_DIRS;
28975
29064
  const fileCount = Object.keys(res.files).length;
28976
29065
  const relDirs = targets.map((harness) => {
@@ -30528,7 +30617,7 @@ var init_actions = __esm({
30528
30617
 
30529
30618
  // src/data/commands/attachments.ts
30530
30619
  import { Command as Command2 } from "commander";
30531
- import { readFileSync as readFileSync20 } from "fs";
30620
+ import { readFileSync as readFileSync18 } from "fs";
30532
30621
  function findAttachmentByFilename(attachments, filename) {
30533
30622
  return attachments.find((a) => a.key.endsWith(`/${filename}`)) ?? null;
30534
30623
  }
@@ -30569,7 +30658,7 @@ function buildAttachmentsCommand() {
30569
30658
  printOutput(data, outputFormat(this));
30570
30659
  return;
30571
30660
  }
30572
- const body = readFileSync20(opts.file);
30661
+ const body = readFileSync18(opts.file);
30573
30662
  await client.upload(uploadPathFrom(data?.upload_url), body, opts.contentType);
30574
30663
  printOutput({ ...data, uploaded: true }, outputFormat(this));
30575
30664
  });
@@ -30969,7 +31058,7 @@ var init_import = __esm({
30969
31058
 
30970
31059
  // src/data/commands/providers.ts
30971
31060
  import { Command as Command5 } from "commander";
30972
- import { writeFileSync as writeFileSync14 } from "fs";
31061
+ import { writeFileSync as writeFileSync9 } from "fs";
30973
31062
  function providerSegment(provider) {
30974
31063
  if (!VALID_PROVIDERS.includes(provider)) {
30975
31064
  throw expected(`Unknown provider ${JSON.stringify(provider)}. Expected one of: ${VALID_PROVIDERS_HELP}.`);
@@ -31002,7 +31091,7 @@ function buildBasesProvidersCommand() {
31002
31091
  );
31003
31092
  if (opts.to) {
31004
31093
  try {
31005
- writeFileSync14(opts.to, JSON.stringify(data, null, 2));
31094
+ writeFileSync9(opts.to, JSON.stringify(data, null, 2));
31006
31095
  } catch (e) {
31007
31096
  throw expected(`--to ${opts.to}: ${e instanceof Error ? e.message : "could not be written"}`);
31008
31097
  }
@@ -31049,7 +31138,7 @@ var init_providers = __esm({
31049
31138
 
31050
31139
  // src/data/commands/report.ts
31051
31140
  import { Command as Command6 } from "commander";
31052
- import { readFileSync as readFileSync21 } from "fs";
31141
+ import { readFileSync as readFileSync19 } from "fs";
31053
31142
  import { dirname as dirname12, join as join30 } from "path";
31054
31143
  import { fileURLToPath as fileURLToPath2 } from "url";
31055
31144
  function resolveCliVersion() {
@@ -31058,7 +31147,7 @@ function resolveCliVersion() {
31058
31147
  join30(here, "..", "..", "..", "package.json")
31059
31148
  ]) {
31060
31149
  try {
31061
- const version = JSON.parse(readFileSync21(candidate, "utf-8")).version;
31150
+ const version = JSON.parse(readFileSync19(candidate, "utf-8")).version;
31062
31151
  if (typeof version === "string" && version) return version;
31063
31152
  } catch {
31064
31153
  }
@@ -31260,7 +31349,7 @@ var init_report2 = __esm({
31260
31349
 
31261
31350
  // src/data/commands/credentials.ts
31262
31351
  import { Command as Command7 } from "commander";
31263
- import { readFileSync as readFileSync22 } from "fs";
31352
+ import { readFileSync as readFileSync20 } from "fs";
31264
31353
  function withValueSourceOptions(cmd, what) {
31265
31354
  return cmd.option(
31266
31355
  "--file <path>",
@@ -31273,7 +31362,7 @@ async function resolveValue(opts, label) {
31273
31362
  throw expected("--file cannot be combined with --value-stdin or --value-prompt \u2014 pass one.");
31274
31363
  }
31275
31364
  try {
31276
- return readFileSync22(opts.file).toString("base64");
31365
+ return readFileSync20(opts.file).toString("base64");
31277
31366
  } catch (e) {
31278
31367
  throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
31279
31368
  }
@@ -31422,7 +31511,7 @@ var init_credentials = __esm({
31422
31511
 
31423
31512
  // src/data/commands/sql.ts
31424
31513
  import { Command as Command8 } from "commander";
31425
- import { readFileSync as readFileSync23 } from "fs";
31514
+ import { readFileSync as readFileSync21 } from "fs";
31426
31515
  function buildBasesSqlCommand() {
31427
31516
  return withBaseOption(new Command8("sql")).description("Execute a read-only SQL query against base data").argument("[query]", "SQL query (SELECT only)").option("--file <path>", "Read SQL from a file instead of the argument").option(
31428
31517
  "--param <kv...>",
@@ -31432,7 +31521,7 @@ function buildBasesSqlCommand() {
31432
31521
  let query;
31433
31522
  if (opts.file) {
31434
31523
  try {
31435
- query = readFileSync23(opts.file, "utf-8").trim();
31524
+ query = readFileSync21(opts.file, "utf-8").trim();
31436
31525
  } catch (e) {
31437
31526
  throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
31438
31527
  }
@@ -32087,8 +32176,8 @@ var init_file_types = __esm({
32087
32176
 
32088
32177
  // src/data/commands/files.ts
32089
32178
  import { Command as Command12 } from "commander";
32090
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
32091
- import { basename as basename18 } from "path";
32179
+ import { readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "fs";
32180
+ import { basename as basename19 } from "path";
32092
32181
  function renderFileDiff(fileType, filePath, from, to, d) {
32093
32182
  console.log(sanitizeTerminalText(`${fileType}/${filePath}: v${from} \u2192 v${to}`));
32094
32183
  const md = d.metadata_delta;
@@ -32120,7 +32209,7 @@ function renderFileDiff(fileType, filePath, from, to, d) {
32120
32209
  }
32121
32210
  function downloadTarget(remotePath, to) {
32122
32211
  if (to) return to;
32123
- const derived = basename18(remotePath);
32212
+ const derived = basename19(remotePath);
32124
32213
  if (derived === "" || derived === "." || derived === "..") {
32125
32214
  throw expected(
32126
32215
  `Cannot derive a local filename from "${remotePath}" \u2014 pass --to <local> to name it.`
@@ -32136,7 +32225,7 @@ function buildFilesCommand() {
32136
32225
  "Upload a local file to a path (e.g. wayai files put reports q3/summary.pdf --file ./summary.pdf)"
32137
32226
  ).requiredOption("--file <local>", "Local file to upload").option("--content-type <type>", "MIME type", "application/octet-stream").action(async function(fileType, filePath, opts) {
32138
32227
  const base = pathSegment(requireBase(this), "--base");
32139
- const body = readFileSync24(opts.file);
32228
+ const body = readFileSync22(opts.file);
32140
32229
  const client = await createDataClient();
32141
32230
  printOutput(
32142
32231
  await client.upload(
@@ -32167,7 +32256,7 @@ function buildFilesCommand() {
32167
32256
  const { bytes } = await client.download(
32168
32257
  `/v1/${base}/files/${pathSegment(fileType, "file_type")}/${encoded}${versionQs ? `?${versionQs}` : ""}`
32169
32258
  );
32170
- writeFileSync15(out, bytes);
32259
+ writeFileSync10(out, bytes);
32171
32260
  console.log(`Downloaded to ${out}`);
32172
32261
  });
32173
32262
  files.command("history <file_type> <path>").description("List the content versions of a file (newest first)").option("--limit <n>", "Max versions to return").option("--offset <n>", "Pagination offset").action(async function(fileType, filePath, opts) {
@@ -33185,7 +33274,7 @@ init_errors2();
33185
33274
  init_mask_secrets();
33186
33275
  init_utils();
33187
33276
  init_registry();
33188
- import { readFileSync as readFileSync25 } from "fs";
33277
+ import { readFileSync as readFileSync23 } from "fs";
33189
33278
  import { fileURLToPath as fileURLToPath3 } from "url";
33190
33279
  import { dirname as dirname13, join as join31 } from "path";
33191
33280
 
@@ -33343,7 +33432,7 @@ Run \`wayai admin skill install\` to update.`);
33343
33432
 
33344
33433
  // src/index.ts
33345
33434
  var __dirname = dirname13(fileURLToPath3(import.meta.url));
33346
- var pkg = JSON.parse(readFileSync25(join31(__dirname, "..", "package.json"), "utf-8"));
33435
+ var pkg = JSON.parse(readFileSync23(join31(__dirname, "..", "package.json"), "utf-8"));
33347
33436
  var [, , command, ...args] = process.argv;
33348
33437
  var isBackgroundRefresh = command === REFRESH_COMMAND;
33349
33438
  if (!isBackgroundRefresh) initSentry(command, pkg.version);