agentsmesh 0.2.1 → 0.2.2

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d42b374: Support installing standalone skill repos (bare GitHub/GitLab URLs), use SKILL.md frontmatter name for skill identity, filter repo boilerplate from installed skills, and fix pack skill reference paths in generated output.
8
+
3
9
  All notable changes to this project will be documented in this file.
4
10
 
5
11
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/sampleXbro/agentsmesh/actions/workflows/ci.yml/badge.svg)](https://github.com/sampleXbro/agentsmesh/actions/workflows/ci.yml)
4
4
  [![npm version](https://img.shields.io/npm/v/agentsmesh.svg)](https://www.npmjs.com/package/agentsmesh)
5
- [![Coverage](https://codecov.io/gh/sampleXbro/agentsmesh/branch/main/graph/badge.svg)](https://codecov.io/gh/sampleXbro/agentsmesh)
5
+ [![Coverage](https://codecov.io/gh/sampleXbro/agentsmesh/branch/master/graph/badge.svg)](https://codecov.io/gh/sampleXbro/agentsmesh)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![Node.js](https://img.shields.io/node/v/agentsmesh.svg)](https://nodejs.org/)
package/dist/cli.js CHANGED
@@ -5455,6 +5455,10 @@ async function readContent(path) {
5455
5455
  return c2 ?? "";
5456
5456
  }
5457
5457
  var SKILL_FILE = "SKILL.md";
5458
+ var EXCLUDED_DIR_PREFIXES = [".git", "node_modules"];
5459
+ function sanitizeSkillName(raw) {
5460
+ return raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
5461
+ }
5458
5462
  async function listSupportingFiles(skillDir) {
5459
5463
  const files = await readDirRecursive(skillDir);
5460
5464
  const result = [];
@@ -5462,6 +5466,9 @@ async function listSupportingFiles(skillDir) {
5462
5466
  const raw = absPath.slice(skillDir.length + 1);
5463
5467
  const name = raw.replace(/\\/g, "/");
5464
5468
  if (name === SKILL_FILE || name.endsWith(`/${SKILL_FILE}`)) continue;
5469
+ const firstSegment = name.split("/")[0];
5470
+ if (EXCLUDED_DIR_PREFIXES.some((p) => firstSegment === p)) continue;
5471
+ if (name === ".DS_Store" || name.endsWith("/.DS_Store")) continue;
5465
5472
  const content = await readContent(absPath);
5466
5473
  result.push({ relativePath: name, absolutePath: absPath, content });
5467
5474
  }
@@ -5473,9 +5480,10 @@ async function parseSkillDirectory(skillDir) {
5473
5480
  if (!content) return null;
5474
5481
  const { frontmatter, body } = parseFrontmatter(content);
5475
5482
  const supportingFiles = await listSupportingFiles(skillDir);
5483
+ const fmName = typeof frontmatter.name === "string" ? sanitizeSkillName(frontmatter.name) : "";
5476
5484
  return {
5477
5485
  source: skillPath,
5478
- name: basename25(skillDir),
5486
+ name: fmName || basename25(skillDir),
5479
5487
  description: typeof frontmatter.description === "string" ? frontmatter.description : "",
5480
5488
  body,
5481
5489
  supportingFiles
@@ -7976,10 +7984,10 @@ function preferEquivalentCodexAgents(results, canonical, config) {
7976
7984
 
7977
7985
  // src/core/reference-rewriter.ts
7978
7986
  import { existsSync as existsSync3 } from "fs";
7979
- import { dirname as dirname19, join as join48 } from "path";
7987
+ import { dirname as dirname20, join as join48 } from "path";
7980
7988
 
7981
7989
  // src/core/output-source-map.ts
7982
- import { join as join47, normalize as normalizePath2 } from "path";
7990
+ import { dirname as dirname19, join as join47, normalize as normalizePath2 } from "path";
7983
7991
  function canonicalRulePath(rule) {
7984
7992
  return `.agentsmesh/rules/${rule.source.split("/").pop()}`;
7985
7993
  }
@@ -8025,6 +8033,22 @@ function ruleOutputPaths(target10, rule, refs) {
8025
8033
  }
8026
8034
  return paths;
8027
8035
  }
8036
+ function addPackSkillPaths(refs, target10, canonical, projectRoot) {
8037
+ const skillDir = SKILL_DIRS[target10];
8038
+ if (!skillDir) return;
8039
+ const packsPrefix = join47(projectRoot, ".agentsmesh", "packs");
8040
+ for (const skill of canonical.skills) {
8041
+ const skillSourceDir = dirname19(skill.source);
8042
+ if (!skillSourceDir.startsWith(packsPrefix)) continue;
8043
+ const targetSkillDir = normalizePath2(join47(projectRoot, skillDir, skill.name));
8044
+ refs.set(normalizePath2(skillSourceDir), targetSkillDir);
8045
+ refs.set(normalizePath2(skill.source), normalizePath2(join47(targetSkillDir, "SKILL.md")));
8046
+ for (const file of skill.supportingFiles) {
8047
+ const targetFilePath = normalizePath2(join47(targetSkillDir, file.relativePath));
8048
+ refs.set(normalizePath2(file.absolutePath), targetFilePath);
8049
+ }
8050
+ }
8051
+ }
8028
8052
  function buildArtifactPathMap(target10, canonical, config, projectRoot, destinationPath) {
8029
8053
  const refs = new Map(
8030
8054
  [...buildReferenceMap(target10, canonical, config)].map(([canonicalPath, targetPath]) => [
@@ -8041,6 +8065,7 @@ function buildArtifactPathMap(target10, canonical, config, projectRoot, destinat
8041
8065
  );
8042
8066
  }
8043
8067
  }
8068
+ addPackSkillPaths(refs, target10, canonical, projectRoot);
8044
8069
  return refs;
8045
8070
  }
8046
8071
  function buildOutputSourceMap(target10, canonical, config) {
@@ -8077,11 +8102,11 @@ function collectPlannedPaths(projectRoot, results) {
8077
8102
  for (const result of results) {
8078
8103
  const absolutePath = join48(projectRoot, result.path);
8079
8104
  planned.add(absolutePath);
8080
- let current = dirname19(absolutePath);
8105
+ let current = dirname20(absolutePath);
8081
8106
  while (current.startsWith(projectRoot) && !planned.has(current)) {
8082
8107
  planned.add(current);
8083
8108
  if (current === projectRoot) break;
8084
- current = dirname19(current);
8109
+ current = dirname20(current);
8085
8110
  }
8086
8111
  }
8087
8112
  return planned;
@@ -9580,7 +9605,7 @@ async function runCheck(flags, projectRoot) {
9580
9605
  import { join as join58 } from "path";
9581
9606
 
9582
9607
  // src/core/merger.ts
9583
- import { dirname as dirname20, join as join57 } from "path";
9608
+ import { dirname as dirname21, join as join57 } from "path";
9584
9609
  var LOCK_FILENAME2 = ".lock";
9585
9610
  var CONFLICT_MARKER = "<<<<<<<";
9586
9611
  async function hasLockConflict(abDir) {
@@ -9595,7 +9620,7 @@ async function resolveLockConflict(abDir, libVersion, config) {
9595
9620
  throw new Error("No conflict to resolve.");
9596
9621
  }
9597
9622
  const checksums = await buildChecksums(abDir);
9598
- const configDir = dirname20(abDir);
9623
+ const configDir = dirname21(abDir);
9599
9624
  const resolvedExtends = config ? await resolveExtendPaths(config, configDir) : [];
9600
9625
  const extendChecksums = resolvedExtends.length > 0 ? await buildExtendChecksums(resolvedExtends) : {};
9601
9626
  const packChecksums = await buildPackChecksums(join57(abDir, "packs"));
@@ -9626,7 +9651,7 @@ async function runMerge(flags, projectRoot) {
9626
9651
  }
9627
9652
 
9628
9653
  // src/install/run-install.ts
9629
- import { join as join71 } from "path";
9654
+ import { join as join72 } from "path";
9630
9655
 
9631
9656
  // src/install/git-pin.ts
9632
9657
  import { execFile as execFile2 } from "child_process";
@@ -10001,6 +10026,50 @@ function parseGitlabBlobUrl(urlStr) {
10001
10026
  return null;
10002
10027
  }
10003
10028
  }
10029
+ var GITHUB_ROUTE_WORDS = /* @__PURE__ */ new Set([
10030
+ "tree",
10031
+ "blob",
10032
+ "commit",
10033
+ "releases",
10034
+ "actions",
10035
+ "issues",
10036
+ "pulls",
10037
+ "settings",
10038
+ "wiki",
10039
+ "discussions",
10040
+ "security",
10041
+ "projects",
10042
+ "packages"
10043
+ ]);
10044
+ function parseGithubRepoUrl(urlStr) {
10045
+ try {
10046
+ const u = new URL3(urlStr);
10047
+ if (u.hostname !== "github.com") return null;
10048
+ const parts = u.pathname.split("/").filter(Boolean).map((s) => s.replace(/\.git$/i, ""));
10049
+ if (parts.length < 2) return null;
10050
+ if (parts.length > 2 || GITHUB_ROUTE_WORDS.has(parts[1])) return null;
10051
+ const org = parts[0];
10052
+ const repo = parts[1];
10053
+ return { org, repo };
10054
+ } catch {
10055
+ return null;
10056
+ }
10057
+ }
10058
+ function parseGitlabRepoUrl(urlStr) {
10059
+ try {
10060
+ const u = new URL3(urlStr);
10061
+ if (u.hostname !== "gitlab.com") return null;
10062
+ const parts = u.pathname.split("/").filter(Boolean).map((s) => s.replace(/\.git$/i, ""));
10063
+ if (parts.length < 2) return null;
10064
+ if (parts.includes("-")) return null;
10065
+ const project = parts[parts.length - 1];
10066
+ const namespace = parts.slice(0, -1).join("/");
10067
+ if (!namespace || !project) return null;
10068
+ return { namespace, project };
10069
+ } catch {
10070
+ return null;
10071
+ }
10072
+ }
10004
10073
  function parseGitSshGithub(ssh) {
10005
10074
  const m = ssh.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/i);
10006
10075
  if (!m) return null;
@@ -10038,26 +10107,48 @@ async function parseInstallSource(raw, configDir, explicitPath) {
10038
10107
  };
10039
10108
  }
10040
10109
  if (trimmed.startsWith("https://") || trimmed.startsWith("http://")) {
10041
- const gh = parseGithubTreeUrl(trimmed) ?? parseGithubBlobUrl(trimmed);
10042
- if (gh) {
10110
+ const ghDetailed = parseGithubTreeUrl(trimmed) ?? parseGithubBlobUrl(trimmed);
10111
+ if (ghDetailed) {
10112
+ return {
10113
+ kind: "github",
10114
+ rawRef: ghDetailed.ref,
10115
+ org: ghDetailed.org,
10116
+ repo: ghDetailed.repo,
10117
+ gitRemoteUrl: `https://github.com/${ghDetailed.org}/${ghDetailed.repo}.git`,
10118
+ pathInRepo: pathFlag || ghDetailed.path
10119
+ };
10120
+ }
10121
+ const ghBare = parseGithubRepoUrl(trimmed);
10122
+ if (ghBare) {
10043
10123
  return {
10044
10124
  kind: "github",
10045
- rawRef: gh.ref,
10046
- org: gh.org,
10047
- repo: gh.repo,
10048
- gitRemoteUrl: `https://github.com/${gh.org}/${gh.repo}.git`,
10049
- pathInRepo: pathFlag || gh.path
10125
+ rawRef: "HEAD",
10126
+ org: ghBare.org,
10127
+ repo: ghBare.repo,
10128
+ gitRemoteUrl: `https://github.com/${ghBare.org}/${ghBare.repo}.git`,
10129
+ pathInRepo: pathFlag
10050
10130
  };
10051
10131
  }
10052
- const gl = parseGitlabTreeUrl(trimmed) ?? parseGitlabBlobUrl(trimmed);
10053
- if (gl) {
10132
+ const glDetailed = parseGitlabTreeUrl(trimmed) ?? parseGitlabBlobUrl(trimmed);
10133
+ if (glDetailed) {
10054
10134
  return {
10055
10135
  kind: "gitlab",
10056
- rawRef: gl.ref,
10057
- org: gl.namespace,
10058
- repo: gl.project,
10059
- gitRemoteUrl: `https://gitlab.com/${gl.namespace}/${gl.project}.git`,
10060
- pathInRepo: pathFlag || gl.path
10136
+ rawRef: glDetailed.ref,
10137
+ org: glDetailed.namespace,
10138
+ repo: glDetailed.project,
10139
+ gitRemoteUrl: `https://gitlab.com/${glDetailed.namespace}/${glDetailed.project}.git`,
10140
+ pathInRepo: pathFlag || glDetailed.path
10141
+ };
10142
+ }
10143
+ const glBare = parseGitlabRepoUrl(trimmed);
10144
+ if (glBare) {
10145
+ return {
10146
+ kind: "gitlab",
10147
+ rawRef: "HEAD",
10148
+ org: glBare.namespace,
10149
+ repo: glBare.project,
10150
+ gitRemoteUrl: `https://gitlab.com/${glBare.namespace}/${glBare.project}.git`,
10151
+ pathInRepo: pathFlag
10061
10152
  };
10062
10153
  }
10063
10154
  }
@@ -10324,7 +10415,7 @@ import { join as join63 } from "path";
10324
10415
  import { rename as rename4 } from "fs/promises";
10325
10416
 
10326
10417
  // src/install/pack-writer.ts
10327
- import { join as join60, basename as basename39, dirname as dirname21 } from "path";
10418
+ import { join as join60, basename as basename39, dirname as dirname22 } from "path";
10328
10419
  import { rm as rm6, rename as rename3, mkdir as mkdir5, copyFile as copyFile2 } from "fs/promises";
10329
10420
  import { stringify as yamlStringify6 } from "yaml";
10330
10421
 
@@ -10385,7 +10476,7 @@ async function writeSkills(canonical, packDir) {
10385
10476
  await copyFile2(skill.source, join60(skillDestDir, "SKILL.md"));
10386
10477
  for (const sf of skill.supportingFiles) {
10387
10478
  const destPath = join60(skillDestDir, sf.relativePath);
10388
- await mkdirp(dirname21(destPath));
10479
+ await mkdirp(dirname22(destPath));
10389
10480
  await copyFile2(sf.absolutePath, destPath);
10390
10481
  }
10391
10482
  }
@@ -10430,7 +10521,7 @@ async function materializePack(packsDir, packName, canonical, metadataInput) {
10430
10521
  }
10431
10522
 
10432
10523
  // src/install/pack-merge.ts
10433
- import { join as join61, basename as basename40, dirname as dirname22 } from "path";
10524
+ import { join as join61, basename as basename40, dirname as dirname23 } from "path";
10434
10525
  import { copyFile as copyFile3 } from "fs/promises";
10435
10526
  import { stringify as yamlStringify7 } from "yaml";
10436
10527
  function union(a, b) {
@@ -10493,7 +10584,7 @@ async function mergeSkills(canonical, packDir) {
10493
10584
  await copyFile3(skill.source, join61(destDir, "SKILL.md"));
10494
10585
  for (const sf of skill.supportingFiles) {
10495
10586
  const destPath = join61(destDir, sf.relativePath);
10496
- await mkdirp(dirname22(destPath));
10587
+ await mkdirp(dirname23(destPath));
10497
10588
  await copyFile3(sf.absolutePath, destPath);
10498
10589
  }
10499
10590
  }
@@ -10919,9 +11010,66 @@ function narrowDiscoveredForInstallScope(canonical, options) {
10919
11010
  }
10920
11011
 
10921
11012
  // src/install/manual-install-scope.ts
10922
- import { basename as basename41, dirname as dirname23, join as join65, relative as relative21 } from "path";
10923
- import { cp, mkdtemp, stat as stat5, rm as rm7 } from "fs/promises";
11013
+ import { basename as basename41, dirname as dirname24, join as join65, relative as relative22 } from "path";
11014
+ import { cp as cp2, mkdtemp, stat as stat5, rm as rm7 } from "fs/promises";
10924
11015
  import { tmpdir } from "os";
11016
+
11017
+ // src/install/skill-repo-filter.ts
11018
+ import { relative as relative21 } from "path";
11019
+ import { cp } from "fs/promises";
11020
+ init_markdown();
11021
+ var REPO_BOILERPLATE_FILES = /* @__PURE__ */ new Set([
11022
+ "README.md",
11023
+ "README.rst",
11024
+ "README.txt",
11025
+ "README",
11026
+ "LICENSE",
11027
+ "LICENSE.md",
11028
+ "LICENSE.txt",
11029
+ "LICENSE-MIT",
11030
+ "LICENSE-APACHE",
11031
+ "CONTRIBUTING.md",
11032
+ "CHANGELOG.md",
11033
+ "CODE_OF_CONDUCT.md",
11034
+ "package.json",
11035
+ "package-lock.json",
11036
+ "pnpm-lock.yaml",
11037
+ "yarn.lock",
11038
+ ".gitignore",
11039
+ ".gitattributes",
11040
+ ".editorconfig",
11041
+ ".DS_Store"
11042
+ ]);
11043
+ var REPO_BOILERPLATE_DIRS = /* @__PURE__ */ new Set([
11044
+ ".git",
11045
+ ".github",
11046
+ ".gitlab",
11047
+ "node_modules",
11048
+ ".vscode",
11049
+ ".idea"
11050
+ ]);
11051
+ async function readSkillFrontmatterName(skillMdPath) {
11052
+ const content = await readFileSafe(skillMdPath);
11053
+ if (!content) return "";
11054
+ const { frontmatter } = parseFrontmatter(content);
11055
+ if (typeof frontmatter.name !== "string") return "";
11056
+ return frontmatter.name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
11057
+ }
11058
+ async function cpFilteredSkill(sourceRoot, destDir) {
11059
+ await cp(sourceRoot, destDir, {
11060
+ recursive: true,
11061
+ filter: (src) => {
11062
+ const rel2 = relative21(sourceRoot, src).replace(/\\/g, "/");
11063
+ if (rel2 === "") return true;
11064
+ const first = rel2.split("/")[0];
11065
+ if (REPO_BOILERPLATE_DIRS.has(first)) return false;
11066
+ if (!rel2.includes("/") && REPO_BOILERPLATE_FILES.has(rel2)) return false;
11067
+ return true;
11068
+ }
11069
+ });
11070
+ }
11071
+
11072
+ // src/install/manual-install-scope.ts
10925
11073
  async function createStageRoot() {
10926
11074
  const stageBase = await mkdtemp(join65(tmpdir(), "am-install-manual-"));
10927
11075
  const discoveryRoot = join65(stageBase, "repo");
@@ -10940,7 +11088,7 @@ async function stageMarkdownCollection(sourceRoot, destinationDir) {
10940
11088
  throw new Error(`Manual install only supports .md files for this collection: ${sourceRoot}`);
10941
11089
  }
10942
11090
  await mkdirp(destinationDir);
10943
- await cp(sourceRoot, join65(destinationDir, basename41(sourceRoot)));
11091
+ await cp2(sourceRoot, join65(destinationDir, basename41(sourceRoot)));
10944
11092
  return;
10945
11093
  }
10946
11094
  const files = (await readDirRecursive(sourceRoot)).filter(
@@ -10960,7 +11108,7 @@ async function stageMarkdownCollection(sourceRoot, destinationDir) {
10960
11108
  );
10961
11109
  }
10962
11110
  usedNames.set(name, file);
10963
- await cp(file, join65(destinationDir, name));
11111
+ await cp2(file, join65(destinationDir, name));
10964
11112
  }
10965
11113
  }
10966
11114
  async function stagePreferredSkills(sourceRoot, destinationDir, preferredSkillNames) {
@@ -10971,7 +11119,7 @@ async function stagePreferredSkills(sourceRoot, destinationDir, preferredSkillNa
10971
11119
  const matches = /* @__PURE__ */ new Map();
10972
11120
  for (const file of await readDirRecursive(sourceRoot)) {
10973
11121
  if (!file.endsWith("/SKILL.md") && !file.endsWith("\\SKILL.md")) continue;
10974
- const skillDir = dirname23(file);
11122
+ const skillDir = dirname24(file);
10975
11123
  const skillName = basename41(skillDir);
10976
11124
  if (!wanted.has(skillName)) continue;
10977
11125
  const previous = matches.get(skillName);
@@ -10985,7 +11133,7 @@ async function stagePreferredSkills(sourceRoot, destinationDir, preferredSkillNa
10985
11133
  if (matches.size !== preferredSkillNames.length) return false;
10986
11134
  await mkdirp(destinationDir);
10987
11135
  for (const skillName of preferredSkillNames) {
10988
- await cp(matches.get(skillName), join65(destinationDir, skillName), { recursive: true });
11136
+ await cp2(matches.get(skillName), join65(destinationDir, skillName), { recursive: true });
10989
11137
  }
10990
11138
  return true;
10991
11139
  }
@@ -10995,10 +11143,10 @@ async function stageSkills(sourceRoot, destinationDir, options = {}) {
10995
11143
  if (basename41(sourceRoot) !== "SKILL.md") {
10996
11144
  throw new Error(`Manual skill install expects SKILL.md or a skill directory: ${sourceRoot}`);
10997
11145
  }
10998
- const skillName = basename41(dirname23(sourceRoot));
11146
+ const skillName = basename41(dirname24(sourceRoot));
10999
11147
  const skillDir = join65(destinationDir, skillName);
11000
11148
  await mkdirp(skillDir);
11001
- await cp(dirname23(sourceRoot), skillDir, { recursive: true });
11149
+ await cp2(dirname24(sourceRoot), skillDir, { recursive: true });
11002
11150
  return;
11003
11151
  }
11004
11152
  if (await isSkillPackLayout(sourceRoot)) {
@@ -11006,9 +11154,11 @@ async function stageSkills(sourceRoot, destinationDir, options = {}) {
11006
11154
  if (await stagePreferredSkills(sourceRoot, destinationDir, options.preferredSkillNames ?? [])) {
11007
11155
  return;
11008
11156
  }
11009
- const skillDir = join65(destinationDir, basename41(sourceRoot));
11157
+ const fmName = await readSkillFrontmatterName(join65(sourceRoot, "SKILL.md"));
11158
+ const skillName = fmName || basename41(sourceRoot);
11159
+ const skillDir = join65(destinationDir, skillName);
11010
11160
  await mkdirp(destinationDir);
11011
- await cp(sourceRoot, skillDir, { recursive: true });
11161
+ await cpFilteredSkill(sourceRoot, skillDir);
11012
11162
  return;
11013
11163
  }
11014
11164
  if (await stagePreferredSkills(sourceRoot, destinationDir, options.preferredSkillNames ?? [])) {
@@ -11020,10 +11170,10 @@ async function stageSkills(sourceRoot, destinationDir, options = {}) {
11020
11170
  for (const file of entries.filter(
11021
11171
  (entry) => entry.endsWith("/SKILL.md") || entry.endsWith("\\SKILL.md")
11022
11172
  )) {
11023
- roots.add(relative21(sourceRoot, dirname23(file)).split(/[\\/]/)[0]);
11173
+ roots.add(relative22(sourceRoot, dirname24(file)).split(/[\\/]/)[0]);
11024
11174
  }
11025
11175
  for (const root of roots) {
11026
- await cp(join65(sourceRoot, root), join65(destinationDir, root), { recursive: true });
11176
+ await cp2(join65(sourceRoot, root), join65(destinationDir, root), { recursive: true });
11027
11177
  }
11028
11178
  return;
11029
11179
  }
@@ -11132,7 +11282,7 @@ function extendPickHasArrays(p) {
11132
11282
  import { basename as basename44, join as join68 } from "path";
11133
11283
 
11134
11284
  // src/install/gemini-install-commands.ts
11135
- import { join as join66, relative as relative22 } from "path";
11285
+ import { join as join66, relative as relative23 } from "path";
11136
11286
  async function inferGeminiCommandNamesFromFiles(repoRoot, pathInRepoPosix) {
11137
11287
  const commandsRoot = join66(repoRoot, ...GEMINI_COMMANDS_DIR.split("/"));
11138
11288
  const scanDir = join66(repoRoot, ...pathInRepoPosix.split("/"));
@@ -11140,7 +11290,7 @@ async function inferGeminiCommandNamesFromFiles(repoRoot, pathInRepoPosix) {
11140
11290
  const names = [];
11141
11291
  for (const f of files) {
11142
11292
  if (!/\.(toml|md)$/i.test(f)) continue;
11143
- const rel2 = relative22(commandsRoot, f).replace(/\\/g, "/");
11293
+ const rel2 = relative23(commandsRoot, f).replace(/\\/g, "/");
11144
11294
  if (rel2.startsWith("..") || rel2 === "") continue;
11145
11295
  const noExt = rel2.replace(/\.(toml|md)$/i, "");
11146
11296
  const name = noExt.split("/").filter(Boolean).join(":");
@@ -11150,16 +11300,16 @@ async function inferGeminiCommandNamesFromFiles(repoRoot, pathInRepoPosix) {
11150
11300
  }
11151
11301
 
11152
11302
  // src/install/native-skill-scan.ts
11153
- import { basename as basename42, dirname as dirname24, relative as relative23 } from "path";
11303
+ import { basename as basename42, dirname as dirname25, relative as relative24 } from "path";
11154
11304
  async function skillNamesFromNativeSkillDir(scanRoot) {
11155
11305
  const files = await readDirRecursive(scanRoot);
11156
11306
  const names = /* @__PURE__ */ new Set();
11157
11307
  for (const f of files) {
11158
11308
  if (basename42(f) === "SKILL.md") {
11159
- names.add(basename42(dirname24(f)));
11309
+ names.add(basename42(dirname25(f)));
11160
11310
  continue;
11161
11311
  }
11162
- const rel2 = relative23(scanRoot, f).replace(/\\/g, "/");
11312
+ const rel2 = relative24(scanRoot, f).replace(/\\/g, "/");
11163
11313
  if (!rel2.includes("/") && f.toLowerCase().endsWith(".md")) {
11164
11314
  names.add(basename42(f, ".md"));
11165
11315
  }
@@ -11342,8 +11492,8 @@ function isImplicitPickEmpty(p) {
11342
11492
  }
11343
11493
 
11344
11494
  // src/install/native-install-scope.ts
11345
- import { basename as basename45, join as join69, relative as relative24 } from "path";
11346
- import { cp as cp2, mkdtemp as mkdtemp2, rm as rm8 } from "fs/promises";
11495
+ import { basename as basename45, join as join69, relative as relative25 } from "path";
11496
+ import { cp as cp3, mkdtemp as mkdtemp2, rm as rm8 } from "fs/promises";
11347
11497
  import { tmpdir as tmpdir2 } from "os";
11348
11498
  function normalizePath3(path) {
11349
11499
  return path.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -11365,7 +11515,7 @@ async function makeStageRoot(repoRoot) {
11365
11515
  await rm8(stageBase, { recursive: true, force: true });
11366
11516
  };
11367
11517
  try {
11368
- await cp2(repoRoot, stageRoot, { recursive: true });
11518
+ await cp3(repoRoot, stageRoot, { recursive: true });
11369
11519
  return { stageRoot, cleanup };
11370
11520
  } catch (error) {
11371
11521
  await cleanup();
@@ -11398,7 +11548,7 @@ function buildPickFromResults(results, stageRoot) {
11398
11548
  }
11399
11549
  if (result.feature === "skills" && result.toPath.startsWith(".agentsmesh/skills/")) {
11400
11550
  const rel2 = normalizePath3(
11401
- relative24(join69(stageRoot, ".agentsmesh", "skills"), join69(stageRoot, result.toPath))
11551
+ relative25(join69(stageRoot, ".agentsmesh", "skills"), join69(stageRoot, result.toPath))
11402
11552
  );
11403
11553
  const skillName = rel2.split("/")[0];
11404
11554
  if (skillName) {
@@ -11586,7 +11736,7 @@ function applyReplayInstallScope(narrowed, discoveredFeatures, replay) {
11586
11736
  }
11587
11737
 
11588
11738
  // src/install/manual-install-persistence.ts
11589
- import { basename as basename46, dirname as dirname25 } from "path";
11739
+ import { basename as basename46, dirname as dirname26, join as join71 } from "path";
11590
11740
  import { stat as stat6 } from "fs/promises";
11591
11741
  function trimDot(pathInRepo) {
11592
11742
  return pathInRepo === "." || pathInRepo === "" ? void 0 : pathInRepo;
@@ -11605,27 +11755,28 @@ async function resolveManualInstallPersistence(args) {
11605
11755
  const info = await stat6(args.contentRoot);
11606
11756
  if (args.as !== "skills" && info.isFile() && args.contentRoot.toLowerCase().endsWith(".md")) {
11607
11757
  return {
11608
- pathInRepo: trimDot(dirname25(normalizedPath)),
11758
+ pathInRepo: trimDot(dirname26(normalizedPath)),
11609
11759
  pick: markdownPick(args.as, normalizedPath || args.contentRoot)
11610
11760
  };
11611
11761
  }
11612
11762
  if (args.as === "skills") {
11613
11763
  if (info.isFile() && basename46(args.contentRoot) === "SKILL.md") {
11614
- const skillDir = normalizedPath ? dirname25(normalizedPath) : dirname25(args.contentRoot);
11764
+ const skillDir = normalizedPath ? dirname26(normalizedPath) : dirname26(args.contentRoot);
11615
11765
  return {
11616
- pathInRepo: trimDot(dirname25(skillDir)),
11766
+ pathInRepo: trimDot(dirname26(skillDir)),
11617
11767
  pick: { skills: [basename46(skillDir)] }
11618
11768
  };
11619
11769
  }
11620
11770
  if (info.isDirectory()) {
11621
11771
  const skillDir = normalizedPath || basename46(args.contentRoot);
11622
- const skillFile = `${args.contentRoot.replace(/\/+$/g, "")}/SKILL.md`;
11772
+ const skillFile = join71(args.contentRoot.replace(/\/+$/g, ""), "SKILL.md");
11623
11773
  try {
11624
11774
  const skillStat = await stat6(skillFile);
11625
11775
  if (skillStat.isFile()) {
11776
+ const fmName = await readSkillFrontmatterName(skillFile);
11626
11777
  return {
11627
- pathInRepo: trimDot(dirname25(skillDir)),
11628
- pick: { skills: [basename46(skillDir)] }
11778
+ pathInRepo: trimDot(dirname26(skillDir)),
11779
+ pick: { skills: [fmName || basename46(skillDir)] }
11629
11780
  };
11630
11781
  }
11631
11782
  } catch {
@@ -11693,7 +11844,7 @@ async function runInstall(flags, args, projectRoot, replay) {
11693
11844
  sourceArg
11694
11845
  );
11695
11846
  const pathInRepo = parsed.pathInRepo.replace(/^\/+|\/+$/g, "");
11696
- const contentRoot = pathInRepo ? join71(resolvedPath, pathInRepo) : resolvedPath;
11847
+ const contentRoot = pathInRepo ? join72(resolvedPath, pathInRepo) : resolvedPath;
11697
11848
  if (!await exists(contentRoot)) {
11698
11849
  throw new Error(`Install path does not exist: ${contentRoot}`);
11699
11850
  }