omniagent 0.1.5 → 0.1.6

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/cli.js CHANGED
@@ -38,7 +38,7 @@ async function findRepoRoot(startDir) {
38
38
  }
39
39
  return await findUp(startDir, "package.json");
40
40
  }
41
- function hashIdentifier$3(value) {
41
+ function hashIdentifier$4(value) {
42
42
  return createHash("sha256").update(value).digest("hex");
43
43
  }
44
44
  async function pathExists$1(candidate) {
@@ -72,7 +72,7 @@ async function listRepoSlashCommandManifestPaths(repoRoot) {
72
72
  return matches;
73
73
  }
74
74
  function resolveRepoScopedStatePaths(repoRoot, homeDir) {
75
- const repoHash = hashIdentifier$3(repoRoot);
75
+ const repoHash = hashIdentifier$4(repoRoot);
76
76
  return [
77
77
  path.join(homeDir, ".omniagent", "state", "managed-outputs", "projects", repoHash),
78
78
  path.join(homeDir, ".omniagent", "state", "instructions", "projects", repoHash),
@@ -333,11 +333,20 @@ function matchAny(name, patterns) {
333
333
  }
334
334
  return matched;
335
335
  }
336
+ function normalizeItemSelection(item) {
337
+ if (!item) {
338
+ return { canonicalName: "", enabledByDefault: true };
339
+ }
340
+ if (typeof item === "string") {
341
+ return { canonicalName: item, enabledByDefault: true };
342
+ }
343
+ return item;
344
+ }
336
345
  function createProfileItemFilter(resolved) {
337
346
  if (!resolved || resolved.names.length === 0) {
338
347
  return {
339
348
  enabled: false,
340
- includes: () => true,
349
+ includes: (_category, item) => normalizeItemSelection(item).enabledByDefault,
341
350
  collectUnknownWarnings: () => []
342
351
  };
343
352
  }
@@ -349,17 +358,20 @@ function createProfileItemFilter(resolved) {
349
358
  }
350
359
  return {
351
360
  enabled: true,
352
- includes(category, canonicalName) {
361
+ includes(category, item) {
362
+ const { canonicalName, enabledByDefault } = normalizeItemSelection(item);
353
363
  const enablePatterns = enablePatternsByCategory.get(category) ?? [];
354
364
  const disablePatterns = disablePatternsByCategory.get(category) ?? [];
355
365
  const enableApplies = enablePatterns.length > 0;
356
- if (enableApplies && !matchAny(canonicalName, enablePatterns)) {
366
+ const enableMatches = matchAny(canonicalName, enablePatterns);
367
+ const disableMatches = matchAny(canonicalName, disablePatterns);
368
+ if (disableMatches) {
357
369
  return false;
358
370
  }
359
- if (matchAny(canonicalName, disablePatterns)) {
360
- return false;
371
+ if (enableApplies) {
372
+ return enableMatches;
361
373
  }
362
- return true;
374
+ return enabledByDefault;
363
375
  },
364
376
  collectUnknownWarnings() {
365
377
  const warnings = [];
@@ -976,6 +988,28 @@ async function listSkillDirectories(root) {
976
988
  }
977
989
  return directories;
978
990
  }
991
+ const SYNC_ROUTING_FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["targets", "targetagents", "enabled"]);
992
+ function resolveFrontmatterEnabledByDefault(options) {
993
+ const rawEnabled = options.frontmatter.enabled;
994
+ if (rawEnabled === void 0) {
995
+ return true;
996
+ }
997
+ if (Array.isArray(rawEnabled)) {
998
+ throw new Error(
999
+ `${options.itemKind} "${options.itemName}" has invalid enabled value in ${options.sourcePath}. Expected true or false.`
1000
+ );
1001
+ }
1002
+ const normalized = rawEnabled.trim().toLowerCase();
1003
+ if (normalized === "true") {
1004
+ return true;
1005
+ }
1006
+ if (normalized === "false") {
1007
+ return false;
1008
+ }
1009
+ throw new Error(
1010
+ `${options.itemKind} "${options.itemName}" has invalid enabled value "${rawEnabled}" in ${options.sourcePath}. Expected true or false.`
1011
+ );
1012
+ }
979
1013
  function resolveLocalPrecedence(options) {
980
1014
  const local = [...options.localPath, ...options.localSuffix];
981
1015
  const localPathKeys = new Set(options.localPath.map(options.key));
@@ -1389,7 +1423,6 @@ function stripFrontmatterFields(contents, keysToRemove) {
1389
1423
  const outputLines = [lines[0], ...filtered, ...lines.slice(endIndex)];
1390
1424
  return outputLines.join(eol);
1391
1425
  }
1392
- const TARGET_FRONTMATTER_KEYS$3 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
1393
1426
  function isSlashCommandLike(value) {
1394
1427
  if (!value || typeof value !== "object") {
1395
1428
  return false;
@@ -1459,7 +1492,7 @@ const copilotTarget = {
1459
1492
  outputs: [
1460
1493
  {
1461
1494
  outputPath: agentPath,
1462
- content: stripFrontmatterFields(item.rawContents, TARGET_FRONTMATTER_KEYS$3)
1495
+ content: stripFrontmatterFields(item.rawContents, SYNC_ROUTING_FRONTMATTER_KEYS)
1463
1496
  },
1464
1497
  {
1465
1498
  outputPath: promptPath,
@@ -1534,7 +1567,7 @@ const BUILTIN_TARGETS = [
1534
1567
  copilotTarget
1535
1568
  ];
1536
1569
  Object.freeze(BUILTIN_TARGETS.map((target) => target.id));
1537
- function resolveSkillName(frontmatter, fallback) {
1570
+ function resolveSkillName$1(frontmatter, fallback) {
1538
1571
  const rawName = frontmatter.name;
1539
1572
  if (typeof rawName === "string") {
1540
1573
  const trimmed = rawName.trim();
@@ -1547,7 +1580,7 @@ function resolveSkillName(frontmatter, fallback) {
1547
1580
  function normalizeSkillKey$1(relativePath) {
1548
1581
  return path.normalize(relativePath).replace(/\\/g, "/").toLowerCase();
1549
1582
  }
1550
- function resolveSkillRelativePath(skillsRoot, directoryPath) {
1583
+ function resolveSkillRelativePath$1(skillsRoot, directoryPath) {
1551
1584
  const relativePath = path.relative(skillsRoot, directoryPath);
1552
1585
  if (!relativePath) {
1553
1586
  return { relativePath, hadLocalSuffix: false };
@@ -1561,6 +1594,16 @@ function resolveSkillRelativePath(skillsRoot, directoryPath) {
1561
1594
  const normalized = parent === "." ? strippedBase : path.join(parent, strippedBase);
1562
1595
  return { relativePath: normalized, hadLocalSuffix: true };
1563
1596
  }
1597
+ function resolveSkillRoutingError(options) {
1598
+ if (options.invalidTargets.length > 0) {
1599
+ const invalidList = options.invalidTargets.join(", ");
1600
+ return `Skill "${options.name}" has unsupported targets (${invalidList}) in ${options.sourcePath}.`;
1601
+ }
1602
+ if (hasRawTargetValues(options.rawTargets) && (!options.targets || options.targets.length === 0)) {
1603
+ return `Skill "${options.name}" has empty targets in ${options.sourcePath}.`;
1604
+ }
1605
+ return null;
1606
+ }
1564
1607
  async function buildSkillDefinition(options) {
1565
1608
  let metadata;
1566
1609
  if (options.sourceType === "local") {
@@ -1576,24 +1619,32 @@ async function buildSkillDefinition(options) {
1576
1619
  const rawContents = await readFile(sourcePath, "utf8");
1577
1620
  const { frontmatter, body } = extractFrontmatter$1(rawContents);
1578
1621
  const relativePath = options.relativePath ?? path.relative(options.skillsRoot, options.directoryPath);
1579
- const name = resolveSkillName(frontmatter, relativePath || path.basename(options.directoryPath));
1622
+ const name = resolveSkillName$1(frontmatter, relativePath || path.basename(options.directoryPath));
1623
+ const enabledByDefault = resolveFrontmatterEnabledByDefault({
1624
+ frontmatter,
1625
+ itemKind: "Skill",
1626
+ itemName: name,
1627
+ sourcePath
1628
+ });
1580
1629
  const rawTargets = [frontmatter.targets, frontmatter.targetAgents];
1581
1630
  const { targets, invalidTargets } = resolveFrontmatterTargets(
1582
1631
  rawTargets,
1583
1632
  options.resolveTargetName
1584
1633
  );
1585
- if (invalidTargets.length > 0) {
1586
- const invalidList = invalidTargets.join(", ");
1587
- throw new InvalidFrontmatterTargetsError(
1588
- `Skill "${name}" has unsupported targets (${invalidList}) in ${sourcePath}.`
1589
- );
1590
- }
1591
- if (hasRawTargetValues(rawTargets) && (!targets || targets.length === 0)) {
1592
- throw new InvalidFrontmatterTargetsError(`Skill "${name}" has empty targets in ${sourcePath}.`);
1634
+ const routingError = resolveSkillRoutingError({
1635
+ name,
1636
+ sourcePath,
1637
+ rawTargets,
1638
+ targets,
1639
+ invalidTargets
1640
+ });
1641
+ if (enabledByDefault && routingError) {
1642
+ throw new InvalidFrontmatterTargetsError(routingError);
1593
1643
  }
1594
1644
  const { outputFileName } = stripLocalSuffix(options.skillFileName, ".md");
1595
1645
  return {
1596
1646
  name,
1647
+ enabledByDefault,
1597
1648
  relativePath,
1598
1649
  directoryPath: options.directoryPath,
1599
1650
  sourcePath,
@@ -1606,9 +1657,15 @@ async function buildSkillDefinition(options) {
1606
1657
  frontmatter,
1607
1658
  body,
1608
1659
  targetAgents: targets,
1609
- invalidTargets
1660
+ invalidTargets,
1661
+ routingError
1610
1662
  };
1611
1663
  }
1664
+ function assertSkillDefinitionUsable(skill) {
1665
+ if (skill.routingError) {
1666
+ throw new InvalidFrontmatterTargetsError(skill.routingError);
1667
+ }
1668
+ }
1612
1669
  async function loadSkillCatalog(repoRoot, options = {}) {
1613
1670
  const includeLocal = options.includeLocal ?? true;
1614
1671
  const fallbackResolver = createTargetNameResolver(BUILTIN_TARGETS).resolveTargetName;
@@ -1629,7 +1686,7 @@ async function loadSkillCatalog(repoRoot, options = {}) {
1629
1686
  const localPathSkills = [];
1630
1687
  const localSuffixSkills = [];
1631
1688
  for (const entry2 of sharedEntries) {
1632
- const { relativePath, hadLocalSuffix } = resolveSkillRelativePath(
1689
+ const { relativePath, hadLocalSuffix } = resolveSkillRelativePath$1(
1633
1690
  skillsRoot,
1634
1691
  entry2.directoryPath
1635
1692
  );
@@ -1686,7 +1743,7 @@ async function loadSkillCatalog(repoRoot, options = {}) {
1686
1743
  if (!skillFileName) {
1687
1744
  continue;
1688
1745
  }
1689
- const { relativePath } = resolveSkillRelativePath(localSkillsRoot, entry2.directoryPath);
1746
+ const { relativePath } = resolveSkillRelativePath$1(localSkillsRoot, entry2.directoryPath);
1690
1747
  localPathSkills.push(
1691
1748
  await buildSkillDefinition({
1692
1749
  directoryPath: entry2.directoryPath,
@@ -1740,7 +1797,13 @@ async function buildCommandDefinition(options) {
1740
1797
  const contents = await readFile(options.filePath, "utf8");
1741
1798
  const { frontmatter, body } = extractFrontmatter$1(contents);
1742
1799
  const prompt = body.trimEnd();
1743
- if (!prompt.trim()) {
1800
+ const enabledByDefault = resolveFrontmatterEnabledByDefault({
1801
+ frontmatter,
1802
+ itemKind: "Slash command",
1803
+ itemName: options.commandName,
1804
+ sourcePath: options.filePath
1805
+ });
1806
+ if (enabledByDefault && !prompt.trim()) {
1744
1807
  throw new Error(`Slash command "${options.commandName}" has an empty prompt.`);
1745
1808
  }
1746
1809
  const rawTargets = [frontmatter.targets, frontmatter.targetAgents];
@@ -1748,16 +1811,15 @@ async function buildCommandDefinition(options) {
1748
1811
  rawTargets,
1749
1812
  options.resolveTargetName
1750
1813
  );
1814
+ let routingError = null;
1751
1815
  if (invalidTargets.length > 0) {
1752
1816
  const invalidList = invalidTargets.join(", ");
1753
- throw new InvalidFrontmatterTargetsError(
1754
- `Slash command "${options.commandName}" has unsupported targets (${invalidList}) in ${options.filePath}.`
1755
- );
1817
+ routingError = `Slash command "${options.commandName}" has unsupported targets (${invalidList}) in ${options.filePath}.`;
1818
+ } else if (hasRawTargetValues(rawTargets) && (!targets || targets.length === 0)) {
1819
+ routingError = `Slash command "${options.commandName}" has empty targets in ${options.filePath}.`;
1756
1820
  }
1757
- if (hasRawTargetValues(rawTargets) && (!targets || targets.length === 0)) {
1758
- throw new InvalidFrontmatterTargetsError(
1759
- `Slash command "${options.commandName}" has empty targets in ${options.filePath}.`
1760
- );
1821
+ if (enabledByDefault && routingError) {
1822
+ throw new InvalidFrontmatterTargetsError(routingError);
1761
1823
  }
1762
1824
  let metadata;
1763
1825
  if (options.sourceType === "local") {
@@ -1771,6 +1833,7 @@ async function buildCommandDefinition(options) {
1771
1833
  }
1772
1834
  return {
1773
1835
  name: options.commandName,
1836
+ enabledByDefault,
1774
1837
  prompt,
1775
1838
  sourcePath: options.filePath,
1776
1839
  sourceType: metadata.sourceType,
@@ -1779,9 +1842,18 @@ async function buildCommandDefinition(options) {
1779
1842
  rawContents: contents,
1780
1843
  targetAgents: targets,
1781
1844
  invalidTargets,
1782
- frontmatter
1845
+ frontmatter,
1846
+ routingError
1783
1847
  };
1784
1848
  }
1849
+ function assertSlashCommandDefinitionUsable(command) {
1850
+ if (!command.prompt.trim()) {
1851
+ throw new Error(`Slash command "${command.name}" has an empty prompt.`);
1852
+ }
1853
+ if (command.routingError) {
1854
+ throw new InvalidFrontmatterTargetsError(command.routingError);
1855
+ }
1856
+ }
1785
1857
  function registerUniqueName$1(seen, commandName, filePath) {
1786
1858
  const lowerName = normalizeName(commandName);
1787
1859
  if (seen.has(lowerName)) {
@@ -2003,9 +2075,6 @@ async function buildSubagentDefinition(options) {
2003
2075
  const message = error instanceof Error ? error.message : String(error);
2004
2076
  throw new Error(`Invalid frontmatter in ${options.filePath}: ${message}`);
2005
2077
  }
2006
- if (!body.trim()) {
2007
- throw new Error(`Subagent file has empty body: ${options.filePath}.`);
2008
- }
2009
2078
  let resolvedName;
2010
2079
  try {
2011
2080
  resolvedName = resolveSubagentName(frontmatter, options.fileName);
@@ -2013,21 +2082,29 @@ async function buildSubagentDefinition(options) {
2013
2082
  const message = error instanceof Error ? error.message : String(error);
2014
2083
  throw new Error(`Invalid frontmatter in ${options.filePath}: ${message}`);
2015
2084
  }
2085
+ const enabledByDefault = resolveFrontmatterEnabledByDefault({
2086
+ frontmatter,
2087
+ itemKind: "Subagent",
2088
+ itemName: resolvedName,
2089
+ sourcePath: options.filePath
2090
+ });
2091
+ if (enabledByDefault && !body.trim()) {
2092
+ throw new Error(`Subagent file has empty body: ${options.filePath}.`);
2093
+ }
2016
2094
  const rawTargets = [frontmatter.targets, frontmatter.targetAgents];
2017
2095
  const { targets, invalidTargets } = resolveFrontmatterTargets(
2018
2096
  rawTargets,
2019
2097
  options.resolveTargetName
2020
2098
  );
2099
+ let routingError = null;
2021
2100
  if (invalidTargets.length > 0) {
2022
2101
  const invalidList = invalidTargets.join(", ");
2023
- throw new InvalidFrontmatterTargetsError(
2024
- `Subagent "${resolvedName}" has unsupported targets (${invalidList}) in ${options.filePath}.`
2025
- );
2102
+ routingError = `Subagent "${resolvedName}" has unsupported targets (${invalidList}) in ${options.filePath}.`;
2103
+ } else if (hasRawTargetValues(rawTargets) && (!targets || targets.length === 0)) {
2104
+ routingError = `Subagent "${resolvedName}" has empty targets in ${options.filePath}.`;
2026
2105
  }
2027
- if (hasRawTargetValues(rawTargets) && (!targets || targets.length === 0)) {
2028
- throw new InvalidFrontmatterTargetsError(
2029
- `Subagent "${resolvedName}" has empty targets in ${options.filePath}.`
2030
- );
2106
+ if (enabledByDefault && routingError) {
2107
+ throw new InvalidFrontmatterTargetsError(routingError);
2031
2108
  }
2032
2109
  let metadata;
2033
2110
  if (options.sourceType === "local") {
@@ -2041,6 +2118,7 @@ async function buildSubagentDefinition(options) {
2041
2118
  }
2042
2119
  return {
2043
2120
  resolvedName,
2121
+ enabledByDefault,
2044
2122
  sourcePath: options.filePath,
2045
2123
  fileName: options.fileName,
2046
2124
  sourceType: metadata.sourceType,
@@ -2050,9 +2128,18 @@ async function buildSubagentDefinition(options) {
2050
2128
  frontmatter,
2051
2129
  body,
2052
2130
  targetAgents: targets,
2053
- invalidTargets
2131
+ invalidTargets,
2132
+ routingError
2054
2133
  };
2055
2134
  }
2135
+ function assertSubagentDefinitionUsable(subagent) {
2136
+ if (!subagent.body.trim()) {
2137
+ throw new Error(`Subagent file has empty body: ${subagent.sourcePath}.`);
2138
+ }
2139
+ if (subagent.routingError) {
2140
+ throw new InvalidFrontmatterTargetsError(subagent.routingError);
2141
+ }
2142
+ }
2056
2143
  function registerUniqueName(seen, resolvedName, filePath) {
2057
2144
  const nameKey = normalizeName(resolvedName);
2058
2145
  const existingPath = seen.get(nameKey);
@@ -2863,23 +2950,64 @@ async function loadProfileValidationCatalog(repoRoot, agentsDir) {
2863
2950
  ]);
2864
2951
  return {
2865
2952
  resolveTargetName,
2866
- skillNames: skillCatalog.skills.map((skill) => skill.name),
2867
- commandNames: commandCatalog.commands.map((command) => command.name),
2868
- subagentNames: subagentCatalog.subagents.map((subagent) => subagent.resolvedName)
2953
+ skills: skillCatalog.skills,
2954
+ commands: commandCatalog.commands,
2955
+ subagents: subagentCatalog.subagents
2869
2956
  };
2870
2957
  }
2871
2958
  function collectProfileReferenceIssues(profileName, resolvedProfile, catalog) {
2872
2959
  const filter = createProfileItemFilter(resolvedProfile);
2873
- for (const skillName of catalog.skillNames) {
2874
- filter.includes("skills", skillName);
2960
+ const issues = [];
2961
+ for (const skill of catalog.skills) {
2962
+ const included = filter.includes("skills", {
2963
+ canonicalName: skill.name,
2964
+ enabledByDefault: skill.enabledByDefault
2965
+ });
2966
+ if (!included) {
2967
+ continue;
2968
+ }
2969
+ try {
2970
+ assertSkillDefinitionUsable(skill);
2971
+ } catch (error) {
2972
+ const message = error instanceof Error ? error.message : String(error);
2973
+ issues.push(`profile "${profileName}" includes unusable skill "${skill.name}": ${message}`);
2974
+ }
2875
2975
  }
2876
- for (const commandName of catalog.commandNames) {
2877
- filter.includes("commands", commandName);
2976
+ for (const command of catalog.commands) {
2977
+ const included = filter.includes("commands", {
2978
+ canonicalName: command.name,
2979
+ enabledByDefault: command.enabledByDefault
2980
+ });
2981
+ if (!included) {
2982
+ continue;
2983
+ }
2984
+ try {
2985
+ assertSlashCommandDefinitionUsable(command);
2986
+ } catch (error) {
2987
+ const message = error instanceof Error ? error.message : String(error);
2988
+ issues.push(
2989
+ `profile "${profileName}" includes unusable command "${command.name}": ${message}`
2990
+ );
2991
+ }
2878
2992
  }
2879
- for (const subagentName of catalog.subagentNames) {
2880
- filter.includes("subagents", subagentName);
2993
+ for (const subagent of catalog.subagents) {
2994
+ const included = filter.includes("subagents", {
2995
+ canonicalName: subagent.resolvedName,
2996
+ enabledByDefault: subagent.enabledByDefault
2997
+ });
2998
+ if (!included) {
2999
+ continue;
3000
+ }
3001
+ try {
3002
+ assertSubagentDefinitionUsable(subagent);
3003
+ } catch (error) {
3004
+ const message = error instanceof Error ? error.message : String(error);
3005
+ issues.push(
3006
+ `profile "${profileName}" includes unusable subagent "${subagent.resolvedName}": ${message}`
3007
+ );
3008
+ }
2881
3009
  }
2882
- const issues = filter.collectUnknownWarnings();
3010
+ issues.push(...filter.collectUnknownWarnings());
2883
3011
  for (const targetName of Object.keys(resolvedProfile.targets)) {
2884
3012
  if (catalog.resolveTargetName(targetName)) {
2885
3013
  continue;
@@ -3232,11 +3360,11 @@ function applyAgentTemplating(options) {
3232
3360
  sourcePath: options.sourcePath
3233
3361
  });
3234
3362
  }
3235
- function hashIdentifier$2(value) {
3363
+ function hashIdentifier$3(value) {
3236
3364
  return createHash("sha256").update(value).digest("hex");
3237
3365
  }
3238
3366
  function resolveIgnorePreferencePath(repoRoot, homeDir = os.homedir()) {
3239
- const repoHash = hashIdentifier$2(repoRoot);
3367
+ const repoHash = hashIdentifier$3(repoRoot);
3240
3368
  return path.join(homeDir, ".omniagent", "state", "ignore-rules", "projects", `${repoHash}.json`);
3241
3369
  }
3242
3370
  async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
@@ -3248,7 +3376,7 @@ async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
3248
3376
  return null;
3249
3377
  }
3250
3378
  return {
3251
- projectId: parsed.projectId ?? hashIdentifier$2(repoRoot),
3379
+ projectId: parsed.projectId ?? hashIdentifier$3(repoRoot),
3252
3380
  ignorePromptDeclined: parsed.ignorePromptDeclined,
3253
3381
  updatedAt: parsed.updatedAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
3254
3382
  };
@@ -3263,7 +3391,7 @@ async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
3263
3391
  async function recordIgnorePromptDeclined(repoRoot, homeDir = os.homedir()) {
3264
3392
  const filePath = resolveIgnorePreferencePath(repoRoot, homeDir);
3265
3393
  const preference = {
3266
- projectId: hashIdentifier$2(repoRoot),
3394
+ projectId: hashIdentifier$3(repoRoot),
3267
3395
  ignorePromptDeclined: true,
3268
3396
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3269
3397
  };
@@ -3957,7 +4085,7 @@ async function runConvertHook(hooks, stage, context) {
3957
4085
  }
3958
4086
  await runHook(hooks[stage], context);
3959
4087
  }
3960
- function hashIdentifier$1(value) {
4088
+ function hashIdentifier$2(value) {
3961
4089
  return createHash("sha256").update(value).digest("hex");
3962
4090
  }
3963
4091
  function hashContent$1(value) {
@@ -4018,7 +4146,7 @@ async function hashOutputPath(outputPath) {
4018
4146
  }
4019
4147
  }
4020
4148
  function resolveManagedOutputsPath(repoRoot, homeDir = os.homedir()) {
4021
- const repoHash = hashIdentifier$1(repoRoot);
4149
+ const repoHash = hashIdentifier$2(repoRoot);
4022
4150
  const baseDir = path.join(
4023
4151
  homeDir,
4024
4152
  ".omniagent",
@@ -4547,9 +4675,8 @@ function listTemplateScriptExecutions(runtime) {
4547
4675
  );
4548
4676
  }
4549
4677
  const utf8Decoder$1 = new TextDecoder("utf-8", { fatal: true });
4550
- const TARGET_FRONTMATTER_KEYS$2 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
4551
4678
  const SKILL_FRONTMATTER_KEYS_TO_REMOVE = /* @__PURE__ */ new Set([
4552
- ...TARGET_FRONTMATTER_KEYS$2,
4679
+ ...SYNC_ROUTING_FRONTMATTER_KEYS,
4553
4680
  "tools",
4554
4681
  "model",
4555
4682
  "color"
@@ -4741,7 +4868,7 @@ async function copySkillDirectory(options) {
4741
4868
  validAgents: options.validAgents,
4742
4869
  sourcePath: winner.sourcePath
4743
4870
  });
4744
- const output = winner.isSkillFile ? stripFrontmatterFields(templated, TARGET_FRONTMATTER_KEYS$2) : templated;
4871
+ const output = winner.isSkillFile ? stripFrontmatterFields(templated, SYNC_ROUTING_FRONTMATTER_KEYS) : templated;
4745
4872
  await mkdir(path.dirname(winner.destinationPath), { recursive: true });
4746
4873
  await writeFile(winner.destinationPath, output, "utf8");
4747
4874
  }
@@ -4785,7 +4912,7 @@ const defaultSubagentWriter = {
4785
4912
  validAgents: options.context.validAgents,
4786
4913
  sourcePath: item.sourcePath
4787
4914
  });
4788
- const cleaned = item.outputKind === "skill" ? stripFrontmatterFields(templated, SKILL_FRONTMATTER_KEYS_TO_REMOVE) : stripFrontmatterFields(templated, TARGET_FRONTMATTER_KEYS$2);
4915
+ const cleaned = item.outputKind === "skill" ? stripFrontmatterFields(templated, SKILL_FRONTMATTER_KEYS_TO_REMOVE) : stripFrontmatterFields(templated, SYNC_ROUTING_FRONTMATTER_KEYS);
4789
4916
  if (item.outputKind === "skill") {
4790
4917
  const destinationPath = path.join(options.outputPath, "SKILL.md");
4791
4918
  return writeOutputFile(destinationPath, cleaned);
@@ -4806,16 +4933,16 @@ const defaultInstructionWriter = {
4806
4933
  async function writeFileOutput(outputPath, content) {
4807
4934
  return writeOutputFile(outputPath, content);
4808
4935
  }
4809
- function hashIdentifier(value) {
4936
+ function hashIdentifier$1(value) {
4810
4937
  return createHash("sha256").update(value).digest("hex");
4811
4938
  }
4812
- function resolveManifestPath(repoRoot, homeDir = os.homedir()) {
4813
- const repoHash = hashIdentifier(repoRoot);
4939
+ function resolveManifestPath$1(repoRoot, homeDir = os.homedir()) {
4940
+ const repoHash = hashIdentifier$1(repoRoot);
4814
4941
  const baseDir = path.join(homeDir, ".omniagent", "state", "instructions", "projects", repoHash);
4815
4942
  return path.join(baseDir, "instruction-outputs.json");
4816
4943
  }
4817
- async function readManifest(repoRoot, homeDir) {
4818
- const manifestPath = resolveManifestPath(repoRoot, homeDir);
4944
+ async function readManifest$1(repoRoot, homeDir) {
4945
+ const manifestPath = resolveManifestPath$1(repoRoot, homeDir);
4819
4946
  try {
4820
4947
  const contents = await readFile(manifestPath, "utf8");
4821
4948
  const parsed = JSON.parse(contents);
@@ -4828,7 +4955,7 @@ async function readManifest(repoRoot, homeDir) {
4828
4955
  }
4829
4956
  }
4830
4957
  async function writeManifest(repoRoot, manifest, homeDir) {
4831
- const manifestPath = resolveManifestPath(repoRoot, homeDir);
4958
+ const manifestPath = resolveManifestPath$1(repoRoot, homeDir);
4832
4959
  const sorted = [...manifest.entries].sort((left, right) => {
4833
4960
  const targetCompare = left.targetName.localeCompare(right.targetName);
4834
4961
  if (targetCompare !== 0) {
@@ -5397,7 +5524,7 @@ async function syncInstructions(request) {
5397
5524
  groupResult.hadFailure = true;
5398
5525
  }
5399
5526
  }
5400
- const previousManifest = await readManifest(request.repoRoot) ?? { entries: [] };
5527
+ const previousManifest = await readManifest$1(request.repoRoot) ?? { entries: [] };
5401
5528
  const previousEntries = /* @__PURE__ */ new Map();
5402
5529
  for (const entry2 of previousManifest.entries) {
5403
5530
  const group = resolveInstructionTargetGroup(entry2.targetName);
@@ -5649,6 +5776,9 @@ function formatDisplayPath$3(repoRoot, absolutePath) {
5649
5776
  const isWithinRepo = relative && !relative.startsWith("..") && !path.isAbsolute(relative);
5650
5777
  return isWithinRepo ? relative : absolutePath;
5651
5778
  }
5779
+ function buildManagedOutputPathKey(entry2) {
5780
+ return `${entry2.targetId}:${normalizeManagedOutputPath(entry2.outputPath)}`;
5781
+ }
5652
5782
  function buildInvalidTargetWarnings$2(skills) {
5653
5783
  const warnings = [];
5654
5784
  for (const skill of skills) {
@@ -5662,6 +5792,20 @@ function buildInvalidTargetWarnings$2(skills) {
5662
5792
  }
5663
5793
  return warnings;
5664
5794
  }
5795
+ function assertUsableSkillsForTargets(options) {
5796
+ for (const skill of options.skills) {
5797
+ const effectiveTargets = resolveEffectiveTargets({
5798
+ defaultTargets: skill.targetAgents,
5799
+ overrideOnly: options.overrideOnly ?? void 0,
5800
+ overrideSkip: options.overrideSkip ?? void 0,
5801
+ allTargets: options.allTargets
5802
+ });
5803
+ if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
5804
+ continue;
5805
+ }
5806
+ assertSkillDefinitionUsable(skill);
5807
+ }
5808
+ }
5665
5809
  async function syncSkills(request) {
5666
5810
  const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
5667
5811
  const sourcePath = resolveSharedCategoryRoot(request.repoRoot, "skills", request.agentsDir);
@@ -5680,17 +5824,25 @@ async function syncSkills(request) {
5680
5824
  agentsDir: request.agentsDir,
5681
5825
  resolveTargetName: request.resolveTargetName
5682
5826
  });
5683
- if (request.includeItem) {
5684
- const includeItem = request.includeItem;
5685
- const predicate = (skill) => includeItem(skill.name);
5686
- catalog.skills = catalog.skills.filter(predicate);
5687
- catalog.sharedSkills = catalog.sharedSkills.filter(predicate);
5688
- catalog.localSkills = catalog.localSkills.filter(predicate);
5689
- catalog.localEffectiveSkills = catalog.localEffectiveSkills.filter(predicate);
5690
- }
5691
- const warnings = buildInvalidTargetWarnings$2(catalog.skills);
5827
+ const includeItem = request.includeItem;
5828
+ const predicate = (skill) => includeItem ? includeItem({
5829
+ canonicalName: skill.name,
5830
+ enabledByDefault: skill.enabledByDefault
5831
+ }) : skill.enabledByDefault;
5832
+ catalog.skills = catalog.skills.filter(predicate);
5833
+ catalog.sharedSkills = catalog.sharedSkills.filter(predicate);
5834
+ catalog.localSkills = catalog.localSkills.filter(predicate);
5835
+ catalog.localEffectiveSkills = catalog.localEffectiveSkills.filter(predicate);
5692
5836
  const allTargetIds = request.targets.map((target) => target.id);
5693
5837
  const targetNames = new Set(skillTargets.map((target) => target.id));
5838
+ assertUsableSkillsForTargets({
5839
+ skills: catalog.skills,
5840
+ activeTargetIds: targetNames,
5841
+ overrideOnly: request.overrideOnly,
5842
+ overrideSkip: request.overrideSkip,
5843
+ allTargets: allTargetIds
5844
+ });
5845
+ const warnings = buildInvalidTargetWarnings$2(catalog.skills);
5694
5846
  const effectiveTargetsBySkill = /* @__PURE__ */ new Map();
5695
5847
  const activeSourcesByTarget = /* @__PURE__ */ new Map();
5696
5848
  for (const skill of catalog.skills) {
@@ -5950,7 +6102,13 @@ async function syncSkills(request) {
5950
6102
  if (managedManifest.entries.length > 0 || nextManaged.size > 0) {
5951
6103
  const updatedEntries = [];
5952
6104
  const managedTargetIds = new Set(skillTargets.map((target) => target.id));
6105
+ const claimedSkillOutputPaths = new Set(
6106
+ Array.from(nextManaged.values()).filter((entry2) => entry2.sourceType === "skill").map((entry2) => buildManagedOutputPathKey(entry2))
6107
+ );
5953
6108
  for (const entry2 of managedManifest.entries) {
6109
+ if (entry2.sourceType === "subagent" && claimedSkillOutputPaths.has(buildManagedOutputPathKey(entry2))) {
6110
+ continue;
6111
+ }
5954
6112
  if (entry2.sourceType !== "skill" || !managedTargetIds.has(entry2.targetId)) {
5955
6113
  updatedEntries.push(entry2);
5956
6114
  continue;
@@ -6075,11 +6233,10 @@ function formatTomlValue(value) {
6075
6233
  function formatYamlString(value) {
6076
6234
  return JSON.stringify(value);
6077
6235
  }
6078
- const TARGET_FRONTMATTER_KEYS$1 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
6079
6236
  function stripTargetMetadata(frontmatter) {
6080
6237
  const filtered = {};
6081
6238
  for (const [key, value] of Object.entries(frontmatter)) {
6082
- if (TARGET_FRONTMATTER_KEYS$1.has(key.toLowerCase())) {
6239
+ if (SYNC_ROUTING_FRONTMATTER_KEYS.has(key.toLowerCase())) {
6083
6240
  continue;
6084
6241
  }
6085
6242
  filtered[key] = value;
@@ -6141,9 +6298,9 @@ function renderYamlFrontmatter(frontmatter, defaultName) {
6141
6298
  lines.push("---", "");
6142
6299
  return lines.join("\n");
6143
6300
  }
6144
- const TOML_RESERVED_KEYS = /* @__PURE__ */ new Set(["prompt", "targets", "targetagents"]);
6301
+ const TOML_RESERVED_KEYS = /* @__PURE__ */ new Set(["prompt", ...SYNC_ROUTING_FRONTMATTER_KEYS]);
6145
6302
  function renderMarkdownCommand(command) {
6146
- return stripFrontmatterFields(command.rawContents, TARGET_FRONTMATTER_KEYS$1);
6303
+ return stripFrontmatterFields(command.rawContents, SYNC_ROUTING_FRONTMATTER_KEYS);
6147
6304
  }
6148
6305
  function renderTomlCommand(command) {
6149
6306
  const lines = [];
@@ -6281,6 +6438,36 @@ function formatSyncSummary(summary, jsonOutput) {
6281
6438
  }
6282
6439
  return lines.join("\n");
6283
6440
  }
6441
+ function includeCommandByDefault(command, includeItem) {
6442
+ if (!includeItem) {
6443
+ return command.enabledByDefault;
6444
+ }
6445
+ return includeItem({
6446
+ canonicalName: command.name,
6447
+ enabledByDefault: command.enabledByDefault
6448
+ });
6449
+ }
6450
+ function filterCommandCatalog(catalog, includeItem) {
6451
+ const predicate = (command) => includeCommandByDefault(command, includeItem);
6452
+ catalog.commands = catalog.commands.filter(predicate);
6453
+ catalog.sharedCommands = catalog.sharedCommands.filter(predicate);
6454
+ catalog.localCommands = catalog.localCommands.filter(predicate);
6455
+ catalog.localEffectiveCommands = catalog.localEffectiveCommands.filter(predicate);
6456
+ }
6457
+ function assertUsableCommandsForTargets(options) {
6458
+ for (const command of options.commands) {
6459
+ const effectiveTargets = resolveEffectiveTargets({
6460
+ defaultTargets: command.targetAgents,
6461
+ overrideOnly: options.overrideOnly ?? void 0,
6462
+ overrideSkip: options.overrideSkip ?? void 0,
6463
+ allTargets: options.allTargets
6464
+ });
6465
+ if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
6466
+ continue;
6467
+ }
6468
+ assertSlashCommandDefinitionUsable(command);
6469
+ }
6470
+ }
6284
6471
  function renderCommandOutput(command, outputKind, outputPath) {
6285
6472
  if (outputKind === "skill") {
6286
6473
  return renderSkillFromCommand(command);
@@ -6310,14 +6497,7 @@ async function syncSlashCommands(request) {
6310
6497
  agentsDir: request.agentsDir,
6311
6498
  resolveTargetName: request.resolveTargetName
6312
6499
  });
6313
- if (request.includeItem) {
6314
- const includeItem = request.includeItem;
6315
- const predicate = (command) => includeItem(command.name);
6316
- catalog.commands = catalog.commands.filter(predicate);
6317
- catalog.sharedCommands = catalog.sharedCommands.filter(predicate);
6318
- catalog.localCommands = catalog.localCommands.filter(predicate);
6319
- catalog.localEffectiveCommands = catalog.localEffectiveCommands.filter(predicate);
6320
- }
6500
+ filterCommandCatalog(catalog, request.includeItem);
6321
6501
  const targets = request.targets.filter(
6322
6502
  (target) => normalizeCommandOutputDefinition(target.outputs.commands) !== null
6323
6503
  );
@@ -6338,6 +6518,13 @@ async function syncSlashCommands(request) {
6338
6518
  const removeMissing = request.removeMissing ?? false;
6339
6519
  const allTargetIds = request.targets.map((target) => target.id);
6340
6520
  const activeTargetIds = new Set(targets.map((target) => target.id));
6521
+ assertUsableCommandsForTargets({
6522
+ commands: catalog.commands,
6523
+ activeTargetIds,
6524
+ overrideOnly: request.overrideOnly,
6525
+ overrideSkip: request.overrideSkip,
6526
+ allTargets: allTargetIds
6527
+ });
6341
6528
  const effectiveTargetsByCommand = /* @__PURE__ */ new Map();
6342
6529
  const activeSourcesByTarget = /* @__PURE__ */ new Map();
6343
6530
  for (const command of catalog.commands) {
@@ -6803,9 +6990,95 @@ async function syncSlashCommands(request) {
6803
6990
  sourceCounts
6804
6991
  };
6805
6992
  }
6806
- const TARGET_FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["targets", "targetagents"]);
6993
+ function hashIdentifier(value) {
6994
+ return createHash("sha256").update(value).digest("hex");
6995
+ }
6996
+ function resolveManifestPath(repoRoot, targetName, homeDir) {
6997
+ const repoHash = hashIdentifier(repoRoot);
6998
+ const baseDir = path.join(homeDir, ".omniagent", "state", "subagents", "projects", repoHash);
6999
+ return path.join(baseDir, `${targetName}.toml`);
7000
+ }
7001
+ function parseTomlValue(rawValue) {
7002
+ const trimmed = rawValue.trim();
7003
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
7004
+ try {
7005
+ return JSON.parse(trimmed);
7006
+ } catch {
7007
+ return trimmed.slice(1, -1);
7008
+ }
7009
+ }
7010
+ return trimmed;
7011
+ }
7012
+ function parseManifest(contents) {
7013
+ const lines = contents.split(/\r?\n/);
7014
+ let targetName = null;
7015
+ const managedSubagents = [];
7016
+ let current = null;
7017
+ for (const line of lines) {
7018
+ const trimmed = line.trim();
7019
+ if (!trimmed || trimmed.startsWith("#")) {
7020
+ continue;
7021
+ }
7022
+ if (trimmed === "[[managedSubagents]]") {
7023
+ if (current?.name && current.hash && current.lastSyncedAt) {
7024
+ managedSubagents.push({
7025
+ name: current.name,
7026
+ hash: current.hash,
7027
+ lastSyncedAt: current.lastSyncedAt
7028
+ });
7029
+ }
7030
+ current = {};
7031
+ continue;
7032
+ }
7033
+ const match = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*(.+)$/);
7034
+ if (!match) {
7035
+ continue;
7036
+ }
7037
+ const [, key, rawValue] = match;
7038
+ const value = parseTomlValue(rawValue);
7039
+ if (current) {
7040
+ if (key === "name") {
7041
+ current.name = value;
7042
+ continue;
7043
+ }
7044
+ if (key === "hash") {
7045
+ current.hash = value;
7046
+ continue;
7047
+ }
7048
+ if (key === "lastSyncedAt") {
7049
+ current.lastSyncedAt = value;
7050
+ continue;
7051
+ }
7052
+ }
7053
+ if (key === "targetName") {
7054
+ targetName = value;
7055
+ }
7056
+ }
7057
+ if (current?.name && current.hash && current.lastSyncedAt) {
7058
+ managedSubagents.push({
7059
+ name: current.name,
7060
+ hash: current.hash,
7061
+ lastSyncedAt: current.lastSyncedAt
7062
+ });
7063
+ }
7064
+ if (!targetName) {
7065
+ return null;
7066
+ }
7067
+ return {
7068
+ targetName,
7069
+ managedSubagents
7070
+ };
7071
+ }
7072
+ async function readManifest(manifestPath) {
7073
+ try {
7074
+ const contents = await readFile(manifestPath, "utf8");
7075
+ return parseManifest(contents);
7076
+ } catch {
7077
+ return null;
7078
+ }
7079
+ }
6807
7080
  /* @__PURE__ */ new Set([
6808
- ...TARGET_FRONTMATTER_KEYS,
7081
+ ...SYNC_ROUTING_FRONTMATTER_KEYS,
6809
7082
  "tools",
6810
7083
  "model",
6811
7084
  "color"
@@ -6816,14 +7089,14 @@ function emptySummaryCounts() {
6816
7089
  function normalizeSkillKey(name) {
6817
7090
  return path.normalize(name).replace(/\\/g, "/").toLowerCase();
6818
7091
  }
6819
- function normalizeSkillRelativePath(relativePath) {
6820
- if (!relativePath) {
6821
- return relativePath;
7092
+ function includeCanonicalSkill(options) {
7093
+ if (!options.includeSkill) {
7094
+ return options.enabledByDefault;
6822
7095
  }
6823
- const baseName = path.basename(relativePath);
6824
- const { baseName: strippedBase } = stripLocalPathSuffix(baseName);
6825
- const parent = path.dirname(relativePath);
6826
- return parent === "." ? strippedBase : path.join(parent, strippedBase);
7096
+ return options.includeSkill({
7097
+ canonicalName: options.canonicalName,
7098
+ enabledByDefault: options.enabledByDefault
7099
+ });
6827
7100
  }
6828
7101
  function formatDisplayPath$1(repoRoot, absolutePath) {
6829
7102
  const relative = path.relative(repoRoot, absolutePath);
@@ -6858,71 +7131,313 @@ function buildSourceCounts(subagents, targets, allTargets, request) {
6858
7131
  }
6859
7132
  return counts;
6860
7133
  }
6861
- async function loadCanonicalSkillIndex(repoRoot, options = {}) {
7134
+ function resolveSkillRelativePath(skillsRoot, directoryPath) {
7135
+ const relativePath = path.relative(skillsRoot, directoryPath);
7136
+ if (!relativePath) {
7137
+ return { relativePath, hadLocalSuffix: false };
7138
+ }
7139
+ const baseName = path.basename(relativePath);
7140
+ const { baseName: strippedBase, hadLocalSuffix } = stripLocalPathSuffix(baseName);
7141
+ if (!hadLocalSuffix) {
7142
+ return { relativePath, hadLocalSuffix: false };
7143
+ }
7144
+ const parent = path.dirname(relativePath);
7145
+ const normalized = parent === "." ? strippedBase : path.join(parent, strippedBase);
7146
+ return { relativePath: normalized, hadLocalSuffix: true };
7147
+ }
7148
+ function resolveSkillName(frontmatter, fallback) {
7149
+ const rawName = frontmatter.name;
7150
+ if (typeof rawName === "string") {
7151
+ const trimmed = rawName.trim();
7152
+ if (trimmed) {
7153
+ return trimmed;
7154
+ }
7155
+ }
7156
+ return fallback;
7157
+ }
7158
+ function shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter) {
7159
+ if (!skillKeyFilter) {
7160
+ return true;
7161
+ }
7162
+ return skillKeyFilter.has(normalizeSkillKey(relativePath));
7163
+ }
7164
+ async function loadCanonicalSkillIndex(repoRoot, options) {
6862
7165
  const includeLocal = options.includeLocal ?? true;
7166
+ const fallbackResolver = createTargetNameResolver(BUILTIN_TARGETS).resolveTargetName;
7167
+ const resolveTargetName = options.resolveTargetName ?? fallbackResolver;
6863
7168
  const skillsRoot = resolveSharedCategoryRoot(repoRoot, "skills", options.agentsDir);
6864
7169
  const localSkillsRoot = resolveLocalCategoryRoot(repoRoot, "skills", options.agentsDir);
6865
- let directories = [];
6866
- try {
6867
- directories = await listSkillDirectories(skillsRoot);
6868
- } catch (error) {
6869
- const code = error.code;
6870
- if (code !== "ENOENT" && code !== "ENOTDIR") {
6871
- throw error;
6872
- }
6873
- }
7170
+ const targetFilter = options.targetIds ? new Set(options.targetIds) : null;
7171
+ const skillKeyFilter = options.skillKeys ? new Set(options.skillKeys) : null;
6874
7172
  const index = /* @__PURE__ */ new Map();
6875
- const addEntry = (relativePath, skillPath) => {
6876
- if (!relativePath) {
6877
- return;
7173
+ const sharedStats = await readDirectoryStats(skillsRoot);
7174
+ if (sharedStats && !sharedStats.isDirectory()) {
7175
+ throw new Error(`Skills root is not a directory: ${skillsRoot}.`);
7176
+ }
7177
+ const localStats = includeLocal ? await readDirectoryStats(localSkillsRoot) : null;
7178
+ if (localStats && !localStats.isDirectory()) {
7179
+ throw new Error(`Local skills root is not a directory: ${localSkillsRoot}.`);
7180
+ }
7181
+ const sharedEntries = sharedStats ? await listSkillDirectories(skillsRoot) : [];
7182
+ const localEntries = localStats ? await listSkillDirectories(localSkillsRoot) : [];
7183
+ const sharedSkills = [];
7184
+ const localPathSkills = [];
7185
+ const localSuffixSkills = [];
7186
+ for (const entry2 of sharedEntries) {
7187
+ const { relativePath, hadLocalSuffix } = resolveSkillRelativePath(
7188
+ skillsRoot,
7189
+ entry2.directoryPath
7190
+ );
7191
+ if (!shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter)) {
7192
+ continue;
6878
7193
  }
6879
- const normalized = normalizeSkillKey(normalizeSkillRelativePath(relativePath));
6880
- index.set(normalized, skillPath);
6881
- };
6882
- for (const entry2 of directories) {
6883
- const relative = path.relative(skillsRoot, entry2.directoryPath);
6884
- if (!relative) {
7194
+ if (hadLocalSuffix) {
7195
+ if (!includeLocal) {
7196
+ continue;
7197
+ }
7198
+ const skillFileName = entry2.localSkillFile ?? entry2.sharedSkillFile;
7199
+ if (!skillFileName) {
7200
+ continue;
7201
+ }
7202
+ localSuffixSkills.push({
7203
+ relativePath,
7204
+ sourcePath: path.join(entry2.directoryPath, skillFileName)
7205
+ });
6885
7206
  continue;
6886
7207
  }
6887
- const isLocalDir = stripLocalPathSuffix(path.basename(entry2.directoryPath)).hadLocalSuffix;
6888
- if (!isLocalDir && entry2.sharedSkillFile) {
6889
- addEntry(relative, path.join(entry2.directoryPath, entry2.sharedSkillFile));
7208
+ if (entry2.sharedSkillFile) {
7209
+ sharedSkills.push({
7210
+ relativePath,
7211
+ sourcePath: path.join(entry2.directoryPath, entry2.sharedSkillFile)
7212
+ });
6890
7213
  }
6891
- if (includeLocal) {
6892
- if (isLocalDir) {
6893
- const skillFileName = entry2.localSkillFile ?? entry2.sharedSkillFile;
6894
- if (skillFileName) {
6895
- addEntry(relative, path.join(entry2.directoryPath, skillFileName));
6896
- }
6897
- } else if (entry2.localSkillFile) {
6898
- addEntry(relative, path.join(entry2.directoryPath, entry2.localSkillFile));
6899
- }
7214
+ if (includeLocal && entry2.localSkillFile) {
7215
+ localSuffixSkills.push({
7216
+ relativePath,
7217
+ sourcePath: path.join(entry2.directoryPath, entry2.localSkillFile)
7218
+ });
6900
7219
  }
6901
7220
  }
6902
7221
  if (includeLocal) {
6903
- let localDirectories = [];
6904
- try {
6905
- localDirectories = await listSkillDirectories(localSkillsRoot);
6906
- } catch (error) {
6907
- const code = error.code;
6908
- if (code === "ENOENT" || code === "ENOTDIR") {
6909
- return index;
7222
+ for (const entry2 of localEntries) {
7223
+ const skillFileName = entry2.sharedSkillFile ?? entry2.localSkillFile;
7224
+ if (!skillFileName) {
7225
+ continue;
6910
7226
  }
6911
- throw error;
7227
+ const { relativePath } = resolveSkillRelativePath(localSkillsRoot, entry2.directoryPath);
7228
+ if (!shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter)) {
7229
+ continue;
7230
+ }
7231
+ localPathSkills.push({
7232
+ relativePath,
7233
+ sourcePath: path.join(entry2.directoryPath, skillFileName)
7234
+ });
7235
+ }
7236
+ }
7237
+ const { localEffective: localEffectiveSkills, sharedEffective: sharedEffectiveSkills } = resolveLocalPrecedence({
7238
+ shared: sharedSkills,
7239
+ localPath: localPathSkills,
7240
+ localSuffix: localSuffixSkills,
7241
+ key: (skill) => normalizeSkillKey(skill.relativePath)
7242
+ });
7243
+ const effectiveSkills = includeLocal ? [...sharedEffectiveSkills, ...localEffectiveSkills] : sharedSkills;
7244
+ for (const skill of effectiveSkills) {
7245
+ const rawContents = await readFile(skill.sourcePath, "utf8");
7246
+ const { frontmatter } = extractFrontmatter$1(rawContents);
7247
+ const fallbackName = skill.relativePath || path.basename(path.dirname(skill.sourcePath));
7248
+ const skillName = resolveSkillName(frontmatter, fallbackName);
7249
+ const rawTargets = [frontmatter.targets, frontmatter.targetAgents];
7250
+ const { targets, invalidTargets } = resolveFrontmatterTargets(rawTargets, resolveTargetName);
7251
+ const hasEmptyTargets = hasRawTargetValues(rawTargets) && (!targets || targets.length === 0);
7252
+ const effectiveTargets = hasEmptyTargets ? [] : resolveEffectiveTargets({
7253
+ defaultTargets: targets,
7254
+ overrideOnly: options.overrideOnly ?? void 0,
7255
+ overrideSkip: options.overrideSkip ?? void 0,
7256
+ allTargets: options.allTargets
7257
+ });
7258
+ const matchingTargets = targetFilter ? effectiveTargets.filter((targetId) => targetFilter.has(targetId)) : effectiveTargets;
7259
+ if (matchingTargets.length === 0) {
7260
+ continue;
6912
7261
  }
6913
- for (const entry2 of localDirectories) {
6914
- const relative = path.relative(localSkillsRoot, entry2.directoryPath);
6915
- if (!relative) {
7262
+ const enabledByDefault = resolveFrontmatterEnabledByDefault({
7263
+ frontmatter,
7264
+ itemKind: "Skill",
7265
+ itemName: skillName,
7266
+ sourcePath: skill.sourcePath
7267
+ });
7268
+ if (!includeCanonicalSkill({
7269
+ canonicalName: skillName,
7270
+ enabledByDefault,
7271
+ includeSkill: options.includeSkill
7272
+ })) {
7273
+ continue;
7274
+ }
7275
+ if (invalidTargets.length > 0) {
7276
+ const invalidList = invalidTargets.join(", ");
7277
+ throw new InvalidFrontmatterTargetsError(
7278
+ `Skill "${skillName}" has unsupported targets (${invalidList}) in ${skill.sourcePath}.`
7279
+ );
7280
+ }
7281
+ if (hasEmptyTargets) {
7282
+ throw new InvalidFrontmatterTargetsError(
7283
+ `Skill "${skillName}" has empty targets in ${skill.sourcePath}.`
7284
+ );
7285
+ }
7286
+ const skillKey = normalizeSkillKey(skill.relativePath);
7287
+ for (const targetId of matchingTargets) {
7288
+ const targetSkills = index.get(targetId) ?? /* @__PURE__ */ new Map();
7289
+ targetSkills.set(skillKey, skill.sourcePath);
7290
+ index.set(targetId, targetSkills);
7291
+ }
7292
+ }
7293
+ return index;
7294
+ }
7295
+ function collectRelevantCanonicalSkillKeys(options) {
7296
+ const relevant = /* @__PURE__ */ new Set();
7297
+ for (const subagent of options.subagents) {
7298
+ const effectiveTargets = resolveEffectiveTargets({
7299
+ defaultTargets: subagent.targetAgents,
7300
+ overrideOnly: options.overrideOnly ?? void 0,
7301
+ overrideSkip: options.overrideSkip ?? void 0,
7302
+ allTargets: options.allTargets
7303
+ });
7304
+ if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
7305
+ continue;
7306
+ }
7307
+ relevant.add(normalizeSkillKey(subagent.resolvedName));
7308
+ }
7309
+ return relevant;
7310
+ }
7311
+ async function collectManagedCanonicalSkillKeys(options) {
7312
+ const managed = /* @__PURE__ */ new Set();
7313
+ const homeDir = os.homedir();
7314
+ const targetIds = new Set(options.targetIds);
7315
+ for (const targetId of options.targetIds) {
7316
+ const manifest = await readManifest(resolveManifestPath(options.repoRoot, targetId, homeDir));
7317
+ if (!manifest || manifest.targetName !== targetId) {
7318
+ continue;
7319
+ }
7320
+ for (const entry2 of manifest.managedSubagents) {
7321
+ managed.add(normalizeSkillKey(entry2.name));
7322
+ }
7323
+ }
7324
+ const managedOutputs = await readManagedOutputs(options.repoRoot, homeDir);
7325
+ for (const entry2 of managedOutputs?.entries ?? []) {
7326
+ if (entry2.sourceType !== "subagent" || !targetIds.has(entry2.targetId)) {
7327
+ continue;
7328
+ }
7329
+ managed.add(normalizeSkillKey(entry2.sourceId));
7330
+ }
7331
+ return managed;
7332
+ }
7333
+ function getCanonicalSkillPath(index, targetId, skillKey) {
7334
+ return index.get(targetId)?.get(skillKey);
7335
+ }
7336
+ function recordShadowedSubagentSource(shadowedSources, targetId, sourceId) {
7337
+ const existing = shadowedSources.get(targetId) ?? /* @__PURE__ */ new Set();
7338
+ existing.add(normalizeName(sourceId));
7339
+ shadowedSources.set(targetId, existing);
7340
+ }
7341
+ function includeSubagentByDefault(subagent, includeItem) {
7342
+ if (!includeItem) {
7343
+ return subagent.enabledByDefault;
7344
+ }
7345
+ return includeItem({
7346
+ canonicalName: subagent.resolvedName,
7347
+ enabledByDefault: subagent.enabledByDefault
7348
+ });
7349
+ }
7350
+ function filterSubagentCatalog(catalog, includeItem) {
7351
+ const predicate = (subagent) => includeSubagentByDefault(subagent, includeItem);
7352
+ catalog.subagents = catalog.subagents.filter(predicate);
7353
+ catalog.sharedSubagents = catalog.sharedSubagents.filter(predicate);
7354
+ catalog.localSubagents = catalog.localSubagents.filter(predicate);
7355
+ catalog.localEffectiveSubagents = catalog.localEffectiveSubagents.filter(predicate);
7356
+ }
7357
+ function assertUsableSubagentsForTargets(options) {
7358
+ for (const subagent of options.subagents) {
7359
+ const effectiveTargets = resolveEffectiveTargets({
7360
+ defaultTargets: subagent.targetAgents,
7361
+ overrideOnly: options.overrideOnly ?? void 0,
7362
+ overrideSkip: options.overrideSkip ?? void 0,
7363
+ allTargets: options.allTargets
7364
+ });
7365
+ if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
7366
+ continue;
7367
+ }
7368
+ assertSubagentDefinitionUsable(subagent);
7369
+ }
7370
+ }
7371
+ function targetRequiresCanonicalSkillLookup(target) {
7372
+ const outputDef = normalizeOutputDefinition(target.outputs.subagents);
7373
+ if (!outputDef) {
7374
+ return false;
7375
+ }
7376
+ if (outputDef.fallback?.mode !== "convert" || outputDef.fallback.targetType !== "skills") {
7377
+ return false;
7378
+ }
7379
+ return normalizeOutputDefinition(target.outputs.skills) !== null;
7380
+ }
7381
+ async function resolveCanonicalSkillsForSubagentSync(options) {
7382
+ const targetIds = options.activeTargets.filter(targetRequiresCanonicalSkillLookup).map((target) => target.id);
7383
+ if (targetIds.length === 0) {
7384
+ return /* @__PURE__ */ new Map();
7385
+ }
7386
+ const relevantCanonicalSkillKeys = collectRelevantCanonicalSkillKeys({
7387
+ subagents: options.subagents,
7388
+ activeTargetIds: new Set(targetIds),
7389
+ overrideOnly: options.overrideOnly,
7390
+ overrideSkip: options.overrideSkip,
7391
+ allTargets: options.allTargetIds
7392
+ });
7393
+ for (const skillKey of await collectManagedCanonicalSkillKeys({
7394
+ repoRoot: options.repoRoot,
7395
+ targetIds
7396
+ })) {
7397
+ relevantCanonicalSkillKeys.add(skillKey);
7398
+ }
7399
+ if (relevantCanonicalSkillKeys.size === 0) {
7400
+ return /* @__PURE__ */ new Map();
7401
+ }
7402
+ return loadCanonicalSkillIndex(options.repoRoot, {
7403
+ includeLocal: options.includeLocalSkills ?? true,
7404
+ agentsDir: options.agentsDir,
7405
+ resolveTargetName: options.resolveTargetName,
7406
+ overrideOnly: options.overrideOnly ?? null,
7407
+ overrideSkip: options.overrideSkip ?? null,
7408
+ allTargets: options.allTargetIds,
7409
+ targetIds,
7410
+ skillKeys: relevantCanonicalSkillKeys,
7411
+ includeSkill: options.includeSkill
7412
+ });
7413
+ }
7414
+ async function resolveShadowedSubagentNamesForTargets(options) {
7415
+ const activeTargetIds = new Set(options.activeTargets.map((target) => target.id));
7416
+ const canonicalSkills = await resolveCanonicalSkillsForSubagentSync(options);
7417
+ const shadowedSources = /* @__PURE__ */ new Map();
7418
+ for (const subagent of options.subagents) {
7419
+ const effectiveTargets = resolveEffectiveTargets({
7420
+ defaultTargets: subagent.targetAgents,
7421
+ overrideOnly: options.overrideOnly ?? void 0,
7422
+ overrideSkip: options.overrideSkip ?? void 0,
7423
+ allTargets: options.allTargetIds
7424
+ });
7425
+ for (const targetId of effectiveTargets) {
7426
+ if (!activeTargetIds.has(targetId)) {
6916
7427
  continue;
6917
7428
  }
6918
- const skillFileName = entry2.sharedSkillFile ?? entry2.localSkillFile;
6919
- if (!skillFileName) {
7429
+ const canonicalSkillPath = getCanonicalSkillPath(
7430
+ canonicalSkills,
7431
+ targetId,
7432
+ normalizeSkillKey(subagent.resolvedName)
7433
+ );
7434
+ if (!canonicalSkillPath) {
6920
7435
  continue;
6921
7436
  }
6922
- addEntry(relative, path.join(entry2.directoryPath, skillFileName));
7437
+ recordShadowedSubagentSource(shadowedSources, targetId, subagent.resolvedName);
6923
7438
  }
6924
7439
  }
6925
- return index;
7440
+ return shadowedSources;
6926
7441
  }
6927
7442
  function buildInvalidTargetWarnings(subagents) {
6928
7443
  const warnings = [];
@@ -6974,14 +7489,7 @@ async function syncSubagents(request) {
6974
7489
  agentsDir: request.agentsDir,
6975
7490
  resolveTargetName: request.resolveTargetName
6976
7491
  });
6977
- if (request.includeItem) {
6978
- const includeItem = request.includeItem;
6979
- const predicate = (subagent) => includeItem(subagent.resolvedName);
6980
- catalog.subagents = catalog.subagents.filter(predicate);
6981
- catalog.sharedSubagents = catalog.sharedSubagents.filter(predicate);
6982
- catalog.localSubagents = catalog.localSubagents.filter(predicate);
6983
- catalog.localEffectiveSubagents = catalog.localEffectiveSubagents.filter(predicate);
6984
- }
7492
+ filterSubagentCatalog(catalog, request.includeItem);
6985
7493
  const targets = request.targets.filter(
6986
7494
  (target) => normalizeOutputDefinition(target.outputs.subagents) !== null
6987
7495
  );
@@ -7002,6 +7510,13 @@ async function syncSubagents(request) {
7002
7510
  }
7003
7511
  const allTargetIds = request.targets.map((target) => target.id);
7004
7512
  const activeTargetIds = new Set(targets.map((target) => target.id));
7513
+ assertUsableSubagentsForTargets({
7514
+ subagents: catalog.subagents,
7515
+ activeTargetIds,
7516
+ overrideOnly: request.overrideOnly,
7517
+ overrideSkip: request.overrideSkip,
7518
+ allTargets: allTargetIds
7519
+ });
7005
7520
  const effectiveTargetsBySubagent = /* @__PURE__ */ new Map();
7006
7521
  const activeSourcesByTarget = /* @__PURE__ */ new Map();
7007
7522
  for (const subagent of catalog.subagents) {
@@ -7036,6 +7551,7 @@ async function syncSubagents(request) {
7036
7551
  const managedManifest = await readManagedOutputs(request.repoRoot, homeDir) ?? { entries: [] };
7037
7552
  const nextManaged = /* @__PURE__ */ new Map();
7038
7553
  const activeOutputPaths = /* @__PURE__ */ new Set();
7554
+ const shadowedSubagentSources = /* @__PURE__ */ new Map();
7039
7555
  const countsByTarget = /* @__PURE__ */ new Map();
7040
7556
  const getCounts = (targetId) => {
7041
7557
  const existing = countsByTarget.get(targetId) ?? emptySummaryCounts();
@@ -7046,9 +7562,17 @@ async function syncSubagents(request) {
7046
7562
  const writerRegistry = /* @__PURE__ */ new Map([
7047
7563
  [defaultSubagentWriter.id, defaultSubagentWriter]
7048
7564
  ]);
7049
- const canonicalSkills = await loadCanonicalSkillIndex(request.repoRoot, {
7050
- includeLocal: request.includeLocalSkills ?? true,
7051
- agentsDir: request.agentsDir
7565
+ const canonicalSkills = await resolveCanonicalSkillsForSubagentSync({
7566
+ repoRoot: request.repoRoot,
7567
+ activeTargets: targets,
7568
+ allTargetIds,
7569
+ subagents: catalog.subagents,
7570
+ agentsDir: request.agentsDir,
7571
+ includeLocalSkills: request.includeLocalSkills,
7572
+ resolveTargetName: request.resolveTargetName,
7573
+ overrideOnly: request.overrideOnly,
7574
+ overrideSkip: request.overrideSkip,
7575
+ includeSkill: request.includeSkill
7052
7576
  });
7053
7577
  const validAgents = request.validAgents ?? buildSupportedAgentNames(request.targets);
7054
7578
  const outputDefs = /* @__PURE__ */ new Map();
@@ -7114,8 +7638,13 @@ async function syncSubagents(request) {
7114
7638
  }
7115
7639
  if (outputKind === "skill") {
7116
7640
  const canonicalSkillKey = normalizeSkillKey(subagent.resolvedName);
7117
- const canonicalSkillPath = canonicalSkills.get(canonicalSkillKey);
7641
+ const canonicalSkillPath = getCanonicalSkillPath(
7642
+ canonicalSkills,
7643
+ target.id,
7644
+ canonicalSkillKey
7645
+ );
7118
7646
  if (canonicalSkillPath) {
7647
+ recordShadowedSubagentSource(shadowedSubagentSources, target.id, subagent.resolvedName);
7119
7648
  warnings.push(
7120
7649
  `Skipped ${target.displayName} skill "${subagent.resolvedName}" because canonical skill exists at ${canonicalSkillPath}.`
7121
7650
  );
@@ -7320,6 +7849,35 @@ async function syncSubagents(request) {
7320
7849
  if (nextManaged.has(key)) {
7321
7850
  continue;
7322
7851
  }
7852
+ const canonicalSkillPath = getCanonicalSkillPath(
7853
+ canonicalSkills,
7854
+ entry2.targetId,
7855
+ normalizeSkillKey(entry2.sourceId)
7856
+ );
7857
+ const skillDef = skillDefs.get(entry2.targetId);
7858
+ if (canonicalSkillPath && skillDef) {
7859
+ const expectedSkillOutputPath = resolveOutputPath({
7860
+ template: skillDef.path,
7861
+ context: {
7862
+ repoRoot: request.repoRoot,
7863
+ agentsDir: agentsDirPath,
7864
+ homeDir,
7865
+ targetId: entry2.targetId,
7866
+ itemName: entry2.sourceId
7867
+ },
7868
+ item: { name: entry2.sourceId },
7869
+ baseDir: request.repoRoot
7870
+ });
7871
+ if (normalizeManagedOutputPath(expectedSkillOutputPath) === normalizeManagedOutputPath(entry2.outputPath)) {
7872
+ updatedEntries.push(entry2);
7873
+ continue;
7874
+ }
7875
+ }
7876
+ const shadowedSources = shadowedSubagentSources.get(entry2.targetId);
7877
+ if (shadowedSources?.has(normalizeName(entry2.sourceId))) {
7878
+ updatedEntries.push(entry2);
7879
+ continue;
7880
+ }
7323
7881
  const activeSources = activeSourcesByTarget.get(entry2.targetId);
7324
7882
  const sourceStillActive = activeSources?.has(entry2.sourceId) ?? false;
7325
7883
  if (!removeMissing || sourceStillActive) {
@@ -7813,12 +8371,21 @@ function replayTraversedProfileWarnings(profile, traversedNames) {
7813
8371
  }
7814
8372
  });
7815
8373
  for (const name of traversedNames.skills) {
8374
+ if (!name) {
8375
+ continue;
8376
+ }
7816
8377
  warningFilter.includes("skills", name);
7817
8378
  }
7818
8379
  for (const name of traversedNames.subagents) {
8380
+ if (!name) {
8381
+ continue;
8382
+ }
7819
8383
  warningFilter.includes("subagents", name);
7820
8384
  }
7821
8385
  for (const name of traversedNames.commands) {
8386
+ if (!name) {
8387
+ continue;
8388
+ }
7822
8389
  warningFilter.includes("commands", name);
7823
8390
  }
7824
8391
  return warningFilter.collectUnknownWarnings();
@@ -7838,6 +8405,18 @@ function addTemplateScriptSource(sources, templatePath, content) {
7838
8405
  function intersectsTargets(targets, selectedTargetIds) {
7839
8406
  return targets.some((target) => selectedTargetIds.has(target));
7840
8407
  }
8408
+ function areSelectedTargetsFullyShadowed(options) {
8409
+ const relevantTargets = options.effectiveTargets.filter(
8410
+ (targetId) => options.selectedTargetIds.has(targetId)
8411
+ );
8412
+ if (relevantTargets.length === 0) {
8413
+ return false;
8414
+ }
8415
+ const normalizedName = options.subagentName.trim().toLowerCase();
8416
+ return relevantTargets.every(
8417
+ (targetId) => options.shadowedSubagentsByTarget.get(targetId)?.has(normalizedName)
8418
+ );
8419
+ }
7841
8420
  async function listAllFiles(root) {
7842
8421
  const entries = await readdir(root, { withFileTypes: true });
7843
8422
  const files = [];
@@ -7872,7 +8451,10 @@ async function gatherTemplateScriptSources(options) {
7872
8451
  resolveTargetName: options.resolveTargetName
7873
8452
  });
7874
8453
  for (const command of commandCatalog.commands) {
7875
- if (options.includeCommand && !options.includeCommand(command.name)) {
8454
+ if (options.includeCommand && !options.includeCommand({
8455
+ canonicalName: command.name,
8456
+ enabledByDefault: command.enabledByDefault
8457
+ })) {
7876
8458
  continue;
7877
8459
  }
7878
8460
  const effectiveTargets = resolveEffectiveTargets({
@@ -7884,6 +8466,7 @@ async function gatherTemplateScriptSources(options) {
7884
8466
  if (!intersectsTargets(effectiveTargets, selectedCommandTargetIds)) {
7885
8467
  continue;
7886
8468
  }
8469
+ assertSlashCommandDefinitionUsable(command);
7887
8470
  addTemplateScriptSource(sources, command.sourcePath, command.rawContents);
7888
8471
  }
7889
8472
  }
@@ -7893,8 +8476,23 @@ async function gatherTemplateScriptSources(options) {
7893
8476
  agentsDir: options.agentsDir,
7894
8477
  resolveTargetName: options.resolveTargetName
7895
8478
  });
8479
+ const shadowedSubagentsByTarget = await resolveShadowedSubagentNamesForTargets({
8480
+ repoRoot: options.repoRoot,
8481
+ activeTargets: options.selectedSubagentTargets,
8482
+ allTargetIds: options.allTargetIds,
8483
+ subagents: subagentCatalog.subagents,
8484
+ agentsDir: options.agentsDir,
8485
+ includeLocalSkills: !options.excludeLocalSkills,
8486
+ resolveTargetName: options.resolveTargetName,
8487
+ overrideOnly: options.overrideOnly,
8488
+ overrideSkip: options.overrideSkip,
8489
+ includeSkill: options.includeSkill
8490
+ });
7896
8491
  for (const subagent of subagentCatalog.subagents) {
7897
- if (options.includeSubagent && !options.includeSubagent(subagent.resolvedName)) {
8492
+ if (options.includeSubagent && !options.includeSubagent({
8493
+ canonicalName: subagent.resolvedName,
8494
+ enabledByDefault: subagent.enabledByDefault
8495
+ })) {
7898
8496
  continue;
7899
8497
  }
7900
8498
  const effectiveTargets = resolveEffectiveTargets({
@@ -7906,6 +8504,15 @@ async function gatherTemplateScriptSources(options) {
7906
8504
  if (!intersectsTargets(effectiveTargets, selectedSubagentTargetIds)) {
7907
8505
  continue;
7908
8506
  }
8507
+ if (areSelectedTargetsFullyShadowed({
8508
+ selectedTargetIds: selectedSubagentTargetIds,
8509
+ effectiveTargets,
8510
+ shadowedSubagentsByTarget,
8511
+ subagentName: subagent.resolvedName
8512
+ })) {
8513
+ continue;
8514
+ }
8515
+ assertSubagentDefinitionUsable(subagent);
7909
8516
  addTemplateScriptSource(sources, subagent.sourcePath, subagent.rawContents);
7910
8517
  }
7911
8518
  }
@@ -7936,7 +8543,10 @@ async function gatherTemplateScriptSources(options) {
7936
8543
  resolveTargetName: options.resolveTargetName
7937
8544
  });
7938
8545
  for (const skill of skillCatalog.skills) {
7939
- if (options.includeSkill && !options.includeSkill(skill.name)) {
8546
+ if (options.includeSkill && !options.includeSkill({
8547
+ canonicalName: skill.name,
8548
+ enabledByDefault: skill.enabledByDefault
8549
+ })) {
7940
8550
  continue;
7941
8551
  }
7942
8552
  const effectiveTargets = resolveEffectiveTargets({
@@ -7948,6 +8558,7 @@ async function gatherTemplateScriptSources(options) {
7948
8558
  if (!intersectsTargets(effectiveTargets, selectedSkillTargetIds)) {
7949
8559
  continue;
7950
8560
  }
8561
+ assertSkillDefinitionUsable(skill);
7951
8562
  const files = await listAllFiles(skill.directoryPath);
7952
8563
  for (const filePath of files) {
7953
8564
  const buffer = await readFile(filePath);
@@ -8088,6 +8699,16 @@ async function validateTemplatingSources(options) {
8088
8699
  sourcePath
8089
8700
  });
8090
8701
  };
8702
+ const selectedSkillTargetIds = new Set(options.selectedSkillTargets.map((target) => target.id));
8703
+ const selectedCommandTargetIds = new Set(
8704
+ options.selectedCommandTargets.map((target) => target.id)
8705
+ );
8706
+ const selectedSubagentTargetIds = new Set(
8707
+ options.selectedSubagentTargets.map((target) => target.id)
8708
+ );
8709
+ const selectedInstructionTargetIds = new Set(
8710
+ options.selectedInstructionTargets.map((target) => target.id)
8711
+ );
8091
8712
  if (options.commandsAvailable) {
8092
8713
  const commandCatalog = await loadCommandCatalog(options.repoRoot, {
8093
8714
  includeLocal: options.includeLocalCommands,
@@ -8095,9 +8716,20 @@ async function validateTemplatingSources(options) {
8095
8716
  resolveTargetName: options.resolveTargetName
8096
8717
  });
8097
8718
  for (const command of commandCatalog.commands) {
8098
- if (options.includeCommand && !options.includeCommand(command.name)) {
8719
+ if (options.includeCommand && !options.includeCommand({
8720
+ canonicalName: command.name,
8721
+ enabledByDefault: command.enabledByDefault
8722
+ })) {
8099
8723
  continue;
8100
8724
  }
8725
+ const effectiveTargets = resolveEffectiveTargets({
8726
+ defaultTargets: command.targetAgents,
8727
+ allTargets: options.selectedCommandTargets.map((target) => target.id)
8728
+ });
8729
+ if (!intersectsTargets(effectiveTargets, selectedCommandTargetIds)) {
8730
+ continue;
8731
+ }
8732
+ assertSlashCommandDefinitionUsable(command);
8101
8733
  validateContent(command.sourcePath, command.rawContents);
8102
8734
  }
8103
8735
  }
@@ -8108,9 +8740,20 @@ async function validateTemplatingSources(options) {
8108
8740
  resolveTargetName: options.resolveTargetName
8109
8741
  });
8110
8742
  for (const skill of skillCatalog.skills) {
8111
- if (options.includeSkill && !options.includeSkill(skill.name)) {
8743
+ if (options.includeSkill && !options.includeSkill({
8744
+ canonicalName: skill.name,
8745
+ enabledByDefault: skill.enabledByDefault
8746
+ })) {
8112
8747
  continue;
8113
8748
  }
8749
+ const effectiveTargets = resolveEffectiveTargets({
8750
+ defaultTargets: skill.targetAgents,
8751
+ allTargets: options.selectedSkillTargets.map((target) => target.id)
8752
+ });
8753
+ if (!intersectsTargets(effectiveTargets, selectedSkillTargetIds)) {
8754
+ continue;
8755
+ }
8756
+ assertSkillDefinitionUsable(skill);
8114
8757
  const files = await listFiles(skill.directoryPath);
8115
8758
  const filesToValidate = options.includeLocalSkills ? files : files.filter((filePath) => !hasLocalMarker(filePath));
8116
8759
  for (const filePath of filesToValidate) {
@@ -8129,29 +8772,61 @@ async function validateTemplatingSources(options) {
8129
8772
  agentsDir: options.agentsDir,
8130
8773
  resolveTargetName: options.resolveTargetName
8131
8774
  });
8775
+ const shadowedSubagentsByTarget = await resolveShadowedSubagentNamesForTargets({
8776
+ repoRoot: options.repoRoot,
8777
+ activeTargets: options.selectedSubagentTargets,
8778
+ allTargetIds: options.selectedSubagentTargets.map((target) => target.id),
8779
+ subagents: subagentCatalog.subagents,
8780
+ agentsDir: options.agentsDir,
8781
+ includeLocalSkills: options.includeLocalSkills,
8782
+ resolveTargetName: options.resolveTargetName,
8783
+ includeSkill: options.includeSkill
8784
+ });
8132
8785
  for (const subagent of subagentCatalog.subagents) {
8133
- if (options.includeSubagent && !options.includeSubagent(subagent.resolvedName)) {
8786
+ if (options.includeSubagent && !options.includeSubagent({
8787
+ canonicalName: subagent.resolvedName,
8788
+ enabledByDefault: subagent.enabledByDefault
8789
+ })) {
8134
8790
  continue;
8135
8791
  }
8792
+ const effectiveTargets = resolveEffectiveTargets({
8793
+ defaultTargets: subagent.targetAgents,
8794
+ allTargets: options.selectedSubagentTargets.map((target) => target.id)
8795
+ });
8796
+ if (!intersectsTargets(effectiveTargets, selectedSubagentTargetIds)) {
8797
+ continue;
8798
+ }
8799
+ if (areSelectedTargetsFullyShadowed({
8800
+ selectedTargetIds: selectedSubagentTargetIds,
8801
+ effectiveTargets,
8802
+ shadowedSubagentsByTarget,
8803
+ subagentName: subagent.resolvedName
8804
+ })) {
8805
+ continue;
8806
+ }
8807
+ assertSubagentDefinitionUsable(subagent);
8136
8808
  validateContent(subagent.sourcePath, subagent.rawContents);
8137
8809
  }
8138
8810
  }
8139
8811
  if (options.instructionsAvailable) {
8140
- const entries = await scanInstructionTemplateSources({
8812
+ const catalog = await loadInstructionTemplateCatalog({
8141
8813
  repoRoot: options.repoRoot,
8142
8814
  includeLocal: options.includeLocalInstructions,
8143
- agentsDir: options.agentsDir
8815
+ agentsDir: options.agentsDir,
8816
+ resolveTargetName: options.resolveTargetName
8144
8817
  });
8145
- for (const entry2 of entries) {
8146
- const buffer = await readFile(entry2.sourcePath);
8147
- const contents = decodeUtf8(buffer);
8148
- if (contents === null) {
8818
+ for (const template of catalog.templates) {
8819
+ const effectiveTargets = resolveEffectiveTargets({
8820
+ defaultTargets: template.targets,
8821
+ allTargets: options.selectedInstructionTargets.map((target) => target.id)
8822
+ });
8823
+ if (!intersectsTargets(effectiveTargets, selectedInstructionTargetIds)) {
8149
8824
  continue;
8150
8825
  }
8151
8826
  validateAgentTemplating({
8152
- content: contents,
8827
+ content: template.rawContents,
8153
8828
  validAgents: options.validAgents,
8154
- sourcePath: entry2.sourcePath
8829
+ sourcePath: template.sourcePath
8155
8830
  });
8156
8831
  }
8157
8832
  }
@@ -8746,12 +9421,11 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
8746
9421
  commands: /* @__PURE__ */ new Set()
8747
9422
  };
8748
9423
  const includeItemFor = (category) => {
8749
- if (!profileItemFilter.enabled) {
8750
- return void 0;
8751
- }
8752
- return (name) => {
8753
- traversedProfileNames[category].add(name);
8754
- return profileItemFilter.includes(category, name);
9424
+ return (item) => {
9425
+ if (profileItemFilter.enabled) {
9426
+ traversedProfileNames[category].add(item.canonicalName);
9427
+ }
9428
+ return profileItemFilter.includes(category, item);
8755
9429
  };
8756
9430
  };
8757
9431
  if (filteredTargets.length === 0 && !listLocal) {
@@ -8957,6 +9631,10 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
8957
9631
  repoRoot,
8958
9632
  agentsDir,
8959
9633
  validAgents,
9634
+ selectedSkillTargets,
9635
+ selectedCommandTargets,
9636
+ selectedSubagentTargets,
9637
+ selectedInstructionTargets,
8960
9638
  commandsAvailable: hasCommandsToSync,
8961
9639
  skillsAvailable: hasSkillsToSync,
8962
9640
  subagentsAvailable: hasSubagentsToSync,
@@ -9159,7 +9837,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
9159
9837
  resolveTargetName,
9160
9838
  hooks: globalHooks,
9161
9839
  templateScriptRuntime: scriptRuntime,
9162
- includeItem: includeItemFor("subagents")
9840
+ includeItem: includeItemFor("subagents"),
9841
+ includeSkill: includeItemFor("skills")
9163
9842
  });
9164
9843
  if (availabilitySubagentSkips.length > 0) {
9165
9844
  const subagentWarnings = mergeWarnings(