agentsmesh 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -0
- package/dist/canonical.js +199 -147
- package/dist/canonical.js.map +1 -1
- package/dist/cli.js +232 -185
- package/dist/engine.js +213 -147
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +286 -207
- package/dist/index.js.map +1 -1
- package/dist/{init-YKxF2zpQ.d.ts → init-B0aI-g8W.d.ts} +1 -1
- package/dist/lessons.d.ts +2 -2
- package/dist/lessons.js +73 -60
- package/dist/lessons.js.map +1 -1
- package/dist/targets.js +111 -59
- package/dist/targets.js.map +1 -1
- package/package.json +1 -1
package/dist/canonical.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join, basename, dirname, relative, extname, resolve, posix, win32 } from 'path';
|
|
2
|
-
import { access, readdir, readFile,
|
|
2
|
+
import { access, readdir, readFile, rm, mkdir, stat, lstat, unlink, writeFile, rename, chmod, realpath, mkdtemp, cp } from 'fs/promises';
|
|
3
3
|
import { setTimeout } from 'timers/promises';
|
|
4
4
|
import { constants, existsSync, realpathSync, statSync } from 'fs';
|
|
5
5
|
import { stringify, parse } from 'yaml';
|
|
@@ -1392,7 +1392,7 @@ async function importEmbeddedSkills(projectRoot, skillsDir, fromTool, results, n
|
|
|
1392
1392
|
toPath: `${AB_SKILLS}/${entry.name}/SKILL.md`,
|
|
1393
1393
|
feature: "skills"
|
|
1394
1394
|
});
|
|
1395
|
-
const sourceFiles = await
|
|
1395
|
+
const sourceFiles = await readDirRecursiveNoSymlinks(sourceSkillDir);
|
|
1396
1396
|
for (const sourcePath of sourceFiles) {
|
|
1397
1397
|
if (sourcePath === sourceSkillFile) continue;
|
|
1398
1398
|
const relativePath = relative(sourceSkillDir, sourcePath).replace(/\\/g, "/");
|
|
@@ -2340,7 +2340,7 @@ function matchesExtension(path, extensions) {
|
|
|
2340
2340
|
return extensions.some((extension) => path.endsWith(extension));
|
|
2341
2341
|
}
|
|
2342
2342
|
async function importFileDirectory(opts) {
|
|
2343
|
-
const files = await
|
|
2343
|
+
const files = await readDirRecursiveNoSymlinks(opts.srcDir);
|
|
2344
2344
|
const matchedFiles = files.filter((path) => matchesExtension(path, opts.extensions));
|
|
2345
2345
|
const results = [];
|
|
2346
2346
|
for (const srcPath of matchedFiles) {
|
|
@@ -6654,7 +6654,7 @@ var init_settings_helpers2 = __esm({
|
|
|
6654
6654
|
async function importClaudeSkills(projectRoot, results, normalize) {
|
|
6655
6655
|
const skillsBaseDir = join(projectRoot, CLAUDE_SKILLS_DIR);
|
|
6656
6656
|
const destBase = join(projectRoot, CLAUDE_CANONICAL_SKILLS_DIR);
|
|
6657
|
-
const allFiles = await
|
|
6657
|
+
const allFiles = await readDirRecursiveNoSymlinks(skillsBaseDir);
|
|
6658
6658
|
const skillMdFiles = allFiles.filter((f) => f.endsWith("SKILL.md"));
|
|
6659
6659
|
for (const skillMdPath of skillMdFiles) {
|
|
6660
6660
|
const skillDir = dirname(skillMdPath);
|
|
@@ -6673,7 +6673,7 @@ async function importClaudeSkills(projectRoot, results, normalize) {
|
|
|
6673
6673
|
`);
|
|
6674
6674
|
continue;
|
|
6675
6675
|
}
|
|
6676
|
-
const skillFiles = await
|
|
6676
|
+
const skillFiles = await readDirRecursiveNoSymlinks(skillDir);
|
|
6677
6677
|
for (const filePath of skillFiles) {
|
|
6678
6678
|
const fileContent = await readFileSafe(filePath);
|
|
6679
6679
|
if (fileContent === null) continue;
|
|
@@ -7298,7 +7298,7 @@ async function importClineRules(projectRoot, results, normalize) {
|
|
|
7298
7298
|
feature: "rules"
|
|
7299
7299
|
});
|
|
7300
7300
|
} else {
|
|
7301
|
-
const ruleFiles = await
|
|
7301
|
+
const ruleFiles = await readDirRecursiveNoSymlinks(clineRulesPath);
|
|
7302
7302
|
const mdFiles = ruleFiles.filter((f) => f.endsWith(".md") && !f.includes("/workflows/")).sort();
|
|
7303
7303
|
const first = mdFiles[0];
|
|
7304
7304
|
if (first) {
|
|
@@ -7362,27 +7362,40 @@ var init_importer_rules = __esm({
|
|
|
7362
7362
|
init_constants8();
|
|
7363
7363
|
}
|
|
7364
7364
|
});
|
|
7365
|
+
function toStringRecord2(raw) {
|
|
7366
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
7367
|
+
return Object.fromEntries(
|
|
7368
|
+
Object.entries(raw).filter((entry) => typeof entry[1] === "string")
|
|
7369
|
+
);
|
|
7370
|
+
}
|
|
7365
7371
|
function mapClineServerToCanonical(raw) {
|
|
7366
7372
|
if (!raw || typeof raw !== "object") return null;
|
|
7367
7373
|
const obj = raw;
|
|
7368
|
-
const
|
|
7369
|
-
|
|
7370
|
-
const
|
|
7371
|
-
const args = Array.isArray(obj.args) ? obj.args.filter((x) => typeof x === "string") : [];
|
|
7372
|
-
const envRaw = obj.env;
|
|
7373
|
-
const env = envRaw !== null && typeof envRaw === "object" && !Array.isArray(envRaw) ? Object.fromEntries(
|
|
7374
|
-
Object.entries(envRaw).filter(
|
|
7375
|
-
(entry) => typeof entry[1] === "string"
|
|
7376
|
-
)
|
|
7377
|
-
) : {};
|
|
7374
|
+
const transport = typeof obj.type === "string" ? obj.type : void 0;
|
|
7375
|
+
const transportType = typeof obj.transportType === "string" ? obj.transportType : void 0;
|
|
7376
|
+
const env = toStringRecord2(obj.env);
|
|
7378
7377
|
const description = typeof obj.description === "string" ? obj.description : void 0;
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7378
|
+
const command = typeof obj.command === "string" ? obj.command : "";
|
|
7379
|
+
if (command) {
|
|
7380
|
+
const args = Array.isArray(obj.args) ? obj.args.filter((x) => typeof x === "string") : [];
|
|
7381
|
+
return {
|
|
7382
|
+
...description !== void 0 && { description },
|
|
7383
|
+
type: transport ?? transportType ?? "stdio",
|
|
7384
|
+
command,
|
|
7385
|
+
args,
|
|
7386
|
+
env
|
|
7387
|
+
};
|
|
7388
|
+
}
|
|
7389
|
+
if (typeof obj.url === "string") {
|
|
7390
|
+
return {
|
|
7391
|
+
...description !== void 0 && { description },
|
|
7392
|
+
type: transport ?? transportType ?? "http",
|
|
7393
|
+
url: obj.url,
|
|
7394
|
+
headers: toStringRecord2(obj.headers),
|
|
7395
|
+
env
|
|
7396
|
+
};
|
|
7397
|
+
}
|
|
7398
|
+
return null;
|
|
7386
7399
|
}
|
|
7387
7400
|
async function importClineMcp(projectRoot, results) {
|
|
7388
7401
|
const candidatePaths = [CLINE_MCP_SETTINGS, CLINE_MCP_SETTINGS_LEGACY].map(
|
|
@@ -7456,7 +7469,7 @@ var init_reserved = __esm({
|
|
|
7456
7469
|
}
|
|
7457
7470
|
});
|
|
7458
7471
|
async function readNativeSkill(skillDir) {
|
|
7459
|
-
const allFiles = await
|
|
7472
|
+
const allFiles = await readDirRecursiveNoSymlinks(skillDir).catch(() => []);
|
|
7460
7473
|
const entries = [];
|
|
7461
7474
|
for (const absPath of allFiles) {
|
|
7462
7475
|
const relPath = relative(skillDir, absPath).replace(/\\/g, "/");
|
|
@@ -7522,7 +7535,7 @@ async function importFlatSkill(skillName, srcPath, content, options) {
|
|
|
7522
7535
|
async function findDirectorySkills(skillsDir) {
|
|
7523
7536
|
const skills = /* @__PURE__ */ new Map();
|
|
7524
7537
|
try {
|
|
7525
|
-
const allFiles = await
|
|
7538
|
+
const allFiles = await readDirRecursiveNoSymlinks(skillsDir);
|
|
7526
7539
|
const skillMdFiles = allFiles.filter((f) => basename(f) === "SKILL.md");
|
|
7527
7540
|
for (const skillMdPath of skillMdFiles) {
|
|
7528
7541
|
const skillDir = dirname(skillMdPath);
|
|
@@ -7653,7 +7666,7 @@ function extractMeta(content, key) {
|
|
|
7653
7666
|
return match?.[1]?.trim() ?? null;
|
|
7654
7667
|
}
|
|
7655
7668
|
async function loadHooksFromDir(dir, hooks) {
|
|
7656
|
-
const files = await
|
|
7669
|
+
const files = await readDirRecursiveNoSymlinks(dir).catch(() => []);
|
|
7657
7670
|
const shFiles = files.filter((f) => basename(f).endsWith(".sh") && dirname(f) === dir);
|
|
7658
7671
|
for (const srcPath of shFiles) {
|
|
7659
7672
|
const content = await readFileSafe(srcPath);
|
|
@@ -8388,7 +8401,7 @@ async function importCodexAgentsFromToml(projectRoot, results, normalize) {
|
|
|
8388
8401
|
const agentsPath = join(projectRoot, CODEX_AGENTS_DIR);
|
|
8389
8402
|
const agentsDestDir = join(projectRoot, CODEX_CANONICAL_AGENTS_DIR);
|
|
8390
8403
|
try {
|
|
8391
|
-
const agentFiles = await
|
|
8404
|
+
const agentFiles = await readDirRecursiveNoSymlinks(agentsPath);
|
|
8392
8405
|
const tomlFiles = agentFiles.filter((f) => f.endsWith(".toml"));
|
|
8393
8406
|
for (const srcPath of tomlFiles) {
|
|
8394
8407
|
const content = await readFileSafe(srcPath);
|
|
@@ -8484,7 +8497,7 @@ async function importCodexNonRootRuleFiles(projectRoot, destDir, normalize) {
|
|
|
8484
8497
|
const results = [];
|
|
8485
8498
|
const codexRulesPath = join(projectRoot, CODEX_RULES_DIR);
|
|
8486
8499
|
try {
|
|
8487
|
-
const ruleFiles = await
|
|
8500
|
+
const ruleFiles = await readDirRecursiveNoSymlinks(codexRulesPath);
|
|
8488
8501
|
const mdFiles = ruleFiles.filter((f) => f.endsWith(".md"));
|
|
8489
8502
|
for (const srcPath of mdFiles) {
|
|
8490
8503
|
const content = await readFileSafe(srcPath);
|
|
@@ -8641,7 +8654,7 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
|
|
|
8641
8654
|
}
|
|
8642
8655
|
async function importInstructionMirrors(projectRoot, destDir, results, normalize) {
|
|
8643
8656
|
try {
|
|
8644
|
-
const files = await
|
|
8657
|
+
const files = await readDirRecursiveNoSymlinks(join(projectRoot, CODEX_INSTRUCTIONS_DIR));
|
|
8645
8658
|
const instructionFiles = files.filter((file) => file.endsWith(".md"));
|
|
8646
8659
|
const instructionsRoot = join(projectRoot, CODEX_INSTRUCTIONS_DIR);
|
|
8647
8660
|
for (const srcPath of instructionFiles) {
|
|
@@ -9087,19 +9100,31 @@ function readMcpServers(content, extension) {
|
|
|
9087
9100
|
for (const [name, value] of Object.entries(rawServers)) {
|
|
9088
9101
|
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
9089
9102
|
const server = value;
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9103
|
+
const description = typeof server.description === "string" ? server.description : void 0;
|
|
9104
|
+
if (typeof server.command === "string") {
|
|
9105
|
+
servers[name] = {
|
|
9106
|
+
type: typeof server.type === "string" ? server.type : "stdio",
|
|
9107
|
+
command: server.command,
|
|
9108
|
+
args: toStringArray5(server.args),
|
|
9109
|
+
env: toStringRecord(server.env),
|
|
9110
|
+
description
|
|
9111
|
+
};
|
|
9112
|
+
continue;
|
|
9113
|
+
}
|
|
9114
|
+
if (typeof server.url === "string") {
|
|
9115
|
+
servers[name] = {
|
|
9116
|
+
type: typeof server.type === "string" ? server.type : "http",
|
|
9117
|
+
url: server.url,
|
|
9118
|
+
headers: toStringRecord(server.headers),
|
|
9119
|
+
env: toStringRecord(server.env),
|
|
9120
|
+
description
|
|
9121
|
+
};
|
|
9122
|
+
}
|
|
9098
9123
|
}
|
|
9099
9124
|
return servers;
|
|
9100
9125
|
}
|
|
9101
9126
|
async function importMcp2(projectRoot, results) {
|
|
9102
|
-
const files = (await
|
|
9127
|
+
const files = (await readDirRecursiveNoSymlinks(join(projectRoot, CONTINUE_MCP_DIR))).filter(
|
|
9103
9128
|
(file) => [".json", ".yaml", ".yml"].includes(extname(file))
|
|
9104
9129
|
);
|
|
9105
9130
|
const merged = {};
|
|
@@ -9759,7 +9784,7 @@ function extractWrapperCommand(content) {
|
|
|
9759
9784
|
}
|
|
9760
9785
|
async function importHooks(projectRoot, results) {
|
|
9761
9786
|
const hooksDir = join(projectRoot, COPILOT_HOOKS_DIR);
|
|
9762
|
-
const allFiles = await
|
|
9787
|
+
const allFiles = await readDirRecursiveNoSymlinks(hooksDir).catch(() => []);
|
|
9763
9788
|
const jsonFiles = allFiles.filter((file) => file.endsWith(".json"));
|
|
9764
9789
|
const hooks = {};
|
|
9765
9790
|
for (const srcPath of jsonFiles) {
|
|
@@ -9795,7 +9820,7 @@ async function importHooks(projectRoot, results) {
|
|
|
9795
9820
|
}
|
|
9796
9821
|
}
|
|
9797
9822
|
const legacyDir = join(projectRoot, COPILOT_LEGACY_HOOKS_DIR);
|
|
9798
|
-
const legacyFiles = await
|
|
9823
|
+
const legacyFiles = await readDirRecursiveNoSymlinks(legacyDir).catch(() => []);
|
|
9799
9824
|
const shFiles = legacyFiles.filter(
|
|
9800
9825
|
(file) => dirname(file) === legacyDir && /^[^-]+-\d+\.sh$/i.test(basename(file))
|
|
9801
9826
|
);
|
|
@@ -9872,7 +9897,7 @@ var init_importer10 = __esm({
|
|
|
9872
9897
|
}
|
|
9873
9898
|
});
|
|
9874
9899
|
async function skillNamesFromNativeSkillDir(scanRoot) {
|
|
9875
|
-
const files = await
|
|
9900
|
+
const files = await readDirRecursiveNoSymlinks(scanRoot);
|
|
9876
9901
|
const names = /* @__PURE__ */ new Set();
|
|
9877
9902
|
for (const f of files) {
|
|
9878
9903
|
if (basename(f) === "SKILL.md") {
|
|
@@ -9894,7 +9919,7 @@ var init_native_skill_scan = __esm({
|
|
|
9894
9919
|
async function inferCopilotPickFromPath(repoRoot, posixPath) {
|
|
9895
9920
|
const scan = join(repoRoot, ...posixPath.split("/"));
|
|
9896
9921
|
if (posixPath.startsWith(COPILOT_PROMPTS_DIR)) {
|
|
9897
|
-
const files = await
|
|
9922
|
+
const files = await readDirRecursiveNoSymlinks(scan);
|
|
9898
9923
|
const commands = [
|
|
9899
9924
|
...new Set(
|
|
9900
9925
|
files.filter((f) => f.toLowerCase().endsWith(".prompt.md")).map((f) => basename(f, ".prompt.md"))
|
|
@@ -9903,7 +9928,7 @@ async function inferCopilotPickFromPath(repoRoot, posixPath) {
|
|
|
9903
9928
|
return commands.length ? { commands } : {};
|
|
9904
9929
|
}
|
|
9905
9930
|
if (posixPath.startsWith(".github/copilot") && !posixPath.includes("copilot-instructions.md")) {
|
|
9906
|
-
const files = await
|
|
9931
|
+
const files = await readDirRecursiveNoSymlinks(scan);
|
|
9907
9932
|
const rules = [
|
|
9908
9933
|
...new Set(
|
|
9909
9934
|
files.filter((f) => f.includes(".instructions.md")).map((f) => basename(f).replace(/\.instructions\.md$/i, ""))
|
|
@@ -9912,7 +9937,7 @@ async function inferCopilotPickFromPath(repoRoot, posixPath) {
|
|
|
9912
9937
|
return rules.length ? { rules } : {};
|
|
9913
9938
|
}
|
|
9914
9939
|
if (posixPath.startsWith(".github/instructions")) {
|
|
9915
|
-
const files = await
|
|
9940
|
+
const files = await readDirRecursiveNoSymlinks(scan);
|
|
9916
9941
|
const names = /* @__PURE__ */ new Set();
|
|
9917
9942
|
for (const f of files) {
|
|
9918
9943
|
const b = basename(f);
|
|
@@ -9928,7 +9953,7 @@ async function inferCopilotPickFromPath(repoRoot, posixPath) {
|
|
|
9928
9953
|
return skills.length ? { skills } : {};
|
|
9929
9954
|
}
|
|
9930
9955
|
if (posixPath.startsWith(".github/agents")) {
|
|
9931
|
-
const files = await
|
|
9956
|
+
const files = await readDirRecursiveNoSymlinks(scan);
|
|
9932
9957
|
const agents = [
|
|
9933
9958
|
...new Set(
|
|
9934
9959
|
files.filter((f) => f.toLowerCase().endsWith(".agent.md")).map((f) => basename(f, ".agent.md"))
|
|
@@ -11476,7 +11501,7 @@ async function importSkills3(projectRoot, results, normalize, skillsRelDir = CUR
|
|
|
11476
11501
|
for (const [skillName, skillDir] of directorySkills) {
|
|
11477
11502
|
await importDirectorySkill(skillName, skillDir, options);
|
|
11478
11503
|
}
|
|
11479
|
-
const allFiles = await
|
|
11504
|
+
const allFiles = await readDirRecursiveNoSymlinks(skillsDir).catch(() => []);
|
|
11480
11505
|
const mdFiles = allFiles.filter((f) => f.endsWith(".md"));
|
|
11481
11506
|
const handledPaths = new Set(
|
|
11482
11507
|
Array.from(directorySkills.values()).flatMap(
|
|
@@ -11514,11 +11539,11 @@ async function hasGlobalCursorArtifacts(projectRoot) {
|
|
|
11514
11539
|
const stat8 = await readFileSafe(p);
|
|
11515
11540
|
if (stat8 !== null && stat8.trim() !== "") return true;
|
|
11516
11541
|
}
|
|
11517
|
-
const skillFiles = await
|
|
11542
|
+
const skillFiles = await readDirRecursiveNoSymlinks(join(projectRoot, CURSOR_SKILLS_DIR));
|
|
11518
11543
|
if (skillFiles.some((f) => f.endsWith(".md"))) return true;
|
|
11519
|
-
const agentFiles = await
|
|
11544
|
+
const agentFiles = await readDirRecursiveNoSymlinks(join(projectRoot, CURSOR_AGENTS_DIR));
|
|
11520
11545
|
if (agentFiles.some((f) => f.endsWith(".md"))) return true;
|
|
11521
|
-
const commandFiles = await
|
|
11546
|
+
const commandFiles = await readDirRecursiveNoSymlinks(join(projectRoot, CURSOR_COMMANDS_DIR));
|
|
11522
11547
|
if (commandFiles.some((f) => f.endsWith(".md"))) return true;
|
|
11523
11548
|
return false;
|
|
11524
11549
|
}
|
|
@@ -13106,7 +13131,7 @@ async function importGeminiPolicies(projectRoot) {
|
|
|
13106
13131
|
const policiesDir = join(projectRoot, GEMINI_POLICIES_DIR);
|
|
13107
13132
|
let policyFiles;
|
|
13108
13133
|
try {
|
|
13109
|
-
policyFiles = await
|
|
13134
|
+
policyFiles = await readDirRecursiveNoSymlinks(policiesDir);
|
|
13110
13135
|
} catch {
|
|
13111
13136
|
return results;
|
|
13112
13137
|
}
|
|
@@ -13205,7 +13230,7 @@ var init_importer_strip = __esm({
|
|
|
13205
13230
|
});
|
|
13206
13231
|
async function importGeminiSkillsAndAgents(projectRoot, results, normalize) {
|
|
13207
13232
|
const geminiSkillsPath = join(projectRoot, GEMINI_SKILLS_DIR);
|
|
13208
|
-
const skillDirs = await
|
|
13233
|
+
const skillDirs = await readDirRecursiveNoSymlinks(geminiSkillsPath);
|
|
13209
13234
|
const skillMdFiles = skillDirs.filter((f) => basename(f) === "SKILL.md");
|
|
13210
13235
|
for (const srcPath of skillMdFiles) {
|
|
13211
13236
|
const content = await readFileSafe(srcPath);
|
|
@@ -13244,7 +13269,7 @@ async function importGeminiSkillsAndAgents(projectRoot, results, normalize) {
|
|
|
13244
13269
|
toPath: `${GEMINI_CANONICAL_SKILLS_DIR}/${skillName}/SKILL.md`,
|
|
13245
13270
|
feature: "skills"
|
|
13246
13271
|
});
|
|
13247
|
-
const allSkillFiles = await
|
|
13272
|
+
const allSkillFiles = await readDirRecursiveNoSymlinks(dirname(srcPath));
|
|
13248
13273
|
for (const absPath of allSkillFiles) {
|
|
13249
13274
|
if (absPath === srcPath) continue;
|
|
13250
13275
|
const supportContent = await readFileSafe(absPath);
|
|
@@ -13263,7 +13288,7 @@ async function importGeminiSkillsAndAgents(projectRoot, results, normalize) {
|
|
|
13263
13288
|
}
|
|
13264
13289
|
const geminiAgentsPath = join(projectRoot, GEMINI_AGENTS_DIR);
|
|
13265
13290
|
try {
|
|
13266
|
-
const agentFiles = await
|
|
13291
|
+
const agentFiles = await readDirRecursiveNoSymlinks(geminiAgentsPath);
|
|
13267
13292
|
const agentMdFiles = agentFiles.filter((f) => f.endsWith(".md"));
|
|
13268
13293
|
for (const srcPath of agentMdFiles) {
|
|
13269
13294
|
const content = await readFileSafe(srcPath);
|
|
@@ -13396,7 +13421,7 @@ function isUnderGeminiCommands(pathInRepoPosix) {
|
|
|
13396
13421
|
async function inferGeminiCommandNamesFromFiles(repoRoot, pathInRepoPosix) {
|
|
13397
13422
|
const commandsRoot = join(repoRoot, ...GEMINI_COMMANDS_DIR.split("/"));
|
|
13398
13423
|
const scanDir = join(repoRoot, ...pathInRepoPosix.split("/"));
|
|
13399
|
-
const files = await
|
|
13424
|
+
const files = await readDirRecursiveNoSymlinks(scanDir);
|
|
13400
13425
|
const names = [];
|
|
13401
13426
|
for (const f of files) {
|
|
13402
13427
|
if (!/\.(toml|md)$/i.test(f)) continue;
|
|
@@ -15608,7 +15633,7 @@ async function importNonRootRules(projectRoot, results, normalize) {
|
|
|
15608
15633
|
}
|
|
15609
15634
|
async function importHooks2(projectRoot, results) {
|
|
15610
15635
|
const hooks = {};
|
|
15611
|
-
for (const absPath of await
|
|
15636
|
+
for (const absPath of await readDirRecursiveNoSymlinks(join(projectRoot, KIRO_HOOKS_DIR))) {
|
|
15612
15637
|
if (!absPath.endsWith(".kiro.hook")) continue;
|
|
15613
15638
|
const parsed = parseKiroHookFile(await readFileSafe(absPath) ?? "");
|
|
15614
15639
|
if (!parsed) continue;
|
|
@@ -15960,7 +15985,7 @@ var init_generator24 = __esm({
|
|
|
15960
15985
|
init_constants19();
|
|
15961
15986
|
}
|
|
15962
15987
|
});
|
|
15963
|
-
function
|
|
15988
|
+
function toStringRecord3(value) {
|
|
15964
15989
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
15965
15990
|
const out2 = {};
|
|
15966
15991
|
for (const [k, v] of Object.entries(value)) {
|
|
@@ -15986,8 +16011,8 @@ function parseOpenCodeMcp(content) {
|
|
|
15986
16011
|
out2[name] = {
|
|
15987
16012
|
type: "url",
|
|
15988
16013
|
url: entry.url,
|
|
15989
|
-
headers:
|
|
15990
|
-
env:
|
|
16014
|
+
headers: toStringRecord3(entry.headers),
|
|
16015
|
+
env: toStringRecord3(entry.environment),
|
|
15991
16016
|
...typeof entry.description === "string" ? { description: entry.description } : {}
|
|
15992
16017
|
};
|
|
15993
16018
|
continue;
|
|
@@ -16001,7 +16026,7 @@ function parseOpenCodeMcp(content) {
|
|
|
16001
16026
|
type: "stdio",
|
|
16002
16027
|
command,
|
|
16003
16028
|
args,
|
|
16004
|
-
env:
|
|
16029
|
+
env: toStringRecord3(entry.environment),
|
|
16005
16030
|
...typeof entry.description === "string" ? { description: entry.description } : {}
|
|
16006
16031
|
};
|
|
16007
16032
|
}
|
|
@@ -18823,7 +18848,7 @@ function toStringArray8(value) {
|
|
|
18823
18848
|
}
|
|
18824
18849
|
async function importWorkflows(projectRoot, results, normalize) {
|
|
18825
18850
|
const workflowsDir = join(projectRoot, WINDSURF_WORKFLOWS_DIR);
|
|
18826
|
-
const workflowFiles = await
|
|
18851
|
+
const workflowFiles = await readDirRecursiveNoSymlinks(workflowsDir);
|
|
18827
18852
|
const workflowMdFiles = workflowFiles.filter((f) => f.endsWith(".md"));
|
|
18828
18853
|
const destCommandsDir = join(projectRoot, WINDSURF_CANONICAL_COMMANDS_DIR);
|
|
18829
18854
|
for (const srcPath of workflowMdFiles) {
|
|
@@ -19900,6 +19925,100 @@ function redactUrlSecrets(message) {
|
|
|
19900
19925
|
}
|
|
19901
19926
|
);
|
|
19902
19927
|
}
|
|
19928
|
+
function gitProtocolOptIns() {
|
|
19929
|
+
const on = (v) => v === "1" || v === "true";
|
|
19930
|
+
return {
|
|
19931
|
+
http: on(process.env.AGENTSMESH_ALLOW_INSECURE_GIT),
|
|
19932
|
+
file: on(process.env.AGENTSMESH_ALLOW_LOCAL_GIT)
|
|
19933
|
+
};
|
|
19934
|
+
}
|
|
19935
|
+
function isAllowedGitProtocol(url) {
|
|
19936
|
+
let parsed;
|
|
19937
|
+
try {
|
|
19938
|
+
parsed = new URL(url);
|
|
19939
|
+
} catch {
|
|
19940
|
+
return false;
|
|
19941
|
+
}
|
|
19942
|
+
const { http, file } = gitProtocolOptIns();
|
|
19943
|
+
const allowed = ["https:", "ssh:"];
|
|
19944
|
+
if (http) allowed.push("http:");
|
|
19945
|
+
if (file) allowed.push("file:");
|
|
19946
|
+
return allowed.includes(parsed.protocol);
|
|
19947
|
+
}
|
|
19948
|
+
function gitAllowProtocolEnv() {
|
|
19949
|
+
const { http, file } = gitProtocolOptIns();
|
|
19950
|
+
const protos = ["https", "ssh"];
|
|
19951
|
+
if (http) protos.push("http");
|
|
19952
|
+
if (file) protos.push("file");
|
|
19953
|
+
return protos.join(":");
|
|
19954
|
+
}
|
|
19955
|
+
function assertAllowedGitUrl(url) {
|
|
19956
|
+
if (isAllowedGitProtocol(url)) return;
|
|
19957
|
+
throw new Error(
|
|
19958
|
+
`agentsmesh refuses a git remote with a disallowed transport: "${redactUrlSecrets(url)}". Allowed: https, ssh. Set AGENTSMESH_ALLOW_INSECURE_GIT=1 to permit http, AGENTSMESH_ALLOW_LOCAL_GIT=1 to permit file.`
|
|
19959
|
+
);
|
|
19960
|
+
}
|
|
19961
|
+
function splitSourceRef(source, prefix, defaultRef) {
|
|
19962
|
+
if (!source.startsWith(prefix)) return null;
|
|
19963
|
+
const rest = source.slice(prefix.length).trim();
|
|
19964
|
+
if (!rest) return null;
|
|
19965
|
+
const refIdx = rest.lastIndexOf("@");
|
|
19966
|
+
if (refIdx < 0) return [rest, defaultRef];
|
|
19967
|
+
const slug = rest.slice(0, refIdx).trim();
|
|
19968
|
+
const ref = rest.slice(refIdx + 1).trim();
|
|
19969
|
+
if (!slug || !ref) return null;
|
|
19970
|
+
return [slug, ref];
|
|
19971
|
+
}
|
|
19972
|
+
function parseGithubSource(source) {
|
|
19973
|
+
const parts = splitSourceRef(source, "github:", "latest");
|
|
19974
|
+
if (!parts) return null;
|
|
19975
|
+
const [slug, tag] = parts;
|
|
19976
|
+
const slash = slug.indexOf("/");
|
|
19977
|
+
if (slash < 0) return null;
|
|
19978
|
+
const org = slug.slice(0, slash).trim();
|
|
19979
|
+
const repo = slug.slice(slash + 1).trim();
|
|
19980
|
+
if (!org || !repo || !tag) return null;
|
|
19981
|
+
return { org, repo, tag };
|
|
19982
|
+
}
|
|
19983
|
+
function parseGitlabSource(source) {
|
|
19984
|
+
const parts = splitSourceRef(source, "gitlab:");
|
|
19985
|
+
if (!parts) return null;
|
|
19986
|
+
const [slug, ref] = parts;
|
|
19987
|
+
const slash = slug.lastIndexOf("/");
|
|
19988
|
+
if (slash < 0) return null;
|
|
19989
|
+
const namespace = slug.slice(0, slash).trim();
|
|
19990
|
+
const project31 = slug.slice(slash + 1).trim();
|
|
19991
|
+
if (!namespace || !project31) return null;
|
|
19992
|
+
return {
|
|
19993
|
+
namespace,
|
|
19994
|
+
project: project31,
|
|
19995
|
+
ref,
|
|
19996
|
+
cloneUrl: `https://gitlab.com/${namespace}/${project31}.git`
|
|
19997
|
+
};
|
|
19998
|
+
}
|
|
19999
|
+
function parseGitSource(source) {
|
|
20000
|
+
if (!source.startsWith("git+")) return null;
|
|
20001
|
+
const rest = source.slice(4).trim();
|
|
20002
|
+
if (!rest) return null;
|
|
20003
|
+
const hashIdx = rest.lastIndexOf("#");
|
|
20004
|
+
const url = (hashIdx < 0 ? rest : rest.slice(0, hashIdx)).trim();
|
|
20005
|
+
const ref = hashIdx < 0 ? void 0 : rest.slice(hashIdx + 1).trim();
|
|
20006
|
+
if (!url || hashIdx >= 0 && !ref) return null;
|
|
20007
|
+
if (!isAllowedGitProtocol(url)) return null;
|
|
20008
|
+
return { url, ref };
|
|
20009
|
+
}
|
|
20010
|
+
function parseRemoteSource(source) {
|
|
20011
|
+
const github = parseGithubSource(source);
|
|
20012
|
+
if (github) return { kind: "github", ...github };
|
|
20013
|
+
const gitlab = parseGitlabSource(source);
|
|
20014
|
+
if (gitlab) return { kind: "gitlab", ...gitlab };
|
|
20015
|
+
const git = parseGitSource(source);
|
|
20016
|
+
if (git) return { kind: "git", ...git };
|
|
20017
|
+
return null;
|
|
20018
|
+
}
|
|
20019
|
+
function isSupportedRemoteSource(source) {
|
|
20020
|
+
return parseRemoteSource(source) !== null;
|
|
20021
|
+
}
|
|
19903
20022
|
|
|
19904
20023
|
// src/config/remote/git-remote.ts
|
|
19905
20024
|
var execFileAsync = promisify(execFile);
|
|
@@ -19970,7 +20089,8 @@ function resolveCloneUrl(parsed) {
|
|
|
19970
20089
|
}
|
|
19971
20090
|
async function cloneRepo(cloneUrl, repoDir) {
|
|
19972
20091
|
ensureNotFlag(cloneUrl, "clone-url");
|
|
19973
|
-
|
|
20092
|
+
assertAllowedGitUrl(cloneUrl);
|
|
20093
|
+
await runGit(["clone", "-c", "core.symlinks=false", cloneUrl, repoDir]);
|
|
19974
20094
|
}
|
|
19975
20095
|
async function checkoutRef(repoDir, ref) {
|
|
19976
20096
|
ensureNotFlag(ref, "ref");
|
|
@@ -19984,7 +20104,10 @@ async function runGit(args, cwd) {
|
|
|
19984
20104
|
cwd,
|
|
19985
20105
|
env: {
|
|
19986
20106
|
...process.env,
|
|
19987
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
20107
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
20108
|
+
// Constrain transports git may use (incl. mid-clone redirects/insteadOf)
|
|
20109
|
+
// to the same allowlist the clone URL itself passed.
|
|
20110
|
+
GIT_ALLOW_PROTOCOL: gitAllowProtocolEnv()
|
|
19988
20111
|
}
|
|
19989
20112
|
});
|
|
19990
20113
|
return stdout.trim();
|
|
@@ -20172,80 +20295,6 @@ async function fetchGithubDefaultBranch(parsed, extendName, options, cacheDir, b
|
|
|
20172
20295
|
}
|
|
20173
20296
|
throw lastError instanceof Error ? lastError : new Error("Failed to clone GitHub default branch");
|
|
20174
20297
|
}
|
|
20175
|
-
function splitSourceRef(source, prefix, defaultRef) {
|
|
20176
|
-
if (!source.startsWith(prefix)) return null;
|
|
20177
|
-
const rest = source.slice(prefix.length).trim();
|
|
20178
|
-
if (!rest) return null;
|
|
20179
|
-
const refIdx = rest.lastIndexOf("@");
|
|
20180
|
-
if (refIdx < 0) return [rest, defaultRef];
|
|
20181
|
-
const slug = rest.slice(0, refIdx).trim();
|
|
20182
|
-
const ref = rest.slice(refIdx + 1).trim();
|
|
20183
|
-
if (!slug || !ref) return null;
|
|
20184
|
-
return [slug, ref];
|
|
20185
|
-
}
|
|
20186
|
-
function parseGithubSource(source) {
|
|
20187
|
-
const parts = splitSourceRef(source, "github:", "latest");
|
|
20188
|
-
if (!parts) return null;
|
|
20189
|
-
const [slug, tag] = parts;
|
|
20190
|
-
const slash = slug.indexOf("/");
|
|
20191
|
-
if (slash < 0) return null;
|
|
20192
|
-
const org = slug.slice(0, slash).trim();
|
|
20193
|
-
const repo = slug.slice(slash + 1).trim();
|
|
20194
|
-
if (!org || !repo || !tag) return null;
|
|
20195
|
-
return { org, repo, tag };
|
|
20196
|
-
}
|
|
20197
|
-
function parseGitlabSource(source) {
|
|
20198
|
-
const parts = splitSourceRef(source, "gitlab:");
|
|
20199
|
-
if (!parts) return null;
|
|
20200
|
-
const [slug, ref] = parts;
|
|
20201
|
-
const slash = slug.lastIndexOf("/");
|
|
20202
|
-
if (slash < 0) return null;
|
|
20203
|
-
const namespace = slug.slice(0, slash).trim();
|
|
20204
|
-
const project31 = slug.slice(slash + 1).trim();
|
|
20205
|
-
if (!namespace || !project31) return null;
|
|
20206
|
-
return {
|
|
20207
|
-
namespace,
|
|
20208
|
-
project: project31,
|
|
20209
|
-
ref,
|
|
20210
|
-
cloneUrl: `https://gitlab.com/${namespace}/${project31}.git`
|
|
20211
|
-
};
|
|
20212
|
-
}
|
|
20213
|
-
function parseGitSource(source) {
|
|
20214
|
-
if (!source.startsWith("git+")) return null;
|
|
20215
|
-
const rest = source.slice(4).trim();
|
|
20216
|
-
if (!rest) return null;
|
|
20217
|
-
const hashIdx = rest.lastIndexOf("#");
|
|
20218
|
-
const url = (hashIdx < 0 ? rest : rest.slice(0, hashIdx)).trim();
|
|
20219
|
-
const ref = hashIdx < 0 ? void 0 : rest.slice(hashIdx + 1).trim();
|
|
20220
|
-
if (!url || hashIdx >= 0 && !ref) return null;
|
|
20221
|
-
let parsedUrl;
|
|
20222
|
-
try {
|
|
20223
|
-
parsedUrl = new URL(url);
|
|
20224
|
-
} catch {
|
|
20225
|
-
return null;
|
|
20226
|
-
}
|
|
20227
|
-
const allowInsecure = process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "1" || process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "true";
|
|
20228
|
-
const allowLocalGit = process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "1" || process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "true";
|
|
20229
|
-
const allowed = ["https:", "ssh:"];
|
|
20230
|
-
if (allowInsecure) allowed.push("http:");
|
|
20231
|
-
if (allowLocalGit) allowed.push("file:");
|
|
20232
|
-
if (!allowed.includes(parsedUrl.protocol)) {
|
|
20233
|
-
return null;
|
|
20234
|
-
}
|
|
20235
|
-
return { url, ref };
|
|
20236
|
-
}
|
|
20237
|
-
function parseRemoteSource(source) {
|
|
20238
|
-
const github = parseGithubSource(source);
|
|
20239
|
-
if (github) return { kind: "github", ...github };
|
|
20240
|
-
const gitlab = parseGitlabSource(source);
|
|
20241
|
-
if (gitlab) return { kind: "gitlab", ...gitlab };
|
|
20242
|
-
const git = parseGitSource(source);
|
|
20243
|
-
if (git) return { kind: "git", ...git };
|
|
20244
|
-
return null;
|
|
20245
|
-
}
|
|
20246
|
-
function isSupportedRemoteSource(source) {
|
|
20247
|
-
return parseRemoteSource(source) !== null;
|
|
20248
|
-
}
|
|
20249
20298
|
async function sweepStaleCache(cacheDir, maxAgeMs) {
|
|
20250
20299
|
const dir = cacheDir ?? getCacheDir();
|
|
20251
20300
|
const threshold = Number(process.env.AGENTSMESH_CACHE_MAX_AGE_DAYS ?? 30) * 864e5;
|
|
@@ -20479,15 +20528,17 @@ function assertNoBasenameCollisions(feature, paths, stripExt) {
|
|
|
20479
20528
|
const idx = Math.max(fwdIdx, bckIdx);
|
|
20480
20529
|
const base = idx === -1 ? p : p.slice(idx + 1);
|
|
20481
20530
|
const slug = base.endsWith(stripExt) ? base.slice(0, -stripExt.length) : base;
|
|
20482
|
-
const
|
|
20483
|
-
|
|
20531
|
+
const key = slug.toLowerCase();
|
|
20532
|
+
const prior = seen.get(key);
|
|
20533
|
+
if (prior !== void 0 && prior.path !== p) {
|
|
20534
|
+
const detail = prior.slug === slug ? `"${slug}"` : `"${prior.slug}" vs "${slug}" (case-insensitive)`;
|
|
20484
20535
|
throw new CanonicalNameError(
|
|
20485
20536
|
feature,
|
|
20486
20537
|
slug,
|
|
20487
|
-
`canonical ${feature} files collide on slug
|
|
20538
|
+
`canonical ${feature} files collide on slug ${detail}: ${prior.path} vs ${p}. Rename one.`
|
|
20488
20539
|
);
|
|
20489
20540
|
}
|
|
20490
|
-
seen.set(
|
|
20541
|
+
seen.set(key, { path: p, slug });
|
|
20491
20542
|
}
|
|
20492
20543
|
}
|
|
20493
20544
|
|
|
@@ -20602,7 +20653,7 @@ function toStrArray(v) {
|
|
|
20602
20653
|
return [];
|
|
20603
20654
|
}
|
|
20604
20655
|
async function parseRules(rulesDir, opts = {}) {
|
|
20605
|
-
const files = await
|
|
20656
|
+
const files = await readDirRecursiveNoSymlinks(rulesDir);
|
|
20606
20657
|
const mdFiles = files.filter((f) => {
|
|
20607
20658
|
if (!f.endsWith(".md")) return false;
|
|
20608
20659
|
const name = basename(f, ".md");
|
|
@@ -20611,6 +20662,7 @@ async function parseRules(rulesDir, opts = {}) {
|
|
|
20611
20662
|
warnIfUnrecognizedResourceFormats("rules", rulesDir, files, mdFiles, {
|
|
20612
20663
|
handledByOtherReader: opts.handledByOtherReader
|
|
20613
20664
|
});
|
|
20665
|
+
assertNoBasenameCollisions("rule", mdFiles, ".md");
|
|
20614
20666
|
const rules = [];
|
|
20615
20667
|
for (const path of mdFiles) {
|
|
20616
20668
|
const content = await readFileSafe(path);
|
|
@@ -20659,7 +20711,7 @@ function toToolsArray(v) {
|
|
|
20659
20711
|
return [];
|
|
20660
20712
|
}
|
|
20661
20713
|
async function parseCommands(commandsDir, opts = {}) {
|
|
20662
|
-
const files = await
|
|
20714
|
+
const files = await readDirRecursiveNoSymlinks(commandsDir);
|
|
20663
20715
|
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename(f).startsWith("_"));
|
|
20664
20716
|
warnIfUnrecognizedResourceFormats("commands", commandsDir, files, mdFiles, {
|
|
20665
20717
|
handledByOtherReader: opts.handledByOtherReader
|
|
@@ -20719,7 +20771,7 @@ function toHooks(v) {
|
|
|
20719
20771
|
return {};
|
|
20720
20772
|
}
|
|
20721
20773
|
async function parseAgents(agentsDir, opts = {}) {
|
|
20722
|
-
const files = await
|
|
20774
|
+
const files = await readDirRecursiveNoSymlinks(agentsDir);
|
|
20723
20775
|
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename(f).startsWith("_"));
|
|
20724
20776
|
warnIfUnrecognizedResourceFormats("agents", agentsDir, files, mdFiles, {
|
|
20725
20777
|
handledByOtherReader: opts.handledByOtherReader
|
|
@@ -21303,7 +21355,7 @@ async function importEntities(kind, dir, opts) {
|
|
|
21303
21355
|
}
|
|
21304
21356
|
async function readToolNativeEntities(srcDir, targetId, kind, parseOpts = {}) {
|
|
21305
21357
|
const specs = directorySpecsFor(getDescriptor(targetId)?.importer, kind);
|
|
21306
|
-
const allFiles = await
|
|
21358
|
+
const allFiles = await readDirRecursiveNoSymlinks(srcDir);
|
|
21307
21359
|
const nonMdExtensions = /* @__PURE__ */ new Set();
|
|
21308
21360
|
for (const spec of specs) {
|
|
21309
21361
|
for (const ext of spec.extensions) {
|
|
@@ -21660,7 +21712,7 @@ async function stageSingleFile(sourcePath, destinationDir, acceptMdc) {
|
|
|
21660
21712
|
async function stageMarkdownCollection(sourceRoot, destinationDir, acceptMdc) {
|
|
21661
21713
|
const info = await stat(sourceRoot);
|
|
21662
21714
|
if (info.isFile()) return stageSingleFile(sourceRoot, destinationDir, acceptMdc);
|
|
21663
|
-
const files = (await
|
|
21715
|
+
const files = (await readDirRecursiveNoSymlinks(sourceRoot)).filter(
|
|
21664
21716
|
(file) => isAcceptedFile(file, acceptMdc) && !isBoilerplate(basename(file))
|
|
21665
21717
|
);
|
|
21666
21718
|
if (files.length === 0) {
|
|
@@ -21707,7 +21759,7 @@ async function stagePreferredSkills(sourceRoot, destinationDir, preferredSkillNa
|
|
|
21707
21759
|
}
|
|
21708
21760
|
const wanted = new Set(preferredSkillNames);
|
|
21709
21761
|
const matches = /* @__PURE__ */ new Map();
|
|
21710
|
-
for (const file of await
|
|
21762
|
+
for (const file of await readDirRecursiveNoSymlinks(sourceRoot)) {
|
|
21711
21763
|
if (!file.endsWith("/SKILL.md") && !file.endsWith("\\SKILL.md")) continue;
|
|
21712
21764
|
const skillDir = dirname(file);
|
|
21713
21765
|
const skillName = basename(skillDir);
|
|
@@ -21755,7 +21807,7 @@ async function stageSkills(sourceRoot, destinationDir, options = {}) {
|
|
|
21755
21807
|
return;
|
|
21756
21808
|
}
|
|
21757
21809
|
await mkdirp(destinationDir);
|
|
21758
|
-
const entries = await
|
|
21810
|
+
const entries = await readDirRecursiveNoSymlinks(sourceRoot);
|
|
21759
21811
|
const roots = /* @__PURE__ */ new Set();
|
|
21760
21812
|
for (const file of entries.filter(
|
|
21761
21813
|
(entry) => entry.endsWith("/SKILL.md") || entry.endsWith("\\SKILL.md")
|