@wayai/cli 0.3.164 → 0.3.166
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 +535 -405
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17455,40 +17455,228 @@ var init_expected = __esm({
|
|
|
17455
17455
|
}
|
|
17456
17456
|
});
|
|
17457
17457
|
|
|
17458
|
-
// src/lib/
|
|
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 isUnder(parent, child) {
|
|
17532
|
+
const rel = path.relative(parent, child);
|
|
17533
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel);
|
|
17534
|
+
}
|
|
17535
|
+
function isSymlink(p) {
|
|
17536
|
+
try {
|
|
17537
|
+
return fs.lstatSync(p).isSymbolicLink();
|
|
17538
|
+
} catch {
|
|
17539
|
+
return false;
|
|
17540
|
+
}
|
|
17541
|
+
}
|
|
17542
|
+
function workspaceRefusal(message) {
|
|
17543
|
+
const err = expected(message);
|
|
17544
|
+
err.isWorkspaceRefusal = true;
|
|
17545
|
+
return err;
|
|
17546
|
+
}
|
|
17547
|
+
function isWorkspaceRefusal(err) {
|
|
17548
|
+
return err?.isWorkspaceRefusal === true;
|
|
17549
|
+
}
|
|
17550
|
+
function symlinkRefusal(rel, kind) {
|
|
17551
|
+
return workspaceRefusal(
|
|
17552
|
+
`${rel} is a symlink, is reached through one, or is not a ${kind}. The CLI never reads or writes workspace config through a symlink \u2014 make it a real ${kind}.`
|
|
17553
|
+
);
|
|
17554
|
+
}
|
|
17555
|
+
function requireRealSubdirNoSymlink(root, target, create) {
|
|
17556
|
+
if (ensureRealSubdirNoSymlink(root, target, create)) return;
|
|
17557
|
+
throw symlinkRefusal(path.relative(path.dirname(root), target), "directory");
|
|
17558
|
+
}
|
|
17559
|
+
function requireRealHubFolder(hubFolder, create) {
|
|
17560
|
+
if (!create) {
|
|
17561
|
+
try {
|
|
17562
|
+
fs.lstatSync(hubFolder);
|
|
17563
|
+
} catch {
|
|
17564
|
+
return;
|
|
17565
|
+
}
|
|
17566
|
+
}
|
|
17567
|
+
requireRealSubdirNoSymlink(path.dirname(hubFolder), hubFolder, create);
|
|
17568
|
+
for (const sub of HUB_MANAGED_SUBDIRS) {
|
|
17569
|
+
requireRealSubdirNoSymlink(hubFolder, path.join(hubFolder, sub), false);
|
|
17570
|
+
}
|
|
17571
|
+
for (const name of HUB_CONFIG_FILES) {
|
|
17572
|
+
let st;
|
|
17573
|
+
try {
|
|
17574
|
+
st = fs.lstatSync(path.join(hubFolder, name));
|
|
17575
|
+
} catch {
|
|
17576
|
+
continue;
|
|
17577
|
+
}
|
|
17578
|
+
if (!st.isFile()) throw symlinkRefusal(path.join(path.basename(hubFolder), name), "file");
|
|
17579
|
+
}
|
|
17580
|
+
}
|
|
17581
|
+
function readRealFileOrThrow(root, abs) {
|
|
17582
|
+
let st;
|
|
17583
|
+
try {
|
|
17584
|
+
st = fs.lstatSync(abs);
|
|
17585
|
+
} catch {
|
|
17586
|
+
return null;
|
|
17587
|
+
}
|
|
17588
|
+
const bytes = st.isFile() ? readFileNoFollow(root, abs) : null;
|
|
17589
|
+
if (!bytes) throw symlinkRefusal(path.relative(path.dirname(root), abs), "file");
|
|
17590
|
+
return bytes.toString("utf-8");
|
|
17591
|
+
}
|
|
17592
|
+
function readFileNoFollow(root, abs) {
|
|
17593
|
+
if (!ensureRealSubdirNoSymlink(root, path.dirname(abs), false)) return null;
|
|
17594
|
+
try {
|
|
17595
|
+
if (!fs.lstatSync(abs).isFile()) return null;
|
|
17596
|
+
return fs.readFileSync(abs);
|
|
17597
|
+
} catch {
|
|
17598
|
+
return null;
|
|
17599
|
+
}
|
|
17600
|
+
}
|
|
17601
|
+
function writeFileNoFollow(root, abs, data) {
|
|
17602
|
+
const parent = path.dirname(abs);
|
|
17603
|
+
if (!ensureRealSubdirNoSymlink(root, parent, true)) return false;
|
|
17604
|
+
let st;
|
|
17605
|
+
try {
|
|
17606
|
+
st = fs.lstatSync(abs);
|
|
17607
|
+
} catch {
|
|
17608
|
+
}
|
|
17609
|
+
if (st?.isSymbolicLink()) fs.rmSync(abs);
|
|
17610
|
+
fs.writeFileSync(abs, data);
|
|
17611
|
+
return true;
|
|
17612
|
+
}
|
|
17613
|
+
function createFileNoFollow(root, abs, data) {
|
|
17614
|
+
if (!ensureRealSubdirNoSymlink(root, path.dirname(abs), true)) return "refused";
|
|
17615
|
+
try {
|
|
17616
|
+
fs.writeFileSync(abs, data, { flag: "wx" });
|
|
17617
|
+
} catch (err) {
|
|
17618
|
+
if (err.code === "EEXIST") return "exists";
|
|
17619
|
+
throw err;
|
|
17620
|
+
}
|
|
17621
|
+
return "created";
|
|
17622
|
+
}
|
|
17623
|
+
var HUB_MANAGED_SUBDIRS, HUB_CONFIG_FILES;
|
|
17624
|
+
var init_fs_safety = __esm({
|
|
17625
|
+
"src/lib/fs-safety.ts"() {
|
|
17626
|
+
"use strict";
|
|
17627
|
+
init_expected();
|
|
17628
|
+
HUB_MANAGED_SUBDIRS = ["agents", "evals", "journeys", "resources", "attachments"];
|
|
17629
|
+
HUB_CONFIG_FILES = ["hub.yaml", "wayai.yaml"];
|
|
17630
|
+
}
|
|
17631
|
+
});
|
|
17632
|
+
|
|
17633
|
+
// src/lib/layout.ts
|
|
17634
|
+
import * as fs2 from "fs";
|
|
17635
|
+
import * as path2 from "path";
|
|
17461
17636
|
function isDirectory(p) {
|
|
17462
17637
|
try {
|
|
17463
|
-
return
|
|
17638
|
+
return fs2.statSync(p).isDirectory();
|
|
17639
|
+
} catch {
|
|
17640
|
+
return false;
|
|
17641
|
+
}
|
|
17642
|
+
}
|
|
17643
|
+
function isRealDirectory(p) {
|
|
17644
|
+
try {
|
|
17645
|
+
return fs2.lstatSync(p).isDirectory();
|
|
17464
17646
|
} catch {
|
|
17465
17647
|
return false;
|
|
17466
17648
|
}
|
|
17467
17649
|
}
|
|
17468
17650
|
function resolveLayout(gitRoot, layout = WAYAI_LAYOUT) {
|
|
17469
|
-
const newWs =
|
|
17470
|
-
const legacyWs =
|
|
17471
|
-
const legacyOrg =
|
|
17472
|
-
const legacyExists =
|
|
17473
|
-
const basesDir =
|
|
17474
|
-
const hubsDir =
|
|
17475
|
-
const orgDir =
|
|
17651
|
+
const newWs = path2.join(gitRoot, layout.wsDir);
|
|
17652
|
+
const legacyWs = path2.join(gitRoot, layout.legacy.wsDir);
|
|
17653
|
+
const legacyOrg = path2.join(gitRoot, layout.legacy.orgAtRoot);
|
|
17654
|
+
const legacyExists = isRealDirectory(legacyWs) || isRealDirectory(legacyOrg);
|
|
17655
|
+
const basesDir = path2.join(newWs, layout.basesSubdir);
|
|
17656
|
+
const hubsDir = path2.join(newWs, layout.hubsSubdir);
|
|
17657
|
+
const orgDir = path2.join(newWs, layout.orgSubdir);
|
|
17476
17658
|
const newDisplacesLegacy = () => isDirectory(hubsDir) || isDirectory(orgDir) || isDirectory(basesDir);
|
|
17659
|
+
let resolved;
|
|
17477
17660
|
if (legacyExists && !newDisplacesLegacy()) {
|
|
17478
|
-
|
|
17661
|
+
resolved = { hubsDir: legacyWs, orgDir: legacyOrg, basesDir, isLegacy: true, legacyAlsoPresent: false };
|
|
17662
|
+
} else {
|
|
17663
|
+
resolved = { hubsDir, orgDir, basesDir, isLegacy: false, legacyAlsoPresent: legacyExists };
|
|
17479
17664
|
}
|
|
17480
|
-
|
|
17665
|
+
for (const dir of [resolved.hubsDir, resolved.orgDir, resolved.basesDir]) {
|
|
17666
|
+
requireRealSubdirNoSymlink(gitRoot, dir, false);
|
|
17667
|
+
}
|
|
17668
|
+
return resolved;
|
|
17481
17669
|
}
|
|
17482
17670
|
function resolveBasesDir(gitRoot) {
|
|
17483
17671
|
return resolveLayout(gitRoot).basesDir;
|
|
17484
17672
|
}
|
|
17485
17673
|
function hubsDirLabel(gitRoot) {
|
|
17486
|
-
if (!gitRoot) return
|
|
17487
|
-
return
|
|
17674
|
+
if (!gitRoot) return path2.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.hubsSubdir);
|
|
17675
|
+
return path2.relative(gitRoot, resolveLayout(gitRoot).hubsDir);
|
|
17488
17676
|
}
|
|
17489
17677
|
function basesDirLabel(gitRoot) {
|
|
17490
|
-
if (!gitRoot) return
|
|
17491
|
-
return
|
|
17678
|
+
if (!gitRoot) return path2.join(WAYAI_LAYOUT.wsDir, WAYAI_LAYOUT.basesSubdir);
|
|
17679
|
+
return path2.relative(gitRoot, resolveLayout(gitRoot).basesDir);
|
|
17492
17680
|
}
|
|
17493
17681
|
function warnLayoutOnce(gitRoot) {
|
|
17494
17682
|
const r = resolveLayout(gitRoot);
|
|
@@ -17516,6 +17704,7 @@ var init_layout = __esm({
|
|
|
17516
17704
|
"src/lib/layout.ts"() {
|
|
17517
17705
|
"use strict";
|
|
17518
17706
|
init_dist();
|
|
17707
|
+
init_fs_safety();
|
|
17519
17708
|
WAYAI_LAYOUT = {
|
|
17520
17709
|
...WAYAI_WORKSPACE_LAYOUT,
|
|
17521
17710
|
legacy: { wsDir: "workspace", orgAtRoot: "org" }
|
|
@@ -17550,8 +17739,8 @@ __export(workspace_exports, {
|
|
|
17550
17739
|
scanWorkspaceHubs: () => scanWorkspaceHubs
|
|
17551
17740
|
});
|
|
17552
17741
|
import { execFileSync } from "child_process";
|
|
17553
|
-
import * as
|
|
17554
|
-
import * as
|
|
17742
|
+
import * as fs3 from "fs";
|
|
17743
|
+
import * as path3 from "path";
|
|
17555
17744
|
import * as yaml from "js-yaml";
|
|
17556
17745
|
function findGitRoot() {
|
|
17557
17746
|
try {
|
|
@@ -17566,8 +17755,8 @@ function findGitRoot() {
|
|
|
17566
17755
|
function findRepoRootSync() {
|
|
17567
17756
|
let current = process.cwd();
|
|
17568
17757
|
while (true) {
|
|
17569
|
-
if (
|
|
17570
|
-
const parent =
|
|
17758
|
+
if (fs3.existsSync(path3.join(current, ".git"))) return current;
|
|
17759
|
+
const parent = path3.dirname(current);
|
|
17571
17760
|
if (parent === current) return null;
|
|
17572
17761
|
current = parent;
|
|
17573
17762
|
}
|
|
@@ -17576,7 +17765,7 @@ function detectWorkspace() {
|
|
|
17576
17765
|
const gitRoot = findGitRoot();
|
|
17577
17766
|
if (!gitRoot) return null;
|
|
17578
17767
|
const { hubsDir } = resolveLayout(gitRoot);
|
|
17579
|
-
if (!
|
|
17768
|
+
if (!fs3.existsSync(hubsDir) || !fs3.statSync(hubsDir).isDirectory()) {
|
|
17580
17769
|
return null;
|
|
17581
17770
|
}
|
|
17582
17771
|
return { gitRoot, workspaceDir: hubsDir };
|
|
@@ -17592,10 +17781,9 @@ function resolveWorkspaceDir() {
|
|
|
17592
17781
|
return resolveLayout(gitRoot).hubsDir;
|
|
17593
17782
|
}
|
|
17594
17783
|
function readHubYaml(yamlPath) {
|
|
17595
|
-
if (!
|
|
17784
|
+
if (!fs3.existsSync(yamlPath) || isSymlink(yamlPath)) return null;
|
|
17596
17785
|
try {
|
|
17597
|
-
const
|
|
17598
|
-
const config = yaml.load(content);
|
|
17786
|
+
const config = yaml.load(fs3.readFileSync(yamlPath, "utf-8"));
|
|
17599
17787
|
if (!config?.hub_id || !config.hub_environment) return null;
|
|
17600
17788
|
return { hubId: config.hub_id, hubEnvironment: config.hub_environment };
|
|
17601
17789
|
} catch {
|
|
@@ -17605,9 +17793,9 @@ function readHubYaml(yamlPath) {
|
|
|
17605
17793
|
function scanWorkspaceHubs(workspaceDir) {
|
|
17606
17794
|
const hubs = [];
|
|
17607
17795
|
for (const top of safeReaddir(workspaceDir)) {
|
|
17608
|
-
const topDir =
|
|
17609
|
-
if (!
|
|
17610
|
-
const meta = readHubYaml(
|
|
17796
|
+
const topDir = path3.join(workspaceDir, top);
|
|
17797
|
+
if (!isRealDirectory(topDir)) continue;
|
|
17798
|
+
const meta = readHubYaml(path3.join(topDir, "hub.yaml")) || readHubYaml(path3.join(topDir, "wayai.yaml"));
|
|
17611
17799
|
if (meta) {
|
|
17612
17800
|
hubs.push({ hubFolder: topDir, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
|
|
17613
17801
|
}
|
|
@@ -17621,10 +17809,9 @@ function filterPreviewHubs(hubs) {
|
|
|
17621
17809
|
return hubs.filter(isPreviewHub);
|
|
17622
17810
|
}
|
|
17623
17811
|
function readNewHubYaml(yamlPath) {
|
|
17624
|
-
if (!
|
|
17812
|
+
if (!fs3.existsSync(yamlPath) || isSymlink(yamlPath)) return null;
|
|
17625
17813
|
try {
|
|
17626
|
-
const
|
|
17627
|
-
const config = yaml.load(content);
|
|
17814
|
+
const config = yaml.load(fs3.readFileSync(yamlPath, "utf-8"));
|
|
17628
17815
|
if (config?.hub_id) return null;
|
|
17629
17816
|
if (!config?.hub?.name) return null;
|
|
17630
17817
|
return { hubName: config.hub.name, hubType: config.hub.hub_type };
|
|
@@ -17635,9 +17822,9 @@ function readNewHubYaml(yamlPath) {
|
|
|
17635
17822
|
function scanNewHubs(workspaceDir) {
|
|
17636
17823
|
const hubs = [];
|
|
17637
17824
|
for (const top of safeReaddir(workspaceDir)) {
|
|
17638
|
-
const topDir =
|
|
17639
|
-
if (!
|
|
17640
|
-
const meta = readNewHubYaml(
|
|
17825
|
+
const topDir = path3.join(workspaceDir, top);
|
|
17826
|
+
if (!isRealDirectory(topDir)) continue;
|
|
17827
|
+
const meta = readNewHubYaml(path3.join(topDir, "hub.yaml")) || readNewHubYaml(path3.join(topDir, "wayai.yaml"));
|
|
17641
17828
|
if (meta) {
|
|
17642
17829
|
hubs.push({ hubFolder: topDir, hubName: meta.hubName, hubType: meta.hubType });
|
|
17643
17830
|
}
|
|
@@ -17657,22 +17844,22 @@ function resolveHubFolder(workspaceDir, hubId, hubName, hubEnvironment, previewL
|
|
|
17657
17844
|
if (match) return match.hubFolder;
|
|
17658
17845
|
}
|
|
17659
17846
|
const hubFolderSlug = getHubFolderSlug(hubName, hubEnvironment, hubId || "", previewLabel, branchName);
|
|
17660
|
-
return
|
|
17847
|
+
return path3.join(workspaceDir, hubFolderSlug);
|
|
17661
17848
|
}
|
|
17662
17849
|
function findLocalHubFolder(hubId) {
|
|
17663
17850
|
const workspace = detectWorkspace();
|
|
17664
17851
|
const gitRoot = findGitRoot();
|
|
17665
17852
|
const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
|
|
17666
|
-
if (!workspaceDir || !
|
|
17853
|
+
if (!workspaceDir || !fs3.existsSync(workspaceDir)) return null;
|
|
17667
17854
|
const match = scanWorkspaceHubs(workspaceDir).find((h) => h.hubId === hubId);
|
|
17668
17855
|
return match ? match.hubFolder : null;
|
|
17669
17856
|
}
|
|
17670
17857
|
function getChangedHubs(workspaceDir) {
|
|
17671
17858
|
const gitRoot = findGitRoot();
|
|
17672
17859
|
if (!gitRoot) return [];
|
|
17673
|
-
const relWorkspace =
|
|
17674
|
-
const normalizedRel =
|
|
17675
|
-
if (normalizedRel.startsWith("..") ||
|
|
17860
|
+
const relWorkspace = path3.relative(gitRoot, workspaceDir);
|
|
17861
|
+
const normalizedRel = path3.normalize(relWorkspace);
|
|
17862
|
+
if (normalizedRel.startsWith("..") || path3.isAbsolute(normalizedRel)) {
|
|
17676
17863
|
return [];
|
|
17677
17864
|
}
|
|
17678
17865
|
let statusOutput;
|
|
@@ -17697,9 +17884,9 @@ function getChangedHubs(workspaceDir) {
|
|
|
17697
17884
|
if (hubFiles.length === 0) return [];
|
|
17698
17885
|
const hubFolders = /* @__PURE__ */ new Set();
|
|
17699
17886
|
for (const file of hubFiles) {
|
|
17700
|
-
const absFile =
|
|
17887
|
+
const absFile = path3.resolve(gitRoot, file);
|
|
17701
17888
|
if (file.endsWith("hub.yaml") || file.endsWith("wayai.yaml")) {
|
|
17702
|
-
hubFolders.add(
|
|
17889
|
+
hubFolders.add(path3.dirname(absFile));
|
|
17703
17890
|
} else if (file.includes("/agents/")) {
|
|
17704
17891
|
const agentsIndex = absFile.lastIndexOf("/agents/");
|
|
17705
17892
|
hubFolders.add(absFile.substring(0, agentsIndex));
|
|
@@ -17707,7 +17894,8 @@ function getChangedHubs(workspaceDir) {
|
|
|
17707
17894
|
}
|
|
17708
17895
|
const hubs = [];
|
|
17709
17896
|
for (const hubFolder of hubFolders) {
|
|
17710
|
-
|
|
17897
|
+
if (!isRealDirectory(hubFolder)) continue;
|
|
17898
|
+
const meta = readHubYaml(path3.join(hubFolder, "hub.yaml")) || readHubYaml(path3.join(hubFolder, "wayai.yaml"));
|
|
17711
17899
|
if (meta) {
|
|
17712
17900
|
hubs.push({ hubFolder, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment });
|
|
17713
17901
|
}
|
|
@@ -17742,19 +17930,19 @@ function resolveExplicitHubPath(hubPath) {
|
|
|
17742
17930
|
}
|
|
17743
17931
|
function findHubByFolderName(workspaceDir, hubFolderName) {
|
|
17744
17932
|
const all = scanWorkspaceHubs(workspaceDir);
|
|
17745
|
-
return all.find((h) =>
|
|
17933
|
+
return all.find((h) => path3.basename(h.hubFolder) === hubFolderName) ?? null;
|
|
17746
17934
|
}
|
|
17747
17935
|
function autoRenameHubFolder(currentFolder, hubName, hubEnvironment, hubId, previewLabel, branchName) {
|
|
17748
17936
|
const expectedSlug = getHubFolderSlug(hubName, hubEnvironment, hubId, previewLabel, branchName);
|
|
17749
|
-
const currentSlug =
|
|
17937
|
+
const currentSlug = path3.basename(currentFolder);
|
|
17750
17938
|
if (currentSlug === expectedSlug) return currentFolder;
|
|
17751
|
-
const targetFolder =
|
|
17752
|
-
if (
|
|
17939
|
+
const targetFolder = path3.join(path3.dirname(currentFolder), expectedSlug);
|
|
17940
|
+
if (fs3.existsSync(targetFolder)) {
|
|
17753
17941
|
console.warn(` Warning: skipping hub folder rename ${currentSlug} \u2192 ${expectedSlug} (target already exists)`);
|
|
17754
17942
|
return currentFolder;
|
|
17755
17943
|
}
|
|
17756
17944
|
try {
|
|
17757
|
-
|
|
17945
|
+
fs3.renameSync(currentFolder, targetFolder);
|
|
17758
17946
|
} catch (err) {
|
|
17759
17947
|
console.warn(` Warning: could not rename ${currentSlug} \u2192 ${expectedSlug}: ${err instanceof Error ? err.message : String(err)}`);
|
|
17760
17948
|
return currentFolder;
|
|
@@ -17765,39 +17953,37 @@ function autoRenameHubFolder(currentFolder, hubName, hubEnvironment, hubId, prev
|
|
|
17765
17953
|
}
|
|
17766
17954
|
function findEnclosingHubFolder(workspaceDir) {
|
|
17767
17955
|
let current = process.cwd();
|
|
17768
|
-
const stop =
|
|
17769
|
-
while (
|
|
17770
|
-
const meta = readHubYaml(
|
|
17956
|
+
const stop = path3.resolve(workspaceDir);
|
|
17957
|
+
while (isUnder(stop, current)) {
|
|
17958
|
+
const meta = readHubYaml(path3.join(current, "hub.yaml")) || readHubYaml(path3.join(current, "wayai.yaml"));
|
|
17771
17959
|
if (meta) {
|
|
17772
17960
|
return { hubFolder: current, hubId: meta.hubId, hubEnvironment: meta.hubEnvironment };
|
|
17773
17961
|
}
|
|
17774
17962
|
if (current === stop) return null;
|
|
17775
|
-
|
|
17776
|
-
if (parent === current) return null;
|
|
17777
|
-
current = parent;
|
|
17963
|
+
current = path3.dirname(current);
|
|
17778
17964
|
}
|
|
17965
|
+
return null;
|
|
17779
17966
|
}
|
|
17780
17967
|
function findEnclosingNewHubFolder(workspaceDir) {
|
|
17781
17968
|
let current = process.cwd();
|
|
17782
|
-
const stop =
|
|
17783
|
-
while (
|
|
17784
|
-
const meta = readNewHubYaml(
|
|
17969
|
+
const stop = path3.resolve(workspaceDir);
|
|
17970
|
+
while (isUnder(stop, current)) {
|
|
17971
|
+
const meta = readNewHubYaml(path3.join(current, "hub.yaml")) || readNewHubYaml(path3.join(current, "wayai.yaml"));
|
|
17785
17972
|
if (meta) {
|
|
17786
17973
|
return { hubFolder: current, hubName: meta.hubName, hubType: meta.hubType };
|
|
17787
17974
|
}
|
|
17788
17975
|
if (current === stop) return null;
|
|
17789
|
-
|
|
17790
|
-
if (parent === current) return null;
|
|
17791
|
-
current = parent;
|
|
17976
|
+
current = path3.dirname(current);
|
|
17792
17977
|
}
|
|
17978
|
+
return null;
|
|
17793
17979
|
}
|
|
17794
17980
|
function resolvePushTarget(workspaceDir, existingHubs, newHubs, selector) {
|
|
17795
17981
|
if (selector) {
|
|
17796
17982
|
const existingMatch = existingHubs.find(
|
|
17797
|
-
(h) => h.hubId === selector ||
|
|
17983
|
+
(h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
|
|
17798
17984
|
);
|
|
17799
17985
|
if (existingMatch) return { ok: true, target: { kind: "existing", hub: existingMatch } };
|
|
17800
|
-
const newMatch = newHubs.find((h) =>
|
|
17986
|
+
const newMatch = newHubs.find((h) => path3.basename(h.hubFolder) === selector);
|
|
17801
17987
|
if (newMatch) return { ok: true, target: { kind: "new", hub: newMatch } };
|
|
17802
17988
|
return { ok: false, reason: "selector_miss" };
|
|
17803
17989
|
}
|
|
@@ -17813,10 +17999,10 @@ function resolvePushTarget(workspaceDir, existingHubs, newHubs, selector) {
|
|
|
17813
17999
|
}
|
|
17814
18000
|
function resolveNewHubForCreate(workspaceDir, existingHubs, newHubs, selector) {
|
|
17815
18001
|
if (selector) {
|
|
17816
|
-
const newMatch = newHubs.find((h) =>
|
|
18002
|
+
const newMatch = newHubs.find((h) => path3.basename(h.hubFolder) === selector);
|
|
17817
18003
|
if (newMatch) return { ok: true, hub: newMatch };
|
|
17818
18004
|
const existingMatch = existingHubs.find(
|
|
17819
|
-
(h) => h.hubId === selector ||
|
|
18005
|
+
(h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
|
|
17820
18006
|
);
|
|
17821
18007
|
if (existingMatch) return { ok: false, reason: "exists", existing: existingMatch };
|
|
17822
18008
|
return { ok: false, reason: "selector_miss" };
|
|
@@ -17843,7 +18029,7 @@ function resolveActiveHubId(args2) {
|
|
|
17843
18029
|
const gitRoot = findGitRoot();
|
|
17844
18030
|
const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
|
|
17845
18031
|
const wsLabel = hubsDirLabel(gitRoot);
|
|
17846
|
-
if (!workspaceDir || !
|
|
18032
|
+
if (!workspaceDir || !fs3.existsSync(workspaceDir)) {
|
|
17847
18033
|
if (selector && UUID_RE2.test(selector)) return selector;
|
|
17848
18034
|
console.error(`No ${wsLabel}/ directory found. Run \`wayai pull --hub <uuid>\` to fetch a hub, or pass --hub <uuid>.`);
|
|
17849
18035
|
process.exit(1);
|
|
@@ -17851,7 +18037,7 @@ function resolveActiveHubId(args2) {
|
|
|
17851
18037
|
const allHubs = scanWorkspaceHubs(workspaceDir);
|
|
17852
18038
|
if (selector) {
|
|
17853
18039
|
const match = allHubs.find(
|
|
17854
|
-
(h) => h.hubId === selector ||
|
|
18040
|
+
(h) => h.hubId === selector || path3.basename(h.hubFolder) === selector
|
|
17855
18041
|
);
|
|
17856
18042
|
if (match) return match.hubId;
|
|
17857
18043
|
if (UUID_RE2.test(selector)) return selector;
|
|
@@ -17868,7 +18054,7 @@ function resolveActiveHubId(args2) {
|
|
|
17868
18054
|
}
|
|
17869
18055
|
console.error(`Multiple hubs in ${wsLabel}/. Pass --hub <uuid|folder-name> or run from inside a hub folder:`);
|
|
17870
18056
|
for (const h of previewHubs) {
|
|
17871
|
-
console.error(` ${
|
|
18057
|
+
console.error(` ${path3.basename(h.hubFolder)} (${h.hubId})`);
|
|
17872
18058
|
}
|
|
17873
18059
|
process.exit(1);
|
|
17874
18060
|
}
|
|
@@ -17876,12 +18062,12 @@ function localHubEnvironment(hubId) {
|
|
|
17876
18062
|
const workspace = detectWorkspace();
|
|
17877
18063
|
const gitRoot = findGitRoot();
|
|
17878
18064
|
const workspaceDir = workspace?.workspaceDir ?? (gitRoot ? resolveLayout(gitRoot).hubsDir : null);
|
|
17879
|
-
if (!workspaceDir || !
|
|
18065
|
+
if (!workspaceDir || !fs3.existsSync(workspaceDir)) return null;
|
|
17880
18066
|
return scanWorkspaceHubs(workspaceDir).find((h) => h.hubId === hubId)?.hubEnvironment ?? null;
|
|
17881
18067
|
}
|
|
17882
18068
|
function safeReaddir(dir) {
|
|
17883
18069
|
try {
|
|
17884
|
-
return
|
|
18070
|
+
return fs3.readdirSync(dir).filter((entry) => !entry.startsWith("."));
|
|
17885
18071
|
} catch {
|
|
17886
18072
|
return [];
|
|
17887
18073
|
}
|
|
@@ -17891,23 +18077,29 @@ var init_workspace = __esm({
|
|
|
17891
18077
|
"use strict";
|
|
17892
18078
|
init_utils();
|
|
17893
18079
|
init_layout();
|
|
18080
|
+
init_fs_safety();
|
|
17894
18081
|
}
|
|
17895
18082
|
});
|
|
17896
18083
|
|
|
17897
18084
|
// src/lib/workspace-manifest.ts
|
|
17898
|
-
import * as
|
|
17899
|
-
import * as
|
|
18085
|
+
import * as fs4 from "fs";
|
|
18086
|
+
import * as path4 from "path";
|
|
17900
18087
|
import * as yaml2 from "js-yaml";
|
|
17901
18088
|
function workspaceManifestPath(gitRoot) {
|
|
17902
|
-
return
|
|
18089
|
+
return path4.join(gitRoot, WAYAI_LAYOUT.wsDir, WORKSPACE_MANIFEST_FILE);
|
|
17903
18090
|
}
|
|
17904
18091
|
function rootConfigPath(gitRoot) {
|
|
17905
|
-
return
|
|
18092
|
+
return path4.join(gitRoot, ROOT_CONFIG_FILE);
|
|
17906
18093
|
}
|
|
17907
18094
|
function loadYamlMapping(file) {
|
|
18095
|
+
for (const p of [file, path4.dirname(file)]) {
|
|
18096
|
+
if (isSymlink(p)) {
|
|
18097
|
+
return { kind: "malformed", reason: `${path4.basename(p)} is a symlink \u2014 make it a real ${p === file ? "file" : "directory"}` };
|
|
18098
|
+
}
|
|
18099
|
+
}
|
|
17908
18100
|
let raw;
|
|
17909
18101
|
try {
|
|
17910
|
-
raw =
|
|
18102
|
+
raw = fs4.readFileSync(file, "utf-8");
|
|
17911
18103
|
} catch (err) {
|
|
17912
18104
|
if (err.code === "ENOENT") return { kind: "absent" };
|
|
17913
18105
|
return { kind: "malformed", reason: err instanceof Error ? err.message : String(err) };
|
|
@@ -17932,6 +18124,7 @@ var init_workspace_manifest = __esm({
|
|
|
17932
18124
|
"src/lib/workspace-manifest.ts"() {
|
|
17933
18125
|
"use strict";
|
|
17934
18126
|
init_layout();
|
|
18127
|
+
init_fs_safety();
|
|
17935
18128
|
WORKSPACE_MANIFEST_FILE = "wayai.yaml";
|
|
17936
18129
|
WORKSPACE_MANIFEST_LABEL = `${WAYAI_LAYOUT.wsDir}/${WORKSPACE_MANIFEST_FILE}`;
|
|
17937
18130
|
ROOT_CONFIG_FILE = ".wayai.yaml";
|
|
@@ -17950,8 +18143,7 @@ __export(repo_config_exports, {
|
|
|
17950
18143
|
resolveRepoConfig: () => resolveRepoConfig,
|
|
17951
18144
|
writeRepoConfig: () => writeRepoConfig
|
|
17952
18145
|
});
|
|
17953
|
-
import * as
|
|
17954
|
-
import * as path4 from "path";
|
|
18146
|
+
import * as path5 from "path";
|
|
17955
18147
|
import * as yaml3 from "js-yaml";
|
|
17956
18148
|
function noticeOnce(key, emit) {
|
|
17957
18149
|
if (noticed.has(key)) return;
|
|
@@ -17989,7 +18181,7 @@ function legacyFieldsIn(load11) {
|
|
|
17989
18181
|
if (load11.kind !== "ok") return [];
|
|
17990
18182
|
return LEGACY_FIELDS.filter((f) => load11.doc[f] !== void 0);
|
|
17991
18183
|
}
|
|
17992
|
-
function
|
|
18184
|
+
function resolve3(gitRoot) {
|
|
17993
18185
|
const manifestFile = workspaceManifestPath(gitRoot);
|
|
17994
18186
|
const manifest = declarationFrom(loadWorkspaceManifest(gitRoot));
|
|
17995
18187
|
if (manifest.kind === "invalid") {
|
|
@@ -18098,7 +18290,7 @@ function report(r, posture) {
|
|
|
18098
18290
|
function resolveRepoConfig(root) {
|
|
18099
18291
|
const gitRoot = root ?? findGitRoot();
|
|
18100
18292
|
if (!gitRoot) return null;
|
|
18101
|
-
const r =
|
|
18293
|
+
const r = resolve3(gitRoot);
|
|
18102
18294
|
report(r, "soft");
|
|
18103
18295
|
return r.kind === "ok" ? r.resolved : null;
|
|
18104
18296
|
}
|
|
@@ -18108,7 +18300,7 @@ function readRepoConfig(root) {
|
|
|
18108
18300
|
function readRepoConfigUnlessBlocked(root) {
|
|
18109
18301
|
const gitRoot = root ?? findGitRoot();
|
|
18110
18302
|
if (!gitRoot) return null;
|
|
18111
|
-
const r =
|
|
18303
|
+
const r = resolve3(gitRoot);
|
|
18112
18304
|
switch (r.kind) {
|
|
18113
18305
|
case "ok":
|
|
18114
18306
|
report(r, "soft");
|
|
@@ -18123,7 +18315,7 @@ function readRepoConfigUnlessBlocked(root) {
|
|
|
18123
18315
|
}
|
|
18124
18316
|
function requireRepoConfig(root) {
|
|
18125
18317
|
const gitRoot = root ?? findGitRoot();
|
|
18126
|
-
const r = gitRoot ?
|
|
18318
|
+
const r = gitRoot ? resolve3(gitRoot) : { kind: "none" };
|
|
18127
18319
|
report(r, "hard");
|
|
18128
18320
|
if (r.kind === "ok") return r.resolved.config;
|
|
18129
18321
|
return process.exit(1);
|
|
@@ -18131,7 +18323,7 @@ function requireRepoConfig(root) {
|
|
|
18131
18323
|
function readRepoScopeBlocker(root) {
|
|
18132
18324
|
const gitRoot = root ?? findGitRoot();
|
|
18133
18325
|
if (!gitRoot) return null;
|
|
18134
|
-
const r =
|
|
18326
|
+
const r = resolve3(gitRoot);
|
|
18135
18327
|
if (r.kind === "conflict") {
|
|
18136
18328
|
return {
|
|
18137
18329
|
kind: "conflict",
|
|
@@ -18168,6 +18360,7 @@ function writeRepoConfig(config, root) {
|
|
|
18168
18360
|
if (!gitRoot) {
|
|
18169
18361
|
throw expected("Not inside a git repository. Run `git init` first.");
|
|
18170
18362
|
}
|
|
18363
|
+
readRealFileOrThrow(gitRoot, workspaceManifestPath(gitRoot));
|
|
18171
18364
|
const stale = declarationFrom(loadYamlMapping(rootConfigPath(gitRoot)));
|
|
18172
18365
|
if (stale.kind === "declared" && stale.config.organization_id !== config.organization_id) {
|
|
18173
18366
|
throw expected(rebindRefusal(config.organization_id, stale.config.organization_id));
|
|
@@ -18183,12 +18376,8 @@ function writeRepoConfig(config, root) {
|
|
|
18183
18376
|
if (config.organization_name?.trim()) doc.organization_name = config.organization_name.trim();
|
|
18184
18377
|
Object.assign(doc, rest);
|
|
18185
18378
|
const file = workspaceManifestPath(gitRoot);
|
|
18186
|
-
|
|
18187
|
-
|
|
18188
|
-
file,
|
|
18189
|
-
yaml3.dump(doc, { lineWidth: -1, quotingType: '"', forceQuotes: false }),
|
|
18190
|
-
"utf-8"
|
|
18191
|
-
);
|
|
18379
|
+
requireRealSubdirNoSymlink(gitRoot, path5.dirname(file), true);
|
|
18380
|
+
writeFileNoFollow(gitRoot, file, Buffer.from(yaml3.dump(doc, { lineWidth: -1, quotingType: '"', forceQuotes: false }), "utf-8"));
|
|
18192
18381
|
return file;
|
|
18193
18382
|
}
|
|
18194
18383
|
var LEGACY_FIELDS, noticed, RECONCILE_REMEDY;
|
|
@@ -18196,6 +18385,7 @@ var init_repo_config = __esm({
|
|
|
18196
18385
|
"src/lib/repo-config.ts"() {
|
|
18197
18386
|
"use strict";
|
|
18198
18387
|
init_expected();
|
|
18388
|
+
init_fs_safety();
|
|
18199
18389
|
init_workspace();
|
|
18200
18390
|
init_utils();
|
|
18201
18391
|
init_workspace_manifest();
|
|
@@ -18210,7 +18400,7 @@ var init_repo_config = __esm({
|
|
|
18210
18400
|
|
|
18211
18401
|
// src/lib/utils.ts
|
|
18212
18402
|
import * as fs5 from "fs";
|
|
18213
|
-
import * as
|
|
18403
|
+
import * as path6 from "path";
|
|
18214
18404
|
import * as readline from "readline";
|
|
18215
18405
|
function prompt(question) {
|
|
18216
18406
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -18264,7 +18454,7 @@ function readStdin() {
|
|
|
18264
18454
|
}
|
|
18265
18455
|
function resolveHubYamlPath(hubFolder) {
|
|
18266
18456
|
for (const filename of ["hub.yaml", "wayai.yaml"]) {
|
|
18267
|
-
const yamlPath =
|
|
18457
|
+
const yamlPath = path6.join(hubFolder, filename);
|
|
18268
18458
|
if (fs5.existsSync(yamlPath)) return yamlPath;
|
|
18269
18459
|
}
|
|
18270
18460
|
return null;
|
|
@@ -18730,17 +18920,17 @@ var init_registry = __esm({
|
|
|
18730
18920
|
});
|
|
18731
18921
|
|
|
18732
18922
|
// src/lib/version-cache.ts
|
|
18733
|
-
import { existsSync as existsSync3, readFileSync as
|
|
18734
|
-
import { dirname as
|
|
18923
|
+
import { existsSync as existsSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
18924
|
+
import { dirname as dirname6, join as join7 } from "path";
|
|
18735
18925
|
import { homedir as homedir2 } from "os";
|
|
18736
18926
|
function getVersionCachePath(filename = CLI_CACHE_FILE) {
|
|
18737
|
-
return
|
|
18927
|
+
return join7(homedir2(), ".wayai", filename);
|
|
18738
18928
|
}
|
|
18739
18929
|
function readVersionCache(filename = CLI_CACHE_FILE) {
|
|
18740
18930
|
try {
|
|
18741
18931
|
const path35 = getVersionCachePath(filename);
|
|
18742
18932
|
if (!existsSync3(path35)) return null;
|
|
18743
|
-
const parsed = JSON.parse(
|
|
18933
|
+
const parsed = JSON.parse(readFileSync6(path35, "utf-8"));
|
|
18744
18934
|
if (typeof parsed.lastCheck !== "number") return null;
|
|
18745
18935
|
if (parsed.latest !== null && typeof parsed.latest !== "string") return null;
|
|
18746
18936
|
return parsed;
|
|
@@ -18761,7 +18951,7 @@ function isVersionCacheStale(filename = CLI_CACHE_FILE, maxAgeMs = MAX_AGE_24H_M
|
|
|
18761
18951
|
}
|
|
18762
18952
|
function writeVersionCache(filename, cache) {
|
|
18763
18953
|
const path35 = getVersionCachePath(filename);
|
|
18764
|
-
const dir =
|
|
18954
|
+
const dir = dirname6(path35);
|
|
18765
18955
|
if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
|
|
18766
18956
|
writeFileSync2(path35, JSON.stringify(cache));
|
|
18767
18957
|
}
|
|
@@ -18780,8 +18970,8 @@ var init_version_cache = __esm({
|
|
|
18780
18970
|
});
|
|
18781
18971
|
|
|
18782
18972
|
// src/lib/skill-version.ts
|
|
18783
|
-
import { existsSync as existsSync4, readFileSync as
|
|
18784
|
-
import { join as
|
|
18973
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
|
|
18974
|
+
import { join as join8 } from "path";
|
|
18785
18975
|
import * as yaml4 from "js-yaml";
|
|
18786
18976
|
function skillInstallPaths(skillName) {
|
|
18787
18977
|
return HARNESS_SKILL_DIRS.map((dir) => `${dir}/skills/${skillName}/${SKILL_FILENAME}`);
|
|
@@ -18802,11 +18992,11 @@ function parseFrontmatterVersion(content) {
|
|
|
18802
18992
|
function findInstalledSkills(projectRoot, paths = SKILL_INSTALL_PATHS) {
|
|
18803
18993
|
const found = [];
|
|
18804
18994
|
for (const rel of paths) {
|
|
18805
|
-
const path35 =
|
|
18995
|
+
const path35 = join8(projectRoot, rel);
|
|
18806
18996
|
if (!existsSync4(path35)) continue;
|
|
18807
18997
|
let version = null;
|
|
18808
18998
|
try {
|
|
18809
|
-
version = parseFrontmatterVersion(
|
|
18999
|
+
version = parseFrontmatterVersion(readFileSync7(path35, "utf-8"));
|
|
18810
19000
|
} catch {
|
|
18811
19001
|
}
|
|
18812
19002
|
found.push({ path: path35, version });
|
|
@@ -18841,13 +19031,13 @@ __export(config_exports, {
|
|
|
18841
19031
|
writeConfig: () => writeConfig
|
|
18842
19032
|
});
|
|
18843
19033
|
import * as fs6 from "fs";
|
|
18844
|
-
import * as
|
|
19034
|
+
import * as path7 from "path";
|
|
18845
19035
|
import * as os from "os";
|
|
18846
19036
|
function configDir() {
|
|
18847
|
-
return
|
|
19037
|
+
return path7.join(os.homedir(), ".wayai");
|
|
18848
19038
|
}
|
|
18849
19039
|
function configPath() {
|
|
18850
|
-
return
|
|
19040
|
+
return path7.join(configDir(), "config.json");
|
|
18851
19041
|
}
|
|
18852
19042
|
function getConfigPath() {
|
|
18853
19043
|
return configPath();
|
|
@@ -18900,13 +19090,13 @@ var init_config = __esm({
|
|
|
18900
19090
|
|
|
18901
19091
|
// src/lib/token-store.ts
|
|
18902
19092
|
import * as fs7 from "fs";
|
|
18903
|
-
import * as
|
|
19093
|
+
import * as path8 from "path";
|
|
18904
19094
|
import * as os2 from "os";
|
|
18905
19095
|
function configDir2() {
|
|
18906
|
-
return
|
|
19096
|
+
return path8.join(os2.homedir(), ".wayai");
|
|
18907
19097
|
}
|
|
18908
19098
|
function configPath2() {
|
|
18909
|
-
return
|
|
19099
|
+
return path8.join(configDir2(), "config.json");
|
|
18910
19100
|
}
|
|
18911
19101
|
function manualCleanupCommand(account) {
|
|
18912
19102
|
if (process.platform === "darwin") {
|
|
@@ -19406,26 +19596,26 @@ __export(skill_symlink_exports, {
|
|
|
19406
19596
|
healClaudeSkillLink: () => healClaudeSkillLink,
|
|
19407
19597
|
healSkillLinkForCommand: () => healSkillLinkForCommand
|
|
19408
19598
|
});
|
|
19409
|
-
import { existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync5, rmSync, symlinkSync } from "fs";
|
|
19410
|
-
import { join as
|
|
19599
|
+
import { existsSync as existsSync7, lstatSync as lstatSync3, mkdirSync as mkdirSync5, rmSync as rmSync2, symlinkSync } from "fs";
|
|
19600
|
+
import { join as join11 } from "path";
|
|
19411
19601
|
function healClaudeSkillLink(root) {
|
|
19412
19602
|
try {
|
|
19413
|
-
const source =
|
|
19414
|
-
if (!existsSync7(
|
|
19415
|
-
const link =
|
|
19416
|
-
if (existsSync7(
|
|
19603
|
+
const source = join11(root, ".agents", "skills", SKILL_NAME);
|
|
19604
|
+
if (!existsSync7(join11(source, SKILL_FILENAME))) return false;
|
|
19605
|
+
const link = join11(root, ".claude", "skills", SKILL_NAME);
|
|
19606
|
+
if (existsSync7(join11(link, SKILL_FILENAME))) return false;
|
|
19417
19607
|
let entry = null;
|
|
19418
19608
|
try {
|
|
19419
|
-
entry =
|
|
19609
|
+
entry = lstatSync3(link);
|
|
19420
19610
|
} catch {
|
|
19421
19611
|
entry = null;
|
|
19422
19612
|
}
|
|
19423
19613
|
if (entry) {
|
|
19424
19614
|
if (!entry.isSymbolicLink()) return false;
|
|
19425
|
-
|
|
19615
|
+
rmSync2(link, { force: true });
|
|
19426
19616
|
}
|
|
19427
|
-
mkdirSync5(
|
|
19428
|
-
symlinkSync(
|
|
19617
|
+
mkdirSync5(join11(root, ".claude", "skills"), { recursive: true });
|
|
19618
|
+
symlinkSync(join11("..", "..", ".agents", "skills", SKILL_NAME), link, "dir");
|
|
19429
19619
|
return true;
|
|
19430
19620
|
} catch {
|
|
19431
19621
|
return false;
|
|
@@ -19709,7 +19899,7 @@ var init_base_id = __esm({
|
|
|
19709
19899
|
// src/lib/worktree-scope.ts
|
|
19710
19900
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
19711
19901
|
import * as fs8 from "fs";
|
|
19712
|
-
import * as
|
|
19902
|
+
import * as path9 from "path";
|
|
19713
19903
|
import * as yaml5 from "js-yaml";
|
|
19714
19904
|
function axisNoun(axis) {
|
|
19715
19905
|
return AXES[axis].noun;
|
|
@@ -19724,7 +19914,7 @@ function resolveGitDir() {
|
|
|
19724
19914
|
encoding: "utf-8",
|
|
19725
19915
|
stdio: ["pipe", "pipe", "pipe"]
|
|
19726
19916
|
}).trim();
|
|
19727
|
-
gitDir = raw ?
|
|
19917
|
+
gitDir = raw ? path9.resolve(cwd, raw) : null;
|
|
19728
19918
|
} catch {
|
|
19729
19919
|
gitDir = null;
|
|
19730
19920
|
}
|
|
@@ -19733,12 +19923,12 @@ function resolveGitDir() {
|
|
|
19733
19923
|
}
|
|
19734
19924
|
function getScopePath() {
|
|
19735
19925
|
const gitDir = resolveGitDir();
|
|
19736
|
-
return gitDir ?
|
|
19926
|
+
return gitDir ? path9.join(gitDir, SCOPE_FILE) : null;
|
|
19737
19927
|
}
|
|
19738
19928
|
function legacyPaths() {
|
|
19739
19929
|
const gitDir = resolveGitDir();
|
|
19740
19930
|
if (!gitDir) return [];
|
|
19741
|
-
return AXIS_ORDER.flatMap((axis) => AXES[axis].legacyFiles).map((f) =>
|
|
19931
|
+
return AXIS_ORDER.flatMap((axis) => AXES[axis].legacyFiles).map((f) => path9.join(gitDir, f));
|
|
19742
19932
|
}
|
|
19743
19933
|
function emptyScope() {
|
|
19744
19934
|
return { hubs: [], bases: [] };
|
|
@@ -19762,7 +19952,7 @@ function readLegacyAxis(axis) {
|
|
|
19762
19952
|
for (const filename of legacyFiles) {
|
|
19763
19953
|
let raw;
|
|
19764
19954
|
try {
|
|
19765
|
-
raw = fs8.readFileSync(
|
|
19955
|
+
raw = fs8.readFileSync(path9.join(gitDir, filename), "utf-8");
|
|
19766
19956
|
} catch (err) {
|
|
19767
19957
|
if (err.code === "ENOENT") continue;
|
|
19768
19958
|
throw err;
|
|
@@ -19982,8 +20172,13 @@ function buildSkillState() {
|
|
|
19982
20172
|
}
|
|
19983
20173
|
function buildWorkspaceState(resolved) {
|
|
19984
20174
|
if (!resolved) return { scoped: false, path: null, hub_count: 0 };
|
|
19985
|
-
|
|
19986
|
-
|
|
20175
|
+
let hubCount = 0;
|
|
20176
|
+
try {
|
|
20177
|
+
const ws = detectWorkspace();
|
|
20178
|
+
hubCount = ws ? scanWorkspaceHubs(ws.workspaceDir).length : 0;
|
|
20179
|
+
} catch {
|
|
20180
|
+
hubCount = 0;
|
|
20181
|
+
}
|
|
19987
20182
|
return { scoped: true, path: resolved.path, hub_count: hubCount };
|
|
19988
20183
|
}
|
|
19989
20184
|
async function statusCommand(args2, pkg2) {
|
|
@@ -20221,12 +20416,12 @@ __export(init_exports, {
|
|
|
20221
20416
|
parseArgs: () => parseArgs3
|
|
20222
20417
|
});
|
|
20223
20418
|
import { mkdirSync as mkdirSync6 } from "fs";
|
|
20224
|
-
import
|
|
20419
|
+
import path10 from "path";
|
|
20225
20420
|
function ensureHubsDir(gitRoot) {
|
|
20226
20421
|
const hubsDir = resolveLayout(gitRoot).hubsDir;
|
|
20227
20422
|
if (isDirectory(hubsDir)) return null;
|
|
20228
20423
|
mkdirSync6(hubsDir, { recursive: true });
|
|
20229
|
-
return `${
|
|
20424
|
+
return `${path10.relative(gitRoot, hubsDir)}/`;
|
|
20230
20425
|
}
|
|
20231
20426
|
function parseArgs3(args2) {
|
|
20232
20427
|
let orgId;
|
|
@@ -20355,118 +20550,8 @@ var init_init = __esm({
|
|
|
20355
20550
|
}
|
|
20356
20551
|
});
|
|
20357
20552
|
|
|
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
20553
|
// src/lib/resource-files.ts
|
|
20469
|
-
import * as
|
|
20554
|
+
import * as fs9 from "fs";
|
|
20470
20555
|
import * as path11 from "path";
|
|
20471
20556
|
import * as crypto3 from "crypto";
|
|
20472
20557
|
function isBinaryFile(filename) {
|
|
@@ -20513,14 +20598,16 @@ function computeHash(data) {
|
|
|
20513
20598
|
}
|
|
20514
20599
|
function scanResourceFiles(dir, prefix = "") {
|
|
20515
20600
|
const files = [];
|
|
20516
|
-
const entries =
|
|
20601
|
+
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
20517
20602
|
for (const entry of entries) {
|
|
20518
20603
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
20519
|
-
if (entry.
|
|
20604
|
+
if (entry.isSymbolicLink()) {
|
|
20605
|
+
throw symlinkRefusal(relPath, "file or folder");
|
|
20606
|
+
} else if (entry.isDirectory()) {
|
|
20520
20607
|
files.push(...scanResourceFiles(path11.join(dir, entry.name), relPath));
|
|
20521
20608
|
} else if (entry.isFile()) {
|
|
20522
20609
|
const fullPath = path11.join(dir, entry.name);
|
|
20523
|
-
const stat2 =
|
|
20610
|
+
const stat2 = fs9.statSync(fullPath);
|
|
20524
20611
|
if (stat2.size > MAX_RESOURCE_FILE_SIZE3) {
|
|
20525
20612
|
console.warn(` Warning: skipping ${relPath} (${(stat2.size / 1024 / 1024).toFixed(1)}MB exceeds 10MB limit)`);
|
|
20526
20613
|
continue;
|
|
@@ -20530,7 +20617,7 @@ function scanResourceFiles(dir, prefix = "") {
|
|
|
20530
20617
|
mime_type: guessMimeType(entry.name),
|
|
20531
20618
|
file_size: stat2.size
|
|
20532
20619
|
};
|
|
20533
|
-
const data =
|
|
20620
|
+
const data = fs9.readFileSync(fullPath);
|
|
20534
20621
|
fileEntry.hash = computeHash(data);
|
|
20535
20622
|
if (isBinaryFile(entry.name)) {
|
|
20536
20623
|
fileEntry.content_base64 = data.toString("base64");
|
|
@@ -20590,7 +20677,7 @@ function writeResourceFileTree(resDir, files, root, log) {
|
|
|
20590
20677
|
return;
|
|
20591
20678
|
}
|
|
20592
20679
|
if (files.length === 0) {
|
|
20593
|
-
if (
|
|
20680
|
+
if (fs9.existsSync(resDir)) cleanOrphanFiles(resDir, "", /* @__PURE__ */ new Set(), root, log);
|
|
20594
20681
|
return;
|
|
20595
20682
|
}
|
|
20596
20683
|
const writtenPaths = /* @__PURE__ */ new Set();
|
|
@@ -20611,18 +20698,18 @@ function writeResourceFileTree(resDir, files, root, log) {
|
|
|
20611
20698
|
writtenPaths.delete(file.path);
|
|
20612
20699
|
}
|
|
20613
20700
|
}
|
|
20614
|
-
if (
|
|
20701
|
+
if (fs9.existsSync(resDir)) cleanOrphanFiles(resDir, "", writtenPaths, root, log);
|
|
20615
20702
|
}
|
|
20616
20703
|
function cleanOrphanFiles(dir, prefix, writtenPaths, root, log) {
|
|
20617
|
-
const entries =
|
|
20704
|
+
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
20618
20705
|
for (const entry of entries) {
|
|
20619
20706
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
20620
20707
|
const fullPath = path11.join(dir, entry.name);
|
|
20621
20708
|
if (entry.isDirectory()) {
|
|
20622
20709
|
cleanOrphanFiles(fullPath, relPath, writtenPaths, root, log);
|
|
20623
|
-
if (
|
|
20710
|
+
if (fs9.readdirSync(fullPath).length === 0) fs9.rmdirSync(fullPath);
|
|
20624
20711
|
} else if (!writtenPaths.has(relPath)) {
|
|
20625
|
-
|
|
20712
|
+
fs9.unlinkSync(fullPath);
|
|
20626
20713
|
if (log && root) log.removed.push(path11.relative(root, fullPath));
|
|
20627
20714
|
}
|
|
20628
20715
|
}
|
|
@@ -20643,8 +20730,8 @@ async function downloadBinaryFiles(resDir, files, root, log) {
|
|
|
20643
20730
|
}
|
|
20644
20731
|
if (file.hash) {
|
|
20645
20732
|
try {
|
|
20646
|
-
const st =
|
|
20647
|
-
if (st.isFile() && !st.isSymbolicLink() && computeHash(
|
|
20733
|
+
const st = fs9.lstatSync(filePath);
|
|
20734
|
+
if (st.isFile() && !st.isSymbolicLink() && computeHash(fs9.readFileSync(filePath)) === file.hash) continue;
|
|
20648
20735
|
} catch {
|
|
20649
20736
|
}
|
|
20650
20737
|
}
|
|
@@ -20698,7 +20785,7 @@ var init_resource_files = __esm({
|
|
|
20698
20785
|
});
|
|
20699
20786
|
|
|
20700
20787
|
// src/lib/eval-attachments.ts
|
|
20701
|
-
import * as
|
|
20788
|
+
import * as fs10 from "fs";
|
|
20702
20789
|
import * as path12 from "path";
|
|
20703
20790
|
function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
|
|
20704
20791
|
const raw = turn.attachments;
|
|
@@ -20722,7 +20809,7 @@ function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
|
|
|
20722
20809
|
}
|
|
20723
20810
|
let stat2;
|
|
20724
20811
|
try {
|
|
20725
|
-
stat2 =
|
|
20812
|
+
stat2 = fs10.statSync(abs);
|
|
20726
20813
|
} catch {
|
|
20727
20814
|
}
|
|
20728
20815
|
if (!stat2?.isFile()) {
|
|
@@ -20736,7 +20823,7 @@ function resolveTurnAttachments(hubFolder, turn, label, bytesByHash) {
|
|
|
20736
20823
|
`${label}: attachment "${entry}" is ${(stat2.size / 1024 / 1024).toFixed(1)}MB, over the 10MB limit.`
|
|
20737
20824
|
);
|
|
20738
20825
|
}
|
|
20739
|
-
const data =
|
|
20826
|
+
const data = fs10.readFileSync(abs);
|
|
20740
20827
|
const hash = computeHash(data);
|
|
20741
20828
|
const fileName = path12.basename(abs);
|
|
20742
20829
|
const mimeType = guessMimeType(fileName) ?? "application/octet-stream";
|
|
@@ -20844,16 +20931,16 @@ async function downloadEvalAttachments(hubFolder, downloads) {
|
|
|
20844
20931
|
console.warn(` Warning: ${ATTACHMENTS_DIR}/ is not reachable inside the hub folder without a symlink; skipping attachment sync.`);
|
|
20845
20932
|
return result;
|
|
20846
20933
|
}
|
|
20847
|
-
if (!
|
|
20934
|
+
if (!fs10.existsSync(attachDir)) return result;
|
|
20848
20935
|
for (const dl of downloads) {
|
|
20849
20936
|
const abs = path12.resolve(hubFolder, dl.relPath);
|
|
20850
20937
|
if (abs !== attachDir && !abs.startsWith(attachDir + path12.sep)) continue;
|
|
20851
20938
|
let existing;
|
|
20852
20939
|
try {
|
|
20853
|
-
existing =
|
|
20940
|
+
existing = fs10.lstatSync(abs);
|
|
20854
20941
|
} catch {
|
|
20855
20942
|
}
|
|
20856
|
-
if (existing?.isFile() && !existing.isSymbolicLink() && computeHash(
|
|
20943
|
+
if (existing?.isFile() && !existing.isSymbolicLink() && computeHash(fs10.readFileSync(abs)) === dl.hash) {
|
|
20857
20944
|
continue;
|
|
20858
20945
|
}
|
|
20859
20946
|
try {
|
|
@@ -20871,11 +20958,11 @@ async function downloadEvalAttachments(hubFolder, downloads) {
|
|
|
20871
20958
|
}
|
|
20872
20959
|
}
|
|
20873
20960
|
const keep = new Set(downloads.map((d) => path12.resolve(hubFolder, d.relPath)));
|
|
20874
|
-
for (const name of
|
|
20961
|
+
for (const name of fs10.readdirSync(attachDir)) {
|
|
20875
20962
|
const abs = path12.join(attachDir, name);
|
|
20876
|
-
const st =
|
|
20963
|
+
const st = fs10.lstatSync(abs);
|
|
20877
20964
|
if ((st.isFile() || st.isSymbolicLink()) && !keep.has(abs)) {
|
|
20878
|
-
|
|
20965
|
+
fs10.rmSync(abs);
|
|
20879
20966
|
result.removed.push(path12.relative(hubFolder, abs));
|
|
20880
20967
|
}
|
|
20881
20968
|
}
|
|
@@ -20893,15 +20980,28 @@ var init_eval_attachments = __esm({
|
|
|
20893
20980
|
});
|
|
20894
20981
|
|
|
20895
20982
|
// src/lib/parser.ts
|
|
20896
|
-
import * as
|
|
20983
|
+
import * as fs11 from "fs";
|
|
20897
20984
|
import * as path13 from "path";
|
|
20898
20985
|
import * as yaml6 from "js-yaml";
|
|
20986
|
+
function refuseConsumedLink(hubFolder, dir, entry) {
|
|
20987
|
+
if (!entry.isSymbolicLink()) return;
|
|
20988
|
+
const abs = path13.join(dir, entry.name);
|
|
20989
|
+
let toDir = false;
|
|
20990
|
+
try {
|
|
20991
|
+
toDir = fs11.statSync(abs).isDirectory();
|
|
20992
|
+
} catch {
|
|
20993
|
+
}
|
|
20994
|
+
if (toDir || entry.name.endsWith(".yaml")) {
|
|
20995
|
+
throw symlinkRefusal(path13.relative(hubFolder, abs), "file or folder");
|
|
20996
|
+
}
|
|
20997
|
+
}
|
|
20899
20998
|
function parseHubFolder(hubFolder, opts) {
|
|
20999
|
+
requireRealHubFolder(hubFolder, false);
|
|
20900
21000
|
const yamlPath = resolveHubYamlPath(hubFolder);
|
|
20901
21001
|
if (!yamlPath) {
|
|
20902
21002
|
throw expected(`hub.yaml not found in ${hubFolder}`);
|
|
20903
21003
|
}
|
|
20904
|
-
const yamlContent =
|
|
21004
|
+
const yamlContent = readRealFileOrThrow(hubFolder, yamlPath) ?? "";
|
|
20905
21005
|
let config;
|
|
20906
21006
|
try {
|
|
20907
21007
|
config = yaml6.load(yamlContent);
|
|
@@ -20929,8 +21029,14 @@ function parseHubFolder(hubFolder, opts) {
|
|
|
20929
21029
|
if (typeof resolved.instructions === "string" && resolved.instructions.endsWith(".md")) {
|
|
20930
21030
|
const instrValue = resolved.instructions;
|
|
20931
21031
|
const instructionsPath = instrValue.startsWith("agents/") ? path13.join(hubFolder, instrValue) : path13.join(hubFolder, "agents", instrValue);
|
|
20932
|
-
if (
|
|
20933
|
-
|
|
21032
|
+
if (!isUnder(path13.join(hubFolder, "agents"), instructionsPath)) {
|
|
21033
|
+
throw workspaceRefusal(
|
|
21034
|
+
`Agent instructions path "${instrValue}" (agent "${agent.name}") must stay inside agents/.`
|
|
21035
|
+
);
|
|
21036
|
+
}
|
|
21037
|
+
const instructions = readRealFileOrThrow(hubFolder, instructionsPath);
|
|
21038
|
+
if (instructions !== null) {
|
|
21039
|
+
resolved.instructions = instructions;
|
|
20934
21040
|
} else {
|
|
20935
21041
|
throw expected(
|
|
20936
21042
|
`Agent instructions file not found: ${instructionsPath} (referenced by agent "${agent.name}")`
|
|
@@ -20938,9 +21044,8 @@ function parseHubFolder(hubFolder, opts) {
|
|
|
20938
21044
|
}
|
|
20939
21045
|
} else if (resolved.instructions === void 0 && typeof agent.name === "string") {
|
|
20940
21046
|
const conventionPath = path13.join(hubFolder, "agents", `${slugify(agent.name)}.md`);
|
|
20941
|
-
|
|
20942
|
-
|
|
20943
|
-
}
|
|
21047
|
+
const instructions = readRealFileOrThrow(hubFolder, conventionPath);
|
|
21048
|
+
if (instructions !== null) resolved.instructions = instructions;
|
|
20944
21049
|
}
|
|
20945
21050
|
return resolved;
|
|
20946
21051
|
});
|
|
@@ -20994,18 +21099,20 @@ function parseHubFolder(hubFolder, opts) {
|
|
|
20994
21099
|
}
|
|
20995
21100
|
function scanEvalYamlFiles(hubFolder, bytesByHash) {
|
|
20996
21101
|
const evalsDir = path13.join(hubFolder, "evals");
|
|
20997
|
-
if (!
|
|
21102
|
+
if (!fs11.existsSync(evalsDir)) return [];
|
|
20998
21103
|
const evals = [];
|
|
20999
21104
|
const seen = /* @__PURE__ */ new Set();
|
|
21000
|
-
const topEntries =
|
|
21105
|
+
const topEntries = fs11.readdirSync(evalsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
21001
21106
|
for (const entry of topEntries) {
|
|
21107
|
+
refuseConsumedLink(hubFolder, evalsDir, entry);
|
|
21002
21108
|
if (entry.isFile() && entry.name.endsWith(".yaml")) {
|
|
21003
21109
|
collectEval(evals, seen, path13.join(evalsDir, entry.name), `evals/${entry.name}`, null, hubFolder, bytesByHash);
|
|
21004
21110
|
} else if (entry.isDirectory()) {
|
|
21005
21111
|
const setName = entry.name;
|
|
21006
21112
|
const setDir = path13.join(evalsDir, setName);
|
|
21007
|
-
const setEntries =
|
|
21113
|
+
const setEntries = fs11.readdirSync(setDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
21008
21114
|
for (const sub of setEntries) {
|
|
21115
|
+
refuseConsumedLink(hubFolder, setDir, sub);
|
|
21009
21116
|
if (sub.isDirectory()) {
|
|
21010
21117
|
throw expected(
|
|
21011
21118
|
`Nested scenario sets are not supported: ${path13.relative(hubFolder, path13.join(setDir, sub.name))}. Move scenarios up to evals/${setName}/.`
|
|
@@ -21033,7 +21140,7 @@ function collectEval(evals, seen, filePath, relPath, setName, hubFolder, bytesBy
|
|
|
21033
21140
|
evals.push(evalEntry);
|
|
21034
21141
|
}
|
|
21035
21142
|
function parseEvalYaml(filePath, relPath, setName, hubFolder, bytesByHash) {
|
|
21036
|
-
const content =
|
|
21143
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
21037
21144
|
let raw;
|
|
21038
21145
|
try {
|
|
21039
21146
|
raw = yaml6.load(content);
|
|
@@ -21136,11 +21243,12 @@ function parseFixtureField(raw, label, key) {
|
|
|
21136
21243
|
}
|
|
21137
21244
|
function scanJourneyYamlFiles(hubFolder, bytesByHash) {
|
|
21138
21245
|
const journeysDir = path13.join(hubFolder, "journeys");
|
|
21139
|
-
if (!
|
|
21246
|
+
if (!fs11.existsSync(journeysDir)) return [];
|
|
21140
21247
|
const journeys = [];
|
|
21141
21248
|
const seen = /* @__PURE__ */ new Set();
|
|
21142
|
-
const entries =
|
|
21249
|
+
const entries = fs11.readdirSync(journeysDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
21143
21250
|
for (const entry of entries) {
|
|
21251
|
+
refuseConsumedLink(hubFolder, journeysDir, entry);
|
|
21144
21252
|
if (entry.isDirectory()) {
|
|
21145
21253
|
throw expected(
|
|
21146
21254
|
`Subfolders are not supported under journeys/: ${path13.relative(hubFolder, path13.join(journeysDir, entry.name))}. A journey owns its own managed scenario set \u2014 put each journey in a single journeys/<slug>.yaml file.`
|
|
@@ -21160,7 +21268,7 @@ function scanJourneyYamlFiles(hubFolder, bytesByHash) {
|
|
|
21160
21268
|
return journeys;
|
|
21161
21269
|
}
|
|
21162
21270
|
function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
|
|
21163
|
-
const content =
|
|
21271
|
+
const content = fs11.readFileSync(filePath, "utf-8");
|
|
21164
21272
|
let raw;
|
|
21165
21273
|
try {
|
|
21166
21274
|
raw = yaml6.load(content);
|
|
@@ -21216,13 +21324,13 @@ function parseJourneyYaml(filePath, relPath, hubFolder, bytesByHash) {
|
|
|
21216
21324
|
}
|
|
21217
21325
|
function scanAgentYamlFiles(hubFolder) {
|
|
21218
21326
|
const agentsDir = path13.join(hubFolder, "agents");
|
|
21219
|
-
if (!
|
|
21220
|
-
const yamlFiles =
|
|
21327
|
+
if (!fs11.existsSync(agentsDir)) return [];
|
|
21328
|
+
const yamlFiles = fs11.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml")).sort();
|
|
21221
21329
|
if (yamlFiles.length === 0) return [];
|
|
21222
21330
|
const agents = [];
|
|
21223
21331
|
for (const file of yamlFiles) {
|
|
21224
21332
|
const filePath = path13.join(agentsDir, file);
|
|
21225
|
-
const content =
|
|
21333
|
+
const content = readRealFileOrThrow(hubFolder, filePath) ?? "";
|
|
21226
21334
|
let agent;
|
|
21227
21335
|
try {
|
|
21228
21336
|
agent = yaml6.load(content);
|
|
@@ -21257,7 +21365,8 @@ function parseResources(hubFolder, configResources) {
|
|
|
21257
21365
|
if (res.skill_name) resource.skill_name = res.skill_name;
|
|
21258
21366
|
const resSlug = slugify(resource.name);
|
|
21259
21367
|
const resDir = path13.join(resourcesDir, resSlug);
|
|
21260
|
-
|
|
21368
|
+
requireRealSubdirNoSymlink(hubFolder, resDir, false);
|
|
21369
|
+
if (fs11.existsSync(resDir)) {
|
|
21261
21370
|
const files = scanResourceFiles(resDir, "");
|
|
21262
21371
|
if (files.length > 0) {
|
|
21263
21372
|
resource.files = files;
|
|
@@ -21274,6 +21383,7 @@ var init_parser = __esm({
|
|
|
21274
21383
|
init_resource_files();
|
|
21275
21384
|
init_eval_attachments();
|
|
21276
21385
|
init_expected();
|
|
21386
|
+
init_fs_safety();
|
|
21277
21387
|
}
|
|
21278
21388
|
});
|
|
21279
21389
|
|
|
@@ -21331,7 +21441,7 @@ var init_workspace_files = __esm({
|
|
|
21331
21441
|
});
|
|
21332
21442
|
|
|
21333
21443
|
// src/lib/yaml-writer.ts
|
|
21334
|
-
import * as
|
|
21444
|
+
import * as fs12 from "fs";
|
|
21335
21445
|
import * as path15 from "path";
|
|
21336
21446
|
import * as yaml7 from "js-yaml";
|
|
21337
21447
|
function writeFileIfChanged(hubFolder, absPath, content, log) {
|
|
@@ -21382,11 +21492,11 @@ function buildEvalYamlObject(evalEntry, slug) {
|
|
|
21382
21492
|
function writeHubFolder(hubFolder, payload, options = {}) {
|
|
21383
21493
|
const log = { changed: [], removed: [] };
|
|
21384
21494
|
const agentsDir = path15.join(hubFolder, "agents");
|
|
21385
|
-
if (!
|
|
21386
|
-
|
|
21495
|
+
if (!fs12.existsSync(hubFolder)) {
|
|
21496
|
+
fs12.mkdirSync(hubFolder, { recursive: true });
|
|
21387
21497
|
}
|
|
21388
|
-
if (!
|
|
21389
|
-
|
|
21498
|
+
if (!fs12.existsSync(agentsDir)) {
|
|
21499
|
+
fs12.mkdirSync(agentsDir, { recursive: true });
|
|
21390
21500
|
}
|
|
21391
21501
|
const yamlPayload = buildYamlPayload(payload);
|
|
21392
21502
|
const agentFiles = extractAgentFiles(payload);
|
|
@@ -21401,8 +21511,8 @@ function writeHubFolder(hubFolder, payload, options = {}) {
|
|
|
21401
21511
|
if (seeded) log.changed.push(seeded);
|
|
21402
21512
|
}
|
|
21403
21513
|
const oldYamlPath = path15.join(hubFolder, "wayai.yaml");
|
|
21404
|
-
if (
|
|
21405
|
-
|
|
21514
|
+
if (fs12.existsSync(oldYamlPath)) {
|
|
21515
|
+
fs12.unlinkSync(oldYamlPath);
|
|
21406
21516
|
log.removed.push(path15.relative(hubFolder, oldYamlPath));
|
|
21407
21517
|
}
|
|
21408
21518
|
const yamlSlugs = writeAgentYamlFiles(hubFolder, agentsDir, payload.agents || [], log);
|
|
@@ -21411,20 +21521,20 @@ function writeHubFolder(hubFolder, payload, options = {}) {
|
|
|
21411
21521
|
mdSlugs.add(slug);
|
|
21412
21522
|
writeFileIfChanged(hubFolder, path15.join(agentsDir, `${slug}.md`), content, log);
|
|
21413
21523
|
}
|
|
21414
|
-
const existingFiles =
|
|
21524
|
+
const existingFiles = fs12.readdirSync(agentsDir);
|
|
21415
21525
|
for (const file of existingFiles) {
|
|
21416
21526
|
if (file.endsWith(".yaml")) {
|
|
21417
21527
|
const slug = file.slice(0, -5);
|
|
21418
21528
|
if (!yamlSlugs.has(slug)) {
|
|
21419
21529
|
const orphan = path15.join(agentsDir, file);
|
|
21420
|
-
|
|
21530
|
+
fs12.unlinkSync(orphan);
|
|
21421
21531
|
log.removed.push(path15.relative(hubFolder, orphan));
|
|
21422
21532
|
}
|
|
21423
21533
|
} else if (file.endsWith(".md")) {
|
|
21424
21534
|
const slug = file.slice(0, -3);
|
|
21425
21535
|
if (!mdSlugs.has(slug)) {
|
|
21426
21536
|
const orphan = path15.join(agentsDir, file);
|
|
21427
|
-
|
|
21537
|
+
fs12.unlinkSync(orphan);
|
|
21428
21538
|
log.removed.push(path15.relative(hubFolder, orphan));
|
|
21429
21539
|
}
|
|
21430
21540
|
}
|
|
@@ -21435,12 +21545,13 @@ function writeHubFolder(hubFolder, payload, options = {}) {
|
|
|
21435
21545
|
return log;
|
|
21436
21546
|
}
|
|
21437
21547
|
function setPreviewLabelInHubYaml(hubFolder, label) {
|
|
21548
|
+
requireRealHubFolder(hubFolder, false);
|
|
21438
21549
|
const yamlPath = resolveHubYamlPath(hubFolder);
|
|
21439
21550
|
if (!yamlPath) return;
|
|
21440
|
-
const obj = yaml7.load(
|
|
21551
|
+
const obj = yaml7.load(readRealFileOrThrow(hubFolder, yamlPath) ?? "") ?? {};
|
|
21441
21552
|
if (label) obj.preview_label = label;
|
|
21442
21553
|
else delete obj.preview_label;
|
|
21443
|
-
|
|
21554
|
+
writeFileNoFollow(hubFolder, yamlPath, Buffer.from(yaml7.dump(obj, YAML_DUMP_OPTIONS), "utf-8"));
|
|
21444
21555
|
}
|
|
21445
21556
|
function buildYamlPayload(payload) {
|
|
21446
21557
|
const result = {
|
|
@@ -21505,17 +21616,17 @@ function extractAgentFiles(payload) {
|
|
|
21505
21616
|
function writeEvalYamlFiles(hubFolder, evals, log) {
|
|
21506
21617
|
const evalsDir = path15.join(hubFolder, "evals");
|
|
21507
21618
|
if (evals.length === 0) {
|
|
21508
|
-
if (
|
|
21619
|
+
if (fs12.existsSync(evalsDir)) {
|
|
21509
21620
|
cleanEvalOrphans(hubFolder, evalsDir, /* @__PURE__ */ new Set(), log);
|
|
21510
21621
|
try {
|
|
21511
|
-
if (
|
|
21622
|
+
if (fs12.readdirSync(evalsDir).length === 0) fs12.rmdirSync(evalsDir);
|
|
21512
21623
|
} catch {
|
|
21513
21624
|
}
|
|
21514
21625
|
}
|
|
21515
21626
|
return;
|
|
21516
21627
|
}
|
|
21517
|
-
if (!
|
|
21518
|
-
|
|
21628
|
+
if (!fs12.existsSync(evalsDir)) {
|
|
21629
|
+
fs12.mkdirSync(evalsDir, { recursive: true });
|
|
21519
21630
|
}
|
|
21520
21631
|
const writtenRelPaths = /* @__PURE__ */ new Set();
|
|
21521
21632
|
for (const evalEntry of evals) {
|
|
@@ -21527,12 +21638,6 @@ function writeEvalYamlFiles(hubFolder, evals, log) {
|
|
|
21527
21638
|
console.warn(` Warning: skipping eval "${evalEntry.name}" (scenario set "${setName}" escapes evals/ \u2014 possible bad backend data)`);
|
|
21528
21639
|
continue;
|
|
21529
21640
|
}
|
|
21530
|
-
if (setName) {
|
|
21531
|
-
const setDir = path15.join(evalsDir, setName);
|
|
21532
|
-
if (!fs13.existsSync(setDir)) {
|
|
21533
|
-
fs13.mkdirSync(setDir, { recursive: true });
|
|
21534
|
-
}
|
|
21535
|
-
}
|
|
21536
21641
|
const yamlContent = yaml7.dump(buildEvalYamlObject(evalEntry, slug), YAML_DUMP_OPTIONS);
|
|
21537
21642
|
writeFileIfChanged(hubFolder, targetPath, yamlContent, log);
|
|
21538
21643
|
writtenRelPaths.add(relPath);
|
|
@@ -21540,31 +21645,31 @@ function writeEvalYamlFiles(hubFolder, evals, log) {
|
|
|
21540
21645
|
cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log);
|
|
21541
21646
|
}
|
|
21542
21647
|
function cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log) {
|
|
21543
|
-
const entries =
|
|
21648
|
+
const entries = fs12.readdirSync(evalsDir, { withFileTypes: true });
|
|
21544
21649
|
for (const entry of entries) {
|
|
21545
21650
|
const fullPath = path15.join(evalsDir, entry.name);
|
|
21546
21651
|
if (entry.isFile()) {
|
|
21547
21652
|
if (entry.name.endsWith(".yaml") && !writtenRelPaths.has(entry.name)) {
|
|
21548
|
-
|
|
21653
|
+
fs12.unlinkSync(fullPath);
|
|
21549
21654
|
log.removed.push(path15.relative(hubFolder, fullPath));
|
|
21550
21655
|
}
|
|
21551
21656
|
continue;
|
|
21552
21657
|
}
|
|
21553
21658
|
if (entry.isDirectory()) {
|
|
21554
21659
|
const setName = entry.name;
|
|
21555
|
-
const subEntries =
|
|
21660
|
+
const subEntries = fs12.readdirSync(fullPath, { withFileTypes: true });
|
|
21556
21661
|
for (const sub of subEntries) {
|
|
21557
21662
|
if (sub.isFile() && sub.name.endsWith(".yaml")) {
|
|
21558
21663
|
const relPath = `${setName}/${sub.name}`;
|
|
21559
21664
|
if (!writtenRelPaths.has(relPath)) {
|
|
21560
21665
|
const orphan = path15.join(fullPath, sub.name);
|
|
21561
|
-
|
|
21666
|
+
fs12.unlinkSync(orphan);
|
|
21562
21667
|
log.removed.push(path15.relative(hubFolder, orphan));
|
|
21563
21668
|
}
|
|
21564
21669
|
}
|
|
21565
21670
|
}
|
|
21566
21671
|
try {
|
|
21567
|
-
if (
|
|
21672
|
+
if (fs12.readdirSync(fullPath).length === 0) fs12.rmdirSync(fullPath);
|
|
21568
21673
|
} catch {
|
|
21569
21674
|
}
|
|
21570
21675
|
}
|
|
@@ -21603,17 +21708,17 @@ function buildJourneyYamlObject(journeyEntry, slug) {
|
|
|
21603
21708
|
function writeJourneyYamlFiles(hubFolder, journeys, log) {
|
|
21604
21709
|
const journeysDir = path15.join(hubFolder, "journeys");
|
|
21605
21710
|
if (journeys.length === 0) {
|
|
21606
|
-
if (
|
|
21711
|
+
if (fs12.existsSync(journeysDir)) {
|
|
21607
21712
|
cleanJourneyOrphans(hubFolder, journeysDir, /* @__PURE__ */ new Set(), log);
|
|
21608
21713
|
try {
|
|
21609
|
-
if (
|
|
21714
|
+
if (fs12.readdirSync(journeysDir).length === 0) fs12.rmdirSync(journeysDir);
|
|
21610
21715
|
} catch {
|
|
21611
21716
|
}
|
|
21612
21717
|
}
|
|
21613
21718
|
return;
|
|
21614
21719
|
}
|
|
21615
|
-
if (!
|
|
21616
|
-
|
|
21720
|
+
if (!fs12.existsSync(journeysDir)) {
|
|
21721
|
+
fs12.mkdirSync(journeysDir, { recursive: true });
|
|
21617
21722
|
}
|
|
21618
21723
|
const writtenFiles = /* @__PURE__ */ new Set();
|
|
21619
21724
|
const usedSlugs = /* @__PURE__ */ new Set();
|
|
@@ -21627,11 +21732,11 @@ function writeJourneyYamlFiles(hubFolder, journeys, log) {
|
|
|
21627
21732
|
cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log);
|
|
21628
21733
|
}
|
|
21629
21734
|
function cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log) {
|
|
21630
|
-
const entries =
|
|
21735
|
+
const entries = fs12.readdirSync(journeysDir, { withFileTypes: true });
|
|
21631
21736
|
for (const entry of entries) {
|
|
21632
21737
|
if (entry.isFile() && entry.name.endsWith(".yaml") && !writtenFiles.has(entry.name)) {
|
|
21633
21738
|
const orphan = path15.join(journeysDir, entry.name);
|
|
21634
|
-
|
|
21739
|
+
fs12.unlinkSync(orphan);
|
|
21635
21740
|
log.removed.push(path15.relative(hubFolder, orphan));
|
|
21636
21741
|
}
|
|
21637
21742
|
}
|
|
@@ -21645,12 +21750,12 @@ function writeResourceFiles(hubFolder, resources, log) {
|
|
|
21645
21750
|
const resDir = path15.join(resourcesDir, resSlug);
|
|
21646
21751
|
writeResourceFileTree(resDir, resource.files || [], hubFolder, log);
|
|
21647
21752
|
}
|
|
21648
|
-
if (
|
|
21649
|
-
const existingDirs =
|
|
21753
|
+
if (fs12.existsSync(resourcesDir)) {
|
|
21754
|
+
const existingDirs = fs12.readdirSync(resourcesDir, { withFileTypes: true });
|
|
21650
21755
|
for (const entry of existingDirs) {
|
|
21651
21756
|
if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
|
|
21652
21757
|
const orphanDir = path15.join(resourcesDir, entry.name);
|
|
21653
|
-
|
|
21758
|
+
fs12.rmSync(orphanDir, { recursive: true, force: true });
|
|
21654
21759
|
log.removed.push(`${path15.relative(hubFolder, orphanDir)}/`);
|
|
21655
21760
|
}
|
|
21656
21761
|
}
|
|
@@ -21687,6 +21792,7 @@ async function materializeHubFolder(hubFolder, payload, options = {}) {
|
|
|
21687
21792
|
);
|
|
21688
21793
|
}
|
|
21689
21794
|
materialized.add(payload);
|
|
21795
|
+
requireRealHubFolder(hubFolder, true);
|
|
21690
21796
|
const attachmentDownloads = rewriteEvalAttachmentsToLocalPaths(payload);
|
|
21691
21797
|
const writeLog = writeHubFolder(hubFolder, payload, options);
|
|
21692
21798
|
const resourceDownloads = await downloadBinaryResourceFiles(hubFolder, payload);
|
|
@@ -21718,6 +21824,7 @@ var init_hub_materializer = __esm({
|
|
|
21718
21824
|
init_yaml_writer();
|
|
21719
21825
|
init_eval_attachments();
|
|
21720
21826
|
init_resource_files();
|
|
21827
|
+
init_fs_safety();
|
|
21721
21828
|
init_utils();
|
|
21722
21829
|
materialized = /* @__PURE__ */ new WeakSet();
|
|
21723
21830
|
}
|
|
@@ -21739,7 +21846,7 @@ var init_terminal_output = __esm({
|
|
|
21739
21846
|
});
|
|
21740
21847
|
|
|
21741
21848
|
// src/lib/base-workspace.ts
|
|
21742
|
-
import * as
|
|
21849
|
+
import * as fs13 from "fs";
|
|
21743
21850
|
import * as path17 from "path";
|
|
21744
21851
|
import * as yaml8 from "js-yaml";
|
|
21745
21852
|
function readBaseMeta(folder) {
|
|
@@ -21757,7 +21864,7 @@ function readBaseMeta(folder) {
|
|
|
21757
21864
|
function listBaseFolders(basesDir) {
|
|
21758
21865
|
let entries;
|
|
21759
21866
|
try {
|
|
21760
|
-
entries =
|
|
21867
|
+
entries = fs13.readdirSync(basesDir).filter((entry) => !entry.startsWith("."));
|
|
21761
21868
|
} catch {
|
|
21762
21869
|
return [];
|
|
21763
21870
|
}
|
|
@@ -21776,10 +21883,6 @@ function isProductionFolder(meta) {
|
|
|
21776
21883
|
function filterEditableBases(bases) {
|
|
21777
21884
|
return bases.filter((b) => !isProductionFolder(b.meta));
|
|
21778
21885
|
}
|
|
21779
|
-
function isUnder(parent, child) {
|
|
21780
|
-
const rel = path17.relative(parent, child);
|
|
21781
|
-
return rel === "" || !rel.startsWith("..") && !path17.isAbsolute(rel);
|
|
21782
|
-
}
|
|
21783
21886
|
function findEnclosingBaseFolder(basesDir, cwd) {
|
|
21784
21887
|
let dir = path17.resolve(cwd);
|
|
21785
21888
|
const stop = path17.resolve(basesDir);
|
|
@@ -21844,7 +21947,7 @@ function resolveBaseSelectorToId(gitRoot, selector) {
|
|
|
21844
21947
|
}
|
|
21845
21948
|
function hasBaseMetaFile(folder) {
|
|
21846
21949
|
try {
|
|
21847
|
-
return
|
|
21950
|
+
return fs13.lstatSync(path17.join(folder, BASE_META_FILE)).isFile();
|
|
21848
21951
|
} catch {
|
|
21849
21952
|
return false;
|
|
21850
21953
|
}
|
|
@@ -21857,6 +21960,7 @@ var init_base_workspace = __esm({
|
|
|
21857
21960
|
init_expected();
|
|
21858
21961
|
init_base_id();
|
|
21859
21962
|
init_fs_safety();
|
|
21963
|
+
init_fs_safety();
|
|
21860
21964
|
BASE_META_FILE = "base.yaml";
|
|
21861
21965
|
}
|
|
21862
21966
|
});
|
|
@@ -22157,7 +22261,7 @@ var init_client = __esm({
|
|
|
22157
22261
|
});
|
|
22158
22262
|
|
|
22159
22263
|
// src/data/helpers.ts
|
|
22160
|
-
import { readFileSync as
|
|
22264
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
22161
22265
|
function pathSegment(id, label = "id") {
|
|
22162
22266
|
if (!isPathSafeId(id)) {
|
|
22163
22267
|
throw expected(`Invalid ${label}: ${JSON.stringify(id)}. An id may use ${PATH_SAFE_ID_RULE}.`);
|
|
@@ -22185,7 +22289,7 @@ function parseData(data, flag) {
|
|
|
22185
22289
|
let text = data;
|
|
22186
22290
|
if (source !== void 0) {
|
|
22187
22291
|
try {
|
|
22188
|
-
text =
|
|
22292
|
+
text = readFileSync14(source, "utf-8");
|
|
22189
22293
|
} catch (e) {
|
|
22190
22294
|
throw expected(`${prefix}${source}: ${e instanceof Error ? e.message : "could not be read"}`);
|
|
22191
22295
|
}
|
|
@@ -22310,7 +22414,7 @@ var init_types2 = __esm({
|
|
|
22310
22414
|
});
|
|
22311
22415
|
|
|
22312
22416
|
// src/data/config-as-code/config-writer.ts
|
|
22313
|
-
import * as
|
|
22417
|
+
import * as fs14 from "fs";
|
|
22314
22418
|
import * as path19 from "path";
|
|
22315
22419
|
import * as yaml9 from "js-yaml";
|
|
22316
22420
|
function dump5(value) {
|
|
@@ -22345,14 +22449,14 @@ function pruneOrphans(folder, dir, keep, log) {
|
|
|
22345
22449
|
if (!ensureRealSubdirNoSymlink(folder, dir, false)) return;
|
|
22346
22450
|
let entries;
|
|
22347
22451
|
try {
|
|
22348
|
-
entries =
|
|
22452
|
+
entries = fs14.readdirSync(dir);
|
|
22349
22453
|
} catch {
|
|
22350
22454
|
return;
|
|
22351
22455
|
}
|
|
22352
22456
|
for (const file of entries) {
|
|
22353
22457
|
if (!file.endsWith(".yaml") || keep.has(file)) continue;
|
|
22354
22458
|
const abs = path19.join(dir, file);
|
|
22355
|
-
|
|
22459
|
+
fs14.rmSync(abs);
|
|
22356
22460
|
log.removed.push(path19.relative(folder, abs));
|
|
22357
22461
|
}
|
|
22358
22462
|
}
|
|
@@ -22366,7 +22470,7 @@ function metaFileObject(meta) {
|
|
|
22366
22470
|
function writeBaseFolder(folder, meta, config) {
|
|
22367
22471
|
const delta = { changed: [], removed: [] };
|
|
22368
22472
|
const parent = path19.dirname(folder);
|
|
22369
|
-
|
|
22473
|
+
fs14.mkdirSync(parent, { recursive: true });
|
|
22370
22474
|
if (!ensureRealSubdirNoSymlink(parent, folder, true)) {
|
|
22371
22475
|
throw expected(
|
|
22372
22476
|
`Refusing to write ${folder}: the path crosses a symlink. Remove it and pull again.`
|
|
@@ -22393,7 +22497,7 @@ function writeBaseFolder(folder, meta, config) {
|
|
|
22393
22497
|
for (const deprecated of DEPRECATED_ENTITY_DIRS) {
|
|
22394
22498
|
const dir = path19.join(folder, deprecated);
|
|
22395
22499
|
if (ensureRealSubdirNoSymlink(folder, dir, false)) {
|
|
22396
|
-
|
|
22500
|
+
fs14.rmSync(dir, { recursive: true, force: true });
|
|
22397
22501
|
}
|
|
22398
22502
|
}
|
|
22399
22503
|
return delta;
|
|
@@ -22545,7 +22649,7 @@ var init_api = __esm({
|
|
|
22545
22649
|
});
|
|
22546
22650
|
|
|
22547
22651
|
// src/data/config-as-code/config-parser.ts
|
|
22548
|
-
import * as
|
|
22652
|
+
import * as fs15 from "fs";
|
|
22549
22653
|
import * as path20 from "path";
|
|
22550
22654
|
import * as yaml10 from "js-yaml";
|
|
22551
22655
|
function readEntityDir(folder, dir) {
|
|
@@ -22554,7 +22658,7 @@ function readEntityDir(folder, dir) {
|
|
|
22554
22658
|
}
|
|
22555
22659
|
if (!isDirectory(dir)) return [];
|
|
22556
22660
|
const out = [];
|
|
22557
|
-
for (const file of
|
|
22661
|
+
for (const file of fs15.readdirSync(dir).sort()) {
|
|
22558
22662
|
if (!file.endsWith(".yaml")) continue;
|
|
22559
22663
|
const abs = path20.join(dir, file);
|
|
22560
22664
|
const bytes = readFileNoFollow(folder, abs);
|
|
@@ -22941,7 +23045,7 @@ __export(push_exports, {
|
|
|
22941
23045
|
shouldWarnIgnoredPreviewLabel: () => shouldWarnIgnoredPreviewLabel,
|
|
22942
23046
|
syncAfterPush: () => syncAfterPush
|
|
22943
23047
|
});
|
|
22944
|
-
import * as
|
|
23048
|
+
import * as fs16 from "fs";
|
|
22945
23049
|
import * as path22 from "path";
|
|
22946
23050
|
import * as yaml11 from "js-yaml";
|
|
22947
23051
|
function parseArgs5(args2) {
|
|
@@ -23050,13 +23154,14 @@ function printLocalFileChanges(delta) {
|
|
|
23050
23154
|
emit(delta.changed, "~");
|
|
23051
23155
|
}
|
|
23052
23156
|
async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, remoteConfig) {
|
|
23157
|
+
requireRealHubFolder(hubFolder, false);
|
|
23053
23158
|
const agentsDir = path22.join(hubFolder, "agents");
|
|
23054
23159
|
let agentsWithIds = [];
|
|
23055
|
-
if (
|
|
23056
|
-
const yamlFiles =
|
|
23160
|
+
if (fs16.existsSync(agentsDir)) {
|
|
23161
|
+
const yamlFiles = fs16.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
|
|
23057
23162
|
for (const file of yamlFiles) {
|
|
23163
|
+
const content = readRealFileOrThrow(hubFolder, path22.join(agentsDir, file)) ?? "";
|
|
23058
23164
|
try {
|
|
23059
|
-
const content = fs17.readFileSync(path22.join(agentsDir, file), "utf-8");
|
|
23060
23165
|
const agent = yaml11.load(content);
|
|
23061
23166
|
if (agent?.id && agent.name) {
|
|
23062
23167
|
agentsWithIds.push({ id: agent.id, name: agent.name });
|
|
@@ -23069,7 +23174,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
23069
23174
|
if (agentsWithIds.length === 0) {
|
|
23070
23175
|
const yamlPath = resolveHubYamlPath(hubFolder);
|
|
23071
23176
|
if (!yamlPath) return;
|
|
23072
|
-
const yamlContent =
|
|
23177
|
+
const yamlContent = readRealFileOrThrow(hubFolder, yamlPath) ?? "";
|
|
23073
23178
|
const config = yaml11.load(yamlContent);
|
|
23074
23179
|
agentsWithIds = (config.agents || []).filter((a) => !!a.id && !!a.name);
|
|
23075
23180
|
}
|
|
@@ -23101,18 +23206,18 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
23101
23206
|
}
|
|
23102
23207
|
}
|
|
23103
23208
|
if (renames.length === 0) return;
|
|
23104
|
-
if (!
|
|
23105
|
-
for (const file of
|
|
23209
|
+
if (!fs16.existsSync(agentsDir)) return;
|
|
23210
|
+
for (const file of fs16.readdirSync(agentsDir)) {
|
|
23106
23211
|
if (file.startsWith("__rename_temp_") && (file.endsWith(".md") || file.endsWith(".yaml"))) {
|
|
23107
23212
|
console.warn(` Warning: removing orphaned temp file agents/${file}`);
|
|
23108
|
-
|
|
23213
|
+
fs16.unlinkSync(path22.join(agentsDir, file));
|
|
23109
23214
|
}
|
|
23110
23215
|
}
|
|
23111
23216
|
const renameFileIfExists = (dir, oldName, newName) => {
|
|
23112
23217
|
const oldPath = path22.join(dir, oldName);
|
|
23113
23218
|
const newPath = path22.join(dir, newName);
|
|
23114
|
-
if (!
|
|
23115
|
-
|
|
23219
|
+
if (!fs16.existsSync(oldPath)) return false;
|
|
23220
|
+
fs16.renameSync(oldPath, newPath);
|
|
23116
23221
|
return true;
|
|
23117
23222
|
};
|
|
23118
23223
|
const oldSlugs = new Set(renames.map((r) => r.oldSlug));
|
|
@@ -23145,9 +23250,9 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
23145
23250
|
}
|
|
23146
23251
|
} else {
|
|
23147
23252
|
for (const { oldSlug, newSlug } of renames) {
|
|
23148
|
-
const hasOldFile = extensions.some((ext) =>
|
|
23253
|
+
const hasOldFile = extensions.some((ext) => fs16.existsSync(path22.join(agentsDir, `${oldSlug}${ext}`)));
|
|
23149
23254
|
if (!hasOldFile) continue;
|
|
23150
|
-
const hasNewFile = extensions.some((ext) =>
|
|
23255
|
+
const hasNewFile = extensions.some((ext) => fs16.existsSync(path22.join(agentsDir, `${newSlug}${ext}`)));
|
|
23151
23256
|
if (hasNewFile) {
|
|
23152
23257
|
console.warn(` Warning: skipping rename agents/${oldSlug}.* \u2192 agents/${newSlug}.* (target already exists)`);
|
|
23153
23258
|
continue;
|
|
@@ -23162,7 +23267,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
23162
23267
|
if (completedRenames.length === 0) return;
|
|
23163
23268
|
const mainYamlPath = resolveHubYamlPath(hubFolder);
|
|
23164
23269
|
if (mainYamlPath) {
|
|
23165
|
-
const mainYamlContent =
|
|
23270
|
+
const mainYamlContent = readRealFileOrThrow(hubFolder, mainYamlPath) ?? "";
|
|
23166
23271
|
const substitutionMap = /* @__PURE__ */ new Map();
|
|
23167
23272
|
for (const { oldSlug, newSlug } of completedRenames) {
|
|
23168
23273
|
substitutionMap.set(`agents/${oldSlug}.md`, `agents/${newSlug}.md`);
|
|
@@ -23173,7 +23278,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
23173
23278
|
(_match, prefix, pathMatch) => `${prefix}${substitutionMap.get(pathMatch) ?? pathMatch}`
|
|
23174
23279
|
);
|
|
23175
23280
|
if (updatedYaml !== mainYamlContent) {
|
|
23176
|
-
|
|
23281
|
+
writeFileNoFollow(hubFolder, mainYamlPath, Buffer.from(updatedYaml, "utf-8"));
|
|
23177
23282
|
console.log(` Updated instructions paths in ${path22.basename(mainYamlPath)}`);
|
|
23178
23283
|
}
|
|
23179
23284
|
}
|
|
@@ -23267,11 +23372,13 @@ New hub: "${newHub.hubName}" (${hubType})`);
|
|
|
23267
23372
|
return;
|
|
23268
23373
|
}
|
|
23269
23374
|
}
|
|
23375
|
+
requireRealHubFolder(newHub.hubFolder, false);
|
|
23270
23376
|
const hubYamlPath = resolveHubYamlPath(newHub.hubFolder);
|
|
23271
23377
|
if (!hubYamlPath) {
|
|
23272
23378
|
console.error(`hub.yaml not found in ${newHub.hubFolder}. Cannot proceed with hub creation.`);
|
|
23273
23379
|
process.exit(1);
|
|
23274
23380
|
}
|
|
23381
|
+
const content = readRealFileOrThrow(newHub.hubFolder, hubYamlPath) ?? "";
|
|
23275
23382
|
console.log("Creating hub...");
|
|
23276
23383
|
const createResult = await client.createHub(opts.organizationId, {
|
|
23277
23384
|
hubName: newHub.hubName,
|
|
@@ -23285,7 +23392,6 @@ New hub: "${newHub.hubName}" (${hubType})`);
|
|
|
23285
23392
|
process.exit(1);
|
|
23286
23393
|
}
|
|
23287
23394
|
console.log(`Hub created: ${createdHub.hub_name} (${hubId})`);
|
|
23288
|
-
const content = fs17.readFileSync(hubYamlPath, "utf-8");
|
|
23289
23395
|
const hasVersion = content.match(/^version:\s/m);
|
|
23290
23396
|
let updated;
|
|
23291
23397
|
if (hasVersion) {
|
|
@@ -23301,7 +23407,7 @@ hub_id: "${hubId}"
|
|
|
23301
23407
|
hub_environment: preview
|
|
23302
23408
|
${content}`;
|
|
23303
23409
|
}
|
|
23304
|
-
|
|
23410
|
+
writeFileNoFollow(newHub.hubFolder, hubYamlPath, Buffer.from(updated, "utf-8"));
|
|
23305
23411
|
seedScopeIfEmpty("hubs", hubId);
|
|
23306
23412
|
await pushSingleHub(client, hubId, newHub.hubFolder, opts.autoConfirm, opts.organizationId, { skipAgentRename: true });
|
|
23307
23413
|
}
|
|
@@ -23347,7 +23453,7 @@ async function pushCommand(args2) {
|
|
|
23347
23453
|
const client = new ApiClient({ apiUrl: config.api_url, accessToken });
|
|
23348
23454
|
const workspaceDir = resolveWorkspaceDir();
|
|
23349
23455
|
const wsLabel = hubsDirLabel(gitRoot);
|
|
23350
|
-
if (!
|
|
23456
|
+
if (!fs16.existsSync(workspaceDir)) {
|
|
23351
23457
|
console.error(`No ${wsLabel}/ directory found. Run \`wayai pull\` first or create hub files in ${wsLabel}/<hub>/hub.yaml.`);
|
|
23352
23458
|
process.exit(1);
|
|
23353
23459
|
}
|
|
@@ -23391,6 +23497,7 @@ var init_push = __esm({
|
|
|
23391
23497
|
init_repo_config();
|
|
23392
23498
|
init_worktree_scope();
|
|
23393
23499
|
init_subtree_routing();
|
|
23500
|
+
init_fs_safety();
|
|
23394
23501
|
LOCAL_CHANGE_LIST_CAP = 20;
|
|
23395
23502
|
}
|
|
23396
23503
|
});
|
|
@@ -23403,7 +23510,7 @@ __export(pull_exports, {
|
|
|
23403
23510
|
resolveHubTarget: () => resolveHubTarget,
|
|
23404
23511
|
writeProductionMirror: () => writeProductionMirror2
|
|
23405
23512
|
});
|
|
23406
|
-
import * as
|
|
23513
|
+
import * as fs17 from "fs";
|
|
23407
23514
|
import * as path23 from "path";
|
|
23408
23515
|
function parseArgs6(args2) {
|
|
23409
23516
|
return { autoConfirm: args2.includes("--yes") || args2.includes("-y") };
|
|
@@ -23470,7 +23577,7 @@ async function pullCommand(args2) {
|
|
|
23470
23577
|
payload.preview_label,
|
|
23471
23578
|
payload.branch_name
|
|
23472
23579
|
);
|
|
23473
|
-
|
|
23580
|
+
fs17.mkdirSync(path23.dirname(hubFolder), { recursive: true });
|
|
23474
23581
|
console.log("Writing hub configuration...");
|
|
23475
23582
|
await materializeHubFolder(hubFolder, payload);
|
|
23476
23583
|
const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
|
|
@@ -23499,7 +23606,8 @@ async function pullCommand(args2) {
|
|
|
23499
23606
|
}
|
|
23500
23607
|
action = "apply";
|
|
23501
23608
|
}
|
|
23502
|
-
} catch {
|
|
23609
|
+
} catch (err) {
|
|
23610
|
+
if (isWorkspaceRefusal(err)) throw err;
|
|
23503
23611
|
action = "overwrite";
|
|
23504
23612
|
}
|
|
23505
23613
|
if (action === "overwrite") console.log("Writing hub configuration...");
|
|
@@ -23524,7 +23632,7 @@ async function pullCommand(args2) {
|
|
|
23524
23632
|
}
|
|
23525
23633
|
async function writeProductionMirror2(workspaceDir, prodPayload) {
|
|
23526
23634
|
const folder = resolveHubFolder(workspaceDir, prodPayload.hub_id, prodPayload.hub.name, "production", null, null);
|
|
23527
|
-
|
|
23635
|
+
fs17.mkdirSync(path23.dirname(folder), { recursive: true });
|
|
23528
23636
|
await materializeHubFolder(folder, prodPayload, { seedAgentContext: false });
|
|
23529
23637
|
const finalFolder = autoRenameHubFolder(folder, prodPayload.hub.name, "production", prodPayload.hub_id, null, null);
|
|
23530
23638
|
prependMirrorMarker(finalFolder, prodPayload.hub_id);
|
|
@@ -23542,11 +23650,11 @@ async function mirrorLinkedProduction2(client, workspaceDir, productionHubId, or
|
|
|
23542
23650
|
function prependMirrorMarker(hubFolder, productionHubId) {
|
|
23543
23651
|
const hubYaml = path23.join(hubFolder, "hub.yaml");
|
|
23544
23652
|
try {
|
|
23545
|
-
const content =
|
|
23653
|
+
const content = fs17.readFileSync(hubYaml, "utf-8");
|
|
23546
23654
|
if (content.startsWith(MIRROR_MARKER_PREFIX2)) return;
|
|
23547
23655
|
const marker = `${MIRROR_MARKER_PREFIX2} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
|
|
23548
23656
|
`;
|
|
23549
|
-
|
|
23657
|
+
fs17.writeFileSync(hubYaml, marker + content, "utf-8");
|
|
23550
23658
|
} catch {
|
|
23551
23659
|
}
|
|
23552
23660
|
}
|
|
@@ -23574,6 +23682,7 @@ var init_pull = __esm({
|
|
|
23574
23682
|
init_utils();
|
|
23575
23683
|
init_resource_files();
|
|
23576
23684
|
init_hub_materializer();
|
|
23685
|
+
init_fs_safety();
|
|
23577
23686
|
init_push();
|
|
23578
23687
|
init_workspace();
|
|
23579
23688
|
init_layout();
|
|
@@ -23590,7 +23699,7 @@ __export(create_exports, {
|
|
|
23590
23699
|
createCommand: () => createCommand
|
|
23591
23700
|
});
|
|
23592
23701
|
import * as path24 from "path";
|
|
23593
|
-
import * as
|
|
23702
|
+
import * as fs18 from "fs";
|
|
23594
23703
|
function parseArgs7(args2) {
|
|
23595
23704
|
let autoConfirm = false;
|
|
23596
23705
|
let folderSelector;
|
|
@@ -23617,7 +23726,7 @@ async function createCommand(args2) {
|
|
|
23617
23726
|
const gitRoot = findGitRoot();
|
|
23618
23727
|
const wsLabel = hubsDirLabel(gitRoot);
|
|
23619
23728
|
if (gitRoot) warnLayoutOnce(gitRoot);
|
|
23620
|
-
if (!
|
|
23729
|
+
if (!fs18.existsSync(workspaceDir)) {
|
|
23621
23730
|
console.error(`No ${wsLabel}/ directory found. Create hub files in ${wsLabel}/<hub>/hub.yaml with \`hub: { name: ... }\` first.`);
|
|
23622
23731
|
process.exit(1);
|
|
23623
23732
|
}
|
|
@@ -23751,7 +23860,7 @@ var replicate_exports = {};
|
|
|
23751
23860
|
__export(replicate_exports, {
|
|
23752
23861
|
replicateCommand: () => replicateCommand
|
|
23753
23862
|
});
|
|
23754
|
-
import * as
|
|
23863
|
+
import * as fs19 from "fs";
|
|
23755
23864
|
import * as path25 from "path";
|
|
23756
23865
|
function parseArgs9(args2) {
|
|
23757
23866
|
let label;
|
|
@@ -23798,8 +23907,8 @@ async function replicateCommand(args2) {
|
|
|
23798
23907
|
payload.preview_label,
|
|
23799
23908
|
payload.branch_name
|
|
23800
23909
|
);
|
|
23801
|
-
const folderPreExisted =
|
|
23802
|
-
|
|
23910
|
+
const folderPreExisted = fs19.existsSync(hubFolder);
|
|
23911
|
+
fs19.mkdirSync(path25.dirname(hubFolder), { recursive: true });
|
|
23803
23912
|
const delta = await materializeHubFolder(hubFolder, payload);
|
|
23804
23913
|
hubFolder = autoRenameHubFolder(
|
|
23805
23914
|
hubFolder,
|
|
@@ -24226,7 +24335,7 @@ __export(migrate_exports, {
|
|
|
24226
24335
|
migrateCommand: () => migrateCommand
|
|
24227
24336
|
});
|
|
24228
24337
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
24229
|
-
import * as
|
|
24338
|
+
import * as fs20 from "fs";
|
|
24230
24339
|
import * as path29 from "path";
|
|
24231
24340
|
function isTracked(gitRoot, p) {
|
|
24232
24341
|
try {
|
|
@@ -24240,7 +24349,7 @@ function isTracked(gitRoot, p) {
|
|
|
24240
24349
|
}
|
|
24241
24350
|
}
|
|
24242
24351
|
function moveDir(gitRoot, from, to) {
|
|
24243
|
-
|
|
24352
|
+
fs20.mkdirSync(path29.dirname(to), { recursive: true });
|
|
24244
24353
|
if (isTracked(gitRoot, from)) {
|
|
24245
24354
|
try {
|
|
24246
24355
|
execFileSync3("git", ["mv", path29.relative(gitRoot, from), path29.relative(gitRoot, to)], {
|
|
@@ -24251,7 +24360,7 @@ function moveDir(gitRoot, from, to) {
|
|
|
24251
24360
|
} catch {
|
|
24252
24361
|
}
|
|
24253
24362
|
}
|
|
24254
|
-
|
|
24363
|
+
fs20.renameSync(from, to);
|
|
24255
24364
|
return "fs";
|
|
24256
24365
|
}
|
|
24257
24366
|
async function migrateCommand(_args) {
|
|
@@ -24266,8 +24375,11 @@ async function migrateCommand(_args) {
|
|
|
24266
24375
|
const legacyOrg = path29.join(gitRoot, WAYAI_LAYOUT.legacy.orgAtRoot);
|
|
24267
24376
|
const newHubs = path29.join(newWs, WAYAI_LAYOUT.hubsSubdir);
|
|
24268
24377
|
const newOrg = path29.join(newWs, WAYAI_LAYOUT.orgSubdir);
|
|
24269
|
-
|
|
24270
|
-
|
|
24378
|
+
requireRealSubdirNoSymlink(gitRoot, newHubs, false);
|
|
24379
|
+
requireRealSubdirNoSymlink(gitRoot, newOrg, false);
|
|
24380
|
+
readRealFileOrThrow(gitRoot, workspaceManifestPath(gitRoot));
|
|
24381
|
+
const hasLegacyWs = isRealDirectory(legacyWs);
|
|
24382
|
+
const hasLegacyOrg = isRealDirectory(legacyOrg);
|
|
24271
24383
|
const orgPlan = planOrgMigration(gitRoot);
|
|
24272
24384
|
if (orgPlan.kind === "refuse") {
|
|
24273
24385
|
console.error(orgPlan.message);
|
|
@@ -24331,6 +24443,7 @@ var init_migrate = __esm({
|
|
|
24331
24443
|
"use strict";
|
|
24332
24444
|
init_workspace();
|
|
24333
24445
|
init_layout();
|
|
24446
|
+
init_fs_safety();
|
|
24334
24447
|
init_repo_config();
|
|
24335
24448
|
init_workspace_manifest();
|
|
24336
24449
|
}
|
|
@@ -24414,12 +24527,12 @@ var send_message_exports = {};
|
|
|
24414
24527
|
__export(send_message_exports, {
|
|
24415
24528
|
sendMessageCommand: () => sendMessageCommand
|
|
24416
24529
|
});
|
|
24417
|
-
import * as
|
|
24530
|
+
import * as fs21 from "fs";
|
|
24418
24531
|
import * as path30 from "path";
|
|
24419
24532
|
function statAttachment(filePath) {
|
|
24420
24533
|
let stat2;
|
|
24421
24534
|
try {
|
|
24422
|
-
stat2 =
|
|
24535
|
+
stat2 = fs21.statSync(filePath);
|
|
24423
24536
|
} catch {
|
|
24424
24537
|
console.error(`Error: file not found: ${filePath}`);
|
|
24425
24538
|
process.exit(1);
|
|
@@ -24435,7 +24548,7 @@ function readAttachment(filePath, size) {
|
|
|
24435
24548
|
const ext = path30.extname(fileName).replace(/^\./, "");
|
|
24436
24549
|
return {
|
|
24437
24550
|
file_name: fileName,
|
|
24438
|
-
file_binary:
|
|
24551
|
+
file_binary: fs21.readFileSync(filePath).toString("base64"),
|
|
24439
24552
|
file_size: size,
|
|
24440
24553
|
...ext && { file_extension: ext }
|
|
24441
24554
|
};
|
|
@@ -26634,7 +26747,7 @@ var eval_capture_exports = {};
|
|
|
26634
26747
|
__export(eval_capture_exports, {
|
|
26635
26748
|
evalCaptureCommand: () => evalCaptureCommand
|
|
26636
26749
|
});
|
|
26637
|
-
import * as
|
|
26750
|
+
import * as fs22 from "fs";
|
|
26638
26751
|
import * as path31 from "path";
|
|
26639
26752
|
import * as yaml12 from "js-yaml";
|
|
26640
26753
|
function isValidSetName(name) {
|
|
@@ -26708,7 +26821,17 @@ async function evalCaptureCommand(args2) {
|
|
|
26708
26821
|
console.error(`Resolved path "${path31.relative(hubFolder, targetPath)}" escapes evals/. Aborting.`);
|
|
26709
26822
|
process.exit(1);
|
|
26710
26823
|
}
|
|
26711
|
-
if (
|
|
26824
|
+
if (!ensureRealSubdirNoSymlink(hubFolder, targetDir, false)) {
|
|
26825
|
+
console.error(`${path31.relative(hubFolder, targetDir)} is reached through a symlink. Aborting.`);
|
|
26826
|
+
process.exit(1);
|
|
26827
|
+
}
|
|
26828
|
+
let targetTaken = true;
|
|
26829
|
+
try {
|
|
26830
|
+
fs22.lstatSync(targetPath);
|
|
26831
|
+
} catch {
|
|
26832
|
+
targetTaken = false;
|
|
26833
|
+
}
|
|
26834
|
+
if (targetTaken) {
|
|
26712
26835
|
console.error(`File already exists: ${path31.relative(hubFolder, targetPath)}. Use --name to choose a different name.`);
|
|
26713
26836
|
process.exit(1);
|
|
26714
26837
|
}
|
|
@@ -26741,8 +26864,13 @@ async function evalCaptureCommand(args2) {
|
|
|
26741
26864
|
...captured.evaluator_instructions ? { evaluator_instructions: captured.evaluator_instructions } : {}
|
|
26742
26865
|
};
|
|
26743
26866
|
const yamlObj = buildEvalYamlObject(evalEntry, slug);
|
|
26744
|
-
|
|
26745
|
-
|
|
26867
|
+
const outcome = createFileNoFollow(hubFolder, targetPath, Buffer.from(yaml12.dump(yamlObj, YAML_DUMP_OPTIONS), "utf-8"));
|
|
26868
|
+
if (outcome !== "created") {
|
|
26869
|
+
console.error(
|
|
26870
|
+
`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.`
|
|
26871
|
+
);
|
|
26872
|
+
process.exit(1);
|
|
26873
|
+
}
|
|
26746
26874
|
const relPath = path31.relative(process.cwd(), targetPath);
|
|
26747
26875
|
console.log(`
|
|
26748
26876
|
Wrote ${relPath}`);
|
|
@@ -26757,6 +26885,7 @@ var init_eval_capture = __esm({
|
|
|
26757
26885
|
init_workspace();
|
|
26758
26886
|
init_utils();
|
|
26759
26887
|
init_yaml_writer();
|
|
26888
|
+
init_fs_safety();
|
|
26760
26889
|
}
|
|
26761
26890
|
});
|
|
26762
26891
|
|
|
@@ -28114,23 +28243,21 @@ var init_set_connection_credential = __esm({
|
|
|
28114
28243
|
});
|
|
28115
28244
|
|
|
28116
28245
|
// src/lib/org-workspace.ts
|
|
28117
|
-
import * as
|
|
28246
|
+
import * as fs23 from "fs";
|
|
28118
28247
|
import * as path32 from "path";
|
|
28119
28248
|
import * as yaml13 from "js-yaml";
|
|
28120
28249
|
function getOrgDir(gitRoot) {
|
|
28121
28250
|
return resolveLayout(gitRoot).orgDir;
|
|
28122
28251
|
}
|
|
28123
28252
|
function orgManifestExists(orgDir) {
|
|
28124
|
-
return
|
|
28253
|
+
return fs23.existsSync(path32.join(orgDir, ORG_MANIFEST_NAME));
|
|
28125
28254
|
}
|
|
28126
28255
|
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
28256
|
const resourcesDir = path32.join(orgDir, "resources");
|
|
28257
|
+
requireRealSubdirNoSymlink(orgDir, resourcesDir, false);
|
|
28258
|
+
const manifestText = readRealFileOrThrow(orgDir, path32.join(orgDir, ORG_MANIFEST_NAME));
|
|
28259
|
+
const manifest = (manifestText !== null ? yaml13.load(manifestText) : null) ?? {};
|
|
28260
|
+
const rawResources = Array.isArray(manifest.resources) ? manifest.resources : [];
|
|
28134
28261
|
const resources = rawResources.map((res) => {
|
|
28135
28262
|
const resource = { name: res.name };
|
|
28136
28263
|
if (res.id) resource.id = res.id;
|
|
@@ -28143,7 +28270,8 @@ function parseOrgResources(orgDir) {
|
|
|
28143
28270
|
if (Array.isArray(res.tags)) resource.tags = res.tags;
|
|
28144
28271
|
if (Array.isArray(res.folders)) resource.folders = res.folders;
|
|
28145
28272
|
const resDir = path32.join(resourcesDir, slugify(resource.name));
|
|
28146
|
-
|
|
28273
|
+
requireRealSubdirNoSymlink(orgDir, resDir, false);
|
|
28274
|
+
if (fs23.existsSync(resDir)) {
|
|
28147
28275
|
const files = scanResourceFiles(resDir, "");
|
|
28148
28276
|
if (files.length > 0) resource.files = files;
|
|
28149
28277
|
}
|
|
@@ -28152,28 +28280,29 @@ function parseOrgResources(orgDir) {
|
|
|
28152
28280
|
return { version: 1, resources };
|
|
28153
28281
|
}
|
|
28154
28282
|
function writeOrgResources(orgDir, payload) {
|
|
28155
|
-
|
|
28283
|
+
fs23.mkdirSync(orgDir, { recursive: true });
|
|
28284
|
+
const resourcesDir = path32.join(orgDir, "resources");
|
|
28285
|
+
requireRealSubdirNoSymlink(orgDir, resourcesDir, false);
|
|
28156
28286
|
const resources = payload.resources ?? [];
|
|
28157
28287
|
const manifestResources = resources.map((r) => {
|
|
28158
28288
|
const { files: _files, ...rest } = r;
|
|
28159
28289
|
return rest;
|
|
28160
28290
|
});
|
|
28161
|
-
|
|
28291
|
+
writeFileNoFollow(
|
|
28292
|
+
orgDir,
|
|
28162
28293
|
path32.join(orgDir, ORG_MANIFEST_NAME),
|
|
28163
|
-
yaml13.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS),
|
|
28164
|
-
"utf-8"
|
|
28294
|
+
Buffer.from(yaml13.dump({ version: 1, resources: manifestResources }, YAML_DUMP_OPTIONS), "utf-8")
|
|
28165
28295
|
);
|
|
28166
|
-
const resourcesDir = path32.join(orgDir, "resources");
|
|
28167
28296
|
const currentSlugs = /* @__PURE__ */ new Set();
|
|
28168
28297
|
for (const resource of resources) {
|
|
28169
28298
|
const resSlug = slugify(resource.name);
|
|
28170
28299
|
currentSlugs.add(resSlug);
|
|
28171
28300
|
writeResourceFileTree(path32.join(resourcesDir, resSlug), resource.files || [], orgDir);
|
|
28172
28301
|
}
|
|
28173
|
-
if (
|
|
28174
|
-
for (const entry of
|
|
28302
|
+
if (fs23.existsSync(resourcesDir)) {
|
|
28303
|
+
for (const entry of fs23.readdirSync(resourcesDir, { withFileTypes: true })) {
|
|
28175
28304
|
if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
|
|
28176
|
-
|
|
28305
|
+
fs23.rmSync(path32.join(resourcesDir, entry.name), { recursive: true, force: true });
|
|
28177
28306
|
}
|
|
28178
28307
|
}
|
|
28179
28308
|
}
|
|
@@ -28193,6 +28322,7 @@ var init_org_workspace = __esm({
|
|
|
28193
28322
|
"use strict";
|
|
28194
28323
|
init_utils();
|
|
28195
28324
|
init_layout();
|
|
28325
|
+
init_fs_safety();
|
|
28196
28326
|
init_resource_files();
|
|
28197
28327
|
init_yaml_writer();
|
|
28198
28328
|
ORG_MANIFEST_NAME = "resources.yaml";
|
|
@@ -28478,7 +28608,7 @@ var init_report_edit_args = __esm({
|
|
|
28478
28608
|
});
|
|
28479
28609
|
|
|
28480
28610
|
// src/lib/file-map.ts
|
|
28481
|
-
import * as
|
|
28611
|
+
import * as fs24 from "fs";
|
|
28482
28612
|
import * as path33 from "path";
|
|
28483
28613
|
function isSafeRelPath(rel) {
|
|
28484
28614
|
if (rel.length === 0 || rel.length > 300) return false;
|
|
@@ -28495,8 +28625,8 @@ function writeFileMap(targetDir, files) {
|
|
|
28495
28625
|
throw new Error(`Refusing to write unsafe path: ${rel}`);
|
|
28496
28626
|
}
|
|
28497
28627
|
const abs = path33.join(targetDir, rel);
|
|
28498
|
-
|
|
28499
|
-
|
|
28628
|
+
fs24.mkdirSync(path33.dirname(abs), { recursive: true });
|
|
28629
|
+
fs24.writeFileSync(abs, body, "utf-8");
|
|
28500
28630
|
written.push(rel);
|
|
28501
28631
|
}
|
|
28502
28632
|
return written;
|
|
@@ -28512,7 +28642,7 @@ var admin_exports = {};
|
|
|
28512
28642
|
__export(admin_exports, {
|
|
28513
28643
|
adminCommand: () => adminCommand
|
|
28514
28644
|
});
|
|
28515
|
-
import * as
|
|
28645
|
+
import * as fs25 from "fs";
|
|
28516
28646
|
import * as path34 from "path";
|
|
28517
28647
|
async function adminCommand(args2) {
|
|
28518
28648
|
const [group, ...afterGroup] = args2;
|
|
@@ -28828,7 +28958,7 @@ async function runArchiveRead(positional, flagArgs) {
|
|
|
28828
28958
|
exitOnApiError(err);
|
|
28829
28959
|
throw err;
|
|
28830
28960
|
}
|
|
28831
|
-
|
|
28961
|
+
fs25.writeFileSync(outPath, zip);
|
|
28832
28962
|
console.log(`Wrote ${zip.byteLength} bytes to ${outPath}`);
|
|
28833
28963
|
return;
|
|
28834
28964
|
}
|
|
@@ -28970,7 +29100,7 @@ async function runSkillInstall(positional) {
|
|
|
28970
29100
|
throw err;
|
|
28971
29101
|
}
|
|
28972
29102
|
const root = findGitRoot() ?? process.cwd();
|
|
28973
|
-
const present = HARNESS_SKILL_DIRS.filter((dir) =>
|
|
29103
|
+
const present = HARNESS_SKILL_DIRS.filter((dir) => fs25.existsSync(path34.join(root, dir)));
|
|
28974
29104
|
const targets = present.length > 0 ? present : HARNESS_SKILL_DIRS;
|
|
28975
29105
|
const fileCount = Object.keys(res.files).length;
|
|
28976
29106
|
const relDirs = targets.map((harness) => {
|
|
@@ -30528,7 +30658,7 @@ var init_actions = __esm({
|
|
|
30528
30658
|
|
|
30529
30659
|
// src/data/commands/attachments.ts
|
|
30530
30660
|
import { Command as Command2 } from "commander";
|
|
30531
|
-
import { readFileSync as
|
|
30661
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
30532
30662
|
function findAttachmentByFilename(attachments, filename) {
|
|
30533
30663
|
return attachments.find((a) => a.key.endsWith(`/${filename}`)) ?? null;
|
|
30534
30664
|
}
|
|
@@ -30569,7 +30699,7 @@ function buildAttachmentsCommand() {
|
|
|
30569
30699
|
printOutput(data, outputFormat(this));
|
|
30570
30700
|
return;
|
|
30571
30701
|
}
|
|
30572
|
-
const body =
|
|
30702
|
+
const body = readFileSync17(opts.file);
|
|
30573
30703
|
await client.upload(uploadPathFrom(data?.upload_url), body, opts.contentType);
|
|
30574
30704
|
printOutput({ ...data, uploaded: true }, outputFormat(this));
|
|
30575
30705
|
});
|
|
@@ -30969,7 +31099,7 @@ var init_import = __esm({
|
|
|
30969
31099
|
|
|
30970
31100
|
// src/data/commands/providers.ts
|
|
30971
31101
|
import { Command as Command5 } from "commander";
|
|
30972
|
-
import { writeFileSync as
|
|
31102
|
+
import { writeFileSync as writeFileSync9 } from "fs";
|
|
30973
31103
|
function providerSegment(provider) {
|
|
30974
31104
|
if (!VALID_PROVIDERS.includes(provider)) {
|
|
30975
31105
|
throw expected(`Unknown provider ${JSON.stringify(provider)}. Expected one of: ${VALID_PROVIDERS_HELP}.`);
|
|
@@ -31002,7 +31132,7 @@ function buildBasesProvidersCommand() {
|
|
|
31002
31132
|
);
|
|
31003
31133
|
if (opts.to) {
|
|
31004
31134
|
try {
|
|
31005
|
-
|
|
31135
|
+
writeFileSync9(opts.to, JSON.stringify(data, null, 2));
|
|
31006
31136
|
} catch (e) {
|
|
31007
31137
|
throw expected(`--to ${opts.to}: ${e instanceof Error ? e.message : "could not be written"}`);
|
|
31008
31138
|
}
|
|
@@ -31049,8 +31179,8 @@ var init_providers = __esm({
|
|
|
31049
31179
|
|
|
31050
31180
|
// src/data/commands/report.ts
|
|
31051
31181
|
import { Command as Command6 } from "commander";
|
|
31052
|
-
import { readFileSync as
|
|
31053
|
-
import { dirname as
|
|
31182
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
31183
|
+
import { dirname as dirname13, join as join30 } from "path";
|
|
31054
31184
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
31055
31185
|
function resolveCliVersion() {
|
|
31056
31186
|
for (const candidate of [
|
|
@@ -31058,7 +31188,7 @@ function resolveCliVersion() {
|
|
|
31058
31188
|
join30(here, "..", "..", "..", "package.json")
|
|
31059
31189
|
]) {
|
|
31060
31190
|
try {
|
|
31061
|
-
const version = JSON.parse(
|
|
31191
|
+
const version = JSON.parse(readFileSync18(candidate, "utf-8")).version;
|
|
31062
31192
|
if (typeof version === "string" && version) return version;
|
|
31063
31193
|
} catch {
|
|
31064
31194
|
}
|
|
@@ -31254,13 +31384,13 @@ var init_report2 = __esm({
|
|
|
31254
31384
|
init_terminal_output();
|
|
31255
31385
|
init_workspace();
|
|
31256
31386
|
init_skill_version();
|
|
31257
|
-
here =
|
|
31387
|
+
here = dirname13(fileURLToPath2(import.meta.url));
|
|
31258
31388
|
}
|
|
31259
31389
|
});
|
|
31260
31390
|
|
|
31261
31391
|
// src/data/commands/credentials.ts
|
|
31262
31392
|
import { Command as Command7 } from "commander";
|
|
31263
|
-
import { readFileSync as
|
|
31393
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
31264
31394
|
function withValueSourceOptions(cmd, what) {
|
|
31265
31395
|
return cmd.option(
|
|
31266
31396
|
"--file <path>",
|
|
@@ -31273,7 +31403,7 @@ async function resolveValue(opts, label) {
|
|
|
31273
31403
|
throw expected("--file cannot be combined with --value-stdin or --value-prompt \u2014 pass one.");
|
|
31274
31404
|
}
|
|
31275
31405
|
try {
|
|
31276
|
-
return
|
|
31406
|
+
return readFileSync19(opts.file).toString("base64");
|
|
31277
31407
|
} catch (e) {
|
|
31278
31408
|
throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
|
|
31279
31409
|
}
|
|
@@ -31422,7 +31552,7 @@ var init_credentials = __esm({
|
|
|
31422
31552
|
|
|
31423
31553
|
// src/data/commands/sql.ts
|
|
31424
31554
|
import { Command as Command8 } from "commander";
|
|
31425
|
-
import { readFileSync as
|
|
31555
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
31426
31556
|
function buildBasesSqlCommand() {
|
|
31427
31557
|
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
31558
|
"--param <kv...>",
|
|
@@ -31432,7 +31562,7 @@ function buildBasesSqlCommand() {
|
|
|
31432
31562
|
let query;
|
|
31433
31563
|
if (opts.file) {
|
|
31434
31564
|
try {
|
|
31435
|
-
query =
|
|
31565
|
+
query = readFileSync20(opts.file, "utf-8").trim();
|
|
31436
31566
|
} catch (e) {
|
|
31437
31567
|
throw expected(`--file ${opts.file}: ${e instanceof Error ? e.message : "could not be read"}`);
|
|
31438
31568
|
}
|
|
@@ -32087,8 +32217,8 @@ var init_file_types = __esm({
|
|
|
32087
32217
|
|
|
32088
32218
|
// src/data/commands/files.ts
|
|
32089
32219
|
import { Command as Command12 } from "commander";
|
|
32090
|
-
import { readFileSync as
|
|
32091
|
-
import { basename as
|
|
32220
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync10 } from "fs";
|
|
32221
|
+
import { basename as basename20 } from "path";
|
|
32092
32222
|
function renderFileDiff(fileType, filePath, from, to, d) {
|
|
32093
32223
|
console.log(sanitizeTerminalText(`${fileType}/${filePath}: v${from} \u2192 v${to}`));
|
|
32094
32224
|
const md = d.metadata_delta;
|
|
@@ -32120,7 +32250,7 @@ function renderFileDiff(fileType, filePath, from, to, d) {
|
|
|
32120
32250
|
}
|
|
32121
32251
|
function downloadTarget(remotePath, to) {
|
|
32122
32252
|
if (to) return to;
|
|
32123
|
-
const derived =
|
|
32253
|
+
const derived = basename20(remotePath);
|
|
32124
32254
|
if (derived === "" || derived === "." || derived === "..") {
|
|
32125
32255
|
throw expected(
|
|
32126
32256
|
`Cannot derive a local filename from "${remotePath}" \u2014 pass --to <local> to name it.`
|
|
@@ -32136,7 +32266,7 @@ function buildFilesCommand() {
|
|
|
32136
32266
|
"Upload a local file to a path (e.g. wayai files put reports q3/summary.pdf --file ./summary.pdf)"
|
|
32137
32267
|
).requiredOption("--file <local>", "Local file to upload").option("--content-type <type>", "MIME type", "application/octet-stream").action(async function(fileType, filePath, opts) {
|
|
32138
32268
|
const base = pathSegment(requireBase(this), "--base");
|
|
32139
|
-
const body =
|
|
32269
|
+
const body = readFileSync21(opts.file);
|
|
32140
32270
|
const client = await createDataClient();
|
|
32141
32271
|
printOutput(
|
|
32142
32272
|
await client.upload(
|
|
@@ -32167,7 +32297,7 @@ function buildFilesCommand() {
|
|
|
32167
32297
|
const { bytes } = await client.download(
|
|
32168
32298
|
`/v1/${base}/files/${pathSegment(fileType, "file_type")}/${encoded}${versionQs ? `?${versionQs}` : ""}`
|
|
32169
32299
|
);
|
|
32170
|
-
|
|
32300
|
+
writeFileSync10(out, bytes);
|
|
32171
32301
|
console.log(`Downloaded to ${out}`);
|
|
32172
32302
|
});
|
|
32173
32303
|
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,9 +33315,9 @@ init_errors2();
|
|
|
33185
33315
|
init_mask_secrets();
|
|
33186
33316
|
init_utils();
|
|
33187
33317
|
init_registry();
|
|
33188
|
-
import { readFileSync as
|
|
33318
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
33189
33319
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
33190
|
-
import { dirname as
|
|
33320
|
+
import { dirname as dirname14, join as join31 } from "path";
|
|
33191
33321
|
|
|
33192
33322
|
// src/lib/version-refresh.ts
|
|
33193
33323
|
init_version_cache();
|
|
@@ -33342,8 +33472,8 @@ Run \`wayai admin skill install\` to update.`);
|
|
|
33342
33472
|
}
|
|
33343
33473
|
|
|
33344
33474
|
// src/index.ts
|
|
33345
|
-
var __dirname =
|
|
33346
|
-
var pkg = JSON.parse(
|
|
33475
|
+
var __dirname = dirname14(fileURLToPath3(import.meta.url));
|
|
33476
|
+
var pkg = JSON.parse(readFileSync22(join31(__dirname, "..", "package.json"), "utf-8"));
|
|
33347
33477
|
var [, , command, ...args] = process.argv;
|
|
33348
33478
|
var isBackgroundRefresh = command === REFRESH_COMMAND;
|
|
33349
33479
|
if (!isBackgroundRefresh) initSentry(command, pkg.version);
|