allagents 0.5.2 → 0.6.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.
Files changed (2) hide show
  1. package/dist/index.js +280 -43
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -5324,8 +5324,8 @@ var require_pattern = __commonJS((exports) => {
5324
5324
  }
5325
5325
  exports.endsWithSlashGlobStar = endsWithSlashGlobStar;
5326
5326
  function isAffectDepthOfReadingPattern(pattern) {
5327
- const basename = path3.basename(pattern);
5328
- return endsWithSlashGlobStar(pattern) || isStaticPattern(basename);
5327
+ const basename2 = path3.basename(pattern);
5328
+ return endsWithSlashGlobStar(pattern) || isStaticPattern(basename2);
5329
5329
  }
5330
5330
  exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
5331
5331
  function expandPatternsWithBraceExpansion(patterns) {
@@ -11059,7 +11059,7 @@ import { dirname as dirname7, join as join12 } from "node:path";
11059
11059
  import { fileURLToPath as fileURLToPath4 } from "node:url";
11060
11060
 
11061
11061
  // src/core/workspace.ts
11062
- import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile4, copyFile as copyFile2 } from "node:fs/promises";
11062
+ import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile4, copyFile as copyFile2 } from "node:fs/promises";
11063
11063
  import { existsSync as existsSync7 } from "node:fs";
11064
11064
  import { join as join8, resolve as resolve5, dirname as dirname5, relative as relative2, sep, isAbsolute as isAbsolute2 } from "node:path";
11065
11065
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -19558,11 +19558,27 @@ async function verifyGitHubUrlExists(source) {
19558
19558
  }
19559
19559
 
19560
19560
  // src/core/plugin.ts
19561
- import { mkdir, readdir, stat } from "node:fs/promises";
19561
+ import { mkdir, readdir, stat, readFile as readFile2 } from "node:fs/promises";
19562
19562
  import { existsSync } from "node:fs";
19563
- import { dirname, join, resolve as resolve2 } from "node:path";
19564
- async function fetchPlugin(url, options2 = {}) {
19563
+ import { basename, dirname, join, resolve as resolve2 } from "node:path";
19564
+
19565
+ // src/models/plugin-config.ts
19566
+ var PluginManifestSchema = exports_external.object({
19567
+ name: exports_external.string(),
19568
+ version: exports_external.string(),
19569
+ description: exports_external.string(),
19570
+ author: exports_external.string().optional(),
19571
+ license: exports_external.string().optional()
19572
+ });
19573
+
19574
+ // src/core/plugin.ts
19575
+ async function fetchPlugin(url, options2 = {}, deps = {}) {
19565
19576
  const { force = false, branch } = options2;
19577
+ const {
19578
+ execa: execaFn = execa,
19579
+ existsSync: existsSyncFn = existsSync,
19580
+ mkdir: mkdirFn = mkdir
19581
+ } = deps;
19566
19582
  const validation = validatePluginSource(url);
19567
19583
  if (!validation.valid) {
19568
19584
  return {
@@ -19584,7 +19600,7 @@ async function fetchPlugin(url, options2 = {}) {
19584
19600
  const { owner, repo } = parsed;
19585
19601
  const cachePath = getPluginCachePath(owner, repo, branch);
19586
19602
  try {
19587
- await execa("gh", ["--version"]);
19603
+ await execaFn("gh", ["--version"]);
19588
19604
  } catch {
19589
19605
  return {
19590
19606
  success: false,
@@ -19594,7 +19610,7 @@ async function fetchPlugin(url, options2 = {}) {
19594
19610
  Install: https://cli.github.com`
19595
19611
  };
19596
19612
  }
19597
- const isCached = existsSync(cachePath);
19613
+ const isCached = existsSyncFn(cachePath);
19598
19614
  if (isCached && !force) {
19599
19615
  return {
19600
19616
  success: true,
@@ -19604,7 +19620,7 @@ async function fetchPlugin(url, options2 = {}) {
19604
19620
  }
19605
19621
  try {
19606
19622
  if (isCached && force) {
19607
- await execa("git", ["pull"], { cwd: cachePath });
19623
+ await execaFn("git", ["pull"], { cwd: cachePath });
19608
19624
  return {
19609
19625
  success: true,
19610
19626
  action: "updated",
@@ -19612,11 +19628,11 @@ async function fetchPlugin(url, options2 = {}) {
19612
19628
  };
19613
19629
  }
19614
19630
  const parentDir = dirname(cachePath);
19615
- await mkdir(parentDir, { recursive: true });
19631
+ await mkdirFn(parentDir, { recursive: true });
19616
19632
  if (branch) {
19617
- await execa("gh", ["repo", "clone", `${owner}/${repo}`, cachePath, "--", "--branch", branch]);
19633
+ await execaFn("gh", ["repo", "clone", `${owner}/${repo}`, cachePath, "--", "--branch", branch]);
19618
19634
  } else {
19619
- await execa("gh", ["repo", "clone", `${owner}/${repo}`, cachePath]);
19635
+ await execaFn("gh", ["repo", "clone", `${owner}/${repo}`, cachePath]);
19620
19636
  }
19621
19637
  return {
19622
19638
  success: true,
@@ -19666,9 +19682,23 @@ async function fetchPlugin(url, options2 = {}) {
19666
19682
  };
19667
19683
  }
19668
19684
  }
19685
+ async function getPluginName(pluginPath) {
19686
+ const manifestPath = join(pluginPath, "plugin.json");
19687
+ if (existsSync(manifestPath)) {
19688
+ try {
19689
+ const content = await readFile2(manifestPath, "utf-8");
19690
+ const manifest = JSON.parse(content);
19691
+ const result = PluginManifestSchema.safeParse(manifest);
19692
+ if (result.success && result.data.name) {
19693
+ return result.data.name;
19694
+ }
19695
+ } catch {}
19696
+ }
19697
+ return basename(pluginPath);
19698
+ }
19669
19699
 
19670
19700
  // src/core/transform.ts
19671
- import { readFile as readFile3, writeFile, mkdir as mkdir2, cp, readdir as readdir2 } from "node:fs/promises";
19701
+ import { readFile as readFile4, writeFile, mkdir as mkdir2, cp, readdir as readdir2 } from "node:fs/promises";
19672
19702
  import { existsSync as existsSync3 } from "node:fs";
19673
19703
  import { join as join4, dirname as dirname2 } from "node:path";
19674
19704
 
@@ -19752,7 +19782,7 @@ var CLIENT_MAPPINGS = {
19752
19782
 
19753
19783
  // src/validators/skill.ts
19754
19784
  var import_gray_matter = __toESM(require_gray_matter(), 1);
19755
- import { readFile as readFile2 } from "node:fs/promises";
19785
+ import { readFile as readFile3 } from "node:fs/promises";
19756
19786
  import { existsSync as existsSync2 } from "node:fs";
19757
19787
  import { join as join3 } from "node:path";
19758
19788
 
@@ -19776,7 +19806,7 @@ async function validateSkill(skillDir) {
19776
19806
  };
19777
19807
  }
19778
19808
  try {
19779
- const content = await readFile2(skillMdPath, "utf-8");
19809
+ const content = await readFile3(skillMdPath, "utf-8");
19780
19810
  const { data: frontmatter } = import_gray_matter.default(content);
19781
19811
  if (!frontmatter || Object.keys(frontmatter).length === 0) {
19782
19812
  return {
@@ -19826,7 +19856,7 @@ async function ensureWorkspaceRules(filePath, rules) {
19826
19856
  `, "utf-8");
19827
19857
  return;
19828
19858
  }
19829
- const content = await readFile3(filePath, "utf-8");
19859
+ const content = await readFile4(filePath, "utf-8");
19830
19860
  const startIndex = content.indexOf(startMarker);
19831
19861
  const endIndex = content.indexOf(endMarker);
19832
19862
  if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
@@ -19862,7 +19892,7 @@ async function copyCommands(pluginPath, workspacePath, client, options2 = {}) {
19862
19892
  return { source: sourcePath, destination: destPath, action: "copied" };
19863
19893
  }
19864
19894
  try {
19865
- const content = await readFile3(sourcePath, "utf-8");
19895
+ const content = await readFile4(sourcePath, "utf-8");
19866
19896
  await writeFile(destPath, content, "utf-8");
19867
19897
  return { source: sourcePath, destination: destPath, action: "copied" };
19868
19898
  } catch (error) {
@@ -19877,7 +19907,7 @@ async function copyCommands(pluginPath, workspacePath, client, options2 = {}) {
19877
19907
  return Promise.all(copyPromises);
19878
19908
  }
19879
19909
  async function copySkills(pluginPath, workspacePath, client, options2 = {}) {
19880
- const { dryRun = false } = options2;
19910
+ const { dryRun = false, skillNameMap } = options2;
19881
19911
  const mapping = CLIENT_MAPPINGS[client];
19882
19912
  const results = [];
19883
19913
  if (!mapping.skillsPath) {
@@ -19895,7 +19925,8 @@ async function copySkills(pluginPath, workspacePath, client, options2 = {}) {
19895
19925
  const skillDirs = entries.filter((e) => e.isDirectory());
19896
19926
  const copyPromises = skillDirs.map(async (entry) => {
19897
19927
  const skillSourcePath = join4(sourceDir, entry.name);
19898
- const skillDestPath = join4(destDir, entry.name);
19928
+ const resolvedName = skillNameMap?.get(entry.name) ?? entry.name;
19929
+ const skillDestPath = join4(destDir, resolvedName);
19899
19930
  const validation = await validateSkill(skillSourcePath);
19900
19931
  if (!validation.valid) {
19901
19932
  return {
@@ -19930,6 +19961,20 @@ async function copySkills(pluginPath, workspacePath, client, options2 = {}) {
19930
19961
  });
19931
19962
  return Promise.all(copyPromises);
19932
19963
  }
19964
+ async function collectPluginSkills(pluginPath, pluginSource) {
19965
+ const skillsDir = join4(pluginPath, "skills");
19966
+ if (!existsSync3(skillsDir)) {
19967
+ return [];
19968
+ }
19969
+ const entries = await readdir2(skillsDir, { withFileTypes: true });
19970
+ const skillDirs = entries.filter((e) => e.isDirectory());
19971
+ return skillDirs.map((entry) => ({
19972
+ folderName: entry.name,
19973
+ skillPath: join4(skillsDir, entry.name),
19974
+ pluginPath,
19975
+ pluginSource
19976
+ }));
19977
+ }
19933
19978
  async function copyHooks(pluginPath, workspacePath, client, options2 = {}) {
19934
19979
  const { dryRun = false } = options2;
19935
19980
  const mapping = CLIENT_MAPPINGS[client];
@@ -19984,7 +20029,7 @@ async function copyAgents(pluginPath, workspacePath, client, options2 = {}) {
19984
20029
  return { source: sourcePath, destination: destPath, action: "copied" };
19985
20030
  }
19986
20031
  try {
19987
- const content = await readFile3(sourcePath, "utf-8");
20032
+ const content = await readFile4(sourcePath, "utf-8");
19988
20033
  await writeFile(destPath, content, "utf-8");
19989
20034
  return { source: sourcePath, destination: destPath, action: "copied" };
19990
20035
  } catch (error) {
@@ -19999,11 +20044,12 @@ async function copyAgents(pluginPath, workspacePath, client, options2 = {}) {
19999
20044
  return Promise.all(copyPromises);
20000
20045
  }
20001
20046
  async function copyPluginToWorkspace(pluginPath, workspacePath, client, options2 = {}) {
20047
+ const { skillNameMap, ...baseOptions } = options2;
20002
20048
  const [commandResults, skillResults, hookResults, agentResults] = await Promise.all([
20003
- copyCommands(pluginPath, workspacePath, client, options2),
20004
- copySkills(pluginPath, workspacePath, client, options2),
20005
- copyHooks(pluginPath, workspacePath, client, options2),
20006
- copyAgents(pluginPath, workspacePath, client, options2)
20049
+ copyCommands(pluginPath, workspacePath, client, baseOptions),
20050
+ copySkills(pluginPath, workspacePath, client, { ...baseOptions, ...skillNameMap && { skillNameMap } }),
20051
+ copyHooks(pluginPath, workspacePath, client, baseOptions),
20052
+ copyAgents(pluginPath, workspacePath, client, baseOptions)
20007
20053
  ]);
20008
20054
  return [...commandResults, ...skillResults, ...hookResults, ...agentResults];
20009
20055
  }
@@ -20119,7 +20165,7 @@ async function copyWorkspaceFiles(sourcePath, workspacePath, files, options2 = {
20119
20165
  }
20120
20166
  try {
20121
20167
  await mkdir2(dirname2(destPath), { recursive: true });
20122
- const content = await readFile3(resolved.sourcePath, "utf-8");
20168
+ const content = await readFile4(resolved.sourcePath, "utf-8");
20123
20169
  await writeFile(destPath, content, "utf-8");
20124
20170
  results.push({ source: resolved.sourcePath, destination: destPath, action: "copied" });
20125
20171
  if (AGENT_FILES2.includes(resolved.relativePath)) {
@@ -20190,7 +20236,7 @@ async function copyWorkspaceFiles(sourcePath, workspacePath, files, options2 = {
20190
20236
  }
20191
20237
  try {
20192
20238
  await mkdir2(dirname2(destPath), { recursive: true });
20193
- const content = await readFile3(srcPath, "utf-8");
20239
+ const content = await readFile4(srcPath, "utf-8");
20194
20240
  await writeFile(destPath, content, "utf-8");
20195
20241
  results.push({ source: srcPath, destination: destPath, action: "copied" });
20196
20242
  if (AGENT_FILES2.includes(entry.dest)) {
@@ -20223,10 +20269,153 @@ async function copyWorkspaceFiles(sourcePath, workspacePath, files, options2 = {
20223
20269
  return results;
20224
20270
  }
20225
20271
 
20272
+ // src/utils/hash.ts
20273
+ import { createHash } from "node:crypto";
20274
+ function getShortId(input) {
20275
+ return createHash("sha256").update(input).digest("hex").substring(0, 6);
20276
+ }
20277
+
20278
+ // src/utils/source-parser.ts
20279
+ function extractOrgFromSource(source) {
20280
+ if (!source || source.trim() === "") {
20281
+ return null;
20282
+ }
20283
+ const trimmedSource = source.trim();
20284
+ if (isLocalPath(trimmedSource)) {
20285
+ return null;
20286
+ }
20287
+ if (trimmedSource.startsWith("github:")) {
20288
+ return parseOrgFromPrefix(trimmedSource.slice("github:".length));
20289
+ }
20290
+ if (trimmedSource.startsWith("gh:")) {
20291
+ return parseOrgFromPrefix(trimmedSource.slice("gh:".length));
20292
+ }
20293
+ const urlMatch = trimmedSource.match(/^(?:https?:\/\/)?(?:www\.)?github\.com\/([^/]+)(?:\/|$)/);
20294
+ if (urlMatch?.[1]) {
20295
+ return validateOrg(urlMatch[1]);
20296
+ }
20297
+ if (trimmedSource.includes("/") && !trimmedSource.includes("://")) {
20298
+ const firstSlashIndex = trimmedSource.indexOf("/");
20299
+ const potentialOrg = trimmedSource.slice(0, firstSlashIndex);
20300
+ return validateOrg(potentialOrg);
20301
+ }
20302
+ return null;
20303
+ }
20304
+ function isLocalPath(source) {
20305
+ if (source.startsWith(".")) {
20306
+ return true;
20307
+ }
20308
+ if (source.startsWith("/")) {
20309
+ return true;
20310
+ }
20311
+ if (/^[a-zA-Z]:[\\/]/.test(source)) {
20312
+ return true;
20313
+ }
20314
+ if (source.includes("\\")) {
20315
+ return true;
20316
+ }
20317
+ return false;
20318
+ }
20319
+ function parseOrgFromPrefix(prefixContent) {
20320
+ const withoutBranch = prefixContent.split("#")[0] || "";
20321
+ const slashIndex = withoutBranch.indexOf("/");
20322
+ if (slashIndex === -1) {
20323
+ return null;
20324
+ }
20325
+ const org = withoutBranch.slice(0, slashIndex);
20326
+ return validateOrg(org);
20327
+ }
20328
+ function validateOrg(org) {
20329
+ if (!org || org.trim() === "") {
20330
+ return null;
20331
+ }
20332
+ const trimmedOrg = org.trim();
20333
+ const validOrgPattern = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
20334
+ if (!validOrgPattern.test(trimmedOrg)) {
20335
+ if (trimmedOrg.length === 1 && /^[a-zA-Z0-9]$/.test(trimmedOrg)) {
20336
+ return trimmedOrg;
20337
+ }
20338
+ return null;
20339
+ }
20340
+ if (trimmedOrg.includes("--")) {
20341
+ return null;
20342
+ }
20343
+ return trimmedOrg;
20344
+ }
20345
+
20346
+ // src/utils/skill-name-resolver.ts
20347
+ function getSkillKey(entry) {
20348
+ return `${entry.pluginSource}::${entry.pluginName}::${entry.folderName}`;
20349
+ }
20350
+ function getDisambiguatorPrefix(pluginSource) {
20351
+ const org = extractOrgFromSource(pluginSource);
20352
+ if (org) {
20353
+ return org;
20354
+ }
20355
+ return getShortId(pluginSource);
20356
+ }
20357
+ function resolveSkillNames(skills) {
20358
+ const resolved = [];
20359
+ const nameMap = new Map;
20360
+ const byFolderName = new Map;
20361
+ for (const skill of skills) {
20362
+ const existing = byFolderName.get(skill.folderName) || [];
20363
+ existing.push(skill);
20364
+ byFolderName.set(skill.folderName, existing);
20365
+ }
20366
+ for (const [folderName, group] of byFolderName) {
20367
+ if (group.length === 1) {
20368
+ const skill = group[0];
20369
+ if (skill) {
20370
+ const resolvedEntry = {
20371
+ original: skill,
20372
+ resolvedName: folderName,
20373
+ wasRenamed: false
20374
+ };
20375
+ resolved.push(resolvedEntry);
20376
+ nameMap.set(getSkillKey(skill), folderName);
20377
+ }
20378
+ } else {
20379
+ const byPluginName = new Map;
20380
+ for (const skill of group) {
20381
+ const existing = byPluginName.get(skill.pluginName) || [];
20382
+ existing.push(skill);
20383
+ byPluginName.set(skill.pluginName, existing);
20384
+ }
20385
+ const hasPluginNameConflict = Array.from(byPluginName.values()).some((pluginGroup) => pluginGroup.length > 1);
20386
+ if (!hasPluginNameConflict) {
20387
+ for (const skill of group) {
20388
+ const resolvedName = `${skill.pluginName}_${folderName}`;
20389
+ const resolvedEntry = {
20390
+ original: skill,
20391
+ resolvedName,
20392
+ wasRenamed: true
20393
+ };
20394
+ resolved.push(resolvedEntry);
20395
+ nameMap.set(getSkillKey(skill), resolvedName);
20396
+ }
20397
+ } else {
20398
+ for (const skill of group) {
20399
+ const prefix = getDisambiguatorPrefix(skill.pluginSource);
20400
+ const resolvedName = `${prefix}_${skill.pluginName}_${folderName}`;
20401
+ const resolvedEntry = {
20402
+ original: skill,
20403
+ resolvedName,
20404
+ wasRenamed: true
20405
+ };
20406
+ resolved.push(resolvedEntry);
20407
+ nameMap.set(getSkillKey(skill), resolvedName);
20408
+ }
20409
+ }
20410
+ }
20411
+ }
20412
+ return { resolved, nameMap };
20413
+ }
20414
+
20226
20415
  // src/core/marketplace.ts
20227
- import { mkdir as mkdir3, readFile as readFile4, readdir as readdir3, writeFile as writeFile2 } from "node:fs/promises";
20416
+ import { mkdir as mkdir3, readFile as readFile5, readdir as readdir3, writeFile as writeFile2 } from "node:fs/promises";
20228
20417
  import { existsSync as existsSync4 } from "node:fs";
20229
- import { basename, join as join5, resolve as resolve3 } from "node:path";
20418
+ import { basename as basename2, join as join5, resolve as resolve3 } from "node:path";
20230
20419
  var WELL_KNOWN_MARKETPLACES = {
20231
20420
  "claude-plugins-official": "anthropics/claude-plugins-official"
20232
20421
  };
@@ -20246,7 +20435,7 @@ async function loadRegistry() {
20246
20435
  return { version: 1, marketplaces: {} };
20247
20436
  }
20248
20437
  try {
20249
- const content = await readFile4(registryPath, "utf-8");
20438
+ const content = await readFile5(registryPath, "utf-8");
20250
20439
  return JSON.parse(content);
20251
20440
  } catch {
20252
20441
  return { version: 1, marketplaces: {} };
@@ -20285,7 +20474,7 @@ function parseMarketplaceSource(source) {
20285
20474
  }
20286
20475
  if (source.startsWith("/") || source.startsWith(".")) {
20287
20476
  const absPath = resolve3(source);
20288
- const name = basename(absPath) || "local";
20477
+ const name = basename2(absPath) || "local";
20289
20478
  return {
20290
20479
  type: "local",
20291
20480
  location: absPath,
@@ -20526,7 +20715,7 @@ function getWellKnownMarketplaces() {
20526
20715
  }
20527
20716
 
20528
20717
  // src/core/sync-state.ts
20529
- import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir4 } from "node:fs/promises";
20718
+ import { readFile as readFile6, writeFile as writeFile3, mkdir as mkdir4 } from "node:fs/promises";
20530
20719
  import { existsSync as existsSync5 } from "node:fs";
20531
20720
  import { join as join6, dirname as dirname3 } from "node:path";
20532
20721
 
@@ -20547,7 +20736,7 @@ async function loadSyncState(workspacePath) {
20547
20736
  return null;
20548
20737
  }
20549
20738
  try {
20550
- const content = await readFile5(statePath, "utf-8");
20739
+ const content = await readFile6(statePath, "utf-8");
20551
20740
  const parsed = JSON.parse(content);
20552
20741
  const result = SyncStateSchema.safeParse(parsed);
20553
20742
  if (!result.success) {
@@ -20581,7 +20770,9 @@ async function selectivePurgeWorkspace(workspacePath, state, clients) {
20581
20770
  return [];
20582
20771
  }
20583
20772
  const result = [];
20584
- for (const client of clients) {
20773
+ const previousClients = Object.keys(state.files);
20774
+ const clientsToProcess = [...new Set([...clients, ...previousClients])];
20775
+ for (const client of clientsToProcess) {
20585
20776
  const previousFiles = getPreviouslySyncedFiles(state, client);
20586
20777
  const purgedPaths = [];
20587
20778
  for (const filePath of previousFiles) {
@@ -20828,10 +21019,10 @@ async function validatePlugin(pluginSource, workspacePath, force) {
20828
21019
  async function validateAllPlugins(plugins, workspacePath, force) {
20829
21020
  return Promise.all(plugins.map((plugin) => validatePlugin(plugin, workspacePath, force)));
20830
21021
  }
20831
- async function copyValidatedPlugin(validatedPlugin, workspacePath, clients, dryRun) {
21022
+ async function copyValidatedPlugin(validatedPlugin, workspacePath, clients, dryRun, skillNameMap) {
20832
21023
  const copyResults = [];
20833
21024
  for (const client of clients) {
20834
- const results = await copyPluginToWorkspace(validatedPlugin.resolved, workspacePath, client, { dryRun });
21025
+ const results = await copyPluginToWorkspace(validatedPlugin.resolved, workspacePath, client, { dryRun, ...skillNameMap && { skillNameMap } });
20835
21026
  copyResults.push(...results);
20836
21027
  }
20837
21028
  const hasFailures = copyResults.some((r) => r.action === "failed");
@@ -20842,6 +21033,47 @@ async function copyValidatedPlugin(validatedPlugin, workspacePath, clients, dryR
20842
21033
  copyResults
20843
21034
  };
20844
21035
  }
21036
+ async function collectAllSkills(validatedPlugins) {
21037
+ const allSkills = [];
21038
+ for (const plugin of validatedPlugins) {
21039
+ const pluginName = await getPluginName(plugin.resolved);
21040
+ const skills = await collectPluginSkills(plugin.resolved, plugin.plugin);
21041
+ for (const skill of skills) {
21042
+ allSkills.push({
21043
+ folderName: skill.folderName,
21044
+ pluginName,
21045
+ pluginSource: plugin.plugin,
21046
+ pluginPath: plugin.resolved
21047
+ });
21048
+ }
21049
+ }
21050
+ return allSkills;
21051
+ }
21052
+ function buildPluginSkillNameMaps(allSkills) {
21053
+ const skillEntries = allSkills.map((skill) => ({
21054
+ folderName: skill.folderName,
21055
+ pluginName: skill.pluginName,
21056
+ pluginSource: skill.pluginSource
21057
+ }));
21058
+ const resolution = resolveSkillNames(skillEntries);
21059
+ const pluginMaps = new Map;
21060
+ for (let i2 = 0;i2 < allSkills.length; i2++) {
21061
+ const skill = allSkills[i2];
21062
+ const entry = skillEntries[i2];
21063
+ if (!skill || !entry)
21064
+ continue;
21065
+ const resolvedName = resolution.nameMap.get(getSkillKey(entry));
21066
+ if (resolvedName) {
21067
+ let pluginMap = pluginMaps.get(skill.pluginPath);
21068
+ if (!pluginMap) {
21069
+ pluginMap = new Map;
21070
+ pluginMaps.set(skill.pluginPath, pluginMap);
21071
+ }
21072
+ pluginMap.set(skill.folderName, resolvedName);
21073
+ }
21074
+ }
21075
+ return pluginMaps;
21076
+ }
20845
21077
  async function syncWorkspace(workspacePath = process.cwd(), options2 = {}) {
20846
21078
  const { force = false, dryRun = false, workspaceSourceBase } = options2;
20847
21079
  const configDir = join7(workspacePath, CONFIG_DIR);
@@ -20918,7 +21150,12 @@ ${errors2}`
20918
21150
  if (!dryRun) {
20919
21151
  await selectivePurgeWorkspace(workspacePath, previousState, config.clients);
20920
21152
  }
20921
- const pluginResults = await Promise.all(validatedPlugins.map((validatedPlugin) => copyValidatedPlugin(validatedPlugin, workspacePath, config.clients, dryRun)));
21153
+ const allSkills = await collectAllSkills(validatedPlugins);
21154
+ const pluginSkillMaps = buildPluginSkillNameMaps(allSkills);
21155
+ const pluginResults = await Promise.all(validatedPlugins.map((validatedPlugin) => {
21156
+ const skillNameMap = pluginSkillMaps.get(validatedPlugin.resolved);
21157
+ return copyValidatedPlugin(validatedPlugin, workspacePath, config.clients, dryRun, skillNameMap);
21158
+ }));
20922
21159
  let workspaceFileResults = [];
20923
21160
  if (config.workspace) {
20924
21161
  const sourcePath = validatedWorkspaceSource?.resolved;
@@ -21010,7 +21247,7 @@ ${fileValidationErrors.map((e) => ` - ${e}`).join(`
21010
21247
  }
21011
21248
  }
21012
21249
  const hasFailures = pluginResults.some((r) => !r.success) || totalFailed > 0;
21013
- if (!hasFailures && !dryRun) {
21250
+ if (!dryRun) {
21014
21251
  const allCopyResults = [
21015
21252
  ...pluginResults.flatMap((r) => r.copyResults),
21016
21253
  ...workspaceFileResults
@@ -21298,7 +21535,7 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
21298
21535
  sourceDir = parentDir;
21299
21536
  }
21300
21537
  }
21301
- workspaceYamlContent = await readFile6(sourceYamlPath, "utf-8");
21538
+ workspaceYamlContent = await readFile7(sourceYamlPath, "utf-8");
21302
21539
  if (sourceDir) {
21303
21540
  const parsed2 = load(workspaceYamlContent);
21304
21541
  const workspace = parsed2?.workspace;
@@ -21317,7 +21554,7 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
21317
21554
  if (!existsSync7(defaultYamlPath)) {
21318
21555
  throw new Error(`Default template not found at: ${defaultTemplatePath}`);
21319
21556
  }
21320
- workspaceYamlContent = await readFile6(defaultYamlPath, "utf-8");
21557
+ workspaceYamlContent = await readFile7(defaultYamlPath, "utf-8");
21321
21558
  }
21322
21559
  await writeFile4(configPath, workspaceYamlContent, "utf-8");
21323
21560
  const copiedAgentFiles = [];
@@ -21339,7 +21576,7 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
21339
21576
  for (const agentFile of AGENT_FILES) {
21340
21577
  const sourcePath = join8(effectiveSourceDir, agentFile);
21341
21578
  if (existsSync7(sourcePath)) {
21342
- const content = await readFile6(sourcePath, "utf-8");
21579
+ const content = await readFile7(sourcePath, "utf-8");
21343
21580
  await writeFile4(join8(absoluteTarget, agentFile), content, "utf-8");
21344
21581
  copiedAgentFiles.push(agentFile);
21345
21582
  }
@@ -21449,7 +21686,7 @@ function getPluginStatus(parsed) {
21449
21686
  }
21450
21687
 
21451
21688
  // src/core/workspace-modify.ts
21452
- import { readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
21689
+ import { readFile as readFile8, writeFile as writeFile5 } from "node:fs/promises";
21453
21690
  import { existsSync as existsSync9 } from "node:fs";
21454
21691
  import { join as join10 } from "node:path";
21455
21692
  async function addPlugin(plugin, workspacePath = process.cwd()) {
@@ -21565,7 +21802,7 @@ async function ensureMarketplaceRegistered(spec) {
21565
21802
  }
21566
21803
  async function addPluginToConfig(plugin, configPath, autoRegistered) {
21567
21804
  try {
21568
- const content = await readFile7(configPath, "utf-8");
21805
+ const content = await readFile8(configPath, "utf-8");
21569
21806
  const config = load(content);
21570
21807
  if (config.plugins.includes(plugin)) {
21571
21808
  return {
@@ -21597,7 +21834,7 @@ async function removePlugin(plugin, workspacePath = process.cwd()) {
21597
21834
  };
21598
21835
  }
21599
21836
  try {
21600
- const content = await readFile7(configPath, "utf-8");
21837
+ const content = await readFile8(configPath, "utf-8");
21601
21838
  const config = load(content);
21602
21839
  let index = config.plugins.indexOf(plugin);
21603
21840
  if (index === -1 && isPluginSpec(plugin) === false) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allagents",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "CLI tool for managing multi-repo AI agent workspaces with plugin synchronization",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "docs:install": "bun install --cwd docs",
15
15
  "docs:build": "bun run --cwd docs build",
16
16
  "dev": "bun run src/cli/index.ts",
17
- "test": "bun test tests/unit/validators tests/unit/utils tests/unit/models && bun test tests/unit/core/marketplace.test.ts tests/unit/core/sync.test.ts tests/unit/core/transform-glob.test.ts tests/unit/core/github-fetch.test.ts && bun test tests/unit/core/plugin.test.ts",
17
+ "test": "bun test",
18
18
  "test:watch": "bun test --watch",
19
19
  "test:coverage": "bun test --coverage",
20
20
  "test:integration": "bats tests/integration/*.bats",
@@ -24,7 +24,8 @@
24
24
  "format": "biome format --write src",
25
25
  "check": "biome check src",
26
26
  "check:fix": "biome check --write src",
27
- "prepare": "bun run build && (test -d .git && bunx prek install -t pre-push || true)"
27
+ "prepare": "bun run build && (test -d .git && bunx prek install -t pre-push || true)",
28
+ "release": "bun run scripts/release.ts"
28
29
  },
29
30
  "keywords": [
30
31
  "cli",