@wayai/cli 0.3.107 → 0.3.109
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 +375 -286
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11185,6 +11185,20 @@ var init_init = __esm({
|
|
|
11185
11185
|
// src/lib/fs-safety.ts
|
|
11186
11186
|
import * as fs9 from "fs";
|
|
11187
11187
|
import * as path11 from "path";
|
|
11188
|
+
function fileHasBytes(abs, data) {
|
|
11189
|
+
let st;
|
|
11190
|
+
try {
|
|
11191
|
+
st = fs9.lstatSync(abs);
|
|
11192
|
+
} catch {
|
|
11193
|
+
return false;
|
|
11194
|
+
}
|
|
11195
|
+
if (!st.isFile() || st.isSymbolicLink()) return false;
|
|
11196
|
+
try {
|
|
11197
|
+
return fs9.readFileSync(abs).equals(data);
|
|
11198
|
+
} catch {
|
|
11199
|
+
return false;
|
|
11200
|
+
}
|
|
11201
|
+
}
|
|
11188
11202
|
function realpathContained(root, abs) {
|
|
11189
11203
|
let realRoot;
|
|
11190
11204
|
let realAbs;
|
|
@@ -14838,13 +14852,13 @@ function assertResourcePayloadFitsWithoutPruning(payload, cause) {
|
|
|
14838
14852
|
}
|
|
14839
14853
|
}
|
|
14840
14854
|
}
|
|
14841
|
-
function writeResourceFileTree(resDir, files, root) {
|
|
14855
|
+
function writeResourceFileTree(resDir, files, root, log) {
|
|
14842
14856
|
if (!ensureRealSubdirNoSymlink(root, resDir, files.length > 0)) {
|
|
14843
14857
|
console.warn(` Warning: skipping resource dir (not reachable inside the workspace without a symlink)`);
|
|
14844
14858
|
return;
|
|
14845
14859
|
}
|
|
14846
14860
|
if (files.length === 0) {
|
|
14847
|
-
if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", /* @__PURE__ */ new Set());
|
|
14861
|
+
if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", /* @__PURE__ */ new Set(), root, log);
|
|
14848
14862
|
return;
|
|
14849
14863
|
}
|
|
14850
14864
|
const writtenPaths = /* @__PURE__ */ new Set();
|
|
@@ -14855,34 +14869,33 @@ function writeResourceFileTree(resDir, files, root) {
|
|
|
14855
14869
|
continue;
|
|
14856
14870
|
}
|
|
14857
14871
|
writtenPaths.add(file.path);
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
} else
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
writtenPaths.delete(file.path);
|
|
14867
|
-
}
|
|
14872
|
+
const buf = file.content !== void 0 ? Buffer.from(file.content, "utf-8") : file.content_base64 ? Buffer.from(file.content_base64, "base64") : void 0;
|
|
14873
|
+
if (buf === void 0) continue;
|
|
14874
|
+
if (fileHasBytes(filePath, buf)) continue;
|
|
14875
|
+
if (writeFileNoFollow(resDir, filePath, buf)) {
|
|
14876
|
+
log?.changed.push(path12.relative(root, filePath));
|
|
14877
|
+
} else {
|
|
14878
|
+
console.warn(` Warning: skipping ${file.path} (destination escapes the resource folder via a symlink)`);
|
|
14879
|
+
writtenPaths.delete(file.path);
|
|
14868
14880
|
}
|
|
14869
14881
|
}
|
|
14870
|
-
if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", writtenPaths);
|
|
14882
|
+
if (fs10.existsSync(resDir)) cleanOrphanFiles(resDir, "", writtenPaths, root, log);
|
|
14871
14883
|
}
|
|
14872
|
-
function cleanOrphanFiles(dir, prefix, writtenPaths) {
|
|
14884
|
+
function cleanOrphanFiles(dir, prefix, writtenPaths, root, log) {
|
|
14873
14885
|
const entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
14874
14886
|
for (const entry of entries) {
|
|
14875
14887
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
14876
14888
|
const fullPath = path12.join(dir, entry.name);
|
|
14877
14889
|
if (entry.isDirectory()) {
|
|
14878
|
-
cleanOrphanFiles(fullPath, relPath, writtenPaths);
|
|
14890
|
+
cleanOrphanFiles(fullPath, relPath, writtenPaths, root, log);
|
|
14879
14891
|
if (fs10.readdirSync(fullPath).length === 0) fs10.rmdirSync(fullPath);
|
|
14880
14892
|
} else if (!writtenPaths.has(relPath)) {
|
|
14881
14893
|
fs10.unlinkSync(fullPath);
|
|
14894
|
+
if (log && root) log.removed.push(path12.relative(root, fullPath));
|
|
14882
14895
|
}
|
|
14883
14896
|
}
|
|
14884
14897
|
}
|
|
14885
|
-
async function downloadBinaryFiles(resDir, files, root) {
|
|
14898
|
+
async function downloadBinaryFiles(resDir, files, root, log) {
|
|
14886
14899
|
if (!ensureRealSubdirNoSymlink(root, resDir, true)) {
|
|
14887
14900
|
console.warn(` Warning: skipping resource downloads (dir not reachable inside the workspace without a symlink)`);
|
|
14888
14901
|
return 0;
|
|
@@ -14896,14 +14909,26 @@ async function downloadBinaryFiles(resDir, files, root) {
|
|
|
14896
14909
|
console.warn(` Warning: skipping ${file.path} (path traversal detected)`);
|
|
14897
14910
|
continue;
|
|
14898
14911
|
}
|
|
14912
|
+
if (file.hash) {
|
|
14913
|
+
try {
|
|
14914
|
+
const st = fs10.lstatSync(filePath);
|
|
14915
|
+
if (st.isFile() && !st.isSymbolicLink() && computeHash(fs10.readFileSync(filePath)) === file.hash) continue;
|
|
14916
|
+
} catch {
|
|
14917
|
+
}
|
|
14918
|
+
}
|
|
14899
14919
|
const response = await fetch(file.download_url);
|
|
14900
14920
|
if (!response.ok) {
|
|
14901
14921
|
console.warn(` Warning: failed to download ${file.path} (${response.status})`);
|
|
14902
14922
|
continue;
|
|
14903
14923
|
}
|
|
14904
14924
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
14905
|
-
if (
|
|
14906
|
-
|
|
14925
|
+
if (fileHasBytes(filePath, buffer)) continue;
|
|
14926
|
+
if (writeFileNoFollow(resDir, filePath, buffer)) {
|
|
14927
|
+
count++;
|
|
14928
|
+
log?.changed.push(path12.relative(root, filePath));
|
|
14929
|
+
} else {
|
|
14930
|
+
console.warn(` Warning: skipping ${file.path} (destination escapes the resource folder via a symlink)`);
|
|
14931
|
+
}
|
|
14907
14932
|
} catch (err) {
|
|
14908
14933
|
console.warn(` Warning: failed to download ${file.path} (${err instanceof Error ? err.message : String(err)})`);
|
|
14909
14934
|
}
|
|
@@ -15082,12 +15107,12 @@ function rewriteEvalAttachmentsToLocalPaths(payload) {
|
|
|
15082
15107
|
}
|
|
15083
15108
|
async function downloadEvalAttachments(hubFolder, downloads) {
|
|
15084
15109
|
const attachDir = path13.resolve(hubFolder, ATTACHMENTS_DIR);
|
|
15085
|
-
|
|
15110
|
+
const result = { written: 0, changed: [], removed: [] };
|
|
15086
15111
|
if (!ensureRealSubdirNoSymlink(hubFolder, attachDir, downloads.length > 0)) {
|
|
15087
15112
|
console.warn(` Warning: ${ATTACHMENTS_DIR}/ is not reachable inside the hub folder without a symlink; skipping attachment sync.`);
|
|
15088
|
-
return
|
|
15113
|
+
return result;
|
|
15089
15114
|
}
|
|
15090
|
-
if (!fs11.existsSync(attachDir)) return
|
|
15115
|
+
if (!fs11.existsSync(attachDir)) return result;
|
|
15091
15116
|
for (const dl of downloads) {
|
|
15092
15117
|
const abs = path13.resolve(hubFolder, dl.relPath);
|
|
15093
15118
|
if (abs !== attachDir && !abs.startsWith(attachDir + path13.sep)) continue;
|
|
@@ -15105,7 +15130,10 @@ async function downloadEvalAttachments(hubFolder, downloads) {
|
|
|
15105
15130
|
console.warn(` Warning: failed to download ${dl.relPath} (HTTP ${res.status})`);
|
|
15106
15131
|
continue;
|
|
15107
15132
|
}
|
|
15108
|
-
if (writeFileNoFollow(hubFolder, abs, Buffer.from(await res.arrayBuffer())))
|
|
15133
|
+
if (writeFileNoFollow(hubFolder, abs, Buffer.from(await res.arrayBuffer()))) {
|
|
15134
|
+
result.written++;
|
|
15135
|
+
result.changed.push(dl.relPath);
|
|
15136
|
+
}
|
|
15109
15137
|
} catch (err) {
|
|
15110
15138
|
console.warn(` Warning: failed to download ${dl.relPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
15111
15139
|
}
|
|
@@ -15114,9 +15142,12 @@ async function downloadEvalAttachments(hubFolder, downloads) {
|
|
|
15114
15142
|
for (const name of fs11.readdirSync(attachDir)) {
|
|
15115
15143
|
const abs = path13.join(attachDir, name);
|
|
15116
15144
|
const st = fs11.lstatSync(abs);
|
|
15117
|
-
if ((st.isFile() || st.isSymbolicLink()) && !keep.has(abs))
|
|
15145
|
+
if ((st.isFile() || st.isSymbolicLink()) && !keep.has(abs)) {
|
|
15146
|
+
fs11.rmSync(abs);
|
|
15147
|
+
result.removed.push(path13.relative(hubFolder, abs));
|
|
15148
|
+
}
|
|
15118
15149
|
}
|
|
15119
|
-
return
|
|
15150
|
+
return result;
|
|
15120
15151
|
}
|
|
15121
15152
|
var ATTACHMENTS_DIR;
|
|
15122
15153
|
var init_eval_attachments = __esm({
|
|
@@ -15536,6 +15567,15 @@ var init_diff_display = __esm({
|
|
|
15536
15567
|
import * as fs13 from "fs";
|
|
15537
15568
|
import * as path15 from "path";
|
|
15538
15569
|
import * as yaml5 from "js-yaml";
|
|
15570
|
+
function writeFileIfChanged(hubFolder, absPath, content, log) {
|
|
15571
|
+
const buf = Buffer.from(content, "utf-8");
|
|
15572
|
+
if (fileHasBytes(absPath, buf)) return;
|
|
15573
|
+
if (writeFileNoFollow(hubFolder, absPath, buf)) {
|
|
15574
|
+
log.changed.push(path15.relative(hubFolder, absPath));
|
|
15575
|
+
} else {
|
|
15576
|
+
console.warn(` Warning: skipping ${path15.relative(hubFolder, absPath)} (destination escapes the hub folder via a symlink)`);
|
|
15577
|
+
}
|
|
15578
|
+
}
|
|
15539
15579
|
function buildEvalYamlObject(evalEntry, slug) {
|
|
15540
15580
|
const out = {};
|
|
15541
15581
|
if (evalEntry.id) out.id = evalEntry.id;
|
|
@@ -15570,6 +15610,7 @@ function buildEvalYamlObject(evalEntry, slug) {
|
|
|
15570
15610
|
return out;
|
|
15571
15611
|
}
|
|
15572
15612
|
function writeHubFolder(hubFolder, payload, options = {}) {
|
|
15613
|
+
const log = { changed: [], removed: [] };
|
|
15573
15614
|
const agentsDir = path15.join(hubFolder, "agents");
|
|
15574
15615
|
if (!fs13.existsSync(hubFolder)) {
|
|
15575
15616
|
fs13.mkdirSync(hubFolder, { recursive: true });
|
|
@@ -15580,38 +15621,48 @@ function writeHubFolder(hubFolder, payload, options = {}) {
|
|
|
15580
15621
|
const yamlPayload = buildYamlPayload(payload);
|
|
15581
15622
|
const agentFiles = extractAgentFiles(payload);
|
|
15582
15623
|
const yamlContent = yaml5.dump(yamlPayload, YAML_DUMP_OPTIONS);
|
|
15583
|
-
|
|
15624
|
+
writeFileIfChanged(hubFolder, path15.join(hubFolder, "hub.yaml"), yamlContent, log);
|
|
15584
15625
|
if (options.seedAgentContext ?? true) {
|
|
15585
|
-
|
|
15586
|
-
|
|
15626
|
+
for (const seeded of [
|
|
15627
|
+
writeIfAbsent(path15.join(hubFolder, "AGENTS.md"), perHubAgentsMd(path15.basename(hubFolder))),
|
|
15628
|
+
writeIfAbsent(path15.join(hubFolder, "CLAUDE.md"), CLAUDE_MD_SHIM)
|
|
15629
|
+
]) {
|
|
15630
|
+
if (seeded) log.changed.push(seeded);
|
|
15631
|
+
}
|
|
15587
15632
|
}
|
|
15588
15633
|
const oldYamlPath = path15.join(hubFolder, "wayai.yaml");
|
|
15589
15634
|
if (fs13.existsSync(oldYamlPath)) {
|
|
15590
15635
|
fs13.unlinkSync(oldYamlPath);
|
|
15636
|
+
log.removed.push(path15.relative(hubFolder, oldYamlPath));
|
|
15591
15637
|
}
|
|
15592
|
-
const yamlSlugs = writeAgentYamlFiles(agentsDir, payload.agents || []);
|
|
15638
|
+
const yamlSlugs = writeAgentYamlFiles(hubFolder, agentsDir, payload.agents || [], log);
|
|
15593
15639
|
const mdSlugs = /* @__PURE__ */ new Set();
|
|
15594
15640
|
for (const { slug, content } of agentFiles) {
|
|
15595
15641
|
mdSlugs.add(slug);
|
|
15596
|
-
|
|
15642
|
+
writeFileIfChanged(hubFolder, path15.join(agentsDir, `${slug}.md`), content, log);
|
|
15597
15643
|
}
|
|
15598
15644
|
const existingFiles = fs13.readdirSync(agentsDir);
|
|
15599
15645
|
for (const file of existingFiles) {
|
|
15600
15646
|
if (file.endsWith(".yaml")) {
|
|
15601
15647
|
const slug = file.slice(0, -5);
|
|
15602
15648
|
if (!yamlSlugs.has(slug)) {
|
|
15603
|
-
|
|
15649
|
+
const orphan = path15.join(agentsDir, file);
|
|
15650
|
+
fs13.unlinkSync(orphan);
|
|
15651
|
+
log.removed.push(path15.relative(hubFolder, orphan));
|
|
15604
15652
|
}
|
|
15605
15653
|
} else if (file.endsWith(".md")) {
|
|
15606
15654
|
const slug = file.slice(0, -3);
|
|
15607
15655
|
if (!mdSlugs.has(slug)) {
|
|
15608
|
-
|
|
15656
|
+
const orphan = path15.join(agentsDir, file);
|
|
15657
|
+
fs13.unlinkSync(orphan);
|
|
15658
|
+
log.removed.push(path15.relative(hubFolder, orphan));
|
|
15609
15659
|
}
|
|
15610
15660
|
}
|
|
15611
15661
|
}
|
|
15612
|
-
writeResourceFiles(hubFolder, payload.resources || []);
|
|
15613
|
-
writeEvalYamlFiles(hubFolder, payload.evals || []);
|
|
15614
|
-
writeJourneyYamlFiles(hubFolder, payload.journeys || []);
|
|
15662
|
+
writeResourceFiles(hubFolder, payload.resources || [], log);
|
|
15663
|
+
writeEvalYamlFiles(hubFolder, payload.evals || [], log);
|
|
15664
|
+
writeJourneyYamlFiles(hubFolder, payload.journeys || [], log);
|
|
15665
|
+
return log;
|
|
15615
15666
|
}
|
|
15616
15667
|
function setPreviewLabelInHubYaml(hubFolder, label) {
|
|
15617
15668
|
const yamlPath = resolveHubYamlPath(hubFolder);
|
|
@@ -15657,7 +15708,7 @@ function buildYamlPayload(payload) {
|
|
|
15657
15708
|
}
|
|
15658
15709
|
return result;
|
|
15659
15710
|
}
|
|
15660
|
-
function writeAgentYamlFiles(agentsDir, agents) {
|
|
15711
|
+
function writeAgentYamlFiles(hubFolder, agentsDir, agents, log) {
|
|
15661
15712
|
const slugs = /* @__PURE__ */ new Set();
|
|
15662
15713
|
for (const agent of agents) {
|
|
15663
15714
|
const slug = slugify(agent.name);
|
|
@@ -15665,7 +15716,7 @@ function writeAgentYamlFiles(agentsDir, agents) {
|
|
|
15665
15716
|
const entry = { ...agent };
|
|
15666
15717
|
delete entry.instructions;
|
|
15667
15718
|
const yamlContent = yaml5.dump(entry, YAML_DUMP_OPTIONS);
|
|
15668
|
-
|
|
15719
|
+
writeFileIfChanged(hubFolder, path15.join(agentsDir, `${slug}.yaml`), yamlContent, log);
|
|
15669
15720
|
}
|
|
15670
15721
|
return slugs;
|
|
15671
15722
|
}
|
|
@@ -15681,11 +15732,11 @@ function extractAgentFiles(payload) {
|
|
|
15681
15732
|
}
|
|
15682
15733
|
return files;
|
|
15683
15734
|
}
|
|
15684
|
-
function writeEvalYamlFiles(hubFolder, evals) {
|
|
15735
|
+
function writeEvalYamlFiles(hubFolder, evals, log) {
|
|
15685
15736
|
const evalsDir = path15.join(hubFolder, "evals");
|
|
15686
15737
|
if (evals.length === 0) {
|
|
15687
15738
|
if (fs13.existsSync(evalsDir)) {
|
|
15688
|
-
cleanEvalOrphans(evalsDir, /* @__PURE__ */ new Set());
|
|
15739
|
+
cleanEvalOrphans(hubFolder, evalsDir, /* @__PURE__ */ new Set(), log);
|
|
15689
15740
|
try {
|
|
15690
15741
|
if (fs13.readdirSync(evalsDir).length === 0) fs13.rmdirSync(evalsDir);
|
|
15691
15742
|
} catch {
|
|
@@ -15713,18 +15764,19 @@ function writeEvalYamlFiles(hubFolder, evals) {
|
|
|
15713
15764
|
}
|
|
15714
15765
|
}
|
|
15715
15766
|
const yamlContent = yaml5.dump(buildEvalYamlObject(evalEntry, slug), YAML_DUMP_OPTIONS);
|
|
15716
|
-
|
|
15767
|
+
writeFileIfChanged(hubFolder, targetPath, yamlContent, log);
|
|
15717
15768
|
writtenRelPaths.add(relPath);
|
|
15718
15769
|
}
|
|
15719
|
-
cleanEvalOrphans(evalsDir, writtenRelPaths);
|
|
15770
|
+
cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log);
|
|
15720
15771
|
}
|
|
15721
|
-
function cleanEvalOrphans(evalsDir, writtenRelPaths) {
|
|
15772
|
+
function cleanEvalOrphans(hubFolder, evalsDir, writtenRelPaths, log) {
|
|
15722
15773
|
const entries = fs13.readdirSync(evalsDir, { withFileTypes: true });
|
|
15723
15774
|
for (const entry of entries) {
|
|
15724
15775
|
const fullPath = path15.join(evalsDir, entry.name);
|
|
15725
15776
|
if (entry.isFile()) {
|
|
15726
15777
|
if (entry.name.endsWith(".yaml") && !writtenRelPaths.has(entry.name)) {
|
|
15727
15778
|
fs13.unlinkSync(fullPath);
|
|
15779
|
+
log.removed.push(path15.relative(hubFolder, fullPath));
|
|
15728
15780
|
}
|
|
15729
15781
|
continue;
|
|
15730
15782
|
}
|
|
@@ -15735,7 +15787,9 @@ function cleanEvalOrphans(evalsDir, writtenRelPaths) {
|
|
|
15735
15787
|
if (sub.isFile() && sub.name.endsWith(".yaml")) {
|
|
15736
15788
|
const relPath = `${setName}/${sub.name}`;
|
|
15737
15789
|
if (!writtenRelPaths.has(relPath)) {
|
|
15738
|
-
|
|
15790
|
+
const orphan = path15.join(fullPath, sub.name);
|
|
15791
|
+
fs13.unlinkSync(orphan);
|
|
15792
|
+
log.removed.push(path15.relative(hubFolder, orphan));
|
|
15739
15793
|
}
|
|
15740
15794
|
}
|
|
15741
15795
|
}
|
|
@@ -15776,11 +15830,11 @@ function buildJourneyYamlObject(journeyEntry, slug) {
|
|
|
15776
15830
|
}
|
|
15777
15831
|
return out;
|
|
15778
15832
|
}
|
|
15779
|
-
function writeJourneyYamlFiles(hubFolder, journeys) {
|
|
15833
|
+
function writeJourneyYamlFiles(hubFolder, journeys, log) {
|
|
15780
15834
|
const journeysDir = path15.join(hubFolder, "journeys");
|
|
15781
15835
|
if (journeys.length === 0) {
|
|
15782
15836
|
if (fs13.existsSync(journeysDir)) {
|
|
15783
|
-
cleanJourneyOrphans(journeysDir, /* @__PURE__ */ new Set());
|
|
15837
|
+
cleanJourneyOrphans(hubFolder, journeysDir, /* @__PURE__ */ new Set(), log);
|
|
15784
15838
|
try {
|
|
15785
15839
|
if (fs13.readdirSync(journeysDir).length === 0) fs13.rmdirSync(journeysDir);
|
|
15786
15840
|
} catch {
|
|
@@ -15797,33 +15851,37 @@ function writeJourneyYamlFiles(hubFolder, journeys) {
|
|
|
15797
15851
|
const slug = ensureUniqueSlug(slugify(journeyEntry.name), usedSlugs);
|
|
15798
15852
|
const fileName = `${slug}.yaml`;
|
|
15799
15853
|
const yamlContent = yaml5.dump(buildJourneyYamlObject(journeyEntry, slug), YAML_DUMP_OPTIONS);
|
|
15800
|
-
|
|
15854
|
+
writeFileIfChanged(hubFolder, path15.join(journeysDir, fileName), yamlContent, log);
|
|
15801
15855
|
writtenFiles.add(fileName);
|
|
15802
15856
|
}
|
|
15803
|
-
cleanJourneyOrphans(journeysDir, writtenFiles);
|
|
15857
|
+
cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log);
|
|
15804
15858
|
}
|
|
15805
|
-
function cleanJourneyOrphans(journeysDir, writtenFiles) {
|
|
15859
|
+
function cleanJourneyOrphans(hubFolder, journeysDir, writtenFiles, log) {
|
|
15806
15860
|
const entries = fs13.readdirSync(journeysDir, { withFileTypes: true });
|
|
15807
15861
|
for (const entry of entries) {
|
|
15808
15862
|
if (entry.isFile() && entry.name.endsWith(".yaml") && !writtenFiles.has(entry.name)) {
|
|
15809
|
-
|
|
15863
|
+
const orphan = path15.join(journeysDir, entry.name);
|
|
15864
|
+
fs13.unlinkSync(orphan);
|
|
15865
|
+
log.removed.push(path15.relative(hubFolder, orphan));
|
|
15810
15866
|
}
|
|
15811
15867
|
}
|
|
15812
15868
|
}
|
|
15813
|
-
function writeResourceFiles(hubFolder, resources) {
|
|
15869
|
+
function writeResourceFiles(hubFolder, resources, log) {
|
|
15814
15870
|
const resourcesDir = path15.join(hubFolder, "resources");
|
|
15815
15871
|
const currentSlugs = /* @__PURE__ */ new Set();
|
|
15816
15872
|
for (const resource of resources) {
|
|
15817
15873
|
const resSlug = slugify(resource.name);
|
|
15818
15874
|
currentSlugs.add(resSlug);
|
|
15819
15875
|
const resDir = path15.join(resourcesDir, resSlug);
|
|
15820
|
-
writeResourceFileTree(resDir, resource.files || [], hubFolder);
|
|
15876
|
+
writeResourceFileTree(resDir, resource.files || [], hubFolder, log);
|
|
15821
15877
|
}
|
|
15822
15878
|
if (fs13.existsSync(resourcesDir)) {
|
|
15823
15879
|
const existingDirs = fs13.readdirSync(resourcesDir, { withFileTypes: true });
|
|
15824
15880
|
for (const entry of existingDirs) {
|
|
15825
15881
|
if (entry.isDirectory() && !currentSlugs.has(entry.name)) {
|
|
15826
|
-
|
|
15882
|
+
const orphanDir = path15.join(resourcesDir, entry.name);
|
|
15883
|
+
fs13.rmSync(orphanDir, { recursive: true, force: true });
|
|
15884
|
+
log.removed.push(`${path15.relative(hubFolder, orphanDir)}/`);
|
|
15827
15885
|
}
|
|
15828
15886
|
}
|
|
15829
15887
|
}
|
|
@@ -15837,6 +15895,7 @@ var init_yaml_writer = __esm({
|
|
|
15837
15895
|
init_resource_files();
|
|
15838
15896
|
init_eval_attachments();
|
|
15839
15897
|
init_workspace_files();
|
|
15898
|
+
init_fs_safety();
|
|
15840
15899
|
YAML_DUMP_OPTIONS = {
|
|
15841
15900
|
lineWidth: -1,
|
|
15842
15901
|
// don't wrap lines
|
|
@@ -15859,22 +15918,28 @@ async function materializeHubFolder(hubFolder, payload, options = {}) {
|
|
|
15859
15918
|
}
|
|
15860
15919
|
materialized.add(payload);
|
|
15861
15920
|
const attachmentDownloads = rewriteEvalAttachmentsToLocalPaths(payload);
|
|
15862
|
-
writeHubFolder(hubFolder, payload, options);
|
|
15863
|
-
await downloadBinaryResourceFiles(hubFolder, payload);
|
|
15864
|
-
const
|
|
15865
|
-
return {
|
|
15921
|
+
const writeLog = writeHubFolder(hubFolder, payload, options);
|
|
15922
|
+
const resourceDownloads = await downloadBinaryResourceFiles(hubFolder, payload);
|
|
15923
|
+
const attachments = await downloadEvalAttachments(hubFolder, attachmentDownloads);
|
|
15924
|
+
return {
|
|
15925
|
+
attachmentsWritten: attachments.written,
|
|
15926
|
+
changed: [...writeLog.changed, ...resourceDownloads.changed, ...attachments.changed],
|
|
15927
|
+
removed: [...writeLog.removed, ...attachments.removed]
|
|
15928
|
+
};
|
|
15866
15929
|
}
|
|
15867
15930
|
async function downloadBinaryResourceFiles(hubFolder, payload) {
|
|
15868
15931
|
const resources = payload.resources || [];
|
|
15932
|
+
const log = { changed: [], removed: [] };
|
|
15869
15933
|
let downloadCount = 0;
|
|
15870
15934
|
for (const resource of resources) {
|
|
15871
15935
|
if (!resource.files) continue;
|
|
15872
15936
|
const resDir = path16.join(hubFolder, "resources", slugify(resource.name));
|
|
15873
|
-
downloadCount += await downloadBinaryFiles(resDir, resource.files, hubFolder);
|
|
15937
|
+
downloadCount += await downloadBinaryFiles(resDir, resource.files, hubFolder, log);
|
|
15874
15938
|
}
|
|
15875
15939
|
if (downloadCount > 0) {
|
|
15876
15940
|
console.log(`Downloaded ${downloadCount} binary resource file(s).`);
|
|
15877
15941
|
}
|
|
15942
|
+
return { changed: log.changed };
|
|
15878
15943
|
}
|
|
15879
15944
|
var materialized;
|
|
15880
15945
|
var init_hub_materializer = __esm({
|
|
@@ -15888,207 +15953,13 @@ var init_hub_materializer = __esm({
|
|
|
15888
15953
|
}
|
|
15889
15954
|
});
|
|
15890
15955
|
|
|
15891
|
-
// src/commands/pull.ts
|
|
15892
|
-
var pull_exports = {};
|
|
15893
|
-
__export(pull_exports, {
|
|
15894
|
-
connectionsEqual: () => connectionsEqual,
|
|
15895
|
-
pullCommand: () => pullCommand,
|
|
15896
|
-
resolveHubTarget: () => resolveHubTarget,
|
|
15897
|
-
writeProductionMirror: () => writeProductionMirror
|
|
15898
|
-
});
|
|
15899
|
-
import * as fs14 from "fs";
|
|
15900
|
-
import * as path17 from "path";
|
|
15901
|
-
function parseArgs4(args2) {
|
|
15902
|
-
let autoConfirm = false;
|
|
15903
|
-
let hubSelector;
|
|
15904
|
-
for (let i = 0; i < args2.length; i++) {
|
|
15905
|
-
const arg = args2[i];
|
|
15906
|
-
if (arg === "--yes" || arg === "-y") {
|
|
15907
|
-
autoConfirm = true;
|
|
15908
|
-
} else if (arg === "--hub" && args2[i + 1]) {
|
|
15909
|
-
hubSelector = args2[++i];
|
|
15910
|
-
}
|
|
15911
|
-
}
|
|
15912
|
-
return { autoConfirm, hubSelector };
|
|
15913
|
-
}
|
|
15914
|
-
function resolveHubTarget(workspaceDir, selector) {
|
|
15915
|
-
const wsLabel = hubsDirLabel(findGitRoot());
|
|
15916
|
-
const allHubs = scanWorkspaceHubs(workspaceDir);
|
|
15917
|
-
if (selector) {
|
|
15918
|
-
const match = allHubs.find(
|
|
15919
|
-
(h) => h.hubId === selector || path17.basename(h.hubFolder) === selector
|
|
15920
|
-
);
|
|
15921
|
-
if (match) return { hubId: match.hubId, hubFolder: match.hubFolder };
|
|
15922
|
-
if (UUID_RE2.test(selector)) return { hubId: selector, hubFolder: null };
|
|
15923
|
-
console.error(`No hub matching --hub ${selector} found in ${wsLabel}/. Pass a UUID for first-time pulls.`);
|
|
15924
|
-
process.exit(1);
|
|
15925
|
-
}
|
|
15926
|
-
const enclosing = findEnclosingHubFolder(workspaceDir);
|
|
15927
|
-
if (enclosing) return { hubId: enclosing.hubId, hubFolder: enclosing.hubFolder };
|
|
15928
|
-
const previewHubs = filterPreviewHubs(allHubs);
|
|
15929
|
-
if (previewHubs.length === 1) return { hubId: previewHubs[0].hubId, hubFolder: previewHubs[0].hubFolder };
|
|
15930
|
-
if (previewHubs.length === 0) {
|
|
15931
|
-
console.error(`No hub folders found in ${wsLabel}/. Pass --hub <uuid> to fetch a hub for the first time.`);
|
|
15932
|
-
process.exit(1);
|
|
15933
|
-
}
|
|
15934
|
-
console.error(`Multiple hubs found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
|
|
15935
|
-
for (const h of previewHubs) {
|
|
15936
|
-
console.error(` ${path17.basename(h.hubFolder)} (${h.hubId})`);
|
|
15937
|
-
}
|
|
15938
|
-
process.exit(1);
|
|
15939
|
-
}
|
|
15940
|
-
async function pullCommand(args2) {
|
|
15941
|
-
const { autoConfirm, hubSelector } = parseArgs4(args2);
|
|
15942
|
-
const repoConfig = requireRepoConfig();
|
|
15943
|
-
const { organization_id: organizationId } = repoConfig;
|
|
15944
|
-
const { config, accessToken } = await requireAuth();
|
|
15945
|
-
const client = new ApiClient({ apiUrl: config.api_url, accessToken });
|
|
15946
|
-
const workspaceDir = resolveWorkspaceDir();
|
|
15947
|
-
const gitRoot = findGitRoot();
|
|
15948
|
-
if (gitRoot) warnLayoutOnce(gitRoot);
|
|
15949
|
-
if (gitRoot) {
|
|
15950
|
-
for (const file of ensureWorkspaceFiles(gitRoot)) {
|
|
15951
|
-
console.error(`Created ${file}`);
|
|
15952
|
-
}
|
|
15953
|
-
}
|
|
15954
|
-
const { hubId, hubFolder: existingFolder } = resolveHubTarget(workspaceDir, hubSelector);
|
|
15955
|
-
console.log("Fetching hub configuration...");
|
|
15956
|
-
const payload = await client.pull(hubId, organizationId);
|
|
15957
|
-
if (payload.hub_environment === "production") {
|
|
15958
|
-
const folder = await writeProductionMirror(workspaceDir, payload);
|
|
15959
|
-
console.log(`Production hub mirrored (read-only) \u2192 ${folder}`);
|
|
15960
|
-
return;
|
|
15961
|
-
}
|
|
15962
|
-
assertHubMatchesBinding(hubId);
|
|
15963
|
-
let hubFolder = existingFolder;
|
|
15964
|
-
let wroteFiles = false;
|
|
15965
|
-
if (!hubFolder) {
|
|
15966
|
-
hubFolder = resolveHubFolder(
|
|
15967
|
-
workspaceDir,
|
|
15968
|
-
hubId,
|
|
15969
|
-
payload.hub.name,
|
|
15970
|
-
payload.hub_environment,
|
|
15971
|
-
payload.preview_label,
|
|
15972
|
-
payload.branch_name
|
|
15973
|
-
);
|
|
15974
|
-
fs14.mkdirSync(path17.dirname(hubFolder), { recursive: true });
|
|
15975
|
-
console.log("Writing hub configuration...");
|
|
15976
|
-
await materializeHubFolder(hubFolder, payload);
|
|
15977
|
-
const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
|
|
15978
|
-
console.log(`Hub configuration written to ${finalFolder}`);
|
|
15979
|
-
wroteFiles = true;
|
|
15980
|
-
} else {
|
|
15981
|
-
let action = "overwrite";
|
|
15982
|
-
try {
|
|
15983
|
-
const localPayload = parseHubFolder(hubFolder);
|
|
15984
|
-
const diffResult = await client.diff(hubId, prepareResourcePayload(localPayload, payload), "pull", organizationId);
|
|
15985
|
-
const connectionsChanged = !connectionsEqual(localPayload.connections, payload.connections);
|
|
15986
|
-
if (!diffResult.has_changes && !connectionsChanged) {
|
|
15987
|
-
action = "sync_metadata";
|
|
15988
|
-
} else {
|
|
15989
|
-
console.log("\nChanges to apply locally:");
|
|
15990
|
-
if (connectionsChanged) {
|
|
15991
|
-
console.log("**Connections:** updated");
|
|
15992
|
-
}
|
|
15993
|
-
printDiff(diffResult.summary);
|
|
15994
|
-
if (!autoConfirm) {
|
|
15995
|
-
const ok = await confirm("Apply these changes?");
|
|
15996
|
-
if (!ok) {
|
|
15997
|
-
console.log("Cancelled.");
|
|
15998
|
-
return;
|
|
15999
|
-
}
|
|
16000
|
-
}
|
|
16001
|
-
action = "apply";
|
|
16002
|
-
}
|
|
16003
|
-
} catch {
|
|
16004
|
-
action = "overwrite";
|
|
16005
|
-
}
|
|
16006
|
-
if (action === "overwrite") console.log("Writing hub configuration...");
|
|
16007
|
-
await materializeHubFolder(hubFolder, payload);
|
|
16008
|
-
const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
|
|
16009
|
-
wroteFiles = true;
|
|
16010
|
-
if (action === "sync_metadata") {
|
|
16011
|
-
if (finalFolder === hubFolder) {
|
|
16012
|
-
console.log("Metadata synced \u2014 no config changes.");
|
|
16013
|
-
} else {
|
|
16014
|
-
console.log("Metadata synced; folder renamed.");
|
|
16015
|
-
}
|
|
16016
|
-
} else {
|
|
16017
|
-
console.log(`Hub configuration written to ${finalFolder}`);
|
|
16018
|
-
}
|
|
16019
|
-
}
|
|
16020
|
-
if (wroteFiles) autoBindIfUnbound(hubId);
|
|
16021
|
-
if (payload.production_hub_id) {
|
|
16022
|
-
await mirrorLinkedProduction(client, workspaceDir, payload.production_hub_id, organizationId);
|
|
16023
|
-
}
|
|
16024
|
-
}
|
|
16025
|
-
async function writeProductionMirror(workspaceDir, prodPayload) {
|
|
16026
|
-
const folder = resolveHubFolder(workspaceDir, prodPayload.hub_id, prodPayload.hub.name, "production", null, null);
|
|
16027
|
-
fs14.mkdirSync(path17.dirname(folder), { recursive: true });
|
|
16028
|
-
await materializeHubFolder(folder, prodPayload, { seedAgentContext: false });
|
|
16029
|
-
const finalFolder = autoRenameHubFolder(folder, prodPayload.hub.name, "production", prodPayload.hub_id, null, null);
|
|
16030
|
-
prependMirrorMarker(finalFolder, prodPayload.hub_id);
|
|
16031
|
-
return finalFolder;
|
|
16032
|
-
}
|
|
16033
|
-
async function mirrorLinkedProduction(client, workspaceDir, productionHubId, organizationId) {
|
|
16034
|
-
try {
|
|
16035
|
-
const prodPayload = await client.pull(productionHubId, organizationId);
|
|
16036
|
-
const folder = await writeProductionMirror(workspaceDir, prodPayload);
|
|
16037
|
-
console.log(`Mirrored production hub \u2192 ${folder} (read-only)`);
|
|
16038
|
-
} catch (err) {
|
|
16039
|
-
console.warn(`Warning: could not mirror production hub (${err instanceof Error ? err.message : String(err)}). Preview pull is unaffected.`);
|
|
16040
|
-
}
|
|
16041
|
-
}
|
|
16042
|
-
function prependMirrorMarker(hubFolder, productionHubId) {
|
|
16043
|
-
const hubYaml = path17.join(hubFolder, "hub.yaml");
|
|
16044
|
-
try {
|
|
16045
|
-
const content = fs14.readFileSync(hubYaml, "utf-8");
|
|
16046
|
-
if (content.startsWith(MIRROR_MARKER_PREFIX)) return;
|
|
16047
|
-
const marker = `${MIRROR_MARKER_PREFIX} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
|
|
16048
|
-
`;
|
|
16049
|
-
fs14.writeFileSync(hubYaml, marker + content, "utf-8");
|
|
16050
|
-
} catch {
|
|
16051
|
-
}
|
|
16052
|
-
}
|
|
16053
|
-
function connectionsEqual(a, b) {
|
|
16054
|
-
const listA = a || [];
|
|
16055
|
-
const listB = b || [];
|
|
16056
|
-
if (listA.length !== listB.length) return false;
|
|
16057
|
-
const key = (c) => c.id || `${c.name}|${c.type}|${c.service || ""}`;
|
|
16058
|
-
const setA = new Set(listA.map(key));
|
|
16059
|
-
const setB = new Set(listB.map(key));
|
|
16060
|
-
if (setA.size !== setB.size) return false;
|
|
16061
|
-
for (const k of setA) {
|
|
16062
|
-
if (!setB.has(k)) return false;
|
|
16063
|
-
}
|
|
16064
|
-
return true;
|
|
16065
|
-
}
|
|
16066
|
-
var MIRROR_MARKER_PREFIX;
|
|
16067
|
-
var init_pull = __esm({
|
|
16068
|
-
"src/commands/pull.ts"() {
|
|
16069
|
-
"use strict";
|
|
16070
|
-
init_auth();
|
|
16071
|
-
init_api_client();
|
|
16072
|
-
init_parser();
|
|
16073
|
-
init_diff_display();
|
|
16074
|
-
init_utils();
|
|
16075
|
-
init_resource_files();
|
|
16076
|
-
init_hub_materializer();
|
|
16077
|
-
init_workspace();
|
|
16078
|
-
init_layout();
|
|
16079
|
-
init_workspace_files();
|
|
16080
|
-
init_repo_config();
|
|
16081
|
-
init_hub_binding();
|
|
16082
|
-
MIRROR_MARKER_PREFIX = "# Read-only mirror of production hub";
|
|
16083
|
-
}
|
|
16084
|
-
});
|
|
16085
|
-
|
|
16086
15956
|
// src/commands/push.ts
|
|
16087
15957
|
var push_exports = {};
|
|
16088
15958
|
__export(push_exports, {
|
|
16089
15959
|
autoRenameAgentFiles: () => autoRenameAgentFiles,
|
|
16090
15960
|
createAndPushNewHub: () => createAndPushNewHub,
|
|
16091
15961
|
printErrors: () => printErrors,
|
|
15962
|
+
printLocalFileChanges: () => printLocalFileChanges,
|
|
16092
15963
|
printSyncResult: () => printSyncResult,
|
|
16093
15964
|
printWarnings: () => printWarnings,
|
|
16094
15965
|
pushCommand: () => pushCommand,
|
|
@@ -16097,10 +15968,10 @@ __export(push_exports, {
|
|
|
16097
15968
|
shouldWarnIgnoredPreviewLabel: () => shouldWarnIgnoredPreviewLabel,
|
|
16098
15969
|
syncAfterPush: () => syncAfterPush
|
|
16099
15970
|
});
|
|
16100
|
-
import * as
|
|
16101
|
-
import * as
|
|
15971
|
+
import * as fs14 from "fs";
|
|
15972
|
+
import * as path17 from "path";
|
|
16102
15973
|
import * as yaml6 from "js-yaml";
|
|
16103
|
-
function
|
|
15974
|
+
function parseArgs4(args2) {
|
|
16104
15975
|
let autoConfirm = false;
|
|
16105
15976
|
let hubSelector;
|
|
16106
15977
|
let label;
|
|
@@ -16190,14 +16061,30 @@ function printErrors(errors) {
|
|
|
16190
16061
|
console.error(` \x1B[31m! ${error}\x1B[0m`);
|
|
16191
16062
|
}
|
|
16192
16063
|
}
|
|
16064
|
+
function printLocalFileChanges(delta) {
|
|
16065
|
+
if (delta.changed.length === 0 && delta.removed.length === 0) {
|
|
16066
|
+
console.log("Local files already in sync.");
|
|
16067
|
+
return;
|
|
16068
|
+
}
|
|
16069
|
+
console.log("Local files updated from server:");
|
|
16070
|
+
const emit = (paths, sigil) => {
|
|
16071
|
+
const sorted = [...paths].sort();
|
|
16072
|
+
for (const p of sorted.slice(0, LOCAL_CHANGE_LIST_CAP)) console.log(` ${sigil} ${p}`);
|
|
16073
|
+
if (sorted.length > LOCAL_CHANGE_LIST_CAP) {
|
|
16074
|
+
console.log(` \u2026and ${sorted.length - LOCAL_CHANGE_LIST_CAP} more ${sigil === "-" ? "removed" : "changed"}`);
|
|
16075
|
+
}
|
|
16076
|
+
};
|
|
16077
|
+
emit(delta.removed, "-");
|
|
16078
|
+
emit(delta.changed, "~");
|
|
16079
|
+
}
|
|
16193
16080
|
async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, remoteConfig) {
|
|
16194
|
-
const agentsDir =
|
|
16081
|
+
const agentsDir = path17.join(hubFolder, "agents");
|
|
16195
16082
|
let agentsWithIds = [];
|
|
16196
|
-
if (
|
|
16197
|
-
const yamlFiles =
|
|
16083
|
+
if (fs14.existsSync(agentsDir)) {
|
|
16084
|
+
const yamlFiles = fs14.readdirSync(agentsDir).filter((f) => f.endsWith(".yaml"));
|
|
16198
16085
|
for (const file of yamlFiles) {
|
|
16199
16086
|
try {
|
|
16200
|
-
const content =
|
|
16087
|
+
const content = fs14.readFileSync(path17.join(agentsDir, file), "utf-8");
|
|
16201
16088
|
const agent = yaml6.load(content);
|
|
16202
16089
|
if (agent?.id && agent.name) {
|
|
16203
16090
|
agentsWithIds.push({ id: agent.id, name: agent.name });
|
|
@@ -16210,7 +16097,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
16210
16097
|
if (agentsWithIds.length === 0) {
|
|
16211
16098
|
const yamlPath = resolveHubYamlPath(hubFolder);
|
|
16212
16099
|
if (!yamlPath) return;
|
|
16213
|
-
const yamlContent =
|
|
16100
|
+
const yamlContent = fs14.readFileSync(yamlPath, "utf-8");
|
|
16214
16101
|
const config = yaml6.load(yamlContent);
|
|
16215
16102
|
agentsWithIds = (config.agents || []).filter((a) => !!a.id && !!a.name);
|
|
16216
16103
|
}
|
|
@@ -16242,18 +16129,18 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
16242
16129
|
}
|
|
16243
16130
|
}
|
|
16244
16131
|
if (renames.length === 0) return;
|
|
16245
|
-
if (!
|
|
16246
|
-
for (const file of
|
|
16132
|
+
if (!fs14.existsSync(agentsDir)) return;
|
|
16133
|
+
for (const file of fs14.readdirSync(agentsDir)) {
|
|
16247
16134
|
if (file.startsWith("__rename_temp_") && (file.endsWith(".md") || file.endsWith(".yaml"))) {
|
|
16248
16135
|
console.warn(` Warning: removing orphaned temp file agents/${file}`);
|
|
16249
|
-
|
|
16136
|
+
fs14.unlinkSync(path17.join(agentsDir, file));
|
|
16250
16137
|
}
|
|
16251
16138
|
}
|
|
16252
16139
|
const renameFileIfExists = (dir, oldName, newName) => {
|
|
16253
|
-
const oldPath =
|
|
16254
|
-
const newPath =
|
|
16255
|
-
if (!
|
|
16256
|
-
|
|
16140
|
+
const oldPath = path17.join(dir, oldName);
|
|
16141
|
+
const newPath = path17.join(dir, newName);
|
|
16142
|
+
if (!fs14.existsSync(oldPath)) return false;
|
|
16143
|
+
fs14.renameSync(oldPath, newPath);
|
|
16257
16144
|
return true;
|
|
16258
16145
|
};
|
|
16259
16146
|
const oldSlugs = new Set(renames.map((r) => r.oldSlug));
|
|
@@ -16286,9 +16173,9 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
16286
16173
|
}
|
|
16287
16174
|
} else {
|
|
16288
16175
|
for (const { oldSlug, newSlug } of renames) {
|
|
16289
|
-
const hasOldFile = extensions.some((ext) =>
|
|
16176
|
+
const hasOldFile = extensions.some((ext) => fs14.existsSync(path17.join(agentsDir, `${oldSlug}${ext}`)));
|
|
16290
16177
|
if (!hasOldFile) continue;
|
|
16291
|
-
const hasNewFile = extensions.some((ext) =>
|
|
16178
|
+
const hasNewFile = extensions.some((ext) => fs14.existsSync(path17.join(agentsDir, `${newSlug}${ext}`)));
|
|
16292
16179
|
if (hasNewFile) {
|
|
16293
16180
|
console.warn(` Warning: skipping rename agents/${oldSlug}.* \u2192 agents/${newSlug}.* (target already exists)`);
|
|
16294
16181
|
continue;
|
|
@@ -16303,7 +16190,7 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
16303
16190
|
if (completedRenames.length === 0) return;
|
|
16304
16191
|
const mainYamlPath = resolveHubYamlPath(hubFolder);
|
|
16305
16192
|
if (mainYamlPath) {
|
|
16306
|
-
const mainYamlContent =
|
|
16193
|
+
const mainYamlContent = fs14.readFileSync(mainYamlPath, "utf-8");
|
|
16307
16194
|
const substitutionMap = /* @__PURE__ */ new Map();
|
|
16308
16195
|
for (const { oldSlug, newSlug } of completedRenames) {
|
|
16309
16196
|
substitutionMap.set(`agents/${oldSlug}.md`, `agents/${newSlug}.md`);
|
|
@@ -16314,16 +16201,16 @@ async function autoRenameAgentFiles(client, hubId, hubFolder, organizationId, re
|
|
|
16314
16201
|
(_match, prefix, pathMatch) => `${prefix}${substitutionMap.get(pathMatch) ?? pathMatch}`
|
|
16315
16202
|
);
|
|
16316
16203
|
if (updatedYaml !== mainYamlContent) {
|
|
16317
|
-
|
|
16318
|
-
console.log(` Updated instructions paths in ${
|
|
16204
|
+
fs14.writeFileSync(mainYamlPath, updatedYaml, "utf-8");
|
|
16205
|
+
console.log(` Updated instructions paths in ${path17.basename(mainYamlPath)}`);
|
|
16319
16206
|
}
|
|
16320
16207
|
}
|
|
16321
16208
|
}
|
|
16322
16209
|
async function syncAfterPush(client, hubId, hubFolder, organizationId) {
|
|
16323
16210
|
try {
|
|
16324
16211
|
const remoteConfig = await client.pull(hubId, organizationId);
|
|
16325
|
-
await materializeHubFolder(hubFolder, remoteConfig);
|
|
16326
|
-
|
|
16212
|
+
const delta = await materializeHubFolder(hubFolder, remoteConfig);
|
|
16213
|
+
printLocalFileChanges(delta);
|
|
16327
16214
|
const finalFolder = autoRenameHubFolder(hubFolder, remoteConfig.hub.name, remoteConfig.hub_environment, hubId, remoteConfig.preview_label, remoteConfig.branch_name);
|
|
16328
16215
|
if (finalFolder !== hubFolder) {
|
|
16329
16216
|
console.log(`Hub folder is now ${finalFolder}`);
|
|
@@ -16383,7 +16270,7 @@ async function pushSingleHub(client, hubId, hubFolder, autoConfirm, organization
|
|
|
16383
16270
|
function selectExistingHub(workspaceDir, allHubs, selector, wsLabel) {
|
|
16384
16271
|
if (selector) {
|
|
16385
16272
|
const match = allHubs.find(
|
|
16386
|
-
(h) => h.hubId === selector ||
|
|
16273
|
+
(h) => h.hubId === selector || path17.basename(h.hubFolder) === selector
|
|
16387
16274
|
);
|
|
16388
16275
|
if (!match) {
|
|
16389
16276
|
console.error(`No hub matching --hub ${selector} found in ${wsLabel}/.`);
|
|
@@ -16426,7 +16313,7 @@ New hub: "${newHub.hubName}" (${hubType})`);
|
|
|
16426
16313
|
process.exit(1);
|
|
16427
16314
|
}
|
|
16428
16315
|
console.log(`Hub created: ${createdHub.hub_name} (${hubId})`);
|
|
16429
|
-
const content =
|
|
16316
|
+
const content = fs14.readFileSync(hubYamlPath, "utf-8");
|
|
16430
16317
|
const hasVersion = content.match(/^version:\s/m);
|
|
16431
16318
|
let updated;
|
|
16432
16319
|
if (hasVersion) {
|
|
@@ -16442,7 +16329,7 @@ hub_id: "${hubId}"
|
|
|
16442
16329
|
hub_environment: preview
|
|
16443
16330
|
${content}`;
|
|
16444
16331
|
}
|
|
16445
|
-
|
|
16332
|
+
fs14.writeFileSync(hubYamlPath, updated, "utf-8");
|
|
16446
16333
|
autoBindIfUnbound(hubId);
|
|
16447
16334
|
await pushSingleHub(client, hubId, newHub.hubFolder, opts.autoConfirm, opts.organizationId, { skipAgentRename: true });
|
|
16448
16335
|
}
|
|
@@ -16451,7 +16338,7 @@ function reportUnresolvedPushTarget(reason, existingHubs, newHubs, selector, wsL
|
|
|
16451
16338
|
if (existingHubs.length > 0) {
|
|
16452
16339
|
console.error(`No pushable hub found in ${wsLabel}/ \u2014 only read-only production mirror folder(s). Edit the linked preview hub, pull one, or create a new hub with \`wayai create\`:`);
|
|
16453
16340
|
for (const h of existingHubs) {
|
|
16454
|
-
console.error(` ${
|
|
16341
|
+
console.error(` ${path17.basename(h.hubFolder)} (${h.hubId}, production mirror)`);
|
|
16455
16342
|
}
|
|
16456
16343
|
} else {
|
|
16457
16344
|
console.error(`No hub folders found. Create hub files in ${wsLabel}/<hub>/hub.yaml with \`hub: { name: ... }\` and run \`wayai push\` (or \`wayai create\`).`);
|
|
@@ -16464,15 +16351,15 @@ function reportUnresolvedPushTarget(reason, existingHubs, newHubs, selector, wsL
|
|
|
16464
16351
|
console.error(`Multiple hub folders found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
|
|
16465
16352
|
}
|
|
16466
16353
|
for (const h of existingHubs) {
|
|
16467
|
-
console.error(` ${
|
|
16354
|
+
console.error(` ${path17.basename(h.hubFolder)} (${h.hubId})`);
|
|
16468
16355
|
}
|
|
16469
16356
|
for (const h of newHubs) {
|
|
16470
|
-
console.error(` ${
|
|
16357
|
+
console.error(` ${path17.basename(h.hubFolder)} (new \u2014 "${h.hubName}")`);
|
|
16471
16358
|
}
|
|
16472
16359
|
process.exit(1);
|
|
16473
16360
|
}
|
|
16474
16361
|
async function pushCommand(args2) {
|
|
16475
|
-
const { autoConfirm, hubSelector, label } =
|
|
16362
|
+
const { autoConfirm, hubSelector, label } = parseArgs4(args2);
|
|
16476
16363
|
const repoConfig = requireRepoConfig();
|
|
16477
16364
|
const { organization_id: organizationId } = repoConfig;
|
|
16478
16365
|
const { config, accessToken } = await requireAuth();
|
|
@@ -16486,7 +16373,7 @@ async function pushCommand(args2) {
|
|
|
16486
16373
|
console.error(`Created ${file}`);
|
|
16487
16374
|
}
|
|
16488
16375
|
}
|
|
16489
|
-
if (!
|
|
16376
|
+
if (!fs14.existsSync(workspaceDir)) {
|
|
16490
16377
|
console.error(`No ${wsLabel}/ directory found. Run \`wayai pull\` first or create hub files in ${wsLabel}/<hub>/hub.yaml.`);
|
|
16491
16378
|
process.exit(1);
|
|
16492
16379
|
}
|
|
@@ -16505,14 +16392,15 @@ async function pushCommand(args2) {
|
|
|
16505
16392
|
if (label) {
|
|
16506
16393
|
console.warn("Note: --label is only used when creating a new hub. To change an existing hub's label, use `wayai relabel`.");
|
|
16507
16394
|
}
|
|
16508
|
-
console.log(`Target hub: ${
|
|
16509
|
-
assertHubMatchesBinding(existing.hubId,
|
|
16395
|
+
console.log(`Target hub: ${path17.basename(existing.hubFolder)} (${existing.hubId})`);
|
|
16396
|
+
assertHubMatchesBinding(existing.hubId, path17.basename(existing.hubFolder));
|
|
16510
16397
|
await pushSingleHub(client, existing.hubId, existing.hubFolder, autoConfirm, organizationId);
|
|
16511
16398
|
return;
|
|
16512
16399
|
}
|
|
16513
16400
|
assertNoBindingBlocksHubCreation(resolution.target.hub.hubName);
|
|
16514
16401
|
await createAndPushNewHub(client, resolution.target.hub, { autoConfirm, label, organizationId });
|
|
16515
16402
|
}
|
|
16403
|
+
var LOCAL_CHANGE_LIST_CAP;
|
|
16516
16404
|
var init_push = __esm({
|
|
16517
16405
|
"src/commands/push.ts"() {
|
|
16518
16406
|
"use strict";
|
|
@@ -16528,6 +16416,204 @@ var init_push = __esm({
|
|
|
16528
16416
|
init_workspace_files();
|
|
16529
16417
|
init_repo_config();
|
|
16530
16418
|
init_hub_binding();
|
|
16419
|
+
LOCAL_CHANGE_LIST_CAP = 20;
|
|
16420
|
+
}
|
|
16421
|
+
});
|
|
16422
|
+
|
|
16423
|
+
// src/commands/pull.ts
|
|
16424
|
+
var pull_exports = {};
|
|
16425
|
+
__export(pull_exports, {
|
|
16426
|
+
connectionsEqual: () => connectionsEqual,
|
|
16427
|
+
pullCommand: () => pullCommand,
|
|
16428
|
+
resolveHubTarget: () => resolveHubTarget,
|
|
16429
|
+
writeProductionMirror: () => writeProductionMirror
|
|
16430
|
+
});
|
|
16431
|
+
import * as fs15 from "fs";
|
|
16432
|
+
import * as path18 from "path";
|
|
16433
|
+
function parseArgs5(args2) {
|
|
16434
|
+
let autoConfirm = false;
|
|
16435
|
+
let hubSelector;
|
|
16436
|
+
for (let i = 0; i < args2.length; i++) {
|
|
16437
|
+
const arg = args2[i];
|
|
16438
|
+
if (arg === "--yes" || arg === "-y") {
|
|
16439
|
+
autoConfirm = true;
|
|
16440
|
+
} else if (arg === "--hub" && args2[i + 1]) {
|
|
16441
|
+
hubSelector = args2[++i];
|
|
16442
|
+
}
|
|
16443
|
+
}
|
|
16444
|
+
return { autoConfirm, hubSelector };
|
|
16445
|
+
}
|
|
16446
|
+
function resolveHubTarget(workspaceDir, selector) {
|
|
16447
|
+
const wsLabel = hubsDirLabel(findGitRoot());
|
|
16448
|
+
const allHubs = scanWorkspaceHubs(workspaceDir);
|
|
16449
|
+
if (selector) {
|
|
16450
|
+
const match = allHubs.find(
|
|
16451
|
+
(h) => h.hubId === selector || path18.basename(h.hubFolder) === selector
|
|
16452
|
+
);
|
|
16453
|
+
if (match) return { hubId: match.hubId, hubFolder: match.hubFolder };
|
|
16454
|
+
if (UUID_RE2.test(selector)) return { hubId: selector, hubFolder: null };
|
|
16455
|
+
console.error(`No hub matching --hub ${selector} found in ${wsLabel}/. Pass a UUID for first-time pulls.`);
|
|
16456
|
+
process.exit(1);
|
|
16457
|
+
}
|
|
16458
|
+
const enclosing = findEnclosingHubFolder(workspaceDir);
|
|
16459
|
+
if (enclosing) return { hubId: enclosing.hubId, hubFolder: enclosing.hubFolder };
|
|
16460
|
+
const previewHubs = filterPreviewHubs(allHubs);
|
|
16461
|
+
if (previewHubs.length === 1) return { hubId: previewHubs[0].hubId, hubFolder: previewHubs[0].hubFolder };
|
|
16462
|
+
if (previewHubs.length === 0) {
|
|
16463
|
+
console.error(`No hub folders found in ${wsLabel}/. Pass --hub <uuid> to fetch a hub for the first time.`);
|
|
16464
|
+
process.exit(1);
|
|
16465
|
+
}
|
|
16466
|
+
console.error(`Multiple hubs found in ${wsLabel}/. Pass --hub <uuid|folder-name> to choose, or run from inside a hub folder:`);
|
|
16467
|
+
for (const h of previewHubs) {
|
|
16468
|
+
console.error(` ${path18.basename(h.hubFolder)} (${h.hubId})`);
|
|
16469
|
+
}
|
|
16470
|
+
process.exit(1);
|
|
16471
|
+
}
|
|
16472
|
+
async function pullCommand(args2) {
|
|
16473
|
+
const { autoConfirm, hubSelector } = parseArgs5(args2);
|
|
16474
|
+
const repoConfig = requireRepoConfig();
|
|
16475
|
+
const { organization_id: organizationId } = repoConfig;
|
|
16476
|
+
const { config, accessToken } = await requireAuth();
|
|
16477
|
+
const client = new ApiClient({ apiUrl: config.api_url, accessToken });
|
|
16478
|
+
const workspaceDir = resolveWorkspaceDir();
|
|
16479
|
+
const gitRoot = findGitRoot();
|
|
16480
|
+
if (gitRoot) warnLayoutOnce(gitRoot);
|
|
16481
|
+
if (gitRoot) {
|
|
16482
|
+
for (const file of ensureWorkspaceFiles(gitRoot)) {
|
|
16483
|
+
console.error(`Created ${file}`);
|
|
16484
|
+
}
|
|
16485
|
+
}
|
|
16486
|
+
const { hubId, hubFolder: existingFolder } = resolveHubTarget(workspaceDir, hubSelector);
|
|
16487
|
+
console.log("Fetching hub configuration...");
|
|
16488
|
+
const payload = await client.pull(hubId, organizationId);
|
|
16489
|
+
if (payload.hub_environment === "production") {
|
|
16490
|
+
const folder = await writeProductionMirror(workspaceDir, payload);
|
|
16491
|
+
console.log(`Production hub mirrored (read-only) \u2192 ${folder}`);
|
|
16492
|
+
return;
|
|
16493
|
+
}
|
|
16494
|
+
assertHubMatchesBinding(hubId);
|
|
16495
|
+
let hubFolder = existingFolder;
|
|
16496
|
+
let wroteFiles = false;
|
|
16497
|
+
if (!hubFolder) {
|
|
16498
|
+
hubFolder = resolveHubFolder(
|
|
16499
|
+
workspaceDir,
|
|
16500
|
+
hubId,
|
|
16501
|
+
payload.hub.name,
|
|
16502
|
+
payload.hub_environment,
|
|
16503
|
+
payload.preview_label,
|
|
16504
|
+
payload.branch_name
|
|
16505
|
+
);
|
|
16506
|
+
fs15.mkdirSync(path18.dirname(hubFolder), { recursive: true });
|
|
16507
|
+
console.log("Writing hub configuration...");
|
|
16508
|
+
await materializeHubFolder(hubFolder, payload);
|
|
16509
|
+
const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
|
|
16510
|
+
console.log(`Hub configuration written to ${finalFolder}`);
|
|
16511
|
+
wroteFiles = true;
|
|
16512
|
+
} else {
|
|
16513
|
+
let action = "overwrite";
|
|
16514
|
+
try {
|
|
16515
|
+
const localPayload = parseHubFolder(hubFolder);
|
|
16516
|
+
const diffResult = await client.diff(hubId, prepareResourcePayload(localPayload, payload), "pull", organizationId);
|
|
16517
|
+
const connectionsChanged = !connectionsEqual(localPayload.connections, payload.connections);
|
|
16518
|
+
if (!diffResult.has_changes && !connectionsChanged) {
|
|
16519
|
+
action = "sync_metadata";
|
|
16520
|
+
} else {
|
|
16521
|
+
console.log("\nChanges to apply locally:");
|
|
16522
|
+
if (connectionsChanged) {
|
|
16523
|
+
console.log("**Connections:** updated");
|
|
16524
|
+
}
|
|
16525
|
+
printDiff(diffResult.summary);
|
|
16526
|
+
if (!autoConfirm) {
|
|
16527
|
+
const ok = await confirm("Apply these changes?");
|
|
16528
|
+
if (!ok) {
|
|
16529
|
+
console.log("Cancelled.");
|
|
16530
|
+
return;
|
|
16531
|
+
}
|
|
16532
|
+
}
|
|
16533
|
+
action = "apply";
|
|
16534
|
+
}
|
|
16535
|
+
} catch {
|
|
16536
|
+
action = "overwrite";
|
|
16537
|
+
}
|
|
16538
|
+
if (action === "overwrite") console.log("Writing hub configuration...");
|
|
16539
|
+
const delta = await materializeHubFolder(hubFolder, payload);
|
|
16540
|
+
const finalFolder = autoRenameHubFolder(hubFolder, payload.hub.name, payload.hub_environment, payload.hub_id, payload.preview_label, payload.branch_name);
|
|
16541
|
+
wroteFiles = true;
|
|
16542
|
+
if (action === "sync_metadata") {
|
|
16543
|
+
if (finalFolder === hubFolder) {
|
|
16544
|
+
printLocalFileChanges(delta);
|
|
16545
|
+
} else {
|
|
16546
|
+
console.log("Metadata synced; folder renamed.");
|
|
16547
|
+
}
|
|
16548
|
+
} else {
|
|
16549
|
+
console.log(`Hub configuration written to ${finalFolder}`);
|
|
16550
|
+
printLocalFileChanges(delta);
|
|
16551
|
+
}
|
|
16552
|
+
}
|
|
16553
|
+
if (wroteFiles) autoBindIfUnbound(hubId);
|
|
16554
|
+
if (payload.production_hub_id) {
|
|
16555
|
+
await mirrorLinkedProduction(client, workspaceDir, payload.production_hub_id, organizationId);
|
|
16556
|
+
}
|
|
16557
|
+
}
|
|
16558
|
+
async function writeProductionMirror(workspaceDir, prodPayload) {
|
|
16559
|
+
const folder = resolveHubFolder(workspaceDir, prodPayload.hub_id, prodPayload.hub.name, "production", null, null);
|
|
16560
|
+
fs15.mkdirSync(path18.dirname(folder), { recursive: true });
|
|
16561
|
+
await materializeHubFolder(folder, prodPayload, { seedAgentContext: false });
|
|
16562
|
+
const finalFolder = autoRenameHubFolder(folder, prodPayload.hub.name, "production", prodPayload.hub_id, null, null);
|
|
16563
|
+
prependMirrorMarker(finalFolder, prodPayload.hub_id);
|
|
16564
|
+
return finalFolder;
|
|
16565
|
+
}
|
|
16566
|
+
async function mirrorLinkedProduction(client, workspaceDir, productionHubId, organizationId) {
|
|
16567
|
+
try {
|
|
16568
|
+
const prodPayload = await client.pull(productionHubId, organizationId);
|
|
16569
|
+
const folder = await writeProductionMirror(workspaceDir, prodPayload);
|
|
16570
|
+
console.log(`Mirrored production hub \u2192 ${folder} (read-only)`);
|
|
16571
|
+
} catch (err) {
|
|
16572
|
+
console.warn(`Warning: could not mirror production hub (${err instanceof Error ? err.message : String(err)}). Preview pull is unaffected.`);
|
|
16573
|
+
}
|
|
16574
|
+
}
|
|
16575
|
+
function prependMirrorMarker(hubFolder, productionHubId) {
|
|
16576
|
+
const hubYaml = path18.join(hubFolder, "hub.yaml");
|
|
16577
|
+
try {
|
|
16578
|
+
const content = fs15.readFileSync(hubYaml, "utf-8");
|
|
16579
|
+
if (content.startsWith(MIRROR_MARKER_PREFIX)) return;
|
|
16580
|
+
const marker = `${MIRROR_MARKER_PREFIX} ${productionHubId}. Edits are ignored; push is blocked. Edit the linked preview hub instead.
|
|
16581
|
+
`;
|
|
16582
|
+
fs15.writeFileSync(hubYaml, marker + content, "utf-8");
|
|
16583
|
+
} catch {
|
|
16584
|
+
}
|
|
16585
|
+
}
|
|
16586
|
+
function connectionsEqual(a, b) {
|
|
16587
|
+
const listA = a || [];
|
|
16588
|
+
const listB = b || [];
|
|
16589
|
+
if (listA.length !== listB.length) return false;
|
|
16590
|
+
const key = (c) => c.id || `${c.name}|${c.type}|${c.service || ""}`;
|
|
16591
|
+
const setA = new Set(listA.map(key));
|
|
16592
|
+
const setB = new Set(listB.map(key));
|
|
16593
|
+
if (setA.size !== setB.size) return false;
|
|
16594
|
+
for (const k of setA) {
|
|
16595
|
+
if (!setB.has(k)) return false;
|
|
16596
|
+
}
|
|
16597
|
+
return true;
|
|
16598
|
+
}
|
|
16599
|
+
var MIRROR_MARKER_PREFIX;
|
|
16600
|
+
var init_pull = __esm({
|
|
16601
|
+
"src/commands/pull.ts"() {
|
|
16602
|
+
"use strict";
|
|
16603
|
+
init_auth();
|
|
16604
|
+
init_api_client();
|
|
16605
|
+
init_parser();
|
|
16606
|
+
init_diff_display();
|
|
16607
|
+
init_utils();
|
|
16608
|
+
init_resource_files();
|
|
16609
|
+
init_hub_materializer();
|
|
16610
|
+
init_push();
|
|
16611
|
+
init_workspace();
|
|
16612
|
+
init_layout();
|
|
16613
|
+
init_workspace_files();
|
|
16614
|
+
init_repo_config();
|
|
16615
|
+
init_hub_binding();
|
|
16616
|
+
MIRROR_MARKER_PREFIX = "# Read-only mirror of production hub";
|
|
16531
16617
|
}
|
|
16532
16618
|
});
|
|
16533
16619
|
|
|
@@ -16745,8 +16831,9 @@ async function replicateCommand(args2) {
|
|
|
16745
16831
|
payload.preview_label,
|
|
16746
16832
|
payload.branch_name
|
|
16747
16833
|
);
|
|
16834
|
+
const folderPreExisted = fs17.existsSync(hubFolder);
|
|
16748
16835
|
fs17.mkdirSync(path20.dirname(hubFolder), { recursive: true });
|
|
16749
|
-
await materializeHubFolder(hubFolder, payload);
|
|
16836
|
+
const delta = await materializeHubFolder(hubFolder, payload);
|
|
16750
16837
|
hubFolder = autoRenameHubFolder(
|
|
16751
16838
|
hubFolder,
|
|
16752
16839
|
payload.hub.name,
|
|
@@ -16756,6 +16843,7 @@ async function replicateCommand(args2) {
|
|
|
16756
16843
|
payload.branch_name
|
|
16757
16844
|
);
|
|
16758
16845
|
autoBindIfUnbound(previewHubId);
|
|
16846
|
+
if (folderPreExisted) printLocalFileChanges(delta);
|
|
16759
16847
|
console.log(`Preview written to ${path20.basename(hubFolder)}`);
|
|
16760
16848
|
console.log(` Switch to it with: wayai use ${path20.basename(hubFolder)}`);
|
|
16761
16849
|
}
|
|
@@ -16766,6 +16854,7 @@ var init_replicate = __esm({
|
|
|
16766
16854
|
init_api_client();
|
|
16767
16855
|
init_hub_materializer();
|
|
16768
16856
|
init_pull();
|
|
16857
|
+
init_push();
|
|
16769
16858
|
init_workspace();
|
|
16770
16859
|
init_layout();
|
|
16771
16860
|
init_repo_config();
|
|
@@ -22865,7 +22954,7 @@ var init_update = __esm({
|
|
|
22865
22954
|
|
|
22866
22955
|
// src/index.ts
|
|
22867
22956
|
init_sentry();
|
|
22868
|
-
import { readFileSync as
|
|
22957
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
22869
22958
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22870
22959
|
import { dirname as dirname9, join as join28 } from "path";
|
|
22871
22960
|
|
|
@@ -23047,7 +23136,7 @@ Run \`wayai admin skill install\` to update.`);
|
|
|
23047
23136
|
|
|
23048
23137
|
// src/index.ts
|
|
23049
23138
|
var __dirname = dirname9(fileURLToPath2(import.meta.url));
|
|
23050
|
-
var pkg = JSON.parse(
|
|
23139
|
+
var pkg = JSON.parse(readFileSync21(join28(__dirname, "..", "package.json"), "utf-8"));
|
|
23051
23140
|
var [, , command, ...args] = process.argv;
|
|
23052
23141
|
var isBackgroundRefresh = command === REFRESH_COMMAND;
|
|
23053
23142
|
if (!isBackgroundRefresh) initSentry(command, pkg.version);
|