agentsmesh 0.20.0 → 0.21.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/dist/engine.js CHANGED
@@ -768,6 +768,33 @@ async function readDirRecursive(dir, visited, branchSegments) {
768
768
  );
769
769
  }
770
770
  }
771
+ async function readDirRecursiveNoSymlinks(dir, branchSegments) {
772
+ const currentBranchSegments = branchSegments ?? [basename(dir)];
773
+ try {
774
+ const entries = await readdir(dir, { withFileTypes: true });
775
+ const files = [];
776
+ for (const ent of entries) {
777
+ if (ent.isSymbolicLink()) continue;
778
+ const full = join(dir, ent.name);
779
+ if (ent.isDirectory()) {
780
+ const nextSegments = [...currentBranchSegments, ent.name];
781
+ if (shouldSkipRecursiveBranch(nextSegments)) continue;
782
+ files.push(...await readDirRecursiveNoSymlinks(full, nextSegments));
783
+ } else if (ent.isFile()) {
784
+ files.push(full);
785
+ }
786
+ }
787
+ return files;
788
+ } catch (err) {
789
+ const e = err;
790
+ if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "EACCES") return [];
791
+ throw new FileSystemError(
792
+ dir,
793
+ `Failed to read directory ${dir}: ${e.message}. Check permissions.`,
794
+ { cause: err, errnoCode: e.code }
795
+ );
796
+ }
797
+ }
771
798
  var MAX_RECURSIVE_DEPTH, MAX_SEGMENT_REPETITIONS;
772
799
  var init_fs_traverse = __esm({
773
800
  "src/utils/filesystem/fs-traverse.ts"() {
@@ -20147,6 +20174,19 @@ init_fs();
20147
20174
 
20148
20175
  // src/config/remote/git-remote.ts
20149
20176
  init_fs();
20177
+
20178
+ // src/utils/output/redact-url-secrets.ts
20179
+ var URL_WITH_CREDENTIALS = /([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s"'<>]+)@([^\s"'<>]+)/g;
20180
+ function redactUrlSecrets(message) {
20181
+ return message.replace(
20182
+ URL_WITH_CREDENTIALS,
20183
+ (_full, scheme, _userinfo, rest) => {
20184
+ return `${scheme}***@${rest}`;
20185
+ }
20186
+ );
20187
+ }
20188
+
20189
+ // src/config/remote/git-remote.ts
20150
20190
  var execFileAsync = promisify(execFile);
20151
20191
  var REPO_DIRNAME = "repo";
20152
20192
  function ensureNotFlag(value, kind) {
@@ -20180,12 +20220,13 @@ async function fetchGitRemoteExtend(parsed, extendName, options, cacheDir, build
20180
20220
  await rm(stagedRoot, { recursive: true, force: true });
20181
20221
  const allowFallback = options.allowOfflineFallback !== false;
20182
20222
  if (allowFallback && await hasCachedRepo(cacheRepoDir)) {
20223
+ const rawMsg = err instanceof Error ? err.message : String(err);
20183
20224
  console.warn(
20184
- `[agentsmesh] Remote fetch failed for ${extendName}; using cached version. Error: ${err instanceof Error ? err.message : String(err)}`
20225
+ `[agentsmesh] Remote fetch failed for ${extendName}; using cached version. Error: ${redactUrlSecrets(rawMsg)}`
20185
20226
  );
20186
20227
  return readCachedRepo(cacheRepoDir);
20187
20228
  }
20188
- throw err;
20229
+ throw err instanceof Error ? Object.assign(new Error(redactUrlSecrets(err.message)), { cause: err.cause }) : err;
20189
20230
  }
20190
20231
  }
20191
20232
  async function readCachedRepo(repoDir) {
@@ -20346,13 +20387,14 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
20346
20387
  if (allowFallback && await exists(extractDir)) {
20347
20388
  const topDir2 = await findExtractTopDir(extractDir);
20348
20389
  if (topDir2) {
20390
+ const rawMsg = err instanceof Error ? err.message : String(err);
20349
20391
  console.warn(
20350
- `[agentsmesh] Network failed for ${extendName}; using cached version. Error: ${err instanceof Error ? err.message : String(err)}`
20392
+ `[agentsmesh] Network failed for ${extendName}; using cached version. Error: ${redactUrlSecrets(rawMsg)}`
20351
20393
  );
20352
20394
  return { resolvedPath: join(extractDir, topDir2), version: tag };
20353
20395
  }
20354
20396
  }
20355
- throw err;
20397
+ throw err instanceof Error ? Object.assign(new Error(redactUrlSecrets(err.message)), { cause: err.cause }) : err;
20356
20398
  }
20357
20399
  await rm(extractDir, { recursive: true, force: true });
20358
20400
  await mkdir(extractDir, { recursive: true });
@@ -20363,12 +20405,14 @@ async function fetchGithubRemoteExtend(parsed, extendName, options, cacheDir, bu
20363
20405
  file: tarPath,
20364
20406
  cwd: extractDir,
20365
20407
  strict: true,
20408
+ // Allowlist entry types instead of denylist: only `File` and `Directory`
20409
+ // can be extracted. Hardlinks (`Link`), symlinks (`SymbolicLink`), FIFOs,
20410
+ // character/block devices, and any future/exotic tar entry type are
20411
+ // rejected. A denylist would silently let an unknown variant through.
20366
20412
  filter: (entryPath, entry) => {
20367
20413
  if (isZipSlipPath(entryPath)) return false;
20368
- if (entry && "type" in entry && (entry.type === "Link" || entry.type === "SymbolicLink")) {
20369
- return false;
20370
- }
20371
- return true;
20414
+ const type = entry && "type" in entry ? entry.type : void 0;
20415
+ return type === "File" || type === "Directory";
20372
20416
  }
20373
20417
  });
20374
20418
  } finally {
@@ -20466,8 +20510,11 @@ function parseGitSource(source) {
20466
20510
  return null;
20467
20511
  }
20468
20512
  const allowInsecure = process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "1" || process.env.AGENTSMESH_ALLOW_INSECURE_GIT === "true";
20469
- const allowedProtocols = allowInsecure ? ["https:", "http:", "ssh:", "file:"] : ["https:", "ssh:", "file:"];
20470
- if (!allowedProtocols.includes(parsedUrl.protocol)) {
20513
+ const allowLocalGit = process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "1" || process.env.AGENTSMESH_ALLOW_LOCAL_GIT === "true";
20514
+ const allowed = ["https:", "ssh:"];
20515
+ if (allowInsecure) allowed.push("http:");
20516
+ if (allowLocalGit) allowed.push("file:");
20517
+ if (!allowed.includes(parsedUrl.protocol)) {
20471
20518
  return null;
20472
20519
  }
20473
20520
  return { url, ref };
@@ -20926,6 +20973,7 @@ async function parseAgents(agentsDir, opts = {}) {
20926
20973
 
20927
20974
  // src/canonical/features/skills.ts
20928
20975
  init_fs();
20976
+ init_fs_traverse();
20929
20977
  init_markdown();
20930
20978
  init_boilerplate_filter();
20931
20979
  async function readContent(path) {
@@ -20944,7 +20992,7 @@ function sanitizeSkillName(raw) {
20944
20992
  return raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
20945
20993
  }
20946
20994
  async function listSupportingFiles(skillDir) {
20947
- const files = await readDirRecursive(skillDir);
20995
+ const files = await readDirRecursiveNoSymlinks(skillDir);
20948
20996
  const result = [];
20949
20997
  for (const absPath of files) {
20950
20998
  const raw = absPath.slice(skillDir.length + 1);