omniagent 0.1.5 → 0.1.7
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/README.md +6 -2
- package/dist/cli.js +1080 -201
- package/package.json +3 -2
- package/schemas/profile.v1.json +1 -1
- package/CLAUDE.md +0 -67
- package/CONTRIBUTING.md +0 -56
- package/biome.json +0 -41
- package/tasks.md +0 -25
- package/tsconfig.json +0 -13
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -10
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$
|
|
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$
|
|
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: () =>
|
|
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,
|
|
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
|
-
|
|
366
|
+
const enableMatches = matchAny(canonicalName, enablePatterns);
|
|
367
|
+
const disableMatches = matchAny(canonicalName, disablePatterns);
|
|
368
|
+
if (disableMatches) {
|
|
357
369
|
return false;
|
|
358
370
|
}
|
|
359
|
-
if (
|
|
360
|
-
return
|
|
371
|
+
if (enableApplies) {
|
|
372
|
+
return enableMatches;
|
|
361
373
|
}
|
|
362
|
-
return
|
|
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,
|
|
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
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1754
|
-
|
|
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 (
|
|
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
|
-
|
|
2024
|
-
|
|
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 (
|
|
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);
|
|
@@ -2811,6 +2898,26 @@ function resolveTargets(options) {
|
|
|
2811
2898
|
disabledTargets
|
|
2812
2899
|
};
|
|
2813
2900
|
}
|
|
2901
|
+
const PROFILE_SCHEMA_URL = "https://raw.githubusercontent.com/JoeRoddy/omniagent/master/schemas/profile.v1.json";
|
|
2902
|
+
const ANSI_GRAY = "\x1B[90m";
|
|
2903
|
+
const ANSI_RESET_FOREGROUND = "\x1B[39m";
|
|
2904
|
+
const PROFILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
2905
|
+
const STARTER_PROFILE = {
|
|
2906
|
+
$schema: PROFILE_SCHEMA_URL,
|
|
2907
|
+
description: "",
|
|
2908
|
+
targets: {},
|
|
2909
|
+
enable: {
|
|
2910
|
+
skills: [],
|
|
2911
|
+
subagents: [],
|
|
2912
|
+
commands: []
|
|
2913
|
+
},
|
|
2914
|
+
disable: {
|
|
2915
|
+
skills: [],
|
|
2916
|
+
subagents: [],
|
|
2917
|
+
commands: []
|
|
2918
|
+
},
|
|
2919
|
+
variables: {}
|
|
2920
|
+
};
|
|
2814
2921
|
async function resolveRepoAndAgentsDir(argv) {
|
|
2815
2922
|
const startDir = process.cwd();
|
|
2816
2923
|
const repoRoot = await findRepoRoot(startDir);
|
|
@@ -2844,6 +2951,122 @@ function formatAnnotations(entry2) {
|
|
|
2844
2951
|
}
|
|
2845
2952
|
return annotations;
|
|
2846
2953
|
}
|
|
2954
|
+
function validateProfileNamePart(name) {
|
|
2955
|
+
if (!PROFILE_NAME_PATTERN.test(name)) {
|
|
2956
|
+
return "Profile names may only contain letters, numbers, dots, underscores, and hyphens, and must start with a letter or number.";
|
|
2957
|
+
}
|
|
2958
|
+
return null;
|
|
2959
|
+
}
|
|
2960
|
+
function parseInitProfileTarget(name) {
|
|
2961
|
+
if (name.endsWith(".local")) {
|
|
2962
|
+
const profileName = name.slice(0, -".local".length);
|
|
2963
|
+
const issue2 = validateProfileNamePart(profileName);
|
|
2964
|
+
if (issue2) {
|
|
2965
|
+
return { error: issue2 };
|
|
2966
|
+
}
|
|
2967
|
+
if (profileName.endsWith(".local")) {
|
|
2968
|
+
return { error: 'Profile names cannot end with ".local.local".' };
|
|
2969
|
+
}
|
|
2970
|
+
return {
|
|
2971
|
+
profileName,
|
|
2972
|
+
isLocal: true
|
|
2973
|
+
};
|
|
2974
|
+
}
|
|
2975
|
+
const issue = validateProfileNamePart(name);
|
|
2976
|
+
if (issue) {
|
|
2977
|
+
return { error: issue };
|
|
2978
|
+
}
|
|
2979
|
+
return {
|
|
2980
|
+
profileName: name,
|
|
2981
|
+
isLocal: false
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
function colorsEnabled() {
|
|
2985
|
+
if (process.env.NO_COLOR !== void 0) {
|
|
2986
|
+
return false;
|
|
2987
|
+
}
|
|
2988
|
+
const forced = process.env.FORCE_COLOR;
|
|
2989
|
+
if (forced !== void 0) {
|
|
2990
|
+
return forced !== "0" && forced.toLowerCase() !== "false";
|
|
2991
|
+
}
|
|
2992
|
+
return Boolean(process.stdout.isTTY);
|
|
2993
|
+
}
|
|
2994
|
+
function findLineCommentStart(line) {
|
|
2995
|
+
let inString = false;
|
|
2996
|
+
let escaped = false;
|
|
2997
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
2998
|
+
const char = line[index];
|
|
2999
|
+
if (escaped) {
|
|
3000
|
+
escaped = false;
|
|
3001
|
+
continue;
|
|
3002
|
+
}
|
|
3003
|
+
if (char === "\\" && inString) {
|
|
3004
|
+
escaped = true;
|
|
3005
|
+
continue;
|
|
3006
|
+
}
|
|
3007
|
+
if (char === '"') {
|
|
3008
|
+
inString = !inString;
|
|
3009
|
+
continue;
|
|
3010
|
+
}
|
|
3011
|
+
if (!inString && char === "/" && line[index + 1] === "/") {
|
|
3012
|
+
return index;
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
return null;
|
|
3016
|
+
}
|
|
3017
|
+
function colorizeGuideComments(text) {
|
|
3018
|
+
if (!colorsEnabled()) {
|
|
3019
|
+
return text;
|
|
3020
|
+
}
|
|
3021
|
+
return text.split("\n").map((line) => {
|
|
3022
|
+
const commentStart = findLineCommentStart(line);
|
|
3023
|
+
if (commentStart === null) {
|
|
3024
|
+
return line;
|
|
3025
|
+
}
|
|
3026
|
+
return `${line.slice(0, commentStart)}${ANSI_GRAY}${line.slice(commentStart)}${ANSI_RESET_FOREGROUND}`;
|
|
3027
|
+
}).join("\n");
|
|
3028
|
+
}
|
|
3029
|
+
function initGuide(target, displayPath) {
|
|
3030
|
+
const label = target.isLocal ? `Created local profile "${target.profileName}" at ${displayPath}.` : `Created profile "${target.profileName}" at ${displayPath}.`;
|
|
3031
|
+
const localHint = target.isLocal ? `
|
|
3032
|
+
Use profile name "${target.profileName}" when syncing; ".local" is only the file suffix.
|
|
3033
|
+
` : "";
|
|
3034
|
+
return colorizeGuideComments(`${label}${localHint}
|
|
3035
|
+
|
|
3036
|
+
Profile files must be valid JSON. This commented version is just a guide:
|
|
3037
|
+
|
|
3038
|
+
{
|
|
3039
|
+
"$schema": "${PROFILE_SCHEMA_URL}",
|
|
3040
|
+
|
|
3041
|
+
"description": "shown in \`omniagent profiles\`",
|
|
3042
|
+
|
|
3043
|
+
"targets": {
|
|
3044
|
+
"claude": { "enabled": true }, // includes Claude; overrides an earlier profile setting it false
|
|
3045
|
+
"gemini": { "enabled": false } // skips Gemini for this profile
|
|
3046
|
+
},
|
|
3047
|
+
|
|
3048
|
+
"enable": { // names/globs to include; also opts in items marked enabled:false
|
|
3049
|
+
"skills": ["code-review"],
|
|
3050
|
+
"subagents": ["reviewer"],
|
|
3051
|
+
"commands": []
|
|
3052
|
+
},
|
|
3053
|
+
|
|
3054
|
+
"disable": { // names/globs to exclude after enable rules
|
|
3055
|
+
"skills": [],
|
|
3056
|
+
"subagents": [],
|
|
3057
|
+
"commands": ["*-legacy"]
|
|
3058
|
+
},
|
|
3059
|
+
|
|
3060
|
+
// https://github.com/JoeRoddy/omniagent/blob/master/docs/templating.md
|
|
3061
|
+
"variables": {
|
|
3062
|
+
"REVIEW_STYLE": "thorough" // replaces {{REVIEW_STYLE}} in synced files
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
Try it:
|
|
3067
|
+
omniagent profiles show ${target.profileName}
|
|
3068
|
+
omniagent sync --profile ${target.profileName}`);
|
|
3069
|
+
}
|
|
2847
3070
|
async function loadProfileValidationCatalog(repoRoot, agentsDir) {
|
|
2848
3071
|
const { config } = await loadTargetConfig({ repoRoot, agentsDir });
|
|
2849
3072
|
const validation = validateTargetConfig({ config, builtIns: BUILTIN_TARGETS });
|
|
@@ -2863,23 +3086,64 @@ async function loadProfileValidationCatalog(repoRoot, agentsDir) {
|
|
|
2863
3086
|
]);
|
|
2864
3087
|
return {
|
|
2865
3088
|
resolveTargetName,
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
3089
|
+
skills: skillCatalog.skills,
|
|
3090
|
+
commands: commandCatalog.commands,
|
|
3091
|
+
subagents: subagentCatalog.subagents
|
|
2869
3092
|
};
|
|
2870
3093
|
}
|
|
2871
3094
|
function collectProfileReferenceIssues(profileName, resolvedProfile, catalog) {
|
|
2872
3095
|
const filter = createProfileItemFilter(resolvedProfile);
|
|
2873
|
-
|
|
2874
|
-
|
|
3096
|
+
const issues = [];
|
|
3097
|
+
for (const skill of catalog.skills) {
|
|
3098
|
+
const included = filter.includes("skills", {
|
|
3099
|
+
canonicalName: skill.name,
|
|
3100
|
+
enabledByDefault: skill.enabledByDefault
|
|
3101
|
+
});
|
|
3102
|
+
if (!included) {
|
|
3103
|
+
continue;
|
|
3104
|
+
}
|
|
3105
|
+
try {
|
|
3106
|
+
assertSkillDefinitionUsable(skill);
|
|
3107
|
+
} catch (error) {
|
|
3108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3109
|
+
issues.push(`profile "${profileName}" includes unusable skill "${skill.name}": ${message}`);
|
|
3110
|
+
}
|
|
2875
3111
|
}
|
|
2876
|
-
for (const
|
|
2877
|
-
filter.includes("commands",
|
|
3112
|
+
for (const command of catalog.commands) {
|
|
3113
|
+
const included = filter.includes("commands", {
|
|
3114
|
+
canonicalName: command.name,
|
|
3115
|
+
enabledByDefault: command.enabledByDefault
|
|
3116
|
+
});
|
|
3117
|
+
if (!included) {
|
|
3118
|
+
continue;
|
|
3119
|
+
}
|
|
3120
|
+
try {
|
|
3121
|
+
assertSlashCommandDefinitionUsable(command);
|
|
3122
|
+
} catch (error) {
|
|
3123
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3124
|
+
issues.push(
|
|
3125
|
+
`profile "${profileName}" includes unusable command "${command.name}": ${message}`
|
|
3126
|
+
);
|
|
3127
|
+
}
|
|
2878
3128
|
}
|
|
2879
|
-
for (const
|
|
2880
|
-
filter.includes("subagents",
|
|
3129
|
+
for (const subagent of catalog.subagents) {
|
|
3130
|
+
const included = filter.includes("subagents", {
|
|
3131
|
+
canonicalName: subagent.resolvedName,
|
|
3132
|
+
enabledByDefault: subagent.enabledByDefault
|
|
3133
|
+
});
|
|
3134
|
+
if (!included) {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
try {
|
|
3138
|
+
assertSubagentDefinitionUsable(subagent);
|
|
3139
|
+
} catch (error) {
|
|
3140
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3141
|
+
issues.push(
|
|
3142
|
+
`profile "${profileName}" includes unusable subagent "${subagent.resolvedName}": ${message}`
|
|
3143
|
+
);
|
|
3144
|
+
}
|
|
2881
3145
|
}
|
|
2882
|
-
|
|
3146
|
+
issues.push(...filter.collectUnknownWarnings());
|
|
2883
3147
|
for (const targetName of Object.keys(resolvedProfile.targets)) {
|
|
2884
3148
|
if (catalog.resolveTargetName(targetName)) {
|
|
2885
3149
|
continue;
|
|
@@ -2888,6 +3152,70 @@ function collectProfileReferenceIssues(profileName, resolvedProfile, catalog) {
|
|
|
2888
3152
|
}
|
|
2889
3153
|
return issues;
|
|
2890
3154
|
}
|
|
3155
|
+
const initSubcommand = {
|
|
3156
|
+
command: "init <name>",
|
|
3157
|
+
describe: "Create a new sync profile",
|
|
3158
|
+
builder: (yargs2) => yargs2.positional("name", {
|
|
3159
|
+
type: "string",
|
|
3160
|
+
demandOption: true,
|
|
3161
|
+
describe: "Profile name"
|
|
3162
|
+
}).option("agentsDir", {
|
|
3163
|
+
type: "string",
|
|
3164
|
+
describe: "Override the agents directory",
|
|
3165
|
+
defaultDescription: DEFAULT_AGENTS_DIR
|
|
3166
|
+
}),
|
|
3167
|
+
handler: async (argv) => {
|
|
3168
|
+
const typed = argv;
|
|
3169
|
+
const initTarget = parseInitProfileTarget(typed.name);
|
|
3170
|
+
if ("error" in initTarget) {
|
|
3171
|
+
console.error(`Error: ${initTarget.error}`);
|
|
3172
|
+
process.exit(1);
|
|
3173
|
+
return;
|
|
3174
|
+
}
|
|
3175
|
+
const resolved = await resolveRepoAndAgentsDir(typed);
|
|
3176
|
+
if (!resolved) return;
|
|
3177
|
+
if (initTarget.isLocal) {
|
|
3178
|
+
const existingDedicatedPath = profileLocalDedicatedPath(
|
|
3179
|
+
resolved.repoRoot,
|
|
3180
|
+
initTarget.profileName,
|
|
3181
|
+
resolved.agentsDir
|
|
3182
|
+
);
|
|
3183
|
+
const inspected = await inspectProfileFiles(
|
|
3184
|
+
resolved.repoRoot,
|
|
3185
|
+
initTarget.profileName,
|
|
3186
|
+
resolved.agentsDir
|
|
3187
|
+
);
|
|
3188
|
+
if (inspected.localDedicated.exists) {
|
|
3189
|
+
const displayPath2 = path.relative(resolved.repoRoot, existingDedicatedPath).split(path.sep).join("/");
|
|
3190
|
+
console.error(
|
|
3191
|
+
`Error: Local profile "${initTarget.profileName}" already exists at ${displayPath2}.`
|
|
3192
|
+
);
|
|
3193
|
+
process.exit(1);
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
const targetPath = initTarget.isLocal ? profileLocalSiblingPath(resolved.repoRoot, initTarget.profileName, resolved.agentsDir) : profileSharedPath(resolved.repoRoot, initTarget.profileName, resolved.agentsDir);
|
|
3198
|
+
const displayPath = path.relative(resolved.repoRoot, targetPath).split(path.sep).join("/");
|
|
3199
|
+
const starterContents = `${JSON.stringify(STARTER_PROFILE, null, 2)}
|
|
3200
|
+
`;
|
|
3201
|
+
try {
|
|
3202
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
3203
|
+
await writeFile(targetPath, starterContents, { encoding: "utf8", flag: "wx" });
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
const code = error.code;
|
|
3206
|
+
if (code === "EEXIST") {
|
|
3207
|
+
const label = initTarget.isLocal ? "Local profile" : "Profile";
|
|
3208
|
+
console.error(
|
|
3209
|
+
`Error: ${label} "${initTarget.profileName}" already exists at ${displayPath}.`
|
|
3210
|
+
);
|
|
3211
|
+
process.exit(1);
|
|
3212
|
+
return;
|
|
3213
|
+
}
|
|
3214
|
+
throw error;
|
|
3215
|
+
}
|
|
3216
|
+
console.log(initGuide(initTarget, displayPath));
|
|
3217
|
+
}
|
|
3218
|
+
};
|
|
2891
3219
|
const listSubcommand = {
|
|
2892
3220
|
command: "$0",
|
|
2893
3221
|
describe: "List available sync profiles",
|
|
@@ -3063,7 +3391,7 @@ const validateSubcommand = {
|
|
|
3063
3391
|
const profilesCommand = {
|
|
3064
3392
|
command: "profiles",
|
|
3065
3393
|
describe: "Inspect and validate sync profiles",
|
|
3066
|
-
builder: (yargs2) => yargs2.command(listSubcommand).command(showSubcommand).command(validateSubcommand).demandCommand(0).strictCommands(),
|
|
3394
|
+
builder: (yargs2) => yargs2.command(listSubcommand).command(initSubcommand).command(showSubcommand).command(validateSubcommand).demandCommand(0).strictCommands(),
|
|
3067
3395
|
handler: () => {
|
|
3068
3396
|
}
|
|
3069
3397
|
};
|
|
@@ -3232,11 +3560,11 @@ function applyAgentTemplating(options) {
|
|
|
3232
3560
|
sourcePath: options.sourcePath
|
|
3233
3561
|
});
|
|
3234
3562
|
}
|
|
3235
|
-
function hashIdentifier$
|
|
3563
|
+
function hashIdentifier$3(value) {
|
|
3236
3564
|
return createHash("sha256").update(value).digest("hex");
|
|
3237
3565
|
}
|
|
3238
3566
|
function resolveIgnorePreferencePath(repoRoot, homeDir = os.homedir()) {
|
|
3239
|
-
const repoHash = hashIdentifier$
|
|
3567
|
+
const repoHash = hashIdentifier$3(repoRoot);
|
|
3240
3568
|
return path.join(homeDir, ".omniagent", "state", "ignore-rules", "projects", `${repoHash}.json`);
|
|
3241
3569
|
}
|
|
3242
3570
|
async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
|
|
@@ -3248,7 +3576,7 @@ async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
|
|
|
3248
3576
|
return null;
|
|
3249
3577
|
}
|
|
3250
3578
|
return {
|
|
3251
|
-
projectId: parsed.projectId ?? hashIdentifier$
|
|
3579
|
+
projectId: parsed.projectId ?? hashIdentifier$3(repoRoot),
|
|
3252
3580
|
ignorePromptDeclined: parsed.ignorePromptDeclined,
|
|
3253
3581
|
updatedAt: parsed.updatedAt ?? (/* @__PURE__ */ new Date(0)).toISOString()
|
|
3254
3582
|
};
|
|
@@ -3263,7 +3591,7 @@ async function readIgnorePreference(repoRoot, homeDir = os.homedir()) {
|
|
|
3263
3591
|
async function recordIgnorePromptDeclined(repoRoot, homeDir = os.homedir()) {
|
|
3264
3592
|
const filePath = resolveIgnorePreferencePath(repoRoot, homeDir);
|
|
3265
3593
|
const preference = {
|
|
3266
|
-
projectId: hashIdentifier$
|
|
3594
|
+
projectId: hashIdentifier$3(repoRoot),
|
|
3267
3595
|
ignorePromptDeclined: true,
|
|
3268
3596
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3269
3597
|
};
|
|
@@ -3957,7 +4285,7 @@ async function runConvertHook(hooks, stage, context) {
|
|
|
3957
4285
|
}
|
|
3958
4286
|
await runHook(hooks[stage], context);
|
|
3959
4287
|
}
|
|
3960
|
-
function hashIdentifier$
|
|
4288
|
+
function hashIdentifier$2(value) {
|
|
3961
4289
|
return createHash("sha256").update(value).digest("hex");
|
|
3962
4290
|
}
|
|
3963
4291
|
function hashContent$1(value) {
|
|
@@ -4018,7 +4346,7 @@ async function hashOutputPath(outputPath) {
|
|
|
4018
4346
|
}
|
|
4019
4347
|
}
|
|
4020
4348
|
function resolveManagedOutputsPath(repoRoot, homeDir = os.homedir()) {
|
|
4021
|
-
const repoHash = hashIdentifier$
|
|
4349
|
+
const repoHash = hashIdentifier$2(repoRoot);
|
|
4022
4350
|
const baseDir = path.join(
|
|
4023
4351
|
homeDir,
|
|
4024
4352
|
".omniagent",
|
|
@@ -4547,9 +4875,8 @@ function listTemplateScriptExecutions(runtime) {
|
|
|
4547
4875
|
);
|
|
4548
4876
|
}
|
|
4549
4877
|
const utf8Decoder$1 = new TextDecoder("utf-8", { fatal: true });
|
|
4550
|
-
const TARGET_FRONTMATTER_KEYS$2 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
|
|
4551
4878
|
const SKILL_FRONTMATTER_KEYS_TO_REMOVE = /* @__PURE__ */ new Set([
|
|
4552
|
-
...
|
|
4879
|
+
...SYNC_ROUTING_FRONTMATTER_KEYS,
|
|
4553
4880
|
"tools",
|
|
4554
4881
|
"model",
|
|
4555
4882
|
"color"
|
|
@@ -4741,7 +5068,7 @@ async function copySkillDirectory(options) {
|
|
|
4741
5068
|
validAgents: options.validAgents,
|
|
4742
5069
|
sourcePath: winner.sourcePath
|
|
4743
5070
|
});
|
|
4744
|
-
const output = winner.isSkillFile ? stripFrontmatterFields(templated,
|
|
5071
|
+
const output = winner.isSkillFile ? stripFrontmatterFields(templated, SYNC_ROUTING_FRONTMATTER_KEYS) : templated;
|
|
4745
5072
|
await mkdir(path.dirname(winner.destinationPath), { recursive: true });
|
|
4746
5073
|
await writeFile(winner.destinationPath, output, "utf8");
|
|
4747
5074
|
}
|
|
@@ -4785,7 +5112,7 @@ const defaultSubagentWriter = {
|
|
|
4785
5112
|
validAgents: options.context.validAgents,
|
|
4786
5113
|
sourcePath: item.sourcePath
|
|
4787
5114
|
});
|
|
4788
|
-
const cleaned = item.outputKind === "skill" ? stripFrontmatterFields(templated, SKILL_FRONTMATTER_KEYS_TO_REMOVE) : stripFrontmatterFields(templated,
|
|
5115
|
+
const cleaned = item.outputKind === "skill" ? stripFrontmatterFields(templated, SKILL_FRONTMATTER_KEYS_TO_REMOVE) : stripFrontmatterFields(templated, SYNC_ROUTING_FRONTMATTER_KEYS);
|
|
4789
5116
|
if (item.outputKind === "skill") {
|
|
4790
5117
|
const destinationPath = path.join(options.outputPath, "SKILL.md");
|
|
4791
5118
|
return writeOutputFile(destinationPath, cleaned);
|
|
@@ -4806,16 +5133,16 @@ const defaultInstructionWriter = {
|
|
|
4806
5133
|
async function writeFileOutput(outputPath, content) {
|
|
4807
5134
|
return writeOutputFile(outputPath, content);
|
|
4808
5135
|
}
|
|
4809
|
-
function hashIdentifier(value) {
|
|
5136
|
+
function hashIdentifier$1(value) {
|
|
4810
5137
|
return createHash("sha256").update(value).digest("hex");
|
|
4811
5138
|
}
|
|
4812
|
-
function resolveManifestPath(repoRoot, homeDir = os.homedir()) {
|
|
4813
|
-
const repoHash = hashIdentifier(repoRoot);
|
|
5139
|
+
function resolveManifestPath$1(repoRoot, homeDir = os.homedir()) {
|
|
5140
|
+
const repoHash = hashIdentifier$1(repoRoot);
|
|
4814
5141
|
const baseDir = path.join(homeDir, ".omniagent", "state", "instructions", "projects", repoHash);
|
|
4815
5142
|
return path.join(baseDir, "instruction-outputs.json");
|
|
4816
5143
|
}
|
|
4817
|
-
async function readManifest(repoRoot, homeDir) {
|
|
4818
|
-
const manifestPath = resolveManifestPath(repoRoot, homeDir);
|
|
5144
|
+
async function readManifest$1(repoRoot, homeDir) {
|
|
5145
|
+
const manifestPath = resolveManifestPath$1(repoRoot, homeDir);
|
|
4819
5146
|
try {
|
|
4820
5147
|
const contents = await readFile(manifestPath, "utf8");
|
|
4821
5148
|
const parsed = JSON.parse(contents);
|
|
@@ -4828,7 +5155,7 @@ async function readManifest(repoRoot, homeDir) {
|
|
|
4828
5155
|
}
|
|
4829
5156
|
}
|
|
4830
5157
|
async function writeManifest(repoRoot, manifest, homeDir) {
|
|
4831
|
-
const manifestPath = resolveManifestPath(repoRoot, homeDir);
|
|
5158
|
+
const manifestPath = resolveManifestPath$1(repoRoot, homeDir);
|
|
4832
5159
|
const sorted = [...manifest.entries].sort((left, right) => {
|
|
4833
5160
|
const targetCompare = left.targetName.localeCompare(right.targetName);
|
|
4834
5161
|
if (targetCompare !== 0) {
|
|
@@ -5397,7 +5724,7 @@ async function syncInstructions(request) {
|
|
|
5397
5724
|
groupResult.hadFailure = true;
|
|
5398
5725
|
}
|
|
5399
5726
|
}
|
|
5400
|
-
const previousManifest = await readManifest(request.repoRoot) ?? { entries: [] };
|
|
5727
|
+
const previousManifest = await readManifest$1(request.repoRoot) ?? { entries: [] };
|
|
5401
5728
|
const previousEntries = /* @__PURE__ */ new Map();
|
|
5402
5729
|
for (const entry2 of previousManifest.entries) {
|
|
5403
5730
|
const group = resolveInstructionTargetGroup(entry2.targetName);
|
|
@@ -5649,6 +5976,9 @@ function formatDisplayPath$3(repoRoot, absolutePath) {
|
|
|
5649
5976
|
const isWithinRepo = relative && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
5650
5977
|
return isWithinRepo ? relative : absolutePath;
|
|
5651
5978
|
}
|
|
5979
|
+
function buildManagedOutputPathKey(entry2) {
|
|
5980
|
+
return `${entry2.targetId}:${normalizeManagedOutputPath(entry2.outputPath)}`;
|
|
5981
|
+
}
|
|
5652
5982
|
function buildInvalidTargetWarnings$2(skills) {
|
|
5653
5983
|
const warnings = [];
|
|
5654
5984
|
for (const skill of skills) {
|
|
@@ -5662,6 +5992,20 @@ function buildInvalidTargetWarnings$2(skills) {
|
|
|
5662
5992
|
}
|
|
5663
5993
|
return warnings;
|
|
5664
5994
|
}
|
|
5995
|
+
function assertUsableSkillsForTargets(options) {
|
|
5996
|
+
for (const skill of options.skills) {
|
|
5997
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
5998
|
+
defaultTargets: skill.targetAgents,
|
|
5999
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
6000
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
6001
|
+
allTargets: options.allTargets
|
|
6002
|
+
});
|
|
6003
|
+
if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
|
|
6004
|
+
continue;
|
|
6005
|
+
}
|
|
6006
|
+
assertSkillDefinitionUsable(skill);
|
|
6007
|
+
}
|
|
6008
|
+
}
|
|
5665
6009
|
async function syncSkills(request) {
|
|
5666
6010
|
const templateScriptRuntime = request.templateScriptRuntime ?? createTemplateScriptRuntime({ cwd: request.repoRoot });
|
|
5667
6011
|
const sourcePath = resolveSharedCategoryRoot(request.repoRoot, "skills", request.agentsDir);
|
|
@@ -5680,17 +6024,25 @@ async function syncSkills(request) {
|
|
|
5680
6024
|
agentsDir: request.agentsDir,
|
|
5681
6025
|
resolveTargetName: request.resolveTargetName
|
|
5682
6026
|
});
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
6027
|
+
const includeItem = request.includeItem;
|
|
6028
|
+
const predicate = (skill) => includeItem ? includeItem({
|
|
6029
|
+
canonicalName: skill.name,
|
|
6030
|
+
enabledByDefault: skill.enabledByDefault
|
|
6031
|
+
}) : skill.enabledByDefault;
|
|
6032
|
+
catalog.skills = catalog.skills.filter(predicate);
|
|
6033
|
+
catalog.sharedSkills = catalog.sharedSkills.filter(predicate);
|
|
6034
|
+
catalog.localSkills = catalog.localSkills.filter(predicate);
|
|
6035
|
+
catalog.localEffectiveSkills = catalog.localEffectiveSkills.filter(predicate);
|
|
5692
6036
|
const allTargetIds = request.targets.map((target) => target.id);
|
|
5693
6037
|
const targetNames = new Set(skillTargets.map((target) => target.id));
|
|
6038
|
+
assertUsableSkillsForTargets({
|
|
6039
|
+
skills: catalog.skills,
|
|
6040
|
+
activeTargetIds: targetNames,
|
|
6041
|
+
overrideOnly: request.overrideOnly,
|
|
6042
|
+
overrideSkip: request.overrideSkip,
|
|
6043
|
+
allTargets: allTargetIds
|
|
6044
|
+
});
|
|
6045
|
+
const warnings = buildInvalidTargetWarnings$2(catalog.skills);
|
|
5694
6046
|
const effectiveTargetsBySkill = /* @__PURE__ */ new Map();
|
|
5695
6047
|
const activeSourcesByTarget = /* @__PURE__ */ new Map();
|
|
5696
6048
|
for (const skill of catalog.skills) {
|
|
@@ -5950,7 +6302,13 @@ async function syncSkills(request) {
|
|
|
5950
6302
|
if (managedManifest.entries.length > 0 || nextManaged.size > 0) {
|
|
5951
6303
|
const updatedEntries = [];
|
|
5952
6304
|
const managedTargetIds = new Set(skillTargets.map((target) => target.id));
|
|
6305
|
+
const claimedSkillOutputPaths = new Set(
|
|
6306
|
+
Array.from(nextManaged.values()).filter((entry2) => entry2.sourceType === "skill").map((entry2) => buildManagedOutputPathKey(entry2))
|
|
6307
|
+
);
|
|
5953
6308
|
for (const entry2 of managedManifest.entries) {
|
|
6309
|
+
if (entry2.sourceType === "subagent" && claimedSkillOutputPaths.has(buildManagedOutputPathKey(entry2))) {
|
|
6310
|
+
continue;
|
|
6311
|
+
}
|
|
5954
6312
|
if (entry2.sourceType !== "skill" || !managedTargetIds.has(entry2.targetId)) {
|
|
5955
6313
|
updatedEntries.push(entry2);
|
|
5956
6314
|
continue;
|
|
@@ -6075,11 +6433,10 @@ function formatTomlValue(value) {
|
|
|
6075
6433
|
function formatYamlString(value) {
|
|
6076
6434
|
return JSON.stringify(value);
|
|
6077
6435
|
}
|
|
6078
|
-
const TARGET_FRONTMATTER_KEYS$1 = /* @__PURE__ */ new Set(["targets", "targetagents"]);
|
|
6079
6436
|
function stripTargetMetadata(frontmatter) {
|
|
6080
6437
|
const filtered = {};
|
|
6081
6438
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
6082
|
-
if (
|
|
6439
|
+
if (SYNC_ROUTING_FRONTMATTER_KEYS.has(key.toLowerCase())) {
|
|
6083
6440
|
continue;
|
|
6084
6441
|
}
|
|
6085
6442
|
filtered[key] = value;
|
|
@@ -6141,9 +6498,9 @@ function renderYamlFrontmatter(frontmatter, defaultName) {
|
|
|
6141
6498
|
lines.push("---", "");
|
|
6142
6499
|
return lines.join("\n");
|
|
6143
6500
|
}
|
|
6144
|
-
const TOML_RESERVED_KEYS = /* @__PURE__ */ new Set(["prompt",
|
|
6501
|
+
const TOML_RESERVED_KEYS = /* @__PURE__ */ new Set(["prompt", ...SYNC_ROUTING_FRONTMATTER_KEYS]);
|
|
6145
6502
|
function renderMarkdownCommand(command) {
|
|
6146
|
-
return stripFrontmatterFields(command.rawContents,
|
|
6503
|
+
return stripFrontmatterFields(command.rawContents, SYNC_ROUTING_FRONTMATTER_KEYS);
|
|
6147
6504
|
}
|
|
6148
6505
|
function renderTomlCommand(command) {
|
|
6149
6506
|
const lines = [];
|
|
@@ -6281,6 +6638,36 @@ function formatSyncSummary(summary, jsonOutput) {
|
|
|
6281
6638
|
}
|
|
6282
6639
|
return lines.join("\n");
|
|
6283
6640
|
}
|
|
6641
|
+
function includeCommandByDefault(command, includeItem) {
|
|
6642
|
+
if (!includeItem) {
|
|
6643
|
+
return command.enabledByDefault;
|
|
6644
|
+
}
|
|
6645
|
+
return includeItem({
|
|
6646
|
+
canonicalName: command.name,
|
|
6647
|
+
enabledByDefault: command.enabledByDefault
|
|
6648
|
+
});
|
|
6649
|
+
}
|
|
6650
|
+
function filterCommandCatalog(catalog, includeItem) {
|
|
6651
|
+
const predicate = (command) => includeCommandByDefault(command, includeItem);
|
|
6652
|
+
catalog.commands = catalog.commands.filter(predicate);
|
|
6653
|
+
catalog.sharedCommands = catalog.sharedCommands.filter(predicate);
|
|
6654
|
+
catalog.localCommands = catalog.localCommands.filter(predicate);
|
|
6655
|
+
catalog.localEffectiveCommands = catalog.localEffectiveCommands.filter(predicate);
|
|
6656
|
+
}
|
|
6657
|
+
function assertUsableCommandsForTargets(options) {
|
|
6658
|
+
for (const command of options.commands) {
|
|
6659
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
6660
|
+
defaultTargets: command.targetAgents,
|
|
6661
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
6662
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
6663
|
+
allTargets: options.allTargets
|
|
6664
|
+
});
|
|
6665
|
+
if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6668
|
+
assertSlashCommandDefinitionUsable(command);
|
|
6669
|
+
}
|
|
6670
|
+
}
|
|
6284
6671
|
function renderCommandOutput(command, outputKind, outputPath) {
|
|
6285
6672
|
if (outputKind === "skill") {
|
|
6286
6673
|
return renderSkillFromCommand(command);
|
|
@@ -6310,14 +6697,7 @@ async function syncSlashCommands(request) {
|
|
|
6310
6697
|
agentsDir: request.agentsDir,
|
|
6311
6698
|
resolveTargetName: request.resolveTargetName
|
|
6312
6699
|
});
|
|
6313
|
-
|
|
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
|
-
}
|
|
6700
|
+
filterCommandCatalog(catalog, request.includeItem);
|
|
6321
6701
|
const targets = request.targets.filter(
|
|
6322
6702
|
(target) => normalizeCommandOutputDefinition(target.outputs.commands) !== null
|
|
6323
6703
|
);
|
|
@@ -6338,6 +6718,13 @@ async function syncSlashCommands(request) {
|
|
|
6338
6718
|
const removeMissing = request.removeMissing ?? false;
|
|
6339
6719
|
const allTargetIds = request.targets.map((target) => target.id);
|
|
6340
6720
|
const activeTargetIds = new Set(targets.map((target) => target.id));
|
|
6721
|
+
assertUsableCommandsForTargets({
|
|
6722
|
+
commands: catalog.commands,
|
|
6723
|
+
activeTargetIds,
|
|
6724
|
+
overrideOnly: request.overrideOnly,
|
|
6725
|
+
overrideSkip: request.overrideSkip,
|
|
6726
|
+
allTargets: allTargetIds
|
|
6727
|
+
});
|
|
6341
6728
|
const effectiveTargetsByCommand = /* @__PURE__ */ new Map();
|
|
6342
6729
|
const activeSourcesByTarget = /* @__PURE__ */ new Map();
|
|
6343
6730
|
for (const command of catalog.commands) {
|
|
@@ -6803,39 +7190,125 @@ async function syncSlashCommands(request) {
|
|
|
6803
7190
|
sourceCounts
|
|
6804
7191
|
};
|
|
6805
7192
|
}
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
...TARGET_FRONTMATTER_KEYS,
|
|
6809
|
-
"tools",
|
|
6810
|
-
"model",
|
|
6811
|
-
"color"
|
|
6812
|
-
]);
|
|
6813
|
-
function emptySummaryCounts() {
|
|
6814
|
-
return { created: 0, updated: 0, removed: 0, converted: 0, skipped: 0 };
|
|
7193
|
+
function hashIdentifier(value) {
|
|
7194
|
+
return createHash("sha256").update(value).digest("hex");
|
|
6815
7195
|
}
|
|
6816
|
-
function
|
|
6817
|
-
|
|
7196
|
+
function resolveManifestPath(repoRoot, targetName, homeDir) {
|
|
7197
|
+
const repoHash = hashIdentifier(repoRoot);
|
|
7198
|
+
const baseDir = path.join(homeDir, ".omniagent", "state", "subagents", "projects", repoHash);
|
|
7199
|
+
return path.join(baseDir, `${targetName}.toml`);
|
|
6818
7200
|
}
|
|
6819
|
-
function
|
|
6820
|
-
|
|
6821
|
-
|
|
7201
|
+
function parseTomlValue(rawValue) {
|
|
7202
|
+
const trimmed = rawValue.trim();
|
|
7203
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
7204
|
+
try {
|
|
7205
|
+
return JSON.parse(trimmed);
|
|
7206
|
+
} catch {
|
|
7207
|
+
return trimmed.slice(1, -1);
|
|
7208
|
+
}
|
|
6822
7209
|
}
|
|
6823
|
-
|
|
6824
|
-
const { baseName: strippedBase } = stripLocalPathSuffix(baseName);
|
|
6825
|
-
const parent = path.dirname(relativePath);
|
|
6826
|
-
return parent === "." ? strippedBase : path.join(parent, strippedBase);
|
|
6827
|
-
}
|
|
6828
|
-
function formatDisplayPath$1(repoRoot, absolutePath) {
|
|
6829
|
-
const relative = path.relative(repoRoot, absolutePath);
|
|
6830
|
-
const isWithinRepo = relative && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
6831
|
-
return isWithinRepo ? relative : absolutePath;
|
|
7210
|
+
return trimmed;
|
|
6832
7211
|
}
|
|
6833
|
-
function
|
|
6834
|
-
const
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
7212
|
+
function parseManifest(contents) {
|
|
7213
|
+
const lines = contents.split(/\r?\n/);
|
|
7214
|
+
let targetName = null;
|
|
7215
|
+
const managedSubagents = [];
|
|
7216
|
+
let current = null;
|
|
7217
|
+
for (const line of lines) {
|
|
7218
|
+
const trimmed = line.trim();
|
|
7219
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
7220
|
+
continue;
|
|
7221
|
+
}
|
|
7222
|
+
if (trimmed === "[[managedSubagents]]") {
|
|
7223
|
+
if (current?.name && current.hash && current.lastSyncedAt) {
|
|
7224
|
+
managedSubagents.push({
|
|
7225
|
+
name: current.name,
|
|
7226
|
+
hash: current.hash,
|
|
7227
|
+
lastSyncedAt: current.lastSyncedAt
|
|
7228
|
+
});
|
|
7229
|
+
}
|
|
7230
|
+
current = {};
|
|
7231
|
+
continue;
|
|
7232
|
+
}
|
|
7233
|
+
const match = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*(.+)$/);
|
|
7234
|
+
if (!match) {
|
|
7235
|
+
continue;
|
|
7236
|
+
}
|
|
7237
|
+
const [, key, rawValue] = match;
|
|
7238
|
+
const value = parseTomlValue(rawValue);
|
|
7239
|
+
if (current) {
|
|
7240
|
+
if (key === "name") {
|
|
7241
|
+
current.name = value;
|
|
7242
|
+
continue;
|
|
7243
|
+
}
|
|
7244
|
+
if (key === "hash") {
|
|
7245
|
+
current.hash = value;
|
|
7246
|
+
continue;
|
|
7247
|
+
}
|
|
7248
|
+
if (key === "lastSyncedAt") {
|
|
7249
|
+
current.lastSyncedAt = value;
|
|
7250
|
+
continue;
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
if (key === "targetName") {
|
|
7254
|
+
targetName = value;
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
if (current?.name && current.hash && current.lastSyncedAt) {
|
|
7258
|
+
managedSubagents.push({
|
|
7259
|
+
name: current.name,
|
|
7260
|
+
hash: current.hash,
|
|
7261
|
+
lastSyncedAt: current.lastSyncedAt
|
|
7262
|
+
});
|
|
7263
|
+
}
|
|
7264
|
+
if (!targetName) {
|
|
7265
|
+
return null;
|
|
7266
|
+
}
|
|
7267
|
+
return {
|
|
7268
|
+
targetName,
|
|
7269
|
+
managedSubagents
|
|
7270
|
+
};
|
|
7271
|
+
}
|
|
7272
|
+
async function readManifest(manifestPath) {
|
|
7273
|
+
try {
|
|
7274
|
+
const contents = await readFile(manifestPath, "utf8");
|
|
7275
|
+
return parseManifest(contents);
|
|
7276
|
+
} catch {
|
|
7277
|
+
return null;
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
7280
|
+
/* @__PURE__ */ new Set([
|
|
7281
|
+
...SYNC_ROUTING_FRONTMATTER_KEYS,
|
|
7282
|
+
"tools",
|
|
7283
|
+
"model",
|
|
7284
|
+
"color"
|
|
7285
|
+
]);
|
|
7286
|
+
function emptySummaryCounts() {
|
|
7287
|
+
return { created: 0, updated: 0, removed: 0, converted: 0, skipped: 0 };
|
|
7288
|
+
}
|
|
7289
|
+
function normalizeSkillKey(name) {
|
|
7290
|
+
return path.normalize(name).replace(/\\/g, "/").toLowerCase();
|
|
7291
|
+
}
|
|
7292
|
+
function includeCanonicalSkill(options) {
|
|
7293
|
+
if (!options.includeSkill) {
|
|
7294
|
+
return options.enabledByDefault;
|
|
7295
|
+
}
|
|
7296
|
+
return options.includeSkill({
|
|
7297
|
+
canonicalName: options.canonicalName,
|
|
7298
|
+
enabledByDefault: options.enabledByDefault
|
|
7299
|
+
});
|
|
7300
|
+
}
|
|
7301
|
+
function formatDisplayPath$1(repoRoot, absolutePath) {
|
|
7302
|
+
const relative = path.relative(repoRoot, absolutePath);
|
|
7303
|
+
const isWithinRepo = relative && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
7304
|
+
return isWithinRepo ? relative : absolutePath;
|
|
7305
|
+
}
|
|
7306
|
+
function buildSourceCounts(subagents, targets, allTargets, request) {
|
|
7307
|
+
const targetSet = new Set(targets.map((target) => target.toLowerCase()));
|
|
7308
|
+
const counts = {
|
|
7309
|
+
shared: 0,
|
|
7310
|
+
local: 0,
|
|
7311
|
+
excludedLocal: request.excludeLocal ?? false
|
|
6839
7312
|
};
|
|
6840
7313
|
for (const subagent of subagents) {
|
|
6841
7314
|
const effectiveTargets = resolveEffectiveTargets({
|
|
@@ -6858,71 +7331,313 @@ function buildSourceCounts(subagents, targets, allTargets, request) {
|
|
|
6858
7331
|
}
|
|
6859
7332
|
return counts;
|
|
6860
7333
|
}
|
|
6861
|
-
|
|
7334
|
+
function resolveSkillRelativePath(skillsRoot, directoryPath) {
|
|
7335
|
+
const relativePath = path.relative(skillsRoot, directoryPath);
|
|
7336
|
+
if (!relativePath) {
|
|
7337
|
+
return { relativePath, hadLocalSuffix: false };
|
|
7338
|
+
}
|
|
7339
|
+
const baseName = path.basename(relativePath);
|
|
7340
|
+
const { baseName: strippedBase, hadLocalSuffix } = stripLocalPathSuffix(baseName);
|
|
7341
|
+
if (!hadLocalSuffix) {
|
|
7342
|
+
return { relativePath, hadLocalSuffix: false };
|
|
7343
|
+
}
|
|
7344
|
+
const parent = path.dirname(relativePath);
|
|
7345
|
+
const normalized = parent === "." ? strippedBase : path.join(parent, strippedBase);
|
|
7346
|
+
return { relativePath: normalized, hadLocalSuffix: true };
|
|
7347
|
+
}
|
|
7348
|
+
function resolveSkillName(frontmatter, fallback) {
|
|
7349
|
+
const rawName = frontmatter.name;
|
|
7350
|
+
if (typeof rawName === "string") {
|
|
7351
|
+
const trimmed = rawName.trim();
|
|
7352
|
+
if (trimmed) {
|
|
7353
|
+
return trimmed;
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
return fallback;
|
|
7357
|
+
}
|
|
7358
|
+
function shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter) {
|
|
7359
|
+
if (!skillKeyFilter) {
|
|
7360
|
+
return true;
|
|
7361
|
+
}
|
|
7362
|
+
return skillKeyFilter.has(normalizeSkillKey(relativePath));
|
|
7363
|
+
}
|
|
7364
|
+
async function loadCanonicalSkillIndex(repoRoot, options) {
|
|
6862
7365
|
const includeLocal = options.includeLocal ?? true;
|
|
7366
|
+
const fallbackResolver = createTargetNameResolver(BUILTIN_TARGETS).resolveTargetName;
|
|
7367
|
+
const resolveTargetName = options.resolveTargetName ?? fallbackResolver;
|
|
6863
7368
|
const skillsRoot = resolveSharedCategoryRoot(repoRoot, "skills", options.agentsDir);
|
|
6864
7369
|
const localSkillsRoot = resolveLocalCategoryRoot(repoRoot, "skills", options.agentsDir);
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
directories = await listSkillDirectories(skillsRoot);
|
|
6868
|
-
} catch (error) {
|
|
6869
|
-
const code = error.code;
|
|
6870
|
-
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
6871
|
-
throw error;
|
|
6872
|
-
}
|
|
6873
|
-
}
|
|
7370
|
+
const targetFilter = options.targetIds ? new Set(options.targetIds) : null;
|
|
7371
|
+
const skillKeyFilter = options.skillKeys ? new Set(options.skillKeys) : null;
|
|
6874
7372
|
const index = /* @__PURE__ */ new Map();
|
|
6875
|
-
const
|
|
6876
|
-
|
|
6877
|
-
|
|
7373
|
+
const sharedStats = await readDirectoryStats(skillsRoot);
|
|
7374
|
+
if (sharedStats && !sharedStats.isDirectory()) {
|
|
7375
|
+
throw new Error(`Skills root is not a directory: ${skillsRoot}.`);
|
|
7376
|
+
}
|
|
7377
|
+
const localStats = includeLocal ? await readDirectoryStats(localSkillsRoot) : null;
|
|
7378
|
+
if (localStats && !localStats.isDirectory()) {
|
|
7379
|
+
throw new Error(`Local skills root is not a directory: ${localSkillsRoot}.`);
|
|
7380
|
+
}
|
|
7381
|
+
const sharedEntries = sharedStats ? await listSkillDirectories(skillsRoot) : [];
|
|
7382
|
+
const localEntries = localStats ? await listSkillDirectories(localSkillsRoot) : [];
|
|
7383
|
+
const sharedSkills = [];
|
|
7384
|
+
const localPathSkills = [];
|
|
7385
|
+
const localSuffixSkills = [];
|
|
7386
|
+
for (const entry2 of sharedEntries) {
|
|
7387
|
+
const { relativePath, hadLocalSuffix } = resolveSkillRelativePath(
|
|
7388
|
+
skillsRoot,
|
|
7389
|
+
entry2.directoryPath
|
|
7390
|
+
);
|
|
7391
|
+
if (!shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter)) {
|
|
7392
|
+
continue;
|
|
6878
7393
|
}
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
7394
|
+
if (hadLocalSuffix) {
|
|
7395
|
+
if (!includeLocal) {
|
|
7396
|
+
continue;
|
|
7397
|
+
}
|
|
7398
|
+
const skillFileName = entry2.localSkillFile ?? entry2.sharedSkillFile;
|
|
7399
|
+
if (!skillFileName) {
|
|
7400
|
+
continue;
|
|
7401
|
+
}
|
|
7402
|
+
localSuffixSkills.push({
|
|
7403
|
+
relativePath,
|
|
7404
|
+
sourcePath: path.join(entry2.directoryPath, skillFileName)
|
|
7405
|
+
});
|
|
6885
7406
|
continue;
|
|
6886
7407
|
}
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
7408
|
+
if (entry2.sharedSkillFile) {
|
|
7409
|
+
sharedSkills.push({
|
|
7410
|
+
relativePath,
|
|
7411
|
+
sourcePath: path.join(entry2.directoryPath, entry2.sharedSkillFile)
|
|
7412
|
+
});
|
|
6890
7413
|
}
|
|
6891
|
-
if (includeLocal) {
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
}
|
|
6897
|
-
} else if (entry2.localSkillFile) {
|
|
6898
|
-
addEntry(relative, path.join(entry2.directoryPath, entry2.localSkillFile));
|
|
6899
|
-
}
|
|
7414
|
+
if (includeLocal && entry2.localSkillFile) {
|
|
7415
|
+
localSuffixSkills.push({
|
|
7416
|
+
relativePath,
|
|
7417
|
+
sourcePath: path.join(entry2.directoryPath, entry2.localSkillFile)
|
|
7418
|
+
});
|
|
6900
7419
|
}
|
|
6901
7420
|
}
|
|
6902
7421
|
if (includeLocal) {
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
const code = error.code;
|
|
6908
|
-
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
6909
|
-
return index;
|
|
7422
|
+
for (const entry2 of localEntries) {
|
|
7423
|
+
const skillFileName = entry2.sharedSkillFile ?? entry2.localSkillFile;
|
|
7424
|
+
if (!skillFileName) {
|
|
7425
|
+
continue;
|
|
6910
7426
|
}
|
|
6911
|
-
|
|
7427
|
+
const { relativePath } = resolveSkillRelativePath(localSkillsRoot, entry2.directoryPath);
|
|
7428
|
+
if (!shouldIncludeCanonicalSkillRelativePath(relativePath, skillKeyFilter)) {
|
|
7429
|
+
continue;
|
|
7430
|
+
}
|
|
7431
|
+
localPathSkills.push({
|
|
7432
|
+
relativePath,
|
|
7433
|
+
sourcePath: path.join(entry2.directoryPath, skillFileName)
|
|
7434
|
+
});
|
|
6912
7435
|
}
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
7436
|
+
}
|
|
7437
|
+
const { localEffective: localEffectiveSkills, sharedEffective: sharedEffectiveSkills } = resolveLocalPrecedence({
|
|
7438
|
+
shared: sharedSkills,
|
|
7439
|
+
localPath: localPathSkills,
|
|
7440
|
+
localSuffix: localSuffixSkills,
|
|
7441
|
+
key: (skill) => normalizeSkillKey(skill.relativePath)
|
|
7442
|
+
});
|
|
7443
|
+
const effectiveSkills = includeLocal ? [...sharedEffectiveSkills, ...localEffectiveSkills] : sharedSkills;
|
|
7444
|
+
for (const skill of effectiveSkills) {
|
|
7445
|
+
const rawContents = await readFile(skill.sourcePath, "utf8");
|
|
7446
|
+
const { frontmatter } = extractFrontmatter$1(rawContents);
|
|
7447
|
+
const fallbackName = skill.relativePath || path.basename(path.dirname(skill.sourcePath));
|
|
7448
|
+
const skillName = resolveSkillName(frontmatter, fallbackName);
|
|
7449
|
+
const rawTargets = [frontmatter.targets, frontmatter.targetAgents];
|
|
7450
|
+
const { targets, invalidTargets } = resolveFrontmatterTargets(rawTargets, resolveTargetName);
|
|
7451
|
+
const hasEmptyTargets = hasRawTargetValues(rawTargets) && (!targets || targets.length === 0);
|
|
7452
|
+
const effectiveTargets = hasEmptyTargets ? [] : resolveEffectiveTargets({
|
|
7453
|
+
defaultTargets: targets,
|
|
7454
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
7455
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
7456
|
+
allTargets: options.allTargets
|
|
7457
|
+
});
|
|
7458
|
+
const matchingTargets = targetFilter ? effectiveTargets.filter((targetId) => targetFilter.has(targetId)) : effectiveTargets;
|
|
7459
|
+
if (matchingTargets.length === 0) {
|
|
7460
|
+
continue;
|
|
7461
|
+
}
|
|
7462
|
+
const enabledByDefault = resolveFrontmatterEnabledByDefault({
|
|
7463
|
+
frontmatter,
|
|
7464
|
+
itemKind: "Skill",
|
|
7465
|
+
itemName: skillName,
|
|
7466
|
+
sourcePath: skill.sourcePath
|
|
7467
|
+
});
|
|
7468
|
+
if (!includeCanonicalSkill({
|
|
7469
|
+
canonicalName: skillName,
|
|
7470
|
+
enabledByDefault,
|
|
7471
|
+
includeSkill: options.includeSkill
|
|
7472
|
+
})) {
|
|
7473
|
+
continue;
|
|
7474
|
+
}
|
|
7475
|
+
if (invalidTargets.length > 0) {
|
|
7476
|
+
const invalidList = invalidTargets.join(", ");
|
|
7477
|
+
throw new InvalidFrontmatterTargetsError(
|
|
7478
|
+
`Skill "${skillName}" has unsupported targets (${invalidList}) in ${skill.sourcePath}.`
|
|
7479
|
+
);
|
|
7480
|
+
}
|
|
7481
|
+
if (hasEmptyTargets) {
|
|
7482
|
+
throw new InvalidFrontmatterTargetsError(
|
|
7483
|
+
`Skill "${skillName}" has empty targets in ${skill.sourcePath}.`
|
|
7484
|
+
);
|
|
7485
|
+
}
|
|
7486
|
+
const skillKey = normalizeSkillKey(skill.relativePath);
|
|
7487
|
+
for (const targetId of matchingTargets) {
|
|
7488
|
+
const targetSkills = index.get(targetId) ?? /* @__PURE__ */ new Map();
|
|
7489
|
+
targetSkills.set(skillKey, skill.sourcePath);
|
|
7490
|
+
index.set(targetId, targetSkills);
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
return index;
|
|
7494
|
+
}
|
|
7495
|
+
function collectRelevantCanonicalSkillKeys(options) {
|
|
7496
|
+
const relevant = /* @__PURE__ */ new Set();
|
|
7497
|
+
for (const subagent of options.subagents) {
|
|
7498
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
7499
|
+
defaultTargets: subagent.targetAgents,
|
|
7500
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
7501
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
7502
|
+
allTargets: options.allTargets
|
|
7503
|
+
});
|
|
7504
|
+
if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
|
|
7505
|
+
continue;
|
|
7506
|
+
}
|
|
7507
|
+
relevant.add(normalizeSkillKey(subagent.resolvedName));
|
|
7508
|
+
}
|
|
7509
|
+
return relevant;
|
|
7510
|
+
}
|
|
7511
|
+
async function collectManagedCanonicalSkillKeys(options) {
|
|
7512
|
+
const managed = /* @__PURE__ */ new Set();
|
|
7513
|
+
const homeDir = os.homedir();
|
|
7514
|
+
const targetIds = new Set(options.targetIds);
|
|
7515
|
+
for (const targetId of options.targetIds) {
|
|
7516
|
+
const manifest = await readManifest(resolveManifestPath(options.repoRoot, targetId, homeDir));
|
|
7517
|
+
if (!manifest || manifest.targetName !== targetId) {
|
|
7518
|
+
continue;
|
|
7519
|
+
}
|
|
7520
|
+
for (const entry2 of manifest.managedSubagents) {
|
|
7521
|
+
managed.add(normalizeSkillKey(entry2.name));
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
const managedOutputs = await readManagedOutputs(options.repoRoot, homeDir);
|
|
7525
|
+
for (const entry2 of managedOutputs?.entries ?? []) {
|
|
7526
|
+
if (entry2.sourceType !== "subagent" || !targetIds.has(entry2.targetId)) {
|
|
7527
|
+
continue;
|
|
7528
|
+
}
|
|
7529
|
+
managed.add(normalizeSkillKey(entry2.sourceId));
|
|
7530
|
+
}
|
|
7531
|
+
return managed;
|
|
7532
|
+
}
|
|
7533
|
+
function getCanonicalSkillPath(index, targetId, skillKey) {
|
|
7534
|
+
return index.get(targetId)?.get(skillKey);
|
|
7535
|
+
}
|
|
7536
|
+
function recordShadowedSubagentSource(shadowedSources, targetId, sourceId) {
|
|
7537
|
+
const existing = shadowedSources.get(targetId) ?? /* @__PURE__ */ new Set();
|
|
7538
|
+
existing.add(normalizeName(sourceId));
|
|
7539
|
+
shadowedSources.set(targetId, existing);
|
|
7540
|
+
}
|
|
7541
|
+
function includeSubagentByDefault(subagent, includeItem) {
|
|
7542
|
+
if (!includeItem) {
|
|
7543
|
+
return subagent.enabledByDefault;
|
|
7544
|
+
}
|
|
7545
|
+
return includeItem({
|
|
7546
|
+
canonicalName: subagent.resolvedName,
|
|
7547
|
+
enabledByDefault: subagent.enabledByDefault
|
|
7548
|
+
});
|
|
7549
|
+
}
|
|
7550
|
+
function filterSubagentCatalog(catalog, includeItem) {
|
|
7551
|
+
const predicate = (subagent) => includeSubagentByDefault(subagent, includeItem);
|
|
7552
|
+
catalog.subagents = catalog.subagents.filter(predicate);
|
|
7553
|
+
catalog.sharedSubagents = catalog.sharedSubagents.filter(predicate);
|
|
7554
|
+
catalog.localSubagents = catalog.localSubagents.filter(predicate);
|
|
7555
|
+
catalog.localEffectiveSubagents = catalog.localEffectiveSubagents.filter(predicate);
|
|
7556
|
+
}
|
|
7557
|
+
function assertUsableSubagentsForTargets(options) {
|
|
7558
|
+
for (const subagent of options.subagents) {
|
|
7559
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
7560
|
+
defaultTargets: subagent.targetAgents,
|
|
7561
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
7562
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
7563
|
+
allTargets: options.allTargets
|
|
7564
|
+
});
|
|
7565
|
+
if (!effectiveTargets.some((targetId) => options.activeTargetIds.has(targetId))) {
|
|
7566
|
+
continue;
|
|
7567
|
+
}
|
|
7568
|
+
assertSubagentDefinitionUsable(subagent);
|
|
7569
|
+
}
|
|
7570
|
+
}
|
|
7571
|
+
function targetRequiresCanonicalSkillLookup(target) {
|
|
7572
|
+
const outputDef = normalizeOutputDefinition(target.outputs.subagents);
|
|
7573
|
+
if (!outputDef) {
|
|
7574
|
+
return false;
|
|
7575
|
+
}
|
|
7576
|
+
if (outputDef.fallback?.mode !== "convert" || outputDef.fallback.targetType !== "skills") {
|
|
7577
|
+
return false;
|
|
7578
|
+
}
|
|
7579
|
+
return normalizeOutputDefinition(target.outputs.skills) !== null;
|
|
7580
|
+
}
|
|
7581
|
+
async function resolveCanonicalSkillsForSubagentSync(options) {
|
|
7582
|
+
const targetIds = options.activeTargets.filter(targetRequiresCanonicalSkillLookup).map((target) => target.id);
|
|
7583
|
+
if (targetIds.length === 0) {
|
|
7584
|
+
return /* @__PURE__ */ new Map();
|
|
7585
|
+
}
|
|
7586
|
+
const relevantCanonicalSkillKeys = collectRelevantCanonicalSkillKeys({
|
|
7587
|
+
subagents: options.subagents,
|
|
7588
|
+
activeTargetIds: new Set(targetIds),
|
|
7589
|
+
overrideOnly: options.overrideOnly,
|
|
7590
|
+
overrideSkip: options.overrideSkip,
|
|
7591
|
+
allTargets: options.allTargetIds
|
|
7592
|
+
});
|
|
7593
|
+
for (const skillKey of await collectManagedCanonicalSkillKeys({
|
|
7594
|
+
repoRoot: options.repoRoot,
|
|
7595
|
+
targetIds
|
|
7596
|
+
})) {
|
|
7597
|
+
relevantCanonicalSkillKeys.add(skillKey);
|
|
7598
|
+
}
|
|
7599
|
+
if (relevantCanonicalSkillKeys.size === 0) {
|
|
7600
|
+
return /* @__PURE__ */ new Map();
|
|
7601
|
+
}
|
|
7602
|
+
return loadCanonicalSkillIndex(options.repoRoot, {
|
|
7603
|
+
includeLocal: options.includeLocalSkills ?? true,
|
|
7604
|
+
agentsDir: options.agentsDir,
|
|
7605
|
+
resolveTargetName: options.resolveTargetName,
|
|
7606
|
+
overrideOnly: options.overrideOnly ?? null,
|
|
7607
|
+
overrideSkip: options.overrideSkip ?? null,
|
|
7608
|
+
allTargets: options.allTargetIds,
|
|
7609
|
+
targetIds,
|
|
7610
|
+
skillKeys: relevantCanonicalSkillKeys,
|
|
7611
|
+
includeSkill: options.includeSkill
|
|
7612
|
+
});
|
|
7613
|
+
}
|
|
7614
|
+
async function resolveShadowedSubagentNamesForTargets(options) {
|
|
7615
|
+
const activeTargetIds = new Set(options.activeTargets.map((target) => target.id));
|
|
7616
|
+
const canonicalSkills = await resolveCanonicalSkillsForSubagentSync(options);
|
|
7617
|
+
const shadowedSources = /* @__PURE__ */ new Map();
|
|
7618
|
+
for (const subagent of options.subagents) {
|
|
7619
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
7620
|
+
defaultTargets: subagent.targetAgents,
|
|
7621
|
+
overrideOnly: options.overrideOnly ?? void 0,
|
|
7622
|
+
overrideSkip: options.overrideSkip ?? void 0,
|
|
7623
|
+
allTargets: options.allTargetIds
|
|
7624
|
+
});
|
|
7625
|
+
for (const targetId of effectiveTargets) {
|
|
7626
|
+
if (!activeTargetIds.has(targetId)) {
|
|
6916
7627
|
continue;
|
|
6917
7628
|
}
|
|
6918
|
-
const
|
|
6919
|
-
|
|
7629
|
+
const canonicalSkillPath = getCanonicalSkillPath(
|
|
7630
|
+
canonicalSkills,
|
|
7631
|
+
targetId,
|
|
7632
|
+
normalizeSkillKey(subagent.resolvedName)
|
|
7633
|
+
);
|
|
7634
|
+
if (!canonicalSkillPath) {
|
|
6920
7635
|
continue;
|
|
6921
7636
|
}
|
|
6922
|
-
|
|
7637
|
+
recordShadowedSubagentSource(shadowedSources, targetId, subagent.resolvedName);
|
|
6923
7638
|
}
|
|
6924
7639
|
}
|
|
6925
|
-
return
|
|
7640
|
+
return shadowedSources;
|
|
6926
7641
|
}
|
|
6927
7642
|
function buildInvalidTargetWarnings(subagents) {
|
|
6928
7643
|
const warnings = [];
|
|
@@ -6974,14 +7689,7 @@ async function syncSubagents(request) {
|
|
|
6974
7689
|
agentsDir: request.agentsDir,
|
|
6975
7690
|
resolveTargetName: request.resolveTargetName
|
|
6976
7691
|
});
|
|
6977
|
-
|
|
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
|
-
}
|
|
7692
|
+
filterSubagentCatalog(catalog, request.includeItem);
|
|
6985
7693
|
const targets = request.targets.filter(
|
|
6986
7694
|
(target) => normalizeOutputDefinition(target.outputs.subagents) !== null
|
|
6987
7695
|
);
|
|
@@ -7002,6 +7710,13 @@ async function syncSubagents(request) {
|
|
|
7002
7710
|
}
|
|
7003
7711
|
const allTargetIds = request.targets.map((target) => target.id);
|
|
7004
7712
|
const activeTargetIds = new Set(targets.map((target) => target.id));
|
|
7713
|
+
assertUsableSubagentsForTargets({
|
|
7714
|
+
subagents: catalog.subagents,
|
|
7715
|
+
activeTargetIds,
|
|
7716
|
+
overrideOnly: request.overrideOnly,
|
|
7717
|
+
overrideSkip: request.overrideSkip,
|
|
7718
|
+
allTargets: allTargetIds
|
|
7719
|
+
});
|
|
7005
7720
|
const effectiveTargetsBySubagent = /* @__PURE__ */ new Map();
|
|
7006
7721
|
const activeSourcesByTarget = /* @__PURE__ */ new Map();
|
|
7007
7722
|
for (const subagent of catalog.subagents) {
|
|
@@ -7036,6 +7751,7 @@ async function syncSubagents(request) {
|
|
|
7036
7751
|
const managedManifest = await readManagedOutputs(request.repoRoot, homeDir) ?? { entries: [] };
|
|
7037
7752
|
const nextManaged = /* @__PURE__ */ new Map();
|
|
7038
7753
|
const activeOutputPaths = /* @__PURE__ */ new Set();
|
|
7754
|
+
const shadowedSubagentSources = /* @__PURE__ */ new Map();
|
|
7039
7755
|
const countsByTarget = /* @__PURE__ */ new Map();
|
|
7040
7756
|
const getCounts = (targetId) => {
|
|
7041
7757
|
const existing = countsByTarget.get(targetId) ?? emptySummaryCounts();
|
|
@@ -7046,9 +7762,17 @@ async function syncSubagents(request) {
|
|
|
7046
7762
|
const writerRegistry = /* @__PURE__ */ new Map([
|
|
7047
7763
|
[defaultSubagentWriter.id, defaultSubagentWriter]
|
|
7048
7764
|
]);
|
|
7049
|
-
const canonicalSkills = await
|
|
7050
|
-
|
|
7051
|
-
|
|
7765
|
+
const canonicalSkills = await resolveCanonicalSkillsForSubagentSync({
|
|
7766
|
+
repoRoot: request.repoRoot,
|
|
7767
|
+
activeTargets: targets,
|
|
7768
|
+
allTargetIds,
|
|
7769
|
+
subagents: catalog.subagents,
|
|
7770
|
+
agentsDir: request.agentsDir,
|
|
7771
|
+
includeLocalSkills: request.includeLocalSkills,
|
|
7772
|
+
resolveTargetName: request.resolveTargetName,
|
|
7773
|
+
overrideOnly: request.overrideOnly,
|
|
7774
|
+
overrideSkip: request.overrideSkip,
|
|
7775
|
+
includeSkill: request.includeSkill
|
|
7052
7776
|
});
|
|
7053
7777
|
const validAgents = request.validAgents ?? buildSupportedAgentNames(request.targets);
|
|
7054
7778
|
const outputDefs = /* @__PURE__ */ new Map();
|
|
@@ -7114,8 +7838,13 @@ async function syncSubagents(request) {
|
|
|
7114
7838
|
}
|
|
7115
7839
|
if (outputKind === "skill") {
|
|
7116
7840
|
const canonicalSkillKey = normalizeSkillKey(subagent.resolvedName);
|
|
7117
|
-
const canonicalSkillPath =
|
|
7841
|
+
const canonicalSkillPath = getCanonicalSkillPath(
|
|
7842
|
+
canonicalSkills,
|
|
7843
|
+
target.id,
|
|
7844
|
+
canonicalSkillKey
|
|
7845
|
+
);
|
|
7118
7846
|
if (canonicalSkillPath) {
|
|
7847
|
+
recordShadowedSubagentSource(shadowedSubagentSources, target.id, subagent.resolvedName);
|
|
7119
7848
|
warnings.push(
|
|
7120
7849
|
`Skipped ${target.displayName} skill "${subagent.resolvedName}" because canonical skill exists at ${canonicalSkillPath}.`
|
|
7121
7850
|
);
|
|
@@ -7320,6 +8049,35 @@ async function syncSubagents(request) {
|
|
|
7320
8049
|
if (nextManaged.has(key)) {
|
|
7321
8050
|
continue;
|
|
7322
8051
|
}
|
|
8052
|
+
const canonicalSkillPath = getCanonicalSkillPath(
|
|
8053
|
+
canonicalSkills,
|
|
8054
|
+
entry2.targetId,
|
|
8055
|
+
normalizeSkillKey(entry2.sourceId)
|
|
8056
|
+
);
|
|
8057
|
+
const skillDef = skillDefs.get(entry2.targetId);
|
|
8058
|
+
if (canonicalSkillPath && skillDef) {
|
|
8059
|
+
const expectedSkillOutputPath = resolveOutputPath({
|
|
8060
|
+
template: skillDef.path,
|
|
8061
|
+
context: {
|
|
8062
|
+
repoRoot: request.repoRoot,
|
|
8063
|
+
agentsDir: agentsDirPath,
|
|
8064
|
+
homeDir,
|
|
8065
|
+
targetId: entry2.targetId,
|
|
8066
|
+
itemName: entry2.sourceId
|
|
8067
|
+
},
|
|
8068
|
+
item: { name: entry2.sourceId },
|
|
8069
|
+
baseDir: request.repoRoot
|
|
8070
|
+
});
|
|
8071
|
+
if (normalizeManagedOutputPath(expectedSkillOutputPath) === normalizeManagedOutputPath(entry2.outputPath)) {
|
|
8072
|
+
updatedEntries.push(entry2);
|
|
8073
|
+
continue;
|
|
8074
|
+
}
|
|
8075
|
+
}
|
|
8076
|
+
const shadowedSources = shadowedSubagentSources.get(entry2.targetId);
|
|
8077
|
+
if (shadowedSources?.has(normalizeName(entry2.sourceId))) {
|
|
8078
|
+
updatedEntries.push(entry2);
|
|
8079
|
+
continue;
|
|
8080
|
+
}
|
|
7323
8081
|
const activeSources = activeSourcesByTarget.get(entry2.targetId);
|
|
7324
8082
|
const sourceStillActive = activeSources?.has(entry2.sourceId) ?? false;
|
|
7325
8083
|
if (!removeMissing || sourceStillActive) {
|
|
@@ -7813,12 +8571,21 @@ function replayTraversedProfileWarnings(profile, traversedNames) {
|
|
|
7813
8571
|
}
|
|
7814
8572
|
});
|
|
7815
8573
|
for (const name of traversedNames.skills) {
|
|
8574
|
+
if (!name) {
|
|
8575
|
+
continue;
|
|
8576
|
+
}
|
|
7816
8577
|
warningFilter.includes("skills", name);
|
|
7817
8578
|
}
|
|
7818
8579
|
for (const name of traversedNames.subagents) {
|
|
8580
|
+
if (!name) {
|
|
8581
|
+
continue;
|
|
8582
|
+
}
|
|
7819
8583
|
warningFilter.includes("subagents", name);
|
|
7820
8584
|
}
|
|
7821
8585
|
for (const name of traversedNames.commands) {
|
|
8586
|
+
if (!name) {
|
|
8587
|
+
continue;
|
|
8588
|
+
}
|
|
7822
8589
|
warningFilter.includes("commands", name);
|
|
7823
8590
|
}
|
|
7824
8591
|
return warningFilter.collectUnknownWarnings();
|
|
@@ -7838,6 +8605,18 @@ function addTemplateScriptSource(sources, templatePath, content) {
|
|
|
7838
8605
|
function intersectsTargets(targets, selectedTargetIds) {
|
|
7839
8606
|
return targets.some((target) => selectedTargetIds.has(target));
|
|
7840
8607
|
}
|
|
8608
|
+
function areSelectedTargetsFullyShadowed(options) {
|
|
8609
|
+
const relevantTargets = options.effectiveTargets.filter(
|
|
8610
|
+
(targetId) => options.selectedTargetIds.has(targetId)
|
|
8611
|
+
);
|
|
8612
|
+
if (relevantTargets.length === 0) {
|
|
8613
|
+
return false;
|
|
8614
|
+
}
|
|
8615
|
+
const normalizedName = options.subagentName.trim().toLowerCase();
|
|
8616
|
+
return relevantTargets.every(
|
|
8617
|
+
(targetId) => options.shadowedSubagentsByTarget.get(targetId)?.has(normalizedName)
|
|
8618
|
+
);
|
|
8619
|
+
}
|
|
7841
8620
|
async function listAllFiles(root) {
|
|
7842
8621
|
const entries = await readdir(root, { withFileTypes: true });
|
|
7843
8622
|
const files = [];
|
|
@@ -7872,7 +8651,10 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7872
8651
|
resolveTargetName: options.resolveTargetName
|
|
7873
8652
|
});
|
|
7874
8653
|
for (const command of commandCatalog.commands) {
|
|
7875
|
-
if (options.includeCommand && !options.includeCommand(
|
|
8654
|
+
if (options.includeCommand && !options.includeCommand({
|
|
8655
|
+
canonicalName: command.name,
|
|
8656
|
+
enabledByDefault: command.enabledByDefault
|
|
8657
|
+
})) {
|
|
7876
8658
|
continue;
|
|
7877
8659
|
}
|
|
7878
8660
|
const effectiveTargets = resolveEffectiveTargets({
|
|
@@ -7884,6 +8666,7 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7884
8666
|
if (!intersectsTargets(effectiveTargets, selectedCommandTargetIds)) {
|
|
7885
8667
|
continue;
|
|
7886
8668
|
}
|
|
8669
|
+
assertSlashCommandDefinitionUsable(command);
|
|
7887
8670
|
addTemplateScriptSource(sources, command.sourcePath, command.rawContents);
|
|
7888
8671
|
}
|
|
7889
8672
|
}
|
|
@@ -7893,8 +8676,23 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7893
8676
|
agentsDir: options.agentsDir,
|
|
7894
8677
|
resolveTargetName: options.resolveTargetName
|
|
7895
8678
|
});
|
|
8679
|
+
const shadowedSubagentsByTarget = await resolveShadowedSubagentNamesForTargets({
|
|
8680
|
+
repoRoot: options.repoRoot,
|
|
8681
|
+
activeTargets: options.selectedSubagentTargets,
|
|
8682
|
+
allTargetIds: options.allTargetIds,
|
|
8683
|
+
subagents: subagentCatalog.subagents,
|
|
8684
|
+
agentsDir: options.agentsDir,
|
|
8685
|
+
includeLocalSkills: !options.excludeLocalSkills,
|
|
8686
|
+
resolveTargetName: options.resolveTargetName,
|
|
8687
|
+
overrideOnly: options.overrideOnly,
|
|
8688
|
+
overrideSkip: options.overrideSkip,
|
|
8689
|
+
includeSkill: options.includeSkill
|
|
8690
|
+
});
|
|
7896
8691
|
for (const subagent of subagentCatalog.subagents) {
|
|
7897
|
-
if (options.includeSubagent && !options.includeSubagent(
|
|
8692
|
+
if (options.includeSubagent && !options.includeSubagent({
|
|
8693
|
+
canonicalName: subagent.resolvedName,
|
|
8694
|
+
enabledByDefault: subagent.enabledByDefault
|
|
8695
|
+
})) {
|
|
7898
8696
|
continue;
|
|
7899
8697
|
}
|
|
7900
8698
|
const effectiveTargets = resolveEffectiveTargets({
|
|
@@ -7906,6 +8704,15 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7906
8704
|
if (!intersectsTargets(effectiveTargets, selectedSubagentTargetIds)) {
|
|
7907
8705
|
continue;
|
|
7908
8706
|
}
|
|
8707
|
+
if (areSelectedTargetsFullyShadowed({
|
|
8708
|
+
selectedTargetIds: selectedSubagentTargetIds,
|
|
8709
|
+
effectiveTargets,
|
|
8710
|
+
shadowedSubagentsByTarget,
|
|
8711
|
+
subagentName: subagent.resolvedName
|
|
8712
|
+
})) {
|
|
8713
|
+
continue;
|
|
8714
|
+
}
|
|
8715
|
+
assertSubagentDefinitionUsable(subagent);
|
|
7909
8716
|
addTemplateScriptSource(sources, subagent.sourcePath, subagent.rawContents);
|
|
7910
8717
|
}
|
|
7911
8718
|
}
|
|
@@ -7936,7 +8743,10 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7936
8743
|
resolveTargetName: options.resolveTargetName
|
|
7937
8744
|
});
|
|
7938
8745
|
for (const skill of skillCatalog.skills) {
|
|
7939
|
-
if (options.includeSkill && !options.includeSkill(
|
|
8746
|
+
if (options.includeSkill && !options.includeSkill({
|
|
8747
|
+
canonicalName: skill.name,
|
|
8748
|
+
enabledByDefault: skill.enabledByDefault
|
|
8749
|
+
})) {
|
|
7940
8750
|
continue;
|
|
7941
8751
|
}
|
|
7942
8752
|
const effectiveTargets = resolveEffectiveTargets({
|
|
@@ -7948,6 +8758,7 @@ async function gatherTemplateScriptSources(options) {
|
|
|
7948
8758
|
if (!intersectsTargets(effectiveTargets, selectedSkillTargetIds)) {
|
|
7949
8759
|
continue;
|
|
7950
8760
|
}
|
|
8761
|
+
assertSkillDefinitionUsable(skill);
|
|
7951
8762
|
const files = await listAllFiles(skill.directoryPath);
|
|
7952
8763
|
for (const filePath of files) {
|
|
7953
8764
|
const buffer = await readFile(filePath);
|
|
@@ -8088,6 +8899,16 @@ async function validateTemplatingSources(options) {
|
|
|
8088
8899
|
sourcePath
|
|
8089
8900
|
});
|
|
8090
8901
|
};
|
|
8902
|
+
const selectedSkillTargetIds = new Set(options.selectedSkillTargets.map((target) => target.id));
|
|
8903
|
+
const selectedCommandTargetIds = new Set(
|
|
8904
|
+
options.selectedCommandTargets.map((target) => target.id)
|
|
8905
|
+
);
|
|
8906
|
+
const selectedSubagentTargetIds = new Set(
|
|
8907
|
+
options.selectedSubagentTargets.map((target) => target.id)
|
|
8908
|
+
);
|
|
8909
|
+
const selectedInstructionTargetIds = new Set(
|
|
8910
|
+
options.selectedInstructionTargets.map((target) => target.id)
|
|
8911
|
+
);
|
|
8091
8912
|
if (options.commandsAvailable) {
|
|
8092
8913
|
const commandCatalog = await loadCommandCatalog(options.repoRoot, {
|
|
8093
8914
|
includeLocal: options.includeLocalCommands,
|
|
@@ -8095,9 +8916,20 @@ async function validateTemplatingSources(options) {
|
|
|
8095
8916
|
resolveTargetName: options.resolveTargetName
|
|
8096
8917
|
});
|
|
8097
8918
|
for (const command of commandCatalog.commands) {
|
|
8098
|
-
if (options.includeCommand && !options.includeCommand(
|
|
8919
|
+
if (options.includeCommand && !options.includeCommand({
|
|
8920
|
+
canonicalName: command.name,
|
|
8921
|
+
enabledByDefault: command.enabledByDefault
|
|
8922
|
+
})) {
|
|
8099
8923
|
continue;
|
|
8100
8924
|
}
|
|
8925
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
8926
|
+
defaultTargets: command.targetAgents,
|
|
8927
|
+
allTargets: options.selectedCommandTargets.map((target) => target.id)
|
|
8928
|
+
});
|
|
8929
|
+
if (!intersectsTargets(effectiveTargets, selectedCommandTargetIds)) {
|
|
8930
|
+
continue;
|
|
8931
|
+
}
|
|
8932
|
+
assertSlashCommandDefinitionUsable(command);
|
|
8101
8933
|
validateContent(command.sourcePath, command.rawContents);
|
|
8102
8934
|
}
|
|
8103
8935
|
}
|
|
@@ -8108,9 +8940,20 @@ async function validateTemplatingSources(options) {
|
|
|
8108
8940
|
resolveTargetName: options.resolveTargetName
|
|
8109
8941
|
});
|
|
8110
8942
|
for (const skill of skillCatalog.skills) {
|
|
8111
|
-
if (options.includeSkill && !options.includeSkill(
|
|
8943
|
+
if (options.includeSkill && !options.includeSkill({
|
|
8944
|
+
canonicalName: skill.name,
|
|
8945
|
+
enabledByDefault: skill.enabledByDefault
|
|
8946
|
+
})) {
|
|
8112
8947
|
continue;
|
|
8113
8948
|
}
|
|
8949
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
8950
|
+
defaultTargets: skill.targetAgents,
|
|
8951
|
+
allTargets: options.selectedSkillTargets.map((target) => target.id)
|
|
8952
|
+
});
|
|
8953
|
+
if (!intersectsTargets(effectiveTargets, selectedSkillTargetIds)) {
|
|
8954
|
+
continue;
|
|
8955
|
+
}
|
|
8956
|
+
assertSkillDefinitionUsable(skill);
|
|
8114
8957
|
const files = await listFiles(skill.directoryPath);
|
|
8115
8958
|
const filesToValidate = options.includeLocalSkills ? files : files.filter((filePath) => !hasLocalMarker(filePath));
|
|
8116
8959
|
for (const filePath of filesToValidate) {
|
|
@@ -8129,29 +8972,61 @@ async function validateTemplatingSources(options) {
|
|
|
8129
8972
|
agentsDir: options.agentsDir,
|
|
8130
8973
|
resolveTargetName: options.resolveTargetName
|
|
8131
8974
|
});
|
|
8975
|
+
const shadowedSubagentsByTarget = await resolveShadowedSubagentNamesForTargets({
|
|
8976
|
+
repoRoot: options.repoRoot,
|
|
8977
|
+
activeTargets: options.selectedSubagentTargets,
|
|
8978
|
+
allTargetIds: options.selectedSubagentTargets.map((target) => target.id),
|
|
8979
|
+
subagents: subagentCatalog.subagents,
|
|
8980
|
+
agentsDir: options.agentsDir,
|
|
8981
|
+
includeLocalSkills: options.includeLocalSkills,
|
|
8982
|
+
resolveTargetName: options.resolveTargetName,
|
|
8983
|
+
includeSkill: options.includeSkill
|
|
8984
|
+
});
|
|
8132
8985
|
for (const subagent of subagentCatalog.subagents) {
|
|
8133
|
-
if (options.includeSubagent && !options.includeSubagent(
|
|
8986
|
+
if (options.includeSubagent && !options.includeSubagent({
|
|
8987
|
+
canonicalName: subagent.resolvedName,
|
|
8988
|
+
enabledByDefault: subagent.enabledByDefault
|
|
8989
|
+
})) {
|
|
8134
8990
|
continue;
|
|
8135
8991
|
}
|
|
8992
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
8993
|
+
defaultTargets: subagent.targetAgents,
|
|
8994
|
+
allTargets: options.selectedSubagentTargets.map((target) => target.id)
|
|
8995
|
+
});
|
|
8996
|
+
if (!intersectsTargets(effectiveTargets, selectedSubagentTargetIds)) {
|
|
8997
|
+
continue;
|
|
8998
|
+
}
|
|
8999
|
+
if (areSelectedTargetsFullyShadowed({
|
|
9000
|
+
selectedTargetIds: selectedSubagentTargetIds,
|
|
9001
|
+
effectiveTargets,
|
|
9002
|
+
shadowedSubagentsByTarget,
|
|
9003
|
+
subagentName: subagent.resolvedName
|
|
9004
|
+
})) {
|
|
9005
|
+
continue;
|
|
9006
|
+
}
|
|
9007
|
+
assertSubagentDefinitionUsable(subagent);
|
|
8136
9008
|
validateContent(subagent.sourcePath, subagent.rawContents);
|
|
8137
9009
|
}
|
|
8138
9010
|
}
|
|
8139
9011
|
if (options.instructionsAvailable) {
|
|
8140
|
-
const
|
|
9012
|
+
const catalog = await loadInstructionTemplateCatalog({
|
|
8141
9013
|
repoRoot: options.repoRoot,
|
|
8142
9014
|
includeLocal: options.includeLocalInstructions,
|
|
8143
|
-
agentsDir: options.agentsDir
|
|
9015
|
+
agentsDir: options.agentsDir,
|
|
9016
|
+
resolveTargetName: options.resolveTargetName
|
|
8144
9017
|
});
|
|
8145
|
-
for (const
|
|
8146
|
-
const
|
|
8147
|
-
|
|
8148
|
-
|
|
9018
|
+
for (const template of catalog.templates) {
|
|
9019
|
+
const effectiveTargets = resolveEffectiveTargets({
|
|
9020
|
+
defaultTargets: template.targets,
|
|
9021
|
+
allTargets: options.selectedInstructionTargets.map((target) => target.id)
|
|
9022
|
+
});
|
|
9023
|
+
if (!intersectsTargets(effectiveTargets, selectedInstructionTargetIds)) {
|
|
8149
9024
|
continue;
|
|
8150
9025
|
}
|
|
8151
9026
|
validateAgentTemplating({
|
|
8152
|
-
content:
|
|
9027
|
+
content: template.rawContents,
|
|
8153
9028
|
validAgents: options.validAgents,
|
|
8154
|
-
sourcePath:
|
|
9029
|
+
sourcePath: template.sourcePath
|
|
8155
9030
|
});
|
|
8156
9031
|
}
|
|
8157
9032
|
}
|
|
@@ -8746,12 +9621,11 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
8746
9621
|
commands: /* @__PURE__ */ new Set()
|
|
8747
9622
|
};
|
|
8748
9623
|
const includeItemFor = (category) => {
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
return profileItemFilter.includes(category, name);
|
|
9624
|
+
return (item) => {
|
|
9625
|
+
if (profileItemFilter.enabled) {
|
|
9626
|
+
traversedProfileNames[category].add(item.canonicalName);
|
|
9627
|
+
}
|
|
9628
|
+
return profileItemFilter.includes(category, item);
|
|
8755
9629
|
};
|
|
8756
9630
|
};
|
|
8757
9631
|
if (filteredTargets.length === 0 && !listLocal) {
|
|
@@ -8957,6 +9831,10 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
8957
9831
|
repoRoot,
|
|
8958
9832
|
agentsDir,
|
|
8959
9833
|
validAgents,
|
|
9834
|
+
selectedSkillTargets,
|
|
9835
|
+
selectedCommandTargets,
|
|
9836
|
+
selectedSubagentTargets,
|
|
9837
|
+
selectedInstructionTargets,
|
|
8960
9838
|
commandsAvailable: hasCommandsToSync,
|
|
8961
9839
|
skillsAvailable: hasSkillsToSync,
|
|
8962
9840
|
subagentsAvailable: hasSubagentsToSync,
|
|
@@ -9159,7 +10037,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
9159
10037
|
resolveTargetName,
|
|
9160
10038
|
hooks: globalHooks,
|
|
9161
10039
|
templateScriptRuntime: scriptRuntime,
|
|
9162
|
-
includeItem: includeItemFor("subagents")
|
|
10040
|
+
includeItem: includeItemFor("subagents"),
|
|
10041
|
+
includeSkill: includeItemFor("skills")
|
|
9163
10042
|
});
|
|
9164
10043
|
if (availabilitySubagentSkips.length > 0) {
|
|
9165
10044
|
const subagentWarnings = mergeWarnings(
|